首頁  >  文章  >  後端開發  >  使用python實作一個小型的文本分類系統

使用python實作一個小型的文本分類系統

高洛峰
高洛峰原創
2017-03-27 15:02:454237瀏覽

背景

文本探勘是指從大量文本資料中抽取實現未知的、可理解的、最終可用的知識的過程,同時運用這些知識更好地組織資訊以便將來參考。即從非結構化的文本中尋找知識的過程。

目前文本探勘主要有7個主要領域:

  • · 搜尋與資訊檢索IR

  • · 文字聚類:使用聚類方法對詞彙、片段、段落或文件進行分組和歸類

  • #· 文本分類:將片段、段落或文件分組和歸類,在使用資料探勘分類方法的基礎上,經過訓練地標記實例模型

  • · Web挖掘:在互聯網上進行資料和文字挖掘,病特別關注網路的規模和相互聯繫

  • · 資訊抽取IE:從非結構文本中識別和抽取有關的事實和關係;從非結構化或半結構化的文本中抽取結構化的抽取出結構化資料的過程

  • · 自然語言處理NLP:從語法、語意的角度發現語言本質的結構和所表達的意義

文字分類系統(python 3.5)

中文語言的文字分類技術和流程,主要包括下面幾個步驟:
1. 預處理:移除文字雜訊訊息,例如HTML標籤,文字格式轉換,偵測句子邊界

2. 中文分詞:使用中文分詞器為文字分詞,並移除停用詞

3. 建構詞向量空間:統計文本詞頻,產生文本的詞向量空間

4. 權重策略-TF-IDF:使用TF-IDF發現特徵詞,並抽取為反映文件主題的特徵

5. 分類詞:使用演算法訓練分類器

6. 評估分類結果

1. 預處理

a. 選擇處理文字的範圍

b. 建立分類文字語料庫

  • · 訓練集語料

已經分好類別的文字資源

  • · 測試集語料

待分類的文本語料,可以使訓練集的一部分,也可以是外部來源的文本語料

c. 文本格式轉換:使用Python的lxml庫去除html標籤

d. 偵測句子邊界:標記句子的結束

2. 中文分詞

#分詞是將連續的字序列按照一定的規範重新組合成詞序列的過程,中文分詞即將一個漢字序列(句子)切分成一個個獨立的單詞,中文分詞很複雜,從某種程度上並不完全是一個演算法問題,最終機率論解決了這個問題,演算法是基於機率圖模型的條件隨機場(CRF)

分詞是自然語言處理中最基本,最底層的模組,分詞精確度對後續應用模組的影響很大,文字或句子的結構化表示是語言處理中最核心的任務,目前文本的結構化表示分為四大類:詞向量空間、主體模型、依存句法的樹表示、 RDF的圖表示。

下面給出中文字的範例程式碼:

# -*- coding: utf-8 -*-import os
import jieba
def savefile(savepath, content):
    fp = open(savepath,"w",encoding='gb2312', errors='ignore')
    fp.write(content)
    fp.close()
def readfile(path):
    fp = open(path,"r", encoding= 'gb2312', errors='ignore')
    content = fp.read()
    fp.close()
    returncontent
## "train_small/"  # 未分詞分類預料庫路徑
# seg_path = "train_seg/"  # 分詞後分類語料庫路徑corpus_path = "test_small/"  # 未分詞分類預料庫路徑seg_path = "test_seg/"  # 分詞後分類語料庫路徑catelist = os.listdir(corpus_path)  # 取得變更目錄下所有子目錄for mydir in catelist:
    class_path = corpus_path + mydir + "/" # 拼出分類子目錄#的路徑
    seg_dir = seg_path + mydir + "/"  # 拼出分詞後預料分類目錄
    if not os.path.exists(seg_dir): 
if
not os.path.exists(seg_dir): # #if
not os.path.
        os.makedirs(seg_dir)
    file_list = os.listdir(class_path)    for file_pathin file_list:##  content = readfile(fullname).strip()  #讀取檔案
內容
        content = content.replace("\r\n", "").strip()  #移除換行和多餘的空格
        content_seg = jieba.cut(content)
        savefile(seg_dir + file_path, " ".join(content_seg))print

("分詞結束")

為了後續生成詞向量空間模型的方便,這些分詞後的文字資訊還要轉換成文字向量資訊並物件化,利用了Scikit-Learn庫的Bunch資料結構,具體程式碼如下:

