美文网首页Python时空大数据数据分析呆鸟的Python数据分析
案例分析三——UK Retailer 购物行为分析(RFM模型)

案例分析三——UK Retailer 购物行为分析(RFM模型)

作者: 粉红狐狸_dhf | 来源:发表于2020-06-14 09:34 被阅读0次

    1 项目背景

    (1)数据

    Kaggle数据源。英国零售商的实际交易数据,包含了2010年12月1日至2011年12月9日在英国注册的非实体网上零售发生的所有交易。公司主要销售独特的全天候礼品。该公司的许多客户都是批发商。本篇基于Python进行分析,还有一篇是基于SQL语言进行的分析

    (2)分析目的

    采用RFM模型,从用户、地区和时间等维度分析用户行为并提出优化建议。

    2 理解数据

    InvoiceNo --> 订单号码: 6位字符串
    StockCode --> 产品代码: 6位字符串
    Description --> 产品描述
    Quantity --> 产品数量:交易产品数量
    InvoiceDate --> 订单日期:订单发生的日期和时间
    UnitPrice --> 单价:浮点数值
    CustomerID --> 顾客ID:5位字符串
    Country --> 国家:客户所在地

    import pandas as pd
    import numpy as np
    import matplotlib.pyplot as plt
    import seaborn as sns
    import warnings
    warnings.filterwarnings('ignore')
    
    import plotly as py
    import plotly.graph_objs as go
    pyplot = py.offline.iplot
    py.offline.init_notebook_mode()
    
    df = pd.read_csv(r'E:\jupyter_lab\leetcode\data\UK retailer-kaggle\data.csv',encoding='ISO-8859-1',dtype={'CustomerID':str}) 
    df.head()
    
    360截图176106119511198.png
    df.info()
    
    360截图1872011583114132.png

    3 数据清洗

    (1) 空值 :空值是什么?没有影响的删掉,有影响的填充。
    (2) 去重操作(看情况分析)。
    (3) 数据格式:时间格式(日期表示)、字符格式、类别格式(编码问题)。
    (4) 异常值分析(describe:负数,极值等)。此处,负数代表退货。
    (5) 计算一些分析用到的统计变量。

    (1)空值
    df.apply(lambda x : sum(x.isnull())/len(x)) #缺失率
    df.isnull().sum() #缺失值个数
    
    (2)重复值、无用字段 和 空值填充
    df=df.drop_duplicates()
    df.drop(['Description'],axis=1,inplace=True) #按列操作,默认是删除行的
    df.CustomerID = df.CustomerID .fillna('U') #U表示customer_id缺失
    
    (3)数据格式转化
    df['date'] = [x.split(' ')[0] for x in df.InvoiceDate ] #月-日-年
    df['time'] = [x.split(' ')[1] for x in df.InvoiceDate ]
    df.drop(['InvoiceDate'],axis=1,inplace=True)
    
    df['year'] = [x.split('/')[2] for x in df.date]
    df['month'] = [x.split('/')[0] for x in df.date]
    df['day'] = [x.split('/')[1] for x in df.date]
    
    df['date'] = pd.to_datetime(df.date)
    
    df['year']=pd.to_numeric(df['year'])
    df['month']=pd.to_numeric(df['month'])
    df['day']=pd.to_numeric(df['day'])
    #是数字的一定变成数字,不然排序的时候不灵光
    
    (4)异常值分析
    df.describe() #数据探索,异常值分析
    
    360截图16720402111152114.png
    #禁用科学计数法
    pd.set_option('display.float_format',lambda x : '%.2f' % x)
    pd.options.display.float_format = '{:,.2f}'.format
    
    df2 = df[df['UnitPrice']<=0]
    df2.shape[0]/df.shape[0] #单价为负值的比例
    

    0.00468

    #分类统计方法一
    df2.UnitPrice.groupby(df2.UnitPrice).count()
    #分类统计方法二
    from collections import Counter
    Counter(df.UnitPrice)
    
    360截图1672033173103102.png
    (5)统计一些分析用到的变量
    df['amount'] = df.Quantity * df.UnitPrice #消费总金额
    

    4 数据分析

    该是数值的地方一定在数据处理的时候改成数值类型,不然在排序的时候打死你也不知道为什么不能排序

    (1)退货率=退货金额/销售金额

    df1 = df[df.Quantity<=0]
    
    sales_return = pd.pivot_table(df1,index=['year'],columns=['month'],values=['amount'],aggfunc=np.sum,fill_value=0)
    
    df2 = df[(df.Quantity>0) & (df.UnitPrice>0)]
    sales = pd.pivot_table(df2,index=['year'],columns=['month'],values=['amount'],aggfunc=np.sum,fill_value=0.001)
    
    return_goods_ratio=np.abs(sales_return/sales)
    
    return_goods_ratio.sort_index(level=1,axis=1,inplace=True) 
    
    360截图18290329726667.png

    这涉及多重索引,下面是数据提取的一些方法。

    return_goods_ratio.iloc[0,:].index.levels[1]
    
    return_goods_ratio.iloc[1,:]
    
    按照month 排序,然后把amount绘制出来
    data_2011 = pd.DataFrame({'return_ratio':return_goods_ratio.iloc[1,:]})
    data_2011 = data_2011.iloc[:,-1].reset_index().iloc[:,1:]
    
    %matplotlib inline
    plt.plot(data_2011.month,data_2011.return_ratio)
    
    360截图18720122103705.png
    return_goods_ratio.iloc[1,:].mean()
    #2011年退货的平均数 0.092
    

    (2)RFM模型

    R_value = df2.groupby('CustomerID').date.max()
    
    R_value = (df2.date.max()-R_value).dt.days
    #每位客户最近一次购买时间到参考日期的时间间隔(此值越小越好)
    
    F_value = df2.groupby('CustomerID').InvoiceNo.nunique() #唯一值的个数
    #每位客户的购买频率(此值越大越好
    
    M_value = df2.groupby('CustomerID').amount.sum() 
    #每位用户的消费总金额(此值越大越好)
    
    (2.1)探索RFM数据
    R_value.describe()
    
    360截图187201248212296.png

    可视化一:

    sns.distplot(R_value,bins=30)
    
    360截图17650105739789.png

    可视化二:

    plt.hist(R_value,bins=30)
    plt.show()
    
    360截图168004118911176.png

    同理于消费频次与购买金额的分析。在此略过。

    (2.2) RFM分级

    指定分割段

    R_bins = [0,30,90,180,360,720]
    

    通过分位数指定分割段

    F_value.quantile([0.1,0.2,0.3,0.4,0.5,0.9,1])
    F_bins = [0,2,10,100,1000,2000]
    
    M_value.quantile([0.1,0.2,0.3,0.4,0.5,0.9,1])
    M_bins = [100,200,500,5000,100000,2000000]
    

    依据分割段分割

    R = pd.cut(R_value,R_bins,labels=[5,4,3,2,1],right=False)
    #不包含上线  越小越好
    F = pd.cut(F_value,F_bins,labels=[1,2,3,4,5],right=False)
    #不包含上线
    M = pd.cut(M_value,M_bins,labels=[1,2,3,4,5],right=False)
    #不包含上线
    
    rfm = pd.concat([R,F,M],axis=1)
    #按列操作,扩展
    rfm.rename(columns={'date':'R_score','InvoiceNo':'F_score','amount':'M_score'},inplace=True)
    rfm.head()
    
    360截图17411027432772.png

    看一下rfm的数据类型

    rfm.info()
    
    360截图16720401180641.png
    (2.3) 数据类型的转化,便于计算
    for i in rfm.columns:
        rfm[i] = rfm[i].astype(float)
    

    依据平均值划分客户类型

    rfm['R'] = np.where(rfm['R_score']>rfm['R_score'].mean(),'高','低')
    rfm['F'] = np.where(rfm['F_score']>rfm['F_score'].mean(),'高','低')
    rfm['M'] = np.where(rfm['M_score']>rfm['M_score'].mean(),'高','低')
    
    rfm['values'] = rfm.R.str[:]+rfm.F.str[:]+rfm.M.str[:]
    rfm['values']=rfm['values'].str.strip()
    

    定义客户类型的函数

    def class_func(x):
        if x == '高高高':
            return '重要价值客户'
        elif x == '高低高':
            return '重要发展客户'
        elif x == '低高高':
            return '重要保持客户'
        elif x == '低低高':
            return '重要挽留客户'
        
        elif x == '高高低':
            return '一般价值客户'
        elif x == '高低低':
            return '一般发展客户'
        elif x == '低高低':
            return '一般保持客户'
        else:
            return '一般挽留客户'
    

    将客户类型映射到函数上,得到客户等级

    rfm['用户等级'] = rfm['values'].apply(class_func)
    rfm.head()
    
    360截图16780702407079.png

    存一下数据

    rfm.to_csv(r'E:\jupyter_lab\leetcode\data\UK retailer-kaggle\rfm.csv')
    
    (2.4) RFM可视化

    条形图

    trace_base = [go.Bar(x=rfm['用户等级'].value_counts().index,
                        y=rfm['用户等级'].value_counts().values
                       , marker=dict(color='orange'),opacity=0.5
                        )]
    layout = go.Layout(title='用户等级分布',xaxis=dict(title='用户等级'))
    
    figure_base = go.Figure(data=trace_base,layout=layout)
    
    pyplot(figure_base, auto_open=True)
    
    newplot.png

    饼图

    trace_pie = [go.Pie(labels=rfm['用户等级'].value_counts().index,
                        values=rfm['用户等级'].value_counts().values
                       , textfont=dict(color='orange',size=12))]
    layout = go.Layout(title='用户等级比例',xaxis=dict(title='用户等级'))
    
    figure_base = go.Figure(data=trace_pie,layout=layout)
    
    pyplot(figure_base, auto_open=True)
    
    pie.png

    5 结论与对策

    (1)1月与12月的退货率比较高,我们要对比往年同时间段的退货率,如果与往年不同,此时我们要继续分析退货率增加的原因。
    (2)由RFM模型可知,客户类型中占比最多的是“重要价值客户”(最近购买了,购买频率还挺高,购买金额也挺大)此时,应向该部分人群继续推送公司主营业务,通过宣传推广等手段,让产品信息送达客户手中。其次,占比较多的是“一般挽留客户”(很长时间没买了,购买的频率比较低,购买的金额也比较少),公司应该面向该部分人群推出促销活动,拉动消费的积极性。

    相关文章

      网友评论

        本文标题:案例分析三——UK Retailer 购物行为分析(RFM模型)

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