使用Sklearn训练模型预测台风路径

运用Sklearn的多种线性回归策略提高台风路径预测的准确性


内容

  • 使用Sklearn中线性回归、岭回归、ElasticNet回归以及Lasso回归模型对台风路径数据进行训练、预测,进行误差分析,并比较各个模型的优劣。
  • 比较训练数据量对结果准确性的影响。
  • 找出预测台风路径最优的回归模型,并使用模型对目标数据进行预测。

数据描述

台风训练数据typhoon.dat, 共计500条,共18列,前16列为预报因子,最后2列分别是经纬度。 每行数据是间隔12个小时采集到的台风预报因子,数据的任务是预测台风的路径,即预测台风的经纬度,最后两列的值。 LON .V1: 起报时刻经度 lon+00 LON .V2: 起报时刻前12小时纬向移速 vlat-12 LON .V3: 起报时刻前24小时纬向移速 vlat-24(可能是经向) LON .V4: 起报时刻前24 小时所在经度 lon-24 LON .V5: 起报时刻前12 小时至前24小时纬向移速 vlat-24 LON .V6: 起报时刻与前12小时的经度差 (lon+00)-(lon-12) LON .V7: 起报时刻前6 小时所在经度 lon-06 LON .V8: 起报时刻前18 小时所在经度 lon-18 Lat.v9: 起报时刻纬度 lat+00 Lat.v10: 起报时刻前12小时经向移速 vlon-12 Lat.v11: 起报时刻前24小时经向移速的平方 (vlon-24)^2 Lat.v12: 起报时刻前12 小时所在纬度 lat-12 Lat.v13: 起报时刻与前24小时的经度差 (lon+00)-(lon-24) Lat.v14: 起报时刻前6 小时所在纬度 lat-06 Lat.v15: 起报时刻前18 小时所在纬度 lat-18 Lat.v16: 起报时刻前6 小时地面附近最大风速 wind-06 LON . t: 要预报的24小时后的经度(预报量) lon+24 Lat.t: 要预报的24小时后的纬度(预报量) lat+24 台风测试数据为 typhoon200Test.dat,共计200条,每条有16列预报因子,与训练数据的前16列数据格式顺序相同,但是没有最后的两列经纬度数据。 测试的任务就是对这200条台风数据预测每条记录的经度和纬度值。

分析

(分析过程代码见最后)

首先分析一下各个回归模型训练数据量对预测结果准确性的影响。

上图是训练样本量对各个模型预测结果与真实结果的距离误差的影响。其中,横坐标是训练数据集的大小,纵坐标是真实的经纬度与预测的经纬度之间的距离。 由图可见,随着训练数据集中数据数量的增多,预测误差是逐渐减小的。 上图是训练样本量对各个模型预测结果与真实结果的经纬度误差的影响。其中,横坐标是训练数据集的大小,纵坐标是真实的经纬度与预测的经纬度之间的误差大小。 由图亦可看出,随着训练数据集中数据数量的增多,预测误差是逐渐减小的。并且各个模型预测纬度的误差要小于对经度进行预测的误差。

使用50到300个预测样本分析不同的回归模型对台风路径预测误差的影响。

上图是截取了训练样本数据量在50到300时预测的距离误差随训练数据量的变化趋势。 由图可见,在训练样本数据量稍大的情况下,岭回归与线性回归对台风路径的预测的误差较小。 上图是截取了训练样本数据量在50到300时预测的经纬度误差随训练数据量的变化趋势。 由图可见,总体来说,各个回归模型对台风路径纬度的预测误差要小于对经度的预测误差。 在训练样本数据量稍大的情况下,岭回归对台风路径经度的预测的误差相对较小,线性回归对台风路径纬度的预测的误差相对较小。


由上述分析可知,在此数量级的训练样本下,线性回归对纬度的预测要较为准确,而岭回归对经度的预测较为准确。所以,可以对台风路径的经纬度分别使用这两种回归模型进行预测。 上图是训练样本量对预测经纬度与真实经纬度之间相关系数的影响。由图可见,在数据量为150到300之间时,岭回归对经度的预测结果与真实结果相关性最强,线性回归对纬度的预测结果与真实结果相关性最强。 所以在此实验中,可以使用岭回归来预测台风路径的经度值,使用线性回归来预测台风路径的纬度值。

