【博客的主要內(nèi)容主要是自己的學(xué)習(xí)筆記,并結(jié)合個(gè)人的理解,供各位在學(xué)習(xí)過(guò)程中參考,若有疑問(wèn),歡迎提出;若有侵權(quán),請(qǐng)告知博主刪除,原創(chuàng)文章轉(zhuǎn)載還請(qǐng)注明出處?!?/p>
[機(jī)器學(xué)習(xí)實(shí)戰(zhàn):文本過(guò)濾器]
實(shí)例一:在線社區(qū)留言板過(guò)濾器
1 需求描述:
為維護(hù)在線社區(qū)留言板的正常次序,需屏蔽侮辱性的言論,需構(gòu)建一個(gè)快速過(guò)濾器,如果某條留言使用了負(fù)面或侮辱性的言語(yǔ),那么就將該留言標(biāo)識(shí)為內(nèi)容不當(dāng)。
2 算法分析:【自問(wèn)的過(guò)程】
1、擁有數(shù)據(jù)樣本情況?
有若干條數(shù)據(jù)樣本,其中每條“言論”均標(biāo)識(shí)所屬類別(即侮辱性言語(yǔ)或非侮辱性言語(yǔ))
2、程序如何判斷言語(yǔ)為侮辱性和非侮辱性?
- 樸素貝葉斯
將使用樸素貝葉斯公式:

c 表示分類類別即:侮辱性言語(yǔ)和非侮辱性言語(yǔ)
對(duì)每個(gè)類別分母都一樣,即需計(jì)算$P(w|c_i)$ 和 $P(c_i)$,在樸素貝葉斯中假設(shè)事件是相互獨(dú)立的,故:
$P(w|c_i)=P(w_0|c_i)P(w_1|c_i)...P(w_n|c_i)$
需要計(jì)算什么?
$P(w|c_i)=P(w_0|c_i)P(w_1|c_i)...*P(w_n|c_i)$
以上用文字描述:計(jì)算每個(gè)類別下各個(gè)單詞出現(xiàn)的概率。由此,需要統(tǒng)計(jì)內(nèi)容:
a)每條言論下各個(gè)單詞出現(xiàn)的次數(shù);
b)每個(gè)類別的單詞總數(shù);數(shù)據(jù)分析:現(xiàn)有數(shù)據(jù)什么樣?需要對(duì)數(shù)據(jù)如何處理?
a、對(duì)每條言語(yǔ)轉(zhuǎn)換成向量數(shù)組;
b、制定“詞典集合”,將每條言語(yǔ)做并集,去除重復(fù)單詞;并將“詞典集合”轉(zhuǎn)換為向量數(shù)組;
- 特殊情況分析:
-
a、由于$P(w|c_i)=P(w_0|c_i)P(w_1|c_i)...*P(w_n|c_i)$ 是做乘法運(yùn)算,若其中一個(gè)單詞概率為0,則該言語(yǔ)概率為0。
- [解決方法]將所有詞出現(xiàn)數(shù)初始化為1,分母初始化為2。
-
b、太多很小數(shù)相乘,結(jié)果將趨近為0.
- [解決方法]對(duì)乘積取自然對(duì)數(shù)。在代數(shù)中有l(wèi)n(a*b) = ln(a) + ln(b)。
3 算法實(shí)現(xiàn)
#1、將文本轉(zhuǎn)換為數(shù)字向量
##a、建立不重復(fù)的詞匯表
def createVocabList(dataSet):
vocabSet = set([])
for document in dataSet:
vocabSet = vocabSet | set(document)
return list(vocabSet)
#test
myVocabLists = createVocabList(postingLists)
##b、將每條言語(yǔ)轉(zhuǎn)換為數(shù)字向量:建立與詞匯表同等大小的言語(yǔ)向量,若言語(yǔ)中的詞匯在詞匯表中出現(xiàn)則標(biāo)記為1,否則為0.
#vocabList:單詞字典集合
#inputSet:單條文本
def setOfWords2Vec(vocabList,inputSet):
returnVec = [0]*len(vocabList)
for word in inputSet:
if word in vocabList:
returnVec[vocabList.index(word)] = 1
else:
print "the word :%s is not in my vocabulary!" % word
return returnVec
#test
wordsVec=[]
for postingList in postingLists:
wordsVec.append(setOfWords2Vec(myVocabLists,postingList))
#trainMainx - 輸入文檔矩陣
#trainCategory - 由每篇文檔類別標(biāo)簽所構(gòu)成的向量
def trainNB0(trainMatrix,trainCategory):
numTrainDocs = len(trainMatrix)
numWords = len(trainMatrix[0])
pAbusive = sum(trainCategory)/float(numTrainDocs)
#初始化概率
p0Num = ones(numWords)
p1Num = ones(numWords)
p0Denom = 2.0
p1Denom = 2.0
#向量相加
for i in range(numTrainDocs):
if trainCategory[i] == 1:
p1Num += trainMatrix[i]
p1Denom += sum(trainMatrix[i])
else:
p0Num += trainMatrix[i]
p0Denom += sum(trainMatrix[i])
p1Vect = log(p1Num / p1Denom)
p0Vect = log(p0Num / p0Denom)
return p0Vect,p1Vect,pAbusive
##test
p0Vect,p1Vect,pAbusive=trainNB0(wordsVec,classLists)
2 實(shí)例二:電子郵件垃圾過(guò)濾
如何從文本文檔中構(gòu)建自己的詞列表
隨機(jī)選擇數(shù)據(jù)的一部分作為訓(xùn)練集,剩余部分作為測(cè)試集的過(guò)程稱為“留存交叉驗(yàn)證”(hold-out cross validation)
思路:
1)構(gòu)建詞列表:對(duì)文本文檔進(jìn)行按詞切分
2)交叉驗(yàn)證:對(duì)現(xiàn)有數(shù)據(jù)劃分為訓(xùn)練集和測(cè)試集
3)樸素貝葉斯算法計(jì)算獨(dú)立事件概率
- 計(jì)算算法準(zhǔn)確率
5)多次重復(fù)實(shí)驗(yàn),提高正確率
textParse()接受一個(gè)大字符串并將其解析為字符串列表;
spamTest()對(duì)垃圾郵件分類器進(jìn)行自動(dòng)處理。主要:
1)解析文本文件編制成詞列表;
2)構(gòu)建測(cè)試集合訓(xùn)練集
######電子郵件垃圾過(guò)濾######
def textParse(bigString):
import re
listOfTokens = re.split(r'\W*',bigString)
return [tok.lower() for tok in listOfTokens if len(tok) > 2]
def spamTest():
docList=[]; classList=[]; fullText=[]
#創(chuàng)建詞匯表
for i in range(1,26):
wordList = textParse(open('email/spam/%d.txt'%i).read())
docList.append(workList)
fullText.extend(workList)
classList.append(1)
wordList = textParse(open('email/ham/%d.txt'%i).read())
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList)
#劃分測(cè)試集 和 訓(xùn)練集
trainingSet = range(50);
testSet=[]
for i in range(10):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
#樸素貝葉斯計(jì)算概率
trainMat = [];trainClasses=[]
for docIndex in trainingSet:
trainMat.append(bagOfWord2VecMN(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainNB(array(trainMat),array(trainClasses))
#統(tǒng)計(jì)錯(cuò)誤率
errorCount = 0
for docIndex in testSet:
wordVector = bagOfWord2VecMN(vocabList,docList[docIndex])
if classifyNB(array(wordVector),p0V,p1V,pSpam) != classList[docIndex]:
errorCount +=1
print "classification error:",docList[docIndex]
print "the error rate is:", float(errorCount)/len(testSet)
3 實(shí)例三:使用樸素貝葉斯分類器從個(gè)人廣告中獲取區(qū)域傾向
對(duì)兩個(gè)城市所發(fā)布的征婚廣告信息,來(lái)比較這兩個(gè)城市的人們?cè)趶V告用詞上是否不同。
如果結(jié)論是不同,那么他們各自常用的詞是那些?
從人們的用詞中,能否對(duì)不同城市的人所關(guān)心的內(nèi)容有所了解?
該實(shí)例目的:通過(guò)觀察單詞和條件概率值來(lái)發(fā)現(xiàn)與特定城市相關(guān)的內(nèi)容
calcMostFreq() 遍歷詞匯表中每個(gè)詞并統(tǒng)計(jì)它在文本中出現(xiàn)的次數(shù),然后根據(jù)出現(xiàn)次數(shù)從高到低對(duì)詞典進(jìn)行排序,最后返回排序最高的100個(gè)單詞。
localWords() 主要:1)解析文本詞列表;2)構(gòu)建測(cè)試集合訓(xùn)練集
getTopWords() 訓(xùn)練并測(cè)試樸素貝葉斯分類器,返回使用的概率值。