紧接上次的分析初探,进行进一步特征工程的详细分析。
1.数据准备
1.1导入工具包
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import lightgbm as lgb
import gc
%matplotlib inline
1.2导入数据
path = '/home/WLY/learn/Kaggle_example_learn/Instacart/Data/'
aisles = pd.read_csv(path + 'aisles.csv')
departments = pd.read_csv(path + 'departments.csv')
products = pd.read_csv(path + 'products.csv')
orders = pd.read_csv(path + 'orders.csv')
order_products__train = pd.read_csv(path + 'order_products__train.csv')
order_products__prior = pd.read_csv(path + 'order_products__prior.csv')
2.特征工程
特征工程在很多比赛中的作用十分重要,有句话说的是:
数据和特征决定机器学习的上限,而算法只是用来逼近这个上限
接下来以推荐问题为例,介绍基本的推荐算法的特征工程
将该赛题的特征工程粗略得分为几个模块:
- 用户特征
- 产品特征
- 用户产品特征
2.1用户特征
新建一个DataFrame存储用户特征
user_fea=pd.DataFrame()
新增一列用户id,得到用户id的取值情况
user_fea['user_id']=orders['user_id'].unique()
将用户id的取值排序
user_fea=user_fea[['user_id']].sort_values('user_id')
2.1.1用户购物总次数
将orders数据集按照用户id分组,统计order_id的次数,即得到用户购物的总次数
user_fea['user_orderid_count']=orders.groupby('user_id')['order_id'].count().values
2.1.2用户购物频繁度
根据orders数据集中的days_since_prior_order用户本单购物与上一次的时间间隔来得出以下情况:
1.若用户购买的平均相隔天数少,说明用户是爱频繁购物的,则有可能会不断地消费某些产品
2.若用户距离上次购物的最大天数都很小,则证明用户非常爱购物
3.若用户距离上次购物的时间的方差较小,说明用户购物具有较强的周期性
4.用户距离上次购买产品的众数较小,证明用户爱购物
user_fea['user_days_since_prior_order_mean']=orders.groupby('user_id')['days_since_prior_order'].mean().values
user_fea['user_days_since_prior_order_max'] = orders.groupby('user_id')['days_since_prior_order'].max().values
user_fea['user_days_since_prior_order_std'] = orders.groupby('user_id')['days_since_prior_order'].std().values
user_fea['user_days_since_prior_order_mode'] = orders.groupby('user_id')['days_since_prior_order'].apply(lambda x: x.mode()[0]).values
user_fea.head()
2.1.3用户时间喜好
根据orders数据集中的order_dow和order_hour_of_day用户购买的星期几和时间点得出以下情形:
根据用户购买的星期数和时间点的众数,可能得知用户的一些生活习惯等
user_fea['user_order_dow_mode'] = orders.groupby('user_id')['order_dow'].apply(lambda x: x.mode()[0]).values
user_fea['user_order_hour_of_day_mode'] = orders.groupby('user_id')['order_hour_of_day'].apply(lambda x: x.mode()[0]).values
补充一个二阶的用户时间喜好特征,用来表示用户喜欢在每周晚上几点开始购物?对于该特征还有些疑问。。。
orders['dow_hour'] = orders['order_dow'].values * 25 + orders['order_hour_of_day'].values
user_fea['user_dow_hour_mode'] = orders.groupby('user_id')['dow_hour'].apply(lambda x: x.mode()[0]).values
user_fea.head()
2.1.4用户商品喜好特征
注意此处以priors数据集进行商品特征的提取,为什么不结合train一起呢?
原因是这样数据量更大,主要考虑到test中并无类似的特征,而且test用户并没有出现在train中,
因而这样提取特征是有问题的,因为训练集中的特征来源于prior和train,但test只来源于prior,可能会有所偏差
思考:
将order_product__prior_和orders拼接,根据拼接的数据集得到以下的情形:
用户购买不同产品的数量,即产品的种类
用户购买最多的三种产品,若用户只购买了两类产品,则最后一种产品用-1表示
用户购买所有产品的数量
用户平均每一单购买产品的数量
order_product_prior_=order_products__prior.merge(orders,on='order_id',how='left')
将prior_数据集按照用户id分组,统计不同产品的数量,即产品的种类数
user_fea['user_product_nunique']=order_product_prior_.groupby('user_id')['product_id'].nunique().sort_index().values
定义函数来计算众数,最多的三种产品情况
def mode_N(x,i):
m = x.value_counts().index
if len(m) > i:
return m[i]
return -1
user_fea['user_product_mode'] = order_product_prior_.groupby('user_id')['product_id'].apply(lambda x: x.mode()[0]).sort_index().values
user_fea['user_product_mode_1'] = order_product_prior_.groupby('user_id')['product_id'].apply(l