社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

【Python】Kaggle可视化:黑色星期五画像分析

机器学习初学者 • 4 年前 • 541 次点击  

作者:Peter
编辑:Peter

本文还是kaggle上一份黑色星期五消费数据的分析,主要是针对用户和商品信息的画像分析。建模的方案参考文章:

kaggle实战:星期五黑了,随机森林输了!

本文重点是可视化,使用的图形:柱状图、饼图、散点图、小提琴图、桑基图、树状图、漏斗图、多子图等,全部是Plotly库绘制。

关键词:用户画像、可视化、plotly、Pandas

导入库

import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
import seaborn as sns 
import matplotlib.patches as mpatches
import matplotlib
# 中文显示问题
plt.rcParams["font.sans-serif"]=["SimHei"#设置字体
plt.rcParams["axes.unicode_minus"]=False #正常显示负号

import plotly.graph_objects as go
import plotly.express as px
from plotly.subplots import make_subplots
from plotly.offline import init_notebook_mode, iplot

# 忽略notebook中的警告
import warnings
warnings.filterwarnings("ignore")

数据基本信息

导入数据

探索数据的基本信息

In [2]:

df = pd.read_csv("train.csv")
df

基本信息

In [3]:

# 1、数据大小
df.shape

Out[3]:

(550068, 12)

In [4]:

# 2、字段类型
df.dtypes

Out[4]:

User_ID                         int64
Product_ID                     object
Gender                         object
Age                            object
Occupation                      int64
City_Category                  object
Stay_In_Current_City_Years     object
Marital_Status                  int64
Product_Category_1              int64
Product_Category_2            float64
Product_Category_3            float64
Purchase                        int64
dtype: object

下面是具体的字段含义为:

  • User_ID:用户编码
  • Product_ID:商品编码
  • Gender:性别(M为男性,F为女性)
  • Age:年龄(0-17,18-25,26-35,36-45,46-50,51-55,55+,7种)
  • Occupation:职业(用数字代表具体职业,一共20种职业)
  • City_Category:城市分类(分为三类城市:ABC)
  • Stay_in_Current_City_Years:在目前城市的居住的年数(0,1,2,3,4+,5种)
  • Marital_Status:婚姻状态(0为未婚,1为已婚)
  • Product_Category_1:产品分类为1(服饰,20种,用1-20表示)
  • Product_Category_2:产品分类为2(电子产品)
  • Product_Category_3:产品分类为3(家具用品)
  • Purchase:购买金额(单位为美元)

In [5]:

# 3、缺失值情况
df.isnull().sum()

Out[5]:

User_ID                            0
Product_ID                         0
Gender                             0
Age                                0
Occupation                         0
City_Category                      0
Stay_In_Current_City_Years         0
Marital_Status                     0
Product_Category_1                 0
Product_Category_2            173638   # 存在缺失值
Product_Category_3            383247
Purchase                           0
dtype: int64

In [6]:

# 4、数据信息
df.info()
'pandas.core.frame.DataFrame'
>
RangeIndex: 550068 entries, 0 to 550067
Data columns (total 12 columns):
 #   Column                      Non-Null Count   Dtype  
---  ------                      --------------   -----  
 0   User_ID                     550068 non-null  int64  
 1   Product_ID                  550068 non-null  object 
 2   Gender                      550068 non-null  object 
 3   Age                         550068 non-null  object 
 4   Occupation                  550068 non-null  int64  
 5   City_Category               550068 non-null  object 
 6   Stay_In_Current_City_Years  550068 non-null  object 
 7   Marital_Status              550068 non-null  int64  
 8   Product_Category_1          550068 non-null  int64  
 9   Product_Category_2          376430 non-null  float64
 10  Product_Category_3          166821 non-null  float64
 11  Purchase                    550068 non-null  int64  
dtypes: float64(2), int64(5), object(5)
memory usage: 50.4+ MB

缺失值可视化

In [7]:

import missingno
df.isna().sum() / df.shape[0]

Out[7]:

User_ID                       


    
0.000000
Product_ID                    0.000000
Gender                        0.000000
Age                           0.000000
Occupation                    0.000000
City_Category                 0.000000
Stay_In_Current_City_Years    0.000000
Marital_Status                0.000000
Product_Category_1            0.000000
Product_Category_2            0.315666  # 缺失值字段
Product_Category_3            0.696727
Purchase                      0.000000
dtype: float64

In [8]:

可以看到有两个字段存在缺失值

# 矩阵图:查看缺失值的分布

missingno.matrix(df)
plt.show()
# 条形图
missingno.bar(df, color="blue")
plt.show()

从下面的图像中也能够观察到只有两个字段存在缺失值

小结1:在我们的数据中包含object、float64和int64共3种数据类型

其中Product_Category_2字段有约31%的缺失占比,Product_Category_3有69%的缺失值占比。

总信息

寻找3个总体的数据信息:

  • 总消费人数
  • 总消费商品种类
  • 总消费金额

In [10]:

# 总消费人数

df["User_ID"].nunique()

Out[10]:

5891

In [11]:

# 总消费商品种类

df["Product_ID"].nunique()

Out[11]:

3631

In [12]:

# 总消费金额
sum(df["Purchase"])

Out[12]:

5095812742

商品类别

In [13]:

# 总消费商品种类

df["Product_Category_1"].nunique()

Out[13]:

20

In [14]:

df["Product_Category_2"].nunique()

Out[14]:

17

画像1:消费金额Top10

In [15]:

不同用户的消费金额对比

df1 = df.groupby("User_ID")["Purchase"].sum().reset_index()

df2 = df1.sort_values("Purchase", ascending=False)
df2["User_ID"] = df2["User_ID"].apply(lambda x: "id_"+str(x))
fig = px.bar(df2[:10],   # 选择前10人
             x="User_ID",
             y="Purchase",
             text="Purchase")

fig.show()

可以看到最高的一位用户花费了1千多万!

画像2:高频消费前10

In [19]:

df3 = df.groupby("User_ID").size().reset_index()

# Number表示购买次数
df3.columns = ["User_ID""Number"]  

# 降序排列
df4 = df3.sort_values("Number", ascending=False)
df4.head(10)
df4["User_ID"


    
] = df4["User_ID"].apply(lambda x: "id_"+str(x))

fig = px.bar(df4[:10],   # 选择前10人
             x="User_ID",
             y="Number",
             text="Number",
             color="Number"
            )

fig.show()

画像3:人均消费金额Top10

In [23]:

df5 = pd.merge(df2, df4)
# 人均消费金额

df5["Average"] = df5["Purchase"] / df5["Number"]
df5["Average"] = df5["Average"].apply(lambda x: round(x,2))
df5.head()
fig = px.scatter(df5, 
                 x="User_ID"
                 y="Average",
                 color="Average")

fig.show()
px.violin(df5["Average"])

从散点分布图和小提琴图中能够看到,大部分用户的平均消费金额在8k到10k之间

画像4:男女消费对比

In [28]:

df6 = df.groupby("Gender").agg({"User_ID":"nunique""Purchase":"sum"}).reset_index()
df6

Out[28]:


GenderUser_IDPurchase
0F16661186232642
1M42253909580100

总结:男士才是消费主力军!

画像5:不同年龄的消费人数和金额

In [30]:

df7 = df.groupby("Age").agg({"User_ID":"nunique""Purchase":"sum"}).reset_index()
df7

Out[30]:


AgeUser_IDPurchase
00-17218134913183
118-251069913848675
226-3520532031770578
336-4511671026569884
446-50531420843403
551-55481367099644
655+372200767375

In [31]:

总结:26到35岁的人群,年轻人,大部分都是工作多年的用户,有家庭和经济基础,成为了消费主力军

画像6:不同性别+年龄的消费人数、金额

In [32]:

df8 = df.groupby(["Gender","Age"]).agg({"User_ID":"nunique""Purchase":"sum"}).reset_index()
df8
fig = px.treemap(
    df8,  # 传入数据
    path=[px.Constant("all"),"Gender","Age"],  
    values="Purchase" # 消费金额
)

fig.update_traces(root_color="lightskyblue")

fig.update_layout(margin=dict(t=30,l=20,r=25,b=30))

fig.show()

画像7:不同城市、年龄消费金额

In [34]:

df9 = df.groupby(["City_Category","Age"]).agg({"User_ID":"nunique""Purchase":"sum"}).reset_index()
df9.head()
fig = px.bar(df9,
             x="City_Category",
             y="Purchase",
             color="Age",
             barmode="group",
             text="Purchase"
            )

fig.update_layout(title="不同城市不同年龄段的消费金额")

fig.show()

从3个城市来看,26-35一直都是消费主力

从上面的柱状图来看,在不同的年龄段,一直保持A < B < C的现象。C城市果真是消费的主要城市

画像8:不同婚姻状态的消费次数和金额

In [37]:

df10 = df.groupby(["Marital_Status"]).agg({"User_ID":"nunique""Purchase":"sum"}).reset_index()
df10

Out[37]:


Marital_StatusUser_IDPurchase
0034173008927447
1124742086885295

In [38]:

df10["Marital_Status"] = df10["Marital_Status"].map({0:"未婚",1:"已婚"})

In [39]:

fig = px.pie(names=df10["Marital_Status"],
             values=df10["Purchase"]
            )

fig.update_traces(
    textposition='inside',   # 文本显示位置:['inside', 'outside', 'auto', 'none']
    textinfo='percent+label'
)

fig.show()

总结:单身自由,就是要买

画像9:城市停留时间

In [41]:

px.violin(df,
          y="Purchase",
          color="Stay_In_Current_City_Years")
df11 = (df.groupby(["Stay_In_Current_City_Years"])
        .agg({"User_ID":"nunique""Purchase":"sum"})
        .reset_index())
df12 = df11.sort_values("User_ID",ascending=False)
df12
stages = df12["Stay_In_Current_City_Years"].tolist()

fig = px.funnel_area(values = df12["User_ID"].tolist(),
                     names = stages
                    )
fig.show()

在一个城市停留1-2年内的用户更容易成为消费主力

画像10:销售额Top20商品

In [46]:

df13 = df.groupby(["Product_ID"]).agg({"Purchase":"sum"}).reset_index()
# 改成以万为单位
df13["Purchase"] = df13["Purchase"].apply(lambda x: round(x / 10000,2))

# 销售额降序
df13.sort_values("Purchase", ascending=False, inplace=True)

df13
fig = px.bar(df13[:10],   # 选择前10人
             x="Product_ID",
             y="Purchase",
             color="Purchase",
             text="Purchase")

fig.update_layout(title="Top20商品销售额对比图(万)")

fig.show()

画像11:二八法则

In [49]:

# 销售额

top20 = int(df13["Product_ID"].nunique() * 0.2)
top20

Out[49]:




    
726

In [50]:

sum(df13[:top20]["Purchase"]) / sum(df13["Purchase"])

Out[50]:

0.7325143993257992

通过计算的结果发现:销售额排名前20的商品其总销售额占据整体的73%,基本上是符合我们听到的二八法则

画像11:商品种类

In [51]:

df14 = df.groupby(["Product_Category_1"]).agg({"Purchase":"sum"}).reset_index()

fig = px.pie(names=df14["Product_Category_1"],
             values=df14["Purchase"],
             hole=0.5
            )

fig.update_traces(
    textposition='inside',   
    textinfo='percent+label'
)

fig.show()
px.box(df,
       x="Product_Category_1",
       y="Purchase",
       color="Product_Category_1")

画像12:不同性别不同种类销售额

In [54]:

第一级

In [56]:

df16 = df15.groupby("Gender")["Purchase"].sum().reset_index()
df16

Out[56]:


GenderPurchase
0F416719106
1M1528099293

In [57]:

df16["Total"] = "总销售额"

In [58]:

df16 = df16[["Total","Gender","Purchase"]]

df16.columns = ["父类","子类","数据"]

df16

Out[58]:


父类子类数据
0总销售额F416719106
1总销售额M1528099293

第二级

In [59]:

df17 = df15.groupby(["Gender","Product_Category_1"])["Purchase"].sum().reset_index()
df17.head()

第三级

In [61]:

df18 = df15.groupby(["Product_Category_1","Product_Category_2"])["Purchase"].sum().reset_index()
df18.head()

Out[61]:

In [62]:

df18.columns = ["父类","子类","数据"]

第四级

In [63]:




    
df19 = df15.groupby(["Product_Category_2","Product_Category_3"])["Purchase"].sum().reset_index()
df19.head()

Out[63]:

In [64]:

df19.columns = ["父类","子类","数据"]

数据合并

In [65]:

df20 = pd.concat([df16,df17,df18,df19],axis=0).reset_index(drop=True)
df20.head()

Out[65]:

子类和父类元素个数

In [66]:

labels = list(set(df20["父类"].tolist() + df20["子类"].tolist()))
labels[:5]

Out[66]:

['c1_3''c3_14''c3_18''c2_4''c2_12']

元素字典设置

In [67]:

number = list(range(0, len(labels)))

index = dict(list(zip(labels, number)))

配对

In [68]:

df20["父类索引"] = df20["父类"].map(index)
df20["子类索引"] = df20["子类"].map(index)
df20

Out[68]:

绘图

In [69]:

从性别、3个不同的商品类别来看:

  • 男性的消费能力远高于女性
  • 在商品1中,1号品类是一个高需求的物品;在商品2中,2号最高,8号其次
  • 在商品3中,头部需求的物品差距缩小,整体的需求更均衡
  • 从商品种类的关联性来看,c1_1、c2_2、c3_15是最强的

往期精彩回顾




Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/135324