NumPy: Introdução ao NumPy

NumPy é a base da computação científica em Python. Seja você fazendo aprendizado de máquina, análise de dados ou simulação de engenharia, quase todas as bibliotecas numéricas são construídas sobre o NumPy. Este capítulo começa com os problemas de desempenho das listas Python e revela como o NumPy alcança uma aceleração de 160x — seu primeiro passo na computação numérica.

⚠️ Nota: O código abaixo precisa ser executado em um ambiente Python local.

1. O que Você Aprenderá



2. Jornada de Aceleração com Dados de Nível Milhão

(1) O Problema: O Loop de Lista da Alice

Alice é uma analista de dados que precisa elevar ao quadrado 1 milhão de números aleatórios. Ela escreve o código Python mais "natural" — um loop for processando os elementos da lista um por um.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Elevando uma lista ao quadrado (Dificuldade ⭐)

PYTHON
import time
import random

size = 1_000_000  # 1 milhão de números
data = [random.random() for _ in range(size)]

start = time.time()
result = [x * x for x in data]
elapsed = time.time() - start

print(f"List comprehension: {elapsed:.4f} seconds")
# Saída típica: List comprehension: 0.8000 seconds
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

O código da Alice roda em cerca de 0,8 segundos. Isso não parece ruim — até que ela precise fazer a mesma operação em centenas de milhões de pontos de dados, onde a espera se torna insuportível.

(2) A Solução: Vetorização do NumPy pelo Bob

Bob muda apenas duas linhas: substituindo a lista por np.array e o loop por uma única multiplicação vetorizada.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Elevando ao quadrado com NumPy (Dificuldade ⭐⭐)

PYTHON
import time
import numpy as np

size = 1_000_000  # 1 milhão de números
data = np.random.random(size)

start = time.time()
result = data * data  # operação vetorizada
elapsed = time.time() - start

print(f"NumPy vectorized: {elapsed:.4f} seconds")
# Saída típica: NumPy vectorized: 0.0050 seconds
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

Os mesmos 1 milhão de números levam apenas cerca de 5 milissegundos com NumPy — aproximadamente 160x mais rápido.

(3) O Resultado: O Que Torna Isso 160x Mais Rápido

A velocidade do NumPy não se trata de "Python ser mais rápido" — trata-se de descarregar a computação para C e usar memória contígua:

Esta é a filosofia central do NumPy — a conveniência do Python com a velocidade do C.



3. Por Que as Listas Python Têm Dificuldades com Números

(1) Sobrecarga de Loop: Execução Interpretada

Python é tipado dinamicamente. Cada iteração do loop passa por: verificação de tipo → busca de método → executar operação → empacotar o resultado. Para trabalho numérico, esses passos extras são puro desperdício.

PYTHON
# Cada iteração: verificação de tipo + busca de método + empacotamento
result = []
for x in data:          # Sobrecarga do loop Python por iteração
    result.append(x * x)  # verificação de tipo, despacho de método, empacotamento do resultado
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

Comparado ao código de máquina C compilado, uma única iteração de loop Python pode ser dezenas de vezes mais cara que a multiplicação real.

(2) Sobrecarga de Tipo: Cada Elemento É um Objeto Completo

Uma lista Python não armazena números brutos — ela armazena ponteiros PyObject. O inteiro 42 ocupa 28 bytes em Python, mas apenas 4 bytes em C.



4. Vantagens Centrais do NumPy

(1) O Que É ndarray

ndarray (array N-dimensional) é a estrutura de dados central do NumPy. Ele é:

(2) ndarray vs Lista Python

Característica Lista Python NumPy ndarray
Tipo de elemento Qualquer mistura Homogêneo (dtype único)
Layout de memória Array de ponteiros, elementos espalhados Bloco de memória contíguo
Memória de um int único 28 bytes (PyObject) 8 bytes (int64)
Operações em massa List comprehension / loop for Vetorizadas, instrução única
Broadcasting Não suportado Expansão automática de dimensões
Fatia view Retorna uma cópia Retorna uma view por padrão (zero-copy)
Multidimensional Listas aninhadas (irregulares) N-dimensões nativas, atributo shape
Por baixo dos panos Interpretador CPython Código compilado em C / Fortran

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Comparação de memória (Dificuldade ⭐)

