7  TOPSIS

TOPSIS 法,也称为理想解法,是一种多目标决策方法,能充分利用原始数据的信息,结果能精确地反映各评价对象之间的差距。其基本原理是:

7.1 算法步骤

设有 \(n\) 个评价对象,\(m\) 个评价指标,形成原始指标数据矩阵 \(A\),称为决策矩阵,其中 \(a_{ij}\) 表示第 \(i\) 个评价对象第 \(j\) 个指标的值。

若存在居中型、区间型指标,先做归一化处理,得到的数据仍记为 \(A\)

(1) 数据无量纲化处理:规范化

\[ b_{ij}=\dfrac{a_{ij}}{\sqrt{\sum_{i=1}^n{a_{ij}}^2}},\quad i=1,\cdots n; \; j=1,\cdots,m \]\(B_{n\times m}=(b_{ij})_{n\times m}\) 称为规范决策矩阵,规范化法处理后,同一评价指标的各样本值的平方和为 \(1\),适合 TOPSIS 法中计算欧氏距离。

(2)计算加权规范决策矩阵

根据赋权法赋以合理的权重 \(w=[w_1,w_2,\cdots,w_m]\),将 \(B\) 的第 \(j\) 列乘以其权重 \(w_j\) 得到加权规范决策矩阵\[ C_{n\times m}=B_{n\times m}\cdot*\begin{pmatrix}w\\\vdots\\w\end{pmatrix}_{n\times m} \]

(3) 确定正理想解 \(C^∗\) 和负理想解 \(C^0\)

