资讯详情

记录自己使用循环神经网络对天气进行预测的过程

本实验中使用的数据来自链接: http://www.tianqihoubao.com/lishi/,选定的城市是广西客人,将使用2011-2021年的数据。机器学习的框架是tensorflow2.3.0。 在这里插入图片描述

1.数据爬取

首先,我们必须在这里抓取数据并使用它python爬虫中最常见的requests库和BeautifulSoup库,以下是数据爬取craw.py

import requests from bs4 import BeautifulSoup import numpy as np import pandas as pd import re   def data_list(numpy):     z = []     for i in numpy:         if i.string is not None:             z.append(i.string)     for m, n in enumerate(z):         z[m] = n.replace('\n', '').replace(' ', '')     return z   class Grab:     def __init__(self, url):         self.url = url         self.header = { 
        'User-Agent': r'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, '                                      r'like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32'}      def analysis(self):         for i in range(3):             try:                 resp = requests.get(url=self.url, headers=self.header,                                    proxies=None, timeout=(3, 7))
                if resp.status_code == 200:
                    break
            except:
                print('请求超时!')
        resp.encoding = 'gbk'
        html = BeautifulSoup(resp.text, 'html5lib')
        return html

    def location(self, str1):
        text = self.analysis()
        data = text.find_all(str1)
        return data

    def data(self):
        data = self.location('td')
        data = data_list(data)
        data = np.array(data).reshape(-1, 3)
        data_date = self.date()
        data = np.c_[data_date, data]
        print(data)
        return data

    def date(self):
        date = self.location('a')
        date = data_list(date)
        data_str = ''.join(date)
        date = re.findall(r'\d\d\d\d年\d\d月\d\d日', data_str)
        return date


if __name__ == "__main__":
    flag = 0
    for i in range(2011, 2021 + 1):
        for j in range(1, 13):
            ur = r'http://www.tianqihoubao.com/lishi/laibin/month/{}{:0>2}.html'.format(i, j)
            a = Grab(ur)
            b = a.data()
            if flag == 0:
                weather = b.copy()
                flag += 1
            else:
                weather = np.r_[weather, b]
            if i == 2022:
                if j == 5:
                    break
    c = ['日期', '天气', '气温', '风力风向']
    df = pd.DataFrame(data=weather, columns=c)
    df.to_csv('data.csv', header=True, index=False, encoding='gbk')

下面说一下思路: 这个网站对于每一个月的数据都会做成一个网页,而且格式也是固定的形式,这样我们只需要两个for循环就能得到所有想要的网页网址

for i in range(2011, 2021 + 1):
        for j in range(1, 13):
            ur = r'http://www.tianqihoubao.com/lishi/laibin/month/{}{:0>2}.html'.format(i, j)

format是格式化输入,用于控制输入的年份和月份,由于有些月份前面会带一个0,所以这里使用了{:0>2}来让每个数字都左对齐两位。 下面进入到Grab类,初始化从循环中得到的网址和请求头。

 def __init__(self, url):
        self.url = url
        self.header = { 
        'User-Agent': r'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, '
                                     r'like Gecko) Chrome/101.0.4951.41 Safari/537.36 Edg/101.0.1210.32'}

请求头可以去百度一下常用的即可。 接下来就是请求访问了,调用requests库中的get方法(),get中timeout=(3,7)表示连接时间为3,响应时间为7,使用得当可以提高访问速度,节省时间。resp.status_code根据自己实际访问的网页来填写,编码使用汉字最常见的gbk,最终再使用BeautifulSoup根据html5lib格式来解析即可得到一个类似其实就是 json格式的文本。

    def analysis(self):
        for i in range(3):
            try:
                resp = requests.get(url=self.url, headers=self.header,
                                    proxies=None, timeout=(3, 7))
                if resp.status_code == 200:
                    break
            except:
                print('请求超时!')
        resp.encoding = 'gbk'
        html = BeautifulSoup(resp.text, 'html5lib')
        return html

将得到的文本复制到记事本里分析一下 想要的数据的标签都在td里,但是时间轴却在a里。那我们先对数据动手,为了方便下面多次访问不同的标签,写了一个可以多次调用的访问函数

    def location(self, str1):
        text = self.analysis()
        data = text.find_all(str1)
        return data

