TOPSIS法(優劣解距離法)筆記

TOPSIS法 什麼時候用?

TOPSIS法 是根據有限個評價對象與理想化目標的接近程度進行排序的方法,是在現有的對象中進行相對優劣的評價
【其中最優解的各指標值都達到各評價指標的最優值,最劣解的各指標值都達到各評價指標的最差值】

TOPSIS法 特別適合具有多組評價對象時,要求通過檢測評價對象與最優解、最劣解的距離來進行排序

作業解答

如何改編代碼,使用戶能選擇是否加入指標的權重計算?

% % % % % % % % % % % % % % % % % % % % % % % 舉個例子 % % % % % % % % % % % % % % % % % % % % % % % 

% 假如原始數據爲:
A = [1, 2, 3;
     2, 4, 6]
   
% 權重矩陣爲:
B = [ 0.2, 0.5 ,0.3 ] 

% 加權後輸出:
0.2000    1.0000    0.9000
0.4000    2.0000    1.8000		% 加權後的矩陣 C

% 簡約的代碼如下:
C = A;
for i = 1: size(A,2)
    C(:,i) = C(:,i) .* B(i);
end
disp(C)


% % % % % % % % % % % % % % % % % % % % % % % 正式代碼 % % % % % % % % % % % % % % % % % % % % % % % 

disp('請輸入是否需要增加權重向量,需要輸入1,不需要輸入0')
Judge = input('請輸入是否需要增加權重: ');
if Judge == 1
    disp(['如果你有3個指標,你就需要輸入3個權重,例如它們分別爲0.25,0.25,0.5, 則你需要輸入[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

TOPSIS法的順序

正向化(每一列都轉爲極大型)
標準化(每一個元素都被標準化處理)
歸一化(每一列的和都爲 1 )
計算權重(求每一行的和)

下圖引用自 數學建模優劣解距離算法——Topsis模型
在這裏插入圖片描述
在這裏插入圖片描述

什麼時候用熵權法?

可以用熵值來判斷某個指標的離散程度,其信息熵值越小,指標的離散程度越大, 該指標對綜合評價的影響(即權重)就越大,因此,可利用信息熵這個工具,計算出各個指標的權重【如果某項指標的值全部相等,則該指標在綜合評價中不起作用】

對於一些數據容易獲取的分析,個人覺得熵值法可靠一些
對於數據比較難獲取且存在相關及共線性問題的話建議採取主成分分析法(第14講學)

TOPSIS法的代碼部分

%%  第一步:把數據複製到工作區,並將這個矩陣命名爲 X
load data_water_quality.mat          % 數據的名字叫 data_water_quality


%%  第二步:判斷是否需要正向化
[n,m] = size(X);
disp(['共有' num2str(n) '個評價對象, ' num2str(m) '個評價指標']) 
Judge = input(['這' num2str(m) '個指標是否需要經過正向化處理,需要請輸入1 ,不需要輸入0:  ']);

if Judge == 1
    Position = input('請輸入需要正向化處理的指標所在的列,例如第2、3、6三列需要處理,那麼你需要輸入[2,3,6]: ');%[2,3,4]
    disp('請輸入需要處理的這些列的指標類型(1:極小型, 2:中間型, 3:區間型) ')
    Type = input('例如:第2列是極小型,第3列是區間型,第6列是中間型,就輸入[1,3,2]:  '); % [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


%% 第三步:對正向化後的矩陣進行標準化
Z = X ./ repmat(sum(X.*X) .^ 0.5, n, 1);
disp('標準化矩陣 Z = ')
disp(Z)


%% 第四步:讓用戶判斷是否需要增加權重(可以自己決定權重,也可以用熵權法確定權重)
disp("請輸入是否需要增加權重向量,需要輸入1,不需要輸入0")
Judge = input('請輸入是否需要增加權重: ');
if Judge == 1
    Judge = input('使用熵權法確定權重請輸入1,否則輸入0: ');
    if Judge == 1
        if sum(sum(Z<0)) >0   % 如果之前標準化後的Z矩陣中存在負數,則重新對X進行標準化
            disp('原來標準化得到的Z矩陣中存在負數,所以需要對X重新標準化')
            for i = 1:n
                for j = 1:m
                    Z(i,j) = [X(i,j) - min(X(:,j))] / [max(X(:,j)) - min(X(:,j))];
                end
            end
            disp('X重新進行標準化得到的標準化矩陣Z爲:  ')
            disp(Z)
        end
        weight = Entropy_Method(Z);
        disp('熵權法確定的權重爲:')
        disp(weight)
    else
        disp(['如果你有3個指標,你就需要輸入3個權重,例如它們分別爲0.25,0.25,0.5, 則你需要輸入[0.25,0.25,0.5]']);
        weight = input(['你需要輸入' num2str(m) '個權數。' '請以行向量的形式輸入這' num2str(m) '個權重: ']);
        OK = 0;  % 用來判斷用戶的輸入格式是否正確
        while OK == 0 
            if abs(sum(weight) -1)<0.000001 && size(weight,1) == 1 && size(weight,2) == m  % 注意浮點數
                OK =1;
            else
                weight = input('你輸入的有誤,請重新輸入權重行向量: ');
            end
        end
    end
else
    weight = ones(1,m) ./ m ; %如果不需要加權重就默認權重都相同,即都爲1/m
end


%% 第五步:計算與最大值的距離和最小值的距離,並算出得分
D_P = sum([(Z - repmat(max(Z),n,1)) .^ 2 ] .* repmat(weight,n,1) ,2) .^ 0.5;   % D+ 與最大值的距離向量
D_N = sum([(Z - repmat(min(Z),n,1)) .^ 2 ] .* repmat(weight,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')

切記不能直接用於論文中,要根據題目適當的修改,避免查重

TOPSIS法的評估

Topsis法 的優點:
(1) 避免了數據的主觀性,不需要目標函數,不用通過檢驗,而且能夠很好的刻畫多個影響指標的綜合影響力度
(2) 對於數據分佈及樣本量、指標多少無嚴格限制,既適於小樣本資料,也適於多評價單元、多指標的大系統,較爲靈活、方便
Topsis法 的缺點:
(1) 需要的每個指標的數據,對應的量化指標選取會有一定難度
(2) 不確定指標的選取個數爲多少適宜,才能夠去很好刻畫指標的影響力度
(3) 必須有兩個以上的研究對象纔可以進行使用

其他文件

%% Entropy_Method.m       % 是熵權法計算權重的函數

function [W] = Entropy_Method(Z)
    [n,m] = size(Z);
    D = zeros(1,m);  % 初始化保存信息效用值的行向量
    for i = 1:m
        x = Z(:,i);  % 取出第i列的指標
        p = x / sum(x);
        % 注意,p有可能爲0,此時計算ln(p)*p時,Matlab會返回NaN,所以這裏我們自己定義一個函數
        e = -sum(p .* mylog(p)) / log(n); % 計算信息熵
        D(i) = 1- e; % 計算信息效用值
    end
    W = D ./ sum(D);  % 將信息效用值歸一化,得到權重    
end



%% mylog.m       % 用於替代MATLAB中的log函數,因爲計算熵權法時需要判斷 p = 0

function [lnp] =  mylog(p)
n = length(p);   % 向量的長度
lnp = zeros(n,1);   % 初始化最後的結果
    for i = 1:n   % 開始循環
        if p(i) == 0   % 如果第i個元素爲0
            lnp(i) = 0;  % 那麼返回的第i個結果也爲0
        else
            lnp(i) = log(p(i));  
        end
    end
end



%% Positivization.m       % 是處理矩陣正向化的函數

function [posit_x] = Positivization(x,type,i)
    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向量中是否有除了1、2、3之外的其他值')
    end
end



%% Min2Max.m 、Mid2Max.m 、Inter2Max.m           % 處理極小型、中間型、區間型的函數

function [posit_x] = Min2Max(x)          % 極小型
    posit_x = max(x) - x;
end

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

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);
    % 初始化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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章