как выбрать / сгруппировать строки фрейма данных, чтобы исправить определенные c распределения в группе? - PullRequest
0 голосов
/ 08 мая 2020

У меня есть DataFrame c, содержащий столбцы a.

import numpy as np
a = np.random.randint(0,10, size=(100))
c = pd.DataFrame(a, columns=['a'])

Я хочу сделать случайную группировку строк c так, чтобы в каждой группе было 5 строк и чтобы в каждой группе была 1 строка с a < 3

так, например:

[1,2,3,2,10]  <-- good group 
[1,1,3,4,6]  <-- good group
[2,4,7,3,7] <-- bad group

И если у меня закончились строки, чтобы соответствовать этим критериям (например, у меня закончились строки с a < 1), игнорируйте остальную часть фрейма данных

В настоящее время я делаю это, создавая новый столбец group_id и отделяя c по условию, а затем итеративно выбирая из них, пока у меня не закончатся кандидаты:

c['group_id'] = None
c_w_small_a = c[c.a < 3].copy()
c_w_large_a = c[c.a >= 3].copy()
group_id = 0
while len(c_w_small_a) >= 1 and len(c_w_large_a) >= 4:
   c.loc[c_w_small_a.sample(1, replace=False).index, 'group_id'] = group_id
   c.loc[c_w_large_a.sample(4, replace=False).index, 'group_id'] = group_id
   group_id += 1

c = c[c.group_id.apply(lambda x,x is not None)] # filter rows without id
c_groups = c.groupby('group_id')

Проблема с этим подходом в том, что я могу ' Обобщим этот подход более сложным условием, при котором подмножества перекрывают друг друга. например,

не более 2 строк с a > 2 и не менее 1 строки с 'a == 3'.

Я не знаю, как это кодировать таким образом, чтобы максимально увеличить количество групп, которые я могу получить с помощью этой группировки. Например, если a == 3 очень ограничено, я не хочу, чтобы a> 2 выбирал 3, даже если это удовлетворяет его условию.

1 Ответ

0 голосов
/ 08 мая 2020

Я не уверен, но я думаю, что проблема, которую вы описываете, является NP-полной, и для этой цели я предлагаю вам подумать об эвристике c, чтобы найти удовлетворительное решение. для этой цели вы можете написать жадную эвристию c, которая будет выглядеть так:

def is_satisfying(group):
...     if (np.sum(group > 2) > 2) or (np.sum(group == 3) < 1): 
...             return False
...     else:
...             return True

, а затем, чтобы создать группу, вы можете написать что-то вроде:

group = []
while len(group) != 4 : 
...     np.append(group, df['a'].sample(n=1))
...     if not is_satisfying(group):
...             group = group[:-1]

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

...