NLP系列(4)_朴素贝叶斯实战与进阶

来源:互联网 发布:html5棋牌游戏源码 编辑:程序博客网 时间:2024/05/29 02:46

1.引言

前两篇博文介绍了朴素贝叶斯这个名字读着”萌蠢”但实际上简单直接高效的方法,我们也介绍了一下贝叶斯方法的一些细节。按照老规矩,『锄头』给你了,得负责教教怎么用和注意事项,也顺便带大家去除除草对吧。恩,此节作为更贴近实际应用的部分,将介绍贝叶斯方法的优缺点、常见适用场景和可优化点,然后找点实际场景撸点例子练练手,看看工具怎么用。

PS:本文所有的python代码和ipython notebook已整理至github相应页面,欢迎下载和尝试。

2.贝叶斯方法优缺点

既然讲的是朴素贝叶斯,那博主保持和它一致的风格,简单直接高效地丢干货了:

  • 优点
  1. 对待预测样本进行预测,过程简单速度快(想想邮件分类的问题,预测就是分词后进行概率乘积,在log域直接做加法更快)。
  2. 对于多分类问题也同样很有效,复杂度也不会有大程度上升。
  3. 在分布独立这个假设成立的情况下,贝叶斯分类器效果奇好,会略胜于逻辑回归,同时我们需要的样本量也更少一点
  4. 对于类别类的输入特征变量,效果非常好。对于数值型变量特征,我们是默认它符合正态分布的。
  • 缺点
  1. 对于测试集中的一个类别变量特征,如果在训练集里没见过,直接算的话概率就是0了,预测功能就失效了。当然,我们前面的文章提过我们有一种技术叫做『平滑』操作,可以缓解这个问题,最常见的平滑技术是拉普拉斯估测。
  2. 那个…咳咳,朴素贝叶斯算出的概率结果,比较大小还凑合,实际物理含义…恩,别太当真。
  3. 朴素贝叶斯有分布独立的假设前提,而现实生活中这些predictor很难是完全独立的

3.最常见应用场景

  • 文本分类/垃圾文本过滤/情感判别:这大概会朴素贝叶斯应用做多的地方了,即使在现在这种分类器层出不穷的年代,在文本分类场景中,朴素贝叶斯依旧坚挺地占据着一席之地。原因嘛,大家知道的,因为多分类很简单,同时在文本数据中,分布独立这个假设基本是成立的。而垃圾文本过滤(比如垃圾邮件识别)和情感分析(微博上的褒贬情绪)用朴素贝叶斯也通常能取得很好的效果。
  • 多分类实时预测:这个是不是不能叫做场景?对于文本相关的多分类实时预测,它因为上面提到的优点,被广泛应用,简单又高效。
  • 推荐系统:是的,你没听错,是用在推荐系统里!!朴素贝叶斯和协同过滤(Collaborative Filtering)是一对好搭档,协同过滤是强相关性,但是泛化能力略弱,朴素贝叶斯和协同过滤一起,能增强推荐的覆盖度和效果。

4.朴素贝叶斯注意点

这个部分的内容,本来应该在最后说的,不过为了把干货集中放在代码示例之前,先搁这儿了,大家也可以看完朴素贝叶斯的各种例子之后,回来再看看这些tips。

  • 大家也知道,很多特征是连续数值型的,但是它们不一定服从正态分布,一定要想办法把它们变换调整成满足正态分布!!
  • 对测试数据中的0频次项,一定要记得平滑,简单一点可以用『拉普拉斯平滑』。
  • 先处理处理特征,把相关特征去掉,因为高相关度的2个特征在模型中相当于发挥了2次作用。
  • 朴素贝叶斯分类器一般可调参数比较少,比如scikit-learn中的朴素贝叶斯只有拉普拉斯平滑因子alpha,类别先验概率class_prior和预算数据类别先验fit_prior。模型端可做的事情不如其他模型多,因此我们还是集中精力进行数据的预处理,以及特征的选择吧。
  • 那个,一般其他的模型(像logistic regression,SVM等)做完之后,我们都可以尝试一下bagging和boosting等融合增强方法。咳咳,很可惜,对朴素贝叶斯里这些方法都没啥用。原因?原因是这些融合方法本质上是减少过拟合,减少variance的。朴素贝叶斯是没有variance可以减小。

5. 朴素贝叶斯训练/建模

理论干货和注意点都说完了,来提提怎么快速用朴素贝叶斯训练模型吧。博主一直提倡要站在巨人的肩膀上编程(其实就是懒…同时一直很担忧写出来的代码的健壮性…),咳咳,我们又很自然地把scikit-learn拿过来了。scikit-learn里面有3种不同类型的朴素贝叶斯:

  • 高斯分布型:用于classification问题,假定属性/特征是服从正态分布的。
  • 多项式型:用于离散值模型里。比如文本分类问题里面我们提到过,我们不光看词语是否在文本中出现,也得看出现的次数。如果总词数为n,出现词数为m的话,说起来有点像掷骰子n次出现m次这个词的场景。
  • 伯努利型:这种情况下,就如之前博文里提到的bag of words处理方式一样,最后得到的特征只有0(没出现)和1(出现过)。

