19個Python Sklearn中超實用的隱藏功能分享

今天跟大傢介紹 19 個 Sklearn 中超級實用的隱藏的功能,這些功能雖然不常見,但非常實用,它們可以直接優雅地替代手動執行的常見操作。接下來我們就一個一個介紹這些功能,希望對大傢有所幫助!

寫在前面

通過查看 Sklearn 的 API,發現最常用的模型和函數隻是眾多庫中的一小部分。盡管某些功能的使用范圍非常小並且一般用於一些邊緣情況,但我發現很多評估器、轉換器和實用程序功能可以很好地處理手動執行的常見操作。

https://scikit-learn.org/stable/modules/classes.html#api-reference

因此,接下來我將列出最重要的一些功能並做個簡要的解釋,這樣可以我們擴展一些 Sklearn 工具集,以便在學習工作中可以更好地更快地處理事務。

1 .covariance.EllipticEnvelope

通常,在我們的所處理的數據分佈中有異常值是很常見的,並且許多算法都可以處理離群值,而 EllipticalEnvelope 就是 Sklearn 中直接內置的一個例子。該算法的優勢在於,它在檢測正態分佈(高斯)特征中的異常點時表現得非常好:

import numpy as np
from sklearn.covariance import EllipticEnvelope

# 創建一個樣本正態分佈
X = np.random.normal(loc=5, scale=2, size=50).reshape(-1, 1)

# 擬合估計量
ee = EllipticEnvelope(random_state=0)
_ = ee.fit(X)

# 測試
test = np.array([6, 8, 20, 4, 5, 6, 10, 13]).reshape(-1, 1)

# Predict返回1作為內嵌值,返回-1作為異常值
>>> ee.predict(test)

array([ 1,  1, -1,  1,  1,  1, -1, -1])

為瞭檢驗評估結果,我們創建瞭一個均值為5,標準差為2的正態分佈。訓練完成後,將一些隨機數傳遞給它的預測方法。該方法返回-1表示測試中的異常值,即20、10、13。

2 .feature_selection.RFECV

我們在做數據挖掘,做特征工程時,選擇對預測最有幫助的特征是防止過擬合和降低模型復雜性的必要步驟。Sklearn提供的最健壯的算法之一是遞歸特征消除(RFE)。它通過使用交叉驗證自動找到最重要的特性,並丟棄其餘的。

這個評估器的一個優點是它是一個包裝器——它可以用於返回特征重要性或系數分數的任何 Sklearn 算法。下面是一個關於合成數據集的例子:

from sklearn.datasets import make_regression
from sklearn.feature_selection import RFECV
from sklearn.linear_model import Ridge

# 構建一個合成數據集
X, y = make_regression(n_samples=10000, n_features=15, n_informative=10)

# 初始化和擬合選擇器
rfecv = RFECV(estimator=Ridge(), cv=5)
_ = rfecv.fit(X, y)

# 轉換特性陣列
>>> rfecv.transform(X).shape
(10000, 10)

數據集有 15 個特征,其中 10 個特征是信息豐富的,其餘都是冗餘的。我們用嶺回歸擬合 5-fold RFECV 作為評估器。訓練後,可以使用變換方法丟棄冗餘特征。最後調用 .shape 查看評估器刪除瞭所有 5 個冗餘的特性。

3 .ensemble.ExtraTrees

我們都知道,盡管隨機森林非常強大,但過度擬合的風險非常高。因此,Sklearn提供瞭稱為 ExtraTrees(分類器和回歸器) 的 RF 替代方案。

"Extra" 這個詞並不是指更多的樹,而是指更多的隨機性。該算法使用瞭另一種類似於決策樹的樹。唯一的區別是,不同於在構建每棵樹時計算分割閾值,這些閾值是為每個特征隨機繪制的,並選擇最佳閾值作為分割規則。這允許以偏差略微增加的代價來降低方差:

from sklearn.ensemble import ExtraTreesRegressor, RandomForestRegressor
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor

X, y = make_regression(n_samples=10000, n_features=20)

# 決策樹
clf = DecisionTreeRegressor(max_depth=None, min_samples_split=2, random_state=0)
scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.6376080094392635

# 隨機森林
clf = RandomForestRegressor(
    n_estimators=10, max_depth=None, min_samples_split=2, random_state=0
)
scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.8446103607404536

# ExtraTrees
clf = ExtraTreesRegressor(
    n_estimators=10, max_depth=None, min_samples_split=2, random_state=0
)
scores = cross_val_score(clf, X, y, cv=5)
>>> scores.mean()
0.8737373931608834

如結果所示,ExtraTreesRegressor 在合成數據集上的表現優於隨機森林。

4 .impute.IterativeImputer 和 .impute.KNNImputer

如果你正在尋找比 SimpleImputer 更健壯、更先進的 imputation 技術,Sklearn再次為你提供瞭支持。impute 子包包括兩個基於模型的 impute 算法 KNNImputer 和 IterativeImputer

顧名思義,KNNImputer 使用 k-Nearest-Neighbors 算法來尋找缺失值的最佳替代:

from sklearn.impute import KNNImputer
# 代碼取自Sklearn用戶指南
X = [[1, 2, np.nan], 
     [3, 4, 3], 
     [np.nan, 6, 5], 
     [8, 8, 7]]
imputer = KNNImputer(n_neighbors=2)
imputer.fit_transform(X)

輸出:

array([[1. , 2. , 4. ],
       [3. , 4. , 3. ],
       [5.5, 6. , 5. ],
       [8. , 8. , 7. ]])

另一個更健壯的算法是 IterativeImputer它通過將每個特征的缺失值建模為其他特征的函數來尋找缺失值。 這個過程是按循序漸進的循環方式完成的。在每一步中,選擇一個具有缺失值的特征作為目標(y),其餘的作為特征數組(X)。然後,使用回歸函數預測 y 中的缺失值,並對每個特征繼續這個過程,直到 max_iter 次數 (IterativeImputer的一個參數)。

因此,會為一個缺失的值生成多個預測。這樣做的好處是,可以將每個缺失的值視為隨機變量,並將其與固有的不確定性聯系起來:

from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
from sklearn.linear_model import BayesianRidge
imp_mean = IterativeImputer(estimator=BayesianRidge())
imp_mean.fit([[7, 2, 3], 
              [4, np.nan, 6], 
              [10, 5, 9]])
              
X = [[np.nan, 2, 3], 
     [4, np.nan, 6], 
     [10, np.nan, 9]]
imp_mean.transform(X)

輸出:

array([[ 6.95847623,  2.        ,  3.        ],
       [ 4.        ,  2.6000004 ,  6.        ],
       [10.        ,  4.99999933,  9.        ]])

結果表明,使用 IterativeImputer 缺失值填補算法的 BayesianRidge 和 ExtraTree 算法性能效果變現更加優秀。

5 .linear_model.HuberRegressor

雖然正常情況下,數據分佈中存在異常值是非常常見的, 但異常值的存在會嚴重破壞任何模型的預測。許多異常值檢測算法會丟棄異常值並將其標記為缺失。雖然這有助於模型的學習,但它完全消除瞭異常值對分佈的影響。

另一種算法是 HuberRegressor 回歸算法。它不是完全去除它們,而是在擬合數據期間給予異常值更小的權重。它有超參數 epsilon 來控制樣本的數量,這些樣本應該被歸類為異常值。參數越小,對異常值的魯棒性越強。它的API與任何其他線性回歸函數相同。下面,你可以看到它與貝葉斯嶺回歸器在一個有大量異常值的數據集上的比較:

可以看到,設置參數 epsilon 為 1.35 1.5, 1.75 的 huberregressionor 算法設法捕獲不受異常值影響的最佳擬合線。

6 .tree.plot_tree

Sklearn 中可以使用 plot_tree 函數繪制單個決策樹的結構。這個特性可能對剛開始學習基於樹的模型和集成模型的初學者很方便,通過該方法,對決策樹的決策過程可視化,對其決策過程和原理更加一目瞭然。

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier, plot_tree

iris = load_iris()
X, y = iris.data, iris.target
clf = DecisionTreeClassifier()
clf = clf.fit(X, y)

plt.figure(figsize=(15, 10), dpi=200)
plot_tree(clf, feature_names=iris.feature_names, 
               class_names=iris.target_names);

還有其他繪制樹的方法,比如 Graphviz。

7 .linear_model.Perceptron

盡管感知機是一個奇特的名字,但它是一個簡單的線性二進制分類器。算法的定義特征是適合大規模學習,默認為:

  • 它不需要學習速率。
  • 不要實現正則化。
  • 它隻在分類錯誤的情況下更新模型。

它等價於 SGDClassifierloss='perceptron', eta0=1, learning_rate="constant", penalty=None ,但略快:

from sklearn.datasets import make_classification
from sklearn.linear_model import Perceptron
# 創建一個更大的數據集
X, y = make_classification(n_samples=100000, n_features=20, n_classes=2)
# Init/Fit/Score
clf = Perceptron()
_ = clf.fit(X, y)
clf.score(X, y)

輸出:

0.91928

8 .feature_selection.SelectFromModel

Sklearn 中另一個基於模型的特征選擇模型是 SelectFromModel。它不像RFECV那樣健壯,但由於它具有較低的計算成本,可以作為大規模數據集的一個很好的選擇。它也是一個包裝器模型,適用於任何具有 .feature_importance_ 或 .coef_ 屬性的模型:

from sklearn.feature_selection import SelectFromModel

# 創建一個包含40個無信息特征的數據集
X, y = make_regression(n_samples=int(1e4), n_features=50, n_informative=10)

# 初始化選擇器並轉換特性數組
selector = SelectFromModel(estimator=ExtraTreesRegressor()).fit(X, y)

selector.transform(X).shape

輸出:

(10000, 8)

如結果所示,算法成功地刪除瞭所有40個冗餘特征。

9 .metrics.ConfusionMatrixDisplay

總所周知,混淆矩陣是用於評估分類問題的常用方法。我們通常使用的大多數指標都來自於它,如精度、召回率、F1、ROC AUC等等。Sklearn中可以計算和繪制一個默認的混淆矩陣:

from sklearn.metrics import plot_confusion_matrix
from sklearn.model_selection import train_test_split

# 創建一個二元分類問題
X, y = make_classification(n_samples=200, n_features=5, n_classes=2)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.5, random_state=1121218
)

clf = ExtraTreeClassifier().fit(X_train, y_train)
fig, ax = plt.subplots(figsize=(5, 4), dpi=100)
plot_confusion_matrix(clf, X_test, y_test, ax=ax);

老實說,我不喜歡默認的混淆矩陣。它的格式是固定的—行是true labels,列是predictions label。第一行和第一列是負類,第二行和第二列是正類。有些人可能更喜歡不同格式的矩陣,可能是轉置或翻轉的。

例如,我喜歡將正類作為第一行和第一列。這有助於我更好地隔離 4 矩陣項 — TP, FP, TN, FN。幸運的是,你可以用另一個函數 ConfusionMatrixDisplay 繪制自定義矩陣:

from sklearn.metrics import ConfusionMatrixDisplay, confusion_matrix

clf = ExtraTreeClassifier().fit(X_train, y_train)
y_preds = clf.predict(X_test)

fig, ax = plt.subplots(figsize=(5, 4), dpi=100)
cm = confusion_matrix(y_test, y_preds)
cmp = ConfusionMatrixDisplay(cm, 
      display_labels=["Positive", "Negative"])
cmp.plot(ax=ax);

在傳遞給 ConfusionMatrixDisplay 之前,可以把 混淆矩陣cm 放在任何格式中。

10 .Generalized Linear Models

一般情況下,如果有可用於其他類型分佈的替代方案,則將目標(y)轉換為正態分佈是沒有意義的。

例如,Sklearn 為目標變量提供瞭3種廣義線性模型,分別是泊松、Tweedie或Gamma分佈 ,而不是所期望的正態分佈,poissonregressionor, TweedieRegressor 和 GammaRegressor 可以生成具有各自分佈的目標的穩健結果。

除此之外,他們的api與任何其他Sklearn模型一樣。為瞭找出目標的分佈是否與上述三個相匹配,可以將它們的PDF(概率密度函數)繪制在相同軸上。

例如,要查看目標是否遵循泊松分佈,可以使用 Seaborn 的 kdeploy 繪制它的 PDF,並在相同的軸上使用 np.random_poisson 從 Numpy 中采樣,繪制完美的泊松分佈。

11 .ensemble.IsolationForest

一般情況下,基於樹的模型和集合模型通常產生更穩健的結果,它們在異常點檢測方面也被證明是有效的。Sklearn 中的 IsolationForest 使用一個極端隨機樹 (tree.ExtraTreeRegressor) 來檢測異常值。每棵樹試圖通過選擇一個單一的特征,並在所選特征的最大值和最小值之間隨機選擇一個分裂值來隔離每個樣本。

這種隨機分區會在每棵樹的根節點和終止節點之間產生明顯更短的路徑。

