跳到主要内容机器学习模型评估:8 种算法对比实战 | 极客日志PythonAI算法
机器学习模型评估:8 种算法对比实战
本文对比了逻辑回归、随机森林、支持向量机、AdaBoost、高斯贝叶斯、XGBoost、全连接神经网络及卷积神经网络共 8 种算法在矿物分类任务上的表现。通过网格搜索调优,XGBoost 测试集准确率达 97%,CNN 达 100%,MLP 为 94.88%。高斯贝叶斯因准确率过低被弃用。结论显示集成学习与深度学习模型在该数据集上泛化能力更强,其中 XGBoost 与 CNN 效果最佳。
追风少年1 浏览 将得到的训练数据集和测试数据集通过 8 种算法来进行模型评估,对比结果得到最优的模型评估。
1. LR 逻辑回归算法
数据提取(本文以平均填充值为例子)
import pandas as pd
from sklearn import metrics
train_data = pd.read_excel()
train_data_x = train_data.iloc[:, :]
train_data_y = train_data.iloc[:, ]
test_data = pd.read_excel()
test_data_x = test_data.iloc[:, :]
test_data_y = test_data.iloc[:, ]
result_data = {}
r'训练数据集 [平均填充].xlsx'
1
0
r'测试数据集 [平均值填充].xlsx'
1
0
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV
param_grid = {
'C': [0.01],
'penalty': ['l2'],
'solver': ['lbfgs'],
'max_iter': [3000],
'class_weight': ['balanced']
}
logreg = LogisticRegression()
grid_search = GridSearchCV(logreg, param_grid, cv=5)
grid_search.fit(train_data_x, train_data_y)
print("best parameters set found on development set:")
print(grid_search.best_params_)
LR_result = {}
lr = LogisticRegression(C=0.01, max_iter=1000, penalty=None, solver='lbfgs')
lr.fit(train_data_x, train_data_y)
测试结果(含训练数据集的测试 + 测试数据集的测试)
train_predicted = lr.predict(train_data_x)
print('LR 的 train:\n', metrics.classification_report(train_data_y, train_predicted))
test_predicted = lr.predict(test_data_x)
print('LR 的 test:\n', metrics.classification_report(test_data_y, test_predicted))
a = metrics.classification_report(test_data_y, test_predicted, digits=6)
b = a.split()
LR_result['recall_0'] = float(b[8])
LR_result['recall_1'] = float(b[11])
LR_result['recall_2'] = float(b[16])
LR_result['recall_3'] = float(b[21])
LR_result['acc'] = float(b[25])
result_data['acc'] = LR_result
print('lr 结束')
训练集准确率:0.87
测试集准确率:0.87
训练集和测试集准确率几乎一致,说明模型没有过拟合 / 欠拟合,泛化能力稳定。
2. 随机森林算法
import pandas as pd
from sklearn import metrics
'''数据提取'''
train_data = pd.read_excel(r'训练数据集 [平均值填充].xlsx')
train_data_x = train_data.iloc[:, 1:]
train_data_y = train_data.iloc[:, 0]
test_data = pd.read_excel(r'测试数据集 [平均值填充].xlsx')
test_data_x = test_data.iloc[:, 1:]
test_data_y = test_data.iloc[:, 0]
result_data = {}
'''----------------------RF 算法实现代码------------------------------'''
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
param_grid = {
'n_estimators': [50, 100, 200],
'max_depth': [None, 10, 20, 30],
'min_samples_split': [2, 5, 10],
'min_samples_leaf': [1, 2, 5],
'max_features': ['auto', 'sqrt', 'log2'],
'bootstrap': [True, False]
}
rf = RandomForestClassifier()
grid_search = GridSearchCV(rf, param_grid, cv=5)
grid_search.fit(train_data_x, train_data_y)
print("Best parameters set found on development set:")
print(grid_search.best_params_)
RF_result = {}
rf = RandomForestClassifier(
bootstrap=False,
max_depth=20,
max_features='log2',
min_samples_leaf=1,
n_estimators=50,
random_state=487
)
rf.fit(train_data_x, train_data_y)
测试结果(含训练数据集的测试 + 测试数据集的测试)
train_predicted = rf.predict(train_data_x)
print('RF 的 train:\n', metrics.classification_report(train_data_y, train_predicted))
test_predicted = rf.predict(test_data_x)
print('RF 的 test:\n', metrics.classification_report(test_data_y, test_predicted))
a = metrics.classification_report(test_data_y, test_predicted, digits=6)
b = a.split()
RF_result['recall_0'] = float(b[8])
RF_result['recall_1'] = float(b[11])
RF_result['recall_2'] = float(b[16])
RF_result['recall_3'] = float(b[21])
RF_result['acc'] = float(b[25])
result_data['acc'] = RF_result
print('rf 结束')
训练集准确率:1
测试集准确率:0.96
随机森林准确率更高,泛化能力极强,几乎没有过拟合。
3. 支持向量机算法
import pandas as pd
from sklearn import metrics
'''数据提取'''
train_data = pd.read_excel(r'训练数据集 [平均值填充].xlsx')
train_data_x = train_data.iloc[:, 1:]
train_data_y = train_data.iloc[:, 0]
test_data = pd.read_excel(r'测试数据集 [平均值填充].xlsx')
test_data_x = test_data.iloc[:, 1:]
test_data_y = test_data.iloc[:, 0]
result_data = {}
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
param_grid = {
'C': [0.01, 0.1, 1, 2],
'kernel': ['linear', 'poly', 'rbf', 'sigmoid'],
'degree': [2, 3, 4, 5],
'gamma': ['scale', 'auto'] + [1],
'coef0': [0.1]
}
svc = SVC()
grid_search = GridSearchCV(svc, param_grid, cv=5)
grid_search.fit(train_data_x, train_data_y)
print("Best parameters set found on development set:")
print()
print(grid_search.best_params_)
SVM_result = {}
svm = SVC(C=1, coef0=0.1, degree=4, gamma=1, kernel='poly', probability=True, random_state=100)
svm.fit(train_data_x, train_data_y)
test_predicted = svm.predict(test_data_x)
print('SVM 的 test:\n', metrics.classification_report(test_data_y, test_predicted))
a = metrics.classification_report(test_data_y, test_predicted, digits=6)
b = a.split()
print(a)
SVM_result['recall_0'] = float(b[6])
SVM_result['recall_1'] = float(b[11])
SVM_result['recall_2'] = float(b[16])
SVM_result['recall_3'] = float(b[25])
SVM_result['acc'] = float(b[25])
result_data['SVM'] = SVM_result
4. AdaBoost 算法
AdaBoost 算法是集成学习算法中的 stacking 方法。
随机森林和 XGBoost 使用的基学习器都是决策树,而 AdaBoost 可以使用其他各种弱学习器,属于集成学习。
import pandas as pd
from sklearn import metrics
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
'''数据提取'''
train_data = pd.read_excel(r'训练数据集 [平均值填充].xlsx').dropna(how='any')
train_data_x = train_data.iloc[:, 1:]
train_data_y = train_data.iloc[:, 0]
test_data = pd.read_excel(r'测试数据集 [平均值填充].xlsx').dropna(how='any')
test_data_x = test_data.iloc[:, 1:]
test_data_y = test_data.iloc[:, 0]
result_data = {}
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
ada = AdaBoostClassifier(algorithm='SAMME', random_state=0)
param_grid = {
'n_estimators': [50, 100, 200],
'learning_rate': [0.01, 0.1, 0.5, 1.0],
'algorithm': ['SAMME', 'SAMME.R'],
'estimator': [DecisionTreeClassifier(max_depth=1), DecisionTreeClassifier(max_depth=2)]
}
abf = AdaBoostClassifier(n_estimators=100, random_state=0)
grid_search = GridSearchCV(abf, param_grid, cv=5)
grid_search.fit(train_data_x, train_data_y)
print("Best parameters set found on development set :\n ")
print(grid_search.best_params_)
AdaBoostClassifier_result = {}
abf = AdaBoostClassifier(
algorithm='SAMME',
estimator=DecisionTreeClassifier(max_depth=2),
n_estimators=200,
learning_rate=1.0,
random_state=0
)
abf.fit(train_data_x, train_data_y)
train_predicted = abf.predict(train_data_x)
print("AdaBoost 的 train:\n", metrics.classification_report(train_data_y, train_predicted))
test_predicted = abf.predict(test_data_x)
print("AdaBoost 的 test:\n", metrics.classification_report(test_data_y, test_predicted))
a = metrics.classification_report(test_data_y, test_predicted, digits=6)
b = a.split()
AdaBoostClassifier_result['recall_0'] = float(b[6])
AdaBoostClassifier_result['recall_1'] = float(b[11])
AdaBoostClassifier_result['recall_2'] = float(b[16])
AdaBoostClassifier_result['recall_3'] = float(b[21])
AdaBoostClassifier_result['acc'] = float(b[25])
result_data['AdaBoost'] = AdaBoostClassifier_result
5. 高斯贝叶斯(GNB)算法
要求是连续性的变量。本项目矿物数据文件中的数据矿物的含量就是连续的变量。
from sklearn import metrics
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
'''数据提取'''
train_data = pd.read_excel(r'训练数据集 [平均值填充].xlsx').dropna(how='any')
train_data_x = train_data.iloc[:, 1:]
train_data_y = train_data.iloc[:, 0]
test_data = pd.read_excel(r'测试数据集 [平均值填充].xlsx').dropna(how='any')
test_data_x = test_data.iloc[:, 1:]
test_data_y = test_data.iloc[:, 0]
result_data = {}
from sklearn.naive_bayes import GaussianNB
GNB_result = {}
gnb = GaussianNB()
gnb.fit(train_data_x, train_data_y)
train_predicted = gnb.predict(train_data_x)
print('GNB 的 train:\n', metrics.classification_report(train_data_y, train_predicted))
test_predicted = gnb.predict(test_data_x)
print('GNB 的 test:\n', metrics.classification_report(test_data_y, test_predicted))
a = metrics.classification_report(test_data_y, test_predicted, digits=6)
b = a.split()
6. XGBoost 算法
import pandas as pd
from sklearn import metrics
import warnings
warnings.filterwarnings('ignore', category=FutureWarning)
'''数据提取'''
train_data = pd.read_excel(r'训练数据集 [平均值填充].xlsx').dropna(how='any')
train_data_x = train_data.iloc[:, 1:]
train_data_y = train_data.iloc[:, 0]
test_data = pd.read_excel(r'测试数据集 [平均值填充].xlsx').dropna(how='any')
test_data_x = test_data.iloc[:, 1:]
test_data_y = test_data.iloc[:, 0]
result_data = {}
import xgboost as xgb
XGBoost_result = {}
xgb_model = xgb.XGBClassifier(
learning_rate=0.05,
n_estimators=200,
num_class=5,
max_depth=7,
min_child_weight=1,
gamma=0,
subsample=0.6,
colsample_bytree=0.8,
objective='multi:softmax',
seed=0
)
xgb_model.fit(train_data_x, train_data_y)
train_predicted = xgb_model.predict(train_data_x)
print("XGBoost 的 train:\n", metrics.classification_report(train_data_y, train_predicted))
test_predicted = xgb_model.predict(test_data_x)
print("XGBoost 的 test:\n", metrics.classification_report(test_data_y, test_predicted))
a = metrics.classification_report(test_data_y, test_predicted, digits=6)
b = a.split()
XGBoost_result['recall_0'] = float(b[6])
XGBoost_result['recall_1'] = float(b[11])
XGBoost_result['recall_2'] = float(b[16])
XGBoost_result['recall_3'] = float(b[21])
XGBoost_result['acc'] = float(b[25])
- 测试集准确率 97%,比 RF 高 1%,比 LR 高 10%;
- 类别 2 召回率 100%,对小样本类别的识别能力极强;
- 训练集全对、测试集 97% 准确率,几乎无过拟合,泛化能力拉满。
XGBoost 模型在你的矿物分类数据集上表现极佳,训练集完全拟合,测试集准确率高达 97%,是目前最优的分类模型。
7. 神经网络算法
有两层神经元组成的神经网络 - 感知器,感知器只能划分数据。
将输入信息与ω1,ω2...相乘,输出的结果代入非线性激活函数 sigmod 得到输出结果。
多层感知器:增加一个中间层,隐含层,神经网络可以做非线性分类的关键 - 隐藏层,即神经网络构造包括:输入层,隐藏层,输出层。
在神经网络的每个层次中,除了输出层以外,都会有一个偏置单元,本质上是一个只含有存储功能,且存储值为 1 的单元。
输入层的节点数:与特征的维度匹配
输出层的节点数:与目标的维度匹配。
中间层的节点数:目前业界没有完善的理论来指导这个决策。一般是根据经验来设置。较好的方法就是预先设定几个可选值,通过切换这几个值来看整个模型的预测效果,选择效果最好的值作为最终选择。
模型训练的目的:使得参数尽可能的与真实的模型逼近。
具体做法:
- 首先给所有参数赋上随机值。我们使用这些随机生成的参数值,来预测训练数据中的样本。
- 计算预测值为 yi,真实值为 y。那么,定义一个损失值 loss,损失值用于判断预测的结果和真实值的误差,误差越小越好。
常用的损失函数:0-1 损失函数、均方差损失、平均绝对差损失、交叉熵损失、合页损失。
回归用均方损失函数,二分类多分类用交叉熵损失函数。
均方差损失函数【Mean Squared Error Loss,MSE】:

多分类情况下,如何计算损失值:用 Softmax + 交叉熵损失实现多分类,其作用是衡量模型预测概率与真实标签的差距。
-log 的原因 —— 概率越接近 1(预测越准),损失越小;概率越接近 0(预测错误),损失越大,实现对错误预测的强惩罚。
正则化:解决过拟合问题
L1 正则化:
让权重稀疏化;
L2 正则化:
让权重平滑,是实战中最常用的方式。
梯度下降:沿损失函数梯度的反方向更新参数,逐步找到损失最小值,学习率(lr)决定更新幅度;
反向传播(BP):通过链式法则将损失误差从输出层反向传递到输入层,计算各层权重的梯度,是神经网络端到端训练的核心。
神经网络训练三部分:神经网络本身,梯度下降,损失函数。
MLP(全连接神经网络)由全连接层(nn.Linear)堆叠而成,通过激活函数引入非线性,突破线性模型的表达限制:
从数据中学习特征并完成分类 / 回归任务,且遵循统一的训练范式:
- 前向传播:输入数据通过网络层计算得到预测输出;
- 损失计算:用损失函数(如交叉熵)衡量预测值与真实值的差距;
- 反向传播:通过梯度下降优化算法,更新网络参数以最小化损失;
- 评估迭代:重复上述过程,直到模型收敛或达到预设训练轮数。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
from sklearn.model_selection import train_test_split
''' 1. 网络结构定义:包括输入层、隐含层和输出层的神经元数量。
2. 初始化方法:通过继承 nn.Module 类,初始化父类并进行自定义层的创建。
3. 权重初始化:全连接层的权重参数通过随机初始化进行赋值
'''
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = nn.Linear(13, 32)
self.fc2 = nn.Linear(32, 64)
self.fc3 = nn.Linear(64, 4)
def forward(self, x):
x = torch.relu(self.fc1.forward(x))
x = torch.relu(self.fc2(x))
x = self.fc3(x)
return x

X_train = torch.tensor(train_data_x.values, dtype=torch.float32)
Y_train = torch.tensor(train_data_y.values)
X_test = torch.tensor(test_data_x.values, dtype=torch.float32)
Y_test = torch.tensor(test_data_y.values)
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
def evaluate_model(model, X_data, Y_data, train_or_test):
size = len(X_data)
model.eval()
with torch.no_grad():
predictions = model(X_data)
correct = (predictions.argmax(1) == Y_data).type(torch.float).sum().item()
correct /= size
loss = criterion(predictions, Y_data).item()
print(f"{train_or_test}:\t 准确率:{(100*correct):.2f}%,损失:{loss:.4f}")
model.train()
return correct
epochs = 15000
accs = []
for epoch in range(epochs):
outputs = model(X_train)
loss = criterion(outputs, Y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch[{epoch + 1}/{epochs},Loss:{loss.item():.4f}')
train_acc = evaluate_model(model, X_train, Y_train, 'train')
test_acc = evaluate_model(model, X_test, Y_test, 'test')
accs.append(test_acc * 100)
net_result = {}
net_result['acc'] = max(accs)
result_data['net'] = net_result
训练数据集准确率:1
测试数据集准确率:0.94888
全连接神经网络
优势:结构简单、训练速度快,适配无局部关联的表格数据(如年龄、性别、收入等)
劣势:无参数共享,参数数量随特征数指数增长,易过拟合;忽略特征的局部 / 序列关联,不适配序列 / 图像数据。
8. 卷积神经网络算法
卷积神经网络是神经网络的子集,继承了神经网络的核心训练逻辑,核心结构:卷积层 + 池化层 + 少量全连接,通过「局部感受野 + 参数共享」优化,专门处理有局部关联的结构化数据(序列、图像、3D 数据)。
import torch
import torch.nn as nn
import torch.optim as optim
import numpy as np
class ConvNet(nn.Module):
def __init__(self, num_features, hidden_size, num_classes):
super(ConvNet, self).__init__()
self.conv1 = nn.Conv1d(in_channels=1, out_channels=16, kernel_size=3, padding=1)
self.conv2 = nn.Conv1d(in_channels=16, out_channels=32, kernel_size=3, padding=1)
self.conv3 = nn.Conv1d(in_channels=32, out_channels=64, kernel_size=3, padding=1)
self.relu = nn.ReLU()
self.fc = nn.Linear(64, num_classes)
def forward(self, x):
x = x.unsqueeze(1)
x = self.conv1(x)
x = self.relu(x)
x = self.conv2(x)
x = self.relu(x)
x = self.conv3(x)
x = self.relu(x)
x = x.mean(dim=2)
x = self.fc(x)
return x
Conv1d 输入格式:[batch, in_channels, seq_len],需通过 unsqueeze(1) 为扁平特征增加通道维度;
CNN 的不同维度实现仅适配不同数据形态,核心逻辑完全一致:
| 卷积类型 | 输入维度 | 卷积核形态 | 滑动维度 | 核心应用场景 |
|---|
| Conv1d | [batch, C, L](序列) | [out_C, in_C, kL] | 沿长度 L 滑动 | 时间序列、语音、文本 |
| Conv2d | [batch, C, H, W](图像) | [out_C, in_C, kH, kW] | 沿 H/W 滑动 | RGB 图片、灰度图、二维特征图 |
| Conv3d | [batch, C, D, H, W](3D) | [out_C, in_C, kD, kH, kW] | 沿 D/H/W 滑动 | 3D 医学影像、视频、点云数据 |
卷积核 kernel_size=3:每次捕捉 3 个连续特征的局部关联(如传感器读数的短期趋势);
参数共享:卷积核权重在整个序列上复用,大幅减少参数数量。
数据预处理:Pandas 转 PyTorch 张量
X_train = torch.tensor(train_data_x.values, dtype=torch.float32)
Y_train = torch.tensor(train_data_y.values)
X_test = torch.tensor(test_data_x.values, dtype=torch.float32)
Y_test = torch.tensor(test_data_y.values)
hidden_size = 10
num_classes = 4
model = ConvNet(13, hidden_size, num_classes)
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
num_epochs = 15000
accs = []
for epoch in range(num_epochs):
outputs = model(X_train)
loss = criterion(outputs, Y_train)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print(f'Epoch[{epoch + 1}/{num_epochs},Loss:{loss.item():.4f}')
with torch.no_grad():
predictions = model(X_train)
predicted_classes = predictions.argmax(dim=1)
accuracy = (predicted_classes == Y_train).float().mean()
print(f'Train Accuracy:{accuracy.item()*100:.2f}%')
predictions = model(X_test)
predicted_classes = predictions.argmax(dim=1)
accuracy = (predicted_classes == Y_test).float().mean()
print(f'Test Accuracy:{accuracy.item()*100:.2f}%')
accs.append(accuracy * 100)
accs.append(accuracy * 100)
cnn_result = {}
cnn_result['acc'] = max(accs).item()
result_data['cnn'] = cnn_result
print(result_data)
import json
result = {}
result['mean fill'] = result_data
with open(r'temp_data/平均值填充 result.json', 'w', encoding='utf-8') as file:
json.dump(result, file, ensure_ascii=False, indent=4)
卷积神经网络的准确率为 100% 很高,说明与全连接神经网络相比,卷积神经网络泛化能力更强,不容易过拟合。
微信扫一扫,关注极客日志
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
相关免费在线工具
- 加密/解密文本
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
- RSA密钥对生成器
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
- Mermaid 预览与可视化编辑
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
- curl 转代码
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online