算法:N-gram语法

一、N-gram介绍

  n元语法(英语:N-gram)指文本中连续出现的n个语词。n元语法模型是基于(n - 1)阶马尔可夫链的一种概率语言模型,通过n个语词出现的概率来推断语句的结构。这一模型被广泛应用于概率论通信理论计算语言学(如基于统计的自然语言处理NLP)、计算生物学(如序列分析)、数据压缩等领域。

  N-gram文本广泛用于文本挖掘自然语言处理任务。它们基本上是给定窗口内的一组同时出现的单词,在计算n元语法时,通常会将一个单词向前移动(尽管在更高级的场景中可以使X个单词向前移动)。

  例如,对于句子"The cow jumps over the moon" N = 2(称为二元组),则 ngram 为:

  • the cow
  • cow jumps
  • jumps over
  • over the
  • the moon

  因此,在这种情况下,有 5 个 n-gram。

  再来看看 N = 3,ngram 将为:

  • the cow jumps
  • cow jumps over
  • jumps over the
  • over the moon

  因此,在这种情况下,有 4 个 n-gram。

  所以,在一个句子中 N-grams 的数量有:

      Ngrams(K) = X - (N - 1)

  其中,X 为给定句子K中的单词数,N 为 N-gram 的N,指的是连续出现的 N 个单词。

  N-gram用于各种不同的任务。例如,在开发语言模型时,N-grams不仅用于开发unigram模型,而且还用于开发bigram和trigram模型。谷歌和微软已经开发了网络规模的 n-gram模型,可用于多种任务,例如拼写校正分词文本摘要N-gram的另一个用途是为受监督的机器学习模型(例如SVMMaxEnt模型朴素贝叶斯等)开发功能。其想法是在特征空间使用标记(例如双字母组),而不是仅使用字母组合。

  下面简单介绍一下如何用 Java 生成 n-gram。

二、用 Java 生成 n-gram

  这个是生成 n-gram 的主要方法,方法首先是对传进来的句子 sentence 进行单词拆分,这个正则表达式“\\s+”是能匹配任何空白字符,包括空格、制表符、换页符等等, 等价于 [ \f\n\r\t\v]。拆分完后对单词进行拼接算法时间复杂度为 O(X - (N - 1)),X 为给定句子K中的单词数,N 为 N-gram 的 N。

 1     /**
 2      * 生成n元语法
 3      * <p>
 4      * 一个句子中有多少个N-gram?
 5      * 如果 X = 给定句子K中的单词数,则句子K的 N-gram数为:
 6      * N(grams<K>) = X - (N - 1)
 7      *
 8      * @param n        连续 n个单词
 9      * @param sentence 句子级别的文本
10      * @return         存着ngram的列表
11      */
12     public static List<String> ngrams(int n, String sentence) {
13         List<String> ngrams = new ArrayList<>();
14         String[] words = sentence.split("\\s+");
15         for (int i = 0; i < words.length - n + 1; i++)
16             ngrams.add(concat(words, i, i + n));
17         return ngrams;
18     }

  进行单词拼接,这里使用 StringBuilder线程不安全,效率相对StringBuffer高点)对拆分好的单词进行拼接并返回拼接好的字符串。

 1     /**
 2      * 拼接单词
 3      *
 4      * @param words 单词
 5      * @param start 开始位置
 6      * @param end   结束位置
 7      * @return      拼接好的字符串
 8      */
 9     public static String concat(String[] words, int start, int end) {
10         StringBuilder sb = new StringBuilder();
11         for (int i = start; i < end; i++)
12             sb.append(i > start ? " " : "").append(words[i]);
13         return sb.toString();
14     }

  对 n-gram 的出现次数进行统计,使用 HashMap<String, Integer> 来存储 n-gram 的出现次数并且按照 value 的逆序排序 Map,次数较多的在前面先打印。这里使用 Java 8 Stream API 按照 value 降序顺序进行 Map 排序。

  在 Java 8 中,Map.Entry具有静态方法 comparingByValue() 来帮助按 value 排序,此方法返回以自然顺序 Comparator 比较 Map.Entry值的。还有,你可以传递自定义Comparator 以用于排序。

  下面是根据 value 进行排序的方法:

 1     /**
 2      * 按 value对 HashMap进行逆序排序
 3      * <p>
 4      * 使用 Java 8 Stream API按照降序对Value进行Map排序
 5      * 逻辑的中心是按自然顺序 Map.Entry.comparingByValue()比较 Map.Entry值的方法。
 6      *
 7      * @param unSortedMap 未排序的HashMap
 8      * @return 按照value降序排序的HashMap
 9      */
