2017-01-22 45 views
2

我有兩個數據幀,比如A和B,它們的大小相等(行和列)。我想輸出數據框,說C,與所有的值或者大小相同0 1比較每個單元格在R中具有相同大小的兩個數據幀中的相等性。

C[i,j] = 0, if A[i,j] != B[i,j] 
C[i,j] = 1, if A[i,j] == B[i,j] 

的我不想使用循環或ifelse語句,我已經成功地做到這一點,但它需要很長時間。如果還有其他方法可以做到這一點,那將非常有幫助。感謝

+0

是否有一個原因,您希望將結果C作爲'data.frame'而不是e。 G。作爲矩陣? –

+0

當有人發佈答案時,刪除問題並不合適 – akrun

回答

6

只需比較兩個data.frame s至得到一個matrix具有相同的大小和邏輯在所述細胞指示比較結果:

A <- mtcars 
B <- mtcars 

A == B 

結果(僅示出第一行):

     mpg cyl disp hp drat wt qsec vs am gear carb 
Mazda RX4   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
Mazda RX4 Wag  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
Datsun 710   TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
Hornet 4 Drive  TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 

從比較使用得到data.frame

C <- as.data.frame(A == B) 

您可以使用一個事實,即TRUE == 1和R中FALSE == 0(作爲OP要求)將結果對象轉換成明確的整數

as.data.frame(lapply(as.data.frame(A == B), as.integer)) 

