2
.gitignore
vendored
@@ -3,7 +3,7 @@ __pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
.vscode
|
||||
data/*
|
||||
data
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
* [在线阅读](https://ailearning.apachecn.org)
|
||||
* [在线阅读(Gitee)](https://apachecn.gitee.io/ailearning)
|
||||
* [ApacheCN 面试求职交流群 724187166](https://jq.qq.com/?_wv=1027&k=54ujcL3)
|
||||
* [ApacheCN 面试求职交流群 979932878](https://qm.qq.com/cgi-bin/qm/qr?k=2oFEp1KHbDCP0Te4Wt-I6FOK4hvg4iBk&jump_from=webapi&authKey=dw08LmD1w9km55TSmcW2J4gjeaiyn7KTff+8bnqiIeDweqrzQF2ccsE/hQswWQk7)
|
||||
* [ApacheCN 学习资源](http://www.apachecn.org/)
|
||||
|
||||
## 公告
|
||||
|
||||
102
docs/nlp_old/1.入门介绍.md
Normal file
@@ -0,0 +1,102 @@
|
||||
# 自然语言处理 - 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)**: 分析篇章级文本的内在结构,进而分析文本情感倾向,提取评论性观点,并生成反映文本关键信息的标签与摘要
|
||||
|
||||
例如:
|
||||
|
||||

|
||||
|
||||
### 案例7(机器翻译)
|
||||
|
||||
**机器翻译技术(Machine Translating)**: 基于互联网大数据,融合深度神经网络、统计、规则多种翻译方法,帮助用户跨越语言鸿沟,与世界自由沟通
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
* 参考百度科普课程: <http://bit.baidu.com/product>
|
||||
694
docs/nlp_old/2.分词.md
Normal file
@@ -0,0 +1,694 @@
|
||||
# 自然语言处理 - 2.分词
|
||||
|
||||
**分词(Word Segmentation)**: 将连续的自然语言文本,切分成具有语义合理性和完整性的词汇序列
|
||||
|
||||
例句: 致毕业和尚未毕业的同学。
|
||||
|
||||
1. `致` `毕业` `和` `尚未` `毕业` `的` `同学`
|
||||
2. `致` `毕业` `和尚` `未` `毕业` `的` `同学`
|
||||
|
||||
> 今天我们聊聊 jieba 结巴分词器(牛逼)
|
||||
|
||||
* 第一个不靠吹嘘学校or公司,完全靠实力开源的一个项目
|
||||
* 知乎上网友评论是腾讯,而最近GitHub上看到的是百度邮箱
|
||||
* “结巴”中文分词: 做最好的 Python 中文分词组件(这个的确没吹牛!)
|
||||
* GitHub上面 README.md 为中文版本(别看这个小事,很多中国公司开源项目都是英文)
|
||||
|
||||
## 部署使用
|
||||
|
||||
> 安装
|
||||
|
||||
`pip install jieba`
|
||||
|
||||
> 引用
|
||||
|
||||
`import jieba`
|
||||
|
||||
> 特点
|
||||
|
||||
* 四种分词模式
|
||||
* 精确模式: 试图将句子最精确地切开,适合文本分析;
|
||||
* 全模式: 把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义
|
||||
* 搜索引擎模式: 在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词
|
||||
* paddle模式: 利用PaddlePaddle深度学习框架,训练序列标注(双向GRU)网络模型实现分词,同时支持词性标注
|
||||
* paddle模式使用需安装paddlepaddle-tiny: `pip install paddlepaddle-tiny==1.6.1`
|
||||
* 目前paddle模式支持jieba v0.40及以上版本。
|
||||
* jieba v0.40以下版本,请升级 jieba: `pip install jieba --upgrade`
|
||||
* 支持繁体分词
|
||||
* 支持自定义词典
|
||||
* MIT 授权协议
|
||||
|
||||
## 四种分词模式
|
||||
|
||||
> 1.精确模式
|
||||
|
||||
精确模式: 试图将句子最精确地切开,适合文本分析
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
seg_list = jieba.cut("他来到了网易杭研大厦") # 默认是精确模式
|
||||
print(", ".join(seg_list))
|
||||
|
||||
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
|
||||
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
|
||||
|
||||
# 输出结果
|
||||
#【精确模式】: 我/ 来到/ 北京/ 清华大学
|
||||
```
|
||||
|
||||
> 2.全模式
|
||||
|
||||
全模式: 把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
seg_list = jieba.cut("我来到北京清华大学", cut_all=True)
|
||||
print("Full Mode: " + "/ ".join(seg_list)) # 全模式
|
||||
|
||||
|
||||
# 输出结果
|
||||
#【全模式】: 我/ 来到/ 北京/ 清华/ 清华大学/ 华大/ 大学
|
||||
```
|
||||
|
||||
> 3.搜索引擎模式
|
||||
|
||||
搜索引擎模式: 在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
seg_list = jieba.cut_for_search("小明硕士毕业于中国科学院计算所,后在日本京都大学深造") # 搜索引擎模式
|
||||
print(", ".join(seg_list))
|
||||
|
||||
# 输出结果
|
||||
#【搜索引擎模式】: 小明, 硕士, 毕业, 于, 中国, 科学, 学院, 科学院, 中国科学院, 计算, 计算所, 后, 在, 日本, 京都, 大学, 日本京都大学, 深造
|
||||
```
|
||||
|
||||
> 4.paddle 模式
|
||||
|
||||
paddle 模式: 利用PaddlePaddle深度学习框架,训练序列标注(双向GRU)网络模型实现分词,同时支持词性标注
|
||||
|
||||
* paddle模式使用需安装paddlepaddle-tiny: `pip install paddlepaddle-tiny==1.6.1`
|
||||
* 目前paddle模式支持jieba v0.40及以上版本。
|
||||
* jieba v0.40以下版本,请升级 jieba: `pip install jieba --upgrade`
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
jieba.enable_paddle() # 启动paddle模式。 0.40版之后开始支持,早期版本不支持
|
||||
strs=["我来到北京清华大学", "乒乓球拍卖完了", "中国科学技术大学"]
|
||||
for str in strs:
|
||||
seg_list = jieba.cut(str,use_paddle=True) # 使用paddle模式
|
||||
print("Paddle Mode: " + '/'.join(list(seg_list)))
|
||||
|
||||
# 输出结果
|
||||
#【Paddle 模式】 我/来到/北京/清华大学
|
||||
#【Paddle 模式】 乒乓球/拍卖/完/了
|
||||
#【Paddle 模式】 中国/科学技术/大学
|
||||
```
|
||||
|
||||
## 添加自定义词典
|
||||
|
||||
> 延迟加载机制
|
||||
|
||||
* jieba 采用延迟加载,`import jieba` 和 `jieba.Tokenizer()` 不会立即触发词典的加载,一旦有必要才开始加载词典构建前缀字典。
|
||||
* 如果你想手工初始 jieba,也可以手动初始化。
|
||||
|
||||
```python
|
||||
import jieba
|
||||
jieba.initialize() # 手动初始化(可选)
|
||||
```
|
||||
|
||||
在 0.28 之前的版本是不能指定主词典的路径的,有了延迟加载机制后,你可以改变主词典的路径:
|
||||
|
||||
```python
|
||||
jieba.set_dictionary('data/dict.txt.big')
|
||||
```
|
||||
|
||||
案例
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import sys
|
||||
sys.path.append("../")
|
||||
import jieba
|
||||
|
||||
def cuttest(test_sent):
|
||||
result = jieba.cut(test_sent)
|
||||
print(" ".join(result))
|
||||
|
||||
def testcase():
|
||||
cuttest("这是一个伸手不见五指的黑夜。我叫孙悟空,我爱北京,我爱Python和C++。")
|
||||
cuttest("我不喜欢日本和服。")
|
||||
cuttest("雷猴回归人间。")
|
||||
cuttest("工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作")
|
||||
cuttest("我需要廉租房")
|
||||
cuttest("永和服装饰品有限公司")
|
||||
cuttest("我爱北京天安门")
|
||||
cuttest("abc")
|
||||
cuttest("隐马尔可夫")
|
||||
cuttest("雷猴是个好网站")
|
||||
|
||||
if __name__ == "__main__":
|
||||
testcase()
|
||||
"""foobar.txt 格式
|
||||
的 3188252 uj
|
||||
了 883634 ul
|
||||
是 796991 v
|
||||
"""
|
||||
jieba.set_dictionary("foobar.txt")
|
||||
print("================================")
|
||||
testcase()
|
||||
```
|
||||
|
||||
> 切换其他词典
|
||||
|
||||
* 占用内存较小的词典文件: <https://github.com/fxsjy/jieba/raw/master/extra_dict/dict.txt.small>
|
||||
* 支持繁体分词更好的词典文件: <https://github.com/fxsjy/jieba/raw/master/extra_dict/dict.txt.big>
|
||||
* 下载你所需要的词典,然后覆盖 `jieba/dict.txt` 即可;或者用 `jieba.set_dictionary('data/dict.txt.big')`
|
||||
|
||||
> 载入自定义词典
|
||||
|
||||
* 开发者可以指定自己自定义的词典,以便包含 jieba 词库里没有的词
|
||||
* 虽然 jieba 有新词识别能力,但是自行添加新词可以保证更高的正确率
|
||||
* 用法: `jieba.load_userdict(file_name)` # file_name 为文件类对象或自定义词典的路径
|
||||
* 词典格式和 dict.txt 一样,一个词占一行
|
||||
* 每一行分三部分: 词语、词频(可省略)、词性(可省略),`用空格隔开`,`顺序不可颠倒`
|
||||
* file_name 若为路径或二进制方式打开的文件,则文件必须为 UTF-8 编码
|
||||
* 词频省略时使用自动计算的能保证分出该词的词频
|
||||
|
||||
```python
|
||||
""" filename 内容为:
|
||||
创新办 3 i
|
||||
云计算 5
|
||||
凱特琳 nz
|
||||
台中
|
||||
"""
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
|
||||
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
|
||||
|
||||
jieba.load_userdict(file_name)
|
||||
|
||||
seg_list = jieba.cut("我来到北京清华大学", cut_all=False)
|
||||
print("Default Mode: " + "/ ".join(seg_list)) # 精确模式
|
||||
|
||||
# 加载自定义词库前: 李小福 / 是 / 创新 / 办 / 主任 / 也 / 是 / 云 / 计算 / 方面 / 的 / 专家 /
|
||||
# 加载自定义词库后: 李小福 / 是 / 创新办 / 主任 / 也 / 是 / 云计算 / 方面 / 的 / 专家 /
|
||||
```
|
||||
|
||||
## 调整词典的词
|
||||
|
||||
* 使用 `add_word(word, freq=None, tag=None)` 和 `del_word(word)` 可在程序中动态修改词典。
|
||||
* 使用 `suggest_freq(segment, tune=True)` 可调节单个词语的词频,使其能(或不能)被分出来。
|
||||
|
||||
**注意: 自动计算的词频在使用 HMM 新词发现功能时可能无效**
|
||||
|
||||
代码示例:
|
||||
|
||||
```python
|
||||
print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))
|
||||
# 如果/放到/post/中将/出错/。
|
||||
|
||||
jieba.suggest_freq(('中', '将'), True)
|
||||
# 494
|
||||
print('/'.join(jieba.cut('如果放到post中将出错。', HMM=False)))
|
||||
# 如果/放到/post/中/将/出错/。
|
||||
|
||||
|
||||
print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))
|
||||
#「/台/中/」/正确/应该/不会/被/切开
|
||||
|
||||
jieba.suggest_freq('台中', True)
|
||||
# 69
|
||||
print('/'.join(jieba.cut('「台中」正确应该不会被切开', HMM=False)))
|
||||
#「/台中/」/正确/应该/不会/被/切开
|
||||
```
|
||||
|
||||
## 关键词提取
|
||||
|
||||
### 基于 TF-IDF 算法的关键词抽取
|
||||
|
||||
* 基于该框架的 TF-IDF 效果一般
|
||||
* 1.它使用的是他默认的 IDF 值的文件【不是针对我们的项目】
|
||||
* 2.我们先得有词,你才能计算 IDF的值。而框架是要先提供IDF值才能计算最终的 TF-IDF 值。
|
||||
* 如果你有计算IDF的值存成文件,再加载进来,计算TF-IDF值,才能得到适合这个类型数据的值!
|
||||
|
||||
> TF `优化点: 分子/分母 都加1`
|
||||
|
||||
TF: term frequency 短期频率, 用于衡量一个词在一个文件中的出现频率。因为每个文档的长度的差别可以很大,因而一个词在某个文档中出现的次数可能远远大于另一个文档,所以词频通常就是一个词出现的次数除以文档的总长度,相当于是做了一次归一化。
|
||||
|
||||
公式: `TF(t) = (词t在某个文档中出现的总次数) / (某个文档的词总数)`
|
||||
|
||||
> IDF `优化点: 分子/分母 都加1`
|
||||
|
||||
IDF: inverse document frequency 逆向文件频率,用于衡量一个词的重要性/区分度。计算词频TF的时候,所有的词语都被当做一样重要的,但是某些词,比如”is”, “of”, “that”很可能出现很多很多次,但是可能根本并不重要,因此我们需要减轻在多个文档中都频繁出现的词的权重。
|
||||
|
||||
公式: `IDF = log_e(总文档数/词t出现的文档数)`
|
||||
|
||||
> TF-IDF(term frequency–inverse document frequency)
|
||||
|
||||
公式: `TF-IDF = TF*IDF`
|
||||
|
||||
> 注意
|
||||
|
||||
`非常短的文本很可能影响 tf-idf 值`
|
||||
|
||||
> 行业用途
|
||||
|
||||
```
|
||||
TF-IDF(term frequency–inverse document frequency)是一种用于资讯检索与文本挖掘的常用加权技术。
|
||||
TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。
|
||||
TF-IDF加权的各种形式常被搜索引擎应用,作为文件与用户查询之间相关程度的度量或评级。
|
||||
除了TF-IDF以外,互联网上的搜索引擎还会使用基于连结分析的评级方法,以确定文件在搜寻结果中出现的顺序。
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
import jieba.analyse
|
||||
|
||||
# allowPOS('ns', 'n', 'vn', 'v') 地名、名词、动名词、动词
|
||||
tags = jieba.analyse.extract_tags(sentence, topK=20, withWeight=False, allowPOS=())
|
||||
"""
|
||||
* sentence 为待提取的文本
|
||||
* topK 为返回几个 TF/IDF 权重最大的关键词,默认值为 20
|
||||
* withWeight 为是否一并返回关键词权重值,默认值为 False
|
||||
* allowPOS 仅包括指定词性的词,默认值为空,即不筛选
|
||||
* jieba.analyse.TFIDF(idf_path=None) 新建 TFIDF 实例,idf_path 为 IDF 频率文件
|
||||
# idf是jieba通过语料库统计得到的
|
||||
# idf的值时通过语料库统计得到的,所以,实际使用时,可能需要依据使用环境,替换为使用对应的语料库统计得到的idf值。
|
||||
"""
|
||||
|
||||
# 关键词提取所使用逆向文件频率(IDF)文本语料库可以切换成自定义语料库的路径
|
||||
jieba.analyse.set_idf_path(file_name) # file_name为自定义语料库的路径
|
||||
|
||||
# 关键词提取所使用停止词(Stop Words)文本语料库可以切换成自定义语料库的路径
|
||||
jieba.analyse.set_stop_words(file_name) # file_name为自定义语料库的路径
|
||||
|
||||
|
||||
# 测试案例
|
||||
# 下载地址: https://github.com/fxsjy/jieba/blob/master/extra_dict/stop_words.txt
|
||||
"""
|
||||
the
|
||||
of
|
||||
is
|
||||
"""
|
||||
jieba.analyse.set_stop_words("~/work/data/nlp/jieba/extra_dict/stop_words.txt")
|
||||
# 下载地址: https://raw.githubusercontent.com/fxsjy/jieba/master/extra_dict/idf.txt.big
|
||||
"""格式如下:
|
||||
劳动防护 13.900677652
|
||||
勞動防護 13.900677652
|
||||
奥萨贝尔 13.900677652
|
||||
"""
|
||||
jieba.analyse.set_idf_path("~/work/data/nlp/jieba/extra_dict/idf.txt.big")
|
||||
content = "此外,公司拟对全资子公司吉林欧亚置业有限公司增资4.3亿元,增资后,吉林欧亚置业注册资本由7000万元增加到5亿元。吉林欧亚置业主要经营范围为房地产开发及百货零售等业务。目前在建吉林欧亚城市商业综合体项目。2013年,实现营业收入0万元,实现净利润-139.13万元。"
|
||||
# content = open("~/work/data/nlp/jieba/extra_dict/test_content.txt", 'rb').read()
|
||||
for word, weight in jieba.analyse.extract_tags(content, withWeight=True):
|
||||
print('%s %s' % (word, weight))
|
||||
|
||||
"""输出结果:
|
||||
吉林 1.0174270215234043
|
||||
欧亚 0.7300142700289363
|
||||
增资 0.5087135107617021
|
||||
实现 0.5087135107617021
|
||||
置业 0.4887134522112766
|
||||
万元 0.3392722481859574
|
||||
此外 0.25435675538085106
|
||||
全资 0.25435675538085106
|
||||
有限公司 0.25435675538085106
|
||||
4.3 0.25435675538085106
|
||||
注册资本 0.25435675538085106
|
||||
7000 0.25435675538085106
|
||||
增加 0.25435675538085106
|
||||
主要 0.25435675538085106
|
||||
房地产 0.25435675538085106
|
||||
业务 0.25435675538085106
|
||||
目前 0.25435675538085106
|
||||
城市 0.25435675538085106
|
||||
综合体 0.25435675538085106
|
||||
2013 0.25435675538085106
|
||||
"""
|
||||
```
|
||||
|
||||
### 基于 TextRank 算法的关键词抽取
|
||||
|
||||
> 基本思想:
|
||||
|
||||
1. 将待抽取关键词的文本进行分词
|
||||
2. 以固定窗口大小(默认为5,通过span属性调整),词之间的共现关系,构建图
|
||||
3. 计算图中节点的PageRank,注意是无向带权图
|
||||
|
||||
> 举例说明
|
||||
|
||||
```py
|
||||
例如: sentence = "A B C A D B C B A"
|
||||
|
||||
第一次 index = 0
|
||||
dict[(A, B)] = 2
|
||||
dict[(A, C)] = 1
|
||||
dict[(A, A)] = 1
|
||||
dict[(A, D)] = 2
|
||||
|
||||
第一次 index = 1
|
||||
dict[(B, A)] = 1
|
||||
dict[(B, B)] = 1
|
||||
dict[(B, C)] = 2
|
||||
dict[(B, D)] = 1
|
||||
|
||||
由于是 无向带权图
|
||||
|
||||
graph[start].append((start, end, weight))
|
||||
graph[end].append((end, start, weight))
|
||||
|
||||
假设:
|
||||
A B => 20
|
||||
所有 B => 50
|
||||
A, C => 5
|
||||
所有 C => 15
|
||||
总共: 10个单词
|
||||
A 权重PR值: 1/10 = 0.1
|
||||
s_A = 20/50 * 0.1 + 5/15 * 0.1
|
||||
d阻尼系数,即按照超链接进行浏览的概率,一般取经验值为0.85
|
||||
1−d浏览者随机跳转到一个新网页的概率
|
||||
A 权重PR值: (1 - d) + d * s_A
|
||||
```
|
||||
|
||||
> 代码案例
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
# 直接使用,接口相同,注意默认过滤词性。
|
||||
# allowPOS('ns', 'n', 'vn', 'v') 地名、名词、动名词、动词
|
||||
jieba.analyse.textrank(sentence, topK=20, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))
|
||||
# 新建自定义 TextRank 实例
|
||||
jieba.analyse.TextRank()
|
||||
|
||||
|
||||
# 测试案例
|
||||
content = "此外,公司拟对全资子公司吉林欧亚置业有限公司增资4.3亿元,增资后,吉林欧亚置业注册资本由7000万元增加到5亿元。吉林欧亚置业主要经营范围为房地产开发及百货零售等业务。目前在建吉林欧亚城市商业综合体项目。2013年,实现营业收入0万元,实现净利润-139.13万元。"
|
||||
# content = open("~/work/data/nlp/jieba/extra_dict/test_content.txt", 'rb').read()
|
||||
for x, w in jieba.analyse.textrank(content, withWeight=True):
|
||||
print('%s %s' % (x, w))
|
||||
"""
|
||||
吉林 1.0
|
||||
欧亚 0.9966893354178172
|
||||
置业 0.6434360313092776
|
||||
实现 0.5898606692859626
|
||||
收入 0.43677859947991454
|
||||
增资 0.4099900531283276
|
||||
子公司 0.35678295947672795
|
||||
城市 0.34971383667403655
|
||||
商业 0.34817220716026936
|
||||
业务 0.3092230992619838
|
||||
在建 0.3077929164033088
|
||||
营业 0.3035777049319588
|
||||
全资 0.303540981053475
|
||||
综合体 0.29580869172394825
|
||||
注册资本 0.29000519464085045
|
||||
有限公司 0.2807830798576574
|
||||
零售 0.27883620861218145
|
||||
百货 0.2781657628445476
|
||||
开发 0.2693488779295851
|
||||
经营范围 0.2642762173558316
|
||||
"""
|
||||
```
|
||||
|
||||
|
||||
## 词性标注
|
||||
|
||||
* `jieba.posseg.POSTokenizer(tokenizer=None)` 新建自定义分词器, tokenizer 参数可指定内部使用的 `jieba.Tokenizer` 分词器, `jieba.posseg.dt` 为默认词性标注分词器
|
||||
* 标注句子分词后每个词的词性,采用和 ictclas 兼容的标记法
|
||||
* 除了jieba默认分词模式,提供paddle模式下的词性标注功能。paddle模式采用延迟加载方式,通过 `enable_paddle()` 安装 `paddlepaddle-tiny`,并且import相关代码
|
||||
|
||||
paddle模式词性标注对应表如下:
|
||||
|
||||
paddle模式词性和专名类别标签集合如下表,其中词性标签 24 个(小写字母),专名类别标签 4 个(大写字母)
|
||||
|
||||
| 标签 | 含义 | 标签 | 含义 | 标签 | 含义 | 标签 | 含义 |
|
||||
| ---- | -------- | ---- | -------- | ---- | -------- | ---- | -------- |
|
||||
| n | 普通名词 | f | 方位名词 | s | 处所名词 | t | 时间 |
|
||||
| nr | 人名 | ns | 地名 | nt | 机构名 | nw | 作品名 |
|
||||
| nz | 其他专名 | v | 普通动词 | vd | 动副词 | vn | 名动词 |
|
||||
| a | 形容词 | ad | 副形词 | an | 名形词 | d | 副词 |
|
||||
| m | 数量词 | q | 量词 | r | 代词 | p | 介词 |
|
||||
| c | 连词 | u | 助词 | xc | 其他虚词 | w | 标点符号 |
|
||||
| PER | 人名 | LOC | 地名 | ORG | 机构名 | TIME | 时间 |
|
||||
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
import jieba.posseg as pseg
|
||||
|
||||
|
||||
words = jieba.posseg.cut("我爱北京天安门")
|
||||
for word, flag in words:
|
||||
print('%s %s' % (word, flag))
|
||||
|
||||
"""
|
||||
我 r
|
||||
爱 v
|
||||
北京 ns
|
||||
天安门 ns
|
||||
"""
|
||||
|
||||
words = pseg.cut("我爱北京天安门") #jieba默认模式
|
||||
jieba.enable_paddle() #启动paddle模式。 0.40版之后开始支持,早期版本不支持
|
||||
words = pseg.cut("我爱北京天安门",use_paddle=True) #paddle模式
|
||||
for word, flag in words:
|
||||
print('%s %s' % (word, flag))
|
||||
|
||||
"""
|
||||
我 r
|
||||
爱 v
|
||||
北京 ns
|
||||
天安门 ns
|
||||
"""
|
||||
```
|
||||
|
||||
## 并行分词
|
||||
|
||||
原理: 将目标文本按行分隔后,把各行文本分配到多个 Python 进程并行分词,然后归并结果,从而获得分词速度的可观提升
|
||||
|
||||
基于 python 自带的 multiprocessing 模块,目前暂不支持 Windows
|
||||
|
||||
用法:
|
||||
|
||||
* `jieba.enable_parallel(4)` # 开启并行分词模式,参数为并行进程数
|
||||
* `jieba.disable_parallel()` # 关闭并行分词模式
|
||||
|
||||
```python
|
||||
import sys
|
||||
import time
|
||||
import jieba
|
||||
|
||||
jieba.enable_parallel()
|
||||
|
||||
url = sys.argv[1]
|
||||
content = open(url, "rb").read()
|
||||
t1 = time.time()
|
||||
words = "/ ".join(jieba.cut(content))
|
||||
|
||||
t2 = time.time()
|
||||
tm_cost = t2-t1
|
||||
|
||||
log_f = open("1.log","wb")
|
||||
log_f.write(words.encode('utf-8'))
|
||||
|
||||
print('speed %s bytes/second' % (len(content)/tm_cost))
|
||||
```
|
||||
|
||||
实验结果: 在 4 核 3.4GHz Linux 机器上,对金庸全集进行精确分词,获得了 1MB/s 的速度,是单进程版的 3.3 倍。
|
||||
|
||||
注意: 并行分词仅支持默认分词器 `jieba.dt` 和 `jieba.posseg.dt`
|
||||
|
||||
## Tokenize: 返回词语在原文的起止位置
|
||||
|
||||
注意,输入参数只接受 unicode
|
||||
|
||||
> 默认模式
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
|
||||
result = jieba.tokenize(u'永和服装饰品有限公司')
|
||||
for tk in result:
|
||||
print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))
|
||||
|
||||
"""
|
||||
word 永和 start: 0 end:2
|
||||
word 服装 start: 2 end:4
|
||||
word 饰品 start: 4 end:6
|
||||
word 有限公司 start: 6 end:10
|
||||
"""
|
||||
```
|
||||
|
||||
|
||||
```python
|
||||
# encoding=utf-8
|
||||
import jieba
|
||||
|
||||
|
||||
result = jieba.tokenize(u'永和服装饰品有限公司', mode='search')
|
||||
for tk in result:
|
||||
print("word %s\t\t start: %d \t\t end:%d" % (tk[0],tk[1],tk[2]))
|
||||
|
||||
"""
|
||||
word 永和 start: 0 end:2
|
||||
word 服装 start: 2 end:4
|
||||
word 饰品 start: 4 end:6
|
||||
word 有限 start: 6 end:8
|
||||
word 公司 start: 8 end:10
|
||||
word 有限公司 start: 6 end:10
|
||||
"""
|
||||
```
|
||||
|
||||
## ChineseAnalyzer for Whoosh 搜索引擎
|
||||
|
||||
引用: `from jieba.analyse import ChineseAnalyzer`
|
||||
|
||||
* `pip install whoosh`
|
||||
* Whoosh是一个用来索引文本并能根据索引搜索的的包含类和方法的类库。它允许你开发一个针对自己内容的搜索引擎。
|
||||
* 例如,如果你想创建一个博客软件,你可以使用Whoosh添加一个允许用户搜索博客类目的搜索功能。
|
||||
|
||||
```python
|
||||
# -*- coding: UTF-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
import sys,os
|
||||
sys.path.append("../")
|
||||
from whoosh.index import create_in,open_dir
|
||||
from whoosh.fields import *
|
||||
from whoosh.qparser import QueryParser
|
||||
|
||||
from jieba.analyse.analyzer import ChineseAnalyzer
|
||||
|
||||
analyzer = ChineseAnalyzer()
|
||||
|
||||
schema = Schema(title=TEXT(stored=True), path=ID(stored=True), content=TEXT(stored=True, analyzer=analyzer))
|
||||
if not os.path.exists("tmp"):
|
||||
os.mkdir("tmp")
|
||||
|
||||
ix = create_in("tmp", schema) # for create new index
|
||||
#ix = open_dir("tmp") # for read only
|
||||
writer = ix.writer()
|
||||
|
||||
writer.add_document(
|
||||
title="document1",
|
||||
path="/a",
|
||||
content="This is the first document we’ve added!"
|
||||
)
|
||||
|
||||
writer.add_document(
|
||||
title="document2",
|
||||
path="/b",
|
||||
content="The second one 你 中文测试中文 is even more interesting! 吃水果"
|
||||
)
|
||||
|
||||
writer.add_document(
|
||||
title="document3",
|
||||
path="/c",
|
||||
content="买水果然后来世博园。"
|
||||
)
|
||||
|
||||
writer.add_document(
|
||||
title="document4",
|
||||
path="/c",
|
||||
content="工信处女干事每月经过下属科室都要亲口交代24口交换机等技术性器件的安装工作"
|
||||
)
|
||||
|
||||
writer.add_document(
|
||||
title="document4",
|
||||
path="/c",
|
||||
content="咱俩交换一下吧。"
|
||||
)
|
||||
|
||||
writer.commit()
|
||||
searcher = ix.searcher()
|
||||
parser = QueryParser("content", schema=ix.schema)
|
||||
|
||||
for keyword in ("水果世博园","你","first","中文","交换机","交换"):
|
||||
print("result of ", keyword)
|
||||
q = parser.parse(keyword)
|
||||
results = searcher.search(q)
|
||||
for hit in results:
|
||||
print(hit.highlights("content"))
|
||||
print("="*10)
|
||||
|
||||
for t in analyzer("我的好朋友是李明;我爱北京天安门;IBM和Microsoft; I have a dream. this is intetesting and interested me a lot"):
|
||||
print(t.text)
|
||||
|
||||
|
||||
"""
|
||||
result of 水果世博园
|
||||
买<b class="match term0">水果</b>然后来<b class="match term1">世博园</b>
|
||||
==========
|
||||
result of 你
|
||||
second one <b class="match term0">你</b> 中文测试中文 is even more interesting
|
||||
==========
|
||||
result of first
|
||||
<b class="match term0">first</b> document we’ve added
|
||||
==========
|
||||
result of 中文
|
||||
second one 你 <b class="match term0">中文</b>测试<b class="match term0">中文</b> is even more interesting
|
||||
==========
|
||||
result of 交换机
|
||||
干事每月经过下属科室都要亲口交代24口<b class="match term0">交换机</b>等技术性器件的安装工作
|
||||
==========
|
||||
result of 交换
|
||||
咱俩<b class="match term0">交换</b>一下吧
|
||||
干事每月经过下属科室都要亲口交代24口<b class="match term0">交换</b>机等技术性器件的安装工作
|
||||
==========
|
||||
我
|
||||
好
|
||||
朋友
|
||||
是
|
||||
李明
|
||||
我
|
||||
爱
|
||||
北京
|
||||
天安
|
||||
天安门
|
||||
ibm
|
||||
microsoft
|
||||
dream
|
||||
intetest
|
||||
interest
|
||||
me
|
||||
lot
|
||||
"""
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
测试过:
|
||||
|
||||
* jieba: [https://github.com/fxsjy/jieba](https://github.com/fxsjy/jieba)
|
||||
* Hanlp: [https://github.com/hankcs/HanLP](https://github.com/hankcs/HanLP)
|
||||
* nltk: [https://yiyibooks.cn/yiyi/nltk_python/index.html](https://yiyibooks.cn/yiyi/nltk_python/index.html)
|
||||
* nltk 已经兼容 stanford corenlp 分词模版
|
||||
* CoreNLP: [https://github.com/Lynten/stanford-corenlp](https://github.com/Lynten/stanford-corenlp)
|
||||
* pyltp: [http://www.ltp-cloud.com/document](http://www.ltp-cloud.com/document)
|
||||
* pkuseg: [https://github.com/lancopku/pkuseg-pytho](https://github.com/lancopku/pkuseg-python)
|
||||
|
||||
呆测试:
|
||||
|
||||
* NLPIR: [http://ictclas.nlpir.org](http://ictclas.nlpir.org)
|
||||
* 新浪云: [http://www.sinacloud.com/doc/sae/python/segment.html](http://www.sinacloud.com/doc/sae/python/segment.html)
|
||||
* 盘古分词: [http://pangusegment.codeplex.com/](http://pangusegment.codeplex.com/)
|
||||
* 搜狗分词: [http://www.sogou.com/labs/webservice/](http://www.sogou.com/labs/webservice/)
|
||||
* 庖丁解牛: [https://code.google.com/p/paoding/](https://code.google.com/p/paoding/)
|
||||
* BosonNLP: [http://bosonnlp.com/dev/center](http://bosonnlp.com/dev/center)
|
||||
* IKAnalyzer: [http://www.oschina.net/p/ikanalyzer](http://www.oschina.net/p/ikanalyzer)
|
||||
* SCWS中文分词: [http://www.xunsearch.com/scws/docs.php](http://www.xunsearch.com/scws/docs.php)
|
||||
30
docs/nlp_old/3.1.篇章分析-内容概述.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# 篇章分析-内容概述
|
||||
|
||||
## 篇章分析变迁
|
||||
|
||||
1. 内容生态: 新浪 -> 百家号、今日头条(自媒体)
|
||||
2. 用户成为信息的生产中心: web 1.0 -> 百度贴吧、新浪微博、团购网站(用户评论,富有个人情感和用户观点的信息)
|
||||
3. 移动、无屏: 显示屏 -> 手机、Siri(展示的终端)
|
||||
|
||||
## 篇章分析场景
|
||||
|
||||
篇章分析重要性: 让人们最平等`便捷`地`获取信息`,`找到所求`。
|
||||
|
||||
1. 个性化信息获取(搜索引擎的理解和推荐): 从搜索的角度来看,通过对内容的深入理解,我们能够精准地对内容进行分析,然后将内容推荐给需要的用户,达到不搜即得。
|
||||
2. 便捷咨询阅读(头条的热门推荐): 从资讯阅读的角度来看,我们通过对内容进行概括总结、形成摘要,就能搞让用户更快捷地浏览信息、获取知识。
|
||||
3. 信息直接满足: 更进一步说,对用户的问题,我们可以基于内容理解,直接给出答案,从而满足用户的需求。
|
||||
|
||||
`总之`: 通过篇章分析,我们能够进行内容理解,从而更好地服务用户。
|
||||
|
||||
## 篇章分析概述
|
||||
|
||||
`篇章是形式上互相衔接、语义上前后连贯的句子序列。`
|
||||
|
||||
有以下3种:
|
||||
* 1.文章: 新闻稿、博客、微博
|
||||
* 2.评论: O2O服务的用户评论、豆瓣的影评、微博上的动态
|
||||
* 3.对话: 话题上是相互衔接的、语义上也是连贯的一个对话序列
|
||||
|
||||
## 篇章分析任务
|
||||
|
||||

|
||||
82
docs/nlp_old/3.2.篇章分析-内容标签.md
Normal file
@@ -0,0 +1,82 @@
|
||||
# 篇章分析-内容标签
|
||||
|
||||
`标签`: 这种种的`单词`和`词组`都是一种标签的形式
|
||||
1. 新闻稿,打出关于该报道的各种各样的标签,来表示其关键信息
|
||||
2. 论文中,我们也会表明一些文章的`领域分类`以及`关键词`等标签
|
||||
3. 微博用#代表一个话题,这是典型的社会化标签
|
||||
|
||||
## 标签用途
|
||||
|
||||
1. 关键信息展示
|
||||
* 用户可以大致了解文章的主要信息,从而决定要不要对信息进行进一步深入地浏览
|
||||
|
||||
2. 频道划分
|
||||
* 在很多的媒体网站,经常会有频道划分,使用了就是文章的分类标签
|
||||
|
||||
3. 话题聚合
|
||||
* 标签也可以用来做话题聚合(例如: #人民的名义# 集合所有关于这个话题的信息,让用户更深入的了解信息)
|
||||
|
||||
## 应用: 个性化推荐
|
||||
|
||||
* 标签可以用来建立用户的画像
|
||||
|
||||
比如对对于用户搜索过的Query,还有他浏览过的文章,都可以通过标签的技术。提取出主要的兴趣点,从而也就建立了用户的画像
|
||||
|
||||
* 标签可以对内容进行建模
|
||||
|
||||
通过标签技术,我们能够提取文章中的关键信息标签。这样来看标签就作为了用户和内容的一个共同表示。
|
||||
|
||||
* 推荐的时候,我们通过对用户画像的标签和内容模型的标签进行匹配,就能够对用户进行一个精准的个性化推荐
|
||||
|
||||
## 百度内容标签
|
||||
|
||||

|
||||
|
||||
## 标签体系: 面向推荐的标签图谱
|
||||
|
||||
* 标签图谱刻画了用户的兴趣点,以及兴趣点之间的关联关系。
|
||||
* 节点表示了用户的兴趣点,而边表示了兴趣点之间的关联关系(边是带有权重的,表示关联强度)。
|
||||
* 包括3种节点: 主题标签-绿色,话题标签-紫色,实体标签-蓝色。
|
||||
* 有了关联关系,我们可以进行一定程度的探索和泛化。(例如: 无人驾驶和人工智能关联很强,如果有人看了无人驾驶,我们就给他推荐人工智能)
|
||||
|
||||

|
||||
|
||||
## 标签体系: 基于大数据分析的图谱构建
|
||||
|
||||
* 用户信息来源: 贴吧、微博
|
||||
* 标签的相关性分析: 通过关联规则,发现2个标签总同时出现,我们觉得这是高相关的。
|
||||
|
||||

|
||||
|
||||
## 标签计算
|
||||
|
||||
> 主题分类
|
||||
|
||||
* 主题标签的计算,是一种很典型的文本分类问题: 传统的朴素贝叶斯、最大熵、SVM 等解决方案。
|
||||
* 当前我们主要采用的是: 基于神经网络的方法(可以看右侧的示意图)
|
||||
* 整个网络分成3层次:
|
||||
* 第一层 原始特征层: 抽取简单的原始特征,例如说文章出现的单词、词组 等等
|
||||
* 第二层 表示层: 通过一些 embedding的算法、CNN、LSTM的方法
|
||||
* 第三层 排序层: 计算文章与主题之间的相似度,具体会计算每个主题与文章的相似度,并将相似度作为最终的一个主题分类的结果。这种计算的好处能够天然的支持多标记,也就是一篇文章可以同时计算出多个主题标签。
|
||||
|
||||

|
||||
|
||||
> 通用标签
|
||||
|
||||
* 通用标签主要是计算内容中的实体和话题,我们综合了两种策略。
|
||||
* 第一种策略: 针对比较热门的高频标签
|
||||
* 这种标签我们主要通过一些预测的方法得到,预测的方法: 基于相似度计算得到的---这种方法并不要求标签一定在文章中出现
|
||||
* 例如: 美国大选这种标签,如果一篇文章出现了 `希拉里` `特朗普` `辩论` 等一些词,即使没有出现美国大选,我们通过语义相似度的方法也能把这个标签计算出来。
|
||||
* 第二种策略: 面向中低频的标签
|
||||
* 这种标签相关的信息,不是那么丰富,所以我们计算的时候更多依赖的是标签在文章中的信息
|
||||
* 比如: 这个标签在文章中出现的频率 或 出现的位置;如果出现在标题,那么它可能就会比较重要。
|
||||
* 通过融合这2种策略,形成我们通用标签的结果。
|
||||
|
||||

|
||||
|
||||
## 内容标签在Feed流中的应用
|
||||
|
||||
1. 标签可以用来话题聚合: 比如表示人工智能的标签全部都会集合到同一个话题下面。这样用户可以对人工智能这个话题进行非常充分的浏览。
|
||||
2. 话题频道划分: 比如我们在手机百度上面就可以看到,Feed流上面有多个栏目,用户可以点击 `体育` `时尚`等频道
|
||||
|
||||

|
||||
45
docs/nlp_old/3.3.篇章分析-情感分析.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# 篇章分析-情感分类
|
||||
|
||||
## 用户评论剧增
|
||||
|
||||
`服务评论` `商品评论` `社交评论`
|
||||
|
||||
## 情感分析应用
|
||||
|
||||
`消费决策` `舆情分析`
|
||||
|
||||
> 情感分类 和 观点挖掘
|
||||
|
||||
* 对(文本的)观点、情感、情绪和评论进行分析计算
|
||||
|
||||

|
||||
|
||||
> 情感分类
|
||||
|
||||
* 给定一个文本判断其情感的极性,包括积极、中性、消极。
|
||||
* LSTM 对文本进行语义表示,进而基于语义表示进行情感分类。
|
||||
|
||||

|
||||
|
||||
> 观点挖掘
|
||||
|
||||
* 观点聚类: 主要目标是对大量的评论数据进行聚类,将相同的观点抽取出来,并形成一个情感搭配词典(算法是: 搭配抽取、词法分析、聚类归一,从而获得一个情感搭配。我们就可以进行观点抽取)
|
||||
* 观点抽取: 就是对输入的文本进行计算,将其中的情感标签抽取出来,这里的标签,都是来自于情感搭配词典的,也就是观点聚类获得的词典。
|
||||
* 观点抽取一种简单的做法是直接通过标签匹配的方式得到,比如: 服务不错这个情感搭配,恰好在文本中出现,我们就可以把它抽取出来。
|
||||
* 但是这种简单的抽取方法,其实上只能从字面上抽取情感搭配,而无法解决字面不一致的,但是意思一样的情感搭配抽取,因此我们还引入了语义相似度的方法。这种方法主要是通过神经网络进行计算的。它能解决这种字面不一致,语义一样的抽取问题。
|
||||
|
||||

|
||||
|
||||
> 观点摘要
|
||||
|
||||
综合了情感分类和观点挖掘的一些技术,而获得的一个整体的应用技术
|
||||
|
||||

|
||||
|
||||
## 百度应用: 评论观点
|
||||
|
||||

|
||||
|
||||
## 百度应用: 推荐理由
|
||||
|
||||

|
||||
62
docs/nlp_old/3.4.篇章分析-自动摘要.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# 篇章分析-自动摘要
|
||||
|
||||
## 信息爆炸与移动化
|
||||
|
||||

|
||||
|
||||
## 自动摘要应用
|
||||
|
||||
* 便捷信息浏览
|
||||
* 我们可以为每个新闻抽取摘要,用户可以通过摘要快速了解新闻概况。
|
||||
* 进而决定是否要进一步细致地浏览。
|
||||
* 而更进一步说: 摘要还可以直接进行信息满足。
|
||||
* 信息满足
|
||||
* 传统搜索得到一大批网页信息
|
||||
* 现在通过问答技术我们能够将网页中最核心的片段摘要提取出来。
|
||||
* 用户通过阅读片段,就可以直接得到满足,而不需要打开页面。
|
||||
|
||||
## 自动摘要
|
||||
|
||||
* 对海量内容进行提炼与总结
|
||||
* 以简洁、直观的摘要来概括用户所关注的主要内容
|
||||
* 方便用户快速了解与浏览海量内容
|
||||
|
||||

|
||||
|
||||
* 自动摘要分类
|
||||
|
||||

|
||||
|
||||
* 典型摘要计算流程
|
||||
|
||||

|
||||
|
||||
> 基于篇章信息的通用新闻摘要
|
||||
|
||||

|
||||
|
||||
> 篇章主题摘要
|
||||
|
||||

|
||||
|
||||
> 问答摘要
|
||||
|
||||

|
||||
|
||||
## 百度应用
|
||||
|
||||
> 文本和语言摘要
|
||||
|
||||

|
||||
|
||||
> 问答摘要
|
||||
|
||||

|
||||
|
||||
> 搜索播报摘要和图像摘要
|
||||
|
||||

|
||||
|
||||
## 总结
|
||||
|
||||

|
||||
13
docs/nlp_old/3.命名实体识别.md
Normal file
@@ -0,0 +1,13 @@
|
||||
|
||||
|
||||
|
||||
使用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)$$
|
||||
109
docs/nlp_old/README.md
Normal file
@@ -0,0 +1,109 @@
|
||||
# 【入门须知】必须了解
|
||||
|
||||
实体: 抽取
|
||||
关系: 图谱
|
||||
意图: 分类
|
||||
|
||||
* **【入门须知】必须了解**: <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
|
||||
48
docs/nlp_old/Word2Vec.md
Normal file
@@ -0,0 +1,48 @@
|
||||
# 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
|
||||
BIN
docs/nlp_old/img/1.自然语言处理入门介绍/机器翻译.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
docs/nlp_old/img/1.自然语言处理入门介绍/篇章分析.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/nlp_old/img/3.1.篇章分析-内容标签/篇章分析任务.jpg
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
docs/nlp_old/img/3.2.篇章分析-内容标签/主题分类.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/nlp_old/img/3.2.篇章分析-内容标签/内容标签在Feed流中的应用.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
docs/nlp_old/img/3.2.篇章分析-内容标签/基于大数据分析的图谱构建.jpg
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
docs/nlp_old/img/3.2.篇章分析-内容标签/百度内容标签.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/nlp_old/img/3.2.篇章分析-内容标签/通用标签.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/nlp_old/img/3.2.篇章分析-内容标签/面向推荐的标签图谱.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/nlp_old/img/3.3.篇章分析-情感分类/情感分类.jpg
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
docs/nlp_old/img/3.3.篇章分析-情感分类/情感分类和观点挖掘.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
docs/nlp_old/img/3.3.篇章分析-情感分类/百度应用推荐理由.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/nlp_old/img/3.3.篇章分析-情感分类/百度应用评论观点.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/nlp_old/img/3.3.篇章分析-情感分类/观点挖掘.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
docs/nlp_old/img/3.3.篇章分析-情感分类/观点摘要.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/信息爆炸与移动化.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/典型摘要计算流程.jpg
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/基于篇章信息的通用新闻摘要.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/总结.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/摘要系统.jpg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/百度应用搜索播报摘要和图像摘要.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/百度应用文本和语言摘要.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/百度应用问答摘要.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/篇章主题摘要.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/自动摘要分类.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
docs/nlp_old/img/3.4.篇章分析-自动摘要/问答摘要.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
docs/nlp_old/img/F94581F64C21A1094A473397DFA42F9C.jpg
Normal file
|
After Width: | Height: | Size: 45 KiB |
BIN
docs/nlp_old/img/Word2Vce/CBoW.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
docs/nlp_old/img/Word2Vce/Skip-gram.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
10
index.html
@@ -17,6 +17,16 @@
|
||||
<!-- google webmaster -->
|
||||
<meta name="google-site-verification" content="pyo9N70ZWyh8JB43bIu633mhxesJ1IcwWCZlM3jUfFo" />
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-8DP4GX97XY"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments);}
|
||||
gtag('js', new Date());
|
||||
|
||||
gtag('config', 'G-8DP4GX97XY');
|
||||
</script>
|
||||
|
||||
<link rel="stylesheet" href="asset/dark-mode.css">
|
||||
<script src="asset/dark-mode.js"></script>
|
||||
<link rel="stylesheet" href="asset/share.css">
|
||||
|
||||
20
run_example.py
Normal file
@@ -0,0 +1,20 @@
|
||||
# import tutorials.keras.text_NER as ft
|
||||
# import tutorials.keras.brat_tag as ft
|
||||
import tutorials.RecommenderSystems.rs_rating_demo as ft
|
||||
# from middleware.utils import TimeStat, Chart
|
||||
# import matplotlib.pyplot as plt
|
||||
# import matplotlib.gridspec as gridspec
|
||||
# from matplotlib.font_manager import FontProperties
|
||||
# plt.rcParams['font.sans-serif'] = ['SimHei']
|
||||
# plt.rcParams['axes.unicode_minus'] = False
|
||||
|
||||
|
||||
def main():
|
||||
ft.main()
|
||||
# x=y=[1,2,3]
|
||||
# plt.plot(x, y, color='g', linestyle='-') # 绘制
|
||||
# plt.grid(True, ls = '--')
|
||||
# plt.show()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -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)
|
||||
|
||||
BIN
src/py3.x/tensorflow2.x/Emotion/neg.xlsx
Normal file
BIN
src/py3.x/tensorflow2.x/Emotion/pos.xlsx
Normal file
@@ -348,4 +348,4 @@ predicts = model.predict([indices, segments, masks])[0].argmax(axis=-1).tolist()
|
||||
print('Fill with: ', list(map(lambda x: token_dict_rev[x], predicts[0][1:3])))
|
||||
# Fill with: ['数', '学']
|
||||
|
||||
# %%
|
||||
# %%
|
||||
213
tutorials/AI常用函数说明.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# AI常用函数说明
|
||||
|
||||
## numpy 相关
|
||||
|
||||
> from numpy import random, mat, eye
|
||||
|
||||
```py
|
||||
'''
|
||||
# NumPy 矩阵和数组的区别
|
||||
NumPy存在2中不同的数据类型:
|
||||
1. 矩阵 matrix
|
||||
2. 数组 array
|
||||
相似点:
|
||||
都可以处理行列表示的数字元素
|
||||
不同点:
|
||||
1. 2个数据类型上执行相同的数据运算可能得到不同的结果。
|
||||
2. NumPy函数库中的 matrix 与 MATLAB中 matrices 等价。
|
||||
'''
|
||||
from numpy import random, mat, eye
|
||||
|
||||
# 生成一个 4*4 的随机数组
|
||||
randArray = random.rand(4, 4)
|
||||
# 转化关系, 数组转化为矩阵
|
||||
randMat = mat(randArray)
|
||||
'''
|
||||
.I 表示对矩阵求逆(可以利用矩阵的初等变换)
|
||||
意义: 逆矩阵是一个判断相似性的工具。逆矩阵A与列向量p相乘后,将得到列向量q,q的第i个分量表示p与A的第i个列向量的相似度。
|
||||
参考案例链接:
|
||||
https://www.zhihu.com/question/33258489
|
||||
http://blog.csdn.net/vernice/article/details/48506027
|
||||
.T 表示对矩阵转置(行列颠倒)
|
||||
* 等同于: .transpose()
|
||||
.A 返回矩阵基于的数组
|
||||
参考案例链接:
|
||||
http://blog.csdn.net/qq403977698/article/details/47254539
|
||||
'''
|
||||
invRandMat = randMat.I
|
||||
TraRandMat = randMat.T
|
||||
ArrRandMat = randMat.A
|
||||
# 输出结果
|
||||
print('randArray=(%s) \n' % type(randArray), randArray)
|
||||
print('randMat=(%s) \n' % type(randMat), randMat)
|
||||
print('invRandMat=(%s) \n' % type(invRandMat), invRandMat)
|
||||
print('TraRandMat=(%s) \n' % type(TraRandMat), TraRandMat)
|
||||
print('ArrRandMat=(%s) \n' % type(ArrRandMat), ArrRandMat)
|
||||
# 矩阵和逆矩阵 进行求积 (单位矩阵,对角线都为1嘛,理论上4*4的矩阵其他的都为0)
|
||||
myEye = randMat*invRandMat
|
||||
# 误差
|
||||
print(myEye - eye(4))
|
||||
```
|
||||
|
||||
> np.dot
|
||||
|
||||
```py
|
||||
import numpy as np
|
||||
|
||||
a = np.array([2, 3])
|
||||
b = np.array([4, 5])
|
||||
np.dot(a, b, out=None) #该函数的作用是获取两个元素a,b的乘积
|
||||
|
||||
Out[1]: 23 = 2*4 + 3*5
|
||||
|
||||
a = np.array([2, 3, 4])
|
||||
b = np.array([5, 6, 7])
|
||||
np.dot(a, b, out=None) #该函数的作用是获取两个元素a,b的乘积
|
||||
|
||||
Out[2]: 56 = 2*5 + 3*6 + 4*7
|
||||
```
|
||||
|
||||
> array sum/mean
|
||||
|
||||
```py
|
||||
import numpy as np
|
||||
|
||||
# ---- sum ---- #
|
||||
a = np.array([[2, 3, 4], [2, 3, 4]])
|
||||
|
||||
# 纵向求和: 0 表示某一列所有的行求和
|
||||
a.sum(axis=0)
|
||||
Out[6]: array([4, 6, 8])
|
||||
|
||||
# 横向求和: 1 表示某一行所有的列求和
|
||||
a.sum(axis=1)
|
||||
Out[7]: array([9, 9])
|
||||
|
||||
|
||||
# ---- mean ---- #
|
||||
a = np.array([[2, 3, 4], [12, 13, 14]])
|
||||
|
||||
# 纵向求平均: 0 表示某一列所有的行求和
|
||||
a.mean(axis=0)
|
||||
Out[13]: array([7., 8., 9.])
|
||||
|
||||
# 横向求平均: 1 表示某一行所有的列求平均
|
||||
a.mean(axis=1)
|
||||
Out[14]: array([ 3., 13.])
|
||||
|
||||
```
|
||||
|
||||
> np.newaxis
|
||||
|
||||
* numpy 添加新的维度: newaxis(可以给原数组增加一个维度)
|
||||
|
||||
```py
|
||||
import numpy as np
|
||||
|
||||
In [59]: x = np.random.randint(1, 8, size=(2, 3, 4))
|
||||
In [60]: y = x[:, np.newaxis, :, :]
|
||||
In [61]: Z = x[ :, :, np.newaxis, :]
|
||||
|
||||
In [62]: x. shape
|
||||
Out[62]: (2, 3, 4)
|
||||
|
||||
In [63]: y. shape
|
||||
Out[63]: (2, 1, 3, 4)
|
||||
|
||||
In [64]: z. shape
|
||||
Out [64]: (2, 3, 1, 4)
|
||||
```
|
||||
|
||||
## pandas 相关
|
||||
|
||||
> df.shift()
|
||||
|
||||
```
|
||||
DataFrame.shift(periods=1, freq=None, axis=0)
|
||||
|
||||
* periods: 类型为int,表示移动的幅度,可以是正数,也可以是负数,默认值是1,
|
||||
1就表示移动一次,注意这里移动的都是数据,而索引是不移动的,移动之后没有对应值的,就赋值为NaN
|
||||
* freq: DateOffset, timedelta, or time rule string,可选参数,默认值为None,只适用于时间序列,如果这个参数存在,那么会按照参数值移动时间索引,而数据值没有发生变化。
|
||||
* axis: {0, 1, ‘index’, ‘columns’},表示移动的方向,如果是0或者’index’表示上下移动,如果是1或者’columns’,则会左右移动。
|
||||
```
|
||||
|
||||
```py
|
||||
|
||||
"""
|
||||
index value1
|
||||
A 0
|
||||
B 1
|
||||
C 2
|
||||
D 3
|
||||
"""
|
||||
|
||||
df.shift() # 或 df.shift(1)
|
||||
# 就会变成如下:
|
||||
|
||||
"""
|
||||
index value1
|
||||
A NaN
|
||||
B 0
|
||||
C 1
|
||||
D 2
|
||||
"""
|
||||
|
||||
df.shift(2)
|
||||
|
||||
"""
|
||||
|
||||
index value1
|
||||
A NaN
|
||||
B NaN
|
||||
C 0
|
||||
D 1
|
||||
"""
|
||||
|
||||
df.shift(-1)
|
||||
|
||||
"""
|
||||
index value1
|
||||
A 1
|
||||
B 2
|
||||
C 3
|
||||
D NaN
|
||||
"""
|
||||
|
||||
####################
|
||||
|
||||
"""
|
||||
index value1
|
||||
2016-06-01 0
|
||||
2016-06-02 1
|
||||
2016-06-03 2
|
||||
2016-06-04 3
|
||||
"""
|
||||
|
||||
# 如果 index 为时间
|
||||
df1.shift(periods=1,freq=datetime.timedelta(1))
|
||||
|
||||
"""
|
||||
index value1
|
||||
2016-06-02 0
|
||||
2016-06-03 1
|
||||
2016-06-04 2
|
||||
2016-06-05 3
|
||||
"""
|
||||
```
|
||||
|
||||
|
||||
|
||||
## keras 相关
|
||||
|
||||
> from keras.preprocessing.sequence import pad_sequences
|
||||
|
||||
```python
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
|
||||
|
||||
# padding: pre(默认) 向前补充0 post 向后补充0
|
||||
# truncating: 文本超过 pad_num, pre(默认) 删除前面 post 删除后面
|
||||
x = [[1,2,3,4,5]]
|
||||
x_train = pad_sequences(x, maxlen=pad_num, value=0, padding='post', truncating="post")
|
||||
print("--- ", x_train[0][:20])
|
||||
```
|
||||
318
tutorials/RecommenderSystems/rs_content_demo.py
Normal file
@@ -0,0 +1,318 @@
|
||||
#!/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()
|
||||
113
tutorials/test.ipynb
Normal file
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"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))"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||