基于XGBoost的机器学习预测(预测平均温度)

欢迎在评论区讨论,在最后附有源码链接(github),如果使用帮忙留个star。本文章有用也请多评论、点赞、收藏,以供大家学习参考!

本篇文章有些库是没有使用,或者过度引入,请大家自行检查~(作者偷偷懒)

我用的开发工具:Jupyter NoteBook(Pyhton版本:3.11.5),开发使用的库见代码

数据准备分析过程

爬取数据(顺带实现了断点续爬功能)

首先爬取茂名近五年天气数据,爬取过程要严格遵守网站的Robots协议

分析url路径,根据前端样式进行爬取

断点续爬:上次断开爬取的地方,能接着继续爬取,不用重头开始,增强代码可用性

import httpx
from bs4 import BeautifulSoup
import csv
import random
import time
import pandas as pd
import os

# 记录已成功爬取的URL,用于断点续爬
success_urls_file = "success_urls.txt"
if os.path.exists(success_urls_file):
    with open(success_urls_file, 'r') as f:
        success_urls = set(line.strip() for line in f.readlines())
else:
    success_urls = set()

file = open('maoming_temp.csv', mode='a', encoding='utf-8', newline='')
csv_writer = csv.DictWriter(file, fieldnames=[
    "日期", "最高温", "最低温", "天气", "风力风向", "空气质量指数"
])
# 如果文件为空(首次运行),写入表头
if os.path.getsize('maoming_temp.csv') == 0:
    csv_writer.writeheader()

headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36",
    "cookie":"切换为你自己的cookie"
}

urls = []
for year in range(2019, 2024 + 1):
    for month in range(1, 12 + 1):
        url = "http://www.826226.com/lstq/440900_{}_{}/".format(year, month)
        urls.append(url)

for url in urls:
    try:
        if url in success_urls:
            continue
        # 请求数据
        response = httpx.get(url, headers=headers)
        # 分析数据
        soup = BeautifulSoup(response.text, "lxml")
        # 提取数据
        table = soup.find("table", attrs={"class": "history-table"})
        trs = table.findAll("tr")
        # 遍历数据
        for tr in trs[1:]:
            tds = tr.findAll("td")
            date = tds[0].text
            max_temp = tds[1].text
            min_temp = tds[2].text
            weather = tds[3].text
            windy = tds[4].text
            aqi = tds[5].text
            Dict = {"日期": date, "最高温": max_temp, "最低温": min_temp, "天气": weather, "风力风向": windy, "空气质量指数": aqi}
            print(Dict)  # 新增这行,打印当前提取的数据字典,可实时看到每行数据内容
            csv_writer.writerow(Dict)
        # 将成功爬取的URL记录下来
        with open(success_urls_file, 'a') as f:
            f.write(url + '\n')
        # 随机休眠几秒
        time.sleep(random.randint(3, 8))
    except:
        time.sleep(random.randint(5, 8))
        continue

爬取部分结果:

数据清洗存放最初数据

存放并保存在本地文件夹中的天气记录数据csv文件中

清洗过程是通过爬取后数据查看需要清洗的类型对其格式进行特定清洗

# 数据处理
df = pd.read_csv("maoming_temp.csv")

df["日期"] = df["日期"].map(lambda x: x.split(" ")[0])
df["风向"] = df["风力风向"].map(lambda x: x[:-2])
df["风力"] = df["风力风向"].map(lambda x: x[-2:])
df["空气质量指数标签"] = df["空气质量指数"].map(lambda x: x.split(" ")[1] if x!= "-" else "-")
df["空气质量指数"] = df["空气质量指数"].map(lambda x: x.split(" ")[0] if x!= "-" else "-")
df = df[['日期', '最高温', '最低温', '天气', '风向', '风力', '空气质量指数', '空气质量指数标签']]

df.to_csv("近五年(2019-2024)茂名市天气记录数据.csv", encoding="utf-8-sig", index=False)

数据可视化过程

此过程是分析数据,为后面模型训练做准备

#数据可视化
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib import font_manager
import warnings

warnings.filterwarnings('ignore')

font_path = 'fonts\ZhuqueFangsong-Regular.ttf'
font_manager.fontManager.addfont(font_path)
prop = font_manager.FontProperties(fname=font_path)

