Multiplicação de Matrizes em Python: 3 Métodos Simples e Eficientes!

Multiplicação de Matrizes em Python: Um Guia Completo

Neste guia, você explorará detalhadamente a multiplicação de matrizes utilizando Python. Abordaremos desde os fundamentos teóricos até a implementação prática, garantindo um aprendizado completo e eficaz.

Inicialmente, você compreenderá a condição essencial para que a multiplicação de matrizes seja considerada válida, e então, desenvolverá uma função personalizada em Python para realizar essa operação. Em seguida, exploraremos como alcançar o mesmo resultado através de compreensões de lista aninhadas.

Por fim, você avançará para o uso do NumPy, uma biblioteca poderosa, e suas funções integradas, que oferecem uma forma otimizada e eficiente de efetuar a multiplicação de matrizes.

Verificando a Validade da Multiplicação de Matrizes

Antes de mergulharmos no código Python, vamos recordar os princípios básicos que regem a multiplicação de matrizes.

A multiplicação de duas matrizes, digamos A e B, é considerada válida somente se o número de colunas da matriz A coincidir com o número de linhas da matriz B.

Você já deve ter se deparado com essa regra anteriormente. Mas, você já se questionou sobre a razão por trás dessa condição?

A resposta reside na própria mecânica da multiplicação de matrizes. Observe a ilustração a seguir:

Neste cenário genérico, a matriz A possui m linhas e n colunas, enquanto a matriz B tem n linhas e p colunas.

Qual a Dimensão da Matriz Resultante?

O elemento localizado no índice (i, j) da matriz resultante C é, na verdade, o produto escalar entre a linha i da matriz A e a coluna j da matriz B.

Portanto, para obter um elemento específico na matriz resultante C, é necessário calcular o produto escalar da linha e coluna correspondentes das matrizes A e B.

Ao repetir este processo, você obterá a matriz produto C com dimensões mxp, ou seja, com m linhas e p colunas, como demonstrado a seguir.

O produto escalar, ou produto interno, entre dois vetores, a e b, é expresso pela seguinte equação:

Vamos recapitular os pontos principais:

  • É fundamental notar que o produto escalar só é definido entre vetores com o mesmo comprimento.
  • Consequentemente, para que o produto escalar entre uma linha e uma coluna seja válido durante a multiplicação de matrizes, ambas devem ter a mesma quantidade de elementos.
  • No exemplo genérico apresentado, cada linha da matriz A possui n elementos, assim como cada coluna da matriz B.

Observando mais atentamente, percebemos que n corresponde ao número de colunas da matriz A e, simultaneamente, ao número de linhas da matriz B. Esta é exatamente a razão pela qual o número de colunas da matriz A deve ser idêntico ao número de linhas da matriz B.

Espero que agora você tenha uma compreensão clara da condição necessária para a validação da multiplicação de matrizes, bem como do processo de obtenção de cada elemento da matriz resultante.

Vamos prosseguir com a escrita do código Python para realizar a multiplicação de duas matrizes.

Criando uma Função Personalizada em Python para Multiplicar Matrizes

Inicialmente, desenvolveremos uma função personalizada para efetuar a multiplicação de matrizes.

Esta função deverá realizar as seguintes operações:

  • Receber duas matrizes, A e B, como entradas.
  • Verificar se a multiplicação entre A e B é válida.
  • Caso seja válida, multiplicar as matrizes A e B e retornar a matriz produto C.
  • Caso contrário, retornar uma mensagem de erro indicando que a multiplicação entre A e B não é possível.

Passo 1: Vamos gerar duas matrizes de inteiros utilizando a função random.randint() do NumPy. Alternativamente, você também pode definir matrizes utilizando listas aninhadas em Python.

import numpy as np
np.random.seed(27)
A = np.random.randint(1,10,size = (3,3))
B = np.random.randint(1,10,size = (3,2))
print(f"Matrix A:n {A}n")
print(f"Matrix B:n {B}n")

# Output
Matrix A:
 [[4 9 9]
 [9 1 6]
 [9 2 3]]

Matrix B:
 [[2 2]
 [5 7]
 [4 4]]

Passo 2: Agora, definiremos a função `multiply_matrix(A,B)`. Esta função receberá as matrizes A e B como entradas e retornará a matriz produto C, caso a multiplicação seja possível.

