Python+Tableau分析英国电商

Python+Tableau分析英国电商

关注我专栏的朋友应该知道,我学习python也有一段时间了,只不过之前一直停留在入门的阶段,而且很多文章都是一个入门的介绍以及学习的过程。但是在我看来,如果不能通过练习把知识转化为自己的认知,那么自己就会一直浮在水面上,也就没有办法去更进一步。

所以就有了这篇文章.这篇文是我最用心的一篇,也是我花费时间最长的一篇,希望能让各位看官看的痛快。

这篇文章我将使用python和Tableau分析。

从以下几个维度进行分析

订单维度,客户维度,商品维度,时间维度,区域维度,生命周期,至于最后一个预测分析我只在Tableau中使用

一、Python分析部分

首先是python完成数据的清洗,以及后续处理,然后通过Tableau来分析制作可视化的图形

数据集来自UCI加州大学欧文分校机器学习库:https://archive.ics.uci.edu/ml/datasets/online+retail#​archive.ics.uci.edu

字段介绍:

InvoiceNo: 6位的交易序列号,系统为每笔交易自动分配的6为不同的数字序列,如果是以c开头则表明该订单被取消了

StockCode: 产品类别编码,每一种不同类别的商品对应不同的编码

Description: 对产品类别的描述,可能有缺失

Quantity: 每次交易的某种产品的购买数量,数字型

InvoiceDate: 交易触发时间,也就是交易日期

UnitPrice: 每个产品的单价,单位是英镑

CustomerID: 客户id,每个客户的id都不相同

Country: 客户居住国家

1.数据处理

#先导入必要的包
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from wordcloud import WordCloud,STOPWORDS,ImageColorGenerator
from PIL import Image
%matplotlib inline
sns.set(style='darkgrid')

导入数据集

sales = pd.read_excel(r'E:\Kaggle\Online_Retail.xlsx')
sales.head()

能够看到这个数据集存在缺失值

  1. 去除重复值

只有当两行数据完全相同时才算是重复值,这里去除重复值

#删除重复行,并打印重复行数
before_delete = sales.shape[0]
sales.drop_duplicates(inplace=True)
after_delete = sales.shape[0]
print('原有行数:',before_delete,'删除后:',after_delete,'重复行数:',
      before_delete-after_delete)
执行结果

2.处理缺失值

删除重复值以后的dataframe

sales.info()
执行结果

能够看到Description和CustomerID这两列还有重复值,所以缺失值的处理就是对这两列处理

由于Description是对商品的描述,所以即使有缺失也无法处理

而CustomerID 是这个数据集非常重要的一部分,所以不能直接删除,而且缺失值较多,

我觉得有必要看一下CustomerID这一列的数据

sales['CustomerID'].nunique()
# output
4372

一共有4372个不同的id,第一想法是用ffill的方式填补空值,但是考虑到这种做法可能会造成很大偏差,因此我使用0来代替这些缺失值

但是在替代之前要先看一下是否有id==0的

sales[sales['CustomerID']== '0']
output

可以看到输出结果只有表头,因此没有id为0的值,

下面使用0来填充

sales['CustomerID'].fillna('0',inplace=True)
#看一下是否有缺失值
sales['CustomerID'].isnull().sum()
#output
0

处理完后还有没有缺失值

sales.isnull().sum()

可以发现除了Description这一列,已经没有缺失值了

3.一致化处理

新增字段date,month

#新增字段date
sales['date'] = pd.to_datetime(sales['InvoiceDate'].dt.date,errors='coerce')

新增字段month

sales['Month'] = sales['InvoiceDate'].astype('datetime64[M]')

看下结果

sales.head()

看下数据类型

sales.dtypes

为了后边处理方便把cuustomerid转换位整型

sales['CustomerID'] = sales['CustomerID'].astype('int64')

新增一列求每次消费的消费者总额

sales['SumCost'] = sales['Quantity'] * sales['UnitPrice']