10     public static HashMap<String, Integer> sortByValue(HashMap<String, Integer> unSortedMap) {
11         // System.out.println("Unsorted Map : " + unSortedMap);
12
13         // LinkedHashMap保留插入元素的顺序
14         LinkedHashMap<String, Integer> reverseSortedMap = new LinkedHashMap<>();
15
16         // 使用 Comparator.reverseOrder() 进行反向排序
17         unSortedMap.entrySet()
18                 .stream()
19                 .sorted(Map.Entry.comparingByValue(Comparator.reverseOrder()))
20                 .forEachOrdered(x -> reverseSortedMap.put(x.getKey(), x.getValue()));
21
22         // System.out.println("Reverse Sorted Map   : " + reverseSortedMap);
23
24         return reverseSortedMap;
25     }

  主函数测试代码:

 1 public static void main(String[] args) {
 2         HashMap<String, Integer> count = new HashMap<>();
 3         String text = "I can go to the supermarket to buy spicy bars or go to the store to buy spicy bars.";
 4
 5         // 生成n为1~3的N元语法
 6 //        for (int n = 1; n <= 3; n++) {
 7 //            for (String ngram : ngrams(n, text)) {
 8 //                System.out.println(ngram);
 9 //            }
10 //            System.out.println();
11 //        }
12
13         for (String ngram : ngrams(3, text)) {
14             // counting ngram by using HashMap
15             if (!count.containsKey(ngram)) {
16                 count.put(ngram, 1);
17             } else if (count.containsKey(ngram)) {
18                 count.replace(ngram, count.get(ngram) + 1);
19             }
20             System.out.println(ngram);
21         }
22
23         // 按出现次由多到少的顺序打印ngram
24         System.out.println("\nCounting Result: ");
25         for (Map.Entry<String, Integer> entry : sortByValue(count).entrySet()) {
26             System.out.println(entry.getKey() + ": " + entry.getValue());
27         }
28
29     }

原文地址:https://www.cnblogs.com/magic-sea/p/12181108.html

时间: 2024-11-05 22:44:38

算法:N-gram语法的相关文章

javacc-LOOKAHEAD MiniTutorial 翻译

本文翻译自\javacc-5.0\doc\lookahead.html章节. 上文:http://blog.csdn.net/chaofanwei/article/details/25541065 1.LOOKAHEAD是什么 lookahead就是当语法分析器从词法分析器里取token时,需要取多少个才能让分析器正确的走下去. 例一 void Input() : {} { "a" BC() "c" } void BC() : {} { "b"

《软件测试方法和技术》 读书笔记

<软件测试方法和技术> 读书笔记 2014-07-17 第一章 引论  1.3 什么是软件测试  1.4 软件测试与软件开发的关系第二章 软件测试基本概念  2.1 软件缺陷  2.3 软件测试的分类  2.4 测试阶段  2.5 软件测试的工作范畴第三章 软件测试方法  黑盒测试    边界值测试    等价测试      报表日期      三角形    基于决策表的测试      NextDate函数  白盒测试    语句覆盖    判定覆盖    条件覆盖    判定条件覆盖   

浅谈自然语言处理基础(下)

