r - 如何根据R中的相似值合并两个数据帧

标签 r dataframe merge

我是 R 的新手,我有一个关于合并两个数据框的问题,它确实包含来自两个域(mz 和 rt)但不相同的相似数字数据。 这是一个描述我的问题的例子:

mz1    <- c(seq(100, 190, by = 10))
rt1    <- c(seq(1, 10, by = 1))
value1 <- runif(10, min = 100, max = 100000)
mz2    <- mz1 + runif(10, -0.1, 0.1)
rt2    <- rt1 + runif(10, -0.2, 0.2)
value2 <- runif(10, min = 100, max = 100000)

df1 <- as.data.frame(cbind(mz1, rt1, value1))
df2 <- as.data.frame(cbind(mz2, rt2, value2))


df1
   mz1 rt1    value1
1  100   1 44605.646
2  110   2 13924.598
3  120   3 35727.265
4  130   4 75175.652
5  140   5 25221.724
6  150   6 29080.653
7  160   7  3170.749
8  170   8 10184.708
9  180   9 48055.072
10 190  10 77644.865


df2
        mz2      rt2   value2
1  100.0243 1.043092 58099.49
2  110.0514 2.164753 76397.67
3  120.0258 2.838141 43901.05
4  130.0921 4.044322 34543.96
5  139.9577 5.023823 53086.10
6  150.0170 6.061794 13929.27
7  160.0884 6.828779 60905.61
8  170.0440 7.932000 66627.20
9  180.0872 9.116425 44587.62
10 189.9694 9.834091 51186.03

我想合并 df1 和 df2 中在 rt 域中差异 <= 0.1 和 在 mz 域中差异 <= 0.05 的所有行。 此外,如果有两行或更多行满足此条件,则应合并到两个域的距离最小的行(可能需要进行额外计算:distance = sqrt(mz^2+rt^2)),其余行行必须找到不同的合并伙伴(如果存在)。 如果没有合并伙伴保留该行并将“NA”填入缺失值。

到目前为止我尝试了什么:

merge.data.frame(df1, df2, by.x = c("mz1", "rt1"), by.y = c("mz2", "rt2") , all = T)

        mz1 rt1    value1      rt2   value2
1  100.0000   1 44605.646       NA       NA
2  100.0243  NA        NA 1.043092 58099.49
3  110.0000   2 13924.598       NA       NA
4  110.0514  NA        NA 2.164753 76397.67
5  120.0000   3 35727.265       NA       NA
6  120.0258  NA        NA 2.838141 43901.05
7  130.0000   4 75175.652       NA       NA
8  130.0921  NA        NA 4.044322 34543.96
9  139.9577  NA        NA 5.023823 53086.10
10 140.0000   5 25221.724       NA       NA
11 150.0000   6 29080.653       NA       NA
12 150.0170  NA        NA 6.061794 13929.27
13 160.0000   7  3170.749       NA       NA
14 160.0884  NA        NA 6.828779 60905.61
15 170.0000   8 10184.708       NA       NA
16 170.0440  NA        NA 7.932000 66627.20
17 180.0000   9 48055.072       NA       NA
18 180.0872  NA        NA 9.116425 44587.62
19 189.9694  NA        NA 9.834091 51186.03
20 190.0000  10 77644.865       NA       NA

这至少为我提供了一个格式正确的数据框,其中包含无法合并的 NA。

如果有人能帮我解决这个问题那就太好了!

问候

更新

好的,我会记住的。到目前为止谢谢你。我尝试了以下想法:

#select data in joined which has no partner
no_match_df1 <- anti_join(joined, df2)
no_match_df1 <- no_match_df1[1:3]

#select data in df2 which has been excluded due to duplication
collist <- c("mz2", "rt2", "value2")
dublicates <- joined[complete.cases(joined[collist]), collist]
dublicates <- anti_join(df2, dublicates)


#repetition for joining
joined2 <- fuzzy_join(no_match_df1, dublicates, multi_by = c("mz1" = "mz2", "rt1" = "rt2"),
                     multi_match_fun = mmf, mode = "full")

joined2 <- group_by(joined2, mz1, rt1) %>%
  mutate(min_dist = min(dist))
head(joined2)

joined2 <- filter(joined2, dist == min_dist | is.na(dist)) %>%
  select(-dist, -min_dist)
head(joined2)

#select only rows with new match or where dublicates coulnd't find a partner

add <- subset(joined2, !is.na(joined2$mz2) | !is.na(joined2$mz2) &  !is.na(joined2$mz1))

#add to joined
##I need some help here, how can I update the existing joined data frame?

Maybe this helps

也许我们可以像以前那样将 no_match_df1duplicates 连接起来,然后通过覆盖现有 joined< 中的特定行来添加结果 数据框。 最后,我们必须重复该过程,因为 duplicates 的长度 >1。

最佳答案

按照 joran 的建议,我找到了使用 fuzzyjoin 包的解决方案。我创建了如下数据集:

set.seed(123)
mz1    <- c(seq(100, 190, by = 10))
rt1    <- c(seq(1, 10, by = 1))
value1 <- runif(10, min = 100, max = 100000)
mz2    <- mz1 + runif(10, -0.1, 0.1)
rt2    <- rt1 + runif(10, -0.2, 0.2)
value2 <- runif(10, min = 100, max = 100000)

