You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中LSTM实现遇数据基数歧义ValueError问题求助

LSTM分类变长车辆速度曲线的报错解决

问题背景

作为机器学习新手,尝试用LSTM神经网络分类车辆速度曲线。现有某路段车辆速度数据,因交通状况与红绿灯差异,不同车辆的速度记录条数不一(每秒记录一次,快速通过的记录少,耗时久的记录多)。原以为LSTM支持变长数据,但运行代码时出现「ValueError: Data cardinality is ambiguous」错误,尝试多种数据结构仍未解决。

原代码

import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras.layers import LSTM
import fileLayout as fl


tf.random.set_seed(7)

filename = "segmentedData.csv"
csv = pd.read_csv(filename, sep = fl.delimeter)

filename = "Clusters.csv"
clstr = pd.read_csv(filename, sep = fl.delimeter)

csv = csv[csv["segment"] == "T1"]

stations = csv["fullID"].drop_duplicates()
stations = [station for station in stations]

x = []
y = []

for station in stations :
    clcsv = csv[csv["fullID"] == station]
    clcsv = clcsv["speedvalue"].to_numpy()
    x.append(clcsv)
    ytemp = clstr[clstr["stationId"] == station]
    ytemp = ytemp["class"].iloc[0]
    y.append(ytemp)
    
y = np.asarray(y).astype(np.int)

model = Sequential()
model.add(LSTM(128))
model.add(Dense(3))
model.compile(loss='mean_squared_error', optimizer='adam')

model.fit(x, y, epochs=100, batch_size=1, verbose=2)

遇到的错误

  1. 数据基数模糊错误:
ValueError: Data cardinality is ambiguous: x sizes: 17, 20, 5, 20, 17, 45, 21, 60, 8, 6, 28, 51, 6, 40, 78, 73, 66, 26, 32, 8, 12, 11, 22, 10, 36, 84, 2, 11, 18, 31, 32, 8, 25, 20, 17, 36, 11, 11, 4, 14, 18, 8, 46, 53, 19, 34, 13, 25, 38, 20, 11, 14, 27, 29, 56, 43, 31, 130, 63, 184, 13, 13, 32, 22, 14, 12, 10, 23, 35, 17, 34 y sizes: 71 Make sure all arrays contain the same number of samples.
  1. NumPy数组转张量失败错误:
ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type numpy.ndarray).

错误原因

  • 第一个错误:Keras的fit方法要求输入数据维度统一,即使batch_size=1,也不能直接传入嵌套的不等长NumPy数组列表,系统无法识别这是71个样本的变长序列,反而误判为多个不同长度的输入数组,导致样本数不匹配。
  • 第二个错误:输入的x是包含多个NumPy数组的列表,这种嵌套结构无法直接转换为TensorFlow张量,TensorFlow要求输入是形状统一的张量或可标准化的数据结构。

解决方案

针对变长序列的LSTM处理,最适合新手的是填充法:将所有序列填充到最长序列的长度,再通过Masking层让LSTM忽略填充值,不影响模型学习。同时调整模型的损失函数和输出层激活函数,适配分类任务。

修改后的代码

import numpy as np
import pandas as pd
import tensorflow as tf
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, LSTM, Masking
import fileLayout as fl

tf.random.set_seed(7)

# 加载数据
filename = "segmentedData.csv"
csv = pd.read_csv(filename, sep=fl.delimeter)

filename = "Clusters.csv"
clstr = pd.read_csv(filename, sep=fl.delimeter)

csv = csv[csv["segment"] == "T1"]

stations = csv["fullID"].drop_duplicates().tolist()

x = []
y = []

for station in stations:
    # 提取单辆车的速度序列
    speed_seq = csv[csv["fullID"] == station]["speedvalue"].to_numpy()
    x.append(speed_seq)
    # 提取对应标签
    label = clstr[clstr["stationId"] == station]["class"].iloc[0]
    y.append(label)

y = np.asarray(y).astype(np.int)

# 处理变长序列:填充至最长序列长度
max_seq_length = max([len(seq) for seq in x])
# 用0填充序列末尾,也可根据数据特性选择均值等其他值
x_padded = np.array([np.pad(seq, (0, max_seq_length - len(seq)), mode='constant') for seq in x])
# 转换为LSTM要求的三维输入格式:(样本数, 时间步长, 特征数),这里特征数为1(仅速度)
x_padded = x_padded.reshape(x_padded.shape[0], x_padded.shape[1], 1)

# 构建带Masking层的模型
model = Sequential()
# Masking层:指定填充值为0,LSTM会跳过这些位置的计算
model.add(Masking(mask_value=0., input_shape=(max_seq_length, 1)))
model.add(LSTM(128))
# 分类任务用softmax激活,输出3类概率
model.add(Dense(3, activation='softmax'))
# 损失函数用sparse_categorical_crossentropy(适配整数类型的标签)
model.compile(loss='sparse_categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 训练模型
model.fit(x_padded, y, epochs=100, batch_size=1, verbose=2)

关键修改点

  1. 序列填充与格式转换:将所有速度序列统一长度,并调整为LSTM要求的三维输入形状,解决张量转换问题。
  2. 加入Masking层:让LSTM忽略填充的无效值,保证模型仅学习有效速度序列的特征。
  3. 适配分类任务:将输出层改为softmax激活,损失函数替换为sparse_categorical_crossentropy,原代码用回归损失(mean_squared_error)不适合分类场景。

进阶方案(可选)

若不想填充序列,可使用tf.data.Dataset处理变长数据,适合数据量较大的场景:

# 将数据转换为tf.data.Dataset
dataset = tf.data.Dataset.from_generator(
    lambda: zip(x, y),
    output_signature=(
        tf.TensorSpec(shape=(None,), dtype=tf.float32),  # 变长序列
        tf.TensorSpec(shape=(), dtype=tf.int32)          # 标签
    )
)
# 为每个序列增加特征维度(变为(时间步, 1))
dataset = dataset.map(lambda seq, label: (tf.expand_dims(seq, -1), label))
# 按批次填充序列(自动统一批次内的序列长度)
dataset = dataset.padded_batch(32, padded_shapes=((None, 1), ()))

# 训练模型
model.fit(dataset, epochs=100, verbose=2)

内容的提问来源于stack exchange,提问作者Mohamed Lamine Benzagouta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 01:42:25