来源:阿里云天池,案例:机器学习实践
业界广泛流传着这样一句话:“数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已”,由此可见特征工程在机器学习中的重要性,今天我们将通过《阿里云天池大赛赛题解析——机器学习篇》中的【天猫用户重复购买预测】案例来深入解析特征工程在实际商业场景中的应用。(1)本文特征工程讲解部分参考自图书《阿里云天池大赛赛题解析—机器学习篇》中的第二个赛题:天猫用户重复购买预测。(2)本文相关数据可以在阿里云天池竞赛平台下载,数据地址:https://tianchi.aliyun.com/competition/entrance/231576/information按照上面方法下载好数据集后,我们来看看具体数据含义。test_format1.csv和train_format1.csv里分别存放着测试数据和训练数据,测试数据集最后一个字段为prob,表示测试结果,训练数据集最后一个字段为label,训练数据各字段信息如下图所示:user_log_format1.csv里存放着用户行为日志,字段信息如下图所示:
user_info_format1.csv里存放着用户行基本信息,字段信息如下图所示:本赛题基于天猫电商数据,主要关心用户、店铺和商家这三个实体,所以特征构造上也以用户、店铺和商家为核心,可以分为以下几部分:
用户-店铺特征构造
店铺特征构造对店铺特征选取可以使用,如 Numpy 的 corrcoef(x,y)函数计算相关系数,保留相关系数小于0.9 的特征组合,具体内容如图 2-3。总结以上内容,特征主要基于基础特征、用户特征、店铺特征、用户+店铺四个方面,如下图所示:首先我们导入需要的工具包,进行数据分析和特征提取。import numpy as np
import pandas as pd
import matplotlib.pyplot as plt import seaborn as sns
from scipy import stats
import gc
from collections import Counter import copy
import warnings warnings.filterwarnings("ignore")
%matplotlib inline
直接调用Pandas的read_csv函数读取训练集和测试集及用户信息、用户日志数据。test_data = pd.read_csv('./data_format1/test_format1.csv')
train_data = pd.read_csv('./data_format1/train_format1.csv')
user_info = pd.read_csv('./data_format1/user_info_format1.csv')
user_log = pd.read_csv('./data_format1/user_log_format1.csv')
def reduce_mem_usage(df, verbose=True):
start_mem = df.memory_usage().sum() / 1024**2
numerics = ['int16', 'int32', 'int64', 'float16', 'float32', 'float64']
for col in df.columns: col_type = df[col].dtypes if col_type in numerics:
c_min = df[col].min()
c_max = df[col].max()
if str(col_type)[:3] == 'int':
if c_min > np.iinfo(np.int8).min and c_max df[col] = df[col].astype(np.int8)
elif c_min > np.iinfo(np.int16).min and c_max np.int16).max:
df[col] = df[col].astype(np.int16)
elif c_min > np.iinfo(np.int32).min and c_max df[col] = df[col].astype(np.int32)
elif c_min > np.iinfo(np.int64).min and c_max np.int64).max:
df[col] = df[col].astype(np.int64)
else:
if c_min > np.finfo(np.float16).min and c_max np.float16).max:
df[col] = df[col].astype(np.float16)
elif c_min > np.finfo(np.float32).min and c_max df[col] = df[col].astype(np.float32)
else:
df[col] = df[col].astype(np.float64)
end_mem = df.memory_usage().sum() / 1024**2
print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))
首先测试数据添加到训练数据后,然后将用户基本信息合并到训练数据左边,并删除不需要的变量,释放内存。all_data = train_data.append(test_data)
all_data = all_data.merge(user_info,on=['user_id'],how='left')
del train_data, test_data, user_info
gc.collect()
将用户日志数据各字段合并成一个新的字段item_id,并将其插入到用户信息数据之后。# 用户日志数据按时间排序
user_log = user_log.sort_values(['user_id', 'time_stamp'])
# 合并用户日志数据各字段,新字段名为item_id
list_join_func = lambda x: " ".join([str(i) for i in x])
agg_dict = {
'item_id': list_join_func,
'cat_id': list_join_func,
'seller_id': list_join_func,
'brand_id': list_join_func,
'time_stamp': list_join_func,
'action_type': list_join_func
}
rename_dict = {
'item_id': 'item_path',
'cat_id': 'cat_path',
'seller_id': 'seller_path',
'brand_id': 'brand_path',
'time_stamp': 'time_stamp_path',
'action_type': 'action_type_path'
}
def merge_list(df_ID, join_columns, df_data, agg_dict, rename_dict):
df_data = df_data.groupby(join_columns).agg(agg_dict).reset_index().rename(
columns=rename_dict)
df_ID = df_ID.merge(df_data, on=join_columns, how="left")
return df_ID
all_data = merge_list(all_data, 'user_id', user_log, agg_dict, rename_dict)
del user_log
gc.collect()
基于之前的特征构造图,我们提前编写一些统计相关函数,依次有:数据总数、数据唯一值总数、数据最大值、数据最小值、数据标准差、数据中top N数据以及数据中top N数据的总数。def cnt_(x):
try:
return len(x.split(' '))
except:
return -1
def nunique_(x):
try:
return len(set(x.split(' ')))
except:
return -1
def max_(x):
try:
return np.max([float(i) for i in x.split(' ')])
except:
return -1
def min_(x):
try:
return np.min([float(i) for i in x.split(' ')])
except:
return -1
def std_(x):
try:
return np.std([float(i) for i in x.split(' ')])
except:
return -1
def most_n(x, n):
try:
return Counter(x.split(' ')).most_common(n)[n-1][0]
except:
return -1
def most_n_cnt(x, n):
try:
return Counter(x.split(' ')).most_common(n)[n-1][1]
except:
return -1
基于上面编写的基本统计方法,我们可以针对数据进行特征统计。def user_cnt(df_data, single_col, name):
df_data[name] = df_data[single_col].apply(cnt_)
return df_data
def user_nunique(df_data, single_col, name):
df_data[name] = df_data[single_col].apply(nunique_)
return df_data
def user_max(df_data, single_col, name):
df_data[name] = df_data[single_col].apply(max_)
return df_data
def user_min(df_data, single_col, name):
df_data[name] = df_data[single_col].apply(min_)
return df_data
def user_std(df_data, single_col, name):
df_data[name] = df_data[single_col].apply(std_)
return df_data
def user_most_n(df_data, single_col, name, n=1):
func = lambda x: most_n(x, n)
df_data[name] = df_data[single_col].apply(func)
return df_data
def user_most_n_cnt(df_data, single_col, name, n=1):
func = lambda x: most_n_cnt(x, n)
df_data[name] = df_data[single_col].apply(func)
return df_data
基于上一步中编写的用户数据统计函数,以店铺特征统计为例,统计与店铺特点有关的特征,如店铺、商品、品牌等。# 取2000条数据举例
all_data_test = all_data.head(2000)
# 总次数
all_data_test = user_cnt(all_data_test, 'seller_path', 'user_cnt')
# 不同店铺个数
all_data_test = user_nunique(all_data_test, 'seller_path', 'seller_nunique ')
# 不同品类个数
all_data_test = user_nunique(all_data_test, 'cat_path', 'cat_nunique')
# 不同品牌个数
all_data_test = user_nunique(all_data_test, 'brand_path',
'brand_nunique')
# 不同商品个数
all_data_test = user_nunique(all_data_test, 'item_path', 'item_nunique')
# 活跃天数
all_data_test = user_nunique(all_data_test, 'time_stamp_path',
'time_stamp _nunique')
# 不同用户行为种数
all_data_test = user_nunique(all_data_test, 'action_type_path',
'action_ty pe_nunique')
此外还可以统计用户最喜欢的店铺、最喜欢的类目、最喜欢的品牌、最长见的行为动作等数据。