Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Clase 4: Gráficos en pandas
Fecha: 05 de diciembre del 2022
unique()
value_counts()
replace()
Inicialmente en esta clase recapitularemos algunos conceptos sobre pandas que se abordaron en el proyecto resuelto de la clase 2, los cuales son muy importantes y por ende los volveremos a ver, al inicio, de esta clase.
Utilizaremos la librería seaborn (la cual es muy parecida con matplotlib y la cual está destinada a la graficación) para obtener conjuntos de datos con los cuales trabajar. Para ello:
# importacion necesaria
import seaborn as sns
# veamos los nombres de todos los conjuntos de datos
# que se disponen en dicha libreria
sns.get_dataset_names()
['anagrams', 'anscombe', 'attention', 'brain_networks', 'car_crashes', 'diamonds', 'dots', 'dowjones', 'exercise', 'flights', 'fmri', 'geyser', 'glue', 'healthexp', 'iris', 'mpg', 'penguins', 'planets', 'seaice', 'taxis', 'tips', 'titanic']
Trabajaremos con el conjunto iris. Para cargar ese conjunto de datos utilizamos el método load_dataset()
como sigue
df = sns.load_dataset("iris")
df.head()
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
El método unique()
actúa sobre una columna (serie) y nos devuelve los valores distintos que hay en dicha columna, por ejemplo
df.species.unique()
array(['setosa', 'versicolor', 'virginica'], dtype=object)
nos dice que en la columna species
solo hay 4 valores únicos, los cuales son las especies.
Este método agrupará de manera automática los distintos valores únicos de una columna determinada y después contará el número de apariciones de esos valores únicos en la columna correspondiente. Por ejemplo, si utilizamos el método value_counts_()
sobre la columna species
lo que pasará es que se considerará inicialmente los valores únicos ['setosa', 'versicolor', 'virginica']
y después se contará cuántas filas tienen asociado el valor setosa
, cuántas filas tienen asociado el valor virginica
y cuántos el valor versicolor
. Así:
df.species.value_counts()
setosa 50 versicolor 50 virginica 50 Name: species, dtype: int64
lo que nos dice que tenemos 50 filas de cada especie. De manera totalmente alternativa podemos escribir
df.value_counts('species')
species setosa 50 versicolor 50 virginica 50 dtype: int64
Para elminar filas o columnas de un dataframe utilizamos el método drop()
de dos posibles maneras:
# eliminacion de una fila:
# eliminaremos la primer fila
df.drop(0, axis=0).head()
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
5 | 5.4 | 3.9 | 1.7 | 0.4 | setosa |
notamos que la fila que tenía el índice 0 ya no se ve. Podemos eliminar más de una fila a la vez
# eliminamos las primeras tres filas
df.drop([0,1,2], axis=0).head()
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa |
5 | 5.4 | 3.9 | 1.7 | 0.4 | setosa |
6 | 4.6 | 3.4 | 1.4 | 0.3 | setosa |
7 | 5.0 | 3.4 | 1.5 | 0.2 | setosa |
# eliminamos las primeras 10 filas
df.drop([i for i in range(10)], axis=0).head()
sepal_length | sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|---|
10 | 5.4 | 3.7 | 1.5 | 0.2 | setosa |
11 | 4.8 | 3.4 | 1.6 | 0.2 | setosa |
12 | 4.8 | 3.0 | 1.4 | 0.1 | setosa |
13 | 4.3 | 3.0 | 1.1 | 0.1 | setosa |
14 | 5.8 | 4.0 | 1.2 | 0.2 | setosa |
o también podemos eliminar columnas, para lo cual cambiaremos el parámetro de axis=0
al de axis=1
:
# eliminacion de una columna:
# eliminaremos la primer columna
df.drop('sepal_length', axis=1).head()
sepal_width | petal_length | petal_width | species | |
---|---|---|---|---|
0 | 3.5 | 1.4 | 0.2 | setosa |
1 | 3.0 | 1.4 | 0.2 | setosa |
2 | 3.2 | 1.3 | 0.2 | setosa |
3 | 3.1 | 1.5 | 0.2 | setosa |
4 | 3.6 | 1.4 | 0.2 | setosa |
# eliminaremos dos columnas a la vez
df.drop(['sepal_length', 'species'], axis=1).head()
sepal_width | petal_length | petal_width | |
---|---|---|---|
0 | 3.5 | 1.4 | 0.2 |
1 | 3.0 | 1.4 | 0.2 |
2 | 3.2 | 1.3 | 0.2 |
3 | 3.1 | 1.5 | 0.2 |
4 | 3.6 | 1.4 | 0.2 |
Supongamos que queremos agregar una columna nueva de la siguiente manera: si la especie es setosa, entonces en la columna nueva colocaremos un 1; si la especie es versicolor colocaremos un 2 y si la especie es virginica colocaremos un 3.
En pandas podemos realizar este tipo de "reemplazos" de valores mediante el método replace()
. Este método lo que hace es cambiar los valores de una columna por nuevos valores que nosotros especifiquemos. De tal manera, de acuerdo a lo que queremos hacer deberemos de crear primero una columna nueva como sigue
# Creamos una columna como copia de la columna specie
df['species_num'] = df.species
df.head()
sepal_length | sepal_width | petal_length | petal_width | species | species_num | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa | setosa |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa | setosa |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa | setosa |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa | setosa |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa | setosa |
Después utilizaremos el método replace()
para realizar los cambios numéricos que mencionamos. Para ello, inicialmente, creamos un diccionario con los valores de la columna species_num, dichos valores serán las llaves de ese diccionario, y después, a esas llaves, les asociaremos los valores a sustituir. Esto es
dict_valor = {'setosa': 1, 'versicolor': 2, 'virginica': 3}
Después, pasaremos ese diccionario al método replace()
, pero deberemos pasarlo como sigue:
# nombre de la |diccionario con los
# columna |valores a reemplazar
dict_reemplazo = {'species_num': dict_valor}
# pasamos el diccionario anterior al metodo replace()
df = df.replace(dict_reemplazo)
df
sepal_length | sepal_width | petal_length | petal_width | species | species_num | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa | 1 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa | 1 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa | 1 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa | 1 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa | 1 |
... | ... | ... | ... | ... | ... | ... |
145 | 6.7 | 3.0 | 5.2 | 2.3 | virginica | 3 |
146 | 6.3 | 2.5 | 5.0 | 1.9 | virginica | 3 |
147 | 6.5 | 3.0 | 5.2 | 2.0 | virginica | 3 |
148 | 6.2 | 3.4 | 5.4 | 2.3 | virginica | 3 |
149 | 5.9 | 3.0 | 5.1 | 1.8 | virginica | 3 |
150 rows × 6 columns
con lo cual hemos conseguido nuestro objetivo.
Podemos reemplazar los valores de más de una columna a la vez, por ejemplo
dict_reemplazo = {'species_num': dict_valor,
'species': dict_valor}
# pasamos el diccionario anterior al metodo replace()
df.replace(dict_reemplazo)
sepal_length | sepal_width | petal_length | petal_width | species | species_num | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | 1 | 1 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | 1 | 1 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | 1 | 1 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | 1 | 1 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | 1 | 1 |
... | ... | ... | ... | ... | ... | ... |
145 | 6.7 | 3.0 | 5.2 | 2.3 | 3 | 3 |
146 | 6.3 | 2.5 | 5.0 | 1.9 | 3 | 3 |
147 | 6.5 | 3.0 | 5.2 | 2.0 | 3 | 3 |
148 | 6.2 | 3.4 | 5.4 | 2.3 | 3 | 3 |
149 | 5.9 | 3.0 | 5.1 | 1.8 | 3 | 3 |
150 rows × 6 columns
donde ahora modificamos los valores de dos columna. Asimismo, podríamos pasar diferentes diccionarios de reemplazo como el diccionario dict_valor
.
Dentro de un dataframe podemos obtener cierta información de nuestros datos. Por ejemplo, podemos ver el tipo de dato de las columnas, si hay en ellas valores nulos, el total de filas y el peso del conjunto de datos:
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 150 entries, 0 to 149 Data columns (total 6 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 sepal_length 150 non-null float64 1 sepal_width 150 non-null float64 2 petal_length 150 non-null float64 3 petal_width 150 non-null float64 4 species 150 non-null object 5 species_num 150 non-null int64 dtypes: float64(4), int64(1), object(1) memory usage: 7.2+ KB
donde vemos que el conjunto de datos tiene un peso de aproximadamente 7.2 kilobytes. Mencionamos que el tipo de dato object
de pandas es el equivalente al tipo de datos string
normal de python.
Podemos ver un resumen de estadísticas:
df.describe()
sepal_length | sepal_width | petal_length | petal_width | species_num | |
---|---|---|---|---|---|
count | 150.000000 | 150.000000 | 150.000000 | 150.000000 | 150.000000 |
mean | 5.843333 | 3.057333 | 3.758000 | 1.199333 | 2.000000 |
std | 0.828066 | 0.435866 | 1.765298 | 0.762238 | 0.819232 |
min | 4.300000 | 2.000000 | 1.000000 | 0.100000 | 1.000000 |
25% | 5.100000 | 2.800000 | 1.600000 | 0.300000 | 1.000000 |
50% | 5.800000 | 3.000000 | 4.350000 | 1.300000 | 2.000000 |
75% | 6.400000 | 3.300000 | 5.100000 | 1.800000 | 3.000000 |
max | 7.900000 | 4.400000 | 6.900000 | 2.500000 | 3.000000 |
que nos indica:
Podemos ver, en cuanto a columna numéricas, el coeficiente de correlación de pearson (el cual nos dice si una variable y otra presentar alguna relación lineal):
df.corr(method='pearson')
sepal_length | sepal_width | petal_length | petal_width | species_num | |
---|---|---|---|---|---|
sepal_length | 1.000000 | -0.117570 | 0.871754 | 0.817941 | 0.782561 |
sepal_width | -0.117570 | 1.000000 | -0.428440 | -0.366126 | -0.426658 |
petal_length | 0.871754 | -0.428440 | 1.000000 | 0.962865 | 0.949035 |
petal_width | 0.817941 | -0.366126 | 0.962865 | 1.000000 | 0.956547 |
species_num | 0.782561 | -0.426658 | 0.949035 | 0.956547 | 1.000000 |
donde:
Del ejemplo anterior tenemos que las variables species_num
(la cual representan a las especies) está altamente relacionada con la variable petal_width
.
¿Qué otras relaciones, a parte de las que mencionamos inmediatamente antes, pueden detectarse a partir de la tabla de correlaciones?
Pandas tiene métodos incorporados que permiten la realización de diversos gráficos.
Podemos realizar un gráfico de dispersión entre dos variables (columnas) de un dataframe utilizando plot.scatter()
que pandas tiene incorporado. Por ejemplo crearemos el diagrama de dispersión entre las columnas del largo del sépalo versus el ancho del sépalo:
df.plot.scatter(x='sepal_length', y='sepal_width', c='red')
<AxesSubplot:xlabel='sepal_length', ylabel='sepal_width'>
Podemos colorear los puntos del diagrama de dispersión de acuerdo a la especie, para ello utilizaremos al columna species_num
y reemplazaremos los valores 1,2 y 3 por códigos hexagécimales de tres diferentes colores:
dict_colores = {1: '#FF0000', 2: '#FF7F00', 3: '#FDDE0E'}
df = df.replace({'species_num': dict_colores})
df.head()
sepal_length | sepal_width | petal_length | petal_width | species | species_num | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa | #FF0000 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa | #FF0000 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa | #FF0000 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa | #FF0000 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa | #FF0000 |
# para el parametro c colocamos el nombre de la columna species_num
# el cual ahora tiene como entradas los codigos hexagecimales
# de tres diferentes colores
df.plot.scatter(x='sepal_length', y='sepal_width', c='species_num')
<AxesSubplot:xlabel='sepal_length', ylabel='sepal_width'>
Podemos aumentar el tamaño de los puntos mediante el parámetro s
:
ax = df.plot.scatter(x='sepal_length', y='sepal_width', c='species_num', s=50)
Un histograma es un gráfico que se utiliza para representar la distribución de frecuencias, lo cual nos puede servir para observar la distribución de una variable. Asimismo, un histograma nos puede servir para observar la frecuencia de aparición de ciertas clases.
Por ejemplo, podemos ver la frecuencia de aparición de cada especie:
# volveremos a tener la siguiente estructura en el dataframe:
# cargamos de nuevo los datos
df = sns.load_dataset("iris")
# diccionario para cambiar valores
dict_valor = {'setosa': 1, 'versicolor': 2, 'virginica': 3}
# agregamos una columna nueva
df['species_num'] = df.species
# cambiamos los valores de la columna anterior
df = df.replace({'species_num': dict_valor})
df.head()
sepal_length | sepal_width | petal_length | petal_width | species | species_num | |
---|---|---|---|---|---|---|
0 | 5.1 | 3.5 | 1.4 | 0.2 | setosa | 1 |
1 | 4.9 | 3.0 | 1.4 | 0.2 | setosa | 1 |
2 | 4.7 | 3.2 | 1.3 | 0.2 | setosa | 1 |
3 | 4.6 | 3.1 | 1.5 | 0.2 | setosa | 1 |
4 | 5.0 | 3.6 | 1.4 | 0.2 | setosa | 1 |
Para graficar un histograma deberemos de escribrir
<nombre_dataframe>.<nombre_columna_interes>.hist()
de modo que
ax = df.species_num.plot.hist()
lo cual nos dice, como sabíamos antes, que hay 50 elementos por especie. Es preciso mencionar que la variable o columna de la cual queremos graficar el histograma debe ser numérica.
Podemos graficar los siguientes histogramas:
# histogramas de frecuencia de la variable sepal_length
ax = df.sepal_length.plot.hist(bins = 20, grid=True, figsize=(10,4))
donde configuramos 20 rectángulos (bins=20
), mostramos la cuadrícula (grid=True
) y configuramos el tamaño del gráfico.
Podemos cambiar el color del histograma
# histogramas de frecuencia de la variable petal_length
ax = df.petal_length.plot.hist(bins = 20, grid=True, figsize=(10,4), color='red')
# histogramas de frecuencia de la variable petal_width
ax = df.petal_width.plot.hist(bins = 20, grid=True, figsize=(10,4),
color='#FF7F00')