本次受華師和武大研會共同舉辦的“python訓(xùn)練營”之邀,來給大家做一期“python數(shù)據(jù)分析”主題的分享。疫情期間,研會的朋友為大家組織一次python訓(xùn)練營也是十分的不容易,那我這次就盡量把我所掌握的分享給大家,不過較為基礎(chǔ),大佬繞道哈哈!本次分享的內(nèi)容以這篇文章為課件,這篇文章寫的很詳細(xì),在直播中我?guī)Т蠹疫^一遍,如果因時間問題分享不完的話,自行參照代碼學(xué)習(xí),也能很快掌握!直播回訪地址,我是第四期的分享!本次課程分享文件可在公眾號回復(fù)“20200419”獲得。
前言
python無疑是當(dāng)下最火爆的語言,你從微信朋友圈時不時的python廣告和地產(chǎn)大佬潘石屹的學(xué)python微博就可窺見一斑。這次研會的同學(xué)組織了四次python主題,我個人覺得這剛好是學(xué)習(xí)python的四個不同階段的主題,再換一下順序可能就更貼切了:python入門分享、python爬蟲入門、python數(shù)據(jù)分析、python深度學(xué)習(xí)。python以其簡潔的語言吸引了很多同學(xué)的學(xué)習(xí),但相信大多數(shù)同學(xué)可能就止步于一二步了吧,我也一樣哈哈,由于本科階段做了一點(diǎn)項(xiàng)目,所以相較于大多數(shù)同學(xué),我在python上花的時間多一點(diǎn),但我也僅僅是到了python爬蟲入門這個階段,如果這次是來邀請我分享爬蟲的話,我想我會很得心應(yīng)手的,但這次給我的主題是數(shù)據(jù)分析,可是把我難倒了好久,我的python數(shù)據(jù)分析生涯僅僅在于爬完數(shù)據(jù)后對數(shù)據(jù)的一個簡單的清理和平常自己論文里的一些實(shí)證實(shí)現(xiàn)。python數(shù)據(jù)分析應(yīng)用非常廣泛,在金融、數(shù)理統(tǒng)計(jì)、文本處理等方面都有很好的應(yīng)用,也具備很高的商業(yè)價值,但是相對而言它對涉及的理論知識也有一定的要求。我本來打算這周惡補(bǔ)一些python數(shù)據(jù)分析的numpy、scipy、pandas、matplotlib這些python包,然后講一下這些包的基礎(chǔ)操作,但后來意識到這樣的分享會很枯燥無聊,而且關(guān)于包的基礎(chǔ)操作大家完全可以在網(wǎng)上自行搜索。于是我就斗膽決定分享一下一些我做過的關(guān)于python文本數(shù)據(jù)分析的工作,用《射雕英雄傳》這個例子把它們串起來。我的專業(yè)是情報(bào)學(xué),我的數(shù)據(jù)分析經(jīng)歷大多數(shù)在于給自己或者師兄、師姐、老師論文里的實(shí)證部分實(shí)現(xiàn)的過程,所以我今天就只分享一些我做過的一些涉及情報(bào)學(xué)理論的文本信息處理,相信可能會對大家使用python應(yīng)用于自己論文中有一點(diǎn)點(diǎn)的幫助。本次分享過程沒有從《射雕英雄傳》中獲得任何的理論或者發(fā)現(xiàn)(哈哈),只是單純根據(jù)個人喜好借用一下金庸老爺子的名作,重點(diǎn)是利用python代碼復(fù)現(xiàn)情報(bào)學(xué)領(lǐng)域部分?jǐn)?shù)據(jù)分析方法。
目錄
- 1.采集語料
- 2.利用jieba分詞進(jìn)行數(shù)據(jù)預(yù)處理
- 2.1 分詞
- 2.2 載入自定義詞典和去除停用詞
- 2.3 關(guān)鍵詞提取
- 3.cos余弦值計(jì)算
- 3.1 文本余弦相似度原理
- 3.2 以簡單的例子來說明一下文本余弦相似度的計(jì)算過程
- 3.3 python代碼實(shí)現(xiàn)
- 4.基于樸素貝葉斯的書評情感判斷
- 4.1 樸素貝葉斯介紹
- 4.2 利用樸素貝葉斯進(jìn)行情感判斷
- 4.3 代碼實(shí)現(xiàn)
正文
1.語料采集
語料采集也就是之前一次“python爬蟲入門”那次主題的內(nèi)容,這里我就直接展示一下本次要使用到的語料。我們本次使用射雕英雄傳前三回的文本和一部分由我杜撰的書評。

首先看到上圖的文本我們就發(fā)現(xiàn)了第一個問題,分行不太對,這樣會導(dǎo)致分詞過程出現(xiàn)錯誤(這可能源于這個文本是爬取自某個在線小說閱讀的數(shù)據(jù)),所以先來解決它。
在解決這個錯誤之前,我們先來寫一個函數(shù),這個函數(shù)的作用是去掉文本中的所有分行和空格,利用一下這個方法獲取一下文本然后重新存到新的文檔里面,主函數(shù)這樣寫。其中l(wèi)ine.replace("", "")是一個文本替換函數(shù),
\n就是文本文檔中的換行; f = open(after, 'w', encoding='utf-8')里面的參數(shù)要注意,w是指覆蓋寫入,a為覆蓋,r為只讀。
def get_current_txt(path):
sentences = ''
for line in open(path, encoding='utf-8'):
line = line.replace("\n", "")
line = line.replace(" ", "")
sentences = sentences + line
return sentences
if __name__ == '__main__':
txt_name = [['射雕英雄傳第一章.txt','1.txt'],
['射雕英雄傳第二章.txt','2.txt'],
['射雕英雄傳第三章.txt','3.txt']]
for txt in txt_name:
before = '添加你自己文檔位置' + txt[0]
after = '添加你自己文檔位置' + txt[1]
t = get_current_txt(before)
f = open(after, 'w', encoding='utf-8')
f.write(t)
運(yùn)行之后的文件變成了這樣