PYTHON
import sys
import numpy as np

size = 1_000_000  # 1 milhão de inteiros

# Lista Python
py_list = list(range(size))
list_bytes = sys.getsizeof(py_list) + sum(sys.getsizeof(x) for x in py_list[:1000]) * size // 1000
print(f"Python list: ~{list_bytes / 1024 / 1024:.1f} MB")

# NumPy ndarray
np_array = np.arange(size, dtype=np.int64)
array_bytes = np_array.nbytes
print(f"NumPy ndarray: {array_bytes / 1024 / 1024:.1f} MB")

print(f"Ratio: {list_bytes / array_bytes:.1f}x more memory for list")
# Saída típica:
# Python list: ~44.7 MB
# NumPy ndarray: 7.6 MB
# Ratio: 5.9x more memory for list
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

Um ndarray int64 simples usa cerca de 6x menos memória que uma lista Python do mesmo tamanho — porque o ndarray armazena valores brutos, não objetos Python completos.

(3) Uma Primeira Olhada no Broadcasting

"Broadcasting" permite que arrays de formatos diferentes operem juntos diretamente, sem expandir dimensões manualmente.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Operações de array vs list comprehension (Dificuldade ⭐⭐)

PYTHON
import numpy as np

# Tarefa: adicionar 100 a cada elemento e multiplicar por 2
data = [1, 2, 3, 4, 5]

# --- Lista Python ---
result_list = [(x + 100) * 2 for x in data]
print(result_list)
# [202, 204, 206, 208, 210]

# --- NumPy ndarray ---
arr = np.array(data)
result_np = (arr + 100) * 2  # broadcasting + vetorização
print(result_np)
# [202 204 206 208 210]

# Com um array 2D e um array 1D
matrix = np.array([[1, 2, 3],
                   [4, 5, 6]])
row = np.array([10, 20, 30])
print(matrix + row)
# [[11 22 33]
#  [14 25 36]]
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

Uma list comprehension precisa detalhar a lógica do loop; NumPy precisa apenas de uma expressão matemática — o código é a fórmula.



5. Visão Geral do Ecossistema NumPy

(1) O Ecossistema NumPy

NumPy é a base de todo o ecossistema de computação científica Python. Quase todas as bibliotecas principais dependem dele:

100%
mindmap
  root((Ecossistema NumPy))
    Ciência de Dados
      Pandas
      Polars
    Aprendizado de Máquina
      Scikit-learn
      TensorFlow
      PyTorch
    Computação Científica
      SciPy
      Matplotlib
      SymPy
    Frameworks de Aprendizado Profundo
      Keras
      JAX
      MXNet
    Domínios Especializados
      scikit-image
      NetworkX
      AstroPy
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

(2) Tabela de Referência do Ecossistema

Biblioteca Domínio Por Que Depende do NumPy
Pandas Análise de dados DataFrame armazena dados de coluna como ndarray por baixo dos panos
Scikit-learn Aprendizado de máquina Entradas e saídas dos modelos são ndarray
SciPy Computação científica Fornece álgebra linear / otimização / integração sobre ndarray
Matplotlib Visualização Fontes de dados dos gráficos são ndarray
TensorFlow Aprendizado profundo Conceito de Tensor origina-se do ndarray, conversível
PyTorch Aprendizado profundo Tensor e ndarray são intercambiáveis
Polars Análise de dados Armazenamento colunar, ainda compatível com NumPy

(3) Quando Usar NumPy vs Python Puro

Cenário Python Puro NumPy Recomendação
Algumas dezenas de operações simples Suficiente Um pouco mais rápido Python Puro
10K+ operações em massa Lento 10~100x mais rápido NumPy
Multiplicação de matrizes Loops aninhados, muito lento Com BLAS, muito rápido NumPy
Resolver equações lineares Impraticável escrever manualmente np.linalg.solve NumPy
Processamento de strings Flexível Não é seu ponto forte Python Puro
Dados de tipos mistos Listas lidam naturalmente Requer arrays estruturados Depende


