如何在R中按组向量行和

时间:2018-08-07 18:20:27

标签: r

假设我有一个像这样的数据框:

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

我想要的是rowSums()的组矢量,它是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

我的真实数据集有来自18个小组的超过110K cols,并且会找到一种优雅而简单的方法来实现它。

4 个答案:

答案 0 :(得分:2)

由于data.frame的内部构造方式,行操作通常比列操作慢得多。给定您对data.frame实际大小的评论,我可能会使用data.table将其转换为long,将组作为其自己的变量隔离,并进行按组求和。

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

首先,使用data.framedata.table转换为setDT

library(data.table)

setDT(df)

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

df[, row_number := 1:.N]

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

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列,该列应位于“。”之后。在新的“变量”列中(^.*?\\.是从字符串开头到第一个“。”的所有内容; gsub(pattern, "", variable)pattern中删除了variable)。

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

最后,按sum(value)row_numbergroup进行分组。 在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 :(得分:2)

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 :(得分: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

答案 3 :(得分:0)

使用dplyr

new_df <- df %>% 
  mutate(ones = rowSums(select(., grep(".1", names(df), value = TRUE))),
         twos = rowSums(select(., grep(".2", names(df), value = TRUE)))) %>% 
  select(ones, twos)

new_df

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