[PyTorch Deep Learning] Using Graph Convolutional Neural Networks to Predict Beijing Subway Inbound Traffic Actual Combat (with Source Code and Dataset)

If you need source code and data sets, please like and follow the collection and leave a private message in the comment area~~~

1. Data preprocessing

AFC (Automatic Fare Collection System) data is the data record of some travel information of passengers collected by the automatic fare collection system when passengers enter and exit the station by swiping their cards through the gates. The system can accurately record passengers' card numbers, Inbound and outbound time, inbound and outbound codes and other information, all recorded information contains 42 fields. It should be noted that only the start and end points are recorded in the card data, and the transfer information of passengers will not be recorded.

Using the AFC card swiping data of Beijing Metro for 5 consecutive weeks and 25 working days from February 29th to April 1st, 2016, a total of 130 million records, the data span is 05:00-23:00 (18 hours or 1080 minutes), The original card data records information such as the card number, the time of entry and exit, the station number of the entry and exit station, and the name of the station of entry and exit. In March 2016, Beijing had a total of 17 operating lines and 276 operating stations (transfer stations are not counted repeatedly, excluding the airport line). For stations where two or three lines cross and transfer, different station numbers are given, and other stations are given unique numbers

The information in the subway AFC data is coded, and the station code must be matched with the corresponding station name in order to have practical significance. The main fields required for extracting passenger flow time series are card issue number, inbound number, inbound time, outbound number, outbound time, and inbound and outbound station names after matching the inbound code and outbound code

It is considered that two data records will be generated when a passenger enters and exits the station by swiping the card through the automatic fare collection system for one trip. One record will be generated when the passenger swipes the card to enter the station, and the record generated when the passenger swipes the card to exit the station contains both the entry information and the exit information. , which adds information such as outbound time, outbound station number, etc.

In summary, the data records generated when entering the station can be deleted, greatly reducing the amount of data and reducing the difficulty of data processing.

Because of the large amount of data, the data cleaning work in this part is mainly carried out in the Oracle database.

 For the subway AFC data, considering the spatio-temporal characteristics of passenger travel and passenger travel rules, the main method is to delete logically obviously irrational records and some variables that are useless to this study. The main processing methods are as follows:

Extract the fields required for the research, delete useless fields, match the inbound and outbound codes with the inbound and outbound station names, and delete records that cannot normally match the station names;

Delete the records whose inbound time is later than the outbound time;

Delete records where the time of entry and exit is outside the operating time of the subway;

Delete the records where the entry and exit dates are not on the same day (some lines operate across days);

Delete the records where the time difference between entering and leaving the station is greater than 4 hours, because the Beijing Subway stipulates that staying in the station for more than 4 hours will pay 3 yuan, except for begging and posting small advertisements, very few passengers can take the subway for more than 4 hours;

Delete records where the travel time does not match the travel distance, that is, the passenger travel speed is not within the normal range;

Delete the records of entry and exit of the same station;

Delete records with missing fields, for example, records with "0" or NULL in some fields should be deleted

A sample of card data before processing is shown in the figure below:

A sample of processed card data is shown in the figure below:

 

According to the processed card data, the time series of inbound passenger flow at different time granularities are extracted respectively, and the extracted time series of passenger flow at a time granularity of 15 minutes is shown in the figure below

 

The station numbers are sorted by line number and adjacency relationship. The passenger flow sequence data is normalized to the (0, 1) interval using a min-max scaler, and then denormalized to the original magnitude of the data when evaluating the results

The input of this code is the processed card data, and the output is the time series of inbound passenger flow at different time granularities. (The specific structure is shown above.) The output results are stored in the CSV file. The code is as follows

# _*_coding:utf-8_*_
import os
import time
import numpy as np

# 以两天的数据为例,共计276个车站,15分钟时间粒度下,每天05:00-23:00共计18个小时,每天共72个时间片
# 两天共计144个时间片,所以最终得到的为276×144的矩阵

