前言
最近剛剛監督學習線性回歸算法,再加上最近青島天氣異常多變,天氣預報一直預測的不准確於是想親自寫一個氣溫預測的功能。
數據獲取
本次數據是在天氣+獲取的。由於一開始沒有想用特別多的數據來訓練模型所以選擇手動復制然后寫程序預處理這些數據。但是后來發現模型不太准確於是就手動獲取了四五年的數據。。
最一開始復制過來的數據大概是這樣的:
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. 😦
結論
模型在溫差不大的情況下預測結果尚能接受,但是當溫差比較大的時候預測值與真實值的結果相差極大。