因此,當隨機樹組成的森林為特定樣本共同產生更短的路徑長度時,它們極有可能是異常——Sklearn用戶指南。

from sklearn.ensemble import IsolationForest
X = np.array([-1.1, 0.3, 0.5, 100]).reshape(-1, 1)
clf = IsolationForest(random_state=0).fit(X)
clf.predict([[0.1], [0], [90]])

輸出:

array([ 1,  1, -1])

12 .preprocessing.PowerTransformer

許多線性模型需要在數值特征上進行一些轉換才能使其服從正態分佈。StandardScaler 和 MinMaxScaler 在大多數發行版中都比較適用。然而,當數據存在高偏度時,分佈的核心指標,如平均值、中位數、最小值和最大值,就會受到影響。因此,簡單的標準化和標準化對傾斜分佈不起作用。

相反,Sklearn 實現中提供瞭一個名為 PowerTransformer的方法,它使用對數變換將任何傾斜的特征盡可能地轉化為正態分佈。考慮 Diamonds 數據集中的兩個特征:

import seaborn as sns

diamonds = sns.load_dataset("diamonds")
diamonds[["price", "carat"]].hist(figsize=(10, 5));

兩者都嚴重傾斜。我們用對數變換 PowerTransformer來解決這個問題:

from sklearn.preprocessing import PowerTransformer

pt = PowerTransformer()
diamonds.loc[:, ["price", "carat"]] = pt.fit_transform(diamonds[["price", "carat"]])

diamonds[["price", "carat"]].hist(figsize=(10, 5));

13 .preprocessing.RobustScaler

Sklearn 中的另一個數字轉換器是 RobustScaler,我們可以從它的名稱猜出它的用途——可以以一種健壯到異常值的方式轉換特性。如果一個特征中存在異常值,就很難使其服從正態分佈,因為它們會嚴重扭曲均值和標準差。

與使用均值/標準不同,RobustScaler 使用中值和IQR(四分位數范圍)來衡量數據,因為這兩個指標都不會因為異常值而有偏差。

14 .compose.make_column_transformer

在 Sklearn 中,有一個用 make_pipeline 函數創建 Pipeline 實例的簡寫。該函數不需要為Pipeline中的每一步命名,而是隻接受變形器和估計器並執行它的工作,從而不需要使代碼那麼長:

from sklearn.impute import SimpleImputer
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

pipeline = make_pipeline(SimpleImputer(), StandardScaler(), ExtraTreesRegressor())
pipeline
Pipeline(steps=[('simpleimputer', 
                  SimpleImputer()),
                ('standardscaler', 
                  StandardScaler()),
                ('extratreesregressor', 
                  ExtraTreesRegressor())])

對於更復雜的場景,使用 ColumnTransformer,這有相同的問題——每個預處理步驟都應該命名,這會使代碼變得冗長且不可讀。Sklearn提供瞭與 make_pipeline 類似的函數:

import seaborn as sns
from sklearn.compose import make_column_transformer
from sklearn.preprocessing import OneHotEncoder

# 負載鉆石數據集
diamonds = sns.load_dataset("diamonds")
X, y = diamonds.drop("price", axis=1), diamonds.price.values.reshape(-1, 1)

# 拆分數字和類別標簽
num_cols = X.select_dtypes(include=np.number).columns
cat_cols = X.select_dtypes(exclude=np.number).columns

make_column_transformer((StandardScaler(), num_cols), 
                            (OneHotEncoder(), cat_cols))
ColumnTransformer(
  transformers=[('standardscaler', 
                  StandardScaler(),
                 Index(['carat', 'depth', 
                        'table', 'x', 'y', 'z'],
                  dtype='object')),
                ('onehotencoder', 
                  OneHotEncoder(),
                 Index(['cut', 'color', 
                        'clarity'], 
                  dtype='object'))]
  )

如上所示,使用 make_column_transformer 要短得多,並且它自己負責命名每個轉換器步驟。

15 .compose.make_column_selector

上文中,我們使用 select_dtypes 函數和 pandas DataFrames 的 columns 屬性來拆分數值列和分類列。雖然這當然有效,但使用 Sklearn 有一個更靈活、更優雅的解決方案。

make_column_selector 函數創建一個可以直接傳遞到 ColumnTransformer 實例中的列選擇器。它的工作原理與 select_dtypes 類似,甚至更好。它有 dtype_include 和 dtype_exclude 參數,可以根據數據類型選擇列。如果需要自定義列篩選器,可以將正則表達式傳遞給 pattern,同時將其他參數設置為 None。下面是它的工作原理:

