电商零售交易数据挖掘价值用户

电商零售交易数据挖掘价值用户 

 

目录

1.提出问题

1.1.电子零售商面对的挑战和问题

1.2.本次分析的业务问题及适用指标¶

2.理解数据

2.1. 数据来源

2.2.本次分析选取的数据样本

2.3.字段含义

3.数据清洗

3.1.准备工作

3.2.选择子集并重命名列名

3.3.删除重复值

3.4.缺失值处理

3.5.一致化处理

3.6.异常值处理¶

4.运营指标统计分析

4.1.月追踪:月销售量、月销售额、月均销售额

4.2.周追踪:周销售量、周销售额、周均销售额

4.3.效率指标:客单价、件单价、连带率、退货金额¶

5.构建RFM模型

5.1.RFM指标计算¶

5.2.利用RFM模型挖掘价值用户¶

5.3.利用K-Means算法挖掘价值用户

6.价值用户挖掘结果

6.1.用户画像

6.2.价值用户对销售额的贡献

6.3.总结


1.提出问题

1.1.电子零售商面对的挑战和问题

近年来全球网民渗透率逐步提高,欧美地区网民渗透率远高于亚非地区。得益于互联网及全球网民规模的不断发展,全球零售总体规模保持增长,2019年全球零售总额为25万亿美元,其中网络零售额为3.5万亿美元,占比14%。

在2020年发布的《世界电子商务报告》中,全球有7个国家网购用户数量过亿,从市场规模来看,中国是全球最大、最活跃的互联网互用市场,英国是欧洲最大的电子商务市场,互联网普及达93%,而拉丁美洲是最受欢迎的电子商务新兴市场。全球使用移动端进行消费的用户占12%,中国使用移动段进行网购的消费者占88%,全球排名第一。

传统零售商争相往电子商务转型,因为有互联网的依托,网络消费者的消费行为变得有迹可循,产生了大量消费数据,如何利用这些数据挖掘出有用的商业信息是所有电子零售商都需要面对的挑战。

电子零售商面对的问题可能有:

  • (1)哪些产品最受欢迎,也即被访问的次数最多,购买的次数最多?

  • (2)哪些用户是最有价值的用户?也即在特定的时间范围内消费总额最高,这些高价值用户有什么样的用户特征?

  • (3)哪些用户是最忠诚的用户?也即复购率最高用户,如何提高这些用户的消费体验,增加消费额度?

  • (4)用户的消费习惯是什么?哪些产品是用户们喜欢一起购买的?或者有特定的购买时间顺序?

  • (5)促销对于哪些用户最有效?也即用户反应最活跃?促销策略能够考虑这些因素?

1.2.本次分析的业务问题及适用指标

本次分析要解决的核心业务问题是:从大量的电子零售交易数据中分析并找到价值用户,针对价值用户提供以消费者为中心的智能商业模式。

适用的指标有:

本次电子零售数据分析主要分为了两大方面:

  • (1)了解电子零售商的整体运营情况,通过分析计算运营的各项指标来了解目前经营的效率和经营趋势。

  • (2)使用RFM模型对用户进行分级,找出价值用户,从而进行经营策略管理,比如进一步挖掘最高价值用户的消费模式,提出个性化的销售服务提高价值用户体验,从而提高经营效率和利润。

2.理解数据

2.1. 数据来源

kaggle数据平台数据:https://link.zhihu.com/?target=https%3A//www.kaggle.com/jihyeseo/online-retail-data-set-from-uci-ml-repo

数据集来自一个在英国注册的在线电子零售公司,在2010年12月1日到2011年12月9日期间发生的网络交易数据。

2.2.本次分析选取的数据样本

本次分析选取一整年的交易数据,即从2010年12月1日到2011年12月1日期间的数据。原数据集储存在.csv格式的文件中,总共有541909条数据,8个字段。整个文件导入Jupyter lab,在清洗过程中才进行节选样本。

2.3.字段含义

