機器學習之數據預處理


在sklearn之數據分析中總結了數據分析常用方法,接下來對數據預處理進行總結

當我們拿到數據集后一般需要進行以下步驟:

  • (1)明確有數據集有多少特征,哪些是連續的,哪些是類別的
  • (2)檢查有沒有缺失值,對缺失的特征選擇恰當的方式進行彌補,使數據完整
  • (3)對連續的數值型特征進行標准化
  • (4)對類別型的特征進行編碼
  • (5)根據實際問題分析是否需要對特征進行相應的函數轉換

依然以房價數據為例,依次進行上述操作

import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
housing = pd.read_csv('./datasets/housing/housing.csv')

1. 明確數據集有多少特征,哪些是連續的,哪些是類別的

print(housing.shape)
(20640, 10)
print(housing.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20640 entries, 0 to 20639
Data columns (total 10 columns):
longitude             20640 non-null float64
latitude              20640 non-null float64
housing_median_age    20640 non-null float64
total_rooms           20640 non-null float64
total_bedrooms        20433 non-null float64
population            20640 non-null float64
households            20640 non-null float64
median_income         20640 non-null float64
median_house_value    20640 non-null float64
ocean_proximity       20640 non-null object
dtypes: float64(9), object(1)
memory usage: 1.6+ MB
None

2. 檢查有沒有缺失值,對缺失的特征選擇恰當的方式進行彌補,使數據完整

通過info()發現除了:

  • ocean_proximity屬性類別為object外,其余都為float64類型,則判斷ocean_proximity為標簽,其余為特征值
  • total_bedrooms存在缺失值

2.1 缺失值處理方式

(1) 放棄缺失值所在的行

(2) 放棄缺失值所在的屬性,即列

(3) 將缺失值設置為某個值(0,平均值、中位數或使用頻率高的值)

print(housing[housing.isnull().T.any().T][:5])  #打印有NaN的行的前5行
     longitude  latitude  housing_median_age  total_rooms  total_bedrooms  \
290    -122.16     37.77                47.0       1256.0             NaN   
341    -122.17     37.75                38.0        992.0             NaN   
538    -122.28     37.78                29.0       5154.0             NaN   
563    -122.24     37.75                45.0        891.0             NaN   
696    -122.10     37.69                41.0        746.0             NaN   

     population  households  median_income  median_house_value ocean_proximity  
290       570.0       218.0         4.3750            161900.0        NEAR BAY  
341       732.0       259.0         1.6196             85100.0        NEAR BAY  
538      3741.0      1273.0         2.5762            173400.0        NEAR BAY  
563       384.0       146.0         4.9489            247100.0        NEAR BAY  
696       387.0       161.0         3.9063            178400.0        NEAR BAY  

2.1.1 刪除缺失值所在的行

# 刪除行
housing1 = housing.dropna(subset=['total_bedrooms'])
print(housing1.info())
<class 'pandas.core.frame.DataFrame'>
Int64Index: 20433 entries, 0 to 20639
Data columns (total 10 columns):
longitude             20433 non-null float64
latitude              20433 non-null float64
housing_median_age    20433 non-null float64
total_rooms           20433 non-null float64
total_bedrooms        20433 non-null float64
population            20433 non-null float64
households            20433 non-null float64
median_income         20433 non-null float64
median_house_value    20433 non-null float64
ocean_proximity       20433 non-null object
dtypes: float64(9), object(1)
memory usage: 1.7+ MB
None

2.1.2 刪除缺失值所在的列

# 刪除列
housing2 = housing.drop(['total_bedrooms',],axis=1)
print(housing2.info())
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 20640 entries, 0 to 20639
Data columns (total 9 columns):
longitude             20640 non-null float64
latitude              20640 non-null float64
housing_median_age    20640 non-null float64
total_rooms           20640 non-null float64
population            20640 non-null float64
households            20640 non-null float64
median_income         20640 non-null float64
median_house_value    20640 non-null float64
ocean_proximity       20640 non-null object
dtypes: float64(8), object(1)
memory usage: 1.4+ MB
None

2.1.3 替換缺失值

# 使用平均值替換
mean = housing['total_bedrooms'].mean()
print('mean:',mean)
housing3 = housing.fillna({'total_bedrooms':mean})
print(housing3[290:291])
mean: 537.8705525375618
     longitude  latitude  housing_median_age  total_rooms  total_bedrooms  \
290    -122.16     37.77                47.0       1256.0      537.870553   

     population  households  median_income  median_house_value ocean_proximity  
290       570.0       218.0          4.375            161900.0        NEAR BAY  

3. 對連續的數值型特征進行標准化

當數據集的數值屬性具有非常大的比例差異,往往導致機器學習的算法表現不佳,當然也有極少數特例。在實際應用中,通過梯度下降法求解的模型通常需要歸一化,包括線性回歸、邏輯回歸、支持向量機、神經網絡等模型。但對於決策樹不使用,以C4.5為例,決策樹在進行節點分裂時主要依據數據集D關於特征X的信息增益比,而信息增益比跟特征是否經過歸一化是無關的

數據標准化常用方法有:

  • 最小-最大縮放(又加歸一化),將值重新縮放使其最終范圍在0-1之間,(current - min)/ (max - min)
  • 標准化,(current - mean) / var,使得得到的結果分布具備單位方差,相比最小-最大縮放,標准化的方法受異常值的影響更小

4. 對類別型的特征進行編碼

4.1 為什么要進行編碼

在監督學習中,除了決策樹等少數模型外都需要將預測值與實際值(也就是說標簽)進行比較,然后通過算法優化損失函數,這就需要將標簽轉換為數值類型用於計算

4.2 如何編碼

常用的編碼方式有:序號編碼,獨熱編碼,二進制編碼

4.2.1 序號編碼

序號編碼通常用於處理類別間具有大小感謝的數據,例如成績,可以分為低、中、高三檔,並且存在‘高>中>低’的排列順序,序號編碼會按照大小關系對類別型特征賦予一個數值ID,例如高表示3,中表示2,低表示1

4.2.2 獨熱編碼

獨熱編碼通常用於處理類別間不具有大小關系的特征。例如血血型,一共有4個取值(A型血、B型血、AB型血、O型血),獨熱編碼會把血型變成一個4維稀疏向量,A型血表示(1,0,0,0),B型血表示(0,1,0,0),C型血表示(0,0,1,0),D型血表示(0,0,0,1)

對於類別取值較多的情況下使用獨熱編碼需要注意以下問題:

(1) 使用稀疏向量來節省空間

在獨熱編碼下,特征向量只有某一維取1,其他位置均為0,因此可以利用向量的稀疏性表示有效地節省空間,並且目前大部分的算法均接受稀疏向量形式的輸入

(2) 配合特征選擇來降低維度

4.2.3 二進制編碼

二進制編碼本質上就是利用二進制對ID進行哈希映射,最終得到0/1特征向量,且維數少於獨熱編碼,節省了存儲空間

5. 根據實際問題分析是否需要對特征進行相應的函數轉換

當我們對數據集進行一定程度的分析之后,可能會發現不同屬性之間的某些有趣的聯系,特別是跟目標屬性相關的聯系,在准備給機器學習算法輸入數據之前,應該嘗試各種屬性的組合

以上面的房價數據集為例,如果你不知道一個地區有多少個家庭,那么知道一個地區的房間總數也沒什么用,你真正想知道是的一個家庭的房間數量,同樣的,但看卧室總數這個屬性本身,也沒有什么意義,你可能想拿它和房間總數來對比,或者拿來通每個家庭的人口數這個屬性結合

5.1 查看原數據集屬性與房間中位數的相關性

corr_martrix = housing.corr()
print(corr_martrix['median_house_value'].sort_values(ascending=False))
median_house_value    1.000000
median_income         0.688075
total_rooms           0.134153
housing_median_age    0.105623
households            0.065843
total_bedrooms        0.049686
population           -0.024650
longitude            -0.045967
latitude             -0.144160
Name: median_house_value, dtype: float64

5.2 查看屬性組合后與房間中位數的相關性

housing4 = housing.copy()
housing4['rooms_per_household'] = housing4['total_rooms'] / housing4['households']
housing4['bedrooms_per_room'] = housing4['total_bedrooms'] / housing4['total_rooms']
housing4['population_per_household'] = housing4['population'] / housing4['households']

corr_martrix1 = housing.corr()
print(corr_martrix1['median_house_value'].sort_values(ascending=False))
median_house_value    1.000000
median_income         0.688075
total_rooms           0.134153
housing_median_age    0.105623
households            0.065843
total_bedrooms        0.049686
population           -0.024650
longitude            -0.045967
latitude             -0.144160
Name: median_house_value, dtype: float64

可以看出bedrooms_per_room較房間總數或是卧室總數與房價中位數的相關性要高的多,所以在進行屬性組合時可以多多嘗試

6. 使用Sklearn.pipeline實現數據預處理

6.1 代碼實現

from sklearn.preprocessing import Imputer,LabelEncoder,OneHotEncoder,StandardScaler
from sklearn.base import BaseEstimator,TransformerMixin
from sklearn.pipeline import Pipeline,FeatureUnion
class DaraFrameSelector(BaseEstimator,TransformerMixin):
    def __init__(self,attr_name):
        self.attr_name = attr_name
        
    def fit(self,X,Y=None):
        return self
    
    def transform(self,X,Y=None):
        return X[self.attr_name].values
features_attr = list(housing.columns[:-1])
labels_attr = [housing.columns[-1]]

feature_pipeline = Pipeline([('selector',DaraFrameSelector(features_attr)),
                 ('imputer',Imputer(strategy='mean')),
                 ('scaler',StandardScaler()),])

label_pipeline = Pipeline([('selector',DaraFrameSelector(labels_attr)),
                           ('encoder',OneHotEncoder()),])

full_pipeline = FeatureUnion(transformer_list=[('feature_pipeline',feature_pipeline),
                                               ('label_pipeline',label_pipeline),])
                                               
C:\Anaconda3\lib\site-packages\sklearn\utils\deprecation.py:58: DeprecationWarning: Class Imputer is deprecated; Imputer was deprecated in version 0.20 and will be removed in 0.22. Import impute.SimpleImputer from sklearn instead.
  warnings.warn(msg, category=DeprecationWarning)
housing_prepared = full_pipeline.fit_transform(housing)
print(housing_prepared.shape)
(20640, 14)

參考資料:

  • (1) 《機器學習實戰基於Scikit-Learn和TensorFlow》
  • (2) 《白面機器學習》


免責聲明!

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



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