02.03 fklearn簡介:Nubank的機器學習庫

Nubank剛剛開源了fklearn,這是我們的機器學習python庫!

fklearn簡介:Nubank的機器學習庫

在Nubank,我們嚴重依賴機器學習來制定可擴展的數據驅動型決策。 儘管那裡還有許多其他的ML庫(例如,我們廣泛使用Xgboost,LGBM和ScikitLearn),但我們感到需要更高層次的抽象,這將有助於我們更輕鬆地將這些庫應用於所面臨的問題。 Fklearn有效地將這些庫包裝為一種格式,使它們在生產中的使用更加有效。

Fklearn當前在Nubank上支持大量的機器學習模型,解決了從信用評分到自動客戶支持聊天響應的問題。 我們在構建時考慮了以下目標:

  • · 驗證應反映現實生活中的情況
  • · 生產模型應與經過驗證的模型匹配
  • · 模型應準備就緒,只需幾個額外步驟
  • · 模型結果的重現性和深入分析應該易於實現

早期,我們認為函數式編程將是實現這些目標的強大盟友。

F代表功能

在Nubank,我們是函數式編程的忠實擁護者,而不僅限於"工程"一章。 但是函數式編程如何幫助數據科學家?

機器學習通常是通過使用面向對象的python代碼來完成的,這也是我們在Nubank所採用的方式。 那時,建立機器學習模型並將其投入生產的過程非常繁瑣,而且常常有很多錯誤。 我們僅部署模型以發現生產中的預測與驗證期間看到的預測不匹配。 而且,驗證通常是無法重現的,通常是在有狀態的Jupyter Notebook中進行的。

函數式編程可通過以下方法幫助解決這些問題:

  • · 使訓練過程中發生的數據轉換與生產中的模型匹配的流水線變得容易。
  • · 允許在交互式環境(例如Jupyter筆記本電腦)中進行更安全的迭代,防止由於有狀態代碼導致的錯誤並提高研究的可重複性。
  • · 使我們能夠編寫適用於模型類型和應用程序的非常通用的驗證,調整和功能選擇代碼,從而使我們整體上效率更高。

讓我們看一個例子,看看函數式編程在實踐中是如何做到的。假設我們要根據兩個變量來預測某人在信用卡上的支出:月收入和以前的帳單金額。由於此模型的輸出將用於敏感的決策,因此,我們要確保它對輸入變量中的異常值具有魯棒性,因此我們決定:

  1. 由於收入是自我報告的,有時會被誇大,因此將月收入的上限設為50,000。
  2. 將模型的輸出範圍限制為[0,20,000]間隔。

然後使用簡單的線性迴歸模型。 代碼如下所示:

<code>from fklearn.training.pipeline import build_pipeline
from fklearn.training.regression import linear_regression_learner
from fklearn.training.transformation import capper, floorer, prediction_ranger

def fit(train_data):
capper_fn = capper(columns_to_cap=["income"], precomputed_caps={"income": 50,000})
regression_fn = linear_regression_learner(features=["income", "bill_amount"], target="spend")
ranger_fn = prediction_ranger(prediction_min=0.0, prediction_max=20000.0)

learner = build_pipeline(capper_fn, regression_fn, ranger_fn)
predict_fn, training_predictions, logs = learner(train_data)

return predict_fn, logs/<code>

不要驚慌! 我們將逐步講解代碼,解釋一些重要的fklearn概念。

學習器函數

在scikit-learn中,模型的主要抽象是具有適合和變換方法的類,而在fklearn中,我們使用所謂的學習器函數。 學習器函數獲取一些訓練數據(以及其他參數),從中學習一些東西,然後返回三樣東西:預測函數,轉換後的訓練數據和日誌。 本示例的前三行正在初始化三個學習器函數:capper,linear_regression_learner和prediction_ranger。

為了更好地說明,這是linear_regression_learner的簡化定義:

<code>from typing import Any, Dict, List
from sklearn.linear_model import LinearRegression
from toolz import curry
import pandas as pd

@curry
def linear_regression_learner(df: pd.DataFrame,
features: List[str],
target: str,
params: Dict[str, Any] = None) -> LearnerReturnType:

# initialize and fit the linear regression
reg = LinearRegression(**params)
reg.fit(df[features].values, df[target].values)

# define the prediction function
def p(new_df: pd.DataFrame) -> pd.DataFrame:
# note that `reg` here refers to the linear regression fit above, via the function’s closure.
return new_df.assign(prediction=reg.predict(new_df[features].values))

