利用python分析电商_Python电商数据清洗及分析

一、数据来源

本文使用python来分析一份电商数据,源数据可在下方评论获取。

二、分析思路

bcb61ad9ff71

image

三、分析过程

3.1 读取数据

首先导入后续分析需要的第三方库及一些常用设置

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

# 设置风格

sns.set(style='white', font_scale=1.2)

%matplotlib inline

plt.rcParams["font.sans-serif"] = "SimHei"

plt.rcParams['axes.titlesize'] = 20

plt.rcParams['axes.unicode_minus']=False

import warnings

warnings.filterwarnings("ignore")

通过pandas库读取数据

filename = "./电商数据源.csv"

data = pd.read_csv(filename,encoding="gbk")

data.head()

bcb61ad9ff71

image

从读取结果可以看到数据源包含24个字段,每个字段的含义如下:

3.2 数据清洗

数据清洗阶段主要处理不符合业务逻辑的异常值,还有缺失值和重复值。

3.2.1 清洗发货日期早于下单日期的异常值

# 根据业务需要提取数据,发货日期早于下单日期

# 1)转换时间类型

data["OrderDate"] = pd.to_datetime(data["OrderDate"])

data["ShipDate"] = pd.to_datetime(data["ShipDate"])

# 2)计算时间差

data["interval"] = (data["ShipDate"]-data["OrderDate"]).dt.total_seconds()

# 3)找时间差为负的数据并删除

data.drop(index=data[data["interval"]<0].index,axis=0,inplace=True)

print(data.shape)

采用如下代码查看数据,建立对数据的基本认识

# 查看行列数量

data.shape

# 数据整体描述

data.describe()

# 数据信息

data.info()

# 统计NAN数据

data.isna().sum()

bcb61ad9ff71

image

可以看到ShipMode(发货模式)和PostalCode(邮编)两列存在缺失值。

3.2.2 清洗RowID重复值

# 重复值

print(data["RowID"].unique().size)

data[data["RowID"].duplicated()]

data.drop(index=data[data["RowID"].duplicated()].index,axis=0,inplace=True)

print(data.shape)

3.2.3 处理ShipMode缺失值

data[data["ShipMode"].isnull()]

data["ShipMode"].unique()

# 众数填充缺失值

# data["ShipMode"].mode()

data["ShipMode"].fillna(data["ShipMode"].mode()[0],inplace=True)

3.2.4 清洗Discount的异常值和缺失值

data[data["Discount"]>1]

data[data["Discount"]<0]

data["Discount"] = data["Discount"].mask(data["Discount"]>1,None)

# 处理缺失值

data["Discount"].isna().sum()

# 平均折扣

meanDiscount = data["Discount"].mean()

# data[data["Discount"].notnull()]["Discount"].sum()/data[data["Discount"].notnull()]["Discount"].size

data["Discount"].fillna(meanDiscount,inplace=True)

3.2.5 删除PostalCode列

邮编对分析意义不大,这里直接删除

data.drop(columns=["PostalCode"],inplace=True)

3.2.6 将订单日期拆分为年、月、季度

data["Order-year"] = data["OrderDate"].dt.year

data["Order-month"] = data["OrderDate"].dt.month

data["quarter"] = data["OrderDate"].dt.to_period('Q')

data[["OrderDate","Order-year","Order-month","quarter"]].sample(5)

bcb61ad9ff71

image

3.3 数据分析

3.3.1 销售额与增长率

sales_year = data.groupby(by='Order-year')['Sales'].sum()

# print(sales_year)

sales_rate_12 = sales_year[2012] / sales_year[2011] - 1

sales_rate_13 = sales_year[2013] / sales_year[2012] - 1

sales_rate_14 = sales_year[2014] / sales_year[2013] - 1

# print(sales_rate_12,sales_rate_13,sales_rate_14)

sales_rate_12_label = "%.2f%%" % (sales_rate_12 * 100)

sales_rate_13_label = "%.2f%%" % (sales_rate_13 * 100)

sales_rate_14_label = "%.2f%%" % (sales_rate_14 * 100)

# print(sales_rate_12,sales_rate_13,sales_rate_14)

sales_rate = pd.DataFrame(

{'sales_all':sales_year,

'sales_rate':[0,sales_rate_12,sales_rate_13,sales_rate_14],

'sales_rate_label':['0.00%',sales_rate_12_label,sales_rate_13_label,sales_rate_14_label]

})

