项目背景
本数据报告以某电子产品销售数据为数据集。以店铺和用户的角度进行探索式分析,从而了解在线销售业务的消费情况以及用户的消费行为,最终提出店铺销售建议。
数据清洗
#导入第三方库
import pandas as pd
import numpy as np
import os
from datetime import datetime
import matplotlib.pyplot as plt
import seaborn as sns
#导入数据
df = pd.read_csv(r"D:\数据分析项目\电子产品销售\电子产品销售分析.csv")
df.head()
Unnamed: 0 | event_time | order_id | product_id | category_id | category_code | brand | price | user_id | age | sex | local | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 2020-04-24 11:50:39 UTC | 2294359932054536986 | 1515966223509089906 | 2.268105e+18 | electronics.tablet | samsung | 162.01 | 1.515916e+18 | 24.0 | 女 | 海南 |
1 | 1 | 2020-04-24 11:50:39 UTC | 2294359932054536986 | 1515966223509089906 | 2.268105e+18 | electronics.tablet | samsung | 162.01 | 1.515916e+18 | 24.0 | 女 | 海南 |
2 | 2 | 2020-04-24 14:37:43 UTC | 2294444024058086220 | 2273948319057183658 | 2.268105e+18 | electronics.audio.headphone | huawei | 77.52 | 1.515916e+18 | 38.0 | 女 | 北京 |
3 | 3 | 2020-04-24 14:37:43 UTC | 2294444024058086220 | 2273948319057183658 | 2.268105e+18 | electronics.audio.headphone | huawei | 77.52 | 1.515916e+18 | 38.0 | 女 | 北京 |
4 | 4 | 2020-04-24 19:16:21 UTC | 2294584263154074236 | 2273948316817424439 | 2.268105e+18 | NaN | karcher | 217.57 | 1.515916e+18 | 32.0 | 女 | 广东 |
选择子集
第一列为数据编号,已有索引故删除
df.drop(["Unnamed: 0"],axis=1,inplace= True)
df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 564169 entries, 0 to 564168
Data columns (total 11 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 event_time 564169 non-null object
1 order_id 564169 non-null int64
2 product_id 564169 non-null int64
3 category_id 564169 non-null float64
4 category_code 434799 non-null object
5 brand 536945 non-null object
6 price 564169 non-null float64
7 user_id 564169 non-null float64
8 age 564169 non-null float64
9 sex 564169 non-null object
10 local 564169 non-null object
dtypes: float64(4), int64(2), object(5)
memory usage: 47.3+ MB
标准化处理
df.dtypes
event_time object
order_id int64
product_id int64
category_id float64
category_code object
brand object
price float64
user_id float64
age float64
sex object
local object
dtype: object
#数据类型转化
df['event_time'] = pd.to_datetime(df['event_time'].str[:19],format="%Y-%m-%d %H:%M:%S")
#计算时间变量
df['Month'] = df['event_time'].dt.month
df['Day'] = df['event_time'].dt.day
df['Dayofweek']=df['event_time'].dt.dayofweek
df['hour'] = df['event_time'].dt.hour
df.head()
event_time | order_id | product_id | category_id | category_code | brand | price | user_id | age | sex | local | Month | Day | Dayofweek | hour | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2020-04-24 11:50:39 | 2294359932054536986 | 1515966223509089906 | 2.268105e+18 | electronics.tablet | samsung | 162.01 | 1.515916e+18 | 24.0 | 女 | 海南 | 4 | 24 | 4 | 11 |
1 | 2020-04-24 11:50:39 | 2294359932054536986 | 1515966223509089906 | 2.268105e+18 | electronics.tablet | samsung | 162.01 | 1.515916e+18 | 24.0 | 女 | 海南 | 4 | 24 | 4 | 11 |
2 | 2020-04-24 14:37:43 | 2294444024058086220 | 2273948319057183658 | 2.268105e+18 | electronics.audio.headphone | huawei | 77.52 | 1.515916e+18 | 38.0 | 女 | 北京 | 4 | 24 | 4 | 14 |
3 | 2020-04-24 14:37:43 | 2294444024058086220 | 2273948319057183658 | 2.268105e+18 | electronics.audio.headphone | huawei | 77.52 | 1.515916e+18 | 38.0 | 女 | 北京 | 4 | 24 | 4 | 14 |
4 | 2020-04-24 19:16:21 | 2294584263154074236 | 2273948316817424439 | 2.268105e+18 | NaN | karcher | 217.57 | 1.515916e+18 | 32.0 | 女 | 广东 | 4 | 24 | 4 | 19 |
缺失值和重复值处理
#查看缺失值
df.isnull().sum()
event_time 0
order_id 0
product_id 0
category_id 0
category_code 129370
brand 27224
price 0
user_id 0
age 0
sex 0
local 0
Month 0
Day 0
Dayofweek 0
hour 0
dtype: int64
#有两列中有数据缺失值,类别列缺失129370条,品牌列缺失27224条,这两列数值缺失对店铺销售情况的分析和用户消费行为的分析没主要影响,
#但是其他数据有重要影响,所以这两列缺失值由missing填充。
df.fillna('missing',inplace=True)
df.isnull().sum()
#缺失值已全部填充
event_time 0
order_id 0
product_id 0
category_id 0
category_code 0
brand 0
price 0
user_id 0
age 0
sex 0
local 0
Month 0
Day 0
Dayofweek 0
hour 0
dtype: int64
#重复值检查和处理
df.duplicated()
df.drop_duplicates()
event_time | order_id | product_id | category_id | category_code | brand | price | user_id | age | sex | local | Month | Day | Dayofweek | hour | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 2020-04-24 11:50:39 | 2294359932054536986 | 1515966223509089906 | 2.268105e+18 | electronics.tablet | samsung | 162.01 | 1.515916e+18 | 24.0 | 女 | 海南 | 4 | 24 | 4 | 11 |
2 | 2020-04-24 14:37:43 | 2294444024058086220 | 2273948319057183658 | 2.268105e+18 | electronics.audio.headphone | huawei | 77.52 | 1.515916e+18 | 38.0 | 女 | 北京 | 4 | 24 | 4 | 14 |
4 | 2020-04-24 19:16:21 | 2294584263154074236 | 2273948316817424439 | 2.268105e+18 | missing | karcher | 217.57 | 1.515916e+18 | 32.0 | 女 | 广东 | 4 | 24 | 4 | 19 |
5 | 2020-04-26 08:45:57 | 2295716521449619559 | 1515966223509261697 | 2.268105e+18 | furniture.kitchen.table | maestro | 39.33 | 1.515916e+18 | 20.0 | 男 | 重庆 | 4 | 26 | 6 | 8 |
6 | 2020-04-26 09:33:47 | 2295740594749702229 | 1515966223509104892 | 2.268105e+18 | electronics.smartphone | apple | 1387.01 | 1.515916e+18 | 21.0 | 男 | 北京 | 4 | 26 | 6 | 9 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
564164 | 2020-11-21 10:10:01 | 2388440981134693942 | 1515966223526602848 | 2.268105e+18 | electronics.smartphone | oppo | 138.87 | 1.515916e+18 | 21.0 | 男 | 上海 | 11 | 21 | 5 | 10 |
564165 | 2020-11-21 10:10:13 | 2388440981134693943 | 1515966223509089282 | 2.268105e+18 | electronics.smartphone | apple | 418.96 | 1.515916e+18 | 21.0 | 女 | 北京 | 11 | 21 | 5 | 10 |
564166 | 2020-11-21 10:10:30 | 2388440981134693944 | 1515966223509089917 | 2.268105e+18 | appliances.personal.scales | vitek | 12.48 | 1.515916e+18 | 19.0 | 女 | 上海 | 11 | 21 | 5 | 10 |
564167 | 2020-11-21 10:10:30 | 2388440981134693944 | 2273948184839454837 | 2.268105e+18 | missing | moulinex | 41.64 | 1.515916e+18 | 19.0 | 女 | 上海 | 11 | 21 | 5 | 10 |
564168 | 2020-11-21 10:10:30 | 2388440981134693944 | 1515966223509127566 | 2.268105e+18 | appliances.kitchen.blender | redmond | 53.22 | 1.515916e+18 | 19.0 | 女 | 上海 | 11 | 21 | 5 | 10 |
563495 rows × 15 columns
分析内容
店铺销售情况分析
df[df['price'] == 0].count()
event_time 39
order_id 39
product_id 39
category_id 39
category_code 39
brand 39
price 39
user_id 39
age 39
sex 39
local 39
Month 39
Day 39
Dayofweek 39
hour 39
dtype: int64
未完成支付的订单只有39单,对比完成支付订单可忽略不计,因此不做未完成订单数、订单金额的统计。
每月成交金额
# 去除警告日志提醒的显示
from pandas.plotting import register_matplotlib_converters
register_matplotlib_converters()
#解决中文乱码等显示问题
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
%config InlineBackend.figure_format = 'svg'
def store_plot(data,xlab,ylab,title):
plt.figure(figsize=(10,5))
plt.plot(data)
plt.xlabel(xlab)
plt.ylabel(ylab)
plt.title(title)
#每月成交金额,包含未成单金额
store_plot(data=df[df['price']>0].groupby('Month')['price'].sum()
,xlab='月份'
,ylab='成交金额'
,title='每月成交金额')
每月销售金额
store_plot(data=df.groupby('Month')['price'].sum()
,xlab = '月份'
,ylab = '销售金额'
,title = '每月销售金额')
每月消费人数
store_plot(data = df[df['price']>0].groupby('Month')['user_id'].nunique()
,xlab = '月份'
,ylab = '消费人数'
,title = '每月消费人数')
每月订单数量
store_plot(data=df[df['price']>0].groupby('Month')['order_id'].nunique()
,xlab = ('月份')
,ylab = ('订单数量')
,title = ('每月订单数量'))
每月客单价
store_plot(data = df[df['price']>0].groupby('Month')['price'].sum()/df[df['price']>0].groupby('Month')['user_id'].nunique()
,xlab = '月份'
,ylab = '客单价'
,title = '每月客单价')
1、销售金额和成交金额曲线很相似,销售金额约等于成交金额。
2、月订单数量、月消费人数、月成交金额、月销售额、月客单价趋势相似,销售情况最好的月份集中在7-10月份。店铺可以在1-4月份减少营业人员,5-11月增加营业人员,应对销售高峰期。
3、店铺销售高峰估计和五一小长假、暑假、开学季、十一小长假有关,店铺应该在这几个关键的节点,提前布局,打造竞品,加大库存量,保证货源充足。
不同省份用户数量
plt.figure(figsize=(12,8))
df[df['price']>0].groupby('local')['user_id'].nunique().sort_values(ascending=True).plot.barh()
plt.xlabel('用户数量')
plt.ylabel('省份')
plt.title('不同省份用户数量')
Text(0.5, 1.0, '不同省份用户数量')
不同省份订单数量
plt.figure(figsize=(12,8))
df[df['price']>0].groupby('local')['order_id'].nunique().sort_values(ascending=True).plot.barh()
plt.xlabel('订单数量')
plt.ylabel('省份')
plt.title('不同省份订单数量')
Text(0.5, 1.0, '不同省份订单数量')
不同省份成交金额
plt.figure(figsize=(12,8))
df[df['price']>0].groupby('local')['price'].sum().sort_values(ascending=True).plot.barh()
plt.xlabel('成交金额')
plt.ylabel('省份')
plt.title('不同省份成交金额')
Text(0.5, 1.0, '不同省份成交金额')
1、北上广的用户数量、订单数量、成交金额都稳居前三。
2、湖南的客户数量虽然少,但是订单数,客单价仅次于北上广,湖南客户的潜力巨大,需要加大宣传,增加客户数量。
下单日分布
plt.figure(figsize=(12,8))
df[df['price']>0].groupby('Dayofweek')['order_id'].nunique().plot.bar()
plt.xticks(range(7),['周一','周二','周三','周四','周五','周六','周日'],rotation=0)
plt.xlabel('星期')
plt.ylabel('订单数')
plt.title('下单日分布')
Text(0.5, 1.0, '下单日分布')
周一到周五订单数差别不大,周六是订单数量最高,周日次之,用户消费行为主要集中在周末。
下单时间分布
plt.figure(figsize=(12,8))
df[df['price']>0].groupby('hour')['order_id'].nunique().plot()
plt.xlabel('小时')
plt.ylabel('订单数')
plt.title('下单时间分布')
Text(0.5, 1.0, '下单时间分布')
订单集中在早晨,8点到13点是消费高峰期,这段时间要注意维持好网站的稳定性。
用户消费行为分析
用户消费次数、用户消费金额
df[df['price']>0].groupby('user_id').agg({'order_id':'nunique',
'price':'sum'}).describe()
order_id | price | |
---|---|---|
count | 93818.000000 | 93818.000000 |
mean | 4.269074 | 1252.415276 |
std | 18.191671 | 4205.922011 |
min | 1.000000 | 0.020000 |
25% | 1.000000 | 145.680000 |
50% | 2.000000 | 460.580000 |
75% | 3.000000 | 1152.570000 |
max | 666.000000 | 165439.030000 |
1、超过一半的用户消费了两次,甚至有用户消费了666次,可能是批发转卖。
2、客户平均消费金额是1252.4,标准差是4205.9,用户平均消费金额大于75分位数,存在高额消费用户,需要注意。
用户消费周期
purchase_time = df[df['price']>0].groupby('user_id').apply(lambda x: x['event_time']-x['event_time'].shift()).dt.days
purchase_time.describe()
count 470312.000000
mean 9.665354
std 377.617753
min -18452.000000
25% 0.000000
50% 0.000000
75% 1.000000
max 18557.000000
Name: event_time, dtype: float64
purchase_time[purchase_time>0].describe()
count 125636.000000
mean 46.194204
std 638.377648
min 1.000000
25% 3.000000
50% 9.000000
75% 30.000000
max 18557.000000
Name: event_time, dtype: float64
至少消费两次的用户有一半是9天,75%的消费者消费金额在一个月,可以在8天、29天两个时间点对用户进行推送和提醒
消费人群分层情况
按性别分析
df_sex = df['sex'].value_counts()
plt.figure(figsize=(8,8))
plt.pie(df_sex.values,labels=df_sex.index,autopct='%.2f%%',
wedgeprops={'linewidth':0.5,'edgecolor':'green'},
textprops={'fontsize':30,'color':'#003371'}
)
plt.title('男女占比',size=30)
plt.show()
购买人群男女占比几乎是1:1的情况
按年龄段分析
df['age'].describe()
count 564130.000000
mean 33.184326
std 10.122218
min 16.000000
25% 24.000000
50% 33.000000
75% 42.000000
max 50.000000
Name: age, dtype: float64
bins = [10,20,30,40,50]
df['age_box'] = pd.cut(df['age'],bins,labels = ['10-20','20-30','30-40','40-50'])
age_box = df['age_box'].value_counts()
age_box
40-50 169576
20-30 159765
30-40 156569
10-20 78259
Name: age_box, dtype: int64
plt.figure(figsize=(10,6))
plt.bar(list(age_box.index)
,list(age_box.values)
,color = '#cb3a56')
plt.xlabel('购买数量',size=22)
plt.ylabel('年龄分段',size=22)
plt.xticks(size=18)
plt.yticks(size=18)
plt.title('不同年龄分段的购买情况',size=25)
plt.show()
40-50岁的人群是购买主力,20-20岁,30-40岁的购买情况差距不大,10-20岁最少,主要和人群的购买力有关。
df.groupby('age_box')['sex'].value_counts()
age_box sex
10-20 女 39858
男 38399
20-30 女 80159
男 79597
30-40 男 81535
女 75015
40-50 男 84863
女 84704
Name: sex, dtype: int64
df.groupby('sex').describe()['price']
count | mean | std | min | 25% | 50% | 75% | max | |
---|---|---|---|---|---|---|---|---|
sex | ||||||||
女 | 279736.0 | 208.584584 | 301.572274 | 0.02 | 23.13 | 90.02 | 277.75 | 9606.48 |
男 | 284394.0 | 207.987789 | 307.481479 | 0.02 | 23.13 | 87.01 | 277.75 | 18328.68 |
男性对高价格的产品的消费能力远超女性
df.groupby('age_box').describe()['price']
count | mean | std | min | 25% | 50% | 75% | max | |
---|---|---|---|---|---|---|---|---|
age_box | ||||||||
10-20 | 78257.0 | 208.859315 | 300.837290 | 0.02 | 23.13 | 92.57 | 277.75 | 7407.38 |
20-30 | 159756.0 | 210.700155 | 306.956375 | 0.02 | 23.13 | 92.34 | 277.75 | 9606.48 |
30-40 | 156550.0 | 209.136216 | 303.147523 | 0.02 | 23.13 | 92.34 | 277.75 | 11574.05 |
40-50 | 169567.0 | 204.954410 | 305.293435 | 0.02 | 21.50 | 81.00 | 277.75 | 18328.68 |
不同年龄段人群在购买价格的75分位上基本一致,但是34-40岁,40-50岁的人群对高价格产品的购买力更强
按喜好品牌分析
df_brand = df['brand'].value_counts().head(12)
plt.figure(figsize=(10,6))
plt.bar(df_brand.index
,df_brand.values
,color='#c83c23')
plt.xticks(size=16,rotation=30)
plt.yticks(size=16)
plt.xlabel("品牌名称",size=18)
plt.ylabel("购买数量",size=18)
plt.title('品牌名称与购买数量')
plt.show()
大家最喜欢的品牌是samsung、apple、ava。由于部分手机品牌信息缺失用missing代替,missing可能包含很多品牌。所以最喜欢的品牌忽略missing.
df['price'].quantile([0,0.25,0.5,0.75,1]).tolist()
[0.02, 23.13, 87.94, 277.75, 18328.68]
df['price_box'] = pd.cut(df['price'],bins=df['price'].quantile([0,0.25,0.5,0.75,1]).tolist()
,labels = ['0.02-23.13','23.13-87.94','87.94-277.75','277.75-18328.68'])
df['price_box'].value_counts()
0.02-23.13 148200
87.94-277.75 142358
277.75-18328.68 139399
23.13-87.94 134173
Name: price_box, dtype: int64
df.groupby('brand').describe()['price']
count | mean | std | min | 25% | 50% | 75% | max | |
---|---|---|---|---|---|---|---|---|
brand | ||||||||
a-case | 295.0 | 3.171492 | 2.039888e+00 | 0.23 | 2.7500 | 3.450 | 4.6100 | 11.55 |
acana | 3.0 | 66.266667 | 5.594992e+01 | 23.59 | 34.5950 | 45.600 | 87.6050 | 129.61 |
accesstyle | 62.0 | 30.443548 | 2.061239e+00 | 23.13 | 30.0700 | 30.070 | 30.0700 | 34.70 |
action | 3.0 | 25.440000 | 0.000000e+00 | 25.44 | 25.4400 | 25.440 | 25.4400 | 25.44 |
activision | 17.0 | 68.058235 | 5.614700e+00 | 46.27 | 69.4200 | 69.420 | 69.4200 | 69.42 |
... | ... | ... | ... | ... | ... | ... | ... | ... |
zhorka | 18.0 | 1.336667 | 2.155158e-01 | 0.93 | 1.2950 | 1.340 | 1.4750 | 1.85 |
zlatek | 2.0 | 53.215000 | 9.821713e+00 | 46.27 | 49.7425 | 53.215 | 56.6875 | 60.16 |
zowie | 240.0 | 82.149958 | 2.055098e+01 | 34.70 | 61.3200 | 85.630 | 99.5100 | 146.50 |
zugo | 23.0 | 27.780000 | 1.453024e-14 | 27.78 | 27.7800 | 27.780 | 27.7800 | 27.78 |
zwilling | 121.0 | 88.072975 | 8.380753e+01 | 7.38 | 28.4500 | 62.480 | 108.7700 | 532.38 |
869 rows × 8 columns
df.groupby('order_id')['price'].sum().describe()
count 400538.000000
mean 293.353181
std 397.066671
min 0.000000
25% 41.640000
50% 148.225000
75% 393.500000
max 18699.030000
Name: price, dtype: float64
75%的人群的购买价格是393.5,说明75%的人群购买力低,后25%的人群对高价格产品的购买力强。
结论
1、月订单数量、月消费人数、月成交金额、月销售额、月客单价趋势相似,销售情况最好的月份集中在7-10月份。店铺可以在1-4月份减少营业人员,5-11月增加营业人员,应对销售高峰期。
2、店铺销售高峰估计和五一小长假、暑假、开学季、十一小长假有关,尤其是开学季的情况最好,店铺应该在这几个关键的节点,提前布局,打造竞品,加大库存量,保证货源充足。
3、北上广用户数量、订单数量、成交金额都远优于其他省份,是主要的市场。湖南省虽然消费人数最少,但是客单价、订单量都表现优异,用户消费潜力巨大。所以要加大对湖南省的宣传力度,增加湖南省的消费人数。
4、超过一半的用户消费了两次,其中存在高额消费用户,需要注意。
5、至少消费两次的用户有一半是9天,75%的消费者消费金额在一个月,可以在8天、29天两个时间点对用户进行推送和提醒,引导客户消费。
6、75%的消费人群购买力不高,对30岁以下的人群主要推荐亲民价格的商品。
7、40-50岁的人群是购买力主力,而且男性对高价格的商品购买力强,因此给40-50岁的男性推荐高价格的商品。
8、周末是用户消费的高峰期,同时订单集中在8点到13点,这段时间要注意维持好网站的稳定性。