Как сопоставить элементы в R на основе некоторых критериев?

#r

Вопрос:

Итак, с места в карьер я думаю, что мне нужно что-то вроде пакета R «fuzzyjoin», или, может быть, это действительно может сработать, но мне тогда нужна помощь в том, как заставить его работать.

У меня есть два фрейма данных df1 и df2. Каждый фрейм данных содержит 7 столбцов. Столбцы: идентификатор; тип 1; тип 2; критерии 1; критерии 2; критерии 3; критерии 4.

df1 имеет, скажем, 500 строк, в то время как df2 имеет, скажем, 2000 строк. Вот небольшой отрывок, чтобы прояснить, что я имею в виду.

 df1

id      type 1  type 2  criteria 1      criteria 2  criteria 3  criteria 4
214     CAF     A       19.76338        44078       0.7         45904
312     BZD     B       17.21671        43333       3.385       45159

 
 df2

id  type 1  type 2  criteria 1  criteria 2  criteria 3  criteria 4
66    CAF   B       20.50012    43963       2.375       45058
163   CAF   B       20.72327    42640       2.125       44466
188   CAF   A       21.12873    41075       4.375       44727
250   CAF   A       20.43558    43427       3.75        45253
345   CAF   A-      18.45072    43669       10.4        45496
357   CAF   A       20.72327    43046       2.75        44932
520   CAF   AA      19.1687     41586       6.25        45238
609   CAF   A       19.32814    42160       4.5         45813
637   CAF   A-      19.32038    42808       4.5         46644
791   CAF   AA      18.79739    42460       4.5         46295
846   BZD   B       18.07695    43399       3.4         45225
854   BZD   A       18.0598     43992       7.5         47644
885   BZD   A       19.15586    42818       3.265       46470
1026  BZD   B       18.9031     41694       3.925       47175
1045  BZD   Aaa     17.49807    42412       0.45        46065
1121  BZD   BB      18.12462    42087       0.68        45740
1176  BZD   A       18.05427    41709       3.05        47553

 

Для каждой строки в df1 я хочу найти наиболее подходящую строку в df2, чтобы тип 1 и тип 2 были идентичны как для df1, так и для df2, а затем критерии от 1 до 4 были как можно ближе, но не обязательно должны быть точно идентичными (на самом деле они вряд ли будут). Предпочтительно, если возможно, я хотел бы использовать расстояние Махаланобиса для критериев, но это не является строго необходимым.

Кто-нибудь знает, какой пакет или функцию я могу использовать для этого?

Комментарии:

1. Пожалуйста, поделитесь воспроизводимым примером, вставив выходные dput(df1) данные и dput(df2)) в свой вопрос. Спасибо.

Ответ №1:

Вы можете сделать это следующим образом:

 df1 = tribble(
 ~id, ~type1, ~type2, ~criteria1, ~criteria2, ~criteria3, ~criteria4, 
 1, "CAF","A ", 19.76338, 44078, 0.7, 45904, 
 2, "BZD","B ", 17.21671, 43333, 3.385, 45159,
 3, "CAF", "A ", 22.12873, 45075, 4.365, 42727,
 4, "BZD","B ", 15.21671, 43333, 3.385, 45159,
 5, "BZD","B ", 16.21671, 43333, 3.385, 45159
)

df2 = tribble(
 ~id, ~type1, ~type2, ~criteria1, ~criteria2, ~criteria3, ~criteria4, 
 66, "CAF", "B ", 20.50012, 43963, 2.375, 45058,
 163, "CAF", "B", 20.72327, 42640, 2.125, 44466,
 188, "CAF", "A ", 21.12873, 41075, 4.375, 44727,
 250, "CAF", "A ", 20.43558, 43427, 3.75, 45253,
 345, "CAF", "A-", 18.45072, 43669, 10.4, 45496,
 357, "CAF", "A ", 20.72327, 43046, 2.75, 44932,
 520, "CAF", "AA", 19.1687, 41586, 6.25, 45238,
 609, "CAF","A ", 19.32814, 42160, 4.5, 45813,
 637, "CAF", "A-", 19.32038, 42808, 4.5, 46644,
 791, "CAF", "AA", 18.79739, 42460, 4.5, 46295,
 846, "BZD", "B ", 18.07695, 43399, 3.4, 45225,
 854, "BZD", "A ", 18.0598, 43992, 7.5, 47644,
 885, "BZD", "A ", 19.15586, 42818, 3.265, 46470,
 1026, "BZD","B ", 18.9031, 41694, 3.925, 47175,
 1045, "BZD", "Aaa", 17.49807, 42412, 0.45, 46065,
 1121, "BZD", "BB", 18.12462, 42087, 0.68, 45740,
 1176, "BZD","A ", 18.05427, 41709, 3.05, 47553
)

addCrit = function(df_1, df_2){
  df_2 %>% 
    filter(type1==df_1$type1 amp; type2==df_1$type2) %>% 
    nest(data=criteria1:criteria4) %>% 
    mutate(
      crit = map_dbl(data, crit, df_1),
      id2 = id
    ) %>% 
    arrange(crit) %>% 
    select(id2, crit) %>% 
    head(1)
}

crit = function(df1, df2) sqrt(
    (df1$criteria1-df2$criteria1)^2 
    (df1$criteria2-df2$criteria2)^2 
    (df1$criteria3-df2$criteria3)^2 
    (df1$criteria4-df2$criteria4)^2)
    

df1 %>% 
  nest(data=type1:criteria4) %>% 
  mutate(
    cr = map(data, addCrit, df2)
  )  %>% unnest(c(cr, data))
 

выход

 # A tibble: 5 x 9
     id type1 type2 criteria1 criteria2 criteria3 criteria4   id2   crit
  <dbl> <chr> <chr>     <dbl>     <dbl>     <dbl>     <dbl> <dbl>  <dbl>
1     1 CAF   A          19.8     44078      0.7      45904   250  921. 
2     2 BZD   B          17.2     43333      3.38     45159   846   93.3
3     3 CAF   A          22.1     45075      4.36     42727   357 2996. 
4     4 BZD   B          15.2     43333      3.38     45159   846   93.4
5     5 BZD   B          16.2     43333      3.38     45159   846   93.4
 

Сделайте crit функцию так, как вы считаете нужным. Это может быть критерий Махаланобиса или что-то еще.
Эта функция принимает два однострочных фрейма данных и возвращает значение критерия в виде double значения.

Комментарии:

1. Привет. Я пытаюсь сделать это с гораздо большим набором данных и получаю следующую ошибку. Это потому, что происходит слишком много возможных совпадений, или в чем проблема? ` Ошибка: Проблема с mutate() колонкой cr . i cr = map(data, addCrit, df2) . проблема x со mutate() столбцом crit . i crit = map_dbl(data, crit, df_1) . Результат x 1 должен быть одинарным двойным, а не двойным вектором длины 9 rlang::last_error() , чтобы увидеть, где произошла ошибка. `

2. Проверьте чистоту ваших данных. Вы уверены criteria1: criteria4 , что переменные будут содержать только dbl значения?

3. Таким образом , используя typeof() и class() , каждый из criteria1:criteria4 них, по-видимому double , и numeric . Следовательно, я думаю, что типы данных должны быть правильными?

4. Можете ли вы тогда поделиться со мной этими данными? Я проверю это для тебя. Если по какой-то причине вы не можете поделиться со мной данными, разделите их пополам и протестируйте, когда получите сообщение об ошибке. Повторите это деление пополам, что приведет к ошибке. Таким образом, вы быстро определите проблему.