这是一些示例数据:
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存在逻辑混乱.它可以在其他电脑上复制.请先做,然后继续讨论.
以下是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等.
由于默认情况下aggregate处理NA值的公式方法如何,您需要在使用na.rm参数之前覆盖它sum.您可以通过设置na.action为NULL或执行此操作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)