2013-02-06 42 views
4

我的問題與張貼的here非常相似。合併數據幀,同時對R中的公共列進行求和

不同之處在於他們知道將會發生衝突的列,而我需要一種不會事先知道哪些列發生衝突的通用方法。

例如:

TABLE1 
Date    Time ColumnA ColumnB 
01/01/2013  08:00  10   30 
01/01/2013  08:30  15   25 
01/01/2013  09:00  20   20 
02/01/2013  08:00  25   15 
02/01/2013  08:30  30   10 
02/01/2013  09:00  35   5 

TABLE2 
Date   ColumnA ColumnB ColumnC 
01/01/2013  100  300   1 
02/01/2013  200  400   2 

表2只具有日期,並因此被施加到表A無論匹配的日期,關於時間的所有字段。

我想合併總結衝突列進1結果應該是這樣的:

TABLE3 
Date    Time ColumnA ColumnB ColumnC 
01/01/2013  08:00  110   330  1 
01/01/2013  08:30  115   325  1 
01/01/2013  09:00  120   320  1 
02/01/2013  08:00  225   415  2 
02/01/2013  08:30  230   410  2 
02/01/2013  09:00  235   405  2 

在我的標準合併只是創建「ColumnA.x」的重複列的那一刻,「ColumnA .y「,」ColumnB.x「,」ColumnB.y「。

任何幫助深表感謝

+0

我可能不會合並。我會rbind.fill然後聚合的關鍵列與data.table或ddply – frankc

+0

聽起來不錯,到目前爲止,你能否詳細說明?合併到目前爲止我的能力達到頂峯,尚未使用任何這些功能。 – EvilWeebl

回答

4

如果我理解正確,您需要一個靈活的方法,不需要知道除了要合併的列和要保留的列之外,每個表中存在哪些列。這可能不是最完美的解決方案,但在這裏是爲了滿足您的需求爲例功能:

merge_Sum <- function(.df1, .df2, .id_Columns, .match_Columns){ 
    merged_Columns <- unique(c(names(.df1),names(.df2))) 
    merged_df1 <- data.frame(matrix(nrow=nrow(.df1), ncol=length(merged_Columns))) 
    names(merged_df1) <- merged_Columns 
    for (column in merged_Columns){ 
     if(column %in% .id_Columns | !column %in% names(.df2)){ 
      merged_df1[, column] <- .df1[, column] 
     } else if (!column %in% names(.df1)){ 
      merged_df1[, column] <- .df2[match(.df1[, .match_Columns],.df2[, .match_Columns]), column] 
     } else { 
      df1_Values=.df1[, column] 
      df2_Values=.df2[match(.df1[, .match_Columns],.df2[, .match_Columns]), column] 
      df2_Values[is.na(df2_Values)] <- 0 
      merged_df1[, column] <- df1_Values + df2_Values 
     } 
    } 
    return(merged_df1) 
} 

此函數假設你有一個表」 .df1' 這是各種各樣的高手,你要合併具有匹配'.df1'中的一個或多個行的行的第二個'.df2'表中的數據。從主表'.df1'保留的列被接受爲數組'.id_Columns',並且提供用於合併兩個表的匹配的列被接受爲數組。'match_Columns'

對於您的示例,它的工作是這樣的:

merge_Sum(table1, table2, c("Date","Time"), "Date") 

# Date  Time ColumnA ColumnB ColumnC 
# 1 01/01/2013 08:00  110  330  1 
# 2 01/01/2013 08:30  115  325  1 
# 3 01/01/2013 09:00  120  320  1 
# 4 02/01/2013 08:00  225  415  2 
# 5 02/01/2013 08:30  230  410  2 
# 6 02/01/2013 09:00  235  405  2 

在簡單的語言,該功能首先找到唯一列的總數量,使在主表中的形狀的空數據幀」 .df1' 以後保持合併數據。然後,對於'.id_Columns',將數據從'.df1'複製到新的合併數據幀中。對於其他列,存在於'中的任何數據。'.df2'中的任何現有數據都添加了'df1',其中'.df2'中的行基於'.match_Columns'匹配。

可能有一些軟件包做類似的操作,但大多數他們需要了解所有現有的專欄以及如何對待它們。正如我之前所說,這不是最優雅的解決方案,但它靈活而準確。

更新:原始函數假設table1和table2之間存在多對一關係,並且OP也請求允許多對一關係。該代碼已被更新,但效率稍低,但靈活性更高100%。

+0

這看起來非常出色,我會嘗試一下,但是關於'.id_columns'的一個簡短問題,我知道它需要日期和時間,因爲它們具體,不會被覆蓋,但它們似乎是隻有一些最初被複制過來,如果我的table1有一個名爲columnZ的列在table2中不匹配怎麼辦?我需要在「id_columns」中指定不匹配的所有列嗎? – EvilWeebl

+1

不可以。只有您想要保留的已知列需要位於'.id_Columns'參數中。這些是您希望函數基本忽略的列,並且直接複製。否則,僅存在於一個表中的其他列將被罰款,但只能在計算兩個表中的存在並嘗試將這些值加在一起之後才能複製。 – Dinre

+0

這是工作出色,我有一個小小的打嗝在表1中,如果有一個日期表的行沒有的行,那麼公共列的值被設置爲NA,而不是採取表1的值,但除此之外它是偉大的。謝謝! – EvilWeebl

3

一個data.table解決方案:

dt1 <- data.table(read.table(header=T, text="Date    Time ColumnA ColumnB 
01/01/2013  08:00  10   30 
01/01/2013  08:30  15   25 
01/01/2013  09:00  20   20 
02/01/2013  08:00  25   15 
02/01/2013  08:30  30   10 
02/01/2013  09:00  35   5")) 

dt2 <- data.table(read.table(header=T, text="Date   ColumnA ColumnB ColumnC 
01/01/2013  100  300   1 
02/01/2013  200  400   2")) 

setkey(dt1, "Date") 
setkey(dt2, "Date") 
# Note: The ColumnC assignment has to be come before the summing operations 
# Else it gives out error (see below) 
dt1[dt2, `:=`(ColumnC = i.ColumnC, ColumnA = ColumnA + i.ColumnA, 
         ColumnB = ColumnB + i.ColumnB)] 

#   Date Time ColumnA ColumnB ColumnC 
# 1: 01/01/2013 08:00  110  330  1 
# 2: 01/01/2013 08:30  115  325  1 
# 3: 01/01/2013 09:00  120  320  1 
# 4: 02/01/2013 08:00  225  415  2 
# 5: 02/01/2013 08:30  230  410  2 
# 6: 02/01/2013 09:00  235  405  2 

我不知道爲什麼把右端ColumnC分配拋出這個錯誤。也許MatthewDowle可以解釋這個錯誤的原因。從v1.8.9

dt1[dt2, `:=`(ColumnA = ColumnA + i.ColumnA, ColumnB = ColumnB + i.ColumnB, 
         ColumnC = i.ColumnC)] 

Error in `[.data.table`(dt1, dt2, `:=`(ColumnA = ColumnA + i.ColumnA, : 
    Value of SET_STRING_ELT() must be a 'CHARSXP' not a 'NULL' 

更新:

ö混合添加新的與更新現有列到一個:=()由基;即
DT[,:= (existingCol=...,newCol=...), by=...]
現在可以正常工作,或者 段錯誤,#2778和#2528。非常感謝Arun報告具有可重複性的例子。添加了測試。

+0

這看起來確實不錯,但是您忘記了Table2將成爲一個我完全不瞭解的表,它可能包含匹配或不匹配的列,因此我無法明確選擇要綁定的列。也許像for循環匹配列名稱的東西? – EvilWeebl

+1

'ColumnC'正被添加到'dt1',但ColumnA和ColumnB正在更新。似乎有一個錯誤在這裏混合添加/更新不喜歡增加在最後出於某種原因。謝謝!已提交[bug#2528](https://r-forge.r-project.org/tracker/index.php?func=detail&aid=2528&group_id=240&atid=975)。 –

+0

有關如何在運行時不知道衝突列的情況下應用此任何想法? – EvilWeebl