- 2021.06.18:
- FM(Factorization Machines)
- FFM(Field-aware Factorization Machine)
- Wide & Deep
- Wide:记忆能力
- Deep:泛化能力
- W&D组合
- DeepFM
- 2020.06.20
- AUC
- 代码中路径问题
- 2020.06.21 函数
- tqdm
- loc & iloc
- pd.Dataframe
- tolist()
- pd.read_csv
- pd.merge
- to_csv
- drop_duplicates
- df.sample
- Series
- 代码报错
- Linux指令
- 2020.06.22
- reset_index
- fillna
- LabelEncoder
- MinMaxScaler
- SparseFeat
- prepare_data.py
- baseline.py
- 2021.06.23
- nn.embedding
- update
- unique & nunique
- 修改思路
- 2021.06.28
小小菜鸡一枚,参加了微信大数据挑战赛,前段时间有其他任务没空做,今天考完试终于能抽出时间看看了,写这篇博客是为了记录整个学习过程。
太多人想要数据集啦,我把数据集上传到百度云,大家自行下载吧:
链接:https://pan.baidu.com/s/1Kpa0Pw5jfT8x__Mq4BQpPg
提取码:btdg
–来自百度网盘超级会员V4的分享
- 下载数据集,下载官方给的代码,这是tensorflow版本的,用的是wide-deep模型。
评价指标是平均AUC
先运行comm.py文件,生成特征样本
运行baseline时,python file.py arg1:相当于命令行输入参数 - 官网模型是wide & deep,自己对这部分不是很熟,因此学习了一下FM,FFM,Wide & Deep,DeepFM:
- 相当于对逻辑回归做了改进,加了特征交叉;目的是解决数据稀疏的情况下,特征怎样组合的问题
传统: y = w 0 + ∑ i = 1 n w i x i + ∑ i = 1 n ∑ j = i + 1 n w i j x i x j y=w_{0}+sum_{i=1}^{n} w_{i} x_{i}+sum_{i=1}^{n} sum_{j=i+1}^{n}w_{i j} x_{i} x_{j} y=w0+∑i=1nwixi+∑i=1n∑j=i+1nwijxixj
FM: y ( X ) = w 0 + ∑ i = 1 n w i x i + ∑ i = 1 n ∑ j = i + 1 n < V i , f j , V j , f i > x i x j y(X)=w_{0}+sum_{i=1}^{n} w_{i} x_{i}+sum_{i=1}^{n} sum_{j=i+1}^{n}x_{i} x_{j} y(X)=w0+∑i=1nwixi+∑i=1n∑j=i+1n xixj - 上述式子关注了两种特征的交叉,需要为每个 x i x_i xi计算embedding;需要求解 w i j w_{ij} wij,当 w i j w_{ij} wij全为0时,退化为LR。
- 引入filed的概念,FM中
x
i
x_i
xi使用的是同一个隐向量
V
i
V_i
Vi。FFM将特征按照一定规则分为多个field,
x
i
x_i
xi会被映射为多个隐向量
V
i
V_i
Vi(数量取决于filed的数量)。
y ( X ) = w 0 + ∑ i = 1 n w i x i + ∑ i = 1 n ∑ j = i + 1 n < V i , f j , V j , f i > x i x j y(X)=w_{0}+sum_{i=1}^{n} w_{i} x_{i}+sum_{i=1}^{n} sum_{j=i+1}^{n}x_{i} x_{j} y(X)=w0+∑i=1nwixi+∑i=1n∑j=i+1n xixj
- 前者缺点:当query-item矩阵是稀疏并且是high-rank的时候(比如user有特殊的爱好,或item比较小众),学习困难。这种情况下,大部分的query-item都没有什么关系。但是dense embedding会导致几乎所有的query-item预测值都是非0的,这就导致了推荐过度泛化,会推荐一些不那么相关的物品。相反,简单的linear model却可以通过cross-product transformation来记住这些exception rules.
- 灵魂:记忆能力和泛化能力(FM就是,因为需要学习用户的隐向量)
Wide&Deep模型。它混合了一个线性模型(Wide part)和Deep模型(Deep part)。这两部分模型需要不同的输入,而Wide part部分的输入,依旧依赖人工特征工程。
Wide:记忆能力- 线性、权重分配(逻辑回归)
- Wide部分是广义线性模型,如逻辑回归
- 记住用户的历史偏好,如将用户吃过的菜用方程表示,进行推荐。
- 输入通常是一些手工的特征,特征工程耗费精力,对于新数据不具备泛化能力
- 使用FTRL进行优化
- 输入的特征主要有两部分组成,一部分是原始的部分特征,另一部分是原始特征的交互特征(cross-product transformation)
ϕ k ( x ) = ∏ i = 1 d x i c k i , c k i ∈ { 0 , 1 } phi_{k}(x)=prod_{i=1}^{d} x_{i}^{c k i}, c_{k i} in{0,1} ϕk(x)=∏i=1dxicki,cki∈{0,1}
Wide部分模型训练完之后留下来的特征都是非常重要的,那么模型的“记忆能力”就可以理解为发现"直接的",“暴力的”,“显然的”关联规则的能力。
- 隐向量(MF)、特征组合、特征交叉(神经网络)
- 基于嵌入的模型(如FM和DNN)可以通过学习到的低维稠密向量实现对未出现过的特征对也具备泛化能力,减轻特征工程负担。
- 如为用户推荐吃过的相似的食品,对于没有见过的特征,由于深度学习的泛化能力,模型也可以做出不错的预测
- 通常是深度学习特征,比如userID和itemID(embedding);非线性特征
- 是一个DNN模型,输入的特征主要分为两大类,一类是数值特征(可直接输入DNN),一类是类别特征(需要经过Embedding之后才能输入到DNN中)
a ( l + 1 ) = f ( W l a ( l ) + b l ) a^{(l+1)}=fleft(W^{l} a^{(l)}+b^{l}right) a(l+1)=f(Wla(l)+bl)
- W&D模型是将两部分输出的结果结合起来联合训练,将deep和wide部分的输出重新使用一个逻辑回归模型做最终的预测,输出概率值。
- Retrieval:利用机器学习模型和一些人为定义的规则,来返回最匹配当前Query的一个小的items集合,这个集合就是最终的推荐列表的候选集。
- Ranking: 收集更细致的用户特征,如:
- User features(年龄、性别、语言、民族等)
- Contextual features(上下文特征:设备,时间等)
- Impression features(展示特征:app age、app的历史统计信息等)
- 将特征分别传入Wide和Deep一起做训练。在训练的时候,根据最终的loss计算出gradient,反向传播到Wide和Deep两部分中,分别训练自己的参数(wide组件只需要填补deep组件的不足就行了,所以需要比较少的cross-produc feature transformations,而不是full-size wide Model)
- 训练方法是用mini-batch stochastic optimization。 Wide组件是用FTRL(Follow-the-regularized-leader)+ L1正则化学习。 Deep组件是用AdaGrad来学习。 训练完之后推荐TopN
所以wide&deep模型尽管在模型结构上非常的简单,但是如果想要很好的使用wide&deep模型的话,还是要深入理解业务,确定wide部分使用哪部分特征,deep部分使用哪些特征,以及wide部分的交叉特征应该如何去选择。
DeepFM- 将深度神经网络模型与FM模型结合,提出了DeepFM模型
- 同时学习低阶和高阶的特征交叉,主要由FM和DNN两部分组成,底部共享同样的输入
- FM模型善于挖掘二阶特征交叉关系,而神经网络DNN的优点是能够挖掘高阶的特征交叉关系,于是DeepFM将两者组合到一起,实验证明DeepFM比单模型FM、DNN效果好。DeepFM相当于同时组合了原Wide部分+二阶特征交叉部分+Deep部分三种结构,无疑进一步增强了模型的表达能力。
AUC是指 随机给定一个正样本和一个负样本,分类器输出该正样本为正的那个概率值 比 分类器输出该负样本为正的那个概率值 要大的可能性
- Area Under Curve:是常见的衡量二分类的评价指标。Curve指的是ROC曲线; 使用accuracy缺点:需要设定阈值,把概率转化为类别
- ROC曲线:x轴是FP(预测为真,实际为假)率,y轴是TP(预测为真,实际为真)率
- TPRate=(TP)/(TP+FN)所有真实类别为1的样本中,预测类别为1的比例
- FPRate=(FP)/(FP+TN) 所有真实类别为0的样本中,预测类别为1的比例
- 预测结果为概率,真实结果为0、1;设置不同阈值,计算出多个真、伪阳性率,ROC曲线也就出来了
- 意义:AUC就是从所有1样本中随机选取一个样本, 从所有0样本中随机选取一个样本,然后根据你的分类器对两个随机样本进行预测,把1样本预测为1的概率为p1,把0样本预测为1的概率为p0,p1>p0的概率就等于AUC。所以AUC反应的是分类器对样本的排序能力。根据这个解释,如果我们完全随机的对样本分类,那么AUC应该接近0.5。
- 我们希望分类器达到的效果是:对于真实类别为1的样本,分类器预测为1的概率(即TPRate),要大于真实类别为0而预测类别为1的概率(即FPRate),即y>x
- 优势:AUC的计算方法同时考虑了分类器对于正例和负例的分类能力,在样本不平衡的情况下,依然能够对分类器作出合理的评价。
. 代表当前所在目录
… 代表当前所在目录的父目录
./ 代表当前所在目录下的某个文件夹或文件
…/ 代表当前所在目录的父目录下的某个文件夹或文件
2020.06.21 函数 tqdm- Tqdm 是一个快速,可扩展的Python进度条
for i in tqdm(range(100)):
time.sleep(0.01)
loc & iloc
- loc为Selection by Label函数,即为按标签取数据
- df.loc[0, :],为第0行的所有记录
- iloc函数为Selection by Position,即按位置选择数据,即第n行,第n列数据,只接受整型参数
df = pd.Dataframe(data=None, index=None, columns=None, dtype=None, copy=False)
- 相当于带标签的二维数组
- data就是传入的数据,可以是数组、字典等多种形式;index, 指定行标签, columns, 指定列标签
- 相当于把数组或矩阵转换为列表
- 参数巨多,但是一般写文件路径参数filepath_or_buffer 就好啦
pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
left_index=False, right_index=False, sort=True,
suffixes=('_x', '_y'), copy=True, indicator=False,
validate=None)
- on: 主键,如果不指定,相同信息的列都会作为拼接依据
- how:控制拼接方式,默认inner取交集,outer取并集。'outer’外连接是保留两个表的所有信息,拼接的时候遇到标签不能对齐的部分,用NAN进行填充。左连接是保留所有左表的信息,把右表中主键与左表一致的信息拼接进来,标签不能对齐的部分,用NAN进行填充。
- 是Dataframe类的方法
- index表示是否保留行索引
- 去除完全重复的行数据data.drop_duplicates(inplace=True)
- 去除某几列重复的行数据data.drop_duplicates(subset=['A','B'],keep='first',inplace=True)
- subset是指定哪几列
- keep: {‘first’, ‘last’, False}, 默认值 ‘first’
first: 保留第一次出现的重复行,删除后面的重复行。
last: 删除重复项,除了最后一次出现。
False: 删除所有重复项。
Dataframe.sample(n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)[source]
- n表示要抽取的行数,默认为1;frac表示抽取行的比例,不能和n同时使用;replace表示有无放回抽样;random_state是随机数发生器种子(可以复现抽样结果,两次抽样得到同样的结果)
初赛是预测[read_comment", “like”, “click_avatar”, "forward]
- series类型由一组数据及与之相关的数据索引组成
df=pd.Dataframe(np.random.random((5,3)),columns=['A','B','C']) a = (df['A']==0) # 结果是series形式代码报错
- import deepctr_torch 时,报错cannot import name 'Layer' from 'tensorflow.python.keras.engine.base_layer', No module named 'tensorflow.python.tools'; 'tensorflow.python' is not a package
尝试将2.0.0版本的tensorflow降级,第二个错不报了,还是报第一个错。
发现官网写的是下载deepctr-torch 0.2.6版本,于是尝试修改:pip install deepctr-torch==0.2.6,还是不行。
发现大家都用的tensorflow2.x,于是又升级 - 报新错:type object 'h5py.h5.H5PYConfig' has no attribute '__reduce_cython__',尝试降级pip install h5py==2.9,顺利解决
总结:需要deepctr-torch0.2.6,tensorflow2.x,h5py2.9版本
- 查看conda版本:conda -V
- 查看环境列表:conda info -- envs, conda env list
- 创建新环境:conda create -n xxx python=3.6
- 激活环境:conda activate base
- 查看已经安装的包:conda list
- 重置索引后,drop参数默认为False,想要删除原先的索引列要置为True
- 填充数据集中的缺失值
- 将离散型的数据转换成0到n-1之间的数。
如下,对A列进行lbe.fit_transform(data["A"]),就按照大小重新赋值了
- 数据归一化处理
- 当数据(x)按照最小值中心化后,再按极差(最大值 - 最小值)缩放,数据移动了最小值个单位,并且会被收敛到[0,1]之间,而这个过程,就叫做数据归一化(Normalization,又称Min-Max Scaling)。
- 这是deepctr里的类,有embedding维度等多种属性
- prepare_data文件是在处理数据集,并形成csv文件存在目录下。
- 主要操作:将用户特征和部分视频特征拼接起来;形成测试集;处理"videoplayseconds"列的数据;负样本采样与正样本组合成新的训练集(按照行为分为好几个csv文件)
- 将训练集和测试集拼成data,定义dense_features和sparse_features,并把NAN值填充为0。
- 离散数据用labelencoder编码,连续数据就归一化。(deectr包需要这样分类和处理)
- 使用DeemFM模型训练,两部分输入都一样。
- 记录踩过的坑:①不要用pycharm装包,尽量用conda install或pip命令。我这次用的pycharm安装pytorch后,发现不能使用电脑的GPU,后来发现装的是cpu版本的pytorch。而且不好卸载,控制台和anaconda可视化界面都卸载不了,最后还是在pycharm中卸载的。② 查看cuda是否能用命令:torch.cuda.is_available()
- 现在运行的代码很多地方是直接调用包,看不清楚具体操作,于是又找到了另一篇实现DeepFM的博客。
torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None, max_norm=None, norm_type=2.0, scale_grad_by_freq=False, sparse=False, _weight=None)
- 存储固定大小的词典的嵌入向量的查找表,给一个编号,嵌入层就能返回这个编号对应的嵌入向量。
- 相当于一个矩阵类,里面初始化了一个随机矩阵,矩阵的长是字典的大小,宽是用来表示字典中每个元素的属性向量,向量的维度根据你想要表示的元素的复杂度而定。类实例化之后可以根据字典中元素的下标来查找元素对应的向量。
- Python 字典 update() 函数把字典参数 dict2 的 key/value(键/值) 对更新到字典 dict 里。
- 相当于在字典后面加了dict2的内容
- unique()是以 数组形式(numpy.ndarray)返回列的所有唯一值(特征的所有唯一值)
- nunique() Return number of unique elements in the object.即返回的是唯一值的个数
- 调参:dnn中的隐藏层数、维度、dropout、激活函数、正则化参数
- 特征:① 调整dnn和fm输入特征。 ② 特征处理,现在的baseline只用了部分特征,处理方式也很简单,可以考虑其他的特征处理方法。
- 加入多任务模型,如MMOE。
修改记录:
4. 调整隐藏层数量dnn_hidden_units=(256, 128, 64)加了一个64,结果从0.6405变到0.6407
5. 调整嵌入维度,之前是4,现在改为embedding_dim == "auto"。dropout改为0.2。结果变为了0.64365
队友试了transformer模型,结果越学越差,都0.51了o(╥﹏╥)o



