首页 > 技术文章 > 利用线性回归进行气温预测

chantmee 2021-10-01 18:46 原文

前言

最近刚刚监督学习线性回归算法,再加上最近青岛天气异常多变,天气预报一直预测的不准确于是想亲自写一个气温预测的功能。

数据获取

本次数据是在天气+获取的。由于一开始没有想用特别多的数据来训练模型所以选择手动复制然后写程序预处理这些数据。但是后来发现模型不太准确于是就手动获取了四五年的数据。。

最一开始复制过来的数据大概是这样的:

2017-01-01 星期日
3℃
-3℃
霾
东南风 1级
2017-01-02 星期一
6℃
-6℃
晴
西南风 2级
2017-01-03 星期二
5℃
-5℃
霾
南风 1级
2017-01-04 星期三
6℃
-5℃
霾
东风 1级
2017-01-05 星期四
2℃
-4℃
小雪
东北风 1级

然后用python对数据进行了处理,处理程序为:

class Data:
    def __init__(self) -> None:
        self.N = int(8565/5)
        self.file_name = '/Users/chant/data.txt'	# 原始数据的存储位置
        self.Days = []
        self.parameter = ['year', 'month', 'day', 'sat', 'tmax', 'tmin', 'weather', 'cloud', 'cloud_grade']
        self.Sat = {
            "星期一": 1,
            "星期二": 2,
            "星期三": 3,
            "星期四": 4,
            "星期五": 5,
            "星期六": 6,
            "星期日": 7,
        }
        self.Weather = {
            '雪': 0,
            '雨夹雪': 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,
        }
        self.Cloud = {
            '西南风': 0,
            '西北风': 1,
            '东北风': 2,
            '西风': 3,
            '北风': 4,
            '东风': 5,
            '南风': 6,
            '东南风': 7,
        }

    def _processData(self):
        res = []
        with open(self.file_name, "r") as f:
            for _ in range(self.N):
                line = []
                for __ in range(5):
                    line.append(f.readline())
                res.append(line)
            f.close()

        for i in range(len(res)):
            date = res[i][0]
            date = date.split()
            date[0] = date[0].split('-')
            Day = {
                'year': date[0][0],
                'month': date[0][1],
                'day': date[0][2],
                'sat': self.Sat[date[1]],
                'tmax': res[i][1].split('℃')[0],
                'tmin': res[i][2].split('℃')[0],
                'weather': self.Weather[res[i][3].split()[0]],
                'cloud': self.Cloud[res[i][4].split()[0]],
                'cloud_grade': res[i][4].split()[1].split('级')[0],
            }
            self.Days.append(Day)

    def _getData(self):
        with open('train_data.txt', "w") as f:
            for day in self.Days:
                line = []
                for i in self.parameter:
                    line.append(str(day[i]))
                tmax = int(day['tmax'])
                tmin = int(day['tmin'])
                ave_t = str(int((tmax + tmin) / 2))
                line.append(ave_t)
                f.write(' '.join(line) + '\n')
            f.close()

    def read(self):
        self._processData()
        self._getData()

data = Data()
data.read()

处理之后的数据的形式为:(以上面提到的数据为例)

2017 01 01 7 3 -3 40 7 1 0
2017 01 02 1 6 -6 47 0 2 0
2017 01 03 2 5 -5 40 6 1 0
2017 01 04 3 6 -5 40 5 1 0
2017 01 05 4 2 -4 6 2 1 -1

模型训练

采用线性回归模型,对之前的模型进行了抽象使得它能够适应不同的训练对象。

代码中N为训练集中有多少组数据,M为用几组数据作为一个大组数据。这里解释一下,这次是采取用连续的M天的天气数据来预测第M+1天的气温,你可以认为我是将每M组数据看成一组数据,然后用这样一个个大的数据来训练模型。正常情况下如果要用这个程序训练其他模型,那么一般取M=1即可。

无论之后要训练什么线性回归模型都可以仅仅改变这两个变量,然后遵循数据输入格式就可以训练得到所要模型。

数据的输入格式就像上面提到的那样,一组数据占一行,属性与属性之间用空格隔开即可。

import numpy as np

N, M = 1713, 7
X, Y = [], []
data = []

def getData():
    with open('train_data.txt', 'r') as f:
        for j in range(N):
            day = f.readline()
            day = day.split()
            x = []
            if j >= M:
                Y.append([int(day[-1])])
            for i in range(1, len(day), 1):
                x.append(int(day[i]))
            data.append(x)
        f.close()

