机器学习:朴素贝叶斯算法(Python)

一、朴素贝叶斯算法的实现

naive_bayes_classifier.py

import numpy as np
import collections as cc  # 集合的计数功能
from scipy.stats import norm  # 极大似然估计样本的均值和标准方差
from data_bin_wrapper import DataBinsWrapper


class NaiveBayesClassifier:
    """
    朴素贝叶斯分类器:对于连续属性两种方式操作,1是分箱处理,2是直接进行高斯分布的参数估计
    """
    def __init__(self, is_binned=False, is_feature_all_R=False, feature_R_idx=None, max_bins=10):
        self.is_binned = is_binned  # 连续特征变量数据是否进行分箱操作,离散化
        if is_binned:
            self.is_feature_all_R = is_feature_all_R  # 是否所有特征变量都是连续数值,bool
            self.max_bins = max_bins  # 最大分箱数
            self.dbw = DataBinsWrapper()  # 分箱对象
            self.dbw_XrangeMap = dict()  # 存储训练样本特征分箱的段点
        self.feature_R_idx = feature_R_idx  # 混合式数据中连续特征变量的索引
        self.class_values, self.n_class = None, 0  # 类别取值以及类别数
        self.prior_prob = dict()  # 先验分布,键是类别取值,键是类别取值
        self.classified_feature_prob = dict()  # 存储每个类所对应的特征变量取值频次或者连续属性的高斯分布参数
        self.feature_values_num = dict()  # 训练样本中每个特征不同的取值数,针对离散数据
        self.class_values_num = dict()  # 目标集中每个类别的样本量,Dc

    def _prior_probability(self, y_train):
        """
        计算类别的先验概率
        :param y_train: 目标集
        :return:
        """
        n_samples = len(y_train)  # 总样本量
        self.class_values_num = cc.Counter(y_train)  # Counter({'否': 9, '是': 8})
        # print(self.class_values_num)
        for key in self.class_values_num.keys():
            self.prior_prob[key] = (self.class_values_num[key] + 1) / (n_samples + self.n_class)
        # print(self.prior_prob)

    def _data_bin_wrapper(self, x_samples):
        """
        针对特定的连续特征属性索引dbw_feature_idx,分别进行分箱,考虑测试样本与训练样本使用同一个XrangeMap
        :param x_samples: 样本:即可以是训练样本,也可以是测试样本
        :return:
        """
        self.feature_R_idx = np.asarray(self.feature_R_idx)
        x_samples_prop = []  # 分箱之后的数据
        if not self.dbw_XrangeMap:
            # 为空,即创建决策树前所做的分箱操作
            for i in range(x_samples.shape[1]):
                if i in self.feature_R_idx:  # 说明当前特征是连续数值
                    self.dbw.fit(x_samples[:, i])
                    self.dbw_XrangeMap[i] = self.dbw.XrangeMap
                    x_samples_prop.append(self.dbw.transform(x_samples[:, i]))
                else:
                    x_samples_prop.append(x_samples[:, i])
        else:  # 针对测试样本的分箱操作
            for i in range(x_samples.shape[1]):
                if i in self.feature_R_idx:  # 说明当前特征是连续数值
                    x_samples_prop.append(self.dbw.transform(x_samples[:, i], self.dbw_XrangeMap[i]))
                else:
                    x_samples_prop.append(x_samples[:, i])
        return np.asarray(x_samples_prop).T

    def fit(self, x_train, y_train):
        """
        朴素贝叶斯分类器训练,可将朴素贝叶斯分类器涉及的所有概率估值事先计算好存储起来
        :param x_train: 训练集
        :param y_train: 目标集
        :return:
        """
        x_train, y_train = np.asarray(x_train), np.asarray(y_train)
        self.class_values = np.unique(y_train)  # 类别取值
        self.n_class = len(self.class_values)  # 类别数
        if self.n_class < 2:
            print("仅有一个类别,不进行贝叶斯分类器估计...")
            exit(0)
        self._prior_probability(y_train)  # 先验概率
        # 每个特征变量不同的取值数,类条件概率的分子D(x, xi)
        for i in range(x_train.shape[1]):
            self.feature_values_num[i] = len(np.unique(x_train[:, i]))
        if self.is_binned:
            self._binned_fit(x_train, y_train)  # 分箱处理
        else:
            self._gaussian_fit(x_train, y_train)  # 直接进行高斯分布估计

    def _binned_fit(self, x_train, y_train):
        """
        对连续特征属性进行分箱操作,然后计算各概率值
        :param x_train:
        :param y_train:
        :return:
        """
        if self.is_feature_all_R:  # 全部是连续
            self.dbw.fit(x_train)
            x_train = self.dbw.transform(x_train)
        elif self.feature_R_idx is not None:
            x_train = self._data_bin_wrapper(x_train)

        for c in self.class_values:
            class_x = x_train[y_train == c]  # 获取对应类别的样本
            feature_counter = dict()  # 每个离散变量特征中特定值的出现的频次,连续特征变量存u、sigma
            for i in range(x_train.shape[1]):
                feature_counter[i] = cc.Counter(class_x[:, i])
            self.classified_feature_prob[c] = feature_counter
        print(self.classified_feature_prob)

    def _gaussian_fit(self, x_train, y_train):
        """
        连续特征变量不进行分箱,直接进行高斯分布估计,离散特征变量取值除外
        :param x_train:
        :param y_train:
        :return:
        """
        for c in self.class_values:
            class_x = x_train[y_train == c]  # 获取对应类别的样本
            feature_counter = dict()  # 每个离散变量特征中特定值的出现的频次,连续特征变量存u、sigma
            for i in range(x_train.shape[1]):
                if self.feature_R_idx is not None and (i in self.feature_R_idx):  # 连续特征
                    # 极大似然估计均值和方差
                    mu, sigma = norm.fit(np.asarray(class_x[:, i], dtype=np.float64))
                    feature_counter[i] = {"mu": mu, "sigma": sigma}
                else:  # 离散特征
                    feature_counter[i] = cc.Counter(class_x[:, i])
            self.classified_feature_prob[c] = feature_counter
        print(self.classified_feature_prob)

    def predict_proba(self, x_test):
        """
        预测测试样本所属类别的概率
        :param x_test: 测试样本集
        :return:
        """
        x_test = np.asarray(x_test)
        if self.is_binned:
            return self._binned_predict_proba(x_test)
        else:
            return self._gaussian_predict_proba(x_test)

    def _binned_predict_proba(self, x_test):
        """
        连续特征变量进行分箱离散化,预测
        :param x_test: 测试样本集
        :return:
        """
        if self.is_feature_all_R:
            x_test = self.dbw.transform(x_test)
        elif self.feature_R_idx is not None:
            x_test = self._data_bin_wrapper(x_test)
        y_test_hat = np.zeros((x_test.shape[0], self.n_class))  # 存储测试样本所属各个类别概率
        for i in range(x_test.shape[0]):
            test_sample = x_test[i, :]  # 当前测试样本
            y_hat = []  # 当前测试样本所属各个类别的概率
            for c in self.class_values:
                prob_ln = np.log(self.prior_prob[c])  # 当前类别的先验概率,取对数
                # 当前类别下不同特征变量不同取值的频次,构成字典
                feature_frequency = self.classified_feature_prob[c]
                for j in range(x_test.shape[1]):  # 针对每个特征变量
                    value = test_sample[j]  # 当前测试样本的当前特征取值
                    cur_feature_freq = feature_frequency[j]  # Counter({'浅白': 4, '青绿': 3, '乌黑': 2})
                    # 按照拉普拉斯修正方法计算
                    prob_ln += np.log((cur_feature_freq.get(value, 0) + 1) /
                                      (self.class_values_num[c] + self.feature_values_num[j]))
                y_hat.append(prob_ln)  # 输入第c个类别的概率
            y_test_hat[i, :] = self.softmax_func(np.asarray(y_hat))  # 适合多分类,且归一化
        return y_test_hat

    @staticmethod
    def softmax_func(x):
        """
        softmax函数,为避免上溢或下溢,对参数x做限制
        :param x: 数组: 1 * n_classes
        :return:
        """
        exps = np.exp(x - np.max(x))  # 避免溢出,每个数减去其最大值
        return exps / np.sum(exps)

    def _gaussian_predict_proba(self, x_test):
        """
        连续特征变量不进行分箱,直接按高斯分布估计
        :param x_test: 测试样本集
        :return:
        """
        y_test_hat = np.zeros((x_test.shape[0], self.n_class))  # 存储测试样本所属各个类别概率
        for i in range(x_test.shape[0]):
            test_sample = x_test[i, :]  # 当前测试样本
            y_hat = []  # 当前测试样本所属各个类别的概率
            for c in self.class_values:
                prob_ln = np.log(self.prior_prob[c])  # 当前类别的先验概率,取对数
                # 当前类别下不同特征变量不同取值的频次,构成字典
                feature_frequency = self.classified_feature_prob[c]
                for j in range(x_test.shape[1]):  # 针对每个特征变量
                    value = test_sample[j]  # 当前测试样本的当前特征取值
                    if self.feature_R_idx is not None and (j in self.feature_R_idx):  # 连续特征
                        # 取极大似然估计的均值和方差
                        # print(feature_frequency[j].values())
                        mu, sigma = feature_frequency[j].values()
                        prob_ln += np.log(norm.pdf(value, mu, sigma) + 1e-8)
                    else:
                        cur_feature_freq = feature_frequency[j]  # Counter({'浅白': 4, '青绿': 3, '乌黑': 2})
                        # 按照拉普拉斯修正方法计算
                        prob_ln += np.log((cur_feature_freq.get(value, 0) + 1) /
                                          (self.class_values_num[c] + self.feature_values_num[j]))
                y_hat.append(prob_ln)  # 输入第c个类别的概率
            y_test_hat[i, :] = self.softmax_func(np.asarray(y_hat))  # 适合多分类,且归一化
        return y_test_hat

    def predict(self, x_test):
        """
        预测测试样本所属类别
        :param x_test: 测试样本集
        :return:
        """
        return np.argmax(self.predict_proba(x_test), axis=1)

二、可视化分类边界函数

plt_decision_function.py

import matplotlib.pyplot as plt
import numpy as np


def plot_decision_function(X, y, clf, is_show=True):
    """
    可视化分类边界函数
    :param X: 测试样本
    :param y: 测试样本的类别
    :param clf: 分类模型
    :param is_show: 是否在当前显示图像,用于父函数绘制子图
    :return:
    """
    if is_show:
        plt.figure(figsize=(7, 5))
    x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xi, yi = np.meshgrid(np.linspace(x_min, x_max, 100),
                         np.linspace(y_min, y_max, 100))
    y_pred = clf.predict(np.c_[xi.ravel(), yi.ravel()])  # 模型预测值
    y_pred = y_pred.reshape(xi.shape)
    plt.contourf(xi, yi, y_pred, cmap="winter", alpha=0.4)
    plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors="k")
    plt.xlabel("Feature 1", fontdict={"fontsize": 12})
    plt.ylabel("Feature 2", fontdict={"fontsize": 12})
    plt.title("NativeBayes Model Classification Boundary", fontdict={"fontsize": 14})
    if is_show:
        plt.show()

三、朴素贝叶斯算法的测试

import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
from naive_bayes_classifier import NaiveBayesClassifier
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from plt_decision_function import plot_decision_function


