原理指路這。
直接上實驗過程。
1、199801人民日報語料
這是已經分詞而且詞性標記好的,我們用來獲取裏面的詞,作爲後續自己分詞的底表。
2、生成底表
# 匹配詞性
def cixing(data):
dic = {}
for line in data: # 匹配普通詞性標註
pattern = re.findall(r'/[A-Za-z]{1,30}', line)
for p in pattern:
if p in dic:
dic[p] += 1
else:
dic[p] = 1
for line in data: # 匹配實體詞性標註,如[江 峽 大道]ns
pattern2 = re.findall(r'][A-Za-z]{1,30}', line)
for p in pattern2:
#print(p)
if p in dic:
dic[p] += 1
else:
dic[p] = 1
print(dic)
print(len(dic))
return dic
# 去除詞性標註
def restore(dic, data):
raw_data=[]
final=[]
for line in data:
#print(line) 這裏其實可以對字典排序一下 但是我懶得改了
line=line.strip(' ').replace('[','')
for i in dic.keys():
if len(i)>=3:
line = line.replace(i,'') # 防止部分詞性前綴相似導致的錯誤匹配
raw_data.append(line)
for l in raw_data:
for i in dic.keys():
l = l.replace(i,'').strip(' ')
final.append(l)
#print(final)
return final
# 統計詞彙
def wordlist(data):
wordlist={}
for line in data:
line=line.split(' ')
for word in line:
if word in wordlist.keys():
wordlist[word] += 1
else:
wordlist[word] = 1
#wordlist.pop('')
print(wordlist)
return wordlist
def write_excel(path,dic):
workbook = xlsxwriter.Workbook(path)
worksheet = workbook.add_worksheet('sheet1')
worksheet.write(0, 0, '詞彙')
worksheet.write(0, 1, '頻次')
for k, i in zip(range(len(dic)), dic.keys()):
j = dic[i]
#print(i, j)
worksheet.write(k+1, 0, i)
worksheet.write(k+1, 1, j)
workbook.close()
形成下面形式的一個詞表,我還統計了一下頻次。
3、正向和逆向最大匹配算法實現
最大步長我設置爲5,一般都是設置爲5。
# 逆向最大匹配分詞
def segword(data):
wordlis= sorted(wordlexicon, key=lambda i: len(i), reverse=True) # 按長度大小排序
#print(wordlis)
re=[]
for i in range(len(data)):
s1 = data[i]
#print(s1)
s2 = ''
maxlen = 5
w = s1[-maxlen:] # 逆向
while (w):
if len(w) != 1:
if w in wordlis:
s2 = w + ' ' + s2
n=len(s1)-len(w)
s1 = s1[0:n]
w = s1[-maxlen:]
#print(s2,s1)
else:
w = w[1:len(w)]
#print(w)
else:
s2 = w + ' ' + s2
n = len(s1) - len(w)
s1 = s1[0:n]
w = s1[-maxlen:]
#print(s2, s1)
re.append(s2)
print(re)
return re
# 正向最大匹配分詞
def segword_2(data):
wordlis= sorted(wordlexicon, key=lambda i: len(i), reverse=True) # 按長度大小排序
# print(wordlis)
re=[]
for i in range(len(data)):
s1 = data[i]
#print(s1)
s2 = ''
maxlen = 5
w = s1[:maxlen] # 逆向
#print(w)
while (w):
if len(w) != 1:
if w in wordlis:
s2 = s2 + w+ ' '
s1 = s1[len(w):]
w = s1[:maxlen]
#print(s2,s1)
else:
w = w[:len(w)-1]
#print(w)
else:
s2 = s2 + w + ' '
s1 = s1[len(w):]
w = s1[:maxlen]
#print(s2, s1)
re.append(s2)
print(re)
return re
4、實踐
我選了一篇新聞,用作待分詞文本。
逆向結果:
正向結果:
5、評估
從處理速度、總體詞數、分詞粒度、以及未登錄詞等各方面都可以進行評估比較正向和逆向分詞的效果。
一般來說,總體詞數越少越好,在相同字數的情況下,總詞數越少,說明語義單元越少,那麼相對的單個語義單元的權重會越大,因此準確性會越高。
一般又說,分詞的顆粒度越大,即單字詞的數量越少,所能表示的含義越確切,比如對於“公安局長”可以分爲“公安 局長”、“公安局 長”、“公安局長”都算對,但是要用於語義分析,則“公安局長”的分詞結果最好。
下面是一個簡單實現計算單字的程序。
# 單字
def word(data):
sum=0
for word in data.keys():
if len(word)==1:
sum+=1
return sum
# 非詞典單字
def non_word(data):
num=0
for word in data.keys():
if len(word)==1 and word not in wordlist:
num+=1
return num
完整代碼見