pandas tiene una clase de objetos llamados GroupedDataFrame que permite agrupar las filas (o columnas) de un DataFrame.
Para crear dataframes agrupados, usaremos el método groupby. (ver User guide, Group by: split-apply-combine)
import pandas as pd
import numpy as np
from os import path
DATA_DIRECTORY = path.join('..', '..', 'data')
df = pd.DataFrame(
{
"X": ['a', 'a', 'a', 'a', 'b', 'b', 'c', 'c'],
"Y": np.arange(8),
"Z": np.arange(8,16)
}
)
df
| X | Y | Z | |
|---|---|---|---|
| 0 | a | 0 | 8 |
| 1 | a | 1 | 9 |
| 2 | a | 2 | 10 |
| 3 | a | 3 | 11 |
| 4 | b | 4 | 12 |
| 5 | b | 5 | 13 |
| 6 | c | 6 | 14 |
| 7 | c | 7 | 15 |
Agrupamos según los valores de la columna X
agrupados = df.groupby('X')
Podemos iterar un GroupedDataFrame para recorrer los grupos:
for n, g in agrupados:
print(f'Nombre del grupo: {n}')
print(g)
Nombre del grupo: a X Y Z 0 a 0 8 1 a 1 9 2 a 2 10 3 a 3 11 Nombre del grupo: b X Y Z 4 b 4 12 5 b 5 13 Nombre del grupo: c X Y Z 6 c 6 14 7 c 7 15
Podemos aplicarle métodos preparados para GroupedDataFrame como mean, sum o describe
agrupados.mean()
| Y | Z | |
|---|---|---|
| X | ||
| a | 1.5 | 9.5 |
| b | 4.5 | 12.5 |
| c | 6.5 | 14.5 |
Nos devuelve el valor de la media por grupos de las dos columnas Y y Z.
agrupados.sum()
| Y | Z | |
|---|---|---|
| X | ||
| a | 6 | 38 |
| b | 9 | 25 |
| c | 13 | 29 |
agrupados.describe()
| Y | Z | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | mean | std | min | 25% | 50% | 75% | max | count | mean | std | min | 25% | 50% | 75% | max | |
| X | ||||||||||||||||
| a | 4.0 | 1.5 | 1.290994 | 0.0 | 0.75 | 1.5 | 2.25 | 3.0 | 4.0 | 9.5 | 1.290994 | 8.0 | 8.75 | 9.5 | 10.25 | 11.0 |
| b | 2.0 | 4.5 | 0.707107 | 4.0 | 4.25 | 4.5 | 4.75 | 5.0 | 2.0 | 12.5 | 0.707107 | 12.0 | 12.25 | 12.5 | 12.75 | 13.0 |
| c | 2.0 | 6.5 | 0.707107 | 6.0 | 6.25 | 6.5 | 6.75 | 7.0 | 2.0 | 14.5 | 0.707107 | 14.0 | 14.25 | 14.5 | 14.75 | 15.0 |
Para ilustrarlo, cargamos el DataFrame de flights que contiene todos los vuelos que salieron de los tres aeropuertos de NYC en 2013.
flights = pd.read_feather(path.join(DATA_DIRECTORY, 'flights.feather'))
flights
| year | month | day | dep_time | sched_dep_time | dep_delay | arr_time | sched_arr_time | arr_delay | carrier | flight | tailnum | origin | dest | air_time | distance | hour | minute | time_hour | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2013 | 1 | 1 | 517.0 | 515 | 2.0 | 830.0 | 819 | 11.0 | UA | 1545 | N14228 | EWR | IAH | 227.0 | 1400.0 | 5.0 | 15.0 | 2013-01-01 05:00:00-05:00 |
| 1 | 2013 | 1 | 1 | 533.0 | 529 | 4.0 | 850.0 | 830 | 20.0 | UA | 1714 | N24211 | LGA | IAH | 227.0 | 1416.0 | 5.0 | 29.0 | 2013-01-01 05:00:00-05:00 |
| 2 | 2013 | 1 | 1 | 542.0 | 540 | 2.0 | 923.0 | 850 | 33.0 | AA | 1141 | N619AA | JFK | MIA | 160.0 | 1089.0 | 5.0 | 40.0 | 2013-01-01 05:00:00-05:00 |
| 3 | 2013 | 1 | 1 | 544.0 | 545 | -1.0 | 1004.0 | 1022 | -18.0 | B6 | 725 | N804JB | JFK | BQN | 183.0 | 1576.0 | 5.0 | 45.0 | 2013-01-01 05:00:00-05:00 |
| 4 | 2013 | 1 | 1 | 554.0 | 600 | -6.0 | 812.0 | 837 | -25.0 | DL | 461 | N668DN | LGA | ATL | 116.0 | 762.0 | 6.0 | 0.0 | 2013-01-01 06:00:00-05:00 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 336771 | 2013 | 9 | 30 | NaN | 1455 | NaN | NaN | 1634 | NaN | 9E | 3393 | None | JFK | DCA | NaN | 213.0 | 14.0 | 55.0 | 2013-09-30 14:00:00-04:00 |
| 336772 | 2013 | 9 | 30 | NaN | 2200 | NaN | NaN | 2312 | NaN | 9E | 3525 | None | LGA | SYR | NaN | 198.0 | 22.0 | 0.0 | 2013-09-30 22:00:00-04:00 |
| 336773 | 2013 | 9 | 30 | NaN | 1210 | NaN | NaN | 1330 | NaN | MQ | 3461 | N535MQ | LGA | BNA | NaN | 764.0 | 12.0 | 10.0 | 2013-09-30 12:00:00-04:00 |
| 336774 | 2013 | 9 | 30 | NaN | 1159 | NaN | NaN | 1344 | NaN | MQ | 3572 | N511MQ | LGA | CLE | NaN | 419.0 | 11.0 | 59.0 | 2013-09-30 11:00:00-04:00 |
| 336775 | 2013 | 9 | 30 | NaN | 840 | NaN | NaN | 1020 | NaN | MQ | 3531 | N839MQ | LGA | RDU | NaN | 431.0 | 8.0 | 40.0 | 2013-09-30 08:00:00-04:00 |
336776 rows × 19 columns
Agrupamos los vuelos para hacer recuentos desglosados por mes y por aeropuerto de origen
agrupados = flights.groupby(['month', 'origin'])
Aplicamos el método size para hacer el recuento de filas (vuelos) por grupo:
agrupados.size()
month origin
1 EWR 9893
JFK 9161
LGA 7950
2 EWR 9107
JFK 8421
LGA 7423
3 EWR 10420
JFK 9697
LGA 8717
4 EWR 10531
JFK 9218
LGA 8581
5 EWR 10592
JFK 9397
LGA 8807
6 EWR 10175
JFK 9472
LGA 8596
7 EWR 10475
JFK 10023
LGA 8927
8 EWR 10359
JFK 9983
LGA 8985
9 EWR 9550
JFK 8908
LGA 9116
10 EWR 10104
JFK 9143
LGA 9642
11 EWR 9707
JFK 8710
LGA 8851
12 EWR 9922
JFK 9146
LGA 9067
dtype: int64
Para ilustrarlo, cargamos el fichero mompean
mompean = pd.read_csv(path.join(DATA_DIRECTORY, 'mompean.csv'), parse_dates=['FechaHora'], index_col='FechaHora')
mompean
| NO | NO2 | SO2 | O3 | TMP | HR | NOX | DD | PRB | RS | VV | C6H6 | C7H8 | XIL | PM10 | Ruido | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| FechaHora | ||||||||||||||||
| 2010-01-01 00:00:00 | 4.0 | 7.0 | 17.0 | NaN | NaN | NaN | 14.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 5.0 | 56.0 |
| 2010-01-01 01:00:00 | 6.0 | 12.0 | 18.0 | NaN | NaN | NaN | 21.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 15.0 | 58.0 |
| 2010-01-01 02:00:00 | 6.0 | 17.0 | 17.0 | NaN | NaN | NaN | 26.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 12.0 | 60.0 |
| 2010-01-01 03:00:00 | 5.0 | 10.0 | 18.0 | NaN | NaN | NaN | 18.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 2.0 | 57.0 |
| 2010-01-01 04:00:00 | 4.0 | 8.0 | 19.0 | NaN | NaN | NaN | 14.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 5.0 | 55.0 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 2019-12-31 19:00:00 | 9.0 | 35.0 | 8.0 | 47.0 | NaN | NaN | 49.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 19.0 | NaN |
| 2019-12-31 20:00:00 | 29.0 | 59.0 | 9.0 | 24.0 | NaN | NaN | 102.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 41.0 | NaN |
| 2019-12-31 21:00:00 | 59.0 | 65.0 | 8.0 | 10.0 | NaN | NaN | 155.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 48.0 | NaN |
| 2019-12-31 22:00:00 | 51.0 | 51.0 | 9.0 | 11.0 | NaN | NaN | 130.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 45.0 | NaN |
| 2019-12-31 23:00:00 | 32.0 | 42.0 | 9.0 | 7.0 | NaN | NaN | 90.0 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 44.0 | NaN |
96408 rows × 16 columns
Queremos crear grupos que correspondan a las distintas horas del día, para ver si hay diferencias en el patrón horario de contaminación.
Para ello, pasamos a groupby una función que se aplique a las etiquetas de las filas (index) y que extraiga la hora de un objeto de tipo dtime
agrupados = mompean.groupby(lambda x: x.hour)
Hemos usado una función anónima. Aplicamos el método mean
agrupados.mean()
| NO | NO2 | SO2 | O3 | TMP | HR | NOX | DD | PRB | RS | VV | C6H6 | C7H8 | XIL | PM10 | Ruido | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 9.618014 | 27.402604 | 7.516146 | 53.871709 | NaN | NaN | 42.020890 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 24.416717 | 57.280031 |
| 1 | 7.779196 | 25.304997 | 7.399091 | 51.332306 | NaN | NaN | 37.115698 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 22.790531 | 55.935533 |
| 2 | 6.599348 | 22.842077 | 7.323167 | 49.531390 | NaN | NaN | 32.844795 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 21.687349 | 54.259800 |
| 3 | 4.858891 | 19.067700 | 7.234885 | 48.993829 | NaN | NaN | 26.410005 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 20.119487 | 53.249424 |
| 4 | 4.147523 | 16.349483 | 7.184957 | 48.060045 | NaN | NaN | 22.607512 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 18.802399 | 52.396618 |
| 5 | 4.095316 | 15.585240 | 7.150509 | 45.970250 | NaN | NaN | 21.786220 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 17.874605 | 51.653077 |
| 6 | 5.992364 | 18.083174 | 7.177069 | 41.162830 | NaN | NaN | 27.149168 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 17.907378 | 53.046959 |
| 7 | 12.616621 | 25.141144 | 7.252747 | 33.026404 | NaN | NaN | 44.355586 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 20.484621 | 56.916923 |
| 8 | 18.700545 | 30.695095 | 7.376575 | 27.968004 | NaN | NaN | 59.242234 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 24.919906 | 59.568129 |
| 9 | 34.211874 | 36.715686 | 7.711188 | 26.932959 | NaN | NaN | 89.038399 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 32.868169 | 60.270978 |
| 10 | 26.159482 | 32.184573 | 7.810072 | 39.895430 | NaN | NaN | 72.175290 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 34.702703 | 60.947096 |
| 11 | 13.300164 | 25.110716 | 7.697393 | 55.724283 | NaN | NaN | 45.379716 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 29.696712 | 61.313124 |
| 12 | 9.329697 | 22.087810 | 7.825563 | 65.378219 | NaN | NaN | 36.264249 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 27.035784 | 61.997703 |
| 13 | 8.356833 | 20.896150 | 7.995197 | 71.142339 | NaN | NaN | 33.565618 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 25.787697 | 62.338168 |
| 14 | 7.735246 | 19.927721 | 8.148641 | 75.562849 | NaN | NaN | 31.660531 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 24.944570 | 62.381679 |
| 15 | 7.167794 | 18.990257 | 8.609205 | 78.299637 | NaN | NaN | 29.848714 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 23.915736 | 61.678380 |
| 16 | 6.474696 | 17.648714 | 8.834398 | 80.232617 | NaN | NaN | 27.457645 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 23.579356 | 60.812404 |
| 17 | 6.404491 | 18.028950 | 9.035134 | 80.065624 | NaN | NaN | 27.702922 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 24.367599 | 60.751149 |
| 18 | 6.553600 | 20.003249 | 9.063149 | 77.836409 | NaN | NaN | 29.928803 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 24.708589 | 61.220352 |
| 19 | 7.001896 | 23.205038 | 8.684084 | 73.640817 | NaN | NaN | 33.828548 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 24.993455 | 61.569678 |
| 20 | 8.330986 | 25.681203 | 8.342933 | 69.847144 | NaN | NaN | 38.321506 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 25.506697 | 61.812261 |
| 21 | 10.382592 | 28.194685 | 7.983729 | 65.330907 | NaN | NaN | 43.979393 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 26.555189 | 61.722265 |
| 22 | 11.746273 | 29.620222 | 7.777807 | 60.919373 | NaN | NaN | 47.500678 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 26.788431 | 60.703675 |
| 23 | 12.008955 | 29.771235 | 7.646823 | 56.430933 | NaN | NaN | 48.046676 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 25.949129 | 58.908046 |
groupby¶Pasamos una lista de funciones
agrupados = mompean.groupby([lambda x: x.dayofweek, lambda x: x.hour])
Calculamos la media desglosada por grupo:
agrupados.mean()
| NO | NO2 | SO2 | O3 | TMP | HR | NOX | DD | PRB | RS | VV | C6H6 | C7H8 | XIL | PM10 | Ruido | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0 | 7.562380 | 25.581574 | 7.512287 | 55.924303 | NaN | NaN | 37.084453 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 22.472486 | 57.027624 |
| 1 | 6.180077 | 23.312261 | 7.435606 | 53.521912 | NaN | NaN | 32.668582 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 20.853890 | 55.419890 | |
| 2 | 5.517241 | 21.136015 | 7.361742 | 51.169323 | NaN | NaN | 29.501916 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 20.206831 | 53.508287 | |
| 3 | 4.126437 | 17.105364 | 7.229167 | 50.878486 | NaN | NaN | 23.373563 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 18.842505 | 52.569061 | |
| 4 | 3.624521 | 14.111111 | 7.143939 | 50.537849 | NaN | NaN | 19.616858 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 17.838710 | 51.806630 | |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 6 | 19 | 5.676245 | 18.860153 | 8.581132 | 77.117296 | NaN | NaN | 27.421456 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 22.644612 | 60.044199 |
| 20 | 6.545977 | 20.641762 | 8.330189 | 73.753479 | NaN | NaN | 30.588123 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 22.718336 | 60.364641 | |
| 21 | 7.767754 | 23.921305 | 7.835539 | 68.711155 | NaN | NaN | 35.700576 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 23.905303 | 60.569061 | |
| 22 | 8.694818 | 26.278311 | 7.667297 | 63.896414 | NaN | NaN | 39.462572 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 23.990512 | 59.972376 | |
| 23 | 9.168906 | 27.220729 | 7.655955 | 59.272908 | NaN | NaN | 41.084453 | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 23.339658 | 58.375691 |
168 rows × 16 columns