miad4.png

Hide code cell source
import os
# Por precaución, cambiamos el directorio activo de Python a aquel que contenga este notebook
if "PAD-book" in os.listdir():
    os.chdir(r"PAD-book/Laboratorio-Computacional-de-Analytics/S4 - Explorar, modificar y visualizar bases de datos/S4.TU1/")

Explorar bases de datos#

Explorar bases de datos es uno de los pasos esenciales en cualquier proyecto de analítica de datos, pues nos permite identificar aspectos útiles del caso de estudio.

En este tutorial establecemos nociones fundamentales sobre el uso del paquete pandas para explorar datos.

Requisitos#

Para desarrollar este tutorial necesitarás:

  • Utilizar arreglos y operaciones básicas y vectorizadas en numpy.

  • Crear, consultar y utilizar métodos para explorar y manipular objetos tipo DataFrame en pandas.

Objetivos#

Al final de este tutorial podrás:

1. Indexar un DataFrame empleando índices múltiples.
2. Aplicar distintos tipos de filtrado utilizando pandas.

1. Indexar un DataFrame#

Entre los aspectos a detallar al explorar una base de datos, se encuentra la llave o el ID que distingue un registro de otro. Esta llave no siempre se conoce de antemano o, en ocasiones, deseamos modificarla.

Para distinguir una observación (o fila) de otra en un DataFrame, pandas define un objeto de tipo Index (o MultiIndex).

Al analizar datos generalmente requerimos que el índice de un DataFrame corresponda a una llave de la base de datos. Todo registro debe tener asignada una llave única, con el fin de distinguirlo de los demás registros. En ocasiones debemos usar más de una característica del registro para crear una llave, es decir, debemos definir un índice de múltiples niveles.

Importamos los paquetes pandas y numpy .

import numpy as np
import pandas as pd

Veamos el siguiente ejemplo para considerar un caso en el que se necesite más de una columna para indexar un DataFrame:

Ejemplo 1#

En la siguiente celda de código declaramos un DataFrame que contiene información de algunas personas.

nombres = pd.DataFrame([["Jorge", "Suárez", 28, "Bogotá"],
                        ["Laura", "Poveda", 37, "Lima"  ],
                        ["Pablo", "Stecco", 30, "Lima"  ],
                        ["Jorge", "Poveda", 30, "Bogotá"]],
                       columns = ["Nombre", "Apellido", "Edad", "Ciudad"])
nombres
Nombre Apellido Edad Ciudad
0 Jorge Suárez 28 Bogotá
1 Laura Poveda 37 Lima
2 Pablo Stecco 30 Lima
3 Jorge Poveda 30 Bogotá

Si bien es posible utilizar la columna "nombre" para indexar la base de datos, este índice no sería una llave, puesto que uno de los valores del índice ("Jorge") corresponde a más de un registro:

  • ["Jorge", "Suárez", 28, "Bogotá"] y

  • ["Jorge", "Poveda", 30, "Bogotá"].

nombres.index = nombres['Nombre']
nombres.loc['Jorge']
Nombre Apellido Edad Ciudad
Nombre
Jorge Jorge Suárez 28 Bogotá
Jorge Jorge Poveda 30 Bogotá

Dado que queremos utilizar el nombre para construir la llave de nuestra base de datos, podemos agregar a cada valor del índice el apellido del registro y así evitar valores duplicados.

nombres_indice = pd.Index(data = nombres[["Nombre", "Apellido"]])
nombres.index = nombres_indice

nombres
Nombre Apellido Edad Ciudad
(Jorge, Suárez) Jorge Suárez 28 Bogotá
(Laura, Poveda) Laura Poveda 37 Lima
(Pablo, Stecco) Pablo Stecco 30 Lima
(Jorge, Poveda) Jorge Poveda 30 Bogotá

Con la modificación anterior podemos referirnos a la información de "Jorge Suárez" o de "Jorge Poveda".

