簡體   English   中英

Keras 和 Scikit-learn 的加權精度度量之間的差異

[英]Difference between weighted accuracy metric of Keras and Scikit-learn

介紹

大家嘿嘿

我正在寫我的畢業論文,我面臨一個類別貢獻不平衡的二元分類問題。 我的負面(“0”)標簽大約是正面(“1”)標簽的 10 倍。 出於這個原因,我不僅考慮了觀察精度和 ROC-AUC,還考慮了加權/平衡精度和 Precision-Recall-AUC。

我已經在 GitHub ( https://github.com/keras-team/keras/issues/12991 ) 上問過這個問題,但問題還沒有得到解答,所以我認為這里的這個平台可能是更好的地方!

問題描述

在自定義回調中對驗證集進行一些計算時,我或多或少偶然地注意到,加權精度總是我使用sklearn.metrics.accuracy_score() 的結果不同

使用 Keras,加權精度必須在model.compile() 中聲明,並且是每個 epoch 之后 logs{} 字典中的一個鍵(並且還通過 CSVLogger 回調寫入日志文件或歷史對象)或返回作為model.evaluate()列表中的值,

model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'], 
              weighted_metrics=['accuracy'])

我使用 Sklearn.metrics 函數class_weight.compute_sample_weight()並在class_weight.compute_class_weight()的幫助下,根據訓練集的類別貢獻計算 val_sample_weights 向量。

cls_weights = class_weight.compute_class_weight('balanced', np.unique(y_train._values), 
                                                y_train._values)
cls_weight_dict = {0: cls_weights[0], 1: cls_weights[1]}
val_sample_weights = class_weight.compute_sample_weight(cls_weight_dict, y_test._values)

model.fit() 中,我將這個向量與驗證數據一起傳遞給sklearn.metrics.accuracy_score()我將它傳遞給參數名稱sample_weight以在相同的基礎上比較結果。

model_output = model.fit(x_train, y_train, epochs=500, batch_size=32, verbose=1,
                         validation_data=(x_test, y_test, val_sample_weights))

此外,我從幾個簡單的例子中推導出了 Scitkit-learn 如何計算加權准確度的方程,它似乎是通過以下方程計算的(這對我來說似乎很合理):

乳膠方程

TP、TN、FP 和 FN 是混淆矩陣中報告的值,w_p 和 w_n 分別是正類和負類的類權重。

可以在此處找到一個簡單的測試示例:

https://scikit-learn.org/stable/modules/generated/sklearn.metrics.balanced_accuracy_score.html

只是為了完整性, sklearn.metrics.accuracy_score(..., sample_weight=)返回與sklearn.metrics.balanced_accuracy_score()相同的結果。

系統信息

  • GeForce RTX 2080 Ti
  • 凱拉斯 2.2.4
  • Tensorflow-GPU 1.13.1
  • sklearn 0.19.2
  • 蟒蛇 3.6.8
  • CUDA 版本 10.0.130

代碼示例

我搜索了一個簡單的例子來使問題易於重現,即使這里的類不平衡較弱(1:2 不是 1:10)。 它基於 Keras 的介紹性教程,可在此處找到:

https://towardsdatascience.com/k-as-in-keras-simple-classification-model-a9d2d23d5b5a

皮馬印第安納州發病糖尿病數據集將按照上面的鏈接從主頁 Machine Learning Mastery 的創建者 Jason Brownlee 的存儲庫中下載。 但我想它也可以從其他各種網站下載。

所以最后這里的代碼:

from keras.layers import Dense, Dropout
from keras.models import Sequential
from keras.regularizers import l2
import pandas as pd
import numpy as np
from sklearn.utils import class_weight
from sklearn.metrics import accuracy_score
from sklearn.model_selection import train_test_split

file = 'https://raw.githubusercontent.com/jbrownlee/Datasets/master/' \
       'pima-indians-diabetes.data.csv'

