R語言構建層次分析模型不看一下嗎~

R語言中文社群發表於2018-05-13

作者簡介

杜雨,EasyCharts團隊成員,R語言中文社群專欄作者,興趣方向為:Excel商務圖表,R語言資料視覺化,地理資訊資料視覺化。

個人公眾號:資料小魔方(微信ID:datamofang) ,“資料小魔方”創始人。 


精彩集錦

那些年倒騰的R語言學習筆記,全都在這裡了~

左手用R右手Python系列之——表格資料抓取之道

左手用R右手Python系列——迴圈中的錯誤異常規避

左手用R右手Python系列——異常捕獲與容錯處理

左手用R右手Python系列——任務進度管理

左手用R右手Python——CSS網頁解析實戰

左手用R右手Python系列17——CSS表示式與網頁解析

左手用R右手Python系列之——字串格式化進階

R語言資料分析筆記——Cohort 存留分析

左手用R右手Python系列之——字串格式化進階

R語言多工處理與並行運算包——foreach

R語言學習筆記之——資料處理神器data.table

ggplot2學習筆記——圖例系統及其調整函式

R語言構建RFM模型瞭解一下

點選圖片,檢視詳情

AHP (Analytic Hierarchy Process)層次分析法是美國運籌學家Saaty教授於二十世紀80年代提出的一種實用的多方案或多目標的決策方法。其主要特徵是,它合理地將定性與定量的決策結合起來,按照思維、心理的規律把決策過程層次化、數量化。

層次分析法的基本思路:先分解後綜合

首先將所要分析的問題層次化,根據問題的性質和要達到的總目標,將問題分解成不同的組成因素,按照因素間的相互關係及隸屬關係,將因素按不同層次聚集組合,形成一個多層分析結構模型,最終歸結為最低層(方案、措施、指標等)相對於最高層(總目標)相對重要程度的權值或相對優劣次序的問題。

用AHP分析問題大體要經過以下五個步驟:

(1)建立層次結構模型;
(2)構造判斷矩陣;
(3)層次單排序;
(4)一致性檢驗;
(5)層次總排序。

其中後三個步驟在整個過程中需要逐層地進行。

以下是一個情景案例:

假期你想要出去旅遊,現有三個目的地(方案):

古風古韻的西安(P1);
天府之國的成都(P2);
如詩如畫的杭州(P3)。

假如選擇的標準和依據(行動方案准則)有5個:

景色,費用,飲食,居住和旅途。

則常規思維的方式一般是:

1、先確定這些準則在心中的各自佔比的大小;
2、然後就每一準則將三個地點進行比較;
3、最後將這兩個層次的比較判斷進行綜合,做出選擇。

以下是根據分析思路構建的層次分析法結構模型:


以上結構模型中,我們需要比較準側層各個準則相對於目標的權重,同時也要比較方案層各個方案相對於準側層每一個準則的權重。

權重的判斷建立在專家打分的基礎上,即通過一組打分標準,來賦予單層各個指標的相對權重。

這裡的打分機制使用1~9標度法:

1代表兩個元素相比,具有相同的重要性;
3代表兩個元素相比,前者比後者稍重要;
5代表兩個元素相比,前者比後者明顯重要;
7代表兩個元素相比,前者比後者極其重要;
9代表兩個元素相比,前者比後者強烈重要

2,4,6,8表示上述相鄰判斷的中間值。


以上準則層的5個指標依次是:

景色:C1
費用:C2
居住:C3
飲食:C4
旅途:C5

相對於目標層:選擇旅遊地,進行兩兩比較打分。

    景色 費用 居住 飲食  旅途    C1  C2   C3  C4   C5

C1       1     1/2        4        3          3
C2       2      1          7        5         5
C3     1/4    1/7       1        1/2       1/3
C4     1/3    1/5       2        1          1
C5     1/3    1/5       2        1          1


構造所有相對於不同準則的方案層判斷矩陣

相對於景色
     P1    p2    p3
P1   1     2     5
P2  1/2    1     2
P3  1/5   1/2    1

相對於費用
     P1    p2    p3
P1   1    1/3   1/8
P2   3     1    1/3
P3   8     3     1

相對於居住
     P1    p2    p3
P1   1     1     3
P2   1     1     3
P3  1/3    1/3   1

相對於飲食
     P1    p2    p3
P1   1     3     4
P2  1/3    1     1
P3  1/4    1     1

相對於旅途

  P1 P2  P3

P1  1     1    1/4
P2  1     1    1/4
P3  4     4     4


以下是整個層次分析法的整個建模流程:


#清空R語言環境記憶體

rm(list = ls())gc()

#載入包

library("readxl")
library("dplyr")
library("magrittr")

準則層:

C1——景色

C2——費用

C3——居住

C4——飲食

C5——旅途


方案層:

P1——西安

P2——成都

P3——杭州


準則層與方案層的判定矩陣:(專(hu)家 (luan) 打 (tian) 分 (xie) )

#準則層判斷矩陣
data_C <- matrix(  c(1,2,1/4,1/3,1/3,1/2,1,1/7,1/5,1/5,4,7,1,2,3,3,5,1/2,1,1,3,5,1/3,1,1),  nrow = 5,  dimnames = list(c("C1","C2","C3","C4","C5"),c("C1","C2","C3","C4","C5")))

