• Posts tagged "TF-IDF"

Blog Archives

用R语言计算文本的TF-IDF

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-text-tf-idf/

前言

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

TF-IDF是一种通过计算词频,进行文本信息检索的一种方式,常用对文本数据进行向量化特征的描述。

目录

  1. 什么是TF-IDF介绍
  2. tidytext包计算TF-IDF
  3. quanteda包计算TF-IDF

1. 什么是TF-IDF介绍

TF-IDF (词频-逆文档频率) 是一种在信息检索和文本挖掘中常用的加权技术。它衡量一个词语对于一个文档的重要性,通过结合词频(TF) 和逆文档频率(IDF) 来计算。

TF (词频): 表示词语在特定文档中出现的次数。一个词语在文档中出现的次数越多,通常认为它在该文档中越重要。
IDF (逆文档频率): 表示词语在整个语料库中的普遍程度。如果一个词语在很多文档中都出现,说明它比较常见,对区分文档的贡献就越小;反之,如果一个词语只出现在少数文档中,说明它对区分这些文档越重要。
TF-IDF 的计算: TF-IDF 值是TF 值和IDF 值的乘积。

公式:


TF (词频) = (词语在文档中出现的次数) / (文档中的总词数)
IDF (逆文档频率) = log(总文档数/ 包含该词语的文档数+ 1) (加1 是为了避免除以零的情况)
TF-IDF = TF * IDF


作用: TF-IDF 通过综合考虑词语在文档内的频率和在语料库中的普遍程度,能够有效地识别出对文档具有区分度的关键词。在搜索引擎中,TF-IDF 常被用于计算文档与用户查询的相关性,从而对搜索结果进行排序。

总结: TF-IDF 是一种简单而有效的文本特征提取方法,通过对词语的权重计算,可以帮助我们更好地理解和利用文本数据.

2. tidytext包计算TF-IDF

R语言中,有多个包都支持TF-IDF的计算。首先,我们先使用tidytext包。

安装tidytext包


# 安装tidytext包
> install.packages("tidytext")

# 加载tidytext包
> library(tidytext)

# 加载其他工具包
> library(dplyr)
> library(tibble)

定义10段文本数据,并进行编号。


# 定义文本数据
> ss <- c(
+     "R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大", 
+     "R语言作为统计学一门语言,一直在小众领域闪耀着光芒。", 
+     "现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。",
+     "直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。",
+     "随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。",
+     "TF-IDF (词频-逆文档频率) 是一种在信息检索和文本挖掘中常用的加权技术。",
+     "它衡量一个词语对于一个文档的重要性,通过结合词频(TF) 和逆文档频率(IDF) 来计算。",
+     "TF (词频): 表示词语在特定文档中出现的次数。一个词语在文档中出现的次数越多,通常认为它在该文档中越重要。",
+     "IDF (逆文档频率): 表示词语在整个语料库中的普遍程度。如果一个词语在很多文档中都出现,说明它比较常见,对区分文档的贡献就越小;反之,如果一个词语只出现在少数文档中,说明它对区分这些文档越重要。",
+     "TF-IDF 的计算: TF-IDF 值是TF 值和IDF 值的乘积。"
+ ) 

# 转成tibble类型,并增加列编号
> s1<- ss %>% as_tibble() %>% rowid_to_column("ID")

# 查看s1变量
> s1
# A tibble: 10 × 2
      ID value                                    
   <int> <chr>                                    
 1     1 R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的…
 2     2 R语言作为统计学一门语言,一直在小众领域闪耀着光芒。……
 3     3 现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。……
 4     4 直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。……
 5     5 随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。……
 6     6 TF-IDF (词频-逆文档频率) 是一种在信息检索和文本挖掘中常用的加权技术。…
 7     7 它衡量一个词语对于一个文档的重要性,通过结合词频(TF) 和逆文档频率(IDF)…
 8     8 TF (词频): 表示词语在特定文档中出现的次数。一个词语在文档中出现的次数越多…
 9     9 IDF (逆文档频率): 表示词语在整个语料库中的普遍程度。如果一个词语在很多文…
10    10 TF-IDF 的计算: TF-IDF 值是TF 值和IDF 值的乘积。……

计算每个文档中的词频,用于计算tf-idf


# 计算文档中的词频
> ss_words <- s1 %>% 
+   unnest_tokens(words, value) %>% 
+   count(ID, words, sort = TRUE);ss_words
# A tibble: 191 × 3
      ID words     n
   <int> <chr> <int>
 1     1 的        5
 2     9 文        5
 3     9 档        5
 4     1 r         3
 5     4 的        3
 6     5 的        3
 7     8 在        3
 8     8 文        3
 9     8 档        3
