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/S3 - Librerias para manejo de datos/S3.TU1/")

Librerías para manejo de datos: numpy y pandas#

En programación, una librería es un conjunto de funcionalidades que ya están escritas y podemos llamar para utilizarlas en nuestros programas. La librería numpy nos ofrece la posibilidad de crear arreglos y matrices multidimensionales lo cual nos permite estructurar datos, con el fin de analizarlos más adelante. Por otro lado, pandas es una librería de Python que ofrece la posibilidad de manipular y explorar datos que forma fácil y rápida.

En este tutorial establecemos nociones fundamentales sobre el uso de las librerías numpy y pandas, para integrarlos en procesos de análisis de datos.

Requisitos#

Para desarrollar este tutorial necesitarás:

  • Utilizar estructuras de datos (listas, tuplas, diccionarios).

  • Utilizar estructuras de control (if, for, while).

Objetivos#

Al final de este tutorial podrás:

1. Utilizar arreglos y operaciones básicas y vectorizadas en numpy.
2. Crear, consultar y utilizar métodos para explorar y manipular objetos tipo Series y DataFrame en pandas.

1. Librería numpy#

numpy es una librería de uso abierto para el lenguaje de Python que permite crear vectores (arreglos) y matrices multidimensionales. Esta librería nos ofrece la posibilidad de llevar a cabo operaciones matemáticas de alto nivel y con una gran velocidad.

Te recomendamos importar la libería numpy utilizando el nombre np (su alias más frecuentemente usado), como se muestra a continuación.

import numpy as np

1.1. Declaración, consulta y operaciones básicas con arreglos#

Los arreglos son la estructura principal que nos provee numpy. Estos nos permiten guardar información en un contenedor para aplicar operaciones sobre ellos posteriormente. Los arreglos de numpy tienen más funcionalidades que las listas nativas de Python.

Declaración#

Para declarar un arreglo utilizamos el método array del paquete numpy.

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

print(arreglo)
[1 2 3 4]

Consulta#

Accedemos a un elemento en un arreglo con la misma sintaxis que consultamos listas. A continuación vemos un ejemplo de cómo acceder al primer elemento del arreglo arreglo.

elemento1 = arreglo[0]

print("El primer elemento del arreglo es " + str(elemento1) + ".")
El primer elemento del arreglo es 1.

Rebanado#

Utilizamos la misma notación de las listas nativas de Python para acceder a una porción de un arreglo. A continuación vemos un ejemplo de cómo acceder a los últimos dos elementos del arreglo arreglo.

porcion_arreglo = arreglo[-2:]

print(porcion_arreglo)
[3 4]

Operaciones básicas con arreglos: agregar y eliminar elementos#

Revisemos como añadir un elemento a un arreglo. Para esto, debemos especificar el arreglo y el elemento que queremos añadir al final del mismo.

arreglo = np.append(arreglo, 5)

print(arreglo)
[1 2 3 4 5]

Ahora, revisemos como eliminar un elemento de un arreglo. Para esto, debemos especificar el arreglo y la posición del elemento que queremos eliminar.

arreglo = np.delete(arreglo, 1)

print(arreglo)
[1 3 4 5]

1.2. Métodos comunes con arreglos en numpy#

La ventaja de utilizar arreglos de numpy es que estos tienen un gran número de métodos que nos permiten llevar a cabo diversos tipos de análisis. A continuación, definiremos un arreglo de tipo numerico e implementaremos algunos de los métodos más utilizados. Recomendamos que revises la bibliografía para expandir el conocimiento acerca de otros métodos.

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

Suma#

Calcula la suma de todos los elementos de un arreglo, siempre y cuando todos sean de tipo numerico.

suma = arreglo.sum()

print("La suma de todos los elementos es " + str(suma) + ".")
La suma de todos los elementos es 10.

Promedio#

Calcula el promedio de todos los elementos de un arreglo, siempre y cuando todos sean de tipo numerico.

promedio = arreglo.mean()

print("El promedio de todos los elementos es " + str(promedio) + ".")
El promedio de todos los elementos es 2.5.

