提问人:DaniCee 提问时间:9/29/2023 更新时间:9/29/2023 访问量:36
按 2 列中的元素对 2 个数据帧进行 RBIND,避免嵌套循环
rbind 2 data frames by the elements in 2 columns, avoiding nested loops
问:
我有两个数据框,如下所示:
df1 <- data.frame(Marker1=c('+','+','+','-','-'), Marker2=c('+','+','+','+','-'), Marker3=c('+','-','+','-','+'),
Sample=c(1,1,2,3,3), Population_ID=c(1,2,1,5,6), Cells_in_Sample=c(443,23,567,98,3))
df2 <- data.frame(Population_ID=c(1,1,1,1,1,1,1,2,2,2,2,2,2,2,5,5,5,5,5,5,5,6,6,6,6,6,6,6),
Marker1=c('+','+','+','+',NA,NA,NA,'+','+','+','+',NA,NA,NA,'-','-','-','-',NA,NA,NA,'-','-','-','-',NA,NA,NA),
Marker2=c('+','+',NA,NA,'+','+',NA,'+','+',NA,NA,'+','+',NA,'+','+',NA,NA,'+','+',NA,'-','-',NA,NA,'-','-',NA),
Marker3=c('+',NA,'+',NA,'+',NA,'+','-',NA,'-',NA,'-',NA,'-','-',NA,'-',NA,'-',NA,'-','+',NA,'+',NA,'+',NA,'+'))
它们看起来像这样:
> df1
Marker1 Marker2 Marker3 Sample Population_ID Cells_in_Sample
1 + + + 1 1 443
2 + + - 1 2 23
3 + + + 2 1 567
4 - + - 3 5 98
5 - - + 3 6 3
> head(df2)
Population_ID Marker1 Marker2 Marker3
1 1 + + +
2 1 + + <NA>
3 1 + <NA> +
4 1 + <NA> <NA>
5 1 <NA> + +
6 1 <NA> + <NA>
df1
包含我的“基础”种群,其中包含 3 个标记的组合(所有 3 个都存在),加上每个样本每个种群的计数 ()。Cells_in_Sample
df2
采用 3 个标记的独特组合,并从中找出 1 和 2 的所有可能组合。请注意,这已经包括了 中的“基础”种群。df2
df1
我想在这里做的只是以一种高效和优雅的方式将两者结合起来,尽可能避免嵌套循环。final_df
应保留 中每个“碱基”3 标记组合的样本和计数值,扩展到 中的所有“子组合”。因此,我应该通过和.final_df
df1
df2
rbind
Sample
Population_ID
现在我设法使用嵌套循环来做到这一点,但我想知道是否有更好的解决方案。for
这是我所做的:
final_df <- NULL
for (s in unique(df1$Sample)){
df1_sub <- subset(df1, Sample==s)
for (p in df1_sub$Population_ID){
df1_sub_sub <- subset(df1_sub, Population_ID==p)
df2_sub <- subset(df2, Population_ID==p)
df2_sub$Sample <- s
df2_sub$Cells_in_Sample <- df1_sub_sub$Cells_in_Sample
df2_sub <- df2_sub[,c(2,3,4,5,1,6)]
#note there is no need to rbind df1_sub_sub and df2_sub
#cause df2 already contains the populations from df1
final_df <- rbind(final_df, df2_sub)
}
}
final_df
看起来和我想要的一模一样。我把它完整粘贴在下面以供参考:
> final_df
Marker1 Marker2 Marker3 Sample Population_ID Cells_in_Sample
1 + + + 1 1 443
2 + + <NA> 1 1 443
3 + <NA> + 1 1 443
4 + <NA> <NA> 1 1 443
5 <NA> + + 1 1 443
6 <NA> + <NA> 1 1 443
7 <NA> <NA> + 1 1 443
8 + + - 1 2 23
9 + + <NA> 1 2 23
10 + <NA> - 1 2 23
11 + <NA> <NA> 1 2 23
12 <NA> + - 1 2 23
13 <NA> + <NA> 1 2 23
14 <NA> <NA> - 1 2 23
15 + + + 2 1 567
16 + + <NA> 2 1 567
17 + <NA> + 2 1 567
18 + <NA> <NA> 2 1 567
19 <NA> + + 2 1 567
20 <NA> + <NA> 2 1 567
21 <NA> <NA> + 2 1 567
151 - + - 3 5 98
161 - + <NA> 3 5 98
171 - <NA> - 3 5 98
181 - <NA> <NA> 3 5 98
191 <NA> + - 3 5 98
201 <NA> + <NA> 3 5 98
211 <NA> <NA> - 3 5 98
22 - - + 3 6 3
23 - - <NA> 3 6 3
24 - <NA> + 3 6 3
25 - <NA> <NA> 3 6 3
26 <NA> - + 3 6 3
27 <NA> - <NA> 3 6 3
28 <NA> <NA> + 3 6 3
有没有一种简单有效的方法可以在没有嵌套循环的情况下做到这一点?我的实际数据比这大很多倍。
谢谢!
答:
4赞
Rui Barradas
9/29/2023
#1
你根本不需要循环,这是合并
的情况。
在下面的代码中,我仅出于测试目的复制了 以保持预期结果不变。final_df
df3 <- final_df
row.names(df3) <- NULL
# join removing the marker columns from df1
mrg <- merge(df2, df1[4:6], by = "Population_ID")[c(2:5, 1, 6)]
mrg <- mrg[order(mrg$Sample), ]
row.names(mrg) <- NULL
identical(df3, mrg)
#> [1] TRUE
创建于 2023-09-29 使用 reprex v2.0.2
2赞
Till
9/29/2023
#2
您想要的结果可以通过 .left_join()
- 删除 Marker 列,因为这些列已包含在 中。
df1
df2
left_join()
这两个数据集。- 对列重新排序并排列行以匹配问题中的结果表。
library(tidyverse)
df1a <-
df1 |>
select(-contains("Marker"))
left_join(df2, df1a, relationship = "many-to-many") |>
select(contains("Marker"), Sample, everything()) |>
arrange(Population_ID, Sample)
#> Joining with `by = join_by(Population_ID)`
#> Marker1 Marker2 Marker3 Sample Population_ID Cells_in_Sample
#> 1 + + + 1 1 443
#> 2 + + <NA> 1 1 443
#> 3 + <NA> + 1 1 443
#> 4 + <NA> <NA> 1 1 443
#> 5 <NA> + + 1 1 443
#> 6 <NA> + <NA> 1 1 443
#> 7 <NA> <NA> + 1 1 443
#> 8 + + + 2 1 567
#> 9 + + <NA> 2 1 567
#> 10 + <NA> + 2 1 567
#> 11 + <NA> <NA> 2 1 567
#> 12 <NA> + + 2 1 567
#> 13 <NA> + <NA> 2 1 567
#> 14 <NA> <NA> + 2 1 567
#> 15 + + - 1 2 23
#> 16 + + <NA> 1 2 23
#> 17 + <NA> - 1 2 23
#> 18 + <NA> <NA> 1 2 23
#> 19 <NA> + - 1 2 23
#> 20 <NA> + <NA> 1 2 23
#> 21 <NA> <NA> - 1 2 23
#> 22 - + - 3 5 98
#> 23 - + <NA> 3 5 98
#> 24 - <NA> - 3 5 98
#> 25 - <NA> <NA> 3 5 98
#> 26 <NA> + - 3 5 98
#> 27 <NA> + <NA> 3 5 98
#> 28 <NA> <NA> - 3 5 98
#> 29 - - + 3 6 3
#> 30 - - <NA> 3 6 3
#> 31 - <NA> + 3 6 3
#> 32 - <NA> <NA> 3 6 3
#> 33 <NA> - + 3 6 3
#> 34 <NA> - <NA> 3 6 3
#> 35 <NA> <NA> + 3 6 3
评论
merge(df2, df1[c("Population_ID","Sample","Cells_in_Sample")], by="Population_ID")
Population_ID
df1
Samples
df2