利用Python進行用戶消費行爲分析(CDNOW_master)

用戶消費行爲的分析報告

  想必大家對於CD用戶消費者行爲的分析已經見得多了,這裏就不再一一敘述,這裏主要是作爲我的一個小練習,來提高自己處理業務的能力。

  項目需求如下:

(1)用戶消費趨勢分析

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

(2)用戶個體消費行爲分析

  • 用戶消費金額和消費總數的描述統計
  • 用戶消費金額和消費總數的散點圖
  • 用戶消費金額和消費總數的分佈圖
  • 用戶累計消費金額的佔比

(3)用戶消費行爲分析

  • 用戶第一次消費時間(用戶首次購買產品的時間)
  • 用戶最後一次消費時間
  • 新老客消費佔比
  • 用戶分層(RFM模型)

獲取數據

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False
%matplotlib inline
columns = ['user_id','order_dt','order_products','order_amount']
CDNOW = pd.read_table('./CDNOW_master.txt',sep='\s+',names=columns)  # \s+多個空格進行分割,+是空格匹配 

CDNOW.head()
user_id order_dt order_products order_amount
0 1 19970101 1 11.77
1 2 19970112 1 12.00
2 2 19970112 5 77.00
3 3 19970102 2 20.76
4 3 19970330 2 20.76

  數據來源CDNow網站的用戶購買明細,主要包括以下幾個字段:

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

數據處理

  • 檢查數據是否有空值
# CDNOW.info()
CDNOW.isnull().any()
user_id           False
order_dt          False
order_products    False
order_amount      False
dtype: bool

  用CDNOW.info()可以發現order_dt的類型爲int型,需要轉換爲日期類型

CDNOW['order_dt'] = pd.to_datetime(CDNOW['order_dt'],format='%Y%m%d')

  添加一列month,方便後面進行分析

CDNOW['month'] = CDNOW['order_dt'].values.astype('datetime64[M]')
CDNOW.head()
user_id order_dt order_products order_amount month
0 14048 1997-02-24 1 11.77 1997-03-01

  查看數據描述

print(CDNOW.mode())
CDNOW.describe()
   user_id   order_dt  order_products  order_amount      month
0    14048 1997-02-24               1         11.77 1997-03-01
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
  • 從用戶購買的商品數來看,平均每位用戶購買2.4個商品,標準差在2.3左右,證明有一定的偏差,而中位數爲2,3/4分位數爲3,說明了大多數的訂單量都不多,購買商品的最大值爲99。(中位數<均值,結合衆數可以發現,用戶購買的商品數分佈是屬於右偏分佈的,均值>中位數>衆數)。
  • 從用戶購買的金額來看,每個用戶貢獻的金額爲36,而最大值達到了1286,證明用戶的購買金額也是服從長尾分佈的,符合二八原則,即20%的用戶貢獻了80%的交易額。

數據分析

進行用戶消費趨勢的分析(按月)

  該部分內容主要是從用戶每月的消費總金額每月的消費次數每月的產品購買量以及每月的消費人數進行分析。

每月的消費總金額

   按月分組後,對order_amount進行求和,可以得到每月的消費總金額

group_month = CDNOW.groupby('month')  # 按月分組
group_month_amount = group_month['order_amount'].sum()

plt.style.use('ggplot')
group_month_amount.plot()
plt.xlabel('月份')
plt.ylabel('消費金額')
plt.title('每月的消費金額折線圖')

在這裏插入圖片描述

  從上圖可以看出,消費金額在1997年的前三個月達到了高峯。其中在3月份,銷售額達到了最大值,爲393155.27元,之後消費金額呈下降趨勢,並不斷趨於平穩的狀態。

每月的消費次數

   按月分組後,對order_product進行計數,可以得到每月的商品消費次數

group_month_order = group_month['order_products'].count()

group_month_count.plot(color='yellow')
plt.xlabel('月份')
plt.ylabel('消費次數')
plt.title('每月的消費次數')

在這裏插入圖片描述

   從上圖可以看出,消費次數在1997年的前三個月達到了最大值。其中在3月份達到了最大值,消費次數爲 11598次,平均消費次數在10000左右,而後續的月份平均消費次數在2500左右。

每月的商品購買量

   按月分組後,對order_product進行求和,可以得到每月的商品購買量。

group_month_product  = group_month['order_products'].sum()

group_month_product.plot(color='green')
plt.xlabel('月份')
plt.ylabel('商品購買量')
plt.title('每月的商品購買量')

在這裏插入圖片描述

  和前面的分析一樣,商品購買量的最大值出現在了1997年的前三個月中,其中最大值達到了26159,其中不斷下降並趨於平穩狀態。1997年的前三個月出現購買量劇增的情況,可能與當時的外部環境、內部環境等多方面因素都有一定的聯繫,這裏沒能拿到進一步的數據,無法詳細的進行分析。

每月的消費人數

使用nunique()去重

# group_userid_count = df.groupby(['month','user_id']).count().reset_index()
# group_userid_count = group_month['user_id'].nunique()
CDNOW.groupby('month').user_id.nunique().plot(color='blue')
plt.xlabel('月份')
plt.ylabel('消費人數')
plt.title('每月的消費人數')

在這裏插入圖片描述

  從上圖來看,每月的消費人數在1997年的前三個月出現了最大值,而後出現平穩的下降趨勢,由於其他的數據,暫時還沒有辦法分析出前三個月出現最大值的原因。

使用數據透視表進行求取

  也可以使用數據透視表進行求和、計數等操作

CDNOW.pivot_table(
    index='month',
    values= ['user_id','order_products','order_amount'],
    aggfunc={
        'order_products':'sum',
        'order_amount':'sum',
        'user_id':'count' }
).head()
order_amount order_products user_id
month
1997-01-01 299060.17 19416 8928
1997-02-01 379590.03 24921 11272
1997-03-01 393155.27 26159 11598
1997-04-01 142824.49 9729 3781
1997-05-01 107933.30 7275 2895

用戶個體消費行爲分析

  這部分內容主要從用戶消費金額和消費總數的描述統計用戶消費金額和消費總數的散點圖用戶消費金額和消費總數的分佈圖(二八法則)用戶累計消費金額的佔比這幾個方面進行分析。

用戶消費金額和消費總數的描述統計

  根據用戶的ID進行分組,分別對每個用戶購買的商品數、消費金額進行求和。

group_user = CDNOW.groupby('user_id')
group_user.sum().describe()
order_products order_amount
count 23570.000000 23570.000000
mean 7.122656 106.080426
std 16.983531 240.925195
min 1.000000 0.000000
25% 1.000000 19.970000
50% 3.000000 43.395000
75% 7.000000 106.475000
max 1033.000000 13990.930000

  每位用戶平均購買了7個產品,但是中位數只有3,結合衆數來看,說明用戶的消費次數時符合右偏分佈的,數據中存在極大值(小部分用戶購買了大量的產品),把平均值往右邊拉,提高了平均值。

  每位用戶的平均消費金額爲106元,中位數值爲43,和用戶的商品購買量一樣,符合右偏分佈,說明了存在極值的干擾,拉高了平均消費金額。

用戶消費金額和消費總數的散點圖

# group_user.sum().plot.scatter(x = 'order_amount',y='order_products')
plt.scatter(group_user.sum()['order_amount'],group_user.sum()['order_products'],c='blue')

plt.xlabel('消費金額')
plt.ylabel('消費總數')
plt.title('用戶消費金額和消費總數的散點圖')

在這裏插入圖片描述

   從上圖的散點圖中可以明顯的看出,數據中存在少數極值,這些極值可能會影響到分析的結果,故需要把極值過濾掉。

group_user_sum = group_user.sum().query('order_amount<4000')

plt.scatter(group_user_sum['order_amount'],group_user_sum['order_products'],c='red')
plt.xlabel('消費金額')
plt.ylabel('消費總數')
plt.title('用戶消費金額和消費總數的散點圖')

在這裏插入圖片描述

   從這張散點圖中可以看出,用戶的消費總數和用戶的消費總金額存在某種線性關係。

用戶消費金額和消費總數的分佈圖(二八法則)

# bins =(group_user.sum()['order_amount'].max()-group_user.sum()['order_amount'].min()) / len(group_user.sum()['order_amount'])
plt.figure(figsize=(16,9))
plt.subplot(2,2,1)
plt.hist(group_user.sum()['order_amount'],bins=20,color='green')
plt.xlabel('order_amount')
plt.ylabel('frequency')
plt.title('用戶消費金額的分佈圖')

plt.subplot(2,2,2)
plt.hist(group_user.sum()['order_products'],bins=20,color='red')
plt.xlabel('order_products')
plt.ylabel('frequency')
plt.title('用戶消費次數的分佈圖')

在這裏插入圖片描述

  從上述直方圖可以看出,用戶消費金額,絕大部分是呈現集中趨勢,小部分極值干擾了判斷,故需要過濾掉極值

plt.figure(figsize=(16,9))
plt.subplot(2,2,1)
group_user_sum = group_user.sum().query('order_amount<4000')

plt.hist(group_user_sum['order_amount'],bins=40,color='green')
plt.xlabel('order_amount')
plt.ylabel('frequency')
plt.title('用戶消費金額的分佈圖')

plt.subplot(2,2,2)
group_user_sum = group_user.sum().query('order_products<100')
plt.hist(group_user_sum['order_amount'],bins=40,color='red')
plt.xlabel('order_products')
plt.ylabel('frequency')
plt.title('用戶消費總數的分佈圖')

在這裏插入圖片描述

  從上面兩個圖中,可以明顯的看出,用戶消費金額的分佈和用戶消費總數的分佈都是符合右偏分佈的,和前面的描述性統計結果一致。

用戶累計消費金額的佔比

  累積消費金額的佔比是使用每次累積得到的消費金額除以總的消費金額。

# user_cumsum = group_user.sum().sort_values('order_amount').apply(lamda x: x.cumsum()/x.sum())
user_cumsum =group_user.sum().sort_values('order_amount').cumsum()/group_user.sum().sort_values('order_amount').sum()
user_cumsum.reset_index().head()
user_id order_products order_amount
0 10175 0.000006 0.0
1 4559 0.000012 0.0
2 1948 0.000018 0.0
3 925 0.000024 0.0
4 10798 0.000030 0.0

  order_amount出現0的情況可能是因爲商品有不同的優惠方式,所以出現購買金額出現0的情況

plt.plot(range(0,23570),user_cumsum['order_amount'],color='blue')

plt.xlabel('消費人數')
plt.ylabel('用戶累計消費金額佔比')
plt.title('用戶累計消費金額的佔比圖')

在這裏插入圖片描述

  按照用戶消費金額進行升序排列,並進行累計求和,可以發現:50%的用戶貢獻了15%的消費額度,而排名前5000的用戶就貢獻了60%的消費額(看頭部用戶)。

用戶消費行爲分析

  用戶消費行爲分析可以從用戶第一次消費時間用戶最後一次消費時間新老客消費比用戶分層用戶購買週期用戶生命週期進行分析。

用戶第一次消費時間(用戶首次購買產品的時間)

  先對用戶進行分組,然後取用戶的最小購買時間。

group_user = CDNOW.groupby('user_id')

group_user.min()['order_dt'].value_counts().plot()  # value_counts()根據日期進行計數
plt.xlabel('用戶第一次消費時間')
plt.ylabel('用戶數')

在這裏插入圖片描述

  用戶的第一次購買時間,集中在前面三個月。其中,在2月11日-2月25日之間有兩次劇烈的波動。

  由於沒有具體的數據,無法分析引起數據發生的變化,但是我們可以做出假設:

  • 渠道發生了變化?
  • 週期性變化?
  • 等等

用戶最後一次消費時間

group_user.max().order_dt.value_counts().plot(color='blue')
plt.xlabel('用戶最後一次消費時間')
plt.ylabel('用戶數')

在這裏插入圖片描述

   用戶最後一次購買的分佈比用戶第一次購買的分佈更廣,大部分用戶最後一次後買,集中在前三個月,說明了有很多新用戶購買了一次之後就不再進行購買了。

  隨着時間的遞增,最後一次購買也在遞增,消費呈現流失上升的狀況。

新老客消費比

  • 多少用戶僅消費了一次?
user_life = group_user['order_dt'].agg(['min','max'])
user_life.head()
min max
user_id
1 1997-01-01 1997-01-01
2 1997-01-12 1997-01-12
3 1997-01-02 1998-05-28
4 1997-01-01 1997-12-12
5 1997-01-01 1998-01-03

  先計算出用戶的首次消費時間和最後一次消費時間,如果首次消費時間=最後一次消費時間,則證明該用戶只消費了一次。比如說用戶ID爲1的用戶,他的首次消費時間爲1997年1月1日,而他的最後一次消費時間也是1997年1月1日,說明這位用戶僅消費了一次。

