Volver a la lista

Transmisión — Reglas de operaciones con arreglos multidimensionales

Comprenda visualmente las reglas de broadcasting que permiten realizar operaciones entre matrices de diferentes tamaños en NumPy.

Intermedio
|
10min
|
Verificado (2026-07)
difusiónNumPycompatibilidad de formaoperaciones con arraysvectorización
Progreso0/17 (0%)

Broadcasting: Reglas de Operaciones con Arreglos Multidimensionales

Al finalizar este tema

Comprenderá la razón de ser del broadcasting en NumPy, sabrá determinar si las operaciones son posibles aplicando sus tres reglas y podrá escribir código eficiente utilizando el broadcasting.


¿Por qué es necesario el broadcasting?

python
import numpy as np
# Quiero sumar 10 a todos los elementos
arr = np.array([1, 2, 3, 4, 5])
result = arr + 10
print(result) # [11 12 13 14 15]

arr tiene 5 elementos, mientras que 10 es un escalar (1 elemento). Aunque tienen tamaños diferentes, se pueden sumar porque NumPy realizó una expansión automática de 10 a [10, 10, 10, 10, 10]. Esta expansión automática se conoce como difusión (broadcasting).

Sin la difusión:

python
# Hay que escribirlo así cada vez
result = arr + np.full(5, 10) # Ineficiente

Operaciones con formas idénticas — Conceptos básicos

Si las dimensiones son iguales, se realiza una operación elemento por elemento.

python
a = np.array([1, 2, 3])
b = np.array([10, 20, 30])
print(a + b) # [11 22 33]
print(a * b) # [10 40 90]

Lo mismo ocurre en dos dimensiones.

python
A = np.array([[1, 2], [3, 4]])
B = np.array([[10, 20], [30, 40]])
print(A + B)
# [[11 22]
# [33 44]]

Reglas de difusión — 3 reglas

Cuando las dimensiones son diferentes, NumPy aplica tres reglas en orden.

Regla 1: Si el número de dimensiones es diferente, se añade un 1 al principio de la matriz con menos dimensiones.

python
a = np.array([[1, 2, 3], # shape: (2, 3)
[4, 5, 6]])
b = np.array([10, 20, 30]) # shape: (3,)
# Regla 1: expandir la forma de b (3,) a (1, 3)
# Después de aplicar la regla 2: (1, 3) → (2, 3)
print(a + b)
# [[11 22 33]
# [14 25 36]]

Regla 2: Las dimensiones con tamaño 1 se expanden para que coincidan con las de otro arreglo.

python
a = np.array([[1, 2, 3]]) # shape: (1, 3)
b = np.array([[10], # shape: (3, 1)
[20],
[30]])
# a: (1, 3) → expansión en dirección de fila → (3, 3)
# b: (3, 1) → expansión en dirección de columna → (3, 3)
print(a + b)
# [[11 12 13]
# [21 22 23]
# [31 32 33]]

Regla 3: Si las dimensiones son diferentes y ninguna de ellas es igual a 1, se produce un error.

python
a = np.array([1, 2, 3]) # shape: (3,)
b = np.array([10, 20]) # shape: (2,)
# 3 vs 2 — ninguno es 1 → ¡Error!
# a + b → ValueError: operands could not be broadcast together

Comprensión visual

text
(4, 3) + (3,)    → OK!
a:  [[1 2 3]      b: [10 20 30]
     [4 5 6]          ↓ Regla1: (1, 3)
     [7 8 9]          ↓ Regla2: (4, 3)
     [0 1 2]]
                  b': [[10 20 30]
                       [10 20 30]
                       [10 20 30]
                       [10 20 30]]

Resultado: [[11 22 33]
       [14 25 36]
       [17 28 39]
       [10 21 32]]
text
(3, 1) + (1, 4)  → ¡OK!  Forma del resultado: (3, 4)
a: [[1]           b: [[10 20 30 40]]
    [2]               ↓ Regla 2: (3, 4)
    [3]]          b': [[10 20 30 40]
    ↓ Regla 2           [10 20 30 40]
a': [[1 1 1 1]        [10 20 30 40]]
     [2 2 2 2]
     [3 3 3 3]]

Resultado: [[11 21 31 41]
       [12 22 32 42]
       [13 23 33 43]]

Patrón práctico: Normalización

python
# Restar la media de cada columna para centrar (centrado)
data = np.array([[170, 60, 30],
[180, 75, 25],
[165, 55, 35],
[175, 70, 28]])
# forma: (4, 3) — 4 personas, 3 mediciones (estatura, peso, edad)
col_mean = data.mean(axis=0) # forma: (3,) — media de cada columna
print(col_mean) # [172.5 65. 29.5]
centered = data - col_mean # (4, 3) - (3,) → ¡transmisión por difuminado!
print(centered)
# [[ -2.5 -5. 0.5]
# [ 7.5 10. -4.5]
# [ -7.5 -10. 5.5]
# [ 2.5 5. -1.5]]

Normalización por puntuación Z

python
col_std = data.std(axis=0)
z_scores = (data - col_mean) / col_std # ¡Transmisión por difuminado dos veces!

(4, 3) - (3,) → OK, (4, 3) / (3,) → OK. Este patrón permite normalizar todo el conjunto de datos.


Transmisión frente a bucle

python
# Mal: Bucle de Python — lento
data = np.random.rand(10000, 100)
mean = data.mean(axis=0)
result = np.zeros_like(data)
for i in range(data.shape[0]):
for j in range(data.shape[1]):
result[i, j] = data[i, j] - mean[j]
# Bien: Transmisión por difuminado — más de 100 veces más rápido
result = data - mean

La difusión se implementa internamente como operaciones vectoriales en C. Es entre diez y cien veces más rápida que los bucles de Python, y el código consta de una sola línea.


Patrón práctico: Matriz de distancias

Calcula todas las distancias entre dos conjuntos de puntos de forma simultánea.

python
# 3 puntos: (1,0), (2,3), (4,1)
points = np.array([[1, 0], [2, 3], [4, 1]]) # shape: (3, 2)
# Distancia euclidiana entre todos los pares
diff = points[:, np.newaxis, :] - points[np.newaxis, :, :]
# (3,1,2) - (1,3,2) → broadcasting → (3,3,2)
dist = np.sqrt((diff ** 2).sum(axis=2))
print(dist.round(2))
# [[0. 3.16 3.16]
# [3.16 0. 2.83]
# [3.16 2.83 0. ]]

np.newaxis se utiliza para añadir una dimensión y calcular las diferencias entre todos los pares de manera simultánea mediante la función de transmisión (broadcasting). Esto es decenas de veces más rápido que utilizar bucles anidados.


Advertencia: posible consumo excesivo de memoria

python
a = np.random.rand(10000, 1) # shape: (10000, 1)
b = np.random.rand(1, 10000) # shape: (1, 10000)
c = a + b # forma: (10000, 10000) — ¡100 millones de elementos!
# Memoria: 10000 × 10000 × 8 bytes = 800 MB

El broadcasting amplía conceptualmente el tamaño, pero el array resultante sí ocupa memoria. (10000, 1) + (1, 10000) crea un array de tamaño (10000, 10000). Con conjuntos de datos grandes, calcule de antemano la forma del resultado para verificar el uso de memoria.

python
# Predicción del uso de memoria
result_shape = (10000, 10000)
dtype_size = 8 # float64 = 8 bytes
memory_bytes = result_shape[0] * result_shape[1] * dtype_size
print(f"{memory_bytes / 1e6:.0f} MB") # 800 MB

Método rápido para determinar la compatibilidad de formas

Alinee los elementos desde la derecha; las dimensiones son compatibles si son iguales o si una de ellas es 1.

text
(4, 3) + (3,)      → (4, 3) + (1, 3) → OK  → (4, 3)
(4, 3) + (4, 1)    → OK  → (4, 3)
(3, 1) + (1, 4)    → OK  → (3, 4)
(4, 3) + (2,)      → (4, 3) + (1, 2) → 3 vs 2 → ERROR
(2, 3, 4) + (3, 1) → (2, 3, 4) + (1, 3, 1) → OK → (2, 3, 4)

Resumen clave

ReglaDescripción
Regla 1Si el número de dimensiones es diferente, se añade un 1 al lado con la dimensión más pequeña.
Regla 2Las dimensiones con tamaño 1 se expanden según su escala relativa.
Regla 3Si los tamaños son diferentes y ninguno de los lados es 1, se produce un error.

El broadcasting es una de las funciones más potentes de NumPy. Permite realizar normalización de datos, cálculo de distancias y transformaciones de matrices en una sola línea, sin necesidad de bucles for. La clave está en observar la forma (shape) y determinar inmediatamente si "se alinea desde la derecha; está bien si es igual o 1".

El mismo principio se aplica en pandas. Las operaciones DataFrame - Series se difunden a lo largo de las columnas. Comprender el broadcasting de NumPy facilita la comprensión natural de las operaciones vectoriales en pandas.

python
import pandas as pd
df = pd.DataFrame({"A": [10, 20, 30], "B": [40, 50, 60]})
means = df.mean() # Series: A=20, B=50
centered = df - means # ¡broadcasting! Resta la media de cada columna
print(centered)
# A B
# 0 -10.0 -10.0
# 1 0.0 0.0
# 2 10.0 10.0

💬 Preguntas y comentarios

0 comentarios

Puedes publicar sin iniciar sesión. Los comentarios de invitados no pueden editarse ni eliminarse después.

0/2000

Cargando...