getData()


for i in range(N - M):
    x = []
    for j in range(i, i + M):
        for k in range(len(data[i])):
            x.append(data[j][k])
    X.append(x)

Y = np.array(Y)
X = np.array(X)

R = np.dot(X.T, X)
R = np.linalg.inv(R)
X = np.dot(R, X.T)
X = np.dot(X, Y)
print(X)

while True:
    x = []
    for i in range(M):
        line = input()
        line = line.split()
        for j in range(1, len(line)):
            x.append(int(line[j]))
    x = np.array([x])
    print(np.dot(x, X))

训练结果

参数

[[-0.00960554][-0.00098373][-0.03482452][-0.09874913][-0.01522894][-0.00690102]
 [-0.00360833][ 0.18596758][ 0.2011527 ][-0.13787361][-0.03879721][-0.04515376]
 [-0.29584184][-0.27286385][-0.00626221][ 0.03855616][ 0.07607454][ 0.68998697]
 [-0.03383131][ 0.02315778][ 0.03845914][-0.2146056 ][-0.18112698][ 0.00590247]
 [ 0.0142927 ][ 0.05891823][ 0.44073106][ 0.22455274][ 0.02297105][-0.08009145]
 [-0.04295759][ 0.02611487][-0.0213408 ][ 0.00678582][ 0.33901778][-0.002793  ]
 [-0.14366115][-0.00638387][ 0.01944473][ 0.05172225][ 0.04167949][-0.01063384]
 [ 0.01878481][ 0.11036187][ 0.1236436 ][-0.30618289][-0.03072733][-0.04739046]
 [ 0.26877076][ 0.32194008][ 0.01257415][ 0.03803252][ 0.04066905][-0.45336595]
 [ 0.32240357][ 0.02578947][ 0.01805024][ 0.18960214][-0.21082523][ 0.0194945 ]
 [-0.01308654][-0.49200897][ 0.41322758]]

效果

这里采用的测试集为:

2021 09 01 3 29 18 21 6 2 23
2021 09 02 4 29 18 15 5 1 23
2021 09 03 5 30 22 13 6 1 26
2021 09 04 6 23 20 8 5 1 21
2021 09 05 7 24 20 6 4 1 22
2021 09 06 1 23 14 21 2 1 18
2021 09 07 2 27 17 21 5 2 22
2021 09 08 3 29 19 13 1 2 24
2021 09 09 4 26 18 15 2 1 22
2021 09 10 5 29 19 21 0 2 24

TEST1

2021 09 01 3 29 18 21 6 2 23
2021 09 02 4 29 18 15 5 1 23
2021 09 03 5 30 22 13 6 1 26
2021 09 04 6 23 20 8 5 1 21
2021 09 05 7 24 20 6 4 1 22
2021 09 06 1 23 14 21 2 1 18
2021 09 07 2 27 17 21 5 2 22
[[21.8357464]]

真实值为24,预测值为22.

TEST2

2021 09 02 4 29 18 15 5 1 23
2021 09 03 5 30 22 13 6 1 26
2021 09 04 6 23 20 8 5 1 21
2021 09 05 7 24 20 6 4 1 22
2021 09 06 1 23 14 21 2 1 18
2021 09 07 2 27 17 21 5 2 22
2021 09 08 3 29 19 13 1 2 24
[[21.83227695]]

真实值为22,预测值为22.

TEST3

2021 09 03 5 30 22 13 6 1 262021 09 04 6 23 20 8 5 1 212021 09 05 7 24 20 6 4 1 222021 09 06 1 23 14 21 2 1 182021 09 07 2 27 17 21 5 2 222021 09 08 3 29 19 13 1 2 242021 09 09 4 26 18 15 2 1 22[[21.98230886]]

真实值24,预测值为22.


现在感觉预测结果还不错,于是我去训练集中找了一个温差比较大的数据:

2017 04 08 6 19 7 38 3 4 132017 04 09 7 19 8 36 0 4 132017 04 10 1 20 10 36 0 5 152017 04 11 2 22 7 47 4 3 142017 04 12 3 25 9 47 4 3 172017 04 13 4 21 8 38 3 3 142017 04 14 5 26 11 36 3 4 18

模型的预测结果为16,但是真实值为7.

推荐阅读