假设数据框df
有一列speed
,那么访问该列的方式有何不同:
df["speed"]
或者像这样:
df$speed
以下正确计算平均值:
lapply(df["speed"], mean)
但是这会打印列速度下的所有值:
lapply(df$speed, mean)
答案 0 :(得分:4)
OP中的问题有两个要素。第一个元素在评论中得到解决:df["speed"]
是data.frame()
类型的对象,而df$speed
是数字向量。我们可以通过str()
函数看到这一点。
我们将用Ezekiel 1930年关于速度和停止距离的分析来说明这一点,即cars
包中的datasets
数据集。
> library(datasets)
> data(cars)
>
> str(cars["speed"])
'data.frame': 50 obs. of 1 variable:
$ speed: num 4 4 7 7 8 9 10 10 10 11 ...
> str(cars$speed)
num [1:50] 4 4 7 7 8 9 10 10 10 11 ...
>
评论中未解决的第二个要素是lapply()
在传递向量与list()
时的行为方式不同。
使用向量,lapply()
可以独立处理向量中的每个元素,从而为mean()
等函数生成意外结果。
> unlist(lapply(cars$speed,mean))
[1] 4 4 7 7 8 9 10 10 10 11 11 12 12 12 12 13 13 13 13 14 14 14 14 15 15
[26] 15 16 16 17 17 17 18 18 18 18 19 19 19 20 20 20 20 20 22 23 24 24 24 24 25
由于cars$speed
的每个元素都由mean()
独立处理,lapply()
会返回50个均值的列表,每个数量为1个数字:cars$speed
向量中的原始元素。
lapply()
使用列表,列表的每个元素都是独立处理的。我们可以使用lapply()
函数计算length()
处理的项目数。
> length(cars["speed"])
[1] 1
>
由于数据框也是list()
,其中包含data.frame()
类型的一个元素,因此length()
函数返回值1.因此,当由lapply()
处理时,计算单个均值,而不是speed
列的每一行。
> lapply(cars["speed"],mean)
$speed
[1] 15.4
>
如果我们将整个cars
数据帧作为lapply()
的输入对象传递,我们在数据帧中每列获得一个均值,因为数据框中的两个变量都是数字。
> lapply(cars,mean)
$speed
[1] 15.4
$dist
[1] 42.98
>
lapply()
的不同行为可以解释为R是一种面向对象的语言。事实上,R所基于的S语言的创建者John Chambers曾经说过:
在R中,两个标语很有帮助。
- 存在的一切都是一个对象,而且 - 发生的一切都是函数调用。
John Chambers,引自 Advanced R, p。 79。
lapply()
在数据框上的工作方式与向量不同的事实是polymorphism的面向对象特征的说明,其中对不同类型的对象以不同的方式实现相同的行为。
答案 1 :(得分:2)
虽然这看起来像一个初学者的问题但我认为值得回答它,因为许多初学者可能有类似的问题,并且相应文档的指南是有用的恕我直言。
请不要投票 - 我只是收集有助于答案的问题中的评论片段 - 随时编辑此答案... *
data.frame
是具有相同长度(元素数量)的向量列表。请阅读R控制台中的帮助(通过键入?data.frame
)
通过将一列作为向量($
)
?"$.data.frame"
运算符
lapply
将函数应用于列表的每个元素(请参阅?lapply
)。如果第一个参数X
是一个包含多个元素的标量向量(整数,双...),向量的每个元素都被转换为("强制")到一个单独的列表元素(与as.list(1:26)
相同)
<强>示例:强>
x <- data.frame(a = LETTERS, b = 1:26, stringsAsFactors = FALSE)
b.vector <- x$b
b.data.frame <- x["b"]
class(b.vector) # integer
class(b.data.frame) # data.frame
lapply(b.vector, mean)
# returns a result list with 26 list elements, the same as `lapply(1:26, mean)`
# [[1]]
# [1] 1
#
# [[2]]
# [1] 2
# ... up to list element 26
lapply(b.data.frame, mean)
# returns a list where each element of the input vector in param X
# becomes a separate list element (same as `as.list(1:26)`)
# $b
# [1] 13.5
所以恕我直言,您的原始问题可以简化为:如果第一个参数是标量向量而不是列表,为什么lapply
表现不同?