ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

R语言自然语言处理:文本分类

2021-07-01 10:01:01  阅读:180  来源: 互联网

标签:文本 string 分类 TF words IDF table 自然语言 id


作者:黄天元,复旦大学博士在读,热爱数据科学与开源工具(R/Python),致力于利用数据科学迅速积累行业经验优势和科学知识发现,涉猎内容包括但不限于信息计量、机器学习、数据可视化、应用统计建模、知识图谱等,著有《R语言高效数据处理指南》、《文本数据挖掘——基于R语言》(《文本数据挖掘 基于R语言》(黄天元)【摘要 书评 试读】- 京东图书)。知乎专栏:R语言数据挖掘 邮箱:huang.tian-yuan@qq.com.欢迎合作交流。

前文参考:

HopeR:R语言自然语言处理:中文分词

HopeR:R语言自然语言处理:词性标注与命名实体识别

HopeR:R语言自然语言处理:关键词提取(TF-IDF)

HopeR:R语言自然语言处理:关键词提取与文本摘要(TextRank)

HopeR:R语言自然语言处理:词嵌入(Word Embedding)

HopeR:R语言自然语言处理:情感分析

 

不知不觉已经写了这么多,但是很多R语言自然语言处理的方法并没有展开来讲。这次希望尝试用简单的技术(TF-IDF和相似度矩阵)做一次实践,即文档分类。

 

任务定义:对于任意给定的一个字符串,判断它与目前哪个文档最为相似,从而进行归类。首先要对当前的文档(数据见https://github.com/hope-data-science/chinese_NLP/blob/master/%E7%AE%80%E5%8D%95%E6%96%87%E6%A1%A3%E5%88%86%E7%B1%BB/classification_corpus_raw.csv)做词嵌入(就用最简单的TF-IDF模型),然后对于任意的新字符串,进行向量化之后,与先前的标准库做相似性的分析,看看与哪个文档相似性最近,就属于哪一个类别。

 

1 读入文件

library(pacman)
p_load(tidyverse,data.table)

fread("classification_corpus_raw.csv",encoding = "UTF-8") %>% 
  as_tibble() %>% 
  mutate(id = 1:n())-> raw

这样,文件就在raw中了。

 

2 计算TF-IDF

这一部分参考HopeR:R语言自然语言处理:关键词提取(TF-IDF),先进行分词,然后对所有的词计算TF-IDF。

## 快速分词
p_load(jiebaR)
worker() -> wk

raw %>% 
  mutate(words = map(title,segment,jieba = wk)) %>% 
  select(id,words) -> corpus 

## 计算TF-IDF
corpus %>% 
  unnest() %>% 
  count(id,words) %>% 
  bind_tf_idf(term = words,document = id,n = n) -> corpus_tf_idf

仔细看,这个文档现在究竟有多少个词语呢?

corpus_tf_idf %>% distinct(words)

# A tibble: 1,510 x 1
   words   
   <chr>   
 1 百年    
 2 办公室  
 3 筹备工作
 4 校庆    
 5 保卫部  
 6 处      
 7 安全    
 8 管理    
 9 生产    
10 保密    
# ... with 1,500 more rows

一共1510个,不多,因此我决定不进行筛选了。本来常规套路要把这个TF-IDF的矩阵变为一个文档-词语矩阵(Document Term Matrix,DTM)。但是既然走了tidy的路线,我突然认为那是一个多余的步骤,做了一个高维稀疏的矩阵效率异常低,而进行连接(join)的速度可谓异常地快。

下面我要写一个函数,它要完成一个这样的任务:对于任意给定的字符串,求这个字符串与当前所有文档的相似性,然后筛选出相似性最高的n个文档,显示出来。

虽然不需要构造矩阵,但是我还是要构造一个类似的数据框。

corpus_tf_idf %>% 
  select(id,tf_idf) -> for_future_use

 

3 举例尝试

先假设给定的字符串为“大数据学院”,我们看看是否能够找到合理的相似文档。我们首先要明确,什么叫做相似?定义:1、字符串中包含相同的组分(相同的分词结果);2、当包含组分数量一致的时候,如果包含重要表征组分,其得分更高(举例说明:我们给定的字符串是“物理学院”,分词之后是“物理”和“学院”,但是“物理”这个词能够表征的程度更高,因此它会得到更高的得分,这个得分在我们的模型中是以TF-IDF的形式存在的)。

下面我们给出代码:

string = "大数据学院"

string %>% 
  segment(jiebar = wk) %>% 
  enframe() %>% 
  transmute(words = value) -> string_table

for_future_use %>% 
  inner_join(string_table) %>% 
  group_by(id) %>% 
  summarise(score = sum(tf_idf)) %>% 
  arrange(desc(score)) -> sort_table

sort_table %>% 
  slice(1:5) %>% 
  inner_join(raw,by = "id")

# A tibble: 5 x 3
     id score title       
  <int> <dbl> <chr>       
1    58  4.70 大数据学院  
2    57  2.86 大数据研究院
3   109  1.84 高级律师学院
4   436  1.84 公共卫生学院
5   479  1.84 管理学院  

我们可以看到,“大数据学院”被正确地筛选出来,而排名第二的是“大数据研究院”,因为“大数据”作为一个比“学院”拥有更高TF-IDF的关键词,更能够表征“大数据”这个特征。其他3个选项得分其实是一样的,它们都因为有“学院”而被筛选出来,但是没有匹配更多更有价值的词语了。现在我们就可以正式对函数进行构造:

get_sim = function(string){
  string %>% 
    segment(jiebar = wk) %>% 
    enframe() %>% 
    transmute(words = value) -> string_table
  
  for_future_use %>% 
    inner_join(string_table,by = "words") %>% 
    group_by(id) %>% 
    summarise(score = sum(tf_idf)) %>% 
    arrange(desc(score)) -> sort_table
  
  sort_table %>% 
    slice(1:3) %>% 
    inner_join(raw,by = "id") -> result
  
  ifelse(nrow(result) == 0,
         NA,
         result %>% 
           pull(title) %>%
           str_c(collapse = ","))
}

这个函数能够对任意的字符串进行识别,如果没有任何识别,就返回NA;如果识别到了,最多返回匹配度最高的3个分类,分类之间以“,”分隔(注意是英文的逗号,这个可以根据自己的洗好更改)。我们用两个例子看看结果如何:

get_sim("稀奇古怪")
[1] NA

get_sim("大数据")
[1] "大数据研究院,大数据学院,大数据试验场研究院(筹)"

显然,这个函数是有效的。

编辑于 04-29

标签:文本,string,分类,TF,words,IDF,table,自然语言,id
来源: https://www.cnblogs.com/purple5252/p/14957456.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有