ARTICLE DETAIL

资讯详情

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

机器学习入门必练:三道综合题串起数据清洗、建模与评估全流程

机器学习入门必练:三道综合题串起数据清洗、建模与评估全流程 1. 三道综合练习题的设计思路为什么要把零散技能串起来先说一下背景。我最近在带几个刚入门机器学习的朋友发现一个特别普遍的问题单独讲线性回归、讲特征处理、讲模型评估每个人都能听懂代码也能跑通。但一到了需要独立完成一个完整小项目的时候就开始卡壳不知道从哪里下手也不知道各个环节要怎么衔接。这就是典型的“知识点都会综合题不会”。我自己当年学的时候也这样看教程觉得什么都简单真让自己从零写一个完整的处理流程才发现到处都是窟窿。所以后来我带人的时候习惯把多个独立技能点揉进三道综合练习题里让初学者在“做题”的过程中把整个链条走通。这三道题的设计初衷很简单每一道题都不是单一知识点而是把数据获取、预处理、建模、评估、结果解读串成一条线。题目难度是递增的从有较为固定的流程到需要自己做一些选择和判断再到必须自己定义问题。每一道题都保留了“做不出来”的空间也就是给学习者留出犯错的机会因为综合能力的提升基本都发生在排查错误的过程中。下面这三道题我已经带着好几批人完整跑过反馈比较真实。题目本身不难但每一步都有讲究。我会把题目要求、设计目的、参考思路和最容易踩的坑一起写出来。2. 练习题一电商用户购买行为分析从数据清洗到特征筛选这是三道题里流程最固定的一道适合第一次接触完整项目的人。它考察的是数据预处理和特征工程的基本功不需要太多模型层面的技巧。2.1 题目要求与数据说明数据是我模拟的一份电商平台用户行为记录一共5000条字段包括user_id用户IDage年龄gender性别0/1income年收入万元time_spent最近30天在平台上的浏览时长小时pages_viewed最近30天浏览页面数cart_added最近30天加入购物车次数previous_purchases过去一年购买次数purchased是否完成购买0/1这是标签列题目的要求如下读取数据做基础的数据探查包括数据类型、缺失值、分布情况。对明显异常的数据做处理例如年龄小于10岁或大于100岁、收入为负数、购买次数的极端值。对清洗后的数据做特征筛选选出你认为对“是否购买”最有影响的3个特征说明理由。将数据按7:3划分为训练集和测试集用逻辑回归训练一个二分类模型。输出模型在测试集上的准确率、精确率、召回率和F1值并解释这四个指标在这里分别意味着什么。2.2 这道题到底在考什么很多人拿到题目第一反应是“赶紧训练模型”其实这道题真正的考察点在前两步。数据清洗是第一个坎。原始数据里我故意混了几个问题样本比如有个用户年龄是198录入错误还有两个用户的收入是负值。如果不处理后面的特征筛选和模型训练都会受影响。逻辑回归对异常值并不像树模型那么鲁棒个别极端值会把系数拉偏。第二个考察点是特征筛选。很多初学者喜欢把全部特征一股脑塞给模型看起来“没有浪费信息”实际上噪声特征会稀释有效信号的权重。这道题里time_spent、pages_viewed、cart_added三者之间存在明显的相关性同时放进模型会引入多重共线性导致逻辑回归的系数解释变得不可靠。我刚带的那批人里有一个学员把8个特征全部丢进模型跑出来的F1是0.42去掉冗余特征后只保留3个F1反而提到了0.51。特征少了效果反而好了这就是综合题想让你体会的东西。2.3 参考实现与常见坑点这里给一个精简版的参考代码用的都是最基础的库import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import StandardScaler from sklearn.metrics import classification_report, accuracy_score # 1. 读取数据 df pd.read_csv(user_behavior.csv) print(df.info()) print(df.describe()) # 2. 清洗异常值 df df[(df[age] 10) (df[age] 100)] df df[df[income] 0] df df[df[cart_added] 0] # 3. 特征选择依据相关性热力图人工筛选 features [time_spent, pages_viewed, cart_added] X df[features] y df[purchased] # 4. 标准化 划分数据集 scaler StandardScaler() X_scaled scaler.fit_transform(X) X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.3, random_state42 ) # 5. 训练与评估 model LogisticRegression(max_iter1000) model.fit(X_train, y_train) y_pred model.predict(X_test) print(accuracy_score(y_test, y_pred)) print(classification_report(y_test, y_pred))这里有几个很典型的坑我必须单独拎出来说第一标准化必须在划分训练集和测试集之前完成吗不是必须但如果你先划分再分别标准化一定要分别fit训练集和测试集不能拿整个数据集的均值和标准差去变换。我见过有学员用scaler.fit_transform(X)处理全部数据后才划分这在严格意义上算数据泄露因为测试集的信息已经参与了训练集预处理参数的生成。这道题数据量小影响不大但养成坏习惯后面很麻烦。第二逻辑回归的max_iter。默认值是100特征一多或者数据没标准化很容易报“ConvergenceWarning”。我让学员加上max_iter1000是为了让他们早点避开这个莫名其妙的问题免得在警告里浪费时间。第三类别不平衡。这份模拟数据里purchased1的样本大约占35%不算极端不平衡但精确率和召回率仍然会出现明显差异。我特别要求学员把classification_report完整读一遍就是为了让他们意识到只看准确率会骗人假设所有用户都不买准确率也有65%。3. 练习题二房价预测中的回归建模把评估指标吃透第二道题比第一道往前推了一步从分类问题切换到回归问题考察的是连续值预测的完整流程并且要求学习者在多个建模方案之间做比较、做选择。3.1 题目要求与数据说明数据是一份模拟的房屋销售记录一共8000条特征包括sqft_living居住面积平方英尺sqft_lot占地面积bedrooms卧室数bathrooms卫生间数floors楼层数waterfront是否临水0/1condition房屋状况评分1-5year_built建造年份price成交价格美元这是标签列题目要求如下完成数据的缺失值处理和类型检查。分别用线性回归、决策树、随机森林三种模型训练使用5折交叉验证评估表现。使用RMSE均方根误差和R²作为评估指标比较三个模型选出最优方案并解释理由。对最优模型产出特征重要性排序分析哪些因素对房价影响最大。3.2 为什么要求用三个模型做对比这道题设置三种模型的根本目的不是让学习者“炫技”而是让他们直观体会不同模型对同一份数据的不同拟合方式。线性回归假定特征与目标是线性关系好解释但容易被非线性关系限制。决策树能捕捉非线性但单棵树容易过拟合。随机森林用多棵树投票泛化能力通常最强但代价是可解释性降低。三种模型放在一起交叉验证学习者能亲眼看到“效果好的模型未必是逻辑上最喜欢的模型”这一事实。我在设计数据时也做了手脚sqft_living和price之间的关系实际上不是完全线性的大面积房子的边际价格递减。线性回归在这份数据上会系统性低估高价房、高估低价房。随机森林能捕捉这种形态所以最终胜出的往往是随机森林。3.3 关键的校验点与参考实现参考代码框架如下import pandas as pd from sklearn.model_selection import cross_val_score, KFold from sklearn.linear_model import LinearRegression from sklearn.tree import DecisionTreeRegressor from sklearn.ensemble import RandomForestRegressor from sklearn.metrics import mean_squared_error, r2_score import numpy as np df pd.read_csv(house_prices.csv) # 缺失值处理数值列用中位数填充 numeric_cols df.select_dtypes(includenp.number).columns df[numeric_cols] df[numeric_cols].fillna(df[numeric_cols].median()) X df.drop(price, axis1) y df[price] # 统一用KFold保证三个模型在同一次划分下对比 kf KFold(n_splits5, shuffleTrue, random_state42) models { LinearRegression: LinearRegression(), DecisionTree: DecisionTreeRegressor(max_depth8, random_state42), RandomForest: RandomForestRegressor(n_estimators200, random_state42) } for name, model in models.items(): rmse_scores np.sqrt(-cross_val_score( model, X, y, cvkf, scoringneg_mean_squared_error )) r2_scores cross_val_score(model, X, y, cvkf, scoringr2) print(f{name}: RMSE{rmse_scores.mean():.2f} (±{rmse_scores.std():.2f}), fR2{r2_scores.mean():.4f})在带练过程中这道题反馈最集中的是两个点。第一个点是RMSE和R²到底看哪个我给出的口径是RMSE告诉你“平均错多少钱”单位真实、直观R²告诉你“模型解释了多大比例的变化”介于0到1之间。实际做项目的时候两个都要看因为一个冷静的“绝对值”加上一个相对的“拟合优度”才能完整描述模型质量。只盯着R²不放的人很容易被高R²误导——R²0.9看起来很好但RMSE如果等于5万美元对于均价30万的市场来说依然是不小的误差。第二个点是为什么决策树要限制深度。初学者写决策树时很容易不设max_depth或者设得过大然后发现训练集上近乎完美、测试集上一塌糊涂。我故意在参考代码里写了max_depth8就是希望学习者看到限制深度前后的差异自己体会到正则化在树模型中的作用。这个体验比从书上看一百遍“决策树容易过拟合”都要深刻。3.4 一个容易忽视的细节特征尺度线性回归这类模型对特征尺度敏感但树模型完全不敏感。第二道题里我不要求对特征做标准化原因是三种模型混在一起对比树模型不需要而线性回归如果做了标准化对比的公平性会变得含糊。实际项目中你应该对每个模型单独做数据预处理但在学习对比阶段我刻意让“不处理”成为统一基线这样不同模型的差异来自模型本身而不是预处理方式。最后补一刀特征重要性分析要基于随机森林的feature_importances_属性数值含义是“在所有决策树的分裂中该特征带来的不纯度减少的归一化总和”。它不是一个严格的因果指标但作为排序参考足够用了。很多初学者会拿它当“事实”去解读这不对。它只告诉你“模型用这个特征的程度”不告诉你“因为这个特征导致房价上涨”。4. 练习题三客户流失预警端到端项目从问题定义到简单策略落地前两道题把分类和回归的基础流程各走了一遍第三道题直接升级为一个“半开放”的端到端练习。我只给业务背景和数据不给明确的建模步骤要求学习者自己定义问题、自己选方案、自己给出结论和落地建议。4.1 题目要求与业务背景模拟场景是一家电信运营商提供了一份近一年的客户数据字段包括customer_id客户编号tenure在网时长月monthly_charges月均消费total_charges累计消费contract_type合约类型按月/按年payment_method付款方式tech_support是否订购技术支持服务0/1online_security是否订购在线安全服务0/1churn是否流失0/1题目要求只有三条自行完成探索性数据分析找出至少两个与流失强相关的特征说明你的判断依据。建立一个可以预测客户流失概率的模型自行选择模型类型、评估指标和阈值。针对模型的预测结果给出三条可落地的运营干预建议。4.2 这道题和前面两道的本质区别前两道题模型选型、评估方式、步骤顺序都已经给定了学习者要做的是“执行”。第三道题的关键在于“决策”——你得自己想清楚什么是正样本、怎么处理类别不平衡、用什么阈值判定流失风险、以及“模型预测出高风险客户”之后怎么办。这道题特别容易暴露一个思维误区把churn当成一个干净的二分类标签就完事了完全不看正负样本比例。我设计的这份数据中真正流失的用户只占26%左右存在明显的不平衡。直接丢给模型训练绝大多数初学者会得到一个“把所有用户都预测为不流失”的模型准确率74%看起来不错实际一点用都没有。处理类别不平衡的常见做法有使用class_weightbalanced、采用AUC作为评估指标、调整判定阈值。这里我建议学习者至少尝试前两种。使用class_weight让模型在训练时给少数类更高的惩罚权重AUC则天然不受阈值影响反映的是模型区分正负样本的能力。4.3 参考实现与分析思路完整代码这里不铺开只给出关键决策点的处理方式。from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import roc_auc_score, classification_report # 使用class_weight处理不平衡 model RandomForestClassifier( n_estimators200, class_weightbalanced, random_state42 ) X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.3, random_state42) model.fit(X_train, y_train) y_proba model.predict_proba(X_test)[:, 1] # 看AUC而不是默认的准确率 print(fAUC: {roc_auc_score(y_test, y_proba):.3f}) # 按0.3作为流失风险阈值而不是默认的0.5 y_pred_custom (y_proba 0.3).astype(int) print(classification_report(y_test, y_pred_custom))这里我说一下为什么把阈值从0.5调到0.3。流失预测这个场景里把“有流失风险”的客户错判为“安全”的代价远高于把“安全客户”误判为“高风险”——前者直接损失一个客户后者最多浪费一次运营关怀的资源。调低阈值等于让模型更敏感宁可多捞一些人去运营关怀也不能放过真正的流失预警对象。这个思路在业务上叫“代价敏感学习”虽然题目里没提这个词但能把阈值调低并且说清楚原因的学员基本上就理解了分类模型的本质——预测概率之后阈值是一个业务决策不是模型的一部分。4.4 三条干预建议如何写才显专业这个环节最考验综合能力。很多学员写出来的建议是“对高风险客户提供折扣”看起来很对但等于没说。我给学员的反馈标准是每一条建议都必须包含“针对谁、做什么、预期为什么有效”三个要素。我比较推荐的写法是针对contract_type为按月签约且tenure低于6个月的高风险客户推动他们转换为年约。原因是在网时长短的客户黏性最低合约锁定能显著降低短期流失概率。针对未订购tech_support或online_security的中年高消费客户定向推广技术服务包。原因是产品绑定数量影响切换成本绑定越深流失门槛越高。对预测流失概率超过0.7的客户建立专属客服一对一回访机制回访时重点排查账单争议和服务故障。原因是极低风险客户不需要打扰极高风险客户的流失原因往往已经具体化批量折扣解决不了个性化问题。这里多说一句第三道题不要求你把这些建议真正落地实施但必须想清楚“模型输出之后业务动作是什么”。这是我坚持加上这个环节的原因——模型预测本身不产生价值只有预测驱动了决策和行动才有价值。很多初学者做完模型就停下来了觉得自己完成了项目其实只完成了前半截。5. 三道题做完之后判断你是否真正入门的三个标志这三道综合练习题带了几批人之后我总结出几个“是否真正入门”的判断标志不是看分数而是看行为方式的变化。第一个标志是拿到数据不再着急写模型代码而是先花时间看数据长什么样。这个转变非常关键。初学者拿到数据集的第一反应是“快让我跑个模型看看”做过几道综合题之后才会明白数据质量决定了模型上限模型只是逼近这个上限的工具。我见过一个学员做完第一道题后说“原来花40分钟清洗数据、画分布图比花40分钟调模型参数有意义多了。”这句话就是入门的信号。第二个标志是开始用交叉验证替代单次划分。单次划分随机性强一次效果好不能说明模型好。5折交叉验证让你对模型的稳定性有了概念——看到±标准差之后你才会知道自己的模型效果是“稳定地好”还是“碰运气地好”。这个认知差异会在实际项目里救你很多次。第三个标志是能说清楚“这个模型在这个业务场景里怎么用”。能跑通代码的人很多能解释“阈值为什么这么设”“特征重要性排序到底意味着什么”“预测结果如何驱动运营动作”的人才是真正能把技术转化为价值的人。第三道题的存在逼着学习者跨过代码去思考模型和业务之间的那一层连接。最后说一句实在的这三道题不要急着一天内全部刷完第一题和第二题各留两天消化第三题给自己留三天。综合练习的价值不在“做出来”而在“做的时候卡住了多久、又是怎么爬出来的”。那些卡壳和排查的过程才是真正长本事的部分。
返回列表