這樣一來,所有文本只有一行,這雖然對我們的閱讀帶來了極大的不便,但是對我們分析文本沒有絲毫的影響。
2.1分詞
這里我們利用一下jieba分詞包,對于中文文本處理,結(jié)巴分詞使用的還是挺多的,還有就是中科院的文本處理包。
jieba分詞有四種分詞模式,一般習(xí)慣用精確模式。
# encoding=utf-8
import jieba
seg_list = jieba.cut("日日夜夜無窮無休的從臨安牛家村邊繞過", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
#輸出結(jié)果:Default Mode: 日日夜夜/ 無窮/ 無休/ 的/ 從/ 臨安/ 牛家村/ 邊/ 繞過
2.2載入自定義詞典和去除停用詞
這里分詞的詞典使用的是jieba分詞自帶的詞典,但有些時候jieba分詞自帶的詞典可能不包含我們需要的詞(例如網(wǎng)絡(luò)專有名詞),我們在這段話里以“無窮無休”為例,假設(shè)這個詞我們需要他作為一個四字成語單獨(dú)出現(xiàn),那么這個時候需要我們自定義一個詞典,我們新建一個自定義詞典。

然后在代碼中加載自定義詞典,結(jié)果就會出現(xiàn)我們想要的無窮無休
# encoding=utf-8
import jieba
jieba.load_userdict("userdict.txt")
seg_list = jieba.cut("日日夜夜無窮無休的從臨安牛家村邊繞過", cut_all=False)
print("Default Mode: " + "/ ".join(seg_list)) # 精確模式
#輸出結(jié)果:Default Mode: 日日夜夜/ 無窮無休/ 的/ 從/ 臨安/ 牛家村/ 邊/ 繞過
可以看到,分詞結(jié)果里面的類似于“的”這樣的沒有實(shí)際意義的詞,也就是屬于我們所說的停用詞范圍,在進(jìn)行文本信息處理的時候我們一般會選擇過濾掉他們也就是除去停用詞,jieba分詞無自帶停用詞詞典,所以一般自行構(gòu)建停用詞詞典進(jìn)行過濾。我這里整理了一個包含1894個中文停用詞的停用詞此表。

用代碼嘗試一下
# encoding=utf-8
import jieba
jieba.load_userdict("userdict.txt")
filepath = "stopwords.txt"
stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
seg_list = jieba.cut("日日夜夜無窮無休的從臨安牛家村邊繞過", cut_all=False)
for i in seg_list:
if i not in stopwords:
print(i)
#輸出結(jié)果:
#日日夜夜
#無窮無休
#臨安
#牛家村
#繞過
以上就是簡單的分詞和去停用詞的步驟,這樣看其實(shí)一點(diǎn)都不難,下面我們把去停用詞封裝成一個函數(shù),這樣以后你就可以那這個函數(shù)去處理你的任意的需要分詞和去停用詞的文本。get_current_txt()對上面的get_current_txt簡化了一下,使其適用于分詞和去停用詞的程序;cutWithNoSW(fileToCut,resultFile)就是分詞且去掉停用詞,輸入待分詞文件,輸出分詞結(jié)果。
import jieba
def get_current_txt(path):
sentences = ''
for line in open(path, encoding='utf-8'):
sentences = sentences + line
return sentences
def cutWithNoSW(fileToCut,resultFile):
content_cut = get_current_txt(fileToCut)
content_result = ''
jieba.load_userdict("/Users/chenjianyao/Desktop/python數(shù)據(jù)分析/文檔/userdict.txt")
filepath = "/Users/chenjianyao/Desktop/python數(shù)據(jù)分析/文檔/stopwords.txt"
stopwords = [line.strip() for line in open(filepath, 'r', encoding='utf-8').readlines()]
seg_list = jieba.cut(content_cut, cut_all=False)
for i in seg_list:
if i not in stopwords:
content_result = content_result + i + '\n'
print(content_result)
f = open(resultFile, 'w', encoding='utf-8')
f.write(content_result + '\n')
if __name__ == '__main__':
txt_name = [['1.txt','1_cut.txt'],
['2.txt','2_cut.txt'],
['3.txt','3_cut.txt']]
for txt in txt_name:
before = '文檔/' + txt[0]
after = '文檔/' + txt[1]
cutWithNoSW(before, after)
得到結(jié)果:

2.3關(guān)鍵詞提取
jieba分詞提供了基于tf-idf和textRank兩種算法提取關(guān)鍵詞,直接上代碼解釋:
import jieba.analyse
def get_current_txt(path):
sentences = ''
for line in open(path, encoding='utf-8'):
sentences = sentences + line
return sentences
if __name__ == '__main__':
txt_name = ['1_cut.txt','2_cut.txt','3_cut.txt']
for txt in txt_name:
filePath = '/Users/chenjianyao/Desktop/python數(shù)據(jù)分析/文檔/' + txt
keyword1 = jieba.analyse.extract_tags(get_current_txt(filePath), topK=3, withWeight=False, allowPOS=())
keyword2 = jieba.analyse.textrank(get_current_txt(filePath), topK=3, withWeight=False, allowPOS=('ns', 'n', 'vn', 'v'))
print("基于TF-IDF的關(guān)鍵詞:",txt,keyword1)
print("基于textrank的關(guān)鍵詞:", txt, keyword1)
#運(yùn)行結(jié)果:
#基于TF-IDF的關(guān)鍵詞: 1_cut.txt ['楊鐵心', '包惜弱', '郭嘯天']
#基于textrank的關(guān)鍵詞: 1_cut.txt ['楊鐵心', '包惜弱', '郭嘯天']
#基于TF-IDF的關(guān)鍵詞: 2_cut.txt ['丘處機(jī)', '段天德', '完顏洪烈']
#基于textrank的關(guān)鍵詞: 2_cut.txt ['丘處機(jī)', '段天德', '完顏洪烈']
#基于TF-IDF的關(guān)鍵詞: 3_cut.txt ['鐵木真', '哲別', '郭靖']
#基于textrank的關(guān)鍵詞: 3_cut.txt ['鐵木真', '哲別', '郭靖']
3.cos余弦相似度計(jì)算
3.1文本余弦相似度原理
cos余弦相似度在文本數(shù)據(jù)分析領(lǐng)域經(jīng)常用到,cos余弦相似度共識很好理解,如果能自行用python代碼實(shí)現(xiàn)一遍cos余弦相似度的計(jì)算,相信你以后遇到類似的相似度計(jì)算都沒有問題。

轉(zhuǎn)換到文本數(shù)據(jù)領(lǐng)域的話,公式就變成了

把兩個文本A和B向量化為由詞語所表示的文檔A=[x1,x2,x3,...,xn],B=[y1,y2,y3,...,yn],然后通過上述公式進(jìn)行計(jì)算,但前提是必須要保證A,B向量的向量維度一致,這個很重要,后面講。
3.2 以簡單的例子來說明一下文本余弦相似度的計(jì)算過程
以《射雕英雄傳》第三章里的部分段落“完顏洪熙見郭靖等許多蒙古小孩站在遠(yuǎn)處,睜大了小眼,目不轉(zhuǎn)瞬的瞧著,便哈哈大笑,探手入懷” 為例。我們?nèi)斯し衷~把這段文本切分成:
A = ['完顏洪熙','見','郭靖','蒙古','小孩','站','遠(yuǎn)處']
B = ['睜大','小眼','目不轉(zhuǎn)瞬','瞧著','哈哈大笑','探手入懷','郭靖']
為了使最終的相似度不為0,手動在B向量后面加一個‘郭靖’。下一步構(gòu)造兩個文本向量的交集,C向量相當(dāng)于包含A,B向量所有詞匯的向量,這就把A,B向量統(tǒng)一到了一個維度里。
C = ['完顏洪熙','見','郭靖','蒙古','小孩','站','遠(yuǎn)處','睜大','小眼','目不轉(zhuǎn)瞬','瞧著','哈哈大笑','探手入懷']
按照C向量把A,B向量按照詞頻數(shù)字化:
A = [1,1,1,1,1,1,1,0,0,0,0,0,0]
B = [0,0,1,0,0,0,0,1,1,1,1,1,1]
計(jì)算兩者的余弦相似度