10     9 在        3
# 181 more rows
# Use `print(n = ...)` to see more rows

使用bind_tf_idf()函数,计算每个词的tf,idf,tf-idf。

tf-idf 的思想是通过减少常用词的权重并增加在文档集合或语料库中不经常使用的词的权重,在这种情况下,我们找到每个文档内容的重要词。计算 tf-idf 会尝试查找文本中重要(即常见)但不太常见的单词。


# 计算tf-idf
> ss_tfidf <- ss_words %>% 
+   bind_tf_idf(ID, words, n)
> ss_tfidf
# A tibble: 191 × 6
      ID words      n    tf   idf tf_idf
   <int> <chr>  <int> <dbl> <dbl>  <dbl>
 1     1 的        5 0.278  1.68  0.466
 2     9 文        5 0.455  1.29  0.585
 3     9 档        5 0.455  1.29  0.585
 4     1 r         3 0.429  1.68  0.720
 5     4 的        3 0.167  2.13  0.354
 6     5 的        3 0.167  2.19  0.365
 7     8 在        3 0.375  1.85  0.695
 8     8 文        3 0.273  1.85  0.505
 9     8 档        3 0.273  1.85  0.505
10     9 在        3 0.375  1.29  0.483
# 181 more rows
# Use `print(n = ...)` to see more rows

# 以tf_idf列分值高倒序排序
> ss_tfidf %>%
+   arrange(desc(tf_idf))
# A tibble: 191 × 6
      ID words      n    tf   idf tf_idf
   <int> <chr>  <int> <dbl> <dbl>  <dbl>
 1    10 值         3     1  2.70   2.70
 2    10 乘         1     1  2.70   2.70
 3    10 积         1     1  2.70   2.70
 4     2 一         1     1  2.41   2.41
 5     2 一直在     1     1  2.41   2.41
 6     2 作为       1     1  2.41   2.41
 7     2 光芒       1     1  2.41   2.41
 8     2 学         1     1  2.41   2.41
 9     2 小众       1     1  2.41   2.41
10     2 闪耀着     1     1  2.41   2.41
# 181 more rows
# Use `print(n = ...)` to see more rows

通过tf-idf判断2个文本的相似性


# 加载widyr包
> library(widyr)

# 判断2段文本的相似性
> ss_tfidf %>% 
+   pairwise_similarity(ID, words, tf_idf, sort = TRUE)
# A tibble: 70 × 3
   item1 item2 similarity
   <int> <int>      <dbl>
 1     8     9     0.135 
 2     9     8     0.135 
 3     7    10     0.0907
 4    10     7     0.0907
 5     6    10     0.0769
 6    10     6     0.0769
 7     3     2     0.0620
 8     2     3     0.0620
 9     7     9     0.0596
10     9     7     0.0596
# 60 more rows
# Use `print(n = ...)` to see more rows

程序提示第8段和第9段文本最相似,查看第8段和第9段文本。


> ss[8]
[1] "TF (词频): 表示词语在特定文档中出现的次数。一个词语在文档中出现的次数越多,通常认为它在该文档中越重要。"

> ss[9]
[1] "IDF (逆文档频率): 表示词语在整个语料库中的普遍程度。如果一个词语在很多文档中都出现,说明它比较常见,对区分文档的贡献就越小;反之,如果一个词语只出现在少数文档中,说明它对区分这些文档越重要。"

3. quanteda包计算TF-IDF

我们再换另一个包quanteda来计算TF-IDF。quanteda包,是一个能力非常强大的文本处理包,详细内容请参考文章用R语言进行量化文本分析quanteda

安装和加载quanteda


# 安装
> install.pacakges("quanteda")
> install.pacakges("quanteda.textstats")

# 加载
> library("quanteda")
> library("quanteda.textstats")

使用上文中已建立的ss文档对象,提取关键词,形成词频矩阵。


> ssdfm
Document-feature matrix of: 10 documents, 144 features (84.51% sparse) and 0 docvars.
       features
docs    r 的 极 客 理想 系列 文章 , 涵 盖了
  text1 3  5  1  1    1    1    1  5  1    1
  text2 1  0  0  0    0    0    0  1  0    0
  text3 1  0  0  0    0    0    0  4  0    0
  text4 1  3  0  0    0    0    0  1  0    0
  text5 1  3  0  0    0    0    0  1  0    0
  text6 0  1  0  0    0    0    0  0  0    0
[ reached max_ndoc ... 4 more documents, reached max_nfeat ... 134 more features ]

使用dfm_tfidf()函数,对词频矩阵计算tfidf值,形成tfidf矩阵。


> ssidf<-dfm_tfidf(ssdfm)
> ssidf
Document-feature matrix of: 10 documents, 144 features (84.51% sparse) and 0 docvars.
       features
docs          r         的 极 客 理想 系列 文章         , 涵 盖了
  text1 0.90309 0.48455007  1  1    1    1    1 0.48455007  1    1
  text2 0.30103 0           0  0    0    0    0 0.09691001  0    0
  text3 0.30103 0           0  0    0    0    0 0.38764005  0    0
  text4 0.30103 0.29073004  0  0    0    0    0 0.09691001  0    0
  text5 0.30103 0.29073004  0  0    0    0    0 0.09691001  0    0
  text6 0       0.09691001  0  0    0    0    0 0           0    0
[ reached max_ndoc ... 4 more documents, reached max_nfeat ... 134 more features ]

用词频矩阵计算2个文档的相似性


> ssdfm %>%
+   textstat_simil(method = "cosine") %>%
+   as.matrix()
           text1      text2      text3     text4     text5      text6      text7      text8      text9     text10
text1  1.0000000 0.21426863 0.44799204 0.4716523 0.5079850 0.13525045 0.19705795 0.20087684 0.22392949 0.23823145
text2  0.2142686 1.00000000 0.40996003 0.2702264 0.2425356 0.04950738 0.07868895 0.08823529 0.11803342 0.04756515
text3  0.4479920 0.40996003 1.00000000 0.2197177 0.2366432 0.03450328 0.13710212 0.12298801 0.24678382 0.03314968
text4  0.4716523 0.27022641 0.21971769 1.0000000 0.4828079 0.15161961 0.15061881 0.20266981 0.13555693 0.25492496
text5  0.5079850 0.24253563 0.23664319 0.4828079 1.0000000 0.20412415 0.16222142 0.31529631 0.19466571 0.27456259
text6  0.1352504 0.04950738 0.03450328 0.1516196 0.2041241 1.00000000 0.46358632 0.44556639 0.36424640 0.28022427
text7  0.1970580 0.07868895 0.13710212 0.1506188 0.1622214 0.46358632 1.00000000 0.55082263 0.56578947 0.22269967
text8  0.2008768 0.08823529 0.12298801 0.2026698 0.3152963 0.44556639 0.55082263 1.00000000 0.72787276 0.19026060
text9  0.2239295 0.11803342 0.24678382 0.1355569 0.1946657 0.36424640 0.56578947 0.72787276 1.00000000 0.09544271
text10 0.2382314 0.04756515 0.03314968 0.2549250 0.2745626 0.28022427 0.22269967 0.19026060 0.09544271 1.00000000

用tfidf矩阵计算2个文档的相似性


> ssidf %>%
+   textstat_simil(method = "cosine") %>%
+   as.matrix()
             text1        text2        text3       text4       text5        text6       text7        text8       text9       text10
text1  1.000000000 0.0219479864 0.0513556447 0.024124188 0.028953788 0.0118764224 0.015076777 0.0064026405 0.006519969 0.0136248773
text2  0.021947986 1.0000000000 0.1217612800 0.075175409 0.041645241 0.0001912012 0.001083631 0.0009743142 0.001830469 0.0001785203
text3  0.051355645 0.1217612800 1.0000000000 0.018812586 0.022578816 0.0001504185 0.002943756 0.0023568679 0.005326873 0.0001404424
text4  0.024124188 0.0751754091 0.0188125856 1.000000000 0.026150152 0.0021071189 0.002852493 0.0038248671 0.002336975 0.0037986508
text5  0.028953788 0.0416452412 0.0225788162 0.026150152 1.000000000 0.0157598001 0.003423554 0.0678499967 0.021859872 0.0045591308
text6  0.011876422 0.0001912012 0.0001504185 0.002107119 0.015759800 1.0000000000 0.178921295 0.1558538111 0.128284299 0.1178464227
text7  0.015076777 0.0010836308 0.0029437558 0.002852493 0.003423554 0.1789212950 1.000000000 0.2790485085 0.271452809 0.0899040023
text8  0.006402640 0.0009743142 0.0023568679 0.003824867 0.067849997 0.1558538111 0.279048509 1.0000000000 0.421606371 0.0331304236
text9  0.006519969 0.0018304690 0.0053268734 0.002336975 0.021859872 0.1282842988 0.271452809 0.4216063707 1.000000000 0.0195965092
text10 0.013624877 0.0001785203 0.0001404424 0.003798651 0.004559131 0.1178464227 0.089904002 0.0331304236 0.019596509 1.0000000000

从2个相似性矩阵返回的结果来看,都是第8段和第9段更相似。

本文从TF-IDF的实现的角度,介绍了TF-IDF怎么使用R语言程序进行计算。这些计算就是把文本转成向量化数据的方法。

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

转载请注明出处:
http://blog.fens.me/r-text-tf-idf/

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/

打赏作者