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

问题描述 投票:1回答:4

基于data.table,DT,带有m个字符串列,如何标记字符串中的行,比如说“BlaBla”出现在至少一列中?

我想要的是:

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

我不想明确引用列名。相反,我需要将第2列引用到DT中的最大列号(可能是: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)
r list data.table
4个回答
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

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
投票

这是与.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,强制转换为整数时为二进制。


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)

© www.soinside.com 2019 - 2024. All rights reserved.