基于随机森林的气温预测
在气象学领域,准确地预测天气对于许多行业来说都是至关重要的。随着机器学习技术的发展,我们现在能够利用历史数据来提高天气预报的准确性。本文将介绍如何使用随机森林算法来进行气温预测,并分享具体的Python实现代码。
python"># -*- coding:utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import datetime
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor #集成学习算法
from sklearn.tree import export_graphviz #实现树的可视化
import pydot
import os
import errno#1.设置输出显示
pd.set_option('display.max_columns', None) # 显示所有列
pd.set_option('display.max_rows', 20) # 根据需要调整显示的行数
pd.set_option('display.width', None) # 自动调整输出宽度#2.读取文件数据
df = pd.read_csv('C:/Users/72688/Desktop/机器学习/随机森林气温预测/data/temps.csv')
#打印前5行
#print(df.head(5))
#打印行列
#print(df.shape)
#打印均值、标准差、第一四分点、中位数、第三四份点
#print(df.describe())# 3.数据预处理
#把日期修改为xxxx-xx-xx
years = df['year']
months = df['month']
days = df['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]#画图查看列和标签的关系#plt.style.use('fivethirtyeight')
#fig,((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows=2,ncols=2,figsize = (10,10))
#fig.autofmt_xdate(rotation=45)#绘制标签数据随时间曲线#用于自动调整子图参数(如间距),使得所有绘图元素都能完美地适应图形区域。这对于避免子图之间的重叠非常有用
#plt.tight_layout(pad=2)# # 在第一个子图(ax1)上绘制实际温度随时间的变化曲线,并设置 x 轴、y 轴标签及标题
# ax1.plot(dates,df['actual'])
# ax1.set_xlabel('')
# ax1.set_ylabel('Temperature')
# ax1.set_title('Max Temp')
#
# #昨天
# ax2.plot(dates,df['temp_1'])
# ax2.set_xlabel('')
# ax2.set_ylabel('Temperature')
# ax2.set_title('Previous Max Temp')
#
# #前天
# ax3.plot(dates,df['temp_2'])
# ax3.set_xlabel('Date')
# ax3.set_ylabel('Temperature')
# ax3.set_title('Two Day Prior Max Temp')
#
# #朋友
# ax4.plot(dates,df['friend'])
# ax4.set_xlabel('Date')
# ax4.set_ylabel('Temperature')
# ax4.set_title('Friend Estimate')#绘图展示
#plt.show()#数据编码:把周几字符串转换为数值类型
df = pd.get_dummies(df)
#print(df.head(5))
#查看API文档
#print (help(pd.get_dummies))
#print(f'Shape of df after one-hote encoding : {df.shape}')#标签数据格式转换#标签
labels = df['actual'].to_numpy()#在特征中去掉标签,0表示行1表示列
df = df.drop('actual',axis=1)
#print(df.friend)#单独保存一下名字
df_list = list(df.columns)
#print(df_list)#转换成数组格式
df = df.to_numpy()
#print(type(df))#4. 划分训练集
train_df,test_df,train_labels,test_labels = train_test_split(df, labels, test_size=0.25, random_state=42)
# print(f'训练集特征:{train_df.shape}')
# print(f'测试集特征:{train_labels.shape}')
# print(f'训练集标签:{test_df.shape}')
# print(f'测试集标签:{test_labels.shape}')#5 .建立随机森林模型并训练#先建立1000棵树,其他参数默认,后续在进行调参
rf = RandomForestRegressor(n_estimators=100, random_state=42)
rf.fit(train_df , train_labels)#测试
#预测结果
predictions = rf.predict(test_df)#6.模型评估
errors = abs(predictions - test_labels)
#mape评价指标
mape = 100 * (errors / test_labels)
#print(type(mape))
#print(f'mape is : {np.mean(mape)}')#可视化展示树#拿到一颗树
tree = rf.estimators_[5]
#导出dot文件
#df_names包含特征名称(列名)的列表rounded=True: 设置节点形状为圆角矩形,precision=1: 设置数字值的精度为小数点后1位。# export_graphviz(tree,out_file='C:/Users/72688/Desktop/随机深林气温预测/tree.dot',feature_names=df_list,rounded=True,precision=1)(graphs,) = pydot.graph_from_dot_file('C:/Users/72688/Desktop/随机深林气温预测/tree.dot')# graphs.write_png('C:/Users/72688/Desktop/随机深林气温预测/tree.png')#限制树的数量和深度rf_small = RandomForestRegressor(n_estimators=10, max_depth=3, random_state=42)
rf_small.fit(train_df,train_labels)
#提取一棵树
tree_small = rf_small.estimators_[5]
#保存
# export_graphviz(tree_small,out_file='C:/Users/72688/Desktop/随机深林气温预测/small_tree.dot',feature_names=df_list,rounded=True,precision=1)
(graphs,) = pydot.graph_from_dot_file('C:/Users/72688/Desktop/随机深林气温预测/small_tree.dot')
# graphs.write_png('C:/Users/72688/Desktop/随机深林气温预测/small_tree.png')#7.参数调优 特征重要性#得到重要特征
importances = list(rf.feature_importances_)#转换格式
feature_importances = [(feature,round(importance,2)) for feature,importance in zip(df_list,importances)]#排序
# 对特征重要性进行排序,依据是每个特征的重要性值(即元组中的第二个元素),reverse=True表示按降序排列
# 对特征重要性列表进行排序:按重要性值(每个元素的第二个值)降序排列
feature_importances = sorted(feature_importances,key=lambda x: x[1], # 指定排序依据为每个元素的第二个值(重要性)reverse=True # 降序排列(从大到小)
)
# 遍历排序后的列表,按格式打印每个特征及其重要性,{:20}表示占位符宽度为20字符,默认左对齐。
# pair 将元组解包为多个参数(例如 pair=('age', 0.8) 解包为 'age', 0.8)
#[print(f'Variable:{Variable:<20} Importance: {Importance}') for Variable,Importance in feature_importances]#用最重要的两个特征试一试rf_most_important = RandomForestRegressor(n_estimators=100,random_state=42)
#拿到这两特征
important_indices = [df_list.index('temp_1'),df_list.index('average')]
#:表示所有行,第二个参数表示取哪些列
train_important = train_df[:,important_indices]
test_important = test_df[:,important_indices]
#重新训练模型
rf_most_important.fit(train_important, train_labels)
#预测结果
predictions = rf_most_important.predict(test_important)
errors = abs(predictions - test_labels)
#评估结果
mape =np.mean(100*(errors/test_labels))
#print(f"mape: {mape}")'''
#转换成list格式
# 计算 importances 列表的长度,这通常对应于特征的数量
# range(len(importances)) 生成一个从 0 开始到 len(importances)-1 的整数序列,
# 这些整数代表了每个特征的索引位置。
# list(range(len(importances))) 将这个整数序列转换成列表形式,
# 以便用于后续操作,例如绘图时作为 x 轴的值。
# 举例importances = [0.2, 0.4, 0.3, 0.1] x_values = [0, 1, 2, 3]
# 这样就可以使用 [0, 1, 2, 3] 作为 x 轴坐标,分别对应 importances 中的各个特征重要性值 [0.2, 0.4, 0.3, 0.1]
x_values = list(range(len(importances)))
# 绘图
# x_values: 一个列表或数组,包含条形图中每个条形的 x 轴位置(通常是特征索引)
# importances: 一个列表或数组,包含与 x_values 中每个位置对应的数值(通常是特征的重要性值)
# orientation='vertical': 显式指定条形图的方向为垂直。虽然默认情况下条形图就是垂直的,
# --代码会根据 x_values 和 importances 绘制一个垂直条形图。
# --每个条形的位置由 x_values 中的对应值确定,高度由 importances 中的对应值确定。
plt.bar(x_values,importances,orientation='vertical')
#x轴名字
# x_values: 一个列表或数组,定义了 x 轴上每个刻度的位置。这些位置通常对应于数据点在 x 轴上的位置。
# df_list: 一个列表、元组或数组,包含了要在 x 轴刻度上显示的标签。这些标签通常是分类变量或特征名称。
# rotation='vertical': 设置 x 轴刻度标签的旋转角度为垂直方向。这有助于改善当标签过长时可能出现的重叠问题,使得标签更易于阅读。
# 代码将 x 轴的刻度位置设置为 x_values 中指定的位置,并将这些刻度对应的标签设置为 df_list 中的元素。
# 此外,它还将 x 轴刻度标签的显示方向设置为垂直,这样即使标签文字较长也不会相互覆盖,提升了图表的可读性。
plt.xticks(x_values,df_list,rotation='vertical')
# 图名
plt.ylabel('Importance') # 设置y轴标签为 "Importance"
plt.xlabel('Variable') #设置x轴标签为 "Variable"
plt.title('Variable Importances')#设置图表的标题为 "Variable Importances"
#打印图标
#plt.show()
'''#预测值和真实值之间的差异#日期数据
months = df[:,df_list.index('month')]
days = df[:,df_list.index('day')]
years = df[:,df_list.index('year')]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]
#创建一个表格来存日期和对应的参数值
true_data = pd.DataFrame(data = {'date': dates, 'actual': labels})# 同理,再创建一个来存日期和其对应的模型预测值
months = test_df[:,df_list.index('month')]
days = test_df[:,df_list.index('day')]
years = test_df[:,df_list.index('year')]
test_dates = [str(int(year)) + '-' + str(int(month)) + '-' + str(int(day)) for year,month,day in zip(years,months,days)]
test_dates = [datetime.datetime.strptime(date,'%Y-%m-%d') for date in test_dates]
predictions_data = pd.DataFrame(data = {'date': test_dates, 'prediction': predictions})#真实值
# true_data['date']: 这是一个包含日期数据的序列(例如,pandas Series 或列表),表示时间轴上的各个点。
# true_data['actual']: 这是与日期对应的观测值或实际值的数据序列。每个值对应于特定日期的实际测量结果。
# 'b-': 这是线条样式的简写:
# - 'b' 表示蓝色(blue)。在 matplotlib 中,不同的字符代表不同的颜色,比如 'r' 代表红色,'g' 代表绿色等。
# - '-' 表示使用实线来连接数据点。其他可能的选项包括 '--' (虚线)、'-.' (点划线)和 ':' (点线)。
# label='actual': 这个参数为绘制的线条提供了一个标签,这里是 'actual'。这个标签会在图表的图例中显示,
# 帮助区分不同数据序列。当你有多个数据序列在同一张图表上时,使用标签并生成图例是非常有用的。
# --代码将在图表上绘制一条蓝色的实线,这条线将展示 'date' 和 'actual' 数据之间的关系。
# --它表示了随时间变化的实际观测值,并且这条线在图例中被标记为 'actual'。
plt.plot(true_data['date'],true_data['actual'],'b-',label='actual')
# 预测值
# 'ro': 这是线条样式的简写:
# - 'r' 表示红色(red)。在 matplotlib 中,不同的字符代表不同的颜色,比如 'b' 代表蓝色,'g' 代表绿色等。
# - 'o' 表示使用圆形标记来标识数据点。其他可能的选项包括 's' (正方形)、'^' (三角形)等等。
# 代码将在图表上绘制一系列红色的圆点,这些点将展示 'date' 和 'prediction' 数据之间的关系。
# 它表示了随时间变化的预测值,并且这些点在图例中被标记为 'prediction'。
plt.plot(predictions_data['date'], predictions_data['prediction'], 'ro', label = 'prediction')
# 调整 x 轴刻度标签的角度以便更易于阅读。这里设置为 60 度倾斜。
plt.xticks(rotation = '60');
# 显示图例。图例展示了图表中不同数据序列的标签(在这个例子中就是 'prediction'),
# 并说明每个标签所代表的数据序列的颜色和样式。
plt.legend()# 图名
plt.xlabel('Date'); plt.ylabel('Maximum Temperature (F)'); plt.title('Actual and Predicted Values')#绘图
plt.show()