Machine Learning: Curso Relâmpago de NumPy

Última atualização: 2026-08-26

NumPy é a base da ciência de dados em Python — toda biblioteca importante de ML (Pandas, Scikit-learn, PyTorch) é construída sobre arrays do NumPy.

1. O que você vai aprender


2. A história real de um engenheiro de dados

(1) O problema: listas em Python são lentas demais para milhões de registros

O Bob precisava calcular estatísticas mensais de vendas em 12 meses e 5 categorias de produtos — 60 mil registros. Usar loops com listas nativas do Python para calcular média e desvio padrão levava mais de 30 segundos, e o conjunto de dados da Alice, com 500 mil registros nos EUA, simplesmente travava. Loops nativos do Python são o gargalo do processamento de dados em ML.

(2) A solução do NumPy

O ndarray do NumPy usa blocos contíguos de memória e operações de baixo nível em C, fazendo cálculos vetorizados serem 50–100x mais rápidos do que loops em Python.

PYTHON
import numpy as np

# Loop em lista Python vs vetorização com NumPy
sales_list = list(range(1, 60001))     # 60.000 registros
sales_arr = np.array(sales_list)

# Vetorização com NumPy: 100x mais rápido
mean_val = sales_arr.mean()
std_val = sales_arr.std()
print(f"Média: {mean_val:.2f}, Desvio padrão: {std_val:.2f}")

(3) O resultado: o tempo de computação caiu de 30s para 0,3s

Depois que o Bob migrou seu processamento de dados de loops em Python para vetorização com NumPy, os cálculos estatísticos sobre 60 mil registros caíram de 30 segundos para 0,3 segundo. Os 500 mil registros da Alice também terminam em menos de 1 segundo.


3. Criação de ndarrays e manipulação de shapes

O ndarray é a estrutura de dados central do NumPy — um array multidimensional de elementos do mesmo tipo, armazenado em memória contígua.

(1) Criando arrays

PYTHON
import numpy as np

# A partir de uma lista Python
a = np.array([1, 2, 3, 4, 5])

# Construtores embutidos
zeros = np.zeros((3, 4))        # matriz 3x4 de zeros
ones = np.ones((2, 3))          # matriz 2x3 de uns
range_arr = np.arange(0, 10, 2) # [0, 2, 4, 6, 8]
linspace = np.linspace(0, 1, 5) # [0, 0.25, 0.5, 0.75, 1.0]

print(f"arange: {range_arr}")
print(f"linspace: {linspace}")

▶ Exemplo: Criando a matriz de vendas do SalesPredict

PYTHON
import numpy as np

# Vendas mensais de 5 categorias em 12 meses (em mil USD)
sales = np.array([
    [120, 135, 150, 142, 160, 175, 180, 190, 195, 200, 220, 250],  # Eletrônicos
    [80, 85, 90, 88, 95, 100, 105, 108, 110, 115, 130, 145],       # Roupas
    [50, 48, 55, 60, 58, 62, 65, 68, 70, 72, 80, 90],              # Alimentos
    [30, 35, 40, 38, 42, 45, 48, 50, 52, 55, 60, 70],              # Livros
    [200, 210, 225, 220, 240, 260, 270, 280, 290, 300, 350, 400],  # Casa
])

print(f"Shape: {sales.shape}")
print(f"Receita anual total: {sales.sum() / 1000:.1f} milhões de USD")
print(f"Receita do Q4: {sales[:, 9:].sum() / 1000:.1f} milhões de USD")

Saída:

TEXT 📖 Somente leitura
Shape: (5, 12)
Receita anual total: 6.3 milhões de USD
Receita do Q4: 2.3 milhões de USD

(2) Operações de shape

Operação Método Descrição
Reshape reshape() Altera a view sem modificar os dados
Transpose T ou transpose() Troca linhas e colunas
Flatten flatten() / ravel() Multidimensional → 1D
Adicionar dimensão np.newaxis / expand_dims Adiciona um novo eixo

▶ Exemplo: reshape e transpose

PYTHON
import numpy as np

# Reshape: 1D para 2D
data = np.arange(12)
matrix = data.reshape(3, 4)
print(f"Remodelado para 3x4:\n{matrix}")

# Transpose: trocar linhas e colunas
transposed = matrix.T
print(f"Transposto para 4x3:\n{transposed}")

# -1 significa calcular a dimensão automaticamente
auto_reshape = data.reshape(2, -1)
print(f"Auto reshape (2, -1): shape={auto_reshape.shape}")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

(3) O mecanismo de broadcasting

O broadcasting permite que arrays de shapes diferentes se expandam automaticamente durante operações aritméticas, eliminando a necessidade de copiar dados manualmente.

100%
graph TB
    A[Escalar + Array] --> B["Escalar é broadcast para o shape do array"]
    C["1D + Array 2D"] --> D["1D é broadcast ao longo do eixo 0"]
    E["Shape (3,1) + (1,4)"] --> F["Ambos são broadcast para (3,4)"]

▶ Exemplo: Broadcasting na prática

PYTHON
import numpy as np

# Escalar + array: o escalar é broadcast
prices = np.array([100, 200, 300, 400])
discount = 0.9  # 10% de desconto
print(f"Preços com desconto: {prices * discount}")

# 1D + 2D: a linha é broadcast entre as linhas
monthly_sales = np.array([[100, 200], [110, 210], [120, 220]])  # 3 meses x 2 categorias
growth_rate = np.array([1.05, 1.10])  # crescimento diferente por categoria
print(f"Vendas projetadas:\n{monthly_sales * growth_rate}")

# Broadcast de coluna + linha
col = np.array([[1], [2], [3]])   # shape (3, 1)
row = np.array([10, 20, 30, 40])  # shape (4,)
print(f"Shape do resultado Col + Row: {(col + row).shape}")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

4. Indexação e fatiamento de arrays

(1) Indexação e fatiamento básicos

PYTHON
import numpy as np

arr = np.arange(10)
print(f"arr[3]: {arr[3]}")          # Elemento único
print(f"arr[2:7]: {arr[2:7]}")      # Fatia
print(f"arr[::2]: {arr[::2]}")      # Passo=2

# Indexação 2D
matrix = np.arange(12).reshape(3, 4)
print(f"matrix[1, 2]: {matrix[1, 2]}")       # Linha 1, Coluna 2
print(f"matrix[0, :]: {matrix[0, :]}")       # Linha 0 inteira
print(f"matrix[:, 1]: {matrix[:, 1]}")       # Coluna 1 inteira

(2) Indexação booleana

▶ Exemplo: Filtrando categorias de alto volume de vendas

PYTHON
import numpy as np

# Vendas mensais por categoria (em mil USD)
sales = np.array([250, 145, 90, 70, 400])
categories = np.array(["Eletrônicos", "Roupas", "Alimentos", "Livros", "Casa"])

# Indexação booleana: encontrar categorias acima de 100k
high_sales = sales > 100
print(f"Máscara de alto volume: {high_sales}")
print(f"Categorias de alto volume: {categories[high_sales]}")
print(f"Valores de alto volume: {sales[high_sales]}")

# Condições compostas
mid_range = (sales >= 80) & (sales <= 200)
print(f"Categorias intermediárias: {categories[mid_range]}")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

(3) Indexação fancy

▶ Exemplo: Selecionando meses e categorias específicos

PYTHON
import numpy as np

sales = np.arange(60).reshape(5, 12)  # 5 categorias x 12 meses

# Selecionar meses específicos: Jan, Abr, Jul, Out (índices 0, 3, 6, 9)
quarterly = sales[:, [0, 3, 6, 9]]
print(f"Shape dos dados trimestrais: {quarterly.shape}")

