statsmodels 主成分分析

主要概念: 主成分分析、世界銀行數據、生育率

在本筆記本中,我們使用主成分分析 (PCA) 來分析 192 個國家生育率的時間序列,數據來自世界銀行。主要目標是了解各國生育率隨時間變化的趨勢有何不同。這是一個稍微不典型的 PCA 應用,因為數據是時間序列。雖然已經開發了用於此設定的方法(例如函數型 PCA),但由於生育率數據非常平滑,因此在這種情況下使用標準 PCA 並沒有真正的缺點。

[1]:
%matplotlib inline

import matplotlib.pyplot as plt
import statsmodels.api as sm
from statsmodels.multivariate.pca import PCA

plt.rc("figure", figsize=(16, 8))
plt.rc("font", size=14)

數據可以從世界銀行網站取得,但這裡我們使用稍微清理過的數據版本

[2]:
data = sm.datasets.fertility.load_pandas().data
data.head()
[2]:
國家名稱 國家代碼 指標名稱 指標代碼 1960 1961 1962 1963 1964 1965 ... 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013
0 阿魯巴 ABW 生育率,總計(每名婦女的生育數) SP.DYN.TFRT.IN 4.820 4.655 4.471 4.271 4.059 3.842 ... 1.786 1.769 1.754 1.739 1.726 1.713 1.701 1.690 NaN NaN
1 安道爾 AND 生育率,總計(每名婦女的生育數) SP.DYN.TFRT.IN NaN NaN NaN NaN NaN NaN ... NaN NaN 1.240 1.180 1.250 1.190 1.220 NaN NaN NaN
2 阿富汗 AFG 生育率,總計(每名婦女的生育數) SP.DYN.TFRT.IN 7.671 7.671 7.671 7.671 7.671 7.671 ... 7.136 6.930 6.702 6.456 6.196 5.928 5.659 5.395 NaN NaN
3 安哥拉 AGO 生育率,總計(每名婦女的生育數) SP.DYN.TFRT.IN 7.316 7.354 7.385 7.410 7.425 7.430 ... 6.704 6.657 6.598 6.523 6.434 6.331 6.218 6.099 NaN NaN
4 阿爾巴尼亞 ALB 生育率,總計(每名婦女的生育數) SP.DYN.TFRT.IN 6.186 6.076 5.956 5.833 5.711 5.594 ... 2.004 1.919 1.849 1.796 1.761 1.744 1.741 1.748 NaN NaN

5 列 × 58 欄

在這裡,我們建立一個 DataFrame,其中只包含數值的生育率數據,並將索引設定為國家名稱。我們也刪除所有有任何遺失數據的國家。

[3]:
columns = list(map(str, range(1960, 2012)))
data.set_index("Country Name", inplace=True)
dta = data[columns]
dta = dta.dropna()
dta.head()
[3]:
1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 ... 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011
國家名稱
阿魯巴 4.820 4.655 4.471 4.271 4.059 3.842 3.625 3.417 3.226 3.054 ... 1.825 1.805 1.786 1.769 1.754 1.739 1.726 1.713 1.701 1.690
阿富汗 7.671 7.671 7.671 7.671 7.671 7.671 7.671 7.671 7.671 7.671 ... 7.484 7.321 7.136 6.930 6.702 6.456 6.196 5.928 5.659 5.395
安哥拉 7.316 7.354 7.385 7.410 7.425 7.430 7.422 7.403 7.375 7.339 ... 6.778 6.743 6.704 6.657 6.598 6.523 6.434 6.331 6.218 6.099
阿爾巴尼亞 6.186 6.076 5.956 5.833 5.711 5.594 5.483 5.376 5.268 5.160 ... 2.195 2.097 2.004 1.919 1.849 1.796 1.761 1.744 1.741 1.748
阿拉伯聯合大公國 6.928 6.910 6.893 6.877 6.861 6.841 6.816 6.783 6.738 6.679 ... 2.428 2.329 2.236 2.149 2.071 2.004 1.948 1.903 1.868 1.841

5 列 × 52 欄

使用 PCA 分析矩形矩陣有兩種方法:我們可以將列視為「對象」,將欄視為「變數」,反之亦然。在這裡,我們將把生育率衡量標準視為衡量國家「對象」的「變數」。因此,目標是將每年的生育率值縮減為少量的生育率「輪廓」或「基底函數」,這些輪廓或基底函數能捕捉不同國家隨著時間推移的大部分變化。

PCA 中會移除平均趨勢,但還是值得看一下。它顯示在該數據集中涵蓋的時間段內,生育率穩步下降。請注意,平均值是使用國家作為分析單位計算的,忽略了人口規模。以下進行的 PC 分析也是如此。更複雜的分析可能會對國家進行加權,例如以 1980 年的人口為權重。

