看一个博主(亚当-adam)的关于hanlp关键词提取算法TextRank的文章,还是非常好的一篇实操经验分享,分享一下给各位需要的朋友一起学习一下!

TextRank是在Google的PageRank算法启发下,针对文本里的句子设计的权重算法,目标是自动摘要。它利用投票的原理,让每一个单词给它的邻居(术语称窗口)投赞成票,票的权重取决于自己的票数。这是一个“先有鸡还是先有蛋”的悖论,PageRank采用矩阵迭代收敛的方式解决了这个悖论。本博文通过hanlp关键词提取的一个Demo,并通过图解的方式来讲解TextRank的算法。

1//长句子

2       String content = "程序员(英文Programmer)是从事程序开发、维护的专业人员。" +

3                "一般将程序员分为程序设计人员和程序编码人员," +

4                "但两者的界限并不非常清楚,特别是在中国。" +

5                "软件从业人员分为初级程序员、高级程序员、系统" +

6                "分析员和项目经理四大类。";

最后提取的关键词是:[程序员, 程序, 分为, 人员, 软件]

  下面来分析为什么会提取出这5个关键词

第一步:分词

  把content 通过一个的分词算法进行分词,这里采用的是Viterbi算法也就是HMM算法。分词后(当然首先应把停用词、标点、副词之类的去除)的结果是:

  

[程序员, 英文, Programmer, 从事, 程序, 开发, 维护, 专业, 人员, 程序员, 分为, 程序, 设计, 人员, 程序, 编码, 人员, 界限, 并不, 非常, 清楚, 特别是在, 中国, 软件, 从业人员, 分为, 程序员, 高级, 程序员, 系统分析员, 项目经理, 四大]

第二步:构造窗口

  hanlp的实现代码如下:

  

Map<String, Set<String>> words = new TreeMap<String, Set<String>>();

Queue<String> que = new LinkedList<String>();

for (String w : wordList)

{

if (!words.containsKey(w))

{

words.put(w, new TreeSet<String>());

}

// 复杂度O(n-1)

if (que.size() >= 5)

{

que.poll();

}

for (String qWord : que)

{

if (w.equals(qWord))

{

continue;

}

//既然是邻居,那么关系是相互的,遍历一遍即可

words.get(w).add(qWord);

words.get(qWord).add(w);

}

que.offer(w);

}

  这个代码的功能是为分个词构造窗口,这个词前后各四个词就是这个词的窗口,如词分词后一个词出现了多次,像[程序员],那就是把每次出现取一次窗口,然后把各次结果合并去重,最后结果是:程序员=[Programmer, 专业, 中国, 人员, 从业人员, 从事, 分为, 四大, 开发, 程序, 系统分析员, 维护, 英文, 设计, 软件, 项目经理, 高级]。最后形成的窗口:

  

1 Map<String, Set<String>> words =

2

3 {Programmer=[从事, 开发, 程序, 程序员, 维护, 英文], 专业=[人员, 从事, 分为, 开发, 程序, 程序员, 维护], 中国=[从业人员, 分为, 并不, 清楚, 特别是在, 程序员, 软件, 非常], 人员=[专业, 分为, 并不, 开发, 清楚, 界限, 程序, 程序员, 维护, 编码, 设计, 非常], 从业人员=[中国, 分为, 清楚, 特别是在, 程序员, 软件, 高级], 从事=[Programmer, 专业, 开发, 程序, 程序员, 维护, 英文], 分为=[专业, 中国, 人员, 从业人员, 特别是在, 程序, 程序员, 系统分析员, 维护, 设计, 软件, 高级], 四大=[程序员, 系统分析员, 项目经理, 高级], 并不=[中国, 人员, 清楚, 特别是在, 界限, 程序, 编码, 非常], 开发=[Programmer, 专业, 人员, 从事, 程序, 程序员, 维护, 英文], 清楚=[中国, 人员, 从业人员, 并不, 特别是在, 界限, 软件, 非常], 特别是在=[中国, 从业人员, 分为, 并不, 清楚, 界限, 软件, 非常], 界限=[人员, 并不, 清楚, 特别是在, 程序, 编码, 非常], 程序=[Programmer, 专业, 人员, 从事, 分为, 并不, 开发, 界限, 程序员, 维护, 编码, 英文, 设计], 程序员=[Programmer, 专业, 中国, 人员, 从业人员, 从事, 分为, 四大, 开发, 程序, 系统分析员, 维护, 英文, 设计, 软件, 项目经理, 高级], 系统分析员=[分为, 四大, 程序员, 项目经理, 高级], 维护=[Programmer, 专业, 人员, 从事, 分为, 开发, 程序, 程序员], 编码=[人员, 并不, 界限, 程序, 设计, 非常], 英文=[Programmer, 从事, 开发, 程序, 程序员], 设计=[人员, 分为, 程序, 程序员, 编码], 软件=[中国, 从业人员, 分为, 清楚, 特别是在, 程序员, 非常, 高级], 非常=[中国, 人员, 并不, 清楚, 特别是在, 界限, 编码, 软件], 项目经理=[四大, 程序员, 系统分析员, 高级], 高级=[从业人员, 分为, 四大, 程序员, 系统分析员, 软件, 项目经理]}

