关于文本摘要的介绍网上有很多资料,大家可以搜一搜。本文主要是针对单文档文本摘要的抽取方法,使用java实现。主要方法是基于两篇文献:
1.
(这里引用阮一峰的博客介绍http://www.ruanyifeng.com/blog/2013/03/automatic_summarization.html。)H.P. Luhn在1958年的论文《The Automatic Creation of Literature Abstracts》。
Luhn博士认为,文章的信息都包含在句子中,有些句子包含的信息多,有些句子包含的信息少。"自动摘要"就是要找出那些包含信息最多的句子。
句子的信息量用"关键词"来衡量。如果包含的关键词越多,就说明这个句子越重要。Luhn提出用"簇"(cluster)表示关键词的聚集。所谓"簇"就是包含多个关键词的句子片段。
上图就是Luhn原始论文的插图,被框起来的部分就是一个"簇"。只要关键词之间的距离小于"门槛值",它们就被认为处于同一个簇之中。Luhn建议的门槛值是4或5。也就是说,如果两个关键词之间有5个以上的其他词,就可以把这两个关键词分在两个簇。
下一步,对于每个簇,都计算它的重要性分值。
以前图为例,其中的簇一共有7个词,其中4个是关键词。因此,它的重要性分值等于 ( 4 x 4 ) / 7 = 2.3。
然后,找出包含分值最高的簇的句子(比如5句),把它们合在一起,就构成了这篇文章的自动摘要。
2.
利用最大边缘相关模型(Maximal Marginal Relevance)提高返回句子的多样性。因为使用以上方法通常会得到一些太相似或太相近的句子,为了避免这种情况,结合MMR来增加内容的多样性。这种方法是权衡相关性和多样性。使得摘要内容更加的全面。MMR方法可以较好地解决句子选择多样性的问题。具体地说,在MMR模型中,同时将相关性和多样性进行衡量。因此,可以方便的调节相关性和多样性的权重来满足偏向“需要相似的内容”或者偏向“需要不同方面的内容”的要求。摘要的核心便是要从原文句子中选一个句子集合,使得该集合在相关性与多样性的评测标准下,得分最高。具体的资料介绍可以看https://github.com/jiangnanboy/NewsSummary有一篇英文介绍。
Di: Documents in the collection C
Q: Query,
R: Relevant documents in C,
S: Current result set
- Constructs the result set incrementally
- User-tunable diversity through λ parameter
- High λ = Higher accuracy
- Low λ = Higher diversity
以上公式中是针对搜索引擎中的查询与文档的关系,这里我们稍作改变:
max[λ*score(i) - (1-λ)*max[similarity(i,j)]]:score(i)根据1中计算句子的得分,similarity(i,j)句子i与j的相似度
MMR程序java程序(完整程序https://github.com/jiangnanboy/NewsSummary)
1 /** 2 * 最大边缘相关(Maximal Marginal Relevance),根据λ调节准确性和多样性 3 * max[λ*score(i) - (1-λ)*max[similarity(i,j)]]:score(i)句子的得分,similarity(i,j)句子i与j的相似度 4 * User-tunable diversity through λ parameter 5 * - High λ= Higher accuracy 6 * - Low λ= Higher diversity 7 * @param sortedSentList 排好序的句子,编号及得分 8 * @return 9 */ 10 private Map<Integer,Double> MMR(List<Map.Entry<Integer, Double>> sortedSentList){ 11 //System.out.println("MMR In..."); 12 double[][] simSentArray=sentJSimilarity();//所有句子的相似度 13 Map<Integer,Double> sortedLinkedSent=new LinkedHashMap<Integer,Double>(); 14 for(Map.Entry<Integer, Double> entry:sortedSentList){ 15 sortedLinkedSent.put(entry.getKey(),entry.getValue()); 16 } 17 Map<Integer,Double> MMR_SentScore=new LinkedHashMap<Integer,Double>();//最终的得分(句子编号与得分) 18 Map.Entry<Integer, Double> Entry=sortedSentList.get(0);//第一步先将最高分的句子加入 19 MMR_SentScore.put(Entry.getKey(), Entry.getValue()); 20 boolean flag=true; 21 while(flag){ 22 int index=0; 23 double maxScore=Double.NEGATIVE_INFINITY;//通过迭代计算获得最高分句子 24 for(Map.Entry<Integer, Double> entry:sortedLinkedSent.entrySet()){ 25 if(MMR_SentScore.containsKey(entry.getKey())) continue; 26 double simSentence=0.0; 27 for(Map.Entry<Integer, Double> MMREntry:MMR_SentScore.entrySet()){//这个是获得最相似的那个句子的最大相似值 28 double simSen=0.0; 29 if(entry.getKey()>MMREntry.getKey()) 30 simSen=simSentArray[MMREntry.getKey()][entry.getKey()]; 31 else 32 simSen=simSentArray[entry.getKey()][MMREntry.getKey()]; 33 if(simSen>simSentence){ 34 simSentence=simSen; 35 } 36 } 37 simSentence=λ*entry.getValue()-(1-λ)*simSentence; 38 if(simSentence>maxScore){ 39 maxScore=simSentence; 40 index=entry.getKey();//句子编号 41 } 42 } 43 MMR_SentScore.put(index, maxScore); 44 if(MMR_SentScore.size()==sortedLinkedSent.size()) 45 flag=false; 46 } 47 return MMR_SentScore; 48 }