news 2026/11/2 4:34:29

气象数据分析实战:从数据清洗到可解释结论的完整路径

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
气象数据分析实战:从数据清洗到可解释结论的完整路径

简介:这份资源面向数据分析初学者与需要完成课程实验的学生,围绕气象数据展开完整实践:通过爬虫代码抓取中国天气网某一城市的天气数据,再对数据做清洗与统计分析,并生成雷达图、条形图等多种可视化图表,配合文字说明形成一份可复用的实验范例。压缩包共39个文件,以20个png图表截图、15个xml与4个rels文档结构文件为主,整体约1.69MB,其中png直观呈现各类分析结果,xml与rels则对应整理后的实验报告文档结构,便于直接查阅与二次编辑。资源已有1854人学习下载,包含全部源文件、源代码与整理过后的实验报告,代码可在jupyter notebook中直接运行,读者既能复现爬取与分析流程,也能借鉴图表选型与结论撰写思路,适合作为数据分析入门练习或课程作业参考。

1. 气象分析不是画几张曲线:从一份逐时观测表说起

手头拿到一份气象逐时观测表,字段无非是时间、气温、气压、湿度、风速风向、降水量。很多人第一反应是画几条折线,看看趋势,写两句“气温先升后降”。但真正做过气象数据分析的人都知道,麻烦从来不在画图,而在数据本身:缺测、跳变、单位不统一、时间戳错位、风向用度数还是十六方位、降水是累计还是瞬时。这些问题不处理,后面所有结论都是空中楼阁。这一篇讲的就是把一份原始气象观测数据,从清洗、质控、特征构造一路做到可解释的分析结论,适合刚接手气象数据、又不想只停留在画图层面的从业者。核心词气象分析会贯穿始终,数据分析的落地路径也会一步步拆开。

2. 气象数据先过质控这一关:字段、单位与时间轴怎么对齐

气象分析的第一步不是建模,而是让数据“可信”。一份逐时观测表看起来规整,实际打开经常是另一回事:气温列里混着字符串“—”、气压单位有的是 hPa 有的是 Pa、时间列有的是本地时有的带时区偏移、风向用 0–360 度但 0 和 360 都表示北。这些不统一,后面算露点、算体感温度、算风玫瑰全部会翻车。

我一般会先做三件事:统一时间轴到 UTC 或明确的本地时区并排序去重;统一单位到一套标准(气温摄氏度、气压 hPa、风速 m/s、降水 mm);把缺测标记成 NaN 而不是 0 或空字符串。顺序不能乱,先时间后单位再缺测,否则去重和插值都会出错。

2.1 用 pandas 把逐时观测表读成可分析的结构

下面这段是最小可复现的读取与规范化骨架,字段名按常见观测表命名,实际替换成你自己的列名即可。

import pandas as pd import numpy as np # 读取原始观测表,缺失值统一识别 df = pd.read_csv( "obs_hourly.csv", na_values=["", "—", "NA", "999999", "9999"], # 常见缺测占位符 parse_dates=["datetime"], # 时间列直接解析 ) # 1) 时间轴:排序 + 去重 + 设为索引 df = df.sort_values("datetime").drop_duplicates(subset="datetime") df = df.set_index("datetime") # 2) 单位统一:气压若为 Pa 则换算成 hPa if df["pressure"].median() > 2000: # 经验阈值,Pa 量级远大于 hPa df["pressure"] = df["pressure"] / 100.0 # 3) 数值列强制转 float,非法值变 NaN num_cols = ["temp", "pressure", "rh", "wind_speed", "precip"] df[num_cols] = df[num_cols].apply(pd.to_numeric, errors="coerce") print(df[num_cols].isna().mean().round(3)) # 先看各列缺测比例

这段代码的逻辑说明:na_values把观测系统常见的缺测占位符一次性识别掉,避免它们被当成真实数值参与统计;parse_dates让时间列变成真正的 datetime 类型,后续重采样才有意义;气压换算用中位数判断量级,比逐行判断稳,因为个别异常值不会带偏整体判断;errors="coerce"把无法解析的字符串转成 NaN,保证列是数值类型。参数上,na_values要按你数据源的实际占位符补全,pressure的 2000 阈值只是经验值,拿到数据先打印describe()看一眼量级再定。

2.2 缺测、跳变与物理界限:三条质控规则

