我有一个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
答案 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
该问题中大多数尝试的问题在于,它们在跨多个向量的向量化比较中没有逐个考虑word
和names
。 Map
或mapply
将负责以下工作:
mapply(paste, 1:3, letters[1:3])
#[1] "1 a" "2 b" "3 c"
其他结果不起作用的原因多种多样。例如:
这将依次比较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
均已进行了检查”
是的,就是这样。
这里的sapply
对names
对象没有任何作用,因为unlist
始终只在每个列表项中运行:
identical(words_data$names, sapply(words_data$names, unlist))
#[1] TRUE
然后,您可以参考上面的%in%
逻辑,以了解其为何无法按预期工作。