news 2026/8/24 14:17:33

评价类模型

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
评价类模型

总览

类别常见模型主要作用数模常用度
主观赋权AHP 层次分析法根据专家判断确定权重★★★★★
客观赋权熵权法根据数据差异程度定权★★★★★
客观赋权CRITIC根据变异性+指标冲突性定权★★★★☆
客观赋权变异系数法根据相对离散程度定权★★★☆☆
组合赋权AHP-熵权、博弈论组合赋权综合主客观权重★★★★☆
综合排序TOPSIS离理想方案越近越好★★★★★
模糊评价模糊综合评价处理“优、良、中、差”等模糊评价★★★★★
灰色评价灰色关联分析小样本、不完全信息下比较接近程度★★★★☆
效率评价DEA 数据包络分析多投入、多产出下比较相对效率★★★★☆
综合评价PCA 主成分综合评价降维后构造综合得分★★★★☆
秩次评价RSR 秩和比法根据秩次进行综合评价和分档★★★☆☆
折中决策VIKOR在“整体最好”和“最差短板”之间折中★★★☆☆
多属性决策ELECTRE通过“优于关系”比较方案★★★☆☆
多属性决策PROMETHEE基于偏好函数进行方案排序★★★☆☆
云模型评价正态云模型同时处理随机性与模糊性★★★☆☆

AHP层次分析

一致性检验的含义用于确定构建的判断矩阵是否存在逻辑问题

(1)构造判断矩阵

(2)层次单排序

根据我们构成的判断矩阵,求解各个指标的权重,有三种方式,一种是方根法,一种是和法,一重特征值

方根法:

一行所有数乘一起开根号

标准化

和法:

特征值法:直接求最大特征值对应的特征向量并归一化,就是最后要的权重结果

(3)求解最大特征根与CI值,判断 判断矩阵是不是正确的

AW为:判断矩阵*标准化后的权重,然后按按行的累加值

直接特征值法:真正把所有特征值算出来,取最大的

C.I.越大,判断矩阵的不一致性程度越严重

Satty 模拟 1000 次得到的随机一致性指标 R.I.取值表(如下表 所示)

当 C.R.<0.1 时,表明判断矩阵 A 的一致性程度被认为在容许的范围内

(4)层次总排序

"""只使用 NumPy 实现 AHP 层次分析法。""" import numpy as np # Saaty 随机一致性指标,索引表示判断矩阵阶数 n。 RI_TABLE = { 1: 0.00, 2: 0.00, 3: 0.58, 4: 0.90, 5: 1.12, 6: 1.24, 7: 1.32, 8: 1.41, 9: 1.45, 10: 1.49, 11: 1.51, 12: 1.48, 13: 1.56, 14: 1.57, 15: 1.59, } def validate_judgment_matrix(matrix, tolerance=1e-8): """检查判断矩阵是否为正互反方阵。""" matrix = np.asarray(matrix, dtype=float) if matrix.ndim != 2 or matrix.shape[0] != matrix.shape[1]: raise ValueError("判断矩阵必须是方阵") if np.any(matrix <= 0): raise ValueError("判断矩阵中的元素必须大于 0") if not np.allclose(np.diag(matrix), 1.0, atol=tolerance): raise ValueError("判断矩阵的对角线元素必须为 1") if not np.allclose(matrix * matrix.T, 1.0, atol=tolerance): raise ValueError("判断矩阵必须满足 a[i,j] * a[j,i] = 1") return matrix def ahp_weights(matrix): """使用最大特征值法计算权重,并进行一致性检验。""" matrix = validate_judgment_matrix(matrix) n = matrix.shape[0] eigenvalues, eigenvectors = np.linalg.eig(matrix)# 计算特征值和特征向量 max_index = np.argmax(eigenvalues.real)# 获取最大特征值的索引 lambda_max = float(eigenvalues[max_index].real)# 获取最大特征值 principal_vector = np.abs(eigenvectors[:, max_index].real)# 获取对应的特征向量,并取绝对值 weights = principal_vector / principal_vector.sum()# 归一化特征向量得到权重 # 一致性指标 CI 和一致性比率 CR if n <= 2: ci = 0.0 cr = 0.0 else: ci = (lambda_max - n) / (n - 1)# 计算一致性指标 CI if n not in RI_TABLE: raise ValueError("当前 RI 表仅支持 1~15 阶判断矩阵") cr = ci / RI_TABLE[n]# 计算一致性比率 CR return { "weights": weights, "lambda_max": lambda_max, "ci": float(ci), "cr": float(cr), "passed": bool(cr < 0.10),# 一致性检验通过的条件是 CR < 0.10 } def print_result(title, names, result): """输出一组权重及其一致性检验结果。""" print(f"\n{title}") for name, weight in zip(names, result["weights"]): print(f" {name:<8}: {weight:.4f}") print(f" lambda_max = {result['lambda_max']:.6f}") print(f" CI = {result['ci']:.6f}") print(f" CR = {result['cr']:.6f}") print(" 一致性检验:", "通过" if result["passed"] else "未通过") def main(): # 目标层:选择最佳供应商。 criteria = ["产品质量", "采购价格", "交付能力", "售后服务"] alternatives = ["供应商A", "供应商B", "供应商C"] # 准则层判断矩阵:质量、价格、交付、服务两两比较。 criteria_matrix = np.array( [ [1, 3, 5, 4],#1-9行对于列越来越重要 [1/3, 1, 2, 2],#倒数列对于行重要 [1/5, 1/2, 1, 1/2], [1/4, 1/2, 2, 1], ], dtype=float, ) # 方案层判断矩阵:分别在每项准则下比较三个供应商。 alternative_matrices = { "产品质量": np.array( [[1, 3, 5], [1/3, 1, 2], [1/5, 1/2, 1]], dtype=float ), "采购价格": np.array( [[1, 1/2, 1/4], [2, 1, 1/3], [4, 3, 1]], dtype=float ), "交付能力": np.array( [[1, 2, 1/2], [1/2, 1, 1/3], [2, 3, 1]], dtype=float ), "售后服务": np.array( [[1, 1/3, 2], [3, 1, 5], [1/2, 1/5, 1]], dtype=float ), } criteria_result = ahp_weights(criteria_matrix) print_result("准则层权重", criteria, criteria_result) local_weight_columns = [] all_passed = criteria_result["passed"] for criterion in criteria: result = ahp_weights(alternative_matrices[criterion]) print_result(f"方案层权重——{criterion}", alternatives, result) local_weight_columns.append(result["weights"]) all_passed = all_passed and result["passed"] # 每列对应一个准则,每行对应一个供应商。 local_weights = np.column_stack(local_weight_columns) total_scores = local_weights @ criteria_result["weights"] ranking = np.argsort(total_scores)[::-1] print("\n综合得分与排序") for rank, index in enumerate(ranking, start=1): print(f" 第 {rank} 名:{alternatives[index]},得分 = {total_scores[index]:.4f}") if not all_passed: print("\n警告:存在未通过一致性检验的判断矩阵,应重新调整比较值。") if __name__ == "__main__": main()
(base) PS D:\桌面\华为杯\code> & d:/Users/anaconda3/python.exe d:/桌面/华为杯/code/评价类/ahp.py 准则层权重 产品质量 : 0.5498 采购价格 : 0.2143 交付能力 : 0.0942 售后服务 : 0.1417 lambda_max = 4.056585 CI = 0.018862 CR = 0.020958 一致性检验: 通过 方案层权重——产品质量 供应商A : 0.6483 供应商B : 0.2297 供应商C : 0.1220 lambda_max = 3.003695 CI = 0.001847 CR = 0.003185 一致性检验: 通过 方案层权重——采购价格 供应商A : 0.1365 供应商B : 0.2385 供应商C : 0.6250 lambda_max = 3.018295 CI = 0.009147 CR = 0.015771 一致性检验: 通过 方案层权重——交付能力 供应商A : 0.2970 供应商B : 0.1634 供应商C : 0.5396 lambda_max = 3.009203 CI = 0.004601 CR = 0.007933 一致性检验: 通过 方案层权重——售后服务 供应商A : 0.2297 供应商B : 0.6483 供应商C : 0.1220 lambda_max = 3.003695 CI = 0.001847 CR = 0.003185 一致性检验: 通过 综合得分与排序 第 1 名:供应商A,得分 = 0.4462 第 2 名:供应商B,得分 = 0.2846 第 3 名:供应商C,得分 = 0.2692

TOPSIS(逼近理想解排序法)

有多个评价对象,每个对象有多个指标,我到底怎么综合这些指标,给对象排个名

最优方案 = 距离最好方案最近 + 距离最差方案最远

开始

输入决策矩阵、权重和指标类型

检查决策矩阵和权重是否合法

将权重归一化

对不同类型的指标进行正向化处理
├─ 效益型指标:保持不变
├─ 成本型指标:最大值减去原值
├─ 目标型指标:计算与目标值的接近程度
└─ 区间型指标:计算与最优区间的接近程度

对正向化指标矩阵进行标准化处理

标准化指标矩阵乘以指标权重

确定正理想解和负理想解

计算各方案到正理想解的距离

计算各方案到负理想解的距离

计算各方案的 TOPSIS 综合得分

按照综合得分从高到低排序

输出各方案得分和排名

结束

越接近1越好

"""使用 NumPy 实现 TOPSIS(逼近理想解排序法)。 支持四类指标: 1. benefit:效益型,数值越大越好; 2. cost:成本型,数值越小越好; 3. target:目标型,越接近给定目标值越好; 4. interval:区间型,落在给定区间内最好。 """ from dataclasses import dataclass from typing import Optional, Sequence, Tuple import numpy as np @dataclass(frozen=True) class TopsisResult: """保存 TOPSIS 的主要中间结果和最终排序。""" scores: np.ndarray ranking: np.ndarray normalized_matrix: np.ndarray weighted_matrix: np.ndarray positive_ideal: np.ndarray negative_ideal: np.ndarray distance_to_positive: np.ndarray distance_to_negative: np.ndarray def _convert_to_benefit( matrix: np.ndarray, indicator_types: Sequence[str], targets: Optional[Sequence[Optional[float]]], intervals: Optional[Sequence[Optional[Tuple[float, float]]]], ) -> np.ndarray: """把各种指标统一转换为“越大越好”的形式。""" converted = matrix.astype(float, copy=True) n_indicators = matrix.shape[1] targets = [None] * n_indicators if targets is None else list(targets) intervals = [None] * n_indicators if intervals is None else list(intervals) if len(indicator_types) != n_indicators: raise ValueError("indicator_types 的长度必须等于指标个数") if len(targets) != n_indicators or len(intervals) != n_indicators: raise ValueError("targets 和 intervals 的长度必须等于指标个数") for j, kind in enumerate(indicator_types): kind = kind.lower() column = matrix[:, j] if kind == "benefit": continue if kind == "cost": # 用“列最大值减原值”正向化,避免使用倒数时遇到零。 converted[:, j] = np.max(column) - column elif kind == "target": if targets[j] is None: raise ValueError(f"第 {j + 1} 个目标型指标缺少目标值") deviation = np.abs(column - float(targets[j])) max_deviation = np.max(deviation) converted[:, j] = ( np.ones_like(column) if max_deviation == 0 else max_deviation - deviation ) elif kind == "interval": if intervals[j] is None: raise ValueError(f"第 {j + 1} 个区间型指标缺少最优区间") lower, upper = intervals[j] if lower > upper: raise ValueError(f"第 {j + 1} 个指标的区间下限不能大于上限") deviation = np.where( column < lower, lower - column, np.where(column > upper, column - upper, 0.0), ) max_deviation = np.max(deviation) converted[:, j] = ( np.ones_like(column) if max_deviation == 0 else max_deviation - deviation ) else: raise ValueError( f"未知指标类型 {kind!r};应为 benefit、cost、target 或 interval" ) return converted def topsis( decision_matrix: Sequence[Sequence[float]], weights: Sequence[float], indicator_types: Sequence[str], *, targets: Optional[Sequence[Optional[float]]] = None, intervals: Optional[Sequence[Optional[Tuple[float, float]]]] = None, ) -> TopsisResult: """计算各方案的 TOPSIS 得分并返回由优到劣的排序。 参数: decision_matrix: 决策矩阵,每行是一个方案,每列是一个指标。 weights: 各指标权重;函数内部会自动归一化,使权重之和为 1。 indicator_types: 每列的指标类型。 targets: 目标型指标的目标值;其他位置填 None。 intervals: 区间型指标的最优区间;其他位置填 None。 """ matrix = np.asarray(decision_matrix, dtype=float) weight_array = np.asarray(weights, dtype=float) if matrix.ndim != 2 or matrix.shape[0] < 2 or matrix.shape[1] < 1: raise ValueError("决策矩阵必须是至少包含 2 个方案的二维矩阵") if not np.all(np.isfinite(matrix)): raise ValueError("决策矩阵不能包含 NaN 或无穷大") if weight_array.ndim != 1 or len(weight_array) != matrix.shape[1]: raise ValueError("weights 的长度必须等于指标个数") if not np.all(np.isfinite(weight_array)) or np.any(weight_array < 0): raise ValueError("权重必须是有限的非负数") if np.sum(weight_array) <= 0: raise ValueError("权重之和必须大于 0") weight_array = weight_array / np.sum(weight_array)# 归一化权重,使其和为 1 benefit_matrix = _convert_to_benefit(# 指标正向化,越大越好 matrix, indicator_types, targets, intervals ) # 向量归一化,消除不同指标量纲的影响。 column_norms = np.sqrt(np.sum(benefit_matrix**2, axis=0)) # 全零列说明该指标下所有方案表现相同,不应影响方案间距离。 zero_columns = column_norms == 0 if np.any(zero_columns): benefit_matrix[:, zero_columns] = 1.0# 统一赋值为 1,避免除以零 column_norms[zero_columns] = np.sqrt(matrix.shape[0]) normalized = benefit_matrix / column_norms# 归一化指标矩阵 weighted = normalized * weight_array#权重越大的指标,对最终距离和综合得分的影响越大 # 所有指标已经正向化,因此最大值为正理想解,最小值为负理想解 positive_ideal = np.max(weighted, axis=0) negative_ideal = np.min(weighted, axis=0) distance_positive = np.linalg.norm(weighted - positive_ideal, axis=1) distance_negative = np.linalg.norm(weighted - negative_ideal, axis=1) denominator = distance_positive + distance_negative # 计算c,分母为0则说明所有方案完全相同,则没有优劣之分,统一记为 0.5。 scores = np.divide( distance_negative, denominator, out=np.full_like(denominator, 0.5), where=denominator != 0, ) #kind="stable" 表示使用稳定排序。当两个方案得分相同时,保持它们原来的先后顺序。 ranking = np.argsort(-scores, kind="stable") return TopsisResult( scores=scores, ranking=ranking, normalized_matrix=normalized, weighted_matrix=weighted, positive_ideal=positive_ideal, negative_ideal=negative_ideal, distance_to_positive=distance_positive, distance_to_negative=distance_negative, ) def main() -> None: """运行一个供应商综合评价示例。""" alternatives = ["供应商 A", "供应商 B", "供应商 C", "供应商 D"] criteria = ["产品质量", "采购价格", "交付准时率", "售后响应时间"] # 行对应供应商,列依次对应上面的四个指标。 decision_matrix = np.array( [ [92, 108, 96, 3.0], [88, 100, 91, 2.0], [95, 115, 98, 4.0], [90, 105, 94, 2.5], ], dtype=float, ) weights = [0.35, 0.25, 0.25, 0.15]#这个权重是根据AHP计算出来的,表示每个指标的重要性 indicator_types = ["benefit", "cost", "benefit", "cost"] result = topsis(decision_matrix, weights, indicator_types) print("指标:", "、".join(criteria)) print("\nTOPSIS 得分与排名:") for rank, index in enumerate(result.ranking, start=1): print(f" 第 {rank} 名:{alternatives[index]},得分 = {result.scores[index]:.4f}") if __name__ == "__main__": main()
(base) PS D:\桌面\华为杯\code> & d:/Users/anaconda3/python.exe d:/桌面/华为杯/code/评价类/topsis.py 指标: 产品质量、采购价格、交付准时率、售后响应时间 TOPSIS 得分与排名: 第 1 名:供应商 B,得分 = 0.9321 第 2 名:供应商 D,得分 = 0.6838 第 3 名:供应商 A,得分 = 0.4757 第 4 名:供应商 C,得分 = 0.0679

