第二章 环境数据采集与预处理实战
大家好,我是你们的老朋友。今天咱们聊聊环境数据采集与预处理。说实话,这步看着基础,但我在项目里见过太多人在这上面栽跟头。数据没处理好,后面模型再漂亮也是白搭。
2.1 数据来源:API、传感器、公开数据集
环境数据从哪来?我总结下来就三条路。
2.1.1 API接口获取
现在很多环境监测平台都开放了API。比如中国环境监测总站、AQICN这些。我个人习惯用requests库直接拉数据,简单粗暴。
import requests
import pandas as pd
# 以某空气质量API为例
url = "https://api.airquality.cn/v1/station/beijing"
params = {
"token": "your_token_here",
"start": "2024-01-01",
"end": "2024-01-31"
}
response = requests.get(url, params=params)
data = response.json()
df = pd.DataFrame(data['records'])
print(df.head())
try-except包一下,再加个重试机制。
2.1.2 传感器数据采集
如果你手头有硬件设备,比如树莓派接个温湿度传感器,那数据就是实时流进来的。我建议用pyserial或者Adafruit_DHT库读取。
import Adafruit_DHT
import time
sensor = Adafruit_DHT.DHT22
pin = 4
while True:
humidity, temperature = Adafruit_DHT.read_retry(sensor, pin)
if humidity is not None and temperature is not None:
print(f"温度: {temperature:.1f}°C, 湿度: {humidity:.1f}%")
else:
print("读取失败,检查传感器连接")
time.sleep(60) # 每分钟采集一次
2.1.3 公开数据集
不想自己采集?直接用公开数据集。我常用的有:
- UCI Machine Learning Repository:空气质量数据集
- Kaggle:全球气候变化数据
- 中国气象数据网:地面气象观测数据
这些数据集通常已经做过初步清洗,但别太相信。我下载过一个号称"干净"的数据集,结果里面还有-9999这种缺失标记。
2.2 缺失值处理:均值填充与中位数填充
数据拿到手,第一件事就是检查缺失值。用df.isnull().sum()一看,心里就有数了。
2.2.1 均值填充
均值填充是最简单的方法。适合数据分布比较对称的情况。
# 均值填充
df['PM2.5'].fillna(df['PM2.5'].mean(), inplace=True)
但这里有个坑。如果数据有异常值,均值会被拉偏。我遇到过PM2.5数据里有个1000的异常值,均值直接飙到200,填充进去全乱了。
2.2.2 中位数填充
中位数对异常值不敏感,更适合有离群点的数据。
# 中位数填充
df['PM2.5'].fillna(df['PM2.5'].median(), inplace=True)
2.2.3 分组填充
有时候全局填充太粗糙。比如不同季节的PM2.5差异很大,按季节分组填充更合理。
# 按季节分组填充
df['season'] = pd.cut(df['month'], bins=[0,3,6,9,12], labels=['冬','春','夏','秋'])
df['PM2.5'] = df.groupby('season')['PM2.5'].transform(lambda x: x.fillna(x.median()))
嗯,这样处理完,数据质量明显上了一个台阶。
2.3 异常值检测:3σ原则与IQR方法
异常值检测是预处理的重头戏。我常用的就两招。
2.3.1 3σ原则
3σ原则假设数据服从正态分布。超出均值±3倍标准差的值,视为异常。
import numpy as np
def detect_outliers_3sigma(data):
mean = np.mean(data)
std = np.std(data)
lower = mean - 3 * std
upper = mean + 3 * std
outliers = (data < lower) | (data > upper)
return outliers
# 应用
df['PM2.5_outlier'] = detect_outliers_3sigma(df['PM2.5'])
print(f"检测到 {df['PM2.5_outlier'].sum()} 个异常值")
2.3.2 IQR方法
IQR方法不依赖正态分布假设。它用四分位距来界定异常。
def detect_outliers_iqr(data):
Q1 = data.quantile(0.25)
Q3 = data.quantile(0.75)
IQR = Q3 - Q1
lower = Q1 - 1.5 * IQR
upper = Q3 + 1.5 * IQR
outliers = (data < lower) | (data > upper)
return outliers
# 应用
df['PM2.5_outlier_iqr'] = detect_outliers_iqr(df['PM2.5'])
print(f"IQR方法检测到 {df['PM2.5_outlier_iqr'].sum()} 个异常值")
你看,IQR方法更稳健。我一般两个方法都跑一遍,对比结果再决定。
2.3.3 异常值处理策略
检测到异常值后怎么处理?我通常有三种选择:
| 策略 | 适用场景 | 代码示例 |
|---|---|---|
| 删除 | 异常值极少,且明显是测量错误 | df = df[~outliers] |
| 替换为边界值 | 异常值可能是真实极端情况 | df.loc[outliers, 'col'] = upper |
| 视为缺失值 | 不确定是否异常,先标记再处理 | df.loc[outliers, 'col'] = np.nan |
2.4 本章知识体系
下面这张图帮你理清整个数据预处理的流程。我画了好几次才满意,你看看。
说白了,数据预处理就是给模型喂好料。你想想看,垃圾进垃圾出,这个道理在机器学习里比什么都重要。我见过太多人花90%的时间调模型参数,却只花10%的时间处理数据,结果模型上线就崩。
好了,这一章的内容就到这。数据预处理这块,多动手练练,慢慢就有感觉了。
公众号:蓝海资料掘金营,微信deep3321