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