# Selecionar as 3 principais categorias pelo total de vendas
total = sales.sum(axis=1)
top3_idx = np.argsort(total)[-3:]
print(f"Índices das 3 principais categorias: {top3_idx}")
print(f"Vendas totais das 3 principais: {total[top3_idx]}")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso
Método de indexação Sintaxe Dimensões retornadas Caso de uso
Indexação básica arr[2] Reduz a dimensão Acessar um único elemento
Fatiamento arr[1:5] Mesma dimensão Acessar um intervalo contíguo
Indexação booleana arr[mask] 1D Filtragem condicional
Indexação fancy arr[[1,3,5]] Mesma dimensão Acessar posições não contíguas

5. Computação numérica e estatística

(1) Operações vetorizadas

As operações vetorizadas do NumPy substituem loops em Python e são o núcleo da sua vantagem de performance.

▶ Exemplo: Comparação de performance entre vetorização e loop

PYTHON
import numpy as np
import time

size = 1_000_000
a = np.random.rand(size)
b = np.random.rand(size)

# Cálculo vetorizado
start = time.time()
c = a + b
vec_time = time.time() - start

# Loop em Python (lento!)
start = time.time()
c_list = [a[i] + b[i] for i in range(size)]
loop_time = time.time() - start

print(f"Vetorizado: {vec_time:.4f}s")
print(f"Loop: {loop_time:.4f}s")
print(f"Aceleração: {loop_time / vec_time:.0f}x")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

(2) Funções estatísticas

▶ Exemplo: Estatísticas de vendas do SalesPredict

PYTHON
import numpy as np

# Dados de vendas diárias por 30 dias (em mil USD)
daily_sales = np.array([
    45, 52, 48, 61, 55, 72, 68, 50, 53, 49,
    58, 63, 71, 66, 59, 54, 47, 70, 75, 62,
    51, 57, 64, 69, 73, 60, 56, 67, 74, 78
])

print(f"Média: {daily_sales.mean():.1f}k USD")
print(f"Mediana: {np.median(daily_sales):.1f}k USD")
print(f"Desvio padrão: {daily_sales.std():.1f}k USD")
print(f"Mínimo: {daily_sales.min()}k USD")
print(f"Máximo: {daily_sales.max()}k USD")
print(f"Total: {daily_sales.sum()}k USD")

# Soma cumulativa para tendência
cum_sales = daily_sales.cumsum()
print(f"Soma cumulativa no dia 30: {cum_sales[-1]}k USD")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

(3) Operações com matrizes

▶ Exemplo: Cálculo da matriz de ROI de gastos com anúncios

PYTHON
import numpy as np

# Gasto com anúncios por canal (3 canais) x 4 produtos
ad_matrix = np.array([
    [10, 15, 8, 12],   # Google Ads (mil USD)
    [5, 20, 10, 8],    # Facebook Ads
    [3, 7, 15, 10],    # Email Marketing
])

# Matriz de taxa de conversão (canal x produto)
conv_rate = np.array([
    [0.05, 0.03, 0.08, 0.04],
    [0.03, 0.06, 0.04, 0.05],
    [0.10, 0.08, 0.12, 0.09],
])

# Receita por conversão (por produto, em mil USD)
revenue_per_conv = np.array([50, 30, 80, 40])

# Multiplicação de matrizes: conversões esperadas
expected_conv = ad_matrix * conv_rate  # element-wise
# Receita total por produto
total_revenue = expected_conv.sum(axis=0) * revenue_per_conv
print(f"Receita por produto: {total_revenue} mil USD")
print(f"Receita total de ROI: {total_revenue.sum():.1f} mil USD")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso

6. Números aleatórios e álgebra linear

(1) Geração de números aleatórios

PYTHON
import numpy as np

rng = np.random.default_rng(seed=42)  # Reprodutível

# Distribuições comuns
uniform = rng.uniform(0, 100, size=5)    # Uniforme [0, 100)
normal = rng.normal(50, 10, size=5)      # Normal(média=50, desvio=10)
integers = rng.integers(1, 100, size=5)  # Inteiros aleatórios [1, 100)
choice = rng.choice(["A", "B", "C"], size=5)  # Escolha aleatória

print(f"Uniforme: {uniform}")
print(f"Normal: {normal}")
print(f"Inteiros: {integers}")

(2) Álgebra linear

