騰訊數(shù)據(jù)科學(xué)家手把手教你做用戶行為分析(案例:出行選擇)
來源:大數(shù)據(jù)DT
[ 導(dǎo)讀 ]生活中的選擇行為無處不在,數(shù)據(jù)分析師面對的商業(yè)場景也存在大量的用戶選擇問題。系統(tǒng)、科學(xué)地研究用戶選擇問題,得到選擇行為背后的客觀規(guī)律并基于這些規(guī)律提出業(yè)務(wù)優(yōu)化策略,這些能力對于數(shù)據(jù)分析師非常重要且極具價值。
01 引子:以出行為例剖析選擇行為的具體邏輯
下面以選擇出行方式為例,剖析選擇行為的具體邏輯,為后面的學(xué)習(xí)做好鋪墊。
1. 出行選擇的場景還原
出行就是“在某時從A點到達B點”,這一行為主要面臨的選擇是“以什么方式前往”,回想一下我們平時做出行選擇時,是否有如下參考信息浮現(xiàn)在腦海。
可以選擇的交通方式有哪些?
同程的人多不多?
需要在什么時間到達?
出行預(yù)算是多少?
公共交通的便捷程度?
出行方式是否受天氣影響?
通常,我們會帶著這些疑問打開出行類App看看各類交通方式的花費、耗時及路線,可能還會打開天氣App看看未來一段時間是否下雨、是否有嚴重的霧霾,如圖1-1所示。
▲圖1-1 打開App查看出行路線和天氣
2. 出行選擇的決策邏輯
接下來,我們通過一個更加具體的案例說明出行選擇的決策邏輯:有200個家庭要進行家庭旅行,每個家庭的情況不同(包括出行人數(shù)、目的地、家庭年收入等),每個家庭都會在飛機、火車、長途巴士及自駕車中選擇一種作為出行方式。
不同的家庭會有不同的選擇,在選擇的表象下有著相似的決策邏輯。我們嘗試置身于這個場景中,在大腦里構(gòu)建一張類似圖1-2的打分表。
出行方式的屬性可以主要歸結(jié)為行程外(等車)耗時、行程中耗時、行程花費、舒適性等,確定這些出行方式的屬性后,再結(jié)合自身屬性(家庭收入、出行人數(shù)等),對每個選項進行定性/定量的排序,得到最適合自己的選擇結(jié)果。
▲圖1-2 旅行出行方式打分表
在選擇的過程中,如果某個因素發(fā)生變化,就有可能對選擇結(jié)果產(chǎn)生影響。例如:其他因素保持不變,由于航空公司促銷,機****價格比火車****還便宜,你的選擇是不是會從火車改為飛機呢?再假設(shè),臨行前你收獲一筆超過預(yù)期的獎金,可支配的現(xiàn)金增多,是不是也會從火車改為飛機呢?
回憶一下我們生活中其他方面的選擇,其實也秉持類似的方式。經(jīng)濟學(xué)家、心理學(xué)家經(jīng)過長期研究,發(fā)現(xiàn)人類個體間的“選擇之道”存在較高相似性,對這些相似性加以總結(jié)就形成了一系列選擇行為的經(jīng)濟學(xué)理論。
這些長期沉淀下來的理論對于數(shù)據(jù)分析師來說是非常有價值的,它不僅能幫助我們從本質(zhì)上理解相關(guān)計量選擇模型的原理,還能在對業(yè)務(wù)方進行分析闡述時有理論背書,下面我們開始學(xué)習(xí)選擇行為的經(jīng)濟學(xué)理論。
02 選擇行為的經(jīng)濟學(xué)理論
選擇行為主要有兩個經(jīng)濟學(xué)派別,分別是理性人選擇和行為經(jīng)濟學(xué)。盡管行為經(jīng)濟學(xué)在某些方面對理性人選擇提出了挑戰(zhàn),但理性人選擇仍然是群體選擇行為分析的主流理論框架。本文后續(xù)內(nèi)容均基于理性人選擇。
1. 理性人選擇理論
理性人選擇是指經(jīng)濟決策的主體是充滿理智的,他們對于所處環(huán)境具有完備的知識,能夠找到實現(xiàn)目標(biāo)的所有備選方案,有穩(wěn)定且清晰的偏好,擁有很強的計算能力,能預(yù)測每種方案的選擇后果,并依據(jù)某種衡量標(biāo)準(zhǔn)從這些方案中做出最優(yōu)選擇,選擇的唯一目標(biāo)是自身經(jīng)濟利益最大化。
結(jié)合上文的出行案例,我們先來解釋什么是理性人選擇。
當(dāng)我們選擇出行方式時,首先確認每種交通方式的重要屬性(行程外耗時、行程中耗時、行程花費、舒適性)、自身屬性(家庭收入、出行人數(shù))、客觀因素(天氣);然后基于這些信息為每個方案計算一個偏好值并排序;最終選擇偏好值最大的選項。
如果選擇了自駕車,那么說明綜合多種因素,自駕是最能獲得滿足感的出行方式。
2. 效用理論
消費者內(nèi)心的滿足感其實可以用一個經(jīng)濟學(xué)的詞匯來表示,即“效用”。依照每種選擇方案的“效用”排序進行選擇的過程叫作“效用最大化”,這就是理性人選擇理論最常用的準(zhǔn)則,學(xué)術(shù)上的描述是當(dāng)消費者面對一系列備選商品的時候,他們會清楚地計算每個商品的效用,并嚴格將所有商品按照效用排序,選擇效用最大化的商品。
讀到這里你也許會有疑問,盡管我們認同選擇時確實是基于理性人選擇理論,但如此抽象的理論怎樣才能在實際的數(shù)據(jù)分析中發(fā)揮作用呢?哪怕知道了影響選擇行為的因素,也無法得出效用的計算公式。此時,我們需要繼續(xù)學(xué)習(xí)揭示性偏好理論。
3. 揭示性偏好理論
揭示性偏好理論由美國經(jīng)濟學(xué)家保羅·安東尼·薩繆爾森提出。該理論表明:可以結(jié)合消費者歷史消費行為分析消費者偏好,通過統(tǒng)計分析的方式得到相關(guān)因素的量化影響。該理論有以下兩個重要假設(shè)。
消費者在進行實際消費行為時,若從備選方案中選擇了一個選項,即為首選選項,則該選項效用是最大的。
在給定的消費者預(yù)算、商品價格等因素不變的情況下,如果消費者購買了某種產(chǎn)品,那么他將始終做出相同的選擇。
在該理論提出之初,包含的影響因素有消費者預(yù)算、商品價格以及其他商品或消費者屬性。對這些因素進行歸納和拓展,再結(jié)合上述假設(shè),形成了離散選擇模型的模型框架。
03 離散選擇模型
了解了必要的理論知識后,我們開始學(xué)習(xí)離散選擇模型(Discrete Choice Models,DCM)。
DCM不是單一模型,而是一個模型簇,它包含了一系列應(yīng)對不同選擇場景的模型,例如邏輯回歸(Logistics Regression,LR)、多項Logit模型(Multinomial Logit Model,MNL)及嵌套Logit模型(Nested Logit Model,NL Model)等。
如圖1-3所示,DCM主要包括5個部分,分別是決策者(決策者屬性)、備選項集合、備選項屬性、決策準(zhǔn)則和選擇結(jié)果,數(shù)學(xué)表達形式如下。
選擇結(jié)果 = F(決策者, 備選項集合, 備選項屬性)
其中,F(xiàn)是決策準(zhǔn)則,即效用最大化準(zhǔn)則。模型最終實現(xiàn)的功能是在給定決策者, 備選項集合, 備選項屬性后,基于效用最大化準(zhǔn)則,得到選擇結(jié)果。
▲圖1-3 離散選擇模型的元素及結(jié)構(gòu)
回到旅行出行方式選擇的案例中,我們對例子中的元素進行映射。
決策者:一次選擇行為的主體(決策者屬性包括家庭收入、出行人數(shù)、天氣)。
備選項集合:飛機、火車、長途巴士、自駕車(不同決策者的備選項集合可以不同)。
備選項屬性:行程外耗時、行程中耗時、行程花費、舒適性(不同備選項的屬性也可以不同)。
選擇準(zhǔn)則:效用的最大化準(zhǔn)則。
選擇結(jié)果:備選項中的一個選項(每個選擇過程均存在選擇結(jié)果)。
04 案例分析:使用邏輯回歸分析自駕選擇問題
基于前文的介紹,相信讀者已經(jīng)迫不及待使用MNL或NL模型進行建模分析了,這里先從LR的實操講起。LR是目前應(yīng)用最廣泛的可解釋二分類模型之一,深入了解LR對我們的日常工作有很大幫助。
通過對案例數(shù)據(jù)進行一定的處理,可以得到一份滿足LR模型要求的寬格式數(shù)據(jù)。具體數(shù)據(jù)描述如下所示,場景邏輯如圖1-5所示。
OBS_ID:離散,選擇行為ID HINC:連續(xù),家庭收入 PSIZE:連續(xù) or 離散,出行人數(shù) TTME_AIR:連續(xù),站點等待時間(飛機) TTME_TRAIN:連續(xù),站點等待時間(火車) TTME_BUS:連續(xù),站點等待時間(長途巴士) INVC_AIR:連續(xù),金錢成本(飛機) INVC_TRAIN:連續(xù),金錢成本(火車) INVC_BUS:連續(xù),金錢成本(長途巴士) INVC_CAR:連續(xù),金錢成本(自駕) INVT_AIR:連續(xù),行程中 -時間成本(飛機) INVT_TRAIN:連續(xù),行程中 -時間成本(火車) INVT_BUS:連續(xù),行程中 -時間成本(長途巴士) INVT_CAR:連續(xù),行程中 -時間成本(自駕) y:離散,是否選擇自駕
▲圖1-5 LR的場景邏輯示意圖
了解數(shù)據(jù)形式后,開始進行具體的模型搭建工作。
第1步:軟件包引入,數(shù)據(jù)讀取
重要的軟件包在代碼的備注中,如代碼清單1-3所示。
代碼清單1-3 軟件包引入及數(shù)據(jù)讀取
import numpy as np # 引入基礎(chǔ)軟件包numpy import pandas as pd # 引入基礎(chǔ)軟件包pandas import statsmodels.api as sm # 引入Logistic regression軟件包statsmodels from sklearn.model_selection import train_test_split # 引入訓(xùn)練集/測試集構(gòu)造工具包 from sklearn import metrics # 引入模型評價指標(biāo)AUC計算工具包 import matplotlib.pyplot as plt # 引入繪圖軟件包 import scipy # 引入scipy軟件包完成卡方檢驗 # 數(shù)據(jù)讀入 data_path = 'wide_data.csv' raw_data = pd.read_table(data_path, sep=',', header=0)
第2步:數(shù)據(jù)預(yù)處理
數(shù)據(jù)預(yù)處理工作對于任何模型搭建都是必要的,這里結(jié)合LR及后續(xù)將介紹的MNL、NL模型的特點著重講3個數(shù)據(jù)預(yù)處理的要點:①不要存在缺失值;②每一列均為為數(shù)值型;③多枚舉值離散變量入模前要進行啞變量處理,如代碼清單1-4所示。
代碼清單1-4 數(shù)據(jù)預(yù)處理
# 1. 缺失值探查&簡單處理 model_data.info() # 查看每一列的數(shù)據(jù)類型和數(shù)值缺失情況 # | RangeIndex: 210 entries, 0 to 209 # | Data columns (total 9 columns): # | ... # | HINC 210 non-null int64 # | ... model_data = model_data.dropna() # 缺失值處理——刪除 model_data = model_data.fillna(0) # 缺失值處理——填充(零、均值、中位數(shù)、預(yù)測值等) # 2. 數(shù)值型核查(連續(xù)變量應(yīng)為int64或float數(shù)據(jù)類型) # 若上一步中存在應(yīng)為連續(xù)數(shù)值變量的字段為object,則執(zhí)行下列代碼,這里假設(shè)'HINC'存在為字符串'null'的值。 import re # 正則表達式工具包 float_patten = '^(-?\\d+)(\\.\\d+)?$' # 定義浮點數(shù)正則patten float_re = re.compile(float_patten) # 編譯 model_data['HINC'][model_data['HINC'].apply(lambda x : 'not_float' if float_re.match(str(x)) == None else 'float') == 'not_float'] # 查看非浮點型數(shù)據(jù) # | 2 null # | Name: distance, dtype: object model_data = model_data[model_data['HINC'] != 'null'] model_data['HINC'] = model_data['HINC'].astype(float)
第3步:單變量分析
在建模之前需要先對每個自變量進行單變量分析,確定是否納入模型,變量分為離散變量和連續(xù)變量兩種,其分析方式也有所不同。
對于離散變量,我們使用k-1自由度的卡方檢驗,其中k為離散變量的值個數(shù);對于連續(xù)變量,比較簡單的分析方法是直接對單變量進行邏輯回歸,查看回歸系數(shù)的顯著性,根據(jù)AUC分析自變量對y的解釋能力。
保留顯著的自變量進入到后續(xù)的操作,如代碼清單1-5所示。
代碼清單1-5 單變量分析
# 離散變量分析 crosstab = pd.crosstab( model_data['y'],model_data['PSIZE']) p=scipy.stats.chi2_contingency(crosstab)[1] print("PSIZE:",p) # PSIZE: 0.0024577358937625327 # 連續(xù)變量分析 logistic = sm.Logit(model_data['y'],model_data['INVT_CAR']).fit() p = logistic.pvalues['INVT_CAR'] y_predict = logistic.predict(model_data['INVT_CAR']) AUC = metrics.roc_auc_score(model_data['y'],y_predict) result = 'INVT_CAR:'+str(p)+' AUC:'+str(AUC) print(result) # INVT_CAR:2.971604856310474e-09 AUC:0.6242563699629587
第4步:共線性檢驗
由于LR模型是一種廣義線性模型,變量間嚴重的共線性會對參數(shù)估計的準(zhǔn)確性及泛化能力產(chǎn)生影響,因此需要對自變量間的共線性進行分析。
若vif值大于10,可認為變量間具有很強的共線性,需要進行相應(yīng)的處理,最簡單的處理方式就是進行自變量剔除,保留單變量分析中AUC最大的變量。共線性檢驗示例如代碼清單1-6所示。
代碼清單1-6 共線性檢驗
from statsmodels.stats.outliers_influence import variance_inflation_factor #共線性診斷包 X = raw_data[[ 'INVT_AIR', 'INVT_TRAIN','INVT_BUS', 'INVT_CAR']] vif = pd.DataFrame() vif['VIF Factor'] = [variance_inflation_factor(X.values, i) for i in range(X.shape[1])] vif['features'] = X.columns print('================多重共線性==============') print(vif) # | 0 14.229424 INVT_AIR # | 1 72.782420 INVT_TRAIN # | 2 80.279742 INVT_BUS # | 3 35.003438 INVT_CAR
第5步:模型搭建
這里需要注意的是,對于3值及以上的離散變量要進行啞變量處理(需要記住去掉的枚舉值),并且增加截距項Intercept,同時進行訓(xùn)練集和測試集的拆分(目的是防止模型的過擬合,確定分析結(jié)論可以泛化),代碼如清單1-7所示。
代碼清單1-7 搭建LR模型
# 建模數(shù)據(jù)構(gòu)造 X = model_data[[ 'HINC','PSIZE','TTME_TRAIN' , 'INVC_CAR']] y = raw_data['y'] # 啞變量處理 dummies = pd.get_dummies(X['PSIZE'], drop_first=False) dummies.columns = [ 'PSIZE'+'_'+str(x) for x in dummies.columns.values] X = pd.concat([X, dummies], axis=1) X = X.drop('PSIZE',axis=1) # 刪去原離散變量 X = X.drop('PSIZE_4',axis=1) # 刪去過于稀疏字段 X = X.drop('PSIZE_5',axis=1) # 刪去過于稀疏字段 X = X.drop('PSIZE_6',axis=1) # 刪去過于稀疏字段 X['Intercept'] = 1 # 增加截距項 # 訓(xùn)練集與測試集的比例為80%和20% X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.8, random_state=1234) # 建模 logistic = sm.Logit(y_train,X_train).fit() print(logistic.summary2()) # 重要返回信息 # | ------------------------------------------------------------------ # | Coef. Std.Err. z P>|z| [0.025 0.975] # | ------------------------------------------------------------------ # | HINC 0.0264 0.0100 2.6477 0.0081 0.0068 0.0459 # | TTME_TRAIN 0.0389 0.0195 1.9916 0.0464 0.0006 0.0772 # | INVC_CAR -0.0512 0.0204 -2.5103 0.0121 -0.0913 -0.0112 # | PSIZE_1 -0.3077 0.7317 -0.4206 0.6741 -1.7419 1.1264 # | PSIZE_2 -1.0800 0.6417 -1.6829 0.0924 -2.3378 0.1778 # | PSIZE_3 -0.7585 0.7582 -1.0004 0.3171 -2.2444 0.7275 # | Intercept -1.8879 1.1138 -1.6951 0.0901 -4.0708 0.2950 # | ================================================================= # 模型評價 print("========訓(xùn)練集AUC========") y_train_predict = logistic.predict(X_train) print(metrics.roc_auc_score(y_train,y_train_predict)) print("========測試集AUC========") y_test_predict = logistic.predict(X_test) print(metrics.roc_auc_score(y_test,y_test_predict)) # | ========訓(xùn)練集AUC======== # | 0.7533854166666667 # | ========測試集AUC======== # | 0.6510263929618768
第6步:模型修正
可以看到由于不顯著變量的影響,模型的測試集AUC與訓(xùn)練集AUC存在較大差異,我們需要對不顯著變量進行剔除。可以看到,新建模型的擬合優(yōu)度尚可(AUC接近0.75),且自變量顯著(p < 0.05),可以進行后續(xù)解讀,如代碼清單1-8所示。
代碼清單1-8 修正LR模型
X = X.drop('PSIZE_1',axis=1) X = X.drop('PSIZE_2',axis=1) X = X.drop('PSIZE_3',axis=1) # 訓(xùn)練集與測試集的比例為80%和20% X_train, X_test, y_train, y_test = train_test_split(X, y, train_size = 0.8, random_state=1234) # 建模 logistic = sm.Logit(y_train,X_train).fit() print(logistic.summary2()) # 重要返回信息 # | ------------------------------------------------------------------ # | Coef. Std.Err. z P>|z| [0.025 0.975] # | ------------------------------------------------------------------ # | HINC 0.0266 0.0096 2.7731 0.0056 0.0078 0.0454 # | TTME_TRAIN 0.0335 0.0161 2.0838 0.0372 0.0020 0.0650 # | INVC_CAR -0.0450 0.0168 -2.6805 0.0074 -0.0778 -0.0121 # | Intercept -2.3486 0.8275 -2.8384 0.0045 -3.9704 -0.7269 # | ================================================================= print("========訓(xùn)練集AUC========") y_train_predict = logistic.predict(X_train) print(metrics.roc_auc_score(y_train,y_train_predict)) print("========測試集AUC========") y_test_predict = logistic.predict(X_test) print(metrics.roc_auc_score(y_test,y_test_predict)) # | ========訓(xùn)練集AUC======== # | 0.7344618055555555 # | ========測試集AUC======== # | 0.7419354838709677
第7步:模型解讀
DCM模型解讀的對象可以分為概率(probability)和幾率(odds)。在本例中,概率為“選擇自駕的概率”,幾率為“選擇自駕的概率/不選擇自駕的概率”。限于模型的數(shù)學(xué)性質(zhì),無法直接從模型參數(shù)中快速得到概率,需要經(jīng)過一定計算,這部分會在復(fù)雜的MNL及NL模型中介紹。
得益于LR的數(shù)學(xué)性質(zhì),分析師可以基于模型參數(shù)直接對幾率進行解讀(這一點類似于線性回歸)。模型解讀的話術(shù)為“在其他條件保持不變的情況下,某因素增長一個單位(或?qū)傩詀相對屬性b),幾率會變化(增長或降低)多少”,計算公式如下。
連續(xù)變量:odd(xi+1)/odd(xi)-1=exp(βi)-1
離散變量:odd(xj=1)/odd(xj=0)-1=exp(βj)-1
例如,根據(jù)模型可知,在其他條件保持不變的情況下,家庭收入增長1個單位,選擇自駕的odds會變化,exp(β"HINC" )-1=exp(0.0266)-1=0.027,即增加0.027倍。
在其他條件保持不變的情況下,自駕成本上升1個單位,選擇自駕的odds會變化exp(β"INVC_CAR" )-1=exp(-0.0450)-1=-0.044,即下降0.044倍。
關(guān)于作者:周銀河,現(xiàn)任騰訊數(shù)據(jù)科學(xué)家,曾任滴滴數(shù)據(jù)科學(xué)家,清華大學(xué)商學(xué)院及哥倫比亞大學(xué)商學(xué)院商業(yè)分析碩士項目指導(dǎo)嘉賓。擁有豐富的數(shù)據(jù)分析、統(tǒng)計建模及實驗設(shè)計經(jīng)驗。
本文摘編自《數(shù)據(jù)科學(xué)工程實踐:用戶行為分析與建模、A/B實驗、SQLFlow》,經(jīng)出版方授權(quán)發(fā)布。
*博客內(nèi)容為網(wǎng)友個人發(fā)布,僅代表博主個人觀點,如有侵權(quán)請聯(lián)系工作人員刪除。