層次分析法(詳解)


注:文章內容主要參閱 《matlab數學建模算法實例與分析》,部分圖片來源於WIKI
文章分為2部分:
1第一部分以通俗的方式簡述一下層次分析法的基本步驟和思想
2第二部分介紹一下我們隊伍數學建模過程中,對層次分析法的應用,中間有些地方做了不嚴謹的推理,例如關於一致性的檢驗,如有人發現不正確,希望可以指正

第一部分:

層次分析法(Analytic Hierarchy Process ,簡稱 AHP )是對一些較為復雜、較為模糊的問題作出決策的簡易方法,它特別適用於那些難於完全定量分析的問題。它是美國運籌學家T. L. Saaty 教授於上世紀 70 年代初期提出的一種簡便、靈活而又實用的多准則決策方法。

人們在進行社會的、經濟的以及科學管理領域問題的系統分析中,面臨的常常是一個由相互關聯、相互制約的眾多因素構成的復雜而往往缺少定量數據的系統。層次分析法為這類問題的決策和排序提供了一種新的、簡潔而實用的建模方法。 


運用層次分析法建模,大體上可按下面四個步驟進行: 
(i )建立遞階層次結構模型; 
(ii )構造出各層次中的所有判斷矩陣; 
(iii )層次單排序及一致性檢驗; 
(iv )層次總排序及一致性檢驗。 

 

這四個步驟中,前兩個步驟最容易理解,后兩個步驟需要一點時間理解

 

首先從層次結構模型說起

層次分析法是用來根據多種准則,或是說因素從候選方案中選出最優的一種數學方法


最頂層是我們的目標,比如說選leader,選工作,選旅游目的地

中間層是判斷候選方物或人優劣的因素或標准

選工作時有:發展前途  ,待遇 ,工作環境等

選leader時有:年齡,經驗,教育背景,魅力

 

在分層以后,為了選出最優候選

給目標層分配值1.000

然后將這一值作為權重,分配給不同因素,對應因素的權重大小代表該因素在整個選擇過程中的重要性程度

然后對於候選方案,每一個標准再將其權重值分配給所有的候選方案,每一方案獲得權重值,來源於不同因素分得的權重值的和

 

如下圖:(alternative1)0.333=0.250/4(criterion1)+0.250/4(criterion2)+0.250/4(criterion3)+0.250/4(criterion4)

最終獲得的各個方案的的權重值的和依然為1


例如選工作時,待遇所占的比重為0.8, 有工作1,2,3候選,     如果工作1的待遇最高,工作2的待遇次之,工作3最差,則可將0.8的值按0.4,0.3,0.1分給工作1,2,3,

這不就是一個簡單的權重打分的過程嗎?為什么還要層次分析呢。這里就有兩個關鍵問題:

1每個准則(因素)權重具體應該分配多少

2每一個候選方案在每一個因素下又應該獲得多少權重

 

這里便進入層次分析法的第二個步驟,也是層次分析法的一個精華(構造比較矩陣(判斷矩陣)comparison matrix):

 

首先解決第一個問題:每個准則(因素)權重具體應該分配多少?

如果直接要給各個因素分配權重比較困難,在不同因素之間兩兩比較其重要程度是相對容易的


 

現在將不同因素兩兩作比獲得的值aij  填入到矩陣的 i 行 j 列的位置,則構造了所謂的比較矩陣,對角線上都是1, 因為是自己和自己比

這個矩陣容易獲得,我們如何從這一矩陣獲得對應的權重分配呢

這里便出現了一個比較高級的概念,正互反矩陣和一致性矩陣

首先正互反矩陣的定義是:

 

我們目前構造出的矩陣很明顯就是正互反矩陣

 

而一致性矩陣的定義是:


這里我們構造出的矩陣就不一定滿足一致性,比如我們做因素1:因素2= 4:1  因素2:因素3=2:1    因素1:因素3=6:1(如果滿足一致性就應該是8:1),我們就是因為難以確定各因素比例分配才做兩兩比較的,如果認為判斷中就能保證一致性,就直接給出權重分配了

 

到了關鍵部分,一致性矩陣有一個性質可以算出不同因素的比例

 


這里的w就是我們想要知道的權重,所以通過 求比較矩陣的最大特征值所對應的特征向量,就可以獲得不同因素的權重,歸一化一下(每個權重除以權重和作為自己的值,最終總和為1)就更便於使用了。(實際上寫這篇博客就是因為,重新翻了線代的書才好不容易理解這里的,就想記錄下來)

 

這里補充一點線性代數的知識:

    n階矩陣有n個特征值,每個特征值對應一個n維特征列向量,特征值和特征向量的計算方法這里就省略了,反正書中的程序是直接用matlab 的eig函數求的

 

這里不能忘了,我們給出的比較矩陣一般是不滿足一致性的,但是我們還是把它當做一致矩陣來處理,也可以獲得一組權重,但是這組權重能不能被接受,需要進一步考量

例如在判斷因素1,2,3重要性時,可以存在一些差異,但是不能太大,1比2重要,2比3 重要,1和3比時卻成了3比1重要,這顯然不能被接受

 

於是引入了一致性檢驗:

          一致性的檢驗是通過計算一致性比例CR 來進行的

          

          當 10 . 0 < CR 時,認為判斷矩陣的一致性是可以接受的,否則應對判斷矩陣作適當修正。 

 

CI的值由判斷矩陣計算獲得,RI的值查表獲得,具體的計算公式這里就略去,重點是理解為什么要做一致性檢驗

 

 

接下來解決第二個問題:每一個候選方案在每一個因素下又應該獲得多少權重

 

這里則需要將不同候選方案,在不同因素下分別比較,具體的比較方法,還是使用比較矩陣,只不過之前准則層的比較矩陣比較的對象是因素,這里比較的是某一因素下,候選方案的優劣, n個因素則需構造出來n個比較矩陣

例如在工作環境的因素下,工作1與工作2相比為 :4:2,工作2與工作3=2:1  工作1:工作3=6:1.,這樣構造一個矩陣,再用之前的一致性矩陣的方法就可以求出一個權重,然后相對應因素(這里是工作環境)所擁有的權值就可以按這個權重比例分配給不同候選物或人。

 

其他因素同理

 

 

至此兩個問題就都得到了解決

最終將每個候選物、人從不同因素獲得的權值求和,就可以得到不同候選對於目標層的權值大小,繼而可以根據值的大小,來選出優劣

 

對於第一部分的總結:

         通過對層次分析法的基本了解,不難發現層次分析法對人們的思維過程進行了加工整理,提出了一套系統分析問題的方法,為
科學管理和決策提供了較有說服力的依據,但很明顯的缺點是,整個分析過程似乎都是依賴於人的主觀判斷思維,一來不夠客觀,二來兩兩比較全部人為完成,還是非常耗費精力的,尤其是當候選方案比較多的時候

 

 

文章的第二部分:


層次分析法的變形應用(也可能本來就是這樣用的,只不過參考書上沒這樣說,外語
論文沒細看)解決最優教練選擇問題

 

目標:選最優教練

 

准則:  職業生涯所帶隊伍的勝率      

職業生涯所帶隊伍的勝場            

從教時長(年)          

職業生涯所帶隊伍獲獎狀況(化成分數)

  

候選:  眾多教練

 

准則層的比較矩陣好構造 ,作6次兩兩比較,就可以獲得4*4的比較矩陣

 

問題在於候選層的比較矩陣怎么獲得,有4000個教練的話,得比4000*3999次,這里就不必人為比較了,引入定量的數據用程序控制作比即可

 

勝率因素下就用勝率兩兩作比構造矩陣,從教時長因素下就用年長來做比

 

這里又有兩點可以注意:

1.不同因素下數據的量綱和性質不一樣,直接用數據作比來分配,不一定合適,比如勝率越要接近1越難,0.7比勝率0.5  和勝率0.9比0.7  ,后者比值比前者小,這顯然不合適。建模中我們結合了冪函數和對數函數處理。

 

2.這里的用定量數據作比獲得的矩陣顯然滿足一致性要求,不需要做一致性檢驗(想做還不好做,計算CR的值要有RI,RI的值查表只給出9個,計算4000個教練,需要4000個RI呢)

 

綜上就對層次分析法完成了定性定量結合的應用,以及對多個候選方案的比較(其實只是就是用程序控制數據作比,我們水平有限,能成功應用該方法已經不容易了)

 

很遺憾的是比賽時編寫的代碼存放的優盤不慎丟失, 沒有辦法把代碼共享出來, 這里只能將書中的代碼貼出。比賽建模時, 就是在這個代碼基礎上進行修改實現。 只要理解了下列代碼,編寫符合自己需求的程序, 應當是水到渠成的事。

 

 代碼:(對應於文章第一部分選 Leader 的內容):

 

clc,clear
fid=fopen('txt3.txt','r');
n1=6;n2=3;
a=[];
for i=1:n1
    tmp=str2num(fgetl(fid));
    a=[a;tmp]; %讀准則層判斷矩陣
end
for i=1:n1
    str1=char(['b',int2str(i),'=[];']);
    str2=char(['b',int2str(i),'=[b',int2str(i),';tmp];']);
    eval(str1);
    for j=1:n2
        tmp=str2num(fgetl(fid));
        eval(str2); %讀方案層的判斷矩陣
    end
