关注微信公共号:小程在线
关注CSDN博客:程志伟的博客
Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
Type "copyright", "credits" or "license" for more information.
IPython 7.12.0 -- An enhanced Interactive Python.
'''
1结论总结先行:
总结:
1-8月份运营效果较好,其中4、5、7、8月是非常好的,9月份开始运营的效果就越来越差,应该再进一步分析为什么会出现这个现象,还有复盘618与双十一的活动。
总指标:
总GMV约1.15亿元,7月8月的GMV上升非常大,8月达到峰值,然后就开始下降。
总的客单价:按客户数量为1240元/人;按订单数量为296元/单。
其他指标:
4月比3月新增用户多了差不多2倍,5月又比4月多了2.3倍,7月份比6月份增多了1.5倍,8月份与7月份持平,证明4、5、7、8月的拉新效果比较好。
复购率1-3月在上升,然后4月份下降到比1月份还低,进一步分析,4月份进行了拉新活动,较多新客当月只购买了一次(有可能是因为拉新活动启动比较晚,新客的复购周期还没到;也有可能这批新客在4月的购买满意度较低,应该着重分析这批客户是否有投诉),所以造成复购率下降。
回购人数在1-8月均上升,9月份开始快速下降,虽然回购人数前几个月在上升,但是整体回购率却是在下降,可见老客的回头率在不断下降,也就证明我们的产品留不住大部分的客户。
销售情况分析:
广东、上海、北京的销售额、销量以及客户数量都是最高的。
销售额与销量1-8月呈上升趋势,8月达到峰值,5、7、8月上升较大,这三个月的新客户都有增长,幅度也不少,证明拉新活动效果不错;9月销售额与销量和新客都开始下降,其中新客的下单量减少了四分之三,证明9月份的拉新活动效果非常差。同时发现618和双十一当天的销售情况非常差。
用户角度:
用户喜欢周六日进行购物,可以在周末多推送商品给用户,适当推销一两款要清仓的商品给用户;喜欢在早上6点至中午12点之间进行购物,也可以在该时间段推送商品给用户。
目前客户最多的是广东(21382),然后是上海(16031),北京(15928),其他8个城市比较平均(5400上下),根据2020年人口普查,广东拥有全国常住人口最多(达1.2亿人),客户仅占0.017%,最高客户占比是北京(0.0728%),约为广东的4倍,所以在广东加大投入拉新活动的性价比是最高的。
目前的客户男女各占一半,总体上在16-50岁之间平均分布。
前27%的用户贡献了80%的销售收入,且客户平均消费金额大于75%的分位数(存在高消费用户),这批用户要做好跟进,一定要留住这批贡献大的客户。
消费两次及以上的客户有50%消费周期为7天内,75%为26天内,消费周期较短。
产品角度:
得出了销量前10和销售额前10的产品,要时刻关注他们的库存量,避免发生缺货现象。
对于产品销量少于10的产品,可以考虑促销活动对其进行清仓处理。
最受欢迎的产品类别是smartphone-即手机,是第二名手提电脑的4倍。
手机销量前五分别为三星、苹果、小米、华为、OPPO,其中三星占了一半以上的份额,苹果约占据了四分之一;分析发现各年龄段和男性女性购买三星、苹果手机都是比较平均的,也发现广东、上海、北京占了50%以上的销量。
RFM模型分析:
重要的客户共有44129人
其中重要价值客户有20012人,约占重要客户的50%,对于重要价值客户,要给与他们VIP式的服务,时刻留意他们的购买反馈
重要发展客户有4415人,这类客户消费频率不够高,要想办法提高他们的消费频率,例如发放满减卷等
重要保持客户有11368人,这类客户最后一次购买时间距离现在已经很远了,应该发送信息,或者电话联系他们,也可以发放满减卷给他们,提高他们的复购率
重要挽留客户有8334人,要想办法挽回这批将近流失的客户,也可以通过短信召回,发放优惠券.
一般的客户共有48626人
对于一般价值、一般发展、一般保持的客户,在处理好重要客户的情况下,可以酌情去发展维系这批客户。
其中一般挽留用户有26843人,这类客户是要流失的,所以在没有多余资源的情况下,就放弃这批客户吧。
'''
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime
plt.rcParams['font.sans-serif'] = ['SimHei'] #设置中文字体为黑体
plt.rcParams['axes.unicode_minus'] = False #正常显示负号
pd.set_option('display.float_format',lambda x : '%.2f' % x)#pandas禁用科学计数法
#忽略警告
import warnings
warnings.filterwarnings('ignore')
'''
2字段介绍:
Unnamed: 行号
event_time:下单时间
order_id:订单编号
product_id:产品标号
category_id :类别编号
category_code :类别
brand :品牌
price :价格
user_id :用户编号
age :年龄
sex :性别
local:省份
'''
data = pd.read_csv(r'F:\Python\电子产品销售分析.csv',index_col=0,dtype={'category_id':'int64','user_id':'int64'})
data.head()
Out[2]:
event_time order_id ... sex local
0 2020-04-24 11:50:39 UTC 2294359932054536986 ... 女 海南
1 2020-04-24 11:50:39 UTC 2294359932054536986 ... 女 海南
2 2020-04-24 14:37:43 UTC 2294444024058086220 ... 女 北京
3 2020-04-24 14:37:43 UTC 2294444024058086220 ... 女 北京
4 2020-04-24 19:16:21 UTC 2294584263154074236 ... 女 广东
[5 rows x 11 columns]
####3创建新列-日期、月份、小时、周几
#创建日期列
data['date'] = data.event_time.apply(lambda x: x.split(' ')[0])
data['date'] = pd.to_datetime(data['date'])
#创建月份列
data['month'] = data.date.dt.month
#创建"小时"列
data['hour'] = data.event_time.apply(lambda x: x.split(' ')[1].split(':')[0])
#创建周几列---周日为0,周一为1
data['weekday'] = data.date.apply(lambda x:x.strftime("%w"))
#删除event_time列
del data['event_time']
data.head()
Out[9]:
order_id product_id ... hour weekday
0 2294359932054536986 1515966223509089906 ... 11 5
1 2294359932054536986 1515966223509089906 ... 11 5
2 2294444024058086220 2273948319057183658 ... 14 5
3 2294444024058086220 2273948319057183658 ... 14 5
4 2294584263154074236 2273948316817424439 ... 19 5
[5 rows x 14 columns]
####4查看数据缺失、重复情况
data.shape
Out[10]: (564169, 14)
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 564169 entries, 0 to 2633520
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 order_id 564169 non-null int64
1 product_id 564169 non-null int64
2 category_id 564169 non-null int64
3 category_code 434799 non-null object
4 brand 536945 non-null object
5 price 564169 non-null float64
6 user_id 564169 non-null int64
7 age 564169 non-null float64
8 sex 564169 non-null object
9 local 564169 non-null object
10 date 564169 non-null datetime64[ns]
11 month 564169 non-null int64
12 hour 564169 non-null object
13 weekday 564169 non-null object
dtypes: datetime64[ns](1), float64(2), int64(5), object(6)
memory usage: 64.6+ MB
'''
缺失数据有category_code-产品类别和brand-品牌这两列,对于category_code用"R"来代替缺失值而不是选择删除缺失值的数据
brand这一列数据缺失比较少,直接删除缺失值
'''
data['category_code'] = data['category_code'].fillna("R")
#删除brand这一列有缺失值的数据
data = data[data.brand.notnull()]
data.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 536945 entries, 0 to 2633520
Data columns (total 14 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 order_id 536945 non-null int64
1 product_id 536945 non-null int64
2 category_id 536945 non-null int64
3 category_code 536945 non-null object
4 brand 536945 non-null object
5 price 536945 non-null float64
6 user_id 536945 non-null int64
7 age 536945 non-null float64
8 sex 536945 non-null object
9 local 536945 non-null object
10 date 536945 non-null datetime64[ns]
11 month 536945 non-null int64
12 hour 536945 non-null object
13 weekday 536945 non-null object
dtypes: datetime64[ns](1), float64(2), int64(5), object(6)
memory usage: 61.4+ MB
####4.1存在重复值,但是换个角度去想,这些重复值就是同笔订单下了多个数量的订单,所以不删除重复值,进而增加一列购买数量的列和总价的列
data.duplicated().sum()
Out[15]: 634
#添加新的列:购买数量
data = data.value_counts().reset_index().rename(columns={0:'buy_cnt'})
Traceback (most recent call last):
File "<ipython-input-16-c9e31d7feae0>", line 1, in <module>
data = data.value_counts().reset_index().rename(columns={0:'buy_cnt'})
File "E:\anaconda3\lib\site-packages\pandas\core\generic.py", line 5274, in __getattr__
return object.__getattribute__(self, name)
AttributeError: 'DataFrame' object has no attribute 'value_counts'
解决方法:
df = data.groupby(['order_id','product_id']).agg(buy_cnt=('user_id','count'))
data = pd.merge(data,df,on=['order_id','product_id'],how='inner')
data = data.drop_duplicates().reset_index(drop=True)
#添加新的列:购买总金额
data['amount'] = data['price'] * data['buy_cnt']
####5查看数据是否有异常
#5.1把几个id的格式转化为object格式
data.order_id = data.order_id.astype('object')
data.product_id = data.product_id.astype('object')
data.category_id = data.category_id.astype('object')
data.user_id = data.user_id.astype('object')
#5.2把hour和weekday转化为int
data['hour'] = data.loc[:,'hour'].astype('int')
data['weekday'] = data.loc[:,'weekday'].astype('int')
data.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 536311 entries, 0 to 536310
Data columns (total 16 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 order_id 536311 non-null object
1 product_id 536311 non-null object
2 category_id 536311 non-null object
3 category_code 536311 non-null object
4 brand 536311 non-null object
5 price 536311 non-null float64
6 user_id 536311 non-null object
7 age 536311 non-null float64
8 sex 536311 non-null object
9 local 536311 non-null object
10 date 536311 non-null datetime64[ns]
11 month 536311 non-null int64
12 hour 536311 non-null int32
13 weekday 536311 non-null int32
14 buy_cnt 536311 non-null int64
15 amount 536311 non-null float64
dtypes: datetime64[ns](1), float64(3), int32(2), int64(2), object(8)
memory usage: 61.4+ MB
#5.3查看价格和年龄是否存在异常值
#以上7个字段均没有异常值
#price和amount最小值为0,这类商品应该就是免费类的商品,所以也不属于异常值。
#应该进一步分析,购买了0元商品的用户,后续是否还有购买了其他的商品
data.describe(percentiles=[0.01,0.25,0.75,0.99]).T
Out[22]:
count mean std min 1% 25% 50% 75% 99% max
price 536311.00 214.54 305.98 0.00 1.13 24.51 99.51 289.33 1387.01 11574.05
age 536311.00 33.18 10.12 16.00 16.00 24.00 33.00 42.00 50.00 50.00
month 536311.00 7.72 2.56 1.00 1.00 6.00 8.00 10.00 11.00 11.00
hour 536311.00 9.52 4.21 0.00 1.00 6.00 9.00 12.00 22.00 23.00
weekday 536311.00 3.03 2.04 0.00 0.00 1.00 3.00 5.00 6.00 6.00
buy_cnt 536311.00 1.00 0.04 1.00 1.00 1.00 1.00 1.00 1.00 4.00
amount 536311.00 214.73 306.48 0.00 1.13 24.98 99.51 289.33 1387.01 11574.05
#5.4检查其他字段是否有异常值
data.describe(include='all').T
Out[23]:
count unique top ... 50% 75% max
order_id 536311.00 389511.00 2388440981134689792.00 ... NaN NaN NaN
product_id 536311.00 19078.00 1515966223517847040.00 ... NaN NaN NaN
category_id 536311.00 786.00 2268105428166508800.00 ... NaN NaN NaN
category_code 536311 124 R ... NaN NaN NaN
brand 536311 868 samsung ... NaN NaN NaN
price 536311.00 NaN NaN ... 99.51 289.33 11574.05
user_id 536311.00 92769.00 1515915625512422912.00 ... NaN NaN NaN
age 536311.00 NaN NaN ... 33.00 42.00 50.00
sex 536311 2 男 ... NaN NaN NaN
local 536311 11 广东 ... NaN NaN NaN
date 536311 323 2020-10-22 00:00:00 ... NaN NaN NaN
month 536311.00 NaN NaN ... 8.00 10.00 11.00
hour 536311.00 NaN NaN ... 9.00 12.00 23.00
weekday 536311.00 NaN NaN ... 3.00 5.00 6.00
buy_cnt 536311.00 NaN NaN ... 1.00 1.00 4.00
amount 536311.00 NaN NaN ... 99.51 289.33 11574.05
[16 rows x 13 columns]
#5.4.1发现date日期有异常值,显示为1970-01-01,把这些异常值删除
data = data[data.date>'1970-01-01']
data.date.min()
Out[25]: Timestamp('2020-01-05 00:00:00')