最后得到相似度為0.143.
3.3python代碼實(shí)現(xiàn)
首先獲取分詞結(jié)果,這個get_current_txt和前兩個get_current_txt又不一樣了,它主要按行獲取txt中的文本,存在列表里,返回一個list->sentences
def get_current_txt(path):
sentences = []
for line in open(path, encoding='utf-8'):
line = line.replace("\n", "")
sentences.append(line)
return sentences
還記得上面的構(gòu)造A,B向量的集合C嗎?這里也要通過代碼實(shí)現(xiàn),set()集合有一個非常好用的優(yōu)點(diǎn),就是他可以實(shí)現(xiàn)類似于自動去重排序的功能,我們輸入一個訓(xùn)練集集合dataSet(也就是我們這里所要用到的A+B),他就會返回一個一個對dataSet自動去重然后排序的結(jié)果,列表化之后返回vocabList詞匯列表。
def createVocabList(dataSet):
vocabSet = set()
for doc in dataSet:
vocabSet = vocabSet | set(doc)
vocabList = list(vocabSet)
return vocabList
好了下面就到了計(jì)算cos余弦相似度的過程了,這里我們利用了python的數(shù)據(jù)字典dict,數(shù)據(jù)字典可以統(tǒng)計(jì)詞頻出現(xiàn)的次數(shù)。首先獲得詞匯列表c
c = createVocabList(a+b)
然后把輸入的兩個文本詞匯向量a,b轉(zhuǎn)換為詞典dict_a,dict_b
dict_a = {}
dict_b = {}
for key in a:
dict_a[key] = dict_a.get(key, 0) + 1
for key in b:
dict_b[key] = dict_b.get(key, 0) + 1
#字典形式:dict = {'江南七怪': 22, '顏烈': 27, '跨出': 1, '房門': 1}
抽取出數(shù)據(jù)字典中的詞頻形成詞頻向量vec_a,vec_b
vec_a = []
vec_b = []
for key in c:
if key in dict_a:
vec_a.append(dict_a[key])
else:
vec_a.append(0)
for key in c:
if key in dict_b:
vec_b.append(dict_b[key])
else:
vec_b.append(0)
下面是計(jì)算余弦值的代碼:
sum = 0
sq1 = 0
sq2 = 0
for i in range(len(vec_a)):
sum += vec_a[i] * vec_b[i]
sq1 += pow(vec_a[i], 2)
sq2 += pow(vec_b[i], 2)
try:
result = round(float(sum) / (math.sqrt(sq1) * math.sqrt(sq2)), 2)
except ZeroDivisionError:
result = 0.0
好了,計(jì)算余弦相似度的代碼基本都已完成了,我們把上述零零散散的代碼匯總一下
import math
def get_current_txt(path):
sentences = []
for line in open(path, encoding='utf-8'):
line = line.replace("\n", "")
sentences.append(line)
return sentences
def createVocabList(dataSet):
vocabSet = set()
for doc in dataSet:
vocabSet = vocabSet | set(doc)
vocabList = list(vocabSet)
return vocabList
def getCos(a,b):
c = createVocabList(a+b)
dict_a = {}
dict_b = {}
for key in a:
dict_a[key] = dict_a.get(key, 0) + 1
for key in b:
dict_b[key] = dict_b.get(key, 0) + 1
vec_a = []
vec_b = []
for key in c:
if key in dict_a:
vec_a.append(dict_a[key])
else:
vec_a.append(0)
for key in c:
if key in dict_b:
vec_b.append(dict_b[key])
else:
vec_b.append(0)
sum = 0
sq1 = 0
sq2 = 0
for i in range(len(vec_a)):
sum += vec_a[i] * vec_b[i]
sq1 += pow(vec_a[i], 2)
sq2 += pow(vec_b[i], 2)
try:
result = round(float(sum) / (math.sqrt(sq1) * math.sqrt(sq2)), 2)
except ZeroDivisionError:
result = 0.0
# print(result)
return result
if __name__ == '__main__':
txt_A = get_current_txt('文檔1.txt')
txt_B = get_current_txt('文檔2.txt')
print(getCos(txt_A, txt_B))
用這個代碼可以實(shí)現(xiàn)中英文任意文獻(xiàn)的相似度計(jì)算,我們是用這個代碼計(jì)算射雕前三章的相似度,得到下述結(jié)果:
| 文檔 | 第一章 | 第二章 | 第三章 |
|---|---|---|---|
| 第一章 | 1 | 0.88 | 0.91 |
| 第二章 | 0.88 | 1 | 0.86 |
| 第三章 | 0.91 | 0.86 | 1 |
仔細(xì)研讀一下這個結(jié)果會發(fā)現(xiàn)非常的有意思!

就我個人經(jīng)驗(yàn),相似度都是很稀疏的,往往很多文檔之間的相似度只有0.0幾或者不超過0.5這樣的,遇到這種情況往往需要?dú)w一化去處理。但是你看看金庸老爺子的章節(jié)之間相似度有多大,達(dá)到了0.91,這就說明作者在語言習(xí)慣、寫作手法、用詞手法等方面都有自己的一套,所以才會得到這么高的相似度?;蛟S可以拿cos去判斷紅樓夢后四十章到底是誰寫的?
4.基于樸素貝葉斯的書評情感判斷
4.1 為何分享樸素貝葉斯
按道理講,樸素貝葉斯應(yīng)該屬于機(jī)器學(xué)習(xí)的行列,但是為什么今天把它放到數(shù)據(jù)分析環(huán)節(jié)呢?一方面我個人覺得其實(shí)我們對文本進(jìn)行數(shù)據(jù)分析目的也是為了從中得到我們想要的信息或者是證明我們的理論,這就回到了情報(bào)學(xué)的初衷,從信息中獲取更有價值的信息,從這一角度來看類似于樸素貝葉斯這類的機(jī)器學(xué)習(xí)算法都應(yīng)該數(shù)據(jù)數(shù)據(jù)分析的行列;另一方面,從難易程度來講,樸素貝葉斯絕對是大家了解數(shù)據(jù)分析或者機(jī)器學(xué)習(xí)算法最簡單的入門算法,因此我就斗膽以此為例給大家分享一下
4.2 樸素貝葉斯簡介
在講公式原理之前,先舉一個例子!
我就舉一個嫁不嫁的例子!
假如現(xiàn)在有一男,已知特征為(帥,無車,無房,上進(jìn)),各位女性聽眾面對這樣一個男生會選擇嫁嗎?當(dāng)你猶豫不決的時候,先去看看你身邊的案例,列一個表,看看你的閨蜜or你的女性朋友都嫁給了什么樣的男性?
| 帥不帥 | 有無車 | 有無房 | 是否上進(jìn) | 嫁不嫁 |
|---|---|---|---|---|
| 帥 | 有 | 無 | 是 | 嫁 |
| 不帥 | 有 | 有 | 是 | 嫁 |
| 帥 | 無 | 無 | 是 | 不嫁 |
| 不帥 | 無 | 有 | 否 | 嫁 |
| 不帥 | 有 | 無 | 否 | 不嫁 |
| 帥 | 有 | 有 | 否 | 嫁 |
| 帥 | 無 | 無 | 否 | 不嫁 |
根絕已有的案例,試著利用樸素貝葉斯公式?jīng)Q定你嫁不嫁。
樸素貝葉斯公式:


轉(zhuǎn)換為特征表達(dá)式:

將困擾這位女生嫁不嫁的問題轉(zhuǎn)換為概率問題:
p(嫁|帥,無車,無房,上進(jìn))
p(不嫁|帥,無車,無房,上進(jìn))
最后得到誰的概率大就怎么做。
計(jì)算過程我在word中寫了好了截過來:


4.3 代碼實(shí)現(xiàn)
上面覺得嫁不嫁的例子是表明了樸素貝葉斯利用特征進(jìn)行分類的過程。
應(yīng)用于文本分類稍微有點(diǎn)不同,可以去這里補(bǔ)習(xí)一下樸素貝葉斯文本分類
應(yīng)用于文本分類的樸素貝葉斯公式是這樣的

簡單的理解就是這個文本屬于哪一個類別,就用它的先驗(yàn)概率乘以他每個單詞的似然概率。我們從豆瓣書評中獲取了幾條訓(xùn)練集和測試集,利用樸素貝葉斯識別訓(xùn)練集的情感極性。
train_post = [
['當(dāng)然','我','最','熱愛','還是','83','電視劇'],
['最愛','一部','靖蓉','之間','感情','真是','美好'],
['這部','是','最','好看','喜歡']
]
train_nega = [
['不喜歡','郭靖','不喜歡','黃蓉','因?yàn)?,'先看了','神雕俠侶'],
['我','真的','很','討厭','郭靖','很','討厭','很','討厭','還有','江南七怪'],
['一個','智商','低','一個','情商','低','這','倆','兄弟','真','絕了']
]
test = [
['從小','就','熱愛','射雕','喜歡','里面','人物','感情'],
['不喜歡','郭靖','江南七怪','尤其','柯鎮(zhèn)惡','打架','沒贏過','裝逼','沒輸過'],
]
首先寫一個獲取文檔數(shù)量和詞匯數(shù)量的方法
def createVocabList(dataSet):
vocabSet = set() # 創(chuàng)建一個空的集合
for doc in dataSet: # 遍歷dataSet中的每一條言論
vocabSet = vocabSet | set(doc) # 取并集,set()可執(zhí)行去重功能
vocabList = list(vocabSet)
voc_num = len(vocabList)
doc_num = len(dataSet)
return voc_num, doc_num
然后寫一個判斷某個單詞x在文檔中出現(xiàn)的次數(shù),以及這個文檔的總詞數(shù)
def count2list(list, x):
show_num = 0
word_num = 0
for i in list:
show_num = show_num + i.count(x)
word_num = word_num + len(i)
return show_num, word_num
文檔的先驗(yàn)概率計(jì)算方法:
# 先驗(yàn)概率
xianyan_post = doc_num_post / doc_num
xianyan_nega = doc_num_nega / doc_num
計(jì)算測試集的每個單詞的似然概率
# 保存每個單詞似然概率的列表
per_word_post = []
per_word_nega = []
for i in test:
# 判斷i在post文檔中出現(xiàn)了幾次以及相應(yīng)的文檔出現(xiàn)的總詞數(shù)
show_num, word_num = count2list(train_post, i)
per_word_post.append((show_num + 1) / (word_num + voc_num))
show_num, word_num = count2list(train_nega, i)
per_word_nega.append((show_num + 1) / (word_num + voc_num))
接著進(jìn)行概率判斷:
# 概率判斷
p_post = xianyan_post * reduce(lambda x, y: x * y, per_word_post)
p_nega = xianyan_nega * reduce(lambda x, y: x * y, per_word_nega)
print('post概率', p_post)
print('nega概率', p_nega)
if p_post > p_nega:
print("該文本情感極性是post")
else:
print("該文本情感極性是naga")
綜合一下上述的代碼就得到:
from functools import reduce
def createVocabList(dataSet):
vocabSet = set() # 創(chuàng)建一個空的集合
for doc in dataSet: # 遍歷dataSet中的每一條言論
vocabSet = vocabSet | set(doc) # 取并集,set()可執(zhí)行去重功能
vocabList = list(vocabSet)
voc_num = len(vocabList)
doc_num = len(dataSet)
return voc_num, doc_num
def count2list(list, x):
show_num = 0
word_num = 0
for i in list:
show_num = show_num + i.count(x)
word_num = word_num + len(i)
return show_num, word_num
def classifier(test, voc_num, doc_num, doc_num_nega, doc_num_post):
# 先驗(yàn)概率
xianyan_post = doc_num_post / doc_num
xianyan_nega = doc_num_nega / doc_num
print(xianyan_post, xianyan_nega)
# 保存每個單詞似然概率的列表
per_word_post = []
per_word_nega = []
for i in test:
# 判斷i在post文檔中出現(xiàn)了幾次以及相應(yīng)的文檔出現(xiàn)的總詞數(shù)
show_num, word_num = count2list(train_post, i)
per_word_post.append((show_num + 1) / (word_num + voc_num))
show_num, word_num = count2list(train_nega, i)
per_word_nega.append((show_num + 1) / (word_num + voc_num))
# 概率判斷
p_post = xianyan_post * reduce(lambda x, y: x * y, per_word_post)
p_nega = xianyan_nega * reduce(lambda x, y: x * y, per_word_nega)
print('post概率', p_post)
print('nega概率', p_nega)
if p_post > p_nega:
print("該文本情感極性是post")
else:
print("該文本情感極性是naga")
if __name__ == '__main__':
train = []
train_post = [
['當(dāng)然','我','最','熱愛','還是','83','電視劇'],
['最愛','一部','靖蓉','之間','感情','真是','美好'],
['這部','是','最','好看','喜歡']
]
train_nega = [
['不喜歡','郭靖','不喜歡','黃蓉','因?yàn)?,'先看了','神雕俠侶'],
['我','真的','很','討厭','郭靖','很','討厭','很','討厭','還有','江南七怪'],
['一個','智商','低','一個','情商','低','這','倆','兄弟','真','絕了']
]
test = [
['從小','就','熱愛','射雕','喜歡','里面','人物','感情'],
['不喜歡','郭靖','江南七怪','尤其','柯鎮(zhèn)惡','打架','沒贏過','裝逼','沒輸過'],
]
train = train_post + train_nega
print(train)
voc_num, doc_num = createVocabList(train)
voc_num_nega, doc_num_nega = createVocabList(train_nega)
voc_num_post, doc_num_post = createVocabList(train_post)
for i in test:
print(i)
classifier(i, voc_num, doc_num, doc_num_nega, doc_num_post)