ansj构造最短路径

一、前言

上节介绍了ansj的原子切分和全切分。切分完成之后,就要构建最短路径,得到分词结果。

以“商品和服务”为例,调用ansj的标准分词:

String str = "商品和服务" ;
Result result = ToAnalysis.parse(str);
System.out.println(result.getTerms());

先不管数字发现、人名识别、用户自定义词典的识别,暂时只考虑ToAnalysis类里面,构建最短路径的这行代码:

graph.walkPath();

上面这行代码执行前,已完成了全切分,构建了如下的有向无环图:

事实上,此时没有“务”这个节点

如上图所示,terms[4] = null。

不过这也没关系,后面给节点打分时,会填充这个null,这段代码位于Graph.merger(Term fromTerm, int to, Map<String, Double> relationMap):

char c = chars[to];
TermNatures tn = DATDictionary.getItem(c).termNatures;
if (tn == null || tn == TermNatures.NULL) {
tn = TermNatures.NULL;
}
terms[to] = new Term(String.valueOf(c), to, tn);

也就是说,给“和服”的后继节点打分时,发现其后继节点为null,那么就实例化一个Term,填充在terms[to]的位置。

二、理论基础

两个节点之间分之计算的代码位于MathUtil.compuScore(Term from, Term to, Map<String, Double> relationMap)

其中核心代码只有一行:

double value = -Math.log(dSmoothingPara * frequency / (MAX_FREQUENCE + 80000) + (1 - dSmoothingPara) * ((1 - dTemp) * nTwoWordsFreq / frequency + dTemp));

我们了探讨一下这行代码的理论基础。

首先,ansj使用二元语法模型(Bigram)进行分词。Bigram模型对应于一阶Markov假设,词只与其前面一个词相关,其对应的分词模型:

三、具体打分流程如下

代码位于Graph.walkPath(Map<String, Double> relationMap)。

Ansj采用了类似于Dijkstra的动态规划算法(作者称之为Viterbi算法)来求解最短路径。

