一、特征工程
首先需要对得到的数据进一步进行特征工程处理。一般来说,对于已经清洗完的数据,特征工程部分核心需要考虑的问题就是特征创建(衍生)与特征筛选,也就是先尽可能创建/增加可能对模型结果有正面影响的特征,然后再对这些进行挑选,以保证模型运行稳定性及运行效率。当然,无论是特征衍生还是特征筛选,其实都有非常多的方法。此处为了保证公开课提供的思路和方法具有通用性,此处列举两种特征衍生的方法,即创建通用组合特征与业务统计特征;并在特征创建完毕后,介绍一种基础而通用的特征筛选的方法:基于皮尔逊相关系数的Filter方法进行特征筛选。这些方法都是非常通用且有效的方法,不仅能够帮助本次建模取得较好的成果,并且也能广泛适用到其他各场景中。
1.通用组合特征创建
1.1 通用组合特征的创建方法
首先是尝试创建一些通用组合特征。
所谓通用组合特征,指的是通过统计不同离散特征在不同取值水平下、不同连续特征取值之和创建的特征,并根据card_id进行分组求和。具体创建过程我们可以如下简例来进行理解:
目的是充分利用特征,为一个cardid添加更多的维度
如何转换
import gc
import time
import numpy as np
import pandas as pd
from datetime import datetime
# 借助字典创建DataFrame
d1 = {'card_id':[1, 2, 1, 3],
'A':[1, 2, 1, 2],
'B':[2, 1, 2, 2],
'C':[4, 5, 1, 5],
'D':[7, 5, 4, 8],}
t1 = pd.DataFrame(t1)
t1
# 标注特征类别
numeric_cols = ['C', 'D']
category_cols = ['A', 'B']
# 创建一个以id为key、空字典为value的字典
features = {}
card_all = t1['card_id'].values.tolist()
for card in card_all:
features[card] = {}
至此我们就完成了在极简数据集上进行通用组合特征的创建工作。
当然,通过上述过程不难发现,这种特征创建的方式能够非常高效的表示更多数据集中的隐藏信息,不过该方法容易产生较多空值,在后续建模过程中需要考虑特征矩阵过于稀疏从而带来的问题。
train = pd.read_csv('preprocess/train_pre.csv')
test = pd.read_csv('preprocess/test_pre.csv')
transaction = pd.read_csv('preprocess/transaction_d_pre.csv')
# 标注离散字段or连续型字段
numeric_cols = ['purchase_amount', 'installments']
category_cols = ['authorized_flag', 'city_id', 'category_1',
'category_3', 'merchant_category_id','month_lag','most_recent_sales_range',
'most_recent_purchases_range', 'category_4',
'purchase_month', 'purchase_hour_section', 'purchase_day']
id_cols = ['card_id', 'merchant_id']
# 创建字典用于保存数据
features = {}
card_all = train['card_id'].append(test['card_id']).values.tolist()
for card in card_all:
features[card] = {}
# 标记不同类型字段的索引
columns = transaction.columns.tolist()
idx = columns.index('card_id')
category_cols_index = [columns.index(col) for col in category_cols]
numeric_cols_index = [columns.index(col) for col in numeric_cols]
# 记录运行时间
s = time.time()
num = 0
# 执行循环,并在此过程中记录时间
for i in range(transaction.shape[0]):
va = transaction.loc[i].values
card = va[idx]
for cate_ind in category_cols_index:
for num_ind in numeric_cols_index:
col_name = '&'.join([columns[cate_ind], va[cate_ind], columns[num_ind]])
features[card][col_name] = features[card].get(col_name, 0) + va[num_ind]
num += 1
if num%1000000==0:
print(time.time()-s, "s")
del transaction
gc.collect()
该过程并不复杂,可以通过pandas中的groupby过程迅速实现。和此前特征构造的思路不同,通过该方法构造的特征,不会存在大量的缺失值,并且新增的列也将相对较少。代码实现过程如下:
transaction = pd.read_csv('preprocess/transaction_g_pre.csv')
# 标注离散字段or连续型字段
numeric_cols = ['authorized_flag', 'category_1', 'installments',
'category_3', 'month_lag','purchase_month','purchase_day','purchase_day_diff', 'purchase_month_diff',
'purchase_amount', 'category_2',
'purchase_month', 'purchase_hour_section', 'purchase_day',
'most_recent_sales_range', 'most_recent_purchases_range', 'category_4']
categorical_cols = ['city_id', 'merchant_category_id', 'merchant_id', 'state_id', 'subsector_id']
# 创建空字典
aggs = {}
# 连续/离散字段统计量提取范围
for col in numeric_cols:
aggs[col] = ['nunique', 'mean', 'min', 'max','var','skew', 'sum']
for col in categorical_cols:
aggs[col] = ['nunique']
aggs['card_id'] = ['size', 'count']
cols = ['card_id']
# 借助groupby实现统计量计算
for key in aggs.keys():
cols.extend([key+'_'+stat for stat in aggs[key]])
df = transaction[transaction['month_lag']<0].groupby('card_id').agg(aggs).reset_index()
df.columns = cols[:1] + [co+'_hist' for co in cols[1:]]
df2 = transaction[transaction['month_lag']>=0].groupby('card_id').agg(aggs).reset_index()
df2.columns = cols[:1] + [co+'_new' for co in cols[1:]]
df = pd.merge(df, df2, how='left',on='card_id')
df2 = transaction.groupby('card_id').agg(aggs).reset_index()
df2.columns = cols
df = pd.merge(df, df2, how='left',on='card_id')
del transaction
gc.collect()
# 生成训练集与测试集
train = pd.merge(train, df, how='left', on='card_id')
test = pd.merge(test, df, how='left', on='card_id')
del df
train.to_csv("preprocess/train_groupby.csv", index=False)
test.to_csv("preprocess/test_groupby.csv", index=False)
gc.collect()