資訊增益(IG)特徵提取例項

破棉襖發表於2016-01-28


最近在做貝葉斯文字多分類,記錄一下特徵提取的過程:


如果你對TF、DF、IDF不懂:
Term Frequency:term 在文件d中的出現次數,記做tf。tf越高,意味著term 對於文件d 就越重要。
Document Frequency:含有term 的文件的數量,記做df。df越高,意味著term在衡量文件之間相似性方面作用越低,比如“的”的df值肯定非常高,因此不具有區別性,這類詞稱為“非焦點詞”。
Inverse Document Frequency:跟df形成“反比關係”,IDF =log(N/df)值越高,意味著term對於文件的區別意義越大。N為全部文件的數量。如果term 僅出現在一個文件中,idf=logN,如果一個專案出現在所有文件中,idf= log1 = 0


為何要進行資訊增益:(直接引用其他博文的原話)
TF-IDF可以有效評估一字詞對於一個檔案集或一個語料庫中的其中一份檔案的重要程度。因為它綜合表徵了該詞在文件中的重要程度和文件區分度。但在文字分類中單純使用TF-IDF來判斷一個特徵是否有區分度是不夠的。
1)它沒有考慮特徵詞在類間的分佈。也就是說該選擇的特徵應該在某類出現多,而其它類出現少,即考察各類的文件頻率的差異。如果一個特徵詞,在各個類間分佈比較均勻,這樣的詞對分類基本沒有貢獻;但是如果一個特徵詞比較集中的分佈在某個類中,而在其它類中幾乎不出現,這樣的詞卻能夠很好代表這個類的特徵,而TF-IDF不能區分這兩種情況。
2)沒有考慮特徵詞在類內部文件中的分佈情況。在類內部的文件中,如果特徵詞均勻分佈在其中,則這個特徵詞能夠很好的代表這個類的特徵,如果只在幾篇文件中出現,而在此類的其它文件中不出現,顯然這樣的特徵詞不能夠代表這個類的特徵。


步驟:
1. python jieba 關鍵詞提取、去停用詞
2.根據提取的關鍵詞計算分別對應每種類別文章的df
3.進行資訊增益特徵提取


關鍵詞提取、去停用詞:

  1. #encoding=utf-8
  2. import jieba
  3. import jieba.analyse
  4. import sys
  5. import os

  6. #判斷是否為中文
  7. def is_chinese(uchar):
  8.         if uchar >= u'\u4e00' and uchar<=u'\u9fa5':
  9.                 return True
  10.         else:
  11.                 return False

  12. #停用詞載入
  13. stopwords = {}.fromkeys([ line.rstrip() for line in open('/usr/wzx/spark/svm/SVM_WZX_lib/stopword.dic') ])
  14. #結果集
  15. resultFile = file("/usr/wzx/spark/bayes/resu",'w')

  16. #訓練集根目錄
  17. base_dir = '/usr/wzx/spark/bayes/train'
  18. list = os.listdir(base_dir)
  19. #檔案集合
  20. filelist = []
  21. for i in range(0, len(list)):
  22.     path = os.path.join(base_dir,list[i])
  23.     lis = os.listdir(path)
  24.     for j in range(0,len(lis)):
  25.         filepath = os.path.join(path,lis[j])
  26.         filelist.append(filepath)

  27. #迴圈讀取檔案進行特徵詞提取
  28. for i in range(0,len(filelist)):
  29.     f = open(filelist[i])
  30.     line = f.readline()
  31.     while line:
  32.        segs = jieba.cut(line,cut_all=False)
  33.        final = ''
  34.        for seg in segs:
  35.           segS = seg.encode('utf-8')
  36.           if segS not in stopwords and is_chinese(seg) and len(segS)>3:
  37.              final += ' '+seg

  38.        seg_list = jieba.analyse.extract_tags(final,5)
  39.        tem = " ".join(seg_list).encode('utf-8')
  40.        resultFile.writelines(tem+' ')
  41.        line = f.readline()

  42. resultFile.close()

資訊增益:

  1. #encoding=utf-8
    import sys
    import os
    import math


    def IG_count(c1,c2,c3,c4):
        list1 = []
        list2 = []
        list3 = []
        dict1 = dict()
        ig_dict = dict()

  2.     class_count = 4
        doc_count = 2400
        
        c1_file = open(c1,"r")
        #c1_word_sets = c1_file.read()
        for line in c1_file:
            list1.append(line.split(" "))        
        
        c2_file = open(c2,"r")
        for line in c2_file:
            list1.append(line.split(" "))


        c3_file = open(c3,"r")
        for line in c3_file:
            list1.append(line.split(" "))


        c4_file = open(c4,"r")
        for line in c4_file:
            list1.append(line.split(" "))

        #計算word-doc—count矩陣
        for i in list1:
            if dict1.get(i[1]) == None:
                list2 = list()
                if i[2] == None:
                    list2.insert((int)(i[0]) - 1,0)
                else:                
                    list2.insert((int)(i[0]) - 1,(int)(i[2]))
                dict1[i[1]] = list2
            else:
                if i[2] == None:
                    dict1[i[1]].insert((int)(i[0]) - 1,0)
                else:                
                    dict1[i[1]].insert((int)(i[0]) - 1,(int)(i[2]))


        #計算每個Word的資訊增益IG並儲存到dit中
        print "word-doc—count矩陣"                
        for dict_cont in dict1.keys():
            #print dict_cont,dict1[dict_cont][0],dict1[dict_cont][1]

            t= class_count
            entropy = class_count * 1/class_count * math.log(t,2);
            wcount = 0 # // 出現word的文件的文件數量

            category_doc_count = doc_count/class_count #每個類別中的文件數量
            wcount_class = [0 for i in range(class_count)] #// 每個類別中出現單詞word的文件數

            pw = 0.0# // 出現word的文件佔全部文件的比重
            pcw = [0 for i in range(class_count)]# // 在單詞word出現時各個類別中文件數佔總文件數的比重
            pcw_b = [0 for i in range(class_count)]#// 在單詞word不出現時各個類別中文件數佔總文件數的比重
            #listabc = [0 for i in range(100)] or [0] * 100

            for i in range(0,class_count):  
                num = dict1[dict_cont][i]
                wcount_class[i] = num
                wcount += num
         
            #print wcount, dict_cont   
            #print wcount, wcount_class

            pw = 1.0 * wcount / doc_count;
            for i in range(0,class_count):
                    pcw[i] = 1.0 * wcount_class[i] / wcount;
                    #print doc_count, wcount
                    pcw_b[i] = 1.0 * (category_doc_count - wcount_class[i])/ (doc_count - wcount);


            d1 = 0.0;
            d2 = 0.0;


            for i in range(0,class_count):
                    #print pcw[i],pcw_b[i]
                    if pcw[i] == 0:
                            t1 = 0
                    else:
                            t1 = math.log(pcw[i],2)                        
                    d1 += pcw[i] * t1;
                    if pcw_b[i] == 0:
                            t2 = 0
                    else:
                            t2 = math.log(pcw_b[i],2)
                    d2 += pcw_b[i] * t2;


            ig = entropy + pw * d1 + (1.0 - pw) * d2;
            ig_dict[dict_cont] = ig
                
            
        #儲存資訊增益資訊
        #print "word IG"
        #for dict_cont in ig_dict.keys():
        #    print dict_cont,ig_dict[dict_cont]

        #print "sort word IG"
        num = 0
        word_dicts_list = sorted([(v, k) for k, v in ig_dict.items()], reverse=True)
        wzx_f = open('/usr/wzx/spark/bayes/result_gain','w')
        wzx_f_temp = open('/usr/wzx/spark/bayes/result_gain_temp','w')
        for i in word_dicts_list:
            wzx_f.write(i[1]+' ')
            wzx_f_temp.write(i[1]+' '+str(i[0])+' \n')
            num = num+1
        wzx_f.close()                 
        wzx_f_temp.close()       
        print(num)

        c1_file.close()
        c2_file.close()
        c3_file.close()
        c4_file.close()


    #---------我是開心快樂的分割線-----------


    #獲取全部關鍵詞
    all_the_text = open('/usr/wzx/spark/bayes/resu').read()
    arrText = all_the_text.split(' ')
    fileLocalNames=os.listdir('/usr/wzx/spark/bayes/train')
    for fn in fileLocalNames: 
      #建立類別檔案
      f=open('/usr/wzx/spark/bayes/gain/'+fn,'w')
      #開啟該類別檔案讀取獲取DF
      f2 = open('/usr/wzx/spark/bayes/train/'+fn+'/'+fn+'.txt')
      wzxDict = {}
      #遍歷關鍵詞新增到字典,並初始化為0
      for temKey in arrText:
         wzxDict[temKey] = 0
      line = f2.readline()
      while line:
         for te in wzxDict.keys():
           if te in line:
             wzxDict[te] = wzxDict[te] + 1     


         line = f2.readline()
      #將dict中的資料插入到檔案中
      for k in wzxDict.keys():
         if k.strip()!='':
            f.write(fn+' '+k+' '+str(wzxDict[k])+'\n')
      f2.close()
      f.close()


    wzxLocal='/usr/wzx/spark/bayes/gain/'
    IG_count(wzxLocal+fileLocalNames[0],wzxLocal+fileLocalNames[1],wzxLocal+fileLocalNames[2],wzxLocal+fileLocalNames[3])



OK,根據提取的特徵將文字向量化即可進行貝葉斯分類,向量維度即特徵個數

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/29754888/viewspace-1983595/,如需轉載,請註明出處,否則將追究法律責任。

相關文章