字段含义:

  • InvoiceNo:发票编号。为每笔订单唯一分配的6位整数。若以字母'C'开头,则表示该订单被取消。
  • StockCode:产品代码。为每个产品唯一分配的编码。
  • Description:产品描述。
  • Quantity:数量。每笔订单中各产品分别的数量。
  • InvoiceDate:发票日期和时间。每笔订单发生的日期和时间。
  • UnitPrice:单价。单位产品价格,单位为英镑。
  • CustomerID:客户编号。为每个客户唯一分配的5位整数。
  • Country:国家。客户所在国家/地区的名称

3.数据清洗

3.1.准备工作

# import library
import pandas as pd
import numpy as np
import datetime as dt

# for visualization
import matplotlib.pyplot as plt
import seaborn as sns

# for machine learning algorithm
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans

import  warnings
warnings.filterwarnings("ignore")

将数据导入Jupyter lab,打印前几行看看数据导入情况。

#load excel data to Jupyter notebook,data type prescribed to be string, change later
salesOR = pd.read_csv('D:/data/E-Commerce_Data/data.csv' )
#print the first 5th row to check data input
salesOR.head()

​​​​​​​了解数据集的基本信息。

3.2.选择子集并重命名列名

本次分析选择原数据集的八个字段用于分析电商业务问题,每个字段都包含有效信息。 原数据集的八个字段命名清晰,保留原来列名,此处没有重新命名。

3.3.删除重复值

如果八个列值相同则删除重复数据只保留一条,一共删除了5268条重复数据。

# delect data if data has the same input for ALL column in subset
salesOR_NoDup=salesOR.drop_duplicates(subset=['InvoiceNo','StockCode','Description','Quantity','InvoiceDate','UnitPrice','CustomerID','Country'])
dup=salesOR.shape[0]-salesOR_NoDup.shape[0]
print('duplicates =',dup)
duplicates = 5268

3.4.缺失值处理

查看缺失数据情况

tab_info=pd.DataFrame(salesOR.dtypes).T.rename(index={0:'特征类型'})
tab_info=tab_info.append(pd.DataFrame(salesOR.isnull().sum()).T.rename(index={0:'缺失值数量'}))
tab_info=tab_info.append(pd.DataFrame(salesOR.isnull().sum()/salesOR.shape[0]).T.
                         rename(index={0:'缺失值占比'}))
display(tab_info)

在查看数据中空值的数量时,我们注意到近25%的条目未分配给特定客户。在现有的数据下,不可能为用户估算出数值,因此这些条目对目前的工作没有用处。所以我从数据框中删除它们,一共删除了135037条数据。

#delect data where either InvoiceNo or CustomerID is missing
salesOR_NoDupNA=salesOR_NoDup.dropna(subset=['InvoiceNo','CustomerID'],how='any')
missing=salesOR_NoDup.shape[0]-salesOR_NoDupNA.shape[0]
print('missings =',missing)
missings = 135037

3.5.一致化处理

(1)字符串转为数字类型(浮点型)

# change string data type to number type
salesOR_NoDupNA['Quantity']=salesOR_NoDupNA['Quantity'].astype('float')
salesOR_NoDupNA['UnitPrice']=salesOR_NoDupNA['UnitPrice'].astype('float')
salesOR_NoDupNA['CustomerID']=salesOR_NoDupNA['CustomerID'].astype('object')
print('Data type after changing:\n',salesOR_NoDupNA.dtypes)

(2)字符串转换为日期数据类型

将InvoiceDate数据转换成日期的数据类型,如果不符合日期的格式,转换后的值为空值

#errors='coerce'如果原始数据不符合日期的格式,转换后的值为空值NaT
salesOR_NoDupNA['InvoiceDate']=pd.to_datetime(salesOR_NoDupNA['InvoiceDate'], errors='coerce')
#分离出年、月、日、星期几方便之后分析
#这样得到的数据依旧是一个整形数据
salesOR_NoDupNA['Year'] = salesOR_NoDupNA['InvoiceDate'].dt.year
salesOR_NoDupNA['Month'] = salesOR_NoDupNA['InvoiceDate'].dt.month 
salesOR_NoDupNA['Date'] = salesOR_NoDupNA['InvoiceDate'].dt.date
salesOR_NoDupNA['weekday'] = salesOR_NoDupNA['InvoiceDate'].dt.weekday
salesOR_NoDupNA.head()

