通过2列中的元素rbind 2个数据框,避免嵌套循环

toiithl6  于 2023-10-13  发布在  其他
关注(0)|答案(2)|浏览(80)

我有两个 Dataframe ,如下所示:

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,以一种高效而优雅的方式将两者结合起来,尽可能避免嵌套循环。
final_df应保留df1中每个“基础”3标记组合的样本和计数值,并扩展到df2中的所有“子组合”。因此,我应该用SamplePopulation_IDrbind它们。
现在我设法做到了这一点,使用嵌套的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

有没有一种简单有效的方法来做到这一点,而不需要嵌套循环?我的实际数据比这个大很多倍。
谢谢你,谢谢

np8igboo

np8igboo1#

你根本不需要循环,这是一个merge的例子。
在下面的代码中,我复制了一个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

kkbh8khc

kkbh8khc2#

您想要的结果可以通过left_join()来实现。
1.删除df1中的Marker列,因为这些列已经包含在df2中。

  1. left_join()两个数据集。
    1.重新排列列和行以匹配问题中的结果表。
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

相关问题