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

Meg*_*gan 4 r 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)
)
Run Code Online (Sandbox Code Playgroud)

所需的输出

过滤到行的data.table,其中word可以在namescolumn中找到该列中的值。

因此,在此特定数据集中唯一匹配的将是第8行,该行具有"Tom"单词和c("Tom", "Connolly", "Pete", "Dawson")名称。

使用%in%

这仅返回一行,但我不知道为什么要显示这一行。

> words_data[word %in% names]
     word names
1: Dawson    NA
Run Code Online (Sandbox Code Playgroud)

使用unlist()

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

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

使用sapply

我认为使用sapply()可能会解决逐行问题,但是输出与只是一样word %in% names

> words_data[word %in% sapply(names, unlist)]
     word names
1: Dawson    NA
Run Code Online (Sandbox Code Playgroud)

the*_*ail 7

从本质上讲,这只是一个隐藏的循环,但它可以工作:

words_data[mapply(`%in%`, word, names)]
#   word                    names
#1:  Tom Tom,Connolly,Pete,Dawson
Run Code Online (Sandbox Code Playgroud)

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

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 
Run Code Online (Sandbox Code Playgroud)

与大多数问题的尝试的问题是,他们没有考虑wordnames片逐片在跨多个向量矢量化比较。Mapmapply会照顾这个:

mapply(paste, 1:3, letters[1:3])
#[1] "1 a" "2 b" "3 c"
Run Code Online (Sandbox Code Playgroud)

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

%在%

这每一个值的比较word反过来,看它是否在存在names完全相同

words_data$word %in% words_data$names
#[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE
#[8] FALSE FALSE FALSE FALSE FALSE  TRUE
Run Code Online (Sandbox Code Playgroud)

"Dawson"在的第12 行的word比赛第13 "Dawson"行中names。它不会与list包含任何其他内容的其他任何内容匹配"Dawson"

"Dawson" %in% list(list("Dawson","Tom"))
#[1] FALSE
Run Code Online (Sandbox Code Playgroud)

不公开

...基本上表明整个names列都未列出,并且所有名称都 word根据

是的,就是这样。

申请+取消列出

sapply这里并没有做任何的names对象,因为unlist只有每一个列表项中运行呢:

identical(words_data$names, sapply(words_data$names, unlist))
#[1] TRUE
Run Code Online (Sandbox Code Playgroud)

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