TOPSIS法的简单应用


参考学习b站: 数学建模学习交流

前言

基本知识可看:TOPSIS法

应用

评价下表中20条河流的水质情况
注:含氧量越高越好;PH值越接近7越好;细菌总数越少越好;植物性营养物量介于10‐20之间最佳,超过20或低于10均不好
在这里插入图片描述

步骤如下

  1. 导入矩阵至matalb
  2. 判断是否需要正向化
  3. 对正向化后的矩阵进行标准化
  4. 计算与最大值的距离和最小值的距离,并算出得分

主函数:

clear;clc
%1.导入矩阵
load data_water_quality.mat
%2.判断是否需要正向化
[n,m] = size(X);
disp(['共有' num2str(n) '个评价对象, ' num2str(m) '个评价指标']) 
Judge = input(['这' num2str(m) '个指标是否需要经过正向化处理,需要请输入1 ,不需要输入0:  ']);

if Judge == 1
    Position = input('请输入需要正向化处理的指标所在的列,如[2,3,4]: ');
    disp('请输入需要处理的这些列的指标类型(1:极小型, 2:中间型, 3:区间型) ')
    Type = input('如[2,1,3]:  '); 
    for i = 1 : size(Position,2) 
        X(:,Position(i)) = Positivization(X(:,Position(i)),Type(i),Position(i));
    end
    disp('正向化后的矩阵 X =  ')
    disp(X)
end

%3.对正向化后的矩阵进行标准化
Z = X ./ repmat(sum(X.*X) .^ 0.5, n, 1);
disp('标准化矩阵 Z = ')
disp(Z)

%4.计算与最大值的距离和最小值的距离,并算出得分
D_P = sum([(Z - repmat(max(Z),n,1)) .^ 2 ],2) .^ 0.5;  
D_N = sum([(Z - repmat(min(Z),n,1)) .^ 2 ],2) .^ 0.5;  
S = D_N ./ (D_P+D_N); 
disp('最后的得分为:')
stand_S = S / sum(S)
[sorted_S,index] = sort(stand_S ,'descend')

输入注意Position和Type是两个同维度的行向量,不然没有意义

Positivization函数作用是进行正向化,其一共有三个参数:

  • 第一个参数是要正向化处理的那一列向量 X(:,Position(i)) (ps. X(:,n)表示取第n列的全部元素)
  • 第二个参数是对应的这一列的指标类型(1:极小型, 2:中间型, 3:区间型)
  • 第三个参数是告诉函数正在处理的是原始矩阵中的哪一列

输出变量posit_x表示:正向化后的列向量,它返回正向化之后的指标,我们将其直接赋值给我们原始要处理的那一列向量

Positivization函数代码:

function [posit_x] = Positivization(x,type,i)
    if type == 1  %极小型
        disp(['第' num2str(i) '列是极小型,正在正向化'] )
        posit_x = Min2Max(x);
        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

中间用到的3个函数不再赘述:

Min2Max函数来正向化极小型:

function [posit_x] = Min2Max(x)
    posit_x = max(x) - x;
     %posit_x = 1 ./ x;    %如果x全部都大于0,也可以这样正向化
end

Mid2Max函数来正向化中间型:

function [posit_x] = Mid2Max(x,best)
    M = max(abs(x-best));
    posit_x = 1 - abs(x-best) / M;
end

Inter2Max函数来正向化列区间型:

function [posit_x] = Inter2Max(x,a,b)
    r_x = size(x,1);  % row of x 
    M = max([a-min(x),max(x)-b]);
    %zeros函数用法: zeros(3)  zeros(3,1)  ones(3)
    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

输入输出:

共有20个评价对象, 4个评价指标
这4个指标是否需要经过正向化处理,需要请输入1 ,不需要输入01
请输入需要正向化处理的指标所在的列,例如第236三列需要处理,那么你需要输入[2,3,6][2,3,4]
请输入需要处理的这些列的指标类型(1:极小型, 2:中间型, 3:区间型) 
例如:第2列是极小型,第3列是区间型,第6列是中间型,就输入[1,3,2][2,1,3]2列是中间型
请输入最佳的那一个值: 72列中间型正向化处理完成
~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~3列是极小型,正在正向化
第3列极小型正向化处理完成
~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~4列是区间型
请输入区间的下界: 10
请输入区间的上界: 204列区间型正向化处理完成
~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~
正向化后的矩阵 X =  
    4.6900    0.7172    3.0000    1.0000
    2.0300    0.4069   35.0000    0.6940
    9.1100    0.5241    8.0000    0.9058
    8.6100    0.9655    8.0000    0.4443
    7.1300    0.6552    4.0000    0.6914
    2.3900    0.8414   16.0000    0.6007
    7.6900    0.8552   16.0000    0.6551
    9.3000    0.8690   27.0000         0
    5.4500    0.5724   49.0000    1.0000
    6.1900    0.8138   37.0000    0.7848
    7.9300    0.6345   45.0000    0.6992
    4.4000    0.8069   37.0000    0.5419
    7.4600    0.1448   31.0000    1.0000
    2.0100         0    7.0000    0.4546
    2.0400    0.5862   31.0000    1.0000
    7.7300    0.4069    2.0000    1.0000
    6.3500    0.6000   29.0000    0.1824
    8.2900    0.0276   15.0000    1.0000
    3.5400    0.8138         0    0.4088
    7.4400    0.4897   46.0000    0.2731

标准化矩阵 Z = 
    0.1622    0.2483    0.0245    0.3065
    0.0702    0.1408    0.2863    0.2127
    0.3150    0.1814    0.0655    0.2776
    0.2977    0.3342    0.0655    0.1361
    0.2466    0.2268    0.0327    0.2119
    0.0826    0.2912    0.1309    0.1841
    0.2659    0.2960    0.1309    0.2008
    0.3216    0.3008    0.2209         0
    0.1885    0.1981    0.4009    0.3065
    0.2141    0.2817    0.3027    0.2405
    0.2742    0.2196    0.3682    0.2143
    0.1522    0.2793    0.3027    0.1661
    0.2580    0.0501    0.2536    0.3065
    0.0695         0    0.0573    0.1393
    0.0705    0.2029    0.2536    0.3065
    0.2673    0.1408    0.0164    0.3065
    0.2196    0.2077    0.2373    0.0559
    0.2867    0.0095    0.1227    0.3065
    0.1224    0.2817         0    0.1253
    0.2573    0.1695    0.3763    0.0837

最后的得分为:

stand_S =

    0.0451
    0.0478
    0.0485
    0.0488
    0.0431
    0.0448
    0.0539
    0.0510
    0.0681
    0.0684
    0.0702
    0.0591
    0.0527
    0.0192
    0.0533
    0.0434
    0.0466
    0.0438
    0.0358
    0.0565


sorted_S =

    0.0702
    0.0684
    0.0681
    0.0591
    0.0565
    0.0539
    0.0533
    0.0527
    0.0510
    0.0488
    0.0485
    0.0478
    0.0466
    0.0451
    0.0448
    0.0438
    0.0434
    0.0431
    0.0358
    0.0192


index =

    11
    10
     9
    12
    20
     7
    15
    13
     8
     4
     3
     2
    17
     1
     6
    18
    16
     5
    19
    14

之后用Excel数据可视化:
在这里插入图片描述
排个序:
在这里插入图片描述

我们可以加入权重,毕竟每个指标的权重可能是不同的

要修改的代码入下:

1.让用户判断是否需要增加权重:

disp('请输入是否需要增加权重向量,需要输入1,不需要输入0')
Judge = input('请输入是否需要增加权重: ');
if Judge == 1
    disp(['如果你有3个指标,你就需要输入3个权重,例如要输入[0.25,0.25,0.5]']);
    weigh = input(['你需要输入' num2str(m) '个权数。' '请以行向量的形式输入这' num2str(m) '个权重: ']);
    OK = 0;  % 用来判断用户的输入格式是否正确
    while OK == 0 
        if abs(sum(weigh) - 1)<0.000001 && size(weigh,1) == 1 && size(weigh,2) == m   % 这里要注意浮点数的运算是不精准的
             OK =1;
        else
            weigh = input('你输入的有误,请重新输入权重行向量: ');
        end
    end
else
    weigh = ones(1,m) ./ m ; %如果不需要加权重就默认权重都相同,即都为1/m
end

2.计算与最大值的距离和最小值的距离,并算出得分:

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')

输入输出样例:

共有20个评价对象, 4个评价指标
这4个指标是否需要经过正向化处理,需要请输入1 ,不需要输入01
请输入需要正向化处理的指标所在的列,例如第236三列需要处理,那么你需要输入[2,3,6][2,3,4]
请输入需要处理的这些列的指标类型(1:极小型, 2:中间型, 3:区间型) 
例如:第2列是极小型,第3列是区间型,第6列是中间型,就输入[1,3,2][2,1,3]2列是中间型
请输入最佳的那一个值: 72列中间型正向化处理完成
~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~3列是极小型,正在正向化
第3列极小型正向化处理完成
~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~4列是区间型
请输入区间的下界: 10
请输入区间的上界: 204列区间型正向化处理完成
~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~
正向化后的矩阵 X =  
    4.6900    0.7172    3.0000    1.0000
    2.0300    0.4069   35.0000    0.6940
    9.1100    0.5241    8.0000    0.9058
    8.6100    0.9655    8.0000    0.4443
    7.1300    0.6552    4.0000    0.6914
    2.3900    0.8414   16.0000    0.6007
    7.6900    0.8552   16.0000    0.6551
    9.3000    0.8690   27.0000         0
    5.4500    0.5724   49.0000    1.0000
    6.1900    0.8138   37.0000    0.7848
    7.9300    0.6345   45.0000    0.6992
    4.4000    0.8069   37.0000    0.5419
    7.4600    0.1448   31.0000    1.0000
    2.0100         0    7.0000    0.4546
    2.0400    0.5862   31.0000    1.0000
    7.7300    0.4069    2.0000    1.0000
    6.3500    0.6000   29.0000    0.1824
    8.2900    0.0276   15.0000    1.0000
    3.5400    0.8138         0    0.4088
    7.4400    0.4897   46.0000    0.2731

请输入是否需要增加权重向量,需要输入1,不需要输入0
请输入是否需要增加权重: 1
如果你有3个指标,你就需要输入3个权重,例如它们分别为0.25,0.25,0.5, 则你需要输入[0.25,0.25,0.5]
你需要输入4个权数。请以行向量的形式输入这4个权重: [0.1 0.2 0.3 0.4]
标准化矩阵 Z = 
    0.1622    0.2483    0.0245    0.3065
    0.0702    0.1408    0.2863    0.2127
    0.3150    0.1814    0.0655    0.2776
    0.2977    0.3342    0.0655    0.1361
    0.2466    0.2268    0.0327    0.2119
    0.0826    0.2912    0.1309    0.1841
    0.2659    0.2960    0.1309    0.2008
    0.3216    0.3008    0.2209         0
    0.1885    0.1981    0.4009    0.3065
    0.2141    0.2817    0.3027    0.2405
    0.2742    0.2196    0.3682    0.2143
    0.1522    0.2793    0.3027    0.1661
    0.2580    0.0501    0.2536    0.3065
    0.0695         0    0.0573    0.1393
    0.0705    0.2029    0.2536    0.3065
    0.2673    0.1408    0.0164    0.3065
    0.2196    0.2077    0.2373    0.0559
    0.2867    0.0095    0.1227    0.3065
    0.1224    0.2817         0    0.1253
    0.2573    0.1695    0.3763    0.0837

最后的得分为:

stand_S =

    0.0463
    0.0540
    0.0469
    0.0427
    0.0408
    0.0458
    0.0504
    0.0430
    0.0730
    0.0694
    0.0696
    0.0599
    0.0560
    0.0230
    0.0603
    0.0437
    0.0424
    0.0458
    0.0333
    0.0536


sorted_S =

    0.0730
    0.0696
    0.0694
    0.0603
    0.0599
    0.0560
    0.0540
    0.0536
    0.0504
    0.0469
    0.0463
    0.0458
    0.0458
    0.0437
    0.0430
    0.0427
    0.0424
    0.0408
    0.0333
    0.0230


index =

     9
    11
    10
    15
    12
    13
     2
    20
     7
     3
     1
    18
     6
    16
     8
     4
    17
     5
    19
    14

这个程序比较大,如果想直接结束程序的运行,可以按ctrl+c

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值