目的
本文使用Python的sklearn類庫,基于對随機森林算法的理論學習,利用工程中的資料,以此來對随機森林的理論知識進行一次實踐總結。
利用過往1年的資料訓練專家系統,目的是判斷使用者3個月内是否會離網。
訓練集主要來自工程中的資料集,一共100萬條樣本資料,16個次元。
實作
導入依賴類庫:
#!-*- coding:utf-8 -*-
import pandas as pd
import numpy as np
import matplotlib.pylab as plt
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV # 網格搜尋調參,即窮盡參數所有可能性
# 從本地讀取訓練資料
data = pd.read_csv('./decision.csv', encoding='utf-8', sep=' ') # 以空格為分隔符,讀取decision檔案的内容
# 資料探索
print(type(data)) # data為DataFrame類型
print(data.shape)
print(data.head(5)) # 前5行
print(data.info())
print(data.describe())
可以通過如下資料來判斷資料是否存在問題,比如年齡的最大、最小值等。
# 資料構造
col_dicts = {}
cols = data.columns.values.tolist() # 讀取所有列名
df = data.loc[:, cols[1:]] # 擷取除去第一列(user_id)的其它所有資料
print(df.shape)
X = df.loc[:, cols[1: -1]] # 擷取除去第一列(user_id)和最後一列(churn_label)的所有資料
# X = df.loc[:, cols[1: 3]]
# X.append(df.loc[:, cols[5]])
# X.append(df.loc[:, cols[8:14]])
print(X.info())
結果:
(1000000, 15) # 100W行,15列
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1000000 entries, 0 to 999999
Data columns (total 14 columns):
age 1000000 non-null int64 # 可以看出,資料集是完整的資料集,無缺失值
net_age 1000000 non-null int64
neto_dur 1000000 non-null int64
chrg_dur 1000000 non-null int64
sms_bill_cnt 1000000 non-null int64
flux_fee 1000000 non-null int64
iset_flux 1000000 non-null int64
arpu 1000000 non-null int64
acct_balance 1000000 non-null int64
extend_paydate_days 1000000 non-null int64
last_year_owe_cnt 1000000 non-null int64
last_year_complain_cnt 1000000 non-null int64
ordered_prodect_cnt 1000000 non-null int64
circle_nou 1000000 non-null int64
dtypes: int64(14)
memory usage: 106.8 MB
None
# 資料拆分及類别資訊檢視
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0) # 20%測試集,80%訓練集。固定随機種子(random_state),可以讓每次劃分訓練集和驗證集的時候都是完全一樣的。
print(y_train.value_counts() / len(y_train))
print('---------')
print(y_test.value_counts() / len(y_test))
結果:
1 0.500988
0 0.499013
Name: churn_label, dtype: float64
---------
0 0.50002
1 0.49998
Name: churn_label, dtype: float64
以上結果顯示正負樣本比例相差不大,不存在資料傾斜。如果出現資料傾斜,可以采取如下方式進行調整:
- 負采樣;
- 建構負樣本
為了節省運算時間,子模型數(n_estimators)參數設定的比較小,實際中可以設定大一點。
# 建構随機森林模型
from sklearn import tree
from sklearn.ensemble import RandomForestClassifier
credit_model = RandomForestClassifier(n_estimators=10, n_jobs=4) # 10個子分類器,4個CPU線程并行
# print(credit_model.fit(X_train, y_train))
# 使用網格搜尋訓練參數
# n_estimators_range = 100 # 子模型數
max_depth_range = np.arange(5, 7, 1) # 最大樹深度
criterion_range = ['gini', 'entropy'] # 分裂條件。gini:CART樹;entropy:C4.5
# 随機選擇特征集合的子集合,并用來分割節點。子集合的個數越少,方差就會減少的越快,但同時偏差就會增加的越快
'''
選擇最适屬性時劃分的特征不能超過此值。
當為整數時,即最大特征數;當為小數時,訓練集特征數*小數;
if “auto”, then max_features=sqrt(n_features).
If “sqrt”, thenmax_features=sqrt(n_features).
If “log2”, thenmax_features=log2(n_features).
If None, then max_features=n_features.
'''
max_features_range = ['auto', 'sqrt', 'log2']
param_grid = {'max_depth': max_depth_range, 'max_features': max_features_range, 'criterion': criterion_range}
# GridSearch作用在訓練集上
grid = GridSearchCV(credit_model, param_grid=param_grid, scoring='accuracy', n_jobs=4, cv=5)
grid.fit(X_train, y_train)
結果:
GridSearchCV(cv=5, error_score='raise-deprecating',
estimator=RandomForestClassifier(bootstrap=True, class_weight=None,
criterion='gini', max_depth=None,
max_features='auto',
max_leaf_nodes=None,
min_impurity_decrease=0.0,
min_impurity_split=None,
min_samples_leaf=1,
min_samples_split=2,
min_weight_fraction_leaf=0.0,
n_estimators=10, n_jobs=4,
oob_score=False,
random_state=None, verbose=0,
warm_start=False),
iid='warn', n_jobs=4,
param_grid={'criterion': ['gini', 'entropy'],
'max_depth': array([5, 6]),
'max_features': ['auto', 'sqrt', 'log2']},
pre_dispatch='2*n_jobs', refit=True, return_train_score=False,
scoring='accuracy', verbose=0)
# 得到最優參數
print(grid.best_score_)
print(grid.best_params_)
print(grid.best_estimator_)
# 訓練參數調優後的模型
credit_model = RandomForestClassifier(n_estimators=10, n_jobs=4, max_depth=grid.best_params_['max_depth'], max_features=grid.best_params_['max_features'], criterion=grid.best_params_['criterion'])
# fit on the trainingt data
credit_model.fit(X_train, y_train)
# 模型預測及結果分析
credit_pred = credit_model.predict(X_test)
from sklearn import metrics
print(metrics.classification_report(y_test, credit_pred)) # y_test:真實值;credit_pred:預測值
print(metrics.confusion_matrix(y_test, credit_pred))
print(metrics.accuracy_score(y_test, credit_pred)) # 預測的準确率
結果:
0.5556025
{'criterion': 'gini', 'max_depth': 5, 'max_features': 'sqrt'}
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=5, max_features='sqrt', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=4,
oob_score=False, random_state=None, verbose=0,
warm_start=False)
precision recall f1-score support
0 0.56 0.56 0.56 100004
1 0.56 0.56 0.56 99996
accuracy 0.56 200000
macro avg 0.56 0.56 0.56 200000
weighted avg 0.56 0.56 0.56 200000
[[55626 44378]
[44432 55564]]
0.55595
總結
本文簡單的構造了一個随機森林,并使用網格搜尋的方式對其進行超參調優,還可以使用如下方式進行調優:
- 把連續性次元換成離散型;
- 特征層面調優;
- 超參數層面調優