Поиск последних n групп строк в фрейме данных

У меня есть большой фрейм данных (1 м+ строк), который содержит тестовые данные. Моментальный снимок «События» был сделан в разное время, и в каждый моментальный снимок к фрейму данных добавлялось до трех строк. Например, в выдержке ниже первый снимок для события At223 был сделан 18.03.2016 18:10:45, второй — 21.03.2016 10:14:28 и т. д.

Я хочу отфильтровать фрейм данных, чтобы он возвращал только последние n снимков на Ref. Рефы уникальны, тогда как События могут дублироваться.

Я новичок в Pandas, но пробовал различные комбинации sort_values, groupby и tail, но не могу получить желаемый результат. Например:

df = df.sort_values(['Ref', 'Time']).groupby(['Time', 'Ref', 'TestId']).tail(3)

Кто-нибудь может подсказать, как это сделать? В приведенном ниже примере желаемого результата n = 3, поэтому он показывает последние три снимка по Ref.

Извлекать:

Время Ссылка Событие Время окончания идентификатор теста Названия тестов Результат 18.03.2016 18:10:45 1.123717985 At223 04.01.2016 16:00 28212 Один 18.03.2016 18:10:45 1.123717985 At223 04.01.2016 16:00 466299 Два 18.03.2016 18:10:45 1.123717985 At223 04.01.2016 16:00 58805 Три 03.21.2016 10:14:28 1.123717985 At223 04.01.2016 16:00 28212 Один 03.21.2016 10:14:28 1.123717985 At223 04.01.2016 16:00 466299 Два 4 03.21.2016 10:14:28 1.123717985 At223 04.01.2016 16:00 58805 Три 03.21.2016 12:44:34 1.123717985 At223 04.01.2016 16:00 28212 Один 03.21.2016 12:44:34 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 03.21.2016 12:44:34 1.123717985 At223 04.01.2016 16:00 58805 Три 03.21.2016 13:05:16 1.123717985 At223 04.01.2016 16:00 28212 Один 03.21.2016 13:05:16 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 03.21.2016 13:05:16 1.123717985 At223 04.01.2016 16:00 58805 Три 03.21.2016 13:14:22 1.123717985 At223 04.01.2016 16:00 28212 Один 03.21.2016 13:14:22 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 03.21.2016 13:14:22 1.123717985 At223 04.01.2016 16:00 58805 Три 04.01.2016 10:37:43 1.123717985 At223 04.01.2016 16:00 28212 Один 04.01.2016 10:37:43 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 04.01.2016 10:37:43 1.123717985 At223 04.01.2016 16:00 58805 Три 18.03.2016 18:12:12 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7 18.03.2016 18:12:12 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,58 18.03.2016 18:12:12 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4.4 03.21.2016 13:03:48 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7.2 03.21.2016 13:03:48 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,58 03.21.2016 13:03:48 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4.4 03.21.2016 13:19:15 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7.2 03.21.2016 13:19:15 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,58 03.21.2016 13:19:15 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4,5 04.01.2016 12:48:13 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7.2 04.01.2016 12:48:13 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,59 04.01.2016 12:48:13 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4,5

Желаемый результат:

Время Ссылка Событие Время окончания идентификатор теста Названия тестов Результат 03.21.2016 13:05:16 1.123717985 At223 04.01.2016 16:00 28212 Один 03.21.2016 13:05:16 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 03.21.2016 13:05:16 1.123717985 At223 04.01.2016 16:00 58805 Три 03.21.2016 13:14:22 1.123717985 At223 04.01.2016 16:00 28212 Один 03.21.2016 13:14:22 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 03.21.2016 13:14:22 1.123717985 At223 04.01.2016 16:00 58805 Три 04.01.2016 10:37:43 1.123717985 At223 04.01.2016 16:00 28212 Один 04.01.2016 10:37:43 1.123717985 At223 04.01.2016 16:00 466299 Два 4,5 04.01.2016 10:37:43 1.123717985 At223 04.01.2016 16:00 58805 Три 03.21.2016 13:03:48 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7.2 03.21.2016 13:03:48 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,58 03.21.2016 13:03:48 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4.4 03.21.2016 13:19:15 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7.2 03.21.2016 13:19:15 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,58 03.21.2016 13:19:15 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4,5 04.01.2016 12:48:13 1.123719512 12 руб. 04.03.2016 16:00 28214 Восемь 7.2 04.01.2016 12:48:13 1.123719512 12 руб. 04.03.2016 16:00 1212772 Девять 1,59 04.01.2016 12:48:13 1.123719512 12 руб. 04.03.2016 16:00 58805 Десять 4,5

