Una base de datos es un conjunto de datos organizados y relacionados entre sí. Existen diferentes tipos de bases de datos, como las bases de datos relacionales y las bases de datos no relacionales.
Las bases de datos relacionales son las más comunes y se basan en el modelo relacional, que organiza los datos en tablas. Cada tabla tiene filas y columnas, donde cada fila representa un registro y cada columna representa un campo.
Las bases de datos no relacionales son aquellas que no se basan en el modelo relacional y pueden tener diferentes estructuras, como documentos, gráficos, clave-valor, entre otros.
Existen lenguajes de consulta para interactuar con las bases de datos, como SQL (Structured Query Language) para las bases de datos relacionales y NoSQL (Not only SQL) para las bases de datos no relacionales.
Aunque existen paqueterias en Python para interactuar con bases de datos, en este curso nos enfocaremos en la manipulación de datos con Pandas, una librería de Python que nos permite manipular datos de manera sencilla y eficiente. Los datos que cargarémos en este curso son datos en formato CSV, que es un formato de archivo que se utiliza para almacenar datos en forma de tabla.
A diferencia de las bases de datos, los datos en formato CSV no tienen un motor de base de datos que nos permita interactuar con ellos. Por lo tanto, no podemos hacer consultas con SQL, pero podemos manipular los datos con Pandas.
Manipulación de datos con Pandas
Pandas es una librería de Python que nos permite manipular datos de manera sencilla y eficiente. En este tutorial aprenderemos a leer, escribir y manipular datos con Pandas. Para leer datos, Pandas soporta una gran variedad de formatos, entre los que se encuentran CSV, Excel, JSON, entre otros.
Podemos leer los datos de manera local o por medio de una url que contenga los datos en bruto, en otro caso tendremos que ya sea descargar el archivo o usar librerias como requests para obtener los datos. En este caso leeremos los datos de una url desde el github de este curso. Para leer los datos en formato CSV, usamos la función pd.read_csv() de Pandas.
Código
import pandas as pd # Primero importamos la libreríaurl ='https://raw.githubusercontent.com/Christian-F-Badillo/Ciencia-de-datos-con-Python-de-estadistica-descriptiva-a-redes-neuronales/main/data/archive/mushroom_cleaned.csv'# Definimos la URL del archivo CSVdata = pd.read_csv(url) # Leemos el archivo CSV
Si tuvieramos un archivo CSV en nuestra computadora, podríamos leerlo de la siguiente manera:
archivo ='directorio/subdirectorio/archivo.csv'# Definimos la ruta del archivo CSVdata = pd.read_csv(archivo) # Leemos el archivo CSV
Explorando los datos
Primero como ya vimos en la lección anterior, podemos ver las primeras filas de los datos con el método head(). En este caso tenemos datos de hongos, donde cada fila representa un hongo y cada columna una característica del hongo.
Las columnas son las siguientes:
Cap Diameter: Diámetro del sombrero.
Cap Shape: Forma del sombrero.
Gill Attachment: Tipo de unión de las branquias.
Gill Color: Color de las branquias.
Stem Height: Altura del tallo.
Stem Width: Ancho del tallo.
Stem Color: Color del tallo.
Season: Temporada en la que se encontró el hongo.
Class: Si es comestible (0) o venerenoso (1).
Código
data.head()
cap-diameter
cap-shape
gill-attachment
gill-color
stem-height
stem-width
stem-color
season
class
0
1372
2
2
10
3.807467
1545
11
1.804273
1
1
1461
2
2
10
3.807467
1557
11
1.804273
1
2
1371
2
2
10
3.612496
1566
11
1.804273
1
3
1261
6
2
10
3.787572
1566
11
1.804273
1
4
1305
6
2
10
3.711971
1464
11
0.943195
1
Lo primero que podemos hacer es ver la forma de los datos, es decir, cuántas filas y columnas tenemos. Para esto usamos el atributo shape.
Código
data.shape
(54035, 9)
Tenemos 54039 y 9 columnas en nuestros datos. Podemos ver los nombres de las columnas con el atributo columns.
También podemos ver los tipos de datos de las columnas con el atributo dtypes.
Código
data.dtypes
cap-diameter int64
cap-shape int64
gill-attachment int64
gill-color int64
stem-height float64
stem-width int64
stem-color int64
season float64
class int64
dtype: object
El tipo de dato es muy importante, ya que restringe las cosas que podemos hacer con los datos. En este dataset, tenemos datos tipo int64 y float64 que son enteros y décimales respectivamente. El tipo de dato más común en Pandas es object, que es un tipo de dato genérico que puede contener cualquier tipo de dato, no es recomendable tener columnas con este tipo de dato, ya que puede ser un indicio de que los datos no están limpios.
Con el metodo info() podemos ver un resumen de los datos, incluyendo el número de valores no nulos y el uso de memoria.
Gracias a este método podemos ver que no tenemos valores nulos en nuestro dataset. Si tuvieramos valores nulos, tendríamos que decidir si eliminarlos, reemplazarlos o imputarlos (usar un valor promedio, mediana, moda, etc. para reemplazar los valores nulos).
Para identificar los valores NA en los datos, podemos usar el método isna(), combinado con el método sum() para ver el número de valores NA en cada columna.
Código
data.isna().sum()
cap-diameter 0
cap-shape 0
gill-attachment 0
gill-color 0
stem-height 0
stem-width 0
stem-color 0
season 0
class 0
dtype: int64
Podemos identificar los valores únicos de una columna con el método unique(). Por ejemplo, si queremos ver los valores únicos de la columna class, podemos hacer lo siguiente:
Código
data['class'].unique()
array([1, 0])
En este caso, los valores únicos son 0 y 1, que representan si el hongo es comestible o venenoso. Podemos ver los valores únicos de todas las columnas con el método unique().
Estadísticas descriptivas
Podemos obtener estadísticas descriptivas de los datos numéricos con el método describe().
Código
data.describe()
cap-diameter
cap-shape
gill-attachment
gill-color
stem-height
stem-width
stem-color
season
class
count
54035.000000
54035.000000
54035.000000
54035.000000
54035.000000
54035.000000
54035.000000
54035.000000
54035.000000
mean
567.257204
4.000315
2.142056
7.329509
0.759110
1051.081299
8.418062
0.952163
0.549181
std
359.883763
2.160505
2.228821
3.200266
0.650969
782.056076
3.262078
0.305594
0.497580
min
0.000000
0.000000
0.000000
0.000000
0.000426
0.000000
0.000000
0.027372
0.000000
25%
289.000000
2.000000
0.000000
5.000000
0.270997
421.000000
6.000000
0.888450
0.000000
50%
525.000000
5.000000
1.000000
8.000000
0.593295
923.000000
11.000000
0.943195
1.000000
75%
781.000000
6.000000
4.000000
10.000000
1.054858
1523.000000
11.000000
0.943195
1.000000
max
1891.000000
6.000000
6.000000
11.000000
3.835320
3569.000000
12.000000
1.804273
1.000000
Por comodidad se suele usar el método transpose() para ver las estadísticas descriptivas de manera vertical, una abreviatura de esto es .T.
Código
data.describe().T
count
mean
std
min
25%
50%
75%
max
cap-diameter
54035.0
567.257204
359.883763
0.000000
289.000000
525.000000
781.000000
1891.000000
cap-shape
54035.0
4.000315
2.160505
0.000000
2.000000
5.000000
6.000000
6.000000
gill-attachment
54035.0
2.142056
2.228821
0.000000
0.000000
1.000000
4.000000
6.000000
gill-color
54035.0
7.329509
3.200266
0.000000
5.000000
8.000000
10.000000
11.000000
stem-height
54035.0
0.759110
0.650969
0.000426
0.270997
0.593295
1.054858
3.835320
stem-width
54035.0
1051.081299
782.056076
0.000000
421.000000
923.000000
1523.000000
3569.000000
stem-color
54035.0
8.418062
3.262078
0.000000
6.000000
11.000000
11.000000
12.000000
season
54035.0
0.952163
0.305594
0.027372
0.888450
0.943195
0.943195
1.804273
class
54035.0
0.549181
0.497580
0.000000
0.000000
1.000000
1.000000
1.000000
Algunas estadísticas descriptivas que obtenemos son:
count: Número de valores no nulos.
mean: Media de los valores.
std: Desviación estándar de los valores.
min: Valor mínimo.
25%: Primer cuartil.
50%: Mediana.
75%: Tercer cuartil.
max: Valor máximo.
Podemos guardar estas estadísticas en un nuevo DataFrame para manipularlas más adelante.
Código
estadisticas = data.describe().T
Si recuerdan sus cursos de estadística una medida de dispersión es el rango, que es la diferencia entre el valor máximo y el valor mínimo. Podemos calcular el rango de los datos restándo el valor máximo y el valor mínimo de cada columna y guardarlo en una nueva columna llamada rango.
Otro estadístico importante es la varianza, que es una medida de dispersión que nos indica qué tan dispersos están los datos. Podemos calcular la varianza de los datos con el método var() y guardarla en una nueva columna llamada varianza.
Un último estadístico es el rango intercuartil (IQR), que es la diferencia entre el tercer cuartil y el primer cuartil. Podemos calcular el IQR de los datos al restar las columnas 75% y 25% y guardar el resultado en una nueva columna llamada IQR.
Podemos ver que hemos calculado el rango, la varianza y el IQR de los datos. Estos estadísticos nos dan una idea de la dispersión de los datos y nos ayudan a entender mejor los datos.
Otro estadtico importante es la correlación, que nos indica la relación entre dos variables. Podemos calcular la correlación de los datos con el método corr().
Código
correlacion = data.corr()correlacion
cap-diameter
cap-shape
gill-attachment
gill-color
stem-height
stem-width
stem-color
season
class
cap-diameter
1.000000
0.204011
0.200481
0.186377
0.135652
0.828469
0.121856
0.113334
-0.165676
cap-shape
0.204011
1.000000
0.043066
0.131387
-0.010393
0.222494
0.029035
0.055442
-0.133338
gill-attachment
0.200481
0.043066
1.000000
0.100276
-0.075284
0.245300
0.020073
-0.040315
-0.052541
gill-color
0.186377
0.131387
0.100276
1.000000
0.015057
0.110283
0.186090
0.059965
-0.063947
stem-height
0.135652
-0.010393
-0.075284
0.015057
1.000000
0.098095
0.002624
-0.000292
0.183354
stem-width
0.828469
0.222494
0.245300
0.110283
0.098095
1.000000
0.157394
0.040679
-0.182856
stem-color
0.121856
0.029035
0.020073
0.186090
0.002624
0.157394
1.000000
0.010750
-0.128339
season
0.113334
0.055442
-0.040315
0.059965
-0.000292
0.040679
0.010750
1.000000
-0.082919
class
-0.165676
-0.133338
-0.052541
-0.063947
0.183354
-0.182856
-0.128339
-0.082919
1.000000
Filtrando datos
Podemos filtrar los datos de acuerdo a una condición. Por ejemplo, si queremos ver los hongos que son venenosos, podemos filtrar los datos de la siguiente manera:
La notación para realizar filtrado en pandas es df[df['columna'] == valor], donde df es el DataFrame, columna es la columna que queremos filtrar y valor es el valor que queremos filtrar.
Podemos hacer filtrados más complejos, por ejemplo, si queremos ver los hongos venenosos que tienen un diámetro de sombrero mayor a su media, podemos hacer lo siguiente:
La sintaxis en este caso es df[(df['columna1'] == valor1) & (df['columna2'] > valor2)], donde & es el operador lógico AND y cada condición va entre paréntesis. Es recomendable no usar más de dos condiciones en un filtro, ya que puede ser difícil de leer.
Otras operaciones lógicas que podemos usar son | para el operador OR y ~ para el operador NOT. Por ejemplo, si queremos ver los hongos que son venenosos o que tienen un diámetro de sombrero mayor a su media, podemos hacer lo siguiente:
Podemos ordenar los datos de acuerdo a una columna. Por ejemplo, si queremos ordenar los hongos por su diámetro de sombrero de manera ascendente, podemos hacer lo siguiente:
Código
data.sort_values(by='cap-diameter').head()
cap-diameter
cap-shape
gill-attachment
gill-color
stem-height
stem-width
stem-color
season
class
11696
0
6
0
11
1.019047
21
12
0.943195
1
12214
1
2
1
6
0.895698
42
7
0.943195
1
11814
1
6
0
11
1.198101
1
11
0.888450
1
12206
2
2
1
6
1.058837
31
7
0.943195
1
35395
2
0
0
3
1.452757
174
6
0.943195
1
Hemos utilizado el método sort_values() para ordenar los datos de acuerdo a la columna cap-diameter. Por defecto, el método ordena de manera ascendente, pero podemos cambiarlo a descendente con el argumento ascending=False. El argumento by es la columna por la que queremos ordenar los datos. Si queremos ordenar los datos de manera descendente, podemos hacer lo siguiente:
Para ordenar con múltiples columnas, podemos pasar una lista de columnas al argumento by. Por ejemplo, si queremos ordenar los hongos por su diámetro de sombrero de manera ascendente y por su altura de tallo de manera descendente, podemos hacer lo siguiente:
Con el argumento kind podemos especificar el algoritmo de ordenamiento. En este caso hemos usado mergesort, que es un algoritmo de ordenamiento estable y eficiente. Otros algoritmos que podemos usar son quicksort y heapsort.
El ordenamiento con más de una columna es útil cuando queremos ordenar los datos de acuerdo a una columna y en caso de empate, ordenarlos de acuerdo a otra columna. En este caso, primero ordenamos los datos de acuerdo a la columna cap-diameter y en caso de empate, ordenamos los datos de acuerdo a la columna stem-height. Podemos comprobarlo viendo los primeros 10 datos.
Agrupando datos
Podemos agrupar los datos de acuerdo a una columna. Por ejemplo, si queremos agrupar los hongos por su color de tallo y ver cuántos hongos hay de cada color, podemos hacer lo siguiente:
El método groupby() agrupa los datos de acuerdo a una columna y el método size() nos da el tamaño de cada grupo. En este caso, hemos agrupado los hongos por su color de tallo y hemos obtenido el tamaño de cada grupo.
Otro método que podemos usar es count(), que nos da el número de valores no nulos de cada columna.
Código
data.groupby('stem-color').count()
cap-diameter
cap-shape
gill-attachment
gill-color
stem-height
stem-width
season
class
stem-color
0
173
173
173
173
173
173
173
173
1
1918
1918
1918
1918
1918
1918
1918
1918
2
1059
1059
1059
1059
1059
1059
1059
1059
3
2626
2626
2626
2626
2626
2626
2626
2626
4
576
576
576
576
576
576
576
576
5
226
226
226
226
226
226
226
226
6
15316
15316
15316
15316
15316
15316
15316
15316
7
1848
1848
1848
1848
1848
1848
1848
1848
8
1025
1025
1025
1025
1025
1025
1025
1025
9
541
541
541
541
541
541
541
541
10
1393
1393
1393
1393
1393
1393
1393
1393
11
20317
20317
20317
20317
20317
20317
20317
20317
12
7017
7017
7017
7017
7017
7017
7017
7017
La diferencia es que size() nos da el tamaño de cada grupo, mientras que count() nos da el número de valores no nulos de cada columna.
Para hacer operaciones más complejas, podemos usar el método agg(), que nos permite aplicar una o más funciones a cada grupo. Por ejemplo, si queremos obtener la media y la mediana del diámetro de sombrero de cada grupo, podemos hacer lo siguiente:
En este caso, hemos agrupado los hongos por su color de tallo y hemos obtenido la media y la mediana del diámetro de sombrero de cada grupo.
Guardando datos
Podemos guardar los datos en un archivo CSV con el método to_csv(). Por ejemplo, si queremos guardar los datos en un archivo llamado mushroom.csv, podemos hacer lo siguiente:
Código
#data.to_csv('mushroom.csv', index=False)
El argumento index=False evita que se guarde el índice en el archivo CSV. Existen otros formatos en los que podemos guardar los datos, como Excel, JSON, entre otros. Para guardar los datos en un archivo Excel, podemos usar el método to_excel().
Código
#data.to_excel('mushroom.xlsx', index=False)
Para guardar los datos en un archivo JSON, podemos usar el método to_json().
Código
#data.to_json('mushroom.json', orient='records')
Ejercicios
Creen un documento de Jupyter Notebook por equipo y resuelvan los siguientes ejercicios, utilicen Markdown para explicar sus respuestas y comentarios en el código. Se sugiere la creación de funciones para resolver los ejercicios.
Carga los datos de Iris desde la siguiente liga “https://raw.githubusercontent.com/mwaskom/seaborn-data/master/iris.csv” y muestra las primeras 10 filas, muestra la forma de los datos, los nombres de las columnas, los tipos de datos, el tamaño de los datos y si hay valores nulos (NA).
Calcula las estadísticas descriptivas de los datos.
Filtra los datos para obtener las flores que tienen un ancho de pétalo mayor a su media, mediana, media y mediana. Impreme las primeras 10 filas.
Ordena los datos de acuerdo a la longitud de sépalo de manera ascendente y de acuerdo a la longitud de pétalo de manera descendente. Muestra las primeras 10 filas.
Filtra los datos para obtener las flores que tienen un ancho de pétalo mayor a su media y que son de la especie setosa. Muestra las primeras 10 filas.
Agrupa los datos por especie y calcula los estadísticos descriptivos de cada grupo (media, mediana, moda, varianza, rango, IQR). Muestra los resultados.
Guarda los datos de los estadísticos descriptivos del ejercicio 2 en un archivo CSV, Excel y JSON.
Calcula la correlación de los datos y muestra los resultados.
Sugiere que gráficos podrías hacer con los datos y que información podrías obtener de ellos.
Explica ¿qué análisis podrías hacer con los datos?, ¿qué preguntas podrías responder con los datos?
Conclusiones
La manipulación de datos es una parte fundamental de la ciencia de datos, ya que nos permite limpiar, transformar y analizar los datos para obtener información útil. En este tutorial hemos aprendido a leer, escribir y manipular datos con Pandas. Hemos visto cómo explorar los datos, obtener estadísticas descriptivas, filtrar los datos, ordenar los datos, agrupar los datos y guardar los datos en diferentes formatos. Estas son habilidades básicas que nos permiten trabajar con los datos de manera eficiente y efectiva.