朴素贝叶斯分类器
贝叶斯公式
联合概率
$P(X=x, Y=y)$ 是指$X$ 取值为$x$ 且$Y$ 取值为$y$ 的概率,显然
$$
P(X,Y) = P(Y|X) \cdot P(X) = P(X|Y) \cdot P(Y)
$$
于是得到贝叶斯公式:
$$
P(X|Y) = \frac{P(X) \cdot P(Y|X)}{P(Y)}
$$
朴素贝叶斯分类器的使用
这里举一个简单的例子,来说明贝叶斯分类器算法的过程。现在假设某公司要发布某种产品,在发布产品前,先进行了用户调查,获得如下信息:
性别(A) | 年龄(B) | 婚姻状况(C) | 是否购买(X) |
---|---|---|---|
M | 小 | 未婚 | Yes |
F | 中 | 已婚 | No |
F | 小 | 未婚 | Yes |
M | 大 | 已婚 | No |
M | 中 | 离异 | No |
M | 中 | 未婚 | Yes |
F | 大 | 已婚 | No |
M | 大 | 未婚 | No |
F | 大 | 未婚 | No |
F | 中 | 已婚 | No |
现在来预测用户$X(A=F,B=中,C=离异)$ 是否会购买此产品?
$$
P(X=Yes|A=F,B=中,C=离异) = \frac{P(X=Yes)}{P(A=F,B=中,C=离异)} \cdot P(A=F,B=中,C=离异|X=Yes)
$$
其中令 $\frac{1}{P(A=F,B=中,C=离异)}=\Delta$ , 而
$$
P(A=F,B=中,C=离异|X=Yes) = P(A=F|Yes) \cdot P(B=中|Yes) \cdot P(C=离异|Yes)
$$
现在分别计算购买相应的概率:
$$
P(X=Yes) = \frac{3}{10} \
P(A=F|Yes) = \frac{1}{3} \
P(B=中|Yes) = \frac{1}{3} \
P(C=离异|Yes) = 0 \
P(X=Yes|A=F,B=中,C=离异) = \Delta \cdot \frac{3}{10} \cdot\frac{1}{3}\cdot\frac{1}{3}\cdot 0=0
$$
不购买的相应概率:
$$
P(X=No) = \frac{7}{10} \
P(A=F|No) = \frac{4}{7} \
P(B=中|No) = \frac{3}{7} \
P(C=离异|NO) = \frac{1}{6} \
P(X=No|A=F,B=中,C=离异) = \Delta \cdot \frac{7}{10} \cdot\frac{4}{7} \frac{3}{7} \cdot \frac{1}{6}=\frac{1}{35}\Delta
$$
于是预测这个用户不会购买次产品。
朴素贝叶斯分类器
朴素贝叶斯的基本思想是:对于给定的待分类项,求出在此项出现的条件下各个类别出现的概率,哪个最大,就认为此待分类项属于哪个类别。
- 基本假设
朴素贝叶斯分类器有一个假设:给定类标号$y_k$,各属性之间条件独立。条件独立假设表述如下:
$$
P(X|Y=y_k) = \Pi_{i+1} ^{m} P(x_i|Y=y_k)
$$
其中,每个属性集$X={x1,x2,⋯,x_m}$包含m个属性。
- 计算流程
- 对于待分类项$C={y_1, y_2, \cdots, y_n }$ ,属性集合$X={x1,x2,⋯,x_m}$
- 分别计算条件概率$P(y_k|X)$ 其中 $k=1,2, \cdots, n$
- $P(y_k |X) = args(k) \max { P(y_1|X), P(y_2|X), \cdots, P(y_n|X)} $ , 则 $X \in y_k$
-
计算属于各个类的概率
$$
P(y_k|X) = \frac{P(X|y_k) \cdot P(y_k)}{P(X)} = \frac{1}{P(X)} \cdot P(y_k) \cdot \Pi_{i=1} ^m P(x_i|y_k)
$$
对于所有的类别$Y$,$P(X)$是固定的,一般直接忽略,只需要比较分子。当特征属性为离散值时,可以通过统计训练样本中各个划分在每个类别中出现的频率来估计;
当特征属性为连续属性时,可以假设连续变量服从某种概率分布,然后使用训练数据估计分布的参数。高斯分布(也称正态分布)常被用来表示连续属性的类条件概率分布。该分布有两个参数,均值$\mu$和方差$\sigma^2$。对每个类,属性$x_i$的类条件概率等于:
$$
P(x_i|y_k) = \frac{1}{\sqrt{2\pi}\sigma_{ik}} \exp\left[-\frac{(x_i - \mu_{ik})2}{2\sigma2_{ik}} \right]
$$
参数$\mu_{ik}$可以用类$y_k$的所有训练记录关于$x_i$的样本均值$\overline x$来估计,参数$\sigma2_{ik}$可以用这些训练记录的样本方差$s2$来估计。
朴素贝叶斯分类完整案例
-
数据介绍
本文使用的测试问题是“皮马印第安人糖尿病问题”。这个问题包括768个对于皮马印第安患者的医疗观测细节,记录所描述的瞬时测量取自诸如患者的年纪,怀孕和血液检查的次数。所有患者都是21岁以上(含21岁)的女性,所有属性都是数值型,而且属性的单位各不相同。每一个记录归属于一个类,这个类指明以测量时间为止,患者是否是在5年之内感染的糖尿病。如果是,则为1,否则为0。
6,148,72,35,0,33.6,0.627,50,1 1,85,66,29,0,26.6,0.351,31,0 8,183,64,0,0,23.3,0.672,32,1 1,89,66,23,94,28.1,0.167,21,0 0,137,40,35,168,43.1,2.288,33,1
字段说明:
1. Number of times pregnant 2. Plasma glucose concentration a 2 hours in an oral glucose tolerance test 3. Diastolic blood pressure (mm Hg) 4. Triceps skin fold thickness (mm) 5. 2-Hour serum insulin (mu U/ml) 6. Body mass index (weight in kg/(height in m)^2) 7. Diabetes pedigree function 8. Age (years) 9. Class variable (0 or 1)
教程分为如下几步
1.处理数据:从CSV文件中载入数据,然后划分为训练集和测试集。
2.提取数据特征:提取训练数据集的属性特征,以便我们计算概率并做出预测。
3.单一预测:使用数据集的特征生成单个预测。
4.多重预测:基于给定测试数据集和一个已提取特征的训练数据集生成预测。
5.评估精度:评估对于测试数据集的预测精度作为预测正确率。
6.合并代码:**使用所有代码呈现一个完整的、独立的朴素贝叶斯算法的实现。
- 代码最终实现
# Example of Naive Bayes implemented from Scratch in Python
# python 2.7
import csv
import random
import math
def loadCsv(filename):
lines = csv.reader(open(filename, "rb"))
dataset = list(lines)
for i in range(len(dataset)):
dataset[i] = [float(x) for x in dataset[i]]
return dataset
def splitDataset(dataset, splitRatio):
trainSize = int(len(dataset) * splitRatio)
trainSet = []
copy = list(dataset)
while len(trainSet) < trainSize:
index = random.randrange(len(copy))
trainSet.append(copy.pop(index))
return [trainSet, copy]
def separateByClass(dataset):
separated = {}
for i in range(len(dataset)):
vector = dataset[i]
if (vector[-1] not in separated):
separated[vector[-1]] = []
separated[vector[-1]].append(vector)
return separated
def mean(numbers):
return sum(numbers) / float(len(numbers))
def stdev(numbers):
avg = mean(numbers)
variance = sum([pow(x - avg, 2) for x in numbers]) / float(len(numbers) - 1)
return math.sqrt(variance)
def summarize(dataset):
summaries = [(mean(attribute), stdev(attribute)) for attribute in zip(*dataset)]
del summaries[-1]
return summaries
def summarizeByClass(dataset):
separated = separateByClass(dataset)
summaries = {}
for classValue, instances in separated.iteritems():
summaries[classValue] = summarize(instances)
return summaries
def calculateProbability(x, mean, stdev):
exponent = math.exp(-(math.pow(x - mean, 2) / (2 * math.pow(stdev, 2))))
return (1 / (math.sqrt(2 * math.pi) * stdev)) * exponent
def calculateClassProbabilities(summaries, inputVector):
probabilities = {}
for classValue, classSummaries in summaries.iteritems():
probabilities[classValue] = 1
for i in range(len(classSummaries)):
mean, stdev = classSummaries[i]
x = inputVector[i]
probabilities[classValue] *= calculateProbability(x, mean, stdev)
return probabilities
def predict(summaries, inputVector):
probabilities = calculateClassProbabilities(summaries, inputVector)
bestLabel, bestProb = None, -1
for classValue, probability in probabilities.iteritems():
if bestLabel is None or probability > bestProb:
bestProb = probability
bestLabel = classValue
return bestLabel
def getPredictions(summaries, testSet):
predictions = []
for i in range(len(testSet)):
result = predict(summaries, testSet[i])
predictions.append(result)
return predictions
def getAccuracy(testSet, predictions):
correct = 0
for i in range(len(testSet)):
if testSet[i][-1] == predictions[i]:
correct += 1
return (correct / float(len(testSet))) * 100.0
def main():
filename = 'pima-indians-diabetes.data.csv'
splitRatio = 0.67
dataset = loadCsv(filename)
trainingSet, testSet = splitDataset(dataset, splitRatio)
print('Split {0} rows into train={1} and test={2} rows').format(len(dataset), len(trainingSet), len(testSet))
# prepare model
summaries = summarizeByClass(trainingSet)
# test model
predictions = getPredictions(summaries, testSet)
accuracy = getAccuracy(testSet, predictions)
print('Accuracy: {0}%').format(accuracy)
main()
>>> Split 768 rows into train=514 and test=254 rows
Accuracy: 76.3779527559%
机器学习代码实现
# python 3.5 or later
from sklearn.naive_bayes import GaussianNB
import csv
import numpy as np
def read_csv(filename: str) -> np.ndarray:
"""
read csv
:return: array
"""
data = []
lines = csv.reader(open(filename, "r"))
for line in lines:
data.append(list(map(float, line)))
return np.array(data)
def generate_sample(data: np.ndarray) -> (np.ndarray, np.ndarray):
"""
构造训练集和验证集
:param data: 样本数据
:return : (训练集,测试集)
"""
ratio = 0.67
index = round(data.shape[0] * ratio)
return data[:index], data[index:]
def main():
data_csv = "pima-indians-diabetes.data.csv"
sample = read_csv(data_csv)
sample_, test_ = generate_sample(sample)
print("训练数据%s条,测试数据%s条" % (sample_.shape[0], test_.shape[0]))
gnb = GaussianNB()
gnb.fit(sample_[:, :-1], sample_[:, -1])
print("score is: %.2f%%" % (gnb.score(test_[:, :-1], test_[:, -1]) * 100))
if __name__ == '__main__':
main()
>>> 训练数据515条,测试数据253条
score is: 77.08%
参考文档
[1]: 机器学习之用Python从零实现贝叶斯分类器 http://python.jobbole.com/81019/
[2]: 贝叶斯分类器 http://funhacks.net/2015/05/18/Bayesian-classifier/