6. Instalação e Seu Primeiro Programa

(1) Métodos de Instalação

Método Comando Quando Usar
pip pip install numpy Geral, mais simples
conda conda install numpy Ambientes Anaconda / Miniconda
Pacote do sistema apt install python3-numpy Instalação system-wide no Linux
A partir do fonte python setup.py build Backend BLAS personalizado necessário

Iniciantes devem usar pip install numpy. Usuários Anaconda podem usar conda install numpy.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Verificar instalação (Dificuldade ⭐)

BASH
# Instalar
pip install numpy

# Verificar
python -c "import numpy as np; print(np.__version__)"
# Saída (exemplo): 2.1.0
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

(2) Criando Seu Primeiro ndarray

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Criando arrays com np.array (Dificuldade ⭐)

PYTHON
import numpy as np

# A partir de uma lista Python
a = np.array([1, 2, 3, 4, 5])
print(type(a))   # <class 'numpy.ndarray'>
print(a.dtype)   # int64
print(a.shape)   # (5,)

# A partir de lista aninhada (2D)
b = np.array([[1, 2, 3],
              [4, 5, 6]])
print(b.shape)   # (2, 3)
print(b.ndim)    # 2

# Especificar dtype explicitamente
c = np.array([1, 2, 3], dtype=np.float32)
print(c.dtype)   # float32
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

(3) Verificando Versão e Configuração

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Verificando versão e configuração (Dificuldade ⭐)

PYTHON
import numpy as np

print(f"NumPy version: {np.__version__}")

# Mostrar configuração de build (BLAS, LAPACK, etc.)
np.show_config()
# A saída inclui: informações do backend BLAS, LAPACK,
# que determinam o desempenho da computação
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

O backend BLAS/LAPACK mostrado por np.show_config() determina quão rápido suas operações de matriz NumPy rodam — diferenças de desempenho entre OpenBLAS, MKL e outros backends podem ser de várias vezes.



7. Mão na Massa: Média e Desvio Padrão de 10 Milhões de Números

Computar a média e o desvio padrão de 10 milhões de números de ponto flutuante — uma das tarefas de análise de dados mais comuns. Vamos implementá-la em Python puro e NumPy, comparando tamanho do código, velocidade e memória.

▶ Exemplo

TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.

: Comparação abrangente — lista vs NumPy (Dificuldade ⭐⭐⭐)

PYTHON
import time
import math
import random
import numpy as np
import sys

size = 10_000_000  # 10 milhões

# ========== Python Puro ==========
py_data = [random.random() for _ in range(size)]

t0 = time.time()
mean_py = sum(py_data) / len(py_data)
var_py = sum((x - mean_py) ** 2 for x in py_data) / len(py_data)
std_py = math.sqrt(var_py)
elapsed_py = time.time() - t0

# Estimativa de memória para lista
mem_py = sys.getsizeof(py_data) + size * 24  # ~24 bytes por objeto float

# ========== NumPy ==========
np_data = np.random.random(size)

t0 = time.time()
mean_np = np.mean(np_data)
std_np = np.std(np_data)
elapsed_np = time.time() - t0

# Memória para ndarray
mem_np = np_data.nbytes

# ========== Resultados ==========
print(f"--- Python Puro ---")
print(f"  Média: {mean_py:.6f}  Desvio Padrão: {std_py:.6f}")
print(f"  Tempo: {elapsed_py:.3f}s")
print(f"  Memória: ~{mem_py / 1024 / 1024:.0f} MB")

print(f"--- NumPy ---")
print(f"  Média: {mean_np:.6f}  Desvio Padrão: {std_np:.6f}")
print(f"  Tempo: {elapsed_np:.3f}s")
print(f"  Memória: {mem_np / 1024 / 1024:.1f} MB")