#景色判斷矩陣
data_B1 <- matrix(  c(1,1/2,1/5,2,1,1/2,5,2,1),  nrow = 3,  dimnames = list(c("P1","P2","P3"),c("P1","P2","P3")))

#費用判斷矩陣
data_B2 <- matrix(  c(1,3,8,1/3,1,3,1/8,1/3,1),  nrow = 3,  dimnames = list(c("P1","P2","P3"),c("P1","P2","P3")))

#居住判斷矩陣
data_B3 <- matrix(  c(1,1,1/3,1,1,1/3,3,3,1),  nrow = 3,  dimnames = list(c("P1","P2","P3"),c("P1","P2","P3")))

#飲食判斷矩陣
data_B4 <- matrix(  c(1,1/3,1/4,3,1,1,4,1,1),  nrow = 3,  dimnames = list(c("P1","P2","P3"),c("P1","P2","P3")))

#路途判斷矩陣
data_B5 <- matrix(  c(1,1,4,1,1,4,1/4,1/4,1),  nrow = 3,  dimnames = list(c("P1","P2","P3"),c("P1","P2","P3")))

準側層判別過程:

1、判斷矩陣歸一化:

Weigth_fun <- function(data){
 if(class(data) == 'matrix'){      data = data       } else {
     if ( class(data) == 'data.frame' & nrow(data) == ncol(data) - 1 & is.character(data[,1,drop = TRUE])){      data = as.matrix(data[,-1])    } else if (class(data) == 'data.frame' & nrow(data) == ncol(data)) {      data = as.matrix(data)    } else {
      stop('please recheck your data structure , you must keep a equal num of the row and col')    }      }  sum_vector_row    =  data %>% apply(2,sum)  decide_matrix     =  data %>% apply(1,function(x) x/sum_vector_row)   weigth_vector     =  decide_matrix %>% apply(2,sum)  result = list(decide_matrix = decide_matrix, weigth_vector  = weigth_vector/sum(weigth_vector ))
 return(result)}Weigth_fun(data_C)


2、輸出特徵向量λ

AW_Weight <- function(data){
 if(class(data) == 'matrix'){    data = data       } else {
     if ( class(data) == 'data.frame' & nrow(data) == ncol(data) - 1 & is.character(data[,1,drop = TRUE])){      data = as.matrix(data[,-1])    } else if (class(data) == 'data.frame' & nrow(data) == ncol(data)) {      data = as.matrix(data)    } else {
     stop('please recheck your data structure , you must keep a equal num of the row and col')    }      }  AW_Vector = data %*% Weigth_fun(data)$weigth_vector  λ = (AW_Vector/Weigth_fun(data)$weigth_vector) %>%  sum(.) %>% `/`(length(AW_Vector))  result = list(    AW_Vector = AW_Vector,    `∑AW/W`   = AW_Vector/Weigth_fun(data)$weigth_vector,    λ         =  λ  )  return(result)}AW_Weight(data_C)


3、一致性檢驗:

Consist_Test <- function(λ,n){  RI_refer =  c(0,0,0.52,0.89,1.12,1.26,1.36,1.41,1.46,1.49,1.52,1.54)  CI = (λ - n)/(n - 1)  CR = CI/(RI_refer[n])
 if (CR <= .1){    cat(" 通過一致性檢驗!",sep = " ")    cat(" Wi: ", round(CR,4), " ")  } else {    cat(" 請調整判斷矩陣!"," ")  }  return(CR)}Consist_Test(AW_Weight(data_C)$λ,5)

 通過一致性檢驗!

 Wi:  0.0163 

[1] 0.01627942


OutPut:


(利用上述各步程式碼,將準則層、方案層的所有權重向量、特徵值及一致性檢驗結果輸出)

#準則層:
rule_Weigth_C <- Weigth_fun(data_C)$weigth_vector   #準則層特徵向量
rule_λ_C      <- AW_Weight(data_C)$λ                #準則層特徵值
CR_C      <-  Consist_Test(AW_Weight(data_C)$λ,5)  #準則層一致性檢驗:
rule_Weigth_C1 <- Weigth_fun(data_B1)$weigth_vector   #方案層(for C1)特徵向量
rule_Weigth_C2 <- Weigth_fun(data_B2)$weigth_vector   #方案層(for C2)特徵向量
rule_Weigth_C3 <- Weigth_fun(data_B3)$weigth_vector   #方案層(for C3)特徵向量
rule_Weigth_C4 <- Weigth_fun(data_B4)$weigth_vector   #方案層(for C4)特徵向量
rule_Weigth_C5 <- Weigth_fun(data_B5)$weigth_vector   #方案層(for C5)特徵向量
scheme_λ_C1      <- AW_Weight(data_B1)$λ              #方案層(for C1)特徵值
scheme_λ_C2      <- AW_Weight(data_B2)$λ              #方案層(for C2)特徵值
scheme_λ_C3      <- AW_Weight(data_B3)$λ              #方案層(for C3)特徵值
scheme_λ_C4      <- AW_Weight(data_B4)$λ              #方案層(for C4)特徵值
scheme_λ_C5      <- AW_Weight(data_B5)$λ              #方案層(for C5)特徵值
CR_C1 <- Consist_Test(AW_Weight(data_B1)$λ,3)         #方案層(for C1)一致性檢驗
CR_C2 <- Consist_Test(AW_Weight(data_B2)$λ,3)         #方案層(for C2)一致性檢驗
CR_C3 <- Consist_Test(AW_Weight(data_B3)$λ,3)         #方案層(for C3)一致性檢驗
CR_C4 <- Consist_Test(AW_Weight(data_B4)$λ,3)         #方案層(for C4)一致性檢驗
CR_C5 <- Consist_Test(AW_Weight(data_B5)$λ,3)         #方案層(for C5)一致性檢驗

