Contents
はじめに
今回は機械学習において、「データの次元」を減らす処理を行う次元削減と呼ばれる手法について勉強します。今回は体験型学習ブログということで、Pythonで記述されたコードを実際に動かしてもらうことで、より理解を深めてもらえるような構成にしました。
次元削減とは
データの次元が多くなると、学習にかかるコストや時間が増え、消費メモリーが増える等の問題が考えられます。これらの問題に対処する方法の一つとして今回紹介する次元削減と呼ばれる処理を行います。次元削減の例を以下の図に示します。

上の図は、あるクラスの数学の点数と物理の点数の関係を示したグラフです。全体の傾向としては、数学の点数と物理の点数は比例関係にあります。この図を一次元のデータすなわち直線上に移したものがオレンジで表記された点になります。直線上に点を移した後でも、データは正の傾きを持つという性質自体は変わっていないことがわかります。
この例ではデータを二次元から一次元に削減していますが、次元削減後も元のデータの持つ情報を保つことができています。まとめると、次元削減とは多次元のデータが持つ情報はなるべく保持しながら低次元のデータに変換する手法のことです。
なぜ次元削減は必要なのか?
ではなぜ次元削減を行うのでしょうか?次元削減を行う目的は
❶処理スピードの高速化
❷データの可視化
の二つに大まかに分けることができます。
1. 学習コストの低下、処理スピードの高速化
一般に高次元のデータの計算にかかる計算コストと時間は少なくありません。次元削減を行うと、メモリの節約につながり、学習コストの低下や処理速度の高速化につながります。
例えば、100次元のデータで学習を行なっていたところを50次元に圧縮することができれば、かかる計算コストは単純に見積もると半分になります。実際は、1万次元から100次元に圧縮する等の大幅な削減も可能です。
2. データの可視化
多変数のデータを扱う上で、残念ながら平面に可視化できるのは最大3次元までです。
4次元以上のデータを可視化する際には、
- 3変数までをxyz軸に取り、4次元目をヒートマップで表示する
- 軸の組み合わせ分のグラフを作成する(例えば、4次元のデータを3次元で可視化する場合は、3次元のグラフを3つ作成する)
などの工夫が必要です。しかし、4次元以上のデータを3次元以内で表すことができると大変便利です。具体例を下の図に示しましょう。

上の図は、4次元のワインのデータセット※を二次元に次元削減した例です。アルコール度数、酸味などワインを分類する際に必要な特徴量がまとめられたデータセットになります。図の左側では、4つの特徴量をそれぞれ別々の種類のワイン(0から2)について可視化をしようとしています。ただ、図として描くことができるのは3次元までで、4次元のデータを可視化するとなると一工夫必要です。今回は、4次元のデータを2次元の組み合わせ6通りについて散布図を作成して可視化を行いました。しかし、左の図をパッと見ただけではデータの全体的な傾向を掴むことは難しいです。そこで、次元削減を適用することで4次元のデータを2次元にして可視化したのが右側の図になります。二次元のデータになると、見やすくなるのではないでしょうか。
(※元のデータセットは13次元のデータセットですが、その中から4つの次元に絞ったものを元データとしました。)
主成分分析PCA
では、先ほどのように4次元データを2次元に圧縮するためにはどのようにしたら良いのでしょうか?今回は、次元削減の例として主成分分析(Primary Component Analysis)と呼ばれる手法を紹介します。
1. 図を用いた説明
PCAは次元削減アルゴリズムの中でも最も有名といっても良い手法です。大まかな理屈としては、元のデータと比較し次元削減後の情報損失がなるべく小さくなるような軸を探し、その軸に向かってデータをマッピングします。情報損失がなるべく小さいとは、統計学的には変換後のデータの広がり、すなわち分散を維持することを指します。元々、離れていたデータ同士が近い位置にマッピングされたら、それは分散を維持しているとは言えません。以下、具体例を挙げて説明します。
3次元のデータを二次元に圧縮する場合を下の図に示します。アプローチとしては、元の3次元のデータを最も多く保持する軸を2つ求めます。これら2つの軸は第一主成分(first principal component)、第二主成分(second principal component)と呼ばれるものです。次に、これら二つの主成分軸を通る平面を考えます。そして、この平面に3次元のデータをマッピングすることで、主要な情報を保持したまま二次元のデータに圧縮することができます。

