《商务智能应用方法》期末课程设计

基于历史数据的天气预测模型

组员:2115090116 卢家业 2115090118 覃庆烽

一、摘要

随着气候变化的加剧和极端天气事件的频发,准确的天气预测变得越来越重要。本文提出了一种基于历史数据的天气预测模型,旨在提高短期和中期天气预报的精度。该模型利用多年的气象观测数据,通过数据清洗、特征提取和机器学习算法,建立了一套完整的预测系统。我们选用了多种算法,包括线性回归、决策树、随机森林和深度神经网络,对比分析其在不同气象条件下的预测性能。研究表明,结合多种算法的集成模型在温度、降水量、风速等指标上的预测精度显著优于单一模型。特别是深度神经网络在处理复杂非线性关系方面表现出色。模型经过交叉验证和实地测试,结果显示其在实际应用中具有较高的可靠性和稳定性。本研究的创新点在于利用历史数据的多样性和丰富性,结合先进的机器学习技术,为天气预测提供了一种有效的解决方案,为相关领域的进一步研究和应用提供了参考依据。

二、研究背景与意义

全球气候变化的加剧和人类活动对环境的影响日益显著,天气预测的重要性愈加凸显。准确的天气预报不仅能够帮助人们合理安排生产和生活,还能够在极端天气事件如台风、暴雨、干旱等发生时,提供及时的预警,减少灾害造成的损失。传统的天气预报方法主要依赖于数值天气预报模型(NWP),这些模型基于物理方程和大气动力学原理,进行大规模的计算和模拟。然而,数值天气预报模型的精度受到多种因素的限制,包括初始条件的不确定性、模型的参数化方法以及计算资源的限制。

近年来,随着大数据技术和机器学习算法的迅速发展,基于历史数据的天气预测方法逐渐受到关注。通过利用大量的气象观测数据,机器学习算法能够从中提取出隐藏的模式和规律,为天气预测提供一种新的方法。相比传统的数值天气预报模型,基于历史数据的预测方法具有计算效率高、适应性强等优点,尤其在短期和中期天气预报中展现出很大的潜力。

本研究的目的在于开发一种基于历史数据的天气预测模型,通过分析多年的气象观测数据,利用数据驱动的方法提高天气预报的准确性和可靠性。具体而言,我们希望通过以下几方面实现研究目标:

  1. 数据整合与清洗:收集并整合多年来的气象观测数据,进行数据清洗和预处理,确保数据的完整性和一致性。
  2. 特征提取与选择:利用数据挖掘技术,从气象数据中提取出与天气变化密切相关的特征,为模型训练提供高质量的输入。
  3. 模型构建与优化:采用多种机器学习算法,包括线性回归、决策树、随机森林和深度神经网络,构建预测模型,并通过交叉验证和参数优化提高模型性能。
  4. 结果验证与评估:通过历史数据的回测和实际天气情况的比较,验证模型的预测效果,评估其在不同气象条件下的适用性和稳定性。

本研究具有重要的理论和实际意义。从理论上讲,探索基于历史数据的天气预测方法有助于丰富和发展天气预报领域的研究方法和技术手段;从实际应用的角度看,精准的天气预报能够为农业生产、交通运输、防灾减灾等领域提供重要的参考,具有广泛的社会和经济效益。通过本研究,我们希望为气象预测领域提供一种有效的解决方案,推动天气预报技术的发展和应用。

三、数据来源

天气预报网:http://www.tianqihoubao.com/

爬取了四组数据

第一组:2021年1月份-6月份北京市的天气预报 链接:http://www.tianqihoubao.com/lishi/beijing/month/202107.html

第二组:2021年1月份-6月份南宁市的天气预报 链接:http://www.tianqihoubao.com/lishi/nangning/month/202107.html

第三组:2021年1月份-6月份长春市的天气预报 链接:http://www.tianqihoubao.com/lishi/changchun/month/202107.html

第四组:2021年1月份-6月份广州市的天气预报 链接:http://www.tianqihoubao.com/lishi/guangzhou/month/202107.html

四、数据存储与预处理

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import pandas as pd
bj_df=pd.read_csv("../data/BJ.csv",encoding="gbk")
cc_df=pd.read_csv("../data/CC.csv",encoding="gbk")
gz_df=pd.read_csv("../data/GZ.csv",encoding="gbk")
nn_df=pd.read_csv("../data/NN.csv",encoding="gbk")

def deal(x):
# 重命名列
x.columns = ['日期', '天气情况', '气温', '风力']
x[['最低温', '最高温']] = x['气温'].str.split("/", expand=True)
x[['去初天气', '后来天气']] = x['天气情况'].str.split("/", expand=True)
# 去掉最低温和最高温列中多余的字符
x['最低温'] = x['最低温'].str.replace('℃', '')
x['最高温'] = x['最高温'].str.replace('℃', '')
# 将温度列转换为数值类型
x['最低温'] = pd.to_numeric(x['最低温'])
x['最高温'] = pd.to_numeric(x['最高温'])

# 将日期拆分为年、月、日
x[['年', '月', '日']] = bj_df['日期'].str.extract(r'(\d{4})年(\d{2})月(\d{2})日')
return x

bj_df=deal(bj_df)
cc_df=deal(cc_df)
gz_df=deal(gz_df)
nn_df=deal(nn_df)

bj_df.to_csv('../data/BJ2.csv',index=0,encoding='gbk')
cc_df.to_csv('../data/CC2.csv',index=0,encoding='gbk')
gz_df.to_csv('../data/GZ2.csv',index=0,encoding='gbk')
nn_df.to_csv('../data/NN2.csv',index=0,encoding='gbk')


这段代码主要完成了以下操作:

  1. 导入了Pandas库,并读取了四个CSV文件:’BJ.csv’, ‘CC.csv’, ‘GZ.csv’, ‘NN.csv’,使用GBK编码。
  2. 定义了一个名为deal的函数,用于处理数据框。这个函数的功能包括:
  • 重命名数据框的列为[‘日期’, ‘天气情况’, ‘气温’, ‘风力’]。
  • 将’气温’列按照”/“进行拆分,分成’最低温’和’最高温’两列。
  • 将’天气情况’列按照”/“进行拆分,分成’去初天气’和’后来天气’两列。
  • 去除’最低温’和’最高温’列中的’℃’字符。
  • 将’最低温’和’最高温’列转换为数值类型。
  • 将日期列拆分为’年’、’月’、’日’三列。
  • 最后返回处理后的数据框。
  1. 对四个数据框分别调用deal函数进行处理,并将处理后的结果重新赋值给相应的数据框bj_dfcc_dfgz_dfnn_df
  2. 将处理后的四个数据框分别写入新的CSV文件:’BJ2.csv’, ‘CC2.csv’, ‘GZ2.csv’, ‘NN2.csv’,并使用GBK编码。

总体来说,这段代码的主要作用是读取四个CSV文件,对每个文件进行特定的数据处理(包括重命名列、拆分列、数据清洗、类型转换等),然后将处理后的结果写入新的CSV文件中。

五、建立数据挖掘模型

聚类分析

代码部分


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import pandas as pd
import re
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import LabelEncoder

# 聚类分析结果
# 簇数:4
# 特征:最低温度、最高温度、天气情况(编码)

# Load the data
file_path = '../data/NN2.csv'
data = pd.read_csv(file_path, encoding='gbk')


data.columns = ['date', 'weather_condition', 'temperature', 'wind', 'min_temp', 'max_temp', 'initial_weather', 'future_weather', 'year', 'month', 'day']


def clean_encoding_issues(text):
text = re.sub(r'Äê', '年', text)
text = re.sub(r'ÔÂ', '月', text)
text = re.sub(r'ÈÕ', '日', text)
text = re.sub(r'¡æ', '℃', text)
text = re.sub(r'¶«±±·ç', '东北风', text)
text = re.sub(r'¼¶', '级', text)
text = re.sub(r'Çç', '阴', text)
text = re.sub(r'¶àÔÆ', '多云', text)
text = re.sub(r'Òõ', '晴', text)
return text


data['date'] = data['date'].apply(clean_encoding_issues)
data['weather_condition'] = data['weather_condition'].apply(clean_encoding_issues)
data['temperature'] = data['temperature'].apply(clean_encoding_issues)
data['wind'] = data['wind'].apply(clean_encoding_issues)
data['initial_weather'] = data['initial_weather'].apply(clean_encoding_issues)
data['future_weather'] = data['future_weather'].apply(clean_encoding_issues)


temp_split = data['temperature'].str.split('℃/', expand=True)
data['min_temp'] = temp_split[0].str.replace('℃', '').astype(float)
data['max_temp'] = temp_split[1].str.replace('℃', '').astype(float)


data['date'] = pd.to_datetime(data['date'], format='%Y年%m月%d日')


data.drop(columns=['temperature'], inplace=True)


le = LabelEncoder()
data['weather_condition_encoded'] = le.fit_transform(data['weather_condition'])
data['wind_encoded'] = le.fit_transform(data['wind'])
data['initial_weather_encoded'] = le.fit_transform(data['initial_weather'])
data['future_weather_encoded'] = le.fit_transform(data['future_weather'])


clustering_features = ['min_temp', 'max_temp', 'weather_condition_encoded']


X_clustering = data[clustering_features]


wcss = []
for i in range(1, 11):
kmeans = KMeans(n_clusters=i, random_state=42)
kmeans.fit(X_clustering)
wcss.append(kmeans.inertia_)


plt.figure(figsize=(10, 6))
plt.plot(range(1, 11, 1), wcss, marker='o', linestyle='-', markersize=5)
plt.title('Elbow Method for Optimal Number of Clusters')
plt.xlabel('Number of Clusters')
plt.ylabel('WCSS')
plt.show()


k_optimal = 4


kmeans_optimal = KMeans(n_clusters=k_optimal, random_state=42)
data['cluster'] = kmeans_optimal.fit_predict(X_clustering)


plt.figure(figsize=(12, 8))
sns.scatterplot(x='min_temp', y='max_temp', hue='cluster', data=data, palette='viridis', s=100)
plt.title('K-Means Clustering of Weather Data')
plt.xlabel('Minimum Temperature (°C)')
plt.ylabel('Maximum Temperature (°C)')
plt.legend(title='Cluster')
plt.show()

代码解释


  1. 导入所需的库,包括Pandas用于数据处理,re用于正则表达式处理,sklearn中的KMeans用于聚类分析,matplotlib.pyplot和seaborn用于数据可视化,以及LabelEncoder用于对分类变量进行编码。
  2. 从文件’NN2.csv’中加载数据,并对列名进行重命名,以处理可能存在的编码问题。
  3. 定义了一个函数clean_encoding_issues,用于清理文本中的编码问题,例如将一些特定编码转换为可读的文本。
  4. 对相关列应用clean_encoding_issues函数,清理数据中的编码问题。
  5. 将温度列拆分为最低温度和最高温度,并转换为浮点数类型。
  6. 将日期列转换为datetime格式,并丢弃原始的温度列。
  7. 使用LabelEncoder对分类变量进行编码,包括天气情况、风力等。
  8. 选择用于聚类的特征,包括最低温度、最高温度和编码后的天气情况。
  9. 使用肘部法则(elbow method)确定最佳聚类数,即通过循环尝试不同聚类数,计算每个聚类数下的WCSS(Within-Cluster Sum of Squares)并绘制肘部法则图。
  10. 根据肘部法则图选择最佳聚类数,这里假设最佳聚类数为4。
  11. 使用最佳聚类数对KMeans模型进行训练,并将每个样本分配到对应的簇中。
  12. 绘制聚类结果的散点图,展示最低温度和最高温度之间的关系,不同簇用不同颜色表示。

总体来说,这段代码实现了对天气数据进行聚类分析,包括数据清洗、特征选择、聚类模型训练和结果可视化。通过聚类分析,可以发现数据中的天气情况在最低温度和最高温度下的分布情况。

图片

image-20240619101801453

image-20240619101813912

六、可视化展示与分析

课题一

各城市风力等级分布时间环形图

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import pandas as pd
from pyecharts.charts import Pie
from pyecharts import options as opts
from pyecharts.charts import Timeline

# 读取CSV文件并准备数据
city_names = ["广州", "长春", "北京", "南宁"]
file_paths = ["GZ2.csv", "CC2.csv", "BJ2.csv", "NN2.csv"]

timelinedata = []
for city, file_path in zip(city_names, file_paths):
weather_data = pd.read_csv(file_path, encoding='GBK')
wind_counts = weather_data['风力'].value_counts()
data = [(wind, count) for wind, count in wind_counts.items()]
timelinedata.append((city, data))

