Open In Colab

💡 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ó:

[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

  1. 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
  1. 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
  1. 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
  1. Usant el fitxer 1/data/WHO.csv, Quants països hi ha per continent? Quin continent té més països?

[197]:
#TODO
  1. 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
  1. 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

License: CC BY 4.0 Isaac Lera and Gabriel Moya Universitat de les Illes Balears isaac.lera@uib.edu, gabriel.moya@uib.edu