Ir al contenido
wannacode

Vectorización

En resumen: La vectorización en NumPy es calcular con todo el arreglo a la vez, sin bucle: aritmética, comparaciones, máscaras con & y | y elecciones con np.where.

Problema

Un bucle para cada pregunta

El gerente quiere los precios con IVA. Justo después pregunta cuántos productos cuestan más de 5 €. Con una lista, cada pregunta es un bucle nuevo:

Pythondatos: las tablas de la tienda

Funciona: 1,20 € pasa a 1,44 €, y 8 productos están por encima de 5 €. Pero para cada pregunta siguiente escribes otro for, otra variable vacía y otro contador. La pregunta misma se pierde entre las líneas.

La idea

Cálculos con todo el arreglo

Con un arreglo escribes el cálculo una vez, para todos los números:

Pythondatos: las tablas de la tienda

prices * 1.2 multiplica cada uno de los 25 precios. El bucle está dentro de NumPy, en C. Esto se llama una operación vectorizada: actúa sobre todo el arreglo, no sobre un solo número. El juego de cuchillos de 39 € pasa a 46,80 €.

+, -, *, / y ** funcionan así, y también funciones como np.round(array, 2), que redondea cada número a 2 decimales.

La idea

Arreglo con arreglo

Dos arreglos de la misma longitud se calculan número a número: el primero con el primero, el segundo con el segundo. En order_items.csv cada línea tiene una cantidad y un precio unitario. El valor de la línea es uno por el otro:

Pythondatos: las tablas de la tienda

La primera línea son 4 unidades a 7,90 €, es decir, 31,60 €. Sin un solo bucle tienes el valor de las 152 líneas. .sum() las suma: 1963,50 €. A los resúmenes como sum llegamos en la lección 3.

Pruébalo

Cuánto vale el stock

Pon en value el valor del stock de cada producto: su precio por la cantidad en almacén.

Pythondatos: las tablas de la tienda

La idea

Comparación y máscara

Una comparación también está vectorizada. prices > 5 no da un True o False, sino uno para cada precio:

Pythondatos: las tablas de la tienda

Un arreglo de True y False así se llama una máscara. Puesta entre corchetes, se queda solo con los lugares con True. Y .sum() de una máscara cuenta los Trues, porque en una suma True es 1 y False es 0:

Pythondatos: las tablas de la tienda

8 precios son mayores que 5 €: la misma respuesta que con el bucle, en una línea. La máscara del stock también sirve para otro arreglo de la misma longitud: los nombres de los productos agotados son la banitsa y los pepinos.

La idea

Dos condiciones: &, | y ~

Los precios de 2 € a 5 € son dos condiciones juntas. En Python normal escribirías and. Con arreglos and no funciona:

Pythondatos: las tablas de la tienda

and pregunta «¿todo esto es verdad?» y quiere un solo True o False. El arreglo tiene 25. NumPy no adivina si quieres decir «todos» o «al menos uno», así que se detiene con un error.

Para las máscaras hay tres signos que actúan número a número:

  • & es «y»: las dos condiciones son verdaderas;
  • | es «o»: al menos una es verdadera;
  • ~ es «no»: da la vuelta a la máscara.
Pythondatos: las tablas de la tienda

9 precios van de 2 € a 5 €. Por debajo de 1 € o por encima de 20 € están 0,80 €, 0,90 €, 24,90 € y 39 €. Los precios de los productos que no están en stock son 2,50 € y 2,80 €.

Míralo

La trampa de los paréntesis

Cada condición alrededor de & y | va entre paréntesis. Si los omites, Python calcula & antes que >= y <=, es decir, empieza con 2 & prices:

Pythondatos: las tablas de la tienda

& entre un número y precios decimales no tiene sentido, así que obtienes un TypeError sobre bitwise_and. La regla es: cada condición entre paréntesis, (prices >= 2) & (prices <= 5).

Más precisamente, para curiosos

En Python &, | y ~ son operaciones bit a bit sobre enteros. Por eso ligan más fuerte que las comparaciones: 2 & 6 > 1 es (2 & 6) > 1. NumPy los tomó para las máscaras porque and, or y not no se pueden redefinir para arreglos: siempre quieren un solo True o False. Lo mismo verás con los filtros de pandas.

Pruébalo

Barato y en stock

¿Cuántos productos cuestan menos de 3 € y están en stock (stock mayor que 0)? Pon la cantidad en count.

Pythondatos: las tablas de la tienda

La idea

Una cosa o la otra: np.where

Una máscara elige qué números se quedan. A veces quieres todos, pero distintos según la condición. np.where(máscara, si_sí, si_no) toma una cosa u otra para cada lugar:

Pythondatos: las tablas de la tienda

Donde el stock es 0 obtienes «agotado», si no «en stock». En lugar del texto también puede haber arreglos: np.where(prices > 10, prices * 0.9, prices) rebaja solo los precios caros un 10 %.

Ejercicio

La lista de precios con IVA

De vuelta con el gerente: los precios con IVA y una promoción.

Pon en with_vat los precios con IVA (por 1,2), redondeados a 2 decimales. Pon en over_10 cuántos de ellos superan los 10 €.

Pythondatos: las tablas de la tienda

Promoción: los productos de más de 10 € son un 10 % más baratos, y los demás conservan el precio viejo. Pon la lista de precios nueva completa (25 precios) en promo.

Pythondatos: las tablas de la tienda

Test

Ponte a prueba

1. ¿Qué da np.array([2, 3]) * np.array([1.5, 4.0])?
2. ¿Qué da (prices > 5).sum()?
3. ¿Qué línea toma los precios de 2 € a 5 €?
4. ¿Por qué el descuento para los productos caros es np.where(prices > 10, prices * 0.9, prices) y no prices[prices > 10] * 0.9?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·