应用 grepl 检查数据 table 列值与列表元素的匹配,并添加结果列

Applying grepl to check for match of data table column values with list elements, and adding resulting column

我这里有两个问题。第一个是我没有从 grepl 函数获得预期的输出,第二个是我无法根据函数调用的结果正确应用循环来添加新列。

myList <- list(a = 1:3, b = 4:6)

myList
$a
[1] 1 2 3
$b
[1] 4 5 6

myData <- data.frame(
    X = sample(1:10),
    Y = sample(c("yes", "no"), 10, replace = TRUE)
)   
myData$Z = NA
myData <- as.data.table(myData) # seems necessary for grepl to work properly?

myData

    X   Y  Z
1:  9 yes NA
2:  1  no NA
3:  4 yes NA
4:  6 yes NA
5:  7  no NA
6:  2  no NA
7:  5  no NA
8:  8  no NA
9: 10  no NA
10: 3  no NA

sapply(myData[,X], function(x) grepl(x,myList))

#      [,1]  [,2]  [,3]  [,4]  [,5]  [,6]  [,7]  [,8]  [,9] [,10]
# [1,] FALSE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE  TRUE
# [2,] FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE FALSE FALSE FALSE

输出正在检查 myData$X 中的值是否包含在 myList 中。我的理解是输出的第一行匹配myList$a,第二行匹配myList$b。但是,对于 myData$X 的第二行和最后一行,输出的第一行已正确声明为 TRUE,即分别为 X == 1 和 3。但是,对于第六行,它 returns FALSE,其中 X == 2。我认为应该 return TRUE,因为 2 包含在 myList$a.

类似地,输出的第二行为 myData$X 第 3 行和第 4 行提供 TRUE,其中 myData$x == 4 和 6。但是,对于第 7 行,它不 return TRUE,其中 myData$X == 5。(myList$b 包含 4、5 和 6。)

~~~

我的第二个问题是如何应用一个循环来用列表元素的标题覆盖 myData$Z,如果 grepl return 该特定行为 TRUE。期望的输出:

    X   Y  Z
1:  9 yes NA
2:  1  no a
3:  4 yes b
4:  6 yes b
5:  7  no NA
6:  2  no a
7:  5  no b
8:  8  no NA
9: 10  no NA
10: 3  no a

我认为类似下面的方法可能会起作用,但它 return 有六个警告消息并且没有产生所需的输出:

for (i in myList) {
myData$Z[sapply(myData[,X], function(x) (grepl(x,myList)))] <- i
}

提前感谢您的任何意见。

不需要as.data.table(),你只是忘了引用列名。除非你想要更高级的部分匹配,否则不需要 grep().

有字符串和多重匹配

myList2 <- list(pet = c("cat", "dog", "horse", "bunny"), 
               food = c("pig", "chicken", "cow", "bunny"))

set.seed(1)
myData2 <- data.frame(
    X = sample(unique(unlist(myList2))),
    Y = sample(c("yes", "no"), 7, replace = TRUE)
)   

exist2 <- sapply(myList2, function(x) myData2[,"X"] %in% x)

Z <- apply(exist2, 1, function(x) names(which(x)))
myData2$Z <- sapply(Z, function(x) 
  ifelse(length(x) == 0, NA, paste(x, collapse="+")))

myData2
#         X   Y        Z
# 1     dog  no      pet
# 2   horse  no      pet
# 3 chicken yes     food
# 4   bunny yes pet+food
# 5     cat yes      pet
# 6     cow  no     food
# 7     pig yes     food

您可以 melt 列表和 merge 数据框:

merge(myData, reshape2::melt(myList), by.x = "X", by.y = "value", all.x = TRUE)

#      X   L1
#  1   1 <NA>
#  2   2    a
#  3   3    a
#  4   4    a
#  5   5 <NA>
#  6   6 <NA>
#  7   7 <NA>
#  8   8    b
#  9   9    b
# 10  10    b

数据:

myData <- data.frame(X = 1:10)
myList <- list(a = 2:4, b = 8:10)