)
AI入门从零开始实现手写数字识别2前言声明决策树Decision Tree简介核心原理决策树的类型决策树的优缺点集成学习Ensemble Learning简介集成学习的类别使用随机森林实现手写数字识别数据准备模型训练使用单棵 CART 决策树使用随机森林优化使用交叉验证和网格搜索对超参数进行优化预测数据问题与总结前言上个帖子我分享了如何使用 KNN 算法在 MNIST 数据集上实现手写数字识别但由于 KNN 算法的局限性在高维空间中对距离和分布及其敏感因此即使在测试集上有良好的表现但是模型的泛化能力不强。这次我将分享CART 决策树算法以及集成学习思想使用随机森林实现手写数字识别。声明这个系列主要是记录个人学习过程。写下来是为了厘清思路顺便加深理解。内容来源包括但不限于网络搜索、AI 生成、视频学习、各大论坛等。如果发现内容有误恳请大佬在评论区指正我会及时修改。学习中有疑问也欢迎私信或评论区讨论。我们正式开始学习吧。决策树Decision Tree简介决策树Decision Tree是一种监督学习算法既可以用于分类任务也可以用于回归任务。决策树通过树状结构来表示决策过程每个内部节点代表对某个特征的判断条件每个叶子节点代表最终的分类结果或者回归输出值。核心原理决策树的核心思想是递归地选择最优特征对数据集进行分裂直到满足停止条件。具体步骤如下选择最佳特征根据某种标准选择最佳特征进行分割常用的有信息增益 - ID3 决策树信息增益率 - C4.5 决策树和基尼指数 - CART 决策树。分割数据集根据选定的特征将数据集分为多个子集。递归构建子树对每个子数据集重复上述步骤直至满足终止条件达到最大深度、达到最小可分数量所有样本已完全分类等。剪枝可选决策树太深太复杂容易过拟合可以进行剪枝处理。预剪枝Pre-pruning在构建树的过程中提前停止例如设置最大深度、最小样本数、最小信息增益等。后剪枝Post-pruning先让树完全生长再从下往上逐层剪去不必要的子树如CART的代价复杂度剪枝。决策树的类型不同类型决策树使用的思想和算法都大致相同主要的区别在最佳特征的选择ID3 决策树ID3 决策树使用信息增益作为特征选择标准。信息增益基于信息熵的概念信息增益 分裂前的熵 - 分裂后的加权熵。选择信息增益最大的特征进行分裂。缺点偏向于选择取值较多的特征。C4.5 决策树为了缓解 ID3 算法对多值特征的偏好C4.5 算法使用信息增益率作为特征选择标准。信息增益率在信息增益的基础上对取值较多的特征进行惩罚使得当特征值种类较多时大幅度降低其重要性。信息熵信息增益信息增益率的原理与计算可以在网上找到很多非常详细的教程此处不再赘述感兴趣的读者可以自行搜索查看。CART 决策树CART 决策树使用基尼指数作为特征选择标准。与 ID3 和 C4.5 决策树不同CART决策树是一颗二叉树。决策树的优缺点优点可解释性强规则清晰像人类的决策过程非技术人员也能理解无需特征缩放不需要对数据做标准化或归一化支持多种数据类型数值型和类别型特征都可以处理计算效率高训练和预测速度较快缺点容易过拟合不加限制的决策树泛化能力差不稳定数据的微小变化可能导致生成完全不同的树贪心算法不能保证得到全局最优树对不平衡数据敏感类别不均衡时会偏向多数类集成学习Ensemble Learning简介集成学习是一种机器学习范式它的核心思想是构建并结合多个弱学习器基模型形成一个强学习器来完成任务。通俗来说就是“三个臭皮匠顶个诸葛亮”。单个模型尤其是简单的模型如浅层决策树可能会犯错但如果将多个模型的预测结果组合起来往往能得到比任何单一模型都更准确、更稳定的结果。集成学习的类别目前集成学习主要分为三大类别BaggingBoosting和StackingBaggingBagging的核心思想是并行训练多个有差异的基模型通过平权投票的方式得到最终结果。训练方法从原始训练集中通过有放回抽样Bootstrap 生成多个不同的子数据集在每个子集上独立训练一个基模型可以选择在获取到子数据集后进一步随机抽取特征进行训练。决策方式采用平权投票的方式分类任务用多数投票回归任务用简单平均。主要作用降低方差防止模型过拟合。非常适合那些容易过拟合的复杂模型如深决策树。代表算法随机森林。BoostingBoosting的核心思想是串行训练多个基模型每一轮新模型重点学习前一轮模型的残差/错误最终加权组合。训练方法基模型按顺序训练。每一轮新模型都会重点关注上一轮被预测错误的样本通过调整样本权重或者拟合上一轮模型的残差。决策方式加权组合表现好的模型权重高。主要作用降低偏差提升模型的预测精度。通常使用简单的弱学习器如浅层决策树/树桩作为基模型。代表算法AdaBoostGBDTXGBoost等。3.StackingStacking的核心思想是分层学习通过训练不同种类的模型并组合它们的预测来提高整体预测准确度。训练方法第一层Base Learners / 基学习器使用不同类型的算法如SVM、随机森林、神经网络、逻辑回归在原始数据上进行训练并通过交叉验证输出预测结果。第二层Meta Learner / 元学习器将第一层模型的预测结果作为新的特征训练一个简单的模型如逻辑回归来做最终预测。主要作用融合不同算法的优势进一步突破单一家族算法的性能瓶颈。缺点结构复杂极易过拟合计算成本极高。使用随机森林实现手写数字识别数据准备本项目数据集选用MNIST数据集该数据集于 1998 年由 Yann LeCun 等人发布可以说是机器学习领域中的Hello World。数据集中包括 70000 张 28 × 28 像素 (单通道灰度图像素值范围为0 - 2550 表示纯黑255 表示纯白)的图像可以分为 60000 张训练集与 10000 张测试集。数据集的获取以及查看在上一个帖子中已经分享此处不再赘述。importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltimporttimeimportjoblibfromsklearn.model_selectionimporttrain_test_split,GridSearchCVfromsklearn.treeimportDecisionTreeClassifier,plot_treefromsklearn.metricsimportclassification_report,accuracy_scorefromsklearn.ensembleimportRandomForestClassifier# 获取数据使用sklearn提供的fetch_openml方法# 下载 MNIST 数据集# (784个特征代表28x28的像素version1表示数据集版本号as_frameFalse表示返回的是NumPy数组)mnistfetch_openml(mnist_784,version1,as_frameFalse,parserauto)# 提取特征集与标签集X,ymnist.data,mnist.target# X 形状为 (70000, 784)y 形状为 (70000,)# 保存为 NumPy 的 .npz 格式是速度最快、体积最小的选择。它可以将 X 和 y 打包压缩进一个文件中。np.savez_compressed(mnist.npz,XX,yy)模型训练使用单棵 CART 决策树随机森林的基模型为 CART 决策树# 先演示 CART 决策树# 定义训练并保存模型函数deftrain_model(x_data,y_target):# 获取数据# 切分训练集与测试集X_train,X_test,y_train,y_testtrain_test_split(x_data,y_target,test_size10000,train_size60000,random_state6,stratifyy_target)# 创建决策树对象dtDecisionTreeClassifier(random_state42,max_depth15)# 训练模型dt.fit(x_train,y_train)# 评估模型y_pred_dtdt.predict(x_test)print(准确度: ,accuracy_score(y_test,y_pred_dt))# 保存模型joblib.dump(knn_estimator,./my_model/CART_model.pkl)print(训练完成模型已经保存)# 读取数据并训练datanp.load(mnist.npz,allow_pickleTrue)Xdata[X]ydata[y]train_model(X,y)运行结果如下准确度: 0.8779 训练完成模型已经保存使用随机森林优化deftrain_model_rf(x_data,y_target):# 切分训练集与测试集X_train,X_test,y_train,y_testtrain_test_split(x_data,y_target,test_size10000,train_size60000,random_state6,stratifyy_target)# 初始化随机森林rf_estimatorRandomForestClassifier(n_estimators100,random_state42,n_jobs-1)# 参1表示使用100课树参3表示使用全部核心计算#训练模型rf_estimator.fit(x_train,y_train)# 评估模型y_pred_dtrf_estimator.predict(x_test)print(准确度: ,accuracy_score(y_test,y_pred_dt))# 保存模型joblib.dump(rf_estimator,./my_model/rf_model.pkl)print(训练完成模型已经保存)运行结果如下准确度: 0.9674 训练完成模型已经保存可以看到随机森林的模型准确率相较于单棵决策树有较大提升。使用交叉验证和网格搜索对超参数进行优化defrf_optimised(x_data,y_target):# 切分训练集和测试集x_train,x_test,y_train,y_testtrain_test_split(x_data,y_target,test_size10000,train_size60000,random_state6)# 初始化网格搜索参数param_grid{n_estimators:[100,200,300],max_depth:[10,15,20,25],min_samples_leaf:[1,3,5,7,9]}# 网格搜索grid_searchGridSearchCV(estimatorRandomForestClassifier(),param_gridparam_grid,cv5,n_jobs-1)grid_search.fit(x_train,y_train)# 打印出最优参数print(grid_search.best_params_)# 获取最佳模型进行预测和评估best_rf_estimatorgrid_search.best_estimator_ y_pred_rfbest_rf.predict(x_test)print(accuracy_score(y_test,y_pred_rf))joblib.dump(best_rf_estimator,./my_model/best_rf_model.pkl)print(训练完成模型已经保存)运行结果如下{max_depth: 25, min_samples_leaf: 1, n_estimators: 300} 准确度: 0.9685714285714285 训练完成模型已经保存可以看到优化后的随机森林准确率略有提升但是因为原来的准确率就已经很高了因此提升幅度很小。预测数据使用已经训练好的模型对图片进行预测# 预测数据defpredict_data(path):# 读取模型rf_estimatorjoblib.load(./my_model/best_rf_model.pkl)# 读取图片imgplt.imread(path)# 显示图片plt.imshow(img,cmapgray)plt.axis(off)plt.show()# 预测图片ximg.reshape(1,-1)#如果图片格式为PNG则返回0-1之间的数值如果图片格式为其他格式则返回0-255之间的数值需要归一化。predknn_estimator.predict(x)returnpredprint(预测结果为,predict_data(./KNN_MNIST_TEST/demo.png))运行结果如下预测结果为 [2]问题与总结相较于上一期的 KNN 算法这次我们真正实现了模型预训练与预测的过程并学习决策树算法以及集成学习思想。同时我们在测试中可以发现即使在测试集上表现良好的模型面对我们自行绘制的与数据集风格不同的手写数字时模型的预测效果并不理想这便是传统机器学习的局限性模型的泛化能力并不强。后续我们将进入到深度学习的部分看看深度学习是如何实现的。欢迎大家在评论区交流学习心得也欢迎大佬指出文章中的错误。下一篇我会分享深度学习以及 CNN 算法并基于该算法实现手写数字识别。