分割其实包含了分词、断句等等,分词对于中文文本是十分重要的。本章我也只关注分词,当然本章最后介绍的分词方法过去简单,仅供参考。
1. 分割, 按照01组成的序列对字符串进行拆分
def segment(text, segs): # 利用01数据将 str切分开
words = []
last = 0
for i in range(len(segs)): # 循环找到1所在的位置
if segs[i] == '1':
words.append(text[last:i+1]) # 把两个1之间的字母放一起
last = i+1
words.append(text[last:])
return words
text = "doyouseethekittyseethedoggydoyoulikethekittylikethedoggy"
seg1 = "0000000000000001000000000010000000000000000100000000000"
segment(text, seg1)
结果如下 ['doyouseethekitty', 'seethedoggy', 'doyoulikethekitty', 'likethedoggy']
2. 评价,分词既不能分的过细又不能太粗
def evaluate(text, segs): # 评价切分的好坏
words = segment(text, segs)
text_size = len(words) # 切出的词有多少个,保证分词不会太细
lexicon_size = len(' '.join(list(set(words)))) # 切出非重复词的长度,注意这里是长度不是个数,保证切出的词不会太粗,文章前后能切出相同的词
return text_size + lexicon_size # 数值越小越好,简单理解就是一篇文章被切出的词应该前后统一,但是词又不能切的太细。
text = "doyouseethekittyseethedoggydoyoulikethekittylikethedoggy"
seg1 = "0000000000000001000000000010000000000000000100000000000"
evaluate(text, seg1)
结果是63
3. 寻找最优分词方法
本方法真的是随机试出来的,程序跑n次能有m种分词结果。可以发现核心内容就是根据当前温度n 随机在01序列上互换n个位置的01,然后评价本次随机改动是不是比现有最好的分词方法要好。
from random import randint
def anneal(text, segs, iterations, cooling_rate):
temperature = float(len(segs))
while temperature > 0.5: # 退火算法,程序随着运行温度原来越低,低到0.5以下就结束循环
best_segs, best = segs, evaluate(text, segs) # 先存一个暂时最优分词结果
for i in range(iterations): # 开始循环
guess = flip_n(segs, int(round(temperature))) # 利用随机算法猜测一个分词方法,真的是猜,完全的随机的猜。请注意每一次猜测的变动原来越小。
score = evaluate(text, guess) # 评估以下猜测结果
if score < best: # 如果猜的比暂时最优的要好,保存本次结果
best, best_segs = score, guess
score, segs = best, best_segs
temperature = temperature / cooling_rate # 退火的速度
print (evaluate(text, segs), segment(text, segs)) #打印最优结果
return segs
def flip_n(segs, n): # segs上随机选n个位置进行01互换,n会随着热度
for i in range(n):
segs = flip(segs, randint(0,len(segs)-1))
return segs
def flip(segs, pos): # 将segs的某一个位置上的01互换
return segs[:pos] + str(1-int(segs[pos])) + segs[pos+1:]
text = "doyouseethekittyseethedoggydoyoulikethekittylikethedoggy"
seg1 = "0000000000000001000000000010000000000000000100000000000"
anneal(text, seg1, 5000, 1.2)
结果如下,结果是随机的。后面我会专门整理几个中文分词的方法,供大家参考。