[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()

這里我們把 petagesalary 都看做類別特征,所不同的是 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.]])

正因為LabelEncoderLabelBinarizer設計為只支持 1-D array,也使得它無法像上面 OneHotEncoder 那樣批量接受多列輸入,也就是說LabelEncoder().fit_transform(testdata[['pet', 'age']])會報錯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM