R:有效地grep大数据行中的字符

时间:2014-09-04 14:21:31

标签: r grep dataframe

我有一个字符串的数据框,长度> 1M行:

>head(df)
     A    B     C     D
1   S1   S2    U1    U2
2   S1   S2    S2    S1
3   S2   S1    S1    S2
4   S1   M2    U1    S2
5   S1   S1    M2    M1
6   M2   M2    M1    M2

我想识别特定字符所在的所有行(例如," U")。 到目前为止我找到的解决方案正在运行,但它们非常慢,例如:

matches <- apply(as.matrix(df), 1, function(x){ sum(grepl("U", x, perl=T)) > 0 })

知道如何改进此查询吗? 谢谢!

4 个答案:

答案 0 :(得分:4)

编辑:更新地址评论:

以下也非常快(0.31秒,甚至比之前更快):

rows <- which(
  rowSums(
    `dim<-`(grepl("U", as.matrix(df), fixed=TRUE), dim(df))
  ) > 0
)

并产生与之前答案相同的结果。使用fixed=FALSE会使时间翻倍,但您的示例并不需要。

我们在这里做的是通过将grepl应用于矩阵来作弊,但我们真正关心的是将df转换为向量(矩阵是),以及{{1} }是更快的方法之一。然后我们可以运行一个as.matrix命令。最后,我们使用grepldim<-向量结果转换回矩阵,并使用grepl检查哪些行匹配。

以下是为什么这比你的版本快得多的原因:

  • 我们拨打rowSums一次,而不是像对grepl那样拨打一百万次,因为函数apply适用于每一行调用一次; apply是矢量化的,这意味着您希望最小化调用它的次数并利用矢量化
  • 我们使用grepl代替rowSums进行行匹配计数; applyrowSums的更快版本(请参阅apply(x, 1, sum)的文档)。

以前的答案:

这是一个相对简单的解决方案,在我的系统上以0.35秒的速度运行1MM行到4列数据帧:

?rowSums

确认

rows <- which(rowSums(as.matrix(df) == "U") > 0)

生成(每行都有一个U):

df[head(rows), ]

数据:

   a b c d
5  F B D U
8  R S U F
15 U L R P
20 U E E O
21 Y U D I
32 P F U H

答案 1 :(得分:2)

library(data.table)

df = fread("~/Rscripts/SO.csv")  # fast read
x = df[, lapply(.SD, function(x) x %like% "U")] # fast grep
y = x[, rowSums(x) > 0]
z = df[y,]

答案 2 :(得分:2)

如果您只是寻找字符的行索引,可以尝试一下。它应该比循环快得多。

unique(row(df)[grep("U", unlist(df))])
# [1] 1 4

答案 3 :(得分:1)

[这回答了原始问题,它与矩阵中的字符完全匹配,而不是正则表达式匹配]。强制转换为矩阵(无论如何都是正确的表示?),将每个元素与“U”进行比较(如果有多个可能感兴趣的值,则使用%in%)来创建逻辑矩阵,并计算行和;用它来原始

which(rowSums(as.matrix(df) == "U") > 0)

无需显式循环(通过apply或vapply);这些是'矢量化'计算和快速(虽然上面意味着创建了2个新矩阵,因此可以改进)。