(user_life['max'] == user_life['min']).value_counts()
True     12054
False    11516
dtype: int64

   結果分析:有超過一半的用戶只消費了一次

  • 新客佔比?
group_month_user = CDNOW.groupby(['month','user_id'])
user_life_month = group_month_user['order_dt'].agg(['min','max'])

(user_life_month['min'] == user_life_month['max']).value_counts()
True     46727
False     8652
dtype: int64

  從上面的分析結果可以看出,新客爲46727人,而老客人數爲8652。

用戶分層

(1)RFM模型

  可以通過用戶進行細分,區別出低價值用戶、高價值用戶,針對不同的用戶羣體開展不同的個性化服務,將有限的資源合理地分配給不同價值的客戶,實現效益最大化。

  • R:recency最近一次消費時間,理論上R值越小,價值越高;
  • F:frequency最近一次消費頻率,消費頻率越高意味着這部分用戶對產品的滿意度越高,用戶粘性比較好,忠誠度也高;
  • M:Montary最近一段時間消費的金額,符合二八原則
# 建立數據透視表
rfm = CDNOW.pivot_table(
    index='user_id',
    values= ['order_products','order_amount','order_dt'],
    aggfunc={
        'order_products': 'count',
        'order_amount': 'sum',
        'order_dt': 'max'
    })

# 計算R是使用當前時間-最近一次時間,但是由於這個數據比較老,隔的時間比較久遠,故用最大時間來代替
rfm['R'] = (rfm['order_dt'].max() - rfm['order_dt']) / np.timedelta64(1,'D')  #  np.timedelta64(1,'D')是爲了消除單位

rfm.rename(columns={'order_amount':'M','order_products':'F'},inplace=True)

rfm.head()
M order_dt F R
user_id
1 11.77 1997-01-01 1 545.0
2 89.00 1997-01-12 2 534.0
3 156.46 1998-05-28 6 33.0
4 100.50 1997-12-12 4 200.0
5 385.61 1998-01-03 11 178.0
rfm1 = rfm[['R','F','M']].apply(lambda x: x-x.mean())  # 根據R、F、M用當前值減去每一列的均值
def rfm_func(x):
    
    level = x.apply(lambda x:'1' if x>= 1 else '0')  # 根據計算的RFM的數值,如果大於1,則標記爲1,如果小於1則標記爲0
    
    label = level['R'] + level['F'] +level['M']  # 根據上述的標記,將標記合併則得到每位用戶的標籤,如用戶ID爲1的用戶的標籤爲100
   
    # 根據各個用戶標籤,將用戶進行分羣
    d = {
        '111':'重要價值客戶',
        '011':'重要保持客戶',
        '101':'重要發展客戶',
        '001':'重要挽留客戶',
        '110':'一般價值客戶',
        '010':'一般保持客戶',
        '100':'一般發展客戶',
        '000':'一般挽留客戶'
    }
    result = d[label]  # 將用戶標籤對應到具體的用戶分羣中
    return result

rfm['label'] = rfm1.apply(rfm_func,axis=1)
# 針對客戶類別進行分組
rfm.groupby('label').sum()
M F R
label
一般價值客戶 9061.26 515 51893.0
一般保持客戶 74247.25 4243 130603.0
一般發展客戶 437939.13 16860 6940318.0
一般挽留客戶 145929.29 6320 499073.0
重要價值客戶 66774.84 1345 106737.0
重要保持客戶 1496321.20 36839 420516.0
重要發展客戶 130311.05 1421 354279.0
重要挽留客戶 139731.61 2116 151995.0
rfm.loc[rfm['label']=='重要價值客戶','color'] = 'g'  # 設置顏色
rfm.loc[~(rfm['label']=='重要價值客戶'),'color'] = 'r'
plt.scatter(rfm['R'],rfm['F'],c=rfm.color)
plt.xlabel('R')
plt.ylabel('F')

在這裏插入圖片描述

  從RFM分層可知,大部分用戶爲重要保持客戶,但是這是由於極值的影響,所以RFM的劃分標準應該以業務爲準

  • 儘量用小部分的用戶覆蓋大部分的額度
  • 不用爲了數據好看劃分等級。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章