☰
熵权法详解:用数据离散度科学确定目标函数权重
2026/10/3 18:07:30 网站建设 项目流程

简介:这是一份针对熵权法权重确定与目标函数构建的MATLAB源码资源,面向需要开展多指标综合评价、决策分析或优化建模的研究者与工程人员。压缩包内包含shang.m与guiyi.m两个脚本文件,整体大小仅1KB,其中shang.m负责数据标准化与信息熵计算,guiyi.m侧重熵权计算及归一化处理,可配合使用完成从原始数据到最终权重的完整流程。资源已吸引约619人学习下载,虽体量精简,但函数逻辑清晰,适合作为客观赋权方法的参考实现。通过运行脚本,读者可直接替换评价数据获得各指标权重,进而构建综合目标函数,减少主观偏好对决策结果的影响,提升多准则评估的可靠性与可复现性。

1. 熵权法不是拍脑袋:数据越乱,越该用它定目标函数权重

给一组待评价的方案定目标函数权重,最让人头疼的往往不是打分,而是权重本身怎么定。熵权法这条路线,核心就一句话:不靠专家拍脑袋,靠数据本身的离散程度反推权重。某个指标下各方案的数值差异越大,说明它携带的区分信息越多,权重就该给得越高;数值全都挤在一起,说明它对最终排序没什么贡献,权重自然低。这套思路在综合评价、多目标决策、算法评测里都很常见,适合手头有完整评估矩阵、又不想让主观偏好污染权重确定过程的工程师。它不玄学,但样本和预处理没做好,照样翻车。

2. 熵权法权重确定的三步推导:信息熵、差异系数与权重之间的数学关系

2.1 信息熵和权重的对应关系:熵小权重大的直觉从哪来

熵这个概念最早从热力学来,香农把它借到信息论里,定义了一个系统的混乱程度:事件概率分布越均匀,熵越大;概率分布越集中,熵越小。熵权法把这个逻辑反转过来用。把 n 个评价对象、m 个指标看成一张信息表,对某个指标 j 来说,如果所有对象在这个指标上的取值都差不多,说明这个指标几乎不携带区分信息,它的熵值接近 1,给的权重就该小;如果取值差异很大、有的高有的低,说明这个指标能帮你把对象拉开差距,熵值小,权重就该大。

这套直觉换成公式就是:权重和熵值反向,和差异系数正向。先算每个指标的熵值e_j,算差异系数d_j = 1 - e_j,最后把d_j归一化就得到权重。整个过程没有引入任何主观评分,所以被称为客观赋权法。实际做多目标决策时,经常遇到 5 个甚至 10 个目标函数要合成一个综合指标,AHP 那种两两比较的打分表在目标多的时候很容易自相矛盾,熵权法只认数据,反而能把权重确定这件事从“开会争论”变成“跑一遍脚本”。

2.2 标准计算流程:从原始矩阵到权重只需要五步

熵权法的计算路径是固定的,我一般按下面的顺序走,每一步都对应一个可检查的中间结果。

第一步,构造原始数据矩阵X(n×m)。n 行是评价对象或者候选方案,m 列是指标或者目标函数。第二步,正向化处理。熵权法要求所有指标方向一致,默认越大越好。成本型指标(越小越好)要先转换,常见做法是取倒数,或者用该列最大值减去当前值。第三步,min-max 归一化到 [0,1] 区间,消除量纲影响。第四步,计算每个对象在某个指标下的比重p_ij = x'_ij / Σ x'_ij,本质上就是把该指标下所有对象的值“摊成概率”。第五步,按熵公式计算熵值:

e_j = -1 / ln(n) * Σ p_ij * ln(p_ij)

前面的1/ln(n)是归一化系数,保证e_j落在 0 到 1 之间。随后算差异系数d_j = 1 - e_j,最后权重w_j = d_j / Σ d_j。

