R: Сопоставить значения в двух фреймах данных, таких как vlookup, но для нескольких критериев без ключа [большие данные] - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть два больших фрейма данных (500 тыс. Строк) из двух отдельных источников без ключа.Вместо возможности объединения с помощью ключа я хочу объединить два фрейма данных путем сопоставления других столбцов.Например, возраст и количество.Это не идеальное совпадение между двумя фреймами данных, поэтому некоторые значения не будут совпадать, и позже я просто удалю их.

Данные могут выглядеть примерно так.

enter image description here

Итак, в примере выше я хочу создать таблицу, соответствующую ключу 1 и ключу 2. На рисунке выше мы видим, что XXX1 и YYY3 - это совпадение.Отсюда я хотел бы создать фрейм данных, например:

[Ключ 1] [Ключ 2]

XXX1 ГГГ3

XXX2 Н / Д

XXX3 N / A

Я знаю, как это сделать в 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)
  }}

Проблема в том, что это занимает путь, путь к длине.Есть ли более эффективный способ отобразить эти данные как можно лучше?

Спасибо!

Ответы [ 2 ]

0 голосов
/ 28 февраля 2019

может ли следующий код работать на вас?

# 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")
  }

, если вас не беспокоит совпадение строк с несколькими другими.

0 голосов
/ 28 февраля 2019

Создайте фиктивные столбцы в обоих фреймах данных, например (я могу показать вам для df1):

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

Аналогично для df2 из Y1 .... Yn, а затем соедините оба фрейма данных с помощью «слияния»на столбцы возраст и количество.Объедините Key1 и key2 в новом столбце в объединенном фрейме данных.Вы напрямую получите желаемый фрейм данных.

...