转载原文:
https://zhuanlan.zhihu.com/p/37738503
C.L.Hwang 和 K.Yoon 于1981年首次提出 TOPSIS (Technique for Order Preference by Similarity to an Ideal Solution)。TOPSIS 法是一种常用的组内综合评价方法,能充分利用原始数据的信息,其结果能精确地反映各评价方案之间的差距。基本过程为基于归一化后的原始数据矩阵,采用余弦法找出有限方案中的最优方案和最劣方案,然后分别计算各评价对象与最优方案和最劣方案间的距离,获得各评价对象与最优方案的相对接近程度,以此作为评价优劣的依据。该方法对数据分布及样本含量没有严格限制,数据计算简单易行。
通俗的例子:小明数学考试 134 分,要怎么知道他的成绩是好还是不好呢?
基于分布的评价方法会观察小明的分数位于班级分数的哪个水平(如前 5%、前 10%),但这种评价方法只能给出一个方向的情况。如班上成绩除了最高分外,其余都是 134 分,那么小明的成绩就是并列的倒数第一,但是正向评价给出的结果是前 5%。
而 TOPSIS 就是找出班上最高分(假设是 147 分)、最低分(假设是 69 分),然后计算小明的分数和这两个分数之间的差距,从而得到自己分数好坏的一个客观评价。距离最高分越近,那么评价情况越好,距离最低分越近,那么评价情况越糟。
网上大部分资料对此部分均有描述,但不少资料与文献原文存在较大偏差、排版较为混乱,并且没有深入思考原理。此部分内容转述外网文献,并加入了笔者自己的理解。
TOPSIS 法使用距离尺度来度量样本差距,使用距离尺度就需要对指标属性进行同向化处理(若一个维度的数据越大越好,另一个维度的数据越小越好,会造成尺度混乱)。通常采用成本型指标向效益型指标转化(即数值越大评价越高,事实上几乎所有的评价方法都需要进行转化),此外,如果需要使用雷达图进行展示,建议此处将所有数据都变成正数。
其中M为指标 x的可能取值的最大值, m为指标 x 的可能取值的最小值
其中 [a,b] 为指标 x的最佳稳定区间, [a*,b*] 为最大容忍区间
def dataDirection_1(datas, offset=0):
def normalization(data):
return 1 / (data + offset)
return list(map(normalization, datas))
def dataDirection_2(datas, x_min, x_max):
def normalization(data):
if data <= x_min or data >= x_max:
return 0
elif data > x_min and data < (x_min + x_max) / 2:
return 2 * (data - x_min) / (x_max - x_min)
elif data < x_max and data >= (x_min + x_max) / 2:
return 2 * (x_max - data) / (x_max - x_min)
return list(map(normalization, datas))
def dataDirection_3(datas, x_min, x_max, x_minimum, x_maximum):
def normalization(data):
if data >= x_min and data <= x_max:
return 1
elif data <= x_minimum or data >= x_maximum:
return 0
elif data > x_max and data < x_maximum:
return 1 - (data - x_max) / (x_maximum - x_max)
elif data < x_min and data > x_minimum:
return 1 - (x_min - data) / (x_min - x_minimum)
return list(map(normalization, datas))
设共有 [公式] 个待评价对象,每个对象都有 [公式] 个指标(属性),则原始数据矩阵构造为:
构造加权规范矩阵,属性进行向量规范化,即每一列元素都除以当前列向量的范数(使用余弦距离度量)
由此得到归一化处理后的标准化矩阵 Z :
最优方案Z+由 [Z中每列元素的最大值构成:
最劣方案 Z- 由 Z中每列元素的最小值构成:
其中 wj为第 j 个属性的权重(重要程度),指标权重建议根据实际确定或使用专家评估方法。在本文第 4 部分也提供了两种常用的确定权重的方法及简要分析。
使用的编程语言:python3.7.1 (Anaconda3)
使用的编辑器:Sublime Text 3
使用的模块:pandas、numpy
import pandas as pd
import numpy as np
def topsis(data, weight=None):
# 归一化
data = data / np.sqrt((data ** 2).sum())
# 最优最劣方案
Z = pd.DataFrame([data.min(), data.max()], index=['负理想解', '正理想解'])
# 距离
weight = entropyWeight(data) if weight is None else np.array(weight)
Result = data.copy()
Result['正理想解'] = np.sqrt(((data - Z.loc['正理想解']) ** 2 * weight).sum(axis=1))
Result['负理想解'] = np.sqrt(((data - Z.loc['负理想解']) ** 2 * weight).sum(axis=1))
# 综合得分指数
Result['综合得分指数'] = Result['负理想解'] / (Result['负理想解'] + Result['正理想解'])
Result['排序'] = Result.rank(ascending=False)['综合得分指数']
return Result, Z, weight
topsis 函数需要输入:
data:原始数据,pandas.DataFrame 类型
weight:权系数, 默认使用熵权法定权. 也可以传入指定权重列表. (熵权法代码见下文)
原文链接:https://blog.csdn.net/CSDN___CSDN/article/details/81042527
说明:有‘%’的地方可灵活变换数值
a=[1 2 3;4 5 6;7 8 9];%【】
c=sqrt(sum(a.*a));
for i=1:3%【[ma,na]=size(A); %ma为A矩阵的行数,na为A矩阵的列数】
for j=1:3%【】
d(i,j)=a(i,j)/c(j)%【d为规范化决策矩阵】
end
end
w=[1 2 3];%【】
for i=1:3%【】
for j=1:3%【】
c(i,j)=d(i,j)*w(j)%【c为加权矩阵】
end
end
cmax=max(c);
cmin=min(c);
for i=1:3%【】
c1=c(i,:)-cmax
s1(i)=norm(c1)
c2=c(i,:)-cmin
s2(i)=norm(c2)
T(i)=s2(i)/(s1(i)+s2(i))
end