这里面最容易出问题的不是公式本身,而是 p_ij 取对数时遇到的零值。归一化后如果某个值恰好是 0,ln(0) 直接报错,所以几乎所有实现里都会加一个极小偏移量。这个偏移量是多少、放在哪个环节,会直接影响权重结果,后面专门讲。

2.3 为什么它适合目标函数权重:和 AHP、均权法的本质差别

目标函数权重确定这件事,本质上是在回答“多个优化目标哪个更重要”。均权法默认所有目标同等重要,适合完全没有先验信息的起步阶段;AHP 靠专家两两比较构造判断矩阵,适合目标数量少、且决策者能给出稳定偏好的场景;熵权法站在中间:不预设偏好,也不完全平均,完全由候选方案之间的差异程度驱动。

三种方法的适用边界差别很大,我常用这张表来向团队解释选型理由。

方法依据主观性适用场景主要短板
均权法默认平等无没有先验信息的探索忽略指标重要程度差异
AHP专家打分高目标数少、偏好明确目标多时判断矩阵一致性难保证
熵权法数据离散度无有完整评估矩阵、样本量足够对数据质量和相关性敏感

需要特别说明的是,熵权法算出的权重描述的是“该指标在这个数据集里的区分力度”,不是“该指标在业务上有多重要”。假如某项目标函数的取值在所有候选方案里几乎一样,熵权法会给它接近 0 的权重,但这不代表这个目标业务上不重要,只是它在当前数据集里没有提供足够的排序信息。理解这一点,后面做组合权重时才能知道它在干嘛。

3. 用 Python 实现熵权法:从原始矩阵到目标函数权重的完整代码

3.1 最小可运行代码:输入矩阵,输出权重

先说结论:熵权法的 Python 实现不需要任何第三方库之外的依赖,numpy 就够了。下面这段代码是最小可用版本,我建议直接复制保存成entropy_weight.py,后面的讨论都基于它。

import numpy as np def entropy_weight(X): """ 熵权法计算指标权重 X: numpy array, shape (n_samples, n_features) 行是样本/方案,列是指标/目标函数 返回: weights, shape (n_features,) """ # 1. min-max 归一化到 [0, 1] X_min = X.min(axis=0) X_max = X.max(axis=0) X_norm = (X - X_min) / (X_max - X_min + 1e-10) # 2. 非负平移,避免后续 log(0) X_norm = X_norm + 1e-10 # 3. 计算每个方案在各指标下的比重 sum_col = X_norm.sum(axis=0) P = X_norm / sum_col # 4. 计算熵值 n = X.shape[0] k = 1.0 / np.log(n) entropy = -k * np.sum(P * np.log(P + 1e-10), axis=0) # 5. 差异系数归一化得到权重 d = 1 - entropy weights = d / d.sum() return weights if __name__ == "__main__": # 示例:4 个候选方案,3 个目标函数(都是越大越好) X = np.array([ [0.8, 0.6, 120], [0.9, 0.7, 95], [0.7, 0.8, 80], [0.6, 0.9, 60], ]) print(entropy_weight(X))

这段代码的逻辑对应上一章的五步推导:归一化、加偏移、算比重、算熵、算权重。要注意的三点是行和列的方向、偏移量加在哪里、以及系数k的意义。

X的行是方案,列是目标函数,这个方向千万别搞反。如果习惯把指标放行,axis=0计算的逻辑会全乱。偏移量1e-10加在分母和取对数两个位置,作用是双保险:分母加偏移防止归一化时分子分母同时为 0 的情况,取对数加偏移防止ln(0)报错。系数k用的是1/np.log(n),n 必须是样本数,不是指标数,写错的话熵值不会落在 [0,1] 区间里。

3.2 归一化与正向化:成本型目标怎么处理

实际拿到的目标函数不全是越大越好。比如多目标优化里常见的“时延”“成本”“能耗”,都是越小越好的成本型指标。这些数据不能直接喂给上面的函数,必须先做正向化。我常用的做法是max - x而不是取倒数。

def preprocess(X, cost_columns=[]): """ 正向化 + min-max 归一化 + 非负平移 cost_columns: 需要反向处理的列索引列表 """ X = X.astype(float).copy() for j in cost_columns: X[:, j] = X[:, j].max() - X[:, j] X_min = X.min(axis=0) X_max = X.max(axis=0) X_norm = (X - X_min) / (X_max - X_min + 1e-10) # 平移确保没有 0 或负值 X_shift = X_norm + 1e-6 return X_shift

为什么不推荐取倒数?因为倒数是非线性变换,会放大数值小的样本之间的差异,压缩数值大的样本之间的差异。一个离群值如果特别小,取倒数后会变成极大的值,直接主导整列的比重计算。max - x是线性变换,能保留原始数据里的比例关系和分布形状,对离群值的容忍度更高。

归一化和平移的先后顺序也要固定:先归一化,再平移。如果先平移再归一化,某些指标原本的范围差异会被平移量覆盖,权重会整体偏向范围大的指标。1e-6这个量级是经验值,足够避免零值又不至于把各样本的真实差异抹平。

3.3 封装成标准函数:适配多目标函数权重的接口设计

上面的函数已经能直接用了,但做目标函数权重时通常还要算加权综合得分,所以我会把预处理和加权得分一起封装。

def objective_weight_and_score(X, cost_columns=[]): """ 熵权法确定目标函数权重,并输出加权综合得分 X: shape (n_solutions, n_objectives) cost_columns: 成本型目标所在的列索引 返回: (weights, scores) """ X_proc = preprocess(X, cost_columns) weights = entropy_weight(X_proc) # 综合得分:归一化后的矩阵与权重做矩阵乘法 scores = X_proc @ weights return weights, scores

这里有一个隐藏的细节:entropy_weight内部对X_proc又做了一遍min-max归一化,而preprocess已经把数据归一化过一次了。重复归一化不会改变列内样本的相对比例吗?如果我们传入的矩阵所有列都已经在 [0,1] 区间,且每列最小值都是 0、最大值都是 1,那么二次归一化后数据不变,结果是对的。如果某列归一化后最小值为 0.1、最大值为 0.9,二次归一化会把它重新拉伸到 [0,1],相当于改变了列间的相对尺度,这就会影响权重。

所以正确的接口设计是:preprocess只做正向化,把归一化统一交给entropy_weight去做。或者反过来,在objective_weight_and_score里用X_proc直接算得分,把归一化逻辑收敛到一处。我倾向于后者,代码里保持“只归一化一次”的原则,避免这种隐蔽的二次拉伸。

4. 熵权法避坑指南:五个让权重翻车的真实场景

4.1 离群值绑架权重:一个 100 分把其他样本压成零头

现象:原始数据里混进一个异常大的值,min-max 归一化后其他样本的值全部被压到 0.01 以下,比重计算时这个离群值几乎独占整列,熵值极低,权重被它一家撑到离谱的高度。

原因:min-max 对离群值没有抵抗力,最大值和最小值被极端数据控制,整个归一化分布被拉伸。

解决:归一化之前先做分位数缩尾。我一般把超过 1% 和 99% 分位数的值拉回边界,再用缩尾后的数据做熵权法。

def winsorize(X, lower=0.01, upper=0.99): """分位数缩尾,防止离群值主导权重""" X_w = X.copy() for j in range(X.shape[1]): lo = np.percentile(X[:, j], lower * 100) hi = np.percentile(X[:, j], upper * 100) X_w[:, j] = np.clip(X[:, j], lo, hi) return X_w

缩尾不是删除数据,而是把极端值压到边界。它牺牲了离群值的绝对量,换回的是权重对整体样本的代表性。对目标函数权重来说,如果某个候选方案的某个目标值异常突出,这个方案本来就该拿高分,但它不该让其他目标函数的权重集体失真。

4.2 强相关指标重复计权:两个指标其实说的是一件事

