无监督识别词语算法的Python实现
作者:邓旭东HIT
前几天写了《 简单的中文分词算法 》,今天就用Python写个 伪分词算法实现。
说 伪分词是因为我这脚本其实并不能对文本进行分词,只是计算两个汉字组合成词的概率(由于是无监督,前期没有人工介入,识别词的能力大大降低。)。 比如 ‘中’、’过’、’国’三个字的组成的字对有
‘中过’、’中国’、’过国’、’国过’、’国中’、’过中’,这六个 字对中,很容易就看到只有 中国这个 字对是能成词,其余都不是词。但是如果给你100个、1000个字,你怎么知道其中的能成词的字对呢。所以这里就要用统计学,统计语料中各个字对的概率,一般概率大者的 字对 有很大可能性是一个词。
代码实现
一、初始化
import
reclass
Bayes
(
object
):
def
__init__
(
self
,
corpus
):
#将语料只保留中文字符
self._corpus = ''.join(re.findall(r'[\u4E00-\u9FD5]+',corpus)) #语料文本长度
self._corpusLen = len(self._corpus) #将语料切分为单字列表
self._ziList = [zi for zi in self._corpus] #去重后的中文字集
self._ziSet = set(self._ziList) #用于储存中文字及其出现在语料中的概率
self._ziFreq = dict() #用于储存字在语料中的位置
self._ziIndex = dict() #{zi1:[index1,...], zi2:[index1...]...}
#用于储存语料中"字对"及 "字对的概率" self._pair = dict() #形如{(zi1,zi2):weight,...}
二、中文字集中每个字及其频率
def Set(self): corpus_len = self._corpusLen zi_list = self._ziList zi_set = self._ziSet for zi in zi_set: zi_freq = zi_list.count(zi) self._ziFreq[zi]=zi_freq/corpus_len
三、每个汉字在语料中出现的位置
def generate_index(self): for index,zi in enumerate(self._corpus):
if zi in self._ziIndex.keys(): self._ziIndex[zi].append(index) else:
self._ziIndex[zi]=[] self._ziIndex[zi].append(index)
四、字对出现的个数
def generate_pair(self): #计算每个字对出现次数
for zi,indexList in self._ziIndex.items(): for index in indexList: if 1<= index <=self._corpusLen-2:
b_zi = self._corpus[index-1] a_zi = self._corpus[index+1] if (b_zi, zi) in self._pair.keys():
self._pair[(b_zi, zi)]+=1 else: self._pair[(b_zi, zi)]=1
if (zi, a_zi) in self._pair.keys(): self._pair[(zi, a_zi)]+=1 else:
self._pair[(zi, a_zi)]=1
五、每个字对出现的频率
def pair_gailv(self): #计算每个"字对"在语料中出现的频率
count = 0 for value in self._pair.values(): count=count+value for k,v in self._pair.items(): self._pair[k]=v/count
五、语料中所有字对及概率从大到小输出
def
output
(
self
):
self
.
Set
()
self
.
generate_index
()
self
.
generate_pair
()
self
.
pair_gailv
()
#对结果按照概率由大到小排序
self._pair = sorted(self._pair.items(), key=lambda x: x[1], reverse=True) data = ['%s%s %.20f' % (k[0], k[1], v) for k, v in self._pair] return data
测试
我下载了本小说《重生之2006》(额,追了快一年了)当做中文语料(其实这也太随意了,真实情况的语料可能都得上G)。在这里顺便测试下运行时间。
import timedef test(input,output,encode): start = time.time() text = open(input,'r',encoding=encode).read()
bayes = Bayes(text) bayes.Set() data = bayes.output() f = open(output, 'w', encoding='utf-8') for word in data:
f.write(word+'\n') f.close() end = time.time() duration = end-start print(duration)input = r'/Users/suosuo/Downloads/重生之2006.txt'output = r'/Users/suosuo/Downloads/词频结果.txt'
test(input,output,encode='gbk')
运行时间 352.6866388320923s. 输出的词频结果(由大到小),截图是前25个词。
小说的主角名叫 陆恒,主角女友 林素,主角开创的集团公司名 恒成,都出现在前25个词里,似乎效果很好。
但打开词频结果.txt中间看,似乎就相当不准了。看来只能选取词频结果的较为靠前的部分的词才算靠谱词。其余的都无法靠谱的成词
End.
转载请注明来自36大数据(36dsj.com): 36大数据 » 无监督识别词语算法的Python实现