1. 程式人生 > >python資料分析:商品資料化運營(中)——基於引數優化的Gradient Boosting的銷售預測

python資料分析:商品資料化運營(中)——基於引數優化的Gradient Boosting的銷售預測

本案例需要使用超引數交叉檢驗和優化方法GridSearchCV以及整合迴歸方法GradientBoostingRegressor

GridSearchCV與GradientBoostingRegressor

GridSearchCV

GridSearchCV用於系統地遍歷多種引數組合,通過交叉驗證確定最佳效果引數,其實就是窮舉法,遍歷所有組合。GridSearchCV,它存在的意義就是自動調參,只要把引數輸進去,就能給出最優化的結果和引數。但是這個方法適合於小資料集,一旦資料的量級上去了,很難得出結果。

GradientBoostingRegressor

Gradient Tree Boosting或Gradient Boosted Regression Trees(GBRT)是一個boosting的泛化表示,它使用了不同的loss函式。GBRT是精確、現成的過程,用於解決迴歸/分類問題。Gradient Tree Boosting模型則用於許多不同的領域:比如:網頁搜尋Ranking、ecology等。

GBRT的優點是:

  • 天然就可處理不同型別的資料(=各種各樣的features)
  • 預測能力強
  • 對空間外的異常點處理很健壯(通過健壯的loss函式)

GBRT的缺點是:

+ 擴充套件性不好,因為boosting天然就是順序執行的,很難並行化

sklearn.ensemble通過GBRT提供了分類和迴歸的功能。

案例資料

以下是本資料集的10個特徵變數,包括:

  • limit_infor:是否有限購字樣資訊提示,1代表有,0代表沒有。
  • campaign_type:促銷活動型別,分型別變數,值域為[0,6]代表7種不同型別的促銷活動,例如單品活動、跨店鋪活動、綜合性活動、3C大品類活動等。
  • campaign_level:促銷活動重要性,分型別變數,值域為[0,1],分別代表促銷活動本身的不重要或重要性程度。
  • product_level:產品重要性分級,分型別變數,值域為[1,3],分別代表運營部門對於商品重要性的分級。
  • resource_amount:促銷資源位數量,整數型變數,代表每次該商品在參加促銷活動時有多少個資源位入口。
  • email_rate:傳送電子郵件中包含該商品的比例,浮點型變數,值域[0,1],值越大代表包含該商品的電子郵件越多。
  • price:單品價格,整數型變數,程式碼商品在不同階段的實際銷售價格。
  • discount_rate:折扣率,浮點型變數,值域[0,1],值越大代表折扣力度越大。
  • hour_resouces:在促銷活動中展示的小時數,整數型變數,值越大代表展示的時間越長。
  • campaign_fee:該單品的促銷費用,整數型變數,值越大代表用於該單品的綜合促銷費用越高,這裡麵包含促銷費用、廣告費用、優惠券費用等綜合攤派的費用。

目標變數:orders,代表該單品在每次活動中形成的訂單量。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import GridSearchCV
import warnings
# 影象在notebook中顯示
%matplotlib inline
# 不顯示提示
warnings.filterwarnings('ignore')

# 資料載入
df = pd.read_csv('https://raw.githubusercontent.com/ffzs/dataset/master/products_sales.txt')

# 資料的簡單檢視
df.head().T

在這裡插入圖片描述

# 資料型別的檢視
df.dtypes

在這裡插入圖片描述
資料型別沒有什麼問題,無需更改

# 資料缺失情況
df.isna().sum()

在這裡插入圖片描述
缺失值情況:目標變數缺失,而且只有少量缺失,直接刪除即可

# 棄去缺失值
df.dropna(inplace=True)

# 資料描述
df.describe().T

在這裡插入圖片描述

在描述性統計結果中,以行為單位檢視每個特徵變數的基本資訊,發現以下異常點:

  • limit_infor的值域應該是0或1,但是最大值卻出現了10。
  • campaign_fee的標準差非常大,說明分佈中存在異常點,並且最大值是33380,嚴重超過均值。
# 檢視campaign_fee分佈
df.campaign_fee.hist()

在這裡插入圖片描述

#發現異常值大於30000,檢視大於30000的資料,只有一條資料
df[df.campaign_fee>30000]

在這裡插入圖片描述

# 將異常極大值替換為均值
df['campaign_fee'] = df['campaign_fee'].replace(33380, df['campaign_fee'].mean())
# 只保留促銷值為0和1的記錄
df = df[df['limit_infor'].isin((0, 1))]  

# 獲取各個特徵的皮爾森相關性
corr = df.corr().round(2)
# 設定畫幅
plt.figure(figsize=(10,10))
# 繪製熱力圖
sns.heatmap(corr, linewidths=0.1, square=True, annot=True, cmap='RdYlBu_r')
# 儲存
plt.savefig('xx.png')

在這裡插入圖片描述

根據相關性可知email_rate和resource_amount具有非常高的相關性,相關係數達到0.98,通常意味著我們需要對此做處理。

# 分割X和y
X = df.ix[:, :-1]  # 分割X
y = df.ix[:, -1]  # 分割y

上述過程中,我們提到了一個共線性的問題還沒有解決,這個問題留在後面的模型優化裡面具體解釋。