第三步:迭代投票

  每个词最后的投票得分由这个词的窗口进行多次迭代投票决定,迭代的结束条件就是大于最大迭代次数这里是200次,或者两轮之前某个词的权重小于某一值这里是0.001f。看下代码:

  

Map<String, Float> score = new HashMap<String, Float>();

//依据TF来设置初值

for (Map.Entry<String, Set<String>> entry : words.entrySet()){

score.put(entry.getKey(),sigMoid(entry.getValue().size()));

}

System.out.println(score);

for (int i = 0; i < max_iter; ++i)

{

Map<String, Float> m = new HashMap<String, Float>();

float max_diff = 0;

for (Map.Entry<String, Set<String>> entry : words.entrySet())

{

String key = entry.getKey();

Set<String> value = entry.getValue();

m.put(key, 1 - d);

for (String element : value)

{

int size = words.get(element).size();

if (key.equals(element) || size == 0) continue;

m.put(key, m.get(key) + d / size * (score.get(element) == null ? 0 : score.get(element)));

}

max_diff = Math.max(max_diff, Math.abs(m.get(key) - (score.get(key) == null ? 0 : score.get(key))));

}

score = m;

if (max_diff <= min_diff) break;

}

System.out.println(score);

return score;

}

  投票的原理拿Programmer=[从事, 开发, 程序, 程序员, 维护, 英文],这个词来说明,Programmer最后的得分是由[从事, 开发, 程序, 程序员, 维护, 英文],这6个词依次投票决定的,每个词投出去的分数是和他本身的权重相关的。

  

1、投票开始前每个词初始化了一个权重,score.put(entry.getKey(),sigMoid(entry.getValue().size())),这个权重是0到1之间,公式是

1 //value是每个词窗口的大小

2    public static float sigMoid(float value) {

3        return (float)(1d/(1d+Math.exp(-value)));

4    }

这个函数的公式和图像如下,因为value一定是大于0的,所以sigMod值属于(0,1)

初始化后的分词是:{特别是在=0.99966466, 程序员=0.99999994, 编码=0.99752736, 四大=0.98201376, 英文=0.9933072, 非常=0.99966466, 界限=0.99908894, 系统分析员=0.9933072, 从业人员=0.99908894, 程序=0.99999774, 专业=0.99908894, 项目经理=0.98201376, 设计=0.9933072, 从事=0.99908894, Programmer=0.99752736, 软件=0.99966466, 人员=0.99999386, 清楚=0.99966466, 中国=0.99966466, 开发=0.99966466, 并不=0.99966466, 高级=0.99908894, 分为=0.99999386, 维护=0.99966466}

  进行迭代投票,第一轮投票,[Programmer, 专业, 中国, 人员, 从业人员, 从事, 分为, 四大, 开发, 程序, 系统分析员, 维护, 英文, 设计, 软件, 项目经理, 高级]依给次*程序员*投票,得分如下:

  

  [Programmer]给[程序员]投票后,[]程序员]的得分:

[专业]给[程序员]投票

这样[Programmer, 专业, 中国, 人员, 从业人员, 从事, 分为, 四大, 开发, 程序, 系统分析员, 维护, 英文, 设计, 软件, 项目经理, 高级]依次给[程序员]投票,投完票后,再给其它的词进行投票,本轮结束后,判断是否达到最大迭代次数200或两轮之间分数差值小于0.001,如果满足则结束,否则继续进行迭代。

 最后的投票得分是:{特别是在=1.0015739, 程序员=2.0620303, 编码=0.78676623, 四大=0.6312981, 英文=0.6835063, 非常=1.0018439, 界限=0.88890904, 系统分析员=0.74232763, 从业人员=0.8993066, 程序=1.554001, 专业=0.88107216, 项目经理=0.6312981, 设计=0.6702926, 从事=0.9027207, Programmer=0.7930236, 软件=1.0078223, 人员=1.4288887, 清楚=0.9998723, 中国=0.99726284, 开发=1.0065585, 并不=0.9968608, 高级=0.9673803, 分为=1.4548829, 维护=0.9946941},分数最高的关键词就是要提取的关键词

自然语言处理工具hanlp关键词提取图解TextRank算法的更多相关文章

  1. Python中调用自然语言处理工具HanLP手记

    手记实用系列文章: 1 结巴分词和自然语言处理HanLP处理手记 2 Python中文语料批量预处理手记 3 自然语言处理手记 4 Python中调用自然语言处理工具HanLP手记 5 Python中 ...

  2. HanLP 关键词提取算法分析

    HanLP 关键词提取算法分析 参考论文:<TextRank: Bringing Order into Texts> TextRank算法提取关键词的Java实现 TextRank算法自动 ...

  3. HanLP 关键词提取算法分析详解

    HanLP 关键词提取算法分析详解 l 参考论文:<TextRank: Bringing Order into Texts> l TextRank算法提取关键词的Java实现 l Text ...

  4. 中文自然语言处理工具HanLP源码包的下载使用记录

    中文自然语言处理工具HanLP源码包的下载使用记录 这篇文章主要分享的是hanlp自然语言处理源码的下载,数据集的下载,以及将让源代码中的demo能够跑通.Hanlp安装包的下载以及安装其实之前就已经 ...

  5. 自然语言处理工具hanlp自定义词汇添加图解

    过程分析 1.添加新词需要确定无缓存文件,否则无法使用成功,因为词典会优先加载缓存文件 2.再确认缓存文件不在时,打开本地词典按照格式添加自定义词汇. 3.调用分词函数重新生成缓存文件,这时会报一个找 ...

  6. 自然语言处理工具hanlp 1.7.3版本更新内容一览

    HanLP 1.7.3 发布了.HanLP 是由一系列模型与算法组成的 Java 工具包,目标是普及自然语言处理在生产环境中的应用.HanLP 具备功能完善.性能高效.架构清晰.语料时新.可自定义的特 ...

  7. 中文自然语言处理工具hanlp隐马角色标注详解

    本文旨在介绍如何利用HanLP训练分词模型,包括语料格式.语料预处理.训练接口.输出格式等. 目前HanLP内置的训练接口是针对一阶HMM-NGram设计的,另外附带了通用的语料加载工具,可以通过少量 ...

  8. 自然语言处理工具HanLP被收录中国大数据产业发展的创新技术新书《数据之翼》

    在12月20日由中国电子信息产业发展研究院主办的2018中国软件大会上,大快搜索获评“2018中国大数据基础软件领域领军企业”,并成功入选中国数字化转型TOP100服务商. 图:大快搜索获评“2018 ...

  9. 自然语言分析工具Hanlp依存文法分析python使用总结(附带依存关系英文简写的中文解释)

    最近在做一个应用依存文法分析来提取文本中各种关系的词语的任务.例如:text=‘新中国在马克思的思想和恩格斯的理论阔步向前’: 我需要提取这个text中的并列的两个关系,从文中分析可知,“马克思的思想 ...

随机推荐

  1. python day 16作业

    day18天作业及默写1,完成下列功能: 1.1创建一个人类Person,再类中创建3个静态变量(静态字段) animal = '高级动物' soup = '有灵魂' language = '语言' ...

  2. swift简单处理调用高清大图导致内存暴涨的情况

    开发中,通常需要用到使用选取多张图片的功能,但是高清大图很吃内存,我想到的处理方案就是拿到高清大图的时候,重新绘制一张小的图片使用.至于清晰度尚可,至少我是分辨不出多大区别. 基本思路就是先固定宽,然 ...

  3. react-navigation实现页面框架(转载)

    初始化一个RN项目 react-native init page_framework page.json { "name": "page_framework", ...

  4. kafka definitive guide - reading notes

    一.认识Kafka 1)什么是sub/pub模型, 发布订阅模型   Publish/subscribe messaging is a pattern that is characterized by ...

  5. PHP中PSR-[0-4]规范(转)

    PHP中PSR-[0-4]规范 更好排版:https://www.zybuluo.com/phper/note/65033 PHP是世界上最伟大的语言,这一点是毋庸置疑的吧.哈哈哈哈哈哈 .这个霸气的 ...

  6. linux shell 中文件编码查看及转换方法

    参考: http://edyfox.codecarver.org/html/vim_fileencodings_detection.html 一.查看文件编码.     在打开文件的时候输入:set ...

  7. openssl:AES CBC PKCS5 加解密 (C/GOLANG)

    #include <openssl/aes.h> /* AES_CBC_PKCS5_Encrypt * 入参: * src:明文 * srcLen:明文长度 * key:密钥 长度只能是1 ...

  8. Unity 3D第三人称视角、用途广泛限定角度(视角不能360度翻转)

    Unity第三人称相机视角控制 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分 ...

  9. 数据类型int、float、str、list、dict、set定义及常用方法汇总

    数据类型int:记录整数事物状态 可变不可变:值不可变类型,改变变量值实则是改变了变量的指向 int():功能:1.工厂函数, i = 5 <==> i = int(5) 2.强制类型转换 ...

  10. java exception 01

    问题:java.util.concurrentmodificationexception 背景:java thread 网上找到的出现的例子如下(项目中真实的code不便给出) public clas ...