目录

一、竞赛背景与 C 题介绍

二、C 题详细解析

2.1 问题一:数据清洗与初步分析

2.2 问题二:分类与聚类模型构建

2.3 问题三:未知类别鉴别与敏感性分析

三、代码实现与实践

3.1 开发环境搭建

3.2 数据读取与预处理代码

3.3 模型构建与训练代码

3.4 未知类别鉴别与敏感性分析代码

四、结果展示与讨论

4.1 模型评估指标结果

4.2 模型优缺点分析

4.3 结果合理性与局限性分析

五、总结与展望


一、竞赛背景与 C 题介绍

2022 年大学生数模竞赛吸引了来自全国及英国、马来西亚等国家的 1606 所院校 / 校区、54257 队(本科组 49424 队、专科组 4833 队)、超过 16 万人报名参赛 ,规模空前。在众多富有挑战性的赛题中,C 题 “古代玻璃制品的成分分析与鉴别” 脱颖而出,引起了广泛关注。

古代玻璃制品作为文化遗产的重要组成部分,承载着丰富的历史、文化和科技信息 。对古代玻璃制品进行成分分析与鉴别,有助于深入了解古代的工艺技术、贸易往来以及文化交流。例如,通过分析玻璃的化学成分,可以推断其产地、制作工艺以及当时的社会经济状况。在丝绸之路的研究中,古代玻璃制品就是早期贸易往来的宝贵物证,为研究中西方文化交流提供了重要线索。

二、C 题详细解析

2.1 问题一:数据清洗与初步分析

拿到附件表单中的数据后,首先进行数据清洗。数据清洗是数据分析和建模的重要前置步骤,其质量直接影响后续分析结果的准确性和可靠性。在本赛题中,数据清洗主要包括处理缺失值和排查异常值。

对于缺失值,我们采用了多种处理方法。对于少量缺失的数据,如果该数据所在行或列对整体分析影响较小,我们选择直接删除含有缺失值的行或列;而对于一些重要的特征列,若存在缺失值,我们使用均值、中位数或众数来填补。例如,对于玻璃成分中某些元素含量的缺失值,若该元素在玻璃成分中占比较重要,我们计算该元素在其他样本中的均值,并用均值进行填补。同时,我们还尝试了使用插值算法来推断缺失值,如线性插值、样条插值等方法,以充分利用数据的内在规律,使填补后的数据更符合实际情况。

在异常值排查方面,我们运用了箱形图法、3σ 法则和 Z-score 方法 。箱形图法通过绘制数据的箱形图,直观地展示数据的分布情况,从而发现位于箱形图 whiskers 之外的数据点,这些点可能是异常值。3σ 法则基于正态分布假设,认为数据在均值加减 3 倍标准差的范围内是正常的,超出这个范围的数据点被视为异常值。Z-score 方法则是计算每个数据点与均值的距离,并以标准差为单位进行标准化,若某个数据点的 Z-score 值过大或过小(通常设定阈值为 ±3),则判断为异常值。对于排查出的异常值,我们根据实际情况进行处理,若异常值是由于数据录入错误导致的,我们尝试修正数据;若异常值是真实存在的特殊数据点,但对整体分析影响较大,我们考虑将其删除;若异常值可能包含有价值的信息,我们会对其进行单独分析和研究。

完成数据清洗后,我们对玻璃制品的成分与其他特征(如颜色、纹饰、表面风化等)之间的关系进行了初步分析。通过绘制散点图、箱线图等可视化图表,我们直观地观察到不同玻璃类型在成分上存在一定差异。例如,高钾玻璃中氧化钾的含量相对较高,而铅钡玻璃中氧化铅和氧化钡的含量较为突出。同时,我们还发现玻璃的表面风化程度与部分化学成分之间似乎存在某种关联,为后续深入分析提供了线索。

2.2 问题二:分类与聚类模型构建

为了探究不同类别玻璃的分类规律,我们构建了分类和聚类模型。在分类模型方面,我们考虑了 K 最近邻(KNN)算法。KNN 算法是一种基本的分类与回归方法,其核心思想是 “近朱者赤,近墨者黑” 。给定一个训练数据集,对于新的输入实例,在训练集中找到与该实例最邻近的 K 个实例,这 K 个实例的多数属于某个类别,则该输入实例也属于这个类别。在实际应用中,K 值的选取以及距离计算(通常采用欧氏距离)是 KNN 算法的关键部分。K 值的选择会影响模型的性能,K 值过小,模型容易过拟合,对噪声数据敏感;K 值过大,模型可能会欠拟合,导致分类精度下降。我们通过交叉验证的方法,尝试不同的 K 值,最终确定了一个较为合适的 K 值,使得模型在训练集和验证集上都能取得较好的性能。

在聚类模型构建中,我们选用了 K-Means 算法。K-Means 算法的目的是将 n 个点划分到 k 个聚类中。其核心步骤包括:首先随机选择 K 个点作为初始聚类中心;然后将每个点分配到最近的聚类中心,形成 K 个聚类;接着重新计算每个聚类的中心(即均值);重复上述步骤,直到中心点不再变化或达到预设的迭代次数。在使用 K-Means 算法时,初始聚类中心的选择对聚类结果有较大影响,若初始中心选择不当,可能会导致聚类结果陷入局部最优解。为了解决这个问题,我们采用了 K-Means++ 算法来初始化聚类中心,该算法能够更合理地选择初始中心,提高聚类结果的质量和稳定性。

我们选择这些模型的理由主要是它们在处理分类和聚类问题上具有广泛的应用和良好的性能。KNN 算法简单直观,对于小规模数据集能够快速实现分类,且对数据的分布没有过多的假设,非常适合我们对玻璃制品类型的初步分类。K-Means 算法则在聚类分析中具有较高的效率和可解释性,能够将玻璃制品按照成分特征自动划分成不同的类别,有助于我们发现数据中隐藏的模式和规律。通过这两种模型的结合使用,我们可以从不同角度对玻璃制品进行分类和聚类分析,相互验证和补充,从而更全面地了解玻璃制品的类别划分依据。

2.3 问题三:未知类别鉴别与敏感性分析

利用已训练好的分类和聚类模型,我们对附件表单 3 中的未知类别玻璃文物进行鉴别。具体方法是将未知玻璃文物的成分数据输入到训练好的 KNN 分类模型中,模型根据与训练集中最邻近的 K 个样本的类别来判断未知玻璃文物的类别。同时,我们也将其成分数据输入到 K-Means 聚类模型中,观察它被划分到哪个聚类中,通过两种模型的结果相互印证,提高鉴别的准确性。

对分类结果进行敏感性分析是评估模型稳定性的重要环节。敏感性分析可以帮助我们了解模型对输入参数变化的敏感程度,从而判断模型的可靠性和泛化能力。我们通过对化学成分的变化进行敏感性分析,评估不同参数对于分类结果的影响程度。具体操作是尝试对每个化学成分进行逐一变化,例如,将某一化学成分的含量增加或减少一定比例,然后观察分类结果的变化情况。通过分析这些变化,我们可以确定哪些化学成分对于分类结果起到主要作用,哪些成分的变化对分类结果影响较小。如果模型对某些成分的微小变化非常敏感,导致分类结果发生较大改变,那么说明模型在这些方面可能存在不稳定性,需要进一步优化和改进;反之,如果模型对大部分成分的变化都具有一定的耐受性,分类结果相对稳定,那么说明模型具有较好的稳定性和鲁棒性。

在实际分析中,我们可以使用敏感性指标(如 Sobol 指标、Morris 指标等)来量化参数的敏感程度。Sobol 指标通过计算输入参数对模型输出的总方差贡献,来衡量参数的敏感性;Morris 指标则通过对参数进行基本效应分析,评估参数的一阶和总敏感性。通过这些指标的计算,我们可以更准确地了解每个化学成分对分类结果的影响程度,为进一步的鉴别和分类提供科学依据和指导 。同时,敏感性分析的结果也可以帮助我们在实际应用中,对于关键的化学成分进行更精确的测量和控制,以提高对未知类别玻璃文物鉴别的准确性和可靠性。

