2014-09-04 250 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