结论

上图中红线是使用岭回归来预测台风路径的经度值,使用线性回归来预测台风路径的纬度值,进而得到的距离误差。 可见,采用此方法预测在数据量大于150时要比其他方法准确。 所以,本实验最终使用岭回归来预测台风路径的经度值,使用线性回归来预测台风路径的纬度值,对200条测试数据进行预测。

预测结果

typhoon200Results.dat

预测代码

from __future__ import division
import os, sys
import numpy as np
# from numpy import
from sklearn import linear_model
from math import

import pandas as pd
from pandas import DataFrame
from pandas_datareader import data
import pandas_datareader as pdr

%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib as mpl

mpl.rcParams[‘font.sans-serif’] = [‘SimHei’]
mpl.rcParams[‘font.serif’] = [‘SimHei’]
import seaborn as sns
sns.set_style(“darkgrid”,{“font.sans-serif”:[‘simhei’, ‘Arial’]})

train_num = 50

#加载数据
def loadDataSet(fileName): #general function to parse tab -delimited floats
numFeat = len(open(fileName).readline().split(‘\t’)) - 2 #get number of fields
dataArr = []
lonArr = []
latArr = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
lineArr.append(1.0) # 增加这一列是为了进行线性回归,存放常量x0
curLine = line.strip().split(‘\t’)
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataArr.append(lineArr)
lonArr.append(float(curLine[-2])) # 倒数第二项是lon经度
latArr.append(float(curLine[-1])) # 最后一项是lat纬度
return dataArr,lonArr, latArr

# 计算误差
def absError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
return abs(yArr-yHatArr).sum() / len(yArr)

# 加载数据,分隔为train和test
dataArr,lonArr,latArr= loadDataSet(‘typhoon.dat’)

#加载测试数据
def loadTestDataSet(fileName): #general function to parse tab -delimited floats
numFeat = len(open(fileName).readline().split(‘\t’)) #get number of fields
dataArr = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
lineArr.append(1.0) # 增加这一列是为了进行线性回归,存放常量x0
curLine = line.strip().split(‘\t’)
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataArr.append(lineArr)
return dataArr

trainX=dataArr[0:500]; lonTrainY=lonArr[0:500]; latTrainY=latArr[0:500]
# testX=dataArr[300:]; lonTestY=lonArr[300:]; latTestY=latArr[300:]
testX=loadTestDataSet(‘typhoon200Test.dat’)

# 构建模型
clf = linear_model.LinearRegression() # 线性回归
clf1 = linear_model.Ridge (alpha = 0.8) # 岭回归
# clf2 = linear_model.ElasticNet(alpha = 1.0) # ElasticNet线性
# clf3 = linear_model.Lasso()

clf.fit (trainX, lonTrainY) # 训练经度模型
lonyHat = clf.predict(testX) # 使用经度模型去预测经度
clf.fit (trainX, latTrainY) # 训练纬度模型
latyHat = clf.predict(testX) # 使用纬度模型去预测纬度
# # 经度误差
# absErrorLon = absError(lonTestY,lonyHat)
# # 纬度误差
# absErrorLat = absError(latTestY,latyHat)
# absErrorLen = 110 sqrt(absErrorLon\*2 + absErrorLat**2)

clf1.fit (trainX, lonTrainY) # 训练经度模型
lonyHat1 = clf1.predict(testX) # 使用经度模型去预测经度
clf1.fit (trainX, latTrainY) # 训练纬度模型
latyHat1 = clf1.predict(testX) # 使用纬度模型去预测纬度

# print(lonyHat1)
# print(latyHat)

data = []

for i in range(0, 200):
data1 = []
data1.append(lonyHat1[i])
data1.append(latyHat[i])
data.append(data1)

df = DataFrame(data)
df.to_csv(‘typhoon200Results.dat’, sep=’\t’, header=False, index=False)

# # 经度误差
# absErrorLon1 = absError(lonTestY,lonyHat1)
# # 纬度误差
# absErrorLat1 = absError(latTestY,latyHat1)
# absErrorLen1 = 110 sqrt(absErrorLon1\*2 + absErrorLat1**2)

# absErrorLen3333 = 110 sqrt(absErrorLon1\*2 + absErrorLat**2)

# print( absErrorLen, absErrorLen1, absErrorLen3333)

分析过程代码

from __future__ import division
import os, sys
import numpy as np
# from numpy import
from sklearn import linear_model
from math import

import pandas as pd
from pandas import DataFrame
from pandas_datareader import data
import pandas_datareader as pdr

%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib as mpl

mpl.rcParams[‘font.sans-serif’] = [‘SimHei’]
mpl.rcParams[‘font.serif’] = [‘SimHei’]
import seaborn as sns
sns.set_style(“darkgrid”,{“font.sans-serif”:[‘simhei’, ‘Arial’]})

train_num = 50

#加载数据
def loadDataSet(fileName): #general function to parse tab -delimited floats
numFeat = len(open(fileName).readline().split(‘\t’)) - 2 #get number of fields
dataArr = []
lonArr = []
latArr = []
fr = open(fileName)
for line in fr.readlines():
lineArr =[]
lineArr.append(1.0) # 增加这一列是为了进行线性回归,存放常量x0
curLine = line.strip().split(‘\t’)
for i in range(numFeat):
lineArr.append(float(curLine[i]))
dataArr.append(lineArr)
lonArr.append(float(curLine[-2])) # 倒数第二项是lon经度
latArr.append(float(curLine[-1])) # 最后一项是lat纬度
return dataArr,lonArr, latArr

# 计算误差
def absError(yArr,yHatArr): #yArr and yHatArr both need to be arrays
return abs(yArr-yHatArr).sum() / len(yArr)

# 加载数据,分隔为train和test
dataArr,lonArr,latArr= loadDataSet(‘typhoon.dat’)

data_all = {‘data size’:[], ‘线性回归’:[], ‘岭回归’:[], ‘ElasticNet回归’:[], ‘Lasso回归’:[]}
data_LonLat_Err = {‘data size’:[], ‘线性回归Lon’:[], ‘岭回归Lon’:[], ‘ElasticNet回归Lon’:[],
‘Lasso回归Lon’:[],
‘线性回归Lat’:[], ‘岭回归Lat’:[], ‘ElasticNet回归Lat’:[],’Lasso回归Lat’:[]}
data_LonLat_corr = {‘data size’:[], ‘线性回归Lon’:[], ‘岭回归Lon’:[], ‘ElasticNet回归Lon’:[],
‘Lasso回归Lon’:[],
‘线性回归Lat’:[], ‘岭回归Lat’:[], ‘ElasticNet回归Lat’:[],’Lasso回归Lat’:[]}
for train_num in range(50, 300, 1):
trainX=dataArr[0:train_num]; lonTrainY=lonArr[0:train_num]; latTrainY=latArr[0:train_num]
testX=dataArr[300:]; lonTestY=lonArr[300:]; latTestY=latArr[300:]

data\_all\['data size'\].append(train\_num)
data\_LonLat\_Err\['data size'\].append(train_num)
data\_LonLat\_corr\['data size'\].append(train_num)

# 构建模型
clf = linear_model.LinearRegression() # 线性回归
clf1 = linear_model.Ridge (alpha = 0.8) # 岭回归
clf2 = linear_model.ElasticNet(alpha = 1.0) # ElasticNet线性
clf3 = linear_model.Lasso()


clf.fit (trainX, lonTrainY) # 训练经度模型
lonyHat = clf.predict(testX) # 使用经度模型去预测经度
clf.fit (trainX, latTrainY) # 训练纬度模型
latyHat = clf.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon = absError(lonTestY,lonyHat)
# 纬度误差
absErrorLat = absError(latTestY,latyHat)
absErrorLen = 110 * sqrt(absErrorLon\*\*2 + absErrorLat\*\*2)

data_all\['线性回归'\].append(absErrorLen)

clf1.fit (trainX, lonTrainY) # 训练经度模型
lonyHat1 = clf1.predict(testX) # 使用经度模型去预测经度
clf1.fit (trainX, latTrainY) # 训练纬度模型
latyHat1 = clf1.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon1 = absError(lonTestY,lonyHat1)
# 纬度误差
absErrorLat1 = absError(latTestY,latyHat1)
absErrorLen1 = 110 * sqrt(absErrorLon1\*\*2 + absErrorLat1\*\*2)

