简介:这份资源面向需要在多属性决策分析中客观确定指标权重的研究者与工程人员,提供CRITIC赋权法的Matlab实现代码。CRITIC方法综合考量属性的一致性、相关性与强度,适合处理带不确定性的复杂评价问题,可应用于项目选择、供应商评估、产品设计等场景。压缩包共1个文件,为单个.m脚本,体积约586B,代码结构涵盖数据预处理、属性归一化、一致性指标、相关性指标、强度指标计算,以及权重求解与对象综合打分等环节,并配有数据生成与打分等子函数,替换随机示例数据即可用于实际数据集。目前已有1658人学习下载,适合希望快速上手CRITIC权重计算、并在此基础上扩展可视化或与其他决策方法组合使用的读者参考。
1. CRITIC 赋权法:为什么它敢说比熵权法更懂指标之间的“打架”
很多人第一次接触多指标综合评价,都是从熵权法入门的:谁的数据波动大,谁就重要。这套逻辑直观、好算,但真拿它去评一个稍微复杂点的体系,往往会翻车——两个高度相关的指标,明明说的是同一件事,却因为各自波动都不小,被熵权法各给了一份不小的权重,等于同一份信息被重复计了两次。CRITIC 赋权法要解决的正是这个“指标打架”的问题。它的核心结论很反直觉:一个指标重不重要,不只看它自己波动多大,还要看它跟别的指标有多“不重合”。波动性(对比强度)和冲突性(相关性)两个维度一起算,才得出真正该给的权重。搞懂这套机制,你才能明白为什么同一份数据,熵权法和 CRITIC 给出的排序会差那么多,也才知道什么时候该信谁。
2. 对比强度与冲突性:CRITIC 的两个权重来源
2.1 标准差为什么能代表“对比强度”
CRITIC 的第一步和熵权法思路相近,都是衡量单个指标内部的数据差异。区别在于,熵权法用的是信息熵,CRITIC 用的是标准差。标准差越大,说明这个指标在不同评价对象之间拉得越开,区分能力越强,理应获得更高权重。
这里有个容易被忽略的细节:标准差是对量纲敏感的。如果指标 A 是百分比(0 到 1 之间),指标 B 是金额(动辄上万),直接算标准差,B 会碾压 A,但这不代表 B 真的更重要,只是单位大。所以 CRITIC 在算标准差之前,必须先做无量纲化处理。常见的实现思路是极差归一化,把每个指标都压到 [0,1] 区间:
% 假设原始数据矩阵 X 为 m 个评价对象 × n 个指标 % 正向指标(越大越好)极差归一化 X_norm(:, j) = (X(:, j) - min(X(:, j))) / (max(X(:, j)) - min(X(:, j))); % 负向指标(越小越好)极差归一化 X_norm(:, j) = (max(X(:, j)) - X(:, j)) / (max(X(:, j)) - min(X(:, j)));这段代码的关键在于方向判断:正向指标和负向指标的归一化公式是反的。如果搞混了,后面算出来的标准差方向就全错了,权重会完全失真。归一化之后,每个指标都落在同一量纲上,标准差才有可比性。这一步是后面所有计算的地基,地基歪了,整栋楼都歪。
2.2 相关系数矩阵:冲突性到底在衡量什么
冲突性是 CRITIC 区别于熵权法的灵魂。它的直觉是:如果一个指标和其他指标高度相关,说明它提供的信息很大程度上是“重复”的,那它的独立价值就该打折。反过来,一个指标跟谁都不太相关,说明它带来了别人没有的信息,应该被重视。
数学上,冲突性用相关系数来刻画。对指标 j,它的冲突性定义为:
$$ \sum_{k=1}^{n} (1 - r_{jk}) $$
其中 $r_{jk}$ 是指标 j 和指标 k 的相关系数。注意这里是 $1 - r_{jk}$ 而不是 $1 - |r_{jk}|$。这个细节很关键:如果两个指标是强负相关($r_{jk}$ 接近 -1),$1 - r_{jk}$ 会接近 2,冲突性反而被放大。这符合直觉——负相关意味着两个指标在唱反调,信息不仅不重复,还互相补充,当然该给高权重。而如果两个指标强正相关($r_{jk}$ 接近 1),$1 - r_{jk}$ 接近 0,冲突性被压缩,权重自然就低了。
% 计算相关系数矩阵 R = corrcoef(X_norm); % 计算每个指标的冲突性 conflict = sum(1 - R, 1); % 对每一列求和,得到 1×n 的冲突性向量这里sum(1 - R, 1)是对矩阵的每一列求和,得到每个指标与其他所有指标(包括它自己)的冲突性总和。指标与自己的相关系数是 1,所以 $1 - r_{jj} = 0$,自己那一项自动消掉,不影响结果。这个设计很干净,不需要额外排除对角线。
2.3 信息量合成:两个维度怎么乘在一起
有了对比强度和冲突性,CRITIC 把两者相乘,得到每个指标的信息量:
$$ C_j = \sigma_j \cdot \sum_{k=1}^{n}(1 - r_{jk}) $$
其中 $\sigma_j$ 是指标 j 归一化后的标准差。这个乘法结构值得琢磨:它意味着两个维度是“与”的关系,不是“或”的关系。一个指标要拿高权重,必须同时满足波动大和冲突性强。如果它波动很大但跟别人高度相关,乘积会被冲突性那一项拉下来;如果它很独立但几乎不波动,乘积也会被标准差那一项压住。这种“双重门槛”的设计,正是 CRITIC 比单一维度赋权更稳健的原因。
% 计算标准差(归一化后) sigma = std(X_norm, 0, 1); % 0 表示按样本标准差(除以 m-1),1 表示沿列方向 % 合成信息量 C = sigma .* conflict; % 归一化得到最终权重 W = C / sum(C);std(X_norm, 0, 1)里的三个参数分别是:输入矩阵、权重标志(0 表示样本标准差,1 表示总体标准差)、维度标志(1 表示沿列计算)。这里用样本标准差还是总体标准差,在评价对象数量 m 较大时差别不大,但 m 较小时会有可见差异。常见的实现思路是用样本标准差(除以 m-1),因为评价对象通常是从更大总体中抽样的,样本标准差更符合统计直觉。
3. 从矩阵到权重:一次完整的 CRITIC 计算链路
3.1 数据预处理的三个必做动作
在真正进入 CRITIC 计算之前,有三件事必须先做,少一件都会让结果失真。
第一是缺失值处理。CRITIC 对缺失值没有原生容忍能力,相关系数矩阵和标准差都要求数据完整。常见的做法是均值填充或中位数填充,但如果缺失比例超过 5%,填充本身就会引入偏差,这时候更稳妥的做法是剔除该指标或该评价对象。
第二是异常值处理。标准差对异常值极其敏感,一个极端值就能把某个指标的标准差拉高好几倍,导致权重虚高。常用的做法是用 3σ 原则或 IQR 方法识别异常值,然后做截尾或替换。这一步在血泪经验里经常被跳过,结果就是某个指标莫名其妙拿了最高权重,回头一查发现是录入错误。
第三是归一化的方向判断。前面提过正向和负向指标的公式是反的,但实际操作中还有一个坑:有些指标是“适度型”的,比如 pH 值,太高太低都不好,最优点在中间。这种指标不能简单套正向或负向公式,需要先做适度化变换,再归一化。如果直接当正向处理,权重会完全跑偏。
% 缺失值检查与填充 if any(isnan(X(:))) X = fillmissing(X, 'constant', median(X, 1, 'omitnan')); end % 异常值检测(3σ 原则,按列) for j = 1:n mu = mean(X(:, j)); sd = std(X(:, j)); outlier_idx = abs(X(:, j) - mu) > 3 * sd; X(outlier_idx, j) = mu; % 用均值替换异常值 end这段预处理代码看起来简单,但每一步都在为后面的标准差和相关系数“排雷”。fillmissing的median(X, 1, 'omitnan')是按列求中位数并忽略 NaN,保证填充值不被缺失值本身污染。异常值替换用均值而不是删除,是为了保持评价对象数量不变,避免后续矩阵维度对不上。
3.2 相关系数矩阵的数值稳定性问题
corrcoef在大多数情况下工作良好,但当指标之间存在近似线性关系时,相关系数矩阵会接近奇异,数值稳定性变差。更隐蔽的问题是:如果两个指标几乎完全线性相关(比如一个指标是另一个指标的线性变换),corrcoef算出来的相关系数可能接近 1 但带有微小误差,导致冲突性计算出现数值噪声。
一个实用的排查方法是看相关系数矩阵的条件数:
R = corrcoef(X_norm); cond_R = cond(R); if cond_R > 1e10 warning('相关系数矩阵接近奇异,存在高度共线的指标,建议检查指标设计'); end条件数超过 1e10 是一个信号,说明矩阵里有指标几乎线性相关。这时候不一定要删指标,但至少要意识到:CRITIC 给出的权重在这个方向上是不稳定的,换一批数据可能排序就变了。常见的处理思路是对高度相关的指标做合并或降维,而不是硬算。
3.3 权重归一化与排序的边界情况
最后一步W = C / sum(C)看起来最无害,但有两个边界情况会让它翻车。
第一种是某个指标的冲突性为负。虽然理论上 $1 - r_{jk}$ 在 $r_{jk} \le 1$ 时非负,但数值误差可能让某个 $r_{jk}$ 略大于 1,导致 $1 - r_{jk}$ 变成极小的负数。如果这个负数恰好出现在求和结果里,整个冲突性向量可能被拉偏。防御性写法是加一个下限截断:
conflict = sum(1 - R, 1); conflict = max(conflict, 0); % 截断负值,防止数值误差第二种是所有指标的信息量都接近 0。这通常发生在数据几乎无波动的情况下(比如所有评价对象在每个指标上都差不多),此时归一化会变成 0/0,MATLAB 返回 NaN。遇到这种情况,说明数据本身不具备区分能力,CRITIC 给不出有意义的权重,应该回头检查数据采集环节,而不是硬算一个结果出来。
4. 避坑与排查:CRITIC 实操中最容易翻车的五个地方
4.1 现象:权重结果和熵权法完全相反
原因:最常见的原因是归一化方向搞反了。负向指标被当成正向处理,标准差方向反了,冲突性也跟着反,最终权重排序自然颠倒。另一个可能是相关系数矩阵用了原始数据而不是归一化后的数据,量纲差异导致相关系数失真。
解决:逐列检查归一化公式,确认正向和负向指标分别用了正确的公式。相关系数矩阵必须基于归一化后的X_norm计算,不能直接用原始X。可以在归一化后打印每列的均值和标准差,确认都在合理范围内。
4.2 现象:某个指标权重异常高,远超其他指标
原因:该指标存在极端异常值,标准差被拉高。或者该指标与其他指标几乎完全不相关(甚至是负相关),冲突性被放大。前者是数据问题,后者可能是指标设计问题。
解决:先做异常值检测,用 3σ 或 IQR 方法排查。如果异常值排除后权重回归正常,说明是数据质量问题。如果权重依然很高,检查该指标是否真的独立于其他指标——如果它确实带来了独特信息,高权重是合理的;如果它只是测量噪声,考虑剔除。
4.3 现象:corrcoef报错或返回 NaN
原因:某一列数据全部相同(方差为 0),corrcoef在计算相关系数时分母为 0,返回 NaN。这种情况在评价对象数量少、某个指标取值又恰好一致时很容易出现。
解决:在归一化之前检查每列的方差,方差为 0 的指标直接剔除,因为它不提供任何区分信息,留着只会污染相关系数矩阵。剔除后重新跑一遍流程。
4.4 现象:权重之和不为 1 或出现负数
原因:数值误差导致冲突性出现微小负值,或者归一化时分母接近 0。前者在指标数量多、相关系数矩阵接近奇异时更常见。
解决:在冲突性求和后加max(conflict, 0)截断负值。归一化前检查sum(C)是否显著大于 0,如果接近 0 说明数据缺乏区分度,应该停止计算并检查数据,而不是强行归一化。
4.5 现象:换一批数据后权重排序大幅变动
原因:指标之间存在高度共线性,相关系数矩阵接近奇异,CRITIC 的权重对数据扰动极其敏感。这种情况下,权重排序本身就不稳定,换一批样本就可能翻转。
解决:计算相关系数矩阵的条件数,超过 1e10 时警惕。对高度相关的指标做合并或主成分降维,减少共线性。如果业务上必须保留所有指标,至少要在报告里说明权重的不稳定性,不要把它当成铁板钉钉的结论。
5. 设计取舍:CRITIC 的边界在哪里,什么时候不该用它
CRITIC 的乘法结构决定了它对“波动大且独立”的指标有天然偏好,这既是优点也是局限。优点前面说过了,局限在于:如果一个指标波动小但业务上极其关键(比如安全合规类指标,取值常年稳定在合格线附近),CRITIC 会给它很低的权重,这在某些评价场景下是不合理的。这时候需要引入主观权重做组合赋权,而不是纯靠 CRITIC 说话。
另一个取舍是相关系数的使用方式。CRITIC 用的是线性相关系数(Pearson),它只能捕捉线性关系。如果两个指标之间存在强非线性关系(比如 U 型关系),Pearson 相关系数可能接近 0,CRITIC 会误判它们“不冲突”,从而给两者都偏高的权重。常见的改进思路是用距离相关系数或互信息替代 Pearson,但这会显著增加计算复杂度,是否值得取决于指标间关系的实际形态。
还有一个容易被忽视的点:CRITIC 的权重是“数据驱动”的,它反映的是当前这批评价对象内部的指标关系,而不是指标本身的绝对重要性。换一批评价对象,权重就可能变。所以 CRITIC 的结果不应该被当成放之四海而皆准的指标重要性排序,它更像是对当前数据集的一次“关系快照”。我一般会这么理解:CRITIC 回答的是“在这批数据里,哪个指标提供了最多的独立区分信息”,而不是“哪个指标最重要”。这两者之间的差距,就是纯数据赋权方法永远绕不开的边界。
验证 CRITIC 结果是否靠谱,一个实用的习惯是做敏感性分析:随机扰动数据 5% 到 10%,重跑几遍,看权重排序是否稳定。如果排序基本不变,说明结果稳健;如果排序频繁翻转,说明指标间共线性严重,权重不可信。这个习惯我从第一次被不稳定的权重坑过之后就养成了,每次跑完 CRITIC 都强制走一遍扰动测试,比事后解释为什么排序变了要省心得多。希望帮到你。
本文还有配套的精品资源,点击获取