\[ C^* = (c_1^*,c_2^*,\cdots,c_m^*), \quad C^0 = (c_1^0,c_2^0,\cdots,c_m^0) \] 其中, \[ c_j^* = \left\{ \begin{array}{cc} \max\limits_i c_{ij}, & \text{若指标} ~j~ \text{为正向指标} \\ \min\limits_i c_{ij}, & \text{若指标} ~j~ \text{为负向指标} \end{array} \right. \quad c_j^0 = \left\{ \begin{array}{cc} \min\limits_i c_{ij}, & \text{若指标} ~j~ \text{为正向指标} \\ \max\limits_i c_{ij}, & \text{若指标} ~j~ \text{为负向指标} \end{array} \right. \]

(4) 计算各个样本到正理想解和负理想解的欧氏距离

\[ d_i^* = \sqrt{\sum\limits_{j=1}^m (c_{ij}-c_j^*)^2},\quad d_i^0 = \sqrt{\sum\limits_{j=1}^m (c_{ij}-c_j^0)^2}, \qquad i=1,\cdots n \]

(5) 计算每个样本到理想解的相对接近度

定义相对接近度如下,来评判各个评价对象的优劣: \[ f_i=\dfrac{d_i^0}{d_i^0+d_i^*},\quad i=1,\cdots,n \]

7.2 案例:河流水质评价

加载包:

library(tidyverse)
library(mathmodels)

使用内置的 water_quality 数据来演示:

water_quality 
# A tibble: 20 × 5
      ID    O2    PH  germ nutrient
   <dbl> <dbl> <dbl> <dbl>    <dbl>
 1     1  4.69  6.59    51    11.9 
 2     2  2.03  7.86    19     6.46
 3     3  9.11  6.31    46     8.91
 4     4  8.61  7.05    46    26.4 
 5     5  7.13  6.5     50    23.6 
 6     6  2.39  6.77    38    24.6 
 7     7  7.69  6.79    38     6.01
 8     8  9.3   6.81    27    31.6 
 9     9  5.45  7.62     5    18.5 
10    10  6.19  7.27    17     7.51
11    11  7.93  7.53     9     6.52
12    12  4.4   7.28    17    25.3 
13    13  7.46  8.24    23    14.4 
14    14  2.01  5.55    47    26.3 
15    15  2.04  6.4     23    17.9 
16    16  7.73  6.14    52    15.7 
17    17  6.35  7.58    25    29.5 
18    18  8.29  8.41    39    12.0 
19    19  3.54  7.27    54     3.16
20    20  7.44  6.26     8    28.4 

这是 \(20\) 条河流的水质数据,含氧量越高越好(正向指标);PH 值越接近 \(7\) 越好(居中型指标);细菌总数越少越好(负向指标);植物性营养物量介于 \(10 \sim 20\) 之间最佳(区间型指标)。

7.2.1 数据预处理

每个指标数据是一列,借助 mathmodels 包提供的预处理函数修改列即可。

中间型、区间型指标必须要先做归一化处理。正向、负向指标不做处理,因为熵权法和 TOPSIS 都会自己对正向、负向指标做归一化/规范化处理。

df = water_quality |>
  mutate(PH = rescale_middle(PH, 7),
         nutrient = rescale_interval(nutrient, 10, 20))
df
# A tibble: 20 × 5
      ID    O2     PH  germ nutrient
   <dbl> <dbl>  <dbl> <dbl>    <dbl>
 1     1  4.69 0.717     51    1    
 2     2  2.03 0.407     19    0.694
 3     3  9.11 0.524     46    0.906
 4     4  8.61 0.966     46    0.444
 5     5  7.13 0.655     50    0.691
 6     6  2.39 0.841     38    0.601
 7     7  7.69 0.855     38    0.655
 8     8  9.3  0.869     27    0    
 9     9  5.45 0.572      5    1    
10    10  6.19 0.814     17    0.785
11    11  7.93 0.634      9    0.699
12    12  4.4  0.807     17    0.542
13    13  7.46 0.145     23    1    
14    14  2.01 0         47    0.455
15    15  2.04 0.586     23    1    
16    16  7.73 0.407     52    1    
17    17  6.35 0.6       25    0.182
18    18  8.29 0.0276    39    1    
19    19  3.54 0.814     54    0.409
20    20  7.44 0.490      8    0.273

7.2.2 指标权重:熵权法

使用 entropy_weight()PHnutrient 已归一化,不再重复做:

res = entropy_weight(df[2:5], c("+",NA,"-",NA))   
res$w
       O2        PH      germ  nutrient 
0.3153202 0.1813149 0.3506929 0.1526721 

7.2.3 TOPSIS 评价

mathmodels 包提供了 topsis() 函数实现 TOPSIS 法,该函数已内置规范化处理,基本语法:

topsis(X, w = NULL, index = NULL)
  • X 为决策矩阵,w 为指标权重,index 指定指标正负向:"+" 表示正向指标,"-" 表示负向指标,默认为 NULL 表示都作为正向指标。
idx = c("+","+","-","+")
RC = topsis(df[2:5], res$w, idx)
RC               # 相对接近度
 [1] 0.3841556 0.4852199 0.5021310 0.5084128 0.4226200 0.3945085 0.5502261
 [8] 0.6258551 0.7260529 0.7138447 0.8091923 0.6159619 0.6007565 0.1593096
[15] 0.4974685 0.4250799 0.5565555 0.4815844 0.3070290 0.7098355

转化成 \(0 \sim 100\) 分数,增加排名列:

tibble(ID = df$ID, closeness = RC, score = rescale(closeness, b = 100),
       rank = min_rank(-score)) |>
  arrange(rank)
# A tibble: 20 × 4
      ID closeness score  rank
   <dbl>     <dbl> <dbl> <int>
 1    11     0.809 100       1
 2     9     0.726  87.2     2
 3    10     0.714  85.3     3
 4    20     0.710  84.7     4
 5     8     0.626  71.8     5
 6    12     0.616  70.3     6
 7    13     0.601  67.9     7
 8    17     0.557  61.1     8
 9     7     0.550  60.2     9
10     4     0.508  53.7    10
11     3     0.502  52.8    11
12    15     0.497  52.0    12
13     2     0.485  50.1    13
14    18     0.482  49.6    14
15    16     0.425  40.9    15
16     5     0.423  40.5    16
17     6     0.395  36.2    17
18     1     0.384  34.6    18
19    19     0.307  22.7    19
20    14     0.159   0      20