機器學習:怎樣用模型預測使用者的生命週期價值?
持續創作,加速成長!這是我參與「掘金日新計劃 · 10 月更文挑戰」的第4天,點選檢視活動詳情
定義問題
預測下使用者在未來能帶來的收益。
LTV
這個被稱為使用者的生命週期價值(CLV:Customer Lifetime Value)或稱為LTV(Lifetime Value),指的是每個使用者(購買者、會員、使用者)在未來可能為該服務帶來的收益總和。
適用領域
對以廣告、銷售等動態現金流入的服務(例如App服務、會員網站、電子商務)是相當重要的營運參考資料。 1. 瞭解產品使用者實際價值。 2. 基於大資料的CLV管理方法,最大化有價值使用者的利潤,對有潛力的使用者提升銷售,甚至挖掘其他“有價值的使用者”。 3. 給予行銷人員廣告投放方向。例如:取得一個使用者的成本不可高於CLV。
資料預處理
預測收益當然需要使用者的交易資料,所以繼續繼續使用《機器學習:從資料中找到使用者的RFM值》中的資料。
``` import pandas as pd # 匯入Pandas
df_sales=pd.read_csv('/Users/wanghaifeng/Documents/零基礎實戰機器學習/geektime-main/獲客關05/易速鮮花訂單記錄.csv') df_sales.head() ```
跟著課程中使用頭三個月的R、F、M這三個數值作為特徵,一年的總消費額作為標籤,做一個迴歸模型預測出LTV。(這個是課程作者選的,至於為啥以後再研究)
資料清洗
``` df_sales.drop_duplicates() #刪除重複的資料行
df_sales=df_sales.loc[df_sales['數量']>0] # 清洗掉數量小於等於0的資料
df_sales.describe()
``` 這裡說下問題:課程裡的沒有清洗數量小於0的髒資料,下面使用模型預測出來的值比較好看,但是清洗掉就不好了,這個先擱置,筆者學這個課程也是先對機器學習有個感覺,太糾結就走不下去了。
加上總價
df_sales['總價'] = df_sales['數量'] * df_sales['單價'] # 計算每單的總價
整理資料集記錄的時間範圍
import numpy as np # 匯入NumPy
print('日期範圍: %s ~ %s' % (df_sales['消費日期'].min(), df_sales['消費日期'].max()))
df_sales['消費日期'] = pd.to_datetime(df_sales['消費日期']) #轉換日期格式
print('日期範圍: %s ~ %s' % (df_sales['消費日期'].min(), df_sales['消費日期'].max()))
輸出:
日期範圍: 1/1/2021 10:11 ~ 9/9/2020 9:20
日期範圍: 2020-06-01 09:09:00 ~ 2021-06-09 12:31:00
資料集中的時間跨度是2020-06-01到2021-06-09,我們想要的是一年的消費總額,所以剔除:
df_sales=df_sales.loc[df_sales['消費日期'] < '2021-06-01']
print('日期範圍: %s ~ %s' % (df_sales['消費日期'].min(), df_sales['消費日期'].max()))
輸出:
日期範圍: 2020-06-01 09:09:00 ~ 2021-05-31 17:37:00
構建特徵和標籤
構建特徵
特徵只需要前三個月的資料:
df_sales_3m=df_sales[(df_sales.消費日期 > '2020-06-01')&(df_sales.消費日期 <= '2020-08-30')]
df_sales_3m.reset_index(drop=True)
特徵提取:
df_user_LTV = pd.DataFrame(df_sales['使用者碼'].unique()) #生成以使用者碼為主鍵的結構
df_user_LTV.columns=['使用者碼'] #設定欄位名
df_user_LTV.head()
df_R_value=df_sales_3m.groupby('使用者碼').消費日期.max().reset_index() #找到每個使用者的最近消費日期,構建df_R_value物件
df_R_value.columns=['使用者碼','最近購買日期']
df_R_value['R值']=(df_R_value['最近購買日期'].max()-df_R_value['最近購買日期']).dt.days #計算最近日期與上次消費日期的天數
df_user_LTV=pd.merge(df_user_LTV,df_R_value[['使用者碼','R值']],on='使用者碼') #把上次消費距最新日期的天數(R值)合併至df_user_LTV
df_F_value=df_sales_3m.groupby('使用者碼').消費日期.count().reset_index()
df_F_value.columns=['使用者碼','F值']
df_user_LTV=pd.merge(df_user_LTV,df_F_value[['使用者碼','F值']],on='使用者碼')
df_M_value=df_sales_3m.groupby('使用者碼').總價.sum().reset_index()
df_M_value.columns=['使用者碼','M值']
df_user_LTV = pd.merge(df_user_LTV, df_M_value, on='使用者碼') #把消費總額整合至df_user結構
df_user_LTV #顯示使用者表結構
構建標籤
df_user_ly=df_sales.groupby('使用者碼')['總價'].sum().reset_index() #計算每個使用者整年消費總額,構建df_user_ly
df_user_ly.columns=['使用者碼','年度LTV']
df_user_ly.head()
df_LTV=pd.merge(df_user_LTV,df_user_ly,how='left')
df_LTV
建立特徵集和標籤集
建立特徵集
X=df_LTV.drop(['使用者碼','年度LTV'],axis=1) #特徵集
X.head()
建立標籤集
y=df_LTV['年度LTV']
y.head()
拆分訓練集、驗證集和測試集
``` from sklearn.model_selection import train_test_split
先拆分訓練集和其它集
X_train,X_rem,y_train,y_rem=train_test_split(X,y,train_size=0.7,random_state=36)
再把其它集拆分成驗證集和測試集
X_valid,X_test,y_valid,y_test=train_test_split(X_rem,y_rem,test_size=0.5,random_state=36) ```
選擇演算法建立模型
課程中使用最基本的線性迴歸模型、決策樹模型和隨機森林模型。
- 線性迴歸:通過梯度下降找到最優的權重和模型偏置的最基本的迴歸演算法。裡,我會用它作為一個基準模型,把其它模型的結果與其相比較,來確定優劣。
- 決策樹演算法:簡單地說是從樣本資料的特徵屬性中,通過學習簡單的決策規則,也就是我們耳熟能詳的IF ELSE規則,來預測目標變數的值。這個演算法的核心是劃分點的選擇和輸出值的確定。
可以看到,這種演算法是根據兩個特徵x1和x2的值,以及標籤y的取值,對二維平面上的區域進行精準分割,以確定從特徵到標籤的對映規則。根據樹的深度和分叉時所選擇的特徵的不同,我們可以訓練出很多顆不一樣的樹來。
- 隨機森林:就是由多棵決策樹構成的整合學習演算法。它既能用於分類問題,也能用於迴歸問題。而且無論是哪類問題,它都是相對優秀的演算法。在訓練模型的過程中,隨機森林會構建多個決策樹,如果解決的是分類問題,那麼它的輸出類別是由個別樹輸出的類別的眾數而定;如果解決的是迴歸問題,那麼它會對多棵樹的預測結果進行平均。隨機森林糾正了決策樹過度擬合其訓練集的問題,在很多情況下它都能有不錯的表現。這裡的“過擬合”,其實就是說模型對訓練集的模擬過頭了,反而不太適合驗證集和測試集。
from sklearn.linear_model import LinearRegression #匯入線性迴歸模型
from sklearn.tree import DecisionTreeRegressor #匯入決策樹迴歸模型
from sklearn.ensemble import RandomForestRegressor #匯入隨機森林迴歸模型
model_lr=LinearRegression() #建立線性迴歸模型
model_dtr=DecisionTreeRegressor() # 建立決策樹迴歸模型
model_rfr=RandomForestRegressor() #建立隨機森林迴歸模型
訓練模型
model_lr.fit(X_train,y_train) # 擬合線性迴歸模型
model_dtr.fit(X_train,y_train) # 擬合決策樹模型
model_rfr.fit(X_train,y_train) # 擬合隨機森林模型
評估模型
X_valid.iloc[2] # 隨便選擇一個數據
輸出:
R值 1.00
F值 154.00
M值 1427.73
Name: 163, dtype: float64
print('真值:', y_valid.iloc[2]) #線性迴歸模型預測值
print('線性迴歸預測值:', y_valid_preds_lr[2]) #線性迴歸模型預測值
print('決策樹預測值:', y_valid_preds_dtr[2]) #決策樹模型預測值
print('隨機森林預測值:', y_valid_preds_rfr[2]) #隨機森林模型預測值
輸出:
真值: 4432.43
線性迴歸預測值: 7474.4181424883545
決策樹預測值: 4074.57
隨機森林預測值: 4282.643300000004
我們還要用$R2$、MSE等評估指標在驗證集上做整體評估,選使用$R2$:
from sklearn.metrics import r2_score,mean_absolute_error
print('驗證集上的R平方-線性迴歸:%0.4f' % r2_score(y_valid,model_lr.predict(X_valid)))
print('驗證集上的R平方分數-決策樹: %0.4f' % r2_score(y_valid, model_dtr.predict(X_valid)))
print('驗證集上的R平方分數-隨機森林: %0.4f' % r2_score(y_valid, model_rfr.predict(X_valid)))
輸出:
驗證集上的R平方-線性迴歸:0.4410
驗證集上的R平方分數-決策樹: 0.1209
驗證集上的R平方分數-隨機森林: 0.4538
可以看出隨機森林樹預測能力好點。
但是0.4幾說明擬合的其實不咋樣。
import matplotlib.pyplot as plt #匯入Matplotlib的pyplot模組 y_test_preds_rfr = model_rfr.predict(X_test) #用模型預隨機森林模型預測驗證集 plt.scatter(y_test, y_test_preds_rfr) #預測值和實際值的散點圖 plt.plot([0, max(y_test)], [0, max(y_test_preds_rfr)], color='gray', lw=1, linestyle='--') #繪圖 plt.xlabel('實際值') #X軸 plt.ylabel('預測值') #Y軸 plt.title('實際值 vs. 預測值') #標題