r匹配相似的行

r匹配相似的行,r,match,euclidean-distance,R,Match,Euclidean Distance,下面我将讨论一些类似的观察结果。我的目标是基于欧几里德距离概念,考虑向量{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.0

下面我将讨论一些类似的观察结果。我的目标是基于欧几里德距离概念,考虑向量
{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

等等

这里有一种使用
fuzzyjoin::distance\u inner\u 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

所以
Match
列只是告诉您在整个数据帧中是否存在匹配?您不关心哪一行匹配,只想知道是否有匹配?就这个问题而言,
Blood
列并不重要?(或者你只在同一血型中寻找匹配物吗?)这看起来有点像聚类(
hclust
,随便什么),因为如果某个特定的
血型组中的观察值与该血型组中的其他血型足够接近,它们就会匹配。人们通常首先使用
kmeans
聚类,它包含在Base R中的
stats
包中。
dbscan
包也很好,但不是参数化的,因此可能不是您想要的。您看过包fuzzyjoin吗?请编辑您的问题以说明更多这方面的信息,因为它听起来像是一个不清楚(或根本不存在)的重要要求在问题的当前措辞中,这是否会识别1:1:1:1匹配,这意味着,对于血型组=A中的每一行,在血型组=B、血型组=AB、血型组=O中至少找到一个匹配?最大距离
max_dist
确定匹配的阈值。(我改为0.02,所以有些不匹配。)所以它可以对0、1或多个匹配进行罚款。初始联接在所有血型中查找匹配项,但我包含了一个筛选步骤
blood.x==blood.y
,前提是不希望包含不同血型的两个观察值之间的匹配项。