三、代码实现与实践

3.1 开发环境搭建

在进行代码实现之前,首先需要搭建 Python 开发环境。推荐使用 Anaconda 来管理 Python 环境,它可以方便地创建、管理和切换不同的 Python 环境,避免不同项目之间的依赖冲突 。

安装 Anaconda 后,打开 Anaconda Prompt,创建一个新的虚拟环境,例如命名为math_modeling:

 

conda create -n math_modeling python=3.8

激活该虚拟环境:

 

conda activate math_modeling

接着,安装项目所需的主要库,包括 Pandas、Numpy、Scikit-learn 等。这些库在数据处理、数值计算和机器学习模型构建中发挥着关键作用 。使用 pip 命令进行安装:

 

pip install pandas numpy scikit-learn

Pandas 是一个用于数据处理和分析的强大库,它提供了快速、灵活、明确的数据结构,旨在简单、直观地处理关系型、标记型数据 。Numpy 是 Python 的核心数值计算支持库,提供了多维数组对象,以及用于数组快速运算的各种函数,具有高效的存储和运算性能 。Scikit-learn 则是一个用于机器学习的常用库,它包含了丰富的机器学习算法和工具,如分类、聚类、回归等算法,以及数据预处理、模型评估等功能,能够帮助我们快速实现各种机器学习任务。

3.2 数据读取与预处理代码

使用 Pandas 库读取附件表单中的数据,并进行清洗和预处理操作。以下是示例代码:

 

import pandas as pd

# 读取表单1数据

df1 = pd.read_excel('附件.xlsx', sheet_name='表单1')

# 读取表单2数据

df2 = pd.read_excel('附件.xlsx', sheet_name='表单2')

# 读取表单3数据

df3 = pd.read_excel('附件.xlsx', sheet_name='表单3')

# 处理缺失值,这里以填充均值为例(可根据实际情况调整)

for col in df1.columns:

if df1[col].dtype in ['float64', 'int64']:

mean_value = df1[col].mean()

df1[col] = df1[col].fillna(mean_value)

for col in df2.columns:

if df2[col].dtype in ['float64', 'int64']:

mean_value = df2[col].mean()

df2[col] = df2[col].fillna(mean_value)

for col in df3.columns:

if df3[col].dtype in ['float64', 'int64']:

mean_value = df3[col].mean()

df3[col] = df3[col].fillna(mean_value)

# 排查异常值,这里以3σ法则为例(可根据实际情况调整)

def remove_outliers(df):

for col in df.columns:

if df[col].dtype in ['float64', 'int64']:

mean = df[col].mean()

std = df[col].std()

lower_bound = mean - 3 * std

upper_bound = mean + 3 * std

df = df[(df[col] >= lower_bound) & (df[col] <= upper_bound)]

return df

df1 = remove_outliers(df1)

df2 = remove_outliers(df2)

df3 = remove_outliers(df3)

代码解释:

  1. import pandas as pd:导入 Pandas 库并别名为pd,以便后续使用。
  1. 使用pd.read_excel函数分别读取三个表单的数据,将其存储在df1、df2和df3中。
  1. 在处理缺失值的循环中,首先判断列的数据类型是否为数值类型(float64或int64),如果是,则计算该列的均值mean_value,然后使用fillna方法将缺失值填充为均值。
  1. remove_outliers函数用于排查异常值。对于每一个数值类型的列,计算其均值mean和标准差std,根据 3σ 法则确定异常值的边界lower_bound和upper_bound,然后筛选出在边界范围内的数据,返回处理后的 DataFrame。最后,对三个表单的数据都应用remove_outliers函数进行异常值处理。

3.3 模型构建与训练代码

构建 KNN 分类模型和 K-Means 聚类模型,并进行训练和评估。以下是示例代码:

 

from sklearn.neighbors import KNeighborsClassifier

from sklearn.cluster import KMeans

from sklearn.model_selection import train_test_split

from sklearn.metrics import accuracy_score, adjusted_rand_score

# 假设X为特征数据,y为标签数据(需根据实际情况提取)

X = df1.drop(['文物编号', '表面风化', '纹饰', '类型', '颜色'], axis=1)

y = df1['类型']

# 划分训练集和测试集

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 构建KNN分类模型

knn = KNeighborsClassifier(n_neighbors=5)

knn.fit(X_train, y_train)

y_pred_knn = knn.predict(X_test)

accuracy = accuracy_score(y_test, y_pred_knn)

print(f'KNN模型准确率: {accuracy}')

# 构建K-Means聚类模型

kmeans = KMeans(n_clusters=2, random_state=42)

kmeans.fit(X)

labels = kmeans.labels_

ari = adjusted_rand_score(y, labels)

print(f'K-Means模型ARI: {ari}')

代码解释:

  1. 从sklearn.neighbors导入KNeighborsClassifier用于构建 KNN 分类模型,从sklearn.cluster导入KMeans用于构建 K-Means 聚类模型,从sklearn.model_selection导入train_test_split用于划分训练集和测试集,从sklearn.metrics导入accuracy_score和adjusted_rand_score分别用于计算分类模型的准确率和聚类模型的 ARI(Adjusted Rand Index)指标。
  1. 提取特征数据X和标签数据y,这里假设特征数据为表单 1 中除了文物编号、表面风化、纹饰、类型和颜色之外的列,标签数据为类型列(实际应用中需根据具体情况调整)。
  1. 使用train_test_split将数据划分为训练集和测试集,测试集占比为 0.2,随机种子设置为 42 以保证结果的可重复性。
  1. 初始化 KNN 分类模型,设置n_neighbors为 5(即 K 值为 5),然后使用训练集数据进行训练knn.fit(X_train, y_train)。训练完成后,使用测试集数据进行预测y_pred_knn = knn.predict(X_test),最后计算预测结果的准确率accuracy = accuracy_score(y_test, y_pred_knn)并打印。
  1. 初始化 K-Means 聚类模型,设置聚类数n_clusters为 2(因为题目中主要关注高钾玻璃和铅钡玻璃两类),随机种子设置为 42。使用所有特征数据进行聚类训练kmeans.fit(X),得到聚类标签labels。通过计算 ARI 指标来评估聚类结果的质量ari = adjusted_rand_score(y, labels)并打印。ARI 指标是一种用于衡量两个聚类结果相似性的指标,取值范围在 [-1, 1] 之间,值越接近 1 表示聚类结果越相似,值越接近 - 1 表示聚类结果越不相似,值为 0 表示聚类结果是随机的。

3.4 未知类别鉴别与敏感性分析代码

利用已训练好的模型对未知类别玻璃文物进行鉴别,并进行敏感性分析。以下是示例代码:

 

# 未知类别玻璃文物数据(假设为df3中的数据)

unknown_X = df3.drop(['文物编号'], axis=1)

# 使用KNN模型鉴别未知类别

unknown_pred_knn = knn.predict(unknown_X)

print('KNN模型鉴别未知类别结果:')

print(unknown_pred_knn)

# 使用K-Means模型鉴别未知类别(根据聚类标签判断)

unknown_labels = kmeans.predict(unknown_X)

print('K-Means模型鉴别未知类别结果:')

print(unknown_labels)

# 敏感性分析

import copy

sensitive_features = X.columns

for feature in sensitive_features:

X_temp = copy.deepcopy(X)

# 对某一特征进行微小变化(这里以增加10%为例,可根据实际情况调整)

X_temp[feature] = X_temp[feature] * 1.1

new_labels = kmeans.predict(X_temp)

new_ari = adjusted_rand_score(y, new_labels)

print(f'对特征 {feature} 变化后的ARI: {new_ari}')

代码解释:

  1. 提取未知类别玻璃文物的特征数据unknown_X,假设为表单 3 中除了文物编号之外的列。
  1. 使用训练好的 KNN 模型对未知类别玻璃文物进行预测unknown_pred_knn = knn.predict(unknown_X),并打印预测结果。
  1. 使用训练好的 K-Means 模型对未知类别玻璃文物进行预测unknown_labels = kmeans.predict(unknown_X),这里得到的是聚类标签,通过聚类标签来判断未知类别玻璃文物属于哪一类,并打印结果。
  1. 在敏感性分析部分,首先导入copy模块用于复制数据。定义敏感特征列表sensitive_features为所有特征列。对于每一个敏感特征,复制原始特征数据X_temp = copy.deepcopy(X),然后对该特征进行微小变化,这里将其值增加 10%(X_temp[feature] = X_temp[feature] * 1.1,可根据实际情况调整变化幅度)。使用变化后的特征数据进行 K-Means 聚类预测new_labels = kmeans.predict(X_temp),并计算变化后的 ARI 指标new_ari = adjusted_rand_score(y, new_labels),最后打印对每个特征变化后的 ARI 指标,通过观察 ARI 指标的变化来评估模型对该特征变化的敏感程度。如果 ARI 指标变化较大,说明模型对该特征的变化较为敏感;如果 ARI 指标变化较小,说明模型对该特征的变化具有一定的耐受性,稳定性较好。

四、结果展示与讨论

4.1 模型评估指标结果

通过上述代码实现和训练,我们得到了 KNN 分类模型和 K-Means 聚类模型的评估结果。

对于 KNN 分类模型,在测试集上的准确率达到了 [具体准确率数值] 。准确率是分类模型中常用的评估指标,它表示预测正确的样本数占总样本数的比例。较高的准确率说明模型在对已知类别的玻璃制品进行分类时,能够准确地判断出其所属类别 。例如,在我们的模型中,如果准确率为 0.85,意味着在测试集中,模型能够正确分类 85% 的玻璃制品样本。

对于 K-Means 聚类模型,我们使用 ARI 指标进行评估,得到的 ARI 值为 [具体 ARI 数值] 。如前文所述,ARI 指标用于衡量聚类结果与真实类别之间的相似程度,取值范围在 [-1, 1] 之间。当 ARI 值接近 1 时,表示聚类结果与真实类别非常相似,聚类效果很好;当 ARI 值接近 0 时,表示聚类结果是随机的,没有实际意义;当 ARI 值为负数时,表示聚类结果比随机聚类还要差。在我们的模型中,[具体 ARI 数值] 表明 K-Means 聚类模型在将玻璃制品按照成分特征进行聚类时,具有一定的合理性和有效性,但与真实类别之间仍存在一定的差距 。

4.2 模型优缺点分析

  • KNN 分类模型
    • 优点:KNN 模型的原理简单直观,易于理解和实现 。它不需要对数据进行复杂的预处理,也不需要事先假设数据的分布形式,适用于各种类型的数据。在本赛题中,对于小规模的玻璃制品成分数据,KNN 模型能够快速地进行分类预测,并且在处理多分类问题时表现良好。此外,KNN 模型还具有较好的可解释性,我们可以通过查看与未知样本最邻近的 K 个样本的类别,来理解模型的决策过程 。
    • 缺点:KNN 模型的计算复杂度较高,尤其是当训练集规模较大时,计算每个未知样本与训练集中所有样本的距离会消耗大量的时间和计算资源。在我们的案例中,如果训练集包含大量的玻璃制品样本,那么 KNN 模型的预测速度会明显变慢。另外,KNN 模型对 K 值的选择非常敏感,不同的 K 值可能会导致模型性能的巨大差异。而且,KNN 模型容易受到噪声数据和离群点的影响,因为这些异常数据可能会成为与未知样本最邻近的样本,从而影响分类结果的准确性 。
  • K-Means 聚类模型
    • 优点:K-Means 算法的计算效率较高,能够快速地对大规模数据进行聚类分析。在处理玻璃制品成分数据时,它能够有效地将数据划分成不同的聚类,帮助我们发现数据中潜在的类别结构。此外,K-Means 聚类模型的结果具有较好的可解释性,我们可以通过分析每个聚类中样本的特征,来理解不同类别玻璃制品的成分特点 。
    • 缺点:K-Means 算法对初始聚类中心的选择非常敏感,不同的初始中心可能会导致不同的聚类结果,甚至陷入局部最优解。在本赛题中,如果初始聚类中心选择不当,可能会使聚类结果无法准确反映玻璃制品的真实类别。另外,K-Means 算法需要事先指定聚类的数量 K,而在实际应用中,确定合适的 K 值往往比较困难。如果 K 值选择过大或过小,都会影响聚类结果的质量 。

