朴素贝叶斯算法
贝叶斯原理作为数学基础,解决了概率论中“逆向概率”的问题,基于这一理论基础设计出了贝叶斯分类器,而朴素贝叶斯分类假设属性是相互独立的前提条件下所设计的贝叶斯分类器中的一种。
朴素贝叶斯的算法思路
朴素贝叶斯算法大致分为:
-
数据处理阶段:抽取特征属性,对数据进行分类标注,形成数据集,分类器的质量很大程度上由特征属性、特征属性划分及训练样本质量决定。
-
训练:计算每个类别在训练样本中的出现频率及每个特征属性划分对每个类别的条件概率,输入是特征属性和训练样本,输出是分类器。
-
测试:对模型进行测试。
朴素贝叶斯的优缺点
朴素贝叶斯的主要优点有:
- 朴素贝叶斯模型有稳定的分类效率。
- 对小规模的数据表现很好,能处理多分类任务,适合增量式训练。
- 对缺失数据不太敏感。
朴素贝叶斯的主要缺点有:
- 理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率,在属性个数比较多或者属性之间相关性较大时,分类效果不好。在属性相关性较小时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
- 需要先验概率,但先验概率很多时候取决于假设。
- 分类决策存在一定的错误率。
- 对输入数据的表达形式敏感。
朴素贝叶斯算法处理wine的实现
#需要的头文件
import math
import time
import numpy as np
from collections import Counter
from sklearn import preprocessing
from sklearn.model_selection import train_test_split
#计算属于各类的概率
def calcProbDensity(meanLabel, stdLabel, test_X):
numAttributes = len(test_X)
MultiProbDensity = 1.0
#print ("this is calcPD")
# print meanLabel
# print stdLabel
for i in range(numAttributes):
MultiProbDensity *= np.exp(-np.square(test_X[i] - meanLabel[i]) / (2.0 * np.square(stdLabel[i]))) / (np.sqrt(2.0 * math.pi) * stdLabel[i])
#print (MultiProbDensity)
return MultiProbDensity
# 计算先验概率P(c)
def calcPriorProb(Y_train):
i, j = 0, 0
global labelValue, classNum
numSamples = Y_train.shape[0] # 读取Y_train的第一维度的长度,比如多少行。
labelValue = np.zeros((numSamples, 1)) # 用前i行来保存标签值
# print "laV:",labelValue
Y_train_counter = sum(Y_train.tolist(), []) # 将Y_train转化为可哈希的数据结构
cnt = Counter(Y_train_counter) # 计算标签值的类别个数{1,2,3}及各类样例的个数
# print "cnt",cnt
for key in cnt:
labelValue[i] = key
i += 1
classNum = i
# print "laV2:",labelValue
# print classNum
Pc = np.zeros((classNum, 1)) # 不同类的先验概率
eachLabelNum = np.zeros((classNum, 1)) # 每类样例数,多少行多少列,这里是classNum行1列
for key in cnt:
Pc[j] = float(cnt[key]) / numSamples #这里加float是为了避免/整除号使Pc=0
eachLabelNum[j] = cnt[key]
j += 1
return labelValue, eachLabelNum, classNum, Pc
def trainBayes(X_train, Y_train):
startTime = time.time()
numTrainSamples, numAttributes = X_train.shape
print ("trainBayes")
# print numAttributes,numTrainSamples
labelValue, eachLabelNum, classNum, Pc = calcPriorProb(Y_train)
meanlabelX, stdlabelX = [], [] # 存放每一类样本在所有属性上取值的均值和方差
for i in range(classNum):
k = 0
labelXMaxtrix = np.zeros((int(eachLabelNum[i]), numAttributes))
for j in range(numTrainSamples):
if Y_train[j] == labelValue[i]:
labelXMaxtrix[k] = X_train[j, :]
k += 1
meanlabelX.append(np.mean(labelXMaxtrix, axis=0).tolist()) # 求该矩阵的列均值与无偏标准差,append至所有类
stdlabelX.append(np.std(labelXMaxtrix, ddof=1, axis=0).tolist())
meanlabelX = np.array(meanlabelX).reshape(classNum, numAttributes)
stdlabelX = np.array(stdlabelX).reshape(classNum, numAttributes)
print('---Train completed.Took %f s.' % ((time.time() - startTime)))
return meanlabelX, stdlabelX, Pc
def predict(X_test, Y_test, meanlabelX, stdlabelX, Pc):
numTestSamples = X_test.shape[0]
matchCount = 0
for m in range(X_test.shape[0]):
x_test = X_test[m, :] # 轮流取测试样本
pred = np.zeros((classNum, 1)) # 对不同类的概率
print ("Pc:", Pc)
for i in range(classNum):
pred[i] = calcProbDensity(meanlabelX[i, :], stdlabelX[i, :], x_test) * Pc[i] # 计算属于各类的概率
# print i
print (pred)
predict1 = labelValue[np.argmax(pred)] # 取最大的类标签,np.argmax(pred)返回最大数据所在的index
print (predict1, "####", Y_test[m])
if predict1 == Y_test[m]:
matchCount += 1
print ("matchCount", matchCount, numTestSamples)
accuracy = float(matchCount) / numTestSamples #这里加float是为了避免/整除号使accuracy=0
# print accuracy
return accuracy
if __name__ == '__main__':
#载入葡萄酒数据集
print('Step 1.下载数据')
data = np.loadtxt("wine.dat",delimiter=',')
print("Step 2.拆分数据集(训练和测试)")
x = data[:,0:13]
y = data[:,13].reshape(178,1)
#包含数据标准化
X_train,X_test,Y_train,Y_test = train_test_split(x,y,test_size=0.4) #拆分数据集
scaler = preprocessing.StandardScaler().fit(X_train) #数据标准化
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
#训练
print("Step 3.训练")
meanlabelX,stdlabelX,Pc = trainBayes(X_train,Y_train)
#测试
print("Step 4.测试")
accuracy = predict(X_test,Y_test,meanlabelX,stdlabelX,Pc)
#打印分类的准确度
print("Step 5.打印分类的准确度")
print(str(accuracy*100)+"%")