Bootstrap

机器学习阶段学习Day31

KNN分类算法

KNN算法原理

根据K个邻居样本来判断当前样本属于哪个类别:K个最相似邻居中大多数所属类别即为当前样本的类别。但是对于数据量巨大或者高纬度的数据样本不太合适,数据量大的数据样本需要进行大量计算,而高纬度数据计算距离不具重要意义。

在这里插入图片描述
在这里插入图片描述

# knn算法
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
import numpy as np
import joblib

iris = load_iris()
x,y = iris.data,iris.target
# print(x)
# print(y)


#划分数据集
x_train ,x_test, y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=40)
#初始化标准化器
stander = StandardScaler()
#对x进行标准化处理
x_stand = stander.fit_transform(x_train)
#创建knn工具
estimater = KNeighborsClassifier(n_neighbors=7)
#训练
estimater.fit(x_stand,y_train)


#预测
y_predict = estimater.predict(x_test)
print('x_test:\n',x_test)
print('y_targer_names:\n',iris.target_names)
print('y_predict:\n',y_predict)
print('y_test:\n',y_test)
#评估1
res = y_predict == y_test
print(res)
score = np.sum(res)/len(res)
print(score)


#评估2
score1 = estimater.score(x_test,y_test)
print(score1)

#模型保存和加载
joblib.dump(estimater,'./mod/knn_iris.pkl')

# #推理(预测)
# x_new = [[5.1,3.5,1.4,0.2],
#          [2.1,1.5,4.4,0.2],
#          [5.1,5.5,1.4,5.2],
#          [1.1,2.3,1.4,3.2]]
# x_new_stand = stander.transform(x_new)
# print(x_new_stand)
# y_detect = estimater.predict(x_new_stand)
# print('推理结果:',y_detect)
# print('种类:',iris.target_names[y_detect])

模型选择和调优

1.保留交叉验证

Train-Test-Split:将数据随机分到训练集和测试集中,可以自定义训练集和测试集的占比大小。对于某些特殊的数据集,可能造成同一类数据全部出现在训练集中,而其他类数据没有一个数据流入训练集,这样会造成模型训练失败(只能识别一种类型的数据)。

2.K-折交叉验证

K-Fold:将整个数据集分割成大小相同的K份,选择一个Fold用作训练,其余所有Fold用于测试。重复K次,直至每个Fold都被训练和验证过。模型的最终准确度是通过取k个模型验证数据的平均准确度来计算的。
在这里插入图片描述

3.分层K-折交叉验证

Stratified k-fold cross validation:对每个Fold进行分层训练和验证,假设原始数据有3类,占比为1:2:1,那么在每个Fold中也保证三类数据的占比为1:2:1。

在这里插入图片描述

from sklearn.model_selection import StratifiedKFold
from sklearn.datasets import load_iris
from sklearn.neighbors import KNeighborsClassifier
import numpy as np
x,y = iris  = load_iris(return_X_y=True)
folder = StratifiedKFold(n_splits=5,shuffle=True,random_state=666)
iter = folder.split(x,y)
knn = KNeighborsClassifier(n_neighbors=7)
score_arr = []
for train_index , test_index in iter:
    print(train_index,test_index,'-----------------')
    model = knn.fit(x[train_index],y[train_index])
    s = model.score(x[test_index],y[test_index])
    score_arr.append(s)
print(score_arr)
print('平均准确率:',np.sum(score_arr)/(len(score_arr)))

4.超参搜索

Grid Searc:在KNN算法中,可以将n_neighbors作为可调参数传入,由Grid Search(网格搜索)验证并找出最优超参数值。

# 超参数的选择(网格搜素)
from sklearn.model_selection import GridSearchCV
from sklearn.neighbors import KNeighborsClassifier
from sklearn.datasets import load_iris

model = KNeighborsClassifier()
model = GridSearchCV(estimator=model,param_grid={'n_neighbors':[1,3,5,7,9]})
x,y = load_iris(return_X_y=True)
model.fit(x,y)

# best_params_  最佳参数
# best_score_ 在训练集中的准确率
# best_estimator_ 最佳估计器
# cv_results_ 交叉验证过程描述
# best_index_最佳k在列表中的下标
print(model.best_params_)
print(model.best_score_)
print(model.best_estimator_)
# model.best_estimator_.predict() 
print(model.cv_results_)
print(model.best_index_)

贝叶斯分类

1.理论

在这里插入图片描述
红色和蓝色分别表示两种事件的概率p1(x,y)和p2(x,y),当出现一个新数据点(x,y):
当p1(x,y)>p2(x,y),新数据点的类别为1;
当p1(x,y)<p2(x,y),新数据点的类别为2。

2.条件概率

