1. sklearn 實(shí)現(xiàn)決策樹
1.1 語法與參數(shù)
class sklearn.tree.DecisionTreeClassifier(criterion='gini', splitter='best', max_depth=None, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_features=None, random_state=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, class_weight=None, presort='deprecated', ccp_alpha=0.0)
參數(shù)說明:
- criterion: 不純度計(jì)算指標(biāo) {“gini”, “entropy”},
- splitter: {“best”, “random”}, default=”best” 節(jié)點(diǎn)切分方法,默認(rèn)是選擇最優(yōu)特征進(jìn)行切分.
- max_depth: 樹能達(dá)到的最大深度,防止模型太深,控制模型復(fù)雜度
- min_samples_split: int or float, default=2 抑制模型分裂
一個節(jié)點(diǎn)想要向下進(jìn)行切分,當(dāng)前樣本個數(shù)必須要大于這個參數(shù)值.
例如設(shè)置為10,當(dāng)這個節(jié)點(diǎn)中如果有9個樣本,則這個節(jié)點(diǎn)只能作為葉節(jié)點(diǎn).
- min_samples_leaf: int or float, default=1 抑制模型分裂
最小葉節(jié)點(diǎn)樣本個數(shù),如果上層節(jié)點(diǎn)分裂之后,分裂出來后的葉節(jié)點(diǎn)當(dāng)中樣本個數(shù)不足這兒參數(shù)值,則本次分裂不能進(jìn)行.
- max_features : int, float or {“auto”, “sqrt”, “l(fā)og2”}, default=None
最大特征,在尋找最優(yōu)分裂點(diǎn)的時(shí)候,要考慮的特征個數(shù)
If int, 考慮特征個數(shù),舉例有100個特征, 填寫20,就是每次分裂的時(shí)候,只計(jì)算20個特征.
If float, 百分比 0-1的浮點(diǎn)數(shù). 100個特征, 填寫0.3,那就是計(jì)算30個特征.
If “auto”, then max_features=sqrt(n_features). 根號個特征.100個特征就是計(jì)算10個特征
If “sqrt”, then max_features=sqrt(n_features). 同上
If “l(fā)og2”, then max_features=log2(n_features). 計(jì)算log2個特征,64個特征,6個.
If None, then max_features=n_features. 所有特征
- random_state: 隨機(jī)數(shù)種子
- max_leaf_nodes: 抑制模型分裂恬涧,最大葉節(jié)點(diǎn)個數(shù),最多能夠分裂出多少個葉節(jié)點(diǎn).
- min_impurity_decrease: 分裂中的最小不純度下降的值.
如果一次分裂過程中,Gain的下降不能超過這個值,那么就不能進(jìn)行本次分裂.
- class_weight: 類別權(quán)重設(shè)置,(類別不均衡數(shù)據(jù)集的問題)
屬性:
- classes_ : 分類標(biāo)簽,沒用
- feature_importances_: 特征重要性.
方法:
- get_depth(self) : 樹的深度
- get_n_leaves(self): 葉節(jié)點(diǎn)的個數(shù)
2. 泰坦尼克數(shù)據(jù)集應(yīng)用決策樹
導(dǎo)包 --> 導(dǎo)入數(shù)據(jù) --> 數(shù)據(jù)探索 --> 數(shù)據(jù)預(yù)處理 --> 切分X,y --> 構(gòu)建模型 --> 評價(jià)
2.1 讀入數(shù)據(jù)
import pandas as pd
import numpy as np
import matplotlib.pylab as plt
train = pd.read_csv('titanic/train.csv')
test = pd.read_csv('titanic/test.csv')
answer = pd.read_csv('titanic/gender_submission.csv')
- PassengerId: 乘客ID,沒用
- Pclass: 票等級
- Name: 姓名,沒用
- Sex: 性別
- Age: 年齡
- SibSp: 乘客同在船上的兄弟姐妹/配偶的個數(shù)(整數(shù)值)
- Parch:乘客同在船上的乘客父母/孩子的個數(shù)(整數(shù)值)
- Ticket:票號(字符串) 沒用
- Fare:乘客所持票的價(jià)格(浮點(diǎn)數(shù),0-500不等)
- Cabin:乘客所在船艙(有缺失)
-
Embark:乘客登船港口:S席噩、C模捂、Q(有缺失)
2.2 數(shù)據(jù)探索
# 各個客艙人數(shù)
train['Pclass'].value_counts()
# 各類票價(jià)均值
train.groupby(by = 'Pclass').mean()['Fare']
# 性別比例
train['Sex'].value_counts()
plt.style.use('seaborn') # 改變繪圖風(fēng)格
# Series里面有封裝自帶的畫圖功能
train.Sex.value_counts().plot(kind='barh')
# 男女獲救比例
train.groupby('Sex').mean()
# 年齡分布
train['Age'].plot(kind = 'hist')
# 將年齡離散化然后看獲救比例(10歲一級)
age_cut = pd.cut(train['Age'],bins = [0,10,20,30,40,50,60,70,80])
train['age_cut'] = age_cut
# 存活下來的Survived標(biāo)簽都是1捶朵,所以直接分類累加聚合就是比例蜘矢,0累加還是0
print("平均生存率: {:.3f}\n".format(train['Survived'].mean()))
print("各倉位等級存活率:\n{}\n".format(train.groupby(by = 'Pclass')['Survived'].mean()))
print("各年齡段生存率如下: \n{}".format(train.groupby(by = 'age_cut').mean()['Survived']))
# 構(gòu)造函數(shù),查看所有特征與生存率
def survive(feature):
#return train.groupby(by=feature).mean()['Survived']
Survived = train.groupby(by = feature)['Survived'].mean()
print(feature + "存活率:\n{}".format(Survived))
Survived.plot(kind = 'pie')
plt.show()
print('-'*40)
for i in ['Pclass','Sex','SibSp','Parch','Embarked']:
survive(i)
2.3 數(shù)據(jù)預(yù)處理
刪除無效特征
填充空值
特征編碼
2.3.1 刪除無效特征
# inplace = True 直接在原表改泉孩,省去賦值
train.drop(columns=['PassengerId','Name','Cabin','Ticket'],inplace=True)
train.pop('age_cut') # 直接刪
test.drop(columns=['PassengerId','Name','Cabin','Ticket'],inplace=True)
2.3.2 填充空值
train.info()
# 將年齡空值填充中位數(shù)
train.Age.fillna(train.Age.median(),inplace=True)
# 登錄港口空值填充眾數(shù)
train.Embarked.fillna('S',inplace=True)
# 測試集填充硼端,測試集也用訓(xùn)練集數(shù)據(jù)填充,參考KNN歸一化
test.Age.fillna(28,inplace=True)
test.Embarked.fillna('S',inplace=True)
2.3.3 特征編碼
# 對性別進(jìn)行編碼 0:男 1:女
train['Sex'] = (train.Sex == 'female').astype('int')
# 對倉位進(jìn)行編碼
train['Embarked'] = train.Embarked.map({'S':0,'C':1,'Q':2})
test['Sex'] = (test.Sex == 'female').astype('int')
# 對倉位進(jìn)行編碼
test['Embarked'] = test.Embarked.map({'S':0,'C':1,'Q':2})
test.Fare.fillna(train.Fare.mean(),inplace=True)
2.4 拆分X寓搬,y
train_y = train.pop('Survived')
train_X = train.copy() #拷貝
test_X = test.copy()# 提取X
test_y = submission.Survived #提取y
2.5 決策樹建模
導(dǎo)包 --> 實(shí)例化 --> fit --> 評估
from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier(random_state = 666)
dtc.fit(train_X,train_y)
dtc.score(train_X,train_y) # 訓(xùn)練精度 0.9797
dtc.score(test_X,test_y) # 測試精度 0.8086 過擬合了
3. 過擬合
上邊的結(jié)果明顯過擬合:訓(xùn)練集的準(zhǔn)確率,遠(yuǎn)遠(yuǎn)高于測試集的準(zhǔn)確率
擬合: 模型對數(shù)據(jù)的學(xué)習(xí)過程,模型去適配數(shù)據(jù)
噪聲: 代表了我們數(shù)據(jù)中存在的一些和普適性的規(guī)律不一樣的信息.
數(shù)據(jù)信息兩類(規(guī)律, 噪聲):舉例: 大部分年齡大的男性都死亡了,但是有幾個活下來了,這幾個就不符合常規(guī)的規(guī)律,就是數(shù)據(jù)集中的異常數(shù)據(jù),或者說是噪聲.
如果模型的學(xué)習(xí)能力太強(qiáng),就不但會學(xué)習(xí)到數(shù)據(jù)中的規(guī)律,還會學(xué)習(xí)到數(shù)據(jù)中的噪聲.
這個時(shí)候模型表現(xiàn): 對訓(xùn)練集預(yù)測非常準(zhǔn)確,但是對測試集表現(xiàn)就會很差,這種情況下,我們就稱為模型過擬合了.
欠擬合:模型的學(xué)習(xí)能力太差了,連訓(xùn)練集中的規(guī)律都沒學(xué)會.
表現(xiàn): 無論是訓(xùn)練集還是測試集,它的表現(xiàn)都很差.
解決方案:網(wǎng)格搜索 調(diào)參(降低訓(xùn)練精度珍昨,提高測試精度)
3.1 語法
GridSearchCV: 交叉驗(yàn)證網(wǎng)格搜索
class sklearn.model_selection.GridSearchCV(estimator, param_grid, scoring=None, n_jobs=None, iid='deprecated', refit=True, cv=None, verbose=0, pre_dispatch='2*n_jobs', error_score=nan, return_train_score=False)
參數(shù)說明:
- estimator: 模型
- param_grid : 參數(shù)字典
- scoring : 模型評估指標(biāo),默認(rèn)準(zhǔn)確率
- n_jobs: CPU個數(shù)
- cv: 交叉驗(yàn)證折數(shù)
- verbose: 日志
屬性:
- best_estimator_ : estimator 在網(wǎng)格搜索過程中,找到的最好的分類器.
- best_score_: 最好的分類器,對應(yīng)的交叉驗(yàn)證分?jǐn)?shù)
- best_params_: 最好的分類器對應(yīng)的參數(shù)
3.2 對泰坦尼克模型使用
from sklearn.model_selection import GridSearchCV
# 實(shí)例化
# 參數(shù)分成兩部分: 1.你要調(diào)參的,就不用設(shè)置 2.你不打算調(diào)的,就可以設(shè)置
dtc = DecisionTreeClassifier( random_state=666)
# max_depth=None, 非常重要
# min_samples_split=2, min_samples_leaf=1, 最小葉節(jié)點(diǎn)分裂個數(shù),可選
# max_leaf_nodes=None, 有一定作用
# min_impurity_decrease=0.0 有一定作用,范圍不好確定
決策樹參數(shù)說明:
- criterion: 不純度計(jì)算指標(biāo) {“gini”, “entropy”},
- splitter: {“best”, “random”}, default=”best” 節(jié)點(diǎn)切分方法,默認(rèn)是選擇最優(yōu)特征進(jìn)行切分.
- max_depth: 樹能達(dá)到的最大深度,防止模型太深,控制模型復(fù)雜度
- min_samples_split: int or float, default=2 抑制模型分裂
一個節(jié)點(diǎn)想要向下進(jìn)行切分,當(dāng)前樣本個數(shù)必須要大于這個參數(shù)值.
例如設(shè)置為10,當(dāng)這個節(jié)點(diǎn)中如果有9個樣本,則這個節(jié)點(diǎn)只能作為葉節(jié)點(diǎn).
- min_samples_leaf: int or float, default=1 抑制模型分裂
最小葉節(jié)點(diǎn)樣本個數(shù),如果上層節(jié)點(diǎn)分裂之后,分裂出來后的葉節(jié)點(diǎn)當(dāng)中樣本個數(shù)不足這兒參數(shù)值,則本次分裂不能進(jìn)行.
- max_features : int, float or {“auto”, “sqrt”, “l(fā)og2”}, default=None
最大特征,在尋找最優(yōu)分裂點(diǎn)的時(shí)候,要考慮的特征個數(shù)
If int, 考慮特征個數(shù),舉例有100個特征, 填寫20,就是每次分裂的時(shí)候,只計(jì)算20個特征.
If float, 百分比 0-1的浮點(diǎn)數(shù). 100個特征, 填寫0.3,那就是計(jì)算30個特征.
If “auto”, then max_features=sqrt(n_features). 根號個特征.100個特征就是計(jì)算10個特征
If “sqrt”, then max_features=sqrt(n_features). 同上
If “l(fā)og2”, then max_features=log2(n_features). 計(jì)算log2個特征,64個特征,6個.
If None, then max_features=n_features. 所有特征
- random_state: 隨機(jī)數(shù)種子
- max_leaf_nodes: 抑制模型分裂句喷,最大葉節(jié)點(diǎn)個數(shù),最多能夠分裂出多少個葉節(jié)點(diǎn).
- min_impurity_decrease: 分裂中的最小不純度下降的值.
如果一次分裂過程中,Gain的下降不能超過這個值,那么就不能進(jìn)行本次分裂.
- class_weight: 類別權(quán)重設(shè)置,(類別不均衡數(shù)據(jù)集的問題)
參數(shù)調(diào)優(yōu):
# 設(shè)置調(diào)參字典
# 設(shè)置一個調(diào)參字典
d = {"ccp_alpha":np.arange(0.0,0.8,0.1),
'criterion':["gini",'entropy'],
"max_depth":[2,3,4,5,6,7],
"min_samples_split":range(2,10), #最小葉節(jié)點(diǎn)樣本個數(shù)
"max_leaf_nodes":range(4,20), #最大葉節(jié)點(diǎn)個數(shù)
#"min_impurity_decrease":np.arange(0.01,0.11,0.01) #分裂中的最小不純度下降的值
}
# 實(shí)例化網(wǎng)格搜索
grid = GridSearchCV(dtc,param_grid =d ,n_jobs=-1,cv=5, verbose=2 )
# 訓(xùn)練
grid.fit(X,y)
# 搜索到的最優(yōu)交叉驗(yàn)證分?jǐn)?shù) : 0.8238026489234824
grid.best_score_
# 搜索到的參數(shù)
grid.best_params_
# 結(jié)果
{'criterion': 'gini',
'max_depth': 6,
'max_leaf_nodes': 15,
'min_samples_split': 2}
# 分類器
best_model = grid.best_estimator_
# 看一下搜索到的這個結(jié)果,在測試集上面表現(xiàn)如何?
best_model.score(X_test,y_test)
# feature_importances_: 特征重要性.
best_model.feature_importances_
#結(jié)果
array([0.1935308 , 0.56999101, 0.09826444, 0.04071957, 0.00751746,
0.08082954, 0.00914718])
#相對應(yīng)的特征
X.columns
#輸出:
Index(['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Embarked'], dtype='object')