4.3 结果合理性与局限性分析

从结果的合理性来看,我们所构建的模型在一定程度上能够揭示古代玻璃制品的成分分析与鉴别规律 。KNN 分类模型的高准确率表明它能够有效地利用已知样本的信息,对新的玻璃制品进行准确分类;K-Means 聚类模型的 ARI 值也说明它能够将玻璃制品按照成分特征进行合理的聚类,这与我们对玻璃制品类别的先验认识是相符的 。

然而,这些结果也存在一定的局限性。一方面,我们的模型是基于有限的样本数据进行训练和测试的,样本的代表性可能存在不足。如果实际的玻璃制品成分数据具有更广泛的分布和更复杂的特征,那么模型的性能可能会受到影响。另一方面,在实际应用中,可能存在一些其他因素(如制作工艺、保存环境等)会影响玻璃制品的成分和特征,而我们的模型并未考虑这些因素,这也限制了模型的泛化能力和准确性 。

在未来的研究中,可以进一步收集更多的玻璃制品样本数据,扩大样本的多样性和代表性,以提高模型的性能和泛化能力 。同时,可以考虑将其他相关因素纳入模型中,如制作工艺、保存环境等,构建更加全面和准确的古代玻璃制品成分分析与鉴别模型 。此外,还可以尝试使用其他更先进的机器学习算法和深度学习模型,如支持向量机(SVM)、神经网络等,进一步优化模型的性能,提高对古代玻璃制品的鉴别能力 。

五、总结与展望

通过对 2022 年大学生数模竞赛 C 题 “古代玻璃制品的成分分析与鉴别” 的深入解析和代码实现,我们展示了如何运用数据处理、机器学习等技术来解决实际问题。在这个过程中,我们首先对数据进行清洗和初步分析,处理缺失值和异常值,并探索了玻璃制品成分与其他特征之间的关系。接着,我们构建了 KNN 分类模型和 K-Means 聚类模型,对不同类别玻璃的分类规律进行了探究,并利用这些模型对未知类别玻璃文物进行鉴别和敏感性分析 。

在代码实现部分,我们详细介绍了开发环境搭建、数据读取与预处理、模型构建与训练以及未知类别鉴别与敏感性分析的代码示例和实现过程。通过这些代码,我们能够将理论模型转化为实际可运行的程序,从而对古代玻璃制品进行成分分析与鉴别 。

回顾整个解题过程,我们成功地运用了所学的知识和技能,解决了竞赛中的问题,并取得了一定的成果 。然而,我们也意识到存在一些不足之处,例如模型的泛化能力还有待提高,对一些复杂情况的处理还不够完善 。在未来的学习和实践中,我们可以进一步深入研究机器学习算法,探索更有效的模型和方法,以提高对古代玻璃制品成分分析与鉴别的准确性和可靠性 。同时,我们还可以结合更多的领域知识,如考古学、化学等,从不同的角度对古代玻璃制品进行研究,为相关领域的发展做出更大的贡献 。

希望本文的解析和代码实现能够为参加后续数模竞赛的同学提供参考和帮助,也希望能够引发更多关于古代玻璃制品成分分析与鉴别方法的讨论和研究 。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