首页 / 资讯中心 / 文章详情

CRITIC赋权法Matlab实现:从权重计算到综合评价的完整指南

CRITIC赋权法Matlab实现:从权重计算到综合评价的完整指南 ★ FEATURED ARTICLE
简介这份资源面向需要在多属性决策分析中客观确定指标权重的Matlab用户提供CRITIC赋权法的完整实现代码适合具备一定Matlab基础、从事评价建模或科研计算的学习者。压缩包共1个文件为单个.m脚本体积约586B代码结构围绕数据预处理、属性归一化、一致性指标、相关性指标、强度指标与权重计算等环节组织并包含对象打分与示例数据生成部分便于替换为实际问题数据后直接运行。已有1658人学习下载说明该方法在项目选择、供应商评估、产品设计等场景中具有较稳定的参考需求。读者可据此理解CRITIC准则的计算流程掌握从决策矩阵到权重与综合评分的完整实现思路并在此基础上扩展可视化或与其他赋权方法组合使用。1. 从一张“权重表”说起CRITIC赋权法到底解决什么问题做综合评价时最容易被忽略的一步不是算得分而是定权重。指标一多主观打分就变成玄学谁嗓门大谁权重高换个人评一遍结果全变。CRITIC赋权法就是来治这个病的——它同时看两件事一是指标自身的波动大小对比强度用标准差衡量二是指标之间的冲突程度用相关系数衡量。波动大、又跟别人不重复的指标权重自然高。这份 Matlab 实现把整套流程封装成可直接调用的脚本输入一个数据矩阵输出权重向量和综合得分适合做课程设计、论文复现、多指标评价原型的开发者直接拿去改。下面按“能干什么、怎么跑、怎么改”拆开讲。2. 项目结构与技术选型一个纯 Matlab 脚本工程长什么样2.1 目录组织与文件职责这类赋权法实现通常不依赖任何工具箱纯基础 Matlab 语法就能跑所以工程结构很轻。拿到源码包后先别急着点运行按下面的职责划分过一遍文件能省掉后面一半的排查时间。文件/目录职责是否需改动main.m入口脚本读数据、调函数、出结果改数据路径critic_weight.m核心赋权函数输入矩阵输出权重一般不动normalize_data.m指标正向化与归一化按指标类型改data.xlsx/data.mat原始指标数据换成自己的result/权重表、得分排序输出自动生成主脚本负责“串流程”核心函数负责“算数学”归一化单独拆出来是因为不同指标方向不一样——效益型越大越好成本型越小越好混在一起算标准差会翻车。这种拆法看着朴素但二次开发时最舒服换数据只动main.m换归一化策略只动normalize_data.m核心算法基本不用碰。2.2 为什么选 CRITIC 而不是熵权法很多人第一反应是熵权法毕竟名气大。但熵权法只看指标内部的离散程度完全不考虑指标之间的相关性。举个典型场景你选了“GDP”和“人均GDP”两个指标它们高度相关信息其实是重复的熵权法照样给两个都分高权重最后等于同一个维度被算了两次。CRITIC 的相关系数项就是专门压这种重复的——相关性越高冲突性越低权重被拉下来。用公式说清楚第 j 个指标的信息量% C_j sigma_j * sum(1 - r_ij), i 1..n, i ~ j % sigma_j : 第 j 列的标准差对比强度 % r_ij : 指标 i 与 j 的相关系数冲突性 % 1 - r_ij 越大说明两指标越不重复该指标信息量越高这里有个细节容易写错求和时要把i j那一项排除因为自己跟自己的相关系数是 11 - 1 0留着不影响结果但逻辑上不干净更常见的错误是忘了取绝对值负相关其实也是“有信息”1 - r在 r 为负时会大于 1反而放大权重这符合 CRITIC 的原意但如果你先对相关系数取了绝对值再算结果会偏。我一般保留原始相关系数直接算跟主流文献口径一致。2.3 运行环境与最小可跑示例环境要求很低Matlab R2016b 及以上即可不需要 Statistics Toolbox标准差和相关系数用基础函数std、corrcoef就够。跑通的最小步骤如下。第一步把数据整理成一个数值矩阵行是样本、列是指标存成data.xlsx放在工程根目录。第二步确认每个指标的方向在main.m顶部维护一个方向向量。% main.m 片段数据加载与方向配置 raw xlsread(data.xlsx); % 读原始数据行样本列指标 direction [1 1 -1 1 -1]; % 1效益型(越大越好), -1成本型(越小越好) X normalize_data(raw, direction);% 正向化 归一化 w critic_weight(X); % 核心算权重 score X * w; % 加权求和得综合得分 [~, idx] sort(score, descend); % 降序排名 disp(table((1:numel(idx)), score(idx), VariableNames, {Rank,Score}));xlsread在新版 Matlab 里会提示推荐readmatrix功能一样老版本没有readmatrix就继续用xlsread。direction的长度必须等于指标列数这是最常见的报错来源——少写一个-1成本型指标没被翻转权重和排名全歪。score X * w这一步是线性加权如果你的评价模型要求非线性聚合这里就是改造点。3. 核心算法拆解从原始矩阵到权重向量的四步链路3.1 第一步指标正向化与归一化原始数据里量纲五花八门有的指标是百分比有的是绝对数值直接算标准差没有可比性。所以第一步必须统一。效益型指标越大越好和成本型指标越小越好处理方式不同区间型指标还要单独处理这里先覆盖前两类够绝大多数场景用。function Xn normalize_data(X, direction) % X: 原始矩阵 m×ndirection: 1×n1 效益型-1 成本型 [m, n] size(X); Xn zeros(m, n); for j 1:n col X(:, j); if direction(j) 1 % 效益型极差归一化(x - min) / (max - min) Xn(:, j) (col - min(col)) / (max(col) - min(col)); else % 成本型翻转(max - x) / (max - min) Xn(:, j) (max(col) - col) / (max(col) - min(col)); end end end逻辑说明极差归一化把每列压到[0,1]成本型用max - x翻转方向翻转后所有指标都变成“越大越好”。参数上要注意max(col) - min(col)不能为 0如果某列所有样本值完全相同这里会除零得到NaN后面标准差全是NaN权重直接崩。稳妥做法是加一行判断遇到常数列直接跳过或给零权重。提示如果数据里有负值或极端离群点极差归一化会被离群点主导这时可以换成 z-score 标准化但要注意 z-score 后可能出现负值标准差计算不受影响加权求和时得留意符号含义。3.2 第二步对比强度——标准差的计算口径归一化之后每个指标的波动程度就用标准差衡量。这里有个口径选择用样本标准差除以n-1还是总体标准差除以n。Matlab 的std默认是样本标准差std(X, 1)才是总体标准差。CRITIC 文献里两种都有差别在小样本时比较明显。% 对比强度按列求标准差默认样本标准差(n-1) sigma std(Xn, 0, 1); % 0 样本标准差, 1 总体标准差 % 若样本量很小(10)建议统一用总体标准差避免权重被放大std(Xn, 0, 1)三个参数分别是输入矩阵、权重标志0 表示按 n-1 归一、维度1 表示按列算。如果你的样本只有五六个样本标准差会让波动被高估权重分布更极端这时候换成std(Xn, 1, 1)更稳。这个细节论文里经常一笔带过但复现时结果对不上八成就是这里口径不一致。3.3 第三步冲突性——相关系数矩阵与信息量合成冲突性是 CRITIC 区别于熵权法的灵魂。先算指标间的相关系数矩阵再对每个指标求sum(1 - r_ij)最后乘上标准差得到信息量C_j归一化就是权重。function w critic_weight(Xn) [~, n] size(Xn); sigma std(Xn, 0, 1); % 1×n 对比强度 R corrcoef(Xn); % n×n 相关系数矩阵 conflict zeros(1, n); for j 1:n % 排除自身累加 (1 - r_ij) others [1:j-1, j1:n]; conflict(j) sum(1 - R(j, others)); end C sigma .* conflict; % 信息量 w C / sum(C); % 归一化为权重 end逐段看corrcoef(Xn)返回对称矩阵对角线上是自己跟自己的相关系数 1。others用索引拼接排掉第 j 个避免把1 - 1 0算进去虽然不影响和但语义清楚。C sigma .* conflict是逐元素相乘得到每个指标的信息量。最后除以总和归一化权重之和为 1。参数上要盯住两点一是corrcoef对常数列会返回NaN所以 3.1 里的常数列判断必须做二是当指标数n 1时others为空conflict为 0权重算不出来——单指标场景没有赋权意义代码里加个n 2的断言更友好。3.4 第四步综合得分与排序输出权重拿到后综合得分就是归一化矩阵乘权重向量。这一步简单但输出格式值得花点心思方便直接贴进报告。score Xn * w; % m×1 综合得分 [sortScore, idx] sort(score, descend); resultTable table((1:numel(idx)), idx, sortScore, ... VariableNames, {Rank,SampleIndex,Score}); writetable(resultTable, fullfile(result,ranking.csv)); fprintf(权重向量: %s\n, mat2str(round(w, 4)));Xn * w里w是行向量转置后做矩阵乘得到每个样本的加权得分。sort的descend保证第一名在前idx保留原始样本序号方便回查。writetable输出 CSV路径用fullfile拼跨平台不会因为斜杠翻车。round(w, 4)只是打印好看实际权重别截断后面还要用。4. 避坑与排查五个真实会踩的坑4.1 权重全是 NaN现象跑完w全是NaN得分排序无意义。原因某列数据全相同max - min 0导致归一化除零或者corrcoef遇到常数列返回NaN并污染整行。解决在normalize_data里加if max(col) min(col)分支给该列全零或直接剔除该指标并在日志里打印被剔除的列号。4.2 排名和参考文献对不上现象同样的数据自己算的排名和论文里的不一致。原因九成是归一化口径不同——论文可能用了 z-score 或向量归一化而你用了极差归一化也可能是标准差用了总体而非样本。解决先确认论文的标准化方法再对齐std的第二个参数最后核对相关系数是取原始值还是绝对值。4.3 成本型指标方向搞反现象某个“越小越好”的指标比如污染排放权重异常高排名明显不合理。原因direction向量里对应位置写成了1成本型没被翻转归一化后数值大的反而得分高。解决把direction和指标名做成一张对照表放在脚本顶部逐列核对别凭记忆填。4.4 相关系数矩阵报错维度不匹配现象corrcoef报错或返回空。原因输入矩阵里有NaN或Inf常见于原始数据缺失值没处理。解决加载数据后先跑一遍sum(isnan(raw(:)))和sum(isinf(raw(:)))缺失值用列均值填补或整行剔除别让脏数据流进算法。4.5 新版 Matlab 读 Excel 报错现象xlsread提示不推荐或直接失败。原因新版 Matlab 对xlsread支持收紧且需要 Excel 组件。解决换成readmatrix(data.xlsx)返回纯数值矩阵不依赖 Excel 安装老版本没有这个函数就退回xlsread或者把数据另存为.mat用load读最省事。5. 二次开发把赋权脚本改成可复用的评价模块5.1 从脚本到函数的封装思路原始工程是脚本式写法跑一次改一次数据复用性差。二次开发第一步是把main.m里的流程收进一个函数输入数据矩阵和方向向量输出权重、得分、排名三件套这样别的项目直接addpath调用就行。function [w, score, rank] evaluate_critic(X, direction, varargin) % 可复用评价入口 p inputParser; addParameter(p, StdFlag, 0); % 0样本标准差, 1总体标准差 addParameter(p, NormMethod, range); % range / zscore parse(p, varargin{:}); Xn normalize_data(X, direction, p.Results.NormMethod); w critic_weight(Xn, p.Results.StdFlag); score Xn * w; [~, rank] sort(score, descend); end用inputParser把标准差口径和归一化方法做成可选参数默认值保持和原脚本一致老调用不受影响。varargin的好处是不改函数签名就能加新选项后面想接熵权法做对比再加一个Method参数即可。这种封装方式在 Matlab 里很常见比全局变量干净得多。5.2 加一个权重敏感性检查CRITIC 权重对数据扰动敏感样本一换权重可能大变。上线前我习惯加一段扰动检查对每个指标加 5% 随机噪声重算权重看排序是否稳定。base_w critic_weight(Xn); perturb zeros(100, numel(base_w)); for k 1:100 Xp Xn .* (1 0.05 * randn(size(Xn))); perturb(k, :) critic_weight(Xp); end w_std std(perturb, 0, 1); % 每个指标权重的波动w_std大的指标说明权重不稳报告里要注明“该指标权重对数据敏感结论需谨慎”。这一步不改变算法但能提前发现“换个样本排名就翻”的隐患比事后被质疑强。5.3 和熵权法做交叉验证单一赋权法容易被挑刺稳妥做法是同时跑熵权法和 CRITIC看两者权重排序的 Spearman 相关系数。如果两种方法给出的权重高度一致结论可信度就高差异大的指标单独拎出来分析原因。实现上把critic_weight旁边加一个entropy_weight共用归一化后的矩阵主流程里并行调用输出一张对比表。这个改造量不大但对报告的说服力提升明显。5.4 一个我踩过的坑早些年我把这套脚本直接塞进一个批量评价流程数据是循环读进来的结果某批数据里有一列全零corrcoef返回NaN整批权重全废但脚本没报错静默输出了NaN表格直到人工核对才发现。从那以后我每次封装评价函数都在入口强制加一道数据体检assert(all(isfinite(X(:))))再补一个常数列检测宁可提前报错也不让脏数据静默流过。这个习惯帮我省了不止一次返工。希望这套拆解能帮你把 CRITIC 赋权快速跑起来也少走我走过的弯路。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站