☰
基于SVM的手写数字识别:从核函数原理到课程设计高分实现
2026/10/9 4:03:18 网站建设 项目流程

简介:基于SVM的手写数字识别Python课程设计资源,面向计算机相关专业在校学生、教师及机器学习入门者,帮助理解支持向量机在图像分类任务中的应用。压缩包共2000个文件,以1998个txt格式的训练/测试数据为主,每个文件对应一张手写数字样本的特征向量,并已按数字标签分目录存放,便于替换或扩展数据集;另含viewdigits.py主程序及README.md文档说明,代码经测试可正常运行,可直接用于模型训练与效果验证。资源包仅828KB,轻量易用,适合作为课程设计、毕业设计或入门实践项目。目前已有105人学习下载。文档对运行环境、实现流程及结果分析均有说明,可帮助读者快速上手,也可在此代码基础上修改拓展其他分类功能。

1. 基于SVM的手写数字识别:为什么课程设计选它最容易拿高分

期末课程设计摆在面前,要求是“机器学习算法实现一个完整应用”,选题绕来绕去,最后大概率会落到手写数字识别上。这个题目好做、好讲、好演示,而且数据现成、效果直观。但很多人第一反应是上深度学习,用CNN卷积网络——这反而容易翻车:训练慢、环境配置麻烦、显卡不支持,最要命的是课程设计答辩时老师一问“卷积层为什么是3x3不是5x5”,你很难讲清楚。基于SVM实现手写数字识别则完全不同,它用数学原理支撑识别过程,几十行Python代码就能在普通笔记本上跑出97%以上的准确率,源码、文档、训练数据、测试数据齐全之后,这套方案几乎是“高分课程设计”的标准答案。这篇文章就把从原理到落地、从参数调优到答辩避坑的完整路径讲透。

2. SVM做手写数字识别的原理与选型:先搞懂黑匣子里在算什么

2.1 线性不可分到高维映射:核函数到底在做什么

手写数字图片本质上是像素矩阵。一张28x28的灰度图,展开后就是784维的向量,SVM要做的就是在784维空间里找一个超平面,把“0”和“1”这两个类别的样本分开。但问题在于,手写数字的笔画千奇百怪,数据在原始空间里根本不是线性可分的——你没法用一条直线把潦草的“7”和歪扭的“1”干净地切开。

核函数就是解决这个问题的钥匙。RBF径向基核函数做的事情,是把原始空间里的样本点映射到更高维的空间,让原本纠缠在一起的数据在高维空间里变得线性可分。这个映射不需要真的计算高维坐标,而是通过核函数计算样本对之间的“相似度”,这就是所谓的“核技巧”。实际训练时,SVM只关心支持向量——那些离分类边界最近的样本点,它们决定超平面的位置,其他远离边界的样本对模型几乎没有影响。

这里有个经常被误解的点:核函数不是越多越好。RBF虽然是默认首选,但它对参数gamma极其敏感,gamma控制着单个样本的影响半径。gamma太大,每个样本只影响自己的极小邻域,模型会过拟合,边界变得支离破碎;gamma太小,所有样本挤在一起,模型欠拟合,边界过于平滑。后面第5章会专门讲参数怎么调,这里先记住一个口诀:RBF能用,但用之前必须做参数搜索。

2.2 多分类策略:OvO和OvR怎么选

SVM天生是二分类器,一次只能回答“是”或“不是”。手写数字有10个类别(0到9),必须把二分类扩展成多分类。常见策略有两种:

一对一(One-vs-One,OvO)把10个类别两两配对,共训练45个二分类器。预测时让每个分类器投票,得票最多的类别获胜。这样每个分类器只需要区分两个数字,任务简单,单个模型准确率高,但预测耗时随类别数增加。

一对多(One-vs-Rest,OvR)训练10个分类器,每个分类器负责区分“是不是数字k”。预测时比较每个分类器输出的置信度分数,取最高者。分类器数量少,训练快,但正负样本不平衡——数字“1”的样本只有十分之一,其余九成都是负样本,模型容易偏向多数类。

在scikit-learn里,SVC的decision_function_shape参数可以控制策略:'ovo'是一对一,'ovr'是一对多。课程设计场景下我一般选'ovo',因为准确率更稳定,尤其当训练数据量足够(比如每类1000张以上)时,45个二分类器的投票机制比10个一对多分类器更抗噪声。

