Feature Tools:可自動構造機器學習特徵的Python庫

目前,不少機器學習項目的模型選擇開始轉向自動化,而特徵工程仍然主要以人工爲主。這個過程的重要性可能比模型選擇更重要,人工獲得的特徵總帶有必定的侷限性。在本文中做者將爲咱們介紹如何使用 Feature Tools Python 庫實現特徵工程自動化,項目已開源。python


機器學習愈來愈多地從人工設計模型轉向使用 H20、TPOT 和 auto-sklearn 等工具自動優化的工具。這些庫以及隨機搜索(參見《Random Search for Hyper-Parameter Optimization》)等方法旨在經過尋找匹配數據集的最優模型來簡化模型選擇和機器學習調優過程,而幾乎不須要任何人工干預。然而,特徵工程做爲機器學習流程中可能最有價值的一個方面,幾乎徹底是人工的。算法

特徵工程也被稱爲特徵構造,是從現有數據中構造新的特徵從而訓練機器學習模型的過程。這一步可能比實際上使用的模型更重要,由於一個機器學習算法只能從咱們給定的數據中學習,因此構造一個和任務相關的特徵是相當重要的,參見優質論文《A Few Useful Things to Know about Machine Learning》。bash

一般,特徵工程是一個冗長的人工過程,依賴於領域知識、直覺和數據操做。這個過程多是極其枯燥的,同時最終獲得的特徵將會受到人的主觀性和時間的限制。特徵工程自動化旨在經過從數據集中自動構造候選特徵,並從中選擇最優特徵用於訓練來幫助數據科學家。網絡

在本文中,咱們將介紹一個使用 Feature Tools Python 庫實現特徵工程自動化的例子。咱們將使用一個示例數據集來講明基本概念(繼續關注以後使用真實世界數據的例子)。本文完整代碼可在 Github 上找到。數據結構

特徵工程基本概念dom

特徵工程意味着從現有的數據中構造額外特徵,這些特徵一般分佈在多張相關的表中。特徵工程須要從數據中提取相關信息並將其存入單張表格中,而後被用來訓練機器學習模型。機器學習

構造特徵是一個很是耗時的過程,由於每一個新的特徵一般須要幾步才能構造,特別是當使用多張表的信息時。咱們能夠將特徵構造的操做分爲兩類:「轉換」和「聚合」。如下經過幾個例子來看看這些概念的實際應用。ide

經過從一或多列中構造新的特徵,「轉換」做用於單張表(在 Python 中,表是一個 Pandas DataFrame)。舉個例子,如有以下的客戶表:

咱們能夠經過查找 joined 列中的月份或是天然對數化 income 列的數據來構造新的特徵。這些都是轉換操做,由於它們只用到了一張表的信息。

另外一方面,「聚合」是跨表實現的,並使用一對多的關聯來對觀測值分組,而後計算統計量。例如,若咱們有另一張包含客戶貸款信息的表格,其中每一個客戶可能有多項貸款,咱們即可以計算每一個客戶貸款的平均值、最大值和最小值等統計量。

這個過程包括根據不一樣客戶對貸款表進行分組並計算聚合後的統計量,而後將結果整合到客戶數據中。如下是咱們在 Python 中使用 Pandas 庫執行此操做。

import pandas as pd

# Group loans by client id and calculate mean, max, min of loans
stats = loans.groupby('client_id')['loan_amount'].agg(['mean', 'max', 'min'])
stats.columns = ['mean_loan_amount', 'max_loan_amount', 'min_loan_amount']

# Merge with the clients dataframe
stats = clients.merge(stats, left_on = 'client_id', right_index=True, how = 'left')

stats.head(10)
複製代碼


這些操做自己並不困難,可是若是有數百個變量分佈在數十張表中,這個過程將沒法經過人工完成。理想狀況下,咱們但願有一個解決方案可以在不一樣表間自動執行轉換和聚合操做,並將結果整合到一張表中。儘管 Pandas 是一個很好的資源,可是仍然有許多數據操做須要咱們人工完成!有關人工特徵工程的更多信息,請查閱《Python Data Science Handbook》。

特徵工具

幸運的是,Feature Tools 正是咱們正在找尋的解決方案。這個開源的 Python 庫能夠從一組相關的表中自動構造特徵。特徵工具基於名爲「深度特徵合成」的方法(參見《Deep Feature Synthesis: Towards Automating Data Science Endeavors》),這個方法的名字聽起來比其自己更高大上(這個名字源於疊加了多重特徵,而不是由於使用了深度學習方法!)。

深度特徵合成疊加多個轉換和聚合操做,這在特徵工具的詞庫中被稱爲特徵基元,以便經過分佈在多張表內的數據來構造新的特徵。與機器學習中的大多數方法同樣,這是創建在簡單概念基礎之上的複雜方法。經過一次學習一個構造塊,咱們能夠很好地理解這個強大的方法。

首先,讓咱們看一下示例數據。咱們已經看到了上面的一些數據集,而且完整的表組以下所示:

  • clients: 關於信用社客戶的基本信息。每一個客戶只對應數據框中的一行。

  • loans: 向用戶提供的貸款。每項貸款只對應數據框中的一行,可是客戶可能有多項貸款。

  • payments:貸款還本的支付。每筆支付只對應一行,可是每項貸款能夠有多筆支付。

若是咱們有一個機器學習任務,例如預測客戶將來是否會償還一項貸款,咱們但願將全部關於客戶的信息整合到一張表中。這些表是相關的(經過 client_id 和 loan_id 變量),而且咱們能夠經過一系列轉換和聚合操做來人工實現這個過程。然而,咱們很快就可使用特徵工具來自動實現這個過程。

實體和實體集

特徵工具的前兩個概念的是「實體」和「實體集」。一個實體就是一張表(或是 Pandas 中的一個 DataFrame(數據框))。一個實體集是一組表以及它們之間的關聯。將一個實體集當作另外一種 Python 數據結構,並帶有本身的方法和屬性。

咱們能夠經過如下操做在特徵工具中建立一個空的實體集:

import featuretools as ft
# Create new entityset
es = ft.EntitySet(id = 'clients')
複製代碼

如今咱們須要整合兩個實體。每一個實體都必須帶有一個索引,它是一個包含全部惟一元素的列。就是說,索引中的每一個值只能在表中出現一次。在 clients 數據框中的索引是 client_id,由於每一個客戶在該數據框中只對應一行。咱們使用如下語法將一個帶有索引的實體添加一個實體集中:

# Create an entity from the client dataframe
# This dataframe already has an index and a time index
es = es.entity_from_dataframe(entity_id = 'clients', dataframe = clients, 
                              index = 'client_id', time_index = 'joined')
複製代碼

loans 數據框還有另一個惟一的索引,loan_id,同時將其添加到實體集的語法與 clients 同樣。然而,payments 數據框不存在惟一索引。當咱們把 payments 數據框添加到實體集中時,咱們須要傳入參數 make_index = True,同時指定索引的名字。另外,儘管特徵工具能自動推斷實體中每列的數據類型,可是咱們能夠經過將列數據類型的字典傳遞給參數 variable_types 來覆蓋它。

# Create an entity from the payments dataframe
# This does not yet have a unique index
es = es.entity_from_dataframe(entity_id = 'payments', 
                              dataframe = payments,
                              variable_types = {'missed': ft.variable_types.Categorical},
                              make_index = True,
                              index = 'payment_id',
                              time_index = 'payment_date')
複製代碼

對於此數據框,儘管 missed 是一個整數,可是它不是一個數值變量,由於它只能取 2 個離散的數值,因此在特徵工具中,將其當作一個分類變量。在將該數據框添加到實體集中後,咱們檢查整個實體集:

列的數據類型已根據咱們指定的修正方案被正確推斷出來。接下來,咱們須要指定實體集中表是如何關聯的。

表的關聯

考慮兩張表之間「關聯」的最好方法是類比父子之間的關聯。這是一種一對多的關聯:每一個父親能夠有多個兒子。對錶來講,每一個父親對應一張父表中的一行,可是子表中可能有多行對應於同一張父表中的多個兒子。

例如,在咱們的數據集中,clients 數據框是 loans 數據框的一張父表。每一個客戶只對應 clients 表中的一行,可是可能對應 loans 表中的多行。一樣,loans 表是 payments 表的一張父表,由於每項貸款能夠有多項支付。父親經過共享變量與兒子相關聯。當咱們執行聚合操做的時候,咱們根據父變量對子表進行分組,並計算每一個父親的兒子的統計量。

爲了形式化特徵工具中的關聯規則,咱們僅需指定鏈接兩張表的變量。clients 表和 loans 表經過 client_id 變量鏈接,同時 loans 表和 payments 表經過 loan_id 變量鏈接。建立關聯並將其添加到實體集中的語法以下所示:

# Relationship between clients and previous loans
r_client_previous = ft.Relationship(es['clients']['client_id'],
                                    es['loans']['client_id'])

# Add the relationship to the entity set
es = es.add_relationship(r_client_previous)

# Relationship between previous loans and previous payments
r_payments = ft.Relationship(es['loans']['loan_id'],
                                      es['payments']['loan_id'])

# Add the relationship to the entity set
es = es.add_relationship(r_payments)

es
複製代碼

該實體集如今包含三個實體(表),以及將這些錶鏈接在一塊兒的關聯規則。在添加實體和形式化關聯規則以後,實體集就完整了並準備好從中構造新的特徵。

特徵基元

在咱們深刻了解深度特徵合成以前,咱們須要瞭解特徵基元的概念。咱們其實早就知道是什麼了,只是咱們剛剛用不一樣的名字來稱呼它們!它們只是咱們用來構造新特徵的操做:

  • 聚合:根據父與子(一對多)的關聯完成的操做,也就是根據父親分組並計算兒子的統計量。一個例子就是根據 client_id 對 loan 表分組並找到每一個客戶的最大貸款額。

  • 轉換:對一張表中一或多列完成的操做。一個例子就是取一張表中兩列之間的差值或者取一列的絕對值。

在特徵工具中單獨使用這些基元或者疊加使用這些基元能夠構造新的特徵。如下是特徵工具中一些特徵基元的列表,也能夠自定義特徵基元。

特徵基元

這些基元能夠單獨使用或是組合使用以構造新的特徵。爲了使用特定的基元構造新的特徵,咱們使用 ft.dfs 函數(表明深度特徵合成)。咱們傳入 entityset 和 target_entity,這是咱們想要在其中添加特徵的表,被選參數 trans_primitives(轉換)和 agg_primitives(聚合)。

public class MyActivity extends AppCompatActivity {
@Override  //override the function
    protected void onCreate(@Nullable Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       try {
            OkhttpManager.getInstance().setTrustrCertificates(getAssets().open("mycer.cer");
            OkHttpClient mOkhttpClient= OkhttpManager.getInstance().build();
        } catch (IOException e) {
            e.printStackTrace();
        }
}
複製代碼

返回的是包含每一個客戶新特徵的數據框(由於咱們定義客戶爲 target_entity)。好比咱們有每一個客戶加入的月份,這是一個轉換操做的特徵基元:

咱們也有許多聚合操做的基元,好比每一個客戶的平均支付總額:

儘管咱們僅指定了一些特徵基元,可是特徵工具能夠經過組合和疊加這些基元來構造新的特徵。

完整的數據框包含 793 列的新特徵!

深度特徵合成

咱們如今具有理解深度特徵合成(dfs)的一切條件。事實上,咱們已經在前面的函數調用中執行了 dfs!深度特徵只是疊加多個基元構造的一個特徵,而 dfs 只是構造這些特徵的過程的名稱。深度特徵的深度是構造這個特徵所需的基元數量。

例如,MEAN(payments.payment_amount)列是深度爲 1 的特徵,由於它是使用單個聚合操做構造的。LAST(loans(MEAN(payments.payment_amount))是一個深度爲 2 的特徵,它是由兩個疊加的聚合操做構造的:MEAN 列之上的 LAST(最近的)列。這表示每一個客戶最近的貸款平均支付額。

咱們能夠疊加任意深度的特徵,但在實踐中,我從沒有使用超過 2 個深度的特徵。此外,這些特徵很難解釋,可是我鼓勵任何對「深刻」感興趣的人。

咱們沒必要人工指定特徵基元,但可讓特徵工具自動爲咱們選取特徵。爲此,咱們使用相同的 ft.dfs 函數調用,可是不傳入任何特徵基元。

# Perform deep feature synthesis without specifying primitives
features, feature_names = ft.dfs(entityset=es, target_entity='clients', 
                                 max_depth = 2)

features.head()
複製代碼

特徵工具構造了不少特徵供咱們使用。儘管這個過程確實能自動構造新的特徵,可是它不會取代數據科學家,由於咱們仍然須要弄清楚如何處理這些特徵。例如,咱們的目的是預測一位客戶是否會償還貸款,咱們能夠尋找與特定結果最相關的特徵。此外,若是咱們具備領域知識,咱們能夠用這些知識來選擇指定的特徵基元或候選特徵的種子深度特徵合成。

下一步

特徵工程自動化解決了一個問題,可是帶來了另外一個問題:特徵太多了。儘管在擬合一個模型以前很難說哪些特徵是重要的,但極可能不是全部這些特徵都與咱們想要訓練的模型的任務相關。此外,擁有太多特徵(參見《Irrelevant Features and the Subset Selection Problem》)可能會致使模型性能不佳,由於較無益的特徵會淹沒那些更重要的特徵。

特徵過多問題以維度災難著稱。隨着特徵數量的上升(數據維度增加),模型愈來愈難以學習特徵與目標之間的映射關係。事實上,讓模型表現良好所需的數據量與特徵數量成指數關係。

維度災難與特徵降維(也叫特徵選擇,去除不相關特徵的過程)相對。這能夠採用多種形式:主成分分析(PCA)、SelectKBest、使用模型中特徵的重要性或使用深度神經網絡進行自編碼。可是,特徵降維是另外一篇文章的不一樣主題。到目前爲止,咱們知道咱們可使用特徵工具以最小的努力從許多表中構造大量的特徵!

結論

與機器學習中的許多主題同樣,使用特徵工具進行特徵工程自動化是一個基於簡單想法的複雜概念。使用實體集、實體和關聯的概念,特徵工具能夠執行深度特徵合成操做來構造新的特徵。深度特徵合成能夠依次疊加特徵基元:「聚合」,它們在多張表間的一對多關聯中起做用,以及「轉換」,是應用於單張表中一或多列以從多張表中構造新的特徵的函數。

在以後的文章中,我將介紹如何在現實世界的問題上使用這項技術,即在 Kaggle 上舉辦的房屋信用違約風險競賽(www.kaggle.com/c/home-cred…)。請繼續關注那則帖子,與此同時,閱讀這則說明以開始競賽(towardsdatascience.com/machine-lea…)! 我但願大家可使用特徵工程自動化做爲數據科學工做中的輔助工具。咱們的模型與咱們提供的數據同樣好,而且特徵工程自動化可使特徵構造的過程更高效。

有關特徵工具更多的信息,包括高級用法,請查看在線文檔(docs.featuretools.com/)。要了解在實踐中如何使用特徵工具,請閱讀開源庫的開發公司 Feature Labs 的工做(www.featurelabs.com/)。

原文連接:
https://towardsdatascience.com/automated-feature-engineering-in-python-99baf11cc219
相關文章
相關標籤/搜索