Wizard Notes

Python, JavaScript を使った音楽信号分析の技術録、作曲活動に関する雑記

Matplotlibで主成分分析の寄与率・累積寄与率を左右2軸プロット

多変量解析の一般的な手法である主成分分析を使っていると、寄与率と累積寄与率を確認することが多いです。

それぞれを別にプロットしてもよいのですが、 1つのプロットで確認できたほうが便利だと思い、matplotlibで実装してみました。

一つのプロットで左右2つの軸を描画するには、matplotlibではax.twinx()をいう関数を使うことで実現できます。

プロット例

f:id:Kurene:20191112025841p:plain

サンプルコード

import numpy as np
import matplotlib.pyplot as plt

n_sample = 1000
n_dim = 30

mean = np.random.normal(0.0, 1, n_dim)
cov = np.eye(n_dim)
for k in range(0, n_dim):
    cov[k,k] = np.abs(np.random.normal(0.0, 1))
for n in range(0, n_dim):
    for m in range(0, n):
        r = np.random.normal(0.0, 0.25)
        cov[m,n] = r
        cov[n,m] = r
x = np.random.multivariate_normal(mean, cov, n_sample).T


from sklearn.decomposition import PCA
pca = PCA()
z = pca.fit(x).transform(x).T
ev_ratio = pca.explained_variance_ratio_
print(np.round(ev_ratio, 2))

fig = plt.figure()
ax1 = fig.add_subplot(111)
hist = np.r_[0.0, ev_ratio] + 1e-9
ax1.bar(np.arange(0, len(hist)), hist, color="m", width=1.0, alpha=0.5, edgecolor="black")
ax1.set_xlabel("Principle components")
ax1.set_ylabel("Contribution ratio")

ax2 = ax1.twinx()
line = np.r_[0.0, ev_ratio.cumsum()]
obj1 = ax1.plot(np.arange(0, len(line)), line, "o-", c="c", alpha=0.5)
ax2.set_ylabel("Cumulative contribution rate")

ax1.set_ylim(0.0, 1.0)
ax2.set_ylim(0.0, 1.0)

ax2.minorticks_on()
ax2.grid(True, 'both')
plt.show()