Autor: Luis Fernando Apáez Álvarez
-Curso PyM-
Clase 7: Introducción a las librerías NumPy y Pandas
Fecha: 03 de Septiembre del 2022
Es recomendable que el estudiante posea conocimientos básicos sobre matrices matemáticas para poder llevar de manera satisfactoria esta clase. De cualquier manera, en el siguiente link se explica una breve introducción a las matrices (o arreglos): Intro. a las matrices
En esta clase comenzaremos indagando en la librería NumPy, la cual trabaja con una estructura de datos de matrices, y los implementa de una manera que permite realizar potentes cálculos de manera eficiente.
La librería Numpy
(Numerical Python) se especializa en el cálculo numérico y sirve para la computación científica. Ésta se basa en la clase de objetos array
. Una de las ventajas de esta librería es el manejo de grandes cantidades de datos, por lo cual es muy útil para análisis de datos.
Los arrays de NumPy son la manera principal de almacenar datos y son muy parecidas a las lista, pero dichos arrays se procesan mucho más rápido que las listas convencionales. Los arrays son una estructura de datos la cual se organiza en forma de una tabla o cuadrícula de distintas dimensiones, puede pensarse como una típica matriz matemática.
Para crear un array utilizaremos la función np.array()
la cual recibe como parámetro una lista, por ejemplo
# Importamos la libreria NumPy
import numpy as np
# Creamos un array utilizando np.array()
array1 = np.array([1, 2, 3, 4])
array1
array([1, 2, 3, 4])
El array anterior es uno de dimensión 1 y podemos imaginarlo como una matriz fila $$ (1 \ \ 2 \ \ 3 \ \ 4) $$
Luego, creamos un array de dimensión 2 utilizando dos lista dentro de una lista, pues recordemos que la función np.array()
recibe como parámetro una sola lista
array2 = np.array([ [1, 2, 3, 4],
[5, 6, 7, 8] ])
print(array2)
[[1 2 3 4] [5 6 7 8]]
el cual es un array de dimensión 2 y que podemos pensarlo como la matriz
$$ \left(\begin{array}{cccc} 1 & 2 & 3 & 4\\ 5 & 6 & 7 & 8 \end{array}\right) $$De tal manera, cada lista dentro de la lista principal en un array, es respectivamente una fila de una matriz. Otro ejemplo de un array de dimensión 2
array3 = np.array([ [1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12] ])
print(array3)
[[ 1 2 3 4] [ 5 6 7 8] [ 9 10 11 12]]
array3.ndim
2
Podemos obtener la forma del array, es decir, el número de filas y columnas que lo componen, y para ello utilizamos el atributo .shape
print(array1.shape)
print(array2.shape)
print(array3.shape)
(4,) (2, 4) (3, 4)
el segundo array tiene dos filas y cuatro columnas; el tercer array tiene tres filas y cuatro columnas. Los arrays de una sola fila son contemplados sólo con el número de columnas.
En realidad, en este contexo de los array, no se habla de filas o columnas, más bien se habla de ejes, axis. Por ejemplo
$$ \left(\begin{array}{cccc} 1 & 2 & 3 & 4\\ 5 & 6 & 7 & 8 \end{array}\right) $$A las filas se les conoce como eje 0, (axis 0); a las columnas se les conoce como eje 1, (axis 1). Luego, podemos tener matrices tridimensionales donde la "profundidad" o "ancho" será denominado eje 2 (axis 2). Con el razonamiento anterior, puede trabajarse con arrays de dimensiones superiores, por ejemplo, aquellos que tengan hasta el eje 4, 5, o más. Por ejemplo, podemos crear un array de dimensión 3
array4 = np.array([ [[1,2,3],
[5,6,7], # "Matriz" uno
[9,10,11]],
[[1,2,3],
[5,6,7], # "Matriz" dos
[9,10,11]],
[[1,2,3],
[5,6,7], # "Matriz" tres
[9,10,11]] ])
# Imprimimos el array
print(array4)
# Imprimimos la forma del array
print(array4.shape)
[[[ 1 2 3] [ 5 6 7] [ 9 10 11]] [[ 1 2 3] [ 5 6 7] [ 9 10 11]] [[ 1 2 3] [ 5 6 7] [ 9 10 11]]] (3, 3, 3)
dicho array lo podemos pensar como 3 matrices de 3 filas y 3 columnas. Podemos visualizar, por ejemplo, un array de 3 dimensiones que conste de tres matrices de 4 filas por 5 columnas como sigue:
Otro ejemplo, podemos visualizar un array de tres matrices cuadradas de $3\times 3$ como una especie de cubo:
Con lo anterior ya hemos visto la creación de cierto tipos de arrays mediante el comando np.array()
. Lo que haremos ahora será crear algunos tipos especiales de arrays, tales como arrays cuyas entradas son nulas, arrays cuyas entradas son números aleatorios, etcétera
# Creacion de un array de ceros utilizando np.empty()
# El array sera de dos filas por 3 columnas
array5 = np.empty((2,3))
print(array5)
[[4.24399158e-314 8.48798317e-314 1.27319747e-313] [1.69759663e-313 2.12199579e-313 2.54639495e-313]]
donde las entradas de dicho array son prácticamente cero.
# O alternativamente utilizando np.zeros()
array5 = np.zeros((2,3))
print(array5)
[[0. 0. 0.] [0. 0. 0.]]
También podemos crear arrays cuyas entradas sean el número 1:
# Array de unos de 3 filas por 4 columnas
array6 = np.ones((3,4))
print(array6)
[[1. 1. 1. 1.] [1. 1. 1. 1.] [1. 1. 1. 1.]]
De manera más general, podemos crear arrays cuyas entradas tengan el mismo valor. Por ejemplo, podemos crear arrays cuyas entradas sean todas el cero, o sean todas el uno, etcétera.
# Array relleno de un valor especifico, por ejemplo el 5.
# Este array tendra 2 filas por 3 columnas
array7 = np.full((2,3), 5)
print(array7)
[[5 5 5] [5 5 5]]
# array de 3 por 3 cuyas entradas seran todas
# iguales al numero pi
array7 = np.full((3,3), np.pi)
print(array7)
[[3.14159265 3.14159265 3.14159265] [3.14159265 3.14159265 3.14159265] [3.14159265 3.14159265 3.14159265]]
Podemos crear también arrays que representen la idea de matrices identidad, por ejemplo
$$ \left(\begin{array}{cc} 1 & 0 \\ 0 & 1 \end{array}\right), \ \ \ \ \ \left(\begin{array}{ccc} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{array}\right) $$etcétera. Para ello utilizaremos np.identity()
como sigue.
# "matriz identidad" de 3 filas por 3 columnas
array8 = np.identity(3)
print(array8)
print()
# "matriz identidad" de 2 filas por 2 columnas
array8 = np.identity(2)
print(array8)
[[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]] [[1. 0.] [0. 1.]]
Creamos también un array cuyas entradas sean números aleatorios mediante np.random.random()
:
# Array con entrads aleatorias de 2 filas
# por 3 columanas
array9 = np.random.random((2,3))
print(array9)
[[0.68747989 0.29228341 0.62560107] [0.81107631 0.91728229 0.5681006 ]]
Podemos crear rangos de números como lo hacíamos con range()
, pero ahora los rangos de números que crearemos con NumPy serán almacenados un un array de dimensión 1:
# Array de una dimensión con entradas generadas por un rango
# arange(0, 5): 0, 1, 2, 3, 4
array10 = np.arange(0, 5)
print(array10)
print("-" * 12)
# Array de un rango de numeros del 0 al 4
# con un paso o avance de 2.
# arange(0, 5, 2): 0, 2, 4
array10 = np.arange(0, 5, 2)
print(array10)
print(array10.shape)
[0 1 2 3 4] ------------ [0 2 4] (3,)
Podemos dividir en partes uniformes un intervalo de números. Por ejemplo, podemos dividir el intervalo del 0 a 1 en 10 partes iguales, para lo cual utilizaremos np.linspace()
como sigue
# np.linspace(inicio intervalo, fin intervalo, numero de partes)
array11 = np.linspace(0, 1, 10)
print(array11)
print(array11.shape)
[0. 0.11111111 0.22222222 0.33333333 0.44444444 0.55555556 0.66666667 0.77777778 0.88888889 1. ] (10,)
Por otro lado, podemos cambiar la forma de un array dado utilizando el método reshape()
. Por ejemplo, podemos cambiar la forma de una matriz de dos filas y tres columnas a una de tres filas y dos columnas:
# Array de 2 por 3
array12 = np.array([ [1,2,3],
[4,5,6]] )
print(array12.shape)
print(array12)
print()
# Cambiamos la forma, para ello creamos un nuevo array.
# Array de 3 por 2 proveniente del array13
# array | cambio de forma
# original| para el array13
array13 = array12.reshape(3,2)
print(array13.shape)
print(array13)
(2, 3) [[1 2 3] [4 5 6]] (3, 2) [[1 2] [3 4] [5 6]]
Cabe la pena resaltar que al aplicar el método reshape()
, en general, no estamos obteniendo la transpuesta de una matriz. Así, el array13
no es la transpuesta del array12
. Si queremos obtener la matriz transpuesta de un array utilizamos np.transpose()
, por ejemplo
# Matriz transpuesta del array12
print(np.transpose(array12))
[[1 4] [2 5] [3 6]]
La diferencia radica en que el método reshape()
lee las entradas de izquierda a derecha, de arriba a abajo, del array, y así como las va leyendo va colocando dichos valores en el nuevo array con la nueva forma. Por otro lado, para una matriz cuyas entradas son, digamos, $a_{ij}$, la matriz transpuesta tendrá las entradas $a_{ji}$, donde la primera posición del subíndice indica la fila y la segunda posición del subíndice indica la columna.
Por ejemplo, dada la matriz
$$ \left(\begin{array}{ccc} 1 & 2 & 3 \\ 5 & 6 & 7 \end{array}\right) $$su matriz transpuesta sería
$$ \left(\begin{array}{ccc} 1 & 4 \\ 2 & 5 \\ 3 & 6 \end{array}\right) $$# En efecto
array14 = np.array([[1, 2, 3],
[4, 5, 6]])
print(np.transpose(array14))
[[1 4] [2 5] [3 6]]
Finalmente, podemos hallar el valor máximo o mínimo de un valor dentro de un array
# Valor maximo en el array14
print(array14.max())
# Valor minimo
print(array14.min())
6 1
Al igual que en las lista, podemos acceder a los elementos de un array utilizando índices (de una manera muy similar a cómo están definidos los índices en una matriz matemática). Asimismo, es posible obtener subarrays utilizando el operador de dos puntos :
. Primero, veamos cómo están indicados los índices en una amtriz matemática de $2\times 2$:
pues en la primer entrada $(1,1)$, ésta se encuentra en la fila 1 y columna 1, para la entrada en $(1,2)$ tenemos que ésta se encuentra en la fila 1 y columna 2; para la entrada en $(2,1)$ tenemos que ésta se encuentra en la segunda fila y primer columna; finalmente, para la entrada en $(2,2)$ tenemos que ésta se encuentra en la segunda fila y segunda columna. Ahora bien, recordemos que en Python las numeraciones comienza en cero, por lo cual los índices de una array NumPy de 2 por 2 quedaría como
(0, 0) (0, 1)
(1, 0) (1, 1)
Con base en lo anterior, accedamos a los elementos de un array
# Creamos un array
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# Accedamos al elemento en la primer fila y
# primer columna
print(array1[0, 0])
print()
# o alternativamente
print(array1[0][0])
print("-" * 10)
# Accedamos al elemento de la primer fila
# y de la última columna
print(array1[0, -1])
print()
# Accedamos al elemento de la segunda fila
# y segunda columna
print(array1[1,1])
1 1 ---------- 3 5
Podemos obtener también un subarray
# Dado el array1
array1 = np.array([[1, 2, 3],
[4, 5, 6]])
# Podemos obtener el subarray que considere todas las filas
# del array original.
# ( Lo cual conseguimos al utilizar : en la primera entrada
# de los corchetes en array1[:, ] )
# Y que considere de la columna 0 a la columna 1 del array
# original. Para lo cual escribimos array1[:, 0:2].
# Esto es
print(array1[:, 0:2])
[[1 2] [4 5]]
donde en la primer entrada al poner los puntos estamos diciendo que se considerarán todas las filas del array original y, después de la coma, estamos considerando las columnas de la 0 a la 1 (el 2 no se incluye).
Veamos otro ejemplo
# Creamos un array de una dimension de un rango
# de numeros del 1 al 81
array2 = np.arange(1, 82)
# Convertimos dicho array de una dimension a uno
# de dos dimensiones (de nueve filas por nueve columnas)
array2 = array2.reshape((9,9))
print(array2)
[[ 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18] [19 20 21 22 23 24 25 26 27] [28 29 30 31 32 33 34 35 36] [37 38 39 40 41 42 43 44 45] [46 47 48 49 50 51 52 53 54] [55 56 57 58 59 60 61 62 63] [64 65 66 67 68 69 70 71 72] [73 74 75 76 77 78 79 80 81]]
Con base en el array anterior, será nuestro interés obtener el subarray
$$ \left(\begin{array}{ccc} & \textrm{columna 3} & \textrm{columna 4} & \textrm{columna 5} \\ \textrm{fila 3}& 31 & 32 & 33\\ \textrm{fila 4}& 40 & 41 & 42\\ \textrm{fila 5}& 49 & 50 & 51 \end{array}\right) $$# queremos de| queremo de
# la fila 3 | la columna 3
# a la fila 5| a la columna 5
print(array2[3:6, 3:6])
[[31 32 33] [40 41 42] [49 50 51]]
También podemos obtener subarrays cuyos valores no sean consecutivos, por ejemplo
$$ \left(\begin{array}{ccc} & \textrm{columna 3} & \textrm{columna 5} \\ \textrm{fila 3} & 31 & 33\\ \textrm{fila 4}& 40 & 42\\ \textrm{fila 5}& 49 & 51 \end{array}\right) $$# de la fila 3 | de la columnas 3 a la columna 5
# a la fila 5 | pero con un paso de dos
print(array2[3:6, 3:6:2])
Una de las características útiles de los arrays son los filtrados, los cuales nos permiten obtener otro array dada una condición de interés.
Por ejemplo
# Creamos un array de dimension 1
array3 = np.arange(1, 10)
# Convertimos ese array a uno de dimension 2
# de 3 filas por 3 columnas
array3 = array3.reshape((3,3))
print(array3)
print()
# Queremos considerar las entradas de nuestro array3
# que son mayores a 5
filtro1 = array3 > 5
print(filtro1)
[[1 2 3] [4 5 6] [7 8 9]] [[False False False] [False False True] [ True True True]]
nos arroja un array de entradas booleanas, donde True
indica que la condición es satisfecha por el elemento en esa entrada correspondiente, y False
lo contrario. Ahora, podemos extraer los valores de las entradas de array3
que cumplen con la condición array3 > 5
, los cuales sabemos que son los números 6, 7, 8, 9. Para extraer dichos valores que cumplen con la condición escribimos
# Del array original
# seleccionamos solo las entradas
# que tiene un valor de True asociado
# en la respectiva entrada del
# array booleano filtro1
print(array3[filtro1])
[6 7 8 9]
La idea detrás de lo anterior la podemos visualizar como
# Otro ejemplo: Los numeros pares mayores o iguales a 4
# operador
# booleano
# and
filtro2 = (array3 % 2 == 0) & (array3 >= 4)
# Obtenemos los numeros de las entradas de array3 que cumple
# con dicha condicion
print(array3[filtro2])
[4 6 8]
# Alternativa en vez de usar & ocupamos np.logical_and:
# Nos saltamos el paso de definir una variable para
# almacenar el filtro.
# condicion1 condicion2
array3[ np.logical_and(array3 % 2 == 0, array3 >= 4) ]
array([4, 6, 8])
El método de filtro anterior se conoce como corte de máscara booleana, donde la máscara es el array de entradas booleanas (los que denominamos como las variables filtro
)
Veamos otro método de filtrado utilizando la función fromiter()
, la cual recibe de parámetros:
iterable
: un objeto iterabledtype
: tipo de datos del array de retornoy algunos otros parámetros opcionales. Veamos un ejemplo
# Elementos del array que dividen al 12:
# Creamos un array de una dimension
array4 = np.arange(1, 10)
print(array4)
print()
# Creamos el filtro utilizando fromiter
# -----------iterable------------- Tipo de dato de las
# recorremos cada una de las entradas del array
# entradas del array filtro2. Dicho tipo
# sera, justamente, el
# el mismo tipo de dato
# que del array4
filtro2 = np.fromiter((i for i in array4 if 12 % i == 0), dtype = array4.dtype)
print(filtro2)
[1 2 3 4 5 6 7 8 9] [1 2 3 4 6]
# Alternativa
# El iterable ahora recorrera cada una de las
# entradas del array pero mediante indices
filtro3 = np.fromiter((array3[i][j] for i in range(3) for j in range(3)
if 12 % array3[i][j] == 0), dtype=array3.dtype)
print(filtro3)
Dado una array, podemos realizar operaciones matemáticas con cada una de las entradas de éste. Por ejemplo, podemos sumar un número fijo a cada una de las entradas:
# Definimos un array de dimension 2,
# con 2 filas por 2 columnas cuyas entradas
# son numeros enteros aleatorios del 0 al 4:
# array de entradas | los numeros| size
# aleatorias enteras| aleatorios | especifica
# | podran ser | la forma
# | el 0,1,2, | del array
# | 3 o 4 |
array1 = np.random.randint(5, size=(2,2))
print(array1)
[[4 3] [3 2]]
# Sumamos un 3 a cada una de las entradas de
# array anterior
print(array1 + 3)
print()
# Multiplicamos cada una de las entradas
# del array original por el 7
print(array1 * 7)
[[7 6] [6 5]] [[28 21] [21 14]]
Y análogamente podemos realizar más operaciones matemáticas como la división, el residuo, exponenciación, etcétera.
Asimismo, dados dos arrays de las mismas dimensiones podemos sumarlos, multiplicarlos, etcétera. Cabe resaltar que las operaciones entre arrays se hacen entrada a entrada. Por ejemplo, la multiplicación entre dos arrays:
$$ \left(\begin{array}{cc} 1 & 2 \\ 0 & 1 \end{array}\right)* \left(\begin{array}{cc} 4 & -2 \\ 5 & 3 \end{array}\right)=\left(\begin{array}{cc} 1*4 & 2*-2 \\ 0*5 & 1*3 \end{array}\right)=\left(\begin{array}{cc} 4 & -4 \\ 0 & 3 \end{array}\right) $$De tal manera:
# Dados los arrays de la misma diemnsion
array1 = np.random.randint(12, size=(3,3))
print(array1)
print()
array2 = np.random.randint(12, size=(3,3))
print(array2)
[[11 10 9] [ 4 10 3] [ 3 5 8]] [[ 5 4 1] [ 6 3 0] [10 4 3]]
# Podemos sumarlos (entrada a entrada)
print(array1 + array2)
print()
# Podemos multiplicarlos (entrada a entrada)
print(array1 * array2)
print()
# Podemos exponenciarlos (entrada a entrada)
print(array1 ** array2)
[[16 14 10] [10 13 3] [13 9 11]] [[55 40 9] [24 30 0] [30 20 24]] [[161051 10000 9] [ 4096 1000 1] [ 59049 625 512]]
Las tablas representan una estructura de datos bastante poderosa y versátil, y las podemos implementar dentro de Python mediante la librería Pandas. Gracias a ella podemos trabajar con tablas (las cuales se conocerán dentro de dicha librería como dataframes) para la manipulación y el análisis de datos. Tendremos tres tipos diferentes de estructuras, las cuales son:
las cuales son construidas a partir de los arrays de NumPy, pero con funcionalidades adicionales. En esta clase sólo nos centraremos en trabajar con los DataFrames.
Comenzaremos por crear una DataFrame (una tabla) a partir de un diccionario:
# Importamos la libreria necesaria
import pandas as pd
# Creamos un diccionario
info = {'nombre': ['Delia', 'Martha', 'Luis'],
'edad': [18, 24, 24],
'estudio': ['Preparatoria', 'Universidad', 'Universidad']}
# Veamos nuestro diccionario
from pprint import pprint as pp
pp(info)
{'edad': [18, 24, 24], 'estudio': ['Preparatoria', 'Universidad', 'Universidad'], 'nombre': ['Delia', 'Martha', 'Luis']}
Con base en lo anterior podemos convertir nuestro diccionario a un formato tabular, donde las llaves del diccionario serán las columnas de nuestra tabla y los valores de dichas llaves serán los valores respectivos en cada fila
nombre | edad | estudio |
---|---|---|
Delia | Martha | Luis |
18 | 24 | 24 |
Preparatoria | Universidad | Universidad |
lo cual conseguimos escribiendo el código:
# Creamos un dataframe a partir del diccionario info
# utilizando pd.DataFrame() como sigue
df1 = pd.DataFrame(info)
# Veamos nuestro dataframe
df1
nombre | edad | estudio | |
---|---|---|---|
0 | Delia | 18 | Preparatoria |
1 | Martha | 24 | Universidad |
2 | Luis | 24 | Universidad |
Donde, por defecto, se agregó un índice que comienza en cero para identificar de manera única cada fila de nuestro dataframe. Podemos recuperar los nombres de las columnas de nuestro dataframe mediante el atributo columns
# Nombre de las columnas de nuestro dataframe
print(df1.columns)
Index(['nombre', 'edad', 'estudio'], dtype='object')
# Obtenemos una breve informacion sobre nuestro
# dataframe mediante el metodo info()
df1.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 3 entries, 0 to 2 Data columns (total 3 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 nombre 3 non-null object 1 edad 3 non-null int64 2 estudio 3 non-null object dtypes: int64(1), object(2) memory usage: 200.0+ bytes None
donde se nos muestra si las columas tienen valores nulos o faltantes, además de que se nos muestra el tipo de los datos en cada columna. Para ello:
Tipo en Pandas | Tipo en Python Nativo | Descripción |
---|---|---|
object | string | El dtype más general. Será asignado a tu columna si la columna contiene tipos mixtos (números y secuencias de caracteres). |
int64 | int | Caracteres numéricos. 64 se refiere a la memoria asignada para almacenar el caracter. |
float64 | float | Caracteres numéricos con decimales. Si una columna contiene números y NaNs (ver más abajo), Pandas usará float64 por defecto, en caso de que los datos faltantes contengan decimales. |
datetime64, timedelta[ns] | N/D (ver el módulo datetime en la biblioteca estandar de Python) | Valores destinados a contener datos de tiempo. Mira en estos para experimentos con series de tiempo. |
Además se nos dice la memoria ocupada (memory usage: 200.0+ bytes
) para almacenar nuestro dataframe.
También, podemos crear un dataframe a partir de lista:
# Definimos varias listas, donde cada lista sera una fila de
# nuestro dataframe
v1 = ['Delia', 18, 'Preparatoria']
v2 = ['Martha', 24, 'Universidad']
v3 = ['Luis', 24, 'Universidad']
# Crearemos nuestro dataframe
# agrupamos las | especificamos
# listas indivi-| manualmente el
# duales en una | nombre de las
# sola lista | columnas
df2 = pd.DataFrame([v1, v2, v3], columns=['Nombre', 'Edad', 'Estudio'])
df2
Nombre | Edad | Estudio | |
---|---|---|---|
0 | Delia | 18 | Preparatoria |
1 | Martha | 24 | Universidad |
2 | Luis | 24 | Universidad |
con lo cual obtenemos el mismo resultado. En la práctica, pocas veces será necesario que definamos nosotros mismos los dataframes como lo hemos hecho antes, más bien, será preciso que carguemos información externa (como csv, archivos de excel, texto en txt, bases de datos SQL, etcétera) dentro de un dataframe, lo cual veremos más adelante.
Por otro lado, podemos ver información sobre el índice de nuestro dataframe mediante el atributo index
df2.index
RangeIndex(start=0, stop=3, step=1)
que nos dice que el índice comienza en el 0 y termina en el 2 (3-1) a un paso de 1, esto es, nuestro índice es 0, 1, 2. Recordemos que el índice dado a nuestro dataframe fue asignado de manera automática, si queremos cambiarlo utilizaremos el método rename()
como sigue
# Primero creamos un diccionario donde las llaves son los
# los valores del primer indice (0, 1, 2) y los values asociados
# corresponden a los nuevos valores del indice que
# queremos
nuevo_indice = {0:'ID 1', 1:'ID 2', 2:'ID 3'}
# Despues creamos un nuevo dataframe con la misma
# informacion que df2 pero ahora con un indizado
# distinto.
# Parametro para especificar
# el nuevo indice que queremos
# asignar
df2_2 = df2.rename(index=nuevo_indice)
# Veamos ahora el nuevo dataframe con el indice
# nuevo
df2_2
Nombre | Edad | Estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
ID 2 | Martha | 24 | Universidad |
ID 3 | Luis | 24 | Universidad |
Si ahora queremos cambiar el nombre de las columnas agregaremos dentro del método rename()
el parámetro columns
:
# Primero creamos un diccionario donde las llaves son los
# los primeros nombres de las columnas y los values
# corresponden a los nuevos nombres de las columnas
# que queremos asignar
nuevas_columnas = {'Nombre':'nombre', 'Edad':'edad',
'Estudio':'estudio'}
# Despues creamos un nuevo dataframe con la misma
# informacion que df2_2 pero ahora con el nombre
# de las columnas distinto.
# Parametro para especificar
# el nuevo nombre de las
# columnas
df2_3 = df2_2.rename(columns=nuevas_columnas)
# Veamos ahora el nuevo dataframe resultante
df2_3
nombre | edad | estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
ID 2 | Martha | 24 | Universidad |
ID 3 | Luis | 24 | Universidad |
Podemos acceder a la información de una columna en especifico escribiendo:
<nombre_dataframe>['<nombre_column>']
Por ejemplo, del dataframe
df2_3
nombre | edad | estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
ID 2 | Martha | 24 | Universidad |
ID 3 | Luis | 24 | Universidad |
Podemos acceder a la información de la columna nombre
como sigue:
df2_3['nombre']
ID 1 Delia ID 2 Martha ID 3 Luis Name: nombre, dtype: object
# O a la columna edad
df2_3['edad']
ID 1 18 ID 2 24 ID 3 24 Name: edad, dtype: int64
# O a la columna estudio
df2_3['estudio']
ID 1 Preparatoria ID 2 Universidad ID 3 Universidad Name: estudio, dtype: object
También, podemos acceder a más de una columna al mismo tiempo, para lo cual ocuparemos una lista donde cada elemento es el nombre de la columna a la cual queremos acceder. Por ejemplo
# accedemos a las columnas nombre y estudio
# lista con el nombre
# de las columnas a las
# cuales queremos acceder
df2_3[ ['nombre', 'estudio'] ]
nombre | estudio | |
---|---|---|
ID 1 | Delia | Preparatoria |
ID 2 | Martha | Universidad |
ID 3 | Luis | Universidad |
Podemos acceder también a la información de una fila completa. Antes de ello notemos que
df2_3[0:]
nombre | edad | estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
ID 2 | Martha | 24 | Universidad |
ID 3 | Luis | 24 | Universidad |
dicho código nos arroja toda la información de nuestro dataframe, pero qué significa exactamente [0:]
. Lo que ocurre al escribir lo anterior es que estamos selecciondo filas de nuestro dataframe df2_3
, desde la fila 0 hasta la última fila, por lo cual se nos muestra todo nuestro dataframe. Con base en lo anterior:
# Si queremos ver toda la informacion de la primer
# fila escribimos
df2_3[0:1]
nombre | edad | estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
Nota que no podemos escribir simplemente df2_3[0]
para acceder a toda la información de la primer fila pues dicha notación es referente al acceso de la información de las columnas. Continuando
# Si queremos ver toda la informacion de la segunda
# fila escribimos
df2_3[1:2]
nombre | edad | estudio | |
---|---|---|---|
ID 2 | Martha | 24 | Universidad |
# Si queremos ver toda la informacion de la tercer
# fila escribimos
df2_3[2:3]
nombre | edad | estudio | |
---|---|---|---|
ID 3 | Luis | 24 | Universidad |
# Si queremos ver toda la informacion de la primer
# fila a la segunda escribimos
df2_3[0:2]
nombre | edad | estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
ID 2 | Martha | 24 | Universidad |
# Si queremos ver toda la informacion de la primer
# fila y la tercer fila escribimos:
# Accedemos de la fila 0 a la 2, es decir, considera-
# remos las filas 0, 1 y 2, pero configuraremos
# un paso de 2, esto es, solo consideraremos las
# filas 0 y 2
df2_3[0:3:2]
nombre | edad | estudio | |
---|---|---|---|
ID 1 | Delia | 18 | Preparatoria |
ID 3 | Luis | 24 | Universidad |
También, podemos considerar información individual de una columna o columnas. Por ejemplo, podemos considerar dos columnas y tan sólo una fila en especifico:
# Consideraremos las columnas nombre y estudio
# pero solo queremos acceder a las dos primeras
# filas
# Acceso a las columnas | acceso a las filas
df2_3[ ['nombre', 'estudio'] ][0:2]
nombre | estudio | |
---|---|---|
ID 1 | Delia | Preparatoria |
ID 2 | Martha | Universidad |
# Accedemos a la columna nombre pero solo
# a la informacion de la fila 0 y 3
df2_3['nombre'][0:3:2]
ID 1 Delia ID 3 Luis Name: nombre, dtype: object
Asimismo, podemos obtener el valor de una entrada de la tabla en especifico
# Accedemos a la columna nombre pero solo
# queremos el valor asociado a este de la fila 0
print(df2_3['nombre'][0])
print()
# Accedemos a la columna nombre pero solo
# queremos el valor asociado a este de la fila 1
print(df2_3['nombre'][1])
print()
# Accedemos a la columna nombre pero solo
# queremos el valor asociado a este de la fila 2
print(df2_3['nombre'][2])
print()
# O tambien, el valor asociado a la columna edad
# de la fila 2
print(df2_3['edad'][1])
Delia Martha Luis 24
Asimismo, podemos obtener el número total de filas de un dataframe:
# Numero de filas del dataframe df2_3
len(df2_3)
3
Podemos obtener una breve información de estadísticas sobre alguna columna (o columnas) de nuestro dataframe cuyo tipo de dato sea numérico, para lo cual utilizamos el método describe()
. En nuestro ejemplo, el dataframe df2_3
solo tiene a la columna edad
con tipo de dato numérico. Luego
df2_3.describe()
edad | |
---|---|
count | 3.000000 |
mean | 22.000000 |
std | 3.464102 |
min | 18.000000 |
25% | 21.000000 |
50% | 24.000000 |
75% | 24.000000 |
max | 24.000000 |
vemos el promedio, la desviación estandár, el máximo y mínimo, así como los cuantiles, de la información (numérica) que almacena la columna edad
.
Para finalizar cargaremos información externa de un archivo csv (valores separados por comas) y la almacenaremos en un dataframe. Para cargar archivos csv ocupamos el método read_csv()
. En este caso, la información que cargaremos será desde una página web por lo cual, dentro de los paréntesis de read_csv()
, colocaremos la url del archivo csv en cuestión:
# Cargamos informacion externa de un archivo csv
# desde la web.
# url del archivo csv que queremos cargar
df3 = pd.read_csv('https://cursopypagina.github.io/CursoPy/titanic.csv')
df3
survived | pclass | age | sibsp | parch | fare | male | age_was_missing | embarked_from_cherbourg | embarked_from_queenstown | embarked_from_southampton | |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 3 | 22.000000 | 1 | 0 | 7.2500 | 1 | False | 0 | 0 | 1 |
1 | 1 | 1 | 38.000000 | 1 | 0 | 71.2833 | 0 | False | 1 | 0 | 0 |
2 | 1 | 3 | 26.000000 | 0 | 0 | 7.9250 | 0 | False | 0 | 0 | 1 |
3 | 1 | 1 | 35.000000 | 1 | 0 | 53.1000 | 0 | False | 0 | 0 | 1 |
4 | 0 | 3 | 35.000000 | 0 | 0 | 8.0500 | 1 | False | 0 | 0 | 1 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
886 | 0 | 2 | 27.000000 | 0 | 0 | 13.0000 | 1 | False | 0 | 0 | 1 |
887 | 1 | 1 | 19.000000 | 0 | 0 | 30.0000 | 0 | False | 0 | 0 | 1 |
888 | 0 | 3 | 29.699118 | 1 | 2 | 23.4500 | 0 | True | 0 | 0 | 1 |
889 | 1 | 1 | 26.000000 | 0 | 0 | 30.0000 | 1 | False | 1 | 0 | 0 |
890 | 0 | 3 | 32.000000 | 0 | 0 | 7.7500 | 1 | False | 0 | 1 | 0 |
891 rows × 11 columns
Asimismo, podremos cargar información de archivos de texto plano (txt), archivos de excel (xlsx) entre otros más, para lo cual utilizaremos un método similar a read_csv()
como lo ocupamos antes.