如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点,那么(Vi...Vk)也必定是从i到k的最短路径。(可参考Dijkstra算法

1、从起始节点“始##始”开始,对其后继节点打分

设置“商”、“商品”的前驱节点(也就是Term类的from属性)为“始##始”。

2、计算“商”后继节点的分值

只有一个后继节点“品”。“商”和“品”的分值是13.509,因此从“始##始”到“品”的分值是19.56。

设置“品”的前驱节点为“商”。

3、计算“商品”后继节点分值

设置“和”、“和服”的前驱节点为“商品”。

4、计算“品”后继节点分值

以“和”为例,“和”有“商品”、“品”两个前驱节点。应该取分值最小的那个。因此,“和”的分值依然是8.92,前驱节点依然是“商品”。

同理,“和服”的前驱节点依然是“商品”。

对上图进行简化:

5、计算“和”后继节点分值

设置“服”、“服务”的前驱节点为“和”。

6、计算“和服”后继节点分值

设置“务”的前驱节点为“和服”。

对上图简化:

7、计算“服”后继节点分值

“务”以“服”为前驱,可以得到更小的分值。因此,更改“务”的前驱节点为“服”。

对上图简化:

8、计算“服务”后继节点分值

设置“末##末”的前驱节点为“服务”。

9、计算“务”后继节点分值

“末##末”以“服务”为前驱节点,分值更新。因此,“末##末”的前驱节点依然是“服务”。

对上图简化:

10、设置后继节点

目前已构建了最短路径,并且知道了每个节点的前驱节点。

例如,“末##末”的前驱节点是“服务”。但是并没有将“服务”的后继节点(也就是Term类的to属性)设置为“末##末”。

Graph.optimalRoot()就是设置后继节点的。执行完该方法后,terms被简化为了如下形式:

去掉null,就是分词结果了。

时间: 2024-10-18 04:23:53

ansj构造最短路径的相关文章

OSPF(开放最短路径优先)

OSPF依据的根本概念是一种称为链路状态数据库(LSDB)的数据结构.AS中的每台路由器均维护该数据库的一个副本,到一个网络或另一台路由器的每条链路载数据库中都表示为一条记录. LSDB:可以将LSDB看作一个数据集合,该集合等价于一张表示AS拓扑的表. OSPF的两种拓扑:基本拓扑.层次拓扑 1.基本拓扑:当只存在少量路由器时,把整个AS作为一个单独的实体来管理. AS中的所有路由器均作为对等方来工作.每台路由器都与其他所有路由器交流选路信息,每台路由器都维护关键的OSPF数据结构LSDB 的

关于Floyd-Warshall算法由前趋矩阵计算出的最短路径反映出了算法的执行过程特性的证明

引言:Floyd-Warshall算法作为经典的动态规划算法,能够在O(n3)复杂度之内计算出所有点对之间的最短路径,且由于其常数较小,对于中等规模数据运行效率依然可观.算法共使用n此迭代,n为顶点个数.其中第k次迭代计算出每对顶点之间所有中间结点小于等于k的最短路径长度,其中i到j的最短路径要么是经过k的一条路径,这条路径的由k所分割出的两个路径i → k.k → j是中间路径小于等于k-1的最短路径:要么是从i到j的中间路径小于等于k-1的最短路径.定义dij(k)为从i到j的最短路径长度,

cocos2d-js版本A*算法

[转]http://blog.csdn.net/realcrazysun1/article/details/43054229 A*算法的东西网上讲了很多~但还是不可避免的要去研究一下,cocos官网上有一个cocos2dx版本的A星算法(cocos2d-x A星算法),正好拿来改造一下,顺便踩踩cocos2d-js的坑 原理和伪代码部分可以参考这个(A*算法伪代码)废话不多说,直接上正题. 主要有2个封装原型类: 1.GameLayer:负责加载地图.保持地图跟随.坐标转换.地图上物品判断.接受

【编程马拉松】【016-过年回家】

[编程马拉松算法目录] [016-过年回家][工程下载>>>] 1 题目描述 NowCoder今年买了一辆新车,他决定自己开车回家过年.回家过程中要经过n个大小收费站,每个收费站的费用不同, 你能帮他计算一下最少需要给多少过路费吗? 1.1 输入描述: 输入包含多组数据,每组数据第一行包含两个正整数m(1≤m≤500)和n(1≤n≤30),其中n表示有n个收费站, 编号依次为1.2.-.n.出发地的编号为0,终点的编号为n,即需要从0到n. 紧接着m行,每行包含三个整数f.t.c,(0≤

LeetCode--064--最小路径和

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例: 输入:[  [1,3,1], [1,5,1], [4,2,1]]输出: 7解释: 因为路径 1→3→1→1→1 的总和最小. 思路:dp思想,为每个点构造最短路径矩阵,每次看左边和上边的最短路径,最小的那个加上该位置的值,就是到达该位置的最短路径. 由于是两层for,时间复杂度比较高 1 class Solution: 2 def minPath

Dijkstra算法求单源最短路径

1.最短路径 在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同.如果是一个带权图,那么路径长度为路径上各边的权值的总和.两个顶点间路径长度最短的那条路径称为两个顶点间的最短路径,其路径长度称为最短路径长度. 最短路径在实际中有重要的应用价值.如用顶点表示城市,边表示两城市之间的道路,边上的权值表示两城市之间的距离.那么城市A到城市B连通的情况下,哪条路径距离最短呢,这样的问题可以归结为最短路径问题. 求最短路径常见的算法有Dijkstra算法和Floyd算法

最短路径之弗洛伊德算法(Floyd)

Floyd算法又称为插点法,是一种用于寻找给定的加权图中多源点之间最短路径的算法. 路径矩阵 通过一个图的权值矩阵求出它的每两点间的最短路径矩阵. 从图的带权邻接矩阵A=[a(i,j)] n×n开始,递归的进行n次更新,即由矩阵D(0)=A,按一个公式,构造出矩阵D(1): 又用同样地公式由D(1)构造出D(2):--:最后又用同样的公式由D(n-1)构造出矩阵D(n).矩阵D(n) 的 i 行 j 列元素便是 i 号顶点到 j 号顶点的最短路径长度,称D(n)为图的距离矩阵,同时还可引入一个后

“中兴捧月”比赛之——二叉查找树(BST)树的最短路径Java求解

问题描述: BST树,又称二叉查找树,求其到所有叶子节点路径的最小值 测试用例一:  10 5 20 返回15: 测试用例二: 100 20 70 110 120 10 null null 89 null null null null 返回130: 程序代码实现: 1 package examination.written; 2 3 /** 4 * 5 * @author ZhuXY 6 * @time 2016-6-12 下午9:57:53 7 * 8 */ 9 public class BS

最短路径算法-Dijkstra算法的应用之单词转换(词梯问题)

一,问题描述 在英文单词表中,有一些单词非常相似,它们可以通过只变换一个字符而得到另一个单词.比如:hive-->five:wine-->line:line-->nine:nine-->mine..... 那么,就存在这样一个问题:给定一个单词作为起始单词(相当于图的源点),给定另一个单词作为终点,求从起点单词经过的最少变换(每次变换只会变换一个字符),变成终点单词. 这个问题,其实就是最短路径问题. 由于最短路径问题中,求解源点到终点的最短路径与求解源点到图中所有顶点的最短路径复