Fundamentos da Manipulação de Arrays NumPy

NumPyBeginner
Pratique Agora

Introdução

Neste laboratório, você explorará os conceitos fundamentais da manipulação de arrays NumPy, focando especificamente na distinção entre cópias (copies) e visualizações (views). Compreender essa diferença é crucial para escrever código numérico eficiente e livre de erros em Python. Você escreverá e executará scripts Python para ver esses conceitos em ação.

Este é um Lab Guiado, que fornece instruções passo a passo para ajudá-lo a aprender e praticar. Siga as instruções cuidadosamente para completar cada etapa e ganhar experiência prática. Dados históricos mostram que este é um laboratório de nível iniciante com uma taxa de conclusão de 96%. Recebeu uma taxa de avaliações positivas de 97% dos estudantes.

A Diferença Entre uma Cópia e uma Visualização (View)

Em NumPy, uma cópia é um array totalmente novo com seus próprios dados, enquanto uma visualização (view) é uma nova maneira de olhar para os mesmos dados. Modificar uma visualização afetará o array original, mas modificar uma cópia não.

Vamos ver isso na prática. Criaremos um array, depois faremos uma visualização e uma cópia dele. Em seguida, modificaremos ambos e observaremos o efeito no array original.

Primeiro, abra o arquivo main.py no explorador de arquivos à esquerda. Em seguida, substitua seu conteúdo pelo seguinte código:

import numpy as np

## --- Parte 1: Modificando uma Visualização ---
print("--- Modificando uma Visualização ---")
## Cria um array original
original_array_view = np.array([1, 2, 3, 4, 5])
print(f"Array original: {original_array_view}")

## Cria uma visualização do array
view_array = original_array_view.view()
## Modifica o primeiro elemento da visualização
view_array[0] = 99
print(f"Visualização após modificação: {view_array}")
print(f"Array original após modificar a visualização: {original_array_view}\n")


## --- Parte 2: Modificando uma Cópia ---
print("--- Modificando uma Cópia ---")
## Cria outro array original
original_array_copy = np.array([10, 20, 30, 40, 50])
print(f"Array original: {original_array_copy}")

## Cria uma cópia do array
copy_array = original_array_copy.copy()
## Modifica o primeiro elemento da cópia
copy_array[0] = 999
print(f"Cópia após modificação: {copy_array}")
print(f"Array original após modificar a cópia: {original_array_copy}")

Agora, salve o arquivo e execute-o no terminal para ver a saída.

python main.py

Você deverá ver a seguinte saída. Observe como o array original mudou quando sua visualização foi modificada, mas permaneceu inalterado quando sua cópia foi modificada.

--- Modificando uma Visualização ---
Array original: [1 2 3 4 5]
Visualização após modificação: [99  2  3  4  5]
Array original após modificar a visualização: [99  2  3  4  5]

--- Modificando uma Cópia ---
Array original: [10 20 30 40 50]
Cópia após modificação: [999  20  30  40  50]
Array original após modificar a cópia: [10 20 30 40 50]

Isso demonstra a diferença principal: uma visualização está ligada aos dados originais, enquanto uma cópia é completamente independente.

Fatiamento de um Array - Criando uma Visualização (View)

Uma operação muito comum em NumPy é o fatiamento (slicing), que é usado para selecionar um intervalo de elementos de um array. O fatiamento básico sempre cria uma visualização (view) do array original. Esta é uma característica fundamental para a eficiência de memória, mas você deve estar ciente de que modificar a fatia alterará os dados originais.

Vamos testar isso. Limpe o conteúdo de main.py e adicione o seguinte código:

import numpy as np

## Cria um array de 0 a 9
original_array = np.arange(10)
print(f"Array original: {original_array}")

## Cria uma fatia do array (elementos do índice 2 ao 4)
array_slice = original_array[2:5]
print(f"Fatia do array: {array_slice}")

## Modifica o primeiro elemento da fatia
print("Modificando o primeiro elemento da fatia para 100...")
array_slice[0] = 100

## Imprime o array original novamente para ver a mudança
print(f"Array original após modificação: {original_array}")

Salve o arquivo e execute-o no terminal.

python main.py

Sua saída será:

