日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python中文文本分类

發布時間:2023/12/10 python 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python中文文本分类 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一,中文文本分類流程:

  • 預處理
  • 中文分詞
  • 結構化表示-構建詞向量空間
  • 權重策略—TF-IDF
  • 分類器
  • 評價.
  • 二,具體實現

  • 預處理

  • 1.1 打標簽:

    對評論數據打好標簽,這里將汽車評論數據分為正面和負面兩類。假設負面標簽為0,正面標簽為1.

    1.2 整理數據集:

    一般可分為訓練集,驗證集和測試集。為什么要這么分,這篇博文給了淺顯的解釋:訓練集、驗證集和測試集的意義本試驗將數據分為訓練集和測試集兩類。

    1.3 得到訓練集預料庫:

    例如,訓練集文本的路徑:train_data/train_positive.xlsx , train_data/train_negtive.xlsx…

    1.4 得到測試集語料庫:

    例如,測試集文本的路徑:test_data/test_negtive.xlsx , test_data/test_positive.xlsx…

    2 中文分詞

    2.1 概述

    第1節預處理中的語料庫都是沒有分詞的原始語料(即連續的句子,而后面的工作需要把文本分為一個個單詞),現在需要對這些文本進行分詞,只有這樣,才能在基于單詞的基礎上,對文檔進行結構化表示。
    中文分詞有其特有的難點(相對于英文而言),最終完全解決中文分詞的算法是基于概率圖模型的條件隨機場(CRF),CRF的原理我們不細說了,直接調用中文分詞的工具,這里用的是python第三方分詞庫jieba(所采用的算法就是條件隨機場)
    關于分詞庫的更多討論可以參考這篇文章:python分詞工具推薦

    2.2 jieba分詞簡述

    首先講解jieba分詞使用方法(詳細的和更進一步的,可以參考jieba分詞原理

    jieba.cut 方法接受三個輸入參數: 需要分詞的字符串;cut_all 參數用來控制是否采用全模式;HMM 參數用來控制是否使用 HMM 模型 jieba.cut_for_search 方法接受兩個參數:需要分詞的字符串;是否使用 HMM 模型。該方法適合用于搜索引擎構建倒排索引的分詞,粒度比較細 待分詞的字符串可以是 unicode 或 UTF-8 字符串、GBK 字符串。注意:不建議直接輸入 GBK 字符串,可能無法預料地錯誤解碼成 UTF-8 jieba.cut 以及 jieba.cut_for_search 返回的結構都是一個可迭代的 generator,可以使用 for 循環來獲得分詞后得到的每一個詞語(unicode),或者用 jieba.lcut 以及 jieba.lcut_for_search 直接返回 list jieba.Tokenizer(dictionary=DEFAULT_DICT) 新建自定義分詞器,可用于同時使用不同詞典。jieba.dt 為默認分詞器,所有全局分詞相關函數都是該分詞器的映射。

    實例代碼:

    import jiebaseg_list = jieba.cut("我來到北京清華大學", cut_all=True) print("Full Mode: " + "/ ".join(seg_list)) # 全模式seg_list = jieba.cut("我來到北京清華大學", cut_all=False) print("Default Mode: " + "/ ".join(seg_list)) # 精確模式seg_list = jieba.cut("他來到了網易杭研大廈") # 默認是精確模式 print(", ".join(seg_list))seg_list = jieba.cut_for_search("小明碩士畢業于中國科學院計算所,后在日本京都大學深造") # 搜索引擎模式 print(", ".join(seg_list)) 輸出: 【全模式】: 我/ 來到/ 北京/ 清華/ 清華大學/ 華大/ 大學【精確模式】: 我/ 來到/ 北京/ 清華大學【新詞識別】:他, 來到, 了, 網易, 杭研, 大廈 (此處,“杭研”并沒有在詞典中,但是也被Viterbi算法識別出來了)【搜索引擎模式】: 小明, 碩士, 畢業, 于, 中國, 科學, 學院, 科學院, 中國科學院, 計算, 計算所, 后, 在, 日本, 京都, 大學, 日本京都大

    接下來,我們要通過python編程,來將1.3節中的 ./train_data/原始訓練語料庫和1.4節中的./test_data/原始測試語料庫進行分詞,分詞后保存的路徑可以設置為:./train_data_seg/和./test_data_seg/

    代碼如下,思路很簡單,就是將excel里面的評論數據一條一條取出來保存到DataFrame中,然后遍歷DataFrame中的文本數據,將每個文本依次進行分詞之后保存到對應路徑。

    # encoding = utf-8import sys import os import jieba import jieba.analyse import pandas as pd import xlrd import importlib from pandas import DataFrame from sklearn.datasets.base import Bunch ''' #全模式 seg_list = jieba.cut("我是一位小仙女", cut_all = True) print("Full Mode:" + "/".join(seg_list))#精確模式,cut_all 屬性不寫的話也是默認精確模式 seg_list = jieba.cut("DX7 Prime是國產汽車SUV由內到外最上乘的!", cut_all= False) print("Default Mode:" + "/".join(seg_list)) '''#保存至文件 def savefile(savepath, content):with open(savepath, "wb") as fp:fp.write(content.encode("utf-8"))# 讀取文件 def readfile(path):with open(path , 'rb') as fp:content = fp.read()return content#讀取Excel中的文件 def read_excel(path):df = pd.read_excel(path)return df#搜索引擎模式,對數據集做分詞切分 def data_segment(df):list=[]for item in df :seg = jieba.cut_for_search(item)seg_str = " ".join(seg)list.append(seg_str)dff = pd.DataFrame(list, columns=["context"])return dffdef text_segment(df, seg_path ):"""corpus_path是未分詞預料庫的路徑seg_path是分詞后語料庫的路徑"""list =[]i = 1if not os.path.exists(seg_path):os.makedirs(seg_path)for item in df:seg =jieba.cut(item)seg_str =",".join(seg)class_path = str(i)+".txt"savefile(seg_path + class_path, "".join(seg_str))i+=1if __name__ == "__main__":#訓練集df_positive = pd.read_excel('train_data/train_positive.xlsx')seg_path1 = "./train_data_seg/1/" # 分詞后分類語料庫路徑df_positive_segment = text_segment(df_positive['context'], seg_path1)df_negtive = pd.read_excel('train_data/train_negtive.xlsx')seg_path0 = "./train_data_seg/0/" #分詞后分類預料庫的路徑df_negtive_segment = text_segment(df_negtive['context'], seg_path0)#df_negtive_segment = data_segment(df_negtive['context'])#測試集test_positive = pd.read_excel('test_data/test_positive.xlsx')seg_test_path1 = "./test_data_seg/1/" #分詞后分類語料庫路徑test_positive_segment = text_segment(test_positive['context'] ,seg_test_path1)test_negtive = pd.read_excel('test_data/test_negtive.xlsx')seg_test_path0 = "./test_data_seg/0/" #分詞后分類語料庫路徑test_negtive_segment = text_segment(test_negtive['context'] , seg_test_path0)

    現在,我們已經得到了分詞后的訓練集語料庫和測試集語料庫,下面我們要把這兩個數據集表示為變量,從而為下面程序調用提供服務。我們采用的是Scikit-Learn庫中的Bunch數據結構來表示這兩個數據集。

    首先來看看Bunch:,通俗的說:

    Bunch這玩意兒,其實就相當于python中的字典。你往里面傳什么,它就存什么。

    接下來,讓我們看看的我們的數據集(訓練集)有哪些信息:

    1,類別,也就是所有分類類別的集合,即我們./train_data_seg/和./test_data_seg/下的所有子目錄的名字。我們在這里不妨把它叫做target_name(這是一個列表)2,文本文件名。例如./train_data_seg/0/1.txt,我們可以把所有文件名集合在一起做一個列表,叫做filenames3,文本標簽(就是文本的類別),不妨叫做label(與2中的filenames相對應)例如2中的文本“1.txt”在./train_data_seg/0/目錄下,則它的標簽就是0。文本標簽與1中的類別區別在于:文本標簽集合里面的元素就是1中類別,而文本標簽集合的元素是可以重復的,因為./train_data_seg/0/目錄下有好多文本,不是嗎?相應的,1中的類別集合元素顯然都是獨一無二的類別。4,文本內容(contens)。上一步代碼我們已經成功的把文本內容進行了分詞,并且去除掉了所有的換行,得到的其實就是一行詞袋。

    那么,用Bunch表示,就是:

    from sklearn.datasets.base import Bunch
    bunch = Bunch(target_name=[],label=[],filenames=[],contents=[])

    我們在Bunch對象里面創建了有4個成員:
    target_name:是一個list,存放的是整個數據集的類別集合。
    label:是一個list,存放的是所有文本的標簽。
    filenames:是一個list,存放的是所有文本文件的名字。
    contents:是一個list,分詞后文本文件(一個文本文件只有一行)

    代碼實現:

    # -*- coding: UTF-8 -*- #數據集的變量表示 from Jieba import data_segment as ds from sklearn.datasets.base import Bunch import os import sys import pandas as pd import pickledef _readfile(path):with open(path, "r" ,encoding="utf-8") as fp:content = fp.read()return contentdef data2Bunch(wordbag_path, seg_path):catelist = os.listdir(seg_path) #獲取seg_path所有的子目錄,也就是分類信息#print(catelist)#創建一個Bunchshilibunch = Bunch(target_name=[], label=[], filenames=[],contents=[])#print(bunch)bunch.target_name.extend(catelist)'''extend(addlist)是python list中的函數,意思是用新的list(addlist)去擴充原來的list'''#獲取每個目錄下的所有文件for mydir in catelist:class_path = seg_path + mydir +"/" #拼出分類子目錄的路徑file_list =os.listdir(class_path) #獲取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)) #讀取文件的內容'''append(element)是python list中的函數,向原來的list中添加element'''#將bunch存儲到wordbag_path路徑中#print(bunch.contents)if not os.path.exists(wordbag_path): # 如果沒有這個路徑就先創建出來os.makedirs(wordbag_path)with open(wordbag_path, "wb" ) as file_obj:pickle.dump(bunch, file_obj , 0)if __name__ == "__main__":#對訓練集進行Bunch化操作wordbag_path = "train_word_bag/train_set1.dat" #Bunch存儲路徑seg_path = "train_data_seg/"data2Bunch(wordbag_path, seg_path)#對測試集進行Bunch化操作wordbag_path = "test_word_bag/test_set.dat" #Bunch存儲路徑seg_path = "test_data_seg/"data2Bunch(wordbag_path, seg_path)

    3,結構化表示–向量空間模型

    在第2節中,我們對原始數據集進行了分詞處理,并且通過綁定為Bunch數據類型,實現了數據集的變量表示。詞向量并沒有清晰的概念,簡單來講,詞向量就是詞向量空間里面的一個向量。這里有一篇非常棒的文章《Deep Learning in NLP (一)詞向量和語言模型》

    你可以類比為三維空間里面的一個向量,例如:

    如果我們規定詞向量空間為:(我,喜歡,相國大人),這相當于三維空間里面的(x,y,z)只不過這里的x,y,z的名字變成了“我”,“喜歡”,“相國大人”

    現在有一個詞向量是:我 喜歡 喜歡相國大人

    表示在詞向量空間中就變為:(1,2,1),歸一化后可以表示為:(0.166666666667 0.333333333333 0.166666666667)表示在剛才的詞向量空間中就是這樣:

    接下來我們要做的,就是把所有這些詞統一到同一個詞向量空間中。

    為了節省空間,我們首先將訓練集中每個文本中一些垃圾詞匯去掉。所謂的垃圾詞匯,就是指意義模糊的詞,或者一些語氣助詞,標點符號等等,通常他們對文本起不了分類特征的意義。這些垃圾詞匯我們稱之為停用詞。把所有停用詞集合起來構成一張停用詞表格,這樣,以后我們處理文本時,就可以從這個根據表格,過濾掉文本中的一些垃圾詞匯了。
    下面的程序,目的就是要將訓練集所有文本文件統一到同一個詞向量空間中。

    下面的一節主要目標是希望得到兩個東西:

    1.詞典(單詞和單詞對應的序號)

    2.權重矩陣tdm,其中,權重矩陣是一個二維矩陣,tdm[i][j]表示,第j個詞(即詞典中的序號)在第i個類別中的IF-IDF值(下文有講解)。

    事實上,tdm的每一列都是一個單詞在各個類別中的全職。我們把這每一列當作詞向量。

    4,權重策略–TF-IDF

    什么是TF-IDF?今后有精力我會在這里更新補充,現在,先給你推薦一篇非常棒的文章《使用scikit-learn工具計算文本TF-IDF值》
    下面,我們假定你已經對TF-IDF有了最基本的了解。請你動動你的小腦袋瓜想一想,我們把訓練集文本轉換成了一個TF-IDF詞向量空間,姑且叫它為A空間吧。那么我們還有測試集數據,我們以后實際運用時,還會有新的數據,這些數據顯然也要轉到詞向量空間,那么應該和A空間為同一個空間嗎?

    是的。

    即使測試集出現了新的詞匯(不是停用詞),即使新的文本數據有新的詞匯,只要它不是訓練集生成的TF-IDF詞向量空間中的詞,我們就都不予考慮。這就實現了所有文本詞向量空間“大一統”,也只有這樣,大家才在同一個世界里。才能進行下一步的研究。

    下面的程序就是要將訓練集所有文本文件(詞向量)統一到同一個TF-IDF詞向量空間中(或者叫做用TF-IDF算法計算權重的有權詞向量空間)。這個詞向量空間最終存放在train_word_bag/tfdifspace.dat中。

    這段代碼你可能有點看不懂,因為我估計你可能比較懶,還沒看過TF-IDF(盡管我剛才已經給你推薦那篇文章了)。你只需要明白,它把一大坨訓練集數據成功的構建了一個TF-IDF詞向量空間,空間的各個詞都是出自這個訓練集(去掉了停用詞)中,各個詞的權值也都一并保存了下來,叫做權重矩陣。

    需要注意的是,你要明白,權重矩陣是一個二維矩陣,a[i][j]表示,第j個詞在第i個類別中的IF-IDF值(看到這里,我估計你壓根就沒去看那篇文章,所以你可能到現在也不知道 這是個啥玩意兒。。。)

    請記住權重矩陣這個詞,代碼解釋中我會用到。

    # -*- coding: UTF-8 -*-import os import sys from scikit_Bunch import Bunch from sklearn.feature_extraction.text import TfidfVectorizerimport pickle#讀取文件 def _readfile(path):with open(path, "r" ,encoding="utf-8") as fp:content = fp.read()return content#讀取bunch對象 def _readbunchobj(path):with open(path, "rb" ) as file_obj:bunch = pickle.load(file_obj)return bunch#寫入bunch對象 def _writebunchobj(path, bunch_obj):with open(path, "wb") as file_obj:pickle.dump(bunch_obj, file_obj, 0)#這個函數用于創建TF-IDF詞向量空間 def Vector_Space(stopWords_path, bunch_path, space_path, train_tfidf_path = None):stopWords = _readfile(stopWords_path).splitlines() #讀取停用詞stopWords[0] = "???"bunch = _readbunchobj(bunch_path) #導入分詞后的詞向量bunch對象# 構建tf-idf詞向量空間對象tfidfspace = Bunch(target_name=bunch.target_name, label=bunch.label, filenames=bunch.filenames, tdm=[], vocabulary={})'''與下面這2行代碼等價的代碼是:vectorizer=CountVectorizer()#構建一個計算詞頻(TF)的玩意兒,當然這里面不只是可以做這些transformer=TfidfTransformer()#構建一個計算TF-IDF的玩意兒tfidf=transformer.fit_transform(vectorizer.fit_transform(corpus))#vectorizer.fit_transform(corpus)將文本corpus輸入,得到詞頻矩陣#將這個矩陣作為輸入,用transformer.fit_transform(詞頻矩陣)得到TF-IDF權重矩陣看名字你也應該知道:TfidfTransformer + CountVectorizer = TfidfVectorizer下面的代碼一步到位,把上面的兩個步驟一次性全部完成值得注意的是,CountVectorizer()和TfidfVectorizer()里面都有一個成員叫做vocabulary_(后面帶一個下劃線)這個成員的意義,與我們之前在構建Bunch對象時提到的自己定義的那個vocabulary的意思是一樣的,只不過一個是私有成員,一個是外部輸入,原則上應該保持一致。創建tfidfspace中定義的vocabulary就應該被賦值為這個vocabulary_'''#構建一個快樂地一步到位的玩意兒,專業一點兒叫做:使用TfidfVectorizer初始化向量空間模型#這里面有TF-IDF權重矩陣還有我們要的詞向量空間坐標軸信息vocabulary_if train_tfidf_path is not None:trainbunch = _readbunchobj(train_tfidf_path)tfidfspace.vocabulary = trainbunch.vocabularyvectorizer = TfidfVectorizer(stop_words=stopWords, sublinear_tf=True,max_df=0.5, vocabulary=trainbunch.vocabulary,analyzer='word',token_pattern=u"(?u)\\b\\w+\\b")# 此時tdm里面存儲的就是if-idf權值矩陣print(bunch.contents)#print("gggggggggg")tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)'''stop_words:參數是用來傳入停用詞,以后我們獲得vocabulary_的時候,就會根據文本信息去掉停用詞得到sublinear_tf:計算tf值采用亞線性策略。比如,我們以前算tf是詞頻,現在用1+log(tf)來充當詞頻。smooth_idf:計算idf的時候log(分子/分母)分母有可能是0,smooth_idf會采用log(分子/(1+分母))的方式解決。默認已經開啟,無需關心。norm:歸一化,我們計算TF-IDF的時候,是用TF*IDF,TF可以是歸一化的,也可以是沒有歸一化的,一般都是采用歸一化的方法,默認開啟.max_df:有些詞,他們的文檔頻率太高了(一個詞如果每篇文檔都出現,那還有必要用它來區分文本類別嗎?當然不用了呀),所以,我們可以設定一個閾值,比如float類型0.5(取值范圍[0.0,1.0]),表示這個詞如果在整個數據集中超過50%的文本都出現了,那么我們也把它列為臨時停用詞。當然你也可以設定為int型,例如max_df=10,表示這個詞如果在整個數據集中超過10的文本都出現了,那么我們也把它列為臨時停用詞。min_df:與max_df相反,雖然文檔頻率越低,似乎越能區分文本,可是如果太低,例如10000篇文本中只有1篇文本出現過這個詞,僅僅因為這1篇文本,就增加了詞向量空間的維度,太不劃算。當然,max_df和min_df在給定vocabulary參數時,就失效了。'''else:vectorizer = TfidfVectorizer(stop_words=stopWords, sublinear_tf=True, max_df=0.5, analyzer='word',token_pattern=u"(?u)\\b\\w+\\b")tfidfspace.tdm = vectorizer.fit_transform(bunch.contents)tfidfspace.vocabulary = vectorizer.vocabulary_print(tfidfspace)print("666666666666")_writebunchobj(space_path, tfidfspace)if __name__ == '__main__':#訓練集stopword_path = "train_word_bag/stop_words.txt"#停用詞表的路徑bunch_path = "train_word_bag/train_set1.dat" #導入訓練集Bunch的路徑space_path = "train_word_bag/tfdifspace.dat" # 詞向量空間保存路徑Vector_Space(stopword_path, bunch_path, space_path)#測試集bunch_path = "test_word_bag/test_set.dat" #導入測試集Bunch的路徑space_path = "test_word_bag/testspace.dat" #測試集詞向量保存路徑train_tfidf_path = "train_word_bag/tfdifspace.dat"Vector_Space(stopword_path, bunch_path, space_path , train_tfidf_path)

    上面的代碼運行之后,會將訓練集數據轉換為TF-IDF詞向量空間中的實例,保存在train_word_bag/tfdifspace.dat中,具體來說,這個文件里面有兩個我們感興趣的東西,一個是vocabulary,即詞向量空間坐標,一個是tdm,即訓練集的TF-IDF權重矩陣。

    接下來,我們要開始第5步的操作,設計分類器,用訓練集訓練,用測試集測試。在做這些工作之前,你一定要記住,首先要把測試數據也映射到上面這個TF-IDF詞向量空間中,也就是說,測試集和訓練集處在同一個詞向量空間(vocabulary相同),只不過測試集有自己的tdm,與訓練集(train_word_bag/tfdifspace.dat)中的tdm不同而已。

    同一個世界,同一個夢想。

    至于說怎么弄,請看下節。

    5,分類器

    這里我們采用的是樸素貝葉斯分類器,今后我們會詳細講解它。

    現在,你即便不知道這是個啥玩意兒,也一點不會影響你,這個分類器我們有封裝好了的函數,MultinomialNB,這玩意兒獲取訓練集的權重矩陣和標簽,進行訓練,然后獲取測試集的權重矩陣,進行預測(給出預測標簽)。

    from sklearn.naive_bayes import MultinomialNB #導入多項式貝葉斯算法 from sklearn import metrics import pickle from sklearn.feature_extraction.text import TfidfVectorizer#讀取bunch對象 def _readbunchobj(path):with open(path, "rb") as file_obj:bunch = pickle.load(file_obj)return bunch#導入訓練集 trainpath = "train_word_bag/tfdifspace.dat" train_set =_readbunchobj(trainpath) print(train_set.tdm.shape)#導入測試集 testpath = "test_word_bag/testspace.dat" test_set = _readbunchobj(testpath) print(test_set.tdm.shape)# 訓練分類器:輸入詞袋向量和分類標簽,alpha:0.001 alpha越小,迭代次數越多,精度越高 clf = MultinomialNB(alpha=0.001).fit(train_set.tdm, train_set.label)#之前報訓練集和測試集維度不匹配,predict方法出錯,百度搜到的解決辦法,然而并沒有什么鬼用的三行 # vectorizer = TfidfVectorizer() # fea_train = vectorizer.fit_transform(train_set) # fea_test = vectorizer.transform(test_set)#預測分類結果,輸出是測試訓練集預測出來的標簽列表 predicted = clf.predict(test_set.tdm)for flabel, file_name, expct_cate in zip(test_set.label, test_set.filenames, predicted):if flabel != expct_cate:print(file_name, ": 實際類別:", flabel, " -->預測類別:", expct_cate)# 計算分類精度: def metrics_result(actual, predict):print('精度:{0:.3f}'.format(metrics.precision_score(actual, predict, average='weighted')))print('召回:{0:0.3f}'.format(metrics.recall_score(actual, predict, average='weighted')))print('f1-score:{0:.3f}'.format(metrics.f1_score(actual, predict, average='weighted')))metrics_result(test_set.label, predicted)

    當然,你也可以采用其他分類器,比如KNN

    總結

    以上是生活随笔為你收集整理的python中文文本分类的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。