8

我想使用几列拆分我的数据框,然后fivenum在每个组上调用。

aggregate(Petal.Width ~ Species, iris, function(x) summary(fivenum(x)))

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

更新

我想要类似下面的代码,使用更少的代码fivenum

ddply(iris, .(Species), summarise,
      Min = min(Petal.Width),
      Q1 = quantile(Petal.Width, .25),
      Med = median(Petal.Width),
      Q3 = quantile(Petal.Width, .75),
      Max = max(Petal.Width)
      )
4

4 回答 4

11

这是一个使用(虽然没有特别要求,但它是对ordata.table的明显补充或替代。除了代码有点长之外,重复调用效率低下,因为对于每个调用,您都将对数据进行排序aggregateddplyquantile

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


编辑

有趣的是,quantile如果您设置,将设置结果向量的名称names = TRUE,这将复制(减慢数字运算并消耗内存 - 它甚至会在帮助中警告您,看中了!)

因此,您可能应该使用

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

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

IRIS[,{quant <- as.list(quantile(Sepal.Length, prob = seq(0,1, by = 0.25), names = FALSE))
       setattr(quant, 'names', Tukeys_five)
       quant}, by = Species]
于 2013-02-11T01:46:35.280 回答
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
于 2013-02-07T19:38:44.273 回答
4

据我所知,没有一种确切的方法可以满足您的要求,因为您使用的函数 (fivenum) 不会以可以轻松绑定到 ' 中的列的方式返回数据ddply 函数。不过,这很容易以编程方式清理。

第 1 步fivenum使用“ddply”函数对每个“物种”值执行函数。

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
于 2013-02-07T19:22:52.883 回答
0

这是我的解决方案:

ddply(iris, .(Species), summarize, value=t(fivenum(Petal.Width)))
于 2015-10-04T22:55:54.627 回答