前言
传统电商营销缺乏对客户需求的有效分析,使得营销决策具有较大的主观性和盲目性,而现代营销有赖于各种营销数据库的建立和数据分析,数据的使用贯穿着整个营销过程的始末,对于营销效果起着至关重要的影响性作用。
数据来源
本次分析以英国礼品电商公司——Kaggle2010年12月1日至2011年12月9日在英国注册的非实体网上零售发生的所有交易数据为对象,Python作为分析工具,结合实际业务指标,分析其销售、退货等情况,且依据RFM模型对客户进行分类。最终得出数据及静态或动态的可视化结果,并对结果进行解读,同时针对不同业务和不同层级的客户提出相关对策和建议。
研究思路
数据处理
数据可视化分析
由于该公司位于英国,因此购买数量和交易额理所应当最多。除此之外,荷兰,爱尔兰,德国,法国也是主要消费国家,需要重点关注。
销量最佳的月份
销量最高的是11月份,其次是12月份,大部分销量较佳的月份集中在下半年,这是因为该产品是礼品,在下半年节日较多,加上促销优惠,所以销量比上半年月份多。
客户消费行为统计性描述
客户平均消费次数为4次,有的客户甚至消费高达210次,是产品的忠诚客户。客户平均消费金额为2053元,而75%的用户消费金额为1661元,低于平均消费金额,这说明有部分用户消费金额较大,是属于非常有价值的用户,需要公司对其保持重点关注。客户购买产品数量平均高达1194件,这是因为销售对象主要是批发商,则属于正常的数量。
退货率分析
退货率透视图中2010年的月份出现空值,这是因为数据最早是为2010年12月1日,其12月份的退货率为9.10%在平均退货率9.25%之下。2011年中,相比其他月份,1月和12月退货率高达19.04%和32.16%,视为异常值,这需要业务人员考虑是外部因素还是内部因素导致的,可以从产品、渠道、价格、促销四个方面去寻找和分析原因,以此改进业务。
客户分类
分类标准:
重要价值客户:三项指标都高的,即带来主要效益的客户
发展客户:消费频次比较低,但是金额和最近日期得分都高
重要保持客户:最近一次消费时间间隔较久,但消费频次和消费金额较高
挽留的客户:最近一次消费时间间隔较久,消费频次较低,但消费金额高
一般价值客户:最近一次消费时间间隔短,消费频次高,但消费金额较低
一般发展客户:最近一次消费时间间隔短,消费频次低,消费金额低
一般保持客户:最近一次消费时间间隔长,消费频次高,消费金额低
一般挽留客户:三项指标都低的
客户分类情况
根据可视化数据可知,该公司最多的是重要价值客户和重要发展客户,占比达到47.2%,这两类客户是该公司创造收益价值的主力军。企业应对此类客户多关心或多收集意见建议。
其次,是一般发展客户和一般挽留客户,占比为40.4%,针对一般发展客户,建议获取该类用户的详细数据信息和用户画像,了解该类用户的消费需求,进行更加精准的营销,及时推送产品信息。
对于近期交易较少的重要保持客户和重要挽留客户,以赠送优惠券或推送折扣信息等措施,增加用户活跃度。
总结
将客户分层,对不同分层的客户采取不同的营销手段,能够大大节约营销成本。根据每类客户的特征和相应的比例进行分配,使营销开支利用率最大化,同时也使营销效果最大化。
python代码块
代码块
# -*- coding: utf-8 -*-
#导入模块
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import plotly as py
import plotly.graph_objs as go#绘图的函数
import os
os.chdir('C:\data\ecommerce-data')
#读取数据
df=pd.read_csv('data.csv',encoding='utf-8',dtype={'Customer':str})
df.shape
df.info()
df[df['InvoiceNo'].str[0]=='C']
#订单编号开头为字母C的属于退货订单
#数据清洗
df.drop(['Description'],axis=1,inplace=True)
df.apply(lambda x: sum(x.isnull())/len(x),axis=0)
df1=df.dropna(how='any').copy()
df1['InvoiceDate']=pd.to_datetime(df1['InvoiceDate'],errors='coerce')
#提取日期部分
df1['InvoiceDate']=df1['InvoiceDate'].dt.date
df1.info()
#新建销售金额字段
df1['Price']=df1.apply(lambda x: x[2]*x[4],axis=1)
#填充,用U表示客户编号缺失的客户
df['CustomerID']=df['CustomerID'].fillna('U')
# 拆分订单日期,并增加年、月、日、日期四个字段,以及合计购买字段
#日期
df['date']=[x.split(' ')[0] for x in df['InvoiceDate']]
#时间
df['time']=[x.split(' ')[1] for x in df['InvoiceDate']]
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.drop(['InvoiceDate'],axis=1,inplace=True)
#查看
df[['date','year','month','day']].head()
df['date']=pd.to_datetime(df['date'])
#合计购买,消费金额=消费数量*单价
df['amount']=df['Quantity']*df['UnitPrice']
df=df.drop_duplicates()
#单价异常值
df.describe()
df2=df.loc[df['UnitPrice']<=0]
df2.shape[0]/df.shape[0]
df2['UnitPrice'].groupby(df2['UnitPrice']).count()
# 数据分析与可视化
#问题一
df1[df1['Quantity']>0].groupby('Country').sum()['Quantity'].sort_values(ascending=False).head(10)
quantity_10=df1[df1['Quantity']>0].groupby('Country').sum()['Quantity'].sort_values(ascending=False).head(10)
trace_basic=[go.Bar(x=quantity_10.index.tolist(),y=quantity_10.values.tolist(),
marker=dict(color='orange'),opacity=0.50)]
layout=go.Layout(title='购买商品前10的国家',xaxis=dict(title='国家'))
figure_basic=go.Figure(data=trace_basic,layout=layout)
py.offline.plot(figure_basic,filename='购买商品前十的国家.html')
#问题二
price_10=df1[df1['Quantity']>0].groupby('Country').sum()['Price'].sort_values(ascending=False).head(10)
trace_basic=[go.Bar(x=price_10.index.tolist(),y=price_10.values.tolist(),
marker=dict(color='orange'),opacity=0.50)]
layout=go.Layout(title='交易额前10的国家',xaxis=dict(title='国家'))
figure_basic=go.Figure(data=trace_basic,layout=layout)
py.offline.plot(figure_basic,filename='交易额前十的国家.html')
#问题三
#创建月份字段
df1['month']=pd.to_datetime(df1['InvoiceDate'],errors='coerce').dt.month
month=df1[df1['Quantity']>0].groupby('month').sum()['Quantity'].sort_values(ascending=False)
sns.set(style='whitegrid',font_scale=1.2)
df1[df1['Quantity']>0].groupby('month').sum()['Quantity'].sort_values(ascending=False).plot(kind='bar')
plt.title("月份销量",fontsize=12)
plt.xlabel("月份")
plt.ylabel("销量")
plt.xticks(rotation=45)
plt.rcParams['font.sans-serif']=['Simhei']
#问题四
sumprice=df1[df1['Quantity']>0]['Price'].sum()
count_ID=df1[df1['Quantity']>0]['InvoiceNo'].count()
avgPrice=sumprice/count_ID
print(avgPrice)
#问题五
#不同用户的汇总
customer=df1[df1['Quantity']>0].groupby('CustomerID').agg({'InvoiceNo':'nunique',
'Quantity':np.sum,
'Price':np.sum})
customer.describe()
# 问题六 退货率
t=df.loc[df['Quantity']<=0]
tt=pd.pivot_table(t,index=['year'],columns=['month'],values=['amount'],aggfunc={'amount':np.sum},margins=False)
p=df[(df['Quantity']>0)&(df['UnitPrice']>0)]
pp=pd.pivot_table(p,index=['year'],columns=['month'],values=['amount'],aggfunc={'amount':np.sum},margins=False)
np.abs(tt/pp)#透视图
np.abs(tt/pp).loc['2011'].mean()
from plotly.graph_objs import Scatter
trace0=Scatter(x=np.arange(1,13),
y=[0.190433,0.048836,0.047753,0.08306,0.061359,0.092788,0.052807,0.071692,0.036764,0.071135,0.031744,0.321562])
layout=go.Layout(title="2011年退货率趋势", xaxis_title="月份", yaxis_title="退货率")
fig=go.Figure(data=[trace0], layout=layout)
py.offline.plot(fig,filename='2011年退货率趋势.html')
#问题七 客户分类
R_value=p.groupby('CustomerID')['date'].max()#最近的购买日期
#把最后一次购买距离截止日期的天数作为参考时间
p['date'].max()
R_value=(p['date'].max()-R_value).dt.days#间隔天数
F_value=p.groupby('CustomerID')['InvoiceNo'].nunique()#消费频次
M_value=p.groupby('CustomerID')['amount'].sum()#消费金额
R_value.describe()
plt.rcParams['savefig.dpi']=500#图片像素
plt.rcParams['figure.dpi']=120#分辨率
sns.set(style='whitegrid')
plt.hist(R_value,bins=30)
plt.title("最近一次消费时间间隔", fontsize=12)
plt.xlabel("天数")
plt.ylabel("数量")
plt.rcParams['font.sans-serif']=['Simhei']
plt.show()
M_value.describe()
plt.hist(M_value[M_value<2000],bins=30)
plt.title("总金额小于2000的分布", fontsize=12)
plt.xlabel("金额")
plt.ylabel("数量")
plt.rcParams['font.sans-serif']=['Simhei']
plt.show()
F_value.describe()
plt.hist(F_value[F_value<25],bins=30)
plt.title("频次小于25的分布", fontsize=12)
plt.xlabel("频次")
plt.ylabel("数量")
plt.rcParams['font.sans-serif']=['Simhei']
plt.show()
#依据分位数和最大值对三个指标R、F、M进行分级
R_value.quantile([0.1,0.2,0.3,0.4,0.5,0.9,1])
F_value.quantile([0.1,0.2,0.3,0.4,0.5,0.9,1])
M_value.quantile([0.1,0.2,0.3,0.4,0.5,0.9,1])
R_bins=[0,30,90,180,360,720]
F_bins=[1,2,5,10,20,5000]
M_bins=[0,500,2000,5000,10000,200000]
R_score=pd.cut(R_value,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','amount':'M_score'},inplace=True)
rfm.info()
#数据类型转换
for i in ['R_score','F_score','M_score']:
rfm[i]=rfm[i].astype(float)
rfm.describe()
# 分层
rfm['R']=np.where(rfm['R_score']>3.82,'高','低')
rfm['F']=np.where(rfm['F_score']>2.03,'高','低')
rfm['M']=np.where(rfm['M_score']>1.89,'高','低')
rfm['value']=rfm['R'].str[:]+rfm['F'].str[:]+rfm['M'].str[:]#新建一个价值字段
rfm['value']=rfm['value'].str.strip()#去除空格
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()
#不同类型客户的情况
trace_basic=[go.Bar(x=rfm['客户分类'].value_counts().index,
y=rfm['客户分类'].value_counts().values,
marker=dict(color='orange'),opacity=0.50)]
layout=go.Layout(title='客户分类情况',xaxis=dict(title='用户重要度'))
figure_basic=go.Figure(data=trace_basic,layout=layout)
py.offline.plot(figure_basic,filename='客户分类情况.html')
#不同类型客户的占比
trace=[go.Pie(labels=rfm['客户分类'].value_counts().index,
values=rfm['客户分类'].value_counts().values,
textfont=dict(size=12,color='white'))]
layout=go.Layout(title='客户分类比例')
figure_basic=go.Figure(data=trace,layout=layout)
py.offline.plot(figure_basic,filename='客户分类比例.html')
数据皮皮侠
您的关注是我们更新的动力
长按识别二维码关注我们