2.3 为什么课程设计选SVM而不是CNN:对比表

维度SVM + 原始像素特征SVM + HOG特征CNN卷积网络
训练时间(普通CPU)2-5分钟3-8分钟30分钟起,依赖GPU
特征工程无需需要提取但代码固定自动学习
可解释性支持向量、核函数,数学清晰特征可视化明确黑匣子,难以直观解释
答辩提问压力低,公式推导有现成材料低,可讲方向梯度高,被追问网络设计细节
环境依赖Python + sklearn + numpyPython + sklearn + skimageTensorFlow/PyTorch + CUDA
识别准确率(MNIST)94%-96%97%-98.5%99%+

从这个表能看出,CNN的准确率确实最高,但代价是环境复杂、训练慢、答辩难讲。SVM方案在准确率上只差2-3个百分点,在工程复杂度上低一个量级。如果你的课程设计题目是“要求识别手写数字”,SVM是最稳妥的选项;如果老师额外要求“比较高精度识别算法”,你还可以在文档里补一节“SVM vs CNN 的精度差异分析”作为加分项。

3. 把图片变成SVM能吃的格式:训练数据与测试数据的预处理

3.1 数据集选择与目录结构:MNIST自带还是自制

数据是课程设计的半条命。手写数字最经典的数据集是MNIST,包含60000张训练图和10000张测试图,每张是28x28的灰度图。但直接下载MNIST原格式(IDX二进制)对初学者不友好,实际做课程设计时常见做法是先用scikit-learn内置的digits数据集(1797张8x8图)跑通整个流程,再换成MNIST完整版。

完整的项目目录我建议这样组织:

handwritten_digits/ ├── data/ │ ├── train/ # 训练图片,按0-9分子目录存放 │ │ ├── 0/ │ │ ├── 1/ │ │ └── ... │ ├── test/ # 测试图片,同样按数字分子目录 │ ├── train_labels.csv │ └── test_labels.csv ├── models/ # 训练好的模型文件 ├── src/ │ ├── data_preprocess.py │ ├── train.py │ ├── test.py │ └── gui.py ├── docs/ │ └── 课程设计报告.md └── requirements.txt

没有现成数据的话,可以先自己画:用OpenCV的鼠标回调写一个小程序,在画布上写数字,按保存键存成图片,每个数字写50张左右,做成一个“自采集数据集”。这个工作量不大,而且答辩时“数据是自己采集的”是加分项。不过自采数据的质量波动大,建议和公开数据集混合使用:公开数据训练、自采数据做演示测试,效果比纯自采好得多。

3.2 图片转特征向量的标准流程:读取、灰度、二值化、直方图

SVM不能直接吃图片,它吃的是特征向量。最简单可靠的特征就是原始像素——把28x28的图片展平成784维向量,每个维度是0-255的灰度值。但直接展平有个问题:光照不均、笔画粗细变化会让同一数字的像素分布差异巨大,模型容易被“噪声”带偏。

我一般会做四步预处理:

# src/data_preprocess.py import cv2 import numpy as np def preprocess_image(image_path, target_size=(28, 28)): """读取图片并转成SVM输入特征向量""" # 1. 读取为灰度图,忽略透明通道 img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 2. 缩放,统一尺寸 img = cv2.resize(img, target_size, interpolation=cv2.INTER_AREA) # 3. 二值化,去掉浅色噪声,手写笔迹变纯黑 _, img = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY_INV) # 4. 归一化到[0,1],让特征值在同一量级 img = img.astype(np.float32) / 255.0 # 展平成1D向量 return img.flatten()

这段代码里,cv2.threshold的二值化很关键:原始图片的背景可能发灰,笔迹可能粗细不均,二值化后像素值只有0和255两种,相当于把噪声直接抹掉。THRESH_BINARY_INV是反色操作,让笔画为255、背景为0,这样特征向量里的非零值代表笔画位置,语义更清晰。归一化到[0,1]是为了配合SVM的RBF核——RBF核计算欧氏距离时,如果特征值范围是0-255而gamma很小,距离会被放大到失真,归一化后距离才能反映真实的样本相似度。

参数说明:target_size统一为28x28是沿用MNIST的标准,这样后续换用MNIST训练时可以无缝衔接。interpolation用INTER_AREA是因为缩小时它对像素求平均,能保留笔画的整体形状而不是只取邻近点。

