用戶行爲與生存分析

生存分析的來歷

生存分析(Survival Analysis)來源於基礎醫學領域,最先用來研究各類治療方案對病人壽命的影響。而壽命則用一個end event(死亡)的方式衡量。基本定義以下:python

T爲標記事件發生的時間。git

  • 生存函數(Survival Function)。用來描述未發生end event的樣本的比例隨時間變化的趨勢

    $S(t) = P(T > t)$github

  • Hazard函數(Hazard Function)。描述end event發生的機率變化率

    $\lambda (t) = {lim}_{h\to 0} \frac{P(t \le T < t + h | T \ge t)}{h}$函數

  • 兩個函數之間的關係:

    $S(t) = e^{-\int_{0}^t \lambda (s)ds}$ui

生存分析與新用戶行爲

然而,生存分析的定義自己讓它和不少用戶行爲事件自己發生聯繫。譬如,用戶流失和生存分析研究的概念徹底一致,而常見的流失分析,可能會存在如下問題:spa

  1. 沒法提供每個時刻流失發生的機率
  2. 很難具備預測性
  3. 多個產品/A-B testing時很難互相作出定量比較。

而生存分析自己就會對以上三個內容作出預測,此外,對Customer Lifetime Value能提出一些更有價值的洞識。3d

但本文試圖擴展生存分析的試用範圍,任何具備觸發時間特徵的事件,均可以採用生存分析的方式作出分析,譬如:code

  1. 用戶留存
  2. 用戶轉化
  3. 用戶點擊
  4. ...

本文以常見的購買行爲的轉化爲例,介紹生存分析的某些應用。blog

用戶轉化

代碼以 jupyter notebook的形式放在 github這裏

前期構思

本實例是研究,用戶從註冊時開始,隨時間變化其轉化率會有何種變化,考慮屆時提供一些運營策略。常規計算本任務轉化率的方式是:three

轉化率 = # 轉化用戶數 / # 總用戶數數

這個轉化率每每很難提供更多的洞識,咱們沒法給出自動化運營能夠介入的時間要素。而生存分析從本質上說,偏偏是研究一個發生事件的機率隨時間發生的變化,在此項任務中,事件顯然就是轉化。基於這種思想,咱們作出以下分析。

數據樣例

生存分析須要以一個用戶爲單位,提取參與實驗的時間(這裏就是註冊時間),終止實驗/end event發生時間(這裏就是指數據採集的截止日期和用戶發生轉化的時間),以及最後是否發生end event的標記。

所以咱們採集了以下數據。其中sexbirth_yearprovince三個字段用之後面的分析,duration則是到事件發生時總共花費的時間,即test_last_time - signup_time

user_id signup_time end_time test_last_time buy_time sex birth_year province have_bought duration
0 513336 2017-10-30 21:58:04.323000 2017-10-30 22:03:54.430000 2018-06-01 00:00:00 2017-10-30 22:03:54.430000 1991 山東 True 0.00405216
1 513340 2017-10-30 22:14:35.853000 2017-10-30 22:45:10.243000 2018-06-01 00:00:00 2017-10-30 22:45:10.243000 1988 安徽 True 0.0212314
2 513353 2017-10-31 07:29:04.293000 2018-06-01 00:00:00 2018-06-01 00:00:00 NaT nan nan nan False 212.688
3 513370 2017-10-31 10:45:45.586000 2018-06-01 00:00:00 2018-06-01 00:00:00 NaT 1979 河南 False 212.552
4 513387 2017-10-31 13:00:32.360000 2017-10-31 13:09:38.100000 2018-06-01 00:00:00 2017-10-31 13:09:38.100000 1992 山東 True 0.00631644

分析轉化率隨註冊後時間發生的變化

Python比較完整的支持生存分析的包是Liflinesscikit-survival。二者之間,對分析友好的方案是前者,咱們在本博文中,也主要採用該模塊進行分析。

from lifelines import NelsonAalenFitter, CoxPHFitter, KaplanMeierFitter
from lifelines.statistics import logrank_test

首先,咱們須要查看用戶的未轉化率(有點繞口),這直接能夠用生存分析自己的定義來實現。

kmf = KaplanMeierFitter()
kmf.fit(df['duration'], event_observed=df['have_bought'], label='all')
kmf.plot()

image-20180805225520337.png
clipboard.png

顯然,咱們能夠發現,在50天后,基本上變化不明顯了,最初的50天內,用40%多的用戶發生轉化。固然,這一圖示並不直觀,咱們能夠用1 - 未轉化率=轉化率的方式來從新繪製轉化率曲線

(1 - kmf.survival_function_).plot()

image-20180805230116015.png
clipboard.png

顯然,這張圖已經能夠參與到運營決策中取了,圖中顯示,用戶會在前10天內轉化,後期變化不在明顯。但咱們能夠經過生存分析獲得更多有意思的結論。

一個例子就是分析不一樣產品的生存曲線圖來分析產品之間的好壞(在此不作示範),一個就是用戶自己特徵對轉化的影響。在此,咱們以性別爲例,分析性別對用戶更早決定購買產品/轉化之間有何有何關係。

ax = subplot(111)

t = np.linspace(0, 50, 51)
kmf.fit(df[df['sex'] == '男']['duration'], event_observed=df[df['sex'] == '男']['have_bought'], timeline=t, label="male")
ax = kmf.plot(ax=ax)

kmf.fit(df[df['sex'] == '女']['duration'], event_observed=df[df['sex'] == '女']['have_bought'], timeline=t, label="female")
ax = kmf.plot(ax=ax)

plt.ylim(0,1)
plt.title("not buying rate between two gender");

image-20180805230614522.png
clipboard.png

ax = subplot(111)

t = np.linspace(0, 50, 51)
kmf.fit(df[df['sex'] == '男']['duration'], event_observed=df[df['sex'] == '男']['have_bought'], timeline=t, label="male")
ax = (1 - kmf.survival_function_).plot(ax=ax)

kmf.fit(df[df['sex'] == '女']['duration'], event_observed=df[df['sex'] == '女']['have_bought'], timeline=t, label="female")
ax = (1 - kmf.survival_function_).plot(ax=ax)

plt.ylim(0,1)
plt.title("conversion rate between two gender");

image-20180805230718723.png
clipboard.png

顯然,咱們從圖中能夠發現,女性更傾向於更快相信此產品,更早時間而且更多比例的發現轉化。接下來,咱們能夠利用自帶的log-rank test對二者是否差別顯著作預測。

logrank_test(event_times_A=df[df['sex']=='男']['duration'], event_observed_A=df[df['sex']=='男']['duration'],
            event_times_B=df[df['sex']=='女']['duration'], event_observed_B=df[df['sex']=='女']['duration'])
<lifelines.StatisticalResult: 

t_0=-1, alpha=0.95, null_distribution=chi squared, df=1

test_statistic      p     
       82.2898 0.0000  ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 
>

顯然,差別是顯著的。

分析轉化率的變化率

在此,咱們使用Nelson Aslen方法分析轉化率的變化率隨時間的變化(即Hazard函數)。

naf = NelsonAalenFitter()
naf.fit(df['duration'], event_observed=df['have_bought'], timeline=t, label='all')
naf.plot_hazard(bandwidth=20)

image-20180805231451494.png
clipboard.png

圖中能夠看出,轉化率的變化在前5天內略微提升,隨後斷崖式減小,大概在20天左右區域和緩。換用運營的術語,前五天內用戶對產品的信任度略微增長,使得更有可能購買產品;但超過五天尚未購買意願的人,購買發生的可能性隨時間遞減。

一個可能的運營策略就是在第5天作出一些行爲,增長用戶的購買意願,從而達到提升用戶的生命週期的總價值。

固然,咱們如同上面板塊同樣,也不叫一下性別差別。

image-20180805231922162.png
clipboard.png

顯然,女性創建信任的速度更快,可是大體都是以5天爲界,在5天時沒有發生購買行爲,後期發生的機率會愈來愈小。

生存分析的迴歸分析

在此,咱們還介紹一種對於不一樣變量對生存曲線影響的分析方法,並能夠做爲預測用戶是否可能發生轉化的模型——Cox PH模型。其基本假設是:

$\lambda (t, X) = \lambda_0(t) exp(\beta X)$

即假設待研究的變量不影響到生存模型的形狀,而形狀只有獨立的$$\lambda_0(t)$$決定(即只和時間有關)。對此,咱們須要對變量進行形狀上的驗證來判斷該模型的有效性。在此咱們只作性別和用戶年齡的迴歸分析。

上面已經驗證過性別的轉化率的形狀,咱們使用雙對數繪製對年齡(出生年)的影響。

kmf0 = KaplanMeierFitter()
kmf0.fit(cph_train_df[cph_train_df['birth_year'] == 1960]['duration'], event_observed=cph_train_df[cph_train_df['birth_year'] == 1960]['have_bought'])

kmf1 = KaplanMeierFitter()
kmf1.fit(cph_train_df[cph_train_df['birth_year'] == 1970]['duration'], event_observed=cph_train_df[cph_train_df['birth_year'] == 1970]['have_bought'])

fig, axes = plt.subplots()
kmf0.plot_loglogs(ax=axes)
kmf1.plot_loglogs(ax=axes)

axes.legend(['1960', '1970'])

plt.show()

image-20180805233353267.png
clipboard.png

結果不是很符合預設,但因爲演示須要,假設數據符合咱們的假定,並且咱們僅作線性模型。

cph = CoxPHFitter()
cph.fit(cph_train_df, duration_col='duration', event_col='have_bought', show_progress=True)
cph.print_summary()
n=10000, number of events=7683

              coef  exp(coef)  se(coef)       z      p  lower 0.95  upper 0.95     
birth_year -0.0084     0.9916    0.0010 -8.7945 0.0000     -0.0103     -0.0066  ***
sex        -0.1676     0.8457    0.0241 -6.9492 0.0000     -0.2149     -0.1203  ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1 

Concordance = 0.528
Likelihood ratio test = 124.891 on 2 df, p=0.00000

咱們能夠發現,sex影響的項更大,參數都是顯著的。以後,咱們就能夠用cph的相關函數對數據進行預測。咱們在此用plot_covariate_group函數來展現不一樣屬性的影響:

cph.plot_covariate_groups('birth_year', [1960, 1970, 1980, 1990])
cph.plot_covariate_groups('sex', [0, 1])

image-20180805234322978.png
clipboard.png

image-20180805234340974.png
clipboard.png

顯然,年齡越大、性別爲女性越容易信任平臺,更早的作出購買行爲。

結語

這裏,咱們用生存分析解決並使用在用戶行爲分析中。給出更多可能有助於運營以及理解用戶畫像的洞識結論。

References and Recommending Reading List

相關文章
相關標籤/搜索