2014-09-04 58 views
3

我有字符串的数据帧是有效的grep字符> 1M行长:R:在大data.frame行

>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

我编辑了示例data.frame来显示目标是识别data.frame中与查询匹配的元素,但可能不是严格相等(“==”)。这就是为什么我在第一个例子中使用grep的原因。对困惑感到抱歉。 – jul635 2014-09-04 14:44:29

回答

4

编辑:更新以解决意见:

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

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

,并产生相同的结果,以前的答案。使用fixed=FALSE大约加倍的时间,但你的例子并不需要这样做。

我们在这里所做的是通过将grepl一个矩阵,虽然作弊真的,我们关心的是转df成向量(其中一个矩阵)和as.matrix是更快的方法可以做到这一个东西。然后我们可以运行一个grepl命令。最后,我们使用dim<-grepl向量结果转换回矩阵,并使用rowSums来检查哪些行匹配。

这里有原因,这是不是您的版本快得多:

  • 我们称之为grepl一次,而不是一万次你因为函数apply申请得到的每一行调用一次与apply做; grepl是向量化的,这意味着您想要最小化您多次调用它并利用矢量化。
  • 我们用rowSums而不是apply执行行匹配计数; rowSumsapply(x, 1, sum)的更快版本(请参阅?rowSums的文档)。

以前的答案:

这里是0.35秒运行一次一个相对简单的解决方案在我的系统为1MM行乘4列的数据帧:

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

为了确认

df[head(rows), ] 

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

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 

并且数据:

set.seed(1) 
df <- as.data.frame(
    `names<-`(
    replicate(4, sample(LETTERS, 1e6, rep=T), simplify=F), 
    letters[1:4] 
) 
) 
+0

谢谢!但看到我上面的评论,这不完全回答我的问题... – jul635 2014-09-04 14:45:35

+0

@ jul635,请参阅更新。 – BrodieG 2014-09-04 14:56:33

1

[本回答原来的问题,这是字符的精确匹配在基质中,而不是正则表达式匹配。胁迫矩阵(无论如何,这是正确的表示?),将每个元素与“U”(如果存在多个可能的感兴趣值,则使用%in%)来创建逻辑矩阵,并计算行总和;使用该子集原始子集

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

不需要显式循环(通过apply或vapply);这些都是“向量化”的计算并且速度很快(尽管上述意味着创建2个新矩阵,所以可以改进)。

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

如果你只是在寻找字符的行索引,也许试试这个。它应该比循环更快。

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