3.3 HOG特征提取:让SVM识别率再上一个台阶

原始像素特征虽然简单,但对手写数字的局部形变很敏感。如果笔画在扫描时轻微旋转、倾斜,像素级对比就会产生大量误分类。HOG(方向梯度直方图)特征能解决这个问题——它统计图片局部区域的梯度方向分布,捕捉笔画的边缘朝向,对位置微移更鲁棒。

scikit-image提供了现成的HOG提取函数,我在课程设计里常用它替换原始像素:

# src/data_preprocess.py(续) from skimage.feature import hog def extract_hog_features(image_path): """提取HOG特征,维度为324""" img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) img = cv2.resize(img, (64, 64), interpolation=cv2.INTER_AREA) features = hog( img, pixels_per_cell=(8, 8), cells_per_block=(2, 2), orientations=9, block_norm='L2-Hys' ) return features

参数解释:pixels_per_cell=(8,8)表示把图分成8x8像素的小格子,计算每个格子的梯度直方图;cells_per_block=(2,2)表示4个格子组成一个block做归一化,消除光照变化;orientations=9表示梯度方向分成9个区间(0-180度,不考虑方向正负);block_norm用L2-Hys裁剪异常值。最终特征维度是(64/8-1)*(64/8-1)94=324,比784维小一半还多。

为什么图像要resize到64x64而不是28x28?因为HOG的分格子逻辑在28x28上只能分出3x3个格子,梯度统计太粗糙;64x64能分出7x7个格子,笔画细节的直方图更有区分度。另有不做缩放、用原始分辨率的做法,但224x224的图提取时间要翻好几倍,精度提升有限,课程设计场景不推荐。

4. 核心代码实现:从训练到评估的完整流程

4.1 环境准备与依赖安装

先确认环境。Python版本我建议3.8到3.10,scikit-learn在3.11以上有一些旧的二进制依赖问题,虽然新版已修复,但课程设计机器上不一定有最新版。安装依赖用pip一条命令:

pip install scikit-learn opencv-python scikit-image numpy pandas matplotlib joblib

安装后用一个五分钟脚本自检环境:import sklearn并打印版本号,用内置digits数据集跑一个迷你SVM,准确率能过80%说明环境正常。这一步能避免后面训练时报一些莫名其妙的错误——最常见的是opencv-python和scikit-image的版本冲突导致import失败,先装scikit-image再装opencv通常能规避。如果装不上opencv,可以先pip install opencv-python-headless,功能完全一样且体积更小。

4.2 训练脚本:加载数据、训练SVM、保存模型

训练脚本是整个项目的核心。以MNIST数据为例,假设你已经把训练图片按数字分目录放好,主函数如下:

# src/train.py import os import numpy as np import joblib from sklearn import svm from sklearn.metrics import classification_report from sklearn.model_selection import train_test_split from data_preprocess import preprocess_image def load_data(data_dir): """从目录结构加载图片和标签""" features = [] labels = [] for digit in range(10): digit_dir = os.path.join(data_dir, str(digit)) for filename in os.listdir(digit_dir): img_path = os.path.join(digit_dir, filename) features.append(preprocess_image(img_path)) labels.append(digit) return np.array(features), np.array(labels) def main(): # 加载全部训练数据 X, y = load_data('data/train') # 划分训练集和验证集,8:2 X_train, X_val, y_train, y_val = train_test_split( X, y, test_size=0.2, random_state=42, stratify=y ) # 创建SVM模型 model = svm.SVC( kernel='rbf', C=10, gamma='scale', decision_function_shape='ovo', probability=True, random_state=42 ) # 训练 model.fit(X_train, y_train) # 在验证集上评估 val_acc = model.score(X_val, y_val) print(f"验证集准确率: {val_acc:.4f}") # 保存模型到models目录 os.makedirs('models', exist_ok=True) joblib.dump(model, 'models/svm_digits_model.pkl') print("模型已保存到 models/svm_digits_model.pkl") if __name__ == '__main__': main()

参数说明:C=10是正则化强度的倒数,C越小越强正则化(防止过拟合)。注意训练前用train_test_split划分了20%作为验证集,目的不是“测试”,而是让你在调参时有独立的评估依据——你不能用最终的测试数据反复调参,否则评估结果会过拟合测试集,这属于“数据泄露”的典型错误。