#### 模型優化及訓練 ####
# 建立GradientBoostingRegressor迴歸物件
gbr = GradientBoostingRegressor() 
# 定義要優化的引數資訊
parameters = {'loss': ['ls', 'lad', 'huber', 'quantile'],
              'min_samples_leaf': [1, 2, 3, 4, 5],
              'alpha': [0.1, 0.3, 0.6, 0.9]}  
# 建立交叉檢驗模型物件
gscv = GridSearchCV(estimator=gbr, param_grid=parameters, cv=5) 
# 訓練模型
gscv.fit(X, y)  

實現過程中的主要功能點如下:

先建立GradientBoostingRegressor模型物件,然後設定交叉檢驗時用到的模型可選引數,也就是GradientBoostingRegressor中的的調節引數,這裡用到了三個引數:

  • loss:loos是GradientBoostingRegressor的損失函式,主要包括四種ls、lad、huber、quantile。ls(Least squares),預設方法,是基於最小二乘法方法的基本方法,也是普通線性迴歸的基本方法;lad(Least absolute deviation)是用於迴歸的魯棒損失函式,它可以降低異常值和資料噪音對迴歸模型的影響;huber是一個結合ls和lad的損失函式,它使用alpha來控制對異常值的靈敏度;quantile是分位數迴歸的損失函式,使用alpha來指定分位數用於預測間隔。
  • min_samples_leaf:作為葉子節點的最小樣本數。如果設定為數字,那麼將指定對應數量的樣本,如果設定為浮點數,則指定為總樣本量的百分比。
  • alpha:用於huber或quantile的調節引數。
    這裡設定了loss的所有可用損失函式,以字串列表的形式定義;min_samples_leaf則是具體值作為定義,而非樣本比例;alpha定義了常用的覆蓋了0到1之間的間隔值。這裡定義為列表或元組都可以,只要是能實現迭代讀取即可。

再使用GridSearchCV建立交叉檢驗模型物件,設定引數如下:

  • estimator:用來設定要訓練的模型器,本示例中是整合迴歸物件model_gbr
  • param_grid:用來設定要檢驗的所有引數列表值,本示例定義的值放在parameters中。該值是一個字典或者字典的列表。
  • cv:用來定義交叉檢驗的方法。如果為空,則使用預設的3折交叉檢驗;如果為數字,則定義為交叉檢驗的次數,這裡自定義為5可以獲得更準確的結論;如果設定為一個物件,那麼這是一個自定義的交叉檢驗方法;如果設定為可迭代的訓練集和測試集物件,那麼將迴圈讀取分割好的資料集做交叉檢驗。我們在第五章的第二個案例中,就是用了自定義的交叉檢驗方法。
# 獲得交叉驗證最有得分
gscv.best_score_
# 0.9309967487903625

# 獲得模型最優引數
gscv.best_params_
# {'alpha': 0.6, 'loss': 'huber', 'min_samples_leaf': 4}

model_best = gscv.best_estimator_  # 獲得交叉檢驗模型得出的最優模型物件
model_best.fit(X, y)  # 訓練最優模型
plt.style.use("ggplot")  # 應用ggplot自帶樣式庫
plt.figure(figsize=(15,8))  # 建立畫布物件
plt.plot(np.arange(X.shape[0]), y, label='true y')  # 畫出原始變數的曲線
plt.plot(np.arange(X.shape[0]), model_best.predict(X), label='predicted y')  # 畫出預測變數曲線
plt.legend(loc=0)  # 設定圖例位置
plt.savefig('xxx.png')

在這裡插入圖片描述

結論

本案例是一個應用型的模型示例,通過業務方給出的訓練集以及預測自變數得到最終訂單量預測值。

從交叉檢驗得到的最佳模型的得分為0.93,該得分由GradientBoostingRegressor的score產生,其值是預測的決定係數R2,該得分越高意味著自變數對因變數的解釋能力越強,最高得分為1,5次交叉檢驗0.93的得分已經能夠充分說明迴歸模型的預測能力比較強且效果相對穩定

問題

問題一 :本案例中,不同的自變數之間其實存在量綱的差異,針對這種情況是否需要做先對每一列做標準化然後再做迴歸分析?

對於迴歸分析而言,是否做標準化取決於具體場景。在本案例中,迴歸分析的目的是做預測,因此無需做標準化;而如果要做特徵重要性的分析,那麼必須要做標準化。標準化的目的是去除量綱對於迴歸係數的影響,如果不做標準化,本案例中的因變數將主要受campaign_fee,即該變數係數的絕對值最大。

問題二 :本案例沒有對具有非常高相關性的變數做任何處理,這是否得當?

本案例應用的是整合方法,具體引數通過交叉檢驗得到的是使用huber損失函式做迴歸評估,它已經能夠兼顧(一定程度上解決共線性)的問題。因為在應用GradientBoostingRegressor方法中,有一個引數learning_rate是用來通過正則化的方法控制梯度下降過程的步長,它通過收縮正常化(learning_rate <1.0)來提高模型效能。將email_rate列去掉,然後再做模型最優化評估會發現得分結果仍然是0.93(小數點後面幾位會有差異,但已經非常不明顯)。

參考:

《python資料分析與資料化運營》 宋天龍