aggregate()将多个输出列放在矩阵中

TMS*_*TMS 8 aggregate r

我要为某个变量计算多个分位数:

> res1 <- aggregate(airquality$Wind, list(airquality$Month), function (x) quantile(x, c(0.9, 0.95, 0.975)))
> head(res1)
  Group.1   x.90%   x.95% x.97.5%
1       5 16.6000 17.5000 18.8250
2       6 14.9000 15.5600 17.3650
3       7 14.3000 14.6000 14.9000
4       8 12.6000 14.0500 14.6000
5       9 14.9600 15.5000 15.8025
Run Code Online (Sandbox Code Playgroud)

结果看起来很好,但聚合实际上以一种非常奇怪的形式返回它,其中最后3列不是data.frame的列,而是单个矩阵!

> names(res1)
[1] "Group.1" "x"      
> dim(res1)
[1] 5 2
> class(res1[,2])
[1] "matrix"
Run Code Online (Sandbox Code Playgroud)

这在进一步处理中引起许多问题.

几个问题:

  1. 为什么aggregate()表现得如此奇怪?
  2. 有没有办法说服它取得我期望的结果?
  3. 或者我可能为此目的使用了错误的功能?有没有其他优先方法来获得想要的结果?

当然我可以对aggregate()的输出进行一些转换,但我寻找一些更简单直接的解决方案.

A5C*_*2T1 11

Q1:为什么这种行为如此奇怪?

这实际上是一种记录在案的行为?aggregate(虽然它可能仍然是意料之外的).要看的相关论点是simplify.

如果simplify设置为FALSE,aggregate则会产生list类似这样的情况.

res2 <- aggregate(airquality$Wind, list(airquality$Month), function (x) 
  quantile(x, c(0.9, 0.95, 0.975)), simplify = FALSE)
str(res2)
# 'data.frame':  5 obs. of  2 variables:
#  $ Group.1: int  5 6 7 8 9
#  $ x      :List of 5
#   ..$ 1  : Named num  16.6 17.5 18.8
#   .. ..- attr(*, "names")= chr  "90%" "95%" "97.5%"
#   ..$ 32 : Named num  14.9 15.6 17.4
#   .. ..- attr(*, "names")= chr  "90%" "95%" "97.5%"
#   ..$ 62 : Named num  14.3 14.6 14.9
#   .. ..- attr(*, "names")= chr  "90%" "95%" "97.5%"
#   ..$ 93 : Named num  12.6 14.1 14.6
#   .. ..- attr(*, "names")= chr  "90%" "95%" "97.5%"
#   ..$ 124: Named num  15 15.5 15.8
#   .. ..- attr(*, "names")= chr  "90%" "95%" "97.5%"
Run Code Online (Sandbox Code Playgroud)

现在,a matrix和a list列似乎都是奇怪的行为,但我认为它更像是"设计状态"而不是"bug"或"缺陷".

例如,请考虑以下内容:我们希望聚合"airquality"数据集中的"Wind"和"Temp"列,并且我们知道每个聚合将产生多个列(就像我们期望的那样quantile).

res3 <- aggregate(cbind(Wind, Temp) ~ Month, airquality, 
                  function (x) quantile(x, c(0.9, 0.95, 0.975)))
res3
#   Month Wind.90% Wind.95% Wind.97.5% Temp.90% Temp.95% Temp.97.5%
# 1     5  16.6000  17.5000    18.8250   74.000   77.500     79.500
# 2     6  14.9000  15.5600    17.3650   87.300   91.100     92.275
# 3     7  14.3000  14.6000    14.9000   89.000   91.500     92.000
# 4     8  12.6000  14.0500    14.6000   94.000   95.000     96.250
# 5     9  14.9600  15.5000    15.8025   91.100   92.550     93.000
Run Code Online (Sandbox Code Playgroud)

在某些方面,将这些值保留为matrix-columns可能有意义 - 数据聚合数据可通过其原始列名轻松访问:

res3$Temp
#       90%   95%  97.5%
# [1,] 74.0 77.50 79.500
# [2,] 87.3 91.10 92.275
# [3,] 89.0 91.50 92.000
# [4,] 94.0 95.00 96.250
# [5,] 91.1 92.55 93.000
Run Code Online (Sandbox Code Playgroud)

Q2:如何将结果作为单独的列中的data.frame

但在很多情况下,作为一个列,作为一个列list处理起来就像笨拙一样matrix.如果要将"展平" matrix到列中,请使用do.call(data.frame, ...):

do.call(data.frame, res1)
#   Group.1 x.90. x.95. x.97.5.
# 1       5 16.60 17.50 18.8250
# 2       6 14.90 15.56 17.3650
# 3       7 14.30 14.60 14.9000
# 4       8 12.60 14.05 14.6000
# 5       9 14.96 15.50 15.8025
str(.Last.value)
# 'data.frame':  5 obs. of  4 variables:
#  $ Group.1: int  5 6 7 8 9
#  $ x.90.  : num  16.6 14.9 14.3 12.6 15
#  $ x.95.  : num  17.5 15.6 14.6 14.1 15.5
#  $ x.97.5.: num  18.8 17.4 14.9 14.6 15.8a
Run Code Online (Sandbox Code Playgroud)

问题3:还有其他选择吗?

和大多数事情一样,R当然是.我首选的选择是使用"data.table"包,您可以使用它:

library(data.table)
as.data.table(airquality)[, as.list(quantile(Wind, c(.9, .95, .975))), 
                          by = Month]
#    Month   90%   95%   97.5%
# 1:     5 16.60 17.50 18.8250
# 2:     6 14.90 15.56 17.3650
# 3:     7 14.30 14.60 14.9000
# 4:     8 12.60 14.05 14.6000
# 5:     9 14.96 15.50 15.8025
str(.Last.value)
# Classes ‘data.table’ and 'data.frame':  5 obs. of  4 variables:
#  $ Month: int  5 6 7 8 9
#  $ 90%  : num  16.6 14.9 14.3 12.6 15
#  $ 95%  : num  17.5 15.6 14.6 14.1 15.5
#  $ 97.5%: num  18.8 17.4 14.9 14.6 15.8
#  - attr(*, ".internal.selfref")=<externalptr> 
Run Code Online (Sandbox Code Playgroud)