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

问题描述 投票:0回答:1

我有两个数据框,如下所示:

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
中的所有“子组合”。因此,我应该通过
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

有没有一种简单有效的方法可以在没有嵌套循环的情况下做到这一点?我的实际数据比这个大很多倍。

谢谢!

r dataframe for-loop apply rbind
1个回答
0
投票

你根本不需要循环,这是

merge
的情况。
在下面的代码中,我复制了
final_df
只是为了测试目的,以保持预期结果不变。

df3 <- final_df
row.names(df3) <- NULL

mrg <- merge(df2, df1[-(1:3)], 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

© www.soinside.com 2019 - 2024. All rights reserved.