LSTM预处理:根据ID

时间:2018-04-12 18:20:28

标签: python pandas numpy keras lstm

我是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数组(我想)我想得到的是基于itemId基于timestamp预测带有lstm图层的神经网络在keras 之前填充

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] ],
...
]

但是,在实际示例中,除了时间戳之外,还有更多功能。

1 个答案:

答案 0 :(得分:4)

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

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

创建x&的步骤你非常相似。我们可以使用列表推导来遍历每个组,将数据帧转换为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。在评论中我指出您当前的设置不支持3d输出值,因为在lstm层中您没有参数return_sequence=True

目前还不清楚你在寻找这个问题的结构。在决定使用哪个LSTM网络时,我想咨询下面的图像。假设您将return_sequence=True添加到LSTM图层,上面的代码将支持多对多网络。如果您想要多对一,请从y中删除.reshape(-1,mx,1),现在您的网络输出为mx

enter image description here

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

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