# the log can contain arbitrary information that helps inspect or debug the model
log = {'linear_regression_learner': {
'features': features,
'target': target,
'parameters': params,
'training_samples': len(df),
'feature_importance': dict(zip(features, reg.coef_.flatten()))
}

return p, p(df), log/<code>

注意使用類型提示! 它們與非常有用的toolz庫一起,有助於使python中的函數式編程不那麼笨拙。

正如我們提到的,學習者函數返回三件事(一個函數,一個DataFrame和一個字典),如LearnerReturnType定義所描述:

<code>from typing import Any, Callable, Dict, Tuple
import pandas as pd

LearnerReturnType = Tuple[PredictFnType, pd.DataFrame, LearnerLogType]
PredictFnType = Callable[[pd.DataFrame], pd.DataFrame]
LearnerLogType = Dict[str, Any]/<code>

· 預測函數始終具有相同的簽名:它接受一個DataFrame並返回一個DataFrame(我們使用Pandas)。 它應該能夠接受任何新的DataFrame(只要它包含必需的列)並對其進行轉換(它等效於scikit-learn對象的transform方法)。 在這種情況下,預測函數僅使用經過訓練的線性迴歸模型的預測來創建新列。

· 轉換後的訓練數據通常只是應用於訓練數據的預測函數。 當您希望對訓練集進行預測或用於構建管道時,此功能非常有用,我們將在後面介紹。

· 日誌是字典,可以包含與檢查或調試學習者有關的任何信息(例如,使用了哪些功能,訓練集中有多少樣本,功能重要性或係數)。

學習器函數顯示一些常見的功能編程屬性:

· 它們是純函數,意味著在給定相同輸入的情況下它們總是返回相同的結果,並且沒有副作用。 實際上,這意味著您可以根據需要多次致電學習者,而不必擔心結果不一致。 例如,在scikit-learn對象上調用fit時,情況並非總是如此,因為對象可能會發生變異。

· 它們是高階函數,因為它們返回另一個函數(預測函數)。 由於預測功能是在學習者內部定義的,因此它可以通過關閉功能訪問學習者功能範圍內的變量。

· 通過具有一致的簽名,學習者功能(和預測功能)是可組合的。 這意味著從中構建整個管道非常簡單,我們將很快看到。

· 它們是可伸縮的,這意味著您可以分步初始化它們,一次僅傳遞幾個參數(這是我們示例前三行中實際發生的情況)。 這在定義管道並將單個模型應用於不同的數據集同時獲得一致的結果時很有用。

可能需要花費一些時間來解決所有這些問題,但是不用擔心,您不需要成為函數式編程的專家就可以有效地使用fklearn。 關鍵是要理解可以根據學習者抽象將模型(和其他數據轉換)定義為函數。

流水線

但是,機器學習模型很少單獨存在。 通過僅關注模型,數據科學家傾向於忘記數據在機器學習部分之前和之後經歷的轉換。 在訓練和部署模型時,這些轉換通常需要完全相同,並且數據科學家可能會嘗試在生產中手動重新創建其訓練前和後處理步驟,這導致難以維護的代碼重複。

學習者功能是可組合的,這意味著可以將兩個或多個學習者結合起來視為一個新的,更復雜的學習者。 這意味著,無論您要執行多少步驟,最終模型的行為都將與單個模型相同,並且進行預測就像對新數據調用最終預測函數一樣簡單。 將建模管道中的所有步驟包含在一個單一的純函數中也有助於進行驗證和調整,因為我們可以將其傳遞給其他函數而不必擔心副作用。

在我們的示例中,我們的流程包括三個步驟:設置收入變量的上限,運行迴歸,然後將回歸輸出限制在[0,20000]範圍內。 在初始化每個學習者之後,我們使用以下兩行代碼構建管道並將其應用於訓練集:

<code>...
learner = build_pipeline(capper_fn, regression_fn, ranger_fn)
predict_fn, training_predictions, logs = learner(train_data)
.../<code>

現在,學習者變量包含組成三個學習者功能的結果的流水線,並將其應用於訓練數據以產生最終的預測功能。 該功能會將管道中所有等效的步驟應用於測試數據,如下圖所示:

fklearn簡介:Nubank的機器學習庫

訓練時數據如何流經管道,預測時如何流經預測功能的示例。預測函數本身由管道返回;它是首次在訓練數據上調用管道時每個學習者生成的三個預測函數的組成。日誌是來自管道中所有學習器功能的日誌的組合。

下一步是什麼?

我們已經瞭解瞭如何將模型和數據轉換步驟編寫為學習者函數,以及fklearn中的功能管道如何幫助我們確保訓練和驗證過程中完成的轉換與生產過程中的轉換匹配。

在此博客文章的第二部分中,我們討論了模型驗證和分析,以及fklearn提供的使這些步驟更有效的工具。

同時,我們邀請您親自嘗試fklearn! 我們不希望fklearn取代ML中的當前標準,但是我們希望它開始有關函數式編程對機器學習的好處的有趣的對話。

對數據科學和Nubank正在開發的令人興奮的產品感興趣? 我們正在招聘!

(本文翻譯自Lucas Estevam的文章《Introducing fklearn: Nubank's machine learning library (Part I)》,參考:https://medium.com/building-nubank/introducing-fklearn-nubanks-machine-learning-library-part-i-2a1c781035d0)


分享到:


相關文章: