Sklearn.datasets.make_classification не может создать сбалансированные классы

Я пытаюсь использовать make_classification из библиотеки sklearn для генерации данных для задач классификации, и я хочу, чтобы у каждого класса было ровно 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 : list of floats or None (default=None)

The proportions of samples assigned to each class. If None, then classes are balanced. Note that if len(weights) == n_classes - 1, then the last class weight is automatically inferred. More than n_samples samples may be returned if the sum of weights exceeds 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?

0
0
892
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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])

Последняя строка:

More than n_samples samples may be returned if the sum of weights exceeds 1.

кажется, добавляет путаницы.

Когда вы передаете 1.0 в качестве пропорций для всех классов, тогда он должен вернуть 80 * 20 = 1600 выборок, по 80 для каждого класса.

Но этого не происходит. Он правильно генерирует сэмплы внутри, но затем возвращает только первые 80 сэмплов (как определено параметром n_samples). Вот почему вы получаете только один класс (0) в сгенерированных данных. Вы должны опубликовать это как проблему на их странице в github: https://github.com/scikit-learn/scikit-learn/issues

Другие вопросы по теме