Vectorización en Python

· Bestiario de Robledo

Sucinta semblanza de mapear, filtrar y reducir

En nuestro periplo picateclero, en los primeros compases, los bucles for son herramientas útiles, aunque con sus limitaciones inherentes, por velocidad. ¿Y si hubiese algo más rápido? ¿Y si pudiésemos vectorizar?

En primer lugar, crearemos un objeto iterable al cual podamos acceder con números, sea una lista, una tupla o un diccionario. Por ejemplo, el lemario de la RAE puede ser esto:

1import urllib
2lemario = urllib.request.urlopen("https://iedra.es/static/lemario-23.5.txt").read().decode("utf-8").split("\n")[:-1]
3
4{x:len(x) for x in lemario} # un diccionario con las longitudes de cada palabra

¿Qué puede hacer map con nuestra lista? Básicamente estamos enchufando una función a nuestra lista. ¿Cómo hacer que veinte palabras castellanas al azar chíllen en mayúsculas?

1from random import seed, choices
2seed(36)
3choices(lemario, k=20)
4list(map(lambda x: x.upper(), choices(lemario, k=20)))

Hemos utilizado una función anónima, lambda, para que a cada elemento se le aplique una función. A este respecto, hay que notar que una alternativa, igual de rápida pero más adepta al lenguaje que nos ocupa, es una lista de comprensión, {} (conjunto), {k:n} (diccionario), [] (lista) y () (generador). En dichas listas podemos aplicar una función a cada elemento en una colección y, si tercia, una condición, como que sean iguales o mayores a cinco, mientras con filter y map estaremos realizando esas tareas por separado. Incluso algunos, como el mismísimo creador de Python, Guido van Rossum, consideran que dichas funciones sobran existiendo listas de comprensión.

Con filter, como en el caso de map, tendremos una condición asociada a una función, sea anónima (lambda) o no. ¿Qué alumnos pasan el corte?

1from random import seed, choices
2seed(10)
3notas = choices(range(0, 10), k=20)
4
5list(filter(lambda x: x >= 5, notas))

Pero, ojo, en una lista de comprensión podemos realizar esto sin tanta fanfarria: [x for x in notas if x >= 5]. Una sola línea, ¿ven?

Por último, hablemos de reduce. Se itera sobre todos los elementos de una colección de elementos, como lo pueda ser una lista. Hay una fila. El camarero va avisando. «Usted, Peláez, puede entrar». Luego, «Usted, Fernández...». Y así sucesivamente hasta agotar la fila. En el caso del Ordenador, se salta de un elemento a otro hasta reducirlo a uno solo, como lo pueda ser el caso de una suma. Veamos.

1from functools import reduce
2reduce(lambda x,y: x+y, notas)

También puede servir, por ejemplo, para convertir una lista con sublistas en una sin ellas, reduce(lambda x,y: x+y, [[1,2], [4,5]]). Aunque hay que notar que sólo la reduce un nivel.

Tras este breve repaso, colegimos que está bien entender qué hacen, es cultura general de Santa Tecla, pero no conviene ir mucho más allá teniendo las listas de comprensión.