2023-03-22 23:09:46 来源:哔哩哔哩
(相关资料图)
import pandas as pdimport numpy as npfrom matplotlib import pyplot as pltplt.style.use('ggplot') # 更改绘图风格,R语言绘图库的风格plt.rcParams['font.sans-serif'] = ['SimHei']# user_id:用户ID,order_dt:购买日期,order_products:购买产品数量,order_amounts:购买金额# 数据时间:1997年1月~1998年6月用户行为数据,约6万条# 导入数据columns = ['user_id', 'order_dt', 'order_products', 'order_amounts']df = pd.read_table('CDNOW_master.txt', names=columns, sep=r'\s+') # sep:'\s+'匹配任意的空格"""1.日期格式需要转换2.存在同一用户一天内购买多次的行为print(df.describe())1.用户平均每笔订单购买2.4个商品,标准差2.3,稍微有点波动,属于正常。然而75%分位数的时候,说明绝大多数订单的购买量都不多,围绕在2~3个产品左右2.购买金额,反映出大部分订单消费金额集中在中小额,30~45左右"""# 数据预处理df['order_date'] = pd.to_datetime(df['order_dt'], format='%Y%m%d')# format参数:按照指定的格式与匹配要转换的数据列# %Y:四位年份 %y:两位的年份 %m:两位月份 %d:两位日期 %h:两位小时 %M:两位分钟 %s:两位秒# 将order_data转化成精度为月份的数据列df['month'] = df['order_date'].astype('datetime64[M]') # [M]:控制转换后的精度# 用户整体消费趋势分析(按月份)# 按月份统计产品购买数量,消费金额,消费次数,消费人数plt.figure(figsize=(20, 15), dpi=240)# 每月的产品购买数量plt.subplot(221) # 两行两列,占据第一个位置df.groupby(by='month')['order_products'].sum().plot() # 默认折线图plt.title('每月的产品购买数量')# 每月的消费金额plt.subplot(222)df.groupby(by='month')['order_amounts'].sum().plot()plt.title('每月的消费金额')# 每月的消费次数plt.subplot(223)df.groupby(by='month')['user_id'].count().plot()plt.title('每月的消费次数')# 每月的消费人数(根据user_id进行去重统计,在计算个数)plt.subplot(224)df.groupby(by='month')['user_id'].apply(lambda x: len(x.drop_duplicates())).plot()plt.title('每月的消费人数')"""图一可以看出,前三个月销量非常高,而以后销量较为稳定,并且稍微呈现下降趋势图二可以看出,依然是前三个月消费金额较高,与消费数量成正比例关系,三月份过后下降严重,并呈现下降趋势 思考原因:1.跟月份有关,在我看来1,2,3月份处于春节前后。 2.公司在1,2,3月份的时候是否加大了促销力度图三可以看出,前三个月订单数在10000左右,后续月份平均消费单数在2500左右图四可以看出,前三个月消费人数在8000~10000左右,平均消费人数在2000不到的样子总结:所有数据显示,97年前三月消费事态异常,后续趋于常态化"""# 用户消费分析# 1.用户消费金额,消费次数(产品数量)描述统计user_grouped = df.groupby(by='user_id').sum()# 从用户的角度:用户数23570个,每位用户平均购买了7个CD,但是中位数只有3,并且最大购买量为1033,平均值大于中位数,属于典型的右偏分布(替购买量<7的用户背锅)# 从消费金额角度:平均用户消费106,中位数43,并且存在土豪用户13990,结合分位数和最大值来看,平均数与75%分位数几乎相等,属于典型的右偏分布,说明存在小部分用户(后面的25%)高额消费(这些用户需要给消费金额<106的用户背锅,只有这样才能使平均数维持在106左右)# 绘制每个用户的产品的购买量与消费金额散点图df.plot(kind='scatter', x='order_products', y='order_amounts')# 从图中可知,用户的消费金额与购买量呈现线性的趋势,每个商品均价15左右# 订单的极值点比较少(消费金额>1000,或者购买量>60),对于样本来说影响不大,可以忽略不计。# 2.用户消费分布图plt.figure(figsize=(12, 4),dpi=80)plt.subplot(121)plt.xlabel('每个订单的消费金额')df['order_amounts'].plot(kind='hist', bins=50) # bins:区间分数,影响柱子的宽度,值越大柱子越细,宽度=(列最大值-最小值)/bins# 消费金额在100以内的订单占据了绝大多数plt.subplot(122)plt.xlabel('每个UID购买数量')df.groupby(by='user_id')['order_products'].sum().plot(kind='hist', bins=50)# 图二可知,每个用户购买数量非常小,集中在50以内# 两幅图得知,我们的用户主要是消费金额低,并且购买小于50的用户人数占据大多数(在电商领域是非常正常的现象)# 3.用户累积消费金额占比分析(用户的贡献度)# 进行用户分组,取出消费金额,进行求和,排序,重置索引user_cumsum = df.groupby('user_id')['order_amounts'].sum().sort_values().reset_index()# 每个用户消费金额累加user_cumsum['amount_cumsum'] = user_cumsum['order_amounts'].cumsum()# 消费金额总值amount_total = user_cumsum['amount_cumsum'].max()user_cumsum['prop'] = user_cumsum.apply(lambda x: x['amount_cumsum']/amount_total,axis=1) # 前xx名用户的总贡献率user_cumsum['prop'].plot()# 由图分析可知,前20000名用户贡献总金额的40%,剩余3500用户贡献了60%。(2/8原则)# 用户消费行为# 1.首购时间# 用户分组,取最小值,即为首购时间df.groupby(by='user_id')['order_date'].min().value_counts().plot()# plt.show()# 由图可知,首次购买的用户量在1月1号~2月10号呈明显上升趋势,后续开始逐步下降,猜测:有可能是公司产品的推广力度或者价格调整所致# 2.最后一次购买时间df.groupby(by='user_id')['order_date'].max().value_counts().plot()# 大多数用户最后一次购买时间集中在前3个月,说明缺少忠诚用户# 随着时间的推移,最后一次购买产品的用户量呈现上升趋势,猜测:这份数据选择的是前三个月消费的用户在后面18个月的跟踪记录# 用户分层# 1.构建RFM模型# 透视表的使用(index:相当于groupby,values:取出数据列,aggfunc:key值必须存在于values列中,并且必须跟随有效的聚合函数)rfm = df.pivot_table(index='user_id', values=['order_products', 'order_amounts', 'order_date'], aggfunc={ 'order_date': 'max', # 最后一次购买 'order_products': 'sum', # 购买产品的总数量 'order_amounts': 'sum' # 消费总金额 })# 用每个用户的最后一次购买时间-日期列中的最大值,最后再转换成天数,小数保留1位rfm['R'] = -(rfm['order_date']-rfm['order_date'].max())/np.timedelta64(1, 'D') # 取相差的天数,保留1位小数rfm.rename(columns={'order_products': 'F', 'order_amounts': 'M'}, inplace=True)# RFM计算方式:每一列数据减去数据所在列的平均值,有正有负,根据结果值与1做比较,如果>=1,设置为1,否则0def rfm_func(x): # x:分别代表每一列数据 level = x.apply(lambda x: '1' if x >= 1 else '0') label = level['R'] + level['F'] + level['M'] # 举例:100 001 d = { '111': '重要价值客户', '011': '重要保持客户', '101': '重要发展客户', '110': '一般价值客户', '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)# 客户分层可视化for label, grouped in rfm.groupby(by='label'): x = grouped['F'] # 单个用户的购买数量 y = grouped['R'] # 最近一次购买时间与98年7月的相差天数 plt.scatter(x, y, label=label)plt.legend() # 显示图例plt.xlabel('F')plt.ylabel('R')
"""新老,活跃,回流用户分析·新用户的定义是第一次消费·活跃用户即老客,在某一个时间窗口内有过消费·不活跃用户则是时间窗口内没有消费过的用户·回流用户:相当于回头客的意思·用户回流的动作可以分为自主回流与人工回流,自主回流指玩家自己回流了,而人工回流则是人为参与导致的"""pivoted_counts = df.pivot_table( index='user_id', columns='month', values='order_dt', aggfunc='count').fillna(0)# 由于浮点数不直观,并且需要转成是否消费过即可,用0、1表示df_purchase = pivoted_counts.applymap(lambda x: 1 if x > 0 else 0)"""apply:作用于dataframe数据中的一行或者一列数据applymap:作用于dataframe数据中的每一个元素map:本身是series的函数,在dataframe中无法使用map函数,map函数作用于series中的每一个元素"""# 判断是否是新用户,活跃用户,不活跃用户,回流用户def active_status(data): # data:整行数据,共18列 status = [] # 负责存储18个月的状态:unreg|new|unactive|return for i in range(18): # 本月没有消费==0 if data[i] == 0: if len(status) == 0: # 前面没有任何记录(97年1月份) status.append('unreg') else: # 开始判断上一个状态 if status[i-1] == 'unreg': # 一直未消费过 status.append('unreg') else: # new/active/unactive/return status.append('unactive') # 不管上个月是否消费过,本月都是不活跃的 # 本月有消费==1 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: # 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替换unregpurchase_states_ct = purchase_states.replace('unreg', np.NaN).apply(lambda x: pd.value_counts(x))purchase_states_ct.T.fillna(0).plot.area()# 前三个月可知,红色活跃用户和蓝色新用户,占比较大;四月份过后,新用户和活跃用户开始下降,并且呈现稳定的趋势;回流用户主要产生在4月过后,呈现稳定趋势,是网站的重要客户# 回流,活跃用户的占比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()# 回流用户:前五个月,回流用户上涨,过后呈现下降趋势,平均维持在5%比例# 活跃用户:前三个月活跃用户大量增长,猜测由于活动吸引来很多新用户所导致,5月份过后开始下降,平均维持在2.5%左右# 网站运营稳定后,回流用户占比大于活跃用户
# 用户购买周期(计算购买日期的时间差值)# shift函数:将数据移动到一定的位置order_diff = df.groupby(by='user_id').apply(lambda x: x['order_date']-x['order_date'].shift()) # 当前订单日期-上一次订单日期(order_diff/np.timedelta64(1, 'D')).hist(bins=20)# 得知:平均消费周期为68天# 大多数用户消费周期低于100天,呈现典型的长尾分布,只有小部分用户消费周期在200天以上(不积极消费的用户),可以在这批用户消费后三天后进行电话回访,或者短信赠送优惠券等活动,增大消费频率
# 用户生命周期# 计算方式:用户最后一次购买日期-第一次购买的日期,如果差值==0,说明用户仅仅购买了一次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位小数plt.legend(['仅消费一次', '多次消费'])# 一半以上用户仅仅消费了一次,说明运营不利,留存率不好print((user_life['max']-user_life['min']).describe()) # 生命周期分析# 用户平均生命周期为134天,但是中位数==0,再次验证了大多数用户消费了一次,低质量用户,75%分位数以后的用户,生命周期>294天,属于核心用户,需要着重维持前三个月的新用户数据,所以分析的是这些用户的生命周期# 绘制所有用户生命周期直方图+多次消费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('生命周期天数')plt.ylabel('用户人数')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('生命周期天数')plt.ylabel('用户人数')plt.show()# 对比可知,第二幅图过滤掉了生命周期==0的用户,呈现双峰结构;虽然二图中还有一部分用户的生命周期趋于0天,但是比第一幅图好了很多,虽然进行了多次消费,但是不能长期来消费,属于普通用户,可针对性进行营销推广活动;少部分用户生命周期集中在300~500天,属于我们的忠诚客户,需要大力度维护此类客户"""复购率和回购率分析复购率分析(计算方式:在自然月内,购买多次的用户在总消费人数中的占比,若客户在同一天消费了多次,也称之复购客户)消费者有三种:消费记录>=2次的;消费总人数;本月无消费用户复购用户:1 非复购的消费用户:0 没有消费记录的用户:Nan"""purchase_r = pivoted_counts.applymap(lambda x: 1 if x > 1 else np.NaN if x == 0 else 0)# sum():求出复购用户,count():求出所有用户(无nan)(purchase_r.sum()/purchase_r.count()).plot(figsize=(12,6))# 前三个月复购率开始上升,后续趋于平稳维持在20%~22%之间,分析前三个月复购率低的原因,可能是因为大批新用户仅仅购买一次造成的# 回购率分析# 计算方式:在一个时间窗口内进行了消费,在下一个时间窗口内又进行了消费def purchase_back(data): status = [] # 存储用户回购率状态 # 1:回购用户 0:非回购用户(当前月消费了,下个月未消费) nan:当前月未消费 for i in range(17): # 当前月份消费了 if data[i] == 1: if data[i+1] == 1: status.append(1) elif data[i+1] == 0: status.append(0) else: # 当前月份未进行消费 status.append(np.NaN) status.append(np.NaN) # 填充最后一列数据 return pd.Series(status, df_purchase.columns)purchase_b = df_purchase.apply(purchase_back, axis=1)# 回购率可视化plt.figure(figsize=(20, 4), dpi=240)plt.subplot(211)# 回购率(purchase_b.sum()/purchase_b.count()).plot(label='回购率')# 复购率(purchase_r.sum()/purchase_r.count()).plot(label='复购率')plt.legend()plt.ylabel('百分比%')plt.title('用户回购率和复购率对比图')# 回购率可知,平稳后在30%左右,波动性稍微较大;复购率低于回购率,平稳后在20%左右,波动性较小;前三个月不论是回购还是复购,都呈现上升趋势,说明新用户需要一定的时间来变成复购或者回购用户# 结合新老用户分析,新客户忠诚度远低于老客户忠诚度# 回购人数与购物总人数plt.subplot(212)plt.plot(purchase_b.sum(), label='回购人数')plt.plot(purchase_b.count(), label='购物总人数')plt.xlabel('month')plt.ylabel('人数')plt.legend()# 前三个月购物总人数远远大于回购人数,主要是因为很多新用户在1月份进行了首次购买;三个月过后,回购人数和购物总数开始稳定,回购人数稳定在1000左右,购物总人数在2000左右
"""方法总结:1.针对用户进行按照月份做整体和个体分析,主要分析维度是人数,消费金额,购买量2.消费分析:首购时间,最后一次购买时间,相邻两个购物时间的间隔,用户分层(RFM模型+数据透视表),分析维度主要是新用户,活跃用户,不活跃用户流失分析,回流用户占比3.复购率和回购率进行分析"""
关键词: