用戶消費行為的分析報告


數據來源 CDNow 網站的用戶購買明細,通過各個指標對用戶行為進行分析,可以更清楚了解用戶行為習慣,為進一步制定營銷策略提供依據。

具體指標包括:

  • 戶消費趨勢分析
  • 用戶個體消費分析
  • 用戶消費行為分析
  • 復購率和回購率分析
  • 留存率分析

一、理解數據

本數據集共有 6 萬條左右數據,數據為 CDNow 網站 1997年1月至1998年6月的用戶行為數據,共計 4 列字段,分別是:

  • user_id: 用戶ID
  • order_dt: 購買日期
  • order_products: 購買產品數
  • order_amount: 購買金額

二、清洗數據

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
plt.style.use('ggplot')

1. 數據加載

columns = ['user_id', 'order_dt', 'order_products', 'order_amount']
# 將 order_dt 轉化為日期數據類型格式
dateparse = lambda dates: pd.datetime.strptime(dates,'%Y%m%d')
df = pd.read_table(r'C:\Users\86134\Desktop\CDNOW_master.txt',
                   names = columns,parse_dates=['order_dt'],
                   sep = '\s+',date_parser=dateparse
                    )

3.數據探索

print(df.info())
print('-'*30)
print(df.isnull().sum())
print('-'*30)
print(df.describe())
print('-'*30)
print(df.head())
print('-'*30)
print(df.tail())
print('-'*30)

輸出

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 69659 entries, 0 to 69658
Data columns (total 4 columns):
user_id           69659 non-null int64
order_dt          69659 non-null datetime64[ns]
order_products    69659 non-null int64
order_amount      69659 non-null float64
dtypes: datetime64[ns](1), float64(1), int64(2)
memory usage: 2.1 MB
None
------------------------------
user_id           0
order_dt          0
order_products    0
order_amount      0
dtype: int64
------------------------------
            user_id  order_products  order_amount
count  69659.000000    69659.000000  69659.000000
mean   11470.854592        2.410040     35.893648
std     6819.904848        2.333924     36.281942
min        1.000000        1.000000      0.000000
25%     5506.000000        1.000000     14.490000
50%    11410.000000        2.000000     25.980000
75%    17273.000000        3.000000     43.700000
max    23570.000000       99.000000   1286.010000
------------------------------
   user_id   order_dt  order_products  order_amount
0        1 1997-01-01               1         11.77
1        2 1997-01-12               1         12.00
2        2 1997-01-12               5         77.00
3        3 1997-01-02               2         20.76
4        3 1997-03-30               2         20.76
------------------------------
       user_id   order_dt  order_products  order_amount
69654    23568 1997-04-05               4         83.74
69655    23568 1997-04-22               1         14.99
69656    23569 1997-03-25               2         25.74
69657    23570 1997-03-25               3         51.12
69658    23570 1997-03-26               2         42.96
------------------------------

通過數據探索我們發現 - 大部分訂單只購買了少量商品 (平均 2.4), 有一定極值干擾; - 用戶消費的金額比較穩定, 平均消費 35 元, 中位數在 35 元, 有一定極值干擾; - 數據呈右偏分布; - 沒有空缺數據,可以直接分析,但考慮到是按月分析,所以將日期進行解析(實際業務是否按月分析,取決於消費頻率) 。

# 解析日期
df['oreder_dt'] = pd.to_datetime(df.order_dt, format='%Y%m%d')
df['month'] = df.order_dt.values.astype('datetime64[M]')

三、用戶消費趨勢分析(按月)

  • 每月的產品購買數量
  • 每月的消費總金額
  • 每月的消費次數
  • 每月的消費人數

1.每月的產品購買數量

grouped_momnth = df.groupby('month')
plt.figure(1, figsize=(10, 4))
plt.title('每月用戶購買張數')
plt.ylabel('CD碟數(張)')
grouped_momnth.order_products.sum().plot()
plt.show()

 

 

 

