#python #python-3.x #pandas #datetime #pandas-groupby
#python #python-3.x #панды #дата и время #pandas-groupby
Вопрос:
В этом наборе данных существуют три столбца: ID (уникальная идентификация сотрудника), WorkComplete (указывает, когда вся работа была завершена) и DateDiff (количество дней с даты их начала). Я хочу сгруппировать столбец DaysDiff на основе определенных периодов времени с добавлением уровня терпимости или снисходительности. Для моих макетных данных я разделяю периоды времени на 30 дней.
Group 0: 0-30 DateDiff (with a 30 day extra window if 'Y' is not found)
Group 1: 31-60 DateDiff (with a 30 day extra window if 'Y' is not found)
Group 2: 61-90 DateDiff (with a 30 day extra window if 'Y' is not found)
Я смог создать очень простой код и назначить группировки, но у меня возникли проблемы с дополнительным 30-дневным окном. Например, если сотрудник выполнил свою работу (Y) в течение указанных выше периодов времени, то он получает атрибутивную группировку. Для идентификатора 111 ниже вы можете видеть, что человек не завершил свою работу в течение первых 30 дней, поэтому я даю им дополнительные 30 дней для завершения их работы. Если они завершают свою работу, то в первом экземпляре мы видим «Y», он сгруппирован в предыдущей группировке.
df = pd.DataFrame({'ID':[111, 111, 111, 111, 111, 111, 112, 112, 112],
'WorkComplete':['N', 'N', 'Y', 'N', 'N', 'N', 'N', 'Y', 'Y'],
'DaysDiff': [0, 29, 45, 46, 47, 88, 1, 12, 89]})
Ввод
ID WorkComplete DaysDiff
111 N 0
111 N 29
111 Y 45
111 N 46
111 N 47
111 N 88
123 N 1
123 Y 12
123 Y 89
Вывод
ID WorkComplete DaysDiff Group
111 N 0 0
111 N 29 0
111 Y 45 0 <---- note here the grouping is 0 to provide extra time
111 N 46 1 <---- back to normal
111 N 47 1
111 N 88 2
123 N 1 0
123 Y 12 0
123 Y 89 2
minQ1 = 0
highQ1 = 30
minQ2 = 31
highQ2 = 60
minQ2 = 61
highQ2 = 90
def Group_df(df):
if (minQ1 <= df['DateDiff'] <= highQ1): return '0'
elif (minQ1 <= df['DateDiff'] <= highQ1): return '1'
elif (minQ2 <= df['DateDiff'] <= highQ2): return '2'
df['Group'] = df.apply(Group_df, axis = 1)
Проблема, с которой я сталкиваюсь, заключается в том, что я допускаю дополнительные 30 дней, если человек не завершил работу. Моя вышеупомянутая попытка является частичной попыткой решить проблему.
Ответ №1:
- Вы можете использовать
np.select
для основных условий. - Затем используйте
mask
для конкретного условия, которое вы упомянули.s
это первое расположение индекса для всехY
значений в группе. Затем я временноassign
s
создаю новый столбец, чтобы я мог проверять наличие строк поdf.index
(индексу), чтобы возвращать строки, соответствующие условию. Второе условие заключается в том, что номер группы1
взят из предыдущей строки кода:
df['Group'] = np.select([df['DaysDiff'].between(0,30),
df['DaysDiff'].between(31,60),
df['DaysDiff'].between(61,90)],
[0,1,2])
s = df[df['WorkComplete'] == 'Y'].groupby('ID')['DaysDiff'].transform('idxmin')
df['Group'] = df['Group'].mask((df.assign(s=s)['s'].eq(df.index)) amp; (df['Group'].eq(1)), 0)
df
Out[1]:
ID WorkComplete DaysDiff Group
0 111 N 0 0
1 111 N 29 0
2 111 Y 45 0
3 111 N 46 1
4 111 N 47 1
5 111 N 88 2
6 123 N 1 0
7 123 Y 12 0
8 123 Y 89 2