单位对齐之后,质控才是重头戏。气象数据有三类典型问题:缺测(NaN)、跳变(相邻小时气温差 20 度)、越界(湿度 120%、风速为负)。我一般用物理界限加变化率双重规则,规则要写死成可复用的函数,而不是每次手改。

def quality_control(df): rules = { "temp": (-60, 60), # 摄氏度物理界限 "pressure": (800, 1100), # hPa 海平面附近合理范围 "rh": (0, 100), # 相对湿度 "wind_speed":(0, 75), # m/s,超过多为仪器异常 "precip": (0, 200), # 逐时降水 mm } for col, (lo, hi) in rules.items(): df.loc[(df[col] < lo) | (df[col] > hi), col] = np.nan # 变化率规则:逐时气温跳变超过 15 度视为可疑 jump = df["temp"].diff().abs() > 15 df.loc[jump, "temp"] = np.nan return df df = quality_control(df)

逻辑说明:先按物理界限把越界值置 NaN,再用diff()抓相邻时刻的异常跳变。这里把跳变值也置 NaN 而不是直接删行,是为了保留时间连续性,后面插值或标记都能用。参数上,气温 15 度的跳变阈值偏宽松,如果你做的是分钟级数据要相应调小;降水上限 200 mm/h 是极端情况下的宽松上限,常规站点可以收紧到 50。质控之后一定要统计每列被置 NaN 的比例,超过 20% 的列要回头查数据源,而不是硬插值。

提示:质控规则不要一次写太严,先把被标记的点导出来和原始记录对照,确认规则没有误杀真实极端天气,再固化下来。

3. 从原始观测到分析特征:派生量、重采样与风玫瑰

质控过关后,原始字段往往不够用。气象分析里真正有解释力的,很多是派生量:露点温度、体感温度、风向的十六方位、日较差、滑动平均。这一步的目标是把“观测值”变成“分析特征”,让后面的趋势判断和异常识别有抓手。

3.1 派生量计算:露点、体感温度与风向离散化

露点用 Magnus 公式近似即可,体感温度用简化热指数,风向从度数转十六方位。这些公式不复杂,但参数和单位要对齐,否则算出来的露点比气温还高就闹笑话了。

import numpy as np def dew_point(temp, rh): # Magnus 近似,temp 摄氏度,rh 百分比 a, b = 17.27, 237.7 gamma = (a * temp) / (b + temp) + np.log(np.clip(rh, 1, 100) / 100.0) return (b * gamma) / (a - gamma) def wind_direction_16(deg): dirs = ["N","NNE","NE","ENE","E","ESE","SE","SSE", "S","SSW","SW","WSW","W","WNW","NW","NNW"] idx = int((deg % 360) / 22.5 + 0.5) % 16 return dirs[idx] df["dew_point"] = dew_point(df["temp"], df["rh"]) df["wind_dir_16"] = df["wind_dir"].apply( lambda d: wind_direction_16(d) if pd.notna(d) else np.nan )

逻辑说明:dew_point里对rh做了clip(1,100),防止湿度为 0 时取对数出错;wind_direction_16用(deg % 360) / 22.5 + 0.5取整再模 16,保证 348.75–360 度落到 N 而不是越界。参数上,Magnus 公式的 a、b 是常用近似常数,精度对分析足够;如果你要做精细的农业气象,可以换更精确的 Goff-Gratch 公式,但计算量会上去。

3.2 重采样与滑动统计:日值、日较差和 24 小时滑动平均

逐时数据直接看趋势噪声很大,重采样到日值、再算日较差和滑动平均,趋势才看得清。重采样时聚合函数要按字段选:气温用 mean,降水用 sum,风向不能平均(要用矢量平均或众数)。

# 日值聚合:气温均值、降水累计、气压均值 daily = df.resample("1D").agg({ "temp": "mean", "precip": "sum", "pressure": "mean", "wind_speed": "mean", }) # 日较差 daily["temp_range"] = df["temp"].resample("1D").max() - df["temp"].resample("1D").min() # 24 小时滑动平均,用于平滑短期波动 df["temp_ma24"] = df["temp"].rolling(window=24, min_periods=18).mean()

逻辑说明:resample("1D")按自然日聚合,agg字典让不同字段走不同聚合,避免降水被平均成小数;temp_range单独用 max 减 min,因为agg里不方便直接写差值;rolling的min_periods=18允许前几小时缺测时仍能出值,但不会在数据太少时硬算。参数上,滑动窗口 24 对应逐时数据的日周期,如果你做的是分钟级数据,窗口要改成 1440;min_periods一般设成窗口的 70%–80%,太低会让滑动平均失真。

3.3 风玫瑰与主导风向:别用平均风向骗自己

风向是角度,直接求平均会得到完全错误的结果——北风 350 度和北风 10 度平均出来是 180 度,南风。正确做法是转成矢量(u、v 分量)再平均,或者直接统计十六方位频次画风玫瑰。

# 转 u/v 分量 rad = np.deg2rad(df["wind_dir"]) df["u"] = -df["wind_speed"] * np.sin(rad) df["v"] = -df["wind_speed"] * np.cos(rad) # 矢量平均得到主导风向 u_mean, v_mean = df["u"].mean(), df["v"].mean() dominant_dir = (np.rad2deg(np.arctan2(-u_mean, -v_mean)) + 360) % 360 # 十六方位频次,用于风玫瑰 freq = df["wind_dir_16"].value_counts(normalize=True).round(3)

逻辑说明:u、v 分量用-sin、-cos是气象约定(u 为东风分量,v 为北风分量),符号错了主导风向会反 180 度;arctan2再转回角度并归一化到 0–360。参数上,矢量平均适合看整体主导方向,但会掩盖双峰分布,所以频次统计要一起看。如果频次显示两个方向各占 30%,说明该站点存在明显的日夜风向转换,这时候平均风向没有意义,要分时段统计。

4. 气象分析的避坑清单:五个让结论翻车的细节

这一章是我踩过的坑里挑出来最典型的五条,每条按现象、原因、解决写,照着排查能省不少返工。

4.1 缺测被当成 0:降水统计虚高的隐形推手

现象:月降水累计比邻近站点高出一大截,逐日看又找不到明显暴雨日。原因:原始表里缺测用 0 或空字符串表示,读取时没识别成 NaN,sum()把缺测当 0 累计,看似没影响,但缺测比例高时会把“有雨日”和“无雨日”混在一起,日均值被拉低、累计被稀释,和邻近站点对比就失真。解决:读取阶段就把所有缺测占位符列进na_values,质控后打印每列 NaN 比例,降水列缺测超过 5% 的月份直接标记为不完整,不参与累计对比。

4.2 时间戳时区错位:日值聚合整体偏移一小时

现象:日最高气温总是出现在上午 11 点而不是下午 2 点,日降水峰值时间和实况对不上。原因:原始时间列是本地时,但某段数据混入了 UTC 时间,或者解析时没指定时区,resample("1D")按错误的时间边界切日。解决:读取时统一tz_localize到明确时区,跨时区数据先tz_convert到同一时区再排序;聚合前打印首尾时间和相邻时间差,确认没有 23 小时或 25 小时的“日”。

4.3 风向直接平均:主导风向反了 180 度

现象:风玫瑰显示主导风向是南风,但现场记录和邻近站点都是北风。原因:把风向度数当普通数值求平均,350 度和 10 度平均成 180 度。解决:一律转 u、v 分量再平均,或者直接统计十六方位频次;检查 u、v 公式的符号约定,u = -speed*sin(dir)、v = -speed*cos(dir)是气象常用约定,符号反了方向就反。

4.4 插值过度:把缺测插成了“真实极端值”

现象:质控后某段连续缺测被线性插值填平,结果这段数据在趋势分析里表现为“异常平稳”,掩盖了真实过程。原因:连续缺测超过几个小时还用线性插值,等于凭空造数据。解决:插值前先看缺测连续长度,连续缺测超过 3 小时的段落标记为缺失段,不插值;短缺口用线性或前向填充,并在结果里保留一个is_filled标记列,分析时能区分真实观测和填充值。

4.5 物理界限一刀切:误杀真实极端天气

现象:某次强对流过程的气温跳变被质控规则置成 NaN,导致过程分析缺了关键时段。原因:变化率阈值设得太严,把真实的快速降温当成仪器异常。解决:质控规则分两级,一级是硬物理界限(如气温 -60–60 度)直接置 NaN,二级是变化率可疑值只做标记不置 NaN,导出标记点和原始记录人工核对后再决定是否剔除;极端天气频发的站点,变化率阈值要相应放宽。

5. 让气象分析结论站得住:交叉验证与可复现的检查习惯

分析做完,最怕的是“图很好看,结论经不起问”。我一般会用三个动作给结论上保险:和邻近站点做交叉对比、用不同时间粒度复算关键指标、把整条处理链固化成可重跑的脚本。交叉对比不是找“标准答案”,而是看同一时段两个站点的趋势是否同向、量级是否合理,偏差超过预期就去查数据源而不是硬解释。不同粒度复算,比如日降水和逐时降水累计对不上,多半是重采样边界或缺测处理的问题。脚本固化则是把读取、质控、派生、聚合写成函数串起来,每次换数据只改输入路径,避免手改中间步骤引入的不一致。

下面这个检查表是我每次出结论前会过一遍的,字段和阈值按项目调整:

检查项具体动作不通过时的信号
时间轴连续性打印相邻时间差分布出现 23/25 小时或重复时间戳
缺测比例按列、按月统计 NaN 占比关键列某月缺测超 20%
单位量级打印各数值列 describe气压中位数在 100000 量级
派生量合理性露点不高于气温、湿度 0–100露点高于气温
聚合一致性日降水累计与逐时累计对比两者偏差超 1%
风向矢量主导风向与频次最高方位对比两者相差超过 45 度

一个具体技巧:把质控前后的数据各存一份,分析结论只基于质控后数据,但所有图表旁边标注被剔除和填充的点数。这样别人质疑某个峰值时,你能立刻说清它是真实观测还是插值产物。我吃过最大的亏就是早期没留这个标记,后来复盘一次异常高温,翻遍脚本也说不清那个值是实测还是插出来的,只能整段重跑。从那以后,is_filled和qc_flag两列成了我处理气象数据的固定习惯,宁可多存一列,也不给自己留说不清的账。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 4:34:26

JETSON频率管理实战:从读取到锁定,平衡性能与功耗

1. 为什么要在 JETSON 上折腾频率这件事拿到一块 JETSON 开发板&#xff0c;很多人第一反应是跑个模型看看帧率&#xff0c;或者插上摄像头看看画面。但真正把设备用到产品里、用到边缘侧长期运行的场景里&#xff0c;你迟早会碰到一个绕不开的问题&#xff1a;这块板子现在到底…

作者头像 李华
网站建设 2026/11/2 4:33:51

从证书固定到授权测试:移动应用传输安全加固与合规边界

简介&#xff1a;面向移动端安全研究与授权测试场景的支付宝小程序抓包学习素材&#xff0c;聚焦小程序 SSL 证书校验绕过与代理抓包调试问题&#xff0c;适合具备一定 Python 与前端调试基础、希望理解 Frida 注入及请求拦截流程的读者参考。压缩包共 3 个文件&#xff0c;包含…

作者头像 李华
网站建设 2026/11/2 4:33:51

Java解压RAR三大技术路线与选型避坑指南

1. 为什么"解压RAR"在Java里是个容易被低估的活儿先说结论&#xff1a;如果你在项目里接到"支持上传RAR压缩包并自动解压"这类需求&#xff0c;别急着写代码&#xff0c;先花十分钟把技术路线选对&#xff0c;否则后面返工的概率非常高。我见过不少团队在这…

作者头像 李华
网站建设 2026/11/2 4:33:50

AI应用底座是什么?QuickBlue如何让大模型落地不再难

从去年开始&#xff0c;不断有朋友问我同一个问题&#xff1a;“大模型到底该怎么接进我们现有系统&#xff1f;”刚开始我以为他们在问技术方案&#xff0c;后来发现真正卡住他们的不是某个模型接口&#xff0c;而是一整层基础设施。模型换了一家又一家&#xff0c;提示词散落…

作者头像 李华
网站建设 2026/11/2 4:33:16

OpenClaw国内安装指南:避坑与优化实践

1. OpenClaw国内安装避坑指南&#xff1a;从零到稳定运行的完整手册作为一款新兴的AI开发工具链&#xff0c;OpenClaw在国内的安装过程往往会遇到网络环境、依赖项冲突等特有难题。本文将基于笔者在三个不同企业环境中的实际部署经验&#xff0c;拆解国内用户最常遇到的7类典型…

作者头像 李华
网站建设 2026/11/2 4:32:16

Python AI入门路线:从环境搭建到调用大模型API,零基础也能跑通

Python 和 AI 这两个词&#xff0c;这两年几乎被刷屏刷烂了。但真正想上手的人&#xff0c;很多连第一步都迈不出去——下载 Python 装了半天&#xff0c;环境变量配不明白&#xff1b;好不容易跑通 hello world&#xff0c;看到 numpy、pandas、sklearn 一堆库又懵了&#xff…

作者头像 李华