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 月 3 日