Python利用卡方Chi特征檢驗(yàn)實(shí)現(xiàn)提取關(guān)鍵文本特征
理論
類別classi | 非類別classi | |
包含單詞wordj的文檔數(shù) | A | B |
不包含單詞wordj的文檔數(shù) | C | D |
卡方特征提取主要度量類別classi和單詞wordj之間的依賴關(guān)系。計(jì)算公式如下
其中N是文檔總數(shù),A是包含單詞wordj且屬于classi的文檔數(shù),B是包含單詞wordj但不屬classi的文檔數(shù),C是不包含單詞wordj但屬于classi的文檔數(shù),D是不包含單詞wordj且不屬于classi的文檔數(shù)。值得注意的是
最終單詞wordj的CHI值計(jì)算公式如下,其中P(classi)表示屬于類別 classi的文檔在所有文檔中出現(xiàn)的概率,k為總的類別數(shù)
代碼
下面以二分類為例介紹一段python代碼:第一個(gè)參數(shù)是文檔列表,包含若干個(gè)文檔,每個(gè)文檔由若干個(gè)單詞通過(guò)空格拼接而成;第二個(gè)參數(shù)是標(biāo)簽列表,對(duì)應(yīng)每個(gè)文檔的類別;第三個(gè)參數(shù)用來(lái)確定選取前百分之多少的單詞。
# documents = [document_1, document_2, document_3, ...] # document_i = "word_1 word_2 word_3" # labels is a list combined with 0 and 1 def feature_word_select(documents:list, labels:list, percentage:float): # get all words word_set = set() for document in documents: words = document.split() word_set.update(words) word_list = list(word_set) word_list.sort() sorted_words = chi(word_list, documents, labels) top_k_words = sorted_words[:int(percentage * len(sorted_words))] return top_k_words
這段代碼首先創(chuàng)建一個(gè)集合word_set,接著遍歷所有的文檔,對(duì)每一個(gè)文檔,使用split()函數(shù)對(duì)其進(jìn)行切分,得到一個(gè)words列表,再將列表中的所有元素輸入到集合word_set中,word_set由于集合的特性會(huì)過(guò)濾集合中已有的單詞。收集完畢后,通過(guò)word_set生成一個(gè)單詞列表word_list。
將單詞列表,文檔列表和標(biāo)簽列表輸入chi函數(shù),得到通過(guò)卡方值降序排列的單詞列表sorted_words。
最后選取前百分之percentage的單詞最為最后的特征單詞。
下面這個(gè)函數(shù)cal_chi_word_class()用來(lái)計(jì)算 CHI(word, 0)和CHI(word, 1)。這里的A1表示屬于類別1的A,A0表示屬于類別0的A。
值得說(shuō)明的是,在二分類問(wèn)題中,A1實(shí)際上等于B0,C1實(shí)際上等于D0。因此,僅計(jì)算A1,B1,C1,D1即可推導(dǎo)出A0,B0,C0,D0。
此外,由于文檔總數(shù)N對(duì)于CHI(word, 0)和CHI(word, 1)來(lái)說(shuō)屬于公共的分子且保持不變,所以可以不參與計(jì)算;A1+C1=B0+D0,B1+D1=A0+C0,所以CHI(word, 0)和CHI(word, 1)的分母部分可以進(jìn)行簡(jiǎn)化
# calculate chi(word,1) and chi(word,0) def cal_chi_word_class(word, labels, documents): N = len(documents) A1, B1, C1, D1 = 0., 0., 0., 0. A0, B0, C0, D0 = 0., 0., 0., 0. for i in range(len(documents)): if word in documents[i].split(): if labels[i] == 1: A1 += 1 B0 += 1 else: B1 += 1 A0 += 1 else: if labels[i] == 1: C1 += 1 D0 += 1 else: D1 += 1 C0 += 1 chi_word_1 = N * (A1*D1-C1*B1)**2 / ((A1+C1)*(B1+D1)*(A1+B1)*(C1+D1)) chi_word_0 = N * (A0*D0-C0*B0)**2 / ((A0+C0)*(B0+D0)*(A0+B0)*(C0+D0)) return chi_word_1, chi_word_0
簡(jiǎn)化后
# calculate chi(word,1) and chi(word,0) def cal_chi_word_class(word, labels, documents): A1, B1, C1, D1 = 0., 0., 0., 0. for i in range(len(documents)): if word in documents[i].split(): if labels[i] == 1: A1 += 1 else: B1 += 1 else: if labels[i] == 1: C1 += 1 else: D1 += 1 A0, B0, C0, D0 = B1, A1, D1, C1 chi_word_1 = (A1*D1-C1*B1)**2 / ((A1+B1)*(C1+D1)) chi_word_0 = (A0*D0-C0*B0)**2 / ((A0+B0)*(C0+D0)) return chi_word_1, chi_word_0
在chi函數(shù)中調(diào)用cal_chi_word_class函數(shù),即可計(jì)算每個(gè)單詞的卡方值,以字典的形式保存每個(gè)單詞的卡方值,最后對(duì)字典的所有值進(jìn)行排序,并提取出排序后的單詞。
def chi(word_list, documents, labels): P1 = labels.count(1) / len(documents) P0 = 1 - P1 dic = {} for word in word_list: chi_word_1, chi_word_0 = cal_chi_word_class(word, labels, documents) chi_word = P0 * chi_word_0 + P1 * chi_word_1 dic[word] = chi_word sorted_list = sorted(dic.items(), key=lambda x:x[1], reverse=True) sorted_chi_word = [x[0] for x in sorted_list] return sorted_chi_word
測(cè)試代碼。這里我略過(guò)了數(shù)據(jù)處理環(huán)節(jié),documents列表中的每一個(gè)元素document_i都是有若干個(gè)單詞或符號(hào)通過(guò)空格拼接而成。
def main(): documents = ["today i am happy !", "she is not happy at all", "let us go shopping !", "mike was so sad last night", "amy did not love it", "it is so amazing !" ] labels = [1, 0, 1, 0, 0, 1] words = feature_word_select(documents, labels, 0.3) print(words) if __name__ == '__main__': main()
運(yùn)行結(jié)果如下
['!', 'not', 'all', 'am', 'amazing', 'amy', 'at']
進(jìn)一步,可以在chi函數(shù)里輸出sorted_list(每個(gè)單詞對(duì)應(yīng)的卡方值),結(jié)果如下。這里輸出的并不是真實(shí)的卡方值,是經(jīng)過(guò)化簡(jiǎn)的,如需輸出原始值,請(qǐng)使用完整版的cal_chi_word_class()函數(shù)。
[('!', 9.0), ('not', 4.5), ('all', 1.8), ('am', 1.8), ('amazing', 1.8), ('amy', 1.8), ('at', 1.8), ('did', 1.8), ('go', 1.8), ('i', 1.8), ('last', 1.8), ('let', 1.8), ('love', 1.8), ('mike', 1.8), ...]
完整代碼
# calculate chi(word,1) and chi(word,0) def cal_chi_word_class(word, labels, documents): A1, B1, C1, D1 = 0., 0., 0., 0. for i in range(len(documents)): if word in documents[i].split(): if labels[i] == 1: A1 += 1 else: B1 += 1 else: if labels[i] == 1: C1 += 1 else: D1 += 1 A0, B0, C0, D0 = B1, A1, D1, C1 chi_word_1 = (A1*D1-C1*B1)**2 / ((A1+B1)*(C1+D1)) chi_word_0 = (A0*D0-C0*B0)**2 / ((A0+B0)*(C0+D0)) return chi_word_1, chi_word_0 def chi(word_list, documents, labels): P1 = labels.count(1) / len(documents) P0 = 1 - P1 dic = {} for word in word_list: chi_word_1, chi_word_0 = cal_chi_word_class(word, labels, documents) chi_word = P0 * chi_word_0 + P1 * chi_word_1 dic[word] = chi_word sorted_list = sorted(dic.items(), key=lambda x:x[1], reverse=True) sorted_chi_word = [x[0] for x in sorted_list] return sorted_chi_word # documents = [document_1, document_2, document_3, ...] # document_i = "word_1 word_2 word_3" # labels is a list combined with 0 and 1 def feature_word_select(documents:list, labels:list, percentage:float): # get all words word_set = set() for document in documents: words = document.split() word_set.update(words) word_list = list(word_set) word_list.sort() sorted_words = chi(word_list, documents, labels) top_k_words = sorted_words[:int(percentage * len(sorted_words))] return top_k_words def main(): documents = ["today i am happy !", "she is not happy at all", "let us go shopping !", "mike was so sad last night", "amy did not love it", "it is so amazing !" ] labels = [1, 0, 1, 0, 0, 1] words = feature_word_select(documents, labels, 0.3) print(words) if __name__ == '__main__': main()
題外話
卡方特征選擇僅考慮單詞是否在文檔中出現(xiàn),并沒(méi)有考慮單詞出現(xiàn)的次數(shù),因此選擇出的特征單詞可能并不準(zhǔn)確。
到此這篇關(guān)于Python利用卡方Chi特征檢驗(yàn)實(shí)現(xiàn)提取關(guān)鍵文本特征的文章就介紹到這了,更多相關(guān)Python提取關(guān)鍵文本特征內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
講清楚fit_transform()和transform()的區(qū)別及說(shuō)明
這篇文章主要介紹了講清楚fit_transform()和transform()的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-02-02可視化工具PyVista多線程顯示多窗口的實(shí)例代碼
這篇文章主要介紹了可視化工具PyVista多線程顯示多窗口,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04python必學(xué)知識(shí)之文件操作(建議收藏)
python中對(duì)文件、文件夾(文件操作函數(shù))的操作需要涉及到os模塊和shutil模塊。下面這篇文章主要給大家介紹了關(guān)于python必學(xué)知識(shí)之文件操作的相關(guān)資料,需要的朋友可以參考下2021-05-05用virtualenv建立多個(gè)Python獨(dú)立虛擬開(kāi)發(fā)環(huán)境
這篇文章主要為大家詳細(xì)介紹了用virtualenv建立多個(gè)Python獨(dú)立虛擬開(kāi)發(fā)環(huán)境,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07對(duì)python實(shí)時(shí)得到鼠標(biāo)位置的示例講解
今天小編就為大家分享一篇對(duì)python實(shí)時(shí)得到鼠標(biāo)位置的示例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10