def multiply_matrix(A,B):
  global C
  if  A.shape[1] == B.shape[0]:
    C = np.zeros((A.shape[0],B.shape[1]),dtype = int)
    for row in range(A.shape[0]): 
        for col in range(B.shape[1]):
            for elt in range(A.shape[1]):
              C[row, col] += A[row, elt] * B[elt, col]
    return C
  else:
    return "Desculpe, não é possível multiplicar A e B."

Analisando a Estrutura da Função

Vamos agora detalhar a estrutura da função.

Declarando C como variável global: Em Python, por padrão, todas as variáveis dentro de uma função têm escopo local. Isso significa que não podem ser acessadas fora da função. Para que a matriz produto C seja acessível externamente, precisamos declará-la como uma variável global. Isso é feito através da inclusão do qualificador `global` antes do nome da variável.

Verificando a validade da multiplicação de matrizes: Utilizamos o atributo `shape` para verificar se a multiplicação entre A e B é possível. Para qualquer array `arr`, `arr.shape[0]` e `arr.shape[1]` retornam o número de linhas e colunas, respectivamente. Portanto, `A.shape[1] == B.shape[0]` verifica se a condição para a multiplicação de matrizes é satisfeita. A matriz produto só será calculada caso essa condição seja verdadeira, caso contrário, a função retornará uma mensagem de erro.

Utilizando loops aninhados para realizar os cálculos: Para calcular os elementos da matriz resultante, precisamos iterar sobre as linhas da matriz A, o que é realizado pelo loop `for` externo. O loop interno nos ajuda a percorrer as colunas da matriz B. O loop mais interno é utilizado para acessar cada elemento dentro da coluna selecionada.

▶️ Agora que compreendemos o funcionamento da função em Python para multiplicar matrizes, vamos executá-la com as matrizes A e B que geramos anteriormente.

multiply_matrix(A,B)

# Output
array([[ 89, 107],
       [ 47,  49],
       [ 40,  44]])

Como a multiplicação entre A e B é válida, a função `multiply_matrix()` retorna a matriz produto C.

Multiplicação de Matrizes com Compreensão de Lista Aninhada em Python

Na seção anterior, você aprendeu a criar uma função personalizada para multiplicar matrizes em Python. Agora, exploraremos como usar compreensões de lista aninhadas para alcançar o mesmo objetivo.

A seguir, apresentamos a compreensão de lista aninhada utilizada para multiplicar matrizes:

Inicialmente, isso pode parecer um pouco complexo, mas vamos analisar a compreensão de lista aninhada passo a passo.

Vamos focar em uma compreensão de lista por vez para entender seu funcionamento.

Utilizaremos o seguinte modelo geral para compreensão de lista:

[<do-this> for <item> in <iterable>]

where,
<do-this>: a operação ou expressão que você deseja realizar
<item>: cada item sobre o qual a operação será executada
<iterable>: o iterável (lista, tupla, etc.) que está sendo percorrido

▶️ Consulte nosso guia sobre Compreensão de listas em Python para uma compreensão mais aprofundada.

Antes de prosseguirmos, lembre-se de que nosso objetivo é construir a matriz resultante C linha por linha.

Entendendo a Compreensão de Lista Aninhada

Etapa 1: Calculando um único valor na matriz C

Dada a linha i da matriz A e a coluna j da matriz B, a expressão abaixo fornece o elemento na posição (i, j) da matriz C.

