當前位置:
首頁 > 新聞 > AI開發最大升級:Pandas與Scikit-Learn合併,新工作流程更簡單強大!

AI開發最大升級:Pandas與Scikit-Learn合併,新工作流程更簡單強大!

新智元AI WORLD 2018世界人工智慧峰會

倒計時12

新智元將於9月20日在北京國家會議中心舉辦AI WORLD 2018世界人工智慧峰會,CMU機器學習系創始人、教科書Machine Learning作者、被譽為「機器學習教父」的Tom Mitchell將親臨會場做《人工智慧與我們的未來》主題演講。Mithcell教授表示,這將是一場融入深度思考與偏技術討論的報告。

活動行購票二維碼:

新智元報道

來源:Medium

作者:Ted Petrou

編輯:三石、大明

【新智元導讀】Scikit-Learn發布0.20預覽版,Scikit-Learn與Pandas的新融合會使以往的工作流程更為簡單,其功能也更為豐富、更具魯棒性。

Scikit-Learn的0.20版本,將會是進行近年來最重磅的升級。

對於許多數據科學家來說,一個典型的工作流程是在Scikit-Learn進行機器學習之前,用Pandas進行探索性的數據分析。新版本的Scikit-Learn將會讓這個過程變得更加簡單、功能更加豐富、更魯棒以及更加標準化。

註:本文中的0.20版本的是指預覽版,最終版本目前還沒有發布。

升級到0.20版本

幾日前,官方剛剛發布這個0.20的預覽版。用戶可以通過conda命令進行安裝:

conda install scikit-learn=0.20rc1 -c conda-forge/label/rc -c conda-forge

也可以通過pip命令進行安裝:

pip install — pre scikit-learn

ColumnTransformer、升級版OneHotEncoder介紹

隨著0.20版本的升級,從Pandas到Scikit-Learn的許多工作流會變得比較相似。ColumnTransformer估計器會將一個轉換應用到Pandas DataFrame(或數組)列的特定子集。

OneHotEncoder估計器不是「新生物」,但已經升級為編碼字元串列。以前,它只對包含數字分類數據的列進行編碼。

接下來,讓我們看看這些新添加的功能是如何處理Pandas DataFrame中的字元串列的。

Kaggle住房數據集

Kaggle最早的機器學習競賽題目之一是《住房價格:先進的回歸技術》。其目標是在給定80個特徵情況下,預測房價。

數據一覽

在DataFrame中讀取數據並輸出前幾行。

>>>importpandasaspd

>>>importnumpyasnp

>>> train = pd.read_csv(『data/housing/train.csv』)

>>> train.head()

>>> train.shape

(1460,81)

從訓練集中刪除目標變數

目標變數是SalePrice,我們將它作為數組移除並分配給它自己的變數。我們將在後面的機器學習中用到它。

>>> y = train.pop("SalePrice").values

編碼單個字元串列

首先,我們編碼一個字元串列HoustStyle,它具有房子外觀的值。讓我們輸出每個字元串值的唯一計數。

>>> vc = train["HouseStyle"].value_counts()

>>> vc

1Story726

2Story445

1.5Fin154

SLvl65

SFoyer37

1.5Unf14

2.5Unf11

2.5Fin8

Name: HouseStyle, dtype: int64

這一列中有8個唯一值(unique value)。

scikitlearn Gotcha必須有2D數據

大多數Scikit-Learn估計器嚴格要求數據是的2D的。從技術角度講,如果我們選擇上面的列作為train[「HouseStyle」],Pandas Series是數據的單一維度。我們可以強制Pandas創建一個單列DataFrame,方法是將一個單項列表傳遞到方括弧中,如下所示:

>>> hs_train = train[["HouseStyle"]].copy()

>>> hs_train.ndim

2

評估器的三個步驟過程——導入、實例化、匹配

Scikit-Learn API對於所有的估計器都是一致的,它根據下面三個步驟來匹配(訓練)數據。

從它所在的模塊中導入我們想要的估計器

實例化估計器,可能改變它的默認值

根據數據擬合估計量。在必要情況下,可以將數據轉換到新的空間。

下面,我們導入一個hotencoder,將它實例化,並確保返回一個密集(而不是稀疏)的數組,然後用fit_transform方法對單個列進行編碼。

>>>fromsklearn.preprocessingimportOneHotEncoder

>>> ohe = OneHotEncoder(sparse=False)

>>> hs_train_transformed = ohe.fit_transform(hs_train)

>>> hs_train_transformed

array([[0.,0.,0., ...,1.,0.,0.],

[0.,0.,1., ...,0.,0.,0.],

[0.,0.,0., ...,1.,0.,0.],

...,

[0.,0.,0., ...,1.,0.,0.],

[0.,0.,1., ...,0.,0.,0.],

[0.,0.,1., ...,0.,0.,0.]])

正如預期的那樣,它將每個唯一的值編碼為自己的二進位列。

>>> hs_train_transformed.shape

(1460,8)

得到了NumPy數組,那麼列名在哪裡?

注意,我們的輸出是一個NumPy數組,而不是Pandas DataFrame。Scikit-Learn最初不是為了直接與Pandas整合而建的。所有的Pandas對象都在內部轉換成NumPy數組,並且在轉換後總是返回NumPy數組。

我們仍然可以通過其get_feature_names方法從OneHotEncoder對象獲得列名。

>>> feature_names = ohe.get_feature_names()

>>> feature_names

array(["x0_1.5Fin","x0_1.5Unf","x0_1Story","x0_2.5Fin",

"x0_2.5Unf","x0_2Story","x0_SFoyer","x0_SLvl"], dtype=object)

驗證第一行數據的正確性

接下來讓我們驗證估計值是否正確。首先是第一行編碼的數據。

>>> row0 = hs_train_transformed[]

>>> row0

array([0.,0.,0.,0.,0.,1.,0.,0.])

這將數組中的第6個值編碼為1。讓我們使用布爾索引(boolean index)來顯示特徵名稱。

>>> feature_names[row0 ==1]

array(["x0_2Story"], dtype=object)

現在,讓我們驗證原始DataFrame列中的第一個值是否相同。

>>> hs_train.values[]

array(["2Story"], dtype=object)

使用inverse_transform來實現自動化

與大多數transformer對象一樣,有一個inverse_transform方法可以返回原始數據。在這裡,我們必須將row0包裝在一個列表中,使其成為一個2D數組。

>>> ohe.inverse_transform([row0])

array([["2Story"]], dtype=object)

我們可以通過轉置整個轉換後的數組來驗證所有的值。

>>> hs_inv = ohe.inverse_transform(hs_train_transformed)

>>> hs_inv

array([["2Story"],

["1Story"],

["2Story"],

...,

["2Story"],

["1Story"],

["1Story"]], dtype=object)

>>> np.array_equal(hs_inv, hs_train.values)

True

將轉換應用到測試集中

無論我們對訓練集做什麼轉換,我們都必須應用到測試集。

>>> test = pd.read_csv("data/housing/test.csv")

>>> hs_test = test[["HouseStyle"]].copy()

>>> hs_test_transformed = ohe.transform(hs_test)

>>> hs_test_transformed

array([[0.,0.,1., ...,0.,0.,0.],

[0.,0.,1., ...,0.,0.,0.],

[0.,0.,0., ...,1.,0.,0.],

...,

[0.,0.,1., ...,0.,0.,0.],

[0.,0.,0., ...,0.,1.,0.],

[0.,0.,0., ...,1.,0.,0.]])

我們又得到了8列。

>>> hs_test_transformed.shape

(1459,8)

必須impute缺失數據

現在,我們必須impute缺失數據。預處理模塊中舊的Imputer已經被棄用。一個新的模塊——impute,由一個新的估計值SimpleImputer和一個新的策略「常量」組成。默認情況下,此策略將用字元串「missing_value」來填充缺失值。我們可以選擇使用fill_value參數設置它。

>>> hs_train = train[["HouseStyle"]].copy()

>>> hs_train.iloc[,] = np.nan

>>>fromsklearn.imputeimportSimpleImputer

>>> si = SimpleImputer(strategy="constant", fill_value="MISSING")

>>> hs_train_imputed = si.fit_transform(hs_train)

>>> hs_train_imputed

array([["MISSING"],

["1Story"],

["2Story"],

...,

["2Story"],

["1Story"],

["1Story"]], dtype=object)

接下來,我們可以像以前那樣編碼啦!

>>> hs_train_transformed = ohe.fit_transform(hs_train_imputed)

>>> hs_train_transformed

array([[0.,0.,0., ...,1.,0.,0.],

[0.,0.,1., ...,0.,0.,0.],

[0.,0.,0., ...,0.,0.,0.],

...,

[0.,0.,0., ...,0.,0.,0.],

[0.,0.,1., ...,0.,0.,0.],

[0.,0.,1., ...,0.,0.,0.]])

注意,我們現在有了一個額外的列和一個額外的特徵名稱。

>>> hs_train_transformed.shape

(1460,9)

>>> ohe.get_feature_names()

array(["x0_1.5Fin","x0_1.5Unf","x0_1Story","x0_2.5Fin",

"x0_2.5Unf","x0_2Story","x0_MISSING","x0_SFoyer",

"x0_SLvl"], dtype=object)

更多關於fit_transform的細節

對於所有的估計器,fit_transform方法將首先調用fit方法,然後調用transform方法。fit方法找到轉換過程中使用的關鍵屬性。例如,對於SimpleImputer,如果策略是「均值」,那麼它就會在fit方法中找到每一列的均值。它會存儲每一列的均值。當調用transform時,它使用每個列的這個存儲平均值來填充缺失值並返迴轉換後的數組。

OneHotEncoder原理是類似的。在fit方法中,它會找到每個列的所有唯一值,並再次存儲這些值。在調用transform時,它使用這些存儲的惟一值來生成二進位數組。

將兩個轉換應用到測試集

我們可以手動應用上面的兩個步驟,如下所示:

>>> hs_test = test[["HouseStyle"]].copy()

>>> hs_test.iloc[,] ="unique value to test set"

>>> hs_test.iloc[1,] = np.nan

>>> hs_test_imputed = si.transform(hs_test)

>>> hs_test_transformed = ohe.transform(hs_test_imputed)

>>> hs_test_transformed.shape

(1459,8)

>>> ohe.get_feature_names()

array(["x0_1.5Fin","x0_1.5Unf","x0_1Story","x0_2.5Fin",

"x0_2.5Unf","x0_2Story","x0_SFoyer","x0_SLvl"],

dtype=object)

使用一個Pipeline來替代

Scikit-Learn提供了一個Pipeline估計器,它獲取一個轉換列表並依次應用它們。您還可以運行機器學習模型作為最終評估器。在這裡,我們只是簡單地impute和編碼。

>>>fromsklearn.pipelineimportPipeline

每個步驟是一個two-item元組,由一個標記步驟和實例化估計器的字元串組成。前一個步驟的輸出是後一個步驟的輸入。

>>> si_step = ("si", SimpleImputer(strategy="constant",

fill_value="MISSING"))

>>> ohe_step = ("ohe", OneHotEncoder(sparse=False,

handle_unknown="ignore"))

>>> steps = [si_step, ohe_step]

>>> pipe = Pipeline(steps)

>>> hs_train = train[["HouseStyle"]].copy()

>>> hs_train.iloc[,] = np.nan

>>> hs_transformed = pipe.fit_transform(hs_train)

>>> hs_transformed.shape

(1460,9)

通過簡單地將測試集傳遞給transform方法,可以輕鬆地通過Pipeline的每個步驟轉換測試集。

>>> hs_test = test[["HouseStyle"]].copy()

>>> hs_test_transformed = pipe.transform(hs_test)