global_start_time = time.time()
print(global_start_time)

# 导入n天的客流数据
datalist = os.listdir('./data/')
print(datalist)
datalist.sort(key=lambda x: int(x[9:13]))
# 初始化n个空列表存放n天的数据
for i in range(0, len(datalist)):
	globals()['flow_'+str(i)] = []

for i in range(0, len(datalist)):
	file = np.loadtxt('./data/'+ datalist[i], skiprows=1, dtype=str)
	for line in file:
		line = line.replace('"', '').strip().split(',')
		line = [int(x) for x in line]
		globals()['flow_'+str(i)].append(line)
	print("已导入第"+str(i)+"天的数据"+"  "+datalist[i])


# 获取车站在所给时间粒度下的进站客流序列
def get_tap_in(flow, time_granularity, station_num):
	# 一天共计1440分钟,去掉23点到5点五个小时300分钟的时间,一天还剩1080分钟,num为每天的时间片个数,
	# 当除不尽时,由于int是向下取整,会出现下标越界,所以加1
	if 1080 % time_granularity == 0:
		num = int(1080/time_granularity)
	else:
		num = int(1080/time_granularity)+1
	# 初始化278*278*num的多维矩阵,每个num代表第num个时间粒度
	OD_matrix = [[([0] * station_num) for i in range(station_num)] for j in range(num)]
	#print (matrix)
	for row in flow:
		# 每一列的含义 GRANT_CARD_CODE	TAP_IN	TAP_OUT	TIME_IN	TIME_OUT
		# row[1]为进站编码,row[2]为出站编码,row[3]为进站时间,t为进站时间所在的第几个时间粒度(角标是从0开始的所以要减1)
		# 通过row[3]将晚上11点到12点的数据删掉不予考虑
		if row[3] < 1380 and row[1] < 277 and row[2] < 277:
			m = int(row[1])-1
			n = int(row[2])-1
			t = int((int(row[3])-300)/time_granularity)+1
			# 对每一条记录,在相应位置进站量加1
			OD_matrix[t-1][m][n] += 1

	# 不同时间粒度下某个站点的进站量num列,行数为station_num
	O_matrix = [([0] * num) for i in range(station_num)]
	for i in range(num):
		for j in range(station_num):
			temp = sum(OD_matrix[i][j])
			O_matrix[j][i] = temp
	return O_matrix, OD_matrix


for i in [5, 10, 15, 30, 60]:
	print('正在提取第'+str(i)+'个时间粒度的时间序列')
	for j in range(len(datalist)):
		print('正在提取该时间粒度下第'+str(j)+'天的时间序列')
		globals()['O_flow_'+str(i)],  globals()['OD_matrix_'+str(i)] = get_tap_in(globals()['flow_'+str(j)], i, station_num=276)
		np.savetxt('O_flow_'+str(i)+'.csv', np.array(globals()['O_flow_'+str(i)]), delimiter=',', fmt='%i')
		print(globals()['O_flow_'+str(i)])

print('总时间为(s):', time.time() - global_start_time)

2. Problem Statement and Model Framework

 Using historical inbound flow data, with the help of a simple graph convolutional neural network (Kipf version) and a two-dimensional convolutional neural network, predict the inbound flow of all subway stations in the next 15 minutes

The model framework is shown in the figure:

Among them, the model input is the short-term inbound flow sequence in the three modes of weekly mode, daily mode and real-time mode, which pass through the GCN layer and CNN layer respectively, and input the inbound flow sequence at the next moment

The directory skeleton of the code is as follows, where:

 

The data folder is mainly used to read data and divide the data into training set, verification set and test set

The model folder mainly provides the layers of the PyTorch version of the Graph Attention Network (GAT) and the Graph Convolutional Network (GCN), as well as the short-term passenger flow prediction deep learning model built in this chapter

The result folder is used to store model prediction results

The runs folder is used to store the model training process, and tensorboard can be used to visualize the training loss and verification loss of the model. save_model is used to save the model of the training process

The files stored in the utils folder are mainly used to terminate model training, model evaluation, and obtain the Laplacian matrix in graph convolution, etc.

3. Data preparation

 The inbound passenger flow time series with 15-minute time granularity extracted from about 130 million pieces of card swiping data for 5 consecutive weeks and 25 working days in Beijing Subway is used. The dimension is 276*1800, and the data of the past 10 time steps are used to predict the next one. The data of the time step, the data of the first 4 weeks is the training set, and 10% (0.1) of the training set is taken out as the verification set, and the data of the next week is the test set

Due to the limited amount of data, and the three modes of weekly mode, daily mode and real-time mode are considered in the forecasting model, the data of the fourth week are used in both the training set and the test set. In the training set, the data of the fourth week As train Y, in the test set, the data of the 4th week is used as test X

The meanings of all custom parameters are shown in the figure below:

In Pytorch, Dataset and Dataloder are components for data loading. The data must be loaded before training the deep learning model. In some case teaching of pytorch, MNIST, CIFAR-10 and other data sets that come with torch.torchvision.datasets are often used. The general process is shown in the following figure:

 However, in the model training of this example, an unofficial self-made dataset needs to be used. At this time, we can load our own dataset by rewriting __getitem__ and __len__ in torch.utils.data.Dataset. After creating the Dataset class, use it together with dataloader to continuously provide data to the model when training the model

When creating subclasses based on the parent class Dataset, all subclasses must override the __getitem__() method and the __len__() method:

The function of the __getitem__() function is to traverse the data according to the index index

The function of the __len__() function is to return the length (that is, the number) of the data set

In the created dataset class, the data can be processed according to your own needs

You can write an independent data processing function and call it in the __getitem__() function; or directly write the data processing method in the __getitem__() function or __init__() function, but __getitem__() must return a response according to the index The value will be passed to the dataloader through the index for subsequent batch batch processing

The data is normalized using a min-max scaler for training, and then denormalized to the original dimension for testing

4. Model Construction

The model building module mainly provides two files, one is the GCN layer file, and the other is the model built in this example

In the GCN layer H^l+1=f(H^l, A)=σ(D ̂^−1/2A ̂D ̂^−1/2H^lW^l+b^l), D ̂^−1/ 2A ̂D ̂^−1/2 is a fixed value and remains unchanged. It can be calculated in advance by using the get_normalized_adj function in the utils file. The input of the GCN layer provided in this chapter is the feature matrix H^l, and the processed adjacency matrix D ̂^−1/2A ̂D ̂^−1/2, corresponding to x and adj respectively

In addition, when initializing the GCN layer, it is necessary to determine the number of input features in_features and the number of output features out_features of each node

In this case, A represents the adjacency matrix with a dimension of 276*276, D ̂^−1/2A ̂D ̂^−1/2 is the normalized adjacency matrix, and its shape remains unchanged, still 276*276, That is, adj, one of the inputs of GCN. x represents the training set train X, in this case its dimension is batchsize*276*30. in_features represents the time step, which is the input 10 time steps, and the number of output features out_features can be adjusted as a parameter. In this case, it is set to 10. The entire GCN layer is shown below

The short-term passenger flow prediction model constructed is the superposition of the GCN layer and the ordinary convolutional layer. Among them, the inbound passenger flow in the three modes of weekly mode, daily mode, and real-time mode is respectively processed by the GCN layer, and then after feature superposition, CNN is used to The spatio-temporal features are extracted again, and then the fully connected layer is used to reduce the output result. The input shape of the model is batchsize*273*30, and the output shape is batchsize*276*1

5. Model Termination and Evaluation

The model termination part adopts early stopping technology, which has two main functions:

Use the verification set loss to save the current optimal model. When the model is trained to a certain standard, the model training is terminated.

