DBT構建和部署機器學習模型預測訂單退貨
介紹
機器學習 (ML) 在數(shù)據(jù)驅(qū)動的決策中越來越重要,因此使用現(xiàn)代工具和技術來簡化機器學習工作流程非常重要。這就是 dbt 和 fal 可以發(fā)揮作用的地方 - 它們一起使以可擴展和可重現(xiàn)的方式管理和部署機器學習模型變得容易。在這篇博文中,我們將引導您了解如何使用 fal 和 dbt 來訓練和存儲邏輯回歸 ML 模型,對新數(shù)據(jù)進行預測,并將這些預測存儲在 dbt 模型中。在這篇文章結束時,您將具備將這些工具應用于您自己的 ML 項目的技能和知識。
設置
我們準備了一個示例項目,您可以在閱讀此博客文章時使用它。它既有一個帶有一些合成數(shù)據(jù)的dbt項目,也有一個示例Jupyter筆記本。您可以克隆它:git clone?https://github.com/fal-ai/dbt_fal_ml_example
我們使用dbt-fal作為Python適配器。這是運行dbt Python模型的最簡單方法。該項目還使用 BigQuery 作為數(shù)據(jù)倉庫。您可以編輯 require.txt 文件以適合您自己的數(shù)據(jù)倉庫。然后,您可以通過運行以下命令在新的 Python 環(huán)境中安裝項目要求:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
讓我們在項目目錄中創(chuàng)建一個文件,并用必要的憑據(jù)填充它:profiles.yml
example_shop:
target: staging
outputs:
staging:
type: fal
db_profile: db
db:
type: bigquery
method: service-account-json
...
輸出應包含數(shù)據(jù)倉庫憑據(jù)。db
最后,讓我們啟動 Jupyter 筆記本:
jupyter notebook notebooks/Experiments.ipynb
這將在您的終端中打印出一個 URL,您可以在瀏覽器中使用該 URL 并打開“Experiments.ipynb”筆記本。
我們的示例數(shù)據(jù)集模擬零售環(huán)境中的客戶訂單和訂單退貨。該數(shù)據(jù)集包含每個訂單的客戶年齡、訂單總價以及是否退回信息。
數(shù)據(jù)探索和準備
在我們的筆記本中,我們首先導入所有必要的模塊:
import pickle
import uuid
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
from fal import FalDbt
Jupyter 筆記本允許我們運行 shell 命令,因此我們可以運行和:dbt seeddbt run
!dbt seed --profiles-dir ..
!dbt run --select customer_orders customer_orders_labeled --profiles-dir ..
如您所見,我們正在計算兩個 dbt 模型,并且 .顧名思義,一個數(shù)據(jù)集包含標記的數(shù)據(jù),而另一個數(shù)據(jù)集包含未標記的“新鮮”數(shù)據(jù)。customer_orderscustomer_orders_labeled
讓我們看一下模型。我們必須實例化:customer_orders_labeledFalDbt
faldbt = FalDbt(project_dir="..", profiles_dir="..")
現(xiàn)在我們可以將模型下載為 pandas 數(shù)據(jù)幀并打印頂部行:customer_orders_labeled
orders_df = faldbt.ref("customer_orders_labeled")
orders_df.head()
這將打印如下所示的表:
order_id customer_id total_price age return
0 210.0 488.0 187.861698 18.0 0.0
1 263.0 578.0 628.745330 18.0 0.0
2 360.0 578.0 99.154886 18.0 0.0
3 482.0 818.0 393.284591 18.0 0.0
4 594.0 656.0 339.542104 18.0 0.0
該列是數(shù)字,其中表示尚未退回訂單,表示已退回訂單。由于它是我們要預測的列的值,因此我們將此列稱為標簽,其他列是特征。讓我們假設特征和 not 在是否退回訂單方面不起作用。這給我們留下了和.return0.01.0returnorder_idcustomer_idtotal_priceage
可視化要素和標注之間關系的一個好方法是繪制繪圖。我們可以通過使用庫輕松做到這一點:
matplotlib
plot_data = orders_df.sample(frac=0.1, random_state=123)
colors = ['red' if r else 'blue' for r in plot_data['return']] # assign colors based on whether or not order was returned
plt.scatter(plot_data['age'], plot_data['total_price'], c=colors)
plt.xlabel('Age')
plt.ylabel('Total Price')
plt.show()
這是結果圖:

退貨(紅色)和未退貨(藍色)訂單的年齡和價格分布
紅點對應于已退貨的訂單。我們可以從圖中看到,左上角的訂單往往比其他訂單更頻繁地退貨。
ML 模型訓練和評估
我們將訓練和評估的 ML 模型類型稱為邏輯回歸。邏輯回歸適用于此問題,因為目標標簽 () 是二進制的(0 或 1),邏輯回歸模型可以輸出介于 0 和 1 之間的概率。在我們的例子中,邏輯回歸模型的輸出將是給定客戶的年齡和訂單總價格的訂單被退回的概率。return
我們首先將數(shù)據(jù)集拆分為訓練集和測試集:
X_train, X_test, y_train, y_test = train_test_split(
orders_df[['age', 'total_price']],
orders_df['return'],
test_size=0.2,
random_state=42)
這會將數(shù)據(jù)集拆分為訓練集和測試集,其中 80% 的數(shù)據(jù)用于訓練,20% 的數(shù)據(jù)用于測試。
接下來,讓我們在訓練集上訓練一個邏輯回歸模型。我們將使用 來自 的類對象,它是邏輯回歸的快速簡單實現(xiàn):LogisticRegressionscikit-learn
lr_model = LogisticRegression(random_state=42)
lr_model.fit(X_train, y_train)
對象的方法進行訓練。一旦這個單元完成計算,將使用我們的數(shù)據(jù)進行訓練。fitlr_modellr_model
訓練模型后,我們可以使用以下方法評估其在測試數(shù)據(jù)上的性能:predict
Make predictions on the test data
y_pred = lr_model.predict(X_test)
Print a classification report
print(classification_report(y_test, y_pred))
這將輸出一個分類報告,其中匯總了模型的性能:
precision recall f1-score support 0.0 0.87 0.97 0.91 227 1.0 0.85 0.53 0.66 73 accuracy 0.86 300
macro avg 0.86 0.75 0.79 300
weighted avg 0.86 0.86 0.85 300
分類報告顯示,該模型在測試數(shù)據(jù)上的準確率為 0.86。對于類 0(無返回),模型的精度為 87.0,對于類 0(返回),模型的精度為 85.1。0 類模型的召回率為 97.0,0 類的召回率為 53.1。該模型的 F1 分數(shù)在 0 類為 91.0,對于 0 類為 66.1。
我們可以看到,該模型對于類 0(無返回)具有良好的精度和召回率,但對于類 1(返回)具有較低的精度和召回率。這表明該模型可能比預測將返回的訂單更能預測不會返回的訂單。盡管如此,該模型的總體準確度為 0.87,表明它可以對新數(shù)據(jù)做出相當準確的預測。
使用 dbt 模型自動執(zhí)行 ML 訓練
將模型訓練工作流存儲在 dbt 模型中,使我們能夠?qū)δP蛿?shù)據(jù)進行版本控制并與其他用戶共享。我們首先在目錄中創(chuàng)建一個新的 dbt 模型:。這是一個 Python 模型,我們將上面的筆記本代碼改編到模型定義中:modelsorder_return_prediction_models.py
import pickle
import uuid
import pandas as pd
import datetime
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report
def model(dbt, fal):
dbt.config(materialized="table")
orders_df = dbt.ref("customer_orders_labeled")
X = orders_df[['age', 'total_price']]
y = orders_df['return']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=123)
print("Model init") lr_model = LogisticRegression(random_state=123) print("Model fitting") lr_model.fit(X_train, y_train) # Test model y_pred = lr_model.predict(X_test) print("Preparing the classification report") # Create a report and put it in a DataFrame model_name = str(uuid.uuid4()) y_test = y_test.astype(float) report = classification_report(y_test, y_pred, output_dict=True) report["model_name"] = model_name report["date"] = datetime.datetime.now() output_df = pd.DataFrame([report]) output_df = output_df.rename(columns={"0.0": "target_0", "1.0": "target_1"}) output_df.set_index("model_name") print("Saving the model") # Save model weights with open(f"ml_models/{model_name}.pkl", "wb") as f: pickle.dump(lr_model, f) return output_df
該模型獲得標記的訂單數(shù)據(jù)并訓練邏輯回歸模型。然后評估模型,并將報表與唯一的模型名稱一起存儲在數(shù)據(jù)幀中。接下來,我們將模型權重保存到本地存儲。您可以修改此步驟以將模型權重存儲在云存儲平臺(例如 S3)上。最后,返回輸出數(shù)據(jù)幀,因此其內(nèi)容將保留在我們的數(shù)據(jù)倉庫中。order_return_prediction_modelslr_model
我們可以運行這個 dbt 模型:
dbt run --select order_return_prediction_models
使用存儲的模型進行預測
首先,我們嘗試在Jupyter筆記本中進行預測,然后我們創(chuàng)建一個Python模型來自動執(zhí)行此操作。
在我們的 Jupyter 筆記本中,我們可以輕松找到最準確的模型:
models_df = faldbt.ref("order_return_prediction_models")
best_model_name = models_df[
model_df.accuracy == models_df.accurary.max()
].model_name[0]
然后,我們從本地存儲(或云存儲提供商)加載此模型:
with open(f"../ml_models/{model_name}.pkl", "rb") as f:
loaded_model = pickle.load(f)
我們還加載新訂單數(shù)據(jù)并檢查其外觀:
orders_new_df = faldbt.ref("customer_orders")
orders_new_df.head()
這將打印出一個表格:
order_id customer_id total_price age
0 1037.0 981.0 193.460803 19.0
1 1027.0 940.0 680.986976 21.0
2 1039.0 123.0 952.906524 22.0
3 1043.0 860.0 545.791012 22.0
4 1046.0 316.0 887.003551 24.0
如我們所見,此數(shù)據(jù)幀的形狀與 不同 缺少列。這是我們想要預測的列。customer_orders_labeledreturn
所以,讓我們做一個預測:
predictions = loaded_model.predict(orders_new_df[["age", "total_price"]])
orders_new_df["predicted_return"] = predictions
order_new_df.head()
在上面的代碼片段中,我們首先執(zhí)行預測,然后將生成的預測附加到數(shù)據(jù)幀。這是 of 應該的樣子:orders_new_dfheadorders_new_df
order_id customer_id total_price age predicted_return
0 1037.0 981.0 193.460803 19.0 0.0
1 1027.0 940.0 680.986976 21.0 1.0
2 1039.0 123.0 952.906524 22.0 1.0
3 1043.0 860.0 545.791012 22.0 1.0
4 1046.0 316.0 887.003551 24.0 1.0
讓我們繪制我們的預測,看看它們是否有意義:
plot_data = orders_new_df.sample(frac=0.5, random_state=123)
colors = ['red' if r else 'blue' for r in plot_data['predicted_return']]
plt.scatter(plot_data['age'], plot_data['total_price'], c=colors)
plt.xlabel('Age')
plt.ylabel('Total Price')
plt.show()
這是結果圖:

退貨(紅色)和未退貨(藍色)訂單的年齡和價格分布
如果這些值對我們來說看起來不錯,我們可以創(chuàng)建另一個 dbt Python 模型來自動運行這些預測。這個新的dbt模型將首先選擇最佳的邏輯回歸模型,使用它來預測訂單是否會被退回,最后將其預測存儲在我們的數(shù)據(jù)倉庫中。predicted_return
以下是我們新模型的定義:order_return_predictions.py
import pickle
def model(dbt, fal):
dbt.config(materialized="table")
models_df = dbt.ref("order_return_prediction_models")
best_model_name = models_df[
models_df.accuracy == models_df.accuracy.max()].model_name[0]
with open(f"ml_models/{best_model_name}.pkl", "rb") as f:
loaded_model = pickle.load(f)
orders_new_df = dbt.ref("customer_orders")
predictions = loaded_model.predict(orders_new_df[["age", "total_price"]])
orders_new_df["predicted_return"] = predictions
return orders_new_df
我們可以運行這個 dbt 模型:
dbt run --select order_return_predictions
結論
在這篇博文中,我們介紹了如何使用 fal 和 dbt 以可擴展和可重現(xiàn)的方式管理和部署機器學習模型。我們使用合成購物數(shù)據(jù)集來訓練一個邏輯回歸模型,該模型可以預測訂單被退回的概率。我們在 dbt 模型中自動化了 ML 訓練過程,并使用生成的 ML 模型對新數(shù)據(jù)進行預測。最后,我們能夠?qū)⒔Y果預測存儲在新的dbt模型中。所有這些現(xiàn)在都可以自動運行。