# wm = pd.read_csv("watermelon.csv").dropna()
# X, y = np.asarray(wm.iloc[:, 1:-1]), np.asarray(wm.iloc[:, -1])
# # print(X)
# # print(y)
# nbc = NaiveBayesClassifier(is_binned=True, feature_R_idx=[6, 7], max_bins=10)
# nbc.fit(X, y)
# y_proba = nbc.predict_proba(X)
# print(y_proba)
# y_hat = nbc.predict(X)
# print(y_hat)

X, y = make_blobs(n_samples=500, n_features=2, centers=4, cluster_std=0.85, random_state=0)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0, stratify=y)

nbc = NaiveBayesClassifier(is_binned=True, max_bins=20, is_feature_all_R=True)
nbc.fit(X_train, y_train)
y_pred = nbc.predict(X_test)
print(classification_report(y_test, y_pred))
plt.figure(figsize=(14, 5))
plt.subplot(121)
plot_decision_function(X_train, y_train, nbc, is_show=False)

nbc = NaiveBayesClassifier(is_binned=False, feature_R_idx=[0, 1])
nbc.fit(X_train, y_train)
y_pred = nbc.predict(X_test)
print(classification_report(y_test, y_pred))
plt.subplot(122)
plot_decision_function(X_train, y_train, nbc, is_show=False)
plt.show()