看一下整个数据集的描述性统计

sales.describe()

可以看到我在图中圈出了一个很有些意思的数据,quantity列居然有负值,考虑到商品的购买量不可能小于零, 所以这些数据应该是异常数据,让我们来看一看这些数据

#筛选出数量和价格小于零的值
sales[(sales['Quantity'] <= 0)|(sales['UnitPrice'] <= 0)]
执行结果

这里我们发现订单号码都是以C开头的,之前在理解字段的时候说过,以C开头代表的是取消的订单

所以把数据集拆分为两部分.1 交易成功的订单,2交易失败的订单

#在InvoiceNo里面找到包含C的字段
query_c = sales['InvoiceNo'].str.contains('C')
#创建新的表格,只含有cancel订单的表格
sales_cancel = sales.loc[query_c,:].copy()
#创建新的表格,只含有剩余的订单的表格
sales_success = sales.loc[-query_c,:].copy()

很不幸的是这里报错了

报的是值错误,我就去分析这个是什么错,因为如果queryc查出来只有True和False两种的话,这个loc切片就是可以使用的,但是这里报错了,所以我考虑是不是qurey_c里面还有其他值

把query_c单独弄出来

#报错了,查询是什么原因报错
query_c = sales['InvoiceNo'].str.contains('C')
query_c

这里还看不出什么,由于前面30个和后面30个显示的都是nan,所以我不知道这个是因为nan的存在报的错。我开始的时候以为这里是因为数据类型的错误,所以把InvoiceNo转换为str型

sales['InvoiceNo'].astype('str')

但是没有效果

所以就考虑把query_c所有的值表示出来

query_c = sales['InvoiceNo'].str.contains('C')
query_c.unique()

到这里我就明白了,这是因为query_c里面有第三者,第三者很讨厌,无论是计算还是人生,哈哈哈

那要怎么才能把第三者去除呢,很简单引入一个判断就好,然后把False和NAN当作一个整体,就把三者转换成了两者

#创建新的表格,只含有cancel订单的表格
#之前做的报错了
sales_cancel = sales.loc[query_c==True,:].copy()
#创建新的表格,只含有剩余的订单的表格
sales_success = sales.loc[-(query_c==True),:].copy()

看一下这两张表

sales_cancel
sales_success

处理完cancel订单以后,我们再来看一下价格为零的订单

query_free = sales_success['UnitPrice'] == 0
sales_free = sales_success.loc[query_free==True,:].copy()
sales_not_free = sales_success.loc[-(query_free==True),:].copy()
sales_not_free.describe()

发现还有价格负的订单,让我们看一看这是什么原因

query_minus = sales_not_free['UnitPrice'] < 0
sales_minus = sales_not_free.loc[query_minus==True,:]
sales_minus

InvoiceNo是以A开头的,然后Description描述的是Adjust bad debt,说明两笔是坏账,我们予以删除

保留最终剩下来的结果

sales_normal = sales_not_free.loc[-(query_minus==True),:]
sales_normal.describe()

可以发现这里已经没有负值和免费的值了,所以到这里数据清洗这一步基本完成了

我们把原有的数据集的行数和现有数据集的行数做一个对比

print('原有行数:',sales.shape[0],'现有行数:',sales_normal.shape[0],
      '处理行数:',sales.shape[0]-sales_normal.shape[0])

而由于我后边想把这个清洗好的数据集在Tableau中进行处理,所以把这个处理好的数据集写入到csv中

#使用df.to_csv
sales_normal.to_csv('new.csv')

好的接下来就是数据的可视化和其他维度的分析过程了

  1. 订单维度

首先将sales_normal按订单号分组,对Quantity商品数量和SumCost总价分组求和:

#按照invoiceno分组,然后对quantity和sumprice
invoiceno_grouped = sales_normal.groupby('InvoiceNo')[['Quantity','SumCost']].sum()

描述性统计