plt.rcParams['font.family'] = 'sans-serif'
plt.rcParams['font.sans-serif'] = prop.get_name()
plt.rcParams['axes.unicode_minus'] = False

df = pd.read_csv('D:\workspace\dashuju\近五年(2019-2024)茂名市天气记录数据.csv')
df.head()

展示出来

为下一步图形进行数据预处理

#数据预处理,为了方便展示图形
df["日期"] = df["日期"].map(lambda x: x.replace("/", "-"))
df["日期"] = pd.to_datetime(df["日期"],format="%Y-%m-%d")

# 键值对获取以下信息
df["最高温"] = df["最高温"].map(lambda x:x[:-1]).astype(float)
df["最低温"] = df["最低温"].map(lambda x:x[:-1]).astype(float)

# 画图准备
df["空气质量指数"] = df["空气质量指数"].replace("-",np.nan).astype(float)
df["空气质量指数"].fillna(round(df["空气质量指数"].mean(),1),inplace=True)

# 计算均温
df["平均温度"] = (df["最高温"]+df["最低温"])/2

# 键值对获取年月
df["年份"] = df["日期"].map(lambda x:x.year)
df["月份"] = df["日期"].map(lambda x:x.month)


#画图,设置格式
fig,ax = plt.subplots(1,1,figsize=(12,6),dpi=100)

ax.plot(df["日期"], df["最高温"],label="最高温",color="#32CCBC",zorder=2)
ax.plot(df["日期"], df["最低温"],label="最低温",color="#8ffcda",zorder=2)
ax.legend(frameon=False,fontsize=12)
ax.tick_params(labelsize=14)
ax.grid(axis="both",ls="--")
ax.set_ylim(-10,)
ax.set_xlabel("日期",fontsize=18)
ax.set_ylabel("温度",fontsize=18)
ax.set_title("近五年(2019-2024)茂名市气温变化趋势",fontsize=22)

for spine in ax.spines.values():  
    spine.set_visible(False)  
plt.show()

结果展示

tmp = df.query("年份 <= 2024").groupby("年份").agg({"平均温度":"mean"}).reset_index()

fig,ax = plt.subplots(1,1,figsize=(12,6),dpi=100)

ax.plot(np.arange(len(tmp)),tmp["平均温度"],color="#8ffcda",marker="o",ms=12,mec="#32CCBC",mew=2,zorder=2)
ax.set_xticks(np.arange(len(tmp)), tmp["年份"])
ax.grid(axis="both",ls="--",zorder=1)
ax.tick_params(axis="both",labelsize=14)
ax.set_xlabel("年份",fontsize=16)
ax.set_ylabel("平均温度",fontsize=16)
for idx,row in tmp.iterrows():
    #ax.text(idx-.06, row["平均温度"]-.04, str(round(row["平均温度"],2))+"°",fontsize=14)
    if row["年份"] < 2022:
        ax.text(idx+.06, row["平均温度"]-.01, str(round(row["平均温度"],2))+"°",fontsize=14)
    else:
        ax.text(idx-.06, row["平均温度"]-.04, str(round(row["平均温度"],2))+"°",fontsize=14)
ax.set_title("2019~2024年年平均温度变化趋势",fontsize=22)  

for spine in ax.spines.values():  
    spine.set_visible(False)  
plt.show()

结果

#计算天气出现的次数
tmp = df["天气"].value_counts().to_frame().reset_index()
# 计算百分比
tmp["percent"] = tmp["count"].map(lambda x:round(x/tmp["count"].sum()*100,2))
# 排名
tmp["rank"] = tmp["count"].rank(method="dense",ascending=False)
# 筛选前十
tmp = tmp.query("rank <= 10")[::-1]

#设置图形参数
fig,ax = plt.subplots(1,1,figsize=(12,6),dpi=100)

b = ax.barh(tmp["天气"],tmp["percent"],height=.6,color="#00c2a8",edgecolor="#008f7a")
ax.bar_label(b,["{}天({}%)".format(i,j) for i,j in zip(tmp["count"], tmp["percent"])],fontsize=14,padding=2)
ax.set_yticklabels(tmp["天气"],fontsize=14)
ax.set_xticks([])

for spine in ax.spines.values():  
    spine.set_visible(False)  
