文本挖掘之特徵選擇(python 實現)

  機器學習算法的空間、時間複雜度依賴於輸入數據的規模,維度規約(Dimensionality reduction)則是一種被用於下降輸入數據維數的方法。維度規約能夠分爲兩類: html

  • 特徵選擇(feature selection),從原始的d維空間中,選擇爲咱們提供信息最多的k個維(這k個維屬於原始空間的子集)
  • 特徵提取(feature extraction),將原始的d維空間映射到k維空間中(新的k維空間不輸入原始空間的子集)

  在文本挖掘與文本分類的有關問題中,常採用特徵選擇方法。緣由是文本的特徵通常都是單詞(term),具備語義信息,使用特徵選擇找出的k維子集,仍然是單詞做爲特徵,保留了語義信息,而特徵提取則找k維新空間,將會喪失了語義信息。 python

  對於一個語料而言,咱們能夠統計的信息包括文檔頻率和文檔類比例,全部的特徵選擇方法均依賴於這兩個統計量,目前,文本的特徵選擇方法主要有:DF, MI, IG, CHI,WLLR,WFO六種。 算法

  爲了方便描述,咱們首先一些機率上的定義: app

    p(t):一篇文檔x包含特徵詞t的機率。 框架

    :文檔x不屬於Ci的機率。 dom

    p(Ci|t):已知文檔x的包括某個特徵詞t條件下,該文檔屬於Ci的機率 機器學習

    : 已知文檔屬於C條件下,該文檔不包括特徵詞t的機率 工具

  相似的其餘的一些機率如p(Ci), 等,有着相似的定義。 性能

爲了估計這些機率,咱們須要經過統計訓練樣本的相關頻率信息,以下表: 學習

 其中:

   Aij包含特徵詞ti,而且類別屬於Cj的文檔數量    Bij: 包含特徵詞ti,而且類別屬於不Cj的文檔數量

   Cij:不包含特徵詞ti,而且類別屬於Cj的文檔數量 Dij:不包含特徵詞ti,而且類別屬於不Cj的文檔數量

   Aij + Bij: 包含特徵詞ti的文檔數量          Cij  + Dij:不包含特徵詞ti的文檔數量

   Aij + Cij:Cj類的文檔數量數據             Bij + Dij:非Cj類的文檔數量數據

   Aij + Bij + Cij  + Dij = N :語料中全部文檔數量。

有了這些統計量,有關機率的估算就變得容易,如:

    p(ti) =     (Aij + Bij) / N;    p(Cj) = (Aij +  Cij) / N;  

    p(Cj|tj) = Aij  / (Aij + Bij)        

  ......相似的一些機率計算能夠依照上表計算。

  介紹了事情發展的前因,如今進入正題:常見的四種特徵選擇方法如何計算。

  1)DF(Document Frequency)

DF:統計特徵詞出現的文檔數量,用來衡量某個特徵詞的重要性,DF的定義以下:

  DF的動機是,若是某些特徵詞在文檔中常常出現,那麼這個詞就可能很重要。而對於在文檔中出現不多(如僅在語料中出現1次)特徵詞,攜帶了不多的信息量,甚至是"噪聲",這些特徵詞,對分類器學習影響也是很小。

  DF特徵選擇方法屬於無監督的學習算法(也有將其改爲有監督的算法,可是大部分狀況都做爲無監督算法使用),僅考慮了頻率因素而沒有考慮類別因素,所以,DF算法的將會引入一些沒有意義的詞。如中文的"的"、"是", "個"等,經常具備很高的DF得分,可是,對分類並無多大的意義。

  2)MI(Mutual Information)

  互信息法用於衡量特徵詞與文檔類別直接的信息量,互信息法的定義以下:

  繼續推導MI的定義公式:

  從上面的公式上看出:若是某個特徵詞的頻率很低,那麼互信息得分就會很大,所以互信息法傾向"低頻"的特徵詞。相對的詞頻很高的詞,得分就會變低,若是這詞攜帶了很高的信息量,互信息法就會變得低效。

  3)IG(Information Gain)

  信息增益法,經過某個特徵詞的缺失與存在的兩種狀況下,語料中先後信息的增長,衡量某個特徵詞的重要性。

信息增益的定義以下:

  依據IG的定義,每一個特徵詞tiIG得分前面一部分:計算值是同樣,能夠省略。所以,IG的計算公式以下:

IG與MI存在關係:

所以,IG方式實際上就是互信息與互信息加權。

4)CHI(Chi-square)

CHI特徵選擇算法利用了統計學中的"假設檢驗"的基本思想:首先假設特徵詞與類別直接是不相關的,若是利用CHI分佈計算出的檢驗值偏離閾值越大,那麼更有信心否認原假設,接受原假設的備則假設:特徵詞與類別有着很高的關聯度。CHI的定義以下:

對於一個給定的語料而言,文檔的總數N以及Cj類文檔的數量,非Cj類文檔的數量,他們都是一個定值,所以CHI的計算公式能夠簡化爲:

CHI特徵選擇方法,綜合考慮文檔頻率與類別比例兩個因素

5)WLLR(Weighted Log Likelihood Ration)

WLLR特徵選擇方法的定義以下:

  計算公式以下:

6)WFO(Weighted Frequency and Odds)

最後一個介紹的算法,是由蘇大李壽山老師提出的算法。經過以上的五種算法的分析,李壽山老師認爲,"好"的特徵應該有如下特色:

  • 好的特徵應該有較高的文檔頻率
  • 好的特徵應該有較高的文檔類別比例

WFO的算法定義以下:

若是

不然:

不一樣的語料,通常來講文檔詞頻與文檔的類別比例起的做用應該是不同的,WFO方法能夠經過調整參數,找出一個較好的特徵選擇依據。

 

-----------------------------------------分割線---------------------------------------------

  介紹完理論部分,就要給出代碼了(只給出公式,不給出代碼的都是調戲良家的行爲~)。文本挖掘之文本表示一文,利用了sklearn開源工具,天然先首先sklearn工具,惋惜的是sklearn文本的特徵選擇方法僅提供了CHI一種。爲此在sklearn框架下,嘗試本身編寫這些特徵選擇方法的代碼,本身動手,豐衣足食。

 筆者實現了三種特徵選擇方法:IG,MI和WLLR,看官若是對其餘特徵選擇方法感興趣,能夠嘗試實現一下~ 好了,啥也不說了,上代碼,特徵選擇模塊代碼:

#!/usr/bin/env python
# coding=gbk

import os
import sys

import numpy as np

def get_term_dict(doc_terms_list):
    term_set_dict = {}
    for doc_terms in doc_terms_list:
        for term in doc_terms:
            term_set_dict[term] = 1
    term_set_list = sorted(term_set_dict.keys())       #term set 排序後,按照索引作出字典
    term_set_dict = dict(zip(term_set_list, range(len(term_set_list))))
    return term_set_dict

def get_class_dict(doc_class_list):
    class_set = sorted(list(set(doc_class_list)))
    class_dict = dict(zip(class_set, range(len(class_set))))
    return  class_dict

def stats_term_df(doc_terms_list, term_dict):
    term_df_dict = {}.fromkeys(term_dict.keys(), 0)
    for term in term_set:
        for doc_terms in doc_terms_list:
            if term in doc_terms_list:
                term_df_dict[term] +=1                
    return term_df_dict

def stats_class_df(doc_class_list, class_dict):
    class_df_list = [0] * len(class_dict)
    for doc_class in doc_class_list:
        class_df_list[class_dict[doc_class]] += 1
    return class_df_list

