¿Cómo aplicar las funciones “primera” y “última” a las columnas mientras se usa agrupar por en pandas?

Tengo un dataframe y me gustaría agruparlo por una columna en particular (o, en otras palabras, por los valores de una columna en particular). Puedo hacerlo de la siguiente manera: grouped = df.groupby(['ColumnName']) .

Imagino el resultado de esta operación como una tabla en la que algunas celdas pueden contener conjuntos de valores en lugar de valores individuales. Para obtener una tabla habitual (es decir, una tabla en la que cada celda contenga solo un único valor), debo indicar qué función deseo utilizar para transformar los conjuntos de valores de las celdas en valores únicos.

Por ejemplo, puedo reemplazar los conjuntos de valores por su sum, o por su valor mínimo o máximo. Puedo hacerlo de la siguiente manera: grouped.sum() o grouped.min() y así sucesivamente.

Ahora quiero usar diferentes funciones para diferentes columnas. Me di cuenta de que puedo hacerlo de la siguiente manera: grouped.agg({'ColumnName1':sum, 'ColumnName2':min}) .

Sin embargo, debido a algunas razones no puedo usar first . En más detalles, grouped.first() funciona, pero grouped.agg({'ColumnName1':first, 'ColumnName2':first}) no funciona. Como resultado obtengo un NameError: NameError: name 'first' is not defined . Entonces, mi pregunta es: ¿Por qué sucede y cómo resolver este problema?

ADICIONAL

Aquí encontré el siguiente ejemplo:

 grouped['D'].agg({'result1' : np.sum, 'result2' : np.mean}) 

Puede ser que también necesito usar np ? Pero en mi caso python no reconoce “np”. ¿Debo importarlo?

Creo que el problema es que hay dos first métodos diferentes que comparten un nombre pero actúan de manera diferente, uno es para los objetos groupby y otro para un Series / DataFrame (relacionado con series temporales).

Para replicar el comportamiento del grupo por el first método en un DataFrame usando agg , puede usar iloc[0] (que obtiene la primera fila de cada grupo (DataFrame / Series) por índice):

 grouped.agg(lambda x: x.iloc[0]) 

Por ejemplo:

 In [1]: df = pd.DataFrame([[1, 2], [3, 4]]) In [2]: g = df.groupby(0) In [3]: g.first() Out[3]: 1 0 1 2 3 4 In [4]: g.agg(lambda x: x.iloc[0]) Out[4]: 1 0 1 2 3 4 

De manera análoga, puedes replicar el last usando iloc[-1] .

Nota: Esto funcionará en forma de columna, et al:

 g.agg({1: lambda x: x.iloc[0]}) 

En una versión anterior de pandas, podría usar el método de irow (por ejemplo, x.irow(0) , ver ediciones anteriores).


Un par de notas actualizadas:

Esto se hace mejor usando el método nth group by, que es mucho más rápido> = 0.13:

 g.nth(0) # first g.nth(-1) # last 

Debe cuidarse un poco, ya que el comportamiento predeterminado de la first y la last ignora las filas de NaN … y IIRC para los grupos de DataFrame que se rompieron antes de la dropna 0.13 … hay una opción dropna para nth .

Puede usar las cadenas en lugar de las integradas (aunque los pandas IIRC detectan que es la sum incorporada y aplica np.sum ):

 grouped['D'].agg({'result1' : "sum", 'result2' : "mean"}) 

En lugar de usar el first o el last , use sus representaciones de cadena en el método agg . Por ejemplo en el caso del OP:

 grouped = df.groupby(['ColumnName']) grouped['D'].agg({'result1' : np.sum, 'result2' : np.mean}) #you can do the string representation for first and last grouped['D'].agg({'result1' : 'first', 'result2' : 'last'}) 

No estoy seguro de si este es realmente el problema, pero sum y min son incorporaciones de Python que toman algunos iterables como entrada, mientras que el first es un método de los objetos de la serie pandas, así que tal vez no esté en su espacio de nombres. Además, toma algo más como una entrada (el documento dice algún valor de compensación).

Supongo que una forma de solucionarlo es crear su propia first función y definirla de tal manera que tome un objeto Serie como entrada, por ejemplo:

 def first(Series, offset): return Series.first(offset) 

o algo así..