天天看點

【譯】如何用Apache Spark和LightGBM建構機器學習模型來預測信用卡欺詐如何用Apache Spark和LightGBM建構機器學習模型來預測信用卡欺詐

如何用Apache Spark和LightGBM建構機器學習模型來預測信用卡欺詐

原文連結 

https://towardsdatascience.com/how-to-perform-credit-card-fraud-detection-at-large-scale-with-apache-spark-and-lightgbm-61a982de8672

編譯:撫月,阿裡巴巴計算平台事業部 EMR 進階工程師,Apache HDFS Committer,目前從事開源大資料存儲和優化方面的工作。

任何一家發行信用卡的金融機構,都要做防欺詐檢測。他們平台上每天不斷的成千上萬的交易記錄,他們用這些大規模的資料集來做檢測。雖然在個人電腦上,在Jupyter notebook上面對小量的靜态資料集做機器學習的模型訓練,相對比較簡單。 但是在金融機構的真實環境下,大量的交易資料存放在Hadoop或者資料湖裡,這時部署機器學習模型就存在巨大挑戰。這篇文章,我将向你們展示如何在Apache Spark環境下,利用LightGBM來建構和訓練模型。 LightGBM被認為是Gradient Boosting算法的高效實作,在資料科學領域被廣泛使用。

Apache Spark是一個in-memory的叢集化的運作環境,用來存儲和處理資料,比起從(單機)SSD或磁盤通路資料會快上千倍。假設資料集存在于Hadoop,S3,資料庫或本地檔案,第一步需要讓Spark叢集可以通路這些資料(将資料轉為Spark dataframe)。在這個例子中,我将Machine Learning Group of ULB的資料,以CSV格式加載到Spark dataframe中。 Spark叢集是6gb記憶體,部署了Databricks社群版。下面是用Spark加載資料的代碼:

# File location and type
file_location = "/FileStore/tables/creditcard.csv"
file_type = "csv"

# CSV options
infer_schema = "true"
first_row_is_header = "true"
delimiter = ","

df = spark.read.format(file_type) \
  .option("inferSchema", infer_schema) \
  .option("header", first_row_is_header) \
  .option("sep", delimiter) \
  .load(file_location)           

資料集包含了300,000條記錄,31個變量,是關于歐洲信用卡持有者的交易記錄。其中28個變量是數值型,是對一些未披露的原始參數進行主成分分析(PCA)得到的。剩下的3個變量是交易數量,交易時間(秒,相對于第一次交易),交易标簽(表示是否真實或詐騙)。雖然資料集比較小,但是我們選擇了Apache Spark來做訓練,是以相同的代碼同樣适用于大規模的資料集。

資料集中,标記為真實的資料, 和标記為詐騙的資料相比,數量嚴重不平衡。其中隻有492個樣本是跟标記為詐騙的交易有關,比起整個資料集來說量很小。你可以

通路這個資料集

下一步,是從dataframe中,選擇我們想要作為輸入變量和目标變量的列。當建構生産級的ML模型時,比較好的做法是做一些資料變換,比如用LabelEncoder或者OneHotEncoder的方式,将類目列轉為數值列,作為整個pipeline當中的幾個stage。這個pipeline可以用來變換訓練、驗證、或者測試資料,而不會将測試用例暴露給訓練資料(當我們做standardized scaling的時候)。而且代碼也好維護。可以參考

Spark的pipeline接口文檔
feature_cols = ["V" + str(i) for i in range(1,29)] + ["Amount"]
assembler = VectorAssembler(inputCols=feature_cols, outputCol="features")
stages = [assembler]           

下一步,我們添加一個LightGBMClassifier執行個體到pipeline。LightGBMClassifier這個類包含在MMLSpark庫中,是由Microsoft Azure團隊維護的一個庫。

按照這個步驟

,可以将其添加到叢集中。我通過maven依賴引入了mmlspark這個包,使用版本0.17。然後,可以通過Python import LightGBMClassifier。

使用LightGBM的時候,對超參數(hyperparameters)進行調優非常重要,比如葉子數量、最大深度、疊代次數等。對相同資料訓練出來的模型,性能差異可能會因為超參數的值的不同而非常大。

通常,這需要進行一個交叉驗證明驗,用一些超參數值空間搜尋政策,比如全網格搜尋、随機搜尋、貝葉斯優化,或者樹狀結構Parzen估計方法(TPE)來找到超參數的最優值,進而使得驗證資料集上模型的性能最大化。通過最小化一些預定義的錯誤量,比如二進制錯誤;或者最大化一些分數,比如ROC曲線下的面積或者F1分數。

根據我們想搜尋的參數值空間的大小,以及我們期望得到的模型的性能的不同,這些搜尋可能會跑很長時間。在這種情況下,我決定調優7個LightGBM模型的超參數。大多數參數是實值,意味着搜尋的參數空間是非常深的。

我用了Kaggle執行環境裡面的Hyperopt庫。為了在有限的時間内搜尋超參數空間,評估不同的超參數值的組合,我使用了一些優化政策來找到超參數的近乎最優值,隻用了較少的幾個評估回合。我用樹狀結構Parzen估計方法,在200次的超參數組合的評估之後, 我找到了超參數的最優值。

notebook裡面

,是我在Spark裡訓練這個模型時,用來确定超參數的代碼。

我用Databricks的社群版,花了2個小時。如果你可以有更多的時間通路Spark叢集,你也可以用Spark裡面的ParamGridBuilder和CrossValidator這2個類來搜尋和評估超參數值。下面是執行個體代碼。

下面,是我在Kaggle的python環境中進行模型調優,得到的大多數最優超參數值,以及Spark例子中的lambda L2正則化參數。注意,我設定了LightGBMClassifier的一個值isUnbalance=True,進而可以處理之前提到的資料集不平衡的問題。

best_params = {        
    'bagging_fraction': 0.8,
         'bagging_freq': 1,
         'eval_metric': 'binary_error',
         'feature_fraction': 0.944714847210862,
    'lambda_l1': 1.0,
         'lambda_l2': 45.0,
         'learning_rate': 0.1,
         'loss_function': 'binary_error',
         'max_bin': 60,
         'max_depth': 58,
         'metric': 'binary_error',
         'num_iterations': 379,
         'num_leaves': 850,
    'objective': 'binary',
         'random_state': 7,
         'verbose': None
}
lgb = LightGBMClassifier(
     learningRate=0.1,
     earlyStoppingRound=100,
           featuresCol='features',
        labelCol='label',
        isUnbalance=True,
      baggingFraction=best_params["bagging_fraction"],
    baggingFreq=1,
    featureFraction=best_params["feature_fraction"],
    lambdaL1=best_params["lambda_l1"],
    # lambdaL2=best_params["lambda_l2"],
    maxBin=best_params["max_bin"],
    maxDepth=best_params["max_depth"],
    numIterations=best_params["num_iterations"],
    numLeaves=best_params["num_leaves"],
    objective="binary",
    baggingSeed=7                  
)
paramGrid = ParamGridBuilder().addGrid(
  lgb.lambdaL2, list(np.arange(1.0, 101.0, 10.0))
).build()
evaluator = BinaryClassificationEvaluator(labelCol="label",metricName="areaUnderROC")
crossValidator = CrossValidator(estimator=lgb,
                          estimatorParamMaps=paramGrid, 
                          evaluator=evaluator, 
                          numFolds=2)   
stages += [crossValidator]
pipelineModel = Pipeline(stages=stages)           

下一步是将資料集分為訓練集和測試集。我們會用訓練集去拟合我們剛才建立的pipeline(調用Spark pipeline的fit方法),其中包含了特征裝配和模型訓練。然後我們用這個pipeline去變換測試集,來生成預測結果。

train, test = df.randomSplit([0.8, 0.2], seed=7)
model = pipelineModel.fit(train)
preds = model.transform(test)           

一旦我們從測試資料集拿到預測結果,我們可以用它們衡量我們模型的性能。Spark提供了BinaryClassificationEvaluator,可以用來計算ROC曲線的面積。

為了計算其它相關的名額,比如精度、召回、F1分數,我們可以利用測試集的預測标簽和實際标簽。

binaryEvaluator = BinaryClassificationEvaluator(labelCol="label")
print ("Test Area Under ROC: " + str(binaryEvaluator.evaluate(preds, {binaryEvaluator.metricName: "areaUnderROC"})))
#True positives
tp = preds[(preds.label == 1) & (preds.prediction == 1)].count() 
#True negatives
tn = preds[(preds.label == 0) & (preds.prediction == 0)].count()
#False positives
fp = preds[(preds.label == 0) & (preds.prediction == 1)].count()
#Falsel negatives
fn = preds[(preds.label == 1) & (preds.prediction == 0)].count()
print ("True Positives:", tp)
print ("True Negatives:", tn)
print ("False Positives:", fp)
print ("False Negatives:", fn)
print ("Total", preds.count())  
r = float(tp)/(tp + fn)  
print ("recall", r)  
p = float(tp) / (tp + fp)
print ("precision", p)
f1 = 2 * p * r /(p + r)  
print ("f1", f1)           

在這個例子裡,AUC-ROC分數是0.93, F1分數是0.70. 在Kaggle notebook裡,在訓練之前,我還用了

SMOTE

來平衡資料集,結果AUC-ROC分數是0.98, F1分數是0.80。我對超參數值的組合做了200次的評估。如果我們想進一步提高模型的性能,那麼下一步顯然是在Spark裡改進SMOTE,在拟合流水線之前先平衡一下訓練集。我們還可以更深入地搜尋超參數空間,通過執行更多次的超參數值組合的評估的方式。

除了在Spark上訓練一個高性能的LightGBM模型,資料科學家遇到的另一個巨大挑戰是管理這樣一個生命周期----準備資料、選擇模型、訓練、調優、儲存最優參數值、部署訓練好的模型、通過API通路輸出的預測值。

MLFlow

是一個開源的解決方案,可以解決這些問題。我建議感興趣的讀者去學習它。我可以寫一篇關于如何如何将它整合進工作流裡面。就像我上面展示的那樣。

你可以參考上面的那些步驟,我放在了

Github repo

上。這是另一個

notebook

我用來進行參數調優實驗。

我希望這篇文章對你開始在Apache Spark上用LightGBMClassifier實作機器學習算法帶來幫助。如果在嘗試過程中遇到什麼問題,歡迎在評論區提問。