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% предметов из группы 0 и 30% из группы 1? Вы можете сделать это, но поскольку ваши группы очень малы, для этого примера данных будет только один элемент из каждой группы.
Вы можете получить 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
:
np.select
, создайте новый столбец c
, который возвращает количество строк в группе для случайной выборки в соответствии с установленным вами процентом 20%, 40% и т. д.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 np.select
потому что есть несколько условий. .loc
— это один из способов, но np.select
обычно лучше подходит для нескольких условий. Вам придется написать .loc
в нескольких строках кода. Там нет ничего плохого. Это просто другой подход. Мне нравится твой код .get_group(0)
.
@BrenBarn Nvmd, теперь я понимаю, что ты имеешь в виду под frac
. Спасибо. Однако это не сработает, если вы укажете frac
> 1. Я думаю, теперь это также делает np.select
немного чище, чем .loc
, на мой взгляд.
Что делает .reset_index().rename({'index' : 'a'}, axis=1)
? @ДэвидЭриксон
@ user14862671, который очищает фрейм данных. .reset_index()
вводит столбец a
во фрейм данных, но он называется index
, поэтому вам также нужно использовать rename
. Передача axis=1
означает, что вы вносите изменения в имена столбцов, а не строк.
Код работает! Быстрое продолжение: я получил новый столбец «level_1», созданный после того, как я применил его в своем фрейме данных. Есть идеи, что это значит? @ДэвидЭриксон
@user14862671 user14862671 вот что происходит, когда вы используете reset_index()
. Попробуйте: .rename({'level_1' : 'a'}, axis=1))
вместо .rename({'index' : 'a'}, axis=1))
что вы имеете в виду под 20% и 30%?