diff --git a/docs/README.md b/docs/README.md
index 4b8c402f..48708fb6 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -95,6 +95,7 @@
- [排序模型&模型融合](ch03/ch3.1/markdown/ch3.1.5)
#### 新闻推荐系统实践
+- [3.2.0 特别说明(必看)](ch03/ch3.2/3.2)
- **视频**
- [新闻推荐系统流程的构建视频讲解](https://datawhale.feishu.cn/minutes/obcnzns778b725r5l535j32o)
- **文档**
@@ -114,7 +115,7 @@
- 地域召回
- [YoutubeDNN召回](ch03/ch3.2/3.2.4.3)
- [DSSM召回](ch03/ch3.2/3.2.4.4)
- - DeepFM排序模型
+ - [DeepFM排序模型](ch03/ch3.2/3.2.5)
- 规则与重排
- 任务监控与调度
- **当前问题汇总**
@@ -156,9 +157,12 @@
- 汪志鸿(Datawhale成员-东北大学-算法工程师)
- 王辰玥(Datawhale意向成员-中国地质大学(武汉)-在校生)
-**其他**
+**重要贡献者(根据内容+社区贡献程度筛选)**
+- 唐鑫(Datawhale意向成员-西安电子科技大学-在校生)
+- 王宇宸(Datawhale意向成员-上海科技大学-在校生)
-感谢徐何军,李万业,陈琰钰,陈锴,梁家晖,王贺,宁彦吉,田雨,唐鑫,宋禹成,刘雯静,吕豪杰,张汉隆,吴丹飞,王云川,肖桐,管柯琴,陈雨龙,宋禹成等在最早期的时候对fun-rec所做的贡献!
+**其他**
+感谢徐何军,李万业,陈琰钰,陈锴,梁家晖,王贺,宁彦吉,田雨,宋禹成,刘雯静,吕豪杰,张汉隆,吴丹飞,王云川,肖桐,管柯琴,陈雨龙,宋禹成等在最早期的时候对fun-rec所做的贡献!
## 关注我们
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index c6a7359a..0207f3b6 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -63,6 +63,7 @@
- [3.1.4 特征工程](ch03/ch3.1/markdown/ch3.1.4)
- [3.1.5 排序模型&模型融合](ch03/ch3.1/markdown/ch3.1.5)
- 3.2 新闻推荐系统的实践
+ - [3.2.0 特别说明(必看)](ch03/ch3.2/3.2)
- 3.2.1 离线物料系统的构建
- [Mysql](ch03/ch3.2/3.2.1.1)
- [MongoDB](ch03/ch3.2/3.2.1.2)
@@ -79,7 +80,7 @@
- 地域召回
- [YouTubeDNN召回](ch03/ch3.2/3.2.4.3)
- [DSSM召回](ch03/ch3.2/3.2.4.4)
- - 3.2.5 DeepFM排序
+ - [3.2.5 DeepFM排序](ch03/ch3.2/3.2.5)
- 3.2.6 规则与重排
- 3.2.7 任务调度与监控
- 3.2.8 当前问题汇总
diff --git a/docs/ch03/ch3.2/3.2.5.md b/docs/ch03/ch3.2/3.2.5.md
new file mode 100644
index 00000000..10afda16
--- /dev/null
+++ b/docs/ch03/ch3.2/3.2.5.md
@@ -0,0 +1,253 @@
+# 数据集介绍
+
+原始数据集共包含3个,实验时存放在目录`rank/examples/dataset/raw_data/`下。
+
++ **user_info_5w.csv**
+ + 该文件共包含了5万条用户的个人数据;
+ + 特征分别包括了:['user_id', 'device', 'os', 'province', 'city', 'age', 'gender'];
+ + 各特征的含义为:['用户id', '设备名称', '操作系统', '所在省', '所在市', '年龄', '性别'];
++ **doc_info.txt**
+ + 该文件包含了所有新闻的特征数据;
+ + 各特征的含义为:['文档id', '标题', '发文时间', '图片数量', '一级分类', '二级分类', '关键词'];
+
++ **train_data_5w.csv**
+ + 该文件为用户点击数据,包含了5万个用户在过去13天的点击数据;
+ + 各特征的含义为:['用户id', '文档id', '展现时间', '网路环境', '刷新次数', '展现位置', '是否点击', '消费时长(秒)'];
+
+
+
+# 数据处理
+
+数据处理的文件存放在`rank/examples/dataset/data_process/`下。
+
+## 训练集和测试集的划分
+
+训练集和测试集的划分程序为:**train&test_data_split.py**
+
++ 训练集:将所有用户在前12天的点击行为划为训练集;
++ 测试集:
+ + 将所有用户在第13天的点击行为化为测试集;
+ + 测试集丢弃特征:消费时长(秒),展现位置,是否点击;
+
++ 测试标签:
+ + 将测试集的真实标签单独进行存储;
+
+其他特征处理:
+
++ 选中消费时长小于0的样本,并将其消费时长设置为0;
++ 对所有样本的展现时间进行了格式处理,并新增了特征展现日期;
++ 新增特征index,目的是为了后续对测试集进行评估;
+
+## 特征处理
+
+### 用户和文档特征
+
+用户数据和文档数据的处理程序为:**user&doc_data_process.py**
+
+**用户数据处理**
+
++ 性别特征:原始的用户性别数据为用户对应不同性别的概率,这里直接将概率最高的性别作为用户的实际性别;
+
++ 年龄数据:原始的用户年龄数据为用户对应不同年龄段的概率,这里将概率最高的年龄段作为用户所处的年龄段;
+
+**文档数据处理**
+
++ 发文时间:对于部分发文时间异常或者为空的数据,使用已有文档中最早的发文时间进行填充;
++ 发文日期:将文档的发文时间,提取出对应的发文日期(年-月-日);
++ 图片数量:对部分异常的脏数据,使用 $0$ 进行填充处理;
++ 二级分类:对于存在多个二级分类的文档,从其选取一个作为其二级分类。优先选择不等于一级分类的二级分类,对于二级分类为空的文档使用一级分类进行填充;
++ 关键词:
+ + 每篇文档均存在多个关键词,每个关键词也会对应一个权重,这里选取权重最高的关键词作为文章的唯一关键词;
+ + 文档中不同的关键词及权重是采用逗号进行隔开的,但部分关键词本来就包含逗号(如==你好,李焕英==),故相关函数还对此进行了特殊处理;
+
+### 统计特征
+
+统计特征的生成的程序为:**news_data_process.py**
+
++ 从文档发文到展示的时间差:对于每一个样本,统计对应文档从发文到展示的日期差;
++ 用户特征统计:
+
+ + 统计每个用户过去几天,所展现的文档总数;
+ + 统计每个用户过去几天,在不同类别文档(一级分类)上的展现总数;
+ + 统计每个用户过去几天,在不同类别文档(二级分类)上的展现总数;
+ + 统计每个用户过去几天,整体的点击率;
+ + 统计每个用户过去几天,对不同类别文档(一级分类)上的点击率;
+ + 统计每个用户过去几天,对不同类别文档(二级分类)上的点击率;
+ + 统计每个用户过去几天,消费时长的总和;
+ + 统计每个用户过去几天,在不同类别文档(一级分类)上的总消费时长;
+ + 统计每个用户过去几天,在不同类别文档(二级分类)上的总消费时长;
+ + 统计每个用户过去几天,在不同类别文档(一级分类)上的平均消费时长;
+ + 统计每个用户过去几天,在不同类别文档(二级分类)上的平均消费时长;
+ + 统计每个用户过去几天,在不同类别文档(一级分类)上的消费时长的方差;
+ + 统计每个用户过去几天,在不同类别文档(二级分类)上的消费时长的方差;
++ 文档特征统计:
+
+ + 统计每篇文档在过去几天,被展示的总次数;
+ + 统计各类别(一级分类)文档在过去几天,被展示的总次数;
+ + 统计各类别(二级分类)文档在过去几天,被展示的总次数;
+ + 统计每篇文档在过去几天,平均的被点击率;
+ + 统计各类别(一级分类)文档在过去几天,平均被点击率;
+ + 统计各类别(二级分类)文档在过去几天,平均被点击率;
+ + 统计每篇文档在过去几天,总的被消费时长;
+ + 统计每篇文档在过去几天,平均的被消费时长;
+ + 统计每篇文档在过去几天,被消费时长的方差;
+ + 统计各类别(一级分类)文档在过去几天,总的被消费时长;
+ + 统计各类别(一级分类)文档在过去几天,平均的被消费时长;
+ + 统计各类别(一级分类)文档在过去几天,被消费时长的方差;
+ + 统计各类别(二级分类)文档在过去几天,总的被消费时长;
+ + 统计各类别(二级分类)文档在过去几天,平均的被消费时长;
+ + 统计各类别(二级分类)文档在过去几天,被消费时长的方差;
+
+
+### 特征归一化和编码
+
++ 连续型特征:
+ + 连续型特征包含的主要是统计特征,这里对于空值统一使用 $0$ 进行填充;
+ + 之后,对所有的连续型特征进行对数归一化, 即取 $log$ 对数;
+
++ 类别型特征:
+
+ + 类别型特征这里主要是通过 $LabelEncoder$ 的方式进行编码,以便后续模型处理为相应的 $Embedding$;
+
+
+
+# 排序模型
+
+排序模型的执行程序存放在`rank/examples/`下,分别为`deepfm_news.py`和`deepfm_ppnet_news.py`。
+
+## DeepFM
+
+DeepFM是2017年由华为与哈工大提出的排序模型,,模型主要包含两部分:FM部分+Deep部分。
+
++ FM部分:对不同特征域的Embedding进行两两交叉,以加强模型在浅层网络中的特征组合能力。
++ Deep部分:多层感知机网络模型。通过对特征各个维度进行充分的特征交叉组合,来学习到更多非线性以及组合特征的信息。
+
+论文链接:[[DeepFM: A Factorization-Machine based Neural Network for CTR Prediction (arxiv.org)](https://arxiv.org/abs/1703.04247)
+
+**实验结果**
+
+1. 参数设置
+
+```yaml
+# data para
+seed: 48
+# model para
+embed_dim: 32
+drop_rate: 0.5
+use_bn: Ture
+hidden_units: [64, 128, 64]
+# compile para
+learning_rate: 0.001
+epochs: 20
+batch_size: 2048
+val_splite: 0.1
+patience: 5
+restore_best_weights: True
+```
+
+2. 运行结果
+
+```bash
+Epoch 1/20
+2653/2653 [==============================] - 47s 17ms/step - loss: 0.3921 - auc: 0.7287 - val_loss: 0.3628 - val_auc: 0.7588
+Epoch 2/20
+2653/2653 [==============================] - 44s 17ms/step - loss: 0.3619 - auc: 0.7616 - val_loss: 0.3581 - val_auc: 0.7647
+Epoch 3/20
+2653/2653 [==============================] - 44s 17ms/step - loss: 0.3569 - auc: 0.7705 - val_loss: 0.3561 - val_auc: 0.7682
+Epoch 4/20
+2653/2653 [==============================] - 47s 18ms/step - loss: 0.3548 - auc: 0.7754 - val_loss: 0.3557 - val_auc: 0.7699
+Epoch 5/20
+2653/2653 [==============================] - 47s 18ms/step - loss: 0.3540 - auc: 0.7777 - val_loss: 0.3560 - val_auc: 0.7702
+Epoch 6/20
+2653/2653 [==============================] - 46s 18ms/step - loss: 0.3536 - auc: 0.7788 - val_loss: 0.3557 - val_auc: 0.7708
+Epoch 7/20
+2653/2653 [==============================] - 45s 17ms/step - loss: 0.3533 - auc: 0.7797 - val_loss: 0.3556 - val_auc: 0.7714
+Epoch 8/20
+2653/2653 [==============================] - 45s 17ms/step - loss: 0.3532 - auc: 0.7802 - val_loss: 0.3558 - val_auc: 0.7712
+Epoch 9/20
+2653/2653 [==============================] - 46s 17ms/step - loss: 0.3530 - auc: 0.7806 - val_loss: 0.3560 - val_auc: 0.7713
+Epoch 10/20
+2653/2653 [==============================] - 46s 17ms/step - loss: 0.3530 - auc: 0.7808 - val_loss: 0.3560 - val_auc: 0.7711
+Epoch 11/20
+2653/2653 [==============================] - 45s 17ms/step - loss: 0.3529 - auc: 0.7811 - val_loss: 0.3560 - val_auc: 0.7715
+Epoch 12/20
+2653/2653 [==============================] - 46s 17ms/step - loss: 0.3528 - auc: 0.7813 - val_loss: 0.3557 - val_auc: 0.7718
+251/251 [==============================] - 3s 11ms/step - loss: 0.3719 - auc: 0.7508
+test AUC: 0.750784
+```
+
+## DeepFM+PPNet
+
+将DeepFM模型中,DNN 模块替换为PPNet模型:
+
++ 在语音识别领域中,2014 年和 2016 年提出的 LHUC 算法(learning hidden unit contributions)核心思想是做说话人自适应(speaker adaptation),其中一个关键突破是在 DNN 网络中,为每个说话人学习一个特定的隐式单位贡献(hidden unit contributions),来提升不同说话人的语音识别效果。
++ 借鉴 LHUC 的思想,快手推荐团队在精排模型上展开了尝试。经过多次迭代优化,推荐团队设计出一种 gating 机制,可以增加 DNN 网络参数个性化并能够让模型快速收敛。快手把这种模型叫做 **PPNet(Parameter Personalized Net)**。
+
+参考链接:[1.9万亿参数量,快手落地业界首个万亿参数推荐精排模型](https://mp.weixin.qq.com/s?__biz=MzA3MzI4MjgzMw==&idx=4&mid=2650808254&scene=21&sn=6c295c8306b7339858f8ecfadfc9d698#wechat_redirect)
+
+**实验结果:**
+
+1. 参数设置
+
+```yaml
+# data para
+seed: 48
+# model para
+embed_dim: 32
+drop_rate: 0.5
+ppnet_size: 256
+ppnet_features: ['user_id', '一级分类', '年龄']
+use_bn: Ture
+hidden_units: [64, 128, 64]
+# compile para
+learning_rate: 0.001
+epochs: 20
+batch_size: 2048
+val_splite: 0.1
+patience: 5
+restore_best_weights: True
+```
+
+2. 运行结果
+
+```bash
+Epoch 1/20
+2653/2653 [==============================] - 56s 20ms/step - loss: 0.3929 - auc: 0.7303 - val_loss: 0.3648 - val_auc: 0.7568
+Epoch 2/20
+2653/2653 [==============================] - 53s 20ms/step - loss: 0.3620 - auc: 0.7622 - val_loss: 0.3591 - val_auc: 0.7651
+Epoch 3/20
+2653/2653 [==============================] - 55s 21ms/step - loss: 0.3578 - auc: 0.7706 - val_loss: 0.3580 - val_auc: 0.7690
+Epoch 4/20
+2653/2653 [==============================] - 53s 20ms/step - loss: 0.3560 - auc: 0.7755 - val_loss: 0.3587 - val_auc: 0.7701
+Epoch 5/20
+2653/2653 [==============================] - 54s 20ms/step - loss: 0.3551 - auc: 0.7787 - val_loss: 0.3580 - val_auc: 0.7706
+Epoch 6/20
+2653/2653 [==============================] - 55s 21ms/step - loss: 0.3545 - auc: 0.7809 - val_loss: 0.3587 - val_auc: 0.7718
+Epoch 7/20
+2653/2653 [==============================] - 54s 20ms/step - loss: 0.3541 - auc: 0.7829 - val_loss: 0.3586 - val_auc: 0.7720
+Epoch 8/20
+2653/2653 [==============================] - 53s 20ms/step - loss: 0.3538 - auc: 0.7842 - val_loss: 0.3587 - val_auc: 0.7721
+251/251 [==============================] - 4s 13ms/step - loss: 0.3686 - auc: 0.7543
+test AUC: 0.754304
+```
+
+
+# 程序执行
+
+```bash
+# 数据预处理
+1. user&doc_data_process.py
+2. train&test_data_split.py
+3. news_data_process.py
+
+# 排序模型
+4. deepfm_news.py 或 deepfm_ppnet_news.py
+```
+
+# Requirements
+
+- Tensorflow2.5 (GPU)
+- Numpy
+- Pandas
+- Swifter
+- Sklearn
diff --git a/docs/ch03/ch3.2/3.2.md b/docs/ch03/ch3.2/3.2.md
new file mode 100644
index 00000000..7fd1cad8
--- /dev/null
+++ b/docs/ch03/ch3.2/3.2.md
@@ -0,0 +1,17 @@
+# 特别说明
+
+早期的新闻推荐系统实践内容中使用数据库(Mysql/Mongo/Redis)+ 前端(Vue)+ 后端(Flask)实+ 推荐策略,实现了推荐系统的基本流程。下面简单对该系统进行总结,看完之后看大家是能从中获取到相应的内容。
+
+- 系统将新闻的爬取、预处理、入库等事情都串在了一起,并将整个过程都自动化的执行
+- 对于展示的新闻内容,没有使用复杂的推荐算法,仅仅是通过简单的策略实现了热门打分,然后按照热度分进行排序。此外,考虑到展示的内容可能同类别的都排在了一起,实现了一个简单的类别打散的策略。(注意:整个系统中都没有排序相关的模型,只有简单的规则类召回)
+- 当前系统虽然能够实现用户的注册,点击等交互功能,但是由于使用的用户很少,很难得到一个比较好的用户行为数据,也就无法有效的将该系统迭代起来,甚至都无法很好的对推荐效果进行评估。
+- 为了实现能够对系统中的推荐算法进行有效的评估,我们在代码中还想嵌入一个现有的公开新闻推荐数据集,这个数据集是科大讯飞的一个竞赛数据集。所以在代码中的recall和rank目录下添加了一部分处理竞赛数据集的代码,目前由于时间原因,还没有把整个竞赛数据集全部迁入到数据库、前端展示等环节。也就是说基于竞赛数据集的系统和上面提到的(已经完全可以运行的基于规则的新闻推荐系统),是完全脱节的,后面会花时间把整个流程给串起来。
+
+该新闻推荐系统只是基于现有的技术,实现了推荐系统的基本流程,对于架构是否合理,技术选型是否合理都没有深入研究,这也是未来该项目的优化方向,会结合实际工业的推荐系统对其进行不断的迭代优化。
+
+**新闻推荐系统实践前端展示和后端逻辑(项目没有任何商用价值仅供入门者学习)**
+
+

+

+
+