Skip to content

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))  # ValueError

np.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))  # True

Use @ 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

CaracteristicaOperador @np.matmul()np.dot()Operador *
OperacaoMultiplicacao matricialMultiplicacao matricialProduto escalarElemento a elemento
1D x 1DProduto escalarProduto escalarProduto escalarElemento a elemento
2D x 2DMultiplicacao matricialMultiplicacao matricialMultiplicacao matricialElemento a elemento
N-D em lotesMatmul em lotesMatmul em lotesSemantica diferenteElemento a elemento
LegibilidadeMelhorBoaOKN/A
Escalares permitidosNaoNaoSimSim
RecomendadoSimSim (funcional)So para ponto 1DPara 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))    # 32

Aplicacoes

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.

📚