资讯动态

从数据清洗到线性回归:一份完整的数据分析作业实战记录

发布时间:2026/10/22 8:06:18 来源:尧图企业网站定制
第一次打开本地文件夹时看到Wk.2_HW这个名字我脑子里蹦出来的第一句话是又到了交作业的时候。Wk.2 是第二周HW 是 Homework说白了就是第二次实践作业。这份作业的任务书里给了一份模拟学习行为数据要求完成从数据清洗、探索性分析到线性回归建模预测的完整流程。下面记录的就是我当时从拆解需求、写代码、踩坑到最终提交的完整经历。如果你也正在做类似的数据分析作业或者只是想知道一份合格的Wk.2_HW应该长什么样这篇内容应该能给你一些参考。1. 拿到 Wk.2_HW 后我先做了什么1.1 文件名里其实藏着不少信息很多课程作业的命名方式都是类似的周次缩写加任务缩写。Wk.2_HW 一眼看上去平平无奇但它至少告诉了三件事这是第二周的任务它是独立作业大概率需要提交一份可运行工程和一份说明文档。不过真正决定工作量的是作业要求本身。我拿到的任务书里写了几条硬性要求第一将原始 CSV 数据清洗成可用于分析的格式第二对关键字段做不少于 5 个维度的探索性可视化第三用线性回归模型完成对连续目标的预测并评估模型效果第四整理成一份包含图表和结论的分析报告。这些要求放在第一周刚结束的背景下难度其实卡得很准不要求上复杂算法但要求把最基础的数据处理链路走通。如果只是照着教程敲一遍代码也能跑通但会出现很多隐蔽问题比如字段类型不对、可视化结果拿不出手、训练集和测试集泄露等。所以我拿到题目的第一反应不是开 Notebook 直接写而是先花半小时拆需求、列检查清单把所有交付物边界想清楚再动手。这一步看起来浪费时间实际是避免返工性价比最高的做法。1.2 作业需求还原与任务拆解把模糊需求转成可执行任务是我做这个作业过程中收获最大的一部分。我先把任务书里的四个要求拆成了具体子任务数据清洗检查缺失值、重复行、异常值、字段类型统一时间格式处理设备字段中的脏值。探索性分析对学习时长、完成率、测验分数三个连续变量做分布分析对设备类型做分组比较对学习时段做趋势分析。特征工程从原始时间戳中拆出周几、时段对设备类型做编码将学习时长按周聚合作为序列特征。建模与评估用线性回归模型预测测验分数合理划分训练集和测试集用 R² 和 RMSE 评估效果。这四块内容听起来都不难但把它们串在一起时很多环节会互相牵连。比如特征工程搞晚了可视化的部分就得重新生成数据清洗时把缺失值处理策略选错后面模型结果会直接受影响。因此我建议每一步都留下过程记录哪怕只是 Notebook 里的 Markdown 单元格也要写下“为什么这样做”。作业提交之后这些记录比代码本身更能说明你会不会思考。2. 环境和数据准备开工前要做的三件事2.1 数据字段说明与观察这次作业使用的数据是一份模拟学习行为记录文件名叫student_learning_log.csv字段大致包括用户编号、课程编号、学习日期、学习时长分钟、完成率、测验分数、设备类型、地区代号。拿到数据后我先做了三件小事用df.info()查看字段类型和缺失情况用df.head()观察前几行确认表头和业务含义用df.describe()查看数值列的量纲和分布范围。做完这三步我注意到了一个非常经典的问题学习日期列被读成了 object 类型而不是 datetime。很多新手忽略这一步后面做月份聚合、按周排序时才发现届时要么转换失败要么排序完全错乱。我把这份数据的字段整理成了一张表格便于后续对照字段名含义实际类型注意事项user_id用户编号整数有少量重复记录course_id课程编号字符串类别多于 10 种study_date学习日期字符串含多种格式需统一study_minutes学习时长浮点数存在 0 值和超大值completion_rate完成率浮点数范围 0~1有缺失quiz_score测验分数浮点数目标变量缺失比例约 8%device_type设备类型字符串有别名脏值region地区代号字符串虚构代号无需处理2.2 开发环境与依赖清单这个作业我用的是最常规的 Python 数据分析环境Python 3.10pandas 2.0scikit-learn 1.3Matplotlib 3.7Seaborn 0.12。选择这些版本的原因很简单稳定资料多遇到报错时网上能直接搜索到解决方案。我所有的代码都写在同一个 Notebook 里但导包放在最前面并且固定了随机种子random_state42保证每次运行结果一致。import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns from sklearn.model_selection import train_test_split, cross_val_score from sklearn.linear_model import LinearRegression, Ridge from sklearn.metrics import r2_score, mean_squared_error from sklearn.preprocessing import OneHotEncoder, StandardScaler plt.rcParams[figure.dpi] 120 sns.set_theme(stylewhitegrid)固定随机种子这一点特别重要作业里如果涉及随机划分数据不固定种子的话你每次重跑结果都会不同最后报告里的数字就不稳定容易被质疑结果不可复现。另一个小经验是不要把绘图的字体、尺寸等设置在代码的中间统一放开头否则每次画图都要重新配置。2.3 数据加载和初步检查代码数据加载阶段我用了pd.read_csv()但注意一个细节原始 CSV 里可能有 BOM 头如果不加encodingutf-8-sig第一列列名会出现\ufeff或者乱码。我在这次作业里没有遇到但还是在代码注释里提醒自己。初步检查我写了这样一段代码df pd.read_csv(student_learning_log.csv, encodingutf-8-sig) print(df.shape) print(df.dtypes) print(df.isna().sum()) print(df.duplicated().sum())执行后我看到结果是 15000 行、8 列其中缺失值比较集中重复行有 37 条。这一段已经足够让我决定下一步清数据的方向先删除重复行再填充缺失值最后处理异常值。处理顺序不能乱如果先填充缺失再删重可能会保留一些带着脏值的重复样本。3. 核心实现流程从脏数据到可用模型3.1 数据清洗缺失值、异常值和重复记录的处理清洗这一步我分了四个动作每个动作背后都有明确原因。第一删除完全重复行。重复数据会导致训练样本权重被放大影响模型评估的客观性。我用df.drop_duplicates()直接删除删完后检查发现只减掉了 37 行。第二统一学习日期格式。原始数据里混杂了2024/01/05、2024-01-05、2024.01.05三种格式。我用pd.to_datetime()转换设置errorscoerce转换失败的值变成NaT再结合业务逻辑判断比如日期为空或时间早于开课日期直接剔除。第三处理学习时长的异常值。有些记录的学习时长是 0 分钟有些高达 1440 分钟。测验分数和学习时长一起看就会发现 0 分钟的学习记录里测验分数反而很高这不符合业务逻辑大概率是测试数据我直接剔除。1440 分钟理论上可能是 24 小时不中断学习但结合其他字段看多是重复导入导致我同样删除避免拉偏模型。第四填充缺失值。完成率缺失比例约 5%测验分数缺失比例约 8%。完成率用用户所在课程组的均值填充测验分数作为目标变量不能随便用全样本均值填充否则会削弱预测意义。我采用的做法是用同一学习时长区间内的测验分数均值填充虽然不完美但比粗暴填 0 靠谱。清洗结束后我重新检查了数据量从 14963 行降到 14120 行缺失值全部处理完毕。整个过程都在 Notebook 中有记录每一步删了多少行、为什么删都在报告中附了表格。3.2 探索性分析与基础可视化清洗后的数据首先要回答几个业务问题学习时长和测验分数什么关系完成率如何影响测验表现不同设备类型之间有没有差异星期几的学习行为有没有规律。我画了五张图学习时长的直方图、测验分数的直方图、学习时长与测验分数的散点图加回归拟合线、不同设备类型的平均测验分数柱状图、完成率与测验分数的联合分布图。这些图不用花哨但每一张都要能解决一个具体问题。观察散点图时我发现学习时长和测验分数并不是简单的线性关系在 0 到 60 分钟区间内分数增长比较快超过 90 分钟后增长趋于平缓。这个现象提示我后续建模时不能只拿原始时长做特征可以考虑把时长分箱或者加一个时长平方项尝试二次项拟合。可视化不只是为了报告好看它会给建模路线提线索这是这次作业最重要的体验之一。设备类型方面我清理了别名脏值比如mobile和Mobile被统一为mobilepc和desktop统一为desktop。清理后的结果显示使用移动设备学习的用户测验平均分略低但标准差更大说明个体差异明显。这个差别后面并没有显著提升模型效果但可以在报告中作为业务洞察提一下。3.3 特征工程和建模评估建模前我构造了三个新特征从日期里提取 “星期几” 当作周期特征从学习时段划分出上午、下午、晚上三个类别以及把同一用户一周内的学习总时长聚合成周学习强度。设备类型做独热编码地区字段因为属于虚构的高基类别且样本量稀疏我没有选入模型。由于目标是连续变量我选择了线性回归作为基线模型。划分数据集时用train_test_split按 7:3 切分保持随机种子一致。预测目标为测验分数特征集合包括周学习强度、学习时长、完成率、星期几、学习时段、设备类型。因为特征量纲差异很大我对数值特征做了标准化避免模型训练时受大数值特征主导。num_cols [study_minutes, completion_rate, weekly_study_minutes] cat_cols [weekday, time_period, device_type] X df_clean[num_cols cat_cols] y df_clean[quiz_score] X pd.get_dummies(X, columnscat_cols, drop_firstTrue) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42 ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) model LinearRegression() model.fit(X_train_scaled, y_train) pred model.predict(X_test_scaled) print(R2:, r2_score(y_test, pred)) print(RMSE:, mean_squared_error(y_test, pred, squaredFalse))第一次跑出的基线模型 R² 只有 0.37RMSE 是 12.8对于学习行为预测而言这个结果不算惊艳但能说明问题测验分数受到很多不可观测因素影响仅仅靠学习行为日志很难预测得很准。这份作业的目的并不是让我们调出高分模型而是让我们学会分析误差来自哪里、怎么改进。为了看模型稳定性我对训练集做了 5 折交叉验证得到的 R² 均值为 0.35和测试集结果接近说明模型没有严重过拟合。这个步骤在报告里很重要因为它证明了当前结果不是偶然形成的。4. 实操中的典型问题与排查实录4.1 时间字段为什么总是解析失败处理时间字段时我一开始直接用了pd.to_datetime(df[study_date])结果报了好几条解析错误。原因很简单原始数据里有空字符串、有2024/01/05 08:00这种带时间的格式还有20240105这种纯数字格式。直接转当然会失败。后来我改成两步df[study_date] df[study_date].astype(str).str.strip() df[study_date] pd.to_datetime(df[study_date], errorscoerce)先转成字符串统一处理再设置errorscoerce让无法解析的值变成NaT之后再检查NaT的占比并决定是否剔除。这个小改动节省了很多排查时间。4.2 缺失值比例不高但集中在一个分组怎么办完成率的缺失比例虽然只有 5%但我发现缺失并不是随机分布的某些课程编号下缺失比例高达 20%。如果直接用整体均值填充会让这些课程的完成率整体偏向均值破坏数据的真实分布。我的处理方式是分组填充先按课程编号分组再用组内中位数填充。这比全样本均值更合理因为不同课程的学习强度本来就不同。如果你在做作业时遇到类似情况不妨先画一个缺失值热力图看看缺失是否集中在某些类别里再选择填充策略。切忌拿到数据就开始fillna(df.mean())。4.3 模型过拟合不明显但正则化仍然值得试基线模型的交叉验证和测试集 R² 接近说明过拟合不明显但我在调整特征组合时发现一个问题加入过多高基数类别变量后训练集 R² 提升明显测试集却保持不变甚至下降。这就是轻微过拟合的信号。我试用了岭回归用GridSearchCV搜索一个比较合适的 alpha。因为特征已经标准化岭回归的惩罚项才有一致的作用。代码如下from sklearn.model_selection import GridSearchCV param_grid {alpha: [0.1, 1, 10, 50, 100]} ridge Ridge() grid GridSearchCV(ridge, param_grid, cv5, scoringr2) grid.fit(X_train_scaled, y_train) print(grid.best_params_)搜索结果里最佳 alpha 是 10但测试集 R² 只比普通线性回归高了 0.01。也就是说正则化并没有带来质的提升。这时候就不要过度调参了把结果如实写进报告比硬凑一个好看的数字更有价值。5. 复盘与改进空间做完这份作业后的思考5.1 这份作业到底训练了哪些能力Wk.2_HW 看起来只是一个课内作业但它设计得很聪明。它没有让你直接用现成的干净数据跑模型而是逼着你经历一遍真实数据会遇到的繁琐问题格式混乱、缺失值、异常值、类别字段脏值。这些内容在教程里都只是提一下但实际动手时才知道每一步都会消耗时间。更重要的是它训练了“结果可解释”的能力。提交报告时除了代码还需要说明为什么删掉某些行、为什么选择某种填充策略、为什么模型效果一般。这些“为什么”才是区分作业完成度和理解深度的关键。如果你只是把代码跑通没有解释决策过程作业反馈大概率会建议你加强数据分析思维。5.2 如果重做一遍我会在哪些地方调整重新回顾整个实现过程我会在三个地方做改进。第一在特征工程阶段不应该只做线性特征。从可视化的结果来看学习时长和分数有明显的非线性趋势我会尝试加入学习时长的平方项或者做分箱处理看是否能提升模型表现。第二预测目标可以换一个角度思考与其直接预测分数不如先预测用户能否完成学习任务也就是把回归问题改成二分类再在子集中预测分数两阶段模型的业务可解释性更强。第三代码组织方式可以再工程化一些把数据清洗、特征工程、建模分别封装成函数而不是全部平铺在 Notebook 单元格里这样后期改参数时不会因为重跑顺序出错。5.3 提交流程中的小技巧最后分享一个实际提交过程中发现的小技巧交作业前把一个空的 Notebook 按报告逻辑重新跑一遍。什么意思呢就是不要用自己写代码时的顺序而是按照报告中的讲解顺序重新整理一遍代码块确认每个变量在被引用前都已经被定义。很多人写着写着会跳到前面补充一个清洗步骤导致后面的代码顺序依赖混乱。重新跑一遍能发现很多“我本地明明能跑”的问题。另外一个技巧是所有图表都要把轴标签和图例写清楚。作业评分和真实工作汇报一样图里的信息需要让读者一眼读懂。我这次有张散点图包含回归拟合线但没有标出图例后来反馈里被提醒图例缺失。虽然只是小细节却会影响整体观感。做完 Wk.2_HW 之后我最大的感受是这种作业的名字虽然简单但内容完全不像文件名那么随意。数据清洗的每一步都在积累经验建模评估的每一个指标都在倒逼你理解模型行为。如果你正在做类似的作业建议耐下心把每一段过程记录下来重点写清楚“为什么选这个方案”而不是“我用了什么方案”。最后你会发现自己收获的不只是一个分数而是一套完整的数据分析思路。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