原始时间序列数据如下所示,我们将纬度、经度、高度作为输入
其轨迹经纬度如下图所示:
用keras创建一个三层的LSTM网络训练模型如下图所示:
import numpy as np
from keras.layers.core import Dense, Activation, Dropout
from keras.layers import LSTM
from keras.models import Sequential, load_model
from keras.callbacks import Callback
import keras.backend.tensorflow_backend as KTF
import tensorflow as tf
import pandas as pd
import os
import keras.callbacks
import matplotlib.pyplot as plt
#设定为自增长
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config)
KTF.set_session(session)
def trainModel(train_X, train_Y):
'''
trainX,trainY: 训练LSTM模型所需要的数据
'''
model = Sequential() # 定义一个堆叠的顺序模型
model.add(LSTM(
240,
input_shape=(train_X.shape[1], train_X.shape[2]),
return_sequences=True))
model.add(Dropout(0.3))
model.add(LSTM(
240,
return_sequences=True))
model.add(Dropout(0.3))
model.add(LSTM(
240,
return_sequences=False)) # 返回维度为 240 的单个向量
model.add(Dropout(0.3))
model.add(Dense(
train_Y.shape[1]))
model.add(Activation("relu"))
model.compile(loss='mse', optimizer='adam', metrics=['acc']) # 配置模型学习过程
model.fit(train_X, train_Y, epochs=100, batch_size=64, verbose=1, validation_data=(test_X, test_Y))
model.summary()
return model
if __name__ == "__main__":
train_num = 6
per_num = 1
# set_range = False
set_range = True
series_idx = ['lat', 'lon', 'altitude']
# 读入时间序列的文件数据
data = pd.read_csv('20081213052002.txt', sep=',').loc[:, series_idx].values
print("样本数:{0},维度:{1}".format(data.shape[0], data.shape[1]))
# print(data)
# 画样本数据库
plt.scatter(data[:, 1], data[:, 0], c='b', marker='o', label='traj_A')
plt.legend(loc='upper left')
plt.grid()
plt.show()
#归一化
data, normalize = NormalizeMult(data, set_range)
# print(normalize)
#生成训练数据
train_X, train_Y, test_X, test_Y = create_dataset(data, train_num, per_num)
print("x\n", train_X.shape)
print("y\n", train_Y.shape)
# 训练模型
model = trainModel(train_X, train_Y)
loss, acc = model.evaluate(train_X, train_Y, verbose=2)
print('Loss : {}, Accuracy: {}'.format(loss, acc * 100))
# 保存模型
np.save("./traj_model_trueNorm.npy", normalize)
model.save("./traj_model_240_3layers_altitude.h5")
模型训练结果如下:
创建LSTM网络预测模型:
import numpy as np
from keras.layers.core import Dense, Activation, Dropout
from keras.layers import LSTM
from keras.models import Sequential, load_model
from keras.callbacks import Callback
import keras.backend.tensorflow_backend as KTF
import tensorflow as tf
import pandas as pd
import os
import keras.callbacks
import matplotlib.pyplot as plt
import copy
#设定为自增长
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config)
KTF.set_session(session)
def rmse(predictions, targets):
return np.sqrt(((predictions - targets) ** 2).mean())
def mse(predictions, targets):
return ((predictions - targets) ** 2).mean()
def reshape_y_hat(y_hat,dim):
re_y = []
i = 0
while i < len(y_hat):
tmp = []
for j in range(dim):
tmp.append(y_hat[i+j])
i = i + dim
re_y.append(tmp)
re_y = np.array(re_y, dtype='float64')
return re_y
#多维反归一化
def FNormalizeMult(data,normalize):
data = np.array(data, dtype='float64')
#列
for i in range(0, data.shape[1]):
listlow = normalize[i, 0]
listhigh = normalize[i, 1]
delta = listhigh - listlow
print("listlow, listhigh, delta", listlow, listhigh, delta)
#行
if delta != 0:
for j in range(0, data.shape[0]):
data[j, i] = data[j, i]*delta + listlow
return data
#使用训练数据的归一化
def NormalizeMultUseData(data,normalize):
for i in range(0, data.shape[1]):
listlow = normalize[i, 0]
listhigh = normalize[i, 1]
delta = listhigh - listlow
if delta != 0:
for j in range(0, data.shape[0]):
data[j, i] = (data[j, i] - listlow)/delta
return data
from math import sin, asin, cos, radians, fabs, sqrt
EARTH_RADIUS = 6371 # 地球平均半径,6371km
# 计算两个经纬度之间的直线距离
def hav(theta):
s = sin(theta / 2)
return s * s
def get_distance_hav(lat0, lng0, lat1, lng1):
# "用haversine公式计算球面两点间的距离。"
# 经纬度转换成弧度
lat0 = radians(lat0)
lat1 = radians(lat1)
lng0 = radians(lng0)
lng1 = radians(lng1)
dlng = fabs(lng0 - lng1)
dlat = fabs(lat0 - lat1)
h = hav(dlat) + cos(lat0) * cos(lat1) * hav(dlng)
distance = 2 * EARTH_RADIUS * asin(sqrt(h))
return distance
if __name__ == '__main__':
test_num = 6
per_num = 1
series_idx = ['lat', 'lon', 'altitude']
test_move_loc = 0
data_all = pd.read_csv('20081213052002.txt', sep=',')
data_all = data_all.loc[np.arange(len(data_all)-test_num-per_num-test_move_loc, len(data_all)-test_move_loc).tolist(), series_idx].values
# print(data_all)
data_all.dtype = 'float64'
data = copy.deepcopy(data_all[:-per_num, :])
y = data_all[-per_num:, :]
# #归一化
normalize = np.load("./traj_model_trueNorm.npy")
data = NormalizeMultUseData(data, normalize)
model = load_model("./traj_model_120.h5")
test_X = data.reshape(1, data.shape[0], data.shape[1])
y_hat = model.predict(test_X)
y_hat = y_hat.reshape(y_hat.shape[1])
y_hat = reshape_y_hat(y_hat, y.shape[1])
#反归一化
y_hat = FNormalizeMult(y_hat, normalize)
print("predict: {0}\ntrue:{1}".format(y_hat, y))
# print('预测均方误差:', mse(y_hat, y))
print('预测均方误差:', mse(y_hat[-1, :], y[-1, :]))
# print('预测直线距离:{:.4f} KM'.format(get_distance_hav(y_hat[0, 0], y_hat[0, 1], y[0, 0], y[0, 1])))
print('预测直线距离:{:.4f} KM'.format(get_distance_hav(y_hat[-1, 0], y_hat[-1, 1], y[-1, 0], y[-1, 1])))
print('预测高度差:{:.4f} M'.format((y_hat[-1, 2]-y[-1, 2]) * 0.3047999995367)) # 1 feet = 0.3047999995367 m
# 画测试样本数据库
p1 = plt.scatter(y_hat[:, 1], y_hat[:, 0], c='r', marker='o', label='pre')
p2 = plt.scatter(y[:, 1], y[:, 0], c='g', marker='o', label='pre_true')
plt.legend(loc='upper left')
plt.grid()
plt.show()
预测结果如下: