数据分析项目——电商平台用户画像分析

pre:数据集导入及说明

# 导入数据集
df = pd.read_excel("order_data.xlsx")
# 导入用户详情数据集
df_user = pd.read_excel("user_data.xlsx")

包括用户行为数据和用户基本信息数据:

  • 用户行为数据(用户id,行为类型[购买、浏览、收藏、加购],商品id,商品种类,行为日期),共258179条
  • 用户基本信息数据(用户id,性别,年龄,城市,省份,婚姻情况,教育程度,工作等),共222条。
  • 时间跨度:2014-11-18 到 2014-12-18

分析思路

  • 基于用户粒度:对用户按照某种规则打标,便于精准式营销
  • 基于群体粒度:分析一个月在该平台活跃的用户整体情况
    整个分析思路如下图:


    基于用户粒度分析.png

    基于群体粒度分析.png

一、数据预处理

重复值处理
缺失值处理
数据格式处理:
日期格式的转换 astype()

1、重复值处理

查看有无重复值:首先看使用df.info查看各个字段的记录数,再看去除重复值后的数量。以此判断有无重复数据。
去重重复值可以使用函数drop_duplicates()

2、数据格式转换

通过df.info查看数据格式

df.info()
#结果
 #   Column         Non-Null Count   Dtype 
---  ------         --------------   ----- 
 0   user_id        258179 non-null  int64 
 1   item_id        258179 non-null  int64 
 2   behavior_type  258179 non-null  int64 
 3   item_category  258179 non-null  int64 
 4   time           258179 non-null  object

看到time是object类型的,不适合处理。同时我们一般将数据分为日期和时间格式,因此对其进行拆分处理。

  • 处理1:将time拆分为两个字段,一个是日期,一个是时间。方便我们打标。
  • 处理2:转换格式。
    日期格式,可进行日期运算。时间转换为整型,可进行分类。
  • 使用的方法:series的str属性(可以类比hql中的substr函数,对其进行切割),to_datetime函数,astype函数(类比hql中的cast函数)

为各个时段打标,将时段分为'凌晨'、'上午'、'中午'、'下午'、'晚上'
知识点:pd.cut函数,区间分割

df['hour'] = pd.cut(df.time, bins=[-1, 5, 10, 13, 18, 23],labels=['凌晨','上午','中午','下午','晚上'])
日期处理结果.png

3、空值的处理

查看空值,并计算数量。可以看到并无空值。

df.isnull().sum()
#返回
user_id          0
item_id          0
behavior_type    0
item_category    0
time             0
dtype: int64

二、用户消费习惯分析

  • 用户浏览活跃时间段:该用户喜欢在哪个时间段活跃?
  • 用户购物活跃时间段:该用户喜欢在哪个时间段购物?

1、用户浏览/购物活跃时间段

在订单表中按照(用户,时段)分组,取每个时段的记录数(订单数):

