sklearn.datasets.make_classification 无法生成平衡类

Posted

技术标签:

【中文标题】sklearn.datasets.make_classification 无法生成平衡类【英文标题】:sklearn.datasets.make_classification fails to generate balanced classes 【发布时间】:2019-02-14 16:45:00 【问题描述】:

我正在尝试使用 sklearn 库中的make_classification 为分类任务生成数据,并且我希望每个类恰好有 4 个样本。

如果类数小于19,则行为正常。

from sklearn.datasets import make_blobs, make_classification
import numpy as np
data = make_classification(n_samples=76, n_features=5, n_informative=5, n_redundant=0, n_repeated=0, 
                           n_classes=19, n_clusters_per_class=1, weights=None, flip_y=0, class_sep=1.0, 
                           shuffle=False, random_state=101)
print(data[1])
[ 0  0  0  0  1  1  1  1  2  2  2  2  3  3  3  3  4  4  4  4  5  5  5  5
  6  6  6  6  7  7  7  7  8  8  8  8  9  9  9  9 10 10 10 10 11 11 11 11
 12 12 12 12 13 13 13 13 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17 17
 18 18 18 18]

但是,如果类的数量等于或大于 20,则第一类有 5 个样本,最后一个类只有 3 个样本,这是不平衡的。

data = make_classification(n_samples=80, n_features=5, n_informative=5, n_redundant=0, n_repeated=0, 
                           n_classes=20, n_clusters_per_class=1, weights=None, flip_y=0, class_sep=1.0, 
                           shuffle=False, random_state=101)
print(data[1])
[ 0  0  0  0  0  1  1  1  1  2  2  2  2  3  3  3  3  4  4  4  4  5  5  5
  5  6  6  6  6  7  7  7  7  8  8  8  8  9  9  9  9 10 10 10 10 11 11 11
 11 12 12 12 12 13 13 13 13 14 14 14 14 15 15 15 15 16 16 16 16 17 17 17
 17 18 18 18 18 19 19 19]

查看文档时,发现weight参数在控制classes的比例:

weights:浮点数列表或无(默认=无)

分配给每个类别的样本比例。如果没有,那么 班级是平衡的。请注意,如果 len(weights) == n_classes - 1,则 最后一个类的权重是自动推断的。超过 n_samples 如果权重之和超过 1,则可能返回样本。

因此,我尝试使用以下代码明确输入比例。

data = make_classification(n_samples=80, n_features=5, n_informative=5, n_redundant=0, n_repeated=0, 
                           n_classes=20, n_clusters_per_class=1, weights=list(np.ones(20)), flip_y=0, class_sep=1.0, 
                           shuffle=False, random_state=101)
print(data[1])
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0]

然而,生成的类是完全错误的。

我不确定为什么这个函数会这样。当n_classes大于等于20时,如何保证类均衡?

【问题讨论】:

【参考方案1】:

虽然没有明确提及并且令人困惑,但参数weights 需要样本的“比例”。它不会自动将数字转换为比例。

因此,如果样本总数 = 80,并且您想将 40 个样本分配给第 1 类,则比例变为0.5

但是,您提供的比例为:

[1.0, 1.0, 1.0, 1.0,.................., 1.0, 1.0, 1.0, 1.0]

这就是错误的来源。该方法采用 1.0 作为头等舱(在您的情况下为 0)并忽略所有其他。

这样做:

n_classes = 20
weights=list(np.ones(20)/n_classes)  <== Making proportions correct

data = make_classification(n_samples=80, n_features=5, n_informative=5, n_redundant=0, n_repeated=0, 
                           n_classes=n_classes, n_clusters_per_class=1, weights=weights, flip_y=0, class_sep=1.0, 
                           shuffle=False, random_state=101)

正确返回:

array([ 0,  0,  0,  0,  1,  1,  1,  1,  2,  2,  2,  2,  3,  3,  3,  3,  4,
        4,  4,  4,  5,  5,  5,  5,  6,  6,  6,  6,  7,  7,  7,  7,  8,  8,
        8,  8,  9,  9,  9,  9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12,
       12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16,
       17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19])

最后一行:

如果权重之和超过 1,则可能返回超过 n_samples 个样本。

似乎增加了混乱。

当您将1.0 作为所有类的比例传递时,它应该返回 80*20 = 1600 个样本,每个类 80 个。

但它没有这样做。它在内部正确生成样本,但随后只返回前 80 个样本(由n_samples 参数定义)。这就是为什么您只能在生成的数据中返回一个类 (0)。您应该将此作为问题发布在他们的 github 页面上:https://github.com/scikit-learn/scikit-learn/issues

【讨论】:

以上是关于sklearn.datasets.make_classification 无法生成平衡类的主要内容,如果未能解决你的问题,请参考以下文章