[譯] 使用 Python 進行自動化特徵工程

mingxing47發表於2019-03-03

Python 中的特徵工程自動化

如何自動化地建立機器學習特徵

[譯] 使用 Python 進行自動化特徵工程

機器學習正在利用諸如 H20TPOTauto-sklearn 等工具越來越多地從手工設計模型向自動化優化管道遷移。以上這些類庫,連同如 random search 等方法一起,目的是在不需要人工干預的情況下找到適合於資料集的最佳模型,以此來簡化器學習的模型選擇和調優部分。然而,特徵工程,作為機器學習管道中一個可以說是更有價值的方面,幾乎全部是手工活。

特徵工程,也稱為特徵建立,是從已有資料中建立出新特徵並且用於訓練機器學習模型的過程。這個步驟可能要比實際使用的模型更加重要,因為機器學習演算法僅僅從我們提供給他的資料中進行學習,建立出與任務相關的特徵是非常關鍵的(可以參照這篇文章 “A Few Useful Things to Know about Machine Learning” —— 《瞭解機器學習的一些有用的事》,譯者注)。

通常來說,特徵工程是一個漫長的手工過程,依賴於某個特定領域的知識、直覺、以及對資料的操作。這個過程可能會非常乏味並且最終獲得的特性會被人類的主觀性和花在上面的時間所限制。自動特徵工程的目標是通過從資料集中建立許多候選特徵來幫助資料科學家減輕工作負擔,從這些建立了候選特徵的資料集中,資料科學家可以選擇最佳的特徵並且用來訓練。

在這篇文章中,我們將剖析一個基於 featuretools Python library 庫進行自動特徵工程處理的案例。我們將使用一個樣例資料集來展示基本資訊(請繼續關注未來的使用真實資料的文章)。這篇文章最終的程式碼可以在 GitHub 獲取。


特徵工程基礎

特徵工程意味著從分佈在多個相關表格中的現有資料集中構建出額外的特徵。特徵工程需要從資料中提取相關資訊,並且將其放入一個單獨的表中,然後可以用來訓練機器學習模型。

構建特徵的過程非常耗時,因為每獲取一項新的特徵都需要很多步驟才能構建出來,尤其是當需要從多於一張表格中獲取資訊時。我們可以把特徵建立的操作分成兩類:轉換聚合。讓我們通過幾個例子的實戰來看看這些概念。

一次轉換操作僅作用於一張表,該操作能從一個或多個現有列中建立新特徵(比如說 Python 中,一張表就如同 Pandas 庫中的一個 DataFrame)。如下面的例子所示,假如我們有如下的一張客戶(clients)資訊表:

[譯] 使用 Python 進行自動化特徵工程

我們可以通過從 joined 列中尋找出月份或者對 income 列取自然對數來建立特徵。這些都是轉換的範疇,因為他們都是使用了單張表中的資訊。

[譯] 使用 Python 進行自動化特徵工程

另一方面,聚合 則是跨表執行的,其使用了一對多關係進行分組觀察,然後再計算統計資料。比如說,如果我們還有另外一張含有客戶貸款資訊的表格,這張表裡可能每個客戶都有多種貸款,我們就可以計算出每位客戶端諸如貸款平均值、最大值、最小值等統計資料。

這個過程包括了根據客戶進行貸款表格分組、計算聚合、然後把計算結果資料合併到客戶資料中。如下程式碼展示了我們如何使用 Python 中的 language of Pandas 庫進行計算的過程:

import pandas as pd

# 根據客戶 id (client id)進行貸款分組,並計算貸款平均值、最大值、最小值
stats = loans.groupby(`client_id`)[`loan_amount`].agg([`mean`, `max`, `min`])
stats.columns = [`mean_loan_amount`, `max_loan_amount`, `min_loan_amount`]

# 和客戶的 dataframe 進行合併
stats = clients.merge(stats, left_on = `client_id`, right_index=True, how = `left`)

stats.head(10)
複製程式碼
[譯] 使用 Python 進行自動化特徵工程

