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

Python 中的特征工程自動化

如何自動化地創(chuàng)建機器學習特征

[譯] 使用 Python 進行自動化特征工程的圖1

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

特征工程,也稱為特征創(chuàng)建,是從已有數(shù)據(jù)中創(chuàng)建出新特征并且用于訓練機器學習模型的過程。這個步驟可能要比實際使用的模型更加重要,因為機器學習算法僅僅從我們提供給他的數(shù)據(jù)中進行學習,創(chuàng)建出與任務(wù)相關(guān)的特征是非常關(guān)鍵的(可以參照這篇文章 "A Few Useful Things to Know about Machine Learning" —— 《了解機器學習的一些有用的事》,譯者注)。

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

在這篇文章中,我們將剖析一個基于 featuretools Python library 庫進行自動特征工程處理的案例。我們將使用一個樣例數(shù)據(jù)集來展示基本信息(請繼續(xù)關(guān)注未來的使用真實數(shù)據(jù)的文章)。這篇文章最終的代碼可以在 GitHub 獲取。


特征工程基礎(chǔ)

特征工程意味著從分布在多個相關(guān)表格中的現(xiàn)有數(shù)據(jù)集中構(gòu)建出額外的特征。特征工程需要從數(shù)據(jù)中提取相關(guān)信息,并且將其放入一個單獨的表中,然后可以用來訓練機器學習模型。

構(gòu)建特征的過程非常耗時,因為每獲取一項新的特征都需要很多步驟才能構(gòu)建出來,尤其是當需要從多于一張表格中獲取信息時。我們可以把特征創(chuàng)建的操作分成兩類:轉(zhuǎn)換聚合。讓我們通過幾個例子的實戰(zhàn)來看看這些概念。

一次轉(zhuǎn)換操作僅作用于一張表,該操作能從一個或多個現(xiàn)有列中創(chuàng)建新特征(比如說 Python 中,一張表就如同 Pandas 庫中的一個 DataFrame)。如下面的例子所示,假如我們有如下的一張客戶(clients)信息表:

[譯] 使用 Python 進行自動化特征工程的圖2

我們可以通過從 joined 列中尋找出月份或者對 income 列取自然對數(shù)來創(chuàng)建特征。這些都是轉(zhuǎn)換的范疇,因為他們都是使用了單張表中的信息。

[譯] 使用 Python 進行自動化特征工程的圖3

另一方面,聚合 則是跨表執(zhí)行的,其使用了一對多關(guān)系進行分組觀察,然后再計算統(tǒng)計數(shù)據(jù)。比如說,如果我們還有另外一張含有客戶貸款信息的表格,這張表里可能每個客戶都有多種貸款,我們就可以計算出每位客戶端諸如貸款平均值、最大值、最小值等統(tǒng)計數(shù)據(jù)。

這個過程包括了根據(jù)客戶進行貸款表格分組、計算聚合、然后把計算結(jié)果數(shù)據(jù)合并到客戶數(shù)據(jù)中。如下代碼展示了我們?nèi)绾问褂?Python 中的 language of Pandas 庫進行計算的過程:

import pandas as pd # 根據(jù)客戶 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 進行自動化特征工程的圖4

這些操作本身并不困難,但是如果我們有數(shù)百個變量分布在數(shù)十張表中,手工進行操作則是不可行的。理想情況下,我們希望有一種解決方案,可以在多個表格當中進行自動轉(zhuǎn)換和聚合操作,最后將結(jié)果數(shù)據(jù)合并到一張表格中。盡管 Pandas 是一個很優(yōu)秀的資源庫,但利用 Pandas 時我們?nèi)匀恍枰止げ僮骱芏嗟臄?shù)據(jù)!(更多關(guān)于手工特征工程的信息可以查看如下這個杰出的著作 Python Data Science Handbook)。

Featuretools 框架

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

深度特征合成疊加了多個轉(zhuǎn)換和聚合操作(在 feautretools 中也被稱為 feature primitives (特征基元))來從遍布很多表格中的數(shù)據(jù)中創(chuàng)建出特征。如同絕大多數(shù)機器學習中的想法一樣,這是一種建立在簡單概念基礎(chǔ)上的復雜方法。通過一次學習一個構(gòu)建模塊,我們可以很好地理解這個強大的方法。

首先,讓我們看看我們的數(shù)據(jù)。之前我們已經(jīng)看到了一些數(shù)據(jù)集,完整的表集合如下所示:

  • clients : 客戶在信用社的的基本信息。每個客戶在這個 dataframe 中僅占一行

[譯] 使用 Python 進行自動化特征工程的圖5

  • loans: 給客戶的貸款。每個貸款在這個 dataframe 中僅占一行,但是客戶可能會有多個貸款

[譯] 使用 Python 進行自動化特征工程的圖6

  • payments: 貸款償還。每個付款只有一行,但是每筆貸款可以有多筆付款。

[譯] 使用 Python 進行自動化特征工程的圖7

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

實體和實體集

對于 featuretools 來說,最重要的兩個概念是實體實體集。一個實體就只是一張表(或者說一個 Pandas 中的 DataFrame) 。一個實體集是一系列表的集合以及這些表格之間的關(guān)系。你可以把實體集認為是 Python 中的另外一個數(shù)據(jù)結(jié)構(gòu),這個數(shù)據(jù)結(jié)構(gòu)有自己的方法和參數(shù)。

我們可以在 featuretools 中利用下面的代碼創(chuàng)建出一個空的實體集:

import featuretools as ft # 創(chuàng)建新實體集   es = ft.EntitySet(id = 'clients') 復制代碼

現(xiàn)在我們必須添加一些實體。每個實體必須有一個索引,它是一個包含所有唯一元素的列。也就是說,索引中的每個值必須只出現(xiàn)在表中一次。clients dataframe 中的索引是 client_id ,因為每個客戶在這個 dataframe 中只有一行。我們使用以下語法向?qū)嶓w集添加一個已經(jīng)有索引的實體:

# 從客戶 dataframe 中創(chuàng)建出一個實體 # 這個 dataframe 已經(jīng)有一個索引和一個時間索引 es = es.entity_from_dataframe(entity_id = 'clients', dataframe = clients,                                index = 'client_id', time_index = 'joined') 復制代碼

loans datafram 同樣有一個唯一的索引,loan_id 以及向?qū)嶓w集添加 loan_id 的語法和 clients 一樣。然而,對于 payments dataframe 來說,并不存在唯一的索引。當我們向?qū)嶓w集添加實體時,我們需要把參數(shù) make_index 設(shè)置為 True( make_index = True ),同時為索引指定好名稱。此外,雖然 featuretools 會自動推斷實體中的每個列的數(shù)據(jù)類型,我們也可以將一個列類型的字典傳遞給參數(shù) variable_types 來進行數(shù)據(jù)類型重寫。

# 從付款 dataframe 中創(chuàng)建一個實體 # 該實體還沒有一個唯一的索引 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 是一個整型數(shù)據(jù),這不是一個數(shù)值變量,因為它只能接受兩個離散值,所以我們告訴 featuretools 將它是為一個分類變量。在向?qū)嶓w集添加了 dataframs 之后,我們將檢查其中的任何一個:

[譯] 使用 Python 進行自動化特征工程的圖8

我們指定的修改可以正確地推斷列類型。接下來,我們需要指定實體集中的表是如何進行關(guān)聯(lián)的。

表關(guān)系

考慮兩個表之間的關(guān)系的最佳方式是父親與孩子的類比。這是一對多的關(guān)系:每個父親可以有多個孩子。在表領(lǐng)域中,父親在每個父表中都有一行,但是子表中可能有多個行對應(yīng)于同一個父親的多個孩子。

例如,在我們的數(shù)據(jù)集中,clients dataframe 是 loans dataframe 的父親。每個客戶在 clients 中只有一行,但在 loans 中可能有多行。同樣, loanspayments 的父親,因為每筆貸款都有多個支付。父親通過共享變量與孩子相連。當我們執(zhí)行聚合時,我們將子表按父變量分組,并計算每個父表的子表的統(tǒng)計信息。

在 featuretools 中格式化關(guān)系,我們只需指定將兩個表鏈接在一起的變量。 clientsloans 表通過 loan_id 變量鏈接, loanspayments 通過 loan_id 聯(lián)系在一起。創(chuàng)建關(guān)系并將其添加到實體集的語法如下所示:

# 客戶與先前貸款的關(guān)系 r_client_previous = ft.Relationship(es['clients']['client_id'],                                     es['loans']['client_id']) # 將關(guān)系添加到實體集 es = es.add_relationship(r_client_previous) # 以前的貸款和以前的付款之間的關(guān)系 r_payments = ft.Relationship(es['loans']['loan_id'],                                       es['payments']['loan_id']) # 將關(guān)系添加到實體集 es = es.add_relationship(r_payments) es 復制代碼

[譯] 使用 Python 進行自動化特征工程的圖9

實體集現(xiàn)在包含三個實體(或者說是表)和連接這些實體的關(guān)系。在添加實體和對關(guān)系形式化之后,我們的實體集就準備完成了,我們接下來可以準備創(chuàng)建特征。

特征基元

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

  • 聚合:通過父節(jié)點對子節(jié)點(一對多)關(guān)系完成的操作,并計算子節(jié)點的統(tǒng)計信息。一個例子是通過 client_idloan 表分組,并為每個客戶機找到最大的貸款金額。

  • 轉(zhuǎn)換:在單個表上對一個或多個列執(zhí)行的操作。舉個例子,取一個表中兩個列之間的差值,或者取列的絕對值。

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

[譯] 使用 Python 進行自動化特征工程的圖10

特征基元

這些基元可以自己使用或組合來創(chuàng)建特征。要使用指定的基元,我們使用 ft.dfs 函數(shù)(代表深度特征合成)。我們傳入 實體集目標實體(這兩個參數(shù)是我們想要加入特征的表)以及 trans_primitives 參數(shù)(用于轉(zhuǎn)換)和 agg_primitives 參數(shù)(用于聚合):

# 使用指定的基元創(chuàng)建新特征 features, feature_names = ft.dfs(entityset = es, target_entity = 'clients',                                   agg_primitives = ['mean', 'max', 'percent_true', 'last'],                                  trans_primitives = ['years', 'month', 'subtract', 'divide']) 復制代碼

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

[譯] 使用 Python 進行自動化特征工程的圖11

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

[譯] 使用 Python 進行自動化特征工程的圖12

盡管我們只指定了很少一部分的特征基元,但是 featuretools 通過組合和疊加這些基元創(chuàng)建了許多新特征。

[譯] 使用 Python 進行自動化特征工程的圖13

完整的 dataframe 有793列新特性!

深度特征合成

現(xiàn)在,我們已經(jīng)準備好了理解深度特征合成(deep feature synthesis, dfs)的所有部分。事實上,我們已經(jīng)在前面的函數(shù)調(diào)用中執(zhí)行了 dfs 函數(shù)!深度特性只是將多個特征基元疊加的特性,而 dfs 是生成這些特性的過程的名稱。深度特征的深度是創(chuàng)建該特性所需的特征數(shù)量。

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

[譯] 使用 Python 進行自動化特征工程的圖14

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


我們不必手工指定特征基元,而是可以讓 featuretools 自動為我們選擇特性。為此,我們使用相同的 ft.dfs 函數(shù)調(diào)用,但不傳遞任何特征基元:

# 執(zhí)行深度特征合成而不指定特征基元。 features, feature_names = ft.dfs(entityset=es, target_entity='clients',                                   max_depth = 2) features.head() 復制代碼

[譯] 使用 Python 進行自動化特征工程的圖15

Featuretools 已經(jīng)為我們構(gòu)建了許多新的特征供我們使用。雖然這個過程會自動創(chuàng)建新特征,但它不會取代數(shù)據(jù)科學家,因為我們?nèi)匀恍枰宄绾翁幚硭羞@些特征。例如,如果我們的目標是預測客戶是否會償還貸款,我們可以查找與特定結(jié)果最相關(guān)的特征。此外,如果我們有特殊領(lǐng)域知識,我們可以使用它來選擇具有候選特征的特定特征基元或種子深度特征合成

接下來的步驟

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

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

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

結(jié)論

像機器學習領(lǐng)域很多的話題一樣,使用 feautretools 的自動特征工程是一個建立在簡單想法之上的復雜概念。使用實體集、實體和關(guān)系的概念,feautretools 可以執(zhí)行深度特性合成來創(chuàng)建新特征。深度特征合成反過來又將特征基元堆疊起來 —— 也就是聚合,在表格之間建立起一對多的關(guān)系,同時進行轉(zhuǎn)換,在單表中對一列或者多列應(yīng)用,通過這些方法從很多的表格中構(gòu)建出新的特征出來。

請持續(xù)關(guān)注這篇文章,與此同時,閱讀關(guān)于這個競賽的介紹 this introduction to get started。我希望您現(xiàn)在可以使用自動化特征工程作為數(shù)據(jù)科學管道中的輔助工具。我們的模型將和我們提供的數(shù)據(jù)一樣好,自動化的特征工程可以幫助使特征創(chuàng)建過程更有效。

要獲取更多關(guān)于特征工具的信息,包括這些工具的高級用法,可以查閱在線文檔。要查看特征工具如何在實踐中應(yīng)用,可以參見 Feature Labs 的工作成果,這就是開發(fā) featuretools 這個開源庫的公司。

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

登錄后免費查看全文
立即登錄
App下載
技術(shù)鄰APP
工程師必備
  • 項目客服
  • 培訓客服
  • 平臺客服

TOP