見出し画像

【Python入門:主成分分析編#4】scikit-learnでサクッとPCA(主成分分析) ― たった2行で次元圧縮

手計算を卒業して、実践へ

以下の3回で、PCAの仕組みを一から説明しました。

NumPyで手計算した経験があるからこそ、ライブラリが「裏で何をしているか」がわかります。

今回は、scikit-learnを使って、PCAを効率的に実行する方法を学びましょう。

手計算で何十行も書いていたコードが、たった2行になります。


🎯 この記事で学べること

  • scikit-learnでPCAを実行する基本的な流れ

  • 寄与率・固有値・固有ベクトルの取り出し方

  • 主成分負荷量の計算方法

  • 散布図とスクリープロットの作成



📦 準備:ライブラリとデータ

ライブラリの読み込み

以下、コードです。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib

from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA

データの準備

おなじみのIrisデータセットを使います。4つの特徴量を持つ150サンプルのデータです。

以下、コードです。

# Irisデータセットを読み込み
iris = load_iris()
X = iris.data
y = iris.target
特徴量名 = iris.feature_names
品種名 = iris.target_names

# 標準化(PCAの前処理として必須)
scaler = StandardScaler()
X_標準化 = scaler.fit_transform(X)

print(f"データの形状: {X_標準化.shape}")
print(f"特徴量: {特徴量名}")

以下、実行結果です。

データの形状: (150, 4)
特徴量: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']

ポイント: PCAは分散を見る手法なので、標準化してスケールを揃えることが重要です。


🚀 scikit-learnでPCAを実行する

基本の2行

scikit-learnのAPIはシンプルです。fitで学習、transformで変換。fit_transformなら一度に両方できます。

以下、コードです。

# ① PCAオブジェクトを作成(2次元に圧縮)
pca = PCA(n_components=2)

# ② 実行!
Z = pca.fit_transform(X_標準化)

# 結果を確認(先頭5行)
print(Z[:5])

以下、実行結果です。

[[-2.26470281 0.4800266 ]
[-2.08096115 -0.67413356]
[-2.36422905 -0.34190802]
[-2.29938422 -0.59739451]
[-2.38984217 0.64683538]]


4次元のデータが2次元に変換されました!

前回までNumPyで行った「共分散行列の計算」「固有値分解」「主成分得点の算出」が、この2行に凝縮されています。


📊 結果を取り出す

PCAオブジェクトには、分析結果がすべて格納されています。主要な属性を見ていきましょう。

寄与率と固有値

以下、コードです。

print("=== 各主成分の情報 ===")
for i in range(len(pca.explained_variance_ratio_)):
    寄与率 = pca.explained_variance_ratio_[i]
    固有値 = pca.explained_variance_[i]
    print(f"PC{i+1}: 寄与率 = {寄与率*100:.2f}%, 固有値 = {固有値:.4f}")

# 累積寄与率
累積 = np.cumsum(pca.explained_variance_ratio_)
print(f"\n累積寄与率: {累積[-1]*100:.2f}%")

以下、実行結果です。

=== 各主成分の情報 ===
PC1: 寄与率 = 72.96%, 固有値 = 2.9381
PC2: 寄与率 = 22.85%, 固有値 = 0.9202

累積寄与率: 95.81%


2つの主成分で、元データの情報の約96%を保持しています。4次元→2次元への圧縮としては十分な結果です。

主成分の方向(固有ベクトル)

components_属性には、各主成分の方向を示す固有ベクトルが格納されています。

以下、コードです。

# 固有ベクトルをDataFrameで見やすく
固有ベクトルDF = pd.DataFrame(
    pca.components_,
    index=['PC1', 'PC2'],
    columns=特徴量名
)
print(固有ベクトルDF.round(3))

以下、実行結果です。

            sepal length (cm)    sepal width (cm)    petal length (cm)    petal width (cm)
PC1  0.521    -0.269    0.580    0.565
PC2  0.377     0.923    0.024    0.067

この表の読み方:

  • PC1: petal length、petal width、sepal lengthの係数が大きい → 花のサイズ全般を表す軸

  • PC2: sepal widthの係数が突出 → がく片の幅を表す軸

主成分負荷量を計算する

固有ベクトルと主成分負荷量は別物です。主成分負荷量は「元の変数と主成分の相関」を表し、解釈しやすい指標です。

