0#02离散型朴素贝叶斯

0x00 数据集合

气球测试集1.0

黄色,小,成人,用手打,不爆炸
黄色,小,成人,用脚踩,爆炸
黄色,小,小孩,用手打,不爆炸
黄色,小,小孩,用脚踩,不爆炸
黄色,大,成人,用手打,爆炸
黄色,大,成人,用脚踩,爆炸
黄色,大,小孩,用手打,不爆炸
黄色,大,小孩,用脚踩,爆炸
紫色,小,成人,用手打,不爆炸
紫色,小,小孩,用手打,不爆炸
紫色,大,成人,用脚踩,爆炸
紫色,大,小孩,用脚踩,爆炸

数据来源https://github.com/carefree0910/MachineLearning/blob/master/_Data/balloon1.0.txt
蘑菇数据集
蘑菇数据集含义

0x01 笔算机器学习

看到是一些颜色、大小、测试人员、测试动作与结果(是否爆炸)的一些数据。
这个数据集比较特别,每个维度(向量)只有2个特征可取值。

1. 颜色==>黄色/紫色
2. 大小==>大/小
3. 测试人员==>成人/小孩
4. 测试动作==>用手打/用脚踩
5. 结果(标签)==>爆炸/不爆炸

离散朴素贝叶斯算法的过程:
[1]计算先验概率分布:(针对标签)
P(爆炸)=P(不爆炸)=0.5
[2]计算条件概率分布:(针对向量)
也就是我们所说的训练
on_counter

    不爆炸            爆炸
  紫色  黄色       紫色  黄色
[[1/3,     2/3],[1/3,    2/3]]),
   小    大
[5/6,      1/6],[1/6,    5/6]]),
  小孩   成人
[2/3,      1/3],[1/3     2/3]]),
    手   脚
[5/6,      1/6],[1/6,    5/6]])]

[3]预测,利用MAP估计进行评估
有了条件概率分布,我们就可以开始预测了
比如第一条数据
黄色,小,成人,用手打
我们分别计算爆炸和不爆炸的情况
爆炸的评估:
P(爆炸的评估)=P(黄色|爆炸)P(小|爆炸)P(成人|爆炸)P(用手打|爆炸)P(爆炸)
=2/3
1/62/31/61/2=0.006172839506172839
P(不爆炸的评估)=P(黄色|不爆炸)
P(小|不爆炸)P(成人|不爆炸)P(用手打|不爆炸)P(不爆炸)=2/35/61/35/61/2=0.07716049382716048
评估得到:
P(爆炸的评估)<P(不爆炸的评估)
所以评估为不爆炸,和第一个标签一致。
但是有个怪坑,0*任何数=0。
如果我们数据量过小,比如
多了一个数据:

黑色,大,成人,用脚踩,爆炸

那么P(黑色|不爆炸)=0
导致带有黑色的数据的评估
P(不爆炸的评估)=0(恒等于)
导致带有黑色的数据永远是爆炸的。
为了避免这种怪坑,于是引入了平滑项。

平滑项

我们把数据重新修改一下为

黄色,小,成人,用手打,不爆炸
黄色,小,成人,用脚踩,爆炸
黄色,小,小孩,用手打,不爆炸
黄色,小,小孩,用脚踩,不爆炸
黄色,大,成人,用手打,爆炸
黑色,大,成人,用脚踩,爆炸
黄色,大,小孩,用手打,不爆炸
黄色,大,小孩,用脚踩,爆炸
紫色,小,成人,用手打,不爆炸
紫色,小,小孩,用手打,不爆炸
紫色,大,成人,用脚踩,爆炸
紫色,大,小孩,用脚踩,爆炸

这时候,颜色有K=3个特征值可以取,我们引入一个变量(lb)平滑系数
举个例子:
P(黄色|不爆炸)=(不爆炸并且为黄色个素+lb)/(不爆炸总个数+lbK)
=(4+lb)/(6+lb
K)
明显的:
当lb=0时,就是我们上面的结果(极大似然估计),
当lb=1时,我们称之为拉普拉斯平滑

0x02 python 伪代码

按照上面的想法把步骤写一下:
TODO:[1]计算先验概率分布:(针对标签)
TODO:[2]计算条件概率分布:(针对向量)
TODO:[3]预测,利用MAP估计进行评估
我们利用一下python的面向对象的方法。

[0] 数据准备

计算机和人不一样,对文字的理解没有人强,却有极强的数字的运算速度。
所以我们第[0]步,进行数据的准备,把各个向量进行整理,按照可能取到的特征值包装为字典,然后用字典,对文字进行映射。
TODO:[0]数据准备
[0.1] 将输入特征(x)和标签(y)分离
输入特征(x):

['黄色', '小', '成人', '用手打'],
['黄色', '小', '成人', '用脚踩'],
['黄色', '小', '小孩', '用手打'],
['黄色', '小', '小孩', '用脚踩'],
['黄色', '大', '成人', '用手打'],
['黄色', '大', '成人', '用脚踩'],
['黄色', '大', '小孩', '用手打'],
['黄色', '大', '小孩', '用脚踩'],
['紫色', '小', '成人', '用手打'],
['紫色', '小', '小孩', '用手打'],
['紫色', '大', '成人', '用脚踩'],
['紫色', '大', '小孩', '用脚踩']]

标签(y):

['不爆炸', '爆炸', '不爆炸', '不爆炸', '爆炸', '爆炸', '不爆炸', '爆炸', '不爆炸', '不爆炸',
'爆炸', '爆炸']

[0.2] 对每个维度生成字典
输入特征(x)的字典:
feat_dic

{'紫色': 0, '黄色': 1},
{'大': 1, '小': 0},
{'小孩': 0, '成人': 1},
{'用手打': 0, '用脚踩': 1}

标签(y)的字典:
label_dic

{'不爆炸': 0, '爆炸': 1}

[0.3] 为了平滑,我们需要计算K(每个向量的特征值个数)
n_possibilities:
颜色/大小/人员/动作
[2, 2, 2, 2]
[0.4] 按照特征值字典进行映射
(feat_dic)对文本的输入特征值进行映射
x=

[1, 0, 1, 0],
[1, 0, 1, 1],
[1, 0, 0, 0],
[1, 0, 0, 1],
[1, 1, 1, 0],
[1, 1, 1, 1],
[1, 1, 0, 0],
[1, 1, 0, 1],
[0, 0, 1, 0],
[0, 0, 0, 0],
[0, 1, 1, 1],
[0, 1, 0, 1]

label_dic对y进行映射
y

[0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1]

[1] 计算先验概率分布:(针对标签)

[1.0] 统计y中每个特征出现的频率
cat_counter

[6, 6]

[1.1] 计算先验概率分布
p_category
[0.5, 0.5]

[2]计算条件概率分布:(针对向量)

[2.1] 统计每个维度的特征值出现的次数

        不爆炸              爆炸
         紫色  黄色
颜色[[array([2, 4]), array([2, 4])],
           小  大
大小 [array([5, 1]), array([1, 5])],
         小孩   成人
人员 [array([4, 2]), array([2, 4])],
            手  脚
动作 [array([5, 1]), array([1, 5])]]

[2.2] 利用平滑对数据进行平滑
假设 lb=1 ,拉普拉斯平滑
和n_possibilities [2, 2, 2, 2]
得到data

         不爆炸              爆炸
        紫色  黄色           
[array([[0.375, 0.625],[0.375, 0.625]]),
         小    大
array([[0.75, 0.25],[0.25, 0.75]]),
         小孩   成人
array([[0.625, 0.375],[0.375, 0.625]]),
         手     脚
array([[0.75, 0.25],[0.25, 0.75]])]

到这里训练就已经完成了

[3]预测,利用MAP估计进行评估

到这一步,我们就要开始考虑我们看重哪些数据,或者说如果把训练完后,过了今天要再次预测。我们保存哪些数据可以避免重复训练?
假设我们要训练的样本为

黄色,小,成人,用手打

他的标签为

不爆炸

[3.1] 利用我们之前得到的 feat_dic 对输入特征值进行向量化
feat_dic

{'紫色': 0, '黄色': 1},
{'大': 1, '小': 0},
{'小孩': 0, '成人': 1},
{'用手打': 0, '用脚踩': 1}

得到

[1, 0, 1, 0],

[3.2] 利用data中的数据,和p_categor中的数据
计算
P(0的评估)=0.6250.750.3750.750.5=0.06591796875
P(1的评估)=0.6250.250.6250.250.5=0.01220703125
得到结果为0。
利用一下 label_dic 反字典,得到0表示的是不爆炸。

{'不爆炸': 0, '爆炸': 1}

伪代码就写完了。
可以看出重要的数据都已经列在上面了。接下来是算法的问题。
对于数据,如果有 data(所有的条件概率)、feat_dic (特征值的字典)、和 label_dic(标签的字典) 的反字典就能对数据进行预测。

0X03 python 的面向对象

对于__init__ ,我们希望他有我们上面的这些元素

初始化

class MultinomialNB(NaiveBayes):
    def __init__(self):
        # 数值化后的输入向量
        self._x = None
        # 数值化后的标签
        self._y = None
        # 训练结果,条件概率分布
        self._data = None
        # 决策函数
        self._func = None
        # 每个向量的取值情况
        self._n_possibilities = None
        # 按标签分类后的x
        self._labelled_x = None
        # 将x,y进行捆绑
        self._label_zip = None
        # 标签的统计
        self._cat_counter = None
        # 特征值的统计
        self._con_counter = None
        # 标签的字典
        self.label_dic = None
        # 特征值的字典
        self._feat_dics = None

然后依次完成以下的任务
TODO:[0]数据准备
TODO:[1]计算先验概率分布:(针对标签)
TODO:[2]计算条件概率分布:(针对向量)
TODO:[3]预测,利用MAP估计进行评估

[0]数据准备

[0.0]数据导入并且[0.1]将输入特征(x)和标签(y)分离

对于数据准备,这个部分很多地方会用到,可以单独扔出来作为一个工具类(Util),也可以当作上面这句话没看见。

import logging
logging.basicConfig(level=logging.DEBUG)
class DataUtil:
    /*
     * path:文件路径(可以用相对路径)
     * train_num:是否设置训练集,训练集的数量
     * tar_idx:标签的列号,默认是最后一列
     * shuffle:是否对数据集进行洗牌,对于贝叶斯算法,在没有区分训练集的情况下,
     *         洗牌只是让最初的数据变得混乱,对最后的结果没有影响
     *         这里为了能得到和我们前面的手算结果一致我们就不洗牌了
     */
    def get_dataset(path, train_num=None, tar_idx=None, shuffle=False):
        x = []
        with open(path, "r", encoding="utf-8") as f:
            for sample in f:
                x.append(sample.strip().split(","))
        if shuffle:
            np.random.shuffle(x)
        # python中的三元运算
        tar_idx = -1 if tar_idx is None else tar_idx
        y = np.array([xx.pop(tar_idx) for xx in x])
        x = np.array(x)
        logging.debug("get_dataset-x")
        logging.debug(x)
        logging.debug("get_dataset-y")
        logging.debug(y)

        if train_num is None:
            return x, y
        return (x[:train_num], y[:train_num]), (x[train_num:], y[train_num:])

预处理数据

重新回到我们的 class MultinomialNB(NaiveBayes)
接下来我们要完成:
[0.2] 对每个维度生成字典
[0.3] 为了平滑,我们需要计算K(每个向量的特征值个数)
[0.4] 按照特征值字典进行映射
这些任务