nombres.loc[[("Jorge", "Poveda")]]
Nombre Apellido Edad Ciudad
(Jorge, Poveda) Jorge Poveda 30 Bogotá

1.1. Objeto de tipo MultiIndex#

La clase MultiIndex permite crear un índice múltiple para los registros de un DataFrame o un Series. Podemos declarar objetos de tipo MultiIndex a partir de métodos que reciben diferentes tipos de objeto por parámetro.

Métodos

Descripción

from_arrays

A partir de un arreglo de arreglos

from_product

A partir del producto cartesiano de estructuras de datos

from_tuples

A partir de una lista de tuplas

from_frame

A partir de la lista actual con otra lista

Ejemplo 2#

Creamos un MultiIndex a partir de las columnas "nombre" y "apellido"y lo utilizamos para indexar el DataFrame contenido en la variable nombres.

Usamos el método from_arrays.

nombres_indice = pd.MultiIndex.from_arrays([nombres["Nombre"],nombres["Apellido"]])
nombres_indice
MultiIndex([('Jorge', 'Suárez'),
            ('Laura', 'Poveda'),
            ('Pablo', 'Stecco'),
            ('Jorge', 'Poveda')],
           names=['Nombre', 'Apellido'])

Después usamos el método reindex para asignar el nuevo MultiIndex.

nombres.reindex(nombres_indice)
Nombre Apellido Edad Ciudad
Nombre Apellido
Jorge Suárez Jorge Suárez 28 Bogotá
Laura Poveda Laura Poveda 37 Lima
Pablo Stecco Pablo Stecco 30 Lima
Jorge Poveda Jorge Poveda 30 Bogotá

También podemos nombrar columnas que tengan múltiples niveles a partir de un objeto MultiIndex.

Ejemplo 3#

A continuación importamos una base de datos llamada "Bid-Cornell.csv" que reúne información sobre un grupo de ciudadanos y los medios de comunicación que utilizan para informarse sobre noticias generales o noticias acerca del COVID-19.

df_covid_19 = pd.read_csv("./Archivos/BID-Cornell.csv", index_col = 0) 
df_covid_19
medios_noti_redessociales medios_noti_chat medios_noti_periodicos medios_noti_tv medios_noti_radio medios_covid_redessociales medios_covid_chat medios_covid_periodicos medios_covid_tv medios_covid_radio
id
1000060.0 Siempre Siempre Casi siempre A veces Nunca Siempre Siempre Siempre A veces Nunca
1000734.0 Casi siempre A veces A veces Casi siempre Casi siempre Casi siempre Casi siempre A veces Casi siempre Casi siempre
1000120.0 Nunca A veces A veces Siempre Siempre Nunca A veces A veces Siempre Siempre
1000235.0 Siempre Siempre A veces A veces A veces Siempre Siempre Nunca A veces Nunca
1000828.0 Casi siempre A veces A veces A veces A veces Casi siempre Casi siempre A veces A veces Nunca
... ... ... ... ... ... ... ... ... ... ...
17001614.0 A veces A veces Casi siempre Siempre Casi siempre Nunca A veces Casi siempre Siempre Casi siempre
17017448.0 Siempre Siempre A veces A veces Nunca Siempre Siempre A veces A veces Nunca
17013032.0 Siempre Siempre Siempre Siempre Siempre Siempre Casi siempre Siempre Siempre Siempre
17014760.0 Siempre Siempre Siempre Casi siempre Casi siempre Siempre Siempre Siempre Casi siempre Casi siempre
17003990.0 Casi siempre Nunca Nunca Casi siempre Casi siempre Casi siempre Nunca A veces Casi siempre Casi siempre

216092 rows × 10 columns

Los nombres de las columnas de df_covid_19 están estructurados de la siguiente manera:

  1. Prefijo:

    • Medios de comunicación ("medios").

  2. Contexto de la información:

    • Noticias generales ("noti").

    • Noticias sobre el COVID-19 ("covid").

  3. Medio de comunicación empleado:

    • Redes Sociales ("redessociales").

    • Chat ("chat").

    • Periodicos ("periodicos").

    • TV ("tv").

    • Radio ("radio").

Por ejemplo, "medios_noti_redessociales" representa que el medio de comunicación utilizado para informarse acerca de noticias generales es las redes sociales.

Podemos utilizar un objeto MultiIndex para nombrar las columnas con un mejor orden, coherente con la estructura descrita. Seccionamos el nombre de cada columna donde coincidan guiones bajos ("_") empleando métodos de pandas para columnas con datos de tipo str.

#Obtenemosla lista de columnas del DataFrame y con .str tomamos para cada una
#lo que está después de "medios_" (por eso el [7:])
df_covid_19.columns = df_covid_19.columns.str[7:]

#Separamos las cadenas de texto al encontrar un "_"
#El parámetro expand nos indica si deseamos dividir la cadena en columnas separadas (creando el multiindex)
indice_multiple_columnas = df_covid_19.columns.str.split("_", expand = True)
indice_multiple_columnas
MultiIndex([( 'noti', 'redessociales'),
            ( 'noti',          'chat'),
            ( 'noti',    'periodicos'),
            ( 'noti',            'tv'),
            ( 'noti',         'radio'),
            ('covid', 'redessociales'),
            ('covid',          'chat'),
            ('covid',    'periodicos'),
            ('covid',            'tv'),
            ('covid',         'radio')],
           )
#Reasignamos el multinindex que creamos antes a las columnas del DataFrame (df)
df_covid_19.columns = indice_multiple_columnas
df_covid_19
noti covid
redessociales chat periodicos tv radio redessociales chat periodicos tv radio
id
1000060.0 Siempre Siempre Casi siempre A veces Nunca Siempre Siempre Siempre A veces Nunca
1000734.0 Casi siempre A veces A veces Casi siempre Casi siempre Casi siempre Casi siempre A veces Casi siempre Casi siempre
1000120.0 Nunca A veces A veces Siempre Siempre Nunca A veces A veces Siempre Siempre
1000235.0 Siempre Siempre A veces A veces A veces Siempre Siempre Nunca A veces Nunca
1000828.0 Casi siempre A veces A veces A veces A veces Casi siempre Casi siempre A veces A veces Nunca
... ... ... ... ... ... ... ... ... ... ...
17001614.0 A veces A veces Casi siempre Siempre Casi siempre Nunca A veces Casi siempre Siempre Casi siempre
17017448.0 Siempre Siempre A veces A veces Nunca Siempre Siempre A veces A veces Nunca
17013032.0 Siempre Siempre Siempre Siempre Siempre Siempre Casi siempre Siempre Siempre Siempre
17014760.0 Siempre Siempre Siempre Casi siempre Casi siempre Siempre Siempre Siempre Casi siempre Casi siempre
17003990.0 Casi siempre Nunca Nunca Casi siempre Casi siempre Casi siempre Nunca A veces Casi siempre Casi siempre

216092 rows × 10 columns

De esta manera, si queremos tener acceso a la información sobre el uso de las redes sociales como medio de comunicación para informarse sobre el COVID-19, podemos usar el método loc.

df_covid_19.loc[:, ('covid', 'redessociales')]
id
1000060.0          Siempre
1000734.0     Casi siempre
1000120.0            Nunca
1000235.0          Siempre
1000828.0     Casi siempre
                  ...     
17001614.0           Nunca
17017448.0         Siempre
17013032.0         Siempre
17014760.0         Siempre
17003990.0    Casi siempre
Name: (covid, redessociales), Length: 216092, dtype: object

2. Filtrar bases de datos utilizando la librería pandas#

2.1. Filtrado de posiciones no consecutivas#

Si las posiciones que queremos seleccionar no son consecutivas, debemos representarlas en una lista. A continuación, vemos un ejemplo de esto.

Ejemplo 5#

