ARTICLE DETAIL

资讯详情

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

Python数据分析实战:从CSV读取到matplotlib可视化全流程复盘

Python数据分析实战:从CSV读取到matplotlib可视化全流程复盘 做了三次Python作业基本都是小程序和语法练习到第四次作业突然换了一副面孔直接上了一个带CSV文件的数据分析任务要求自己读取数据、清洗、统计最后把结果用图表画出来。刚拿到题目的时候确实愣了一下因为这已经不是“一个函数打天下”的难度了而是正儿八经的完整小项目。但做完之后回头看这恰恰是Python学习中最关键的一道分水岭。这篇文章就来完整复盘我第四次Python作业的全过程包括题目拆解、环境准备、每一道题的核心代码、我踩过的坑以及做完之后的一些扩展思考希望给正在学Python的朋友一些参考。1. 作业整体设计与思路拆解1.1 这次作业到底想考察什么第四次作业的题目是一个完整的“数据处理链路”不再是零散的语法点而是把前面学的所有知识串联起来了。作业的要求是这样的给一份销售记录的CSV文件里面包含了日期、商品名称、商品分类、销量、单价、金额等字段共几百条记录。要求完成四个任务读取文件并统计总记录数对数据进行清洗去掉重复记录和空值按商品分类统计销量总和与金额总和最后用matplotlib画出各类别销售额的柱状图。从表面上看这是一道数据分析的入门题但老师的真实意图是考察四个层面的能力文件读写、数据结构的使用、字符串和数值类型的处理、以及第三方库的调用。这四个能力恰好是Python用于实际工作场景中最核心的部分。前三次作业都在练函数、循环、列表但这些知识如果没有一个“容器”把它们装起来学完很容易忘。第四次的作业就是那个容器。1.2 从作业题到真实项目的递进逻辑这道题设计得很有讲究它模拟了真实工作中“拿到一份数据把它变成结论”的完整过程。你在公司里拿到销售部门的Excel报表要算出哪个品类卖得好哪个品类利润高不会有人给你一个现成的函数你必须自己想办法用代码解决。而这次作业把这件事简化成了最适合初学者练习的版本数据是现成的、量是可控的、要求是明确的你只需要一步步去实现。我当时的思路是这样的先不要急着写代码而是把四个任务拆成“读数据—清数据—算数据—画数据”四个阶段。读数据用Python自带的csv模块就能搞定清数据要处理重复和缺失算数据需要遍历统计画数据要引入matplotlib。每一阶段单独写完测试通过再进入下一阶段这样出了问题也好定位。这个思路推荐给大家写作业或者做小项目都别一上来就闷头写。2. 环境准备与开发工具配置2.1 Python环境安装与版本选择在动手写代码之前第一步是确保本机的Python环境是可用的。我猜来看这篇文章的朋友应该基本都装过Python了但考虑到有些同学的作业电脑是新买的或者之前装了一半出了问题还是值得把环境配好这个事再捋一遍。Python的版本选择上我建议直接装3.10或者3.11不要用2.x版本也不要追最新版本除非你确认所有要用的库都兼容。3.11目前兼容性已经非常好了pandas、matplotlib、requests这些主流库都有对应版本。安装的时候有个细节容易踩坑在Windows上安装Python时第一屏有一个“Add Python to PATH”的复选框这个默认是不勾选的如果你忘了勾后续在命令行里敲python会提示“不是内部或外部命令”。解决办法有两个要么重新运行安装程序选Modify再勾上要么手动把Python的安装路径和Scripts路径添加到系统环境变量里。安装完成后在命令行输入python --version可以验证版本号。需要注意的是如果电脑上同时装了Microsoft Store版本的Python和官网安装包可能会冲突。我就是因为之前装了Store版本后来官网装了3.11命令行里显示的却还是旧版本折腾了好一会儿。建议只保留一个版本打开“设置 - 应用”把不需要的卸载掉。2.2 用虚拟环境隔离作业依赖环境准备好之后我强烈建议从一开始就养成使用虚拟环境的习惯不要嫌麻烦。虚拟环境相当于给每个项目单独开一个“包空间”你在作业项目里装的库不会污染系统全局的Python环境将来做别的项目也不会互相冲突。Python自带的venv就够用不需要额外装virtualenv。创建虚拟环境的流程非常简单在项目文件夹下打开终端执行python -m venv venv这个命令会在当前目录下创建一个venv文件夹里面就是一套独立的Python环境。接下来需要“激活”它Windows系统venv\Scripts\activatemacOS或Linuxsource venv/bin/activate激活成功后命令行前面会多一个(venv)的提示符这表示你现在处于虚拟环境中。之后你用pip安装的所有包都会装到这个venv里。我这次需要装两个库。执行pip install matplotlib有的同学可能还会用到pandas不过第四次作业如果只用标准库加matplotlib是完全可以搞定的老师批改时用pandas也能看懂但考虑到某些同学只用标准库更利于理解数据结构所以我在下面一节的代码里先用csv模块演示这样任何一个版本的Python都能跑不会因为库没装好而卡住。顺便说一个在国内常见的坑pip默认源在国外下载速度慢甚至超时。遇到这种情况可以临时指定国内镜像源pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple这个清华镜像源我用了很久速度很稳定。也可以把默认源永久改成国内源新建一个pip.ini配置文件放在用户目录的pip文件夹里但临时方案其实已经足够。2.3 VSCode与Python调试配置编辑器的选择上我用的是VSCode配Python扩展插件这也是目前学生党和程序员用得最多的组合。VSCode里写Python有几个好处代码补全、语法高亮、内置终端都是开箱即用加上Python扩展后还可以直接设置断点调试。配置起来也不复杂在扩展市场里搜“Python”安装微软官方那个认准Publisher是Microsoft的然后在项目目录下打开VSCode用命令面板CtrlShiftP输入“Python: Select Interpreter”选择刚才创建的venv环境。这一步很重要如果没选对解释器你在终端里明明装了numpyVSCode却会提示ModuleNotFoundError因为代码运行时用的是另一个解释器。调试配置也可以说一下在代码行号左侧点一下出现红点就是下了断点然后按F5选择“Python File”就能进入调试模式。按F10单步执行、F11进入函数内部这对理解代码执行流程非常有帮助。我建议大家在写作业时养成调试的习惯尤其是循环和字典操作肉眼检查十遍不如调试器跑一遍看得清楚。3. 作业题目明细与核心代码解析3.1 数据读取用csv模块打开文件题目提供的CSV文件叫sales_data.csv有几行数据大致长这样日期,商品名称,分类,销量,单价,金额 2024-05-01,薯片,零食,3,8.5,25.5 2024-05-01,可乐,饮料,5,3.5,17.5 2024-05-02,薯片,零食,2,8.5,17.0第一行是表头后面每行是一条销售记录。要读这个文件用Python内置的csv模块最直接import csv file_path sales_data.csv rows [] with open(file_path, moder, encodingutf-8, newline) as file: reader csv.DictReader(file) for row in reader: rows.append(row) print(总记录数, len(rows)) print(前三条数据) for i in range(3): print(rows[i])这里用DictReader而不是reader是因为DictReader会把每一行转成一个字典key就是表头字段名后面操作起来不用记下标代码可读性高很多。encoding参数为什么写utf-8因为这份CSV文件是用Excel另存的UTF-8格式。如果直接双击打开CSV用记事本看能看到中文字符正常显示基本就是UTF-8如果中文乱码那就试试encodinggbk。有同学在做作业时直接用pandas的read_csv一行就能搞定但我觉得首次做这个练习用csv模块更能帮助理解“数据读取”的本质逐行打开、逐行解析、按需存入数据结构。需要注意的一个坑是with open打开的文件在这个缩进块结束后会自动关闭这是推荐写法。不要用那种file open(...)然后手动file.close()的写法一旦中间代码报错文件可能一直占着句柄程序操作文件时会有意想不到的权限问题。3.2 数据清洗去掉重复与处理空值原始数据通常不会那么干净这份作业数据里老师特意埋了一些雷有两行完全重复的记录有几行的销量或金额是空的还有一行日期格式跟其他不一样。如果不清洗直接统计最终结果会失真。清洗的思路分两步第一步去重第二步补缺或删缺。print(清洗前记录数, len(rows)) seen set() cleaned_rows [] for row in rows: key (row[日期], row[商品名称], row[分类], row[销量], row[单价], row[金额]) if key not in seen: seen.add(key) cleaned_rows.append(row) count_empty 0 for row in cleaned_rows: if row[销量] or row[金额] : count_empty 1 cleaned_rows [row for row in cleaned_rows if row[销量] ! and row[金额] ! ] print(清洗后记录数, len(cleaned_rows)) print(删除重复记录数, len(rows) - len(seen)) print(存在空值的记录数, count_empty)去重用set来做的逻辑其实很好理解把每一行的关键字段打包成一个元组如果这个元组已经出现过说明是重复数据跳过。这个做法比“两层for循环互相比较”要高效得多数据量到几千条时性能差距会很明显。空值的处理这里选的是直接删除因为题目没有要求填充缺失值。但实际项目中处理空值要谨慎要看缺失值占总数据的比例、缺失字段是否关键。如果缺失的恰好是金额字段直接删掉可能会丢掉有效信息。这道作业删除空值记录的思路没问题因为空值占比很小、不影响整体结论但要在注释里写明“选择删除的原因”这样老师看到也能觉得是你经过思考的。3.3 分类统计字典与循环的组合清洗之后进入核心统计任务按“分类”分组统计每个分类的总销量和总金额。这里没有现成的groupby函数可用如果用了pandas当然有需要自己用字典和for循环实现而这个过程特别能加深对数据结构的理解。category_stats {} for row in cleaned_rows: category row[分类] sales float(row[销量]) # 注意原数据里的销量是字符串 amount float(row[金额]) if category not in category_stats: category_stats[category] {销量: 0, 金额: 0.0} category_stats[category][销量] sales category_stats[category][金额] amount print(分类统计结果) for category, values in category_stats.items(): print(f{category}: 销量 {values[销量]:.0f}, 金额 {values[金额]:.2f})这里有几个值得细说的地方。第一个是类型转换csv读进来的数据全部是字符串比如“3”其实是3不做转换直接加法会变成字符串拼接“35”必须用float()转成数值类型。第二个是if category not in category_stats的写法这是“字典初始化”的经典模式。第一次遇到某个分类时先给它建一个空的统计字典之后再遇到同样的分类就走累加分支。这个写法很多同学初次接触会觉得绕但写多了就成了肌肉记忆。f-string格式化输出也值得掌握{values[金额]:.2f}表示金额保留两位小数{values[销量]:.0f}表示销量保留整数。用这种格式化方式输出统计结果观感好很多也方便后续把结果写入文件是一举两得的操作。3.4 可视化matplotlib画柱状图统计完成后最后一步是把结果画成图这是最有成就感的一步。要求是画一张柱状图纵轴为金额横轴为分类名称。import matplotlib.pyplot as plt import matplotlib matplotlib.rcParams[font.sans-serif] [SimHei, Microsoft YaHei] matplotlib.rcParams[axes.unicode_minus] False categories list(category_stats.keys()) amounts [category_stats[c][金额] for c in categories] plt.figure(figsize(10, 6)) bars plt.bar(categories, amounts, color[#4C72B0, #DD8452, #55A868, #C44E52]) plt.title(各分类销售额统计图) plt.xlabel(分类) plt.ylabel(销售额元) for bar in bars: height bar.get_height() plt.text(bar.get_x() bar.get_width() / 2, height 5, f{height:.0f}, hacenter, vabottom, fontsize10) plt.tight_layout() plt.show()这段代码里最隐蔽、最容易踩坑的是中文字体配置。matplotlib默认字体是英文字体直接画中文标题或横轴标签会显示成一个个小方框。解决办法是显式设置中文字体SimHei是黑体Windows下一般自带Mac系统下可以改成“Heiti TC”或“PingFang SC”Linux系统下可以装文泉驿字体。这个设置必须在绘图之前就声明否则会报警告或者出现方块字。另外还有一个细节plt.bar返回的是一个BarContainer对象可以遍历它拿到每个柱子的坐标和高度然后用plt.text在柱子上方标注数值。这个细节有些教程里不会单独讲但加上之后图表的信息量完全不同老师看到也会加分。这个图如果最终保存成图片而不是简单显示可以用plt.savefig(sales_summary.png, dpi200, bbox_inchestight)保存图片时建议加dpi参数提高清晰度加bbox_inchestight把图片周围多余空白裁掉。有同学问为什么用了plt.show()之后图片一闪而过就没了这其实是因为脚本运行结束时图形窗口自动关闭可以在plt.show()之前加一个input(按回车退出)或者直接从代码里保存成文件再打开看。4. 常见问题与排查技巧实录4.1 报错“ModuleNotFoundError: No module named matplotlib”这个报错是第四题的高频问题几乎每届都有同学遇上。原因基本就是上面说的解释器选错了或者根本没激活虚拟环境。排查思路如果让我来梳理第一件事就是先在终端中输入python -c import matplotlib; print(matplotlib.__version__)看看当前解释器能不能导入matplotlib。如果这一步都报错说明包确实没装进当前环境如果这一步不报错但你在VSCode里运行代码仍然报错那一定是VSCode选择的解释器跟你终端激活的虚拟环境不是同一个。解决办法就是在VSCode里CtrlShiftP选择“Python: Select Interpreter”然后手动指向venv里的python.exe。这个坑我踩过两次之后长了记性现在每开一个新项目第一步就是选解释器根本不会等报错再回头找原因。4.2 CSV文件读取路径找不到读文件的报错通常是FileNotFoundError: [Errno 2] No such file or directory: sales_data.csv。初学者最容易在这个地方翻跟头。原因大多不是文件不存在而是“当前工作目录”和“CSV文件所在的目录”不是同一个。用一个简单的办法可以看清当前工作目录import os print(os.getcwd())如果打印出来的路径不是项目文件夹可以在VSCode的右上角打开终端或者用“打开文件夹”方式打开项目而不是单独打开某一个.py文件这样工作目录就能对齐。更稳妥的写法是使用绝对路径或者在代码开头把工作目录切到文件所在目录import os os.chdir(os.path.dirname(os.path.abspath(__file__)))这一行代码的意思是把当前工作目录切换为“这个Python文件所在的目录”无论从哪里运行脚本都能保证相对路径不出错。虽然它看起来有点投机取巧但在写作业和小工具时非常好用。4.3 中文字体显示方块图表中文显示成方框的问题上面已经给了解决方案。但如果你做了设置还是显示方块一种可能是你设置的字体名称在系统里并不存在。可以在Python里打印所有可用字体逐一检查from matplotlib import font_manager fonts [f.name for f in font_manager.fontManager.ttflist] print(SimHei in fonts)如果返回False说明系统没有黑体需要换其他中文字体或者到网上下载字体文件安装。也可以指定字体文件的路径直接加载import matplotlib.font_manager as fm font_path /path/to/your/chinese-font.ttf fm.fontManager.addfont(font_path) matplotlib.rcParams[font.family] fm.FontProperties(fnamefont_path).get_name()这个办法的好处是不依赖系统安装状态直接把字体文件跟代码放在一起就能用跨电脑拷贝项目时不会丢字体。4.4 数值计算出现意外的字符串拼接我在批改同学作业时经常看到这种问题统计金额的时候输出的是“25.517.525.5”这种连在一起的数字一眼就知道是字符串拼接而不是数值相加。排查方法很简单打印一下类型print(type(row[金额]), row[金额])看到class str就说明还没转数值类型。凡是参与计算的字段在读取后第一时间用float()或int()转换不要等到用的时候再转这样逻辑更清晰。如果想稳妥一点可以在转换前加一个判断try: value float(row[金额]) except ValueError: value 0.0这段代码能把“无法转换的脏数据”兜住不会因为某一行数据格式异常导致整个程序崩溃。作业里老师埋的空值字段就是通过这种方式处理的。4.5 Excel打开CSV乱码怎么处理最后补充一个和Python本身关系不大但经常让同学头疼的问题在Excel里直接双击打开CSV文件中文全部乱码。这是因为原CSV文件是UTF-8编码而Windows版的Excel默认用ANSI编码打开两者不一致。解决办法有两种。第一种是保存CSV时换个编码with open(output.csv, w, encodingutf-8-sig, newline) as f: writer csv.writer(f) writer.writerows(data)utf-8-sig编码会在文件开头加上BOM字节顺序标记Excel就能正确识别UTF-8编码。第二种是在Excel里用“数据 - 从文本/CSV”导入然后在导入向导里手动选择“UTF-8编码”也能正常显示。我个人的习惯是只要生成的CSV要给人用Excel打开就统一用utf-8-sig省得每次解释编码问题。5. 作业进阶从“交差”到“项目化”5.1 把代码封装成函数与模块作业做完提交之后如果你不想只停留在“能跑”这个层次可以继续往项目化的方向改一版。最大的变化是把之前写在顶层的代码全部包进函数里。def load_data(file_path): rows [] with open(file_path, moder, encodingutf-8, newline) as file: reader csv.DictReader(file) for row in reader: rows.append(row) return rows def clean_data(rows): seen set() cleaned [] for row in rows: if row[销量] or row[金额] : continue key tuple(row.items()) if key not in seen: seen.add(key) cleaned.append(row) return cleaned def aggregate_by_category(rows): stats {} for row in rows: cat row[分类] if cat not in stats: stats[cat] {销量: 0, 金额: 0.0} stats[cat][销量] float(row[销量]) stats[cat][金额] float(row[金额]) return stats def plot_category_stats(stats): categories list(stats.keys()) amounts [stats[c][金额] for c in categories] # ... 绘图代码 ... if __name__ __main__: raw load_data(sales_data.csv) cleaned clean_data(raw) stats aggregate_by_category(cleaned) plot_category_stats(stats)这样改造之后的好处非常明显每一步都有一个独立的函数将来要换数据源、要加新的统计维度只需要改对应的函数其他部分不用动。if __name__ __main__:的作用是让这段代码只在直接运行该文件时执行如果从别的模块import这个文件就不会自动跑一遍让代码具备可复用性。5.2 打包成exe脱离Python环境运行有些同学做完了作业想让身边没装Python的朋友也能运行这个统计程序这就涉及到把Python脚本打包成exe文件。工具首选PyInstallerpip install pyinstaller pyinstaller -F sales_analysis.py-F参数意思是打包成单文件生成的exe在dist目录下。命令执行完之后dist文件夹里就会出现一个sales_analysis.exe双击就能运行。如果程序里用了matplotlib画图打包出来的exe体积通常会在30MB以上这是正常的因为要带上运行时依赖。打包过程有个小坑有些杀毒软件会误报exe为病毒这是正常现象不是因为代码有问题。可以加白名单或者用PyInstaller的--noconsole参数把控制台窗口隐藏掉。不过考虑到作业场景不建议一上来就追求exe先把源码写清晰更重要。5.3 用真实数据做一次完整的数据分析第四次作业的终极目标其实是让你体验“拿到真实数据并从中获得洞察”的完整流程。如果你做完作业还有精力我建议去找一份真实的数据集练练手比如自己过去一年的支付宝账单导出的CSV或者某电商平台公开的销售数据。用同样的流程读取、清洗、统计、可视化你会发现同样的代码在不同数据上跑起来的感受完全不一样。真实数据比作业数据脏得多日期格式五花八门、金额有负数、商品分类字段有空值而且行数可能是几万甚至几十万。这时候你才真正理解为什么清洗一环这么重要为什么set去重比两层循环快为什么要在循环里做类型转换。作业里四道题也许只需要一小时就能做完但从“做完作业”到“完成一次真实的数据分析”中间还需要大量的刻意练习。6. 一些实用技巧与个人心得写代码这件事没有捷径但可以从每一次作业中总结出属于你自己的方法论。这次第四次作业让我最深的体会是不要拿到题目就急着敲代码先花十分钟想想整个流程是什么每一步输入是什么、输出是什么然后自顶向下按函数拆解。想清楚之后再动手代码质量会高好几个档次。另外我要特别强调一下提问方式。做作业遇到报错直接截图发群里问“为什么错了”别人很难帮助你因为信息不完整。好的提问方式是说清楚你在做什么、代码只贴出关键部分、把完整的报错信息贴出来、把自己已经尝试过的方案说一下。这样别人一眼就能看出问题在哪你自己在写这个“提问描述”的过程中也常常会豁然开朗找到问题所在。还有一个小技巧是关于数据文件的版本管理。改动CSV或代码之前先复制一份留存原版或者使用Git做版本管理。我的习惯是每次改完一轮代码就执行一次git commit写清楚改了什么。做作业的时候也许觉得多此一举但一旦哪天改崩了想撤回你就知道版本管理有多重要了。这个习惯在你步入工作岗位之后完全用得上。第四次作业确实是一个坎它把“学语法”和“做项目”之间的鸿沟拉近了。迈过去之后你再看Python的世界会发现视野完全不一样原来所谓的数据分析、数据可视化并没有想象中那么高不可攀。希望你也能从这个过程中获得同样的成就感。
返回列表