在校正数据上训练全连接多层神经网络
本例将讨论数据处理和在修正数据上训练神经网络模型。将演示一种滑动窗口方法,将训练样本和测试样本划分为训练数据集,并确定模型参数,以获得最准确的预测结果。
启动必要的库:
Pkg.add(["Statistics", "CSV", "Flux", "Optimisers"])
using Statistics
using CSV
using DataFrames
using Flux
using Plots
using Flux: train!
using Optimisers
准备培训和测试样本
加载用于训练模型的数据
df = DataFrame(CSV.File("$(@__DIR__)/data.csv"));
运行示例 /start/examples/data_analysis/data_processing.ipynb后保存了数据。
形成训练数据集:
整个数据集被分为训练样本和测试样本。训练样本占整个数据集的 0.8,测试样本占 0.2。
T = df[1:1460,3]; # определение обучающего набора данных, весь датасет 1825 строк
first(df, 5)
将向量 T 分成每批 100 个观测值:
batch_starts = 1:1:1360 # определение диапазона для цикла
weather_batches = [] # определение пустого массива для записи результатов выполнения цикла
for start in batch_starts
dop = T[start:start+99] # батч на текущем временном шаге
weather_batches = vcat(weather_batches, dop) # запись батча в массив
end
批次是一个小数据集,可作为建立预测模型的训练集。它采用滑动窗口法从初始训练集 T 中提取。
滑动窗口法:

其中,x 是观测值,y1 是预测值。
将获得的数据集转换为矢量字符串:
weather_batches = weather_batches'
改变数组的形状,使其与上述分批集合的长度相匹配:
weather_batches = reshape(weather_batches, (100,:))
X = weather_batches # переприсвоение
定义目标值数组
Y = (T[101:1460]) # отсчёт начинается с 101, так как предыдущие 100 наблюдений используются в качестве исходных данных
Y = Y'
转换成神经网络可接受的处理格式:
X = convert(Array{Float32}, X)
Y = convert(Array{Float32}, Y)
形成测试数据集:
将测试样本分成长度为 100 个观测值的批次:
X_test = df[1461:1820, 3] # определение тестового набора данных
batch_starts_test = 1:1:261 # определение диапазона для цикла
test_batches = [] # определение пустого массива для записи результатов выполнения цикла
for start in batch_starts_test
dop = X_test[start:start+99] # батч на текущем временном шаге
test_batches = vcat(test_batches, dop) # запись батча в массив
end
test_batches = reshape(test_batches, (100,:)) # изменение формы массива для соответствия длине батча, указанной выше:
X_test = convert(Array{Float32}, test_batches) # преобразование в формат приемлимый для обработки нейросетью
构建和训练神经网络
定义神经网络的结构:
model = Flux.Chain(
Dense(100 => 50, elu),
Dense(50 => 25, elu),
Dense(25 => 5, elu),
Dense(5 => 1)
)
确定训练参数
# Инициализация оптимизатора
learning_rate = 0.001f0
opt = Optimisers.Adam(learning_rate)
state = Optimisers.setup(opt, model) # Создание начального состояния
# Функция потерь
loss(model, x, y) = Flux.mse(model(x), y)
训练模型
loss_history = []
epochs = 200
for epoch in 1:epochs
# Вычисление градиентов
grads = gradient(model) do m
loss(m, X, Y)
end
# Обновление модели и состояния
state, model = Optimisers.update(state, model, grads[1])
# Расчет и сохранение потерь
current_loss = loss(model, X, Y)
push!(loss_history, current_loss)
# Вывод потерь на каждом шаге
if epoch == 1 || epoch % 10 == 0
println("Epoch $epoch: Loss = $current_loss")
end
end
可视化损失函数的变化
plot((1:epochs), loss_history, title="Изменение функции потерь", xlabel="Эпоха", ylabel="Функция потерь")
获取预测值
y_hat_raw = model(X_test) # загрузка тестовой выборки в модель, получение прогноза
y_pred = y_hat_raw'
y_pred = y_pred[:,1]
y_pred = convert(Vector{Float64}, y_pred)
first(y_pred, 5)
预测值的可视化
days = df[:,1] # формирование массива дней, начиная с первого наблюдения
first(days, 5)
连接后台 - 图表显示方法
plotlyjs()
从初始数据集生成一个数据集进行比较:
df_T = df[:, 3]#df[1471:1820, 3]
first(df_T, 5)
使用初始数据和预测数据绘制温度与时间的关系图:
plot(days, df_T)#plot(days, T[11:end]) #T[11:end]
plot!(days[1560:1820], y_pred)
由于原始数据集中有缺失值被线性插值替代的区域,因此很难在一条直线上评估训练有素的神经网络模型的性能。
为此,我们加载了没有缺失值的真实数据:
real_data = DataFrame(CSV.File("$(@__DIR__)/real_data.csv"));
使用真实数据和预测数据绘制温度与时间的关系图:
plot(real_data[1:261,2])
plot!(y_pred)
让我们利用皮尔逊相关性来检查所得数值之间的关系,从而评估所获得模型的准确性:
corr_T = cor(y_pred,real_data[1:261,2])
皮尔逊相关系数的取值范围为-1 到 1,其中 0 表示变量之间没有关系,-1 和 1 表示关系密切(分别为反向依赖和直接依赖)。
结论
本案例研究对过去五年的温度观测数据进行了预处理,并确定了神经网络结构、优化器参数和损失函数。
对模型进行了训练,结果表明,预测值与真实数据的收敛性相当高,但并不完美。为了提高预测质量,可以通过改变层的结构和增加训练样本来修改神经网络。