▶ Exemplo: Equação normal da regressão linear

PYTHON
import numpy as np

# Simular: vendas = 50 + 0.8 * gasto_anuncio + ruído
rng = np.random.default_rng(42)
n = 100
ad_spend = rng.uniform(10, 100, n)
noise = rng.normal(0, 5, n)
sales = 50 + 0.8 * ad_spend + noise

# Resolver pela equação normal: w = (X^T X)^-1 X^T y
X = np.column_stack([np.ones(n), ad_spend])  # Adicionar coluna de bias
w = np.linalg.inv(X.T @ X) @ (X.T @ sales)

print(f"Intercepto: {w[0]:.2f}")
print(f"Coeficiente: {w[1]:.2f}")
print(f"Valores verdadeiros: intercepto=50, coef=0.8")

Saída:

TEXT 📖 Somente leitura
# Executado com sucesso
Função Propósito Sintaxe
np.dot / @ Multiplicação de matrizes A @ B
np.linalg.inv Inversa de matriz inv(A)
np.linalg.det Determinante det(A)
np.linalg.norm Norma de vetor/matriz norm(v)
np.linalg.svd Decomposição em valores singulares U, S, Vt = svd(A)
np.linalg.solve Resolver sistemas lineares solve(A, b)

❓ Perguntas Frequentes

P: Qual a diferença fundamental entre um ndarray e uma lista Python? R: Um ndarray tem elementos de tipo uniforme, memória contígua e suporta operações vetorizadas; uma lista tem tipos mistos, memória dispersa e só pode ser processada com loops. ndarrays são 50–100x mais rápidos em computação numérica.

P: O reshape copia os dados? R: Não. O reshape retorna uma view dos dados originais sem copiar memória. Porém, se os shapes forem incompatíveis (por exemplo, memória não contígua), ele fará uma cópia automaticamente. Use o atributo .base para verificar se algo é uma view.

P: Quais são as regras do broadcasting? R: As dimensões são alinhadas a partir do eixo mais à direita. Qualquer dimensão igual a 1 ou ausente é expandida automaticamente. Duas dimensões devem ser iguais ou uma delas deve ser 1; caso contrário, um erro é lançado.

P: Quando devo usar np.random.seed vs. np.random.default_rng? R: Use default_rng (a API mais recente) — seed pertence à API legada. O default_rng usa o algoritmo PCG64, que tem melhor qualidade estatística e não afeta o estado global.

P: Como saber se dois arrays compartilham memória? R: Use np.shares_memory(a, b) para verificar. Alternativamente, verifique se a.base is b ou b.base is a. Quando a memória é compartilhada, modificar um array afetará o outro.

P: Por que o NumPy é considerado a base do ML? R: O Pandas é construído sobre arrays do NumPy, as entradas e saídas do Scikit-learn são ndarrays, e os tensores do PyTorch são altamente compatíveis com o NumPy. Dominar o NumPy significa dominar a linguagem de dados do ML.


📖 Resumo


📝 Exercícios

  1. Básico (Dificuldade ⭐): Crie uma matriz 5x5 com valores de 1 a 25 e use fatiamento para extrair os elementos da diagonal. Dica: elementos da diagonal têm o mesmo índice de linha e coluna, ou use np.diag().
  2. Intermediário (Dificuldade ⭐⭐): Gere 1000 pontos de dados de vendas aleatórios a partir de uma distribuição normal N(100, 15), use indexação booleana para filtrar valores acima de 130 e calcule a proporção deles. Dica: use rng.normal() e indexação booleana.
  3. Desafio (Dificuldade ⭐⭐⭐): Implemente regressão linear múltipla usando a equação normal do NumPy. Suponha vendas = 20 + 3*gasto_anuncio + 1.5*trafego + ruído. Gere dados simulados, resolva os coeficientes e compare-os com os verdadeiros. Dica: adicione uma coluna de bias ao construir a matriz X e use np.linalg.inv com multiplicação de matrizes.

← Anterior: Introdução ao Machine Learning | Próxima: Processamento de Dados com Pandas →

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%