乘以1(在另議回答)是漂亮,可能更有效的(避免了:

as.data.frame(1 * (A == B)) 

編輯++ [基準加入;基準改進的一致性]:

基於data.frame s與10 Mio的不同答案之間的基準。行(260 MB)...

library(microbenchmark) # install.packages("microbenchmark") 
library(data.table) 

A <- data.frame(col1 = 1:1E7, 
       col2 = rep(c("a string", "another string"), 1E7/2), 
       col3 = 1:1E7, 
       col4 = 1:1E7, 
       col5 = rep(LETTERS[1:10],1E6), 
       stringsAsFactors = FALSE) 
B <- A 
B[1,1]=100 # change one cell to create a copy of the data.frame 

microbenchmark(DF.equals  = as.data.frame(A == B), 
       DF.mult   = as.data.frame(1 * (A == B)), 
       DF.map   = as.data.frame(Map(`==`, A, B)), 
       matrix.equals = A == B, 
       matrix.mult  = 1 * (A == B), 
       matrix.map  = do.call(cbind, Map(`==`, A, B)), # causes a warning: duplicated levels in factors are deprecated 
       list.map  = Map(`==`, A, B),     # fast cause it does not construct a matrix but only vectors 
       times = 100) 

顯示Map()功能以明顯優勢勝出(我的系統上)爲2至4倍的速度作爲其他變體,並且將結果作爲matrixdata.frame快得多:

Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
    DF.equals 627.2541 630.7565 654.0266 635.1831 678.8903 686.0753 100  e 
     DF.mult 743.8531 751.7933 781.1876 796.2282 799.1881 848.2455 100  f 
     DF.map 169.6967 170.5842 176.5944 171.5072 173.5665 223.3354 100 a  
matrix.equals 294.2570 297.5330 311.8095 299.8093 345.0827 351.9193 100 c 
    matrix.mult 402.6166 406.5279 422.9322 408.3012 453.4484 602.2139 100 d 
    matrix.map 206.2596 208.4230 217.8891 209.8968 211.4139 266.1867 100 b  
     list.map 169.1922 170.5403 175.7539 171.4602 173.3891 224.7062 100 a 

BTW:

我真正喜歡的是你可以做一些統計,現在,E。 G。算上每列不匹配的數量(或如果您使用rowSums不是行):

colSums(C != TRUE) 

colSums(A != B) 

獲得可用於先決條件的自動檢查結果(允許如無錯配):

mpg cyl disp hp drat wt qsec vs am gear carb 
    0 0 0 0 0 0 0 0 0 0 0 
+0

感謝您抽出時間做基準測試。 – akrun

+0

你的基準沒有多大意義。爲什麼'Map'答案是唯一沒有'data.frame'包裝的答案?你也主要比較不同'data.frame'包裝器之間的性能,它與IIRC問題無關。另外,無論如何,將其轉換爲'data.frame'有什麼意義?如何布爾'data.frame'比布爾'矩陣'更好?你基本上有兩個方法'''do.call(cbind,Map('==',A,B))'''而不是'A == B' –

+0

@DavidArenburg:公平點,我會重新考慮我的基準。關於'data.frame':OP請求它「我想輸出一個數據幀,比如說C,大小相同,所有值都是0或1」,但實際上我們應該問他/她爲什麼不使用矩陣。 –

4

嘗試:

C <- data.frame(1 * (A == B)) 

1*用於根據需要將TRUE/FALSE設置爲0/1。

+0

對你爲什麼包含'1 *'而不僅僅是'A == B' – G5W

+0

@ G5W完成評論可能會有所幫助,謝謝。 –

1

本示例生成可在R上有效地視爲一個0/1 T/F矩陣

x = matrix(1:9, nrow = 3) 
y = matrix(9:1, nrow = 3) 
x == y 

由於有一對夫婦的答案其他建議我想我測試哪些是因爲這是問題的要求,所以最快。

這裏等於是指A == B解決方案,map_xy是Map解決方案。

microbenchmark(equals(x,y), map_xy(x,y), times = 1000) 
Unit: nanoseconds 
     expr min lq  mean median uq max neval 
equals(x, y) 360 399 468.491 459.0 508 3473 1000 
map_xy(x, y) 10909 12114 13506.830 13132.5 14158 77743 1000 

看起來平等是一個更快的選擇 - 但作爲Map答案表明它可能具有更大的數據集有更好的表現。所以我再次測試了合理大小的數據:

x_big = matrix(1:900000, nrow = 3) 
> y_big = matrix(900000:1, nrow = 3) 
> microbenchmark(equals(x_big,y_big), map_xy(x_big,y_big), times = 100) 
Unit: milliseconds 
       expr  min   lq  mean  median   uq 
equals(x_big, y_big) 1.579069 2.118332 2.515257 2.225747 2.375377 
map_xy(x_big, y_big) 846.172497 1040.383027 1165.354138 1147.239396 1321.166762 
     max neval 
    21.48414 100 
1489.81884 100 

這表明等於仍然是更快的選項。

編輯

在迴應此評論是每個函數的代碼。我已經編輯這些輕微的輸出轉換爲data.frame(雖然我個人認爲這一步是不必要的)

equals = function(x,y){ 
    as.data.frame(x == y) 
} 

map_xy = function(x,y){ 
    Map('==', x, y) %>% 
    unlist(.) %>% 
    matrix(., nrow = 3) %>% 
    as.data.frame(.) 
} 

這改變了基準測試結果,但沒有結果的:

對於小矩陣:

Unit: microseconds 
     expr  min  lq  mean median  uq  max neval 
equals(x, y) 18.090 20.3205 24.31075 22.0205 23.7285 781.048 1000 
map_xy(x, y) 172.699 186.0775 209.39585 193.3645 204.0220 2646.419 1000 

對於大型矩陣:

Unit: milliseconds 
       expr  min  lq  mean median  uq  max 
equals(x_big, y_big) 533.3274 646.0605 744.063 705.4923 871.3479 1067.411 
map_xy(x_big, y_big) 1637.2882 1820.8714 1938.458 1921.2563 2041.0533 2564.669 
neval 
    100 
    100 

如果你想在福我最初使用的nctions - 只是拿出代碼轉換成d​​ata.frame。

+0

+1爲您的努力做一個基準。你可以添加'equals'和'map_xy'函數的代碼來獲得重現性嗎?請注意,OP要比較兩個'data.frame's而不是兩個矩陣,所以結果可能會完全不同(特別是當某些列是字符串列時)。謝謝! –

+0

已更新。此外,基準測試對於圖書館微型基準測試來說非常簡單!所以不知道我是否值得努力點哈哈。 – SamPassmore

4

我們可以使用Map比較兩個data.frame「A」和「B」的相應列

Map(`==`, A, B) 

的好處是,我們得到的邏輯vector一個list!而非一個matrix在工作區。如果數據集真的很大,可能會限制內存使用矩陣輸出

+2

好主意,'Map'在內部使用'mapply',因此避免了在內存中構建完整的矩陣。這允許對「每列基數」進行統計,這種統計不會使用過多的內存,但一次只能有一列邏輯向量。 E. g .:通過映射(函數(a,b)sum(a!= b),A,B)計算每列失配的數量' –

+0

這個答案在性能方面明顯勝出(參見[我的答案](http://stackoverflow.com/a/41790501/4468078))。 –

相關問題