机器学习中的离散变量处理

离散变量处理在机器学习中的策略
本文探讨了在机器学习中如何处理离散变量,包括OneHotEncoder、DictVectorizer、Dummy、LabelEncoder和OrdinalEncoder等方法。重点介绍了各种方法的适用场景,例如OneHotEncoder适用于取值较少的离散变量,而LabelEncoder和OrdinalEncoder对于取值较多的离散变量更为合适。此外,还提供了实际操作的代码示例。

背景

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

虽然现在很多常用的机器学习方法都对离散型变量有了很好的支持,比如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})

机器学习处理离散值有多种方法,以下为您介绍分箱和95分位数盖帽法: ### 分箱法 分箱是一种重要的数据预处理方法,有诸多优势。离散特征的增减容易,利于模型快速迭代。稀疏向量内积乘法运算速度快,计算结果便于存储和扩展。离散化后的特征对异常数据有较强鲁棒性,例如将年龄特征离散化为“年龄>30是1,否则0”,能避免像“年龄300岁”这样的异常数据对模型造成大的干扰。对于线性模型,单变量离散化为N个后,每个变量有单独的权重,相当于引入非线性,可提升模型表达能力;还能进行特征交叉,由M + N个变量变为M * N个变量,进一步引入非线性提升表达能力。此外,特征离散化后模型更稳定,也能简化逻辑回归模型,降低过拟合风险,可将缺失作为独立一类带入模型,还能将所有变量变换到相似尺度上,但区间划分很关键[^1]。 ### 95分位数盖帽法 这是一种处理离散值的具体代码实现方法,通过设定95分位数对数据进行盖帽处理,以减少异常值的影响。以下是Python代码示例: ```python # 训练集处理 def train_add_hat(x, features): import numpy as np import pandas as pd df = x.copy() q95_dict = {} for col in features: q95 = np.percentile(df[col], 95) q95_dict[col] = q95 b = np.array(df[col]) c = list(map(lambda x: q95 if x > q95 else x, b)) df = df.drop(col, axis=1) df[col] = c return df, q95_dict # 用同一标准处理测试集 def add_hat(x, features, q95_dict): import numpy as np import pandas as pd df = x.copy() len_d = len(df.index) for col in features: q95 = q95_dict[col] b = np.array(df[col]) c = list(map(lambda x: q95 if x > q95 else x, b)) df = df.drop(col, axis=1) df[col] = c return df ``` 该方法通过计算每个特征的95分位数,将大于此分位数的值替换为该分位数,以此处理离散值数据[^2]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值