from sklearn.compose import make_column_selector

make_column_transformer(
    (StandardScaler(), make_column_selector(dtype_include=np.number)),
    (OneHotEncoder(), make_column_selector(dtype_exclude=np.number)),
)

隻是傳遞一個實例 make_column_selector 與由你設置相關參數,而不是傳遞一個列名稱列表!

16 .preprocessing.OrdinalEncoder

在我們剛學習機器學習時,常見的一個錯誤是使用 LabelEncoder 來編碼有序的分類特征。註意到,LabelEncoder 一次隻允許轉換一個列,而不是像 OneHotEncoder 那樣同時轉換。你可能會認為 Sklearn 犯瞭一個錯誤!

實際上,LabelEncoder 應該隻用於按照 LabelEncoder 文檔中指定的方式對響應變量(y)進行編碼。要編碼特征數組(X),應該使用 OrdinalEncoder,它將有序分類列轉換為具有(0, n_categories - 1) 類的特性。它在一行代碼中跨所有指定列執行此操作,使得在管道中包含它成為可能。

from sklearn.preprocessing import OrdinalEncoder

oe = OrdinalEncoder()
X = [
    ["class_1", "rank_1"],
    ["class_1", "rank_3"],
    ["class_3", "rank_3"],
    ["class_2", "rank_2"],
]
oe.fit_transform(X)

輸出:

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

17 .metrics.get_scorer

Sklearn 內置瞭 50 多個指標,它們的文本名稱可以在 Sklearn.metrics.scores.keys 中看到。在單個項目中,如果單獨使用它們,則可能需要使用多個指標並導入它們。

從 sklearn.metrics 中導入大量指標可能會污染你的名稱空間,使其變得不必要的長。一種解決方案是可以使用 metrics.get_scorer 函數使用其文本名稱訪問任何度量,而不需要導入它:

from sklearn.metrics import get_scorer

>>> get_scorer("neg_mean_squared_error")
make_scorer(mean_squared_error, 
            greater_is_better=False)

>>> get_scorer("recall_macro")
make_scorer(recall_score, 
            pos_label=None, 
            average=macro)

>>> get_scorer("neg_log_loss")
make_scorer(log_loss, 
            greater_is_better=False, 
            needs_proba=True)

18 .model_selection.HalvingGrid 和 HalvingRandomSearchCV

在 sklearn 的 0.24 版本中,引入瞭兩個實驗性超參數優化器:HalvingGridSearchCV 和 HalvingRandomSearchCV 類。

與它們詳盡的同類 GridSearch 和 RandomizedSearch 不同,新類使用瞭一種稱為連續減半的技術。 不是在所有數據上訓練所有候選集,而是隻將數據的一個子集提供給參數。通過對更小的數據子集進行訓練,篩選出表現最差的候選人。每次迭代後,訓練樣本增加一定的因子,而可能的候選個數減少盡可能多的因子,從而獲得更快的評估時間。

快多少呢?在我做過的實驗中,HalvingGridSearch 比普通 GridSearch 快11倍HalvingRandomSearch 甚至比 HalvingGridSearch 快10倍

19 .sklearn.utils

Sklearn在 sklearn.utils 中有一整套實用程序和輔助功能。Sklearn本身使用這個模塊中的函數來構建我們使用的所有變形器transformers和估計器transformers。

這裡有許多有用的方法,如 class_weight.compute_class_weightestimator_html_reprshufflecheck_X_y等。你可以在自己的工作流程中使用它們,使你的代碼更像 Sklearn,或者在創建適合 Sklearn API 的自定義轉換器和評估器時,它們可能會派上用場。

總結

盡管像 CatBoost, XGBoost, LightGBM 等庫正在慢慢從 Sklearn 中搶走領先的 ML 庫的頭把交椅,但它仍然是現代 ML工程師技能堆棧中不可估量的一部分。

一致的 API、卓越的代碼設計以及創建強大的 ML 工作流的能力仍然使 Sklearn 在功能和靈活性方面無與倫比。盡管我們可以在基礎知識方面完成很多工作,但本文表明 Sklearn 提供的不僅僅是表面上的東西!

以上就是19個Python Sklearn中超實用的隱藏功能分享的詳細內容,更多關於Python Sklearn的資料請關註WalkonNet其它相關文章!

推薦閱讀: