天气数据集爬取
爬取思路:
-
确定目标(目标网站:大同历史天气预报 2020年5月份)
-
请求网页(第三方库 requests)
-
解析网页(数据提取)
-
保存数据(这里以 .csv 格式存储到本地)
import requests
from bs4 import BeautifulSoup
import pandas as pd
def get_data (url) :
# 请求网页(第三方 requests)
resp = requests.get(url)
# 对于获取到的 HTML 二进制文件进行 'gbk' 转码成字符串文件
html = resp.content.decode( 'gbk' )
# 通过第三方库 BeautifulSoup 缩小查找范围(同样作用的包库还有re模块、xpath等)
soup = BeautifulSoup(html, 'html.parser' )
# 获取 HTML 中所有<tr>…</tr>标签,因为我们需要的数据全部在此标签中存放
tr_list = soup.find_all( 'tr' )
# 初始化日期dates、气候contains、温度temp值
dates,contains,temp = [],[],[]
for data in tr_list[ 1 :]: # 不要表头
# 数据值拆分,方便进一步处理(这里可以将获得的列表输出[已注释],不理解的读者可运行查看)
sub_data = data.text.split()
# print(sub_data)
# 观察上一步获得的列表,这里只想要获得列表中第二个和第三个值,采用切片法获取
dates.append(sub_data[ 0 ])
contains.append( ',' .join(sub_data[ 1 : 3 ]))
# print(contains)
# 同理采用切片方式获取列表中的最高、最低气温
temp.append( ',' .join(sub_data[ 3 : 6 ]))
# print(temp)
# 使用 _data 表存放日期、天气状况、气温表头及其值
_data = pd.DataFrame()
# 分别将对应值传入 _data 表中
_data[ '日期' ] = dates
_data[ '天气状况' ] = contains
_data[ '气温' ] = temp
return _data
# 爬取目标网页(大同市2020年5月份天气[网站:天气后报])
data_5_month = get_data( 'http://www.tianqihoubao.com/lishi/datong/month/202005.html' )
# 拼接所有表并重新设置行索引(若不进行此步操作,可能或出现多个标签相同的值)
data = pd.concat([data_5_month]).reset_index(drop = True )
# 将 _data 表以 .csv 格式存入指定文件夹中,并设置转码格式防止乱花(注:此转码格式可与 HTML 二进制转字符串的转码格式不同)
data.to_csv( 'F:/DaTong5Mouth.csv' ,encoding= 'utf-8' )
数据可视化
数据可视化用到了可视化工具。
其要点包含有:读取数据、数据清洗、数据处理、可视化工具的使用。
# 数据可视化
from matplotlib import pyplot as plt
import pandas as pd
# 解决显示中文问题
plt.rcParams[ 'font.sans-serif' ] = [ 'SimHei' ]
# 第一步:数据读取
data = pd.read_csv( 'F:/DaTong5Mouth.csv' )
# 第二步:数据处理(由于我们知道文本内容,不存在脏数据,故忽略数据清理步骤)
data[ '最高气温' ] = data[ '气温' ].str.split( '/' ,expand= True )[ 0 ]
data[ '最低气温' ] = data[ '气温' ].str.split( '/' ,expand= True )[ 1 ]
data[ '最高气温' ] = data[ '最高气温' ].map( lambda x:x.replace( '℃,' , '' ))
data[ '最低气温' ] = data[ '最低气温' ].map( lambda x:x.replace( '℃,' , '' ))
dates = data[ '日期' ]
highs = data[ '最高气温' ]
lows = data[ '最低气温' ]
# 画图(折线图)
# 设置画布大小及比例
fig = plt.figure(dpi= 128 ,figsize=( 10 , 6 ))
# 设置最高温最低温线条颜色及宽度等信息
L1,=plt.plot(dates,lows,label= '最低气温' )
L2,=plt.plot(dates,highs,label= '最高气温' )
plt.legend(handles=[L1,L2],labels=[ '最高气温' , '最低气温' ], loc= 'best' ) # 添加图例
# 图表格式
# 设置图形格式
plt.title( '2020年5月上旬大同天气' ,fontsize= 25 ) # 字体大小设置为25
plt.xlabel( '日期' ,fontsize= 10 ) # x轴显示“日期”,字体大小设置为10
fig.autofmt_xdate() # 绘制斜的日期标签,避免重叠
plt.ylabel( '气温' ,fontsize= 10 ) # y轴显示“气温”,字体大小设置为10
plt.tick_params(axis= 'both' ,which= 'major' ,labelsize= 10 )
# plt.plot(highs,lows,label = '最高气温')
# 修改刻度
plt.xticks(dates[:: 1 ]) # 由于数据不多,将每天的数据全部显示出来
# 显示折线图
plt.show()
模型预测数据
1、单变量线性回归
模型一:单变量线性回归模型
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# 解决中文问题(若没有此步骤,表名字及横纵坐标中的汉语将无法显示[具体会显示矩形小方格])
plt.rcParams[ 'font.sans-serif' ] = [ 'SimHei' ]
# 将数据从上一步存入的 .csv 格式文件中读取
data = pd.read_csv( r'F:\DaTong5Mouth.csv' )
# 由于最高气温与最低气温中有 / 分隔,故将其分开,即“气温”列由一列变为两列——“最高气温”和“最低气温”
data[ '最高气温' ] = data[ '气温' ].str.split( '/' ,expand= True )[ 0 ]
# 我们要对数值进行分析,所以将多余的单位 ℃ 从列表中去掉,只保留数值部分
data[ '最高气温' ] = data[ '最高气温' ].map( lambda x:x.replace( '℃,' , '' ))
# 日次操作同理,这里不再赘述
data[ '日期' ] = data[ '日期' ].map( lambda x:x.replace( '2020年05月0' , '' ))
data[ '日期' ] = data[ '日期' ].map( lambda x:x.replace( '日' , '' ))
# 不理解的小伙伴可运行下两行代码查看运行结果(这里先注释掉了)
# print(data['日期'])
# print(data['最高气温'])
def initPlot () :
# 先准备好一块画布
plt.figure()
# 生成图表的名字
plt.title( '2020年5月上旬大同天气' )
# 横坐标名字
plt.xlabel( '日期' )
# 纵坐标名字
plt.ylabel( '当日最高气温' )
# 表内有栅格(不想要栅格把此行注释掉即可)
plt.grid( True )
return plt
plt = initPlot() # 画图
# 传入对应日期及其最高气温参数
xTrain = np.array([ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ])
yTrain = np.array([ 33 , 35 , 28 , 20 , 26 , 27 , 23 , 22 , 22 ])
# k是黑色,.是以点作为图上显示
plt.plot(xTrain, yTrain, 'k.' )
# 将图显示出来
plt.show()
可以看到:
-
最高气温随着日期的变化,大致呈现线性变化(最近气温下降);
-
如果根据现有的训练数据能够拟合出一条直线,使之与这些训练数据的各点都比较接近,那么根据该直线,就可以计算出在10号或者11号的温度情况(气温受到影响因素较多,故这里仅预测为数不多的数据)。
解决方案:
-
采用Python scikit-learn库中提供的sklearn.linear_model.LinearRegression对象来进行线性拟合。
-
根据判别函数,绘制拟合直线,并同时显示训练数据点。
-
拟合的直线较好的穿过训练数据,根据新拟合的直线,可以方便的求出最近日期下对应的最高气温(预测结果)。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# 解决中文问题(若没有此步骤,表名字及横纵坐标中的汉语将无法显示[具体会显示矩形小方格])
plt.rcParams[ 'font.sans-serif' ] = [ 'SimHei' ]
# 将数据从上一步存入的 .csv 格式文件中读取
data = pd.read_csv( r'F:\DaTong5Mouth.csv' )
# 由于最高气温与最低气温中有 / 分隔,故将其分开,即“气温”列由一列变为两列——“最高气温”和“最低气温”
data[ '最高气温' ] = data[ '气温' ].str.split( '/' ,expand= True )[ 0 ]
# 我们要对数值进行分析,所以将多余的单位 ℃ 从列表中去掉,只保留数值部分
data[ '最高气温' ] = data[ '最高气温' ].map( lambda x:x.replace( '℃,' , '' ))
# 日次操作同理,这里不再赘述
data[ '日期' ] = data[ '日期' ].map( lambda x:x.replace( '2020年05月0' , '' ))
data[ '日期' ] = data[ '日期' ].map( lambda x:x.replace( '日' , '' ))
# 不理解的小伙伴可运行下两行代码查看运行结果(这里先注释掉了)
# print(data['日期'])
# print(data['最高气温'])
# 传入对应日期及其最高气温参数
# # 应以矩阵形式表达(对于单变量,矩阵就是列向量形式)
xTrain = np.array([ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ])[:, np.newaxis]
# 为方便理解,也转换成列向量
yTrain = np.array([ 33 , 35 , 28 , 20 , 26 , 27 , 23 , 22 , 22 ])
# 创建模型对象
model = LinearRegression()
# 根据训练数据拟合出直线(以得到假设函数)
hypothesis = model.fit(xTrain, yTrain)
# 截距
print( "theta0=" , hypothesis.intercept_)
# 斜率
print( "theta1=" , hypothesis.coef_)
# 预测2020年5月10日的最高气温
print( "预测2020年5月10日的最高气温:" , model.predict([[ 10 ]]))
# 也可以批量预测多个日期的气温,注意要以列向量形式表达(有余数据集量少,故间隔时间长气温可能有较大差异)
# 此处仅利用模型表示,不代表真实值(假设要预测10号、11号、12号的天气)
xNew = np.array([ 0 , 10 , 11 , 12 ])[:, np.newaxis]
yNew = model.predict(xNew)
print( "预测新数据:" , xNew)
print( "预测结果:" , yNew)
def initPlot () :
# 先准备好一块画布
plt.figure()
# 生成图表的名字
plt.title( '2020年5月上旬大同天气' )
# 横坐标名字
plt.xlabel( '日期' )
# 纵坐标名字
plt.ylabel( '当日最高气温' )<