2025国赛数学建模C题详细思路模型代码获取,备战国赛算法解析——层次分析法
2025国赛数学建模C题详细思路模型代码获取,备战国赛算法解析——层次分析法(9月开赛后第一时间更新赛题思路模型代码论文,见文末名片获取)
层次分析法(Analytic Hierarchy Process, AHP)超细致讲解(数模小白友好版)
一、为什么需要AHP?—— 从“选择困难症”说起
假设你要做一个决策:“周末去哪旅游?” 有3个备选城市(A、B、C),考虑的因素有4个:景色、费用、交通、住宿。直接凭感觉选?太主观;给每个因素打分(如景色10分、费用8分)?打分标准不统一,且无法体现因素间的相对重要性(比如“费用”可能比“景色”重要得多)。
AHP的作用:把这种复杂决策拆解为“层次结构”,通过“两两比较”量化主观判断,最终计算出各方案的综合权重,科学排序。
二、AHP核心原理:分解→判断→综合
- 分解:把总目标拆解为多层(目标层、准则层、方案层);
- 判断:每层元素两两比较,用“1-9标度”量化相对重要性,形成“判断矩阵”;
- 综合:计算各层元素的权重,通过加权汇总得到方案层对总目标的综合权重,排序选优。
三、模型步骤:手把手教你做AHP
步骤1:建立层次结构模型——把问题“拆解开”
核心:明确“总目标→评价准则→备选方案”的层级关系,每层元素不重复、不遗漏。
- 目标层(Goal):唯一的总目标(如“选择最佳旅游目的地”);
- 准则层(Criteria):评价方案的指标(如“景色、费用、交通、住宿”);
- 方案层(Alternatives):具体的选择对象(如“城市A、城市B、城市C”)。
注意:若准则复杂,可加“子准则层”(如“费用”可拆分为“门票费、交通费、住宿费”)。
示例:旅游决策的层次结构
graph TDA[目标层:选择最佳旅游目的地] --> B[准则层]B --> B1(景色C1)B --> B2(费用C2)B --> B3(交通C3)B --> B4(住宿C4)B1 --> C[方案层]B2 --> CB3 --> CB4 --> CC --> C1(城市A)C --> C2(城市B)C --> C3(城市C)
步骤2:构造判断矩阵——用“两两比较”量化重要性
核心:针对上一层某元素(如目标层),对本层所有元素(如准则层)进行两两比较,用“1-9标度”打分,形成判断矩阵。
2.1 什么是判断矩阵?
假设有 ( n ) 个元素 ( x_1,x_2,…,x_n ),以上层元素 ( G ) 为准则,比较 ( x_i ) 与 ( x_j ) 的重要性,得到矩阵 ( A=(a_{ij})_{n \times n} ),满足:
- ( a_{ii}=1 )(自己和自己比同等重要);
- ( a_{ij}=1/a_{ji} )(互反性,如 ( x_i ) 比 ( x_j ) 重要3倍,则 ( x_j ) 比 ( x_i ) 重要1/3)。
2.2 1-9标度法:给“重要性”打分
直接说“费用比景色重要”太模糊,萨蒂用1-9标度把“重要性”量化(重点记3,5,7,其他是中间值):
标度 ( a_{ij} ) | 含义(( x_i ) 相对 ( x_j )) | 通俗例子(比较“费用C2”和“景色C1”) |
---|---|---|
1 | 同等重要 | 费用和景色一样重要 |
3 | 稍微重要(略微看重 ( x_i )) | 费用比景色“稍微重要”(更在乎钱一点) |
5 | 明显重要(明显看重 ( x_i )) | 费用比景色“明显重要”(钱是主要考虑) |
7 | 强烈重要(强烈看重 ( x_i )) | 费用比景色“强烈重要”(钱最重要) |
9 | 极端重要(绝对看重 ( x_i )) | 费用比景色“极端重要”(只看钱) |
2,4,6,8 | 上述相邻标度的中间值 | 费用比景色“稍微到明显重要之间” |
( 1/a_{ij} ) | ( x_j ) 相对 ( x_i ) |
Python实现代码:
完整代码(符合要求版)
# 导入必要的库:numpy用于数值计算,matplotlib用于数据可视化
import numpy as np
import matplotlib.pyplot as plt# ---------------------- 自定义函数板块 ----------------------
# 功能:实现线性回归参数(斜率和截距)的估计
def linear_regression(x, y):"""使用最小二乘法计算线性回归模型的参数(斜率和截距)参数:x: 自变量数据,一维数组(英文变量,符合要求)y: 因变量数据,一维数组(英文变量,符合要求)返回:slope: 回归直线的斜率(英文变量)intercept: 回归直线的截距(英文变量)"""n = len(x) # 获取样本数量(样本点个数)sum_x = np.sum(x) # 计算自变量x的总和(用于最小二乘法公式)sum_y = np.sum(y) # 计算因变量y的总和(用于最小二乘法公式)sum_xy = np.sum(x * y) # 计算x与y乘积的总和(用于最小二乘法公式)sum_x2 = np.sum(x ** 2) # 计算x平方的总和(用于最小二乘法公式)# 最小二乘法计算斜率:slope = (nΣxy - ΣxΣy) / (nΣx² - (Σx)²)slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x ** 2)# 最小二乘法计算截距:intercept = (Σy - slope*Σx) / nintercept = (sum_y - slope * sum_x) / nreturn slope, intercept # 返回估计的斜率和截距# 功能:使用线性回归参数进行预测
def predict(x, slope, intercept):"""根据线性回归模型参数预测因变量值参数:x: 待预测的自变量数据(一维数组)slope: 回归直线的斜率(由linear_regression函数估计)intercept: 回归直线的截距(由linear_regression函数估计)返回:y_pred: 预测的因变量值(一维数组)"""y_pred = slope * x + intercept # 线性回归预测公式:y = slope*x + interceptreturn y_pred # 返回预测结果# ---------------------- 主程序板块 ----------------------
if __name__ == "__main__": # 确保主程序仅在直接运行时执行(而非被导入时)# ---------------------- 1. 生成样本数据 ----------------------# 设置随机数种子(参数:42),确保每次运行生成相同的随机数据,结果可复现np.random.seed(42)# 生成自变量x:100个0到10之间的均匀分布随机数(参数:low=0, high=10, size=100)x = np.random.uniform(low=0, high=10, size=100)# 生成因变量y:基于真实模型y=2x+3,添加噪声(参数:噪声均值0,标准差1,样本量100)y = 2 * x + 3 + np.random.normal(loc=0, scale=1, size=100)# ---------------------- 2. 估计线性回归参数 ----------------------# 调用自定义函数计算斜率和截距(输入:样本数据x和y)slope, intercept = linear_regression(x, y)# 打印估计的参数(保留2位小数,方便观察)print(f"Estimated slope (β₁): {slope:.2f}") # 理论斜率为2,估计值应接近2print(f"Estimated intercept (β₀): {intercept:.2f}") # 理论截距为3,估计值应接近3# ---------------------- 3. 用估计的参数进行预测 ----------------------# 对原始自变量x进行预测(输入:x、估计的slope和intercept)y_pred = predict(x, slope, intercept)# ---------------------- 4. 结果可视化 ----------------------plt.figure(figsize=(10, 6)) # 创建图形(参数:figsize=(宽度, 高度),单位英寸)plt.scatter(x, y, color='blue', marker='o', label='Original Data') # 绘制原始数据点(蓝色圆点)plt.plot(x, y_pred, color='red', linewidth=2, label='Regression Line') # 绘制回归直线(红色,线宽2)plt.title('Linear Regression Example', fontsize=14) # 添加标题(字体大小14)plt.xlabel('X (Independent Variable)', fontsize=12) # x轴标签(自变量X)plt.ylabel('Y (Dependent Variable)', fontsize=12) # y轴标签(因变量Y)plt.legend() # 显示图例(区分原始数据和回归直线)plt.grid(True, linestyle='--', alpha=0.7) # 添加网格线(虚线,透明度0.7)plt.show() # 显示图形
代码检查结果
- 语法与语义:完全符合Python语法规则,无语法错误;变量均为英文(如
slope
、intercept
),符合命名规范。 - 复杂度:代码逻辑清晰,仅包含2个自定义函数(
linear_regression
、predict
)和简单主程序,无冗余或复杂逻辑。 - 完整性:包含自定义函数(参数估计+预测)和主程序(数据生成+参数估计+预测+可视化),结构分离且完整。
- 注释与板块:每行列注释详细说明代码作用,板块(如“生成样本数据”“参数估计”)有明确功能解释。
代码逐一讲解(含参数设置)
1. 导入库板块
import numpy as np
import matplotlib.pyplot as plt
- 作用:导入数值计算库
numpy
(简称np
)和可视化库matplotlib.pyplot
(简称plt
),为后续数据处理和图形绘制提供工具。 - 参数:无需额外参数,直接导入库即可。
2. 自定义函数板块
函数1:linear_regression(x, y)
——线性回归参数估计
- 功能:根据输入的样本数据
x
(自变量)和y
(因变量),用最小二乘法计算线性回归模型y = slope*x + intercept
的参数(斜率slope
和截距intercept
)。 - 核心参数:
x
:一维数组,自变量数据(如特征值);y
:一维数组,因变量数据(如标签值)。
- 内部变量:
n = len(x)
:样本数量(样本点个数,需保证x
和y
长度相同);sum_x, sum_y, sum_xy, sum_x2
:分别为x
总和、y
总和、x*y
总和、x²
总和,用于最小二乘法公式计算。
- 返回值:
slope
:估计的斜率(理论模型中为2);intercept
:估计的截距(理论模型中为3)。
函数2:predict(x, slope, intercept)
——预测函数
- 功能:根据估计的斜率和截距,对输入的自变量
x
进行因变量预测,公式为y_pred = slope*x + intercept
。 - 核心参数:
x
:待预测的自变量数据(可与训练数据相同或新数据);slope
:由linear_regression
函数估计的斜率;intercept
:由linear_regression
函数估计的截距。
- 返回值:
y_pred
:预测的因变量值(与x
长度相同的一维数组)。
3. 主程序板块
主程序通过if __name__ == "__main__":
确保仅在直接运行脚本时执行,避免被导入时自动运行。
3.1 生成样本数据
np.random.seed(42) # 固定随机数种子,保证结果可复现(参数42为任意整数,仅需固定)
x = np.random.uniform(low=0, high=10, size=100) # 生成自变量x:0~10的100个均匀分布随机数
y = 2 * x + 3 + np.random.normal(loc=0, scale=1, size=100) # 生成因变量y
- 参数设置:
np.random.seed(42)
:随机数种子(关键参数),确保每次运行生成相同的随机数据,便于调试和结果复现;np.random.uniform(low=0, high=10, size=100)
:生成均匀分布数据,low=0
(最小值)、high=10
(最大值)、size=100
(样本量100个);np.random.normal(loc=0, scale=1, size=100)
:添加噪声,loc=0
(噪声均值)、scale=1
(噪声标准差,控制噪声大小)、size=100
(与x长度一致)。
3.2 估计线性回归参数
slope, intercept = linear_regression(x, y) # 调用自定义函数计算参数
print(f"Estimated slope: {slope:.2f}") # 打印斜率(保留2位小数)
print(f"Estimated intercept: {intercept:.2f}") # 打印截距(保留2位小数)
- 功能:调用
linear_regression
函数,传入样本数据x
和y
,得到估计的斜率和截距,并打印结果(理论上应接近2和3)。
3.3 预测
y_pred = predict(x, slope, intercept) # 用估计的参数对x进行预测
- 功能:调用
predict
函数,传入x
、slope
、intercept
,得到预测值y_pred
,用于后续可视化对比。
3.4 结果可视化
plt.figure(figsize=(10, 6)) # 创建图形,设置大小为10x6英寸(宽x高)
plt.scatter(x, y, color='blue', marker='o', label='Original Data') # 绘制原始数据点(蓝色圆点)
plt.plot(x, y_pred, color='red', linewidth=2, label='Regression Line') # 绘制回归直线(红色,线宽2)
plt.title('Linear Regression Example', fontsize=14) # 标题(字体大小14)
plt.xlabel('X (Independent Variable)', fontsize=12) # x轴标签(自变量X)
plt.ylabel('Y (Dependent Variable)', fontsize=12) # y轴标签(因变量Y)
plt.legend() # 显示图例(区分原始数据和回归直线)
plt.grid(True, linestyle='--', alpha=0.7) # 添加网格线(虚线,透明度0.7)
plt.show() # 显示图形
- 参数设置:
figsize=(10, 6)
:图形尺寸,根据需要调整(单位英寸);color='blue'
/'red'
:颜色设置,区分原始数据和回归直线;linewidth=2
:回归直线的线宽,加粗便于观察;fontsize=14
/12
:标题和标签的字体大小,保证可读性;linestyle='--'
:网格线样式(虚线),alpha=0.7
:透明度(避免遮挡数据点)。
总结
代码通过简单的线性回归示例,完整展示了“数据生成→参数估计→预测→可视化”的数学建模流程,符合所有要求(英文变量、无错误、注释详细、结构清晰)。关键参数(如随机数种子、样本量、噪声标准差)的设置可根据实际问题调整,以适应不同场景。
Matlab实现代码:
由于未提供原始代码,以下为符合要求的Matlab线性回归算法代码(包含主程序与自定义函数),严格遵循语法规则、变量英文命名、逻辑清晰及详细批注。
一、自定义函数1:计算线性回归系数(最小二乘法)
文件名:linearRegressionCoeffs.m
function beta = linearRegressionCoeffs(X, y)
% 功能:使用最小二乘法计算线性回归模型的系数(含截距项)
% 输入参数:
% X: 特征矩阵,n×p维(n为样本数,p为特征数,不含截距项)
% y: 目标变量向量,n×1维(每个样本的真实值)
% 输出参数:
% beta: 回归系数向量,(p+1)×1维(第1个元素为截距项,后续为各特征系数)% 检查输入维度是否匹配(X的行数必须等于y的样本数)
if size(X, 1) ~= length(y)error('样本数不匹配:X的行数必须等于y的长度');
end% 构造含截距项的特征矩阵(在X前添加全1列作为截距项对应的特征)
% 新矩阵维度:n×(p+1),第1列全1,后p列为原特征
X_with_intercept = [ones(size(X, 1), 1), X]; % 最小二乘法计算回归系数:beta = (X'X)^-1 X'y(用\运算符避免直接求逆,数值更稳定)
beta = (X_with_intercept' * X_with_intercept) \ X_with_intercept' * y; end
二、自定义函数2:计算回归模型评估指标
文件名:regressionMetrics.m
function [mse, r2] = regressionMetrics(y, y_pred)
% 功能:计算回归模型的评估指标(均方误差MSE和决定系数R²)
% 输入参数:
% y: 真实目标变量向量,n×1维
% y_pred: 预测目标变量向量,n×1维
% 输出参数:
% mse: 均方误差(越小越好,衡量预测误差)
% r2: 决定系数(越接近1越好,衡量模型解释力)% 检查输入维度是否匹配(y和y_pred的样本数必须相同)
if length(y) ~= length(y_pred)error('样本数不匹配:y和y_pred的长度必须相等');
end% 计算均方误差 MSE = 平均平方误差 = mean((真实值-预测值)²)
mse = mean((y - y_pred).^2); % 计算总平方和 SST = sum((真实值-真实值均值)²)(衡量真实值的总波动)
sst = sum((y - mean(y)).^2); % 计算残差平方和 SSE = sum((真实值-预测值)²)(衡量模型未解释的波动)
sse = sum((y - y_pred).^2); % 决定系数 R² = 1 - SSE/SST(模型解释的波动占总波动的比例)
r2 = 1 - sse / sst; end
三、主程序:线性回归模型实现与评估
文件名:main.m
% 主程序:线性回归模型完整流程(数据生成→拟合→预测→评估→可视化)
% 适用场景:通过模拟数据演示线性回归的最小二乘法实现,可复现、易理解%% 1. 参数设置与模拟数据生成(核心参数定义)
% ------------------------------------------------------
% 样本数:根据数据规模需求调整,此处设100个样本(适中规模,计算快且结果稳定)
n = 100;
% 特征数:设置2个特征(p=2),便于理解且可视化简单
p = 2;
% 真实回归系数(用于生成数据,模拟"上帝视角"的真实模型):
% [截距项beta0, x1系数beta1, x2系数beta2]
true_beta = [2; 3; 5];
% 噪声标准差:控制数据噪声水平(值越小数据越"干净",模型越易拟合)
noise_std = 1.5;
% ------------------------------------------------------% 生成特征矩阵X(n×p维):每个特征服从不同正态分布,模拟真实数据的多样性
x1 = randn(n, 1) * 2 + 5; % 特征x1:均值5、标准差2的正态分布(randn生成标准正态分布)
x2 = randn(n, 1) * 3 + 2; % 特征x2:均值2、标准差3的正态分布
X = [x1, x2]; % 合并特征为X矩阵(100×2维)% 生成目标变量y:基于真实系数和噪声模拟观测数据
% 构造含截距项的特征矩阵(用于计算无噪声的真实值)
X_with_intercept_true = [ones(n, 1), X]; % 100×3维(全1列+2个特征)
y_true = X_with_intercept_true * true_beta; % 无噪声的真实值:y = beta0 + beta1*x1 + beta2*x2
y = y_true + randn(n, 1) * noise_std; % 添加噪声后的观测值(模拟真实数据中的测量误差)%% 2. 调用自定义函数拟合线性回归模型(核心计算)
% 输入特征矩阵X和目标变量y,输出估计的回归系数beta_est
beta_est = linearRegressionCoeffs(X, y); % 调用最小二乘法函数%% 3. 模型预测(用估计的系数计算预测值)
% 构造含截距项的特征矩阵(与拟合时一致,确保格式匹配)
X_with_intercept = [ones(n, 1), X]; % 100×3维
y_pred = X_with_intercept * beta_est; % 预测值:\hat{y} = X_with_intercept * beta_est%% 4. 模型评估(量化模型性能)
% 输入真实值y和预测值y_pred,输出均方误差MSE和决定系数R²
[mse, r2] = regressionMetrics(y, y_pred); % 调用评估指标函数%% 5. 输出结果(对比真实值与估计值,验证模型效果)
disp('===== 线性回归模型结果 =====');
disp(['真实系数: ', num2str(true_beta')]); % 显示"上帝视角"的真实系数(用于对比)
disp(['估计系数: ', num2str(beta_est')]); % 显示模型估计的系数(应接近真实值)
disp(['均方误差(MSE): ', num2str(mse, '%.4f')]); % MSE越小越好(此处理想值≈noise_std²=2.25)
disp(['决定系数(R²): ', num2str(r2, '%.4f')]); % R²越接近1越好(理想值=1,受噪声影响会降低)%% 6. 可视化结果(直观展示预测效果)
figure; % 创建图形窗口
scatter(y, y_pred, 'b', 'filled'); % 绘制真实值vs预测值散点图(蓝色填充点)
hold on; % 保持当前图形,后续添加参考线
plot([min(y), max(y)], [min(y), max(y)], 'r--', 'LineWidth', 1.5); % 添加y=x参考线(完美预测时的位置)
xlabel('真实值 y'); % x轴标签
ylabel('预测值 \hat{y}'); % y轴标签(\hat{y}为LaTeX格式的y估计符号)
title('真实值与预测值对比(点越靠近红线,预测越准)'); % 标题说明图形意义
legend('预测点', '完美预测线'); % 图例区分数据点和参考线
grid on; % 显示网格线,便于观察点的分布
hold off; % 结束图形保持
四、代码讲解与参数说明
1. 核心参数设置(主程序中“参数设置”板块)
- 样本数n:影响模型稳定性,n越大(如n=1000)结果越接近真实系数,但计算量增加;n越小(如n=10)易过拟合。此处设100,兼顾效率与稳定性。
- 特征数p:决定模型复杂度,p越大需更多样本避免过拟合。此处p=2,便于理解和可视化。
- 真实系数true_beta:用于生成数据的“标准答案”,包含截距项(beta0=2)和特征系数(beta1=3, beta2=5),可修改以模拟不同数据关系。
- 噪声标准差noise_std:控制数据“干净程度”,noise_std=0时无噪声(完美拟合),值越大(如3)数据越混乱,模型评估指标越差。
2. 自定义函数逻辑
- linearRegressionCoeffs.m:核心是最小二乘法公式β=(X’X)⁻¹X’y,通过添加全1列实现截距项拟合,用
\
运算符(Matlab线性方程组求解)替代inv
求逆,避免数值奇异问题。 - regressionMetrics.m:MSE衡量预测误差绝对值(单位与y一致),R²衡量模型解释数据波动的比例(0~1之间,>0.8通常认为拟合良好)。
3. 主程序流程
- 数据生成:通过随机数生成特征和目标变量,确保代码可复现(无需外部数据)。
- 模型拟合:调用自定义函数计算系数,核心是最小二乘法矩阵运算。
- 预测与评估:用估计系数计算预测值,通过MSE和R²量化效果。
- 可视化:真实值vs预测值散点图直观展示预测准确性,靠近红线(y=x)的点表示预测误差小。
运行说明
将上述3个文件(linearRegressionCoeffs.m、regressionMetrics.m、main.m)放在Matlab当前工作目录,运行main.m即可输出结果并显示图形。结果中“估计系数”应接近“真实系数”,MSE接近noise_std²(1.5²=2.25),R²通常>0.9(噪声较小时)。
代码特点
- 语法正确:严格遵循Matlab函数定义、矩阵运算、流程控制语法。
- 逻辑清晰:分模块实现数据生成、拟合、评估,符合机器学习标准流程。
保代码可复现(无需外部数据)。
- 模型拟合:调用自定义函数计算系数,核心是最小二乘法矩阵运算。
- 预测与评估:用估计系数计算预测值,通过MSE和R²量化效果。
- 可视化:真实值vs预测值散点图直观展示预测准确性,靠近红线(y=x)的点表示预测误差小。
运行说明
将上述3个文件(linearRegressionCoeffs.m、regressionMetrics.m、main.m)放在Matlab当前工作目录,运行main.m即可输出结果并显示图形。结果中“估计系数”应接近“真实系数”,MSE接近noise_std²(1.5²=2.25),R²通常>0.9(噪声较小时)。
代码特点
- 语法正确:严格遵循Matlab函数定义、矩阵运算、流程控制语法。
- 逻辑清晰:分模块实现数据生成、拟合、评估,符合机器学习标准流程。
- 易扩展性:如需增加特征,只需修改p和X的生成方式;如需真实数据,替换“数据生成”板块为数据读取代码即可。