前几天老师发下来一个任务,需要模仿 《CDNow 网站用户消费行为分析》,自己选择一个同类型的数据集进行分析。我不是数据分析专业的,只能照葫芦画瓢去对类似的数据进行分析。本文就是对整个项目操作进行一次梳理,并记录过程中因环境版本更新等原因所采的坑。

CDNow 数据集可以点此下载,完整的 CDNow 数据分析 Jupyter-notebook 可以在此进行下载。

一般上,电商数据集是电商公司的专有财产,因为它可以用于作为用户行为消费、产品销量等重要指标的分析数据。我通过 Kaggle 网站找到了 E-Commerce Data 数据集。以下是该数据集的介绍:

通常,电商数据集是专有的,因此在公开可用的数据中很难找到。然而,UCI机器学习库提供了这个包含2010年和2011年实际交易的数据集。该数据集在其网站上维护,可以通过标题 “Online Retail” 找到。

我们在数据集的介绍资料中了解到:这是一个跨国数据集,其中包含一家总部位于英国的注册非实体店在线零售公司在 2010 年 1 月 12 日至 2011 年 9 月 12 日之间发生的所有交易。该公司主要销售独特的全场合礼品。公司的许多客户都是批发商。

项目要求

通过项目要求以及我们所找到的数据集,可以进行以下分析:

用户消费特征

  1. 用户整体消费分析:计算总收入、平均购买值等指标。
  2. 用户个人消费分析:观察每位用户的购买次数、总收入等。
  3. 用户消费周期分析:
    1. 用户购买周期:计算用户购买相邻两次之间的时间间隔。
    2. 用户生命周期:从第一次购买到最后一次购买的时间跨度。

用户分层

  1. 用户价值度分析——RMF 模型:根据最近购买时间、购买频率、总收入等指标进行分层。
  2. 用户活跃层分析:
    1. 新用户:首次购买时间在分析期内。
    2. 活跃用户:购买频率高的用户。
    3. 不活跃用户:购买频率低的用户。
    4. 回流用户:曾经不活跃,然后再次购买的用户。

如何提高用户质量

  1. 多少用户仅消费了一次?统计购买次数为1的用户数量。
  2. 复购率:计算有多少用户购买了多次。
  3. 回购率:计算有多少用户在分析期内再次购买。
  4. 留存率:观察用户在不同时间段的留存情况。
  5. 客户贡献率:计算每位用户对总收入的贡献比例。

开发环境

我使用的开发环境如下:

  • Python 3.9.13
  • numpy==1.26.2
  • pandas==2.1.4
  • matplotlib==3.8.2
  • jupyter_core==5.5.0

开始分析

由于下载好的数据集就是 .csv 文件,我们直接用 pandas 的 read_csv() 函数将路径传入打开即可。打开后出现了第一个报错:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xa3 in position 79780: invalid start byte

这里,我使用 PyCharm 打开 csv 文件,发现文件是使用 ISO-8859-1 的编码格式进行保存的,所以打开时,我们也需要设定对应的 encoding,然后我也发现 CustomerIDInvoiceID 是由一串数值组成的,但是对于统计中,他们得属于是字符串,否则会出现奇怪的统计现象,所以我将他们使用 dtype 参数修改为字符串。具体 read_csv 函数调用如下:

df = pd.read_csv("Data/E-Commerce Data/data.csv", encoding="ISO-8859-1",
dtype={'CustomerID': str, 'InvoiceID': str})

对于数据的预处理,我首先统计了数据的空值,主要有空值的列是 CustomerID,空值占比近 25%,这些空值会影响后续的统计,所以我们将其舍弃掉,使用 dropna 函数将 CustomerID 为空的列剔除。我们也需要将重复的数据行进行剔除,用 drop_duplicates 函数做到这点。然后再将原数据不需要的列进行删减,留下:订单数、订单额、购买日期,用户 ID 这四个字段来分析。由于此数据集的所有交易是基于订单的(Invoice)所以我们需要合并所有相同 CustomerID 和 InvoiceID 的订单成一条记录。并提取出该订单发生的月份。

# 转换日期格式
df['InvoiceDate'] = pd.to_datetime(df['InvoiceDate'])

# 提供关于列类型和空值数量的一些信息
tab_info = pd.DataFrame(df.dtypes).T.rename(index={0: '列类型'})
tab_info = pd.concat([tab_info, pd.DataFrame(df.isnull().sum()).T.rename(index={0: '空值数量 (个)'})])
tab_info = pd.concat(
[tab_info, pd.DataFrame(df.isnull().sum() / df.shape[0] * 100).T.rename(index={0: '空值百分比 (%)'})])

print('Dataframe dimensions: ', df.shape)

display(tab_info)

# 剔除空值数据项
df.dropna(axis=0, subset=['CustomerID'], inplace=True)

# 提供关于列类型和空值数量的一些信息
tab_info = pd.DataFrame(df.dtypes).T.rename(index={0: '列类型'})
tab_info = pd.concat([tab_info, pd.DataFrame(df.isnull().sum()).T.rename(index={0: '空值数量 (个)'})])
tab_info = pd.concat(
[tab_info, pd.DataFrame(df.isnull().sum() / df.shape[0] * 100).T.rename(index={0: '空值百分比 (%)'})])

print('Dataframe dimensions: ', df.shape)

display(tab_info)

# 删除重复数据项
df.drop_duplicates(inplace=True)

# 转换 Quantity 列为数值型
df['Quantity'] = pd.to_numeric(df['Quantity'], errors='coerce')

# 计算 TotalPrice 列
df['TotalPrice'] = df['Quantity'] * df['UnitPrice']

# 创建 ItemQuantities 列
df['ItemQuantities'] = df['Quantity']

# 创建 Cancelled 列
df['Cancelled'] = df['InvoiceNo'].str.startswith('C')

# 选择所需的列
df_final = df[['CustomerID', 'InvoiceDate', 'ItemQuantities', 'TotalPrice', 'Cancelled']]

# 合并相同 CustomerID 和 InvoiceDate 的订单
df_final = df_final.groupby(['CustomerID', 'InvoiceDate']).agg({
'ItemQuantities': 'sum',
'TotalPrice': 'sum',
'Cancelled': 'any'
}).reset_index()

# 获取订单月份
df_final['InvoiceMonth'] = df_final['InvoiceDate'].values.astype('datetime64[M]')

display(df_final)

我们发现,有些订单其实是被取消的,一切从简,我使用一种逻辑对这些数据进行剔除:如果一张 Cancelled = True 的订单,其 ItemQuantities 和 TotalPrice >= (之前同一 CustomerID 所购买的其中一个订单),则扣除掉该订单的 ItemQuantities 和 TotalPrice,并销毁该 Cancelled 订单。如果找不到,则直接消除 Cancelled 订单

# 去掉被删除的订单
df_final = df_final[df_final['Cancelled'] == False]

对于 Matplotlib 绘制图片中文显示问题

英文 Matplotlib 并没有适配中文字符显示,所以我们需要修改字体,我们可以通过 pylab 包中的属性进行修改:

from pylab import mpl

# 设置显示中文字体
mpl.rcParams["font.sans-serif"] = ["SimHei"]
# 设置正常显示符号
mpl.rcParams["axes.unicode_minus"] = False

在进行数据处理的过程中,由于该电商公司主要经营批发价格,出货量大,买家群体庞大,所以所呈现出来的数据并没有那么容易进行分析。我们需要对数据中的一些值进行 query 筛选掉个别数据,才能对其进行分析。

衍生分析

通过对原数据集进行统计学分析,我还可以获取以下信息:

  • 描述性统计信息: 了解每个变量的基本统计指标,如平均值、中位数、最小值、最大值等,以便了解数据的整体特征。
  • 年龄分布: 分析年龄变量,了解顾客年龄的分布情况,例如平均年龄、最年轻和最年长的顾客。
  • 性别比例: 统计性别变量,计算男女顾客的比例,以便了解你的目标用户群体的性别分布。
  • 收入分析: 对 Revenue_Total 进行分析,包括平均收入、总收入等,以了解顾客的整体购买能力。
  • 购买行为: 分析 N_Purchases ,了解平均购买次数、最大购买次数等,以便了解顾客的购买行为。
  • 购买日期分析: 根据 Purchase_DATE ,可以分析销售在不同日期的分布,可能有季节性或周期性的趋势。
  • 购买价值: 分析 Purchase_VALUE ,了解平均购买价值、最大购买价值等,以便了解不同交易的价值。
  • 支付方式偏好: 对 Pay_Method 进行统计,了解顾客的支付方式偏好。
  • 浏览器使用情况: 分析 Browser 变量,了解顾客使用的主要浏览器。
  • 是否订阅新闻和使用优惠券的情况: 分析 NewsletterVoucher 变量,了解顾客是否订阅新闻和是否使用优惠券。

另外,通过Pyplot,我们还可以绘制多种图形来对数据集进行分析。以下是一些可能的图形选项:

  • 直方图 (Histogram): 年龄分布、总消费金额分布、订单数量分布等。
  • 散点图 (Scatter Plot): 年龄与总消费金额的关系、订单数量与购买金额的关系等。
  • 折线图 (Line Plot): 时间趋势,例如总消费金额随时间的变化。
  • 条形图 (Bar Chart): 性别分布、付款方式分布、浏览器分布等。
  • 箱线图 (Box Plot): 年龄分布的五数概括、总消费金额的五数概括等。
  • 饼图 (Pie Chart): 性别比例、是否使用优惠券的比例等。
  • 热力图 (Heatmap): 可以展示各变量之间的相关性。
  • 多子图组合 (Subplots): 可以在同一图中比较不同变量的分布或趋势。
  • 散点矩阵 (Scatter Matrix): 用于观察多个变量之间的关系。
  • 3D图 (3D Plot): 适用于三维数据的可视化,例如年龄、总消费金额和订单数量的关系。