ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Python机器学习入门:从数据预处理到模型构建全流程指南

Python机器学习入门:从数据预处理到模型构建全流程指南 想说说“Python机器学习入门指南从数据预处理到模型构建”这件事。你把这个标题往搜索引擎里一扔能翻出几百篇教程但大多数都在讲“怎么调包”很少有人把真正要命的环节讲透——喂给模型的每一列数据到底该怎么处理、为什么这样处理、踩了什么坑。我做了几年机器学习相关的工作从最开始跑demo都费劲到现在能独立完成一个完整的建模流程最大的感受是入门机器学习真正的分水岭不是算法而是数据处理和pipeline搭建。这篇博文我打算从一个完整的项目视角出发把从原始数据到模型构建的关键环节逐个拆开不绕弯子不讲数学推导只讲实操。里面会用真实的代码片段、参数对比和踩坑记录尽量让你看完之后能照着做跑通自己的第一个端到端项目。不管是刚看完吴恩达课程想动手的、被期末复习折磨的还是工作中被迫开始学机器学习的同学这篇都应该对你有用。1. 数据是机器学习的起点先别急着跑模型很多新手最大的误区是拿到数据立刻model.fit()。我之前也这样觉得“先把模型跑起来再说”。直到有一次做客户流失预测数据里有一个“是否已离网”字段被我直接当特征喂给模型结果准确率飙到97%实际上模型什么都没学会只是在“偷看答案”。这种教训特别深刻也让我彻底理解了为什么说数据决定模型上限算法只是逼近这个上限。1.1 模型是厨师数据是食材预处理是洗菜切菜打个比方你请了一个米其林大厨模型算法他再厉害拿到发霉的菜原始数据也做不出好菜。数据预处理就是洗菜、切菜、去掉烂叶子、按分量配好。你要是不做模型要么学不动要么学到一堆噪音。GIGO原则在机器学习里体现得淋漓尽致——garbage in, garbage out数据是垃圾输出必然是垃圾。所以真正规范的机器学习项目流程一般长这样业务问题 → 数据采集 → 数据清洗 → 特征处理 → 建模 → 评估 → 调优 → 上线。预处理在中间这环经常要占掉60%-70%的时间。这不是效率低而是现实里的数据大多长这个鬼样子有空值、有异常值、有字符串、有重复行甚至还有编码乱掉的情况。1.2 机器学习项目的标准流程全链路是什么我常说机器学习的完整链路就是一个“由数据到决策”的过程。业务层面要把“怎么减少用户流失”“怎么预测房价”转化成数学问题——“二分类”“回归”。数据层面要处理缺失值、剔除异常值、做特征编码和缩放。模型层面才是训练和调参。这个流程听起来简单但每一步都有坑我见过不少人在模型调参上耗了两周回头发现是特征工程没做好。入门阶段你不必想得太远但要先建立一个全貌认知模型构建只是整条流水线的一个工位不是全部。所以后面的内容我会把前期准备、数据清洗、特征处理都当作重点来展开这些才是容易拉开差距的地方。1.3 工具链准备环境搭好后面才不闹心工欲善其事必先利其器。入门机器学习工具链其实很轻量Pythonpandasnumpyscikit-learnmatplotlib或seaborn就够用了深度学习那套先不急。环境这块我推荐用Anaconda并不是因为它多高级而是它内置了Python环境和大量数据科学库对新手友好。我在项目里一般是这么装的conda create -n ml python3.9 conda activate ml pip install pandas numpy scikit-learn matplotlib seaborn从我个人的经验看Python版本和包之间的兼容性问题是比算法更早给你下马威的东西。比如老项目还在用Python 3.6新装了scikit-learn1.2版本之后直接不兼容报错一堆。所以建议新项目统一使用3.9或3.10少折腾。装好了之后用import pandas as pd试一下不报错就说明环境没问题。下面我们来进入正题——数据预处理。2. 数据预处理把脏数据洗成模型能吃的样子在热词里有人搜“机器学习中的数据处理是什么”这可能就是最核心的问题。数据预处理并没有统一标准但大的方向上我们就是在做四件事看清数据 → 补缺失 → 编特征 → 做缩放。每一个环节都有讲究不是拿函数瞎套。2.1 第一步拿到数据先摸清家底不管数据是从公司数据库里拉出来的表格还是Kaggle上下载的公开数据集到位之后第一件事不是跑模型而是用最快的方式摸清它的结构。我自己常用的三板斧import pandas as pd df pd.read_csv(customer_data.csv) # 1. 看前5行确认字段长什么样 print(df.head()) # 2. 看整体信息包括字段类型、非空值数量 print(df.info()) # 3. 看数值型特征的分布情况 print(df.describe())df.info()这一步最重要它把每一列的数据类型和非空个数列得清清楚楚。比如age列下面显示65533 non-null另一列income却只有43022 non-null说明income少了一大截后面得处理。还有一个必须做的动作看目标变量分布。比如你要预测客户流失看一下流失和未流失的占比执行df[churn].value_counts()。如果发现极度不平衡像95%都是未流失那你后面就要考虑采样策略否则模型学出来就是个“全猜未流失”的废物。2.2 缺失值处理删除不是万能的缺失值这关新手最容易犯两个极端要么不管要么直接整行删。这两种做法都太简单粗暴。缺失率的差别决定了完全不同的处理策略缺失情况建议处理方式单列缺失比例 5%直接用均值/中位数填充简单高效单列缺失比例 5%-30%视特征重要性选择中位数填充、或建立简单模型预测填充单列缺失比例 30%要考虑该特征是否还有存在价值整行多列缺失如果脏行太多直接删除反而更干净代码层面最常用的就是填充# 用中位数填充数值特征 df[age].fillna(df[age].median(), inplaceTrue) # 用众数填充类别特征 df[education].fillna(df[education].mode()[0], inplaceTrue)这里有个细节数值特征我优先用中位数而不是均值。因为均值容易被极端值拉偏——假设一个客户年龄被错误录成200岁均值一下就从35跳到40而中位数基本不受影响。这条经验是我在实际项目里被坑出来的。2.3 特征编码让非数值型数据“说人话”模型不认识“本科”“硕士”“博士”这种字符串只认识数字。所以编码是必须的。但编码方式有讲究不能一股脑全用LabelEncoder。性别、颜色这种无序类别如果用0、1、2去硬编模型会误认为2比1大、1比0大这种“大小关系”在实际语义里是不存在的。我一般这样选择二分类类别如性别男/女直接映射成0/1LabelEncoder或map都行。无序多分类如城市、职业用OneHotEncoder做独热编码每个取值变成一个0/1列。有序类别如学历小学初中高中本科研究生用LabelEncoder反而合理因为本身就有顺序。在sklearn里用ColumnTransformer可以一次性搞定混合编码不用手动一个一个处理from sklearn.compose import ColumnTransformer from sklearn.preprocessing import OneHotEncoder, StandardScaler numeric_features [age, income, tenure] categorical_features [education, city] preprocessor ColumnTransformer([ (num, StandardScaler(), numeric_features), (cat, OneHotEncoder(handle_unknownignore), categorical_features) ])注意handle_unknownignore这个参数我强烈建议加上。它能让模型在预测阶段遇到训练集里没出现过的新类别时不直接报错而是忽略掉。上线后数据随时可能多出来一个“city”取值不加这个参数你就会在预测那天被线上报错搞到怀疑人生。2.4 特征缩放标准化和归一化不是一回事特征缩放是我见过新手最容易忽视的一步。有些sklearn的树模型决策树、随机森林对尺度不敏感你不缩放也能跑但所有基于距离或梯度的模型——逻辑回归、SVM、KNN、神经网络——都强烈依赖特征缩放。如果income取值范围是0-100万age取值范围是0-100这两个特征的“重要性”会被量纲扭曲模型会默认收入的作用大得多尽管实际上这可能是个错误假设。两种最常用的方式标准化StandardScaler把数据变成均值为0、方差为1的分布。公式是(x - 均值) / 标准差。适合数据本身近似正态分布的情况。归一化MinMaxScaler把数据压缩到[0,1]区间。公式是(x - min) / (max - min)。适合数据分布不明显或需要保留原始边界的情况。实操中我基本上无脑用StandardScaler除非业务场景有明确的范围要求比如图像像素值已经天然在0-255之间。而且要记住缩放器只能用训练集fit再同时transform训练集和测试集千万不能先对整个数据集fit再划分否则会造成信息泄漏下面讲模型的时候我会再展开。2.5 类别不平衡一个容易被忽略的坑有些场景里正负样本比例极其悬殊。比如信用卡欺诈正常交易可能占比99.8%欺诈只有0.2%。如果不做任何处理模型只需要把所有样本预测成“正常”准确率就是99.8%看起来非常漂亮但实际上一个欺诈都没拦住。处理类别不平衡我常用的办法有三个class_weight参数、过采样SMOTE等和换评估指标。最简单的入门做法是先给模型设置class_weightbalanced让少数类获得的权重更高from sklearn.linear_model import LogisticRegression model LogisticRegression(class_weightbalanced, max_iter1000)这个“balanced”会根据样本占比自动计算权重一行代码就能改善模型对少数类的关注。但这只是第一步评估时绝对不能用准确率得看召回率、精确率、F1分数和ROC-AUC这部分后面详细讲。3. 模型构建从第一个baseline到逐步优化数据洗得差不多了才轮到模型登场。这部分我强烈建议新手从简单的线性模型开始而不是一上来就整随机森林、XGBoost。逻辑回归就是绝佳的baseline——训练快、可解释性强还能通过它的系数反推特征方向。先用简单模型跑通全流程再逐步替换复杂模型这是我在项目里一直坚持的节奏。3.1 训练集和测试集必须分家还要分得有讲究模型构建的第一步是划分数据集。我是说“分家”这件事听起来简单到不值一提但里面有个细节很多人会忽略要不要做分层抽样。from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy )stratifyy就是做分层抽样它能让训练集和测试集里目标变量的比例保持一致。比如整体流失率是20%分完之后两边都接近20%不会出现训练集里流失率25%、测试集里流失率15%的尴尬。类别不平衡的数据集这个参数尤其重要。random_state42是固定随机种子。设它是为了结果可复现——你跑十次每一次的划分方式都一样方便对照调参效果。不设置的话每次运行结果都不同你都不知道模型变好了还是单纯因为数据切分不同。另一个关键点是先划分再做预处理。很多人习惯先对整个数据集填充均值、做标准化再切训练测试集这会造成严重的数据泄漏。正确顺序是先train_test_split再在训练集上fit预处理器然后transform训练集和测试集。用Pipeline能优雅地解决这个问题下面马上说。3.2 用Pipeline把预处理和模型打包成一整条流水线写机器学习代码最忌讳的是手动记住十几步操作然后测试集又照着重复一遍。又啰嗦又容易漏。Pipeline就能把这个流程打包成一个整体fit和predict都非常干净from sklearn.pipeline import Pipeline from sklearn.linear_model import LogisticRegression # 把前面建好的preprocessor拿过来后面接一个分类器 pipeline Pipeline([ (preprocess, preprocessor), (classifier, LogisticRegression(class_weightbalanced, max_iter1000)) ]) pipeline.fit(X_train, y_train) y_pred pipeline.predict(X_test)这个流水线式的写法好处太多了fit时自动在训练集上学习预处理参数均值、标准差、编码表predict时自动用同一套参数处理测试集。你再也不用担心测试集和训练集处理方式不一致的问题。这个习惯我建议从一开始就养成。3.3 拿“客户流失预测”完整走一遍构建流程为了不那么抽象我拿一个典型场景——银行客户流失预测——来串一下完整的流程。假设df里已经有三类特征数值特征年龄、余额、账户时长、类别特征地区、职业、目标列churn0/1。第一步分离特征与标签X df.drop(columns[churn, customer_id]) y df[churn]customer_id这种东西是唯一标识符对预测没任何帮助必须扔掉。但很多人会忘记。ID字段一旦进入模型模型就会把它当作超级强特征导致严重的过拟合。第二步划分数据然后实例化pipelineX_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) pipeline Pipeline([ (preprocess, preprocessor), (classifier, LogisticRegression(class_weightbalanced, max_iter1000)) ]) pipeline.fit(X_train, y_train)第三步评估from sklearn.metrics import classification_report y_pred pipeline.predict(X_test) print(classification_report(y_test, y_pred))这一步会输出精确率、召回率、F1分数等指标。逻辑回归一跑baseline就出来了。后面任何花哨的操作都要先赢过这个baseline才说明真的有用。3.4 从逻辑回归到随机森林什么时候该换模型逻辑回归训练极快、可解释性好但它有个硬伤对非线性关系的学习能力很弱。现实业务里特征和目标的关系很少是简单的线性加和。比如“年龄”对“流失概率”的影响往往不是单调的——年轻人流动大中年人稳定老年人可能又容易流失这条曲线用一条直线很难描述。这时候就该上树模型了。决策树天然能捕捉非线性关系和特征间的交互随机森林又通过多棵树投票的方式缓解了单棵树的过拟合。在表格数据上随机森林通常是个性价比很高的选择from sklearn.ensemble import RandomForestClassifier pipeline_rf Pipeline([ (preprocess, preprocessor), (classifier, RandomForestClassifier( n_estimators200, max_depth8, min_samples_leaf5, random_state42, class_weightbalanced )) ])n_estimators200代表200棵树max_depth8限制每棵树深度防止过拟合min_samples_leaf5要求叶子节点上至少有5个样本也是正则化手段。这三个参数是随机森林最常用的“防过拟合三件套”。对比一下逻辑回归的baseline你会发现随机森林的分数一般会更好看一些但如果你用默认参数不加约束训练集分数可能极高、测试集却拉胯那就是过拟合了。4. 模型评估与调优别被准确率骗了模型训练出来只是第一步更关键的是看它是不是真的学到了东西。很多人一看准确率90%就欢呼雀跃但90%可能是个假象。我曾经给一个保险公司做车险理赔预测正样本只占2%全都预测成“不会理赔”准确率照样98%然而业务上这模型毫无用处因为它一遍都拦不住真正的理赔风险。这就是为什么我把评估单独拿出来讲一章。4.1 混淆矩阵、精确率、召回率比准确率诚实得多准确率 (预测正确的样本数) / (总样本数)。它只在类别均衡时才有参考价值。更诚实的评估工具是混淆矩阵它能告诉模型到底犯了哪种错误预测为正预测为负实际为正TP真正例FN假负例实际为负FP假正例TN真负例基于混淆矩阵衍生出三个最常用的指标精确率Precision TP / (TPFP)模型说是正例的有多少是真的正例。类似“我说对了几个”。召回率Recall TP / (TPFN)所有真实正例中模型找出来多少。类似“该抓的抓到了几个”。F1分数精确率和召回率的调和平均兼顾两者。场景不同侧重点完全不同做欺诈检测宁可误伤好人也要把欺诈尽量找出来所以更看重召回率。做商品推荐推错了用户不点而已但推对了才有收益所以更看重精确率。很多新人直接拿accuracy_score交差这是不对的。4.2 交叉验证让模型多考几次试别靠撞大运前面我们用train_test_split一次性地划分训练集和测试集。这种单次划分有个问题结果可能依赖某一次运气。万一碰巧测试集里的样本都特别简单分数虚高你却以为模型很厉害。更稳妥的方法是交叉验证。k折交叉验证的基本思想是把数据切成k份每次拿k-1份训练、1份验证轮换k次最后把k次结果取平均from sklearn.model_selection import cross_val_score scores cross_val_score(pipeline, X, y, cv5, scoringf1) print(scores) print(平均F1, scores.mean())用f1而不是accuracy作为打分依据才更贴近前面提到的不平衡场景。交叉验证能让你对模型的真实水平有更稳定的判断而且它等于把数据用到了极致——每个样本都被当作验证集用过一次。缺点是训练k次时间成本高。数据量大时3折或5折就够了。4.3 过拟合与欠拟合模型在“背答案”还是在“学规律”我见过不少新手第一次调参就掉进过拟合的坑。训练集F1高达0.98测试集只有0.72。这时候基本可以断定模型把训练数据里的噪音也背下来了没有泛化能力就像学生考前把题目的答案背下来换一道类似但不完全一样的题就不会做了。对应地欠拟合是指模型太简陋训练集和测试集分数都很低属于“没学会”。处理过拟合的办法不外乎这些增加训练数据量数据多了噪音占比就小了。降低模型复杂度比如减小树模型的max_depth、增大min_samples_leaf线性模型则调低正则化强度对应的逆参数C。增加正则化逻辑回归里C1是默认C0.01表示更强的正则化会迫使系数向0收缩。早停法深度学习常用训练过程中监控验证集指标一旦开始变差就停。欠拟合的处理则恰好相反换更复杂的模型、增加特征或减少正则化强度。4.4 用GridSearchCV自动寻参解放你的双手调参是有章法的不是拿着参数瞎试。最经典的工具是GridSearchCV它会把你指定的参数组合全部跑一遍交叉验证自动选出最优组合。比如我常这样调from sklearn.model_selection import GridSearchCV param_grid { classifier__max_depth: [3, 5, 8, 10], classifier__n_estimators: [100, 200], classifier__min_samples_leaf: [2, 5, 10] } grid_search GridSearchCV( pipeline_rf, param_grid, cv3, scoringf1, n_jobs-1 ) grid_search.fit(X_train, y_train) print(最佳参数, grid_search.best_params_) print(最优交叉验证F1, grid_search.best_score_)注意参数名classifier__max_depth两个下划线连接的是Pipeline里步骤的名字。n_jobs-1表示用满所有CPU核心能大大加速网格搜索。我用这个方式跑过几十个参数组合比自己手动试省了不知道多少时间。5. 常见问题与排查技巧实录这部分是我最想分享的内容。网上教程通常把“正确做法”讲得头头是道但没人告诉你那些折腾了几个小时的报错是怎么解决的。我把自己在项目里踩过的坑、排查过的经典问题整理成下面的速查表你看一眼可能就少走一天弯路。5.1 数据泄漏是“虚假高分”的真凶这个坑我在开头就提过但值得专门拿出来强调。数据泄漏有两类一类是直接泄漏比如预测客户流失时把“是否已注销”放进特征另一类是间接泄漏比如对全量数据做了标准化或填充后再划分数据集。这两种情况都会让评估分数失真。我现在的习惯是写代码前先问自己三句话这个特征在预测时真的拿得到吗这个处理过程有没有用到测试集的信息ID类字段是否已经删除三句过了再继续动手。5.2 中文乱码和画图字体问题用matplotlib画图时如果图中标题、坐标轴是中文默认情况下会出现一堆方框乱码。这不是你代码写错了而是matplotlib默认字体不支持中文。解决方案很简单import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] FalseWindows下用“SimHei”基本都能解决。Linux服务器上可能需要安装中文字体比如fontconfig配合Noto Sans CJK。还有一个相关问题是“python画图横坐标太密集”——日期类的坐标轴动辄上百个刻度叠在一起解决方案是使用plt.xticks(rotation45)旋转标签或每隔N个刻度显示一次。5.3 类别特征取值过多怎么办城市、商品ID这类特征可能有成百上千个取值。直接OneHot会生成几百上千列训练慢且容易过拟合。我常用的办法有只保留出现频率最高的前K个类别剩下的统一归为“其他”或者把类别特征按目标变量的均值做编码target encoding但要注意这一步必须配合交叉验证做否则极易泄漏。5.4 新手高频报错速查表报错信息出现原因解决方案ValueError: Input contains NaN特征里有缺失值没处理用df.isnull().sum()逐列排查先填充或删除ValueError: could not convert string to float字符型数据没编码检查df.info()对非数值列做OneHot或LabelMemoryError数据一次性加载太大或OneHot列数爆炸分块读取、astype(float32)降低精度、稠密转稀疏矩阵ConvergenceWarning逻辑回归等迭代型模型没收敛调大max_iter或先做特征缩放ColumnTransformer报错“columns not found”传入的列名和DataFrame里对不上检查df.columns有没有空格或大小写差异每个报错后面都有个故事我就不一一展开了但你一定要形成习惯报错信息前两行永远最有用。别一报错就慌着贴代码去群里问先自己读一下报错90%的问题其实就是命名不一致、缺失值没处理、格式不统一这类小事情。一些只有动手做了才有的体会要我个人说的话入门阶段最重要的心态转变是别拿算法当宝藏拿数据和特征当主线。我现在带人做项目一定是从“拆解数据”开始练而不是从“拆解论文”开始。你要是能独立跑通一个从pd.read_csv()到GridSearchCV调优的完整流程再去看《机器学习》西瓜书里的理论、吴恩达的课程会发现那些知识突然都有了落点。以后再扩展可以往这几个方向走特征工程组合特征、时序特征、集成学习XGBoost、LightGBM、模型可解释性SHAP值以及把训练好的模型用Flask或者FastAPI包成一个接口服务。每一步都有很多坑但先把基础链路跑通才是最重要的一步。
返回列表