02a: Más sobre NumPy
Paquetes
matplotlib
numpy
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
Playground
Photo by Alfred Kenneally on Unsplasheagle = mpimg.imread("assets/02/alfred-kenneally-UsgLeLorRuM-unsplash.jpg")
plt.imshow(eagle)
<matplotlib.image.AxesImage at 0x113b77640>
eagle.shape
(1280, 1920, 3)
Flip, rotate
ej = np.array([[1, 2], [3, 4]])
print(ej)
np.flipud(ej)
[[1 2]
[3 4]]
array([[3, 4],
[1, 2]])
upside_down = np.flipud(eagle) # eagle[::-1,...].copy()
plt.imshow(upside_down)
<matplotlib.image.AxesImage at 0x113c396d0>
left_to_right = np.fliplr(eagle) # eagle[:, ::-1].copy()
plt.imshow(left_to_right)
<matplotlib.image.AxesImage at 0x113cb41c0>
rotated = np.rot90(eagle)
plt.imshow(rotated)
<matplotlib.image.AxesImage at 0x113d19820>
Uniendo arreglos
v1 = np.full((3,), 1)
v2 = np.full((3,), 2)
v3 = np.full((3,), 3)
print(v1, v2, v3)
[1 1 1] [2 2 2] [3 3 3]
m1 = np.full((3, 3), 1)
m2 = np.full((3, 3), 2)
m3 = np.full((3, 3), 3)
print(m1)
print(m2)
print(m3)
[[1 1 1]
[1 1 1]
[1 1 1]]
[[2 2 2]
[2 2 2]
[2 2 2]]
[[3 3 3]
[3 3 3]
[3 3 3]]
Concatenación
v = np.concatenate((v1, v2))
print(v.shape, v)
(6,) [1 1 1 2 2 2]
v = np.concatenate((v1, v2), axis=0)
print(v.shape, v)
(6,) [1 1 1 2 2 2]
v = np.concatenate((v1, v2, v3), axis=0)
print(v.shape, v)
(9,) [1 1 1 2 2 2 3 3 3]
v = np.concatenate((m1, m2), axis=1)
print(v.shape)
print(v)
(3, 6)
[[1 1 1 2 2 2]
[1 1 1 2 2 2]
[1 1 1 2 2 2]]
v = np.concatenate((m1, m2), axis=0)
print(v.shape)
print(v)
(6, 3)
[[1 1 1]
[1 1 1]
[1 1 1]
[2 2 2]
[2 2 2]
[2 2 2]]
Stacking
# np.stack
v = np.stack((v1, v2, v3))
print(v.shape)
print(v)
(3, 3)
[[1 1 1]
[2 2 2]
[3 3 3]]
v = np.stack((v1, v2, v3), axis=1)
print(v.shape)
print(v)
(3, 3)
[[1 2 3]
[1 2 3]
[1 2 3]]
v = np.hstack((v1, v2, v3))
print(v.shape)
print(v)
(9,)
[1 1 1 2 2 2 3 3 3]
v = np.vstack((v1, v2, v3))
print(v.shape)
print(v)
(3, 3)
[[1 1 1]
[2 2 2]
[3 3 3]]
v = np.dstack((v1, v2, v3))
print(v.shape)
print(v)
(1, 3, 3)
[[[1 2 3]
[1 2 3]
[1 2 3]]]
v = np.dstack((v1, v2, v3))
print(v.shape)
print(v)
(1, 3, 3)
[[[1 2 3]
[1 2 3]
[1 2 3]]]
v = np.stack((m1, m2, m3))
print(v.shape)
print(v)
(3, 3, 3)
[[[1 1 1]
[1 1 1]
[1 1 1]]
[[2 2 2]
[2 2 2]
[2 2 2]]
[[3 3 3]
[3 3 3]
[3 3 3]]]
v = np.stack((m1, m2, m3), axis=1)
print(v.shape)
print(v)
(3, 3, 3)
[[[1 1 1]
[2 2 2]
[3 3 3]]
[[1 1 1]
[2 2 2]
[3 3 3]]
[[1 1 1]
[2 2 2]
[3 3 3]]]
Observaciones sobre unir arreglos
- Concatenamos sobre dimensiones existentes
- Apilamos sobre nuevas dimensiones
Combinación de transformaciones
primer_canal = eagle[:, :, 0]
plt.imshow(primer_canal, cmap="gray")
<matplotlib.image.AxesImage at 0x113d88e50>
half_image = primer_canal[: len(primer_canal) // 4 * 3]
plt.imshow(half_image, cmap="gray")
print(half_image.shape)
(960, 1920)
new_image = np.dstack(
[half_image, np.zeros_like(half_image), half_image] # Rojo # Verde # Azul
)
plt.imshow(new_image)
<matplotlib.image.AxesImage at 0x113e603d0>
upside_down = np.flipud(new_image)
left_to_right = np.fliplr(upside_down)
two_eagle = np.concatenate((new_image, left_to_right))
plt.figure(figsize=(15, 15))
plt.imshow(two_eagle)
<matplotlib.image.AxesImage at 0x113ecb2b0>
ejemplo = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])
print(ejemplo)
np.roll(ejemplo, (1, -2), axis=(0, 1))
[[1 2 3 4]
[5 6 7 8]]
array([[7, 8, 5, 6],
[3, 4, 1, 2]])
plt.figure(figsize=(10, 10))
shift = 100
shifted_left = np.roll(new_image, shift, axis=(1))
shifted_right = np.roll(left_to_right, -shift, axis=(1))
two_eagle = np.concatenate((shifted_left, shifted_right))
plt.imshow(two_eagle)
<matplotlib.image.AxesImage at 0x113f2ffd0>
color_change_1 = np.roll(shifted_left, 2, axis=(2))
color_change_2 = np.roll(shifted_right, 1, axis=(2))
color_change_2 = np.where(color_change_2 < 30, 0, color_change_2)
two_eagle = np.concatenate((color_change_1, color_change_2))
plt.figure(figsize=(10, 10))
plt.imshow(two_eagle)
<matplotlib.image.AxesImage at 0x113fa0a00>
np.where
array = np.ones((5, 4)) * np.array([1, 2, 3, 4])
array_neg = np.ones((5, 4)) * np.array([1, 2, 3, 4]) * -9
print(array)
print(array_neg)
[[1. 2. 3. 4.]
[1. 2. 3. 4.]
[1. 2. 3. 4.]
[1. 2. 3. 4.]
[1. 2. 3. 4.]]
[[ -9. -18. -27. -36.]
[ -9. -18. -27. -36.]
[ -9. -18. -27. -36.]
[ -9. -18. -27. -36.]
[ -9. -18. -27. -36.]]
np.where(array % 2 == 0, 100, -800)
array([[-800, 100, -800, 100],
[-800, 100, -800, 100],
[-800, 100, -800, 100],
[-800, 100, -800, 100],
[-800, 100, -800, 100]])
np.nonzero
array = np.array([[1, 0, 0], [0, 2, 0], [3, 4, 0]])
array
array([[1, 0, 0],
[0, 2, 0],
[3, 4, 0]])
columnas, filas = np.nonzero(array)
for x, y in zip(columnas, filas):
print(f"({x}, {y})", array[x, y])
(0, 0) 1
(1, 1) 2
(2, 0) 3
(2, 1) 4
Ordenación
Sort
Crea una copia ordenada del arreglo que recibe como parámetro. Quicksort es el algoritmo usado por default.
arreglo = np.random.randint(0, 30, size=(6, 6))
print(arreglo)
[[22 12 5 26 0 1]
[ 5 6 22 19 20 9]
[24 5 17 20 19 0]
[28 8 9 17 16 12]
[ 8 24 18 23 18 0]
[23 21 18 4 25 14]]
np.sort(arreglo[0])
array([ 0, 1, 5, 12, 22, 26])
copia = np.array(arreglo[0])
print(copia)
copia.sort() # In Place
print(copia)
[22 12 5 26 0 1]
[ 0 1 5 12 22 26]
np.sort(arreglo, axis=1)
array([[ 0, 1, 5, 12, 22, 26],
[ 5, 6, 9, 19, 20, 22],
[ 0, 5, 17, 19, 20, 24],
[ 8, 9, 12, 16, 17, 28],
[ 0, 8, 18, 18, 23, 24],
[ 4, 14, 18, 21, 23, 25]])
np.argsort
arreglo[0]
array([22, 12, 5, 26, 0, 1])
indices = np.argsort(arreglo[0])
print(indices)
[4 5 2 1 0 3]
[4, 4, 5, 23, 26, 26]
[4, 4, 5, 23, 26, 26]
print(arreglo[0][indices])
[ 0 1 5 12 22 26]
np.argmax
y np.argmin
arreglo[0]
array([22, 12, 5, 26, 0, 1])
maximo = np.argmax(arreglo[0])
minimo = np.argmin(arreglo[0])
print(maximo, minimo)
print(arreglo[0][maximo], arreglo[0][minimo])
3 4
26 0
arreglo
array([[22, 12, 5, 26, 0, 1],
[ 5, 6, 22, 19, 20, 9],
[24, 5, 17, 20, 19, 0],
[28, 8, 9, 17, 16, 12],
[ 8, 24, 18, 23, 18, 0],
[23, 21, 18, 4, 25, 14]])
np.argmin(arreglo, axis=1)
array([4, 0, 5, 1, 5, 3])
Vectorización
Ya hablamos de la vectorización... pero, ¿cómo es que podemos aplicar esto en "la realidad"?
"Regla de oro"
🚫 for
🚫
El objetivo de la vectorización es, entre otras cosas, evitar el programar ciclos explícitamente.
- Analiza las variables de entrada
- Genera arreglos auxiliares
- Aplica las operaciones
- Recolecta los resultados
Alternativas al if
sample = np.random.uniform(-20, 20, (15,))
print(sample)
[ 4.56730224 19.02880331 -11.96054461 -0.5768552 3.88897091
-4.9145975 -17.05731846 -10.8866641 0.60906842 -3.03007902
2.58552579 19.40135034 9.00661466 -16.5622198 -12.71291223]
np.where
copy = sample.copy()
threshold = 2
for i in range(len(copy)):
if copy[i] < threshold:
copy[i] *= 10
print(copy)
[ 4.56730224 19.02880331 -119.60544609 -5.76855196 3.88897091
-49.14597504 -170.57318457 -108.86664097 6.0906842 -30.30079021
2.58552579 19.40135034 9.00661466 -165.62219797 -127.12912226]
copy = sample.copy()
print(np.where(copy < threshold, copy * 10, copy))
[ 4.56730224 19.02880331 -119.60544609 -5.76855196 3.88897091
-49.14597504 -170.57318457 -108.86664097 6.0906842 -30.30079021
2.58552579 19.40135034 9.00661466 -165.62219797 -127.12912226]
np.maximum
copy = sample.copy()
print(np.maximum(copy, 0))
[ 4.56730224 19.02880331 0. 0. 3.88897091 0.
0. 0. 0.60906842 0. 2.58552579 19.40135034
9.00661466 0. 0. ]
np.clip
print(np.clip(copy, -6, 6))
[ 4.56730224 6. -6. -0.5768552 3.88897091 -4.9145975
-6. -6. 0.60906842 -3.03007902 2.58552579 6.
6. -6. -6. ]
np.isnan
aa = np.array([np.nan, 10, 15, np.nan, 16])
promedio = aa[~np.isnan(aa)].mean()
np.where(np.isnan(aa), promedio, aa)
array([13.66666667, 10. , 15. , 13.66666667, 16. ])
print(~np.isnan(aa))
print(np.isnan(aa))
[False True True False True]
[ True False False True False]
Ecuaciones
Sumatorias (y acumulacionse en general)
Imagina una ecuación así
\(\sum_{i=0}^{} \cos(x_i^{2})\)
x = np.random.uniform(0, 1, 10)
np.sum(np.cos(x ** 2))
8.992406423625107
Supongamos que el índice del elemento \(i\) aparece dentro del cuerpo de la sumatoria:
\(\sum_{i=0}^{} \cos(x_i) * i\)
La solución es generar un arreglo con el índice \(i\) de antemano:
i = np.arange(len(x))
print(i)
np.sum(np.cos(x) * i)
[0 1 2 3 4 5 6 7 8 9]
37.43336056246062
Referencias
Libros
- Elegant SciPy: The Art of Scientific Python: México · España · US
- High Performance Python: Practical Performant Programming for Humans: México · España · US
Sitios web
- From Python to NumPy - https://www.labri.fr/perso/nrougier/from-python-to-numpy/
- 100 NumPy excercises - https://github.com/rougier/numpy-100
- NumPy Cheat Sheet — Python for Data Science - https://www.dataquest.io/blog/numpy-cheat-sheet/
- Chapter 3 Numerical calculations with NumPy - http://kestrel.nmt.edu/~raymond/software/python_notes/paper003.html