评价算法
熵权法
上面箭头的一步用到了带权重的隔断公式。
上面是某种求权重的方法,合理就行。
但是在使用熵权法的时间,肯定要注意用的是规范化矩阵再用熵权法求权重。
规范化之前肯定要判断每一列的性子
- #熵权法:
- import xlrd
- import numpy as np
- #读数据并求熵
- path=u"D:\\LearningResource\\myLearningData\\hostital.xls"
- hn,nc=1,1
- #hn为表头行数,nc为表头列数
- sheetname=u'Sheet1'
- def readexcel(hn,nc):
- data = xlrd.open_workbook(path)
- table = data.sheet_by_name(sheetname)
- nrows = table.nrows
- data=[]
- for i in range(hn,nrows):
- data.append(table.row_values(i)[nc:])
- return np.array(data)
- def entropy(data0):
- #返回每个样本的指数
- #样本数,指标个数
- n,m=np.shape(data0)
- #一行一个样本,一列一个指标
- #下面是归一化
- maxium=np.max(data0,axis=0)
- minium=np.min(data0,axis=0)
- data= (data0-minium)*1.0/(maxium-minium)
- ##计算第j项指标,第i个样本占该指标的比重
- sumzb=np.sum(data,axis=0)
- data=data/sumzb
- #对ln0处理
- a=data*1.0
- a[np.where(data==0)]=0.0001
- # #计算每个指标的熵
- e=(-1.0/np.log(n))*np.sum(data*np.log(a),axis=0)
- print(e)
- # #计算权重
- w=(1-e)/np.sum(1-e)
- recodes=np.sum(data0*w,axis=1)
- return recodes
- data=readexcel(hn,nc)
- grades=entropy(data)
- print(grades)
复制代码
Topsis法
TOPSIS(逼近抱负解)算法原理详解与代码实现 - 知乎 (zhihu.com)
(98条消息) TOPSIS优劣解隔断法–代码部分_丰丰小白的博客-CSDN博客
*个人理解:针对存在多项指标,多个方案的方案评价分析方法,也就是根据已存在的一份数据,判断数据中各个方案的优劣。中心头脑是首先确定各项指标的最优抱负值(正抱负值)和最劣抱负值(负抱负解),所谓正抱负值是一设想的最好值(方案),它的的各个属性值都到达各候选方案中最好的值,而负抱负解是另一设想的最坏的值(方案),然后求出各个方案与正抱负值和负抱负值之间的加权欧氏隔断,由此得出各方案与最优方案的靠近程度,作为评价方案的优劣标准,最后得到各个方案的优劣值。*
一、topsis算法
1.1 TOPSIS算法的原理
TOPSIS法(Technique for Order Preference by Similarity to Ideal Solution)可翻译为逼近抱负解排序法,国内常简称为优劣解隔断法
TOPSIS 法是一种常用的综合评价方法,其能充实利用原始数据的信息,其效果能精确地反映各评价方案之间的差距。
为了对浩繁方案给出一个排序,在给出全部方案之后,可以根据这些数据,构造出一个全部方案组成的体系中的抱负最优解和最劣解。而TOPSIS的想法就是,通过肯定的盘算,评估方案体系中任何一个方案隔断抱负最优解和最劣解的综合隔断。如果一个方案隔断抱负最优解越近,隔断最劣解越远,我们就有理由以为这个方案更好。那抱负最优解和最劣解又是什么呢?很简单,抱负最优解就是该抱负最优方案的各指标值都取到体系中评价指标的最优值,最劣解就是该抱负最劣方案的各指标值都取到体系中评价指标的最劣值。
抱负最优解中的数据都是各方案中的数据,而不要选择方案中没有的数据,抱负最劣解同理。
怎样衡量某一个方案与抱负最优解和最劣解的综合隔断呢?
TOPSIS根本头脑是用下面这个表达式举行衡量:
可以发现,如果方案取到了抱负最优解,其表达式取值为1;如果方案取到了抱负最劣解,其表达式取值为0。我们便可以用这个表达式来衡量体系中某一个方案隔断抱负最优解和最劣解的综合隔断,也直接用它给方案举行打分。
当然这个公式只是一个根本的思绪,现实上,为了更准确与合理,会对该公式举行优化。
1.2 TOPSIS算法的实现
在相识TOPSIS算法的根本头脑后就是对相应参数的盘算了,从上面的形貌可以知道,除了要对该公式举行改进之外,由于涉及到数据之间的比较,还需要对方案数据举行处置处罚,消除量纲以及范围太大带来的一系列问题。
二、数据预处置处罚
2.1 数据正向化处置处罚
在处置处罚数据时,有些指标的数据越大越好,有些则是越小越好,有些又是中间某个值大概某段区间最好。我们可以对其举行“正向化处置处罚”,使指标都可以像考试分数那样,越大越好。
将指标分为四类,如下表所示。
三、TOPSIS算法实现
五、TOPSIS算法示例
5.1 TOPSIS算法示例
对一个需要根据学生智商和情商举行排名的数据:原始数据矩阵如下
对其举行正向化:
对其举行标准化:
盘算与最优解和最劣解的隔断:
注:指标权重默认是相同的,我们之前使用熵权法对权重举行肯定的处置处罚,并将权重带入举行盘算。
现实上这很可能并不具有合理性。现实上两种算法在提取信息方面都做到了同类数据相差越大越紧张。
最后盘算得分给出排名:
这个例子告诉我们,效果很紧张,但是情商更紧张。小王固然只考了60分,但也及格了,而且他从不与人辩论,所以我们可以给他一个最好的评价。
5.2 TOPSIS算法扩展
从上面盘算各自与最优解和最劣解的隔断时,我们看到,每一项指标的权重是一样的。
在现实问题中,不同的指标紧张程度可能是不一样的。例如评奖学金的时间,效果往往是最紧张的,之后还有到场活动分,志愿服务分等等,他们的权重又低一点。因此,在现实的应用中,我们也可以给指标举行赋权,将权重放到盘算隔断的公式中。
考虑权重后,不同指标对最后的影响不一样,考虑权重的评价往往是现实生活中很常见的一种评价方式。
关于权重的选取也有不同的方法,好比层次分析法(主观给出)、熵权法等等。
注意:在这个地方请注意:不可以贸然使用熵权法,例如,在奖学金评定过程中,如果同学们的效果以外的其他活动大概志愿服务分分布差异比较大,那使用熵权法就会导致这些指标的权重凌驾学习效果,这不是我们盼望看到的效果,所以这个时间采用主观赋权法:如层次分析法是更加合理的。
六、程序源码
TOPSIS.m程序
- clear all
- clc
- %% 导入数据
- % (1)在工作区右键,点击新建(Ctrl+N),输入变量名称为X
- % (2)双击进入X,输入或拷贝数据到X
- % (3)关掉这个窗口,点击X变量,右键另存为,保存为mat文件
- % (4)注意,代码和数据要放在同一个目录下哦,且Matlab的当前文件夹也要是这个目录。
- load data_water_quality.mat
- %% 数据预处理_正向化
- [n,m] = size(X);
- disp(['共有' num2str(n) '个评价对象, ' num2str(m) '个评价指标'])
- Judge = input(['这' num2str(m) '个指标是否需要经过正向化处理,需要请输入1 ,不需要输入0: ']);
- if Judge == 1
- Position = input('请输入需要正向化处理的指标所在的列,例如[2,3,6]: '); %[2,3,4]
- disp('请输入需要处理的这些列的指标类型(1:极小型, 2:中间型, 3:区间型) ')
- Type = input('例如[1,3,2]: '); %[2,1,3]
- % 注意,Position和Type是两个同维度的行向量
- for i = 1 : size(Position,2)%对每一列进行正向化处理
- X(:,Position(i)) = Positivization(X(:,Position(i)),Type(i),Position(i));
- % 第一个参数是要正向化处理的那一列向量 X(:,Position(i))
- % 第二个参数是对应的这一列的指标类型(1:极小型, 2:中间型, 3:区间型)
- % 第三个参数是告诉函数我们正在处理的是原始矩阵中的哪一列
- % 返回值返回正向化之后的指标
- end
- disp('正向化后的矩阵 X = ')
- disp(X)
- end
- %% 数据预处理_标准化
- Z = X ./ repmat(sum(X.*X) .^ 0.5, n, 1);
- disp('标准化矩阵 Z = ')
- disp(Z)
- %% 指标权重赋值
- disp("请输入是否需要增加权重向量,需要输入1,不需要输入0")
- Judge = input('请输入是否需要增加权重: ');
- if Judge == 1
- disp(['有多少个指标就输入多少个权重数(权重和为1),如[0.25,0.25,0.5]']);
- weigh = input(['请输入输入' num2str(m) '个权重: ']);
- if abs(sum(weigh) - 1)<0.000001 && size(weigh,1) == 1 && size(weigh,2) == m % 这里要注意浮点数的运算是不精准的。
- else
- weigh = input('你输入的有误,请重新输入权重行向量: ');
- end
- else
- weigh = ones(1,m) ./ m ; %如果不需要加权重就默认权重都相同,即都为1/m
- end
- %% 计算与最大值的距离和最小值的距离,并算出得分
- D_P = sum([(Z - repmat(max(Z),n,1)) .^ 2 ] .* repmat(weigh,n,1) ,2) .^ 0.5; % D+ 与最大值的距离向量
- D_N = sum([(Z - repmat(min(Z),n,1)) .^ 2 ] .* repmat(weigh,n,1) ,2) .^ 0.5; % D- 与最小值的距离向量
- S = D_N ./ (D_P+D_N); % 未归一化的得分
- disp('最后的得分为:')
- stand_S = S / sum(S)% 归一化的得分
- [sorted_S,index] = sort(stand_S ,'descend')%对得分进行排序并返回原来的位置
- plot(sorted_S,'r-o')
- xmin=1;xmax = size(sorted_S,1);
- ymin = 0;ymax = max(sorted_S)+min(sorted_S);
- axis([xmin xmax ymin ymax]); % 设置坐标轴在指定的区间
- grid on
- xlabel('方案');ylabel('分数');%坐标轴表示对bai象标签
- title('TOPSIS算法最终评分排序')
复制代码 正向化处置处罚函数Positivization.m程序
- function [posit_x] = Positivization(x,type,i)
- % 输入变量有三个:
- % x:需要正向化处理的指标对应的原始列向量
- % type: 指标的类型(1:极小型, 2:中间型, 3:区间型)
- % i: 正在处理的是原始矩阵中的哪一列
- % 输出变量posit_x表示:正向化后的列向量
- if type == 1 %极小型
- disp(['第' num2str(i) '列是极小型,正在正向化'] )
- posit_x = Min2Max(x); %调用Min2Max函数来正向化
- disp(['第' num2str(i) '列极小型正向化处理完成'] )
- disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
- elseif type == 2 %中间型
- disp(['第' num2str(i) '列是中间型'] )
- best = input('请输入最佳的那一个值(中间的那个值): ');
- posit_x = Mid2Max(x,best);
- disp(['第' num2str(i) '列中间型正向化处理完成'] )
- disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
- elseif type == 3 %区间型
- disp(['第' num2str(i) '列是区间型'] )
- a = input('请输入区间的下界: ');
- b = input('请输入区间的上界: ');
- posit_x = Inter2Max(x,a,b);
- disp(['第' num2str(i) '列区间型正向化处理完成'] )
- disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
- else
- disp('没有这种类型的指标,请检查Type向量中是否有除了1、2、3之外的其他值')
- end
- end
复制代码 以下面这个例子为例:
首先导入数据,然后运行程序,效果如下:
关于运行后没有min2max,是由于没有定义极小、极大、中间型函数,具体代码在CSDN:
**TOPSIS优劣解隔断法–代码部分_丰丰小白的博客-CSDN博客_优劣解隔断法代码**
TOPSIS优劣解隔断法–代码部分
下面要介绍的是TOPSIS的代码书写方法,TOPSIS总体分为三步:
1、矩阵正向化
2、正向化矩阵标准化
3、盘算评分并归一化
下面根据这三步开始我们的代码编写:
第一步:导入数据
把数据复制到工作区,并将这个矩阵定名为x
① 在工作区右键,点击新建(ctrl+n),输入变量名称X
② 在Excel中复制数据,再回到X变量中粘贴数据
③ 右键X另存为,保存为mat文件,以后调用X只需要用load命令即可加载数据(这里我保存的mat文件定名为X.mat)
④ 代码和数据需要放在同一个目次下哦
第二步:判断是否需要正向化,并举行正向化
- [n,m]=size(X);
- disp(['共有num2str(n)'个评价对象'个评价对象'num2str(m)'个评价指标']
- %用向量的方法拼接并输出字符串
- Judge=input(['这'num2str(m)'个指标是否经过正向化处理,需要请输入1,不需要请输入0:']);
- %使用input函数,来给Judge赋值
- if Judge==1
- Position=input('请输入需要正向化处理的指标所在的列,例如第2、3、6三列需要处理,那么你输入[2,3,6]:');
- %使用input函数确定需要正向化处理的位置
- disp('请输入需要处理的这些列的标准类型(1:极小型,2:中间型,3:区间型)')
- Type=input('例如:第2列是极小型,第3列是区间型,第6列是中间型,就输入[1,3,2]:');
- %使用intput函数确定需要处理列的指标类型
- %需要注意的是Position和Type是相同维度的行向量
- for i=1:size(Position,2)%这里得出的是循环次数,也就是每一个需要正向化的列都做一次循环
- X(:,Position(i))=Positivization(X(:,Position(i)),Type(i),Position(i));
- %Positivization是我们自己定义的函数,其作用是进行正向化,一共接受3个参数
- %第一个参数就是要正向化处理的那一列向量X(:,Position(i))
- %第二个参数是对应的这一列的指标类型(1:极小型,2:中间型,3:区间型)
- %第三个参数是告诉函数我们正在处理的是原始矩阵中的哪一列
- %该函数有一个返回值,它返回正向化之后的指标那一列,我们可以直接给我们原始要处理的列向量进行赋值
- end
- disp('正向化后的矩阵X=')
- disp(X)
- end
复制代码 接下来开始定义我们的Positivization函数,函数不可以直接放在主函数中,和大多数语言不同,函数需要在matlab中单独定义一个m文件,并且函数文件需要和主函数放在同一个目次,也就是同一个文件夹当中。首先定义三种指标的转化函数:
极小型转化为极大型:Min2Max
- %function[输出变量]=函数名(输入变量)
- %函数最后需要用end结尾
- function[posit_x]=Min2Max(x)
- posit_x=max(x)-x;
- end
复制代码
- function[posit_x]=Mid2Max(x,best)
- M=max(abs(x-best));
- posit_x=1-abs(x-best)/M;
- end
复制代码
- function[posit_x]=Inter2Max(x,a,b)
- r_x=size(x,1);%表示列向量的行数(row of x),来找到循环的次数
- M=max([a-min(x),max(x)-b]);
- posit_x=zeros(r_x,1) %将posit_x初始化为一个全为0的列向量
- for i=1:r_x
- if x(i)<a
- posit_x(i)=1-(a-x(i)/M;
- elseif x(i)>b
- posit_x(i)=1-(x(i)-b)/M;
- else
- posit_x(i)=1;
- end
- end
- end
复制代码 接下来开始写Positivization函数:
- %function[输出变量]=函数名(输入变量)
- %函数最后需要用end结尾
- %输出变量和输入变量可以有多个,中间用逗号隔开
- function[posit_x]=Positivization(x,type,i)%这里定义函数参数,其中均为形参
- %posit_x表示正向化后的列向量
- %x表示需要正向化处理的指标对应的原始列向量
- %type表示指标的类型(1:极小型,2:中间型,3:区间型)
- %i表示正在处理的是原矩阵中的哪一列
- if type==1 %极小型
- disp(['第'num2str(i)'列是极小型,正在正向化'])
- posit_x=Min2Max(x);%调用Min2Max函数来进行正向化
- disp(['第'num2str(i)'列极小型正向化处理完毕'])
- disp('~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~')
- elseif type==2%中间型
- disp(['第'num2str(i)'列是中间型'])
- best=input('请输入最佳的值:');
- posit_x=Mid2Max(x,best);
- disp(['第'num2str(i)'列中间型正向化处理完毕'])
- disp('~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~')
- elseif type==3 %区间型
- disp(['第'num2str(i)'列是区间型'])
- a=input('请输入区间的上界');
- b=input('请输入区间的下界');
- posit_x=Inter2Max(x,a,b);
- disp(['第'num2str(i)'列区间型正向化处理完毕'])
- disp('~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~')
- end
- end
-
复制代码 第三步:对正向化后的矩阵举行标准化
- Z=X./repmat(sum(X.*X).^0.5,n,1);
- disp('标准化矩阵Z=')
- disp(Z)
复制代码 第四步:盘算与最大值的隔断和与最小值的隔断,并盘算出得分
- D_P=sum([(Z-repmat(max(Z),n,1)).^2],2).^0.5;%D+与最大值的距离
- D_N=sum([(Z-repmat(min(Z),n,1)).^2],2).^0.5;%D-与最小值的距离
- S=D_N./(D_P+D_N);%未归一化的得分
- disp('最后的得分为:')
- stand_S=S/sum(S)
- [sortde_s,index]=sort(stand_S,'descend')
- %这里使用sort函数进行排序,sort函数默认升序排列,加入参数'descend'为降序排列
- %返回值sortde_s为降序排列后的矩阵,index为排列后的序号。
复制代码 python版一个综合练习题
现有一份关于各个河流的数据,此中oxygen表示水中含氧比例,该比例越大越好;PH表示水体的酸碱性,该值越靠近7越好;bacteria表示水中细菌数目,该值越小越好;water plants表示水中水草数目,该值最好是介于[500,1000]。
 - import pandas as pd
- path = 'C:UsersCaraDesktopwaterquality.xlsx'
- rawdata = pd.read_excel(path)
- #一、将所有指标正向化
- #1.处理PH指标,它属于中间型指标,将其转化为极大型指标
- #PH指标最优值为7
- PHbest = 7
-
- #(1)构造PH变量的中间变量M_PH
- PH = list(rawdata['PH'])
- lst1 = []
- for i in range(0,len(PH)):
- d = abs(PH[i] - PHbest)
- lst1.append(d)
- M_PH = max(lst1)
-
- #(2)使用公式将PH指标转化为极大型指标,保留4位小数
- PH_bar = [round(1-abs(i-PHbest)/M_PH,4) for i in PH]
-
- #2.处理Bacteria指标,它属于极小型指标,将其转化为极大型指标
- Bacteria = list(rawdata['Bacteria'])
- #用 max-x的方法正向化
- max_Bacteria = max(Bacteria)
- Bacteria_bar = [max_Bacteria - i for i in Bacteria]
-
- #3.处理WaterPlants指标,它属于区间型指标,将其转化为极大型指标
- #最佳区间为[500,1000]
- WP_a = 500
- WP_b = 1000
- #构造中间变量M_WP
- WP = list(rawdata['WaterPlants'])
- min_WP = min(WP)
- max_WP = max(WP)
- M_WP = max(WP_a - min_WP,max_WP - WP_b)
-
- #根据转化公式,将WaterPlants指标转化为极大型指标
- WP_bar = []
- for i in range(0,len(WP)):
- if WP[i] >= WP_a and WP[i] <= WP_b:
- x = 1
- elif WP[i] < WP_a:
- x = 1 - (WP_a - WP[i])/M_WP
- else:
- x = 1 - (WP[i] -WP_b)/M_WP
- WP_bar.append(x)
-
-
- #二、所有指标进行数据标准化处理
- #1.Oxygen_bar指标标准化
- import numpy as np
- Oxygen_bar = list(rawdata['Oxygen'])
-
- lst2 = []
- for i in range(0,len(Oxygen_bar)):
- p = pow(Oxygen_bar[i], 2)
- lst2.append(p)
- c = np.sqrt(sum(lst2))#构造出标准化公式中的分母部分
- Oxygen_bar_standardized = [i/c for i in Oxygen_bar]
-
-
- #2.PH_bar指标标准化
- lst3 = []
- for i in range(0,len(PH_bar)):
- p = pow(PH_bar[i], 2)
- lst3.append(p)
- c = np.sqrt(sum(lst3))#构造出标准化公式中的分母部分
- PH_bar_standardized = [i/c for i in PH_bar]
-
-
- #3.Bacteria_bar指标标准化
- lst4 = []
- for i in range(0,len(Bacteria_bar)):
- p = pow(Bacteria_bar[i], 2)
- lst4.append(p)
- c = np.sqrt(sum(lst4))#构造出标准化公式中的分母部分
- Bacteria_bar_standardized = [i/c for i in Bacteria_bar]
-
- #4.WP_bar指标标准化
- lst5 = []
- for i in range(0,len(WP_bar)):
- p = pow(WP_bar[i], 2)
- lst5.append(p)
- c = np.sqrt(sum(lst5))#构造出标准化公式中的分母部分
- WP_bar_standardized = [i/c for i in WP_bar]
-
-
- #三、根据评分公式进行评分
- #1.在评分前,将标准化后的变量拼接起来
- stand_data = pd.DataFrame({'River':rawdata['River'],
- 'Oxygen':pd.Series(Oxygen_bar_standardized),
- 'PH':pd.Series(PH_bar_standardized),
- 'Bacteria':pd.Series(Bacteria_bar_standardized),
- 'WaterPlants':pd.Series(WP_bar_standardized)}
- )
-
-
- #2.计算各指标的最大值和最小值,形成两个最值向量
- stand_data.describe()
- #各变量最大值
- max_values = stand_data.describe().iloc[[7],:]
-
- #各变量最小值
- min_values = stand_data.describe().iloc[[3],:]
-
-
- #3.计算每个河流向量到各变量最小值、最大值的距离
- #计算每个河流向量到各变量最小值的距离
- from scipy.spatial import distance
- sd_data = stand_data.copy().drop(columns=['River'])
- dst_to_min = []
- for i in range(0,len(stand_data)):
- v = sd_data.iloc[[i], :]
- d = distance.euclidean(v, min_values)
- dst_to_min.append(d)
-
-
- #计算每个河流向量到各变量最大值的距离
- dst_to_max = []
- for i in range(0,len(stand_data)):
- v = sd_data.iloc[[i], :]
- d = distance.euclidean(v, max_values)
- dst_to_max.append(d)
-
-
- #根据评分公式,计算每个河流的得分
- #S = dst_to_min /(dst_to_max + dst_to_min)
- Score = []
- for i in range(0,len(dst_to_min)):
- s = dst_to_min[i]/(dst_to_max[i] + dst_to_min[i])
- Score.append(s)
-
-
- #得分归一化
- total = sum(Score)
- Score_normalized = [i/total for i in Score]
-
- #将归一化后的得分添加到stand_data数据框中
- stand_data['Score_normalized'] = Score_normalized
- print(stand_data)
复制代码 盘算出的得分效果(Score_normalized):
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |