Как сбалансировать набор данных на основе определенных пропорций значений в нескольких столбцах? - PullRequest
1 голос
/ 28 октября 2019

У меня есть таблица, которая выглядит следующим образом (пример строки):

|---------------------|------------------|---------------|
|      Color          |       Size       |        Age    |
|---------------------|------------------|---------------|
|       Green         |       Small      |       Young   |
|---------------------|------------------|---------------|

Таблица имеет тысячи экземпляров с тремя разными цветами (зеленый, синий, желтый), трех разных размеров (маленький, средний(большой) и три разных возраста (молодой, средний, старый).

У меня также есть набор предопределенных процентов / пропорций для каждого столбца. Например:

  1. Цвет: 30% синий, 40% зеленый, 30% желтый

  2. Размер: 25% маленький, 50% средний,25% большой

  3. Возраст: 45% молодых, 45% среднего возраста, 10% старых

Мой вопрос: Как я могу создатьсамый большой набор данных, который соответствует указанным пропорциям?

Я думаю, что метод недосэмплирования (т.е. отбрасывание строк со значениями, которые имеют избыточный вес), кажется, путь вперед, но я нахожу вещи трудными, так как каждая строка влияет на все три переменные, которые я контролирую,

Окончательным результатом будет максимально возможный набор данных, который соответствует указанным выше пропорциям.

Спасибо!

1 Ответ

1 голос
/ 29 октября 2019

Вам необходимо выбрать каждую строку с вероятностью, пропорциональной произведению весов значений для этой строки. Это легче проиллюстрировать на примере.

N = 100000

# generate N samples of each category; "Color" is sampled non-uniformly to 
# illustrate how to account for prior distribution
df = pd.DataFrame({
    'Color': np.random.choice(['blue', 'green', 'yellow'], N, p=[0.9, 0.05, 0.05]),
    'Size': np.random.choice(['small', 'medium', 'large'], N),
    'Age': np.random.choice(['young', 'middle-age', 'old'], N),
})

# target value distribution (e.g., in the final data set, we want 30% blue,
# 40% green, 30% yellow)
target_weights = {
    'Color': pd.Series({'blue': 30, 'green': 40, 'yellow': 30}),
    'Size': pd.Series({'small': 25, 'medium': 50, 'large': 25}),
    'Age': pd.Series({'young': 45, 'middle-age': 45, 'old': 10}),
}

Сначала нормализуйте по предыдущему распределению. Интуитивно, вы хотите произвести выборку с вероятностью, пропорциональной отношению частоты целевого значения к частоте предыдущего значения.

target_weights['Color'] /= df.Color.value_counts()
target_weights['Size'] /= df.Size.value_counts()
target_weights['Age'] /= df.Age.value_counts()

Затем рассчитайте вероятность выборки для каждой строки.

sample_prob = (
    df.Color.map(target_weights['Color']) *
    df.Size.map(target_weights['Size']) *
    df.Age.map(target_weights['Age'])
)
sample_prob.head()
0    3.354744e-10
1    6.184742e-09
2    3.390995e-10
3    3.396480e-10
4    6.647330e-10
dtype: float64

На этом этапе выборка каждой строки в df с вероятностью sample_prob даст желаемое распределение. Масштабирование вероятностей выборки по константе все равно приведет к целевому распределению. Чтобы получить максимально возможную выборку, убедитесь, что строки с максимальной вероятностью выборки всегда , то есть

sample_prob /= sample_prob.max()

Затем выполните выборку каждой строки с соответствующей вероятностью.

df_sampled = df.loc[np.random.random(df.shape[0]) < sample_prob]

Вы можете проверить правильность распределений:

df_sampled.Color.value_counts(normalize=True)
green     0.400585
yellow    0.304341
blue      0.295074
Name: Color, dtype: float64
df_sampled.Size.value_counts(normalize=True)
medium    0.497805
large     0.253130
small     0.249065
Name: Size, dtype: float64
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...