电商数据分析

作者: 愤怒的果壳 | 来源:发表于2019-08-19 13:42 被阅读11次
    本次分析选用kaggle网站的巴西电商数据,时间跨度从2016年9月-2018年9月,数据集中对客户id进行了处理。

    kaggle

    分析目标:

    1.探索该电商运营情况
    2.客户分类,探索不同客户群的营销策略

    分析思路
    一是探索电商运营情况,主要探索其订单数和销售额的增长情况,客单价情况,以及各区域销售额对比情况,各区域的商品运输时间等指标;
    二是构建RFM模型,应用K-Means聚类方法对客户群进行分类,探索不同客户群的营销策略。

    评估并清洗数据:

    先导入分析中将要用到的python包
    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns
    from sklearn.cluster import KMeans
    from scipy.spatial.distance import cdist
    from mpl_toolkits.mplot3d.axes3d import Axes3D
    
    导入数据集
    customers = pd.read_csv('olist_customers_dataset.csv')
    orders = pd.read_csv('olist_orders_dataset.csv')
    order_items = pd.read_csv('olist_order_items_dataset.csv')
    order_payments = pd.read_csv('olist_order_payments_dataset.csv')
    products = pd.read_csv('olist_products_dataset.csv')
    products_name_trans = pd.read_csv('product_category_name_translation.csv')
    
    数据说明:

    因为原数据集结构比较复杂,产品数据、客户数据、支付数据都通过相应的键值与订单数据连接,本文着重分析经营情况和客户分类,对数据进行了一定取舍,数据清洗的冗杂过程不再赘述。
    经过数据清理之后,汇总成3个数据集:

    • df_orders 订单数据集
    • df_items 产品条目数据集
    • df_payments 支付数据集

    数据分析可视化

    # 备份
    df_o = df_orders.copy()
    df_i = df_items.copy()
    df_p = order_payments.copy()
    # 观察两年来的订单数量情况
    fig,ax = plt.subplots(figsize=(15,6))
    # 按月汇总
    ax.hist(df_o['order_purchase_timestamp'],bins = 30);
    
    月订单数分布图
    output_49_0.png

    可以看到:订单数从刚开始两个月的试探期进入到17年的比较快速的增长期,尤其是12月甚至直接翻倍,猜想可能是年终大促。后有所回落,18年开始增长趋势放缓,但较17年还是获得了较大增长。

    # 观察两年来的销售额情况
    # 按月聚合销售额
    f,ax = plt.subplots(figsize=(15,6))
    ax = df_o.groupby(pd.Grouper(key='order_purchase_timestamp',freq='M'))['sales_volume'].sum().plot()
    ax.set_title('月销售额走势图',fontsize=20);
    
    output_51_0.png

    观察到月销售额也呈现出和订单数量较为相近的走势,有意思的是订单数几乎翻倍的12月,销售额增长幅度并没有那么大,猜想促销活动进行了比较大幅度的降价,紧接着的18年销售额也处在一个比较高的水平,8月9月有小幅下降。

    #客单价
    #按月统计
    f,ax = plt.subplots(figsize=(12,5))
    df_kdj = pd.DataFrame()
    df_kdj['sales'] = df_o.groupby(pd.Grouper(key='order_purchase_timestamp',freq='M'))['sales_volume'].sum()
    df_kdj['counts'] = df_o.groupby(pd.Grouper(key='order_purchase_timestamp',freq='M'))['customer_unique_id'].nunique()
    df_kdj['kdj'] = df_kdj.sales/df_kdj.counts
    ax = sns.lineplot(x=df_kdj.index,y='kdj',data=df_kdj)
    
    客单价走势图
    output_53_0.png

    除了16年底没有营业的特殊情况外,其他月份客单价均保持在160上下,没有明显的增长,猜测客户购买频率较低,购买商品品类比较单一,对网站的认可度还不够高。

    # 观察各州销售情况
    # 各州的销售额情况
    fig,ax = plt.subplots(figsize = (15,6))
    ax = df_o['sales_volume'].groupby(df_o['customer_state']).sum().sort_values(ascending=False).plot(kind='bar')
    plt.xticks(rotation=0)
    
    各州销售额排序
    output_55_0.png

    SP圣保罗州占绝对领先位置,其次是RJ,MG,RS,PR等州,销售额分布集中在前几个州,尤其是SP,市场分布极不均匀,可能和经济发展情况有较大关系

    f,ax = plt.subplots(figsize=(15,6))
    df_ot = df_o[['order_purchase_timestamp','customer_state','sales_volume']]
    df_ot = df_ot.set_index('order_purchase_timestamp')
    g = df_ot.groupby('customer_state')['sales_volume']
    df_g = g.resample('M').sum().sort_values(ascending=False)
    df_g = df_g.reset_index()
    ax = sns.lineplot(x = 'order_purchase_timestamp',y = 'sales_volume',data = df_g,hue = 'customer_state')
    ax.set_title('各州月销售额走势图',fontsize=20);
    
    output_57_0.png

    各州分开进行对比,可以发现除SP保持了较好增长趋势外,其他各州在17年大促之后都在缓慢回落,可能在SP投入的销售资源更多,客户认可度也更高。

    # 查看各州平均运货时间对比
    fig,ax = plt.subplots(figsize = (15,5))
    df_o['deliver_time'].groupby(df_o['customer_state']).mean().sort_values().plot(kind='bar')
    ax.set_title('各州平均送货时间')
    plt.xticks(rotation=0);
    
    output_59_0.png

    对比各州的平均送货时间,能够在10天以内完成送货的只有SP,15天以内的也仅有PR,MG,DF,SC,RJ,RS,线上购物过程中到货时间极大影响购物体验,也说明在仓储物流等资源配置和硬件条件上各州还存在较大差距。

    # 统计销售额最高的产品种类
    f,ax = plt.subplots(figsize=(15,5))
    ax = df_i['price'].groupby(df_i['product_category']).sum().sort_values(ascending=False).head(15).plot(kind='bar')
    plt.xticks(rotation=45);
    
    销售额产品分类Top15
    output_68_0.png

    累计销售额最高的分别是health_beauty健康美容,watches_gifts首标礼品,bed_bath_table浴盆,sports_lersure运动衫,computers_accessories电脑配件等等。反映了一定的顾客偏好,同时注意到一些热门的线上产品如3C类,零食等并未获得较高排名,还有潜力可挖。

    # 查看付款方式订单数占比 和 金额占比
    f,(ax1,ax2) = plt.subplots(nrows = 1,ncols = 2,figsize=(15,6))
    df_p['payment_type'].value_counts().sort_values(ascending=False).plot(kind='bar',ax=ax1)
    df_p['payment_value'].groupby(df_p['payment_type']).sum().sort_values(ascending=False).plot(kind='bar',ax=ax2)
    ax1.set_title('付款方式订单数对比')
    ax2.set_title('付款方式金额数对比')
    ax1.set_xticklabels(ax1.get_xticklabels(), rotation=0)
    ax2.set_xticklabels(ax2.get_xticklabels(), rotation=0);
    
    output_77_0.png

    绝大多数订单和金额都采用信用卡支付,排名第二的boleto是一种巴西银联发行的票券,其他方式占比不高

    客户分类

    建立RFM指标模型,使用K-means聚类算法进行客户分类。选择2017年9月-2018年9月的数据集进行操作。

    # 建立指标数据df_rfm
    df_rfm = df_orders.drop(columns=['customer_id', 'order_status','order_approved_at', 'order_delivered_carrier_date',
           'order_delivered_customer_date', 'order_estimated_delivery_date','customer_zip_code_prefix', 'customer_city',
           'customer_state', 'geolocation_lat', 'geolocation_lng',
           'geolocation_city', 'geolocation_state','order_id' ])
    # 删除空值数据
    df_rfm = df_rfm.dropna()
    # 合并商品价格和运费
    df_rfm['order_value'] = df_rfm['price'] + df_rfm['freight_value']
    # 删除单价和运费列
    df_rfm = df_rfm.drop(columns = ['price','freight_value'])
    # 对时间数据进行格式转换
    df_rfm.order_purchase_timestamp = pd.to_datetime(df_rfm.order_purchase_timestamp)
    # 按照时间由近及远排序
    df_rfm = df_rfm.sort_values(by='order_purchase_timestamp',ascending=False)
    # 选择购买时间在一年内的数据,即20170904——20180903
    rfm_year = df_rfm[df_rfm['order_purchase_timestamp'] > '2017-09-04 00:00:00'].copy()
    # 重置索引
    rfm_year = rfm_year.reset_index(drop=True)
    # 定义数据框rfm_model
    rfm_model = pd.DataFrame()
    # 筛选最近购买时间 recency
    rfm_model['recency'] = rfm_year.order_purchase_timestamp.groupby(rfm_year['customer_unique_id']).max()
    # 统计消费次数 frequency
    rfm_model['frequency'] = rfm_year.order_value.groupby(rfm_year['customer_unique_id']).count()
    # 计算购买额 monetary
    rfm_model['monetary'] = rfm_year.order_value.groupby(rfm_year['customer_unique_id']).sum()
    # 添加一列快捷id,方便显示
    rfm_model['rapid_id'] = np.arange(100001,173253)
    # 重置索引
    rfm_model = rfm_model.reset_index(drop = False)
    # 建立一个索引表,用来对应rapid_id和customer_unique_id
    id_index = rfm_model[['customer_unique_id','rapid_id']].copy()
    # 删除原customer_unique_id
    rfm_model = rfm_model.drop(columns='customer_unique_id')
    # 修改时间按日计数
    rfm_model.recency = rfm_model.recency.dt.round('D')
    # 以2018-09-05来计算时间间隔
    rfm_model.recency = pd.to_datetime('2018-09-05')-rfm_model['recency']
    # 修改格式显示按天计算的整数
    rfm_model.recency = rfm_model.recency.dt.round('D').astype('str').apply(lambda x:x.split(' ')[0]).astype(int)
    # 使用rapid做索引
    data = rfm_model.set_index('rapid_id')
    # 3d呈现数据的三个特征情况
    fig = plt.figure(figsize=(12,8))
    ax = fig.add_subplot(111, projection='3d')
    ax.set_xlabel('Recency')
    ax.set_ylabel('Frequency')
    ax.set_zlabel('Monetary')
    ax.scatter(data['recency'],data['frequency'],data['monetary'],s=30);
    
    3D呈现RFM指标空间客户的分布情况
    output_102_0.png

    明显看出,大部分客户集中在Frequency坐标的0轴附近,高频客户零星散布,购买值也几乎都在2000以内。

    手肘图判断K-means聚类的k值

    # 标准化
    data_zs = 1.0*(data-data.mean())/data.std()
    # 将特征值转化成array格式
    X = np.array(data_zs)
    # 使用手肘图判断k值
    # wcss即within cluster sums of squares 分群的面积
    wcss = []
    # K 经过几次迭代之后选1到15
    K = range(1, 15)
    for k in K:
        kmeans = KMeans(n_clusters=k, init='k-means++', random_state=0)
        kmeans.fit(X)
        wcss.append(kmeans.inertia_)
        # 这里使用wcss也就是分群的面积来判断,每一个k值对应分群的面积,面积越小表明分群越收敛,计算平均距离也可
        # distortions=[]
        # distortions.append(sum(np.min(cdist(X, kmeanModel.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0])
    # 画手肘图
    plt.plot(K, wcss, 'bx-')
    plt.xlabel('k')
    plt.ylabel('WCSS')
    plt.title('Elbow graph')
    plt.show()
    
    output_104_0.png
    手肘图的拐点即肘的位置被认为是最恰当的分类个数,在这里尝试了两种计算方法,一种是上图所示采用计算wcss即分群面积,他的原理是分类越收敛,面积就越小,还有一种是计算平均距离,即数据点距离类中心点的平均距离越小,分类越收敛,个人感觉距离计算敏感度更高,可能分辨率更高。本次分类选用面积法,图上肘部节点4-6段,考虑到F指标区分度太小,选择k=4分类。

    k=4 设置模型

    # 设置模型
    model_4 = KMeans(n_clusters=4, init='k-means++', random_state=0)
    # 进行聚类
    clusters_4 = model_4.fit_predict(X)
    

    图示分类结果

    # 设置索引
    data_4 = rfm_model.set_index('rapid_id')
    # 添加分类标签
    data_4['clusters'] = clusters_4
    # 图示分类结果
    fig = plt.figure(figsize=(12,8))
    dx = fig.add_subplot(111, projection='3d')
    colors = ['blue', 'yellow', 'green', 'red']
    
    for i in range(0,4):
        dx.scatter(data_4[data_4.clusters == i].recency, 
                   data_4[data_4.clusters == i].frequency, 
                   data_4[data_4.clusters == i].monetary, 
                   c = colors[i], 
                   label = 'Cluster ' + str(i), 
                   s=30)
    
    dx.set_title('Clusters of clients')
    dx.set_xlabel('Recency')
    dx.set_ylabel('Frequency')
    dx.set_zlabel('Monetary')
    dx.legend()
    
    output_108_1.png
    可以看出:红色3群购买金额较高,黄色1群购买频率较多,蓝色0群和绿色1群购买金额和频率较低,购买时间距离不同。
    各群人数对比
    # 各分群人数情况
    f,ax = plt.subplots(figsize=(10,5))
    ax = data_4['clusters'].value_counts().plot(kind='bar')
    ax.set_title('各分群数量分布',fontsize=20);
    
    clusters_num.png
    data_4['clusters'].value_counts()
    
        2    34947
        0    34604
        3     1870
        1     1831
    

    0群和2群人数最多,分别接近35000人,而3群和1群不足2000人,即高购买值和频次的客户非常少

    详细查看每个指标范围:箱线图
    # 箱线图
    # 使用默认灰色背景
    sns.set()
    fig,((ax1,ax2,ax3),) = plt.subplots(nrows = 1,ncols = 3,squeeze = False,figsize = (18,6))
    # ax1,ax2,ax3 = axes.flatten()
    sns.boxplot(x= 'clusters',y = 'recency',data = data_4, ax = ax1)
    sns.boxplot(x= 'clusters',y = 'frequency',data = data_4, ax = ax2)
    sns.boxplot(x= 'clusters',y = 'monetary',data = data_4, ax =ax3)
    ax3.set(ylim=(0,1500))
    
    output_109_1.png
    发现特征如下:
    • 0群购买时间:距离225-300天; 购买频率:1次; 购买金额:70-200
    • 1群购买时间:距离90-230天; 购买频率:2次; 购买金额:150-350
    • 2群购买时间:距离50-140天; 购买频率:1次; 购买金额:70-200
    • 3群购买时间:距离100-260天; 购买频率:1次; 购买金额:800-1350
    继续观察:核密度曲线
    # 核密度曲线绘制购买时间和金额
    fig,((ax1,ax2,ax3),) = plt.subplots(nrows=1,ncols = 3,figsize=(18,5),squeeze=False)
    for i in range(0,4):
        sns.kdeplot(data_4[data_4.clusters==i].recency,label = 'cluster'+str(i),ax=ax1)
        sns.kdeplot(data_4[data_4.clusters==i].monetary,label = 'cluster'+str(i),ax=ax2)
    ax2.set(xlim=(0,2500))
    # 0群和2群频率值全都为1,无法绘制kde曲线
    for i in [1,3]:
        sns.kdeplot(data_4[data_4.clusters==i].frequency,label = 'cluster'+str(i),ax=ax3)
    ax3.set(xlim=(0,4));
    
    output_111_0.png
    对照箱线图修正:
    • 购买时间:0群购买时间距离0-180天,2群购买时间距离180-365天,刚好一年对半分;1群和3群基本覆盖全年,比较接近。
    • 购买金额:0群和2群购买金额主要集中在200以内,少量突破500;1群购买金额主要150-350,个别接近1000;3群购买金额主要在700-1200,个别更高。
    • 购买频率:0群2群均为1次;3群大部分1次,少量2次;1群大部分购买2次,少量更高。
    综合客户分类情况:
    • 3群属于高价值客户,虽然大部分仅购买一次,但购买金额远高于其他用户,对平台有一定的信任度,购买时间距离近的客户需要重点维持,购买间隔过长的需要重点挽留;
    • 1群属于重要保持客户,均有回购记录,且消费价值较高,对平台较为认可,可重点挖掘购买潜力,维持购买频率;
    • 2群属于重点发展客户,购买时间较近,属于新客户,需要进一步跟进转化;
    • 0群属于一般挽留客户,购买时间较远,且购买金额较低,可尝试对其进行重新激活。

    综述:

    就数据反映的情况来说,该网站的客户流失率比较高,客户保持做的不好,推测可能发展战略不够平衡,过于注重拉新,而忽视了保留,导致购买频率普遍偏低。而平均送货时间过长也极大影响购买体验,这一定程度上反映了仓储保障能力,在前期如此多新客户进行尝试的情况,及早转换思路,提高留存,可能会取得更好的市场收益。

    相关文章

      网友评论

        本文标题:电商数据分析

        本文链接:https://www.haomeiwen.com/subject/tdhssctx.html