朴素贝叶斯实现森林分类

利用朴素贝叶斯实现森林分类,不明白朴素贝叶斯的同学推荐去看看西瓜书,本文的实现方法和书上一致。PS:转载请注明本文链接

1.数据集下载地址

Forest type mapping Data Set

2.相关资源

我的另一篇博文是利用BP神经网络实现相同任务,有兴趣的可以去看看。

3.代码运行结果

先放一个代码运行完的结果,证明这个代码是可以运行的


在这里插入图片描述

4.实现代码

# 导入包
import pandas as pd
import numpy as np
import time


def load_datasets(filepath):
    """
    功能:
        读取csv文件数据并进行分割,分割为特征集和标签集
    输入参数:
        filepath - 数据文件路径
    返回值:
        feature - 特征集,一个m*n矩阵,m为样本数,n为特征维度
        label - 标签集,一个m*1的矩阵,m为样本数,1为标签维度,值为0,1,2,3
    """
    dataset = pd.read_csv(filepath)  # 读取csv文件
    dataset['class'] = dataset['class'].map({"s ": 0, "h ": 1, "d ": 2, "o ": 3})  # 将字符转换为数值,注意字符后面的空格不能去掉,这是一个坑
    label = dataset.loc[:, ['class']]  # 读取标签,数据类型为DataFrame
    label = np.array(label)  # 转换为array
    feature = dataset.iloc[:, 1:dataset.shape[1]]  # 将特征数据分割出来
    feature = np.array(feature)  # 转换为array
    return feature, label  # (198, 27) (198, 1)


def random_dataset(train_x, train_y, test_x, test_y, seed):
    """
    功能:
        打乱训练集和测试集数据,使数据同分布
    输入参数:
        train_x - 训练特征集,一个m1*n矩阵,m1为训练样本数,n为特征维度
        train_y - 训练标签集,一个m1*1阵,m1为训练样本数
        test_x - 测试特征集,一个m2*n矩阵,m2为测试样本数,n为特征维度
        test_y - 测试标签集,一个m2*1矩阵,m2为测试样本数
        seed - 程序随机种子
    返回值:
        new_train_x - 打乱后的训练特征集,一个m1*n矩阵,m1为训练样本数,n为特征维度
        new_train_y - 打乱后的训练标签集,一个m1*1阵,m1为训练样本数
        new_test_x - 打乱后的测试特征集,一个m2*n矩阵,m2为测试样本数,n为特征维度
        new_test_y - 打乱后的测试标签集,一个m2*1矩阵,m2为测试样本数
    """
    if seed > 0:
        np.random.seed(seed)  # 随机种子大于0,就打乱数据集,设置随机种子
        m = train_x.shape[0]  # 训练样本数
        new_x = np.concatenate((train_x, test_x), axis=0)  # 将特征集进行拼接
        new_y = np.concatenate((train_y, test_y), axis=0)  # 将标签集进行拼接
        per = np.random.permutation(new_x.shape[0])  # 打乱特征集行号
        new_x = new_x[per, :]  # 获取打乱后的特征数据
        new_y = new_y[per, :]  # 获取打乱后的标签数据
        new_train_x, new_test_x = np.vsplit(new_x, [m])  # 按原训练样本数进行分割
        new_train_y, new_test_y = np.vsplit(new_y, [m])  # 按原训练样本数进行分割
    else:
        new_train_x, new_train_y, new_test_x, new_test_y = train_x, train_y, test_x, test_y  # 随机种子小于零就不打乱数据集
    return new_train_x, new_train_y, new_test_x, new_test_y


def get_class_prior_probability(labels):
    """
    功能:
        计算类先验概率,频率代替概率
    输入参数:
        labels - 标签集,m*1矩阵,m为样本数
    返回值:
        calss_prior_probability - 各类先验概率,字典
    """
    labels = labels.T[0, :].tolist()  # 转换为list类型
    labelset = set(labels)  # 去重
    class_prior_probability = {}  # 存入label的概率
    for label in labelset:
        class_prior_probability = labels.count(label) / float(len(labels))  # 类先验概率公式:Pi = count(yi) / count(Y)
    return class_prior_probability


def get_class_feature_mean_std(features, labels):
    """
    功能:
        计算类条件概率,求各特征的高斯密度函数中的均值和标准差
    输入参数:
        features - 特征集,m*n矩阵,m为样本数,n为特征维数
        labels - 标签集,m*1矩阵,m为样本数
    返回值:
        mean_std_dict - c*2*n均值和标准差矩阵字典,c为类别数,2为均值和标准差,n为特征维数,键为类别
    """
    # 特征集按类分割
    labels_set = set(labels.T[0, :].tolist())  # 提取标签集中不重复元素
    features_dict = {}  # 特征集分类字典
    for label in labels_set:
        index = np.where(labels == label)  # 找到标签集中index元素的所有索引
        features_dict = features[index, :][0, :, :]  # 将对应样本的特征矩阵存入字典
    # 计算均值和标准差
    mean_std_dict = {}  # 各类均值和标准差字典
    for key in features_dict.keys():
        features_split = features_dict[key]  # 取出各类特征矩阵
        mean_std = np.zeros((2, features.shape[1]))  # 初始化均值和标准差矩阵
        for index in range(features_split.shape[1]):
            mean_std[0][index] = np.mean(features_split[:, index])  # 求均值
            mean_std[1][index] = np.std(features_split[:, index])  # 求标准差
        mean_std_dict[key] = mean_std  # 将均值和标准差存入字典
    return mean_std_dict


