16 リスト・データフレーム・行列
16.1 リスト(list)
リスト(list)は様々なデータ型・クラスのオブジェクトを一つにまとめたものです。リストの要素となるのは、ベクター、リスト、データフレーム、行列などで、どのようなデータ型・クラスであってもリストの要素にすることができます。
リストの作成には、list
関数を用います。list
関数の引数がリストの要素となります。
16.1.1 リストの名前
ベクターと同様に、リストの要素には名前(names)をつけることができ、要素を名前から呼び出すことができます。名前からの呼び出しでは、ベクターと同じように四角カッコ([ ]
)内に文字列を記入して呼び出してもよいですし、$
(ドルマーク)を用いて呼び出すこともできます。ただし、[ ]
と$
では、返り値の型が異なります([ ]
ではリスト、$
では要素が返ってくる)。
名前の確認・設定はベクターと同じ方法で行います。リストの名前の確認・変更には、names
関数を用います。names
関数の引数にリストを取ると、そのリストの名前が返ってきます。names
関数の引数にリストを取り、文字列ベクターを代入するとリストの名前を設定できます。
16.1.2 リストのインデックス
リストのインデックスは、基本的には二重角カッコ([[ ]]
)で指定します。通常の角カッコ([ ]
)で指定すると、リストの要素がリストのまま返ってきます。角カッコ([ ]
)で返ってくるのはリストですので、コロンを用いて複数の要素をリストとして取り出すことができます。
リストの要素(ベクターや行列)のさらに要素を取り出すには、二重角カッコの後に、ベクターや行列に対応したインデックス指定([1]
や[1, 2]
など)をつけることになります。
リストのインデックス
lst[1] # リストの1番目の要素(リストが返ってくる)
## $a
## [1] 1 2 3 4
lst[[1]] # リストの1番目の要素(要素が返ってくる)
## [1] 1 2 3 4
lst[1:2] # リストの1~2番目の要素(リストが返ってくる)
## $a
## [1] 1 2 3 4
##
## $b
## [1] "dog"
lst[[1]][2] # リストの1番目の要素(ベクター)の2つ目の要素
## [1] 2
16.1.3 リストの長さ(length)
リストは、名前(names)の他に、長さ(length)の特性を持ちます。リストのlengthはリストの要素の数です。リストのlengthもベクターと同じく、length
関数で確認することができます。
リストのアトリビュートはattributes
関数で確認することができます。アトリビュートをattr
関数で別途追加しない場合には、アトリビュートとしては名前を設定したリストではnames
だけが表示されます。各要素のデータ型はstr
関数やsummary
関数を用いて確認することができます。
リストの長さとデータ型
length(lst)
## [1] 3
attributes(lst)
## $names
## [1] "a" "b" "c"
str(lst)
## List of 3
## $ a: num [1:4] 1 2 3 4
## $ b: chr "dog"
## $ c: logi [1:5] TRUE FALSE TRUE TRUE FALSE
summary(lst)
## Length Class Mode
## a 4 -none- numeric
## b 1 -none- character
## c 5 -none- logical
16.1.4 リストへの要素の追加
c
関数を用いることで、リストに要素を追加することができます。また、リストに要素を追加する場合には、ドルマークを用いて設定されていない名前を指定し、代入を行うこともできます。設定されている名前を用いて代入した場合には、その要素が書き換えられます。
リストへの要素の追加
lst <- c(lst, d = "added object") # リストに名前dの要素を追加
lst
## $a
## [1] 1 2 3 4
##
## $b
## [1] "dog"
##
## $c
## [1] TRUE FALSE TRUE TRUE FALSE
##
## $d
## [1] "added object"
# リストに名前eの要素を追加(データフレームにも使える)
lst$e <- "objects can be added with named index" # 名前eの要素を追加
lst$d <- "changed object" # dの要素を変更
lst # 追加・変更後のリスト
## $a
## [1] 1 2 3 4
##
## $b
## [1] "dog"
##
## $c
## [1] TRUE FALSE TRUE TRUE FALSE
##
## $d
## [1] "changed object"
##
## $e
## [1] "objects can be added with named index"
16.1.5 リストのベクター化
リストを全部まとめて1つのベクターにする場合には、unlist
関数を用います。unlist
関数はリストの要素をすべて1次元のベクターに変更します。ベクターに変更すると、ベクターの型が要素の型によって変更されるので、注意が必要です。unlist
関数はリストだけでなく、データフレームの行のデータをベクターにするのにも用いられます。
リストのベクター化
unlist(lst[1:3]) # 文字列のベクターに変換される
## a1 a2 a3 a4 b c1 c2 c3 c4 c5
## "1" "2" "3" "4" "dog" "TRUE" "FALSE" "TRUE" "TRUE" "FALSE"
16.2 データフレーム(data.frame)
Rで最も使用頻度が高いクラスの一つがデータフレーム(data.frame)です。データフレームはExcelの表のような構造を持つクラスで、data.frame
関数を用いて作成することができます。data.frame
関数の引数は各列のベクターで、各列の名前を引数で設定することができます(リストと同じく、「列名=ベクター」という形で設定)。
データフレームは、同じ長さのベクターを列に取ったリストです。ですので、class
関数ではデータフレーム、mode
関数ではリストが返ってきます。
データフレームの作成時に、長さの異なるベクターを用いた場合には、反復(recycling)のルールに従い、短いベクターが長いベクターの長さに合わせて反復されます。
データフレームを作成する
# データフレームをdata.frame関数で作成する
d <- data.frame(x = c("dog", "cat", "pig", "horse"), y = c(1, 2, 3, 4), z = c(T, T, F, T))
d
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
class(d) # classはdata.frame
## [1] "data.frame"
mode(d) # modeはlist
## [1] "list"
# 長さが異なるベクターを用いると、反復が適用される
d2 <- data.frame(x = c("dog", "cat"), y = c(1, 2, 3, 4), z = T)
d2
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 dog 3 TRUE
## 4 cat 4 TRUE
16.2.1 リストからデータフレームを作成する
データフレームはリストと同じですので、長さが同じベクターからなるリストはそのままデータフレームに変換できます。データフレームへの変換にはas.data.frame
関数を用います。この変換は、data.frame
関数を用いても行うことができます。
長さが異なるベクターや、ベクター以外の要素を含むリストをデータフレームに変換しようとすると、エラーが出ます。反復は行われません。
リストをデータフレームに変換
# 長さが同じベクターのリストは、そのままデータフレームに変換できる
lst <- list(x = c("dog", "cat", "pig", "horse"), y = c(1, 2, 3, 4), z = c(T, T, F, T))
as.data.frame(lst)
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
data.frame(lst)
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
# 長さが異なるベクターのリストは、データフレームに変換できない
lst2 <- list(x = c(1, 2, 3, 4), y = "dog", z = c(T, F, T, T, F))
as.data.frame(lst2) # エラー
## Error in (function (..., row.names = NULL, check.rows = FALSE, check.names = TRUE, : arguments imply differing number of rows: 4, 1, 5
16.2.2 データフレームのインデックス
データフレームはリストではありますが、行(横方向)と列(縦方向)を持つ、表の形で表されます。データフレームは表型のデータですので、行・列の2つの次元(dimension)を持ちます。
データフレームの要素をインデックスで指定する場合には、[行, 列]
という形を用います。このとき、インデックスの数値は行・列共に1行目が1、1列目が1となります。インデックスは数値のベクターで指定することもできます。数値のベクターで指定した場合には、ベクターに記載した順番に行・列を取り出すことになります。
ベクターと同様に、データフレームのインデックスはコロン(:
)を用いた連続整数の形でも指定できますし、論理型(TRUE
とFALSE
)のベクターを用いても指定できます。論理型のベクターの長さが行数・列数に足りない場合には、ベクターが反復されます。マイナスのインデックスを用いた場合には、指定した行・列が削除されます。
インデックスでデータフレームの列のみを指定した場合には、返り値としてその列のベクターが返ってきます。一方、行のみを指定した場合には、ベクターではなく、その行がデータフレームとして返ってきます。行をベクターに変換するには、unlist
関数を用います。
データフレームのインデックスの指定時には、コンマで行列を区切らず、1つのインデックスだけで指定することもできます。インデックスを1つだけ指定した場合には、ベクターではなく、データフレームが返ってきます。
データフレームのインデックス
d1 <- data.frame(a = 1:6, b = seq(4, 6.5, by = 0.5), c = rep(1, 6))
d1
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 3 3 5.0 1
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
d1[1, 1] # 1行1列目の要素を取り出す
## [1] 1
d1[1:3, 1] # 1~3行目、1列目の要素を取り出す(ベクター)
## [1] 1 2 3
d1[c(5, 2, 1), ] # 5行目、2行目、1行目を取り出す
## a b c
## 5 5 6.0 1
## 2 2 4.5 1
## 1 1 4.0 1
d1[1, ] # 1行目の要素を取り出す(データフレーム)
## a b c
## 1 1 4 1
unlist(d1[1, ]) # 1行目の要素を取り出して、ベクターに変換する
## a b c
## 1 4 1
d1[2:3, ] # 2~3行目の要素を取り出す(データフレーム)
## a b c
## 2 2 4.5 1
## 3 3 5.0 1
d1[, 2:3] # 2~3列目の要素を取り出す(データフレーム)
## b c
## 1 4.0 1
## 2 4.5 1
## 3 5.0 1
## 4 5.5 1
## 5 6.0 1
## 6 6.5 1
d1[c(T, T, F, T, F, F), ] # 論理型もインデックスに使用できる
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 4 4 5.5 1
d1[c(T, T, F), ] # 反復
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 4 4 5.5 1
## 5 5 6.0 1
d1[, c(T, T, F)] # 列のインデックスにも論理型を使用できる
## a b
## 1 1 4.0
## 2 2 4.5
## 3 3 5.0
## 4 4 5.5
## 5 5 6.0
## 6 6 6.5
d1[-1:-2, ] # 1~2行目を削除
## a b c
## 3 3 5.0 1
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
d1[, -1:-2] # 1~2列目を削除
## [1] 1 1 1 1 1 1
d1[1] # 1列目を取り出す(データフレーム)
## a
## 1 1
## 2 2
## 3 3
## 4 4
## 5 5
## 6 6
class(d1[1]) # 行・列で指定([,1])しないと、データフレームが返ってくる
## [1] "data.frame"
16.2.3 データフレームの行数・列数
データフレームには、行方向と列方向の長さがあります。この行方向と列方向の長さを返すのが、dim
関数、nrow
関数、ncol
関数です。dim
関数は、データフレームを引数に取り、行数,列数の2つの値のベクターを返します。nrow
関数はデータフレームの行数を、ncol
関数はデータフレームの列数を返す関数です。
16.2.4 データフレームの名前
データフレームの各行・各列には、それぞれ名前をつけることができます。データフレームの行の名前はrownames
関数、列の名前はcolnames
関数で求めることができます。
列名はdata.frame
関数でデータフレームを作成するときにつけることができます。また、ベクターと同様に、colnames
関数に列名を代入する形でも列名をつけることができます。
行名をつける場合には、rownames
関数に行名を代入します。特に行名を指定していない場合には、行の番号が1, 2, 3,…といった形で行名として設定されます。
行名・列名のいずれもインデックスとして利用することができます。特に列名は、$
(ドルマーク)を用いた形で列の取り出しに用いることができます。
データフレームの行名・列名
d
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
colnames(d) # 列名
## [1] "x" "y" "z"
colnames(d) <- c("a", "b", "c") # 列名を変更する
rownames(d) # 行名
## [1] "1" "2" "3" "4"
rownames(d) <- c("x", "y", "z", "aa") # 行名を変更する
d["x", ] # 行名をインデックスに用いることもできる
## a b c
## x dog 1 TRUE
d[, "a"] # 列名もインデックス指定に使うことができる
## [1] "dog" "cat" "pig" "horse"
d$a # ドルマークを使って列を指定することもできる
## [1] "dog" "cat" "pig" "horse"
データフレームにおいても、インデックスに論理型のベクターを使用することができるため、列名と比較演算子を利用して、行を選択することができます。
インデックスでの比較演算子の利用と同様に条件によって行を選択する際に用いる関数がsubset
関数です。subset
関数は第一引数にデータフレーム、第二引数に比較演算子を用いた条件式を記載することで、条件に合った行のみを取り出すことができます。
行のデータを利用して論理型ベクターを作成し、列を選択する事もできます。
d1
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 3 3 5.0 1
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
d1$b > 5 # b列が5以上ならTRUE
## [1] FALSE FALSE FALSE TRUE TRUE TRUE
d1[d1$b > 5, ] # b列が5以上の行を選択
## a b c
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
subset(d1, d1$b > 5) # 上と同じ行の選択をsubset関数で行う
## a b c
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
d1[1, ] > 3 # 1行目の値が3以上ならTRUE
## a b c
## 1 FALSE TRUE FALSE
d1[, d1[1, ] > 3] # 1行目が3以上になる列(2列目)を選択
## [1] 4.0 4.5 5.0 5.5 6.0 6.5
16.2.5 データフレームの並べ替え
データフレームの並べ替えには、order
関数を用います。order
関数はベクターの要素の順番に数値を付け、返すだけの関数です。データフレームのインデックスはベクターを取ることができ、ベクターに記載した数値の順番に行を取得します。ですので、order
関数の返り値を行のインデックスとして用いると、order
関数の返り値の通りにデータフレームが並べ替えられます。
order
関数にはdecreasing
(降順)という引数を設定できます。decreasing
のデフォルト値はFALSE
で、通常はorder
関数を用いた並べかえは昇順(一番小さいものが一番上)になります。decreasing
をTRUE
に設定すると、order
関数の結果が逆順になります。したがって、decreasing=TRUE
とした場合には、データフレームを降順(一番大きなものが一番上)に並べ替えることができます。
rev
関数は引数にベクターを取り、ベクターを逆順に変換する関数です。このrev
関数を用いても、データフレームを降順に並べ替えることができます。
データフレームの並べ替え
d <- data.frame(x = c("dog", "cat", "pig", "horse"), y = c(1, 2, 3, 4), z = c(T, T, F, T))
order(d$x) # x列の順序を返す(文字列はアルファベット順)
## [1] 2 1 4 3
d[order(d$x),] # x列を昇順に並べ替え
## x y z
## 2 cat 2 TRUE
## 1 dog 1 TRUE
## 4 horse 4 TRUE
## 3 pig 3 FALSE
order(d$x, decreasing=TRUE)
## [1] 3 4 1 2
d[order(d$x, decreasing=TRUE), ] # x列を降順に並べ替え
## x y z
## 3 pig 3 FALSE
## 4 horse 4 TRUE
## 1 dog 1 TRUE
## 2 cat 2 TRUE
d[rev(order(d$x)), ] # rev関数でもベクターを逆順にできる
## x y z
## 3 pig 3 FALSE
## 4 horse 4 TRUE
## 1 dog 1 TRUE
## 2 cat 2 TRUE
order
関数の代わりにrank
関数を用いることもできます。ただし、rank
関数はデフォルトではタイデータ(同じ値のデータ)に整数で順位を付けないので(2.5位が2つなど)、タイデータがあるとうまく並び替えができません。並べ替えの場合にはorder
関数の方が使い勝手がよいでしょう。
16.2.6 データフレームに行・列を追加する
データフレームに列を追加する方法はいくつかあります。
-
$
(ドルマーク)に列名に使われていない名前を指定し、ベクターを代入する - 現在の列数+1のインデックスを指定し、ベクターを代入する
-
cbind
関数を用いる
$
と新しい列名を用いて、ベクターを代入した場合には、最も右側にその列名を持つ列が追加されます。数値のインデックスで指定した場合には、Vにインデックスが付いた列名(V1、V2など)が自動的に設定され、列が追加されます。cbind
関数を用いた場合には、1つ目の引数(データフレーム)に2つ目の引数(ベクターもしくはデータフレーム)が右側から追加されます。
データフレームに行を追加する方法もほぼ同じです。行を追加する場合には、cbind
関数ではなく、rbind
関数を用います。
ただし、データフレームに行をベクターで追加する場合には、追加した行に従い各列のデータ型が変化します。データ型の変換を起こさないように行を追加するには、追加する行がデータフレームである必要があります。さらに、追加するデータフレームの列名が元のデータフレームの列名と一致する必要があります。
データフレームに行を追加すると予期せぬ型変換が起こり、間違いの原因となりますので、行の追加を行うときには型を逐次確認することをおすすめします。
列・行の追加
d3 <- d
d3
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
d3$newCol <- 5:8
d3[, 5] <- 10:13
d3[5, ] <- c("rat", 6, T, 9, 14) # 各列の型に沿ったベクターを追加
summary(d3) # すべての列が文字列になる
## x y z newCol
## Length:5 Length:5 Length:5 Length:5
## Class :character Class :character Class :character Class :character
## Mode :character Mode :character Mode :character Mode :character
## V5
## Length:5
## Class :character
## Mode :character
d
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
cbind(d, 1:4) # 列を追加
## x y z 1:4
## 1 dog 1 TRUE 1
## 2 cat 2 TRUE 2
## 3 pig 3 FALSE 3
## 4 horse 4 TRUE 4
rbind(d, 1:3) # 行を追加する(列のデータ型が変化する)
## x y z
## 1 dog 1 1
## 2 cat 2 1
## 3 pig 3 0
## 4 horse 4 1
## 5 1 2 3
# データフレームを追加する場合は、列名が同じである必要がある
rbind(d, data.frame(x = "pig", y = 1, z = TRUE))
## x y z
## 1 dog 1 TRUE
## 2 cat 2 TRUE
## 3 pig 3 FALSE
## 4 horse 4 TRUE
## 5 pig 1 TRUE
16.2.7 データフレームの要約
データフレームの各列の要約を調べる場合には、ベクターなどと同様に、summary
関数を用います。summary
関数はデータフレームを引数に取ると、列が文字列の場合にはデータ型と要素の数、論理型や因子の場合はそのレベルごとの要素の数、数値型であれば平均値や中央値、最大値・最小値などを示してくれます。
データフレームの列方向の合計値を求める場合にはcolSums
関数を、行方向の合計値を求める場合にはrowSums
関数を用います。データフレームに文字列の列がある場合には、colSums
関数・rowSums
関数はエラーを返します。
同様の関数に、colMeans
関数、rowMeans
関数もあります。これらはそれぞれ列方向・行方向の平均値を計算する関数です。
データフレームの一部を確認したいときには、ベクターと同様にhead
関数とtail
関数を用いることができます。head
関数はデータフレームの上から6行を、tail
関数はデータフレームの下から6行をそれぞれ表示します。
データフレームの情報を調べる
summary(d) # データフレームの要約
## x y z
## Length:4 Min. :1.00 Mode :logical
## Class :character 1st Qu.:1.75 FALSE:1
## Mode :character Median :2.50 TRUE :3
## Mean :2.50
## 3rd Qu.:3.25
## Max. :4.00
d1
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 3 3 5.0 1
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
colSums(d1) # 列方向に合計した値
## a b c
## 21.0 31.5 6.0
colSums(d) # 数値以外が含まれているとエラーになる
## Error in colSums(d): 'x' must be numeric
rowSums(d1) # 行方向に合計した値
## [1] 6.0 7.5 9.0 10.5 12.0 13.5
colMeans(d1) # 列方向の平均値
## a b c
## 3.50 5.25 1.00
rowMeans(d1) # 行方向の平均値
## [1] 2.0 2.5 3.0 3.5 4.0 4.5
head(d1) # データフレームの上から6行を表示
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 3 3 5.0 1
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
tail(d1) # データフレームの下から6行を表示
## a b c
## 1 1 4.0 1
## 2 2 4.5 1
## 3 3 5.0 1
## 4 4 5.5 1
## 5 5 6.0 1
## 6 6 6.5 1
関数名 | データフレームに適用する演算 |
---|---|
data.frame(x, y) | データフレームを作成する |
dim(x) | 次元(dimension)を返す |
ncol(x) | 列数を返す |
nrow(x) | 行数を返す |
colnames(x) | 列の名前を返す |
rownames(x) | 行の名前を返す |
colnames(x) <- y | yを列の名前に設定する |
rownames(x) <- y | yを行の名前に設定する |
subset(x, 条件) | 条件に適合した行を抽出する |
x[order(x$name), ] | name列で昇順に並べ替え |
cbind(x, y) | 列を追加する |
rbind(x, y) | 行を追加する |
summary(x) | データフレームの要約を表示 |
colSums(x) | 列(縦)方向の和を返す |
rowSums(x) | 行(横)方向の和を返す |
colMeans(x) | 列(縦)方向の平均値を返す |
rowMeans(x) | 行(横)方向の平均値を返す |
head(x) | データフレームの上から6行を表示 |
tail(x) | データフレームの下から6行を表示 |
もっと複雑なデータフレームの要約を行う場合には、apply
関数群やdplyr
パッケージ (Wickham et al. 2023)、tidyr
パッケージ (Wickham, Vaughan, and Girlich 2023)などを用います。apply
関数群、dplyr
、tidyr
に関しては19章、20章でそれぞれ紹介します。
16.2.8 データフレームの列の演算
データフレームの列同士の演算は$
を用いても表現できますが、with
関数を用いても計算することができます。with
関数はデータフレームを引数に取り、列名の演算を第2引数に取ります。返り値はベクターになります。
同様の関数として、within
関数というものもあります。within
関数はwith
と同じくデータフレームと列の演算を引数に取りますが、列の演算を列名に代入することで、演算結果がデータフレームに新たな列として追加されます。
列の演算:with関数とwithin関数
iris6 <- head(iris) # 始めの6行を選択
# Sepal.Lengthの列とSepal.Widthの列の値を掛ける
with(iris6, Sepal.Length * Sepal.Width)
## [1] 17.85 14.70 15.04 14.26 18.00 21.06
# Sepal.Lengthの列とSepal.Widthの列の値を掛けて、値を列として登録する
within(iris6, Sepal_multiple <- Sepal.Length * Sepal.Width) #代入は<-、=だとエラー
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species Sepal_multiple
## 1 5.1 3.5 1.4 0.2 setosa 17.85
## 2 4.9 3.0 1.4 0.2 setosa 14.70
## 3 4.7 3.2 1.3 0.2 setosa 15.04
## 4 4.6 3.1 1.5 0.2 setosa 14.26
## 5 5.0 3.6 1.4 0.2 setosa 18.00
## 6 5.4 3.9 1.7 0.4 setosa 21.06
16.2.9 組み合わせのデータフレームを作成する
様々な要素について、すべての組み合わせを含むデータを作りたい、という場合が時にあります。このような場合には、expand.grid
関数を用いると簡単に組み合わせのデータフレームを作成することができます。expand.grid
関数はdata.frame
関数と同じように引数を設定し、引数に設定したベクターのすべての組み合わせを含むデータフレームを作成してくれます。
expand.grid関数
expand.grid(sex=c("M", "F"), age=c(20,25), location=c("Osaka", "Kobe"))
## sex age location
## 1 M 20 Osaka
## 2 F 20 Osaka
## 3 M 25 Osaka
## 4 F 25 Osaka
## 5 M 20 Kobe
## 6 F 20 Kobe
## 7 M 25 Kobe
## 8 F 25 Kobe
16.3 行列(matrix)
Rは高校数学で学んだ行列、線形代数の行列計算を行うためのクラスである、行列(matrix)を持ちます。行列はベクターと同様に同じ型を持つ要素の集合で、行と列の2つの次元(dimension)を持ちます。
データフレームも行列と同様に次元を持ちますが、データフレームが行方向には異なるデータ型を取ることができるのに対して、行列はすべての要素のデータ型が同じです。また、データフレームがリストであるのに対し、行列は縦・横の2つの次元を持つベクターです。
行列の基本的な取り扱い(インデックス、行・列の追加、行名・列名)はデータフレームとほぼ同じです。上に述べたデータフレームの取り扱いに関する方法は、概ね行列にも適用することができます。
行列の作成には、matrix
関数を用います。matrix
関数は第一引数にベクター、nrow
引数に行の数、ncol
引数に列の数を指定します。matrix
関数はベクターの数値を縦方向(列方向)に並べて配置します。数値を横(行方向)に並べて配置する場合には、byrow
引数をTRUE
に指定します。
行列の作成とインデックス
mat <- matrix(1:12, nrow = 3, ncol = 4) # 列方向にベクターが配置される
mat
## [,1] [,2] [,3] [,4]
## [1,] 1 4 7 10
## [2,] 2 5 8 11
## [3,] 3 6 9 12
matrix(1:12, nrow = 3, ncol = 4, byrow = TRUE) # 行方向に配置するとき
## [,1] [,2] [,3] [,4]
## [1,] 1 2 3 4
## [2,] 5 6 7 8
## [3,] 9 10 11 12
dim(mat) # 行数・列数を返す
## [1] 3 4
nrow(mat) # 行数
## [1] 3
ncol(mat) # 列数
## [1] 4
colnames(mat) <- c("dog", "cat", "pig", "horse") # 列名の設定
rownames(mat) <- c("first", "second", "third") # 行名の設定
mat
## dog cat pig horse
## first 1 4 7 10
## second 2 5 8 11
## third 3 6 9 12
colnames(mat) # 列名の取得
## [1] "dog" "cat" "pig" "horse"
rownames(mat) # 行名の取得
## [1] "first" "second" "third"
mat[1, 1] # 1行1列目の要素
## [1] 1
mat[1, ] # 1行目の要素
## dog cat pig horse
## 1 4 7 10
mat[, 1] # 1列目の要素
## first second third
## 1 2 3
mat[-1, ] # 1行目を削除
## dog cat pig horse
## second 2 5 8 11
## third 3 6 9 12
mat[c(T, T, F), ] # 論理型でも指定できる
## dog cat pig horse
## first 1 4 7 10
## second 2 5 8 11
mat[1:2, ] # 1~2行目の要素
## dog cat pig horse
## first 1 4 7 10
## second 2 5 8 11
mat[, "dog"] # インデックスは列名でも指定できる
## first second third
## 1 2 3
mat$dog # ドルマークを用いることはできない
## Error in mat$dog: $ operator is invalid for atomic vectors
mat["first", ] # 行名での指定
## dog cat pig horse
## 1 4 7 10
cbind(mat, rat = c(4, 6, 8)) # 列の追加
## dog cat pig horse rat
## first 1 4 7 10 4
## second 2 5 8 11 6
## third 3 6 9 12 8
rbind(mat, fourth = c(1, 1, 1, 1)) # 行の追加
## dog cat pig horse
## first 1 4 7 10
## second 2 5 8 11
## third 3 6 9 12
## fourth 1 1 1 1
Rには、次元を3つ以上持つクラスである、arrayも存在しますが、matrixほどには使用頻度は高くありません。
16.3.1 行列の演算
統計の計算には、線形代数(行列)が用いられます。Rには行列の演算に関する関数が一通り揃っています。
関数名 | 行列に適用する演算 |
---|---|
* | スカラー積 |
%*% | 行列の積 |
%o% | 外積 |
%x% | クロネッカー積 |
diag | 単位行列を作成する |
det | 行列式を返す |
t | 転置を返す |
upper.tri | 上三角行列にTRUEを返す |
lower.tri | 下三角行列にTRUEを返す |
solve | 逆行列を返す |
qr | QR分解 |
16.3.2 行列の積
Rでは、%*%
を演算子として行列の積の計算を行います。単に「*
」で計算すると、行列の積ではなく、スカラー積が返ってきます。行列同士を「*
」で掛け算した場合には、行列の各要素をそれぞれ掛け算したもの(アダマール積)が返ってきます。行列の演算子として、他に外積(%o%
)やクロネッカー積(%x%
)の演算子も設定されています。
行列の演算子
# 要素が1~16のランダムな行列を作成
mat <- matrix(sample(1:16, 16), nrow=4)
mat
## [,1] [,2] [,3] [,4]
## [1,] 9 2 13 6
## [2,] 4 14 5 15
## [3,] 7 12 11 16
## [4,] 1 3 10 8
# スカラー積(行列の値をすべて3倍にする)
mat * 3
## [,1] [,2] [,3] [,4]
## [1,] 27 6 39 18
## [2,] 12 42 15 45
## [3,] 21 36 33 48
## [4,] 3 9 30 24
# アダマール積(同じ行・列同士の値を掛け算する)
mat * mat
## [,1] [,2] [,3] [,4]
## [1,] 81 4 169 36
## [2,] 16 196 25 225
## [3,] 49 144 121 256
## [4,] 1 9 100 64
mat %*% mat # 行列の積
## [,1] [,2] [,3] [,4]
## [1,] 186 220 330 340
## [2,] 142 309 327 434
## [3,] 204 362 432 526
## [4,] 99 188 218 275
mat[, 1] %o% mat[, 2] # 外積
## [,1] [,2] [,3] [,4]
## [1,] 18 126 108 27
## [2,] 8 56 48 12
## [3,] 14 98 84 21
## [4,] 2 14 12 3
mat[1:2, 1:2] %x% mat[3:4, 3:4] # クロネッカー積
## [,1] [,2] [,3] [,4]
## [1,] 99 144 22 32
## [2,] 90 72 20 16
## [3,] 44 64 154 224
## [4,] 40 32 140 112
16.3.3 行列式・転置・逆行列の演算
行列式はdet
関数、行列の転置はt
関数、逆行列はsolve
関数で求めることができます。t
関数は行列だけでなく、データフレームを引数に取ることができますが、t
関数の返り値は必ず行列になります。データフレームをt
関数の引数にして転置する場合にはデータ型が変換されることが多いため、注意が必要です。
行列式・転置・逆行列
det(mat) # matの行列式
## [1] -712
t(mat) # matを転置
## [,1] [,2] [,3] [,4]
## [1,] 9 4 7 1
## [2,] 2 14 12 3
## [3,] 13 5 11 10
## [4,] 6 15 16 8
solve(mat) # matの逆行列
## [,1] [,2] [,3] [,4]
## [1,] -0.08005618 -0.3455056 0.4789326 -0.25
## [2,] 0.55758427 1.1432584 -1.4058989 0.25
## [3,] 0.32724719 0.5702247 -0.7823034 0.25
## [4,] -0.60814607 -1.0983146 1.4452247 -0.25
mat %*% solve(mat) # 概ね単位行列になる
## [,1] [,2] [,3] [,4]
## [1,] 1.000000e+00 0 0.000000e+00 4.440892e-16
## [2,] 0.000000e+00 1 3.552714e-15 4.440892e-16
## [3,] -1.776357e-15 0 1.000000e+00 0.000000e+00
## [4,] -8.881784e-16 0 1.776357e-15 1.000000e+00
16.3.4 単位行列・三角行列の作成
diag
関数は単位行列を作成するための関数です。diag
関数は数値を引数に取り、その数値の行数・列数の単位行列を返します。
三角行列の作成には、upper.tri
関数とlower.tri
関数を用います。この2つの関数は、行列を引数に取り、行列と同じ行数・列数の論理型の上三角行列(上がTRUE
、下三角がFALSE
の行列)、下三角行列(下がTRUE
、上三角がFALSE
の行列)をそれぞれ返します。いずれも対角成分はFALSE
となります。
ただし、upper.tri
関数、lower.tri
関数の返り値をそのまま行列のインデックスに用いても上三角行列・下三角行列を作ることはできません。上三角行列を作成する場合には、lower.tri
関数の返り値をインデックスに取り、このインデックスに0を代入します。
逆に、下三角行列を作成する場合には、upper.tri
関数の返り値をインデックスに取り、このインデックスに0を代入します。このように0を下三角・上三角に代入することで、上三角行列・下三角行列を得ることができます。
diag(3) # 3行3列の単位行列
## [,1] [,2] [,3]
## [1,] 1 0 0
## [2,] 0 1 0
## [3,] 0 0 1
upper.tri(mat) # 上三角行列にTRUEを返す
## [,1] [,2] [,3] [,4]
## [1,] FALSE TRUE TRUE TRUE
## [2,] FALSE FALSE TRUE TRUE
## [3,] FALSE FALSE FALSE TRUE
## [4,] FALSE FALSE FALSE FALSE
lower.tri(mat) # 下三角行列にTRUEを返す
## [,1] [,2] [,3] [,4]
## [1,] FALSE FALSE FALSE FALSE
## [2,] TRUE FALSE FALSE FALSE
## [3,] TRUE TRUE FALSE FALSE
## [4,] TRUE TRUE TRUE FALSE
mat.u <- mat
mat.l <- mat
mat.u[lower.tri(mat)] <- 0 # 下三角行列のみに0を代入
mat.l[upper.tri(mat)] <- 0 # 上三角行列のみに0を代入
mat.u # 下三角に0を代入すると上三角行列が得られる
## [,1] [,2] [,3] [,4]
## [1,] 9 2 13 6
## [2,] 0 14 5 15
## [3,] 0 0 11 16
## [4,] 0 0 0 8
mat.l # 上三角に0を代入すると下三角行列が得られる
## [,1] [,2] [,3] [,4]
## [1,] 9 0 0 0
## [2,] 4 14 0 0
## [3,] 7 12 11 0
## [4,] 1 3 10 8