text rank java 实现_使用TextRank实现的关键字提取

本文介绍了如何使用TextRank算法在Java中实现关键字提取。通过构建初始转置矩阵,迭代运算计算PageRank值,最终确定文本的关键字。示例代码展示了分词、矩阵处理和迭代过程。
摘要由CSDN通过智能技术生成

本文主要用于实现使用TextRank算法的关键字提取

TextRank是PageRank算法的变种,用于文本关键字 关键句的提取

主要参考为原作者Rada Mihalcea论文《TextRank:Bring Order into texts》

整个算法步骤:

【1】文本分词

可以使用常见的java分词,本例使用的是IKAnalyer

【2】词性标注

这个暂时没有实现 【只是对提取效果会有一定的影响 一般会选择名次和动词作为关键字】 不影响算法思想实现

【3】构建初始转置矩阵【图的一种表示方式】

我们以文本对象中的每一个独立文本分词作为一个顶点,采用邻接矩阵来表示文本之间的关联,比如:

“A B C D”

"B C A"

"A CA

B

C

D

A

0

0

0

0

B

1

0

0

0

C

1

1

0

0

D

0

0

1

0

(不知道怎么搞的 这表格删除不了多余 请无视)

words=【A,B,C,D】整个文档的单词数(去重复)

(每个单元格的含义:M[i,j]代表从j->i有指向 意即单词words[j] 后面有单词words[i])

假设上面为3段待提取的文字,分词以空格形式切分,那么我们可以得到下面的一个矩阵M

