数据与模型优化随机森林回归进行天气预测
随着天气预报对日常生活和各行各业的影响不断加深,如何提高天气预测的准确性已成为气象领域的重要课题。机器学习,尤其是随机森林回归模型,因其强大的预测能力和较高的鲁棒性,成为了天气预测中的常用工具。
本文将以一个基于随机森林回归的天气预测案例为例,详细分析数据的预处理、特征选择、模型训练、评估及优化过程,探讨如何利用不同的特征配置和参数调整提高预测的精度和效率。
文章目录
- 案例概述
- 数据详解
- 案例分析
- 随机森林
- 数据与特征对随机森林的影响
- 随机森林参数选择
- 总结
案例概述
本案例数据地址 Temperature Prediction_Random Forest气温预测_随机森林。
本案例探讨了使用随机森林回归模型来进行天气数据的预测。数据首先经过了预处理,包括One-Hot编码等方法,将不同的气象变量转化为适合模型训练的形式。在特征选择过程中,案例通过添加多个特征(如风速、降水、雪深等)来增强模型的预测能力。
模块名称 | 内容简介 | 所需技能 | 数据类型 | 应用场景 |
---|---|---|---|---|
案例概述 | 本案例使用随机森林回归模型对天气数据进行预测,并探索了不同特征和模型参数对预测结果的影响。 | 数据预处理,随机森林回归模型 | 结构化数据 | 天气预测,模型优化 |
案例目标 | 通过使用不同的特征与模型参数配置,探索其对随机森林预测效果的影响,优化模型表现。 | 随机森林回归,特征选择与调优 | 数值型数据 | 预测模型优化,特征分析 |
评价指标 | 使用平均绝对误差(MAE)、准确率等指标来评估模型性能。 | 模型评估,误差分析 | 数值型数据 | 模型性能评估,误差计算 |
业务意义 | 优化预测模型能够提高预测精度,并根据不同的特征和参数配置提升天气预测的准确度。 | 数据驱动决策,模型优化与提升 | 分类数据 | 气象预测,业务决策支持 |
通过对模型参数(如树的数量、树的最大深度等)进行调优,探索了最优配置对模型性能的影响。通过与基准模型(仅使用原始特征)对比,验证了使用扩展数据特征的有效性。本案例通过GridSearch和RandomizedSearch进行参数搜索,找到了更优的模型配置,最终通过准确率和误差分析得到了更精确的预测结果。这些分析不仅能够帮助优化天气预测模型,还为其他领域的回归任务提供了重要的参考。
数据详解
这段数据展示了多个变量的统计描述,包括年份、月份、日期、星期、温度(包括temp_1
、temp_2
)、平均温度(average
)、实际温度(actual
)以及朋友相关的数据。每个字段都显示了有效、缺失和不匹配数据的统计信息。数据的统计描述包括各字段的均值、标准差以及分位数,提供了关于数据分布和集中趋势的有用信息。例如,年份数据表现出所有记录都属于2016年,月份数据的平均值为6.48,分布较为分散,而温度数据(temp_1
和 temp_2
)的均值和标准差接近,反映出数据的一致性。
字段名称 | 类型/范围 | 描述信息 |
---|---|---|
year | 2016 | 该字段所有数据都为2016年,共348条记录,缺失和不匹配数据为0,均值为2016年。 |
month | 1 - 12 | 月份数据的分布较为均匀,均值为6.48,标准差为3.49,最小值为1,最大值为12。 |
day | 1 - 31 | 日期数据的均值为15.5,标准差为8.76,数据从1日到31日不等,分布相对均匀。 |
week | 星期二至星期五 | 该字段记录了星期几的数据,星期二占15%,星期五占14%,其余日期占比最大。 |
temp_2 | 35 - 117 | 温度(temp_2)的均值为62.7,标准差为12.1,数据范围从35到117,分布较为集中在54到92之间。 |
temp_1 | 35 - 117 | 与temp_2 类似,temp_1 字段的均值为62.7,标准差为12.1,数据范围与temp_2 一致。 |
average | 45.1 - 77.4 | 平均温度的均值为59.8,标准差为10.5,数据分布较为广泛,最小值为45.1,最大值为77.4。 |
actual | 35 - 92 | 实际温度数据的均值为62.5,标准差为11.8,数据范围从35到92,分布较为均匀。 |
friend | 28 - 95 | 朋友相关的温度数据,均值为60,标准差为15.6,最小值为28,最大值为95。 |
通过这些字段的统计分析,可以更好地理解数据集的特征和分布情况。这些描述性统计数据为进一步的数据探索和建模提供了基础。
案例分析
随机森林
在这个任务中目标是利用历史气温数据进行最高温度预测。任务包括数据的加载、处理、训练机器学习模型、模型评估以及最终结果的可视化。以下是代码的整体分析和逐步解读。
数据加载与预览
import pandas as pd
features = pd.read_csv('data/temps.csv')
features.head(5)
首先,代码通过Pandas加载CSV文件 'data/temps.csv'
,将其存储在 features
变量中。通过 .head(5)
方法查看前五行数据,以快速检查数据结构及是否符合预期。
数据维度
print('The shape of our features is:', features.shape)
此代码段输出数据的维度,即数据集的行数和列数。了解数据的大小有助于评估后续的处理和建模任务的复杂度。
数据统计描述
features.describe()
通过 describe()
方法,快速获取数据集的统计概况,包括均值、标准差、最小值、最大值等。此操作有助于初步检查数据的分布情况。
日期处理
import datetimeyears = features['year']
months = features['month']
days = features['day']dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]
这段代码的目的是将数据中的年月日转换为日期格式。zip()
函数将 year
, month
, day
三列打包在一起,然后通过 datetime.strptime()
转换为 datetime
类型,便于后续操作和可视化。
数据可视化
import matplotlib.pyplot as pltget_ipython().run_line_magic('matplotlib', 'inline')plt.style.use('fivethirtyeight')fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize = (10,10))
fig.autofmt_xdate(rotation = 45)ax1.plot(dates, features['actual'])
ax1.set_xlabel(''); ax1.set_ylabel('Temperature'); ax1.set_title('Max Temp')ax2.plot(dates, features['temp_1'])
ax2.set_xlabel(''); ax2.set_ylabel('Temperature'); ax2.set_title('Previous Max Temp')ax3.plot(dates, features['temp_2'])
ax3.set_xlabel('Date'); ax3.set_ylabel('Temperature'); ax3.set_title('Two Days Prior Max Temp')ax4.plot(dates, features['friend'])
ax4.set_xlabel('Date'); ax4.set_ylabel('Temperature'); ax4.set_title('Friend Estimate')plt.tight_layout(pad=2)
此部分代码使用 matplotlib
进行数据的可视化展示。通过 subplots()
创建了一个 2x2 的网格,分别绘制了四个图表:实际温度、前一天的温度、两天前的温度和朋友估算的温度。每个子图都添加了标题和轴标签,以便清晰地显示不同温度数据的变化趋势。
数据预处理:One-Hot 编码
features = pd.get_dummies(features)
features.head(5)
为了将分类数据转化为机器学习模型可以处理的数字格式,使用了 get_dummies()
进行 One-Hot 编码。这样,所有的分类特征(例如,星期几)会被转换为一系列的二进制列,标记每一天对应的特征是否为该分类。
标签与特征分离
import numpy as nplabels = np.array(features['actual'])features= features.drop('actual', axis = 1)feature_list = list(features.columns)features = np.array(features)
在这个阶段,代码从 features
数据集中提取了目标变量(即实际温度 'actual'
),并将其存储在 labels
中。接着,actual
列被删除,剩余的特征列保留在 features
变量中,并转换为 NumPy 数组,以便后续进行模型训练。
训练集与测试集划分
from sklearn.model_selection import train_test_splittrain_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size = 0.25,random_state = 42)
这里使用 train_test_split()
方法将数据集分为训练集和测试集,其中 25% 的数据用于测试,75% 用于训练。random_state=42
保证每次划分结果相同。
训练模型:随机森林回归
from sklearn.ensemble import RandomForestRegressor
rf = RandomForestRegressor(n_estimators= 1000, random_state=42)
rf.fit(train_features, train_labels)
在这部分,使用了 RandomForestRegressor
来构建回归模型。通过设置 n_estimators=1000
,指定使用 1000 棵树进行预测。训练过程中,模型学习训练数据的特征与目标之间的关系。
模型评估:预测与误差计算
predictions = rf.predict(test_features)
errors = abs(predictions - test_labels)
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
使用训练好的模型对测试数据进行预测,并计算预测值与实际标签之间的绝对误差。Mean Absolute Error
(MAE)表示预测结果与真实值之间的平均差异,帮助评估模型的精度。
MAPE(平均绝对误差百分比)
mape = 100 * (errors / test_labels)
accuracy = 100 - np.mean(mape)
print('Accuracy:', round(accuracy, 2), '%.')
此段代码通过计算 MAPE(Mean Absolute Percentage Error)来进一步评估模型的预测准确度。通过计算误差占实际值的比例,再计算模型的准确率。
决策树可视化
from sklearn.tree import export_graphviz
import pydottree = rf.estimators_[5]
export_graphviz(tree, out_file = './tree.dot', feature_names = feature_list, rounded = True, precision = 1)(graph, ) = pydot.graph_from_dot_file('./tree.dot')
graph.write_png('./tree.png')
此部分代码导出了随机森林中的一棵树并通过 pydot
生成了其图像。生成的 .dot
文件首先被转换为 PNG 格式的图像,以便后续展示和分析。
特征重要性评估
importances = list(rf.feature_importances_)feature_importances = [(feature, round(importance, 2)) for feature, importance in zip(feature_list, importances)]feature_importances = sorted(feature_importances, key = lambda x: x[1], reverse = True)[print('Variable: {:20} Importance: {}'.format(*pair)) for pair in feature_importances]
该代码段评估了各个特征在模型训练中的重要性。通过 .feature_importances_
获取特征重要性分数,并根据重要性对特征进行排序,帮助确定哪些特征对预测影响最大。
使用最重要的特征进行重新训练
rf_most_important = RandomForestRegressor(n_estimators= 1000, random_state=42)
important_indices = [feature_list.index('temp_1'), feature_list.index('average')]
train_important = train_features[:, important_indices]
test_important = test_features[:, important_indices]rf_most_important.fit(train_important, train_labels)
predictions = rf_most_important.predict(test_important)errors = abs(predictions - test_labels)
print('Mean Absolute Error:', round(np.mean(errors), 2), 'degrees.')
在这里,模型使用了两个最重要的特征(temp_1
和 average
)进行重新训练和预测。通过这种方式,可以评估仅用最相关特征进行训练的表现。
预测结果与真实值的比较
plt.plot(true_data['date'], true_data['actual'], 'b-', label = 'actual')
plt.plot(predictions_data['date'], predictions_data['prediction'], 'ro', label = 'prediction')
plt.xticks(rotation = '60');
plt.legend()plt.xlabel('Date'); plt.ylabel('Maximum Temperature (F)'); plt.title('Actual and Predicted Values');
代码通过绘图展示了实际值与预测值之间的差异。图中蓝线表示实际温度,红点表示预测温度,帮助直观地评估模型的预测效果。
数据与特征对随机森林的影响
这个任务旨在分析是否增加更多的特征(例如前一天的风速、降水和积雪深度等)可以提高模型的预测准确性。通过加载并探索不同的数据集,分析不同特征的引入对模型的影响。以下是对代码的逐步解析和概述。
加载和检查新数据
import pandas as pdfeatures = pd.read_csv('data/temps_extended.csv')
features.head(5)
这段代码从 'data/temps_extended.csv'
文件加载新的数据集,其中包含更多的特征(如 ws_1
、prcp_1
和 snwd_1
)。加载数据后,使用 .head(5)
展示前五行数据,以便快速查看数据的结构和格式。
数据规模
print('We have {} days of data with {} variables.'.format(*features.shape))
这里输出数据的行数和列数,帮助了解数据集的大小和维度。
数据的数值和可视化检查
round(features.describe(), 2)
使用 describe()
方法检查数据集的统计概况,如均值、标准差、最小值和最大值。这样可以初步了解数据的分布和变化范围。
日期转换
import datetimeyears = features['year']
months = features['month']
days = features['day']dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year, month, day in zip(years, months, days)]
dates = [datetime.datetime.strptime(date, '%Y-%m-%d') for date in dates]
此段代码将年份、月份和日期拼接为日期字符串,并使用 datetime.strptime()
转换为 datetime
类型,以便于后续的日期操作和可视化。
数据可视化
import matplotlib.pyplot as plt
get_ipython().run_line_magic('matplotlib', 'inline')
plt.style.use('fivethirtyeight')fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize=(15, 10))
fig.autofmt_xdate(rotation=45)# 绘制各类温度数据
ax1.plot(dates, features['actual'])
ax1.set_xlabel(''); ax1.set_ylabel('Temperature (F)'); ax1.set_title('Max Temp')
ax2.plot(dates, features['temp_1'])
ax2.set_xlabel(''); ax2.set_ylabel('Temperature (F)'); ax2.set_title('Prior Max Temp')
ax3.plot(dates, features['temp_2'])
ax3.set_xlabel('Date'); ax3.set_ylabel('Temperature (F)'); ax3.set_title('Two Days Prior Max Temp')
ax4.plot(dates, features['friend'])
ax4.set_xlabel('Date'); ax4.set_ylabel('Temperature (F)'); ax4.set_title('Friend Estimate')plt.tight_layout(pad=2)
通过 matplotlib
展示了四个不同的图表,分别表示实际的最高温度、前一天的最高温度、两天前的最高温度和朋友的估算温度。这样有助于理解这些特征随时间的变化趋势。
新增特征可视化
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2, figsize=(15, 10))
fig.autofmt_xdate(rotation=45)# 绘制新增特征的图表
ax1.plot(dates, features['average'])
ax1.set_xlabel(''); ax1.set_ylabel('Temperature (F)'); ax1.set_title('Historical Avg Max Temp')
ax2.plot(dates, features['ws_1'], 'r-')
ax2.set_xlabel(''); ax2.set_ylabel('Wind Speed (mph)'); ax2.set_title('Prior Wind Speed')
ax3.plot(dates, features['prcp_1'], 'r-')
ax3.set_xlabel('Date'); ax3.set_ylabel('Precipitation (in)'); ax3.set_title('Prior Precipitation')
ax4.plot(dates, features['snwd_1'], 'ro')
ax4.set_xlabel('Date'); ax4.set_ylabel('Snow Depth (in)'); ax4.set_title('Prior Snow Depth')plt.tight_layout(pad=2)
在这一部分,新增的特征(历史平均最高温度、前一天的风速、降水量和积雪深度)被绘制成图,以了解它们与温度数据之间的关系。
季节特征添加
seasons = []
for month in features['month']:if month in [1, 2, 12]:seasons.append('winter')elif month in [3, 4, 5]:seasons.append('spring')elif month in [6, 7, 8]:seasons.append('summer')elif month in [9, 10, 11]:seasons.append('fall')reduced_features = features[['temp_1', 'prcp_1', 'average', 'actual']]
reduced_features['season'] = seasons
通过判断月份,添加了一个 season
(季节)特征,分为冬季、春季、夏季和秋季,并将其加入到 reduced_features
数据集中。
特征关系检查:Pairplot
import seaborn as sns
sns.set(style="ticks", color_codes=True);palette = sns.xkcd_palette(['dark blue', 'dark green', 'gold', 'orange'])
sns.pairplot(reduced_features, hue='season', diag_kind='kde', palette=palette, plot_kws=dict(alpha=0.7), diag_kws=dict(shade=True))
使用 seaborn.pairplot()
可视化了不同特征之间的关系,并按季节颜色区分。通过这种方式,可以直观地检查 temp_1
和 average
特征与真实温度(actual
)之间的关系。
数据预处理:One-Hot 编码
features = pd.get_dummies(features)labels = features['actual']
features = features.drop('actual', axis=1)feature_list = list(features.columns)
features = np.array(features)
labels = np.array(labels)
将数据中的分类特征进行 One-Hot 编码后,分离出目标变量 actual
(实际温度),并将特征转换为 NumPy 数组,为训练模型做准备。
训练集与测试集划分
from sklearn.model_selection import train_test_splittrain_features, test_features, train_labels, test_labels = train_test_split(features, labels, test_size=0.25, random_state=42)
通过 train_test_split()
方法将数据划分为训练集和测试集,25%的数据用于测试,75%用于训练。
模型训练与评估
from sklearn.ensemble import RandomForestRegressorrf = RandomForestRegressor(n_estimators=1000, random_state=42)
rf.fit(train_features, train_labels)predictions = rf.predict(test_features)
errors = abs(predictions - test_labels)print('Average model error:', round(np.mean(errors), 2), 'degrees.')mape = 100 * (errors / test_labels)
accuracy = 100 - np.mean(mape)
print('Accuracy:', round(accuracy, 2), '%.')
使用 RandomForestRegressor
对训练集进行训练,并预测测试集的温度。计算平均绝对误差(MAE)和准确率(accuracy),用来评估模型的性能。
比较不同特征的数据集
rf = RandomForestRegressor(n_estimators=100, random_state=42)rf.fit(original_train_features, original_train_labels)
baseline_predictions = rf.predict(original_test_features)
baseline_errors = abs(baseline_predictions - test_labels)print('Metrics for Random Forest Trained on Original Data')
print('Average absolute error:', round(np.mean(baseline_errors), 2), 'degrees.')baseline_mape = 100 * np.mean((baseline_errors / test_labels))
baseline_accuracy = 100 - baseline_mape
print('Accuracy:', round(baseline_accuracy, 2), '%.')
这部分代码对比了基于原始数据和扩展数据(新特征)的模型表现。通过计算模型的误差和准确率,帮助我们分析是否增加新的特征能带来性能提升。
特征重要性分析
importances = list(rf_exp.feature_importances_)feature_importances = [(feature, round(importance, 2)) for feature, importance in zip(feature_list, importances)]
feature_importances = sorted(feature_importances, key=lambda x: x[1], reverse=True)plt.bar(x_values, importances, orientation='vertical', color='r', edgecolor='k', linewidth=1.2)
plt.xticks(x_values, feature_list, rotation='vertical')
plt.ylabel('Importance'); plt.xlabel('Variable'); plt.title('Variable Importances');
通过分析特征的重要性,我们能够识别哪些特征对模型预测最为关键。使用 RandomForestRegressor
提供的 .feature_importances_
属性来获取每个特征的贡献度。
特征的重要性与性能比较
model_comparison = pd.DataFrame({'model': ['original', 'exp_all', 'exp_reduced'], 'error (degrees)': [original_mae, exp_all_mae, exp_reduced_mae],'accuracy': [original_accuracy, all_accuracy, reduced_accuracy],'run_time (s)': [original_features_time, all_features_time, reduced_features_time]})
代码通过模型比较表格展示了不同模型(原始数据、扩展数据和简化数据集)的误差、准确率和运行时间,以帮助做出性能与计算资源之间的权衡。
随机森林参数选择
import pandas as pd
features = pd.read_csv('data/temps_extended.csv')
在这一部分数据集 temps_extended.csv
被加载到 features
变量中,包含了温度预测相关的各种特征。数据进行了一些基本的预处理,使用 pd.get_dummies()
进行 One-Hot 编码,将分类变量转化为数值变量,便于机器学习模型使用。
特征选择
important_feature_names = ['temp_1', 'average', 'ws_1', 'temp_2', 'friend', 'year']
选择了六个被认为在预测中具有较高重要性的特征。然后,基于这些特征创建了训练和测试数据集,只使用最重要的特征来进行建模。
模型构建与训练
rf = RandomForestRegressor(random_state = 42)
定义了一个基本的随机森林回归模型 RandomForestRegressor
,并使用 random_state=42
保证结果的可重复性。
超参数调优:随机搜索
from sklearn.model_selection import RandomizedSearchCV
使用 RandomizedSearchCV
进行随机超参数搜索,尝试不同的随机森林参数组合,目的是找到最优的参数配置。随机搜索的参数包括树的数量 (n_estimators
)、最大深度 (max_depth
)、最大特征数 (max_features
)、每个节点的最小样本数 (min_samples_split
),以及是否使用放回抽样 (bootstrap
) 等。
rf_random = RandomizedSearchCV(estimator=rf, param_distributions=random_grid,n_iter = 100, scoring='neg_mean_absolute_error', cv = 3, verbose=2, random_state=42, n_jobs=-1)
在这部分,创建了一个 RandomizedSearchCV
对象,执行了 100 次随机超参数搜索,并通过交叉验证(cv=3
)来评估模型的性能。
最优参数选择与评估
rf_random.best_params_
通过 .best_params_
获取随机搜索找到的最优超参数配置。
best_random = rf_random.best_estimator_
evaluate(best_random, test_features, test_labels)
使用最优的随机森林模型对测试集进行评估。评估函数 evaluate
计算模型的平均误差和准确率。
网格搜索:进一步微调
from sklearn.model_selection import GridSearchCV
在完成随机搜索之后,代码继续使用 GridSearchCV
对超参数进行微调,进一步优化模型的性能。网格搜索基于前一步的结果设定了一些更精细的参数范围。
grid_search = GridSearchCV(estimator = rf, param_grid = param_grid, scoring = 'neg_mean_absolute_error', cv = 3, n_jobs = -1, verbose = 2)
此时,GridSearchCV
对各个参数进行更加精确的遍历,寻找出最优配置。
最终模型与结果评估
best_grid = grid_search.best_estimator_
evaluate(best_grid, test_features, test_labels)
网格搜索完成后,最终得到的最佳模型会被评估,输出最终的平均误差和准确度。
总结
通过对天气数据进行随机森林回归建模,能够显著提高气温预测的准确性。数据的预处理、特征选择和模型参数调优是实现高效预测的关键步骤。通过对比不同特征配置和模型性能,发现扩展特征能够有效提升模型的预测能力。结合随机搜索和网格搜索等方法,进一步优化了模型参数配置,使得预测精度得到提升。这些方法不仅对天气预测任务具有应用价值,还为其他回归任务提供了有力的参考。
未来的工作可以继续探索更加复杂的特征工程,如引入更多的气象因素,或通过深度学习方法进一步提升模型性能。此外,进一步优化算法的计算效率和处理大规模数据的能力也是值得关注的方向。