
简介这份资源是面向计算机、人工智能、自动化等专业学生与科研人员的课程设计资料包聚焦人工智能在石油测井领域的落地应用核心任务为Python岩性识别与测井曲线回归。包内共246个文件以175个csv测井数据、28个ipynb实验笔记、23个xlsx表格为主另含docx设计报告、md说明文档及少量py脚本与html页面压缩包约174.51MB数据与代码分层清晰便于按模块复现。目前已有56人学习下载。资源完整覆盖从原始测井曲线读取、特征工程到岩性分类与回归建模的全流程配套设计文档可帮助读者理解建模思路与评价指标适合直接用作课设、毕设或项目初期立项演示也便于在现有代码基础上修改扩展实现其他测井解释功能。1. 从一份课程设计说起Python 岩性识别与测井曲线回归到底在做什么如果你手头正拿着一份“人工智能在石油测井应用”的课程设计大概率会卡在同一个地方数据是一堆 .las 或 .csv 测井曲线任务是岩性识别和曲线回归但真到动手时连第一步该用 pandas 还是 lasio 都要犹豫半天。这个方向说白了就是用 Python 把测井数据喂进机器学习模型让模型学会两件事——一是判断某段地层是什么岩性分类二是根据已有曲线预测缺失或目标曲线回归。它适合地质、测井、石油工程背景的学生和一线技术人员也适合想拿一个真实工业数据集练手的 Python 学习者。核心不在模型多花哨而在数据清洗、特征选择和曲线对齐这些脏活上。2. 数据准备测井曲线读进来、对齐好、特征选对2.1 用 lasio 和 pandas 把 LAS 文件变成可训练的表格测井数据最常见的格式是 LAS 2.0里面按深度排列了 GR、RT、DEN、CNL、AC 等多条曲线。直接拿 pandas 读会丢深度信息我一般先用 lasio 读再转成 DataFrame。下面这段代码是本地跑通的最小命令假设你已经在 vscode python 环境配置里装好了 lasio 和 pandas。import lasio import pandas as pd import numpy as np # 读取 LAS 文件注意 encoding 有时是 gbk las lasio.read(well_01.las, encodinggbk) # 转成 DataFrame深度作为索引 df las.df() df.index.name DEPTH df df.reset_index() # 只保留常用曲线避免全列进模型 cols [DEPTH, GR, RT, DEN, CNL, AC] df df[[c for c in cols if c in df.columns]] # 把 -999.25 这类无效值替换成 NaN df df.replace(-999.25, np.nan) # 按深度排序并去重 df df.sort_values(DEPTH).drop_duplicates(DEPTH).reset_index(dropTrue) print(df.head()) print(df.isna().sum())逻辑说明lasio 负责解析 LAS 头信息和曲线数组df() 直接给出以深度为索引的表格。参数上encoding 要根据文件实际编码调整中文井场数据常见 gbk无效值 -999.25 是测井行业默认的 null 标记必须替换成 NaN否则模型会把 -999.25 当成真实低值学进去。isna().sum() 用来快速看每条曲线的缺失比例缺失超过 40% 的曲线建议直接放弃。2.2 曲线对齐与深度重采样别让不同采样率的曲线互相打架不同测井仪器的采样间隔不一样有的 0.1 米有的 0.2 米直接按行拼接会出现深度错位。常见做法是统一重采样到 0.1 米或 0.125 米。下面用 pandas 的 resample 做前提是深度列已经设为索引。# 设深度为索引转成时间序列式的重采样 df df.set_index(DEPTH) # 统一到 0.1 米间隔用线性插值补空缺 df_res df.resample(0.1).mean().interpolate(methodlinear) # 插值后仍有边缘 NaN用前后值填充 df_res df_res.ffill().bfill() df_res df_res.reset_index() print(df_res.shape)逻辑说明resample(0.1) 表示每 0.1 米一个深度点mean() 处理同一深度有多个值的情况interpolate 做线性插值。参数上如果原始数据是 0.2 米间隔重采样到 0.1 米会引入插值点这对回归任务影响不大但对岩性分类要小心——插值出来的深度点没有真实岩性标签训练前必须把标签对齐到原始采样点或者只保留有标签的深度段。ffill().bfill() 是后悔药防止首尾出现 NaN 导致模型报错。2.3 特征选择GR、RT、DEN 不是越多越好测井曲线之间相关性很高全塞进模型容易过拟合。我一般先算相关系数矩阵再结合地质常识保留 4 到 6 条。GR 对泥质含量敏感RT 区分油水层DEN 和 CNL 组合能识别岩性AC 反映孔隙度。下面这段代码输出相关系数并做简单筛选。import seaborn as sns import matplotlib.pyplot as plt # 只对数值列算相关 corr df_res[[GR, RT, DEN, CNL, AC]].corr() # 打印高相关对 high_corr np.where(np.abs(corr) 0.85) for i, j in zip(*high_corr): if i j: print(corr.index[i], corr.columns[j], corr.iloc[i, j]) # 热力图辅助判断 sns.heatmap(corr, annotTrue, cmapcoolwarm) plt.show()逻辑说明相关系数绝对值超过 0.85 的曲线对保留地质意义更明确的那条。比如 DEN 和 AC 高度负相关时我通常留 DEN因为密度对岩性区分更直接。参数上0.85 不是铁律数据质量差时可以放宽到 0.9。这一步不做后面模型特征重要性会告诉你“每条曲线都重要”那是假象。3. 岩性识别从随机森林到 XGBoost 的完整训练流程3.1 标签制作把岩性描述转成数字编码课程设计里的岩性标签通常来自岩心描述或录井报告格式是“砂岩”“泥岩”“灰岩”这类文本。模型只认数字所以要先编码。常见做法是用 sklearn 的 LabelEncoder同时保存映射关系方便后面画混淆矩阵。from sklearn.preprocessing import LabelEncoder # 假设 df_res 里有一列 LITH 是岩性文本 le LabelEncoder() df_res[LITH_CODE] le.fit_transform(df_res[LITH]) # 保存映射关系 mapping dict(zip(le.classes_, le.transform(le.classes_))) print(mapping) # 查看各类别样本数 print(df_res[LITH_CODE].value_counts())逻辑说明fit_transform 会把“灰岩”“泥岩”“砂岩”按字母顺序编码成 0、1、2具体顺序不重要但 mapping 必须存下来否则预测结果没法还原成岩性名。value_counts() 用来检查类别是否极度不平衡如果某一类少于 50 个样本后面训练要加 class_weight 或做重采样。3.2 随机森林基线先跑通再调参新手最容易犯的错是一上来就上深度学习结果数据量不够模型不收敛。我一般先用随机森林做基线因为它对缺失值和特征尺度不敏感调参也直观。下面是从划分训练集到输出分类报告的完整代码。from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix # 特征列和标签列 feature_cols [GR, RT, DEN, CNL, AC] X df_res[feature_cols].values y df_res[LITH_CODE].values # 按深度顺序划分容易泄漏这里随机划分 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) # 随机森林树数量先设 200 rf RandomForestClassifier( n_estimators200, max_depth12, min_samples_leaf5, class_weightbalanced, random_state42, n_jobs-1 ) rf.fit(X_train, y_train) y_pred rf.predict(X_test) print(classification_report(y_test, y_pred, target_namesle.classes_)) print(confusion_matrix(y_test, y_pred))逻辑说明stratifyy 保证训练集和测试集类别比例一致避免某类岩性在测试集里消失。n_estimators200 是精度和速度的折中max_depth12 防止树太深记住噪声min_samples_leaf5 让每片叶子至少有 5 个样本减少过拟合。class_weightbalanced 自动按类别频率反比加权对不平衡岩性数据很关键。classification_report 里的 f1-score 比准确率更能反映真实效果尤其当泥岩样本占 70% 以上时。3.3 XGBoost 提升参数怎么设、早停怎么用如果随机森林的 f1 卡在 0.75 左右上不去可以换 XGBoost。它对特征交互的捕捉更强但参数更多。下面这段代码带早停防止树太多过拟合。import xgboost as xgb from sklearn.metrics import f1_score # 划分训练和验证用于早停 X_train, X_val, y_train, y_val train_test_split( X_train, y_train, test_size0.2, random_state42, stratifyy_train ) dtrain xgb.DMatrix(X_train, labely_train) dval xgb.DMatrix(X_val, labely_val) dtest xgb.DMatrix(X_test, labely_test) params { objective: multi:softmax, num_class: len(le.classes_), eta: 0.05, max_depth: 6, subsample: 0.8, colsample_bytree: 0.8, eval_metric: mlogloss, seed: 42 } bst xgb.train( params, dtrain, num_boost_round500, evals[(dval, val)], early_stopping_rounds30, verbose_eval50 ) y_pred_xgb bst.predict(dtest, iteration_range(0, bst.best_iteration 1)) print(XGBoost F1:, f1_score(y_test, y_pred_xgb, averagemacro))逻辑说明eta 是学习率0.05 比默认 0.3 慢但更稳max_depth6 控制树复杂度subsample 和 colsample_bytree 都是 0.8引入随机性防过拟合。early_stopping_rounds30 表示验证集损失 30 轮不下降就停best_iteration 告诉你实际用了多少棵树。参数上num_class 必须等于岩性类别数否则报错。iteration_range 确保预测只用早停时的最优轮数而不是全部 500 轮。4. 测井曲线回归用随机森林和 MLP 预测缺失曲线4.1 回归任务定义用 GR、RT、DEN 预测 AC曲线回归的典型场景是某口井缺 AC 曲线但邻井有于是用邻井数据训练模型再预测本井 AC。特征还是 GR、RT、DEN、CNL目标换成 AC。下面先做数据准备和划分。from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, r2_score # 目标曲线 AC特征用其余曲线 feature_cols_reg [GR, RT, DEN, CNL] target_col AC # 去掉目标缺失的行 df_reg df_res.dropna(subsetfeature_cols_reg [target_col]) X_reg df_reg[feature_cols_reg].values y_reg df_reg[target_col].values X_train_r, X_test_r, y_train_r, y_test_r train_test_split( X_reg, y_reg, test_size0.2, random_state42 )逻辑说明dropna 确保特征和目标都没有缺失否则 sklearn 会报错。回归任务不需要 stratify因为目标连续。random_state 固定后结果可复现方便写报告时截图。4.2 随机森林回归n_estimators 和 max_depth 怎么定rf_reg RandomForestRegressor( n_estimators300, max_depth15, min_samples_leaf3, random_state42, n_jobs-1 ) rf_reg.fit(X_train_r, y_train_r) y_pred_r rf_reg.predict(X_test_r) rmse mean_squared_error(y_test_r, y_pred_r, squaredFalse) r2 r2_score(y_test_r, y_pred_r) print(fRMSE: {rmse:.4f}, R2: {r2:.4f})逻辑说明n_estimators300 比分类任务多因为回归对树数量更敏感max_depth15 允许更深的分裂拟合曲线细节min_samples_leaf3 防止叶子节点样本太少导致预测方差大。RMSE 的单位和 AC 一致R2 越接近 1 越好。如果 R2 低于 0.6先检查特征里有没有和目标强相关的曲线比如用 DEN 预测 AC 通常比用 GR 好。4.3 MLP 回归标准化和早停是必须的神经网络对尺度敏感特征必须先标准化。下面用 sklearn 的 MLPRegressor 做对比。from sklearn.preprocessing import StandardScaler from sklearn.neural_network import MLPRegressor scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train_r) X_test_scaled scaler.transform(X_test_r) mlp MLPRegressor( hidden_layer_sizes(64, 32), activationrelu, solveradam, alpha0.001, learning_rate_init0.001, max_iter1000, early_stoppingTrue, validation_fraction0.1, random_state42 ) mlp.fit(X_train_scaled, y_train_r) y_pred_mlp mlp.predict(X_test_scaled) rmse_mlp mean_squared_error(y_test_r, y_pred_mlp, squaredFalse) r2_mlp r2_score(y_test_r, y_pred_mlp) print(fMLP RMSE: {rmse_mlp:.4f}, R2: {r2_mlp:.4f})逻辑说明hidden_layer_sizes(64, 32) 表示两层隐藏层第一层 64 个神经元第二层 32 个。alpha0.001 是 L2 正则化系数防止权重过大。early_stoppingTrue 自动从训练集里分 10% 做验证连续 10 轮验证分数不提升就停。标准化用 fit_transform 在训练集上算均值和方差再用同一个 scaler 去 transform 测试集否则数据泄漏。5. 避坑与排查岩性识别和曲线回归里最容易翻车的 5 个点5.1 深度顺序划分导致数据泄漏现象随机划分训练集和测试集后测试集 f1 高达 0.95但拿另一口井预测时惨不忍睹。原因同一口井相邻深度点的曲线高度相似随机划分让训练集和测试集共享了相邻样本模型等于抄答案。解决按井划分或者按深度段划分确保测试集来自不同井或不同层段。如果只有一口井至少按深度排序后取后 20% 做测试不要随机打乱。5.2 无效值没替换模型学到 -999.25现象回归 RMSE 巨大预测曲线在某个深度段突然跳到 -999。原因LAS 文件里的 -999.25 没被替换成 NaN模型把它当成真实低值。解决读数据后第一件事就是 replace(-999.25, np.nan)同时检查有没有其他无效值标记比如 -9999 或 -1000。用 df.describe() 看最小值如果出现异常负值基本就是无效值。5.3 岩性类别不平衡模型只预测多数类现象泥岩占 80%模型把所有样本都预测成泥岩准确率 0.8 但 f1 只有 0.44。原因默认损失函数对多数类有利。解决分类器加 class_weightbalanced或者用 imblearn 做 SMOTE 过采样。注意 SMOTE 只能在训练集上做测试集保持原始分布。另外看 confusion_matrix如果非对角线全是 0就是这个问题。5.4 特征标准化只在训练集做测试集用了全局统计现象MLP 回归训练时 R2 0.85测试时 0.3。原因先用全量数据算均值和方差再划分测试集信息泄漏到训练过程。解决先 train_test_split再在训练集上 fit_transform测试集只 transform。树模型不需要标准化但神经网络和 SVM 必须遵守这个顺序。5.5 曲线回归目标泄漏用 AC 的衍生曲线预测 AC现象R2 接近 0.99但换一口井就失效。原因特征里混入了和目标曲线计算相关的曲线比如用 AC 算出的孔隙度再去预测 AC。解决检查特征列和目标列的物理关系凡是目标曲线经过公式变换得到的特征一律剔除。常见做法是只保留原始测井曲线不加入任何解释成果曲线。6. 进阶技巧用 SHAP 解释模型并验证曲线回归的物理合理性模型跑通只是第一步课程设计报告里如果只写“f1 0.82”说服力不够。我一般会加 SHAP 值分析看每条曲线对岩性判别的贡献再用交会图验证回归曲线是否符合地质规律。下面这段代码用 SHAP 解释随机森林分类模型。import shap # 用训练集子集算 SHAP全量太慢 explainer shap.TreeExplainer(rf) shap_values explainer.shap_values(X_test[:200]) # summary plot只看第一类岩性 shap.summary_plot(shap_values[0], X_test[:200], feature_namesfeature_cols)逻辑说明TreeExplainer 对随机森林和 XGBoost 都适用shap_values 是一个列表每个类别一个数组。summary_plot 里每个点是一个样本横轴是 SHAP 值颜色是特征值大小。如果 GR 的高值集中在正 SHAP 区域说明高 GR 推动模型判为泥岩这和地质常识一致。参数上X_test[:200] 是抽样全量计算可能几分钟抽样 200 个点足够看趋势。回归曲线的物理验证更直接把预测的 AC 和实测 AC 画在同一张深度图上看趋势是否一致。如果预测曲线在砂岩段突然降低而实测曲线平稳说明模型没学到岩性控制。我一般会再画一个 AC 与 DEN 的交会图预测点应该落在实测点的包络范围内。这一步不做报告里“模型效果良好”就是空话。最后说个血泪经验课程设计里最花时间的不是调模型而是把 LAS 文件读对、把深度对齐、把无效值清干净。我习惯在数据准备阶段就写一个检查脚本输出每条曲线的缺失率、深度范围、异常值数量打印出来贴在报告附录里。这样即使模型 f1 只有 0.78评审也能看到你认真处理了数据。希望帮到你。本文还有配套的精品资源点击获取