【機器學習】特徵工程多特徵值序列化數值化獨熱編碼處理(LabelEncoder, pd.factorize())

多特徵值序列化數值化獨熱編碼處理

當我們在運用某些模型時,比如在Scikit-learn中,它要求數據都得是numberic(數值型),若是文本類型就無法進行訓練。

那麼在這種情況下,我們就應該先對數據進行序列化數值化:

下面是幾種在Python中數值化的方法:

1. 自然數編碼 :   a) 使用sklearn中的LabelEncoder()方法,轉換爲數值型特徵

                           b) 使用pd.factorize()函數

2. 獨熱編碼(one-hot encoding):生成一個(n_examples * n_classes)大小的0~1矩陣,每個樣本僅對應一個label

                           a) 使用pandas中的get_dummies實現

                           b) 使用OneHotEncoder() , LabelEncoder() , LabelBinarizer()  這些方法

自然數編碼

a)LabelEncoder()方法

在所有事情開始之前,我們先引入最常用的兩個包:

import pandas as pd
import numpy as np
fruit_data = pd.DataFrame({
    'fruit':  ['apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4]
})
   fruit   color  weight
0   apple     red       5
1  orange  orange       6
2    pear   green       3
3  orange   green       4

現在想要將‘fruit’和‘color’列的數據進行序列化數值化,我們可以用LabelEncoder()方法這麼做:

from sklearn.preprocessing import LabelEncoder
fruit_data[['fruit','color']]=fruit_data[['fruit','color']].apply(LabelEncoder().fit_transform)
    fruit  color  weight
0      0      2       5
1      1      1       6
2      2      0       3
3      1      0       4

看,是不是成功了呢(‘fruit’列中,‘apple’對應0,‘orange’對應1,‘pear’對應2 。‘color’那列讀者們可以自己口算試一下看看是不是這樣呢)

b)pd.factorize()函數

還是用剛纔的數據:

fruit_data = pd.DataFrame({
    'fruit':  ['apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4]
})
fruit_factorize = pd.factorize(fruit_data.fruit)# fruit_data.fruit 這裏與fruit_data['fruit']等價,
                                                #但是不建議用fruit_data.fruit,因爲可能特徵名稱與可調用的函數名稱衝突 
fruit_factorize
(array([0, 1, 2, 1], dtype=int64),
 Index(['apple', 'orange', 'pear'], dtype='object'))

看,已經完成啦,只是我們還需要做一些處理。可以看到除了數值化後的值以外,現在的fruit_factorize是一個元組的形式,裏面包含了數值化後的數組,還有一個Index數組,讓我們可以很直觀的對應到數值和label。

下面我們將數值化後的數據跟fruit_data整合在一起:

fruit_data['fruit'] = fruit_factorize[0] # 因爲factorize後是一個數組的形式,裏面包含了
factorize後的數字列表,還有原列表等信息,所以要取fruit_factorize[0]
    fruit   color  weight
0      0     red       5
1      1  orange       6
2      2   green       3
3      1   green       4

好啦,自然數編碼就說完啦。

獨熱編碼(one-hot encoding)

a)pd.get_dummies方法

注:這個方法最方便啦,當然下面的方法也很好噠

fruit_data = pd.DataFrame({
    'fruit':  ['apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4]
})
fruit_dummies = pd.get_dummies(fruit_data['fruit'])
   0  1  2
0  1  0  0
1  0  1  0
2  0  0  1
3  0  1  0

下面我們對整個數據應用get_dummies試一下

fruit_data_dummies  = pd.get_dummies(fruit_data)
   weight  fruit_apple  fruit_orange  fruit_pear  color_green  color_orange  color_red
0       5            1             0           0            0             0          1
1       6            0             1           0            0             1          0
2       3            0             0           1            1             0          0
3       4            0             1           0            1             0          0

 b) 使用OneHotEncoder() , LabelEncoder() , LabelBinarizer()  這些方法

先導入相應的包:

from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import LabelBinarizer
from sklearn.preprocessing import MultiLabelBinarizer
fruit_data = pd.DataFrame({
    'fruit':  ['apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4],
    'prize': [12,18,29,8] 
})

 對付數值型類別變量

對 weight 進行二值化很簡單,直接調用 OneHotEncoder():

 OneHotEncoder(sparse = False).fit_transform(fruit_data[['weight']])
 # 在這裏只能用fruit_data[['weight']] 而不能用fruit_data.weight,因爲 sklearn 的新版本中,
 # OneHotEncoder 的輸入必須是 2-D array,而 fruit_data.weight 返回的 Series 本質上是 1-D array
array([[0., 0., 1., 0.],
       [0., 0., 0., 1.],
       [1., 0., 0., 0.],
       [0., 1., 0., 0.]])

可以用同樣的方法對prize進行 OneHotEncoder() ,然後將結果用numpy.hstack()把兩者拼接起來得到變換後的結果:

但是那樣太過於麻煩,不如直接這樣(因爲 OneHotEncoder()要求輸入一個2-D的數組嘛)

OneHotEncoder(sparse = False).fit_transform(fruit_data[['weight','prize']])
array([[0., 0., 1., 0., 0., 1., 0., 0.],
       [0., 0., 0., 1., 0., 0., 1., 0.],
       [1., 0., 0., 0., 0., 0., 0., 1.],
       [0., 1., 0., 0., 1., 0., 0., 0.]])

我們還可以通過 OneHotEncoder()自帶的feature_indices_來實現查看那幾列是屬於weight或prize的編碼。

對付字符串型類別變量

遺憾的是OneHotEncoder()無法直接對字符串型的類別變量編碼。

但,我們可以這樣:

  1.  先用 LabelEncoder() 轉換成連續的數值型變量,再用 OneHotEncoder() 二值化
  2.  直接用 LabelBinarizer() 進行二值化

然而要注意的是,無論 LabelEncoder() 還是 LabelBinarizer(),他們在 sklearn 中的設計初衷,都是爲了解決標籤 y 的離散化,而非輸入 X, 所以他們的輸入被限定爲 1-D array,這恰恰跟 OneHotEncoder() 要求輸入 2-D array 相反。所以使用的時候要格外小心,否則就會出現錯誤。

fruit_data = pd.DataFrame({
    'fruit':  ['apple','orange','pear','orange'],
    'color':  ['red','orange','green','green'],
    'weight': [5,6,3,4],
    'prize': [12,18,29,8] 
})
# 方法一: LabelEncoder() + OneHotEncoder()
a = LabelEncoder().fit_transform(fruit_data['fruit'])
OneHotEncoder( sparse=False ).fit_transform(a.reshape(-1,1)) # 注意: 這裏把 a 用 reshape 轉換成 2-D array


# 方法二: 直接用 LabelBinarizer()
LabelBinarizer().fit_transform(fruit_data['fruit'])

結果都爲:

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

正因爲LabelEncoderLabelBinarizer設計爲只支持 1-D array,也使得它無法像上面 OneHotEncoder 那樣批量接受多列輸入,也就是說OneHotEncoder(sparse = False).fit_transform(fruit_data[['weight','prize']])會報錯。

小結

雖然get_dummies 很好哈,但是,

get_dummies 不像 sklearn 的 transformer一樣,有 transform方法,所以一旦測試集中出現了訓練集未曾出現過的特徵取值,簡單地對測試集、訓練集都用 get_dummies 方法將導致數據錯誤

 

Numpy

當然了Numpy也可以實現獨熱編碼:

# 函數需不需要返回轉置要根據具體情況看
# 如果不轉置每個label返回的就是一個行向量
# 這裏轉置了,每個label就是對應的列向量

def convert_to_one_hot(y, C):
    return np.eye(C)[y.reshape(-1)].T

y = np.array([1,2,3,4])
convert_to_one_hot(y,5)
# array([[ 0.,  0.,  0.,  0.],
#        [ 1.,  0.,  0.,  0.],
#        [ 0.,  1.,  0.,  0.],
#        [ 0.,  0.,  1.,  0.],
#        [ 0.,  0.,  0.,  1.]])

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章