数据转换过程中不符合日期格式的会转换为空值,此处再进行一次删除缺失值处理。

'''转换日期过程中不符合日期格式的数值会被转换为空值,
这里删除InvoiceDate,InvoiceTime,CustomerID,InvoiceNo中为空的行'''
salesOR_NoDupNA=salesOR_NoDupNA.dropna(subset=['InvoiceNo','CustomerID','InvoiceDate'],how='any')

3.6.异常值处理

利用描述性指标查看是否有异常值。

#Description index 描述指标,查看异常值
salesOR_NoDupNA[['Quantity','UnitPrice']].describe()

描述指标中购买产品的数量最小值为-8095,单品单价为0,这两个不符合实际情况确认为异常值,删除异常值可以通过条件判断筛选出合适的数据。

querySer=salesOR_NoDupNA.loc[:,'Quantity']>0
salesOR_NoDupNA=salesOR_NoDupNA.loc[querySer,:]
querySer1=salesOR_NoDupNA.loc[:,'UnitPrice']>0
salesOR_NoDupNA=salesOR_NoDupNA.loc[querySer1,:]
print('after delete outlier:',salesOR_NoDupNA.shape)
after delete outlier: (392692, 12)

经过两次条件判断之后数据集大小为(392692,10),为了检查处理后的结果,再次检查描述指标:

原数据集的时期是2010-12-1到2011-12-09,2011年12月数据不满一个月,为了方便分析和讨论本次分析选择数据时间为:2010-12-01到2011-11-30,12个月。

#delete data after 2011-11-30
querySer2=salesOR_NoDupNA.loc[:,'InvoiceDate']<'2011-12-01'
salesOR_NoDupNA=salesOR_NoDupNA.loc[querySer2,:]
print('delect data after 2011-11-30:',salesOR_NoDupNA.shape)
delect data after 2011-11-30: (375666, 12)

4.运营指标统计分析

运营指标,可以帮助电商了解运营的情况,找出消费者习惯和优化运营结构和效率

4.1.月追踪:月销售量、月销售额、月均销售额

(1)月销售量 monthly transaction

#Monthly transaction = total unique transaction number
'''the same InvoiceNo contain different products,
we need to count unique InvoiceNo'''
transUni=salesOR_NoDupNA.drop_duplicates(subset=['InvoiceNo'])
monthly_trans=transUni.groupby(['Year','Month'])['InvoiceNo'].count()
print('monthly transaction :\n',monthly_trans)

fig,ax = plt.subplots(figsize=(8,3))
monthly_trans.plot(kind='bar')
plt.xlabel('Month')
plt.ylabel('Number of Transaction')
plt.title('Monthly Transaction')
plt.show()
fig.savefig('monthlyTranc.png')

计算结果显示2011年9月、10月、11月的销售单数稳步增长,2011年11月达到最高值2657单,怀疑平台年末促销或者换季用户大量购买冬季产品导致,可以通过查询销售额占比最高的产品确认。

(2)月销售额 monthly sales

#Add a new column Amount = Quantity * UnitPrice
salesOR_NoDupNA['Amount']=salesOR_NoDupNA.Quantity*salesOR_NoDupNA.UnitPrice
monthly_sales=salesOR_NoDupNA.groupby(['Year','Month'])['Amount'].sum()
print('monthly sales:\n',monthly_sales)

fig,ax = plt.subplots(figsize=(8,4))
monthly_sales.plot(kind='bar')
plt.xlabel('Month')
plt.ylabel('Sales')
plt.title('Monthly Sales')
plt.show()
fig.savefig('monthlySales.png',poi=300)

在销售额方面,2011年9月、10月、11月的销售额明显高于其他月份,虽然11月的总销售单数比10月要高出近38%但是11月的总销售额却只比10月高出11.6%,初步评价2011年10月的销售情况最佳,可以重点看看10月份的销售活动。

(3)月均销售额 average of monthly sales

