Multiplicacao de Matrizes NumPy: Guia Completo de np.dot, matmul e @
Updated on
A multiplicacao de matrizes e fundamental para aprendizado de maquina, computacao grafica, processamento de sinais e computacao cientifica. Mas o NumPy oferece tres formas de multiplicar matrizes -- np.dot(), np.matmul() e o operador @ -- e as diferencas entre eles sao confusas. Usar o errado pode silenciosamente produzir resultados incorretos, especialmente ao trabalhar com arrays de dimensoes diferentes ou quando voce confunde multiplicacao elemento a elemento (*) com multiplicacao de matrizes.
Este guia esclarece cada metodo, mostra quando usar qual e fornece exemplos praticos para cada padrao comum de algebra linear.
Multiplicacao elemento a elemento vs matricial
Primeiro, a distincao critica. O operador * realiza multiplicacao elemento a elemento, NAO multiplicacao de matrizes:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# Multiplicacao elemento a elemento (produto de Hadamard)
print(A * B)
# [[ 5 12]
# [21 32]]
# Multiplicacao de matrizes
print(A @ B)
# [[19 22]
# [43 50]]A multiplicacao de matrizes segue a regra: C[i,j] = sum(A[i,k] * B[k,j]) para todo k.
O operador @ (recomendado)
O operador @ (introduzido no Python 3.5) e a forma mais limpa e legivel de fazer multiplicacao de matrizes:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
C = A @ B
print(C)
# [[19 22]
# [43 50]]Regras de forma
Para a multiplicacao de matrizes A @ B funcionar, o numero de colunas de A deve ser igual ao numero de linhas de B:
import numpy as np
# (2, 3) @ (3, 4) = (2, 4)
A = np.ones((2, 3))
B = np.ones((3, 4))
C = A @ B
print(C.shape) # (2, 4)
# (5, 3) @ (3, 2) = (5, 2)
A = np.random.randn(5, 3)
B = np.random.randn(3, 2)
C = A @ B
print(C.shape) # (5, 2)
# Incompatibilidade gera ValueError
# np.ones((2, 3)) @ np.ones((4, 2)) # ValueErrornp.matmul()
np.matmul() faz exatamente o que @ faz. Sao equivalentes para todos os propositos praticos:
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
# Estes produzem resultados identicos
result1 = A @ B
result2 = np.matmul(A, B)
print(np.array_equal(result1, result2)) # TrueUse @ para codigo mais limpo. Use np.matmul() quando precisar passa-lo como argumento de funcao (ex. para reduce).
np.dot()
np.dot() e mais antigo e se comporta diferente de @/matmul para arrays de dimensao superior:
import numpy as np
# Para arrays 1D: produto escalar (resultado escalar)
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
print(np.dot(a, b)) # 32 (1*4 + 2*5 + 3*6)
# Para arrays 2D: multiplicacao de matrizes (igual a @)
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(np.dot(A, B))
# [[19 22]
# [43 50]]Diferenca chave: Dimensoes superiores
Para arrays com mais de 2 dimensoes, np.dot() e @ se comportam diferente:
import numpy as np
A = np.random.randn(2, 3, 4)
B = np.random.randn(2, 4, 5)
# @ trata como lote de multiplicacoes de matrizes: (2, 3, 4) @ (2, 4, 5) = (2, 3, 5)
result_matmul = A @ B
print(result_matmul.shape) # (2, 3, 5)
# np.dot usa broadcasting diferente: soma sobre o ultimo eixo de A e penultimo de B
result_dot = np.dot(A, B)
print(result_dot.shape) # (2, 3, 2, 5) -- forma diferente!Recomendacao: Use @ ou np.matmul() para multiplicacao de matrizes. Use np.dot() apenas para produtos escalares explicitos de vetores 1D.
Comparacao de metodos
| Caracteristica | Operador @ | np.matmul() | np.dot() | Operador * |
|---|---|---|---|---|
| Operacao | Multiplicacao matricial | Multiplicacao matricial | Produto escalar | Elemento a elemento |
| 1D x 1D | Produto escalar | Produto escalar | Produto escalar | Elemento a elemento |
| 2D x 2D | Multiplicacao matricial | Multiplicacao matricial | Multiplicacao matricial | Elemento a elemento |
| N-D em lotes | Matmul em lotes | Matmul em lotes | Semantica diferente | Elemento a elemento |
| Legibilidade | Melhor | Boa | OK | N/A |
| Escalares permitidos | Nao | Nao | Sim | Sim |
| Recomendado | Sim | Sim (funcional) | So para ponto 1D | Para Hadamard |
Produto escalar (vetores)
O produto escalar de dois vetores e a soma de seus produtos elemento a elemento:
import numpy as np
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
# Todos equivalentes para vetores 1D
print(np.dot(a, b)) # 32
print(a @ b) # 32
print(np.sum(a * b)) # 32Aplicacoes
import numpy as np
# Similaridade do cosseno
def cosine_similarity(a, b):
return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b))
vec1 = np.array([1, 2, 3])
vec2 = np.array([4, 5, 6])
print(f"Cosine similarity: {cosine_similarity(vec1, vec2):.4f}")
# 0.9746
# Projecao de a em b
def project(a, b):
return (np.dot(a, b) / np.dot(b, b)) * b
print(project(np.array([3, 4]), np.array([1, 0])))
# [3. 0.]Multiplicacao matriz-vetor
import numpy as np
# Transformacao linear
A = np.array([[2, 0], [0, 3]]) # Matriz de escala
v = np.array([1, 1])
result = A @ v
print(result) # [2 3]
# Aplicar pesos em uma camada de rede neural
weights = np.random.randn(10, 5) # 10 saidas, 5 entradas
inputs = np.random.randn(5)
output = weights @ inputs
print(output.shape) # (10,)Multiplicacao de matrizes em lote
Para deep learning e processamento em lote, @ trata lotes automaticamente:
import numpy as np
# Lote de 32 matrizes, cada 4x3, vezes lote de 32 matrizes, cada 3x5
batch_A = np.random.randn(32, 4, 3)
batch_B = np.random.randn(32, 3, 5)
result = batch_A @ batch_B
print(result.shape) # (32, 4, 5)Exemplos praticos
Sistema de equacoes lineares
import numpy as np
# Resolver Ax = b
# 2x + 3y = 8
# 4x + y = 10
A = np.array([[2, 3], [4, 1]])
b = np.array([8, 10])
x = np.linalg.solve(A, b)
print(f"x = {x[0]:.2f}, y = {x[1]:.2f}")
# x = 2.20, y = 1.20
# Verificar: A @ x deve ser igual a b
print(A @ x) # [8. 10.]Passagem direta de rede neural simples
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
# Rede: 3 entradas -> 4 ocultas -> 2 saidas
np.random.seed(42)
W1 = np.random.randn(4, 3) * 0.5 # Pesos primeira camada
b1 = np.zeros(4)
W2 = np.random.randn(2, 4) * 0.5 # Pesos segunda camada
b2 = np.zeros(2)
# Passagem direta
X = np.array([1.0, 0.5, -1.0]) # Entrada
h = sigmoid(W1 @ X + b1) # Camada oculta
y = sigmoid(W2 @ h + b2) # Camada de saida
print(f"Input: {X}")
print(f"Hidden: {h}")
print(f"Output: {y}")Projecao PCA
import numpy as np
# Gerar dados de exemplo
np.random.seed(42)
data = np.random.randn(100, 5) # 100 amostras, 5 caracteristicas
# Centralizar dados
data_centered = data - data.mean(axis=0)
# Calcular matriz de covariancia usando multiplicacao de matrizes
cov = (data_centered.T @ data_centered) / (len(data) - 1)
# Decomposicao em autovalores
eigenvalues, eigenvectors = np.linalg.eigh(cov)
# Projetar nos 2 componentes principais
top_2 = eigenvectors[:, -2:] # Ultimos 2 (maiores autovalores)
projected = data_centered @ top_2
print(f"Original shape: {data.shape}")
print(f"Projected shape: {projected.shape}") # (100, 2)Visualizar operacoes matriciais
Para explorar os efeitos de transformacoes matriciais em dados, PyGWalker (opens in a new tab) permite visualizar dados projetados interativamente no Jupyter:
import pandas as pd
import pygwalker as pyg
df = pd.DataFrame(projected, columns=['PC1', 'PC2'])
walker = pyg.walk(df)FAQ
Qual e a diferenca entre np.dot e np.matmul?
Para arrays 1D e 2D, produzem o mesmo resultado. A diferenca chave e com arrays de dimensao superior: np.matmul() (e @) os trata como lotes de matrizes, enquanto np.dot() usa uma regra de broadcasting diferente. Para codigo novo, prefira @ ou np.matmul().
O que o operador @ faz no NumPy?
O operador @ realiza multiplicacao de matrizes, equivalente a np.matmul(). Foi introduzido no Python 3.5. Para arrays 2D, A @ B calcula o produto matricial padrao. Para arrays de dimensao superior, realiza multiplicacao de matrizes em lote.
Por que A * B da resultados diferentes de A @ B?
A * B realiza multiplicacao elemento a elemento (produto de Hadamard), multiplicando elementos correspondentes. A @ B realiza multiplicacao de matrizes, seguindo a regra C[i,j] = sum(A[i,k] * B[k,j]). Sao operacoes fundamentalmente diferentes.
Como calculo o produto escalar de dois vetores no NumPy?
Para arrays 1D (vetores), use np.dot(a, b), a @ b ou np.sum(a * b). Todos retornam o mesmo resultado escalar: a soma dos produtos elemento a elemento.
Quais formas sao necessarias para multiplicacao de matrizes?
Para A @ B, a ultima dimensao de A deve ser igual a penultima dimensao de B. Para 2D: (m, n) @ (n, p) = (m, p). O numero de colunas de A deve ser igual ao numero de linhas de B.
Conclusao
Para multiplicacao de matrizes no NumPy, use o operador @ como padrao -- e o mais legivel e trata operacoes em lote corretamente. Use np.dot() apenas para produtos escalares explicitos de vetores 1D. Nunca confunda * (elemento a elemento) com @ (multiplicacao de matrizes). Lembre-se da regra de forma: (m, n) @ (n, p) = (m, p), e voce evitara os erros mais comuns de multiplicacao de matrizes.