data_all\['岭回归'\].append(absErrorLen1)


clf2.fit (trainX, lonTrainY) # 训练经度模型
lonyHat2 = clf2.predict(testX) # 使用经度模型去预测经度
clf2.fit (trainX, latTrainY) # 训练纬度模型
latyHat2 = clf2.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon2 = absError(lonTestY,lonyHat2)
# 纬度误差
absErrorLat2 = absError(latTestY,latyHat2)
absErrorLen2 = 110 * sqrt(absErrorLon2\*\*2 + absErrorLat2\*\*2)

data_all\['ElasticNet回归'\].append(absErrorLen2)


clf3.fit (trainX, lonTrainY) # 训练经度模型
lonyHat3= clf3.predict(testX) # 使用经度模型去预测经度
clf3.fit (trainX, latTrainY) # 训练纬度模型
latyHat3 = clf3.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon3 = absError(lonTestY,lonyHat3)
# 纬度误差
absErrorLat3 = absError(latTestY,latyHat3)
absErrorLen3 = 110 * sqrt(absErrorLon3\*\*2 + absErrorLat3\*\*2)

data_all\['Lasso回归'\].append(absErrorLen3)

data\_LonLat\_Err\['线性回归Lon'\].append(absErrorLon)
data\_LonLat\_Err\['岭回归Lon'\].append(absErrorLon1)
data\_LonLat\_Err\['ElasticNet回归Lon'\].append(absErrorLon2)
data\_LonLat\_Err\['Lasso回归Lon'\].append(absErrorLon3)

data\_LonLat\_Err\['线性回归Lat'\].append(absErrorLat)
data\_LonLat\_Err\['岭回归Lat'\].append(absErrorLat1)
data\_LonLat\_Err\['ElasticNet回归Lat'\].append(absErrorLat2)
data\_LonLat\_Err\['Lasso回归Lat'\].append(absErrorLat3)

data\_LonLat\_corr\['线性回归Lon'\].append(np.corrcoef(lonyHat, lonArr\[300:\])\[0\]\[1\])
data\_LonLat\_corr\['岭回归Lon'\].append(np.corrcoef(lonyHat1, lonArr\[300:\])\[0\]\[1\])
data\_LonLat\_corr\['ElasticNet回归Lon'\].append(np.corrcoef(lonyHat2, lonArr\[300:\])\[0\]\[1\])
data\_LonLat\_corr\['Lasso回归Lon'\].append(np.corrcoef(lonyHat3, lonArr\[300:\])\[0\]\[1\])

data\_LonLat\_corr\['线性回归Lat'\].append(np.corrcoef(latyHat, latArr\[300:\])\[0\]\[1\])
data\_LonLat\_corr\['岭回归Lat'\].append(np.corrcoef(latyHat1, latArr\[300:\])\[0\]\[1\])
data\_LonLat\_corr\['ElasticNet回归Lat'\].append(np.corrcoef(latyHat2, latArr\[300:\])\[0\]\[1\])
data\_LonLat\_corr\['Lasso回归Lat'\].append(np.corrcoef(latyHat3, latArr\[300:\])\[0\]\[1\])



#计算距离公式: 110*sqrt(lon^2+lat^2)

# print(absErrorLen,absErrorLen1,absErrorLen2 )

# 计算经度预测值与真实值的相关系数
# print(np.corrcoef(lonyHat, lonArr\[400:\])\[0\]\[1\])
# 计算纬度预测值与真实值的相关系数
# print(np.corrcoef(latyHat, latArr\[400:\])\[0\]\[1\])

# print(data_all)
data_all = DataFrame(data_all)
data_all.set_index([‘data size’], inplace=True)
data_all.plot(kind=’line’, figsize=(12,8),
title=’训练样本量对预测距离误差的影响’)
plt.legend(bbox_to_anchor=(1.0, 1))

data_LonLat_Err = DataFrame(data_LonLat_Err)
data_LonLat_Err.set_index([‘data size’], inplace=True)
data_LonLat_Err.plot(kind=’line’, figsize=(12,8),
title=’训练样本量对预测经纬度误差的影响’)
plt.legend(bbox_to_anchor=(1.0, 1))

data_LonLat_corr = DataFrame(data_LonLat_corr)
data_LonLat_corr.set_index([‘data size’], inplace=True)
data_LonLat_corr.plot(kind=’line’, figsize=(12,8),
title=’训练样本量对预测经纬度与真实经纬度之间相关系数的影响’)
plt.legend(bbox_to_anchor=(1.0, 1))

data_all = {‘data size’:[], ‘线性回归’:[], ‘岭回归’:[], ‘ElasticNet回归’:[], ‘Lasso回归’:[], ‘线性-岭回归’:[]}
for train_num in range(50, 300, 1):
trainX=dataArr[0:train_num]; lonTrainY=lonArr[0:train_num]; latTrainY=latArr[0:train_num]
testX=dataArr[300:]; lonTestY=lonArr[300:]; latTestY=latArr[300:]

data\_all\['data size'\].append(train\_num)

# data_LonLat_Err[‘data size’].append(train_num)
# data_LonLat_corr[‘data size’].append(train_num)

# 构建模型
clf = linear_model.LinearRegression() # 线性回归
clf1 = linear_model.Ridge (alpha = 0.8) # 岭回归
clf2 = linear_model.ElasticNet(alpha = 1.0) # ElasticNet线性
clf3 = linear_model.Lasso()


clf.fit (trainX, lonTrainY) # 训练经度模型
lonyHat = clf.predict(testX) # 使用经度模型去预测经度
clf.fit (trainX, latTrainY) # 训练纬度模型
latyHat = clf.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon = absError(lonTestY,lonyHat)
# 纬度误差
absErrorLat = absError(latTestY,latyHat)
absErrorLen = 110 * sqrt(absErrorLon\*\*2 + absErrorLat\*\*2)

data_all\['线性回归'\].append(absErrorLen)

clf1.fit (trainX, lonTrainY) # 训练经度模型
lonyHat1 = clf1.predict(testX) # 使用经度模型去预测经度
clf1.fit (trainX, latTrainY) # 训练纬度模型
latyHat1 = clf1.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon1 = absError(lonTestY,lonyHat1)
# 纬度误差
absErrorLat1 = absError(latTestY,latyHat1)
absErrorLen1 = 110 * sqrt(absErrorLon1\*\*2 + absErrorLat1\*\*2)

data_all\['岭回归'\].append(absErrorLen1)



clf2.fit (trainX, lonTrainY) # 训练经度模型
lonyHat2 = clf2.predict(testX) # 使用经度模型去预测经度
clf2.fit (trainX, latTrainY) # 训练纬度模型
latyHat2 = clf2.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon2 = absError(lonTestY,lonyHat2)
# 纬度误差
absErrorLat2 = absError(latTestY,latyHat2)
absErrorLen2 = 110 * sqrt(absErrorLon2\*\*2 + absErrorLat2\*\*2)

data_all\['ElasticNet回归'\].append(absErrorLen2)


clf3.fit (trainX, lonTrainY) # 训练经度模型
lonyHat3= clf3.predict(testX) # 使用经度模型去预测经度
clf3.fit (trainX, latTrainY) # 训练纬度模型
latyHat3 = clf3.predict(testX) # 使用纬度模型去预测纬度
# 经度误差
absErrorLon3 = absError(lonTestY,lonyHat3)
# 纬度误差
absErrorLat3 = absError(latTestY,latyHat3)
absErrorLen3 = 110 * sqrt(absErrorLon3\*\*2 + absErrorLat3\*\*2)

data_all\['Lasso回归'\].append(absErrorLen3)


absErrorLen333 = 110 * sqrt(absErrorLon1\*\*2 + absErrorLat\*\*2)

data_all\['线性-岭回归'\].append(absErrorLen333)

data_all = DataFrame(data_all)
data_all.set_index([‘data size’], inplace=True)
data_all.plot(kind=’line’, figsize=(12,8),
title=’训练样本量对预测距离误差的影响’)
plt.legend(bbox_to_anchor=(1.0, 1))