Eu tenho um dataframe do pandas, por exemplo
df_dupl = pd.DataFrame({
'EVENT_TIME': ['00:01', '00:01', '00:01', '00:03', '00:03', '00:03', '00:06', '00:06', '00:06', '00:08', '00:08', '00:10', '00:10', '00:11', '00:11', '00:13', '00:13', '00:13'],
'UNIQUE_ID': [123, 123, 123, 125, 125, 125, 123, 123, 123, 127, 127, 123, 123, 123, 123, 123, 123, 123],
'Value1': ['A', 'B', 'A', 'A', 'B', 'A', 'A', 'B', 'A', 'A', 'B', 'A', 'B', 'C', 'B', 'A', 'B', 'A'],
'Value2': [0.3, 0.2, 0.2, 0.1, 1.3, 0.2, 0.3, 0.2, 0.2, 0.1, 1.3, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.2]
})
Quero remover as sequências de linhas que possuem os mesmos valores das linhas anteriores (por EVENT_TIME) com o mesmo UNIQUE_ID. Para o exemplo o resultado deve ficar assim:
df = pd.DataFrame({
'EVENT_TIME': ['00:01', '00:01', '00:01', '00:03', '00:03', '00:03', '00:08', '00:08', '00:10', '00:10', '00:11', '00:11', '00:13', '00:13', '00:13'],
'UNIQUE_ID': [123, 123, 123, 125, 125, 125, 127, 127, 123, 123, 123, 123, 123, 123, 123],
'Value1': ['A', 'B', 'A', 'A', 'B', 'A', 'A', 'B', 'A', 'B', 'C', 'B', 'A', 'B', 'A'],
'Value2': [0.3, 0.2, 0.2, 0.1, 1.3, 0.2, 0.1, 1.3, 0.3, 0.2, 0.3, 0.2, 0.3, 0.2, 0.2]
}).
As linhas com horário 00:06 devem ser removidas, pois o subdataframe anterior com UNIQUE_ID 123 (horário 00:01) é idêntico. Por outro lado, as linhas com horário 00:13 devem permanecer - elas também são idênticas às linhas com horário 00:01, mas existem outras linhas com UNIQUE_ID 123 entre elas. A principal coisa é que quero comparar todos os sub-dataframes, não linhas únicas.
Posso alcançar o resultado desejado usando a seguinte função, mas é bastante lenta.
def del_dupl_gr(df):
out = []
for x in df['UNIQUE_ID'].unique():
prev_df = pd.DataFrame()
for y in df[df['UNIQUE_ID'] == x]['EVENT_TIME'].unique():
test_df = df[(df['UNIQUE_ID'] == x) & (df['EVENT_TIME'] == y)]
if not test_df.iloc[:, 2:].reset_index(drop=True).equals(prev_df.iloc[:, 2:].reset_index(drop=True)):
out.append(test_df)
prev_df = test_df
return pd.concat(out).sort_index().reset_index(drop=True)
O dataframe real é bastante grande (mais de um milhão de linhas) e esse loop leva muito tempo. Tenho certeza de que deve haver uma maneira adequada (ou pelo menos mais rápida) de fazer isso.
Resultados
Obrigado por todas as respostas enviadas. Eu comparei a velocidade deles. Em alguns casos, editei ligeiramente os métodos para produzir exatamente os mesmos resultados. Portanto, em todos os métodos sort_values adicionei kind='stable' para garantir que a ordem seja preservada e no final adicionei .reset_index(drop=True).
Método | 1000 linhas | 10.000 linhas | 100.000 linhas |
---|---|---|---|
original | 556ms | 5,41s | Não testado |
mozway | 1,24s | 10,1s | Não testado |
Andrej Kesely | 696ms | 4,56s | Não testado |
Quang Hoang | 11,3ms | 34,1ms | 318ms |
Outra abordagem é deslocar as linhas por enumeração e depois comparar:
Saída:
Você pode formar grupos e fazer hash dos subdataframes e depois
groupby.shift
comparar com o bloco anterior:Saída:
Intermediários:
Outro método:
Impressões: