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.
1. O que Você Aprenderá
- ❶ Por que as listas Python têm dificuldades com computação numérica
- ❷ Vantagens centrais do NumPy (velocidade / memória / broadcasting)
- ❸ Principais diferenças entre ndarray e lista Python
- ❹ Visão geral do ecossistema NumPy
- ❺ Instalando o NumPy e executando seu primeiro programa
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
> **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 ⭐)
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
> **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
> **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 ⭐⭐)
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
> **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:
- Por baixo dos panos está C: As operações centrais do NumPy são implementadas em C/Fortran, contornando a sobrecarga por linha do interpretador Python
- Memória contígua: Os elementos do ndarray são empacotados de forma contígua na memória, alcançando altas taxas de acerto do cache da CPU
- Vetorização: Uma única instrução processa o array inteiro de uma vez, sem necessidade de loop no nível Python
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.
# 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
> **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 é:
- Homogêneo: todos os elementos compartilham o mesmo tipo (ex.: todos
float64) - Tamanho fixo: o tamanho do elemento é fixo, sem necessidade de empacotamento
- Contíguo: os elementos são empacotados de forma contígua na memória, sem indireção de ponteiros
- Multidimensional: suporta dados 1D, 2D e até N-dimensionais
(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
> **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 ⭐)
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
> **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
> **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 ⭐⭐)
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]]
> **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:
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
> **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 usarconda install numpy.
▶ Exemplo
> **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 ⭐)
# Instalar
pip install numpy
# Verificar
python -c "import numpy as np; print(np.__version__)"
# Saída (exemplo): 2.1.0
> **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
> **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 ⭐)
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
> **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
> **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 ⭐)
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
> **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
> **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 ⭐⭐⭐)
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
> **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
arrayintegrado 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
- Listas Python têm dois pontos problemáticos para computação numérica: alta sobrecarga de interpretação de loops e grande memória por elemento (objetos completos)
- NumPy alcança ~160x de aceleração em 1 milhão de pontos de dados através de implementação em C + memória contígua + vetorização
- ndarray é um array multidimensional homogêneo, de tamanho fixo e contíguo, usando cerca de 6x menos memória que listas Python
- Broadcasting permite que arrays de formatos diferentes operem juntos diretamente — o código é a fórmula
- NumPy é a base do ecossistema de computação científica Python: Pandas, Scikit-learn, SciPy, TensorFlow e muitos outros dependem dele
- Instale com
pip install numpy, crie arrays comnp.array(), verifique a configuração comnp.show_config()
📝 Exercícios
-
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. -
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. -
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.