[4]:
ax = dta.mean().plot(grid=False)
ax.set_xlabel("Year", size=17)
ax.set_ylabel("Fertility rate", size=17)
ax.set_xlim(0, 51)
[4]:
(0.0, 51.0)
../../../_images/examples_notebooks_generated_pca_fertility_factors_9_1.png

接下來,我們執行 PCA

[5]:
pca_model = PCA(dta.T, standardize=False, demean=True)

根據特徵值,我們看到第一個 PC 佔據主導地位,第二和第三個 PC 可能捕獲了少量的有意義變化。

[6]:
fig = pca_model.plot_scree(log_scale=False)
../../../_images/examples_notebooks_generated_pca_fertility_factors_13_0.png

接下來,我們將繪製 PC 因子。主導因子是單調遞增的。在第一個因子中得分為正的國家,其增長速度會比上面顯示的平均值更快(或減少速度更慢)。在第一個因子中得分為負的國家,其減少速度會比平均值更快。第二個因子呈 U 形,在 1985 年左右達到正峰值。在第二個因子中得分為正值較大的國家,在數據範圍的開始和結束時的生育率會低於平均水平,但在範圍中間的生育率會高於平均水平。

[7]:
fig, ax = plt.subplots(figsize=(8, 4))
lines = ax.plot(pca_model.factors.iloc[:, :3], lw=4, alpha=0.6)
ax.set_xticklabels(dta.columns.values[::10])
ax.set_xlim(0, 51)
ax.set_xlabel("Year", size=17)
fig.subplots_adjust(0.1, 0.1, 0.85, 0.9)
legend = fig.legend(lines, ["PC 1", "PC 2", "PC 3"], loc="center right")
legend.draw_frame(False)
/tmp/ipykernel_3281/427128218.py:3: UserWarning: set_ticklabels() should only be used with a fixed number of ticks, i.e. after set_ticks() or using a FixedLocator.
  ax.set_xticklabels(dta.columns.values[::10])
../../../_images/examples_notebooks_generated_pca_fertility_factors_15_1.png

為了更好地了解情況,我們將繪製具有相似 PC 分數的國家組的生育率軌跡。以下便利函數會產生這樣的圖表。

[8]:
idx = pca_model.loadings.iloc[:, 0].argsort()

首先,我們繪製在 PC 1 上得分最高的五個國家。這些國家的生育率增長率高於全球平均值(正在下降)。

[9]:
def make_plot(labels):
    fig, ax = plt.subplots(figsize=(9, 5))
    ax = dta.loc[labels].T.plot(legend=False, grid=False, ax=ax)
    dta.mean().plot(ax=ax, grid=False, label="Mean")
    ax.set_xlim(0, 51)
    fig.subplots_adjust(0.1, 0.1, 0.75, 0.9)
    ax.set_xlabel("Year", size=17)
    ax.set_ylabel("Fertility", size=17)
    legend = ax.legend(
        *ax.get_legend_handles_labels(), loc="center left", bbox_to_anchor=(1, 0.5)
    )
    legend.draw_frame(False)
[10]:
labels = dta.index[idx[-5:]]
make_plot(labels)
../../../_images/examples_notebooks_generated_pca_fertility_factors_20_0.png

以下是在因子 2 上得分最高的五個國家。這些國家的生育率在 1980 年左右達到頂峰,比世界其他大部分地區晚,然後生育率迅速下降。

[11]:
idx = pca_model.loadings.iloc[:, 1].argsort()
make_plot(dta.index[idx[-5:]])
../../../_images/examples_notebooks_generated_pca_fertility_factors_22_0.png

最後,我們有在 PC 2 上得分最負的國家。這些國家在 1960 年代和 1970 年代的生育率下降速度比全球平均值快得多,然後趨於平穩。

[12]:
make_plot(dta.index[idx[:5]])
../../../_images/examples_notebooks_generated_pca_fertility_factors_24_0.png

我們也可以查看前兩個主成分分數的散點圖。我們看到國家之間的變化相當連續,但 PC 2 得分最高的兩個國家可能與其他點有些分離。這兩個國家,阿曼和葉門,在 1980 年左右的生育率出現了明顯的尖峰,這是獨特的。沒有其他國家有這樣的尖峰。相反,在 PC 1 上得分較高(生育率持續上升)的國家是變化的連續體的一部分。

[13]:
fig, ax = plt.subplots()
pca_model.loadings.plot.scatter(x="comp_00", y="comp_01", ax=ax)
ax.set_xlabel("PC 1", size=17)
ax.set_ylabel("PC 2", size=17)
dta.index[pca_model.loadings.iloc[:, 1] > 0.2].values
[13]:
array(['Oman', 'Yemen, Rep.'], dtype=object)
../../../_images/examples_notebooks_generated_pca_fertility_factors_26_1.png

最後更新:2024 年 10 月 03 日