domingo, 3 de enero de 2021

2) Accediendo a los datos de las matrices con Numpy. Copia de Matrices. Añadir elementos a un array con np.append()




Accediendo a los datos de las matrices con Numpy. Copia de Matrices. Añadir elementos a un array con numpy.append()


La forma en la que se accede a los datos de las matrices en Numpy es similar a como se hace con las listas en Python. La diferencia está en que mientras que las listas son unidimensionales las matrices son ciertamente multidimensionales. Esto significa que mientras que en una lista solo hay un índice para cada elemento, con Numpy al tratarse de matrices puede haber varios valores índices (uno para cada dimensión)

Vamos a explicar esto mejor, con un ejemplo.

Para acceder a un elemento concreto de una matriz de 3 dimensiones, tenemos que usar el valor del índice de cada dimensión separada por comas:

>>> import numpy as np
# Importamos la librería Numpy

>>> a = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> print(a)
[[1 2 3]
 [4 5 6]
 [7 8 9]]


Ahora imaginemos que queremos seleccionar el número 3 de la primera fila, el 5 de la segunda y el 7 de la tercera fila. Lo primero que tendremos que hacer es, indicar en que fila está el elemento y posteriormente, después de poner la coma, indicar la posición del elemento en la fila. Ten en cuenta que en Python los elementos de una lista si se  empiezan a contar por la izquierda se comienza a contar desde el 0.

>>> print(a[0,2])
3
>>> print(a[1,1])
5
# Seleccionamos el elemento contando desde la izquierda.
>>> print(a[2,-3])
7

Otra forma de acceder a un elemento de estas matrices anteriores es usando una forma muy parecida a la anterior, usando [][]. Por ejemplo el elemento 8 de la matriz a anterior que está en la 3ª fila y 2ª columna se puede buscar también así:

>>> print(a[3,-1][2,-1])
8
# realmente se pondría print(a[2][1]) pero he preferido poner la resta
# ya que los elementos se empiezan a contar en el cero, con lo que el 
# elemento 8, estaría en la fila 2 y columna 1 en python.

También podemos hacer "slicing" o arreglos con las matrices, podemos seleccionar una parte o "rebanada" de los datos de una matriz incluso con múltiples dimensiones.

Pongamos un ejemplo. Creemos un array unidimensional con 10 elementos y seleccionemos los elementos que están desde la posición 1 al 2, funciona como las listas de python. La selección va desde el primer número indicado hasta el último sin incluir este.

>>> m = np.arange(10)
>>> m
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> m[1:3]
array([1, 2])

o una selección que vaya desde la posición 4ª hasta el final

>>> m[3:]
array([3, 4, 5, 6, 7, 8, 9])

o que incluya todos los elementos menos el último

>>> m[:-1]
array([0, 1, 2, 3, 4, 5, 6, 7, 8])

o cambiar los elementos que van desde el 4 al final con un 0

>>> m[4:] = 0
array([0, 1, 2, 3, 0, 0, 0, 0, 0, 0])

o seleccionar los elementos del 1 al 7 (sin incluir) con un salto de dos elementos:

m[1:7:2]
array([1, 3, 0])

Veamos también el caso de una matriz multidimensional con varias filas. Imaginemos que creamos una matriz de 5x5 y la rellenamos con ceros. Después queremos insertar el número 3 en los elementos que ocupan la primera y segunda fila y también  la primera y segunda columna (recordando que tanto filas como columnas se empiezan a contar en el cero)

>>> n = np.zeros((5,5))
>>> n
array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])
>>> n[1:3,1:3]=3
>>> n
array([[0., 0., 0., 0., 0.],
       [0., 3., 3., 0., 0.],
       [0., 3., 3., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]])

Matrices y copia de matrices.


Si queremos copiar una matriz no basta solamente con elegir un nuevo nombre y asignárselo. Si modificamos la matriz usando la nueva referencia, los cambios son visibles en cualquiera de las asignaciones que hagan referencia a la misma matriz. Veámoslo con un ejemplo:

>>> matriz_a = np.array([1,3,5,7,9])
>>> matriz_b = matriz_a
>>> matriz_b[2:]=-7
>>> matriz_a
array([ 1,  3, -7, -7, -7])


Si realmente queremos copiar una matriz y que sea realmente independiente del original hay que utilizar el método copy()

>>> matriz_a = np.array([1,3,5,7,9])
>>> matriz_b = matriz_a.copy()
# Esto copia la matriz_a en matriz_b y hace a esta independiente.

Hay que tener en cuenta que si hacemos slicing a una matriz, cualquier modificación que hagamos quedará reflejada en la matriz. Por tanto si queremos hacer una copia de una parte de una matriz debemos utilizar el método copy()

>>> original = np.arange(10)
>>> una_parte = original[1:4] # Esto es una vista, si cambiamos algún elemento
de una_parte los cambios se reflejaran en los elementos [1:4] de la original.
>>> una_parte = original[1:4].copy() # Esto es una verdadera copia de una parte
de la matriz original.


Añadir elementos a un array con np.append()


Con numpy.append() podemos añadir nuevos elementos al final de los arrays de numpy. Este método tiene la siguiente forma:

np.append(arr, values, axis=None)

En donde:

arr es un array o matriz de Numpy.

values son los elementos que se agregaran al final del array que se pasa en el argumento anterior. Este elemento no tiene porque ser solo unos números ya que también puede ser un array o matriz.

axis (opcional) es el eje en el que se agregarán los valores.

