образец X примеров из каждой метки класса

У меня есть набор данных (вектор numpy) с 50 classes и 9000 обучающих примеров.

x_train=(9000,2048)
y_train=(9000,)  # Classes are strings 
classes=list(set(y_train))

Я хотел бы создать поднабор данных таким образом, чтобы каждый класс имел 5 примеров.

что означает, что я получаю 5*50=250 обучающих примера. Следовательно, мой поднабор данных будет иметь следующую форму:

sub_train_data=(250,2048)
sub_train_labels=(250,)

Примечание: мы берем случайным образом по 5 примеров из каждого класса (общее количество классов = 50)

Спасибо


person Joseph    schedule 24.01.2018    source источник
comment
Звучит неплохо. Что удерживает вас от этого?   -  person kazemakase    schedule 24.01.2018
comment
Я хочу знать, как это сделать, чтобы получить оценку того, сколько примеров необходимо для получения максимальной точности. Я хотел бы начать с 5 примеров для каждого класса, затем 10, 20, 40, 80, 160,320... и построить график точности. Как только точность останется прежней, я прекращу маркировку данных.   -  person Joseph    schedule 24.01.2018
comment
любой ide @kazemakase ?   -  person Joseph    schedule 24.01.2018
comment
Нет, потому что я понятия не имею, в чем проблема. Вы еще ничего не пробовали? Где ты застрял? В чем собственно вопрос?   -  person kazemakase    schedule 24.01.2018
comment
@kazemakase, вот ответ на вопрос   -  person Joseph    schedule 24.01.2018


Ответы (3)


Вот решение этой проблемы:

from collections import Counter
import numpy as np
import matplotlib.pyplot as plt

def balanced_sample_maker(X, y, sample_size, random_seed=42):
    uniq_levels = np.unique(y)
    uniq_counts = {level: sum(y == level) for level in uniq_levels}

    if not random_seed is None:
        np.random.seed(random_seed)

    # find observation index of each class levels
    groupby_levels = {}
    for ii, level in enumerate(uniq_levels):
        obs_idx = [idx for idx, val in enumerate(y) if val == level]
        groupby_levels[level] = obs_idx
    # oversampling on observations of each label
    balanced_copy_idx = []
    for gb_level, gb_idx in groupby_levels.items():
        over_sample_idx = np.random.choice(gb_idx, size=sample_size, replace=True).tolist()
        balanced_copy_idx+=over_sample_idx
    np.random.shuffle(balanced_copy_idx)

    data_train=X[balanced_copy_idx]
    labels_train=y[balanced_copy_idx]
    if  ((len(data_train)) == (sample_size*len(uniq_levels))):
        print('number of sampled example ', sample_size*len(uniq_levels), 'number of sample per class ', sample_size, ' #classes: ', len(list(set(uniq_levels))))
    else:
        print('number of samples is wrong ')

    labels, values = zip(*Counter(labels_train).items())
    print('number of classes ', len(list(set(labels_train))))
    check = all(x == values[0] for x in values)
    print(check)
    if check == True:
        print('Good all classes have the same number of examples')
    else:
        print('Repeat again your sampling your classes are not balanced')
    indexes = np.arange(len(labels))
    width = 0.5
    plt.bar(indexes, values, width)
    plt.xticks(indexes + width * 0.5, labels)
    plt.show()
    return data_train,labels_train

X_train,y_train=balanced_sample_maker(X,y,10)

вдохновленный сбалансированной подвыборкой Scikit-learn

person Joseph    schedule 24.01.2018
comment
Превосходно. Вы уверены, что хотите использовать replace=True? Это означает, что одна и та же точка данных может встречаться в подвыборке более одного раза. - person kazemakase; 25.01.2018
comment
Да, если у меня есть только один пример в данном классе - person Joseph; 25.01.2018
comment
Но на самом деле я использую False. Я использую true в основном, когда хочу резко увеличить набор данных. - person Joseph; 25.01.2018
comment
Как я могу сделать то же самое, когда мне нужно взять разное количество образцов из каждого набора. (или np.unique(y)) - person Fasty; 03.10.2019

Я обычно использую трюк от scikit-learn для этого. Я использую функцию StratifiedShuffleSplit. Поэтому, если мне нужно выбрать 1/n долю моего набора поездов, я делю данные на n сгибов и устанавливаю пропорцию тестовых данных (test_size) как 1-1/n. Вот пример, где я использую только 1/10 моих данных.

sp = StratifiedShuffleSplit(n_splits=1, test_size=0.9, random_state=seed)
  for train_index, _ in sp.split(x_train, y_train):
    x_train, y_train = x_train[train_index], y_train[train_index]
person Sukrit Gupta    schedule 12.10.2018

Вы можете использовать dataframe в качестве входных данных (как в моем случае) и использовать простой код ниже:

col = target
nsamples = min(t4m[col].value_counts().values)
res = pd.DataFrame()
for val in t4m[col].unique():
  t = t4m.loc[t4m[col] == val].sample(nsamples)
  res = pd.concat([res, t], ignore_index=True).sample(frac=1)

col — это имя вашего столбца с классами. Код находит класс меньшинства, перемешивает кадр данных, затем берет образец размера класса меньшинства из каждого класса.

Затем вы можете преобразовать результат обратно в np.array

person Sergey Zaitsev    schedule 18.06.2021