stratify=y保证划分后各类别比例和原数据集一致,数字“0”和其他数字的样本数量不同时,这个参数很重要。random_state=42固定随机种子,保证每次运行的结果可复现——课程设计答辩时老师会随机抽几个测试样本让你重新跑,如果每次结果差异很大,会被质疑代码稳定性。

decision_function_shape='ovo'搭配probability=True有个坑:SVC的Platt缩放(概率校准)在ovo策略下会先做k-fold交叉验证再拟合概率模型,训练时间会增加很多。如果训练集超过2万张,建议把probability关掉,用decision_function的得分替代概率做排序展示。

4.3 测试与评估:混淆矩阵和分类报告

训练完不能只说“准确率97%”,要给出细致的评估材料。分类报告展示了每个类别的精确率(Precision)、召回率(Recall)和F1值——精确率回答“模型说这是7,有多大概率真的是7”,召回率回答“所有真实的7,模型找回了多少个”。这两个指标在数字识别里差异很明显:数字“8”容易被错判成“3”或“5”,召回率会明显低于其他数字。

混淆矩阵是答辩中最直观的图。生成代码:

# src/test.py import joblib import numpy as np import matplotlib.pyplot as plt from sklearn.metrics import confusion_matrix, classification_report, ConfusionMatrixDisplay from data_preprocess import preprocess_image # 加载已保存的模型 model = joblib.load('models/svm_digits_model.pkl') # 手动测试单张图片 def predict_single(image_path): feat = preprocess_image(image_path).reshape(1, -1) pred = model.predict(feat)[0] proba = model.predict_proba(feat)[0] # 需要训练时启用probability print(f"预测结果: {pred}, 置信度: {proba[pred]:.4f}") return pred # 对测试集全部图片做预测,生成混淆矩阵 X_test, y_test = load_data('data/test') y_pred = model.predict(X_test) print(classification_report(y_test, y_pred)) cm = confusion_matrix(y_test, y_pred) disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=range(10)) disp.plot(cmap='Blues') plt.savefig('docs/confusion_matrix.png', dpi=150)

ConfusionMatrixDisplay的cmap='Blues'可以让错分的格子呈深蓝色,答辩PPT截图时一眼能看出哪对数字容易被混淆。classification_report的输出中,如果某个数字的recall低于0.9,说明这个类别的样本区分度不足,需要补充训练数据或者考虑提取HOG特征。

4.4 可视化与GUI:把识别结果画出来

课程设计演示环节,终端打印结果远远不够,一个简单的交互界面能让答辩效果提升一个档次。用tkinter(Python自带GUI库)加OpenCV做一个手写板是常见做法:

# src/gui.py import tkinter as tk import joblib import numpy as np import cv2 from data_preprocess import preprocess_image class DigitRecognitionApp: def __init__(self, model_path): self.model = joblib.load(model_path) self.canvas_size = (280, 280) # 画布10倍放大,展示更清晰 self.window = tk.Tk() self.window.title("SVM 手写数字识别") self.canvas = tk.Canvas(self.window, width=self.canvas_size[0], height=self.canvas_size[1], bg='white') self.canvas.pack() self.canvas.bind("<B1-Motion>", self.draw) self.label = tk.Label(self.window, text="请在画布上写一个数字0-9", font=("Arial", 16)) self.label.pack() self.result = tk.Label(self.window, text="", font=("Arial", 24)) self.result.pack() btn_clear = tk.Button(self.window, text="清除", command=self.clear_canvas) btn_clear.pack(side=tk.LEFT, padx=20) btn_predict = tk.Button(self.window, text="识别", command=self.predict) btn_predict.pack(side=tk.RIGHT, padx=20) self.brush = tk.PhotoImage(width=1, height=1) self.brush.putdata((0,), (0, 0, 0, 0)) # 透明笔刷,画黑色笔画 self.window.mainloop() def predict(self): # 从画布保存手写内容为图片 self.canvas.postscript(file='temp.ps') # PostScript转PNG img = cv2.imread('temp.png', cv2.IMREAD_GRAYSCALE) if img is None: self.result.config(text="识别失败,请重写") return feat = preprocess_image('temp.png').reshape(1, -1) pred = self.model.predict(feat)[0] self.result.config(text=f"识别结果: {pred}") def clear_canvas(self): self.canvas.delete("all") self.result.config(text="") def draw(self, event): x, y = event.x, event.y self.canvas.create_oval(x-4, y-4, x+4, y+4, fill='black', outline='black')

这个GUI实现里有个容易踩的坑:tkinter的canvas.postscript只能输出PostScript格式,OpenCV读不了。解决办法是先截图整个窗口区域,再裁剪出画布部分——在Windows上用PIL的ImageGrab截图最省事。我在最终版本里改用open-cv的高gui窗口而不是tkinter(cv2.namedWindow + 鼠标回调),代码更短而且避免了PostScript转换这个大坑。

5. SVM参数调优与避坑指南:血泪经验总结

5.1 三个必调参数:C、gamma、kernel

RBF核的SVM有三个核心参数:C(正则化强度)、gamma(核函数宽度)、kernel(核函数类型)。三者的关系是:kernel决定用什么函数计算相似度,gamma决定相似度的衰减速度,C决定分类器对错分类样本的容忍程度。

C的常规候选是[0.1, 1, 10, 100]。C越小,模型越保守,倾向于选择更简单的边界,可能欠拟合;C越大,模型对训练集的拟合越“用力”,可能在验证集上过拟合。手写数字识别场景,C在10到100之间通常是安全区间,因为数据本身噪声不多。

gamma的常规候选是[0.001, 0.01, 0.1, 1]。如果设成'scale'(默认值),sklearn会用1/(特征维数*特征方差)自动计算gamma,但这个自动值对784维像素特征往往偏小,导致模型欠拟合。在MNIST上手动搜索时,gamma=0.01附近通常能得到最优效果。

kernel的候选一般是'rbf'和'linear'。linear是rbf在gamma特别大的极限退化情况,速度更快但没有非线性分类能力;课程设计里除非特征维度极高(比如HOG后324维),否则直接rbf不用犹豫。

5.2 参数怎么找:GridSearchCV暴力搜索

手动试参数是玄学,用网格搜索是科学。scikit-learn提供的GridSearchCV可以自动组合尝试所有候选参数组合:

# src/train.py(续:网格搜索版本) from sklearn.model_selection import GridSearchCV param_grid = { 'C': [0.1, 1, 10, 100], 'gamma': [0.001, 0.01, 0.1], 'kernel': ['rbf'], 'decision_function_shape': ['ovo'] } base_svm = svm.SVC(random_state=42) grid_search = GridSearchCV( base_svm, param_grid, cv=5, # 5折交叉验证 scoring='accuracy', n_jobs=-1, # 使用所有CPU核 verbose=1 ) grid_search.fit(X_train, y_train) print(f"最佳参数: {grid_search.best_params_}") print(f"最佳准确率: {grid_search.best_score_:.4f}") best_model = grid_search.best_estimator_

参数解释:param_grid里的组合数是431*1=12组,配合5折交叉验证就是60次训练。如果训练集有5万张、特征784维,每次训练约30秒,总耗时约30分钟——课程设计的接受范围。n_jobs=-1并行加速很重要,可以缩短到10分钟左右。另外要注意GridSearchCV默认用准确率作为评分,但如果某个类别的样本特别少(比如你自采数据时数字“4”只写了20张),建议把scoring改成'f1_macro',防止模型通过忽略少数类来“刷分”。

网格搜索有个伴随问题:结果会偏向验证集。参搜完后最稳妥的做法是用“留出法”再做一次最终评估,即用原本切出来的那20%验证集测试最终模型,不要让网格搜索的结果直接当最终准确率。

5.3 常见问题排查:现象、原因、解决

问题1:训练时内存报错或进程被杀死

现象:MNIST训练到一半,终端提示MemoryError或Killed。

原因:SVM的RBF核需要计算所有样本对之间的核矩阵,5万样本的核矩阵是5万x5万,占用内存约18GB(float64)。普通笔记本8GB内存根本扛不住。

解决:不要上来就用全部5万张训练。第一次调试用1万张(每类1000张),跑通后再考虑增大。如果非要全量训练,换成LinearSVC(线性SVM,用Hinge损失+梯度优化,不计算核矩阵),训练速度和内存双双改善,但准确率会掉1-2个百分点。核方法的内存瓶颈是一个常见“认知”盲区,很多人以为SVM像神经网络一样可以随便加大数据量,实际上SVM的高精度是建立在样本对对计算的代价之上的。

