利用黑五销售统计数据,分析用户特征、商品销售情况、主力消费人群和用户偏好商品四个方面内容。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set_style("ticks")#设置绘图风格
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
1 数据总览
black_friday=pd.read_csv('BlackFriday.csv')
black_friday.head()
User_ID | Product_ID | Gender | Age | Occupation | City_Category | Stay_In_Current_City_Years | Marital_Status | Product_Category_1 | Product_Category_2 | Product_Category_3 | Purchase | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1000001 | P00069042 | F | 0-17 | 10 | A | 2 | 0 | 3 | NaN | NaN | 8370 |
1 | 1000001 | P00248942 | F | 0-17 | 10 | A | 2 | 0 | 1 | 6.0 | 14.0 | 15200 |
2 | 1000001 | P00087842 | F | 0-17 | 10 | A | 2 | 0 | 12 | NaN | NaN | 1422 |
3 | 1000001 | P00085442 | F | 0-17 | 10 | A | 2 | 0 | 12 | 14.0 | NaN | 1057 |
4 | 1000002 | P00285442 | M | 55+ | 16 | C | 4+ | 0 | 8 | NaN | NaN | 7969 |
black_friday.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 537577 entries, 0 to 537576
Data columns (total 12 columns):
User_ID 537577 non-null int64
Product_ID 537577 non-null object
Gender 537577 non-null object
Age 537577 non-null object
Occupation 537577 non-null int64
City_Category 537577 non-null object
Stay_In_Current_City_Years 537577 non-null object
Marital_Status 537577 non-null int64
Product_Category_1 537577 non-null int64
Product_Category_2 370591 non-null float64
Product_Category_3 164278 non-null float64
Purchase 537577 non-null int64
dtypes: float64(2), int64(5), object(5)
memory usage: 49.2+ MB
数据共有537577行,12列。
各列说明如下:
- User_ID:用户ID
- Product_ID:商品ID
- Gender:性别,M为男性,F为女性
- Age:年龄段,划分为0-17、18-25、26-35、36-45、46-55、55+共六个年龄段
- Occupation:职业,已转换为数字标签,共有21类职业
- City_Category:所在城市类别,转换为字母标签,分为A、B、C三类
- Stay_In_Current_City_Years:所在城市居住年份,分为0、1、2、3、4+五个类别
- Marital_Status:婚姻状况,0为未婚,1为已婚
- Product_Category_1:商品标签1,已转换为数字标签,范围1-18
- Product_Category_2:商品标签2,已转换为数字标签,范围2-18
- Product_Category_3:商品标签3,已转换为数字标签,范围3-18
- Purchase:消费金额,单位为美元
2 定义一些画图的函数
def pie(data=None,title=None,length=6,height=6,dpi=100):
'''绘制饼图的函数'''
fig,ax=plt.subplots(figsize=(length,height),dpi=dpi)
size=0.5
labels=data.index
ax.pie(data,labels=labels,
startangle=90,autopct='%.1f%%',colors=sns.color_palette("husl",len(data)),
radius=1,#控制饼图半径,默认为1
pctdistance=0.75,#控制百分比显示位置
wedgeprops=dict(width=size,edgecolor='w'),#控制甜甜圈的宽度,边缘颜色等
textprops=dict(fontsize=10)#控制字号及颜色等
)
ax.set_title(title,fontsize=15)
def bar(data=None,title=None,width=0.6,length=10,height=6,dpi=100,text_distance=10,text_fontsize=10,):
'''绘制柱状图的函数'''
fig,ax=plt.subplots(figsize=(length,height),dpi=dpi)
x=np.arange(len(data))
y=data.values
labels=data.index
width=width
ax.bar(x,y,width=width,color=sns.color_palette("Set2",1))
ax.set_xticks([i for i in range(len(data))])
ax.set_xticklabels(labels)
ax.set_title(title,fontsize=18)
for a,b in enumerate(y):
ax.text(a,b+text_distance,b,ha='center',fontsize=text_fontsize)
def user_analyse_bar(data=None,title=None,n=2,length=10,height=6,dpi=100,total_width=0.6,text_fontsize=10,text_distance=10):
'''
用于绘制用户特征细分的柱状图
'''
fig,ax=plt.subplots(figsize=(length,height),dpi=dpi)
data_m=data.loc['M']
data_f=data.loc['F']
total_width=total_width
n=n
width=total_width/n
x=np.arange(len(data.columns))
x=x-(total_width-width)/2
xlabel=data.columns
ax.bar(x,data_m,width=width,label='Male',color='#36ADA4')
ax.bar(x+width,data_f,width=width,label='Female',color='#F77189')
ax.set_xticks(np.linspace(0,len(data.columns)-1,len(data.columns)))
ax.set_xticklabels(xlabel)
for x,y1,y2 in zip(x,data_m,data_f):
ax.text(x,y1+text_distance,y1,ha='center',fontsize=text_fontsize)
ax.text(x+width,y2+text_distance,y2,ha='center',fontsize=text_fontsize)
ax.set_title(title,fontsize=18)
ax.legend()
3 用户是一些什么人?
#提取用户数据并去重
user=black_friday.loc[:,'User_ID':'Marital_Status'].drop_duplicates(subset='User_ID')
user.head()
User_ID | Product_ID | Gender | Age | Occupation | City_Category | Stay_In_Current_City_Years | Marital_Status | |
---|---|---|---|---|---|---|---|---|
0 | 1000001 | P00069042 | F | 0-17 | 10 | A | 2 | 0 |
4 | 1000002 | P00285442 | M | 55+ | 16 | C | 4+ | 0 |
5 | 1000003 | P00193542 | M | 26-35 | 15 | A | 3 | 0 |
6 | 1000004 | P00184942 | M | 46-50 | 7 | B | 2 | 1 |
9 | 1000005 | P00274942 | M | 26-35 | 20 | A | 1 | 1 |
3.1 性别
gender=user['Gender'].value_counts().sort_index(ascending=1)
gender_title='黑五购物用户性别比'
pie(gender,gender_title)
黑五用户以男性为主,占将近四分之三。
3.2 年龄段
age=user['Age'].value_counts().sort_index()
age_title='各年龄段用户人数'
bar(age,age_title)
3.3 职业
occupation=user['Occupation'].value_counts().sort_values(ascending=False)
occupation_title='各职业用户人数'
bar(occupation,occupation_title,width=0.8,text_distance=5)
3.4 城市类别
city_category=user['City_Category'].value_counts().sort_index()
city_category
A 1045
B 1707
C 3139
Name: City_Category, dtype: int64
city_category_title='黑五购物用户所在城市'
pie(city_category,city_category_title)
3.5 居住年份
stay_year=user['Stay_In_Current_City_Years'].value_counts().sort_index()
stay_year_title='黑五购物用户所在城市居住年份'
pie(stay_year,stay_year_title)
3.6 婚姻状况
marital_status=user['Marital_Status'].value_counts().sort_index()
marital_status.index=['未婚','已婚']
marital_status
未婚 3417
已婚 2474
Name: Marital_Status, dtype: int64
marital_status_title='黑五购物用户婚姻状况'
pie(marital_status,marital_status_title)
3.7 小结
根据以上分析,可以粗略归纳黑五购物用户的一些特点:
- 男性居多
- 年龄以18-45的居多,若缩小年龄段则是26-35
- 主要职业类别是4、0、7
- 来自C类城市的用户最多,占比超过一半;其次为B类城市;A类城市最少
- 居住年份为1年的用户最多,其次为2年的用户,这两类用户占比超过一半
- 未婚用户略多于已婚用户
4 用户属性交叉分析
从单个属性描述用户特征可能不完善,因此,尝试从多个属性角度进行分析,看用户在不同属性分组下是否有差别。
为避免分析太复杂,这里仅选取部分组合在一起有意义的属性进行两两交叉分析。
4.1 性别-年龄
gender_age=pd.crosstab(user['Gender'],user['Age'])
gender_age
Age | 0-17 | 18-25 | 26-35 | 36-45 | 46-50 | 51-55 | 55+ |
---|---|---|---|---|---|---|---|
Gender | |||||||
F | 78 | 287 | 545 | 333 | 182 | 142 | 99 |
M | 140 | 782 | 1508 | 834 | 349 | 339 | 273 |
user_analyse_bar(data=gender_age,title='各年龄段男女用户人数')
#计算各年龄段的男性比例
gender_age.loc['M']/gender_age.sum(axis=0)
Age
0-17 0.642202
18-25 0.731525
26-35 0.734535
36-45 0.714653
46-50 0.657250
51-55 0.704782
55+ 0.733871
dtype: float64
各年龄段都是以男性用户为主,男性占比差异并不十分明显。
4.2 性别-职业
gender_occ=pd.crosstab(user['Gender'],user['Occupation'])
gender_occ.T
Gender | F | M |
---|---|---|
Occupation | ||
0 | 226 | 462 |
1 | 203 | 314 |
2 | 88 | 168 |
3 | 98 | 72 |
4 | 228 | 512 |
5 | 31 | 80 |
6 | 99 | 129 |
7 | 137 | 532 |
8 | 3 | 14 |
9 | 85 | 3 |
10 | 66 | 126 |
11 | 22 | 106 |
12 | 46 | 330 |
13 | 33 | 107 |
14 | 78 | 216 |
15 | 28 | 112 |
16 | 49 | 186 |
17 | 50 | 441 |
18 | 4 | 63 |
19 | 15 | 56 |
20 | 77 | 196 |
user_analyse_bar(data=gender_occ,title='各职业男女用户人数',total_width=0.8,length=12,text_fontsize=8,text_distance=2)
不同职业的男女用户比例差异较大,多数职业男性用户居多,仅有少数职业的女性用户多于男性用户(3、9)。
4.3 性别-城市
gender_city=pd.crosstab(user['Gender'],user['City_Category'])
gender_city
City_Category | A | B | C |
---|---|---|---|
Gender | |||
F | 295 | 503 | 868 |
M | 750 | 1204 | 2271 |
user_analyse_bar(data=gender_city,title='各城市男女用户人数',total_width=0.6,length=6,height=4)
#计算不同城市的男性比例
gender_city.loc['M']/gender_city.sum(axis=0)
City_Category
A 0.717703
B 0.705331
C 0.723479
dtype: float64
不同城市类别的男女用户比例基本一致。
4.4 性别-婚姻状况
gender_marital=pd.crosstab(user['Gender'],user['Marital_Status'])
gender_marital.rename(columns={0:'未婚',1:'已婚'},inplace=True)
gender_marital
Marital_Status | 未婚 | 已婚 |
---|---|---|
Gender | ||
F | 947 | 719 |
M | 2470 | 1755 |
user_analyse_bar(data=gender_marital,title='男女用户婚姻状况',total_width=0.6,length=6,height=4)
#计算两种婚姻状况下的男性比例
gender_marital.loc['M']/gender_marital.sum(axis=0)
Marital_Status
未婚 0.722856
已婚 0.709378
dtype: float64
不同婚姻状态的男女用户比例基本一致。
4.5 年龄段-城市
age_city=pd.crosstab(user['Age'],user['City_Category'])
age_city
City_Category | A | B | C |
---|---|---|---|
Age | |||
0-17 | 25 | 50 | 143 |
18-25 | 214 | 331 | 524 |
26-35 | 461 | 652 | 940 |
36-45 | 176 | 335 | 656 |
46-50 | 53 | 146 | 332 |
51-55 | 67 | 135 | 279 |
55+ | 49 | 58 | 265 |
fig,ax=plt.subplots(figsize=(12,6),dpi=100)
data=age_city
data_A=data['A']
data_B=data['B']
data_C=data['C']
total_width=0.8
n=3
width=total_width/n
x=np.arange(len(data))
x=x-(total_width-width)/2
xlabel=data.index
ax.bar(x-width,data_A,width=width,label='A',color='#F77189')
ax.bar(x,data_B,width=width,label='B',color='#80B131')
ax.bar(x+width,data_C,width=width,label='C',color='#3BA3EC')
ax.set_xticks(np.linspace(0,len(data)-1,len(data)))
ax.set_xticklabels(xlabel)
for x,y1,y2,y3 in zip(x,data_A,data_B,data_C):
ax.text(x-width,y1+2,y1,ha='center',fontsize=8)
ax.text(x,y2+2,y2,ha='center',fontsize=8)
ax.text(x+width,y3+2,y3,ha='center',fontsize=8)
ax.set_title('不同年龄段用户的居住城市',fontsize=18)
ax.legend()
不管在哪个年龄段,都是C类城市的用户最多,B类次之,A类最少。
4.6 年龄段-婚姻状况
age_marital=pd.crosstab(user['Age'],user['Marital_Status'])
age_marital.rename(columns={0:'未婚',1:'已婚'},inplace=1)
age_marital
Marital_Status | 未婚 | 已婚 |
---|---|---|
Age | ||
0-17 | 218 | 0 |
18-25 | 825 | 244 |
26-35 | 1244 | 809 |
36-45 | 705 | 462 |
46-50 | 156 | 375 |
51-55 | 136 | 345 |
55+ | 133 | 239 |
fig,ax=plt.subplots(figsize=(12,6),dpi=100)
data=age_marital
data_A=data['未婚']
data_B=data['已婚']
total_width=0.8
n=2
width=total_width/n
x=np.arange(len(data))
x=x-(total_width-width)/2
xlabel=data.index
ax.bar(x,data_A,width=width,label=data_A.name,color='#36ADA4')
ax.bar(x+width,data_B,width=width,label=data_B.name,color='#F77189')
ax.set_xticks(np.linspace(0,len(data)-1,len(data)))
ax.set_xticklabels(xlabel)
for x,y1,y2 in zip(x,data_A,data_B):
ax.text(x,y1+4,y1,ha='center',fontsize=8)
ax.text(x+width,y2+4,y2,ha='center',fontsize=8)
ax.set_title('不同年龄段用户的婚姻状况',fontsize=18)
ax.legend()
#计算各年龄段的已婚用户比例
age_marital['已婚']/age_marital.sum(axis=1)
Age
0-17 0.000000
18-25 0.228251
26-35 0.394057
36-45 0.395887
46-50 0.706215
51-55 0.717256
55+ 0.642473
dtype: float64
0-17岁均为未婚用户,因为他们没有达到法定婚龄。(美国不同州的法定婚龄不尽相同,但大多为18岁。)
18-25、26-35、36-45这三个年龄段都是未婚用户居多,但已婚用户比例在慢慢增加。
46-50、51-55、55+这三个年龄段都是已婚用户居多,55+年龄段的已婚用户比例较低可能是存在丧偶或离异情况。
4.7 小结
多数交叉分析的结果与单变量分析的结果并无太大差异,在一个属性中占比较大的群体,在与另一个属性进行交叉分析中通常也占较大比例。
职业和婚姻状况存在的较大变动:
- 不同职业的用户虽然整体上是以男性用户居多,但不同职业的性别比例差异较大
- 随着年龄的上升,已婚用户的比例逐渐升高,55+年龄段用户的已婚比例虽然有所降低,但仍高于46岁以下用户
5 哪些商品卖得好?
product=black_friday.loc[:,['Product_ID','Product_Category_1','Product_Category_2','Product_Category_3','Purchase']]
print('黑五期间涉及的销售商品共{}个。'.format(len(product['Product_ID'].unique())))
黑五期间涉及的销售商品共3623个。
black_friday.loc[:,['User_ID','Product_ID','Purchase']].sort_values(by='Product_ID').head()
User_ID | Product_ID | Purchase | |
---|---|---|---|
519782 | 1001991 | P00000142 | 11071 |
320359 | 1001344 | P00000142 | 10946 |
320351 | 1001343 | P00000142 | 13463 |
339410 | 1004233 | P00000142 | 8341 |
104774 | 1004126 | P00000142 | 13610 |
可以看出,同一商品对不同用户的销售金额不尽相同,每条记录可能是多个同一商品何必后的结果。以记录数作为商品销量不合理,因此仅对销售额进行统计分析。
5.1 哪些商品的销售额更高
#将销售额按商品ID分类加和后由高到低排列,并计算累计销售额占比
product_purchase=product.loc[:,['Product_ID','Purchase']].groupby('Product_ID').sum().sort_values(by='Purchase',ascending=0).reset_index()
product_purchase['Percent']=product_purchase['Purchase']/product_purchase['Purchase'].sum()
product_purchase['P_Cumsum']=product_purchase['Percent'].cumsum()
product_purchase.head()
Product_ID | Purchase | Percent | P_Cumsum | |
---|---|---|---|---|
0 | P00025442 | 27532426 | 0.005487 | 0.005487 |
1 | P00110742 | 26382569 | 0.005258 | 0.010745 |
2 | P00255842 | 24652442 | 0.004913 | 0.015658 |
3 | P00184942 | 24060871 | 0.004795 | 0.020453 |
4 | P00059442 | 23948299 | 0.004773 | 0.025226 |
fig=plt.figure(figsize=(12,6),dpi=100)
ax1=fig.add_subplot(111)
ax1.grid()
ax2=ax1.twinx()#建立副纵坐标轴
data_2=product_purchase['Purchase']
data_1=product_purchase['P_Cumsum']
x=np.arange(1,len(product_purchase)+1)
ax1.plot(x,data_1,color='#ed5a65',label='销售额累计占比')
ax2.plot(x,data_2,color='#5cb3cc',label='单个商品销售额')
ax1.set_xlabel('商品种类')
ax1.set_yticks(np.linspace(0,1,11))
ax1.set_yticklabels(['{:.0%}'.format(i/10) for i in range(11)])#y轴刻度显示百分比
ax1.set_ylabel('累计销售额占比')
ax2.set_ylabel('单个商品的销售额')
ax1.legend(loc=(0.83,0.14))
ax2.legend(loc=(0.83,0.08))
ax1.set_title('黑五各商品销售额的帕累托图',fontsize=18)
for i in range(1,10):
percent=i/10
product_kind=len(product_purchase[product_purchase['P_Cumsum']<=percent])
product_percent=product_kind/len(product_purchase)
print("销售额占{:.0%}的商品共有{}种,占销售商品总数的{:.2%}。".format(percent,product_kind,product_percent))
销售额占10%的商品共有23种,占销售商品总数的0.63%。
销售额占20%的商品共有64种,占销售商品总数的1.77%。
销售额占30%的商品共有124种,占销售商品总数的3.42%。
销售额占40%的商品共有206种,占销售商品总数的5.69%。
销售额占50%的商品共有310种,占销售商品总数的8.56%。
销售额占60%的商品共有454种,占销售商品总数的12.53%。
销售额占70%的商品共有647种,占销售商品总数的17.86%。
销售额占80%的商品共有927种,占销售商品总数的25.59%。
销售额占90%的商品共有1400种,占销售商品总数的38.64%。
可以看出,黑五销售额基本符合二八定律,80%的销售额集中在25.59%的商品。
#将销售额占比80%以上的商品作为主要商品
major_product=product_purchase[product_purchase['P_Cumsum']<=0.8]
major_product.head()
Product_ID | Purchase | Percent | P_Cumsum | |
---|---|---|---|---|
0 | P00025442 | 27532426 | 0.005487 | 0.005487 |
1 | P00110742 | 26382569 | 0.005258 | 0.010745 |
2 | P00255842 | 24652442 | 0.004913 | 0.015658 |
3 | P00184942 | 24060871 | 0.004795 | 0.020453 |
4 | P00059442 | 23948299 | 0.004773 | 0.025226 |
销售额占比最高的三种商品的ID分别为P00025442、P00110742、P00255842,销售额占比分别为0.55%、0.53%、0.49%。
5.2 哪些类型的商品更畅销
5.2.1 商品标签统计
对销售涉及各商品的商品标签进行分类统计。
对于一个商品有多个商品标签的,对其也按标签进行重复统计。
因此,所有标签统计的加和会大于商品总数。
category_1=pd.DataFrame(product['Product_Category_1'].value_counts().sort_index())
category_2=pd.DataFrame(product['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
category_3=pd.DataFrame(product['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
product_category=pd.merge(category_1,category_2,how='outer',left_index=True,right_index=True)
product_category=pd.merge(product_category,category_3,how='outer',left_index=True,right_index=True)
product_category=product_category.fillna(0).astype(int)
product_category['All']=product_category.sum(axis=1)
product_category
Product_Category_1 | Product_Category_2 | Product_Category_3 | All | |
---|---|---|---|---|
1 | 138353 | 0 | 0 | 138353 |
2 | 23499 | 48481 | 0 | 71980 |
3 | 19849 | 2835 | 600 | 23284 |
4 | 11567 | 25225 | 1840 | 38632 |
5 | 148592 | 25874 | 16380 | 190846 |
6 | 20164 | 16251 | 4818 | 41233 |
7 | 3668 | 615 | 0 | 4283 |
8 | 112132 | 63058 | 12384 | 187574 |
9 | 404 | 5591 | 11414 | 17409 |
10 | 5032 | 2991 | 1698 | 9721 |
11 | 23960 | 13945 | 1773 | 39678 |
12 | 3875 | 5419 | 9094 | 18388 |
13 | 5440 | 10369 | 5385 | 21194 |
14 | 1500 | 54158 | 18121 | 73779 |
15 | 6203 | 37317 | 27611 | 71131 |
16 | 9697 | 42602 | 32148 | 84447 |
17 | 567 | 13130 | 16449 | 30146 |
18 | 3075 | 2730 | 4563 | 10368 |
bar(data=product_category['All'].sort_values(ascending=False),title='各标签下的商品数量',text_fontsize=8,text_distance=1500)
从不同标签的商品数量看,大致可以划分为3大类:
- 5、8、1为第一集团,商品数量居前三位,但1距离前两名的差距较大
- 16、14、2、15为第二集团
- 其他为第三集团
5.2.2 不同标签商品的销售额统计
与不同商品标签下商品数量的统计一样,不同标签商品销售额的统计存在重复统计的问题。这个统计指标可以理解为,带有该标签的商品的总销售额。
cat_1_purchase=product.loc[:,['Product_Category_1','Purchase']].groupby('Product_Category_1').sum().rename(columns=dict(Purchase='Cat_1'))
cat_2_purchase=product.loc[:,['Product_Category_2','Purchase']].groupby('Product_Category_2').sum().rename(columns=dict(Purchase='Cat_2'))
cat_3_purchase=product.loc[:,['Product_Category_3','Purchase']].groupby('Product_Category_3').sum().rename(columns=dict(Purchase='Cat_3'))
cat_purchase=pd.merge(cat_1_purchase,cat_2_purchase,how='outer',left_index=True,right_index=True)
cat_purchase=pd.merge(cat_purchase,cat_3_purchase,how='outer',left_index=True,right_index=True)
cat_purchase=cat_purchase.fillna(0).astype(int)
cat_purchase['All']=cat_purchase.sum(axis=1)
cat_purchase
Cat_1 | Cat_2 | Cat_3 | All | |
---|---|---|---|---|
1 | 1882666325 | 0 | 0 | 1882666325 |
2 | 264497242 | 660395610 | 0 | 924892852 |
3 | 200412211 | 31835725 | 8374300 | 240622236 |
4 | 26937957 | 257757097 | 17992055 | 302687109 |
5 | 926917497 | 233747130 | 198662402 | 1359327029 |
6 | 319355286 | 186896021 | 63548518 | 569799825 |
7 | 60059209 | 4229499 | 0 | 64288708 |
8 | 840693394 | 648112417 | 161357998 | 1650163809 |
9 | 6277472 | 40716981 | 119043392 | 166037845 |
10 | 99029631 | 46827140 | 22962030 | 168818801 |
11 | 112203088 | 124608092 | 21475687 | 258286867 |
12 | 5235883 | 37763181 | 79288332 | 122287396 |
13 | 3931050 | 100291709 | 70990467 | 175213226 |
14 | 19718178 | 384866069 | 182187903 | 586772150 |
15 | 91658147 | 386556477 | 340670945 | 818885569 |
16 | 143168035 | 438744196 | 385213413 | 967125644 |
17 | 5758702 | 123639094 | 193760503 | 323158299 |
18 | 9149071 | 25582006 | 50118090 | 84849167 |
bar(data=cat_purchase['All'].sort_values(ascending=False),title='各标签下的商品销售额',text_fontsize=6,text_distance=3000)
根据不同标签下的商品销售额,大致可以分为4大类:
- 1、8、5为第一集团,明显高于其他标签商品,但彼此之间的差距也较大
- 16、2、15为第二集团
- 14、6为第三集团
- 其他为第四集团
5.2.3 小结
不同标签的商品数量和销售额的排名基本一致,只是在各集团中的排名略有差异,这应该与商品单价和购买数量有关。
6 哪些用户消费多?
根据用户属性从不同角度分析哪类用户的消费较高。舍弃一些分析意义不大的角度,如居住年份。
6.1 性别
gender_purchase=black_friday.loc[:,['Gender','Purchase']].groupby('Gender').sum()
gender_purchase
Purchase | |
---|---|
Gender | |
F | 1164624021 |
M | 3853044357 |
title='不同性别用户的销售额'
pie(gender_purchase,title)
#分性别计算人均消费金额
gender_count=pd.DataFrame(black_friday['Gender'].value_counts())
gender_purchase_unit=gender_purchase['Purchase']/gender
fig,ax=plt.subplots(figsize=(8,6))
x=np.arange(len(gender_purchase_unit))
y=gender_purchase_unit.values
ax.bar(x,y,width=0.5,color=sns.color_palette('husl',2))
ax.set_xticks([0,1])
ax.set_xticklabels(['F','M'])
ax.set_ylim(0,1000000)
ax.set_ylabel('人均消费金额(美元)')
ax.set_title('人均消费金额',fontsize=15)
for a,b in enumerate(y):
ax.text(a,b+10000,'{:.0f}'.format(b),ha='center')
男性用户在消费总金额和人均消费金额上均高于女性用户。
6.2 年龄段
age_purchase=black_friday.loc[:,['Age','Purchase']].groupby('Age').sum()
age_purchase
Purchase | |
---|---|
Age | |
0-17 | 132659006 |
18-25 | 901669280 |
26-35 | 1999749106 |
36-45 | 1010649565 |
46-50 | 413418223 |
51-55 | 361908356 |
55+ | 197614842 |
pie(age_purchase,title='各年龄段消费金额')
age_purchase_unit=(age_purchase['Purchase']/age).astype(int)
bar(age_purchase_unit,title='各年龄段人均消费金额',text_distance=10000)
18-45岁用户是主要消费人群,消费总金额占比接近80%。人均消费金额也高于其他年龄段。
6.3 职业
occ_purchase=black_friday.loc[:,['Occupation','Purchase']].groupby('Occupation').sum()
occ_purchase.head()
Purchase | |
---|---|
Occupation | |
0 | 625814811 |
1 | 414552829 |
2 | 233275393 |
3 | 160428450 |
4 | 657530393 |
title='各职业的消费金额'
bar(data=occ_purchase.sort_values(by='Purchase',ascending=False)['Purchase'],title=title,length=16,text_fontsize=8.5,text_distance=5000000)
occ_purchase_unit=occ_purchase['Purchase']/occupation
fig,ax=plt.subplots(figsize=(10,6),dpi=100)
x=np.arange(len(occ_purchase_unit))
y=occ_purchase_unit.sort_values(ascending=False).values
labels=occ_purchase_unit.sort_values(ascending=False).index
width=0.6
ax.bar(x,y,width=width,color=sns.color_palette("Set2",1))
ax.set_xticks([i for i in range(len(occ_purchase_unit))])
ax.set_xticklabels(labels)
ax.set_title('各职业人均消费金额',fontsize=18)
各职业消费总金额和人均消费金额差别较大:
- 总消费金额较高的4、0、7三种职业的人均消费金额并不算高,但因其人数较多,所以消费总金额较高
- 人均消费金额较高的20、19、5、16四种职业的消费总金额不高,说明这些职业的消费能力较高,但消费人数较少
- 9、10、13三种职业的人均消费金额明显低于其他职业,可能原因较多,包括其本身消费能力较低、对促销商品不感兴趣、不喜欢在促销时段购物等
6.4 城市
city_purchase=black_friday.loc[:,['City_Category','Purchase']].groupby('City_Category').sum()
city_purchase.head()
Purchase | |
---|---|
City_Category | |
A | 1295668797 |
B | 2083431612 |
C | 1638567969 |
pie(city_purchase,title='各类城市消费金额')
city_purchase_unit=city_purchase['Purchase']/city_category
fig,ax=plt.subplots(figsize=(8,5),dpi=80)
x=np.arange(len(city_purchase_unit))
y=city_purchase_unit.values
labels=city_purchase_unit.index
width=0.6
ax.bar(x,y,width=width,color=sns.color_palette("Set2",1))
ax.set_xticks([i for i in range(len(city_purchase_unit))])
ax.set_xticklabels(labels)
ax.set_title('各类城市人均消费金额',fontsize=18)
消费总金额是B>C>A,人均消费金额是A>B>C,人数则是C>B>A。据此,有如下推断:
- B类城市用户是消费主力人群
- C类城市虽然人数最多,但人均消费能力不足
- A类城市的消费能力最高,但消费人数最少,可通过加强宣传推广提高消费总金额
6.5 婚姻状况
marital_purchase=black_friday.loc[:,['Marital_Status','Purchase']].groupby('Marital_Status').sum()
marital_purchase.index=['未婚','已婚']
marital_purchase
Purchase | |
---|---|
未婚 | 2966289500 |
已婚 | 2051378878 |
pie(marital_purchase,title='不同婚姻状况用户的消费金额')
marital_purchase_unit=marital_purchase['Purchase']/marital_status
fig,ax=plt.subplots(figsize=(8,5),dpi=80)
x=np.arange(len(marital_purchase_unit))
y=marital_purchase_unit.values
labels=marital_purchase_unit.index
width=0.6
ax.bar(x,y,width=width,color=sns.color_palette("Set2",1))
ax.set_xticks([i for i in range(len(marital_purchase_unit))])
ax.set_xticklabels(labels)
ax.set_title('不同婚姻状况用户的人均消费金额',fontsize=18)
已婚用户和未婚用户的人均消费金额差别不大,总消费金额的差异主要由用户数不同引起。
6.6 小结
根据以上分析,黑五消费的主力用户大致有如下特征:
- 男性
- 18-45周岁
- 来自B类城市
- 职业是4、0或7
除此之外,职业是20、19、5、16的,来自A类城市的用户也具有较大的消费能力,应重点发展。
7 不同用户偏爱什么样的商品
7.1 性别
#分别整理出男女用户购买的商品标签
cat_m=black_friday[black_friday['Gender']=='M'].loc[:,'Product_Category_1':'Product_Category_3']
cat_f=black_friday[black_friday['Gender']=='F'].loc[:,'Product_Category_1':'Product_Category_3']
#统计男用户购买的商品标签
cat_1_m=pd.DataFrame(cat_m['Product_Category_1'].value_counts().sort_index())
cat_2_m=pd.DataFrame(cat_m['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_m=pd.DataFrame(cat_m['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_m_sum=pd.merge(cat_1_m,cat_2_m,how='outer',left_index=True,right_index=True)
cat_m_sum=pd.merge(cat_m_sum,cat_3_m,how='outer',left_index=True,right_index=True)
cat_m_sum=cat_m_sum.fillna(0).astype(int)
cat_m_sum['All']=cat_m_sum.sum(axis=1)
cat_m_sum
Product_Category_1 | Product_Category_2 | Product_Category_3 | All | |
---|---|---|---|---|
1 | 113952 | 0 | 0 | 113952 |
2 | 17926 | 39442 | 0 | 57368 |
3 | 13975 | 2224 | 506 | 16705 |
4 | 7995 | 17774 | 1412 | 27181 |
5 | 107393 | 19812 | 12165 | 139370 |
6 | 15689 | 13009 | 4002 | 32700 |
7 | 2740 | 482 | 0 | 3222 |
8 | 79185 | 46842 | 9489 | 135516 |
9 | 334 | 4111 | 8778 | 13223 |
10 | 3894 | 2273 | 1287 | 7454 |
11 | 19301 | 11237 | 1445 | 31983 |
12 | 2378 | 3713 | 6432 | 12523 |
13 | 4012 | 7750 | 4173 | 15935 |
14 | 887 | 34849 | 12614 | 48350 |
15 | 5180 | 30989 | 23080 | 59249 |
16 | 7334 | 33284 | 25490 | 66108 |
17 | 506 | 10689 | 12778 | 23973 |
18 | 2699 | 2261 | 3695 | 8655 |
#统计女用户购买的商品标签
cat_1_f=pd.DataFrame(cat_f['Product_Category_1'].value_counts().sort_index())
cat_2_f=pd.DataFrame(cat_f['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_f=pd.DataFrame(cat_f['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_f_sum=pd.merge(cat_1_f,cat_2_f,how='outer',left_index=True,right_index=True)
cat_f_sum=pd.merge(cat_f_sum,cat_3_f,how='outer',left_index=True,right_index=True)
cat_f_sum=cat_f_sum.fillna(0).astype(int)
cat_f_sum['All']=cat_f_sum.sum(axis=1)
cat_f_sum
Product_Category_1 | Product_Category_2 | Product_Category_3 | All | |
---|---|---|---|---|
1 | 24401 | 0 | 0 | 24401 |
2 | 5573 | 9039 | 0 | 14612 |
3 | 5874 | 611 | 94 | 6579 |
4 | 3572 | 7451 | 428 | 11451 |
5 | 41199 | 6062 | 4215 | 51476 |
6 | 4475 | 3242 | 816 | 8533 |
7 | 928 | 133 | 0 | 1061 |
8 | 32947 | 16216 | 2895 | 52058 |
9 | 70 | 1480 | 2636 | 4186 |
10 | 1138 | 718 | 411 | 2267 |
11 | 4659 | 2708 | 328 | 7695 |
12 | 1497 | 1706 | 2662 | 5865 |
13 | 1428 | 2619 | 1212 | 5259 |
14 | 613 | 19309 | 5507 | 25429 |
15 | 1023 | 6328 | 4531 | 11882 |
16 | 2363 | 9318 | 6658 | 18339 |
17 | 61 | 2441 | 3671 | 6173 |
18 | 376 | 469 | 868 | 1713 |
#合并男女用户购买的商品标签数
cat_gender_sum=pd.DataFrame(cat_m_sum['All']).rename(columns=dict(All='M')).join(pd.DataFrame(cat_f_sum['All']).rename(columns=dict(All='F')))
fig=plt.figure(figsize=(12,6),dpi=100)
ax1=fig.add_subplot(1,2,1)
ax1.pie(cat_gender_sum['M'].sort_values(ascending=False),labels=cat_gender_sum['M'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=9))
ax1.axis('equal')
ax1.set_title('男性用户购买商品的标签数量',fontsize=15)
ax2=fig.add_subplot(1,2,2)
ax2.pie(cat_gender_sum['F'].sort_values(ascending=False),labels=cat_gender_sum['F'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=9))
ax2.axis('equal')
ax2.set_title('女性用户购买商品的标签数量',fontsize=15)
7.2 城市类别
#分别整理出各类城市用户购买的商品标签
cat_A=black_friday[black_friday['City_Category']=='A'].loc[:,'Product_Category_1':'Product_Category_3']
cat_B=black_friday[black_friday['City_Category']=='B'].loc[:,'Product_Category_1':'Product_Category_3']
cat_C=black_friday[black_friday['City_Category']=='C'].loc[:,'Product_Category_1':'Product_Category_3']
#统计A类城市用户购买的商品标签
cat_1_A=pd.DataFrame(cat_A['Product_Category_1'].value_counts().sort_index())
cat_2_A=pd.DataFrame(cat_A['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_A=pd.DataFrame(cat_A['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_A_sum=pd.merge(cat_1_A,cat_2_A,how='outer',left_index=True,right_index=True)
cat_A_sum=pd.merge(cat_A_sum,cat_3_A,how='outer',left_index=True,right_index=True)
cat_A_sum=cat_A_sum.fillna(0).astype(int)
cat_A_sum['All']=cat_A_sum.sum(axis=1)
#统计B类城市用户购买的商品标签
cat_1_B=pd.DataFrame(cat_B['Product_Category_1'].value_counts().sort_index())
cat_2_B=pd.DataFrame(cat_B['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_B=pd.DataFrame(cat_B['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_B_sum=pd.merge(cat_1_B,cat_2_B,how='outer',left_index=True,right_index=True)
cat_B_sum=pd.merge(cat_B_sum,cat_3_B,how='outer',left_index=True,right_index=True)
cat_B_sum=cat_B_sum.fillna(0).astype(int)
cat_B_sum['All']=cat_B_sum.sum(axis=1)
#统计C类城市用户购买的商品标签
cat_1_C=pd.DataFrame(cat_C['Product_Category_1'].value_counts().sort_index())
cat_2_C=pd.DataFrame(cat_C['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_C=pd.DataFrame(cat_C['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_C_sum=pd.merge(cat_1_C,cat_2_C,how='outer',left_index=True,right_index=True)
cat_C_sum=pd.merge(cat_C_sum,cat_3_C,how='outer',left_index=True,right_index=True)
cat_C_sum=cat_C_sum.fillna(0).astype(int)
cat_C_sum['All']=cat_C_sum.sum(axis=1)
#合并各类城市用户购买的商品标签数
cat_city_sum=pd.DataFrame(cat_A_sum['All']).rename(columns=dict(All='A')).join(pd.DataFrame(cat_B_sum['All']).rename(columns=dict(All='B')))
cat_city_sum=cat_city_sum.join(pd.DataFrame(cat_C_sum['All']).rename(columns=dict(All='C')))
fig=plt.figure(figsize=(12,6),dpi=100)
ax1=fig.add_subplot(1,3,1)
ax1.pie(cat_city_sum['A'].sort_values(ascending=False),labels=cat_city_sum['A'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=7))
ax1.axis('equal')
ax1.set_title('A类城市用户购买商品的标签数量',fontsize=13)
ax2=fig.add_subplot(1,3,2)
ax2.pie(cat_city_sum['B'].sort_values(ascending=False),labels=cat_city_sum['B'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=7))
ax2.axis('equal')
ax2.set_title('B类城市用户购买商品的标签数量',fontsize=13)
ax3=fig.add_subplot(1,3,3)
ax3.pie(cat_city_sum['C'].sort_values(ascending=False),labels=cat_city_sum['C'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=7))
ax3.axis('equal')
ax3.set_title('C类城市用户购买商品的标签数量',fontsize=13)
7.3 婚姻状况
#分别整理出已婚、未婚用户购买的商品标签
cat_0=black_friday[black_friday['Marital_Status']==0].loc[:,'Product_Category_1':'Product_Category_3']
cat_1=black_friday[black_friday['Marital_Status']==1].loc[:,'Product_Category_1':'Product_Category_3']
#统计未婚用户购买的商品标签
cat_1_0=pd.DataFrame(cat_0['Product_Category_1'].value_counts().sort_index())
cat_2_0=pd.DataFrame(cat_0['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_0=pd.DataFrame(cat_0['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_0_sum=pd.merge(cat_1_0,cat_2_0,how='outer',left_index=True,right_index=True)
cat_0_sum=pd.merge(cat_0_sum,cat_3_0,how='outer',left_index=True,right_index=True)
cat_0_sum=cat_0_sum.fillna(0).astype(int)
cat_0_sum['All']=cat_0_sum.sum(axis=1)
#统计已婚用户购买的商品标签
cat_1_1=pd.DataFrame(cat_1['Product_Category_1'].value_counts().sort_index())
cat_2_1=pd.DataFrame(cat_1['Product_Category_2'].dropna().astype(int).value_counts().sort_index())
cat_3_1=pd.DataFrame(cat_1['Product_Category_3'].dropna().astype(int).value_counts().sort_index())
cat_1_sum=pd.merge(cat_1_1,cat_2_1,how='outer',left_index=True,right_index=True)
cat_1_sum=pd.merge(cat_1_sum,cat_3_1,how='outer',left_index=True,right_index=True)
cat_1_sum=cat_1_sum.fillna(0).astype(int)
cat_1_sum['All']=cat_1_sum.sum(axis=1)
#合并已婚未婚用户购买的商品标签数
cat_marital_sum=pd.DataFrame(cat_0_sum['All']).rename(columns=dict(All='未婚')).join(pd.DataFrame(cat_1_sum['All']).rename(columns=dict(All='已婚')))
fig=plt.figure(figsize=(12,6),dpi=100)
ax1=fig.add_subplot(1,2,1)
ax1.pie(cat_marital_sum['未婚'].sort_values(ascending=False),labels=cat_marital_sum['未婚'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=9))
ax1.axis('equal')
ax1.set_title('未婚用户购买商品的标签数量',fontsize=15)
ax2=fig.add_subplot(1,2,2)
ax2.pie(cat_marital_sum['已婚'].sort_values(ascending=False),labels=cat_marital_sum['已婚'].sort_values(ascending=False).index,shadow=True,
startangle=90,colors=sns.color_palette('husl',18),
textprops=dict(fontsize=9))
ax2.axis('equal')
ax2.set_title('已婚用户购买商品的标签数量',fontsize=15)
小结
总的来说,从性别、城市类别、婚姻状况三个角度划分用户并分析其购买商品的偏好,发现不同用户群体的偏好差异不大。
仅有男女用户对标签1和14的商品偏好稍大。相比之下,男性用户对于1类商品更为青睐,女性用户对这两种商品的偏好并没有太大差异。
来源:CSDN
作者:采蘑菇的小白
链接:https://blog.csdn.net/qq_41097598/article/details/84310763