1.灰色关联分析

灰色关联分析是一种多因素统计分析方法。它对样本量的多少和样本有无规律都同样适用,计算量小,十分方便,不会出现量化结果与定性分析结果不符的情况。

2.模型原理

灰色关联分析基本思想是根据序列曲线几何形状的相似程度来判断其联系是否紧密。曲线越接近,相应序列之间的关联度就越大,反之就越小。

对一个抽象的系统或现象进行分析,首先要选准反映系统行为特征的数据序列,即找系统行为的映射量,用映射量来间接表征系统行为。

例如:用国名平均接受教育的年数来反映教育发达程度;用刑事案件的发案率来反映社会治安面貌和社会秩序;用医院挂号次数来反映国民的健康水平等。

3.关联分析步骤(结合例题好理解一些)

1)母序列(参考序列) 
能反映系统行为特征的数据序列,类似于因变量 Y ,记为 eq?Y%3D%5By_1%2Cy_2%2C...%2Cy_n%5D%5ET

2)子序列(比较序列)
影响系统行为的因素组成的数据序列,类似于自变量 X ,记为
 eq?X_%7Bnm%7D%3D%5Cbegin%7Bbmatrix%7D%20x_%7B11%7D%20%26x_%7B12%7D%20%26...%26x_%7B1m%7D%20%5C%5C%20x_%7B21%7D%20%26x_%7B22%7D%20%26...%26x_%7B2m%7D%20%5C%5C%20.%26.%26...%26.%5C%5C.%26.%26...%26.%5C%5C.%20%26.%20%26...%26.%5C%5C%20x_%7Bn1%7D%20%26x_%7Bn2%7D%26...%26x_%7Bnm%7D%20%5Cend%7Bbmatrix%7D

3)数据预处理
由于不同要素具有不同量纲和数据范围,因此要进行预处理去量纲,将他们统一到近似的范围内,先求出每个指标的均值,再用指标中的元素除以其均值。

4)计算灰色关联系数
通过计算两级最小差和最大差得到子序列中各个指标与母序列的关联系数。
记两级最小差为 a ,则 eq?a%3D%5Cunderset%7Bi%7D%7Bmin%7D%5C%20%5Cunderset%7Bk%7D%7Bmin%7D%5Cleft%20%7C%20x_0%28k%29%20-x_i%28k%29%5Cright%20%7C
记两级最大差为 b,则 eq?b%3D%5Cunderset%7Bi%7D%7Bmax%7D%5C%20%5Cunderset%7Bk%7D%7Bmax%7D%5Cleft%20%7C%20x_0%28k%29%20-x_i%28k%29%5Cright%20%7C
构造关联系数 eq?%5Cxi%20_i%28k%29 :则 eq?%5Cxi%20_i%28k%29%3Dy%28x_0%28k%29%2Cx_i%28k%29%29%3D%5Cfrac%7Ba+%5Crho%20b%7D%7B%7Cx_0%28k%29-x_i%28k%29%7C+%5Crho%20b%7D,其中 eq?%5Crho 为分辨系数,一般取0.5 。

5)计算关联度
关联度=关联系数的均值,即 eq?r_i%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bk%3D1%7D%5E%7Bn%7D%5Cxi%20_i%28k%29

4.例题讲解及代码实现

4.1 灰色关联分析

题目:已知某地国民生产总值,工业和农业生产总值,原始数据的形式见下表,分析工业农业哪个对国民生产总值影响大。

项目名称年份
2016201720182019
国民生产总值556575100
工业产值24384050
农业产值10221820

解答:
1)定义母序列及子序列如下:

项目名称年份项目代号
2016201720182019 
国民生产总值556575100eq?X_0(母序列)
工业产值24384050eq?X_1(子序列)
农业产值10221820eq?X_2(子序列)
2)数据预处理:
对序列进行均值化(如 eq?%5Cfrac%7B55%7D%7B55+65+75+100%7D%3D0.75),可得下表:
项目名称年份项目代号
2016201720182019 
国民生产总值0.750.881.021.36eq?X_0(母序列)
工业产值0.631.001.051.32eq?X_1(子序列)
农业产值0.571.261.031.14eq?X_2(子序列)
3)求关联系数:

两级最小差:eq?a%3D%5Cunderset%7Bi%7D%7Bmin%7D%5C%20%5Cunderset%7Bk%7D%7Bmin%7D%5Cleft%20%7C%20x_0%28k%29%20-x_i%28k%29%5Cright%20%7C

两级最大差:eq?b%3D%5Cunderset%7Bi%7D%7Bmax%7D%5C%20%5Cunderset%7Bk%7D%7Bmax%7D%5Cleft%20%7C%20x_0%28k%29%20-x_i%28k%29%5Cright%20%7C

