多特徵值序列化數值化獨熱編碼處理
當我們在運用某些模型時,比如在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()無法直接對字符串型的類別變量編碼。
但,我們可以這樣:
- 先用 LabelEncoder() 轉換成連續的數值型變量,再用 OneHotEncoder() 二值化
- 直接用 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]])
正因爲LabelEncoder
和LabelBinarizer
設計爲只支持 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.]])