【问题标题】:r match rows that that are similarr 匹配相似的行
【发布时间】:2019-04-24 02:15:10
【问题描述】:

我正在处理以下几个这样的观察结果。我的目标是根据欧几里得距离概念识别彼此匹配/相似的行,考虑向量{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

等等……

【问题讨论】:

  • 所以Match 列只是告诉您整个数据框中是否存在匹配项?您不在乎哪一行匹配,只想知道是否匹配?对于这个问题,Blood 列无关紧要吗? (或者你只寻找相同血型的匹配项?)
  • 这看起来有点像聚类(hclust,无论如何),如果特定Blood 组内的观察结果与该组的其余部分足够接近,则它们匹配。跨度>
  • 人们通常在第一个实例中使用kmeans 集群,它包含在 Base R 的 stats 包中。dbscan 包也很出色,但它是非参数的,所以可能不是正是你想要的。
  • 你看过fuzzyjoin包吗?
  • 请编辑您的问题以详细说明这一点,因为这听起来像是在问题的当前措辞中不清楚(或根本不存在?)的重要要求。

标签: r match euclidean-distance


【解决方案1】:

这是一种使用fuzzyjoin::distance_inner_join 的方法。连接应该非常快,但我们需要过滤掉具有不同 Blood 值的自我匹配和巧合匹配。

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

【讨论】:

  • 这是否会识别 1:1:1:1 匹配,这意味着对于 BloodGroup = A 中的每一行,在 BloodGroup = B、BloodGroup= AB、BloodGroup=O 中找到至少一个匹配项?
  • max_dist 确定匹配的阈值。 (我改为 0.02,所以有些不匹配。)所以它可以很好地匹配 0、1 或多个匹配。最初的连接会找到所有血型的匹配项,但我包含了一个过滤步骤Blood.x == Blood.y,假设人们不想在不同类型的两个观察值之间包含匹配项。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-02-23
  • 1970-01-01
  • 2012-12-02
  • 1970-01-01
  • 2019-06-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多