資料科學和人工智慧技術筆記 三、資料預處理
阿新 • • 發佈:2018-11-15
三、資料預處理
作者:Chris Albon
譯者:飛龍
為 Scikit-Learn 轉換 Pandas 類別資料
# 匯入所需的庫
from sklearn import preprocessing
import pandas as pd
raw_data = {'patient': [1, 1, 1, 2, 2],
'obs': [1, 2, 3, 1, 2],
'treatment': [0, 1, 0, 1, 0],
'score': ['strong', 'weak', 'normal', 'weak', 'strong']}
df = pd.DataFrame(raw_data, columns = ['patient', 'obs', 'treatment', 'score'])
# 建立標籤(類別)編碼物件
le = preprocessing.LabelEncoder()
# 使編碼器擬合 pandas 列
le.fit(df['score'])
# LabelEncoder()
# 檢視標籤(如果你希望)
list(le.classes_)
# ['normal', 'strong', 'weak']
# 將擬合的編碼器應用於 pandas 列
le.transform(df['score'])
# array([1, 2, 0, 2, 1])
# 將一些整數轉換為它們的類別名稱
list(le.inverse_transform([2, 2, 1]))
# ['weak', 'weak', 'strong']
刪除帶缺失值的觀測
# 載入庫
import numpy as np
import pandas as pd
# 建立特徵矩陣
X = np.array([[1.1, 11.1],
[2.2, 22.2],
[3.3, 33.3],
[ 4.4, 44.4],
[np.nan, 55]])
# 移除帶缺失值的觀測
X[~np.isnan(X).any(axis=1)]
'''
array([[ 1.1, 11.1],
[ 2.2, 22.2],
[ 3.3, 33.3],
[ 4.4, 44.4]])
'''
刪除缺失值
# 載入庫
import numpy as np
import pandas as pd
# 建立特徵矩陣
X = np.array([[1, 2],
[6, 3],
[8, 4],
[9, 5],
[np.nan, 4]])
# 移除帶缺失值的觀測
X[~np.isnan(X).any(axis=1)]
array([[ 1., 2.],
[ 6., 3.],
[ 8., 4.],
[ 9., 5.]])
# 將資料載入為資料幀
df = pd.DataFrame(X, columns=['feature_1', 'feature_2'])
# 移除帶缺失值的觀測
df.dropna()
feature_1 | feature_2 | |
---|---|---|
0 | 1.0 | 2.0 |
1 | 6.0 | 3.0 |
2 | 8.0 | 4.0 |
3 | 9.0 | 5.0 |
檢測離群點
# 載入庫
import numpy as np
from sklearn.covariance import EllipticEnvelope
from sklearn.datasets import make_blobs
# 建立模擬資料
X, _ = make_blobs(n_samples = 10,
n_features = 2,
centers = 1,
random_state = 1)
# 將第一個觀測值替換為異常值
X[0,0] = 10000
X[0,1] = 10000
EllipticEnvelope
假設資料是正態分佈的,並且基於該假設,在資料周圍“繪製”橢圓,將橢圓內的任何觀測分類為正常(標記為1
),並將橢圓外的任何觀測分類為異常值(標記為-1
)。 這種方法的一個主要限制是,需要指定一個contamination
引數,該引數是異常觀測值的比例,這是我們不知道的值。
# 建立檢測器
outlier_detector = EllipticEnvelope(contamination=.1)
# 擬合檢測器
outlier_detector.fit(X)
# 預測離群點
outlier_detector.predict(X)
# array([-1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
離散化特徵
# 載入庫
from sklearn.preprocessing import Binarizer
import numpy as np
# 建立特徵
age = np.array([[6],
[12],
[20],
[36],
[65]])
# 建立二值化器
binarizer = Binarizer(18)
# 轉換特徵
binarizer.fit_transform(age)
'''
array([[0],
[0],
[1],
[1],
[1]])
'''
# 對特徵分箱
np.digitize(age, bins=[20,30,64])
'''
array([[0],
[0],
[1],
[2],
[3]])
'''
編碼序數類別特徵
# 載入庫
import pandas as pd
# 建立特徵
df = pd.DataFrame({'Score': ['Low',
'Low',
'Medium',
'Medium',
'High']})
# 檢視資料幀
df
Score | |
---|---|
0 | Low |
1 | Low |
2 | Medium |
3 | Medium |
4 | High |
建立比例對映
# 建立對映器
scale_mapper = {'Low':1,
'Medium':2,
'High':3}
# 將特徵值對映為比例
df['Scale'] = df['Score'].replace(scale_mapper)
# 檢視資料幀
df
Score | Scale | |
---|---|---|
0 | Low | 1 |
1 | Low | 1 |
2 | Medium | 2 |
3 | Medium | 2 |
4 | High | 3 |
使用下采樣處理不平衡類
在下采樣中,我們從多數類(即具有更多觀測值的類)中不放回隨機抽樣,來建立與少數類相等的新觀測子集。
# 載入庫
import numpy as np
from sklearn.datasets import load_iris
# 載入鳶尾花資料
iris = load_iris()
# 建立特徵矩陣
X = iris.data
# 建立目標向量
y = iris.target
# 移除前 40 個觀測
X = X[40:,:]
y = y[40:]
# 建立二元目標向量,表示是否是類 0
y = np.where((y == 0), 0, 1)
# 檢視不平衡的目標向量
y
'''
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
'''
# 每個類別的觀測的下標
i_class0 = np.where(y == 0)[0]
i_class1 = np.where(y == 1)[0]
# 每個類別的觀測數量
n_class0 = len(i_class0)
n_class1 = len(i_class1)
# 對於類 0 的每個觀測,隨機從類 1 不放回取樣
i_class1_downsampled = np.random.choice(i_class1, size=n_class0, replace=False)
# 將類 0 的目標向量,和下采樣的類 1 的目標向量連線到一起
np.hstack((y[i_class0], y[i_class1_downsampled]))
# array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
使用上取樣處理不平衡類別
在上取樣中,對於多數類中的每個觀測,我們從少數類中帶放回隨機選擇觀測。 最終結果是來自少數類和多數類的觀測數量相同。
# 載入庫
import numpy as np
from sklearn.datasets import load_iris
# 載入鳶尾花資料
iris = load_iris()
# 建立特徵矩陣
X = iris.data
# 建立目標向量
y = iris.target
# 移除前 40 個觀測
X = X[40:,:]
y = y[40:]
# 建立二元目標向量,表示是否是類 0
y = np.where((y == 0), 0, 1)
# 檢視不平衡的目標向量
y
'''
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
'''
# 每個類別的觀測的下標
i_class0 = np.where(y == 0)[0]
i_class1 = np.where(y == 1)[0]
# 每個類別的觀測數量
n_class0 = len(i_class0)
n_class1 = len(i_class1)
# 對於類 1 中的每個觀測,我們從類 0 中帶放回隨機選擇觀測。
i_class0_upsampled = np.random.choice(i_class0, size=n_class1, replace=True)
# 將類 0 的上取樣的目標向量,和類 1 的目標向量連線到一起
np.concatenate((y[i_class0_upsampled], y[i_class1]))
'''
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1])
'''
處理離群點
# 載入庫
import pandas as pd
# 建立 DataFrame
houses = pd.DataFrame()
houses['Price'] = [534433, 392333, 293222, 4322032]
houses['Bathrooms'] = [2, 3.5, 2, 116]
houses['Square_Feet'] = [1500, 2500, 1500, 48000]
houses
Price | Bathrooms | Square_Feet | |
---|---|---|---|
0 | 534433 | 2.0 | 1500 |
1 | 392333 | 3.5 | 2500 |
2 | 293222 | 2.0 | 1500 |
3 | 4322032 | 116.0 | 48000 |
選擇 1:丟棄
# 丟棄大於某個值的觀測
houses[houses['Bathrooms'] < 20]
Price | Bathrooms | Square_Feet | |
---|---|---|---|
0 | 534433 | 2.0 | 1500 |
1 | 392333 | 3.5 | 2500 |
2 | 293222 | 2.0 | 1500 |
選擇 2:標記
# 載入庫
import numpy as np
# 基於布林條件建立特徵
houses['Outlier'] = np.where(houses['Bathrooms'] < 20, 0, 1)
# 展示資料
houses
Price | Bathrooms | Square_Feet | Outlier | |
---|---|---|---|---|
0 | 534433 | 2.0 | 1500 | 0 |
1 | 392333 | 3.5 | 2500 | 0 |
2 | 293222 | 2.0 | 1500 | 0 |
3 | 4322032 | 116.0 | 48000 | 1 |
選擇 3:重縮放
# 對數特徵
houses['Log_Of_Square_Feet'] = [np.log(x) for x in houses['Square_Feet']]
# 展示資料
houses
Price | Bathrooms | Square_Feet | Outlier | Log_Of_Square_Feet | |
---|---|---|---|---|---|
0 | 534433 | 2.0 | 1500 | 0 | 7.313220 |
1 | 392333 | 3.5 | 2500 | 0 | 7.824046 |
2 | 293222 | 2.0 | 1500 | 0 | 7.313220 |
3 | 4322032 | 116.0 | 48000 | 1 | 10.778956 |
使用均值填充缺失值
均值插補用該特徵/變數的平均值替換缺失值。 平均插補是最“樸素”的插補方法之一,因為不像 k 最近鄰居插補這樣的更復雜的方法,它不會使用觀測的資訊來估計它的值。
import pandas as pd
import numpy as np
from sklearn.preprocessing import Imputer
# 建立空資料集
df = pd.DataFrame()
# 建立兩個變數,叫做 x0 和 x1
# 使 x1 的第一個值為缺失值
df['x0'] = [0.3051,0.4949,0.6974,0.3769,0.2231,0.341,0.4436,0.5897,0.6308,0.5]
df['x1'] = [np.nan,0.2654,0.2615,0.5846,0.4615,0.8308,0.4962,0.3269,0.5346,0.6731]
# 觀察資料集
df
x0 | x1 | |
---|---|---|
0 | 0.3051 | NaN |
1 | 0.4949 | 0.2654 |
2 | 0.6974 | 0.2615 |
3 | 0.3769 | 0.5846 |
4 | 0.2231 | 0.4615 |
5 | 0.3410 | 0.8308 |
6 | 0.4436 | 0.4962 |
7 | 0.5897 | 0.3269 |
8 | 0.6308 | 0.5346 |
9 | 0.5000 | 0.6731 |
擬合填充器
# 建立一個填充器物件,它尋找 NaN 值,之後將它們按列替換為特徵的均值
mean_imputer = Imputer(missing_values='NaN', strategy='mean', axis=0)
# 在 df 資料及上訓練填充器
mean_imputer = mean_imputer.fit(df)
# 將填充器應用於 df 資料集
imputed_df = mean_imputer.transform(df.values)
# 檢視資料
imputed_df
'''
array([[ 0.3051 , 0.49273333],
[ 0.4949 , 0.2654 ],
[ 0.6974 , 0.2615 ],
[ 0.3769 , 0.5846 ],
[ 0.2231 , 0.4615 ],
[ 0.341 , 0.8308 ],
[ 0.4436 , 0.4962 ],
[ 0.5897 , 0.3269 ],
[ 0.6308 , 0.5346 ],
[ 0.5 , 0.6731 ]])
'''
請注意,0.49273333
是估算值,取代了np.NaN
值。
填充缺失的類標籤
# 載入庫
import numpy as np
from sklearn.preprocessing import Imputer
# 建立帶有類別特徵的特徵矩陣
X = np.array([[0, 2.10, 1.45],
[1, 1.18, 1.33],
[0, 1.22, 1.27],
[0, -0.21, -1.19],
[np.nan, 0.87, 1.31],
[np.nan, -0.67, -0.22]])
# 建立填充器物件
imputer = Imputer(strategy='most_frequent', axis=0)
# 使用最頻繁的類別填充缺失值
imputer.fit_transform(X)
'''
array([[ 0. , 2.1 , 1.45],
[ 1. , 1.18, 1.33],
[ 0. , 1.22, 1.27],
[ 0. , -0.21, -1.19],
[ 0. , 0.87, 1.31],
[ 0. , -0.67, -0.22]])
'''
使用 KNN 填充缺失類別
# 載入庫
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
# 建立帶有類別特徵的特徵矩陣
X = np.array([[0, 2.10, 1.45],
[1, 1.18, 1.33],
[0, 1.22, 1.27],
[1, -0.21, -1.19]])
# 建立類別特徵有缺失的特徵矩陣
X_with_nan = np.array([[np.nan, 0.87, 1.31],
[np.nan, -0.67, -0.22]])
# 訓練 KNN 學習器
clf = KNeighborsClassifier(3, weights='distance')
trained_model = clf.fit(X[:,1:], X[:,0])
# 預測缺失值的類別
imputed_values = trained_model.predict(X_with_nan[:,1:])
# 將預測分類的列和它們的其它特徵連線
X_with_imputed = np.hstack((imputed_values.reshape(-1,1), X_with_nan[:,1:]))
# 連線兩個特徵矩陣
np.vstack((X_with_imputed, X))
'''
array([[ 0. , 0.87, 1.31],
[ 1. , -0.67, -0.22],
[ 0. , 2.1 , 1.45],
[ 1. , 1.18, 1.33],
[ 0. , 1.22, 1.27],
[ 1. , -0.21, -1.19]])
'''
觀測正則化
# 載入庫
from sklearn.preprocessing import Normalizer
import numpy as np
# 建立特徵矩陣
X = np.array([[0.5, 0.5],
[1.1, 3.4],
[1.5, 20.2],
[1.63, 34.4],
[10.9, 3.3]])
Normalizer
重縮放各個觀側,使其具有單位範數(長度之和為 1)。
# 建立正則化器
normalizer = Normalizer(norm='l2')
# 轉換特徵矩陣
normalizer.transform(X)
'''
array([[ 0.70710678, 0.70710678],
[ 0.30782029, 0.95144452],
[ 0.07405353, 0.99725427],
[ 0.04733062, 0.99887928],
[ 0.95709822, 0.28976368]])
'''
多個標籤的獨熱編碼特徵
# 載入庫
from sklearn.preprocessing import MultiLabelBinarizer
import numpy as np
# 建立 NumPy 陣列
y = [('Texas', 'Florida'),
('California', 'Alabama'),
('Texas', 'Florida'),
('Delware', 'Florida'),
('Texas', 'Alabama')]
# 建立 MultiLabelBinarizer 物件
one_hot = MultiLabelBinarizer()
# 獨熱編碼資料
one_hot.fit_transform(y)
'''
array([[0, 0, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 0, 1, 1],
[0, 0, 1, 1, 0],
[1, 0, 0, 0, 1]])
'''
# 檢視類別
one_hot.classes_
# array(['Alabama', 'California', 'Delware', 'Florida', 'Texas'], dtype=object)
獨熱編碼標稱類別特徵
# 載入庫
import numpy as np
import pandas as pd
from sklearn.preprocessing import LabelBinarizer
# 建立 NumPy 陣列
x = np.array([['Texas'],
['California'],
['Texas'],
['Delaware'],
['Texas']])
# 建立 LabelBinzarizer 物件
one_hot = LabelBinarizer()
# 獨熱編碼資料
one_hot.fit_transform(x)
'''
array([[0, 0, 1],
[1, 0, 0],
[0, 0, 1],
[0, 1, 0],
[0, 0, 1]])
'''
# 檢視類別
one_hot.classes_
'''
array(['California', 'Delaware', 'Texas'],
dtype='<U10')
'''
# 虛擬特徵
pd.get_dummies(x[:,0])
California | Delaware | Texas | |
---|---|---|---|
0 | 0 | 0 | 1 |
1 | 1 | 0 | 0 |
2 | 0 | 0 | 1 |
3 | 0 | 1 | 0 |
4 | 0 | 0 | 1 |
預處理類別特徵
通常,機器學習方法(例如