熵权法(Entropy Weight Method, EWM)

熵权法是一种客观赋权法,避免了人为因素带来的偏差。

越可能发生的事信息熵越大,信息量越少,权值也越低。信息熵本质上就是对信息量的期望。

熵越大,差异越小,信息量越小,发生概率越大。

标准化,去除量纲影响

效益型指标:

成本性指标:

4、差异系数或信息效用值。

  • 信息熵越大,信息效用值越小。
  • 信息熵越小,信息效用值越大。
  • 信息效用值越大,指标权重越高。

5、

6、

"""使用 NumPy 实现熵权法(Entropy Weight Method)。 熵权法根据指标数据的差异程度客观确定权重:指标差异越大, 提供的信息越多,权重通常越高。 """ from dataclasses import dataclass from typing import Sequence import numpy as np @dataclass(frozen=True) class EntropyWeightResult: """保存熵权法的计算结果。""" weights: np.ndarray entropy: np.ndarray information_utility: np.ndarray normalized_matrix: np.ndarray probability_matrix: np.ndarray scores: np.ndarray ranking: np.ndarray def entropy_weight( decision_matrix: Sequence[Sequence[float]], indicator_types: Sequence[str], ) -> EntropyWeightResult: """计算指标的熵权以及各方案的综合得分和排名。 参数: decision_matrix: 决策矩阵,每行是一个方案,每列是一个指标。 indicator_types: 各指标类型;benefit 表示越大越好, cost 表示越小越好。 返回: 包含指标权重、信息熵、综合得分和排名的结果对象。 """ matrix = np.asarray(decision_matrix, dtype=float) if matrix.ndim != 2 or matrix.shape[0] < 2 or matrix.shape[1] < 1: raise ValueError("决策矩阵必须是至少包含 2 个方案的二维矩阵") if not np.all(np.isfinite(matrix)): raise ValueError("决策矩阵不能包含 NaN 或无穷大") if len(indicator_types) != matrix.shape[1]: raise ValueError("indicator_types 的长度必须等于指标个数") # 第一步:使用极差法正向化、无量纲化,使结果落在 [0, 1]。标准化 normalized = np.empty_like(matrix, dtype=float)#创建一个与 matrix 形状相同的空数组,用于存储正向化后的数据 for j, kind in enumerate(indicator_types): kind = kind.lower() column = matrix[:, j] column_min = np.min(column) column_max = np.max(column) value_range = column_max - column_min # 所有方案取值相同时,该指标没有区分能力,先统一记为 1。 if value_range == 0: normalized[:, j] = 1.0 elif kind == "benefit": normalized[:, j] = (column - column_min) / value_range elif kind == "cost": normalized[:, j] = (column_max - column) / value_range else: raise ValueError( f"未知指标类型 {kind!r};应为 benefit 或 cost" ) # 第二步:计算每个方案在各指标下的比重 p_ij。也是归一化 column_sums = np.sum(normalized, axis=0) probability = normalized / column_sums # 第三步:计算信息熵 e_j。规定 0 * ln(0) = 0。 n_alternatives = matrix.shape[0] log_probability = np.zeros_like(probability) positive = probability > 0 log_probability[positive] = np.log(probability[positive]) entropy = -np.sum(probability * log_probability, axis=0) / np.log( n_alternatives ) # 消除浮点运算可能产生的极小越界误差。 entropy = np.clip(entropy, 0.0, 1.0) # 第四步:差异系数(信息效用值)越大,指标提供的信息越多。 information_utility = 1.0 - entropy utility_sum = np.sum(information_utility) if np.isclose(utility_sum, 0.0): # 所有指标都没有区分能力时,采用等权,避免除以零。 weights = np.full(matrix.shape[1], 1.0 / matrix.shape[1]) else: weights = information_utility / utility_sum#熵权,就是归一化 # 第五步:用正向化后的数据进行加权求和,并由高到低排序。 scores = normalized @ weights ranking = np.argsort(-scores, kind="stable") return EntropyWeightResult( weights=weights, entropy=entropy, information_utility=information_utility, normalized_matrix=normalized, probability_matrix=probability, scores=scores, ranking=ranking, ) def main() -> None: """运行一个供应商综合评价示例。""" alternatives = ["供应商 A", "供应商 B", "供应商 C", "供应商 D"] criteria = ["产品质量", "采购价格", "交付准时率", "售后响应时间"] # 每行代表一个供应商,每列依次对应上面的四项指标。 decision_matrix = np.array( [ [92, 108, 96, 3.0], [88, 100, 91, 2.0], [95, 115, 98, 4.0], [90, 105, 94, 2.5], ], dtype=float, ) indicator_types = ["benefit", "cost", "benefit", "cost"] result = entropy_weight(decision_matrix, indicator_types) print("熵权法计算的指标权重:") for criterion, weight in zip(criteria, result.weights): print(f" {criterion}:{weight:.4f}") print("\n方案综合得分与排名:") for rank, index in enumerate(result.ranking, start=1): print( f" 第 {rank} 名:{alternatives[index]}," f"得分 = {result.scores[index]:.4f}" ) if __name__ == "__main__": main()
(base) PS D:\桌面\华为杯\code> & d:/Users/anaconda3/python.exe d:/桌面/华为杯/code/评价类/entropy_weight.py 熵权法计算的指标权重: 产品质量:0.2863 采购价格:0.2385 交付准时率:0.2437 售后响应时间:0.2315 方案综合得分与排名: 第 1 名:供应商 A,得分 = 0.5647 第 2 名:供应商 C,得分 = 0.5300 第 3 名:供应商 D,得分 = 0.5189 第 4 名:供应商 B,得分 = 0.4700