invoiceno_grouped.describe()

该电商网站在2010年12月1日-2011年12月9日内共产生有效订单19960笔,笔单价为533.17英镑,人均购买约279件商品,说明用户群体多以批发商为主,且订单交易金额和订单内商品件数,其均值都高于中位数;订单交易金额的均值甚至高于Q3分位数。说明订单总体差异大,存在部分购买力极强的客户。

1.1绘制订单数量的分布图

x = invoiceno_grouped['Quantity']
sns.distplot(x,bins=100,color='c')
plt.title('Quantity Distribution of Orders')
plt.ylabel('Frequency')
plt.xlabel('Quantity')
plt.show()

由于小部分离群点使得横坐标过大,所以我做了一个筛选,剔除掉大于2000件的值

y = invoiceno_grouped[invoiceno_grouped.Quantity < 2000]['Quantity']
sns.distplot(y,bins=50,color='b',kde=False)
plt.title('Quantity Distribution of Orders  (Below 2000)')
plt.ylabel('Frequency')
plt.xlabel('Quantity')
plt.show()

订单内的商品数量呈现出很典型的长尾分布,大部分订单的商品数量在250件内,商品数量越多,订单数相对越少

1.2 绘制订单金额的分布

x = invoiceno_grouped['SumCost']
sns.distplot(x,bins=100,color='b',kde=False)
plt.title('SumCost Distribution of Orders')
plt.ylabel('Frequency')
plt.xlabel('SumCost')
plt.show()

可以看到这个和上面的订单量的模式很像,我们同样细分一下找到订单价小于1000的订单

x = invoiceno_grouped[invoiceno_grouped.SumCost < 1000]['SumCost']
sns.distplot(x,bins=100,color='b',kde=False)
plt.title('SumCost Distribution of Orders(Below 1000)')
plt.ylabel('Frequency')
plt.xlabel('SumCost')
plt.show()

能够看到订单额集中在400英镑以内,而350左右有一个峰值。

1.3我们接下来探讨一下订单额和订单数量之间的关系

这里用pandas来绘图,因为想直接把两个图放在一个底片上进行比较

#给绘制的图形设置大小
plt.figure(figsize=(20,5))
#plt.subplot绘制子图,1,2,1表示分成1行2个图片区域中的第1个图片
plt.subplot(1,2,1)
x = invoiceno_grouped['Quantity']
y = invoiceno_grouped['SumCost']
#用plt.scatter绘制散点图
plt.scatter(x,y,color='b')
plt.title('SumCost & Quantity')
plt.ylabel('SumCost')
plt.xlabel('Quantity')
#筛选商品订单件数在10000以下的的订单
plt.subplot(1,2,2)
a = invoiceno_grouped[invoiceno_grouped['Quantity'] < 10000]['Quantity']
b = invoiceno_grouped[invoiceno_grouped['Quantity'] < 10000]['SumCost']
plt.scatter(a,b,color='b')
plt.title('SumCost & Quantity(Quantity<10000)')
plt.ylabel('SumCost')
plt.xlabel('Quantity')
plt.show()

可以看到在大体上订单金额和订单数量正相关,好像这个是废话。。。

2.客户维度

由于之前在清洗数据的时候把很多nan替换成0,所以客户id为零的实际不能分析出太多东西,所以仅针对customerid不为0的进行分析

sales_useful = sales_normal[sales_normal.CustomerID != 0].copy()

2.1 对客户id和订单编号进行分组,索引会发生变化,所以重设索引,然后对同笔订单的金额和数量进行求和,然后在按照customerid分组展示

customer_grouped = sales_useful.groupby(['CustomerID','InvoiceNo'])[['Quantity','SumCost']].sum().reset_index()
#对于groupby的内容使用函数需要使用agg参数,,由于有多个参数,所以我采用了字典
customer_grouped = customer_grouped.groupby('CustomerID').agg({'InvoiceNo':np.size,
                                                               'Quantity':np.sum,
                                                              'SumCost':np.sum})
customer_grouped.describe()

通过这个描述性统计我们可以得到人均购买4笔同一种商品,25%的客户买完意见商品以后就没有留存下来,人均购买1187件商品,甚至超过了Q3的购买量,最多购买196915件商品,人均消费4338英镑,也同样超过了Q3,最多消费280206英镑。

2.2 消费金额分布(分组以后的金额)

x = customer_grouped['SumCost']
sns.distplot(x,bins=250,color='b',kde=False)
plt.title('SumCost Distribution of Customers')
plt.ylabel('Frequency')
plt.xlabel('SumCost')
plt.show()

同样做一个筛选

x = customer_grouped[customer_grouped['SumCost']<=5000]['SumCost']
sns.distplot(x,bins=50,color='b',kde=False)
plt.title('SumCost Distribution of Customers (Below 5000)')
plt.ylabel('Frequency')
plt.xlabel('SumCost')
plt.show()

通过这个图像我们可以发现的订单金额相对集中,大多在1000以内。

2.3 绘制消费金额和订单件数之间的关系

接下来的操作和上面的操作很类似

#设置图形的长宽
plt.figure(figsize=(16,4))
#使用plt.subplot绘制子图
plt.subplot(121)
x = customer_grouped['Quantity']
y = customer_grouped['SumCost']
plt.scatter(x,y,color='y')
plt.title('SumPrice & Quantity')
plt.ylabel('SumPrice')
plt.xlabel('Quantity')
#子图2
plt.subplot(122)
a = customer_grouped[customer_grouped['SumCost']<=5000]['Quantity']
b = customer_grouped[customer_grouped['SumCost']<=5000]['SumCost']
plt.scatter(a,b,color='y')
plt.title('SumCost & Quantity(SumCostBelow 5000)')
plt.ylabel('SumCost')
plt.xlabel('Quantity')
plt.show()

我这里设置了总消费额小于5000,第二个子图就很明显的表示了客户的订单数和消费金额成正相关

3.商品维度

商品对应的是stackcode,发先不同客户购买同意商品的价格不一致

我们就以85123A这个商品编号为例来分析一下

sales_normal.loc[sales_normal['StockCode'] == '85123A',:].UnitPrice.value_counts()

可以看到一件商品有多个不同的价格

下边就是要考虑商品的平均价格,商品的平均价格要按照商品来分组,然后求和Quantity和Sumcost,然后再用求和以后的SumCost 除以Quantity

product_grouped = sales_normal.groupby(['StockCode'])[['Quantity','SumCost']].sum()
product_grouped['avg_price'] = stock_grouped['SumCost']/stock_grouped['Quantity']
product_grouped.head()

下一步是查看价格分布

x = product_grouped['avg_price']
sns.distplot(x,bins=100,kde=False)
plt.title('avg_price Distribution')
plt.ylabel('Frequency')
plt.xlabel('avg_price')
plt.show()

同样的对价格做一个筛选

x = product_grouped[product_grouped['avg_price']<=100]['avg_price']
sns.distplot(x,bins=100,kde=False)
plt.title('avg_price Distribution(avg_price Below 100)')
plt.ylabel('Frequency')
plt.xlabel('avg_price')
plt.show()

能够看到绝大多数的商品价格在20英镑以内,可知该网站销售的商品大多是价格比较低的

那么我们来看一下价格和订单的关系,同样这里采用pandas’自带的scatter来绘制

plt.figure(figsize=(16,4))
#绘制子图
plt.subplot(121)
x = product_grouped['avg_price']
y = product_grouped['Quantity']
plt.scatter(x,y,color='r')
plt.title('avg_price & Quantity')
plt.ylabel('Quantity')
plt.xlabel('avg_price')
#子图2
plt.subplot(122)
a = product_grouped[product_grouped['avg_price']<=20]['avg_price']
b = product_grouped[product_grouped['avg_price']<=20]['Quantity']
plt.scatter(a,b,color='r')
plt.title('avg_price & Quantity (avg_price<20)')
plt.ylabel('Quantity')
plt.xlabel('avg_price')
plt.show()

同样的,看价格和订单金额的关系

plt.figure(figsize=(16,4))
#绘制子图
plt.subplot(121)
x = product_grouped['avg_price']
y = product_grouped['SumCost']
plt.scatter(x,y,color='r')
plt.title('avg_price & SumCost')
plt.ylabel('SumCost')
plt.xlabel('avg_price')
#子图2
plt.subplot(122)
a = product_grouped[product_grouped['avg_price']<=20]['avg_price']
b = product_grouped[product_grouped['avg_price']<=20]['SumCost']
plt.scatter(a,b,color='r')
plt.title('avg_price & SumCost (avg_price<20)')
plt.ylabel('SumCost')
plt.xlabel('avg_price')
plt.show()

我想把着四个图放在一起然后形成两组对比

plt.figure(figsize=(12,4))
#绘制子图
plt.subplot(2,2,1)
x = product_grouped['avg_price']
y = product_grouped['Quantity']
plt.scatter(x,y,color='r')
plt.title('avg_price & Quantity')
plt.ylabel('Quantity')
plt.xlabel('avg_price')

#子图2
plt.subplot(2,2,2)
a = product_grouped[product_grouped['avg_price']<=20]['avg_price']
b = product_grouped[product_grouped['avg_price']<=20]['Quantity']
plt.scatter(a,b,color='r')
plt.title('avg_price & Quantity (avg_price<20)')
plt.ylabel('Quantity')
plt.xlabel('avg_price')

#子图三

#绘制子图
plt.subplot(2,2,3)
x = product_grouped['avg_price']
y = product_grouped['SumCost']
plt.scatter(x,y,color='r')
plt.title('avg_price & SumCost')
plt.ylabel('SumCost')
plt.xlabel('avg_price')

#子图四
plt.subplot(2,2,4)
a = product_grouped[product_grouped['avg_price']<=20]['avg_price']
b = product_grouped[product_grouped['avg_price']<=20]['SumCost']
plt.scatter(a,b,color='r')
plt.title('avg_price & SumCost (avg_price<20)')
plt.ylabel('SumCost')
plt.xlabel('avg_price')
plt.show()

但是效果不好,因为这几个表堆叠在一起了

可以使用sharex参数来调整,这里就不做展开了

果然无论是哪个国家的人民都更偏向于低价商品,低价商品在成交量以及成交金额上面都是占据了非常大的部分,而价格较高的商品的销量远低于低价商品,那么可以进一步把平台作为一个走量的平台,就如唯品会。

4.时间维度

按照有效订单分组

time_grouped = sales_useful.groupby('InvoiceNo').agg({'date':np.min,
               'Month':np.min,'Quantity':np.sum,'SumCost':np.sum}).reset_index()

然后按照订单编码和订单量以及订单金额绘制两个图形

这一部分绘制的时候遇到了问题,然后借鉴前辈的做法

sns.set_style('white')
month = time_grouped.groupby('Month').agg({'Quantity': np.sum, 'SumCost': np.sum, 'InvoiceNo': np.size}).plot(secondary_y = 'InvoiceNo',
 x_compat=True, figsize = (12, 4))
month.set_ylabel('Quantity & SumCost')
month.right_ax.set_ylabel('Order quantities')
plt.show()

这里对于plot直接绘图还是有点不知所措,需要找到官方文档补一补

5.区域维度

对于区域维度的处理主要是按照客户id和国家分类,然后在把两张表合并在一起

#提取客户id和国家关系表
sales_country = sales_normal.drop_duplicates(subset=['CustomerID','Country'])

按客户分组,然后计算总金额

country_grouped = sales_useful.groupby('CustomerID')[['SumCost']].sum()

