数据是CDNow网站的用户购买明细。一共有用户ID,购买日期,购买数量,购买金额四个字段。我们通过案例数据完成一份基础的数据分析报告
数据获取可以可以通过百度网盘,
https://pan.baidu.com/s/1o794j3s 提取码2hge。
使用pylab 模式进入ipython,这个模式会自动的加载matplotlib;
在控制在键入ipython –pylab ,回车;
导入数据,
import pandas as pd
columns = ['user_id','order_dt','order_products','order_amount']
df = pd.read_csv('CDNOW_master.txt',names=columns,sep='\s+') # 分隔符用\s+表示匹配任意空白符。
查看数据的一般统计描述,
df.describe()
df.info()
进行时间的数据类型转换,
df['order_date'] = pd.to_datetime(df.order_dt,format='%Y%m%d') # 提取出时间信息
df['month'] = df.order_date.values.astype('datetime64[M]') # 将日期转换为月份.
将月份作为消费行为的主要事件窗口,选择哪种时间窗口取决于消费频率。
进行分组聚合操作,
df.groupby('user_id').sum().describe()
按月进行分析,
df.groupby('month').order_products.sum().plot()
df.groupby('month').order_amount.sum().plot()
绘制每笔订单的散点图,
df.plot.scatter(x='order_amount',y='order_products')
每个用户的散点图,
df.groupby('user_id').sum().plot.scatter(x='order_amount',y='order_products')
分析每个用户的消费能力,
df.groupby('user_id').sum().order_amount.plot(kind='hist',bins=1000,xlim=(0,1000))
用groupby函数将用户分组,并且求月份的最小值,最小值即用户消费行为中的第一次消费时间。 最大值为最后一次消费时间。
df.groupby('user_id').month.min().value_counts()
df.groupby('user_id').month.max().value_counts()
分析消费中的复购率和回购率
pivoted_counts = df.pivot_table(index='user_id',columns='month',values='order_dt',aggfunc='count').fillna(0)
首先求复购率,复购率的定义是在某时间窗口内消费两次及以上的用户在总消费用户中占比。这里的时间窗口是月,如果一个用户在同一天下了两笔订单,这里也将他算作复购用户。
将数据转换一下,消费两次及以上记为1,消费一次记为0,没有消费记为NaN。
pivoted_counts_tran = pivoted_counts.applymap(lambda x: 1 if x > 1 else np.NaN if x == 0 else 0)
如果有复购值就会是1,所以sum除count就是我们要求的复购率,而NaN值并不会被计算,
(pivoted_counts_tran.sum()/pivoted_counts_tran.count()).plot()
单看新客和老客,复购率有三倍左右的差距。
回购率是某一个时间窗口内消费的用户,在下一个时间窗口仍旧消费的占比。比如1月消费用户1000,他们中有300个2月依然消费,回购率是30%。
# 使用一个函数来判断是否有回购情况
def purchase_return(user):
status = []
for i in range(17):
if user[i] >= 1:
if user[i + 1] >= 1:
status.append(1)
else:
status.append(0)
else:
status.append(np.NaN)
status.append(np.NaN)
return status
pivoted_purchase_return = pivoted_counts.apply(purchase_return,axis=1) # 用apply函数应用在所有行上,就是每一个用户上
(pivoted_purchase_return.sum()/pivoted_purchase_return.count()).plot()
将回购率和复购率综合分析,可以得出,新客的整体质量低于老客,老客的忠诚度(回购率)表现较好,消费频次稍次,这是CDNow网站的用户消费特征。
接下来进行用户分层,我们按照用户的消费行为,简单划分成几个维度:新用户、活跃用户、不活跃用户、回流用户。
新用户的定义是第一次消费。活跃用户即老客,在某一个时间窗口内有过消费。不活跃用户则是时间窗口内没有消费过的老客。回流用户是在上一个窗口中没有消费,而在当前时间窗口内有过消费。以上的时间窗口都是按月统计。
比如某用户在1月第一次消费,那么他在1月的分层就是新用户;他在2月消费国,则是活跃用户;3月没有消费,此时是不活跃用户;4月再次消费,此时是回流用户,5月还是消费,是活跃用户。
分层会涉及到比较复杂的逻辑判断。
def active_status(user):
status = []
for i in range(17):
if user[i] == 0:
if len(status) > 0:
if status[i-1] == 'regis': #未注册
status.append('regis')
else:
status.append('unactive')
else:
status.append('regis')
else:
if len(status) == 0:
status.append('new')
else:
if status[i-1] == 'regis':
status.append('new')
elif status[i-1] == 'unactive':
status.append('return')
else:
status.append('active')
return status
pivoted_status = pivoted_counts.apply(active_status,axis=1)
status_counts =pivoted_status.replace('regis',np.NaN).apply(lambda x:pd.value_counts(x)) #统计计数 regis状态排除掉,它是「未来」才作为新客,这么能计数呢.
status_counts.fillna(0).T.plot(kind='area')
rate =status_counts.apply(lambda x:x/x.sum(),axis=1)
rate.loc['return'].plot()
rate.loc['active'].plot()
查看用户回流率,活跃度,图这里就不贴了
回流占比,就是回流用户在总用户中的占比。另外一种指标叫回流率,指上个月多少不活跃/消费用户在本月活跃/消费。因为不活跃的用户总量近似不变,所以这里的回流率也近似回流占比。
结合回流用户和活跃用户看,在后期的消费用户中,60%是回流用户,40%是活跃用户/连续消费用户,整体质量还好,但是针对这两个分层依旧有改进的空间,可以继续细化数据。
用户消费数据的概率分布,
ser_amount = df.groupby('user_id').order_amount.sum().sort_values().reset_index() # 排序
user_amount['amount_cumsum'] = user_amount.order_amount.cumsum() # 累加
user_amount['prop'] = user_amount.apply(lambda x:x.amount_cumsum/user_amount.amount_cumsum.max(),axis=1) # 求概率分布
user_amount.prop.plot()
计算用户生命周期,这里定义第一次消费至最后一次消费为整个用户生命。
(df.groupby('user_id').order_date.max() - df.groupby('user_id').order_date.min()).describe()
所有用户的平均生命周期是134天,但一多半用户都是0;
看一下分布图,
((df.groupby('user_id').order_date.max() - df.groupby('user_id').order_date.min())/np.timedelta64(1,'D')).hist(bins=100) # 换算的方式直接除timedelta函数即可,这里的np.timedelta64(1, 'D'),D表示天,1表示1天,作为单位使用的
life_time =(df.groupby('user_id').order_date.max() - df.groupby('user_id').order_date.min())/np.timedelta64(1,'D')
life_time[life_time > 0].hist(bins=200) # 也可以再给life_time加一个column让他讲他转为Dataframe
再来计算留存率,留存率也是消费分析领域的经典应用。它指用户在第一次消费后,有多少比率进行第二次消费。和回流率的区别是留存倾向于计算第一次消费,并且有多个时间窗口。
user_purchase = df[['user_id','order_products','order_amount','order_date']]
user_retention = pd.merge(left=user_purchase,right=df.groupby('user_id').order_date.min().reset_index(),how='inner',on='user_id',suffixes=('_max','_min'))
这里用到merge函数,它和SQL中的join差不多,用来将两个DataFrame进行合并。我们选择了inner 的方式,对标inner join。即只合并能对应得上的数据。这里以on=user_id为对应标准。这里merge的目的是将用户消费行为和第一次消费时间对应上,形成一个新的DataFrame。suffxes参数是如果合并的内容中有重名column,加上后缀。
user_retention['diff'] = (user_retention['order_date'] - user_retention['order_date_min']).apply(lambda x:x/np.timedelta64(1,'D'))
获得用户每一次消费距第一次消费的时间差值,
将时间差值分桶。我这里分成0~3天内,3~7天内,7~15天等,代表用户当前消费时间距第一次消费属于哪个时间段呢。这里date_diff=0并没有被划分入0~3天,因为计算的是留存率,如果用户仅消费了一次,留存率应该是0。另外一方面,如果用户第一天内消费了多次,但是往后没有消费,也算作留存率0。
user_retention['diff_bin']= pd.cut(user_retention['diff'],bins=[0,3,7,15,60,90,180,365])
user_retention.describe()
但消费更多是一个相对的概念,我们还要看整体中有多少用户在0~3天消费。
用pivot_table数据透视,获得用户在第一次消费之后,在后续各时间段内的消费总额。
pivoted = user_retention.pivot_table(index='user_id',columns='diff_bin',values='order_amount',aggfunc=sum)
pivoted_trans = pivoted.fillna(0).applymap(lamda x:1 if x>0 else 0)
(pivoted_trans.sum()/pivoted_trans.count()).plot(kind='bar')
求出用户的消费间隔,
def diff(group):
d = group.diff - group.diff.shift(-1)
return d
last_diff = user_retention.groupby('user_id').apply(diff)
last_diff.mean()
然后就简单了,用mean函数即可求出用户的平均消费间隔时间是68天。想要召回用户,在60天左右的消费间隔是比较好的。
也可以画一个柱状图,
last_dfff.hist(bins=20)
假若大家有兴趣,不妨多做几个分析假设,看能不能用Python挖掘出更有意思的数据,1月、2月、3月的新用户在留存率有没有差异?不同生命周期的用户,他们的消费累加图是什么样的?消费留存,划分其他时间段怎么样?
这里的数据只是用户ID,消费时间,购买量和消费金额。如果换成用户ID,浏览时间,浏览量,能不能直接套用?浏览变成评论、点赞又行不行?消费行为变成用户其他行为呢?我可以明确地告诉你,大部分代码只要替换部分就能直接用了。
作者:苟雨
链接:https://www.jianshu.com/p/aa54a2df6f0d
本文来自简书,观点不代表一起大数据-技术文章心得立场,如若转载,请注明出处:https://www.jianshu.com/p/aa54a2df6f0d
注意:本文归作者所有,未经作者允许,不得转载