在 R 中的数据帧之间查找最近的条目

Find nearest entry between dataframes in R

我有两个要比较的数据框。我已经知道数据帧一(df1$BP)中的值不在数据帧二(df2$START 和 df2$STOP)中的值范围内,但我想 return 数据帧二中的行,其中 df2 $START 或 df2$STOP 的值最接近 df1$BP,其中“Chr”列在数据集 (df1$Chr, df2$Chr) 之间匹配。

设法做到了这一点(见 Q 的底部),但它似乎非常笨拙,我想知道是否有更简洁的方式来实现同样的事情。

因此对于数据帧一 (df1),我们有:

 df1=data.frame(SNP=c("rs79247094","rs13325007"),
           Chr=c(2,3),
           BP=c(48554955,107916058))

df1

SNP         Chr    BP
rs79247094    2     48554955
rs13325007    3    107916058

对于数据帧二,我们有:

 df2=data.frame(clump=c(1,2,3,4,5,6,7,8),
           Chr=c(2,2,2,2,3,3,3,3),
           START=c(28033538,37576136,58143438,60389362,80814042,107379837,136288405,161777035),
           STOP=c(27451538,36998607,57845065,60242162,79814042,107118837,135530405,161092491))

df2

 Clump    Chr      START       STOP
     1      2   28033538   27451538
     2      2   37576136   36998607
     3      2   58143438   57845065
     4      2   60389362   60242162
     5      3   80814042   79814042
     6      3  107379837  107118837
     7      3  136288405  135530405
     8      3  161777035  161092491

我对 return 哪些 START/STOP 值最接近 BP 感兴趣。理想情况下,我可以 return 该行,以及 BP 和 START 或 STOP 之间的区别是 (df3$Dist),例如:

df3

 Clump   Chr      START       STOP         SNP        BP       Dist
     3     2   58143438   57845065  rs79247094  48554955    9290110
     6     3  107379837  107118837  rs13325007  107916058    536221

我找到了类似个问题,例如:Return rows establishing a "closest value to" in R

但这些是根据固定值而不是变化的值(并在 Chr 列上匹配)找到最接近的值。

我啰嗦的方法是:

df3<-right_join(df1,df2,by="Chr")

给我 df1 和 df2 的所有组合。

df3$start_dist<-abs(df3$START-df3$BP)

创建一个包含 START 和 BP 之间绝对差值的列

df3$stop_dist<-abs(df3$STOP-df3$BP)

创建一个包含 STOP 和 BP 之间绝对差值的列

df3$dist.compare<-ifelse(df3$start_dist<df3$stop_dist,df3$start_dist,df3$stop_dist)
df3<-df3[with(df3,order(SNP,"dist.compare")),]

创建一个列 (dist.compare) 打印 BP 和 START 或 STOP 之间的最小差异(以及该列的重新排序)

df3<- df3 %>%   group_by(SNP) %>%   mutate(Dist = first(dist.compare))

创建一个列 (Dist),打印 df3$dist.compare

中的最小值
df3<-df3[which(df3$dist.compare==df3$Dist),c("clump","Chr","START","STOP","SNP","BP","Dist")]
df3<-df3[order(df3$clump),]

只打印 dist.compare 与 Dist 匹配的行(因此是最小值),并删除中间列,并通过按块重新排序来整理。现在这让我到达了我想去的地方:

df3

 Clump   Chr      START       STOP         SNP        BP       Dist
     3     2   58143438   57845065  rs79247094  48554955    9290110
     6     3  107379837  107118837  rs13325007  107916058    536221

但我觉得它非常非常复杂,想知道是否有人有任何关于如何改进该过程的提示?

提前致谢

按照您在语法中列出的逻辑,这里有一个 dplyr 更简洁的解决方案:

  1. right_join 你的数据帧

  2. 根据绝对值创建一个变量dist.compare

  3. 分组依据SNP

  4. 过滤保持最小距离

  5. Select 变量,按照您希望的最终数据帧顺序排列。请注意,您可以在 dplyr::select 语句 (Dist = dist.compare)

    中重命名变量
  6. 订单值 clump

     library(dplyr)
    
     df3 <- right_join(df1, df2, by = "Chr") %>% 
       mutate(dist.compare = ifelse(abs(START - BP) < abs(STOP - BP), abs(START - BP), abs(STOP - BP))) %>% 
       group_by(SNP) %>% 
       filter(dist.compare == min(dist.compare)) %>% 
       select(clump, Chr, START, STOP, SNP, BP, Dist = dist.compare) %>% 
       arrange(clump)
    

这给了我们:

  clump   Chr     START      STOP SNP               BP    Dist
  <dbl> <dbl>     <dbl>     <dbl> <chr>          <dbl>   <dbl>
1     3     2  58143438  57845065 rs79247094  48554955 9290110
2     6     3 107379837 107118837 rs13325007 107916058  536221