一、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 }

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

  1. acm算法模板(2)

    数学问题: 1.精度计算——大数阶乘 2.精度计算——乘法(大数乘小数) 3.精度计算——乘法(大数乘大数) 4.精度计算——加法 5.精度计算——减法 6.任意进制转换 7.最大公约数.最小公倍数 ...

  2. Lua学习系列(二)

    资源整理: 风云老师博客: http://blog.codingnow.com/eo/luaoeeeaeau/ 知乎: https://www.zhihu.com/question/20736660 ...

  3. STL 小白学习(1) 初步认识

    #include <iostream> using namespace std; #include <vector> //动态数组 #include <algorithm ...

  4. 学习笔记之机器学习实战 (Machine Learning in Action)

    机器学习实战 (豆瓣) https://book.douban.com/subject/24703171/ 机器学习是人工智能研究领域中一个极其重要的研究方向,在现今的大数据时代背景下,捕获数据并从中 ...

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

    2014.10.24[致歉]{抱歉,从7.4号接到朋友的请求,一直忙到现在,最近又有新的CASE要忙,很抱歉教程要延误,开课时间请大家关注Q群} 时隔七年再次接触培训有关的事情,是兴奋,更多的是恐惧, ...

  6. boost开发指南

    C++确实很复杂,神一样的0x不知道能否使C++变得纯粹和干爽? boost很复杂,感觉某些地方有过度设计和太过于就事论事的嫌疑,对实际开发工作的考虑太过于理想化.学习boost本身就是一个复杂度,有 ...

  7. 2019年10月13日 spss习题 wangqingchao

    1.spss发行版本的说法,正确的是:B a.两年发行一个新版本    b.一年发行一个新版本 c.没有任何规律   d.三年发行一个新版本 2.哪些是spss统计分析软件的基本窗口:A a.结果查看 ...

  8. SPSS数据分析基础考题

    选择题 1. SPSS发行版本的说法,正确的是: B A. 两年发行一个新版本 B.一年发行一个新版本 C.没有任何规律 D.三年发行三个新版本 2.哪些是SPSS统计分析软件的基本窗口: A A.结 ...

  9. 关于一些JS的运算符

    首先呢,什么是JavaScript:JavaScript是一种脚本语言,也是一种解释型语言,更是一种由数据值决定变量类型的弱类型语言 JavaScript主要由三部分组成 ECMAScript  这个 ...

随机推荐

  1. 测试平台系列(55) 引入AceEditor(代码编辑器)

    大家好,我是米洛,求三连!求关注测试开发坑货! 回顾 我们上一节已经写好了左侧数据表目录,今天继续完成sql编辑器的部分. 调研组件 monaco 因为我们的项目用的是React,市面上很多编辑器都是 ...

  2. Jwt的新手入门教程

    Jwt的新手入门教程 1.Jwt究竟是什么东东? ​ 先贴官网地址:JSON Web Tokens - jwt.io ​ ​ 再贴官方的定义: What is JSON Web Token? JSON ...

  3. PHP的CLI命令行运行模式浅析

    在做开发的时候,我们不仅仅只是做各种网站或者接口,也经常需要写一些命令行脚本用来处理一些后端的事务.比如对数据进行处理统计等.当然也是为了效率着想,当一个事务有可能会有较长的耗时时,往往会交由服务器的 ...

  4. Jmeter系列(12)- 上传接口压测

    step-1上传接口分析 上传接口源码分析:分析上传文件类型.有无大小限制.存放上传文件服务器 没有源码通过抓包工具,或者Chrome查看框架源代码 接口路径/uploadfile,接口请求POST, ...

  5. 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽 | 百篇博客分析OpenHarmony源码 | v28.03

    百篇博客系列篇.本篇为: v28.xx 鸿蒙内核源码分析(进程通讯篇) | 九种进程间通讯方式速揽 | 51.c.h .o 进程通讯相关篇为: v26.xx 鸿蒙内核源码分析(自旋锁篇) | 自旋锁当 ...

  6. Wannafly挑战赛10F-小H和遗迹【Trie,树状数组】

    正题 题目链接:https://ac.nowcoder.com/acm/contest/72/F 题目大意 \(n\)个字符串,包括小写字母和\(\#\).其中\(\#\)可以替换为任意字符串.求有多 ...

  7. Loj#3026-「ROIR 2018 Day1」管道监控【Trie,费用流】

    正题 题目链接:https://loj.ac/p/3026 题目大意 给出\(n\)个点的一棵外向树,然后\(m\)个字符串和费用表示你每次可以花费这个费用覆盖路径字符串和给出字符串相等的路径,求覆盖 ...

  8. 从0到1告诉你搭建完整Python+requests接口自动化测试框架!

    前言 很多小伙伴不知道什么是框架?框架有哪些东西? 一步步从需求分析到报告生成告诉你如何搭自动化建框架. 学完unittest后这里基本上可以搭建一个简易的项目框架了,我们可以用一条run_main. ...

  9. 势流理论笔记:03 Hess-Smith积分方法

    书接上回势流理论笔记:02 直接法与间接法 Hess-Smith方法 采用面向对象编程的思路,\(Matlab\)程序脚本,实现以下功能: 输入面元(四边形面元顶点坐标) 输出系数矩阵\([H][M] ...

  10. 理解ASP.NET Core - 配置(Configuration)

    注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 配置提供程序 在.NET中,配置是通过多种配置提供程序来提供的,包括以下几种: 文件配置提供程 ...