從圖中可以看到,銷量在前幾個月異常高漲,並在3月達到最高峰,后續銷量較為穩定,且有輕微下降趨勢。

2.每月的消費金額

plt.figure(1, figsize=(10, 4))
plt.title('每月銷售額')
plt.ylabel('銷售額')
grouped_momnth.order_amount.sum().plot()
plt.show()

 

 

 

由圖可以看到,消費金額也一樣呈現早期銷售多,后期平穩下降趨勢,而且前三月數據都呈現出異常狀態,為什么呈現這樣的原因呢?我們可以假設前三個月有促銷活動,或者用戶本身出了問題,早期用戶有異常值。但這里只有消費數據,因此不能做出判斷。

3.每月消費次數

plt.figure(1, figsize=(10, 4))
plt.title('每月訂單數')
plt.ylabel('訂單數')
grouped_momnth.user_id.count().plot()
plt.show()

 

 

 

前三個月訂單數在 10000 筆左右,后續月份的平均消費訂單數則在 2500 筆左右。

4.每月消費人數

plt.figure(1, figsize=(10, 4))
plt.title('每月消費人數')
plt.ylabel('人數')
grouped_momnth.user_id.apply(lambda x: len(x.drop_duplicates())).plot()
plt.show()

 

 

 

每月消費人數低於每月消費次數,但差異不大。
前三個月每月消費人數在 8000~10000 之間,后續月份,平均消費人數在 2000 人不到。

四、用戶個體消費分析

  • 用戶消費金額,消費次數的描述統計
  • 用戶消費金額和購買數量散點圖
  • 用戶消費分布圖
  • 用戶累計消費金額的占比(百分之多少的用戶占了百分之多少的消費)

1.用戶消費金額,消費次數的描述統計

grouped_user = df.groupby('user_id')

 

從用戶角度

  • 用戶數量:23570,每位用戶平均購買 7 張 CD,但是中位數值只有3,且有狂熱用戶購買了1033 張。平均值大於中位數,是右偏分布,說明小部分用戶購買了大量的 CD。

從消費金額角度

  • 用戶平均消費 106 元,中位值只有 43,且有土豪用戶消費 13990,結合分位數和最大值看,平均數僅和 75 分位接近,肯定存在小部分的高頻消費用戶。
plt.figure(figsize=(12,4))
plt.subplot(121)
plt.scatter(x = 'order_amount', y = 'order_products',data=df)
plt.xlabel('每筆訂單消費金額')
plt.ylabel('每筆訂單購買數量')

plt.subplot(122)
plt.scatter(x = 'order_amount',y = 'order_products', 
            data = grouped_user.sum()) 
plt.xlabel('每位用戶消費金額')
plt.ylabel('每位用戶購買數量')
plt.show()

 

 

 

從每筆訂單的散點圖觀察

  • 訂單消費金額和訂單商品有規律性,每個商品均價 10元,且訂單極值較少,超出 1000 的不多,所以不是造成異常波動的原因。

從每位用戶的消費散點圖觀察

  • 用戶比較健康,且線性關系比訂單更強,由於這是 CD 網站的銷售數據,商品較為單一,金額和商品的關系因此呈線性關系,離群點不多。

3.用戶消費分布圖

為了更好的觀察消費能力極強的用戶,因為數量不多,所以用直方圖

plt.figure(figsize=(12, 4))
plt.subplot(121)
ax = grouped_user.order_amount.sum().hist(bins=50)
ax.set_xlabel('金額(美元)')
ax.set_ylabel('用戶人數')
ax.set_xlim(0, 2000)
ax.set_title('用戶消費金額分布圖')

plt.subplot(122)
ax1 = grouped_user.order_products.sum().hist(bins = 50)

ax1.set_xlabel('CD 數(張)')
ax1.set_ylabel('用戶人數')
ax1.set_xlim(0, 150)
ax1.set_title('購買 CD 數分布圖')
plt.show()

 

 

 

從直方圖可知,用戶消費金額,絕大部分呈現集中趨勢,大部分購買CD數20張內,高消費用戶在圖上幾乎看不到,這是符合消費行為的行業規律。

4.用戶累計消費金額的占比

user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum())
user_cumsum
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x:x.cumsum() / x.sum())
user_cumsum.reset_index().order_amount.tail()
# 輸出
23565    0.985405
23566    0.988025
23567    0.990814
23568    0.994404
23569    1.000000
Name: order_amount, dtype: float64
user_cumsum = grouped_user.sum().sort_values('order_amount').apply(lambda x:(x.cumsum() / x.sum())*100)
user_cumsum.reset_index().order_amount.plot()
plt.title('用戶累計消費金額占比')
plt.xlabel('人數')
plt.ylabel('百分比 %')
plt.show()

 

 

 

通過分析累計銷售額占比,從圖中不難看出用戶消費行為基本符合二八定律,80% 的用戶貢獻了 25% 的消費金額,而 60% 的消費由前 5000 名用戶貢獻。所以只要維護了這5000 名用戶,就能完成 60% 的KPI。

五、用戶消費行為

  • 用戶第一次消費(首購)時間
  • 用戶最后一次消費時間
  • 用戶分層
    • RFM (RFM模型是衡量客戶價值和客戶創利能力的重要工具和手段)
    • 新、老、活躍、回流、流失

 

  • 用戶購買周期(按訂單)
    • 用戶消費周期描述
    • 用戶消費周期分布
  • 用戶生命周期(按第一次&最后一次消費)
    • 用戶生命周期描述
    • 用戶生命周期分布

1.用戶首購時間

grouped_user.min().month.value_counts()
# 輸出
1997-02-01    8476
1997-01-01    7846
1997-03-01    7248
Name: month, dtype: int64
grouped_user.min().order_dt.value_counts().plot() # 首購
plt.show()

 

 

 

 

2.用戶最后一次購買時間

grouped_user.month.max().value_counts()
# 輸出
1997-02-01    4912
1997-03-01    4478
1997-01-01    4192
1998-06-01    1506
1998-05-01    1042
1998-03-01     993
1998-04-01     769
1997-04-01     677
1997-12-01     620
1997-11-01     609
1998-02-01     550
1998-01-01     514
1997-06-01     499
1997-07-01     493
1997-05-01     480
1997-10-01     455
1997-09-01     397
1997-08-01     384
Name: month, dtype: int64
grouped_user.max().order_dt.value_counts().plot() # 最后一次消費
plt.show()

 

 

 

通過以上兩個維度觀察,可以看出

  • 用戶第一次購買分布,集中在前三個月,其中,在 2 月 11 日至 2 月 25 日有一次劇烈波動。
  • 用戶最后一次購買的分布比第一次分布廣,但是大部分最后一次購買也集中在前三個月,說明忠誠用戶較少,隨着時間的遞增,最后一次購買數在遞增,消費呈現流失上升的趨勢,所以可以推測,這份數據選擇的是前三個月消費的用戶在后面18個月的跟蹤記錄數據,前三個月消費金額和購買數量的異常趨勢獲得解釋。

3.用戶分層

3.1 構建RFM 模型

  • Recency Frequency Monetary
rfm = df.pivot_table(index = 'user_id',
                    values = ['order_products', 'order_amount', 'order_dt'],
                    aggfunc = {'order_dt':'max',
                               'order_amount':'sum',
                               'order_products':'sum'
                              })
rfm.head()

 

 

 

 

rfm['R'] = -(rfm.order_dt - rfm.order_dt.max()) / np.timedelta64(1, 'D')
rfm.rename(columns = {'order_products': 'F', 'order_amount':'M'},
                 inplace=True)
rfm.head()

 

 

def rfm_func(x):
    level = x.apply(lambda x:'1' if x>=1 else '0')
    label = level.R + level.F + level.M
    d = {
        '111':'重要價值客戶', 
        '011':'重要保持客戶',
        '101':'重要挽留客戶',
        '001':'重要發展客戶',
        '110':'一般價值客戶',
        '010':'一般保持客戶',
        '100':'一般挽留客戶',
        '000':'一般發展客戶'
        }
    result = d[label]
    return result

rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)
rfm.head()

 

 

 

 

rfm.groupby('label').sum()

 

 

 

 

for label,gropued in rfm.groupby('label'):
    x= gropued['F']
    y = gropued['R']

    plt.scatter(x,y,label = label) # 利用循環繪制函數
plt.legend(loc='best') # 圖例位置
plt.xlabel('Frequency')
plt.ylabel('Recency')
plt.show()

 

 

 

從 RFM 分層可知,大部分用戶為重要保持客戶,但這是因為極值存在,所以 FRM 的划分應按照業務為准划分

  • 盡量用小部分的用戶覆蓋大部分的額度
  • 不要為了數據好看而划分等級

 

3.2 按新、活躍、回流、流失分層用戶

# 通過每月是否消費來划分用戶
pivoted_counts = df.pivot_table(index = 'user_id',
                                columns = 'month',
                                values = 'order_dt',
                                aggfunc = 'count').fillna(0)
pivoted_counts.columns = df.month.sort_values().astype('str').unique()
pivoted_counts.head()

 

 

 

 

df_purchase = pivoted_counts.applymap(lambda x: 1 if x> 0 else 0)
df_purchase.tail()

 

 

 

 

def active_status(data):
    status = []
    for i in range(18): 

        if data[i] == 0:
            if len(status) > 0:
                if status[i-1] == 'unreg': 
                    status.append('unreg')
                else:
                    status.append('unactive') 
            else:  
                status.append('unreg')

        else:
            if len(status) == 0:
                status.append('new') 
            else:
                if status[i-1] == 'unactive':
                    status.append('return') 
                elif status[i-1] == 'unreg':
                    status.append('new')
                else:
                    status.append('active')
    return pd.Series(status,df_purchase.columns)

若本月沒有消費

  • 若之前未注冊,則依舊未注冊
  • 若之前有消費,則為流失/為活躍
  • 其他情況,未注冊

若本月消費

  • 若是第一次消費,則為新用戶
  • 如果之前有過消費,上個月為不活躍,則為回流
  • 如果上個月未注冊,則為新用戶
  • 除此之外,為活躍
purchase_states = df_purchase.apply(active_status,axis = 1)
purchase_states.tail()

 

 

 

 

purchase_states_ct = purchase_states.replace('unreg',np.NaN).apply(lambda x:pd.value_counts(x))
purchase_states_ct

 

 

 

unreg 狀態排除掉,是未來才成為新用戶,作為不同分呈用戶每月統計量。

# 轉置后方便觀察
purchase_states_ct.fillna(0).T

 

 

 

 

# 繪制面積圖
purchase_states_ct.fillna(0).T.plot.area(figsize = (12, 6))
plt.show()

 

 

 

由面積圖,藍色和灰色區域占大面積,可以不看,因為這只是某段時間消費過的用戶的后續行為。其次紅色代表的活躍用戶非常穩定,是屬於核心用戶,以及紫色的回流用戶,這兩個分層相加,就是消費用戶人數占比(后期沒用新客)

3.3回流用戶占比

plt.figure(figsize=(20, 4))
rate = purchase_states_ct.fillna(0).T.apply(lambda x: x/x.sum())
plt.plot(rate['return'],label='return')
plt.plot(rate['active'],label='active')
plt.legend()
plt.show()

 

 

 

 

  • 回流用戶比:某個時間段內回流用戶在總用戶中的占比
    • 由圖可知,用戶每月回流用戶比占 5% ~ 8% 之間,有下降趨勢,說明客戶有流失傾向。

 

  • 回流用戶率:上月有多少不活躍用戶在本月消費
    • 由於這份數據的不活躍用戶量基本不變,所以這里的回流率,也近似等於回流比

 

  • 活躍用戶比:某個時間段內活躍用戶在總用戶中的占比。
    • 活躍用戶的占比在 3% ~ 5%間,下降趨勢更顯著,活躍用戶可以看作連續消費用戶,忠誠度高於回流用農戶。

結合活躍用戶和回流用戶看,在后期的消費用戶中,60%是回流用戶,40%是活躍用戶,整體用戶質量相對不錯。也進一步說明前面用戶消費行為分析中的二八定律,反應了在消費領域中,狠抓高質量用戶是不變的道理。

4.用戶購買周期

# 訂單時間間隔
order_diff = grouped_user.apply(lambda x:x.order_dt - x.order_dt.shift())
order_diff.head(10)

 

 

 

 

order_diff.describe()

 

 

 

 

# 訂單周期分布圖
(order_diff / np.timedelta64(1, 'D')).hist(bins = 20)
plt.show()

 

 

 

  • 訂單周期呈指數分布
  • 用戶的平均購買周期是 68 天
  • 絕大部分用戶的購買周期低於 100 天
  • 用戶生命周期圖是典型的長尾圖,大部分用戶的消費間隔確實比較短。不妨將時間召回點設為消費后立即贈送優惠券,消費后10天詢問用戶CD怎么樣,消費后30天提醒優惠券到期,消費后60天短信推送。

5.用戶生命周期

# 最后一次購買的時間減去首購時間
user_life = grouped_user.order_dt.agg(['min', 'max'])
user_life.head()

 

 

 

 

# 只消費過一次的用戶占比
(user_life['min'] == user_life['max']).value_counts().plot.pie()
plt.show()
(user_life['max'] - user_life['min']).describe()

 

 

 

通過描述可知,用戶平均生命周期 134 天,比預想高,但是平均數不靠譜,中位數 0 天,大部分用戶第一次消費也是最后一次,這批屬於低質量用戶,而最大的是 544 天,幾乎是數據集的總天數,這用戶屬於核心用戶。

因為數據中的用戶都是前三個月第一次消費,所以這里的生命周期代表的是1月~3月用戶的生命周期。因為用戶會持續消費,這段時間過后還會繼續消費,用戶的平均生命周期會增長。

plt.figure(figsize=(20, 4))
plt.subplot(121)
((user_life['max'] - user_life['min']) / np.timedelta64(1, 'D')).hist(bins = 15)
plt.title('二次消費以上用戶的生命周期直方圖')
plt.xlabel('天數')
plt.ylabel('人數')

# 過濾生命周期為0 的
plt.subplot(122)
u_l = ((user_life['max'] - user_life['min']).reset_index()[0] / np.timedelta64(1, 'D'))
u_l[u_l > 0].hist(bins = 40)
plt.title('二次消費以上用戶的生命周期直方圖')
plt.xlabel('天數')
plt.ylabel('人數')
plt.show()

 

 

 

通過兩圖對比看出,過濾掉周期為 0 的用戶后,圖像呈雙峰結構,雖然還是有不少用戶生命周期趨於 0 天,但是相比第一幅圖,靠譜多了。部分低質用戶,雖然消費兩次,但還是不能持續消費,要想提高用戶轉化率,應該用戶首次消費 30 天內盡量引導,少部分用戶集中在 50 - 300 天,屬於普通用戶,忠誠度一般。集中在 400 天以后的,是高質量用戶了,后期人數還在增加,這批用戶已經屬於核心用戶了,忠誠度極高,盡量維護這批用戶的利益。

# 消費兩次以上用戶平均生命周期
u_l[u_l > 0].mean()

# 輸出
276.0448072247308

消費兩次以上的用戶平均生命周期是 276 天,遠高於總體,所以如何在用戶首次消費后引導其進行多次消費,可以有效提高用戶生命周期。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM