jjzjj

TOPSIS (优劣解距离法)

虚心求知的熊 2024-05-12 原文

文章目录

一、TOPSIS 简介

  • TOPSIS 是一种常用的综合评价方法,可以充分利用 原始数据 的信息,其结果可以精确地反映各评价方案之间的差距。
  • TOPSIS 是一种逼近于理想解的排序法,该方法只要求各效用函数具有单调递增(或递减)性就行。
  • TOPSIS 是多目标决策分析中一种常用的有效方法,又称为优劣解距离法。
  • TOPSIS 对样本容量没有严格限制,数据计算简单易行,无需数据检验。

二、TOPSIS 步骤

1:将原始矩阵正向化,得到正向化矩阵

1.1 指标类型

指标名称指标特点例子
极大型(效益性)指标越大(多)越好成绩、GDP增速、企业利润
极小型(成本型)指标越小(少)越好费用、坏品率、污染程度
中间型指标越接近某个值越好水质量评估时的PH值
区间型指标落在某个区间最好体温、水中植物性营养物量

1.2 正向化公式

正向化就是将原始数据指标都转化为极大型指标。

符号含义
max一列当中最大的元素
xbest区间最好的值
a区间下限
b区间上限
  • 极小型指标转换为极大型指标:max−x,如果所有的元素均为正数,那么也可以使用:1 / x 。
  • 中间型指标转换为极大型指标:
  • 区间型指标转换为极大型指标:

2. 正向化矩阵标准化

标准化的目的是消除不同指标量纲的影响。
假设有 n 个要评价对象,m个评价指标(已经正向化了)构成的正向化矩阵如下:

那么,对其标准化的矩阵记为 Z ,Z 当中的每一个元素:
(每一个元素 / 其所在列的元素的平方和的开方)
得到标准化矩阵 Z :

3. 计算得分并归一化

3.1 方法

3.2 步骤

  • 定义各个指标的最大值向量与最小值向量
    最大值向量:
    最小值向量:
  • 定义各个对象与最大值、最小值之间的距离
  • 计算各个评价对象的分数
    得分:(显然 0 ≤ Si ≤ 1 ,且 Si 越大,Di+越小,即越接近最大值)
  • 归一化:每一部分为该部分与所有部分和的比值。归一化的目的是为了让我们的结果更加容易解释。例如将得分归一化后可限制在 0-1 这个区间,对区间内每一个得分,都可以容易的得到起所处的比例位置。
  • 分数最高即为最优方案或对象

三、TOPSIS 模型实现

关于具体实现,需要有一定的数据,这里实现所选用的数据如下:

河流含氧量(ppm)PH值细菌总数(个/mL)植物性营养物量
A4.696.595111.94
B2.037.86196.46
C9.116.31468.91
D8.617.054626.43
E7.136.55023.57
F2.396.773824.62
G7.696.79386.01
H9.36.812731.57
I5.457.62518.46
J6.197.27177.51
K7.937.5396.52
L4.47.281725.3
M7.468.242314.42
N2.015.554726.31
O2.046.42317.91
P7.736.145215.72
Q6.357.582529.46
R8.298.413912.02
S3.547.27543.16
T7.446.26828.41

1. MATLAB 实现

1.1 把数据复制到工作区,并将这个矩阵命名为X

  • 在工作区右键,点击新建(Ctrl+N),输入变量名称为X。
  • 在Excel中复制数据,再回到Excel中右键,点击粘贴Excel数据(Ctrl+Shift+V)。
  • 关掉这个窗口,点击X变量,右键另存为,保存为mat文件(下次就不用复制粘贴了,只需使用load命令即可加载数据)。
  • 注意,代码和数据要放在同一个目录下哦。
clear;clc
load data_water_quality.mat

1.2 判断是否需要正向化

  • 判断是否需要正向化,只有当存在非极大型指标时才需要正向化处理。
[n,m] = size(X);
disp(['共有' num2str(n) '个评价对象, ' num2str(m) '个评价指标']) 
Judge = input(['这' num2str(m) '个指标是否需要经过正向化处理,需要请输入1 ,不需要输入0:  ']);
  • 如果需要正向化处理,输入1。