def stats_term_class_df(doc_terms_list, doc_class_list, term_dict, class_dict):
    term_class_df_mat = np.zeros((len(term_dict), len(class_dict)), np.float32)
    for k in range(len(doc_class_list)):
        class_index = class_dict[doc_class_list[k]]
        doc_terms = doc_terms_list[k]
        for term in set(doc_terms):
            term_index = term_dict[term]
            term_class_df_mat[term_index][class_index] +=1
    return  term_class_df_mat
        
def feature_selection_mi(class_df_list, term_set, term_class_df_mat):
    A = term_class_df_mat
    B = np.array([(sum(x) - x).tolist() for x in A])
    C = np.tile(class_df_list, (A.shape[0], 1)) - A
    N = sum(class_df_list)
    class_set_size = len(class_df_list)
    
    term_score_mat = np.log(((A+1.0)*N) / ((A+C) * (A+B+class_set_size)))
    term_score_max_list = [max(x) for x in term_score_mat]
    term_score_array = np.array(term_score_max_list)
    sorted_term_score_index = term_score_array.argsort()[: : -1]
    term_set_fs = [term_set[index] for index in sorted_term_score_index]
    
    return term_set_fs

def feature_selection_ig(class_df_list, term_set, term_class_df_mat):
    A = term_class_df_mat
    B = np.array([(sum(x) - x).tolist() for x in A])
    C = np.tile(class_df_list, (A.shape[0], 1)) - A
    N = sum(class_df_list)
    D = N - A - B - C
    term_df_array = np.sum(A, axis = 1)
    class_set_size = len(class_df_list)
    
    p_t = term_df_array / N
    p_not_t = 1 - p_t
    p_c_t_mat =  (A + 1) / (A + B + class_set_size)
    p_c_not_t_mat = (C+1) / (C + D + class_set_size)
    p_c_t = np.sum(p_c_t_mat  *  np.log(p_c_t_mat), axis =1)
    p_c_not_t = np.sum(p_c_not_t_mat *  np.log(p_c_not_t_mat), axis =1)
    
    term_score_array = p_t * p_c_t + p_not_t * p_c_not_t
    sorted_term_score_index = term_score_array.argsort()[: : -1]
    term_set_fs = [term_set[index] for index in sorted_term_score_index]    
    
    return term_set_fs

def feature_selection_wllr(class_df_list, term_set, term_class_df_mat):
    A = term_class_df_mat
    B = np.array([(sum(x) - x).tolist() for x in A])
    C_Total = np.tile(class_df_list, (A.shape[0], 1))
    N = sum(class_df_list)
    C_Total_Not = N - C_Total
    term_set_size = len(term_set)
    
    p_t_c = (A + 1E-6) / (C_Total + 1E-6 * term_set_size)
    p_t_not_c = (B +  1E-6) / (C_Total_Not + 1E-6 * term_set_size)
    term_score_mat = p_t_c  * np.log(p_t_c / p_t_not_c)
    
    term_score_max_list = [max(x) for x in term_score_mat]
    term_score_array = np.array(term_score_max_list)
    sorted_term_score_index = term_score_array.argsort()[: : -1]
    term_set_fs = [term_set[index] for index in sorted_term_score_index]
    
    print term_set_fs[:10]
    return term_set_fs

def feature_selection(doc_terms_list, doc_class_list, fs_method):
    class_dict = get_class_dict(doc_class_list)
    term_dict = get_term_dict(doc_terms_list)
    class_df_list = stats_class_df(doc_class_list, class_dict)
    term_class_df_mat = stats_term_class_df(doc_terms_list, doc_class_list, term_dict, class_dict)
    term_set = [term[0] for term in sorted(term_dict.items(), key = lambda x : x[1])]
    term_set_fs = []
    
    if fs_method == 'MI':
        term_set_fs = feature_selection_mi(class_df_list, term_set, term_class_df_mat)
    elif fs_method == 'IG':
        term_set_fs = feature_selection_ig(class_df_list, term_set, term_class_df_mat)
    elif fs_method == 'WLLR':
        term_set_fs = feature_selection_wllr(class_df_list, term_set, term_class_df_mat)
        
    return term_set_fs
    

    在movie語料裏面比較着三種特徵選擇方法,調用方法以下:

#!/usr/bin/env python
# coding=gbk

import os
import sys

import numpy as np
import matplotlib.pyplot as plt

from sklearn.datasets import load_files
from sklearn.cross_validation import train_test_split
from sklearn.feature_extraction.text import  CountVectorizer
from sklearn.naive_bayes import MultinomialNB

import feature_selection
    
def text_classifly_twang(dataset_dir_name, fs_method, fs_num):
    print 'Loading dataset, 80% for training, 20% for testing...'
    movie_reviews = load_files(dataset_dir_name)  
    doc_str_list_train, doc_str_list_test, doc_class_list_train, doc_class_list_test = train_test_split(movie_reviews.data, movie_reviews.target, test_size = 0.2, random_state = 0)
    
    print 'Feature selection...'
    print 'fs method:' + fs_method, 'fs num:' + str(fs_num)
    vectorizer = CountVectorizer(binary = True)   
    word_tokenizer = vectorizer.build_tokenizer()
    doc_terms_list_train = [word_tokenizer(doc_str) for doc_str in doc_str_list_train]
    term_set_fs = feature_selection.feature_selection(doc_terms_list_train, doc_class_list_train, fs_method)[:fs_num]
    
    print 'Building VSM model...'
    term_dict = dict(zip(term_set_fs, range(len(term_set_fs))))
    vectorizer.fixed_vocabulary = True
    vectorizer.vocabulary_ = term_dict
    doc_train_vec = vectorizer.fit_transform(doc_str_list_train)
    doc_test_vec= vectorizer.transform(doc_str_list_test)
    
    clf = MultinomialNB().fit(doc_train_vec, doc_class_list_train)  #調用MultinomialNB分類器
    doc_test_predicted = clf.predict(doc_test_vec)
    
    acc = np.mean(doc_test_predicted == doc_class_list_test)  
    print 'Accuracy: ', acc
    
    return acc
       

if __name__ == '__main__':
    dataset_dir_name = sys.argv[1]
    fs_method_list = ['IG', 'MI', 'WLLR']
    fs_num_list = range(25000, 35000, 1000)
    acc_dict = {}
   
    for fs_method in fs_method_list:
        acc_list = []
        for fs_num in fs_num_list:
            acc = text_classifly_twang(dataset_dir_name, fs_method, fs_num)
            acc_list.append(acc)
        acc_dict[fs_method] = acc_list
        print 'fs method:', acc_dict[fs_method]
        
    for fs_method in fs_method_list:
        plt.plot(fs_num_list, acc_dict[fs_method],  '--^',  label = fs_method)
        plt.title('feature  selection')
        plt.xlabel('fs num')
        plt.ylabel('accuracy')
        plt.ylim((0.82, 0.86))
        
    plt.legend( loc='upper left', numpoints = 1)
    plt.show()
    

  輸出的結果:

  從上面的圖看出:分類的性能隨着特徵選擇的數量的增長,呈現「凸」形趨勢:1)在特徵數量較少的狀況下,不斷增長特徵的數量,有利於提升分類器的性能,呈現「上升」趨勢;2)隨着特徵數量的不斷增長,將會引入一些不重要的特徵,甚至是噪聲,所以,分類器的性能將會呈現「降低」的趨勢。這張「凸」形趨勢體現出了特徵選擇的重要性:選擇出重要的特徵,並下降噪聲,提升算法的泛化能力。

參數文獻:

    1.Y. Yang and J. Pedersen. 1997. A comparative study on feature selection in text categorization.

    2.Shoushan Li, Rui Xia, Chengqing Zong and Chu-Ren Huang.2009.A Framework of Feature Selection Methods for Text Categorization

    3.老闆的課件

相關文章
相關標籤/搜索