2016-02-03 39 views
11

對填充值爲0的兩個數據表(dt1,dt2)執行左外連接最簡單的方法是什麼?值)而不是NA(默認)而不覆蓋左側數據表中的有效NA值?R左外連接有0填充而不是NA,同時保留左表中的有效NA

一個常見的答案,如在this thread是做左外連接與任一dplyr::left_join或​​或data.table的DT2 [DT1]鍵控立柱支架的語法,接着簡單地通過0在替換所有NA值的第二步驟聯合數據表。例如:

library(data.table); 
dt1 <- data.table(x=c('a', 'b', 'c', 'd', 'e'), y=c(NA, 'w', NA, 'y', 'z')); 
dt2 <- data.table(x=c('a', 'b', 'c'), new_col=c(1,2,3)); 
setkey(dt1, x); 
setkey(dt2, x); 
merged_tables <- dt2[dt1]; 
merged_tables[is.na(merged_tables)] <- 0; 

這種做法必然假定有一些需要保存沒有有效的NA值dt1。然而,正如可以在上面的例子中看到的,結果是:

x new_col y 
1: a  1 0 
2: b  2 w 
3: c  3 0 
4: d  0 y 
5: e  0 z 

但所期望的結果是:

x new_col y 
1: a  1 NA 
2: b  2 w 
3: c  3 NA 
4: d  0 y 
5: e  0 z 

在這種簡單的情況,而不是使用data.table所有元素替換語法如上,只是new_col的NA值可以代替:

library(dplyr); 
merged_tables <- mutate(merged_tables, new_col = ifelse(is.na(new_col), 0, new_col)); 

然而,這種方法不是非常大的數據集,其中數十或數百個實用的新列被合併,有時還會動態創建列名。即使列名都是事先知道的,但列出所有新列並且在每個列上進行mutate樣式替換是非常難看的。

必須有更好的方法嗎?如果dplyr::left_join,​​或data.table的括號中的任何一個的語法都容易允許用戶指定除NA之外的其他值fill,則問題將簡單解決。喜歡的東西:

merged_tables <- data.table::merge(dt1, dt2, by="x", all.x=TRUE, fill=0); 

data.tabledcast功能允許用戶指定fill價值,所以我想一定有可以做到這一點,我只是沒有想到的一個更簡單的方法。

對此提出建議?

編輯:@jangorecki在評論中指出,目前data.table GitHug page上正在打開的功能請求正是我剛纔提到的,更新了nomatch=0語法。應該在data.table的下一個版本中。

+1

在你'merge'的端部,或使用外部聯接'[...,NOMATCH = NA]'鏈data.table查詢'合併()[is.na (col),col:= 0]'。有一個開放的FR,所以'nomatch' arg可以處理任意值,目前對於外連接它只能使用'NA'。 – jangorecki

+0

我很抱歉,但我無法理解您的答案。 'col'從哪裏來?很高興聽到有一個開放的功能請求。我會爲其添加+1。 –

+0

'col'只是一個正在進行連接的列 – jangorecki

回答

2

您可以使用列索引僅引用新列嗎?與left_join一樣,它們都將位於生成的data.frame的右側?這將是在dplyr:

dt1 <- data.frame(x = c('a', 'b', 'c', 'd', 'e'), 
        y = c(NA, 'w', NA, 'y', 'z'), 
        stringsAsFactors = FALSE) 
dt2 <- data.frame(x = c('a', 'b', 'c'), 
        new_col = c(1,2,3), 
        stringsAsFactors = FALSE) 

merged <- left_join(dt1, dt2) 
index_new_col <- (ncol(dt1) + 1):ncol(merged) 
merged[, index_new_col][is.na(merged[, index_new_col])] <- 0 

> merged 
    x y new_col 
1 a <NA>  1 
2 b w  2 
3 c <NA>  3 
4 d y  0 
5 e z  0 
+0

當使用'dplyr :: left_join'時,如果它是data.table,是否可以保證它們在結果data.frame的右邊?請注意,在'data.table'示例中,列被插入到鍵列的右側,而不是所有現有的'x'列的右側。 –

+1

'left_join'可靠地將右/右表中的列放在右邊。我不知道如何使用它的合併函數''data.table'命令列。我用'data.frame'對象做了這個例子,因爲data.table包裹重載了我最後一行的''',但是當我'left_join'這兩個'data.table'時,我得到了相同的列順序。除了卸載data.table以在我的示例中運行最後一行,在連接之前可以用'as_data_frame'強制對象 - 或者知道'data.table'的人可以使最後一行工作,就像它在基本R中一樣工作 –

+0

謝謝你的回答。我正在處理非常大的數據集,所以每次我進行合併時(我都做了很多),我都有點擔心在data.table和data.frame之間切換。我會做一些性能測試,看看它是否可行。直到'data.table' v1.9.8發佈'nomatch'的新選項時,你的答案可能是最好的答案。 –

1

目前最乾淨的方式可以簡單地是種子與所述值的中間表中的左邊的表(DT1)被接合上,鏈條DT2的合併,設置NA值爲0,將中間表與dt1合併。可以用data.table完全完成,並不依賴於data.frame語法和中間步驟可以確保不會有nomatch NA導致第二合流:

library(data.table); 
dt1 <- data.table(x=c('a', 'b', 'c', 'd', 'e'), y=c(NA, 'w', NA, 'y', 'z')); 
dt2 <- data.table(x=c('a', 'b', 'c'), new_col=c(1,2,3)); 
setkey(dt1, x); 
setkey(dt2, x); 
inter_table <- dt2[dt1[, list(x)]]; 
inter_table[is.na(inter_table)] <- 0; 
setkey(inter_table, x); 
merged <- inter_table[dt1]; 

> merged; 
    x new_col y 
1: a  1 NA 
2: b  2 w 
3: c  3 NA 
4: d  0 y 
5: e  0 z 

這種方法的好處是,它不」 t取決於右側添加的新列,並保持在鍵控速度優化範圍內。歸功於@SamFirke的答案,因爲他的解決方案也可行,在其他情況下可能更有用。

0

我偶然發現了與dplyr相同的問題,並寫了一個小函數來解決我的問題。 (解決方案需要tidyr和dplyr)

left_join0 <- function(x, y, fill = 0L){ 
    z <- left_join(x, y) 
    tmp <- setdiff(names(z), names(x)) 
    z <- replace_na(z, setNames(as.list(rep(fill, length(tmp))), tmp)) 
    z 
}