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) #顯示資料
變數空間顯示的資料