df1 <- as.data.frame(cbind(mz1, rt1, value1))
df2 <- as.data.frame(cbind(mz2, rt2, value2))

(一点旁白:你做了一个很好的可重现的例子。唯一的缺点是你没有设置种子,这是上面代码与你的代码的唯一区别。)

为了确保存在找到两个匹配项的情况,我在 df2 中添加了一行:

df2 <- rbind(df2, c(180.001, 9.09, 0))

现在,我可以使用函数 fuzzy_join() 来合并数据帧:

library(fuzzyjoin)
joined <- fuzzy_join(df1, df2, multi_by = c("mz1" = "mz2", "rt1" = "rt2"),
                     multi_match_fun = mmf, mode = "full")

请注意,语法与 dplyr 中的 join() 非常相似。然而,有一个关键的区别:您可以为 multi_match_fun 提供一个函数,它确定两行是否匹配。它返回一个数据框,其中第一列必须是逻辑的。此列确定两行是否匹配。所有其他列都简单地添加到结果数据框中。我将这个函数定义如下:

mmf <- function(x, y) {
  mz_dist <- abs(x[, 1] - y[, 1])
  rt_dist <- abs(x[, 2] - y[, 2])

  out <- data_frame(merge = rt_dist <= 0.1 & mz_dist < 0.05,
                    dist = sqrt(mz_dist^2 + rt_dist^2))
  return (out)
}

如果您指定的条件得到满足,您可以看到 merge 列(名称是任意的)为 TRUE。此外,还添加了一个包含距离的列供以后使用。我设置 mode = "full" 以便在没有匹配项的情况下获得 NA 值。

结果如下:

head(joined)
##   mz1 rt1   value1      mz2      rt2   value2       dist
## 1 110   2 78851.68 109.9907 2.077121 90239.67 0.07768406
## 2 120   3 40956.79 120.0355 3.056203 69101.46 0.06648308
## 3 180   9 55188.36 179.9656 8.915664 31886.28 0.09108803
## 4 180   9 55188.36 180.0010 9.090000     0.00 0.09000556
## 5 100   1 28828.99       NA       NA       NA         NA
## 6 130   4 88313.44       NA       NA       NA         NA

在第 3 行和第 4 行中,您可以看到,在这种情况下确实有两个匹配项。从 dist 列中,您可以看到第 4 行是我们要保留的行。这意味着第 3 行应被视为未找到匹配项,mz1rt1value1 列应填充 NA。为此,我按 mz1rt1 对行进行分组,然后为每组添加距离的最小值:

library(dplyr)
joined <- group_by(joined, mz1, rt1) %>%
            mutate(min_dist = min(dist))
head(joined)
## Source: local data frame [6 x 8]
## Groups: mz1, rt1 [5]
## 
##     mz1   rt1   value1      mz2      rt2   value2       dist   min_dist
##   <dbl> <dbl>    <dbl>    <dbl>    <dbl>    <dbl>      <dbl>      <dbl>
## 1   110     2 78851.68 109.9907 2.077121 90239.67 0.07768406 0.07768406
## 2   120     3 40956.79 120.0355 3.056203 69101.46 0.06648308 0.06648308
## 3   180     9 55188.36 179.9656 8.915664 31886.28 0.09108803 0.09000556
## 4   180     9 55188.36 180.0010 9.090000     0.00 0.09000556 0.09000556
## 5   100     1 28828.99       NA       NA       NA         NA         NA
## 6   130     4 88313.44       NA       NA       NA         NA         NA

具有有效匹配的行是所有那些,其中distmin_dist 相同。此外,我们也不应丢失 distNA 的行。这可以按如下方式完成:

dbls <- which(joined$dist != joined$min_dist)
joined[dbls, c("mz1", "rt1", "value1")] <- NA
joined <- select(joined, -dist, -min_dist)
head(joined)
## Source: local data frame [6 x 6]
## Groups: mz1, rt1 [6]
## 
##     mz1   rt1   value1      mz2      rt2   value2
##   <dbl> <dbl>    <dbl>    <dbl>    <dbl>    <dbl>
## 1   110     2 78851.68 109.9907 2.077121 90239.67
## 2   120     3 40956.79 120.0355 3.056203 69101.46
## 3    NA    NA       NA 179.9656 8.915664 31886.28
## 4   180     9 55188.36 180.0010 9.090000     0.00
## 5   100     1 28828.99       NA       NA       NA
## 6   130     4 88313.44       NA       NA       NA

根据您的数据看起来,也有可能在双重匹配的情况下,mz1rt1 的值不一致,但是另一对值可以。然后,您还必须对其他分组重复上述步骤。

关于r - 如何根据R中的相似值合并两个数据帧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41472722/

相关文章:

json - 从一个目录导入多个json文件并附加数据

r - browserVignettes 没有找到它们实际所在的位置

r - 在 R 中的一个值上重复数据帧,选择其他列的任何值

r - R 中的 Fama MacBeth 标准错误

python - reshape Pandas 数据框以反射(reflect)隐式 x 值?

python - 如何循环导入多个 .txt 文件但不串联?

R删除按因素分组的数据框中的异常值

git - 构建 git merge 代码的最佳方法是什么

git - 如何使用 Git 扩展配置 Araxis merge

c - 如何在mergeSort中将Infinity指示为哨兵卡?