下面寻找td标签下的所有数据

    def data(self):
        data = self.location('td')
        data = data_list(data)
        data = np.array(data).reshape(-1, 3)
        data_date = self.date()
        data = np.c_[data_date, data]
        print(data)
        return data

这里还调用了一个data_list函数,是为了把所有的数据字符串提取出并且去掉空内容和换行符。这样我们会得到一个装了所有数据的列表,由于每个样本的数据都是3列,这里直接就可以创建一个数组再重新塑形就能得到想要的样子: 还得想办法把日期也放进去,因此创建了一个date函数来将日期抓取下来:

 def date(self):
        date = self.location('a')
        date = data_list(date)
        data_str = ''.join(date)
        date = re.findall(r'\d\d\d\d年\d\d月\d\d日', data_str)
        return date

同样的也是也先调用访问函数,然后再调用data_list函数得到一个装满时间数据的列表,和气象数据不同的是还有很多不需要的数据: 这里我的做法是使用join将列表中的字符串拼接成一个字符串,再使用re库中的findall函数正则匹配\d\d\d\d年\d\d月\d\d日型的字符串,这样就能将这个月的时间都装进一个列表了(其实这里的时间有一个更明确的标签<a href="/lishi/laibin/20110101.html" title="2011年01月01日来宾天气预报">如果使用for加格式化输入遍历应该也能得到,但是我嫌还要处理不同的2月天数就放弃了 ): 然后再看回data函数,直接使用c_将气象数据和天气数据合在一起,最终就将一个月的数据得到了: 至此主函数中的a = Grab(ur) b = a.data()也执行完毕,下面就是将每个月的数组纵向拼接在一起,最终创建一个datafarme将其保持为csv文件方便后续的使用。

2.数据预处理

基本没有什么周期性,就用天气,温度和风向风级来预测好像确实会有一点点离谱,而且该数据的风向风级在2017年之前几乎都是北风小于等于3级。 用于数据预处理的data.py 由于数据量的大小,所以觉得并不需要用生成器。

import numpy as np
import pandas as pd
from collections import Counter
import matplotlib.pyplot as plt
import re


def Get_label_dict(y):
    dict_l = { 
        }
    for i, j in enumerate(y):
        dict_l[j] = i
    return dict_l


def F(matrix, num):
    results = np.zeros((len(matrix), num))
    for i, j in enumerate(matrix):
        results[i, j] = 1
    return results


def load_data(data_dir):
    weather_data = Weather(data_dir).pre()
    data = (weather_data.loc[:, ['白天天气', '夜间天气', '最高温度', '最低温度', '白天风力风向', '夜间风力风向', '白天风级', '夜间风级']]).to_numpy()
    label = weather_data['白天天气'].to_numpy()
    train = data[:1].reshape(-1, 1, data.shape[-1])
    train_label = label[1]
    for i in range(2, data.shape[0], 2):
        index = i + 1
        if index >= data.shape[0]:
            break
        else:
            train = np.r_[train, data[i:index].reshape(-1, 1, data.shape[-1])]
            train_label = np.r_[train_label, label[index]]

    train_label = F(train_label, 13).astype('float32')

    # mean = np.mean(train, axis=0)
    # std = np.std(train, axis=0)
    # train = (train - mean) / std

    return train, train_label


