Agrupaciones de datos
Las agrupaciones son operaciones necesarias para analizar datos, ya que permiten extraer información en función de datos categóricos de nuestro dataframe.
Cargaremos los datos llamados experiment.csv que podemos encontrar en el siguiente enlace
[2]:
import pandas as pd
import numpy as np
df= pd.read_csv("data/experiment.csv")
print(df)
Nombre Apellidos Altura Sexo Nacimiento Cof Categoria
0 Will Smith 1.43 M 10/10/1920 0.19 laboral
1 Jon Snow 1.98 M 10/1/1970 0.98 laboral
2 Laia Ramirez 1.87 F 09/10/1987 0.76 cap6
3 Luzy Raim 1.67 F 23/07/1979 0.56 cap6
4 Fein Mang 1.78 M 12/03/1937 0.27 cap6
5 Victor Colom 1.78 M 22/09/1957 0.97 cap8
En el siguiente ejemplo agrupamos los datos según el sexo de la persona mediante el método groupby
que devuelve un DataFrame
agrupado:
[3]:
bySex = df.groupby('Sexo')
bySex
[3]:
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x126c68b10>
El atributo groups
nos muestra los grupos hemos creado:
[9]:
# Podemos saber los grupos realizados y que índices del dataframe tienen.
bySex.groups # nos proporciona un diccionario
[9]:
{'F': [2, 3], 'M': [0, 1, 4, 5]}
[10]:
bySex.describe()
[10]:
Altura | Cof | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
count | mean | std | min | 25% | 50% | 75% | max | count | mean | std | min | 25% | 50% | 75% | max | |
Sexo | ||||||||||||||||
F | 2.0 | 1.7700 | 0.141421 | 1.67 | 1.7200 | 1.77 | 1.82 | 1.87 | 2.0 | 0.6600 | 0.141421 | 0.56 | 0.61 | 0.66 | 0.7100 | 0.76 |
M | 4.0 | 1.7425 | 0.228674 | 1.43 | 1.6925 | 1.78 | 1.83 | 1.98 | 4.0 | 0.6025 | 0.431383 | 0.19 | 0.25 | 0.62 | 0.9725 | 0.98 |
Esto nos permite realizar operaciones de filtrado con base a los grupos que hemos creado:
[4]:
dfM = df.loc[bySex.groups['M'].values] #Recorda que "loc" accedeix per index de fila
dfM
[4]:
Nombre | Apellidos | Altura | Sexo | Nacimiento | Cof | Categoria | |
---|---|---|---|---|---|---|---|
0 | Will | Smith | 1.43 | M | 10/10/1920 | 0.19 | laboral |
1 | Jon | Snow | 1.98 | M | 10/1/1970 | 0.98 | laboral |
4 | Fein | Mang | 1.78 | M | 12/03/1937 | 0.27 | cap6 |
5 | Victor | Colom | 1.78 | M | 22/09/1957 | 0.97 | cap8 |
[7]:
df[df.Sexo=="M"] # es lo mismo!
[7]:
Nombre | Apellidos | Altura | Sexo | Nacimiento | Cof | Categoria | |
---|---|---|---|---|---|---|---|
0 | Will | Smith | 1.43 | M | 10/10/1920 | 0.19 | laboral |
1 | Jon | Snow | 1.98 | M | 10/1/1970 | 0.98 | laboral |
4 | Fein | Mang | 1.78 | M | 12/03/1937 | 0.27 | cap6 |
5 | Victor | Colom | 1.78 | M | 22/09/1957 | 0.97 | cap8 |
Funciones de agregación en grupos.
El método ‘aggregate’ nos permite crear variables de agregación en la tabla obtenida con ‘groupby’. Indicaremos la información que deseamos obtener de cada columna utilizando un diccionario. Especificamos la función que aplicaremos a los datos de cada grupo en cada columna para obtener un único valor.
Para ejemplificar esta sección, agruparemos el dataframe por Categoria
laboral. En este caso para la columna Altura
consultamos la suma de las alturas del grupo y Cof
la media.
La función aggregate
nos permite crear variables de agregación sobre la tabla obtenida con groupby
. Indicaremos la información que queremos obtener de cada columna con un diccionario. Especificamos la función que vamos a aplicar a los datos de cada grupo en cada columna para obtener un único valor.
[5]:
dfg = df.groupby(["Categoria"]).aggregate({
"Altura":"sum",
"Cof":"mean"})
dfg
[5]:
Altura | Cof | |
---|---|---|
Categoria | ||
cap6 | 5.32 | 0.530 |
cap8 | 1.78 | 0.970 |
laboral | 3.41 | 0.585 |
[12]:
dfg.index
[12]:
Index(['cap6', 'cap8', 'laboral'], dtype='object', name='Categoria')
Podemos aplicar un gran número de funciones de agregación:
Funciones estadísticas: mean, std, …
Funciones matemáticas: sum, prod, …
Otras funciones: max, min, …
[9]:
type(dfg) #Alerta! Una agregación genera un dataframe y por lo tanto podemos seguir aplicando lo que ya sabemos
[9]:
pandas.core.frame.DataFrame
[10]:
dfg[dfg.Altura>3]
[10]:
Altura | Cof | |
---|---|---|
Categoria | ||
cap6 | 5.32 | 0.530 |
laboral | 3.41 | 0.585 |
Agrupaciones de múltiples columnas
También se pueden realizar agrupaciones de múltiples columnas. Se crean todas las combinaciones de las diversas columnas que existen en el DataFrame. Veamos un ejemplo:
[7]:
gr = df.groupby(['Sexo',"Categoria"]).mean(numeric_only=True)
gr
[7]:
Altura | Cof | ||
---|---|---|---|
Sexo | Categoria | ||
F | cap6 | 1.770 | 0.660 |
M | cap6 | 1.780 | 0.270 |
cap8 | 1.780 | 0.970 | |
laboral | 1.705 | 0.585 |
Si queremos realizar un conteo de los elementos, debemos seleccionar
[39]:
gr = df.groupby(['Sexo',"Categoria"])["Sexo"].count()
print(gr)
Sexo Categoria
F cap6 2
M cap6 1
cap8 1
laboral 2
Name: Sexo, dtype: int64
Multiindice
A veces, un índice no es suficiente para expresar la meta-información que identifica una o varias columnas. Por ejemplo, una coordenada está compuesta por la latitud y la longitud.
Un ‘multiíndice’ es una jerarquía de índices.
Agrupar según diferentes criterios resulta en un multiíndice.
[8]:
gr = df.groupby(['Sexo',"Categoria"]).count()
gr.index
[8]:
MultiIndex([('F', 'cap6'),
('M', 'cap6'),
('M', 'cap8'),
('M', 'laboral')],
names=['Sexo', 'Categoria'])
[ ]:
gr.loc[("M",:)] # Como accedemos en rango en un multiindice?
Cell In[9], line 1
gr.loc[("M",:)]
^
SyntaxError: invalid syntax
[17]:
gr.loc["F"] # primer index
[17]:
Nombre | Apellidos | Altura | Nacimiento | Cof | |
---|---|---|---|---|---|
Categoria | |||||
cap6 | 2 | 2 | 2 | 2 | 2 |
[16]:
gr.loc["cap6"] # dependent index
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
File ~/.pyenv/versions/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/site-packages/pandas/_libs/index.pyx:138, in pandas._libs.index.IndexEngine.get_loc()
File ~/.pyenv/versions/3.9.7/lib/python3.9/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: 'cap6'
The above exception was the direct cause of the following exception:
KeyError Traceback (most recent call last)
/Users/isaac/Projects/TxADM_notebooks/notebooks/Part2/00_Pandas/02_Agrupación_de_datos.ipynb Cell 24 line <cell line: 1>()
----> <a href='vscode-notebook-cell:/Users/isaac/Projects/TxADM_notebooks/notebooks/Part2/00_Pandas/02_Agrupaci%C3%B3n_de_datos.ipynb#X61sZmlsZQ%3D%3D?line=0'>1</a> gr.loc["cap6"]
File ~/.pyenv/versions/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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/3.9.7/lib/python3.9/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: 'cap6'
[18]:
# Necesitamos invocar un IndexSlice.
gr.loc[pd.IndexSlice[:, 'cap6'],:]
# https://pandas.pydata.org/docs/reference/api/pandas.IndexSlice.html
[18]:
Nombre | Apellidos | Altura | Nacimiento | Cof | ||
---|---|---|---|---|---|---|
Sexo | Categoria | |||||
F | cap6 | 2 | 2 | 2 | 2 | 2 |
M | cap6 | 1 | 1 | 1 | 1 | 1 |
En estas situaciones donde queremos acceder a esos datos, la forma más sencilla es simplemente eliminar el indice:
[10]:
gr = df.groupby(['Sexo',"Categoria"]).count().reset_index()
gr
[10]:
Sexo | Categoria | Nombre | Apellidos | Altura | Nacimiento | Cof | |
---|---|---|---|---|---|---|---|
0 | F | cap6 | 2 | 2 | 2 | 2 | 2 |
1 | M | cap6 | 1 | 1 | 1 | 1 | 1 |
2 | M | cap8 | 1 | 1 | 1 | 1 | 1 |
3 | M | laboral | 2 | 2 | 2 | 2 | 2 |
[21]:
gr.index = gr["Categoria"]
print(gr)
Sexo Categoria Nombre Apellidos Altura Nacimiento Cof
Categoria
cap6 F cap6 2 2 2 2 2
cap6 M cap6 1 1 1 1 1
cap8 M cap8 1 1 1 1 1
laboral M laboral 2 2 2 2 2
Agregaciones avanzadas
Sobre una agregación, podemos realizar operaciones más allá de las aritméticas.
Por ejemplo, si deseamos crear un histograma de la distribución de tipos de certificados por ciudad y código postal, necesitamos crear una lista para cada grupo.
[11]:
df = pd.read_csv("data/data_groups.csv")
print(df.head())
print(df.shape)
Unnamed: 0 Dni Nom CP Ciutat Sexe \
0 0 H61414629 María Dolores Arjona Jove 7800 Eivissa M
1 1 S3138381C Núria Quirós 7511 Ruberts F
2 2 J8698188C Miguel José María Gil Vargas 7340 Alaro M
3 3 A48821615 Jordi Chaves Bustamante 7609 Bellavista F
4 4 U0247281I Jana Rosa Collado Menéndez 7006 Palma M
Tipus certificat cat Punts
0 B 73
1 A 40
2 A 45
3 B 40
4 B 86
(1000, 8)
[22]:
dfc = df.groupby(["Ciutat","CP"])["Tipus certificat cat"].apply(list)
dfc
[22]:
Ciutat CP
Alaro 7340 [A, C, B, A, A, B, A, D, A, B, A, B, B, A, B, ...
Ariany 7529 [B, A, B, A, A, B, A, B, A, B, A, A, C, A, B, ...
Bellavista 7609 [B, C, A, A, A, C, A, A, B, A, A, A, B, A, C, ...
Binissalem 7350 [A, B, B, C, C, A, A, A, C, A, C, A, B, B, D, ...
Eivissa 7800 [B, A, A, B, B, B, A, A, A, A, B, C, A, A, B, ...
La Savina 7870 [A, A, A, B, A, A, B, B, A, A, B, A, B, B, A, ...
Mao 7701 [B, C, B, C, B, C, A, B, B, B, A, C, C, A, C, ...
7703 [B, A, B, C, A, A, B, A, C, B, A, B, C, A, B, ...
Palma 7006 [B, A, B, B, A, A, A, B, B, A, A, B, B, A, B, ...
7009 [A, D, A, B, C, A, A, C, B, A, A, A, C, A, A, ...
7013 [A, A, B, C, C, C, C, A, A, A, B, A, C, C, A, ...
Pedruscada 7590 [A, B, A, A, A, A, B, B, C, B, B, B, C, A, A, ...
Ruberts 7511 [A, A, A, B, C, A, B, A, A, B, B, A, C, B, B, ...
Name: Tipus certificat cat, dtype: object
[23]:
tipusAlaro = dfc.loc[pd.IndexSlice["Alaro",7340]]
values, counts = np.unique(tipusAlaro, return_counts=True)
print(values) # Tipus
print(counts) # quantitat
print("-"*40)
distribucioAlaro = dict(zip(values,counts)) ## Que fa el ZIP?!
print(distribucioAlaro)
['A' 'B' 'C' 'D']
[57 42 16 5]
----------------------------------------
{'A': 57, 'B': 42, 'C': 16, 'D': 5}
[24]:
def hola(valor):
print(valor*3)
[25]:
hola(9)
27
[24]:
## També podem invocar funcions especifiques! en lloc de una sum, mean, max, etc.
df2 = df.groupby(["Ciutat","CP"]).agg(
{"Tipus certificat cat": [lambda x: list(x), np.size]}) # lambda !
print(df2)
Tipus certificat cat
<lambda_0> size
Ciutat CP
Alaro 7340 [A, C, B, A, A, B, A, D, A, B, A, B, B, A, B, ... 120
Ariany 7529 [B, A, B, A, A, B, A, B, A, B, A, A, C, A, B, ... 113
Bellavista 7609 [B, C, A, A, A, C, A, A, B, A, A, A, B, A, C, ... 98
Binissalem 7350 [A, B, B, C, C, A, A, A, C, A, C, A, B, B, D, ... 93
Eivissa 7800 [B, A, A, B, B, B, A, A, A, A, B, C, A, A, B, ... 91
La Savina 7870 [A, A, A, B, A, A, B, B, A, A, B, A, B, B, A, ... 90
Mao 7701 [B, C, B, C, B, C, A, B, B, B, A, C, C, A, C, ... 63
7703 [B, A, B, C, A, A, B, A, C, B, A, B, C, A, B, ... 45
Palma 7006 [B, A, B, B, A, A, A, B, B, A, A, B, B, A, B, ... 36
7009 [A, D, A, B, C, A, A, C, B, A, A, A, C, A, A, ... 23
7013 [A, A, B, C, C, C, C, A, A, A, B, A, C, C, A, ... 37
Pedruscada 7590 [A, B, A, A, A, A, B, B, C, B, B, B, C, A, A, ... 106
Ruberts 7511 [A, A, A, B, C, A, B, A, A, B, B, A, C, B, B, ... 85
[41]:
# Qué és una funció lambda?
a = np.array([10,10,4,5,7,8,12,4507,30])
b = list(map(lambda i:i**2+2*i,a))
def f1(i):
return i**2+2
b = list(map(f1,a))
print(b)
[102, 102, 18, 27, 51, 66, 146, 20313051, 902]
[36]:
# Em aquest exemple apliquem una funció que té un criterí més específic:
def miBarem50p(serie):
up50list = []
for value in serie.values:
if value>50:
up50list.append(value)
return len(up50list)
df3 = df.groupby(["Ciutat","CP"]).agg(
{"Punts": [lambda x: miBarem50p(x), np.size]}) # lambda: què és X?
print(df3) #Quina interpretació dels resultats feu?
Punts
<lambda_0> size
Ciutat CP
Alaro 7340 61 120
Ariany 7529 56 113
Bellavista 7609 43 98
Binissalem 7350 50 93
Eivissa 7800 44 91
La Savina 7870 41 90
Mao 7701 34 63
7703 18 45
Palma 7006 19 36
7009 10 23
7013 19 37
Pedruscada 7590 65 106
Ruberts 7511 36 85
[ ]:
Ejercicios
1) Usando el fichero WHO.csv, ¿Cuál es el volumen total de CO2 emitido por cada continente?
[ ]:
2) ¿Cuál es el número de paises por continente?
[ ]:
3) Del conjunto “who.csv” selecciona 30 paises al azar y sobre ellos calcula la media de “Net primary school enrolment ratio female (%)” agrupados por: Continente
Nota: la selección de 30 paises aleatoria ha de ser reproducible
[ ]:
3b) Repite la anterior actividad pero ahora con todos los paises. ¿Sale la misma media?
[ ]:
4) Calcula la cantidad de ayuda recibida por cada municipio en función del númeto total de habitantes. (v2)
[1]:
# V2. Con necesidad de agrupar
import pandas as pd
import random
random.seed(0)
nombres = [f'Municipio{i}' for i in range(1, 11)]
data_municipios = {
'Nombre': nombres,
'Código Postal': [random.randint(10000, 99999) for _ in range(10)],
'Población': [random.randint(1000, 50000) for _ in range(10)] # Añadimos un atributo aleatorio, en este caso "Población"
}
df_municipios = pd.DataFrame(data_municipios)
data_ayudas = {
'Nombre': [random.choice(nombres) for _ in range(20)],
'Ayuda Económica (en euros)': [random.randint(1000, 10000) for _ in range(20)],
'Número de Beneficiarios': [random.randint(10, 100) for _ in range(20)]
}
df_ayudas = pd.DataFrame(data_ayudas)
print("Dataframe de Municipios:")
print(df_municipios)
print("\nDataframe de Ayudas:")
print(df_ayudas)
Dataframe de Municipios:
Nombre Código Postal Población
0 Municipio1 60494 39232
1 Municipio2 65125 15315
2 Municipio3 15306 34075
3 Municipio4 43936 10127
4 Municipio5 77013 19470
5 Municipio6 73691 10158
6 Municipio7 63075 7214
7 Municipio8 49755 41525
8 Municipio9 72468 17417
9 Municipio10 56930 35902
Dataframe de Ayudas:
Nombre Ayuda Económica (en euros) Número de Beneficiarios
0 Municipio10 9989 72
1 Municipio3 1230 23
2 Municipio5 2528 48
3 Municipio2 7534 80
4 Municipio2 1018 47
5 Municipio6 9086 100
6 Municipio8 6458 25
7 Municipio9 4996 80
8 Municipio2 6328 52
9 Municipio6 2031 79
10 Municipio7 4130 36
11 Municipio6 4632 87
12 Municipio10 4909 80
13 Municipio4 3334 85
14 Municipio9 9896 46
15 Municipio8 8339 66
16 Municipio8 2494 21
17 Municipio9 2318 86
18 Municipio5 6243 59
19 Municipio1 9322 50
5) Agrupa los datos por el nombre de de la escuela. - ¿Qué escuela tiene más infantes? - ¿Qué escuela tiene los infantes más altos?
[ ]:
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()
[ ]:
#TODO dejar esto pendiente para isaac futuro
#hola
#HOLA
6) Dado el siguiente listado de ventas: - ¿Qué comprador ha gastado más? - ¿Qué vendedor ha hecho más ventas?
[6]:
import pandas as pd
import numpy as np
# Crear datos aleatorios
np.random.seed(1)
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 47 Juan Laura
1 Producto 2 22 Maria Laura
2 Producto 3 82 Pedro Elena
3 Producto 4 19 Maria Miguel
4 Producto 5 85 Juan Carlos
5 Producto 6 15 Ana Miguel
6 Producto 7 89 Juan Laura
7 Producto 8 74 Maria Laura
8 Producto 9 26 Juan Laura
9 Producto 10 11 Pedro Elena
10 Producto 11 86 Maria Elena
11 Producto 12 81 Maria Laura
12 Producto 13 16 Juan Miguel
13 Producto 14 35 Ana Laura
14 Producto 15 60 Ana Laura
[7]:
#TODO
7) Fichero “data/data_groups_cursos.csv”; contiene cursos realizados por personas. Cada muestra corresponde a un curso. Se pide un listado del número de cursos realizado por cada persona y una valoración de sus puntos según el tipo de curso realizado: - ‘A’: 3 puntos - ‘B’: 2 puntos - ‘C’: 1 punto - ‘D’: 0.5 punto - “E”: 0.5 punto - “F”: 1 punto
[8]:
# TODO
[42]:
a = np.array([1,2,3,4,5,6,10])
print(a.max())
print(a.argmax())
10
6
Categorización de datos
TODO Valores ya categorizados?
https://pandas.pydata.org/docs/user_guide/categorical.html
La función cut
de Pandas es una herramienta útil para segmentar y discretizar datos en intervalos o categorías. Esta función es especialmente útil cuando desea convertir una variable numérica continua en una variable categórica al dividirla en intervalos o categorías específicas.
Crearemos un nuevo DataFrame para realizar pruebas:
[3]:
import numpy as np
import pandas as pd
np.random.seed(0)
df_random = pd.DataFrame({"candidat":np.arange(1,11), "nota":np.random.randint(0,11,size=10)})
df_random
[3]:
candidat | nota | |
---|---|---|
0 | 1 | 5 |
1 | 2 | 0 |
2 | 3 | 3 |
3 | 4 | 3 |
4 | 5 | 7 |
5 | 6 | 9 |
6 | 7 | 3 |
7 | 8 | 5 |
8 | 9 | 2 |
9 | 10 | 4 |
A continuación, creamos una columna nueva que contiene la nota pero en escala categórica:
[10]:
df_random["notaCategorica"] = pd.cut(df_random.nota, 3, labels=["dolent", "mig", "bona"])
df_random
[10]:
candidat | nota | notaCategorica | |
---|---|---|---|
0 | 1 | 5 | mig |
1 | 2 | 0 | dolent |
2 | 3 | 3 | dolent |
3 | 4 | 3 | dolent |
4 | 5 | 7 | bona |
5 | 6 | 9 | bona |
6 | 7 | 3 | dolent |
7 | 8 | 5 | mig |
8 | 9 | 2 | dolent |
9 | 10 | 4 | mig |
[12]:
df_random[df_random.notaCategorica==df_random.notaCategorica.max()]
[12]:
candidat | nota | notaCategorica | |
---|---|---|---|
4 | 5 | 7 | bona |
5 | 6 | 9 | bona |
[45]:
# mejora
bins = [-1, 4, 7, 8.5, 10]
labels = ['Suspens', 'Be', 'Notable', 'Excel·lent']
df_random["notaCategorica"] = pd.cut(df_random.nota, bins, labels=labels) # include_lowest=True
df_random
[45]:
candidat | nota | notaCategorica | |
---|---|---|---|
0 | 1 | 5 | Be |
1 | 2 | 0 | Suspens |
2 | 3 | 3 | Suspens |
3 | 4 | 3 | Suspens |
4 | 5 | 7 | Be |
5 | 6 | 9 | Excel·lent |
6 | 7 | 3 | Suspens |
7 | 8 | 5 | Be |
8 | 9 | 2 | Suspens |
9 | 10 | 4 | Suspens |
[48]:
# Podemos definir el intervalo que deseemos (como un Histograma)
import numpy as np
marks = np.arange(0,1.1,0.25)
print(marks)
print
print("-"*10)
factors = pd.qcut(df_random.nota, marks)
print(factors)
print("-"*10)
print(pd.value_counts(factors))
print(df_random.nota)
[0. 0.25 0.5 0.75 1. ]
----------
0 (3.5, 5.0]
1 (-0.001, 3.0]
2 (-0.001, 3.0]
3 (-0.001, 3.0]
4 (5.0, 9.0]
5 (5.0, 9.0]
6 (-0.001, 3.0]
7 (3.5, 5.0]
8 (-0.001, 3.0]
9 (3.5, 5.0]
Name: nota, dtype: category
Categories (4, interval[float64, right]): [(-0.001, 3.0] < (3.0, 3.5] < (3.5, 5.0] < (5.0, 9.0]]
----------
(-0.001, 3.0] 5
(3.5, 5.0] 3
(5.0, 9.0] 2
(3.0, 3.5] 0
Name: nota, dtype: int64
0 5
1 0
2 3
3 3
4 7
5 9
6 3
7 5
8 2
9 4
Name: nota, dtype: int64
[16]:
# Del fichero:
import pandas as pd
df = pd.read_csv("data/rdu-weather-history.csv",sep=";")
# print(df.head())
# print(df.columns)
print(df.shape)
print(df.snowfall.describe())
# values, repeticiones = np.unique(df.snowfall,return_counts=True)
# print(values)
# print(repeticiones)
(4557, 28)
count 4555.000000
mean 0.013723
std 0.214786
min 0.000000
25% 0.000000
50% 0.000000
75% 0.000000
max 7.010000
Name: snowfall, dtype: float64
Queremos discretizar la variable snowfall
para tener 4 categorias de nevada.
En primer lugar, usa la función qcut
para hacer esta categorización. Haz una prueba y analiza por qué está función quizás no sea la mejor opción. Ahora, crea 4 categorías utilizando la función cut
:
[18]:
#TODO
Isaac Lera and Gabriel Moya Universitat de les Illes Balears isaac.lera@uib.edu, gabriel.moya@uib.edu