利用黑五销售统计数据,分析用户特征、商品销售情况、主力消费人群和用户偏好商品四个方面内容。
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)