
简介面向数学建模竞赛参赛者、数据分析初学者与算法爱好者的一份实用算法代码合集围绕30个数学建模高频模型提供Python实现覆盖ARIMA时间序列预测、逻辑回归、二次规划、神经网络分类、线性规划、模拟退火、K-means聚类、随机森林、马尔科夫预测、动态规划、BP神经网络、整数规划、模糊综合评价、卷积神经网络、层次分析法、决策树、0-1背包、最短路径、插值拟合、TOPSIS评价、支持向量机、粒子群、多目标模糊评价、灰色预测、遗传算法、主成分分析、蒙特卡洛、非线性规划、判别分析等方向每个模型均附有可直接参考或改写的Python代码及配套说明文档。压缩包共39个文件以txt算法代码/说明、docx详细笔记、py脚本为主体辅以dat数据文件、rar子压缩包、spec配置与exe可执行程序整体大小约129.22MB目录按算法分类清晰便于按需检索。该资源已有1653人浏览学习适合赛前集中刷模型、对照代码理解原理也可作为课程设计与论文实验的参考工具。1. 数学建模30个常用算法Python代码一份能把备赛周期压缩一半的算法库参加过全国大学生数学建模竞赛或者华为杯研究生数学建模的同学应该都有同感拿到赛题后最耗时间的不是建模思路而是算法代码的调试。想用ARIMA做时间序列预测光差分阶数就能调一晚上想用粒子群解优化问题初始温度和迭代次数设不对结果就跑飞。这套「数学建模30个常用算法Python代码」把预测、分类、优化、评价四大类模型里最高频的30种算法一次性收齐每种都给了可直接运行的Python实现从ARIMA、灰色预测到遗传算法、TOPSIS评价全覆盖。适合正在备战国赛、华为杯或者毕业论文里需要快速验证算法效果的读者拿到手后替换成自己的数据、按下面说的调参思路改几个参数就能跑出结果。2. 预测类算法先选型ARIMA、灰色预测、马尔科夫的适用边界与代码骨架2.1 预测类模型的选型逻辑先看数据形态再挑算法建模比赛里的预测题几乎年年都有但很多人上来就套ARIMA这是最常见的翻车起点。预测类算法不是越复杂越好而是越匹配数据形态越好。拿到一份数据我一般会先回答三个问题数据是不是时间序列样本量有多少数据本身有没有明显的状态转移特征。时间序列连续数值、样本量在30以上优先考虑ARIMA它把自回归和滑动平均组合在一起对平稳序列的拟合能力很强。样本量小到只有几个到十几个点而且序列呈近似指数增长或衰减灰色预测GM(1,1)是更稳妥的选择它不需要大量历史数据用累加生成把随机性抹平再建模。数据是离散状态之间的转移比如天气晴雨、用户购买行为、设备运行状态马尔科夫模型更合适它关注的是状态之间的转移概率而不是数值本身。算法适用数据形态前提条件输出形态ARIMA连续时间序列样本量≥30差分后平稳连续数值预测灰色预测GM(1,1)小样本指数趋势序列级比检验通过连续数值预测马尔科夫/HMM离散状态序列或观测序列状态转移平稳状态概率分布2.2 ARIMA参数d、p、q的确定差分检验与ACF/PACF判读ARIMA三个参数里面d是最容易定的做一阶或二阶差分直到序列通过ADF检验就行。麻烦的是p和q很多人直接靠猜其实标准做法是先画ACF和PACF图看它们的截尾和拖尾特征。ACF在q阶后截尾PACF拖尾判定为MA(q)PACF在p阶后截尾ACF拖尾判定为AR(p)两者都拖尾就考虑ARMA。import pandas as pd from statsmodels.tsa.stattools import adfuller from statsmodels.graphics.tsaplots import plot_acf, plot_pacf from statsmodels.tsa.arima.model import ARIMA # 读取时间序列date列解析成索引 series pd.read_csv(sales.csv, parse_dates[date], index_coldate) # 先做ADF平稳性检验p值0.05说明不平稳需要差分 result adfuller(series[value]) print(ADF p值:, result[1]) # 一阶差分后再做一次检验 diff1 series[value].diff().dropna() print(一阶差分后ADF p值:, adfuller(diff1)[1]) # 看差分后序列的ACF和PACF图确定p和q plot_acf(diff1) plot_pacf(diff1) # 拟合ARIMA(1,1,1)p、q取图上判读的值 model ARIMA(series[value], order(1, 1, 1)) result model.fit() print(result.summary()) # 预测未来7期 forecast result.forecast(steps7) print(forecast)order里的三个数字对应p、d、qp是自回归阶数d是差分阶数q是滑动平均阶数。p、q的取值不需要精确到极致比赛里更看重模型能不能解释数据、预测方向对不对追求过高的拟合精度反而会过拟合历史噪声。statsmodels拟合后记得把summary打出来看重点关注AIC和BIC它们越小说明模型在拟合度和复杂度之间平衡得越好。2.3 灰色预测与马尔科夫的代码骨架小样本和状态转移的兜底方案灰色预测GM(1,1)是建模比赛里的小样本神器核心思想是把原始数据做一次累加生成让随机波动被弱化再用一阶微分方程去拟合这条生成序列。代码实现不复杂但级比检验这一步不能省否则预测结果可能完全不能用。import numpy as np def gm11(data, predict_len5): n len(data) # 级比检验lambda落在可容覆盖区间才算通过 lambda_k data[:-1] / data[1:] valid_range (np.exp(-2 / (n 1)), np.exp(2 / (n 1))) if not (valid_range[0] np.min(lambda_k) and np.max(lambda_k) valid_range[1]): print(级比检验未通过需对序列做平移或开方变换) # 累加生成序列 x1 np.cumsum(data) # 紧邻均值生成序列 z1 z1 (x1[:-1] x1[1:]) / 2 # 构造数据矩阵 B 和观测向量 Y B np.vstack([-z1, np.ones(n - 1)]).T Y data[1:] # 最小二乘估计参数a为发展系数b为灰作用量 a, b np.linalg.inv(B.T B) B.T Y # 时间响应函数还原预测值 x1_hat (data[0] - b / a) * np.exp(-a * np.arange(1, n predict_len)) b / a # 累减还原成原始量纲的预测值 x0_hat np.diff(x1_hat, prependdata[0]) return x0_hat data np.array([15.3, 16.8, 18.2, 19.9, 22.1]) forecast gm11(data, predict_len3) print(原始数据后3期预测:, forecast)B矩阵第一列是紧邻均值序列的负值第二列是全1这是GM(1,1)的标准构造方式。a的绝对值越大序列的增长或衰减趋势越陡b的符号决定预测方向。代码里用prepend参数保证累减还原后第一个值和原始数据对齐很多人自己手写累减时容易在这个位置多算或少算一个点。马尔科夫模型在资源包里给到的是HMM的Python实现适合做隐状态的序列标注比如根据观测到的用户行为推断后续状态它的核心是前向算法和后向算法观测序列的长度直接影响转移概率矩阵的估计精度样本太少时转移概率会失真。3. 分类与聚类模型实战逻辑回归、SVM、K-means的参数取舍3.1 分类模型怎么选逻辑回归、SVM、随机森林的边界划分分类问题是建模比赛里的另一大类但很多人一上来就上神经网络这其实是把简单问题复杂化。逻辑回归适合二分类任务输出的是概率而不是硬标签而且系数可以解释成特征对结果的贡献方向答辩时特别好讲。SVM适合样本量中等、特征维度较高的分类任务通过核函数把低维不可分的数据映射到高维空间但核函数选错了效果还不如逻辑回归。随机森林对特征多、有缺失值、非线性关系明显的数据更稳它天生能处理混合类型特征不容易过拟合。需要说明的是sklearn里的MLPClassifier和资源包里的神经网络分类代码都属于浅层神经网络做数字识别这类图像任务时可以跑通但遇到复杂图片分类还是得用卷积神经网络。比赛里如果数据是表格型的优先试逻辑回归和随机森林最后再用神经网络做对比而不是反过来一上来就把模型复杂度拉满。模型适用场景主要局限关键参数逻辑回归二分类、需要概率解释线性边界C、solverSVM中小样本高维特征核函数敏感C、kernel随机森林特征多、非线性明显预测慢n_estimators、max_depthMLP中等复杂度模式识别需要特征缩放hidden_layer_sizes3.2 逻辑回归与SVM代码落地标准化这一步千万别省逻辑回归和SVM在sklearn里都是几行代码的事但有一个隐藏前置步骤就是特征标准化。逻辑回归的损失函数里包含了惩罚项SVM依赖距离度量如果特征量纲差异大量纲大的特征会主导模型训练系数解释性也全乱了。我自己的习惯是无论用什么分类器先StandardScaler一遍再进模型。from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.metrics import classification_report # X是特征矩阵y是标签先划分训练集和测试集 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) # 标准化fit在训练集上做transform在测试集上做 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) # 逻辑回归C越小正则越强lbfgs适合中小数据集 clf_lr LogisticRegression(C1.0, solverlbfgs, max_iter1000) clf_lr.fit(X_train_scaled, y_train) print(逻辑回归结果:) print(classification_report(y_test, clf_lr.predict(X_test_scaled))) # SVMrbf核适合非线性边界C控制误分类惩罚 clf_svm SVC(C1.0, kernelrbf, gammascale) clf_svm.fit(X_train_scaled, y_train) print(SVM结果:) print(classification_report(y_test, clf_svm.predict(X_test_scaled)))C是正则化强度的倒数C越小对误分类的惩罚越轻模型越简单C越大模型越倾向于拟合每一个训练样本容易过拟合。gamma在SVM里控制的是径向基核的作用半径默认用scale会自动根据特征数量调整一般不用手动改。测试集上如果逻辑回归和SVM的F1分数差不多比赛里优先选逻辑回归因为解释性更强写论文时能给出每个特征的系数和方向。3.3 K-means聚类与神经网络K值确定和特征缩放K-means聚类看起来简单实际用起来最容易出问题的是K值怎么定。不要凭感觉拍脑袋先跑肘部法则画出不同K值下SSE簇内误差平方和的变化曲线找到拐点位置。另外聚类前不做StandardScaler的话距离计算会被数值范围大的特征完全绑架聚类结果几乎没有意义。import numpy as np from sklearn.cluster import KMeans from sklearn.preprocessing import StandardScaler import matplotlib.pyplot as plt # 假设features是已经读取的数值型特征矩阵 scaler StandardScaler() features_scaled scaler.fit_transform(features) # 肘部法则计算K从1到10的SSE sse [] k_range range(1, 11) for k in k_range: kmeans KMeans(n_clustersk, random_state42, n_init10) kmeans.fit(features_scaled) sse.append(kmeans.inertia_) # 画出SSE曲线观察拐点 plt.plot(k_range, sse, markero) plt.xlabel(K) plt.ylabel(SSE) plt.show()n_init表示k-means用不同初始质心跑的次数默认10次取最优random_state固定后才能复现结果。inertia就是SSEK增大时SSE会持续下降真正的拐点在哪图上肉眼判断即可。这个资源包里还包含了CNN的Python代码处理图像分类时用但CNN前必须把图像像素值归一化到0到1区间并且需要足够的样本量否则很容易在训练集上表现好、测试集上一塌糊涂。4. 规划与智能优化算法线性规划到遗传算法的框架与调参4.1 规划模型三分支线性、整数、非线性的场景划分优化类问题在建模比赛里占的比重很大资源包里的线性规划、整数规划、非线性规划、二次规划、动态规划、0-1背包、最短路径、模拟退火、粒子群、遗传算法这些都是优化问题的不同解法。选算法之前先搞清楚目标函数和约束条件的性质目标函数和约束都是线性的用线性规划要求决策变量是整数用整数规划目标函数或约束里带非线性项用非线性规划。scipy的linprog只处理最小化问题求最大值要把目标函数系数取负这是新手最容易踩的地方。整数规划推荐用scipy的milp或者pulp库。非线性规划用minimize加methodSLSQP它支持等式和不等式约束。from scipy.optimize import linprog # 目标max 3x 2y转换为min -3x - 2y c [-3, -2] # 约束2x y 10, x y 8x 0, y 0 A_ub [[2, 1], [1, 1]] b_ub [10, 8] bounds [(0, None), (0, None)] res linprog(c, A_ubA_ub, b_ubb_ub, boundsbounds, methodhighs) print(最优解:, res.x) print(最优值:, -res.fun)linprog里的A_ub是小于等于约束的系数矩阵b_ub是对应的右侧常数。bounds里None表示该变量没有上界或下界。method参数建议用highs它是高精度内点法实现比默认方法更快更稳。注意linprog的res.fun返回的是取负后的目标值所以最大值要用负号还原这一步做错的话整个优化结果都会对不上论文里写的目标函数。4.2 智能优化算法的共性框架模拟退火、粒子群、遗传的调参逻辑智能优化算法都属于元启发式方法核心思想是在解空间里做启发式搜索不保证全局最优但能在可接受时间内给出一个工程可用的解。模拟退火从高温开始允许以一定概率接受更差解来跳出局部最优温度逐渐降低接受差解的概率越来越小。粒子群通过个体最优和群体最优来引导粒子飞行遗传算法则靠选择、交叉、变异三个算子迭代进化。import numpy as np def objective(x): # 多峰测试函数求最小值 return x[0]**2 x[1]**2 - np.cos(12 * x[0]) - np.cos(12 * x[1]) def simulated_annealing(func, bounds, T01000, alpha0.95, iter_max1000): # 随机生成初始解 x_cur np.array([np.random.uniform(b[0], b[1]) for b in bounds]) f_cur func(x_cur) best_x, best_f x_cur.copy(), f_cur T T0 while T 1e-3: for _ in range(iter_max): # 邻域扰动生成新解 x_new x_cur np.random.uniform(-0.1, 0.1, sizelen(bounds)) f_new func(x_new) # Metropolis准则更优则接受更差则按概率接受 if f_new f_cur or np.random.random() np.exp(-(f_new - f_cur) / T): x_cur, f_cur x_new, f_new if f_cur best_f: best_x, best_f x_cur.copy(), f_cur T * alpha return best_x, best_f best_x, best_f simulated_annealing(objective, [(-5, 5), (-5, 5)]) print(最优解:, best_x, 目标值:, best_f)初始温度T0决定算法前期接受差解的概率设太低算法一开始就陷入局部最优降温系数alpha控制降温速度alpha越接近1搜索越充分但耗时越长迭代次数iter_max是每个温度下的搜索步数。这些参数在比赛里属于玄学不同问题的最优参数差异很大。我从实践里总结的调参套路是先固定alpha0.95T0从大到小试几组记录目标值的变化找到拐点后再小幅调iter_max不要同时动三个参数否则出了问题根本定位不了是哪个参数导致的。算法核心参数参数敏感度常见误区模拟退火T0、alpha、iter_max高初温设太低接受差解概率趋近于0粒子群惯性权重、c1、c2中惯性权重固定不衰减后期收敛差遗传算法交叉概率、变异概率中变异率过低种群早熟收敛4.3 动态规划与0-1背包递推式和状态转移的写码套路动态规划解决的是多阶段决策问题核心是写出状态转移方程。0-1背包问题里状态是前i个物品在容量c下能装的最大价值转移方程就是放或不放当前物品两种选择的较大值。资源包里单独给了基础0-1背包的动态规划代码这类代码写熟之后排队调度、资源分配问题都能转换成类似框架。def knapsack(weights, values, capacity): n len(weights) # dp[i][c]表示前i个物品在容量c下的最大价值 dp [[0] * (capacity 1) for _ in range(n 1)] for i in range(1, n 1): w, v weights[i - 1], values[i - 1] for c in range(1, capacity 1): if w c: # 放得下就取max(不放, 放) dp[i][c] max(dp[i - 1][c], dp[i - 1][c - w] v) else: # 放不下只能继承上一行的结果 dp[i][c] dp[i - 1][c] return dp[n][capacity] weights [2, 3, 4, 5] values [3, 4, 5, 6] print(最大价值:, knapsack(weights, values, 8))dp数组的行索引是物品编号列索引是背包容量dp[i-1][c-w]v表示把当前物品放进去腾出w的容量后装前i-1个物品的最大价值加上当前物品价值。这里有个容易绕晕的点dp下标从1开始而weights和values从0开始所以循环里访问weights[i-1]才能对齐。资源包里的动态规划模型代码用的是同样套路换成最短路径问题时把容量换成节点编号转移方程换成距离更新即可。5. 数学建模算法实战避坑指南从数据预处理到结果复现的五个教训5.1 一致性检验没做就出权重层次分析法最大的隐性坑现象判断矩阵算出来的权重看起来有模有样但代入评价模型后排名结果和直觉完全相反复盘时发现一致性比率CR高达0.25远超0.1的合格线。原因构造判断矩阵时凭感觉填比例值忽略了判断的传递性。比如A比B重要3倍B比C重要3倍按理A比C应该接近9倍但手填的时候只填了2倍矩阵的一致性就被破坏了。解决权重计算前必须先求最大特征值λmax按CRCI/RI做一致性检验其中CI(λmax-n)/(n-1)RI查表获取。CR大于0.1时不能直接使用该矩阵的权重要回头调整判断矩阵里偏差最大的元素或者改用熵权法这种完全客观的赋权方式。5.2 指标正向化方向搞反TOPSIS排名错乱的头号原因现象TOPSIS算出来的贴近度排名波动剧烈而且最优方案明显不符合业务直觉检查数据时发现成本型指标的处理方式根本不对。原因TOPSIS要求所有指标先统一成正向指标即数值越大越好。成本型指标比如费用、耗时直接用原始值参与距离计算的话数值越大反而离理想解越近排名逻辑整个颠倒。解决极小型指标做正向化常见做法是取倒数或取负。取倒数会让距离拉大对后续距离计算的影响更平滑。做完正向化后要再扫一遍数据确认所有指标的方向一致再进TOPSIS流程。5.3 GM(1,1)跳过级比检验小样本预测翻车的前兆现象用灰色预测模型跑出来的预测值整体偏离历史趋势有的点甚至出现负值后验差比值C完全不达标。原因原始序列没通过级比检验就直接建模。GM(1,1)要求原始序列的级比落在可容覆盖区间内区间宽度由样本量n决定n越小区间越窄越容易不满足条件。解决建模前先算级比λ(k)x(k-1)/x(k)确认每个级比值都落在(exp(-2/(n1)), exp(2/(n1)))区间内。通不过就做平移变换给序列整体加一个常数C再做预测预测结果出来后减回C即可。这一步是灰色预测的黑匣子资源包里的灰色预测代码注释里标了检验逻辑跑之前一定留意。5.4 智能优化算法不固定随机种子复现直接崩现象同一个脚本同一个数据集上午跑和下午跑结果不一样粒子群的最优解截然不同论文里根本没法写「实验参数固定」。原因智能优化算法用随机数初始化种群和做扰动不设置随机种子的话每次运行的搜索路径完全不同。解决在调用算法前强制加上np.random.seed(42)sklearn里训练模型时设置random_state参数。比赛论文里写明随机种子和运行环境这是评委最容易质疑的点。从那以后我每次跑智能优化算法都会在文件头部固定种子免得答辩时说不清结果怎么来的。5.5 K-means不归一化距离全被量大特征主导现象聚类结果里某个特征几乎完全决定了簇的划分其他特征对结果毫无贡献聚出来的簇连业务上都能一眼看出不合理。原因K-means用欧氏距离衡量样本相似度量纲大的特征在距离计算里占据绝对主导地位。比如一个特征取值范围是0到10000另一个是0到1后者在距离公式里几乎可以忽略。解决聚类前对连续型特征做StandardScaler标准化让每个特征都落在相近的数值范围。对有序分类特征可以用LabelEncoder编码后再标准化但对无序分类特征直接编码会引入伪距离这种情况下需要改用One-Hot编码或者换用支持混合类型距离的聚类算法。6. 把30个算法串成一条流水线数据体检、参数存档与结果验证的完整套路前面把预测、分类、优化、评价四类算法的选型和代码都拆了一遍最后说一个我自己的实操习惯拿到一份新赛题数据不急着选算法先跑一遍数据体检。看缺失值比例、异常值分布、特征量级差异、时间序列的平稳性这些决定了后面所有算法的可用性。体检完再按问题类型进分支预测题先做平稳性检验再决定ARIMA还是灰色预测分类题先跑逻辑回归做基线再对比随机森林和SVM优化题先判断线性还是非线性线性用scipy规划族非线性上智能优化算法评价题先做一致性检验再上TOPSIS或模糊综合评价。一个很实用的技巧是把30个算法脚本的入口统一封装成train(X, y, params)格式让不同模型可以无缝切换对比。def run_model(model_name, X_train, y_train, X_test, params): if model_name logistic: model LogisticRegression(**params) elif model_name svm: model SVC(**params) elif model_name rf: model RandomForestClassifier(**params) model.fit(X_train, y_train) return model.predict(X_test), model每个模型跑完记录三个东西参数配置、随机种子、测试集上的核心指标。备赛期间我建了一个参数记录表每换一组参数就记一行回头写论文时直接抄表上的内容不用翻代码回忆。最终结果用交叉验证而不是单次划分来确认避免随机划分带来的偶然误差。从那以后我每次建模都强制走一遍「数据体检—选型—参数存档—交叉验证」这四步流程比赛里省下的时间都花在结果分析上不在调参和返工里消耗。希望帮到你。本文还有配套的精品资源点击获取