用戶消費(fèi)行為數(shù)據(jù)行為(源碼自用)

import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
plt.style.use('ggplot') ? # 更改繪圖風(fēng)格,R語(yǔ)言繪圖庫(kù)的風(fēng)格
plt.rcParams['font.sans-serif'] = ['SimHei']
# user_id:用戶ID,order_dt:購(gòu)買日期,order_products:購(gòu)買產(chǎn)品數(shù)量,order_amounts:購(gòu)買金額
# 數(shù)據(jù)時(shí)間:1997年1月~1998年6月用戶行為數(shù)據(jù),約6萬條
# 導(dǎo)入數(shù)據(jù)
columns = ['user_id', 'order_dt', 'order_products', 'order_amounts']
df = pd.read_table('CDNOW_master.txt', names=columns, sep=r'\s+') ? # sep:'\s+'匹配任意的空格
"""
1.日期格式需要轉(zhuǎn)換
2.存在同一用戶一天內(nèi)購(gòu)買多次的行為
print(df.describe())
1.用戶平均每筆訂單購(gòu)買2.4個(gè)商品,標(biāo)準(zhǔn)差2.3,稍微有點(diǎn)波動(dòng),屬于正常。然而75%分位數(shù)的時(shí)候,說明絕大多數(shù)訂單的購(gòu)買量都不多,圍繞在2~3個(gè)產(chǎn)品左右
2.購(gòu)買金額,反映出大部分訂單消費(fèi)金額集中在中小額,30~45左右
"""
# 數(shù)據(jù)預(yù)處理
df['order_date'] = pd.to_datetime(df['order_dt'], format='%Y%m%d')
# format參數(shù):按照指定的格式與匹配要轉(zhuǎn)換的數(shù)據(jù)列
# %Y:四位年份 ?%y:兩位的年份 ?%m:兩位月份 ?%d:兩位日期 ?%h:兩位小時(shí) ?%M:兩位分鐘 ?%s:兩位秒
# 將order_data轉(zhuǎn)化成精度為月份的數(shù)據(jù)列
df['month'] = df['order_date'].astype('datetime64[M]') ? # [M]:控制轉(zhuǎn)換后的精度
# 用戶整體消費(fèi)趨勢(shì)分析(按月份)
# 按月份統(tǒng)計(jì)產(chǎn)品購(gòu)買數(shù)量,消費(fèi)金額,消費(fèi)次數(shù),消費(fèi)人數(shù)
plt.figure(figsize=(20, 15), dpi=240)
# 每月的產(chǎn)品購(gòu)買數(shù)量
plt.subplot(221) ? # 兩行兩列,占據(jù)第一個(gè)位置
df.groupby(by='month')['order_products'].sum().plot() ? # 默認(rèn)折線圖
plt.title('每月的產(chǎn)品購(gòu)買數(shù)量')
# 每月的消費(fèi)金額
plt.subplot(222)
df.groupby(by='month')['order_amounts'].sum().plot()
plt.title('每月的消費(fèi)金額')
# 每月的消費(fèi)次數(shù)
plt.subplot(223)
df.groupby(by='month')['user_id'].count().plot()
plt.title('每月的消費(fèi)次數(shù)')
# 每月的消費(fèi)人數(shù)(根據(jù)user_id進(jìn)行去重統(tǒng)計(jì),在計(jì)算個(gè)數(shù))
plt.subplot(224)
df.groupby(by='month')['user_id'].apply(lambda x: len(x.drop_duplicates())).plot()
plt.title('每月的消費(fèi)人數(shù)')
"""
圖一可以看出,前三個(gè)月銷量非常高,而以后銷量較為穩(wěn)定,并且稍微呈現(xiàn)下降趨勢(shì)
圖二可以看出,依然是前三個(gè)月消費(fèi)金額較高,與消費(fèi)數(shù)量成正比例關(guān)系,三月份過后下降嚴(yán)重,并呈現(xiàn)下降趨勢(shì)
?思考原因:1.跟月份有關(guān),在我看來1,2,3月份處于春節(jié)前后。
? ? ? ? ?2.公司在1,2,3月份的時(shí)候是否加大了促銷力度
圖三可以看出,前三個(gè)月訂單數(shù)在10000左右,后續(xù)月份平均消費(fèi)單數(shù)在2500左右
圖四可以看出,前三個(gè)月消費(fèi)人數(shù)在8000~10000左右,平均消費(fèi)人數(shù)在2000不到的樣子
總結(jié):所有數(shù)據(jù)顯示,97年前三月消費(fèi)事態(tài)異常,后續(xù)趨于常態(tài)化
"""
# 用戶消費(fèi)分析
# 1.用戶消費(fèi)金額,消費(fèi)次數(shù)(產(chǎn)品數(shù)量)描述統(tǒng)計(jì)
user_grouped = df.groupby(by='user_id').sum()
# 從用戶的角度:用戶數(shù)23570個(gè),每位用戶平均購(gòu)買了7個(gè)CD,但是中位數(shù)只有3,并且最大購(gòu)買量為1033,平均值大于中位數(shù),屬于典型的右偏分布(替購(gòu)買量<7的用戶背鍋)
# 從消費(fèi)金額角度:平均用戶消費(fèi)106,中位數(shù)43,并且存在土豪用戶13990,結(jié)合分位數(shù)和最大值來看,平均數(shù)與75%分位數(shù)幾乎相等,屬于典型的右偏分布,說明存在小部分用戶(后面的25%)高額消費(fèi)(這些用戶需要給消費(fèi)金額<106的用戶背鍋,只有這樣才能使平均數(shù)維持在106左右)
# 繪制每個(gè)用戶的產(chǎn)品的購(gòu)買量與消費(fèi)金額散點(diǎn)圖
df.plot(kind='scatter', x='order_products', y='order_amounts')
# 從圖中可知,用戶的消費(fèi)金額與購(gòu)買量呈現(xiàn)線性的趨勢(shì),每個(gè)商品均價(jià)15左右
# 訂單的極值點(diǎn)比較少(消費(fèi)金額>1000,或者購(gòu)買量>60),對(duì)于樣本來說影響不大,可以忽略不計(jì)。
# 2.用戶消費(fèi)分布圖
plt.figure(figsize=(12, 4),dpi=80)
plt.subplot(121)
plt.xlabel('每個(gè)訂單的消費(fèi)金額')
df['order_amounts'].plot(kind='hist', bins=50) ? # bins:區(qū)間分?jǐn)?shù),影響柱子的寬度,值越大柱子越細(xì),寬度=(列最大值-最小值)/bins
# 消費(fèi)金額在100以內(nèi)的訂單占據(jù)了絕大多數(shù)
plt.subplot(122)
plt.xlabel('每個(gè)UID購(gòu)買數(shù)量')
df.groupby(by='user_id')['order_products'].sum().plot(kind='hist', bins=50)
# 圖二可知,每個(gè)用戶購(gòu)買數(shù)量非常小,集中在50以內(nèi)
# 兩幅圖得知,我們的用戶主要是消費(fèi)金額低,并且購(gòu)買小于50的用戶人數(shù)占據(jù)大多數(shù)(在電商領(lǐng)域是非常正常的現(xiàn)象)
# 3.用戶累積消費(fèi)金額占比分析(用戶的貢獻(xiàn)度)
# 進(jìn)行用戶分組,取出消費(fèi)金額,進(jìn)行求和,排序,重置索引
user_cumsum = df.groupby('user_id')['order_amounts'].sum().sort_values().reset_index()
# 每個(gè)用戶消費(fèi)金額累加
user_cumsum['amount_cumsum'] = user_cumsum['order_amounts'].cumsum()
# 消費(fèi)金額總值
amount_total = user_cumsum['amount_cumsum'].max()
user_cumsum['prop'] = user_cumsum.apply(lambda x: x['amount_cumsum']/amount_total,axis=1) ?# 前xx名用戶的總貢獻(xiàn)率
user_cumsum['prop'].plot()
# 由圖分析可知,前20000名用戶貢獻(xiàn)總金額的40%,剩余3500用戶貢獻(xiàn)了60%。(2/8原則)
# 用戶消費(fèi)行為
# 1.首購(gòu)時(shí)間
# 用戶分組,取最小值,即為首購(gòu)時(shí)間
df.groupby(by='user_id')['order_date'].min().value_counts().plot()
# plt.show()
# 由圖可知,首次購(gòu)買的用戶量在1月1號(hào)~2月10號(hào)呈明顯上升趨勢(shì),后續(xù)開始逐步下降,猜測(cè):有可能是公司產(chǎn)品的推廣力度或者價(jià)格調(diào)整所致
# 2.最后一次購(gòu)買時(shí)間
df.groupby(by='user_id')['order_date'].max().value_counts().plot()
# 大多數(shù)用戶最后一次購(gòu)買時(shí)間集中在前3個(gè)月,說明缺少忠誠(chéng)用戶
# 隨著時(shí)間的推移,最后一次購(gòu)買產(chǎn)品的用戶量呈現(xiàn)上升趨勢(shì),猜測(cè):這份數(shù)據(jù)選擇的是前三個(gè)月消費(fèi)的用戶在后面18個(gè)月的跟蹤記錄
# 用戶分層
# 1.構(gòu)建RFM模型
# 透視表的使用(index:相當(dāng)于groupby,values:取出數(shù)據(jù)列,aggfunc:key值必須存在于values列中,并且必須跟隨有效的聚合函數(shù))
rfm = df.pivot_table(index='user_id',
? ? ? ? ? ? ? ? ? ? values=['order_products', 'order_amounts', 'order_date'],
? ? ? ? ? ? ? ? ? ? aggfunc={
? ? ? ? ? ? ? ? ? ? ? ? 'order_date': 'max', ? # 最后一次購(gòu)買
? ? ? ? ? ? ? ? ? ? ? ? 'order_products': 'sum', ? # 購(gòu)買產(chǎn)品的總數(shù)量
? ? ? ? ? ? ? ? ? ? ? ? 'order_amounts': 'sum' ? # 消費(fèi)總金額
? ? ? ? ? ? ? ? ? ? })
# 用每個(gè)用戶的最后一次購(gòu)買時(shí)間-日期列中的最大值,最后再轉(zhuǎn)換成天數(shù),小數(shù)保留1位
rfm['R'] = -(rfm['order_date']-rfm['order_date'].max())/np.timedelta64(1, 'D') ? # 取相差的天數(shù),保留1位小數(shù)
rfm.rename(columns={'order_products': 'F', 'order_amounts': 'M'}, inplace=True)
# RFM計(jì)算方式:每一列數(shù)據(jù)減去數(shù)據(jù)所在列的平均值,有正有負(fù),根據(jù)結(jié)果值與1做比較,如果>=1,設(shè)置為1,否則0
def rfm_func(x): ? # x:分別代表每一列數(shù)據(jù)
? ?level = x.apply(lambda x: '1' if x >= 1 else '0')
? ?label = level['R'] + level['F'] + level['M'] ? ?# 舉例:100 ?001
? ?d = {
? ? ? ?'111': '重要價(jià)值客戶',
? ? ? ?'011': '重要保持客戶',
? ? ? ?'101': '重要發(fā)展客戶',
? ? ? ?'110': '一般價(jià)值客戶',
? ? ? ?'001': '重要挽留客戶',
? ? ? ?'010': '一般保持客戶',
? ? ? ?'100': '一般發(fā)展客戶',
? ? ? ?'000': '一般挽留客戶',
? ?}
? ?result = d[label]
? ?return result
rfm['label'] = rfm[['R', 'F', 'M']].apply(lambda x: x-x.mean()).apply(rfm_func, axis=1)
# 客戶分層可視化
for label, grouped in rfm.groupby(by='label'):
? ?x = grouped['F'] ? # 單個(gè)用戶的購(gòu)買數(shù)量
? ?y = grouped['R'] ? # 最近一次購(gòu)買時(shí)間與98年7月的相差天數(shù)
? ?plt.scatter(x, y, label=label)
plt.legend() ? # 顯示圖例
plt.xlabel('F')
plt.ylabel('R')

"""
新老,活躍,回流用戶分析
·新用戶的定義是第一次消費(fèi)
·活躍用戶即老客,在某一個(gè)時(shí)間窗口內(nèi)有過消費(fèi)
·不活躍用戶則是時(shí)間窗口內(nèi)沒有消費(fèi)過的用戶
·回流用戶:相當(dāng)于回頭客的意思
·用戶回流的動(dòng)作可以分為自主回流與人工回流,自主回流指玩家自己回流了,而人工回流則是人為參與導(dǎo)致的
"""
pivoted_counts = df.pivot_table(
? ?index='user_id',
? ?columns='month',
? ?values='order_dt',
? ?aggfunc='count'
).fillna(0)
# 由于浮點(diǎn)數(shù)不直觀,并且需要轉(zhuǎn)成是否消費(fèi)過即可,用0、1表示
df_purchase = pivoted_counts.applymap(lambda x: 1 if x > 0 else 0)
"""
apply:作用于dataframe數(shù)據(jù)中的一行或者一列數(shù)據(jù)
applymap:作用于dataframe數(shù)據(jù)中的每一個(gè)元素
map:本身是series的函數(shù),在dataframe中無法使用map函數(shù),map函數(shù)作用于series中的每一個(gè)元素
"""
# 判斷是否是新用戶,活躍用戶,不活躍用戶,回流用戶
def active_status(data): ? # data:整行數(shù)據(jù),共18列
? ?status = [] ?# 負(fù)責(zé)存儲(chǔ)18個(gè)月的狀態(tài):unreg|new|unactive|return
? ?for i in range(18):
? ? ? ?# 本月沒有消費(fèi)==0
? ? ? ?if data[i] == 0:
? ? ? ? ? ?if len(status) == 0: ?# 前面沒有任何記錄(97年1月份)
? ? ? ? ? ? ? ?status.append('unreg')
? ? ? ? ? ?else: ?# 開始判斷上一個(gè)狀態(tài)
? ? ? ? ? ? ? ?if status[i-1] == 'unreg': ?# 一直未消費(fèi)過
? ? ? ? ? ? ? ? ? ?status.append('unreg')
? ? ? ? ? ? ? ?else: ?# new/active/unactive/return
? ? ? ? ? ? ? ? ? ?status.append('unactive') ?# 不管上個(gè)月是否消費(fèi)過,本月都是不活躍的
? ? ? ?# 本月有消費(fèi)==1
? ? ? ?else:
? ? ? ? ? ?if len(status) == 0:
? ? ? ? ? ? ? ?status.append('new') ? # 第一次消費(fèi)
? ? ? ? ? ?else:
? ? ? ? ? ? ? ?if status[i-1] == 'unactive':
? ? ? ? ? ? ? ? ? ?status.append('return')
? ? ? ? ? ? ? ?elif status[i-1] == 'unreg':
? ? ? ? ? ? ? ? ? ?status.append('new') ? # 第一次消費(fèi)
? ? ? ? ? ? ? ?else: ?# new/active/return=1
? ? ? ? ? ? ? ? ? ?status.append('active')
? ?return pd.Series(status, df_purchase.columns) ? # 值status,列名df_purchase中的列名
purchase_states = df_purchase.apply(active_status, axis=1)
# 用Nan替換unreg
purchase_states_ct = purchase_states.replace('unreg', np.NaN).apply(lambda x: pd.value_counts(x))
purchase_states_ct.T.fillna(0).plot.area()
# 前三個(gè)月可知,紅色活躍用戶和藍(lán)色新用戶,占比較大;四月份過后,新用戶和活躍用戶開始下降,并且呈現(xiàn)穩(wěn)定的趨勢(shì);回流用戶主要產(chǎn)生在4月過后,呈現(xiàn)穩(wěn)定趨勢(shì),是網(wǎng)站的重要客戶
# 回流,活躍用戶的占比
rate = purchase_states_ct.T.fillna(0).apply(lambda x: x/x.sum(), axis=1)
plt.plot(rate['return'], label='return')
plt.plot(rate['active'], label='active')
plt.legend()
# 回流用戶:前五個(gè)月,回流用戶上漲,過后呈現(xiàn)下降趨勢(shì),平均維持在5%比例
# 活躍用戶:前三個(gè)月活躍用戶大量增長(zhǎng),猜測(cè)由于活動(dòng)吸引來很多新用戶所導(dǎo)致,5月份過后開始下降,平均維持在2.5%左右
# 網(wǎng)站運(yùn)營(yíng)穩(wěn)定后,回流用戶占比大于活躍用戶

# 用戶購(gòu)買周期(計(jì)算購(gòu)買日期的時(shí)間差值)
# shift函數(shù):將數(shù)據(jù)移動(dòng)到一定的位置
order_diff = df.groupby(by='user_id').apply(lambda x: x['order_date']-x['order_date'].shift()) ?# 當(dāng)前訂單日期-上一次訂單日期
(order_diff/np.timedelta64(1, 'D')).hist(bins=20)
# 得知:平均消費(fèi)周期為68天
# 大多數(shù)用戶消費(fèi)周期低于100天,呈現(xiàn)典型的長(zhǎng)尾分布,只有小部分用戶消費(fèi)周期在200天以上(不積極消費(fèi)的用戶),可以在這批用戶消費(fèi)后三天后進(jìn)行電話回訪,或者短信贈(zèng)送優(yōu)惠券等活動(dòng),增大消費(fèi)頻率

# 用戶生命周期
# 計(jì)算方式:用戶最后一次購(gòu)買日期-第一次購(gòu)買的日期,如果差值==0,說明用戶僅僅購(gòu)買了一次
user_life = df.groupby('user_id')['order_date'].agg(['min', 'max'])
(user_life['max'] == user_life['min']).value_counts().plot.pie(autopct='%1.1f%%') ?# 格式化成1位小數(shù)
plt.legend(['僅消費(fèi)一次', '多次消費(fèi)'])
# 一半以上用戶僅僅消費(fèi)了一次,說明運(yùn)營(yíng)不利,留存率不好
print((user_life['max']-user_life['min']).describe()) ? # 生命周期分析
# 用戶平均生命周期為134天,但是中位數(shù)==0,再次驗(yàn)證了大多數(shù)用戶消費(fèi)了一次,低質(zhì)量用戶,75%分位數(shù)以后的用戶,生命周期>294天,屬于核心用戶,需要著重維持前三個(gè)月的新用戶數(shù)據(jù),所以分析的是這些用戶的生命周期
# 繪制所有用戶生命周期直方圖+多次消費(fèi)
plt.figure(figsize=(12, 6), dpi=240)
plt.subplot(121)
((user_life['max']-user_life['min'])/np.timedelta64(1, 'D')).hist(bins=15)
plt.title('所有用戶的生命周期')
plt.xlabel('生命周期天數(shù)')
plt.ylabel('用戶人數(shù)')
plt.subplot(122)
u_1 = (user_life['max']-user_life['min']).reset_index()[0]/np.timedelta64(1, 'D')
u_1[u_1 > 0].hist(bins=15)
plt.title('多次用戶的生命周期')
plt.xlabel('生命周期天數(shù)')
plt.ylabel('用戶人數(shù)')
plt.show()
# 對(duì)比可知,第二幅圖過濾掉了生命周期==0的用戶,呈現(xiàn)雙峰結(jié)構(gòu);雖然二圖中還有一部分用戶的生命周期趨于0天,但是比第一幅圖好了很多,雖然進(jìn)行了多次消費(fèi),但是不能長(zhǎng)期來消費(fèi),屬于普通用戶,可針對(duì)性進(jìn)行營(yíng)銷推廣活動(dòng);少部分用戶生命周期集中在300~500天,屬于我們的忠誠(chéng)客戶,需要大力度維護(hù)此類客戶
"""
復(fù)購(gòu)率和回購(gòu)率分析
復(fù)購(gòu)率分析(計(jì)算方式:在自然月內(nèi),購(gòu)買多次的用戶在總消費(fèi)人數(shù)中的占比,若客戶在同一天消費(fèi)了多次,也稱之復(fù)購(gòu)客戶)
消費(fèi)者有三種:消費(fèi)記錄>=2次的;消費(fèi)總?cè)藬?shù);本月無消費(fèi)用戶
復(fù)購(gòu)用戶:1 ?非復(fù)購(gòu)的消費(fèi)用戶:0 ?沒有消費(fèi)記錄的用戶:Nan
"""
purchase_r = pivoted_counts.applymap(lambda x: 1 if x > 1 else np.NaN if x == 0 else 0)
# sum():求出復(fù)購(gòu)用戶,count():求出所有用戶(無nan)
(purchase_r.sum()/purchase_r.count()).plot(figsize=(12,6))
# 前三個(gè)月復(fù)購(gòu)率開始上升,后續(xù)趨于平穩(wěn)維持在20%~22%之間,分析前三個(gè)月復(fù)購(gòu)率低的原因,可能是因?yàn)榇笈掠脩魞H僅購(gòu)買一次造成的
# 回購(gòu)率分析
# 計(jì)算方式:在一個(gè)時(shí)間窗口內(nèi)進(jìn)行了消費(fèi),在下一個(gè)時(shí)間窗口內(nèi)又進(jìn)行了消費(fèi)
def purchase_back(data):
? ?status = [] ? # 存儲(chǔ)用戶回購(gòu)率狀態(tài)
? ?# 1:回購(gòu)用戶 ? 0:非回購(gòu)用戶(當(dāng)前月消費(fèi)了,下個(gè)月未消費(fèi)) ? nan:當(dāng)前月未消費(fèi)
? ?for i in range(17):
? ? ? ?# 當(dāng)前月份消費(fèi)了
? ? ? ?if data[i] == 1:
? ? ? ? ? ?if data[i+1] == 1:
? ? ? ? ? ? ? ?status.append(1)
? ? ? ? ? ?elif data[i+1] == 0:
? ? ? ? ? ? ? ?status.append(0)
? ? ? ?else: ?# 當(dāng)前月份未進(jìn)行消費(fèi)
? ? ? ? ? ?status.append(np.NaN)
? ?status.append(np.NaN) ?# 填充最后一列數(shù)據(jù)
? ?return pd.Series(status, df_purchase.columns)
purchase_b = df_purchase.apply(purchase_back, axis=1)
# 回購(gòu)率可視化
plt.figure(figsize=(20, 4), dpi=240)
plt.subplot(211)
# 回購(gòu)率
(purchase_b.sum()/purchase_b.count()).plot(label='回購(gòu)率')
# 復(fù)購(gòu)率
(purchase_r.sum()/purchase_r.count()).plot(label='復(fù)購(gòu)率')
plt.legend()
plt.ylabel('百分比%')
plt.title('用戶回購(gòu)率和復(fù)購(gòu)率對(duì)比圖')
# 回購(gòu)率可知,平穩(wěn)后在30%左右,波動(dòng)性稍微較大;復(fù)購(gòu)率低于回購(gòu)率,平穩(wěn)后在20%左右,波動(dòng)性較??;前三個(gè)月不論是回購(gòu)還是復(fù)購(gòu),都呈現(xiàn)上升趨勢(shì),說明新用戶需要一定的時(shí)間來變成復(fù)購(gòu)或者回購(gòu)用戶
# 結(jié)合新老用戶分析,新客戶忠誠(chéng)度遠(yuǎn)低于老客戶忠誠(chéng)度
# 回購(gòu)人數(shù)與購(gòu)物總?cè)藬?shù)
plt.subplot(212)
plt.plot(purchase_b.sum(), label='回購(gòu)人數(shù)')
plt.plot(purchase_b.count(), label='購(gòu)物總?cè)藬?shù)')
plt.xlabel('month')
plt.ylabel('人數(shù)')
plt.legend()
# 前三個(gè)月購(gòu)物總?cè)藬?shù)遠(yuǎn)遠(yuǎn)大于回購(gòu)人數(shù),主要是因?yàn)楹芏嘈掠脩粼?月份進(jìn)行了首次購(gòu)買;三個(gè)月過后,回購(gòu)人數(shù)和購(gòu)物總數(shù)開始穩(wěn)定,回購(gòu)人數(shù)穩(wěn)定在1000左右,購(gòu)物總?cè)藬?shù)在2000左右

"""
方法總結(jié):
1.針對(duì)用戶進(jìn)行按照月份做整體和個(gè)體分析,主要分析維度是人數(shù),消費(fèi)金額,購(gòu)買量
2.消費(fèi)分析:首購(gòu)時(shí)間,最后一次購(gòu)買時(shí)間,相鄰兩個(gè)購(gòu)物時(shí)間的間隔,用戶分層(RFM模型+數(shù)據(jù)透視表),分析維度主要是新用戶,活躍用戶,不活躍用戶流失分析,回流用戶占比
3.復(fù)購(gòu)率和回購(gòu)率進(jìn)行分析
"""