背景

离散型变量在某些机器学习任务中经常出现,有时离散型变量是否能够充分使用直接关系到我们训练的模型性能。

虽然现在很多常用的机器学习方法都对离散型变量有了很好的支持,比如catboost、lightGBM等,但有时为了方便比较和尝试更多的模型方案,离散型变量的处理仍然是我们需要解决的问题。

本文的重点在于对现有的常用离散变量处理方法进行梳理,并提供相应的方法函数供读者参考。由于能力有限其中难免有所梳理,欢迎大家多多指教,共同学习、共同进步!

P.S. 由于精力有限,关于是什么和为什么的问题就不在此浪费时间讨论了,我们直接从怎么做入手开始我们今天的探讨。

概述

今天主要介绍以下几种方法,方法都是将离散变量(值为整数或者字符串)转换成大多数模型所支持的数值型变量。不仅提供了测试代码,还提供了工程上可实操的代码。至于其他的一些特殊的离散列编码方式如FC,目标列编码等,由于篇幅原因我们将新开一篇博客讨论。

方法一 OneHotEnCoder  方法四 LableEncoder
方法二 get_dummies方法五 OrdinalEncoder
方法三 DictVectorizer方法六 dict直接映射

方法一二三主要是升维的方法,实际过程中尽量谨慎使用。

方法四五六则不需要升维,在离散变量取值较多时推荐使用。

数据

本文数据为比较典型的城市数据,维度(4942, 2),城市共有439个取值,我们看看这样的数据经过转换后会变成什么样子。

正文开始

方法一:OneHotEncoder

from sklearn.preprocessing import OneHotEncoder
oe = OneHotEncoder(sparse=False)
oe_res = oe.fit_transform(df[['city']])
oe_res = pd.DataFrame(oe_res)
df[['city']].shape
Out[39]: (4942, 1)
oe_res.shape
Out[40]: (4942, 440)

可以看到当前的city变量被展开成了440列,每一列代表一个city的取值,高维稀疏。

 工程实操

工程上分两步:1.命名列名,2.拼接dataframe

from sklearn.preprocessing import OneHotEncoder
oe = OneHotEncoder(sparse=False)
oe_res = oe.fit_transform(df[['city']])
oe_res = pd.DataFrame(oe_res, columns=oe.get_feature_names())
df = pd.merge(df, oe_res, left_index=True, right_index=True)

最后效果是这样子的:会在原始数据集上多出很多列。可见这种方法在离散变量取值非常多的情况并不适用。

 推荐在离散变量取值小于10时使用该方法。代码如下


def categorical2numerical(dfx, cat_cols, method=None):
    if method == 'onehot':
        oe_cols, err_cols = [], []
        for col in cat_cols:
            if dfx[col].nunique() < 10:
                oe_cols.append(col)
            else:
                print('取值超过10不适合使用one hot')
                err_cols.append(col)  # 后续继续处理
        oe = OneHotEncoder(sparse=False)
        oe_res = oe.fit_transform(dfx[oe_cols])
        oe_res = pd.DataFrame(oe_res, columns=oe.get_feature_names())
        dfx = pd.merge(dfx.reset_index(), oe_res.reset_index(), left_index=True, right_index=True)
        return dfx

方法二:DictVectorizer

比较简单,话不多说直接应用

from sklearn.feature_extraction import DictVectorizer
dv = DictVectorizer(sparse=False)
dv_res = dv.fit_transform(df[['city']].to_dict(orient='record'))
de_res = pd.DataFrame(dv_res, columns=dv.feature_names_)
df = pd.merge(df, de_res, left_index=True, right_index=True)

效果如下,可以看到最终效果和onehot没什么区别一样的440列。应用上应该也区别不大。

方法三:Dummy

很简单只需要一行代码

dm = pd.get_dummies(df['city'], columns=df['city'].nunique())

效果和上面两个是一样的。

 

 

方法四\五 LabelEncoder\OrdinalEncoder

代码如下,转换结果也一致,推荐直接使用OrdinalEncoder

from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
le_res = pd.DataFrame(le.fit_transform(df[['city']]))
le_res = le_res.T

from sklearn.preprocessing import OrdinalEncoder
oe = OrdinalEncoder()
oe_res = pd.DataFrame(oe.fit_transform(df[['city']].fillna('nan')))

res = pd.merge(le_res, oe_res, left_index=True, right_index=True)

 

 

方法六:Dict替换

比较简单,举个栗子吧。

resdf['user_stat'] = resdf['user_stat'].replace({'active': 1.0, 'inactive': 0.0})

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