ax.spines["left"].set_visible(True) 
fig.suptitle("近五年(2019~2024)茂名市出现次数Top10的天气类型",fontsize=22)
plt.show()

结果

#计算风向次数
tmp = df["风向"].value_counts().to_frame().reset_index()
# 计算百分比
tmp["percent"] = tmp["count"].map(lambda x:round(x/tmp["count"].sum()*100,2))

fig,ax = plt.subplots(1,1,figsize=(12,6),dpi=100)

b = ax.bar(tmp["风向"],tmp["percent"],width=.5,color="#00c2a8",edgecolor="#008f7a")
ax.bar_label(b,["{}天\n{}%".format(i,j) for i,j in zip(tmp["count"], tmp["percent"])],fontsize=14,padding=2)
ax.set_ylim(0,60)
ax.set_xticklabels(tmp["风向"],fontsize=14)
ax.set_yticks([])

for spine in ax.spines.values():  
    spine.set_visible(False)  
ax.spines["bottom"].set_visible(True) 
fig.suptitle("近五年(2019~2024)茂名市各风向类型的出现次数",fontsize=22)
plt.show()

结果展示

tmp = df["空气质量指数标签"].value_counts().to_frame().reset_index()
# 计算百分比
tmp["percent"] = tmp["count"].map(lambda x:round(x/tmp["count"].sum()*100,2))
# 排序规则
tmp = tmp[::-1]

# 画图格式
tmp["空气质量指数标签"].replace("-","未知",inplace=True)
fig,ax = plt.subplots(1,1,figsize=(12,6),dpi=100)

b1 = ax.barh(tmp["空气质量指数标签"],100,height=.5,color="#b8bbc0",alpha=.5)
b2 = ax.barh(tmp["空气质量指数标签"],tmp["percent"],height=.48,color="#00baad",edgecolor="#008a5e")
ax.set_xlim(0,100)
ax.set_xticks([])
ax.tick_params(axis="y",labelsize=14)
ax.bar_label(b2,padding=2,fmt="%s%%",fontsize=14)
ax.set_title("近五年(2019-2024)茂名市各空气质量天气出现次数",fontsize=22)

for spine in ax.spines.values():  
    spine.set_visible(False) 
plt.show()

结果展示

fig,ax = plt.subplots(1,1,figsize=(12,6),dpi=100)

sns.stripplot(x="年份",y="空气质量指数",hue="年份",data=df,ax=ax,zorder=2)
ax.grid(axis="y",ls="--",zorder=1)
ax.legend().set_visible(False)
ax.tick_params(axis="both",labelsize=12)
ax.set_xlabel("年份",fontsize=16)
ax.set_ylabel("空气质量指数",fontsize=16)

for spine in ax.spines.values():  
    spine.set_visible(False) 
fig.suptitle("近五年(2019-2024)茂名市空气质量指数分布情况",fontsize=22)
plt.show()

结果展示

XGboost模型训练预测过程(预测平均温度)

将刚刚准备好的数据准备好使用

数据二次清洗过程(为模型训练做准备)

将数据转为算法可以检测到的数据(比如中文转为数字形式投入模型进行训练)

字段那一部分要根据实际爬到的情况进行写入,这段写得可能有点复杂,我搜索到的数据是有可以直接转为字段的方法(我这里并没采取,可自行优化)。

import httpx
from bs4 import BeautifulSoup
import csv
import random
import time
import pandas as pd
import os
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import MinMaxScaler
import numpy as np
from pyhive import hive 

df = pd.read_csv('近五年(2019-2024)茂名市天气记录数据.csv')

# 清洗掉错误数据
# 创建一个布尔掩码,用于判断每行是否包含“-”
mask = df.apply(lambda row: row.astype(str).str.contains('-').any(), axis=1)
# 根据布尔掩码删除包含“-”的行
df = df[~mask]
# 再次检查并删除可能遗漏的包含“-”的行(可根据实际情况确定是否需要重复这步)
mask = df.apply(lambda row: row.astype(str).str.contains('-').any(), axis=1)
df = df[~mask]


# 转换为可以由numpy简单处理的格式
df["日期"] = pd.to_datetime(df["日期"], format="%Y/%m/%d")
df["年份"] = df["日期"].dt.year
df["月份"] = df["日期"].dt.month
df["日"] = df["日期"].dt.day
df = df.drop("日期", axis=1)

# 将object格式转为浮点数
df["最高温"] = df["最高温"].astype(str)
df["最低温"] = df["最低温"].astype(str)
df["最高温"] = df["最高温"].str.replace("°", "").astype(float)
df["最低温"] = df["最低温"].str.replace("°", "").astype(float)

# 处理风向
wind_direction_mapping = {"东风": 0, "南风": 1, "西风": 2, "北风": 3, "东南风": 4, "西南风": 5, "西北风": 6, "东北风": 7}
df["风向"] = df["风向"].map(wind_direction_mapping)

# 处理风力
# 先将风力列转换为字符串类型(确保后续替换操作能正常进行)
df["风力"] = df["风力"].astype(str)
# 使用replace方法将"微风"替换为"0级风",可根据实际增加更多替换
df["风力"] = df["风力"].replace("微风", "0级风")
# 再提取数字部分并转换为整数类型
df["风力"] = df["风力"].str.extract('(\d+)').astype(int)

# 处理空气质量指数
df["空气质量指数"] = df["空气质量指数"].astype(float)

# 处理空气质量指数标签(此部分若对温度预测帮助不大,可考虑后续是否保留)
Air_Quality_Index_label = {"优": 2, "良": 1, "轻度": 0}
df["空气质量指数标签"] = df["空气质量指数标签"].map(Air_Quality_Index_label)

# 优化天气特征处理 - 新增是否有降水列
def has_precipitation(weather_type):
    precipitation_keywords = ["雨", "雪", "雹", "雾"]
    for keyword in precipitation_keywords:
        if keyword in weather_type:
            return 1
    return 0
df["是否有降水"] = df["天气"].apply(has_precipitation)

# 优化天气特征处理 - 新增云量等级列
def cloud_cover_level(weather_type):
    if "晴" in weather_type:
        return 0
    elif "多云" in weather_type:
        return 1
    elif "阴" in weather_type:
        return 2
    return 0
df["云量等级"] = df["天气"].apply(cloud_cover_level)

# 优化天气特征处理 - 新增天气变化列及编码
df["天气变化"] = df["天气"].shift(1)
df["天气变化"] = df.apply(lambda row: f"{row['天气变化']}->{row['天气']}" if pd.notnull(row['天气变化']) else row['天气'], axis=1)
weather_change_mapping = {}
unique_weather_changes = df["天气变化"].unique()
for index, change in enumerate(unique_weather_changes):
    weather_change_mapping[change] = index
df["天气变化编码"] = df["天气变化"].map(weather_change_mapping)

# 对天气进行编码(原代码方式,可根据后续情况决定是否保留或调整)
weather_types = ['多云~小雨', '小雨', '阴', '多云', '阴~多云', '阴~小雨', '多云~阴', '晴', '晴~多云', '阵雨~多云', '阵雨', '中雨',
                 '多云~阵雨', '雷阵雨~阵雨', '中雨~阵雨', '中雨~多云', '中雨~阴', '中雨~雷阵雨', '阵雨~中雨', '大到暴雨~中到大雨',
                 '阵雨~阴', '大雨~中雨', '阵雨~大雨', '大到暴雨', '大雨~阵雨', '雷阵雨~多云', '多云~雷阵雨', '大到暴雨~阵雨', '大雨',
                 '中雨~大雨', '大到暴雨~中雨', '雷阵雨~中雨', '雷阵雨', '大雨~大到暴雨', '多云~晴', '多云~中雨', '小雨~多云', '阴~晴',
                 '阴~中雨', '小雨~阴', '小雨~中雨', '阴~阵雨', '小雨~阵雨', '小雨~雷阵雨', '大雨~多云', '雾~多云', '阴~雷阵雨',
                 '小雨~大雨', '阴~大雨', '多云~大雨', '小雨~晴', '雾~阴', '中雨~小雨', '阴~暴雨', '大暴雨~大雨', '雾~晴', '小雨~暴雨',
                 '暴雨', '雾~阵雨', '雾~小雨', '雾~中雨', '雾~雷阵雨', '暴雨~中雨', '大雨~暴雨', '大雨~雷阵雨', '暴雨~阵雨',
                 '大暴雨~暴雨', '暴雨~大雨', '暴雨~晴', '大雨~阴', '暴雨~多云', '中雨~暴雨', '中雨~大暴雨', '大雨~小雨', '中雨~晴']