两张表合并

country_grouped = country_grouped.merge(sales_country,on=['CustomerID'])

合并以后按照国家在分组,计算消费金额和客户总数

country_grouped = country_grouped.groupby('Country').agg({'SumCost':np.sum,
                                                         'CustomerID':np.size})

这个语句一直报错,显示结果是keyerror 也就是没有这个名称,使用

country_grouped.head()

发现这里的sumcost已经变成了sumcost_x,不知道是什么原因,不过没关系我可以重命名

country_grouped.rename(columns={'SumCost_x':'SumCost'},inplace=True)
country_grouped.head()

为这个数据集添加一个新的字段,即avgamount 即人均消费。avg_amount = sumcost/cutomerid

看一下代码

country_grouped['avg_amount'] = country_grouped['SumCost']/country_grouped['CustomerID']
country_grouped.head(30)

这里可以发现除了英国以外其他国家的购买人数都很少

我们来按照avg_amount从大到小排列一下

country_grouped.sort_values(by='avg_amount',ascending=False).head(20)

能够看到虽然其他国家购买人数较少,但是人均购买量很可观,可以考虑吧筛选出具体的客户id然后取得联习给予适当的优惠和配备专属客服。

6.生命周期

我们知道一个网站能够长久的生存下去,那么客户的生命周期是一个很重要的因素。

由于该数据集的统计对象为2010年12月1日至2011年12月9日的全部订单,所以我们就只能统计这一段时间内的消费情况

首先筛选出id为0的客户

sales_useful = sales_normal[sales_normal.CustomerID != 0].copy()

按照客户id分组,然后找到客户第一次购买和最后一次购买的时间差

#客户第一次购买的时间
min_date = sales_useful.groupby('CustomerID')[['date']].min()
#客户最后一次购买的时间
max_date = sales_useful.groupby('CustomerID')[['date']].max()
(max_date - min_date).head(20)

可以看到好多的留存天数很多还是天数是0天,0天代表的是没有留存。

lifetime = max_date - min_date
lifetime.describe()

总共有4338个客户,平均留存时间130days,最小值是0天就是没有留存,前25%是0天说明有4分之一的用户是直接流失掉的,50%是93天,说明平均流失时间为93天,可以考虑在90天左右给予优惠促使客户完成购买然后留存下来,前75%是252天,最多的是留存373天。生命周期呈现两极分化的状态。

由于这个timedelta的类型不能绘制图形,所以转换成datetime的形式

life_time['life_time'] = life_time['date'].dt.days
life_time['life_time'].hist(bins = 20, color = 'c')
plt.title('Life Time Distribution')
plt.ylabel('Customer number')
plt.xlabel('Life time (days)')
plt.show()

可以看到绝大多数都是没有留存,可以考虑增加购买初体验。而且发现在350天左右又有了一个新的高峰

# 将分组增多至100,并拉宽图表的尺寸
life_time[life_time['life_time'] > 0].life_time.hist(bins = 100, figsize = (12, 6), color = 'c')
plt.title('Life Time Distribution without One-time Deal Hunters')
plt.ylabel('Customer number')
plt.xlabel('Life time (days)')
plt.show()

这个图有很多可以讨论的东西,用户会在75-150天左右有一个显著的下滑,那么我觉得可以考虑给这一部分即将流失的用户发放优惠券等,因为可以看到在170天以后的用户就很活跃了,用户粘性也较高,而且在300天以后的客户激增说明这一部分客户是平台的优质客户,要及时和这些客户沟通,询问客户的意见和建议。

Bonus: 我使用wordcolud 绘制一个词云图

from wordcloud import WordCloud
from wordcloud import STOPWORDS
stopwords = set(STOPWORDS)
wordcloud = WordCloud(background_color = 'white', width = 1200, height = 1200).generate(str(sales_useful['Description']))

