Как отфильтровать кадр данных панд по подгруппам с условием в значении другого столбца - PullRequest
0 голосов
/ 05 июня 2019

Я изо всех сил пытаюсь найти решение, вот проблема.

У меня есть датафрейм в форме:

date         day_time   day_time_counter  area

2019-06-05   morning    1                 1
2019-06-05   morning    1                 2
2019-06-05   morning    1                 3

2019-06-05   morning    2                 1
2019-06-05   morning    2                 2
2019-06-05   morning    2                 3

2019-06-05   morning    3                 1
2019-06-05   morning    3                 3

2019-06-05   evening    1                 1
2019-06-05   evening    1                 2

2019-06-05   evening    2                 1
2019-06-05   evening    2                 2
2019-06-05   evening    2                 3

Есть несколько подгрупп для "date", "date_time" и "day_time_counter" (которые я разделил их пустой строкой, чтобы сделать их более заметными). Каждая подгруппа может иметь одну, две или три «области».

Я хочу отфильтровать df, чтобы получить только одну подгруппу для «date» и «day_time», которая имеет наибольшее значение «day_time_counter» И содержит 3 различных значения «area» (1, 2, 3), то есть выбранные подгруппы должны содержать 3 строки, по одной на значение «площадь».

То есть, после фильтрации df выше, я должен получить как OUTPUT:

date         day_time   day_time_counter  area

2019-06-05   morning    2                 1
2019-06-05   morning    2                 2
2019-06-05   morning    2                 3

2019-06-05   evening    2                 1
2019-06-05   evening    2                 2
2019-06-05   evening    2                 3

До сих пор мне удавалось фильтровать, получая подгруппу с самым большим "day_time_counter", но я не знаю, как включить условие полной подгруппы с 3 "областями".

df_new = df.sort_values('day_time_counter', ascending=False).drop_duplicates(['area', 'date', 'day_time'])

Большое спасибо за вашу помощь!

Ответы [ 3 ]

1 голос
/ 06 июня 2019

Следующее будет производить то, что вы ищете:

area_grp_cols = ["date", "day_time", "day_time_counter"]
counter_grp_cols = ["date", "day_time"]
result = (
    df.assign(area_count=lambda df: df.groupby(area_grp_cols)['area']
                                      .transform("count"))
      .loc[lambda df: df["area_count"] == 3]
      .drop(columns=["area_count"])
      .loc[lambda df: df["day_time_counter"]
                      == df.groupby(counter_grp_cols)["day_time_counter"]
                           .transform("max")]
)

Выход:

          date day_time  day_time_counter  area
3   2019-06-05  morning                 2     1
4   2019-06-05  morning                 2     2
5   2019-06-05  morning                 2     3
10  2019-06-05  evening                 2     1
11  2019-06-05  evening                 2     2
12  2019-06-05  evening                 2     3
0 голосов
/ 05 июня 2019

IIUC:

df['group'] = df['area'].eq(1).cumsum()

df_out = df.groupby(['date','day_time','group'])[['area','day_time_counter']]\
           .agg({'area':lambda x: x.nunique()==3,'day_time_counter':'sum'})

df_out.loc[df_out['area'], 'day_time_counter']\
      .rank(ascending=False, method='dense').eq(1).loc[lambda x: x]\
      .to_frame()\
      .merge(df, on=['date','day_time','group'], suffixes=('_',''))[df.columns]

Выход:

   area        date day_time  day_time_counter  group
0     1  2019-06-05  evening                 2      5
1     2  2019-06-05  evening                 2      5
2     3  2019-06-05  evening                 2      5
3     1  2019-06-05  morning                 2      2
4     2  2019-06-05  morning                 2      2
5     3  2019-06-05  morning                 2      2
0 голосов
/ 05 июня 2019

я думаю, что ваш требуемый вывод должен быть другим (вечером есть дневное время 3), поэтому я думаю, что мой код правильный:

выбирая максимум, который имеет все 3 области:

m = df.groupby(['date', 'day_time', 'day_time_counter']).area
new_df = []
for k , _ in m:
    if len(set( _ )) != 3:
        continue
    new_df.append(df[(df.date == k[0]) & (df.day_time == k[1]) & (df.day_time_counter == k[2])])
new_df = pd.concat(new_df, join='outer')

отфильтровывая максимальное количество дней:

g = new_df.groupby(['date', 'day_time'])
g.filter(lambda x: len(set(x.area)) == 3)
g = g.day_time_counter.max()

и завершая:

itr = [df[(df.date == idx[0]) & (df.day_time == idx[1]) & (df.day_time_counter == value)] for idx, value in zip(g.index, g)]
new_df = pd.concat(itr, join='outer')
new_df

скажите мне, если это то, что вы хотели

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...