• Posts tagged "分词"

Blog Archives

用R语言实现余弦相似度Cosine Similarity

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-cosine-similarity/

前言

在文字处理时,我们经常需要判断两段文字是否相似,如果这两段文字的用词越相似,它们的内容就应该越相似。这个场景下,我们就可以考虑先把文字转换成词频向量,然后用余弦相似度来判断是否相似。

目录

  1. 余弦相似度介绍
  2. R语言实现余弦相似度
  3. 计算2个文本的相似度

1. 余弦相似度介绍

余弦相似度,通过测量两个向量的夹角的余弦值来度量它们之间的相似性。例如,将两篇文章向量化,余弦距离可以避免因为文章的长度不同而导致距离偏大,余弦距离只考虑两篇文章生成的向量的夹角。

余弦相似度被大量用于对比:如人脸对比、声音对比,来快速判断两个图片或者两段声音的相似度,进而判断是不是来自同一个人。当一个图像或者声音样本具有n维的特征,我们就可以把他认为是n维向量,两个样本使用余弦相似度比对时,就是对两个n维向量的夹角余弦值,其大小进行衡量。

余弦相似度的取值范围是[-1,1],相同两个向量的之间的相似度为1。余弦距离的取值范围是[0,2]。

  • 当夹角为0,两个向量同向,相当于相似度最高,余弦值为1,表示完全正相关。
  • 当夹角90°,两个向量垂直,余弦为0,表示不相关。
  • 当夹角180°,两个向量反向,余弦为-1,表示完全负相关。

计算公式:

相比其他的距离度量,余弦相似度更加注重两个向量在方向上的差异,而非距离或长度上。

欧式距离与余弦距离的对比:

  1. 欧式距离的数值受到维度的影响,余弦相似度在高维的情况下也依然保持低维完全相同时相似度为1等性质。
  2. 欧式距离体现的是距离上的绝对差异,余弦距离体现的是方向上的相对差异。

不同情况不同选择:

  1. 两个人分别取了蓝球(1,0)与红球(0,1),这两个向量的欧式距离较小,可是事实是这两个球是不同的,而余弦距离为2表示的是完全不同的意思。所以在这种情况下选择余弦距离更具合理性。
  2. 两个人对APP的使用次数与使用时长分别表示为(1,10),(10,100),可知余弦相似度较小,说明这两个人的行为时相同的,可是,事实是不同的,两个人的活跃度有着极大的差异,第二个人的活跃度更高。

2. R语言实现余弦相似度

我们可以安装lsa包,使用cosine()函数,计算2个向量的余弦相似度。

lsa(Latent Semantic Analysis 潜在语义分析)包基本思想是,文本确实具有高阶(=潜在语义)结构,但这种结构会被词语用法(如通过使用同义词或多义词)所掩盖。通过对给定的文档-术语矩阵进行截断奇异值分解(双模式因子分析),以统计方式得出概念指数,从而克服了这一可变性问题。

lsa包的安装过程比较简单。


> install.packages(lsa)
> library(lsa>

计算2个向量的余弦相似度。


> vec1 = c( 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 )
> vec2 = c( 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0 )
> cosine(vec1,vec2) 
          [,1]
[1,] 0.2357023

3. 计算2个文本的相似度

有了计算余弦相似度的工具后,那么接下来,我们就可以尝试计算文本的相似度了。

使用余弦相似度,计算文本相似的具体步骤:

  1. 定义两个文本内容
  2. 对两个文本内容进行分词
  3. 列出所有的词,并计算词频
  4. 整理词频为词向量
  5. 用余弦相似度计算词向量

第一步,我们定义两段文本内容,分别是

  • 句子1:”我买了一个手机,又配了一个手机壳”
  • 句子2:”我有3年没有换新手机了,还是原来的手机壳”

> txt1<-"我买了一个手机,又配了一个手机壳"
> txt2<-"我有3年没有换新手机了,还是原来的手机壳"

第二步,对上面2个句子进行分词,这里我们使用jiebaR包进行分词,关于jiebaR包的具体用法,请参考文章R语言中文分词包jiebaR


# 加载jiabaR包
> library(jiebaR)

# 定义分词引擎
> wk<-worker()

# 分别对两个文本进行分词
> w1<-wk[txt1]
> w2<-wk[txt2]

第三步,进出所有的词,并查看词频


> w1
 [1] "我"   "买"   "了"   "一个" "手机" "又"   "配"   "了"   "一个" "手机" "壳"  
> w2
 [1] "我"     "有"     "3"      "年"     "没有"   "换"     "新手机" "了"     "还是"   "原来"   "的"    
[12] "手机"   "壳" 

# 查看词频
> table(w1)
w1
  壳   了   买   配 手机   我 一个   又 
   1    2    1    1    2    1    2    1 

> table(w2)
w2
     3     的   还是     换     壳     了   没有     年   手机     我 新手机     有   原来 
     1      1      1      1      1      1      1      1      1      1      1      1      1 

第四步,整理词频为词向量,这里我把生成词向量过程,封装成一个函数叫dfm(),形成单词矩阵。


# 加载工具包
> library(plyr)
> library(magrittr)

# 封装词向量函数
> dfm<-function(w1,w2){
+     t1<-table(w1) %>% ldply
+     t2<-table(w2) %>% ldply
+     names(t1)<-c("seg","cnt1")
+     names(t2)<-c("seg","cnt2")
+     mm<-merge(t1,t2,by="seg",all=TRUE)
+     mm$cnt1[which(is.na(mm$cnt1))]<-0
+     mm$cnt2[which(is.na(mm$cnt2))]<-0
+     list(dat=t(mm[,-1]),seg=mm$seg)
+ }

# 查看词向量的输出结果
> m<-dfm(w1,w2);m
$dat
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12] [,13] [,14] [,15] [,16] [,17]
cnt1    0    0    0    0    1    2    1    0    0     1     2     1     0     2     0     1     0
cnt2    1    1    1    1    1    1    0    1    1     0     1     1     1     0     1     0     1

$seg
 [1] "3"      "的"     "还是"   "换"     "壳"     "了"     "买"     "没有"   "年"     "配"     "手机"  
[12] "我"     "新手机" "一个"   "有"     "又"     "原来"  

第五步,用余弦相似度计算词向量的相似度,即两段文本的余弦相似度。结果是0.4,表示不是太相似。


> library(lsa)
> cosine(m$dat[1,],m$dat[2,]) 
          [,1]
[1,] 0.4036037

那我们换一组句子再试试,比如

  • 句子1:如果这两句话的用词越相似,它们的内容就应该越相似。
  • 句子2:如果这两句话的内容越相似,它们的用词也应该越相似。

用R语言计算上面2个句子的余弦相似度,得0.95,表示非常相似了。


> txt1<-"如果这两句话的用词越相似,它们的内容就应该越相似"
> txt2<-"如果这两句话的内容越相似,它们的用词也应该越相似"
> w1<-wk[txt1]
> w2<-wk[txt2]
> m<-dfm(w1,w2);m
$dat
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
cnt1    2    1    1    1    1    1    2    0    1     1     2     1
cnt2    2    0    1    1    1    1    2    1    1     1     2     1

$seg
 [1] "的"     "就"     "两句话" "内容"   "如果"   "它们"   "相似"   "也"     "应该"   "用词"   "越"    
[12] "这"    

> cosine(m$dat[1,],m$dat[2,]) 
     [,1]
[1,] 0.95

本文我们了解余弦相似度的原理和实现,并且应用了余弦相似度计算,从而可以判断两个文本之间的相似程度,让我们进行文本匹配时又多了一种方法。本文代码:https://github.com/bsspirit/r-string-match/blob/main/cosine.r

转载请注明出处:
http://blog.fens.me/r-cosine-similarity/

打赏作者

用R语言进行量化文本分析quanteda

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-word-quanteda/

前言

在互联网的今天,我们每天都会生产和消费大量的文本信息,如报告、文档、新闻、聊天、图书、小说、语音转化的文字等。海量的文本信息,不仅提供扩宽的研究对象和研究领域,也为商业使用带来了巨大的机会。

量化文本分析(Quantitative Analysis of Textual Data),一种新的方式,用结构化数据的方式来管理文本。quanteda包,提出以语料库的形式管理文本,语料库被定义为文本的集合,其中包括特定每个文本的文档级变量,和整个集合的元数据。用户可以轻松地按单词、段落、句子甚至用户提供的分隔符分割文本和标签,按文档级变量将它们分组为更大的文档,形成基于逻辑条件的变量组合。

本文内容为分享内容,详情请参考文章2021 微软Ignite Post Watching Part:用R语言进行量化文本分析,分享内容的PPT请自取。

目录

  1. quanteda包介绍
  2. quanteda包的核心函数
  3. quanteda包的使用

1. quanteda包介绍

Quanteda是一个用于管理和分析文本数据的R包,对于文本管理功能强大,而且还很快。Quanteda包的官方地址 https://quanteda.io/。 Quanteda包由 Quanteda Initiative公司开发,总部位于伦敦,是一家英国非营利组织,致力于推广开源文本分析软件。主要产品R包 quanteda, readtext, spacyr, stopwords等,公司网站 https://quanteda.org/

Quanteda从底层开始重新设计了文本处理过程,在语法与性能上得到了巨大提升。

  • 内部使用stringi作为字符处理工具
  • 内部基于data.table与Matrix包
  • 统一的语法结构

quanteda 文本重新定义了文本处理的过程,自己负责底层文本数据结构,结合应用层不同的功能包进行扩展。quanteda 包的使用,有一套自己的生态。

配合使用的其他包:readtext, stopwords,uanteda.textstats,quanteda.textmodels,quanteda.textplots,ggplot2,magrittr,stringr,plyr,dplyr,reshape2,seededlda 。

官方建议安装以下软件包,以便更好地支持和扩展quanteda的功能:

  • readtext: 可将几乎任何格式的文本文件读入R
  • spacyr: 使用spaCy库的NLP,包括词性标注,命名实体和依存语法
  • quanteda.corpora : 用于quanteda的附加文本数据。

将quanteda包与用于定量文本分析的替代 R 包对比:tm、tidytext、corpus和koRpus

2. quanteda包的核心函数

quanteda软件包由几个核心数据类型,通过调用具有相同名称的构造器创建的。

核心对象类型及其构造函数:

  • corpus():建立语料库对象
  • tokens(): 构造一个分词对象
  • dfm() : 创建文档特征矩阵
  • fcm() : 创建特征共现矩阵
  • kwic() : 关键字查询
  • dictionary() : 创建字典

这些函数就是quanteda包的核心函数,也是我们用于文本分析的工具。使用好这些函数,可以快速实现对大量文本的分析。

官方API文档的解释:https://quanteda.io/reference/index.html

3. quanteda包的使用

首先进行quanteda包的安装,像其他包一样,安装过程很简单,然后加载quanteda包。


> install.packages("quanteda")
> library(quanteda)

具体操作步骤:

  1. 创建文本文件
  2. 使用readtext()的函数加载文本文件
  3. 从字符向量构建语料库
  4. 对语料库进行分词:按词、字、句子进行分隔
  5. 特征清洗和停用词
  6. 文字搜索
  7. 文本特征矩阵化
  8. 建立关键词字典,进行文档管理

第一步,新建一个文件,1.txt,填入文本信息。


国内知名211院校理工科硕士,具有一年半科技企业算法工程师经验,熟练掌握python,r,sql语言,熟悉神经网络,支持向量机,XGBoost等机器学习算法。工作积极主动,良好的沟通协调和自主学习能力,专业应用类别多,知识面广。

项目1:
(1) 数据导出,清洗和分析。数据库导出用户基础信息、行为数据等,并清洗脏数据,计算日活留存,疗效等指标。
(2) 特征提取和导出。根据数据分析结果提出一系列假设,寻找与疗效相关因素,并分析其相关性。使用 PCA 进行特征降维,Xgboost 特征选择等;
(3) 多种推荐算法和机器学习算法实现。根据用户特征使用协同过滤、机器学习、强化学习等为用户推荐更优的 App模块及组合,提升用户使用体验。

项目2:
(1) 设计数据模式和创建数据库:选择测量用户体验所需的特征指标,相应地创建6个特征指标
关系数据表(Table)。绘制其实体关系图(Entity-Relationship Diagrams),使用MySQL  Workbench创建数据框架(Data Schema)。根据数据框架(Data Schema)生成合成数据(Synthetic Data),并通过PostgreSQL创建关系数据库(Relational Database)。
(2) 提取和清理数据:编写了Python代码进行数据预处理,并使用Tableau对数据进行可视化,这是建模前的必要工作。
(3) 建模:为了找到影响用户满意度的重要特征,团队应用了三种不同的机器学习模型(线性回
归、随机森林、神经网络)进行数据分析。线性回归提供了足够的解释性和快速的训练时间。在此基础上,随机森林和神经网络提高了精度和准确性。

第二步,使用readtext()的函数加载文本文件。


# 加载readtext包
> library(readtext)

# 读取文件
> dat<-readtext("./resume/1.txt", encoding = "UTF-8")

# 查看文件内容
> dat
readtext object consisting of 1 document and 0 docvars.
$text
[1] "\033[38;5;246m# A data frame: 1 × 2\033[39m"                                                                  
[2] "  doc_id text                      "                                                                          
[3] "  \033[3m\033[38;5;246m\033[39m\033[23m  \033[3m\033[38;5;246m\033[39m\033[23m                     "
[4] "\033[38;5;250m1\033[39m 1.txt  \033[38;5;246m\"\033[39m\\\"国内知名211院校理\\\"...\033[38;5;246m\"\033[39m"  

$summary
$summary[[1]]
NULL

attr(,"class")
[1] "trunc_mat"

第三步,我们从字符向量构建语料库,建立语料库对象corp。共一个文本文件,15个句子,372个词,188个


# 把通过文本对象,建立语料库对象
> corp <- corpus(dat)

# 查看语料库的统计概览
> summary(corp)
Corpus consisting of 1 document, showing 1 document:

  Text Types Tokens Sentences
 1.txt   188    372        15

