机器学习案例——预测矿物类型(模型训练)

模型训练类完整实现

1. 类初始化 (__init__)

python 复制代码
def __init__(self, model='mode'):
    """
    模型训练类初始化
    
    参数:
    model -- 模型/数据集名称,对应数据文件名前缀
    
    属性:
    train_x -- 训练集特征 (pd.DataFrame)
    train_y -- 训练集标签 (pd.Series)
    test_x -- 测试集特征 (pd.DataFrame) 
    test_y -- 测试集标签 (pd.Series)
    result -- 存储各模型评估结果的字典
    """
    self.model = model  # 模型/数据集名称
    self.train_x = None  # 训练集特征
    self.train_y = None  # 训练集标签
    self.test_x = None  # 测试集特征
    self.test_y = None  # 测试集标签
    self.result = {}  # 存储各模型评估结果
    self.extract_data()  # 调用数据加载方法

2. 数据加载 (extract_data)

python 复制代码
def extract_data(self):
    """
    从Excel文件加载训练集和测试集数据
    
    文件路径格式:
    - 训练集: '数据/{model}[训练集].xlsx'
    - 测试集: '数据/{model}[测试集].xlsx'
    
    数据格式要求:
    - 最后一列为标签列
    - 其他列为特征列
    
    异常处理:
    - 文件不存在时抛出ValueError
    """
    try:
        # 加载训练集
        train_data = pd.read_excel(f'数据/{self.model}[训练集].xlsx')
        self.train_x = train_data.iloc[:, :-1]  # 除最后一列外所有列作为特征
        self.train_y = train_data.iloc[:, -1]   # 最后一列作为标签
        
        # 加载测试集
        test_data = pd.read_excel(f'数据/{self.model}[测试集].xlsx')
        self.test_x = test_data.iloc[:, :-1]    # 除最后一列外所有列作为特征
        self.test_y = test_data.iloc[:, -1]     # 最后一列作为标签
        
    except FileNotFoundError:
        raise ValueError(f"错误: 无法找到{self.model}对应的数据文件")

3. 模型训练方法

3.1 逻辑回归 (logistic_regression)

python 复制代码
def logistic_regression(self):
    """
    逻辑回归模型训练与评估
    
    使用sklearn的LogisticRegression
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - C: 正则化强度的倒数
    - solver: 优化算法
    - max_iter: 最大迭代次数
    - multi_class: 多分类策略
    
    评估指标:
    - 各类别召回率
    - 整体准确率
    """
    param_grid = {
        'C': np.logspace(-2, 3, 9),
        'solver': ['saga','sag','lbfgs','newton-cg'],
        'max_iter': [100,200,500],
        'multi_class': ['ovr','multinomial','multinomial']
    }
    
    # 创建模型
    model = LogisticRegression()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    # 预测与评估
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    # 解析评估报告
    report = report.split()
    lr_result = {
        'recall_0': float(report[6]),   # 类别0召回率
        'recall_1': float(report[11]),  # 类别1召回率
        'recall_2': float(report[16]),  # 类别2召回率
        'recall_3': float(report[21]),  # 类别3召回率
        'acc': float(report[25])        # 整体准确率
    }
    self.result['LR'] = lr_result

3.2 随机森林 (random_forest)

python 复制代码
def random_forest(self):
    """
    随机森林模型训练与评估
    
    使用sklearn的RandomForestClassifier
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - n_estimators: 树的数量
    - max_depth: 树的最大深度
    - min_samples_split: 分裂节点所需最小样本数
    - min_samples_leaf: 叶节点所需最小样本数
    - max_features: 寻找最佳分割时考虑的特征数
    - bootstrap: 是否使用bootstrap采样
    """
    param_grid = {
        'n_estimators': [50, 100],
        'max_depth': [15, 20],
        'min_samples_split': [2,5],
        'min_samples_leaf': [1,2],
        'max_features': ['auto'],
        'bootstrap': [True]
    }
    
    model = RandomForestClassifier()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    rf_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['RF'] = rf_result

3.3 多项式朴素贝叶斯 (multi_naive_bayes)

python 复制代码
def multi_naive_bayes(self):
    """
    多项式朴素贝叶斯模型训练与评估
    
    使用sklearn的MultinomialNB
    处理负值数据: 将所有特征值平移至非负
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - alpha: 平滑参数
    - fit_prior: 是否学习类别先验概率
    """
    # 处理负值数据
    train_x = self.train_x - self.train_x.min()
    test_x = self.test_x - self.test_x.min()
    
    param_grid = {
        'alpha': [0.1, 0.5, 1.0, 2.0],
        'fit_prior': [True, False]
    }
    
    model = MultinomialNB()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(train_x, self.train_y)
    
    y_pred = grid.predict(test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    nb_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['NB'] = nb_result

3.4 XGBoost (xgboost)

python 复制代码
def xgboost(self):
    """
    XGBoost模型训练与评估
    
    使用xgboost的XGBClassifier
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - learning_rate: 学习率
    - n_estimators: 提升迭代次数
    - num_class: 类别数
    - max_depth: 树的最大深度
    - min_child_weight: 子节点所需最小权重和
    - gamma: 分裂所需最小损失函数下降值
    - subsample: 训练样本采样比例
    - colsample_bytree: 特征采样比例
    """
    param_grid = {
        'learning_rate': [0.05],
        'n_estimators': [200],
        'num_class': [5],
        'max_depth': [7],
        'min_child_weight': [1, 3],
        'gamma': [0,0.1],
        'subsample': [0.8, 1.0],
        'colsample_bytree': [0.8, 1.0]
    }
    
    model = XGBClassifier()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    xgb_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['XGB'] = xgb_result

3.5 支持向量机 (svc)

python 复制代码
def svc(self):
    """
    支持向量机模型训练与评估
    
    使用sklearn的SVC
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - C: 惩罚参数
    - kernel: 核函数类型
    - gamma: 核函数系数
    - degree: 多项式核的阶数
    """
    param_grid = {
        'C': [0.1, 1, 10, 100],
        'kernel': ['linear', 'rbf', 'poly'],
        'gamma': ['scale', 'auto', 0.1, 1],
        'degree': [2, 3, 4]
    }
    
    model = SVC()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    svc_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['SVC'] = svc_result

3.6 K近邻 (knn)

python 复制代码
def knn(self):
    """
    K近邻模型训练与评估
    
    使用sklearn的KNeighborsClassifier
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - n_neighbors: 邻居数量
    - weights: 权重计算方式
    - p: 距离度量参数
    """
    param_grid = {
        'n_neighbors': [3, 5, 7, 10],
        'weights': ['uniform', 'distance'],
        'p': [1, 2]
    }
    
    model = KNeighborsClassifier()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    knn_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['KNN'] = knn_result

3.7 决策树 (decisiontree)

python 复制代码
def decisiontree(self):
    """
    决策树模型训练与评估
    
    使用sklearn的DecisionTreeClassifier
    当前版本未设置参数网格
    """
    param_grid = {}
    
    model = DecisionTreeClassifier()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    dt_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['DT'] = dt_result

3.8 AdaBoost (adaboost)

python 复制代码
def adaboost(self):
    """
    AdaBoost模型训练与评估
    
    使用sklearn的AdaBoostClassifier
    通过GridSearchCV进行超参数调优
    
    参数网格:
    - n_estimators: 弱学习器数量
    - learning_rate: 学习率
    - algorithm: 算法实现方式
    """
    param_grid = {
        'n_estimators': [50, 100, 200],
        'learning_rate': [0.01, 0.1, 1.0],
        'algorithm': ['SAMME', 'SAMME.R']
    }
    
    model = AdaBoostClassifier()
    grid = GridSearchCV(model, param_grid, cv=5, scoring='accuracy')
    grid.fit(self.train_x, self.train_y)
    
    y_pred = grid.predict(self.test_x)
    report = metrics.classification_report(self.test_y, y_pred)
    print(report)
    
    report = report.split()
    ab_result = {
        'recall_0': float(report[6]),
        'recall_1': float(report[11]),
        'recall_2': float(report[16]),
        'recall_3': float(report[21]),
        'acc': float(report[25])
    }
    self.result['AdaBoost'] = ab_result

4. 批量训练入口 (train_process)

python 复制代码
def train_process(self, method=''):
    """
    批量训练入口方法
    
    参数:
    method -- 逗号分隔的模型简称字符串
    
    支持的模型简称:
    - lr: 逻辑回归
    - rf: 随机森林
    - nb: 朴素贝叶斯
    - xg: XGBoost
    - svc: 支持向量机
    - knn: K近邻
    - tree: 决策树
    - adaboost: AdaBoost
    
    示例:
    train_process('lr,rf,xg')  # 训练逻辑回归、随机森林和XGBoost
    """
    # 解析输入的方法字符串
    met = [m.strip() for m in method.split(',')]
    
    # 方法映射字典
    method_map = {
        'lr': self.logistic_regression,
        'rf': self.random_forest,
        'nb': self.multi_naive_bayes,
        'xg': self.xgboost,
        'svc': self.svc,
        'knn': self.knn,
        'tree': self.decisiontree,
        'adaboost': self.adaboost,
    }
    
    # 遍历所有指定的方法
    for i in met:
        if i in method_map:
            method_map[i]()  # 调用对应的训练方法
        else:
            print(f"警告:忽略无效方法名 '{i}'")
  • 导入依赖和初始化:
python 复制代码
import json 
from process_data import MakeModel

# 使用json模块保存模型评估结果
# 从process_data模块导入MakeModel类,用于数据预处理和模型训练

模型训练并保存结果

  • 测试不同预处理方法:
python 复制代码
key_list = ['drop','mean','median','mode','line','forest']

# 定义6种不同的缺失值处理方法:
# 'drop' - 直接删除缺失值样本
# 'mean' - 用特征均值填充缺失值
# 'median' - 用特征中位数填充缺失值  
# 'mode' - 用特征众数填充缺失值
# 'line' - 用线性插值填充缺失值
# 'forest' - 用随机森林预测填充缺失值
  • 模型训练和评估:
python 复制代码
mak = MakeModel(key) 
mak.train_process('lr,rf,xg,nb,adaboost')

# 对每种预处理方法(key),训练以下5种机器学习模型:
# 'lr' - 逻辑回归(Logistic Regression)
# 'rf' - 随机森林(Random Forest)
# 'xg' - XGBoost
# 'nb' - 朴素贝叶斯(Naive Bayes)
# 'adaboost' - AdaBoost

# 训练流程包括:
# 1. 数据预处理(根据key指定的方法处理缺失值)
# 2. 特征工程(如标准化、编码等)
# 3. 模型训练
# 4. 交叉验证评估

# 评估结果保存在mak.result字典中,包含各模型的准确率、召回率等指标
  1. 结果保存:
python 复制代码
with open(f'./数据/result.json', 'w', encoding='utf-8') as f:
    json.dump(results, f, ensure_ascii=False, indent=4)

# 将所有预处理方法和模型的评估结果保存为JSON文件:
# - 文件路径为'./数据/result.json'
# - encoding='utf-8'确保支持中文路径和内容
# - ensure_ascii=False保证中文字符正常显示
# - indent=4使输出格式更易读(带缩进)
# - 文件内容包含各预处理方法下各模型的评估指标

可视化结果

python 复制代码
import json
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager

# 设置中文字体(三种方案任选其一)
# 方案1:使用系统自带字体(推荐)
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 微软雅黑,Windows系统默认中文字体
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示为方块的问题

# 方案2:指定具体字体路径(如果方案1无效,比如在Linux系统下)
# font_path = "C:/Windows/Fonts/simhei.ttf"  # 黑体路径示例
# font_prop = font_manager.FontProperties(fname=font_path)
# plt.rcParams['font.family'] = font_prop.get_name()

# 方案3:使用SimHei字体(需确保已安装)
# plt.rcParams['font.sans-serif'] = ['SimHei']  # 适用于所有平台的通用中文字体解决方案

# 加载数据文件
with open('./数据/result.json', 'r', encoding='utf-8') as f:
    data = json.load(f)  # 读取JSON格式的模型评估结果

# 准备数据
models = ['LR', 'rf', 'xb', 'nb', 'adaboost']  # 定义要比较的模型列表:逻辑回归、随机森林、XGBoost、朴素贝叶斯、AdaBoost
fill_methods = list(data.keys())  # 获取所有数据填充方法的名称

# 提取准确率数据
acc_data = {
    model: [data[method][model]['acc'] for method in fill_methods]
    for model in models  # 构建字典,存储每个模型在不同填充方法下的准确率
}

# 创建画布
plt.figure(figsize=(12, 7), dpi=100)  # 设置图表大小和分辨率

# 颜色和标记样式设置
colors = plt.cm.tab10(np.linspace(0, 1, len(models)))  # 使用tab10色系为不同模型分配颜色
markers = ['o', 's', '^', 'D', 'v']  # 定义不同的标记形状:圆形、方形、三角形、菱形、倒三角形

# 为每个模型绘制点线图
for idx, model in enumerate(models):
    plt.plot(fill_methods, acc_data[model],
             marker=markers[idx],  # 设置标记形状
             color=colors[idx],  # 设置线条颜色
             linestyle='-',  # 实线连接
             linewidth=2.5,  # 线条粗细
             markersize=10,  # 标记大小
             markeredgewidth=2,  # 标记边缘宽度
             markeredgecolor='white',  # 标记边缘颜色
             label=model)  # 图例标签

# 添加图表标题和坐标轴标签
plt.title('不同填充方法下模型准确率对比',
         fontsize=15, pad=20)  # 标题字体大小和与图表顶部的距离
plt.xlabel('填充方法', fontsize=13, labelpad=10)  # X轴标签
plt.ylabel('准确率', fontsize=13, labelpad=10)  # Y轴标签
plt.ylim(0.35, 0.75)  # 设置Y轴范围
plt.yticks(np.arange(0.35, 0.76, 0.05))  # 设置Y轴刻度间隔为0.05

# 网格和边框设置
plt.grid(True, linestyle='--', alpha=0.4, which='both')  # 添加虚线网格
ax = plt.gca()  # 获取当前坐标轴
for spine in ax.spines.values():  # 隐藏所有边框
    spine.set_visible(False)

# 添加数据标签
for model in models:
    for x, y in zip(fill_methods, acc_data[model]):
        plt.text(x, y-0.02, f'{y:.2f}',  # 在数据点下方显示两位小数的准确率
                ha='center',  # 水平居中
                va='top',  # 垂直对齐
                fontsize=10,  # 字体大小
                bbox=dict(boxstyle='round,pad=0.2',  # 添加圆角矩形背景
                         fc='white',  # 背景颜色
                         ec='none',  # 无边框
                         alpha=0.7))  # 透明度

# 图例设置
legend = plt.legend(loc='upper left',  # 图例位置
                    bbox_to_anchor=(1, 1),  # 图例框位置
                    frameon=True,  # 显示图例框
                    title='模型类型',  # 图例标题
                    title_fontsize=12)  # 标题字体大小
legend.get_frame().set_facecolor('#f5f5f5')  # 设置图例背景色

# X轴标签旋转
plt.xticks(rotation=35, ha='right')  # 将X轴标签旋转35度,右对齐

plt.tight_layout()  # 自动调整子图参数,使之填充整个图像区域

# 保存图片(使用英文文件名避免编码问题)
plt.savefig('./model_accuracy_comparison.png',  # 输出文件名
            dpi=300,  # 图片分辨率
            bbox_inches='tight')  # 保存时包含所有元素
plt.show()  # 显示图表
 
相关推荐
2501_938140072 小时前
做内容很省心,2026好用AI笔记,支持抖音小红书视频无水印保存
人工智能
sell-cloud4 小时前
Prompt Engineering要凉了?Fable 5.5能“猜“意图,但银行正在封杀AI Agent——企业AI的真正护城河是什么
人工智能·prompt
Navicat中国6 小时前
Navicat 18 内置 AI 助手让数据库开发从繁琐操作迈向智能协作
大数据·人工智能·数据库开发
4SAPI6 小时前
多模型请求路由怎么设计?成本、速度和能力如何平衡
人工智能·python·gateway·php
魔乐社区6 小时前
翼芯・智算测试与适配优化专区,让国产算力“选得准、跑得通、用得好“
人工智能·开源·大模型
XCDoris8 小时前
郴州logo设计机构
大数据·人工智能·python
Goboy9 小时前
一个人带三个Agent,我用全新TRAE从0到1搭了个资讯周刊站
人工智能·trae
俊哥V9 小时前
每日 AI 研究简报 · 2026-10-19
人工智能·ai
AI_AGENT_DEV_AI9 小时前
AI英语教培智能体的开发
人工智能
物联网软硬件开发-轨物科技9 小时前
【技术白皮书】光伏清检一体化机器人系统解决方案技术白皮书
大数据·运维·网络·人工智能·机器人