ARTICLE DETAIL

资讯详情

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

Python第11天实战:用天气数据小项目串起pandas清洗与可视化

Python第11天实战:用天气数据小项目串起pandas清洗与可视化 说实话我学Python到第十天晚上的时候整个人是有点泄气的。语法书翻过一遍变量、列表、字典、循环、函数这些概念都混了个脸熟可合上书让我自己写点东西脑子立马一片空白。第十一天我换了个思路不打算再按部就班往下啃语法而是直接挑了一个小项目练手用Python把一份CSV天气数据读进来做清洗、分组统计最后画出图。就这么一个不起眼的小目标居然把前面学的零零碎碎全部串起来了。这篇文章就是第11天的完整记录包括我为什么要在这个阶段选这个项目、环境怎么收拾、pandas清洗数据时踩了哪些坑、matplotlib画图时被中文乱码折磨的过程以及最后如何把脚本打包成exe。如果你也处于“学完基础语法但做不出东西”的阶段这篇应该能帮上忙。1. 为什么第11天我决定不急着啃语法直接拿一个小项目开刀1.1 语法书翻不完项目却能逼你主动补课我给自己定的节奏是每天下班后学一两个小时。前十天安排得中规中矩装环境、学变量、条件判断、循环、函数、字符串和列表操作、字典、文件读写再到类和对象。听起来挺完整但问题在于这些都学得太“顺”了。教材上讲什么我就记什么做几道课后题感觉都会了转头却发现根本不知道在真实场景里怎么用。第十天晚上我刷到一个说法“语法是学不完的项目才是带你走的。” 想想确实有道理Python的库那么多今天学itertools明天学collections永远有学不完的内容。但如果带着一个具体问题去学效率完全不同。于是第十一天我决定不再纠结下一个语法知识点而是从网上找了一份模拟的天气数据做一次从数据清洗到可视化的完整流程。1.2 今天这个“天气数据小工具”到底在做什么我给自己定的项目目标是这样的手头有一份CSV文件里面包含日期、城市、天气现象、最高气温、最低气温等字段。我的任务分四步。第一用pandas把CSV读进来看看数据长什么样、有没有缺失值、有没有重复行。第二做几项常规清洗去掉空数据、删除重复记录、把气温从字符串转换成数字。第三用groupby做分组统计比如计算每个城市的平均最高气温或者每天所有城市的平均气温。第四用matplotlib把统计结果画成柱状图和折线图输出成PNG图片。如果当天还有余力就顺手把脚本用PyInstaller打包成一个exe放到桌面上双击能跑。说实话在第十一天给自己定这样的目标我心里是打鼓的。但后来发现真正动手做的时候那些语法知识会自己跑出来帮你。1.3 别小看这次实战它把哪些零散知识点串起来了我原本以为“清洗数据”这种词离初学者很远真做起来才发现它全是在用最基础的东西。文件读写用到的是open和CSV操作虽然pandas包装了大部分但原理还是“读文件-处理-写文件”。类型转换用到了int()、float()、str()只是pandas里换成了pd.to_numeric和pd.to_datetime。分组统计本质上就是在用字典的“键-值”逻辑把同一类数据聚在一起。而画图更直接就是造出x轴和y轴两个序列然后交给绘图库。这些东西单看都不难但放一起做一个小项目交互起来就没那么舒服了。比如你知道map函数怎么用但不知道什么时候该用apply你见过切片但不知道pandas里的DataFrame筛选和切片其实长得不太一样。这些经验语法书不会主动告诉你只有踩过坑才记得住。2. 动手前先把环境收拾利索虚拟环境、pandas、matplotlib2.1 为什么坚持要用虚拟环境而不是直接在全局装包很多初学者会嫌虚拟环境麻烦觉得“我直接把pandas装进Python不就行了吗”。我第一次看别人用venv也觉得多此一举直到后来装了一个依赖老版本numpy的库把全局环境搞乱了才发现虚拟环境这东西有多重要。打个比方全局Python环境就像一间公用的厨房你做饭用的调料和别人的混在一起。今天你想放辣别人可能只想吃清淡的明天别人把盐换成一种奇怪的花盐你炒出的菜味道就全变了。虚拟环境就是给你单独开了一间小厨房想装什么装什么装坏了也不影响公共区域。我这次做天气数据小项目就老老实实建了一个venv目录把pandas和matplotlib都装在项目内部。这样哪怕以后这个项目依赖到了2.0版本的numpy另一个项目依赖1.x版本两边也互不干扰。2.2 从创建venv到激活Windows和macOS/Linux的完整命令创建Python虚拟环境其实就一条命令。Windows上的做法是python -m venv venv venv\Scripts\activatemacOS和Linux上稍微有一点区别第一条一样激活命令不同python3 -m venv venv source venv/bin/activate激活之后命令行的提示符前面会多出一个(venv)看到这个括号就说明你已经进入一个独立的Python环境了。这里有个很容易被忽视的前提你的python命令得能正常工作。如果你在Windows命令行里敲python提示“不是内部或外部命令”那多半是安装Python的时候没有勾选“Add Python to PATH”也就是环境变量没有配置好。解决办法很简单去Python官网重新下载安装包安装向导的第一步会有这个勾选框勾上再装一次就行。2.3 安装pandas和matplotlib遇到慢就用国内镜像虚拟环境激活后安装包就是两个pip命令pip install pandas matplotlib如果你的网络环境不太好pip默认从国外源下载经常卡到怀疑人生。这时候用国内镜像会快很多我用的是清华源pip install pandas matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后不要急着写代码先做一次环境自检确认pandas和matplotlib都装上了。运行下面这个命令python -c import pandas as pd; import matplotlib; print(pd.__version__, matplotlib.__version__)如果能输出两个版本号说明环境基本没问题。如果这里就报ModuleNotFoundError也别慌回头检查一下是不是忘了激活venv或者pip是不是装到了别的Python版本里。这类问题非常常见多半不是代码问题而是“当前解释器”选错了。2.4 装完先别写业务代码做一次“环境自检”说到解释器选择必须提醒一句。很多人用VS Code或者PyCharm明明在终端里敲python能运行但只要一运行.py文件就提示找不到pandas。为什么因为VS Code默认用的解释器可能不是你在终端里激活的那个虚拟环境。VS Code的解决办法是按CtrlShiftP输入“Python: Select Interpreter”然后选择venv目录下的Python解释器。PyCharm更简单右下角状态栏会显示当前的解释器路径点一下就能切换。这个小坑当时卡了我二十分钟后来才发现是解释器选错了。我这次的完整流程是先把CSV文件放到项目目录里创建并激活虚拟环境装好两个库在VS Code里把解释器切到venv然后才正式写代码。这一步做完后面几乎再没遇到环境层面的大坑。3. 数据清洗这一关pandas是真的能省命3.1 读入CSV后的第一件事不是写逻辑而是看结构这块是我今天花时间最多的部分。拿到CSV文件后我一上来就想写分组统计结果发现日期格式不对、气温列里混着空字符串还有几行完全重复的数据。这些脏数据不处理干净后面怎么统计都是错。pandas读入CSV就一行代码import pandas as pd df pd.read_csv(weather.csv, encodingutf-8)但读完后的第一件事绝对不是写统计逻辑而是先看数据长什么样。我是这么看的print(df.head()) print(df.info()) print(df.describe())head()看前几行数据info()看每列的类型和缺失值情况describe()看数值列的统计概览。这一步的作用相当于见到陌生人先打量一眼知道对方什么性格再决定怎么打交道。如果不管三七二十一就开算很容易被隐藏的数据格式问题坑到。我当时看info()的输出发现“最高气温”这一列的类型是object而不是int64这就意味着里面的值多半不是纯数字可能混着单位或者空字符串。3.2 缺失值、重复行、类型转换清洗顺序有讲究清洗不是把所有能调用的方法都用一遍顺序很重要。我的操作顺序是去重、修类型、处理缺失值。先删重复行df df.drop_duplicates()再处理类型。气温列里有脏数据直接用pd.to_numeric遇到转换不了的值就变成NaN而不是报错中断df[最高气温] pd.to_numeric(df[最高气温], errorscoerce)日期列也转成真正的日期类型df[日期] pd.to_datetime(df[日期])最后处理缺失值。我这份数据里缺失行不多直接用dropna删掉缺了气温数据的行就行df df.dropna(subset[最高气温, 最低气温])这里有个原则问题如果缺失值很多直接删可能损失太多信息如果只是零星几行删掉最省事。新手容易掉进“为了清洗而清洗”的坑把简单问题复杂化。我的经验是先删重复、再转类型、最后看缺失值每一步都打印一下df.shape看看数据规模变化。3.3 groupby分组统计按城市和日期各算一遍平均值清洗完成后才进入真正的统计环节。我需要回答两个问题每个城市的平均最高气温是多少以及整个时间段内每天的平均最高气温是怎么变化的。第一个用groupbycity_mean df.groupby(城市)[最高气温].mean() print(city_mean)第二个也是groupby只是分的组变成了日期daily_mean df.groupby(日期)[最高气温].mean() print(daily_mean)这里我得特别说一句今天的热搜关键词里有一条问我查了很多次“groupby属于哪个库” 它不属于什么冷门库就是pandas里的方法。之所以有人会被绕晕是因为pandas用得太泛大家直接用df.groupby()很少会关心背后的库归属。遇到这种问题直接import pandas as pd然后df.groupby就能用。groupby的用法我的理解是“先分组再聚合”。groupby(城市)相当于把相同城市的行聚到一起后面接的mean()是对指定列求平均值。如果想一次算多个统计量可以写city_stats df.groupby(城市)[最高气温].agg([mean, max, min, count])这比写多个for循环手算省太多了也是pandas“向量化”思维的核心能用内置聚合方法解决就别自己写循环。3.4 把清洗结果导出顺便解决常见的编码和路径问题统计结果不能只在屏幕上放一下我还想着后面画图用。所以把两个结果都导出成CSVcity_mean.to_csv(city_mean.csv, encodingutf-8-sig) daily_mean.to_csv(daily_mean.csv, encodingutf-8-sig)注意这里用了utf-8-sig而不是utf-8原因是Windows下的Excel打开UTF-8编码的CSV时容易乱码。加个BOM头能让Excel认出编码这也是今天踩到的一个小坑。路径问题同样值得提。我一开始运行脚本时用的是相对路径比如pd.read_csv(weather.csv)这在项目目录下运行没问题但如果你从别的目录运行脚本就会报文件找不到。后来我改成用pathlib定位项目根目录不管从哪里运行都能找到文件from pathlib import Path BASE_DIR Path(__file__).parent df pd.read_csv(BASE_DIR / weather.csv, encodingutf-8)这个习惯对后面打包exe尤其有用因为打包后程序的运行目录会变如果路径写死绝对路径很容易踩坑。4. 用matplotlib把数字变成图乱码和坐标轴是绕不开的坎4.1 该用折线图还是柱状图先想清楚要回答什么问题数据统计出来了下一步就是可视化。选图表类型这件事我踩过一个“为了好看乱选图”的坑。其实选图逻辑很简单柱状图适合对比几个分类的数值比如各城市的平均最高气温对比折线图适合看数值随时间的变化趋势比如每日平均气温的变化。我这两个结果恰好各用一种。城市对比用柱状图import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False city_mean.plot(kindbar) plt.title(各城市平均最高气温) plt.xlabel(城市) plt.ylabel(温度(℃)) plt.tight_layout() plt.savefig(city_mean.png)每日趋势用折线图plt.figure(figsize(12, 6)) plt.plot(daily_mean.index, daily_mean.values, markero, markersize3, linewidth1) plt.title(每日平均高温变化) plt.xlabel(日期) plt.ylabel(温度(℃)) plt.xticks(rotation45) plt.grid(alpha0.3) plt.tight_layout() plt.savefig(daily_mean.png)这里plt.rcParams[font.sans-serif] [SimHei]是解决中文乱码的关键。matplotlib是出了名的“中文乱码重灾区”如果你不设置字体图里的中文标题会变成一个个小方块。4.2 中文乱码不是玄学一次把字体配置写对中文乱码的根因是matplotlib默认字体不支持中文你只需要指定一个本机支持中文的字体即可。Windows一般用SimHei或Microsoft YaHeimacOS可以用PingFang SC或Arial Unicode MSLinux可以用WenQuanYi Micro Hei。我更推荐一种做法是直接写个配置函数放在脚本开头import matplotlib import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [Microsoft YaHei, SimHei, WenQuanYi Micro Hei] plt.rcParams[axes.unicode_minus] False第三行的axes.unicode_minus False是用来解决负号显示成方块的问题。很多教程只写了字体没写负号结果画温度负值时就会出现一个诡异的方块。如果你用的是Linux服务器还没有中文字体可能要安装sudo apt install fonts-wqy-microhei这就是为什么有时候代码在自己电脑上跑得好好的放到服务器上就乱码——不是代码问题是对方系统没有对应字体。4.3 坐标轴旋转、网格线、图例这些“小细节”才是观感关键画图的坑不仅在字体还在各种看起来无关紧要的小参数。比如日期比较多的时候x轴标签会全部挤在一起根本看不清。一个plt.xticks(rotation45)就能让标签旋转45度清爽很多。网格线也是观感的关键。我一开始画图没加网格线条光秃秃的根本看不出数值点在哪里。后来加了plt.grid(alpha0.3)透明度调低一点既不喧宾夺主又能让读者快速定位数值。图例也很重要。如果一张图里有多条线不标图例等于白画。但如果只有一个序列图例反而多余。我的经验是有多组数据就写plt.legend()单线图别硬加。还要说一下tight_layout()。这个函数解决的是“标题和坐标轴标签被截断”的问题。我每次画完图都会调用它省得多调边距。4.4 保存图片到本地以及顺手画个爱心的小彩蛋保存图片我一直用plt.savefig()和plt.show()配合使用。有个细节如果你先调用了show()再调用savefig()保存出来的图可能是空白的。正确的顺序是先savefig()保存再show()查看。今天项目搞完后还给自己加了个小彩蛋既然学了matplotlib顺手画了个爱心代码很简单import numpy as np t np.linspace(0, 2 * np.pi, 500) x 16 * np.sin(t) ** 3 y 13 * np.cos(t) - 5 * np.cos(2 * t) - 2 * np.cos(3 * t) - np.cos(4 * t) plt.figure(figsize(6, 6)) plt.plot(x, y, colorred) plt.axis(equal) plt.show()这个公式是一个经典的心形曲线。别小看这几十行代码它让我彻底理解了“x轴序列 y轴序列 plot函数”这个画图铁三角以后不管画什么图都绕不开这个思路。学透一个例子比背十张图有用。5. 想把脚本给别人用打包exe前你最好先知道这些坑5.1 为什么需要打包以及PyInstaller的定位项目脚本写完了我自己用没问题但身边同事想打开看看总不能让他们先去装Python、装venv、装pandas吧这时候打包成exe就是最省事的选择。今天用的工具是PyInstaller把一个Python脚本连同依赖的库一起装进一个文件夹或单个exe。PyInstaller的定位很简单把我的项目打包成可执行文件目标机器上不需要装Python环境。但这份“便利”是有代价的打包出来的exe体积通常很大而且第一次运行会比较慢因为要把很多动态库加载到内存里。这些预期先建立起来免得打包完被体积吓到。5.2 最简单的打包命令和两种常见模式的区别打包前先在虚拟环境里安装PyInstallerpip install pyinstaller然后针对我已经写好的脚本weather_report.py常见的打包命令是pyinstaller -F -w weather_report.py这里有两个重要参数。-F意思是打成一个单独exe文件方便分发如果不用-F会生成一个文件夹里面有很多依赖文件运行速度会快一点但分发时要整个文件夹一起给。-w意思是运行时不弹出黑色命令行窗口适合有图形界面的脚本。如果我的脚本还需要打印日志就不能加-w否则什么都看不到。我这次用了-F因为只生成一个exe发给别人最简单。但后来发现每次启动这个exe要等两三秒因为PyInstaller会先把所有依赖解压到临时目录。如果你特别在意启动速度其实用文件夹模式更合适。5.3 打包后exe双击没反应先按这个思路排查打包exe最大的坑是“我这里跑得好好的双击exe却没反应”。我一开始也遇到了双击没有任何窗口弹出来也没有报错。排查思路很关键不要在-w模式下找原因因为它把控制台屏蔽了任何报错信息你都看不到。正确的做法是先用不带-w的命令重新打包一次pyinstaller -F weather_report.py这样运行时会出现一个黑色窗口所有报错信息都会打到窗口里。常见的错误是找不到数据文件。因为PyInstaller打包时weather.csv不会被自动包含进去程序运行时在当前目录找不到这个文件就静默崩溃了。解决办法有两种。一种是把weather.csv放在exe同目录下用上一节说的BASE_DIR / weather.csv路径读取。另一种是把CSV文件作为数据文件一起打进去但那样读取路径要改对新手来说更绕。我推荐第一种简单直接。5.4 关于体积、杀软误报和依赖问题的实话打包出来的exe很大我的脚本只有几十行但exe有50多MB。为什么会这样因为PyInstaller把pandas和matplotlib这些库的核心部分都塞进来了而这两个库本身依赖很多底层的二进制文件。这是Python打包的通病很难瘦身到几MB。还有一点要坦然接受某些杀毒软件会对PyInstaller打包的exe误报。因为Python脚本被封装成二进制文件后有些包的特征和加壳程序相似。我遇到过一次添加了信任就能解决。正经的解决方案是尽量用虚拟环境打包、保持PyInstaller版本更新另外别从不明来源下载打包工具。需要强调的是我这里说的是正常开发流程大家只在信任的环境里使用打包结果。6. 第11天复盘哪些“本来会背”的知识这次终于真的会用了6.1 从需求倒推技能点读文件、类型转换、函数、循环全被激活这一天下来我最大的感受是之前单独看每个知识点都觉得简单而一旦放进真实项目它们会互相纠缠逼我理解得更深。比如类型转换。以前我以为int(42)就是全部了。今天遇到pd.to_numeric(..., errorscoerce)才发现生产环境里的“脏数字”远比教材复杂可能是空字符串、可能是带逗号的千分位数字还有可能是--这种无效值。pandas的errorscoerce会把转换不了的变成NaN这样后续就能统一处理。这种“失败友好”的设计思路和直接报错的方式体验完全不同。再比如函数和循环。以前写循环是为了遍历列表今天写统计是在一个二维表格上做聚合。虽然我没显式写for循环但groupby的背后逻辑其实就是“按某个key把数据分组再对每组做计算”。一旦理解了这个以后遇到更复杂的聚合需求思路会清晰很多。6.2 一次典型报错的排查全过程比报错本身更有价值今天最典型的一个错误是KeyError: 最高气温。我明明在CSV里看到这一列了为什么pandas说找不到查了半天发现是列名里有空格CSV文件里写的是最高气温我代码里写的是最高气温。这个排查过程让我学会了pandas的一个基本功先打印df.columns看清楚每一列的真实名字和顺序。别看这个动作小几乎能解决一大半“KeyError”问题。另一个报错是ValueError: could not convert string to float: 27℃。气温列里混着单位℃导致pd.to_numeric默认模式下直接报错。加上errorscoerce之后转换失败的值变成了NaN但后续又要把这些NaN删除才意识到“不直接报错”的代价是“有可能留下隐藏的空值”。这两种设计各有适用场景区别在于你想让程序停下来还是继续跑。6.3 下一步方向从本地数据到爬虫和API第11天之后我对Python的认识变了很多。以前只会在本地处理静态数据现在开始琢磨这些CSV怎么才能自动更新于是自然而然想到了爬虫把网页上的结构化数据抓下来再沿用今天这套清洗和可视化流程。热搜里看到有人问“python调用讯飞星火API”这类问题其实底层逻辑都是一样拿到数据、处理数据、展示结果只是数据来源不同。今天学的pandas和matplotlib不会只为一个CSV服务它们可以处理任何结构化数据。以后不管是从Excel读、从数据库读、还是从API接口里拿数据清洗和可视化的思路都可以复用。这也是这一天的核心收获。回头看看这第11天我花在“查报错”上的时间比“写代码”多但我不觉得浪费。以前背概念是知今天踩坑是行。知和行一结合很多貌似高深的东西就变得普通了。如果你也正处在“学完基础语法但不知道下一步干嘛”的关口我建议你别急着再找一本厚书从头啃而是挑一个一两天能做完的小项目拿真实数据过一遍。等这个项目跑通你会发现自己已经离“能独立写程序”的人不远了。
返回列表