Los pandas suman por grupo, pero excluyen ciertas columnas

88

¿Cuál es la mejor manera de hacer un groupby en un marco de datos de Pandas, pero excluir algunas columnas de ese groupby? por ejemplo, tengo el siguiente marco de datos:

Code   Country      Item_Code   Item    Ele_Code    Unit    Y1961    Y1962   Y1963
2      Afghanistan  15          Wheat   5312        Ha      10       20      30
2      Afghanistan  25          Maize   5312        Ha      10       20      30
4      Angola       15          Wheat   7312        Ha      30       40      50
4      Angola       25          Maize   7312        Ha      30       40      50

Quiero agrupar por la columna Country y Item_Code y solo calcular la suma de las filas que caen debajo de las columnas Y1961, Y1962 e Y1963. El marco de datos resultante debería verse así:

Code   Country      Item_Code   Item    Ele_Code    Unit    Y1961    Y1962   Y1963
2      Afghanistan  15          C3      5312        Ha      20       40       60
4      Angola       25          C4      7312        Ha      60       80      100

Ahora mismo estoy haciendo esto:

df.groupby('Country').sum()

Sin embargo, esto también suma los valores en la columna Item_Code. ¿Hay alguna forma de que pueda especificar qué columnas incluir en la sum()operación y cuáles excluir?

user308827
fuente

Respuestas:

117

Puede seleccionar las columnas de un grupo por:

In [11]: df.groupby(['Country', 'Item_Code'])[["Y1961", "Y1962", "Y1963"]].sum()
Out[11]:
                       Y1961  Y1962  Y1963
Country     Item_Code
Afghanistan 15            10     20     30
            25            10     20     30
Angola      15            30     40     50
            25            30     40     50

Tenga en cuenta que la lista pasada debe ser un subconjunto de las columnas; de lo contrario, verá un KeyError.

Andy Hayden
fuente
1
¿Cómo incluir el recuento de registros para cada país y código de artículo como otra columna?
Sushant Kulkarni
Puede crear una columna ficticia antes de agrupar por que solo contenga 1. luego sum los sumará creando un conteo.
Matt W.
Si solo desea excluir una columna o dos, obtiene todos los nombres de las columnas como en, listColumns = list(df.columns)luego elimina las columnas que no desea listColumns.remove('Y1964')y finalmente hace su resumen:df.groupby(['Country', 'Item_Code'])[listColumns].sum()
Roberto Stelling
Muchas gracias. Puedo hacer que el groupby funcione, pero no la parte de selección. La lista de columnas que puse está entre el marco de datos, pero sigue aumentando ValueError:cannot reindex from a duplicate axis
Bowen Liu
@BowenLiu si tiene varias columnas con el mismo nombre, mostrará este error. En este caso, tendrá que usar iloc to o loc para obtener las columnas que desee, creo que tendrá que hacerlo antes del groupby.
Andy Hayden
40

La aggfunción hará esto por ti. Pase las columnas y funcione como un dictado con columna, salida:

df.groupby(['Country', 'Item_Code']).agg({'Y1961': np.sum, 'Y1962': [np.sum, np.mean]})  # Added example for two output columns from a single input column

Esto mostrará solo el grupo por columnas y las columnas agregadas especificadas. En este ejemplo incluí dos funciones agg aplicadas a 'Y1962'.

Para obtener exactamente lo que esperaba ver, incluya las otras columnas en el grupo y aplique sumas a las variables Y en el marco:

df.groupby(['Code', 'Country', 'Item_Code', 'Item', 'Ele_Code', 'Unit']).agg({'Y1961': np.sum, 'Y1962': np.sum, 'Y1963': np.sum})
leroyJr
fuente
1
gracias, esto se puede generalizar? Tengo muchas columnas con el formato Y1961 ... así que genero una lista como esta: yrs = ['Y' + str (x) para x en el rango (1961, 2010 + 1, 1)]. ¿Puede su solución usar 'yrs' inside agg?
user308827
De veras me gusta esta idea. El truco es construir este dict con el valor de la función de suma numérica. Sin embargo, a la inversa, si todo lo que quiere hacer es sumar todas las columnas restantes, su solución original funcionaría si todo el grupo por columnas se incluye en el grupo por declaración.
leroyJr
11

Si está buscando una forma más generalizada de aplicar a muchas columnas, lo que puede hacer es crear una lista de nombres de columna y pasarla como índice del marco de datos agrupado. En su caso, por ejemplo:

columns = ['Y'+str(i) for year in range(1967, 2011)]

df.groupby('Country')[columns].agg('sum')
Superestrella
fuente