浅谈Entity Embedding

“万物皆可Embedding”

现实生活或者比赛中,我们会经常见到表格数据,其中包含了各种类别特征。
本文将简单介绍利用神经网络来表示类别特征的方法-Entity Embedding,这个方法首先出现在kaggle上的《Rossmann Store Sales》中的rank 3的解决方案,作者在比赛完后为此方法整理一篇论文放在了arXiv,文章名:《Entity Embeddings of Categorical Variables》

1 常见类别编码方法

在数据挖掘中,处理类别特征的方法有很多,最常见的思路是转为one-hot编码等。总结如下:

  • label encoding
    特征存在内在顺序 (ordinal feature)
  • one hot encoding
    特征无内在顺序,category数量 < 4
  • target encoding (mean encoding, likelihood encoding, impact encoding)
    特征无内在顺序,category数量 > 4
  • beta target encoding
    特征无内在顺序,category数量 > 4, K-fold cross validation
  • 不做处理(模型自动编码)
    CatBoost,lightgbm

2 实体嵌入 Entity Embedding

核心:把正整数(索引)转换为固定大小的稠密向量

# 代码来自:https://blog.csdn.net/anshuai_aw1/article/details/83586404
import numpy as np
from keras.layers.embeddings import Embedding
from keras.models import Sequential
import tensorflow as tf
import random as rn
 
# ===================================================================================================
# 保证结果的复现
import os
os.environ['PYTHONHASHSEED'] = '0'
 
np.random.seed(42)
 
rn.seed(12345)
 
session_conf = tf.ConfigProto(intra_op_parallelism_threads=1, inter_op_parallelism_threads=1)
 
from keras import backend as K
 
tf.set_random_seed(1234)
 
sess = tf.Session(graph=tf.get_default_graph(), config=session_conf)
K.set_session(sess)
# ===================================================================================================
 
 
'''
输入数据是32*2,32个样本,2个类别特征,且类别特征的可能值是0到9之间(10个)。
对这2个特征做one-hot的话,应该为32*20,
embedding就是使1个特征原本应该one-hot的10维变为3维(手动设定,也可以是其它),因为有2个类别特征
这样输出的结果就应该是32*6
'''
model = Sequential()
model.add(Embedding(10, 3, input_length=2))
 
# 构造输入数据
input_array = np.random.randint(10, size=(32, 2))
 
# 搭建模型
model.compile('rmsprop', 'mse')
 
# 得到输出数据 输出格式为32*2*3。我们最终想要的格式为32*6,其实就是把2*3按照行拉成6维,然后就是我们对类别特征进行
# embedding后得到的结果了。
output_array = model.predict(input_array)
 
# 查看权重参数
weight = model.get_weights()
 
'''
我们肯定好奇:output_array是怎么得到的?
我们先来看weight的内容:10*3。这是什么意思呢,就是其实就是一个索引的结果表,如果原来特征值为0,那么就找第一行,如果原来特征值为3,
那么就找第4行。
0.00312117  -0.0475833  0.0386381
0.0153809   -0.0185934  0.0234457
0.0137821   0.00433551  0.018144
0.0468446   -0.00687895 0.0320682
0.0313594   -0.0179525  0.03054
0.00135239  0.0309016   0.0453686
0.0145149   -0.0165581  -0.0280098
0.0370018   -0.0200525  -0.0332663
0.0330335   0.0110769   0.00161555
0.00262188  -0.0495747  -0.0343777
以input_array的第一行为例
input_array的第一行是7和4,那么就找第8行和第5行,形成了output_array的第一个2*3,即
0.0370018   -0.0200525  -0.0332663
0.0313594   -0.0179525  0.03054
然后,拉成一个向量0.0370018  -0.0200525  -0.0332663 0.0313594    -0.0179525  0.03054
这就是原始特征值8和5经过embedding层后的转换结果!
'''

在上述的代码中,我们可以看到2个类别特征的值都在0到9,并且我们没有对模型进行训练,而是直接就搭建了一个网络,就输出结果了。在真实的应用中,不是这样。有2点需要改进:

1、对每一个类别特征构建一个embedding层。对embedding层进行拼接。
2、训练网络,得到训练后的embedding层的输出作为类别特征one-hot的替换,这样的embedding的输出更精确。

《Entity Embeddings of Categorical Variables》 结构非常简单,就是embedding层后面接上了两个全连接层,代码用keras写的,构建模型的代码量也非常少,用的keras的sequence model。

文章有几点分析比较值得关注的地方。

  • 店铺所在地的嵌入向量在用TSNE投影到两维空间后和地图位置有着极大的相似性。

  • 使用嵌入后的向量可以提高其他算法(KNN、随机森林、gdbt)的准确性。

  • 作者探索了embedding和度量空间之间的联系,试图从数学层面深入探讨embedding的作用。

代码实践

作者代码 : https://github.com/entron/entity-embedding-rossmann
自己的尝试:https://github.com/yanqiangmiffy/Data-Finance-Cup/,将类别特征嵌入层与数值特征的全连接层进行拼接:

def build_embedding_network():
    inputs = []
    embeddings = []
    for i in range(len(embed_cols)):
        cate_input = Input(shape=(1,))
        input_dim = len(col_vals_dict[embed_cols[i]])
        if input_dim > 1000:
            output_dim = 50
        else:
            output_dim = (len(col_vals_dict[embed_cols[i]]) // 2) + 1

        embedding = Embedding(input_dim, output_dim, input_length=1)(cate_input)
        embedding = Reshape(target_shape=(output_dim,))(embedding)
        inputs.append(cate_input)
        embeddings.append(embedding)

    input_numeric = Input(shape=(4,))
    embedding_numeric = Dense(5)(input_numeric)
    inputs.append(input_numeric)
    embeddings.append(embedding_numeric)

    x = Concatenate()(embeddings)
    x = Dense(300, activation='relu')(x)
    x = Dropout(.35)(x)
    x = Dense(100, activation='relu')(x)
    x = Dropout(.15)(x)
    output = Dense(1, activation='sigmoid')(x)

    model = Model(inputs, output)

    model.compile(loss='binary_crossentropy', optimizer='rmsprop')

    return model

阅读资料

Entity embedding 是一种将实体(如词汇、句子、用户等)转换为高维向量的技术,在自然语言处理和推荐系统中被广泛应用。我将以神经网络模型为例,简要介绍如何在代码中实现 entity embedding。 首先,我们需要使用 Python 和相关的深度学习框架(如 TensorFlow 或 PyTorch)来编写代码。我们可以使用 embedding layer 来将实体转换为向量。假设我们要处理一个用户-电影评分数据集,我们可以使用两个 embedding layer,一个用于用户 ID,另一个用于电影 ID。在神经网络模型中,这两个 embedding layer 将作为输入层与其他层相连。 我们首先需要定义一个简单的神经网络模型,包括一个输入层(分别对应用户 ID 和电影 ID)、一个或多个隐藏层,以及一个输出层(用于预测用户对电影的评分)。然后,我们在输入层中添加两个 embedding layer,分别对应用户和电影的 ID。这两个 embedding layer 的输出将作为神经网络模型的输入。 接下来,我们可以使用真实的数据来训练这个模型。我们将用户的 ID 和电影的 ID 作为输入,将实际的评分作为输出,通过反向传播算法来更新 embedding layer 中的权重。训练完成后,我们可以使用训练好的模型来进行预测,根据用户和电影的 ID,得到相应的评分预测结果。 总的来说,实现 entity embedding 的代码主要涉及神经网络模型的构建和训练,以及 embedding layer 的使用。通过将实体转换为高维向量,我们可以更好地表示实体之间的关系,从而提高模型的性能和表达能力。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值