查找data.table中的列表是否在其他列中包含单词

时间:2019-05-01 09:59:46

标签: r data.table

我有一个data.table。列之一是单词列表。我想看看是否有任何一个单词出现在每一行的另一列中。我觉得这应该很容易,但是我没有得到我期望的结果。

困难之处似乎在于该列包含列表的事实,也可能是不一致的(即,不是列出所有长度相同,有些NA,有些只是一个单词的列表)?

示例数据

words_data <- data.table(
  word = c("Lots", "of", "words", "some", "are", "names", 
           "like", "Tom", "and", "Connolly", "or", "Pete", "Dawson"),
  names = c(list(c("Tom", "Connolly")),
            list(c("Tom", "Connolly")),
            list(c("Tom", "Connolly")),
            NA,
            NA,
            NA,
            list(c("Tom", "Connolly")),
            list(c("Tom", "Connolly", "Pete", "Dawson")),
            list(c("Jenny", "Rogers")),
            NA,
            list(c("Pete", "Dawson")),
            "Dawson",
            NA)
)

所需的输出

一个data.table过滤到行,其中word列中可以找到names列中的值。

因此,在此特定数据集中唯一匹配的是第8行,其第一个行为"Tom",名称为c("Tom", "Connolly", "Pete", "Dawson")

使用%in%

这只会返回一行,但我不知道为什么会出现这一行。

> words_data[word %in% names]
     word names
1: Dawson    NA

使用unlist()

这确实标识出单词是名称,因此基本上建议不列出整个名称列,并检查所有单词,这似乎更接近,但我只希望它检查该行。

> words_data[word %in% unlist(names)]
       word                    names
1:      Tom Tom,Connolly,Pete,Dawson
2: Connolly                       NA
3:     Pete                   Dawson
4:   Dawson                       NA

正常使用

我认为使用sapply()可能有助于解决逐行问题,但是输出与执行word %in% names相同。

> words_data[word %in% sapply(names, unlist)]
     word names
1: Dawson    NA

1 个答案:

答案 0 :(得分:7)

这本质上只是一个隐藏的循环,但它会起作用:

words_data[mapply(`%in%`, word, names)]
#   word                    names
#1:  Tom Tom,Connolly,Pete,Dawson

我认为它可能会扩展得很厉害,但这是还可以

words_data <- words_data[rep(1:13,1e5),]
nrow(words_data)
#[1] 1300000
system.time(words_data[mapply(`%in%`, word, names)])
#   user  system elapsed 
#  1.329   0.016   1.345 

该问题中大多数尝试的问题在于,它们在跨多个向量的向量化比较中没有逐个考虑wordnamesMapmapply将负责以下工作:

mapply(paste, 1:3, letters[1:3])
#[1] "1 a" "2 b" "3 c"

其他结果不起作用的原因多种多样。例如:

%in%

这将依次比较word的每个值,以查看它是否确实存在于names

words_data$word %in% words_data$names
#[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#[8] FALSE FALSE FALSE FALSE FALSE  TRUE
"Dawson"第13行的

word"Dawson"第12行的names匹配。它不会匹配包含list和其他值的"Dawson"的任何其他内容:

"Dawson" %in% list(list("Dawson","Tom"))
#[1] FALSE

取消列出

...基本上表明整个names列均未列出,并且所有名称 word均已进行了检查”

是的,就是这样。

申请+取消列出

这里的sapplynames对象没有任何作用,因为unlist始终只在每个列表项中运行:

identical(words_data$names, sapply(words_data$names, unlist))
#[1] TRUE

然后,您可以参考上面的%in%逻辑,以了解其为何无法按预期工作。

相关问题