LSTM 预处理:基于 ID 从 pandas 数据帧构建 3d 数组

Posted

技术标签:

【中文标题】LSTM 预处理:基于 ID 从 pandas 数据帧构建 3d 数组【英文标题】:LSTM preprocessing: Build 3d arrays from pandas data frame based on ID 【发布时间】:2018-09-23 00:24:33 【问题描述】:

我是 keras 机器学习的新手,我正计划进行机器学习实验,基于具有 lstm 层的递归神经网络预测视频游戏比赛中购买的前十个物品的序列。

假设给定一个由gameIdsidetimestamp预先排序的示例表:

       gameId   side   timestamp  itemId 
   3030038208    100        4260    1055 
   3030038208    100        4648    2010 
   3030038208    100        5036    3340 
   3030038208    100      291561    1001 
   3030038208    100      295807    1083 
   3030038208    100      296457    2010 
   3030038208    200        3257    1055 
   3030038208    200        3516    2003 
   3030038208    200        3775    3340 
   3030038208    200      321461    1038 
   3030038208    200      321818    2003 
   3030038208    200      321979    2003 
   3030038208    200      491099    3006 
   3030038208    200      492238    1042 
   3030038208    200      743864    3086 
   3030038208    200      744773    1043
         ....

我现在想将数据框重塑为两个(x 和 y)3d numpy 数组,其中第三维描述购买序列的长度 (ItemId) - 这样基本上每个 2d numpy 数组中结果序列构成相同gameIdside对的表

在训练神经网络之前,我还需要插入一个填充,因为上面提到的时间序列是 10。在这个例子中,填充值 0 似乎没问题,但是在实际场景中,我使用的是稀疏的包含大量 0 值的矩阵。

现在这里有一些问题:

1) 是否有任何用于 numpy、pandas 甚至 keras 的内置函数来有效地实现我的既定目标。我想不出不用花很长时间才能提出合理的预处理功能的东西。

2) 还有其他需要注意的事项吗?特别是在填充的情况下。处理稀疏矩阵时,填写“-999”会不会更有意义?

3) 假设模型看起来像这样

model = Sequential()
model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2, input_dim=1))
model.add(Dense(y.shape[1], activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
monitor = EarlyStopping(monitor='val_loss', min_delta=1e-3, patience=5, verbose=0, mode='auto')
checkpointer = ModelCheckpoint(filepath=filepath + "best_weights.hdf5", verbose=0, save_best_only=True)

与:

history = model.fit(x_train, y_train, epochs=2, validation_split=0.33, callbacks=[monitor, checkpointer], verbose=0).history

我如何才能正确使用处理填充的遮罩层?

提前感谢您在该线程上花费的任何时间!

编辑: 根据要求,这里是生成的 numpy 数组(我认为)我想得到,以便根据 timestamp 预测 itemId,在 keras 填充前使用带有 lstm 层的神经网络:

y = [
[1055, 2010, 3340, 1001, 1083, 2010],
[1055, 2003, 3340, 1038, 2003, 2003, 3006, 1042, 3086, 1043],
...
]

x = [
[[4260], [4648], [5036], [291561], [295807], [296457]],
[[3257], [3516], [3775], [321461], [321818], [321979], [491099], [492238], [743864], [744773] ],
...
]

之后填充:

y = [
[1055, 2010, 3340, 1001, 1083, 2010, 0, 0, 0, 0],
[1055, 2003, 3340, 1038, 2003, 2003, 3006, 1042, 3086, 1043],
...
]

x = [
[[4260], [4648], [5036], [291561], [295807], [296457], [0], [0], [0], [0]],
[[3257], [3516], [3775], [321461], [321818], [321979], [491099], [492238], [743864], [744773] ],
...
]

但是,在实际示例中,将有更多的功能,而不仅仅是时间戳

【问题讨论】:

您能否添加 x 和 y 的预期 numpy 数组的样子,以及考虑到您的 lstm 的当前结构,为什么 y 是 3d 你是对的,考虑到时间步长,在这种情况下 y 将是二维的。更正了。 你的 x 和 y 是多少? 时间戳和 itemId。我在原帖的编辑版本中设置了一个示例。 【参考方案1】:

您可以通过从 pandas groupby 对象中提取数据通过几个步骤来实现此目的。在前两个步骤中,我们将创建 groupby 对象,以便稍后在代码中对其进行操作。从 groupby 对象中,我们将找到最大的组,以便我们可以相应地填充零

gb = df.groupby(['gameId','side']) # Create Groupby object
mx = gb['side'].size().max() # Find the largest group

创建 x 和 y 的步骤非常相似。我们可以使用列表推导遍历每个组,将数据帧转换为 numpy 数组并使用 np.pad() 填充零。然后将每个数组重塑为 3d

x = np.array([np.pad(frame['timestamp'].values,
                     pad_width=(0,mx-len(frame)),
                     mode='constant',
                     constant_values=0) 
                     for _,frame in gb]).reshape(-1,mx,1)

y = np.array([np.pad(frame['itemId'].values,
                     pad_width=(0,mx-len(frame)),
                     mode='constant',
                     constant_values=0) 
                     for _,frame in gb]).reshape(-1,mx,1)

在此示例中,设置用于多对多 lstm。在 cmets 中,我指出您当前的设置不支持 3d 输出值,因为在 lstm 层中您没有参数 return_sequence=True

不清楚您在此问题中要查找的结构。在决定使用哪个 LSTM 网络时,我喜欢参考下图。上面的代码将支持多对多网络,假设您将return_sequence=True 添加到您的 LSTM 层。如果您想要多对一,请从 y 中删除 .reshape(-1,mx,1),现在您有一个带有 mx 输出的网络。


对于任一设置,您都需要修改模型的 input_shape 参数。此参数必须指定 x 的第二和第三维度的形状,即

                                                        # v Use input_shape here
model.add(LSTM(128, dropout=0.2, recurrent_dropout=0.2, input_shape=x.shape[1:]))

【讨论】:

感谢您的详细解释:关于问题的基数,我的猜测是多对多 lstm 层,因为我希望预测器根据一组时间戳。但是,我忘了提到之前在我的另一个 keras 神经网络中,我曾经对 y 进行一次热编码。在这种情况下它甚至会是一个问题,还是将pd.get_dummies(frame['itemId'])values而不是frame['itemid'].values足够有效?另外,当这些是 3d 时,我将如何将数据拆分为训练和测试? train_test_split 能完成这项工作吗? 使用 get dummines 的问题是,如果每个组没有所有类别,则值将无法对齐。您应该使用 sklearns 分类编码器,将其拟合到唯一值 itemId 和零,因为这是填充值,然后您可以将这些值拟合到列表理解中。 @DJK 如果我们在应用 groupby 操作之前应用 pd.get_dummies,那么我认为他们应该没有问题,如果所有组都没有所有类别。 @DJK 我也有类似的问题。如果我有更多功能,那么我需要在代码中进行哪些更改来制作数组 x?我是否需要创建多个数组并将它们连接起来,或者它们是其他一些简单的解决方案。 LSTM层的input_shape参数应该怎么改? 有了这个答案(我很欣赏),填充将添加到宽度和高度...只添加到高度,我将 pad_width 更改为:pad_width=((0, mx-len(frame)),(0,0))

以上是关于LSTM 预处理:基于 ID 从 pandas 数据帧构建 3d 数组的主要内容,如果未能解决你的问题,请参考以下文章

如何从 pandas 数据帧在 tensorflow v1 中实现 LSTM

基于LSTM+FCN处理多变量时间序列问题记录

自然语言处理(NLP)基于LSTM的命名实体识别

基于pytorch搭建多特征LSTM时间序列预测代码详细解读(附完整代码)

基于pytorch的LSTM进行字符级文本生成实战

Pandas学习笔记02处理数据实用操作