def get_class_posterior_probability(features, class_prior_probability, mean_std_dict):
    """
        功能:
            计算类后验概率
        输入参数:
            features - 特征集,m*n矩阵,m为样本数,n为特征维数
            class_prior_probability - 各类先验概率,列表
            mean_std_dict - c*2*n均值和标准差矩阵字典,c为类别数,2为均值和标准差,n为特征维数,键为类别
        返回值:
            cpp_dict - c*m*1类后验概率矩阵字典,键为类别,c为类别数,m为样本数
    """
    cpp_dict = {}  # 类后验概率字典
    for key in mean_std_dict.keys():
        mean_std = mean_std_dict[key]  # 取出第k类均值和标准差矩阵
        # 计算样本联合密度函数
        fx = (1 / (np.sqrt(2 * np.pi) * mean_std[1, :])) * np.exp(
            -((features - mean_std[0, :]) ** 2) / (2 * mean_std[1, :] ** 2))  # 计算样本特征高斯密度
        ccp = np.ones((fx.shape[0], 1))  # 初始化类条件概率
        for index in range(fx.shape[1]):
            ccp = ccp * (fx[:, index].reshape(ccp.shape[0], -1))  # 类条件概率等于样本联合密度函数,联合密度函数为各边缘密度函数之积
        # 计算类后验概率
        cpp = class_prior_probability[key] * ccp
        cpp_dict[key] = cpp
    return cpp_dict


def evaluation(cpp_dict, labels):
    """
    功能:
        评估预测结果
    输入参数:
        cpp_dict - c*m*1类后验概率矩阵字典,键为类别,c为类别数,m为样本数
        labels - 标签集,一个m*1的矩阵,m为样本数,1为标签维度,值为0,1,2,3
    返回值:
        acc - 准确率
        class_pre - 预测类别
    """
    cpp = np.zeros((cpp_dict[0].shape[0], len(cpp_dict.keys())))  # 零初始化类后验概率矩阵
    for key in cpp_dict.keys():
        cpp[:, key] = tuple(cpp_dict[key])  # 将类后验概率字典读入矩阵
    cpp_one_hot = list(map(lambda x: x == max(x), cpp)) * np.ones(shape=cpp.shape)  # 为方便计算准确率,将类后验概率进行one-hot编码
    labels_one_hot = np.eye(4)[labels].reshape(cpp_one_hot.shape[0], 4)  # 为方便计算准确率,将标签进行one-hot编码
    acc = np.sum(cpp_one_hot * labels_one_hot) / cpp_one_hot.shape[0]  # 计算准确率
    class_pre = pd.Series(cpp_one_hot.argmax(axis=1).tolist()).map({0: 's', 1: 'h', 2: 'd', 3: 'o'})  # 将数字类别标签转化为字符类别标签
    return acc, class_pre


if __name__ == '__main__':
    start = time.time()  # 记录当前时间
    # 训练,测试文件路径
    TrainingFilePath = 'training.csv'
    TestingFilePath = 'testing.csv'
    # 加载数据
    train_x, train_y = load_datasets(TrainingFilePath)
    test_x, test_y = load_datasets(TestingFilePath)
    # 打乱数据集,使训练集和测试集同分布
    # seed = [0,1] average_acc = 0.8642,seed = 9 average_acc = 0.8738
    # 经过初步测试,打乱数据集对平均准确率基本无影响(一般会使训练准确率下降,测试准确率上升)
    # train_x, train_y, test_x, test_y = random_dataset(train_x, train_y, test_x, test_y, 9)
    # 计算类先验概率
    class_prior_probability = get_class_prior_probability(train_y)
    # 计算训练集各类均值和标准差
    mean_std_dict = get_class_feature_mean_std(train_x, train_y)
    print("****************************训练集评估****************************")
    # 计算样本类后验概率
    train_cpp_dict = get_class_posterior_probability(train_x, class_prior_probability, mean_std_dict)
    # 计算预测准确率和预测类别,进行评估
    train_acc, train_class_pre = evaluation(train_cpp_dict, train_y)
    print("训练集准确率:" + str(train_acc))
    # print("训练集预测类别:\n" + str(train_class_pre))
    print("****************************测试集评估****************************")
    # 计算样本类后验概率
    test_cpp_dict = get_class_posterior_probability(test_x, class_prior_probability, mean_std_dict)
    # 计算预测准确率和预测类别,进行评估
    test_acc, test_class_pre = evaluation(test_cpp_dict, test_y)
    print("测试集准确率:" + str(test_acc))
    # print("测试集预测类别:\n" + str(test_class_pre))
    print("*****************************总体评估*****************************")
    average_acc = train_acc * train_x.shape[0] / (train_x.shape[0] + test_x.shape[0]) \
                  + test_acc * test_x.shape[0] / (train_x.shape[0] + test_x.shape[0])
    print("平均准确率:" + str(average_acc))
    print("程序运行时间为:" + str(time.time() - start))
暂无评论

发送评论 编辑评论


|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