Operaciones entre arrays y escalares
Al igual que ocurría en los casos anteriores, si operamos con un array y un escalar, éste último será difundido para abarcar el tamaño del array:
Operaciones unarias
Existen multitud de operaciones sobre un único array. A continuación veremos algunas de las más utilizas en NumPy.
Funciones universales
Las funciones universales «ufunc» son funciones que operan sobre arrays elemento a elemento. Existen muchas funciones universales definidas en Numpy, parte de ellas operan sobre dos arrays y parte sobre un único array.
Un ejemplo de algunas de estas funciones:
Reduciendo el resultado
NumPy nos permite aplicar cualquier función sobre un array reduciendo el resultado por alguno de sus ejes. Esto abre una amplia gama de posibilidades.
A modo de ilustración, veamos un par de ejemplos con la suma y el producto:
Ejercicio
Compruebe que, para 9 = 2n (radianes) y k = 20 se cumple la siguiente igualdad del producto infinito de Euler:
Funciones estadísticas
NumPy proporciona una gran cantidad de funciones estadísticas que pueden ser aplicadas sobre arrays.
Veamos algunas de ellas:
Máximos y mínimos
Una de las operaciones más comunes en el manejo de datos es encontrar máximos o mínimos. Para ello, disponemos de las típicas funciones con las ventajas del uso de arrays multidimensionales:
Si lo que interesa es obtener los índices de aquellos elementos con valores máximos o mínimos, podemos hacer uso de las funciones argmax() y argmin() respectivamente.
Veamos un ejemplo donde obtenemos los valores máximos por columnas (mediante sus índices):
Vectorizando funciones
Una de las ventajas de trabajar con arrays numéricos en NumPy es sacar provecho de la optimización que se produce a nivel de la propia estructura de datos. En el caso de que queramos implementar una función propia para realizar una determinada acción, sería deseable seguir aprovechando esa característica.
Veamos un ejemplo en el que queremos realizar el siguiente cálculo entre dos matrices A y B:
Esta función, definida en Python, quedaría tal que así:
Las dos matrices de partida tienen 9M de valores aleatorios entre -100 y 100:
Una primera aproximación para aplicar esta función a cada elemento de las matrices de entrada sería la siguiente:
Mejorando rendimiento con funciones vectorizadas
Con un pequeño detalle podemos mejorar el rendimiento de la función que hemos diseñado anteriormente. Se trata de decorarla con np.vectorize con lo que estamos otorgándole un comportamiento distinto y enfocado al procesamiento de arrays numéricos:
Dado que ahora ya se trata de una función vectorizada podemos aplicarla directamente a las matrices de entrada (aprovechamos para medir su tiempo de ejecución):
Hemos obtenido una mejora de 2.32x con respecto al uso de funciones simples.
Truco: La mejora de rendimiento se aprecia más claramente a medida que los tamaños de las matrices (arrays) de entrada son mayores.
Consejo: El uso de funciones lambda puede ser muy útil en vectorización: np. vectorize(lambda a, b: return a + b).
Ejercicio
- Cree dos matrices cuadradas de 20×20 con valores aleatorios flotantes uniformes en el intervalo [0,1000)
- Vectorice una función que devuelva la media (elemento a elemento) entre las dos matrices.
- Realice la misma operación que en 2) pero usando suma de matrices y división por escalar.
- Compute los tiempos de ejecución de 2) y 3)
NumPy tiene una sección dedicada al álgebra lineal cuyas funciones pueden resultar muy interesantes según el contexto en el que estemos trabajando.
Producto de matrices
Si bien hemos hablado del producto de arrays elemento a elemento, NumPy nos permite hacer la multiplicación clásica de matrices:
En Python 3.5 se introdujo el operador @ que permitía implementar el método especial_ matmul_ () de multiplicación de matrices. NumPy lo ha desarrollado y simplifica la multiplicación de matrices de la siguiente manera:
Ejercicio
Compruebe que la matriz [︂1 2 3 5 ]︂ satisface la ecuación matricial: 𝑋2 − 6𝑋 − 𝐼 = 0 donde 𝐼
es la matriz identidad de orden 2.
Determinante de una matriz
El cálculo del determinante es una operación muy utilizada en álgebra lineal. Lo podemos realizar en NumPy de la siguiente manera:
Inversa de una matriz
La inversa de una matriz se calcula de la siguiente manera:
Una propiedad de la matriz inversa es que si la multiplicamos por la matriz de partida obtenemos la matriz identidad. Vemos que se cumple 𝒜 · 𝒜−1 = ℐ:
Traspuesta de una matriz
La traspuesta de una matriz A se denota por: (𝒜𝑡)𝑖𝑗 = 𝒜𝑗𝑖, 1 ≤ 𝑖 ≤ 𝑛, 1 ≤ 𝑗 ≤ 𝑚, pero básicamente consiste en intercambiar filas por columnas.
Aún más fácil es computar la traspuesta de una matriz con NumPy:
Ejercicio
Dadas las matrices:
, compruebe que se cumplen las siguientes igualdades:
• (𝐴 + 𝐵)𝑡 = 𝐴𝑡 + 𝐵𝑡
• (3𝐴)𝑡 = 3𝐴𝑡
Elevar matriz a potencia
En el mundo del álgebra lineal es muy frecuente recurrir a la exponenciación de matrices a a través de su producto clásico. En este sentido, NumPy nos proporciona una función para computarlo:
Ejercicio
¿Nota algo especial en los resultados?
Sistemas de ecuaciones lineales
NumPy también nos permite resolver sistemas de ecuaciones lineales. Para ello debemos modelar nuestro sistema a través de arrays.
Veamos un ejemplo en el que queremos resolver el siguiente sistema de ecuaciones lineales:
Podemos almacenar las matrices de coeficientes A y B de la siguiente manera:
La solución al sistema viene dada por la siguiente función:
La solución del sistema debe ser la misma que si obtenemos 𝒳 = 𝒜−1 · 𝐵:
Ejercicio
Resuelva el siguiente sistema de ecuaciones lineales: