trainnetwork中出现如下报错:错误使用 trainNetwork,训练序列具有特征维度 10 9,但输入层需要特征维度为 9 的序列,如何解决?
运行到182 行时特征数为9:“原始输入特征维度: 样本数×特征数 = 43359x9
训练序列数据维度: 时间步×特征数×序列数 = 10x9x30342
模型输入层期望的特征数: 9
训练前最终检查 - 训练数据维度: 10x9x30342
训练前最终检查 - 特征维度位置的值: 9 (应等于9)”
但运行到199行时出现“错误使用 trainNetwork
训练序列具有特征维度 10 9,但输入层需要特征维度为 9 的序列。
出错 ZTD4 (第 182 行)
trainedModel = trainNetwork(XTrain, YTrain, layers, options);
”
% 基于LSTM神经网络的ZTD预测模型
% 输入参数:温度(Ts)、水汽压(e)、气压(P)、纬度、经度、高度、年、年积日、小时
% 输出参数:ZTD值
clear; clc; close all;
%% 1. 数据准备
stationFiles = {'56691+.xlsx', '56739+.xlsx', '56778+.xlsx', ...
'56964+.xlsx', '56985+.xlsx', '57816+.xlsx'};
allData = [];
for i = 1:length(stationFiles)
data = readtable(stationFiles{i}, 'VariableNamingRule', 'preserve');
disp(['站点', num2str(i), '的变量名:']);
disp(data.Properties.VariableNames);
variables = {
'mjd', '约化儒略日';
'Ts', 'Ts';
'longitude', '经度';
'latitude', '纬度';
'height', '测站高';
'doy', '年积日';
'ztd', 'ZTD';
'P', 'P';
};
extracted = struct();
for j = 1:size(variables, 1)
varName = variables{j, 1};
colName = variables{j, 2};
if ~ismember(colName, data.Properties.VariableNames)
error(['站点', num2str(i), '中不存在列:', colName]);
end
[numericData, hasErrors] = convertToNumeric(data.(colName), true);
if hasErrors
warning(['站点', num2str(i), '的"', colName, '"列包含非数值数据,已替换为NaN']);
end
validRows = ~isnan(numericData);
numericData = numericData(validRows);
extracted.(varName) = numericData(:);
end
% 计算年份
jd = extracted.mjd + 2400000.5;
matlab_datenum = jd - 1721058.5;
date_vec = datevec(matlab_datenum);
year = date_vec(:,1);
year = year(:);
% 计算小时
hour = (extracted.mjd - floor(extracted.mjd)) * 24;
hour = hour(:);
% 处理水汽压e
if ismember('e', data.Properties.VariableNames)
[e, eErrors] = convertToNumeric(data.e, true);
if eErrors
warning(['站点', num2str(i), '的"e"列包含非数值数据,已替换为NaN']);
end
e = e(validRows);
e = e(:);
else
e = 0.06108 * exp((17.625 * extracted.Ts) / (extracted.Ts + 243.04));
disp('注意:使用温度计算水汽压,请确认是否有直接的e数据可用');
end
% 检查变量长度一致性
checkVariableLengths({extracted.longitude, extracted.latitude, extracted.height, ...
year, extracted.doy, hour, extracted.Ts, e, extracted.P, extracted.ztd});
% 组织输入特征(9个)和输出
inputFeatures = [extracted.longitude, extracted.latitude, extracted.height, ...
year, extracted.doy, hour, extracted.Ts, e, extracted.P];
outputZTD = extracted.ztd;
stationData = [inputFeatures, outputZTD];
allData = [allData; stationData];
fprintf('站点%d数据处理完成,有效样本数:%d,输入特征数:%d\n', ...
i, size(stationData, 1), size(inputFeatures, 2));
end
if isempty(allData)
error('没有有效的数据可供处理,请检查输入文件');
end
%% 2. 数据预处理
X = allData(:, 1:9); % 9个输入特征
Y = allData(:, 10); % ZTD输出
fprintf('原始输入特征维度: 样本数×特征数 = %dx%d\n', size(X));
% 数据归一化
[X_norm, xMean, xStd] = normalize(X);
[Y_norm, yMean, yStd] = normalize(Y);
% 划分数据集
rng(42);
n = size(X_norm, 1);
idx = randperm(n);
trainRatio = 0.7;
valRatio = 0.1;
testRatio = 0.2;
trainIdx = idx(1:floor(trainRatio*n));
valIdx = idx(floor(trainRatio*n)+1:floor((trainRatio+valRatio)*n));
testIdx = idx(floor((trainRatio+valRatio)*n)+1:end);
X_train = X_norm(trainIdx, :);
Y_train = Y_norm(trainIdx, :);
X_val = X_norm(valIdx, :);
Y_val = Y_norm(valIdx, :);
X_test = X_norm(testIdx, :);
Y_test = Y_norm(testIdx, :);
% 转换为LSTM输入格式
sequenceLength = 10;
% 准备序列数据(修正版本)
[XTrain, YTrain] = prepareData(X_train, Y_train, sequenceLength);
[XVal, YVal] = prepareData(X_val, Y_val, sequenceLength);
[XTest, YTest] = prepareData(X_test, Y_test, sequenceLength);
% **关键检查:确保 XTrain 的特征维度为 9**
if size(XTrain, 2) ~= 9
error(['训练数据特征数为 ', num2str(size(XTrain, 2)), ',应为 9']);
end
% 显示序列数据维度(关键检查)
fprintf('训练序列数据维度: 时间步×特征数×序列数 = %dx%dx%d\n', size(XTrain));
fprintf('模型输入层期望的特征数: %d\n', 9);
% % 检查序列数据有效性
% if isempty(XTrain) || isempty(YTrain)
% error('无法生成有效的序列数据,请减小sequenceLength');
% end
%
% % 显示序列数据维度(关键检查)
% fprintf('训练序列数据维度: 时间步×特征数×序列数 = %dx%dx%d\n', size(XTrain));
% fprintf('模型输入层期望的特征数: %d\n', 9);
%% 3. 构建LSTM模型
inputSize = 9; % 输入特征数
hiddenSize = 50;
outputSize = 1;
layers = [ ...
sequenceInputLayer(inputSize) % 明确接收9维特征
lstmLayer(hiddenSize)
fullyConnectedLayer(outputSize)
regressionLayer];
%% 4. 训练模型前的最终维度验证
if size(XTrain, 2) ~= inputSize
error(['维度不匹配:训练数据特征数为', num2str(size(XTrain, 2)), ...
',模型需要', num2str(inputSize), '个特征']);
end
% 再次确认维度信息
fprintf('训练前最终检查 - 训练数据维度: %dx%dx%d\n', size(XTrain));
fprintf('训练前最终检查 - 特征维度位置的值: %d (应等于9)\n', size(XTrain, 2));
options = trainingOptions('adam', ...
'MaxEpochs', 50, ...
'MiniBatchSize', 64, ...
'Shuffle', 'every-epoch', ...
'Verbose', 1, ...
'Plots', 'training-progress', ...
'ValidationData', {XVal, YVal});
% 训练模型
trainedModel = trainNetwork(XTrain, YTrain, layers, options);
%% 5. 模型预测与评估
YPred = predict(trainedModel, XTest);
% 反归一化
YPred_actual = YPred * yStd + yMean;
YTest_actual = YTest * yStd + yMean;
% 计算评估指标
rmse = sqrt(mean((YPred_actual - YTest_actual).^2));
mae = mean(abs(YPred_actual - YTest_actual));
r2 = 1 - sum((YTest_actual - YPred_actual).^2) / sum((YTest_actual - mean(YTest_actual)).^2);
fprintf('测试集评估结果:\n');
fprintf('RMSE: %.4f\n', rmse);
fprintf('MAE: %.4f\n', mae);
fprintf('R²: %.4f\n', r2);
%% 6. 结果可视化
figure;
plot(YTest_actual, 'b', 'LineWidth', 1.2);
hold on;
plot(YPred_actual, 'r--', 'LineWidth', 1.2);
xlabel('样本索引');
ylabel('ZTD值');
title('ZTD预测值与实际值对比');
legend('实际值', '预测值');
grid on;
figure;
scatter(YTest_actual, YPred_actual);
hold on;
plot([min(YTest_actual), max(YTest_actual)], [min(YTest_actual), max(YTest_actual)], 'r--');
xlabel('实际ZTD值');
ylabel('预测ZTD值');
title('预测值 vs 实际值');
grid on;
%% 辅助函数
function [num, hasErrors] = convertToNumeric(var, allowNaN)
hasErrors = false;
num = [];
try
if iscell(var)
num = cellfun(@str2double, var);
elseif isstring(var) || ischar(var)
num = str2double(var);
elseif iscategorical(var)
num = double(var);
elseif isnumeric(var)
num = var;
else
num = double(var);
end
if any(isnan(num))
hasErrors = true;
if ~allowNaN
error('存在无法转换为数值的数据');
end
end
catch
hasErrors = true;
if allowNaN
num = NaN(size(var));
else
rethrow(lasterror);
end
end
end
function checkVariableLengths(vars)
lengths = cellfun(@length, vars);
uniqueLengths = unique(lengths);
if length(uniqueLengths) > 1
error(['变量长度不一致: ', num2str(uniqueLengths)]);
end
end
% 修正的序列准备函数(确保维度顺序正确)
function [XSequence, YSequence] = prepareData(X, Y, sequenceLength)
numObservations = size(X, 1); % 样本数量
numFeatures = size(X, 2); % 特征数量(必须为9)
% 检查输入特征数是否正确
if numFeatures ~= 9
error(['输入特征数错误:实际为', num2str(numFeatures), ',期望为9']);
end
numSequences = numObservations - sequenceLength + 1;
if numSequences <= 0
XSequence = [];
YSequence = [];
warning('数据量不足,无法生成序列,请减小sequenceLength');
return;
end
% 初始化序列数据 (时间步 × 特征数 × 序列数)
XSequence = zeros(sequenceLength, numFeatures, numSequences);
YSequence = zeros(numSequences, 1);
% 填充序列数据
for i = 1:numSequences
% 提取连续的sequenceLength个样本,形状为[sequenceLength × numFeatures]
sequenceData = X(i:i+sequenceLength-1, :);
% 强制检查提取的序列维度
if size(sequenceData, 1) ~= sequenceLength
error(['第', num2str(i), '个序列时间步错误:实际', num2str(size(sequenceData, 1)), ...
',期望', num2str(sequenceLength)]);
end
if size(sequenceData, 2) ~= numFeatures
error(['第', num2str(i), '个序列特征数错误:实际', num2str(size(sequenceData, 2)), ...
',期望', num2str(numFeatures)]);
end
% 确保数据维度正确 - 转置以保证特征数为第二维
XSequence(:, :, i) = sequenceData;
YSequence(i) = Y(i + sequenceLength - 1);
end
% 最终验证序列数据的维度顺序
if size(XSequence, 1) ~= sequenceLength || size(XSequence, 2) ~= numFeatures
error(['序列数据维度顺序错误:实际为', num2str(size(XSequence)), ...
',正确应为[', num2str(sequenceLength), '×', num2str(numFeatures), '×N]']);
end
end