[scikit-learn] 特征二值化
1.首先造一个测试数据集
#coding:utf-8 import numpy import pandas as pd from sklearn.preprocessing import OneHotEncoder from sklearn.preprocessing import LabelEncoder from sklearn.preprocessing import LabelBinarizer from sklearn.preprocessing import MultiLabelBinarizer def t2(): testdata = pd.DataFrame({'pet': ['chinese', 'english', 'english', 'math'], 'age': [6 , 5, 2, 2], 'salary':[7, 5, 2, 5]}) print testdata t2()
这里我们把 pet
、age
、salary
都看做类别特征,所不同的是 age
和 salary
都是数值型,而 pet
是字符串型。我们的目的很简单: 把他们全都二值化,进行 one-hot 编码
2. 对付数值型类别变量
对 age 进行二值化很简单,直接调用 OneHotEncoder
OneHotEncoder(sparse = False).fit_transform(testdata.age) # testdata.age 这里与 testdata[['age']]等价
然而运行结果是 array([[ 1., 1., 1., 1.]])
,这个结果是错的,从 Warning 信息中得知,原因是 sklearn 的新版本中,OneHotEncoder
的输入必须是 2-D array,而 testdata.age 返回的 Series 本质上是 1-D array,所以要改成
OneHotEncoder(sparse = False).fit_transform(testdata[['age']])
我们得到了我们想要的:
array([[ 0., 1., 0.],
[ 0., 0., 1.],
[ 1., 0., 0.],
[ 1., 0., 0.]])
可以用同样的方法对 salary
进行 OneHotEncoder
, 然后将结果用 numpy.hstack()
把两者拼接起来得到变换后的结果
import numpy result1 = OneHotEncoder(sparse = False).fit_transform(testdata[['age']]) result2 = OneHotEncoder(sparse=False).fit_transform(testdata[['salary']]) final_output = numpy.hstack((result1,result2)) print final_output
不过这样的代码略显冗余,既然 OneHotEncoder()
可以接受 2-D array 输入,那我们可以写成这样
result = OneHotEncoder(sparse = False).fit_transform( testdata[['age', 'salary']])
结果为
array([[ 0., 1., 0., 0., 1., 0.],
[ 0., 0., 1., 0., 0., 1.],
[ 1., 0., 0., 1., 0., 0.],
[ 1., 0., 0., 1., 0., 0.]])
有时候我们除了得到最终编码结果,还想知道结果中哪几列属于 age
的二值化编码,哪几列属于 salary
的,这时候我们可以通过 OneHotEncoder()
自带的 feature_indices_
来实现这一要求,比如这里 feature_indices_
的值是[0, 3, 6],表明 第[0:3]列是age
的二值化编码,[3:6]是salary
的。更多细节请参考 sklearn 文档,
3. 对付字符串型类别变量
遗憾的是OneHotEncoder
无法直接对字符串型的类别变量编码,也就是说OneHotEncoder().fit_transform(testdata[['pet']])
这句话会报错(不信你试试)。已经有很多人在 stackoverflow 和 sklearn 的 github issue 上讨论过这个问题,但目前为止的 sklearn 版本仍没有增加OneHotEncoder
对字符串型类别变量的支持,所以一般都采用曲线救国的方式:
方法一 先用 LabelEncoder() 转换成连续的数值型变量,再用 OneHotEncoder() 二值化
方法二 直接用 LabelBinarizer() 进行二值化
然而要注意的是,无论 LabelEncoder() 还是 LabelBinarizer(),他们在 sklearn 中的设计初衷,都是为了解决标签 y 的离散化,而非输入 X, 所以他们的输入被限定为 1-D array,这恰恰跟 OneHotEncoder() 要求输入 2-D array 相左。所以我们使用的时候要格外小心,否则就会出现上面array([[ 1., 1., 1., 1.]])
那样的错误
# 方法一: LabelEncoder() + OneHotEncoder()
a = LabelEncoder().fit_transform(testdata['pet'])
OneHotEncoder( sparse=False ).fit_transform(a.reshape(-1,1)) # 注意: 这里把 a 用 reshape 转换成 2-D array
# 方法二: 直接用 LabelBinarizer()
LabelBinarizer().fit_transform(testdata['pet'])
这两种方法得到的结果一致,都是
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
正因为LabelEncoder
和LabelBinarizer
设计为只支持 1-D array,也使得它无法像上面 OneHotEncoder 那样批量接受多列输入,也就是说LabelEncoder().fit_transform(testdata[['pet', 'age']])
会报错。
posted on 2017-08-22 14:32 running_wolf 阅读(1670) 评论(0) 编辑 收藏 举报