现象:指标体系里有“完成数”和“完成率”,两个指标高度相关,熵权法算出来的这两个权重都偏高,加起来几乎占了总量的一半,导致其他指标被边缘化。

原因:熵权法把每个指标当成独立信息源,完全不考虑指标间的相关性。两个强相关指标携带的信息几乎重合,相当于同一份信息被计算了两次。

解决:先算相关系数矩阵,把|r| > 0.8的指标对找出来,删掉其中一个再跑熵权法。这一步在目标函数权重场景下同样适用——如果两个目标函数本质上是一强相关,保留一个就够了。这也是后文要讲的“熵权法+critic”组合思路存在的根本原因:critic 显式考虑了指标间的冲突性,能惩罚这种重复计权。

4.3 样本量太少:三个方案算出来的权重没法信

现象:只有 3 个样本、6 个指标,算出来的权重忽高忽低,换一个样本权重排序就变了。

原因:熵值计算的归一化系数1/ln(n)在 n 很小时对概率分布的敏感度极高。3 个样本的熵值可能只有 0.3~0.7,差异系数被整体放大,权重看起来差异很大,实际上都是噪声驱动的。

解决:熵权法的样本量不建议少于指标数的 3 倍。如果样本量实在不够,可以做自助抽样看权重分布:每次有放回抽 n 个样本,重复 500 次,观察每个指标权重的均值方差。如果方差大到权重排序不稳定,就不要用熵权法作为唯一依据,换 CRITIC 或者主观赋权。

4.4 归一化方法换来换去:同一份数据算出两套权重

现象:同事用 min-max 归一化,你用 z-score 标准化,同一个数据集跑出来的权重完全不一样,开会时各执一词。

原因:z-score 会产生负值,负值没法直接取对数,必须平移。平移量一加,原来的数据分布就被扭曲了,熵值跟 min-max 的结果没有可比性。z-score 适合用于需要保留离群值影响的场景,但它和熵权法天然不搭。

解决:锁定一套流程,不要混用。我固定用正向化 → min-max → 平移 → 比重 → 熵值,并且把预处理参数记录在代码配置里。任何人回跑结果时必须用同一套参数,否则结论不可比。

4.5 熵值接近 1,权重约等于 0:这个指标该不该删

现象:某个指标在所有样本上的取值几乎一致,算出来的熵值 0.9999,差异系数只有 0.0001,归一化后权重接近 0。看起来该删,但业务上这个指标明明很关键。

原因:熵权法度量的是“差异化信息量”,不是“业务重要度”。数据分布越均匀,权重越小是熵权法的正常行为,不是 bug。

解决:不要直接删指标,先确认数据是不是采集出了问题。如果数据确实没问题,就在报告里说明:该指标当前数据集未能提供足够的区分信息,权重低不代表业务不重要。如果希望它参与决策,可以用组合权重方案,把熵权法结果和主观权重或 critic 权重做几何平均,防止它被一票否决。

5. 熵权法与 CRITIC 法怎么选:目标函数权重确定的两个客观方案对比

5.1 CRITIC 法的核心逻辑:对比强度加上冲突性

CRITIC 法做的是另一件事:它用标准差衡量指标的对比强度,标准差越大说明这个指标区分能力越强;再用指标间的相关系数衡量冲突性,相关系数越低说明这个指标和其他指标越不重复。综合成一个信息量指数:

C_j = σ_j * Σ(1 - r_jk)

其中σ_j是指标 j 的标准差,r_jk是指标 j 与指标 k 的相关系数,求和遍历所有其他指标。权重同样是C_j归一化后的结果。

这个公式的价值在于它显式惩罚了强相关指标。如果一个指标和很多指标都高度相关,Σ(1-r)会比较小,就算它自己的标准差大,最终权重也会被压低。这正是熵权法缺失的能力。

5.2 两种方法的适用场景对比

客观赋权领域,熵权法和 CRITIC 是出场率最高的两个名字。它们都解决同一个问题——目标函数权重怎么确定,但适用条件差别不小。

