R - 根据列名将列加在一起

R - adding columns together, depending on column name

我有一个数据框 (df1),其中包含每个样本中不同物种的丰度:

> SampleID   Sp1   Sp2   Sp3   Sp4   ... Spn
> asb-001      3     0     0    23         9
> asb-002      4    15    10    56        98
> asb-003      8    45     8   453         0
> asb-004      0     5     0     3         6
> asb-005    120    56     0     0         0
...

每一列代表一个不同的物种。

我有另一个数据框 (df2)

Sp     Fam
Sp1   Fam1
Sp2   Fam2
Sp3   Fam1
Sp4   Fam3
Sp5   Fam2
Sp6   Fam1
...

家族名称的数量少于物种名称的数量。

我想根据物种名称将列加在一起以获得该科的总数(例如 Sp1 + Sp3 + Sp6 = Fam1)。我不想保留带有物种名称的原始列。

如果一切按计划进行,我的新数据框 (df3) 将如下所示:

> SampleID  Fam1  Fam2  Fam3 
> asb-001     12     0     9 
> asb-002     14    18   112 
> asb-003     28    58    18
> asb-004     10    12    10
> asb-005    142    65     0
...

我可以手动遍历并将单个物种添加在一起,但这对于大型数据集来说似乎很乏味,并且可能会产生错误。我有种感觉,我应该融化df1,但我对细节没有信心。任何意见,将不胜感激!

将您的原始数据更改为长格式并加入物种-家族映射。然后,您可以使用 group_by 计算每个家庭的总和。最后,将数据展开为宽格式。

library( tidyverse )

df1 %>% gather( Sp, Value, -SampleID ) %>%     # Convert to long format
  inner_join( df2 ) %>%                        # Combine with family mapping
  group_by( SampleID, Fam ) %>%                # Work on each sample/family pair
  summarize( ValSum = sum(Value) ) %>%         # Compute the sum across species
  ungroup %>% spread( Fam, ValSum, fill=0 )    # Convert back to wide format

根据每个样本是否代表每个家族,您可能会在转换回宽格式后得到 NA。可选参数 fill=0 负责将这些 NA 转换为 0.

另一种方式,使用library(data.table):

setDT(df1); setDT(df2) # Convert data.frames into data.tables

x = df2[melt(df1, variable.name = 'Sp'), on = 'Sp'] # Join melted df1 to df2 on species
df3 = dcast(x, SampleID~Fam, fun.aggregate = sum) # cast to wide format by summing total values per family