R提供了两种不同的方法来访问list或data.frame中的元素:[]和[[]]。

这两者之间的区别是什么,什么时候我应该使用其中一个而不是另一个?


当前回答

请参考以下详细说明。

我使用了R中的内置数据框架,称为mtcars。

> mtcars 
               mpg cyl disp  hp drat   wt ... 
Mazda RX4     21.0   6  160 110 3.90 2.62 ... 
Mazda RX4 Wag 21.0   6  160 110 3.90 2.88 ... 
Datsun 710    22.8   4  108  93 3.85 2.32 ... 
           ............

表的顶部行称为标题,其中包含列名。之后的每条水平线表示一个数据行,它以行名开始,然后跟着实际数据。 一行中的每个数据成员称为一个单元格。

单个方括号“[]”运算符

要检索单元格中的数据,可以在单个方括号“[]”操作符中输入它的行坐标和列坐标。这两个坐标用逗号分隔。换句话说,坐标以行位置开始,然后以逗号结尾,以列位置结束。顺序很重要。

例1:-这是mtcars的第一行第二列的单元格值。

> mtcars[1, 2] 
[1] 6

例2:-此外,我们可以使用行名和列名来代替数字坐标。

> mtcars["Mazda RX4", "cyl"] 
[1] 6 

双方括号“[[]]”操作符

我们用双方括号“[[]]”操作符引用数据帧列。

例1:-为了检索内置数据集mtcars的第九列向量,我们编写mtcars[[9]]。

山地车[[9]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...

例2:-我们可以通过名称检索相同的列向量。

MTCARS[[“AM”]] [1] 1 1 1 0 0 0 0 0 0 0 0 ...

其他回答

只是在这里添加[[也用于递归索引。

@JijoMatthew在回答中暗示了这一点,但没有深入探讨。

正如在?"[["中所指出的,像x[[y]]这样的语法,其中长度(y) > 1被解释为:

x[[ y[1] ]][[ y[2] ]][[ y[3] ]] ... [[ y[length(y)] ]]

注意,这并没有改变关于[和[[]之间的主要区别,即前者用于子集设置,后者用于提取单个列表元素。

例如,

x <- list(list(list(1), 2), list(list(list(3), 4), 5), 6)
x
# [[1]]
# [[1]][[1]]
# [[1]][[1]][[1]]
# [1] 1
#
# [[1]][[2]]
# [1] 2
#
# [[2]]
# [[2]][[1]]
# [[2]][[1]][[1]]
# [[2]][[1]][[1]][[1]]
# [1] 3
#
# [[2]][[1]][[2]]
# [1] 4
#
# [[2]][[2]]
# [1] 5
#
# [[3]]
# [1] 6

要得到值3,我们可以这样做:

x[[c(2, 1, 1, 1)]]
# [1] 3

回到上面@JijoMatthew的答案,回想一下r:

r <- list(1:10, foo=1, far=2)

特别是,这解释了我们在误用[[时往往会得到的错误,即:

r[[1:3]]

r[[1:3]]中的错误:递归索引在级别2失败

由于这段代码实际上试图求值r[[1]][[2]][[3]],并且r的嵌套在第一级停止,因此通过递归索引提取的尝试在[[2]]失败,即在第2级。

r[[c("foo", "far")]]错误:下标越界

这里,R正在寻找R [["foo"]][["far"]],而R并不存在,所以我们得到了下标越界错误。

如果这两个错误给出相同的信息,可能会更有帮助/一致一些。

对于另一个具体的用例,当您想要选择split()函数创建的数据帧时,使用双括号。如果您不知道,split()会根据关键字段将列表/数据帧分组为子集。如果你想对多个组进行操作,绘制它们,等等,这很有用。

> class(data)
[1] "data.frame"

> dsplit<-split(data, data$id)
> class(dsplit)
[1] "list"

> class(dsplit['ID-1'])
[1] "list"

> class(dsplit[['ID-1']])
[1] "data.frame"

哈德利·维克汉姆:

我(蹩脚的外观)修改显示使用tidyverse / purrr:

作为术语,[[操作符从列表中提取元素,而[操作符获取列表的子集。

为了帮助新手在手动迷雾中导航,看看[[…]]]符号作为一个折叠函数-换句话说,当你只是想从一个命名向量,列表或数据帧中“获取数据”时。如果您想使用来自这些对象的数据进行计算,那么这样做是很好的。这些简单的例子将说明。

(x <- c(x=1, y=2)); x[1]; x[[1]]
(x <- list(x=1, y=2, z=3)); x[1]; x[[1]]
(x <- data.frame(x=1, y=2, z=3)); x[1]; x[[1]]

从第三个例子来看

> 2 * x[1]
  x
1 2
> 2 * x[[1]]
[1] 2