照亮理想与现实的距离——优劣解距离法


联系数计加油站获取论文和代码等资源。
邮箱: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=xi2 xi

一篇简单的小论文

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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)
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值