weather_mapping = {}
for index, weather_type in enumerate(weather_types):
    weather_mapping[weather_type] = index
df['天气编码'] = df['天气'].map(weather_mapping)
df = df.drop("天气", axis=1)

# 特征组合与交互项添加(风向和风力交互示例)
wind_direction = df[["风向"]].values
wind_force = df[["风力"]].values
poly = PolynomialFeatures(degree=2, interaction_only=True, include_bias=False)
wind_combined = poly.fit_transform(np.concatenate((wind_direction, wind_force), axis=1))
wind_combined_df = pd.DataFrame(wind_combined, columns=["风向", "风力", "风向_风力交互"])
df = pd.concat([df, wind_combined_df], axis=1)

# 清除包含空值的行
df = df.dropna()


# 将处理好的数据保存为csv文件,设置编码为utf-8,不保存索引列
df.to_csv('maoming_optimized.csv', encoding='utf-8', index=False)

分析影响温度的最主要特征(影响排行榜与热力图)

这一段的归一化可以使得模型预测更加准确,不过会将温度转为0~1,不过后面没有反归一化操作会使得温度并不是以正常数据显示

这里可能有点小缺点(基于我现在的技术无法将天气变化非常好的放入模型进行训练),所以导致可能天气相关性不是很高

import httpx
from bs4 import BeautifulSoup
import csv
import random
import time
import pandas as pd
import os
import xgboost as xgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from sklearn.preprocessing import PolynomialFeatures
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# 读取数据
#df = pd.read_csv('maoming_optimized.csv',encoding='GBK')
df = pd.read_csv('maoming_optimized.csv')

# 新增特征示例(温差、平均温度,延续你提供代码的思路)
df['温差'] = df['最高温'] - df['最低温']
df['平均温度'] = (df["最高温"] + df["最低温"]) / 2

# 重新审视特征选择(以预测最高温为例,根据实际情况调整目标和特征列表)
target = "平均温度"
features = ["月份", "日", "是否有降水", "云量等级", "天气变化编码", "风向", "风力", "空气质量指数", "风向_风力交互", "温差"]

# 数据归一化处理(示例对部分特征归一化,可根据实际情况调整要归一化的特征列)
# cols_to_normalize = ["风力", "空气质量指数", "温差", "平均温度"]
# scaler = MinMaxScaler()
# df[cols_to_normalize] = scaler.fit_transform(df[cols_to_normalize])

# 相关性分析部分(与你提供代码类似,但基于更新后的特征和数据)
df = df.drop("天气变化", axis=1)
corr_matrix = df.corr()
# 提取目标变量与其他变量的相关系数,并按绝对值大小排序
sorted_corr = corr_matrix[target].abs().sort_values(ascending=False)
print(sorted_corr)

# 设置中文字体显示及负号显示正常(适用于中文标注及可视化)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 绘制相关性热图(可视化各特征之间以及与目标变量的相关性)
plt.figure(figsize=(10, 8))
sns.heatmap(df.corr(), linewidths=.2, annot=True)
plt.show()

结果展示

可以看到影响最大的特征是空气质量指数、月份、风力(颜色最深)。最低温、最高温空气质量指数标签不采纳的原因是前两个是计算出平均温度的,舍去;最后一个是由空气质量指数计算出来的,所以可以舍去。

划分数据集开始训练

这里参考了文章可自行找到最优参数的方法(存疑未验证,但是训练的模型准确性尚可)

73划分数据集,开始训练!

from sklearn.model_selection import GridSearchCV

# 划分训练集和测试集(假设70%数据用于训练,30%用于测试)
X = df[features]
y = df["平均温度"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)

# 创建XGBoost模型对象(可调整参数优化模型性能)

# 定义要搜索的参数网格
param_grid = {
   'max_depth': [3, 5, 7],
   'eta': [0.05, 0.1, 0.2],
   'subsample': [0.7, 0.8, 0.9],
   'colsample_bytree': [0.7, 0.8, 0.9]
}

# 创建XGBoost模型对象(先不传入具体参数)
model = xgb.XGBRegressor()

