基於信息熵的分詞及新詞發現(三)基於天龍八部小說的新詞發現

算法原理在一、二部分:

一、基於信息熵的分詞及新詞發現(一) 信息熵的理解

二、基於信息熵的分詞及新詞發現(二)統計學意義下的詞語構成

代碼流程如下:

1、讀取天龍八部小說文檔,並轉換爲Series 數據結構。Series是一個一維數組,是基於NumPy的ndarray結構。Pandas會默然用0到n-1來作爲series的index,但也可以自己指定index(可以把index理解爲dict裏面的key)。

f = open('天龍八部.txt', 'r',encoding='utf-8')  # 讀取文章
s = f.read()  # 讀取爲一個字符串

t = []  # 保存結果用。
t.append(pd.Series(list(s)).value_counts())  # 逐字統計 value_counts()返回值爲 series,所有的元素排序返回。
tsum = t[0].sum()  # 統計總字數。獨一無二的字的個數。
rt = []  # 保存結果用

2、數據預處理,標點字符過濾

# 定義要去掉的標點字
drop_dict = [u',', u'\n', u'。', u'、', u':', u'(', u')', u'[', u']', u'.', u',', u' ', u'\u3000', u'”', u'“', u'?', u'?',
             u'!', u'‘', u'’', u'…']
for i in drop_dict:  # 去掉標點字
    s = s.replace(i, '')

3、因爲要對2、3、4字的詞語分別進行匹配,定義字典

# 爲了方便調用,自定義了一個正則表達式的詞典
myre = {2: '(..)', 3: '(...)', 4: '(....)', 5: '(.....)', 6: '(......)', 7: '(.......)'}

4、 定義四個參數,依次爲(二)中定義的頻數、內部凝固程度,自由運用程度,詞語長度

min_count = 10  # 錄取詞語最小出現次數
min_support = 30  # 錄取詞語最低支持度,1代表着隨機組合
min_s = 3  # 錄取詞語最低信息熵,越大說明越有可能獨立成詞
max_sep = 4  # 候選詞語的最大字數

5、由於re.findall() 返回的是匹配到的 non-overlapping 字符串,因此從i 從0到m進行遍歷以得到所有可能的組合。

s = 'abcdede'
ree = '(..)'
res = re.findall(ree, s)
print(res)   # ['ab', 'cd', 'ed']

 計算內部凝固程度,進行第一步的篩選。

for m in range(2, max_sep + 1):
    print(u'正在生成%s字詞...' % m)
    t.append([]) # 2,3,4 三個空的列表。
    for i in range(m):  # 生成所有可能的m字詞
        t[m - 1] = t[m - 1] + re.findall(myre[m], s[i:])

    t[m - 1] = pd.Series(t[m - 1]).value_counts()  # 逐詞統計
    t[m - 1] = t[m - 1][t[m - 1] > min_count]  # 最小次數篩選
    tt = t[m - 1][:]
    for k in range(m - 1):
        qq = np.array(list(map(lambda ms: tsum * t[m - 1][ms] / t[m - 2 - k][ms[:m - 1 - k]] / t[k][ms[m - 1 - k:]],
                               tt.index))) > min_support  # 最小支持度篩選。
        tt = tt[qq]
    rt.append(tt.index)

 6、定義信息熵計算函數,並計算其左右鄰信息熵得到最終結果

def cal_S(sl):  # 信息熵計算函數
    return -((sl / sl.sum()).apply(log) * sl / sl.sum()).sum()


for i in range(2, max_sep + 1):
    print(u'正在進行%s字詞的最大熵篩選(%s)...' % (i, len(rt[i - 2])))
    pp = []  # 保存所有的左右鄰結果
    for j in range(i + 2):
        pp = pp + re.findall('(.)%s(.)' % myre[i], s[j:])
    pp = pd.DataFrame(pp).set_index(1).sort_index()  # 先排序,這個很重要,可以加快檢索速度
    index = np.sort(np.intersect1d(rt[i - 2], pp.index))  # 作交集
    # 下面兩句分別是左鄰和右鄰信息熵篩選
    index = index[np.array(list(map(lambda s: cal_S(pd.Series(pp[0][s]).value_counts()), index))) > min_s]
    rt[i - 2] = index[np.array(list(map(lambda s: cal_S(pd.Series(pp[2][s]).value_counts()), index))) > min_s]

for j in range(i+2) :   s[j:] 的作用同5,找到所有可能的左右鄰。

s = 'abcdede'
ree = '(..)'
pp = []
for j in range(2 + 2):
    pp = pp + re.findall('(.)%s(.)' % ree, s[j:])

print(pp)
#[('a', 'bc', 'd'), ('b', 'cd', 'e'), ('c', 'de', 'd'), ('d', 'ed', 'e')]

7、保存結果。   result.txt 文件部分內容如下

無崖子,60
木婉清,738
王語嫣,859
# 下面都是輸出前處理
for i in range(len(rt)):
    t[i + 1] = t[i + 1][rt[i]]
    t[i + 1].sort_values(ascending = False)

# 保存結果並輸出
pd.DataFrame(pd.concat(t[1:])).to_csv('result.txt', header=False)

完整代碼及數據集下載:

關注微信公衆號:曉說AI

留言:天龍八部    獲取下載鏈接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章