假设一个数据框df
有一个列speed
,那么访问列的方式有何不同,如下所示:
df["speed"]
或者像这样:
df$speed
以下正确计算平均值:
lapply(df["speed"], mean)
但是这会打印列速度下的所有值:
lapply(df$speed, mean)
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的面向对象特征,其中相同的行为以不同的方式针对不同类型的对象实现。
虽然这看起来像一个初学者的问题,我认为值得回答它,因为许多初学者可能会有类似的问题,相应的文档指南是有用的恕我直言。
请不要投票 - 我只是收集有助于答案的问题的评论片段 - 随时编辑这个答案...... *
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
表现不同?