Se nos solicita mostrar un DataFrame que contenga únicamente las 10 primeras y las 10 últimas observaciones del DataFrame df_covid_19.

posiciones_filas = list(range(10)) + list(range(-10,0))
df_10_y_10 = df_covid_19.iloc[posiciones_filas, : ]
df_10_y_10
noti covid
redessociales chat periodicos tv radio redessociales chat periodicos tv radio
id
1000060.0 Siempre Siempre Casi siempre A veces Nunca Siempre Siempre Siempre A veces Nunca
1000734.0 Casi siempre A veces A veces Casi siempre Casi siempre Casi siempre Casi siempre A veces Casi siempre Casi siempre
1000120.0 Nunca A veces A veces Siempre Siempre Nunca A veces A veces Siempre Siempre
1000235.0 Siempre Siempre A veces A veces A veces Siempre Siempre Nunca A veces Nunca
1000828.0 Casi siempre A veces A veces A veces A veces Casi siempre Casi siempre A veces A veces Nunca
1000352.0 A veces A veces Siempre Casi siempre Casi siempre A veces A veces Siempre Siempre Siempre
1000746.0 Casi siempre Casi siempre Casi siempre Casi siempre Nunca Casi siempre Casi siempre Casi siempre Casi siempre Nunca
1000079.0 Siempre Siempre Siempre Nunca A veces Siempre Siempre Siempre Nunca A veces
1000110.0 Siempre Siempre Siempre Siempre Siempre Siempre Siempre Siempre Siempre Siempre
1000221.0 Casi siempre A veces Siempre Siempre Nunca Casi siempre A veces Siempre Siempre Nunca
17000500.0 Siempre Siempre Siempre Siempre Casi siempre Casi siempre Casi siempre Casi siempre Siempre Casi siempre
17000564.0 Casi siempre A veces A veces Nunca A veces Casi siempre Casi siempre A veces Nunca A veces
17015108.0 A veces A veces A veces Nunca Nunca A veces A veces A veces Nunca Nunca
17020582.0 Siempre Siempre Siempre Siempre Siempre Siempre Siempre Siempre Siempre Siempre
17003368.0 Siempre Siempre A veces A veces A veces Siempre Siempre A veces Siempre A veces
17001614.0 A veces A veces Casi siempre Siempre Casi siempre Nunca A veces Casi siempre Siempre Casi siempre
17017448.0 Siempre Siempre A veces A veces Nunca Siempre Siempre A veces A veces Nunca
17013032.0 Siempre Siempre Siempre Siempre Siempre Siempre Casi siempre Siempre Siempre Siempre
17014760.0 Siempre Siempre Siempre Casi siempre Casi siempre Siempre Siempre Siempre Casi siempre Casi siempre
17003990.0 Casi siempre Nunca Nunca Casi siempre Casi siempre Casi siempre Nunca A veces Casi siempre Casi siempre

Ejemplo 6#

Se nos solicita mostrar un DataFrame que contenga únicamente las 3 primeras columnas y de la columna 6 en adelante del DataFrame df_covid_19.

posiciones_columnas = list(range(3)) + list(range(5, len(df_covid_19.columns)))
df_3_y_6_en_adelante = df_covid_19.iloc[ : , posiciones_columnas]
df_3_y_6_en_adelante
noti covid
redessociales chat periodicos redessociales chat periodicos tv radio
id
1000060.0 Siempre Siempre Casi siempre Siempre Siempre Siempre A veces Nunca
1000734.0 Casi siempre A veces A veces Casi siempre Casi siempre A veces Casi siempre Casi siempre
1000120.0 Nunca A veces A veces Nunca A veces A veces Siempre Siempre
1000235.0 Siempre Siempre A veces Siempre Siempre Nunca A veces Nunca
1000828.0 Casi siempre A veces A veces Casi siempre Casi siempre A veces A veces Nunca
... ... ... ... ... ... ... ... ...
17001614.0 A veces A veces Casi siempre Nunca A veces Casi siempre Siempre Casi siempre
17017448.0 Siempre Siempre A veces Siempre Siempre A veces A veces Nunca
17013032.0 Siempre Siempre Siempre Siempre Casi siempre Siempre Siempre Siempre
17014760.0 Siempre Siempre Siempre Siempre Siempre Siempre Casi siempre Casi siempre
17003990.0 Casi siempre Nunca Nunca Casi siempre Nunca A veces Casi siempre Casi siempre

216092 rows × 8 columns

2.2. Filtrado por niveles#

El objeto IndexSlice nos permite indicar, para cada nivel de un objeto MultiIndex, qué elementos queremos incluir.

Ejemplo 7#

A partir de la base de datos del BID, nos solicitan seleccionar las columnas que tengan información de noticias generales ("noti") sobre el uso del "chat" o "tv":

df_covid_19.loc[:, pd.IndexSlice["noti", ('chat','tv')]]
noti
chat tv
id
1000060.0 Siempre A veces
1000734.0 A veces Casi siempre
1000120.0 A veces Siempre
1000235.0 Siempre A veces
1000828.0 A veces A veces
... ... ...
17001614.0 A veces Siempre
17017448.0 Siempre A veces
17013032.0 Siempre Siempre
17014760.0 Siempre Casi siempre
17003990.0 Nunca Casi siempre

216092 rows × 2 columns

2.3. Filtrado condicional#

El filtrado condicional nos permite indicarle a un DataFrame, mediante un arreglo de objetos tipo bool, cuales elementos incluir. Podemos declarar un arreglo de objetos tipo bool aplicando, término a término, los operadores relacionales (==, !=, >, <, >=, <=) o lógicos (&, |, ~) que ya conoces.

A continuación, encuentras un ejemplo utilizando un operador relacional:

np.array([2, 2, 3, 4]) >= 3

>>> array([False, False, True, True])

A continuación, encuentras un ejemplo utilizando un operador lógico:

np.array([True, False, False, True]) | np.array([False, True, False, True])

>>> array([ True,  True, False,  True])

Veamos un ejemplo de cómo aplicar filtrado condicional a las filas de un DataFrame.

Ejemplo 8#

Seleccionemos los registros correspondientes a personas menores de 35 años, oriundas de "Lima".

nombres[(nombres['Edad'] <= 35) & (nombres['Ciudad'] == "Lima")]
Nombre Apellido Edad Ciudad
(Pablo, Stecco) Pablo Stecco 30 Lima

Veamos un ejemplo de cómo aplicar filtrado condicional a las columnas de un DataFrame.

Ejemplo 9#

Seleccionemos los registros correspondientes a personas menores de 35 años, oriundas de "Lima", exluyendo las columnas cuyo nombre tenga menos de 6 caracteres.

Para esto, utilizamos el atributo loc.

nombres.loc[(nombres['Edad'] <= 35) & (nombres['Ciudad'] == "Lima"), nombres.columns.str.len() > 5]
Nombre Apellido Ciudad
(Pablo, Stecco) Pablo Stecco Lima

Referencias#

Pandas (2020). Documentación sobre el método .iloc(). Recuperado el 11 de febrero de 2020 de: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iloc.html

Pandas (2020). Documentación sobre el método .loc(). Recuperado el 11 de febrero de 2020 de: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.loc.html

Pandas (2020). Documentación sobre el método .IndexSlice() . Recuperado el 11 de febrero de 2020 de: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.IndexSlice.html

BID (2020). Encuesta Coronavirus BID/Cornell. Recuperado el 11 de febrero de 2020 de: https://data.iadb.org/DataCatalog/Dataset#DataCatalogID=11319/28452

Créditos#

Autores: Juan David Reyes Jaimes, Jorge Esteban Camargo Forero, Alejandro Mantilla Redondo, Diego Alejandro Cely Gómez

Fecha última actualización: 12/07/2022