ARTICLE DETAIL

资讯详情

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

Python数据分析实战:从古代玻璃成分鉴别到数学建模全流程解析

Python数据分析实战:从古代玻璃成分鉴别到数学建模全流程解析 1. 项目概述从一道赛题到一套完整的分析框架去年带学生备战国赛C题“古代玻璃制品的成分分析与鉴别”成了我们讨论的焦点。这道题之所以经典不仅在于它融合了化学、材料学、考古学和数据分析更因为它完美地呈现了数学建模竞赛的核心精神如何将一个开放的、跨学科的实际问题转化为可量化、可计算的数学模型并用代码实现。很多同学拿到题目看到“风化”、“化学成分”、“类型鉴别”这些词就有点发怵感觉涉及领域太多无从下手。其实这道题的魅力恰恰在于此它考察的不是你对古代玻璃工艺有多了解而是你从杂乱数据中提炼规律、构建模型并解决问题的能力。简单来说题目给了一批古代玻璃文物的化学成分检测数据这些文物有的经历了地下埋藏的风化成分发生了变化有的属于不同文化类型如高钾玻璃、铅钡玻璃。我们需要回答几个核心问题这些玻璃文物化学成分之间的关联规律是什么如何根据成分鉴别其类型风化对化学成分的影响有何规律可循以及对于给定化学成分的文物能否合理推测其风化前的原始成分这本质上是一道以数据驱动为核心的综合性题目非常适合用Python这一数据科学利器来攻克。通过这道题的完整拆解你不仅能掌握数学建模解决实际问题的完整流程更能深入理解描述性统计、相关性分析、主成分分析PCA、聚类分析、分类预测如逻辑回归、支持向量机以及回归分析等一系列核心算法的应用场景和实现细节。下面我就结合当时的解题思路和代码实战把这道题的“里子”和“面子”都讲透。2. 解题核心思路与整体设计面对这样一道数据丰富、问题多元的题目最忌讳的就是一头扎进数据里开始漫无目的地尝试各种算法。一个清晰的顶层设计是成功的一半。我们的整体思路可以概括为“数据理解 - 规律探索 - 模型构建 - 综合解答”四个阶段。2.1 问题拆解与建模路线图首先我们将赛题的四个问题转化为四个明确的建模任务成分关联与规律分析问题1这是探索性数据分析EDA阶段。目标不是预测而是描述和理解。我们需要分析化学成分之间的统计关系相关性并试图降低维度找到影响玻璃成分的主要“因子”或“成分组合”。这里相关性分析和主成分分析PCA是天然的工具。玻璃类型鉴别问题2这是一个典型的有监督分类问题。我们已知部分样本的“类型”标签高钾、铅钡目标是构建一个模型能够根据化学成分特征对未知样本或全部样本进行分类。逻辑回归、支持向量机SVM、决策树/随机森林等都是候选模型。风化效应分析问题3这可以看作一个差异性分析问题。我们需要比较风化样品与未风化样品在各项化学成分上的统计差异揭示风化过程导致的成分变化规律。独立样本T检验、箱线图可视化以及针对成分比例变化的特殊分析如风化前后氧化物含量的比值变化是主要手段。风化前成分预测问题4这是一个回归预测问题。对于风化样品我们已知其风化后成分需要预测其风化前的原始成分。由于风化过程复杂我们通常假设风化主要导致某些易流失成分如K2O, Na2O减少而某些稳定成分相对富集。可以尝试建立基于未风化样品规律的多元线性回归模型或使用更稳健的机器学习回归模型。2.2 工具选型与Python生态优势为什么选择Python因为它的数据科学生态Pandas, NumPy, Scikit-learn, Matplotlib/Seaborn为上述每一个任务都提供了强大、统一且高效的工具包。Pandas用于数据加载、清洗、转换和预处理的核心。处理赛题提供的Excel或CSV格式数据得心应手。NumPy提供底层数组计算支持是许多科学计算和算法的基础。Matplotlib Seaborn数据可视化的黄金搭档。从简单的散点图、直方图到复杂的多变量关系图、热力图都能轻松实现让数据规律一目了然。Scikit-learn机器学习算法的宝库。我们需要的PCA、逻辑回归、SVM、随机森林、回归模型等全部都有成熟、高效的实现并且API设计一致学习成本低。这个技术栈的优势在于从数据读取到模型评估可以在一个连贯的脚本或Jupyter Notebook中完成保证了分析流程的可复现性。接下来我们就进入实战环节看看如何用代码一步步实现这个分析框架。3. 数据预处理清洗、转换与特征工程拿到数据后切忌直接套用模型。原始数据往往存在缺失、量纲不一、分布异常等问题。高质量的数据预处理是模型成功的基石。3.1 数据加载与初步审查我们使用Pandas加载数据。假设数据文件为glass_data.csv。import pandas as pd import numpy as np # 加载数据 df pd.read_csv(glass_data.csv) # 查看数据概览 print(df.info()) # 查看列名、数据类型、非空值数量 print(df.head()) # 查看前几行数据 print(df.describe()) # 查看数值型特征的统计描述均值、标准差、分位数等通过df.info()我们需要重点关注以下几点缺失值化学成分数据中可能出现“ND”未检出或空白。这些需要被识别并处理。数据类型确保化学成分列是数值型float类型列是分类型object或category。样本划分数据中应包含“风化与否”和“玻璃类型”的标识列用于后续分组分析。3.2 缺失值处理与成分数据转换对于化学成分数据常见的缺失情况是“未检出”通常可以用一个较小的值如检测下限的一半或0进行替换但需谨慎因为0在后续对数变换或比例计算中会出问题。更稳健的方法是对于少量缺失使用该列的中位数或均值进行填充对于缺失严重的成分考虑是否将其从特征中移除。# 假设‘SiO2’ ‘Na2O’等是成分列 component_cols [SiO2, Na2O, K2O, CaO, MgO, Al2O3, Fe2O3, CuO, PbO, BaO] # 根据实际数据列名调整 # 检查缺失 print(df[component_cols].isnull().sum()) # 处理缺失这里以中位数填充为例 for col in component_cols: if df[col].isnull().any(): median_val df[col].median() df[col].fillna(median_val, inplaceTrue) print(f列 {col} 的缺失值已用中位数 {median_val:.4f} 填充)一个关键步骤是成分数据的归一化。玻璃成分通常是氧化物含量的重量百分比其总和理论上应为100%。但由于测量误差和微量未测成分实际总和可能略有偏差。进行定和归一化将所有成分换算为总和100%可以消除这种偏差使数据更符合实际情况也有利于后续分析。# 定和归一化使每个样本的所有成分之和为100% df[component_cols] df[component_cols].div(df[component_cols].sum(axis1), axis0) * 100注意定和归一化后特征之间存在严格的线性约束和为常数这在进行PCA等分析时需要留意。PCA本身可以处理这种共线性但理解数据的这一特性很重要。3.3 特征工程为模型创造更好的输入原始成分数据可以直接作为特征但根据化学知识我们还可以构造一些更有意义的衍生特征这可能有助于模型学习。比例特征例如碱金属与碱土金属的比例(Na2OK2O)/(CaOMgO)铅钡比PbO/BaO等这些比值可能对区分玻璃类型或判断风化程度更敏感。风化敏感指数根据文献钾、钠等碱金属氧化物在风化过程中易淋失。可以构造一个“风化敏感元素总量”特征如 K2ONa2O。是否为高钾/铅钡玻璃根据题目定义可以创建一个二分类标签。# 示例创建比例特征 df[NaK_to_CaMg] (df[Na2O] df[K2O]) / (df[CaO] df[MgO] 1e-6) # 加一个小数避免除零 df[Pb_to_Ba] df[PbO] / (df[BaO] 1e-6) df[Al_Si_ratio] df[Al2O3] / (df[SiO2] 1e-6) # 创建风化敏感指数 df[alkali_sum] df[Na2O] df[K2O]预处理完成后我们得到了一个干净、规整且包含潜在高价值特征的数据集可以正式开启建模分析之旅。4. 核心问题一玻璃成分关联与统计规律分析这是整个研究的基石目的是“读懂”数据。我们主要运用统计描述和降维技术。4.1 描述性统计与相关性分析首先分类型高钾/铅钡和分状态风化/未风化查看成分的统计特性。import seaborn as sns import matplotlib.pyplot as plt # 设置绘图风格 plt.style.use(seaborn-v0_8-darkgrid) sns.set_palette(husl) # 1. 按玻璃类型分组描述 type_groups df.groupby(玻璃类型)[component_cols] print(type_groups.mean()) print(type_groups.std()) # 2. 绘制成分均值对比柱状图 mean_by_type df.groupby(玻璃类型)[component_cols].mean().T mean_by_type.plot(kindbar, figsize(14, 6)) plt.title(不同玻璃类型化学成分平均含量对比) plt.ylabel(平均含量 (%)) plt.xticks(rotation45) plt.tight_layout() plt.show()接下来是相关性分析。我们计算所有化学成分之间的皮尔逊相关系数并用热力图可视化。# 计算相关系数矩阵 corr_matrix df[component_cols].corr() # 绘制热力图 plt.figure(figsize(12, 10)) sns.heatmap(corr_matrix, annotTrue, fmt.2f, cmapcoolwarm, center0, squareTrue, linewidths.5, cbar_kws{shrink: .8}) plt.title(玻璃化学成分相关性热力图) plt.tight_layout() plt.show()从热力图中我们可以直观看到哪些成分正相关如PbO和BaO可能在铅钡玻璃中同高同低哪些负相关。这为理解成分共生或拮抗关系提供了线索。4.2 主成分分析PCA探索内在结构当特征数量较多且可能存在共线性时PCA可以帮助我们找到数据中主要的变异方向用少数几个“主成分”来概括大部分信息。from sklearn.decomposition import PCA from sklearn.preprocessing import StandardScaler # 提取特征并标准化PCA受量纲影响必须标准化 X df[component_cols].values scaler StandardScaler() X_scaled scaler.fit_transform(X) # 执行PCA先保留所有成分看方差贡献 pca_full PCA() X_pca_full pca_full.fit_transform(X_scaled) # 绘制方差解释率碎石图 explained_variance_ratio pca_full.explained_variance_ratio_ cumulative_ratio np.cumsum(explained_variance_ratio) plt.figure(figsize(10, 5)) plt.subplot(1, 2, 1) plt.bar(range(1, len(explained_variance_ratio)1), explained_variance_ratio, alpha0.8) plt.xlabel(主成分序号) plt.ylabel(方差解释率) plt.title(PCA方差解释率碎石图) plt.subplot(1, 2, 2) plt.plot(range(1, len(cumulative_ratio)1), cumulative_ratio, bo-) plt.axhline(y0.85, colorr, linestyle--, alpha0.5) # 标记85%解释率线 plt.xlabel(主成分序号) plt.ylabel(累计方差解释率) plt.title(PCA累计方差解释率) plt.tight_layout() plt.show() print(f前3个主成分累计解释方差: {cumulative_ratio[2]:.2%}) print(f前5个主成分累计解释方差: {cumulative_ratio[4]:.2%})通常我们会选择累计解释方差达到85%左右的主成分数量。假设前3个主成分PC1 PC2 PC3已足够。# 选择前3个主成分重新拟合 n_components 3 pca PCA(n_componentsn_components) X_pca pca.fit_transform(X_scaled) # 将主成分得分添加到原数据框方便后续按类型/状态着色绘图 df[PC1] X_pca[:, 0] df[PC2] X_pca[:, 1] df[PC3] X_pca[:, 2] # 查看主成分的载荷Loading即每个原始变量对主成分的贡献 loadings pca.components_.T * np.sqrt(pca.explained_variance_) loading_matrix pd.DataFrame(loadings, columns[fPC{i1} for i in range(n_components)], indexcomponent_cols) print(主成分载荷矩阵前3个) print(loading_matrix) # 可视化按玻璃类型着色的PC1-PC2散点图 plt.figure(figsize(10, 8)) scatter plt.scatter(df[PC1], df[PC2], cpd.factorize(df[玻璃类型])[0], cmapviridis, alpha0.7, edgecolorsk, s80) plt.colorbar(scatter, label玻璃类型) plt.xlabel(fPC1 ({explained_variance_ratio[0]:.2%})) plt.ylabel(fPC2 ({explained_variance_ratio[1]:.2%})) plt.title(PCA降维结果按玻璃类型着色) # 可以在图上标注载荷较大的成分方向更直观 for i, comp in enumerate(component_cols): plt.arrow(0, 0, loadings[i, 0]*5, loadings[i, 1]*5, colorr, alpha0.5, head_width0.05) # 乘以5是为了放大箭头便于观察 plt.text(loadings[i, 0]*5.2, loadings[i, 1]*5.2, comp, colordarkred, fontsize9) plt.grid(True, alpha0.3) plt.tight_layout() plt.show()通过PCA图我们可以直观看到高钾玻璃和铅钡玻璃是否在主成分空间中被自然分开以及哪些化学成分箭头方向是导致这种分离的主要驱动力。例如PC1可能主要代表了“铅钡含量”轴而PC2可能代表了“碱金属含量”轴。实操心得PCA前务必进行标准化。解读主成分时重点看载荷矩阵的绝对值大小绝对值大的变量对该主成分贡献大。结合散点图能清晰展示样本的聚类情况和分离维度。5. 核心问题二基于化学成分的玻璃类型鉴别这是一个分类任务。我们利用已知类型的样本训练模型然后对全部样本进行分类。5.1 数据准备与模型选择首先我们需要准备训练集和测试集。由于数据量可能不大采用分层抽样和交叉验证是更稳健的策略。from sklearn.model_selection import train_test_split, StratifiedKFold, cross_val_score from sklearn.preprocessing import LabelEncoder from sklearn.linear_model import LogisticRegression from sklearn.svm import SVC from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import classification_report, confusion_matrix, accuracy_score # 准备特征和标签 # 使用原始成分衍生特征作为输入 feature_cols component_cols [NaK_to_CaMg, Pb_to_Ba, Al_Si_ratio, alkali_sum] X df[feature_cols].values # 编码标签将‘高钾’、‘铅钡’转为0/1 le LabelEncoder() y le.fit_transform(df[玻璃类型]) # 假设df[玻璃类型]列存在 # 划分训练集和测试集 (8:2)并分层抽样以保持类型比例 X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42, stratifyy) print(f训练集样本数: {X_train.shape[0]}, 测试集样本数: {X_test.shape[0]})接下来我们尝试几种经典的分类器并通过交叉验证初步评估其性能。# 初始化模型 models { Logistic Regression: LogisticRegression(max_iter1000, random_state42), SVM (RBF): SVC(kernelrbf, random_state42), Random Forest: RandomForestClassifier(n_estimators100, random_state42) } # 使用5折分层交叉验证评估 cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) results {} for name, model in models.items(): cv_scores cross_val_score(model, X_train, y_train, cvcv, scoringaccuracy) results[name] cv_scores print(f{name} - 交叉验证平均准确率: {cv_scores.mean():.4f} (/- {cv_scores.std()*2:.4f}))5.2 模型训练、评估与特征重要性分析选择交叉验证表现最好的模型假设是随机森林在完整训练集上训练并在独立测试集上最终评估。# 训练最佳模型以Random Forest为例 best_model RandomForestClassifier(n_estimators100, random_state42) best_model.fit(X_train, y_train) # 在测试集上预测和评估 y_pred best_model.predict(X_test) y_pred_proba best_model.predict_proba(X_test)[:, 1] # 获取属于正类的概率 print( 测试集性能评估 ) print(f准确率: {accuracy_score(y_test, y_pred):.4f}) print(\n分类报告:) print(classification_report(y_test, y_pred, target_namesle.classes_)) # 绘制混淆矩阵 cm confusion_matrix(y_test, y_pred) plt.figure(figsize(6,5)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsle.classes_, yticklabelsle.classes_) plt.ylabel(真实标签) plt.xlabel(预测标签) plt.title(混淆矩阵) plt.show()随机森林的一个巨大优势是可以输出特征重要性这能告诉我们哪些化学成分对区分玻璃类型最关键。# 特征重要性分析 feature_importance pd.DataFrame({ feature: feature_cols, importance: best_model.feature_importances_ }).sort_values(importance, ascendingFalse) plt.figure(figsize(10, 6)) sns.barplot(datafeature_importance, ximportance, yfeature) plt.title(随机森林特征重要性玻璃类型分类) plt.xlabel(重要性得分) plt.tight_layout() plt.show() print(特征重要性排序:) print(feature_importance)这个结果极具价值。它可能显示PbO、BaO、K2O等成分是区分高钾和铅钡玻璃的最关键因素这与我们的化学常识和PCA分析结果相互印证。5.3 对未知类型样本的预测训练好模型后我们可以对数据集中那些“类型未知”的样本如果题目提供了进行预测。如果没有也可以将模型应用于整个数据集观察分类结果与风化状态等其他信息的关系。# 假设df中有一部分样本的‘玻璃类型’为‘未知’或NaN # 首先分离出已知类型和未知类型的样本 mask_known df[玻璃类型].notna() (df[玻璃类型] ! 未知) mask_unknown ~mask_known df_known df[mask_known].copy() df_unknown df[mask_unknown].copy() if not df_unknown.empty: # 对未知样本使用相同的特征工程 X_unknown df_unknown[feature_cols].values # 使用在整个已知数据集上重新训练的模型进行预测为了利用所有已知信息 model_full RandomForestClassifier(n_estimators100, random_state42) model_full.fit(df_known[feature_cols].values, le.transform(df_known[玻璃类型])) predictions model_full.predict(X_unknown) df_unknown[预测类型] le.inverse_transform(predictions) print(未知类型样本的预测结果:) print(df_unknown[[文物编号, 预测类型]].head()) # 假设有‘文物编号’列注意事项分类模型的性能严重依赖于数据质量和特征工程。如果数据量很小模型可能过拟合。务必使用交叉验证来评估模型的泛化能力。此外分类结果应结合化学常识进行合理性判断如果模型将某个明显富含铅钡的样本分为高钾类则需要检查特征或模型。6. 核心问题三风化对玻璃成分影响的差异性分析风化过程会改变玻璃表面的化学成分。我们的目标是定量描述这种改变。6.1 分组统计与可视化对比最直接的方法是分别计算风化组和未风化组各成分的均值、中位数等统计量并进行比较。# 按风化状态分组 weathered_groups df.groupby(风化状态)[component_cols] # 假设有‘风化状态’列值为‘风化’、‘未风化’ summary weathered_groups.agg([mean, std, median]) print(summary) # 绘制分组箱线图对比关键成分 key_components [K2O, Na2O, CaO, PbO, BaO] fig, axes plt.subplots(2, 3, figsize(15, 10)) axes axes.ravel() for idx, comp in enumerate(key_components[:6]): # 选前6个成分绘图 sns.boxplot(x风化状态, ycomp, datadf, axaxes[idx]) axes[idx].set_title(f{comp} 含量对比) axes[idx].set_ylabel(含量 (%)) plt.tight_layout() plt.show()箱线图可以直观展示两组数据的中位数、四分位数和异常值观察风化是否导致了成分分布的整体偏移或离散度变化。6.2 统计检验量化差异的显著性仅仅看均值不同还不够我们需要用统计检验来判断这种差异是否具有统计学意义。对于两组独立样本风化 vs 未风化若数据近似正态分布可以使用独立样本T检验若不满足正态分布可以使用Mann-Whitney U检验非参数检验。from scipy import stats # 分离风化与未风化样本数据 weathered df[df[风化状态] 风化][component_cols] unweathered df[df[风化状态] 未风化][component_cols] t_test_results [] for col in component_cols: # 进行方差齐性检验Levene检验 _, levene_p stats.levene(weathered[col].dropna(), unweathered[col].dropna()) equal_var True if levene_p 0.05 else False # 通常以p0.05认为方差齐 # 进行独立样本T检验 t_stat, p_value stats.ttest_ind(weathered[col].dropna(), unweathered[col].dropna(), equal_varequal_var, nan_policyomit) t_test_results.append({ 成分: col, T统计量: t_stat, P值: p_value, 差异显著 (p0.05): p_value 0.05, 风化组均值: weathered[col].mean(), 未风化组均值: unweathered[col].mean(), 均值变化(%): (weathered[col].mean() - unweathered[col].mean()) / unweathered[col].mean() * 100 }) t_test_df pd.DataFrame(t_test_results) print(风化与未风化玻璃成分T检验结果:) print(t_test_df.sort_values(P值))通过检验结果表格我们可以清晰地看到哪些成分在风化前后发生了显著变化P值小于0.05以及变化的幅度和方向均值变化%。例如很可能会发现K2O和Na2O在风化组中显著降低而SiO2或Al2O3等稳定成分的相对含量可能表现出显著升高由于其他成分流失导致的相对富集。6.3 风化前后成分比例变化规律除了绝对含量研究成分之间的比例变化更能揭示风化过程的化学机理。例如计算每个样本风化前后假设有配对数据或两组之间平均的K2O/SiO2、(Na2OK2O)/CaO等比值的变化。# 计算并对比关键比值 df[K_Si_ratio] df[K2O] / (df[SiO2] 1e-6) df[NaK_Ca_ratio] (df[Na2O] df[K2O]) / (df[CaO] 1e-6) ratio_cols [K_Si_ratio, NaK_Ca_ratio] ratio_summary df.groupby(风化状态)[ratio_cols].mean() print(关键比值分组均值:) print(ratio_summary) # 可视化比值分布 fig, axes plt.subplots(1, 2, figsize(12, 5)) for idx, col in enumerate(ratio_cols): sns.violinplot(x风化状态, ycol, datadf, axaxes[idx], innerquartile) axes[idx].set_title(f{col} 比值分布对比) plt.tight_layout() plt.show()小提琴图结合了箱线图和核密度估计能更好地展示比值的分布形态看出风化是否使得比值分布更加集中或分散。实操心得风化分析中关注“相对变化”往往比“绝对变化”更有意义。因为风化是表面过程绝对含量的测量受风化层厚度、测量位置影响大而成分之间的比例关系更能反映风化作用的化学选择性。例如碱金属的显著流失会导致SiO2的相对百分比上升但这不一定是SiO2绝对增加了。7. 核心问题四风化前化学成分的预测推断这是最具挑战性的一问本质上是根据风化后的成分X_weathered预测其风化前的原始成分X_original。这是一个回归问题但难点在于我们通常没有“风化前-风化后”的配对数据。7.1 建模思路与数据准备有两种主要思路基于未风化样本建立“健康”成分模型假设未风化样本的成分代表了该类型玻璃的原始组成。那么对于风化样本其原始成分应接近于同类型未风化样本的成分分布。我们可以用未风化样本各成分的均值或中位数作为预测值。这是一种简单的基准方法。建立回归模型假设风化过程对成分的影响存在某种系统性的数学关系尽管很复杂。我们可以利用全部样本将“是否风化”作为状态变量尝试建立从“当前成分”到“原始成分”的映射。但这需要很强的假设。一个更可行的方案是针对每种玻璃类型分别用其未风化样本训练一个回归模型预测该类型玻璃风化后的成分变化模式然后反推。这里我们展示第二种思路中一个简化的实现针对每种类型假设主要变化发生在少数易风化成分上建立这些成分的回归预测模型。from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error, r2_score # 假设我们决定预测易风化的 K2O 和 Na2O 的原始含量 target_components [K2O, Na2O] predictor_components [c for c in component_cols if c not in target_components] # 用其他稳定成分作为预测因子 predictions {} for glass_type in df[玻璃类型].unique(): print(f\n 处理玻璃类型: {glass_type} ) type_data df[df[玻璃类型] glass_type].copy() # 分离训练集未风化和预测集风化 train_data type_data[type_data[风化状态] 未风化] predict_data type_data[type_data[风化状态] 风化] if train_data.empty or predict_data.empty: print(f 类型 {glass_type} 缺少未风化或风化样本跳过。) continue for target in target_components: print(f 训练模型预测原始 {target} ...) X_train train_data[predictor_components].values y_train train_data[target].values # 使用简单的线性回归 model LinearRegression() model.fit(X_train, y_train) # 评估模型在训练集上的表现仅供参考 y_train_pred model.predict(X_train) r2_train r2_score(y_train, y_train_pred) print(f 训练集 R^2 {r2_train:.4f}) # 对风化样本进行预测即预测其原始含量 X_pred predict_data[predictor_components].values y_pred_original model.predict(X_pred) # 将预测结果保存 for idx, sample_id in enumerate(predict_data.index): key (sample_id, target) predictions[key] y_pred_original[idx] # 将预测结果整合回原数据框 for (sample_id, target), pred_val in predictions.items(): df.loc[sample_id, f预测原始_{target}] pred_val # 查看部分预测结果 cols_to_show [文物编号, 玻璃类型, 风化状态, K2O, Na2O, 预测原始_K2O, 预测原始_Na2O] if 预测原始_K2O in df.columns: print(df[cols_to_show].head(10))7.2 结果分析与合理性评估得到预测值后必须进行严格的合理性检查化学合理性预测的原始含量是否在合理的范围内例如K2O的预测值是否显著高于当前风化后的值因为风化会流失是否可能出现负值模型可能产生但化学上不可能统计合理性预测的原始成分分布是否与同类型未风化样本的分布相似可以通过比较预测值的均值、方差与未风化组实际值的均值、方差来评估。模型评估回归模型的R^2值有多高如果很低说明当前选择的稳定成分不足以很好地预测易风化成分模型可信度低。可能需要引入更多先验知识或采用更复杂的模型如考虑交互项的非线性模型但也要警惕过拟合。# 合理性评估示例比较预测的原始K2O与未风化组实际K2O for glass_type in df[玻璃类型].unique(): type_data df[df[玻璃类型] glass_type] unweathered_actual type_data[type_data[风化状态]未风化][K2O] weathered_pred type_data[type_data[风化状态]风化][预测原始_K2O] if not unweathered_actual.empty and not weathered_pred.empty: print(f\n玻璃类型: {glass_type}) print(f 未风化组实际 K2O 均值: {unweathered_actual.mean():.3f}%) print(f 风化组预测原始 K2O 均值: {weathered_pred.mean():.3f}%) print(f 风化组当前 K2O 均值: {type_data[type_data[风化状态]风化][K2O].mean():.3f}%) # 理想情况下预测原始均值应接近未风化实际均值且大于风化当前均值。如果预测结果不合理我们需要回到模型假设也许风化过程并非只影响少数成分或者不同风化程度的影响是非线性的。这时在论文中坦诚地讨论模型的局限性并提出改进思路如引入风化程度指标、使用物理化学模型约束等同样是高质量答卷的重要组成部分。踩坑提醒第四问的预测极具挑战性几乎没有完美解。在数学建模竞赛中清晰合理的建模思路、严谨的求解过程、对结果的批判性讨论比追求一个看似精确但脆弱的预测值更重要。务必在论文中详细说明你的假设、模型构建过程、结果及其解释并讨论不确定性。8. 代码整合、优化与论文写作建议将上述分散的步骤整合成一个连贯的、可执行的Python脚本或Jupyter Notebook是项目复现的关键。同时为了将分析结果转化为一篇优秀的数学建模论文还需要注意以下几点8.1 代码结构与可复现性一个良好的代码结构应该包括导入包与配置所有import语句放在开头设置随机种子保证结果可复现。数据加载与预处理函数将数据清洗、缺失值处理、特征工程等步骤封装成函数或清晰独立的代码块。分析模块对应四个问题建立四个独立的分析函数或代码段每个模块输出关键结果、图表和中间数据。结果保存将重要的结果如分类预测表、成分预测表、统计检验结果保存为CSV或Excel文件将生成的图表保存为图片。主程序流程按顺序调用各个模块并添加必要的注释。# 示例主程序框架 def main(): # 1. 数据准备 df load_and_clean_data(glass_data.csv) df preprocess_data(df) # 2. 问题一分析 print(正在进行成分关联与规律分析...) analyze_composition_correlation(df) perform_pca_analysis(df) # 3. 问题二分析 print(\n正在进行玻璃类型鉴别...) classification_model, feature_imp train_type_classifier(df) predict_unknown_samples(df, classification_model) # 4. 问题三分析 print(\n正在进行风化效应分析...) weathering_effect_analysis(df) # 5. 问题四分析 print(\n正在进行风化前成分预测...) predict_pre_weathering_composition(df) print(\n所有分析完成) if __name__ __main__: main()8.2 论文写作核心要点数学建模论文看重的是模型、结果和洞察代码是支撑。在论文中问题重述与分析用你自己的话精炼概括问题并阐述解题的整体思路和流程图。模型建立对每个问题明确写出所使用的数学模型如PCA的数学表达、逻辑回归方程、T检验的假设等。即使使用了sklearn这样的高级库也要说明背后的数学原理。求解过程简要说明你是如何用软件Python求解模型的列出关键步骤和参数选择依据。结果展示与分析这是论文的核心。图表要精美、自明有清晰的标题、坐标轴标签、图例。对每一个图表都要配以详细的文字分析解释你从图中看到了什么规律这个规律说明了什么。例如“图3显示PCA的前两个主成分能够解释78%的方差并且在PC1-PC2平面上高钾玻璃和铅钡玻璃呈现出明显的分离趋势其中PC1主要与PbO和BaO含量高度相关这表明铅钡含量是区分两类玻璃的最主要因素。”模型检验与灵敏度分析讨论模型的稳健性。例如分类模型用了交叉验证准确率回归模型用了R^2和残差分析改变PCA的主成分数量观察结论是否稳定。优缺点与推广客观评价你模型的优点和局限性并提出可能的改进方向。将模型推广到更一般的文物成分分析或材料风化研究场景。8.3 常见问题与排查技巧在实现过程中你可能会遇到以下问题数据读取错误检查文件路径、编码格式encodingutf-8或gbk以及分隔符。使用pd.read_csv的error_bad_linesFalse参数跳过格式错误的行。缺失值处理导致后续计算报错确保在计算相关性、进行PCA或模型训练前已经妥善处理了所有缺失值。使用.fillna()或.dropna()时要小心避免误删重要样本。PCA结果解读困难主成分是原始变量的线性组合没有直接的物理意义。重点看载荷矩阵绝对值大的变量对该主成分贡献大。可以将主成分得分与原始变量做散点图矩阵帮助理解。分类模型准确率低检查特征是否相关性强但与标签无关尝试特征选择。检查数据是否极度不平衡使用class_weightbalanced参数或过采样/欠采样技术。尝试不同的分类器并调参如SVM的C和gamma随机森林的n_estimators和max_depth。回归预测结果出现负值或极端值这是风化预测中常见的问题。可以尝试对目标变量进行变换如对数变换。使用能约束输出范围的模型如岭回归、套索回归。在论文中将其作为模型局限性提出并给出化学上合理的修正如将负值截断为0。可视化图表混乱控制图形尺寸figsize。使用清晰的颜色映射cmap如viridis,plasma。添加足够的标签、标题和图例。使用plt.tight_layout()自动调整子图间距。通过以上从数据到模型从代码到论文的完整梳理相信你已经对如何攻克“古代玻璃制品的成分分析与鉴别”这类综合性数学建模问题有了清晰的认识。记住核心在于理解问题本质、设计合理的分析流程、熟练运用Python工具进行实现并能将你的工作和思考清晰、严谨地呈现出来。这不仅是解决一道赛题的过程更是一次完整的数据科学项目实战演练。
返回列表