天天看點

【sklearn】随機森林 - 預測使用者是否離網目的實作總結

目的

本文使用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())
           
【sklearn】随機森林 - 預測使用者是否離網目的實作總結
【sklearn】随機森林 - 預測使用者是否離網目的實作總結

可以通過如下資料來判斷資料是否存在問題,比如年齡的最大、最小值等。

【sklearn】随機森林 - 預測使用者是否離網目的實作總結
【sklearn】随機森林 - 預測使用者是否離網目的實作總結
# 資料構造
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
           

總結

本文簡單的構造了一個随機森林,并使用網格搜尋的方式對其進行超參調優,還可以使用如下方式進行調優:

  • 把連續性次元換成離散型;
  • 特征層面調優;
  • 超參數層面調優

繼續閱讀