关联系数:eq?%5Cxi%20_i%28k%29%3Dy%28x_0%28k%29%2Cx_i%28k%29%29%3D%5Cfrac%7Ba+%5Crho%20b%7D%7B%7Cx_0%28k%29-x_i%28k%29%7C+%5Crho%20b%7D
eq?keq?X_0eq?X_1eq?X_2eq?%5Cleft%20%7C%20x_0%28k%29%20-x_1%28k%29%5Cright%20%7Ceq?%5Cleft%20%7C%20x_0%28k%29%20-x_2%28k%29%5Cright%20%7C
10.750.630.570.120.18
20.8811.260.120.38
31.021.051.030.030.01
41.361.321.140.040.22

因为0.01<0.03,所以两级最小差a=0.01;又0.38>0.12,所以两级最大差b=0.38,将这两值代入关联系数公式可得下表:

eq?keq?%5Cleft%20%7C%20x_0%28k%29%20-x_1%28k%29%5Cright%20%7Ceq?%5Cleft%20%7C%20x_0%28k%29%20-x_2%28k%29%5Cright%20%7Ceq?%5Cxi%20_1eq?%5Cxi%20_2
10.120.180.6450.541
20.120.380.6450.351
30.030.010.9091.000
40.040.220.8700.488

4)求关联度:

关联度=关联系数的均值,即 eq?r_i%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bk%3D1%7D%5E%7Bn%7D%5Cxi%20_i%28k%29
eq?keq?%5Cxi%20_1eq?%5Cxi%20_2
10.6450.541
20.6450.351
30.9091.000
40.8700.488
r0.7670.595
因为 eq?r_1%3Er_2 ,所以工业产值关联度更大。

代码实现:

import numpy as np

# 输入初始矩阵[[55,24,10],[65,38,22],[75,40,18],[100,50,20]]
A=np.array(eval(input('请输入初始矩阵=')))

# 求出每一列的均值以供后续的数据预处理
Mean=np.mean(A,axis=0)

# 预处理后的矩阵
A_norm=A/Mean

print('预处理后的矩阵为:')
print(A_norm)

# 母序列
Y=A_norm[:,0]

# 子序列
X=A_norm[:,1:]

# 计算|X0-Xi|矩阵(这里我们把X0定义为了Y) 母序列与子序列对应差值的一个绝对值
absX0_Xi=np.abs(X-np.tile(Y.reshape(-1,1),(1,X.shape[1])))

# 计算两级最小差a
a=np.min(absX0_Xi)

# 计算两级最大差b
b=np.max(absX0_Xi)

# 分辨系数取0.5
rho=0.5

# 计算子序列中各个指标与母序列的关联系数
gamma=(a+rho*b)/(absX0_Xi+rho*b)

print('子序列中各个指标的灰色关联度分别为:')
print(np.mean(gamma,axis=0))

输出结果如下:
9fbe57e324c545faac89571e9c1a19ab.png
 

4.2 灰色关联评价

例:给 X 选结婚对象,现有A、B、C三位相亲对象(X觉得身高165是最好,体重在90-100斤是最好)。

候选人颜值脾气(争吵次数)身高体重
A910175120
B8716480
C6315790

解答:
1)数据正向化处理(可参考TOPSIS法):

将原始矩阵正向化,即将所有指标类型统一转化为极大型指标。下表是数据正向化后的表:

候选人颜值脾气(争吵次数)身高体重
A9000
B830.90.5
C670.21
2)正向化后数据预处理:
即将每个指标的元素除以该指标元素的平均值,如 3%7D%3D1.17,预处理后的表为:
候选人颜值脾气(争吵次数)身高体重
A1.170.000.000.00
B1.040.902.451.00
C0.782.100.552.00
3)构造母序列和子序列:
在灰色关联分析中,有明确的母序列的,但在评价决策类问题中,往往没有这么明显的因变量,所以这时我们要构造出一个母序列,即将每个对象所有指标中的最大值作为母序列。
eq?Y%3D%5By_1%2Cy_2%2C...%2Cy_n%5D%5ET,其中 eq?y_i%3Dmax%28z_%7Bi1%7D%2Cz_%7Bi2%7D%2C...%2Cz_%7Bim%7D%29,所以构造出母序列和子序列后的表如下:
候选人eq?Yeq?Z_1eq?Z_2eq?Z_3eq?Z_4
A1.171.170.000.000.00
B2.451.040.902.451.00
C2.100.782.100.552.00
4)计算关联系数:

