KNN、决策树、随机森林..调参学习笔记

实例:Titanic生存率预测实例(通过sklearn实现Knn,决策树,线性回归)

import pandas as pd
from IPython.display import display
train = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')

# display(train) #可以查看一下数据,之后再注释掉
#查看缺失率 利用for循环
for column in train.columns:
    print("name:{0} miss rate:{1:.2f} ".format(column,1-train[column].count()/len(train)))
for column in test.columns:
    print("name:{0} miss rate:{1:.2f} ".format(column,1-test[column].count()/len(train)))
    
#去除不需要的字段和缺失率较大的字段
train,test= train.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin']),test.drop(columns=['PassengerId', 'Name', 'Ticket', 'Cabin'])


#填补空缺
#用Age平均值(也可以选取众数)填补空缺
train['Embarked'] = train['Embarked'].fillna('S')
test['Embarked'] = test['Embarked'].fillna('S')
train['Age'] = train['Age'].fillna(int(train['Age'].mean()))
test['Age'] = test['Age'].fillna(int(test['Age'].mean()))
test['Fare'] = test['Fare'].fillna(float(test['Fare'].dropna().mode()[0]))#这里注意众数不唯一因此得到的是一个列表,我们用到第一个元素便可

#将一些字符串转化为数字表示
train.loc[train["Sex"]=="male","Sex"] = 0; 
train.loc[train["Sex"]=="female","Sex"] = 1;
train.loc[train["Embarked"]=="S","Embarked"] = 0; 
train.loc[train["Embarked"]=="C","Embarked"] = 1;
train.loc[train["Embarked"]=="Q","Embarked"] = 2;
test.loc[test["Sex"]=="male","Sex"] = 0; 
test.loc[test["Sex"]=="female","Sex"] = 1;
test.loc[test["Embarked"]=="S","Embarked"] = 0; 
test.loc[test["Embarked"]=="C","Embarked"] = 1;
test.loc[test["Embarked"]=="Q","Embarked"] = 2;


#构建数据集
result=pd.read_csv('gender_submission.csv')#这里加载数据集
X_train,y_train=train.drop(columns=['Survived']),train['Survived']
X_test=test
y_test=result.drop(columns=['PassengerId'])
print('OK')
#构建模型,这里构建三种knn、决策树、线性回归

#填入knn模型
print("knn:")
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=5)
knn.fit(X_train, y_train)
y_predict = knn.predict(X_test)
print('train score: {:.2f}'.format(knn.score(X_train, y_train)))
print('test score: {:.2f}'.format(knn.score(X_test,y_test)))


# 使用决策树分类器模型
print("决策树:")
from sklearn.tree import DecisionTreeClassifier #回归树 
dtc = DecisionTreeClassifier()
dtc.fit(X_train, y_train)
y_predict = dtc.predict(X_test)
from sklearn.metrics import classification_report
print('train  score: {:.2f}'.format(dtc.score(X_train, y_train)))
print('test  score: {:.2f}'.format(dtc.score(X_test, y_test)))

#线性回归
print("线性回归:")
from sklearn.linear_model import LinearRegression
lr=LinearRegression()
lr.fit(X_train,y_train)
Predict =lr.predict(X_test)
print('train  score: {:.2f}'.format(lr.score(X_train, y_train)))
print('test  score: {:.2f}'.format(lr.score(X_test, y_test)))

决策树

from sklearn import tree
from sklearn.datasets import load_wine #数据
from sklearn.model_selection import train_test_split #用于将数据集划分为训练集和测试集

wine=load_wine() #导入数据
wine.data #特征
wine.target #标签
wine.feature_names

import pandas as pd
pd.concat([pd.DataFrame(wine.data),pd.DataFrame(wine.target)],axis=1) #将特征和标签拼接起来	

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5PmLGaqv-1663578437705)(D:\Doc\TyporaPic\image-20220916195428978.png)]

#分训练集和测试集
X_train,X_test,Y_train,Y_test=train_test_split(wine.data,wine.target,test_size=0.3) #数据集的30%是测试集,70%是训练集


#建模
clf = tree.DecisionTreeClassifier() #实例化
clf = clf.fit(X_train,Y_train) #训练
score = clf.score(X_test,Y_test) #测试
score #测试的准确率

#重要的接口 fit\score\feature_importances_
#特征重要性!
clf.feature_importances_  #数值越大,证明该特征对结果的影响越大
[*zip(wine.feature_names,clf.feature_importances_)] #将特征名称和数值拼接在一起
#load_wine数据集中的特征及重要性
'''
[('alcohol', 0.0),
 ('malic_acid', 0.0),
 ('ash', 0.0),
 ('alcalinity_of_ash', 0.0),
 ('magnesium', 0.0),
 ('total_phenols', 0.012226385328337608),
 ('flavanoids', 0.10361861565766123),
 ('nonflavanoid_phenols', 0.0),
 ('proanthocyanins', 0.0),
 ('color_intensity', 0.0),
 ('hue', 0.08442027964804541),
 ('od280/od315_of_diluted_wines', 0.3298354996677837),
 ('proline', 0.4698992196981721)]'''

#random_state参数
#决策树本身是带有随机性的,会随机的挑选特征,
#random_state参数就可以避免随机性
#splitter = "best" 参数也是为了避免随机性,会默认选择最好的特征
#以上两个参数都是为了避免模型过拟合,一般情况下都要进行一定的设置
clf = tree.DecisionTreeClassifier(random_state=30,splitter="best") #实例化
clf = clf.fit(X_train,Y_train) #训练
score = clf.score(X_test,Y_test) #测试
score

随机森林

#随机森林是一种——Bagging集成算法
#RandomForestClassifier
#参数
#n_estimators :随机森林中树的数量,即基评估器的数量。往往越大,训练效果越好,但是也要在内存和性能之间取一个折中的数

#导包
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import load_wine
from sklearn.model_selection import train_test_split
#构建数据据
wine=load_wine()
Xtrain,Xtest,Ytrain,Ytest = train_test_split(wine.data,wine.target,test_size=0.3)
clf = DecisionTreeClassifier(random_state=0)
rfc = RandomForestClassifier(random_state=0)

clf= clf.fit(Xtrain,Ytrain)
rfc= rfc.fit(Xtrain,Ytrain)

score_c=clf.score(Xtest,Ytest)
score_r=rfc.score(Xtest,Ytest)
print("single Tree:{}".format(score_c))
print("random forest:{}".format(score_r))

决策树/随机森林—调参–实现最小泛化误差

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-atPPxmyq-1663578437706)(D:\Doc\TyporaPic\image-20220916194702364.png)]

1、模型太复杂或者太简单,都会提高泛化误差

2、模型太复杂,会导致过拟合,太简单导致欠拟合

3、对与树模型或树的集成模型来说,树的深度越深,枝叶越多,模型越复杂

4、树模型和树的集成模型的调参目标,都是减少模型的复杂度,把模型往上图的左边移动,尽可能找到泛化误差的最低点

以下室随机森林参数对模型的影响程度

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ghqQ3UGy-1663578437706)(D:\Doc\TyporaPic\image-20220916194635277.png)]

实例:随机森林在乳腺癌数据上的调参

from sklearn.ensemble import RandomForestClassifier  #随机森林分类器
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import GridSearchCV #网格搜索---自动调参
from sklearn.model_selection import cross_val_score #交叉验证--用于调参
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

data = load_breast_cancer()

#建模
rfc = RandomForestClassifier(n_estimators=100,random_state=90) #建100课树的随机森林,random_state的值随意
score_pred = cross_val_score(rfc,data.data,data.target,cv=10).mean() #进行10次交叉验证,10次结果求均值
score_pred
0.9648809523809524
#第一步:调n_estimators
#使用学习曲线,可以很清晰的看到随着n_estimators的增加,整体准确率的变化
scorel=[]
for i in range(0,200,10): #10个10个增加
    rfc = RandomForestClassifier(n_estimators=i+1
                                ,n_jobs=-1  ##n_jobs:用来设定CPU运行情况,n_jobs=-1便是使用全部的CPU。一般不需要设定
										##使用默认值即可
                                ,random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
print(max(scorel),(scorel.index(max(scorel))*10)+1)#找出score最大值对应的index,再*10+1得到最佳n-estimator的数量
plt.figure(figsize=[20,5])
plt.plot(range(1,201,10),scorel)
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wvAmk9KO-1663578437706)(D:\Doc\TyporaPic\image-20220917085254624.png)]

#通过第一次调参确定一个n_estimators的一个峰值数为71
#再继续,缩小范围缩小为(65,75)进行,一个一个的遍历,找到一个更加精确的值
scorel=[]
for i in range(65,75):
    rfc = RandomForestClassifier(n_estimators=i
                                ,n_jobs=-1
                                ,random_state=90)
    score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
    scorel.append(score)
print(max(scorel),([*range(65,75)][scorel.index(max(scorel))]))
plt.figure(figsize=[20,5])
plt.plot(range(65,75),scorel)
plt.show()
##结果为73

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fLrHUd0Z-1663578437707)(D:\Doc\TyporaPic\image-20220917085816334.png)]

可以发现,准确率提升了一些,并且得到最终的最优 n_estimators的值为73

#选定n_estimators=73
#第二步:使用网格搜索,调max_depth
param_grid = {'max_depth':np.arange(1,30,1)}
'''
	调max_depth是把模型变得简单
	根据数据的大小进行一个试探,数据量级小的话,一般采用1-10,或者1-20
	但是对与比较大的数据集,可以直接尝试从30-50,40-60的深度
	有条件的话(配置够牛逼)可以画出学习曲线来观察深度对模型的影响
'''
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
#{'max_depth': 8}
GS.best_score_
#0.9666353383458647  准确率没有提升

尝试增大为(9,30),准确率会下降,说明对max_depth的调参可以告一段落。剩余的参数能够影响模型复杂度的就是max_features和min_sample_leaf

先调一下min_samples_leaf,理论上是没有用的

#调整min_samples_leaf
param_grid = {'min_samples_leaf':np.arange(1,1+20,1)}
""" 
    对于min_samples_split和min_samples_leaf,一般是从他们的最小值开始向上增加10或20 
    面对高维度高样本量数据,如果不放心,也可以直接+50,对于大型数据,可能需要200~300的范围 
    调整的时候发现准确无论如何都上不来,那可以放心大胆调一个很大的数据,大力限制模型的复杂度 
"""
rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
#{'min_samples_leaf': 1}
GS.best_score_
#0.9666353383458647  验证了确实无效

接下来

#调max_features
param_grid = {'max_features':np.arange(5,30,1)}
"""
	max_features,该参数既可以使模型变复杂,也可以变简单
	默认最小值是sqrt(n_features),因此我们要用这个值作为调参的范围的最小值
"""

rfc = RandomForestClassifier(n_estimators=73
                            ,random_state=90)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
#{'max_features': 24}
GS.best_score_
#0.9666666666666668   #准确率有所提升

多次尝试调整max_features的变化区间,可以发现能找到一个值最终为24,在24的左右区间内,调参后的准确率都会降低,所以24就是最优值

#最后再尝试调一下criterion
param_grid = {'criterion':['gini', 'entropy']}	 

rfc = RandomForestClassifier(n_estimators=73
                             ,n_jobs=-1
                            ,random_state=90
                            ,max_features = 24)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)
GS.best_params_
#{'criterion': 'gini'}
GS.best_score_
#0.9666666666666668   #准确率没有发生变化

到此,能调整的参数就都调整完了,调参也就这样了,总结出模型的最佳参数

rfc = RandomForestClassifier(n_estimators=73,random_state=90,max_depth=8, max_features=24, n_jobs=-1)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score  # 0.9666666666666668

完结!
fier(n_estimators=73
,n_jobs=-1
,random_state=90
,max_features = 24)
GS = GridSearchCV(rfc,param_grid,cv=10)
GS.fit(data.data,data.target)


```python
GS.best_params_
#{'criterion': 'gini'}
GS.best_score_
#0.9666666666666668   #准确率没有发生变化

到此,能调整的参数就都调整完了,调参也就这样了,总结出模型的最佳参数

rfc = RandomForestClassifier(n_estimators=73,random_state=90,max_depth=8, max_features=24, n_jobs=-1)
score = cross_val_score(rfc,data.data,data.target,cv=10).mean()
score  # 0.9666666666666668

完结!

你可能感兴趣的:(决策树,随机森林,机器学习)