💡 Si el botó no funciona: Copia i enganxa aquesta URL al teu navegador: https://colab.research.google.com/github/wisaaco/TallerPythonFEE/blob/main/notebooks/5_PandasGroups.ipynb
Unitat 5. Agrupacions de dades
Les agrupacions són operacions necessàries per a analitzar dades, ja que permeten extreure informació en funció de dades categòriques del nostre dataframe.
Començarem aquest aprenentatge amb les següents dades
[2]:
import pandas as pd
from tabulate import tabulate # Nova llibreria
df = pd.read_csv("data/data_groups.csv") # Atenció: Dades creades aleatòriament !!
print(tabulate(df.head(), headers='keys'))
print("-"*30)
print(df.columns)
print("-"*30)
print(df.shape)
Unnamed: 0 Dni Nom CP Ciutat Genere Tipus certificat cat Punts
-- ------------ --------- ---------------------------- ---- ---------- -------- ---------------------- -------
0 0 H61414629 María Dolores Arjona Jove 7800 Eivissa M B 73
1 1 S3138381C Núria Quirós 7511 Ruberts F A 40
2 2 J8698188C Miguel José María Gil Vargas 7340 Alaro M A 45
3 3 A48821615 Jordi Chaves Bustamante 7609 Bellavista F B 40
4 4 U0247281I Jana Rosa Collado Menéndez 7006 Palma M B 86
------------------------------
Index(['Unnamed: 0', 'Dni', 'Nom', 'CP', 'Ciutat', 'Genere',
'Tipus certificat cat', 'Punts'],
dtype='object')
------------------------------
(1000, 8)
A.4.0 Activitats “d’escalfament”
[3]:
#A401 - Quines i quantes ciutats n'hi ha?
[4]:
#A402 - Suprimeix la columna primera: "Unnamed: 0"
[5]:
#A403 - Llista les files 3, 4 i 5 amb les columnes de Nom i Punts
[6]:
#A404 - Crea dues columnes noves amb nom i llinatges de l'actual columna de "Nom".
[7]:
#A405 - Quantes categories de "Tipus de certificat cat" ?
Groups
Per a agrupar només cal usar el mètode de groupby.
En el següent exemple agrupem les dades segons el sexe de la persona mitjançant el mètode groupby que retorna un DataFrame agrupat:
[8]:
bySex = df.groupby('Genere')
type(bySex)
[8]:
pandas.core.groupby.generic.DataFrameGroupBy
[9]:
print(bySex)
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x135151850>
[10]:
bySex
[10]:
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x135151850>
Una agupació té sentit quan se fà qualque tipus d’agregació de dades. Ara mateix la variable bySex només te informació computacional que separa els elements de cada tipus de grup. Hem de fer qualque operació, com per exemple, describe()
[11]:
# Podem descriure la informació d'un "[DataFrame]Groupby"
bySex.describe()
[11]:
| Unnamed: 0 | CP | Punts | |||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | mean | std | min | 25% | 50% | 75% | max | count | mean | ... | 75% | max | count | mean | std | min | 25% | 50% | 75% | max | |
| Genere | |||||||||||||||||||||
| F | 483.0 | 503.248447 | 290.076225 | 1.0 | 245.0 | 496.0 | 757.5 | 999.0 | 483.0 | 7519.567288 | ... | 7701.0 | 7870.0 | 483.0 | 50.084886 | 28.548551 | 1.0 | 24.5 | 50.0 | 74.0 | 99.0 |
| M | 517.0 | 495.998066 | 287.877191 | 0.0 | 253.0 | 502.0 | 744.0 | 998.0 | 517.0 | 7533.143133 | ... | 7701.0 | 7870.0 | 517.0 | 49.321083 | 28.504273 | 1.0 | 24.0 | 50.0 | 73.0 | 99.0 |
2 rows × 24 columns
Només guarda quins elements pertanyen a cada categoria. L’atribut groups ens mostra quines mostres/files pertanyen a cada grup:
[12]:
bySex.groups # Quin tipus de variable és? Quina informació conté?
[12]:
{'F': [1, 3, 6, 7, 8, 9, 12, 23, 25, 26, 28, 29, 32, 33, 35, 36, 38, 42, 43, 44, 45, 48, 53, 54, 57, 58, 59, 63, 65, 70, 71, 72, 79, 80, 81, 82, 84, 87, 88, 92, 94, 95, 97, 98, 99, 103, 105, 106, 107, 108, 111, 112, 115, 116, 117, 118, 120, 125, 128, 129, 132, 134, 135, 136, 137, 138, 140, 141, 142, 143, 144, 147, 148, 150, 151, 153, 154, 155, 156, 161, 162, 163, 164, 165, 168, 170, 172, 174, 175, 176, 177, 178, 179, 181, 182, 184, 185, 188, 194, 196, ...], 'M': [0, 2, 4, 5, 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 27, 30, 31, 34, 37, 39, 40, 41, 46, 47, 49, 50, 51, 52, 55, 56, 60, 61, 62, 64, 66, 67, 68, 69, 73, 74, 75, 76, 77, 78, 83, 85, 86, 89, 90, 91, 93, 96, 100, 101, 102, 104, 109, 110, 113, 114, 119, 121, 122, 123, 124, 126, 127, 130, 131, 133, 139, 145, 146, 149, 152, 157, 158, 159, 160, 166, 167, 169, 171, 173, 180, 183, 186, 187, 189, 190, 191, 192, 193, 195, 197, 199, 201, ...]}
Aquest atribut, (un dictionari) ens permet realitzar operacions de filtrat en funció dels grups:
[13]:
dfM = df.loc[bySex.groups['M'].values] #Recorda que "loc" accedeix per index de fila
dfM
[13]:
| Unnamed: 0 | Dni | Nom | CP | Ciutat | Genere | Tipus certificat cat | Punts | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | H61414629 | María Dolores Arjona Jove | 7800 | Eivissa | M | B | 73 |
| 2 | 2 | J8698188C | Miguel José María Gil Vargas | 7340 | Alaro | M | A | 45 |
| 4 | 4 | U0247281I | Jana Rosa Collado Menéndez | 7006 | Palma | M | B | 86 |
| 5 | 5 | V3761435A | Antonio Murillo Suarez | 7701 | Mao | M | B | 53 |
| 10 | 10 | A64863723 | Nil Mínguez Hervás | 7350 | Binissalem | M | B | 17 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 991 | 991 | G28994028 | Juan Cervera Arribas | 7006 | Palma | M | B | 83 |
| 993 | 993 | J3906733E | Josefa María Dolores Barreda Ibañez | 7609 | Bellavista | M | B | 17 |
| 994 | 994 | C26665125 | Josefa Ferrando-Navas | 7340 | Alaro | M | A | 56 |
| 996 | 996 | H72967045 | Álex Javier Campos Palomar | 7701 | Mao | M | B | 72 |
| 998 | 998 | C61296679 | Èric Pinedo | 7009 | Palma | M | A | 1 |
517 rows × 8 columns
Obviament: Segons el tipus d’agrupació, l’operació pot realitzar-se com una selecció lògica.
[15]:
df[df.Genere=="M"]
[15]:
| Unnamed: 0 | Dni | Nom | CP | Ciutat | Genere | Tipus certificat cat | Punts | |
|---|---|---|---|---|---|---|---|---|
| 0 | 0 | H61414629 | María Dolores Arjona Jove | 7800 | Eivissa | M | B | 73 |
| 2 | 2 | J8698188C | Miguel José María Gil Vargas | 7340 | Alaro | M | A | 45 |
| 4 | 4 | U0247281I | Jana Rosa Collado Menéndez | 7006 | Palma | M | B | 86 |
| 5 | 5 | V3761435A | Antonio Murillo Suarez | 7701 | Mao | M | B | 53 |
| 10 | 10 | A64863723 | Nil Mínguez Hervás | 7350 | Binissalem | M | B | 17 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 991 | 991 | G28994028 | Juan Cervera Arribas | 7006 | Palma | M | B | 83 |
| 993 | 993 | J3906733E | Josefa María Dolores Barreda Ibañez | 7609 | Bellavista | M | B | 17 |
| 994 | 994 | C26665125 | Josefa Ferrando-Navas | 7340 | Alaro | M | A | 56 |
| 996 | 996 | H72967045 | Álex Javier Campos Palomar | 7701 | Mao | M | B | 72 |
| 998 | 998 | C61296679 | Èric Pinedo | 7009 | Palma | M | A | 1 |
517 rows × 8 columns
[17]:
#Cada dataframegroupby te dos elements: el id-value del grup i el df de elements d'aquest grup
for identificador, group in df.groupby('Genere'):
# Criteri de l'agrupacio: M o F
print("*"*10)
print(identificador)
print("*"*10)
# Dataframe específic
print(group.head())
print("-"*60)
**********
F
**********
Unnamed: 0 Dni Nom CP Ciutat Genere \
1 1 S3138381C Núria Quirós 7511 Ruberts F
3 3 A48821615 Jordi Chaves Bustamante 7609 Bellavista F
6 6 H16936148 Arlet del Rovira 7350 Binissalem F
7 7 E47121991 Emma Tapia Salas 7340 Alaro F
8 8 E15932486 Jana Barrios 7870 La Savina F
Tipus certificat cat Punts
1 A 40
3 B 40
6 A 54
7 C 60
8 A 35
------------------------------------------------------------
**********
M
**********
Unnamed: 0 Dni Nom CP Ciutat \
0 0 H61414629 María Dolores Arjona Jove 7800 Eivissa
2 2 J8698188C Miguel José María Gil Vargas 7340 Alaro
4 4 U0247281I Jana Rosa Collado Menéndez 7006 Palma
5 5 V3761435A Antonio Murillo Suarez 7701 Mao
10 10 A64863723 Nil Mínguez Hervás 7350 Binissalem
Genere Tipus certificat cat Punts
0 M B 73
2 M A 45
4 M B 86
5 M B 53
10 M B 17
------------------------------------------------------------
Agregacions
El mètodo aggregate ens permet crear variables d’agregació sobre la taula obtinguda amb groupby. Indicarem la informació que volem obtenir de cada columna amb un diccionari. Especifiquem la funció que aplicarem a les dades de cada grup en cada columna per a obtenir un únic valor.
[18]:
df.groupby(["Tipus certificat cat"]).aggregate(
{ # Dictionari
"Punts":sum # Columna : Operacion de agregació
}
) #
[18]:
| Punts | |
|---|---|
| Tipus certificat cat | |
| A | 22502 |
| B | 17289 |
| C | 7399 |
| D | 2500 |
Podem aplicar un gran nombre de funcions d’agregació:
Funcions estadístiques: mean, std, …
Funcions matemàtiques: sum, prod, …
Altres funcions: max, min, …
[19]:
df.groupby(["Tipus certificat cat"]).aggregate({"Punts":max})
[19]:
| Punts | |
|---|---|
| Tipus certificat cat | |
| A | 99 |
| B | 99 |
| C | 99 |
| D | 99 |
Si volem incloure la mateixa columna múltiples vegades, hem de fer servir el mètode agg
[20]:
import numpy as np
## Una manera
dftipus = df.groupby(["Tipus certificat cat"]).agg(Maximo=('Punts', max), Minim=('Punts', 'min'), Mitj=('Punts', np.mean))
dftipus
[20]:
| Maximo | Minim | Mitj | |
|---|---|---|---|
| Tipus certificat cat | |||
| A | 99 | 1 | 50.115813 |
| B | 99 | 1 | 49.681034 |
| C | 99 | 1 | 48.045455 |
| D | 99 | 1 | 51.020408 |
[21]:
type(dftipus) #Nota: Una vegada feta una agregació damunt una agrupació obtenim un dataframe !!!
[21]:
pandas.core.frame.DataFrame
[22]:
dftipus[dftipus.Mitj<50]
[22]:
| Maximo | Minim | Mitj | |
|---|---|---|---|
| Tipus certificat cat | |||
| B | 99 | 1 | 49.681034 |
| C | 99 | 1 | 48.045455 |
4.1. Activitats
[23]:
# 4.1.1 Quina estructura té aquest dataframe: shape, index, columns?
[24]:
# 4.1.2 Pots accedir al valor mínim del certificat "C"
[25]:
# 4.1.3 Pots canviar el nom a les columnes a "max punts", "min punts" i "mitjana punts", respectivament.
[26]:
# Una altra manera
dftipus2 = df.groupby(["Tipus certificat cat"]).agg({
'Punts': ['mean', 'count', np.min, np.std],
})
dftipus2
[26]:
| Punts | ||||
|---|---|---|---|---|
| mean | count | amin | std | |
| Tipus certificat cat | ||||
| A | 50.115813 | 449 | 1 | 28.518712 |
| B | 49.681034 | 348 | 1 | 28.271817 |
| C | 48.045455 | 154 | 1 | 27.907724 |
| D | 51.020408 | 49 | 1 | 32.520180 |
[27]:
dftipus2.columns ## ALERTA ! MULTIINDEX
[27]:
MultiIndex([('Punts', 'mean'),
('Punts', 'count'),
('Punts', 'amin'),
('Punts', 'std')],
)
[28]:
#Si volem accedir a una columna específica
dftipus2["Punts"]["mean"] ### Obliga a fer ús d'un conjunt seguit de "keys" de columnes
[28]:
Tipus certificat cat
A 50.115813
B 49.681034
C 48.045455
D 51.020408
Name: mean, dtype: float64
[29]:
dftipus2[("Punts","mean")] ### O fer us del concepte de tupla
[29]:
Tipus certificat cat
A 50.115813
B 49.681034
C 48.045455
D 51.020408
Name: (Punts, mean), dtype: float64
Agrupacions amb múltiples columnes
En una agrupació amb diversos criteris, es creen totes les combinacions possibles entre els criteris donant lloc a un producte cartesià de les agregacions indicades.
[30]:
import numpy as np
dftc = df.groupby(["Tipus certificat cat","Ciutat"]).mean(numeric_only = True)
dftc
[30]:
| Unnamed: 0 | CP | Punts | ||
|---|---|---|---|---|
| Tipus certificat cat | Ciutat | |||
| A | Alaro | 447.929825 | 7340.000000 | 50.789474 |
| Ariany | 547.203704 | 7529.000000 | 52.537037 | |
| Bellavista | 499.148936 | 7609.000000 | 46.787234 | |
| Binissalem | 535.375000 | 7350.000000 | 44.325000 | |
| Eivissa | 504.931818 | 7800.000000 | 52.227273 | |
| La Savina | 468.194444 | 7870.000000 | 47.944444 | |
| Mao | 528.918919 | 7701.864865 | 47.027027 | |
| Palma | 471.918367 | 7009.469388 | 51.081633 | |
| Pedruscada | 475.347826 | 7590.000000 | 56.847826 | |
| Ruberts | 503.487179 | 7511.000000 | 49.128205 | |
| B | Alaro | 485.333333 | 7340.000000 | 52.452381 |
| Ariany | 496.404762 | 7529.000000 | 49.166667 | |
| Bellavista | 540.851852 | 7609.000000 | 44.185185 | |
| Binissalem | 560.909091 | 7350.000000 | 52.787879 | |
| Eivissa | 525.484848 | 7800.000000 | 47.393939 | |
| La Savina | 524.470588 | 7870.000000 | 44.441176 | |
| Mao | 497.040816 | 7701.775510 | 50.673469 | |
| Palma | 493.062500 | 7008.625000 | 55.375000 | |
| Pedruscada | 486.606061 | 7590.000000 | 50.484848 | |
| Ruberts | 391.956522 | 7511.000000 | 47.391304 | |
| C | Alaro | 451.625000 | 7340.000000 | 39.687500 |
| Ariany | 606.583333 | 7529.000000 | 41.833333 | |
| Bellavista | 503.111111 | 7609.000000 | 37.500000 | |
| Binissalem | 478.058824 | 7350.000000 | 67.823529 | |
| Eivissa | 525.777778 | 7800.000000 | 41.444444 | |
| La Savina | 508.357143 | 7870.000000 | 52.500000 | |
| Mao | 433.428571 | 7701.857143 | 52.428571 | |
| Palma | 371.333333 | 7011.666667 | 33.083333 | |
| Pedruscada | 554.000000 | 7590.000000 | 53.166667 | |
| Ruberts | 541.823529 | 7511.000000 | 51.235294 | |
| D | Alaro | 203.200000 | 7340.000000 | 66.800000 |
| Ariany | 446.600000 | 7529.000000 | 47.200000 | |
| Bellavista | 728.833333 | 7609.000000 | 56.333333 | |
| Binissalem | 470.000000 | 7350.000000 | 67.666667 | |
| Eivissa | 581.800000 | 7800.000000 | 35.800000 | |
| La Savina | 455.333333 | 7870.000000 | 43.000000 | |
| Mao | 467.000000 | 7703.000000 | 20.000000 | |
| Palma | 613.666667 | 7008.000000 | 30.333333 | |
| Pedruscada | 496.777778 | 7590.000000 | 66.777778 | |
| Ruberts | 636.833333 | 7511.000000 | 40.000000 |
Observacions
És necessari la mitja de “CP”?
4.2 Activitat
[31]:
# 4.2.1 Fes que només surti la columna de "Punts" a l'agrupació anterior.
[32]:
# 4.2.2 Pots seleccionar només les mostres de Mao.
[33]:
# 4.2.3 Com podries calcular la mida de cada grup?
MultIndex
A vegades un índex no és suficient per expressar la meta-informació que identifica una o algunes columnes. Per exemple, una coordenada està formada per la latitud i longitud.
Un multindex és una jerarquia d’índexs.
Una agrupació amb diferents criteris origina un multiindex
[34]:
dftc = df.groupby(["Tipus certificat cat","Ciutat"]).mean(numeric_only = True) # evitant el futureWarning...
dftc
[34]:
| Unnamed: 0 | CP | Punts | ||
|---|---|---|---|---|
| Tipus certificat cat | Ciutat | |||
| A | Alaro | 447.929825 | 7340.000000 | 50.789474 |
| Ariany | 547.203704 | 7529.000000 | 52.537037 | |
| Bellavista | 499.148936 | 7609.000000 | 46.787234 | |
| Binissalem | 535.375000 | 7350.000000 | 44.325000 | |
| Eivissa | 504.931818 | 7800.000000 | 52.227273 | |
| La Savina | 468.194444 | 7870.000000 | 47.944444 | |
| Mao | 528.918919 | 7701.864865 | 47.027027 | |
| Palma | 471.918367 | 7009.469388 | 51.081633 | |
| Pedruscada | 475.347826 | 7590.000000 | 56.847826 | |
| Ruberts | 503.487179 | 7511.000000 | 49.128205 | |
| B | Alaro | 485.333333 | 7340.000000 | 52.452381 |
| Ariany | 496.404762 | 7529.000000 | 49.166667 | |
| Bellavista | 540.851852 | 7609.000000 | 44.185185 | |
| Binissalem | 560.909091 | 7350.000000 | 52.787879 | |
| Eivissa | 525.484848 | 7800.000000 | 47.393939 | |
| La Savina | 524.470588 | 7870.000000 | 44.441176 | |
| Mao | 497.040816 | 7701.775510 | 50.673469 | |
| Palma | 493.062500 | 7008.625000 | 55.375000 | |
| Pedruscada | 486.606061 | 7590.000000 | 50.484848 | |
| Ruberts | 391.956522 | 7511.000000 | 47.391304 | |
| C | Alaro | 451.625000 | 7340.000000 | 39.687500 |
| Ariany | 606.583333 | 7529.000000 | 41.833333 | |
| Bellavista | 503.111111 | 7609.000000 | 37.500000 | |
| Binissalem | 478.058824 | 7350.000000 | 67.823529 | |
| Eivissa | 525.777778 | 7800.000000 | 41.444444 | |
| La Savina | 508.357143 | 7870.000000 | 52.500000 | |
| Mao | 433.428571 | 7701.857143 | 52.428571 | |
| Palma | 371.333333 | 7011.666667 | 33.083333 | |
| Pedruscada | 554.000000 | 7590.000000 | 53.166667 | |
| Ruberts | 541.823529 | 7511.000000 | 51.235294 | |
| D | Alaro | 203.200000 | 7340.000000 | 66.800000 |
| Ariany | 446.600000 | 7529.000000 | 47.200000 | |
| Bellavista | 728.833333 | 7609.000000 | 56.333333 | |
| Binissalem | 470.000000 | 7350.000000 | 67.666667 | |
| Eivissa | 581.800000 | 7800.000000 | 35.800000 | |
| La Savina | 455.333333 | 7870.000000 | 43.000000 | |
| Mao | 467.000000 | 7703.000000 | 20.000000 | |
| Palma | 613.666667 | 7008.000000 | 30.333333 | |
| Pedruscada | 496.777778 | 7590.000000 | 66.777778 | |
| Ruberts | 636.833333 | 7511.000000 | 40.000000 |
[35]:
dftc.index
[35]:
MultiIndex([('A', 'Alaro'),
('A', 'Ariany'),
('A', 'Bellavista'),
('A', 'Binissalem'),
('A', 'Eivissa'),
('A', 'La Savina'),
('A', 'Mao'),
('A', 'Palma'),
('A', 'Pedruscada'),
('A', 'Ruberts'),
('B', 'Alaro'),
('B', 'Ariany'),
('B', 'Bellavista'),
('B', 'Binissalem'),
('B', 'Eivissa'),
('B', 'La Savina'),
('B', 'Mao'),
('B', 'Palma'),
('B', 'Pedruscada'),
('B', 'Ruberts'),
('C', 'Alaro'),
('C', 'Ariany'),
('C', 'Bellavista'),
('C', 'Binissalem'),
('C', 'Eivissa'),
('C', 'La Savina'),
('C', 'Mao'),
('C', 'Palma'),
('C', 'Pedruscada'),
('C', 'Ruberts'),
('D', 'Alaro'),
('D', 'Ariany'),
('D', 'Bellavista'),
('D', 'Binissalem'),
('D', 'Eivissa'),
('D', 'La Savina'),
('D', 'Mao'),
('D', 'Palma'),
('D', 'Pedruscada'),
('D', 'Ruberts')],
names=['Tipus certificat cat', 'Ciutat'])
[36]:
dftc.loc["A"] # primer index
[36]:
| Unnamed: 0 | CP | Punts | |
|---|---|---|---|
| Ciutat | |||
| Alaro | 447.929825 | 7340.000000 | 50.789474 |
| Ariany | 547.203704 | 7529.000000 | 52.537037 |
| Bellavista | 499.148936 | 7609.000000 | 46.787234 |
| Binissalem | 535.375000 | 7350.000000 | 44.325000 |
| Eivissa | 504.931818 | 7800.000000 | 52.227273 |
| La Savina | 468.194444 | 7870.000000 | 47.944444 |
| Mao | 528.918919 | 7701.864865 | 47.027027 |
| Palma | 471.918367 | 7009.469388 | 51.081633 |
| Pedruscada | 475.347826 | 7590.000000 | 56.847826 |
| Ruberts | 503.487179 | 7511.000000 | 49.128205 |
[37]:
dftc.loc["Mao"] # dependent index ??? COM ES POT ACCEDIR?
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexes/base.py:3802, in Index.get_loc(self, key, method, tolerance)
3801 try:
-> 3802 return self._engine.get_loc(casted_key)
3803 except KeyError as err:
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/_libs/index.pyx:138, in pandas._libs.index.IndexEngine.get_loc()
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/_libs/index.pyx:165, in pandas._libs.index.IndexEngine.get_loc()
File pandas/_libs/hashtable_class_helper.pxi:5745, in pandas._libs.hashtable.PyObjectHashTable.get_item()
File pandas/_libs/hashtable_class_helper.pxi:5753, in pandas._libs.hashtable.PyObjectHashTable.get_item()
KeyError: 'Mao'
The above exception was the direct cause of the following exception:
KeyError Traceback (most recent call last)
Cell In[37], line 1
----> 1 dftc.loc["Mao"] # dependent index ??? COM ES POT ACCEDIR?
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexing.py:1073, in _LocationIndexer.__getitem__(self, key)
1070 axis = self.axis or 0
1072 maybe_callable = com.apply_if_callable(key, self.obj)
-> 1073 return self._getitem_axis(maybe_callable, axis=axis)
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexing.py:1312, in _LocIndexer._getitem_axis(self, key, axis)
1310 # fall thru to straight lookup
1311 self._validate_key(key, axis)
-> 1312 return self._get_label(key, axis=axis)
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexing.py:1260, in _LocIndexer._get_label(self, label, axis)
1258 def _get_label(self, label, axis: int):
1259 # GH#5567 this will fail if the label is not present in the axis.
-> 1260 return self.obj.xs(label, axis=axis)
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/generic.py:4049, in NDFrame.xs(self, key, axis, level, drop_level)
4046 self._consolidate_inplace()
4048 if isinstance(index, MultiIndex):
-> 4049 loc, new_index = index._get_loc_level(key, level=0)
4050 if not drop_level:
4051 if lib.is_integer(loc):
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexes/multi.py:3160, in MultiIndex._get_loc_level(self, key, level)
3158 return indexer, maybe_mi_droplevels(indexer, ilevels)
3159 else:
-> 3160 indexer = self._get_level_indexer(key, level=level)
3161 if (
3162 isinstance(key, str)
3163 and self.levels[level]._supports_partial_string_indexing
3164 ):
3165 # check to see if we did an exact lookup vs sliced
3166 check = self.levels[level].get_loc(key)
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexes/multi.py:3263, in MultiIndex._get_level_indexer(self, key, level, indexer)
3259 return slice(i, j, step)
3261 else:
-> 3263 idx = self._get_loc_single_level_index(level_index, key)
3265 if level > 0 or self._lexsort_depth == 0:
3266 # Desired level is not sorted
3267 if isinstance(idx, slice):
3268 # test_get_loc_partial_timestamp_multiindex
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexes/multi.py:2849, in MultiIndex._get_loc_single_level_index(self, level_index, key)
2847 return -1
2848 else:
-> 2849 return level_index.get_loc(key)
File ~/.pyenv/versions/my3110/lib/python3.11/site-packages/pandas/core/indexes/base.py:3804, in Index.get_loc(self, key, method, tolerance)
3802 return self._engine.get_loc(casted_key)
3803 except KeyError as err:
-> 3804 raise KeyError(key) from err
3805 except TypeError:
3806 # If we have a listlike key, _check_indexing_error will raise
3807 # InvalidIndexError. Otherwise we fall through and re-raise
3808 # the TypeError.
3809 self._check_indexing_error(key)
KeyError: 'Mao'
[38]:
dftc.loc[("A","Mao")]
[38]:
Unnamed: 0 528.918919
CP 7701.864865
Punts 47.027027
Name: (A, Mao), dtype: float64
[39]:
# Una manera més elegant és:
dftc.loc[pd.IndexSlice[:, 'Mao'],:] # Quins parametres n'hi ha? LOC i IndexSlice
# https://pandas.pydata.org/docs/reference/api/pandas.IndexSlice.html
[39]:
| Unnamed: 0 | CP | Punts | ||
|---|---|---|---|---|
| Tipus certificat cat | Ciutat | |||
| A | Mao | 528.918919 | 7701.864865 | 47.027027 |
| B | Mao | 497.040816 | 7701.775510 | 50.673469 |
| C | Mao | 433.428571 | 7701.857143 | 52.428571 |
| D | Mao | 467.000000 | 7703.000000 | 20.000000 |
[40]:
dfBCMao = dftc.loc[pd.IndexSlice[["B","C"], 'Mao'],"Punts"]
dfBCMao
[40]:
Tipus certificat cat Ciutat
B Mao 50.673469
C Mao 52.428571
Name: Punts, dtype: float64
Una altra opció és aplanar o esborrar l’índex
[41]:
dftc = df.groupby(["Tipus certificat cat","Ciutat"]).mean(numeric_only = True).reset_index()
print(dftc)
Tipus certificat cat Ciutat Unnamed: 0 CP Punts
0 A Alaro 447.929825 7340.000000 50.789474
1 A Ariany 547.203704 7529.000000 52.537037
2 A Bellavista 499.148936 7609.000000 46.787234
3 A Binissalem 535.375000 7350.000000 44.325000
4 A Eivissa 504.931818 7800.000000 52.227273
5 A La Savina 468.194444 7870.000000 47.944444
6 A Mao 528.918919 7701.864865 47.027027
7 A Palma 471.918367 7009.469388 51.081633
8 A Pedruscada 475.347826 7590.000000 56.847826
9 A Ruberts 503.487179 7511.000000 49.128205
10 B Alaro 485.333333 7340.000000 52.452381
11 B Ariany 496.404762 7529.000000 49.166667
12 B Bellavista 540.851852 7609.000000 44.185185
13 B Binissalem 560.909091 7350.000000 52.787879
14 B Eivissa 525.484848 7800.000000 47.393939
15 B La Savina 524.470588 7870.000000 44.441176
16 B Mao 497.040816 7701.775510 50.673469
17 B Palma 493.062500 7008.625000 55.375000
18 B Pedruscada 486.606061 7590.000000 50.484848
19 B Ruberts 391.956522 7511.000000 47.391304
20 C Alaro 451.625000 7340.000000 39.687500
21 C Ariany 606.583333 7529.000000 41.833333
22 C Bellavista 503.111111 7609.000000 37.500000
23 C Binissalem 478.058824 7350.000000 67.823529
24 C Eivissa 525.777778 7800.000000 41.444444
25 C La Savina 508.357143 7870.000000 52.500000
26 C Mao 433.428571 7701.857143 52.428571
27 C Palma 371.333333 7011.666667 33.083333
28 C Pedruscada 554.000000 7590.000000 53.166667
29 C Ruberts 541.823529 7511.000000 51.235294
30 D Alaro 203.200000 7340.000000 66.800000
31 D Ariany 446.600000 7529.000000 47.200000
32 D Bellavista 728.833333 7609.000000 56.333333
33 D Binissalem 470.000000 7350.000000 67.666667
34 D Eivissa 581.800000 7800.000000 35.800000
35 D La Savina 455.333333 7870.000000 43.000000
36 D Mao 467.000000 7703.000000 20.000000
37 D Palma 613.666667 7008.000000 30.333333
38 D Pedruscada 496.777778 7590.000000 66.777778
39 D Ruberts 636.833333 7511.000000 40.000000
[42]:
print(dftc[dftc["Ciutat"]=="Mao"])
Tipus certificat cat Ciutat Unnamed: 0 CP Punts
6 A Mao 528.918919 7701.864865 47.027027
16 B Mao 497.040816 7701.775510 50.673469
26 C Mao 433.428571 7701.857143 52.428571
36 D Mao 467.000000 7703.000000 20.000000
[43]:
print(dftc[dftc["Ciutat"]=="Mao"].Punts) # Quina informació trobeu?
6 47.027027
16 50.673469
26 52.428571
36 20.000000
Name: Punts, dtype: float64
Activitat 4.3
Agrupa els segënts dades per el nom de la escola.
Quina escola té més nins?
Quina escola té els nins més alts?
[44]:
data = {
'school': ['s001', 's002', 's003', 's001', 's002', 's004'],
'class': ['V', 'V', 'VI', 'VI', 'V', 'VI'],
'name': ['Alberto Franco', 'Gino Mcneill', 'Ryan Parkes', 'Eesha Hinton', 'Gino Mcneill', 'David Parkes'],
'date_Of_Birth': ['15/05/2002', '17/05/2002', '16/02/1999', '25/09/1998', '11/05/2002', '15/09/1997'],
'age': [12, 12, 13, 13, 14, 12],
'height': [173, 192, 186, 167, 151, 159],
'weight': [35, 32, 33, 30, 31, 32],
'address': ['street1', 'street2', 'street3', 'street1', 'street2', 'street4']
}
df = pd.DataFrame(data, index=['S1', 'S2', 'S3', 'S4','S5','S6'])
df.head()
[44]:
| school | class | name | date_Of_Birth | age | height | weight | address | |
|---|---|---|---|---|---|---|---|---|
| S1 | s001 | V | Alberto Franco | 15/05/2002 | 12 | 173 | 35 | street1 |
| S2 | s002 | V | Gino Mcneill | 17/05/2002 | 12 | 192 | 32 | street2 |
| S3 | s003 | VI | Ryan Parkes | 16/02/1999 | 13 | 186 | 33 | street3 |
| S4 | s001 | VI | Eesha Hinton | 25/09/1998 | 13 | 167 | 30 | street1 |
| S5 | s002 | V | Gino Mcneill | 11/05/2002 | 14 | 151 | 31 | street2 |
[45]:
#TODO
Donat el següent llistat de vendes:
Quin comprador ha gastat més?
Quin vendedor ha fet més vendes?
[46]:
import pandas as pd
import numpy as np
# Crear datos aleatorios
n = 15
productos = ['Producto ' + str(i) for i in range(1, n+1)]
precios = np.random.randint(10, 100, n)
compradores = np.random.choice(['Juan', 'Pedro', 'Maria', 'Ana'], n)
vendedores = np.random.choice(['Carlos', 'Laura', 'Miguel', 'Elena'], n)
# Crear DataFrame
df_ventas = pd.DataFrame({
'Producto': productos,
'Precio': precios,
'Comprador': compradores,
'Vendedor': vendedores
})
print(df_ventas)
Producto Precio Comprador Vendedor
0 Producto 1 65 Juan Laura
1 Producto 2 43 Pedro Laura
2 Producto 3 30 Maria Laura
3 Producto 4 41 Ana Elena
4 Producto 5 29 Juan Laura
5 Producto 6 46 Ana Elena
6 Producto 7 54 Ana Miguel
7 Producto 8 36 Juan Carlos
8 Producto 9 17 Juan Elena
9 Producto 10 59 Maria Elena
10 Producto 11 47 Maria Elena
11 Producto 12 49 Pedro Carlos
12 Producto 13 65 Maria Carlos
13 Producto 14 42 Juan Carlos
14 Producto 15 10 Pedro Miguel
[47]:
#TODO
Usant el fitxer 1/data/WHO.csv, Quin és el volum total de CO2 emès per cada continent? Qui continent emet més CO2?
[198]:
#TODO
Usant el fitxer 1/data/WHO.csv, Quants països hi ha per continent? Quin continent té més països?
[197]:
#TODO
Usant el fitxer 1/data/presupuesto_gastos_2023.csv, Calcula la despesa total per “SAILAREN DESKRIBAPENA_EU/DESCRIPCION DEPARTAMENT_CAS” ? Ordena el resultats per despesa (descendent)
[ ]:
#TODO
Fitxer “data/data_groups_cursos.csv”, El fitxer conté cursos realitzats per persones. Cada mostra correspon a un curs. Es demana obtenir un llistat de número de cursos realitzat per cada persona, una valoració de punts segons el curs de la següent manera:
‘A’: 3 punts
‘B’: 2 punts
‘C’: 1 punt
‘D’: 0.5 punt
“E”: 0.5 punt
“F”: 1 punt
[199]:
#TODO
D.2 (amb el anterior cas D), tonar a calcula la valoració de punts considerant la combinació de cursos (independentment del seu ordre):
A, B i C : +10 punts
A i F: +3 punts
E i F: -10 punts
C i F: +5 punts
[201]:
#TODO
Sèries temporals
Les sèries temporals són mostres de valors preses al llarg d’un temps amb un mostreig generalment equidistant. Per exemple, informació econòmica, demografia, meteorològica; registres de seguretat, activitat, etc.
La llibreria Pandas gestiona les sèries temporals usant l’índex: una data (datetime,timedelta):
L’índex d’un dataframe és el pilar bàsic d’accés als valors, per la qual cosa el seu ús simplifica processos de filtratge, selecció, interpolació, etc.
Enllaç a la documentació: TimeSeries
En aquesta secció començarem a treballar amb sèries temporals, començarem inspeccionant un conjunt de dades:
[57]:
import pandas as pd
df = pd.read_csv("data/rdu-weather-history.csv",sep=";")
df.tail()
[57]:
| date | temperaturemin | temperaturemax | precipitation | snowfall | snowdepth | avgwindspeed | fastest2minwinddir | fastest2minwindspeed | fastest5secwinddir | ... | drizzle | snow | freezingrain | smokehaze | thunder | highwind | hail | blowingsnow | dust | freezingfog | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 4552 | 2019-05-24 | 68.0 | 93.0 | 0.00 | 0.0 | 0.0 | 5.82 | 280.0 | 14.09 | 330.0 | ... | No | No | No | Yes | Yes | No | No | No | No | No |
| 4553 | 2019-05-26 | 72.0 | 93.9 | 0.05 | 0.0 | 0.0 | 5.82 | 240.0 | 17.00 | 240.0 | ... | No | No | No | No | Yes | No | No | No | No | No |
| 4554 | 2019-06-08 | 71.1 | 79.0 | 0.32 | 0.0 | 0.0 | 9.40 | 100.0 | 18.12 | 80.0 | ... | No | No | No | No | Yes | No | No | No | No | No |
| 4555 | 2019-05-06 | 60.1 | 77.0 | 0.00 | 0.0 | 0.0 | 5.82 | 40.0 | 14.09 | 50.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 4556 | 2019-05-12 | 64.9 | 75.9 | 0.00 | 0.0 | 0.0 | 11.63 | 230.0 | 21.92 | 220.0 | ... | No | No | No | No | No | No | No | No | No | No |
5 rows × 28 columns
[38]:
print(list(df.columns))
['date', 'temperaturemin', 'temperaturemax', 'precipitation', 'snowfall', 'snowdepth', 'avgwindspeed', 'fastest2minwinddir', 'fastest2minwindspeed', 'fastest5secwinddir', 'fastest5secwindspeed', 'fog', 'fogheavy', 'mist', 'rain', 'fogground', 'ice', 'glaze', 'drizzle', 'snow', 'freezingrain', 'smokehaze', 'thunder', 'highwind', 'hail', 'blowingsnow', 'dust', 'freezingfog']
[58]:
from pandas import DatetimeIndex
df.index = DatetimeIndex(df["date"]) # una sèrie de strings
## Aquesta transformació és "una mica intel·ligent": "03-12-1920" "12-03-1920" "1920-12-03"...
df.head()
[58]:
| date | temperaturemin | temperaturemax | precipitation | snowfall | snowdepth | avgwindspeed | fastest2minwinddir | fastest2minwindspeed | fastest5secwinddir | ... | drizzle | snow | freezingrain | smokehaze | thunder | highwind | hail | blowingsnow | dust | freezingfog | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| date | |||||||||||||||||||||
| 2015-04-08 | 2015-04-08 | 62.1 | 84.0 | 0.00 | 0.0 | 0.0 | 5.82 | 40.0 | 29.97 | 30.0 | ... | No | No | No | Yes | No | No | No | No | No | No |
| 2015-04-20 | 2015-04-20 | 63.0 | 78.1 | 0.28 | 0.0 | 0.0 | 11.86 | 180.0 | 21.92 | 170.0 | ... | No | No | No | No | Yes | No | No | No | No | No |
| 2015-04-26 | 2015-04-26 | 45.0 | 54.0 | 0.02 | 0.0 | 0.0 | 5.82 | 50.0 | 12.97 | 40.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-04-28 | 2015-04-28 | 39.0 | 69.1 | 0.00 | 0.0 | 0.0 | 2.68 | 40.0 | 12.08 | 40.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-05-03 | 2015-05-03 | 46.9 | 79.0 | 0.00 | 0.0 | 0.0 | 2.68 | 200.0 | 12.08 | 210.0 | ... | No | No | No | No | No | No | No | No | No | No |
5 rows × 28 columns
[40]:
df.index.year
[40]:
Int64Index([2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015, 2015,
...
2011, 2011, 2011, 2011, 2019, 2019, 2019, 2019, 2019, 2019],
dtype='int64', name='date', length=4557)
[60]:
# any
df.loc["12/2015"]
[60]:
| date | temperaturemin | temperaturemax | precipitation | snowfall | snowdepth | avgwindspeed | fastest2minwinddir | fastest2minwindspeed | fastest5secwinddir | ... | drizzle | snow | freezingrain | smokehaze | thunder | highwind | hail | blowingsnow | dust | freezingfog | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| date | |||||||||||||||||||||
| 2015-12-03 | 2015-12-03 | 39.0 | 57.9 | 0.00 | 0.0 | 0.0 | 4.25 | 310.0 | 12.97 | 340.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-04 | 2015-12-04 | 33.1 | 54.0 | 0.00 | 0.0 | 0.0 | 2.01 | 30.0 | 10.07 | 30.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-09 | 2015-12-09 | 42.1 | 64.0 | 0.00 | 0.0 | 0.0 | 4.70 | 230.0 | 16.11 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-10 | 2015-12-10 | 44.1 | 66.9 | 0.00 | 0.0 | 0.0 | 3.58 | 220.0 | 12.08 | 220.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-18 | 2015-12-18 | 37.0 | 59.0 | 0.16 | 0.0 | 0.0 | 6.26 | 300.0 | 16.11 | 310.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-24 | 2015-12-24 | 66.0 | 77.0 | 0.04 | 0.0 | 0.0 | 12.75 | 220.0 | 23.04 | 200.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-25 | 2015-12-25 | 64.9 | 73.9 | 0.00 | 0.0 | 0.0 | 8.05 | 230.0 | 17.00 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-26 | 2015-12-26 | 63.0 | 73.9 | 0.01 | 0.0 | 0.0 | 2.91 | 190.0 | 8.95 | 210.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-02 | 2015-12-02 | 52.0 | 64.0 | 0.04 | 0.0 | 0.0 | 7.61 | 170.0 | 17.00 | 180.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-17 | 2015-12-17 | 51.1 | 59.0 | 0.89 | 0.0 | 0.0 | 2.01 | 300.0 | 14.09 | 310.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-19 | 2015-12-19 | 26.2 | 48.0 | 0.00 | 0.0 | 0.0 | 6.71 | 240.0 | 21.03 | 240.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-21 | 2015-12-21 | 36.0 | 57.0 | 0.00 | 0.0 | 0.0 | 2.01 | 200.0 | 6.93 | 200.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-22 | 2015-12-22 | 51.1 | 64.9 | 0.66 | 0.0 | 0.0 | 4.92 | 160.0 | 16.11 | 180.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-28 | 2015-12-28 | 51.1 | 68.0 | 0.15 | 0.0 | 0.0 | 8.95 | 80.0 | 21.92 | 80.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-01 | 2015-12-01 | 43.0 | 53.1 | 0.04 | 0.0 | 0.0 | 2.01 | 290.0 | 6.93 | 150.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-08 | 2015-12-08 | 36.0 | 61.0 | 0.00 | 0.0 | 0.0 | 2.24 | 130.0 | 10.07 | 130.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-11 | 2015-12-11 | 50.0 | 71.1 | 0.00 | 0.0 | 0.0 | 6.26 | 230.0 | 12.97 | 210.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-15 | 2015-12-15 | 48.0 | 72.0 | 0.00 | 0.0 | 0.0 | 5.59 | 240.0 | 18.12 | 240.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-16 | 2015-12-16 | 43.0 | 64.9 | 0.00 | 0.0 | 0.0 | 4.70 | 100.0 | 12.08 | 120.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-20 | 2015-12-20 | 27.1 | 54.0 | 0.00 | 0.0 | 0.0 | 2.01 | 160.0 | 8.05 | 160.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-23 | 2015-12-23 | 61.0 | 73.0 | 1.68 | 0.0 | 0.0 | 9.17 | 230.0 | 29.08 | 220.0 | ... | No | No | No | No | Yes | No | No | No | No | No |
| 2015-12-30 | 2015-12-30 | 63.0 | 66.9 | 1.79 | 0.0 | 0.0 | 5.14 | 290.0 | 14.99 | 290.0 | ... | No | No | No | No | Yes | No | No | No | No | No |
| 2015-12-12 | 2015-12-12 | 53.1 | 75.0 | 0.00 | 0.0 | 0.0 | 4.47 | 230.0 | 12.08 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-27 | 2015-12-27 | 64.0 | 75.9 | 0.00 | 0.0 | 0.0 | 9.40 | 230.0 | 21.92 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-29 | 2015-12-29 | 53.1 | 73.9 | 0.10 | 0.0 | 0.0 | 4.25 | 220.0 | 17.00 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-05 | 2015-12-05 | 29.1 | 55.9 | 0.00 | 0.0 | 0.0 | 3.80 | 50.0 | 14.99 | 30.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-06 | 2015-12-06 | 29.1 | 60.1 | 0.00 | 0.0 | 0.0 | 1.12 | 340.0 | 6.04 | 330.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-07 | 2015-12-07 | 41.0 | 57.9 | 0.00 | 0.0 | 0.0 | 1.34 | 220.0 | 6.93 | 140.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-13 | 2015-12-13 | 50.0 | 73.0 | 0.00 | 0.0 | 0.0 | 2.91 | 220.0 | 10.07 | 210.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-14 | 2015-12-14 | 62.1 | 75.0 | 0.04 | 0.0 | 0.0 | 10.74 | 230.0 | 23.04 | 230.0 | ... | No | No | No | No | No | No | No | No | No | No |
| 2015-12-31 | 2015-12-31 | 51.1 | 66.0 | 0.47 | 0.0 | 0.0 | 4.47 | 220.0 | 14.09 | 200.0 | ... | No | No | No | No | No | No | No | No | No | No |
31 rows × 28 columns
[42]:
df.loc["2015"].temperaturemin.min() > df.loc["2016"].temperaturemin.min()
[42]:
False
[43]:
# que estem fent aqui?
dfmax = df["temperaturemax"].groupby([df.index.year,df.index.month]).max()
print(dfmax) #penseu l'index
date date
2007 1 73.9
2 73.9
3 87.1
4 87.1
5 91.9
...
2019 2 79.0
3 75.9
4 86.0
5 96.1
6 93.0
Name: temperaturemax, Length: 150, dtype: float64
Isaac Lera and Gabriel Moya Universitat de les Illes Balears isaac.lera@uib.edu, gabriel.moya@uib.edu