Python pandas группировка части датафрейма по условию
Подскажите, пожалуйста, как сгруппировать в DataFrame в кварталы только те данные, в которых представлены все три месяца квартала?
Контрагенты Период Год
0 Компания Март 2022г
1 Компания Апрель 2022г
2 Компания Май 2022г
3 Компания Июнь 2022г
4 Компания Июль 2022г
5 Компания Август 2022г
6 Компания Сентябрь 2022г
7 Компания Октябрь 2022г
8 Компания Ноябрь 2022г
9 Компания Декабрь 2022г
10 Компания Март 2020г
11 Компания Апрель 2020г
12 Компания Июнь 2020г
13 Компания Июль 2020г
14 Компания Август 2020г
15 Компания Сентябрь 2020г
16 Компания Ноябрь 2020г
17 Компания Декабрь 2020г
Ответы (3 шт):
В целом у вас логика правильная. Потом нужно из тех групп, где три строки, оставить одну строку и название месяца заменить на название квартала. Я сделал через apply и функцию. Если потребуется агрегировать какие-то числовые данные (сумма по кварталу, например), это также можно сделать в этой функции.
def fun(x):
if x.shape[0] < 3:
return x
s = x.head(1)
s.at[s.index[0], 'Период'] = f"{q[s.at[s.index[0], 'Период']]} кв."
return s
df = pd.DataFrame({'Контрагенты': ['Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания'],
'Период': ['Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь', 'Март', 'Апрель', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Ноябрь', 'Декабрь'],
'Год': ['2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2020г', '2020г', '2020г', '2020г', '2020г', '2020г', '2020г', '2020г']})
q = {'Январь': 1, 'Февраль': 1, 'Март': 1, 'Апрель': 2, 'Май': 2, 'Июнь': 2, 'Июль': 3, 'Август': 3, 'Сентябрь': 3, 'Октябрь': 4, 'Ноябрь': 4, 'Декабрь': 4}
df = df.groupby([df['Период'].replace(q), 'Год'], as_index=False, sort=False).apply(fun).reset_index(drop=True)
print(df)
Контрагенты Период Год
0 Компания Март 2022г
1 Компания 2 кв. 2022г
2 Компания 3 кв. 2022г
3 Компания 4 кв. 2022г
4 Компания Март 2020г
5 Компания Апрель 2020г
6 Компания Июнь 2020г
7 Компания 3 кв. 2020г
8 Компания Ноябрь 2020г
9 Компания Декабрь 2020г
Я бы сделал так:
locale.setlocale(locale.LC_ALL, ('ru_RU.UTF-8'))
df ["Date"] = pd.to_datetime("1-"+pd.to_datetime(df['Период'], format='%B')
.dt.month.astype(str)+"-"+df["Год"].str[:-1], dayfirst=True)
res = pd.DataFrame()
for i,g in df.groupby([df["Date"].dt.year, df["Date"].dt.quarter]):
if len(g)==3:
g["Период"] = g["Date"].dt.quarter.astype(str)+" Квартал"
res = pd.concat([res, g.head(1).drop(columns=["Date"])])
else:
res = pd.concat([res, g.drop(columns=["Date"])])
res:
Контрагенты Период Год
10 Компания Март 2020г
11 Компания Апрель 2020г
12 Компания Июнь 2020г
13 Компания 3 Квартал 2020г
16 Компания Ноябрь 2020г
17 Компания Декабрь 2020г
0 Компания Март 2022г
1 Компания 2 Квартал 2022г
4 Компания 3 Квартал 2022г
7 Компания 4 Квартал 2022г
Решение без apply.
Сначала делаем булев массив, True - там где есть полный квартал. Меняем все названия месяцев в этих строках на номер квартала. Потом в выборке по булеву массиву удаляем дубликаты - будут удалены все повторы кварталов, а пустые строки заполнятся NaN'ами. Их дропаем.
df = pd.DataFrame({'Контрагенты': ['Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания', 'Компания'],
'Период': ['Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь', 'Март', 'Апрель', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Ноябрь', 'Декабрь'],
'Год': ['2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2022г', '2020г', '2020г', '2020г', '2020г', '2020г', '2020г', '2020г', '2020г']})
q = {'Январь': 1, 'Февраль': 1, 'Март': 1, 'Апрель': 2, 'Май': 2, 'Июнь': 2, 'Июль': 3, 'Август': 3, 'Сентябрь': 3, 'Октябрь': 4, 'Ноябрь': 4, 'Декабрь': 4}
kv = df.groupby([df['Период'].replace(q), 'Год'], as_index=False, sort=False)['Период'].transform('count').gt(2)
df.loc[kv, 'Период'] = df.loc[kv, 'Период'].replace(q).astype(str) + ' кв.'
df[kv] = df[kv].drop_duplicates(['Период', 'Год'])
df = df.dropna()
print(df)
Контрагенты Период Год
0 Компания Март 2022г
1 Компания 2 кв. 2022г
4 Компания 3 кв. 2022г
7 Компания 4 кв. 2022г
10 Компания Март 2020г
11 Компания Апрель 2020г
12 Компания Июнь 2020г
13 Компания 3 кв. 2020г
16 Компания Ноябрь 2020г
17 Компания Декабрь 2020г