示例:使用朴素贝叶斯分类器从个人广告中获取区域倾向
我们将分别从美国的两个城市中选取一些人,通过分析这些人发布的征婚广告信息,来比较这两个城市的人们在广告用词上是否不同。如果结论确实是不同,那么他们各自常用的词是哪些?从人们的用词当中,我们能否对不同城市的人所关心的内容有所了解?
下面使用来自不同城市的广告训练一个分类器,然后观察分类器的效果。我们的目的并不是使用该分类器进行分类,而是通过观察单词和条件概率值来发现与特定城市相关的内容。
一、收集数据:导入RSS源
Universal Feed Parser是python中最常用的RSS程序库。
下载并安装feedparser:
1、下载的是feedparser-5.2.1版本https://pypi.python.org/pypi/feedparser/ ,下载后解压缩
2、修改setup.py文件
用python打开文件夹里面的setup.py文件,修改第一行代码,将from setuptools import setup改为from distutils.core import setup,然后保存。
3、打开cmd命令窗口,进入setup.py所在目录,执行命令:
python setup.py install
4、测试,关闭pycharm,再重新打开,命令行输入:import feedparser
不报错即为安装成功 。
我们可以构建一个类似于spamTest()的函数来测试过程自动化。程序代码如下:
#RSS源分类器及高频词去除函数
def calcMostFreq(vocabList, fullText):
import operator
freqDict = {}
for token in vocabList:
freqDict[token] = fullText.count(token)
sortedFreq = sorted(freqDict.items(), key=operator.itemgetter(1), reverse=True)
return sortedFreq[:30] #返回30个频率最高的词汇
def localWords(feed1, feed0):
import feedparser
docList = []; classList = []; fullText = [] #初始化数据列表
minLen = min(len(feed1['entries']), len(feed0['entries']))
for i in range(minLen):#导入文本文件
wordList = textParse(feed1['entries'][i]['summary']) #切分文本
docList.append(wordList)#切分后的文本以原始列表形式加入文档列表
fullText.extend(wordList)#切分后的文本直接合并到词汇列表
classList.append(1)#标签列表更新
wordList = textParse(feed0['entries'][i]['summary'])#切分文本
docList.append(wordList) #切分后的文本以原始列表形式加入文档列表
fullText.extend(wordList)#切分后的文本直接合并到词汇列表
classList.append(0)#标签列表更新
vocabList = createVocabList(docList)#获得词汇表
top30Words = calcMostFreq(vocabList, fullText)#获得30个频率最高的词汇
for pairW in top30Words:#去掉出现次数最高的那些词
if pairW[0] in vocabList:
vocabList.remove(pairW[0])
trainingSet = range(2*minLen)
testSet = []
for i in range(20):#随机构建测试集,随机选取二十个样本作为测试样本,并从训练样本中剔除
randIndex = int(random.uniform(0, len(trainingSet)))#随机得到Index
#print(randIndex)
testSet.append(trainingSet[randIndex])#将该样本加入测试集中
del(trainingSet[randIndex]) #同时将该样本从训练集中剔除
trainMat = []; trainClasses = [] #初始化训练集数据列表和标签列表
for docIndex in trainingSet: #遍历训练集
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex]))#词表转换到向量,并加入到训练数据列表中
trainClasses.append(classList[docIndex]) #相应的标签也加入训练标签列表中
p0V, p1V, pSpam = trainNB0(array(trainMat), array(trainClasses))#朴素贝叶斯分类器训练函数
errorCount = 0
for docIndex in testSet: #遍历测试集进行测试
wordVector = setOfWords2Vec(vocabList, docList[docIndex])#词表转换到向量
if classifyNB(array(wordVector), p0V, p1V, pSpam) != classList[docIndex]:
errorCount += 1
print("classification error",docList[docIndex])#输出出错的文档
print('the erroe rate is: ', float(errorCount)/len(testSet))
return vocabList, p0V, p1V #返回词汇表和两个类别概率向量
calcMostFreq()函数遍历词汇表中的每个词并统计它在文本中出现的次数,然后根据出现次数从高到低对词典进行排序,最后返回频率最高的30个词。
localWords()函数使用两个RSS源作为参数,其余与spamTest()基本类似。可以注释掉用于移除高频词的三行代码,然后比较注释前后的分类性能。
书上说 保留代码的错误率是70%,去掉代码的错误率是54%。而留言中出现次数最多的前30个词涵盖了所有用词的30%,也就是说,词汇表的一小部分单词却占据了所有文本用词的一大部分。==产生这种现象是因为语言中大部分都是冗余和结构辅助性内容。==另一个常用的方法是不仅移除高频词,同时从某个预定词表中移除结构上的辅助词。
def main():
import feedparser
ny = feedparser.parse('https://newyork.craigslist.org/search/stp?format=rss')
print(ny)
print(len(ny['entries']))
sf = feedparser.parse('http://sfbay.craiglist.org/stp/index.rss')
vocabList, pSF, pNY = localWords(ny, sf)
执行结果为:
也就是说,从网页确实获得了数据,但是print(len(ny[‘entries’]))的结果为0,这里的用法是我没搞明白还是就是0?先记录在这,之后再解决……
二、分析数据:显示地域相关的用词
#最具表征性的词汇显示函数
def getTopWords(ny,sf):
import operator
vacabList, p0V, p1V = localWords(ny,sf) #训练并测试朴素贝叶斯分类器
topNY = []
topSF = []
for i in range(len(p0V)):
if p0V[i] > -6.0:
topSF.append((vocabList[i],p0V[i]))
if p1V[i] > -6.0:
topSF.append((vocabList[i],p1V[i]))
sortedSF = sorted(topSF, key=lambda pair:pair[1], reverse=True)
print("SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**SF**")
for item in sortedSF:
print(item[0])
sortedNY = sorted(topNY, key=lambda pair: pair[1], reverse=True)
print("NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**NY**")
for item in sortedNY:
print(item[0])
函数getTopWords()使用两个RSS源作为输入,然后训练并测试朴素贝叶斯分类器,返回使用的概率值。然后创建两个列表用于元组的存储。与之前返回排名最高的X个单词不同,这里可以返回大于某个阈值的所有词。这些元组会按照它们的条件概率进行排序。
三、总结
1、贝叶斯概率及贝叶斯准则提供了一种利用已知值来估计未知概率的有效方法;
2、朴素贝叶斯:通过特征之间的条件独立性假设,降低对数据量的需求。(独立性假设是指一个词的出现概率并不依赖于文档中的其他词)
3、编程语言:下溢出是其中一个问题,可以通过对概率取对数来解决;
4、词袋模型在解决文档分类问题上比词集模型有所提高;
5、其他方面的改进:比如移除停用词,也可以花大量时间对切分器进行优化。