if Judge == 1
    Position = input('请输入需要正向化处理的指标所在的列,例如第236三列需要处理,那么你需要输入[2,3,6]: '); %[2,3,6]
    disp('请输入需要处理的这些列的指标类型(1:极小型, 2:中间型, 3:区间型) ')
    Type = input('例如:第2列是极小型,第3列是区间型,第6列是中间型,就输入[1,3,2]:  '); %[2,1,3]
    % 注意,Position和Type是两个同维度的行向量
    for i = 1 : size(Position,2)  %这里需要对这些列分别处理,因此我们需要知道一共要处理的次数,即循环的次数
        X(:,Position(i)) = Positivization(X(:,Position(i)),Type(i),Position(i));
    % Positivization是我们自己定义的函数,其作用是进行正向化,其一共接收三个参数
    % 第一个参数是要正向化处理的那一列向量 X(:,Position(i))   回顾上一讲的知识,X(:,n)表示取第n列的全部元素
    % 第二个参数是对应的这一列的指标类型(1:极小型, 2:中间型, 3:区间型)
    % 第三个参数是告诉函数我们正在处理的是原始矩阵中的哪一列
    % 该函数有一个返回值,它返回正向化之后的指标,我们可以将其直接赋值给我们原始要处理的那一列向量
    end
    disp('正向化后的矩阵 X =  ')
    disp(X)
end
  • 可以得到正向化后的矩阵为:
含氧量(ppm)PH值细菌总数(个/mL)植物性营养物量
4.690.71724137931
2.030.406896552350.694036301
9.110.52413793180.905790838
8.610.96551724180.444252377
7.130.65517241440.691443388
2.390.84137931160.600691443
7.690.855172414160.65514261
9.30.868965517270
5.450.572413793491
6.190.813793103370.784788245
7.930.634482759450.699222126
4.40.806896552370.541918755
7.460.144827586311
2.01070.454624028
2.040.586206897311
7.730.40689655221
6.350.6290.182368194
8.290.027586207151
3.540.81379310300.408815903
7.440.489655172460.273120138

1.2.1 极小型指标正向化

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

1.2.2 中间型指标正向化

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

1.2.3 区间型指标正向化

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

1.2.4 指标正向化处理

% function [输出变量] = 函数名称(输入变量)  
% 函数的中间部分都是函数体
% 函数的最后要用end结尾
% 输出变量和输入变量可以有多个,用逗号隔开
% function [a,b,c]=test(d,e,f)
%     a=d+e;
%     b=e+f;
%     c=f+d;
% end
% 自定义的函数要单独放在一个m文件中,不可以直接放在主函数里面(和其他大多数语言不同)
 
function [posit_x] = Positivization(x,type,i)
% 输入变量有三个:
% x:需要正向化处理的指标对应的原始列向量
% type: 指标的类型(1:极小型, 2:中间型, 3:区间型)
% i: 正在处理的是原始矩阵中的哪一列
% 输出变量posit_x表示:正向化后的列向量
    if type == 1  %极小型
        disp(['第' num2str(i) '列是极小型,正在正向化'] )
        posit_x = Min2Max(x);  %调用Min2Max函数来正向化
        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向量中是否有除了123之外的其他值')
    end
end 

1.3 对正向化后的矩阵进行标准化

Z = X ./ repmat(sum(X.*X) .^ 0.5, n, 1);
disp('标准化矩阵 Z = ')
disp(Z)
  • 标准化后的矩阵为:
含氧量(ppm)PH值细菌总数(个/mL)植物性营养物量
0.1621859160.2482552780.0245440350.306457563
0.0701998740.1408371290.2863470710.212692674
0.3150349040.1814173190.0654507590.277586453
0.2977442940.3341897980.0654507590.136144501
0.246564090.2267716480、032725380.211898056
0.0826491130.2912225380.1309015180.184086436
0.2659295730.2959966780.1309015180.200773408
0.3216053350.3007708180.2208963120
0.1884676430.1981268090.40088590.306457563
0.2140577450.2816742580.3027097610.240504293
0.2742290650.2196104380.368160520.214281909
0.1521573630.2792871880.3027097610.166075101
0.2579758920.050128470.2536216920.306457563
0.0695082500.0572694140.139322972
0.0705456860.2029009490.2536216920.306457563
0.2673128220.1408371290.016362690.306457563
0.219590740.2076750880.2372590020.055888112
0.2866783040.009548280.1227201730.306457563
0.1224175150.28167425800.125284726
0.2572842680.1694819690.3763418650.083699732

1.4 计算得分并归一化(计算与最大值的距离和最小值的距离,并算出得分)

D_P = sum([(Z - repmat(max(Z),n,1)) .^ 2 ],2) .^ 0.5;   % D+ 与最大值的距离向量
D_N = sum([(Z - repmat(min(Z),n,1)) .^ 2 ],2) .^ 0.5;   % D- 与最小值的距离向量
S = D_N ./ (D_P+D_N);    % 未归一化的得分
disp('最后的得分为:')
stand_S = S / sum(S)%归一化后的得分
%[sorted_S,index] = sort(stand_S ,'descend')
  • 得分排名情况:
河流D+D-Stand_S(归一化后得分)排名
K0.15790.52120.07021
J0.16830.49970.06842
I0.19040.55500.06813
L0.24710.45170.05914
T0.28550.46110.05655
G0.29770.42850.05396
O0.31930.44660.05337
M0.32620.44300.05278
H0.35700.45030.05109
D0.37700.43200.048810
C0.36980.41780.048511
B0.35000.38350.047812
Q0.34050.35370.046613
A0.41770.40590.045114
F0.38320.36880.044815
R0.42890.39530.043816
P0.43380.39130.043417
E0.40210.35880.043118
S0.48580.31280.035819
N0.56680.15060.019220

四、TOPSIS 模型优缺点

1. TOPSIS 法的优点

  • 避免了数据的主观性,不需要目标函数,不用通过检验,而且能够很好的刻画多个影响指标的综合影响力度。
  • 对于数据分布及样本量、指标多少无严格限制,既适于小样本资料,也适于多评价单元、多指标的大系统,较为灵活、方便。

2. TOPSIS 法的缺点

  • 需要的每个指标的数据,对应的量化指标选取会有一定难度。
  • 不确定指标的选取个数为多少适宜,才能够去很好刻画指标的影响力度。
  • 必须有两个以上的研究对象才可以进行使用

五、TOPSIS 模型优化

在 TOPSIS 当中,默认了各个评价指标所占的权重相同,但在实际的评价过程当中由于各种主观客观因素的影响,导致每一个评价指标所占的权重是有差异的。因此,对于 TOPSIS 模型的优化,可以从合理调整个评价指标所占权重入手。

1. 主观权重——层次分析法(AHP)

在此处只是简单介绍,详细介绍有时间的话会补充

  • 层次分析法是一个较为主观的评价方法,其在赋权得到权重向量时,主观因素占比很大。
  • 首先,分析系统中各因素之间的关系,建立系统的递阶层次结构。
  • 其次,对于同一层次的个元素关于上一层次中某一准则的重要性两两比较,构造两两比较矩阵(判断矩阵)。
  • 然后,由判断矩阵计算被比较元素对于该准则的相对权重,并进行 一致性检验(检验通过权重才能用)。
  • 最后,填充权重矩阵,根据矩阵计算得分,得出结果。
  • 权重矩阵填充方法
标度含义
1表示两个因素相比,具有同样重要性
3表示两个因素相比,一个因素比另一个因素稍微重要
5表示两个因素相比,一个因素比另一个因素明显重要
7表示两个因素相比,一个因素比另一个因素强烈重要
9表示两个因素相比,一个因素比另一个因素极端重要
2、4、6、8上述两相邻判断的中值
倒数A和B相比如果标度为3,那么B和A相比就是1/3
  • 判断矩阵实际情况下都是专家填的,但是很多时候大都是我们自己填的,最好有一些理论的依据支撑。
  • 判断矩阵当中,a[i][j] 表示:与指标 j 相比,i 的重要程度。

1.1 权重求解方法

(1) 算术平均法求权重

  • 将判断矩阵按照列归一化。
  • 将归一化的列相加(按行求和)。
  • 将相加后得到的向量中的每个元素除以 n 即可得到权重向量。

(2) 几何平均法求权重

  • 将A的元素按照行相乘得到一个新的列向量。
  • 将新的向量的每个分量开n次方。
  • 对该列向量进行归一化即可得到权重向量。

