新詞發(fā)現(xiàn)是一個老生常談的任務(wù)了族淮,對怎么算“詞”屎鳍,有一個很好的比喻:怎樣判斷兩個人是情侶?首先蛋勺,我們得經(jīng)巢须纾看到他們在一起村斟,而不是今天看到A和B在一起,明天看到A和C抛猫,B和D蟆盹,那可能是海王;第二是他們周圍的圈子也很豐富闺金,不能說每次看到他們一起都是和其他同樣的面孔在同樣的環(huán)境逾滥,那可能是英語角練英語[/doge]。前者反映為凝固度败匹,后者反映為自由度寨昙。
1.互信息:MI(Mutual Information)
這個指標(biāo)衡量凝固度,對兩個字計算
對多個字的掀亩,算平均互信息(AMI):
還有資料用以下方式計算:
也就是考慮詞的兩兩組合的不同情況舔哪,取情況最壞(說明不能成為一個詞)的某種組合作為瓶頸值。這樣等于說我們期待這個詞是無論怎么切分都很凝聚的槽棍。
2.自信息(信息熵):Entropy
這個公式用于新詞發(fā)現(xiàn)的計算時捉蚤,反映了周圍字的豐富度抬驴。我們分別計算一個詞的左右鄰字的信息熵。一個詞我們希望左右鄰字的信息熵都很高缆巧。這里需要一個公式計算左右鄰熵的綜合值怎爵。
hanlp中取左右信息熵中最小值。SmoothNLP和HelloNLP中公開的計算公式如下盅蝗。
實際上源碼中計算公式為:
smoothnlp:
math.log((l_e * 2 ** r_e + r_e * 2 ** l_e + 0.00001) / (abs(l_e - r_e) + 1), 1.5)
hellonlp:
math.log((l_e * math.e ** r_e+0.00001)/(abs(l_e - r_e)+1), math.e) \
+ math.log((r_e * math.e ** l_e+0.00001)/(abs(l_e - r_e)+1), math.e)
這里的公式個人認(rèn)為不是很合理。因為我們的目標(biāo)是希望EL和ER都很大姆蘸,而|EL-ER|是隱含希望他們很相近墩莫,所以會出現(xiàn):
LS(2.99, 2.99) = 9.5222271192095
LS(3.0, 3.5) = 9.176423134994266
LH(2.99, 2.99) = 8.170547111175976
LH(3.0, 3.5) = 8.040445283853845
也就是說,EL和ER雙高的情況的值竟然比EL和ER相對雙低的情況的值還低逞敷,只因為后者接近狂秦,這顯然不合理。
以及
LS(2, 100) = 161.32768043007533
LS(40, 40) = 79.18785911538012
LH(2, 100) = 98.10807767981238
LH(40, 40) = 87.37775890822788
這里左右鄰熵失衡推捐、左鄰熵非常小的情況下裂问,分值比左右鄰熵雙高且均衡的情況還要大,說明公式也沒有很好地讓雙高且接近的值更大(因為差值的倒數(shù)有邊際效應(yīng)遞減)牛柒。
所以可以自己設(shè)計一個公式L_mine堪簿。e.g.
min(l_e, r_e) * math.sqrt(max(l_e, r_e))
L_mine(2.99, 2.99) = 5.170193323271384
L_mine(3.0, 3.5) = 5.612486080160912
L_mine(2, 100) = 20.0
L_mine(40, 40) = 252.98221281347037
L_mine(20, 50) = 141.4213562373095
這樣就同時考慮的兩邊的值同時削弱了大值的影響,很好地讓EL和ER雙高的情況值最大皮壁。
以上兩點是新詞發(fā)現(xiàn)常用的兩個指標(biāo)椭更,對于我們?nèi)蝿?wù)關(guān)鍵詞抽取來說,還是欠缺了一點蛾魄。因為我們希望抽取的詞能更專業(yè)名詞一點虑瀑,且長詞優(yōu)先。不希望充斥大量的“這句話”滴须、“忽大忽小”舌狗,雖然他們符合詞的定義,但是不是我們的target word扔水。所以后續(xù)還可以結(jié)合一些指標(biāo)來篩選和算分痛侍。
3.tf-idf
我們希望這個詞有一點特別,不是每篇文章都出現(xiàn)的口水詞铭污。很容易就能想到tf-idf可以做關(guān)鍵詞提取恋日。這里計算一個詞的idf并不是用的這個詞的idf,而是詞里的每個字的idf的平均值嘹狞。
4.詞性結(jié)構(gòu)
我們可以將詞當(dāng)作字進(jìn)行如上的計算岂膳,先分詞再結(jié)合。這時候分詞就可以得到每個詞的詞性磅网。整理出詞性組合谈截,就可以通過詞性組合來篩選出目標(biāo)詞了。但是由于詞性這一步也會有錯誤和例外,所以這一步我只做了簡單的判斷:當(dāng)出現(xiàn)名詞時簸喂,加分毙死;當(dāng)出現(xiàn)助詞、符號等明顯錯誤的喻鳄,減分扼倘。
代碼來說,先統(tǒng)計文檔里ngram的基本信息除呵,以及統(tǒng)計idf再菊。
def calculate_idf(idf_list):
idf_di = dict()
for sentence_word_set in idf_list:
for word in sentence_word_set:
if word not in idf_di:
idf_di[word] = 0
idf_di[word] += 1
l = len(idf_list)
for word in idf_di:
idf_di[word] = math.log(l/(idf_di[word] + 1))
return idf_di
def calculate_frequency(sentences, k=4, mode="word"):
word_num = 0
freq_di = dict()
idf_list = []
for sentence in sentences:
sentence_set = set()
if mode == "word":
res = jieba.lcut(sentence)
words = [elem.word for elem in res]
flags = [elem.flag for elem in res]
elif mode == "char":
words = list(sentence)
flags = ["n" for i in words]
l = len(words)
word_num = word_num + l
for i in range(l):
sentence_set.add(words[i])
for j in range(1, k + 1 if i + k + 1 <= l else l - i):
word = tuple(words[i: i + j])
if word not in freq_di:
freq_di[word] = {"freq": 0, "left": [], "right": [], "pos":[]}
freq_di[word]["freq"] += 1
freq_di[word]["left"].append(words[i - 1] if i - 1 >= 0 else "")
freq_di[word]["right"].append(words[i + j] if i + j <= l else "")
freq_di[word]["pos"] = flags[i: i + j]
idf_list.append(sentence_set)
idf_di = calculate_idf(idf_list)
return freq_di, word_num, idf_di
計算entropy,這里有個問題颜曾,就是有的詞是句首詞或句尾詞時意味著它沒有左鄰/右鄰纠拔,這時候想到幾種處理方式:1.沒有鄰時即不將這種情況算進(jìn)去。這種方式容易漏掉諸如名字等容易出現(xiàn)在句首的詞泛豪。2.此時將鄰看作""這個字符和其他字符一樣處理稠诲。 3.將鄰看作""這個字符,但是“”彼此之間看作不同字符诡曙,也就是說句首句尾詞認(rèn)為它有一個互不相同的鄰字臀叙。這時候我的處理方式是2和3方法的折中處理。將所有""看作不同字符岗仑,然而對這個情況的數(shù)目通過開方來降權(quán)匹耕。
def entropy(word_list):
di = dict(Counter(word_list))
num = sum(di.values())
res = 0
for word, freq in di.items():
if word == "":
res -= (1/num * math.log2(1/num)) * math.sqrt(freq)
else:
res -= freq/num * math.log2(freq/num)
return res
def L_entropy(freq_di, threshold=0, percent=10):
di = dict()
for word in freq_di:
if len(word) > 1:
l_e = entropy(freq_di[word]["left"])
r_e = entropy(freq_di[word]["right"])
final_entropy = min(l_e, r_e) * math.sqrt(max(l_e, r_e))
if final_entropy > threshold:
#di[word] = final_entropy
di[word] = [final_entropy, l_e, r_e]
#di = sorted(di.items(), key=lambda x: x[1], reverse=True)
di = sorted(di.items(), key=lambda x: x[1][0], reverse=True)
di = di[:int(len(freq_di) * percent / 100)]
print(di[0][1], di[-1][1])
di = {key: value for key, value in di}
return di
計算ami:
def ami(freq_di, word_num, threshold=0, percent=10):
di = dict()
for word in freq_di:
if len(word) > 1:
val = freq_di[word]["freq"]/word_num
for single_word in word:
val = val / (freq_di[tuple([single_word])]["freq"]/word_num)
val = math.log2(val)
val /= len(word)
if val > threshold:
di[word] = val
di = sorted(di.items(), key=lambda x: x[1], reverse=True)
di = di[:int(len(freq_di) * percent / 100)]
print(di[0][1], di[-1][1])
di = {key: value for key, value in di}
return di
最后對三體.txt進(jìn)行測試,結(jié)合entropy, ami, idf, 詞性結(jié)構(gòu)分荠雕,詞頻幾個因素綜合篩選稳其、算分得char模式top100詞:
['雷迪亞茲', '章北海', '希恩斯', 'PDC', '狄奧倫娜', '申玉菲', '穿梭機(jī)', '瓦季姆', '金字塔', '銀河系', '吳岳', '饕餮魚', '楊衛(wèi)寧', '曲率驅(qū)動', '曹彬', '黑暗森林', '思想鋼印', '山杉惠子', 'PIA', '赫爾辛根默斯肯', '常偉思', 'ETO', '降臨派', '塵埃云', '斐茲羅', '東方延緒', '高Way', '階梯計劃', '逃亡主義', '黑暗森林威懾', '聯(lián)邦政府', '黑暗森林打擊', '行星防御理事會', '馮?諾伊曼', '威懾紀(jì)元', '伽爾寧', '伊甸園', '白Ice', 'DX3906', '弗雷斯', '疲憊', '法扎蘭', '張援朝', '失敗主義', '‘自然選擇’號', '執(zhí)政官', '柯伊伯帶', '公元世紀(jì)', '亞洲艦隊', 'IDC', '哈勃二號', '雷迪亞茲的', '鋼印族', '韋斯特', '引力波發(fā)射', '喬納森', '國際社會', '殘骸', '君士坦丁', '蒙娜麗莎', '曲率引擎', '翹曲點', '露珠公主', '盧浮宮', '白沐霖', '星環(huán)集團(tuán)', '拯救派', '楊晉文', '小心翼翼地', '信息窗口', '基礎(chǔ)研究', '褐蟻', 'KILLER', '君士坦丁堡', '宇宙廣播', '晶瑩', '陶醉', '紅岸基地', '末日戰(zhàn)役', '‘星環(huán)’號', '祈禱', '葉哲泰', '科學(xué)執(zhí)政官', '四維碎塊', 'NH558J2', '拐杖', '針眼畫師', '階梯計劃的', '沙瑞山', '聚變發(fā)動機(jī)', '指揮系統(tǒng)', '艦隊聯(lián)席會議', '電磁輻射', '莫沃維奇', '幼稚', '螞蟻', '紅岸系統(tǒng)', '肥皂', '追擊艦隊', '‘審判日’號']
這里的一些錯誤詞主要是"的,"地"模式炸卑,smoothnnlp對這種情況(最后一個字為頻繁字)專門做了過濾處理既鞠,我這里還沒做。
如果用word模式:
['行星防御理事會', '狄奧倫娜', '治安軍', '山杉惠子', '各常任理事國', '馮?諾伊曼', '執(zhí)劍人', '雷達(dá)峰', '莫沃維奇', '莫沃維奇和關(guān)一帆', '奧爾特星云', '宏原子', '無故事王國', '恒星型氫彈', '恒星級戰(zhàn)艦', '強互作用力', '機(jī)械臂', '程心想', '常任理事國', '聯(lián)合國行星防御理事會', '化學(xué)火箭', '史耐德', 'V裝具', '赫爾辛根默斯', '可控核聚變', '猜疑鏈', '黑暗森林理論', '禇巖', '低熵體', '斐茲羅', '面壁者雷迪亞茲', '”馮?諾伊曼', '托馬斯?維德', '兩位副艦長', '187J3X1恒星', '解析攝像機(jī)', '半人馬座', '強互作用力宇宙探測器', '解讀者', '第三宇宙速度']
效果還是不錯的盖文,肉眼看出遠(yuǎn)好于下面smoothnlp和hellonlp的結(jié)果嘱蛋。
['短短', '長長', '空間', '技術(shù)', '宇宙', '引力', '00', '太陽', '11', '太空', '狄奧倫娜', '赫爾辛根默', '辛根默斯肯', '爾辛根默斯', '史瓦西半徑', '爾辛根默', '福爾摩斯', '瓦西半徑', '赫爾辛根', '申玉菲', 'V裝具', '狄奧倫', '奧倫娜', '根默斯肯', '辛根默斯', '福爾摩', '雷迪亞茲', '史瓦西半', '辛根默', '張援朝', '赫爾辛', '逃亡主義', '默斯肯', '爾辛根', '瓦西半', '希恩斯', '降臨派', '爾摩斯', '饕餮魚', '控制單元', '西半徑', '嘿嘿嘿', '根默斯', '青銅時代號', '楊衛(wèi)寧', '運載艙', '青銅時代', '自然選擇', '史瓦西', '雷迪亞', '迪亞茲', '執(zhí)政官', '自然選擇號', '拯救派', '機(jī)械臂', '逃亡主', '澳大利亞', '技術(shù)突變', '望遠(yuǎn)鏡', '螳螂號', '1187', '章北海', '思想鋼印', '然選擇號', '然選擇', '隊司令', '艦隊司令', '控制單', '蒸汽機(jī)', '科學(xué)和理性', '層隱喻', '187', '環(huán)集團(tuán)', '亡主義', '技術(shù)公有化', '亂紀(jì)元', '制單元', '銀河系', '塵埃云', '要回答', '秘書長', '哈哈哈', '金字塔', '星環(huán)集團(tuán)', '穿梭機(jī)', '青銅時', '銅時代號', '000萬年', '短短短短', '護(hù)士', 'KB', '裝具', '吳岳', '狄奧', '殘骸', '倫娜', '申玉', '援朝', '械臂', '奧倫']
['短短', '長長', '太陽', '技術(shù)', '世界', '宇宙', '飛船', '三體', '太空', '187j3x1', '赫爾辛根默', '辛根默斯肯', '爾辛根默斯', '爾辛根默', '赫爾辛根', '根默斯肯', '辛根默斯', '187j3', 'j3x1', '福爾摩斯', '辛根默', '愛因斯坦', '雷迪亞茲', '爾辛根', '嘿嘿嘿嘿', '戰(zhàn)略研究室', '饕餮魚', '福爾摩', '略研究室', '食品垛', '黑暗森林', '赫爾辛', '默斯肯', '根默斯', '暗森林', '爾摩斯', '術(shù)戰(zhàn)略研究', '青銅時代號', '執(zhí)政官', '降臨派', '因斯坦', '青銅時代', '逃亡主義', '拯救派', '技術(shù)戰(zhàn)略研', '嘿嘿嘿', '控制單元', '雷迪亞', '迪亞茲', '技術(shù)突變', '洛文斯基', '自然選擇', '自然選擇號', '紅衛(wèi)兵', '思想鋼印', '研究室', '機(jī)械臂', '澳大利亞', '望遠(yuǎn)鏡', '戰(zhàn)略研究', '章北海', '愛因斯', '金字塔', '環(huán)集團(tuán)', '層隱喻', '復(fù)制世界', '黑暗森', '蒸汽機(jī)', '術(shù)戰(zhàn)略研', '然選擇號', '監(jiān)護(hù)官', '然選擇', '監(jiān)聽部', '信念簿', '星環(huán)集團(tuán)', '技術(shù)戰(zhàn)略', '同義詞', '逃亡主', '銀河系人類', '略研究', '哈哈哈', '銀河系', '術(shù)突變', '治安軍', '短短短短', '怎樣想', '萬千米', '要回答', '青銅時', '穿梭機(jī)', '控制單', '銅時代號', '饕餮', '187j', '幽閉', '規(guī)律', '退卻', '獨裁', '仇恨', '莊顏']
參考資料:
http://www.reibang.com/p/9b8bf8bb197c
https://github.com/smoothnlp/SmoothNLP/tree/master/tutorials/新詞發(fā)現(xiàn)
https://zhuanlan.zhihu.com/p/210584733
https://blog.csdn.net/cdd2xd/article/details/94354751
https://blog.csdn.net/wendingzhulu/article/details/44464895
https://blog.csdn.net/zhaomengszu/article/details/81452907