# Rのベクトル(行・列の区別なし)
a <- c(1, 3, 5)
a[1] 1 3 5
# 行ベクトル(1×3の行列)
matrix(a, nrow = 1) [,1] [,2] [,3]
[1,] 1 3 5
# 列ベクトル(3×1の行列)
matrix(a, ncol = 1) [,1]
[1,] 1
[2,] 3
[3,] 5
分類: 枝(選択)
依存関係: U2 → U3 → U14(因子分析等)、U15(クラスタリング等)
学習目標:
matrix()で行列を作成し、要素にアクセスできるt())、行列積(%*%)の計算ができるcor())と分散共分散行列(cov())を計算・解釈できるdist())を計算し、その意味を理解できるeigen())の意味と使い方を理解できる心理学のデータ分析では、因子分析・主成分分析・クラスタ分析・多次元尺度構成法など、多くの多変量解析が行列の計算に基づいています。統計パッケージが瞬時に答えを出してくれますが、その仕組みを知らなければ結果の意味を正しく理解できません。
行列を使う最大の利点は、多くの数字のセットを簡単な記号で一般的に表現できることです。変数や回答者数が数十、数百になったとき、1つ1つのデータにアルファベットを割り振っていたのでは間に合いません。
このユニットでは、行列の基本的な計算規則とRでの操作方法を学びます。
行列でもベクトルでもない、ただの1つの数字をスカラー(scalar)と呼びます。普段の計算で使っている \(1, 2, 3\) などはすべてスカラーです。
複数の数字を一行、あるいは一列にまとめたものをベクトルと呼びます。横に並べたものを行ベクトル(row vector)、縦に並べたものを列ベクトル(column vector)と言います。
\[ \text{行ベクトル: } \boldsymbol{a} = \begin{pmatrix} 1 & 3 & 5 \end{pmatrix}, \quad \text{列ベクトル: } \boldsymbol{b} = \begin{pmatrix} 2 \\ 4 \\ 6 \end{pmatrix} \]
\(\boldsymbol{a}\) はサイズ3の行ベクトル(\(1 \times 3\))、\(\boldsymbol{b}\) はサイズ3の列ベクトル(\(3 \times 1\))です。ベクトルは数字のセットを記号ひとつで表せるので便利です。慣例として、行列やベクトルは太字(\(\boldsymbol{A}\), \(\boldsymbol{x}\))で書きます。
Rではベクトルに行・列の区別はありませんが、matrix()で明示できます:
行列(matrix)とは、数を長方形に並べたものです。横の並びを行(row)、縦の並びを列(column)と呼びます。
\[ \boldsymbol{A} = \begin{pmatrix} a_{11} & a_{12} & \cdots & a_{1m} \\ a_{21} & a_{22} & \cdots & a_{2m} \\ \vdots & \vdots & \ddots & \vdots \\ a_{n1} & a_{n2} & \cdots & a_{nm} \end{pmatrix} \]
これは \(n\) 行 \(m\) 列の行列で、サイズは \(n \times m\) と表します。成分 \(a_{ij}\) の添え字は、最初が行番号、次が列番号です。
Rでは matrix() 関数で行列を作ります。列優先(column-major order)で要素が埋められることに注意してください:
[,1] [,2] [,3]
[1,] 1 3 5
[2,] 2 4 6
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
行列の要素には [行, 列] でアクセスします:
データ分析でよく登場する特殊な行列を紹介します。
正方行列: 行数と列数が等しい行列(\(n \times n\))。
対称行列: \(a_{ij} = a_{ji}\) を満たす正方行列。左上から右下の対角線を軸に対称です。
相関行列は対称行列の代表例です。3変数 \(x_1, x_2, x_3\) の相関行列は:
\[ \boldsymbol{R} = \begin{pmatrix} 1 & r_{12} & r_{13} \\ r_{12} & 1 & r_{23} \\ r_{13} & r_{23} & 1 \end{pmatrix} \]
対角成分は1(自分自身との相関)、\(r_{ij} = r_{ji}\)(対称)です。
分散共分散行列は、対角成分が分散、非対角成分が共分散の対称行列です:
\[ \boldsymbol{V} = \begin{pmatrix} s_1^2 & s_{12} & s_{13} \\ s_{12} & s_2^2 & s_{23} \\ s_{13} & s_{23} & s_3^2 \end{pmatrix} \]
対角行列: 対角成分以外がすべて0の正方行列。単位行列 \(\boldsymbol{I}\) は対角成分がすべて1の対角行列で、「かけても変わらない」行列です。
行列の足し算・引き算は、対応する位置にある成分どうしを加える(引く)だけです。サイズが同じ行列でないと計算できません。
\[ \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} + \begin{pmatrix} 5 & 6 \\ 7 & 8 \end{pmatrix} = \begin{pmatrix} 6 & 8 \\ 10 & 12 \end{pmatrix} \]
行列にスカラー(数値)をかけると、各成分がスカラー倍されます:
\[ 2 \times \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} = \begin{pmatrix} 2 & 4 \\ 6 & 8 \end{pmatrix} \]
行列の掛け算は普通の掛け算とは異なります。掛けて足すという操作が入ります。
まず行ベクトルと列ベクトルの積から見ましょう。結果はスカラーになります:
\[ \begin{pmatrix} 1 & 2 & 1 \end{pmatrix} \begin{pmatrix} 3 \\ 4 \\ 2 \end{pmatrix} = 1 \times 3 + 2 \times 4 + 1 \times 2 = 13 \]
掛け算なのに足し算が入る。これが行列の計算の特徴です。
行列 \(\boldsymbol{A}\)(\(n \times m\))と行列 \(\boldsymbol{B}\)(\(m \times l\))の積は、\(n \times l\) の行列になります。前の行列の列数と後ろの行列の行数が一致していないと計算できません。
\[ \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix} \begin{pmatrix} 2 \\ 1 \end{pmatrix} = \begin{pmatrix} 1 \times 2 + 2 \times 1 \\ 3 \times 2 + 4 \times 1 \end{pmatrix} = \begin{pmatrix} 4 \\ 10 \end{pmatrix} \]
結果のサイズは「前の行数 × 後ろの列数」です。また、スカラーの計算と違い、かける順番を入れ替えると結果が変わります(\(\boldsymbol{AB} \neq \boldsymbol{BA}\))。
Rでは %*% が行列積、* は要素ごとの積です。この区別は非常に重要です:
[,1]
[1,] 4
[2,] 10
[,1] [,2]
[1,] 2 4
[2,] 3 4
* を使うと各行に \(b\) の要素がかかるだけで、行列積とはまったく異なる結果になります。
行列の行と列を入れ替える操作を転置(transpose)と呼び、\(\boldsymbol{A}'\) や \(\boldsymbol{A}^T\) と書きます。
\[ \boldsymbol{A} = \begin{pmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{pmatrix} \quad \Rightarrow \quad \boldsymbol{A}' = \begin{pmatrix} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{pmatrix} \]
\(2 \times 3\) の行列は転置すると \(3 \times 2\) になります。行ベクトルを転置すると列ベクトルに、列ベクトルを転置すると行ベクトルになります。
逆行列は、行列における「割り算」のイメージです。ある正方行列 \(\boldsymbol{A}\) に対して、\(\boldsymbol{A}\boldsymbol{A}^{-1} = \boldsymbol{I}\)(単位行列)となるような行列 \(\boldsymbol{A}^{-1}\) を逆行列と呼びます。スカラーでいう「逆数をかけると1になる」のと同じです。
\[ \boldsymbol{A} = \begin{pmatrix} 2 & 1 \\ 5 & 3 \end{pmatrix} のとき、\quad \boldsymbol{A}\boldsymbol{A}^{-1} = \begin{pmatrix} 2 & 1 \\ 5 & 3 \end{pmatrix} \begin{pmatrix} 3 & -1 \\ -5 & 2 \end{pmatrix} = \begin{pmatrix} 1 & 0 \\ 0 & 1 \end{pmatrix} \]
逆行列が存在しない正方行列もあります。Rでは solve() で計算します:
[,1] [,2]
[1,] 3 -1
[2,] -5 2
[,1] [,2]
[1,] 1.000000e+00 0
[2,] 1.776357e-15 1
逆行列の便利さは、連立方程式が解けることです。\(\boldsymbol{Ax} = \boldsymbol{b}\) の両辺に \(\boldsymbol{A}^{-1}\) をかけると \(\boldsymbol{x} = \boldsymbol{A}^{-1}\boldsymbol{b}\) が得られます。
正方行列 \(\boldsymbol{A}\) に対して、次の関係を満たすスカラー \(\lambda\) と ベクトル \(\boldsymbol{x}\) を、それぞれ固有値(eigenvalue)と固有ベクトル(eigenvector)と呼びます。
\[ \boldsymbol{Ax} = \lambda \boldsymbol{x} \]
左辺は「行列をかける」操作ですが、右辺は「スカラーをかける」だけ。行列をかけても方向が変わらず、伸び縮みだけするベクトルがあるということです。
具体例で確認しましょう:
\[ \begin{pmatrix} 1 & 6 \\ 2 & 5 \end{pmatrix} \begin{pmatrix} 1 \\ 1 \end{pmatrix} = \begin{pmatrix} 7 \\ 7 \end{pmatrix} = 7 \begin{pmatrix} 1 \\ 1 \end{pmatrix} \]
確かに \(\lambda = 7\)、\(\boldsymbol{x} = (1, 1)\) で成り立っています。
[1] 7 -1
[,1] [,2]
[1,] -0.7071068 -0.9486833
[2,] -0.7071068 0.3162278
\(n \times n\) の正方行列からは \(n\) 個の固有値が得られます。そして、固有値の総和は行列の対角成分の総和(トレース)と一致します:
\[ \sum_{i=1}^{n} \lambda_i = \mathrm{trace}(\boldsymbol{A}) = \sum_{i=1}^{n} a_{ii} \]
相関行列の場合、対角成分はすべて1ですから、トレースは変数の数と一致します。固有値分解は、その情報量を重要度順に再分配する操作です。
固有値分解は主成分分析や因子分析の数学的な基盤です。U14(因子分析等)で詳しく学びますが、ここでは「相関行列を固有値分解すると、データの構造を少数の次元に要約できる」ということを覚えておいてください。
| 用語 | 意味 | Rの関数 |
|---|---|---|
| スカラー | ただの数値 | — |
| ベクトル | 数値の1次元の並び | c() |
| 行列 | 数値の2次元の並び | matrix() |
| 転置 | 行と列を入れ替える | t() |
| 行列積 | 掛けて足す乗法 | %*% |
| 逆行列 | かけると単位行列になる | solve() |
| 対角成分 | 正方行列の \(a_{ii}\) | diag() |
| 固有値分解 | \(\boldsymbol{Ax} = \lambda\boldsymbol{x}\) の \(\lambda, \boldsymbol{x}\) を求める | eigen() |
| 相関行列 | 変数間の相関係数の行列 | cor() |
| 分散共分散行列 | 分散と共分散の行列 | cov() |
| 距離行列 | ケース間の距離の行列 | dist() |
matrix(1:6, nrow = 2)で作られる行列の大きさは?
要素は6個、行数が2と指定されているので、列数は6÷2=3で、2行3列の行列になります。Rは列優先(column-major order)で要素を埋めるので、1列目が1,2、2列目が3,4、3列目が5,6となります。
matrix(1:6, nrow = 2, byrow = TRUE)とmatrix(1:6, nrow = 2)の違いは何ですか?
byrow = TRUEを指定すると、要素が行方向に埋められます。
行列Aの2行3列目の要素にアクセスするための書き方は?
行列の要素アクセスはA[行, 列]の順です。A[2, 3]で2行3列目の要素を取り出せます。行だけ、列だけの指定も可能です:
転置行列を求めるRの関数は?
t()(transposeの略)は行と列を入れ替えます。\(m \times n\)行列の転置は\(n \times m\)行列になります。
Rで行列の積(行列同士の掛け算)を計算する演算子は?
%*%が行列積(matrix multiplication)です。*は要素ごとの積(element-wise multiplication)で、行列積とは異なります。
行列積\(C = AB\)では、\(C\)の\((i,j)\)要素は\(A\)の\(i\)行と\(B\)の\(j\)列の内積です。\(A\)が\(m \times k\)、\(B\)が\(k \times n\)のとき、結果は\(m \times n\)行列になります。
行列積\(AB\)が計算可能であるための条件は?
\(A\)が\(m \times k\)行列、\(B\)が\(k \times n\)行列のとき、\(AB\)は\(m \times n\)行列になります。\(A\)の列数と\(B\)の行数が一致していなければ計算できません。
逆に、\(BA\)が計算可能かどうかは別の問題です。一般に\(AB \neq BA\)で、積の順序が重要です。
cor()関数は何を計算しますか?
cor()はデータフレームや行列の各列(変数)間のピアソン相関係数を計算し、相関行列を返します。相関行列は:
分散共分散行列はcov()で計算します。
dist()関数は何を計算しますか?
dist()は行列やデータフレームの各行(ケース)間の距離を計算します。デフォルトはユークリッド距離です。
距離行列は: - 対称行列(\(d_{ij} = d_{ji}\)) - 対角成分はすべて0(自分自身との距離) - すべての要素が0以上
クラスタ分析や多次元尺度構成法(MDS)の入力として使います。
eigen()関数は何を返しますか?
eigen()は正方行列の固有値分解を行い、固有値(values)と固有ベクトル(vectors)を含むリストを返します。
固有値分解は主成分分析や因子分析の計算基盤です。相関行列を固有値分解すると、各主成分がデータの分散のどれだけを説明するかがわかります。
単位行列を作るRの関数は?
diag(n)は\(n \times n\)の単位行列を作ります。単位行列\(I\)は対角成分が1、非対角成分が0の行列で、どんな行列\(A\)に対しても\(AI = IA = A\)が成り立ちます。
diag()はベクトルを渡すと対角行列を作り、行列を渡すと対角成分を取り出すという多機能な関数です。
3行4列の行列を作成し、その転置行列を求めてください。転置前後でサイズが変わることをdim()で確認してください。
転置すると行と列が入れ替わるので、\(3 \times 4\)行列は\(4 \times 3\)行列になります。元の行列の1行目が転置行列の1列目になっていることを確認してください。
次の2つの行列の行列積\(AB\)を計算してください。*(要素ごとの積)との違いも確認してください。
\[A = \begin{pmatrix} 1 & 2 \\ 3 & 4 \end{pmatrix}, \quad B = \begin{pmatrix} 5 & 6 \\ 7 & 8 \end{pmatrix}\]
行列積の(1,1)要素: \(1 \times 5 + 2 \times 7 = 19\)。要素ごとの積の(1,1)要素: \(1 \times 5 = 5\)。まったく異なる結果になります。
irisデータセットの数値変数(1〜4列目)について、相関行列と分散共分散行列を計算してください。
cor()とcov()にデータフレームの数値列を渡します。
相関行列の対角成分はすべて1、分散共分散行列の対角成分は各変数の分散です。Petal.LengthとPetal.Widthの相関が約0.96と非常に高いことがわかります。
相関行列と分散共分散行列の関係: 各変数を標準化(平均0、SD1)したデータの分散共分散行列は相関行列と一致します。
irisの数値変数(1〜4列目)について、ケース間のユークリッド距離行列を計算してください。最初の5ケースだけに限定して距離行列を確認してください。
dist()は"dist"クラスのオブジェクトを返します(下三角行列のみ表示)。as.matrix()で完全な正方行列に変換できます。対角成分は0(自分自身との距離)、対称行列であることを確認してください。
irisデータセットの相関行列を固有値分解してください。固有値の大きさから、第1主成分がどの程度の分散を説明するか計算してください。
寄与率 = 各固有値 ÷ 固有値の合計
第1固有値が全体の約73%を説明します。つまり、4変数の情報の大部分が1つの主成分で説明できるということです。これが主成分分析(PCA)の原理です。
diag()関数の3つの使い方を確認してください: (1) 単位行列の作成、(2) 対角行列の作成、(3) 行列から対角成分の抽出。
diag()はスカラーを渡すと単位行列、ベクトルを渡すと対角行列を作り、行列を渡すと対角成分を抽出します。引数の型によって動作が変わる多態的(polymorphic)な関数です。
行列\(A\)の逆行列をsolve()で計算し、\(AA^{-1} = I\)(単位行列)になることを確認してください。
\[A = \begin{pmatrix} 2 & 1 \\ 1 & 3 \end{pmatrix}\]
コンピュータの浮動小数点演算では微小な誤差が生じるため、round()で丸めると単位行列であることがはっきりわかります。
solve(A, b)の形で連立方程式\(Ax = b\)の解を求めることもできます。
BaseballDecade.csvを読み込み、height(身長)とweight(体重)の2変数について分散共分散行列を手計算で求め、cov()の結果と一致するか確認してください。
分散共分散行列は\(S = \frac{1}{n-1}(X - \bar{X})^T(X - \bar{X})\)で計算できます。\(X\)はデータ行列、\(\bar{X}\)は各列の平均を各行に持つ行列です。
pacman::p_load(tidyverse)
df <- readr::read_csv("../data/BaseballDecade.csv")
# height, weight を行列として取り出す(NAを除く)
hw <- df %>%
dplyr::select(height, weight) %>%
tidyr::drop_na() %>%
as.matrix()
n <- nrow(hw)
# 各列の平均を引く(中心化)
hw_centered <- scale(hw, center = TRUE, scale = FALSE)
# 分散共分散行列の手計算
S_manual <- t(hw_centered) %*% hw_centered / (n - 1)
S_manual
# cov() の結果
cov(hw)
# 一致の確認
all.equal(S_manual, cov(hw))分散共分散行列の公式\(S = \frac{1}{n-1}X_c^TX_c\)(\(X_c\)は中心化データ)を行列積で直接計算しています。scale(center = TRUE, scale = FALSE)は中心化(各列から平均を引く)だけ行います。
課題: irisデータセットの相関行列を固有値分解し、以下についてAIに相談しながら考察してください。
prcomp()関数の結果と固有値分解の結果の対応関係提出物: AIとの対話ログ、コードと考察。
課題: 距離行列のさまざまな定義(ユークリッド距離、マンハッタン距離、マハラノビス距離など)についてAIに質問し、dist()のmethod引数を変えて結果を比較してください。
提出物: AIとの対話ログ、比較結果と考察。
このユニットでは、Rにおける行列操作の基礎を学びました:
matrix()、byrow引数、列優先の並び順A[行, 列]t()%*%(*は要素ごとの積)diag()(単位行列、対角行列、対角成分抽出)solve()cor()(対称、対角成分1)cov()(対称、対角成分は分散)dist()(対称、対角成分0)eigen()(主成分分析・因子分析の基盤)行列はU14(因子分析等)やU15(クラスタリング等)の前提知識です。特に相関行列の固有値分解が主成分分析・因子分析の原理であること、距離行列がクラスタ分析・MDSの入力であることを覚えておいてください。
進捗: あなたは今 3-C-10 まで完了しました!(と仮定)次は 3-B-1 に進みましょう。