关于机器学习:使用分类权重解决数据不平衡的问题

1次阅读

共计 3544 个字符,预计需要花费 9 分钟才能阅读完成。

在分类工作中,不均衡数据集是指数据集中的分类不均匀的状况,会有一个或多个类比其余类多的多或者少的多。

在咱们的日常生活中,不均衡的数据是十分常见的比方本篇文章将应用一个最常见的例子,信用卡欺诈检测来介绍,在咱们的日常应用中欺诈的数量要远比失常应用的数量少很多,对于咱们来说这就是数据不均衡的问题。

咱们应用 kaggle 上的信用卡交易数据集作为本文的数据集。数据的细节不是特地重要。因为为了进行脱敏,这个数据集的特色是通过 PCA 降维后输入的,所以探讨这些特色代表什么没有任何意义。除了 PCA 输入的特色以外,这个数据集还包含与每笔交易相干的美元金额、以秒为单位的间断工夫索引,以及一个示意存在或不存在欺诈的二进制指标。对于工夫索引,咱们思考到某些特色工程,它可能会很有用,但这不是本文的重点。对于咱们实在可见的数据只有金额一项,这个很重要!

咱们再看看指标,在 284,807 行数据中只有 0.173% 的行是欺诈案例,这相对是不均衡数据的样例,这种数据的散布会使建模和预测欺诈行为变得有十分的辣手。

性能指标

在不均衡数据时,能够应用几个有价值的性能指标来理解模型的性能。通常状况下,指标的抉择很大水平上取决于利用以及与正负相干的后果。独自的一种办法不能实用于所有人。

在信用卡欺诈的背景下,咱们不会对产生高准确度分数的模型感兴趣。因为数据集十分不均衡欺诈的数据很少,如果咱们将所有样本分类为不存在欺诈,那么准确率还是很高。然而咱们对精确预测信用卡交易何时不存在欺诈不感兴趣,咱们关怀的是信用卡是否存在欺诈,也就是样本量少的分类是否可能被判断进去。

最简略的方法就是召回分数作为模型性能的次要指标。召回是掂量有多少侧面案例被模型精确预测的指标。在咱们的特定用例中,更高的召回分数意味着咱们检测到更多的欺诈案例。

在本文中,咱们除了应用召回以外还将分类与最初的财务指标相结合,还记得咱们后面提到的数据集的蕴含交易的美元金额吗? 咱们也将把它纳入绩效评估,称之为“财务召回”。咱们将在上面具体介绍。

数据筹备

首先,让咱们读入数据,并将其分成训练集和测试集:

import pandas as pd
from sklearn.model_selection import train_test_split

df = pd.read_csv('creditcard.csv')

# enumerate the feature columns
feats = [col for col in df.columns if 'V' in col]

# Split data
x = df[feats + ['Amount']]
y = df['Class']

X_train, X_test, y_train, y_test = train_test_split(
    x, y,
    test_size=.2,
    stratify=y,
    random_state=41)

如果以前没有在 train_test_split 中应用过 stratify 参数,那么在解决不均衡数据时应该应用该参数,train_test_split 宰割后欺诈案例的比例会依据传递列的比例进行调配(具体应用办法能够查看 sklearn 的文档),咱们的指标是为了确保咱们在训练集和测试集中放弃雷同比例类别散布。

基类模型

咱们将创立并训练一个根本的逻辑回归模型作为基线。但在此之前咱们先创立一个小函数,将每笔交易的金额纳入性能评估。

因为关怀的是可能正确分类的欺诈案件的数量,并且咱们也关怀 (可能更关怀) 将欺诈损失的美元放弃在最低限度。这就是咱们之前探讨的“财务召回”。让咱们创立一个函数来计算正确辨认的欺诈金额:

from sklearn.metrics import recall_score

def assess_test_set_performance(model):
    # create predictions
    yhat = model.predict(X_test[feats])
    # evaluate performance using counts
    model_recall = recall_score(y_test, yhat)*100
    print("Classification Test Performance:")
    print(f"Recall: {model_recall:.2f}%")
    
    # calculate financial performance using the dollar amount associated with each transaction
    performance_df = pd.DataFrame({'Amount':X_test['Amount'], 'Actual':y_test, 'Pred':yhat})
    performance_df['fraud_amount'] = performance_df['Amount']*performance_df['Actual']
    performance_df['fraud_prevented'] = performance_df['fraud_amount']*performance_df['Pred']
    performance_df['fraud_realized'] = performance_df['fraud_amount'] - performance_df['fraud_prevented']
    
    financial_recall = (performance_df['fraud_prevented'].sum() / (performance_df['fraud_prevented'].sum() + performance_df['fraud_realized'].sum()))*100

    print()
    print("Financial Test Performance:")
    print(f"Financial Recall: {financial_recall:.2f}%")

当初咱们曾经确定了评估函数,让咱们训练基线模型并评估它的性能:

from sklearn.linear_model import LogisticRegression

baseline_model = LogisticRegression()
baseline_model.fit(X_train[feats], y_train)

assess_test_set_performance(baseline_model)

咱们的基线模型实现了 59% 的召回和 61% 的财务召回,这实际上比预期的要好。然而这在理论应用时必定不好,所以其实咱们能够做的更好。

改良模型退出类权重

基线模型将两个类设置成等同重要,因为模型不晓得咱们更关怀欺诈的状况,所以咱们须要从新定义咱们的损失函数。sklearn API 提供了让模型晓得对正确辨认欺诈的偏好:class_weight 参数。

当应用 class_weight 时,模型接管一个字典,每个类都有一个键,其中的值是该类的权重。咱们有两类,为了阐明这个例子,咱们假如欺诈案的重要性是前者的 10 倍。在这种状况下,咱们能够像这样向 class_weight 传递一个字典:

fraud_class_weights = {0:1, 1:10}

然而 sklearn API 实际上使这个过程更容易。class_weight 参数也能够取 ’balanced’ 的值。咱们须要做的是应用上面的公式建设一个字典,其中权重与数据中的类散布成比例:

len(X_train) / (2 * numpy.bincount(y_train))

将下面的公式利用到咱们的数据中,咱们预计正状况实际上比负状况重要 575 倍。

当咱们把这个新的代码放到逻辑回归模型中时,它将更专一于正确地对咱们的欺诈交易进行分类。这正是咱们想要的后果!

让咱们设置它,而后钻研性能:

lr_class_weights = LogisticRegression(class_weight='balanced')
lr_class_weights.fit(X_train[feats], y_train)

assess_test_set_performance(lr_class_weights)

这个简略的扭转将使咱们的召回率进步到 90% 和 93% ! 因为当初对欺诈更加敏感,比应用基线模型精确地辨认更多的欺诈案例。

总结

在模型中应用 class_weight 必定会帮忙从模型中取得更多相干的性能。并且它很容易设置,至多值得试一试。本文中介绍的办法是解决分类不均衡问题的一种过简略的办法,在这个畛域中还有许多其余的办法能够探讨,然而为分类设置权重是一个十分好的开始。

https://avoid.overfit.cn/post/13e8cb84f1e1480eb62d9f029647ed3a

作者;Greg J

正文完
 0