画像与标签

电商销售数据分析案例(Oracle)

2021-04-01  本文已影响0人  蓝天花园

目录:

一、项目背景

数据来源于Kaggle的电商数据集The UCI Machine Learning Repository,英国在线零售商在2010年12月1日到2011年12月9日的在线销售数据,该电商公司主要以销售各类礼品为主,多数客户都是批发商。

二、项目目标

使用Oracle 对数据进行处理与清洗,通过RFM模型、复购率、消费生命周期等对用户维度进行分析,利用ABC分类、退货率等维度展开剖析,结合Excel图表进行可视化展示,为精准营销与个性化服务提供支持。

三、字段说明

InvoiceNo: 发票编号,代表每笔交易的编号,如果编号开头为C,代表该笔交易取消
StockCode: 产品编号
Description: 产品名称
Quantity: 每笔交易的数量(含有负数,代表退货)
InvoiceDate: 交易时间
UnitPrice: 产品单价
CustomerID: 用户ID
Country: 产生交易国家

四、数据清洗/处理

1、选择字段

根据分析目的选择字段,数据集共8个字段,如果表格字段较多,视情根据分析目的的需要选择合适的字段。

2、删除重复值
CREATE TABLE new_ecommerce AS SELECT DISTINCT * FROM e_ecom;

创建备用表new_ecommerce,将旧表的数据去重添加进备用表。原有数据541909条, 去重后数据536641条,删除重复值5268条。

3、缺失值处理

检查缺失值

SELECT 
SUM(CASE WHEN CustomerID IS NULL THEN 1 ELSE 0 END)  "客户编号",
SUM(CASE WHEN InvoiceNo IS NULL THEN 1 ELSE 0 END )"发票编号",
SUM(CASE WHEN StockCode IS NULL THEN 1 ELSE 0 END )"产品编号",
SUM(CASE WHEN Quantity IS NULL THEN 1 ELSE 0 END )"发票编号",
SUM(CASE WHEN InvoiceDate IS NULL THEN 1 ELSE 0 END )"数量",
SUM(CASE WHEN UnitPrice IS NULL THEN 1 ELSE 0 END )"单价",
SUM(CASE WHEN Description IS NULL THEN 1 ELSE 0 END )"产品描述",
SUM(CASE WHEN Country IS NULL THEN 1 ELSE 0 END )"国家"
FROM new_ecommerce;

CustomerID存在缺失值135037条,Description出现缺失值1454条。数据都很大,不可能全部删除。Description产品描述不是项目分析,不用处理。



在实际工作中,像CustomerID客户ID缺失,首先找业务部门或者数据来源部门确认信息并且补上。本项目只有单一数据,无法找到相关人员确认,暂且把NULL值替换为0。

UPDATE new_ecommerce SET customerid = NVL(customerid,'0') ;

5、异常值处理

5.1检查日期是否在范围内(2010年12月1日到2011年12月9日)

SELECT MAX(InvoiceDate),MIN(InvoiceDate) FROM new_ecommerce

结果显示日期都在范围里,数据正常
5.2检查单价与销量数量,如出现负值与零值
SELECT MAX(UnitPrice)"最高价格",MIN(UnitPrice)"最低价格",MAX(Quantity)"最高销量",MIN(Quantity)"最低销量"
FROM new_ecommerce;

交易成功,销量不可能为负值或零值。如果销量为零或者负值情况,那么需要和业务/数据来源部门确认具体的原因。这里假设出现负值是客户退货情况。

DELETE FROM (SELECT * FROM new_ecommerce WHERE quantity <0 AND invoiceno NOT LIKE'C%');

检查发现交易销量小于0的发票编号大都是"C”开头的,有部分异常销量小于0但不是以"C"开头,这里做删除处理。

SELECT * FROM  new_ecommerce WHERE unitprice = 0;
DELETE FROM (SELECT * FROM new_ecommerce WHERE unitprice = 0);

检查发现有单价为0的免费单,共计1174。暂且不分析免费单,直接删除免费单的数据。

DELETE FROM ( SELECT * FROM new_ecommerce WHERE unitprice < 0)

检查发现两笔坏账,单价都是负值,故把它删除。


6、一致化处理

根据分析目的,我们处理InvoiceDate日期数据。这里只做日期分析,不分析小时分钟,故转换为日期格式。

ALTER TABLE new_ecommerce ADD Date_id VARCHAR2(15)
UPDATE new_ecommerce SET DATE_id = to_char(invoicedate,'yyyy-mm-dd')

五、用户行为分析

