Scikit-Learn中提供了几个对分类变量进行独热编码的转换量(transformer):LabelEncoder、OneHotEncoder、LabelBinarizer。可能是由于版本的差异,在实际使用过程中和《Scikit-Learn与TensorFlow机器学习实用指南》的运行结果略有不同。故在本文中对三者做个简单梳理。
我的sklearn版本是0.20.0,Python是3.7.0 on Windows x64,本文使用房价数据进行测试。
>>> import sklearn
>>> sklearn.__versions__
0.20.0
首先导入数据源,提取需要处理的字段。
>>> import pandas as pd
>>> housing = pd.read_csv("housing/housing.csv")
>>> attrib_cat = housing["ocean_proximity"]
>>> attrib_cat.describe()
count 20640
unique 5
top <1H OCEAN
freq 9136
Name: ocean_proximity, dtype: object
要处理的字段存储在attrib_cat
变量中,包含5个类型,共计20640个样本,类型是pands的Series。接下来开始依次使用以上三个转换量来将其转换为独热编码:
LabelEncoder
>>> from sklearn.preprocessing import LabelEncoder, OneHotEncoder, LabelBinarizer
>>> LabelEncoder?
Encode labels with value between 0 and n_classes-1.
...
It can also be used to transform non-numerical labels (as long as they are
hashable and comparable) to numerical labels.
LabelEncoder可以将值转换为0~n-1个类型,也可以用来将非数值的标签转换为数值标签(需要确保非数值标签是可比的和可哈希的)。
Sklearn的API设计的比较巧妙,所有转换的过程都比较类似:
>>> le = LabeEncoder()
>>> letrans = le.fit_transform(attrib_cat)
>>> letrans
array([3, 3, 3, ..., 1, 1, 1])
分类变量被转换成由数值做成的数组(array)。获取独热编码还需要使用OneHotDecoder(),书中介绍的第一种方法也是这个流程。
>>> oh = OneHotDecoder()
>>> oh.fit_transform(letrans)
ValueError: Expected 2D array, got 1D array instead:
array=[3 3 3 ... 1 1 1].
Reshape your data either using array.reshape(-1, 1) if your data has a single feature or array.reshape(1, -1) if it contains a single sample.
OneHotDecoder接受的数据需要是2维数组,错误提示很明显,书中也提到了这一点,这里仅仅作为提示。OneHotDecoder的介绍后面再整理。
>>> oh.fit_transform(letrans.reshape(-1,1))
<20640x5 sparse matrix of type '<class 'numpy.float64'>'
with 20640 stored elements in Compressed Sparse Row format>
输出结果是SciPy的稀疏矩阵,为了减少内存的占用。调用toarray()
可以将其转换为NumPy的数组。
OneHotDecoder
>>> OneHotDecoder?
Encode categorical integer features as a one-hot numeric array.
The input to this transformer should be an array-like of integers or
strings, denoting the values taken on by categorical (discrete) features.
The features are encoded using a one-hot (aka 'one-of-K' or 'dummy')
encoding scheme. This creates a binary column for each category and
returns a sparse matrix or dense array.
By default, the encoder derives the categories based on the unique values
in each feature. Alternatively, you can also specify the `categories`
manually.
The OneHotEncoder previously assumed that the input features take on
values in the range [0, max(values)). This behaviour is deprecated.
This encoding is needed for feeding categorical data to many scikit-learn
estimators, notably linear models and SVMs with the standard kernels.
Note: a one-hot encoding of y labels should use a LabelBinarizer
instead.
OneHotEncoder将数值型的特征转换为独热编码的数值型数组。接收的输入是类数组的数值和字符串变量,依次来代表分类(离散)特征。这些特征会被按照热点编码的方式进行转换。为每个类型创建一个二元的栏,返回一个稀疏矩阵或者密集数组。
该转换量默认以各个属性的唯一值作为分类依据。但也支持通过categories
参数手动设置。
之前版本的OneHotEncoder假设输入属性的值在[0, max(values)]的范围,我用的版本已经被移除。
注意: 对预测属性的独热编码应该使用LabelBinarizer来进行。
上例中已经演示了OneHotEncoder对数值型数组的转换,但文档中可以看到它可以直接对字符类的数组进行独热编码,这里来尝试一下。
>>> oh.fit_transform(np.array(attrib_cat).reshape(-1,1))
<20640x5 sparse matrix of type '<class 'numpy.float64'>'
with 20640 stored elements in Compressed Sparse Row format>
确实可以完成上一个例子中两步才能进行的操作。
LabelBinarizer
LabelBinarizer?
Binarize labels in a one-vs-all fashion
Several regression and binary classification algorithms are
available in scikit-learn. A simple way to extend these algorithms
to the multi-class classification case is to use the so-called
one-vs-all scheme.
At learning time, this simply consists in learning one regressor
or binary classifier per class. In doing so, one needs to convert
multi-class labels to binary labels (belong or does not belong
to the class). LabelBinarizer makes this process easy with the
transform method.
At prediction time, one assigns the class for which the corresponding
model gave the greatest confidence. LabelBinarizer makes this easy
with the inverse_transform method.
LabelBinarizer顾名思义将标签转换为一对多的形式。
为了将而分类或者回归算法扩展到多分类,我们需要将标签转换为一对多的形式。
在训练过程中,通常包含了为每个类学习二分类模型或者回归模型。为了实现这个目的,我们需要将多分类标签转换为而分类标签(属于某类或者不属于某类)。LabelBinerizer是这个转换的过程变得比较简单。
在预测阶段,LabelBinerizer也可以方便得将预测结果转换成多分类标签。
>>> lbe = LabelBinerizer()
>>> lbe.fit_transform(attrib_cat)
array([[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 1, 0],
...,
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 1, 0, 0, 0]])
LabelBinarizer相当于集合了LabeEncoder和OneHotEncoder的过程,同时相比与OneHotEncoder,他的操作更简单:直接接受pandas的Series格式数据,默认输出密集的NumPy数组,dtype是int32。
总结
梳理过后,三个转换量的区别就比较明显了:
- 描述
- LabelEncoder :将类型变量转换为数值组成的数组。
- OneHotEncoder:将数值类型属性转换成独热编码的数值型数组。
- LabelBinerizer: 将标签二值化为一对多的形式。
- fit_transform的输入
- LabelEncoder :pd.Series/np.array, 可哈希、可比的非数值或者数值, ndim=1。
- OneHotEncoder:np.array,可比的非数值或者数值,ndim=2。
- LabelBinerizer: pd.Series/np.array, 可哈希、可比的非数值或者数值,ndim=1。
- fit_transform的默认输出
- LabelEncoder :np.array, dtype=int64。
- OneHotEncoder:SciPy.Sparse Matrix, dtype=float64。
- LabelBinerizer: np.array, dtype=int32。