下面将使用来自不同城市的广告训练一个分类器,然后观察分类器的效果。我们的目的并不是使用该分类器进行分类,而是通过观察单词和条件概率值来发现与特定城市相关的内容。
收集数据:导入RSS源
Python count() 方法用于统计字符串里某个字符出现的次数。可选参数为在字符串搜索的开始与结束位置。
使用iteritems()这个函数得到我们字典中的所有元素,就是键-值对{‘yes’:2,’maybe’:1}
之后定义一个叫做key的函数,这个名字可以任意取,key只是习惯性定义的
之后通过itemgetter函数对字典中的元素进行排序,operator.itemgetter(1)表示按照元素的第二个进行排序,指按键-值对的值来排,也就是分类出现的多少。
reverse=True 表示按照递减的顺序来排序,即降序。
def calcMostFreq(vocabList,fullText):#该函数遍历词汇表中的每个词并统计它在文本中出现的次数,
# 然后根据出现的次数从高到低对词典进行排序,最后返回排序最高的30个单词。
import operator
freqDict = {}#出现频率,建立字典
for token in vocabList:
freqDict[token]=fullText.count(token)#字典的键对应这个词在fullText中出现的次数
sortedFreq = sorted(freqDict.items(), key=operator.itemgetter(1),reverse=True)
return sortedFreq[0:30]
def localWords(feed1,feed0):#使用两个RSS源作为参数
import feedparser
docList=[];classList = []; fullText = []
minLen = min(len(feed1['entries']),len(feed0['entries']))
for i in range(minLen):
wordList = textParse(feed1['entries'][i]['summary']) # 进行文本分切,每次访问一条RSS源
docList.append(wordList) # docList最后是一个放满了n个被切分后的RSS源
fullText.extend(wordList) # fullText是一个有n个元素的列表
classList.append(1) # n个1,0交叉的列表
wordList = textParse(feed0['entries'][i]['summary'])
docList.append(wordList)
fullText.extend(wordList)
classList.append(0)
vocabList = createVocabList(docList) # 找出n个RSS源中不重复的词组成列表
top30Words = calcMostFreq(vocabList,fullText)#得到出现次数最多的前30个单词
for pairW in top30Words:
if pairW[0] in vocabList:vocabList.remove(pairW[0])#移去vocabList中那些出现频率高的词
trainingSet = list(range(2*minLen));
testSet = [] # trainingSet是一个整数列表,其中的值从0-2len
for i in range(20):
randIndex = int(random.uniform(0, len(trainingSet))) # 从0-49随机选择10个文件
testSet.append(trainingSet[randIndex]) # testSet是一个放了10个文件序列号的列表
del (trainingSet[randIndex]) # 删去trainingSet中已被随机挑选出的元素
trainMat = [];
trainClasses = [] # trainMat构建一个文档矩阵,trainClasses每片文档类别标签构成的向量
for docIndex in trainingSet: # 循环遍历训练集的所有文档 trainingSet40
trainMat.append(setOfWords2Vec(vocabList, docList[docIndex])) # 对每封邮件基于词汇表使用setOfWords2Vec构建词向量
trainClasses.append(classList[docIndex]) # 由1和0组成的列表,1代表邮件来自spam,0代表邮件来自ham
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('the error rate is: ', float(errorCount) / len(testSet))
return vocabList,p0V,p1V
一个现象,留言中出现次数最多的前30个词涵盖了所有用词的30%,在进行测试的时候,vocabList的大小约为3000个词,也就是说,词汇表中的一小部分单词却占据了所有文本用词的一大部分。
在移除高频词的同时,从某个预定词表中移除结构上的辅助词,该词表称为停用词表。
分析数据:显示地域相关的用词
(Python将不能修改的值称为是不可变的,而不可变的列表称为元组,用())
lambda函数是一种快速定义单行的最小函数
>>> def f(x,y):
... return x*y
...
>>> f(2,3)
>>> g = lambda x,y: x*y
>>> g(2,3)
def getTopWords(ny,sf):#使用两个RSS源作为输入,返回大于某个阈值的所有词
import operator
vocabList,p0V,p1V=localWords(ny,sf)
topNY=[];topSF=[]#创建两个列表用于元组的存储
for i in range(len(p0V)):#p0V是一个数组,元素是RSS源中每条信息对应的vocabList中的每个词出现的概率
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**")
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**")
for item in sortedNY:
print item[0]
key=lambda pair: pair[1]这里其实每看懂
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
在之前,注释掉用于移除高频词的三行代码后,也就是说不移除高频词,错误率为54%,而保留得到的错误率为70%,移除固定的停用词,分类错误率也将会降低。
贝叶斯 通过特征之间的条件独立性假设,降低对数据量的需求。改进,词袋模型在解决文档分类问题上比词集模型有所提高,移除停用词。
停用词:文本中出现频率很高,但实际意义又不大的词。这一类主要包括了语气助词、副词、介词、连词等,通常自身并无明确意义,只有将其放入一个完整的句子中才有一定作用的词语。如常见的“的”、“在”、“和”、“接着”之类,比如“SEO研究院是原创的SEO博客”这句话中的“是”、“的”就是两个停用词。