在这里插入图片描述
在事件B发生的情况下,事件A发生的概率就是P(A∩B)除以P(B)。
𝑃(𝐴|𝐵)=𝑃(𝐴∩𝐵)/𝑃(𝐵)→𝑃(𝐴∩𝐵)=𝑃(𝐴|𝐵)𝑃(𝐵)
同理:
𝑃(𝐴∩𝐵)=𝑃(𝐵|𝐴)𝑃(𝐴)
故条件概率的计算公式为
𝑃(𝐴|𝐵)=𝑃(B|A)𝑃(𝐴)/𝑃(𝐵)

3.全概率公式

在这里插入图片描述
𝑃(𝐵)=𝑃(𝐵∩𝐴)+𝑃(𝐵∩𝐴′)
∵𝑃(𝐵∩𝐴)=𝑃(𝐵|𝐴)𝑃(𝐴)
∴𝑃(𝐵)=𝑃(𝐵|𝐴)𝑃(𝐴)+𝑃(𝐵|𝐴′)𝑃(𝐴′)
全概率公式为
P ( A ∣ B ) = P ( B ∣ A ) P ( A ) P ( B ∣ A ) P ( A ) + P ( B ∣ A , ) P ( A , ) P(A|B)=\frac{P(B|A)P(A)}{P(B|A)P(A)+P(B|A^,)P(A^,)} P(AB)=P(BA)P(A)+P(BA,)P(A,)P(BA)P(A)

纹理色泽鼔声类别
1清晰清绿清脆好瓜
2模糊乌黑浊响坏瓜
3模糊清绿浊响坏瓜
4清晰乌黑沉闷好瓜
5清晰清绿浊响好瓜
6模糊乌黑沉闷坏瓜
7清晰乌黑清脆好瓜
8模糊清绿沉闷好瓜
9清晰乌黑浊响坏瓜
10模糊清绿清脆好瓜
11清晰清绿沉闷
12模糊乌黑浊响?
示例:
p(a|X) = p(X|a)* p(a)/p(X)
p(X|a) = p(x1,x2,x3...xn|a) = p(x1|a)*p(x2|a)*p(x3|a)...p(xn|a)
p(X) = p(x1,x2,x3...xn) = p(x1)*p(x2)*p(x3)...p(xn)
p(a|X) = p(x1|a)*p(x2|a)*p(x3|a)...p(xn|a) * p(a) / p(x1)*p(x2)*p(x3)...p(xn)

P(好瓜)=(好瓜数量)/所有瓜
P(坏瓜)=(坏瓜数量)/所有瓜
p(纹理清晰)=(纹理清晰数量)/所有瓜
p(纹理清晰|好瓜)= 好瓜中纹理清晰数量/好瓜数量
p(纹理清晰|坏瓜)= 坏瓜中纹理清晰数量/坏瓜数量

p(好瓜|纹理清晰,色泽清绿,鼓声沉闷)
	=【p(好瓜)】*【p(纹理清晰,色泽清绿,鼓声沉闷|好瓜)】/【p(纹理清晰,色泽清绿,鼓声沉闷)】
	=【p(好瓜)】*【p(纹理清晰|好瓜)*p(色泽清绿|好瓜)*p(鼓声沉闷|好瓜)】/【p(纹理清晰)*p(色泽清绿)*p(鼓声沉闷)】

p(坏瓜|纹理清晰,色泽清绿,鼓声沉闷)
	=【p(坏瓜)*p(纹理清晰|坏瓜)*p(色泽清绿|坏瓜)*p(鼓声沉闷|坏瓜)】/【p(纹理清晰)*p(色泽清绿)*p(鼓声沉闷)】

从公式中判断"p(好瓜|纹理清晰,色泽清绿,鼓声沉闷)"和"p(坏瓜|纹理清晰,色泽清绿,鼓声沉闷)"时,因为它们的分母
值是相同的,[值都是p(纹理清晰)*p(色泽清绿)*p(鼓声沉闷)],所以只要计算它们的分子就可以判断是"好瓜"还是"坏瓜"之间谁大谁小了,所以没有必要计算分母
p(好瓜) = 6/10
p(坏瓜)=4/10
p(纹理清晰|好瓜) = 4/6 
p(色泽清绿|好瓜) = 4/6
p(鼓声沉闷|好瓜) = 2/6
p(纹理清晰|坏瓜) = 1/4 
p(色泽清绿|坏瓜) = 1/4
p(鼓声沉闷|坏瓜) = 1/4
把以上计算代入公式的分子
p(好瓜)*p(纹理清晰|好瓜)*p(色泽清绿|好瓜)*p(鼓声沉闷|好瓜) = 4/45
p(坏瓜)*p(纹理清晰|坏瓜)*p(色泽清绿|坏瓜)*p(鼓声沉闷|坏瓜) = 1/160
所以
p(好瓜|纹理清晰,色泽清绿,鼓声沉闷) >  p(坏瓜|纹理清晰,色泽清绿,鼓声沉闷),
所以把(纹理清晰,色泽清绿,鼓声沉闷)的样本归类为好瓜

4.拉普拉斯平滑系数

为避免事件未出现的情况而导致的概率被估计为0,可以使用拉普拉斯平滑系数规避。
在这里插入图片描述
α通常取1,m为总特征数量

p(好瓜|纹理清晰,色泽淡白,鼓声沉闷)
	=【p(好瓜)】*【p(纹理清晰|好瓜)*p(色泽淡白|好瓜)*p(鼓声沉闷|好瓜)】/【p(纹理清晰)*p(色泽淡白)*p(鼓声沉闷)】
p(坏瓜|纹理清晰,色泽淡白,鼓声沉闷)
	=【p(坏瓜)】*【p(纹理清晰|坏瓜)*p(色泽淡白|坏瓜)*p(鼓声沉闷|坏瓜)】/【p(纹理清晰)*p(色泽淡白)*p(鼓声沉闷)】   
p(纹理清晰|好瓜)= (4+1)/(6+3)  # +1是因为防止零概率 +3是因为有3个特征(纹理,色泽,鼓声)
p(色泽淡白|好瓜)= (0+1)/(6+3)  
p(鼓声沉闷|好瓜) = (2+1)/(6+3) 
p(纹理清晰|坏瓜)= (1+1)/(4+3)   
p(色泽淡白|坏瓜)= (0+1)/(4+3)  
p(鼓声沉闷|坏瓜) = (1+1)/(4+3)  
from sklearn.datasets import  load_iris
from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
import joblib
#实例化贝叶斯分类器
model = MultinomialNB()
# 加载鸢尾花数据集
x,y = load_iris(return_X_y=True)
# 划分数据集
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.8,random_state=666)
# 训练
model.fit(x_train,y_train)
# 评估
score = model.score(x_test,y_test)
print(score)
# 保存
joblib.dump(model,'mod/bys.bin')

import joblib
model1 = joblib.load('mod/bys.bin')
y_predect = model1.predict([[1,2,3,4]])
print(y_predect)

决策树分类

1.概念

1、决策节点
通过条件判断而进行分支选择的节点。如:将某个样本中的属性值(特征值)与决策节点上的值进行比较,从而判断它的流向。

2、叶子节点
没有子节点的节点,表示最终的决策结果。

3、决策树的深度
所有节点的最大层次数。

决策树具有一定的层次结构,根节点的层次数定为0,从下面开始每一层子节点层次数增加

4、决策树优点:

​ 可视化 - 可解释能力-对算力要求低

5、 决策树缺点:

​ 容易产生过拟合,所以不要把深度调整太大了。

2.基于基尼指数决策树的建立

基尼指数(Gini Index)是决策树算法中用于评估数据集纯度的一种度量,基尼指数衡量的是数据集的不纯度,或者说分类的不确定性。在构建决策树时,基尼指数被用来决定如何对数据集进行最优划分,以减少不纯度。

基尼指数的计算

对于一个二分类问题,如果一个节点包含的样本属于正类的概率是 §,则属于负类的概率是 (1-p)。那么,这个节点的基尼指数 (Gini§) 定义为:

G i n i ( p ) = 1 − p 2 − ( 1 − p ) 2 = 2 p ( 1 − p ) Gini(p) = 1 - p^2 - (1-p)^2 = 2p(1-p) Gini(p)=1p2(1p)2=2p(1p)

对于多分类问题,如果一个节点包含的样本属于第 k 类的概率是 p k p_k pk,则节点的基尼指数定义为:

G i n i ( p ) = 1 − ∑ k = 1 K p k 2 Gini(p) = 1 - \sum_{k=1}^{K} p_k^2 Gini(p)=1k=1Kpk2

基尼指数的意义

  • 当一个节点的所有样本都属于同一类别时,基尼指数为 0,表示纯度最高。
  • 当一个节点的样本均匀分布在所有类别时,基尼指数最大,表示纯度最低。

决策树中的应用

在构建决策树时,我们希望每个内部节点的子节点能更纯,即基尼指数更小。因此,选择分割特征和分割点的目标是使子节点的平均基尼指数最小化。具体来说,对于一个特征,我们计算其所有可能的分割点对应的子节点的加权平均基尼指数,然后选择最小化这个值的分割点。这个过程会在所有特征中重复,直到找到最佳的分割特征和分割点。

例如,考虑一个数据集 (D),其中包含 (N) 个样本,特征 (A) 将数据集分割为 ∣ D 1 ∣ |D_1| D1 ∣ D 2 ∣ |D_2| D2 ,则特征 (A) 的基尼指数为:

G i n i A = ∣ D 1 ∣ ∣ D ∣ G i n i ( D 1 ) + ∣ D 2 ∣ ∣ D ∣ G i n i ( D 2 ) Gini_A = \frac{|D_1|}{|D|} Gini(D_1) + \frac{|D_2|}{|D|} Gini(D_2) GiniA=DD1Gini(D1)+DD2Gini(D2)

其中 ∣ D 1 ∣ |D_1| D1 ∣ D 2 ∣ |D_2| D2 分别是子集 D 1 D_1 D1 D 2 D_2 D2 中的样本数量。

通过这样的方式,决策树算法逐步构建一棵树,每一层的节点都尽可能地减少基尼指数,最终达到对数据集的有效分类。

from sklearn.tree import DecisionTreeClassifier,export_graphviz
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler


model = DecisionTreeClassifier(criterion='entropy')#entroopy信息熵的方式构建决策树,默认gini构建决策树
x,y = load_iris(return_X_y=True)
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.25)
scaler = StandardScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
model.fit(x_train,y_train)
x_test = scaler.transform(x_test)
rank = model.score(x_test,y_test)
print(rank)
y_predict = model.predict([[1,2,3,6],[2,5,1,3]])
print(y_predict)


# 决策过程可视化
export_graphviz(model,out_file='jueceshu/tree.dot',feature_names=['sepal length', 'sepal width', 'petal length', 'petal width'])
import pydotplus
from IPython.display import Image

# 读取 .dot 文件内容
dot_file_path = 'jueceshu/tree1.dot'
with open(dot_file_path, 'r') as f:
    dot_data = f.read()

# 使用 pydotplus 将 .dot 文件内容转换为 PNG 图片
png_file_path = 'jueceshu/tree1.png'
graph = pydotplus.graph_from_dot_data(dot_data)
if graph is not None:
    graph.write_png(png_file_path)
    # 显示图片
    Image(graph.create_png())
else:
    print("Failed to create graph from dot data.")

随机森林

机器学习中有一种大类叫集成学习(Ensemble Learning),集成学习的基本思想就是将多个分类器组合,从而实现一个预测效果更好的集成分类器。集成算法可以说从一方面验证了中国的一句老话:三个臭皮匠,赛过诸葛亮。集成算法大致可以分为:Bagging,Boosting 和 Stacking 三大类型。

(1)每次有放回地从训练集中取出 n 个训练样本,组成新的训练集;

(2)利用新的训练集,训练得到M个子模型;

(3)对于分类问题,采用投票的方法,得票最多子模型的分类类别为最终的类别;

随机森林就属于集成学习,是通过构建一个包含多个决策树(通常称为基学习器或弱学习器)的森林,每棵树都在不同的数据子集和特征子集上进行训练,最终通过投票或平均预测结果来产生更准确和稳健的预测。这种方法不仅提高了预测精度,也降低了过拟合风险,并且能够处理高维度和大规模数据集

1.算法原理

在这里插入图片描述

  • 随机: 特征随机,训练集随机
    • 样本:对于一个总体训练集T,T中共有N个样本,每次有放回地随机选择n个样本。用这n个样本来训练一个决策树。
    • 特征:假设训练集的特征个数为d,每次仅选择k(k<d)个来构建决策树。
  • 森林: 多个决策树分类器构成的分类器, 因为随机,所以可以生成多个决策树
  • 处理具有高维特征的输入样本,而且不需要降维
  • 使用平均或者投票来提高预测精度和控制过拟合

在这里插入图片描述

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.feature_extraction import DictVectorizer
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

data = pd.read_csv('src/titanic/titanic.csv')
print(data)
data['age'].fillna(data['age'].mode()[0],inplace = True)
y = data[['survived']].to_numpy()
# print(y)
data.drop(['survived'],axis = 1,inplace = True)
# print(data.tail())
x = data[['age','sex','pclass']]
dict1 = data.to_dict(orient='records')
# dict1
vec = DictVectorizer(sparse=False)
x = vec.fit_transform(dict1)
# print(x)
# print(y)

#数据划分
x_train,x_test,y_train,y_test = train_test_split(x,y,train_size=0.25,random_state=666)
# 标准化
scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)
# 训练模型
model = RandomForestClassifier(n_estimators=100 ,max_depth=8,criterion='gini')
model.fit(x_train,y_train)
# 模型评估
x_test = scaler.transform(x_test)
rank = model.score(x_test,y_test)
print(rank)
;