df [“速度”]和df $速度之间的差异

问题描述 投票:1回答:2

假设一个数据框df有一个列speed,那么访问列的方式有何不同,如下所示:

df["speed"]

或者像这样:

df$speed

以下正确计算平均值:

lapply(df["speed"], mean) 

但是这会打印列速度下的所有值:

lapply(df$speed, mean)
r dataframe
2个回答
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的面向对象特征,其中相同的行为以不同的方式针对不同类型的对象实现。


2
投票

虽然这看起来像一个初学者的问题,我认为值得回答它,因为许多初学者可能会有类似的问题,相应的文档指南是有用的恕我直言。

请不要投票 - 我只是收集有助于答案的问题的评论片段 - 随时编辑这个答案...... *

  1. data.frame是具有相同长度(元素数量)的向量列表。请阅读R控制台中的帮助(输入?data.frame
  2. 通过将一列作为向量返回来实现$运算符(?"$.data.frame"
  3. 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表现不同?

© www.soinside.com 2019 - 2024. All rights reserved.