综合评价与决策方法一:优劣解距离法(TOPSIS法)

TOPSIS是一种综合评价方法,利用原始数据信息计算方案与最优解和最劣解的距离,适用于多个评价指标的情况。本文详细介绍了TOPSIS的流程,包括极小型、中间型和区间型指标的正向化处理,矩阵标准化,计算得分和归一化,并通过案例分析展示了如何应用该方法。案例中,通过对11条河流的水质指标进行TOPSIS分析,得出水质优劣排序,与熵权法结果对比显示了TOPSIS在数据细化处理上的优势。
摘要由CSDN通过智能技术生成

目录

1.TOPSIS方法简介

2.算法流程

3.算法步骤

3.1 原始矩阵正向化(即统一转化为极大指标) 

3.1.1 极小型指标转化为极大型指标

3.1.2  中间型指标转化为极大型指标

 3.1.3 区间型指标转化为极大型指标

3.2 正向化矩阵标准化

3.3 计算得分并归一化

4.案例分析

4.1 题目简介

4.2原始矩阵正向化

4.2.1 极小型指标转化为极大型指标

4.2.2 中间型指标转化为极大型指标

4.2.3 区间型指标转化为极大型指标

4.3 正向化矩阵标准化

4.4 计算得分

5.代码示例

5.1 代码展示

5.2 运行截图


1.TOPSIS方法简介

        前文所讲的层次分析法熵权法主要用来确定每个指标在每个方案中所占权重,在得到权重后与每个指标对应的值求积再求和就能得到每个方案的综合评分,因此也可以用来进行评价。但是其也有各自的局限性,例如层次分析法主观性太强并且方案层不能太多,否则很难通过一致性检验,而熵权法就只适用于计算权重,其所得评价结果也具有一定局限性。

         而TOPSIS是一种综合评价方法,可以弥补层次分析法的一些缺点:

(1)优劣解距离法可以充分利用原始数据信息,且其结果能充分反应各评价方案与最优方案的接近程度。

(2)对样本容量没有严格限制,数据计算简单易行,无需数据检验。(topsis法适用于两个以上)

2.算法流程

3.算法步骤

3.1 原始矩阵正向化(即统一转化为极大指标) 

3.1.1 极小型指标转化为极大型指标

        极小型指标指其数值越小所代表的效果越好,例如排名,数值越小越好。其转换方法有以下两种:

3.1.2  中间型指标转化为极大型指标

        中间型指标指其数值在某个中间值时为其最佳值,例如PH值,PH=7即为其中间值(最佳值)。其转换方法如下: 

参数M(到最佳值距离的最大值):

         式中表示最佳值,例如PH最佳值为7。

 3.1.3 区间型指标转化为极大型指标

        区间型指标指其数值落在某一个区间内时均为最佳值,例如人的体温区间为[36,37.2]。假设其最佳区间为[a,b],则其转换方法如下:

3.2 正向化矩阵标准化

假设已正向化的矩阵有n个评价对象,m个指标。

3.3 计算得分并归一化

 每列最大值:

每列最小值:

第i个评价对象(方案)与最大值距离: 

第i个评价对象(方案)与最小值距离: 

         式中为每个指标的权重,默认权重都相同,在实际计算中可以根据实际情况对每个指标赋予不同的权重,其主要方法有层次分析法和熵权法,具体操作步骤在前文有详细解说。

则第i个评价对象的得分(未归一化):

4.案例分析

4.1 题目简介

        已知判断某一水域水质情况的好坏时可以通过x1-x9共9种指标来评判,现有A-K共11条河流的指标测量情况,请以此判断各河流水质的优良情况。其中x1,x3,x6,x7为极大型指标,x2,x5为中间型指标,其中间值分别为45、52,x4,x8,x9为区间型指标,其最佳区间依次为[30,65],[40,50],[30,70]。

河流x1x2x3x4x5x6x7x8x9
A886317505349642432
B7512431453311842
C794873624348727698
D7395934204654459
E36705351006742543
F4046926068192768
G20783598837035581
H6729383322734775
I383028724620504274
J952520421354565482
K40322714225968153

4.2原始矩阵正向化

4.2.1 极小型指标转化为极大型指标

河流x1x2x3x4x5x6x7x8x9
A76375505321102432
B20190431417431842
C16481962432227698
D22958334202420459
E59703951006402543
F5546060685172768
G7578579883039581
H28295433243714775
I573064724650244274
J02572421316185482
K553265142211688153

4.2.2 中间型指标转化为极大型指标

河流x1x2x3x4x5x6x7x8x9
A70.6475500.97916721102432
B200.1290430.20833317431842
C160.9419620.81252227698
D22083340.3333332420459
E590.539506402543
F550.980600.6666675172768
G750.3457980.354167039581
H280.685430.58333343714775
I570.764720.87550244274
J00.672420.187516185482
K550.7465140.37511688153

4.2.3 区间型指标转化为极大型指标

河流x1x2x3x4x5x6x7x8x9
A70.647510.97916721100.5555561
B200.129010.20833317430.3888891
C160.941910.81252220.2777780.034483
D2208310.333333242001
E590.5390.24242406400.5833331
F550.98010.66666751720.2777780.241379
G750.345700.3541670390.7777780
H280.68540.1818180.583333437110.827586
I570.7640.7878790.875502410.862069
J00.67210.187516180.8888890.586207
K550.74650.5151520.37511680.1388891

4.3 正向化矩阵标准化

河流x1x2x3x4x5x6x7x8x9
A0.0490360.3019140.3652410.3785610.5142840.1826920.0713870.2657940.382607
B0.1401040.0566090.438290.3785610.1094220.1478930.3069630.1860560.382607
C0.1120830.4434360.0925280.3785610.4267460.1913910.0142770.1328970.013193
D0.15411400.4042010.3785610.1750750.208790.14277300.382607
E0.4133060.235870.1899260.09177200.55677400.2790840.382607
F0.3852850.46230500.3785610.350150.443680.5139840.1328970.092353
G0.5253880.1603920.27758400.18601700.2784080.3721120
H0.1961450.3207830.2629740.0688290.3063820.3740830.5068460.4784290.31664
I0.3992950.3302180.3116730.298260.4595730.434980.1713280.4784290.329834
J00.2830440.3506320.3785610.098480.1391940.1284960.425270.224287
K0.3852850.3490880.3165430.1950160.196960.0956960.485430.0664480.382607

4.4 计算得分

由熵权法可得9个指标权重如下(详情见文章):

指标x1x2x3x4x5x6x7x8x9
权重0.097370.0819280.1278740.1214240.170780.0829740.1330280.0927660.091855

输入权重可以得到11条河流水质综合评分如下

河流ABCDEFGHIJK
得分0.5629870.5280230.5040480.4902260.4823290.5030790.4971640.5115090.5288560.5214460.524432

由此可见水质优劣排序依次为:A>I>B>K>J>H>C>F>G>D>E

而直接使用熵权法得到的水质情况为:C>G>E>A>F>J>I>D>K>H>B

        对比可见还是有很大差别,这是因为熵权法最后只是得到了各指标的权重,直接用权重求出的得分就很笼统,没有对数据进行细化处理。

5.代码示例

5.1 代码展示

package TOPSIS;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Scanner;

import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import jxl.write.WriteException;

public class topsis {
	private String filepath;//文件路径
	private double[][] orig = new double[1000][1000];//原始矩阵
	private double[][] pos = new double[1000][1000];//正向化后的矩阵
	private double[][] stad = new double[1000][1000];//标准化后的矩阵
	private double[][] uniform = new double[1000][1000];//归一化后的矩阵
	int rows,cols;//存储Excel的行和列数

	Scanner input = new Scanner(System.in);

	//读取数据
	public void read(String filepath) throws IOException, BiffException,WriteException {
		//创建输入流
		InputStream stream = new FileInputStream(filepath);
		//获取Excel文件对象
		Workbook  rwb = Workbook.getWorkbook(stream);
		//获取文件的指定工作表 默认的第一个
	    Sheet sheet = rwb.getSheet("Sheet1");
	    rows = sheet.getRows();
	    cols = sheet.getColumns();
		//row为行
		for(int i=0;i<sheet.getRows();i++) {
			for(int j=0;j<sheet.getColumns();j++) {
				//orig = new double[sheet.getRows()][sheet.getColumns()];
				String[] str = new String[sheet.getColumns()];
		        Cell cell = null;
		        cell = sheet.getCell(j,i);    
			    str[j] = cell.getContents();
			    orig[i][j] = Double.valueOf(str[j]);
			    pos[i][j] = Double.valueOf(str[j]);
			    stad[i][j] = Double.valueOf(str[j]);
			    uniform[i][j] = Double.valueOf(str[j]);
			}
	    }
		//输出原始矩阵,行为评价对象,列为评价指标
		System.out.println("原始矩阵为:");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				System.out.print(orig[i][j]+"   ");
			}
			System.out.println();
		}
	}
	
	//原始矩阵正向化
	//极小型指标——>极大型指标
	public void positive1() {
		System.out.println("有几列数据(指标)要将极小型转化为极大型:");
		int num = input.nextInt();
		System.out.println("输入要将极小型转化为极大型的列数:");//以空格分分开
		int[] col = new int[num];//存储要转化的列
		for(int i=0;i<num;i++) {
			col[i] = input.nextInt();
			//System.out.println(col[i]);
		}
		
		//挑选每列最大值
		double[] colmaxs = new double[num];//存储每列的最大值
		for(int j=0;j<num;j++) {
			double colmax = 0;
			int x = col[j];
			for(int i=0;i<rows;i++) {
				if(orig[i][x] >= colmax) {
					colmax = orig[i][x];
					//System.out.println("orig:"+orig[i][x]);
				}
			}
			colmaxs[j] = colmax;
			//System.out.println(colmaxs[j]);
			
			//每列最大值减去当前值:max-x
			for(int i=0;i<rows;i++) {
				pos[i][x] = colmaxs[j] - pos[i][x];
			}
		}
		
		System.out.println("(极小型指标——>极大型指标)pos1矩阵为:");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				System.out.print(pos[i][j]+"   ");
			}
			System.out.println();
		}
	}
	
	//中间型指标——>极大型指标
	public void positive2() {
		System.out.println("有几列数据(指标)要将中间型转化为极大型:");
		int num = input.nextInt();
		System.out.println("输入要将中间型转化为极大型的列数:");//以空格分分开
		int[] col = new int[num];//存储要转化的列
		for(int i=0;i<num;i++) {
			col[i] = input.nextInt();
			//System.out.println(col[i]);
		}
		System.out.println("依次输入对应列的最佳值:");
		double[] best = new double[num];
		for(int i=0;i<num;i++) {
			System.out.println("第"+col[i]+"列的最佳值:");
			best[i] = input.nextDouble();
			//System.out.println(best[i]);
		}
		
		//计算每个元素到最佳距离的值以及最大值、正向化矩阵
		for(int j=0;j<num;j++) {
			int x = col[j];
			//System.out.println(colmaxs[j]);
			
			double[][] dis = new double[rows][num];
			double[] MAX = new double[num];//到最佳距离的最大值
			double max = 0;
			for(int i=0;i<rows;i++) {
				double a = pos[i][x] - best[j];
				//System.out.println(a);
				dis[i][j] = Math.abs(a);
				//System.out.println(dis[i]);
				if(dis[i][j] >= max) {
					max = dis[i][j];
					MAX[j] = max;
				}
			}
			System.out.println("MAX:"+MAX[j]);
			
			//System.out.println("dis矩阵为:");
			for(int i=0;i<rows;i++) {
				pos[i][x] = 1-(dis[i][j]/MAX[j]);
				//System.out.println(dis[i][j]);
			}
		}
		
		System.out.println("(中间型指标——>极大型指标)pos2矩阵为:");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				System.out.print(pos[i][j]+"   ");
			}
			System.out.println();
		}
	}	
	
	//区间型指标——>极大型指标
	public void positive3() {
		System.out.println("有几列数据(指标)要将区间型转化为极大型:");
		int num = input.nextInt();
		System.out.println("输入要将区间型转化为极大型的列数:");//以空格分分开
		int[] col = new int[num];//存储要转化的列
		for(int i=0;i<num;i++) {
			col[i] = input.nextInt();
			//System.out.println(col[i]);
		}
		System.out.println("输入每列对应的区间[a,b]:");
		double[][] sec = new double[num][2];//存储区间
		for(int i=0;i<num;i++) {
			int a=col[i];
			System.out.println("输入第"+a+"列的区间:");
			for(int j=0;j<2;j++) {
				sec[i][j] = input.nextDouble();
			}
		}
		
		double[] colmaxs = new double[num];//存储每列的最大值
		double[] colmins = new double[num];//存储每列的最小值
		double[] MAX = new double[num];//到a,b距离的最大值
		for(int j=0;j<num;j++) {
			double colmax = 0;
			int x = col[j];
			for(int i=0;i<rows;i++) {
				if(orig[i][x] >= colmax) {
					colmax = orig[i][x];
					//System.out.println("orig:"+orig[i][x]);
				}
			}
			colmaxs[j] = colmax;
			
			double colmin = 0;
			for(int i=0;i<rows;i++) {
				if(i==0) {
					colmin = orig[i][x];
				}
				else if(orig[i][x] <= colmin) {
					colmin = orig[i][x];
					//System.out.println("orig:"+orig[i][x]);
				}
			}
			colmins[j] = colmin;
			MAX[j] = Math.max(sec[j][0] - colmins[j], colmaxs[j] - sec[j][1]);
			
			for(int i=0;i<rows;i++) {
				if(pos[i][x] < sec[j][0]) {
					pos[i][x] = 1-((sec[j][0] - pos[i][x])/MAX[j]);
				}
				else if(pos[i][x] > sec[j][1]) {
					pos[i][x] = 1-((pos[i][x] - sec[j][1])/MAX[j]);
				}
				else {
					pos[i][x] = 1;
				}
			}
		}
		/*
		for(int j=0;j<num;j++) {
			int x = col[j];
			System.out.println("第"+x+"列最大值:");
			System.out.println(colmaxs[j]);
			System.out.println("第"+x+"列最小值:");
			System.out.println(colmins[j]);
			System.out.println("第"+x+"列最大距离:");
			System.out.println(MAX[j]);
		}
		*/
		System.out.println("(区间型指标——>极大型指标)pos3矩阵为:");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				System.out.print(pos[i][j]+"   ");
			}
			System.out.println();
		}
	}
	
	//正向化举证标准化
	public void standar() {
		double[] sum =new double[cols];
		for(int j=0;j<cols;j++) {
			for(int i=0;i<rows;i++) {
				sum[j] += pos[i][j]*pos[i][j];
			}
		}
		
		for(int j=0;j<cols;j++) {
			for(int i=0;i<rows;i++) {
				stad[i][j] = pos[i][j]/Math.sqrt(sum[j]);
			}
		}
		
		System.out.println("(标准化)stad矩阵为:");
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				System.out.print(stad[i][j]+"   ");
			}
			System.out.println();
		}
	}
	
	//计算得分并归一化
	public void uniform() {
		double[] Zmax = new double[cols];//存储每列的最大值
		double[] Zmin = new double[cols];//存储每列的最小值
		for(int j=0;j<cols;j++) {
			double colmax = 0;
			for(int i=0;i<rows;i++) {
				if(stad[i][j] >= colmax) {
					colmax = stad[i][j];
					//System.out.println("orig:"+orig[i][x]);
				}
			}
			Zmax[j] = colmax;//每列的最大值
			
			double colmin = 0;
			for(int i=0;i<rows;i++) {
				if(i==0) {
					colmin = stad[i][j];
				}
				else if(stad[i][j] <= colmin) {
					colmin = stad[i][j];
					//System.out.println("orig:"+orig[i][x]);
				}
			}
			Zmin[j] = colmin;//每列的最小值
		}
		
		double Dmax = 0.0;
		double Dmin = 0.0;
		double summax =0.0;
		double summin =0.0;
		double[] wi = new double[cols];//权重向量
		System.out.println("依次输入每个指标(列)的权重:");
		for(int i =0;i<cols;i++) {
			wi[i] = input.nextDouble();
		}
		for(int i=0;i<rows;i++) {
			for(int j=0;j<cols;j++) {
				summax += wi[j]*Math.pow(Zmax[j] - stad[i][j], 2.0);
				summin += wi[j]*Math.pow(Zmin[j] - stad[i][j], 2.0);
			}
			Dmax = Math.sqrt(summax);
			Dmin = Math.sqrt(summin);
			uniform[i][0] = Dmin/(Dmax+Dmin); 
		}
		
		System.out.println("uniform矩阵(最终得分):");
		for(int i=0;i<rows;i++) {
			System.out.println(uniform[i][0]);
		}
	}
		

	public String getFilepath() {
		return filepath;
	}

	public void setFilepath(String filepath) {
		this.filepath = filepath;
	}
}
package TOPSIS;

import java.io.IOException;

import jxl.read.biff.BiffException;
import jxl.write.WriteException;

public class topsismain {
	public static void main(String args[]) throws BiffException, IOException, WriteException {
		topsis top = new topsis();
		top.read("topsis.xls");
		top.positive1();
		top.positive2();
		top.positive3();
		top.standar();
		top.uniform();
	}
}

5.2 运行截图

  • 22
    点赞
  • 164
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

离陌lm

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值