检查字符串是否出现在data.table的任何列中(第一列除外)

时间:2019-03-31 07:27:27

标签: r list data.table

基于具有m个字符串列的data.table DT,如何标记至少一个列中出现字符串的行(例如,“ BlaBla”)?

我想要的是:

DT[, flag_BlaBLa:=(test if "BlaBLa" appears in any column except the first one)]

我不想明确引用列名。相反,我需要将col 2引用为DT中的最大col编号(也许:2:ncol(DT))。为什么不?实际上,我有一个data.frames列表,每个列表中的列数都不同。如上所述,我需要为列表中的所有data.frames创建标记。

Edit1:添加一个可复制的示例。 Edit2:将某些“ BlaBLa”字符串更改为“ BlaBLa + something”。还应将此匹配项视为匹配项,因为它们包括“ BlaBLa”。

DT以cols a,b,c开头,我想要一个脚本来创建flag_BlaBLa。最终结果将是:

DT <- data.table(a=c("x","y","z",'w'),
                 b=c('BlaBLa','BLe','Bli','BlaBLaSometing'), 
                 c=c('Bla','BLe','BlaBLa','Blo'), 
                 flag_BlaBLa=c(T,F,T,T)
                 )

对于列表,最终结果应为:

DT1 <- data.table(a=c("x","y","z",'w'),
                 b=c('BlaBLa','BLe','Bli','BlaBLaSomething'), 
                 c=c('Bla','BLe','BlaBLa','Blo'), 
                 flag_BlaBLa=c(T,F,T,T)
                 )

DT2 <- data.table(a=c("q","j","p"),
                 b=c('BLe','Bli','BlaBLa'), 
                 flag_BlaBLa=c(F,F,T)
                 )
l <- list(DT1,DT2)

4 个答案:

答案 0 :(得分:3)

我们可以在.SDcols中指定感兴趣的列,遍历data.table(.SD)的子集,检查它是否等于'BlaBLa',Reduce使其成为单个逻辑vector创建列

library(data.table)
lapply(l, function(x) x[, flag_BlaBLa := Reduce(`|`, lapply(.SD, `==`, 
           "BlaBLa")), .SDcols = 2:ncol(x)][])
#[[1]]
#   a      b      c flag_BlaBLa
#1: x BlaBLa    Bla        TRUE
#2: y    BLe    BLe       FALSE
#3: z    Bli BlaBLa        TRUE
#4: w BlaBLa    Blo        TRUE

#[[2]]
#   a      b flag_BlaBLa
#1: q    BLe       FALSE
#2: j    Bli       FALSE
#3: p BlaBLa        TRUE

答案 1 :(得分:1)

我们可以遍历列表,选择列,然后检查任何一行中是否至少有一个“ BlaBLa”并标记行TRUE / FALSE

library(data.table)
lapply(l, function(x) x[, flag_BlaBLa := rowSums(x[,2:ncol(x)] == "BlaBLa") > 0])


l
#[[1]]
#   a      b      c flag_BlaBLa
#1: x BlaBLa    Bla        TRUE
#2: y    BLe    BLe       FALSE
#3: z    Bli BlaBLa        TRUE
#4: w BlaBLa    Blo        TRUE

#[[2]]
#   a      b flag_BlaBLa
#1: q    BLe       FALSE
#2: j    Bli       FALSE
#3: p BlaBLa        TRUE

编辑

如果这不是完全匹配,并且我们需要找到该字符串的模式,那么在使用rowSums

之前,我们还需要遍历各列(类似于@MichaelChirico)

lapply(l, function(x) x[, flag_BlaBLa := rowSums(sapply(x[, 2:ncol(x)],
                      grepl, pattern = 'BlaBLa', fixed = TRUE)) > 0])


#[[1]]
#   a               b      c flag_BlaBLa
#1: x          BlaBLa    Bla        TRUE
#2: y             BLe    BLe       FALSE
#3: z             Bli BlaBLa        TRUE
#4: w BlaBLaSomething    Blo        TRUE

#[[2]]
#   a      b flag_BlaBLa
#1: q    BLe       FALSE
#2: j    Bli       FALSE
#3: p BlaBLa        TRUE

答案 2 :(得分:1)

这是使用.SDcols

的方法
require(dplyr)
require(data.table)
require(stringr)

DT <- DT[, key_ := do.call(paste, c(.SD, sep = "_")), .SDcols = 2:ncol(DT)]
DT <- DT[, has_blabla := as.integer(str_detect(key_, "BlaBla"))]

第一个创建键,每行所有列值均以'_'分隔。然后,下一个对其进行搜索并将其标记为二进制。搜索返回TRUEFALSE,将其强制为整数时为二进制。

答案 3 :(得分:1)

我将在列表上使用for循环,在列上使用sapply,并使用.SDcols排除第一个:

for (ii in seq_along(l)) {
  l[[ii]][ , .SDcols = -1L, 
          flag_BlaBLa := any(sapply(.SD, grepl, pattern = 'BlaBLa', fixed = TRUE))] 
}

请注意,由于您实际上并未使用任何正则表达式,因此fixed = TRUE是使用grepl的更有效的选择。如果您要检测的模式确实是正则表达式,请删除fixed = TRUE

如果不是所有的列都是字符串列,则可以通过使.SDcols更严格(例如

)来提高效率。
.SDcols = intersect(2:ncols(l[[ii]]), which(sapply(l[[ii]], is.character)))

(或可能使用is.character(x) || is.factor(x)