前言
简单介绍一下我自己:博主专注建模四年,参与过大大小小数十来次数学建模,理解各类模型原理以及每种模型的建模流程和各类题目分析方法。参与过十余次数学建模大赛,三次美赛获得过二次M奖一次H奖,国赛二等奖。**提供免费的思路和部分源码,以后的数模比赛只要我还有时间肯定会第一时间写出免费开源思路。**博主紧跟各类数模比赛,每场数模竞赛博主都会将最新的思路和代码写进此专栏以及详细思路和完全代码且完全免费。希望有需求的小伙伴不要错过笔者精心打造的文章。
数学建模的基本步骤大致如下:
- 问题定义:明确你需要解决的问题。这包括对问题的背景进行研究,理解问题的实际意义,以及确定问题的边界条件和假设。
- 建立数学模型:将实际问题转换为数学问题。这通常涉及到定义变量、参数、约束条件以及目标函数(如果是优化问题的话)。
- 求解数学模型:选择合适的数学工具和方法求解模型。这可能包括解析方法、数值方法、仿真等。
- 模型验证与分析:使用实际数据测试模型的有效性,分析模型结果,对模型进行必要的调整和优化。
- 撰写模型报告:详细记录模型的建立过程、求解步骤、结果分析以及模型的局限性等。
本篇文章上接第三问分类,前面两问都有单独的文章进行讲解,大家直接可以进我专栏搜索2022C题即可看到源码以及详细的建模过程,本篇文章主要详解第三问的分类模型建模,对第三张表的未知数据分类。
问题 3
对附件表单 3 中未知类别玻璃文物的化学成分进行分析,鉴别其所属类型,并对分类结果的敏感性进行分析。问题三就是一个比较简单的分类算法了,到了这一步就相当好做了,因为我们有第一二问的基础,根据对应的数据可以很好的构造分类模型,首先我们还是根据建模步骤来一步步完成第三问分类模型的建模
数据预览
那么我们根据风化和无风化把他们分开:
同时我们需要根据之前分类的风化数据和无风化数据提取特征列和标签列,进行训练,这些数据确实太适合应用KNN算法了,我这里就直接采用KNN算法来进行分类预测,我其实认为K为1的时候会比较适合,因为微量元素的欺负不会很大,但是对于颜色来说就十分难以分类了,因为关于颜色的数据实在是过少,后续需要进行数据均衡,但是前两个标签纹饰和类型就很好分类了,而且准确率都挺高的。
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.multioutput import MultiOutputClassifier
from sklearn.metrics import classification_report
# 分离特征和标签
X = df_fenhua.iloc[:,list(range(1, 15))]
y = df_fenhua.iloc[:,list(range(18, 21))]
# 标签列(纹饰、类型、颜色)
label_columns = ['纹饰', '类型', '颜色']
# 拆分训练集和测试集(用于模型验证)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 使用KNN分类器
knn_model = KNeighborsClassifier(n_neighbors=1)
# 使用MultiOutputClassifier来处理多输出问题
multi_target_knn = MultiOutputClassifier(knn_model, n_jobs=-1)
# 训练模型
multi_target_knn.fit(X_train, y_train)
# 在测试集上进行预测
y_pred = multi_target_knn.predict(X_test)
# 输出分类结果报告
for i, label in enumerate(label_columns):
print(f"Classification Report for {label}:")
print(classification_report(y_test.iloc[:, i], y_pred[:, i]))
Classification Report for 纹饰:
precision recall f1-score support
A 0.00 0.00 0.00 1
B 1.00 1.00 1.00 1
C 0.80 0.80 0.80 5
accuracy 0.71 7
macro avg 0.60 0.60 0.60 7
weighted avg 0.71 0.71 0.71 7
Classification Report for 类型:
precision recall f1-score support
铅钡 1.00 1.00 1.00 6
高钾 1.00 1.00 1.00 1
accuracy 1.00 7
macro avg 1.00 1.00 1.00 7
weighted avg 1.00 1.00 1.00 7
Classification Report for 颜色:
precision recall f1-score support
浅蓝 0.00 0.00 0.00 2
深绿 0.50 0.50 0.50 2
蓝绿 0.33 0.33 0.33 3
黑 0.00 0.00 0.00 0
accuracy 0.29 7
macro avg 0.21 0.21 0.21 7
weighted avg 0.29 0.29 0.29 7
切换K为3的时候准确率可以更高:
Classification Report for 纹饰:
precision recall f1-score support
A 0.00 0.00 0.00 1
B 1.00 1.00 1.00 1
C 0.83 1.00 0.91 5
accuracy 0.86 7
macro avg 0.61 0.67 0.64 7
weighted avg 0.74 0.86 0.79 7
Classification Report for 类型:
precision recall f1-score support
铅钡 1.00 1.00 1.00 6
高钾 1.00 1.00 1.00 1
accuracy 1.00 7
macro avg 1.00 1.00 1.00 7
weighted avg 1.00 1.00 1.00 7
Classification Report for 颜色:
precision recall f1-score support
浅绿 0.00 0.00 0.00 0
浅蓝 0.25 0.50 0.33 2
深绿 1.00 0.50 0.67 2
蓝绿 1.00 0.33 0.50 3
accuracy 0.43 7
macro avg 0.56 0.33 0.38 7
weighted avg 0.79 0.43 0.50 7
对于颜色来说我们需要另外选择其他的模型,我们可以通过数据可视化来看看颜色的分布:
我们可以清晰的看到数据几乎是十分不均衡的,浅绿颜色仅仅只有一条,检查类别样本数量并移除少量样本类别:
from collections import Counter
from imblearn.over_sampling import SMOTE
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import classification_report
# 分离特征和标签
X = df_fenhua.iloc[:, list(range(1, 15))]
y = df_fenhua['颜色']
# 检查每个类别的样本数量
counter = Counter(y)
print(counter)
# 移除样本数少于2的类别
to_remove = [k for k, v in counter.items() if v < 2]
X_filtered = X[~y.isin(to_remove)]
y_filtered = y[~y.isin(to_remove)]
# 再次检查过滤后的类别分布
counter_filtered = Counter(y_filtered)
print(counter_filtered)
# 拆分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_filtered, y_filtered, test_size=0.2, random_state=42)
# 使用SMOTE进行过采样,调整k_neighbors为1
smote = SMOTE(random_state=42, k_neighbors=1)
X_train_resampled, y_train_resampled = smote.fit_resample(X_train, y_train)
# 使用KNN分类器
knn_model = KNeighborsClassifier(n_neighbors=3)
# 训练KNN模型
knn_model.fit(X_train_resampled, y_train_resampled)
# 在测试集上进行预测
y_pred = knn_model.predict(X_test)
# 输出分类结果报告
print(f"Classification Report for 颜色:")
print(classification_report(y_test, y_pred))
Counter({'浅蓝': 10, '蓝绿': 9, '深绿': 5, '紫': 4, '黑': 3, '浅绿': 1})
Counter({'浅蓝': 10, '蓝绿': 9, '深绿': 5, '紫': 4, '黑': 3})
KNeighborsClassifier(n_neighbors=3)
Classification Report for 颜色:
precision recall f1-score support
浅蓝 0.50 0.67 0.57 3
深绿 1.00 0.50 0.67 2
蓝绿 1.00 0.50 0.67 2
黑 0.00 0.00 0.00 0
accuracy 0.57 7
macro avg 0.62 0.42 0.48 7
weighted avg 0.79 0.57 0.63 7
多标签能到达这个准确率还行。
最后得到预测结果,无风化数据也是一样的,重复次过程即可。