对上面的矩阵稍作处理 使 每一列的值结果如下:[有点像单元化处理m[i][j]=m[i][j]/(sum[0-N][j])

A

B

C

D

A

0

0

0

0

B

1/2

0

0

0

C

1/2

1

0

0

D

0

0

1

0

具体实现:部分源码

/**

* 传入经过分词处理后的wordsWrapper对象

*matrix[i][j]代表从j->i有指向 现在为未带权处理

* @param wordsWrapper

* @return 返回生成的double矩阵

*/

public static double[][] listToGraph(WordsWrapper wordsWrapper) {

int wordCount = wordsWrapper.wordcount;

List nodulWords = Arrays.asList(wordsWrapper.nodulWords);

double[][] a = new double[wordCount][wordCount];

ArrayList content = wordsWrapper.words;

for (String x : content) {

String xs[] = x.split(" ");

int curindex = -1, preindex = -1, nextindex = -1;

for (int i = 0; i < xs.length; i++) {

String tx = xs[i];

int index = nodulWords.indexOf(tx);

if (i != 0) {

preindex = nodulWords.indexOf(xs[i - 1]);

}

if (preindex != -1) {

a[index][preindex] = 1d;

}

}

}

//just for test

// System.out.println("before ...");

//~~~test end here

//初始矩阵处理

for (int j = 0; j < wordCount; j++) {

//这里可以修正 为带权值的

int nozero = 0;

for (int i = 0; i < wordCount; i++) {

if (a[i][j] != 0) {

nozero++;

}

}

if (nozero != 0) {

for (int i = 0; i < wordCount; i++) {

a[i][j] = a[i][j] / nozero;

}

}

}

return a;

}

【4】迭代运算

采用最大迭代次数和误差控制判断是否要求迭代

关于每个单词的PR(PageRank)值计算,在论文总是得分计算公式:

1365595161_6339.JPG

其中各个参数含义:

S(Vi)--顶点i的得分 可以理解为单词i的PR值

d-----阻尼系数 默认为;0.85

In(Vi)---所有指向顶点i的顶点 【比如:单词A 面跟着单词B 那么A属于In(B)】

|Out(Vj)|---节点j的出度【与图算法中的出度意义一样 上面的是入度】

具体实现:【最大迭代次数(20)和 最大容错率由自己指定(0.000001)】

/**

* 判断是否需要下一次pagerank迭代 会进行精度计算和总的迭代次数考虑

*

* @param before 之前迭代结果 PR值

* @param cur当前迭代结果 PR值

* @param curIteration 已经迭代次数

* @return 是否需要下一次迭代

*/

public static boolean neededDoNext(double[] before, double[] cur, int curIteration) {

//先检查迭代次数是否已经超过最大迭代次数

if (curIteration > MAX_ITERATE_NUM) {

return false;

} else {

//精度要求

int n = before.length;

for (int i = 0; i < n; i++) {

if (Math.abs(cur[i] - before[i]) > DEFAULT_ERROR_RATE) {

return true;

}

}

System.out.println("All is ok???");

outputArray(before);

outputArray(cur);

//所有都满足精度要求

return false;

}

}

迭代计算处理核心:

double []prevPR//记录前一次的算出来的pr值 初始值设置为全0

double []curPR//记录当前算出的PR值 初始值设定为全1/wordCount;

while (neededDoNext(prevPR, curPR, iterationCount)) {

//计算下一次迭代

prevPR=curPR;

curPR = doPageRank(transMatrix,prevPR,outDegrees);

System.out.println("当前迭代次数:"+iterationCount+"RESULT:");

outputArray(curPR);

iterationCount++;

}

效果演示:

总共迭代次数为:21

word->d score->0.4023749808259771

word->b score->0.3210029191796684

word->c score->0.5938468678121206

word->a score->0.4023749808259771

可以看出本文的关键字应该是C 注意pagerank可能不会收敛 所以设置最大迭代次数

【5】后处理

提供将临近的关键字 结合起来形成新的关键字【未完成】

【6】写在最后

由于看的是英文的论文 可能有的理解有失偏颇 有的地方理解的不到位还望指教,

还有如果使用带权图可以获得更好的计算效果【论文中有叙述】实现起来也就是修改PR[i] 或者score的计算,原理是一样的

关于如何确定文本单词词性的问题 暂时还没有头绪

TextRank是一种用于文本关键词提取和摘要生成的算法,它基于图的排序算法PageRank,可以很好地解决文本中关键词和摘要的提取问题。 以下是一个简单的Java实现: ```java import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class TextRank { private static final int MAX_ITERATIONS = 100; private static final double DAMPING_FACTOR = 0.85; private static final double CONVERGENCE_THRESHOLD = 0.0001; public static List<String> extractKeywords(String text, int numKeywords) { String[] sentences = text.split("[\\.\\?\\!\\n]"); List<List<String>> wordsInSentences = new ArrayList<>(); Set<String> wordSet = new HashSet<>(); for (String sentence : sentences) { List<String> words = new ArrayList<>(); for (String word : sentence.split("\\s+")) { if (word.matches("\\w+")) { words.add(word.toLowerCase()); wordSet.add(word.toLowerCase()); } } wordsInSentences.add(words); } Map<String, Integer> wordFreq = new HashMap<>(); for (String word : wordSet) { int freq = 0; for (List<String> words : wordsInSentences) { if (words.contains(word)) { freq++; } } wordFreq.put(word, freq); } Map<String, List<String>> wordAdjacencyList = new HashMap<>(); for (String word1 : wordSet) { List<String> adjList = new ArrayList<>(); for (String word2 : wordSet) { if (!word1.equals(word2)) { for (List<String> words : wordsInSentences) { if (words.contains(word1) && words.contains(word2)) { adjList.add(word2); break; } } } } wordAdjacencyList.put(word1, adjList); } Map<String, Double> wordScores = new HashMap<>(); for (String word : wordSet) { wordScores.put(word, 1.0); } for (int i = 0; i < MAX_ITERATIONS; i++) { Map<String, Double> newWordScores = new HashMap<>(); double maxDiff = 0; for (String word : wordSet) { double newScore = (1 - DAMPING_FACTOR) + DAMPING_FACTOR * score(word, wordAdjacencyList, wordScores, wordFreq); double diff = Math.abs(newScore - wordScores.get(word)); maxDiff = Math.max(maxDiff, diff); newWordScores.put(word, newScore); } wordScores = newWordScores; if (maxDiff < CONVERGENCE_THRESHOLD) { break; } } List<String> keywords = new ArrayList<>(wordSet); keywords.sort((w1, w2) -> Double.compare(wordScores.get(w2), wordScores.get(w1))); return keywords.subList(0, numKeywords); } private static double score(String word, Map<String, List<String>> wordAdjacencyList, Map<String, Double> wordScores, Map<String, Integer> wordFreq) { double score = 0; for (String adjWord : wordAdjacencyList.get(word)) { double weight = 1.0 / wordAdjacencyList.get(adjWord).size(); score += weight * wordScores.get(adjWord) / wordFreq.get(adjWord); } return score; } } ``` 该实现将输入文本分割成句子,然后将每个句子分割成单词,并构建单词之间的邻接表。接下来,它使用PageRank对单词进行排序,并返回前N个单词作为关键字。 请注意,这个实现是非常简单的,并且可能不够健壮,但它可以帮助你了解TextRank算法的基本思想和实现方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值