標籤:

用戶消費信息分析案例練習

用戶消費信息分析案例練習

1 人贊了文章

本文就某產品兩個月的消費記錄,進行分析。

本次數據包含兩張表:商品消費信息表,用戶信息表。主要從以下幾個維度進行:

使用工具:python

正文

導入相關庫

#導入相關庫import datetimeimport pandas as pdimport numpy as npimport matplotlib.pyplot as pltplt.style.use(ggplot)

讀取excel訂單數據

#讀取excel訂單數據fileName = order.xlsxxls = pd.ExcelFile(fileName)df_o = xls.parse(Sheet1)

讀取csv用戶數據

#讀取csv用戶數據columns = [user_id,sex,birthday]df_u = pd.read_csv(user_info_utf.csv,names = columns,sep = ,)

查看數據

訂單表

用戶表

訂單表各欄位含義

orderID: 商品id

userID :用戶id

ispaid :是否購買商品

price :成交金額

paidtime:購買時間

用戶表各欄位含義

user_id : 用戶id

sex : 性別

birthday: 生日

數據清洗

首先對訂單數據進行清洗

df_o.info()

篩選出已支付並且購買時間不為空的值

#篩選出已支付並且購買時間不為空的值df_o = df_o[(df_o[ispaid] == 已支付) & (df_o[paidtime].notnull())]

對日期標準化,改為年月日形式

#對日期標準化,改為年月日形式df_o[order_dt] = df_o[paidtime].apply(lambda x:x.date())

更改日期格式

#更改日期格式df_o[order_dt]=pd.to_datetime(df_o.order_dt,format=%Y-%m-%d)

將數據按照每天用戶購買數分組

#將數據按照每天用戶購買數分組df_c = df_o.groupby([order_dt,userID]).orderID.count().reset_index()df_p = df_o.groupby([order_dt,userID]).price.sum().reset_index()df_c[price] = df_p.price

更改列名

#更改列名columns = [order_dt,user_id,order_products,order_amount]df_c.columns = columns

算出時間相對應的星期,並算出是該年的第幾周(這裡使用的方法是以完整的7天為一周,不足7天不算,所以與實際可能存在1周的偏差)

#算出時間相對應的星期,並算出是第幾周df_c[weekday] = df_c.order_dt.apply(lambda x:x.weekday())df_c[weeks] = df_c.order_dt.apply(lambda x:x.strftime("%W"))

處理後數據信息

df_c.info()

處理後表

df_c.head()

對用戶數據清洗

df_u.info()

將生日轉換為日期格式,並按照訂單購買的最後一天計算年齡

#將生日轉換為日期格式,並按照訂單購買的最後一天計算年齡df_u[birthday] = pd.to_datetime(df_u.birthday,format=%Y/%m/%d,errors=coerce)df_u[age] = df_o.order_dt.values.astype(datetime64[Y]).max()-df_u.birthday.values.astype(datetime64[Y])df_u[age] = df_u[age]/np.timedelta64(1,Y)

為了使年齡更加準確,這裡選取年齡為18-80歲的數據

#為了使年齡更加準確,這裡選取18-80歲df_u = df_u[(df_u[age] > 17) & (df_u[age] < 81) | (df_u[age].isnull())]

處理後數據信息

df_u.info()

合併數據集

#合併數據集df = pd.merge(df_c,df_u,how = left,left_on = user_id,right_on = user_id)df.tail()

由於5月2日只有一項紀錄,這裡去掉該項

df = df[:-1]

查看最終數據

df.info()

描述統計

df.describe()

  • 大部分訂單只是消費了少量商品(平均3.7),有極值干擾
  • 用戶的消費金額同樣受極值干擾

用戶消費趨勢(按周)

每周消費總金額

按每周分類

#按每周分類grouped_weeks = df.groupby(weeks)

繪製折線圖

plt.figure(figsize=(10,6))plt.plot(grouped_weeks.order_amount.sum())plt.title(每周消費總金額)

從圖像可知,消費金額在前幾周增長迅速,在第13周有所下降,隨後繼續增長並在第16周達到最高峰,又在最後一周下跌

每周消費次數

plt.figure(figsize=(10,6))plt.plot(grouped_weeks.user_id.count())plt.title(每周消費次數)

由上圖可知,前四周消費訂單數成上升趨勢,第五周開始下降,到最後一周僅剩9500單

每周產品購買量

