向量

向量筛选 属于 R

3 个练习

关于 向量筛选

我们在Vectors概念中看到,向量可以用在条件表达式里,得到一个逻辑向量。 而逻辑向量又可以用在诸如all()和any()这样的函数中。

v <- c(4, 7, 10)
v >= 6
#> [1] FALSE  TRUE  TRUE
all(v > 6)
#> [1] FALSE    # not all elements match this condition
any(v > 6)
#> [1] TRUE     # at least one element matches

这项技术的作用远不止于此。

向量子集

可以用一个下标数字或一个下标向量,把向量中选定的元素取出来:

v <- 5:10
v
#> [1]  5  6  7  8  9 10
v[3] 
#> [1] 7
v[c(2, 4)]
#> [1] 6 8

另一种做法是用逻辑向量筛选原向量,返回其中与TRUE值匹配的那些元素的子集:

v <- 1:3
bools <- c(FALSE, TRUE, TRUE)
v[bools]
#> [1] 2 3

从这里再走一小步,就可以用条件表达式生成这个布尔向量:

bools <- v >= 2
bools
#> [1] FALSE  TRUE  TRUE

v[bools]
#> [1] 2 3

# simpler form
v[v >= 2]
#> [1] 2 3

这些条件表达式可以任意复杂,可以涉及多个向量或函数:

v <- 1:10
w <- 10:1

# pairwise comparison
v > w
#> [1] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE

# shorter form
v[v > w]
#> [1]  6  7  8  9 10

命名

我们把这个概念命名为“向量筛选”,希望这样能让尽可能多的程序员都看得懂。

在 R 社区里,“子集选取”这个说法可能更常见。

循环补齐

为简单起见,上面的例子比较的都是长度相同的向量。 如果长度对不上,会怎样?

结果会是一种刻意使用时非常强大、意外出现时却让人困惑的机制。

举个例子:

v <- 1:6
cond <- c(TRUE, FALSE)
v[cond]
#> [1] 1 3 5

这里发生了什么? 我们用一个长度为 2 的布尔向量给长度为 6 的向量取下标,结果却得到一个长度为 3 的向量。

如果某个向量对于它所在的表达式来说“太短”了,R 就会重复它,直到达到所需长度:这叫做“循环补齐”。 这就把我们的c(TRUE, FALSE)向量变成了c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE),接着v[cond]返回了v中值为TRUE的那些元素:在这里就是奇数。

那么下面这个例子里又发生了什么?

v <- 1:3
0.5 * v
#> [1] 0.5 1.0 1.5
2 + v
#> [1] 3 4 5

乍一看像是标量乘法,以及(略显奇怪的)标量加法,但 R 里根本没有标量。

实际上,这些数字会被循环补齐,得到一个与v长度相同的向量,然后使用c(0.5, 0.5, 0.5)或c(2, 2, 2)逐元素地进行运算。

Caution

循环补齐非常非常有用,但一定要确认这就是你想要的。

向量长度稍有出入(例如 99 与 100),就可能引发让人困惑的 bug。

有些作者建议,只有当其中一个向量的长度为 1 时,才应该使用循环补齐。

查找下标

which()函数接受一个布尔实参,返回一个由结果为TRUE的下标组成的向量。

v
#> [1] 2 7 9

v[v > 5]  # returns values
#> [1]  7  9

which(v > 5) # returns indices
#> [1] 2 3

检查某个元素是否存在

前面几节讲的是找出符合某个条件的元素。

如果你只是想知道向量里是否包含某个特定元素,可以用%in%运算符。

3 %in% 1:5
#> [1] TRUE
7 %in% 1:5
#> [1] FALSE

它在功能上等同于下面这段代码,但用起来方便得多:

length(v[v == 3]) > 0
#> [1] TRUE

此外还有一个%notin%运算符,它给出%in%的逻辑not。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 向量筛选

练习已锁定

再解锁 2 个练习即可练习 向量筛选