Фрейм данных Pandas: Как изящно отбрасывать непрерывные строки

#pandas #dataframe

#панды #фрейм данных

Вопрос:

У меня есть фрейм данных, имеющий два типа строк: ПЕРЕКЛЮЧАТЕЛЬ и РЕЗУЛЬТАТ.Я ожидаю, что отброшу соседний «ПЕРЕКЛЮЧАТЕЛЬ» и сохраню только последний ПЕРЕКЛЮЧАТЕЛЬ в блоке, но сохраню все строки РЕЗУЛЬТАТОВ.

Я сделал это с помощью итераций фреймов данных и в основном сканировал строку за строкой. Это не по-питонски. Не могли бы вы, пожалуйста, посоветовать, видите ли вы лучший способ? Ниже приведены примеры данных и код, который я использую:

 import pandas as pd  data = {'TYPE':['SWITCH','SWITCH','SWITCH', 'SWITCH','RESULT','RESULT','RESULT', 'RESULT','RESULT','SWITCH','SWITCH', 'RESULT','RESULT','RESULT','RESULT'], 'RESULT':['YES', 'NO','NO','YES', 'DONE','DONE','DONE', 'DONE','DONE','NO', 'YES','DONE','DONE', 'DONE','DONE']}  df = pd.DataFrame(data) l = [] start=-1 for index, row in df.iterrows():  type = row["TYPE"]  if type == "RESULT":  if start == -1:  start = index   elif type == "SWITCH":  if start== -1:  df.drop(index=[*range(index, index 1, 1)], inplace=True)  continue    end = index-1  if start lt;= end:  df.drop(index=[*range(start,end,1)], inplace=True)  start = index   1  print(df)  

Просто проверил вывод и обнаружил, что мой код не сделал того, что я ищу:

Перед применением кода

Поскольку индекс 0~индекс 3 все являются «ПЕРЕКЛЮЧАТЕЛЯМИ», я хочу удалить индекс 0/1/2 и сохранить только индекс 3, так как это «блок переключения» Аналогично, для индекса 9/10 я хочу сохранить только индекс 10

 TYPE RESULT 0 SWITCH YES 1 SWITCH NO 2 SWITCH NO 3 SWITCH YES 4 RESULT DONE 5 RESULT DONE 6 RESULT DONE 7 RESULT DONE 8 RESULT DONE 9 SWITCH NO 10 SWITCH YES 11 RESULT DONE 12 RESULT DONE 13 RESULT DONE 14 RESULT DONE  

Ожидаемый результат:

 TYPE RESULT 3 SWITCH YES 4 RESULT DONE 5 RESULT DONE 6 RESULT DONE 7 RESULT DONE 8 RESULT DONE 10 SWITCH YES 11 RESULT DONE 12 RESULT DONE 13 RESULT DONE 14 RESULT DONE  

Фактический объем производства:

 TYPE RESULT 8 RESULT DONE 9 SWITCH NO 10 SWITCH YES 11 RESULT DONE 12 RESULT DONE 13 RESULT DONE 14 RESULT DONE  

Комментарии:

1. Не могли бы вы уточнить, что вы подразумеваете под «только в блоке»? Также не могли бы вы добавить предполагаемый результат.

2. Спасибо @j__Карлсон. Я просто добавил немного больше описания. Надеюсь, теперь все стало яснее

Ответ №1:

Если я вас правильно понимаю, для каждой группы последовательных строк с TYPE == "SWITCH" вами нужно сохранить последнюю строку. Это можно сделать следующим образом:

 df_processed = df[(df.TYPE != "SWITCH") | (df.TYPE.shift(-1) != "SWITCH")]  

Выходные данные для приведенного примера данных являются

введите описание изображения здесь

Комментарии:

1. Это такое умное однострочное решение!

Ответ №2:

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

Я верю, что вы ищете что-то в этом роде:

 # Get the rows where TYPE == RESULT df_type_result = df[df['TYPE'] == 'RESULT']  # Get the last index when the result type == SWITCH  idxs = df.reset_index().groupby(['TYPE', 'RESULT']).last().loc['SWITCH']['index'] df_type_switch = df.loc[idxs]  # Concatenate and sort the results df_result = pd.concat([df_type_result, df_type_switch]).sort_index() df_result  

введите описание изображения здесь

Комментарии:

1. Извините, что я создал путаницу в моем первоначальном описании вопроса — да, повторение строки-это худшее 🙂 Я принял решение @Anton, которое довольно изящно, но все равно спасибо вам

Ответ №3:

Ленивое решение

 df["DROP"] = df["TYPE"].shift(-1) df = df.loc[~((df["TYPE"]=="SWITCH")amp;(df["DROP"]=="SWITCH"))] df.drop(columns="DROP", inplace=True)   

Комментарии:

1. Извините, я должен был выразиться яснее. Я думаю, что ваше решение имеет аналогичную стратегию @Anton, и оно также может генерировать желаемый результат. Огромное спасибо

2. Да, именно более длинная версия :))