簡體   English   中英

R:在兩個數據幀(例如vlookup)中匹配值,但對於不帶Key [大數據]的多個條件

[英]R: Match values in two data frames like vlookup but for multiple criteria without Key [large data]

我有兩個來自兩個單獨來源的大型數據框(500k行),沒有密鑰。 與其能夠使用鍵進行合並,不如通過匹配其他列來合並兩個數據框。 如年齡和數量。 這不是兩個數據幀之間的完美匹配,因此某些值將不匹配,我稍后將簡單地刪除這些值。

數據可能看起來像這樣。

在此處輸入圖片說明

因此,在上面的示例中,我希望能夠創建一個與鍵1和鍵2匹配的表。在上圖中,我們看到XXX1和YYY3是匹配項。 所以從這里我想創建一個像這樣的數據框:

[鍵1] [鍵2]

XXX1 YYY3

XXX2不適用

XXX3不適用

我知道如何在Excel中執行此操作,但是由於大量數據,它只會崩潰。 我想專注於R,但是對於它的價值,這是我在Excel中構建它的方式(其思想是我們首先執行VLOOKUP,然后使用INDEX作為VLOOKUP來獲得第二個匹配項,如果第一個匹配的話)不符合這兩個條件):

=IF(P2=0;IFNA(VLOOKUP(L2;B:C;2;FALSE);VLOOKUP(L2;G:H;2;FALSE));IF(O2=Q2;INDEX($A$2:$A$378300;SMALL(IF($L2=$B$2:$B378300;ROW($B$2:$B$378300)-ROW($B$2)+1);2));0))

這是R中的方法:

for (i in 1:nrow(df)) {
  for (j in 1:nrow(df)) {
    if (df_1$pc_age[i] == df_2$pp_age[j] && (df_1$amount[i] %in% c(df_2$amount1[j], df_2$amount2[j], df_2$amount3[j]))) {
      df_1$Key1[i] = df_2$Key2[j]
    } else (df_1$Key1[i] = N/A)
  }}

問題是這需要很長的路要走。 有沒有更有效的方法來盡可能更好地映射此數據?

謝謝!

在兩個數據框中創建虛擬列,例如(我可以為df1展示):

 for(i in 1:nrow(df1)){
 df1$key1 <- paste0("X_",i)
 }

同樣,對於Y1 .... Yn中的df2,然后使用“合並”列年齡和金額對兩個數據框進行合並。 將Key1和key2連接到合並數據框中的新列中。 您將直接獲得所需的數據框。

以下代碼可以為您工作嗎?

# create random data
set.seed(123)
df1 <- data.frame(
  key_1=as.factor(paste("xxx",1:100,sep="_")),
  age = sample(1:100,100,replace=TRUE),
  amount = sample(1:200,100))

df2 <- data.frame(
  key_1=paste("yyy",1:500,sep="_"),
  age = sample(1:100,500,replace=TRUE),
  amount_1 = sample(1:200,500,replace=TRUE),
  amount_2 = sample(1:200,500,replace=TRUE),
  amount_3 = sample(1:200,500,replace=TRUE))
# ensure at least three fit rows
df2[10,2:3]    <- df1[1,2:3]
df2[20,c(2,4)] <- df1[2,2:3]
df2[30,c(2,5)] <- df1[3,2:3]
# define comparrison with df2
comp2df2 <- function(x){
  ageComp <- df2$age == as.numeric(x[2])
  if(!any(ageComp)){
    return(NaN)
  }
  amountComp <- apply(df2,1,function(a) as.numeric(x[3]) %in% as.numeric(a[3:5]))
  if(!any(amountComp)){
    return(NaN)
  }
  matchIdx <- ageComp & amountComp
  if(sum(matchIdx) > 1){
    warning("multible match detected first match is taken\n")
  }
  return(which(matchIdx)[1])
}
# run match
matchIdx <- apply(df1,1,comp2df2)
# merge
df_new <- cbind(df1[!is.na(matchIdx),],df2[matchIdx[!is.na(matchIdx)],])

沒時間對真正的大數據進行測試,但是我想這應該比您的兩個for循環要快。...要進一步加快處理速度,您可以刪除

if(sum(matchIdx) > 1){
    warning("multible match detected first match is taken\n")
  }

如果您不擔心一行會與其他幾行相匹配,則可以使用這些行。

暫無
暫無

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

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