簡體   English   中英

通過匹配列來合並具有不同大小的兩個數據幀

[英]Merging two data frames with different sizes by matching their columns

如果列X和Y等於(我必須匹配dOne.X == dTwo.X & dOne.Y == dTwo.Y以及dOne.X == dTwo.Y & dOne.Y == dTwo.X我試圖在另一個中“合並”數據框的第V列dOne.X == dTwo.Y & dOne.Y == dTwo.X )我使用for循環解決了這個問題,但是當數據幀dOne很大時它很慢(在我的機器中如果length(dOne.X) == 500000需要25分鍾length(dOne.X) == 500000 )。 我想知道是否有辦法使用更快的“矢量化”操作來解決這個問題。 以上是我想要做的事例:

Data Frame ONE
X Y  V
a b  2
a c  3
a d  0
a e  0
b c  2
b d  3
b e  0
c d  2
c e  0
d e  0

Data Frame TWO
X Y  V
a b  1
a c  1
a d  1
b c  1
b d  1
c d  1
e d  1

Expected Data Frame after the columns are merged
X Y  V V2
a b  2  1
a c  3  1
a d  0  1
a e  0  0
b c  2  1
b d  3  1
b e  0  0
c d  2  1
c e  0  0
d e  0  1

這是我目前使用的代碼,當dOne很大(數十萬或幾行)時,這個代碼很慢:

copyadjlistValueColumn <- function(dOne, dTwo) {
    dOne$V2 <- 0

    lv <- union(levels(dOne$Y), levels(dOne$X))

    dTwo$X <- factor(dTwo$X, levels = lv)
    dTwo$Y <- factor(dTwo$Y, levels = lv)
    dOne$X <- factor(dOne$X, levels = lv)
    dOne$Y <- factor(dOne$Y, levels = lv)

    for(i in 1:nrow(dTwo)) {
      row <- dTwo[i,]
      dOne$V2[dOne$X == row$X & dOne$Y == row$Y] <- row$V
      dOne$V2[dOne$X == row$Y & dOne$Y == row$X] <- row$V
    }
    dOne
}

這是一個測試案例,涵蓋了我期望的內容(使用上面的數據框):

test_that("Copy V column to another Data Frame", {
    dfOne <- data.frame(X=c("a", "a", "a", "a", "b", "b", "b", "c", "c", "d"),
                        Y=c("b", "c", "d", "e", "c", "d", "e", "d", "e", "e"),
                        V=c(2, 3, 0, 0, 2, 3, 0, 2, 0, 0))

    dfTwo <- data.frame(X=c("a", "a", "a", "b", "b", "c", "e"),
                        Y=c("b", "c", "d", "c", "d", "d", "d"),
                        V=c(1, 1, 1, 1, 1, 1, 1))

    lv <- union(levels(dfTwo$Y), levels(dfTwo$X))
    dfExpected <- data.frame(X=c("a", "a", "a", "a", "b", "b", "b", "c", "c", "d"),
                             Y=c("b", "c", "d", "e", "c", "d", "e", "d", "e", "e"),
                             V=c(2, 3, 0, 0, 2, 3, 0, 2, 0, 0),
                             V2=c(1, 1, 1, 0, 1, 1, 0, 1, 0, 1))
    dfExpected$X <- factor(dfExpected$X, levels = lv)
    dfExpected$Y <- factor(dfExpected$Y, levels = lv)

    dfMerged <- copyadjlistValueColumn(dfOne, dfTwo)

    expect_identical(dfMerged, dfExpected)
})

有什么建議嗎?

非常感謝 :)

嘗試兩次merge ,其中匹配列的順序在第二次中反轉,以獲得“雙向”匹配。 然后,您可以使用例如rowSums將兩個創建的列折疊為一個。

d1 <- merge(dfOne, dfTwo, by.x = c("X", "Y"), by.y = c("X", "Y"), all.x = TRUE)
d2 <- merge(d1, dfTwo, by.x = c("X", "Y"), by.y = c("Y", "X"), all.x = TRUE)
cbind(dfOne, V2 = rowSums(cbind(d2$V.y, d2$V), na.rm = TRUE))


#    X Y V V2
# 1  a b 2  1
# 2  a c 3  1
# 3  a d 0  1
# 4  a e 0  0
# 5  b c 2  1
# 6  b d 3  1
# 7  b e 0  0
# 8  c d 2  1
# 9  c e 0  0
# 10 d e 0  1

要獲得更快的merge替代方案,請在此處檢查data.tabledplyr替代方案:stackoverflow.com/questions/1299871/how-to-join-data-frames-in-r-inner-outer-left-right/

這是一個可能的data.table包方法。 對於像您這樣的大數據集,這種方法應該特別有效:

首先轉換為data.table對象並添加鍵

library(data.table)
setkey(setDT(dfOne), X, Y)
setkey(setDT(dfTwo), X, Y)

然后,執行基於連接X & Y的組合-通過匹配鍵列進行連接X,YdfOne與鍵列X,YdfTwo分別。

dfOne[dfTwo, V2 := i.V]

現在執行基於連接Y & X組合-該連接通過匹配鍵列進行X,YdfOne與鍵列Y,XdfTwo分別。

setkey(dfTwo, Y, X)
dfOne[dfTwo, V2 := i.V][]

結果(我將保持不匹配的NA而不是零,因為這樣更有意義):

#     X Y V V2
#  1: a b 2  1
#  2: a c 3  1
#  3: a d 0  1
#  4: a e 0 NA
#  5: b c 2  1
#  6: b d 3  1
#  7: b e 0 NA
#  8: c d 2  1
#  9: c e 0 NA
# 10: d e 0  1

使用dplyr

library(dplyr)

left_join(dfOne, dfTwo, by = c("X", "Y")) %>% 
  left_join(dfTwo, by = c("X" = "Y", "Y" = "X")) %>% 
  mutate(V2 = ifelse(is.na(V.y), V, V.y)) %>% 
  select(X, Y, V = V.x, V2) %>% 
  do(replace(., is.na(.), 0))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM