自然语言处理工具hanlp关键词提取图解TextRank算法

2023-06-04 0 754

看两个写手(丹尼尔-adam)的有关hanlp关键字抽取演算法TextRank的该文,却是十分好的一则Jalgaon实战经验撷取,撷取呵呵给诸位须要的好友一同自学呵呵!

自然语言处理工具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> words = new TreeMap>();

        Queueque = new LinkedList();

        for (String w : wordList)

        {

if (!words.containsKey(w))

            {

                words.put(w, new TreeSet());

            }

            // 复杂度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> words =

2

3 {Programmer=[专门从事, 开发, 流程, 开发相关人员, 保护, 英语], 专精=[相关人员, 专门从事, 分成, 开发, 流程, 开发相关人员, 保护], 中国=[从业相关人员, 分成, 并不, 确切, 的的, 开发相关人员, 软件, 十分], 相关人员=[专精, 分成, 并不, 开发, 确切, 界线, 流程, 开发相关人员, 保护, 代码, 结构设计, 十分], 从业相关人员=[中国, 分成, 确切, 的的, 开发相关人员, 软件, 高阶], 专门从事=[Programmer, 专精, 开发, 流程, 开发相关人员, 保护, 英语], 分成=[专精, 中国, 相关人员, 从业相关人员, 的的, 流程, 开发相关人员, 名词表, 保护, 结构设计, 软件, 高阶], 五大=[开发相关人员, 名词表, 部门经理, 高阶], 并不=[中国, 相关人员, 确切, 的的, 界线, 流程, 代码, 十分], 开发=[Programmer, 专精, 相关人员, 专门从事, 流程, 开发相关人员, 保护, 英语], 确切=[中国, 相关人员, 从业相关人员, 并不, 的的, 界线, 软件, 十分], 的的=[中国, 从业相关人员, 分成, 并不, 确切, 界线, 软件, 十分], 界线=[相关人员, 并不, 确切, 的的, 流程, 代码, 十分], 流程=[Programmer, 专精, 相关人员, 专门从事, 分成, 并不, 开发, 界线, 开发相关人员, 保护, 代码, 英语, 结构设计], 开发相关人员=[Programmer, 专精, 中国, 相关人员, 从业相关人员, 专门从事, 分成, 五大, 开发, 流程, 名词表, 保护, 英语, 结构设计, 软件, 部门经理, 高阶], 名词表=[分成, 五大, 开发相关人员, 部门经理, 高阶], 保护=[Programmer, 专精, 相关人员, 专门从事, 分成, 开发, 流程, 开发相关人员], 代码=[相关人员, 并不, 界线, 流程, 结构设计, 十分], 英语=[Programmer, 专门从事, 开发, 流程, 开发相关人员], 结构设计=[相关人员, 分成, 流程, 开发相关人员, 代码], 软件=[中国, 从业相关人员, 分成, 清楚, 的的, 开发相关人员, 十分, 高阶], 十分=[中国, 相关人员, 并不, 确切, 的的, 界线, 代码, 软件], 部门经理=[五大, 开发相关人员, 名词表, 高阶], 高阶=[从业相关人员, 分为, 五大, 开发相关人员, 名词表, 软件, 部门经理]}

第三步:插值投票表决

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

Mapscore = new HashMap();

        //依据TF来设置初值

for (Map.Entry> entry : words.entrySet()){

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

        }

        System.out.println(score);

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

        {

            Mapm = new HashMap();

            float max_diff = 0;

for (Map.Entry> entry : words.entrySet())

            {

                String key = entry.getKey();

                Setvalue = 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)

自然语言处理工具hanlp关键词提取图解TextRank算法

初始化后的分词是:{的的=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]给[开发相关人员]投票表决后,[]开发相关人员]的得分:

自然语言处理工具hanlp关键词提取图解TextRank算法

[专精]给[开发相关人员]投票表决

自然语言处理工具hanlp关键词提取图解TextRank算法

这样[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},分数最高的关键字就是要抽取的关键字

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务