问题2:模型准确率只有30%-50%

现象:训练完成,验证准确率低得离谱。

原因:多半是图片预处理出了问题。常见的有:二值化阈值设太死把浅色笔画抹掉了;图片方向反了(白底黑字变成了黑底白字,而SVM学的是笔画为亮色);或者图片没有resize到统一尺寸,特征向量长度不一致直接报错或错位。

解决:把预处理后的特征向量重新“画”回图片看一下。也就是把preprocess_image函数最后一步的flatten去掉,改成imshow,肉眼确认预处理后的图长什么样。这个问题排查时最有用的一句话是:“代码先别管,先把中间结果可视化出来看看”。

问题3:训练正常但单张图片预测总是错

现象:验证集准确率97%,但自己手写一个“2”放到程序里总是识别成“7”。

原因:自采图片和训练数据的分布不一致——训练集是印刷体或标准手写体,你写的潦草字在特征空间里离训练样本很远。

解决:优先把预测图片做同样的预处理:缩放、二值化、反色、归一化。别忘了图像是否已经反转了颜色。如果预处理一致还错,那说明SVM的实际泛化边界就是没覆盖到你的写法,这时可以把自己写的这10张图(0-9各一张)追加到训练集,重新训练。这是课程设计中最容易忽视的复盘路径——模型是死的,数据是活的,把“测试失败的样本”补充进训练集本身就是机器学习迭代的常态。

问题4:代码在别人电脑上跑不起来

现象:答辩现场老师的电脑没有装opencv,或者python版本是2.7。

原因:依赖清单不完整,或者用了老版本语法。

解决:把环境“打包”成requirements.txt并写清楚Python版本。答辩前一天用一台“干净”的虚拟机从头pip install一遍是最保险的做法。如果老师电脑不让装环境,还有一个后悔药:把服务打包成exe(PyInstaller打包有GUI的程序可以做到,但文件较大),或者准备一个网页版推理的备用方案(用Flask起个服务,老师电脑只要有浏览器就能演示)。

6. 课程设计报告与进阶验证技巧:让文档帮你撑起答辩

课程设计的评分构成里,源码能跑是基础分,文档和答辩表现是拉开差距的部分。报告建议按五章来写:绪论(选题背景+国内外研究现状)、理论基础(SVM原理+核函数+多分类策略)、系统设计(数据预处理+特征提取+模型训练流程)、实验结果(准确率+混淆矩阵+参数分析)、总结与展望。其中“参数分析”是最容易写深的章节——把你用GridSearchCV搜到的不同C、gamma组合的准确率变化列成表格,再解释为什么C=100比C=0.1效果好,老师一看就知道你是真调过参而不是跑了个默认模型。

进阶验证方面,建议额外做两个实验放进文档:第一个是“不同核函数对比”实验,用同一个数据集分别测linear、poly、rbf三个核的准确率和训练时间,表格呈现后讨论各自的特点;第二个是“特征对比”实验,原始像素特征 vs HOG特征,各训练一个模型对同一测试集评估。这两个实验不需要额外写代码,直接复用train.py改两行就能跑,但它们的价值在于证明你手里这个SVM方案是我们工程师常说的跨方法验证——不是碰运气跑到97%的。

还有一条血泪经验:模型训练完一定把joblib存下来的.pkl文件保留好,答辩演示时如果现场机器环境出问题,直接加载模型做推理,而不是现场重新训练。顺便把预测失败的两个样本(比如“8”被识别成“5”)打印出来,主动讲“这里错是因为两个数字的笔画密度分布接近”,这种诚实比“我的模型完美无瑕”更能拿分。

最后一件事是训练轮数和随机性的记录。我踩过最大的坑是答辩前一天发现输出了不同的准确率——因为训练时随机抽样切分了验证集,每次结果略不一样。这个问题的根治办法是固定random_state,然后把每个实验的随机种子、训练轮数、参数组合写成一个“实验记录表”放在附录里。答辩时老师问“你的准确率能复现吗”,直接把实验配置表亮出来比口头保证有力得多。

从SVM原理到数据预处理,从网格搜索到GUI演示,这套方案覆盖了课程设计所需的全链条。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询