两级最小差:eq?a%3D%5Cunderset%7Bi%7D%7Bmin%7D%5C%20%5Cunderset%7Bk%7D%7Bmin%7D%5Cleft%20%7C%20x_0%28k%29%20-x_i%28k%29%5Cright%20%7C

两级最大差:eq?b%3D%5Cunderset%7Bi%7D%7Bmax%7D%5C%20%5Cunderset%7Bk%7D%7Bmax%7D%5Cleft%20%7C%20x_0%28k%29%20-x_i%28k%29%5Cright%20%7C

关联系数:eq?%5Cxi%20_i%28k%29%3Dy%28x_0%28k%29%2Cx_i%28k%29%29%3D%5Cfrac%7Ba&plus;%5Crho%20b%7D%7B%7Cx_0%28k%29-x_i%28k%29%7C&plus;%5Crho%20b%7D
候选人eq?Yeq?Z_1eq?Z_2eq?Z_3eq?Z_4eq?%7Cz_%7Bk1%7D-y_k%7Ceq?%7Cz_%7Bk2%7D-y_k%7Ceq?%7Cz_%7Bk3%7D-y_k%7Ceq?%7Cz_%7Bk4%7D-y_k%7C
A1.171.170.000.000.000.001.171.171.17
B2.451.040.902.451.001.411.550.001.45
C2.100.782.100.552.001.320.001.550.10
易得 a=0,b=1.55,然后得出关联系数表为:
候选人eq?%7Cz_%7Bk1%7D-y_k%7Ceq?%7Cz_%7Bk2%7D-y_k%7Ceq?%7Cz_%7Bk3%7D-y_k%7Ceq?%7Cz_%7Bk4%7D-y_k%7Ceq?%5Cxi%20_1eq?%5Cxi%20_2eq?%5Cxi%20_3eq?%5Cxi%20_4
A0.001.171.171.171.0000.3980.3980.398
B1.411.550.001.450.3550.3331.0000.348
C1.320.001.550.100.3700.3700.3330.886
5)计算关联度:

关联度=关联系数的均值,即 eq?r_i%3D%5Cfrac%7B1%7D%7Bn%7D%5Csum_%7Bk%3D1%7D%5E%7Bn%7D%5Cxi%20_i%28k%29
候选人eq?%5Cxi%20_1eq?%5Cxi%20_2eq?%5Cxi%20_3eq?%5Cxi%20_4
A1.0000.3980.3980.398
B0.3550.3331.0000.348
C0.3700.3700.3330.886
r0.5750.5770.5770.544
6)计算指标权重:

权重:eq?w_i%3D%5Cfrac%7Br_i%7D%7B%5Csum_%7Bk%3D1%7D%5E%7Bm%7Dr_k%7D%5C%20%28i%3D1%2C2%2C...%2Cm%29,所以各因素权重为:
 颜值脾气争吵次数身高体重
r0.5750.5770.5770.544
w0.2530.2540.2540.239
7)计算得分并归一化:

eq?S_i%3D%5Csum_%7Bk%3D1%7D%5E%7Bm%7DZ_%7Bik%7D%5Ccdot%20w_i%5C%20%2C%5C%20%5Cwidetilde%7BS_i%7D%3D%5Cfrac%7BS_i%7D%7B%5Csum_%7Bk%3D1%7D%5E%7Bm%7DS_k%20%7D%5C%20%28i%3D1%2C2%2C...%2Cn%29
候选人颜值脾气(争吵次数)身高体重得分归一化得分
A1.170.000.000.000.2960.099
B1.040.902.451.001.3530.451
C0.782.100.552.001.3480.450
可知,相亲对象 B 的归一化得分最高,在 X 心里她的综合评分最优秀,最适合作为结婚对象。

代码如下:

import numpy as np

# 从用户输入中接收参评数目和指标数目(对象和指标),并将输入的字符串转换为数值
print("请输入参评数目:")
n=int(input()) # 接收参评数目
print("请输入指标数目:")
m=int(input()) # 接收指标数目

# 接收用户输入的类型矩阵,该矩阵指示了每个指标的类型(极大型、极小型等)
print("请输入类型矩阵:1.极大型,2.极小型,3.中间型,4.区间型")
kind=input().split(" ") # 将输入的字符串按空格分割,形成列表

# 接收用户输入的矩阵并转换为numpy数组
print("请输入矩阵:")
A=np.zeros(shape=(n,m)) # 初始化一个n行m列的全零矩阵A
for i in range(n):
    A[i]=input().split(" ") # 接收每行输入的数据
    A[i]=list(map(float,A[i])) # 将接收到的字符串列表转换为浮点数列表
print("输入矩阵为:\n{}".format(A))

# 自定义函数
# 2.极小型指标转换为极大型指标的函数
def minTomax(maxx,x): # (极小型指标的最大值,数据)
    x=list(x) # 将输入的指标数据转换为列表
    ans=[[(maxx-e)] for e in x] # 计算最大值与每个指标的差,并将其放入新列表中
    return np.array(ans) # 将列表转换为numpy数组并返回

# 3.中间型指标转换为极大型指标的函数
def midTomax(bestx,x): # (中间型指标的最佳值,数据)
    x=list(x) # 将输入的指标数据转换为列表
    h=[abs(e-bestx) for e in x] # 计算每个指标值与最优值之间的绝对差
    M=max(h) # 找到最大的差值
    if M==0:
        M=1 # 防止最大差值为0的情况
    ans=[[(1-e/M)] for e in h] # 计算每个差值占最大差值的比例,并从1中减去,得到新指标值
    return np.array(ans) # 返回处理后的numpy数组

# 4.区间型指标转换为极大型指标的函数
def regTomax(lowx,highx,x):
    x=list(x) # 将输入的指标数据转换为列表
    M=max(lowx-min(x),max(x)-highx) # 计算指标值超出区间的最大距离
    if M==0:
        M=1 # 防止最大距离为0的情况
    ans=[]
    for i in range(len(x)):
        if x[i]<lowx:
            ans.append([(1-(lowx-x[i])/M)]) # 如果指标值小于下限,则计算其与下限的距离比例
        elif x[i]>highx:
            ans.append([(1-(x[i]-highx)/M)]) # 如果指标值大于上限,则计算其与上限的距离比例
        else:
            ans.append([1]) # 如果指标值在区间内,则直接取为1
    return np.array(ans) # 返回处理后的numpy数组

# 统一指标类型,将所有指标转换为极大型指标
X=np.zeros(shape=(n,1))
for i in range(m):
    if kind[i]=='1':
        v=np.array(A[:,i]) # 如果当前指标为极大型,则直接使用原值
    elif kind[i]=='2':
        maxA=max(A[:,i])
        v = minTomax(maxA,A[:,i]) # 如果当前指标为极小型,调用minTomax函数转换
    elif kind[i]=='3':
        print("类型三,请输入最优值:")
        bestA=eval(input()) # eval:包含int和float两种形式
        v=midTomax(bestA,A[:,i]) # 如果当前指标为中间型,调用midTomax函数转换
    elif kind[i]=='4':
        print("类型四,请输入区间[a,b]值a:")
        lowA=eval(input())
        print("类型四,请输入区间[a,b]值b:")
        highA=eval(input())
        v=regTomax(lowA,highA,A[:,i]) # 如果当前指标为区间型,调用regTomax函数转换
    
    if i==0:
        # 当一个数字为-1时,表示自动识别所需的行数,列数为第二个值
        X=v.reshape(-1,1) # 把正向化后的第一列直接赋值给X,即把数组转换成列向量
    else:
        # np.hstack:用于在水平方向(沿着列)将多个数组堆叠在一起
        X=np.hstack([X,v.reshape(-1,1)]) # 如果不是第一个指标则将新指标列拼接到X数组上
print("统一指标后矩阵为:\n{}".format(X)) # 打印处理后的矩阵

# 对正向化后的矩阵进行预处理
Mean=np.mean(X,axis=0)
Z=X/Mean

print('预处理后的矩阵为:')
print(Z)

# 构造母序列和子序列
Y=np.max(Z,axis=1) # 母序列为虚构的,用每一行的最大值构成的列向量表示母序列
X=Z # 子序列就是预处理后的数据矩阵

# 计算得分
absX0_Xi=np.abs(X-np.tile(Y.reshape(-1,1),(1,X.shape[1]))) # 母序列与子序列对应差值的绝对值
a=np.min(absX0_Xi) # 计算两级最小差a
b=np.max(absX0_Xi) # 计算两级最大差b
rho=0.5 # 分辨系数取0.5
gamma=(a+rho*b)/(absX0_Xi+rho*b) # 计算子序列中各个指标与母序列的关联系数
weight=np.mean(gamma,axis=0)/np.sum(np.mean(gamma,axis=0)) # 利用子序列中各个指标的灰色关联度计算权重
score=np.sum(X*np.tile(weight,(X.shape[0],1)),axis=1) # 未归一化的得分
stand_S=score/np.sum(score) # 归一化后的得分
sorted_S=np.sort(stand_S)[::-1] # 进行降序排序
index=np.argsort(stand_S)[::-1] # 排序后的索引

print('归一化后的得分及其索引(降序):')
print(sorted_S,index)

输出结果如下:
7f12aae0bc81486b86d3428104bf65cc.png

 

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