最近和几个刚入门数据分析的朋友聊天发现大家几乎都卡在了同一道坎上——第二次作业。第一次作业通常只是按部就班地跑个示例、填个表格哪怕过程磕磕绊绊最后也能交差。但到了第二次作业题目变活了数据变脏了要求变模糊了很多人第一次意识到“原来上课听懂了和真正能做出来是两码事”。这篇文章就以我自己的实操经验拆一份典型的数据分析第二次作业从接题、清洗、分析到写报告把每一步的坑和技巧都摊开聊一聊。这篇内容适合正在做课程作业的在校学生也适合刚转行、需要用项目证明自己的新人。无论你用的是 Python 工具链还是 Excel 加透视表的老路子核心思路都通用。看懂这篇你不仅能交出一份体面的作业更重要的是能提前摸到真实业务里“从数据到结论”的完整工作流。1. 拿到第二次作业先别急着敲代码1.1 第二次作业为什么是一道分水岭第一次作业往往是“照着步骤走一遍”甚至很多题目已经把代码框架给好了你只需要填空。这种作业本质上是在验证你有没有把工具装好、能不能让程序跑起来。但第二次作业不一样它通常只给一个数据文件、几句描述性要求剩下的全靠你自己发挥。这种开放程度会让两种人同时栽跟头一种是想太多觉得必须用到机器学习模型才显得高级另一种是想太少直接把每个字段做成一张图表就交上去分析深度约等于零。我见过一个典型例子。老师给了一份超市销售数据要求“分析销售额的影响因素并提出建议”。有人用线性回归把所有字段硬塞进去R方很低、参数解释也不合理最后建议写了一句话“建议提高销售额”——等于没分析。另一个人只做了几组透视表和条形图但认真写清楚了“周末销售额比工作日高32%主要受客流量的影响建议周末增加促销员排班”分数反而远高于前者。第二次作业考察的核心从来不是工具多炫酷而是你有没有能力把一个模糊问题拆解成可执行的分析步骤并且把结果转化成能听懂的结论。另一个层面第二次作业也是最容易出现“代码能跑但毫无逻辑”这种问题的场景。很多人打开 Jupyter Notebook 就从上往下逐行写写到哪算哪。中间发现某个字段没啥用就删掉某个分析做出来不好看就换个图最后整个文件像一份涂鸦板。这种交付物即便结论是正确的也会让评分的人或者面试官觉得你不具备结构化思考能力。所以拿到题目的头两个小时千万不要打开电脑干活先拿一张纸把思路捋出来。1.2 从题目描述里读出隐藏要求作业题目里每个词都值得反复咀嚼。我把常见的要求动词和背后的真实意图列一下“描述”数据分布通常意味着至少要有统计量加直方图或者箱线图而不是只贴个 info 输出。“对比”两组或多组数据一般要求做显著性考虑或至少通过分组统计量来讲差异而不是各画一张图放在一起就结束。“分析”影响关系通常暗示要探索多种因素、指出主要矛盾和次要矛盾不是跑一个模型就完事。“可视化展示”重点在选对图表类型并让读者一眼看懂核心信息不是图表种类越多越好。“提出建议”考察的是你把数据结论落地的能力需要在结论和行动之间建立起直接的因果链条。如果没有给明确的评估标准我通常还会主动找往届的公开课或者同类题目的优秀作业。不是要抄而是去确认“什么样的深度算合格”。比如有的学校要求期末作业控制在8页以内那说明老师期望你把图表做精而不是做多有的老师会在题目里写“鼓励创新”那可以适当加一点基础建模或者动态交互可视化作为加分项。做完这一步把拆解出的需求写成一个清单例如交付物一个 PDF 报告 可复现的代码文件数据集8700 条订单记录18 个字段含缺失值和少量异常值硬性要求至少包含 3 张图表分析流程要完整加分项能解释业务背景建议有数据支撑这个动作看起来简单却能有效防止你写到一半突然发现“好像理解错了题目”的惨剧。1.3 时间规划比写代码更重要第二次作业通常会给你三到七天很多人的节奏是前两天焦虑地刷手机第三天咬牙开工第四天凌晨赶工第五天交一个自己都不敢回头看的东西。我自己习惯把周期压成四个阶段每个阶段都有明确的完成节点。第一天只做需求拆解和数据预览把字段含义、数据质量、缺失情况摸清楚同时确定报告的核心结论方向。第二天做数据清洗和预处理这一步最容易出现意外比如你以为的数值列里混着文本或者日期格式五花八门必须预留足够的缓冲时间。第三、四天做探索性分析和可视化逐步验证前面的假设如果发现数据不支持原定方向及时调整。第五天写报告留最后一天做整体检查。这个安排里最关键的一点是写报告的优先级必须提高。很多人以为报告是分析完以后顺手写的东西实际上写报告的过程本身就是整理逻辑的过程。你写摘要的时候才会意识到前面某个分析其实没有回答业务问题你写结论的时候才会发现某张图和数据说话的方向并不一致。所以我每次都会逼自己在分析阶段就同步维护一个“草稿本”每个发现用一两句话记录下来最后往报告里填的时候非常省力。2. 数据清洗与预处理八成的坑都埋在这里2.1 数据为什么总是不听话真实场景的数据和课程演示数据完全是两回事。当你打开一份 CSV 文件第一眼看到的信息往往会刷新你的认知字段名有中英文混写、同一列里数字和“暂无”共存、日期有的写成2024/01/05有的写成2024-01-05、城市名里混着“北京市”和“北京”。这些情况在作业里不算考官故意刁难而是真实业务里的日常。数据清洗的过程本质上就是把“记录”变成“能用于分析的结构化信息”。我每次拿到数据都会先做一次“体检”用代码快速看三件事import pandas as pd df pd.read_csv(raw_data.csv, encodingutf-8) # 第一眼整体结构和类型 print(df.info()) # 第二眼数值列的基本统计量 print(df.describe()) # 第三眼每列缺失值数量 print(df.isnull().sum())这三行代码能告诉你大部分问题哪些列的数据类型判断错误哪些列的缺失比例大到需要战略性放弃哪些数值列里存在明显超出业务范围的值。做完这一步再决定清洗的优先级。2.2 缺失值处理不是选个函数就完事很多教程喜欢给你一张表“缺失值用均值填充”“缺失值用中位数填充”“缺失值直接删除”。但真实选择远比这句话复杂得多核心判断标准是三个问题这个字段是否重要、缺失比例有多大、是否能从其他字段推断出来。举一个实际作业里遇到的例子。一份电商订单数据里“客户年龄”字段缺失了22%看上去不算特别多但如果直接删掉这些行会丢失宝贵的订单信息。如果直接用均值填充又会让年龄分布中间堆一坨相同的数值。最后我观察到这 22% 的缺失记录里有大部分订单能通过“会员注册时间”推算出一个年龄下限比如注册时必须年满18岁于是我把年龄分成两批处理能推算的用推算值不能推算的标记为“未知”并在后续分析中单独作为一类。这个处理方式比无脑均值填充复杂但它更接近真实业务逻辑。如果你是在做一个预测模型想用平均年龄填补缺失值本质上等于告诉模型“所有年龄未知的人都是平均年龄”这会引入偏差。正确的做法是增加一个“是否缺失”的辅助列让模型自己学习缺失这个状态本身携带的信息。如果只是做描述性统计和可视化作业我建议的原则很简单缺失比例低于5%且不是关键维度直接删行最省事。连续变量缺失优先看分布是否偏态偏态用中位数近似正态用均值。分类变量缺失不要自作聪明填众数单独归为“未知类”往往更稳妥。2.3 异常值不要一刀切异常值大概是数据清洗里最考验业务理解的环节。一个订单金额是负数可能是退款记录也可能是录入错误一个年龄写着 180显然是无效数据但一个全网价格调查里的 99 元是不是异常还得看收集渠道。我的做法是先统计识别再做业务判断最后决定保留、删除还是单独标记。统计识别我用两个工具一个是describe()看四分位数和最大值最小值如果最大值和 75 分位数之间差距大得离谱那大概率存在离群点另一个是箱线图它能直观显示哪些点超过了 1.5 倍四分位距。但箱线图找出来的点只代表“统计上的离群”不代表“业务上的异常”。比如一份订单金额数据箱线图显示客单价 2000 元以上都是离群点但如果这份数据里有企业团购订单2000 元反而正常。实操中对异常值我通常保留一个单独的分析维度而不是急着处理。如果某列异常值占比很小直接剔除影响不大如果占比不小我会做一个“含异常值”和“不含异常值”的对比分析往往能发现更有趣的规律。作业里这样做还能额外体现你的严谨性。2.4 建立清洗规则并保留记录数据清洗中很常见的问题清洗到一半发现前面某一步做错了想把数据还原结果所有操作都在同一个 Dataframe 上反复修改根本没法回退。后来我养成一个习惯每做一个清洗动作都用新列或者新变量去承接而不是在原列上覆盖。同时我会把每一条清洗规则写进一个注释里说明“为什么这么做”。# 规则1订单日期统一为标准日期格式 df[order_date] pd.to_datetime(df[order_date], errorscoerce) # 规则2订单金额为负的记录先标记为退款订单不直接删除 df[is_refund] df[order_amount] 0 # 规则3会员年龄缺失优先用注册时间推算剩余填充为 -1 并标记未知 df[customer_age_estimated] df[customer_age].fillna(...)这些记录最后放进报告里就是“数据清洗说明”那一小节评分者一看就知道你不是蒙头乱搞而是在按工程化的方式工作。真实企业里这也叫数据血缘管理——每个字段的来龙去脉都有据可查。这个概念对作业来说可能有点重但养成这个意识对你以后做项目百利而无一害。3. 探索性分析与可视化让图表自己会说话3.1 先问对问题再选分析方法数据清洗完手里的 Dataframe 已经干干净净了这时候最容易犯的错误就是急着出图。图本身不会错错在没有主线。什么叫没有主线就是把每个字段都做一遍直方图、每个分类都做一遍计数图最后拼出 20 张互不相关的图读者翻到第三页就失去耐心。我在准备分析之前会先写下三到五个业务问题这些问题是从作业要求里拆出来的。比如“顾客的复购行为是否和所在城市等级有关”“不同支付方式下的订单金额是否有明显差异”“销售额的时间趋势是否受促销活动影响”。每个问题都对应一组变量、一张或一组图、一段结论。分析过程就是逐题回答而不是漫无目的地漫游。这样做还有一个附带的好处当你发现某个问题和数据对不上或者答案和常识矛盾时能更早触发你的怀疑而不是等写完报告才发现逻辑不通。3.2 图表选型的原则与常见误区图表是分析的语言语言用错了表达就乱。我每次做可视化前都会核对一遍“这个图是否在回答这个问句”要回答“分布长什么样”用直方图或密度图不要用折线图。要回答“某个类别的数量或大小排名”用条形图类别多时横向条形图更好读。要回答“随时间的变化趋势”用折线图注意时间轴要连续。要回答“两个连续变量的关系”用散点图必要时加趋势线。要回答“不同组的分布差异”用箱线图或小提琴图不要只画平均值柱状图。要回答“占比结构”最多用饼图且类别不要超过5个否则用堆叠条形图。还有一个特别常见的翻车点图表类型太多颜色太花哨标题写“XX分布图”而不是结论。我给图起标题的习惯是直接用结论或者用“问题结论”的组合。比如“各城市等级复购率对比一线城市显著高于三四线城市”就比“城市等级复购率柱状图”有用得多。读者不需要猜你想说明什么一眼就看到重点。import matplotlib.pyplot as plt import seaborn as sns plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False sns.set_style(whitegrid) sns.barplot(datacity_repurchase, xcity_level, yrepurchase_rate, paletteBlues_d) plt.title(各城市等级复购率对比一线城市显著更高, fontsize14) plt.xlabel(城市等级) plt.ylabel(复购率) plt.savefig(repurchase_by_city.png, dpi200, bbox_inchestight)这里的两行字体设置是很多教程不会强调的。如果不设置中文字体图里所有中文都会变成方块如果不设置axes.unicode_minus坐标轴上的负号也会显示成乱码。这两行代码建议所有人在画图前无脑加上。3.3 探索性分析的三个递进层次新手的探索性分析往往停留在“画图”这一层。真正能拉开差距的是画完图之后有没有继续往下挖一层、再挖一层。我习惯把分析分成三个递进的层次每一层都在回答“为什么”。第一层是单变量分析先看每个关键字段的分布。这个阶段会暴露数据的偏态、缺失和异常也是你判断后续分析方向的基础。第二层是多变量交叉思考“谁会影响谁”。比如复购率和城市等级、复购率和会员时长、复购率和最近一次消费时间间隔两两组合看很多结论开始浮现。第三层是简单建模或因子归纳。不一定要用高级算法即使是一张相关性热力图也能帮你梳理多重因素之间的关系。拿常见的相关性热力图来说这一步特别能体现信息密度。几个变量之间的相关系数排成一个矩阵后你会发现原来“消费频次”和“用户满意度”之间竟然是弱的负相关——这看起来反常识但如果结合“满意度数据来自最活跃用户的抱怨”这个背景就能形成很有意思的分析。这种“数据结果 领域解释”的组合正是作业得分的关键。3.4 可视化工具的取舍与实操细节工欲善其事必先利其器。如果你所在课程没有强制指定工具我建议优先用 Python pandas seaborn。因为用代码绘图的好处是可复现改一个参数重新运行就能得到新图而且图片质量稳定不会出现 Excel 图表在不同机器上字体漂移的问题。如果环境本身没有装好又没有太多时间折腾Excel 的透视表加图表也能完成 80% 的分析尤其适合快速分组看统计量。不过用 Excel 做出来的图后续调整颜色、字体、加数值标签都相对费劲如果一份报告里有十几张图工作量反而更大。另外一个折中方案是先用 pandas 做数据处理导出成干净的表再用 Excel 或者在线可视化工具做图这样两边优势都能发挥。图像输出方面一个经常被忽略的细节是精度。报告插图的 dpi 至少要 200 甚至 300否则放大之后全是马赛克。保存图表时最好加上bbox_inchestight参数避免图表的标题或轴标签被裁切。这些细节看起来零碎但在打印或投屏场景下直接决定观众对你专业度的第一印象。4. 从分析结果到一份“能打”的报告4.1 报告结构的黄金模型很多同学把报告写成一堆代码输出和图片的堆叠结果是评分者要耐着性子在一堆“图”里找你到底想表达什么。好的报告结构应该是结论驱动的我常用的模板是一句话摘要用最直白的话说清楚你发现了什么、建议怎么做。背景与问题交代数据从哪来、要回答什么问题以及分析的边界。数据说明与清洗方法不仅写“我删除了缺失值”更要解释“为什么这么删、这个操作对结论有什么影响”。分析与发现按照业务问题逐条展开每个小节用“结论→证据→解释”的结构写。结论与建议把前面所有发现收敛成有优先级的行动建议。这个模板看起来简单但它能保证不管读者从哪一段开始都不会迷失。4.2 让你的文字像分析师而不是复读机我批改作业时发现一个通病报告里充满了“我分析了一下”“我调用了某个包”“数据里有一个字段叫XX”。这种写法是流水账不是分析。对比一下两种表达低分表达订单金额平均数是342元标准差是187元最大值为5600元样本量为8700个。高分表达订单金额整体呈右偏分布低于500元的订单占七成但少数高客单价订单贡献了将近一半的销售额因此均值342元并不能代表典型订单水平。同样的统计数字第二种表达多了“为什么重要”和“所以呢”。评分者想看到的正是这种转化能力。每次写完一段建议回头审查一遍这段里有没有“所以”这个词如果从头到尾都找不到因果连接那大概率还是在罗列数据。写作还有个实用技巧结论先行。把要表达的判断放在句子的最前面后面放数据支撑。比如“夜间时段的订单取消率最高达到21%约为白天的两倍”而不是“有人发现夜间取消率好像是21%比白天高”。前者有观点后者只是描述。4.3 提交前的检查清单交作业之前用 10 分钟过一遍下面的清单能避免很多灾难代码是否能在干净环境下从头运行路径是否用了绝对路径图片是否清晰字体是否正常显示有没有被裁切报告里的每个结论是否都有对应的图表或数据支撑有没有明显的前后矛盾比如摘要说“建议增加促销”但正文数据显示促销期间利润反而下降。依赖库版本是否写清楚有没有用到的包没有导入另外一个容易被忽略的点是文件命名。如果提交时要求发压缩包建议命名成“姓名-学号-第二次作业.zip”里面再建一个src目录放代码、data目录放原始数据、report目录放报告。这种组织方式在评分者那里会留下“这个学生有工程意识”的印象哪怕题目不要求也是加分项。5. 实战中遇到的常见问题与排查技巧5.1 中文乱码和字体失效中文乱码大概是国内做数据可视化的人遇到率最高的问题没有之一。处理方案分两头在读数据时pd.read_csv(..., encodingutf-8)如果报错试试gbk或gb18030。在画图时设置字体前先确认系统中确实存在字体再用plt.rcParams指定。如果是在 Linux 服务器上跑代码经常遇到中文字体缺失。解决办法是安装中文字体包或者在画图前用matplotlib.font_manager动态指定一个本地字体文件的路径。这种问题初见时很烦但排查过一次以后就再也不会踩。5.2 文件路径的“我的电脑能跑”代码里写C:/Users/张三/Desktop/第二次作业/data.csv在别人的电脑上一定跑不通。正确做法是把数据和代码放在同一个项目目录下用相对路径引用。比如data/raw.csv。还有个小陷阱如果你在 Windows 上写路径分隔符要用/而不是\否则某些环境会出问题。pandas 在读取有中文路径的文件时也可能遇到底层编码报错如果打包给别人的代码里涉及移动路径最好提前把所有文件重命名成英文。5.3 环境版本不一致作业里写了import pandas as pd你用的是 pandas 2.x 的环境对方可能还在用 1.x 环境某些函数的行为并不完全一样。最省事的方法是在提交的代码文件夹里附带一个requirements.txtpandas2.0.3 matplotlib3.7.2 seaborn0.12.2如果对方找不到环境也可以直接把关键代码的运行环境写在报告开头比如“本作业基于 Python 3.11 与 pandas 2.0.3 运行”。这种说明字不多但避免了老师复现时浪费大量时间。5.4 分析做到一半发现方向错了这是高年级作业里最沮丧的时刻几乎每个人都经历过。我目前的应对方式是在做探索性分析之前先花时间把“预期”写下来。比如看到数据后先猜“根据经验支付金额可能和购物车数量强相关”再设计图表去验证。如果数据和预期不符就要问自己是我的业务假设有问题还是数据清洗时引入了偏差这种“先假设后验证”的工作流本质上就是科学方法在数据领域的应用。它会让你的分析不会因为一个意外结果就全线崩盘因为每个节点都有记录你能更快定位究竟是哪个环节出了问题。5.5 常见问题速查表下面这张表是我整理成速查看板保存下来的每次开工前扫一眼能避开 90% 的坑问题可能原因解决方案UnicodeDecodeError文件编码不是 UTF-8尝试encodinggbk或gb18030图表中文变方块未设置字体plt.rcParams[font.sans-serif] [SimHei]读入日期为字符串未解析日期列pd.to_datetime()配合format参数缺失值统计结果异常空字符串未被识别先replace替换空值数值列里混入文本数据录入问题用pd.to_numeric(errorscoerce)图表保存后内容被截断没有调整边界加bbox_inchestight对方电脑运行报错版本或路径差异写requirements.txt、使用相对路径6. 一些关于做事方式的体会如果你正在做自己的第二次作业我最想分享的一点是不要把它当成一次单纯的“交差”而是把它当成一次完整项目的预演。评分标准只决定了你是否及格但整个过程中你有没有建立“需求拆解—数据清洗—探索分析—报告表达”的闭环思维决定了你走到下一份工作或下一个项目时是否从容。我在复盘很多次作业和真实项目之后发现最容易拉开差距的不是技术工具而是“有没有认真思考每一步操作背后的原因”。用均值填充缺失值谁都会但看出“这个变量偏态严重、应该用中位数且要加一个是否缺失的标记”的人才真正理解数据。画一张柱状图谁都会但基于业务问题拆解图表的选型、标题和结论让图表自己会说话的人才能把分析价值传达到位。最后再分享一个小技巧每次做完作业花 20 分钟把过程中遇到的报错和解决方式整理成一个文档命名叫“踩坑记录”。半年以后回看你会惊讶于自己解决过多少类型的问题。这些记录才是比分数本身更值钱的资产。祝这次作业顺利。