# print(sales_rate)

sales_rate = pd.DataFrame(

{'sales_all':sales_year,

'sales_rate':[0,sales_rate_12,sales_rate_13,sales_rate_14]

})

y1 = sales_rate['sales_all']

y2 = sales_rate['sales_rate']

x = [str(value) for value in sales_rate.index.tolist()]

# 新建figure对象

fig=plt.figure(figsize=(10,6))

# 新建子图1

ax1=fig.add_subplot(1,1,1)

# ax2与ax1共享X轴

ax2 = ax1.twinx()

ax1.bar(x,y1,color = 'dodgerblue')

ax2.plot(x,y2,marker='o',color = 'r')

ax1.set_xlabel('年份')

ax1.set_ylabel('销售额')

ax2.set_ylabel('增长率')

ax1.set_title('销售额与增长率')

bcb61ad9ff71

image

3.3.2 地区分析

sales_area = data.groupby(by="Market")["Sales"].sum()

# sales_area

pie_labels = sales_area.index.to_list()

f, ax = plt.subplots(figsize=(10,10))

pie_sales_area = plt.pie(sales_area,labels=pie_labels,autopct="%.1f%%",startangle=90)

plt.title('2011-2014年总销售额占比')

bcb61ad9ff71

image

# 各地区每一年的销售额

sales_area = data.groupby(by=["Market","Order-year"])["Sales"].sum()

# 将多层索引设置为列,level这个参数的意思是要把哪些索引设置为列

sales_area = sales_area.reset_index(level=[0,1])

# pd.pivot_table(data=sales_area,values="Sales",index="Market",columns="Order-year",aggfunc="sum")

# 绘制柱形图

fig = plt.figure(figsize=(10,6))

sns.barplot(x="Market",y="Sales",hue="Order-year",data=sales_area,estimator=np.sum)

plt.title('2011-2014年不同地区销售额对比')

bcb61ad9ff71

image

# 各地区不同产品的销售额

sales_area = data.groupby(by=["Market","Category"])["Sales"].sum()

# 将多层索引设置为列,level这个参数的意思是要把哪些索引设置为列

sales_area = sales_area.reset_index(level=[0,1])

# pd.pivot_table(data=sales_area,values="Sales",index="Market",columns="Order-year",aggfunc="sum")

# 绘制柱形图

fig = plt.figure(figsize=(10,6))

sns.barplot(x="Market",y="Sales",hue="Category",data=sales_area,estimator=np.sum)

plt.title('不同产品类型在不同地区的销售额对比')

bcb61ad9ff71

image

3.3.3 销售淡旺季分析

sales_year_month = data.groupby(by=["Order-year","Order-month"])["Sales"].sum()

# 将多层索引设置为列,level这个参数的意思是要把哪些索引设置为列

sales_year_month = sales_year_month.reset_index(level=[0,1])

# 绘制折线图

fig = plt.figure(figsize=(10,6))

sns.lineplot(x="Order-month",y="Sales",hue="Order-year",data=sales_year_month,estimator=np.sum)

plt.title('2011-2014年不同月份销售额对比')

bcb61ad9ff71

image

3.3.4 每月新增用户

data_customer = data.copy()

data_customer = data_customer.drop_duplicates(subset=["CustomerID"])

new_customer = data_customer.groupby(["Order-year","Order-month"]).size()

new_customer = new_customer.reset_index(level=[0,1])

new_customer.columns = ["Order-year","Order-month","count"]

new_customer = pd.pivot_table(data=new_customer,values="count",index="Order-month",columns="Order-year",fill_value=0)

new_customer

bcb61ad9ff71

image

3.3.5 用户RFM模型

首先计算用户的R、F和M值,然后根据均值算法或评分制算法来对用户分类,均值算法就是直接与各自的平均值比较,高于平均值即为高,低于平均值即为低;评分制算法就是对R、F和M制定相应的打分规则,一般采用5分制,计算得到R、F和M相应的得分,最后与得分的平均值进行比较。

# 获取2014年数据

data_14 = data [data ['Order-year']==2014]

data_14 = data_14[['CustomerID','OrderDate','Sales']]

# print(data_14.shape)

customdf = data_14.copy()

customdf.set_index('CustomerID',drop=True,inplace=True)

customdf['orders'] = 1

customdf

rfmdf = customdf.pivot_table(index=['CustomerID'],

values=['OrderDate','orders','Sales'],

aggfunc={'OrderDate':'max',

'orders':'sum',

'Sales':'sum'})

rfmdf['R'] = (rfmdf["OrderDate"].max()-rfmdf["OrderDate"]).dt.days

rfmdf.rename(columns={'Sales':'M','orders':'F'},inplace=True)

rfmdf

1)均值算法

def rfm_func(x):

level = x.apply(lambda x: "1" if x >= 0 else '0')

label = level.R + level.F + level.M

d = {

'011':'重要价值客户',

'111':'重要唤回客户',

'001':'重要深耕客户',

'101':'重要挽留客户',

'010':'潜力客户',

'110':'一般维持客户',

'000':'新客户',

'100':'流失客户'

}

result = d[label]

return result

rfmdf['label'] = rfmdf[['R','F','M']].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)

rfmdf

result = rfmdf.groupby('label')["OrderDate"].count()

result = result.reset_index()

result.columns = ["label","count"]

result

# 绘制柱形图

fig = plt.figure(figsize=(10,6))

order = ['重要价值客户', '重要唤回客户', '重要深耕客户', '重要挽留客户', '潜力客户', '一般维持客户', '新客户', '流失客户']

sns.barplot(x="count",y="label",data=result,orient='h',order=order)

plt.title('RFM用户数')

bcb61ad9ff71

image

2)RFM模型除了使用上面的均值算法,还可以使用评分制算法来实现,评分一般采用5分制,评分规则也要根据具体的业务情况来决定,这里我们采用五分位数来制定评分规则,python实现如下:

rfm_score_df = rfmdf[['R','F',"M"]]

# 修改describe区间范围,得到五分位数

rfm_score_df.describe(percentiles=[0.2,0.4,0.6,0.8])

bcb61ad9ff71

image.png

计算R、F和M的评分

# 区间( ],所以第一个设置为最小值-1

section_list_R = [-1,9,24,43,103,362]

grade_R = pd.cut(rfm_score_df['R'],bins=section_list_R,labels=[5,4,3,2,1])

rfm_score_df['R_S'] = grade_R.values.astype(int)

# 区间( ],所以第一个设置为最小值-1

section_list_F = [0,4,7,13,19,48]

grade_F = pd.cut(rfm_score_df['F'],bins=section_list_F,labels=[1,2,3,4,5])

rfm_score_df['F_S'] = grade_F.values.astype(int)

# 区间( ],所以第一个设置为最小值-1

section_list_M = [0,365,1196,2855,4938,23296]

grade_M = pd.cut(rfm_score_df['M'],bins=section_list_M,labels=[1,2,3,4,5])

# 上一步的cut方法返回值是category类型,不能用户后续计算,这里要转为数值类型

rfm_score_df['M_S'] = grade_M.values.astype(int)

rfm_score_df

bcb61ad9ff71

image.png

用户的R、F和M分值与平均分比较

def rfm_func(x):

level = x.apply(lambda x: "1" if x >= 0 else '0')

level

label = level.R_S + level.F_S + level.M_S

d = {

'111':'重要价值客户',

'011':'重要唤回客户',

'101':'重要深耕客户',

'001':'重要挽留客户',

'110':'潜力客户',

'010':'一般维持客户',

'100':'新客户',

'000':'流失客户'

}

result = d[label]

return result

rfm_score_df["label"] = rfm_score_df[["R_S","F_S","M_S"]].apply(lambda x:x-x.mean()).apply(rfm_func,axis=1)

rfm_score_df

bcb61ad9ff71

image.png

result = rfm_score_df.groupby('label')["R"].count()

result = result.reset_index()

result.columns = ["label","count"]

result

# 绘制柱形图

fig = plt.figure(figsize=(10,6))

order = ['重要价值客户', '重要唤回客户', '重要深耕客户', '重要挽留客户', '潜力客户', '一般维持客户', '新客户', '流失客户']

sns.barplot(x="count",y="label",data=result,orient='h',order=order)

plt.title('RFM用户数')

bcb61ad9ff71

image.png

从均值算法和评分制算法的结果可以看出,两种方法存在一定差异,具体使用哪种算法要根据实际业务情况决定。比如评分制算法中的R打分可以根据7日留存,30日留存,90日留存等来制定。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值