Array original: [0 1 2 3 4 5 6 7 8 9]
Fatia do array: [2 3 4]
Modificando o primeiro elemento da fatia para 100...
Array original após modificação: [  0   1 100   3   4   5   6   7   8   9]

Como você pode ver, alterar array_slice[0] também alterou original_array[2]. Isso confirma que a fatia era uma visualização (view), não uma cópia.

Indexação Avançada - Criando uma Cópia

Enquanto o fatiamento básico cria visualizações (views), a indexação avançada sempre cria uma cópia. A indexação avançada envolve passar uma lista, tupla ou outro array de índices para selecionar elementos. Como os elementos selecionados podem não estar em um bloco contíguo de memória, o NumPy cria um novo array (uma cópia) para contê-los.

Vamos contrastar isso com o passo anterior. Limpe main.py e insira este código:

import numpy as np

## Cria um array de 0 a 9
original_array = np.arange(10)
print(f"Array original: {original_array}")

## Usa indexação avançada para selecionar elementos nos índices 1, 3 e 5
indexed_array = original_array[[1, 3, 5]]
print(f"Array indexado: {indexed_array}")

## Modifica o primeiro elemento do novo array
print("Modificando o primeiro elemento do array indexado para 100...")
indexed_array[0] = 100

## Imprime o array original novamente para ver se ele mudou
print(f"Array original após modificação: {original_array}")

Salve o arquivo e execute o script.

python main.py

A saída será:

Array original: [0 1 2 3 4 5 6 7 8 9]
Array indexado: [1 3 5]
Modificando o primeiro elemento do array indexado para 100...
Array original após modificação: [0 1 2 3 4 5 6 7 8 9]

Desta vez, o array original permanece inalterado. O indexed_array era uma cópia, portanto, as modificações nele não afetaram o original_array.

Identificando Cópias e Visualizações com .base

Às vezes, não é óbvio se uma operação retornou uma visualização (view) ou uma cópia. O NumPy fornece uma maneira confiável de verificar: o atributo .base de um array.

  • Se um array é uma visualização (view), seu atributo .base apontará para o objeto array original ao qual pertence.
  • Se um array é uma cópia, seu atributo .base será None.

Vamos usar isso para confirmar nossas descobertas dos passos anteriores. Limpe main.py e adicione o seguinte código:

import numpy as np

## Cria um array original
original_array = np.arange(10)
print(f"Array original: {original_array}\n")

## Cria uma visualização (view) usando fatiamento
view_slice = original_array[2:5]
print(f"Fatia (view): {view_slice}")
## Verifica se a fatia é uma visualização do array original
print(f"A fatia é uma view? {view_slice.base is original_array}\n")

## Cria uma cópia usando indexação avançada
copy_indexed = original_array[[1, 3, 5]]
print(f"Indexado (cópia): {copy_indexed}")
## Verifica se o array indexado é uma cópia
print(f"O array indexado é uma cópia? {copy_indexed.base is None}")

Salve o arquivo e execute-o no terminal.

python main.py

Você obterá a seguinte saída, que confirma programaticamente que a fatia é uma visualização (view) e o array indexado é uma cópia.

Array original: [0 1 2 3 4 5 6 7 8 9]

Fatia (view): [2 3 4]
A fatia é uma view? True

Indexado (cópia): [1 3 5]
O array indexado é uma cópia? True

O atributo .base é uma ferramenta inestimável para depuração e para garantir que seu código se comporte como esperado.

Resumo

Neste laboratório, você aprendeu a diferença crítica entre uma cópia e uma visualização (view) de um array NumPy. Você praticou a criação de ambos e observou como as modificações afetam os dados originais.

  • Você aprendeu que métodos como .view() e o fatiamento básico criam visualizações (views), que são eficientes em termos de memória, mas podem levar a efeitos colaterais indesejados se modificadas.
  • Você aprendeu que métodos como .copy() e a indexação avançada criam cópias, que são independentes do array original.
  • Finalmente, você aprendeu a usar o atributo .base para verificar definitivamente se um array é uma visualização (view) ou uma cópia.

Dominar esses conceitos é um passo fundamental para escrever aplicações numéricas robustas e eficientes com NumPy.