這些操作本身並不困難,但是如果我們有數百個變數分佈在數十張表中,手工進行操作則是不可行的。理想情況下,我們希望有一種解決方案,可以在多個表格當中進行自動轉換和聚合操作,最後將結果資料合併到一張表格中。儘管 Pandas 是一個很優秀的資源庫,但利用 Pandas 時我們仍然需要手工操作很多的資料!(更多關於手工特徵工程的資訊可以檢視如下這個傑出的著作 Python Data Science Handbook)。

Featuretools 框架

幸運的是, featuretools 正是我們所尋找的解決方案。這個開源的 Python 庫可以自動地從一系列有關聯的表格中建立出很多的特徵。 Featuretools 是基於一個被稱為 “Deep feature synthesis” (深度特徵合成)的方法所建立出來的,這個方法聽起來要比實際跑起來更加令人印象深刻。(這個名字是來自於多特徵的疊加,並不是因為這個方法使用了深度學習!)

深度特徵合成疊加了多個轉換和聚合操作(在 feautretools 中也被稱為 feature primitives (特徵基元))來從遍佈很多表格中的資料中建立出特徵。如同絕大多數機器學習中的想法一樣,這是一種建立在簡單概念基礎上的複雜方法。通過一次學習一個構建模組,我們可以很好地理解這個強大的方法。

首先,讓我們看看我們的資料。之前我們已經看到了一些資料集,完整的表集合如下所示:

  • clients : 客戶在信用社的的基本資訊。每個客戶在這個 dataframe 中僅佔一行
[譯] 使用 Python 進行自動化特徵工程
  • loans: 給客戶的貸款。每個貸款在這個 dataframe 中僅佔一行,但是客戶可能會有多個貸款
[譯] 使用 Python 進行自動化特徵工程
  • payments: 貸款償還。每個付款只有一行,但是每筆貸款可以有多筆付款。
[譯] 使用 Python 進行自動化特徵工程

如果我們有一件機器學習任務,例如預測一個客戶是否會償還一個未來的貸款,我們將把所有關於客戶的資訊合併到一個表格中。這些表格是相互關聯的(通過 client_idloan_id 變數),我們可以使用一系列的轉換和聚合操作來手工完成這一過程。然而,我們很快就將看到,我們可以使用 featuretools 來自動化這個過程。

實體和實體集

對於 featuretools 來說,最重要的兩個概念是實體實體集。一個實體就只是一張表(或者說一個 Pandas 中的 DataFrame) 。一個實體集是一系列表的集合以及這些表格之間的關係。你可以把實體集認為是 Python 中的另外一個資料結構,這個資料結構有自己的方法和引數。

我們可以在 featuretools 中利用下面的程式碼建立出一個空的實體集:

import featuretools as ft

# 建立新實體集  
es = ft.EntitySet(id = `clients`)
複製程式碼

現在我們必須新增一些實體。每個實體必須有一個索引,它是一個包含所有唯一元素的列。也就是說,索引中的每個值必須只出現在表中一次。clients dataframe 中的索引是 client_id ,因為每個客戶在這個 dataframe 中只有一行。我們使用以下語法向實體集新增一個已經有索引的實體:

# 從客戶 dataframe 中建立出一個實體
# 這個 dataframe 已經有一個索引和一個時間索引
es = es.entity_from_dataframe(entity_id = `clients`, dataframe = clients, 
                              index = `client_id`, time_index = `joined`)
複製程式碼

loans datafram 同樣有一個唯一的索引,loan_id 以及向實體集新增 loan_id 的語法和 clients 一樣。然而,對於 payments dataframe 來說,並不存在唯一的索引。當我們向實體集新增實體時,我們需要把引數 make_index 設定為 True( make_index = True ),同時為索引指定好名稱。此外,雖然 featuretools 會自動推斷實體中的每個列的資料型別,我們也可以將一個列型別的字典傳遞給引數 variable_types 來進行資料型別重寫。

# 從付款 dataframe 中建立一個實體
# 該實體還沒有一個唯一的索引
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`)
複製程式碼

對於這個 dataframe 來說,即使 missed 是一個整型資料,這不是一個數值變數,因為它只能接受兩個離散值,所以我們告訴 featuretools 將它是為一個分類變數。在向實體集新增了 dataframs 之後,我們將檢查其中的任何一個:

[譯] 使用 Python 進行自動化特徵工程

我們指定的修改可以正確地推斷列型別。接下來,我們需要指定實體集中的表是如何進行關聯的。

表關係

考慮兩個表之間的關係的最佳方式是父親與孩子的類比。這是一對多的關係:每個父親可以有多個孩子。在表領域中,父親在每個父表中都有一行,但是子表中可能有多個行對應於同一個父親的多個孩子。

例如,在我們的資料集中,clients dataframe 是 loans dataframe 的父親。每個客戶在 clients 中只有一行,但在 loans 中可能有多行。同樣, loanspayments 的父親,因為每筆貸款都有多個支付。父親通過共享變數與孩子相連。當我們執行聚合時,我們將子表按父變數分組,並計算每個父表的子表的統計資訊。

在 featuretools 中格式化關係,我們只需指定將兩個錶連結在一起的變數。 clientsloans 表通過 loan_id 變數連結, loanspayments 通過 loan_id 聯絡在一起。建立關係並將其新增到實體集的語法如下所示:

# 客戶與先前貸款的關係
r_client_previous = ft.Relationship(es[`clients`][`client_id`],
                                    es[`loans`][`client_id`])

# 將關係新增到實體集
es = es.add_relationship(r_client_previous)

# 以前的貸款和以前的付款之間的關係
r_payments = ft.Relationship(es[`loans`][`loan_id`],
                                      es[`payments`][`loan_id`])

# 將關係新增到實體集
es = es.add_relationship(r_payments)

es
複製程式碼
[譯] 使用 Python 進行自動化特徵工程

實體集現在包含三個實體(或者說是表)和連線這些實體的關係。在新增實體和對關係形式化之後,我們的實體集就準備完成了,我們接下來可以準備建立特徵。

特徵基元

在深入瞭解特性合成之前,我們需要了解特徵基元。我們已經知道它們是什麼了,但是我們只是用不同的名字稱呼它們!這些是我們用來形成新特徵的基本操作:

  • 聚合:通過父節點對子節點(一對多)關係完成的操作,並計運算元節點的統計資訊。一個例子是通過 client_idloan 表分組,併為每個客戶機找到最大的貸款金額。
  • 轉換:在單個表上對一個或多個列執行的操作。舉個例子,取一個表中兩個列之間的差值,或者取列的絕對值。

新特性是在 featruetools 中建立的,使用這些特徵基元本身或疊加多個特徵基元。下面是 featuretools 中的一些特徵基元列表(我們還可以定義自定義特徵基元

[譯] 使用 Python 進行自動化特徵工程

特徵基元

這些基元可以自己使用或組合來建立特徵。要使用指定的基元,我們使用 ft.dfs 函式(代表深度特徵合成)。我們傳入 實體集目標實體(這兩個引數是我們想要加入特徵的表)以及 trans_primitives 引數(用於轉換)和 agg_primitives 引數(用於聚合):

# 使用指定的基元建立新特徵
features, feature_names = ft.dfs(entityset = es, target_entity = `clients`, 
                                 agg_primitives = [`mean`, `max`, `percent_true`, `last`],
                                 trans_primitives = [`years`, `month`, `subtract`, `divide`])
複製程式碼

以上函式返回結果是每個客戶的新特徵 dataframe (因為我們把客戶定義為目標實體)。例如,我們有每個客戶加入的月份,這個月份是一個轉換特性基元:

[譯] 使用 Python 進行自動化特徵工程

我們還有一些聚合基元,比如每個客戶的平均支付金額:

[譯] 使用 Python 進行自動化特徵工程

儘管我們只指定了很少一部分的特徵基元,但是 featuretools 通過組合和疊加這些基元建立了許多新特徵。

[譯] 使用 Python 進行自動化特徵工程

完整的 dataframe 有793列新特性!

深度特徵合成

現在,我們已經準備好了理解深度特徵合成(deep feature synthesis, dfs)的所有部分。事實上,我們已經在前面的函式呼叫中執行了 dfs 函式!深度特性只是將多個特徵基元疊加的特性,而 dfs 是生成這些特性的過程的名稱。深度特徵的深度是建立該特性所需的特徵數量。

例如,MEAN(payments.payment_amount) 列是一個深度為 1 的特徵,因為它是使用單個聚合建立的。深度為 2 的特徵是 LAST(loans(MEAN(payments.payment_amount)) ,這是通過疊加兩個聚合而成的: LAST(most recent) 在均值之上。這表示每個客戶最近一次貸款的平均支付金額。

[譯] 使用 Python 進行自動化特徵工程

我們可以將特徵疊加到任何我們想要的深度,但是在實踐中,我從來沒有超過 2 的深度。在這之後,這些特徵就很難解釋了,但我鼓勵有興趣的人嘗試“深入研究”


我們不必手工指定特徵基元,而是可以讓 featuretools 自動為我們選擇特性。為此,我們使用相同的 ft.dfs 函式呼叫,但不傳遞任何特徵基元:

# 執行深度特徵合成而不指定特徵基元。
features, feature_names = ft.dfs(entityset=es, target_entity=`clients`, 
                                 max_depth = 2)

features.head()
複製程式碼
[譯] 使用 Python 進行自動化特徵工程

Featuretools 已經為我們構建了許多新的特徵供我們使用。雖然這個過程會自動建立新特徵,但它不會取代資料科學家,因為我們仍然需要弄清楚如何處理所有這些特徵。例如,如果我們的目標是預測客戶是否會償還貸款,我們可以查詢與特定結果最相關的特徵。此外,如果我們有特殊領域知識,我們可以使用它來選擇具有候選特徵的特定特徵基元或種子深度特徵合成

接下來的步驟

自動化的特徵工程解決了一個問題,但卻創造了另一個問題:創造出太多的特徵。雖然說在確定好一個模型之前很難說這些特徵中哪些是重要的,但很可能並不是所有的特徵都與我們想要訓練的任務相關。而且,擁有太多特徵可能會讓模型的表現下降,因為在訓練的過程中一些不太有用的特徵會淹沒那些更為重要的特徵。

太多特徵的問題被稱為維數的詛咒。隨著特徵數量的增加(資料的維數增加),模型越來越難以瞭解特徵和目標之間的對映。事實上,模型執行良好所需的資料量(與特性的數量成指數比例)(stats.stackexchange.com/a/65380/157…)。

可以化解維數詛咒的是特徵削減(也稱為特徵選擇):移除不相關特性的過程。這可以採取多種形式:主成分分析(PCA),使用 SelectKBest 類,使用從模型引入的特徵,或者使用深度神經網路進行自動編碼。當然,特徵削減則是另一篇文章的另一個主題了。現在,我們知道,我們可以使用 featuretools ,以最少的工作量從許多表中建立大量的特性!

結論

像機器學習領域很多的話題一樣,使用 feautretools 的自動特徵工程是一個建立在簡單想法之上的複雜概念。使用實體集、實體和關係的概念,feautretools 可以執行深度特性合成來建立新特徵。深度特徵合成反過來又將特徵基元堆疊起來 —— 也就是聚合,在表格之間建立起一對多的關係,同時進行轉換,在單表中對一列或者多列應用,通過這些方法從很多的表格中構建出新的特徵出來。

請持續關注這篇文章,與此同時,閱讀關於這個競賽的介紹 this introduction to get started。我希望您現在可以使用自動化特徵工程作為資料科學管道中的輔助工具。我們的模型將和我們提供的資料一樣好,自動化的特徵工程可以幫助使特徵建立過程更有效。

要獲取更多關於特徵工具的資訊,包括這些工具的高階用法,可以查閱線上文件。要檢視特徵工具如何在實踐中應用,可以參見 Feature Labs 的工作成果,這就是開發 featuretools 這個開源庫的公司。

我一如既往地歡迎各位的反饋和建設性的批評,你們可以在 Twitter @koehrsen_will 上與我進行交流。

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章