给语料库对象corp,增加属性信息。


> docvars(corp, "职位")<- "算法工程师"
> docvars(corp, "技能")<- "R语言"

# 查看语料库的统计概览,以多了2个属性字段
> summary(corp)
Corpus consisting of 1 document, showing 1 document:

  Text Types Tokens Sentences       职位  技能
 1.txt   188    372        15 算法工程师 R语言

查看corp对象基本属性


# 文档数量
> ndoc(corp)
[1] 1

# 文件名
> docnames(corp)
[1] "1.txt"

# 原始文本信息
> as.character(corp)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              1.txt 
"国内知名211院校理工科硕士,具有一年半科技企业算法工程师经验,熟练掌握python,r,sql语言,熟悉神经网络,支持向量机,XGBoost等机器学习算法。工作积极主动,良好的沟通协调和自主学习能力,专业应用类别多,知识面广。\n\n项目1:\n(1) 数据导出,清洗和分析。数据库导出用户基础信息、行为数据等,并清洗脏数据,计算日活留存,疗效等指标。\n(2) 特征提取和导出。根据数据分析结果提出一系列假设,寻找与疗效相关因素,并分析其相关性。使用 PCA 进行特征降维,Xgboost 特征选择等;\n(3) 多种推荐算法和机器学习算法实现。根据用户特征使用协同过滤、机器学习、强化学习等为用户推荐更优的 App模块及组合,提升用户使用体验。\n\n项目2:\n(1) 设计数据模式和创建数据库:选择测量用户体验所需的特征指标,相应地创建6个特征指标\n关系数据表(Table)。绘制其实体关系图(Entity-Relationship Diagrams),使用MySQL  Workbench创建数据框架(Data Schema)。根据数据框架(Data Schema)生成合成数据(Synthetic Data),并通过PostgreSQL创建关系数据库(Relational Database)。\n(2) 提取和清理数据:编写了Python代码进行数据预处理,并使用Tableau对数据进行可视化,这是建模前的必要工作。\n(3) 建模:为了找到影响用户满意度的重要特征,团队应用了三种不同的机器学习模型(线性回\n归、随机森林、神经网络)进行数据分析。线性回归提供了足够的解释性和快速的训练时间。在此基础上,随机森林和神经网络提高了精度和准确性。"

第四步,对语料库进行分词。tokens()函数,提供了三种方式,按词、字、句子进行分隔。

按词进行分隔


> token<-tokens(corp)

# 查看分词的结果,前20个
> head(as.character(token[1]),20)
 [1] "国内"   "知名"   "211"    "院校"   "理工科" "硕士"   ","     "具有"   "一年半" "科技"   "企业"   "算法"  
[13] "工程"   "师"     "经验"   ","     "熟练"   "掌握"   "python" "," 

按句子进行分隔


> sentence <- tokens(corp, what = "sentence")

> sentence
Tokens consisting of 1 document and 2 docvars.
1.txt :
 [1] "国内知名211院校理工科硕士,具有一年半科技企业算法工程师经验,熟练掌握python,r,sql语言,熟悉神经网络,支持向量机,XGBoost等机器学习算法。"
 [2] "工作积极主动,良好的沟通协调和自主学习能力,专业应用类别多,知识面广。"                                                                    
 [3] "项目1: (1) 数据导出,清洗和分析。"                                                                                                        
 [4] "数据库导出用户基础信息、行为数据等,并清洗脏数据,计算日活留存,疗效等指标。"                                                              
 [5] "(2) 特征提取和导出。"                                                                                                                      
 [6] "根据数据分析结果提出一系列假设,寻找与疗效相关因素,并分析其相关性。"                                                                      
 [7] "使用 PCA 进行特征降维,Xgboost 特征选择等; (3) 多种推荐算法和机器学习算法实现。"                                                          
 [8] "根据用户特征使用协同过滤、机器学习、强化学习等为用户推荐更优的 App模块及组合,提升用户使用体验。"                                          
 [9] "项目2: (1) 设计数据模式和创建数据库:选择测量用户体验所需的特征指标,相应地创建6个特征指标 关系数据表(Table)。"                         
[10] "绘制其实体关系图(Entity-Relationship Diagrams),使用MySQL  Workbench创建数据框架(Data Schema)。"                                       
[11] "根据数据框架(Data Schema)生成合成数据(Synthetic Data),并通过PostgreSQL创建关系数据库(Relational Database)。"                        
[12] "(2) 提取和清理数据:编写了Python代码进行数据预处理,并使用Tableau对数据进行可视化,这是建模前的必要工作。"                                 
[ ... and 3 more ]

按字进行分隔


> chars <- tokens(corp, what = "character")
> head(as.character(chars),50)
 [1] "国" "内" "知" "名" "2"  "1"  "1"  "院" "校" "理" "工" "科" "硕" "士" "," "具" "有" "一" "年" "半" "科" "技" "企"
[24] "业" "算" "法" "工" "程" "师" "经" "验" "," "熟" "练" "掌" "握" "p"  "y"  "t"  "h"  "o"  "n"  "," "r"  "," "s" 
[47] "q"  "l"  "语" "言"

第五步,特征清洗。清洗过程中,我们可以使用默认停用词库进行过滤,也可以自定义停用词库。

进行初步特征清洗。


# 计算默认分词的词的长度
> token_len<-length(as.character(token));token_len
[1] 372

# 去空格去符号后,词的长度
> t1<-tokens(token, remove_punct = TRUE, remove_numbers = TRUE)
> t1_len<-length(as.character(t1));t1_len
[1] 285

进行停用词的特征清洗,quanteda包中,提供了3个默认的停用词表。

默认的英文停用词表。


> stopwords("english")
  [1] "i"          "me"         "my"         "myself"     "we"         "our"        "ours"       "ourselves" 
  [9] "you"        "your"       "yours"      "yourself"   "yourselves" "he"         "him"        "his"       
 [17] "himself"    "she"        "her"        "hers"       "herself"    "it"         "its"        "itself"    
 [25] "they"       "them"       "their"      "theirs"     "themselves" "what"       "which"      "who"       
 [33] "whom"       "this"       "that"       "these"      "those"      "am"         "is"         "are"       
 [41] "was"        "were"       "be"         "been"       "being"      "have"       "has"        "had"       
 [49] "having"     "do"         "does"       "did"        "doing"      "would"      "should"     "could"     
 [57] "ought"      "i'm"        "you're"     "he's"       "she's"      "it's"       "we're"      "they're"   
 [65] "i've"       "you've"     "we've"      "they've"    "i'd"        "you'd"      "he'd"       "she'd"     
 [73] "we'd"       "they'd"     "i'll"       "you'll"     "he'll"      "she'll"     "we'll"      "they'll"   
 [81] "isn't"      "aren't"     "wasn't"     "weren't"    "hasn't"     "haven't"    "hadn't"     "doesn't"   
 [89] "don't"      "didn't"     "won't"      "wouldn't"   "shan't"     "shouldn't"  "can't"      "cannot"    
 [97] "couldn't"   "mustn't"    "let's"      "that's"     "who's"      "what's"     "here's"     "there's"   