# 修改列名item_id为hour_counts
time_browse.rename(columns={'item_id':'hour_counts'},inplace=True)
# 统计每个用户浏览次数最多的时刻
time_browse_max = time_browse.groupby(['user_id']).hour_counts.max().reset_index()
# 进行关联
time_browse = pd.merge(time_browse, time_browse_max, how='inner', on=['user_id','hour')
# 选取各用户浏览次数最多的时刻,如有并列,用逗号连接
time_browse_hour = time_browse.loc[:,'hour'].groupby(time_browse['user_id']).agg(lambda x:','.join(x)).reset_index()

这里的操作流程与hive-sql类似,我们需要先把max算出来,再去关联。
将生成的标签加入标签表:


用户浏览活跃时间.png

同理,可统计出用户购买的活跃时间段,在此不赘述,仅展示结果


用户购物活跃时间.png

2、用户最喜欢的类目

分析用户最喜欢的类目,从而便于我们为其进行推荐。

# 先获取需要的数据集
df_browse = df.loc[df['behavior_type']==1,['user_id','item_id','item_category']]
# 计算每个类目的出现次数
df_cate_browse = df_browse.groupby(['user_id','item_category']).item_id.count().reset_index()
df_cate_browse.rename(columns={'item_id':'cate_counts'},inplace=True)
# 按照user_id计算出现频次最高的类目
df_cate_browse_max = df_cate_browse.groupby('user_id').cate_counts.max().reset_index()
# 关联每个用户的最频繁访问类目
df_cate_browse = pd.merge(df_cate_browse,df_cate_browse_max, how='inner',on=['user_id','cate_counts'])
# 可能存在浏览次数相同的类目,对其进行合并,首先对类型进行转换
df_cate_browse['item_category'] = df_cate_browse['item_category'].astype(str)
df_cate_browse = df_cate_browse.loc[:,'item_category'].\
 groupby(df_cate_browse.user_id).agg(lambda x:','.join(x)).reset_index()
# 将其加入用户标签表
labels = pd.merge(labels, df_cate_browse, how='left',on='user_id')
labels.rename(columns={'item_category':'cate_most_browse'},inplace=True)

最终得到标签表:


各用户最喜欢类目.png

三、RFM分析

  • 用户近30天活跃天数(活跃:有浏览、收藏、加购、购物四种行为之一)
  • 用户最近一次购物距今天数:判断用户最近是否活跃
  • 用户最近两次消费间隔时间:判断用户的消费频率

1、用户近30天行为分析

通过分析用户分析最近的行为,来判断该用户是否活跃、流失

# 用户近30天的购买次数
df_counts_30_buy = df[df.behavior_type==4].groupby('user_id').item_id.count().reset_index()
# 加入标签表
labels = pd.merge(labels,df_counts_30_buy,how='left',on='user_id')
labels.rename(columns={'item_id':'counts_30_buy'},inplace=True)
用户近30天的购买次数.png

分析近30天的活跃天数,只要有浏览、收藏、加购和购物四种行为之一就认为是活跃。

# nunique表示不同日期的天数,去重计数
counts_30_active = df.groupby('user_id')['date'].nunique()
# 加入标签表
labels = pd.merge(labels,counts_30_active,how='left',on='user_id')
labels.rename(columns={'date':'counts_30_active'},inplace=True)

结果如下:


用户近30天活跃天数.png

我们可以通过查看所有用户30天活跃天数的分布情况,来确认一个分类的标准,判断某个用户是否活跃。
用户30天活跃天数分布图如图:


用户30天活跃天数分布情况.png

总体上看,访问天数多的访客比访问天数少的访客数量多,且以20次左右为拐点,因此定义访问天数小于20次的为低活跃,访问天数大于等于20次的定义为高活跃。此定义只是从用户的分布角度出发,工作中当从业务出发定义是否活跃。
labels['buy_active_level'] = '高'
labels.loc[labels['counts_30_buy']<=19,'buy_active_level'] = '低'

同理,可分析用户近7天的行为,包括其购物次数和活跃天数。
与上述操作类似,展示结果:


用户近7天行为分析.png

2、最后一次行为距今天数

明确今天的日期,在本项目中,“今天”指“2014-12-19”,然后统计订单表中用户某种行为的最大日期与当前日期的差值。
使用的函数是:datetime.strptime: new datetime parsed from a string (like time.strptime()) ,将字符串转为date格式,以方便我们做日期运算

days_buy = df[df['behavior_type']==4].groupby('user_id')['date'].max().apply(lambda x:(datetime.strptime('2014-12-19','%Y-%m-%d')-x).days)
#加入标签表
labels = pd.merge(labels,days_buy,how='left',on='user_id')
labels.rename(columns={'date':'days_buy'},inplace=True)

结果如图:


用户最后一次行为距今天数.png

3、最后两次购买行为间隔天数

使用日期的diff函数

# 首先对user_id和date进行分组去重
df_interval_buy = df[df.behavior_type==4].groupby(['user_id','date']).item_id.count().reset_index()
# 然后对date降序排列,对其进行差分,去空后保留第一行
df_interval_buy = df_interval_buy.groupby('user_id').date.apply(lambda x: x.sort_values().diff(1).dropna().head(1)).reset_index()
df_interval_buy['date'] = df_interval_buy['date'].apply(lambda x: x.days)
df_interval_buy.drop('level_1',axis=1,inplace=True)
df_interval_buy.rename({'date':'interval_buy'},inplace=True)
# 将其加入标签
labels = pd.merge(labels,df_interval_buy,how='left',on='user_id')
labels.head()

返回结果


用户最后两次购买行为间隔天数png

4、RFM分组

RFM分组是指按照最近一次消费 (Recency)、消费频率 (Frequency)和消费金额(Monetary)进行分组
最近一次消费,我们按照最后一次购物距今的天数进行分组,同样是观看用户的一个分布情况,然后看如何进行分类。
消费频率,这里放宽要求,按照用户的30天活跃天数进行分类
消费金额,本次不涉及金额的统计。
因此,我们可以根据活跃度分类和最近一次消费将用户划分为四类:

  • 最近一次消费距今天数(近)活跃度(高):重要价值客户
  • 最近一次消费距今天数(远)活跃度(高):重要唤回客户。历史活跃度比较高但是最近没买,说明存在流失的可能,要唤回他。
  • 最近一次消费距今天数(近)活跃度(低):重要深耕客户。最近购买了,但是活跃度不是很高。是我们要努力留住的客户。
  • 最近一次消费距今天数(远)活跃度(低):即将流失客户。历史活跃度比较低且最近没购买,可能用户就要跑路了。
    首先看一下最近一次购物距今天数用户的分布情况,看一下怎么分类。
last_buy_days = labels['days_buy'].value_counts().sort_index()
# 图形绘制
plt.figure(figsize=(16,9))
last_buy_days.plot(title='最后一次购买距今天数与人数的关系',fontsize=18)
plt.ylabel('购买人数',fontsize=14)
plt.xlabel('距今天数',fontsize=14)

结果如图


最后一次消费距今天数分布情况.png

可以看到在第8天前后,用户有明显的分层,因此按照8天对其进行划分,最后一次消费距今天数小于8天的,认为最近有消费,大于8天的认为最近无消费

labels['buy_days_level'] = '高'
labels.loc[labels['days_buy']>8,'buy_days_level'] = '低'
#利用series的字符串属性对值进行拼接
labels['rfm_value'] = labels['buy_active_level'].str.cat(labels['buy_days_level'])
#自定义函数
def trans_value(x):
    if x == '高高':  ## 高活跃且最近购买
        return '重要价值客户' 
    elif x == '低高':  ## 低活跃且最近购买(要继续保持,所以要深耕)
        return '重要深耕客户'
    elif x == '高低':   ##高度活跃但是最近没购买,要唤回
        return '重要唤回客户'
    else:            ##不活跃且最近没有购买
        return '即将流失客户'
labels['rfm'] = labels['rfm_value'].apply(trans_value)

返回结果:


用户RF分层.png

通过value_counts查看每个值的出现次数:

labels['rfm'].value_counts()
#返回
重要深耕客户    114
重要价值客户     67
即将流失客户     40
重要唤回客户      1

四、潜在购物行为分析

  • 是否浏览未下单
  • 是否加购未下单
    提取bahavior=1或者behavior=4的数据,根据用户id、商品id以及用户行为来进行分组,统计每个用户的浏览情况和购买情况,每一个用户对于每一件商品,如果浏览了但是未购买,则将其记为1。
    该标签基于的粒度是(用户,商品),若用户对某一商品浏览未下单,可相应地进行运营策略的投放。
    下面的方法使用了数据透视表,数据透视表可以实现类似于列转行的功能,将原来的数据变为维度,如在下列的方法中,我们将behavior_type变为了维度。
#提取浏览和购买的行为数据
df_browse_buy = df.loc[(df.behavior_type==1) | (df.behavior_type==4),['user_id','item_id','behavior_type','time']]
#使用数据透视表的方法打标浏览未购买的行为
df_browse_buy.head()
browse_not_buy = pd.pivot_table(df_browse_buy,index=['user_id','item_id'], columns=['behavior_type'],values=['time'],aggfunc=['count'])

上述返回的结果值是:


1628926422.png

如果值为空,说明无相应的行为,对浏览未购买的数据记录进行打标
以上的步骤到商品粒度,下面对用户进行统计,即只要用户有浏览未下单的行为就对其进行打标

browse_not_buy = browse_not_buy.groupby('user_id').browse_not_buy.sum().reset_index()
labels = pd.merge(labels, browse_not_buy,how='left',on='user_id')

返回的结果如图:


用户浏览未购买分析.png

加购未下单同上述步骤

五、用户的基本属性分析

分析平台用户的年龄、学历、性别、城市、职业、婚姻情况等,以便于我们去分析我们的典型用户是什么。

1、性别

user_sex = df.groupby('gender').user_id.count()
# autopct设置显示百分比,explode 表示各项距离圆心n个半径
user_sex.plot.pie(y="user_id",figsize=(10,5),explode=[0.01,0.01],autopct='%1.1f%%',title="性别分布图")
用户性别比例.png

从上图可以看出,平台用户中男性居多,女性较少。

2、年龄

值的分层可以使用pd.cut函数

# 用户的年龄分布
bins = [0,20,25,30,35,40,45,50,55,200]
labels =["(0-20]","(20-25]","(25-30]","(30-35]","(35-40]","(40-45]","(45-50]","(50-55]","55岁以上"]
df['age_group'] = pd.cut(df.age, bins=bins, labels=labels)
# 绘制柱状图
age_group = df.groupby('age_group').user_id.count()
age_group.plot.bar(figsize=(10,5),x='age_group',y='user_id',title='用户年龄分布',rot=0)
用户年龄分布.png

从年龄分布图中,可以看出平台的用户以25岁-40岁的用户居多。青年人和中老年用户较少。

3、地域分布

# 地域分布
province_df = df.groupby('province').user_id.count().reset_index().sort_values(by='user_id',ascending=True)
province_df.plot.barh(figsize=(10,5),x='province',y='user_id',legend=False)
# 根据城市排序
city_df = df.groupby('city').user_id.count().reset_index().sort_values(by='user_id',ascending=True)
city_df.plot.barh(x='city', y='user_id',legend=False)

返回结果如下图,从结果中可以看到来自北上广深的用户占绝大部分比例。


省份分布.png

城市分布.png

4、婚姻

从婚姻分布情况中可以看到,平台用户中有超过60%的用户为已婚。


婚姻分布.png

5、学历

使用该平台的用户大部分拥有大学及以上的学历


学历分布.png

6、职业

使用该平台的用户大部分为互联网从业人群


职业分布.png

六、用户购物活跃分析

6.1 用户购物时间

首先查看这一个月的时间跨度用户每天的购物情况:


每天下单用户数.png

从上图可以看出,该平台每天的下单用户数比较平稳,有一些周期性因素在其中,可能是每周周中和周末的购物情况不同。同时,注意到12.12这一天购物用户激增,可能是12.12购物节的因素。

再分析下用户喜欢在周几下单,哪个时间下单


购物日期分布.png

购物时间分布.png

从图中我们可以看到用户的喜欢的购物时间:周五,晚上9点。上午购物的人数都比较少,主要集中在下午和晚上。

6.2 下单用户分层

通过用户的下单情况,我们可以对每周的下单用户进行分层,将其分为活跃用户、不活跃用户和回流用户。

  • 活跃用户:上周消费,本周也消费
  • 回流用户:上周没消费,本周消费
  • 不活跃用户:上周没消费,本周没消费
    首先使用date中的weekofyear函数判断当前日期是本年的第几周,然后根据上一周和本周的活跃情况对用户进行分层。判断分层的代码如下:
def active_status(data):
    status = []
    for i in range(5):
        # 本周有活跃
        if data[i+47] ==1:
            if len(status) > 0:
                if status[i-1] == 'unactive':
                    status.append('return')
                else:
                    status.append('active')
            else:
                status.append('active')
        # 本周不活跃
        else:
            status.append('unactive')

最终结果


用户活跃分层.png

通过面积图看一下每周不同类型用户的比例情况:


不同类型用户比例.png

从图中可以看到,每周活跃的用户数比较平稳

6.3每周复购率分析

复购率:一周内购买多次(>1)的用户占总用户的比例


每周复购率.png

从中可以看到,5周的复购用户都在50%以上,47周和51周的复购率较低,可能是因为数据不完整的原因。

7基于品类的分析

7.1 用户最喜欢品类分析

用户最喜欢购买的品类?
用户最多收藏的品类?


用户购物最多品类TOP5.png

用户收藏最多品类TOP5.png

从结果可见,用户最喜欢购买的品类前五名是6344、12189、5232、1863和4370,用户收藏最多的品类是13230、5894、1863、6513和5027。

7.2 各商品的浏览/购物转换率

转换率=浏览该商品的用户数/购买该商品的用户数
最终结果如图:


各品类转换率.png

查看转换率的分布情况:


转换率情况.png

由于数据原因,存在一人浏览一人购买的情况,所以有部分的转换率为100%。除去此部分数据,大部分的商品转换率在0.5以下。

你可能感兴趣的:(数据分析项目——电商平台用户画像分析)