我有一个字符串的数据框,长度> 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 })
知道如何改进此查询吗? 谢谢!
答案 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
命令。最后,我们使用grepl
将dim<-
向量结果转换回矩阵,并使用grepl
检查哪些行匹配。
以下是为什么这比你的版本快得多的原因:
rowSums
一次,而不是像对grepl
那样拨打一百万次,因为函数apply
适用于每一行调用一次; apply
是矢量化的,这意味着您希望最小化调用它的次数并利用矢量化grepl
代替rowSums
进行行匹配计数; apply
是rowSums
的更快版本(请参阅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个新矩阵,因此可以改进)。