几种 sklearn 的二值化编码函数:OneHotEncoder(), LabelEncoder(), LabelBinarize

转载http://blog.csdn.net/gao1440156051/article/details/55096630

所涉及到的几种 sklearn 的二值化编码函数:OneHotEncoder(), LabelEncoder(), LabelBinarizer(), MultiLabelBinarizer()

1.代码块

import pandas as pd 

from sklearn.preprocessing import OneHotEncoder 

from sklearn.preprocessing import LabelEncoder 

from sklearn.preprocessing import LabelBinarizer 

from sklearn.preprocessing import MultiLabelBinarizer

testdata = pd.DataFrame({‘pet’: [‘cat’, ‘dog’, ‘dog’, ‘fish’],‘age’: [4 , 6, 3, 3],
‘salary’:[4, 5, 1, 1]})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8


这里我们把 pet、age、salary 都看做类别特征,所不同的是 age 和 salary 都是数值型,而 pet 是字符串型。我们的目的很简单: 把他们全都二值化,进行 one-hot 编码.

2.对付数值型类别变量

OneHotEncoder(sparse = False).fit_transform( testdata.age ) # testdata.age 这里与 testdata[['age']]等价
  • 1
  • 1


然而运行结果是 array([[ 1., 1., 1., 1.]]),这个结果是错的,从 Warning 信息中得知,原因是 sklearn 的新版本中,OneHotEncoder 的输入必须是 2-D array,而 testdata.age 返回的 Series 本质上是 1-D array,所以要改成 


OneHotEncoder(sparse = False).fit_transform(testdata[['age']])
  • 1
  • 1


testdata[[‘age’]]的取值是:0,4,6所以对这个三个值进行one-hot化,第一行:[4]===>得到one-hot:[0,1,0]

注意: one-hot化是每个feature的取值个数作为one-hot后的长度,对应的位置0/1的值是原数据在此位置取值的有无.不是取值的max的长度编号:如这个最大为6,按照one-hot的定义是testdata[[‘age’]]=[4]–>one-hot后:[0,0,0,1,0,0]但定义直观理解是这样的,但在工程实现这样没必要,只针对有值得取值编码就可以,节约矩阵one-hot后的规模而且效果一样;

我们得到了我们想要的:

array([[ 0.,  1.,  0.], 

       [ 0.,  0.,  1.], 

       [ 1.,  0.,  0.], 

       [ 1.,  0.,  0.]])
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4


可以用同样的方法对 salary 进行 OneHotEncoder, 然后将结果用 numpy.hstack() 把两者拼接起来得到变换后的结果


a1 = OneHotEncoder(sparse = False).fit_transform( testdata[['age']] ) 

a2 = OneHotEncoder(sparse = False).fit_transform( testdata[['salary']]) 

final_output = numpy.hstack((a1,a2))
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3


结果为


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.]])
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4


有时候我们除了得到最终编码结果,还想知道结果中哪几列属于 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’])

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7


这两种方法得到的结果一致,都是


array([[ 1.,  0.,  0.], 

       [ 0.,  1.,  0.], 

       [ 0.,  1.,  0.], 

       [ 0.,  0.,  1.]])
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4


正因为LabelEncoder和LabelBinarizer设计为只支持 1-D array,也使得它无法像上面 OneHotEncoder 那样批量接受多列输入,也就是说LabelEncoder().fit_transform(testdata[[‘pet’, ‘age’]])会报错。 

4.无用的尝试

然而执着如我怎会就此放弃,我又仔细翻了翻 sklearn 的 API 接口,果然发现有个叫 MultiLabelBinarizer() 的,看着似乎可以解决这个问题,于是尝试了一下

MultiLabelBinarizer().fit_transform(testdata[['age','salary']].values)
  • 1
  • 1


输出结果如下


array([[0, 0, 1, 0, 0], 

       [0, 0, 0, 1, 1], 

       [1, 1, 0, 0, 0], 

       [1, 1, 0, 0, 0]])
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4


5.另一种解决方案

其实如果我们跳出 scikit-learn, 在 pandas 中可以很好地解决这个问题,用 pandas 自带的get_dummies函数即可

pd.get_dummies(testdata,columns=testdata.columns)
  • 1
  • 1


结果正是我们想要的


age_3   age_4   age_6   pet_cat pet_dog pet_fish    salary_1    salary_4    salary_5 

0   0.0 1.0 0.0 1.0 0.0 0.0 0.0 1.0 0.0 

1   0.0 0.0 1.0 0.0 1.0 0.0 0.0 0.0 1.0 

2   1.0 0.0 0.0 0.0 1.0 0.0 1.0 0.0 0.0 

3   1.0 0.0 0.0 0.0 0.0 1.0 1.0 0.0 0.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5


get_dummies的优势: 
* 1.本身就是 pandas 的模块,所以对 DataFrame 类型兼容很好. 
* 2.无论你的列是字符型还是数字型都可以进行二值编码. 
* 3.能根据用户指定,自动生成二值编码后的变量名. 
这么看来,我们找到最完美的解决方案了? No!get_dummies千般好,万般好,但毕竟不是 sklearn 里的transformer类型,所以得到的结果得手动输入到 sklearn 里的相应模块,也无法像 sklearn 的transformer一样可以输入到pipeline中 进行流程化地机器学习过程。更重要的一点.

注意: get_dummies 不像 sklearn 的 transformer一样,有 transform方法,所以一旦测试集中出现了训练集未曾出现过的特征取值,简单地对测试集、训练集都用 get_dummies 方法将导致数据错误。 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值