6.8. Operadores

El primer tipo de operación matemática que numpy ejecuta sobre un ndarray son los operadores estándar de Python. Los operadores aritméticos, de comparación y a nivel de bits funcionan todos elemento a elemento – cada operador recorre el array (o ambos arrays) una vez de principio a fin dentro de una única llamada a la biblioteca, mucho más rápido que el bucle for de Python equivalente.

6.8.1. Aritmética

+, -, *, /, //, %, ** funcionan todos entre dos arrays de forma compatible, o entre un array y un escalar:

a = np.array([1, 2, 3, 4], dtype=np.float)
b = np.array([10, 20, 30, 40], dtype=np.float)

print(a + b)        # array([11.0, 22.0, 33.0, 44.0])
print(a * 2)        # array([2.0, 4.0, 6.0, 8.0])
print(b - a)        # array([9.0, 18.0, 27.0, 36.0])
print(b / a)        # array([10.0, 10.0, 10.0, 10.0])

El dtype del resultado sigue las reglas de promoción descritas en Dtypes. Los arrays de enteros se envuelven en caso de desbordamiento; convierte a un dtype más amplio antes de la operación cuando eso importe.

El operador de multiplicación de matrices @ no está implementado. Usa dot() para productos de matrices o vectores.

6.8.1.1. Formas in situ

Cada operador aritmético tiene una forma in situ – +=, -=, *=, /=, %=, **=. La forma in situ escribe a través del búfer existente en lugar de reservar uno temporal:

b = b + 1            # allocates a temporary the size of b
b += 1               # no temporary

En un microcontrolador, la segunda forma es esencialmente obligatoria para cualquier bucle crítico.

6.8.2. A nivel de bits

Los operadores a nivel de bits &, |, ^ funcionan elemento a elemento sobre arrays de enteros. Aplicados a un array float o complex lanzan TypeError:

a = np.array([0b1100, 0b1010], dtype=np.uint8)
b = np.array([0b1010, 0b1100], dtype=np.uint8)
print(a & b)        # array([8, 8], dtype=uint8)
print(a | b)        # array([14, 14], dtype=uint8)
print(a ^ b)        # array([6, 6], dtype=uint8)

El operador unario ~ realiza un NOT a nivel de bits sobre un array de enteros.

Los operadores de desplazamiento << y >> no están conectados a nivel de operador de Python. Las formas de función left_shift() y right_shift() sí funcionan:

np.left_shift(a, 2)
np.right_shift(b, 1)

6.8.3. Comparación

==, !=, <, <=, >, >= devuelven todos un ndarray de tipo bool con la forma resultante del broadcasting:

a = np.array([1, 2, 3, 4, 5], dtype=np.uint8)
print(a < 3)
# array([True, True, False, False, False], dtype=bool)

El resultado booleano es exactamente lo que consumen la indexación y la Selección y reordenación.

6.8.3.1. La regla del lado

El ndarray debe estar a la izquierda de un operador relacional al compararlo con un escalar. a > 2 funciona; 2 < a lanza TypeError. Para la forma simétrica, usa los nombres de función:

np.greater(5, a)        # 5 > a, element-wise
np.less(5, a)           # 5 < a, element-wise
np.equal(5, a)          # 5 == a, element-wise
np.not_equal(5, a)      # 5 != a, element-wise

6.8.4. Operadores unarios

  • +a – devuelve una copia del array.

  • -a – negación. En dtypes sin signo los valores se envuelven módulo \(2^N\), igual que hacen los operadores binarios.

  • abs(a) – valor absoluto elemento a elemento. En dtypes sin signo devuelve una copia sin cálculo.

  • ~a – inversión a nivel de bits (solo arrays de enteros).

  • len(a) – devuelve la longitud del primer eje, conforme a la convención de secuencias de Python.

6.8.5. Qué falta

Los operadores del lado derecho para la comparación y algunas de las operaciones a nivel de bits no están implementados de la misma manera que los operadores aritméticos. Usa las formas de función (arriba) cuando un ndarray quedaría a la derecha.

Para la lista completa de operadores admitidos y la promoción de tipos que siguen, consulta numpy — operaciones con arreglos compatibles con numpy.