Кажется, на снимок всегда приходится 3 строки?

Corralien 06.02.2023 17:15

Почему желаемый результат содержит более 3 записей для Ref 1.123717985?

Guru Stron 06.02.2023 17:20

Был ли ответ на ваш вопрос?

jprebys 06.02.2023 22:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
71
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Вы можете пройтись по каждому уникальному событию и взять верхнее n раз из каждого. Затем объедините результаты вместе:

n = 3
event_dfs = []
for event in df['Event'].unique():
   sub_df = df.loc[df['Event'] == event]
   max_times = sub_df['Time'].nlargest(n=n)
   event_dfs.append(sub_df.loc[sub_df['Time'].isin(max_times)])

result = pd.concat(event_dfs)

Факторизируйте дату и сохраните n самых высоких значений (при условии, что ваш фрейм данных уже отсортирован по времени)

# Number of snapshot you want to keep
n = 3 

# Create a boolean mask
m = (df.assign(val=pd.factorize(df['Time'])[0])
       .groupby('Ref')['val']
       .transform(lambda x: x.max() - x < n))

out = df[m]

Выход:

>>> out
                   Time       Ref  Event           EndTime   TestId TestNames  Result
9   21/03/2016 13:05:16  1.123718  At223  01/04/2016 16:00    28212       One     NaN
10  21/03/2016 13:05:16  1.123718  At223  01/04/2016 16:00   466299       Two    4.50
11  21/03/2016 13:05:16  1.123718  At223  01/04/2016 16:00    58805     Three     NaN
12  21/03/2016 13:14:22  1.123718  At223  01/04/2016 16:00    28212       One     NaN
13  21/03/2016 13:14:22  1.123718  At223  01/04/2016 16:00   466299       Two    4.50
14  21/03/2016 13:14:22  1.123718  At223  01/04/2016 16:00    58805     Three     NaN
15  01/04/2016 10:37:43  1.123718  At223  01/04/2016 16:00    28212       One     NaN
16  01/04/2016 10:37:43  1.123718  At223  01/04/2016 16:00   466299       Two    4.50
17  01/04/2016 10:37:43  1.123718  At223  01/04/2016 16:00    58805     Three     NaN
21  21/03/2016 13:03:48  1.123720   Br12  03/04/2016 16:00    28214     Eight    7.20
22  21/03/2016 13:03:48  1.123720   Br12  03/04/2016 16:00  1212772      Nine    1.58
23  21/03/2016 13:03:48  1.123720   Br12  03/04/2016 16:00    58805       Ten    4.40
24  21/03/2016 13:19:15  1.123720   Br12  03/04/2016 16:00    28214     Eight    7.20
25  21/03/2016 13:19:15  1.123720   Br12  03/04/2016 16:00  1212772      Nine    1.58
26  21/03/2016 13:19:15  1.123720   Br12  03/04/2016 16:00    58805       Ten    4.50
27  01/04/2016 12:48:13  1.123720   Br12  03/04/2016 16:00    28214     Eight    7.20
28  01/04/2016 12:48:13  1.123720   Br12  03/04/2016 16:00  1212772      Nine    1.59
29  01/04/2016 12:48:13  1.123720   Br12  03/04/2016 16:00    58805       Ten    4.50

Вы можете использовать apply после groupby

И создайте функцию, которая обрабатывает кадры данных только с одним Ref

def extract_n_last_times(n: int):
    def extract_last_times(group: pd.DataFrame):
        times = group.sort_values("Time")["Time"].unique()
        return group[group["Time"].isin(times[-n:])]
    return extract_last_times

df.sort_values(["Ref", "Time"]).groupby("Ref", group_keys=False).apply(extract_n_last_times(n=3))

Другие вопросы по теме