Introducción al análisis de datos en Python con Numpy

Arrays de 2 dimensiones

En la lección anterior vimos como trabajar con arrays de una dimensión, ahora veremos como se trasladan esos conceptos a la segunda dimensión.

Es extremadamente sencillo si nos imaginamos el array como una tabla con filas y columnas.

# %%
import numpy as np

arr_2d = np.array(([0,5,10], [15,20,25], [30,35,40]))

arr_2d

Índices

Si tenemos dos dimensiones, entonces necesitamos dos índices.

El primer índice hace referencia a la primera dimensión, podemos entenderlo como la fila:

# Primera fila
arr_2d[0]

Ahora para acceder a la segunda dimensión, o columna, utilizaremos un segundo índice. Así podemos acceder a valors individuales:

# Primera fila y primera columna
arr_2d[0][0]

También podemos utilizar los índices negativos para posicionarnos muy fácilmente en la última fila y última columna:

arr_2d[-1][-1]

Utilizando esta lógica podemos cambiar fácilmente la primera columna de la última fila:

arr_2d[-1][0] = 99

arr_2d

Slicing

También es posible utilizar slicing, aunque al tener dos dimensiones deberemos hacerlo doblando los indices de inicio y fin separados por una coma.

Por ejemplo, un slicing sin indices buscaría un subarray con todas las filas y columnas:

arr_2d[:,:]

Para conseguir un subarray de las dos primeras filas haríamos:

arr_2d[:2,:]

O uno con la primera columna:

arr_2d[:,:1]

Con esta lógica podemos también modificar los elementos masivamente. Por ejemplo toda la segunda columna:

arr_2d[:,1:2] = 0

arr_2d

Copias

Evidentemente los arrays de dos dimensiones también están referenciados en memoria, por lo que todos los cambios realizados en un subarray se verán reflejados en el original.

Recordad utilizar el método .copy() para crear copias por valor y no por referencia a la memoria.

Fancy index

El último concepto importante que veremos sobre los arrays 2d es el fancy index. Esta propiedad de los arrays nos permite trabajar muy cómodamente con las filas de estos arrays.

Por ejemplo, vamos a crear una matriz 5x10 llena de ceros:

arr_2d = np.zeros((5,10))

arr_2d

Ahí tenemos nuestra matriz de 5 filas y 10 columnas.

Hasta ahora sabemos acceder fácilmente a una fila concreta, por ejemplo la 3 (3-1):

arr_2d[2] = 10

arr_2d

¿Pero habría alguna forma de acceder a varias a la vez? Pues sí, con el fancy index, que se basa en pasarle una lista al array haciendo referencia a las filas donde queremos acceder.

Por ejemplo podemos modificar al vuelo la primera, tercera y última fila:

arr_2d[[0,2,-1]] = 99
       
arr_2d   

Incluso podemos utilizarlo en cualquier orden o doblando índices:

arr_2d[[4,0,1,0,4]]

La verdad es que es casi mágico, y todo es por la idea de que realmente las filas simulan sublistas.

De hecho podríamos recorrer este array 2d con un for y cada vez que entramos al bucle estamos en una fila:

for row in arr_2d:
    print(row)

De manera que si quisiéramos darle el mismo valor a cada fila no costaría mucho, sólo deberíamos acceder a través de nuestro índice mágico, que podemos sacarlo por ejemplo con un enumerador:

for i, row in enumerate(arr_2d):
    arr_2d[i] = i
    
arr_2d