先に触れたように,Rで取り扱うデータにはデータ型(data type)とデータ構造(data structure)があります.ここでは,データ構造について解説します.オブジェクトがデータなどを入れる箱であると見做せるということはすでに解説しましたが,データ構造とはこの箱の形状を意味します.主要なデータ構造としてベクトル(vector),行列(matrix),配列(array),データフレーム(data frame),リスト(list)があります.
ベクトルは1つ以上の要素(element)を一次元に配置したデータ構造です.ただし,ベクトルに含まれるすべての要素は同一のデータ型でなくてはなりません.仮に数値と文字列が混在しているとすると,すべての要素は文字列に変換されます.行列はベクトルを行方向,あるいは列方向に結合した二次元のデータ構造で,矩形データ(rectangular data)を表現するために使用します.Excelなどのスプレッドシートで構築されたデータはおおよそ矩形データに該当します.次に,配列とは行列を重ねた三次元のデータ構造です.行列や配列もベクトルと同様に,単一のデータ型の値しか許容しません.なお,配列を用いる機会あまり多くはないため,本稿では配列の作成方法等については割愛します.
データフレームは行列を拡張したデータ構造で,列ごとに異なるデータ型を許容します.すなわち,1列目は数値,2列目は文字列,3列目は論理値,というようなデータを構築できます.そのため,データフレームはRで最もよく使用されるます.最後に,リストはあらゆるデータ構造を要素として格納できる柔軟なデータ構造です.よって,リストは様々なオブジェクトを一括管理するために広く利用されます.
本稿ではこれらのデータ構造に加えて,因子(factor)という特殊なデータ構造を採り上げます.ベクトルから順に作成方法,操作方法,計算方法について解説します.
2.1 ベクトルの作成
ベクトルはRの基本となるデータ構造です。行列やデータフレームなどを作成するときにもベクトルを利用することが多く,そのためベクトルはとても重要なデータ構造です.ベクトルを作成する関数はc関数です.この c は combine が由来であると言われています.まず,以下ではベクトルの要素の数が5,すなわちベクトルの長さ(vector length)が5のベクトルを作成し,オブジェクトに代入します.文字列のベクトルを作成するときは,これまでと同様に文字列をダブルクォーテーションで囲みます.もしダブルクォーテーションを付けなければ文字列ではなくオブジェクトと認識されるため注意が必要です.
v1 <- c(5, 8, 1, 9, 7)
v1
[1] 5 8 1 9 7
v2 <- c("a", "d", "c", "b", "a")
v2
[1] "a" "d" "c" "b" "a"
次に,c関数の括弧の中に数値と文字列が混在した場合を見ていきます.先に述べたように,ベクトルというデータ構造は単一のデータ型しか許容しません.この場合,数値は数字へと変換され,以下のようにすべての要素が文字列に変換されます.数値と数字の見分け方は,出力結果にダブルクォーテーションが付くか否かです.数値はダブルクォーテーションが付きませんが,数字は下記のようにダブルクォーテーションが付きます.
test <- c(1, 2, "a", "b", "c")
test
[1] "1" "2" "a" "b" "c"
この他に,指定した区間内で刻み幅が1となる数値からなるベクトルを作成するとき,いくつか作成方法がありますが,コロンを使用する方法が最も簡単です.この方法は反復処理を実行するときによく使用します.
v3 <- 1:5
v3
[1] 1 2 3 4 5
コロンの使用は刻み幅が1に限定されますが,刻み幅が等間隔であるベクトルを作成するときはseq関数を用います.この seq は sequence に由来します.seq関数は第1引数で始めの値,第2引数は取り得る値の上限値,第3引数の by で刻み幅を指定します.また,by の代わりに length という引数を使用することもあります.length で指定するのはベクトルの要素の数であり,第1引数と第2引数の範囲内で等間隔になるように,指定した個数の数値からなるベクトルを作成します.
v4 <- seq(1, 10, by = 3)
v4
[1] 1 4 7 10
v4 <- seq(1, 10, length = 4)
v4
[1] 1 4 7 10
特定の要素,あるいはベクトルを指定した回数だけ複製するための関数にrep関数があります.これは複製を意味する英単語の replicate に由来します.下記の例は,1 から 5 までの整数を3回繰り返すベクトルの作成方法です.rep関数は数値だけではなく文字列や論理値の複製も可能です.なお,引数の "times =" は省略できます.
v5 <- rep(1:5, times = 3)
v5
[1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
v5 <- rep(v3, 3)
v5
[1] 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
このようにベクトルは複数の要素を一括して管理するためのデータ構造であると言えます.また,データ型の解説において,オブジェクトに1つの数値,あるいは1つの文字列を代入していますが,これは要素数が1のベクトルとなります.
2.2 ベクトルの操作
次にベクトルの操作方法を概観します.ベクトルに代入されている特定の要素を参照したいときは,添え字(index)を用いてその要素の番号を指定します.上掲の v1 を例とすると,v1 には 5, 8, 1, 9, 7 という5つの要素が代入されています.vec1の 8 という数値を参照したいのであれば、8 は2番目の要素ですので,下記のように添え字を付けます.
v1[2]
[1] 8
このように,Rでは添え字が1から始まります.他のプログラミング言語は添え字が 0 から始まることもありますので,他のプログラミング言語に慣れ親しんでいる人は注意をしてください.また,複数の要素を参照したいのであれば,c関数を利用して添え字を記述します.例えば,v2 から1番目と4番目の要素を参照するのであれば,以下のように記述します.つまり,添え字の中に抽出したい要素の番号を代入したベクトルを記述します.
v2[c(1, 4)]
[1] "a" "b"
この添え字を用いることで,ベクトルの要素を他の値に置換することが可能です.上掲のv1の2番目の要素を 99 に置き換えるならば,添え字で要素を指定して99を代入します.ただし,要素の置換は不可逆な処理であることに注意が必要です.
v1[2] <- 99
v1
[1] 5 99 1 9 7
ベクトルに新たな要素を追加するためにはc関数を使用する方法と添え字を利用する方法があります.添え字を利用する方法は置換と同様に不可逆な処理になるため,あまり推奨はしません.まずはc関数を使用する方法です.例として,v1に 10 と 11 の2つの値を追加します.
v6 <- c(v1, 10, 11)
v6
[1] 5 99 1 9 7 10 11
次いで,添え字を利用する方法です.v1の要素は5つですので,当たり前のことですが6番目以降の値を持っていません.そこで,下記のように6番目に 10 を,7番目に 11 を代入します.これによってベクトルに新しい2つの数値が追加されます.
v1[6] <- 10
v1[7] <- 11
v1
[1] 5 99 1 9 7 10 11
ベクトルから特定の要素の削除にも添え字を利用します.先ほど作成したv6から2番目の要素である 99 を削除するためには,添え字にマイナス記号を付けます.これによって指定された要素が削除されます.複数の要素を削除するときは,添え字の中にc関数を記述し削除する要素の番号を指定します.
v6[-2]
[1] 5 1 9 7 10 11
v6[-c(6, 7)]
[1] 5 99 1 9 7
2.3 ベクトルの演算
複数の値に対して同一の処理を行うのであれば,ベクトルを使用すると効率的に計算できます.例えば,v1のすべての要素に10を加えるとき,あるいはv1のすべての値を2乗するときは次のように実行します.
v1 <- c(5, 8, 1, 9, 7)
v1 + 10
[1] 15 18 11 19 17
v1 ^ 2
[1] 25 64 1 81 49
複数のベクトルを用いて計算するときは,ベクトルの長さ(ベクトルの要素の数)に留意する必要があります.例えば,v1と同じ長さのベクトルとの和を求める場合と異なる長さのベクトルとの和を求める場合を見ていきます.
v1 <- c(5, 8, 1, 9, 7)
v7 <- 1:5
v1 + v7
[1] 6 10 4 13 12
v8 <- 1:3
v1 + v8
[1] 6 10 4 10 9
Warning message:
In v1 + v8 :
longer object length is not a multiple of shorter object length
前者の場合はv1とv7の長さが同一であるため,それぞれのベクトルの1つめの要素から順に計算されています.一方,後者はv8が3つしか要素を持っていないため,v1の4つめと5つめの要素はv8の1つめと2つめの要素との計算が行われます.これをリサイクル規則(vector recycling rule)と言います.後者の計算ではこのリサイクル規則が適用されたため,警告メッセージ(warning messege)が表示されています.このメッセージは「長いベクトルが短いベクトルの整数倍の長さになっていない」ことを警告しています.そのため,長いベクトルが短いベクトルの整数倍の長さであるときは警告メッセージが表示されません.
2.4 便利な関数
Rではベクトルの各要素にラベルを付与することが可能です.例えば,47都道府県の人口を代入したベクトルを作成したとき,どの数値がどの都道府県に対応しているのか分からなくなることがあります.このような場合にラベルの付与は効果的です.ラベルの付与にはnames関数を使用します.例として,5つの要素を持つ上掲のv1にAからEの1文字のアルファベットをラベルとして与えます.
v1 <- c(5, 8, 1, 9, 7)
names(v1)
NULL
names(v1) <- c("A", "B", "C", "D", "E")
v1
A B C D E
5 8 1 9 7
names関数はラベルの付与に使用されることが多いですが,各要素のラベルを確認するためにも使用されます.もしベクトルにラベルが付与されていなければ,上記のように戻り値はNULLとなります.なお,NULLは「ヌル」ではなく「ナル」と読みます.また,names関数はベクトル以外にも後述のデータフレームやリストにも使用できます.
次に,データの加工や分析を行うときに,対象のベクトルの要素数を求めなくてはならないことがあります.その場合はlength関数を使用します.length関数はベクトルの他に因子やリストなどにも用いることがあります.特に反復処理を行うときに利用することが多いと思われます.
v1 <- c(5, 8, 1, 9, 7)
length(v1)
[1] 5
質的変数を表現するためのデータ構造として,因子という特殊なデータ構造があります.質的変数には名義尺度と順序尺度がありますが,Rではそれぞれ順序なし因子(unordered factor)と順序付き因子(ordered factor)となります.順序なし因子および順序付き因子のいずれもRの内部では整数で構成されるベクトルになっており,この整数に質的変数のラベルを対応づけています.実際にRで分析を行うときに,因子がデータ構造であることを意識しなくてはならない場面は少なく,文字列や論理値と同様のデータ型として取り扱っても大きな問題はありません.
なお,Rの4.0.0より前のバージョンでは,インポートしたデータに文字列が含まれると自動的に因子に変換されましたが,現行のRでは文字列が強制的に因子に変換されることはありません.R 4.0.0がリリースされたのは2020年4月24日ですので,それ以前の書籍やWeb記事等を参考にする場合は注意してください.
3.1 因子の作成
因子を作成する関数はfactor関数です.因子を作成するためには,まずベクトルを作成し,これを因子に変換します.ベースとなるベクトルは文字列と数値のいずれでも良いですが,実際のデータ分析では文字列ベクトルの方が扱いやすいと思います.例えば,下記のようにcha1というベースとなる文字列ベクトルを作成します.このcha1は"abc","def","ghi"という3種類の文字列からなる5つの要素を持っています.これらの文字列をlevels引数に記述することで,文字列ベクトルが因子へと変換されます.
cha1 <- c("abc", "def", "abc", "ghi", "ghi")
f1 <- factor(cha1, levels = c("abc", "def", "ghi"))
f1
[1] abc def abc ghi ghi
Levels: abc def ghi
f1に代入されている値は文字列ではなく因子であるため,出力された値にはダブルクォーテーションが付かず,Levelsという項目が付記されています.Levelsは因子における各水準の名称を指しています.factor関数ではlabels引数を用いることで,各水準の名称を自由に変更できます.例えば,"abc","def","ghi"という水準の名称を"X","Y","Z"に変更するのであれば以下のようになります.
f2 <- factor(cha1, levels = c("abc", "def", "ghi"), labels = c("X", "Y", "Z"))
f2
[1] X Y X Z Z
Levels: X Y Z
f1とf2はいずれも順序なし因子です.順序付き因子を作成するならば,ordered引数を追記します.ordered引数はデフォルトの値がFALSEとなっており,これをTRUEとすることで当該のベクトルは順序付き因子になります.また,各水準の順序はlevels引数に記述されている順に小さな値となります.
f3 <- factor(cha1, levels = c("abc", "def", "ghi"), ordered = TRUE)
f3
[1] abc def abc ghi ghi
Levels: abc < def < ghi
f4 <- factor(cha1, levels = c("abc", "def", "ghi"), labels = c("X", "Y", "Z"), ordered = TRUE)
f4
[1] X Y X Z Z
Levels: X < Y < Z
上記の方法は文字列ベクトルから順序付き因子の作成方法です.上掲のf1やf2のような順序なし因子がすでに作成されている場合は,factor関数の第1引数をf1やf2としてordered引数を追記するだけで順序付き因子が作成されます.
f3 <- factor(f1, ordered = TRUE)
f3
[1] abc def abc ghi ghi
Levels: abc < def < ghi
f4 <- factor(f2, ordered = TRUE)
f4
[1] X Y X Z Z
Levels: X < Y < Z
3.2 ベクトルから因子への変換
次に,as.factor関数を使用してベクトルを因子に変換する方法を解説します.as.factor関数は文字列ベクトルをそのまま順序なし因子に変換するときに用います.そのため,因子の水準の名称を変更するときにはlevels関数を,順序付き因子を作成するときにはordered関数を利用しなくてはなりません.
cha1 <- c("a", "b", "a", "c", "c")
f5 <- as.factor(cha1)
f5
[1] a b a c c
Levels: a b c
levels(f5) <- c("X", "Y", "Z")
f5
[1] X Y X Z Z
Levels: X Y Z
f6 <- ordered(f5, levels = c("X", "Y", "Z"))
f6
[1] X Y X Z Z
Levels: X < Y < Z
上記のようにlevels関数はnames関数と似たような機能を有する関数です.names関数がベクトルの各要素のラベルの確認に使用できたように,levels関数も水準の名称の確認にも使用できます.また,因子を再び文字列に戻すのであれば,as.character関数を使用します.
4.1 行列の作成
行列を作成するにはmatrix関数を使用します.まず必要な長さのベクトルを準備し,matrix関数のnrow引数で行数を、ncol引数で列数を指定することで行列を生成します。
m1 <- matrix(1:12, nrow = 3, ncol = 4)
m1
[,1] [,2] [,3] [,4]
[1,] 1 4 7 10
[2,] 2 5 8 11
[3,] 3 6 9 12
上掲の例では1から12までの整数からなる長さ12のベクトルを用意し,これを3行4列の行列に変換しています.Rでは列優先(column-major)で要素が配置されるため,1列目の1行目,2行目,3行目,次に2列目の1行目という順序で値が行列に代入されます.この例ではベクトルの長さが12であるため,行数か列数のいずれか一方を指定すれば,もう一方は自ずと決定されます.そのため,nrow引数かncol引数のいずれかを指定しても問題はありません.また,行列に行優先(row-major)で要素を配置したい場合は,matrix関数にbyrow引数をTRUEとします.
test <- matrix(1:12, nrow = 3, byrow = TRUE)
test
[,1] [,2] [,3] [,4]
[1,] 1 2 3 4
[2,] 5 6 7 8
[3,] 9 10 11 12
5.1 データフレームの作成
データフレームはデータ分析を行うときに最もよく使用されるデータ構造です.Excelなどの表計算ソフトで作成されたデータをRにインポートすると,特殊な関数を使用した場合を除き,基本的にはデータフレームとして扱われます.
データフレームを作成する関数はdata.frame関数です.
リストの作成はとても簡単です.
7.1 データ構造の確認
オブジェクトに代入されているデータ構造を確認するときには,データ型の確認と同様にclass関数を使用します.ただし,他のデータ構造とは異なり,ベクトルに対してclass関数を実行すると,vectorとはならずnumericやcharacterなどのデータ型が出力されます.
v1 <- c(5, 8, 1, 9, 7)
class(v1)
[1] "numeric"
v2 <- c("a", "d", "c", "b", "a")
class(v2)
[1] "character"