1 指标数据预处理
多指标综合评价中,指标数据的预处理是确保评价结果科学、合理和具有可比性的关键。由于原始数据常存在量纲不同、数量级差异大以及指标方向不一致等问题,直接计算会导致量纲大的指标主导结果,或方向相反的指标相互抵消。因此,通常采用无量纲化、标准化、归一化等方法消除量纲影响;对负向指标进行正向化处理;必要时还可使用对数变换减少极端值的影响。
这些预处理使得不同方向、量纲和数量级的指标能够在同一方向、统一尺度上进行比较与合成,从而更准确地体现各自的实际贡献,为后续的权重赋值和综合评价提供可靠基础。
假设有 \(n\) 个评价对象,\(m\) 个评价指标,形成原始指标数据矩阵 \(\mathbf{X}\),其中,\(x_{ij}\) 表示第 \(i\) 个评价对象第 \(j\) 个指标的值。
R 语言实现的话,指标数据 \(\mathbf{X}\) 通常用数据框存放,一个指标的数据是 \(\mathbf{X}\) 的 \(1\) 列(向量 \(\mathbf{x}\))。所以,指标数据预处理,就是用 mutate() 修改列,若同时对多列做某一种预处理,可以结合 across()。
以下所有预处理函数,都设计为接受一个向量 x,返回同样长度的结果向量。
1.1 方向一致性处理
1.1.1 负向指标正向化
正向指标,值越大越好,如 GDP;负向指标,值越小越好,如失业率。
正向指标不用处理,负向指标可用以下方式转化为正向指标:
- 倒数变换:\(\mathbf{x}' = 1 / \mathbf{x}\)
- 极小极大变换:\(\mathbf{x}' = \max \mathbf{x} - \mathbf{x}\)
注:负向指标正向化,也可以在做归一化/标准化时同时完成(见下文)。
mathmodels 包提供了 to_positive() 函数实现负向指标正向化,基本语法为:
-
type指定处理方法:"minmax"(极小极大变换,默认)、"reciprocal"(倒数变换)。
1.1.2 居中型指标正向化
居中型指标,是指值越接近某个中间值 \(x_{best}\) 越好,如 PH 值,通常按如下公式变换: \[ \mathbf{x}' = 1 - \dfrac{|\mathbf{x} - x_{best}|}{\max \{|\mathbf{x} - x_{best}|\}} \]
mathmodels 包提供了 rescale_middle() 函数实现居中型指标正向化,基本语法为:
-
m为最佳的中间值。
1.1.3 区间型指标正向化
区间型指标,是指值在某个确定的区间范围 \([a,b]\) 内为最好,如体温,通常做如下变换: \[ \mathbf{x}' = \left\{ \begin{array}{cl} 1-\dfrac{a-\mathbf{x}}{M}, & \mathbf{x} <a \\ 1, & a \leq \mathbf{x} \leq b \\ 1-\dfrac{\mathbf{x}-b}{M}, & \mathbf{x} > b \end{array} \right. \] 其中,\(M = \max\{a - \min \mathbf{x}, \, \max \mathbf{x} - b \}\)。
mathmodels 包提供了 rescale_interval() 函数实现区间型指标正向化,基本语法为:
-
a, b为最佳区间的左右端点值
注意,上述居中型、区间型指标正向化已含归一化,结果落在 \([0,1]\),不必再做归一化。
1.2 无量纲化处理
各指标通常具有不同的量纲(单位)和数量级,若直接进行综合计算,容易使量纲或数值范围较大的指标主导结果,而量纲小或范围窄的指标被弱化,影响评价的客观性与准确性。因此,需对原始数据进行无量纲化处理,消除单位和量级差异,使得指标能够在统一尺度上进行比较与合成。
1.2.1 标准化
标准化,也称为 \(Z\) 标准化,将数据变成均值为 \(0\),标准差为 \(1\): \[ \mathbf{x}' = \dfrac{\mathbf{x} - \mu}{\sigma} \] 其中,\(\mu\) 和 \(\sigma\) 分别为 \(\mathbf{x}\) 的均值和标准差。
若是负向指标,可以标准化后再乘以 \(-1\) 进行正向化处理。
注:若只减去均值,不除以标准差,叫做中心化。
mathmodels 包提供了 standardize() 函数实现标准化,基本语法为:
该函数是将自带的 scale() 函数封装为只处理向量,默认是做标准化,设置 scale = FALSE 则做中心化。
1.2.2 归一化
归一化,是指对数据进行线性变换,等比例缩放,并平移到目标区间 \([a,b]\)(通常取 \([0,1]\)),保持原始数据的相对大小关系不变。
对于正向指标, \[ \mathbf{x}' = (b - a) \cdot \dfrac{\mathbf{x} - \min \mathbf{x}}{\max \mathbf{x} - \min \mathbf{x}} + a \]
对于负向指标, \[ \mathbf{x}' = (b - a) \cdot \dfrac{\max \mathbf{x} - \mathbf{x}}{\max \mathbf{x} - \min \mathbf{x}} + a \]
mathmodels 包提供了 rescale() 函数实现归一化,基本语法为:
-
type指定指标方向 -
a, b确定目标区间,默认是0和1
注:标准化更适合应用到近似服从正态分布的数据;归一化更适合应用到近似服从均匀分布的数据。
1.2.3 规范化
规范化,是指将向量除以其范数,变成单位长度(即长度为 \(1\)): \[ \mathbf{x}' = \dfrac{\mathbf{x}}{\|\mathbf{x}\|_2} \] 这里使用 \(L_2\) 范数(欧几里德范数):\(\|\mathbf{x}\|_2 = \sqrt{x_1^2 + x_2^2 + \cdots + x_n^2}\)。
规范化后,向量在欧氏空间中的长度为 \(1\),以便用于 TOPSIS 法。
mathmodels 包提供了 normalize()函数实现 \(L_2\) 规范化:
1.2.4 用于GRA的无量纲化
灰色关联分析(GRA)中,原始数据通常被视为具有时间序列特性的指标。通常优先使用初值化法,因其能保留序列的增长特性,与灰色系统理论强调的“少数据建模”特点契合。
初值化:适合分析增长趋势(如经济指标、产量变化) \[ \mathbf{x}' = \dfrac{\mathbf{x}}{\mathbf{x}[1]}, ~~ \text{(正向指标)} \quad \mathbf{x}' = \dfrac{\mathbf{x}[1]}{\mathbf{x}}, ~~ \text{(负向指标)} \]
还有另外两种方法:
均值化:适合稳定波动的数据(如温度、pH 值) \[ \mathbf{x}' = \dfrac{\mathbf{x}}{\mathrm{mean}(\mathbf{x})} \]
最大值化:适合极差较大的数据 \[ \mathbf{x}' = \dfrac{\mathbf{x}}{\max(\mathbf{x})}, ~~ \text{(正向指标)} \quad \mathbf{x}' = \dfrac{\min(\mathbf{x})}{\mathbf{x}}, ~~ \text{(负向指标)} \]
mathmodels 包提供了如下三个函数实现这三种无量纲化方法:
-
type设置指标方向。
1.3 综合案例
加载包:
\(20\) 条河流的水质数据,已内置到 mathmodels 包,直接访问:
# 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
指标包括:含氧量越高越好(正向指标);PH 值越接近 \(7\) 越好(居中型指标);细菌总数越少越好(负向指标);植物性营养物量介于 \(10 \sim 20\) 之间最佳(区间型指标)。
做如下预处理:
- 居中型、区间型指标做正向化(归一化)处理
- 负向指标做极小极大正向化
- (两个)正向指标做归一化
前文说了,指标数据预处理就是 mutate() 修改列问题。
water_quality |>
mutate(PH = rescale_middle(PH, 7),
nutrient = rescale_interval(nutrient, 10, 20),
germ = to_positive(germ),
across(c(O2, germ), rescale))# A tibble: 20 × 5
ID O2 PH germ nutrient
<dbl> <dbl> <dbl> <dbl> <dbl>
1 1 0.368 0.717 0.0612 1
2 2 0.00274 0.407 0.714 0.694
3 3 0.974 0.524 0.163 0.906
4 4 0.905 0.966 0.163 0.444
5 5 0.702 0.655 0.0816 0.691
6 6 0.0521 0.841 0.327 0.601
7 7 0.779 0.855 0.327 0.655
8 8 1 0.869 0.551 0
9 9 0.472 0.572 1 1
10 10 0.573 0.814 0.755 0.785
11 11 0.812 0.634 0.918 0.699
12 12 0.328 0.807 0.755 0.542
13 13 0.748 0.145 0.633 1
14 14 0 0 0.143 0.455
15 15 0.00412 0.586 0.633 1
16 16 0.785 0.407 0.0408 1
17 17 0.595 0.6 0.592 0.182
18 18 0.861 0.0276 0.306 1
19 19 0.210 0.814 0 0.409
20 20 0.745 0.490 0.939 0.273