如何在R中按组向量计算行总和?

4
假设我有一个类似这样的数据框:
df<-data.frame(A.1=1:5,B.1=2:6,C.1=3:7, 
               D.2=4:8,E.2=5:9,F.2=6:10)
df
  A.1 B.1 C.1 D.2 E.2 F.2
1   1   2   3   4   5   6
2   2   3   4   5   6   7
3   3   4   5   6   7   8
4   4   5   6   7   8   9
5   5   6   7   8   9  10

我想对df的列名(例如c(1,1,1,2,2,2))进行分组,并使用rowSums()函数,输出如下:
      1  2
[1,]  6 15
[2,]  9 18
[3,] 12 21
[4,] 15 24
[5,] 18 27

我的真实数据集包括来自18个组的超过110K个cols,我希望找到一种优雅且易于实现的方法。


dim 的大小为 33694 x 166438。 - David Z
压缩后的文件大小为500M。 - David Z
我给了你的建议一个赞。谢谢。 - David Z
我创建了一个向量。 - David Z
1
@李哲源 类似这样的代码 data.frame(lapply(split.default(df, sub('^.\\.', '', names(df))), rowSums)) - acylam
我已经完成了。谢谢! - David Z
4个回答

3

rowsum 可以实现此功能:

t(rowsum(t(df), c(1,1,1,2,2,2)))

      1  2
[1,]  6 15
[2,]  9 18
[3,] 12 21
[4,] 15 24
[5,] 18 27

(由于某种原因,没有colsum函数。)

2

由于 data.frame 的内部结构,按行进行的操作通常比按列进行的操作慢得多。考虑到您关于这个 data.frame 的实际大小的评论,我可能会使用 data.table 将其转换为长格式,将组单独作为变量进行隔离,并执行分组求和操作。

df <- data.frame(
  A.1 = 1:5,
  B.1 = 6:10,
  C.2 = 11:15,
  D.2 = 16:20
)

首先,使用setDTdata.frame转换为data.table

library(data.table)

setDT(df)

接着,添加一个 row_number 列 (:= 创建一个新列; .N 是一个特殊变量,它包含表中行数)。

df[, row_number := 1:.N]

使用 row_number 作为唯一ID列将其转换为“长”data.table

df_long <- melt(df, id.vars = "row_number")
df_long
#>     row_number variable value
#>  1:          1      A.1     1
#>  2:          2      A.1     2
#>  3:          3      A.1     3
#>  4:          4      A.1     4
#>  5:          5      A.1     5
#>  6:          1      B.1     6
#>  7:          2      B.1     7
#>  8:          3      B.1     8
#>  9:          4      B.1     9
#> 10:          5      B.1    10
#> 11:          1      C.2    11
#> 12:          2      C.2    12
#> 13:          3      C.2    13
#> 14:          4      C.2    14
#> 15:          5      C.2    15
#> 16:          1      D.2    16
#> 17:          2      D.2    17
#> 18:          3      D.2    18
#> 19:          4      D.2    19
#> 20:          5      D.2    20

创建一个新的 group 列,该列包含在新的 "variable" 列中 "." 之后的所有内容(^.*?\\. 表示从字符串开头到第一个 "." 的所有内容;gsub(pattern, "", variable)variable 中移除 pattern)。
df_long[, group := as.integer(gsub("^.*?\\.", "", variable))]
df_long
#>     row_number variable value group
#>  1:          1      A.1     1     1
#>  2:          2      A.1     2     1
#>  3:          3      A.1     3     1
#>  4:          4      A.1     4     1
#>  5:          5      A.1     5     1
#>  6:          1      B.1     6     1
#>  7:          2      B.1     7     1
#>  8:          3      B.1     8     1
#>  9:          4      B.1     9     1
#> 10:          5      B.1    10     1
#> 11:          1      C.2    11     2
#> 12:          2      C.2    12     2
#> 13:          3      C.2    13     2
#> 14:          4      C.2    14     2
#> 15:          5      C.2    15     2
#> 16:          1      D.2    16     2
#> 17:          2      D.2    17     2
#> 18:          3      D.2    18     2
#> 19:          4      D.2    19     2
#> 20:          5      D.2    20     2

最后,按row_numbergroup分组执行sum(value)操作。 这种类型的操作在data.table中非常快速,比基本的R更快且更高效。
df_long[, sum(value), by = list(row_number, group)]
#>     row_number group V1
#>  1:          1     1  7
#>  2:          2     1  9
#>  3:          3     1 11
#>  4:          4     1 13
#>  5:          5     1 15
#>  6:          1     2 27
#>  7:          2     2 29
#>  8:          3     2 31
#>  9:          4     2 33
#> 10:          5     2 35

1
使用 dplyr
df %>% 
 mutate(ones = rowSums(select(., grep(".1", names(.), value = TRUE))),
        twos = rowSums(select(., grep(".2", names(.), value = TRUE)))) %>% 
 select(ones, twos)

  ones twos
1    6   15
2    9   18
3   12   21
4   15   24
5   18   27

0

使用库dplyrreshape2。您可以逐行执行每个命令(不带有尾随的%>%),以了解转换过程。基本思路是将其melt成整洁(高)格式以操作行,然后将其dcast回宽格式。

library(dplyr)
library(reshape2)
df %>% 
  # assign a row number for later grouping
  mutate(rn=row_number()) %>%
  # make into a tall data frame, with rn as the row key
  melt(id.vars = "rn") %>% 
  # calculate the row suffix for grouping
  mutate(suffix = str_extract(variable, "\\d+")) %>%
  # put it back into a dataframe, summing value (could use acast if you want an array)
  dcast(rn ~ suffix, value.var="value", fun.aggregate = sum)

#   rn  1  2  
# 1  1  6 15
# 2  2  9 18
# 3  3 12 21
# 4  4 15 24
# 5  5 18 27

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接