赞
踩
1.无序离散特征:one-hot encoding,比如所属国家、城市
(1)无序离散特征:one-hot encoding,比如所属国家,城市。(1)如果one-hot之后unique值不多可以不用做Embedding, (2)但是如果该特征unique值过多,比如所属国家、城市,onehot产生的矩阵过宽,这种情况下,我们的通常做法就是将其转换为embedding。
(2)也可以先做LabelEncoder将特征的不同取值区分开,然后再embedding
2.有序离散特征:label encoding,比如年龄 (类似分桶)
3.单值离散特征:做Embedding映射成1*K维向量,然后与其他特征拼接
4.多值离散特征:做Embedding映射成3*K维,然后MeanPooling 成1*K维,比如某人的爱好有3个这种特征。
总结:
- 特征用于FM一次项wi*xi:
- 原值:比如1、2、3等级
- Onehot:比如性别,省份,城市
- LabelEncoder:有序离散特征 年龄
- 特征用于FM二次项的隐向量
- OneHot --> Embedding
- LabelEncoder -->
- 1.归一化:去除不同维度数据的量纲以及量纲单位 服从均匀分布
- 2.标准化: 标准化成正态分布之后,可以更加容易地得出最优参数目标函数的最小值,从而达到加速收敛的效果。服从高斯分布,一般数据服从高斯分布,所以标准化用的比较多。
区别:两者都可以对特征做幅度缩放,两者的效果差不多,选择其中一个即可。
- 分桶:
- (1)连续特征可以通过分桶实现离散化成[0,1,2,3,..9]
- (2)大量离散特征比如 每个用户观看的视频数,也可以分桶
应用于FM一次项时:先通过标准化/分桶 --> 乘以权重系数wi*xi 再与其他特征拼接。 例如1个连续特征先通过Dense(1) (wi*xi)得到1个数,再与其他特征拼接。
应用于FM二次项时:先通过标准化/分桶 -->Embedding得到K个数,在通过RepeatVector 得到1*K维向量,再与其他特征相乘。例如1个连续特征先通过Dense(1)(类似一个Embedding) 得到K个数,在通过RepeatVector 得到1*K维向量,再与其他特征相乘。(Ref: DeepFM-keras 实现中FM二次项)
## 离散/连续特征 总结:
- 第一步:原值,标准化,OneHot,LabelEncoder,分桶
- 第二步:如果需要得到隐向量的话 就再做Embedding
# 正则化:
- 常见的有正则项有 L1 正则 和 L2 正则 以及 Dropout
更详细内容请参考:[ML 入门:归一化、标准化和正则化](https://zhuanlan.zhihu.com/p/29957294)
- libsvm数据格式:libsvm 格式的数据 一行中只有有数据的才会写上 比如5.0 1:1 5:1 10:5.1 11193:1 就表示预测值y=5.0,其中特征1(表示这条样本的userid=1),其中特征5(表示这条样本性别男特征=1),特征10(比如score表示分数连续值),特征11193(表示这条样本的itemid=11193)。
- 比如 userid有8千个,itemid 有3万个,连续,离散以及onehot之后的特征有2千个,那么共有4万个特征。这4万个特征依次排开形成 field_1,field_2....field_40000,
field:index:value
连续: filed_index:0:得分:表示一条样本的filed_score 这个特征 只有一个取值,大小就是实际分数比如5.1分
离散:field_index:9:1:表示这个特征被分了0~9十个桶,这条样本的filed_score取值位于第9个桶范围内,比如实际分数在(90,100)之间
field_index:0:1:表示这个特征被分了0~9十个桶,这条样本的filed_score取值位于第1个桶范围内,比如实际分数在(90,100)之间
下表是一条样本的libsvm数据:其中231、10005都是特征索引,表示第几个特征。
label | 单值离散 | 单值离散(少) | 单值离散(多) | 连续(范围小) | 连续(范围大) | 多值离散 | 单值离散 | |
样本1 | y=5.0 | userid=231 | user_level=2 | action_statis=121 | score1=5.1 | score2=51 | hobby=[0,3,4] | itemid=11193 |
libsvm | 5.0 | 231:1 | 8005:1 | 100021:1:1 | 10010:0:5.1 或10010:5.1 | 10010:5:1 | 10210:0:1 10210:3:1 10210:4:1 | 11193:1 |
样本2 | y=4.1 | userid=241 | user_level=3 | action_statis=522 | score1=7.1 | score2=71 | hobby=[1,3] | itemid=13241 |
libsvm | 4.1 | 241:1 | 8006:1 | 100022:5:1 | 10010:0:7.1 或10010:7.1 | 10010:7:1 | 10210:1:1 10210:3:1 | 13241:1 |
做分桶 | 当做连续值 | 当做离散值 做分桶 |
原理图,和实际物理实现方式之间的区别,
连续特征: 输入到Input中的是 原值(归一化)/分桶之后的离散值
- 原值输入,#取值范围较小的 对一次项的贡献等于自身数值乘以权值w,可以用Dense(1)层实现
- 可以通过归一化/标准化 做幅度缩放 直接作为FM的输入 #取值范围较大的做幅度缩放 对一次项的贡献等于缩放后数值乘以权值w,可以用Dense(1)层实现
- 也可以 通过分桶,然后再onehot 作为输入
- in_score = Input(shape=[1], name="score") # None*1
- emb_score = Dense(1)(in_score) # None*1 wi*xi
- # or
- in_score = Input(shape=[1], name="score") # None*1
- numeric = Concatenate()([in_score, in_sales]) # None*2
- dense_numeric = Dense(1)(numeric) # None*1
单值离散特征:输入到Input中的是 原值/分桶之后的离散值
- onthot 之后作为输入 # 取值个数较少
- labelEncoder之后再 onehot作为输入。# 取值个数较多的
- in_age = Input(shape=[1], name="age") # None*1
- emb_age_1d = Reshape([1])(Embedding(10, 1)(in_age)) # None*1, 年龄取值10种
多值离散特征:输入到Input中的是 [2,3]
- 先做padding补成相同长度的,就得到了[0,1,0,1,1,0..0] 然后做Embedding(10,1) 即(w31*x1+w32*x2+...+w310*x10)/10
- in_topic = Input(shape=[4], name="topic") # None*4, 最长长度4
- emb_topic_1d = Embedding(22, 1, mask_zero=True)(in_topic) # None*4*1
- emb_topic_1d = MyMeanPool(axis=1)(emb_topic_1d) # None*1
首先,连续型field对一次项的贡献等于自身数值乘以权值w,可以用Dense(1)层实现,任意个连续型field输入到同一个Dense层即可,因此在数据处理时,可以先将所有连续型field拼成一个大矩阵,同时如上所述,ID可以省略。
其次,单值离散型field根据样本特征取值的index,从w中取出对应权值(标量),由于离散型特征值为1,故它对一次项的贡献即取出的权值本身。取出权值的过程称为 table-lookup,可以用Embedding(n,1)层实现(n为该field特征取值个数)。若将所有单值离散型field的特征值联合编码,则可使用同一个Embedding Table进行lookup,不需要对每个field单独声明Embedding层。因此在数据处理时,可以先将所有单值离散型field拼起来并联合编码,同时如上所述,Value可以省略,只关心lookup出来的权值ww即可。
最后,多值离散型field可以同时取多个特征值,为了batch training,必须对样本进行补零padding。相似地可用Embedding层实现,Value并不是必要的,但Value可以作为mask来使用,当然也可以在Embedding中设置mask_zero=True。Ref:https://blog.csdn.net/songbinxu/article/details/80151814
word2vec是基于上下文的共现学习来学习词向量的;一般的embedding,就相当于是网络里的一层,是跟着任务端到端优化网络学习到权重参数,从而得到隐向量的。
word embedding是指词向量,是一个将词向量化的概念,word2vec则是将词映射成词向量的一种具体的技术。几个比较有名的word embedding方法包括: word2vec (Google), GloVe, wordRank, FastText (Facebook)。区别的话,就是一个是概念,一个是实现手段。
word2vec 的实现:先将离散特征(比如一句话中的每个词表示成onehot形式, 然后输入到CBOW或者Skip-Gram模型中得到 某一个单词的词向量。其中 CBOW的输入是好几个onehot向量,而Skip-Gram 输入的事一个onehot值。
比如特征score=2.5,直接输入到Input神经元,分别乘以不同权重,得到隐向量
- in_score = Input(shape=[1], name="score") # None*1
- emb_score_Kd = RepeatVector(1)(Dense(latent)(in_score)) # None * 1 * K
参考用keras实现一个DeepFM 画出对于单值离散的embedding图1 . 直接将年龄分桶之后的值(age=2)作为神经元的输入,然后得到1个3维隐向量,这是将Embedding视做黑盒子得到的结构图,可以看成是 keras层级图。
图1. 是Embedding 内部网络结构图,直接将年龄分桶之后的值(age=2)作为Embedding的输入,然后embedding内部将age=2 映射成一个1*5的向量[0,0,1,0,0] 通过全连接网络得到 3维隐向量。假设 年龄分桶之后取值(0,5),0对应(0~20)岁,4对应(80,100)岁,先将每样样本的年龄进行onehot,然后将onehot映射成一个3维向量,比如这三维向量是身高,体重,阅历。显然w01 要小于w21;w11>w21>w41,因为人的身高先增大,后减小,20-40岁之间最大。
Embedding 实际物理实现方式:age=23 分桶之后变成 age=2 输入--> embedding --> 输出age=2的一个8维隐向量,也就是embedding内部去将age=2 onehot成 [0,0,1,0..0] 然后乘以lookup table表 取出隐向量。也就是我们输入到Input层的事age=2 而不是age=[0,0,1,0...0] ,因此不需要我们自己在特征工程时将age=2 变成onehot形式,
- in_age = Input(shape=[1], name="age") # None*1
- emb_age_Kd = Embedding(10, 8)(in_age) # None*1, 年龄取值10种
比如爱好特征共有22个不同取值而一个人爱好最多是4个,其中一个人有2个爱好[1,3] 那么我们直接将[1,3]补零后[1,3,0,0]作为Input层输入,embedding会逐个进行onehot 然后乘以权重矩阵得到对应的一个4*8的隐向量矩阵。
- in_topic = Input(shape=[4], name="topic") # None*4, 最长长度4
- emb_topic_Kd = Embedding(22, 8, mask_zero=True)(in_topic) # None * 4 * K
- # (22,8) 表示Embedding lookup table 是22*8的,也就是topic 共有22中不同取值0~21
-
总结:
常用的分桶方式:
离散化方法的缺点:
AutoDis框架,具有高模型容量、端到端训练,每个特征取值具有独立表示的特点
三个步骤:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。