
为了找策略产品的实习,现在正在学习阿里云天池平台上的一个新闻推荐项目,在这里记录一下自己学习的历程,目前还处于更新状态。
本次新人赛是Datawhale与天池联合发起的0基础入门系列赛事第五场 —— 零基础入门推荐系统之新闻推荐场景下的用户行为预测挑战赛。
赛题以新闻APP中的新闻推荐为背景,要求选手根据用户历史浏览点击新闻文章的数据信息预测用户未来点击行为,即用户的最后一次点击的新闻文章,测试集对最后一次点击行为进行了剔除。通过这道赛题来引导大家了解推荐系统中的一些业务背景,解决实际问题,帮助竞赛新人进行自我练习、自我提高。
为了更好的引导大家入门,还特别为本赛题定制了学习方案,其中包括推荐系统基础、通用流程和baseline方案学习三部分。通过对本方案的完整学习,可以帮助掌握推荐系统相关竞赛的基本技能。同时平台也将提供专属的视频直播学习通道,敬请关注平台通告。
新人赛的目的主要是为了更好地带动处于初学者阶段的新同学们一起玩起来,因此,我们鼓励所有选手,基于赛题发表notebook分享,内容包含但不限于对赛题的理解、数据分析及可视化、算法模型的分析以及一些核心的思路等内容。
根据教程,这个题目要求通过已有的用户、文章信息来对最后一次用户的点击文章事件进行预测。按照一般思路来看,这是一个分类问题,但是直接从36万份样本中进行分类,成本较大,所以可以尝试先用特定的特征对用户的喜好范围文章进行一个快速召回,然后,在根据进一步的细化特征对用户的喜好文章进行排序筛选,得出比较小的筛选范围,最后再通过相应的特征进行建模,对用户的点击文章行为(是、否)进行二分类的模型判断,可以尝试使用逻辑回归模型(Q:有没有其他的模型来作为备选项呢?)
一共有五个task可供学习:
| 1 | 赛题理解+Baseline |
| 2 | 数据分析 |
| 3 | 多路召回 |
| 4 | 特征工程 |
| 5 | 排序模型+模型融合 |
Task1-Baseline
20220401
今天对task1部分进行了学习,先初步了解相应的样本处理,以及生成了一个用户-文章-时间的字典,方便后续进行基础的统计分析,避免浪费内存及相应的处理时间。
Q:线上线下验证的作用是什么?
Task2-数据分析
20220511
dataframe的几个函数用法
| groupby | 依据某个字段分组 | 通常,后面附加的计数等操作,都是以组别的形式统计出现的 |
| transform | 对groupby之后的某个统计结果进行格式处理,使之记录在每一条单独的数据行上 | 比如,transform('count')或者transform('sum'),意思就是对groupby之后的某个字段的计算之后,将计算结果赋予到每个数据行上,从而兼容格式 |
| merge | 类似于sql里面的join合并 | Df.merge(df2, how='left', on=['unique_key']) |
| Value_counts | 对某个字段内的类别重复情况自动统计,不需要再使用groupby | Df.value_counts(),给出来的格式则是字段名+统计数,如果需要规范成标准化的df,则可以加上reset_index()来处理 |
总结
今天尝试把数据的整理和可视化初步搭建出来,但细节部分还没有展现。
20220512、20220513
dataframe的agg与transform的对比
| agg | 应用函数,对数据进行统合统计,没有把数据铺设到每一行 | |
| transform | 应用函数,结果铺设在每个数据行 | |
| apply | 仅仅是一个套用计算函数的函数,可用lambda函数 | Apply() |
参考这里:csdn-pandas agg apply, transform的区别
其他dataframe函数介绍
| sort_values | 按照某个字段进行排序,可设置顺倒序 | |
| value_counts | 如果是针对某个df字段使用,则,是对该字段内的每个答案进行重复次数统计,注意和agg、transform等作对比 | 如,df['abc'].value_counts(),如abc包括eeeffgggg,那么答案则是e-3,f-2,g-4 |
Word2Vec的几个参数需要注意
| vector_size | 向量的维度数量,一般在50-300 | 旧版为size |
| sg | 使用的架构,如何进行预测模拟的方式,包括CBOW连续词袋(根据上下文来猜测中间词),以及skip-gram连续跳格(根据中间词来猜测上下文,尤其是下文)两种模式,参考这篇文章,参考这份视频 | sg=0(cbow), sg=1(skip-gram) |
| window | 当前当前词与预测词在一个桔子的最大距离是多少 | |
| seed | 随机数发生器,用于初始化词向量,这里写的是2020 | |
| workers | 并行任务数 | |
| min_count | 最小出现次数 | 默认为5 |
| epochs | 迭代次数,默认为5 | 旧版为iter |
| …… | ||
word2vec的使用流程(参考20220608的Word2vec介绍)
1-搜集样本,明确接下来的目标,如推荐下一篇文章;
2-依据文章发表时间,df全部排序;
3-选择将文章id(也许还有标题)作为训练对象,依据user_id分组(因为是预测单个用户的下一篇文章),产生list,二次转化为list;
4-设置word2vec的参数;
5-对文章id部分,进行向量样本建设(计算相似度矩阵),也就是与上文的list进行对照,产生整个向量库;
6-到这里,word2vec的向量库基本建设完毕;
6-若要测算用户浏览的所有文章的相关度,可使用随机用户及其阐述的信息,然后将其相关文章进行两两对比,测算,得出结果;
其他
使用df.shift()函数,可查看这里的文章,对用户的阅读时间与文章发表时间差进行计算;
处理一段文本材料当中的词汇关系网络,可以使用文本共现网络分析,文章链接在这里,这里和“词汇共现矩阵”有那么一点点不同,后者更多应用于word2vec的环境当中;
基本的数据检查思路
1-将用户行为信息与文章有关信息进行数据合并,并尝试合并训练集、测试集等内容,增加样本量;
2-查看用户总数、文章总数等信息;
3-对用户部分而言,查看用户相关行为信息(系统、地区、设备等)的基本分布情况,并查看单个用户的内部行为特征差异分化情况(比如,是不是用了很多个系统,是不是在不同地区浏览过文章),查看用户浏览文章数量多少的分化情况(有的用户多,有的用户少);
4-对文章部分而言,可查看文章的相关分类基本分布情况(比如文章发布占比,以及类别被浏览的分化情况),文章的词汇数量分布,文章被浏览次数的分布情况;
5-聚焦到时间部分,查看用户浏览文章时间与文章发布时间的差异情况,这部分涉及到时间,可以尝试使用归一化处理;
6-聚焦与浏览内容情况,查看单个用户浏览的文章的同质性(相关性)高不高,这部分就需要使用向量来描述文章相似度了;
7-对于描述性的部分,经典的关注角度有top10(100)、中位数、平均数、最大最小值,标准差,等等;
数据分析总结
这边需要补充,通过task2,得知了哪些数据的基本情况?
Task3-多路召回(唤起)
20220528-20220530
了解zip函数的配对用法,很实用,能够将两个列表、字段的数据单个单个地配对在一起输出:
a = [1,2,3]
b = [4,5,6]
c = [4,5,6,7,8]
zipped = zip(a,b) # 返回一个对象
zipped
<zip object at 0x103abc288>
list(zipped) # list() 转换为列表
[(1, 4), (2, 5), (3, 6)]
list(zip(a,c)) # 元素个数与最短的列表一致
[(1, 4), (2, 5), (3, 6)]
https://www.runoob.com/python/python-func-zip.html
归一化的用途、思路。归一化在于将同一个字段的数据进行标准化,从而使得同一个字段的不同来源数据可以比较,并减少因为数值高低占比带来的数据分析的影响。
一般可以使用sklearn的归一化方法
from sklearn.preprocessing import MinMaxScaler<br><br>minmax = MinMaxScaler()<br>x_new = minmax.fit_transform(x)<br># 如果是针对dataframe的某个字段的话,请记得将其转化为二维数组,而不是一维series<br>df['timestamp'] = ['1', '9999', '88888']<br># 其实df的字段是一个数列,上面仅仅是方便演示,以list的形式展现<br>df['timestamp'] = minmax.fit_transform(df[['timestamp']])<br># 包括drop_duplicates的用法也是类似的,都要使用两次中括号,因为drop_duplicate只支持df,不支持series<br># 归一化其实核心要素在于某列数据内的最大最小值与当前数据的处理,新闻推荐项目出现过多次作者自写的归一化函数
https://blog.csdn.net/wuzhongqiang/article/details/103764412
np.linalg.norm对于归一化的作用,但已经看不出来是做什么用了
https://blog.csdn.net/hqh131360239/article/details/79061535
如何划分sample、线下验证、线上验证数据
sample随机抽取,主要涉及到用户的历史浏览行为;线下验证其实是把训练集和验证集划分开来,后者用来调节参数(但我在task3没怎么看到这部分的使用);线上验证,即对训练集、验证集合并使用。
agg的set集合用法,结合用户历史多次浏览行为的信息,能够将某个字段的所有内容整合成一个set集合(不是字典),方便整合查询(参考20220512、20220513):
| user_id | class_type | instructor | |
|---|---|---|---|
| 1 | Krav Maga | Bob | |
| 1 | Ju-jitsu | Alice | |
df.groupby('user_id').agg(lambda x: set(x))
| User_id | Class_type | Instructor | |
|---|---|---|---|
| 1 | {Krav Maga, Ju-jitsu} | {Alice, Bob} | |
https://blog.csdn.net/qq_39321513/article/details/110395460
Value_counts返回的是一个没有序列化的ndarray,用来统计dataframe某个字段内的所有值的计数占比
| Unit Name | |||
|---|---|---|---|
| Percent of GDP | |||
| Domestic currency | |||
| Percent of total expenditure | |||
| Percent of GDP | |||
| Percent of total expenditure | |||
| Percent of GDP | |||
| Percent of GDP | |||
| Percent of GDP | |||
| ... |
data['Unit Name'].value_counts()<br>#输出<br>Percent of GDP 3561<br>Domestic currency 3561<br>Percent of total expenditure 470<br>Name: Unit Name, dtype: int64
https://www.jianshu.com/p/f773b4b82c66
tqdm的用法,直接在range内部使用即可,用来展示循环的进度。
对于行(row)的用法
| iloc, loc... | 寻求特定位置的行(似乎也可以) | |
| Index | 选取某个片段的行?(还是仅仅是索引呢?) | |
collections.defaultdict的用法,能够对某个字典的默认值设置为int0的数值。
https://www.jianshu.com/p/bbd258f99fd3
| e指数函数 | 模拟事物增长、衰减的过程 | https://zh.wikipedia.org/wiki/E_(%E6%95%B0%E5%AD%A6%E5%B8%B8%E6%95%B0) |
| log函数 | 没怎么说怎么用,只是说明在计算机语言当中很常用 | https://zh.wikipedia.org/wiki/%E5%AF%B9%E6%95%B0 |
召回机制
| itemcf(itemcf_sim_itemcf_recall) | 基于物品的协同过滤(有行为数据) | 基于单一用户的历史浏览记录,对浏览文章a之外的其他文章进行比对,测算两个文章的位置差距loc_weight、创建时间差距created_time_weight、被关联度指数content_weight,形成综合指数item_rank,并尝试使用热门文章填充空缺的召回数量。特点:借助不同用户对同一篇文章的浏览行为,判断与某一篇文章有关的文章范围。缺点:就是在于,假设了一个用户的所有浏览文章都是相似的,这个假设的应用范围是有相应条件的,需要特别注意。 |
| usercf(?)(请与user embedding结合看待) | 基于用户的协同过滤(有行为数据) | 借助youtubednn通过行为数据产生的u2u_sim相似矩阵,将有关用户的文章信息进行结合,设定位置loc_weight、内容content_weight、文章创建时间权重created_time_weight,不足则用热门文章补充。特点:借用了youtubednn的u2u_sim相似矩阵计算;原文作者提到,这里的方式与itemcf很相似,但是计算的权重有一些不同,这里是累加的(?需要确认)缺点:? |
| item embedding(embedding_sim_item_recall) | 基于物品的向量相似度(无行为数据) | 与itemcf类似,但是主要使用的是已有的文章向量矩阵emb_i2i_sim模型。特点:不是通过用户浏览行为,而是通过已有的文章相似矩阵来判断。缺点:用户不一定只喜欢同一种内容,因此itemcf类别的推荐更适合平台早期,内容较少的情况,亦或是内容稳定性大于用户稳定性的情况。https://blog.csdn.net/weixin_40375871/article/details/119119975 |
| user embedding(youtubednn_usercf_recall)(请与usercf结合看待) | 基于用户的向量相似度(似乎有行为数据) | 使用youtubednn产生的user embedding向量,直接进行相似文章推荐。缺点:但这里的项目,明显user embedding是基于行为数据生成的,其实与usercf的差别似乎也不是很大。 |
| youtubednn(youtubednn_recall) | 计算用户与文章之间的embedding,然后直接推荐 | 通过已有的历史浏览记录,划分user_profile以及item_profile,对两者进行训练,形成相应的embedding,产生两者的相似embedding,并借此进行推荐,借用faiss加速算法进行相似内容(用户、文章)的查找。 https://zhuanlan.zhihu.com/p/52504407 |
| cold_start(以文章冷启动为例)(cold_start_recall) | 冷启动,包括文章冷启动、用户冷启动、完全冷启动 | 借用itemcf的规则,通过文章类型、字数、创建时间等进行比较,进行文章推荐。 |
softmax函数与多分类问题
?(参考20220608的word2vec部分)
tolist的用法,看样子像是对将一维数组升格为双重列表?
https://blog.csdn.net/lilong117194/article/details/78437224
两个list进行相减的时候,转化为set进行操作可以摆脱排序的痛苦
通过random.shuffle进行内容的随机排序
import random<br>list = [120, 16, 10, 5]<br>random.shuffle(list)<br><br>print(list)<br>[16, 5, 10, 20]
https://www.runoob.com/python/func-number-shuffle.html
python具体数据的预处理
padding的用途,用来针对一些细节不够多的数据,进行周围的扩张,从而更好训练数据。
labelencoder和onehotencoder的用法和意义:labelencoder更多是单独的不连续数据进行编码,后者则注重编码的同时,将不同字段的特征数据分类编码,自行以list的形式存储。
https://blog.csdn.net/quintind/article/details/79850455
记得有一个函数,可以将dataframe某个字段的上下位置调节,生成一个新字段,用来接下来的计算,但突然忘了叫啥。。。。。。
之后可以看一下(参考20220512、20220513的df.shift())
20220607
环境配置问题:tensorflow, faiss, python,
https://www.jianshu.com/p/5eed417e04ca
https://www.cnblogs.com/hmy-666/p/14453722.html
https://www.cnblogs.com/hmy-666/p/12488571.html
jupyter notebook的部分代码需要手动运行才能正常执行的问题
一些字段有没有s的标注(如item、items),以及内容缩进问题
在进行召回策略之前,需要进行基本的数据关系的梳理
| item | 文章id-创建时间created_ts | |
| 文章id-文章类型item_type | ||
| 文章id-文章字数item_words | ||
| click | 用户id-文章id-浏览时间click_timestamp | |
| 文章id-用户id-浏览时间click_timestamp | ||
| Single_user_click | (单个)用户id-历史浏览的文章id | |
| (单个)用户id-历史浏览的最后一篇文章id | ||
| (单个)用户id-历史浏览的文章id-文章类别item_types-文章字数item_words-文章创建时间created_time | ||
faiss的作用——加速对于相似矩阵的文章、用户的内容召回,筛选出topk相似的内容。
总结
在前期对于数据分析的部分之后,这里主要建立起用户-文章-行为的相应模型,并从三个维度进行了文章的召回,分别是item、user、cold_start三个部分。
item类别主要基于embedding,亦或是基于相关行为数据,将单个用户浏览的文章视为用一个item类别,从而进行推荐。
user类别主要是基于embedding,亦或是基于相关行为数据,对借用相似用户浏览的文章进行推荐。
cold_start则主要是基于需要被推荐的新事物的初步画像(文章,是类别、字数、创建时间等)(人,可能是各个内容,包括设备特征、网络及地域特征、人口学特征等)与已具有交互行为的文章、用户的画像进行对比,从而进行相似事物的推荐。
20220608
对Word2vec的一些学习
数据训练模型的大致流程有:
1-建立相似矩阵,
2-对实际输入调用相似矩阵计算预测可能性,
3-输出候选选项列表。
word2vec大致遵循如上流程,但有其相应的特点:
1-在建立以滑动窗口为思路的相似矩阵(参数:词汇量(样本量)vocal_size, 向量宽度(特征宽度)embedding_size)的阶段,不仅包括了n-gram的顺位嵌入矩阵,也包括了以skip-gram跨位为代表的上下文矩阵,两种矩阵同时结合在一起使用;
2-收集样本时,不仅包括了正样本pos_sample,也包括了负样本neg_sample,进行了负采样;
3-与之相对的是,为了提高预测效率,并不是直击将候选选项列表进行遍历式的召回排序,而是直接将候选列表的若干个内容与输入内容进行可能性预测,这被认定为是一个二分类的问题,通过逻辑回归予以解决,所以sigmod函数、softmax函数等等用法都和这里的二分法有着很多关联;
4-在一轮训练、学习(epoch, training step)的过程当中,使用余弦相似度来进行相似矩阵的比较、度量,如果发现预测结果与actual outcome不一样时,会给出偏差值,从而回馈到下一轮学习当中进行改进;
5-两个超参数可供参考:窗口大小(默认值为5,推荐2-15),以及负样本数(默认值为5,推荐5-20)。
https://libertydream.github.io/2019/11/09/%E5%9B%BE%E8%A7%A3-word2vec/
https://jalammar.github.io/feedforward-neural-networks-visual-interactive/#sigmoid-visualization
