简介:这是一套面向环保数据分析与后端开发学习者的城市空气质量数据分析平台源码包,帮助掌握从数据采集、入库、清洗到统计可视化的完整流程。技术栈涉及Python、requests、SQLAlchemy与matplotlib,可应用于课程设计、毕业设计或环境数据分析入门实践。压缩包共9个文件,以6个Python脚本为主,配合2个文本说明与1个Markdown文档,分别实现数据采集、数据库存储、数据处理、可视化展示等模块,结构清晰便于二次开发。资源包约18KB,轻量易部署。目前已有123人学习下载。通过代码与说明文档,用户可快速搭建一套可运行的空气质量监控演示系统,并了解面向对象封装、数据库映射及数据可视化等关键实现细节。 城市空气质量数据分析平台,听起来像是一个可以查查今天适不适合跑步的简单面板,但真动手做起来才发现,这玩意儿的地基是整套数据处理链路。你以为你缺的是“画图代码”,实际上你缺的是:怎么拿到干净可信的监测数据、怎么把几十个站点的分钟级数据管起来、怎么让“AQI”这个数字经得起业务方追问,以及最后怎么把分析结果变成别人愿意天天打开看的界面。这篇文章我就用自己的实操经历,把从零搭一个城市空气质量数据分析平台的全过程拆开来讲,适合正在做数据分析项目但不知道从哪下手的同学,也适合已经跑通Demo但卡在细节上的同行。
1. 从“看一张图”到“建一个平台”,差距到底在哪
1.1 一张空气质量的图,背后是整整一条数据链路
如果你只是用爬虫抓一个城市的实时AQI,然后画个折线图,那你其实不需要“平台”这两个字。一个定时脚本加一个Excel图表就够了。但一旦你要回答下面这些问题,事情就变了:
- 过去三年这个城市的PM2.5是整体变好了还是局部恶化?
- 哪个城区的臭氧高发季是哪几个月?和温度湿度到底有没有关系?
- 春节前后的污染峰值,是燃放烟花还是气象扩散条件变差导致的?
- 某个监测站的数据突然比周边高出一倍,是真的污染事件还是传感器漂移?
这些问题没有一个能靠单个接口返回的现成数字回答。它们要求你把“历史数据”“空间分布”“多污染因子”“气象要素”全部关联起来,并且保证每一次计算的口径是一致的。这才是“数据平台”和“一张报表”的分水岭——平台意味着可重复、可追溯、可扩展,报表只是一次性产物。
1.2 平台不是把图表搬到网页上
我做第一版的时候犯过一个典型错误:以为数据进了数据库、前端用ECharts画了图,就算平台了。结果业务方问了一句“你这个AQI用的是日均值还是实时滑动平均?”我当场卡住——因为我根本没在数据流里区分统计口径。
这也引出了平台架构里最容易被忽略的一点:数据分析平台的本质不是“可视化项目”,而是“口径管理项目”。同一个指标,站房日均值、城市日均值、实时发布值、滑动24小时均值,算出来的数字可能差别巨大。所以在架构设计阶段,就应该把“数据分层”想清楚,而不是上来就写图表代码。
我最终采用的架构分四层:
- 采集层:定时拉取监测站点JSON、气象接口、历史离线文件。
- 存储层:原始数据原样落库,同时建立按小时、按天的汇总表。
- 分析层:AQI计算、相关性分析、污染特征提取,全部写成可复用的Python模块。
- 应用层:Web面板、导出服务、定时告警。
这个分层最直接的好处是:每个环节都能单独验证,出了问题能快速定位是采集坏了、清洗错了还是展示层写崩了。
2. 数据采集与清洗:环境监测数据最容易踩的坑
2.1 采集通道怎么搭:公开接口、站点文件与气象数据
空气质量监测数据的来源,比很多人想象中要杂。常见的公开接口返回的是“城市均值”或“站点实时值”,适合做实时展示;但做历史分析时,公开接口往往只保留最近几天,你必须要找历史数据文件来补。不同来源的字段、单位、更新频率还完全不一样——有的返回的是PM2.5的质量浓度(微克每立方米),有的返回的是AQI指数,有的站点文件里直接混着没校准的原始计数。
我在项目里把采集通道分成了三类:实时轮询接口、定时下载的日更文件、以及气象接口(因为后续做相关性分析必须用到温湿度、风速)。每类通道单独写采集器,统一输出为标准的JSON结构,落到同一个原始数据表里。这样做的原因是:单一接口挂掉不会被其他链路拖累,而且来源可以在原始表里用字段区分,方便追查异常数据的根因。
提示:采集频率不是越高越好。监测站点的数据本质上是每5分钟或每小时的仪器读数,你30秒轮询一次,拉到的还是同一个值,徒增存储和接口压力。实测下来,5分钟拉一次实时值,每天定时补拉一次日更文件,基本能覆盖展示和分析两种场景。
2.2 清洗的真实战场:缺失、漂移与口径差异
环境监测数据的脏,是那种“表面看很整齐、一算就翻车”的脏。我总结下来最折磨人的三类问题:
- 缺失值不是随机的。夜间到凌晨时段,部分站点会上传失败,连续缺失三五小时是常态;如果直接对缺失值做线性插值,碰到早晚高峰污染突变期,插出来的值会“削峰填谷”,让真实污染过程完全失真。
- 传感器会漂移。同一个城市两个站点,理论上PM2.5读数不会差太远,但设备校准周期不一致、光学传感器老化,可能导致某站点持续偏高或偏低,时间久了就出现“永久性系统偏差”。这类偏差如果在分析前不修正,算出来的城市均值会带方向性误差。
- 统计口径五花八门。有的数据源给的是整点瞬时值,有的是小时均值,还有的是从小时均值反推的日均值;更隐蔽的是,某些城市的“日均值”用的是北京时间,某些公开数据集却用UTC时间存储,差8小时直接导致每日曲线错位。
我处理缺失值的原则是:连续缺失不超过2小时,用前后2小时均值插补,但不参与日均值计算;连续缺失超过6小时的,当天日均值直接标记为不可用,宁缺毋滥。对于传感器漂移,用同城同类型站点的同期中位数做归一化比值,计算出疑似漂移站点的偏差系数,在分析时打标签,而不是粗暴改数。
下面是我整理的一个常见问题速查表,很多新手踩坑都逃不出这几条:
| 问题类型 | 典型表现 | 我的处理方式 |
|---|---|---|
| 时间时区不一致 | 日曲线整体偏移8小时 | 统一转为北京时间并加来源标记 |
| 站点搬迁 | 某站某日后数据整体跳变 | 在站点字典表里记录搬迁日期,分析时按“搬迁前后”切分 |
| 单位不一致 | 某字段数值是另一位字段的1000倍 | 根据污染物量级自动校验量程,异常量程转警告 |
| 日均值算法差异 | 城市均值和站点均值对不上 | 明确区分“站点日均”和“城市日均”,分开存储不下混 |
| 实时值跳变 | 短时间出现极端峰 | 用同区域站点做横向比对,超出3倍标准差才标记 |
3. 存储选型:MySQL、时序数据库与大数据框架的取舍
3.1 先算数据量,再决定要不要上重框架
很多人在项目一开始就想着“我是不是该上Hadoop/Spark?”——说实话,城市级空气质量分析平台,数据量远没到需要大数据框架的级别。我们来算一笔账:一个城市假设50个监测站点,每个站点每5分钟一条记录,一天的原始数据量是50乘以288,等于14400条,一年也就500多万条。就算加上气象站数据,单表一年几千万条,对MySQL来说完全是常规操作,只要索引设计合理,查询性能完全够用。
我第一版用了MySQL,一张原始数据表加一张日均汇总表,加上合理索引,后端跑得相当轻松。真正需要思考的不是“要不要上Spark”,而是“要不要上时序数据库”。时序数据库在处理连续时间段聚合、保留策略、压缩存储方面确实比MySQL省心,但引入一套新组件也意味着运维成本上升。如果你只是自己跑个分析平台,MySQL加分区表就是性价比最高的方案。
3.2 什么时候该换时序数据库,什么时候别碰大数据栈
我给一个相对实用的判断标准:单城市、站点少于100个、分钟级采集,MySQL完全够用;如果要做多城市对比、历史十年以上数据、甚至接入气象预报模型输出,建议上时序数据库(InfluxDB或TDengine这类),因为它的连续查询和自动保留策略能省掉大量写定时任务的时间。
| 方案 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| MySQL + 分区表 | 运维简单、生态成熟、团队都熟 | 时间聚合要自己写 | 单城市、站点数100以内、分钟级 |
| 时序数据库 | 聚合快、保留策略自动清理、压缩率高 | 需要额外运维、生态相对小众 | 多城市、长周期、高并发写入 |
| Spark/Flink等大数据栈 | 处理海量数据能力强 | 太重,开发部署成本高 | 数据量日均亿级以上,基本用不上 |
我最后采用的做法是:MySQL存原始数据和日汇总,月汇总再单独建一张表。写了一个定时任务,每天凌晨把前一天的小时数据聚合成日均数据,再喂给分析模块。这个轻量方案让我整个平台在一年多的运行里没有因为存储性能头疼过一次。很多面试题里喜欢问“实时流处理”,但工程上先满足“今天能用、明天可扩展”才是第一位。
4. 分析模型:从AQI计算到污染特征挖掘
4.1 AQI计算里的口径细节,比你想的更讲究
AQI(空气质量指数)不是一个传感器测出来的直接值,而是由六项污染物——PM2.5、PM10、SO₂、NO₂、CO、O₃——的分指数(IAQI)取最大值得到的。每一档的浓度界限不同,计算时要先判断当前浓度落在哪个区间,再用线性插值算分指数。这个逻辑本身不复杂,但实现时有两个坑:
第一,标准表经常更新,环保部门在不同年份发布过不同版本的浓度限值,如果你把旧版本的表格写死在代码里,跨年份分析时就会系统性偏差。我处理方式是把标准表单独存一张配置表,计算时根据日期自动选择对应版本。
第二,实时发布值和日均值计算使用的时间窗口不同。比如O₃的评价标准用的是最大8小时滑动平均值,CO用的是24小时均值,如果直接用整点瞬时值去套标准表,算出来的IAQI在部分时段会失真。代码层面我建议把“计算窗口”和“浓度插值”拆成两个独立方法,方便复用和测试。
def calc_iaqi(concentration, breakpoints, iaqi_range): # 简化示例,实际工程中用 decimal 处理四舍五入 for i in range(len(breakpoints) - 1): bp_lo, bp_hi = breakpoints[i], breakpoints[i + 1] if bp_lo <= concentration <= bp_hi: lo_i, hi_i = iaqi_range[i], iaqi_range[i + 1] return round((hi_i - lo_i) / (bp_hi - bp_lo) * (concentration - bp_lo) + lo_i) return None4.2 真正有价值的是“多因子关联”分析
AQI只能告诉你“今天空气质量好不好”,平台能不能提供增量价值,取决于你能否回答“为什么不好”以及“趋势是怎样的”。我在分析层做了三个方向,实测下来覆盖了业务方80%的问题:
- 污染物相关性分析。把PM2.5、PM10、NO₂和气象要素放到一起算相关系数,能直观看出城市污染类型。比如某城市PM2.5和PM10的高相关性说明扬尘贡献不小,NO₂和CO的相关性则提示机动车排放特征。
- 时间序列分解。把历史日均值分解为趋势项、季节项和残差项,能识别出“大概率是长期减排政策有效”还是“只是今年气象条件帮忙”这类问题。这对做治理效果评估特别有用。
- 空间分布聚类。按站点坐标做污染区域聚类,能发现城市内部的“污染孤岛”,以及跨站点污染输送的可能路径。
做相关性分析时有个容易被忽略的点:相关系数对异常值非常敏感。如果某几天有强沙尘事件,PM10数据会出现极高值,直接把相关系数拉到接近1,会误导判断。我处理方式是先做一次稳健标准化(用中位数和MAD替代均值和标准差),再做相关性计算,或者在计算前剔除标记为异常的事件日。面试题里经常考“相关不代表因果”,在空气质量数据分析里体现得淋漓尽致——温度升高和臭氧浓度上升相关,但不等于升温导致臭氧生成,背后是光化学反应机制。
5. 可视化与平台化:开源方案落地的完整思路
5.1 图表选型:别一上来就买商业BI
市面上有很多商业BI工具做数据面板很省事,但对空气质量这种带地理信息、实时性要求又高的场景,开源技术栈反而更灵活。我最终的技术选型是:地图用Leaflet加OpenStreetMap底图,图表用ECharts,后端用FastAPI提供JSON接口,前端用轻量Vue页面承接。整套下来视觉效果完全不输那些需要按年付费的BI工具。
用ECharts做空气质量可视化有几个非常顺手的内置能力:地图上做散点分布图可以直接标注站点位置,用颜色映射AQI等级;日历热力图能一眼看出一整年哪几个月污染高发;时间序列图自带缩放和平滑,对小时级数据拖拽查看特别友好。我强烈建议把“地图散点图层”和“时间曲线图例”联动起来,点击地图站点的瞬间,下方折线图切换到该站点历史曲线,这个交互效果在实际使用中比任何花哨大屏都实用。
5.2 平台化不止是做一个页面
做可视化页面只是平台化的外壳,真正的平台化体现在三件事上:定时调度、自动告警、元数据管理。
调度方面,我用的是Cron加一个Python调度脚本,每天凌晨拉历史数据、计算日均值、刷新汇总表。告警逻辑写成一个独立服务:当某个站点的实时AQI连续一小时超过设定的阈值,就通过邮件或企业微信机器人推消息。这一条看起来简单,但实际效果很好——污染过程刚起头就能知道,不用等第二天看昨天数据。
元数据管理是我后期补上的,也是最庆幸补上的一环。每个表、每个指标、每次算法版本都记录了“计算口径、数据来源、更新频率、归属人”。有一次业务方质疑某天PM2.5数据偏高,我靠数据字典里记录的“该站当天处于沙尘影响标记状态”,十分钟就解释清楚了。如果没有这份元数据,可能又要从代码里一行行翻。
6. 复盘:做完这个平台我最后悔的几件事
先说最后悔的第一件事:花了太多时间在“让图表更炫”上。我一度沉迷调动画效果、配色方案,结果真正上线后,用户问得最多的永远是“数据准不准”“为什么和官方APP不一样”。后来我把精力全部转移到数据校验和口径对齐上,给每个数字都标清了统计周期和来源,用户的信任感反而眼看着涨。
第二件后悔的事是前期没做字段命名规范。采集器是从不同数据源写的,有的字段叫pm25,有的叫pm2_5,还有的直接叫value,后期写分析脚本时到处做字段映射,白白改了一周代码。如果你也打算做类似平台,我最真诚的建议是:第一步先定一份字段字典。
最后一件我想提醒的是:别高估历史数据的可用性。网站提供的历史数据文件经常存在延迟补传、版本修订的情况,如果只按日期去拉,可能拉到的是修订前的版本。我的经验是每周末做一次全量历史数据对齐,把过去七天所有天的数据和官方渠道重新比对一遍,发现偏差自动覆盖更新。这个机制让我在“数据可信度”这件事上没有翻过大车。
城市空气质量数据分析平台这个项目,做完以后回头看的感受是:技术上没有一项是“高精尖”,它考验的是你能不能把琐碎的采集、清洗、计算、展示串成一条不塌方的流水线。数据平台的价值从来不在于代码多复杂、图表多炫,而在于别人问起任何一个数时,你敢不敢说一句“这个数我知道是怎么来的”。
本文还有配套的精品资源,点击获取