如何使用ddply或aggregate返回向量(如fivenum)的函数?

时间:2013-02-07 18:42:10

标签: r aggregate plyr

我想使用几列来分割我的数据框,并在每个组上调用let {}} {/ p>}。

fivenum

返回的值是一个只有2列的data.frame,第二个是矩阵。如何将其转换为data.frame的普通列?

更新

我希望使用aggregate(Petal.Width ~ Species, iris, function(x) summary(fivenum(x)))

以更少代码完成以下内容
fivenum

4 个答案:

答案 0 :(得分:10)

以下是使用data.table的解决方案(虽然没有特别要求,但它是对aggregateddply的明显恭维或替代。除了代码稍长,反复调用quantile效率低下,因为每次调用都会对数据进行排序

library(data.table)
Tukeys_five <- c("Min","Q1","Med","Q3","Max") 

IRIS <- data.table(iris)
# this will create the wide data.table
lengthBySpecies <- IRIS[,as.list(fivenum(Sepal.Length)), by = Species]

# and you can rename the columns from V1, ..., V5 to something nicer

setnames(lengthBySpecies, paste0('V',1:5), Tukeys_five)


lengthBySpecies



      Species Min  Q1 Med  Q3 Max
1:     setosa 4.3 4.8 5.0 5.2 5.8
2: versicolor 4.9 5.6 5.9 6.3 7.0
3:  virginica 4.9 6.2 6.5 6.9 7.9

或者,使用适当的quantile参数对prob进行一次调用。

IRIS[,as.list(quantile(Sepal.Length, prob = seq(0,1, by = 0.25))), by = Species]


       Species  0%   25% 50% 75% 100%
1:     setosa 4.3 4.800 5.0 5.2  5.8
2: versicolor 4.9 5.600 5.9 6.3  7.0
3:  virginica 4.9 6.225 6.5 6.9  7.9  

请注意,虽然您可以使用setnames

进行类似的重命名,但创建的列的名称在语法上并不有效。

编辑

有趣的是,如果设置quantilenames = TRUE将设置生成的向量的名称,这将复制(减慢数字运算速度并消耗内存 - 它甚至在帮助中警告你,花哨该!)

因此,您应该使用

 IRIS[,as.list(quantile(Sepal.Length, prob = seq(0,1, by = 0.25), names = FALSE)), by = Species]

或者,如果您想要返回命名列表,而不在内部复制{{1}

R

答案 1 :(得分:5)

您可以使用do.call递归调用每个矩阵元素上的data.frame来获取带有向量元素的data.frame:

dim(do.call("data.frame",dfr))
[1] 3 7

str(do.call("data.frame",dfr))
'data.frame':   3 obs. of  7 variables:
 $ Species            : Factor w/ 3 levels "setosa","versicolor",..: 1 2 3
 $ Petal.Width.Min.   : num  0.1 1 1.4
 $ Petal.Width.1st.Qu.: num  0.2 1.2 1.8
 $ Petal.Width.Median : num  0.2 1.3 2
 $ Petal.Width.Mean   : num  0.28 1.36 2
 $ Petal.Width.3rd.Qu.: num  0.3 1.5 2.3
 $ Petal.Width.Max.   : num  0.6 1.8 2.5

答案 2 :(得分:4)

据我所知,没有一种确切的方法来执行您所要求的操作,因为您正在使用的函数(fivenum)不会以一种可以轻松绑定到列的方式返回数据在'ddply'功能中。但是,这很容易以程序化的方式进行清理。

第1步:使用'ddply'函数对每个'Species'值执行fivenum函数。

data <- ddply(iris, .(Species), summarize, value=fivenum(Petal.Width))

#       Species value
# 1      setosa   0.1
# 2      setosa   0.2
# 3      setosa   0.2
# 4      setosa   0.3
# 5      setosa   0.6
# 6  versicolor   1.0
# 7  versicolor   1.2
# 8  versicolor   1.3
# 9  versicolor   1.5
# 10 versicolor   1.8
# 11  virginica   1.4
# 12  virginica   1.8
# 13  virginica   2.0
# 14  virginica   2.3
# 15  virginica   2.5

现在,'fivenum'函数返回一个列表,因此我们最终得到每个物种的5个行条目。这就是'fivenum'功能与我们作斗争的部分。

第2步:添加标签列。我们知道Tukey的五个数字是什么,所以我们只是按照'fivenum'函数返回它们的顺序调出它们。列表将重复,直到它到达数据的末尾。

Tukeys_five <- c("Min","Q1","Med","Q3","Max") 
data$label <- Tukeys_five

#       Species value label
# 1      setosa   0.1   Min
# 2      setosa   0.2    Q1
# 3      setosa   0.2   Med
# 4      setosa   0.3    Q3
# 5      setosa   0.6   Max
# 6  versicolor   1.0   Min
# 7  versicolor   1.2    Q1
# 8  versicolor   1.3   Med
# 9  versicolor   1.5    Q3
# 10 versicolor   1.8   Max
# 11  virginica   1.4   Min
# 12  virginica   1.8    Q1
# 13  virginica   2.0   Med
# 14  virginica   2.3    Q3
# 15  virginica   2.5   Max

第3步:使用标签,我们可以使用'reshape2'软件包中的'dcast'函数快速将此数据转换为新形状。

library(reshape2)
dcast(data, Species ~ label)[,c("Species",Tukeys_five)]

#      Species Min  Q1 Med  Q3 Max
# 1     setosa 0.1 0.2 0.2 0.3 0.6
# 2 versicolor 1.0 1.2 1.3 1.5 1.8
# 3  virginica 1.4 1.8 2.0 2.3 2.5

最后的所有垃圾都只是指定列顺序,因为'dcast'函数会自动按字母顺序排列。

希望这有帮助。

更新:我决定回来,因为我意识到还有另外一个选项可供您使用。您始终可以将矩阵绑定为数据框定义的一部分,因此您可以像这样解析“聚合”函数:

data <- aggregate(Petal.Width ~ Species, iris, function(x) summary(fivenum(x))) 
result <- data.frame(Species=data[,1],data[,2])

#      Species Min. X1st.Qu. Median Mean X3rd.Qu. Max.
# 1     setosa  0.1      0.2    0.2 0.28      0.3  0.6
# 2 versicolor  1.0      1.2    1.3 1.36      1.5  1.8
# 3  virginica  1.4      1.8    2.0 2.00      2.3  2.5

答案 3 :(得分:0)

这是我的解决方案:

ddply(iris, .(Species), summarize, value=t(fivenum(Petal.Width)))