以下、コードです。

# 主成分負荷量 = 固有ベクトル × √固有値
負荷量 = 固有ベクトルDF.T * np.sqrt(pca.explained_variance_)
print("=== 主成分負荷量 ===")
print(負荷量.round(3))

以下、実行結果です。

=== 主成分負荷量 ===
                                 PC1      PC2
sepal length (cm)    0.893     0.362
sepal width (cm)    -0.462     0.886
petal length (cm)     0.995    0.023
petal width (cm)      0.968     0.064


負荷量が ±0.7 以上なら「強い関連」と解釈できます。

  • PC1: petal length (0.995)、petal width (0.968)、sepal length (0.893) と強く関連

  • PC2: sepal width (0.886) と強く関連


📈 可視化する

主成分得点の散布図

2次元に圧縮したデータを散布図で確認しましょう。

以下、コードです。

plt.figure(figsize=(10, 8))

# 品種ごとに色分け
colors = ['#E74C3C', '#2ECC71', '#3498DB']

for i, (name, color) in enumerate(zip(品種名, colors)):
    mask = y == i
    plt.scatter(
        Z[mask, 0], Z[mask, 1],
        c=color, label=name, s=80, alpha=0.7
    )

plt.xlabel(f'PC1 ({pca.explained_variance_ratio_[0]*100:.1f}%)')
plt.ylabel(f'PC2 ({pca.explained_variance_ratio_[1]*100:.1f}%)')
plt.title('PCA: Irisデータセットの2次元表現')
plt.legend(title='品種')
plt.grid(True, alpha=0.3)
plt.axhline(y=0, color='gray', linewidth=0.5)
plt.axvline(x=0, color='gray', linewidth=0.5)
plt.show()

以下、実行結果です。

3品種がきれいに分離されていることが確認できます。特にsetosaは他の2種と完全に分かれています。

これが次元削減の威力です。4次元空間では見えなかったパターンが、2次元に圧縮することで可視化できました。

スクリープロット

すべての主成分を抽出して、最適な主成分数を判断するためのスクリープロットを作成します。

以下、コードです。

# 全主成分を抽出(n_componentsを指定しない)
pca_full = PCA()
pca_full.fit(X_標準化)

# プロット作成
fig, axes = plt.subplots(2, 1, figsize=(10, 10))

x = np.arange(1, len(pca_full.explained_variance_) + 1)

# 上段:固有値
axes[0].bar(x, pca_full.explained_variance_, color='steelblue')
axes[0].set_xlabel('主成分')
axes[0].set_ylabel('固有値')
axes[0].set_title('スクリープロット')
axes[0].set_xticks(x)

# 下段:寄与率と累積寄与率
累積寄与率 = np.cumsum(pca_full.explained_variance_ratio_) * 100
axes[1].bar(x, pca_full.explained_variance_ratio_ * 100, 
            label='寄与率', color='steelblue')
axes[1].plot(x, 累積寄与率, 'ro-', markersize=10, linewidth=2, 
             label='累積寄与率')
axes[1].axhline(y=80, color='green', linestyle='--', label='80%ライン')
axes[1].set_xlabel('主成分')
axes[1].set_ylabel('寄与率 (%)')
axes[1].set_title('寄与率と累積寄与率')
axes[1].set_xticks(x)
axes[1].legend()

plt.tight_layout()
plt.show()

以下、実行結果です。

このグラフから、「エルボー法」や「累積寄与率80%以上」といった基準で、最適な主成分数を判断できます。


まとめ

scikit-learnを使ったPCAの実行方法をお話ししました。

基本の流れ:

  1. PCA(n_components=2) でオブジェクト作成

  2. fit_transform(X) で実行

  3. 属性から寄与率や固有ベクトルを取得

重要なポイント:

  • 事前にデータを標準化する

  • explained_variance_ratio_ で寄与率を確認

  • 主成分負荷量は components_.T * √explained_variance_ で計算


📺 次回予告

次回は、PCAと似ているようで異なる「因子分析」を取り上げます。

  • PCAは「データを要約する」

  • 因子分析は「背後にある構造を見つける」

両者の違いを理解することで、分析目的に応じた手法選択ができるようになります。

お楽しみに!


📚 参考にした情報源


最後まで読んでいただきありがとうございました! 「スキ」を押していただけると励みになります 🙌

いいなと思ったら応援しよう!