ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

机器学习实战:从数据清洗到模型评估的完整案例精解

机器学习实战:从数据清洗到模型评估的完整案例精解 简介《机器学习实战案例精解》是一本面向数据科学家与技术初学者的机器学习实战电子书以五个真实案例为主线系统讲解统计与概率、回归、时间序列、聚类与分类等核心方法适合希望通过完整案例掌握机器学习流程的读者。书中每个案例均结合Python代码实践完整覆盖从数据预处理、特征构建到模型训练与评估的全流程并落到市场营销、医疗供需、金融预测等实用场景中案例选择本身就强调了实际问题的可操作性。资源为单个PDF文件体积约11.41MB排版清晰已吸引797人学习下载。读者可以借此理解不同算法在不同业务场景中的适用逻辑通过代码示例加深对模型构建、训练与优化的理解并学习如何在实际项目中快速定位问题、给出解决方案从而更自信地处理数据科学问题是一份原理与实操并重的入门进阶资料。 从入门到能实战机器学习这条路我走了不少弯路。最开始跟风刷完了吴恩达的课周志华的《机器学习》也翻了大半本可真拿到一份数据集让我自己从头到尾建一个模型的时候整个人是懵的——课上学的那些算法好像都认识我我却不认识它们。相信不少朋友都有类似的体验理论背了一堆遇到真实数据却不知道先干什么、后干什么调参全靠瞎试跑出来的结果自己都不敢信。这篇文章就用一个完整的实战案例把机器学习应用流程从头到尾捋一遍——包括数据清洗、特征工程、模型选型、评估验证这些环节讲讲每一步为什么要这么做以及在实操中容易踩的坑。不管你是刚入门想找一个能复现的完整案例还是已经跑通过几个Demo但缺乏系统实战经验这份记录都能给你一些参考。1. 为什么“案例精解”比“算法原理”更能带你入门先聊点感性的。很多人学机器学习的路径是买书、看视频、记公式然后动手时发现无从下手。这个现象太普遍了问题不在于你数学不够好而是你缺少一个“把知识串起来”的完整项目经验。1.1 从公式到代码之间的巨大鸿沟我在头歌平台上做过不少实训任务也看过很多人的解题过程。会发现一个很有意思的现象线性回归、逻辑回归、决策树这些基础算法的原理大家都能说出来个大概但一旦要求面对一份真实数据集做预测很多人的第一反应是“我该用哪个算法”。其实这个问题的答案不在算法里而在数据里。数据长什么样、有多大规模、特征是什么类型、目标变量是离散还是连续这些才决定了算法选型的方向。可惜这些内容是教科书很少强调的——书里给你的都是处理干净的经典数据集真实世界中根本不存在这种好事。周志华老师的书和李航老师的书我都读过它们是很好的“地图”但地图不能代替你亲自走一遍实地。实战经验的积累必须靠完整地跑通一个案例来获得。1.2 这个精解系列要解决的问题我会围绕一个真实场景展开人口收入预测。这是一个经典到不能再经典的二分类问题——根据个人的年龄、职业、教育程度、工作时长等属性预测这个人的年收入是否超过5万美元。这个案例的好处有三个数据集开源公开Adult数据集在UCI和Kaggle上都能直接下载不存在数据可得性问题特征类型足够丰富既有年龄、教育年限这类数值特征也有职业、性别、国家这类类别特征能覆盖大部分特征工程手段任务目标明确二分类问题的评价指标直观精确率、召回率、F1分数、AUC这些都能讲透我不打算只给一段能跑的代码就完事而是把从零到一的全过程拆开揉碎——包括环境搭建、数据探索、特征处理、模型训练、结果对比、调参优化这几个阶段。每走一步我都会说明这一步解决什么问题以及我在实际中踩过的坑。提示这套思路不仅适用于这个案例它就是机器学习应用流程的通用骨架。你以后面对任何分类问题基本都能沿用这个流程跑一遍。2. 环境准备与数据探索别急着训练先搞懂你的数据2.1 搭建可复现的机器学习课程环境先说环境。我见过太多人在这一步消耗了过多精力——装了Anaconda又没配好虚拟环境sklearn和pandas版本冲突跑个模型报一堆看不懂的错。其实初学者不需要追求最新的环境稳定好用才是第一位的。我的推荐组合是Python 3.9 pandas 1.5.x numpy 1.23.x scikit-learn 1.2.x matplotlib 3.6.x seaborn 0.12.x一个简单的创建命令帮你把环境搞定conda create -n ml_practice python3.9 conda activate ml_practice pip install pandas numpy scikit-learn matplotlib seaborn这个组合我已经用了很长时间稳定性很好。至少到目前为止我还没遇到过因为库版本问题导致代码跑不通的情况。2.2 第一次面对真实数据集时先问自己三个问题环境准备好了数据下载好了接下来就是关键部分。拿到一份数据之后不要急着调模型我建议你先问自己三个问题我的数据有多少行、多少列规模大不大我的目标字段是哪个它是离散的还是连续的我的特征字段里有多少是数值型、多少是类别型有没有缺失值这三个问题的答案直接决定了后面的处理方案。为了把问题说清楚我先用pandas把数据读进来做些基础探索import pandas as pd # Adult数据集的列名 columns [age, workclass, fnlwgt, education, education_num, marital_status, occupation, relationship, race, sex, capital_gain, capital_loss, hours_per_week, native_country, income] df pd.read_csv(adult.data, namescolumns, na_values ?, skipinitialspaceTrue) print(df.shape) print(df.info()) print(df.head())输出结果会告诉你一共32561条样本15个字段其中income就是我们要预测的目标变量取值为50K或50K属于典型的二分类问题。workclass、occupation、native_country这些字段存在缺失值后面需要处理。注意Adult数据集的缺失值是用?表示的如果你的读取代码没指定na_values ?pandas会把它当成一个正常的字符串类别你就不容易发现缺失问题了。这个坑非常隐蔽——我估计头歌上面不少同学跑这个数据的时候都被坑过。2.3 数据可视化一张图胜过千行统计量很多人会忽略可视化这一步觉得它“不够技术”。但从我的实战经验看可视化恰恰是帮你快速理解数据分布的最好方式还能帮你发现一些潜在问题。我一般会做三张图目标变量分布图、年龄分布直方图、工作时长与收入的关系图。import matplotlib.pyplot as plt import seaborn as sns # 目标变量分布 sns.countplot(datadf, xincome) plt.title(Income Distribution) plt.show() # 年龄分布 df[age].hist(bins30) plt.title(Age Distribution) plt.show() # 工作时长与收入关系 sns.boxplot(datadf, xincome, yhours_per_week) plt.title(Hours per Week by Income) plt.show()从这些图里你能直观地看到高收入人群每周工作时长的中位数明显更高整体分布呈现右偏特征年龄集中在30~50岁之间绝大部分人的收入不超过5万美元。这些观察会在后面的模型评估阶段派上用场——比如如果你发现数据严重不平衡就不能只用准确率来评价模型。3. 数据清洗与特征工程机器学习实战中最花时间的环节说句大实话在整个机器学习应用流程里这一步往往要占掉70%的时间虽然它不像算法那样“风光”但直接决定了模型效果的上下限。我见过太多人急着跑模型结果特征清洗没做好后面花大量时间调参也拉不回来——方向错了越努力跑得越偏。3.1 缺失值处理不要只会删行要想想为什么缺失Adult数据集中带缺失值的主要是workclass、occupation、native_country这三个字段。缺失率不算高大概在5%~7%左右。常见的处理策略有三种直接删除缺失行适合缺失比例很低比如低于1%且删除后不影响整体分布的情况用众数或中位数填充适合缺失比例中等且缺失字段本身对预测有一定作用的情况单独把“缺失”作为一个新类别适合缺失本身可能携带信息的情况我的选择是用众数填充for col in [workclass, occupation, native_country]: df[col].fillna(df[col].mode()[0], inplaceTrue)这里有个小细节为什么要用众数而不用均值因为workclass、occupation这些是类别变量均值对它没有数学意义众数才是“最可能出现的值”。这是个基础知识但很多初学者容易犯这个错误。3.2 特征编码的两条路One-Hot还是Label Encoding类别特征不能直接喂给模型必须转成数值。常用的手段有两种Label Encoding把类别映射成0、1、2……适合类别本身有顺序关系的情况比如教育程度“小学 初中 高中 大学”One-Hot Encoding把每个类别拆成一个独立列适合类别之间没有大小关系的情况比如职业、国家对于education它本身有顺序关系——毕竟教育程度的高低是客观存在的。当然我们也有education_num这个字段它已经用数字表示了教育年限所以education可以直接用也可以用Label Encoding来处理。from sklearn.preprocessing import LabelEncoder # 对无顺序的类别做One-Hot df pd.get_dummies(df, columns[workclass, occupation, relationship, race, sex, marital_status, native_country]) # 对有顺序的类别做Label Encoding le LabelEncoder() df[education] le.fit_transform(df[education]) df[income] le.fit_transform(df[income]) # 50K - 0, 50K - 1我讲义一点One-Hot Encoding会大幅增加特征维度Adult数据经过处理后特征列会从原来的15列膨胀到100列左右这对逻辑回归这类线性模型是能接受的但如果你的数据集类别特别多比如商品ID有上万个就需要考虑用目标编码、频率编码等手段来降维了。这也是面试时的高频话题。3.3 特征缩放为什么不能省经过编码之后你会发现age和education_num的取值范围和One-Hot出来的0/1根本不在一个量级上。如果不做缩放对于K-Means这种基于距离的算法来说量级大的特征会主导整个距离计算相当于量级小的特征直接失去作用了。标准化的手段主要有两种StandardScaler标准化把数据变成均值为0、方差为1的分布MinMaxScaler归一化把数据缩放到[0, 1]区间内对于逻辑回归和SVM这类对特征尺度敏感的模型我一般优先用StandardScaler因为它假设数据近似服从正态分布而这个假设在多数场景下是合理的。from sklearn.preprocessing import StandardScaler # 获取数值型特征列 numeric_cols df.select_dtypes(include[int64, float64]).columns.tolist() numeric_cols.remove(income) scaler StandardScaler() df_scaled df.copy() df_scaled[numeric_cols] scaler.fit_transform(df[numeric_cols])一个重要的原则scaler是在训练集上fit之后再同时transform训练集和测试集。绝对不能在全部数据上做fit再切分那样会造成数据泄露让你的模型评估结果虚高这一点怎么强调都不过分。很多入门项目偷偷犯了这个错而不自知最后在线下评估和线上测试对不上账的时候才反应过来是这里出了问题。4. 模型选型与训练从简单到复杂建立你的第一个baseline4.1 不要一上来就上XGBoost先跑个逻辑回归我想先讲一个很多人会犯的常识性错误一上来就上随机森林、XGBoost、神经网络然后将参数调整到过拟合最后感叹自己运气不好。实际上成熟的做法是先跑一个简单的逻辑回归模型作为基线也就是baseline。为什么这样做两点原因逻辑回归模型简单、训练速度快、可解释性强可以通过查看特征系数来理解特征的方向和影响baseline的意义在于给后续的复杂模型提供一个立脚点——如果复杂模型表现还不如逻辑回归那说明问题出在数据或特征上而不是模型复杂度不够代码非常直接from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score X df_scaled.drop(income, axis1) y df_scaled[income] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy) model LogisticRegression(max_iter1000, C1.0) model.fit(X_train, y_train) y_pred model.predict(X_test) print(准确率:, accuracy_score(y_test, y_pred)) print(精确率:, precision_score(y_test, y_pred)) print(召回率:, recall_score(y_test, y_pred)) print(F1分数:, f1_score(y_test, y_pred))你会得到一个准确率在80%左右的模型这个结果已经比“闭眼猜”也就是预测所有人收入不超过5万美元的准确率约为76%要好不少。4.2 逻辑回归结果之外的收获影响收入的关键特征逻辑回归一个特别大的好处是可以直接输出特征系数。系数越大说明该特征对预测收入的正向影响越强系数越小负向影响越强。我在实际跑的时候得到的结果大致是capital_gain资本收益、education_num教育年限、hours_per_week每周工作时长排在前列这些和我们的直观认知高度一致。但这里也有一个容易误读的地方capital_gain这个字段的特征系数很大甚至远远超过其他特征这会不会有问题实际上Adult数据里大部分人的capital_gain是0只有少数人特别高这种强偏态分布在标准化之后会让逻辑回归对它产生较大依赖。这种情况不算错误但你需要心里有数。适合的做法是查看一下这个字段的分布根据需要尝试做log变换或干脆去掉再训练一次看看效果变化——这样能对特征的重要性有更深刻的理解。4.3 SVM和决策树在同一份数据上的表现既然热搜词里出现了“SVM”和“决策树”我就一并聊聊这两个经典模型。先试SVMfrom sklearn.svm import SVC svm_model SVC(kernelrbf, C1.0, gammascale) svm_model.fit(X_train, y_train) y_pred_svm svm_model.predict(X_test) print(SVM 准确率:, accuracy_score(y_test, y_pred_svm))SVM的效果通常比逻辑回归好一些准确率可以达到85%左右但训练时间也会明显增加——尤其是在特征维度比较多的情况下。C和gamma这两个超参数是关键C控制误分类的惩罚力度gamma控制RBF核的影响范围它们的组合对结果影响很大如果不调好效果可能反而不如逻辑回归。这里也不妨用一下GridSearchCV做网格搜索找到合适的参数组合from sklearn.model_selection import GridSearchCV param_grid {C: [0.1, 1, 10], gamma: [scale, 0.01, 0.1]} grid GridSearchCV(SVC(kernelrbf), param_grid, cv5, scoringf1) grid.fit(X_train, y_train) print(Best params:, grid.best_params_) print(Best score:, grid.best_score_)接下来是决策树。决策树的一个特点是几乎不需要做特征缩放因为它做的是if-else式的划分不依赖距离度量。我用决策树跑出来的准确率大概在82%左右略低于SVM。但决策树的优势是可以绘制树的结构具有极强的可解释性而且也可以很容易地用调参策略剪枝参数、最小样本数等来防止过拟合。三大模型放在一起比较的话模型准确率训练速度可解释性是否需要特征缩放逻辑回归~80%极快好需要决策树~82%快最好不需要SVM(RBF)~85%慢差需要这个对比告诉你一件事没有绝对“最好”的模型只有最符合你需求的模型。如果你要的是一个能向业务方解释的模型决策树和逻辑回归显然比SVM更合适如果追求精度且不打算解释SVM可以做得不错。这也就是为什么这个案例值得你完整跑一遍——你会在对比中理解机器学习算法选择的真正逻辑。5. 模型评估与调参跑通Demo之后才是实战的开始5.1 准确率骗人的时候从混淆矩阵说起如果只看准确率上面任何一个模型“看起来都还可以”。但就像我前面提过的——Adult数据集并不完全平衡大概76%的样本收入在5万美元以下。如果你写一个“永远预测低收入”的模型准确率也有76%。所以准确率并不是一个绝对可信的指标至少在这个数据上不是。真正要看的指标有这几个精确率Precision预测为正类的样本里有多少是真的正类召回率Recall真正的正类样本里模型成功找出多少F1分数精确率和召回率的调和平均两者兼顾AUCROC曲线下的面积衡量模型把正负样本区分开的能力对收入预测这个场景我个人认为召回率更值得关注——因为如果模型的目标是定位“高收入人群”那么少报漏掉真正的高收入者比多报把低收入者误判为高收入代价更大。这取决于你的业务目标没有标准答案。来看混淆矩阵from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay cm confusion_matrix(y_test, y_pred) disp ConfusionMatrixDisplay(confusion_matrixcm) disp.plot() plt.show()输出结果会告诉你模型在哪些样本上容易犯错。我跑完之后注意到模型更容易把高收入者预测为低收入也就是漏报率偏高。原因很简单——高收入样本在数据集中占比本来就少模型在训练时见到的正样本不够多自然学不好它的“样子”。5.2 对付类别不平衡的三板斧知道了问题在类别不平衡上接下来的处理手段就有方向了。第一板斧改评价指标不盯准确率改看F1和AUC。第二板斧调阈值。模型输出的其实是一个概率值默认以0.5为阈值来判断正负类。如果你更在意召回率可以把阈值降低比如0.3这样更多的样本会被判为正类召回率就上去了但精确率会下降。一升一降你需要根据自己的业务场景来权衡。y_pred_proba model.predict_proba(X_test)[:, 1] y_pred_custom (y_pred_proba 0.3).astype(int)第三板斧用采样手段调整训练集。常用的有SMOTE合成少数类过采样技术和随机欠采样。随机欠采样是从多数类中随机抽出一部分样本使正负样本比例趋于均衡SMOTE则是人为合成新样本对少数类进行扩充。采样手段适合类别极度失衡的场景但它也有自己的代价——过采样容易引入噪声数据欠采样则可能丢失多数类的有用信息。所以在我自己的实践中优先调阈值不行了再考虑采样方法。5.3 交叉验证让你对模型效果更有信心初学者最容易犯的一个错误就是只用一次训练/测试划分来评估模型——运气好的时候分数高运气差的时候分数低完全没法稳定复现。解决这个问题靠交叉验证。交叉验证的基本思想是把训练数据分成K份每次用K-1份训练、1份验证轮流K次最后把K次结果取平均。这样做的好处是每一份数据都被用于验证过评估结果更稳定、更可信。from sklearn.model_selection import cross_val_score scores cross_val_score(model, X_train, y_train, cv5, scoringf1) print(CV scores:, scores) print(Mean F1:, scores.mean())我在实际项目中通常会先跑交叉验证觉得分数稳定了再在留出的测试集上做最终评估。这个习惯帮我避免了好几次“模型线下表现很好、上线却拉胯”的问题。6. 那些网上没人明说的事我的踩坑记录说到底机器学习实战学的不只是算法更是这些踩坑经验。有些坑你不亲自走一遍真的很难避开我把我自己遇到的几个典型问题分享出来希望你能少走点弯路。6.1 数据集划分的“先缩放再划分”还是“先划分再缩放”这个问题我专门拿出来讲是因为它太容易被忽略。严谨的做法一定是先划分训练集和测试集再在训练集上做scaler.fit然后分别transform训练集和测试集。如果你先对整个数据集做了标准化再切分训练集和测试集测试集的信息其实已经被“偷看”进了训练过程这会导致你的准确率评估虚高给后续上线埋下隐患。6.2 网格搜索与交叉验证的搭配网格搜索和交叉验证是很好的搭配但要注意如果你用的是GridSearchCV它在内部已经把交叉验证做完了所以不需要在它的结果之上再手动进行一次交叉验证评估。直接用grid.best_estimator_在测试集上评估一次就行否则会重复劳动还容易混淆结果。同样的道理也适用于随机搜索。# 正确做法 best_model grid.best_estimator_ final_pred best_model.predict(X_test)6.3 类似案例头歌平台实训任务的经验迁移和这个案例非常相似的任务我在头歌平台上见过不少包括线性回归、逻辑回归、决策树、K-Means聚类这些实训它们的核心流程基本都是“数据加载 → 清洗 → 特征工程 → 模型训练 → 评估”。很多同学做完一个任务发现自己只会“照着填空”换一份数据就不会做了。根本原因就是没把底层流程吃透——只是记住了代码没理解每一步在解决什么问题自然也不会迁移到新问题上。我建议你做完这个项目之后可以试着换一个数据集比如泰坦尼克号生存预测、鸢尾花分类重新跑一遍同样的流程你会发现一旦流程熟悉了剩下的其实只是换汤不换药。如果身边有其他同样入门的朋友还可以互相给对方数据让对方做预测——这种“出题-做题”的练习方式对巩固机器学习应用流程非常有帮助。6.4 从简单的贝叶斯、K-Means到前沿这个案例的延伸方向当你能独立跑通这个二分类案例之后还可以尝试几个延伸方向。一是聚类视角用K-Means对收入数据进行无监督聚类看看能不能在没有标签的情况下自然地区分高收入和低收入人群。二是多分类任务把收入从二分类扩成多分类比如低收入、中等收入、高收入体验一下多分类学习与二分类的差异。三是关注一些较新的方向比如物理约束的机器学习它把物理定律作为约束条件嵌入到神经网络训练中在一些工程场景下能大幅减少对数据的依赖这也是我比较感兴趣的方向。当然这几个方向难度各有不同。聚类相对容易上手当成练手项目很合适多分类就是在现有数据上改几个参数的事物理约束的机器学习需要的理论基础就深一些适合有余力再深入。还是那句话——先跑通一个完整流程再谈扩展不要贪多。7. 给新手的最后几句实在话如果你准备开始做第一个机器学习实战项目我最诚恳的建议只有三条。第一条不要追求最新最好的模型先把逻辑回归、决策树跑到熟练。能对一个简单模型做全面的特征分析、评估、调参你对机器学习应用流程的理解就已经超过大半初学者了。第二条从kaggle或者UCI上找一个适合入门的免费公开数据集完整地跑通一遍数据加载、清洗、特征工程、模型训练、评估这个全流程。中间遇到报错不要怕把报错信息完整复制到搜索引擎里你会找到比我在这篇文章里写的更多的答案。关键是你要真的动手去查。第三条记录你的每一次尝试。我在跑这个案例时做了一个简单的实验记录表内容包括用了什么特征、什么模型、什么参数、评估结果如何。训练到后面你就会发现这份记录远比任何教程都珍贵它能帮你快速定位哪些改动有效、哪些改动无效避免重复踩坑。我的看法是机器学习入门最核心的不是算法的难度而是完整经历的深度。你完完整整地跑通一个案例之后就会建立那个连接知识和实践的桥梁再去看其他的项目会发现自己突然“开窍”了——那些曾经看不懂的代码、听不懂的名词一下子都有了具体的落点。这个从“好像懂了”到“真会了”的跨越就是一个又一个亲手完成的项目堆出来的。本文还有配套的精品资源点击获取
返回列表