在 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
更简洁的解决方案:
right_join
你的数据帧
根据绝对值创建一个变量dist.compare
分组依据SNP
过滤保持最小距离
Select 变量,按照您希望的最终数据帧顺序排列。请注意,您可以在 dplyr::select
语句 (Dist = dist.compare
)
中重命名变量
订单值 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
我有两个要比较的数据框。我已经知道数据帧一(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
更简洁的解决方案:
right_join
你的数据帧根据绝对值创建一个变量
dist.compare
分组依据
SNP
过滤保持最小距离
Select 变量,按照您希望的最终数据帧顺序排列。请注意,您可以在
中重命名变量dplyr::select
语句 (Dist = dist.compare
)订单值
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