IMPORTANTE:  ¡Este método no MODIFICA el array original, sino que crea una copia a la que se agregan los nuevos valores.!

Por otro lado si no especificamos un eje en el que añadir los elementos, la matriz que le hayamos pasado se aplanará antes de agregar los nuevos elementos, para así poder añadirlos al final.

Recordamos que si:

axis = 0 estamos refiriéndonos al eje vertical por lo que si es posible se añadirán nuevas filas.
axis = 1 estamos refiriéndonos al eje horizontal por lo que si es posible se añadirán nuevas columnas.

Veamos unos cuantos ejemplos de todo esto.


Añadir un número al final de un array unidimensional.


>>> import numpy as np
>>> arr = np.array([1, 2, 3, 4, 5])

# Queremos añadir el número 10 al final de este array
>>> np.append(arr, 10)
array([ 1,  2,  3,  4,  5, 10])

#O también podríamos agregar otro arrray.
>>> np.append(arr, [11, 12])
array([ 1,  2,  3,  4,  5, 11, 12])

# Como puedes ver en este último caso el array original no se modifica,
# ya que como ves no aparece el número 10 del caso anterior.

Agregar elementos a matrices o arrays que no sean unidimensionales.

Cuando agregamos elementos a una matriz  es necesario que indiquemos mediante la propiedad axis si los nuevos elementos se agregan por filas o por columnas. En el caso de que no lo hagamos, la matriz se aplanará antes de añadir los elementos, obteniéndose un array unidimensional.

Por ejemplo:

>>> mat = np.array([[1, 2, 3],[4, 5, 6]])
>>> np.append(mat, [11, 12])
array([ 1,  2,  3,  4,  5,  6, 11, 12])

Como veremos más adelante, para poder añadir una nueva fila a la matriz esta tiene que ser compatible, es decir tiene que tener el mismo número de columnas que la original. Sino es así Numpy te dará un error. Si en el ejemplo anterior intentamos añadir estos dos elementos a la matriz original, nos dará un error ya que nuestra matriz tiene 3 columnas y le estamos tratando de añadir solo 2 elementos en vez de 3.

>>> np.append(mat, [[11, 12]], axis=0)
ValueError: all the input array dimensions for the concatenation axis 
must match exactly, but along dimension 1, the array at index 0 has 
size 3 and the array at index 1 has size 2

Por tanto si queremos añadirle una nueva fila a nuestra matriz esta tiene que tener 3 elementos para poder hacerlo, además de establecer el parámetro axis=0. Vamos a añadir entonces [11, 12, 13]  a nuestra matriz.

>>> np.append(mat, [[11, 12, 13]], axis=0)
array([[ 1,  2,  3],
       [ 4,  5,  6],
       [11, 12, 13]])

Si lo que queremos añadir es una nueva columna el método funciona exactamente igual. Los elementos a agregar deberán estar en una matriz con el mismo número de filas que la matriz original.

Como nuestra matriz original tiene 2 filas si queremos añadir una nueva columna deberemos añadir una matriz con  2 elementos y que tenga la misma dimensión.

>>> np.append(mat, [[11], [12]], axis=1)
array([[ 1,  2,  3, 11],
       [ 4,  5,  6, 12]])


Y con esto hemos visto lo básico del método np.append() de Numpy, sigamos repasando lo visto en el capítulo con un nuevo ejercicio.


EJERCICIO


Creemos una matriz con una dimensión de 4*4 con valores aleatorios. 

Luego extraigamos todos los valores de la segunda fila.

A continuación extraeremos todos los valores de la tercera columna.

Asignaremos el valor 0.31 al subarreglo  2x2 superior izquierdo.

Para finalizar crearemos una matriz de 8x8 con un patrón de tablero de damas, es decir, alternando ceros y unos :

1 0 1

0 1 0

1 0 1

...


SOLUCIÓN.


>>> import numpy as np


"Creamos una matriz de 4x4 con valores arbitrarios enteros del 0,1"
>>> a=np.random.rand(4,4) # o números enteros con np.random.randint(0,11,(4,4))
>>> print(a)
[[0.86244938 0.10086289 0.49685669 0.89849421]
 [0.63274446 0.90953088 0.87053284 0.32822434]
 [0.94201367 0.60204052 0.72596334 0.36410397]
 [0.68208797 0.46102898 0.59214942 0.89901397]]


"Extraer cada elemento de la segunda fila."
>>> print(a[1])
[0.63274446 0.90953088 0.87053284 0.32822434]

"Extraer cada elemento de la tercera columna"
print(a[:,2])
[0.49685669 0.87053284 0.72596334 0.59214942]

"Asignar un valor de .31 a la matriz de 2*2 de arriba a la izquierda"
a[:2,:2]=0.31
print(a)
[[0.31       0.31       0.49685669 0.89849421]
 [0.31       0.31       0.87053284 0.32822434]
 [0.94201367 0.60204052 0.72596334 0.36410397]
 [0.68208797 0.46102898 0.59214942 0.89901397]]

"Crear una matriz de 8x8 alternando 0 y 1"
#b = np.array([[(i+j+1) % 2 for i in range(8)] for j in range(8)]) solución alternativa
b=np.zeros((8,8),dtype="int")
b[::2,::2]=1
b[1::2,1::2]=1
print(b)
[[1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]
 [1 0 1 0 1 0 1 0]
 [0 1 0 1 0 1 0 1]]



Próximo Post. Matemáticas con Numpy.

No hay comentarios:

Publicar un comentario