首页 > 编程语言 > 详细

手写朴素贝叶斯(naive_bayes)分类算法

时间:2019-10-03 10:25:43      阅读:77      评论:0      收藏:0      [点我收藏+]

朴素贝叶斯假设各属性间相互独立,直接从已有样本中计算各种概率,以贝叶斯方程推导出预测样本的分类。

为了处理预测时样本的(类别,属性值)对未在训练样本出现,从而导致概率为0的情况,使用拉普拉斯修正(假设属性值与类别均匀分布)。

代码及注释如下:

一、离散值

1,朴素贝叶斯算法计算相关参数并返回,预测使用这些参数即可

# 手写拉普拉斯修正的朴素贝叶斯
import numpy as np
import pandas as pd
def naive_bayes(data):
    ‘‘‘data:pandas.DataFrame‘‘‘
#     列名
    attrs=data.columns
#     类别
    labels=data[attrs[-1]].unique()
#     类别数
    N=labels.size
#     样本总数
    D=data.index.size
#     c类样本概率
    pc=np.empty(shape=(N,1))
#     c类中,第i个属性取值为xi的概率,这里计算了所有,而非只针对测试样本,保存后predict时直接从里面取值即可
    p_xc=[]
#     包含每个属性的可取值
    features=[data[i].unique() for i in attrs[:-1]]
    for i in range(N):
        df=data[data[attrs[-1]]==labels[i]]
        Dc=df[attrs[0]].count()
        pc[i]=np.array([(Dc+1)/(D+N)])
        p_c=[]
        for j in range(len(features)):
            values=features[j]
            Ni=values.size
            c_attr=[]
            for value in values:
                Dc_xi=df[df[attrs[j]]==value].index.size
                c_attr.append((Dc_xi+1)/(Dc+Ni))
            p_c.append(c_attr)
        p_xc.append(p_c)
    return p_xc,pc,N,features,labels
# 预测一个样本
def predict(x,p_xc,pc,num_class,features,labels):
    result=[]
    for i in range(num_class):
        res=1.
        c=p_xc[i]
        for j in range(len(c)):
            feature_j=c[j]
            for k in range(len(feature_j)):
                if x[j]==features[j][k]:
                    res*=feature_j[k]
        result.append(pc[i][0]*res)
    max_c=0
    max_index=-1
    for i in range(len(result)):
        if result[i]>max_c:
            max_c=result[i]
            max_index=i
    return result,labels[max_index]
# 预测多个样本
def predicts(x,p_xc,pc,num_class,features,labels):
    result=[]
    for data in x:
        _,clazz=predict(data,p_xc,pc,num_class,features,labels)
        result.append(clazz)
    return result

2,使用西瓜集2.0训练及测试

def createDataSet():

    dataSet = [
        # 1
        [青绿, 蜷缩, 浊响, 清晰, 凹陷, 硬滑, 好瓜],
        # 2
        [乌黑, 蜷缩, 沉闷, 清晰, 凹陷, 硬滑, 好瓜],
        # 3
        [乌黑, 蜷缩, 浊响, 清晰, 凹陷, 硬滑, 好瓜],
        # 4
        [青绿, 蜷缩, 沉闷, 清晰, 凹陷, 硬滑, 好瓜],
        # 5
        [浅白, 蜷缩, 浊响, 清晰, 凹陷, 硬滑, 好瓜],
        # 6
        [青绿, 稍蜷, 浊响, 清晰, 稍凹, 软粘, 好瓜],
        # 7
        [乌黑, 稍蜷, 浊响, 稍糊, 稍凹, 软粘, 好瓜],
        # 8
        [乌黑, 稍蜷, 浊响, 清晰, 稍凹, 硬滑, 好瓜],

        # ----------------------------------------------------
        # 9
        [乌黑, 稍蜷, 沉闷, 稍糊, 稍凹, 硬滑, 坏瓜],
        # 10
        [青绿, 硬挺, 清脆, 清晰, 平坦, 软粘, 坏瓜],
        # 11
        [浅白, 硬挺, 清脆, 模糊, 平坦, 硬滑, 坏瓜],
        # 12
        [浅白, 蜷缩, 浊响, 模糊, 平坦, 软粘, 坏瓜],
        # 13
        [青绿, 稍蜷, 浊响, 稍糊, 凹陷, 硬滑, 坏瓜],
        # 14
        [浅白, 稍蜷, 沉闷, 稍糊, 凹陷, 硬滑, 坏瓜],
        # 15
        [乌黑, 稍蜷, 浊响, 清晰, 稍凹, 软粘, 坏瓜],
        # 16
        [浅白, 蜷缩, 浊响, 模糊, 平坦, 硬滑, 坏瓜],
        # 17
        [青绿, 蜷缩, 沉闷, 稍糊, 稍凹, 硬滑, 坏瓜]
    ]
    

    # 特征值列表
    labels = [色泽, 根蒂, 敲击, 纹理, 脐部, 触感,好坏]
    dataset=pd.DataFrame(data=dataSet,columns=labels)
    return dataset

3,训练及预测

这里预测使用训练数据,可以看到精度却不咋样,个人认为这跟样本太小、使用了修正(修正在大样本下的影响较小)及属性并非相互独立有关

dataset=createDataSet()
p_xc,pc,num_class,features,labels=naive_bayes(dataset)

value=dataset[dataset.columns[:-1]].values
result=predicts(value,p_xc,pc,num_class,features,labels)
real=dataset[dataset.columns[-1]].values
df=pd.DataFrame([[result[i]==real[i] for i in range(len(result))]])
# 精度 0.8235294117647058
df.iloc[0].sum()/df.iloc[0].count()

二、连续值

1,贝叶斯方法

def normal_distribution(mean,var,x):
    return np.power(np.e,-(x-mean)*(x-mean)/(2*var))/np.sqrt(2*np.pi*var)
# 连续值处理,假设数据服从正态分布,如上函数所示
def naive_bayes_2(X_train,y_train):
    ‘‘‘data:pandas.DataFrame‘‘‘
    labels=list(set(y_train))
#     类别数
    num_class=len(labels)
    data=pd.DataFrame(X_train,columns=[l1,l2,l3,l4])
    data[label]=y_train
    N=len(y_train)
#     均值和方差
    means=[]
    vals=[]
    #     c类样本概率
    pc=np.empty(shape=(num_class,1))
#     对每一类求均值和方差
    for i in range(num_class):
        df=data[data[label]==labels[i]]
        l=df.index.size
        pc[i]=l/N
        mean=[]
        val=[]
#         各属性的均值和方差
        for col in df.columns[:-1]:
            mean.append(df[col].mean())
            val.append(df[col].var())
        means.append(mean)
        vals.append(val)
    
    return means,vals,pc,labels
# 预测多个样本
def predict_2(x_test,means,vals,pc,labels):
    num_class=len(labels)
    results=[]
    for x in x_test:
        result=[]
        for i in range(num_class):
            res=1.
            res*=pc[i][0]
            j=0
            for mean,val in zip(means[i],vals[i]):
                res*=normal_distribution(mean,val,x[j])
                j+=1
            result.append(res)
        results.append(labels[result.index(max(result))])
    return results

2,使用sklearn中iris数据集

from sklearn.datasets import load_iris
data = load_iris()

x=data[data]
y=data[target]
cols=data[target_names]

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test=train_test_split(x,y,test_size=0.2,random_state=10)

3,训练及测试

means,vals,pc,labels=naive_bayes_2(X_train,y_train)

results=predict_2(X_test,means,vals,pc,labels)

from sklearn.metrics import accuracy_score
# 精度100%
accuracy_score(results,y_test)

三、总结

例举了2个例子,离散值的样本少,使用了修正,精度不咋样,连续值的精度100%,取得不错的效果,也说明各个类别下的各个特征基本符合正态分布。

手写朴素贝叶斯(naive_bayes)分类算法

原文:https://www.cnblogs.com/lunge-blog/p/11618970.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!