# 创建网格搜索对象,传入模型、参数网格和评估指标等
grid_search = GridSearchCV(estimator=model, param_grid=param_grid, scoring='neg_mean_squared_error', cv=5)

# 在训练集上进行网格搜索,找到最优参数组合
grid_search.fit(X_train, y_train)

# 获取最优参数
best_params = grid_search.best_params_
print(best_params)

# 使用最优参数创建模型并训练
best_model = xgb.XGBRegressor(**best_params)
best_model.fit(X_train, y_train)

# # 模型训练
# model.fit(X_train, y_train)
model = best_model
# 模型预测
y_pred = model.predict(X_test)

参数如下:

评估模型

采用多种方法,如均方误差、决定系数...等方法进行评估

# 评估模型预测结果(示例使用均方误差,可根据实际选用其他评估指标)
from sklearn.metrics import mean_squared_error, r2_score, mean_absolute_error
# 1. 均方误差(MSE)
mse = mean_squared_error(y_test, y_pred)

# 2. 决定系数(R²)
r2 = r2_score(y_test, y_pred)

# 3. 平均绝对误差(MAE)
mae = mean_absolute_error(y_test, y_pred)

# 4. 均方根误差(RMSE),是MSE的平方根,对误差的衡量更符合直观感受
rmse = np.sqrt(mean_squared_error(y_test, y_pred))


# 5. 平均绝对百分比误差(MAPE),衡量预测值相对误差的百分比,能直观体现相对误差情况,但要注意分母不能为0的情况
def mape(y_true, y_pred):
    y_true, y_pred = np.array(y_true), np.array(y_pred)
    return np.mean(np.abs((y_true - y_pred) / y_true)) * 100
mape_value = mape(y_test, y_pred)

print(f"均方误差(MSE): {mse}")
print(f"决定系数(R²): {r2}")
print(f"平均绝对误差(MAE): {mae}")
print(f"均方根误差(RMSE): {rmse}")
print(f"平均绝对百分比误差(MAPE): {mape_value}")

结果如下:

可发现模型是个优秀的水平,但未达到出色,不过平时学习的话个人认为还是非常不错~

可视化展示

代码如下,并随机抽取模型

errors = abs(y_test - y_pred)
plt.figure(figsize=(12, 6))  # 设置图形大小
plt.bar(range(len(errors)), errors)  # 绘制柱形图,横坐标为样本序号,纵坐标为误差绝对值
plt.xlabel('测试集样本序号')
plt.ylabel('预测误差绝对值')
plt.title('真实数据与预测数据间的误差分布')
plt.show()



# 绘制折线图展示预测值与真实值对比
# 生成索引用于横坐标(这里简单使用测试集的索引,可根据实际需求调整更合理的横坐标表示方式)
index = range(len(y_test))
plt.plot(index, y_test, label='真实值', marker='o')
plt.plot(index, y_pred, label='预测值', marker='s', linestyle='--')
plt.xlabel('样本序号')
plt.ylabel('平均温度')
plt.title('平均温度预测值与真实值对比')
plt.legend()
plt.show()


print("前5个平均温度真实值:", y_test[:5])
print("前5个平均温度预测值:", y_pred[:5])



import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates


# 设置中文字体显示及负号显示正常(适用于中文标注及可视化)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False


#随机10天的预测点
y_pred = y_pred[:10]
y_test = y_test[:10]
X_test_date = X_test["日"][:10]

# 绘制散点图(点状图),使用plt.scatter替换原来的plt.plot
plt.scatter(X_test_date, y_pred, label='预测平均温度', marker='o')
plt.scatter(X_test_date, y_test, label='实际平均温度', marker='s')
plt.xlabel('日期')
plt.ylabel('平均温度')
plt.title('茂名市平均温度随日期变化趋势(部分数据示例)')
plt.xticks(rotation=45)  # 让x轴刻度标签旋转45度,避免重叠显示不清
plt.legend()
plt.show()

结果展示

这里可以看到走势图走势非常接近真实数据,不错的模型,随机五个点的值也与预测很接近!

结尾

此次经历也让我收获颇丰,希望这篇文章对你也有些许帮助。不妨点个赞,留个言收个藏,如果有想学习交流可以一起哇~

源码https://github.com/gf139/XGBoot_WeatherForecastingSystem.git

希望留个star啊!

Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