上次去深圳招行面试。被问到了这个。中间讨论了几个关于贝叶斯的问题。可能我并不偏向知识图谱。然后就没有下文了。
结合李航的《统计学》和几篇博客,还有在凤凰网某位仁兄贡献新闻分类的源码。给自己复习一下。
为什么叫朴素贝叶斯和大学课本里的贝叶斯有什么不同?
朴素一词来源于==>假设各特征之间相互独立。这一假设使得朴素贝叶斯算法变得简单,但有时会牺牲一定的分类准确率。
招行的那位小姐姐有先验。说的就是这个。
大学里面的贝叶斯
算法使用的朴素贝叶斯(怎么我感觉叫条件特征独立贝叶斯更好呢):
条件独立假设:
就是说分类特征在类确定的条件下都是独立的。
朴素贝叶斯分类时,对于给定输出的x,通过学习得到的模型计算后验概率分布p(Y=ck|X=x),将后验概率最大的类作为x的类输出,后验概率计算根据贝叶斯定理进行:
把特征独立条件带入上面公式:
所以贝叶斯分类器可以表示为:
因为分母对于所有的K都是相同的,公式可以简化为
朴素贝叶斯法的参数估计
学习就意味着估计,使用极大似然估计法估计相应的概率。
先验概率的极大似然估计是
条件概率的极大似然估计是
朴素贝叶斯的优缺点
优点:
(1) 算法逻辑简单,易于实现(算法思路很简单,只要使用贝叶斯公式转化即可!)
(2)分类过程中时空开销小(假设特征相互独立,只会涉及到二维存储)
缺点:
朴素贝叶斯假设属性之间相互独立,这种假设在实际过程中往往是不成立的。在属性之间相关性越大,分类误差也就越大。
朴素贝叶斯实战
sklearn中有3种不同类型的朴素贝叶斯:
高斯分布型:用于classification问题,假定属性/特征服从正态分布的。
多项式型:用于离散值模型里。比如文本分类问题里面我们提到过,我们不光看词语是否在文本中出现,也得看出现次数。如果总词数为n,出现词数为m的话,有点像掷骰子n次出现m次这个词的场景。
伯努利型:最后得到的特征只有0(没出现)和1(出现过)。
莺尾花Demo
https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.cross_val_score.html
from sklearn.naive_bayes import GaussianNB from sklearn.model_selection import cross_val_score from sklearn import datasets iris = datasets.load_iris() gnb = GaussianNB() scores=cross_val_score(gnb, iris.data, iris.target, cv=10) print(scores)
[ 0.93333333 0.93333333 1. 0.93333333 0.93333333 0.93333333 0.86666667 1. 1. 1. ]
kaggle比赛中旧金山犯罪
1.数据观察
import pandas as pd import numpy as np from sklearn import preprocessing from sklearn.metrics import log_loss from sklearn.cross_validation import train_test_split train = pd.read_csv('train.csv', parse_dates = ['Dates']) test = pd.read_csv('test.csv', parse_dates = ['Dates'])
train
特征为
Date: 日期
Category: 犯罪类型,比如 Larceny/盗窃罪 等.
Descript: 对于犯罪更详细的描述
DayOfWeek: 星期几
PdDistrict: 所属警区
Resolution: 处理结果『逮捕』『逃了』
Address: 发生街区位置
X and Y: GPS坐标
2.特征处理
sklearn.preprocessing模块中的 LabelEncoder函数可以对类别做编号,我们用它对犯罪类型做编号;
pandas中的get_dummies( )可以将变量进行二值化01向量,我们用它对”街区“、”星期几“、”时间点“进行因子化。
#对犯罪类别:Category; 用LabelEncoder进行编号 leCrime = preprocessing.LabelEncoder() crime = leCrime.fit_transform(train.Category) #39种犯罪类型 #用get_dummies因子化星期几、街区、小时等特征 days=pd.get_dummies(train.DayOfWeek) district = pd.get_dummies(train.PdDistrict) hour = train.Dates.dt.hour hour = pd.get_dummies(hour) #组合特征 trainData = pd.concat([hour, days, district], axis = 1) #将特征进行横向组合 trainData['crime'] = crime #追加'crime'列 days = pd.get_dummies(test.DayOfWeek) district = pd.get_dummies(test.PdDistrict) hour = test.Dates.dt.hour hour = pd.get_dummies(hour) testData = pd.concat([hour, days, district], axis=1) trainData
3.建立贝叶斯模型
from sklearn.naive_bayes import BernoulliNB import time features=['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'BAYVIEW', 'CENTRAL', 'INGLESIDE', 'MISSION', 'NORTHERN', 'PARK', 'RICHMOND', 'SOUTHERN', 'TARAVAL', 'TENDERLOIN'] X_train, X_test, y_train, y_test = train_test_split(trainData[features], trainData['crime'], train_size=0.6) NB = BernoulliNB() nbStart = time.time() NB.fit(X_train, y_train) nbCostTime = time.time() - nbStart print(X_test.shape) propa = NB.predict_proba(X_test) #X_test为263415*17; 那么该行就是将263415分到39种犯罪类型中,每个样本被分到每一种的概率 print("朴素贝叶斯建模%.2f秒"%(nbCostTime)) predicted = np.array(propa) logLoss=log_loss(y_test, predicted) print("朴素贝叶斯的log损失为:%.6f"%logLoss)
输出:
(351220, 17) 朴素贝叶斯建模0.87秒 朴素贝叶斯的log损失为:2.615733
凤凰新闻的文章
package com.ifeng.classify.Util; import java.io.Serializable; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; public class NativeBayes implements Serializable { /** * 序列化ID */ private static final long serialVersionUID = -5809782578272943999L; /** * 默认频率 */ private double defaultFreq = 0.1; /** * 训练数据的比例 */ private Double trainingPercent = 0.8; private Map<String, List<String>> files_all = new HashMap<String, List<String>>(); private Map<String, List<String>> files_train = new HashMap<String, List<String>>(); private Map<String, List<String>> files_test = new HashMap<String, List<String>>(); public NativeBayes() { } /** * 每个分类的频数 */ private Map<String, Integer> classFreq = new HashMap<String, Integer>(); /** * 每个分类所占的百分比 先验概率 p(yi) */ private Map<String, Double> ClassProb = new HashMap<String, Double>(); /** * 特征总数 */ private Set<String> WordDict = new HashSet<String>(); /** * 每个分类中每个特征的频数 */ private Map<String, Map<String, Integer>> classFeaFreq = new HashMap<String, Map<String, Integer>>(); /** * 每个分类中每个特征的概率 p(xi/yi) */ private Map<String, Map<String, Double>> ClassFeaProb = new HashMap<String, Map<String, Double>>(); /** * 每个分类默认的概率 */ private Map<String, Double> ClassDefaultProb = new HashMap<String, Double>(); public double getDefaultFreq() { return defaultFreq; } public void setDefaultFreq(double defaultFreq) { this.defaultFreq = defaultFreq; } public Double getTrainingPercent() { return trainingPercent; } public void setTrainingPercent(Double trainingPercent) { this.trainingPercent = trainingPercent; } public Map<String, List<String>> getFiles_all() { return files_all; } public void setFiles_all(Map<String, List<String>> files_all) { this.files_all = files_all; } public Map<String, List<String>> getFiles_train() { return files_train; } public void setFiles_train(Map<String, List<String>> files_train) { this.files_train = files_train; } public Map<String, List<String>> getFiles_test() { return files_test; } public void setFiles_test(Map<String, List<String>> files_test) { this.files_test = files_test; } public Map<String, Integer> getClassFreq() { return classFreq; } public void setClassFreq(Map<String, Integer> classFreq) { this.classFreq = classFreq; } public Map<String, Double> getClassProb() { return ClassProb; } public void setClassProb(Map<String, Double> classProb) { ClassProb = classProb; } public Set<String> getWordDict() { return WordDict; } public void setWordDict(Set<String> wordDict) { WordDict = wordDict; } public Map<String, Map<String, Integer>> getClassFeaFreq() { return classFeaFreq; } public void setClassFeaFreq(Map<String, Map<String, Integer>> classFeaFreq) { this.classFeaFreq = classFeaFreq; } public Map<String, Map<String, Double>> getClassFeaProb() { return ClassFeaProb; } public void setClassFeaProb(Map<String, Map<String, Double>> classFeaProb) { ClassFeaProb = classFeaProb; } public Map<String, Double> getClassDefaultProb() { return ClassDefaultProb; } public void setClassDefaultProb(Map<String, Double> classDefaultProb) { ClassDefaultProb = classDefaultProb; } }