Rのvector(厳密にはatomic vector)は、同じtypeの値の集まりです。よく使われるのはinteger、numeric、character、logicalで、complexやrawはまれです。
これらはCの配列と同様に、メモリ上に連続して格納されます。
型の異なる値を渡すと、Rはそれらをこっそり共通の型(たいていはcharacter)に変換してしまいます。これが思わぬ結果を招くことがあります。
v <- c(2, 5.4, "txt")
v
#> [1] "2" "5.4" "txt"
typeof(v)
#> [1] "character"
すべての値がすでに手元にあるなら、c()("concatenate"の略)を使います。
x <- 10
v <- c(4, 7, x)
c()関数はとても柔軟で、入力には他のベクトルや範囲を含めることもできます。
c()はどんな数・種類の入力でも受け取り、それらを1つのベクトルにまとめます。
ベクトルが小さく始まって実行中に大きく成長する場合(たとえばループの中で値を追加する場合)は、あらかじめ長いベクトルを確保しておき、あとから実際のデータで埋めるほうが、格段に速くなることがあります。
v <- vector(length = 100)
こうするとオブジェクトをコピーする必要が最小限になります。長いベクトルでは、このコピーは遅く、メモリを大量に消費する処理だからです。
連続する値の範囲(増加または減少)には、:記法が使えます。
v <- 1:5 # equivalent to c(1, 2, 3, 4, 5)
w <- 10:7 # c(10, 9, 8, 7)
Rでは、範囲は独立した型ではなく、ベクトルを作るための省略記法にすぎません。
seq()関数を使うと、より細かく制御できます。
# specify step size
seq(2, 11, by = 3) # c(2, 5, 8, 11)
# specify number of values, evenly-spaced
seq(2.5, 4, length.out = 5) # c(2.500, 2.875, 3.250, 3.625, 4.000)
rep()関数を使うと、繰り返しのパターンを簡単に作れます。
count <- 3
rep(7, count)
#> [1] 7 7 7
rep(1:3, count)
#> [1] 1 2 3 1 2 3 1 2 3
rep(1:3, each = 2) # the "each" keyword is required in this case
#> [1] 1 1 2 2 3 3
いくつかの範囲は、組み込み定数としてあらかじめ定義されています。
letters # LETTERS is the UPPERCASE equivalent
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"
month.name
#> [1] "January" "February" "March" "April" "May" "June" "July" "August"
#> [9] "September" "October" "November" "December"
month.abb
#> [1] "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
演算はベクトルに沿って自動的に要素ごとに適用されます。 他の言語でよく使われるループ、リスト内包表記、再帰は必要なく、(性能上の理由から)できれば避けるべきです。
2 + 1:3 # c(3, 4, 5)
2 * 1:3 # c(2, 4, 6)
12 / 1:3 # c(12 6 4)
2 ^ (1:3) # c(2, 4, 8) : exponentiation, operator precedence order here needs ()
2つのベクトルの組でも同じように動作し、要素はペアごとに処理されます。
v <- 1:3
w <- 5:7
v + w
#> [1] 6 8 10
v * w
#> [1] 5 12 21
v ^ w
#> [1] 1 64 2187
これは一見する以上に強力で、後の概念でさらに詳しく見ていきます。
多くの言語と同じように、角括弧([])の中にインデックスを書いてアクセスできます。
v <- 4:7
v[2]
#> [1] 5
v[2:4]
#> [1] 5 6 7
ただし注意が必要です。Rはデフォルトで1始まりのインデックスを使います。 これは科学技術計算向けの言語(Fortran、Matlab、Julia)ではよくあることですが、Cとその後継言語の多くが使う0始まりのインデックスとは異なります。
範囲は上の例のように使えるほか、非常に柔軟なc()関数の中でも使えます。
v <- c(4, 7, 10)
w <- c(2, v[2:3], 11) # c(2, 7, 10, 11)
vectorsは(Rのほとんどのものと同様に)可変として扱え、似た柔軟な記法で1つの要素にも複数の要素にも書き込めます。
v <- 1:10
v[2] <- 42
v[4:6] <- c(11, 12, 13)
v
#> [1] 1 42 3 11 12 13 7 8 9 10
他の言語に慣れたプログラマーなら、v[-1]がベクトルの最後の要素にアクセスする方法だと推測するかもしれません。
それは間違いです!
その用途にはtail()を使います。
v <- c(2, 4, 6) # defaults to last 6 entries
tail(v)
#> [1] 2 4 6
tail(v, n=1) # just the last entry
#> [1] 6
負のインデックスは、実は要素を取り除くための方法です。
v <- c(2, 4, 6)
v[-2]
#> [1] 2 6 # second element gone
これはベクトルの短いコピーを返します。v自体は変わりません。
ベクトルに比較を適用すると、同じ長さの真偽値のベクトルが返ります。
これは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
もっと複雑な論理式では、ベクトルに対して働く&と|演算子を使うことが重要です。
2文字の&&と||は、[真偽値の概念][concept-boolean]で説明するように、単一の値の比較のためだけのものです。
v <- c(4, 7, 10)
v %% 2 == 0 & v > 5
#> [1] FALSE FALSE TRUE
これは後のトピックで再び取り上げるテーマです。 今は、コンソールでの出力の形式だけ覚えておきましょう。
1:20
#> [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#> [18] 18 19 20
各行は[ ]に入った数字で始まり、最初の要素のインデックスを示します(複数行に折り返す長いベクトルで便利です)。
しかし、なぜ単一の値にも[1]が付くのでしょうか?
Rには真の意味でのスカラー値は存在しません!
単一の数値や文字に見えるものも、実は長さ1のベクトルなのです。
数値型と論理型を扱う基本と真偽値の概念で、すでにこの片鱗を見てきました。
ここまで説明してきたベクトルは、より正式にはatomic vectorsと呼ばれます。numeric、character、booleanのような単純で分割できない(ゆえに"atomic"な)値しか入れられないからです。より複雑な構造はrecursive vectorsを作ることができ、これはlistsを扱うときに紹介します。