1 O que é Machine Learning?
A arte de fazer computadores aprenderem sem serem explicitamente programados.
Programação tradicional vs Machine Learning
💻 Programação Tradicional
Entrada: Regras + Dados
Saída: Respostas
Ex: SE temperatura > 30 ENTÃO ligue_ar()
✅ Previsível, transparente
❌ Não escala, não generaliza
🧠 Machine Learning
Entrada: Dados + Respostas
Saída: Regras (modelo)
Ex: treina com 10.000 dias de clima → modelo prevê temperatura
✅ Generaliza, escala com dados
❌ Caixa preta, precisa de muitos dados
Exemplo prático: prever tempo de resolução de tickets
Na Nimbus Cloud (nossa empresa fictícia), temos milhares de tickets de suporte resolvidos. Cada ticket tem:
- Features (características): prioridade, categoria, cliente, hora do dia, complexidade estimada
- Target (alvo): tempo real de resolução (em minutos)
Um modelo de ML analisa esses dados históricos e aprende a prever quanto tempo um novo ticket vai levar — antes mesmo de ele ser aberto.
- Dimensionar a equipe de suporte
- Alertar clientes sobre prazos realistas
- Identificar tickets que vão atrasar antes que aconteça
2 Os 3 tipos de aprendizado
Supervisionado, não-supervisionado e por reforço — cada um para um tipo de problema.
Aprendizado Supervisionado
Dados etiquetados: você sabe a resposta correta para cada exemplo de treinamento.
Exemplos: classificar e-mails (spam/não-spam), prever preço de casas, diagnosticar doenças.
🎯 Analogia: professor corrige cada exercício.
Aprendizado Não-Supervisionado
Dados sem rótulos: o algoritmo descobre padrões e agrupamentos sozinho.
Exemplos: agrupar clientes por comportamento, detectar anomalias, reduzir dimensionalidade.
🎯 Analogia: explorar uma cidade sem mapa.
Aprendizado por Reforço
Agente aprende por tentativa e erro, recebendo recompensas ou punições.
Exemplos: AlphaGo, carros autônomos, robótica, jogos.
🎯 Analogia: treinar um cachorro com petiscos.
Qual usar na Nimbus Cloud?
| Problema | Tipo de ML | Por quê? |
|---|---|---|
| Prever tempo de resolução de tickets | 👨🏫 Supervisionado (regressão) | Temos histórico com tempos reais |
| Classificar tickets por prioridade | 👨🏫 Supervisionado (classificação) | Temos tickets etiquetados (alta/média/baixa) |
| Agrupar usuários por comportamento | 🔍 Não-supervisionado (clustering) | Não sabemos заранее quantos grupos existem |
| Detectar anomalias em logs | 🔍 Não-supervisionado (detecção de outliers) | Anomalias são raras e difíceis de etiquetar |
| Otimizar roteamento de chamadas | 🎮 Reforço | Ambiente dinâmico, decisões em sequência |
3 Regressão Linear — prever valores
O algoritmo mais simples e fundamental do ML. A base de tudo.
y = a * x + b, onde y é o valor que queremos prever, x é a feature, a é o peso (quanto cada unidade de x influencia y) e b é o intercepto (valor base). O algoritmo encontra os melhores valores de a e b minimizando o erro.
Exemplo: prever tempo de resolução de tickets
Na Nimbus Cloud, coletamos dados de 50 tickets resolvidos. Para cada ticket, temos:
- Feature (x): complexidade estimada (1-10)
- Target (y): tempo real de resolução (em minutos)
🎮 Simulador de Regressão Linear
Ajuste a inclinação e o intercepto para ver a reta de regressão
🔵 Pontos azuis: dados reais (complexidade vs tempo de resolução)
🟢 Linha ciano: reta de regressão (y = a*x + b)
🟢 Círculos verdes: previsões do modelo
Objetivo: ajustar a reta para minimizar a distância entre ela e os pontos (erro quadrático médio).
Exemplo: ticket com complexidade 7 → tempo previsto = 135 minutos
Como o algoritmo encontra a melhor reta?
O algoritmo de Gradient Descent (descida do gradiente) ajusta iterativamente os valores de a e b para minimizar o erro quadrático médio (MSE):
# MSE = média dos quadrados das diferenças entre previsto e real MSE = (1/n) * Σ(y_real - y_previsto)² # Gradient Descent ajusta a e b na direção que reduz o MSE a = a - learning_rate * d(MSE)/da b = b - learning_rate * d(MSE)/db
Código Python: regressão com scikit-learn
import numpy as np from sklearn.linear_model import LinearRegression from sklearn.metrics import mean_squared_error # Dados de treinamento (50 tickets da Nimbus Cloud) X = np.array([2, 3, 4, 5, 6, 7, 8, 9]).reshape(-1, 1) # complexidade y = np.array([62, 78, 88, 105, 118, 135, 152, 168]) # tempo (min) # Treina o modelo model = LinearRegression() model.fit(X, y) # Coeficientes aprendidos print(f"Inclinação (a): {model.coef_[0]:.2f}") # ~15.3 print(f"Intercepto (b): {model.intercept_:.2f}") # ~31.2 # Previsão para novo ticket novo_ticket = np.array([[7]]) # complexidade 7 previsao = model.predict(novo_ticket) print(f"Tempo previsto: {previsao[0]:.1f} minutos") # ~138 min # Avalia o modelo y_pred = model.predict(X) mse = mean_squared_error(y, y_pred) print(f"MSE: {mse:.2f}") # erro quadrático médio
y = a1*x1 + a2*x2 + a3*x3 + ... + b. Cada feature tem seu próprio peso.
4 Classificação — categorizar dados
Quando a resposta não é um número, mas uma categoria.
Exemplo: classificar tickets por prioridade
Na Nimbus Cloud, cada ticket precisa ser classificado como:
- 🔴 Alta: sistema fora do ar, impacto crítico
- 🟡 Média: funcionalidade degradada, workaround existe
- 🟢 Baixa: dúvida, sugestão, cosmético
Features disponíveis: palavras-chave do título, categoria, cliente, hora do dia, histórico do cliente.
Algoritmos de classificação populares
Decision Tree
Árvore de decisões: uma série de perguntas sim/não que levam à classificação.
Ex: "É cliente enterprise? → Sim → Tem SLA crítico? → Sim → ALTA"
Random Forest
Múltiplas árvores de decisões votando. Mais robusto que uma árvore sozinha.
Ex: 100 árvores votam → 70 dizem ALTA, 20 MÉDIA, 10 BAIXA → ALTA
SVM (Support Vector Machine)
Encontra a "linha" que melhor separa as classes no espaço de features.
Bom para dados linearmente separáveis.
Naive Bayes
Baseado em probabilidade (teorema de Bayes). Rápido e funciona bem com texto.
Clássico para classificação de e-mails (spam/não-spam).
Código Python: classificação com Random Forest
import pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report # Dataset de tickets da Nimbus Cloud data = { 'complexidade': [8, 9, 7, 3, 2, 6, 5, 4, 9, 1], 'cliente_enterprise': [1, 1, 0, 1, 0, 1, 0, 0, 1, 0], 'fora_do_ar': [1, 1, 0, 1, 0, 0, 0, 0, 1, 0], 'prioridade': ['alta', 'alta', 'media', 'alta', 'baixa', 'media', 'baixa', 'baixa', 'alta', 'baixa'] } df = pd.DataFrame(data) # Separa features (X) e target (y) X = df[['complexidade', 'cliente_enterprise', 'fora_do_ar']] y = df['prioridade'] # Divide em treino e teste (80% treino, 20% teste) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # Treina o modelo clf = RandomForestClassifier(n_estimators=100, random_state=42) clf.fit(X_train, y_train) # Previsões y_pred = clf.predict(X_test) # Avaliação print(classification_report(y_test, y_pred)) # Previsão para novo ticket novo_ticket = pd.DataFrame({ 'complexidade': [8], 'cliente_enterprise': [1], 'fora_do_ar': [1] }) previsao = clf.predict(novo_ticket) print(f"Prioridade prevista: {previsao[0]}") # 'alta'
Métricas de avaliação
| Métrica | O que mede | Quando usar |
|---|---|---|
| Acurácia | % de previsões corretas | Classes balanceadas |
| Precisão | Dos que o modelo disse "alta", quantos realmente são? | Quando falsos positivos são caros |
| Recall | Dos que realmente são "alta", quantos o modelo achou? | Quando falsos negativos são perigosos |
| F1-Score | Média harmônica entre precisão e recall | Classes desbalanceadas |
5 Clustering — agrupar sem rótulos
Quando você não sabe as categorias — o algoritmo descobre.
Exemplo: agrupar usuários da Nimbus Cloud por comportamento
Temos 200 usuários e queremos descobrir padrões de uso. Features:
- Horas de uso por dia
- Número de tickets abertos por mês
- Features mais utilizadas
O clustering vai agrupar usuários similares — talvez descubramos "power users", "usuários casuais", "usuários em risco de churn".
K-Means — o algoritmo mais popular
O K-Means funciona assim:
- Você escolhe o número de clusters (K)
- O algoritmo inicializa K centros aleatórios
- Cada ponto é atribuído ao centro mais próximo
- Os centros são reposicionados para a média dos pontos do cluster
- Repete até convergir (centros não mudam mais)
🎮 Simulador de K-Means
Veja o K-Means agrupando pontos em tempo real
🔵 Pontos coloridos: dados agrupados por cluster
✕ Centros: centroides de cada cluster (média dos pontos)
Objetivo: minimizar a distância entre pontos e seus centros.
Código Python: K-Means com scikit-learn
import numpy as np from sklearn.cluster import KMeans import matplotlib.pyplot as plt # Dados de usuários da Nimbus Cloud (200 usuários, 2 features) # Feature 1: horas de uso por dia # Feature 2: tickets abertos por mês np.random.seed(42) X = np.vstack([ np.random.randn(80, 2) * [2, 3] + [8, 15], # power users np.random.randn(70, 2) * [1, 2] + [3, 5], # usuários casuais np.random.randn(50, 2) * [1.5, 4] + [1, 20] # usuários em risco (muitos tickets) ]) # Aplica K-Means com K=3 kmeans = KMeans(n_clusters=3, random_state=42, n_init=10) kmeans.fit(X) # Resultados labels = kmeans.labels_ centers = kmeans.cluster_centers_ print("Centroides dos clusters:") print(centers) # [[3.1, 5.2], ← usuários casuais # [8.3, 14.8], ← power users # [1.2, 19.5]] ← usuários em risco # Visualização plt.scatter(X[:, 0], X[:, 1], c=labels, cmap='viridis', alpha=0.6) plt.scatter(centers[:, 0], centers[:, 1], c='red', marker='X', s=200) plt.xlabel('Horas de uso/dia') plt.ylabel('Tickets abertos/mês') plt.title('Clusters de usuários Nimbus Cloud') plt.show()
Como escolher o K ideal?
O Método do Cotovelo (Elbow Method) plota a inércia (soma das distâncias ao quadrado) para diferentes valores de K. O "cotovelo" da curva indica o K ideal:
# Elbow Method inertias = [] K_range = range(1, 11) for k in K_range: kmeans = KMeans(n_clusters=k, random_state=42, n_init=10) kmeans.fit(X) inertias.append(kmeans.inertia_) plt.plot(K_range, inertias, marker='o') plt.xlabel('Número de clusters (K)') plt.ylabel('Inércia') plt.title('Elbow Method') plt.show()
6 Overfitting vs Underfitting
O dilema central do ML: memorizar vs generalizar.
Os 3 cenários
❌ Underfitting
Modelo muito simples. Não aprende nem os dados de treinamento.
Causa: modelo incapaz de capturar padrões.
Sintoma: erro alto em treino E teste.
Ex: usar regressão linear para dados não-lineares.
✅ Modelo ideal
Generaliza bem. Aprende padrões dos dados de treino e funciona em dados novos.
Causa: complexidade adequada.
Sintoma: erro baixo em treino E teste.
Ex: Random Forest com profundidade adequada.
⚠️ Overfitting
Modelo muito complexo. Decora os dados de treino, incluindo ruído.
Causa: modelo flexível demais, poucos dados.
Sintoma: erro baixo em treino, erro alto em teste.
Ex: árvore de decisão muito profunda.
📊 Como detectar?
Divida os dados em treino (80%) e teste (20%).
Compare métricas:
- Treino bom, teste ruim → overfitting
- Treino ruim, teste ruim → underfitting
- Treino bom, teste bom → ideal
🎮 Simulador: complexidade do modelo
Ajuste a complexidade do modelo e veja o efeito
🔵 Pontos: dados de treinamento
🟢 Linha: curva ajustada pelo modelo
Observação: complexidade baixa = underfitting (linha reta). Complexidade alta = overfitting (curva passa por todos os pontos, mas não generaliza).
Como evitar overfitting?
Mais dados
Quanto mais dados de treinamento, mais difícil o modelo decora tudo.
Regularização
Adiciona penalidade para modelos muito complexos (L1/Lasso, L2/Ridge).
Pruning
"Poda" árvores de decisão muito profundas.
Dropout (redes neurais)
Desativa neurônios aleatoriamente durante treinamento.
Cross-validation
Treina em múltiplos subconjuntos e valida em diferentes partes.
Early stopping
Para o treinamento quando o erro de validação começa a subir.
7 Métricas de avaliação
Como saber se seu modelo é bom — números não mentem.
Para regressão (prever valores)
| Métrica | Fórmula | Interpretação |
|---|---|---|
| MSE (Mean Squared Error) | Média dos quadrados dos erros | Quanto menor, melhor. Sensível a outliers. |
| RMSE (Root MSE) | Raiz quadrada do MSE | Mesma unidade do target. Mais interpretável. |
| MAE (Mean Absolute Error) | Média dos valores absolutos dos erros | Robusto a outliers. |
| R² (R-squared) | Proporção da variância explicada | 0 a 1. Quanto mais próximo de 1, melhor. |
Para classificação (categorizar)
| Métrica | Fórmula | Interpretação |
|---|---|---|
| Acurácia | (VP + VN) / Total | % de previsões corretas. Ruim para classes desbalanceadas. |
| Precisão | VP / (VP + FP) | Dos que o modelo disse "positivo", quantos realmente são? |
| Recall | VP / (VP + FN) | Dos que realmente são "positivo", quantos o modelo achou? |
| F1-Score | 2 * (Precisão * Recall) / (Precisão + Recall) | Média harmônica. Bom para classes desbalanceadas. |
Matriz de confusão
Visualização completa de acertos e erros:
Verdadeiro Positivo
Falso Positivo
Falso Negativo
Verdadeiro Negativo
- Precisão: 90 / (90+10) = 90%
- Recall: 90 / (90+30) = 75%
- F1: 2 * (0.9 * 0.75) / (0.9 + 0.75) = 81.8%
8 Conexão com RAG
Como tudo que você aprendeu aqui se aplica ao Módulo 7 (RAG).
Conceitos que se conectam
| Conceito de ML | Aplicação em RAG |
|---|---|
| Vetores / Embeddings | Chunks são transformados em vetores. A busca vetorial encontra chunks similares por similaridade de cosseno. |
| Clustering (K-Means) | Vector DBs usam algoritmos similares (HNSW, IVF) para organizar vetores e acelerar a busca. |
| Similaridade de cosseno | Métrica central da busca vetorial. Mede o ângulo entre vetores da pergunta e dos chunks. |
| Overfitting | Modelos de embedding podem overfitar no domínio de treinamento. Por isso testamos diferentes modelos. |
| Métricas de avaliação | RAGAS usa métricas similares (faithfulness, relevancy) para avaliar a qualidade do RAG. |
Exemplo: embeddings como clustering
# No RAG, chunks similares são "agrupados" semanticamente # Isso é essencialmente clustering no espaço vetorial import numpy as np from sklearn.metrics.pairwise import cosine_similarity # Embeddings de 3 chunks chunk_1 = np.array([0.23, -0.71, 0.45]) # "contrato vence em março" chunk_2 = np.array([0.21, -0.69, 0.47]) # "prazo final é março" chunk_3 = np.array([-0.82, 0.34, -0.19]) # "pizza de calabresa" # Calcula similaridade entre chunks sim_12 = cosine_similarity([chunk_1], [chunk_2])[0][0] sim_13 = cosine_similarity([chunk_1], [chunk_3])[0][0] print(f"Similaridade chunk 1-2: {sim_12:.3f}") # 0.998 (muito similares) print(f"Similaridade chunk 1-3: {sim_13:.3f}") # -0.42 (diferentes) # No RAG, quando o usuário faz uma pergunta: # 1. A pergunta vira um vetor (embedding) # 2. Calculamos similaridade com todos os chunks # 3. Retornamos os top-K mais similares
🎯 Quiz — teste seu conhecimento
Clique em uma alternativa para ver se acertou.
→ O que vem a seguir?
Agora que você entende ML clássico, vamos mergulhar nas redes neurais.
Conceitos que vamos construir aqui
Neurônio artificial
A unidade básica de uma rede neural.
Camadas
Input, hidden e output — a estrutura da rede.
Ativação
ReLU, sigmoid — funções que dão não-linearidade.
Backpropagation
Como a rede "aprende" ajustando pesos.