# al = pd.read_csv("mushroom/agaricus-lepiota.data").dropna()


 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/411739.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

绝对路径拼接漏洞 [NISACTF 2022]babyupload

打开题目 最开始以为是文件上传的漏洞 结果发现无论我们上传什么文件都会显示bad filename 去网上看了大佬的wp知道 我们直接去看源代码得到提示 /source 那我们去访问一下这个路径看看 得到一个下载文件 用记事本打开得到 源代码如下 from flask import Flask, request, r…

猫头虎分享已解决Bug || ValueError: Unknown label type: ‘continuous‘

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

Linux:线程控制

目录 线程的相关知识 线程创建 pthread_create 线程关于进程内部资源问题 线程等待 pthread_join 线程退出 pthread_cancel 线程id的理解 pthread_self 线程分离 pthread_detach 线程的相关知识 首先线程是在进程内部执行的&#xff0c;是OS调度的基本单位 线程的…

JAVA学习笔记12

1.键盘输入语句 1.1 介绍 ​ *在编程中&#xff0c;需要接收用户输入的数据&#xff0c;就可以使用键盘输入语句来获取。 1.2 步骤 ​ 1.导入该类的所在包&#xff0c;java.util.* ​ 2.创建该类对象&#xff08;声明变量&#xff09; ​ 3.调用里面的功能 import java.…

算法打卡day2|数组篇|Leetcode 977.有序数组的平方、 209.长度最小的子数组、59.螺旋矩阵II

算法题 Leetcode 977.有序数组的平方 题目链接: 977.有序数组的平方 大佬视频讲解&#xff1a;977.有序数组的平方 个人思路 第一时间就只想到暴力解法&#xff0c;双重循环一个循环比较一个循环赋值&#xff1b;但这样可能会超时&#xff0c;所以还能用双指针&#xff0…

halcon中的2D测量-椭圆

一、定义 二维测量指的是测量二维几何图形的参数&#xff0c;例如圆、椭圆、圆弧、矩形的相关参数。这里的参数对圆来说可以是半径&#xff1b;椭圆可以是长半轴、短半轴&#xff1b;矩形则包括宽和高。 二、基本步骤 1.创建测量模型 使用算子 create_metrology_model 2.设…

积分商城管理系统的设计与实现

积分商城管理系统的设计与实现 获取源码——》公主号&#xff1a;计算机专业毕设大全

设计模式(二)单例模式的七种写法

相关文章设计模式系列 面试的时候&#xff0c;问到许多年轻的Android开发他所会的设计模式是什么&#xff0c;基本上都会提到单例模式&#xff0c;但是对单例模式也是一知半解&#xff0c;在Android开发中我们经常会运用单例模式&#xff0c;所以我们还是要更了解单例模式才对…

【任何电机可使用的七段式s曲线-----包括matlab代码和simulink仿真】

永磁同步电机七段式s曲线 一、前言二、理论分析三、7段式s曲线加减速关系图四、matlab代码代码结果 五、simulink七段式s曲线整体框图simulink结果s-function内嵌代码 六、使用双闭环FOC控制-----simulink仿真示意 一、前言 S形&#xff1a;加加速(T1)→>匀加速(T2)→减加速…

【JVM】StringTable 字符串常量池

参考&#xff1a;javaGuide 字符串常量池 是 JVM 为了提升性能和减少内存消耗针对字符串&#xff08;String 类&#xff09;专门开辟的一块区域&#xff0c;主要目的是为了避免字符串的重复创建 String的不可变性 1.通过字面量的方式&#xff08;区别于new&#xff09;给一个…

Avalonia学习(二十六)-桌面系统界面Ribbon

这个界面是开源项目中拔下来的&#xff0c;我没有全部改完&#xff0c;只能按照我得界面测试。我还有一个bug没有找到&#xff0c;但是解决了一下。这里没有任何和大家说的&#xff0c;给大家看一下界面效果。 另外地图研究了缩放和显示鼠标位置经纬度

https://htmlunit.sourceforge.io/

https://htmlunit.sourceforge.io/ 爬虫 HtmlUnit – Welcome to HtmlUnit HtmlUnit 3.11.0 API https://mvnrepository.com/artifact/net.sourceforge.htmlunit/htmlunit/2.70.0 https://s01.oss.sonatype.org/service/local/repositories/releases/content/org/htmlunit…

Java核心知识点常考面试题(持续更新中)

Java核心知识点常考面试题&#xff08;持续更新中&#xff09; 线程与线程池线程线程池 Java锁机制java线程模型java锁分类轻量级锁重量级锁ReentrantLock 底层原理与源码深度解析ReentrantReadWriteLock 深入理解读写锁CountDownLatchsemaphore 实现公平锁与非公平锁线程死锁与…

Android 9.0 禁用插入耳机时弹出的保护听力对话框

1.前言 在9.0的系统rom定制化开发中,在某些产品中会对耳机音量调节过高限制,在调高到最大音量的70%的时候,会弹出音量过高弹出警告,所以产品 开发的需要要求去掉这个音量弹窗警告功能,接下来就来具体实现这个功能 2.禁用插入耳机时弹出的保护听力对话框的核心类 framework…

第六十八天 APP攻防-XposedFridaHook证书校验反代理代理转发

第68天 APP攻防-Xposed&Frida&Hook&证书校验&反代理&代理转发 知识点&#xff1a; 1、APP防代理绕过-应用&转发 2、APP证书校验类型-单向&双向 3、APP证书校验绕过-Frida&XP框架等 章节点&#xff1a; 1、信息收集-应用&资产提取&权…

蓝桥杯-标题统计

知识点: 关键是考察getline的作用 #include <iostream> using namespace std; int main() { string a; int t0; getline(cin,a);//每次读取一整行并把Enter键生成的换行符抛弃 for(int i0;i<a.length();i){ if(a[i]! )t; } cout<<t; return …

【LTSPICE】宏模型中的语法分析(持续更新)

本篇文章用来总结模型文件、仿真文件中的语法&#xff0c;写给自己看的&#xff0c;格式和内容上比较随意 上图是在安森美官网上下载的一款二极管的spice模型文件。 * 字符串&#xff1a;注释&#xff0c;能看到这篇文章的应该都懂啥叫注释.model&#xff1a;.一个词是命令…

如何修改图片尺寸大小不变形?简单的图片改大小的方法

在平时工作或者学习时&#xff0c;有时候需要将图片的大小进行修改&#xff0c;以便于存储、分享或打印&#xff0c;很多人都习惯性的去下载一些图片处理软件&#xff0c;比较麻烦&#xff0c;这里推荐大家使用图片在线处理工具&#xff0c;打开浏览器直接将图片尺寸修改&#…

【Flink】Flink 中的时间和窗口之窗口(Window)

1. 窗口的概念 Flink是一种流式计算引擎&#xff0c;主要是来处理无界数据流&#xff0c;数据流的数据是一直都有的&#xff0c;等待流结束输入数据获取所有的流数据在做聚合计算是不可能的。为了更方便高效的处理无界流&#xff0c;一种方式就是把无限的流数据切割成有限的数…

【析】装卸一体化车辆路径问题的自适应并行遗传算法

0 引言 国内外有关 &#xff36;&#xff32;&#xff30;&#xff33;&#xff30;&#xff24;的文献较多&#xff0c;求解目标多以最小化车辆行驶距离为主&#xff0c;但现实中可能存在由租赁费用产生的单次派出成本&#xff0c;需要综合考 虑单次派车成本和配送路径成本。…