1.Python实现新词发现算法
代码基于jupyter notebook
导库
import re
import sys
import math
测试语料
text=['这个程序用来实现新词发现功能','运行完新词发现程序后会得到几个指标','这些指标包括凝固度、左邻熵和右邻熵','依靠计算的几个指标(凝固度、左邻熵和右邻熵),可以发现新词','在做新词发现前,要对语料进行清洗','比如去除字符串里面的字母或数字,像abc、123这种','完']
字符串正则清洗
#字符串正则清洗
def re_filter(line):
#去除所有非中文汉字、给定标点符号的字符(先保留标点符号,减少一些词错误邻词的出现,包含给定标点符号的词后面会再过滤掉)
re_comp=re.compile(r'[^-—_,,、/()().。::;;??!!\u4e00-\u9fa5]')
line=re_comp.sub('',line)
return line
筛选句子长度>=2的
#筛选句子长度>=2的
text=[re_filter(line) for line in text if len(re_filter(line))>=2]
text
切词
#切词,切分后词的长度范围:[min_w_len,max_w_len],max_w_len表示ngrams最长片段字数
def word_split(line,min_w_len,max_w_len):
w_len=len(line)
result=[]
for l in range(min_w_len,max_w_len+1): #j:切词长度:min_w_len-max_w_len
for i in range(w_len-l,-1,-1):
result.append((line[i:i+l],1))
#返回(word,1)
return result
计算词频
#计算词频,此处ngrams不建议对词长度或词频做筛选,可能会影响凝固度的计算(凝固度会取组成词的各片段的词频)
from collections import defaultdict
ngrams = defaultdict(int)
min_w_len=1
max_w_len=5
words=[word_split(line,1,5) for line in text]
len(words)
#对列表解除嵌套
words=[item for ls in words for item in ls]
len(words)
words
for item in words:
if not re.search(r'[-—_,,、/()().。::;;??!!]',item[0]): #去除包含带给定标点符号的词汇
ngrams[item[0]] += 1 #返回{word,词频}
len(ngrams)
ngrams
计算词总数
#词总数(用于计算凝固度使用)
total=sum([ngrams[key] for key in ngrams])*1.0
total
获取候选词
#候选词:选长度在2-4的作为最终输出候选词
freq_filter=2 #要保留的最小词频
candi_ngrams={key:ngrams[key] for key in ngrams if len(key)>=2 and len(key)<=4 and ngrams[key]>=freq_filter}
len(candi_ngrams)
candi_ngrams
计算凝固度
#计算凝固度
def coagulation_degree(ngram,ngram_freq): #ngram:词 ngram_freq:词频
ngram_len=len(ngram) #词的长度
coagulation=min([ (ngram_freq*total) / (ngrams[ngram[:i+1]]*ngrams[ngram[i+1:]]) for i in range(ngram_len-1)])
return (ngram,coagulation)
#计算每个候选词的凝固度
coagulation_ngram=[coagulation_degree(ngram,candi_ngrams[ngram]) for ngram in candi_ngrams]
len(coagulation_ngram)
coagulation_ngram
计算熵
#计算熵
def entropy(ngram,entropy_rl_dict):
word=ngram #词
neighbours=entropy_rl_dict[ngram] #所有不同右邻字出现的频次组成的列表
neighbours_sum=sum(neighbours) #所有不同右邻字出现的频次之和
prob=map(lambda x:float(x)/neighbours_sum,neighbours) #每个右邻字出现频率/所有右邻字出现的频次之和
entropy=sum(map(lambda x:-(x)*math.log(x),prob))
return (word,entropy)
右邻熵
#计算右邻熵
candi_ngrams_keys=set(candi_ngrams.keys()) #所有候选词
#每个候选词的每个右邻字出现的频次,返回(候选词,其某个右邻字出现的频次)
entropy_r=[(key[0:-1],ngrams[key]) for key in ngrams if len(key)>=3 and key[0:-1] in candi_ngrams_keys]
entropy_r
#返回{word,所有不同右邻字出现的频次组成的列表}
entropy_r_dict = defaultdict(list)
for item in entropy_r:
entropy_r_dict[item[0]].append(item[1])
entropy_r_dict
#计算候选词的右邻熵
entropy_right=[entropy(ngram,entropy_r_dict) for ngram in entropy_r_dict]
entropy_right
左邻熵
#计算左邻熵
#每个候选词的每个左邻字出现的频次,返回(候选词,其某个左邻字出现的频次)
entropy_l=[(key[1:],ngrams[key]) for key in ngrams if len(key)>=3 and key[1:] in candi_ngrams_keys]
entropy_l
#返回{word,所有不同左邻字出现的频次组成的列表}
entropy_l_dict = defaultdict(list)
for item in entropy_l:
entropy_l_dict[item[0]].append(item[1])
entropy_l_dict
#计算候选词的左邻熵
entropy_left=[entropy(ngram,entropy_l_dict) for ngram in entropy_l_dict]
entropy_left
2.Pyspark实现新词发现算法
TBD…