monthSales=salesOR_NoDupNA.groupby(['Year','Month'])['Amount'].sum()
avg_monthSales=round(monthSales.sum()/12,2)
print('Average of monthly sales:',avg_monthSales)
Average of monthly sales: 697501.54

计算得出月均销售额为697501.54英镑,2011年9、10、11月远超平均值。

4.2.周追踪:周销售量、周销售额、周均销售额

(1)周销售量 weekly transactions

transUni=salesOR_NoDupNA.drop_duplicates(subset=['InvoiceNo'])
weekly_trans=transUni.groupby(['weekday'])['InvoiceNo'].count()
print('weekly transaction:\n',weekly_trans)

发现竟然没有5,看看数据集里是不是不包含5的星期数。 真的没有5,查看原始数据以及对应的星期数,5代表星期六。

fig,ax = plt.subplots(figsize=(8,3))
x = ['Mon', 'Tue','Wed','Thur','Fri','Sun']
y = weekly_trans
plt.plot(x,y)
plt.xlabel('Week')
plt.ylabel('Weekly Transaction')
plt.show()
fig.savefig('weeklyTrans.png',poi=300)

此处计算的是在一年观察时间段内,每个星期天数的累计订单数。星期四的订单数是最多的,怀疑有公司(周末不上班)在该电商平台购买用品和礼品。这里要特别提醒上面的结果是一年里面每一个星期的累计单数,数据集没有星期六的销售订单,需要跟电商公司确认。

(2)周销售额 weekly sales

#Weekly sales
weeklySales=salesOR_NoDupNA.groupby(['weekday'])['Amount'].sum()
print('weekly sales:\n',weeklySales)

fig,ax = plt.subplots(figsize=(8,4))
x = ['Mon', 'Tue','Wed','Thur','Fri','Sun']
y = weeklySales
plt.plot(x,y)
plt.xlabel('Week')
plt.ylabel('Weekly Sales')
plt.show()
fig.savefig('weeklySales.png',poi=300)

跟销售量相吻合,累计周销售量在星期四达到峰值,临近周末回落,高度怀疑该电商平台出售的产品不是针对普通家庭消费者,因为周末是消费的低谷跟实际情况不符。

(3)周均销售额 average of weekly sales

#Average of weekly sales
avg_weeklySales=round(weeklySales.sum()/52,2)
print('Average of weekly sales:',avg_weeklySales)
Average of weekly sales: 160961.89

计算结果为160961.89欧元,这是每周平均销售额,给运营者提供一个参考,可以初步评价每一星期的销售情况,是高于还是低于平均值。

4.3.效率指标:客单价、件单价、连带率、退货金额

(1)客单价 sales per customer

#total sales from 2010-12-01 to 2011-11-30
total_Sales=salesOR_NoDupNA.Amount.sum()
total_customer=salesOR_NoDupNA.drop_duplicates(subset=['CustomerID']).shape[0]
#Sales per customer
sales_perCustomer=round(total_Sales/total_customer,2)
print('sales per customer=',sales_perCustomer)
sales per customer= 1947.87

客单价=总的销售额/总的客户数,计算结果客单价为1947.87欧元,也即一年里面每个消费者平均贡献了1947.87欧元。

(2)件单价 sales per item

#total number of products sold
total_product=salesOR_NoDupNA.Quantity.sum()
#Sales per item
sale_perItem=round(total_Sales/total_product,2)
print('sales per item=',sale_perItem)
sales per item= 1.72

件单价=销售总额/售出产品总数量,计算结果为每件产品的平均价格为1.72欧元。

(3)连带率

连带率=售出的产品总数/总的交易单数

#joint rate
total_transUni=transUni.shape[0]
joint_Rate=round(total_product/total_transUni,2)
print('Joint rate=',joint_Rate)
Joint rate= 274.04

计算结果连带率=274.04,在分析的一年时间段里,每一笔交易售出的平均产品总数为274件,这里怀疑有大量采购的用户。

(4)退货金额

在原数据集说明中,订单号如果以字母c开头表示该订单为取消订单,所以在这里想看看退货的情况。