class MultinomialNB(NaiveBayes):
    def feed_data(self, x, y, sample_weight=None):
        # 进行转置
        if isinstance(x, list):
            features = map(list, zip(*x))
        else:
            features = x.T
        # 利用集合获取各个维度的特征值
        # TODO:[0.2] 对每个维度生成字典
        features = [set(feat) for feat in features]
        feat_dict = [{_l: i for i, _l in enumerate(feats)} for feats in features]
        label_dic = {_l: i for i, _l in enumerate(set(y))}
        [0.4] 按照特征值字典进行映射
        x = np.array([[feat_dict[i][_l] for i, _l in enumerate(sample)] for sample in x])
        y = np.array([label_dic[yy] for yy in y])
        [1.0] 统计y中每个特征出现的频率
        cat_counter = np.bincount(y)
        [0.3] 为了平滑,我们需要计算K(每个向量的特征值个数)
        n_possibilities = [len(feads) for feads in features]
        # 获取各类别数据的下标
        labels = [y == value for value in range(len(cat_counter))]
        # 利用下标获取记录按类别分开后的输入数据的数组
        labelled_x = [x[ci].T for ci in labels]

        self._x = x
        logging.debug("self._x")
        logging.debug(x)

        self._y = y
        logging.debug("self._y")
        logging.debug(y)

        self._labelled_x = labelled_x
        logging.debug("labelled_x")
        logging.debug(labelled_x)

        self._label_zip = list(zip(labels, labelled_x))
        logging.debug("_label_zip")
        logging.debug(self._label_zip)

        self._cat_counter = cat_counter
        logging.debug("cat_counter")
        logging.debug(cat_counter)

        self._feat_dics = feat_dict
        logging.debug("feat_dict")
        logging.debug(feat_dict)

        self._n_possibilities = n_possibilities
        logging.debug("n_possibilities")
        logging.debug(n_possibilities)
        #注意这里是反字典
        self.label_dic = {i: _l for _l, i in label_dic.items()}
        logging.debug("label_dic")
        logging.debug(self.label_dic)
 
        # 处理样本权重的函数,以更新记录概率的数组
        self.feed_sample_weight(sample_weight)
        logging.debug("feed_sample_weight _con_counter")
        logging.debug(self._con_counter)

任务完成了,还顺便把一些比如
[1.0] 统计y中每个特征出现的频率
完成了
留下了一个接口:
self.feed_sample_weight(sample_weight)
用来计算con_counter每个向量特征值的取值情况
也就是[2.1] 统计每个维度的特征值出现的次数
单独扔出来的是为了定制,对不同的权重可以有修改。

[1]计算先验概率分布:(针对标签)

我们的任务是
[1.1] 计算先验概率分布

[1.1] 计算先验概率

    # TODO:[1.1] 计算先验概率,lb就是平滑项
    # lb为1表示拉普拉斯平滑
    def get_prior_probability(self, lb=1):
        return [(_c_num + lb) / (len(self._y) + lb * len(self._cat_counter)) \
                for _c_num in self._cat_counter]

[2]计算条件概率分布:(针对向量)

也就是我们称为的训练
[2.1] 统计每个维度的特征值出现的次数,使用接口self.feed_sample_weight(sample_weight)
[2.2] 对数据进行平滑

[2.1] 统计每个维度的特征值出现的次数

    # TODO:[2.1] 统计每个维度的特征值出现的次数
    def feed_sample_weight(self, sample_weight=None):
        self._con_counter = []
        for dim, _p in enumerate(self._n_possibilities):
            if sample_weight is None:
                self._con_counter.append([np.bincount(xx[dim], minlength=_p) for xx in self._labelled_x])
            else:
                self._con_counter.append(
                    [np.bincount(xx[dim], weights=sample_weight[label] / sample_weight[label].mean(), minlength=_p) for
                     label, xx in self._label_zip])

[2.2] 对数据进行平滑

    def _fit(self, lb):
        # 维度
        n_dim = len(self._n_possibilities)
        # n种结果
        n_category = len(self._cat_counter)
        # TODO:计算先验概率的函数,lb就是平滑项
        p_category = self.get_prior_probability(lb)
        logging.debug("p_category")
        logging.debug(p_category)
        # 初始化 data
        # In [1]: [None]*3
        # Out[1]: [None, None, None]
        data = [None] * n_dim
        for dim, n_possibilities in enumerate(self._n_possibilities):
            data[dim] = [[(self._con_counter[dim][c][p] + lb) / (self._cat_counter[c] + lb * n_possibilities) \
                          for p in range(n_possibilities)] for c in range(n_category)]
        self._data = [np.array(dim_info) for dim_info in data]
        logging.debug("_data")
        logging.debug(self._data)
        """
        [
        array([[0.625, 0.375],
               [0.625, 0.375]]), 
        array([[0.75, 0.25],
               [0.25, 0.75]]), 
        array([[0.375, 0.625],
               [0.625, 0.375]]), 
        array([[0.25, 0.75],
               [0.75, 0.25]])]
        """
        def func(input_x, tar_category):
            rs = 1
            for d, xx in enumerate(input_x):
                rs *= data[d][tar_category][xx]
            return rs * p_category[tar_category]
        return func