根据分析目的,本次分析将采用RFM模型
在RFM模式中:
R:最近一次消费时间(最近一次消费到参考时间的间隔)
F:消费的频率(消费了多少次)
M:消费的金额 (总消费金额)
一般的分析型RFM强调以客户的行为来区分客户。

1、RFM值计算
SELECT customerid,(to_date('2011-12-09','yyyy-mm-dd')-to_date(MAX(date_id),'yyyy-mm-dd')) R_time
FROM new_ecommerce
GROUP BY customerid
ORDER BY R_time

根据最近一次消费与客户数的分析结果显示最长的天数差是373天,最短0天;80%的客户在200天内都有交易记录,说明客户忠诚度不错。

SELECT customerid,count(DISTINCT invoiceno) F_times
FROM new_ecommerce
GROUP BY customerid;

分析显示,10次交易记录以内的客户占绝大部分,说明客户是很认可产品和服务。

SELECT customerid,sum(Quantity*UnitPrice) M_times
FROM new_ecommerce
GROUP BY customerid;

在2010年12月1日到2011年12月9日期间,交易金额主要集中在 1000英镑以内和1000-3000英镑这两个范围内。

CREATE VIEW view_rfm AS
(select CustomerID,
       (to_date('2011-12-09','yyyy-mm-dd')-to_date(MAX(date_id),'yyyy-mm-dd')) "天数差",
       count(DISTINCT invoiceno) "消费次数",
       sum(Quantity*UnitPrice) "消费金额" 
from new_ecommerce 
group by CustomerID)
SELECT CustomerID,天数差,消费次数,消费金额,(case when 天数差<=30 then 5
when  天数差 >30 and 天数差 <=90 then 4 
when 天数差>90 and 天数差<=180 then 3  
when 天数差>180 and 天数差<=365 then 2 else 1 END) "R评分",
(case when 消费次数<=10 then 1
when  消费次数 >10 and 消费次数 <=30 then 2 
when 消费次数>30 and 天数差<=50 then 3 
when 消费次数>50 and 消费次数<=80 then 4 else 5 END) "F评分",
(case when 消费金额<=1000 then 1
when  消费金额 >1000 and 消费金额 <=3000 then 2 
when 消费金额>3000 and 消费金额<=5000 then 3  
when 消费金额>5000 and 消费金额<=8000 then 4 else 5 END) "M评分"
from view_rfm;
select ROUND(avg(R评分),1) "R平均值",ROUND(avg(F评分),1) "F平均值",ROUND(avg(M评分),1) "M平均值"
FROM view_rfm1;
select CustomerID,
(case when R评分>3 then 1 else 0 END)  "R值",
(case when F评分>1 then 1 else 0 END)  "F值",
(case when M评分>1.1 then 1 else 0 END)  "M值"
FROM view_rfm1;
SELECT CustomerID,
(case when R值=1 and F值=1 and M值=1 then '重要价值客户'
  when R值=0 and F值=1 and M值=1 then '重要唤回客户'
  when R值=1 and F值=0 and M值=1 then '重要发展客户'      
  when R值=0 and F值=0 and M值=1 then '重要挽留客户'
  when R值=1 and F值=1 and M值=0 then '一般价值客户'
  when R值=1 and F值=0 and M值=0 then '一般发展客户'
  when R值=0 and F值=1 and M值=0 then '一般保持客户' 
ELSE '一般挽留客户' END) "客户分层"
from view_rfm2


分析发现,该电商平台总交易客户数4372位。交易客户中,一般发展客户(可以说是新客户)最多,占总数的34%,其次是一般挽留客户(流失客户)29%,重要发展客户22%,重要价值客户10%,重要挽留客户5%和重要挽回客户0.16%。

2.新老客户占比

每月新客数量及其占比

SELECT mon,SUM(new_1),SUM(total) mon_total,ROUND(SUM(new_1)/SUM(total),4) first_per
FROM(SELECT mon,customerid,MAX(is_new)new_1,COUNT(DISTINCT CustomerID ) total
FROM(SELECT     a.*,
     b.first_pur,
     to_char(INVOICEDATE,'yyyy-mm') mon,
     (CASE WHEN b.first_pur = to_char(INVOICEDATE,'yyyy-mm') THEN 1 ELSE 0 END) is_new
FROM new_ecommerce a
JOIN (
     SELECT 
            CustomerID,
            MIN(to_char(INVOICEDATE,'yyyy-mm')) first_pur
     FROM new_ecommerce
     GROUP BY CustomerID)b ON b.CustomerID = a.customerid)
GROUP BY mon,customerid
)
WHERE mon !='2010-12'
GROUP BY mon



每月的新老客户的销售数量与销售金额

