一个简单的例子
情景叙述
假设我们有一群学生的成绩数据,包括语文、数学、英语和物理这四门课的分数。
每个学生都有这四门课对应的成绩,这就形成了一个四维的数据空间。但我们发现,可能数学和物理成绩往往有较强的相关性,英语和语文成绩也有一定的关联。 这时我们使用主成分分析(PCA),它会找到新的“综合科目”,也就是主成分。比如第一个主成分可能综合反映了学生的理科思维能力,与数学和物理成绩的关系较大;第二个主成分可能综合反映了学生的语言能力,与英语和语文成绩关系较大。
通过这种方式,我们把原本复杂的四维数据,用两个新的“综合科目”(主成分)来近似表示,达到了降维和简化数据的目的,让我们能更清晰地看出学生在不同方面的总体表现趋势。
数学推导
假设有n个学生(n个样本),p门成绩(p个指标),则可构成大小为np的样本矩阵
:
现在我们想要找到一组新的变量,
,
,
(m
p)来更方便地描述学生成绩,则变量变量
,
,
,
可以表示为
,
,
,
的线性组合:
由于可以任意地对原始变量进行上述线性变换,由不同的线性变换得到的综合变量也不尽相同。为了取得较好的效果,我们总是希望
的方差尽可能大且各
之间相互独立。我们将线性变换约束在下面的原则之下:
计算步骤
1.计算原矩阵的相关系数矩阵:
2.计算R的特征值和特征向量
求解特征值和特征向量的数学部分不再赘述,这里给出简单的pythn实现:
import numpy as np
def calculate_eigenvalues_eigenvectors(correlation_matrix):
eigenvalues, eigenvectors = np.linalg.eig(correlation_matrix)
return eigenvalues, eigenvectors
# 示例相关系数矩阵
correlation_matrix = np.array([[1, 0.5, 0.2], [0.5, 1, 0.3], [0.2, 0.3, 1]])
eigenvalues, eigenvectors = calculate_eigenvalues_eigenvectors(correlation_matrix)
print("特征值:", eigenvalues)
print("特征向量:", eigenvectors)
3.计算主成分贡献率以及累计贡献率
import numpy as np
def calculate_contribution_rates(eigenvalues):
total_variance = np.sum(eigenvalues)
contribution_rates = eigenvalues / total_variance
cumulative_contribution_rates = np.cumsum(contribution_rates)
return contribution_rates, cumulative_contribution_rates
# 示例特征值
eigenvalues = np.array([3.5, 1.2, 0.8])
contribution_rates, cumulative_contribution_rates = calculate_contribution_rates(eigenvalues)
print("主成分贡献率:", contribution_rates)
print("主成分累计贡献率:", cumulative_contribution_rates)
一般取累计贡献率大于某一百分比的特征值所对应的前m个主成分,从而达到数据降维的作用。
具体情境示例
在文章初描述的情境中,假设有10名学生A~J,分别有数学、物理、语文、英语四门学科成绩,具体数据如下:
Student: ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']
Math: [57, 51, 90, 99, 86, 84, 75, 82, 57, 78]
Physics: [69, 53, 90, 116, 98, 88, 91, 99, 66, 80]
Chinese: [59, 79, 74, 79, 53, 76, 56, 70, 51, 89]
English: [68, 80, 74, 92, 62, 79, 68, 83, 58, 91]
进行主成分分析:
import numpy as np
from scipy.stats import zscore
from sklearn.decomposition import PCA
# 将数据转换为 numpy 数组
data = np.array([
[57, 69, 59, 68],
[51, 53, 79, 80],
[90, 90, 74, 74],
[99, 116, 79, 92],
[86, 98, 53, 62],
[84, 88, 76, 79],
[75, 91, 56, 68],
[82, 99, 70, 83],
[57, 66, 51, 58],
[78, 80, 89, 91]
])
# 标准化数据
data_std = zscore(data)
# 进行主成分分析
pca = PCA(n_components=2) # 指定只保留 2 个主成分
pca.fit(data_std)
# 打印前 2 个主成分
print("第一个主成分:", pca.components_[0])
print("第二个主成分:", pca.components_[1])
# 获取解释方差比例(即每个主成分的贡献率)
explained_variance_ratio = pca.explained_variance_ratio_
# 计算累计贡献率
cumulative_contribution = np.cumsum(explained_variance_ratio)
print("前两个主成分的累计贡献率:", cumulative_contribution[1])
输出结果如下:
第一个主成分: [0.53311981 0.47316645 0.45517108 0.53358791]
第二个主成分: [-0.42931496 -0.55051269 0.57499604 0.42661926]前两个主成分的累计贡献率: 0.9732164017362895
第一个主成分基本反映了平均分对于整体成绩的影响,第二个主成分反映了理科思维与语言能力的相对差异。