高次元のデータをどう扱えばよいか悩んでいませんか? 「特徴量が多すぎて、データの傾向が掴めない…」「機械学習モデルの学習がなかなか終わらない…」
データ分析の世界では、扱うデータの次元(特徴量の数)が増えるほど、こうした問題に直面しやすくなります。そんな悩みを解決する強力な手法が、**主成分分析(PCA: Principal Component Analysis)**です。
この記事では、Pythonの定番ライブラリであるScikit-learnを使い、PCAの基本的な考え方から、実際にデータを次元削減し、その結果を可視化するまでの一連の流れを、初心者の方にも分かりやすく丁寧に解説します。
この記事を最後まで読めば、あなたもPCAを自在に使いこなし、複雑なデータをシンプルに捉え、データ分析の幅を大きく広げることができるようになります。
そもそも主成分分析(PCA)とは?
まずは、PCAがどのような手法なのか、その考え方を掴みましょう。専門的な数式は一旦置いておき、ここでは直感的なイメージを理解することを目標とします。
PCAを一言でいうと「情報の損失を抑えつつデータを要約する」手法
PCAとは、たくさんの関連しあう変数(特徴量)を、情報の損失をできるだけ抑えながら、互いに相関のない少数の新しい変数「主成分」に変換する手法です。
例えるなら、個人の健康診断データに「身長」「体重」「座高」「腕の長さ」「胸囲」…といった多くの項目があったとします。これらの項目は互いにある程度関連していますよね。PCAを使えば、これらの情報を集約して「体の大きさ」という新しい指標(第1主成分)や、「がっしり度」(第2主成分)といった、より本質的で少数の指標にまとめ直すことができます。
このように、元の特徴量を合成して新しい軸(主成分)を作り出すことで、より少ない変数で効率的にデータを表現するのがPCAの核心です。
なぜ次元削減が重要なのか?
では、なぜわざわざ次元を削減する必要があるのでしょうか。主なメリットは2つあります。
メリット①:データの可視化が容易になる
私たちの脳が直感的に理解できるのは、2次元(平面)や3次元(空間)の世界までです。しかし、実際のデータは4次元、10次元、ときには100次元を超えることもあります。PCAを使って高次元のデータを2次元や3次元に削減すれば、散布図などのグラフで可視化し、データの分布や傾向を視覚的に把握できるようになります。
メリット②:機械学習モデルの計算コスト削減と過学習の抑制
特徴量の数が多いと、それに比例して機械学習モデルの学習に必要な計算時間やメモリが増大します。また、多すぎる特徴量はノイズとして働き、モデルが訓練データに過剰に適合してしまう「過学習」の原因にもなり得ます。 次元削減によって不要な情報を削ぎ落とし、本質的な特徴量だけを用いることで、モデルの性能向上や計算効率の改善が期待できます。
Scikit-learnでPCAを実装するための準備
それでは、実際にPythonとScikit-learnを使ってPCAを実装していきましょう。まずは、そのための準備から始めます。
使用するライブラリのインストール
今回の分析では、以下の4つのライブラリを使用します。もしまだインストールしていないものがあれば、ターミナルやコマンドプロンプトで以下のコマンドを実行してください。
pip install scikit-learn numpy pandas matplotlib- scikit-learn: 機械学習のための総合ライブラリ。今回の主役であるPCAもここに含まれます。
- numpy: 数値計算を効率的に行うためのライブラリ。
- pandas: データ分析を支援する機能を提供するライブラリ。表形式のデータを扱うのに便利です。
- matplotlib: データをグラフで可視化するためのライブラリ。
今回利用するサンプルデータ
今回は、Scikit-learnに付属しているiris(アヤメ)のデータセットを使用します。このデータセットは、機械学習やデータ分析の入門で非常によく使われる有名なものです。
irisデータセットには、3種類のアヤメ(’setosa’, ‘versicolor’, ‘virginica’)について、それぞれ以下の4つの特徴量が記録されています。
- sepal length (cm): がくの長さ
- sepal width (cm): がくの幅
- petal length (cm): 花びらの長さ
- petal width (cm): 花びらの幅
この4次元のデータを、PCAを使って2次元に削減し、可視化するのが今回のゴールです。
【実践】PCAによる次元削減と可視化の4ステップ
準備が整いました。ここからは、実際にコードを書きながらPCAによる次元削減と可視化を4つのステップで進めていきます。
Step 1. データの読み込みと確認
まずは、必要なライブラリをインポートし、irisデータセットを読み込みます。PandasのDataFrame形式に変換すると、中身が確認しやすくなります。
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
import matplotlib.pyplot as plt
import seaborn as sns
# irisデータセットの読み込み
iris = load_iris()
# 特徴量をDataFrameに格納
# iris.feature_names には特徴量の名前が格納されている
df = pd.DataFrame(iris.data, columns=iris.feature_names)
# 目的変数(アヤメの種類)を追加
df['species'] = iris.target_names[iris.target]
# データの最初の5行を表示
print(df.head())実行すると、以下のように4つの特徴量とアヤメの種類(species)が格納された表が表示されるはずです。
sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) species
0 5.1 3.5 1.4 0.2 setosa
1 4.9 3.0 1.4 0.2 setosa
2 4.7 3.2 1.3 0.2 setosa
3 4.6 3.1 1.5 0.2 setosa
4 5.0 3.6 1.4 0.2 setosaStep 2. データの前処理(標準化)
次に、データの前処理として標準化を行います。これはPCAを適用する上で非常に重要なステップです。
標準化とは、各特徴量の平均が0、分散が1になるようにデータを変換する処理です。なぜこれが必要かというと、PCAは分散が大きい特徴量を重視する傾向があるためです。例えば、「がくの長さ(cm単位)」と「花びらの幅(mm単位)」のように単位やスケールが全く違う特徴量が混在していると、スケールの大きい特徴量に分析結果が引っ張られてしまいます。
そこで、StandardScalerを使って全特徴量を同じ土俵に乗せてあげます。
from sklearn.preprocessing import StandardScaler
# 特徴量データを取り出す
features = ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
x = df.loc[:, features].values
# 標準化の実行
x_scaled = StandardScaler().fit_transform(x)
# 標準化後のデータを確認(最初の5行)
print(x_scaled[:5])Step 3. PCAのインスタンス化と実行
いよいよPCAの実行です。Scikit-learnでは、非常に簡単なコードでPCAを適用できます。
PCAクラスのインスタンスを作成する際に、n_componentsという引数で削減後の次元数を指定します。今回は4次元から2次元へ削減したいので、n_components=2とします。
from sklearn.decomposition import PCA
# n_componentsを2に設定して、PCAのインスタンスを作成
pca = PCA(n_components=2)
# 標準化したデータにPCAを適用(学習と変換を同時に実行)
principal_components = pca.fit_transform(x_scaled)
# 変換後のデータから新しいDataFrameを作成
pca_df = pd.DataFrame(data=principal_components,
columns=['principal component 1', 'principal component 2'])
# アヤメの種類(species)の列を結合
final_df = pd.concat([pca_df, df[['species']]], axis=1)
# 変換後のデータを確認
print(final_df.head())出力を見ると、元の4つの特徴量が「principal component 1」「principal component 2」という2つの新しい特徴量(主成分)に集約されていることが確認できます。
principal component 1 principal component 2 species
0 -2.264703 0.480027 setosa
1 -2.080961 -0.674134 setosa
2 -2.364229 -0.341908 setosa
3 -2.299384 -0.597395 setosa
4 -2.389842 0.646835 setosaStep 4. 次元削減した結果を可視化する
最後に、2次元に削減したデータをグラフにして、本当にうまく特徴を捉えられているのかを視覚的に確認しましょう。matplotlibを使って散布図を作成します。
# グラフのサイズ設定
plt.figure(figsize=(8, 6))
# 可視化
sns.scatterplot(
x='principal component 1',
y='principal component 2',
hue='species', # 種類ごとに色分け
data=final_df,
palette='Set1', # カラーパレット
s=70, # マーカーのサイズ
alpha=0.8 # 透明度
)
# グラフのタイトルとラベル
plt.title('PCA of Iris Dataset', fontsize=20)
plt.xlabel('Principal Component 1', fontsize=15)
plt.ylabel('Principal Component 2', fontsize=15)
plt.grid()
plt.legend()
plt.show()このコードを実行すると、美しい散布図が表示されます。 (※実行環境によってはグラフが表示されます)
グラフを見ると、アヤメの種類ごとにデータがうまくグループ化されていることが一目瞭然です。特にsetosaは他の2種から明確に分離できています。これは、PCAによって生成された2つの主成分が、元の4つの特徴量が持っていた「アヤメの種類を分類するための情報」をうまく保持していることを示しています。
PCAの結果をもう少し詳しく見てみよう
次元削減と可視化はできましたが、PCAはさらに奥深い情報を提供してくれます。ここでは、結果を解釈するための2つの重要な指標を見ていきましょう。
寄与率を確認する:主成分はどれだけ元の情報を説明している?
**寄与率(explained variance ratio)**とは、各主成分が元のデータ全体の情報の(分散の)うち、どれだけの割合を説明できているかを示す指標です。
Scikit-learnでは、学習済みのPCAオブジェクトのexplained_variance_ratio_属性を調べることで、簡単に確認できます。
# 各主成分の寄与率を表示
print('各主成分の寄与率:', pca.explained_variance_ratio_)
# 寄与率の合計を計算
total_variance = sum(pca.explained_variance_ratio_)
print(f'2つの主成分で説明される情報の割合: {total_variance:.4f} ({total_variance*100:.2f}%)')実行結果は以下のようになります。
各主成分の寄与率: [0.72962445 0.22850762]
2つの主成分で説明される情報の割合: 0.9581 (95.81%)これは、第1主成分(principal component 1)だけで元の情報の約73%、第2主成分(principal component 2)が約23%を説明していることを意味します。そして、この2つの主成分を合わせると、元の4次元データが持っていた情報の約95.8%を説明できていることが分かります。非常に効率的に情報を要約できていると言えるでしょう。
どこまで次元削減すべき?累積寄与率の活用
n_componentsをいくつに設定すれば良いかは、分析の目的によって変わりますが、一つの目安となるのが累積寄与率です。これは、第1主成分から第N主成分までの寄与率を足し合わせたものです。
一般的には、累積寄与率が80%〜90%程度になる次元数を選ぶことが多いです。これをグラフで可視化すると、判断がしやすくなります。
# n_componentsを指定せずに再度PCAを実行
pca_full = PCA().fit(x_scaled)
# 累積寄与率を計算
cumulative_variance_ratio = np.cumsum(pca_full.explained_variance_ratio_)
# 累積寄与率のグラフ(スクリープロット)を描画
plt.figure(figsize=(8, 5))
plt.plot(range(1, len(cumulative_variance_ratio) + 1), cumulative_variance_ratio, marker='o', linestyle='--')
plt.title('Scree Plot of Cumulative Explained Variance')
plt.xlabel('Number of Components')
plt.ylabel('Cumulative Explained Variance')
plt.xticks(range(1, len(cumulative_variance_ratio) + 1))
plt.grid()
plt.show()このグラフを見ると、主成分の数が2つの時点で累積寄与率が95%を超えていることが分かります。そのため、今回のケースではn_components=2という選択は非常に妥当であったと言えます。
まとめ
今回は、PythonのScikit-learnライブラリを使った主成分分析(PCA)について、基本的な考え方から実践的なコード、結果の解釈までを解説しました。
最後に、この記事の要点を振り返りましょう。
- PCAは、情報の損失を抑えつつ高次元のデータを低次元に要約する強力な手法です。
- 次元削減により、データを可視化したり、機械学習モデルの効率と性能を改善したりできます。
- Scikit-learnを使えば、
StandardScalerによる前処理からPCAの実行、結果の可視化までが驚くほど簡単に行えます。 - 寄与率や累積寄与率を確認することで、主成分がどれだけ元の情報を捉えられているかを評価し、適切な次元数を判断するのに役立ちます。
PCAは、複雑なデータセットに隠された構造を明らかにするための第一歩として、非常に有効なツールです。ぜひ、ご自身のデータセットでも試してみてください。PCAで可視化したデータを眺めたり、次元削減した特徴量を機械学習モデルの入力に使ったりと、データ分析の活用の幅が大きく広がるはずです。


コメント