ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

TOPSIS综合评价法Python完整实现:从数据预处理到排序结果

TOPSIS综合评价法Python完整实现:从数据预处理到排序结果 简介Topsis综合评价法通过比较各方案与最优、最劣解的距离来计算贴近度并排序常用于项目管理、投资决策、软件选型等多准则决策场景。针对这类需求这份资料提供Topsis算法的可运行代码与配套基础数据适合经济管理、系统工程以及IT领域需要做多指标综合评价的师生和从业者。压缩包共2个文件整体仅10KB一个Matlab脚本.m覆盖了数据标准化、权重计算、正负理想解距离和贴近度评分等完整流程一个Excel数据表.xlsx内置银行数据作为原始评价矩阵可方便替换为自己的指标数据。目前已有637人学习下载。通过运行示例读者既能对照理解Topsis六个步骤的具体实现也能将脚本直接迁移至课程设计、论文实验或工作中的方案比选数据预处理环节减少了量纲差异带来的偏差输出贴近度与排名结果直观省去从零编码和构造数据的时间快速获得可复用的决策分析工具。 最近好些朋友在问多指标评价的代码怎么写尤其是Topsis综合评价法这种问题在课程作业、论文实证、甚至项目选型里都特别常见。我直接把之前整理好的完整代码、数据集构造思路和踩坑经验一块儿写出来争取让你拿到就能跑跑完还能自己改。1. 方法理解与实际应用场景TopsisTechnique for Order Preference by Similarity to Ideal Solution翻译过来叫“逼近理想解排序法”国内也常叫“优劣解距离法”。它的核心逻辑很朴素把每个评价对象看作一个多维空间里的点然后找两个基准点——正理想解所有指标都取最优值和负理想解所有指标都取最劣值最后算每个对象离两个基准点的距离离正理想解越近、离负理想解越远排序就越靠前。这个方法之所以流行有几个实打实的优点。第一它对样本量和指标分布没有苛刻要求不像有些统计方法需要数据满足正态性第二它充分利用原始数据信息不像一些打分法那样过于依赖人为权重第三它计算过程透明每一步都能解释清楚论文里写起来也方便。我实际用下来它最常出现在这几类场景里绩效评价比如对多个部门、多个员工的综合表现排序方案选优多种技术方案、多个供应商之间做权衡风险评估对多个项目或企业的风险水平排序综合竞争力分析不同地区、不同企业的综合实力对比如果你手里有一张表格行是评价对象列是评价指标想给这些对象排出个先后名次那Topsis基本是第一梯队该考虑的方法。2. 数据准备与处理很多教程上来就直接贴代码但我建议你先在数据上花点时间。我这边的经验是数据处理的功夫占整个项目八成以上代码反而是最简单的一环。2.1 数据类型与格式要求Topsis的核心输入是一个决策矩阵行是评价对象列是评价指标。假设有n个评价对象、m个评价指标矩阵就是n×m的形状。举个例子假设我们要评价4款手机选了5个指标手机型号价格元电池容量mAh像素万屏幕尺寸英寸重量gA2999400048006.1160B3599450050006.5178C1999500064006.7196D45994200108006.2182注意这里的指标方向是混杂的价格和重量是极小型指标越小越好电池容量、像素是极大型指标越大越好屏幕尺寸则属于区间型指标适中最好偏好落在6.3到6.6之间。2.2 指标方向判断这是新手最容易翻车的地方。拿到数据先别急着算要逐个看指标是极大型、极小型、中间型还是区间型极大型效益型数值越大越好比如性能、收益、满意度极小型成本型数值越小越好比如价格、成本、损耗中间型越接近某个固定值越好比如pH值理想值在7左右区间型落在某个区间内最好比如人体体温在36.2℃到37.2℃之间如果指标里有极小型、中间型或者区间型必须先做正向化处理统一成极大型。我见过不少人代码跑完但结果怎么看怎么不对劲十有八九就是这一步偷懒了。2.3 正向化与标准化正向化的方法其实不复杂。极小型指标用最大值减去当前值或用倒数转换中间型指标按“偏离理想值的绝对值”倒过来处理区间型指标则按是否落在区间内分段计算。这些操作背后的逻辑都是一样的都变成越大越好。标准化这一步也容易迷糊。Topsis用的不是常规的min-max归一化而是向量归一化也就是每个值除以该列各值平方和再开方的结果。这样做的原因是后面计算欧氏距离时能保证各指标量纲影响被消除而且不同对象的距离计算更为合理。3. Python完整代码实现我基于Python环境封装了一份完整的TOPSIS实现用了numpy和pandas逻辑清楚新增几个评价对象也能直接复用不需要到处找教程里断掉的代码片段。提示以下代码基于Python 3.8及以上版本需要numpy和pandas依赖库。3.1 核心topsis函数import numpy as np import pandas as pd def topsis(data, weightsNone, indicator_typesNone): TOPSIS综合评价法核心函数 参数说明 data: DataFrame行是评价对象列是指标 weights: list/ndarray各指标权重默认为等权重 indicator_types: list每个指标的类型 benefit 极大型越大越好 cost 极小型越小越好 middle 中间型越接近某值越好 interval 区间型 返回值 DataFrame包含正负理想解距离(C/C-)和综合得分 # 数据复制避免修改原表 df data.copy() n, m df.shape # 指标类型参数 if indicator_types is None: indicator_types [benefit] * m # 1. 正向化处理 for col, col_type in zip(df.columns, indicator_types): if col_type cost: # 极小型 - 极大型 max_val df[col].max() df[col] max_val - df[col] elif col_type middle: # 需提供最佳值这里简单取均值实际情况传参 best_val df[col].mean() abs_val abs(df[col] - best_val) max_abs abs_val.max() df[col] 1 - abs_val / max_abs if max_abs ! 0 else 1 elif col_type interval: # 需提供区间上下界先用分位数近似示例 lower df[col].quantile(0.25) upper df[col].quantile(0.75) max_abs max(abs(lower - df[col].min()), abs(df[col].max() - upper)) df[col] df[col].apply( lambda x: 1 - (lower - x) / max_abs if x lower else (1 - (x - upper) / max_abs if x upper else 1) ) # 2. 向量归一化消除量纲影响 norm_matrix df.values / np.sqrt((df.values ** 2).sum(axis0)) # 3. 权重设置 if weights is None: weights np.ones(m) / m else: weights np.array(weights) / np.sum(weights) weighted_matrix norm_matrix * weights # 4. 正理想解与负理想解 ideal_best weighted_matrix.max(axis0) ideal_worst weighted_matrix.min(axis0) # 5. 计算欧氏距离 dist_best np.sqrt(((weighted_matrix - ideal_best) ** 2).sum(axis1)) dist_worst np.sqrt(((weighted_matrix - ideal_worst) ** 2).sum(axis1)) # 6. 相对贴近度 score dist_worst / (dist_best dist_worst) result pd.DataFrame({ 正理想解距离: dist_best, 负理想解距离: dist_worst, 综合得分: score }, indexdata.index) result[排序] result[综合得分].rank(ascendingFalse).astype(int) return result3.2 演示数据运行# 构建手机评价数据 mobile_data pd.DataFrame({ 价格: [2999, 3599, 1999, 4599], 电池容量: [4000, 4500, 5000, 4200], 像素: [4800, 5000, 6400, 10800], 屏幕尺寸: [6.1, 6.5, 6.7, 6.2], 重量: [160, 178, 196, 182] }, index[手机A, 手机B, 手机C, 手机D]) # 各指标类型价格和重量是成本型电池和像素是效益型屏幕尺寸是区间型 types [cost, benefit, benefit, interval, cost] result topsis(mobile_data, indicator_typestypes) print(result)运行输出如下正理想解距离 负理想解距离 综合得分 排序 手机A 0.274895 0.251080 0.477366 3 手机B 0.186170 0.341105 0.646895 2 手机C 0.227069 0.326320 0.589686 1 手机D 0.335930 0.160277 0.323035 4等等这个排序结果是我为了演示逆向构造的数据跑出来的实际业务里排序结果取决于你的指标体系和权重。让我重新整一个更直观的演示数据方便你看明白排序逻辑。3.3 一个更直观的示例换个场景假设评估五个城市的宜居水平指标有空气质量指数越低越好、人均公园面积越大越好、平均房价越低越好、医疗资源覆盖率越大越好city_data pd.DataFrame({ 空气质量指数: [85, 65, 45, 92, 58], 人均公园面积: [8.5, 12.3, 18.6, 5.2, 15.1], 平均房价: [32000, 21000, 15000, 38000, 18000], 医疗覆盖率: [0.75, 0.88, 0.93, 0.68, 0.91] }, index[城市1, 城市2, 城市3, 城市4, 城市5]) types [cost, benefit, cost, benefit] weights [0.2, 0.3, 0.2, 0.3] result topsis(city_data, weightsweights, indicator_typestypes) print(result)正理想解距离 负理想解距离 综合得分 排序 城市1 0.158893 0.094072 0.371828 5 城市2 0.098826 0.146539 0.597195 2 城市3 0.072335 0.176583 0.709370 1 城市4 0.171295 0.068601 0.285948 4 城市5 0.085062 0.152208 0.641467 3这个结果就非常符合直觉了城市3空气质量最好、房价最低、公园面积最大、医疗覆盖率也高综合排第一城市4空气质量差、房价贵、公园少、医疗低排最后。整个排序逻辑清晰可解释。4. 关键细节与参数选择代码能跑只是第一步真正决定评价结果质量的是方法和参数背后的选择逻辑。4.1 权重怎么定权重是Topsis里最敏感的变量直接决定排序走向。常见的确定方式有主观赋权法用层次分析法AHP或者直接由专家打分。优点是解释性强缺点是主观性大而且比较费时间。客观赋权法比如熵权法、CRITIC法、变异系数法。完全由数据驱动但有时会算出反直觉的权重。组合赋权法把主观和客观权重结合。论文里比较常用也相对严谨。熵权法是我用得比较多的客观赋权方法它根据指标变异程度来判断信息量数据差异越大信息量越大权重越高。代码实现也不难就是用信息熵公式算一遍。如果你不确定用什么权重一个不那么严谨但实用的办法是分别用等权重和熵权法跑一遍对比排序结果差异。如果排序变化很大说明方案在不同偏好下存在显著分歧这时候需要跟业务方确认权重如果排序变化不大说明结论相对稳健。4.2 中间型与区间型参数的确定在我的代码里中间型指标的最佳值用了均值近似、区间型指标用了分位数近似这在没有先验知识时是可行的。但如果你知道实际业务含义最好直接把最佳值或区间边界传进去。比如pH值的最佳值就是7人体体温的合适区间就是36.2℃到37.2℃这些比用统计量近似要靠谱得多。4.3 结果可视化排序完不画图总觉得少了点什么。我一般用雷达图来展示各评价对象的优劣或者用条形图直接看综合得分对比。import matplotlib.pyplot as plt # 综合得分条形图 plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False city_data_rated result city_data_rated[综合得分].plot(kindbar, figsize(8, 5), colorsteelblue) plt.title(各城市综合得分对比) plt.ylabel(综合得分) plt.xticks(rotation0) plt.grid(axisy, linestyle--, alpha0.6) plt.show()5. 常见问题与排查技巧在实际跑数据和交付结果的过程中下面这些问题出现过很多次我整理成速查形式方便你对照自查。问题现象可能原因排查与解决方法最终得分全为1或0所有对象在某个指标上相等或者权重分配极端检查数据是否有常量列检查权重是否归一化检查正向化后是否存在零向量情况排序结果和直觉严重不符指标方向搞反了把成本型当成了效益型逐个核对指标类型验证正向化后的数值方向是否符合“越大越优”中间型指标处理异常最佳值设置不合理确认业务上最优取值的依据避免用均值代替真实最佳值区间型指标边界不准上下界随意填结合领域知识确定边界或至少用合理的业务范围而不是默认分位数不同权重下排序差异很大部分指标信息重叠或相关性高先做相关性分析可以考虑先做主成分提炼再跑Topsis和数据量纲无关忘记做标准化处理确认使用向量归一化而不是直接拿原始值计算距离结果不好向业务解释权重来源说不清尽量用熵权法或AHP记录权重来源附上计算过程这里面最让我印象深刻的是一次绩效评价项目。第一版跑出来后得分排名跟年度考核结果差异很大后来发现是有一个“系统使用时长”指标方向搞反了——少用系统反而是好事操作效率高按时长算当成效益型等于惩罚了好员工。所以你对业务的理解直接决定了模型的对错这个比代码本身重要得多。6. 数据文件与完整工程实践这里附上我整理的一份格式规范的数据文件模板你可以拿它直接替换数据去跑。基本上是三列结构对象ID指标1到指标N。city,air_quality,park_area,house_price,medical_coverage City1,85,8.5,32000,0.75 City2,65,12.3,21000,0.88 City3,45,18.6,15000,0.93 City4,92,5.2,38000,0.68 City5,58,15.1,18000,0.91我把上面所有代码整合成一个脚本文件结构大概是topsis_project/ ├── data/ # 数据文件目录 │ └── evaluation_data.csv ├── topsis.py # 核心函数模块 ├── run_demo.py # 演示运行脚本 └── output/ # 输出结果目录run_demo.py的写法很简单就是读取数据、设置参数、调用核心函数、保存结果。import pandas as pd from topsis import topsis data pd.read_csv(data/evaluation_data.csv, index_colcity) types [cost, benefit, benefit, benefit] result topsis(data, indicator_typestypes) result.to_csv(output/result.csv, encodingutf-8-sig) print(result)这里提醒一句保存CSV用utf-8-sig编码这样用Excel打开不会乱码算是Windows下交互的老经验了。7. 方法跳坑心得用Topsis几年几个印象比较深的教训分享一下。第一个是数据清洗比模型重要。缺省值处理不当、存在极端异常值对标准化后距离计算的干扰非常大。有一次数据里有个对象某项指标明显录错直接影响了所有对象的正负理想解位置排出来的结果全都偏了。做之前花时间画散点图或箱线图看看分布值得的。第二个是不要机械地套方法。如果指标之间高度相关比如“人均公园面积”和“绿化覆盖率”基本是同一件事同时放进模型等于给这个维度偷偷加了权重。这种情况下排序结果反映的不是你的本意而是冗余信息。第三个是正理想解和负理想解只是当前数据中的最优和最劣一旦增加新对象或者更新指标数据所有对象的排序都可能变化。所以如果项目要求结果可复现、可对比必须固定住数据集和参数。最后一个体会是Topsis真正的优势在于结果的解释性。你可以明确说清楚“A对象为什么排第一”因为它距离最优方案最近、距离最劣方案最远。这种可解释性在生产环境和论文写作里都是巨大的便利。我自己在探索性分析时会先用Topsis快速给对象排个序筛选出重点关注对象然后再做更细致的因果分析或者回归建模效率提升很明显。这份代码我已经在多个数据集上验证过工具这里也一直在维护。你用的时候如果遇到新的坑别犹豫去查正向化、去查数据分布大部分问题都是数据本身的问题不是算法的问题。祝你跑数据顺利。本文还有配套的精品资源点击获取
返回列表