提交 71899ca1 编写于 作者: 片刻小哥哥's avatar 片刻小哥哥

修复原来删除 nlp的内容,迁移到 docs/nlp_old 下面

上级 5d89832c
......@@ -3,7 +3,7 @@ __pycache__/
*.py[cod]
*$py.class
.vscode
data/*
data
# C extensions
*.so
......
# 自然语言处理 - 1.入门介绍
* 语言是知识和思维的载体
* 自然语言处理 (Natural Language Processing, NLP) 是计算机科学,人工智能,语言学关注计算机和人类(自然)语言之间的相互作用的领域。
## NLP相关的技术
| 中文 | 英文 | 描述 |
| --- | --- | --- |
| 分词 | Word Segmentation | 将连续的自然语言文本,切分成具有语义合理性和完整性的词汇序列 |
| 命名实体识别 | Named Entity Recognition | 识别自然语言文本中具有特定意义的实体(人、地、机构、时间、作品等) |
| 词性标注 | Part-Speech Tagging | 为自然语言文本中的每个词汇赋予一个词性(名词、动词、形容词等) |
| 依存句法分析 | Dependency Parsing | 自动分析句子中的句法成分(主语、谓语、宾语、定语、状语和补语等成分) |
| 词向量与语义相似度 | Word Embedding & Semantic Similarity | 依托全网海量数据和深度神经网络技术,实现了对词汇的向量化表示,并据此实现了词汇的语义相似度计算 |
| 文本语义相似度 | Text Semantic Similarity | 依托全网海量数据和深度神经网络技术,实现文本间的语义相似度计算的能力 |
| 篇章分析 | Document Analysis | 分析篇章级文本的内在结构,进而分析文本情感倾向,提取评论性观点,并生成反映文本关键信息的标签与摘要 |
| 机器翻译技术 | Machine Translating | 基于互联网大数据,融合深度神经网络、统计、规则多种翻译方法,帮助用户跨越语言鸿沟,与世界自由沟通 |
## 场景案例
### 案例1(解决交叉歧义)
**分词(Word Segmentation)** : 将连续的自然语言文本,切分成具有语义合理性和完整性的词汇序列
例句: 致毕业和尚未毕业的同学。
1. `致` `毕业` `和` `尚未` `毕业` `的` `同学`
2. `致` `毕业` `和尚` `未` `毕业` `的` `同学`
其他案例:
1. 校友 和 老师 给 尚未 毕业 同学 的 一 封 信
2. 本科 未 毕业 可以 当 和尚 吗
### 案例2(从粒度整合未登录体词)
**命名实体识别(Named Entity Recognition)**: 识别自然语言文本中具有特定意义的实体(人、地、机构、时间、作品等)
例句: 天使爱美丽在线观看
* 分词: `天使` `爱` `美丽` `在线` `观看`
* 实体: 天使爱美丽 -> 电影
其他案例:
1. 网页: 天使爱美丽 土豆 高清视频
2. 网页: 在线直播 爱 美丽 的 天使
### 案例3(结构歧义问题)
* **词性标注(Part-Speech Tagging)**: 为自然语言文本中的每个词汇赋予一个词性(名词、动词、形容词等)
* **依存句法分析(Dependency Parsing)**: 自动分析句子中的句法成分(主语、谓语、宾语、定语、状语和补语等成分)
评论: 房间里还可以欣赏日出
* 房间里: 主语
* 还可以: 情态动词
* 欣赏: 动词
* 日出: 宾语
歧义:
1. 房间还可以
2. 可以欣赏日出
### 案例4(词汇语言相似度)
**词向量与语义相似度(Word Embedding & Semantic Similarity)**: 对词汇进行向量化表示,并据此实现词汇的语义相似度计算。
例如: 西瓜 与 (呆瓜/草莓),哪个更接近?
* 向量化表示: 西瓜(0.1222, 0.22333, .. )
* 相似度计算: 呆瓜(0.115) 草莓(0.325)
* 向量化表示: (-0.333, 0.1223 .. ) (0.333, 0.3333, .. )
### 案例5(文本语义相似度)
**文本语义相似度(Text Semantic Similarity)**: 依托全网海量数据和深度神经网络技术,实现文本间的语义相似度计算的能力
例如: 车头如何防止车牌 与 (前牌照怎么装/如何办理北京牌照),哪个更接近?
* 向量化表示: 车头如何防止车牌(0.1222, 0.22333, .. )
* 相似度计算: 前牌照怎么装(0.762) 如何办理北京牌照(0.486)
* 向量化表示: (-0.333, 0.1223 .. ) (0.333, 0.3333, .. )
### 案例6(篇章分析)
**篇章分析(Document Analysis)**: 分析篇章级文本的内在结构,进而分析文本情感倾向,提取评论性观点,并生成反映文本关键信息的标签与摘要
例如:
![](img/1.自然语言处理入门介绍/篇章分析.jpg)
### 案例7(机器翻译)
**机器翻译技术(Machine Translating)**: 基于互联网大数据,融合深度神经网络、统计、规则多种翻译方法,帮助用户跨越语言鸿沟,与世界自由沟通
![](img/1.自然语言处理入门介绍/机器翻译.png)
---
* 参考百度科普课程: <http://bit.baidu.com/product>
此差异已折叠。
# 篇章分析-内容概述
## 篇章分析变迁
1. 内容生态: 新浪 -> 百家号、今日头条(自媒体)
2. 用户成为信息的生产中心: web 1.0 -> 百度贴吧、新浪微博、团购网站(用户评论,富有个人情感和用户观点的信息)
3. 移动、无屏: 显示屏 -> 手机、Siri(展示的终端)
## 篇章分析场景
篇章分析重要性: 让人们最平等`便捷``获取信息``找到所求`
1. 个性化信息获取(搜索引擎的理解和推荐): 从搜索的角度来看,通过对内容的深入理解,我们能够精准地对内容进行分析,然后将内容推荐给需要的用户,达到不搜即得。
2. 便捷咨询阅读(头条的热门推荐): 从资讯阅读的角度来看,我们通过对内容进行概括总结、形成摘要,就能搞让用户更快捷地浏览信息、获取知识。
3. 信息直接满足: 更进一步说,对用户的问题,我们可以基于内容理解,直接给出答案,从而满足用户的需求。
`总之`: 通过篇章分析,我们能够进行内容理解,从而更好地服务用户。
## 篇章分析概述
`篇章是形式上互相衔接、语义上前后连贯的句子序列。`
有以下3种:
* 1.文章: 新闻稿、博客、微博
* 2.评论: O2O服务的用户评论、豆瓣的影评、微博上的动态
* 3.对话: 话题上是相互衔接的、语义上也是连贯的一个对话序列
## 篇章分析任务
![](img/3.1.篇章分析-内容标签/篇章分析任务.jpg)
# 篇章分析-内容标签
`标签`: 这种种的`单词``词组`都是一种标签的形式
1. 新闻稿,打出关于该报道的各种各样的标签,来表示其关键信息
2. 论文中,我们也会表明一些文章的`领域分类`以及`关键词`等标签
3. 微博用#代表一个话题,这是典型的社会化标签
## 标签用途
1. 关键信息展示
* 用户可以大致了解文章的主要信息,从而决定要不要对信息进行进一步深入地浏览
2. 频道划分
* 在很多的媒体网站,经常会有频道划分,使用了就是文章的分类标签
3. 话题聚合
* 标签也可以用来做话题聚合(例如: #人民的名义# 集合所有关于这个话题的信息,让用户更深入的了解信息)
## 应用: 个性化推荐
* 标签可以用来建立用户的画像
比如对对于用户搜索过的Query,还有他浏览过的文章,都可以通过标签的技术。提取出主要的兴趣点,从而也就建立了用户的画像
* 标签可以对内容进行建模
通过标签技术,我们能够提取文章中的关键信息标签。这样来看标签就作为了用户和内容的一个共同表示。
* 推荐的时候,我们通过对用户画像的标签和内容模型的标签进行匹配,就能够对用户进行一个精准的个性化推荐
## 百度内容标签
![](img/3.2.篇章分析-内容标签/百度内容标签.jpg)
## 标签体系: 面向推荐的标签图谱
* 标签图谱刻画了用户的兴趣点,以及兴趣点之间的关联关系。
* 节点表示了用户的兴趣点,而边表示了兴趣点之间的关联关系(边是带有权重的,表示关联强度)。
* 包括3种节点: 主题标签-绿色,话题标签-紫色,实体标签-蓝色。
* 有了关联关系,我们可以进行一定程度的探索和泛化。(例如: 无人驾驶和人工智能关联很强,如果有人看了无人驾驶,我们就给他推荐人工智能)
![](img/3.2.篇章分析-内容标签/面向推荐的标签图谱.jpg)
## 标签体系: 基于大数据分析的图谱构建
* 用户信息来源: 贴吧、微博
* 标签的相关性分析: 通过关联规则,发现2个标签总同时出现,我们觉得这是高相关的。
![](img/3.2.篇章分析-内容标签/基于大数据分析的图谱构建.jpg)
## 标签计算
> 主题分类
* 主题标签的计算,是一种很典型的文本分类问题: 传统的朴素贝叶斯、最大熵、SVM 等解决方案。
* 当前我们主要采用的是: 基于神经网络的方法(可以看右侧的示意图)
* 整个网络分成3层次:
* 第一层 原始特征层: 抽取简单的原始特征,例如说文章出现的单词、词组 等等
* 第二层 表示层: 通过一些 embedding的算法、CNN、LSTM的方法
* 第三层 排序层: 计算文章与主题之间的相似度,具体会计算每个主题与文章的相似度,并将相似度作为最终的一个主题分类的结果。这种计算的好处能够天然的支持多标记,也就是一篇文章可以同时计算出多个主题标签。
![](img/3.2.篇章分析-内容标签/主题分类.jpg)
> 通用标签
* 通用标签主要是计算内容中的实体和话题,我们综合了两种策略。
* 第一种策略: 针对比较热门的高频标签
* 这种标签我们主要通过一些预测的方法得到,预测的方法: 基于相似度计算得到的---这种方法并不要求标签一定在文章中出现
* 例如: 美国大选这种标签,如果一篇文章出现了 `希拉里` `特朗普` `辩论` 等一些词,即使没有出现美国大选,我们通过语义相似度的方法也能把这个标签计算出来。
* 第二种策略: 面向中低频的标签
* 这种标签相关的信息,不是那么丰富,所以我们计算的时候更多依赖的是标签在文章中的信息
* 比如: 这个标签在文章中出现的频率 或 出现的位置;如果出现在标题,那么它可能就会比较重要。
* 通过融合这2种策略,形成我们通用标签的结果。
![](img/3.2.篇章分析-内容标签/通用标签.jpg)
## 内容标签在Feed流中的应用
1. 标签可以用来话题聚合: 比如表示人工智能的标签全部都会集合到同一个话题下面。这样用户可以对人工智能这个话题进行非常充分的浏览。
2. 话题频道划分: 比如我们在手机百度上面就可以看到,Feed流上面有多个栏目,用户可以点击 `体育` `时尚`等频道
![](img/3.2.篇章分析-内容标签/内容标签在Feed流中的应用.jpg)
# 篇章分析-情感分类
## 用户评论剧增
`服务评论` `商品评论` `社交评论`
## 情感分析应用
`消费决策` `舆情分析`
> 情感分类 和 观点挖掘
* 对(文本的)观点、情感、情绪和评论进行分析计算
![](img/3.3.篇章分析-情感分类/情感分类和观点挖掘.jpg)
> 情感分类
* 给定一个文本判断其情感的极性,包括积极、中性、消极。
* LSTM 对文本进行语义表示,进而基于语义表示进行情感分类。
![](img/3.3.篇章分析-情感分类/情感分类.jpg)
> 观点挖掘
* 观点聚类: 主要目标是对大量的评论数据进行聚类,将相同的观点抽取出来,并形成一个情感搭配词典(算法是: 搭配抽取、词法分析、聚类归一,从而获得一个情感搭配。我们就可以进行观点抽取)
* 观点抽取: 就是对输入的文本进行计算,将其中的情感标签抽取出来,这里的标签,都是来自于情感搭配词典的,也就是观点聚类获得的词典。
* 观点抽取一种简单的做法是直接通过标签匹配的方式得到,比如: 服务不错这个情感搭配,恰好在文本中出现,我们就可以把它抽取出来。
* 但是这种简单的抽取方法,其实上只能从字面上抽取情感搭配,而无法解决字面不一致的,但是意思一样的情感搭配抽取,因此我们还引入了语义相似度的方法。这种方法主要是通过神经网络进行计算的。它能解决这种字面不一致,语义一样的抽取问题。
![](img/3.3.篇章分析-情感分类/观点挖掘.jpg)
> 观点摘要
综合了情感分类和观点挖掘的一些技术,而获得的一个整体的应用技术
![](img/3.3.篇章分析-情感分类/观点摘要.jpg)
## 百度应用: 评论观点
![](img/3.3.篇章分析-情感分类/百度应用评论观点.jpg)
## 百度应用: 推荐理由
![](img/3.3.篇章分析-情感分类/百度应用推荐理由.jpg)
# 篇章分析-自动摘要
## 信息爆炸与移动化
![](img/3.4.篇章分析-自动摘要/信息爆炸与移动化.jpg)
## 自动摘要应用
* 便捷信息浏览
* 我们可以为每个新闻抽取摘要,用户可以通过摘要快速了解新闻概况。
* 进而决定是否要进一步细致地浏览。
* 而更进一步说: 摘要还可以直接进行信息满足。
* 信息满足
* 传统搜索得到一大批网页信息
* 现在通过问答技术我们能够将网页中最核心的片段摘要提取出来。
* 用户通过阅读片段,就可以直接得到满足,而不需要打开页面。
## 自动摘要
* 对海量内容进行提炼与总结
* 以简洁、直观的摘要来概括用户所关注的主要内容
* 方便用户快速了解与浏览海量内容
![](img//3.4.篇章分析-自动摘要/摘要系统.jpg)
* 自动摘要分类
![](img/3.4.篇章分析-自动摘要/自动摘要分类.jpg)
* 典型摘要计算流程
![](img/3.4.篇章分析-自动摘要/典型摘要计算流程.jpg)
> 基于篇章信息的通用新闻摘要
![](img/3.4.篇章分析-自动摘要/基于篇章信息的通用新闻摘要.jpg)
> 篇章主题摘要
![](img/3.4.篇章分析-自动摘要/篇章主题摘要.jpg)
> 问答摘要
![](img/3.4.篇章分析-自动摘要/问答摘要.jpg)
## 百度应用
> 文本和语言摘要
![](img/3.4.篇章分析-自动摘要/百度应用文本和语言摘要.jpg)
> 问答摘要
![](img/3.4.篇章分析-自动摘要/百度应用问答摘要.jpg)
> 搜索播报摘要和图像摘要
![](img/3.4.篇章分析-自动摘要/百度应用搜索播报摘要和图像摘要.jpg)
## 总结
![](img/3.4.篇章分析-自动摘要/总结.jpg)
使用Bakeoff-3评测中所采用的的BIO标注集:
B-PER、I-PER 代表人名首字、人名非首字,
B-LOC、I-LOC 代表地名首字、地名非首字,
B-ORG、I-ORG 代表组织机构名首字、组织机构名非首字,
O 代表该字不属于命名实体的一部分。
输入输出的计算方式:
$$L_{out}=floor((L_{in}+2*padding-dilation*(kernerl\_size-1)-1)/stride+1)$$
# 【入门须知】必须了解
实体: 抽取
关系: 图谱
意图: 分类
* **【入门须知】必须了解**: <https://github.com/apachecn/AiLearning/tree/master/docs/nlp>
* **【入门教程】强烈推荐: PyTorch 自然语言处理**: <https://github.com/apachecn/NLP-with-PyTorch>
* Python 自然语言处理 第二版: <https://usyiyi.github.io/nlp-py-2e-zh>
* 推荐一个[liuhuanyong大佬](https://github.com/liuhuanyong)整理的nlp全面知识体系: <https://liuhuanyong.github.io>
## nlp 学习书籍和工具:
* 百度搜索: Python自然语言处理
* 读书笔记: <https://wnma3mz.github.io/hexo_blog/2018/05/13/《Python自然语言处理》阅读笔记(一)>
* Python自然语言处理工具汇总: <https://blog.csdn.net/sa14023053/article/details/51823122>
## nlp 全局介绍视频: (简单做了解就行)
地址链接: http://bit.baidu.com/Course/detail/id/56.html
1. 自然语言处理知识入门
2. 百度机器翻译
3. 篇章分析
4. UNIT: 语言理解与交互技术
## 中文 NLP
> 开源 - 词向量库集合
* <https://github.com/Embedding/Chinese-Word-Vectors>
* <https://github.com/brightmart/nlp_chinese_corpus>
* <https://github.com/codemayq/chinese_chatbot_corpus>
* <https://github.com/candlewill/Dialog_Corpus>
> 深度学习必学
1. [反向传递](/docs/dl/反向传递.md): https://www.cnblogs.com/charlotte77/p/5629865.html
2. [CNN原理](/docs/dl/CNN原理.md): http://www.cnblogs.com/charlotte77/p/7759802.html
3. [RNN原理](/docs/dl/RNN原理.md): https://blog.csdn.net/qq_39422642/article/details/78676567
4. [LSTM原理](/docs/dl/LSTM原理.md): https://blog.csdn.net/weixin_42111770/article/details/80900575
> [Word2Vec 原理](/docs/nlp/Word2Vec.md):
1. 负采样
介绍:
自然语言处理领域中,判断两个单词是不是一对上下文词(context)与目标词(target),如果是一对,则是正样本,如果不是一对,则是负样本。
采样得到一个上下文词和一个目标词,生成一个正样本(positive example),生成一个负样本(negative example),则是用与正样本相同的上下文词,再在字典中随机选择一个单词,这就是负采样(negative sampling)。
案例:
比如给定一句话“这是去上学的班车”,则对这句话进行正采样,得到上下文“上”和目标词“学”,则这两个字就是正样本。
负样本的采样需要选定同样的“上”,然后在训练的字典中任意取另一个字,如“我”、“梦”、“目”,这一对就构成负样本。
训练需要正样本和负样本同时存在。
优势:
负采样的本质: 每次让一个训练样本只更新部分权重,其他权重全部固定;减少计算量;(一定程度上还可以增加随机性)
## nlp 操作流程
[本项目](https://pytorch.apachecn.org/docs/1.0/#/char_rnn_classification_tutorial) 试图通过名字分类问题给大家描述一个基础的深度学习中自然语言处理模型,同时也向大家展示了Pytorch的基本玩法。 其实对于大部分基础的NLP工作,都是类似的套路:
1. 收集数据
2. 清洗数据
3. 为数据建立字母表或词表(vocabulary或者叫look-up table)
4. 根据字母表或者词表把数据向量化
5. 搭建神经网络,深度学习中一般以LSTM或者GRU为主,按照需求结合各种其他的工具,包括embedding,注意力机制,双向RNN等等常见算法。
6. 输入数据,按需求得到输出,比如分类模型根据类别数来得到输出,生成模型根据指定的长度或者结束标志符来得到输出等等。
7. 把输出的结果进行处理,得到最终想要的数据。常需要把向量化的结果根据字母表或者词表变回文本数据。
8. 评估模型。
如果真的想要对自然语言处理或者序列模型有更加全面的了解,建议大家去网易云课堂看一看吴恩达深度学习微专业中的序列模型这一板块,可以说是讲的非常清楚了。 此外极力推荐两个blog:
1. 讲述RNN循环神经网络在深度学习中的各种应用场景。http://karpathy.github.io/2015/05/21/rnn-effectiveness/
2. 讲述LSTM的来龙去脉。http://colah.github.io/posts/2015-08-Understanding-LSTMs/
最后,本文参考整合了:
* Pytorch中文文档: https://pytorch.apachecn.org
* Pytorch官方文档: http://pytorch.org/tutorials/intermediate/char_rnn_classification_tutorial.html
* Ngarneau小哥的博文: https://github.com/ngarneau/understanding-pytorch-batching-lstm
* 另外,本项目搭配Sung Kim的Pytorch Zero To All的第13讲rnn_classification会更加方便食用喔,视频可以在油管和b站中找到。
## nlp - 比赛链接
* https://competitions.codalab.org/competitions/12731
* https://sites.ualberta.ca/%7Emiyoung2/COLIEE2018/
* https://visualdialog.org/challenge/2018
+ 人机对话 NLP
- http://jddc.jd.com
+ 司法数据文本的 NLP
- http://cail.cipsc.org.cn
+ “达观杯” 文本智能处理挑战赛
- http://www.dcjingsai.com/common/cmpt/“达观杯”文本智能处理挑战赛_竞赛信息.html
+ 中文论文摘要数据
- https://biendata.com/competition/smpetst2018
+ 中文问答任务
- https://biendata.com/competition/CCKS2018_4/
+ 第二届讯飞杯中文机器阅读理解评测
- http://www.hfl-tek.com/cmrc2018
+ 2018机器阅读理解技术竞赛 这也是结束了的 NLP
- http://mrc2018.cipsc.org.cn
+ 句子文本相似度计算
- https://www.kaggle.com/c/quora-question-pairs
* * *
【比赛收集平台】: https://github.com/iphysresearch/DataSciComp
# Word2Vec 讲解
## 介绍
**需要复习** 手写 Word2Vec 源码: https://blog.csdn.net/u014595019/article/details/51943428
* 2013年,Google开源了一款用于词向量计算的工具—— `word2vec`,引起了工业界和学术界的关注。
* `word2vec` 算法或模型的时候,其实指的是其背后用于计算 **word vector**`CBoW` 模型和 `Skip-gram` 模型
* 很多人以为 `word2vec` 指的是一个算法或模型,这也是一种谬误。
* 因此通过 Word2Vec 技术 输出的词向量可以被用来做很多NLP相关的工作,比如聚类、找同义词、词性分析等等.
> 适用场景
1. cbow适用于小规模,或者主题比较散的语料,毕竟他的向量产生只跟临近的字有关系,更远的语料并没有被采用。
2. 而相反的skip-gram可以处理基于相同语义,义群的一大批语料。
## CBoW 模型(Continuous Bag-of-Words Model)
* 连续词袋模型(CBOW)常用于NLP深度学习。
* 这是一种模式,它试图根据目标词 `之前``之后` 几个单词的背景来预测单词(CBOW不是顺序)。
* CBOW 模型: 能够根据输入周围n-1个词来预测出这个词本身.
* 也就是说,CBOW模型的输入是某个词A周围的n个单词的词向量之和,输出是词A本身的词向量.
![CBoW 模型/img/NLP/Word2Vce/CBoW.png)
## Skip-gram 模型
* skip-gram与CBOW相比,只有细微的不同。skip-gram的输入是当前词的词向量,而输出是周围词的词向量。
* Skip-gram 模型: 能够根据词本身来预测周围有哪些词.
* 也就是说,Skip-gram模型的输入是词A本身,输出是词A周围的n个单词的词向量.
![Skip-gram 模型/img/NLP/Word2Vce/Skip-gram.png)
明天看看这个案例: https://blog.csdn.net/lyb3b3b/article/details/72897952
## 补充: NPLM - Ngram 模型
* n-gram 模型是一种近似策略,作了一个马尔可夫假设: 认为目标词的条件概率只与其之前的 n 个词有关
* NPLM基于 n-gram, 相当于目标词只有上文。
* * *
参考资料:
1. https://www.cnblogs.com/iloveai/p/word2vec.html
......@@ -13,6 +13,9 @@ import sys
import math
import random
from operator import itemgetter
from collections import defaultdict
# 这是我的自定义库,可以注释掉,代码也可以注释 TimeStat
from middleware.utils import TimeStat
print(__doc__)
# 作用: 使得随机数据可预测
random.seed(0)
......@@ -117,13 +120,20 @@ class UserBasedCF():
# 统计在相同电影时,不同用户同时出现的次数
print('building user co-rated movies matrix...', file=sys.stderr)
# for movie, users in movie2users.items():
# for u in users:
# for v in users:
# if u == v:
# continue
# usersim_mat.setdefault(u, {})
# usersim_mat[u].setdefault(v, 0)
# usersim_mat[u][v] += 1
for movie, users in movie2users.items():
for u in users:
usersim_mat.setdefault(u, defaultdict(int))
for v in users:
if u == v:
continue
usersim_mat.setdefault(u, {})
usersim_mat[u].setdefault(v, 0)
usersim_mat[u][v] += 1
print('build user co-rated movies matrix success', file=sys.stderr)
......@@ -132,10 +142,13 @@ class UserBasedCF():
simfactor_count = 0
PRINT_STEP = 2000000
for u, related_users in usersim_mat.items():
for v, count in related_users.iteritems():
# 余弦相似度
for v, count in related_users.items():
# 余弦相似度(有问题)
usersim_mat[u][v] = count / math.sqrt(
len(self.trainset[u]) * len(self.trainset[v]))
# 杰卡德(Jaccard)相似性
# usersim_mat[u][v] = count / (len(set(self.trainset[u] + self.trainset[v]))
simfactor_count += 1
# 打印进度条
if simfactor_count % PRINT_STEP == 0:
......@@ -165,7 +178,7 @@ class UserBasedCF():
for v, wuv in sorted(
self.user_sim_mat[user].items(), key=itemgetter(1),
reverse=True)[0:K]:
for movie, rating in self.trainset[v].iteritems():
for movie, rating in self.trainset[v].items():
if movie in watched_movies:
continue
# predict the user's "interest" for each movie
......@@ -224,15 +237,22 @@ class UserBasedCF():
precision, recall, coverage, popularity), file=sys.stderr)
if __name__ == '__main__':
@TimeStat
def main():
path_root = "/Users/jiangzl/work/data/机器学习"
# ratingfile = 'data/16.RecommenderSystems/ml-1m/ratings.dat'
ratingfile = 'data/16.RecommenderSystems/ml-100k/u.data'
ratingfile = '%s/16.RecommenderSystems/ml-100k/u.data' % path_root
# 创建UserCF对象
usercf = UserBasedCF()
# 将数据按照 7:3的比例,拆分成: 训练集和测试集,存储在usercf的trainset和testset中
usercf.generate_dataset(ratingfile, pivot=0.7)
# 计算用户之间的相似度
usercf.calc_user_sim()
# 评估推荐效果
usercf.evaluate()
print(usercf.testset)
# # 计算用户之间的相似度
# usercf.calc_user_sim()
# # 评估推荐效果
# usercf.evaluate()
if __name__ == '__main__':
main()
......@@ -5,8 +5,10 @@ import numpy as np
from sklearn.decomposition import NMF
import matplotlib.pyplot as plt
RATE_MATRIX = np.array([[5, 5, 3, 0, 5, 5], [5, 0, 4, 0, 4, 4],
[0, 3, 0, 5, 4, 5], [5, 4, 3, 3, 5, 5]])
RATE_MATRIX = np.array([[5, 5, 3, 0, 5, 5],
[5, 0, 4, 0, 4, 4],
[0, 3, 0, 5, 4, 5],
[5, 4, 3, 3, 5, 5]])
nmf = NMF(n_components=2) # 设有2个隐主题
user_distribution = nmf.fit_transform(RATE_MATRIX)
......
......@@ -93,64 +93,6 @@ if __name__ == "__main__":
## bert / Embedding/ + lstm + crt
#%%
# 加载数据
class TextBert():
def __init__(self):
self.path_config = Config.bert.path_config
self.path_checkpoint = Config.bert.path_checkpoint
self.token_dict = {}
with codecs.open(Config.bert.dict_path, 'r', 'utf8') as reader:
for line in reader:
token = line.strip()
self.token_dict[token] = len(self.token_dict)
def prepare_data(self):
neg = pd.read_excel(Config.bert.path_neg, header=None)
pos = pd.read_excel(Config.bert.path_pos, header=None)
data = []
for d in neg[0]:
data.append((d, 0))
for d in pos[0]:
data.append((d, 1))
# 按照9:1的比例划分训练集和验证集
random_order = list(range(len(data)))
np.random.shuffle(random_order)
train_data = [data[j] for i, j in enumerate(random_order) if i % 10 != 0]
valid_data = [data[j] for i, j in enumerate(random_order) if i % 10 == 0]
return train_data, valid_data
def build_model(self, m_type="bert"):
if m_type == "bert":
bert_model = load_trained_model_from_checkpoint(self.path_config, self.path_checkpoint, seq_len=None)
for l in bert_model.layers:
l.trainable = True
x1_in = Input(shape=(None,))
x2_in = Input(shape=(None,))
x = bert_model([x1_in, x2_in])
x = Lambda(lambda x: x[:, 0])(x)
p = Dense(1, activation='sigmoid')(x)#根据分类种类自行调节,也可以多加一些层数
model = Model([x1_in, x2_in], p)
model.compile(
loss='binary_crossentropy',
optimizer=Adam(1e-5), # 用足够小的学习率
metrics=['accuracy']
)
else:
# 否则用 Embedding
model = Sequential()
model.add(Embedding(len(vocab), EMBED_DIM, mask_zero=True)) # Random embedding
model.add(Bidirectional(LSTM(BiRNN_UNITS // 2, return_sequences=True)))
crf = CRF(len(chunk_tags), sparse_target=True)
model.add(crf)
model.compile('adam', loss=crf.loss_function, metrics=[crf.accuracy])
model.summary()
return model
#%%
# 加载数据
from keras_bert import Tokenizer
......
#!/usr/bin/python
# coding:utf-8
# -------------------------------------------------------------------------------
# Name: 推荐系统
# Purpose: 基于内容推荐
# Author: jiangzhonglian
# Create_time: 2020年10月15日
# Update_time: 2020年10月21日
# -------------------------------------------------------------------------------
import os
import sys
import numpy as np
import pandas as pd
# 自定义库
import config.set_content as setting
from middleware.utils import pd_load, pd_like, pd_save, pd_rename, get_days
def data_converting(infile, outfile):
"""
# 将用户交易数据转化为:
# 将
# 用户ID、各种基金、变动金额、时间
# 转化为:
# 用户ID、基金ID、购买金额、时间的数据
"""
print("Loading user daliy data...")
df = pd_load(infile)
df["money"] = df["变动金额"].apply(lambda line: abs(line))
df_user_item = df.groupby(["用户账号", "证券代码"], as_index=False).agg({
"money": np.sum
}).sort_values("money", ascending=True)
pd_rename(df_user_item, ["user_id", "item_id", "rating"])
pd_save(df_user_item, outfile)
def create_user2item(infile, outfile):
"""创建user-item评分矩阵"""
print("Loading user daliy data...")
df_user_item = pd_load(infile)
user_id = sorted(df_user_item['user_id'].unique(), reverse=False)
item_id = sorted(df_user_item['item_id'].unique(), reverse=False)
# print("+++ user_id:", user_id)
# print("+++ item_id:", item_id)
rating_matrix = np.zeros([len(user_id),len(item_id)])
rating_matrix = pd.DataFrame(rating_matrix, index=user_id, columns=item_id)
print("Converting data...")
count = 0
user_num= len(user_id)
for uid in user_id:
user_rating = df_user_item[df_user_item['user_id'] == uid].drop(['user_id'], axis=1)
user_rated_num = len(user_rating)
for row in range(0, user_rated_num):
item_id = user_rating['item_id'].iloc[row]
# 行(用户),列(电影),得分
rating_matrix.loc[uid, item_id] = user_rating['rating'].iloc[row]
count += 1
if count % 10 == 0:
completed_percentage = round(float(count) / user_num * 100)
print("Completed %s" % completed_percentage + "%")
rating_matrix.index.name = 'user_id'
pd_save(rating_matrix, outfile, index=True)
def create_item2feature(infile, outfile):
"""创建 item-特征-是否存在 矩阵"""
print("Loading item feature data...")
df_item_info = pd_load(infile, header=1)
items_num = df_item_info.shape[0]
columns = df_item_info.columns.tolist()
new_cols = [col for col in columns if col not in ["info_type", "info_investype"]]
info_types = sorted(df_item_info["info_type"].unique(), reverse=False)
info_investypes = sorted(df_item_info["info_investype"].unique(), reverse=False)
dict_n_cols = {"info_type": info_types, "info_investype": info_investypes}
new_cols.append(dict_n_cols)
# 获取新的列名
def get_new_columns(new_cols):
new_columns = []
for col in new_cols:
if isinstance(col, dict):
for k, vs in col.items():
new_columns += vs
else:
new_columns.append(col)
return new_columns
new_columns = get_new_columns(new_cols)
# print(new_cols)
# print(new_columns)
# ['item_id', 'info_name', 'info_trackerror', 'info_manafeeratioo', 'info_custfeeratioo', 'info_salefeeratioo', 'info_foundsize', 'info_foundlevel', 'info_creattime', 'info_unitworth'
# {'info_type': ['QDII-ETF', '混合型', '股票指数', 'ETF-场内'], 'info_investype': ['契约型开放式', '契约型封闭式']}]
def deal_line(line, new_cols):
result = []
for col in new_cols:
if isinstance(col, str):
result.append(line[col])
elif isinstance(col, dict):
for k, vs in col.items():
for v in vs:
if v == line[k]:
result.append(1)
else:
result.append(0)
else:
print("类型错误")
sys.exit(1)
return result
df = df_item_info.apply(lambda line: deal_line(line, new_cols), axis=1, result_type="expand")
pd_rename(df, new_columns)
# 处理时间
end_time = "2020-10-19"
df["days"] = df["info_creattime"].apply(lambda str_time: get_days(str_time, end_time))
# print(df.head(5))
df.drop(['info_name', 'info_foundlevel', 'info_creattime'], axis=1, inplace=True)
pd_save(df, outfile)
def rs_1_data_preprocess():
# 原属数据
data_infile = setting.PATH_CONFIG["user_daily"]
# 用户-物品-评分
user_infile = setting.PATH_CONFIG["user_item"]
user_outfile = setting.PATH_CONFIG["matrix_user_item2rating"]
# 物品-特征-评分
item_infile = setting.PATH_CONFIG["item_info"]
item_outfile = setting.PATH_CONFIG["matrix_item2feature"]
# 判断用户交易数据,如果不存在就要重新生成
if not os.path.exists(user_infile):
"""数据处理部分"""
# user 数据预处理
data_converting(data_infile, user_infile)
# 创建 user-item-评分 矩阵
create_user2item(user_infile, user_outfile)
else:
if not os.path.exists(user_outfile):
# 创建 user-item-评分 矩阵
create_user2item(user_infile, user_outfile)
if not os.path.exists(item_outfile):
# 创建 item-feature-是否存在 矩阵
create_item2feature(item_infile, item_outfile)
user_feature = pd_load(user_outfile)
item_feature = pd_load(item_outfile)
user_feature.set_index('user_id', inplace=True)
item_feature.set_index('item_id', inplace=True)
return user_feature, item_feature
def cos_measure(item_feature_vector, user_rated_items_matrix):
"""
计算item之间的余弦夹角相似度
:param item_feature_vector: 待测量的item特征向量
:param user_rated_items_matrix: 用户已评分的items的特征矩阵
:return: 待计算item与用户已评分的items的余弦夹角相识度的向量
"""
x_c = (item_feature_vector * user_rated_items_matrix.T) + 0.0000001
mod_x = np.sqrt(item_feature_vector * item_feature_vector.T)
mod_c = np.sqrt((user_rated_items_matrix * user_rated_items_matrix.T).diagonal())
cos_xc = x_c / (mod_x * mod_c)
return cos_xc
def comp_user_feature(user_rated_vector, item_feature_matrix):
"""
根据user的评分来计算得到user的喜好特征
:param user_rated_vector : user的评分向量
:param item_feature_matrix: item的特征矩阵
:return: user的喜好特征
"""
# user评分的均值
user_rating_mean = user_rated_vector.mean()
# # 分别得到user喜欢和不喜欢item的向量以及item对应的引索(以该user的评分均值来划分)
user_like_item = user_rated_vector.loc[user_rated_vector >= user_rating_mean]
user_unlike_item = user_rated_vector.loc[user_rated_vector < user_rating_mean]
print("user_like_item: \n", user_like_item)
print("user_unlike_item: \n", user_unlike_item)
# 获取买入和卖出的 index
user_like_item_index = map(int, user_like_item.index.values)
user_unlike_item_index = map(int, user_unlike_item.index.values)
# 获取买入和卖出的 value
user_like_item_rating = np.matrix(user_like_item.values)
user_unlike_item_rating = np.matrix(user_unlike_item.values)
#得到user喜欢和不喜欢item的特征矩阵
user_like_item_feature_matrix = np.matrix(item_feature_matrix.loc[user_like_item_index, :].values)
user_unlike_item_feature_matrix = np.matrix(item_feature_matrix.loc[user_unlike_item_index, :].values)
#计算user的喜好特征向量,以其对item的评分作为权重
weight_of_like = user_like_item_rating / user_like_item_rating.sum()
weight_of_unlike = user_unlike_item_rating / user_unlike_item_rating.sum()
print("weight_of_like: ", weight_of_like)
print("weight_of_unlike: ", weight_of_unlike)
#计算user的喜欢特征和不喜欢特征以及总特征
user_like_feature = weight_of_like * user_like_item_feature_matrix
user_unlike_feature = weight_of_unlike * user_unlike_item_feature_matrix
user_feature_tol = user_like_feature - user_unlike_feature
return user_feature_tol
def rs_2_cb_recommend(user_feature, item_feature_matrix, K=20):
"""
计算得到与user最相似的Top K个item推荐给user
:param user_feature: 待推荐用户的对item的评分向量
:param item_feature_matrix: 包含所有item的特征矩阵
:param K: 推荐给user的item数量
:return: 与user最相似的Top K个item的编号
"""
# 得到user已评分和未评分的item向量
user_rated_vector = user_feature.loc[user_feature > 0]
# print("操作 >>> \n", user_rated_vector)
# user_unrated_vector = user_feature.loc[user_feature == 0]
# print("未操作 >>> \n", user_unrated_vector)
# 买过的其实也可以推荐
user_unrated_vector = user_feature
# print(">>> \n", user_unrated_vector)
# user喜好总特征(就是用户的调性)
user_item_feature_tol = comp_user_feature(user_rated_vector, item_feature_matrix)
print(">>> 用户调性", user_item_feature_tol)
#未评分item的特征矩阵
user_unrated_item_index = map(int, user_unrated_vector.index.values)
user_unrated_item_feature_matrix = np.matrix(item_feature_matrix.loc[user_unrated_item_index, :].values)
#得到相似度并进行排序
similarity = list(np.array(cos_measure(user_item_feature_tol, user_unrated_item_feature_matrix))[0])
key = {'item_index': list(user_unrated_vector.index.values), 'similarity': similarity}
item_sim_df = pd.DataFrame(key)
item_sim_df.sort_values('similarity', ascending=False, inplace=True)
# print(item_sim_df.head(100))
return item_sim_df.iloc[:K, 0].values
def estimate_rate(user_rated_vector, similarity):
"""
估计用户对item的评分
:param user_rated_vector: 用户已有item评分向量
:param similarity: 待估计item和已评分item的相识度向量
:return:用户对item的评分的估计
"""
rate_hat = (user_rated_vector * similarity.T) / similarity.sum()
# print(">>> ", rate_hat)
return rate_hat[0, 0]
def rs_2_cb_recommend_estimate(user_feature, item_feature_matrix, item):
"""
基于内容的推荐算法对item的评分进行估计
:param item_feature_matrix: 包含所有item的特征矩阵
:param user_feature: 待估计用户的对item的评分向量
:param item: 待估计item的编号
:return: 基于内容的推荐算法对item的评分进行估计
"""
# #得到item的引索以及特征矩阵
# item_index = item_feature_matrix.index
# item_feature = item_feature_matrix.values
#得到所有user评分的item的引索
user_item_index = user_feature.index
#某一用户已有评分item的评分向量和引索以及item的评分矩阵
user_rated_vector = np.matrix(user_feature.loc[user_feature > 0].values)
user_rated_items = map(int, user_item_index[user_feature > 0].values)
user_rated_items_matrix = np.matrix(item_feature_matrix.loc[user_rated_items, :].values)
#待评分item的特征向量,函数中给出的是该item的Id
item_feature_vector = np.matrix(item_feature_matrix.loc[item].values)
#得到待计算item与用户已评分的items的余弦夹角相识度的向量
cos_xc = cos_measure(item_feature_vector, user_rated_items_matrix)
# print(">>> 相似度: %s" % cos_xc)
#计算uesr对该item的评分估计
rate_hat = estimate_rate(user_rated_vector, cos_xc)
return rate_hat
def main():
# 数据初始化
user_id = 20200930
K = 10
user_feature, item_feature = rs_1_data_preprocess()
# 基于内容推荐的模块(给某一个用户推荐 10个 他感兴趣的内容)
user_feature = user_feature.loc[user_id, :] # 一行 用户(具体某一个用户)-电影-评分 数据
print(">>> 1 \n", user_feature)
# 效果不好,有几个原因
# 1. 交易数据比较少
# 2. 基金的特征不够全面
# 3. 优化喜欢和不喜欢的阈值
result = rs_2_cb_recommend(user_feature, item_feature, K)
print(result)
# for code in result:
# # 给某一个用户推荐一个item, 预估推荐评分
# price = rs_2_cb_recommend_estimate(user_feature, item_feature, code)
# if price > 1000:
# print("--- %s 基金买入 %s" % (code, abs(price)) )
# elif price < -1000:
# print("--- %s 基金卖出 %s" % (code, abs(price)) )
# else:
# print("--- 不做任何操作")
if __name__ == "__main__":
main()
......@@ -259,4 +259,4 @@ def main():
if __name__ == "__main__":
main()
main()
\ No newline at end of file
{
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.3-final"
},
"orig_nbformat": 2,
"kernelspec": {
"name": "python_defaultSpec_1599819467604",
"display_name": "Python 3.6.3 64-bit ('python3.6': virtualenv)"
}
},
"nbformat": 4,
"nbformat_minor": 2,
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"from numpy import linalg as la\n",
"from numpy import *"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def loadExData3():\n",
" # 利用SVD提高推荐效果,菜肴矩阵\n",
" return[[2, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0],\n",
" [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5],\n",
" [0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0],\n",
" [3, 3, 4, 0, 3, 0, 0, 2, 2, 0, 0],\n",
" [5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0],\n",
" [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],\n",
" [4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5],\n",
" [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4],\n",
" [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],\n",
" [0, 0, 0, 3, 0, 0, 0, 0, 4, 5, 0],\n",
" [1, 1, 2, 1, 1, 2, 1, 0, 4, 5, 0]]\n",
"\n",
"myMat = mat(loadExData3())"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": "matrix([[2, 0, 0, 4, 4, 0, 0, 0, 0, 0, 0],\n [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5],\n [0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 0],\n [3, 3, 4, 0, 3, 0, 0, 2, 2, 0, 0],\n [5, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0],\n [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],\n [4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5],\n [0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 4],\n [0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0],\n [0, 0, 0, 3, 0, 0, 0, 0, 4, 5, 0],\n [1, 1, 2, 1, 1, 2, 1, 0, 4, 5, 0]])"
},
"metadata": {},
"execution_count": 3
}
],
"source": [
"myMat"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def recommend(dataMat, user, N=3, simMeas=cosSim, estMethod=standEst):\n",
" \"\"\"svdEst( )\n",
" Args:\n",
" dataMat 训练数据集\n",
" user 用户编号\n",
" simMeas 相似度计算方法\n",
" estMethod 使用的推荐算法\n",
" Returns:\n",
" 返回最终 N 个推荐结果\n",
" \"\"\"\n",
" # 寻找未评级的物品\n",
" # 对给定的用户建立一个未评分的物品列表\n",
" \n",
" unratedItems = nonzero(dataMat[user, :].A == 0)[1]\n",
" # 如果不存在未评分物品,那么就退出函数\n",
" if len(unratedItems) == 0:\n",
" return 'you rated everything'\n",
" # 物品的编号和评分值\n",
" itemScores = []\n",
" # 在未评分物品上进行循环\n",
" for item in unratedItems:\n",
" # 获取 item 该物品的评分\n",
" estimatedScore = estMethod(dataMat, user, simMeas, item)\n",
" itemScores.append((item, estimatedScore))\n",
" # 按照评分得分 进行逆排序,获取前N个未评级物品进行推荐\n",
" return sorted(itemScores, key=lambda jj: jj[1], reverse=True)[: N]\n",
"\n",
"\n",
"print(recommend(myMat, 1, estMethod=svdEst))"
]
}
]
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册