Python: фильтрация dataFrame с сохранением только последних данных по ActiveFlag и дате - PullRequest
0 голосов
/ 26 марта 2020

Я отсортировал по Date и ID наборам данных (df):

Date          ID      Start_flag    End_flag                               
01-01-2019    100     1             0     
01-02-2019    100     0             0
01-03-2019    100     0             0
01-04-2019    100     0             0
01-05-2019    100     0             1
01-09-2019    100     1             0 
01-10-2019    100     0             0
01-11-2019    100     0             0
01-12-2019    100     0             0
01-03-2019    500     1             0     
01-04-2019    500     0             0
01-05-2019    500     0             0
01-06-2019    500     0             0
01-07-2019    500     0             0
01-08-2019    500     0             0 
01-09-2019    700     1             0
01-10-2019    700     0             0
01-11-2019    700     0             1

Я хотел бы отфильтровать df по последним фактическим Date, где Start_flag = Появляется 1, все данные, которые были до этого для того же ID с Start_flag = 1. Не должны быть извлечены.

Другими словами, если есть несколько раз, Start_flag=1 для одного и того же ID, тогда оставьте только последний Start_flag=1 с максимальным Date.

Ожидаемое представление df:

Date          ID      Start_flag    End_flag                               
01-09-2019    100     1             0 
01-10-2019    100     0             0
01-11-2019    100     0             0
01-12-2019    100     0             0
01-03-2019    500     1             0     
01-04-2019    500     0             0
01-05-2019    500     0             0
01-06-2019    500     0             0
01-07-2019    500     0             0
01-08-2019    500     0             0 
01-09-2019    700     1             0
01-10-2019    700     0             0
01-11-2019    700     0             1 

Я пытаюсь сделать это .groupby(['ID','Start_flag'])['Date'].last(), но это неправильный подход.

Не могли бы вы мне помочь? Как я могу отфильтровать дополнительные данные из df? Спасибо

РЕДАКТИРОВАТЬ: Возможное решение:

def filterTable(df):
    result_list = []
    for x in df['ID'].unique():
        df_1 = df[df['ID']==x]
        indx = df_1.where(((df_1['Start_flag']==0) & (df_1['Date']==df_1['Date'].min())) | (df_1['Start_flag'] == 1)).last_valid_index()
        result_list.append(df_1.loc[indx:])   
    result= pd.concat(result_list)
    return result

Условие df_1['Start_flag']==0 добавляется из-за возврата last_valid_index для случаев, когда первоначально Start_flag=0 до End_flag=1

Кроме того, это не оптимальное решение из-за времени выполнения для огромного dataFrame. Попробуйте найти лучшее решение для этого.

Ответы [ 2 ]

1 голос
/ 26 марта 2020

Не pythoni c

result = []
for i in df['ID'].unique():
    adf = df[df['ID'] == i].sort_values(by="Date").reset_index(drop=True)
    i = adf.where(adf['Start_flag'] == 1).last_valid_index()
    result.append(adf.iloc[range(i, len(adf))])   
print (pd.concat(result).reset_index(drop=True))

Вывод:

         Date   ID  Start_flag  end
0  2019-01-09  100           1    0
1  2019-01-10  100           0    0
2  2019-01-11  100           0    0
3  2019-01-12  100           0    0
4  2019-01-03  500           1    0
5  2019-01-04  500           0    0
6  2019-01-05  500           0    0
7  2019-01-06  500           0    0
8  2019-01-07  500           0    0
9  2019-01-08  500           0    0
10 2019-01-09  700           1    0
11 2019-01-10  700           0    0
12 2019-01-11  700           0    1

Примечание : мы можем избежать l oop, перемещая лог c к функции и вызывая функцию через apply через groupby. Однако groupby запускает функцию дважды в первой группе, поэтому мы должны убедиться, что наша функция не имеет побочных эффектов.

Использование groupby:

def fun(adf):
    adf = adf.sort_values(by="Date").reset_index(drop=True)
    i = adf.where(adf['Start_flag'] == 1).last_valid_index()
    return adf.iloc[range(i, len(adf))]

print (df.groupby('ID').apply(fun).reset_index(drop=True))
0 голосов
/ 26 марта 2020

Окончательно исправлено Решение:

def validateData(adf):  
    adf = adf.sort_values(by="Date").reset_index(drop=True)
    indx = adf.where(((adf['Start_flag']==0) & (adf['Date']==adf['Date'].min())) | (adf['Start_flag'] == 1)).last_valid_index()

    return adf.iloc[range(indx, len(adf))]

def filterData(df):
    start_time = datetime.now()
    print('Start_time=', start_time)
    RESULT_DF = df.groupby('ID').apply(lambda x: validateData(x))
    print("--- %s seconds ---" % (datetime.now() - start_time))
    return RESULT_DF

Для применения к данным: RESULT_DF = filterData(df)

...