# 创建时间轮播图
timeline = Timeline()
for city, data in timelinedata:
pie = (
Pie()
.add(
"",
data,
radius=["30%", "75%"],
center=["50%", "50%"],

)
.set_global_opts(title_opts=opts.TitleOpts(title=f"{city}风力等级分布" , pos_left="0%", pos_top="20%"))
# .set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
)
timeline.add(pie, city)

# 渲染为HTML文件
timeline.render("各个城市风力等级占比.html")

print("风力等级时间轮播图已生成并保存为 'wind_force_timeline_chart.html'")

可视化

图片链接

image-20240619084108475

总结

由风力等级分布时间环形图可以看出

广州大部分的时间都是1-2级的北风

南宁以南风、东南风、东北风为主

而长春和北京各种风错综复杂

课题二

各城市的天气变化率

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import pandas as pd
from pyecharts.charts import Line
from pyecharts.charts import Bar, Grid, Line, Page, Tab
from pyecharts import options as opts

def calculate_monthly_accuracy(data):
# 提取月份信息
data['月'] = pd.to_datetime(data['月'])

# 计算每个月的准确率
monthly_accuracy = data.groupby('月').apply(lambda x: (x['去初天气'] == x['后来天气']).sum() / len(x))

return monthly_accuracy.round(2)

def create_monthly_accuracy_chart(city_name, monthly_accuracy):
# 创建折线图
list_month = [str(i + 1) + "月" for i in range(len(monthly_accuracy.index.tolist()))]
# 创建一个 Grid 实例

line = (
Line()
.add_xaxis(list_month)
.add_yaxis("准确率", monthly_accuracy.tolist(), markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max")]))
.set_global_opts(
title_opts=opts.TitleOpts(title=f"{city_name}每月天气预报当天变化率"),
xaxis_opts=opts.AxisOpts(name="月份"),
yaxis_opts=opts.AxisOpts(name="准确率", min_=0, max_=1,is_show=False), # 设置 y 轴范围为 0 到 1
tooltip_opts=opts.TooltipOpts(trigger="axis", axis_pointer_type="cross"), # 设置 tooltip 样式
)
)
tab.add(line,f"{city_name}每月天气预报当天变化率")


# 城市名称和文件路径
city_names = ["广州", "长春", "北京", "南宁"]
file_paths = ["GZ2.csv", "CC2.csv", "BJ2.csv", "NN2.csv"]
# 创建一个 Grid 实例,并将多个图表添加到 Grid 中
grid = Grid()
tab = Tab()
# 针对每个城市生成准确率图表
for city_name, file_path in zip(city_names, file_paths):
# 读取天气数据
weather_data = pd.read_csv(file_path, encoding="GBK")

# 计算每个月的准确率
monthly_accuracy = calculate_monthly_accuracy(weather_data)

# 创建并保存每月准确率变化的折线图
create_monthly_accuracy_chart(city_name, monthly_accuracy)


# # 创建每个城市的折线图
# line = create_monthly_accuracy_chart(city_name, monthly_accuracy)

# # 将每个折线图添加到 Grid 中
# grid.add(line, grid_opts=opts.GridOpts(pos_top=f"{(city_names.index(city_name) * 25) + 5}%")) # 每个图表在适当的位置


# 渲染图表为 HTML 文件
tab.render("各个城市的天气变化率.html")

可视化

图片链接

image-20240619102958081

image-20240619103033175

总结

由该天气变化率组合图可以看出

广州在3月份的天气变化无常,6月份的天气相对稳定

长春整体天气变化情况都比较稳定,没有太大的浮动

北京在6月份的天气变化无常,3月份的天气相对稳定

南宁天气上下波动,成心率变化

课题三

各城市每月带有雨的天气情况占比时间环形图

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import pandas as pd
from pyecharts.charts import Pie, Timeline
from pyecharts import options as opts

def calculate_rainy_days_percentage(data):
# 提取月份信息
data['日期'] = data['日期'].apply(lambda x: x.replace("年", "-").replace("月", "-").replace("日", "")) # 将日期字符串格式转换为 "YYYY-MM-DD" 形式
data['日期'] = pd.to_datetime(data['日期'])

data['月'] = data['日期'].dt.month_name()

# 中文月份
month_map = {
'January': '一月',
'February': '二月',
'March': '三月',
'April': '四月',
'May': '五月',
'June': '六月',
'July': '七月',
'August': '八月',
'September': '九月',
'October': '十月',
'November': '十一月',
'December': '十二月'
}
data['月'] = data['月'].map(month_map)

# 计算每个月带有雨的天气情况的占比
monthly_rainy_days_percentage = (
data[data['天气情况'].str.contains('雨')].groupby('月').size() / data.groupby('月').size()
).round(2)

return monthly_rainy_days_percentage

def create_rainy_days_pie_chart(city_name, monthly_rainy_days_percentage):
# 创建饼图
pie = (
Pie()
.add(
"",
[list(z) for z in zip(monthly_rainy_days_percentage.index, monthly_rainy_days_percentage)],
radius=["40%", "75%"],
center=["50%", "50%"], # 设置图表居中
)
.set_global_opts(title_opts=opts.TitleOpts(title=f"{city_name}每月带有雨的天气情况占比", pos_left="left"))
.set_series_opts(label_opts=opts.LabelOpts(formatter="{b}: {d}%"))
)

return pie

# 读取天气数据
city_names = ["广州", "长春", "北京", "南宁"]
file_paths = ["GZ2.csv", "CC2.csv", "BJ2.csv", "NN2.csv"]

# 创建时间轮播图
timeline = Timeline()

for city_name, file_path in zip(city_names, file_paths):
# 读取天气数据
weather_data = pd.read_csv(file_path, encoding="GBK")

# 计算每个月带有雨的天气情况的占比
monthly_rainy_days_percentage = calculate_rainy_days_percentage(weather_data)

# 创建饼图
pie = create_rainy_days_pie_chart(city_name, monthly_rainy_days_percentage)

# 添加到时间轮播图中
timeline.add(pie, city_name)

# 渲染图表为 HTML 文件
timeline.render("各个城市每月雨天占比情况.html")

可视化

图片链接

image-20240619103425148

总结

由该雨天时间轮播图可以看出

各城市的雨季都集中在6月份

各城市的旱季都集中在2月份

课题四

各个城市的天气最低最高温情况

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import pandas as pd
from pyecharts.charts import Bar, Grid, Line, Page, Tab
from pyecharts import options as opts

def create_weather_chart(city_name, weather_data):
# 创建图表
line = Line()

# 添加 X 轴数据(日期)
line.add_xaxis(weather_data['日期'].tolist())

# 添加 Y 轴数据(最低温度和最高温度)
line.add_yaxis("最低温度 (℃)", weather_data['最低温'].tolist(),
label_opts=opts.LabelOpts(is_show=False), # 隐藏每个点的标签
itemstyle_opts=opts.ItemStyleOpts(color="blue")) # 设置折线的颜色
line.add_yaxis("最高温度 (℃)", weather_data['最高温'].tolist(),
label_opts=opts.LabelOpts(is_show=False), # 隐藏每个点的标签
itemstyle_opts=opts.ItemStyleOpts(color="red")) # 设置折线的颜色

# 设置图表标题和其他选项
line.set_global_opts(

title_opts=opts.TitleOpts(title=f"{city_name} 天气数据"),
tooltip_opts=opts.TooltipOpts(trigger="axis"),
xaxis_opts=opts.AxisOpts(type_="category"),
yaxis_opts=opts.AxisOpts(type_="value", axislabel_opts=opts.LabelOpts(formatter="{value} ℃")),
)

tab.add(line,f"{city_name} 天气数据")



# 读取多个城市的天气数据
city_names = ["广州", "长春", "北京", "南宁"] # 替换为你的城市名称
file_paths = ["GZ2.csv", "CC2.csv", "BJ2.csv", "NN2.csv"] # 替换为你的文件路径
tab = Tab()
for city_name, file_path in zip(city_names, file_paths):
# 读取 CSV 文件
weather_data = pd.read_csv(file_path,encoding="GBK")

# 创建并保存图表
create_weather_chart(city_name, weather_data)

# 渲染图表为 HTML 文件
tab.render("各个城市的气温变化.html")

可视化

图片链接

image-20240619105059705

总结

由图可以看出

广州天气整体偏热 最高气温大部分大于20摄氏度
长春天气在13月天气低至零下 在4月份的时候才开始回暖
北京天气在1
3月天气也低至零下 但是相对长春 温度整体较高 整个折线图呈较明显的上升趋势
南宁天气起伏不定 部分天数出现较大起伏 可能出现前一天与后一天温差在10摄氏度的情况