[105] "when's"     "where's"    "why's"      "how's"      "a"          "an"         "the"        "and"       
[113] "but"        "if"         "or"         "because"    "as"         "until"      "while"      "of"        
[121] "at"         "by"         "for"        "with"       "about"      "against"    "between"    "into"      
[129] "through"    "during"     "before"     "after"      "above"      "below"      "to"         "from"      
[137] "up"         "down"       "in"         "out"        "on"         "off"        "over"       "under"     
[145] "again"      "further"    "then"       "once"       "here"       "there"      "when"       "where"     
[153] "why"        "how"        "all"        "any"        "both"       "each"       "few"        "more"      
[161] "most"       "other"      "some"       "such"       "no"         "nor"        "not"        "only"      
[169] "own"        "same"       "so"         "than"       "too"        "very"       "will" 

优化的英文停用词表


 stopwords(language = "en", source = "smart")
  [1] "a"             "a's"           "able"          "about"         "above"         "according"     "accordingly"  
  [8] "across"        "actually"      "after"         "afterwards"    "again"         "against"       "ain't"        
 [15] "all"           "allow"         "allows"        "almost"        "alone"         "along"         "already"      
 [22] "also"          "although"      "always"        "am"            "among"         "amongst"       "an"           
 [29] "and"           "another"       "any"           "anybody"       "anyhow"        "anyone"        "anything"     
 [36] "anyway"        "anyways"       "anywhere"      "apart"         "appear"        "appreciate"    "appropriate"  
 [43] "are"           "aren't"        "around"        "as"            "aside"         "ask"           "asking"       
 [50] "associated"    "at"            "available"     "away"          "awfully"       "b"             "be"           
 [57] "became"        "because"       "become"        "becomes"       "becoming"      "been"          "before"       
 [64] "beforehand"    "behind"        "being"         "believe"       "below"         "beside"        "besides"      
 [71] "best"          "better"        "between"       "beyond"        "both"          "brief"         "but"          
 [78] "by"            "c"             "c'mon"         "c's"           "came"          "can"           "can't"    

//....省略

中文停用词表


> stopwords(language = "zh",source="misc")
  [1] "按"       "按照"     "俺"       "们"       "阿"       "别"       "别人"     "别处"     "是"       "别的"    
 [11] "别管"     "说"       "不"       "不仅"     "不但"     "不光"     "不单"     "不只"     "不外乎"   "不如"    
 [21] "不妨"     "不尽"     "然"       "不得"     "不怕"     "不惟"     "不成"     "不拘"     "料"       "不是"    
 [31] "不比"     "不然"     "特"       "不独"     "不管"     "不至于"   "若"       "不论"     "不过"     "不问"    
 [41] "比"       "方"       "比如"     "及"       "本身"     "本着"     "本地"     "本人"     "本"       "巴巴"    
 [51] "巴"       "并"       "并且"     "非"       "彼"       "时"       "彼此"     "便于"     "把"       "边"      
 [61] "鄙人"     "罢了"     "被"       "般"       "的"       "此"       "间"       "此次"     "此时"     "此外"    
 [71] "处"       "此地"     "才"       "才能"     "朝"       "朝着"     "从"       "从此"     "从而"     "除非"    
 [81] "除此之外" "除"       "开"       "除外"     "除了"     "诚"       "诚如"     "出来"     "出于"     "曾"      
 [91] "趁"       "着"       "在"       "乘"       "冲"       "等等"     "等到"     "等"       "第"       "当"  

//....省略

使用停用词表进行特征过滤,就是在tokens_select(),输入停用词参数。由于都是中文字符,所以用英文停用词表,并没有实际过滤去词。


> t2 <- tokens_select(t1, stopwords('english'),selection='remove')
> t2_len<-length(as.character(t1));t2_len
[1] 285

第六步,文字搜索。针对核心的关键词进行搜索,使用kwic()函数,支持正则匹配。

针对“算法”进行搜索,匹配文本中,算法的关键词,同时匹配中,算法前后的上下文的词。共找到4处“算法”出现的位置,可以让我们非常直观的定位核心段落。


> kwic(t2, pattern = "算法", valuetype = "regex")
Keyword-in-context with 4 matches.                                                                          
  [1.txt, 10] 硕士 具有 一年半 科技 企业 | 算法 | 工程 师 经验 熟练 掌握  
  [1.txt, 30]    机 XGBoost 等 机器 学习 | 算法 | 工作 积极 主动 良好 的  
 [1.txt, 108]     特征 选择 等 多种 推荐 | 算法 | 和 机器 学习 算法 实现  
 [1.txt, 112]     推荐 算法 和 机器 学习 | 算法 | 实现 根据 用户 特征 使用

以“精通”、"硕士"关键字进行匹配。


> kwic(t2, pattern = "精通", valuetype = "regex")
Keyword-in-context with 0 matches.
> kwic(t2, pattern = "硕士", valuetype = "regex")
Keyword-in-context with 1 match.                                                                     
 [1.txt, 5] 国内 知名 院校 理工科 | 硕士 | 具有 一年半 科技 企业 算法

以正则表达式 "R|python|sql",进行多词匹配。


> kwic(t2, pattern = "R|python|sql", valuetype = "regex")
Keyword-in-context with 10 matches.                                                                                                                   
  [1.txt, 16]                     工程 师 经验 熟练 掌握 |       python        | r sql 语言 熟悉 神经              
  [1.txt, 17]                   师 经验 熟练 掌握 python |          r          | sql 语言 熟悉 神经 网络           
  [1.txt, 18]                    经验 熟练 掌握 python r |         sql         | 语言 熟悉 神经 网络 支持          
 [1.txt, 171]                       绘制 其实 体 关系 图 | Entity-Relationship | Diagrams 使用 MySQL Workbench 创建
 [1.txt, 172]        其实 体 关系 图 Entity-Relationship |      Diagrams       | 使用 MySQL Workbench 创建 数据    
 [1.txt, 174]  关系 图 Entity-Relationship Diagrams 使用 |        MySQL        | Workbench 创建 数据 框架 Data     
 [1.txt, 175] 图 Entity-Relationship Diagrams 使用 MySQL |      Workbench      | 创建 数据 框架 Data Schema        
 [1.txt, 193]                数据 Synthetic Data 并 通过 |     PostgreSQL      | 创建 关系 数据 库 Relational      
 [1.txt, 198]               PostgreSQL 创建 关系 数据 库 |     Relational      | Database 提取 和 清理 数据        
 [1.txt, 206]                       和 清理 数据 编写 了 |       Python        | 代码 进行 数据 预 处理  

第七步,文本特征矩阵化,形成分词后的词频矩阵。


# 对原始分词进行矩阵化
> dfm1<-dfm(token)

# 查看输出
> dfm1
Document-feature matrix of: 1 document, 186 features (0.00% sparse) and 2 docvars.
       features
docs    国内 知名 211 院校 理工科 硕士 , 具有 一年半 科技
  1.txt    1    1   1    1      1    1 25    1      1    1
[ reached max_nfeat ... 176 more features ]

对特征清洗后的特征进行矩阵化


> dfm1<-dfm(t2)
> dfm1
Document-feature matrix of: 1 document, 172 features (0.00% sparse) and 2 docvars.
       features
docs    国内 知名 院校 理工科 硕士 具有 一年半 科技 企业 算法
  1.txt    1    1    1      1    1    1      1    1    1    4
[ reached max_nfeat ... 162 more features ]

查看前100个高频的特征


> topfeatures(dfm1, 100)
   数据      和      的    特征    学习    用户      等    使用    算法    机器    分析      并    进行    创建 
     16       9       8       7       6       6       5       5       4       4       4       4       4       4 
   神经    网络    导出      库    指标    根据      性      模    关系    data      了  python xgboost    工作 
      3       3       3       3       3       3       3       3       3       3       3       2       2       2 
   应用    项目    清洗    基础    疗效    提取    相关    选择    推荐    体验    框架  schema      建    线性 
      2       2       2       2       2       2       2       2       2       2       2       2       2       2 
   随机    森林    国内    知名    院校  理工科    硕士    具有  一年半    科技    企业    工程      师    经验 
      2       2       1       1       1       1       1       1       1       1       1       1       1       1 
   熟练    掌握       r     sql    语言    熟悉    支持    向量      机    积极    主动    良好    沟通    协调 
      1       1       1       1       1       1       1       1       1       1       1       1       1       1 
   自主    能力    专业    类别      多    知识      面      广    信息    行为      脏    计算      日      活 
      1       1       1       1       1       1       1       1       1       1       1       1       1       1 
   留存    结果    提出  一系列    假设    寻找      与    因素      其     pca      降      维    多种    实现 
      1       1       1       1       1       1       1       1       1       1       1       1       1       1 
   协同    过滤 
      1       1 

第八步,建立关键词字典,对文本向量按字典进行分组统计。


# 建立字典向量
> dict <- dictionary(
+   list(算法 = c("算法","模型","统计"),
+        业务 = c("业务","行业","需求"),
+        大数据 = c("hadoop","Spark","Flink"),
+        编程 = c("R","Python","Java","sql")))

# 对文本向量按字典进行分组统计
> tokens_lookup(t2,dictionary = dict) %>%
+   dfm()%>%
+   dfm_group(groups = 职位)
Document-feature matrix of: 1 document, 4 features (50.00% sparse) and 2 docvars.
            features
docs         算法 业务 大数据 编程
  算法工程师    5    0      0    4

本文我们了解了quanteda包的核心函数的使用,通过quanteda包可以让我们进行文本分析事倍功半。确实功能强大,下一篇文章,我们将用quanteda包做一个招聘职位的数据分析案例,请参考文章基于quanteda包招聘职位分析案例

本文的代码已上传到github:https://github.com/bsspirit/quanteda/blob/main/quanteda-basic.r

转载请注明出处:
http://blog.fens.me/r-word-quanteda/

打赏作者

R语言中文分词包jiebaR

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹(Conan), 程序员Java,R,PHP,Javascript
  • weibo:@Conan_Z
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-word-jiebar/

jiebaR

前言

本文挖掘是数据挖掘中一个非常重要的部分,有非常广阔的使用场景,比如我们可以对新闻事件进行分析,了解国家大事;也可以对微博信息进行分析,通过社交舆情看看大家的关注点。通过文本挖掘找到文章中的隐藏信息,对文章的结构进行分析,判断是不是同一个作者写文章;同时可以对邮件分析,结合bayes算法判断哪些是垃圾邮件,哪些是有用的邮件。

本文挖掘的第一步,就是要进行分词,分词将直接影响文本挖掘的效果。R语言在分词方面有很好的支持,接下来就给大家介绍一个不错的R语言中文分词包“结巴分词”(jiebaR)。

目录

  1. jiebaR包介绍
  2. 5分钟上手
  3. 分词引擎
  4. 配置词典
  5. 停止词过滤
  6. 关键词提取

1. jiebaR包介绍

结巴分词(jiebaR),是一款高效的R语言中文分词包,底层使用的是C++,通过Rcpp进行调用很高效。结巴分词基于MIT协议,就是免费和开源的,感谢国人作者的给力支持,让R的可以方便的处理中文文本。

官方Github的地址:https://github.com/qinwf/jiebaR

本文所使用的系统环境

  • Win10 64bit
  • R: 3.2.3 x86_64-w64-mingw32/x64 b4bit

jiebaR包是在CRAN发布的标准库,安装起来非常简单,2条命令就可以了。


~ R
> install.packages("jiebaR")
> library("jiebaR")

如果想要安装开发版本,可以使用devtools来进行安装,devtools的介绍请参考文章:在巨人的肩膀前行 催化R包开发


> library(devtools)
> install_github("qinwf/jiebaRD")
> install_github("qinwf/jiebaR")
> library("jiebaR")

开发版本安装,官方建议使用Linux系统 gcc >= 4.6 编译,Windows需要安装 Rtools。

2. 5分钟上手

5分钟上手,直接看第一个例子吧,对一段文字进行分词。


> wk = worker()

> wk["我是《R的极客理想》图书作者"]
[1] "我是" "R"    "的"   "极客" "理想" "图书" "作者"

> wk["我是R语言的深度用户"]
[1] "我"   "是"   "R"    "语言" "的"   "深度" "用户"

很简单地,2行代码,就完成了中文分词。

jiebaR提供了3种分词语句的写法,例子上面的用[]符号的语法,还可以使用<=符合语法,或者使用segment()函数。虽然形式不同,但是分词效果是一样的。使用<=符号的语法,如下


> wk<='另一种符合的语法'
[1] "另"   "一种" "符合" "的"   "语法"

使用segment()函数的语法,如下


> segment( "segment()函数语句的写法" , wk )
[1] "segment" "函数"    "语句"    "的"      "写法" 

如果你觉得很神奇,想了解如何自定义操作符的,可以检查项目的源代码quick.R文件


# <= 符号定义
`<=.qseg`<-function(qseg, code){
  if(!exists("quick_worker",envir = .GlobalEnv ,inherits = F) || 
       .GlobalEnv$quick_worker$PrivateVarible$timestamp != TIMESTAMP){
    
    if(exists("qseg",envir = .GlobalEnv,inherits = FALSE ) ) 
      rm("qseg",envir = .GlobalEnv)
    
    modelpath  = file.path(find.package("jiebaR"),"model","model.rda")
    quickparam = readRDS(modelpath)
    
    if(quickparam$dict == "AUTO") quickparam$dict = DICTPATH
    if(quickparam$hmm == "AUTO") quickparam$hmm = HMMPATH
    if(quickparam$user == "AUTO") quickparam$user = USERPATH
    if(quickparam$stop_word == "AUTO") quickparam$stop_word = STOPPATH
    if(quickparam$idf == "AUTO") quickparam$idf = IDFPATH
    
    createquickworker(quickparam)
    setactive()
  } 

  //..代码省略
}

# [ 符号定义
`[.qseg`<- `<=.qseg`

我们也可以直接对文本文件进行分词,在当前目录新建一个文本文件idea.txt。


~ notepad idea.txt

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

当然,我们运行分词程序,会在当前目录生成一个新的分词结果的文件。


> wk['./idea.txt']
[1] "./idea.segment.2016-07-20_23_25_34.txt"

打开文件idea.segment.2016-07-20_23_25_34.txt,整个本文以空格进行分词。


~ notepad idea.segment.2016-07-20_23_25_34.txt

R 的 极客 理想 系列 文章 涵盖 了 R 的 思想 使用 工具 创新 等 的 一系列 要点 以 我 个人 的 学习 和 体验 去 诠释 R 的 强大 R 语言 作为 统计学 一门 语言 一直 在 小众 领域 闪耀着 光芒 直到 大 数据 的 爆发 R 语言 变成 了 一门 炙手可热 的 数据分析 的 利器 随着 越来越 多 的 工程 背景 的 人 的 加入 R 语言 的 社区 在 迅速 扩大 成长 现在 已 不仅仅 是 统计 领域 教育 银行 电商 互联网 都 在 使用 R 语言

是不是很简单,5分钟实践就能完成分词的任务。

3. 分词引擎

在调用worker()函数时,我们实际是在加载jiebaR库的分词引擎。jiebaR库提供了7种分词引擎。

  • 混合模型(MixSegment):是四个分词引擎里面分词效果较好的类,结它合使用最大概率法和隐式马尔科夫模型。
  • 最大概率法(MPSegment) :负责根据Trie树构建有向无环图和进行动态规划算法,是分词算法的核心。
  • 隐式马尔科夫模型(HMMSegment):是根据基于人民日报等语料库构建的HMM模型来进行分词,主要算法思路是根据(B,E,M,S)四个状态来代表每个字的隐藏状态。 HMM模型由dict/hmm_model.utf8提供。分词算法即viterbi算法。
  • 索引模型(QuerySegment):先使用混合模型进行切词,再对于切出来的较长的词,枚举句子中所有可能成词的情况,找出词库里存在。
  • 标记模型(tag)
  • Simhash模型(simhash)
  • 关键词模型(keywods)

如果你不太关心引擎的事,那么直接用官方推荐的混合模型(默认选择)就行了。查看worker()函数的定义。


worker(type = "mix", dict = DICTPATH, hmm = HMMPATH, user = USERPATH,
  idf = IDFPATH, stop_word = STOPPATH, write = T, qmax = 20, topn = 5,
  encoding = "UTF-8", detect = T, symbol = F, lines = 1e+05,
  output = NULL, bylines = F, user_weight = "max")

参数列表:

  • type, 引擎类型
  • dict, 系统词典
  • hmm, HMM模型路径
  • user, 用户词典
  • idf, IDF词典
  • stop_word, 关键词用停止词库
  • write, 是否将文件分词结果写入文件,默认FALSE
  • qmax, 最大成词的字符数,默认20个字符
  • topn, 关键词数,默认5个
  • encoding, 输入文件的编码,默认UTF-8
  • detect, 是否编码检查,默认TRUE
  • symbol, 是否保留符号,默认FALSE
  • lines, 每次读取文件的最大行数,用于控制读取文件的长度。大文件则会分次读取。
  • output, 输出路径
  • bylines, 按行输出
  • user_weight, 用户权重

我们在调用worker()时,就加载了分词引擎,可以打印出来,查看分词的引擎的配置。


> wk = worker()
> wk
Worker Type:  Jieba Segment

Default Method  :  mix     # 混合模型
Detect Encoding :  TRUE    # 检查编码
Default Encoding:  UTF-8   # UTF-8
Keep Symbols    :  FALSE   # 不保留符号
Output Path     :          # 输出文件目录
Write File      :  TRUE    # 写文件
By Lines        :  FALSE   # 不行输出
Max Word Length :  20      # 最大单单词长度
Max Read Lines  :  1e+05   # 最大读入文件行数

Fixed Model Components:  

$dict                      # 系统词典
[1] "D:/tool/R-3.2.3/library/jiebaRD/dict/jieba.dict.utf8"

$user                      # 用户词典
[1] "D:/tool/R-3.2.3/library/jiebaRD/dict/user.dict.utf8"

$hmm                       # 隐式马尔科夫模型模型
[1] "D:/tool/R-3.2.3/library/jiebaRD/dict/hmm_model.utf8"

$stop_word                 # 停止词,无
NULL

$user_weight               # 用户词典权重
[1] "max"

$timestamp                 # 时间戳
[1] 1469027302

$default $detect $encoding $symbol $output $write $lines $bylines can be reset.

如果我们想改变分词引擎的配置项,可以在调用worker()创建分词引擎时,也可以通过wk$XX来进行设置。如果想了解wk是什么类型的对象,我们通过pryr包的otype的函数来检查wk对象的类型。关于pryr包的详细使用,请参考文章撬动R内核的高级工具包pryr


# 加载 pryr包
> library(pryr)
> otype(wk)  # 面向对象的类型检查
[1] "S3"

> class(wk)  # 查看class是属性
[1] "jiebar"  "segment" "jieba" 

4. 配置词典

对于分词的结果好坏的关键因素是词典,jiebaR默认有配置标准的词典。对于我们的使用来说,不同行业或不同的文字类型,最好用专门的分词词典。在jiebaR中通过show_dictpath()函数可以查看默认的标准词典,可以通过上一小节介绍的配置项,来指定我们自己的词典。日常对话的常用词典,比如搜狗输入法的词库。


# 查看默认的词库位置
> show_dictpath()
[1] "D:/tool/R-3.2.3/library/jiebaRD/dict"

# 查看目录
> dir(show_dictpath())
[1] "D:/tool/R-3.2.3/library/jiebaRD/dict"
 [1] "backup.rda"      "hmm_model.utf8"  "hmm_model.zip"  
 [4] "idf.utf8"        "idf.zip"         "jieba.dict.utf8"
 [7] "jieba.dict.zip"  "model.rda"       "README.md"      
[10] "stop_words.utf8" "user.dict.utf8" 

看到词典目录中,包括了多个文件。

  • jieba.dict.utf8, 系统词典文件,最大概率法,utf8编码的
  • hmm_model.utf8, 系统词典文件,隐式马尔科夫模型,utf8编码的
  • user.dict.utf8, 用户词典文件,utf8编码的
  • stop_words.utf8,停止词文件,utf8编码的
  • idf.utf8,IDF语料库,utf8编码的
  • jieba.dict.zip,jieba.dict.utf8的压缩包
  • hmm_model.zip,hmm_model.utf8的压缩包
  • idf.zip,idf.utf8的压缩包
  • backup.rda,无注释
  • model.rda,无注释
  • README.md,说明文件

打开系统词典文件jieba.dict.utf8,并打印前50行。


> scan(file="D:/tool/R-3.2.3/library/jiebaRD/dict/jieba.dict.utf8",
+           what=character(),nlines=50,sep='\n',
+           encoding='utf-8',fileEncoding='utf-8')
Read 50 items
 [1] "1号店 3 n"  "1號店 3 n"  "4S店 3 n"   "4s店 3 n"  
 [5] "AA制 3 n"   "AB型 3 n"   "AT&T 3 nz"  "A型 3 n"   
 [9] "A座 3 n"    "A股 3 n"    "A輪 3 n"    "A轮 3 n"   
[13] "BB机 3 n"   "BB機 3 n"   "BP机 3 n"   "BP機 3 n"  
[17] "B型 3 n"    "B座 3 n"    "B股 3 n"    "B超 3 n"   
[21] "B輪 3 n"    "B轮 3 n"    "C# 3 nz"    "C++ 3 nz"  
[25] "CALL机 3 n" "CALL機 3 n" "CD机 3 n"   "CD機 3 n"  
[29] "CD盒 3 n"   "C座 3 n"    "C盘 3 n"    "C盤 3 n"   
[33] "C語言 3 n"  "C语言 3 n"  "D座 3 n"    "D版 3 n"   
[37] "D盘 3 n"    "D盤 3 n"    "E化 3 n"    "E座 3 n"   
[41] "E盘 3 n"    "E盤 3 n"    "E通 3 n"    "F座 3 n"   
[45] "F盘 3 n"    "F盤 3 n"    "G盘 3 n"    "G盤 3 n"   
[49] "H盘 3 n"    "H盤 3 n"

我们发现系统词典每一行都有三列,并以空格分割,第一列为词项,第二列为词频,第三列为词性标记。

打开用户词典文件user.dict.utf8,并打印前50行。


> scan(file="D:/tool/R-3.2.3/library/jiebaRD/dict/user.dict.utf8",
+      what=character(),nlines=50,sep='\n',
+      encoding='utf-8',fileEncoding='utf-8')
Read 5 items
[1] "云计算"   "韩玉鉴赏" "蓝翔 nz"  "CEO"      "江大桥"  

用户词典第一行有二列,,第一列为词项,第二列为词性标记,没有词频的列。用户词典默认词频为系统词库中的最大词频。

jiebaR包关于词典词性标记,采用ictclas的标记方法。ICTCLAS 汉语词性标注集。

代码名称帮助记忆的诠释
Ag形语素形容词性语素。形容词代码为a,语素代码g前面置以A。
a形容词取英语形容词adjective的第1个字母。
ad副形词直接作状语的形容词。形容词代码a和副词代码d并在一起。
an名形词具有名词功能的形容词。形容词代码a和名词代码n并在一起。
b区别词取汉字"别"的声母。
c连词取英语连词conjunction的第1个字母。
Dg副语素副词性语素。副词代码为d,语素代码g前面置以D。
d副词取adverb的第2个字母,因其第1个字母已用于形容词。
e叹词取英语叹词exclamation的第1个字母。
f方位词取汉字"方"的声母。
g语素绝大多数语素都能作为合成词的"词根",取汉字"根"的声母。
h前接成分取英语head的第1个字母。
i成语取英语成语idiom的第1个字母。
j简称略语取汉字"简"的声母。
k后接成分
l习用语习用语尚未成为成语,有点"临时性",取"临"的声母。
m数词取英语numeral的第3个字母,n,u已有他用。
Ng名语素名词性语素。名词代码为n,语素代码g前面置以N。
n名词取英语名词noun的第1个字母。
nr人名名词代码n和"人(ren)"的声母并在一起。
ns地名名词代码n和处所词代码s并在一起。
nt机构团体"团"的声母为t,名词代码n和t并在一起。
nz其他专名"专"的声母的第1个字母为z,名词代码n和z并在一起。
o拟声词取英语拟声词onomatopoeia的第1个字母。
p介词取英语介词prepositional的第1个字母。
q量词取英语quantity的第1个字母。
r代词取英语代词pronoun的第2个字母,因p已用于介词。
s处所词取英语space的第1个字母。
Tg时语素时间词性语素。时间词代码为t,在语素的代码g前面置以T。
t时间词取英语time的第1个字母。
u助词取英语助词auxiliary 的第2个字母,因a已用于形容词。
Vg动语素动词性语素。动词代码为v。在语素的代码g前面置以V。
v动词取英语动词verb的第一个字母。
vd副动词直接作状语的动词。动词和副词的代码并在一起。
vn名动词指具有名词功能的动词。动词和名词的代码并在一起。
w标点符号
x非语素字非语素字只是一个符号,字母x通常用于代表未知数、符号。
y语气词取汉字"语"的声母。
z状态词取汉字"状"的声母的前一个字母。

下面我们自定义一个用户词典,来试试效果。编写词典文件,user.utf8。


~ notepad user.utf8

R语言
R的极客理想
大数据
数据

使用我们的自定义的用户词典,对刚才的文本再进行分词。


> wk = worker(user='user.utf8')
> wk['./idea.txt']
[1] "./idea.segment.2016-07-21_11_14_24.txt"

对比2次产生的分词结果,idea.segment.2016-07-20_23_25_34.txt 和 idea.segment.2016-07-21_11_14_24.txt。

jiebaR-cut

在实际使用中,jiebaR默认提供的用户词典只有5个单词,太简单了,肯定是不够用的。我们可以用搜狗词典,来丰富用户自己的词库。接下来,让我们配置搜狗词典。你需要安装一个搜狗输入法,具体的安装过程不再解释。

我安装的是搜狗五笔输入法,找到搜狗的安装目录,并找到词典文件。我的搜狗词典,在下面的安装位置。


C:\Program Files (x86)\SogouWBInput\2.1.0.1288\scd\17960.scel

把17960.scel文件复制到自己的项目目录里,用文本编辑器打开文件,发现是二进制的。那么我需要用工具进行转换,把二进制的词典转成我们可以使用的文本文件。jiebaR包的作者,同时开发了一个cidian项目,可以转换搜狗的词典,那么我们只需要安装cidian包即可。

安装cidian项目


> install.packages("devtools")
> install.packages("stringi")
> install.packages("pbapply")
> install.packages("Rcpp")
> install.packages("RcppProgress")
> library(devtools)
> install_github("qinwf/cidian")
> library(cidian)

转换二进制词典到文本文件。


# 转换
> decode_scel(scel = "./17960.scel",cpp = TRUE)
output file: ./17960.scel_2016-07-21_00_22_11.dict

# 查看生成的词典文件
> scan(file="./17960.scel_2016-07-21_00_22_11.dict",
+      what=character(),nlines=50,sep='\n',
+      encoding='utf-8',fileEncoding='utf-8')
Read 50 items
 [1] "阿坝州 n"         "阿百川 n"         "阿班 n"          
 [4] "阿宾 n"           "阿波菲斯 n"       "阿不都热希提 n"  
 [7] "阿不都西库尔 n"   "阿不力克木 n"     "阿尔姆格伦 n"    
[10] "阿尔沙文 n"       "阿肥星 n"         "阿菲正传 n"      
[13] "阿密特 n"         "阿穆 n"           "阿穆隆 n"        
[16] "阿帕鲁萨镇 n"     "阿披实 n"         "阿衰 n"          
[19] "阿霞 n"           "艾奥瓦 n"         "爱不疚 n"        
[22] "爱的错位 n"       "爱得得体 n"       "爱的火焰 n"      
[25] "爱的流刑地 n"     "爱得起 n"         "埃夫隆 n"        
[28] "爱搞网 n"         "爱国红心 n"       "爱呼 n"          
[31] "爱就宅一起 n"     "埃克希儿 n"       "爱没有错 n"      
[34] "埃蒙斯 n"         "爱奴新传 n"       "爱起点 n"        
[37] "爱情的牙齿 n"     "爱情海滨 n"       "爱情节 n"        
[40] "爱情美的样子 n"   "爱情无限谱 n"     "爱情占线 n"      
[43] "爱情转移 n"       "爱情左灯右行 n"   "爱上你是一个错 n"
[46] "矮哨兵 n"         "爱是妥协 n"       "爱似水仙 n"      
[49] "爱太痛 n"         "爱无界 n"    

接下来,直接把搜狗词典配置到我们的分词库中,就可以直接使用了。把搜狗词典文件改名,从17960.scel_2016-07-21_00_22_11.dict到user.dict.utf8,然后替换D:\tool\R-3.2.3\library\jiebaRD\dict目录下面的user.dict.utf8。这样默认的用户词典,就是搜狗词典了。很酷吧!

5. 停止词过滤

停止词就是分词过程中,我们不需要作为结果的词,像英文的语句中有很多的a,the,or,and等,中文语言中也有很多,比如 的,地,得,我,你,他。这些词因为使用频率过高,会大量出现在一段文本中,对于分词后的结果,在统计词频的时候会增加很多的噪音,所以我们通常都会将这些词进行过滤。

在jiebaR中,过滤停止词有2种方法,一种是通过配置stop_word文件,另一种是使用filter_segment()函数。

首先我们先来看,通过配置stop_word文件的方法。新建一个stop_word.txt文件。


~ notepad stop_word.txt

我
我是

加载分词引擎,并配置停止词过滤。


> wk = worker(stop_word='stop_word.txt')
> segment<-wk["我是《R的极客理想》图书作者"]
> segment
[1] "R"    "的"   "极客" "理想" "图书" "作者"

上面的文本,我们把"我是"通过停止词进行了过滤。如果还想过滤“作者”一词,可以动态的调用filter_segment()函数。


> filter<-c("作者")
> filter_segment(segment,filter)
[1] "R"    "的"   "极客" "理想" "图书"

6. 关键词提取

关键词提取是文本处理非常重要的一个环节,一个经典算法是TF-IDF算法。其中,TF(Term Frequency)代表词频,IDF(Inverse Document Frequency)表示逆文档频率。如果某个词在文章中多次出现,而且不是停止词,那么它很可能就反应了这段文章的特性,这就是我们要找的关键词。再通过IDF来算出每个词的权重,不常见的词出现的频率越高,则权重越大。计算TF-IDF的公式为:

TF-IDF = TF(词频) * 逆文档频率(IDF)

对文档中每个词计算TF-IDF的值,把结果从大到小排序,就得到了这篇文档的关键性排序列表。关于IF-IDF的解释,参考了文章TF-IDF与余弦相似性的应用(一):自动提取关键词

jiebaR包的关键词提取提取的实现,也是使用了TF-IDF的算法。在安装目录中的idf.utf8文件,为IDF的语料库。查看idf.utf8内容。


> scan(file="D:/tool/R-3.2.3/library/jiebaRD/dict/idf.utf8",
+      what=character(),nlines=50,sep='\n',
+      encoding='utf-8',fileEncoding='utf-8')
Read 50 items
 [1] "劳动防护 13.900677652"      "生化学 13.900677652"       
 [3] "奥萨贝尔 13.900677652"      "考察队员 13.900677652"     
 [5] "岗上 11.5027823792"         "倒车档 12.2912397395"      
 [7] "编译 9.21854642485"         "蝶泳 11.1926274509"        
 [9] "外委 11.8212361103"         "故作高深 11.9547675029"    
[11] "尉遂成 13.2075304714"       "心源性 11.1926274509"      
[13] "现役军人 10.642581114"      "杜勃留 13.2075304714"      
[15] "包天笑 13.900677652"        "贾政陪 13.2075304714"      
[17] "托尔湾 13.900677652"        "多瓦 12.5143832909"        
[19] "多瓣 13.900677652"          "巴斯特尔 11.598092559"     
[21] "刘皇帝 12.8020653633"       "亚历山德罗夫 13.2075304714"
[23] "社会公众 8.90346537821"     "五百份 12.8020653633"      
[25] "两点阈 12.5143832909"       "多瓶 13.900677652"         
[27] "冰天 12.2912397395"         "库布齐 11.598092559"       
[29] "龙川县 12.8020653633"       "银燕 11.9547675029"        
[31] "历史风貌 11.8212361103"     "信仰主义 13.2075304714"    
[33] "好色 10.0088573539"         "款款而行 12.5143832909"    
[35] "凳子 8.36728816325"         "二部 9.93038573842"        
[37] "卢巴 12.1089181827"         "五百五 13.2075304714"      
[39] "畅叙 11.598092559"          "吴栅子 13.2075304714"      
[41] "智力竞赛 13.900677652"      "库邦 13.2075304714"        
[43] "非正义 11.3357282945"       "编订 10.2897597393"        
[45] "悲号 12.8020653633"         "陈庄搭 13.2075304714"      
[47] "二郎 9.62401153296"         "电光石火 11.8212361103"    
[49] "抢球 11.9547675029"         "南澳大利亚 10.9562386728"  

idf.utf8文件每一行有2列,第一列是词项,第二列为权重。然后,我通过计算文档的词频(TF),与语料库的IDF值相乘,就可以得到TF-IDF值,从而提取文档的关键词。

比如,我们对下面的文本内容进行关键词的提取。


> wk = worker()
> segment<-wk["R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。"]

# 计算词频
> freq(segment)
     char freq
1    创新    1
2      了    1
3    文章    1
4    强大    1
5       R    3
6    个人    1
7      的    5
8    诠释    1
9      和    1
10 一系列    1
11   使用    1
12     以    1
13     等    1
14   极客    1
15   理想    1
16   思想    1
17   涵盖    1
18   系列    1
19     去    1
20     我    1
21   工具    1
22   学习    1
23   体验    1
24   要点    1

# 取TF-IDF的前5的关键词
> keys = worker("keywords",topn=5)

# 计算关键词
> vector_keywords(segment,keys)
11.7392 8.97342 8.23425  8.2137 7.43298 
 "极客"  "诠释"  "要点"  "涵盖"  "体验" 

使用jiebaR包处理分词确实简单,几行的代码就能实现分词的各种算法操作。有了这个工具,我们就可以文档中,发现各种语言规则进行文本挖掘了。下篇文章让我们挖掘一下上市公司的公告吧,说不定能发现什么市场规则。

本文只是抛砖引玉地介绍了jiebaR包的使用方法,详细使用操作,请参考包作者的官方介绍。再次感谢jiebaR作者@qinwenfeng,为R语言在中文分词中提供了一套非常不错的工具包!

转载请注明出处:
http://blog.fens.me/r-word-jiebar/

打赏作者