向上采样不平衡数据集的次要类

时间:2018-11-09 00:55:51

标签: python machine-learning scikit-learn

我正在使用scikit-learn对数据进行分类,此刻我正在运行一个简单的DecisionTree分类器。 我上三堂课,有一个很大的失衡问题。这些类是0,1和2。次要类是1和2。

让您对这些类的样本数有所了解:

0 = 25.000 samples
1 = 15/20 less or more
2 = 15/20 less or more

因此次要类别约占数据集的0.06%。 我遵循的解决不平衡问题的方法是小类的UPSAMPLING。代码:

from sklearn.utils import resample,
resample(data, replace=True, n_samples=len_major_class, random_state=1234)

现在是问题所在。我做了两个测试:

  1. 如果我对次要类进行上采样,然后将我的数据集分为两组进行训练,一组进行测试...则准确性为:
             precision    recall  f1-score   support

          0       1.00      1.00      1.00     20570
          1       1.00      1.00      1.00     20533
          2       1.00      1.00      1.00     20439

avg / total       1.00      1.00      1.00     61542

非常好结果

  1. 如果我仅对培训数据进行上采样,并将原始数据留待测试,则结果为:
             precision    recall  f1-score   support

          0       1.00      1.00      1.00     20570
          1       0.00      0.00      0.00        15
          2       0.00      0.00      0.00        16

avg / total       1.00      1.00      1.00     20601

您可以看到全局精度很高,但是1级和2级的精度为

我以这种方式创建分类器:

DecisionTreeClassifier(max_depth=20, max_features=0.4, random_state=1234, criterion='entropy')

我还尝试添加具有 balanced 值的class_weight,但这没什么区别。

我应该只对训练数据进行升采样,为什么会出现这个奇怪的问题?

3 个答案:

答案 0 :(得分:6)

在拆分之前进行重新采样时,您获得该行为的事实很正常;您会在数据中引起偏差。

如果对数据进行过采样然后分解,则测试中的少数样本将不再独立于训练集中的样本,因为它们是一起生成的。对于您而言,它们是训练集中样本的精确副本。您的准确性为100%,因为分类器正在对训练中已经看到的样本进行分类。

由于您的问题严重失衡,因此我建议使用分类器的组合来处理它。 1)将数据集分为训练集和测试集。给定数据集的大小,您可以从少数派样本中抽取1-2个样本进行测试,而将另一个样本留作训练。 2)从训练中,您生成N个数据集,其中包含少数群体类别的所有剩余样本和多数群体类别的欠样本(我说2 *少数群体样本的数量)。 3)对于获得的每个数据集,您都要训练一个模型。 4)使用测试集获得预测;最终预测将是分类器所有预测的多数表决结果。

要拥有可靠的指标,请使用不同的初始拆分测试/培训执行不同的迭代。

答案 1 :(得分:1)

不应在上采样后拆分数据集。您可以在训练数据中进行升采样。

基本上,您是将测试数据泄漏到训练数据中。

答案 2 :(得分:0)

我有一个函数可以对每个类的数据集重新采样以具有相同数量的实例。

from sklearn.utils import resample
import pandas as pd

def make_resample(_df, column):

  dfs_r = {}
  dfs_c = {}
  bigger = 0
  ignore = ""
  for c in _df[column].unique():
    dfs_c[c] = _df[df[column] == c]
    if dfs_c[c].shape[0] > bigger:
      bigger = dfs_c[c].shape[0]
      ignore = c

  for c in dfs_c:
    if c == ignore:
      continue
    dfs_r[c] = resample(dfs_c[c], 
                        replace=True,
                        n_samples=bigger - dfs_c[c].shape[0],
                        random_state=0)
  return pd.concat([dfs_r[c] for c in dfs_r] + [_df])