查看全课大纲(第 41 / 51 节)
- 1.为什么人人都该学点编程?
- 2.计算机与程序设计:你的电脑到底在“想”什么?
- 3.Python 这门语言,到底有什么魔力?
- 4.Python 开发环境配置:如何拥有你的第一个“编程工具箱”?
- 5.如何安装一个更强大的代码编辑器?
- 6.汇率兑换1.0:你的第一个“钱生钱”小程序
- 7.你的第一行代码,藏着哪些秘密?
- 8.汇率兑换2.0(上):让程序看懂“CNY”和“USD”
- 9.汇率兑换程序,如何让它“聪明”地判断币种?
- 10.汇率兑换程序能一直运行,直到我喊停吗?
- 11.汇率兑换4.0:如何把“算钱”功能打包成积木?
- 12.汇率兑换5.0:给你的程序穿上“结构化”的西装
- 13.怎么用 Python 画一个会动的五角星?
- 14.如何让程序自动画出不同大小的五角星?
- 15.函数自己调用自己,会发生什么?
- 16.用递归画出神奇的分形树
- 17.Python 怎么计算你一天躺着不动能消耗多少热量?
- 18.如何让程序“活”起来,持续为你服务?
- 19.如何让 BMR 计算器更“聪明”?
- 20.当程序遇到“不按套路出牌”的用户怎么办?
- 21.怎么用 Python 模拟一个“滚雪球”式的存钱计划?
- 22.如何用列表记录每一周的存款?
- 23.如何让程序自己数数?—— 用 for 循环解放你的双手
- 24.52周存钱挑战4.0:你的存款计算器能有多灵活?
- 25.52周存钱挑战:怎么根据日期自动查存款?
- 26.Python 怎么判断一年中的第几天?
- 27.列表 vs 元组:哪个更适合存储月份天数?
- 28.用集合给月份分个队,换个思路算天数
- 29.把月份和天数“锁”在一起:用字典给数据配个对
- 30.Python 怎么判断密码强弱?
- 31.Python 怎么给密码设置“防沉迷”系统?
- 32.Python 怎么把密码保存到文件里?
- 33.Python 怎么读取文件里的密码?
- 34.Python 怎么把密码检查工具“打包”起来?
- 35.Python 怎么把文件操作也“打包”起来?
- 36.计算机怎么“扔骰子”?——用Python模拟随机事件
- 37.如何用 Python 模拟掷两个骰子?
- 38.怎么用 Python 把骰子轨迹画出来?
- 39.骰子点数分布长啥样?用直方图一眼看穿!
- 40.用科学计算库让骰子程序“起飞”
- 41.空气质量指数怎么算?手把手教你写一个AQI计算器
- 42.空气质量指数计算:从零开始,让程序看懂空气
- 43.如何读取空气质量数据文件并找出空气质量最好的五个监测点?
- 44.JSON 数据怎么变成 Excel 表格?—— 让数据换个“马甲”
- 45.Python 怎么让程序自己判断文件类型?
- 46.如何让程序自己上网查空气质量?
- 47.用美味的汤来解析网页:Beautiful Soup 入门
- 48.如何让爬虫自动抓取全国所有城市的空气质量?
- 49.爬到的数据怎么存下来?—— 把全国空气质量数据保存为CSV文件
- 50.用 pandas 玩转空气质量数据:找出全国空气最好和最差的城市
- 51.空气质量数据怎么“洗”干净,还能画成图?
空气质量指数怎么算?手把手教你写一个AQI计算器
约 18 分钟
小象实战讲义 · Python 入门:8 个小项目边玩边学
欢迎来到我们《Python 入门》课程的最后一个项目!经过前面八个项目的历练,你已经从完全不会写代码,到现在能做出汇率换算、存钱计划、密码评分等实用工具。今天我们要挑战一个跟生活特别相关的项目——空气质量指数(AQI)计算器。
想象一下:你早上出门前,想知道今天的空气质量怎么样,是适合户外运动还是最好待在室内?通过今天的学习,你将能自己写一个程序,输入PM2.5、一氧化碳等污染物的浓度值,就能计算出对应的AQI指数,告诉你空气质量到底如何。
更重要的是,这个项目会把你之前学过的所有知识都用上,还会加入一些新的技巧,让你感受到「学以致用」的成就感。
💡 核心导读
本节你将学到:
- AQI的计算原理:空气质量指数是怎么算出来的?
- 函数的分层设计:如何把一个复杂问题拆成几个简单函数
- 列表与最大值:如何从多个污染物指数中找出最差的那个
- 线性缩放:数学中的「按比例换算」在编程中怎么实现
空气质量指数:一个数字背后的科学
空气质量指数(AQI)是一个用来定量描述空气质量状况的数字。你可能在天气预报里见过它,比如「今日AQI 85,空气质量良」。但这个数字是怎么来的呢?
其实,AQI是由多种污染物的分指数计算出来的。空气中常见的污染物有:
- PM2.5(细颗粒物)
- PM10(可吸入颗粒物)
- 二氧化硫(SO₂)
- 二氧化氮(NO₂)
- 一氧化碳(CO)
- 臭氧(O₃)
每种污染物都有自己的浓度标准。环保部门会监测这些污染物的浓度,然后通过一个公式计算出每种污染物的「分指数」(IAQI),最后取所有分指数中的最大值作为最终的AQI。
为什么取最大值?因为空气质量是由「最差」的那个污染物决定的!就像木桶的短板效应一样。
查表计算:从浓度到指数
我们来看一个具体的例子。假设监测到PM2.5的浓度是55 µg/m³(微克每立方米)。
根据国家标准,PM2.5的浓度分级是这样的:
| 浓度范围(µg/m³) | 对应的AQI范围 |
|---|---|
| 0 – 35 | 0 – 50 |
| 35 – 75 | 50 – 100 |
| 75 – 115 | 100 – 150 |
| …(后面还有更多分级) |
55落在35-75这个范围里,所以我们需要把浓度值55「映射」到AQI的50-100这个范围。
这其实是一个线性缩放的过程:把浓度范围[35, 75]按比例缩放到指数范围[50, 100]。
计算公式是这样的:
IAQI = (IAQI_高 - IAQI_低) × (浓度 - 浓度_低) ÷ (浓度_高 - 浓度_低) + IAQI_低代入我们的数值:
IAQI = (100 - 50) × (55 - 35) ÷ (75 - 35) + 50
= 50 × 20 ÷ 40 + 50
= 25 + 50
= 75所以PM2.5浓度为55时,它的分指数是75。
本节新增了什么? 我们第一次接触「查表计算」和「线性缩放」的概念,这是很多实际应用(比如成绩换算、温度转换)的基础思路。
搭建程序框架:先想清楚再动手
写复杂程序时,一个好习惯是先搭框架,再填细节。就像盖房子先画设计图一样。
我们的AQI计算器需要做这几件事:
- 让用户输入两种污染物的浓度值
- 分别计算每种污染物的分指数
- 取两个分指数中的最大值作为最终AQI
- 输出结果
# AQI计算器 v1.0 - 框架版
# 功能:计算空气质量指数
def cal_pm_iaqi(pm_val):
"""计算PM2.5的分指数"""
# 这里先留空,后面实现
pass
def cal_co_iaqi(co_val):
"""计算一氧化碳的分指数"""
# 这里先留空,后面实现
pass
def cal_aqi(param_list):
"""计算最终的AQI"""
pm_val = param_list[0] # 第一个值是PM2.5
co_val = param_list[1] # 第二个值是一氧化碳
# 计算各自的分指数
pm_iaqi = cal_pm_iaqi(pm_val)
co_iaqi = cal_co_iaqi(co_val)
# 放到列表里,取最大值
iaqi_list = []
iaqi_list.append(pm_iaqi)
iaqi_list.append(co_iaqi)
aqi = max(iaqi_list) # 取最大值
return aqi
# 主程序开始
print('请输入以下信息,用空格分割')
# 原程序用 input() 让用户输入,这里用固定值代替,你可以改成自己的值试
input_str = '55 2' # PM2.5=55, 一氧化碳=2
print(f'(1)PM2.5 (2)CO: {input_str}')
# 分割字符串,转换成数字
str_list = input_str.split(' ')
pm_val = float(str_list[0])
co_val = float(str_list[1])
# 放到列表里传给计算函数
param_list = []
param_list.append(pm_val)
param_list.append(co_val)
# 调用AQI计算函数
aqi_val = cal_aqi(param_list)
print('空气质量指数为:{}'.format(aqi_val))运行这个框架程序,虽然还不能真正计算(因为分指数函数还没实现),但你能看到程序的流程已经清晰了。
小技巧:pass 是Python的一个特殊语句,意思是「这里先占个位置,什么都不做」。在搭框架时特别有用。
实现线性缩放函数
刚才我们提到,计算分指数本质上是做线性缩放。这个功能很通用,我们可以把它单独写成一个函数。
# 线性缩放函数
def cal_linear(iaqi_lo, iaqi_hi, bp_lo, bp_hi, cp):
"""
线性缩放函数
参数说明:
iaqi_lo: 目标范围下限(AQI低值)
iaqi_hi: 目标范围上限(AQI高值)
bp_lo: 原始范围下限(浓度低值)
bp_hi: 原始范围上限(浓度高值)
cp: 当前浓度值
"""
# 公式:IAQI = (IAQI高 - IAQI低) × (浓度 - 浓度低) ÷ (浓度高 - 浓度低) + IAQI低
iaqi = (iaqi_hi - iaqi_lo) * (cp - bp_lo) / (bp_hi - bp_lo) + iaqi_lo
return iaqi
# 测试一下:PM2.5浓度55,应该在35-75映射到50-100
test_result = cal_linear(50, 100, 35, 75, 55)
print(f'PM2.5浓度55对应的分指数是:{test_result}')PM2.5浓度55对应的分指数是:75.0PM2.5浓度55对应的分指数是:75.0看,我们得到了和手工计算一样的结果!这个函数现在可以复用了,任何需要线性缩放的场景都能用它。
生活化类比:这就像把考试成绩从「百分制」换算到「150分制」。如果100分制的80分相当于150分制的120分,那么85分应该换算到多少?用我们的cal_linear函数就能轻松算出来!
完善污染物计算函数
有了线性缩放函数,现在我们可以完善PM2.5和一氧化碳的计算函数了。
根据国家标准,PM2.5的分级标准是:
- 0-35 µg/m³ → AQI 0-50
- 35-75 µg/m³ → AQI 50-100
- 75-115 µg/m³ → AQI 100-150
- …(实际还有更多级,我们先实现前三级)
一氧化碳(CO)的标准是:
- 0-3 mg/m³ → AQI 0-50
- 3-5 mg/m³ → AQI 50-100
- …(同样先实现前两级)
# 完整的AQI计算器 v1.0
def cal_linear(iaqi_lo, iaqi_hi, bp_lo, bp_hi, cp):
"""线性缩放函数"""
iaqi = (iaqi_hi - iaqi_lo) * (cp - bp_lo) / (bp_hi - bp_lo) + iaqi_lo
return iaqi
def cal_pm_iaqi(pm_val):
"""计算PM2.5的分指数"""
if 0 <= pm_val < 36: # 注意:35是闭区间,36是开区间
# 0-35 映射到 0-50
iaqi = cal_linear(0, 50, 0, 35, pm_val)
elif 36 <= pm_val < 76:
# 35-75 映射到 50-100
iaqi = cal_linear(50, 100, 35, 75, pm_val)
elif 76 <= pm_val < 116:
# 75-115 映射到 100-150
iaqi = cal_linear(100, 150, 75, 115, pm_val)
else:
# 超过115的情况暂时不处理
print(f'PM2.5浓度{pm_val}超出当前处理范围')
iaqi = 0
return iaqi
def cal_co_iaqi(co_val):
"""计算一氧化碳的分指数"""
if 0 <= co_val < 3:
# 0-3 映射到 0-50
iaqi = cal_linear(0, 50, 0, 3, co_val)
elif 3 <= co_val < 5:
# 3-5 映射到 50-100
iaqi = cal_linear(50, 100, 2, 4, co_val) # 注意:标准是2-4,不是3-5
else:
# 超过5的情况暂时不处理
print(f'一氧化碳浓度{co_val}超出当前处理范围')
iaqi = 0
return iaqi
def cal_aqi(param_list):
"""计算最终的AQI"""
pm_val = param_list[0]
co_val = param_list[1]
pm_iaqi = cal_pm_iaqi(pm_val)
co_iaqi = cal_co_iaqi(co_val)
print(f'PM2.5分指数:{pm_iaqi:.1f}')
print(f'一氧化碳分指数:{co_iaqi:.1f}')
iaqi_list = []
iaqi_list.append(pm_iaqi)
iaqi_list.append(co_iaqi)
aqi = max(iaqi_list)
return aqi
# 主程序
print('=== AQI计算器 v1.0 ===')
print('请输入以下信息,用空格分割')
# 测试数据1:PM2.5=55, 一氧化碳=2
input_str = '55 2'
print(f'(1)PM2.5 (2)CO: {input_str}')
str_list = input_str.split(' ')
pm_val = float(str_list[0])
co_val = float(str_list[1])
param_list = [pm_val, co_val] # 更简洁的列表创建方式
aqi_val = cal_aqi(param_list)
print('=' * 30)
print('空气质量指数为:{:.1f}'.format(aqi_val))
# 再测试一组数据
print('\n' + '=' * 30)
print('测试另一组数据:PM2.5=120, 一氧化碳=1')
test_aqi = cal_aqi([120, 1])
print('空气质量指数为:{:.1f}'.format(test_aqi))=== AQI计算器 v1.0 ===
请输入以下信息,用空格分割
(1)PM2.5 (2)CO: 55 2
PM2.5分指数:75.0
一氧化碳分指数:33.3
==============================
空气质量指数为:75.0
==============================
测试另一组数据:PM2.5=120, 一氧化碳=1
PM2.5浓度120超出当前处理范围
PM2.5分指数:0.0
一氧化碳分指数:16.7
空气质量指数为:16.7=== AQI计算器 v1.0 ===
请输入以下信息,用空格分割
(1)PM2.5 (2)CO: 55 2
PM2.5分指数:75.0
一氧化碳分指数:33.3
==============================
空气质量指数为:75.0
==============================
测试另一组数据:PM2.5=120, 一氧化碳=1
PM2.5浓度120.0超出当前处理范围
PM2.5分指数:0.0
一氧化碳分指数:16.7
空气质量指数为:16.7程序解读:
- 第一组数据(PM2.5=55, CO=2):PM2.5分指数75,CO分指数33.3,取最大值75
- 第二组数据(PM2.5=120):因为120超出了我们目前处理的范围(0-115),所以返回0,最终AQI由CO的16.7决定
注意:实际应用中需要处理所有浓度范围,我们这里为了简化只实现了前几级。你可以看到,当数据超出范围时,程序会给出提示。
函数设计的思想:分层与复用
回顾一下我们的程序结构:
cal_aqi() ← 顶层函数:协调整个计算流程
├── cal_pm_iaqi() ← 中层函数:处理PM2.5的具体计算
│ └── cal_linear() ← 底层函数:通用的线性缩放
└── cal_co_iaqi() ← 中层函数:处理一氧化碳的具体计算
└── cal_linear() ← 复用同一个底层函数这种「分层设计」的思想在编程中非常重要:
- 底层函数(如
cal_linear)做最通用、最基础的工作 - 中层函数(如
cal_pm_iaqi)处理特定领域的逻辑 - 顶层函数(如
cal_aqi)负责协调和整合
好处是什么?
- 易于维护:如果要修改线性缩放的算法,只需要改
cal_linear一个地方 - 易于扩展:要增加新的污染物(如二氧化硫),只需要写一个新的
cal_so2_iaqi函数,然后在cal_aqi里调用它 - 代码复用:
cal_linear可以被所有污染物计算函数共用
真实工作中的应用:在软件开发中,这种分层思想无处不在。比如一个电商网站,底层有「计算运费」的函数,中层有「处理订单」的函数,顶层有「完成购物车结算」的函数。
📝 动手练一练
理解线性缩放
如果考试成绩从「百分制」换算到「150分制」,且已知100分制的80分对应150分制的120分。请用cal_linear函数计算:100分制的92分应该换算到150分制的多少分?扩展污染物类型
我们的程序目前只处理PM2.5和一氧化碳。请尝试添加对PM10的支持。PM10的标准是:- 0-50 µg/m³ → AQI 0-50
- 50-150 µg/m³ → AQI 50-100
你需要:
- 编写
cal_pm10_iaqi(pm10_val)函数 - 修改
cal_aqi函数,让它能接收三个值(PM2.5, CO, PM10) - 在最终计算时考虑PM10的分指数
优化用户输入
现在的程序要求用户用空格分割两个数字,如果用户输错了(比如多输了一个空格,或者输入了非数字字符),程序会崩溃。你能想到什么办法让程序更健壮吗?
👉 点击查看第1题参考答案
def cal_linear(iaqi_lo, iaqi_hi, bp_lo, bp_hi, cp):
"""线性缩放函数"""
iaqi = (iaqi_hi - iaqi_lo) * (cp - bp_lo) / (bp_hi - bp_lo) + iaqi_lo
return iaqi
# 百分制80分对应150分制120分
# 所以原始范围是[0, 100],目标范围是[0, 150]
# 注意:80分是已知对应点,但不是范围边界
# 我们需要用两个点来确定线性关系
# 方法:用0分和80分这两个已知对应点
# 0分 → 0分,80分 → 120分
# 所以当cp=92时:
result = cal_linear(0, 120, 0, 80, 92)
print(f'100分制的92分对应150分制的:{result:.1f}分')
# 验证:比例是120/80=1.5,92×1.5=138,结果一致100分制的92分对应150分制的:138.0分100分制的92分对应150分制的:138.0分思路:线性缩放需要知道两个范围。已知「80分→120分」和「0分→0分」,所以原始范围是[0, 80],目标范围是[0, 120]。用这个比例计算92分的对应值。
👉 点击查看第2题参考答案
def cal_linear(iaqi_lo, iaqi_hi, bp_lo, bp_hi, cp):
"""线性缩放函数"""
iaqi = (iaqi_hi - iaqi_lo) * (cp - bp_lo) / (bp_hi - bp_lo) + iaqi_lo
return iaqi
def cal_pm10_iaqi(pm10_val):
"""计算PM10的分指数"""
if 0 <= pm10_val < 51: # 0-50
iaqi = cal_linear(0, 50, 0, 50, pm10_val)
elif 51 <= pm10_val < 151: # 50-150
iaqi = cal_linear(50, 100, 50, 150, pm10_val)
else:
print(f'PM10浓度{pm10_val}超出当前处理范围')
iaqi = 0
return iaqi
# 测试
pm10_test = 85 # PM10浓度85
pm10_iaqi = cal_pm10_iaqi(pm10_test)
print(f'PM10浓度{pm10_test}对应的分指数是:{pm10_iaqi:.1f}')
# 如果要集成到主程序,需要:
# 1. 修改cal_aqi函数,接收三个参数
# 2. 在iaqi_list中添加pm10_iaqi
# 3. 修改用户输入提示和参数列表PM10浓度85对应的分指数是:67.5PM10浓度85对应的分指数是:67.5关键点:PM10浓度85落在50-150范围,按比例缩放到50-100,计算结果是67.5。
👉 点击查看第3题思路提示
思路方向(不写完整代码,只给思路):
- 处理多余空格:可以用
strip()去掉字符串两端的空格 - 处理多个空格:可以用
split()不指定分隔符,它会自动处理连续的空格 - 检查输入数量:判断分割后的列表长度是否符合预期
- 处理非数字输入:用
try...except捕获转换错误
示例代码片段:
input_str = '55 2 ' # 有多余空格
str_list = input_str.strip().split() # 不指定分隔符,自动处理连续空格
if len(str_list) != 2:
print('请输入两个数值,用空格分割')
else:
try:
pm_val = float(str_list[0])
co_val = float(str_list[1])
# 继续处理...
except ValueError:
print('请输入有效的数字')进阶思考:如果用户输入「55,2」用逗号分割怎么办?如果输入「五十五 二」中文数字怎么办?在实际项目中,用户输入验证是一个重要课题。
本章小结
恭喜!你已经完成了AQI计算器的第一个版本。虽然它目前只处理两种污染物,但核心的计算逻辑已经完整了。
今天你学到了:
- ✅ AQI的计算原理:由多种污染物的分指数取最大值得到
- ✅ 线性缩放:把数值从一个范围按比例转换到另一个范围
- ✅ 函数分层设计:底层通用函数 + 中层专用函数 + 顶层协调函数
- ✅ 列表与最大值:用
max()函数找出列表中的最大值
📋 行动清单
学完立刻可以做的:
- 运行今天的完整代码,尝试不同的PM2.5和CO浓度值
- 修改程序,添加对二氧化硫(SO₂)的支持(标准:0-150 µg/m³ → AQI 0-50)
- 思考:如果要处理全国所有城市的AQI数据,程序结构可以怎么优化?
在接下来的几节中,我们将:
- 从文件读取真实的污染物数据(JSON格式)
- 把计算结果保存到文件
- 从网络获取实时的空气质量数据
- 用更强大的工具(pandas)分析全国城市的AQI排名
你会发现,今天搭建的这个「计算引擎」是整个项目的基础。就像汽车发动机一样,后面的所有功能(读取数据、保存结果、网络获取)都是在这个引擎上添加的「配件」。
准备好了吗?下一节,我们将学习如何处理JSON数据文件,让程序能读取预先准备好的污染物数据!
—— 小象教研组
配套资料 · 直接下载
课件、代码、数据集等配套资料全部免费,点击即可直接下载,无需分享或解锁。