2. 数式を用いた説明
では次に、主成分の分散が最大となるような主成分軸を見つける方法について説明したいと思います。先ほどの例のように、p次元のn個の要素を持つデータXを圧縮したい次元の数分の軸に射影することを考えます。一般の次元と要素数を持つデータについて考えますので、行列と呼ばれる概念が登場します。行列の演算についての知識がない方は、簡単な行列の計算について学ばれてから以降を勉強されると良いです。今回、p次元からq次元に圧縮することを考えます。高次元データを低次元にマッピングする際には変換行列を作用させ、線形変換を行います。この時の変換行列wと元データXは
\( \textbf{X} = \left( \begin{array}{cccc} x_{11} & x_{12} & \ldots & x_{1p} \\ x_{21} & x_{22} & \ldots & x_{2p} \\ \vdots & \vdots & \ddots & \vdots \\ x_{n1} & x_{n2} & \ldots & x_{np} \end{array} \right) 、 \textbf{w} = \left( \begin{array}{cccc} w_{11} & w_{12} & \ldots & w_{1q} \\ w_{21} & w_{22} & \ldots & w_{2q} \\ \vdots & \vdots & \ddots & \vdots \\ w_{p1} & w_{p2} & \ldots & w_{pq} \end{array} \right) \)となります。p次元のデータに射影行列を作用させることでq次元に圧縮することができます。行列演算の結果をYとすると、
\( \left( \begin{array}{cccc} y_{11} & y_{12} & \ldots & y_{1q} \\ y_{21} & y_{22} & \ldots & y_{2q} \\ \vdots & \vdots & \ddots & \vdots \\ y_{n1} & y_{n2} & \ldots & y_{nq} \end{array} \right) = \left( \begin{array}{cccc} x_{11} & x_{12} & \ldots & x_{1p} \\ x_{21} & x_{22} & \ldots & x_{2p} \\ \vdots & \vdots & \ddots & \vdots \\ x_{n1} & x_{n2} & \ldots & x_{np} \end{array} \right) \left( \begin{array}{cccc} w_{11} & w_{12} & \ldots & w_{1q} \\ w_{21} & w_{22} & \ldots & w_{2q} \\ \vdots & \vdots & \ddots & \vdots \\ w_{p1} & w_{p2} & \ldots & w_{pq} \end{array} \right) \)\( \textbf{Y} = \textbf{X}\textbf{w} \) \( \textit{[n,q]} = \textit{[n,p]} \textit{[p,q]} \)のように行列の積の形で記述することができます。そして、この射影行列を求めるために、射影軸上のデータの分散を計算したいと思います。
ある軸への射影後のベクトルについて考えましょう。 分散の定義式は、\( s^2 =\frac{1}{n}\sum_{i=1}^{n} (y_i – \bar{y})^2 \) より、まずは平均を求める必要があります。計算式は、\( \bar{y} =\frac{1}{n}\sum_{i=1}^{n} y_i = \frac{1}{n}\sum_{i=1}^{n} (w_{1}x_{i,1} + w_{2}x_{i,2}+\ldots w_{p}x_{i,p}) =w_{1}\bar{x_{1}} + w_{2}\bar{x_{2}} \ldots w_{p}\bar{x_{p}} \) となります。
よって、分散は以下のように計算されます。 \( s^2 = \frac{1}{n}\sum_{i=1}^{n} (y_i – \bar{y})^2 = \frac{1}{n}\sum_{i=1}^{n} (w_{1}(x_{i,1}-\bar{x_{1}}) + w_{2}(x_{i,2}-\bar{x_{2}}))^2 \) \( =w^TSw \)
ここで、行列\( S \) が登場しますが、これは共分散行列と呼ばれる行列です。共分散行列の定義は以下の通りです。
\( S = \left( \begin{array}{cccc} s_{11} & s_{12} & \ldots & s_{1p} \\ s_{21} & s_{22} & \ldots & s_{2p} \\ \vdots & \vdots & \ddots & \vdots \\ s_{p1} & s_{p2} & \ldots & s_{pp} \end{array} \right) 、 s_{j,k} = \frac{1}{n}\sum_{i=1}^{n} (x_{i,j}-\bar{x_{j}})(x_{i,k}-\bar{x_{k}}) 、 j,k = 1,2,3 \dots p \)よって、分散を最大化することは、\( w^TSw \)を最大化することと等しく、そのような\( w \)はどのように求めたら良いでしょうか。ここで注意ですが、\( w \)の大きさは変えずに、分散が最大となる方向を考えます。なぜならば、値そのものを大きくしようと思えば、無限大に発散するまで大きくすることができます。しかし、今回のポイントは、分散が最大となる射影軸を見つけることなので、ベクトルの大きさ自体には興味はないのです。そのために、\( w \)に\( w^{T}w =1 \)という制約を課します。
よって、制約を課した状態で最大化を行う、制約付き最大化問題に帰着することができます。つまり、
\( max_{w} (w^{T}Sw) \hspace{5pt} subject\hspace{5pt}to \hspace{5pt} w^{T}w=1 \)という最適化問題を解くことになります。
制約付き最大化問題はラグランジュの未定条数法を用いることによって、解くことができます。制約を与える関数を
\( g(w) = w^{T}w -1 = 0 \)とおき、最大化する目的関数を
\( f(w) = w^{T}Sw \)とおきます。そして、目的関数と制約関数にラグランジュ定数をかけた項の和をとったものを
\( F(w,\lambda) = f(w) + \lambda g(w) \)と定義し、これをラグランジュ関数と呼びます。\( F(w,\lambda) \)を\( w \)で偏微分して、停留点を計算します。
\( \frac{\partial L}{\partial w} = \frac{\partial (w^{T}Sw)}{\partial w} – \lambda \frac{\partial (1- w^{T}w)}{\partial w} = 2Sw – 2\lambda w \)そして、極値を取る場合は上の式が0になります。結果、次式が求まります。
\( Sw = \lambda w \)よく見ると、共分散行列の固有方程式を表していることがわかります。PCAの説明において、いきなり固有分解の概念を持ち込んでいる例がありますが、制約付きの最大化問題を得ことで、固有分解に行き着きます。
先程の固有方程式において、固有値\( \lambda \) はどのような意味を持つのでしょうか? 固有方程式を少し変形してみましょう。
\( w^{T}Sw = w^{T} \lambda w \) \( w^{T}Sw = \lambda w^{T}w \) \( w^{T}Sw = s^2, w^{T}w=1より \lambda = s^{2} \)つまり、固有値が分散そのものに対応します。以上より、最大固有値は最大分散に対応し、その時の固有ベクトルが第一主成分に対応します。そして、削減したい次元数分の固有ベクトルを求め、並べて行列にすると最終的な変換行列が求まります。図で表すと以下のようになります。

