十二、贝叶斯算法
-
使用概率来估计数据的类别信息
-
条件概率:在B发生了的时候,A发生的概率,数学符号P(A|B)
-
P(A∩B):就是AB同时发生的概率
-
P(B):B发生的概率
-
独立事件:事件A和事件B两个发生的时候,互不影响 ---
-
假设我们收到了一封邮件,有可能是垃圾邮件、有可能不是垃圾邮件
-
先验概率:根据以后的经验,收到邮件之后,我认为它是垃圾邮件的一个概率值
-
假设垃圾邮件中存在词语国外高新业务
-
似然:认为邮件就是垃圾邮件,邮件中有国外高新业务的一个概率情况
-
后验概率:知道邮件里有国外高新业务后,更新判断,他现在有多大可能是垃圾邮件
-
证据:一般可以忽略,这个值就是拿来做归一化的
-
-
张三去市场买西瓜,他认为这个商贩买的西瓜中买到熟瓜的概率是0.6【先验概率】,商贩告诉他,如果你选择瓜蒂脱落的西瓜,大概率是熟瓜,张三就要去选择瓜蒂脱落的西瓜,他就认为这就是判定是否是熟瓜的一个条件,计算的概率就是P(熟瓜|瓜蒂脱离)【后验概率,需要求出来的内容】,利用概率公式
-
把求解的内容变成了求解
P(瓜蒂脱离|熟瓜)
+P(熟瓜)
+P(瓜蒂脱离)
,其中张三认为这个瓜就是熟瓜,那么去计算瓜蒂脱离的概率 --- P(瓜蒂脱离|熟瓜) 似然 -
生瓜
-
我们只需要比较输出的后验概率的值,选择后验概率较高的作为结果,即我们比较后验概率的时候,由于求解概率的时候的分母是相同的,那么只需要比较分子即可
-
突然,张三的大爷来了,大爷告诉张三,买到熟瓜和生瓜不仅要看瓜蒂是否脱落,还需要看西瓜花纹是否清晰
- 朴素贝叶斯:假设每个特征之间是独立的,我们设特征为 X,结果【类型】为 a
- 朴素贝叶斯中朴素二字就是建立在假设各个特征之间独立的情况下,那么概率公式就可以转化为
-
假设张三经过自己的计算,算出来P(熟瓜|瓜蒂脱离)的概率为0.7
-
有可能存在存在概率为0的情况,这情况情况是需要避免,朴素贝叶斯中使用拉普拉斯平滑来解决这个问题,在原概率的基础之上,分子+1,分母+F1一共的种类数,比如F1是(生瓜、熟瓜),那么分母+2
符号 | 含义 |
---|---|
Ni | 在类别 C 中,特征 F1 取当前特定值的样本数量 |
N | 类别 C 的总样本数 |
α | 平滑系数(通常取 1,称为拉普拉斯平滑;若取其他值,称为 Lidstone 平滑) |
m | 特征 F1 的可能取值数(例如,若 F1 是"颜色",则 m 为颜色种类数) |
特性 | GaussianNB(高斯朴素贝叶斯) | MultinomialNB(多项式朴素贝叶斯) |
---|---|---|
数据分布假设 | 特征服从高斯分布(连续数据) | 特征服从多项式分布(离散计数数据) |
公式 | 基于概率密度函数(PDF) | 基于类别条件概率(频次统计) |
输入数据 | 连续数值(如温度、身高) | 离散计数(如单词出现次数、分类标签) |
平滑处理 | 无显式平滑(依赖数据分布估计) | 使用拉普拉斯平滑(避免零概率) |
适用场景 | 医学诊断、金融预测 | 文本分类、推荐系统 |
数据预处理 | 无需特殊处理(假设特征已正态分布) | 需将文本转换为词频/TF-IDF向量 |
零值处理 | 自动处理连续值 | 依赖拉普拉斯平滑解决零频问题 |
计算效率 | 较高(仅需计算均值和方差) | 较低(需存储大量离散计数) |
特征相关性 | 对非高斯分布特征敏感 | 对高维稀疏数据鲁棒性强 |
是否需要标准化 | 不需要(依赖原始数据的均值和方差,标准化会扭曲分布) | 不需要(输入应为离散计数,标准化会破坏数据特性) |
python
"""
朴素贝叶斯:假设特征之间独立的情况的一种贝叶斯算法
api:from sklearn.naive_bayes import GaussianNB
"""
import numpy as np
# 导入朴素贝叶斯
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
iris = load_iris()
data, target = iris.data, iris.target
print(data[:5])
X_train, X_test, y_train, y_test = train_test_split(data, target, test_size=0.2, random_state=42)
# 创建估计器
gnb = GaussianNB()
# fit
gnb.fit(X_train, y_train)
# 输出模型得分
print(gnb.score(X_test, y_test))
# 预测
predict_data = np.array([[4.7, 2.9, 2, 0.1]])
"""
predict:对应标签
predict_proba:每个标签的概率
"""
result = gnb.predict_proba(predict_data)
np.set_printoptions(suppress=True)
print(result)
十三、决策树
-
ID3 算法:基于信息熵和信息增益来判定所选择的节点
-
信息熵:用来描述数据集中数据的混乱程度,信息熵越高,数据越混乱,信息熵越低,数据越纯净
-
p(x_i)是数据中第 i 类取值的概率
-
信息增益
-
H(D):数据集 D 的初始信息熵(划分前的混乱程度)
-
H(D∣A):在特征 A 的条件下,D 的加权平均条件熵(划分后的混乱程度)
-
-
信息增益越大,说明特征 A 对分类的贡献越大
-
决策树算法(如ID3)会选择信息增益最大的特征作为当前节点的分裂标准
-
CART算法:
- 基尼指数
基尼指数越低,数据集越纯净
-
对于给定的数据集 D,其基尼指数定义为:其中P_k是类 K 在数据集 D 中的比例。如果数据集中只有一个类,那么𝐺𝑖𝑛𝑖(𝐷)=0
-
D:当前数据集
-
p_k:第 k 类样本的比例
-
- DecisionTreeClassifier
是 scikit-learn 库中的一个类,用于创建决策树分类器,
DecisionTreeClassifier()`用来创建决策树模型实例,参数如下:
参数名 | 类型 | 默认值 | 说明说明 |
---|---|---|---|
criterion |
str | "gini" |
衡量分裂质量的标准: - "gini" :使用基尼指数 - "entropy" :使用信息熵 |
max_depth |
int | None |
树的最大深度。如果为 None ,则节点会一直扩展,直到所有叶子都是纯净的,或直到所有叶子包含的样本数少于 min_samples_split 的值。 |
朴素贝叶斯实现葡萄酒分类
python
"""
决策树算法:就是基于树的数据结构思想,来做分类(回归)的一个算法,通过节点的特征信息,做出数据的类别的判定
在构建的决策树的过程中,我们可以采取信息增益、gini指数的方式来实现,对应ID3算法和CART算法
使用决策树算法实现判定titanic事故中,某个人是否可以存活
titanic数据集是一个csv文件,如果要获取其中的数据,pandas 读取
# 了解每一列数据是什么内容 --- 就是特征信息
plcass --- 座位的信息,1st 2ed 3rd
age --- 年龄,有的人年龄为空,我们就需要做数据集的处理,这里采取使用所有人的平均年龄作为填充
sex --- 性别,male 男性、female女性
# 标签
survived --- 是否存活,1存活,0死亡
"""
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV
import joblib
# 读取数据集
data = pd.read_csv("titanic.csv")
"""
fillna --- 填充空缺的数据内容,即没有值的地方,使用设置的值填充上去
获取age的平均值,mean()方法
"""
data['age'].fillna(value=data['age'].mean(), inplace=True)
"""
pandas 从 dataFrame 同时取出多个列,需要使用[[列名....]]
loc 方法也可以实现
"""
X = data[['pclass', 'age', 'sex']]
# X = data.loc[:, ['pclass', 'age', 'sex']]
# 把 X 转成 [{第一条数据},{第二条数据},{第三条数据}] --- dataFrame 转 dict
"""
to_dict 方法:把 dataFrame 转 dict,但是会发现,使用列名作为key,列对应的值做为value
orient='records':把每一行看作是一条数据,每一条数据就是一个以各自列名作为key,列值作为value的字典,放在一个列表中
"""
X = X.to_dict(orient='records')
y = data['survived']
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
# 由于数据集中存在字符,所以我们需要把字符转为机器可以识别的数字
dv = DictVectorizer(sparse=False)
# 提取训练集信息,进行数据转换
X_train = dv.fit_transform(X_train)
# 利用训练集的信息,直接执行数据转换
X_test = dv.transform(X_test)
print(X_train[:5])
print(dv.get_feature_names_out())
# 是否需要正则化?看具体情况,这里是不需要的
# 创建决策数据的估计器
"""
DecisionTreeClassifier 的参数:
criterion:默认gini,选择的算法,可以选择{"gini", "entropy"}
max_depth:最大的深度
random_state:随机数种子,设置了max_depth才生效
"""
dtc = DecisionTreeClassifier()
params_grid = {
"max_depth": [1, 2, 3]
}
# 使用网格搜索来设置 max_depth 值
gsc = GridSearchCV(estimator=dtc, param_grid=params_grid, cv=5)
# 投喂
gsc.fit(X_train, y_train)
# 得到最佳模型
print(gsc.best_estimator_)
print(gsc.score(X_test, y_test)) # 0.8297872340425532
# 保存模型
joblib.dump(gsc, "titanic.pkl")
十四、随机森林算法
-
随机森林算法使用很多个决策树来构建的
-
这些决策树是如何构建的?
-
一棵决策树:它是通过在数据集中(数据集大小为N),有放回的取出N个数据(一个一个的取,取出来的数据集中有重复的),所选择的特征也是随机的,并不是所有的特征信息,比如特征为k,那么选择的特征就是m<k,训练出来一个决策树
-
N 棵决策树:每一棵的构建方式和上一步一样,它们是并行的构建出来的
-
-
并行和串行:
-
并行:一起执行
-
串行:看上去像一起执行,但是他不是一起执行的,是一个一个的执行的
-
-
输出结果:
-
分类:就是统计每一棵树的结果,选择类别数量最大的那个
-
回归:所有树的平均值
-
-
猜想随机森林算法的API的超参数
-
树的数量
-
树的深度
-
生成树的算法
-
-
代码改动:把之前实现的titanic的决策树算法,改成随机森林算法【只需要把决策树的估计器换成随机森林的估计器,然后修改网格搜索的超参数设置】
-
sklearn.ensemble.RandomForestClassifier
是sklearn
库中用来构建随机森林的类,参数介绍如下
参数名 | 类型 | 默认值 | 含义说明 |
---|---|---|---|
n_estimators |
int |
100 |
森林中决策树的数量(即生成的决策树个数) |
criterion |
{"gini", "entropy"} |
"gini" |
衡量特征划分质量的标准: - "gini" :使用基尼不纯度 - "entropy" :使用信息增益 |
max_depth |
int |
None |
树的最大深度。如果为 None ,则节点会一直扩展直到叶子节点都是纯净的,或达到其他停止条件(如 `min_samples_split |
python
"""
随机森林算法:
思想:在数据集中,样本数为N,有放回的执行N次,取出N个数据,然后随机选择特征信息,用这两个数据训练出来多棵树
每棵树:样本数据内容、特征信息可能是不一样的,但是样本数据由于是有放回的取出,所以有一定重复
随机森林在构建的时候,就会构建多棵树,并行构建
输出:
回归:每一棵树输出结果的平均数
分类:统计每一棵数输出的类别信息,选择最多的那个最为结果
API:from sklearn.ensemble import RandomForestClassifier
参数设置:
n_estimators:构成随机森林的决策树的数量
criterion:决策树生成选择的算法
max_depth:决策树的深度
"""
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction import DictVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
import joblib
# 读取数据集
data = pd.read_csv("titanic.csv")
"""
fillna --- 填充空缺的数据内容,即没有值的地方,使用设置的值填充上去
获取age的平均值,mean()方法
"""
data['age'].fillna(value=data['age'].mean(), inplace=True)
"""
pandas 从 dataFrame 同时取出多个列,需要使用[[列名....]]
loc 方法也可以实现
"""
X = data[['pclass', 'age', 'sex']]
# X = data.loc[:, ['pclass', 'age', 'sex']]
# 把 X 转成 [{第一条数据},{第二条数据},{第三条数据}] --- dataFrame 转 dict
"""
to_dict 方法:把 dataFrame 转 dict,但是会发现,使用列名作为key,列对应的值做为value
orient='records':把每一行看作是一条数据,每一条数据就是一个以各自列名作为key,列值作为value的字典,放在一个列表中
"""
X = X.to_dict(orient='records')
y = data['survived']
# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)
# 由于数据集中存在字符,所以我们需要把字符转为机器可以识别的数字
dv = DictVectorizer(sparse=False)
# 提取训练集信息,进行数据转换
X_train = dv.fit_transform(X_train)
# 利用训练集的信息,直接执行数据转换
X_test = dv.transform(X_test)
print(X_train[:5])
print(dv.get_feature_names_out())
# 是否需要正则化?看具体情况,这里是不需要的
# 创建决策数据的估计器
rfc = RandomForestClassifier()
params_grid = {
"n_estimators": [10, 20, 30], # 构成随机森林的决策树的数量
"max_depth": [1, 2, 3], # 决策树的深度
}
# 使用网格搜索来设置随机森林超参数
gsc = GridSearchCV(estimator=rfc, param_grid=params_grid, cv=5)
# 投喂
gsc.fit(X_train, y_train)
# 得到最佳模型
print(gsc.best_estimator_)
print(gsc.score(X_test, y_test)) # 0.8358662613981763
# 保存模型
joblib.dump(gsc, "titanic_rfc.pkl")