import numpy as np
import pandas as pd
class TOPSIS:
'''
TOPSIS法(Technique for Order Preference by Similarity to Ideal Solution)
可翻译为逼近理想解排序法,国内常简称为优劣解距离法
TOPSIS 法是一种常用的综合评价方法,其能充分利用原始数据的信息,其结果能精确地反映各评价方案之间的差距。
为了对众多方案给出一个排序,在给出所有方案之后,可以根据这些数据,构造出一个所有方案组成的系统中的理想最优解和最劣解。
而TOPSIS的想法就是,通过一定的计算,评估方案系统中任何一个方案距离理想最优解和最劣解的综合距离。
如果一个方案离正理想解越近,离负理想解越远,我们就认为这个方案更好。那理想最优解和最劣解又是什么呢?
很简单,理想最优解就是该理想最优方案的各指标值都取到系统中评价指标的最优值,
最劣解就是该理想最劣方案的各指标值都取到系统中评价指标的最劣值。
Parameters
----------
kind : 决策矩阵去量纲化方法,取值:{1,2,3},默认值是1
kind=1,归一化
kind=2,标准化
kind=3,规范化
'''
def __init__(self,kind=1):
'''
初始化方法
'''
self.kind=kind
def positive_processing(self,data,feture_type=1):
'''
指标正向化,TOPSIS法使用距离尺度来度量样本差距,使用距离尺度就需要对指标属性进行同向化处理,
若一个维度的数据越大越好,另一个维度的数据越小越好,会造成尺度混乱。
Parameters
----------
data : TYPE nparray
DESCRIPTION. 导入需要正向化的数组
method : TYPE, optional
DESCRIPTION. 默认值是method=1(极小转极大);若method=2(中间转极大);若method为其他值(区间转极大)
Returns
-------
data : TYPE nparray
DESCRIPTION. 经过正向化之后的数组
'''
if feture_type==1:
data=data.max(axis=0)-data
elif feture_type==2:
x_best = float(input("请输入最佳值: "))
M=abs(data-x_best).max(axis=0)
data=1-abs(x_best-data)/M
else:
x_min=float(input("左区间值"))
x_max=float(input("右区间值"))
M=max(x_min-data.min(axis=0),data.max(axis=0)-x_max)
data = 1 - np.where(data < x_min, (x_min - data) / M,
np.where(data <= x_max, 0, (data - x_max) / M))
return data
def dimensionless_processing(self,data):
'''
无量纲化矩阵,排除量纲对评价结果产生的影响
Parameters
----------
data : TYPE nparray
DESCRIPTION. 导入的已经正向化后的数组
method : TYPE, optional
DESCRIPTION. 默认值是method=0,则采用归一化方法;若method=1,则采用标准化方法;若method为其他值,则采用规范化方法
Returns
-------
data : TYPE nparray
DESCRIPTION. 经过无量纲化之后的数组
'''
if self.kind==0:
#归一化
data=(data-data.min(axis=0))/(data.max(axis=0)-data.min(axis=0))
elif self.kind==1:
#标准化
data=(data-data.mean(axis=0))/data.std(axis=0)
else:
#规范化
data=data/np.linalg.norm(data,axis=0)
return data
def fit(self,data,weight=1):
'''
通过检测评价对象与最优解、最劣解的距离来进行排序;若评价对象最靠近最优解同时又最远离最劣解,则为最好;
否则不为最优。其中最优解的各指标值都达到各评价指标的最优值。最劣解的各指标值都达到各评价指标的最差值。
方案排序的规则是把各备选方案与理想解和负理想解做比较,若其中有一个方案最接近理想解,而同时又远离负理想解,
则该方案是备选方案中最好的方案。
Parameters
----------
data : TYPE nparray
DESCRIPTION. 导入原始数据组成的数组
method : TYPE, optional
DESCRIPTION. 默认值method=0
Returns
-------
C : TYPE nparray
DESCRIPTION. 评价对象与最优方案的接近程度
'''
answer=int(input("是否需要在正向化处理,需要请属于1,不需要请输入0: "))
if answer==1:
columns=list(input("需要正向化的列,如 [1,2,3]表示需要正向化的是第1-3列: "))
columns_temp=[]
#去除列表columns中的‘,’
for i in range(len(columns)):
if i%2!=0:
columns_temp.append(int(columns[i])-1)
types=input("需要正向化的列的类型是什么?1:极小转极大,2:中间转极大,3:区间转极大,\
如[1,2,3]表示需要正向化的列分别是极小转极大、中间转极大和区间转极大:")
types_temp=[]
#去除列表types中的‘[],’
for i in range(len(types)):
if i%2!=0:
types_temp.append(int(types[i]))
for i in range(len(columns_temp)):
if types_temp[i]==1:
data[:,columns_temp[i]]=self.positive_processing(data[:,columns_temp[i]],1)
elif types_temp[i]==2:
data[:,columns_temp[i]]=self.positive_processing(data[:,columns_temp[i]],2)
else:
data[:,columns_temp[i]]=self.positive_processing(data[:,columns_temp[i]],3)
data=self.dimensionless_processing(data)
data=data*weight
#最优方案
pos_ideal_solution=data.max(axis=0)
#最劣方案
neg_ideal_solution=data.min(axis=0)
#评价对象与最优方案的距离
D_plus=((pos_ideal_solution-data)**2).sum(axis=1)
#评价对象与最劣方案的距离
D_minus=((neg_ideal_solution-data)**2).sum(axis=1)
#评价对象与最优方案的接近程度
C=D_minus/(D_plus+D_minus)
return C
class WEIGH:
'''
Parameters
----------
weight_type : TYPE, optional
DESCRIPTION. The default is 'equal'.
权重的类型:{'critic','entropy','equal'},默认值是'equal'
weight_type='critic',critic权重
weight_type='entropy',熵权
weight_type='equal',等权
kind : TYPE, optional
DESCRIPTION. The default is 1.
kind : 权重计算时,去量纲化方法,取值:{1,2,3},默认值是1
kind=1,归一化
kind=2,标准化
kind=3,规范化
Returns
-------
None.
'''
def __init__(self,weight_type='equal',kind=1):
self.weight_type=weight_type
self.kind=kind
def critic_weight(self,data):
'''
CRITIC 权重法是一种客观赋权法。其思想在于用两项指标,分别是对比强度和冲突性指标。
对比强度使用标准差进行表示,如果数据标准差越大说明波动越大,权重会越高;冲突性使
用相关系数进行表示,如果指标之间的相关系数值越大,说明冲突性越小,那么其权重也就
越低。对于多指标多对象的综合评价问题,CRITIC 法去消除一些相关性较强的指标的影响,
减少指标之间信息上的重叠,更有利于得到可信的评价结果。
Parameters
----------
data : TYPE nparray
DESCRIPTION. 导入的由原始数据构成的数组
Returns
-------
W : TYPE nparray
DESCRIPTION. 经过crittc权重法计算出的每个指标的权重
'''
if type(data)!=np.ndarray:
X=np.array(pd.DataFrame(data))
else:
X=data
if self.kind==1:
#归一化
Y=(X-X.min(axis=0))/(X.max(axis=0)-X.min(axis=0))
elif self.kind==2:
#标准化
Y=(X-X.mean(axis=0))/X.std(axis=0)
else:
#规范化
Y=X/np.linalg.norm(X,axis=0)
#计算标准差
data_std=np.std(Y,axis=0)
#计算相关系数
data_corr=abs(np.corrcoef(Y.T))
#信息量
C=data_std*np.sum(1-data_corr,axis=0)
#权重
W=C/(np.sum(C)+1e-9)
return W
def entropy_weight(self,data):
'''
熵权法中信息熵是度量信息量的不确定性和随机性的指标,可以用来评估指标的重要性,
熵权法是根据指标变异性大小来确定客观权重,若指标的信息熵越小,表明该指标的变异程度越大,
该指标提供的信息量就越大,在综合评价中起的作用越大,权重应该越高
Parameters
----------
data : TYPE nparray
DESCRIPTION. 导入的由原始数据构成的数组
Returns
-------
W : TYPE nparray
DESCRIPTION. 经过熵权法计算出的每个指标的权重
'''
if type(data)!=np.ndarray:
X=np.array(pd.DataFrame(data))
else:
X=data
Y=(X-X.min(axis=0))/(X.max(axis=0)-X.min(axis=0))
n=Y.shape[0]
#各指标在各方案下的比值
p=Y/Y.sum(axis=0)
#消除ln0影响
p=p+1e-6
#各指标的信息熵
e=(-1/np.log(n))*((p*np.log(p)).sum(axis=0))
#各项指标的差异系数
d=1-e
#计算权重
W=d/d.sum(axis=0)
return W
def fit(self,data):
'''
定义一个计算权重时该采用什么方法的函数
Parameters
----------
data : TYPE nparray
DESCRIPTION. 先根据weight_type的初始值判断该用什么方法计算权重,再用相应的方法计算每个指标的权重
Returns
-------
weight : TYPE nparray
DESCRIPTION. 计算出的每个指标的权重
'''
if self.weight_type=='critic':
weight=self.critic_weight(data)
elif self.weight_type=='entropy':
weight=self.entropy_weight(data)
else:
weight=1
return weight
import numpy as np
import pandas as pd
from marcos import TOPSIS,WEIGH
if __name__=="__main__":
#实例化一个对象
data={'A1':[9,2,3],'A2':[2,3,4],'A3':[3,6,5],'A4':[4,5,6],
'A5':[-2,9,13]}
df=pd.DataFrame(data)
data=np.array(df).astype('float64')
clf1=WEIGH(weight_type='critic')
w=clf1.fit(data)
clf2=TOPSIS(kind=2)
C=clf2.fit(data,weight=w)