【博客的主要内容主要是自己的学习笔记,并结合个人的理解,供各位在学习过程中参考,若有疑问,欢迎提出;若有侵权,请告知博主删除,原创文章转载还请注明出处。】
[机器学习实战:文本过滤器]
实例一:在线社区留言板过滤器
1 需求描述:
为维护在线社区留言板的正常次序,需屏蔽侮辱性的言论,需构建一个快速过滤器,如果某条留言使用了负面或侮辱性的言语,那么就将该留言标识为内容不当。
2 算法分析:【自问的过程】
1、拥有数据样本情况?
有若干条数据样本,其中每条“言论”均标识所属类别(即侮辱性言语或非侮辱性言语)
2、程序如何判断言语为侮辱性和非侮辱性?
- 朴素贝叶斯
将使用朴素贝叶斯公式:
c 表示分类类别即:侮辱性言语和非侮辱性言语
对每个类别分母都一样,即需计算$P(w|c_i)$ 和 $P(c_i)$,在朴素贝叶斯中假设事件是相互独立的,故:
$P(w|c_i)=P(w_0|c_i)P(w_1|c_i)...P(w_n|c_i)$
需要计算什么?
$P(w|c_i)=P(w_0|c_i)P(w_1|c_i)...*P(w_n|c_i)$
以上用文字描述:计算每个类别下各个单词出现的概率。由此,需要统计内容:
a)每条言论下各个单词出现的次数;
b)每个类别的单词总数;数据分析:现有数据什么样?需要对数据如何处理?
a、对每条言语转换成向量数组;
b、制定“词典集合”,将每条言语做并集,去除重复单词;并将“词典集合”转换为向量数组;
- 特殊情况分析:
-
a、由于$P(w|c_i)=P(w_0|c_i)P(w_1|c_i)...*P(w_n|c_i)$ 是做乘法运算,若其中一个单词概率为0,则该言语概率为0。
- [解决方法]将所有词出现数初始化为1,分母初始化为2。
-
b、太多很小数相乘,结果将趋近为0.
- [解决方法]对乘积取自然对数。在代数中有ln(a*b) = ln(a) + ln(b)。
3 算法实现
#1、将文本转换为数字向量
##a、建立不重复的词汇表
def createVocabList(dataSet):
vocabSet = set([])
for document in dataSet:
vocabSet = vocabSet | set(document)
return list(vocabSet)
#test
myVocabLists = createVocabList(postingLists)
##b、将每条言语转换为数字向量:建立与词汇表同等大小的言语向量,若言语中的词汇在词汇表中出现则标记为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 - 由每篇文档类别标签所构成的向量
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 实例二:电子邮件垃圾过滤
如何从文本文档中构建自己的词列表
随机选择数据的一部分作为训练集,剩余部分作为测试集的过程称为“留存交叉验证”(hold-out cross validation)
思路:
1)构建词列表:对文本文档进行按词切分
2)交叉验证:对现有数据划分为训练集和测试集
3)朴素贝叶斯算法计算独立事件概率
- 计算算法准确率
5)多次重复实验,提高正确率
textParse()接受一个大字符串并将其解析为字符串列表;
spamTest()对垃圾邮件分类器进行自动处理。主要:
1)解析文本文件编制成词列表;
2)构建测试集合训练集
######电子邮件垃圾过滤######
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=[]
#创建词汇表
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)
#划分测试集 和 训练集
trainingSet = range(50);
testSet=[]
for i in range(10):
randIndex = int(random.uniform(0,len(trainingSet)))
testSet.append(trainingSet[randIndex])
del(trainingSet[randIndex])
#朴素贝叶斯计算概率
trainMat = [];trainClasses=[]
for docIndex in trainingSet:
trainMat.append(bagOfWord2VecMN(vocabList,docList[docIndex]))
trainClasses.append(classList[docIndex])
p0V,p1V,pSpam=trainNB(array(trainMat),array(trainClasses))
#统计错误率
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 实例三:使用朴素贝叶斯分类器从个人广告中获取区域倾向
对两个城市所发布的征婚广告信息,来比较这两个城市的人们在广告用词上是否不同。
如果结论是不同,那么他们各自常用的词是那些?
从人们的用词中,能否对不同城市的人所关心的内容有所了解?
该实例目的:通过观察单词和条件概率值来发现与特定城市相关的内容
calcMostFreq() 遍历词汇表中每个词并统计它在文本中出现的次数,然后根据出现次数从高到低对词典进行排序,最后返回排序最高的100个单词。
localWords() 主要:1)解析文本词列表;2)构建测试集合训练集
getTopWords() 训练并测试朴素贝叶斯分类器,返回使用的概率值。