联系数计加油站获取论文和代码等资源。
邮箱:MathComputerSharing@outlook.com
微信公众号:数计加油站
致谢:清风数学建模
比较是评价的精髓 😄
这次考试我考得好不好?要想知道这个问题的答案,你会怎么做呢?
引用老师常常说的几句话:“不要气馁啊,虽然还是犯了很多简单的错误,但还是考得要比上上次要好哦💪”“别看你在我们学校排名不错,放到重点学校,你这就很一般了,要加油啊✊”
这两句话里面,其实透露出了一个不得不承认的真理:评价是在比较中产生的。我们要和差的、好的进行比较,和差的离得越远,和好的离得越近,我们的表现就可以说是越好。
用数学的语言描述,令 D − D^- D−表示离差的的距离, D + D^+ D+表示离好的的距离,则比值 S = D − D − + D + \displaystyle S = \frac{D^-}{D^-+D^+} S=D−+D+D−越大,表现越好; S S S越小,表现越差。
谁最好,谁最差❔理想型最好❕
要比肯定要和最好的和最差的相比喽。各个指标都是全能,这就是最好的。各个指标都是废物,这就是最差的。然而,现实是骨感的,全能者和全废者往往都不可能出现。
现实很骨感,理想很丰满。其实,我们可以从已有的评价对象中,让指标各取其所最长,组成我们的理想最优解;让指标各取其所最短,组成我们的理想最劣解。这样,一个完美的理想型,一个废柴的厌恶型就形成了。让现实的评价对象与它们求距离,得出 S S S值,就可以进行评价了。
越大越好 👍
指标各式各样。有越大越好的,有越小越好的,有就专门是一个数才算最好的,有就专门只在一个范围内才算最好的。而距离只是一个数,它越大就越大,越小就越小😎。怎么样才能从一堆最优准则不同的数中计算出一个能代表距离的数呢?
答案是,把所有指标都变成越大越好的。这一点可以通过代数变换实现(详见后面的小论文)。
指标都变成越大越好的后,还要通过标准化来消除量纲的影响,否则距离就容易由那些数比较大的指标来决定,失去距离的意义。
x = x i ∑ x i 2 x = \frac{x_i}{\sqrt{\sum \limits x_i^2}} x=∑xi2xi
一篇简单的小论文
Matlab代码
极小型指标转化为极大型指标
function X = TOPSISsmall(X0,position)
% 将极小型指标转化为极大型指标
% X0:原始矩阵
% position:极小型指标位置索引
% X:转化后的矩阵
for i=position
small = X0(:,i);
big = max(small) - small;
X0(:,i) = big;
end
X=X0;
end
中间型指标转化为极大型指标
function X = TOPSISmiddle(X0,x0,position)
% 将中间型指标转化为极大型指标
% X0:原始矩阵
% x0:中间值
% position:中间型指标位置索引
% X:转化后的矩阵
%% 判断x0和position是不是一样大
n1 = length(x0);
n2 = length(position);
if n1~=n2
disp("输入的参数维数不对应!!!")
X = [];
return
end
%% 转化
for i = 1:n1
medium = X0(:,position(i));
M = max(abs(medium-x0(i)));
big = 1 - abs(medium-x0(i))/M;
X0(:,position(i)) = big;
end
X=X0;
end
区间型指标转化为极大型指标
function X = TOPSISrange(X0,S,E,position)
% 将区间型指标转化为极大型指标
% X0:原始矩阵
% S:区间起点
% E:区间终点
% position:中间型指标位置索引
% X:转化后的矩阵
%% 判断x0和S和E是不是一样大
n1 = length(S);
n2 = length(position);
n3 = length(E);
if ~(n1==n2 && n1==n3)
disp("输入的参数维数不对应!!!")
X = [];
return
end
%% 转化
for i = 1:n1
range = X0(:,position(i));
a = S(i);
b = E(i);
M = max(a-min(range),max(range)-b);
big = ones(1,length(range));
for j = 1:length(range)
if range(j)<a
big(j)=1-(a-range(j))/M;
elseif range(j)>=a && range(j)<=b
big(j)=1;
else
big(j)=1-(range(j)-b)/M;
end
end
X0(:,position(i)) = big;
end
X=X0;
end
数据标准化
function X = TOPSISnormlize(X0)
% 将数据标准化
n = size(X0,2);
for i=1:n
X0(:,i)=X0(:,i)/norm(X0(:,i));
end
X = X0;
end
计算距离
function D = TOPSISdistance(X,b,w)
% 计算矩阵每个行向量距离某一个向量的加权距离
[m,n1] = size(X);
n2 = length(b);
n3 = length(w);
if n3==0
w = ones(n2,1);
n3 = n2;
end
if ~(n1==n2 && n1==n3)
disp("参数维数不对应");
end
w = w/sum(w);
D = ones(m,1);
for i=1:m
D(i,1) = sqrt((X(i,:)-b).^2*w);
end
end
权重排序
function [sortedWeights,sortedLabels] = sortWeights(weights,labels)
% 使用冒泡排序算法从小到大排序权重和标签
% weights和labels应为行向量或列向量
n = length(weights);
%% 冒泡排序
for i=1:n
for j=1:n-i
if weights(j)>=weights(j+1)
tempNum = weights(j);
weights(j) = weights(j+1);
weights(j+1) = tempNum;
tempLabel = labels(j);
labels(j) = labels(j+1);
labels(j+1) = tempLabel;
end
end
end
sortedWeights = weights;
sortedLabels = labels;
end
绘制权重图
function drawWeights(weights,labels)
% 绘制权重图
% weights:权重行向量或列向量
% labels:数据标签
n = length(weights);
weights = weights / sum(weights);
facecolor = "#3691ff";
width = 0.3;
barh(weights,FaceColor=facecolor,BarWidth=width);
xlim([0,3/2*max(weights)]);
yticks(1:n)
yticklabels(labels);
for i=1:n
text(weights(i)+1/100*max(weights),i,num2str(weights(i)))
end
end
TOPSIS主体
clc,clear
%% 导入数据
waterMatrix = readmatrix("data\水质数据.csv");
%% 确定指标类型
% 极小型
smallIndex = 3;
% 中间型
mediumIndex = 2;
x0 = 7;
% 区间型
rangeIndex = 4;
S = 10;
E = 20;
%% 指标正向化
waterMatrix = TOPSISsmall(waterMatrix,smallIndex);
waterMatrix = TOPSISmiddle(waterMatrix,x0,mediumIndex);
waterMatrix = TOPSISrange(waterMatrix,S,E,rangeIndex);
%% 标准化
waterMatrix = TOPSISnormlize(waterMatrix);
%% 计算得分并归一化
best = max(waterMatrix);
worst = min(waterMatrix);
Db = TOPSISdistance(waterMatrix,best,[]);
Dw = TOPSISdistance(waterMatrix,worst,[]);
weights = Dw./(Db+Dw);
weights = weights/sum(weights);
[weights,labels] = sortWeights(weights,["A","B","C","D","E","F","G","H","I" ...
,"J","K","L","M","N","O","P","Q","R","S","T"]);
drawWeights(weights,labels)
Python代码
初始化
## 导包
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
np.set_printoptions(suppress=True)
plt.rcParams["font.sans-serif"]=["SimHei"] #设置字体
plt.rcParams["axes.unicode_minus"]=False # 解决图像中的“-”负号的乱码问题
## 导入数据
waterMatrix = pd.read_csv("../data/水质数据.csv",header=None)
waterMatrix = waterMatrix.to_numpy()
## 指标类型确定
# 极小型指标
small = [2]
# 中间型指标
medium = [1]
x0 = [7]
# 区间型指标
Range = [3]
S = [10]
E = [20]
函数定义
def TOPSISsmall(X0, position):
"""将极小型指标转化为极大型指标"""
X = X0.copy()
for i in position:
X[:, i] = np.max(X[:, i]) - X[:, i]
return X
def TOPSISmedium(X0,x0,position):
"""将中间型指标转化为极大型指标"""
# 判断x0和position是不是一样大
n1,n2 = len(x0),len(position)
if n1!=n2:
print("列表维数不对应!!!")
return None
# 转化
X=X0.copy()
for i in range(n1):
medium = X[:,position[i]]
M = np.max(np.abs(medium - x0[i]))
X[:,position[i]]=1-np.abs(medium-x0[i])/M
return X
def TOPSISrange(X0, S, E, position):
"""将区间型指标转化为极大型指标"""
# 判断n1,n2,n3是否一样大
n1, n2, n3 = len(S), len(E), len(position)
if not (n1 == n2 and n1 == n3):
print("输入的参数维数不对!!!")
return None
# 转化
X=X0.copy()
for i in range(n1):
Range = X[:, position[i]]
m = np.size(Range)
a = S[i]
b = E[i]
M = np.max([a-np.min(Range), np.max(Range)-b])
big = np.ones(m)
for j in range(m):
if Range[j] < a:
big[j] = 1-(a-Range[j])/M
elif Range[j] >= a or Range <= b:
big[j] = 1
else:
big[j]=1-(Range[j]-b)/M
X[:,position[i]] = big
return X
def TOPSISnormlize(X0):
"""矩阵标准化"""
X = X0.copy()
n = X.shape[1]
for i in range(n):
X[:,i] = X[:,i] / np.linalg.norm(X[:,i])
return X
def TOPSISdistance(X, b, w=None):
"""计算一个矩阵的每个行向量与某个向量的加权距离"""
m, n1 = X.shape
n2 = np.size(b)
if type(w) != np.array:
w = np.ones(n2)
n3 = n2
n3 = np.size(w)
if not (n1 == n2 and n1 == n3):
print("输入的参数维数不对!!!")
return None
w = w / np.sum(w)
D = np.ones(m)
for i in range(m):
D[i] = np.sqrt(np.dot(np.dot(X[i, :]-b, X[i, :]-b), w))[0]
return D
def sortWeights(weights, labels):
"""从小到大排序权重和标签"""
weights = weights / sum(weights)
wl = list(zip(weights, labels))
wl.sort(key=lambda x: x[0])
sortedWeights, sortedLabels = zip(*wl)
sortedWeights = np.array(sortedWeights)
sortedLabels = list(sortedLabels)
return sortedWeights, sortedLabels
def drawWeights(weights, labels, height=0.2):
"""绘制权重图"""
n = len(weights)
ax = plt.axes()
ax.set_facecolor("#FAFAF8")
ax.barh([i for i in range(1,
len(weights) + 1)],
weights,
height=height,
color="#3691ff")
y = [i for i in range(1, n + 1)]
plt.yticks(y, labels)
plt.xlim(0, 4/3*np.max(weights))
for i in range(n):
plt.text(weights[i] + 1/100*np.max(weights),
y[i], np.around(weights[i], 4), ha="left", va="center")
TOPSIS主体
# 指标正向化
waterMatrix = TOPSISsmall(waterMatrix, small)
waterMatrix = TOPSISmedium(waterMatrix, x0, medium)
waterMatrix = TOPSISrange(waterMatrix, S, E, Range)
# 标准化
waterMatrix = TOPSISnormlize(waterMatrix)
# 计算得分并归一化
best = np.max(waterMatrix,0)
worst = np.min(waterMatrix,0)
Db = TOPSISdistance(waterMatrix, best)
Dw = TOPSISdistance(waterMatrix, worst)
weights = Dw / (Db + Dw)
weights = weights / np.sum(weights)
[weights, labels] = sortWeights(weights, ["A", "B", "C", "D", "E", "F",
"G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T"])
drawWeights(weights,labels,0.7)