# Load csv data from file to data using pandas
data = pd.read_csv(file, names=['pregnancies', 'glucose', 'diastolic', 'triceps', 'insulin',
                                'bmi', 'dpf', 'age', 'diabetes'])

# Process data
data.head()
x = data.drop(columns=['diabetes'])
y = data['diabetes']

# Split into train and test
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.1, random_state=0)

# define a sequential model
model = Sequential()
# 1st hidden layer
model.add(Dense(100, activation='relu', input_dim=8, kernel_regularizer=l2(0.01)))
model.add(Dropout(0.3))
# 2nd hidden layer
model.add(Dense(100, activation='relu', kernel_regularizer=l2(0.01)))
model.add(Dropout(0.3))
# Output layer
model.add(Dense(1, activation='sigmoid'))
# Compilation with weighted metrics
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'], 
                         weighted_metrics=['accuracy'])

# Calculate validation _sample_weights_ based on the class distribution of train labels and 
# apply it to test labels using Sklearn
cls_weights = class_weight.compute_class_weight('balanced', np.unique(y_train._values), 
                                                y_train._values)
cls_weight_dict = {0: cls_weights[0], 1: cls_weights[1]}
val_sample_weights = class_weight.compute_sample_weight(cls_weight_dict, y_test._values)

# Train model
model_output = model.fit(x_train, y_train, epochs=500, batch_size=32, verbose=1,
                         validation_data=(x_test, y_test, val_sample_weights))

# Predict model
y_pred = model.predict(x_test, batch_size=32, verbose=1)

# Classify predictions based on threshold at 0.5
y_pred_binary = (y_pred > 0.5) * 1

# Sklearn metrics
sklearn_accuracy = accuracy_score(y_test, y_pred_binary)
sklearn_weighted_accuracy = accuracy_score(y_test, y_pred_binary, 
                                           sample_weight=val_sample_weights)

# metric_list has 3 entries: [0] val_loss weighted by val_sample_weights, [1] val_accuracy 
# [2] val_weighted_accuracy
metric_list = model.evaluate(x_test, y_test, batch_size=32, verbose=1, 
                             sample_weight=val_sample_weights)

print('sklearn_accuracy=%.3f' %sklearn_accuracy)
print('sklearn_weighted_accuracy=%.3f' %sklearn_weighted_accuracy)
print('keras_evaluate_accuracy=%.3f' %metric_list[1])
print('keras_evaluate_weighted_accuracy=%.3f' %metric_list[2])

結果和總結

例如我得到:

sklearn_accuracy=0.792

sklearn_weighted_accuracy=0.718

keras_evaluate_accuracy=0.792

keras_evaluate_weighted_accuracy=0.712

“未加權”的准確度值是相同的,對於 Sklearn 和 Keras 都是一樣的。 差異並不是很大,但隨着數據集變得更加不平衡,差異會變得更大。 例如,對於我的任務,它總是彼此相差 5% 左右!

也許我遺漏了一些東西,它應該是這樣的,但無論如何,Keras 和 Sklearn 提供不同的值令人困惑,尤其是將整個 class_weights 和 sample_weights 視為一個難以進入的話題。 不幸的是,我對 Keras 不太深入,無法自己搜索 Keras 代碼。

我真的很感激收到任何答案!

我重復了您的確切玩具示例,實際上發現sklearnkeras確實給出了相同的結果。 我重復了 5 次實驗,以確保它不是偶然的,而且每次的結果都是相同的。 例如,對於其中一次運行:

sklearn_accuracy=0.831
sklearn_weighted_accuracy=0.800
keras_evaluate_accuracy=0.831
keras_evaluate_weighted_accuracy=0.800

僅供參考,我正在使用sklearnkeras版本:

0.20.3
2.3.1

分別。 請參閱此 google colab 示例: https ://colab.research.google.com/drive/1b5pqbp9TXfKiY0ucEIngvz6_Tc4mo_QX

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM