我有一个数据表。列之一是单词列表。我想看看是否有任何一个单词出现在每一行的另一列中。我觉得这应该很容易,但是我没有得到我期望的结果。
困难之处似乎在于该列包括列表,也可能是不一致的(即,不是列出所有相同长度的列表,某些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)
从本质上讲,这只是一个隐藏的循环,但它可以工作:
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)
与大多数问题的尝试的问题是,他们没有考虑word和names片逐片在跨多个向量矢量化比较。Map或mapply会照顾这个:
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%上面的逻辑,以了解其为何无法按预期工作。