SELECT mon,is_new,SUM(total_q),SUM(total_a)
FROM(SELECT mon,customerid,is_new,SUM(quantity) total_q,SUM(quantity*unitprice) total_a
FROM(SELECT     a.*,
     b.first_pur,
     to_char(INVOICEDATE,'yyyy-mm') mon,
     (CASE WHEN b.first_pur = to_char(INVOICEDATE,'yyyy-mm') THEN 1 ELSE 0 END) is_new
FROM new_ecommerce a
JOIN (
     SELECT 
            CustomerID,
            MIN(to_char(INVOICEDATE,'yyyy-mm')) first_pur
     FROM new_ecommerce
     GROUP BY CustomerID)b ON b.CustomerID = a.customerid)
GROUP BY mon,customerid,is_new
)
WHERE mon !='2010-12'
GROUP BY mon,is_new


3、用户生命周期分析

用户生命周期 = 最近一次购买时间 - 第一次购买时间

SELECT customerid,
       MIN(date_id) first_time,
       MAX(date_id) last_time,
       (MAX(to_date(date_id,'yyyy-mm-dd')) - MIN(to_date(date_id,'yyyy-mm-dd'))) life_time
FROM New_Ecommerce
GROUP BY customerid     

4、用户复购率分析
SELECT mon,ROUND(SUM(CASE WHEN user_mon_buy_times >1 THEN 1 ELSE 0 END)/COUNT(1),2) "复购率"
FROM(SELECT mon,COUNT(invoiceno) user_mon_buy_times
       FROM(  SELECT to_char(invoicedate,'yyyy-mm')mon,customerid,invoiceno
              FROM NEW_ECOMMERCE
              WHERE quantity >0
              GROUP BY to_char(invoicedate,'yyyy-mm'),customerid,invoiceno)
GROUP BY mon,customerid)
GROUP BY mon

5、商品分析
SELECT stockcode,
       SUM(quantity) sales,
       MAX(unitprice) price --销售价格存在折扣,取原价(最大值)
FROM new_ecommerce
WHERE quantity > 0  --销量存在退货
GROUP BY stockcode
ORDER BY sales; 
SELECT stockcode,sales,SUM(sales/total_sales) OVER(ORDER BY sales DESC) per_sales,row_number() OVER(ORDER BY sales DESC) RANK
FROM(SELECT DISTINCT stockcode,
       SUM(quantity*unitprice) OVER(PARTITION BY stockcode) sales,
       SUM(quantity*unitprice) OVER() total_sales
FROM new_ecommerce
WHERE quantity > 0)  
--创建商品销售额占比的视图,即是上面代码的视图 view_sales
SELECT stockcode,
       sales,
       per_sales,
       CASE WHEN per_sales <0.5 THEN 'A'
            WHEN per_sales <0.8 THEN 'B'
            ELSE 'C' END CLASS
FROM view_sales   
SELECT CLASS,
       SUM(sales) total_sales,
       COUNT(CLASS) total_class  
FROM(SELECT stockcode,
       sales,
       per_sales,
       CASE WHEN per_sales <0.5 THEN 'A'
            WHEN per_sales <0.8 THEN 'B'
            ELSE 'C' END CLASS
FROM view_sales)       
GROUP BY CLASS

商品退货分析

SELECT stockcode,
       COUNT(1) sales_times,
       SUM(CASE WHEN quantity < 0 THEN 1 ELSE 0 END) return_times,
       SUM(CASE WHEN quantity < 0 THEN 1 ELSE 0 END)/COUNT(1) return_rate
FROM NEW_ECOMMERCE
GROUP BY stockcode 
ORDER BY sales_times DESC      
SELECT
    to_char(invoicedate,'yyyy-mm') mon,
    SUM(CASE WHEN Quantity < 0 THEN Quantity*Unitprice ELSE 0 END) return_amount,
    SUM(CASE WHEN Quantity > 0 THEN Quantity*Unitprice ELSE 0 END) sales
FROM New_Ecommerce
GROUP BY to_char(invoicedate,'yyyy-mm') 

结合ABC分类进行分析,选取退货率大于均值且为A级的商品(主要是综合上文提及的ABC分类和退货率计算,通过创建view的形式进行联结后筛选,创建退货率视图为view_return_rate,ABC分类视图为view_class),这里筛选出64个商品。

SELECT vc.stockcode,sales,sales_times,return_times,return_rate
FROM view_class vc
JOIN view_return_rate vr
ON vc.stockcode = vr.stockcode
WHERE CLASS = 'A' AND return_rate > (SELECT AVG(return_rate) FROM view_return_rate)  
上一篇 下一篇

猜你喜欢

热点阅读