我想为我的类别特征构建一个带有嵌入的一层LSTM模型。我目前有数值特征和一些类别特征,例如位置,由于计算复杂性,无法进行独热编码,例如使用pd.get_dummies()
,这本来是我最初打算做的。
让我们看一个例子:
样本数据
data = { 'user_id': [1,1,1,1,2,2,3], 'time_on_page': [10,20,30,20,15,10,40], 'location': ['London','New York', 'London', 'New York', 'Hong Kong', 'Tokyo', 'Madrid'], 'page_id': [5,4,2,1,6,8,2]}d = pd.DataFrame(data=data)print(d) user_id time_on_page location page_id0 1 10 London 51 1 20 New York 42 1 30 London 23 1 20 New York 14 2 15 Hong Kong 65 2 10 Tokyo 86 3 40 Madrid 2
让我们来看一个人访问网站的情况。我正在跟踪页面上的时间等数值数据。类别数据包括:位置(超过1000个唯一值)、页面ID(超过1000个唯一值)、作者ID(100多个唯一值)。最简单的解决方案是将所有内容进行独热编码,并将其放入具有可变序列长度的LSTM中,每个时间步对应于不同的页面查看。
上面的DataFrame将生成7个训练样本,具有可变的序列长度。例如,对于user_id=2
,我将有2个训练样本:
[ ROW_INDEX_4 ] and [ ROW_INDEX_4, ROW_INDEX_5 ]
设X
为训练数据,让我们看第一个训练样本X[0]
。
从上图可以看出,我的类别特征是X[0][:, n:]
。
在创建序列之前,我使用pd.factorize()
将类别变量因子化为[0,1... number_of_cats-1]
,因此X[0][:, n:]
中的数据是与其索引对应的数字。
我是否需要为每个类别特征分别创建一个Embedding
?例如,为每个x_*n, x_*n+1, ..., x_*m
创建一个嵌入?
如果是的话,我如何将这些内容放入Keras代码中呢?
model = Sequential()model.add(Embedding(?, ?, input_length=variable)) # 我如何将数据输入到这个嵌入中?只有类别输入。model.add(LSTM())model.add(Dense())model.add.Activation('sigmoid')model.compile()model.fit_generator() # 适应变长序列的`X[i]`一个接一个地进行训练。
我的解决方案想法:
看起来像这样:
我可以为每个单一的类别特征(m-n)训练一个Word2Vec模型,以向量化任何给定的值。例如,伦敦将在3个维度上被向量化。假设我使用3维嵌入。然后我会将所有内容放回X矩阵中,现在它将有n + 3(n-m),并使用LSTM模型来训练它?
我只是觉得应该有更简单/更智能的方法。
回答:
如您所述的一个解决方案是,对类别数据进行独热编码(甚至按原样使用,以索引为基础的格式),并将其与数值数据一起输入到LSTM层。当然,您也可以在这里使用两个LSTM层,一个用于处理数值数据,另一个用于处理类别数据(以独热编码格式或索引基础格式),然后合并它们的输出。
另一个解决方案是为每个类别数据设置一个单独的嵌入层。每个嵌入层可以有自己的嵌入维度(如上所述,您可以有多个LSTM层分别处理数值和类别特征):
num_cats = 3 # 类别特征的数量n_steps = 100 # 每个样本中的时间步数n_numerical_feats = 10 # 每个样本中的数值特征数量cat_size = [1000, 500, 100] # 每个类别特征中的类别数量cat_embd_dim = [50, 10, 100] # 每个类别特征的嵌入维度numerical_input = Input(shape=(n_steps, n_numerical_feats), name='numeric_input')cat_inputs = []for i in range(num_cats): cat_inputs.append(Input(shape=(n_steps,1), name='cat' + str(i+1) + '_input'))cat_embedded = []for i in range(num_cats): embed = TimeDistributed(Embedding(cat_size[i], cat_embd_dim[i]))(cat_inputs[i]) cat_embedded.append(embed) cat_merged = concatenate(cat_embedded)cat_merged = Reshape((n_steps, -1))(cat_merged)merged = concatenate([numerical_input, cat_merged])lstm_out = LSTM(64)(merged)model = Model([numerical_input] + cat_inputs, lstm_out)model.summary()