由于有之前的项目,所以今天我们直接开始,不做需求分析,还不会需求分析的可以看我之前的文章。Python实战项目——用户消费行为数据分析(三)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei']# 用来正常显示中文标签
from datetime import datetime
df = pd.read_csv('kelu.csv')
df.info()
df.head()
df.describe()
df['time'] = pd.to_datetime(df['time'],format='%Y/%m/%d')
df.groupby('time')['rating'].count().plot(figsize=(12,4))
df['month'] = df['time'].values.astype('datetime64[M]') #保留月份精度的日期
df.head()
df.groupby('month')['rating'].count().plot(figsize=(12,4)) #按照月份进度进行计数
plt.xlabel('月份')
plt.ylabel('销售数量')
plt.title('16~19年每月销量分析')
月份整体销量依然呈现上升趋势,但是在18年2,3,4月份月销量下滑明显。跟每天销量下降有关。猜测:台风,疫情,运营推广不利
merge用法,相当于sql当中join:
df1 = pd.DataFrame({
'name':['zhangsan','lisi'],
'group':['A','B']
})
df2 = pd.DataFrame({
'name':['wangwu','lisi'],
'score':[88,90],
'group':['C','D']
})
pd.merge(left=df1,right=df2,on='name',how='inner',suffixes=['_1','_2'])
left:左表 right:右表 on:关联字段 how:inner(默认值,交集)|outer(并集)|left(只保留左侧)|right(只保留右侧) #suffixes:如果两个表中有多个相同列,用suffixes给的值进行区分(默认值xy)
#按照游客分组,统计每个游客的购买次数
grouped_count_author = df.groupby('author')['frequency'].count().reset_index()
#按照游客分组,统计每个游客的消费金额
grouped_sum_amount = df.groupby('author')['amount'].sum().reset_index()
user_purchase_retention = pd.merge(left=grouped_count_author,
right=grouped_sum_amount,
on='author',
how='inner')
user_purchase_retention.tail(60)
user_purchase_retention.plot.scatter(x='frequency',y='amount',figsize=(12,4))
plt.title('用户的购买次数和消费金额关系图')
plt.xlabel('购物次数')
plt.ylabel('消费金额')
结论:斜率就是门票价格110,用户的消费金额和消费次数呈现线性关系
df.groupby('author')['frequency'].count().plot.hist(bins=50) #影响柱子的宽度,宽度= (最大值-最小值)/bins
plt.xlim(1,17)
plt.xlabel('购买数量')
plt.ylabel('人数')
plt.title('用户购买门票数量直方图')
df_frequency_2 = df.groupby('author').count().reset_index()
df_frequency_2.head()
df_frequency_2[df_frequency_2['frequency']>=2].groupby('author')['frequency'].sum().plot.hist(bins=50)
plt.xlabel('购买数量')
plt.ylabel('人数')
plt.title('购买门票在2次及以上的用户数量')
消费两次的用户在整体上占比较大,大于2次的用户占小部分,用户购买次数最多为8次
df_frequency_2[df_frequency_2['frequency']>=2].groupby('frequency')['author'].count()
出去购买一次的顾客,可以看出购买2次有402人,购买3次的99人,以此类推得知大多数据倾向于购买2~5
1.按照用户进行分组 2.取出购买次数 3.过滤出1~5次用户 4.绘制饼图
df_frequency_gte_1 = df.groupby('author')['frequency'].count().reset_index()
#过滤出<=5次的用户
values = list(df_frequency_gte_1[df_frequency_gte_1['frequency']<=5].groupby('frequency')['frequency'].count())
print(values)
plt.pie(values,labels=['购买1次','购买2次','购买3次','购买4次','购买5次'],autopct='%1.1f%%')
plt.title('购买次数在1~5次之间的人数占比')
plt.legend()
可以看出购买一次的占比83%,其次逐渐递减。并且递减比较明显,购买3.4.5的占比相近,人数都很少。
#过滤出>=2次并且<=5次的用户
df_frequency_gte_2 = df_frequency_2[df_frequency_2['frequency']>=2].reset_index()
values = list(df_frequency_gte_2[df_frequency_gte_2['frequency']<=5].groupby('frequency')['frequency'].count())
print(values)
plt.pie(values,labels=['购买2次','购买3次','购买4次','购买5次'],autopct='%1.1f%%')
plt.title('购买次数在2~5次之间的人数占比')
plt.legend()
在2~5次之间,购买2.3次用户占比最大,综合占据了80%
复购率:在某一时间窗口内(多指一个月)内消费次数在两次及以上的用户在总消费用户的占比
df.head()
pivot_count = df.pivot_table(index='author',
columns='month',
values='frequency',
aggfunc='count').fillna(0)
pivot_count.head()
#三种情况:
#消费次数>1,为复购用户,用1表示
#消费次数=1,为非复购用户,用0表示
#消费次数=0, 未消费用户,用na表示
#applymap:df,处理每一个元素
#apply:df,处理每一行或者每一列数据
#map:Serise,处理每一个元素
pivot_count = pivot_count.applymap(lambda x: 1 if x>1 else np.NAN if x==0 else 0)
# pivot_count[pivot_count['2016-09-01']==1]
(pivot_count.sum()/pivot_count.count()).plot()
plt.xlabel('时间(月)')
plt.ylabel('百分比(%)')
plt.title('16~19年每月用户复购率')
16年9月份复购率最高达到了7.5%,然后开始下降,趋于平稳在1.2%
pivot_count.sum().plot()
plt.xlabel('时间/月')
plt.ylabel('复购人数')
plt.title('16~19年每月的复购人数折线图'
回购率:在某一个时间窗口内消费过的用户,在下一个时间窗口仍旧消费的占比。 举个例子:当前月消费用户人数1000人,其中200人在下一个月仍旧进行了消费,回购率200/1000=20%
pivot_purchase = df.pivot_table(index='author',
columns='month',
values='frequency',
aggfunc='count'
).fillna(0)
pivot_purchase.head()
len(pivot_purchase.columns)
def purchase_return(data): #data:代表的是每一名游客的所有月份消费记录
status = [] #存储每一个月回购状态
for i in range(30):#遍历每一个月(最后一个月除外)
####本月消费
if data[i] == 1:
if data[i+1] ==1:#下个月有消费,是回购用户,1
status.append(1)
else:#na|未消费
status.append(0) #非回购用户,0
else: ####本月未消费
status.append(np.NaN)
status.append(np.NaN)
return pd.Series(status,pivot_purchase.columns)
pivot_purchase_return = pivot_purchase.apply(purchase_return,axis=1) #用户回购状态
(pivot_purchase_return.sum()/pivot_purchase_return.count()).plot()
plt.title('16年~19年每月的回购率')
plt.xlabel('月份')
plt.ylabel('回购率%')
pivot_purchase_return.sum().plot()
plt.title('16年~19年每月的回购人数')
plt.xlabel('月份')
plt.ylabel('回购人数')
print(pivot_purchase_return.sum())
活跃用户|不活跃用户|回流用户|新用户
def active_status(data): #data:每一行数据(共31列)
status = [] #存储用户31个月的状态(new|active|unactive|return|unreg)
for i in range(31):
#判断本月没有消费==0
if data[i] ==0:
if len(status)==0: #前几个月没有任何记录(也就是97年1月==0)
status.append('unreg')
else:#之前的月份有记录(判断上一个月状态)
if status[i-1] =='unreg':#一直没有消费过
status.append('unreg')
else:#上个月的状态可能是:new|active|unative|reuturn
status.append('unactive')
else:#本月有消费==1
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
status.append('active') #活跃用户
return pd.Series(status,pivot_purchase.columns) #值:status,列名:18个月份
pivot_purchase_status =pivot_purchase.apply(active_status,axis=1)
pivot_status_count =pivot_purchase_status.replace('unreg',np.NaN).apply(pd.value_counts)
pivot_status_count.T.plot.area()
return_rate = pivot_status_count.apply(lambda x:x/x.sum())
return_rate.T.plot()
return_rate.T['active'].plot(figsize=(12,6))
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.title('每月活跃用户的占比分析')
return_rate.T['return'].plot(figsize=(12,6))
plt.xlabel('时间(月)')
plt.ylabel('百分比')
plt.title('每月回流用户的占比分析')
np.mean(return_rate.T['return']) #回流用户平均值在0.73%左右
#计算方式:每一个用户最后一个购买商品的时间——用户第一次购买商品的时间,转换成天数,即为生命周期
time_min = df.groupby('author')['time'].min()
time_max = df.groupby('author')['time'].max()
life_time = (time_max-time_min).reset_index()
life_time.describe()
#讲日期类型转成数值类型
life_time['life_time'] = life_time['time']/np.timedelta64(1,'D')
life_time['life_time'].plot.hist(bins = 100,figsize=(12,6))
plt.xlabel('天数')
plt.ylabel('人数')
plt.title('所有用户的生命周期直方图')
print(life_time[life_time['life_time']==0])
life_time[life_time['life_time']>0]['life_time'].plot.hist(bins = 100,figsize=(12,6))
plt.xlabel('天数')
plt.ylabel('人数')
plt.title('生命周期在0天以上的用户分布直方图')
life_time[life_time['life_time']>0]['life_time'].mean()
#pd.cut()函数
np.random.seed(666) #保证每次运行程序产生的随机数都是相同的。
score_list = np.random.randint(25,100,size=3)
print(score_list)
bins = [0,59,70,80,100] #指定多个区间
score_cut = pd.cut(score_list,bins)
score_cut
user_purchase_retention = pd.merge(left=df,right=time_min.reset_index(),how='inner',on='author',suffixes=('','_min'))
#计算留存天数
user_purchase_retention['time_diff'] = user_purchase_retention['time']-user_purchase_retention['time_min']
#将time_diff转成数值
user_purchase_retention['time_diff'] = user_purchase_retention['time_diff'].apply(lambda x:x/np.timedelta64(1,'D'))
#生成时间跨度(3个月,即90天),判断属于哪个区间
bin = [i*90 for i in range(11)]
user_purchase_retention['time_diff_bin'] = pd.cut(user_purchase_retention['time_diff'],bin)
#统计每个游客,在不同的时间段内的消费频率和值(便于稍后判断该用户在某个区间内是不是留存用户)
pivot_retention = user_purchase_retention.groupby(['author','time_diff_bin'])['frequency'].sum().unstack()
#判断是否是留存用户(1:留存,0:未留存)
pivot_retention_trans = pivot_retention.fillna(0).applymap(lambda x:1 if x>0 else 0)
#留存率
print(pivot_retention_trans.sum()/pivot_retention_trans.count())
(pivot_retention_trans.sum()/pivot_retention_trans.count()).plot.bar()
plt.xlabel('时间跨度(天)')
plt.ylabel('留存率')
plt.title('各时间段内的用户留存率')