欢迎关注个人博客:枫之羽

前言

   这部分内容侧重于机器学习的应用以及如何使用sklearn和调优。该部分内容基于Udacity的机器学习入门课程,偏重实践,有兴趣的可以看看,也可以一起学习。

1、朴素贝叶斯

训练分类器

from sklearn.naive_bayes import GaussianNB

clf = GaussianNB()  # 创建分类器
clf.fit(features_train, labels_train)  # 使用训练特征和标签进行拟合
pred = clf.predict(features_test)  # 预测

评估分类器效果

准确性:正确分类的测试点数目除以测试点总数

两种方法:

  • 根据定义计算准确性
  • 使用sklearn的accuracy_score()方法from sklearn.met
from sklearn.metrics import accuracy_score

print(accuracy_score(pred, labels_test))  # 参数normalize=Flase时方法返回的是正确个数,默认为True

先验概率和后验概率

先验概率

P(C)=0.1,P(ℸC)=0.9

后验概率

Posterior 应该写为:

P(C, Pos) = P(C) • P(Pos|C)

P(ℸC, Pos) = P(ℸC)• P(Pos|ℸC)

朴素贝叶斯之所以“朴素”。

举例:A,B两个人在邮件中都喜欢使用love,deal,life这三个单词,但是使用频率不同。(这里只是为了说明“朴素”一次,因此不给出词频)

然后给定love life,问是那个人说的概率比较大。

这个答案可以根据贝叶斯公式、先验概率和后验概率计算得到。

那么它的朴素是因为什么?  当然是没有考虑单词的顺序啦。。在计算的时候是p1*p2*……*pn,没有把顺序考虑在内。

朴素贝叶斯实战(迷你项目)

几年前,J.K. 罗琳(凭借《哈利波特》出名)试着做了件有趣的事。她以 Robert Galbraith 的化名写了本名叫《The Cuckoo’s Calling》的书。尽管该书得到一些不错的评论,但是大家都不太重视它,直到 Twitter 上一个匿名的知情人士说那是 J.K. Rowling 写的。《伦敦周日泰晤士报》找来两名专家对《杜鹃在呼唤》和 Rowling 的《偶发空缺》以及其他几名作者的书进行了比较。分析结果强有力地指出罗琳就是作者,《泰晤士报》直接询问出版商情况是否属实,而出版商也证实了这一说法,该书在此后一夜成名。

我们也将在此项目中做类似的事。我们有一组邮件,分别由同一家公司的两个人撰写其中半数的邮件。我们的目标是仅根据邮件正文区分每个人写的邮件。在这个迷你项目一开始,我们将使用朴素贝叶斯,并在之后的项目中扩展至其他算法。

我们会先给你一个字符串列表。每个字符串代表一封经过预处理的邮件的正文;然后,我们会提供代码,用来将数据集分解为训练集和测试集(在下节课中,你将学习如何进行预处理和分解,但是现在请使用我们提供的代码)。

朴素贝叶斯特殊的一点在于,这种算法非常适合文本分类。在处理文本时,常见的做法是将每个单词看作一个特征,这样就会有大量的特征。此算法的相对简单性和朴素贝叶斯独立特征的这一假设,使其能够出色完成文本的分类。在这个迷你项目中,你将在计算机中下载并安装 sklearn,然后使用朴素贝叶斯根据作者对邮件进行分类。

 

安装Python,建议IDE使用Pycharm(个人喜好).然后安装一些python包。

  1. 安装自然语言工具包:pip install nltk
  2. 获取机器学习简介源代码。你将需要 git 来复制资源库:git clone https://github.com/udacity/ud120-projects.git

你只需操作一次,基础代码包含所有迷你项目的初始代码。进入 tools/ 目录,运行 startup.py。该程序首先检查 python 模块,然后下载并解压缩我们在后期将大量使用的大型数据集。下载和解压缩需要一些时间,但是你无需等到全部完成再开始第一部分。

在 naive_bayes/nb_author_id.py 中创建和训练朴素贝叶斯分类器,用其为测试集进行预测。准确率是多少?

0.9732650739476678 【核心代码附在下文】

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 1.17324280739

[0 0 1 ... 1 0 0]

0.9732650739476678

predict time 0.159196138382

在训练期间,你可能会看到以下错误:“用户警告:分数重复。结果可能取决于特征排序,或者你对回归任务使用了分类分数。” 警告(“分数重复。结果可能取决于特征排序。”)

邮件中两个以上的单词恰巧具有相同的使用模式时,会出现这一警告—对算法而言,这表示两个特征是相同的。当重复特征出现时,一些算法实际上会中断(数学上无法运行),或给出多个不同的答案(取决于特征排序),然后 sklearn 发出警告。这种信息能起到帮助作用,所以我们无需担心。

核心代码

#!/usr/bin/python

""" 
    This is the code to accompany the Lesson 1 (Naive Bayes) mini-project. 

    Use a Naive Bayes Classifier to identify emails by their authors
    
    authors and labels:
    Sara has label 0
    Chris has label 1
"""
    
import sys
from time import time
sys.path.append("../tools/")
from email_preprocess import preprocess


### features_train and features_test are the features for the training
### and testing datasets, respectively
### labels_train and labels_test are the corresponding item labels
features_train, features_test, labels_train, labels_test = preprocess()



start_time = time()
#########################################################
### your code goes here ###
from sklearn.naive_bayes import GaussianNB

clf = GaussianNB()
clf.fit(features_train, labels_train)

fit_time = time()
print"traing time",fit_time - start_time

pred = clf.predict(features_test)
print (pred)

from sklearn.metrics import accuracy_score
print accuracy_score(pred, labels_test)

predict_time = time()
print "predict time",predict_time - fit_time
#########################################################
2、支持向量机

训练分类器

from sklearn.svm import SVC

clf = SVC(kernel=”linear”)

clf.fit(features_train, labels_train)

 

pred = clf.predict(fetures_test)

核技巧

 

SVM参数

kernel:核,默认为’rbf’,还有linear,poly,sigmod,precomputed

gamma:默认为auto

C:平滑项,越大边界越平滑得到更多正确的训练点

SVM实战(迷你项目)

这个项目依然是朴素贝叶斯中的项目,只是换成了支持向量机来实现了。

另外会介绍如何通过调整参数来优化提高准确率。

      在此迷你项目中,我们将解决与朴素贝叶斯迷你项目相同的电子邮件作者 ID 问题,不同的是我们将运用 SVM。我们的研究结果将阐明两种算法之间的一些实际差异。此项目还向我们提供比朴素贝叶斯更多的机会来使用参数,因此我们也将这样做。

转到 svm 目录,查找初始代码 (svm/svm_author_id.py)。

使用 sklearn SVC 分类器进行导入、创建、训练和预测。在创建分类器时使用线性内核(如果你忘记此步骤,你会发现分类器要花很长的时间来训练)。

分类器的准确率是多少?

准确率:0.9840728100113766

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 197.081834078

[0 0 1 ... 1 0 0]

predict time 20.2912540436

0.9840728100113766

核心代码

svm_author_id.py

#!/usr/bin/python

""" 
    This is the code to accompany the Lesson 2 (SVM) mini-project.

    Use a SVM to identify emails from the Enron corpus by their authors:    
    Sara has label 0
    Chris has label 1
"""

import sys
from time import time

sys.path.append("../tools/")
from email_preprocess import preprocess

### features_train and features_test are the features for the training
### and testing datasets, respectively
### labels_train and labels_test are the corresponding item labels
features_train, features_test, labels_train, labels_test = preprocess()

start_time = time()
#########################################################
### your code goes here ###
from sklearn.svm import SVC

clf = SVC(kernel="linear")
clf.fit(features_train, labels_train)

fit_time = time()
print"traing time",fit_time - start_time

pred = clf.predict(features_test)
print(pred)
predict_time = time()
print "predict time",predict_time - fit_time

from sklearn.metrics import accuracy_score

accuracy = accuracy_score(pred, labels_test)

print(accuracy)
#########################################################

Naive_Bayes与SVM的比较

SVM在训练和预测时相比Naive_Bayes慢很多。【你可以从运行结果中打印的时间看出来】

调参与优化

更小的数据集

加快算法速度的一种方式是在一个较小的训练数据集上训练它。这样做换来的是准确率几乎肯定会下降。让我们更具体地探讨这个问题:在训练分类器之前,立即加入以下两行。 

features_train = features_train[:len(features_train)/100] 
labels_train = labels_train[:len(labels_train)/100] 


这两行有效地将训练数据集切割至原始大小的 1%,丢弃掉 99% 的训练数据。你可以使其他所有代码保持不变。

现在的准确率是多少?

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 0.28026509285

[0 1 1 ... 1 0 1]

predict time 1.30546784401

0.8845278725824801

如果速度是一个主要考虑因素(对于许多实时机器学习应用而言确实如此),并且如果牺牲一些准确率可加快你的训练/预测速度,则你可能会想这样做。

在以下哪些应用中,你可以想象非常快速地运行的算法尤其重要?

·  >预测电子邮件作者

·  标记信用卡欺诈,在欺诈发生之前阻止交易

·  Siri 之类的语音识别

部署RBF内核

保留上一个测试题中的训练集代码段,以便仍在 1% 的完整训练集上进行训练。将 SVM 的内核更改为“rbf”。

这个更复杂的内核给出的准确率是多少?

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 0.149940013885

[0 1 1 ... 1 1 1]

predict time 1.56838107109

0.6160409556313993

优化C参数

保持训练集大小不变,并且保留上一个测试题中的 rbf 内核,但是尝试多个 C 值(比如:10.0、100.、1000. 和 10000.)。

哪个给出的准确率最高?

C=10.0 0.6160409556313993

C=100 0.6160409556313993

C=1000 0.8213879408418657

C=10000 0.8924914675767918

优化C后的准确率

在你为 RBF 内核优化了 C 值后,你会获得怎样的准确率?该 C 值是否对应更简单或者更复杂的决策边界?

(如果你不确定复杂度,请回顾本节课有关“SVM C 参数”的视频。你在该处发现的结果同样适用于此处,不过,在简单的散点图中画出决策边界现在变得更加困难甚至不可能。)

优化后的RBF与现行SVM:准确率

你已经为 RBF 内核优化了 C,现在恢复为使用完整的训练集。较大的训练集往往能提高算法的性能,所以(通过在大数据集上调整 C 和进行训练)我们应得到相当优化的结果。

经过优化的 SVM 的准确率是多少?

no. of Chris training emails: 7936

no. of Sara training emails: 7884

traing time 133.572846889

[0 0 1 ... 1 0 0]

predict time 12.8665001392

0.9908987485779295

从SVM提取预测

你的 SVM(0 或 1,分别对应 Sara 和 Chris)将测试集中的元素 10 预测为哪一类?元素 26 ?还是元素 50 ?

(使用 RBF 内核、C=10000 和 1% 的训练集。通常,使用完整的训练集能获得最好的结果,但是我们发现使用 1% 的完整训练集不仅大幅加快计算过程,而且不会改变我们的结果,因此你在这里可以随意使用该快捷算法。)

而且需要说明的是,我们这里给出的数据点数字 (10, 26, 50) 假设使用的是零索引列表。因此,使用类似于 answer=predictions[100] 的表达式可找到元素 # 100 的正确答案。

print(clf.predict(features_test[10]))
print(clf.predict(features_test[26]))
print(clf.predict(features_test[20]))

输出为1 ,0,1

预测有多少Chris的邮件

There are over 1700 test events--how many are predicted to be in the “Chris” (1) class? (Use the RBF kernel, C=10000., and the full training set.) 测试事件的数量超过 1700——其中多少预测在“Chris” (1) 类中?(使用 RBF 内核、C=10000. 以及完整的训练集。)

print "no. of Chris predicting emails:", sum(clf.predict(features_test))
print "no. of Sara predicting emails:", len(clf.predict(features_test))-sum(clf.predict(features_test))redict

no. of Chris predicting emails: 877

no. of Sara predicting emails: 881

小结

希望 Sebastian 在说朴素贝叶斯非常适合文本时,更清楚地表达了他的意思。对于这一具体问题,朴素贝叶斯不仅更快,而且通常比 SVM 更出色。当然,SVM 更适合许多其他问题。你在第一次求解问题时就知道该尝试哪个算法,这是机器学习艺术和科学性的一个体现。除了选择算法外,视你尝试的算法而定,你还需要考虑相应的参数调整以及过拟合的可能性(特别是在你没有大量训练数据的情况下)。

我们通常建议你尝试一些不同的算法来求解每个问题。调整参数的工作量很大,但你现在只需要听完这堂课,我们将向你介绍 GridCV,一种几乎能自动查找最优参数调整的优秀 sklearn 工具。

 

最近更新于2018.9.18,有问题或者建议请留言,谢谢~