作者:Peter 编辑:Peter
本文还是kaggle上一份黑色星期五消费数据的分析,主要是针对用户和商品信息的画像分析。建模的方案参考文章:
kaggle实战:星期五黑了,随机森林输了!
本文重点是可视化,使用的图形:柱状图、饼图、散点图、小提琴图、桑基图、树状图、漏斗图、多子图等,全部是Plotly库绘制。
关键词:用户画像、可视化、plotly、Pandas
导入库 import pandas as pdimport numpy as npimport matplotlib.pyplot as pltimport seaborn as sns import matplotlib.patches as mpatchesimport matplotlib# 中文显示问题 plt.rcParams["font.sans-serif" ]=["SimHei" ] #设置字体 plt.rcParams["axes.unicode_minus" ]=False #正常显示负号 import plotly.graph_objects as goimport plotly.express as pxfrom plotly.subplots import make_subplotsfrom 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
下面是具体的字段含义为:
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(家具用品) 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]:
Gender User_ID Purchase 0 F 1666 1186232642
1 M 4225 3909580100
总结:男士才是消费主力军!
画像5:不同年龄的消费人数和金额 In [30]:
df7 = df.groupby("Age" ).agg({"User_ID" :"nunique" , "Purchase" :"sum" }).reset_index() df7
Out[30]:
Age User_ID Purchase 0 0-17 218 134913183 1 18-25 1069 913848675 2 26-35 2053 2031770578 3 36-45 1167 1026569884 4 46-50 531 420843403 5 51-55 481 367099644
6 55+ 372 200767375
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_Status User_ID Purchase 0 0 3417 3008927447 1 1 2474 2086885295
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]:
Gender Purchase 0 F 416719106
1 M 1528099293
In [57]:
df16["Total" ] = "总销售额"
In [58]:
df16 = df16[["Total" ,"Gender" ,"Purchase" ]] df16.columns = ["父类" ,"子类" ,"数据" ] df16
Out[58]:
父类 子类 数据 0 总销售额 F 416719106 1 总销售额 M 1528099293
第二级 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是最强的