命名实体识别 命名实体的提出源自信息抽取问题,即从报章等非结构化文本中抽取关于公司活动和国防相关活动的结构化信息,而人名.地名.组织机构名.时间和数字表达式结构化信息的关键内容,所以需要从文本中去识别这些实体指称及其类别,即命名实体识别和分类. 21世纪以后,基于大规模语料库的统计方法成为自然语言处理的主流,以下是基于统计模型的命名实体识别方法归纳: 基于CRF的命名实体识别方法 基于CRF的命名实体识别方法简便易行,而且可以获得较好的性能,广泛地应用于人名.地名和组织机构等各种类型命名实体的识

软件测试方法和技术

第一章 引论  1.3 什么是软件测试  1.4 软件测试与软件开发的关系第二章 软件测试基本概念  2.1 软件缺陷  2.3 软件测试的分类  2.4 测试阶段  2.5 软件测试的工作范畴第三章 软件测试方法  黑盒测试    边界值测试    等价测试      报表日期      三角形    基于决策表的测试      NextDate函数  白盒测试    语句覆盖    判定覆盖    条件覆盖    判定条件覆盖    条件组合覆盖    路径覆盖    基本路径测试     

Python资料&amp; 个人日常总结 _20151220

后期有时间再排版. 后面越来越乱了.没时间整理分类 不嫌麻烦 就打开链接试试吧. 这是我之前为同学准备的,也是我从入门以来搜集的资源 适合以Python为第一个语言来学习编程的同学. 下面这个重要,可以先看看.再往下看.或者通览一遍 有没有你需要的. --> 编程入门指南 v1.4 http://zhuanlan.zhihu.com/xiao-jing-mo/19959253 ???????????? 写给 编程入门者 : __更新关于 0编程者接触Python的知乎讨论 https://www

J2EE开发实战基础系列之开卷有益

时隔七年再次接触培训有关的事情,是兴奋,更多的是恐惧,不知该如何下手. 本系列针对有Java语法基础的开发者或者爱好者,从工作开发角度出发讲解,不同于其他视频,一切皆以实用为主,过程中如有疑问,请提问于我,回答将发布在教程中添加提问部分,提问者越多,教程覆盖越全面,以实际问题为主. ----------------------------------------------------------------------------------------- 首先介绍下目前J2EE方面培训的入门

软件测试重点

文章1章  软件测试概述 什么是软件测试 ü  广义的概念:它指的是整个软件生命周期的检查.审查和验证,其中包含分析.设计阶段,毕开发后维护阶段的各类文档.代码的审查和确认 ü  狭义概念:识别软件缺陷的过程,即实际结果与预期结果的不一致 ü  软件測试通常包含验证(verification)和确认(validation): -    验证指保证软件正确的实现了某一特定功能的一系列活动 -    确认指的是保证软件的实现满足了用户需求的一系列活动 软件測试的目的 ü  測试的目的就是发现软件中的

山东大学软件质量保证与测试技术复习纲要

软件质量保证与测试技术复习提纲 1.3  1.5   2.1 2.3 2.5 2.6   3.3(3.3.1    扩展) 3.4 3.7.3  FSM   状态图 状态表   5.1 5.7.1 5.7.2   8.1.1 8.1.5   9.1 9.6 3.3.1    扩展 某研究所重新对其在大学以上学历的职工安排工作.其方针如下:"如果年龄不满18岁,文化程度是大学,若是男性,则一律要求考研究生.若是女性,则分配到研究所办公室任行政干部:如果年龄满18岁但不足50岁,文化程度是研究生,不

这个文件必看啊 太好了

数学问题: 1.精度计算——大数阶乘 2.精度计算——乘法(大数乘小数) 3.精度计算——乘法(大数乘大数) 4.精度计算——加法 5.精度计算——减法 6.任意进制转换 7.最大公约数.最小公倍数 8.组合序列 9.快速傅立叶变换(FFT) 10.Ronberg算法计算积分 11.行列式计算 12.求排列组合数 13.求某一天星期几 字符串处理: 1.字符串替换 2.字符串查找 3.字符串截取 4.LCS—最大公共子串长度 5.LCS-生成最大公共子串 6.数字转化为字符 计算几何: 1.叉乘