print(wordcloud)
plt.rcParams['figure.figsize'] = (20, 15)
plt.axis('off')
plt.imshow(wordcloud)
plt.title('Most Occuring word in the Description list', fontsize = 20)
plt.show()

结论:

  1. 订单维度:该电商网站在2010年12月1日-2011年12月9日内共产生有效订单19960笔,笔单价为533.17英镑,人均购买约279件商品,说明用户群体多以批发商为主,且订单交易金额和订单内商品件数,其均值都高于中位数;订单交易金额的均值甚至高于Q3分位数。说明订单总体差异大,存在部分购买力极强的客户
  2. 客户维度:通过这个描述性统计我们可以得到人均购买4笔同一种商品,25%的客户买完意见商品以后就没有留存下来,人均购买1187件商品,甚至超过了Q3的购买量,最多购买196915件商品,人均消费4338英镑,也同样超过了Q3,最多消费280206英镑
  3. 商品维度:能够看到绝大多数的商品价格在20英镑以内,可知该网站销售的商品大多是价格比较低的,且价格越低对应的购买量越高,商品整体是较低价的平民商品
  4. 时间维度:总共有4338个客户,平均留存时间130days,最小值是0天就是没有留存,前25%是0天说明有4分之一的用户是直接流失掉的,50%是93天,说明平均流失时间为93天,可以考虑在90天左右给予优惠促使客户完成购买然后留存下来,前75%是252天,最多的是留存373天。生命周期呈现两极分化的状态。
  5. 区域维度:绝大多数的客户是来自英国本土,其他国家的客户较少,但是却多为优质客户,可以对这些客户进行深挖予以物流上面的支持

二、Tableau绘图可视化分析部分

好的,使用Pyhton分析以及可视化以后,我们来看一下使用Tableau绘制图形的结果,同样的还是使用上述的几个维度

Tableau部分我没有完全按照python的来,在使用Tableau的过程中涉及到多次的维度和度量之间的转换,还有很多其他的操作,但是因为这篇文章已经足够长了,所以就不写具体的操作步骤了。

这个购买趋势是我自己随意点击的时候发现的就留在最上边作为一个开篇图了

每天的购买量趋势分析:

这个是8月份的一个交易数据,能够看到这个交易数据有着明显的周期,这个在后续的操作中会有涉及

1.订单维度

1.1平均单价和购买数量的显示

平均单价
购买商品数量分析

1.2金额和订单商品分析

2.客户维度

2.1客户散点图

我使用tableau中一个特别方便的方法,就是使用鼠标右键点击选中一片区域,然后点击只保留,这样这里就只剩我选中的数据了,

客户散点图

当然还可以继续选下去,但是已经没有必要了,可以发现绝大多数的购买金额都在1000以下,而购买数量大都在500以下

2.2客户购买量

由于0代表的是之前的nan的值,所以将0这个id给去除掉,然后按照购买量的从高到低排列

这个很有意思,这个图还可以加入一个商品维度,不过这个就在商品维度分析了,这里就不展开了

2.3商品购买量

同样去除id为0的客户,可以发现id为14646的这位客户的购买量远大于其他的客户,可以通过电商平台的工具与该用户联系,然后给与一定的优惠

客户商品购买量分析

3.商品维度

3.1单件商品分析

单件商品分析

正如上面说明的同一件商品在不同客户购买时,单价不一样,对这件商品进一步分析以后发现这件商品在7月份以前价格都很低,但是在7月份价格激增,去查找了以下这件商品的描述

porecelain butterfly oil burner 好吧不知道这个是什么东西,但是知道这个有一个周期性的变化

3.2单价与购买量分析

单价与购买量分析

3.3商品种类与购买量分析

商品种类与购买量分析

3.4购买量前20的商品细分

12月份购买量前20名

4.时间维度

4.1全年购买趋势

4.2每季度购买趋势

4.3每天购买趋势

4.4单独分析8月份

可以明显看到,8月购买有明显的周期,进一步分析波峰和波谷分别是周几

按照每周的时间,得到下图可以看到周五和周四的购买量较多,周日的购买量较少

周四和周日的详细对比

可以看到每周的周日的购买量最少,考虑可能是周末的时候更多的在休息,而周四周五,购买量相对较多,考虑这个可能是由于一周的工作到此时想买点东西补偿以下自己,那么对于平台来说就有必要考虑在这几天做一个活动的策划,然后引导客户更多的消费

5.区域分析

5.1各国人均购买量分析

人均购买量分析

5.2国家购买分析

上图中的颜色越红代表购买量越多,这和python分析的结果是一致的

由于很多国家的购买量都很少,想要分析购买趋势需要按照一定的量来分析所以这里有一个筛选过程。

这一图是没有筛选的结果,由于图形颜色过多而且趋势也很杂,我觉得不利于找到规律,所以这里我先把购买总量大于50000的国家(不含英国)筛选出来

分别是Australia,Eire,France,Germany,Netherlands,Spain,Switzerland

这7个国家单独分析一下

首先是Australia

澳大利亚

Eire–爱尔兰

爱尔兰

France–法国

法国

Germany–德国

德国

Netherlands–荷兰

荷兰

Spain–西班牙

最后就是Switzerland

瑞士

通过图形发现荷兰是在所有国家中排名第二的国家,有一个很明显的低谷,7月份的购买量和购买数量几乎为零,这是什么原因呢?

试着分析一下

看看有多少人参与了这个购买过程

荷兰客户分析

发现了,荷兰的购买量基本就是14646这个客户的购买趋势。还记不记得之前在商品分析的时候提到的平均购买量的事情,这个就是那个平均购买量最多的客户。

我们就单独分析这个客户都买些什么商品了,再加入Stockcode以后发现客户买的很杂,考虑这个客户可能是一个分销商。无论怎样这个客户一定要取得联系,这个客户是特别优质的客户。受到这个的启发,我把这个7个国家的按照id来探寻一下规律

最终结果,发现澳大利亚,爱尔兰

澳大利亚:主要客户是12415这位客户

澳大利亚的头部客户

爱尔兰主要有两个客户,id为14156和14911的两位客户

爱尔兰客户分析

法国–法国好像不怎么符合这个结果

法国客户分析

德国–德国也是有很多用户购买

德国客户分析

西班牙–总体来讲也是符合几个头部用户的情况,比如:客户id 12502,12540,12597

西班牙客户分析

最后是瑞士,瑞士也基本符合这一特征

瑞士客户分析

主要是12451这个客户

12451客户的购买量

还差一个预测分析,由于预测分析有很多的问题,暂时还没有绘制出来。这个就先留个坑吧。

结论:通过Tableau的分析,我觉得总体和python差不多,而且有一点就是Tableau作为可视化的工具确实很方便,特别是其自带的汇总等功能能够很好地处理数据。而通过Tableau我最大的收获是通过趋势的对比找到了几个别国的特别优质客户,虽然这些客户的量在python中也有体现,但是在看到数字的时候还是没有和购买量联系起来,而通过图形我们就能够很直观的得到一个趋势,进而去探讨那些异常的点。

当然各有优缺点,能够互补是最好的。

最后我觉得如果让我做一份分析报告,这几个人我是一定要向老板推荐的,分别是14646,12415,14156,14911,12502,12540,12597以及12451,因为这几位客户无论是从哪个维度来说都是很优质的客户,在RFM模型中属于最优质的一档。

作者:Roar
链接:https://zhuanlan.zhihu.com/p/73039757

关注公众号:Python数据科学,get更多干货。

公众号回复:学习资源 获取100G干货
公众号回复:学习资源
获取100G干货

本文转载自知乎,只做主题效果测试使用,本文观点不代表datadeepin立场。

发表评论

电子邮件地址不会被公开。 必填项已用*标注