ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

内配型钢钢管混凝土柱承载力预测:机器学习模型与特征工程实践

内配型钢钢管混凝土柱承载力预测:机器学习模型与特征工程实践 简介基于机器学习的内配型钢钢管混凝土柱承载力预测项目覆盖随机森林、线性回归、XGBoost、CNN四种主流模型面向土木工程结构智能设计方向的学生、研究者和工程师可用于柱承载力快速预估、算法对比及模型选型。压缩包共包含5个文件其中4个Python脚本对应不同模型的完整训练与预测流程另有1个Markdown说明文档辅助解读代码结构与运行参数整体体积仅6KB轻量且易于二次开发。目前已有251人学习浏览适合作为课程设计、毕业设计或科研前期探索的参考代码。资源可直接运行涵盖数据读取、特征处理、模型构建、训练评估与结果输出等完整环节通过统一数据集上四种模型的精度对比能直观反映各算法的适用性差异同时代码结构清晰、注释到位便于读者调整特征参数或迁移至其他结构构件的承载力预测中是快速上手机器学习工程应用的实用样例。1. 内配型钢钢管混凝土柱承载力预测为什么该改用机器学习又要防着它内配型钢的钢管混凝土柱说白了就是在钢管混凝土里再埋一道型钢骨承载力、延性都往上走但计算公式也跟着变复杂。近三年结构工程论文里冒出一大批“承载力预测 机器学习”的题目随机森林、线性回归、XGBoost、CNN 是被点名的常客。这个标题的本质是用试验或有限元生成的表格数据训练一个回归模型把截面尺寸、材料强度、长细比这些输入变成轴压承载力 Nu 的预测值。适合谁看土木方向的研究生做组合结构试验但被数据拟合折磨过的人想给设计院做快速评估工具、又不想背一厚本规范公式的工程师。先给一个反直觉的结论这种几百条样本的表格回归任务里CNN 经常打不过 XGBoost线性回归也没你想的那么不堪——关键在数据和特征怎么喂而不是模型的“高级程度”。2. 训练数据与特征工程预测模型的上限在数据侧2.1 承载力预测的数据从哪来试验库整理与有限元补样本这种题目最缺的从来不是模型代码而是干净、带物理意义的训练数据。常见做法是两条路并行先整理已发表试验数据再拿 ABAQUS 这类通用有限元软件做参数化补充。整理试验库时一条记录就是一个试件的实测结果字段通常包括钢管外径 D、壁厚 t、柱高 L、核心混凝土强度 fc、钢管屈服强度 fy、内配型钢的屈服强度与截面积以及最终的轴压承载力 Nu。试验数据的问题在于样本量太少能干到一两百条已经是很大的工作量。想喂饱随机森林和 XGBoost 还凑合想训 CNN 就远远不够。所以我会用有限元做参数扫描补样本对柱顶施加单调位移加载提取峰值荷载作为标签。补样本的时候要控制变量几何、材料、含钢率、长细比各取几档别只在一个参数附近反复扫否则模型学到的只是插值而不是规律。提示如果你没有试验数据也不要伪造。最低成本的可复现方案是用公开文献中的试验数据表手工整理再标注数据来源。做学术用途时务必在论文里写明数据出处与有限元模型验证过程。2.2 一张表定义输入特征几何、材料、荷载三类 14 个字段我一般把输入特征分成三组。几何组钢管外径 D、壁厚 t、柱高 L、核心混凝土面积 Ac、钢管面积 As、内配型钢面积 Ass、截面回转半径 i。材料组混凝土抗压强度 fc、钢管屈服强度 fy、型钢屈服强度 fys。构造与荷载组计算长度系数 μ、长细比 λ、偏心距 e、套箍系数 ξ。换算后的目标只有一个轴压承载力 Nu单位统一用 kN。这里有个新手最容易犯的错误直接把“面积×强度”当作特征塞进去。这没错但会教坏模型——既然 A×f 已经接近答案模型就没必要学约束效应和失稳模式了。更稳妥的输入是原始几何和材料参数让模型自己组合出物理规律再手工加入少量公认的组合特征。下面这个函数就是我在做特征工程时惯用的写法import pandas as pd df_raw pd.read_excel(cfst_raw.xlsx) # 原始试验/有限元表 def build_features(df): df df.copy() # 统一单位长度 mm、应力 MPa、力 kN df[alpha] df[As] / df[Ac] # 含钢率 df[xi] df[fy] * df[As] / (df[fc] * df[Ac]) # 套箍系数 df[D_over_t] df[D] / df[t] # 径厚比 df[lambda] df[mu] * df[L] / df[i] # 长细比 df[rho_ass] df[Ass] / df[Ac] # 型钢配钢率 return df df_feat build_features(df_raw) X df_feat.drop(columns[Nu, ID, source]) y df_feat[Nu] print(X.shape)逻辑不复杂但每个字段都有讲究。含钢率 alpha 和套箍系数 xi 是钢管混凝土的核心控制参数把这两个值算出来树模型分裂时更容易找到物理边界。长细比 lambda 需要回转半径 i如果原始表里没有就按组合截面的换算截面去算别用钢管单独的回转半径搪塞过去。D_over_t 和 rho_ass 是控制局部屈曲和型钢贡献的比例项对 CNN 的截面编码也有辅助作用。要注意单位必须统一否则计算 xi 时会错出数量级。2.3 特征加工后的检查相关性、量纲、异常值三个坑特征加工完别直接开训先做三个检查。第一是相关性用X.corr()看有没有相关系数超过 0.95 的冗余特征比如 D 和 Ac 通常高度相关此时保留哪一个要看物理意义而不是看相关性数字。第二是量纲线性回归和 CNN 对量纲敏感mm、MPa、kN 混在一起会让梯度更新被大数值特征支配随机森林和 XGBoost 对单调变换不敏感但特征重要性会被特征尺度干扰。第三是异常值试验数据里偶尔会出现手误录入fc 写成 120 MPa 或 D 写错了一位这类脏数据对树模型的影响比想象中大。一个实用做法是分位数裁剪而不是直接删行import numpy as np def clip_outliers(X, feat_cols, low0.01, high0.99): X X.copy() for c in feat_cols: lo, hi X[c].quantile(low), X[c].quantile(high) X[c] X[c].clip(lo, hi) return X X_clipped clip_outliers(X, X.columns)分位数裁剪不是万能的它保留了样本数量只是把极端尾部压到边界。对于承载力预测这种物理上本来就有上下限的任务这个手段比“超过 3σ 就删”温和得多也更不容易误杀真实的高强混凝土样本。2.4 训练集划分的坑同一根柱子的多个工况会泄漏承载力试验和有限元扫描有一个隐蔽的数据泄漏源——同一根柱子经常被计算多个偏心工况或者同一截面被不同长细比重复扫描。直接train_test_split会把同一来源的行同时分进训练和测试模型等于提前背了答案验证集 R2 虚高到 0.98换个试件就崩。正确的做法是按试件 ID 分组切分或者用 GroupShuffleSplit 做交叉验证from sklearn.model_selection import GroupShuffleSplit gss GroupShuffleSplit(n_splits5, test_size0.2, random_state42) for train_idx, test_idx in gss.split(X, y, groupsdf_feat[ID]): X_train, X_test X.iloc[train_idx], X.iloc[test_idx] y_train, y_test y.iloc[train_idx], y.iloc[test_idx]groupsdf_feat[ID]是关键ID是试件或有限元模型编号。同一 ID 下的所有行要么全在训练集、要么全在测试集模型看到的才是“没见过的新柱子”。这个操作对后续所有模型都生效线性回归、随机森林、XGBoost、CNN 全都按这套划分来评估模型之间才具有可比性。3. 四种模型逐个落地线性回归、随机森林、XGBoost、CNN 怎么选3.1 基线先行线性回归的代码与评价指标线性回归在这个任务里不算主力但它是必须跑的基线。原因很简单钢管混凝土的承载力在主效应上和“面积×强度”近似线性如果线性回归的 R2 都不到 0.7说明特征构造或数据本身有问题后面换多复杂的模型都是白费。跑之前要标准化因为线性回归的系数受量纲影响标准化后还能顺手看哪些特征对承载力贡献大。from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score, mean_absolute_error, mean_absolute_percentage_error X_train, X_test, y_train, y_test train_test_split( X_clipped, y, test_size0.2, random_state42 ) scaler StandardScaler().fit(X_train) X_train_s scaler.transform(X_train) X_test_s scaler.transform(X_test) lr LinearRegression().fit(X_train_s, y_train) y_pred_lr lr.predict(X_test_s) print(R2:, r2_score(y_test, y_pred_lr)) print(MAE (kN):, mean_absolute_error(y_test, y_pred_lr)) print(MAPE:, mean_absolute_percentage_error(y_test, y_pred_lr))注意mean_absolute_percentage_error在 scikit-learn 1.4 之后才进主包老版本需要自己写np.mean(np.abs((y_true - y_pred) / y_true))。MAPE 对真实值很小的样本特别敏感承载力一般都在几百 kN 以上问题不大但如果你的数据里有短柱也有细长柱细长柱的真实值可能只有 200 kN一个 30 kN 的绝对误差就能把 MAPE 拉到 15%。所以我一般同时看 MAE 和 R2MAPE 只作参考。实际跑下来线性回归在精心构造特征后通常能到 0.8 左右的 R2。它学不到套箍效应这种交互项——承载力的提升并不是钢管和混凝土各自贡献的简单相加而是约束使混凝土强度提高这正是线性回归的天花板。3.2 随机森林回归先给一组能用的默认参数随机森林在中小样本表格数据上是稳健起手式不怕量纲、不容易大幅过拟合。我在这个任务里的默认参数是n_estimators300, min_samples_leaf3, max_features1.0。max_features1.0是回归下 sklearn 的默认值意味着每棵树的每个分裂都能看所有特征特征数只有十几个时这个设置比随机子空间更合理。min_samples_leaf3是防过拟合的关键不设的话叶子节点可能只装一个样本训练集 R2 接近 1测试集立刻崩。from sklearn.ensemble import RandomForestRegressor rf RandomForestRegressor( n_estimators300, min_samples_leaf3, max_features1.0, random_state42, n_jobs-1 ) rf.fit(X_train, y_train) y_pred_rf rf.predict(X_test) print(RF R2:, r2_score(y_test, y_pred_rf)) print(RF MAE:, mean_absolute_error(y_test, y_pred_rf)) importances pd.Series(rf.feature_importances_, indexX_train.columns) print(importances.sort_values(ascendingFalse).head(10))特征重要性只反映“分裂时带来的不纯度下降”不等于物理贡献。比如 fc 如果变化范围大它更容易被选来分裂重要性就虚高这不代表混凝土强度比截面尺寸更重要。所以我只在特征筛选用它不会拿它写进论文做物理结论。看特征重要性时还有个小技巧把重要性超过 0.1 的特征列出来看看是不是集中在 Ac、fc、fy 附近如果分布太散说明样本量不够或者特征构造有问题。3.3 XGBoost 回归learning_rate 与 early_stopping 的配合XGBoost 在数百到数千条的表格数据上通常是最强基线。它的优势在于能自动学到特征交互——套箍系数对承载力的影响会被反复分裂捕捉。参数上我习惯把learning_rate降到 0.05 左右树深度限制在 4 层然后把n_estimators放到 1000配合早停让它自己决定何时停下。import xgboost as xgb model xgb.XGBRegressor( n_estimators1000, learning_rate0.05, max_depth4, subsample0.8, colsample_bytree0.8, random_state42, early_stopping_rounds30 ) model.fit( X_train, y_train, eval_set[(X_test, y_test)], verboseFalse ) y_pred_xgb model.predict(X_test) print(XGB R2:, r2_score(y_test, y_pred_xgb)) print(XGB MAE:, mean_absolute_error(y_test, y_pred_xgb))learning_rate0.05配合n_estimators1000的含义是每一步只学 5% 的残差靠大量小步逼近答案。这样比直接用 0.3 的高学习率加 100 棵树稳定得多尤其在小样本上几乎不会一把就过拟合。max_depth4控制了交互阶数承载力预测里四层足以覆盖“尺寸 × 强度 × 约束”的交互。subsample和colsample_bytree分别是行采样和列采样每棵树只用 80% 的数据和 80% 的特征方差会明显下降。不同版本的 xgboost 对early_stopping_rounds的接收位置有差异老版本放在fit里新版本可以直接放进构造函数。报TypeError: __init__() got an unexpected keyword argument early_stopping_rounds时把它挪到fit里就行。还有个细节早停是基于eval_set的指标默认是 RMSE如果你更在意 MAE可以显式写eval_metricmae。3.4 CNN 怎么接承载力预测一维卷积是伪需求二维截面编码才是正路标题里的 CNN 是最容易“为了用而用”的模型。如果把 14 个表格特征排成一行塞进 Conv1D性能大概率被 XGBoost 碾压而且解释性更差。我见过不少代码就是这么写的跑完发现 CNN 最差于是得出一句“深度学习方法不适用于小样本结构数据”——这话说早了错在输入形式。CNN 真正有意义的地方在截面空间编码。内配型钢钢管混凝土柱的核心特征是截面里不同材料的空间分布钢管在周边、混凝土在中间、型钢埋在混凝土内工字形、十字形、角钢布置对承载力的影响是二维空间性的。表格数据把“型钢面积”压缩成一个数丢失了“型钢分布在哪”的信息。CNN 的卷积核天然适合处理这种空间结构。做法是把截面划分成 64×64 的网格每个像素用材料编码赋值——钢管为 1.0、混凝土为 0.0、内配型钢为 0.5再叠加上该像素对应的材料强度或应力分配权重。这样每张图本身就携带了截面几何信息。import tensorflow as tf from tensorflow.keras import layers, models def section_to_image(D, t, Ass_layout, grid64): # 按实际截面几何生成材料编码图 # 返回 shape: (grid, grid, 1) img np.zeros((grid, grid, 1), dtypenp.float32) # 这里填充钢管环、型钢布置、混凝土区的编码逻辑 return img # 假设 X_cnn_train 形状为 (n_samples, 64, 64, 1) inputs tf.keras.Input(shape(64, 64, 1)) x layers.Conv2D(16, 3, activationrelu, paddingsame)(inputs) x layers.MaxPooling2D(2)(x) x layers.Conv2D(32, 3, activationrelu, paddingsame)(x) x layers.GlobalAveragePooling2D()(x) x layers.Dense(32, activationrelu)(x) x layers.Dropout(0.2)(x) outputs layers.Dense(1)(x) cnn_model tf.keras.Model(inputs, outputs) cnn_model.compile(optimizeradam, lossmse, metrics[mae]) cnn_model.fit( X_cnn_train, y_train, epochs300, batch_size16, validation_split0.2, callbacks[tf.keras.callbacks.EarlyStopping(patience30, restore_best_weightsTrue)], verbose0 )网络结构上我先用两层卷积加池化提取局部材料分布模式然后直接用GlobalAveragePooling2D替代 Flatten这样不管截面网格多大全连接层参数都是固定的也不容易过拟合。Dropout(0.2)加在全连接层前CNN 在几百条样本上很容易记住训练集这个 Dropout 是后悔药。batch_size16对于小样本是合理选择别用 128梯度更新次数太少模型根本学不动。如果想让 CNN 更强还可以做多输入模型截面图喂卷积分支表格特征喂全连接分支最后合并输出。但我会提醒一句如果你的样本量少于 500CNN 的效果大概率不如 XGBoost这个阶段更值得做的是调特征和做交叉验证而不是在 CNN 上死磕。4. 避坑清单小样本承载力回归最容易翻车的五个点4.1 训练 R2 接近 1测试 R2 暴跌典型的过拟合现象随机森林或 XGBoost 训练集 R2 高达 0.99测试集只有 0.7 左右CNN 更夸张训练损失降到几乎为 0验证集却一路走高。原因样本量一般只有几百条模型容量超过了数据信息量。树模型的min_samples_leaf1会为每个样本单独建叶子CNN 的全连接层参数过多。再加上这个任务本身信噪比不高试验数据自带离散性模型为了拟合噪声把边界画得特别碎。解决树模型把min_samples_leaf调到 3~5把 XGBoost 的max_depth降到 3~4配合早停。CNN 加 Dropout、减小 Dense 层宽度、用 EarlyStopping 恢复最佳权重。评估指标以交叉验证为准不要看单次留出集的 R2。4.2 模型预测出负承载力物理常识校验失败现象对细长柱或大偏心样本做预测个别输出是负值比如 -120 kN。承载力在物理上不可能为负这个结果一旦交付出去业主和审图方直接失去信任。原因回归模型的输出层是线性的理论上可以输出任意实数。当训练数据里没有极端细长柱样本时模型在特征空间外推线性组合或树的叶子平均就会算出负值。解决两种手段。第一种是工程兜底预测后执行y_pred np.clip(y_pred, 0, None)把负值截断为零第二种是训练时把标签做下限感知例如对输出层Dense(1, activationrelu)至少保证前向传播的输出非负。物理问题先工程解决再谈模型改进。4.3 单位不统一导致结果差一个数量级现象特征表里 fc 用 MPa某些源自国外的数据用 psi 或 ksi力的单位 kN 与 N 混用。特征工程阶段没报错但套箍系数 xi 的计算结果差了好几个量级模型表现奇差。原因手敲数据时没做单位规范化或者合并多来源数据时只检查了列名没检查单位。更隐蔽的是有限元软件输出的默认单位与手算表不一致比如 ABAQUS 用 N/mm²实际整理时忘了换算。解决在特征工程函数开头写一个assert_units检查例如assert df[fc].max() 300因为常规混凝土 fc 不可能超过 300 MPa。每次合并数据后重跑这个断言把单位问题挡在训练之前。4.4 同一试件的多行样本被随机切分看似样本多实则泄漏现象加了有限元补样本后N 从 100 变成 800验证集 R2 也涨到 0.96但实际换新截面预测就废。原因同一根柱子在不同偏心距、不同长细比下产生了多行样本随机切分让“同一根柱子”的一部分出现在训练集、一部分出现在测试集。模型记住的是这根柱子的整体规律不是截面的泛化规律。解决按试件 ID 使用GroupShuffleSplit或者干脆每个试件只保留一个代表工况。这个泄漏源比过拟合更隐蔽因为它不报错只会在模型部署后突然翻车。4.5 归一化放错了位置测试集信息提前泄露给模型现象线性回归和 CNN 的验证集 R2 虚高但换一批新数据就崩检查代码发现 scaler 在划分训练集之前就对全部数据做了fit_transform。原因StandardScaler().fit()计算了全量数据的均值和方差测试集的信息通过这两个统计量进入了训练流程。树模型不受影响但线性回归和 CNN 的特征缩放依赖这些统计量。解决先切分再在训练集上fit标准化器测试集只transform。代码第 3.1 节里写的顺序——train_test_split先于StandardScaler().fit(X_train)——就是为了避免这个泄漏。额外注意交叉验证时每一折都要重新fitscaler不能只 fit 一次。5. 验证与进阶物理一致性检查、交叉验证与规范公式兜底5.1 物理一致性单调性探针比指标分数更可靠R2 和 MAE 只能告诉你误差大小不能告诉你模型是否学到了物理规律。承载力预测最怕的不是误差大而是预测结果违背常识钢管直径增大承载力不升反降混凝土强度提高承载力反而减少。我在交付模型前固定跑一遍单调性探针——把其他特征固定在中位数逐个特征在训练集的 5% 到 95% 分位数之间取 20 个点看预测序列是否单调上升。import numpy as np def monotonicity_probe(model, X_train, feats): base X_train.median().to_frame().T for feat in feats: vals np.linspace( X_train[feat].quantile(0.05), X_train[feat].quantile(0.95), 20 ) preds [] for v in vals: row base.copy() row[feat] v preds.append(model.predict(row)[0]) diff np.diff(preds) ratio (diff 0).mean() if ratio 0.2: print(f{feat} 单调性异常下降比例 {ratio:.2f})树模型的预测是分段常数单变量扫描时会出现小幅锯齿所以下降比例容忍到 20%。如果超过 20%不是数据有偏就是特征构造有问题——比如长细比与承载力呈倒 U 型关系这时候单调性探针本身就不适用要改用相关性或交互分析不要一刀切。5.2 用分组五折交叉验证替代单次留出单次留出集的结果波动太大尤其是只有几百条样本时换一个随机种子 R2 可能差 0.1。我的做法是固定的五折分组交叉验证一折对应 20% 的试件。每一折单独完成标准化、训练、预测最后汇总全部预测值计算总指标。这样每个试件都参与过测试结果对数据划分不敏感。随机森林和 XGBoost 在这个验证框架下一般能稳定在 0.85 以上的 R2线性回归 0.75 左右CNN 则看样本量和截面编码的质量。5.3 进阶技巧给模型配一个规范公式兜底模型做得再好交付到设计流程里总会遇到一个问题——审图方要求提供可复核的依据。我的习惯是从不把机器学习输出作为唯一结果而是同时用 GB 50936-2014 或 EC4 的钢管混凝土承载力公式算一个参考值。如果机器学习预测值落在规范公式值的 0.85 到 1.15 区间内认为模型合理超出这个区间就以规范值为准并把这条样本标记为“模型外推风险点”。这就是给模型配了个兜底公式。实际交付时我会把三个数字并列输出机器学习预测值、规范公式值、两者的比值。工程师看到比值在合理范围才会愿意把模型当作快速估算工具用起来。另外我习惯把训练好的 xgboost 模型连同特征字典、数据清洗脚本一起打进 zip 包里而不是只交付训练好的model.json。特征字典里记录每个字段的单位、来源、裁剪边界。半年后你再打开这个项目能让你快速恢复上下文的不是模型权重而是那份特征字典。做结构数据项目这个习惯帮我省了太多返工的时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表