数据分析实战—未来天气预测
如何预测未来的天气?这是很多人关心的话题,无论是农民期待雨水滋润庄稼,还是旅行者计划周末的户外活动,都离不开对天气的了解和预测。一场及时的雨,或许是农作物的生机;一个晴朗的周末,或许是家庭欢聚的完美时光。天气预测早已不仅仅是科学的探索,更是日常生活的一部分,是文化、经济、社交的交织。
然而,天气的变化千变万化,复杂到令人眼花缭乱。那么,我们究竟如何捕捉风的轻抚、雨的低语、云的流动?科学家们凭借气象站的观测、卫星的眼睛,以及最重要的,数据科学的力量,试图解读天气的密码,预知未来的风云。
借助18个欧洲城市的详尽气象记录,我将带您走近这一神奇的科学领域,一同探索如何用随机森林的智慧、算法的精确,去描绘明天的天空。未来的降雨,将不再是未知的迷雾,而是科学与自然的和谐乐章。
数据收集、选择和处理
最初的气象数据从ECA&D[1]检索,该项目提供了欧洲和地中海各气象站的每日观测数据。选择了18个欧洲城市或地方,其中多个每日观测数据在2000年至2010年之间可用。这些地方包括瑞士的巴塞尔、匈牙利的布达佩斯、德国的德累斯顿、杜塞尔多夫、卡塞尔、慕尼黑、荷兰的De Bilt和Maastricht、英国的希思罗、斯洛文尼亚的卢布尔雅那、瑞典的马尔默和斯德哥尔摩、法国的蒙特利马尔、佩皮尼昂和图尔、挪威的奥斯陆、意大利的罗马和奥地利的索恩布利克。
这18个地点的每日气象观测记录跨越不同的时间,其中一些回溯到19世纪。但是,在这里我们仅选择了从2000年到2010年的时间跨度,共有3654个每日观测数据。然后从这18个地点的所有数据中构建数据集。
此外,数据还包括不同的观测值。虽然所有选定的地点都提供了“平均温度”、“最高温度”和“最低温度”的数据,我们还包括了变量“云覆盖率”、“风速”、“阵风”、“湿度”、“压力”、“全球辐射”、“降水量”、“阳光时间”等的数据。
在收集数据后,对数据进行了非常基本的清理。删除了>5% 无效条目(“-9999”)的列,保留了<=5% 无效条目的列,但将无效条目替换为平均值。这导致了165个变量(或特征)在3654天的过程中。最后,我们转换了几个数据单位,以使现有值的范围更为相似。这使数据更适合用于机器学习或深度学习,甚至不需要额外的处理。我们故意不选择完全标准化数据,因为我们想保持所呈现的单位和值尽可能直观地可访问。现在,温度以摄氏度表示,风速和阵风以米/秒表示,湿度以百分比的分数表示,海平面压力以1000 hPa表示,全球辐射以100 W/m^2表示,降水量以厘米表示,阳光以小时表示。
变量的物理单位:
原始数据单位:
CC : 云覆盖八分之几 DD : 风向,以度为单位 FG : 风速,以0.1米/秒为单位 FX : 阵风,以0.1米/秒为单位 HU : 湿度,以1%为单位 PP : 海平面压力,以0.1 hPa为单位 QQ : 全球辐射,以W/m^2为单位 RR : 降水量,以0.1毫米为单位 SS : 阳光时间,以0.1小时为单位 TG : 平均温度,以0.1°C为单位 TN : 最低温度,以0.1°C为单位 TX : 最高温度,以0.1°C为单位
转换后:
CC : 云覆盖八分之几 DD : 风向,以度为单位 FG : 风速,以1米/秒为单位 FX : 阵风,以1米/秒为单位 HU : 湿度,以100%的分数表示 PP : 海平面压力,以1000 hPa为单位 QQ : 全球辐射,以100 W/m^2为单位 RR : 降水量,以10毫米为单位 SS : 阳光时间,以1小时为单位 TG : 平均温度,以1°C为单位 TN : 最低温度,以1°C为单位 TX : 最高温度,以1°C为单位
# 导入所需的库
import pandas as pd
# 加载数据集
file_path = "data/weather_prediction_dataset.csv"
weather_data = pd.read_csv(file_path)
# 显示数据集的前五行
weather_data.head()
这是数据前5行的样本:
DATE MONTH BASEL_cloud_cover BASEL_humidity BASEL_pressure \
0 2000-01-01 1 8 0.89 1.0286
1 2000-01-02 1 8 0.87 1.0318
2 2000-01-03 1 5 0.81 1.0314
3 2000-01-04 1 7 0.79 1.0262
4 2000-01-05 1 5 0.90 1.0246
BASEL_global_radiation BASEL_precipitation BASEL_sunshine \
0 0.20 0.03 0.0
1 0.25 0.00 0.0
2 0.50 0.00 3.7
3 0.63 0.35 6.9
4 0.51 0.07 3.7
BASEL_temp_mean BASEL_temp_min ... BASEL_humidity_lag_3 \
0 2.9 1.6 ... NaN
1 3.6 2.7 ... NaN
2 2.2 0.1 ... NaN
3 3.9 0.5 ... 0.89
4 6.0 3.8 ... 0.87
BASEL_pressure_lag_1 BASEL_pressure_lag_2 BASEL_pressure_lag_3 \
0 NaN NaN NaN
1 1.0286 NaN NaN
2 1.0318 1.0286 NaN
3 1.0314 1.0318 1.0286
4 1.0262 1.0314 1.0318
BASEL_cloud_cover_lag_1 BASEL_cloud_cover_lag_2 BASEL_cloud_cover_lag_3 \
0 NaN NaN NaN
1 8.0 NaN NaN
2 8.0 8.0 NaN
3 5.0 8.0 8.0
4 7.0 5.0 8.0
BASEL_precipitation_lag_1 BASEL_precipitation_lag_2 \
0 NaN NaN
1 0.03 NaN
2 0.00 0.03
3 0.00 0.00
4 0.35 0.00
BASEL_precipitation_lag_3
0 NaN
1 NaN
2 NaN
3 0.03
4 0.00
[5 rows x 180 columns]
接下来将按照以下四个部分进行分析:
数据完整性分析:检查数据中的缺失值和异常值。 季节性和趋势分析:分析温度、降水量等的季节性变化。 城市间比较:比较不同城市的气象特性。 建立预测模型:数据处理+机器学习模型预测未来一天的气温、湿度等。
数据完整性分析
首先,我们将检查数据集中的缺失值和异常值
# 检查数据集中的缺失值
missing_data_summary = weather_data.isnull().sum()
# 显示具有缺失值的列(如果有的话)
missing_columns = missing_data_summary[missing_data_summary > 0]
missing_columns
Series([], dtype: int64)
在数据集中没有发现缺失值。现在,我们将进一步检查数据中的异常值。由于数据集较大,我们将选择一些代表性的变量进行检查。
季节性和趋势分析
我们将分析巴塞尔(瑞士)的温度和降水量的季节性和趋势变化。选择巴塞尔作为示例城市,但我们可以根据需要分析其他城市。让我们首先可视化这些变量的时间序列。
import matplotlib.pyplot as plt
# 将日期列转换为日期时间格式
weather_data['DATE'] = pd.to_datetime(weather_data['DATE'], format='%Y%m%d')
# 选择巴塞尔的温度和降水量数据
basel_temp_mean = weather_data[['DATE', 'BASEL_temp_mean']]
basel_precipitation = weather_data[['DATE', 'BASEL_precipitation']]
# 绘制温度时间序列
plt.figure(figsize=(12, 6))
plt.plot(basel_temp_mean['DATE'], basel_temp_mean['BASEL_temp_mean'], label='Mean Temperature (°C)')
plt.xlabel('Date')
plt.ylabel('Temperature (°C)')
plt.title('Mean Temperature Trend in Basel (Switzerland)')
plt.legend()
plt.show()
# 绘制降水量时间序列
plt.figure(figsize=(12, 6))
plt.plot(basel_precipitation['DATE'], basel_precipitation['BASEL_precipitation'], label='Precipitation (cm)')
plt.xlabel('Date')
plt.ylabel('Precipitation (cm)')
plt.title('Precipitation Trend in Basel (Switzerland)')
plt.legend()
plt.show()
上述图表显示了巴塞尔(瑞士)的平均温度和降水量的时间序列。
平均温度趋势:可以观察到明显的季节性变化,温度在夏季上升,在冬季下降。长期趋势似乎相对稳定,没有明显的上升或下降。 降水量趋势:降水量也显示出一定的季节性变化,但不如温度明显。降水量的长期趋势也相对稳定。
城市间比较
接下来,我们将比较不同城市的气象特性。作为示例,我们可以比较2000年至2010年期间所有城市的平均温度和湿度。
首先,我们将计算每个城市的平均温度和湿度。
# 从列名中提取城市名称
cities = list(set([col.split('_')[0] for col in weather_data.columns if '_' in col]))
# 计算每个城市的平均温度和湿度
city_avg_temp_humidity = []
for city in cities:
temp_cols = [col for col in weather_data.columns if city in col and 'temp_mean' in col]
humidity_cols = [col for col in weather_data.columns if city in col and 'humidity' in col]
avg_temp = weather_data[temp_cols].mean().mean()
avg_humidity = weather_data[humidity_cols].mean().mean()
city_avg_temp_humidity.append((city, avg_temp, avg_humidity))
# 转换为 DataFrame
city_avg_temp_humidity_df = pd.DataFrame(city_avg_temp_humidity, columns=['City', 'Avg_Temperature (°C)', 'Avg_Humidity'])
city_avg_temp_humidity_df = city_avg_temp_humidity_df.sort_values(by='Avg_Temperature (°C)', ascending=False)
# 显示结果
city_avg_temp_humidity_df
下表展示了2000年至2010年期间18个欧洲城市的平均温度和湿度:
温度比较:罗马和佩皮尼昂是平均温度最高的城市,而索恩布利克的平均温度最低。 湿度比较:索恩布利克的平均湿度最高,而佩皮尼昂的平均湿度最低。
机器学习模型
我们将使用巴塞尔(Basel)的数据来预测未来一天的降雨。以下是我们的分析流程:
选择目标变量和特征我们将选择降雨作为目标变量,并选择与降雨可能相关的其他气象变量作为特征。特征可能包括温度、湿度、压力等。
创建滞后特征由于我们是基于过去的观测来预测未来的降雨,所以我们将创建滞后特征。这些特征表示过去的观测值。
数据分割我们将数据分割为训练集、验证集和测试集。
模型选择和训练我们将选择一个适合时间序列预测的模型,并使用训练集进行训练。
预测和评估我们将使用模型对未来一天的降雨进行预测,并使用测试集评估模型的性能。
首先,我们将从巴塞尔的数据中选择目标变量和特征,并创建滞后特征。
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
# 选择巴塞尔的降雨数据作为目标变量
target_variable = 'BASEL_precipitation'
features = ['BASEL_temp_mean', 'BASEL_humidity', 'BASEL_pressure', 'BASEL_cloud_cover']
# 创建滞后特征
lag_days = 3
for feature in features + [target_variable]:
for lag in range(1, lag_days + 1):
weather_data[f'{feature}_lag_{lag}'] = weather_data[feature].shift(lag)
# 选择特征和目标变量
selected_features = [f'{feature}_lag_{lag}' for feature in features for lag in range(1, lag_days + 1)]
selected_features += features
X = weather_data[selected_features][lag_days:]
y = weather_data[target_variable][lag_days:]
# 标准化特征
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
# 分割数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, shuffle=False)
# 显示选定的特征和目标变量的前几行
X_train[:5], y_train[:5]
我们已经选择了与降雨相关的特征,并创建了过去3天的滞后特征。特征包括巴塞尔的平均温度、湿度、压力和云覆盖率。接下来,我们将选择一个合适的预测模型并进行训练。
由于我们正在处理一个回归问题(预测连续的降雨量),我们可以考虑使用诸如线性回归、随机森林回归或梯度增强回归等回归模型。这里我们使用随机森林回归模型来预测巴塞尔(Basel)未来一天的降雨量。
首先,我们将训练随机森林回归模型,并在训练集上评估其性能。然后,我们将使用模型在测试集上进行预测,并评估其性能。
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_absolute_error, mean_squared_error
import numpy as np
# 创建随机森林回归模型
rf_regressor = RandomForestRegressor(n_estimators=100, random_state=42)
# 训练模型
rf_regressor.fit(X_train, y_train)
# 在训练集上进行预测
y_train_pred = rf_regressor.predict(X_train)
# 计算训练集的性能指标
train_mae = mean_absolute_error(y_train, y_train_pred)
train_rmse = np.sqrt(mean_squared_error(y_train, y_train_pred))
# 在测试集上进行预测
y_test_pred = rf_regressor.predict(X_test)
# 计算测试集的性能指标
test_mae = mean_absolute_error(y_test, y_test_pred)
test_rmse = np.sqrt(mean_squared_error(y_test, y_test_pred))
train_mae, train_rmse, test_mae, test_rmse
随机森林回归模型的训练和测试性能如下:
训练集:
平均绝对误差 (MAE):0.0865 cm 均方根误差 (RMSE):0.1651 cm 测试集: 平均绝对误差 (MAE):0.2450 cm 均方根误差 (RMSE):0.4743 cm
这些指标量化了模型预测与实际观测之间的误差。训练集上的误差较小,而测试集上的误差较大,这可能表明模型在训练数据上过拟合。我们可以通过调整模型参数、选择不同的特征或使用正则化技术来进一步改进模型。
接下来,我们可以可视化测试集上的预测结果与实际降雨量的比较。这将帮助我们直观地了解模型的性能。
# 可视化测试集上的预测结果与实际降雨量的比较
plt.figure(figsize=(12, 6))
plt.plot(weather_data['DATE'][lag_days:].iloc[-len(y_test):], y_test, label='Actual Precipitation (cm)')
plt.plot(weather_data['DATE'][lag_days:].iloc[-len(y_test):], y_test_pred, label='Predicted Precipitation (cm)', linestyle='--')
plt.xlabel('Date')
plt.ylabel('Precipitation (cm)')
plt.title('Predicted vs Actual Precipitation in Basel (Switzerland)')
plt.legend()
plt.show()
上图展示了巴塞尔(Basel)的实际降雨量与随机森林回归模型预测的降雨量之间的比较。实线表示实际降雨量,虚线表示预测的降雨量。
从图中可以看出,虽然模型捕捉到了一些降雨的趋势和模式,但在某些情况下也存在一些偏差。
总结
我们选择了巴塞尔的降雨量作为预测目标,并使用了与降雨量可能相关的气象变量作为特征。 我们使用随机森林回归模型进行了预测,并在测试集上评估了其性能。 模型的预测与实际降雨量之间存在一些差异,可能需要进一步的特征工程和模型调优。
参考文献:
[1] Klein Tank, A.M.G. and Coauthors, 2002. Daily dataset of 20th-century surface
air temperature and precipitation series for the European Climate Assessment.
Int. J. of Climatol., 22, 1441-1453.
[2] https://www.kaggle.com/datasets/thedevastator/weather-prediction