本文主要是对Black Friday案例的分析,将从产品和用户两方面展开分析,为电商平台制定策略提供分析和建议。并将结果用PowerBI实现可视化
成果如下:
项目目录
- 项目背景
- 分析目的
- 分析思路与过程
- 结论与建议
一、项目背景
黑色星期五是美国感恩节后一天,圣诞节前的一次大采购活动,当天一般美国商场会推出大量的打折优惠、促销活动, 由于美国的商场一般以红笔记录赤字,以黑笔记录盈利,而感恩节后的这个星期五人们疯狂的抢购使得商场利润大增,因此被商家们称作黑色星期五。 商家期望通过以这一天开始的圣诞大采购为这一年获得最多的盈利。
二、分析目的
本次的分析数据来自于Kaggle提供的某电商黑色星期五的销售记录, 将围绕产品和用户两大方面展开叙述,为电商平台制定策略提供分析及建议。
三、分析思路与过程
分析思路
分析过程
0.数据集观察
(1)导入常用包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
plt.rcParams['font.sans-serif']=['SimHei']#用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
import seaborn as sns
(2)导入数据集
df = pd.read_csv('D:\\Users\\yuan\\Desktop\\BlackFriday.csv')
(3)数据的初步了解
df.info()
原始数据中共有12个字段,每个字段共537577行,有两个字段缺失数据:产品类别2、产品类别3。字段解释如下:
User_ID: 用户ID
Product_ID: 产品ID
Gender: 性别
Age: 年龄
Occupation: 职业
City_Category: 城市(A,B,C)
Stay_In_Current_City_Years: 居住时长
Marital_Status: 婚姻状况
Product_Category_1 产品类别1,是一级分类
Product_Category_2 产品类别2,是二级分类
Product_Category_3 产品类别3,是三级分类
Purchase: 金额(美元)
#查看数据是否有欠缺,缺多少
(df.shape[0]-df.count(axis=0))/df.shape[0]
Product_Category_2 有31%的数据缺失
Product_Category_3 有69%的数据缺失
df.describe()
1、整体消费情况
(1)销售额
df["Purchase"].sum()
总的消费金额是50亿美元
(2)销量
df["Product_ID"].count()
总销售产品量是537577
(3)平均销售单价
df['Purchase'].sum()/df['Product_ID'].count()
平均产品价格是9333美元
(4)商品种类
df['Product_ID'].drop_duplicates(keep='first').count()
总共销售出3623种不同的商品。
(5)消费人数
df['User_ID'].drop_duplicates(keep='first').count()
总共有5891位用户参与黑五消费活动。
(6)客单价
df['Purchase'].sum()/df['User_ID'].drop_duplicates(keep='first').count()
平均客单价为85万
总结:从本次的消费记录来看,记录的主要是大客户的消费数据,人均消费已经达到了85万美元!这些人一共贡献了50亿美金的销售额。抓住忠实用户,并促进他们消费,是互联网电商发展的基本操作。
2、用户画像分析(探究最优价值的用户类型:性别、年龄、职业、婚姻)
(1)性别方面
#按性别分组计算消费金额
df_gender_purchase=df.groupby('Gender').agg({'Purchase':'sum'}).reset_index().rename(columns={'Purchase':'Purchase_amount'})
#新增字段:不同性别的消费额占比
df_gender_purchase['gender_purchase_prop']=df_gender_purchase.apply(lambda x : x[1]/df['Purchase'].sum(),axis=1)#x[1]返回的是下标为1的元素
#定义一个函数,用于计数
def Gender_user_count(x):
if x[0] == 'F':
#user_id 去重后计数
return(df.loc[df['Gender']=='F'].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
if x[0] == 'M':
return(df.loc[df['Gender']=='M'].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
#新增字段,不同性别的用户数
df_gender_purchase['gender_user_count']= df_gender_purchase.apply(lambda x : Gender_user_count(x),axis=1 )
# 新增字段,不同性别的客单价
df_gender_purchase['gender_costomer_price']=df_gender_purchase.apply(lambda x : x[1]/x[3],axis=1)
#新增字段,不同性别的用户占比
df_gender_purchase['gender_count_prop']=df_gender_purchase.apply(lambda x : x[3]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
df_gender_purchase
在黑色星期五的活动中,男性用户明显高于女性,占比达到71.7%,是女性的2.5倍,但男性用户的销售总额占比76.7%,是女性的3.3倍 对于客单价来说,男性也是高于女性的,是女性的1.3倍 所以这类活动主要针对男性用价格较高的来推销
(2)年龄方面
#按年龄分组计算消费金额
df_age_purchase=df.groupby('Age').agg({'Purchase':'sum'}).reset_index().rename(columns={'Purchase':'Purchase_amount'})
#新增字段,不同年龄段的消费额占比
df_age_purchase['Age_purchase_prop']=df_age_purchase.apply(lambda x : x[1]/df['Purchase'].sum(),axis=1)
#定义一个函数
def Age_user_count(x):
for i in df["Age"].drop_duplicates():
if x[0] == i:
return (df.loc[df['Age']==i].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
#新增字段,不同年龄段的用户数
df_age_purchase['Age_user_count']= df_age_purchase.apply(lambda x : Age_user_count(x),axis=1)
#新增字段,不同年龄段的客单价
df_age_purchase['Age_costomer_price']=df_age_purchase.apply(lambda x : x[1]/x[3],axis=1)
#新增字段,不同年龄段的用户占比
df_age_purchase['Age_count_prop']=df_age_purchase.apply(lambda x : x[3]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
df_age_purchase
18-45岁年龄段的用户,人数占比73%,贡献了78%的销售额,而且客单价明显高于其他年龄段。其中,26-35岁年龄段的用户人数和消费金额都是最多的。
所以黑五活动应该针对18-45岁年龄段的人进行推销,尤其是26-35岁的用户。
(3)婚姻状态
#按婚姻状态分组计算消费金额
df_marital_purchase=df.groupby('Marital_Status').agg({'Purchase':'sum'}).reset_index().rename(columns={'Purchase':'Purchase_amount'})
#新增字段,不同婚姻状态的消费额占比
df_marital_purchase['Marital_Status_prop']=df_marital_purchase.apply(lambda x : x[1]/df['Purchase'].sum(),axis=1)
#定义一个函数
def Marital_user_count(x):
if x[0] == 0:
#user_id 去重后计数
return(df.loc[df['Marital_Status']==0].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
if x[0] == 1:
return(df.loc[df['Marital_Status']==1].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
#新增字段,不同婚姻状态的用户数
df_marital_purchase['Marital_user_count']= df_marital_purchase.apply(lambda x : Marital_user_count(x),axis=1)
#新增字段,不同婚姻状态的客单价
df_marital_purchase['Marital_costomer_price']=df_marital_purchase.apply(lambda x : x[1]/x[3],axis=1)
#新增字段,不同婚姻状态的用户占比
df_marital_purchase['Marital_count_prop']=df_marital_purchase.apply(lambda x : x[3]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
df_marital_purchase
未婚用户占比58%,贡献了59%的销售额,将近一半,且未婚客单价略高于已婚客单价,所以此次活动应重点给未婚用户推销产品
(4)综合考虑性别+婚姻状态+年龄
#新增字段,性别—婚姻状态
df['Gender_MaritalStatus'] = df[['Gender','Marital_Status']].apply(lambda x : str(x[0])+'_'+str(x[1]),axis=1)
#使用性别——婚姻状态+年龄进行分组,计算消费金额
df_GenderMtital_age=df.groupby(['Gender_MaritalStatus','Age']).agg({'Purchase' : 'sum'}).reset_index().rename(columns={'Purchase':'Purchase_amount'})
#不同性别婚姻状态+年龄的销售额占比
df_GenderMtital_age['GenderMtital_age_prop']=df_GenderMtital_age.apply(lambda x : x[2]/df['Purchase'].sum(),axis=1)
#定义一个新的函数
def GenderMtital_age_user_count(x):
for i in df['Gender_MaritalStatus'].drop_duplicates():
for j in df["Age"].drop_duplicates():
if x[0]==i and x[1]== j:
return (df.loc[(df['Gender_MaritalStatus']== i) & (df['Age']==j)].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
#不同性别婚姻状态+年龄的用户数
df_GenderMtital_age['GenderMtital_age_user_count']=df_GenderMtital_age.apply(lambda x:GenderMtital_age_user_count(x),axis=1)
#不同性别婚姻状态+年龄的客单量
df_GenderMtital_age['GenderMtital_age_user_price']=df_GenderMtital_age.apply(lambda x : x[2]/x[4],axis=1)
#不同性别婚姻状态+年龄用户占比
df_GenderMtital_age['GenderMtital_age_user_prop']=df_GenderMtital_age.apply(lambda x : x[4]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
df_GenderMtital_age.head(5)
sns.barplot(x="Age",hue="Gender_MaritalStatus",y="Gender_MaritalStatus_user_count",data=df_Gender_MaritalStatus_purchase
26到35这个时间区间中,未婚状态下的男性参与活动的人数的最多的,而到18-35这个地区中未婚男性的销量也排到第二位的
#消费金额
sns.barplot(x='Age',hue='Gender_MaritalStatus',y='GenderMtital_age_user_count',data=df_GenderMtital_age)
本次黑五活动中,26-35岁年龄段的未婚男性对销售额的贡献最大,其次是26-35岁年龄段的已婚男性,排在第三位的是18-25岁年龄段的未婚男性。
不同性别_婚姻状态、不同年龄段的销售额分布情况与用户数大致相同
(5)职业方面
#按职位分组计算消费金额
df_Occupation_purchase=df.groupby("Occupation").agg({"Purchase":"sum"}).reset_index().rename(columns={"Purchase":"Purchase_amount"})
#新增字段,不同城市的消费额占比
df_Occupation_purchase["Occupation_purchase_prop"]=df_Occupation_purchase.apply(lambda x:x[1]/df["Purchase"].sum(),axis=1)
#定义一个函数
def Occupation_user_count(x):
for i in df["Occupation"].drop_duplicates():
if x[0]==i:
return (df.loc[df["Occupation"]==i].drop_duplicates(subset=["User_ID"],keep="first")["User_ID"].count())
#新增字段,不同职位的用户数
df_Occupation_purchase['Occupation_user_count']= df_Occupation_purchase.apply(lambda x : Occupation_user_count(x),axis=1)
#新增字段,不同职位的客单价
df_Occupation_purchase['Occupation_costomer_price']=df_Occupation_purchase.apply(lambda x : x[1]/x[3],axis=1)
#新增字段,不同职位的用户占比
df_Occupation_purchase['Occupation_count_prop']=df_Occupation_purchase.apply(lambda x : x[3]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
#按照用户数量降序排序
df_Occupation_purchase.sort_values(by='Occupation_user_count',ascending=False).head(5)
4、0、7、1的人数占到了用户总人数的40%,这些职位应该是我们关注的对象
3、城市业绩分析(城市分布、居住年限分布)
(1)城市分布
#按城市分组计算消费金额
df_City_Category_purchase=df.groupby('City_Category').agg({'Purchase':'sum'}).reset_index().rename(columns={'Purchase':'Purchase_amount'})
# 新增字段,不同城市的消费额占比
df_City_Category_purchase['City_Category_purchase_prop']=df_City_Category_purchase.apply(lambda x : x[1]/df['Purchase'].sum(),axis=1)
#定义一个函数
def City_Category_user_count(x):
if x[0] == 'A':
#user_id 去重后计数
return(df.loc[df['City_Category']=='A'].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
if x[0] == 'B':
return(df.loc[df['City_Category']=='B'].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
if x[0] == 'C':
return(df.loc[df['City_Category']=='C'].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
#新增字段,不同城市的的用户数
df_City_Category_purchase['City_Category_user_count']= df_City_Category_purchase.apply(lambda x : City_Category_user_count(x),axis=1)
#新增字段,不同城市的客单价
df_City_Category_purchase['City_Category_customer_price']=df_City_Category_purchase.apply(lambda x : x[1]/x[3],axis=1)
#新增字段,不同城市的用户占比
df_City_Category_purchase['City_Category_count_prop']=df_City_Category_purchase.apply(lambda x : x[3]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
df_City_Category_purchase
B城市的用户数量在总用户的占比为29%,但贡献了42%的消费额,C城市的用户有53% ,却只贡献了33%的消费额并且AB城市的客单价是分别是C城市的近似2倍。我们大致能够猜测到AB城市的消费水品较高,下次举办活动的时候,可以对AB城市的价格适当提高。C城市可以适当降低价格,通过提高销售量来提高销售额。
(2)居住年限分布
#按居住年限分组,统计消费金额
df_Stay_In_Current_City_Years_purchase=df.groupby('Stay_In_Current_City_Years').agg({'Purchase':'sum'}).reset_index().rename(columns={'Purchase':'Purchase_amount'})
#新增字段,不同居住年限的消费额占比
df_Stay_In_Current_City_Years_purchase['Stay_In_Current_City_Years_purchase_prop']=df_Stay_In_Current_City_Years_purchase.apply(lambda x : x[1]/df['Purchase'].sum(),axis=1)
#定义一个函数
def Stay_In_Current_City_Years_user_count(x):
for i in df["Stay_In_Current_City_Years"].drop_duplicates():
if x[0] == i:
return (df.loc[df['Stay_In_Current_City_Years']==i].drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count())
#新增字段,不同年龄段的用户数
df_Stay_In_Current_City_Years_purchase['Stay_In_Current_City_Years_user_count']= df_Stay_In_Current_City_Years_purchase.apply(lambda x : Stay_In_Current_City_Years_user_count(x),axis=1)
#新增字段,不同年龄段的客单价
df_Stay_In_Current_City_Years_purchase['Stay_In_Current_City_Years_costomer_price']=df_Stay_In_Current_City_Years_purchase.apply(lambda x : x[1]/x[3],axis=1)
#新增字段,不同年龄段的用户占比
df_Stay_In_Current_City_Years_purchase['Stay_In_Current_City_Years_count_prop']=df_Stay_In_Current_City_Years_purchase.apply(lambda x : x[3]/df.drop_duplicates(subset=['User_ID'],keep='first')['User_ID'].count(),axis=1)
df_Stay_In_Current_City_Years_purchase
在城市中居住1年的用户最多也最具有消费活力。
4、产品分析(探究最优价值的产品)
(1)销售额top10的产品
#将产品ID进行分组,计算销售额、销量,并按照销售额升序排序
df_top10=df.groupby('Product_ID').agg({'Purchase':'sum','User_ID':'count'}).rename(columns={'Purchase':'Purchase_amount','User_ID':'User_count'}).reset_index().sort_values(by=['Purchase_amount'],ascending = False)[['Product_ID','Purchase_amount']].head(10)
df_top10.head(10)
销售额最高的产品是P00025442,销售额为2700万
(2)销量top10的产品
df_count10=df.groupby('Product_ID').agg({'Purchase':'sum','User_ID':'count'}).rename(columns={'Purchase':'Purchase_amount','User_ID':'User_count'}).reset_index().sort_values(by=['User_count'],ascending = False)[['Product_ID','User_count']].head(10)
df_count10.head(10)
销售量最高的产品为P00265242,共销售1858件,但销售额不在top10 的行列,说明该产品单价较低 对于产品P00025442,销售量排在第3位,为1586件,但其销售额最高
(3)有哪些产品在销量和销量金额都是在Top10中的
pd.merge(df_top10,df_count10,left_on="Product_ID",right_on="Product_ID",how="inner")
(4)产品类别(一级分类)销售额排行榜
#按照产品类别(一级分类)销售额排行榜
df_amount_Product_Category_1=df.groupby('Product_Category_1').agg({'Purchase':'sum','User_ID':'count'}).rename(columns={'Purchase':'Purchase_amount','User_ID':'User_count'}).reset_index().sort_values(by=['Purchase_amount'],ascending = False)[['Product_Category_1','Purchase_amount']]
#不同产品类别1对销售额的贡献占比
df_amount_Product_Category_1['Category_prop']=df_amount_Product_Category_1.apply(lambda x :x[1]/df['Purchase'].sum(),axis=1)
df_amount_Product_Category_1
销售额最高的产品类别是1,销售额接近19亿,在总销售额中的占比是38%。
销售额排名前三的产品类别1、5、8,总共贡献了73%的销售额。
销售额排名末三位的产品类别17、12、13仅贡献了不到0.3%的销售额。
(2)产品类别(一级分类)销量排行榜
df_count_Product_Category_1=df.groupby('Product_Category_1').agg({'User_ID':'count','Purchase':'sum'}).rename(columns={'Purchase':'Purchase_amount','User_ID':'User_count'}).reset_index().sort_values(by=['User_count'],ascending=False)[['Product_Category_1','User_count']]
# 不同产品类别1对销量的贡献占比
df_count_Product_Category_1['Category_count_Prop']=df_count_Product_Category_1.apply(lambda x:x[1]/df['User_ID'].count(),axis=1)
df_count_Product_Category_1
销量最高的产品类别是5,销量接近15万,在总销量中的占比是28%。
销量排名前三的产品类别5、1、8,总销量占比可达75%。
销量排名末三位的产品类别14、17、19,总销量仅占0.4%左右。
5、最大贡献用户价值分析
(1)价值top10用户清单
# 按照用户分组,计算消费金额
df_amount_user=df.groupby('User_ID').agg({'Purchase':'sum'}).rename(columns={'Purchase':'Purchase_amount'}).reset_index().sort_values(by=['Purchase_amount'],ascending=False)[['User_ID','Purchase_amount']]
# 不同用户对销售额的贡献占比
df_amount_user['User_purchase_prop']=df_amount_user.apply(lambda x:x[1]/df['Purchase'].sum(),axis=1)
df_amount_user.head(10)
价值最高的用户,贡献了0.21%的销售额;价值排名第10的用户,贡献了0.13%的销售额。
(2)用户贡献(百分之多少的用户贡献了百分之多少的销售额)
df_user_cumsum=df_amount_user.sort_values(by='Purchase_amount').apply(lambda x:x.cumsum()/x.sum())
df_user_cumsum.reset_index().Purchase_amount.plot()
总共有5891位用户,其中32%的用户贡献了70%的销售额。
抓住最有价值的用户就能保证大部分的销售额。
四、结论与建议
1、用户的角度
结论汇总:
- 年龄在26-35岁,职业编号为"4","0","7","1"的未婚男性消费人群属于高消费人群,该平台的超级忠实用户
后续改进:
- 对高价值用户重点关注,进行更精细化的营销,后续为这些高价值用户提供更多的高价值消费品;
- 针对其他的用户,主要引导用户点击购买,多推荐一些热销的商品;
2、商品的角度
结论汇总:
- 黑色星期五期间,一级商品分类的5、1、8的销量、销售额都是排在前3的,
而且最受用户欢迎的商品top10中也有这3类商品,这3类商品贡献了72%的销售额;
销量排名最低的三个商品种类是16、11、12,占比都不到0.3%;
即在在Top10销售额中的产品和在Top10销售量的产品,可利用爆款商品陈列位置为其他产品引流。
后续改进:
可以在最受用户欢迎的商品top10的商品和其他一些相关的商品做一些捆绑销售,带动其他商品的销量;在一级商品分类为5、1、8的商品页面推荐一些其他的商品,引导用户去点击购买;
具体再分析下销量排名最低的三个商品种类是什么原因造成的,如果商品种类16、11、12是一些已经淘汰过时的商品或者被一些该商品的替代品占领了市场,可以考虑是否要下架,减少相关渠道的广告等;
3.城市角度
结论汇总
- 畅销第一级别类目依次是5、8、1,仓库管理需按畅销商品名单、分类,安排库存,对于消费旺盛B城市提前备货,节省调度;同时监控库存,防止断货。