后面有个小尾巴 def func 是用来返回的,请看下面。
现在我们可以完整的写一下训练的过程了,输入(x,y)的文本,将数据训练好

    # TODO:进行训练
    def fit(self, x=None, y=None, sample_weight=None, lb=1):
        if x is not None and y is not None:
            self.feed_data(x, y, sample_weight)
        self._func = self._fit(lb)

[3]预测,利用MAP估计进行评估

我们要完成以下任务:
[3.1] 单样本预测
[3.2] 多样本预测
[3.3] 利用数值化后的(x,y)进行评估

[3.1] 单样本预测

    # TODO:预测单一样本
    def predict_one(self, x, get_raw_result=False):
        if isinstance(x, np.ndarray):
            x = x.tolist()
        else:
            x = x[:]
        # 相关数值化方法进行数值话
        x = self._transfer_x(x)
        m_arg = 0
        m_probability = 0
        for i in range(len(self._cat_counter)):
            p = self._func(x, i)
            logging.debug("p"+str(i))
            logging.debug(p)
            if p > m_probability:
                m_arg = i
                m_probability = p
        if not get_raw_result:
            return self.label_dic[m_arg]
        return m_probability

其中有对标签的数值化函数
self._transfer_x(x)
方法同 feed_data 中的方法

def _transfer_x(self, x):
    return x = np.array([feat_dict[i][_l] for i, _l in enumerate(x)])

[3.2] 多样本预测

也就是不停的调用单样本预测

    # TODO:多样本预测
    def predict(self, x, get_raw_result=False):
        return np.array([self.predict_one(xx, get_raw_result) for xx in x])

[3.3] 利用数值化后的(x,y)进行评估

    # TODO:对预测进行评估
    def evaluate(self, x, y):
        y_pred = self.predict(x)
        print("正确率:{:12.6}%".format(100 * np.sum(y_pred == y) / len(y)))

[4] 导入和保存数据

到这里就结束了,但是为了更加丰富一下内容。为了能够节约训练的时间(不超过0.001s),或者说就是纯粹为了保存(演示)一下训练结果,和导入训练结果。
[4.1] 保存训练结果
[4.2] 导入训练结果

[4.1] 保存训练结果

    def saveresult(self):
        np.save(os.path.abspath("./data"), self._data)
        print("data保存成功")
        np.save(os.path.abspath("./label_dic"), self._laabel_dic)
        print("label_dic保存成功")
        np.save(os.path.abspath("./feat_dic"), self._feat_dic)
        print("_feat_dic保存成功")

[4.2] 导入训练结果

    def loadresult(self,datapath,label_dicpath,feat_dic):
        self._data = np.load(datapath)
        print("datapath导入成功")
        print(self._data)
        self._label_dic = np.load(label_dicpath)
        print("label_dicpath导入成功")
        print(self._label_dic)
        self._feat_dic= np.load(feat_dic)
        print("_feat_dic导入成功")
        print(self._feat_dic)

0X04 完整代码

import logging
import numpy as np

logging.basicConfig(level=logging.DEBUG)


class DataUtil:
    """
    path: 文件路径(可以用相对路径)
    train_num: 是否设置训练集,训练集的数量
    tar_idx: 标签的列号,默认是最后一列
    shuffle: 是否对数据集进行洗牌,对于贝叶斯算法,在没有区分训练集的情况下,
    洗牌只是让最初的数据变得混乱,对最后的结果没有影响
    这里为了能得到和我们前面的手算结果一致我们就不洗牌了
    """

    def get_dataset(path, train_num=None, tar_idx=None, shuffle=False):
        x = []
        with open(path, mode="r", encoding="utf-8") as f:
            for sample in f:
                x.append(sample.strip().split(","))
        if shuffle:
            np.random.shuffle(x)
        # python中的三元运算
        tar_idx = -1 if tar_idx is None else tar_idx
        y = np.array([xx.pop(tar_idx) for xx in x])
        x = np.array(x)
        logging.debug("get_dataset-x")
        logging.debug(x)
        logging.debug("get_dataset-y")
        logging.debug(y)

        if train_num is None:
            return x, y
        return (x[:train_num], y[:train_num]), (x[train_num:], y[train_num:])


class MultinomialNB(object):
    def __init__(self):
        # 数值化后的输入向量
        self._x = None
        # 数值化后的标签
        self._y = None
        # 训练结果,条件概率分布
        self._data = None
        # 决策函数
        self._func = None
        # 每个向量的取值情况
        self._n_possibilities = None
        # 按标签分类后的x
        self._labelled_x = None
        # 将x,y进行捆绑
        self._label_zip = None
        # 标签的统计
        self._cat_counter = None
        # 特征值的统计
        self._con_counter = None
        # 标签的字典
        self._label_dic = None
        # 特征值的字典
        self._feat_dic = None

    def feed_data(self, x, y, sample_weight=None):
        # 进行转置
        if isinstance(x, list):
            features = map(list, zip(*x))
        else:
            features = x.T
        # 利用集合获取各个维度的特征值
        # TODO:[0.2] 对每个维度生成字典
        features = [set(feat) for feat in features]
        feat_dict = [{_l: i for i, _l in enumerate(feats)} for feats in features]
        label_dic = {_l: i for i, _l in enumerate(set(y))}
        # [0.4] 按照特征值字典进行映射
        x = np.array([[feat_dict[i][_l] for i, _l in enumerate(sample)] for sample in x])
        y = np.array([label_dic[yy] for yy in y])
        # [1.0] 统计y中每个特征出现的频率
        cat_counter = np.bincount(y)
        # [0.3] 为了平滑,我们需要计算K(每个向量的特征值个数)
        n_possibilities = [len(feads) for feads in features]
        # 获取各类别数据的下标
        labels = [y == value for value in range(len(cat_counter))]
        # 利用下标获取记录按类别分开后的输入数据的数组
        labelled_x = [x[ci].T for ci in labels]

        self._x = x
        logging.debug("self._x")
        logging.debug(x)

        self._y = y
        logging.debug("self._y")
        logging.debug(y)

        self._labelled_x = labelled_x
        logging.debug("labelled_x")
        logging.debug(labelled_x)

        self._label_zip = list(zip(labels, labelled_x))
        logging.debug("_label_zip")
        logging.debug(self._label_zip)

        self._cat_counter = cat_counter
        logging.debug("cat_counter")
        logging.debug(cat_counter)

        self._feat_dic = feat_dict
        logging.debug("feat_dict")
        logging.debug(feat_dict)

        self._n_possibilities = n_possibilities
        logging.debug("n_possibilities")
        logging.debug(n_possibilities)
        # 注意这里是反字典
        self._label_dic = {i: _l for _l, i in label_dic.items()}
        logging.debug("label_dic")
        logging.debug(self._label_dic)

        # 处理样本权重的函数,以更新记录概率的数组
        self.feed_sample_weight(sample_weight)
        logging.debug("feed_sample_weight _con_counter")
        logging.debug(self._con_counter)

    def get_prior_probability(self, lb=1):
        return [(_c_num + lb) / (len(self._y) + lb * len(self._cat_counter)) \
                for _c_num in self._cat_counter]

    def feed_sample_weight(self, sample_weight=None):
        self._con_counter = []
        for dim, _p in enumerate(self._n_possibilities):
            if sample_weight is None:
                self._con_counter.append([np.bincount(xx[dim], minlength=_p) for xx in self._labelled_x])
            else:
                self._con_counter.append(
                    [np.bincount(xx[dim], weights=sample_weight[label] / sample_weight[label].mean(), minlength=_p) for
                     label, xx in self._label_zip])

    def _fit(self, lb):
        # 维度
        n_dim = len(self._n_possibilities)
        # n种结果
        n_category = len(self._cat_counter)
        # TODO:计算先验概率的函数,lb就是平滑项
        p_category = self.get_prior_probability(lb)
        logging.debug("p_category")
        logging.debug(p_category)
        # 初始化 data
        # In [1]: [None]*3
        # Out[1]: [None, None, None]
        data = [None] * n_dim
        for dim, n_possibilities in enumerate(self._n_possibilities):
            data[dim] = [[(self._con_counter[dim][c][p] + lb) / (self._cat_counter[c] + lb * n_possibilities) \
                          for p in range(n_possibilities)] for c in range(n_category)]
        self._data = [np.array(dim_info) for dim_info in data]
        logging.debug("_data")
        logging.debug(self._data)

        def func(input_x, tar_category):
            rs = 1
            for d, xx in enumerate(input_x):
                rs *= data[d][tar_category][xx]
            return rs * p_category[tar_category]

        return func

    def fit(self, x=None, y=None, sample_weight=None, lb=1):
        if x is not None and y is not None:
            self.feed_data(x, y, sample_weight)
        self._func = self._fit(lb)

    def predict_one(self, x, get_raw_result=False):
        if isinstance(x, np.ndarray):
            x = x.tolist()
        else:
            x = x[:]
        # 相关数值化方法进行数值话
        x = self._transfer_x(x)
        m_arg = 0
        m_probability = 0
        for i in range(len(self._cat_counter)):
            p = self._func(x, i)
            logging.debug("p" + str(i))
            logging.debug(p)
            if p > m_probability:
                m_arg = i
                m_probability = p
        if not get_raw_result:
            return self._label_dic[m_arg]
        return m_probability

    def _transfer_x(self, x):
        return  np.array([self._feat_dic[i][_l] for i, _l in enumerate(x)])

    def predict(self, x, get_raw_result=False):
        return np.array([self.predict_one(xx, get_raw_result) for xx in x])

    def evaluate(self, x, y):
        y_pred = self.predict(x)
        print("正确率:{:12.6}%".format(100 * np.sum(y_pred == y) / len(y)))

    def saveresult(self):
        np.save("./data", self._data)
        print("data保存成功")
        np.save("./label_dic", self._label_dic)
        print("label_dic保存成功")
        np.save("./feat_dic", self._feat_dic)
        print("_feat_dic保存成功")

    def loadresult(self, datapath, label_dicpath, feat_dic):
        self._data = np.load(datapath)
        print("datapath导入成功")
        print(self._data)
        self._label_dic = np.load(label_dicpath)
        print("label_dicpath导入成功")
        print(self._label_dic)
        self._feat_dic = np.load(feat_dic)
        print("_feat_dic导入成功")
        print(self._feat_dic)


if __name__ == '__main__':
    import time

    # TODO:数据导入
    # 读入数据
    logging.debug("开始导入数据\n")
    _x, _y = DataUtil.get_dataset("../balloon1.0.txt")
    # 实例化模型并进行训练
    # TODO:数据训练
    learning_time = time.time()
    nb = MultinomialNB()
    # nb.loadresult("./data.npy","./label_dic.npy","./feat_dic.npy")
    nb.fit(_x, _y)
    learning_time = time.time() - learning_time
    # TODO:进行评估
    estimation_time = time.time()
    nb.evaluate(_x, _y)
    estimation_time = time.time() - estimation_time
    # nb.saveresult()

0X05 后记

如果你看完这篇博客,对其中的一些语句感觉惊讶,“(#`')靠,这都能运行吗?”,可能和我当时看完大佬写的这章的内容有差不多的感受。这篇算是一篇读书笔记吧,半抄半改,默默写注释。
比如这行代码:

    def _transfer_x(self, x):
        return np.array([self._feat_dic[i][_l] for i, _l in enumerate(x)])
相当与:
x=[]
for j,char in enumerate(x):
    x[j]=feat_dict[i][_l] for i,_l in enumerate(x)
x=np.array(x)
return x
大佬的书.jpg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,723评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,003评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,512评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,825评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,874评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,841评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,812评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,582评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,033评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,309评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,450评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,158评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,789评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,409评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,609评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,440评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,357评论 2 352

推荐阅读更多精彩内容

  • 忘光了概率统计的知识还想学朴素贝叶斯算法?这一篇就是为你准备的。虽然如此,作为初学者,别指望 5 分钟就能完全理解...
    kamidox阅读 2,685评论 4 7
  • 一、认识皮肤的结构 皮肤是覆盖整个体表,是人体最大的器官,有生命的衣裳之称。它是由表皮,真皮以及皮下组织三大组成部...
    纯净淡然阅读 382评论 0 1
  • 春节假期已过,各位回家过年的小伙伴也都陆续踏上归程,有小伙伴在微信上问:“父母非让装上二十斤大米,是带还是不带?”...
    妙所阅读 379评论 2 6
  • 8.东晋对江南的开发 晋一统后,天下太平,社会经济有所恢复,史称“人咸安其业而乐其事”。但好景不长,晋惠帝即位之后...
    张七公子阅读 1,594评论 0 13