一、Word Segmentation(分词)
1、分词工具
- Jieba分词: https://github.com/fxsjy/jieba
- SnowNLP: https://github.com/isnowfy/snownlp
- LTP: http://www.ltp-cloud.com/
- HanNLP: https://github.com/hankcs/HanLP/
- PKUseg
2、分词算法
任何分词算法都是基于已有词典库来对一句话进行分词
2.1 前向最大匹配(forward-max matching)
缺点:不能考虑语义
2.2 后向最大匹配(backward-max matching)
前向最大匹配与后向最大匹配 90%的几率分出来的结果一样
缺点:不能考虑语义
2.3 最大匹配&考虑语义
将所有通过最大匹配算法生成的所有分词组合方式通过“语言模型”来计算概率,概率越大的分词方式越好
- 第一步:生成所有分词结果
- 第二步:通过语言模型选择最好的分词结果
缺点:时间复杂度高,因为分词的组合太多了
2.4 维特比算法(Viterbi Algorithm)
维特比算法(Viterbi Algorithm)本质上还是动态规划(Dynamic Programming)
计算最短路径
二、Spell Correction(拼写纠错)
1、编辑距离(edit distance)
基于动态规划
编辑距离可以用来计算两个字符串的相似度,它的应用场景很多,其中之一是拼写纠正(spell correction)。 编辑距离的定义是给定两个字符串str1和str2, 我们要计算通过最少多少代价cost可以把str1转换成str2.
举个例子:
输入: str1 = “geek”, str2 = “gesek”
输出: 1
插入 's’即可以把str1转换成str2
输入: str1 = “cat”, str2 = “cut”
输出: 1
用u去替换a即可以得到str2
输入: str1 = “sunday”, str2 = “saturday”
输出: 3
我们假定有三个不同的操作: 1. 插入新的字符 2. 替换字符 3. 删除一个字符。 每一个操作的代价为1.
# 基于动态规划的解法
def edit_dist(str1, str2):
# m,n分别字符串str1和str2的长度
m, n = len(str1), len(str2)
# 构建二维数组来存储子问题(sub-problem)的答案
dp = [[0 for x in range(n+1)] for x in range(m+1)]
# 利用动态规划算法,填充数组
for i in range(m+1):
for j in range(n+1):
# 假设第一个字符串为空,则转换的代价为j (j次的插入)
if i == 0:
dp[i][j] = j
# 同样的,假设第二个字符串为空,则转换的代价为i (i次的插入)
elif j == 0:
dp[i][j] = i
# 如果最后一个字符相等,就不会产生代价
elif str1[i-1] == str2[j-1]:
dp[i][j] = dp[i-1][j-1]
# 如果最后一个字符不一样,则考虑多种可能性,并且选择其中最小的值
else:
dp[i][j] = 1 + min(dp[i][j-1], # Insert
dp[i-1][j], # Remove
dp[i-1][j-1]) # Replace
return dp[m][n]
三、Stop words Removal
对于NLP的应用,通常先把停用词、出现频率很低的词汇过滤掉
类似于特征筛选的过程
有成熟的工具:NLTK停用词库
四、Stemming(单词的标准化)
有成熟的工具
https://tartarus.org/martin/PorterStemmer/java.txt
五、Sentence Similarity(句子相似度)
1、欧式距离
2、余弦相似度
参考资料:
中文分词引擎 java 实现 — 正向最大、逆向最大、双向最大匹配法
Spelling Correction and the Noisy Channel