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

时间:2013-12-30 11:27:49

标签: r aggregate

以下是一些示例数据:

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   

如何在A中获得Cx1 以及的总和?

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

当我使用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

为什么我在第一行获得<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 ...

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

我可以证明x4和x5中的所有NA都是这样的:

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

因此sqldf以不同方式处理sum(x4)sum(x5)这一事实非常奇怪,我认为sqldf存在逻辑混乱。它可以在其他电脑上复制。请先做,然后继续讨论。

4 个答案:

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

如果您希望sum在删除NA之后返回NA而不是总和,请删除na.rm=TRUE参数。

.SD这是一个内部data.table变量,默认情况下构建by以外的所有列 - 除了x1之外的所有列。您可以通过执行以下操作检查.SD的内容:

dt[, print(.SD), by=x1]

了解.SD是什么。如果您有兴趣,请检查?data.table其他内部(非常有用)特殊变量,例如.I.N.GRP等。

答案 1 :(得分:5)

由于aggregate的公式方法默认处理NA值,您需要在使用na.rm中的sum参数之前覆盖它。您可以将na.action设置为NULLna.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

关于sqldf,根据第一个分组变量的第一行中的项目是NA还是<{1}},似乎会将这些列投射到不同类型不。如果是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

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

示例(前面创建了相同的“df2”):

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

您可以轻松使用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

如果您希望将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

答案 2 :(得分:2)

aggregate(data[, -1], by=list(data$x1), FUN=sum)

我删除了第一列,因为你没有在总和中使用它,它只是一个分组数据的组变量(事实上我在“by”中使用它)

答案 3 :(得分:2)

以下是使用reshape包执行此操作的方法:

> # x1 = identifier variable, everything else = measured variables
> data_melted <- melt(data, id="x1", measured=c("x2", "x3", "x4", "x5"))
>
> # Thus we now have (measured variable and it's value) per x1 (id variable)
> head(data_melted)
  x1 variable value
1  C       x2     1
2  A       x2     1
3  A       x2     1
4  A       x2     4
5  C       x2     4
6  A       x2     1

> tail(data_melted)
   x1 variable value
43  A       x5    NA
44  A       x5    NA
45  B       x5    32
46  A       x5    NA
47  B       x5    32
48  B       x5    16

> # Now aggregate using sum, passing na.rm to it
> cast(data_melted, x1 ~ ..., sum, na.rm=TRUE)
  x1 x2  x3  x4 x5
1  A 12 192 192  0
2  B 11 176  96 80
3  C  5  80   0 80

或者,您可以在na.rm过程中完成melt()

学习library(reshape)的好处是,引用作者("Reshaping Data with the reshape Package"),

  

“在R中,有许多可以聚合数据的通用函数,   例如tapply,by和aggregate,以及一个特定的函数   重塑数据,重塑。这些功能中的每一个都易于处理   有一个或两个特定场景,每个场景需要稍微不同   输入参数。在实践中,你需要仔细考虑   将正确的操作顺序放在一起以获取数据   你想要的形式。重塑包装源于我的挫败感   为咨询客户重塑数据,并克服这些   使用两个一般概念框架的问题   功能:熔化和铸造。“