[Python] 电商平台用户的购物篮分析

目录

  • 一、背景
    • 1. 项目描述
    • 2. 数据描述
  • 二、相关模块
    • 1. 相关模块
    • 2. 数据导入
    • 3. 数据处理
  • 三、商品销售分析
    • 1. 日销售情况
    • 2. 月销售情况
    • 3. 观察畅销品
  • 四、 购物篮分析
    • 1. 购物篮系数
    • 2. 指定商品的购物篮系数
    • 3. 指定商品的人气指数
  • 五、用户行为分析
    • 1. 用户的消费情况
    • 2. 用户初次购物时间
    • 3. 复购率计算
    • 4. 回购率计算
  • 六、小结

一、背景

1. 项目描述

数据来源:https://www.kesci.com/home/project/5f4b17336476cf0036f7d40b/dataset

  • Python版本:3.7.1
  • Pycharm版本:社区版2019.2

2. 数据描述

字段名 解释
InvoiceNo 发票编号
StockCode 商品编号
Description 商品描述
Quantity 购买数量
InvoiceDate 发票日期
UnitPrice 每单位的价格
CustomerID 客户编号
Country 国家

二、相关模块

1. 相关模块

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.stats as sci
from pyecharts.charts import Bar
from pyecharts import options as opts
import pyecharts.charts as pyec
import warnings
warnings.filterwarnings("ignore")

2. 数据导入

# 显示所有行
pd.set_option('display.max_columns', 100)
pd.set_option('display.width', 500)
# 解决中文无法显示的问题
plt.rc('font', family='SimHei', size='12')

io = '.../online_retail.csv'
data = pd.read_csv(io, parse_dates=[4])
df = pd.DataFrame(data)
# 查看数据的描述性统计
print(df.head())
print(df.info())
print(df.describe())
print('数据共{}行'.format(df.shape[0]), ',共{}列'.format(df.shape[1]))
print(df.count())

输出结果如下:

  InvoiceNo StockCode                          Description  Quantity         InvoiceDate  UnitPrice  CustomerID         Country
0    536365    85123A   WHITE HANGING HEART T-LIGHT HOLDER         6 2010-12-01 08:26:00       2.55     17850.0  United Kingdom
1    536365     71053                  WHITE METAL LANTERN         6 2010-12-01 08:26:00       3.39     17850.0  United Kingdom
2    536365    84406B       CREAM CUPID HEARTS COAT HANGER         8 2010-12-01 08:26:00       2.75     17850.0  United Kingdom
3    536365    84029G  KNITTED UNION FLAG HOT WATER BOTTLE         6 2010-12-01 08:26:00       3.39     17850.0  United Kingdom
4    536365    84029E       RED WOOLLY HOTTIE WHITE HEART.         6 2010-12-01 08:26:00       3.39     17850.0  United Kingdom
--------------------------------------------------------------------------
 #   Column       Non-Null Count   Dtype         
---  ------       --------------   -----         
 0   InvoiceNo    541909 non-null  object        
 1   StockCode    541909 non-null  object        
 2   Description  540455 non-null  object        
 3   Quantity     541909 non-null  int64         
 4   InvoiceDate  541909 non-null  datetime64[ns]
 5   UnitPrice    541909 non-null  float64       
 6   CustomerID   406829 non-null  float64       
 7   Country      541909 non-null  object        
dtypes: datetime64[ns](1), float64(2), int64(1), object(4)
--------------------------------------------------------------------------
            Quantity      UnitPrice     CustomerID
count  541909.000000  541909.000000  406829.000000
mean        9.552250       4.611114   15287.690570
std       218.081158      96.759853    1713.600303
min    -80995.000000  -11062.060000   12346.000000
25%         1.000000       1.250000   13953.000000
50%         3.000000       2.080000   15152.000000
75%        10.000000       4.130000   16791.000000
max     80995.000000   38970.000000   18287.000000
--------------------------------------------------------------------------
数据共541909行 ,共8列
InvoiceNo      541909
StockCode      541909
Description    540455
Quantity       541909
InvoiceDate    541909
UnitPrice      541909
CustomerID     406829
Country        541909

3. 数据处理

删除数据中的销售数量Quantity和单位价格UnitPrice存在负数的记录。

# 将负数替换为空值
df[df['Quantity'] < 0] = np.nan
df[df['UnitPrice'] < 0] = np.nan
# 删除含有空值的数据行
df.dropna(subset=['Quantity'], inplace=True)
df.dropna(subset=['UnitPrice'], inplace=True)

新增两列:月份InvoiceDate(M)$和销售金额Sale_Amount。

# 对时间列'InvoiceDate'进行处理
df['InvoiceDate'] = df['InvoiceDate'].values.astype('datetime64[D]')
df['InvoiceDate(M)'] = df['InvoiceDate'].values.astype('datetime64[M]')
# print(df.tail(10))
# 计算每条记录的销售金额Sale_Amount = Quantity × UnitPrice
df['Sale_Amount'] = df['Quantity'] * df['UnitPrice']
print(df.head())

结果如下:

  InvoiceNo StockCode                          Description  Quantity InvoiceDate  UnitPrice  CustomerID         Country InvoiceDate(M)  Sale_Amount
0    536365    85123A   WHITE HANGING HEART T-LIGHT HOLDER       6.0  2010-12-01       2.55     17850.0  United Kingdom     2010-12-01        15.30
1    536365     71053                  WHITE METAL LANTERN       6.0  2010-12-01       3.39     17850.0  United Kingdom     2010-12-01        20.34
2    536365    84406B       CREAM CUPID HEARTS COAT HANGER       8.0  2010-12-01       2.75     17850.0  United Kingdom     2010-12-01        22.00
3    536365    84029G  KNITTED UNION FLAG HOT WATER BOTTLE       6.0  2010-12-01       3.39     17850.0  United Kingdom     2010-12-01        20.34
4    536365    84029E       RED WOOLLY HOTTIE WHITE HEART.       6.0  2010-12-01       3.39     17850.0  United Kingdom     2010-12-01        20.34

三、商品销售分析

1. 日销售情况

# 绘制折线图
plt.figure(1, figsize=(12, 12))
n = 0
for x in ['Quantity', 'Sale_Amount']:
    n += 1
    plt.subplot(2, 1, n)
    plt.subplots_adjust(hspace=5, wspace=5)
    df.groupby('InvoiceDate')[x].sum().plot()
    plt.xlabel('date', color='k', fontsize=10)
    plt.ylabel(x, color='k', fontsize=10)
    # plt.title('{} 趋势图'.format(x), fontsize=10)
    plt.tight_layout()
    plt.grid(linestyle='-.')
plt.show()

结果如下:
[Python] 电商平台用户的购物篮分析_第1张图片

2. 月销售情况

# 绘制折线图
plt.figure(1, figsize=(12, 12))
n = 0
for x in ['Quantity', 'Sale_Amount']:
    n += 1
    plt.subplot(2, 1, n)
    plt.subplots_adjust(hspace=5, wspace=5)
    df.groupby('InvoiceDate(M)')[x].sum().plot()
    plt.xlabel('date', color='k', fontsize=10)
    plt.ylabel(x, color='k', fontsize=10)
    # plt.title('{} 趋势图'.format(x), fontsize=10)
    plt.tight_layout()
plt.show()

月销售金额和数量结果如下:
[Python] 电商平台用户的购物篮分析_第2张图片

3. 观察畅销品

按照商品编号StockCode进行分组。

df_StockCode = df.groupby('StockCode')

由于商品数量比较多,这里仅取前1%的商品。

df_StockCode_q = df_StockCode['Quantity'].sum().sort_values(ascending=False)
# 前1%的商品
df_StockCode_q_len = len(df_StockCode_q)
df_StockCode_q_temp = df_StockCode_q[: int(df_StockCode_q_len * 0.01)]

绘图。

# 各产品的销售数量柱形图
product_bar1 = Bar(init_opts=opts.InitOpts(width='1300px', height='650px'))
# 增加x轴数据
product_bar1.add_xaxis(df_StockCode_q_temp.index.tolist())
# 增加y轴数据
product_bar1.add_yaxis('', df_StockCode_q_temp.values.tolist())
# 全局配置设置
product_bar1.set_global_opts(title_opts=opts.TitleOpts(title="各产品的销售数量分布"),
                     yaxis_opts=opts.AxisOpts(name="销售数量"),
                     xaxis_opts=opts.AxisOpts(name="商品编号", axislabel_opts=opts.LabelOpts(font_size=10, interval=0, rotate=60)),
                     visualmap_opts=opts.VisualMapOpts(is_show=True, type_="color",
                                                       max_=max(df_StockCode_q_temp.values.tolist()), pos_left='-20'))
# 系列配置设置
product_bar1.set_series_opts(markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max", name="max"),
                                                             opts.MarkPointItem(name="min", type_="min")]),
                     markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(name="average", type_="average")]))
product_bar1.render('StockCode_sale_bar.html')

结果如下:
[Python] 电商平台用户的购物篮分析_第3张图片


四、 购物篮分析

购物篮分析来自于线下零售,可以对顾客的购物清单进行分析来洞悉消费者的购物行为。这个概念参考《数据化管理-洞悉零售及电子商务运营》一书。

1. 购物篮系数

购物篮系数是指客户平均购买数量,一个购物篮类似一张客户消费订单,公式如下: 购 物 篮 系 数 = 某 段 时 间 商 品 销 售 数 量 某 段 时 间 的 购 物 篮 总 数 购物篮系数=\frac{某段时间商品销售数量}{某段时间的购物篮总数} \quad =

# 计算购物篮总数
gwl_count = df['InvoiceNo'].count()
# 计算购物篮系数
gwl_coefficient = round((df['Quantity'].sum() / gwl_count), 2)
print('购物篮系数为: {}'.format(gwl_coefficient))

结果如下,即平均每位客户一次性购买10.66件商品。

购物篮系数为: 10.66

2. 指定商品的购物篮系数

指 定 商 品 购 物 篮 系 数 = 某 段 时 间 指 定 商 品 购 物 篮 的 销 售 总 数 某 段 时 间 含 指 定 商 品 的 购 物 篮 总 数 指定商品购物篮系数=\frac{某段时间指定商品购物篮的销售总数}{某段时间含指定商品的购物篮总数} \quad = 举个例子,上个月中,共有2000张销售订单中包含某品牌巧克力,而这2000张销售单一共包含8000件商品,则某品牌巧克力的购物篮系数为4。

df_StockCode_q_temp = df_StockCode_q.reset_index()
df_i_s = df[['InvoiceNo', 'StockCode']]
# 统计各张订单的总销售量
df_InvoiceNo = df.groupby('InvoiceNo')['Quantity'].sum()
df_i_s_q = pd.merge(df_i_s, df_InvoiceNo, on=['InvoiceNo'], how='inner')

自定义函数

# 计算含有某商品的订单数
def search_stockcode(data):
    # 将循环的每一行(series)转换成Dataframe
    stockcode_temp = data.to_frame()
    stockcode = pd.DataFrame(stockcode_temp.values.T, columns=stockcode_temp.index)
    # 表链接,查询原有数据中包含当前产品编号的订单记录。
    merge_temp = pd.merge(df_i_s_q, stockcode['StockCode'], on=['StockCode'], how='inner')
    # 分别统计有多少张订单包含该商品,以及这些订单的销售总数量
    order_count = len(merge_temp)
    quantity_sum = merge_temp['Quantity'].sum()
    return order_count, quantity_sum
df_StockCode_q_temp[['order_count', 'order_quantity_sum']] = df_StockCode_q_temp.apply(lambda x: search_stockcode(x),                                                                                       axis=1, result_type='expand')
df_StockCode_temp['gwl'] = df_StockCode_temp['order_quantity_sum'] / df_StockCode_temp['order_count']
# 删除“异常值”
df_StockCode_temp_1 = df_StockCode_temp[df_StockCode_temp['order_quantity_sum'] < 10000]
# 绘制散点图
sns.jointplot(x=df_StockCode_temp_1['gwl'], y=df_StockCode_temp_1['order_quantity_sum'],
              data=df,                               # 设置数据
              color='b',                             # 设置颜色
              s=30, edgecolor='w', linewidth=1,      # 设置散点大小、边缘颜色及宽度(只针对scatter)
              stat_func=sci.pearsonr,
              kind='scatter',                        # 设置类型:'scatter','reg','resid','kde','hex'
              space=0.05,                            # 设置散点图和布局图的间距
              size=9,                                # 图表大小(自动调整为正方形))
              ratio=5,                               # 散点图与布局图高度比,整型
              marginal_kws=dict(bins=10, rug=True),  # 设置柱状图箱数,是否设置rug
              )
plt.show()
  • 结果如下。但是,高购物篮系数的商品不一定是人气商品,例如商品A的购物篮系数为4,而商品B的购物篮系数为3.5,我们不能说商品A的人气更高,只能说明购买了商品A的客户同时购买了更多的其他商品。人气商品不但要求购物篮系数高,销售单总量也不少。
  • 另外,可以绘制四象限分析图,分别针对每一象限的客户指定相应的运营措施。例如,对于右上角(称为第一象限)的客户,即购物篮系数和购物篮数量都高于均值的,他们应该是销售量和平台人气的主要来源,也是促销活动的重点考虑对象。
    [Python] 电商平台用户的购物篮分析_第4张图片

3. 指定商品的人气指数

指 定 商 品 的 人 气 指 数 = 某 段 时 间 含 指 定 商 品 购 物 篮 的 销 售 总 数 某 段 时 间 的 购 物 篮 总 数 指定商品的人气指数=\frac{某段时间含指定商品购物篮的销售总数}{某段时间的购物篮总数} \quad =人气指数并不是指定商品的销售数量的比重,销售数量比重只能判断该商品卖得还不好。人气指数高的商品不一定是卖得最好的,但是它带来的销售量是最大的。
例如,上月销售了10万件商品,共2万个购物篮。部分数据如下。虽然商品B销量比A少,但是含商品B的购物篮一共销售了4200件,大于A的3200,人气指数为0.21。

/ 商品A 商品B
销售量 2600 1500
占总销售 2.6% 1.5%
含该商品的购物篮数 3200 4200
人气指数 0.16 0.21
# 计算商品的人气指数
df_StockCode_temp['rqzs'] = df_StockCode_temp['order_quantity_sum'] / gwl_count
df_StockCode_temp_len = len(df_StockCode_temp)
df_StockCode_temp_2 = df_StockCode_temp.sort_values(by='rqzs', ascending=False)[: int(df_StockCode_q_len * 0.01)]
# 各产品的销售数量柱形图
product_bar2 = Bar(init_opts=opts.InitOpts(width='1300px', height='650px'))
# 增加x轴数据
product_bar2.add_xaxis(df_StockCode_temp_2['StockCode'].tolist())
# 增加y轴数据
product_bar2.add_yaxis('', df_StockCode_temp_2['rqzs'].tolist())
# 全局配置设置
product_bar2.set_global_opts(title_opts=opts.TitleOpts(title="商品人气指数"),
                     yaxis_opts=opts.AxisOpts(name="人气指数"),
                     xaxis_opts=opts.AxisOpts(name="商品编号", axislabel_opts=opts.LabelOpts(font_size=10, interval=0, rotate=60)),
                     visualmap_opts=opts.VisualMapOpts(is_show=True, type_="color",
                                                       max_=max(df_StockCode_temp_2['rqzs'].tolist()), pos_left='-20'))
# 系列配置设置
product_bar2.set_series_opts(markpoint_opts=opts.MarkPointOpts(data=[opts.MarkPointItem(type_="max", name="max"),
                                                             opts.MarkPointItem(name="min", type_="min")]),
                     markline_opts=opts.MarkLineOpts(data=[opts.MarkLineItem(name="average", type_="average")]),
                             label_opts=opts.LabelOpts(is_show=False))
product_bar2.render('StockCode_rqzs_bar.html')

结果如下:
[Python] 电商平台用户的购物篮分析_第5张图片


五、用户行为分析

1. 用户的消费情况

df_user = df.groupby('CustomerID')
sns.jointplot(x=df_user['Sale_Amount'].sum(), y=df_user['Quantity'].sum(),
              data=df,                               # 设置数据
              color='b',                             # 设置颜色
              s=50, edgecolor='w', linewidth=1,      # 设置散点大小、边缘颜色及宽度(只针对scatter)
              stat_func=sci.pearsonr,
              kind='scatter',                        # 设置类型:'scatter','reg','resid','kde','hex'
              space=0.05,                            # 设置散点图和布局图的间距
              size=8,                                # 图表大小(自动调整为正方形))
              ratio=5,                               # 散点图与布局图高度比,整型
              marginal_kws=dict(bins=10, rug=True),  # 设置柱状图箱数,是否设置rug
              )
plt.show()

结果如下:
[Python] 电商平台用户的购物篮分析_第6张图片

2. 用户初次购物时间

df_user['InvoiceDate(M)'].min().value_counts().plot(marker='o')
plt.grid(linestyle='-.')
plt.show()

结果如下,大部分的用户是在前几个月进入平台消费的。
[Python] 电商平台用户的购物篮分析_第7张图片

3. 复购率计算

df_pivot_counts = df.pivot_table(index='CustomerID', columns='InvoiceDate(M)', values='Quantity', aggfunc='count')
print()
print(df_pivot_counts)
# 将数据中两次及以上的转为1,以下的转为0
df_pivot_counts_repurchase = df_pivot_counts.applymap(lambda x: 1 if x >= 2 else 0 if pd.notnull(x) else np.nan)
(df_pivot_counts_repurchase.sum()/df_pivot_counts_repurchase.count()).plot(marker='o')
plt.title('每月的复购率')
plt.grid(linestyle='-.')
plt.show()

结果如下:
[Python] 电商平台用户的购物篮分析_第8张图片

4. 回购率计算

自定义函数:

def cal_hgl(x):
    status = []
    for i in range(len(x)-1):
        # 该顾客在当月有消费
        if x[i] > 0:
            if x[i+1] > 0:
                # 下个月依然消费
                status.append(1)
            else:
                status.append(0)
        else:
            status.append(np.nan)
    # 数据填充
    status.append(np.nan)
    return status

计算每月回购率。

df_pivot_counts_hgl = df_pivot_counts.apply(lambda x: pd.Series(cal_hgl(x), index=x.index), axis=1)  # axis=1指对行数据进行操作
(df_pivot_counts_hgl.sum()/df_pivot_counts_hgl.count()).plot(marker='o')
plt.title('每月的回购率')
plt.grid(linestyle='-.')
plt.show()

结果如下:
[Python] 电商平台用户的购物篮分析_第9张图片

六、小结

后续可以继续做客户的留存分析

你可能感兴趣的:(数据分析,python,数据分析)