如何在R中将函数应用于列的子集?

6
我正在使用 by 来对数据帧的一组列应用函数,基于一个因子。如果我使用 mean() 作为函数,一切都可以运行得很完美,但是如果我使用 median(),我会得到一个类型为 "Error in median.default(x) : need numeric data" 的错误信息,即使在数据框中没有缺失值。
使用 mean() 的代码行:
by(iris[,1:3], iris$Species, function(x) mean(x,na.rm=T))

> by(iris[,1:3], iris$Species, function(x) mean(x,na.rm=T))
iris$Species: setosa
Sepal.Length  Sepal.Width Petal.Length 
       5.006        3.428        1.462 
------------------------------------------------------------ 
iris$Species: versicolor
Sepal.Length  Sepal.Width Petal.Length 
       5.936        2.770        4.260 
------------------------------------------------------------ 
iris$Species: virginica
Sepal.Length  Sepal.Width Petal.Length 
       6.588        2.974        5.552 
Warning messages:
1: mean(<data.frame>) is deprecated.
 Use colMeans() or sapply(*, mean) instead. 
2: mean(<data.frame>) is deprecated.
 Use colMeans() or sapply(*, mean) instead. 
3: mean(<data.frame>) is deprecated.
 Use colMeans() or sapply(*, mean) instead. 

但是如果我使用 median() 函数(注意加上 na.rm=T 参数):

> by(iris[,1:3], iris$Species, function(x) median(x,na.rm=T))
Error in median.default(x, na.rm = T) : need numeric data

然而,如果我选择的不是列范围[,1:3],而只是其中的一列,则会起作用:
> by(iris[,1], iris$Species, function(x) median(x,na.rm=T))
iris$Species: setosa
[1] 5
------------------------------------------------------------ 
iris$Species: versicolor
[1] 5.9
------------------------------------------------------------ 
iris$Species: virginica
[1] 6.5

如何在选择一系列列时实现此行为?

当你使用 mean 函数时收到的警告信息应该是一个强烈的提示,实际上,并不是一切都“正常运行”。我最近的回答可能会为您解决这个问题。 - joran
2个回答

4
当您使用by时,您正在使用分割-应用策略。传递给函数的对象是数据框,由于median.data.frame不存在以及mean.data.frame即将不存在,因此会出现警告和错误。如果您使用aggregate,可能会更好地工作:
> aggregate(iris[,1:3], iris["Species"], function(x) mean(x,na.rm=T))
     Species Sepal.Length Sepal.Width Petal.Length
1     setosa        5.006       3.428        1.462
2 versicolor        5.936       2.770        4.260
3  virginica        6.588       2.974        5.552
> aggregate(iris[,1:3], iris["Species"], function(x) median(x,na.rm=T))
     Species Sepal.Length Sepal.Width Petal.Length
1     setosa          5.0         3.4         1.50
2 versicolor          5.9         2.8         4.35
3  virginica          6.5         3.0         5.55
< p > aggregate 按列向量分别进行操作,然后汇总结果。


谢谢。现在它可以工作了。 我现在只是怀疑aggregate(iris[,1:3], iris["Species"], function(x) median(x,na.rm=T))aggregate(iris[,1:3], iris$Species, function(x) median(x,na.rm=T))之间有什么区别。第二个会返回错误信息:Error in aggregate.data.frame(iris[, 1:3], iris$Species, function(x) median(x,na.rm=T)) : 'by' must be a list - pedrosaurio
1
@pedrosaurio 错误信息已经表明了一切。iris["Species"] 是一个列表(事实上是数据框),而 iris$Species 不是。您可以使用 str() 来验证这一点。 - joran
1
我想添加一条注释,说明你使用的是 $Species,它等同于 [["Species"]],返回一个原子向量,而我使用的是 ["Species"],返回一个列表。我想我应该这样做。 - IRTFM

1
原始问题已得到解答。然而,如果范围恰好是除公式中指定的自变量之外的所有列,则点公式符号有效,并表示一种巧妙的替代方法:
> aggregate(. ~ Species, data = iris, mean)
     Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1     setosa        5.006       3.428        1.462       0.246
2 versicolor        5.936       2.770        4.260       1.326
3  virginica        6.588       2.974        5.552       2.026

> aggregate(. ~ Species, data = iris, median)
     Species Sepal.Length Sepal.Width Petal.Length Petal.Width
1     setosa          5.0         3.4         1.50         0.2
2 versicolor          5.9         2.8         4.35         1.3
3  virginica          6.5         3.0         5.55         2.0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接