12  リスト・データフレーム・行列

12.1 リスト(list)

リスト(list)は様々なデータ型・クラスを一つにまとめたものです。リストの要素となるのは、ベクター、リスト、データフレーム、行列などで、どのようなデータ型・クラスであってもリストの要素にすることができます。

リストの作成には、list関数を用います。list関数の引数がリストの要素となります。

ベクターと同様に、リストの要素には名前(names)をつけることができ、要素を名前から呼び出すことができます。名前からの呼び出しでは、ベクターと同じように四角カッコ([ ])内に文字列を記入して呼び出してもよいですし、$(ドルマーク)を用いて呼び出すこともできます。ただし、[ ]$では、返り値の型が異なります([ ]ではリスト、$では要素が返ってくる)。

名前の確認・設定はベクターと同じ方法で行います。リストの名前の確認・変更には、names関数を用います。names関数の引数にリストを取ると、そのリストの名前が返ってきます。names関数の引数にリストを取り、文字列ベクターを代入するとリストの名前を設定できます。

リストの作成と名前
# リストの作成(=の左がnames、右が要素)
lst <- list(x = c(1, 2, 3, 4), y = "dog", z = c(T, F, T, T, F))
lst # 名前付きリストを表示する
## $x
## [1] 1 2 3 4
## 
## $y
## [1] "dog"
## 
## $z
## [1]  TRUE FALSE  TRUE  TRUE FALSE

names(lst) # リストの名前を表示する
## [1] "x" "y" "z"

names(lst) <- c("a", "b", "c") # リストの名前を変更する

names(lst) # 変更後の名前
## [1] "a" "b" "c"

lst["a"] # 名前での要素の呼び出し(リストが返ってくる)
## $a
## [1] 1 2 3 4

lst$a # ドルマーク($)を用いた呼び出し(要素が返ってくる)
## [1] 1 2 3 4

12.1.1 リストのインデックス

リストのインデックスは、基本的には二重角カッコ([[ ]]で指定します。通常の角カッコ([ ])で指定すると、リストの要素がリストのまま返ってきます。角カッコ([ ])で返ってくるのはリストですので、コロンを用いて複数の要素をリストとして取り出すことができます。

リストの要素(ベクターや行列)のさらに要素を取り出すには、二重角カッコの後に、ベクターや行列に対応したインデックス指定([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

12.1.2 リストの長さ(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

12.1.3 リストへの要素の追加

c関数を用いることで、リストに要素を追加することができます。また、リストに要素を追加する場合には、ドルマークを用いて設定されていない名前を指定し、代入を行うこともできます。設定されている名前を用いて代入した場合には、その要素が書き換えられます。

リストへの要素の追加
lst <- c(lst, d = "added list") # リストに名前dの要素を追加
lst
## $a
## [1] 1 2 3 4
## 
## $b
## [1] "dog"
## 
## $c
## [1]  TRUE FALSE  TRUE  TRUE FALSE
## 
## $d
## [1] "added list"

# リストに名前eの要素を追加(データフレームにも使える)
lst$e <- "object can be added with named index" # 名前eの要素を追加
lst$d <- "revised list" # dの要素を変更
lst # 追加・変更後のリスト
## $a
## [1] 1 2 3 4
## 
## $b
## [1] "dog"
## 
## $c
## [1]  TRUE FALSE  TRUE  TRUE FALSE
## 
## $d
## [1] "revised list"
## 
## $e
## [1] "object can be added with named index"

12.1.4 リストのベクター化

リストを全部まとめて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"

12.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

12.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

12.2.2 データフレームのインデックス

データフレームはリストではありますが、行(横方向)と列(縦方向)を持つ、表の形で表されます。データフレームは表型のデータですので、行・列の2つの次元(dimension)を持ちます。

データフレームの要素をインデックスで指定する場合には、[行, 列]という形を用います。このとき、インデックスの数値は行列共に1行目が1、1列目が1となります。インデックスは数値のベクターで指定することもできます。数値のベクターで指定した場合には、ベクターに記載した順番に行・列を取り出すことになります。

ベクターと同様に、データフレームのインデックスはコロン(:)を用いた連続整数の形でも指定できますし、論理型(TRUEFALSE)のベクターを用いても指定できます。論理型のベクターの長さが行数・列数に足りない場合には、ベクターが反復されます。マイナスのインデックスを用いた場合には、指定した行・列が削除されます。

インデックスでデータフレームの列のみを指定した場合には、返り値としてその列のベクターが返ってきます。一方、行のみを指定した場合には、ベクターではなく、その行がデータフレームとして返ってきます。行をベクターに変換するには、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"

12.2.3 データフレームの行数・列数

データフレームには、行方向と列方向の長さがあります。この行方向と列方向の長さを返すのが、dim関数、nrow関数、ncol関数です。dim関数は、データフレームを引数に取り、行数,列数の2つの値のベクターを返します。nrow関数はデータフレームの行数を、ncol関数はデータフレームの列数を返す関数です。

データフレームの行・列数
d # dは4行3列のデータフレーム
##       x y     z
## 1   dog 1  TRUE
## 2   cat 2  TRUE
## 3   pig 3 FALSE
## 4 horse 4  TRUE

dim(d) # 4行3列なので、4と3が返ってくる
## [1] 4 3

nrow(d) # 行数が返ってくる
## [1] 4

ncol(d) # 列数が返ってくる
## [1] 3

12.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

12.2.5 データフレームの並べ替え

データフレームの並べ替えには、order関数を用います。order関数はベクターの要素の順番に数値を付け、返すだけの関数です。データフレームのインデックスはベクターを取ることができ、ベクターに記載した数値の順番に行を取得します。ですので、order関数の返り値を行のインデックスとして用いると、order関数の返り値の通りにデータフレームが並べ替えられます。

order関数にはdecreasing(降順)という引数を設定できます。decreasingのデフォルト値はFALSEで、通常はorder関数を用いた並べかえは昇順(一番小さいものが一番上)になります。decreasingTRUEに設定すると、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関数の方が使い勝手はよいでしょう。

12.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

12.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
表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列で昇順に並べ替え | |x[rev(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関数群、dplyrtidyrに関しては15章16章でそれぞれ紹介します。

12.2.8 組み合わせのデータフレームを作成する

様々な要素について、すべての組み合わせを含むデータを作りたい、という場合が時にあります。このような場合には、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

12.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ほどには使用頻度は高くありません。

12.3.1 行列の演算

統計の計算には、線形代数(行列)が用いられます。Rには行列の演算に関する関数が一通り揃っています。

表2:行列に関する関数
関数名 行列に適用する演算
* スカラー積
%*% 行列の積
%o% 外積
%x% クロネッカー積
diag 単位行列を作成する
det 行列式を返す
t 転置を返す
upper.tri 上三角行列にTRUEを返す
lower.tri 下三角行列にTRUEを返す
solve 逆行列を返す
qr QR分解

12.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

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

12.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

12.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