根据你的数据集,可以选择scikit-learn中以上任意一种朴素贝叶斯,我们直接举个简单的例子,用高斯分布型朴素贝叶斯建模:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 我们直接取iris数据集,这个数据集有名到都不想介绍了...</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 其实就是根据花的各种数据特征,判定是什么花</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> datasetsiris = datasets.load_iris()iris.data[:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#array([[ 5.1,  3.5,  1.4,  0.2],</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#       [ 4.9,  3. ,  1.4,  0.2],</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#       [ 4.7,  3.2,  1.3,  0.2],</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#       [ 4.6,  3.1,  1.5,  0.2],</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#       [ 5. ,  3.6,  1.4,  0.2]])</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#我们假定sepal length, sepal width, petal length, petal width 4个量独立且服从高斯分布,用贝叶斯分类器建模</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.naive_bayes <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> GaussianNBgnb = GaussianNB()y_pred = gnb.fit(iris.data, iris.target).predict(iris.data)right_num = (iris.target == y_pred).sum()print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Total testing num :%d , naive bayes accuracy :%f"</span> %(iris.data.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>], float(right_num)/iris.data.shape[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># Total testing num :150 , naive bayes accuracy :0.960000</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

你看,朴素贝叶斯分类器,简单直接高效,在150个测试样本上,准确率为96%。

6.朴素贝叶斯之文本主题分类器

这是朴素贝叶斯最擅长的应用场景之一,对于不同主题的文本,我们可以用朴素贝叶斯训练一个分类器,然后将其应用在新数据上,预测主题类型。

6.1 新闻数据分类

我们使用搜狐新闻数据来实验朴素贝叶斯分类器,这部分新闻数据包括it、汽车、财经、健康等9个类别,简洁版数据解压缩后总共16289条新闻,一篇新闻一个txt,我们把数据合并到一个大文件中,一行一篇文章,同时将新闻id(指明新闻的类别)放在文章之前,然后用ICTCLAS(python的话你也可以用结巴分词)进行分词,得到以下的文本内容: 


分词后内容 

我们随机选取3/5的数据作为训练集,2/5的数据作为测试集,采用互信息对文本特征进行提取,提取出1000个左右的特征词。然后用朴素贝叶斯分类器进行训练,实际训练过程就是对于特征词,统计在训练集和各个类别出现的次数,测试阶段做预测也是扫描一遍测试集,计算相应的概率。因此整个过程非常高效,完整的运行代码如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 这部分代码基本纯手撸的...没有调用开源库...大家看看就好...</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#!encoding=utf-8</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> sys, math, random, collections<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">shuffle</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(inFile)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        简单的乱序操作,用于生成训练集和测试集    '''</span>    textLines = [line.strip() <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> line <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> open(inFile)]    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"正在准备训练和测试数据,请稍后..."</span>    random.shuffle(textLines)    num = len(textLines)    trainText = textLines[:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>*num/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>]    testText = textLines[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>*num/<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>:]    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"准备训练和测试数据准备完毕,下一步..."</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> trainText, testText<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#总共有9种新闻类别,我们给每个类别一个编号</span>lables = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'A'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'B'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'C'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'D'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'E'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'F'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'G'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'H'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'I'</span>]<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">lable2id</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(lable)</span>:</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(len(lables)):        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> lable == lables[i]:            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> i    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">raise</span> Exception(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Error lable %s'</span> % (lable))<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">doc_dict</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">()</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        构造和类别数等长的0向量    '''</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> [<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]*len(lables)<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">mutual_info</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(N,Nij,Ni_,N_j)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        计算互信息,这里log的底取为2    '''</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> Nij * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span> / N * math.log(N * (Nij+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)*<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>/(Ni_*N_j))/ math.log(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>)<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">count_for_cates</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(trainText, featureFile)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        遍历文件,统计每个词在每个类别出现的次数,和每类的文档数        并写入结果特征文件    '''</span>    docCount = [<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] * len(lables)    wordCount = collections.defaultdict(doc_dict())    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#扫描文件和计数  </span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> line <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> trainText:        lable,text = line.strip().split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)        index = lable2id(lable[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>])                words = text.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span>)        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> word <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> words:            wordCount[word][index] += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>            docCount[index] += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#计算互信息值</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"计算互信息,提取关键/特征词中,请稍后..."</span>    miDict = collections.defaultdict(doc_dict())    N = sum(docCount)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> k,vs <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> wordCount.items():        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(len(vs)):            N11 = vs[i]            N10 = sum(vs) - N11            N01 = docCount[i] - N11            N00 = N - N11 - N10 - N01            mi = mutual_info(N,N11,N10+N11,N01+N11) + mutual_info(N,N10,N10+N11,N00+N10)+ mutual_info(N,N01,N01+N11,N01+N00)+ mutual_info(N,N00,N00+N10,N00+N01)            miDict[k][i] = mi    fWords = set()    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(len(docCount)):        keyf = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">lambda</span> x:x[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>][i]        sortedDict = sorted(miDict.items(),key=keyf,reverse=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>)        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> j <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">100</span>):            fWords.add(sortedDict[j][<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>])    out = open(featureFile, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'w'</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#输出各个类的文档数目</span>    out.write(str(docCount)+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n"</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#输出互信息最高的词作为特征词</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> fword <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> fWords:        out.write(fword+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n"</span>)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"特征词写入完毕..."</span>    out.close()<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">load_feature_words</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(featureFile)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        从特征文件导入特征词    '''</span>    f = open(featureFile)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#各个类的文档数目</span>    docCounts = eval(f.readline())    features = set()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#读取特征词</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> line <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> f:        features.add(line.strip())    f.close()    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> docCounts,features<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">train_bayes</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(featureFile, textFile, modelFile)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        训练贝叶斯模型,实际上计算每个类中特征词的出现次数    '''</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"使用朴素贝叶斯训练中..."</span>    docCounts,features = load_feature_words(featureFile)    wordCount = collections.defaultdict(doc_dict())    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#每类文档特征词出现的次数</span>    tCount = [<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>]*len(docCounts)    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> line <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> open(textFile):        lable,text = line.strip().split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)        index = lable2id(lable[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>])                words = text.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span>)        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> word <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> words:            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> word <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> features:                tCount[index] += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>                wordCount[word][index] += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>    outModel = open(modelFile, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'w'</span>)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#拉普拉斯平滑</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"训练完毕,写入模型..."</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> k,v <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> wordCount.items():        scores = [(v[i]+<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span> / (tCount[i]+len(wordCount)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(len(v))]        outModel.write(k+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\t"</span>+scores+<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\n"</span>)    outModel.close()<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">load_model</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(modelFile)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        从模型文件中导入计算好的贝叶斯模型    '''</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"加载模型中..."</span>    f = open(modelFile)    scores = {}    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> line <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> f:        word,counts = line.strip().rsplit(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'\t'</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)            scores[word] = eval(counts)    f.close()    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> scores<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">predict</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(featureFile, modelFile, testText)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''        预测文档的类标,标准输入每一行为一个文档    '''</span>    docCounts,features = load_feature_words()        docScores = [math.log(count * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span> /sum(docCounts)) <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> count <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> docCounts]    scores = load_model(modelFile)    rCount = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>    docCount = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"正在使用测试数据验证模型效果..."</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> line <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> testText:        lable,text = line.strip().split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)        index = lable2id(lable[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>])                words = text.split(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">' '</span>)        preValues = list(docScores)        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> word <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> words:            <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> word <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> features:                                <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(len(preValues)):                    preValues[i]+=math.log(scores[word][i])        m = max(preValues)        pIndex = preValues.index(m)        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> pIndex == index:            rCount += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>        <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#print lable,lables[pIndex],text</span>        docCount += <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>    print(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"总共测试文本量: %d , 预测正确的类别量: %d, 朴素贝叶斯分类器准确度:%f"</span> %(rCount,docCount,rCount * <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span> / docCount))       <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> __name__==<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"__main__"</span>:    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> len(sys.argv) != <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">4</span>:    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"Usage: python naive_bayes_text_classifier.py sougou_news.txt feature_file.out model_file.out"</span>    sys.exit()    inFile = sys.argv[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]    featureFile = sys.argv[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>]    modelFile = sys.argv[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>]    trainText, testText = shuffle(inFile)    count_for_cates(trainText, featureFile)    train_bayes(featureFile, trainText, modelFile)    predict(featureFile, modelFile, testText)</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li><li style="box-sizing: border-box; padding: 0px 5px;">43</li><li style="box-sizing: border-box; padding: 0px 5px;">44</li><li style="box-sizing: border-box; padding: 0px 5px;">45</li><li style="box-sizing: border-box; padding: 0px 5px;">46</li><li style="box-sizing: border-box; padding: 0px 5px;">47</li><li style="box-sizing: border-box; padding: 0px 5px;">48</li><li style="box-sizing: border-box; padding: 0px 5px;">49</li><li style="box-sizing: border-box; padding: 0px 5px;">50</li><li style="box-sizing: border-box; padding: 0px 5px;">51</li><li style="box-sizing: border-box; padding: 0px 5px;">52</li><li style="box-sizing: border-box; padding: 0px 5px;">53</li><li style="box-sizing: border-box; padding: 0px 5px;">54</li><li style="box-sizing: border-box; padding: 0px 5px;">55</li><li style="box-sizing: border-box; padding: 0px 5px;">56</li><li style="box-sizing: border-box; padding: 0px 5px;">57</li><li style="box-sizing: border-box; padding: 0px 5px;">58</li><li style="box-sizing: border-box; padding: 0px 5px;">59</li><li style="box-sizing: border-box; padding: 0px 5px;">60</li><li style="box-sizing: border-box; padding: 0px 5px;">61</li><li style="box-sizing: border-box; padding: 0px 5px;">62</li><li style="box-sizing: border-box; padding: 0px 5px;">63</li><li style="box-sizing: border-box; padding: 0px 5px;">64</li><li style="box-sizing: border-box; padding: 0px 5px;">65</li><li style="box-sizing: border-box; padding: 0px 5px;">66</li><li style="box-sizing: border-box; padding: 0px 5px;">67</li><li style="box-sizing: border-box; padding: 0px 5px;">68</li><li style="box-sizing: border-box; padding: 0px 5px;">69</li><li style="box-sizing: border-box; padding: 0px 5px;">70</li><li style="box-sizing: border-box; padding: 0px 5px;">71</li><li style="box-sizing: border-box; padding: 0px 5px;">72</li><li style="box-sizing: border-box; padding: 0px 5px;">73</li><li style="box-sizing: border-box; padding: 0px 5px;">74</li><li style="box-sizing: border-box; padding: 0px 5px;">75</li><li style="box-sizing: border-box; padding: 0px 5px;">76</li><li style="box-sizing: border-box; padding: 0px 5px;">77</li><li style="box-sizing: border-box; padding: 0px 5px;">78</li><li style="box-sizing: border-box; padding: 0px 5px;">79</li><li style="box-sizing: border-box; padding: 0px 5px;">80</li><li style="box-sizing: border-box; padding: 0px 5px;">81</li><li style="box-sizing: border-box; padding: 0px 5px;">82</li><li style="box-sizing: border-box; padding: 0px 5px;">83</li><li style="box-sizing: border-box; padding: 0px 5px;">84</li><li style="box-sizing: border-box; padding: 0px 5px;">85</li><li style="box-sizing: border-box; padding: 0px 5px;">86</li><li style="box-sizing: border-box; padding: 0px 5px;">87</li><li style="box-sizing: border-box; padding: 0px 5px;">88</li><li style="box-sizing: border-box; padding: 0px 5px;">89</li><li style="box-sizing: border-box; padding: 0px 5px;">90</li><li style="box-sizing: border-box; padding: 0px 5px;">91</li><li style="box-sizing: border-box; padding: 0px 5px;">92</li><li style="box-sizing: border-box; padding: 0px 5px;">93</li><li style="box-sizing: border-box; padding: 0px 5px;">94</li><li style="box-sizing: border-box; padding: 0px 5px;">95</li><li style="box-sizing: border-box; padding: 0px 5px;">96</li><li style="box-sizing: border-box; padding: 0px 5px;">97</li><li style="box-sizing: border-box; padding: 0px 5px;">98</li><li style="box-sizing: border-box; padding: 0px 5px;">99</li><li style="box-sizing: border-box; padding: 0px 5px;">100</li><li style="box-sizing: border-box; padding: 0px 5px;">101</li><li style="box-sizing: border-box; padding: 0px 5px;">102</li><li style="box-sizing: border-box; padding: 0px 5px;">103</li><li style="box-sizing: border-box; padding: 0px 5px;">104</li><li style="box-sizing: border-box; padding: 0px 5px;">105</li><li style="box-sizing: border-box; padding: 0px 5px;">106</li><li style="box-sizing: border-box; padding: 0px 5px;">107</li><li style="box-sizing: border-box; padding: 0px 5px;">108</li><li style="box-sizing: border-box; padding: 0px 5px;">109</li><li style="box-sizing: border-box; padding: 0px 5px;">110</li><li style="box-sizing: border-box; padding: 0px 5px;">111</li><li style="box-sizing: border-box; padding: 0px 5px;">112</li><li style="box-sizing: border-box; padding: 0px 5px;">113</li><li style="box-sizing: border-box; padding: 0px 5px;">114</li><li style="box-sizing: border-box; padding: 0px 5px;">115</li><li style="box-sizing: border-box; padding: 0px 5px;">116</li><li style="box-sizing: border-box; padding: 0px 5px;">117</li><li style="box-sizing: border-box; padding: 0px 5px;">118</li><li style="box-sizing: border-box; padding: 0px 5px;">119</li><li style="box-sizing: border-box; padding: 0px 5px;">120</li><li style="box-sizing: border-box; padding: 0px 5px;">121</li><li style="box-sizing: border-box; padding: 0px 5px;">122</li><li style="box-sizing: border-box; padding: 0px 5px;">123</li><li style="box-sizing: border-box; padding: 0px 5px;">124</li><li style="box-sizing: border-box; padding: 0px 5px;">125</li><li style="box-sizing: border-box; padding: 0px 5px;">126</li><li style="box-sizing: border-box; padding: 0px 5px;">127</li><li style="box-sizing: border-box; padding: 0px 5px;">128</li><li style="box-sizing: border-box; padding: 0px 5px;">129</li><li style="box-sizing: border-box; padding: 0px 5px;">130</li><li style="box-sizing: border-box; padding: 0px 5px;">131</li><li style="box-sizing: border-box; padding: 0px 5px;">132</li><li style="box-sizing: border-box; padding: 0px 5px;">133</li><li style="box-sizing: border-box; padding: 0px 5px;">134</li><li style="box-sizing: border-box; padding: 0px 5px;">135</li><li style="box-sizing: border-box; padding: 0px 5px;">136</li><li style="box-sizing: border-box; padding: 0px 5px;">137</li><li style="box-sizing: border-box; padding: 0px 5px;">138</li><li style="box-sizing: border-box; padding: 0px 5px;">139</li><li style="box-sizing: border-box; padding: 0px 5px;">140</li><li style="box-sizing: border-box; padding: 0px 5px;">141</li><li style="box-sizing: border-box; padding: 0px 5px;">142</li><li style="box-sizing: border-box; padding: 0px 5px;">143</li><li style="box-sizing: border-box; padding: 0px 5px;">144</li><li style="box-sizing: border-box; padding: 0px 5px;">145</li><li style="box-sizing: border-box; padding: 0px 5px;">146</li><li style="box-sizing: border-box; padding: 0px 5px;">147</li><li style="box-sizing: border-box; padding: 0px 5px;">148</li><li style="box-sizing: border-box; padding: 0px 5px;">149</li><li style="box-sizing: border-box; padding: 0px 5px;">150</li><li style="box-sizing: border-box; padding: 0px 5px;">151</li><li style="box-sizing: border-box; padding: 0px 5px;">152</li><li style="box-sizing: border-box; padding: 0px 5px;">153</li><li style="box-sizing: border-box; padding: 0px 5px;">154</li><li style="box-sizing: border-box; padding: 0px 5px;">155</li><li style="box-sizing: border-box; padding: 0px 5px;">156</li><li style="box-sizing: border-box; padding: 0px 5px;">157</li><li style="box-sizing: border-box; padding: 0px 5px;">158</li><li style="box-sizing: border-box; padding: 0px 5px;">159</li><li style="box-sizing: border-box; padding: 0px 5px;">160</li><li style="box-sizing: border-box; padding: 0px 5px;">161</li><li style="box-sizing: border-box; padding: 0px 5px;">162</li><li style="box-sizing: border-box; padding: 0px 5px;">163</li><li style="box-sizing: border-box; padding: 0px 5px;">164</li><li style="box-sizing: border-box; padding: 0px 5px;">165</li><li style="box-sizing: border-box; padding: 0px 5px;">166</li><li style="box-sizing: border-box; padding: 0px 5px;">167</li><li style="box-sizing: border-box; padding: 0px 5px;">168</li><li style="box-sizing: border-box; padding: 0px 5px;">169</li><li style="box-sizing: border-box; padding: 0px 5px;">170</li><li style="box-sizing: border-box; padding: 0px 5px;">171</li><li style="box-sizing: border-box; padding: 0px 5px;">172</li></ul>

6.2 分类结果

运行结果如下,在6515条数据上,9个类别的新闻上,有84.1%的准确度: 


朴素贝叶斯分类器结果 

7. Kaggle比赛之『旧金山犯罪分类预测』

7.1 旧金山犯罪分类预测问题

没过瘾对吧,确实每次学完一个机器学习算法,不在实际数据上倒腾倒腾,总感觉不那么踏实(想起来高中各种理科科目都要找点题来做的感觉)。好,我们继续去Kaggle扒点场景和数据来练练手。正巧之前Kaggle上有一个分类问题,场景和数据也都比较简单,我们拿来用朴素贝叶斯试试水。问题请戳这里。

7.2 背景介绍

我们大致介绍一下,说的是『水深火热』的大米国,在旧金山这个地方,一度犯罪率还挺高的,然后很多人都经历过大到暴力案件,小到东西被偷,车被划的事情。当地警方也是努力地去总结和想办法降低犯罪率,一个挑战是在给出犯罪的地点和时间的之后,要第一时间确定这可能是一个什么样的犯罪类型,以确定警力等等。后来干脆一不做二不休,直接把12年内旧金山城内的犯罪报告都丢带Kaggle上,说『大家折腾折腾吧,看看谁能帮忙第一时间预测一下犯罪类型』。犯罪报告里面包括日期描述星期几所属警区处理结果地址GPS定位等信息。当然,分类问题有很多分类器可以选择,我们既然刚讲过朴素贝叶斯,刚好就拿来练练手好了。

7.3 数据一瞥

数据可以在Kaggle比赛数据页面下载到,大家也可以在博主提供的百度网盘地址中下载到。我们依旧用pandas载入数据,先看看数据内容。

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> pandas <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> pd<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#用pandas载入csv训练数据,并解析第一列为日期格式</span>train=pd.read_csv(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/Users/Hanxiaoyang/sf_crime_data/train.csv'</span>, parse_dates = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Dates'</span>])test=pd.read_csv(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/Users/Hanxiaoyang/sf_crime_data/test.csv'</span>, parse_dates = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Dates'</span>])train</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

得到如下的结果: 


旧金山犯罪类型图

我们依次解释一下每一列的含义:

  • Date: 日期
  • Category: 犯罪类型,比如 Larceny/盗窃罪 等.
  • Descript: 对于犯罪更详细的描述
  • DayOfWeek: 星期几
  • PdDistrict: 所属警区
  • Resolution: 处理结果,比如说『逮捕』『逃了』
  • Address: 发生街区位置
  • X and Y: GPS坐标

train.csv中的数据时间跨度为12年,包含了90w+的记录。另外,这部分数据,大家从上图上也可以看出来,大部分都是『类别』型,比如犯罪类型,比如星期几。

7.4 特征预处理

上述数据中类别和文本型非常多,我们要进行特征预处理,对于特征预处理的部分,我们在前面的博文机器学习系列(3)逻辑回归应用之Kaggle泰坦尼克之灾和机器学习系列(6)从白富美相亲看特征预处理与选择(下)都有较细的介绍。对于类别特征,我们用最常见的因子化操作将其转成数值型,比如我们把犯罪类型用因子化进行encode,也就是说生成如下的向量:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">星期一/Monday = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,...星期二/Tuesday = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,...星期三/Wednesday = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,......</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>

我们之前也提到过,用pandas的get_dummies()可以直接拿到这样的一个二值化的01向量。Pandas里面还有一个很有用的方法LabelEncoder可以用于对类别编号。对于已有的数据特征,我们打算做下面的粗略变换:

  • 用LabelEncoder**对犯罪类型做编号**;
  • 处理时间,在我看来,也许犯罪发生的时间点(小时)是非常重要的,因此我们会用Pandas把这部分数据抽出来;
  • 街区星期几时间点用get_dummies()因子化;
  • 做一些组合特征,比如把上述三个feature拼在一起,再因子化一下;

具体的数据和特征处理如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> pandas <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> pd<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.cross_validation <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> train_test_split<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> preprocessing<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#用LabelEncoder对不同的犯罪类型编号</span>leCrime = preprocessing.LabelEncoder()crime = leCrime.fit_transform(train.Category)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#因子化星期几,街区,小时等特征</span>days = pd.get_dummies(train.DayOfWeek)district = pd.get_dummies(train.PdDistrict)hour = train.Dates.dt.hourhour = pd.get_dummies(hour) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#组合特征</span>trainData = pd.concat([hour, days, district], axis=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)trainData[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>]=crime<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#对于测试数据做同样的处理</span>days = pd.get_dummies(test.DayOfWeek)district = pd.get_dummies(test.PdDistrict)hour = test.Dates.dt.hourhour = pd.get_dummies(hour) testData = pd.concat([hour, days, district], axis=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>)trainData</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li></ul>

然后可以看到特征处理后的数据如下所示: 
特征处理之后

7.5 朴素贝叶斯 VS 逻辑回归

拿到初步的特征了,下一步就可以开始建模了。

因为之前的博客机器学习系列(1)逻辑回归初步,机器学习系列(2)从初等数学视角解读逻辑回归,机器学习系列(3)_逻辑回归应用之Kaggle泰坦尼克之灾中提到过逻辑回归这种分类算法,我们这里打算一并拿来建模,做个比较。 
还需要提到的一点是,大家参加Kaggle的比赛,一定要注意最后排名和评定好坏用的标准,比如说在现在这个多分类问题中,Kaggle的评定标准并不是precision,而是multi-class log_loss,这个值越小,表示最后的效果越好。

我们可以快速地筛出一部分重要的特征,搭建一个baseline系统,再考虑步步优化。比如我们这里简单一点,就只取星期几街区作为分类器输入特征,我们用scikit-learn中的train_test_split函数拿到训练集和交叉验证集,用朴素贝叶斯和逻辑回归都建立模型,对比一下它们的表现:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">ffrom sklearn.cross_validation <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> train_test_split<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> preprocessing<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.metrics <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> log_loss<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.naive_bayes <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> BernoulliNB<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.linear_model <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> LogisticRegression<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 只取星期几和街区作为分类器输入特征</span>features = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Monday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Tuesday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Wednesday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Thursday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Friday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Saturday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Sunday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'BAYVIEW'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'CENTRAL'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'INGLESIDE'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'MISSION'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'NORTHERN'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'PARK'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'RICHMOND'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'SOUTHERN'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'TARAVAL'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'TENDERLOIN'</span>]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 分割训练集(3/5)和测试集(2/5)</span>training, validation = train_test_split(trainData, train_size=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.60</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 朴素贝叶斯建模,计算log_loss</span>model = BernoulliNB()nbStart = time.time()model.fit(training[features], training[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>])nbCostTime = time.time() - nbStartpredicted = np.array(model.predict_proba(validation[features]))<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"朴素贝叶斯建模耗时 %f 秒"</span> %(nbCostTime)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"朴素贝叶斯log损失为 %f"</span> %(log_loss(validation[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>], predicted))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#逻辑回归建模,计算log_loss</span>model = LogisticRegression(C=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.01</span>)lrStart= time.time()model.fit(training[features], training[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>])lrCostTime = time.time() - lrStartpredicted = np.array(model.predict_proba(validation[features]))log_loss(validation[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>], predicted)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"逻辑回归建模耗时 %f 秒"</span> %(lrCostTime)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"逻辑回归log损失为 %f"</span> %(log_loss(validation[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>], predicted)) </code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li></ul>

实验的结果如下:


nb vs lr 

我们可以看到目前的特征和参数设定下,朴素贝叶斯的log损失还低一些,另外我们可以明显看到,朴素贝叶斯建模消耗的时间0.640398秒远小于逻辑回归建模42.856376秒。

考虑到犯罪类型可能和犯罪事件发生的小时时间点相关,我们加入小时时间点特征再次建模,代码和结果如下:

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.cross_validation <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> train_test_split<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> preprocessing<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.metrics <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> log_loss<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.naive_bayes <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> BernoulliNB<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.linear_model <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> LogisticRegression<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> time<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 添加犯罪的小时时间点作为特征</span>features = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Friday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Monday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Saturday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Sunday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Thursday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Tuesday'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'Wednesday'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'BAYVIEW'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'CENTRAL'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'INGLESIDE'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'MISSION'</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'NORTHERN'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'PARK'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'RICHMOND'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'SOUTHERN'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'TARAVAL'</span>, <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'TENDERLOIN'</span>]hourFea = [x <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> x <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> range(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">24</span>)]features = features + hourFea<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 分割训练集(3/5)和测试集(2/5)</span>training, validation = train_test_split(trainData, train_size=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.60</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 朴素贝叶斯建模,计算log_loss</span>model = BernoulliNB()nbStart = time.time()model.fit(training[features], training[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>])nbCostTime = time.time() - nbStartpredicted = np.array(model.predict_proba(validation[features]))<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"朴素贝叶斯建模耗时 %f 秒"</span> %(nbCostTime)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"朴素贝叶斯log损失为 %f"</span> %(log_loss(validation[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>], predicted))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#逻辑回归建模,计算log_loss</span>model = LogisticRegression(C=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">.01</span>)lrStart= time.time()model.fit(training[features], training[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>])lrCostTime = time.time() - lrStartpredicted = np.array(model.predict_proba(validation[features]))log_loss(validation[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>], predicted)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"逻辑回归建模耗时 %f 秒"</span> %(lrCostTime)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"逻辑回归log损失为 %f"</span> %(log_loss(validation[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'crime'</span>], predicted))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li></ul>


添加小时时间点后的结果 

可以看到在这三个类别特征下,朴素贝叶斯相对于逻辑回归,依旧有一定的优势(log损失更小),同时训练时间很短,这意味着模型虽然简单,但是效果依旧强大。顺便提一下,朴素贝叶斯1.13s训练出来的模型,预测的效果在Kaggle排行榜上已经能进入Top 35%了,如果进行一些优化,比如特征处理、特征组合等,结果会进一步提高。

8. Kaggle比赛之影评与观影者情感判定

博主想了想,既然朴素贝叶斯最常见的应用场景就那么几个,干脆我们都一并覆盖得了。咳咳,对,还有一个非常重要的应用场景是情感分析(尤其是褒贬判定),于是我又上Kaggle溜达了一圈,扒下来一个类似场景的比赛。比赛的名字叫做当词袋/Bag of words 遇上 爆米花/Bags of Popcorn,地址为https://www.kaggle.com/c/word2vec-nlp-tutorial/,有兴趣的同学可以上去瞄一眼。

8.1 背景介绍

这个比赛的背景大概是:国外有一个类似豆瓣电影一样的IMDB,也是你看完电影,可以上去打个分,吐个槽的地方。然后大家就在想,有这么多数据,总得折腾点什么吧,于是乎,第一个想到的就是,赞的喷的内容都有了,咱们就来分分类,看看能不能根据内容分布褒贬。PS:很多同学表示,分个褒贬有毛线难的,咳咳,计算机比较笨,另外,语言这种东西,真心是博大精深的,我们随手从豆瓣上抓了几条《功夫熊猫3》影评下来,表示有些虽然我是能看懂,但是不处理直接给计算机看,它应该是一副『什么鬼』的表情。。。


功夫熊猫3影评 

多说一句,Kaggle原文引导里是用word2vec的方式将词转为词向量,后再用deep learning的方式做的。深度学习好归好,但是毕竟耗时耗力耗资源,我们用最最naive的朴素贝叶斯撸一把,说不定效果也能不错,不试试谁知道呢。另外,朴素贝叶斯建模真心速度快,很多场景下,快速建模快速迭代优化正是我们需要的嘛。

8.2 数据一瞥

言归正传,回到Kaggle中这个问题上来,先瞄一眼数据。Kaggle数据页面地址为https://www.kaggle.com/c/word2vec-nlp-tutorial/data,大家也可以到博主的百度网盘中下载。数据包如下图所示:


Kaggle影评数据页面 

其中包含有情绪标签的训练数据labeledTrainData,没有情绪标签的训练数据unlabeledTrainData,以及测试数据testData。labeledTrainData包括idsentiment和**review**3个部分,分别指代用户id,情感标签,评论内容。

解压缩labeledTrainData后用vim打开,内容如下:


训练数据内容

下面我们读取数据并做一些基本的预处理(比如说把评论部分的html标签去掉等等):

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> re  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#正则表达式</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> bs4 <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> BeautifulSoup  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#html标签处理</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> pandas <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> pd<span class="hljs-function" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">def</span> <span class="hljs-title" style="box-sizing: border-box;">review_to_wordlist</span><span class="hljs-params" style="color: rgb(102, 0, 102); box-sizing: border-box;">(review)</span>:</span>    <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'''    把IMDB的评论转成词序列    '''</span>    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 去掉HTML标签,拿到内容</span>    review_text = BeautifulSoup(review).get_text()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 用正则表达式取出符合规范的部分</span>    review_text = re.sub(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"[^a-zA-Z]"</span>,<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" "</span>, review_text)    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 小写化所有的词,并转成词list</span>    words = review_text.lower().split()    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 返回words</span>    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> words<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 使用pandas读入训练和测试csv文件</span>train = pd.read_csv(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/Users/Hanxiaoyang/IMDB_sentiment_analysis_data/labeledTrainData.tsv'</span>, header=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, delimiter=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\t"</span>, quoting=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>)test = pd.read_csv(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'/Users/Hanxiaoyang/IMDB_sentiment_analysis_data/testData.tsv'</span>, header=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, delimiter=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"\t"</span>, quoting=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span> )<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 取出情感标签,positive/褒 或者 negative/贬</span>y_train = train[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'sentiment'</span>]<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 将训练和测试数据都转成词list</span>train_data = []<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,len(train[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'review'</span>])):    train_data.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" "</span>.join(review_to_wordlist(train[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'review'</span>][i])))test_data = []<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> i <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">in</span> xrange(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>,len(test[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'review'</span>])):    test_data.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">" "</span>.join(review_to_wordlist(test[<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'review'</span>][i])))</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li></ul>

我们在ipython notebook里面看一眼,发现数据已经格式化了,如下: 


格式化后的数据

8.3 特征处理

紧接着又到了头疼的部分了,数据有了,我们得想办法从数据里面拿到有区分度的特征。比如说Kaggle该问题的引导页提供的word2vec就是一种文本到数值域的特征抽取方式,比如说我们在第6小节提到的用互信息提取关键字也是提取特征的一种。比如说在这里,我们打算用在文本检索系统中非常有效的一种特征:TF-IDF(term frequency-interdocument frequency)向量。每一个电影评论最后转化成一个TF-IDF向量。对了,对于TF-IDF不熟悉的同学们,我们稍加解释一下,TF-IDF是一种统计方法,用以评估一字词(或者n-gram)对于一个文件集或一个语料库中的其中一份文件的重要程度。字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料库中出现的频率成反比下降。这是一个能很有效地判定对评论褒贬影响大的词或短语的方法。

那个…博主打算继续偷懒,把scikit-learn中TFIDF向量化方法直接拿来用,想详细了解的同学可以戳sklearn TFIDF向量类。对了,再多说几句我的处理细节,停用词被我掐掉了,同时我在单词的级别上又拓展到2元语言模型(对这个不了解的同学别着急,后续的博客介绍马上就来),恩,你可以再加3元4元语言模型…博主主要是单机内存不够了,先就2元上,凑活用吧…

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.feature_extraction.text <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> TfidfVectorizer <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> TFIV<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 初始化TFIV对象,去停用词,加2元语言模型</span>tfv = TFIV(min_df=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">3</span>,  max_features=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>, strip_accents=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'unicode'</span>, analyzer=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'word'</span>,token_pattern=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">r'\w{1,}'</span>, ngram_range=(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>), use_idf=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,smooth_idf=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,sublinear_tf=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, stop_words = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'english'</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 合并训练和测试集以便进行TFIDF向量化操作</span>X_all = train_data + test_datalen_train = len(train_data)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 这一步有点慢,去喝杯茶刷会儿微博知乎歇会儿...</span>tfv.fit(X_all)X_all = tfv.transform(X_all)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 恢复成训练集和测试集部分</span>X = X_all[:len_train] X_test = X_all[len_train:]</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li></ul>

8.4 朴素贝叶斯 vs 逻辑回归

特征现在我们拿到手了,该建模了,好吧,博主折腾劲又上来了,那个…咳咳…我们还是朴素贝叶斯和逻辑回归都建个分类器吧,然后也可以比较比较,恩。 
『talk is cheap, I’ll show you the code』,直接放码过来了哈。

<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 多项式朴素贝叶斯</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.naive_bayes <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> MultinomialNB <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> MNBmodel_NB = MNB()model_NB.fit(X, y_train) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#特征数据直接灌进来</span>MNB(alpha=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>, class_prior=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>, fit_prior=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>)<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.cross_validation <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> cross_val_score<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> numpy <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> np<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"多项式贝叶斯分类器20折交叉验证得分: "</span>, np.mean(cross_val_score(model_NB, X, y_train, cv=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, scoring=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'roc_auc'</span>))<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 多项式贝叶斯分类器20折交叉验证得分: 0.950837239</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>
<code class="language-python hljs  has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 折腾一下逻辑回归,恩</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.linear_model <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> LogisticRegression <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">as</span> LR<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">from</span> sklearn.grid_search <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> GridSearchCV<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 设定grid search的参数</span>grid_values = {<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'C'</span>:[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>]}  <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 设定打分为roc_auc</span>model_LR = GridSearchCV(LR(penalty = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'L2'</span>, dual = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>, random_state = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>), grid_values, scoring = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'roc_auc'</span>, cv = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 数据灌进来</span>model_LR.fit(X,y_train)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;"># 20折交叉验证,开始漫长的等待...</span>GridSearchCV(cv=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">20</span>, estimator=LogisticRegression(C=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1.0</span>, class_weight=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>, dual=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>,              fit_intercept=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>, intercept_scaling=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, penalty=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'L2'</span>, random_state=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>, tol=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0.0001</span>),        fit_params={}, iid=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>, loss_func=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>, n_jobs=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>,        param_grid={<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'C'</span>: [<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">30</span>]}, pre_dispatch=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'2*n_jobs'</span>, refit=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">True</span>,        score_func=<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">None</span>, scoring=<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'roc_auc'</span>, verbose=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">#输出结果</span><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">print</span> model_LR.grid_scores_</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

最后逻辑回归的结果是[mean: 0.96459, std: 0.00489, params: {'C': 30}]

咳咳…看似逻辑回归在这个问题中,TF-IDF特征下表现要稍强一些…不过同学们自己跑一下就知道,这2个模型的训练时长真心不在一个数量级,逻辑回归在数据量大的情况下,要等到睡着…另外,要提到的一点是,因为我这里只用了2元语言模型(2-gram),加到3-gram和4-gram,最后两者的结果还会提高,而且朴素贝叶斯说不定会提升更快一点,内存够的同学们自己动手试试吧^_^

9. 总结

本文为朴素贝叶斯的实践和进阶篇,先丢了点干货,总结了贝叶斯方法的优缺点,应用场景,注意点和一般建模方法。紧接着对它最常见的应用场景,抓了几个例子,又来了一遍手把手系列,不管是对于文本主题分类、多分类问题(犯罪类型分类) 还是 情感分析/分类,朴素贝叶斯都是一个简单直接高效的方法。尤其是在和逻辑回归的对比中可以看出,在这些问题中,朴素贝叶斯能取得和逻辑回归相近的成绩,但是训练速度远快于逻辑回归,真正的直接和高效。

0 0
原创粉丝点击