1. 项目概述为什么需要一份专属的代码记录做数学建模无论是参加比赛还是完成课程作业最让人头疼的瞬间之一大概就是比赛进行到一半或者作业写到深夜突然需要用到某个算法或数据处理技巧你明明记得上次用过但死活想不起来代码放在哪个文件夹、当时用了什么参数、甚至为什么那么写。翻遍硬盘里一堆命名混乱的untitled.py、final_final2.m时间就在这种焦躁的搜索中流逝了。“数学建模复习——代码记录”这个项目解决的正是这个痛点。它不是一个简单的代码打包合集而是一套经过系统化整理、带有详细注释和实战心得的“个人代码工具箱”。其核心价值在于将你在历次建模实践中零散、临时的代码片段转化为可快速检索、即拿即用的标准化资产。无论是准备美赛、国赛还是应对期末大作业这份记录都能让你在关键时刻快人一步把精力集中在模型构建和论文写作上而不是在调试基础代码上反复踩坑。这份记录的目标读者非常明确所有正在学习或即将参与数学建模的在校学生以及任何需要频繁使用数学工具解决实际问题的数据分析爱好者。对于新手它是一份避坑指南和快速上手的脚手架对于有经验的选手它则是提高效率、保证代码质量的“第二大脑”。接下来我将详细拆解如何从零开始构建这样一份高价值的代码记录并分享我在多年指导和参赛中积累的核心心法。2. 代码记录的整体架构设计一份好的代码记录绝不是把代码扔进一个文件夹那么简单。它需要清晰的逻辑结构、统一的编码风格和丰富的上下文信息。一个混乱的代码库其查找成本甚至高于重写。因此在动手写第一行代码之前设计好顶层架构至关重要。2.1 目录结构规划按模块而非按比赛划分很多同学习惯按比赛或作业来建立文件夹比如2023_MCM/、2024_国赛/。这在项目归档时没问题但对于“复习”和“复用”来说效率极低。因为你很难记住某个优化算法是在哪次比赛中用的。我强烈建议采用“按功能模块”划分的目录结构。这样当你需要解决一个“数据预处理”或“综合评价”问题时可以直接进入对应的模块查找。一个推荐的目录结构如下math_modeling_codebook/ ├── README.md # 项目总说明包含快速指南和更新日志 ├── requirements.txt # Python环境依赖包列表若主要使用Python ├── data_preprocessing/ # 数据预处理模块 │ ├── missing_value_handling.py │ ├── outlier_detection.py │ ├── normalization_scaling.py │ └── feature_engineering.py ├── classical_models/ # 经典模型模块 │ ├── regression_models/ # 回归模型 │ ├── classification_models/# 分类模型 │ ├── clustering_models/ # 聚类模型 │ └── time_series/ # 时间序列 ├── optimization_algorithms/ # 优化算法模块 │ ├── linear_programming.py │ ├── integer_programming.py │ ├── heuristic_algorithms/ # 启发式算法遗传、模拟退火等 │ └── multi_objective_optimization.py ├── evaluation_methods/ # 评价与决策方法 │ ├── ahp_entropy_weight.py # 层次分析法、熵权法 │ ├── topsis.py # TOPSIS法 │ ├── fuzzy_comprehensive_evaluation.py # 模糊综合评价 │ └── grey_relational_analysis.py # 灰色关联分析 ├── visualization/ # 可视化模块 │ ├── basic_plots.py │ ├── advanced_charts.py # 热力图、雷达图、三维图等 │ └── map_visualization.py # 地理信息可视化如有需要 └── utils/ # 工具函数模块 ├── file_io.py # 文件读写封装 ├── performance_metrics.py # 各种评估指标计算 └── timer_decorator.py # 计时装饰器用于性能分析这种结构的优势在于“所见即所得”。你需要什么功能就进入什么文件夹。每个.py文件都应是一个独立、完整的函数或类集合专注于解决一个特定子问题。2.2 代码规范与注释标准让未来的自己能看懂代码是写给人看的只是偶尔让机器执行。尤其是复习时你可能已经忘了半年前自己的思路。因此统一的编码规范和详尽的注释是代码记录的生命线。1. 文件头注释每个.py文件开头必须用三引号包含一个标准化的文件头至少包括功能描述这个文件是干什么的核心函数/类列表主要提供了哪些接口输入输出示例快速展示如何使用。作者与日期记录版本历史。注意事项使用时的关键前提或常见陷阱。 文件名topsis.py 功能实现TOPSIS逼近理想解排序法综合评价模型。 核心函数 - topsis(data_matrix, weight_vector, positive_idealNone): 主计算函数。 - normalize_matrix(matrix, methodvector): 矩阵归一化。 接口说明 输入data_matrix (np.ndarray, m*n), weight_vector (list/np.ndarray, n), positive_ideal (list, optional 指定哪些指标为正向指标). 输出综合得分列表、排序结果。 示例 scores, ranking topsis(data, [0.2, 0.3, 0.5], positive_ideal[True, True, False]) 作者YourName 创建日期2023-10-01 最后修改2024-04-15 注意 1. 默认所有指标均为正向越大越好。若有负向指标必须通过positive_ideal参数指定。 2. weight_vector之和应为1函数内部不会自动归一化。 3. 输入矩阵不应包含NaN或Inf建议先进行预处理。 2. 函数级注释每个函数定义下方使用Args:、Returns:、Raises:等标准段落许多IDE自动生成进行说明。重点解释参数的业务含义而不仅仅是数据类型。3. 行内注释在复杂的逻辑块、关键的算法步骤或使用了“黑魔法”技巧的地方用简洁的注释说明“为什么这么做”。例如# 使用Ward连接法适用于类簇方差最小化的场景就比# 使用methodward更有价值。实操心得养成“写代码即写文档”的习惯。在编写函数的同时立刻把注释写好。如果事后补你一定会忘记很多当时的设计细节。我常用一个“五分钟法则”如果一个函数你无法在五分钟内通过自己的注释完全理解其作用和用法那么注释就是不合格的。3. 核心模块的代码实现与解析有了好的结构接下来就是填充内容。数学建模涉及面广我们选取几个最核心、最通用的模块看看如何实现一份既稳健又灵活的代码记录。3.1 数据预处理模块的稳健性实现数据预处理是建模的基石其代码的健壮性直接决定后续模型的成败。这里以缺失值处理和异常值检测为例。缺失值处理一个常见的错误是简单地用均值或中位数填充所有缺失值。在实际建模中我们需要根据数据的特性和缺失机制来选择策略。我的代码记录中会包含一个综合性的处理函数。import numpy as np import pandas as pd from sklearn.impute import SimpleImputer, KNNImputer def handle_missing_values(df, strategyauto, **kwargs): 智能处理缺失值。 Args: df: pandas DataFrame 待处理的数据框。 strategy: 填充策略。 mean/median/most_frequent: 使用sklearn的SimpleImputer。 knn: 使用KNNImputer计算量大但更合理。 auto: 自动策略。数值列缺失率5%用中位数否则用KNN分类列用众数。 **kwargs: 传递给具体Imputer的参数如n_neighbors for KNN。 Returns: 处理后的DataFrame。 df_filled df.copy() missing_ratio df.isnull().sum() / len(df) for col in df.columns: if df[col].isnull().any(): col_type df[col].dtype miss_rate missing_ratio[col] # 自动策略逻辑 if strategy auto: if np.issubdtype(col_type, np.number): # 数值型 if miss_rate 0.05: # 缺失较少 imp SimpleImputer(strategymedian) else: # 缺失较多考虑样本间关系 imp KNNImputer(n_neighbors5) df_filled[col] imp.fit_transform(df[[col]]).ravel() else: # 非数值型对象、分类 imp SimpleImputer(strategymost_frequent) df_filled[col] imp.fit_transform(df[[col]]).ravel() else: # 指定策略 # ... 其他策略的实现 pass return df_filled注意事项KNN填充虽然效果好但会严重拖慢大数据集的处理速度。在时间紧迫的比赛中对于缺失率低的数据用中位数或均值填充是更务实的选择。务必在函数注释里提醒这一点。异常值检测我通常会记录多种方法因为不同方法对“异常”的定义不同。def detect_outliers_iqr(series, scale1.5): 使用IQR四分位距法检测异常值适用于近似正态分布的数据。 Q1 series.quantile(0.25) Q3 series.quantile(0.75) IQR Q3 - Q1 lower_bound Q1 - scale * IQR upper_bound Q3 scale * IQR return (series lower_bound) | (series upper_bound) def detect_outliers_zscore(series, threshold3): 使用Z-score法检测异常值假设数据服从正态分布。 from scipy import stats z_scores np.abs(stats.zscore(series.dropna())) outlier_mask np.zeros(len(series), dtypebool) outlier_mask[series.notna()] z_scores threshold return outlier_mask def detect_outliers_isolation_forest(df, contamination0.05): 使用孤立森林进行多变量异常值检测能捕捉复杂的非线性关系。 from sklearn.ensemble import IsolationForest clf IsolationForest(contaminationcontamination, random_state42) preds clf.fit_predict(df.select_dtypes(include[np.number])) return preds -1 # -1表示异常在记录中我会用一个对比表格说明每种方法的适用场景和优缺点帮助复习时快速选择方法原理优点缺点适用场景IQR法基于数据四分位距计算快不依赖分布假设只适用于单变量对非对称分布敏感初步筛查单指标异常判断Z-score法基于数据与均值的标准差距离标准统计方法意义明确严格依赖正态分布假设数据近似正态分布时孤立森林通过构建随机树隔离样本适用于多变量、非线性关系无需分布假设计算量较大参数contamination需估计高维数据复杂异常模式3.2 经典模型模块的模板化封装在建模中我们经常需要快速尝试多个模型并比较效果。为此我会封装一个“模型训练与评估”的模板函数将数据拆分、训练、预测、评估和基础可视化流水线化。import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score def train_evaluate_model(model, X, y, model_nameModel, test_size0.2, random_state42, plotTrue): 通用模型训练与评估模板。 Args: model: 未训练的sklearn风格模型对象。 X: 特征数据。 y: 标签数据。 model_name: 模型名称用于打印和绘图。 test_size: 测试集比例。 random_state: 随机种子。 plot: 是否绘制真实值-预测值散点图。 Returns: dict: 包含训练好的模型、预测结果和各项评估指标的字典。 # 1. 划分数据集 X_train, X_test, y_train, y_test train_test_split( X, y, test_sizetest_size, random_staterandom_state ) # 2. 训练模型 model.fit(X_train, y_train) # 3. 预测 y_pred model.predict(X_test) # 4. 评估 mse mean_squared_error(y_test, y_pred) mae mean_absolute_error(y_test, y_pred) r2 r2_score(y_test, y_pred) metrics { MSE: round(mse, 4), MAE: round(mae, 4), R²: round(r2, 4) } print(f[{model_name}] 评估结果:) for key, value in metrics.items(): print(f {key}: {value}) # 5. 可视化 if plot: plt.figure(figsize(8, 6)) plt.scatter(y_test, y_pred, alpha0.6, edgecolorsk) plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], r--, lw2) # 对角线 plt.xlabel(True Values) plt.ylabel(Predicted Values) plt.title(f{model_name}: True vs Predicted) plt.grid(True, linestyle--, alpha0.5) plt.tight_layout() # 建议将图片保存到特定目录而不是直接show便于报告使用 # plt.savefig(f./output/{model_name}_prediction.png, dpi150) plt.show() return { model: model, y_test: y_test, y_pred: y_pred, metrics: metrics }这个模板的价值在于无论你是用线性回归、随机森林还是XGBoost都可以用同一套流程快速跑通并得到格式一致的评估报告和图表极大提升了模型对比的效率。3.3 优化算法模块的实战心得数学建模中的优化问题如线性规划、整数规划、非线性规划是难点。对于常用库如PuLP for LP, SciPy for NLP记录的重点不应是API调用这些查文档即可而是如何将实际问题转化为标准模型以及调试技巧。以PuLP求解线性规划为例我会记录一个包含完整建模、求解和结果解析的范例并特别强调易错点from pulp import LpProblem, LpVariable, LpMaximize, LpStatus, value def production_planning_example(): 生产计划问题示例资源约束下的利润最大化。 问题生产产品A和B消耗资源R1和R2如何安排生产使利润最大 # 1. 初始化问题 prob LpProblem(Maximize_Profit, LpMaximize) # 2. 定义决策变量非负连续变量 x_A LpVariable(Product_A, lowBound0, catContinuous) # 产品A的产量 x_B LpVariable(Product_B, lowBound0, catContinuous) # 产品B的产量 # 3. 定义目标函数 prob 50 * x_A 60 * x_B, Total_Profit # 4. 添加约束条件 prob 2 * x_A 3 * x_B 100, Resource_R1_Limit # 资源R1约束 prob 4 * x_A 2 * x_B 120, Resource_R2_Limit # 资源R2约束 prob x_A 30, Market_Demand_A # 产品A的市场需求上限 # 5. 求解问题 prob.solve() # 6. 输出结果 print(f求解状态: {LpStatus[prob.status]}) print(f最优总利润: {value(prob.objective)}) print(f产品A最优产量: {value(x_A)}) print(f产品B最优产量: {value(x_B)}) # 7. 高级影子价格分析 - 这是建模报告中常需要的深度分析 print(\n--- 约束影子价格对偶价格分析 ---) for name, constraint in prob.constraints.items(): print(f约束 {name} 的影子价格: {constraint.pi}) # 调用示例 if __name__ __main__: production_planning_example()踩坑记录与心得变量类型务必明确catInteger还是catContinuous一字之差问题性质从线性规划变成整数规划求解难度和时间天差地别。定义变量时就要想清楚。约束条件的方向、还是必须根据实际问题含义仔细核对。经常有同学把资源上限误写成下限。结果解析prob.status可能返回Optimal、Infeasible无解或Unbounded无界。代码中必须包含状态判断否则当问题无解时直接调用value(prob.objective)会出错。影子价格constraint.pi可以获取约束的影子价格即该资源每增加一个单位所能带来的目标函数增量。这在分析资源瓶颈、撰写论文的灵敏度分析部分时极其有用但很多初学者会忽略。对于更复杂的启发式算法如遗传算法、模拟退火代码记录的重点则在于参数调优的经验。我会记录一个参数敏感度分析的简单框架用于快速寻找较优的参数组合。4. 评价方法模块的标准化与可扩展性评价与决策方法如AHP、TOPSIS、熵权法是数学建模尤其是社科类题目的常客。这些方法的代码实现往往不复杂但细节决定成败。以TOPSIS法为例一个健壮、清晰的实现需要处理好以下几点指标正向化统一将指标转化为极大型越大越好。矩阵归一化常用向量归一化或极差归一化。距离计算区分到正理想解和负理想解的欧氏距离。结果检验确保得分在[0,1]区间且排序合理。下面是我在多次使用后打磨出的一个版本它包含了清晰的步骤和必要的校验import numpy as np def topsis(data_matrix, weight_vector, positive_idealNone): TOPSIS综合评价方法。 Args: data_matrix: 决策矩阵m个评价对象*n个评价指标。np.ndarray类型 shape (m, n)。 weight_vector: 权重向量长度为n。列表或np.ndarray类型。函数内部会归一化。 positive_ideal: 布尔列表长度为n。True表示该指标为正向指标越大越好 False表示负向指标越小越好。默认为None即全为正向。 Returns: relative_closeness: 各评价对象与理想解的相对接近度得分值越大越优。 ranking: 按得分从高到低的排序索引从0开始。 # 输入校验 m, n data_matrix.shape if len(weight_vector) ! n: raise ValueError(f权重向量长度({len(weight_vector)})与指标数({n})不匹配) if positive_ideal is not None and len(positive_ideal) ! n: raise ValueError(fpositive_ideal长度({len(positive_ideal)})与指标数({n})不匹配) # 1. 指标正向化 matrix data_matrix.astype(float).copy() if positive_ideal is None: positive_ideal [True] * n # 默认全为正向指标 for j in range(n): if not positive_ideal[j]: # 如果是负向指标则取倒数或采用其他方法如 max - x # 这里采用 min-max 转换 x max(x) - x 将其转化为正向指标 col_max matrix[:, j].max() matrix[:, j] col_max - matrix[:, j] # 注意如果原列有0取倒数法会出错故推荐用减法或区间型转换。 # 2. 矩阵归一化向量归一化 norm_sqrt np.sqrt((matrix ** 2).sum(axis0)) norm_matrix matrix / norm_sqrt # 避免除零假设数据已预处理无全零列 # 3. 构造加权规范矩阵 weight_vector np.array(weight_vector) weight_vector weight_vector / weight_vector.sum() # 确保权重和为1 weighted_matrix norm_matrix * weight_vector # 4. 确定正、负理想解 Z_pos weighted_matrix.max(axis0) # 正理想解每列最大值 Z_neg weighted_matrix.min(axis0) # 负理想解每列最小值 # 5. 计算各对象到正/负理想解的距离 D_pos np.sqrt(((weighted_matrix - Z_pos) ** 2).sum(axis1)) D_neg np.sqrt(((weighted_matrix - Z_neg) ** 2).sum(axis1)) # 6. 计算相对接近度得分 C D_neg / (D_pos D_neg 1e-10) # 加一个极小值防止除零 # 7. 排序 ranking np.argsort(-C) # 按得分降序排列的索引 return C, ranking关键细节解析负向指标处理代码中采用了col_max - x的方法进行正向化。这是最安全的方法之一。网上有些教程用倒数1/x但如果原数据有0或负数就会出错。务必在注释中强调这一点。权重处理函数内部对权重进行了归一化weight_vector / weight_vector.sum()。这是一个很好的实践即使用户输入的权重之和不是1也能得到正确结果提高了代码的容错性。防止除零在计算相对接近度C时分母加了1e-10。这是因为在极端情况下D_pos和D_neg可能同时为0例如所有对象在所有指标上完全一致导致除零错误。这个小技巧保证了程序的稳定性。输入校验开头的长度检查非常必要。它能快速定位参数传递错误避免后续计算出现难以理解的维度错误。在代码记录中我还会附上一个简单的使用示例和验证案例确保复习时能立刻上手# 使用示例 if __name__ __main__: # 假设有4个对象3个评价指标 data np.array([ [100, 80, 7], # 对象1 [90, 85, 8], # 对象2 [95, 70, 9], # 对象3 [80, 90, 6] # 对象4 ]) # 假设指标1和2是正向越大越好指标3是负向越小越好如故障次数 positive_flags [True, True, False] weights [0.4, 0.3, 0.3] # 权重 scores, rank topsis(data, weights, positive_flags) print(综合得分:, scores) print(排序对象索引:, rank) print(排序得分从高到低:) for i, idx in enumerate(rank): print(f 第{i1}名: 对象{idx1}, 得分{scores[idx]:.4f})5. 工具函数与效率提升技巧除了核心算法一些能提升编码效率和代码质量的小工具也值得记录。它们就像螺丝刀和扳手平时不起眼但用对了地方能省下大量时间。5.1 计时与性能分析装饰器在优化算法或处理大数据时了解函数运行时间至关重要。一个简单的计时装饰器可以无缝集成到任何函数中。import time import functools def timer_decorator(func): 一个简单的函数运行计时装饰器。 functools.wraps(func) # 保留原函数的元信息 def wrapper_timer(*args, **kwargs): start_time time.perf_counter() # 使用高精度计时器 result func(*args, **kwargs) end_time time.perf_counter() run_time end_time - start_time print(f函数 {func.__name__!r} 运行耗时: {run_time:.4f} 秒) return result return wrapper_timer # 使用示例 timer_decorator def heavy_computation(n): s 0 for i in range(n): s i ** 2 return s # 调用 heavy_computation(1000000) 时会自动打印运行时间5.2 数据保存与加载的封装数学建模中经常需要在不同步骤间保存和加载中间数据如预处理后的数据、训练好的模型。统一的封装能避免路径混乱和格式错误。import pickle import json import pandas as pd import numpy as np import os def save_pickle(obj, filepath): 将Python对象保存为pickle文件。 os.makedirs(os.path.dirname(filepath), exist_okTrue) # 确保目录存在 with open(filepath, wb) as f: pickle.dump(obj, f) print(f对象已保存至: {filepath}) def load_pickle(filepath): 从pickle文件加载Python对象。 with open(filepath, rb) as f: obj pickle.load(f) print(f已从 {filepath} 加载对象) return obj def save_dataframe_csv(df, filepath, indexFalse): 保存DataFrame到CSV并自动创建目录。 os.makedirs(os.path.dirname(filepath), exist_okTrue) df.to_csv(filepath, indexindex, encodingutf-8-sig) # utf-8-sig避免中文乱码 print(fDataFrame已保存至: {filepath}) # 扩展一个简单的实验记录函数用于记录每次运行的参数和结果 def log_experiment(params, results, logfile./logs/experiment_log.json): 将实验参数和结果记录到JSON文件。 os.makedirs(os.path.dirname(logfile), exist_okTrue) entry { timestamp: time.strftime(%Y-%m-%d %H:%M:%S), params: params, results: results } # 如果文件存在则追加否则创建 if os.path.exists(logfile): with open(logfile, r, encodingutf-8) as f: data json.load(f) else: data [] data.append(entry) with open(logfile, w, encodingutf-8) as f: json.dump(data, f, indent2, ensure_asciiFalse) print(f实验记录已更新至: {logfile})实操心得养成使用os.makedirs(os.path.dirname(filepath), exist_okTrue)的习惯。这行代码会在保存文件前自动创建不存在的目录避免因“目录不存在”导致的FileNotFoundError。这是我从无数次报错中学到的宝贵经验。6. 代码记录的维护、更新与实战应用构建代码记录不是一劳永逸的事情它需要随着你的学习和实践不断迭代。一个动态成长的代码库才是最有价值的。6.1 版本管理与更新策略我强烈建议将你的math_modeling_codebook文件夹初始化为一个Git仓库使用GitHub Desktop或命令行均可。这带来了三大好处版本回溯当你修改了一个通用函数却引入了新bug时可以轻松回退到稳定版本。变更记录每次更新添加新算法、优化旧函数后写一条清晰的commit信息相当于为你的代码库写了成长日记。多设备同步通过GitHub或Gitee你可以在实验室电脑、个人笔记本间同步代码库随时随地访问。每次学习一个新模型或算法后不要只停留在理论或跑通示例。问自己三个问题并将答案融入代码记录这个算法的核心思想是什么用一两句话写在函数注释的开头它最适合解决哪类问题有什么前提假设写在“适用场景”或“注意事项”里它的关键参数有哪些调参经验是什么通过一个简单的参数网格搜索示例来记录6.2 在实战中快速调用建立个人“武器库”索引当比赛或作业来临时面对浩如烟海的代码文件如何快速找到所需我建议在项目根目录维护一个INDEX.md或CHEATSHEET.md文件。这不是详细的API文档而是一个“问题-解决方案”的速查表。例如# 数学建模代码速查表 ## 数据预处理 - **数据清洗**data_preprocessing/handle_missing_values.py - handle_missing_values(df, strategyauto) - **异常值检测单变量**data_preprocessing/outlier_detection.py - detect_outliers_iqr(), detect_outliers_zscore() - **异常值检测多变量/复杂**data_preprocessing/outlier_detection.py - detect_outliers_isolation_forest() - **数据标准化**data_preprocessing/normalization_scaling.py - minmax_scale(), standard_scale() ## 预测模型 - **快速训练评估模板**classical_models/train_evaluate_template.py - train_evaluate_model() - **时间序列预测ARIMA**classical_models/time_series/arima_forecast.py - **集成学习XGBoost/LightGBM**classical_models/ensemble/ 附有调参示例 ## 优化问题 - **线性/整数规划**optimization_algorithms/linear_programming.py 使用PuLP - **多目标优化NSGA-II示例**optimization_algorithms/multi_objective_optimization.py - **启发式算法遗传算法**optimization_algorithms/heuristic_algorithms/genetic_algorithm.py ## 评价与决策 - **客观赋权熵权法**evaluation_methods/entropy_weight.py - **主客观结合AHP熵权**evaluation_methods/ahp_entropy_weight.py - **TOPSIS法**evaluation_methods/topsis.py - **灰色关联分析**evaluation_methods/grey_relational_analysis.py这个索引文件应该保持简洁只包含最常用的函数和路径。它的存在让你在紧张的比赛环境中能像查字典一样在30秒内定位到需要的工具。6.3 从记录到创新迭代出属于自己的“高级货”代码记录的最终目的不是收藏而是内化和超越。当你对某个算法足够熟悉后可以尝试进行“魔改”或“组合创新”。例如经典的熵权法计算权重时有时会出现某个指标权重为0的情况信息熵为1。这在实际评价中可能不太合理。你可以在记录中新增一个改进版本加入一个平滑因子或改用另一种标准化方法并对比改进前后的结果差异。又比如你可以将TOPSIS与层次分析法AHP结合先用AHP确定主观权重再代入TOPSIS计算形成一个完整的“AHP-TOPSIS”综合评价模块。将这个组合过程封装成一个函数并记录下这种组合方法在什么类型的题目中如方案选优、供应商评估特别有效。这个过程就是将公共知识转化为个人智慧的过程。你的代码记录库也因此从一个“工具箱”升级为一个“经验知识库”成为你在数学建模道路上最独特的竞争优势。最后我想分享一点个人体会整理代码记录最大的收获其实不是比赛时节省的那几个小时而是在整理过程中被迫进行的“反刍”和“梳理”。为了把一段代码写清楚、注释明白你必须真正理解它背后的每一个细节和选择。这个过程本身就是最有效的复习和深度学习。当你看着自己日渐丰满、条理清晰的代码库时那种对知识的掌控感和应对挑战的底气是任何临时抱佛脚都无法替代的。