import os
import pickle
from sklearn.datasets.base import Bunch
#Bunch 类提供了一种key,value的对象形式
#target_name 所有分类集的名称列表
#label 每个文件的分类标签列表
#filenames 文件路径
#contents 分词后文件词向量形式def readfile(path):
    fp = open(path, "r", encoding='gb2312', errors='ignore')
    content = fp.read()
    fp.close()
    return content
bunch=Bunch(target_name=[],label=[],filenames=[],contents=[])
# wordbag_path="train_word_bag/train_set.dat"
# seg_path="train_seg/"wordbag_path="test_word_bag/test_set.dat"seg_path="test_seg/"catelist=os.listdir(seg_path)
bunch.target_name.extend(catelist)#将类别信息保存到Bunch对象for mydir in catelist:
    class_path=seg_path+mydir+"/"
    file_list=os.listdir(class_path)
    for file_path in file_list:
        fullname=class_path+file_path
        bunch.label.append(mydir)#保存当前文件的分类标签
        bunch.filenames.append(fullname)#保存当前文件的文件路径
        bunch.contents.append(readfile(fullname).strip())#保存文件词向量
#Bunch对象持久化file_obj=open(wordbag_path,"wb")
pickle.dump(bunch,file_obj)
file_obj.close()
print("构建文本对象结束")
3.向量空間模型

由於文字在儲存未向量空間是維度較高,為節省儲存空間和提高搜尋效率,在文字分類之前會自動過濾

掉某些字詞,這些字或詞稱為停用詞,停用此表可以到點這裡下載。

4. 權重策略:TF-IDF方法

如果某個字或片語在一篇文章中出現的頻率高,並且在其他文章中很少出現,那麼認為這個詞或短語具有很好的類別區分能力,適合用來分類。

再給這部分程式碼之前,我們先來看詞頻和逆向檔案頻率的概念

詞頻(TF):指的是某一個給定的字詞在該檔案中出現的頻率。這個數字是詞數的歸一化,以防止它偏向長的文件,對於某一個特定文件裡的詞語來說,它的重要性可表示為:

分子是該詞在文件中出現的次數,分母是在文件中所有字詞的出現次數之和

逆向文件頻率(IDF)是一個詞語普遍重要性的度量,某一特定詞語的IDF,可以由總文件數目除以包含該詞語的文件的數目,再將得到的商取對數:

|D|是語料庫中的文件總數,j是包含詞語的文件數目,如果該詞語不在語料庫中,就會導致分母為零,因此一般情況下分母還要額外再加上1

之後計算詞頻和逆向文件頻率的乘積,某一特定文件內的高詞語頻率,以及該詞語在整個檔案集合中的低檔案頻率,可以產生出高權重的TF-IDF,因此TF-IDF傾向於過濾掉常見的字詞,保留重要的字詞。程式碼如下:

import os
from sklearn.datasets.base import Bunch
import pickle#持久化类from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer#TF-IDF向量转换类from sklearn.feature_extraction.text import TfidfVectorizer#TF-IDF向量生成类def readbunchobj(path):
    file_obj=open(path,"rb")
    bunch=pickle.load(file_obj)
    file_obj.close()
    return bunch
def writebunchobj(path,bunchobj):
    file_obj=open(path,"wb")
    pickle.dump(bunchobj,file_obj)
    file_obj.close()
def readfile(path):
    fp = open(path, "r", encoding='gb2312', errors='ignore')
    content = fp.read()
    fp.close()
    return content
path="train_word_bag/train_set.dat"bunch=readbunchobj(path)
#停用词stopword_path="train_word_bag/hlt_stop_words.txt"stpwrdlst=readfile(stopword_path).splitlines()
#构建TF-IDF词向量空间对象tfidfspace=Bunch(target_name=bunch.target_name,label=bunch.label,filenames=bunch.filenames,tdm=[],vocabulary={})
#使用TfidVectorizer初始化向量空间模型vectorizer=TfidfVectorizer(stop_words=stpwrdlst,sublinear_tf=True,max_df=0.5)
transfoemer=TfidfTransformer()#该类会统计每个词语的TF-IDF权值
#文本转为词频矩阵,单独保存字典文件tfidfspace.tdm=vectorizer.fit_transform(bunch.contents)
tfidfspace.vocabulary=vectorizer.vocabulary_
#创建词袋的持久化space_path="train_word_bag/tfidfspace.dat"writebunchobj(space_path,tfidfspace)
5.使用樸素貝葉斯分類模組

常用的文字分類方法有kNN最近鄰法,樸素貝葉斯演算法和支援向量機演算法,一般而言:

kNN演算法原來最簡單,分類精度尚可,但是速度最快支

樸素貝葉斯演算法對於短文本分類的效果最好,精度很高

