r соответствуют строкам, которые похожи - PullRequest
0 голосов
/ 24 апреля 2019

Я имею дело с несколькими наблюдениями, подобными приведенным ниже. Моя цель - определить строки, которые совпадают / похожи друг на друга, на основе евклидова расстояния, учитывая вектор {x1,x2,x3,x4} и порог 0.2 . Любое расстояние между строками меньше 0,2 считается одинаковым.

 Observation    Blood   x1   x2    x3     x4
 1              A      0.01  0.16  0.31  0.46
 2              A      0.02  0.17  0.32  0.47
 3              A      0.03  0.18  0.33  0.48

 4              B      0.05  0.20  0.35  0.49
 5              B      0.06  0.21  0.36  0.50
 6              B      0.07  0.22  0.37  0.51

 7              AB     0.09  0.24  0.39  0.52
 8              AB     0.1   0.25  0.4   0.53
 9              AB     0.11  0.26  0.41  0.54

 10             O      0.13  0.28  0.43  0.55
 11             O      0.14  0.29  0.44  0.56
 12             O      0.15  0.3   0.45  0.57

Я могу сделать это, используя очень неуклюжий двойной forloop. Мне интересно, есть ли эффективный способ сделать это.

Ожидаемый результат

 Observation    Blood   x1   x2    x3     x4    Match
 1              A      0.01  0.16  0.31  0.46   Yes
 2              A      0.02  0.17  0.32  0.47   Yes
 3              A      0.03  0.18  0.33  0.48   No 

 4              B      0.05  0.20  0.35  0.49   Yes
 5              B      0.06  0.21  0.36  0.50   Yes
 6              B      0.07  0.22  0.37  0.51   No

 7              AB     0.09  0.24  0.39  0.52   No
 8              AB     0.1   0.25  0.4   0.53   Yes
 9              AB     0.11  0.26  0.41  0.54   No

 10             O      0.13  0.28  0.43  0.55   No
 11             O      0.14  0.29  0.44  0.56   Yes
 12             O      0.15  0.3   0.45  0.57   Yes

 Match Dataset

 RowToBeMatched      FoundMatches_Bgroup_B  FoundMatches_Bgroup_AB  FoundMatches_Bgroup_O
 1                   4                      8                       11    
 2                   5                      NA                      12

Так далее ...

1 Ответ

1 голос
/ 24 апреля 2019

Вот подход, использующий fuzzyjoin::distance_inner_join. Объединение должно быть очень быстрым, но нам нужно отфильтровать самосопоставления и совпадения совпадений с различными значениями крови.

df %>% 
  fuzzyjoin::distance_inner_join(df, by = c("x1", "x2", "x3", "x4"), 
                                max_dist = 0.02) %>%
  filter(Observation.x != Observation.y,
         Blood.x == Blood.y)

Выходные данные показывают все наблюдения с их достаточно похожими совпадениями:

   Observation.x Blood.x x1.x x2.x x3.x x4.x Observation.y Blood.y x1.y x2.y x3.y x4.y
1              1       A 0.01 0.16 0.31 0.46             2       A 0.02 0.17 0.32 0.47
2              2       A 0.02 0.17 0.32 0.47             1       A 0.01 0.16 0.31 0.46
3              2       A 0.02 0.17 0.32 0.47             3       A 0.03 0.18 0.33 0.48
4              3       A 0.03 0.18 0.33 0.48             2       A 0.02 0.17 0.32 0.47
5              4       B 0.05 0.20 0.35 0.49             5       B 0.06 0.21 0.36 0.50
6              5       B 0.06 0.21 0.36 0.50             4       B 0.05 0.20 0.35 0.49
7              8      AB 0.10 0.25 0.40 0.53             9      AB 0.11 0.26 0.41 0.54
8              9      AB 0.11 0.26 0.41 0.54             8      AB 0.10 0.25 0.40 0.53
9             10       O 0.13 0.28 0.43 0.55            11       O 0.14 0.29 0.44 0.56
10            11       O 0.14 0.29 0.44 0.56            10       O 0.13 0.28 0.43 0.55
11            11       O 0.14 0.29 0.44 0.56            12       O 0.15 0.30 0.45 0.57
12            12       O 0.15 0.30 0.45 0.57            11       O 0.14 0.29 0.44 0.56

И этот вывод можно вернуть обратно, чтобы получить вывод в запрошенном формате:

df %>% 
  fuzzyjoin::distance_inner_join(df, by = c("x1", "x2", "x3", "x4"), 
                                 max_dist = 0.02) %>%
  filter(Observation.x != Observation.y,
         Blood.x == Blood.y) %>%
  select(Observation.x, Blood.x) %>%
  rename(Observation = Observation.x,
         Blood = Blood.x) %>%
  mutate(Match = "Yes") %>%
  right_join(df) %>%
  replace_na(list(Match = "No"))

Joining, by = c("Observation", "Blood")
   Observation Blood Match   x1   x2   x3   x4
1            1     A   Yes 0.01 0.16 0.31 0.46
2            2     A   Yes 0.02 0.17 0.32 0.47
3            2     A   Yes 0.02 0.17 0.32 0.47
4            3     A   Yes 0.03 0.18 0.33 0.48
5            4     B   Yes 0.05 0.20 0.35 0.49
6            5     B   Yes 0.06 0.21 0.36 0.50
7            6     B    No 0.07 0.22 0.37 0.51
8            7    AB    No 0.09 0.24 0.39 0.52
9            8    AB   Yes 0.10 0.25 0.40 0.53
10           9    AB   Yes 0.11 0.26 0.41 0.54
11          10     O   Yes 0.13 0.28 0.43 0.55
12          11     O   Yes 0.14 0.29 0.44 0.56
13          11     O   Yes 0.14 0.29 0.44 0.56
14          12     O   Yes 0.15 0.30 0.45 0.57
...