假设A是数据帧,A的结构如下
Row no C1 C2
1 I am fine 1234
2 He is fine 1234
3 am better 1234
4 better butter 1234
5 fine good 1234
6 good to be better 1234
和B是另一个数据框,
Row no C1
1 fine
2 good
我想比较A $ C1和B $ C1,B $ C1中的字符串应该包含在A $ C1中。 因此,当我将A $ C1与B $ C1进行比较时,结果将是A中包含B字符串的行号。对于上面的场景,输出将是1,2,5,6,因为1,2,5包含单词“fine”和6,因为它包含单词“good”。我不想将“好”与A的第5行进行比较,因为我已经选择了第5行。我想要一个有效的解决方案,因为我的真实数据(A)集的行数大约是400000而B是10000
答案 0 :(得分:3)
grep
可以为您完成这项工作:
grep(paste(B$C1, collapse="|"), A$C1)
1 2 5 6
上面的代码为您提供A$C1
中包含至少一个B$C1
字的所有行,即第1,2,5和6行。第一个参数是正则表达式,这就是我们用"|"
(意思是“或”)折叠单词的原因。
它似乎可扩展。使用100.000个示例短语(来自您的短语)和两个单词grep
进行基准测试仅需0.076秒。
答案 1 :(得分:3)
此功能
phrasesWithWords <- function(x, table)
{
words <- strsplit(x, "\\W")
found <- relist(unlist(words) %in% table, words)
which(sapply(found, any))
}
适用于您的短语和可接受单词的表格:
phrase <- c("I am fine", "He is fine", "am better", "better butter",
"fine good", "good to be better")
table <- c("fine", "good")
phrasesWithWords(phrase, table)
该功能的工作原理是将短语分成单词,然后在表格中查找每个单词(不通过长短语列表),重新列出逻辑向量,并询问哪些列表元素至少包含一个TRUE。
与简单的grep解决方案相比,这并不是那么有效
f1 <- function(x, table)
grep(paste(table, collapse="|"), x)
与
library(microbenchmark)
x1000 <- rep(x, 1000)
给
> microbenchmark(phrasesWithWords(x1000, table), f1(x1000, table),
+ times=5)
Unit: milliseconds
expr min lq median uq
phrasesWithWords(x1000, table) 130.167172 132.815303 133.011161 133.112888
f1(x1000, table) 2.959576 2.973416 2.990412 3.060494
max neval
134.504282 5
3.439293 5
漂亮整齐的包“lineprof”表示对于修改过的函数
f0 <- function(x, table)
{
words <- strsplit(x, "\\W")
idx <- unlist(words) %in% table
found <- relist(idx, words)
which(sapply(found, any))
}
主要瓶颈在于重新存在
> lineprof(f0(x1000, table))
Reducing depth to 2 (from 7)
Common path: words.R!30719TCY
time alloc release dups ref src
1 0.003 0.668 0 0 words.R!30719TCY#3 f0/strsplit
2 0.024 28.240 0 17393 words.R!30719TCY#5 f0/relist
3 0.003 3.959 0 6617 words.R!30719TCY#6 f0/which
导致更精细的方法
f2 <- function(x, table)
{
words <- strsplit(x, "\\W")
len <- cumsum(sapply(words, length))
idx <- cumsum(unlist(words) %in% table)
which(idx[len] != c(0, idx[head(len, -1)]))
}
表现稍好一些
> identical(f2(x1000, table), f1(x1000, table))
[1] TRUE
> microbenchmark(f2(x1000, table), f1(x1000, table), times=5)
Unit: milliseconds
expr min lq median uq max neval
f2(x1000, table) 25.426832 25.815504 25.844033 26.075279 26.387559 5
f1(x1000, table) 2.963365 2.968197 2.984395 2.984423 3.129873 5
我认为f2和f1都可以很好地扩展到原始问题中的问题,只要有足够的内存(如果可接受的单词表与短语相比较小,那么我认为grep方法实际上会更多内存效率;最后我想我可能会投票给简单的grep解决方案!)。也许grep方法的主要限制是正则表达式的大小是有限的,在我的计算机上大约2560个术语
> grep(paste(as.character(1:2559), collapse="|"), "1")
[1] 1
> grep(paste(as.character(1:2560), collapse="|"), "1")
Error in grep(paste(as.character(1:2560), collapse = "|"), "1") :
invalid regular expression '1|2|3|4|5|6|7|8|9|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40|41|42|43|44|45|46|4