灰色关联(Grey Relational Analysis,GRA)

看每个方案的数据变化趋势,和“理想方案”的变化趋势有多像。越像,关联度越高,方案越好。

信息不完全性:系统的结构、参数、边界条件、输入输出关系中,至少有一项是未知或模糊的。

数据稀疏性:系统可观测的数据量少(小样本),无法通过传统统计方法(如回归分析)捕捉规律。

不确定性与非线性:系统内部因素之间、因素与目标之间的关系是非线性、非确定性的,无法用简单的线性方程描述

1、正向化

2、选择参考序列

3、计算距离

4、计算灰色关联系数,某一个指标越接近理想值,这个指标对应的灰色关联系数就越大,分辨系数一般为0.5。

5、计算灰色关联度,表示与参考序列的关联程度

没有权重直接求均值

有权重

越大,方案越好。

也可以用灰色关联度计算权重

"""使用 NumPy 实现灰色关联分析(Grey Relational Analysis, GRA)。 灰色关联分析通过比较各方案序列与最优参考序列的接近程度, 得到灰色关联系数、综合关联度以及方案排名。 """ from dataclasses import dataclass from typing import Optional, Sequence import numpy as np @dataclass(frozen=True) class GreyRelationalResult: """保存灰色关联分析的主要计算结果。""" normalized_matrix: np.ndarray reference_sequence: np.ndarray difference_matrix: np.ndarray relational_coefficients: np.ndarray relational_grades: np.ndarray ranking: np.ndarray weights: np.ndarray def grey_relational_analysis( decision_matrix: Sequence[Sequence[float]], indicator_types: Sequence[str], weights: Optional[Sequence[float]] = None, rho: float = 0.5, ) -> GreyRelationalResult: """计算各方案的灰色关联度并返回由优到劣的排序。 参数: decision_matrix: 决策矩阵,每行是一个方案,每列是一个指标。 indicator_types: 指标类型;benefit 表示越大越好,cost 表示越小越好。 weights: 指标权重。省略时使用等权,输入后会自动归一化。 rho: 分辨系数,取值范围为 (0, 1),通常取 0.5。 """ matrix = np.asarray(decision_matrix, dtype=float) if matrix.ndim != 2 or matrix.shape[0] < 2 or matrix.shape[1] < 1: raise ValueError("决策矩阵必须是至少包含 2 个方案的二维矩阵") if not np.all(np.isfinite(matrix)): raise ValueError("决策矩阵不能包含 NaN 或无穷大") if len(indicator_types) != matrix.shape[1]: raise ValueError("indicator_types 的长度必须等于指标个数") if not 0 < rho < 1: raise ValueError("分辨系数 rho 必须满足 0 < rho < 1") n_indicators = matrix.shape[1] if weights is None: weight_array = np.full(n_indicators, 1.0 / n_indicators) else: weight_array = np.asarray(weights, dtype=float) if weight_array.ndim != 1 or len(weight_array) != n_indicators: raise ValueError("weights 的长度必须等于指标个数") if not np.all(np.isfinite(weight_array)) or np.any(weight_array < 0): raise ValueError("权重必须是有限的非负数") if np.sum(weight_array) <= 0: raise ValueError("权重之和必须大于 0") weight_array = weight_array / np.sum(weight_array) # 第一步:极差标准化,并将所有指标统一为“越大越好”。 normalized = np.empty_like(matrix, dtype=float) for j, kind in enumerate(indicator_types): kind = kind.lower() column = matrix[:, j] column_min = np.min(column) column_max = np.max(column) value_range = column_max - column_min # 该列数据完全相同时,各方案在此指标上的表现相同。 if value_range == 0: normalized[:, j] = 1.0 elif kind == "benefit": normalized[:, j] = (column - column_min) / value_range elif kind == "cost": normalized[:, j] = (column_max - column) / value_range else: raise ValueError( f"未知指标类型 {kind!r};应为 benefit 或 cost" ) # 第二步:以各指标的最优值组成参考序列。 reference = np.max(normalized, axis=0) # 第三步:计算各方案序列与参考序列的绝对差。 differences = np.abs(normalized - reference) global_min = np.min(differences) global_max = np.max(differences) # 第四步:计算灰色关联系数。越接近1越好。 if np.isclose(global_max, 0.0): # 所有方案完全相同时,所有关联系数均为 1。 coefficients = np.ones_like(differences) else: coefficients = (global_min + rho * global_max) / ( differences + rho * global_max ) # 第五步:对关联系数加权求和,得到综合灰色关联度。 grades = coefficients @ weight_array ranking = np.argsort(-grades, kind="stable") return GreyRelationalResult( normalized_matrix=normalized, reference_sequence=reference, difference_matrix=differences, relational_coefficients=coefficients, relational_grades=grades, ranking=ranking, weights=weight_array, ) def main() -> None: """运行一个供应商综合评价示例。""" alternatives = ["供应商 A", "供应商 B", "供应商 C", "供应商 D"] criteria = ["产品质量", "采购价格", "交付准时率", "售后响应时间"] # 每行代表一个供应商,每列依次对应上面的四项指标。 decision_matrix = np.array( [ [92, 108, 96, 3.0], [88, 100, 91, 2.0], [95, 115, 98, 4.0], [90, 105, 94, 2.5], ], dtype=float, ) indicator_types = ["benefit", "cost", "benefit", "cost"] weights = [0.35, 0.25, 0.25, 0.15] result = grey_relational_analysis( decision_matrix, indicator_types, weights=weights, rho=0.5, ) print("指标权重:") for criterion, weight in zip(criteria, result.weights): print(f" {criterion}:{weight:.4f}") print("\n灰色关联度与排名:") for rank, index in enumerate(result.ranking, start=1): print( f" 第 {rank} 名:{alternatives[index]}," f"关联度 = {result.relational_grades[index]:.4f}" ) if __name__ == "__main__": main()
(base) PS D:\桌面\华为杯\code> & d:/Users/anaconda3/python.exe d:/桌面/华为杯/code/评价类/grey_relational.py 指标权重: 产品质量:0.3500 采购价格:0.2500 交付准时率:0.2500 售后响应时间:0.1500 灰色关联度与排名: 第 1 名:供应商 C,关联度 = 0.7333 第 2 名:供应商 B,关联度 = 0.6000 第 3 名:供应商 A,关联度 = 0.5435 第 4 名:供应商 D,关联度 = 0.5108

CRITIC(Criteria Importance Through Intercriteria Correlation基于指标对比强度和指标间冲突性的客观赋权法

一个指标如果自身差异很大,而且和其他指标不太重复,那么它的信息量就大,权重就应该高。

熵权法相比,多考虑了一件事:指标之间是不是重复

第 j 个指标的信息量通常写成

自身标准差 皮尔逊系数

归一化

输入决策矩阵

正向化和极差标准化

计算标准差

计算相关系数

计算冲突性

计算指标信息量

计算 CRITIC 权重

计算方案得分与排名

CRITIC 法不宜采用 Z-score 标准化,因为 Z-score 处理会使各指标的标准差统一为 1,导致标准差无法反映指标的对比强度。可以采用极差标准化,在消除量纲并完成指标正向化的同时,保留标准化后各指标分布差异。

"""使用 NumPy 实现 CRITIC 客观赋权法。 CRITIC(Criteria Importance Through Intercriteria Correlation)同时考虑: 1. 指标内部的数据差异,即对比强度; 2. 指标之间的相关程度,即冲突性。 指标对比越强、与其他指标的冲突越大,其客观权重通常越高。 """ from dataclasses import dataclass from typing import Sequence import numpy as np @dataclass(frozen=True) class CriticResult: """保存 CRITIC 法的主要中间结果和最终结果。""" weights: np.ndarray normalized_matrix: np.ndarray standard_deviations: np.ndarray correlation_matrix: np.ndarray conflicts: np.ndarray information: np.ndarray scores: np.ndarray ranking: np.ndarray def critic_weight( decision_matrix: Sequence[Sequence[float]], indicator_types: Sequence[str], ) -> CriticResult: """计算 CRITIC 指标权重以及各方案的综合得分和排名。 参数: decision_matrix: 决策矩阵,每行是一个方案,每列是一个指标。 indicator_types: 指标类型;benefit 表示越大越好, cost 表示越小越好。 """ matrix = np.asarray(decision_matrix, dtype=float) if matrix.ndim != 2 or matrix.shape[0] < 2 or matrix.shape[1] < 1: raise ValueError("决策矩阵必须是至少包含 2 个方案的二维矩阵") if not np.all(np.isfinite(matrix)): raise ValueError("决策矩阵不能包含 NaN 或无穷大") if len(indicator_types) != matrix.shape[1]: raise ValueError("indicator_types 的长度必须等于指标个数") # 第一步:极差标准化,并将指标统一转换为“越大越好”。 normalized = np.empty_like(matrix, dtype=float) for j, kind in enumerate(indicator_types): kind = kind.lower() column = matrix[:, j] column_min = np.min(column) column_max = np.max(column) value_range = column_max - column_min # 常量指标没有区分能力,标准化后统一记为 0。 if np.isclose(value_range, 0.0): normalized[:, j] = 0.0 elif kind == "benefit": normalized[:, j] = (column - column_min) / value_range elif kind == "cost": normalized[:, j] = (column_max - column) / value_range else: raise ValueError( f"未知指标类型 {kind!r};应为 benefit 或 cost" ) # 第二步:用标准差表示各指标的对比强度。 standard_deviations = np.std(normalized, axis=0, ddof=0)# ddof=0 表示总体标准差 varying = ~np.isclose(standard_deviations, 0.0) # 第三步:计算指标间的皮尔逊相关系数。 # 常量列的相关系数没有定义;这里将其冲突贡献记为 0,避免影响其他指标。 n_indicators = matrix.shape[1] correlation = np.ones((n_indicators, n_indicators), dtype=float)# 初始化相关系数矩阵为1 varying_indices = np.flatnonzero(varying)# 找出数值有变化的指标 if len(varying_indices) >= 2: varying_correlation = np.corrcoef(#皮尔逊相关系数 normalized[:, varying_indices], rowvar=False ) correlation[np.ix_(varying_indices, varying_indices)] = varying_correlation correlation = np.clip(correlation, -1.0, 1.0) # 第四步:相关性越弱,指标之间的冲突越强。 conflicts = np.sum(1.0 - correlation, axis=1) # 第五步:信息量 = 标准差 × 冲突性。 information = standard_deviations * conflicts information_sum = np.sum(information) if not np.isclose(information_sum, 0.0): weights = information / information_sum#归一化 else: # 只有一个有效指标或有效指标完全正相关时,CRITIC 信息量可能全为 0。 # 此时优先按照标准差赋权;若所有指标均为常量,则采用等权重。 deviation_sum = np.sum(standard_deviations) if not np.isclose(deviation_sum, 0.0): weights = standard_deviations / deviation_sum else: weights = np.full(n_indicators, 1.0 / n_indicators) # 第六步:对正向化数据加权求和,并按综合得分从高到低排序。 scores = normalized @ weights ranking = np.argsort(-scores, kind="stable") return CriticResult( weights=weights, normalized_matrix=normalized, standard_deviations=standard_deviations, correlation_matrix=correlation, conflicts=conflicts, information=information, scores=scores, ranking=ranking, ) def main() -> None: """运行一个供应商综合评价示例。""" alternatives = ["供应商 A", "供应商 B", "供应商 C", "供应商 D"] criteria = ["产品质量", "采购价格", "交付准时率", "售后响应时间"] # 每行代表一个供应商,每列依次对应上面的四项指标。 decision_matrix = np.array( [ [92, 108, 96, 3.0], [88, 100, 91, 2.0], [95, 115, 98, 4.0], [90, 105, 94, 2.5], ], dtype=float, ) indicator_types = ["benefit", "cost", "benefit", "cost"] result = critic_weight(decision_matrix, indicator_types) print("CRITIC 法计算的指标权重:") for criterion, weight in zip(criteria, result.weights): print(f" {criterion}:{weight:.4f}") print("\n方案综合得分与排名:") for rank, index in enumerate(result.ranking, start=1): print( f" 第 {rank} 名:{alternatives[index]}," f"得分 = {result.scores[index]:.4f}" ) if __name__ == "__main__": main()
(base) PS D:\桌面\华为杯\code> & d:/Users/anaconda3/python.exe d:/桌面/华为杯/code/评价类/critic.py CRITIC 法计算的指标权重: 产品质量:0.2532 采购价格:0.2462 交付准时率:0.2501 售后响应时间:0.2505 方案综合得分与排名: 第 1 名:供应商 A,得分 = 0.5635 第 2 名:供应商 D,得分 = 0.5315 第 3 名:供应商 C,得分 = 0.5033 第 4 名:供应商 B,得分 = 0.4967
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/24 14:15:11

2026深度测评10款降AI率工具红黑榜!优缺点全曝光,达标率对标顶级水准

2026 年&#xff0c;AI 写稿、AI 生成内容已经成了学生党、打工人和内容创作者的日常&#xff0c;但随之而来的「AI 率过高」问题也成了新的麻烦&#xff1a;论文查重 AI 率超标、职场报告被判定 AI 生成、自媒体内容过不了平台原创审核… 为了帮大家解决这个痛点&#xff0c;我…

作者头像 李华
网站建设 2026/8/24 14:08:58

单片机毕设项目:融合温光人体检测的 STM32 智能晾衣架设计与开发 本地显示 + 远程 APP 监控 STM32 智能晾衣架系统研究(017204)

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机&#xff0c;Java、小程序技术领域和毕业项目实战 ✌️…

作者头像 李华
网站建设 2026/8/24 14:08:10

团队一体化协同平台怎么选?多款协作工具能力客观记录

日常项目推进、任务派发、流程审批、文件归档、内部沟通时&#xff0c;团队会用到各类协同办公平台。不同工具在任务管理、审批流程、文档能力、权限分级、部署模式上存在明显差异。下文客观记录五款协同相关工具的基础能力与使用局限&#xff0c;本文无任何商业合作&#xff0…

作者头像 李华
网站建设 2026/8/24 14:05:17

SAP Gateway Foundation OData V4 工具全景解析,从服务发布、Metadata Cache 到 Payload Trace 的完整排障链路

在 SAP S/4HANA 项目里,OData V4 服务真正让人头疼的时候,往往不是 CDS View 写错了,也不是 RAP Behavior Definition 激活失败,而是服务已经成功发布,浏览器或者 SAP Fiori 应用也确实发出了 HTTP 请求,返回的数据却和预期不一致。更麻烦的情况是,HTTP Status Code 还是…

作者头像 李华
网站建设 2026/8/24 14:03:08

8.22【A】

3116先是预处理出来各种组合下的LCM然后二分搜索&#xff0c;对于每个数x&#xff0c;由容斥定理算现在问题在于两个&#xff0c;一是如何优雅的预处理&#xff0c;二是如何优雅地使用容斥定理算对于预处理&#xff0c;如果有N个&#xff0c;那就是全组合&#xff0c;从2一直排…

作者头像 李华