Máximo y mínimo#

Calcula el máximo y mínimo elemento dentro de un arreglo, respectivamente, siempre y cuando todos los elementos sean de tipo numerico.

maximo = arreglo.max()

print("El máximo elemento es " + str(maximo) + ".")
El máximo elemento es 4.
minimo = arreglo.min()

print("El minimo elemento es " + str(minimo) + ".")
El minimo elemento es 1.

Concatenar#

Concatena dos o más arreglos en uno.

arreglo_1 = np.array([1,2,3,4])
arreglo_2 = np.array([5,6,7,8])

arreglo_concat = np.concatenate((arreglo_1, arreglo_2))

print(arreglo_concat)
[1 2 3 4 5 6 7 8]

1.3. Operaciones básicas sobre vectores con numpy#

Otra gran funcionalidad que nos provee numpy es la posibilidad de realizar operaciones vectoriales de una manera sencilla y rápida. Para esto, veremos como crear matrices con numpy.

Matrices#

numpy provee la posibilidad de crear matrices multidimensionales a las cuales les podemos aplicar múltiples operaciones. La forma de crearlas en numpy es la siguiente:

matriz = np.array( [ [1,2,3], [4,5,6] ] )
matriz
array([[1, 2, 3],
       [4, 5, 6]])

Creemos dos matrices para aplicarles algunas operaciones:

mat_1 = np.array([[1,2], [3,4]])
mat_1
array([[1, 2],
       [3, 4]])
mat_2 = np.array([[1,1], [4,4]])
mat_2
array([[1, 1],
       [4, 4]])

Ahora, procedamos a ver operaciones con matrices en numpy.

Suma término a término#

Para sumar cada elemento de mat_1 con el elemento ubicado en la misma posición de mat_2, utilizamos el operador +.

suma_matrices = mat_1 + mat_2
suma_matrices
array([[2, 3],
       [7, 8]])

Multiplicación término a término#

Para multiplicar cada elemento de mat_1 con el elemento ubicado en la misma posición de mat_2, utilizamos el operador *.

producto_matrices = mat_1 * mat_2
producto_matrices
array([[ 1,  2],
       [12, 16]])

Multiplicación matricial#

Para realizar una multiplicación matricial en numpy utilizamos el método dot().

mat_1_por_mat_2 = mat_1.dot(mat_2)
mat_1_por_mat_2
array([[ 9,  9],
       [19, 19]])
mat_2_por_mat_1 = mat_2.dot(mat_1)
mat_2_por_mat_1
array([[ 4,  6],
       [16, 24]])

Matriz transpuesta#

Para transponer una matriz en numpy utilizamos el método transpose().

trans_matriz = mat_1.transpose()
trans_matriz
array([[1, 3],
       [2, 4]])

Expresión lógica término a término#

Podemos aplicar los operadores lógicos &, | y ~ (similares a and, or y not, respectivamente) a dos objetos tipo array de numpy (que contengan valores de tipo bool), con el fin de evaluar término a término la condición lógica.

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

2. Librería pandas#

pandas es una librería abierta de Python que permite llevar a cabo manipulación y exploración de datos de forma sencilla. Sus estructuras básicas son llamadas Series y DataFrame, y nos permiten almacenar, limpiar y analizar datos.

Te recomendamos importar la libería pandas utilizando el nombre pd (su alias más frecuentemente usado), como se muestra a continuación.

import pandas as pd

2.1. Objeto Series#

Un Series es un objeto unidimensional similar a una columna de una matriz, en el cual podemos almacenar datos. Un Series esta compuesto por índices y datos almacenados.

Índice

Datos

1

A

2

B

3

C

4

D

5

E

Declaración#

Podemos declarar un Series a partir de diferentes estructuras de datos. A continuación, vemos un ejemplo de declaración a partir de una lista:

serie = pd.Series(['A','B','C','D','E'])

serie
0    A
1    B
2    C
3    D
4    E
dtype: object

También podemos usar diccionarios para declarar Series, a continuación vemos un ejemplo de cómo hacerlo:

serie = pd.Series({"Colombia":"Bogotá", "Argentina": "Buenos Aires", "Peru": "Lima", "Mexico": "Ciudad de Mexico"})

serie
Colombia               Bogotá
Argentina        Buenos Aires
Peru                     Lima
Mexico       Ciudad de Mexico
dtype: object

Finalmente, veamos cómo darle valor a los índices y nombrar el Series:

serie = pd.Series(['A','B','C','D','E'], index = [10,20,30,40,50], name = "Mi_serie")

serie
10    A
20    B
30    C
40    D
50    E
Name: Mi_serie, dtype: object

Consulta#

Para acceder a un elemento de un Series podemos hacer uso de su posición o del valor de su índice, utilizando los atributos iloc o loc, respectivamente. A continuación, veremos un ejemplo de cómo acceder al segundo elemento según su posición.

elem_2 = serie.iloc[1]
elem_2
'B'

También veremos un ejemplo de cómo acceder al segundo elemento según su índice.

elem_2 = serie.loc[20]
elem_2
'B'

Rebanado#

De manera similar a cómo accedimos a un elemento, también podemos acceder a una porción de un Series utilizando los atributos iloc y loc, y la sintaxis que ya hemos aprendido anteriormente para rebanar. Veremos cómo obtener los primeros dos elementos del Series serie usando un rebanado por posición:

parte_serie = serie.iloc[0:2]

parte_serie
10    A
20    B
Name: Mi_serie, dtype: object

2.2. Objeto DataFrame#

Un DataFrame es una estructura de datos mutable de dos dimensiones: filas y columnas. Usualmente utilizamos un DataFrame para registrar observaciones de variables o características. A cada observación le corresponde una fila y a cada característica una columna.

Esta convención no es exclusiva de Python, generalmente los programas para el análisis de datos se manejan de la misma manera.

Podemos ver en la siguiente tabla un ejemplo de como ordenamos observaciones en una tabla o DataFrame

Índice

Nombre

Sexo

Estatura (metros)

0

Alejandro

Masculino

1.70

1

Esteban

Masculino

1.75

2

Manuela

Femenino

1.69

3

Diego

Masculino

1.60

4

Alejandra

Femenino

1.65

5

Paula

Femenino

1.55

Declaración#

Podemos declarar un DataFrame a partir de diferentes estructuras de datos. A continuación, vemos un ejemplo de declaración a partir de una listas:

l1 = ["Jorge", 28, "Bogotá"]
l2 = ["Laura", 37, "Lima"]

df = pd.DataFrame([l1,l2], index = ["Persona 1", "Persona 2"], columns = ["Nombre", "Edad", "Ciudad Residencia"])

df
Nombre Edad Ciudad Residencia
Persona 1 Jorge 28 Bogotá
Persona 2 Laura 37 Lima

También podemos declarar un DataFrame a partir de múltiples Series.

s1 = pd.Series({"Pais":"Colombia", "Capital": "Bogotá"})
s2 = pd.Series({"Pais": "Argentina", "Capital": "Buenos Aires"})
s3 = pd.Series({"Pais": "Peru", "Capital": "Lima"})

df = pd.DataFrame([s1,s2, s3], index = ["Pais 1", "Pais 2", "Pais 3"])

df
Pais Capital
Pais 1 Colombia Bogotá
Pais 2 Argentina Buenos Aires
Pais 3 Peru Lima

Consulta#

De manera similar al filtrado por posiciones de un Series, para acceder a uno o más valores dentro de un DataFrame, podemos hacer uso de su posición, del nombre de su índice o del nombre de su columna.

Los atributos loc y iloc son estructuras iterables que nos permiten filtrar filas y columnas de manera simultánea.

Por ejemplo, podemos utilizar los objetos filas y columnas para indicar las posiciones deseadas, como se muestra a continuación:

df.iloc[filas, columnas]

Si queremos seleccionar las primeras \(n\) filas y las columnas de la \(m\) en adelante, podemos hacerlo de la siguiente manera:

df.iloc[ :n, m: ]

A continuación accedemos a los valores de la columna llamada "Pais".

paises = df["Pais"]

paises
Pais 1     Colombia
Pais 2    Argentina
Pais 3         Peru
Name: Pais, dtype: object

Veamos ahora como acceder a los valores de una fila utilizando su posición.

primer_pais = df.iloc[0]

primer_pais
Pais       Colombia
Capital      Bogotá
Name: Pais 1, dtype: object

También, podemos acceder a esta misma información utilizando el nombre del índice de la fila consultada.

primer_pais = df.loc["Pais 1"]

primer_pais
Pais       Colombia
Capital      Bogotá
Name: Pais 1, dtype: object

Finalmente, accedemos a un elemento en específico utlizando el nombre de su índice y su columna.

capital_pais_1 = df.loc["Pais 1", "Capital"]

capital_pais_1
'Bogotá'

Rebanado#

De manera similar a cómo accedimos a un elemento, también podemos acceder a una porción de un DataFrame utilizando los atributos iloc y loc, y la sintaxis que ya hemos aprendido anteriormente para rebanar. Veremos cómo obtener las primeras dos filas del DataFrame df usando un rebanado por posición:

filas_df = df.iloc[0:2]

filas_df
Pais Capital
Pais 1 Colombia Bogotá
Pais 2 Argentina Buenos Aires

A continuación mostramos como obtener la segunda columna del DataFrame.

columnas_df = df.iloc[:,1:2]

columnas_df
Capital
Pais 1 Bogotá
Pais 2 Buenos Aires
Pais 3 Lima

Además, veamos como obtener la porción que contiene únicamente la capital de los dos primero países.

porcion_df = df.iloc[0:2, 1:2]

porcion_df
Capital
Pais 1 Bogotá
Pais 2 Buenos Aires

Si las posiciones que queremos rebanar no son consecutivas, pandas nos permite indicarlas en una lista. A continuación, vemos una manera de mostrar únicamente la primera y última fila de un DataFrame.

df.iloc[ [0, df.shape[0] - 1], : ]
Pais Capital
Pais 1 Colombia Bogotá
Pais 3 Peru Lima

2.3. Declaración de un Series o un DataFrame desde un archivo#

Un Series y un DataFrame también pueden ser declarados a partir de archivos externos, tales como archivos de Excel (.xlsx), CSV (.csv), JSON (.json) y muchos más. Para declarar un DataFrame a partir de un archivo de Excel usamos la siguiente sintaxis:

df = pd.read_excel("Archivos/Datos.xlsx")

df
Nombre Edad Ingresos Ciudad Residencia
0 Juan 48 71 Bogotá
1 Maria 29 150 Lima
2 Jorge 43 98 Buenos Aires
3 Pablo 50 105 Bogotá
4 Laura 33 80 La Paz
5 Esteban 21 127 Lima
6 Juliana 48 131 La Paz
7 Valentina 47 89 Bogotá
8 Silvana 43 109 Buenos Aires

La forma en la que se leen otros tipos de archivos es completamente análoga a esta. Por ejemplo:

  • CSV: pd.read_csv("Nombre archivo")

  • JSON: pd.read_json("Nombre archivo")

2.4. Exploración de los objetos Series y DataFrame#

A continuación, implementamos algunos de los métodos más utilizados para explorar Series y DataFrame utilizando la librería pandas. Recomendamos que revises la documentación oficial de pandas para expandir el conocimiento acerca de otros métodos.

  • head: muestra las primeras n filas.

df.head(5)
Nombre Edad Ingresos Ciudad Residencia
0 Juan 48 71 Bogotá
1 Maria 29 150 Lima
2 Jorge 43 98 Buenos Aires
3 Pablo 50 105 Bogotá
4 Laura 33 80 La Paz
  • tail: muestra las últimas n filas.

df.tail(5)
Nombre Edad Ingresos Ciudad Residencia
4 Laura 33 80 La Paz
5 Esteban 21 127 Lima
6 Juliana 48 131 La Paz
7 Valentina 47 89 Bogotá
8 Silvana 43 109 Buenos Aires
  • columns: muestra los nombres de las columnas del DataFrame.

df.columns
Index(['Nombre', 'Edad', 'Ingresos', 'Ciudad Residencia'], dtype='object')
  • info: muestra la información general del DataFrame.

df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 9 entries, 0 to 8
Data columns (total 4 columns):
 #   Column             Non-Null Count  Dtype 
---  ------             --------------  ----- 
 0   Nombre             9 non-null      object
 1   Edad               9 non-null      int64 
 2   Ingresos           9 non-null      int64 
 3   Ciudad Residencia  9 non-null      object
dtypes: int64(2), object(2)
memory usage: 420.0+ bytes
  • describe: muestra medidas de tendencia de las columnas numéricas del DataFrame.

df.describe()
Edad Ingresos
count 9.000000 9.000000
mean 40.222222 106.666667
std 10.158467 25.646637
min 21.000000 71.000000
25% 33.000000 89.000000
50% 43.000000 105.000000
75% 48.000000 127.000000
max 50.000000 150.000000
  • dtypes: muestra el tipo de dato de cada columna del DataFrame.

df.dtypes
Nombre               object
Edad                  int64
Ingresos              int64
Ciudad Residencia    object
dtype: object
  • unique: muestra los datos únicos de una columna del DataFrame.

df["Ciudad Residencia"].unique()
array(['Bogotá', 'Lima', 'Buenos Aires', 'La Paz'], dtype=object)
  • max: muestra el valor máximo de una columna de un DataFrame.

df["Edad"].max()
50
  • min: muestra el valor minimo de una columna de un DataFrame.

df["Edad"].min()
21
  • sum: muestra la suma de todos los valores de una columna en específico.

df["Ingresos"].sum()
960
  • mean: muestra el promedio de todos los valores de una columna en específico.

df["Ingresos"].mean()
106.66666666666667

2.5. Manipulación de Series y DataFrame#

A continuación, implementaremos algunos de los métodos más utilizados para manipular Series y DataFrame utilizando la librería pandas. Recomendamos que revises la documentación oficial de pandas para expandir el conocimiento acerca de otros métodos. A continuación crearemos un DataFrame que contiene información personal de tres personas:

persona_1 = ["Jorge","Suaréz", 28, "Bogotá"]
persona_2 = ["Laura","Poveda", 37, "Lima"]
persona_3 = ["Pablo", "Goméz", 30, "Lima"]
df2 = pd.DataFrame([persona_1, persona_2, persona_3], columns=["Nombre", "Apellido", "Edad", "Ciudad"])

df2
Nombre Apellido Edad Ciudad
0 Jorge Suaréz 28 Bogotá
1 Laura Poveda 37 Lima
2 Pablo Goméz 30 Lima
  • set_index: permite establecer una columna como índice de un DataFrame.

df2.set_index("Nombre")
Apellido Edad Ciudad
Nombre
Jorge Suaréz 28 Bogotá
Laura Poveda 37 Lima
Pablo Goméz 30 Lima
  • drop: permite eliminar filas o columnas de un DataFrame.

Eliminar filas por posición:

df2.drop([0,2])
Nombre Apellido Edad Ciudad
1 Laura Poveda 37 Lima

Eliminar columnas por nombre:

df2.drop(columns = ["Ciudad"])
Nombre Apellido Edad
0 Jorge Suaréz 28
1 Laura Poveda 37
2 Pablo Goméz 30
  • rename: permite renombrar elementos de un DataFrame.

df2.rename(columns = {"Ciudad": "Residencia"})
Nombre Apellido Edad Residencia
0 Jorge Suaréz 28 Bogotá
1 Laura Poveda 37 Lima
2 Pablo Goméz 30 Lima

Créditos#

Autores: Camilo Falla Moreno, Juan David Reyes, Alejandro Mantilla Redondo, Diego Alejandro Cely Gomez

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