plt.figure(figsize=(10,6))plt.plot(grouped_weeks.order_products.sum())plt.title(每周產品購買量)

由上圖可以看出,每周產品購買量整體趨勢與消費金額相似,結合每周訂單數可以看出,該商品在後期存在用戶大量購買的情況。另外在第16周總消費金額大於第13周,然而消費總商品數卻相反,說明該商品有漲價行為

每周消費人數

plt.figure(figsize=(10,6))plt.plot(grouped_weeks.user_id.apply(lambda x:x.drop_duplicates().count()))plt.title(每周消費人數)

每周消費人數低於消費出三個月,但差異不大

將該商品消費金額兩次下跌,單獨分析

#繪製第13、17周以及總消費折線圖fig=plt.figure(figsize=(7,14))ax1=fig.add_subplot(311)ax1.plot(df[df[weeks]==13].groupby(order_dt).order_amount.sum(),color=b,label=第13周記錄)plt.legend(loc=best)ax2=fig.add_subplot(312)ax2.plot(df[df[weeks]==17].groupby(order_dt).order_amount.sum(),color=y,label=第17周記錄)plt.legend(loc=best)ax3=fig.add_subplot(313)ax3.plot(df.groupby(weekday).order_amount.sum(),color=r,label=總記錄)plt.legend(loc=best)

從消費金額每日趨勢圖可以看出,該商品一般情況下在周二至周四達到高峰,隨著節假日的到來,有所下降,在周六達到低估,在周日回有所回升,考慮為工作做準備。而第13周和第17周都在周日不增反減,考慮是受清明節與五一節的影響。所以該商品銷量受節假日影響較大。

用戶個體消費分析

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

按用戶分組,並查看描述統計

grouped_user = df.groupby(user_id)grouped_user.sum().describe()

  • 用戶平均購買了5件商品,但中位數只有1說明小部分用戶購買了大量的商品
  • 用戶平均消費3700元,中位數有737,判斷同上,有極值干擾

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

這裡勁量避免極值干擾,選取消費金額小於400000,商品數少於2000的數據

grouped_user.sum().query("order_amount<400000").plot.scatter(x=order_amount,y=order_products,figsize=(10,6))plt.title(用戶消費金額和消費的散點圖)

可以看出,大部分用戶購買了少量產品

用戶累計新消費金額佔比(百分之多少的用戶佔了百分之多少的消費)

user_cumsum = grouped_user.sum().query(order_amount<400000).sort_values(order_amount).apply(lambda x:x.cumsum()/x.sum())user_cumsum.reset_index().order_amount.plot(figsize=(10,6))plt.title(用戶累計新消費金額佔比)

按用戶消費金額進行升序排列,由圖可知,50%的用戶僅貢獻了25%的消費額度。而排名前一萬的用戶就貢獻了40%的消費額。

用戶消費行為

用戶第一次消費(首購)

grouped_user.order_dt.min().value_counts().plot(figsize=(16,8))

用戶第一次購買在每個周六都會有所下降,並且整體呈下降趨勢,說明新用戶在減少

用戶最後一次消費

grouped_user.order_dt.max().value_counts().plot(figsize=(16,8))plt.title(用戶最後一次消費)

用戶最後一次購買同樣在每個周六都會有所下降(考慮周六消費人數較少),並且整體有略微上升的趨勢,說明老用戶在流失

多少用戶僅消費一次

user_life = grouped_user.order_dt.agg([max,min])user_life.head()

(user_life[min] == user_life[max]).value_counts().plot.pie(figsize=(10,8),labels=[僅消費一次的客戶,消費一次以上的客戶])plt.title(多少用戶僅消費一次)

70%以上的用戶僅消費了一次

用戶分層

RFM

數據透視

rfm = df.pivot_table(index = user_id, values = [order_products,order_amount,order_dt], aggfunc={order_dt:max, order_amount:sum, order_products:sum })

這裡時間以最後一次消費為標準,對RMF模型進行處理。按照每個指標與平均數的對比,將用戶分為8個標籤:

  • 重要價值客戶
  • 重要保持客戶
  • 重要挽留客戶
  • 重要發展客戶
  • 一般保持客戶
  • 一般挽留客戶
  • 一般發展客戶

#計算最近一次消費時間rfm[R] = -(rfm[order_dt]-rfm[order_dt].max())/np.timedelta64(1,D)#更改列名rfm.rename(columns = {order_products:F,order_amount:M},inplace = True)#定義轉換函數def rfm_func(x): level = x.apply(lambda x:1 if x>0 else 0) label = level.R + level.F + level.M d = { 111:重要價值客戶, 011:重要保持客戶, 101:重要挽留客戶, 001:重要發展客戶, 010:一般保持客戶, 100:一般挽留客戶, 000:一般發展客戶 } result = d[label] return resultrfm[label] = rfm[[R,F,M]].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)#篩選數據rfm = rfm[(rfm[F]<2000) & (rfm[M]<400000)]

按類型對金額統計

rfm.groupby(label).sum()

按類型對購買人數統計

rfm.groupby(label).count()

繪製散點圖

fig=plt.figure(figsize=(16,8))ax1=fig.add_subplot(111)ax1.scatter(rfm.loc[rfm.label == 重要價值客戶].F,rfm.loc[rfm.label == 重要價值客戶].R,label=重要價值客戶,color=g,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 重要保持客戶].F,rfm.loc[rfm.label == 重要保持客戶].R,label=重要保持客戶,color=b,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 重要挽留客戶].F,rfm.loc[rfm.label == 重要挽留客戶].R,label=重要挽留客戶,color=r,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 重要發展客戶].F,rfm.loc[rfm.label == 重要發展客戶].R,label=重要發展客戶,color=k,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 一般價值客戶].F,rfm.loc[rfm.label == 一般價值客戶].R,label=一般價值客戶,color=m,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 一般保持客戶].F,rfm.loc[rfm.label == 一般保持客戶].R,label=一般保持客戶,color=y,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 一般挽留客戶].F,rfm.loc[rfm.label == 一般挽留客戶].R,label=一般挽留客戶,color=c,alpha=.5)ax1.scatter(rfm.loc[rfm.label == 一般發展客戶].F,rfm.loc[rfm.label == 一般發展客戶].R,label=一般發展客戶,color=w,alpha=.5)plt.xlabel(F)plt.ylabel(R)plt.legend(loc=best)

這裡結合圖表發現一般發展客戶,一般挽留客戶居然佔據了最高的消費金額,這一方面是由於數據時間段太短,另一方面是由於這兩個指標擁有大量的人群。此外RMF模型的劃分標準應該以業務為準。

男女消費對比

這裡注意,計算人數用去重,消費總金額用戶分組

#這裡注意,計算人數用去重,消費總金額用戶分組df_dup = df.drop_duplicates(subset=user_id,keep=first)

繪製條形圖

fig=plt.figure(figsize=(10,6))ax1=fig.add_subplot(131)ax1.bar(df_dup.sex.value_counts().index,df_dup.sex.value_counts().values)plt.title(男女人數比)ax2=fig.add_subplot(132)ax2.bar(df.groupby(sex).order_amount.sum().index,df.groupby(sex).order_amount.sum().values)plt.title(男女消費比)ax3=fig.add_subplot(133)ax3.bar((df.groupby(sex).order_amount.sum()/df_dup.sex.value_counts()).index,(df.groupby(sex).order_amount.sum()/df_dup.sex.value_counts()).values)plt.title(男女人均消費比)

從圖中可以看出,雖然男士比女士人數多,但是女士的評分消費水平更大

年齡段消費對比

篩選出年齡不為空的數據

df_age = df[df[age].notnull()]

將年齡分組

bins = [0,25,35,45,55,65,100]level = [0-25,25-35,35-45,45-55,55-65,65以上]df_age[level] = pd.cut(df_age[age],bins = bins,labels = level)df_age.head()

按用戶去重

df_age_dup = df_age.drop_duplicates(subset=user_id,keep=first)

繪製條形圖

fig=plt.figure(figsize=(10,6))ax1=fig.add_subplot(121)ax1.bar(df_age.groupby(level).order_amount.sum().index,df_age.groupby(level).order_amount.sum().values)plt.title(各年齡段人數比)ax2=fig.add_subplot(122)ax2.bar(df_age_dup.level.value_counts().index,df_age_dup.level.value_counts().values)plt.title(各年齡段消費比)

由上圖可知,25-35歲無論是消費人數還是消費金額都遙遙領先,是該商品主要目標客戶。


推薦閱讀:

全國霧霾大數據,哪裡才是桃花源?
hive入門第二章-增刪改查
可視化開腦洞期刊(一)
重做紅樓夢的數據分析-判斷前80回後40回是否一個人寫的
誰動了你的文件 -- 使用「透視表」分析文件訪問日誌

TAG:數據分析 |