第10章 天气数据分析实战
把前面九章串成一个项目:采集天气数据 → Sqoop 入库 → 清洗去重分区 → 三类分析。
本章学习目标
- 能说明案例背景、目的与整体流程
- 能完成数据采集并用 Sqoop 将 MySQL 数据导入 Hive
- 能完成缺失值处理、格式化、去重与分区
- 能写出月气温、晴天天数、霾天气三类分析 SQL
本章导览
核心内容
10.1
案例简介
数据来源为天气网站的公开数据,包含日期、城市、最高温、最低温、天气、风向、风力等字段。目标是把"脏数据"变成可分析的指标表。
项目整体流程(教材 10.1.3)
| 阶段 | 任务 | 产出 |
|---|---|---|
| 数据采集 | 分析页面结构、抓取数据、存入 MySQL | 原始数据表 |
| 数据预处理 | 缺失值处理、格式化、去重、分区 | 清洗后的明细表 |
| 数据分析 | 月气温、晴天天数、霾天气分析 | 指标结果 |
10.2
数据采集
# 1) 建 MySQL 接收表(字段与页面一致,先全用字符串接住)
CREATE TABLE nev.weather (
id INT PRIMARY KEY AUTO_INCREMENT,
city VARCHAR(20), wdate VARCHAR(20),
high VARCHAR(10), low VARCHAR(10),
weather VARCHAR(30), wind VARCHAR(30), power VARCHAR(20)
);
# 2) 采集后(脚本/Python),用 Sqoop 导入 Hive
sqoop import \
--connect jdbc:mysql://hadoop1:3306/nev --username root --password 123456 \
--table weather --hive-import --hive-database ods --hive-table weather_ods \
--fields-terminated-by '\t' -m 110.3
数据预处理
教材把预处理拆成四步:缺失值处理、数据格式化、数据去重、数据分区——这四步是离线分析项目的标准动作。
10.3.1
缺失值处理与格式化
-- 缺失值:补默认值或排除
SELECT nvl(high, '0') AS high, nvl(weather, '未知') AS weather FROM weather_ods;
-- 格式化:"3℃" → 3;"2025年07月01日" → 2025-07-01
SELECT cast(regexp_replace(high, '[^0-9-]', '') AS INT) AS high_num,
date_format(to_date(wdate, 'yyyy年MM月dd日'), 'yyyy-MM-dd') AS dt
FROM weather_ods;10.3.3
数据去重与分区
-- 去重:按城市+日期保留一条(row_number 或 distinct)
INSERT OVERWRITE TABLE dwd.weather_clean PARTITION (y, m)
SELECT city, dt, high_num, low_num, weather,
year(dt) AS y, month(dt) AS m
FROM (
SELECT *, row_number() OVER (PARTITION BY city, dt ORDER BY id DESC) rn
FROM tmp_weather_parsed
) t WHERE rn = 1;💡 先按分区字段(年月)分区,后续所有分析都能命中分区裁剪,扫描量大幅下降。
10.4
数据分析
教材给出三类分析,正好覆盖"聚合统计、条件统计、文本匹配"三种典型写法。
10.4.1
月气温分析
SELECT m, round(avg(high_num), 1) AS avg_high,
max(high_num) AS max_high, min(low_num) AS min_low
FROM dwd.weather_clean
WHERE y = '2025'
GROUP BY m ORDER BY m;10.4.2
各城市每月晴天天数统计
SELECT city, m, count(*) AS sunny_days
FROM dwd.weather_clean
WHERE y = '2025' AND weather LIKE '%晴%'
GROUP BY city, m
ORDER BY city, m;10.4.3
北京市霾天气的初步分析
SELECT m, count(*) AS haze_days,
round(count(*) * 100 / 30, 1) AS haze_rate
FROM dwd.weather_clean
WHERE city = '北京' AND y = '2025' AND (weather LIKE '%霾%' OR weather LIKE '%雾%')
GROUP BY m ORDER BY m;这类分析的关键是口径:什么算霾天(只算"霾"还是含"雾")、分母取当月天数还是有效记录数——口径不同结论会差很多,写进报告时要注明。
本章小结
本章是一次完整的小型离线分析项目:先理解背景与流程,再完成数据采集与 Sqoop 入库,接着按"缺失值处理 → 格式化 → 去重 → 分区"四步清洗进 DWD 层,最后完成月气温、晴天天数、霾天气三类分析。这套流程可以直接套用到任何日志分析场景。
思考与练习 先自己做,再点开答案
01
为什么预处理阶段要先去重再分区?
查看参考答案
分区是按年月切目录,若先去重后分区,数据量更小、目录更干净;若先分区再去重,需要在每个分区内单独去重,容易漏掉跨分区的重复(例如同一城市同一天在不同分区)。
02
数据分区对后续分析有什么好处?
查看参考答案
分区裁剪:带年/月条件的查询只扫描对应目录,扫描量可降低一到两个数量级;同时便于按天/月增量重跑与归档。
03
"霾天气分析"的口径为什么要写清楚?
查看参考答案
不同口径(是否含雾、分母是自然日还是有效记录)会得出不同占比,结论可能完全相反。数据分析报告必须注明口径,否则无法复现与对比。