系列文章目录
【学习笔记】 陈强-机器学习-Python-Ch4 线性回归
【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归
【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv)
【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归
【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析
文章目录
前言
本学习笔记 仅为以防自己忘记了,顺便分享给一起学习的网友们参考。如有不同意见/建议,可以友好讨论。
本学习笔记 所有的代码和数据都可以从 陈强老师的个人主页 上下载
参考书目:陈强.机器学习及Python应用. 北京:高等教育出版社, 2021.
数学原理等 详见陈强老师的 PPT
参考了网友阡之尘埃的Python机器学习06——朴素贝叶斯
一、朴素贝叶斯 案例:spam.scv
1. spam.scv数据
1)基本信息
import pandas as pd
import numpy as np
#读取CSV文件的路径
csv_path = r'D:\桌面文件\Python\【陈强-机器学习】MLPython-PPT-PDF\MLPython_Data\spam.csv'
spam = pd.read_csv(csv_path)
spam.shape
pd.options.display.max_columns =60 #控制DataFrame在输出时最多显示60列。
'''默认情况下,pandas 会根据终端的宽度和 DataFrame 的大小自动调整显示的列数。
如果 DataFrame 列数超过了默认显示的最大列数,pandas 可能会省略中间的列,仅显示开始和结束的列。'''
spam.head(1) #显示60列的第一行
结果输出:(4601, 58)
A.1 A.2 A.3 A.4 A.5 A.6 A.7 A.8 A.9 A.10 A.11 A.12 A.13 A.14 A.15 A.16 A.17 A.18 A.19 A.20 A.21 A.22 A.23 A.24 A.25 A.26 A.27 A.28 A.29 A.30 A.31 A.32 A.33 A.34 A.35 A.36 A.37 A.38 A.39 A.40 A.41 A.42 A.43 A.44 A.45 A.46 A.47 A.48 A.49 A.50 A.51 A.52 A.53 A.54 A.55 A.56 A.57 spam
0 0.0 0.64 0.64 0.0 0.32 0.0 0.0 0.0 0.0 0.0 0.0 0.64 0.0 0.0 0.0 0.32 0.0 1.29 1.93 0.0 0.96 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.778 0.0 0.0 3.756 61 278 spam
2)响应变量spam的分布
#响应变量spam的分布
print(spam.spam.value_counts())
spam.spam.value_counts(normalize=True) #百分比计算
spam
email 2788
spam 1813
Name: count, dtype: int64
spam
email 0.605955
spam 0.394045
Name: proportion, dtype: float64
笔记:value_counts
value_counts 用于计算每个唯一值的频数。
#基本语法和参数
Series.value_counts(
normalize=False, #normalize:默认为 False。如果为 True,返回每个唯一值的比例,而不是频数。
sort=True, #sort:默认为 True(按频数从高到低排序)。如果为 False,则按唯一值排序。
ascending=False, #ascending:默认为 False。如果为 True,以升序排序频数。与 sort 参数配合使用。
bins=None, #bins:(整数)默认为 None。用于将数据分箱(即将数据分成指定数量的区间),通常用于连续数据。
dropna=True) #dropna:默认为 True(忽略 NaN 值)。如果为 False,包括 NaN 的计数。
3)特征变量的分布(直方图)
import matplotlib.pyplot as plt
import seaborn as sns
spam.iloc[:, :5].plot.hist( #绘制 spam DataFrame 的前五列的直方图
subplots=True,
bins=100)
spam.iloc[:, -4:].plot.hist( #绘制 spam DataFrame 的最后3个特征变量的直方图
grid=True, # 显示网格线
bins=100)
笔记:plot.hist()
(pandas 的)plot.hist() 用于绘制直方图。
#基本语法和参数
DataFrame.plot.hist(
bins=None, #指定直方图的条形数量或边界数。可以是一个整数(条形的数量),也可以是一个列表(每个条形的边界)。
range=None, #元组 (min, max),指定直方图显示的值的范围。默认情况下使用数据的最小和最大值。
density=False, #默认为 False。如果为 True,显示概率密度,而不是频数。
weights=None, #数组,指定每个值的权重,用于加权的直方图。
cumulative=False, #默认为 False。如果为 True,显示累积直方图。
bottom=None, #标量或数组,设置条形的底部位置,通常用于堆积直方图。
histtype='bar', #指定直方图的类型。可选值包括 'bar'(条形),'barstacked'(堆叠条形),'step'(线条),'stepfilled'(填充的线条)。
align='mid', #指定条形的对齐方式。可选值有 'left'、'mid' 和 'right'。
orientation='vertical', #指定直方图的方向。可选值为 'vertical'(垂直)和 'horizontal'(水平)。
rwidth=None, #浮点数,指定条形的宽度占整个区间宽度的比例。
log=False, #默认为 False。如果为 True,则 y 轴以对数尺度显示。
color=None, #指定条形的颜色。可以是单个颜色,也可以是颜色列表。
edgecolor='black', #指定条形边框的颜色。
linestyle=None, #指定条形边框的样式。
subplots=False, #默认为 False。如果为 True,为 DataFrame 的每列绘制一个子图。
sharex=False, #默认为 False。如果为 True,所有子图共享 x 轴。
sharey=False, #默认为 False。如果为 True,所有子图共享 y 轴。
figsize=None, #元组 (宽度, 高度),指定图形的大小。
grid=True, #默认为 True。是否显示网格线。
ax=None, #Matplotlib 的 Axes 对象,指定绘制图形的轴。
layout=None, #元组 (行数, 列数),指定子图的布局。
legend=True, #默认为 True。是否显示图例。
title=None, #字符串,指定图形的标题。
4)定义数据矩阵X与响应向量y
#定义X与y
X = spam.iloc[:, :-1]
y = spam.iloc[:, -1]
#全样本随机分20%测试集和80%训练集
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,
stratify=y,
random_state=0)
2.朴素贝叶斯估计
1)高斯朴素贝叶斯 (Gaussian Naive Bayes)
适用于:特征符合高斯(正态)分布的连续数据。
#高斯朴素贝叶斯(Gaussian Naive Bayes)
from sklearn.naive_bayes import GaussianNB
GNB = GaussianNB()
GNB.fit(X_train, y_train)
# 进行预测
y_pred_GNB = GNB.predict(X_test)
# 测试集的预测准确率
print("GaussianNB 测试集的预测准确率:",GNB.score(X_test, y_test))
#打印 混淆矩阵
from sklearn.metrics import confusion_matrix
print("GaussianNB 混淆矩阵:\n",confusion_matrix(y_test, y_pred_GNB))
# 打印分类报告
from sklearn.metrics import classification_report
print("GaussianNB Classification Report:\n", classification_report(y_test, y_pred_GNB))
结果输出: GaussianNB 测试集的预测准确率: 0.8447339847991314
GaussianNB 混淆矩阵:
[[428 130]
[ 13 350]]
笔记:GaussianNB
GaussianNB 是 scikit-learn 中实现的高斯朴素贝叶斯分类器,用于处理特征分布符合高斯分布的二分类或多分类问题。它属于朴素贝叶斯分类器的一种,假设每个特征的条件分布都是高斯分布。
#基本语法和参数
from sklearn.naive_bayes import GaussianNB
# 创建 GaussianNB 对象
gnb = GaussianNB(
priors = None, #(可选)类别的先验概率。默认值为 None。也可以指定了 priors 参数,必须提供一个一维数组,数组的长度等于类别的数量。数组中的每个值对应于各个类别的先验概率。
var_smoothing=1e-9) #(高级配置)如果你数据特征的方差较小或者存在异常值,可以使用 var_smoothing 参数来进行平滑处理。默认=1e-9
2)多项朴素贝叶斯 (Multinomial Naive Bayes)
多项朴素贝叶斯(Multinomial Naive Bayes) 适用于特征是离散计数数据的情况,比如文档分类中的词频特征。
假设特征符合多项分布,用于处理分类数据或文本数据。
#多项朴素贝叶斯 (Multinomial Naive Bayes)
from sklearn.naive_bayes import MultinomialNB
MNB = MultinomialNB(alpha=0)
MNB.fit(X_train, y_train)
# 进行预测
y_pred_MNB = MNB.predict(X_test)
# 测试集的预测准确率
print("MultinomialNB 测试集的预测准确率:",MNB.score(X_test, y_test))
#打印 混淆矩阵
print("MultinomialNB 混淆矩阵:\n",confusion_matrix(y_test, y_pred_MNB))
# 打印分类报告
print("MultinomialNB Classification Report:\n", classification_report(y_test, y_pred_MNB))
结果输出: MultinomialNB 测试集的预测准确率: 0.7926167209554832
MultinomialNB 混淆矩阵:
[[473 85]
[106 257]]
笔记:MultinomialNB
**MultinomialNB ** 是 用于处理具有离散特征的数据,通常应用于文本分类等任务。它假设特征的分布符合多项分布。
#基本语法和参数
from sklearn.naive_bayes import MultinomialNB
# 创建 MultinomialNB 对象
mnb = MultinomialNB(
alpha=1, #平滑参数,用于避免在训练数据中某些特征频率为零时出现问题。alpha 为 1.0 对应拉普拉斯平滑(加1平滑),alpha 值越小,平滑效果越弱。
fit_prior=False, #是否学习类别的先验概率。默认=True;如果设置为 False,则所有类别的先验概率将被设置为相等值。
class_prior =None #类别的先验概率。如果 fit_prior 为 False,需要显式指定 class_prior,以设置每个类别的先验概率。数组长度应与类别数量匹配。
)
(1)拉普拉斯修正
#拉普拉斯修正(alpha=1)
MNB_1 = MultinomialNB(alpha=1)
MNB_1.fit(X_train, y_train)
# 进行预测
y_pred_MNB_1 = MNB_1.predict(X_test)
# 测试集的预测准确率
print("MultinomialNB拉普拉斯修正 测试集的预测准确率:",MNB_1.score(X_test, y_test))
#打印 混淆矩阵
print("MultinomialNB拉普拉斯修正 混淆矩阵:\n",confusion_matrix(y_test, y_pred_MNB_1))
# 打印分类报告
print("MultinomialNB拉普拉斯修正 Classification Report:\n", classification_report(y_test, y_pred_MNB_1))
(2)互补朴素贝叶斯(Complement Naive Bayes)
互补朴素贝叶斯(Complement Naive Bayes)是多项朴素贝叶斯的一种改进,专为处理类别不平衡问题设计。
在训练过程中,它使用每个类别的补集来计算概率,有助于提升分类性能。
#互补朴素贝叶斯(Complement Naive Bayes)
from sklearn.naive_bayes import ComplementNB
CNB = ComplementNB(alpha=1)
CNB.fit(X_train, y_train)
# 进行预测
y_pred_CNB = CNB.predict(X_test)
# 测试集的预测准确率
print("CNB 测试集的预测准确率:",CNB.score(X_test, y_test))
#打印 混淆矩阵
print("CNB 混淆矩阵:\n",confusion_matrix(y_test, y_pred_CNB))
# 打印分类报告
print("CNB Classification Report:\n", classification_report(y_test, y_pred_CNB))
笔记:ComplementNB
ComplementNB 特别设计用于处理类别不平衡的数据集。它是一种改进的朴素贝叶斯算法,旨在解决标准 MultinomialNB 在类别不平衡情况下性能下降的问题。
#基本语法和参数
from sklearn.naive_bayes import ComplementNB
# 创建 ComplementNB 对象
norm = ComplementNB (
alpha=1,#平滑参数,用于避免在训练数据中某些特征频率为零时出现问题。alpha 为 1.0 对应拉普拉斯平滑(加1平滑),alpha 值越小,平滑效果越弱。
norm = True, #是否对每个类别的特征频率进行归一化。默认=True(归一化,以确保类别间的公平比较);如果设置为 False,则不进行归一化。
fit_prior=False, #是否学习类别的先验概率。默认=True;如果设置为 False,则所有类别的先验概率将被设置为相等值。
class_prior =None) #类别的先验概率。如果 fit_prior 为 False,需要显式指定 class_prior,以设置每个类别的先验概率。数组长度应与类别数量匹配。
3)二项朴素贝叶斯(Bernoulli Naive Bayes)
二项朴素贝叶斯(Bernoulli Naive Bayes)适用于特征是二值(0或1)的情况,比如文档分类中的词是否出现。
假设每个特征是二项分布的,用于处理离散的二值特征。
#二项朴素贝叶斯(Bernoulli Naive Bayes)
from sklearn.naive_bayes import BernoulliNB
BNB = BernoulliNB() #默认参数“alpha=1”
BNB.fit(X_train, y_train)
# 进行预测
y_pred_BNB = BNB.predict(X_test)
# 测试集的预测准确率
print("BNB 测试集的预测准确率:",BNB.score(X_test, y_test))
# 打印分类报告
print("BNB Classification Report:\n", classification_report(y_test, y_pred_BNB))
'''不同门槛值'''
BNB_0 = BernoulliNB(binarize=0.1,alpha=1)
BNB_0.fit(X_train, y_train)
# 进行预测
y_pred_BNB_0 = BNB_0.predict(X_test)
# 测试集的预测准确率
print("BNB(门槛值0.1) 测试集的预测准确率:",BNB_0.score(X_test, y_test))
# 打印分类报告
print("BNB(门槛值0.1) Classification Report:\n", classification_report(y_test, y_pred_BNB_0))
笔记:BernoulliNB
BernoulliNB 适用于特征符合伯努利分布的场景。通常用于二分类问题或特征值为二元(如是否存在某个特征)的场景,例如文本分类中的词是否存在(布尔值特征)。
#基本语法和参数
from sklearn.naive_bayes import BernoulliNB
# 创建 BernoulliNB 对象
bnb = BernoulliNB(
alpha=1,#平滑参数,用于避免在训练数据中某些特征频率为零时出现问题。alpha 为 1.0 对应拉普拉斯平滑(加1平滑),alpha 值越小,平滑效果越弱。
binarize = 0.0, #用于将特征值转换为布尔值的阈值。对于特征值大于等于 binarize 的情况,该特征被认为存在(1),否则认为不存在(0)。默认值为 0.0,意味着所有的非零值都被视为特征存在。
fit_prior=False, #是否学习类别的先验概率。默认=True;如果设置为 False,则所有类别的先验概率将被设置为相等值。
class_prior =None)#类别的先验概率。如果 fit_prior 为 False,需要显式指定 class_prior,以设置每个类别的先验概率。数组长度应与类别数量匹配。
(1)超参数(binarize与alpha)的取值
#超参数(binarize与alpha)的取值:双重for循环
best_score = 0 #初始化最佳预测准确率为0
for binarize in np.arange(0, 1.1, 0.1): #循环遍历 binarize 参数的取值范围从 0 到 1(不包括 1),步长为 0.1
for alpha in np.arange(0, 1.1, 0.1): #在每个 binarize 参数下,再次循环遍历 alpha 参数的取值范围
model = BernoulliNB(binarize=binarize, alpha=alpha) #创建一个 BernoulliNB 模型,设置当前的 binarize 和 alpha 参数取值。
model.fit(X_train, y_train)
score = model.score(X_test, y_test)
if score > best_score: #如果当前模型的预测准确率高于之前记录的最佳预测准确率,则执行以下操作:
best_score = score #更新 最佳预测准确率为当前模型的准确率。
best_parameters = { #记录当前的 binarize 和 alpha 参数取值作为最佳参数组合。
'binarize': binarize, 'alpha': alpha}
best_score #最佳预测准确率
best_parameters #最佳超参数 取值
结果输出: 0.9218241042345277
{‘binarize’: 0.30000000000000004, ‘alpha’: 1.0}
这种方法严格来说等于提前泄露测试集的信息,可能会导致过拟合。
(2)解决过拟合的两种方法
方法一:全样本分为三份(训练集、测试集、验证集):要求原始数据样本容量较大
#方法一:全样本分为三份(训练集、测试集、验证集):要求原始数据样本容量较大
X_trainval, X_test, y_trainval, y_test = train_test_split(
X, y, test_size=0.2, stratify=y, random_state=0)
X_train, X_val, y_train, y_val = train_test_split(
X_trainval, y_trainval, test_size=0.25,
stratify=y_trainval, random_state=123)
y_train.shape, y_val.shape, y_test.shape
#超参数(binarize与alpha)的取值:双重for循环
best_val_score = 0
for binarize in np.arange(0, 1.1, 0.1):
for alpha in np.arange(0, 1.1, 0.1):
model = BernoulliNB(binarize=binarize, alpha=alpha)
model.fit(X_train, y_train)
score = model.score(X_val, y_val)
if score > best_val_score:
best_val_score = score
best_val_parameters = {'binarize': binarize, 'alpha': alpha}
print(best_val_score) #最佳预测准确率
print(best_val_parameters) #最佳超参数 取值
#使用训练集与验证集的合集,进行BernoulliNB,并估计 测试集的预测准确率
model_val = BernoulliNB(**best_val_parameters) #将best_val_parameters字典中的键值对作为参数传递给BernoulliNB类的构造函数。
''' ** 用于字典展开(dictionary unpacking),将字典中的键值对作为关键字参数传递给函数或类的构造函数。'''
model_val.fit(X_trainval, y_trainval)
model_val.score(X_test, y_test)
结果输出: ((2760,), (920,), (921,))
0.9065217391304348
{‘binarize’: 0.30000000000000004, ‘alpha’: 0.1}
0.9207383279044516
方法二:交叉验证
#方法二:交叉验证 cross_val_score()
from sklearn.model_selection import StratifiedKFold
from sklearn.model_selection import cross_val_score
#超参数(binarize与alpha)的取值:双重for循环
best_kfold_score = 0
kfold = StratifiedKFold(
n_splits=10, shuffle = True, random_state=1)
for binarize in np.arange(0, 1.1, 0.1):
for alpha in np.arange(0, 1.1, 0.1):
model = BernoulliNB(binarize=binarize, alpha=alpha)
scores = cross_val_score(
model, X_trainval, y_trainval, cv=kfold)
score = np.mean(scores)
if score > best_kfold_score:
best_kfold_score = score
best_kfold_parameters = {'binarize': binarize, 'alpha': alpha}
print(best_kfold_score) #最佳预测准确率
print(best_kfold_parameters) #最佳超参数 取值
#使用训练集与验证集的合集,进行BernoulliNB,并估计 测试集的预测准确率
model_kfold = BernoulliNB(**best_kfold_parameters)
model_kfold.fit(X_trainval, y_trainval)
model_kfold.score(X_test, y_test)
结果输出: 0.8991847826086957
{‘binarize’: 0.1, ‘alpha’: 0.1}
0.9153094462540716
网格上交叉验证
#定义超参数网格
param_grid = {'binarize': np.arange(0, 1.1, 0.1),
'alpha': np.arange(0, 1.1, 0.1)}
from sklearn.model_selection import GridSearchCV
GCV = GridSearchCV(BernoulliNB(), param_grid, cv=kfold)
GCV.fit(X_trainval, y_trainval)
#测试集评分
print(GCV.score(X_test, y_test))
#模型最优参数
print(GCV.best_params_)
#验证时最优评分
print(GCV.best_score_)
#最佳的估计器
print(GCV.best_estimator_)
结果输出: 0.9153094462540716
{‘alpha’: 0.1, ‘binarize’: 0.1}
0.8991847826086957
BernoulliNB(alpha=0.1, binarize=0.1)
展示交叉验证结果
#获取每个交叉验证的详细信息,变为数据框
results = pd.DataFrame(GCV.cv_results_)
results.head(2)
#热力图:10个子样本的 平均预测准确率
scores = np.array(results.mean_test_score).reshape(11,11)
ax = sns.heatmap(scores, cmap='nipy_spectral', annot=True, fmt='.3f')
ax.set_xlabel('binarize')
ax.set_xticklabels([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])
ax.set_ylabel('alpha')
ax.set_yticklabels([0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1])
plt.tight_layout()
4)预测 结果 展示
#预测概率
prob = GCV.predict_proba(X_test)
prob[:3]
结果输出:
array([[4.76074721e-05, 9.99952393e-01],
[9.99997643e-01, 2.35698580e-06],
[9.98936466e-01, 1.06353378e-03]])
#预测类别
pred = GCV.predict(X_test)
pred[:3]
结果输出: array([‘spam’, ‘email’, ‘email’], dtype=‘<U5’)
#数据透视表,混淆矩阵
table = pd.crosstab(y_test, pred, rownames=['Actual'], colnames=['Predicted'])
table
结果输出:
#计算准确率、错误率、敏感度、特异度、召回率、科恩指标
table = np.array(table)
Accuracy = (table[0, 0] + table[1, 1]) / np.sum(table)
print(Accuracy) #准确率
Error_rate = 1 - Accuracy
print(Error_rate) #错误率
Sensitivity = table[1, 1]/(table[1, 0] + table[1, 1])
print(Sensitivity) # 敏感度
Specificity = table[0, 0] / (table[0, 0] + table[0, 1])
print(Specificity) #特异度
Recall = table[1, 1] / (table[0, 1] + table[1, 1])
print(Recall) #召回率
from sklearn.metrics import cohen_kappa_score
print(cohen_kappa_score(y_test, pred)) #科恩指标
结果输出: 0.9153094462540716
0.08469055374592838
0.8760330578512396
0.9408602150537635
0.905982905982906
0.821639256346085
#绘制 roc:RocCurveDisplay
from sklearn.metrics import RocCurveDisplay
RocCurveDisplay.from_estimator(GCV, X_test, y_test, plot_chance_level=True)
笔记:RocCurveDisplay
RocCurveDisplay 是 scikit-learn 中用于绘制 ROC 曲线的显示类。
from sklearn.metrics import RocCurveDisplay
display = RocCurveDisplay.from_predictions(
y_true, #真实标签,通常是二进制(0 和 1)
y_score, #模型的预测"概率",用于计算 ROC 曲线
pos_label=None, #正类标签,默认为 None。指定正类的标签值。如果标签不是二进制,必须提供此参数。
sample_weight=None, #样本权重,默认为 None。用于加权样本。
drop_intermediate=True, #控制是否在计算过程中丢弃中间步骤。默认为True(在计算过程中丢弃中间步骤), False(保留中间步骤)。
response_method='predict_proba') #表示获取预测概率的方法,默认为 'predict_proba'。可以是 'decision_function' 或 'predict_proba'。
二、iris数据作为案例:高斯朴素贝叶斯
from sklearn.datasets import load_iris
from mlxtend.plotting import plot_decision_regions
X, y = load_iris(return_X_y=True)
X2 = X[:, 2:4]
#进行 高斯朴素贝叶斯 估计
model = GaussianNB()
model.fit(X2, y)
print(model.score(X2, y))
#画出 模型决策边界
plot_decision_regions(X2, y, model)
plt.xlabel('petal_length')
plt.ylabel('petal_width')
plt.title('Decision Boundary for Gaussian Naive Bayes')
结果输出: 0.96