class Weather:
    def __init__(self, file_dir):
        self.data = pd.read_csv(file_dir, encoding='gbk')

    def pre(self):
        col = ['天气', '气温', '风力风向']
        list_col = ['白天天气', '夜间天气', '最高温度', '最低温度', '白天风力风向', '夜间风力风向', '白天风级', '夜间风级']
        q = 0
        for i, j in enumerate(col):
            new_data = self.data[j].str.split('/', 1, True)
            new_data.columns = [list_col[q], list_col[q + 1]]
            q += 2
            self.data = self.data.drop([j], axis=1).join(new_data)

        self.data['日期'] = self.data['日期'].apply(lambda x: x.replace('年', '-').replace('月', '-').replace('日', ''))
        self.data['日期'] = pd.to_datetime(self.data['日期'])

        self.data['最高温度'] = self.data['最高温度'].apply(lambda x: int(x.replace('℃', '')))
        self.data['最低温度'] = self.data['最低温度'].apply(lambda x: int(x.replace('℃', '')))

        weather_c = Counter(self.data['白天天气'])
        weather_dict = Get_label_dict(weather_c)
        self.data['白天天气'] = self.data['白天天气'].apply(lambda x: weather_dict[x])
        self.data['夜间天气'] = self.data['夜间天气'].apply(lambda x: weather_dict[x])

        self.data['白天风力风向'] = self.data['白天风力风向'].str.replace('微风', '3级')

        self.data['白天风级'] = self.data['白天风力风向'].apply(lambda x: x.replace(re.findall('[\u4e00-\u9fa5]+', x)[0], ''))
        wind_level_c = Counter(self.data['白天风级'])
        wind_level_dict = Get_label_dict(wind_level_c)
        self.data['白天风级'] = self.data['白天风级'].apply(lambda x: wind_level_dict[x])

        self.data['白天风力风向'] = self.data['白天风力风向'].apply(lambda x: re.findall('[\u4e00-\u9fa5]+', x)[0])
        wind_direction_c = Counter(self.data['白天风力风向'])
        wind_direction_dict = Get_label_dict(wind_direction_c)
        self.data['白天风力风向'] = self.data['白天风力风向'].apply(lambda x: wind_direction_dict[x])

        self.data['夜间风力风向'] = self.data['夜间风力风向'].str.replace('微风', '3级')

        self.data['夜间风级'] = self.data['夜间风力风向'].apply(lambda x: x.replace(re.findall('[\u4e00-\u9fa5]+', x)[0], ''))
        wind_level_c = Counter(self.data['夜间风级'])
        wind_level_dict = Get_label_dict(wind_level_c)
        self.data['夜间风级'] = self.data['夜间风级'].apply(lambda x: wind_level_dict[x])

        self.data['夜间风力风向'] = self.data['夜间风力风向'].apply(lambda x: re.findall('[\u4e00-\u9fa5]+', x)[0])
        wind_direction_c = Counter(self.data['夜间风力风向'])
        wind_direction_dict = Get_label_dict(wind_direction_c)
        self.data['夜间风力风向'] = self.data['夜间风力风向'].apply(lambda x: wind_direction_dict[x])

        df = self.data

        return df

    # def str_vector(self):
    # wind = self.pre()['白天风力风向'].to_list()
    # wind_str = []
    # wind_str_dict = {}
    # data_str = []
    # for i, j in enumerate(wind):
    # medium = []
    # medium.extend(j)
    # wind_str.extend(j)
    # data_str.append(medium)
    # wind_str = set(wind_str)
    # for m, n in enumerate(wind_str):
    # wind_str_dict[n] = m
    # result = np.zeros((4022, 40))
    # for z, x in enumerate(data_str):
    # for v in x:
    # result[z, wind_str_dict[v]] = 1
    # return result

我们先将白天夜间天气,风向风级以及最高最低温度分开来:

    def pre(self):
        col = ['天气', '气温', '风力风向']
        list_col = ['白天天气', '夜间天气', '最高温度', '最低温度', '白天风力风向', '夜间风力风向', '白天风级', '夜间风级']
        q = 0
        for i, j in enumerate(col):
            new_data = self.data[j].str.split('/', 1, True)
            new_data.columns = [list_col[q], list_col[q + 1]]
            q += 2
            self.data = self.data.drop([j], axis=1).join(new_data)
            print(self.data)

然后我们可以查看一下温度情况(下面的图是基于已经预处理完的数据): 如果这是一个温度回归预测,那么我们甚至只用温度的数据都能预测出未来的温度,可惜这是一个天气分类问题,天气就没有这么好的规律了: 下面继续对数据进行处理,日期随便处不处理,将温度后面的符号去掉:

self.data['日期'] = self.data['日期'].apply(lambda x: x.replace('年', '-').replace('月', '-').replace('日', ''))
        self.data['日期'] = pd.to_datetime(self.data['日期'])

        self.data['最高温度'] = self.data['最高温度'].apply(lambda x: int(x.replace('℃', '')))
        self.data['最低温度'] = self.data['最低温度'].apply(lambda x: int(x.replace('℃', '')))

天气的话使用collections库下的Counter 来统计所有出现

标签: edg连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台