Paquetes

  • matplotlib
  • numpy
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np

Playground

Photo by Alfred Kenneally on Unsplash
eagle = mpimg.imread("assets/02/alfred-kenneally-UsgLeLorRuM-unsplash.jpg")
plt.imshow(eagle)
<matplotlib.image.AxesImage at 0x113b77640>

png

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>

png

left_to_right = np.fliplr(eagle)  # eagle[:, ::-1].copy()
plt.imshow(left_to_right)
<matplotlib.image.AxesImage at 0x113cb41c0>

png

rotated = np.rot90(eagle)
plt.imshow(rotated)
<matplotlib.image.AxesImage at 0x113d19820>

png

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>

png

half_image = primer_canal[: len(primer_canal) // 4 * 3]
plt.imshow(half_image, cmap="gray")
print(half_image.shape)
(960, 1920)

png

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>

png

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>

png

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>

png

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>

png

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