维度熵权法CRITIC 法
信息度量信息熵(离散度)标准差(对比强度)+ 相关系数(冲突性)
指标相关性不考虑显式考虑
数据量要求建议样本数 ≥ 3 倍指标数样本数太少时相关系数矩阵不稳定
主要风险强相关指标重复计权相关系数估计受离群值影响
典型场景指标独立或近似独立指标间存在明显关联

实际项目里,如果指标数量少、业务上能确认它们彼此独立,我直接用熵权法。如果指标之间明显存在关联,比如“时延”和“排队长度”,“能耗”和“运行时长”,我会换成 CRITIC。判断标准很简单:先跑一个相关系数矩阵,如果大部分相关系数的绝对值超过 0.6,熵权法就要打个问号。

5.3 组合权重落地:熵权法+critic 的几何平均方案

热词“熵权法+critic”对应的其实是一个很实际的诉求:两种客观方法各有短板,能不能合起来用。组合权重是我在高风险决策里常用的折中方案。线性加权组合是w = α*w_熵 + (1-α)*w_critic,α 可以调;几何平均组合是w = sqrt(w_熵 * w_critic)。

我更推荐几何平均,原因是它保留了“一票否决”的属性。某个指标在一种方法下权重接近 0 时,组合后也会被压得很低,而线性加权会把它拉回来一部分。具体用哪种取决于业务上需不需要这种保护。下面是几何平均组合的代码。

def critic_weight(X): """CRITIC 法权重:标准差 + 冲突性""" std = X.std(axis=0) corr = np.corrcoef(X.T) conflict = (1 - corr).sum(axis=0) info = std * conflict return info / info.sum() def combined_entropy_critic(X): """熵权法 + CRITIC 组合权重(几何平均)""" w_entropy = entropy_weight(X) w_critic = critic_weight(X) w_comb = np.sqrt(w_entropy * w_critic) return w_comb / w_comb.sum()

注意这里X需要先完成正向化和归一化再传进去。组合权重的哲学是:熵权法捕捉数据分布的离散度,CRITIC 捕捉指标间的冲突性,两者互补。但组合不是免费的,它对数据质量的要求比单独使用更高——相关系数矩阵在样本量不足时本身就有噪声,组合之后会把噪声也带进来。所以我的原则是:样本量够(≥ 3 倍指标数)且指标关系复杂时,才做组合;样本量不足时,宁可只跑熵权法。

6. 拿到熵权法权重后,先做这三项验证再投入使用

6.1 敏感性分析:给数据加一点噪声,看权重稳不稳

权重算出来只是第一步,真正能不能投入决策,要看权重对数据扰动是否敏感。我习惯的做法是对每个指标单独加 5% 的高斯噪声,重新算一遍权重,观察排名变化。

np.random.seed(42) X_noise = X * (1 + 0.05 * np.random.randn(*X.shape)) w_noise = entropy_weight(X_noise) change = np.abs(w_noise - w0) / w0

如果某个指标的权重相对变化超过 20%,说明这个权重被当前数据里的少数样本牵制,需要回到数据清洗环节排查原因。

6.2 与主观排序交叉验证:解释不通的权重先别用

我会把熵权法的权重排序拿给业务方看,问一个问题:排名前二的指标是不是业务上真正关心的。如果业务方认为最重要的指标在熵权法里垫底,先别急着解释“这是客观算法”,大概率是数据里有脏值或者指标放错了方向。用 AHP 或简单的主观打分做个交叉验证,差异过大就回头查数据,这是最便宜的质量检查。

6.3 Bootstrap 稳定性检验:留一法看权重排序是否翻转

去掉一个样本,重新计算权重,重复 n 次。如果某指标的权重排序在多次留一验证里反复翻转,说明它区分信息不足,应该考虑和研究哪些指标真正驱动评价结果。

这套流程走完,我才敢把权重带到决策会上。我的习惯是:权重必须能被业务逻辑解释通,解释不通,先查数据质量,而不是急着调公式参数。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询