1. 程式人生 > >sklearn中自定義轉換器以及使用流水線對資料據進行處理

sklearn中自定義轉換器以及使用流水線對資料據進行處理

儘管 Scikit-Learn 提供了許多有用的轉換器,你還是需要自己動手寫轉換器執行任務,比如自定義的清理操作,或屬性組合。你需要讓自制的轉換器與 Scikit-Learn 元件(比如流水線)無縫銜接工作,因為 Scikit-Learn 是依賴鴨子型別的(而不是繼承),你所需要做的是建立一個類並執行三個方法: fit() (返回 self ), transform() ,和 fit_transform() 。通過新增 TransformerMixin 作為基類,可以很容易地得到最後一個。另外,如果你新增 BaseEstimator 作為基類(且構造器中避免使用 *args 和 **kargs ),你就能得到兩個額外的方法( get_params() 和 set_params() ),二者可以方便地進行超引數自動微調。例如,一個小轉換器類添加了上面討論的屬性:(來自hands _On Machine Learning with Scikit_learn&TensorFlow

我們的原始資料格式:

上述資料的第3、4、5、6列資料分別是總共房間數、總共的床數、人口數、總共的家庭數,我們可以通過對這些資料變換得到更加細緻的資料。比如可以算出每個家庭擁有的房間數、每個房間平均擁有的床數

首先我們需要使用sklearn中的TransformerMixin和BaseEstimator

匯入的類:

import pandas as pd
from sklearn.base import BaseEstimator,TransformerMixin

全域性變數

  total_rooms,total_bedrooms,population,household=3,4,5,6 #取出我們需要的屬性列

 

自定義的轉換器:

class Attribute_Add(BaseEstimator,TransformerMixin): # 匯入兩個基類獲得fit、transform方法
    def __init__(self,bedrooms_per_room=None):       # bedrooms_per_room=bedrooms_per_room為可選屬性,同時我們設定了兩個必選屬性
        self.bedrooms_per_room=bedrooms_per_room
    def fit(self,x,y=None):
        return self
    def transform(self, x, y=None, ):
          # x=inputdata,y=targetdata
          #下面兩個屬性為我們必選合成屬性
        rooms_per_household = x[:,total_rooms] / x[:,household] # 求取每個房間平均的房間數
        rooms_per_population = x[:,population] / x[:,total_rooms]# 求每個人擁有的平均房間數
        if self.bedrooms_per_room:
          bedrooms_per_room=x[:,total_rooms]/x[:,total_bedrooms]  #bedrooms_per_room為可選的合成屬性
          return np.c_[x,rooms_per_househols,rooms_per_population,bedrooms_per_room]
        else:
            return np.c_[x,rooms_per_househols,rooms_per_population]

同理我們定義如下的轉換器:get_data()、MyOneHotEncode、

class get_data(BaseEstimator,TransformerMixin):#獲取資料表中數值資料或者是文字型別的資料,其中attributes為我們屬性值列表
    def __init__(self,attributes):
        self.attributes=attributes;
    def fit(self,x,y=None):
        return self
    def transform(self,x,y=None):
        return x[self.attributes].values
class MyOneHotEncode(BaseEstimator,TransformerMixin):#將文字型別的資料轉換成數值型別的資料,然後再轉換成獨熱碼
    def __init__(self,data=None):
        self.data=data
    def fit(self,x,y=None):
        return self
    def transform(self,x,y=None):
        encoder = LabelEncoder()
        array1 = encoder.fit_transform(x)
        onehotencode=OneHotEncoder()
        tp=onehotencode.fit_transform(array1.reshape(-1,1))
        #print(tp.toarray())
        return tp.toarray()

 流水線(pipeline)

from sklearn.pipeline import Pipeline  #通俗理解就是前一個轉換器的輸出作為下一個轉換的輸入,依次對資料進行處理
from sklearn.pipeline import FeatureUnion #可以理解為多個流水線同時並行對資料操作,各個流水線工作互不影響
"""
sklearn 中的流水線處理數字資料
"""
num_attributes=list(housing_data.drop("ocean_proximity",axis=1))# ocean_proximity為非數值型別的資料,需要去除掉
num_pipeline=Pipeline([
                 ('get_num',get_data(num_attributes)), # 獲取數值型別資料
                 ('imputer',Imputer(strategy="median")),#補全資料中的空值(用中位數填充空值)sklearn自帶的Imputer      # ( 需要匯入,這裡沒有寫出 from sklearm.preprocessing import Imputer)
                 ('add_attributes',Attribute_Add()),    #合成屬性
                 ('normalize',StandardScaler()),        #資料標準化

])
"""
sklearn中的流水線處理非數字資料
"""
cat=["ocean_proximity"]  # 非數值屬性列
N_num_pipeline=Pipeline([
    ('get_char',get_data(cat)), #獲取非數值資料
    ('label_bin',MyOneHotEncode()),轉換成獨熱碼
])

使用FeatureUnion來讓兩個流水線並行工作(from sklearn.pipline import FeatureUnion)

union_pipeline=FeatureUnion(transformer_list=[
    ("pipeline1",num_pipeline),
    ("pipeline2",N_num_pipeline),
])
tq=union_pipeline.fit_transform(housing_data) # 執行 得出的結果是一個簡單numpy陣列,我們可以將其轉換成pd中DataFrame資料
#格式,方便我們檢視
list=["rooms_per_househols","rooms_per_population","hot1","hot2","hot3","hot4","hot5"] #為新增的屬性列增加名稱
num_attributes.extend(list) # 與之前的屬性列合併
final_data=pd.DataFrame(tq,columns=num_attributes) #轉換成DataFrame
print(final_data) #顯示資料

變數空間顯示的資料