特征工程 -类别型特征的预处理

目录

序言

主要介绍:

1 .使用Sklearn的LabelBinarizer来进行one-hot

2 .使用Sklearn的MultilabelBinarizer来进行组合类别特征的One-hot

 3 .对Oridinal序数特征进行编码

4 .对特征字典编码

 5 .填充缺失的分类特征值

6.使用category_encoder包来进行特征转换

总结


序言

在机器学习建模过程中,许多模型例如逻辑回归、支持向量机、K近邻等传统的机器学习模型不能直接将类别型特征用于训练。但是在近年,许多新诞生的模型例如:LightGBM和Catboost等算法开始支持类别型特征直接进行建模。所以,处理类别型特征,是进行机器学习建模前的必不可少的步骤。

 本文将介绍若干种类别特征的处理方案,相信通过这些方法,希望能在今后遇到类别型特征时,能找到一种最合适的解决方法。

主要介绍:

  • 使用sklearn的LabelBinarizer来进行one-hot类别特征
  • 使用sklearn的MultiLabelBinarizer来进行组合类别特征的one-hot
  • 使用sklearn对oridinal序数特征进行编码
  • 对特征字典进行编码
  • 填充缺失的分类值
  • 使用category_encoder包来进行类别特征编码
  1. OridinalEncoder
  2. OnehotEncoder
  3. 目标编码TargetEncoder
  4. M估计量编码MEstimateEncoder
  5. JamesSteinEncoder
  6. WOE编码
  7. Catboost编码

1 .使用Sklearn的LabelBinarizer来进行one-hot

# 导入相关包
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelBinarizer

# 创建特征
feature = np.array([['Texas'],
                    ['Cliforniya'],
                    ['Texas'],
                    ['Delaware'],
                    ['Texas']])

# 实例化编码器
one_hot = LabelBinarizer()

# 查看转换后的结果
display(one_hot.fit_transform(feature))
display(one_hot.classes_)

特征工程 -类别型特征的预处理_第1张图片

如上图所示,我们会得到一个类型为

下面将展示两种方法:

# 使用one-hot编码进行逆转换
one_hot.inverse_transform(one_hot.transform(feature))

# output
array(['Texas', 'Cliforniya', 'Texas', 'Delaware', 'Texas'], dtype='
# 使用pandas中的pd.get_dummies()来进行转换
pd.get_dummies(pd.DataFrame(feature,columns=['feature name']))


特征工程 -类别型特征的预处理_第2张图片

2 .使用Sklearn的MultilabelBinarizer来进行组合类别特征的One-hot

from sklearn.preprocessing import MultiLabelBinarizer
''' multiclass_features = [('Texas','Florida'),
                       ('Californiya','Alabama'),
                       ('Texas','Florida'),
                       ('Delware','Florida'),
                       ('Texas','Alabama')]
'''
multiclass_features =  np.array([['Texas'],
                    ['Cliforniya'],
                    ['Texas'],
                    ['Delaware'],
                    ['Texas']])

one_hot_multiclass = MultiLabelBinarizer()

display(one_hot_multiclass.fit_transform(multiclass_features))
display(one_hot_multiclass.classes_)

特征工程 -类别型特征的预处理_第3张图片 

就会得到相同的结果,这里需要注意的是:得到类型为字节。

 3 .对Oridinal序数特征进行编码

可以使用字典来对相应的特征进行映射。

df = pd.DataFrame({"Score":['Low','Low','Medium','Medium','High']})
display(df)

scale_mapper = {"Low":1,'Medium':2,'High':3}
display(df.replace(scale_mapper))

                                                                                                                   特征工程 -类别型特征的预处理_第4张图片

 特征工程 -类别型特征的预处理_第5张图片

 对于某种天然的顺序,例如李克特量表(Likert scale),值与值之间的间隔可能不是数字所反映出来的大小关系,我们应该主动去更改数字大小。

4 .对特征字典编码

# 加载库
from sklearn.feature_extraction import DictVectorizer
# 创建字典
data_dict = [{"Red":2,"Blue":4},
             {"Red":4,"Blue":3},
             {"Red":1,"Yellow":2},
             {"Red":2,"Yellow":2}]

# 创建字典向量化器(指定非稀疏矩阵)
dictvectorizer = DictVectorizer(sparse=False)
display(dictvectorizer.fit_transform(data_dict))

# 获取特征的名字,使用get_feature_names()
feature_names = dictvectorizer.get_feature_names()
display(feature_names)

# 创建DataFrame
pd.DataFrame(dictvectorizer.fit_transform(data_dict),columns=feature_names)

特征工程 -类别型特征的预处理_第6张图片

 5 .填充缺失的分类特征值

import numpy as np
from sklearn.neighbors import KNeighborsClassifier

# 用分类特征创建特征矩阵
X = np.array([[0,2.10,1.45],
             [1,1.18,1.33],
             [0,1.22,1.27],
             [1,-0.21,-1.19]])

# 创建带缺失值的特征矩阵
X_with_nan = np.array([[np.nan,0.87,1.31],
                       [np.nan,-0.67,-0.22]])

# 训练分类器
clf = KNeighborsClassifier(3,weights='distance')
trained_model = clf.fit(X[:,1:],X[:,0])

# 预测缺失值的分类
imputed_values = trained_model.predict(X_with_nan[:,1:])

# 将所预测的分类和它们的其他特征链接起来
X_with_imputed = np.hstack((imputed_values.reshape(-1,1),X_with_nan[:,1:]))

# 连接两个特征矩阵
np.vstack((X_with_imputed,X))



#用特征中出现次数最多的值来填充缺失值。

from sklearn.impute import SimpleImputer
# 链接两个特征矩阵
X_complete = np.vstack((X_with_nan,X))

imputer = SimpleImputer(strategy='most_frequent',)
imputer.fit_transform(X_complete)

特征工程 -类别型特征的预处理_第7张图片

6.使用category_encoder包来进行特征转换

6.1 使用OrdinalEncoder进行序数转换

缺点:这个编码的缺点在于它随机的给特征排序了,会给这个特征增加不存在的顺序关系,也就是增加了噪声,与编码后特征的顺序不存在相关性。

# 首先安装category_encoder包
# !pip install category_encoder
# 导入序数编码器
from category_encoders import OrdinalEncoder

# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female',20],['male',10],
                                  ['female',20],['female',15]]),columns=['Sex','Type'])