では、一連の計算の流れを図3で示した例で再現すると以下のようになります。

上の例では、3次元のデータを2次元に削減するので、固有値と固有ベクトルは2組抽出することになります。抽出した2つの固有ベクトルを列方向に並べて3行2列の行列すなわち変換行列を作成します。そして、その変換行列とn個の要素を持った3次元のデータすなわちn行3列の行列の積を取ると、削減後のデータが求まります。変換後のデータはn行2列の行列になります。
\( X_{pca} = \textbf{X}\textbf{w} = \left( \begin{array}{cccc} x_{11} & x_{12} & x_{13} \\ x_{21} & x_{22} & x_{23} \\ \vdots & \vdots & \vdots \\ x_{n1} & x_{n2} & x_{n3} \end{array} \right) \times \left( \begin{array}{cccc} w_{11} & w_{12}\\ w_{21} & w_{22}\\ w_{31} & w_{32} \end{array} \right) = \left( \begin{array}{cccc} x_{11} & x_{12}\\ x_{21} & x_{22}\\ \vdots & \vdots\\ x_{n1} & x_{n2} \end{array} \right) \)これで、主成分分析を用いたアルゴリズムの一連の流れを学習することができました。では数式のみの説明だけではなく、一連の流れを復習しながら、Pythonで主成分分析の実装を行ってみましょう。
3. 実装を用いた説明
本実装では、理論の部分で説明した例と同じで3次元のデータを2次元に削減することを考えてみましょう。一番初めの方でお見せした、wineデータと呼ばれるデータセットを用います。では、まずデータセットを読み込んで、3次元の図をプロットします。
次に、3次元の特徴データの共分散行列を求めます。
共分散行列を求めた後は、共分散行列についての固有値問題を解きます。今回は2次元に削減するので、抽出する固有ベクトルの個数は2つです。固有ベクトルを抽出した後、列方向に並べて連結させます。ここまでの流れを実装します。
変換行列wを求めた後は、元々のデータとの行列積を取り、線形変換を行います。
よって、3次元のデータから二次元のデータに次元削減を行うことができました。では、3次元の図と二次元の図で見比べてみましょう。
解説したアルゴリズムから実装を再現することができました。今回は、3次元を2次元に圧縮するシンプルなものでしたが、wineデータは元々13次元のデータセットですので、13次元からどこまで削減できるか検証してみると良いかもしれません。
補足-削減次元数の決定-
今回は元データから削減する次元数を決めて次元削減を行いました。しかし、大規模なデータセットを用いる場合はどこまで削減するべきかわからない場合がほとんどです。ここでは、どこまで次元を削減するべきか説明したいと思います。
累積寄与率
ここで見慣れない言葉が出てきました。主成分は固有方程式を解いた際の固有値(分散値)の大きいものから順に第一主成分、第二種成分…と決定しました。その時、どこまでの主成分を採用するかで元データの再現度が異なります。この再現度を定量的に表す手法として累積寄与率を定義します。p次元のデータをq次元まで圧縮した際の累積寄与率は以下の式で計算することができます。
累積寄与率 \( = \frac{\lambda_1 + \lambda_2 + … + \lambda_q}{\lambda_1 + \lambda_2 + … + \lambda_p} \)
指標としては累積寄与率が80%となるように主成分を抽出すると良いとされています。では、今回用いたwineデータにおいて、元々の13次元のデータから何次元までなら圧縮可能か検証してみましょう。
圧縮次元数に対しての累積寄与率を計算したものをプロットすると、上のようになりました。これよりqが2を超えた時点で、累積寄与率はほぼ1となっています。つまり、13次元のデータは最低2次元あれば説明可能ということです。
補足-その他の手法-
今回は次元削減の手法としてPCAを取り上げましたが、次元削減にはPCA以外の手法も用いられますので、最後に簡潔に紹介したいと思います。
t-SNE
PCAは高次元のデータの分散を最大化するように、低次元の空間に線形に変換するものでした。しかし、高次元空間において非線形なデータを低次元空間において線形なデータとして表現することは難しいです。そこで、データポイント間の距離を確率として表現し、高次元空間と低次元空間の確率分布の距離を最小化することで次元削減を行う手法を用います。これがt-SNEです。非線形なデータでも確率分布として扱うので、PCAのような問題が起こりません。このように、データ点の位置を分布として表現する手法はGANなどの生成モデルにも用いられています。

まとめ
今回は次元削減について扱い、必要とされる背景、有名アルゴリズムの紹介、簡単な実装を紹介しました。詳細なアルゴリズムを理解するためには線形代数・解析学・確率論の知識が必要となるため、一部難しいと感じた方もおられると思いますが、興味がある人はぜひ勉強してみてください。また、t-SNEの実装については本記事では取り扱いませんでしたが、実装までやってみたいという方は調べて取り組んでみてください。