騰訊數(shù)據(jù)科學(xué)家手把手教你做用戶行為分析(案例:出行選擇)
導(dǎo)讀:生活中的選擇行為無處不在,數(shù)據(jù)分析師面對(duì)的商業(yè)場(chǎng)景也存在大量的用戶選擇問題。系統(tǒng)、科學(xué)地研究用戶選擇問題,得到選擇行為背后的客觀規(guī)律并基于這些規(guī)律提出業(yè)務(wù)優(yōu)化策略,這些能力對(duì)于數(shù)據(jù)分析師非常重要且極具價(jià)值。

可以選擇的交通方式有哪些? 同程的人多不多? 需要在什么時(shí)間到達(dá)? 出行預(yù)算是多少? 公共交通的便捷程度? 出行方式是否受天氣影響?


消費(fèi)者在進(jìn)行實(shí)際消費(fèi)行為時(shí),若從備選方案中選擇了一個(gè)選項(xiàng),即為首選選項(xiàng),則該選項(xiàng)效用是最大的。 在給定的消費(fèi)者預(yù)算、商品價(jià)格等因素不變的情況下,如果消費(fèi)者購買了某種產(chǎn)品,那么他將始終做出相同的選擇。

決策者:一次選擇行為的主體(決策者屬性包括家庭收入、出行人數(shù)、天氣)。 備選項(xiàng)集合:飛機(jī)、火車、長途巴士、自駕車(不同決策者的備選項(xiàng)集合可以不同)。 備選項(xiàng)屬性:行程外耗時(shí)、行程中耗時(shí)、行程花費(fèi)、舒適性(不同備選項(xiàng)的屬性也可以不同)。 選擇準(zhǔn)則:效用的最大化準(zhǔn)則。 選擇結(jié)果:備選項(xiàng)中的一個(gè)選項(xiàng)(每個(gè)選擇過程均存在選擇結(jié)果)。
OBS_ID:離散,選擇行為ID HINC:連續(xù),家庭收入 PSIZE:連續(xù) or 離散,出行人數(shù) TTME_AIR:連續(xù),站點(diǎn)等待時(shí)間(飛機(jī)) TTME_TRAIN:連續(xù),站點(diǎn)等待時(shí)間(火車) TTME_BUS:連續(xù),站點(diǎn)等待時(shí)間(長途巴士) INVC_AIR:連續(xù),金錢成本(飛機(jī)) INVC_TRAIN:連續(xù),金錢成本(火車) INVC_BUS:連續(xù),金錢成本(長途巴士) INVC_CAR:連續(xù),金錢成本(自駕) INVT_AIR:連續(xù),行程中 -時(shí)間成本(飛機(jī)) INVT_TRAIN:連續(xù),行程中 -時(shí)間成本(火車) INVT_BUS:連續(xù),行程中 -時(shí)間成本(長途巴士) INVT_CAR:連續(xù),行程中 -時(shí)間成本(自駕) y:離散,是否選擇自駕

代碼清單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)練集/測(cè)試集構(gòu)造工具包
from sklearn import metrics # 引入模型評(píng)價(jià)指標(biāo)AUC計(jì)算工具包
import matplotlib.pyplot as plt # 引入繪圖軟件包
import scipy # 引入scipy軟件包完成卡方檢驗(yàn)
# 數(shù)據(jù)讀入
data_path = 'wide_data.csv'
raw_data = pd.read_table(data_path, sep=',', header=0)代碼清單1-4 數(shù)據(jù)預(yù)處理
# 1. 缺失值探查&簡(jiǎn)單處理
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() # 缺失值處理——?jiǎng)h除
model_data = model_data.fillna(0) # 缺失值處理——填充(零、均值、中位數(shù)、預(yù)測(cè)值等)
# 2. 數(shù)值型核查(連續(xù)變量應(yīng)為int64或float數(shù)據(jù)類型)
# 若上一步中存在應(yīng)為連續(xù)數(shù)值變量的字段為object,則執(zhí)行下列代碼,這里假設(shè)'HINC'存在為字符串'null'的值。
import re # 正則表達(dá)式工具包
float_patten = '^(-?\\d+)(\\.\\d+)?$' # 定義浮點(diǎn)數(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'] # 查看非浮點(diǎn)型數(shù)據(jù)
# | 2 null
# | Name: distance, dtype: object
model_data = model_data[model_data['HINC'] != 'null']
model_data['HINC'] = model_data['HINC'].astype(float)代碼清單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代碼清單1-6 共線性檢驗(yàn)
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
代碼清單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 # 增加截距項(xiàng)
# 訓(xùn)練集與測(cè)試集的比例為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
# | =================================================================
# 模型評(píng)價(jià)
print("========訓(xùn)練集AUC========")
y_train_predict = logistic.predict(X_train)
print(metrics.roc_auc_score(y_train,y_train_predict))
print("========測(cè)試集AUC========")
y_test_predict = logistic.predict(X_test)
print(metrics.roc_auc_score(y_test,y_test_predict))
# | ========訓(xùn)練集AUC========
# | 0.7533854166666667
# | ========測(cè)試集AUC========
# | 0.6510263929618768
代碼清單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)練集與測(cè)試集的比例為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("========測(cè)試集AUC========")
y_test_predict = logistic.predict(X_test)
print(metrics.roc_auc_score(y_test,y_test_predict))
# | ========訓(xùn)練集AUC========
# | 0.7344618055555555
# | ========測(cè)試集AUC========
# | 0.7419354838709677連續(xù)變量:odd(xi+1)/odd(xi)-1=exp(βi)-1 離散變量:odd(xj=1)/odd(xj=0)-1=exp(βj)-1

評(píng)論
圖片
表情
