Tengo el siguiente marco de datos:

time        id  type
2012-12-19  1   abcF1
2013-11-02  1   xF1yz
2012-12-19  1   abcF1
2012-12-18  1   abcF1
2013-11-02  1   xF1yz
2006-07-07  5   F5spo
2006-07-06  5   F5spo
2005-07-07  5   F5abc

Para una identificación dada, necesito encontrar la fecha máxima.

Para esa fecha máxima, necesito verificar el tipo.

Tengo que descartar cada fila para la identificación dada si el tipo difiere del tipo de la fecha máxima.

Ejemplo para el marco de datos objetivo:

time        id  type
<deleted because for id 1 the date is not the max value and the type differs from the type of the max date for id 1>
2013-11-02  1   xF1yz
<deleted because for id 1 the date is not the max value and the type differs from the type of the max date for id 1>
<deleted because for id 1 the date is not the max value and the type differs from the type of the max date for id 1>
2013-11-02  1   xF1yz
2006-07-07  5   F5spo
2006-07-06  5   F5spo //kept because although the date is not max, it has the same type as the row with the max date for id 5
<deleted because for id 5 the date is not the max value and the type differs from the type of the max date for id 5>

¿Cómo puedo conseguir esto? Soy nuevo en los pandas y trato de aprender la forma correcta de usar la biblioteca.

1
whitefang1993 10 may. 2019 a las 09:39

5 respuestas

La mejor respuesta

Utilice DataFrameGroupBy.idxmax para obtener índices de valores máximos, filtre solo las columnas id y type y DataFrame.merge:

df = df.merge(df.loc[df.groupby('id')['time'].idxmax(), ['id','type']])
print (df)
        time  id   type
0 2013-11-02   1  xF1yz
1 2013-11-02   1  xF1yz
2 2006-07-07   5  F5spo
3 2006-07-06   5  F5spo

O use DataFrame.sort_values con DataFrame.drop_duplicates :

df = df.merge(df.sort_values('time').drop_duplicates('id', keep='last')[["id", "type"]])
3
jezrael 10 may. 2019 a las 06:49

La otra forma usando duplicado.

import pandas as pd
import datetime

# if needed
df['time'] = pd.to_datetime(df['time'])

# sort values of id and time ascendingly, and tagged the duplicates
df = df.sort_values(by=['id','time'], ascending=[True,True])
df['time_max'] = df.duplicated(subset=['id'], keep='last')
# keep the max value only
df2 = df.loc[~df['time_max'],['id','type']].rename(columns={'type':'type_max'}).copy()

# merge with the original df
df = pd.merge(df, df2, on=['id'], how='left')
# get the result
df['for_drop'] = df['type']==df['type_max']
df = df.loc[df['for_drop'],:]

[fuera]:

df
    time        id  type    time_max    type_max    for_drop
3   2013-11-02  1   xF1yz   True          xF1yz       True
4   2013-11-02  1   xF1yz   False         xF1yz       True
6   2006-07-06  5   F5spo   True          F5spo       True
7   2006-07-07  5   F5spo   False         F5spo       True
0
Umar Sahid 10 may. 2019 a las 07:54

Puede ordenar el marco de datos por tiempo, luego agrupar por id y elegir la última fila de cada grupo. Esa es la fila con la fecha más grande.

last_rows = df.sort_values('time').groupby('id').last()

Luego combine el marco de datos original con el nuevo:

result = df.merge(last_rows, on=["id", "type"])
#       time_x  id   type      time_y
#0  2013-11-02   1  xF1yz  2013-11-02
#1  2013-11-02   1  xF1yz  2013-11-02
#2  2006-07-07   5  F5spo  2006-07-07
#3  2006-07-06   5  F5spo  2006-07-07

Si es necesario, suelte la última columna duplicada:

result.drop('time_y', axis=1, inplace=True)
1
DYZ 10 may. 2019 a las 06:45

Cree un ayudante Series usando { {X1}}, { {X2}} y { {X3}} {{{ X4}}. Luego use boolean indexing:

# If neccessary cast to datetime dtype
# df['time'] = pd.to_datetime(df['time'])

s = df.set_index('type').groupby('id')['time'].transform('idxmax')
df[df.type == s.values]

[fuera]

        time  id   type
1 2013-11-02   1  xF1yz
4 2013-11-02   1  xF1yz
5 2006-07-07   5  F5spo
6 2006-07-06   5  F5spo
1
Chris A 10 may. 2019 a las 06:59
import pandas as pd

df = pd.DataFrame({
    'time': ['2012-12-19', '2013-11-02', '2013-12-19', '2013-12-18', '2013-11-02', '2006-07-07', '2006-07-06', '2005-07-07'],
    'id': [1,1,1,1,1,5,5,5],
    'type': ['abcF1', 'xF1yz', 'abcF1', 'abcF1', 'xF1yz', 'F5spo', 'F5spo', 'F5abc']
})

df['time'] = pd.to_datetime(df['time'])
def remove_non_max_date_ids(df):
    max_type = df.loc[df['time'].idxmax()]['type']
    print(max_type)
    return df[
        df['type'] != max_type
    ]

df.groupby('id').apply(remove_non_max_date_ids)

Cree una función auxiliar que filtre las filas que no tienen el mismo tipo que la fecha máxima, luego aplíquela a cada grupo df según id

0
zero 10 may. 2019 a las 07:08