这是 R 中的一个重要概念。 为了更好地理解各种可能性,从各个函数的输入和输出的维度来考虑会很有帮助。
我们已经见过一些接收向量、返回单个类似标量的值的函数:
v <- 1:5
length(v)
#> [1] 5
sum(v)
#> [1] 15
许多统计函数也属于这一类,比如 mean()。
对于逻辑向量,有 all() 和 any(),它们返回单个 TRUE 或 FALSE。
R 中的许多函数会作用于整个向量,通常输出也是向量。 这包括大多数数学函数:
sq <- c(4, 9, 16, 25)
sqrt(sq) # square root
#> [1] 2 3 4 5
这不仅简洁方便,还省去了循环、列表推导式或递归的需要,而这些在其他语言中很常见。 在 R 中,向量函数往往比这些技术运行得快得多。
你用过向量化函数的次数,可能比你以为的要多。比较下面这些:
v <- c(2, 7, 9)
w <- c(3, 1, 5)
v + w
#> [1] 5 8 14
"+"(v, w)
#> [1] 5 8 14
熟悉的中缀运算符,不过是底层向量化函数的语法糖!在这里就是 "+"()。
要对向量排序,可以用 sort() 返回值,用 order() 返回下标:
v <- c("I", "am", "not", "in", "order")
sort(v)
#> [1] "am" "I" "in" "not" "order"
order(v)
#> [1] 2 1 4 3 5
默认按升序排序。
如有需要,可以指定 decreasing = TRUE,也可以用 rev() 反转已有的向量。
v <- c("I", "am", "not", "in", "order")
sort(v, decreasing = TRUE)
#> [1] "order" "not" "in" "I" "am"
rev(1:4)
#> [1] 4 3 2 1
还有一些函数,比如 cumsum() 和 cumprod(),可以生成累积的向量输出,从左到右依次作用于输入向量:
cumsum(1:5)
#> [1] 1 3 6 10 15 # sums
cumprod(1:5)
#> [1] 1 2 6 24 120 # equivalent to factorials
上面的例子类似于许多函数式语言中的 foldl 操作,区别在于输出的是一个包含所有中间值的向量。
把这个概念加以延伸,还可以用来比较向量。
例如,考虑逐对取最大值的函数 pmax():
v
#> [1] 2 7 9
w
#> [1] 3 1 5
pmax(v, w)
#> [1] 3 7 9 # max of each pairwise comparison
这个函数以及类似的其他函数也接受任意数量的输入向量,而不只是两个。
上面的例子使用的是长度相等的向量。 正如向量过滤概念中所讨论的,R 会用循环补齐来扩展那些“太短”的向量。 再强调一次:请谨慎使用,最好只用长度为 1 的向量。
pmax(v, 5)
#> [1] 5 7 9
这种情况不太常见,但写出看似标量输入、实则向量输出的函数相当容易。
当作用于向量输入时,输出是一个二维的 matrix,后面的概念会讲到它。