用Python实战熵权TOPSIS:从数据清洗到科学决策的全流程指南
当我们需要对多个候选方案进行综合评价时,如何避免主观赋权带来的偏差?熵权TOPSIS组合模型提供了一种数据驱动的客观解决方案。这个方法论在学术研究、企业决策和工程评估中都有广泛应用,但很多实践者仍停留在理论层面,不知如何落地。本文将用完整的Python代码演示如何从原始数据到科学决策。
1. 环境准备与数据加载
工欲善其事,必先利其器。我们需要配置一个稳定的分析环境:
import numpy as np import pandas as pd from sklearn.preprocessing import MinMaxScaler import matplotlib.pyplot as plt plt.style.use('ggplot') # 使用更美观的绘图样式假设我们有一个供应商评估的Excel文件,包含以下指标:
- 价格(万元,越小越好)
- 交货周期(天,越小越好)
- 质量合格率(%,越大越好)
- 售后服务评分(1-10分,越大越好)
# 读取示例数据 data = pd.read_excel('supplier_evaluation.xlsx') print("原始数据预览:") print(data.head()) # 保存原始列名便于后续处理 columns = data.columns.tolist()2. 数据预处理:指标正向化
不同类型的指标需要统一转换为极大型(效益型)指标:
def normalize_indicators(df): """指标正向化处理""" df_normalized = df.copy() # 极小型 -> 极大型 df_normalized['价格'] = df['价格'].max() - df['价格'] df_normalized['交货周期'] = df['交货周期'].max() - df['交货周期'] return df_normalized normalized_data = normalize_indicators(data) print("\n正向化后数据:") print(normalized_data.head())3. 数据标准化:消除量纲影响
不同指标的量纲和量级差异会影响结果,需要进行标准化:
def standardize_data(df): """Z-score标准化""" scaler = MinMaxScaler() # 采用MinMax标准化到[0,1]区间 scaled_array = scaler.fit_transform(df) return pd.DataFrame(scaled_array, columns=df.columns) standardized_data = standardize_data(normalized_data) print("\n标准化后矩阵:") print(standardized_data)4. 熵权法计算指标权重
通过信息熵计算各指标的客观权重:
def calculate_entropy_weights(df): """计算熵权""" # 计算比重矩阵 p = df.div(df.sum(axis=0), axis=1) # 计算信息熵 k = 1 / np.log(len(df)) entropy = -k * (p * np.log(p)).sum(axis=0) # 计算权重 diversity = 1 - entropy weights = diversity / diversity.sum() return weights.round(4) weights = calculate_entropy_weights(standardized_data) print("\n各指标权重:") print(weights)5. TOPSIS综合评价
结合权重计算各方案与理想解的相对接近度:
def topsis_method(df, weights): """带权重的TOPSIS评价""" # 加权标准化矩阵 weighted_matrix = df * weights.values # 确定理想解和负理想解 ideal_best = weighted_matrix.max() ideal_worst = weighted_matrix.min() # 计算距离 d_best = np.sqrt(((weighted_matrix - ideal_best) ** 2).sum(axis=1)) d_worst = np.sqrt(((weighted_matrix - ideal_worst) ** 2).sum(axis=1)) # 计算相对接近度 score = d_worst / (d_best + d_worst) return score.sort_values(ascending=False).round(4) final_scores = topsis_method(standardized_data, weights) print("\n供应商综合评价得分:") print(final_scores)6. 结果可视化与分析
直观展示评价结果:
def visualize_results(scores, original_data): """结果可视化""" fig, ax = plt.subplots(figsize=(10, 6)) # 绘制雷达图展示各供应商表现 categories = original_data.columns.tolist() N = len(categories) angles = np.linspace(0, 2 * np.pi, N, endpoint=False).tolist() angles += angles[:1] # 闭合图形 for idx in range(3): # 展示前三名供应商 values = original_data.iloc[scores.index[idx]].tolist() values += values[:1] ax.plot(angles, values, linewidth=2, label=f"供应商{scores.index[idx]+1} (得分:{scores.iloc[idx]})") ax.fill(angles, values, alpha=0.25) ax.set_xticks(angles[:-1]) ax.set_xticklabels(categories) ax.set_title('TOP3供应商各指标表现对比', pad=20) ax.legend(loc='upper right', bbox_to_anchor=(1.3, 1)) plt.tight_layout() plt.show() visualize_results(final_scores, data)7. 实战中的常见问题与解决方案
在实际应用中,我们经常会遇到一些典型问题:
指标相关性处理
- 问题:多个指标高度相关导致信息重复
- 解决方案:先进行PCA降维或删除相关性>0.9的指标
数据缺失处理
- 问题:部分供应商某些指标缺失
- 解决方案:采用列均值填充或使用随机森林预测缺失值
权重合理性检验
def check_weights_reasonableness(weights, threshold=0.1): """检查是否有指标权重过低""" return weights[weights < threshold].index.tolist() low_weight_indicators = check_weights_reasonableness(weights) print(f"\n需要人工复核的指标:{low_weight_indicators}")敏感性分析
- 通过微调权重观察排名变化,评估模型稳定性
8. 进阶应用:动态权重调整
对于需要随时间变化的评价场景,我们可以实现动态权重:
def dynamic_entropy_topsis(data_series, window_size=5): """滑动窗口动态评价""" results = [] for i in range(len(data_series) - window_size + 1): window_data = data_series[i:i+window_size] weights = calculate_entropy_weights(window_data) scores = topsis_method(window_data, weights) results.append(scores) return pd.concat(results, axis=1) # 假设我们有按时间排序的多个评价周期数据 # dynamic_scores = dynamic_entropy_topsis(standardized_data)9. 与其他评价方法的对比
为验证模型效果,我们可以对比几种常见方法:
| 方法 | 优点 | 局限性 | 适用场景 |
|---|---|---|---|
| 熵权TOPSIS | 客观赋权,计算简单 | 无法处理模糊信息 | 数据量适中的精确评价 |
| AHP | 能处理定性指标 | 主观性强,一致性检验复杂 | 专家经验主导的评估 |
| 灰色关联 | 对小样本适应好 | 分辨率有时较低 | 数据稀缺的不确定系统 |
| DEA | 不需要预设权重 | 无法直接排序 | 效率评价 |
10. 完整项目结构建议
对于实际项目,推荐以下文件结构:
/project_root │── /data │ ├── raw_data.xlsx # 原始数据 │ └── processed_data.csv # 处理后的数据 │── /notebooks │ ├── 1_data_exploration.ipynb │ └── 2_entropy_topsis.ipynb │── /src │ ├── preprocessing.py # 数据预处理函数 │ └── evaluation.py # 评价模型核心代码 │── requirements.txt # 依赖库 └── README.md # 项目说明在数据科学项目中,这种结构既保证了代码的可复用性,又便于团队协作和结果复现。实际开发时,可以将核心函数封装为Python模块,通过Jupyter Notebook进行交互式分析。