ITPub博客

首页 > 数据库 > 数据库开发技术 > 竞赛姿势必会:特征工程中的奇淫技巧

竞赛姿势必会:特征工程中的奇淫技巧

原创 数据库开发技术 作者:quincyqiang 时间:2021-05-02 10:18:53 0 删除 编辑

前言

结合之前的手动特征工程Part1更好理解特征解释性 & Featuretools自动特征工程,这是特征工程系列的第三篇文章了,这里将会介绍一些奇淫技巧,这些方法其实已经占据我们特征工程工作中的绝大部分,希望对你有所帮助。

NAN值处理

如果给出np.nan到LGBM,然后在每个树节点上拆分,它会拆分非nan值,然后根据哪个最好将所有nan发送给左子节点或右子节点。因此,nan在每个节点上都得到了特殊处理,可能会出现过拟合。通过简单地将所有NAN转换为小于所有非NAN值的负数(例如-999);

df = pd.concat([train[col],test[col]],axis=0)
df[col].fillna(-999, inplace=True)

那么LGBM将不再过度处理NAN。相反,它将给予它和其他数字一样的关注。过拟合虽然不是很好,但是两种方法都试一试,看看哪一种线下分数反馈最高。

目标编码/分解/内存减少

目标编码(分解)将一个(string,categroy,object)列转换为整数。之后,您可以根据max是否小于128,小于32768,或者更大,将其强制转换为int8, int16或int32。分解会减少内存,并将NAN变成一个影响如上所述的CV和LB的数字(即-1)。分解还可以选择将类别变量视为如下所述的数值;

df[col],_ = df[col].factorize()

if df[col].max()<128: df[col] = df[col].astype('int8')
elif df[col].max()<32768: df[col] = df[col].astype('int16')
else: df[col].astype('int32')

此外,为了减少内存,人们在其他列上使用流行的memory_reduce函数。一种更简单、更安全的方法是将所有float64转换为float32,将所有int64转换为int32。

for col in df.columns:
    if df[col].dtype=='float64': df[col] = df[col].astype('float32')
    if df[col].dtype=='int64': df[col] = df[col].astype('int32')

或者使用封装好的memory_reduce函数

def reduce_mem(df):
    start_mem = df.memory_usage().sum() / 1024 ** 2
    for col in df.columns:
        col_type = df[col].dtypes
        if col_type != object:
            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 < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).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('{:.2f} Mb, {:.2f} Mb ({:.2f} %)'.format(start_mem, end_mem, 100 * (start_mem - end_mem) / start_mem))
    gc.collect()
    return df

类别特征编码

对于类别变量,你可以选择告诉LGBM它们是类别的,或者你可以告诉LGBM把它当作数字(事先标记编码)。无论哪种方式,LGBM都可以提取类别特征。两种方法都试一试,看看哪一种线下反馈最高。在目标编码之后,对category执行以下操作,或者对numeric将其保留为int

df[col] = df[col].astype('category')

字符切分

单列(字符串或数字)可以通过拆分变成两列。

  • 例如字符串列“id_30”(如Mac OS X 10_9_5)可以分为操作系统“Mac OS X”和版本号“Version 10_9_5”(这就造出两个特征)。

  • 例如数字列TransactionAmt 1230.45可以分为美元1230和美分45。

LGBM不能单独看到这些碎片,你需要把它们分开。

组合/转换/交叉

两个(字符串或数字)列可以合并成一个列。例如card1和card2可以成为一个新的列

df['uid'] = df[‘card1’].astype(str)+’_’+df[‘card2’].astype(str)

这有助于LGBM模型学习,因为card1和card2本身可能与目标不相关,因此LGBM不会在树节点上分割它们。但是交叉特征uid = card1_card2可能与target相关,现在LGBM将对其进行拆分。

数字列可以与加、减、乘、除等相结合。一个数字例子是:

df['x1_x2'] = df['x1'] * df['x2']

频率编码

频率编码是一种强大的技术,它允许LGBM查看列值是罕见的还是常见的(即频率高低)。例如,如果你想让LGBM学习到哪些信用卡不常使用,比如

temp = df['card1'].value_counts().to_dict()
df['card1_counts'] = df['card1'].map(temp)

Aggregations/Group统计

为LGBM提供组的统计信息允许LGBM确定某个值对于特定组是常见的还是罕见的。通过pandas提供3个变量来计算组的统计信息,例如

temp = df.groupby('card1')['TransactionAmt'].agg(['mean'])   
    .rename({'mean':'TransactionAmt_card1_mean'},axis=1)
df = pd.merge(df,temp,on='card1',how='left')

这里的特征向每行添加该行card1组的平均TransactionAmt。因此,LGBM现在可以判断一行是否有其card1组的异常TransactionAmt。

自身列、其他列标准化/归一化

对列本身归一化

df[col] = ( df[col]-df[col].mean() ) / df[col].std() 

或者你可以将一列与另一列标准化。比如,创建了一个组的统计信息来表示D3的平均值。然后你可以通过下面计算,新变量D3_remove_time不再随着时间的推移而增加,因为我们已经根据时间的影响对其进行了规范化。

df['D3_remove_time'] = df['D3'] - df['D3_week_mean']

离群值移除/平滑/PCA

通常情况下,我们希望消除数据中的异常值,因为他们会影响我们的模型学习能力。这个时候可以考虑使用平滑技术,这个方法背后的思想是确定和删除不常见的值。

  • 例如,通过使用变量的频率编码,可以删除所有显示小于0.1%的值,方法是用-9999这样的新值替换它们(注意,应该使用与用于NAN不同的值)。

如果这对你的工作生活有帮助,点赞关注一键三连,支持我的工作。

原文来自知乎,点击阅读原文,获取更多内容。


扫码加我好友进微信群|QQ群



原文作者:ChallengeHub;如有侵权,请联系管理员删除。

请登录后发表评论 登录
全部评论

注册时间:2019-01-07

  • 博文量
    350
  • 访问量
    161028