(3) 特征值法求权重

一致矩阵有一个特征值为 n,其余特征值均为 0。另外,我们很容易可以得到,特征值为 n 时,对应的特征向量刚好为:

在实际过程中建议综合三种方法求得的权重得到一个综合的权重向量更具有说服力。

2. 客观权重——熵权法

  • 熵权法就是根据一项指标的变化程度来分配权重的。
  • 第一步:判断输入的矩阵中是否存在负数,如果有则要重新标准化到非负区间(后面计算概率时需要保证每一个元素为非负数)。
  • 第二步:计算第 j 项指标下第 i 个样本所占的比重,并将其看作相对熵计算中用到的概率。
  • 第三步:计算每个指标的信息熵,并计算信息效用值,并归一化得到每个指标的熵权。

(1) 第一步

  • 假设有 n 个要评价的对象,m 个评价指标(已经正向化了)构成的正向化矩阵如下:
  • 设标准化矩阵为 Z ,Z 中元素记为 zij
  • 判断 Z 矩阵中是否存在着负数,如果存在的话,需要对 X 使用另一种标准化方法对矩阵 X 进行一次标准化得到 Z 矩阵,其标准化的公式为:
  • 这样可以保证 zij 在 [0,1] 区间,没有负数。

(2) 第二步

  • 假设有 n 个要评价的对象,m 个评价指标,且经过了上一步处理得到的非负矩阵为:
  • 计算概率矩阵 P ,其中 P 中每一个元素 Pij 的计算公式如下:
  • 保证每一列的加和为 1 ,即每个指标所对应的概率和为 1 。

(3) 第三步

  • 对于第 j 个指标而言,其信息嫡的计算公式为:

3. 优化结果

在各个对象与最大值、最小值之间的距离公式转变为:

有关TOPSIS (优劣解距离法)的更多相关文章

  1. 最新版人脸识别小程序 图片识别 生成二维码签到 地图上选点进行位置签到 计算签到距离 课程会议活动打卡日常考勤 上课签到打卡考勤口令签到 - 2

    技术选型1,前端小程序原生MINA框架cssJavaScriptWxml2,管理后台云开发Cms内容管理系统web网页3,数据后台小程序云开发云函数云开发数据库(基于MongoDB)云存储4,人脸识别算法基于百度智能云实现人脸识别一,用户端效果图预览老规矩我们先来看效果图,如果效果图符合你的需求,就继续往下看,如果不符合你的需求,可以跳过。1-1,登录注册页可以看到登录页有注册入口,注册页如下我们的注册,需要管理员审核,审核通过后才可以正常登录使用小程序1-2,个人中心页登录成功以后,我们会进入个人中心页我们在个人中心页可以注册人脸,因为我们做人脸识别签到,需要先注册人脸才可以进行人脸比对,进

  2. ruby - 在 Elasticsearch 中计算地理距离 - 2

    我在查询中使用geo_distancefilter和tire,它工作正常:search.filter:geo_distance,:distance=>"#{request.distance}km",:location=>"#{request.lat},#{request.lng}"我预计结果会以某种方式包括到我用于过滤器的地理位置的计算距离。有没有办法告诉elasticsearch在响应中包含它,这样我就不必在ruby​​中为每个结果计算它?==更新==我在谷歌群组中的foundtheanswer:search.sortdoby"_geo_distance","location"=>"

  3. ruby - 如何在没有 O^2 问题的情况下找到 Ruby 中一串二进制 bin 的最接近对(汉明距离)? - 2

    我有一个MongoDB,其中包含大约100万个文档。这些文档都有一个字符串,表示256位bin的1和0,例如:0110101010101010110101010101理想情况下,我想查询近似二进制匹配项。这意味着,如果这两个文件具有以下编号。是的,这就是汉明距离。Mongo当前不支持此功能。所以,我不得不在应用层做。因此,鉴于此,我试图找到一种方法来避免在文档之间进行单独的汉明距离比较。这使得基本上不可能有时间做这件事。我有很多内存。而且,在ruby​​中,似乎有一个很棒的gem(算法)可以创建许多树,但我似乎(还)没有一个可以减少我需要进行的查询数量。理想情况下,我想进行100万次查

  4. ruby - 计算 ruby 汉明距离的最有效方法? - 2

    在ruby​​中,计算两个无符号整数之间的位差(例如汉明距离)的最有效方法是什么?例如,我有整数a=2323409845和b=178264714​​4。它们的二进制表示是:a=10001010011111000110101110110101b=01101010010000010000100101101000a和b之间的位差是17..我可以对它们进行逻辑异或,但这会给我一个不同的整数!=17,然后我将不得不遍历结果的二进制表示并计算1的数量。计算位差的最有效方法是什么?现在,计算多个整数序列的位差的答案是否改变了?例如。给定2个无符号整数序列:x={2323409845,64176042

  5. ruby - 用 Ruby 测量两个字符串之间的距离? - 2

    我可以用Ruby测量两个字符串之间的距离吗?即:compare('Test','est')#Returns1compare('Test','Tes')#Returns1compare('Test','Tast')#Returns1compare('Test','Taste')#Returns2compare('Test','tazT')#Returns5 最佳答案 由于原生C绑定(bind),更加容易和快速:geminstalllevenshtein-ffigeminstalllevenshteinrequire'levenshte

  6. ruby - 如何在不使用 Google Maps API 的情况下计算两个 GPS 坐标之间的距离? - 2

    我想知道是否有一种方法可以在不依赖GoogleMapsAPI的情况下计算两个GPS坐标的距离。我的应用程序可能会收到float坐标,否则我将不得不对地址执行反向GEO。 最佳答案 地球上两个坐标之间的距离通常使用Haversineformula来计算.该公式考虑了地球形状和半径。这是我用来计算以米为单位的距离的代码。defdistance(loc1,loc2)rad_per_deg=Math::PI/180#PI/180rkm=6371#Earthradiusinkilometersrm=rkm*1000#Radiusinmeter

  7. 有符号距离场原理及实现源码 - 2

    有符号距离场(SDF:SignedDistanceField)是距离场的一种变体,它在3D(2D)空间中将位置映射到其到最近平面(边缘)的距离。距离场在图像处理、物理学和计算机图形学等许多研究中都有应用。在计算机图形的上下文中,距离场通常是有符号的,表示某个位置是否在网格内。在计算机图形学和游戏开发中,SDF显示出极大的通用性,它可以用于碰撞测试、网格表示、光线追踪等。此外,人们发现它在使用光线追踪渲染场景时也有一些好处(即,ray-marching)算法——几乎不需要额外成本就可以产生像软阴影和环境光遮蔽这样的阴影效果。这个项目是关于实时光线行进渲染器的从零开始的C++实现,它包括一个SDF

  8. javascript - d3.forcesimulation() 链接距离 - 2

    我在堆栈中查看了不同的链接距离,似乎为了改变链接距离,您需要实现一个函数,然后传递该函数以动态分配链接距离:functionlinkDistance(d){returnd.distance;}然后我认为我可以传递给svg,但返回函数错误而不是现有的linkdistance或distancevarlink=svg.selectAll(".link").data(bilinks).enter().append("path").style("stroke","#6b7071")//gunmetalgreylink.attr("class","link").linkDistance(linkD

  9. javascript - 如何获得两个div之间的距离 - 2

    所以我有一个div在另一个里面-我怎样才能得到它们之间的距离?我尝试了类似$('#child').parentsUntil($('#parent')).andSelf()的方法-但它返回的是对象,而不是距离。附言我需要它来按下其他按钮。 最佳答案 http://api.jquery.com/position/要获得您可以使用的左侧距离:vardistLeft=$('#child').position().left;这将返回以px为单位的相对于父级偏移量的距离如果您对元素的页面偏移感兴趣:varoffsLeft=$('#child')

  10. javascript - 对于字符串距离,是否有比 Levenshtein 更快(不太精确)的算法? - 2

    我想运行Levenshtein,但要快得多,因为它是我正在构建的实时应用程序。一旦距离大于10,它就会终止。 最佳答案 从评论来看,人们似乎对Sift3很满意.http://sift.codeplex.com 关于javascript-对于字符串距离,是否有比Levenshtein更快(不太精确)的算法?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/6178708/

随机推荐