检测数据框中的字符串模式并有条件地在 R 中填充另一个
Detect string pattern in dataframe and conditionally fill another in R
我有一个包含文本和数字引用的数据框,以及一个可能出现在文本中的单词向量。我想要的是检查 words_df
中的单词出现在 text_df$text
中的每个实例,并将 word_df
中的单词和 text_df$ref
中的数字引用记录在新的数据框(edge_df
)。
text_df <- data.frame(text = c("John went to the shops", "Sarita hates apples", "Wendy doesn't care about this"),
ref = c("13.5", "1.9.9", "20.1"))
words_df <- data.frame(word = c("shops", "John", "apples", "Wendy", "this"))
edge_df <- data.frame(ref = NA, word = NA)
输出应如下所示:
> edge_df
ref word
1 13.5 shops
2 13.5 John
3 1.9.9 apples
4 20.1 Wendy
5 20.1 this
它不是很优雅,但我认为 for 循环会起作用,其中使用 stringr::str_detect
对照文本检查每个单词,如果结果是 TRUE
,它会记录单词和参考:
for (i in 1:nrow(text_df)) {
for (j in 1:nrow(words_df)) {
if (str_detect(text_df$text[i], words_df$word[j]) == TRUE) {
edge_df$ref <- text_df$ref[i]
edge_df$word <- words_df$word[j]
}
}
}
这没有用,而且这个循环也没有几个变体。如果可能的话,我宁愿根本不使用循环,因为我正在使用的数据帧每个都有大约 1000 行,并且循环遍历它们需要太长时间。非常感谢对循环的任何修复,如果你可以在没有循环的情况下完成它,则奖励 points/props。
谢谢!
试试这个 tidyverse
方法。您的问题的关键:您可以通过分隔句子中的每个单词然后使用 left_join()
来将数据格式化为 long。代码在这里(我使用了你提供的数据):
library(tidyverse)
#Data
text_df <- data.frame(text = c("John went to the shops", "Sarita hates apples", "Wendy doesn't care about this"),
ref = c("13.5", "1.9.9", "20.1"),stringsAsFactors = F)
words_df <- data.frame(word = c("shops", "John", "apples", "Wendy", "this"),stringsAsFactors = F)
#Join
words_df %>% left_join(text_df %>% separate_rows(text,sep = ' ') %>%
rename(word=text))
输出:
word ref
1 shops 13.5
2 John 13.5
3 apples 1.9.9
4 Wendy 20.1
5 this 20.1
library(data.table)
words_df <- data.frame(word = c("shops", "John", "apples", "Wendy", "this"))
text_df <- data.frame(text = c("John went to the shops",
"Sarita hates apples", "Wendy doesn't care about this"),
ref = c("13.5", "1.9.9", "20.1"))
setDT(words_df)
setDT(text_df)
首先我们准备好词向量。
wordvec <- paste0(words_df[,word],collapse="|")
现在要做的就是检查每一行 wordvec
中的所有单词
## > text_df[,.(word=unlist(regmatches(text,gregexpr(wordvec,text)))),ref]
## ref word
## 1: 13.5 John
## 2: 13.5 shops
## 3: 1.9.9 apples
## 4: 20.1 Wendy
## 5: 20.1 this
regmatches 函数,grepexpr 将 return 一个列表,其中包含与模式 wordvec
.
匹配的所有单词
> regmatches("John went to the shops",gregexpr(wordvec,"John went to the shops"))
##[[1]]
##[1] "John" "shops"
警告,为了快速格式化输出,我 over-relying 引用变量并将它们视为 ID。如果不是这种情况,那么最好创建一个 id 列并将其与 ref 一起使用。例如
text_df[,id:=1:.N][,.(word=unlist(regmatches(text,
gregexpr(wordvec,text)))),.(id,ref)]
这是一个基本的 R 选项
u <- lapply(text_df$text,function(x) words_df$word[sapply(words_df$word,function(y) grepl(y,x))])
edge_df <- data.frame(ref = rep(text_df$ref,lengths(u)),word = unlist(u))
这给出了
ref word
1 13.5 shops
2 13.5 John
3 1.9.9 apples
4 20.1 Wendy
5 20.1 this
这里是 str_extract
和 unnest
的选项。我们将 'text' 列中的单词提取到 list
中,并使用 unnest
扩展行
library(dplyr)
library(stringr)
library(tidyr)
text_df %>%
transmute(ref, word = str_extract_all(text,
str_c(words_df$word, collapse="|"))) %>%
unnest(c(word))
# A tibble: 5 x 2
# ref word
# <chr> <chr>
#1 13.5 John
#2 13.5 shops
#3 1.9.9 apples
#4 20.1 Wendy
#5 20.1 this
我有一个包含文本和数字引用的数据框,以及一个可能出现在文本中的单词向量。我想要的是检查 words_df
中的单词出现在 text_df$text
中的每个实例,并将 word_df
中的单词和 text_df$ref
中的数字引用记录在新的数据框(edge_df
)。
text_df <- data.frame(text = c("John went to the shops", "Sarita hates apples", "Wendy doesn't care about this"),
ref = c("13.5", "1.9.9", "20.1"))
words_df <- data.frame(word = c("shops", "John", "apples", "Wendy", "this"))
edge_df <- data.frame(ref = NA, word = NA)
输出应如下所示:
> edge_df
ref word
1 13.5 shops
2 13.5 John
3 1.9.9 apples
4 20.1 Wendy
5 20.1 this
它不是很优雅,但我认为 for 循环会起作用,其中使用 stringr::str_detect
对照文本检查每个单词,如果结果是 TRUE
,它会记录单词和参考:
for (i in 1:nrow(text_df)) {
for (j in 1:nrow(words_df)) {
if (str_detect(text_df$text[i], words_df$word[j]) == TRUE) {
edge_df$ref <- text_df$ref[i]
edge_df$word <- words_df$word[j]
}
}
}
这没有用,而且这个循环也没有几个变体。如果可能的话,我宁愿根本不使用循环,因为我正在使用的数据帧每个都有大约 1000 行,并且循环遍历它们需要太长时间。非常感谢对循环的任何修复,如果你可以在没有循环的情况下完成它,则奖励 points/props。
谢谢!
试试这个 tidyverse
方法。您的问题的关键:您可以通过分隔句子中的每个单词然后使用 left_join()
来将数据格式化为 long。代码在这里(我使用了你提供的数据):
library(tidyverse)
#Data
text_df <- data.frame(text = c("John went to the shops", "Sarita hates apples", "Wendy doesn't care about this"),
ref = c("13.5", "1.9.9", "20.1"),stringsAsFactors = F)
words_df <- data.frame(word = c("shops", "John", "apples", "Wendy", "this"),stringsAsFactors = F)
#Join
words_df %>% left_join(text_df %>% separate_rows(text,sep = ' ') %>%
rename(word=text))
输出:
word ref
1 shops 13.5
2 John 13.5
3 apples 1.9.9
4 Wendy 20.1
5 this 20.1
library(data.table)
words_df <- data.frame(word = c("shops", "John", "apples", "Wendy", "this"))
text_df <- data.frame(text = c("John went to the shops",
"Sarita hates apples", "Wendy doesn't care about this"),
ref = c("13.5", "1.9.9", "20.1"))
setDT(words_df)
setDT(text_df)
首先我们准备好词向量。
wordvec <- paste0(words_df[,word],collapse="|")
现在要做的就是检查每一行 wordvec
## > text_df[,.(word=unlist(regmatches(text,gregexpr(wordvec,text)))),ref]
## ref word
## 1: 13.5 John
## 2: 13.5 shops
## 3: 1.9.9 apples
## 4: 20.1 Wendy
## 5: 20.1 this
regmatches 函数,grepexpr 将 return 一个列表,其中包含与模式 wordvec
.
> regmatches("John went to the shops",gregexpr(wordvec,"John went to the shops"))
##[[1]]
##[1] "John" "shops"
警告,为了快速格式化输出,我 over-relying 引用变量并将它们视为 ID。如果不是这种情况,那么最好创建一个 id 列并将其与 ref 一起使用。例如
text_df[,id:=1:.N][,.(word=unlist(regmatches(text,
gregexpr(wordvec,text)))),.(id,ref)]
这是一个基本的 R 选项
u <- lapply(text_df$text,function(x) words_df$word[sapply(words_df$word,function(y) grepl(y,x))])
edge_df <- data.frame(ref = rep(text_df$ref,lengths(u)),word = unlist(u))
这给出了
ref word
1 13.5 shops
2 13.5 John
3 1.9.9 apples
4 20.1 Wendy
5 20.1 this
这里是 str_extract
和 unnest
的选项。我们将 'text' 列中的单词提取到 list
中,并使用 unnest
扩展行
library(dplyr)
library(stringr)
library(tidyr)
text_df %>%
transmute(ref, word = str_extract_all(text,
str_c(words_df$word, collapse="|"))) %>%
unnest(c(word))
# A tibble: 5 x 2
# ref word
# <chr> <chr>
#1 13.5 John
#2 13.5 shops
#3 1.9.9 apples
#4 20.1 Wendy
#5 20.1 this