print(f"--- Comparação ---")
print(f"  Aceleração: {elapsed_py / elapsed_np:.1f}x")
print(f"  Economia de memória: {mem_py / mem_np:.1f}x")
# Saída típica:
# --- Python Puro ---
#   Média: 0.500032  Desvio Padrão: 0.288675
#   Tempo: 3.200s
#   Memória: ~305 MB
# --- NumPy ---
#   Média: 0.500032  Desvio Padrão: 0.288675
#   Tempo: 0.030s
#   Memória: 76.3 MB
# --- Comparação ---
#   Aceleração: 106.7x
#   Economia de memória: 4.0x
TEXT 📖 Somente leitura
> **Saída:** Execute NumPy 2.x no seu ambiente Python local para ver a saída do ndarray. O servidor Piston não tem NumPy pré-instalado — instale localmente (`pip install numpy`) e compare. Os valores reais podem variar conforme a versão do NumPy e a semente aleatória.
Métrica Python Puro NumPy Comparação
Linhas de código (lógica central) 4 linhas 2 linhas NumPy usa 50% menos
Tempo de execução ~3,2s ~0,03s ~100x mais rápido
Uso de memória ~305 MB ~76 MB 4x menos

Conclusão: Quanto maiores seus dados, mais o NumPy se destaca. Com 10 milhões de pontos de dados, NumPy supera o Python puro em velocidade e memória.



❓ Perguntas Frequentes

P: Como o NumPy se relaciona com Python? R: NumPy é uma biblioteca de terceiros, não parte da biblioteca padrão Python. Seu mecanismo de computação central é escrito em C e exposto através de uma interface Python, dando a você velocidades próximas do C a partir do Python.

P: Por que o NumPy é tão mais rápido que as listas? R: Três razões — ① Implementação em nível C contorna a sobrecarga do interpretador Python; ② Layout de memória contígua maximiza a eficiência do cache da CPU; ③ Operações vetorizadas processam o array inteiro em uma instrução, sem loop elemento por elemento.

P: Preciso aprender C para usar o NumPy? R: Não. O objetivo de design do NumPy é permitir que usuários Python desfrutem de velocidade de nível C com sintaxe Python. Você só precisa de C se quiser contribuir com código de baixo nível ou escrever extensões C personalizadas para o NumPy.

P: O NumPy pode substituir o Excel? R: Para computação numérica e processamento em lote, NumPy é muito mais poderoso e eficiente que o Excel. Mas NumPy não oferece uma interface de planilha, gráficos de arrastar e soltar, ou filtragem interativa — você normalmente o combinaria com Pandas (dados tabulares) e Matplotlib (visualização).

P: Qual a diferença entre NumPy 2.x e 1.x? R: NumPy 2.0 (lançado em 2024) melhorou principalmente a estabilidade da API C, adicionou algumas APIs de operação com strings e aprimorou o sistema dtype. Para usuários Python do dia a dia, as mudanças na API são menores — a maioria do código 1.x migra sem problemas. Novos projetos devem usar 2.x.

P: Qual a diferença entre ndarray e o módulo array do Python? R: O módulo array integrado do Python suporta apenas arrays homogêneos 1D sem broadcasting, álgebra linear ou capacidades de FFT. O ndarray do NumPy suporta dados multidimensionais, broadcasting e um conjunto rico de funções matemáticas — estão em categorias completamente diferentes.


📖 Resumo



📝 Exercícios

  1. Básico (Dificuldade ⭐): Instale o NumPy e execute import numpy as np; print(np.__version__). Certifique-se de que a versão seja ≥ 1.24. Registre a saída.

  2. Intermediário (Dificuldade ⭐⭐): Crie uma lista e um ndarray, cada um contendo 5 milhões de números aleatórios. Use list comprehension e vetorização NumPy para computar o quadrado de cada número mais 10. Meça ambas as abordagens com time.time() e compare. Registre a razão de velocidade.

  3. Desafio (Dificuldade ⭐⭐⭐): Execute np.show_config() e identifique o backend BLAS que seu NumPy usa (OpenBLAS / MKL / outro). Pesquise como esse backend afeta o desempenho de operações de matriz e escreva uma breve explicação.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%