層次總排序:

all_matrix <- matrix(c(rule_Weigth_C1,rule_Weigth_C2,rule_Weigth_C3,rule_Weigth_C4,rule_Weigth_C5),nrow = 3)decide_result <- all_matrix %*% rule_Weigth_Cdimnames(decide_result) <- list(c("P1","P2","P3"),"score")       scoreP1 0.2990074
P2 0.2454134
P3 0.4555792
P3(杭州) > p1(西安) > P2(成都)

最終決策結果顯示,我們應該去的地方推薦優先順序分別為:杭州 > 西安 > 成都

備註(因為打分資料是虛構的,所以並沒有任何決策價值)


Python:


(備註:這裡只給出使用Python構造模型的工具程式碼,具體判定過程需要自己操作)

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time
import numpy   as np
import pandas  as pd import os
from scrapy.exceptions import DropItemnp.random.seed(233333)os.chdir('D:/R/File')
#!!!
#溫馨提示,這裡的函式是基於pandas資料框,
#如果直接構造的矩陣陣列,需要微調程式碼!
#判定矩陣歸一化

def Weight(data):    if data.shape[0] == data.shape[1] - 1 and data.iloc[:,0].dtype == 'object':        data = data.iloc[:,1:]        data.index = data.columns        elif data.shape[0] == data.shape[1]:        data.index = data.columns
   else:        
       raise DropItem("please recheck your data structure , you must keep a equal num of the row and col")    weigth_matrix  = data.loc[:,].values    weight_vector  = weigth_matrix/np.sum(data.loc[:,].values,0)    sum_vector_col = weight_vector.sum(axis = 1)
   return {
   "weigth_matrix":weigth_matrix,
   "weight_vector":sum_vector_col/sum_vector_col.sum()    }Weight(mydata)["weigth_matrix"]Weight(mydata)["weight_vector"]
#計算權重矩陣與特徵值、特徵向量
def AW_Weight(data):    if data.shape[0] == data.shape[1] - 1 and data.iloc[:,0].dtype == 'object':        data = data.iloc[:,1:]        data.index = data.columns        elif data.shape[0] == data.shape[1]:        data.index = data.columns
   else:
       raise DropItem("please recheck your data structure , you must keep a equal num of the row and col")    AW_Vector = np.dot(data.values,Weight(mydata)["weight_vector"])    λ = (AW_Vector/Weight(mydata)["weight_vector"]).sum()/len(AW_Vector)
   return dict(        AW_Vector = AW_Vector,        AW_Vector_w = AW_Vector/Weight(mydata)["weight_vector"],        λ = λ        )AW_Weight(mydata)["AW_Vector"]AW_Weight(mydata)["AW_Vector_w"]AW_Weight(mydata)["λ"]
#一致性檢驗
def Consist_Test(λ,n):    RI_refer =  [0,0,0.52,0.89,1.12,1.26,1.36,1.41,1.46,1.49,1.52,1.54]    CI = (λ - n)/(n - 1)    CR = CI/(RI_refer[n-1])
   if (CR <= 0.1):        print(" 通過一致性檢驗!")        print(" Wi: ", np.round(CR,4))
   else:        print(" 請調整判斷矩陣!"," ")
   return np.round(CR,4)

層次分析法雖然在多目標決策上可以很好地將定性決策定量化,但越是完美無缺的:

1~9標準打分機制是否合理(因為幾乎很難區別出臨界兩個分值之間的區別)

專家打分如何保證專家基於同一樣的評分尺度、客觀公允不划水,這些都是問題。


沒有完美無缺的模型,還是要具體問題具體分析,多方案交叉驗證效果!


參考資料:

《層次分析法原理》——章牧



如果你想要深入的去學ggplot2,但是又苦於平時學習、工作太忙木有時間研究浩如煙海的源文件,那也沒關係,本小編最近花了不少功夫,把我自己學習ggplot2過程中的一些心得體會、學習經驗、仿入坑指南精心整理,現已成功上線了R語言ggplot2視覺化的視訊課程,由天善智慧獨家發行,希望這門課程可以給你的R語言資料視覺化學習帶來更加豐富的體驗。

相關課程推薦

體系全面,最具調性!R語言視覺化&商務圖表實戰課程:


點選“閱讀原文”開啟新姿勢

相關文章