#Select cancullation with InvoiceNo starts with 'c'
querySer3=salesOR_NoDupNA.loc[:,'InvoiceNo'].str.startswith('c')
querySer3.unique()
array([False])

结果显示:array([False]),该数据集中并没有包含取消的订单,所以本次分析没能够涉及这一块。

5.构建RFM模型

RFM模型是研究价值用户的经典方法之一,本次数据集数据信息完整,可以有效地利用RFM模型来找出价值用户。

第一步先计算出RFM模型的每一个指标,第二步则采用K-means clustering alrogithm算法将用户进行分组从而找出最具有价值的用户群。

5.1.RFM指标计算

(1)R - Recency

Recency在这里定义为用户最后一次购物距离现在有多少个月。

#Recency - How recently did the customer purchases?
#Last and First purchase date
Last_purchase=salesOR_NoDupNA.groupby(['CustomerID']).Date.max()
First_purchase=salesOR_NoDupNA.groupby(['CustomerID']).Date.min()
Last_purchase.head()

先计算出最后一次购买时间距离最后一天的天数,然后再计算月分数。

#Recency in days
Max_date=salesOR_NoDupNA.Date.max()+dt.timedelta(days=1)
Recency_days=Last_purchase.map(lambda x:(x-Max_date).days)
#Recency in months
Recency_months=Recency_days.map(lambda x:round((-1*x)/30,1))
Recency_months.head()

为了了解数据集的情况,可以查看一下描述统计指标。

#Description information
Recency_months.describe()

还有切片看看分布情况。

#Bin information
bins1=[0,1,2,3,4,5,6,7,8,9,10,11,12,13]
pd.cut(Recency_months,bins1).value_counts()

大概有37.7%的客户在一个月之内有购物行为,利用Python的matplotlib包画个图看看。

import matplotlib.pyplot as plt
pd.cut(Recency_months,bins1).value_counts().plot.bar(rot=20)

分布总体来说比较理想,可以利用customer-centric以客户为中心的商业理念来提高[1,2]以及[2,3]也即1~2个月,2~3个月之内有购物行为的用户。

(2)F- Frequency

Frequency在这里定义为购物频率,也即在分析的一年里面,用户总购买次数。

#Frequency - How often do they purchase?
Unique_purchase=salesOR_NoDupNA.drop_duplicates(subset=['InvoiceNo'])
Freq_purchase=Unique_purchase.groupby(['CustomerID']).InvoiceNo.count()
Freq_purchase.head()

描述统计指标:

#Description information
Freq_purchase.describe()

购买的频率差异很大,最小为1次,最大为200次,切片看数据分布情况。

#Bin information
bins2=[1,20,40,60,80,100,120,140,160,180,200]
pd.cut(Freq_purchase,bins2).value_counts()

大部分用户在一年的时间里购买次数在1~20次以内,比较符合实际情况。这里要注意有些离散的数值,比如一年里面消费100~120次的用户有1位用户,180~200次的用户有2位,后续的分析会针对这些离散值做特殊处理。

最后是利用matplotlib画出的柱状图。

pd.cut(Freq_purchase,bins2).value_counts().plot.bar(rot=20)

(3)M - Monetary

Monetary定义为用户在一年之内所花总金额

#Monetary - How much do they spend?
Money_purchase=salesOR_NoDupNA.groupby(['CustomerID']).Amount.sum()
Money_purchase.head()

描述统计指标:

#Description information
Money_purchase.describe()

每个用户的消费总金额差异很大,最小值位2.9欧元,最大值位268478欧元。

切片看数据分布:

#Bin information
bins3=[2.5,10,50,100,1000,10000,100000,200000,300000]
pd.cut(Money_purchase,bins3).value_counts()

最后是利用matplotlib画出的柱状图。

pd.cut(Money_purchase,bins3).value_counts().plot.bar(rot=20)

跟购物频率F一样,购买金额也存在一些离散值,后续分析中会特别处理。

综合上面的计算,RFM的三个指标的数据区间范围分别是:

R [0.0, 12.1]

F [1.0, 200.0]

M [2.9, 268478.0]

5.2.利用RFM模型挖掘价值用户

第一步,建立RFM矩阵,并且给列名重命名。

#Calculate RFM metrics
rfm=salesOR_NoDupNA.groupby(['CustomerID']).agg({'Date':lambda x:(Max_date-x.max()).days,
                                                'InvoiceNo':'count',
                                                'Amount':'sum'})
#Rename columns
rfm.rename(columns={'Date':'Recency','InvoiceNo':'Frequency','Amount':'Monetary'},inplace=True)
rfm.head()

第二步,建立用户行为评分机制,评分从1-4,对于recency标签,数值越大评分越小,因为商家喜欢近期活跃的用户,对于frequency购买频率以及monetary消费总额是越大评分越高。

#Building RFM rating principle
r_labels=range(4,0,-1)
f_labels=range(1,5,1)
m_labels=range(1,5,1)

根据RFM用户三个标签对用户行为进行划分,使用了pd.qcut函数对每个标签下的数据进行4等分,并且赋予评分。

r_quartiles = pd.qcut(rfm['Recency'],q=4,labels=r_labels)
f_quartiles = pd.qcut(rfm['Frequency'],q=4,labels=f_labels)
m_quartiles = pd.qcut(rfm['Monetary'],q=4,labels=m_labels)
rfm = rfm.assign(R=r_quartiles, F=f_quartiles, M=m_quartiles)

有了RFM每个标签的评分后进行统计和算出每一位用户的最终得分,这里是把每个标签的评分相加。

#Calculate RFM Segment and RFM Score
def add_rfm(x):
    return str(x['R'])+str(x['F'])+str(x['M'])

rfm['RFM_Segment']=rfm.apply(add_rfm,axis=1)
rfm['RFM_Score']=rfm[['R','F','M']].sum(axis=1)
rfm.head()

再来看看RFM综合评分的统计信息,综合评分最低为3分,最高为12分。

#Summary metrics over RFM Score
rfm.groupby('RFM_Score').agg({'Recency':'mean','Frequency':'mean','Monetary':['mean','count']}).round(1)

用户根据RFM的综合评分RFM_Score分为了10个等级,实际运用中可能需要比较粗略的划分,这里把用户分为3个大的等级。

#Use RFM score to group customers into Gold, Silver, Bronze segments:
def segments(df):
    if df['RFM_Score']>9:
        return 'Gold'
    elif (df['RFM_Score']>5) and (df['RFM_Score']<=9):
        return 'Silver'
    else:
        return 'Bronze'
    
rfm['General_Segment']=rfm.apply(segments,axis=1)
rfm.groupby('General_Segment').agg({'Recency':'mean','Frequency':'mean','Monetary':['mean','count']}).round(1)

分别是金、银、铜三个等级,RFM综合评分分别为:10-12、6-9、3-5。 这样可以把所有的用户根据上述RFM模型进行划分,价值用户就可以挖掘出来,可以根据粗略的划分General_Segment或者根据RFM_Score确定价值用户。

rfm.head()

5.3.利用K-Means算法挖掘价值用户

在机器学习中大概可以划分为三种学习类型:(1)supervised learning; (2) unsupervised learning; (3) semi-supervised learning。在Unsupervised learning中模型不需要算出某个预测值,最经典的应用就是clustering聚类,也就是对数据集进行分组。

聚类是将一组对象组合在一起的任务,使得同一聚类中的对象彼此更相似,而不是与其他聚类中的对象相似。相似度是反映两个数据对象之间关系强度的度量。聚类主要用于探索性数据挖掘。它在许多领域具有多种用途,例如机器学习,模式识别,图像分析,信息检索,生物信息学,数据压缩和计算机图形学等等。

在聚类计算中,K-Means是个非常流行的算法,在本次分析中就采用了这个方法来进行价值用户的挖掘。

K-Means算法的应用有三个限制:(1)标签的分布是对称的,not skewed;(2)标签的平均值一样;(3)标签的方差一样。

针对对称问题,可以用对数变换(Logarithmic transformation)来解决,针对平均值和方差一样的问题,可以标准化转换(standardization)来解决,这两步的顺序是有严格要求的,因为log变换只适用于大于零的数值,而标准化会产生负值,所以必须要先进行log转换后进行standardization。 在前面的描述统计分析中,我们已经清楚地知道R\F\M三个标签的直方图是严重不对称,而且平均值以及方差都不一样,所以需要进行下面的两步转换。

