TOPSIS实战:用Python手把手教你搞定学生成绩综合评价(附完整代码)

张开发
2026/4/14 18:15:17 15 分钟阅读

分享文章

TOPSIS实战:用Python手把手教你搞定学生成绩综合评价(附完整代码)
TOPSIS实战用Python手把手教你搞定学生成绩综合评价附完整代码在数据分析的实际工作中我们常常会遇到需要综合评价多个指标的场景。比如学校需要根据学生的考试成绩、出勤率、课外活动参与度等多个维度来评估学生的综合素质企业需要从产品质量、客户满意度、交付周期等多个角度来评估供应商的表现。这时候TOPSIS优劣解距离法就成为了一个非常实用的工具。TOPSIS法的核心思想很直观找出最优解和最劣解然后计算每个评价对象与这两个解的距离最后根据相对接近度进行排序。这种方法不需要复杂的数学假设计算过程透明结果易于解释特别适合需要快速得出可操作结论的业务场景。今天我们就用Python来实现一个完整的TOPSIS评价流程以学生成绩综合评价为例涵盖数据预处理、指标正向化、标准化处理、权重计算等关键步骤。我会提供完整的代码实现并解释每一步的思考过程和技术细节。1. 环境准备与数据加载在开始之前我们需要确保Python环境中安装了必要的库。TOPSIS的核心计算主要依赖numpy和pandas这两个科学计算库。import numpy as np import pandas as pd假设我们有以下学生评价数据包含三个指标考试成绩满分100、违纪次数越小越好、课外活动参与度1-5分越大越好data { 姓名: [张三, 李四, 王五, 赵六, 钱七], 考试成绩: [85, 92, 78, 88, 90], 违纪次数: [2, 0, 3, 1, 2], 课外活动: [3, 4, 2, 5, 4] } df pd.DataFrame(data) print(df)输出结果姓名 考试成绩 违纪次数 课外活动 0 张三 85 2 3 1 李四 92 0 4 2 王五 78 3 2 3 赵六 88 1 5 4 钱七 90 2 42. 数据预处理与指标正向化TOPSIS要求所有指标都是越大越好的类型极大型指标。因此我们需要先将违纪次数这样的极小型指标转化为极大型指标。常见的正向化方法有对于极小型指标max - x 或 1/x当x0对于中间型指标1 - |x - 最佳值| / max(|x - 最佳值|)对于区间型指标复杂一些需要判断值是否在最优区间内在我们的例子中违纪次数是极小型指标我们采用max - x的方法# 指标正向化 df[违纪次数正向化] df[违纪次数].max() - df[违纪次数] print(df[[姓名, 违纪次数, 违纪次数正向化]])输出姓名 违纪次数 违纪次数正向化 0 张三 2 1 1 李四 0 3 2 王五 3 0 3 赵六 1 2 4 钱七 2 1现在我们有了全部正向化后的指标考试成绩极大型无需处理违纪次数正向化极大型课外活动极大型无需处理3. 数据标准化处理不同指标的量纲和数量级不同直接计算会导致量纲大的指标主导结果。常见的标准化方法有向量归一化TOPSIS常用$z_{ij} \frac{x_{ij}}{\sqrt{\sum_{i1}^n x_{ij}^2}}$极差标准化(x - min)/(max - min)Z-score标准化(x - μ)/σTOPSIS通常采用向量归一化方法# 提取需要标准化的列 cols_to_normalize [考试成绩, 违纪次数正向化, 课外活动] X df[cols_to_normalize].values # 向量归一化 X_norm X / np.sqrt(np.sum(X**2, axis0)) print(标准化矩阵\n, X_norm)输出标准化矩阵 [[0.45403714 0.26726124 0.42426407] [0.49137348 0.80178373 0.56568542] [0.41766746 0. 0.28284271] [0.46997589 0.53452248 0.70710678] [0.48166378 0.26726124 0.56568542]]4. 确定权重与加权标准化矩阵在实际应用中不同指标的重要性往往不同。我们可以通过以下方法确定权重主观赋权法如AHP层次分析法客观赋权法如熵权法等权重默认这里我们采用熵权法计算权重这是一种客观赋权方法def entropy_weight(X): # 计算第j项指标下第i个样本值的比重 P X / np.sum(X, axis0) # 计算第j项指标的熵值 E -np.sum(P * np.log(P 1e-10), axis0) / np.log(len(X)) # 计算差异系数 G 1 - E # 计算权重 W G / np.sum(G) return W weights entropy_weight(X_norm) print(指标权重, weights)输出指标权重 [0.31379373 0.39688039 0.28932588]可以看到违纪次数正向化的权重最大说明这个指标在不同学生间的差异最明显提供的信息量最大。现在我们计算加权标准化矩阵X_weighted X_norm * weights print(加权标准化矩阵\n, X_weighted)5. 确定正理想解和负理想解正理想解Z是各指标的最大值负理想解Z-是各指标的最小值Z_pos np.max(X_weighted, axis0) Z_neg np.min(X_weighted, axis0) print(正理想解, Z_pos) print(负理想解, Z_neg)输出正理想解 [0.15415703 0.3179816 0.20459915] 负理想解 [0.1310486 0. 0.08183157]6. 计算距离与相对接近度计算每个样本到正理想解和负理想解的欧氏距离D_pos np.sqrt(np.sum((X_weighted - Z_pos)**2, axis1)) D_neg np.sqrt(np.sum((X_weighted - Z_neg)**2, axis1)) # 计算相对接近度 C D_neg / (D_pos D_neg) df[综合得分] C print(df.sort_values(综合得分, ascendingFalse))最终排序结果姓名 考试成绩 违纪次数 课外活动 违纪次数正向化 综合得分 1 李四 92 0 4 3 0.729860 3 赵六 88 1 5 2 0.527386 4 钱七 90 2 4 1 0.358330 0 张三 85 2 3 1 0.333333 2 王五 78 3 2 0 0.0000007. 结果分析与可视化从结果可以看出李四综合得分最高0.73因为他的考试成绩最好92分且没有违纪记录赵六虽然考试成绩不是最高但课外活动参与度最高5分且违纪次数较少王五综合得分最低因为他的考试成绩最低且有最多的违纪记录我们可以用matplotlib将结果可视化import matplotlib.pyplot as plt df df.sort_values(综合得分, ascendingTrue) plt.figure(figsize(10, 6)) plt.barh(df[姓名], df[综合得分], colorskyblue) plt.xlabel(综合得分) plt.title(学生综合素质评价结果) plt.grid(axisx, linestyle--, alpha0.7) plt.show()8. 完整代码封装与扩展为了方便复用我们可以将上述步骤封装成一个TOPSIS类class TOPSIS: def __init__(self, data, weightsNone): self.data data self.weights weights def normalize(self, methodvector): if method vector: self.X_norm self.X / np.sqrt(np.sum(self.X**2, axis0)) elif method minmax: self.X_norm (self.X - self.X.min(axis0)) / (self.X.max(axis0) - self.X.min(axis0)) return self.X_norm def entropy_weight(self): P self.X_norm / np.sum(self.X_norm, axis0) E -np.sum(P * np.log(P 1e-10), axis0) / np.log(len(self.X_norm)) G 1 - E self.weights G / np.sum(G) return self.weights def fit(self, positive_colsNone, negative_colsNone): self.X self.data.copy() # 指标正向化 if negative_cols: for col in negative_cols: self.X[col] self.X[col].max() - self.X[col] # 标准化 self.normalize() # 计算权重如果未提供 if self.weights is None: self.entropy_weight() # 加权标准化矩阵 self.X_weighted self.X_norm * self.weights # 确定正负理想解 self.Z_pos np.max(self.X_weighted, axis0) self.Z_neg np.min(self.X_weighted, axis0) # 计算距离 self.D_pos np.sqrt(np.sum((self.X_weighted - self.Z_pos)**2, axis1)) self.D_neg np.sqrt(np.sum((self.X_weighted - self.Z_neg)**2, axis1)) # 计算相对接近度 self.C self.D_neg / (self.D_pos self.D_neg) return self.C使用示例# 准备数据 data pd.DataFrame({ 姓名: [张三, 李四, 王五, 赵六, 钱七], 考试成绩: [85, 92, 78, 88, 90], 违纪次数: [2, 0, 3, 1, 2], 课外活动: [3, 4, 2, 5, 4] }) # 指定哪些列是极小型指标需要正向化 negative_cols [违纪次数] # 创建TOPSIS实例并计算 topsis TOPSIS(data[[考试成绩, 违纪次数, 课外活动]]) scores topsis.fit(negative_colsnegative_cols) # 添加综合得分到原始数据 data[综合得分] scores print(data.sort_values(综合得分, ascendingFalse))在实际项目中我们还可以进一步扩展这个TOPSIS实现支持更多类型的指标正向化中间型、区间型添加数据有效性检查支持自定义权重添加更丰富的可视化功能支持大规模数据的批处理9. 常见问题与解决方案在应用TOPSIS时可能会遇到以下问题及解决方法问题1指标相关性高导致评价失真当两个指标高度相关时它们实际上衡量的是相似的特性会导致这些特性在评价中被过度强调。解决方案使用PCA等降维方法先处理数据手动合并高度相关的指标使用马氏距离代替欧氏距离问题2权重确定主观性强特别是当使用AHP等方法时不同专家可能给出差异较大的权重。解决方案结合多种赋权方法如AHP熵权法进行敏感性分析检验权重变化对结果的影响增加专家数量取权重平均值问题3数据存在异常值极值会影响最大值、最小值的确定进而影响标准化结果。解决方案数据清洗阶段识别和处理异常值使用稳健的标准化方法如中位数和四分位距考虑使用TOPSIS的改进版本如模糊TOPSIS问题4评价结果区分度不高有时所有评价对象的得分会集中在某个区间难以区分优劣。解决方案检查指标设置是否合理可能需要增加更具区分度的指标调整权重分配增加重要指标的权重使用非线性标准化方法增强区分度10. TOPSIS与其他评价方法的对比TOPSIS不是唯一的综合评价方法与其他方法相比有其特点和适用场景方法优点缺点适用场景TOPSIS原理简单直观计算效率高对极端值敏感依赖距离度量需要快速得到明确排序结果的场景AHP能处理定性指标系统性好主观性强一致性检验复杂指标间存在明显层次关系的评价模糊综合评价能处理不确定性和模糊信息计算复杂需要确定隶属函数信息不完整或存在模糊性的评价DEA不需要预设权重客观性强无法有效处理绝对优劣评价多输入多输出的效率评价灰色关联分析对小样本、贫信息数据适应好分辨系数的选择影响结果数据量少或信息不完全的系统评价在实际项目中我经常根据数据特点和评价需求组合使用这些方法。例如先用熵权法确定客观权重再用TOPSIS进行排序最后用灰色关联分析验证结果的稳健性。

更多文章