Pandas отбирает разные фракции для каждой группы после groupby

import pandas as pd

df = pd.DataFrame({'a': [1,2,3,4,5,6,7],
                   'b': [1,1,1,0,0,0,0],
})

grouped = df.groupby('b')

теперь выборка из каждой группы, например, я хочу 30% из группы b = 1 и 20% из группы b = 0. Как мне это сделать? если я хочу иметь 150% для какой-то группы, могу ли я это сделать?

что вы имеете в виду под 20% и 30%?

U13-Forward 21.12.2020 04:01

Вы имеете в виду, что хотите получить случайные 20% предметов из группы 0 и 30% из группы 1? Вы можете сделать это, но поскольку ваши группы очень малы, для этого примера данных будет только один элемент из каждой группы.

BrenBarn 21.12.2020 05:02
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
2 223
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы можете получить DataFrame из объекта GroupBy, например. grouped.get_group(0). Если вы хотите взять образец из этого, вы можете использовать метод .sample. Например, grouped.get_group(0).sample(frac=0.2) дает:

   a
5  6

Например, в приведенном вами примере оба образца дадут только один элемент, потому что группы имеют 4 и 3 элемента, а 0.2*4 = 0.8 и 0.3*3 = 0.9 округляются до 1.

Ответ принят как подходящий

Вы можете динамически возвращать фрейм данных случайной выборки с разным процентом выборок, определенным для каждой группы. Вы можете сделать это с процентами ниже 100% (см. пример 1) И выше 100% (см. пример 2), передав replace=True:

  1. Используя np.select, создайте новый столбец c, который возвращает количество строк в группе для случайной выборки в соответствии с установленным вами процентом 20%, 40% и т. д.
  2. Оттуда вы можете sample x строк в группе на основе этих процентных условий. Из этих строк верните .index строк и отфильтруйте строки с .loc, а также столбцы 'a','b'. Код grouped.apply(lambda x: x['c'].sample(frac=x['c'].iloc[0])) создает серию мультииндексов вывода, который вы ищете, но требует некоторой очистки. Вот почему для меня проще взять .index и отфильтровать исходный фрейм данных с помощью .loc, чем пытаться очистить беспорядочную серию мультииндексов.

grouped = df.groupby('b', group_keys=False)
df['c'] = np.select([df['b'].eq(0), df['b'].eq(1)], [0.4, 0.2])
df.loc[grouped.apply(lambda x: x['c'].sample(frac=x['c'].iloc[0])).index, ['a','b']]
Out[1]: 
   a  b
6  7  0
8  9  0
3  4  1

Если вы хотите вернуть большую случайную выборку, используя дубликаты существующих значений cvalue, просто передайте replace=True. Затем выполните некоторую очистку, чтобы получить результат.

grouped = df.groupby('b', group_keys=False)
v = df['b'].value_counts()
df['c'] = np.select([df['b'].eq(0), df['b'].eq(1)],
                    [int(v.loc[0] * 1.2), int(v.loc[1] * 2)]) #frac parameter doesn't work with sample when frac > 1, so we have to calcualte the integer value for number of rows to be sampled.
(grouped.apply(lambda x: x['b'].sample(x['c'].iloc[0], replace=True))
        .reset_index()
        .rename({'index' : 'a'}, axis=1))
Out[2]: 
    a  b
0   7  0
1   8  0
2   9  0
3   7  0
4   7  0
5   8  0
6   1  1
7   3  1
8   3  1
9   1  1
10  0  1
11  0  1
12  4  1
13  2  1
14  3  1
15  0  1

Не уверен, что есть много причин для использования np.select. Вы можете просто сделать df.loc[db.b == 0, 'c'] = 0.3 и аналогично для другой группы. Нет необходимости преобразовывать дробь в целое число, так как sample принимает аргумент frac, который может принимать пропорцию.

BrenBarn 21.12.2020 05:49

@BrenBarn np.select потому что есть несколько условий. .loc — это один из способов, но np.select обычно лучше подходит для нескольких условий. Вам придется написать .loc в нескольких строках кода. Там нет ничего плохого. Это просто другой подход. Мне нравится твой код .get_group(0).

David Erickson 21.12.2020 05:52

@BrenBarn Nvmd, теперь я понимаю, что ты имеешь в виду под frac. Спасибо. Однако это не сработает, если вы укажете frac > 1. Я думаю, теперь это также делает np.select немного чище, чем .loc, на мой взгляд.

David Erickson 21.12.2020 06:15

Что делает .reset_index().rename({'index' : 'a'}, axis=1)? @ДэвидЭриксон

double 21.12.2020 07:07

@ user14862671, который очищает фрейм данных. .reset_index() вводит столбец a во фрейм данных, но он называется index, поэтому вам также нужно использовать rename. Передача axis=1 означает, что вы вносите изменения в имена столбцов, а не строк.

David Erickson 21.12.2020 07:10

Код работает! Быстрое продолжение: я получил новый столбец «level_1», созданный после того, как я применил его в своем фрейме данных. Есть идеи, что это значит? @ДэвидЭриксон

double 21.12.2020 07:57

@user14862671 user14862671 вот что происходит, когда вы используете reset_index(). Попробуйте: .rename({'level_1' : 'a'}, axis=1)) вместо .rename({'index' : 'a'}, axis=1))

David Erickson 21.12.2020 08:14

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