由于感觉因子分析不是很懂,因此又通过python把
因子分析(factor analysis)案例(matlab实现) 这题又给打了一遍。
这里加上了碎石图,用来选择辅助选择因子个数,但是我感觉这里没啥用吧。
这里可能由于数据标准化的方式有些不同,因此计算出来的数值和之前那个不太一样,但是综合评分的排名还是一样的。
数据的话我上传到资源里了,因为有一次聚类数据太大了,博客里放不了,因此就想着试试上传资源了。
设置的是0积分,放心大胆用
import pandas as pd
import numpy as np
import numpy.linalg as nlg
import matplotlib.pyplot as plt
from factor_analyzer import FactorAnalyzer, calculate_kmo, calculate_bartlett_sphericity
from sklearn.preprocessing import StandardScaler
import matplotlib
def main():
contribution_rate = 0.8
auto_choose_N = True # 设置为True的时候就自动根据贡献率来选择因子个数,为False则要自己设置N
N = 2
file = "test.csv"
f = pd.read_csv(file, sep=" ", header=None)
f = StandardScaler().fit_transform(f) # 数据标准化
f = pd.DataFrame(f)
# 皮尔逊相关系数
f_corr = f.corr()
kmo = calculate_kmo(f)
bartlett = calculate_bartlett_sphericity(f)
if kmo[1] >= 0.7 and bartlett[1] <= 0.05: # bartlett球形度检验p值要小于0.05 kmo值要大于0.7
print("\n因子分析适用性检验通过\n")
else:
print("\n因子分析适用性检验未通过\n")
print('kmo:{},bartlett:{}'.format(kmo[1], bartlett[1]))
# 计算旋转前的载荷矩阵的方差贡献率,可以用来看有几个因子时总共先率到达多少
Load_Matrix = FactorAnalyzer(rotation=None, n_factors=len(f.T), method='principal')
Load_Matrix.fit(f)
f_contribution_var = Load_Matrix.get_factor_variance()
matrices_var = pd.DataFrame()
matrices_var["旋转前特征值"] = f_contribution_var[0]
matrices_var["旋转前方差贡献率"] = f_contribution_var[1]
matrices_var["旋转前方差累计贡献率"] = f_contribution_var[2]
print(matrices_var)
if auto_choose_N:
sum_con = 0
N = 0
for c in matrices_var["旋转前方差贡献率"]:
sum_con += c
N += 1
if sum_con >= contribution_rate:
print("\n选择了" + str(N) + "个因子累计贡献率为"+str(sum_con)+"\n")
break
matplotlib.rcParams["font.family"] = "SimHei" # 碎石图主要用来看取多少因子合适,一般是取到平滑处左右,当然还要需要结合贡献率
ev, v = Load_Matrix.get_eigenvalues()
print('\n相关矩阵特征值:', ev)
plt.figure(figsize=(8, 6.5))
plt.scatter(range(1, f.shape[1]+1), ev)
plt.plot(range(1, f.shape[1]+1), ev)
plt.title('碎石图', fontdict={'weight': 'normal', 'size': 25})
plt.xlabel('因子', fontdict={'weight': 'normal', 'size': 15})
plt.ylabel('特征值', fontdict={'weight': 'normal', 'size': 15})
plt.grid()
plt.show()
# 使用主成分分析的方法来计算出因子载荷矩阵,使用最大方差法旋转因子载荷矩阵
Load_Matrix_rotated = FactorAnalyzer(rotation='varimax', n_factors=N, method='principal')
Load_Matrix_rotated.fit(f)
# 计算旋转后的载荷矩阵的贡献率
f_contribution_var_rotated = Load_Matrix_rotated.get_factor_variance()
matrices_var_rotated = pd.DataFrame()
matrices_var_rotated["特征值"] = f_contribution_var_rotated[0]
matrices_var_rotated["方差贡献率"] = f_contribution_var_rotated[1]
matrices_var_rotated["方差累计贡献率"] = f_contribution_var_rotated[2]
print(matrices_var_rotated)
# 计算因子得分(回归方法)(系数矩阵的逆乘以因子载荷矩阵)
X1 = np.mat(f_corr)
X1 = nlg.inv(X1)
factor_score_weight = np.dot(X1, Load_Matrix_rotated.loadings_)
factor_score_weight = pd.DataFrame(factor_score_weight)
col = []
for i in range(N):
col.append("factor" + str(i+1))
factor_score_weight.columns = col
factor_score_weight.index = f_corr.columns
print("\n第一列为第一个因子得分函数的对应系数")
print("因子得分:\n", factor_score_weight)
factor_score = pd.DataFrame(np.dot(np.mat(f), np.mat(factor_score_weight))) # 指标 * 对应权重,计算出因子的分数
i = 0
factor_score["综合得分"] = 0
for factor_score_weight in matrices_var_rotated["方差贡献率"]:
factor_score["综合得分"] += factor_score_weight * factor_score[i] # 因子贡献率 * 因子的分数 用于计算综合得分
i += 1
if i == N:
break
factor_score["综合得分"] = factor_score["综合得分"] / matrices_var_rotated["方差贡献率"].sum() # 计算综合得分
factor_score.index = ["歌", "五", "用", "太", "浙", "烟", "方", "红河", "贵", "中", "红星", "伊", "青", "湖", "雅", "福"] # 更改索引
print(factor_score.sort_values(by=["综合得分"], ascending=False)) # 排序
if __name__ == '__main__':
main()
运行结果上图所示,我看了一下,由于matlab和python数据预处理的函数输出的结果有些出入,因此分数可能和原题有点出入,但是综合得分的排名是一样的顺序,应该没啥大问题。