第一步,对数变换(Logarithmic transformation)

rfm_k=rfm[['Recency','Frequency','Monetary']]
#unskew the data with log transformation
rfm_log=rfm[['Recency','Frequency','Monetary']].apply(np.log,axis=1).round(3)

方便查看,把三个标签的直方图画在一起。

#plot the distribution of RFM values
f,ax=plt.subplots(figsize=(10,12))
plt.subplot(3,1,1);sns.distplot(rfm_log.Recency,label='Recency')
plt.subplot(3,1,2);sns.distplot(rfm_log.Frequency,label='Frequency')
plt.subplot(3,1,3);sns.distplot(rfm_log.Monetary,label='Monetary')
plt.show()

第二步,标准化(Standardization)

对数变换之后是标准化,使用公式:Z=(X-μ)/σ 可以使用scikit-learn里面preprocessing下面的StandardScaler实现标准化转换。

#Normalize the variables with StandardScaler
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(rfm_log)
#Store it separately for clustering
rfm_normalized=scaler.transform(rfm_log)

第三步,选择适合的聚类数目

选择聚类数目的方法有好几种,这里采用的是Elbow Criterion method。

from sklearn.cluster import KMeans
#1st step: get the best KMeans
ks = range(1,8)
inertias=[]

for k in ks:
    kc = KMeans(n_clusters=k, random_state=1)
    kc.fit(rfm_normalized)
    inertias.append(kc.inertia_)#sum of squared distances of samples to their closest cluster center

把计算的1-8个聚类数目情况画在一起,寻找Elbow弯点。

#plot ks vs inertias
f,ax = plt.subplots(figsize=(10,6))
plt.plot(ks,inertias,'-o')
plt.xlabel('Number of clusters,k')
plt.ylabel('Inertia')
plt.title('What is the best number for KMeans?')
plt.show()

这里要说一下K-Means聚类方法的原理,简单说就是找到聚类的中心点,可以是已有的数值点也可以是数据集中没有实际存在的数值点,比如3个聚类就有3个聚类中心点,围绕这3个中心点计算数据集中每一个点到这3个中心点的距离,将数据点归类到最短距离的中心点类别中,距离计算的公式为:sqrt[(x2-x1)^2+(y2-y1)^2+(z2-z1)^2],聚类中心点越多,也就是分类越多,数据点距离这些中心点的距离平方和就越大,所以上图中clusterk越大,inertia就越小,这里我们选择cluster_k=3进行分组聚类计算。

第四步,模型计算

# clustering
kc=KMeans(n_clusters=3,random_state=1)
kc.fit(rfm_normalized)

# Create a cluster label column in the original DataFrame
cluster_labels = kc.labels_

# Calculate average RFM values and size for each cluster
rfm_k3=rfm_k.assign(k_cluster=cluster_labels)

#Calculate average RFM values and sizes for each cluster
rfm_k3.groupby('k_cluster').agg({'Recency':'mean','Frequency':'mean','Monetary':['mean','count']}).round(0)

通过对比RFM模型得出的Gold\Silver\Bronze,这里得出的三个聚类0,1,2分别对应了Silver\Bronze\Gold,最具有价值的用户群是k_cluster = 2这个类别的用户。

利用K-Means算法把用户进行分类,从而挖掘出价值用户,看看分析的最终结果。

rfm_k3.head()

找到k_cluster=2的价值用户,对价值用户的购物行为进行针对性分析,比如消费习惯(购物时段)、喜欢购买的商品种类、购物种类的关联性(喜欢一起购买的产品)等等,这样就可以给价值用户提供个性化的消费方案,针对价值用户提供以消费者为中心的智能商业模式。

这里使用了机器学习中的unsupervised类型的学习方法,没有评估模型的特定指标,想要验证上述采用 RFM模型以及K-Means算法进行价值用户挖掘的有效性和准确性,需要在实际应用中验证分类效果。

6.价值用户挖掘结果

6.1.用户画像

用户已经进行分组,接下来看看不同类型用户的消费行为特征。

# cov = coefficient of variance
def cov(x):
    return np.std(x)/np.mean(x)

rfm.groupby('General_Segment').agg({'Recency':['mean','std',cov],'Frequency':['mean','std',cov],'Monetary':['mean','std',cov]}).round(1)

通过建立RFM模型及评分方法分组得出的结果显示,价值用户最近一次消费的平均值是20.8天,平均频率是217.3次,平均花费是5056.7英镑。

# cov = coefficient of variance
def cov(x):
    return np.std(x)/np.mean(x)

rfm_k3_sta=rfm_k3.groupby('k_cluster').agg({'Recency':['mean','std',cov],'Frequency':['mean','std',cov],'Monetary':['mean','std',cov]}).round(1)
rfm_k3_sta  

上面结果是使用K-Means方法得出的结果,价值用户最近一次消费的平均值是17.7天,平均频率是242.8次,平均花费是5863.7英镑,结果比使用评分方法要更好一些。

6.2.价值用户对销售额的贡献

# different customer category and the number of customer using K-means
customer_num=rfm_k3.groupby('k_cluster').agg({'Recency':['count']})
# pie figure
fig=plt.figure(figsize=(6,9))
test=[1815,1462,1020]
labels = [u'cluster0',u'cluster1',u'cluster2']
colors=['red','yellow','green']
patches,text1,text2 = plt.pie(test,
                      labels=labels,
                      colors=colors,
                      autopct = '%3.2f%%',
                      labeldistance = 1.2,
                      shadow=False,
                      startangle=90,
                      pctdistance = 0.6)
plt.axis('equal')
plt.legend()
plt.title('Customer Segment in %')
plt.show()
fig.savefig('segmentINpercent.png')

上图是用户分组的情况,按照价值贡献情况排名分别是cluster2, cluster0, cluster1,价值用户cluster2占比23.74%。下面看看不同用户分组对销售额的贡献情况。

# different customer category and associated sales using K-means
customer_sales=rfm_k3.groupby('k_cluster').agg({'Monetary':['sum']})
# pie figure
fig=plt.figure(figsize=(6,9))
test=[1911297.113,424054.261,6034667.080]
labels = [u'cluster0',u'cluster1',u'cluster2']
colors=['red','yellow','green']
patches,text1,text2 = plt.pie(test,
                      labels=labels,
                      colors=colors,
                      autopct = '%3.2f%%',
                      labeldistance = 1.2,
                      shadow=False,
                      startangle=90,
                      pctdistance = 0.6)
plt.axis('equal')
plt.legend()
plt.title('Customer Segment assocated sales in %')
plt.show()
fig.savefig('segmentSales.png')

价值用户cluster2占比只有23.74%却贡献了72.10%的销售额,是业务的重点发展对象。

6.3.总结

本次分析利用Python语言对电子零售数据进行了数据分析和挖掘,计算分析主要有两个方面:(1)运营指标统计分析;(2)使用了两种方法RFM模型以及K-Means机器学习算法挖掘价值用户。

(1)通过运营指标统计分析,我们了解了该电子商务公司的整体运营情况,计算了月销售数量、月销售总额、月均销售额、周销售量、周销售总额、周均销售额、客单价、件单价、连带率,通过这些指标我们了解到该电子商务公司月销售单数、月销售额在2011年的9月、10月以及11月有明显的增长,周销售额在星期四达到最高值。

(2)为了挖掘价值用户,我们使用了两种方法,第一个方法是利用RFM模型对用户进行评分分组,第二个方法是利用K-Means算法对用户进行“机器学习”分组,两种方法都挖掘出价值用户,比较两种方法得出的用户画像结果,K-Means方法得出的结果更好一些,最终挖掘出的价值用户占比23.74%却贡献了72.10%的销售额。

确定价值用户之后可以进一步学习价值用户的消费习惯,从而提供以消费者为中心的智能商业模式,根据实际应用情况进行多次迭代来优化价值用户挖掘的模型。

  • 4
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值