これは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
この関数や同様の関数は、2つだけでなく任意の数の入力ベクトルを受け取ります。
上の例では、同じ長さのベクトルを使っています。 ベクトルのフィルタリングの概念で説明したように、Rは「短すぎる」ベクトルをリサイクルして長さを合わせます。 繰り返しますが、これは慎重に使い、できれば長さ1のベクトルにだけ使ってください。
pmax(v, 5)
#> [1] 5 7 9
これはあまり一般的ではありませんが、一見するとスカラー入力に見えて、実際にはベクトルを出力する関数を書くのはそれほど難しくありません。
ベクトルを入力として与えると、出力は2次元のmatrixになります(後の概念で扱います)。