本文共 7383 字,大约阅读时间需要 24 分钟。
代码已在本人设备上完美的跑过了,如果在一些读者的电脑上有问题,大家可以检查如下东西:1. 代码是否拼接在一起,因为实在jupyter上写的,因此我这里不需要刻意拼接大家可以将代码糅合在一起。2. torch版本和anconda版本的问题,可能有部分函数或者方法不兼容。3. matplotlib版本问题,在之前的某次版本更新后,pyplot的部分方法 改变了。4. 文件的读取形式,我的csv文件的存储形式为ANSI,因此使用UTF-8的 编码可能会报错。
该文章包含了从爬取数据到训练模型预测数据画图的整个过程,莫 白 嫖。。。。。。。。
数据网址:
因为需要大量的数据,所以需要爬取k个网页的数据,因此,包含了几个url,该url只是第一个罢了,具体的情况可以在代码中看到。#依靠网络爬虫获取数据import requestsfrom bs4 import BeautifulSoupimport csvimport redef get_html(url): header={ 'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 'Accept-Encoding':'gzip, deflate', 'Accept-Language':'zh-CN,zh;q=0.9', 'Connection':'keep-alive', 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36', } rep=requests.get(url,headers=header,timeout=random.choice(range(50,80))).coding='utf-8' return rep.textdef get_data(html): bs=BeautifulSoup(html,'html.parser') text_list=[] li=bs.find('ul',class_='thrui').find_all('li') for line in li: text_list.append(line.text.replace('\n','').split(' ')) return text_listdef solve_list(data): data.insert(2,re.compile(r'\d+') .findall(data[2])[0]) data.insert(3,re.compile(r'\d+') .findall(data[3])[1]) data.pop(1) data=data[:3] return datadef write_in_csv(filename,data): with open(filename,"a",newline='') as filewrite: for line in data: csv.writer(filewrite).writerow(line)def __Main__(): data=[] with open('weather.csv','w',newline='') as filewrite: csv.writer(filewrite).writerow(['time','min','max']) for y in range(11,21): for m in range(1,13): if m<10: url='http://lishi.tianqi.com/xian/20'+str(y)+'0'+str(m)+'.html' else: url=url='http://lishi.tianqi.com/xian/20'+str(y)+str(m)+'.html' print(url,'爬取完成') for i in get_data(get_html(url)): data.append(solve_list(i)) write_in_csv('weather.csv',data) print('写入完成')__Main__()
这里将数据爬取和数据处理放在同一个py文件中,是为了到时候,用数据时不需要太多的处理,这里注意我的桌面位置是E盘。
最小温度数据预测
# -*- coding: utf-8 -*-import numpy as npimport pandas as pd import matplotlib.pyplot as pltimport timeimport torchfrom torch.autograd import Variableimport torch.nn as nnimport datetimedef get_dataset(dataset,look_back): data_x=data_y= [] for i in range(len(dataset)-look_back): data_x.append(dataset[i:i+look_back]) data_y.append(dataset[i+look_back]) return np.asarray(data_x), np.asarray(data_y) #转为ndarray数据class RNN(nn.Module): def __init__(self): super(RNN,self).__init__() #面向对象 self.lstm = nn.LSTM(2,6,2) #输入:2个特征6个隐藏层,2个LSTM串联 self.out = nn.Linear(6,1) #接受6维,输出1维,承接上面一行代码 def forward(self,x): x1,_ = self.lstm(x) a,b,c = x1.shape out = self.out(x1.view(-1,c)) out1 = out.view(a,b,-1) return out1#实例化一个RNNrnn = RNN()#加载数据file='E:\\桌面\\jupyter_notebook\\weather.csv'data=pd.read_csv(file,encoding='ANSI')#检查数据print('数据维度:', data.shape)datas_min=data['min'].valuesdatas_min=np.array([[m] for m in data['min']])max_datas_min,min_datas_min=np.max(datas_min),np.min(datas_min)#这里归一化并没有必要,当然这里归一化可以处理的更快,但是会丢失一些精度,在本身就丢失了一些精度的训练情况下,我想尽可能的提高精度。#datas_min=list(map(lambda x:(x-min_datas_min)/(max_datas_min-min_datas_min),datas_min))data_min_X,data_min_Y=creat_dataset(datas_min,2)x_min_train=torch.from_numpy(data_min_X[:2500].reshape(-1, 1, 2))#这里通过reshape转化维度,成为我们可以利用的数据y_min_train=torch.from_numpy(data_min_Y[:2500] .reshape(-1, 1, 1) )#optim优化算法 构造一个优化器 指定优化对象optimizer=torch.optim.Adam(rnn.parameters(),lr = 0.02)#这里选择训练一千轮是因为我发现在九百到一千轮的,损失已经很难在降低了。for i in range(1000): var_x=Variable(x_min_train).type(torch.FloatTensor) var_y=Variable(y_min_train).type(torch.FloatTensor) out =rnn(var_x) loss=nn.MSELoss()(out,var_y) optimizer.zero_grad() loss.backward() optimizer.step() if (i+1)%100==0: print('次数:{}, 损失:{:.5f}'.format(i+1, loss.item()))#获取测试集数据 并转化类型var_dataX=Variable(torch.from_numpy(data_min_X.reshape(-1,1,2))).type(torch.FloatTensor)#训练模型pred=rnn(var_dataX)print(pred)
# -*- coding: utf-8 -*-import numpy as npimport pandas as pd import matplotlib.pyplot as pltimport timeimport torchfrom torch.autograd import Variableimport torch.nn as nnimport datetimedef creat_dataset(dataset,look_back): data_x = [] data_y = [] for i in range(len(dataset)-look_back): data_x.append(dataset[i:i+look_back]) data_y.append(dataset[i+look_back]) return np.asarray(data_x), np.asarray(data_y) #转为ndarray数据class RNN(nn.Module): def __init__(self): super(RNN,self).__init__() #面向对象中的继承 self.lstm = nn.LSTM(2,6,2) #输入数据2个特征维度,5个隐藏层维度,2个LSTM串联,第二个LSTM接收第一个的计算结果 self.out = nn.Linear(6,1) #线性拟合,接收数据的维度为6,输出数据的维度为1 def forward(self,x): x1,_ = self.lstm(x) a,b,c = x1.shape out = self.out(x1.view(-1,c)) #因为线性层输入的是个二维数据,所以此处应该将lstm输出的三维数据x1调整成二维数据,最后的特征维度不能变 out1 = out.view(a,b,-1) #因为是循环神经网络,最后的时候要把二维的out调整成三维数据,下一次循环使用 return out1#加载数据file='E:\\桌面\\jupyter_notebook\\weather.csv'data=pd.read_csv(file,encoding='ANSI')#检查数据print('数据维度:', data.shape)datas_min=data['max'].valuesdatas_min=np.array([[m] for m in data['max']])max_datas_min,min_datas_min=np.max(datas_min),np.min(datas_min)#做归一化处理#datas_min=list(map(lambda x:(x-min_datas_min)/(max_datas_min-min_datas_min),datas_min))#print(datas_min)data_min_X,data_min_Y=creat_dataset(datas_min,2)x_min_train=data_min_X[:2500]y_min_train=data_min_Y[:2500] x_min_train=x_min_train.reshape(-1, 1, 2) y_min_train=y_min_train.reshape(-1, 1, 1) x_min_train=torch.from_numpy(x_min_train)y_min_train=torch.from_numpy(y_min_train)rnn = RNN()#计算损失函数optimizer = torch.optim.Adam(rnn.parameters(),lr = 0.02)loss_func = nn.MSELoss()for i in range(1000): var_x = Variable(x_min_train).type(torch.FloatTensor) var_y = Variable(y_min_train).type(torch.FloatTensor) out = rnn(var_x) loss = loss_func(out,var_y) optimizer.zero_grad() loss.backward() optimizer.step() if (i+1)%100==0: print('次数:{}, 损失:{:.5f}'.format(i+1, loss.item()))data_min_X1=data_min_X.reshape(-1,1,2)data_min_X2=torch.from_numpy(data_min_X1)var_dataX=Variable(data_min_X2).type(torch.FloatTensor)pred=rnn(var_dataX)print(pred)
代码所预测的是每日的最高温和最低温,平均温度的问题很好解决。这里不多做赘述。
利用matplotlib绘图
绘图的代码给个最低温就可以了,最低温只需要改几个词就可以了。
import matplotlib.dates as mdatespred_test=pred.view(-1).data.numpy()data_times=[datetime.datetime.strptime(time,'%Y-%m-%d') for time in data['time'] ]#data_min_Y为实值 预测值为pred[:-2] 时间为plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签plt.rcParams['axes.unicode_minus']=False #用来正常显示负号plt.figure(figsize=(30,30))plt.xlabel('日期')plt.ylabel('温度/℃')plt.title('西安市日最低温度预测曲线')plt.plot(data_times[:-2],pred.view(-1).data.numpy(), 'r',color='red', label='预测')plt.plot(data_times[:-2],data_min_Y, 'b',color='yellow', label='实值')#添加标签plt.legend(loc='best')
结果:
转载地址:http://gzcki.baihongyu.com/