支援向量機演算法的優點是支援線性不可分的情況,精確度上取中###

上文代码中进行操作的都是训练集的数据,下面是测试集(抽取字训练集),训练步骤和训练集相同,首先是分词,之后生成词向量文件,直至生成词向量模型,不同的是,在训练词向量模型时需要加载训练集词袋,将测试集产生的词向量映射到训练集词袋的词典中,生成向量空间模型,代码如下:

import os
from sklearn.datasets.base import Bunch
import pickle#持久化类from sklearn import feature_extraction
from sklearn.feature_extraction.text import TfidfTransformer#TF-IDF向量转换类from sklearn.feature_extraction.text import TfidfVectorizer#TF-IDF向量生成类from TF_IDF import space_path
def readbunchobj(path):
    file_obj=open(path,"rb")
    bunch=pickle.load(file_obj)
    file_obj.close()
    return bunch
def writebunchobj(path,bunchobj):
    file_obj=open(path,"wb")
    pickle.dump(bunchobj,file_obj)
    file_obj.close()
def readfile(path):
    fp = open(path, "r", encoding='gb2312', errors='ignore')
    content = fp.read()
    fp.close()
    return content
#导入分词后的词向量bunch对象path="test_word_bag/test_set.dat"bunch=readbunchobj(path)
#停用词stopword_path="train_word_bag/hlt_stop_words.txt"stpwrdlst=readfile(stopword_path).splitlines()
#构建测试集TF-IDF向量空间testspace=Bunch(target_name=bunch.target_name,label=bunch.label,filenames=bunch.filenames,tdm=[],vocabulary={})
#导入训练集的词袋trainbunch=readbunchobj("train_word_bag/tfidfspace.dat")
#使用TfidfVectorizer初始化向量空间vectorizer=TfidfVectorizer(stop_words=stpwrdlst,sublinear_tf=True,max_df=0.5,vocabulary=trainbunch.vocabulary)
transformer=TfidfTransformer();
testspace.tdm=vectorizer.fit_transform(bunch.contents)
testspace.vocabulary=trainbunch.vocabulary
#创建词袋的持久化space_path="test_word_bag/testspace.dat"writebunchobj(space_path,testspace)

下面执行多项式贝叶斯算法进行测试文本分类并返回精度,代码如下:

import pickle
from sklearn.naive_bayes import MultinomialNB  # 导入多项式贝叶斯算法包
def readbunchobj(path):
    file_obj = open(path, "rb")
    bunch = pickle.load(file_obj)
    file_obj.close()
    return bunch
# 导入训练集向量空间trainpath = "train_word_bag/tfidfspace.dat"train_set = readbunchobj(trainpath)
# d导入测试集向量空间testpath = "test_word_bag/testspace.dat"test_set = readbunchobj(testpath)
# 应用贝叶斯算法
# alpha:0.001 alpha 越小,迭代次数越多,精度越高clf = MultinomialNB(alpha=0.001).fit(train_set.tdm, train_set.label)
# 预测分类结果predicted = clf.predict(test_set.tdm)
total = len(predicted);rate = 0
for flabel, file_name, expct_cate in zip(test_set.label, test_set.filenames, predicted):
    if flabel != expct_cate:
        rate += 1
        print(file_name, ": 实际类别:", flabel, "-->预测分类:", expct_cate)
# 精度print("error_rate:", float(rate) * 100 / float(total), "%")

6.分类结果评估

机器学习领域的算法评估有三个基本指标:

  • · 召回率(recall rate,查全率):是检索出的相关文档数与文档库中所有相关文档的比率,衡量的是检索系统的查全率

召回率=系统检索到的相关文件/系统所有相关的文件综述

  • · 准确率(Precision,精度):是检索出的相关文档数于检索出的文档总数的比率,衡量的是检索系统的查准率

准确率=系统检索到的相关文件/系统所有的检索到的文件数

准确率和召回率是相互影响的,理想情况下是二者都高,但是一般情况下准确率高,召回率就低;召回率高,准确率就低

  • · F-Score():计算公式为:

当=1时就是最常见的-Measure

三者关系如下:

具体评估代码如下:

import numpy as np
from sklearn import metrics
#评估def metrics_result(actual,predict):
    print("精度:{0:.3f}".format(metrics.precision_score(actual,predict)))
    print("召回:{0:0.3f}".format(metrics.recall_score(actual,predict)))
    print("f1-score:{0:.3f}".format(metrics.f1_score(actual,predict)))
metrics_result(test_set.label,predicted)
中文文本语料
中文停用词文本集合
工程全部代码
原文链接

以上是使用python實作一個小型的文本分類系統的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn