《Advanced R》
最常用的子集运算符是[]
,除此之外还有[[]]
和$
首先[[]]
:
[[]]
和[]
用法类似,不同的是[[]]
可以从列表中取子集,而且它只能返回single value
由于data frame
是由一列一列的list
构成的,固然也可以使用[[]]
来提取列
当[]
用于list
,返回的结果也是list
形式,而用[[]]
可以直接得到其内容(打破list框架)
举个例子:如果list x 是一辆火车,那么x[[5]]是5号车厢中的乘客,而x[5]是5号车厢
a <- list(a = 1, b = 2)
a[[1]]
#> [1] 1
a[["a"]]
#> [1] 1
# 如果你提供一个向量,它会循环索引
b <- list(a = list(b = list(c = list(d = 1))))
b[[c("a", "b", "c", "d")]]
#> [1] 1
# 同样的
b[["a"]][["b"]][["c"]][["d"]]
#> [1] 1
其次$
:
$
是一个简化符号,x$y
等同于x[["y" , exact = FALSE]]
通常用于访问data frame
中的列,即variables
$
只能用列名直接提取,而不能用储存在变量中的列名去提取
var <- "cyl"
# Doesn't work - mtcars$var translated to mtcars[["var"]]
mtcars$var
#> NULL
但是[[]]
可以
mtcars[[var]]
#> [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
此外[[]]
和$
还有一个重要区别
$
可以进行部分匹配
x <- list(abc = 1)
x$a
#> [1] 1
x[["a"]]
#> NULL
当遇到缺失值NA
或越界索引OOB
(out of bounds) 时
举例:
- 当你尝试在长度为4的向量中提取第5个元素时;
- 当你取带有NA或NULL的向量子集时
x <- 1:4
str(x[5])
#> int NA
str(x[NA_real_])
#> int NA
str(x[NULL])
#> int(0)
子集化和赋值
所有子集运算符都可以与赋值运算符结合使用,以修改输入向量的选定值
# 赋值特定位置
x <- 1:5
x[c(1, 2)] <- 2:3
x
#> [1] 2 3 3 4 5
x[-1] <- 4:1
x
#> [1] 2 4 3 2 1
# 赋值重复位置
# 直接被覆盖
x[c(1, 1)] <- 2:3
x
#> [1] 3 4 3 2 1
# 整数混入NA,报错
x[c(1, NA)] <- c(1, 2)
#> Error in x[c(1, NA)] <- c(1, 2): NAs are not allowed in subscripted assignments
# 逻辑值混入NA,可以
# 因为NA在逻辑值中视为FALSE
x[c(T, F, NA)] <- 1
x
#> [1] 1 4 3 1 1
# 当遇到条件修改向量
df <- data.frame(a = c(1, 10, NA))
df$a[df$a < 5] <- 0
df$a
#> [1] 0 10 NA
不带任何内容的子集设置与赋值一起使用非常有用,因为它将保留原始对象类和结构。
比较以下两个表达式:
- 在第一种情况下,
mtcars
将保留为数据帧; - 在第二种情况下,
mtcars
将成为一个列表。
mtcars[] <- lapply(mtcars, as.integer)
mtcars <- lapply(mtcars, as.integer)
对于列表,可以使用subsetting + assignment + NULL
从列表中删除组件
要将 NULL
添加到列表中,使用 []
然后 list(NULL)
:
x <- list(a = 1, b = 2)
x[["b"]] <- NULL
str(x)
#> List of 1
#> $ a: num 1
y <- list(a = 1)
y["b"] <- list(NULL)
str(y)
#> List of 2
#> $ a: num 1
#> $ b: NULL