When instantiating the EarlyStoping class, the __call__ function will be called automatically, and its input is the loss val_loss of the verification set, the parameter dictionary model_dict of the model, the model class model, the current iteration number epoch, and the save path save_path of the model

Regarding model evaluation, this case mainly uses four indicators of root mean square error RMSE, Pearson correlation coefficient R2, mean absolute error MAE, and weighted mean absolute percentage error WMAPE

This case provides evaluation functions for one-dimensional data and two-dimensional data respectively, that is, both the actual value and the predicted value are one-dimensional data, or both the actual value and the predicted value are two-dimensional data. The function input is the actual value and predicted value in the form of numpy.array, and the output value is the corresponding evaluation index

6. Model training and testing

During the training process, multiple models may be saved with the help of earlystopping technology. For the convenience of testing, in this case, the training and verification part is written in the main function, and the test part is rewritten as a function.

For each epoch, training is performed first, and then verification is performed. During the process, the training loss and verification loss are saved with the help of SummaryWriter, which can be visualized with the help of tensorboard. After each verification, use earlystopping to judge whether to save the current model and whether to terminate the model training. The criterion for saving the model is to save the current model as long as the loss of the verification set decreases. The criterion for terminating model training is to terminate the training process when the loss of the verification set exceeds 100 times and no longer decreases. In view of this, the epoch of the model It can be set as large as possible to prevent the model from terminating training prematurely

The code of the model testing part is slightly different, but it is roughly the same as the code in the training and testing process. The test process first needs to use the torch.load function to re-import the saved model, and then use the model.load_state_dict to load the saved parameter dictionary into the model. At this time, the parameters in the model are the trained parameters in the training process.

When testing, it is necessary to denormalize the predicted results to the magnitude of the original data for testing

7. Model training and result display

Model display:

The model training process shows:

 

Comparison of actual value and predicted value:

It can be seen that the fitting effect of the model is very accurate, especially in the case that some models usually have poor fitting effects on the maximum and minimum values, this model is also very accurate on the fitting of the maximum and minimum values 

 
 8. Code

The last part of the code is as follows. If you need all the codes and data sets, please like and follow the collection and leave a private message in the comment area~~~

main.py 

import numpy as np
import os, time, torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from utils.utils import GetLaplacian
from model.main_model import Model
from utils.earlystopping import EarlyStopping
from data.get_dataloader import get_inflow_dataloader, get_outflow_dataloader
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")

print(device)

epoch_num = 1000
lr = 0.001
time_interval = 15
time_lag = 10
tg_in_one_day = 72
forecast_day_number = 5
pre_len = 1
batch_size = 32
station_num = 276
model_type = 'ours'
TIMESTAMP = str(time.strftime("%Y_%m_%d_%H_%M_%S"))
save_dir = './save_model/' + model_type + '_' + TIMESTAMP
if not os.path.exists(save_dir):
	os.makedirs(save_dir)

inflow_data_loader_train, inflow_data_loader_val, inflow_data_loader_test, max_inflow, min_inflow = \
	get_inflow_dataloader(time_interval=time_interval, time_lag=time_lag, tg_in_one_day=tg_in_one_day, forecast_day_number=forecast_day_number, pre_len=pre_len, batch_size=batch_size)
outflow_data_loader_train, outflow_data_loader_val, outflow_data_loader_test, max_outflow, min_outflow = \
	get_outflow_dataloader(time_interval=time_interval, time_lag=time_lag, tg_in_one_day=tg_in_one_day, forecast_day_number=forecast_day_number, pre_len=pre_len, batch_size=batch_size)

# get normalized adj
adjacency = np.loadtxt('./data/adjacency.csv', delimiter=",")
adjacency = torch.tensor(GetLaplacian(adjacency).get_normalized_adj(station_num)).type(torch.float32).to(device)

global_start_time = time.time()
writer = SummaryWriter()


# 用于初始化卷积层的参数,可提升模型训练效果
def weights_init(m):
	classname = m.__class__.__name__
	if classname.find('Conv2d') != -1:
		nn.init.xavier_normal_(m.weight.data)
		nn.init.constant_(m.bias.data, 0.0)
	if classname.find('ConvTranspose2d') != -1:
		nn.init.xavier_normal_(m.weight.data)
		nn.init.constant_(m.bias.data, 0.0)


model = Model(time_lag, pre_len, station_num, device)
print(model)
model.apply(weights_init)
if torch.cuda.is_available():
	model.cuda()

model = model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
mse = torch.nn.MSELoss().to(device)

temp_time = time.time()
early_stopping = EarlyStopping(patience=100, verbose=True)
for epoch in range(0, epoch_num):
	# model train
	train_loss = 0
	model.train()
	for inflow_tr, outflow_tr in zip(enumerate(inflow_data_loader_train), enumerate(outflow_data_loader_train)):
		i_batch, (train_inflow_X, train_inflow_Y) = inflow_tr
		i_batch, (train_outflow_X, train_outflow_Y) = outflow_tr
		train_inflow_X, train_inflow_Y = train_inflow_X.type(torch.float32).to(device), train_inflow_Y.type(torch.float32).to(device)
		train_outflow_X, train_outflow_Y = train_outflow_X.type(torch.float32).to(device), train_outflow_Y.type(torch.float32).to(device)
		target = model(train_inflow_X, train_outflow_X, adjacency)
		loss = mse(input=train_inflow_Y, target=target)
		train_loss += loss.item()
		optimizer.zero_grad()
		loss.backward()
		optimizer.step()

	with torch.no_grad():
		# model validation
		model.eval()
		val_loss = 0
		for inflow_val, outflow_val in zip(enumerate(inflow_data_loader_val), enumerate(outflow_data_loader_val)):
			i_batch, (val_inflow_X, val_inflow_Y) = inflow_tr
			i_batch, (val_outflow_X, val_outflow_Y) = outflow_tr
			val_inflow_X, val_inflow_Y = val_inflow_X.type(torch.float32).to(device), val_inflow_Y.type(torch.float32).to(device)
			val_outflow_X, val_outflow_Y = val_outflow_X.type(torch.float32).to(device), val_outflow_Y.type(torch.float32).to(device)
			target = model(val_inflow_X, val_outflow_X, adjacency)
			loss = mse(input=val_inflow_Y, target=target)
			val_loss += loss.item()

	avg_train_loss = train_loss/len(inflow_data_loader_train)
	avg_val_loss = val_loss/len(inflow_data_loader_val)
	writer.add_scalar("loss_train", avg_train_loss, epoch)
	writer.add_scalar("loss_eval", avg_val_loss, epoch)
	print('epoch:', epoch, 'train Loss', avg_train_loss, 'val Loss:', avg_val_loss)

	if epoch > 0:
		# early stopping
		model_dict = model.state_dict()
		early_stopping(avg_val_loss, model_dict, model, epoch, save_dir)
		if early_stopping.early_stop:
			print("Early Stopping")
			break
	# 每10个epoch打印一次训练时间
	if epoch % 10 == 0:
		print("time for 10 epoches:", round(time.time() - temp_time, 2))
		temp_time = time.time()
global_end_time = time.time() - global_start_time
print("global end time:", global_end_time)

Train_time_ALL = []

Train_time_ALL.append(global_end_time)
np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_Train_time_ALL.txt', Train_time_ALL)
print("end")

main_predict.py

import numpy as np
import os, time, torch
from torch import nn
from torch.utils.tensorboard import SummaryWriter
from utils.utils import GetLaplacian
from model.main_model import Model
import matplotlib.pyplot as plt
from utils.metrics import Metrics, Metrics_1d
from data.get_dataloader import get_inflow_dataloader, get_outflow_dataloader

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print(device)

epoch_num = 1000
lr = 0.001
time_interval = 15
time_lag = 10
tg_in_one_day = 72
forecast_day_number = 5
pre_len = 1
batch_size = 32
station_num = 276
model_type = 'ours'
TIMESTAMP = str(time.strftime("%Y_%m_%d_%H_%M_%S"))
save_dir = './save_model/' + model_type + '_' + TIMESTAMP
if not os.path.exists(save_dir):
	os.makedirs(save_dir)

inflow_data_loader_train, inflow_data_loader_val, inflow_data_loader_test, max_inflow, min_inflow = \
	get_inflow_dataloader(time_interval=time_interval, time_lag=time_lag, tg_in_one_day=tg_in_one_day, forecast_day_number=forecast_day_number, pre_len=pre_len, batch_size=batch_size)
outflow_data_loader_train, outflow_data_loader_val, outflow_data_loader_test, max_outflow, min_outflow = \
	get_outflow_dataloader(time_interval=time_interval, time_lag=time_lag, tg_in_one_day=tg_in_one_day, forecast_day_number=forecast_day_number, pre_len=pre_len, batch_size=batch_size)

# get normalized adj
adjacency = np.loadtxt('./data/adjacency.csv', delimiter=",")
adjacency = torch.tensor(GetLaplacian(adjacency).get_normalized_adj(station_num)).type(torch.float32).to(device)

global_start_time = time.time()
writer = SummaryWriter()

model = Model(time_lag, pre_len, station_num, device)

if torch.cuda.is_available():
	model.cuda()

model = model.to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
mse = torch.nn.MSELoss().to(device)

path = 'D:/subway flow prediction_for book/save_model/1_ours2021_04_12_14_34_43/model_dict_checkpoint_29_0.00002704.pth'
checkpoint = torch.load(path)
model.load_state_dict(checkpoint, strict=True)
optimizer = torch.optim.Adam(model.parameters(), lr=lr)

# test
result = []
result_original = []
if not os.path.exists('result/prediction'):
	os.makedirs('result/prediction/')
if not os.path.exists('result/original'):
	os.makedirs('result/original')
with torch.no_grad():
	model.eval()
	test_loss = 0
	for inflow_te, outflow_te in zip(enumerate(inflow_data_loader_test), enumerate(outflow_data_loader_test)):
		i_batch, (test_inflow_X, test_inflow_Y, test_inflow_Y_original) = inflow_te
		i_batch, (test_outflow_X, test_outflow_Y, test_outflow_Y_original) = outflow_te
		test_inflow_X, test_inflow_Y = test_inflow_X.type(torch.float32).to(device), test_inflow_Y.type(torch.float32).to(device)
		test_outflow_X, test_outflow_Y = test_outflow_X.type(torch.float32).to(device), test_outflow_Y.type(torch.float32).to(device)

		target = model(test_inflow_X, test_outflow_X, adjacency)

		loss = mse(input=test_inflow_Y, target=target)
		test_loss += loss.item()

		# evaluate on original scale
		# 获取result (batch, 276, pre_len)
		clone_prediction = target.cpu().detach().numpy().copy() * max_inflow  # clone(): Copy the tensor and allocate the new memory
		# print(clone_prediction.shape)  # (16, 276, 1)
		for i in range(clone_prediction.shape[0]):
			result.append(clone_prediction[i])

		# 获取result_original
		test_inflow_Y_original = test_inflow_Y_original.cpu().detach().numpy()
		# print(test_OD_Y_original.shape)  # (16, 276, 1)
		for i in range(test_inflow_Y_original.shape[0]):
			result_original.append(test_inflow_Y_original[i])

	print(np.array(result).shape, np.array(result_original).shape)  # (num, 276, 1)
	# 取整&非负取0
	result = np.array(result).astype(np.int)
	result[result < 0] = 0
	result_original = np.array(result_original).astype(np.int)
	result_original[result_original < 0] = 0
	# # 保存为一个npy文件
	# np.save("result/prediction/result.npy", np.array(result))
	# np.save("result/original/result_original.npy", np.array(result_original))
	# # 每一个时间步保存为一个OD矩阵
	# for i in range(np.array(result).shape[0]):
	# 	np.savetxt("result/prediction/" + str(i) + ".csv", result[i], delimiter=",")
	# 	np.savetxt("result/original/" + str(i) + "_original.csv", result_original[i], delimiter=",")
	#
	# # 取出多个车站进行画图   # (num, 276, 1)   # (num, 276, 2)  # (num, 276, 3)
	x = [[], [], [], [], []]
	y = [[], [], [], [], []]
	for i in range(result.shape[0]):
		x[0].append(result[i][4][0])
		y[0].append(result_original[i][4][0])
		x[1].append(result[i][18][0])
		y[1].append(result_original[i][18][0])
		x[2].append(result[i][30][0])
		y[2].append(result_original[i][30][0])
		x[3].append(result[i][60][0])
		y[3].append(result_original[i][60][0])
		x[4].append(result[i][94][0])
		y[4].append(result_original[i][94][0])
	result = np.array(result).reshape(station_num, -1)
	result_original = result_original.reshape(station_num, -1)

	RMSE, R2, MAE, WMAPE = Metrics(result_original, result).evaluate_performance()

	avg_test_loss = test_loss / len(inflow_data_loader_test)
	print('test Loss:', avg_test_loss)

	RMSE_y0, R2_y0, MAE_y0, WMAPE_y0 = Metrics_1d(y[0], x[0]).evaluate_performance()
	RMSE_y1, R2_y1, MAE_y1, WMAPE_y1 = Metrics_1d(y[1], x[1]).evaluate_performance()
	RMSE_y2, R2_y2, MAE_y2, WMAPE_y2 = Metrics_1d(y[2], x[2]).evaluate_performance()
	RMSE_y3, R2_y3, MAE_y3, WMAPE_y3 = Metrics_1d(y[3], x[3]).evaluate_performance()
	RMSE_y4, R2_y4, MAE_y4, WMAPE_y4 = Metrics_1d(y[4], x[4]).evaluate_performance()

# L3, = plt.plot(x[0], color="r")
# L4, = plt.plot(y[0], color="b")
# plt.legend([L3, L4], ["L3-prediction", "L4-true"], loc='best')
# plt.show()

ALL = [RMSE, MAE, WMAPE]
y0_ALL = [RMSE_y0, MAE_y0, WMAPE_y0]
y1_ALL = [RMSE_y1, MAE_y1, WMAPE_y1]
y2_ALL = [RMSE_y2, MAE_y2, WMAPE_y2]
y3_ALL = [RMSE_y3, MAE_y3, WMAPE_y3]
y4_ALL = [RMSE_y4, MAE_y4, WMAPE_y4]

np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_ALL.txt', ALL)
np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_y0_ALL.txt', y0_ALL)
np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_y1_ALL.txt', y1_ALL)
np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_y2_ALL.txt', y2_ALL)
np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_y3_ALL.txt', y3_ALL)
np.savetxt('result/lr_' + str(lr) + '_batch_size_' + str(batch_size) + '_y4_ALL.txt', y4_ALL)
np.savetxt('result/X_original.txt', x)
np.savetxt('result/Y_prediction.txt', y)

print("ALL:", ALL)
print("y0_ALL:", y0_ALL)
print("y1_ALL:", y1_ALL)
print("y2_ALL:", y2_ALL)
print("y3_ALL:", y3_ALL)
print("y4_ALL:", y4_ALL)

print("end")

x = x[0]
y = y[0]
L1, = plt.plot(x, color="r")
L2, = plt.plot(y, color="y")
plt.legend([L1, L2], ["pre", "actual"], loc='best')
plt.show()

It's not easy to create and find it helpful, please like, follow and collect~~~

Guess you like

Origin blog.csdn.net/jiebaoshayebuhui/article/details/130454177