赞
踩
这个数据集是kaggle上面的一个电商数据集,其中包含2010年12月12日至2011年12月9日之间在英国注册的非商店在线零售的所有交易。该公司主要销售各种独特的礼品之类,其中许多客户该公司是批发商。因此本次数据分析将对客户进行分析,并对客户进行相关分层处理。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import os
import warnings
import missingno as msno
warnings.filterwarnings('ignore')
data = pd.read_csv('data.csv',encoding = 'utf-8', dtype = {'CustomerID' : str})
data.head()
这就是data数据集的前五行。
接下来观看数据概况
data.describe()
我们看到这里面Description和CustomerID字段都有相应的缺失,因此我们选择将这里面的数据进行处理。
首先我们选择将Description字段里面缺失的行删除,另外我们将CustinerID中确实字段填补为U。
data.dropna(axis = 0, subset = ['Description'], inplace = True)
data.CustomerID = data.CustomerID.fillna('U')
做好以上处理后我们看每个客户的每个订单的购买商品数量
temp = data.groupby(by=['CustomerID', 'InvoiceNo'], as_index=False)['StockCode'].count()
temp.rename(columns = {'StockCode': 'product numbers'})
数据集标签InvioceNo里有一些编号包含’C’,这代表这些订单时退货订单,因此我们需要对这些退货订单进行处理。我们写一个函数,找出退货订单的原订单。这里面会有如下两种情况:
data_cleaned = data.copy(deep = True) data_cleaned['quantity_canceled'] = 0 unpaired_invoice = [] paired_invoice = [] for index, col in data.iterrows(): if col['Quantity'] > 0 or col['Description'] == 'Discount': continue #提取出和取消订单的商品配对的原订单 df_test = data[(data['CustomerID'] == col['CustomerID']) &(data['StockCode'] == col['StockCode']) &(data['InvoiceDate'] < col['InvoiceDate']) &(data['Quantity']) > 0] if (len(df_test) == 0): unpaired_invoice.append(index) elif (len(df_test) == 1): index_order = df_test.index[0] data_cleaned.loc[index_order, 'quantity_canceled'] = -col['Quantity'] paired_invoice.append(index) elif (len(df_test) > 1): df_test.sort_index(axis=0 ,ascending=False, inplace = True) for ind, val in df_test.iterrows(): if val['Quantity'] < -col['Quantity']: continue data_cleaned.loc[ind, 'quantity_canceled'] = -col['Quantity'] paired_invoice.append(index) break
经过上述代码处理后,我们就得到了两个列表,一个列表叫unpaired_invoice,这个里面记录了没有配对的订单。还有一个列表叫做paired_invoice,表示配对的订单。
我们查看列表长度,发现分别有7106和1994条。
我们接下来先探索相应的退货情况。
#分别提取数量为正的订单和数量为负的订单
data_canceled = data[data['Quantity'] <= 0]
data_all = data[(data['Quantity'] > 0)]
data_canceled['month'] = pd.to_datetime(data_canceled['InvoiceDate']).dt.month
data_all['month'] = pd.to_datetime(data_all['InvoiceDate']).dt.month
data_canceled['year'] = pd.to_datetime(data_canceled['InvoiceDate']).dt.year
data_all['year'] = pd.to_datetime(data_all['InvoiceDate']).dt.year
data_canceled['price'] = - data_canceled['Quantity'] * data_canceled['UnitPrice']
data_all['price'] = data_all['Quantity'] * data_all['UnitPrice']
按照年月分别统计退货金额和退货率,tt这个表就是展示分月的退货总金额,pp代表所有订单数量为正的购物总金额,tt / pp 就代表退货率情况。
tt = data_canceled.groupby(['year','month'])['price'].sum().unstack()
pp = data_all.groupby(['year','month'])['price'].sum().unstack()
plt.figure(figsize = (8,6))
plt.title('各月份退货金额',fontsize = 16)
plt.bar(tt.loc[2011].index, tt.loc[2011].values)
plt.figure(figsize = (8,6))
plt.title('各月份退货比例',fontsize = 16)
plt.plot((tt / pp).loc[2011].index, (tt / pp).loc[2011].values,)
我们看到在1月份和12月份相应的退货金额和退货比例都是上升的,这里的原因应该是在那个时候西方人可能会过圣诞节之类的节日,出现大批购物的次数变多,同时相应的退货次数也增多了,这和我们的双十一有没有点像啊,购买之后都是会有大批退货。
RFM分析主要包括三个维度,R代表客户最近一次购物消费的时间,F代表客户消费的频率, M代表客户消费总金额。为了进行这一分析,我们首先对数据进行以下处理,删除掉最近之前未配对的quantity为负的订单,由于配对订单已经包含在data_cleaned这一特征里面的quantity_canceled标签中,因此我们对配对的订单也予以删除
data_cleaned.drop(unpaired_invoice, axis = 0, inplace = True)
data_cleaned.drop(paired_invoice, axis = 0, inplace =True)
为了计算RFM,我们计算total_price,这包含了客户的退货订单,同时取每个客户每笔订单的时间
data_cleaned['TotalPrice'] = data_cleaned['UnitPrice'] * (data_cleaned['Quantity'] - data_cleaned['quantity_canceled'])
data_cleaned.sort_values('CustomerID')[:5]
invoice_price = data_cleaned.groupby(by = ['CustomerID','InvoiceNo'], as_index = False).agg({'TotalPrice': 'sum','InvoiceDate': 'first'})
invoice_price.rename(columns = {'TotalPrice': 'basket_price'}, inplace =True)
invoice_price = invoice_price.loc[invoice_price['basket_price'] > 0]
invoice_price.head()
接下来我们就可以计算相应的R_value, F_value, M_value了。
invoice_price['year'] = np.array([i.year for i in invoice_price['date']])
invoice_price['month'] = np.array([i.month for i in invoice_price['date']])
invoice_price['day'] = np.array([i.day for i in invoice_price['date']])
R_value = invoice_price['date'].max() - invoice_price.groupby('CustomerID')['date'].max()
F_value = invoice_price.groupby('CustomerID')['InvoiceNo'].count()
M_value = invoice_price.groupby('CustomerID')['basket_price'].sum()
#观察R_value的频数分布
plt.title('R_value分布直方图')
plt.hist(R_value.dt.days, bins = 20)
#观察F_value的频数分布
plt.title('F_value分布直方图')
plt.hist(F_value[F_value < 20], bins = 20)
#观察M_value的频数分布
plt.title('M_value分布直方图')
plt.hist(M_value[M_value < 4000], bins = 30)
接下来我们对R_value,F_value, M_value进行离散化分箱,便于我们对客户分类。
#分箱
R_bins = [0, 30, 60, 90, 360, 720]
F_bins = [1, 2, 5, 10, 20, 2000]
M_bins = [0, 500, 2000, 5000, 10000, 2000000]
R_score = pd.cut(R_value.dt.days, R_bins, labels = [5, 4, 3, 2, 1], right = False)
F_score = pd.cut(F_value, F_bins, labels = [1, 2, 3, 4, 5], right = False)
M_score = pd.cut(M_value, M_bins, labels = [1, 2, 3, 4, 5], right = False)
rfm = pd.concat([R_score, F_score, M_score], axis = 1)
rfm.rename(columns = {'date': 'R_score', 'InvoiceNo': 'F_score', "basket_price": 'M_score'}, inplace = True)
我们这里选取R_value、F_value、M_value的均值作为相应的分割点,分为高低等级。
rfm['R'] = np.where(rfm['R_score'] > 3.57, '高', '低')
rfm['F'] = np.where(rfm['F_score'] > 2.03, '高', '低')
rfm['M'] = np.where(rfm['M_score'] > 1.89, '高', '低')
rfm['value'] = rfm['R'] + rfm['F'] + rfm['M']
rfm
最后我们根据value标签对客户进行分类
def trans_value(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['value'].apply(trans_value) rfm['用户等级'].value_counts()
最后我们用plotly这个包来进行展示分类
import plotly as py import plotly.graph_objs as go pyplot = py.offline.iplot py.offline.init_notebook_mode(connected=True) trace_basic = [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_basic = go.Figure(data = trace_basic, layout = layout) pyplot(figure_basic) trace = [go.Pie(labels = rfm['用户等级'].value_counts().index, values = rfm['用户等级'].value_counts().values, textfont = dict(size = 12, color = 'white'), opacity = 0.5)] layout = go.Layout(title = '用户等级比例') figure = go.Figure(data = trace, layout = layout) pyplot(figure)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。