揭秘黑色星期五:深度学习略胜随机森林
本文是kaggle的一个新案例,使用是一份关于国外黑色星期五的消费数据。
西方国家的黑色星期五类似我国的“双十一”活动,会产生很多的消费数据。
本数据提供了黑色星期五当天用户精选大批量产品产生的购买信息,主要包含两部分:
-
客户人口统计信息(年龄,性别,婚姻状况,城市类别,定居时长)
-
商品详细信息(商品id和商品类别)以及总购买金额
导入库
1 | import pandas as pd |
数据基本信息
1 | df1 = pd.read_csv("train.csv") |
数据基本信息:
In [3]:
1 | df1.shape |
Out[3]:
总共是55万+的数据:
1 | (550068, 12) |
In [4]:
1 | columns = df1.columns # 全部的字段 |
Out[4]:
1 | Index(['User_ID', 'Product_ID', 'Gender', 'Age', 'Occupation', 'City_Category', |
In [5]:
1 | df1.dtypes |
Out[5]:
1 | User_ID int64 |
In [6]:
1 | # 不同字段类型的占比 |
字段基本信息
缺失值情况
查看整体数据的缺失值情况,后面会专门处理缺失值:
统计与可视化分析
从不同的角度对数据进行数量统计和可视化的分析
性别分析
In [9]:
1 | df2 = df1["Gender"].value_counts().reset_index() |
Out[9]:
index | Gender | |
---|---|---|
0 | M | 414259 |
1 | F | 135809 |
In [10]:
不同性别下的数量分布统计:
1 | colors = ["red", "blue"] |
不同性别下的数量占比统计:
1 | # 统计不同性别的个数 |
职位分析
In [12]:
1 | df3 = df1["Occupation"].value_counts().sort_index().reset_index() |
Out[12]:
index | Occupation | |
---|---|---|
0 | 0 | 69638 |
1 | 1 | 47426 |
2 | 2 | 26588 |
3 | 3 | 17650 |
4 | 4 | 72308 |
In [13]:
1 | fig = px.bar(df3, |
不同职位下的数量统计:可以看到0-4-7的职位消费人数是最多的
下面是基于seaborn的统计方法:
1 | palette=sns.color_palette("Set2") |
每个职位的总消费
不同职位下的消费总金额:
In [69]:
1 | sum_by_occ = df1.groupby('Occupation')['Purchase'].sum() |
年龄段
In [16]:
1 | df4 = df1["Age"].value_counts().reset_index().sort_values("index") |
Out[16]:
index | Age | |
---|---|---|
6 | 0-17 | 15102 |
2 | 18-25 | 99660 |
0 | 26-35 | 219587 |
1 | 36-45 | 110013 |
3 | 46-50 | 45701 |
4 | 51-55 | 38501 |
5 | 55+ | 21504 |
In [17]:
1 | fig = px.pie(df4, names="index",values="Age") |
柱状图的表示方法:
性别+年龄段
In [19]:
1 | columns |
Out[19]:
1 | Index(['User_ID', 'Product_ID', 'Gender', 'Age', 'Occupation', 'City_Category', |
In [20]:
1 | df5 = df1.groupby(["Gender", "Age"]).size().reset_index() |
Out[20]:
Gender | Age | Number | |
---|---|---|---|
0 | F | 0-17 | 5083 |
1 | F | 18-25 | 24628 |
2 | F | 26-35 | 50752 |
3 | F | 36-45 | 27170 |
4 | F | 46-50 | 13199 |
5 | F | 51-55 | 9894 |
6 | F | 55+ | 5083 |
7 | M | 0-17 | 10019 |
8 | M | 18-25 | 75032 |
9 | M | 26-35 | 168835 |
10 | M | 36-45 | 82843 |
11 | M | 46-50 | 32502 |
12 | M | 51-55 | 28607 |
13 | M | 55+ | 16421 |
In [21]:
1 | fig = px.bar(df5, x="Age", y="Number", color="Gender", text="Number") |
城市属性分析
In [72]:
1 | plt.rcParams['figure.figsize'] = (18, 9) |
停留年限df6-Stay_In_Current_City_Years
下面是对停留年限字段的统计分析:
In [23]:
1 | df6 = df1["Stay_In_Current_City_Years"].value_counts().reset_index() |
Out[23]:
index | Stay_In_Current_City_Years | |
---|---|---|
0 | 1 | 193821 |
1 | 2 | 101838 |
2 | 3 | 95285 |
3 | 4+ | 84726 |
4 | 0 | 74398 |
In [24]:
1 | fig = px.pie(df6, names="index",values="Stay_In_Current_City_Years") |
婚姻状态Marital_Status
0-未婚 1-已婚
In [25]:
1 | df1["Marital_Status"].value_counts(normalize=True) |
Out[25]:
1 | 0 0.590347 |
Product_Category_1
In [26]:
1 | df8 = df1["Product_Category_1"].value_counts(normalize=True).reset_index() |
Out[26]:
index | Product_Category_1 | |
---|---|---|
0 | 5 | 0.274390 |
1 | 1 | 0.255201 |
2 | 8 | 0.207111 |
3 | 11 | 0.044153 |
4 | 2 | 0.043384 |
In [27]:
下面的图形显示的是Product_Category_1字段中每个取值的占比,主要集中在1-5-8
1 | fig = px.bar(df8, x="index",y="Product_Category_1") |
查看字段Product_Category_1的相关统计信息:
同样的方法可以查看Product_Category_2和Product_Category_3的相关分布和统计信息。
缺失值处理
查看缺失值
In [29]:
1 | df1.isnull().sum() |
Out[29]:
1 | User_ID 0 |
缺失值处理
缺失值的处理方式:
- 删除缺失值的数据
- 填充缺失值:用0填充、均值或其他统计值填充、前向或后向的值填充、KNN算法的差值填充
方法1:均值填充
In [30]:
1 | # 针对Product_Category_2 |
Out[30]:
1 | 9.0 |
In [31]:
1 | df1["Product_Category_2"].fillna(median, inplace=True) # 填充均值 |
assert断言是否有缺失值:
In [32]:
1 | df1.isnull().sum() |
Out[32]:
1 | User_ID 0 |
方法2:前后项填充
In [33]:
1 |
|
我们发现Product_Category_3字段在首尾都存在缺失值,因此我们使用前后项同时填充的方法:
目标变量正态化
将目标变量Purchase进行正态化
In [38]:
1 | from scipy import stats |
In [39]:
1 | plt.rcParams['figure.figsize'] = (20, 7) |
字段处理
删除无效字段
In [40]:
1 | df1.drop(["User_ID", "Product_ID"], inplace=True, axis=1) |
In [41]:
1 | df1.columns |
Out[41]:
1 | Index(['Gender', 'Age', 'Occupation', 'City_Category', |
字符型字段
In [42]:
1 | df9 = df1.select_dtypes(include="object") |
Out[42]:
1 | Index(['Gender', 'Age', 'City_Category', 'Stay_In_Current_City_Years'], dtype='object') |
In [43]:
1 | df10 = df1.select_dtypes(exclude="object") # 数值型变量 |
特征工程
哑变量
对字符型字段进行独热码,生成哑变量
In [44]:
1 | df_Gender = pd.get_dummies(df1['Gender']) |
合并
In [45]:
1 | df11 = pd.concat([df10, df_Gender, df_Age, df_City_Category, df_Stay_In_Current_City_Years], axis=1) |
标准化
In [46]:
1 | from sklearn.preprocessing import StandardScaler |
In [47]:
1 | X = df11.drop("Purchase", axis=1) |
In [48]:
1 | columns = X.columns |
In [49]:
1 | ss = StandardScaler() |
Out[49]:
数据分割
In [50]:
1 | # 切分比例为8:2 |
Out[50]:
1 | (440054, 22) |
线性回归
建模
In [51]:
1 | from sklearn.linear_model import LinearRegression |
Out[51]:
1 | LinearRegression() |
In [52]:
1 | LinearRegression(copy_X=True, |
Out[52]:
1 | LinearRegression(normalize=False) |
In [53]:
1 | print('Intercept parameter:', lr.intercept_) |
预测
对测试集的预测
In [54]:
1 | predictions = lr.predict(X_test) |
Out[54]:
1 | array([ 7982.58970335, 9525.58970335, 7910.58970335, ..., |
评价指标
In [55]:
1 | from sklearn import metrics |
随机森林回归
建模
随机森林中3个重要的属性:
- 查看森林中树的状况:estimators_
- 袋外估计准确率得分:oob_score_,必须是oob_score参数选择True的时候才可用
- 变量的重要性:feature_importances_
In [56]:
1 | from sklearn.ensemble import RandomForestRegressor |
Out[56]:
1 | RandomForestRegressor(max_depth=5) |
预测
In [57]:
1 | predictions_rf = rf.predict(X_test) |
Out[57]:
1 | array([ 7895.32997516, 6153.32785418, 7895.32997516, ..., |
评价指标
In [58]:
1 | from sklearn import metrics |
基于keras神经网络
数据缩放
神经网络中输入的数据一般都是比较小的,我们将输出y_train和y_test缩小10000倍,即以万为单位:
In [59]:
1 | import tensorflow as tf |
In [60]:
1 | y_train /= 10000 |
构建网络
In [61]:
1 | model = models.Sequential() |
编译网络
In [62]:
1 | model.compile(optimizer="rmsprop", # 优化器 |
训练网络
In [63]:
1 | history = model.fit(X_train, |
指标可视化
In [64]:
1 | mae_history = history.history["mae"] |
In [65]:
1 | len(mae_history) |
Out[65]:
1 | 100 |
In [66]:
1 | # 损失绘图 |
模型预测
In [67]:
1 | model.evaluate(X_test, y_test) |
Out[67]:
1 | [0.09745179861783981, 0.2381529062986374] |
对比
3种方案的对比(深度学习的指标中得到的结果需要进行转化还原)
LOSS(MSE) | MAE | |
---|---|---|
线性回归 | 21,934,597 | 3591 |
随机森林回归 | 10,568,250 | 2396 |
深度学习Keras | 0.09745(9,745,000) | 0.2381(2381) |
所以来说:深度学习还是略胜一筹!