train_y = np.array([False,True,True,False,False])

# 随机生成一些测试集,并有意让其包含未在训练集出现过的类别值与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male',20],['others',15],
                                   ['male',20],['female',40],['male',25]]),columns=['Sex','Type'])
test_set.loc[4,'Type'] = np.nan

display(train_set)
display(test_set)

特征工程 -类别型特征的预处理_第8张图片 

6.2 进行one-hot编码

缺点:但是在离散特征的特征值过多的时候不宜使用,因为会导致生成特征的数量太多且过于稀疏。

# 首先安装category_encoder包
# !pip install category_encoder
# 导入序数编码器
from category_encoders import OrdinalEncoder

# 随机生成一些训练集
train_set = pd.DataFrame(np.array([['male',10],['female',20],['male',10],
                                  ['female',20],['female',15]]),columns=['Sex','Type'])
train_y = np.array([False,True,True,False,False])

# 随机生成一些测试集,并有意让其包含未在训练集出现过的类别值与缺失值
test_set = pd.DataFrame(np.array([['female',20],['male',20],['others',15],
                                   ['male',20],['female',40],['male',25]]),columns=['Sex','Type'])
test_set.loc[4,'Type'] = np.nan

display(train_set)
display(test_set)



from category_encoders import OneHotEncoder

encoder = OneHotEncoder(cols=['Sex','Type'], 
                        handle_unknown='indicator', 
                        handle_missing='indicator', 
                        use_cat_names=True).fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集
# 将 handle_unknown设为‘indicator’,即会新增一列指示未知特征值
# 将 handle_missing设为‘indicator’,即会新增一列指示缺失值
# 其他的handle_unknown/handle_missing 的选择为:
# ‘error’:即报错; ‘return_nan’:即未知值/缺失之被标记为nan; ‘value’:即未知值/缺失之被标记为0

6.3 使用TargetEncoder目标编码

由名字目标编码就可以猜到,目标编码是一种不仅基于特征值本身,还基于相应因变量的类别变量编码方法。
对于分类问题:将类别特征替换为给定某一特定类别值的因变量后验概率与所有训练数据上因变量的先验概率的组合。
对于连续目标:将类别特征替换为给定某一特定类别值的因变量目标期望值与所有训练数据上因变量的目标期望值的组合。
该方法严重依赖于因变量(target)的分布,但这大大减少了生成编码后特征的数量。
参考文献: Micci-Barreca, D. (2001). A preprocessing scheme for high-cardinality categorical attributes in classification and prediction problems. ACM SIGKDD Explorations Newsletter, 3(1), 27-32.

from category_encoders import  TargetEncoder
encoder = TargetEncoder(cols=['Sex','Type'], 
                        handle_unknown='value',  
                        handle_missing='value').fit(train_set,train_y) # 在训练集上训练
encoded_train = encoder.transform(train_set) # 转换训练集
encoded_test = encoder.transform(test_set) # 转换测试集

# handle_unknown 和 handle_missing 被设定为 'value'
# 在目标编码中,handle_unknown 和 handle_missing 仅接受 ‘error’, ‘return_nan’ 及 ‘value’ 设定
# 两者的默认值均为 ‘value’, 即对未知类别或缺失值填充训练集的因变量平均值

总结

处理分类特征是机器学习建模数据预处理时所不可避免的一项环节,相应通过以上若干种方法,以后在遇到分类特征时,可以不一上手就直接进行Onehot,而有了更多的选择,也可以使得训练的模型能够更好的效果,祝愿未来蒸蒸日上。

参考: Category Encoders — Category Encoders 2.5.1.post0 documentation

参考: GitHub - YC-Coder-Chen/feature-engineering-handbook: A practical feature engineering handbook

参考:特征工程.类别型特征的预处理 - 知乎

你可能感兴趣的:(数据预处理,人工智能,深度学习)