引子
在数学建模比赛和数据分析中,综合评价模型的出场率还是比较高的,实际应用也确实比较广泛。下面是我在学习过程中对综合评价模型的总结。
综合评价无外乎两种:对多个系统进行评价和对一个系统进行评价。对多个系统进行评价的目的基本上有两种:这东西是谁的——分类;哪个好哪个差——比较、排序。对一个系统进行评价的目的基本上就是看它达没达标、及不及格——实现程度。对一个系统的精确评价往往对它进行进一步的预测起着决定性的参考作用。因为如果我们需要对某一系统进行预测的话一个良好的评价系统也非常关键。
评价模型综述
这部分主要讲常见的评价模型,再具体而言就是确定评价标准的评价模型。
这类模型其实很多,但是万变不离其宗,一篇综述便可以完全搞定,不像优化模型、机理模型那样,分门别类那么多。基本上,看这一篇综述,在了解了各个方法的大体思想之后,根据题目的特点、要求以及模型的特点去选择合适的模型即可。
首先需要谈及的一个概念是,数据的内生性和外生性,这个是各个评价模型最本质的出发点。
内生性是指,模型的评价标准的确定,完全依赖于各个方案的指标数据本身。比如熵权法,数据的权重完完全全依赖于各个指标下数据的信息熵的大小,信息熵由数据本身决定,与其他因素无关。
外生性是指,模型的评价标准的确定,完全依赖于外部因素对各个方案指标数据的评判。比如层次分析法,数据的权重完全依赖于指标的重要性比较,与指标下的数据一点关系也没有。这里所谓的外部因素,包括重要性、首要度、依赖关系等等。
然后,接下来是关于主要评价模型的类别。个人感觉,大体上可以分为权重型和排序型两种。接下来就是详细的介绍。
当然在介绍开始之前,我们同样需要优先考虑数据的预处理过程
综合指标的预处理方法
目的:消除不同指标间有关类型、单位、数量级等的差异,避免出现不合理的评价结果,对指标进行一致化处理、无量纲化处理,在一般情况下我们要求某项数据越大越好,因此对于一些极小型和区间型数据需要做一些额外的处理
Step1:一致化处理
极小型转最大型:取倒转化、平移转化(用该列数据的最大值减去数据本身)
中间型转极大型:例如下面转化
区间型转极大型:例如如下转化
Step2:指标无量纲处理
将指标实际值转化为指标评价值
标准样本变换:不再赘述。注意:这个变换处理会出现负值,将不能直接用于后续的熵权法/几何加权法
比例样本变换:变换签后属性值成比例,对于极大型数据可以除以某一列的最大值,对于极小型数据可以用1-上述变换方法
向量归一化:数据列本身除以全部数据的二范数
极差变换:
功效系数法:
补充一下定性指标的定量化标准:
综合评价模型介绍
一、权重型评价模型
这类模型的目标呢,就是通过一套模型,得到一套权重标准。至于什么是权重,跳转开头传送门【评价模型的本质】。具体而言,这套权重标准的本质就是:
权重的本质就是, 确定一套向量(标准),使得方案-指标关系的线性加权组合能够反应方案的本质特征,以实现合理的评价。求得权重的方法,无论是层次分析法,还是熵权法,本质上并无不同,都是对方案-指标关系的线性加权组合,只不过方法、原理的差异。 ——数学建模杂谈(1)
前面也说了,根据数据的内生性和外生性,评价模型也会有不同的特点。权重型评价模型也不例外,接下来就是对其的综述。
1. 层次分析法(AHP)
能不用就不用
老生常谈的模型了,一个外生性的模型。层次分析法就是将一个决策事件分解为目标层(例如选择旅游地),准则层(影响决策的因素,例如景色、交通、费用等)以及方案层(指的是方案,例如去广州、桂林等地旅游),这个模型的本质,就是通过主观打分确定权重。
层次分析法应用过程中,大体步骤主要包括四个。第一步是层次结构模型的构建。第二步构造判断矩阵,第三步为层次单排序及其一致性检验,这步即为对指标定权,第四步为层次总排序及其一致性检验,这布如果没有决策层的话,通常可以省略。
事实上而言,由于模型主观因素过强,会导致说服力不够、结果容易遭到质疑,因此在近些年的竞赛中更多的被规避,很多老的数学建模教师谈AHP就色变。但为啥还要说这个方法呢,因为AHP提供了一套防止过于主观打分拍脑袋的机制,即一致性检验,防止打分时过于拍脑袋,导致A>B,B>C,C>A这种由于拍脑袋搞出的闹剧情形,这也是这个方法没有被淘汰的原因,好用、简洁、有效避免打分失误。
PS:一致性检验的含义用于确定构建的判断矩阵是否存在逻辑问题,例如以A、B、C构建判断矩阵,若判定A相当于B为3(A比B稍微重要),A相当于C为1/3(C比A稍微重要),在判断B相当于C时,根据上述的逻辑,理应C比B重要,若我们在构建判断矩阵时,错误填写为B相当于C为3(B比C稍微重要),那么就犯了逻辑错误。
但是咱还是尽可能避免外生性的模型,后面我们也不再介绍其他外生性模型
import numpy as np #导入所需包并将其命名为np
def ConsisTest(X): #函数接收一个如上述A似的矩阵
#计算权重
#方法一:算术平均法
## 第一步:将判断矩阵按照列归一化(每个元素除以其所在列的和)
X = np.array(X) #将X转换为np.array对象
sum_X = X.sum(axis=0) #计算X每列的和
(n,n) = X.shape #X为方阵,行和列相同,所以用一个n来接收
sum_X = np.tile(sum_X,(n,1)) #将和向量重复n行组成新的矩阵
stand_X = X/sum_X #标准化X(X中每个元素除以其所在列的和)
## 第二步:将归一化矩阵每一行求和
sum_row = stand_X.sum(axis=1)
## 第三步:将相加后得到的向量中每个元素除以n即可得到权重向量
print("算数平均法求权重的结果为:")
print(sum_row/n)
#方法二:特征值法
## 第一步:找出矩阵X的最大特征值以及其对应的特征向量
V,E = np.linalg.eig(X) #V是特征值,E是特征值对应的特征向量
max_value = np.max(V) #最大特征值
#print("最大特征值是:",max_value)
max_v_index = np.argmax(V) #返回最大特征值所在位置
max_eiv = E[:,max_v_index] #最大特征值对应的特征向量
## 第二步:对求出的特征向量进行归一化处理即可得到权重
stand_eiv = max_eiv/max_eiv.sum()
print("特征值法求权重的结果为:")
print(stand_eiv)
print("———————————————————————————————")
#一致性检验
## 第一步:计算一致性指标CI
CI = (max_value-n)/(n-1)
## 第二步:查找对应的平均随机一致性指标RI
RI = np.array([15,0,0,0.52,0.89,1.12,1.26,1.36,1.41,1.46,1.49,1.52,1.54,1.56,1.58,1.59])
## 第三步:计算一致性比例CR
CR = CI/RI[n]
if CR < 0.1:
print("CR=",CR,",小于0.1,通过一致性检验")
else:
print("CR=",CR,",大于等于0.1,没有通过一致性检验,请修改判断矩阵")
return None
2. 变异系数法(CV-Weight)
按需使用
变异系数法,也叫标准离差法,内生性模型,本质是通过变异系数(说白了就是均值/标准差)来确定指标下数据的离散程度和集中程度,基本思想是计算每个指标下数据的方差Si,用Si除以各个Si的总和作为第i个指标的权重值,方差越大者权重也越大。
这种方法的优点是比较简单,也容易实现,能够有效区分各个指标。
它的缺点也是显著的——变异系数法的前提是各个指标重要性相当。指标方差越大只能说明该指标对不同方案的区分度很高,事实上并不能等同于指标的重要度。因此使用变异系数法时,对指标的选取有一定要求。
相较于熵权法而言,使用在生态化数据有奇效,也更加合理。当然,本质和熵权法没什么不同,所以也没什么人讲。好处就是,客观、正态化数据的打分效果优于熵权法。坏处就是,太客观,很可能出现与决策人主观意志不一致的结果。
import numpy as np
'''1.输入数据'''
print("请输入参评对象数目:")
n = eval(input())
print("请输入评价指标数目:")
m = eval(input())
print("请输入指标类型:1:极大型,2:极小型")
kind = input().split(" ")
print("请输入矩阵:")
X = np.zeros(shape=(n, m))
for i in range(n):
X[i] = input().split(" ")
X[i] = list(map(float, X[i]))
print("输入的矩阵为:\n{}".format(X))
'''2.正向化处理'''
def minTomax(maxx, x):
x = list(x)
ans = [[(maxx-e)] for e in x]
# ans = [list(1/e) for e in x]
return np.array(ans)
A = np.zeros(shape=(n, 1))
for i in range(m):
if kind[i] == "1":
v = np.array(X[:, i])
elif kind[i] == "2":
maxA = max(X[:, i])
v = minTomax(maxA, X[:, i])
if i == 0:
A = v.reshape(-1, 1)
else:
A = np.hstack([A, v.reshape(-1, 1)])
print("正向化矩阵为:\n{}".format(A))
'''3.标准化处理'''
A = A.astype('float')
for j in range(m):
A[:, j] = A[:, j]/np.sqrt(sum(A[:, j]**2))
print("归一化矩阵为:\n{}".format(A))
'''4.计算变异系数'''
Avg = np.average(A, axis=0) # 计算均值
Stad = np.std(A, axis=0) # 计算标准差
V = Stad/Avg # 计算变异系数
print("变异系数为:\n{}".format(V))
'''5.计算权重'''
w = V/sum(V)
print('权重为:\n{}'.format(w))
'''6.得分'''
s = np.dot(A, w)
Score = 100*s/max(s)
for i in range(len(Score)):
print(f"第{i+1}个测评对象的百分制得分为:{Score[i]}")
3. 熵权法(Entropy-Weight)
按需使用
内生性模型,本质是通过信息熵来确定指标下数据的信息增益程度,说的人话点还是数据的离散程度。相较于变异系数而言,信息熵更能够挖掘那些有趋势规律的数据,比如经济数据这种,变异系数往往没法挖掘、衡量这种的差异,本质也和变异系数没啥区别,一体两面而已。好处,客观,评委喜欢这种有数学本质道理的模型。坏处还是那三个字,太客观。
这玩意说实话也是老声常谈了,常见的就是熵权-TOPSIS法,大家看国赛论文用的最多也是这个。事实上,你也可以使用其他权重型-TOPSIS模型,因为本质没有区别
import numpy as np
def entropy_weight(x):
# 计算每个指标的熵值
m, n = x.shape
e = np.zeros((1, n))
for j in range(n):
p = x[:, j] / x[:, j].sum()
e[0][j] = - (p * np.log(p)).sum()
# 计算每个指标的权重
w = np.zeros((1, n))
for j in range(n):
w[0][j] = (1 - e[0][j]) / ((1 - e).sum())
return w
def topsis(x, w):
# 将x归一化处理
m, n = x.shape
x_norm = np.zeros((m, n))
for j in range(n):
x_norm[:, j] = x[:, j] / np.sqrt((x[:, j]**2).sum())
# 计算加权后的矩阵
x_weighted = np.zeros((m, n))
for j in range(n):
x_weighted[:, j] = w[0][j] * x_norm[:, j]
# 计算最优解和最劣解
max_vec = x_weighted.max(axis=0)
min_vec = x_weighted.min(axis=0)
# 计算每个评价对象与最优解和最劣解的距离
d_plus = np.sqrt(((x_weighted - max_vec)**2).sum(axis=1))
d_minus = np.sqrt(((x_weighted - min_vec)**2).sum(axis=1))
# 计算得分
score = d_minus / (d_minus + d_plus)
return score
# 示例数据
x = np.array([[1,2,3],[4,5,6],[7,8,9]])
# 计算熵权法得到的权重
w = entropy_weight(x)
# 计算TOPSIS得分
score = topsis(x, w)
print(score)
4. 偏相关系数法(PCC-Weight)
个人比较推荐,方法逻辑性和连贯性比较强
内生性模型,本质是通过衡量两组指标之间的偏相关关系强弱确定指标的相似性。这个方法需要首先明确自变量和因变量,衡量因变量与每个自变量的相关系数,相关系数的绝对值高,相似性强,权重低;反之,相关系数的绝对值低,相似性弱,权重高。这个方法的好处,可以和回归分析、相关分析配套使用,充分考虑指标的共线性。不好的地方,就是不是所有的问题都明确告诉你因变量是啥,因变量选的不好会使得你的模型遭到更多的质疑。
偏自相关系数的计算这里就不再赘述
5. CRITIC法
麻烦,不推荐使用
内生性模型,本质是综合考虑指标下数据的标准差(离散程度)和指标间的相关系数(相似性)组合确定权重,因此它优于变异系数法和熵权法,每个指标都有自己的标准差,也有和其他指标的相关系数总和,两者相乘再归一化便是权重。
具体而言,这种方法,适合指标之间有复杂关系的情形(比如关联、依赖、推导),比如经济数据,人均型数据和总体型数据混杂,就适合使用这种方法确定权重。这个方法的好处是,充分考虑指标的稳定性和指标间的相互关系。不好的地方呢,模型比较复杂,建模是一个崇尚简洁、简单的过程。
import numpy as np
'''
4
5
1 1 2 1 1
0.483 13.2682 0.0 4.3646 5.1070
0.4035 13.4909 39.0131 3.6151 5.5005
0.8979 25.7776 9.0513 4.8920 7.5342
0.5927 16.0245 13.2935 4.4529 6.5913
'''
'''1.输入数据'''
print("请输入参评对象数目:")
n = eval(input())
print("请输入评价指标数目:")
m = eval(input())
print("请输入指标类型:1:极大型,2:极小型")
kind = input().split(" ")
print("请输入矩阵:")
X = np.zeros(shape=(n, m))
for i in range(n):
X[i] = input().split(" ")
X[i] = list(map(float, X[i]))
print("输入的矩阵为:\n{}".format(X))
'''2.标准化处理'''
def maxTomax(maxx, minx, x):
x = list(x)
ans = [[(e-minx)]/(maxx-minx) for e in x]
return np.array(ans)
def minTomax(maxx, minx, x):
x = list(x)
ans = [[(maxx-e)]/(maxx-minx) for e in x]
return np.array(ans)
A = np.zeros(shape=(n, 1))
for i in range(m):
maxA = max(X[:, i])
minA = min(X[:, i])
if kind[i] == "1":
v = maxTomax(maxA, minA, X[:, i])
elif kind[i] == "2":
v = minTomax(maxA, minA, X[:, i])
if i == 0:
A = v.reshape(-1, 1)
else:
A = np.hstack([A, v.reshape(-1, 1)])
print("标准化矩阵为:\n{}".format(A))
'''3.计算对比强度'''
V = np.std(A, axis=0)
print("对比强度为:\n{}".format(V))
'''4.计算冲突性'''
A2 = list(map(list, zip(*A))) # 矩阵转置
r = np.corrcoef(A2) # 求皮尔逊相关系数
f = np.sum(1-r, axis=1)
print("冲突性为:\n{}".format(f))
'''5.计算信息承载量'''
C = V*f
print('信息承载量为:\n{}'.format(C))
'''6.计算权重'''
w = C/np.sum(C)
print('权重为:\n{}'.format(w))
'''7.计算得分'''
s = np.dot(A, w)
Score = 100*s/max(s)
for i in range(len(Score)):
print(f"第{i+1}个测评对象的百分制得分为:{Score[i]}")
二、排序型评价模型
这类模型的目标呢,主要是实现不同方案的优劣排序。当然,一般的权重模型也能做到这一点,权重模型得到的评分大小就代表着方案的优劣。但是,这里更加侧重于,对数据本身做变换,使得更好反映数据的内生性特点。在此基础上直接进行评价,或者和权重型模型结合进行加权评价都是可以的。这一类就是评价模型的组合,详细的将在第三部分讲。
1.TOPSIS法
用太多了
又又又是老生常谈了。这方法就是考虑最优解、最劣解的情形,衡量每个方案到最优解、最劣解的距离,将评分以方案到最优方案的距离的形式进行评估。本质上,这是一种基于最大-最小值的线性变换,简单、直接、粗暴,这是他最大的优点。当然,上面这个距离可以是加权距离,也就是和权重型模型进行组合,常见的就是熵权-TOPSIS法,大家看国赛论文用的最多也是这个。事实上,你也可以使用其他权重型模型,因为本质没有区别。
2.模糊综合评价
适合创新,虽然美赛被模糊函数创死了
这方法的本质就是,确定每个指标的模糊函数,将原方案的数据通过模糊函数映射到新的数据域中,实现有效的评价。这种方法的优点在于,可以根据问题实际需求自定义模糊函数,评价结果兼备主观性与客观性、针对性和科学性,前提是你要找到合适的模糊函数。他的缺点就是,很多时候找不到合适的模糊函数,况且你要对自己找的模糊函数能自圆其说。
关于这个方法,多说一句关于模糊函数的事情。一般情况下,适用于告诉你某些评价准则的题目,比如某个指标大于A就是最优解,或者是某个指标范围在A-B之间是最优解。这种情况下,使用模糊函数,将处于最优解范围的解评分映射到1,非最优解范围其他使用线性、二次或者其他函数进行模糊评价,十分合适。另一种情形,有文献支撑你做出这样的模糊函数,也是非常亮眼和加分的。不一定非要对所有的数据做模糊函数的变换,针对实际问题进行数据变换,是所有数学建模比赛支持和鼓励的点。
3.灰色关联分析
可以用吧
这个方法基于灰色关联度理论,他的评判标准不同于传统的评价模型,而是基于母方案评价其他方案与母方案的相似性或关联度。因此,灰色关联评判,最重要的就是确定母方案(不是最优方案),然后计算其他方案与母方案的关联度,关联度越高越好,越低越差。这个方案好处就是,提供了一种推荐近似方案的方法。坏处就是,母方案不是很好确定,母方案确定错误会让大家质疑你模型的可靠性。
以下代码选用经典的红酒数据集
# 导入可能要用到的库
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# 读取数据
wine = pd.read_excel("C:/Users/Administrate/Desktop/wine.xls",index_col=0)
wine
# 无量纲化
def dimensionlessProcessing(df_values,df_columns):
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
res = scaler.fit_transform(df_values)
return pd.DataFrame(res,columns=df_columns)
# 求第一列(影响因素)和其它所有列(影响因素)的灰色关联值
def GRA_ONE(data,m=0): # m为参考列
# 标准化
data = dimensionlessProcessing(data.values,data.columns)
# 参考数列
std = data.iloc[:,m]
# 比较数列
ce = data.copy()
n = ce.shape[0]
m = ce.shape[1]
# 与参考数列比较,相减
grap = np.zeros([n,m])
for i in range(m):
for j in range(n):
grap[j,i] = abs(ce.iloc[j,i] - std[j])
# 取出矩阵中的最大值和最小值
mmax = np.amax(grap)
mmin = np.amin(grap)
ρ = 0.5 # 灰色分辨系数
# 计算值
grap = pd.DataFrame(grap).applymap(lambda x:(mmin+ρ*mmax)/(x+ρ*mmax))
# 求均值,得到灰色关联值
RT = grap.mean(axis=0)
return pd.Series(RT)
# 调用GRA_ONE,求得所有因素之间的灰色关联值
def GRA(data):
list_columns = np.arange(data.shape[1])
df_local = pd.DataFrame(columns=list_columns)
for i in np.arange(data.shape[1]):
df_local.iloc[:,i] = GRA_ONE(data,m=i)
return df_local
data_gra = GRA(data)
data_gra
4.秩和比综合评价
麻烦,不推荐使用
这个方法并不是给出综合的评价值,而是给出一个合理的方案排序。所有的方案,基于指标的特点进行编秩,计算方案的秩和比(或者是加权秩和比,和TOPSIS一样),使用概率分布的方法进行方案的比较排序。这种方法的好处在于,根据数据的相对大小而不是绝对大小进行评价,不容易受到极端值的影响。但是,这个评价方法比较麻烦,还是那句话,模型能简单就不复杂,这也是TOPSIS用的最多,秩和比没什么数模论文使用的原因。
三、评价模型的组合
这部分谈谈常见的评价模型的组合方案。一般情况下,大多数的数学建模赛题,都要求你在实现评价的基础上对方案的优劣进行排序,给出topK的结果。因此,实行加权基础上的排序型模型,是最为合适的方案,也就是将权重型和排序型进行组合。这样一想,事实上也无外乎就是上述方案的排列组合,实质都是一样的。
但是但是,这里需要谈及一个观点,就是如何进行combine,使得你的模型和别人的完全不一样呢?组合模型,什么熵权TOPSIS的,你在用,大家都在用,都一样的。那么,还有什么创新的空间呢?
创新角度
1)第一种可以考虑的角度,就是将数据的内生性特点和外生性特点结合
也就是给出内生性、外生性两套权重,使用某种方法进行组合,作为你最终的权重。这种方法,就是典型的既要又要,当然是一种好的选择。简单的方法,加权平均,或者几何平均;难一点的方法,比如建立组合优化模型优化权重。这都是可以的,很创新。这样做的优点也很明显,就是主客观一体嘛。
2)第二种可以考虑的角度,就是多权重方案的对比,比选合适的权重。
这种方案,也是典型的既要又要,多个权重方案进行比选,选择一个最好的权重组合。但是,这充分考验建模手、论文手分析权重方案优劣性的水平,很容易遭到质疑。
3)第三种可以考虑的角度,就是类似于模糊函数的方法。
使用数据变换的方法,将原数据做映射到新的数据域中,使得数据呈现出更能够反映原先数据的特征。比如这几年国赛题,什么中心对数比变换(2023国赛C题优秀论文)、百分对数变换等等,无外乎就是让数据更加优异。这个就是更加剑走偏锋、考验队伍真实水平的方法了。当然简单点,对某几个指标进行合适的模糊函数变换,这也是很优秀的方法。
一些代码还可以参考:多种综合评价方法的python实现_python如何根据权重算分数-CSDN博客