Show 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 |
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 delDataFrame
.
df.columns
Index(['Nombre', 'Edad', 'Ingresos', 'Ciudad Residencia'], dtype='object')
info
: muestra la información general delDataFrame
.
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 delDataFrame
.
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 delDataFrame
.
df.dtypes
Nombre object
Edad int64
Ingresos int64
Ciudad Residencia object
dtype: object
unique
: muestra los datos únicos de una columna delDataFrame
.
df["Ciudad Residencia"].unique()
array(['Bogotá', 'Lima', 'Buenos Aires', 'La Paz'], dtype=object)
max
: muestra el valor máximo de una columna de unDataFrame
.
df["Edad"].max()
50
min
: muestra el valor minimo de una columna de unDataFrame
.
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 unDataFrame
.
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 unDataFrame
.
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 unDataFrame
.
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