1.分类预测模型:朴素贝叶斯
构建分类器的简单方法,不是训练分类器的单一算法,而是一系列基于相同原理的算法。
假定样本每个特征与其他特征都不相关,即样本所包含的属性在判定其是否为某一类时的概率分布上是独立的(条件概率)。
优点:学习和预测的效率高,易于实现;在数据较少时仍然有效,可以处理多分类问题。
缺点:分类的效果不一定高,特征独立性假设使该模型简单,但是会牺牲一定的分类准确率。
p
(
C
∣
F
1
,
.
.
.
,
F
n
)
=
p
(
C
)
p
(
F
1
,
.
.
.
,
F
n
∣
C
)
p
(
F
1
,
.
.
.
F
n
)
=
p
(
C
)
p
(
F
1
∣
C
)
.
.
.
p
(
F
n
∣
C
)
p
(
F
1
,
.
.
.
F
n
)
p(C|F_1,...,F_n)=\frac{p(C)p(F_1,...,F_n|C)}{p(F_1,...F_n)}=\frac{p(C)p(F_1|C)...p(F_n|C)}{p(F_1,...F_n)}
p(C∣F1,...,Fn)=p(F1,...Fn)p(C)p(F1,...,Fn∣C)=p(F1,...Fn)p(C)p(F1∣C)...p(Fn∣C)
1.1概率计算及参数估计
特征是离散变量,可以用频率来估计概率。
特征的连续的,一种通常的假设使这些连续数值服从高斯分布。
首先对数据类别分类,然后计算每个类别中特征x的均值和方差。
2.代码及注释
mian.py
# -*- coding: utf-8 -*-
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from nb_tools import NaiveBayes, cal_acc
def run_main():
"""
主函数
"""
n_feat = 100 # 特征个数(维度)
X, y = make_classification(
n_samples=400, #400个样本
n_features=n_feat,
n_classes=4, #四类
random_state=5)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,
random_state=17)
nb_model = NaiveBayes(n_feat)
# 样本特征为连续值,假设其符合高斯分布,则需要求出每个特征的均值和标准差
# 这里称为统计参数 stats
# 获取训练集中每个类别的统计参数nb_model里获得均值方差
tr_cls_stats = nb_model.get_cls_stats(X_train, y_train)
for cls, samples_stats in tr_cls_stats.items():
print('类{}的统计参数:'.format(cls))
for i, feat_stats in enumerate(samples_stats):
# 查看每个特征的统计参数
print('第{}个特征的统计参数{}'.format(i, feat_stats))
# 根据训练样本的统计参数进行预测
y_pred = nb_model.predict(tr_cls_stats, X_test)
# 准确率
print('准确率:{}'.format(cal_acc(y_test, y_pred)))
if __name__ == '__main__':
run_main()
nb_tools.py
# -*- coding: utf-8 -*-
import numpy as np
import scipy.stats
class NaiveBayes(object):
"""
Naive Bayes 类
"""
def __init__(self, n_feat):
self.n_feat = n_feat # 样本的特征维度
def get_cls_stats(self, X_train, y_train):
"""
返回训练集中每个类的统计参数
"""
# 获取类别
unique_cls_list = list(set(y_train.tolist()))
# 构造字典
dataset_stats = {}
for cls in unique_cls_list:
# 获取属于该类的样本(过滤)
samples_in_cls = X_train[y_train == cls]
# 获取该类样本中每个特征的统计参数
samples_in_cls_stats = self.get_samples_stats(samples_in_cls)
dataset_stats[cls] = samples_in_cls_stats
return dataset_stats
def get_samples_stats(self, samples):
"""
返回一组样本中每个特征(属性)的统计参数
"""
# 每个特征维度上计算统计参数,即均值和标准差
samples_stats = [(np.mean(samples[:, i]), np.std(samples[:, i]))
for i in range(self.n_feat)]
return samples_stats
def predict(self, tr_cls_stats, X_test):
"""
根据训练样本统计参数预测整个测试样本集
"""
y_pred = []
n_sample = X_test.shape[0] # 测试样本的个数
for i in range(n_sample):
# 遍历每个测试样本
sample = X_test[i, :]
pred = self.predict_sample(tr_cls_stats, sample)
y_pred.append(pred)
return y_pred
def predict_sample(self, tr_cls_stats, sample):
"""
根据训练样本统计参数预测单一样本
"""
cls_probs = self.cal_cls_probs(tr_cls_stats, sample)
# 初始化
best_label = None
best_prob = -1
for cls, cls_prob in cls_probs.items():
if best_label is None or cls_prob > best_prob:
best_prob = cls_prob
best_label = cls
return best_label
def cal_cls_probs(self, tr_cls_stats, sample):
"""
根据高斯分布及训练集的统计参数返回样本分类的概率
"""
probs = {}
for cls, cls_stats in tr_cls_stats.items():
# 初始化属于cls类的概率100%
probs[cls] = 1
for i in range(len(cls_stats)):
# 遍历cls类中每个特征维度上的统计参数
mean, std = cls_stats[i]
single_feat_vec = sample[i]
# 根据高斯分布的概率密度函数及每个特征维度上的统计参数求联合该概率
probs[cls] *= scipy.stats.norm.pdf(single_feat_vec, mean, std)
return probs
def cal_acc(true_labels, pred_labels):
"""
计算准确率
"""
n_total = len(true_labels)
correct_list = [true_labels[i] == pred_labels[i] for i in range(n_total)]
acc = sum(correct_list) / n_total
return acc