sum(a*b for a,b in zip(A_row, B_col)

# zip(A_row, B_col) retorna um iterador de tuplas
# Se A_row = [a1, a2, a3] & B_col = [b1, b2, b3]
# zip(A_row, B_col) retorna (a1, b1), (a2, b2), e assim por diante

Se i = j = 1, a expressão retornará o elemento c_11 da matriz C. Assim, é possível obter um elemento de uma linha desta forma.

Passo 2: Construindo uma linha na matriz C

Nosso próximo objetivo é construir uma linha completa.

Para a linha 1 da matriz A, é necessário percorrer todas as colunas da matriz B para obter uma linha completa na matriz C.

Retorne ao modelo de compreensão de lista.

  • Substitua <do-this> pela expressão da etapa 1, pois é o cálculo desejado.
  • Substitua <item> por B_col—cada coluna da matriz B.
  • Por fim, substitua <iterable> por zip(*B)—a lista contendo todas as colunas na matriz B.

E aqui está a primeira compreensão de lista:

[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] 

# zip(*B): * é o operador de desempacotamento
# zip(*B) retorna uma lista das colunas da matriz B

Passo 3: Construindo todas as linhas e obtendo a matriz C

Em seguida, preencheremos a matriz produto C calculando as demais linhas.

Para isso, é preciso percorrer todas as linhas da matriz A.

Volte novamente à compreensão de lista e faça o seguinte:

  • Substitua <do-this> pela compreensão de lista da etapa 2. Lembre-se que na etapa anterior calculamos uma linha completa.
  • Agora, substitua <item> por A_row—cada linha da matriz A.
  • E o <iterable> será a própria matriz A, que será percorrida por suas linhas.

E aqui está nossa compreensão de lista aninhada final.🎉

[[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] 
    for A_row in A]

Agora é hora de verificar o resultado! ✔

# Converta para um array NumPy utilizando np.array()
C = np.array([[sum(a*b for a,b in zip(A_row, B_col)) for B_col in zip(*B)] 
    for A_row in A])

# Output:
[[ 89 107]
 [ 47  49]
 [ 40  44]]

Analisando com atenção, vemos que o resultado é equivalente aos loops `for` aninhados que vimos anteriormente, porém de forma mais concisa.

Também é possível realizar essa operação de forma mais eficiente utilizando algumas funções internas. Vamos explorá-las na próxima seção.

Utilizando NumPy matmul() para Multiplicação de Matrizes em Python

A função `np.matmul()` recebe duas matrizes como entrada e retorna o produto, caso a multiplicação entre elas seja válida.

C = np.matmul(A,B)
print(C)

# Output:
[[ 89 107]
 [ 47  49]
 [ 40  44]]

Observe como este método é mais simples e direto do que os dois métodos que aprendemos anteriormente. Na verdade, ao invés de `np.matmul()`, você também pode usar o operador `@` que possui a mesma funcionalidade. Iremos explorar esse operador a seguir.

Como Utilizar o Operador @ em Python para Multiplicar Matrizes

Em Python, o operador `@` é um operador binário que realiza a multiplicação de matrizes.

Ele opera sobre duas matrizes, geralmente arrays NumPy N-dimensionais, e retorna a matriz produto resultante.

Observação: É necessário ter o Python versão 3.5 ou superior para utilizar o operador `@`.

Veja como ele pode ser utilizado:

C = A @ B
print(C)

# Output
array([[ 89, 107],
       [ 47,  49],
       [ 40,  44]])

Note que a matriz produto C é idêntica à que obtivemos anteriormente.

É Possível Utilizar np.dot() para Multiplicar Matrizes?

Caso você já tenha se deparado com algum código que utiliza `np.dot()` para multiplicar matrizes, entenda como ele funciona:

C = np.dot(A,B)
print(C)

# Output:
[[ 89 107]
 [ 47  49]
 [ 40  44]]

Você verá que `np.dot(A, B)` também retorna a matriz produto esperada.

Entretanto, conforme a documentação do NumPy, você deve usar `np.dot()` apenas para calcular o produto escalar de dois vetores unidimensionais e não para a multiplicação de matrizes.

Lembre-se que, conforme discutido anteriormente, o elemento na posição (i, j) da matriz produto C corresponde ao produto escalar da linha i da matriz A e da coluna j da matriz B.

Como o NumPy aplica implicitamente essa operação de produto escalar a todas as linhas e colunas, você obtém a matriz produto resultante. No entanto, para manter a clareza e evitar ambiguidades em seu código, é recomendado utilizar `np.matmul()` ou o operador `@`.

Conclusão

🎯 Neste guia, você aprendeu os seguintes conceitos:

  • A condição para que a multiplicação de matrizes seja válida: o número de colunas da matriz A deve ser igual ao número de linhas da matriz B.
  • Como desenvolver uma função personalizada em Python que verifica a validade da multiplicação de matrizes e retorna a matriz produto. Essa função utiliza loops `for` aninhados.
  • Como utilizar compreensões de lista aninhadas para multiplicar matrizes. Essa abordagem é mais concisa do que o uso de loops `for`, mas pode ser menos legível.
  • Como utilizar a função interna do NumPy `np.matmul()` para multiplicar matrizes, e como essa abordagem é a mais eficiente em termos de desempenho.
  • Você também aprendeu sobre o operador `@` para multiplicar duas matrizes em Python.

Com isso, concluímos nossa análise sobre a multiplicação de matrizes em Python. Como próximos passos, você pode aprender como verificar se um número é primo em Python ou explorar problemas interessantes envolvendo strings em Python.

Bons estudos! 🎉