【数模学习笔记】TOPSIS优劣解距离法计算得分

TOPSIS计算得分的过程主要分为3步:

一、矩阵正向化

二、正向化矩阵标准化

三、计算得分并归一化


一、矩阵正向化

1.极小型转化成极大型

x_return = max(x)-x; 
% x为处理的列向量,max(x)取得列向量中的最大值
% 广播机制使得max(x)扩充为和x同型的列向量

2.中间型转换成极大型

距离best最远的为0分,best为1分,根据xi距离best的距离换算得分,这样就变成了极大型

best = input('请输入中间值: ');
M = max( abs(x-best) ); % |列向量中的元素-best|,取其中的最大值
x_return = 1 - abs(x-best) / M;

3.区间型转换成极大型

与中间型转换的方法相同,就是把中间型的点变成一个区间,区间内为1分,区间外根据距离打分

size_x = size(x, 1); % 获取x有多少个元素
bounds = input("请输入区间上下界: "); % 获得区间范围
left = bounds(1); % 获取上界
right = bounds(2); % 获取下界
M = max([left-min(x), max(x)-right]);
x_return = ones(size_x, 1); % 创建一个size行1列的矩阵
for i = 1: size_x
    if x(i) < left % 在区间左侧
        x_return(i) = 1 - (left - x(i)) / M;
    elseif x(i) > right % 在区间右侧
        x_return(i) = 1 - (x(i) - right) / M;
    else % 在区间内
        x_return(i) = 1;
    end

二、正向化矩阵标准化

标准化的是为了消除不同指标量纲的影响

D = X ./ repmat(sum(X.*X) .^ 0.5, r, 1);
disp("标准化后的矩阵为: ")
disp(D)

三、计算得分并归一化

计算得分的逻辑:一个指标中最低为0分,最高为1分,中间值根据距离打分

这也就是TOPSIS被称为优劣解距离法的原因

归一化是为了让结果更加清晰

D_max = max(D); % D矩阵中的最大值
D_min = min(D); % D矩阵中的最小值
weigh = input("请输入各项指标的权重(例如[0.4, 0.3, 0.2, 0.1], 没有请输入0): ");
if sum(weigh) == 0 % 不进行权重计算
    weigh = 1;
    % 或者weigh = ones(1,c) ./ c
else
    while true
        if sum(weigh)-1 < 0.000001 && size(weigh, 2) == c && size(weigh, 1) == 1
            break % 权重输入正确则跳出循环
        else
            weigh = input('输入权重有误,请重新输入: ');
        end
    end
end
S_P = sum(weigh .* (D_max - D).^2, 2) .^ 0.5; % 与最大值的距离
S_N = sum(weigh .* (D_min - D).^2, 2) .^ 0.5; % 与最小值的距离
S = S_N ./ (S_P + S_N); % 得分
disp('最后的得分为:')
final_S = S / sum(S) % 进行归一化
[sorted_S,index] = sort(final_S ,'descend') % 排降序

总代码

主函数

clear;clc
load data_water_quality.mat % 导入数据


 判断是否需要正向化
[r, c] = size(X); % 获取矩阵的行r和列c
disp(['共有' num2str(r) '个评价对象, ' num2str(c) '个评价指标']); % 多个字符串要用[]括起来,进行字符串拼接必须使用单引号,字符串之间隔开
Position = input("请输入需要正向化的列,如2、3列则输入[2,3],若没有则输入0: "); % 获取输入
if Position ~= 0
    Type = input("请输入这些列的处理类型(1:极小型, 2:中间型, 3:区间型):");
    for i = 1:size(Position, 2) % 获取需要处理的列数,处理这么多列就需要循环这么多次
        X(:, Position(i)) = Positivization(X(:,Position(i)),Type(i),Position(i));
        % Positivization为自己写的正向化的函数,
        % Position(i)是X中的需要处理的列索引
        % X(:,Position(i))是矩阵X中列索引的列向量
        % Type(i)是处理类型
        % 该函数的返回值是处理好的列向量,将X原本的列向量覆盖
    end
    disp("正向化后的矩阵X = ");
    disp(X);
end


正向化矩阵标准化
D = X ./ repmat(sum(X.*X) .^ 0.5, r, 1);
disp("标准化后的矩阵为: ")
disp(D)


计算得分并归一化
D_max = max(D); % D矩阵中的最大值
D_min = min(D); % D矩阵中的最小值
weigh = input("请输入各项指标的权重(例如[0.4, 0.3, 0.2, 0.1], 没有请输入0): ");
if sum(weigh) == 0 % 不进行权重计算
    weigh = 1;
    % 或者weigh = ones(1,c) ./ c
else
    while true
        if sum(weigh)-1 < 0.000001 && size(weigh, 2) == c && size(weigh, 1) == 1
            break % 权重输入正确则跳出循环
        else
            weigh = input('输入权重有误,请重新输入: ');
        end
    end
end
S_P = sum(weigh .* (D_max - D).^2, 2) .^ 0.5; % 与最大值的距离
S_N = sum(weigh .* (D_min - D).^2, 2) .^ 0.5; % 与最小值的距离
S = S_N ./ (S_P + S_N); % 得分
disp('最后的得分为:')
final_S = S / sum(S) % 进行归一化
[sorted_S,index] = sort(final_S ,'descend') % 排降序

正向化函数Position

function x_return = Positivization(x,type,i)
    if type == 1 % 极小型
        disp(['第' num2str(i) '列是极小型,正在正向化'] )
        x_return = max(x)-x;
        disp(['第' num2str(i) '列极小型正向化处理完成'])
        disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
    elseif type == 2 % 中间型
        disp(['第' num2str(i) '列是中间型,正在正向化'] )
        best = input('请输入中间值: ');
        M = max(abs(x-best));
        x_return = 1 - abs(x-best) / M;
        disp(['第' num2str(i) '列中间型正向化处理完成'])
        disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
    elseif type == 3 % 区间型
        disp(['第' num2str(i) '列是区间型,正在正向化'] )
        size_x = size(x, 1); % 获取x有多少个元素
        bounds = input("请输入区间上下界: "); % 获得区间范围
        left = bounds(1); % 获取上界
        right = bounds(2); % 获取下界
        M = max([left-min(x), max(x)-right]);
        x_return = ones(size_x, 1); % 创建一个size行1列的矩阵
        for i = 1: size_x
            if x(i) < left % 在区间左侧
                x_return(i) = 1 - (left - x(i)) / M;
            elseif x(i) > right % 在区间右侧
                x_return(i) = 1 - (x(i) - right) / M;
            else % 在区间内
                x_return(i) = 1;
            end
        end
        disp(['第' num2str(i) '列区间型正向化处理完成'])
        disp('~~~~~~~~~~~~~~~~~~~~分界线~~~~~~~~~~~~~~~~~~~~')
    else % 指标输入错误
        disp("指标输入错误,请重新输入")
    end

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值