Выберите идентификаторы, которые удовлетворяют условию при каждом повторении

#python #pandas

#python #панды

Вопрос:

Я хочу выбрать из идентификатора столбца те уникальные элементы, которые завершены. Каждый идентификатор представляет задачу и может появляться несколько раз. Задача завершается только тогда, когда столбец состояния имеет значение 100 для каждой строки. Пример набора данных:

 import pandas as pd
df = pd.DataFrame(data= {'ID': ['A', 'A', 'B', 'B', 'C', 'D'], 'Status': [100, 100, 100, 25, 100, 34]})
  

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

   ID  Status
0  A     100
4  C     100
  
  • A: появляется дважды с 100. A завершено
  • B: появляется дважды, кроме одного с 25. B не завершено
  • C: появляется один раз со 100. C завершен
  • D: появляется один раз с 34. D не завершен.

Это моя работа до сих пор:

 df_completed = df[df['Status']==100].drop_duplicates()

df_filtered = df[df.ID.isin(df_completed.ID) amp; (df.Status<100)]

df_completed = df_completed[~df_completed.ID.isin(df_filtered.ID)]
  

Как вы можете видеть, я могу получить правильный результат, но мне интересно, есть ли менее сложный способ сделать это. Кроме того, код должен быть общим, а df огромен, поэтому простота и эффективность приветствуются.

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

1. ID кажется запутанным именем для поля, которое не является уникальным…

Ответ №1:

Это кажется хорошим вариантом использования для groupby . Вот несколько примеров:

df.groupby("ID").apply(lambda df: (df.Status == 100).all())

Это дает логический статус для каждого идентификатора:

 ID
A     True
B    False
C     True
D    False
  

Другой вариант, если на среднее значение можно положиться:

df.groupby("ID").mean().pipe(lambda df: df[df.Status == 100])

Это дает результат:

 ID  Status
A   100.0
C   100.0
  

Ответ №2:

Учитывая, что переменная является статусом, я предполагаю, что она существует исключительно [0,100]? Если это так, минимальный статус должен быть 100 для этого идентификатора.

 import pandas as pd
df = pd.DataFrame(data= {'ID': ['A', 'A', 'B', 'B', 'C', 'D'], 'Status': [100, 100, 100, 25, 100, 34]})
df_completed=df.groupby(['ID']).min()==100 #gives True/False for each ID.
df_completed=df_completed[df == True].dropna()*100 #essentially just formatting
  

Вывод:

     Status
ID
A    100.0
C    100.0
  

Ответ №3:

Много способов сделать это.

Вариант 1

groupby() и отфильтруйте min==100

 df.groupby('ID')['Status'].min()[lambda x:x==100].reset_index()

ID  Status
0  A     100
1  C     100
  

Вариант 2
Фильтруйте IDs , которые имеют какие Status -либо значения, не равные 100 и извлекайте их index с помощью groupby() , filter(boolean selection)

Исключить выбранный индекс с помощью обратного .isin запроса и drop duplicates из результата

 s=df.loc[df.groupby('ID')['Status'].filter(lambda x:(x!=100).any()).index,:]
df[~df.index.isin(s.index)].drop_duplicates()


   ID  Status
0  A     100
4  C     100