end
ri=[0,0,0.58,0.90,1.12,1.24,1.32,1.41,1.45]; %一致性指標
[x,y]=eig(a);  % matlab eig(a) 返回矩陣的特征值和特征向量, 這里的 x 為矩陣 a 的 n 個特征向量, y 為矩陣 a 的 n 個特征值
lamda=max(diag(y));  %  eig 函數返回的 y 是矩陣形式保存的, dig(y) 提取對角線上的n 個特征值到一個數組中, 求出最大特征值 lamda
num=find(diag(y)==lamda);  % 返回最大特征的索引
w0=x(:,num)/sum(x(:,num));  % x( :num) 為最大特征值所對應的那一列特征向量。 w0 中准則層計算出的 包含歸一化后的n 個權重值
cr0=(lamda-n1)/(n1-1)/ri(n1)

for i=1:n1 % 循環 n 個維度, 針對每個維度, 都計算一次方案層的比較矩陣及其權重值
    [x,y]=eig(eval(char(['b',int2str(i)])));
    lamda=max(diag(y));
    num=find(diag(y)==lamda);
    w1(:,i)=x(:,num)/sum(x(:,num));
    cr1(i)=(lamda-n2)/(n2-1)/ri(n2);
end
cr1, ts=w1*w0, cr=cr1*w0

 

txt3.txt 中的內容, 前6行為准則層的 6 x 6 比較矩陣, 后 18 行則為 6 個准則下, 各自的 3 x 3 的比較矩陣。 

1 1 1 4 1 1/2
1 1 2 4 1 1/2
1 1/2 1 5 3 1/2
1/4 1/4 1/5 1 1/3 1/3
1 1 1/3 3 1 1
2 2 2 3 3 1
1 1/4 1/2
4 1 3
2 1/3 1
1 1/4 1/5
4 1 1/2
5 2 1
1 3 1/3
1/3 1 1/7
3 7 1
1 1/3 5
3 1 7
1/5 1/7 1
1 1 7
1 1 7
1/7 1/7 1
1 7 9
1/7 1 1
1/9 1 1
再上一段 JAVA 代碼, 方便 JAVA 童鞋參考, 這部分僅僅展示了如何用JAVA 代碼進行准則層比較矩陣計算 。 

 

import org.apache.commons.math3.linear.*;


public class MatrixTester {
    public static void main(String[] args) {

        // Create a real matrix with two rows and three columns, using a factory
        // method that selects the implementation class for us.
        double[][] matrixData = {   {1d,    1d,     1d,     4d,     1d,     1d/2d},
                                    {1d,    1d,     2d,     4d,     1d,     1d/2d},
                                    {1d,    1d/2d,  1d,     5d,     3d,     1d/2d },
                                    {1d/4d, 1d/4d,  1d/5d,  1d,     1d/3d,  1d/3d },
                                    {1d,   1d,     1d/3d,  3d,     1d,     1d },
                                    {2d,    2d,     2d,     3d,     3d,     1d },
                                };
        RealMatrix m = MatrixUtils.createRealMatrix(matrixData);



        // One more with three rows, two columns, this time instantiating the
        // RealMatrix implementation class directly.
        double[][] matrixData2 = {{1d, 2d}, {2d, 5d}, {1d, 7d}};
        RealMatrix n = new Array2DRowRealMatrix(matrixData2);

        // Note: The constructor copies  the input double[][] array in both cases.
        // Now multiply m by n
//        RealMatrix p = m.multiply(n);
//        System.out.println(p.getRowDimension());    // 2
//        System.out.println(p.getColumnDimension()); // 2
//
//        // Invert p, using LU decomposition
//        RealMatrix pInverse = new LUDecomposition(p).getSolver().getInverse();


        RealMatrix D = new EigenDecomposition(m).getD();
        RealMatrix V = new EigenDecomposition(m).getV();

        for(int i=0; i<D.getRowDimension();i++)
        {
            System.out.println(D.getRowMatrix(i));
        }

        for(int i=0; i<V.getRowDimension();i++)
        {
            System.out.println(V.getRowMatrix(i));
        }

        // 特征值
        double maxLamda;
        int columIndexForMaxLamda=0;
        maxLamda=D.getEntry(0,0);

        for(int i =0, j=0; i<D.getRowDimension()&&j<D.getColumnDimension();i++,j=i)
        {
            double lamda = D.getEntry(i,j);
            if(maxLamda<lamda)
            {
                maxLamda=lamda;
                columIndexForMaxLamda = j;
            }
            System.out.println(lamda);
        }

        // 輸出尚未做歸一化 w1, w2, w3, w4, w5, w6 , 
        System.out.println(V.getColumnMatrix(columIndexForMaxLamda));

    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM