不同的朴素贝叶斯算法,主要是对P(xi|y)的分布假设不同,进而采用不同的参数估计方式。我们能够发现,朴素贝叶斯算法,主要就是计算P(xi|y),一旦P(xi|y)确定,最终属于每个类别的概率,自然也就迎刃而解了。
一般来说,如果样本特征的分布大部分是连续值,适用GaussianNB会比较好。如果样本特征的分布大部分是多元离散值,使用MultinomialNB比较合适。而如果样本特征是二元离散值或者很稀疏的多元离散值,应该使用BernoulliNB。
1,理论上,朴素贝叶斯模型与其他分类方法相比具有最小的误差率。但是实际上并非总是如此,这是因为朴素贝叶斯模型给定输出类别的情况下,假设属性之间相互独立,这个假设在实际应用中往往是不成立的,在属性个数比较多或者属性之间相关性较大时,分类效果不好。而在属性相关性较小的时,朴素贝叶斯性能最为良好。对于这一点,有半朴素贝叶斯之类的算法通过考虑部分关联性适度改进。
import pandas as pd
from sklearn.naive_bayes import BernoulliNB
trainfile = '../data/mnist_train.csv'
testfile = '../data/mnist_test.csv'
# 第0列是手写体数字,从第1列到第784列是28*28的像素,每个特征代表一个像素值
df_train = pd.read_csv(trainfile, header=None)
df_test = pd.read_csv(testfile, header=None)
# 伯努利算法模型要求每个特征只有2种值类型,这个案例中就是要把像素值这个特征转换为0和1来满足该算法模型要求
def transform(x):
if x<255/2:
return 0
else:
return 1
# 把像素特征二值化,所有的行都需要操作,所有的列操作第1列到最后一列,即为[:,1:],逗号前操作行,逗号后操作列
df_train.iloc[:,1:] = df_train.iloc[:,1:].applymap(transform)
df_test.iloc[:,1:] = df_test.iloc[:,1:].applymap(transform)
train_y = df_train.iloc[:,0] # 选中所有行中的第0列,该列含义是手写体的数值0-9,数字就这10类
train_x = df_train.iloc[:,1:] # 所有行的像素特征
model = BernoulliNB()
# 每一个手写体对应的像素数据 train_x -> 手写体数值 train_y,拟合数据
model.fit(train_x, train_y)
sample_0 = df_test.iloc[0,1:].values.reshape(1,-1) # 取一个测试样本
model.predict(sample_0) # 预测它
df_test.iloc[0][0] # 查看该测试样本真实值
# 计算在全部测试样本下的准确率
model.score(df_test.iloc[:,1:].values, df_test.iloc[:,0])
import pandas as pd
import numpy as np
trainfile = '../data/mnist_train.csv'
testfile = '../data/mnist_test.csv'
df_train = pd.read_csv(trainfile,header=None)
df_test = pd.read_csv(testfile,header=None)
def transform(x):
if x<255/2:
return 0
else:
return 1
df_train.iloc[:,1:] = df_train.iloc[:,1:].applymap(transform)
df_test.iloc[:,1:] = df_test.iloc[:,1:].applymap(transform)
train_y = df_train.iloc[:,0]
train_x = df_train.iloc[:,1:]
P_class = train_y.value_counts(sort=False)/len(train_y)
f_sum = train_x[train_y==0].apply(np.sum,axis=0)
c_num = train_y.value_counts(sort=False)
c_0 = c_num[0]
k,N = 1,2
P_fi_c0 = (f_sum +k)/(c_0+k*N)
P_fi_c0[:5]
def train(X, Y, k=1,N=2,C=10):
# 参数说明:
# X:样本特征,pandas.DataFrame类型
# Y: 样本标签,pandas.Series类型
# k,N : 拉普拉斯平滑参数
# C: 类别数
#用numpy.array计算,
#都返回array类型
'''
P_class = np.array(Y.value_counts(sort=False)) #shape:(C,)
I_fc = np.array([X[Y==i].apply(np.sum,axis=0).tolist() for i in range(10)]) + k #shape:(10,784)
I_c = P_class + N*k
E = I_fc/I_c[:,None]
#用pandas中DataFrame,Series计算,
#返回:P_class(Series),E(DataFrame)
'''
P_class = Y.value_counts(sort=False)
I_fc = pd.DataFrame([X[Y==i].apply(np.sum,axis=0).tolist() for i in range(C)]) + k
I_c = P_class + N*k
E = I_fc.div(I_c,axis=0).values #结果为 np.array 类型
return P_class,E
P_class,E = train(train_x,train_y)
pd.DataFrame(E)
sample_x = df_test.iloc[0,1:].values.reshape(1,-1) #取一个测试样本
sample_y = df_test.iloc[0,0] #样本标签
P_class,E = train(train_x,train_y)
bz1 = np.subtract(sample_x,1)
bz2 = np.abs(bz1)
bz3 = np.subtract(bz2,E)
bz4 = np.abs(bz3)
log_p_fi_c0 = np.log(bz4) #取对数
log_p_c0 = np.log(P_class)
P_c0_X = log_p_c0 + np.sum(log_p_fi_c0,axis=1)
def predict(X,P_class,E):
bz1 = np.subtract(X,1)
bz2 = np.abs(bz1)
bz3 = np.subtract(bz2,E)
bz4 = np.abs(bz3)
log_p_fi_cj = np.log(bz4)
log_p_cj = np.log(P_class.values)
P_cj_X = np.add(log_p_cj, np.sum(log_p_fi_cj,axis=1))
return np.argmax(P_cj_X)
max_class = predict(sample_x,P_class,E)
pre_list = []
for i in range(df_test.shape[0]):
sample_x = df_test.iloc[i,1:].values.reshape(1,-1)
pre_list.append(predict(sample_x,P_class,E))
y = df_test.iloc[:,0]
acc = len(y[y==pd.Series(pre_list)])/len(y)