目錄html
更新、更全的《機器學習》的更新網站,更有python、go、數據結構與算法、爬蟲、人工智能教學等着你:http://www.javashuo.com/article/p-vozphyqp-cm.htmlpython
sklearn數據預處理官方文檔地址:https://scikit-learn.org/stable/modules/classes.html#module-sklearn.preprocessing算法
import numpy as np import pandas as pd import matplotlib.pyplot as plt from matplotlib.font_manager import FontProperties from sklearn import datasets %matplotlib inline font = FontProperties(fname='/Library/Fonts/Heiti.ttc')
現實生活中的數據每每是不全面的,不少樣本的屬性值會有缺失,例如某我的填寫的我的信息不完整或者對我的隱私的保護政策致使建模時可能沒法獲得所須要的特徵,尤爲是在數據量較大時,這種缺失值的產生會對模型的性能形成很大的影響。接下來將經過鳶尾花數據討論缺失值處理的方法。安全
# 缺失值處理示例 from io import StringIO iris_data = ''' 5.1,,1.4,0.2 4.9,3.0,1.4,0.2 4.7,3.2,,0.2 7.0,3.2,4.7,1.4 6.4,3.2,4.5,1.5 6.9,3.1,4.9, ,,, ''' iris = datasets.load_iris() df = pd.read_csv(StringIO(iris_data), header=None) df.columns = iris.feature_names df = df.iloc[:, :4] df
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | NaN | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | NaN | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | NaN |
6 | NaN | NaN | NaN | NaN |
# axis=0刪除有NaN值的行,axis=1刪除有NaN值的列 df.dropna(axis=0)
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
1 | 4.9 | 3.0 | 1.4 | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
# 刪除全爲NaN值得行或列 df.dropna(how='all')
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | NaN | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | NaN | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | NaN |
# 刪除行不爲4個值的 df.dropna(thresh=4)
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
1 | 4.9 | 3.0 | 1.4 | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
# 刪除花萼長度中有NaN值的數據 df.dropna(subset=['sepal length (cm)'])
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | NaN | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | NaN | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | NaN |
# 填充缺失值示例 from sklearn.impute import SimpleImputer # 對全部缺失值填充固定值0 # imputer = SimpleImputer(missing_values=np.nan, strategy='constant', fill_value=0) # 中位數strategy=median,衆數strategy=most_frequent imputer = SimpleImputer(missing_values=np.nan, strategy='mean') imputer = imputer.fit_transform(df.values) df = pd.DataFrame(imputer, columns=iris.feature_names) df
sepal length (cm) | sepal width (cm) | petal length (cm) | petal width (cm) | |
---|---|---|---|---|
0 | 5.1 | 0.0 | 1.4 | 0.2 |
1 | 4.9 | 3.0 | 1.4 | 0.2 |
2 | 4.7 | 3.2 | 0.0 | 0.2 |
3 | 7.0 | 3.2 | 4.7 | 1.4 |
4 | 6.4 | 3.2 | 4.5 | 1.5 |
5 | 6.9 | 3.1 | 4.9 | 0.0 |
6 | 0.0 | 0.0 | 0.0 | 0.0 |
異常值有時候也會被稱爲離羣值,處理異常值的方式相似於缺失值處理,能夠暴力刪除,也能夠填充。可是異常值每每須要手動獲取,通常獲取異常值的方式有如下兩種:數據結構
統計分析原則app
對特徵值統計後分析判斷哪些值是不符合邏輯的,拿年齡舉例,若是發現某我的的年齡是200,至少目前是不合理的,所以能夠設定一個條件,把年齡大於200的數據都排除掉。機率分佈原則dom
根據高斯分佈可知距離平均值\(3\delta\)以外的機率爲0.003,這在統計學中屬於極小機率事件,所以能夠把超過該距離的值看成異常值處理。固然,你也能夠手動設定這個距離或機率,具體問題具體分析。機器學習
# 標準高斯分佈曲線 fig, ax = plt.subplots() np.random.seed(1) # 建立一組平均數爲0,標準差δ爲1,總個數爲100000的符合標準正態分佈的數據 Gaussian = np.random.normal(0, 1, 100000) ax.hist(Gaussian, bins=100, histtype="stepfilled", density=True, alpha=0.5, color='r') plt.xticks(np.arange(3, 4)) plt.title('標準高斯分佈曲線', fontproperties=font, fontsize=20) plt.show()
現有一個汽車樣本集,經過這個汽車樣本集能夠判斷人們是否會購買該汽車。可是這個樣本集的特徵值是離散型的,爲了確保計算機能正確讀取該離散值的特徵,須要給這些特徵作編碼處理,即建立一個映射表。若是特徵值分類較少,能夠選擇自定義一個字典存放特徵值與自定義值的關係。接下來將直接經過scikit-learn庫轉換屬性值類型。函數
# 汽車樣本 car_data = ''' 乘坐人數,後備箱大小,安全性,是否能夠接受 4,med,high,acc 2,big,low,unacc 4,big,med,acc 4,big,high,acc 6,small,low,unacc 6,small,med,unacc ''' df = pd.read_csv(StringIO(car_data), header=0) df
乘坐人數 | 後備箱大小 | 安全性 | 是否能夠接受 | |
---|---|---|---|---|
0 | 4 | med | high | acc |
1 | 2 | big | low | unacc |
2 | 4 | big | med | acc |
3 | 4 | big | high | acc |
4 | 6 | small | low | unacc |
5 | 6 | small | med | unacc |
safety_mapping = { 'low': 0, 'med': 1, 'high': 2, } df['安全性'] = df['安全性'].map(safety_mapping) df
乘坐人數 | 後備箱大小 | 安全性 | 是否能夠接受 | |
---|---|---|---|---|
0 | 4 | med | 2 | acc |
1 | 2 | big | 0 | unacc |
2 | 4 | big | 1 | acc |
3 | 4 | big | 2 | acc |
4 | 6 | small | 0 | unacc |
5 | 6 | small | 1 | unacc |
# 對上述字典作反向映射處理,即反向映射回原來的離散類型的特徵值。 inverse_safety_mapping = {v: k for k, v in safety_mapping.items()} df['安全性'].map(inverse_safety_mapping)
0 high 1 low 2 med 3 high 4 low 5 med Name: 安全性, dtype: object
繼續沿用上一個汽車樣本,使用sklearn自帶庫對數據類型編碼。性能
# scikit-learn數據類型編碼示例 from sklearn.preprocessing import LabelEncoder X_label_encoder = LabelEncoder() X = df[['乘坐人數', '後備箱大小', '安全性']].values X[:, 1] = X_label_encoder.fit_transform(X[:, 1]) X
array([[4, 1, 2], [2, 0, 0], [4, 0, 1], [4, 0, 2], [6, 2, 0], [6, 2, 1]], dtype=object)
# 對標記進行編碼 y_label_encoder = LabelEncoder() y = y_label_encoder.fit_transform(df['是否能夠接受'].values) y
array([0, 1, 0, 0, 1, 1])
# 對標記反向映射回原始數據 y_label_encoder.inverse_transform(y)
array(['acc', 'unacc', 'acc', 'acc', 'unacc', 'unacc'], dtype=object)
假設汽車安全性只是一個衡量標準,沒有特定的順序。可是計算機頗有可能把這些\(0,1,2\)做一個特定排序或者所以區分它們的重要性,這個時候就得考慮建立一個二進制值分別表示low、med、high這三個屬性值,有爲1,沒有爲0,例如\(010\)表示爲med。
# 獨熱編碼示例 from sklearn.preprocessing import OneHotEncoder one_hot_encoder = OneHotEncoder(categories='auto') one_hot_encoder.fit_transform(X).toarray()
array([[0., 1., 0., 0., 1., 0., 0., 0., 1.], [1., 0., 0., 1., 0., 0., 1., 0., 0.], [0., 1., 0., 1., 0., 0., 0., 1., 0.], [0., 1., 0., 1., 0., 0., 0., 0., 1.], [0., 0., 1., 0., 0., 1., 1., 0., 0.], [0., 0., 1., 0., 0., 1., 0., 1., 0.]])
# 使用pandas對數據作獨熱編碼處理,數值型數據不作編碼處理 pd.get_dummies(df[['乘坐人數', '後備箱大小', '安全性']])
乘坐人數 | 安全性 | 後備箱大小_big | 後備箱大小_med | 後備箱大小_small | |
---|---|---|---|---|---|
0 | 4 | 2 | 0 | 1 | 0 |
1 | 2 | 0 | 1 | 0 | 0 |
2 | 4 | 1 | 1 | 0 | 0 |
3 | 4 | 2 | 1 | 0 | 0 |
4 | 6 | 0 | 0 | 0 | 1 |
5 | 6 | 1 | 0 | 0 | 1 |
使用獨熱編碼在解決特徵值無序性的同時也增長了特徵數,這無疑會給將來的計算增長難度,所以能夠適當減小沒必要要的維度。例如當爲後備箱進行獨熱編碼的時候會有後備箱大小_big、後備箱大小_med、後備箱大小_small三個特徵,能夠減去一個特徵,即後備箱大小_big與後備箱大小_med都爲0則表明是後備箱大小_small。在調用pandas的get_dummies函數時,能夠添加drop_first=True參數;而使用OneHotEncoder時得本身分隔。
pd.get_dummies(df[['乘坐人數', '後備箱大小', '安全性']], drop_first=True)
乘坐人數 | 安全性 | 後備箱大小_med | 後備箱大小_small | |
---|---|---|---|---|
0 | 4 | 2 | 1 | 0 |
1 | 2 | 0 | 0 | 0 |
2 | 4 | 1 | 0 | 0 |
3 | 4 | 2 | 0 | 0 |
4 | 6 | 0 | 0 | 1 |
5 | 6 | 1 | 0 | 1 |
爲了解決相同權重特徵不一樣尺度的問題,可使用機器學習中的最小-最大標準化作處理,把他們兩個值壓縮在\([0-1]\)區間內。
最小-最大標準化公式:
\[ x_{norm}^{(i)}={\frac{x^{(i)}-x_{min}}{x_{max}-x_{min}}} \]
其中\(i=1,2,\cdots,m\);\(m\)爲樣本個數;\(x_{min},x_{max}\)分別是某個的特徵最小值和最大值。
# 最小最大標準化示例 from sklearn.preprocessing import MinMaxScaler import numpy as np test_data = np.array([1, 2, 3, 4, 5]).reshape(-1, 1).astype(float) min_max_scaler = MinMaxScaler() min_max_scaler.fit_transform(test_data)
array([[0. ], [0.25], [0.5 ], [0.75], [1. ]])
Z-score標準化方法也能夠對數據進行標準化,可是它的標準化並不能把數據限制在某個區間,它把數據壓縮成相似高斯分佈的分佈方式,而且也能處理離羣值對數據的影響。
在分類、聚類算法中,須要使用距離來度量類似性的時候應用很是好,尤爲是數據自己呈正態分佈的時候。
數據標準化公式:
\[ x_{std}^{(i)}={\frac{x^{(i)}-\mu{_x}}{\sigma{_x}}} \]
使用標準化後,能夠把特徵列的中心設在均值爲\(0\)且標準差爲\(1\)的位置,即數據處理後特徵列符合標準正態分佈。
# Z-score標準化 from sklearn.preprocessing import StandardScaler test_data = np.array([1, 2, 3, 4, 5]).reshape(-1, 1).astype(float) standard_scaler = StandardScaler() # fit_transform()=fit()+transform(), fit()方法估算平均值和方差,transform()方法對數據標準化 standard_scaler.fit_transform(test_data)
array([[-1.41421356], [-0.70710678], [ 0. ], [ 0.70710678], [ 1.41421356]])
二值化數據相似於獨熱編碼,可是不一樣於獨熱編碼的是它不是0就是1,即又有點相似於二分類。直接給出數據二值化的公式:
\[ y = \begin{cases} 0,\quad if x \leq {\theta} \\ 1,\quad if x \geq {\theta} \end{cases} \]
其中\(\theta\)是手動設置的閾值,若是特徵值小於閾值爲0;特徵值大於閾值爲1。
# 數據二值化示例 from sklearn.preprocessing import Binarizer test_data = np.array([1, 2, 3, 4, 5]).reshape(-1, 1).astype(float) binarizer = Binarizer(threshold=2.5) binarizer.fit_transform(test_data)
array([[0.], [0.], [1.], [1.], [1.]])
正則化是將每一個樣本縮放到單位範數,即便得每一個樣本的p範數爲1,對須要計算樣本間類似度有很大的做用,一般有L1正則化和L2正則化兩種方法。
# L1正則化示例 from sklearn.preprocessing import normalize test_data = [[1, 2, 0, 4, 5], [2, 3, 4, 5, 9]] normalize = normalize(test_data, norm='l1') normalize
array([[0.08333333, 0.16666667, 0. , 0.33333333, 0.41666667], [0.08695652, 0.13043478, 0.17391304, 0.2173913 , 0.39130435]])
# L2正則化示例 from sklearn.preprocessing import Normalizer test_data = [[1, 2, 0, 4, 5], [2, 3, 4, 5, 9]] normalize = Normalizer(norm='l2') normalize = normalize.fit_transform(test_data) normalize
array([[0.14744196, 0.29488391, 0. , 0.58976782, 0.73720978], [0.17213259, 0.25819889, 0.34426519, 0.43033148, 0.77459667]])
# 生成多項式特徵圖例 import matplotlib.pyplot as plt from sklearn import datasets %matplotlib inline X1, y1 = datasets.make_circles( n_samples=1000, random_state=1, factor=0.5, noise=0.1) plt.scatter(0, 0, s=23000, color='white', edgecolors='r') plt.scatter(X1[:, 0], X1[:, 1], marker='*', c=y1) plt.xlabel('$x_1$', fontsize=15) plt.ylabel('$x_2$', fontsize=15) plt.title('make_circles()', fontsize=20) plt.show()
有時候可能會遇到上圖所示的數據分佈狀況,若是這個時候使用簡單的\(x_1,x_2\)特徵去擬合曲線,明顯是不可能的,可是咱們可使用,可是咱們可使用\(x_1^2+x_2^2=1\)去擬合數據,可能會獲得一個較好的模型,因此咱們有時候會對特徵作一個多項式處理,即把特徵\(x_1,x_2\)變成\(x_1^2,x_2^2\)。
test_data = [[1, 2], [3, 4], [5, 6]] test_data
[[1, 2], [3, 4], [5, 6]]
經過多項式特徵,特徵將會作以下變換
\[ x_1,x_2\quad\rightarrow\quad1,x_1,x_2,x_1^2,x_1x_2,x_2^2 \]
# 生成多項式特徵示例 from sklearn.preprocessing import PolynomialFeatures poly = PolynomialFeatures() poly = poly.fit_transform(test_data) poly
array([[ 1., 1., 2., 1., 2., 4.], [ 1., 3., 4., 9., 12., 16.], [ 1., 5., 6., 25., 30., 36.]])