如何在R中有效地比较两个不同的列(都包含字符串)?

如何在R中有效地比较两个不同的列(都包含字符串)?,r,R,假设A是一个数据帧,A的结构如下 Row no C1 C2 1 I am fine 1234 2 He is fine

假设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”。我不想将“good”与A的第5行进行比较,因为我已经选择了第5行。我需要一个有效的解决方案,因为我的真实数据(A)集的行数约为400000行,B约为10000行。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秒。

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秒。

此功能

phrasesWithWords <- function(x, table)
{
    words <- strsplit(x, "\\W")
    found <- relist(unlist(words) %in% table, words)
    which(sapply(found, any))
}
相当简洁的包“lineprof”显示了对于修改后的函数

f0 <- function(x, table)
{
    words <- strsplit(x, "\\W")
    idx <- unlist(words) %in% table
    found <- relist(idx, words)
    which(sapply(found, any))
}
导致一个更复杂的方法

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)]))
}
我认为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
此函数

phrasesWithWords <- function(x, table)
{
    words <- strsplit(x, "\\W")
    found <- relist(unlist(words) %in% table, words)
    which(sapply(found, any))
}
相当简洁的包“lineprof”显示了对于修改后的函数

f0 <- function(x, table)
{
    words <- strsplit(x, "\\W")
    idx <- unlist(words) %in% table
    found <- relist(idx, words)
    which(sapply(found, any))
}
导致一个更复杂的方法

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)]))
}
我认为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

谢谢,马丁,它很有效。。。但我有一个问题,这是一种可扩展的巨大数据集的方法。。注:我刚刚对小数据集的方法进行了测试。@tanay我认为
grep
更快,我在这里用10万个示例短语(来自您的短语)进行了基准测试,其中两个词:
grep
需要0.076秒,而
phrasewhords
需要13秒。@Carlosinelli我同意,grep似乎是一个更好的解决方案;表中的总字数有限制。谢谢Martin它可以工作。。。但我有一个问题,这是一种可扩展的巨大数据集的方法。。注:我刚刚对小数据集的方法进行了测试。@tanay我认为
grep
更快,我在这里用10万个示例短语(来自您的短语)进行了基准测试,其中两个词:
grep
需要0.076秒,而
phrasewhords
需要13秒。@Carlosinelli我同意,grep似乎是一个更好的解决方案;表格中的字数是有限制的。
> 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