如何获得聚合函数的所有总和?

it_*_*ure 8 aggregate r

这是一些示例数据:

dat="x1 x2 x3 x4 x5
1   C  1 16 NA 16
2   A  1 16 16 NA
3   A  1 16 16 NA
4   A  4 64 64 NA
5   C  4 64 NA 64
6   A  1 16 16 NA
7   A  1 16 16 NA
8   A  1 16 16 NA
9   B  4 64 32 32
10  A  3 48 48 NA
11  B  4 64 32 32
12  B  3 48 32 16"

data<-read.table(text=dat,header=TRUE)   
aggregate(cbind(x2,x3,x4,x5)~x1, FUN=sum, data=data)   
 x1 x2  x3 x4 x5   
1  B 11 176 96 8   
Run Code Online (Sandbox Code Playgroud)

我如何获得的总和A,并C 以及x1

 aggregate(.~x1, FUN=sum, data=data, na.action = na.omit)  
   x1 x2  x3 x4 x5
 1  B 11 176 96 80 
Run Code Online (Sandbox Code Playgroud)

我用的时候sqldf:

library("sqldf")
sqldf("select sum(x2),sum(x3),sum(x4),sum(x5) from data group by x1")
  sum(x2) sum(x3) sum(x4) sum(x5)
1      12     192     192    <NA>
2      11     176      96      80
3       5      80      NA      80
Run Code Online (Sandbox Code Playgroud)

为什么我会<NA>进入第一行,但是NA在第三行?它们之间有什么区别?为什么我得到了<NA><NA>数据中没有!

str(data)
'data.frame':   12 obs. of  5 variables:
 $ x1: Factor w/ 3 levels "A","B","C": 3 1 1 1 3 1 1 1 2 1 ...
 $ x2: int  1 1 1 4 4 1 1 1 4 3 ...
 $ x3: int  16 16 16 64 64 16 16 16 64 48 ...
 $ x4: int  NA 16 16 64 NA 16 16 16 32 48 ...
 $ x5: int  16 NA NA NA 64 NA NA NA 32 NA ...
Run Code Online (Sandbox Code Playgroud)

sqldf问题仍然存在,为什么sum(x4)得到NA,相反sum(x5)得到<NA>

我可以证明NAx4和x5都是这样的:

data[is.na(data)] <- 0     

> data
   x1 x2 x3 x4 x5
1   C  1 16  0 16
2   A  1 16 16  0
3   A  1 16 16  0
4   A  4 64 64  0
5   C  4 64  0 64
6   A  1 16 16  0
7   A  1 16 16  0
8   A  1 16 16  0
9   B  4 64 32 32
10  A  3 48 48  0
11  B  4 64 32 32
12  B  3 48 32 16
Run Code Online (Sandbox Code Playgroud)

所以sqldf对待sum(x4)sum(x5)不同的事实是如此奇怪,以至于我认为sqldf存在逻辑混乱.它可以在其他电脑上复制.请先做,然后继续讨论.

Aru*_*run 6

以下是data.table您感兴趣的方式:

require(data.table)
dt <- data.table(data)
dt[, lapply(.SD, sum, na.rm=TRUE), by=x1]
#    x1 x2  x3  x4 x5
# 1:  C  5  80   0 80
# 2:  A 12 192 192  0
# 3:  B 11 176  96 80
Run Code Online (Sandbox Code Playgroud)

如果要在删除NA后sum返回NA而不是总和,只需删除na.rm=TRUE参数即可.

.SD这是一个内部data.table变量,默认情况下构造所有不在的列by- 这里除了x1.您可以通过以下方式检查内容.SD:

dt[, print(.SD), by=x1]
Run Code Online (Sandbox Code Playgroud)

了解什么是.SD.如果你有兴趣支票?data.table像其他内部(和非常有用的)特殊变量.I,.N,.GRP等.


A5C*_*2T1 5

由于默认情况下aggregate处理NA值的公式方法如何,您需要在使用na.rm参数之前覆盖它sum.您可以通过设置na.actionNULL或执行此操作na.pass:

aggregate(cbind(x2,x3,x4,x5) ~ x1, FUN = sum, data = data, 
          na.rm = TRUE, na.action = NULL)
#   x1 x2  x3  x4 x5
# 1  A 12 192 192  0
# 2  B 11 176  96 80
# 3  C  5  80   0 80

aggregate(cbind(x2,x3,x4,x5) ~ x1, FUN = sum, data = data, 
          na.rm = TRUE, na.action = na.pass)
#   x1 x2  x3  x4 x5
# 1  A 12 192 192  0
# 2  B 11 176  96 80
# 3  C  5  80   0 80
Run Code Online (Sandbox Code Playgroud)

关于sqldf,根据第一个分组变量的第一行中的项是否是一个,似乎将列转换为不同类型NA.如果是NA,则该列被转换为character.

相比:

df1 <- data.frame(id = c(1, 1, 2, 2, 2),
                 A = c(1, 1, NA, NA, NA),
                 B = c(NA, NA, 1, 1, 1))
sqldf("select sum(A), sum(B) from df1 group by id")
#   sum(A) sum(B)
# 1      2   <NA>
# 2     NA    3.0

df2 <- data.frame(id = c(2, 2, 1, 1, 1),
                  A = c(1, 1, NA, NA, NA),
                  B = c(NA, NA, 1, 1, 1))
sqldf("select sum(A), sum(B) from df2 group by id")
#   sum(A) sum(B)
# 1   <NA>      3
# 2    2.0     NA
Run Code Online (Sandbox Code Playgroud)

但是,有一个简单的解决方法:将原始名称重新分配给正在创建的新列.也许让我们的SQLite继承以前数据库中的一些信息?(我真的不使用SQL.)

示例(前面创建的"df2"相同):

sqldf("select sum(A) `A`, sum(B) `B` from df2 group by id")
#    A  B
# 1 NA  3
# 2  2 NA
Run Code Online (Sandbox Code Playgroud)

您可以轻松地使用它paste来创建select语句:

Aggs <- paste("sum(", names(data)[-1], ") `", 
              names(data)[-1], "`", sep = "", collapse = ", ")
sqldf(paste("select", Aggs, "from data group by x1"))
#   x2  x3  x4 x5
# 1 12 192 192 NA
# 2 11 176  96 80
# 3  5  80  NA 80
str(.Last.value)
# 'data.frame':  3 obs. of  4 variables:
#  $ x2: int  12 11 5
#  $ x3: int  192 176 80
#  $ x4: int  192 96 NA
#  $ x5: int  NA 80 80
Run Code Online (Sandbox Code Playgroud)

如果要NA替换为0以下内容,可以采用类似的方法:

Aggs <- paste("sum(ifnull(", names(data)[-1], ", 0)) `", 
              names(data)[-1], "`", sep = "", collapse = ", ")
sqldf(paste("select", Aggs, "from data group by x1"))
#   x2  x3  x4 x5
# 1 12 192 192  0
# 2 11 176  96 80
# 3  5  80   0 80
Run Code Online (Sandbox Code Playgroud)