>>> hs_test_transformed.shape

(1459,9)

為什麼只對測試集轉換方法?

在轉換測試集時,重要的是只調用transform方法,而不是fit_transform。當我們在訓練集中運行fit_transform時,Scikit-Learn找到了它需要的所有必要信息,以便轉換包含相同列名的任何其他數據集。

多字元串列轉換

對多列字元串進行編碼不成問題。先選擇你要編碼的列,再通過同樣的流程傳遞新的數據框架。

>>> string_cols = ["RoofMatl","HouseStyle"]

>>> string_train = train[string_cols]

>>> string_train.head(3)

RoofMatl HouseStyle

CompShg2Story

1CompShg1Story

2CompShg2Story

>>> string_train_transformed = pipe.fit_transform(string_train)

>>> string_train_transformed.shape

(1460,16)

把握pipeline的每個部分

我們可以通過named_steps字典屬性中的名稱檢索pipeline中的每個轉換器。在本例中,我們可以得到一個熱門編碼器,用來輸出特徵名稱。

>>> ohe = pipe.named_steps["ohe"]

>>> ohe.get_feature_names()

array(["x0_ClyTile","x0_CompShg","x0_Membran","x0_Metal",

"x0_Roll","x0_Tar&Grv","x0_WdShake","x0_WdShngl",

"x1_1.5Fin","x1_1.5Unf","x1_1Story","x1_2.5Fin",

"x1_2.5Unf","x1_2Story","x1_SFoyer","x1_SLvl"],

dtype=object)

使用新的列轉換器來選擇列

全新的列轉換器(屬於新組合模塊的一部分)可以讓用戶選擇要讓哪些列獲得哪些轉換。 與連續列相比,分類列幾乎總是需要單獨的轉換。

列轉換器目前是還是實驗性的,其功能將來可能會發生變化。

ColumnTransformer獲取三項元組(tuple)的列表。 元組中的第一個值其標記作用的名稱,第二個是實例化的估算器,第三個是要進行轉換的列的列表。 元組如下所示:

("name", SomeTransformer(parameters), columns)

這裡的列實際上不必一定是列名。用戶可以使用列的整數索引,布爾數組,甚至函數(它可以使用整個DataFrame作為參數,並且必須返回選擇的列)。

用戶也可以將NumPy數組與列轉換器一起使用,但本教程主要關注Pandas的集成,因此我們這裡繼續使用DataFrames。

將pipeline傳遞給列轉換器

我們甚至可以將多個轉換的流程傳遞給列轉換器,我們現在正是要這樣做,因為在字元串列上有多個轉換。

下面,我們使用列轉換器重現上述流程和編碼。 請注意,實際流程與上面的流程完全相同,只是附加了每個變數名稱的cat。 我們將在下一章節中為數字列添加不同的流程。

>>>fromsklearn.composeimportColumnTransformer

>>> cat_si_step = ("si", SimpleImputer(strategy="constant",

fill_value="MISSING"))

>>> cat_ohe_step = ("ohe", OneHotEncoder(sparse=False,

handle_unknown="ignore"))

>>> cat_steps = [cat_si_step, cat_ohe_step]

>>> cat_pipe = Pipeline(cat_steps)

>>> cat_cols = ["RoofMatl","HouseStyle"]

>>> cat_transformers = [("cat", cat_pipe, cat_cols)]

>>> ct = ColumnTransformer(transformers=cat_transformers)

將整個DataFrame傳遞給列轉換器

列轉換器實例可以選擇我們想要使用的列,因此我們只需將整個DataFrame傳遞給fit_transform方法,就可以選擇我們所需的列。

>>> X_cat_transformed = ct.fit_transform(train)

>>> X_cat_transformed.shape

(1460,16)

然後可以使用同樣的方法轉換測試集。

>>> X_cat_transformed_test = ct.transform(test)

>>> X_cat_transformed_test.shape

(1459,16)

檢索特徵名

我們必須進一步挖掘,來獲取特徵名。所有的轉換器都存儲在named_transformers_ dictionary屬性中。 然後使用特徵名、含有三項要素的元組中的第一項,來選擇特定的轉換器。 下面的代碼就是選擇轉換器(此例中只有一個流程,名為cat)。

>>> pl = ct.named_transformers_["cat"]

然後從這個流程中選擇一個熱編碼器對象,最後得到特徵名。

>>> ohe = pl.named_steps["ohe"]

>>> ohe.get_feature_names()

array(["x0_ClyTile","x0_CompShg","x0_Membran","x0_Metal",

"x0_Roll","x0_Tar&Grv","x0_WdShake","x0_WdShngl",

"x1_1.5Fin","x1_1.5Unf","x1_1Story","x1_2.5Fin",

"x1_2.5Unf","x1_2Story","x1_SFoyer","x1_SLvl"],

dtype=object)

轉換數字列

數字列需要一組不同的轉換。我們不使用常亮來填充缺失值,而是經常選擇中值或均值。一般不對列中的值進行編碼,而是通常將列中的值減去每列的平均值併除以標準差,對列中的值進行標準化。這有助於讓許多模型產生更好的擬合結果(比如脊回歸)。

使用所有數字列

我們可以選擇所有數字列,而不是像處理字元串列一樣,手動選擇一列或兩列。首先使用dtypes屬性查找每列的數據類型,然後測試每個dtype的類型是否為「O」。 dtypes屬性會返回一系列NumPy dtype對象,每個對象都有一個單一字元的kind屬性。我們可以利用它來查找數字或字元串列。 Pandas將其所有字元串列存儲為kind屬性等於「O」的對象。有關kind屬性的更多信息,請參閱NumPy文檔。

獲取kind屬性,該屬性是表示dtype的單字字元串。

假設所有的數字列都是非對象性的。我們可以使用同樣的方法來獲取類別列。

獲取數字列列名之後,可以再次使用列轉換器。

>>>fromsklearn.preprocessingimportStandardScaler

>>> num_si_step = ("si", SimpleImputer(strategy="median"))

>>> num_ss_step = ("ss", StandardScaler())

>>> num_steps = [num_si_step, num_ss_step]

>>> num_pipe = Pipeline(num_steps)

>>> num_transformers = [("num", num_pipe, num_cols)]

>>> ct = ColumnTransformer(transformers=num_transformers)

>>> X_num_transformed = ct.fit_transform(train)

>>> X_num_transformed.shape

(1460,37)

類別列和數字列轉換的結合

我們可以使用類轉換器對DataFrame的每個部分進行單獨轉換。在本文的示例中,我們將使用每一列。

然後,將類別列和數字列分別創建單獨的流程,然後使用列轉換器進行獨立轉換。這兩個轉換過程是並行的。最後,將每個轉換結果連接在一起。

>>> transformers = [("cat", cat_pipe, cat_cols),

("num", num_pipe, num_cols)]

>>> ct = ColumnTransformer(transformers=transformers)

>>> X = ct.fit_transform(train)

>>> X.shape

(1460,305)

機器學習

本文的重點就是設置數據,以便進行機器學習。我們可以創建一個最終流程,並添加機器學習模型作為最終的估算器。這個流程的第一步就是我們上文剛剛完成的整個轉換過程。我們在本文開始處設定y表示售價。在這裡,我們將使用thefit方法,而不是fit_transform方法,因為流程的最後一步是機器學習模型,而且不進行轉換。

>>>fromsklearn.linear_modelimportRidge

>>> ml_pipe = Pipeline([("transform", ct), ("ridge", Ridge())])

>>> ml_pipe.fit(train, y)

我們可以用score方法來評估模型,它將返回一個R-Squared值:

>>> ml_pipe.score(train, y)

0.92205

交叉驗證

當然,在訓練集上進行自我評分是沒有用的。我們需要做一些K重交叉驗證,以了解如何處理不可見的數據。這裡我們設置一個隨機狀態,以便在整個教程的其餘各部分保持同樣的狀態。

>>>fromsklearn.model_selectionimportKFold, cross_val_score

>>> kf = KFold(n_splits=5, shuffle=True, random_state=123)

>>> cross_val_score(ml_pipe, train, y, cv=kf).mean()

0.813

在網格搜索時選擇參數

在Scikit-Learn中進行網格搜索,要求我們將映射傳遞至到可能值的參數名稱字典中。 在流程中,我們必須將步驟的名稱加上雙下劃線,然後使用參數名。 如果流程中有多個層級,必須繼續使用雙下劃線,向上移動一級,直至到達我們想要優化其參數的估算器為止。

>>>fromsklearn.model_selectionimportGridSearchCV

>>> param_grid = {

"transform__num__si__strategy": ["mean","median"],

"ridge__alpha": [.001,0.1,1.0,5,10,50,100,1000],

}

>>> gs = GridSearchCV(ml_pipe, param_grid, cv=kf)

>>> gs.fit(train, y)

>>> gs.best_params_

{"ridge__alpha":10,"transform__num__si__strategy":"median"}

>>> gs.best_score_

0.819

在Pandas DataFrame中獲取所有網格搜索結果

網格搜索的所有結果都存儲在cv_results_屬性中。 這是一個字典,可以轉換為Pandas DataFrame以獲得更好的顯示效果,該屬性使用一種更容易進行手動掃描的結構。

>>> pd.DataFrame(gs.cv_results_)

參數網格中每一種組合中都包含大量數據

構建一個具備全部基礎功能的自定義轉換器

在上述工作流程中存在一些限制。例如,如果熱編碼器允許在使用fit方法期間忽略缺失值,那就更好了,那就可以簡單地將缺失值編碼為全零行。而目前,它還要強制用戶用一些字元串去填充缺失值,然後將此字元串編碼為單獨的列。

低頻字元串

此外,在訓練集中僅出現幾次的字元串列,可能不是測試集中的可靠預測變數。我們可能希望將它們編碼為缺失值。

編寫自己的估算器類

Scikit-Learn可以幫助用戶編寫自己的估算器類。基本模塊中的BaseEstimator類可以提供get_params和set_params方法。當進行網格搜索時,set_params方法是必需的。用戶可以自己編寫,也可以用BaseEstimator。還有一個TransformerMixin,但只是為用戶編寫fit_transform方法。

以下代碼構建的類基本轉換器可執行以下操作:

?使用數字列的均值或中位數填充缺失值

?對所有數字列進行標準化

?對字元串列使用一個熱編碼

?不用再填充類別列中的缺失值,而是直接將其編碼為0

?忽略測試集中字元串列中的少數獨特值

?允許您為字元串列中值必須具有的出現次數選擇閾值。低於此閾值的字元串將被編碼為全0

?僅適用於DataFrames,並且只是實驗性的,未經過測試,因此可能會破壞某些數據集。

?之所以稱其為「基本」轉換器,是因為對許多數據集而言,這些操作屬於最基本的轉換。

fromsklearn.baseimportBaseEstimator

classBasicTransformer(BaseEstimator):

def__init__(self, cat_threshold=None, num_strategy="median",

return_df=False):

# store parameters as public attributes

self.cat_threshold = cat_threshold

ifnum_strategynotin["mean","median"]:

raiseValueError("num_strategy must be either "mean" or

"median"")

self.num_strategy = num_strategy

self.return_df = return_df

deffit(self, X, y=None):

# Assumes X is a DataFrame

self._columns = X.columns.values

# Split data into categorical and numeric

self._dtypes = X.dtypes.values

self._kinds = np.array([dt.kindfordtinX.dtypes])

self._column_dtypes = {}

is_cat = self._kinds =="O"

self._column_dtypes["cat"] = self._columns[is_cat]

self._column_dtypes["num"] = self._columns[~is_cat]

self._feature_names = self._column_dtypes["num"]

# Create a dictionary mapping categorical column to unique

# values above threshold

self._cat_cols = {}

forcolinself._column_dtypes["cat"]:

vc = X[col].value_counts()

ifself.cat_thresholdisnotNone:

vc = vc[vc > self.cat_threshold]

vals = vc.index.values

self._cat_cols[col] = vals

self._feature_names = np.append(self._feature_names, col

+"_"+ vals)

# get total number of new categorical columns

self._total_cat_cols = sum([len(v)forcol, vin

self._cat_cols.items()])

# get mean or median

num_cols = self._column_dtypes["num"]

self._num_fill = X[num_cols].agg(self.num_strategy)

returnself

deftransform(self, X):

# check that we have a DataFrame with same column names as

# the one we fit

ifset(self._columns) != set(X.columns):

raiseValueError("Passed DataFrame has different columns

than fit DataFrame")

eliflen(self._columns) != len(X.columns):

raiseValueError("Passed DataFrame has different number

of columns than fit DataFrame")

# fill missing values

num_cols = self._column_dtypes["num"]

X_num = X[num_cols].fillna(self._num_fill)

# Standardize numerics

std = X_num.std()

X_num = (X_num - X_num.mean()) / std

zero_std = np.where(std ==)[]

# If there is 0 standard deviation, then all values are the

# same. Set them to 0.

iflen(zero_std) >:

X_num.iloc[:, zero_std] =

X_num = X_num.values

# create separate array for new encoded categoricals

X_cat = np.empty((len(X), self._total_cat_cols),

dtype="int")

i =

forcolinself._column_dtypes["cat"]:

vals = self._cat_cols[col]

forvalinvals:

X_cat[:, i] = X[col] == val

i +=1

# concatenate transformed numeric and categorical arrays

data = np.column_stack((X_num, X_cat))

# return either a DataFrame or an array

ifself.return_df:

returnpd.DataFrame(data=data,

columns=self._feature_names)

else:

returndata

deffit_transform(self, X, y=None):

returnself.fit(X).transform(X)

defget_feature_names():

returnself._feature_names

使用基礎轉換器

上面構建的基礎轉換器估算器應該可以像任何其他scikit-learn估算器一樣使用。我們可以將其實例化,然後轉換數據。

>>> bt = BasicTransformer(cat_threshold=3, return_df=True)

>>> train_transformed = bt.fit_transform(train)

>>> train_transformed.head(3)

DataFrame中數字列和類別列相交處的列

在pipeline中使用轉換器

上文構建的轉換器可以作為流程的一部分。

>>> basic_pipe = Pipeline([("bt", bt), ("ridge", Ridge())])

>>> basic_pipe.fit(train, y)

>>> basic_pipe.score(train, y)

0.904

用戶也可以使用它進行交叉驗證,獲得與上面的scikit-learn列轉換器流程相似的分數。

>>> cross_val_score(basic_pipe, train, y, cv=kf).mean()

0.816

我們也可以將其用作網格搜索的一部分。事實證明,將低頻字元串排除在外,並沒有明顯改善模型的表現,儘管它可以在其他模型中使用。不過,在最佳評分方面確實有所提高,這可能是由於使用了略微不同的編碼方案。

>>> param_grid = {

"bt__cat_threshold": [,1,2,3,5],

"ridge__alpha": [.1,1,10,100]

}

>>> gs = GridSearchCV(p, param_grid, cv=kf)

>>> gs.fit(train, y)

>>> gs.best_params_

{"bt__cat_threshold":,"ridge__alpha":10}

>>> gs.best_score_

0.830

使用新的KBinsDiscretizer對數字列進行分裝(bin)和編碼

對於包含年份的一些數字列,將其中的值視為類別列更有意義。 Scikit-Learn推出了新的估算器KBinsDiscretizer來實現這一點。它不僅可以存儲值,還可以對這些值進行編碼。在使用Pandas cut或qcut函數手動完成此這類操作之前,一起來看看它如何處理年份數字列的。

>>>fromsklearn.preprocessingimportKBinsDiscretizer

>>> kbd = KBinsDiscretizer(encode="onehot-dense")

>>> year_built_transformed = kbd.fit_transform(train[["YearBuilt"]])

>>> year_built_transformed

array([[0.,0.,0.,0.,1.],

[0.,0.,1.,0.,0.],

[0.,0.,0.,1.,0.],

...,

[1.,0.,0.,0.,0.],

[0.,1.,0.,0.,0.],

[0.,0.,1.,0.,0.]])

在默認設置下,每個bin中都包括相等數量的觀察數據。下面對每列求和來驗證這一點。

>>> year_built_transformed.sum(axis=)

array([292.,274.,307.,266.,321.])

這就是「分位數策略」,用戶可以選擇「統一」模式,為bin邊界劃定相等的空間,也可以選擇「k平均」聚類,自定義bin邊界。

>>> kbd.bin_edges_

array([array([1872.,1947.8,1965.,1984.,2003.,2010.])],

dtype=object)

使用列轉換器分別處理所有年份列

現在有一個需要單獨處理的列子集,我們可以使用列轉換器來執行此操作。下面的代碼為我們之前的轉換添加了一個步驟。此外還刪除了標識列,只標識出每一行。

>>> year_cols = ["YearBuilt","YearRemodAdd","GarageYrBlt",

"YrSold"]

>>> not_year = ~np.isin(num_cols, year_cols + ["Id"])

>>> num_cols2 = num_cols[not_year]

>>> year_si_step = ("si", SimpleImputer(strategy="median"))

>>> year_kbd_step = ("kbd", KBinsDiscretizer(n_bins=5,

encode="onehot-dense"))

>>> year_steps = [year_si_step, year_kbd_step]

>>> year_pipe = Pipeline(year_steps)

>>> transformers = [("cat", cat_pipe, cat_cols),

("num", num_pipe, num_cols2),

("year", year_pipe, year_cols)]

>>> ct = ColumnTransformer(transformers=transformers)

>>> X = ct.fit_transform(train)

>>> X.shape

(1460,320)

通過交叉驗證和評分,發現所有這些處理都沒有帶來任何改進。

>>> ml_pipe = Pipeline([("transform", ct), ("ridge", Ridge())])

>>> cross_val_score(ml_pipe, train, y, cv=kf).mean()

0.813

為每列使用不同數量的bin可能會改善我們的結果。儘管如此,KBinsDiscretizer還可以輕鬆地對數字變數進行分裝。

標題:Scikit-Learn 0.20的更多亮點

本次即將發布的版本附帶了更多新功能。更多詳細信息,請查看文檔的「新增內容」部分。有很多變化哦。

結論

本文介紹了一個新的工作流程,提供了一個基於Pandas進行初步數據探索和準備的Scikit-Learn用戶方案。現在,改進型的新估算器ColumnTransformer,SimpleImputer,OneHotEncoder和KBinsDiscretizer,讓整個數據處理流程變得更加平滑,功能也更加豐富。用戶可以獲取Pandas DataFrame,並對其進行轉換,為機器學習做好準備。

https://medium.com/dunder-data/from-pandas-to-scikit-learn-a-new-exciting-workflow-e88e2271ef62

新智元AI WORLD 2018世界人工智慧峰會

倒計時12

門票已開售!

新智元將於9月20日在北京國家會議中心舉辦AI WORLD 2018世界人工智慧峰會,邀請機器學習教父、CMU教授 Tom Mitchell,邁克思·泰格馬克,周志華,陶大程,陳怡然等AI領袖一起關注機器智能與人類命運。

大會官網:

http://www.aiworld2018.com/

活動行購票鏈接:

http://www.huodongxing.com/event/6449053775000

活動行購票二維碼:


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 新智元 的精彩文章:

「阿里演算法專家」深度學習將業界技術迭代提升100倍,GraphDL 應用廣闊
谷歌官方:反向傳播演算法圖解

TAG:新智元 |