从网上找对应分析的资料的时候,发现很多都是理论性的文章,有案例的文章很少。这篇博文主要是利用参考资料中2中的数据,复现一下论文中的整个实验过程。参考资料2中关于对应分析的介绍有错误,所以对应分析的计算过程来源于资料3
1 对应分析
对应分析(Correspondence Analysis)也称关联分析、R-Q型因子分析,是近年新发展起来的一种多元相依变量统计分析技术,通过分析由定性变量构成的交互汇总表来揭示变量间的联系。该技术可以揭示同一变量中各个类别之间的差异,以及不同变量各个类别之间的对应关系。对应分析的基本思想是将一个联列表中的行和列中的各元素的比例结构以点的形式在较低维的空间中表示出来。
2 对应分析过程
2.1 原始矩阵标准化
假设原始矩阵
X
X
X
X
=
[
x
11
x
12
…
x
1
p
x
21
x
22
…
x
2
p
⋮
⋮
⋮
x
n
1
x
n
2
…
x
n
p
]
X=\begin{bmatrix} x_{11}&x_{12}&\dots&x_{1p} \\ x_{21}&x_{22}&\dots&x_{2p} \\ \vdots&\vdots&&\vdots \\ x_{n1}&x_{n2}&\dots&x_{np} \end{bmatrix}
X=⎣⎢⎢⎢⎡x11x21⋮xn1x12x22⋮xn2………x1px2p⋮xnp⎦⎥⎥⎥⎤其中,行表示样品(比如网站),列表示属性(比如浏览量)。
(1) 将数据矩阵
X
X
X转化为概率矩阵
P
P
P,其中矩阵
P
P
P中每个元素的定义如下:
P
=
(
p
i
j
)
n
×
p
,
p
i
j
=
x
i
j
/
T
,
T
=
∑
i
=
1
n
∑
j
=
1
p
x
i
j
P=(p_{ij})_{n \times p}, p_{ij}=x_{ij}/T,T=\sum_{i=1}^{n}\sum_{j=1}^{p}x_{ij}
P=(pij)n×p,pij=xij/T,T=i=1∑nj=1∑pxij变换后,概率矩阵
P
P
P的元素之和为1。
(2)求边缘概率
p
.
j
p_{.j}
p.j和
p
i
.
p_{i.}
pi.的边缘概率,其计算公式如下:
p
i
.
=
∑
j
=
1
p
p
i
j
,
p
.
j
=
∑
i
=
1
n
p
i
j
p_{i.}=\sum_{j=1}^{p}p_{ij},p_{.j}=\sum_{i=1}^{n}p_{ij}
pi.=j=1∑ppij,p.j=i=1∑npij(3)对概率矩阵
P
P
P做中心化及标准化变换得到矩阵
Z
Z
Z,其中矩阵
Z
Z
Z中的元素定义如下:
Z
=
(
z
i
j
)
n
×
p
=
p
i
j
−
p
i
.
p
.
j
p
i
.
p
.
j
Z=(z_{ij})_{n \times p}=\frac{ p_{ij}-p_{i.}p_{.j} }{ \sqrt{p_{i.}p_{.j}} }
Z=(zij)n×p=pi.p.jpij−pi.p.j
2.2 计算 R R R型因子分析载荷矩阵
(1) 计算协方差矩阵
S
R
=
Z
T
Z
S_{R}=Z^{T}Z
SR=ZTZ的特征值和标准化的特征向量。设特征值
λ
1
≥
λ
2
≥
⋯
≥
λ
m
>
0
\lambda_{1}\ge\lambda_{2}\ge\dots\ge\lambda_{m}>0
λ1≥λ2≥⋯≥λm>0,相应标准化特征向量为
v
1
,
v
2
,
…
,
v
m
v_{1},v_{2},\dots,v_{m}
v1,v2,…,vm。在实际应用中常按累计贡献率
λ
1
+
λ
2
+
⋯
+
λ
l
λ
1
+
⋯
+
λ
l
+
⋯
+
λ
m
≥
0.85
\frac{ \lambda_{1}+\lambda_{2}+\dots+\lambda_{l} }{ \lambda_{1}+\dots+\lambda_{l}+\dots+\lambda_{m}}\ge0.85
λ1+⋯+λl+⋯+λmλ1+λ2+⋯+λl≥0.85确定所取公共因子
l
≤
m
l\le m
l≤m。注意
d
i
=
λ
i
,
i
=
(
1
,
2
,
…
,
m
)
d_{i}=\sqrt{\lambda_{i}},i=(1,2,\dots,m)
di=λi,i=(1,2,…,m)称为奇异值。
(2)
R
R
R型因子的“因子载荷矩阵”为
R
=
[
λ
1
v
11
p
.
1
λ
2
v
12
p
.
1
⋯
λ
l
v
1
l
p
.
1
λ
1
v
21
p
.
2
λ
2
v
22
p
.
2
⋯
λ
2
v
2
l
p
.
2
⋮
⋮
⋮
λ
1
v
p
1
p
.
p
λ
2
v
p
2
p
.
p
⋯
λ
l
v
p
l
p
.
p
]
R=\begin{bmatrix} \frac{\sqrt{\lambda_{1}}v_{11}}{\sqrt{p_{.1}}}&\frac{\sqrt{\lambda_{2}}v_{12}}{\sqrt{p_{.1}}}&\cdots&\frac{\sqrt{\lambda_{l}}v_{1l}}{\sqrt{p_{.1}}} \\ \frac{\sqrt{\lambda_{1}}v_{21}}{\sqrt{p_{.2}}}&\frac{\sqrt{\lambda_{2}}v_{22}}{\sqrt{p_{.2}}}&\cdots&\frac{\sqrt{\lambda_{2}}v_{2l}}{\sqrt{p_{.2}}} \\ \vdots&\vdots&&\vdots \\ \frac{\sqrt{\lambda_{1}}v_{p1}}{\sqrt{p_{.p}}}&\frac{\sqrt{\lambda_{2}}v_{p2}}{\sqrt{p_{.p}}}&\cdots&\frac{\sqrt{\lambda_{l}}v_{pl}}{\sqrt{p_{.p}}} \\ \end{bmatrix}
R=⎣⎢⎢⎢⎢⎢⎡p.1λ1v11p.2λ1v21⋮p.pλ1vp1p.1λ2v12p.2λ2v22⋮p.pλ2vp2⋯⋯⋯p.1λlv1lp.2λ2v2l⋮p.pλlvpl⎦⎥⎥⎥⎥⎥⎤
2.3 计算 Q Q Q型因子分析载荷矩阵
(1) 计算协方差矩阵
S
Q
=
Z
Z
T
S_{Q}=ZZ^{T}
SQ=ZZT的特征值和标准化的特征向量。
S
R
S_{R}
SR和
S
Q
S_{Q}
SQ两个矩阵矩阵大于0的特征值相同的。设
S
Q
S_{Q}
SQ的特征值
λ
1
,
λ
2
,
…
,
λ
l
\lambda_{1},\lambda_{2},\dots,\lambda_{l}
λ1,λ2,…,λl其对应的标准化特征向量为
u
1
,
u
2
,
…
,
u
m
u_{1},u_{2},\dots,u_{m}
u1,u2,…,um。
(2)
Q
Q
Q型因子的“因子载荷矩阵”为
Q
=
[
λ
1
u
11
p
1.
λ
2
u
12
p
1.
⋯
λ
l
u
1
l
p
1.
λ
1
u
21
p
2.
λ
2
u
22
p
2.
⋯
λ
2
u
2
l
p
2.
⋮
⋮
⋮
λ
1
u
n
1
p
n
.
λ
2
u
n
2
p
n
.
⋯
λ
l
u
n
l
p
n
.
]
Q=\begin{bmatrix} \frac{\sqrt{\lambda_{1}}u_{11}}{\sqrt{p_{1.}}}&\frac{\sqrt{\lambda_{2}}u_{12}}{\sqrt{p_{1.}}}&\cdots&\frac{\sqrt{\lambda_{l}}u_{1l}}{\sqrt{p_{1.}}} \\ \frac{\sqrt{\lambda_{1}}u_{21}}{\sqrt{p_{2.}}}&\frac{\sqrt{\lambda_{2}}u_{22}}{\sqrt{p_{2.}}}&\cdots&\frac{\sqrt{\lambda_{2}}u_{2l}}{\sqrt{p_{2.}}} \\ \vdots&\vdots&&\vdots \\ \frac{\sqrt{\lambda_{1}}u_{n1}}{\sqrt{p_{n.}}}&\frac{\sqrt{\lambda_{2}}u_{n2}}{\sqrt{p_{n.}}}&\cdots&\frac{\sqrt{\lambda_{l}}u_{nl}}{\sqrt{p_{n.}}} \\ \end{bmatrix}
Q=⎣⎢⎢⎢⎢⎢⎡p1.λ1u11p2.λ1u21⋮pn.λ1un1p1.λ2u12p2.λ2u22⋮pn.λ2un2⋯⋯⋯p1.λlu1lp2.λ2u2l⋮pn.λlunl⎦⎥⎥⎥⎥⎥⎤
2.4 计算 χ 2 \chi^{2} χ2统计量和总惯量
(1) 计算总惯量
Q
Q
Q,总惯量表示
n
n
n个样品到中心
c
c
c的加权平方距离的总和,其最终的计算公式如下:
Q
=
∑
i
=
1
n
∑
j
=
1
p
z
i
j
2
=
∑
i
=
1
l
λ
i
Q=\sum_{i=1}^{n}\sum_{j=1}^{p}z_{ij}^{2}=\sum_{i=1}^{l}\lambda_{i}
Q=i=1∑nj=1∑pzij2=i=1∑lλi(2) 计算
χ
2
\chi^{2}
χ2统计量,其计算公式如下:
χ
2
=
T
∑
i
=
1
n
∑
j
=
1
p
z
i
j
2
=
T
Q
\chi^{2}=T\sum_{i=1}^{n}\sum_{j=1}^{p}z_{ij}^{2}=TQ
χ2=Ti=1∑nj=1∑pzij2=TQ
3 实验过程
本文使用的是参考文献2中的数据。
import pandas as pd
import numpy as np
from math import sqrt
from matplotlib import pyplot as plt
import seaborn as sns
from scipy import stats
path='Documents/data.xlsx'
data=pd.read_excel(path,index_col=0,sheet_name='网站评价分析数据')
#1 卡方检验
# 判断这种分析方法是否适用
data_j=data.sum()/data.sum().sum()
data_i=data.sum(axis=1)
data_exp=np.dot(data_i.values.reshape(-1,1),data_j.values.reshape(1,-1))
data_exp=pd.DataFrame(data_exp,index=data_i.index,columns=data_j.index) #期望值
data_obj=data.values.flatten()
data_exp=data_exp.values.flatten()
chi_val,p_val=stats.chisquare(f_obs=data_obj,f_exp=data_exp)
#这里只展示了person卡方分析结果。
#在参考资料4中找到了一个似然卡方公式,但是计算出来的结果和论文中的结果相差太大,所以这里就忽略了
#2 将data转化为概率矩阵,然后进行标准化
data_p=data/data.sum().sum() #概率矩阵
data_j=data_p.sum() #列边缘概率
data_i=data_p.sum(axis=1) #行边缘概率
#概率矩阵标准化
tmp=np.dot(data_i.values.reshape(-1,1),data_j.values.reshape(1,-1))
data_z=(data_p-tmp)/np.sqrt(tmp)
data_z=pd.DataFrame(data_z,index=data.index,columns=data.columns)
#3 求解奇异值和惯量,确定公共因子数量
data_z_np=data_z.to_numpy()
S_R=np.dot(data_z_np.T,data_z_np)
eig_val_R,eig_fea_R=np.linalg.eig(S_R) #返回特征值和特征向量
#注意eig_val_R没有排序,并且只去eig_val_R中大于0的特征值
#返回维度惯量 惯量其实就是特征值
dim_matrix=pd.DataFrame(sorted([i for i in eig_val_R if i>0],reverse=True),columns=['惯量'])
dim_matrix['奇异值']=np.sqrt(dim_matrix['惯量'])
dim_matrix['对应部分']=dim_matrix['惯量']/dim_matrix['惯量'].sum()
dim_matrix['累计']=dim_matrix['对应部分'].cumsum()
#R型因子载荷矩阵
#由dim_matrix['累计']可以得出,我们选择3个公共因子
com_fea_index=[x[0] for x in sorted(enumerate(eig_val_R),reverse=True,key=lambda x:x[1])][:3]
cols=['c'+str(i+1) for i in range(len(com_fea_index))]
eig_fea_R=np.multiply(eig_fea_R[:,com_fea_index],np.sqrt(eig_val_R[com_fea_index]))
R_matrix=pd.DataFrame(eig_fea_R,index=data_j.index,columns=cols)
R_matrix['tmp']=np.sqrt(data_j)
for col in cols:
R_matrix[col]=R_matrix[col]/R_matrix['tmp']
R_matrix.drop('tmp',axis=1,inplace=True)
#Q型因子载荷矩阵
S_Q=np.dot(data_z_np,data_z_np.T)
eig_val_Q,eig_fea_Q=np.linalg.eig(S_Q)
com_fea_index=[x[0] for x in sorted(enumerate(eig_val_Q),reverse=True,key=lambda x:x[1])][:3]
cols=['c'+str(i+1) for i in range(len(com_fea_index))]
eig_fea_Q=np.multiply(eig_fea_Q[:,com_fea_index],np.sqrt(eig_val_Q[com_fea_index]))
Q_matrix=pd.DataFrame(eig_fea_Q,index=data_i.index,columns=cols)
Q_matrix=Q_matrix.astype(float,copy=False) #Q_matrix中的数据类型为复数类型,但是虚部都为0,所以这里转化成float
Q_matrix['tmp']=np.sqrt(data_i)
for col in cols:
Q_matrix[col]=Q_matrix[col]/Q_matrix['tmp']
Q_matrix.drop('tmp',axis=1,inplace=True)
#4 选取公共因子c0和c1画定位图
plot_data=pd.concat([Q_matrix[['c1','c2']],R_matrix[['c1','c2']]],axis=0)
plot_data.index=list(data_i.index)+list(data_j.index)
plot_data['style']=['地区']*data_i.shape[0]+['指标']*data_j.shape[0]
#画图
plt.rcParams["font.family"] = 'Arial Unicode MS'
marks={'地区':'o','指标':'s'}
ax=sns.scatterplot(x='c2',y='c1',hue='style',style='style',markers=marks,data=plot_data)
ax.set_xlim(left=-1,right=1)
ax.set_ylim(bottom=-1,top=1)
ax.set_xticks([-1,-0.5,0,0.5,1])
ax.set_yticks([-1,-0.5,0,0.5,1])
ax.axhline(0,color='k',lw=0.5)
ax.axvline(0,color='k',lw=0.5)
for idx in plot_data.index:
ax.text(plot_data.loc[idx,'c2']+0.005,plot_data.loc[idx,'c1']+0.005,idx)
plt.show()
最后的结果和论文中的结果有些差别,需要对此进行说明:
- 原始数据中有一些缺失值,我在原始数据中用0进行了填充。
- 计算出来的R型因子载荷矩阵和Q型因子载荷矩阵和论文中展示出的结果可能符号相反,误差在百分位上。
参考资料
- 百度百科: 对应分析
- 基于对应分析法的省级政府门户网站评价研究
- MATLAB对应分析
- Pearson and Log-likelihood Chi-square Test of Fit for Latent Class Analysis Estimated with Complex Samples