Logo Passei Direto
Buscar
Material
páginas com resultados encontrados.
páginas com resultados encontrados.
left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

left-side-bubbles-backgroundright-side-bubbles-background

Experimente o Premium!star struck emoji

Acesse conteúdos dessa e de diversas outras disciplinas.

Libere conteúdos
sem pagar

Ajude estudantes e ganhe conteúdos liberados!

Prévia do material em texto

Mãos em
Aprendizado de 
máquina com Scikit-Learn
& TensorFlow
CONCEITOS, FERRAMENTAS E TÉCNICAS
PARA CONSTRUIR SISTEMAS INTELIGENTES
Aurélien Géron
Scikit-Learn e TensorFlow
Aprendizado de máquina prático com
Aurélien Géron
Pequim Boston Farnham Sebastopol Tóquio
Construa Sistemas Inteligentes
Conceitos, ferramentas e técnicas para
Aprendizado de máquina prático com Scikit-Learn e 
TensorFlow por Aurélien Géron
Designer de capa: Randy Comer
10/03/2017: Primeiro lançamento
Consulte http://oreilly.com/catalog/errata.csp?isbn=9781491962299 para detalhes do lançamento.
Ilustradora: Rebeca Demarest
Editora: Nicole Tache
Copyright © 2017 Aurélien Géron. Todos os direitos reservados.
O logotipo da O'Reilly é uma marca registrada da O'Reilly Media, Inc. Hands-On Machine Learning com Scikit-Learn e TensorFlow, 
a imagem da capa e a identidade visual relacionada são marcas registradas da O'Reilly Media, Inc.
Editor de Produção: Nicholas Adams
Editor de texto: Rachel Monaghan
Impresso nos Estados Unidos da América.
Embora a editora e o autor tenham feito esforços de boa fé para garantir que as informações e instruções contidas neste trabalho 
sejam precisas, a editora e o autor se isentam de toda responsabilidade por erros ou omissões, incluindo, sem limitação, 
responsabilidade por danos resultantes do uso ou confiança neste trabalho. O uso das informações e instruções contidas neste 
trabalho é por sua conta e risco. Se qualquer amostra de código ou outra tecnologia que este trabalho contém ou descreve estiver 
sujeita a licenças de código aberto ou direitos de propriedade intelectual de terceiros, é sua responsabilidade garantir que seu uso 
esteja em conformidade com tais licenças e/ou direitos.
978-1-491-96229-9
Revisor: Charles Roumeliotis
Publicado por O'Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
[LSI]
Os livros da O'Reilly podem ser adquiridos para uso educacional, comercial ou promocional de vendas. Edições online também 
estão disponíveis para a maioria dos títulos (http://oreilly.com/safari). Para obter mais informações, entre em contato com nosso 
departamento de vendas corporativo/institucional: 800-998-9938 ou corporate@oreilly.com.
Março de 2017: Primeira edição
Indexador: Wendy Catalano
Designer de Interiores: David Futato
Histórico de revisão para a primeira edição
http://oreilly.com/catalog/errata.csp?isbn=9781491962299
http://oreilly.com/safari
iii
Índice
Parte I. Os fundamentos do aprendizado de máquina
Quantidade insuficiente de dados de treinamento
Tipos de sistemas de aprendizado de máquina 
Aprendizado supervisionado/não supervisionado 
em lote e aprendizado online baseado 
em instância versus aprendizado baseado em modelo
Dados de treinamento não representativos 24 
25Dados de baixa qualidade
4
25
26
28
7
Recursos irrelevantes
37
8 14
17
Sobreajustando os dados de treinamento
28 
29
Subajustando os dados de treinamento
22
Recuando
31
Testando e validando
22
33 
35
35
O que é aprendizado de máquina?
Por que usar aprendizado de máquina?
Principais desafios do aprendizado de máquina
exercícios
Prefácio. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1. O Cenário do Aprendizado de Máquina. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
3 4
xiii
2. Projeto de aprendizado de máquina de ponta a ponta. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
33 Trabalhando com dados 
reais Observe o quadro 
geral do problema 
Selecione uma medida de desempenho
59
62
40
91
79
Obter os dados
74
Manipulando Texto e Atributos Categóricos
Classificação multiclasse
53
68
Treinando um Classificador Binário
77
Criar um conjunto de teste
55 
58
83 
84
40
87
60
Verifique as suposições
74
Limpeza de dados
A curva ROC
53
MNIST
68
101
Pipelines de Transformação
Dê uma olhada rápida na estrutura de dados
76
Classificação de múltiplas saídas
Matriz de Confusão
Procurando por correlações
exercícios
86
Preparar os dados para algoritmos de aprendizado de máquina
72
Compensação Precisão/Recall
82
49
66
100
Dimensionamento de recursos
Baixe os dados
Classificação multirrótulo
75
Treinamento e avaliação no conjunto de treinamento 
Melhor avaliação usando validação cruzada Ajuste 
fino do seu modelo Pesquisa 
em grade 
Pesquisa aleatória 
Métodos de conjunto 
Analise os melhores modelos e seus erros Avalie seu 
sistema no conjunto de testes Inicie, monitore 
e mantenha seu sistema Experimente!
Visualizando Dados Geográficos
Medindo a precisão usando a validação cruzada
Experimentando combinações de atributos
Precisão e Recall
69 
71
64 
65
43 
45
82
93 
96
Criar o espaço de trabalho
Erro de análise
Transformadores personalizados
74
Selecione e treine um modelo
Descubra e visualize os dados para obter insights
Medidas de Desempenho
40
77
3. Classificação. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
iv | Índice
121
127
Descida de Gradiente em Minilote
161 
164
Núcleo Gaussiano RBF
102
145
Limites de Decisão
152
Regressão Ridge
134
Função de Decisão e Previsões
Classificação SVM não linear
111
117 
119
157
Descida de Gradiente Estocástico
160
123
Adicionando recursos de similaridade
exercícios
Classificação Linear SVM
Função de treinamento e custo
150 
151
Modelos Lineares Regularizados
sob o capô
133
114
110
Classificação de Margem Suave
156 
156
O Problema Duplo
Parada Antecipada
139
159
Estimando probabilidades
SVMs on-line
Regressão SVM
Curvas de aprendizado
132
165
exercícios
106 
108
154
149
136
Rede Elástica
Programação Quadrática
Regressão Logística
Kernelized SVM
142
127 
130
regressão polinomial
Complexidade computacional
exercícios
153
Regressão Softmax
146
134 
135
Regressão de laço
Objetivo do treinamento
Descida de Gradiente em Lote
Núcleo polinomial
4. Modelos de treinamento. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 
105 Regressão 
Linear A Equação Normal 
Complexidade Computacional 
Descida de Gradiente
5. Suporte a máquinas de vetores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Índice | v
7. Ensemble Learning e Random Forests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 
Classificadores de 
votação Ensacamento 
e colagem Ensacamento e colagem no 
Scikit-Learn Avaliação fora 
do saco Patches aleatórios e subespaços 
aleatórios Florestas aleatórias
8. Redução de Dimensionalidade. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205
6. Árvores de decisão. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
Projeção
Projetando abaixo das dimensões d
PCA para Compressão
207 
210
Regularização Hiperparâmetros 
Regressão 
Instabilidade
213 
214
Razão de variância explicada
Aumento de Gradiente
185
Extra-Árvores
200
A Maldição da DimensionalidadePreservando a Variância
206
Impulsionando
171
192
175
189
exercícios
Aprendizado múltiplo
PCA incremental
169
178
172 
172
186 
187
211
Empilhamento
Principais Abordagens para Redução de Dimensionalidade
Escolhendo o Número Certo de Dimensões
212
214
216
Usando o Scikit-Learn
Treinando e visualizando uma árvore de decisão 
Fazendo previsões 
Estimando probabilidades de classe 
O algoritmo de treinamento CART 
Complexidade computacional 
Gini Impureza ou entropia?
181
AdaBoostGenericName
211
exercícios
171
Importância do recurso
202
Componentes principais
207
217 
218
167
PCA
177
190
195
PCA randomizado
215
188
173
190 
191
| Índicevi
Índice | vii
Usando um otimizador 239
223 
224
Número de neurônios por camada oculta
O Perceptron
Selecionando um Kernel e Ajustando Hiperparâmetros
248
235
265
Criando seu primeiro gráfico e executando-o em uma sessão
Visualizando o gráfico e as curvas de treinamento usando o TensorBoard
Fase de construção
254
218
Usando o diferencial automático
270
221
Número de camadas ocultas
238
Computações Lógicas com Neurônios
Kernel PCA
246
234
264
Instalação
Treinando um DNN usando o TensorFlow simples
Salvando e Restaurando Modelos
Calculando manualmente os gradientes
exercícios
270
255
Regressão linear com TensorFlow
Variáveis de Compartilhamento
Hiperparâmetros de rede neural de ajuste fino
232 
232
245
261
Treinando um MLP com a API de alto nível do TensorFlow
Alimentando dados para o algoritmo de treinamento
272 
272
237 
237
Outras Técnicas de Redução de Dimensionalidade
270
exercícios
Modularidade
Ciclo de vida de um valor de nó
Usando a Rede Neural
Implementando descida de gradiente
256 
257
241 
242
239
Perceptron multicamadas e retropropagação
Funções de ativação
LLE
265 
269
235
251
Escopos de Nome
Gerenciando Gráficos
Fase de Execução
219
Neurônios Biológicos
9. Instalado e funcionando com o TensorFlow. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 229
10. Introdução às Redes Neurais Artificiais. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 De 
neurônios biológicos a artificiais
Parte II. Redes Neurais e Deep Learning
Gradiente Acelerado de Nesterov
RMSProp
Recorte Gradiente
298
273
290 
291Zoológicos modelo
314
286
Parada Antecipada 
ÿ1 e Regularização ÿ2
304
294 
295
275 
277
otimização de momento
321 
323
Normalização em lote
325
AdaGrad
298
exercícios
290
Ajustando, descartando ou substituindo as camadas superiores
282
303
Evitando o overfitting por meio da regularização
Otimizadores mais rápidos
Xavier e He Inicialização
293
318
exercícios
Reutilizando modelos de outros frameworks
Aumento de dados
323
Cacheando as Camadas Congeladas
289
311
303
279
Agendamento da Taxa de Aprendizagem
Pré-treinamento em uma tarefa auxiliar
Problemas de gradientes de desaparecimento/explosão
317
292
Regularização de norma máxima
Reutilizando um modelo do TensorFlow
Orientações Práticas
Congelando as Camadas Inferiores
310
288
Otimização de Adam
Reutilizando camadas pré-treinadas
300 
302
314
Pré-treinamento não supervisionado 291
Cair fora
286 
287
307 
309
Funções de Ativação Não Saturantes
296
12. Distribuição do TensorFlow entre dispositivos e servidores. . . . . . . . . . . . . . . . . . . . . . . . . . . 313 
Vários dispositivos em uma única máquina 
Instalação 
Gerenciando a RAM da GPU 
Colocando operações em dispositivos 
Dependências de 
controle de execução 
paralela Vários dispositivos em vários servidores 
Abertura de uma sessão
11. Treinamento de redes neurais profundas. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275
| Índiceviii
355
389 
392
358
Replicação dentro do gráfico versus entre gráficos
Treinamento para prever séries temporais
367 
368
Fixando operações entre tarefas
GoogLeNet
343 
345
RNNs básicos no TensorFlow
325
387
Empilhando vários mapas de recursos
380
363
Carregando dados diretamente do gráfico
354
Manipulando Sequências de Saída de Comprimento Variável
Uma rede neural por dispositivo
Treinando um Classificador de Sequência
357
366
Os Serviços de Mestre e Operário
AlexNet
342
Sequências de entrada e saída
exercícios
Filtros
385 
387
Comunicação assíncrona usando filas do TensorFlow
360 
362
Manipulando Sequências de Entrada de Comprimento Variável
384
328 
329
Camada de agrupamento
RNNs de treinamento
342
396
LeNet-5
Células de Memória
376
Paralelismo de dados
Camada Convolucional
RNNs profundos
352
Compartilhando estado entre sessões usando contêineres de recursos
Desenrolamento Dinâmico Através do Tempo
exercícios
Requisitos de memória
327
382
389
335
Neurônios Recorrentes
Arquiteturas da CNN
396
A arquitetura do córtex visual
Paralelismo de modelo
372
RNN criativo
Variáveis de fragmentação em vários servidores de parâmetros
Desenrolamento Estático Através do Tempo
347
ResNet
Implementação do TensorFlow
326
388
382
Como paralelizar redes neurais em um cluster do TensorFlow
365
14. Redes Neurais Recorrentes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
13. Redes Neurais Convolucionais. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353
ixÍndice |
433
441
453
Processamento de linguagem natural
447
420 
421
404
413 
415
Autoencoders variacionais
431
438
460
417
Peephole Conexões
425
exercícios
407 
410
400
Outros codificadores automáticos
exercícios
A Dificuldade de Treinar em Muitos Passos de Tempo
397
Incorporações de palavras
405
457 
459
422
432
448
Distribuindo um RNN profundo em várias GPUs
428
Célula GRU
401 
403
418
444
399
Célula LSTM
416
Gerando Dígitos
440
Aplicando Dropout
460
412
426 
427
405
Uma Rede Codificador-Decodificador para Tradução Automática
424
15. Codificadores automáticos. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 411 
Representações de Dados 
Eficientes Executando PCA com um Autoencoder Linear Subcompleto 
Implementação de 
Autoencoders Empilhados 
TensorFlow 
Treinamento de Pesos Vinculados Um 
Autoencoder por Vez Visualizando 
as Reconstruções 
Visualizando Recursos Pré-treinamento Não Supervisionado 
Usando Autoencoders 
Empilhados Denoising 
Autoencoders 
Implementação de TensorFlow Autoencoders Esparsos Implementação de TensorFlow
16. Aprendizagem por Reforço. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 437 
Learning to Optimize Rewards 
Policy Search 
Introdução às políticas de redes 
neurais OpenAI Gym 
Avaliando ações: o problema de atribuição de crédito Política 
Gradientes Markov 
Processos de decisão Diferença 
temporal Políticas de aprendizagem e exploração de 
Q-Learning Q-Learning 
aproximado Aprendendo a 
jogar Ms. Pac-Man Usando Deep Q -Aprendizado
x | Índice
469
470
Exercícios 
Obrigado!
A. Soluções de exercícios. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B. Lista de verificação do projeto de aprendizado de máquina. . . . . . . . . . . . . . . . . . .. . . . . . . . . . . . . . . . . . . . . . . . 497
C. Problema duplo SVM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 503
471
D. Autodif. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 507
E. Outras Arquiteturas ANN Populares. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 515
Índice. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525
Índice | XI
desde a década de 1990, embora não fossem de uso geral.
xiii
1 Disponível na página inicial da Hinton em http://www.cs.toronto.edu/~hinton/.
Prefácio
Avançando 10 anos, o aprendizado de máquina conquistou o setor: agora está no centro de grande 
parte da mágica dos produtos de alta tecnologia de hoje, classificando seus resultados de pesquisa 
na Web, potencializando o reconhecimento de fala de seu smartphone e recomendando vídeos, 
vencendo o mundo campeão no jogo de Go. Antes que você perceba, ele estará dirigindo seu carro.
Então, naturalmente, você está entusiasmado com o aprendizado de máquina e adoraria participar 
da festa!
Em 2006, Geoffrey Hinton et al. publicaram um artigo1 mostrando como treinar uma rede neural 
profunda capaz de reconhecer dígitos manuscritos com precisão de última geração (>98%). Eles 
batizaram essa técnica de “Aprendizado Profundo”. Treinar uma rede neural profunda era amplamente 
considerado impossível na época,2 e a maioria dos pesquisadores havia abandonado a ideia desde 
a década de 1990. Este artigo reavivou o interesse da comunidade científica e, em pouco tempo, 
muitos novos artigos demonstraram que o Deep Learning não era apenas possível, mas capaz de 
realizações alucinantes que nenhuma outra técnica de Machine Learning (ML) poderia esperar 
igualar (com a ajuda de tremendos poder de computação e grandes quantidades de dados). Esse 
entusiasmo logo se estendeu a muitas outras áreas do Machine Learning.
Talvez você queira dar ao seu robô caseiro um cérebro próprio? Fazê-lo reconhecer rostos? Ou 
aprender a andar por aí?
2 Apesar do fato de que as redes neurais convolucionais profundas de Yann Lecun funcionaram bem para reconhecimento de imagem
Machine Learning em seus projetos
O tsunami de aprendizado de máquina
http://www.cs.toronto.edu/~hinton/
Em vez de implementar nossas próprias versões de brinquedo de cada algoritmo, usaremos 
estruturas Python prontas para produção:
Seja qual for o motivo, você decidiu aprender Machine Learning e implementá-lo em seus projetos. 
Boa ideia!
Embora você possa ler este livro sem pegar seu laptop, é altamente recomendável que você 
experimente os exemplos de código disponíveis on-line como notebooks Jupyter em https://github.com/
ageron/handson-ml.
• Segmentar clientes e encontrar a melhor estratégia de marketing para cada grupo • 
Recomendar produtos para cada cliente com base no que clientes semelhantes compraram 
• Detectar quais transações provavelmente serão fraudulentas • 
Prever a receita do próximo ano • 
E muito mais
Abordaremos um grande número de técnicas, desde as mais simples e mais comumente usadas 
(como a regressão linear) até algumas das técnicas de Deep Learning que regularmente vencem 
competições.
O livro favorece uma abordagem prática, desenvolvendo uma compreensão intuitiva do aprendizado 
de máquina por meio de exemplos práticos concretos e um pouco de teoria.
Ou talvez sua empresa tenha toneladas de dados (registros de usuários, dados financeiros, dados 
de produção, dados de sensores de máquinas, estatísticas de linha direta, relatórios de RH etc.) por 
exemplo:
Este livro pressupõe que você não saiba quase nada sobre aprendizado de máquina. Seu objetivo é 
fornecer os conceitos, as intuições e as ferramentas de que você precisa para realmente implementar 
programas capazes de aprender com os dados.
• Scikit-Learn é muito fácil de usar, mas implementa muitos algoritmos de Aprendizado de Máquina 
de forma eficiente, por isso é um ótimo ponto de entrada para aprender Aprendizado de 
Máquina. • TensorFlow é uma biblioteca mais complexa para computação numérica distribuída 
usando gráficos de fluxo de dados. Ele torna possível treinar e executar redes neurais muito 
grandes de forma eficiente, distribuindo as computações em potencialmente milhares de 
servidores multi-GPU. O TensorFlow foi criado no Google e oferece suporte a muitos de seus 
aplicativos de aprendizado de máquina em grande escala. Foi aberto em novembro de 2015.
Objetivo e Abordagem
xiv | Prefácio
https://github.com/ageron/handson-ml
https://www.kaggle.com/wiki/DataScienceUseCases
http://scikit-learn.org/
http://tensorflow.org/
Pré-requisitos
Roteiro
Se você ainda não conhece Python, http://learnpython.org/ é um ótimo lugar para começar. O tutorial 
oficial em python.org também é muito bom.
ting (a troca de viés/variância).
Além disso, se você se preocupa com o que está por baixo do capô, também deve ter um conhecimento 
razoável de matemática de nível universitário (cálculo, álgebra linear, probabilidades e estatística).
• Reduzindo a dimensionalidade dos dados de treinamento para combater a maldição da dimensãoÿ
• As principais etapas de um projeto típico de Machine Learning. • 
Aprender ajustando um modelo aos dados. 
• Otimização de uma função de 
custo. • Manuseio, limpeza e preparação de 
dados. • Seleção e recursos de engenharia. 
• Selecionar um modelo e ajustar hiperparâmetros usando validação cruzada. • Os 
principais desafios do Machine Learning, em particular underfitting e overfitÿ
Este livro pressupõe que você tenha alguma experiência em programação Python e que esteja 
familiarizado com as principais bibliotecas científicas do Python, em particular NumPy, Pandas, e 
Matplotlib.
Se você não estiver familiarizado com as bibliotecas científicas do Python, os notebooks Jupyter 
fornecidos incluem alguns tutoriais. Há também um rápido tutorial de matemática para álgebra linear.
• O que é aprendizado de máquina? Que problemas ele tenta resolver? Quais são as principais 
categorias e conceitos fundamentais dos sistemas de Machine Learning?
Se você nunca usou o Jupyter, o Capítulo 2 o guiará pela instalação e pelo básico: é uma ótima 
ferramenta para se ter em sua caixa de ferramentas.
Este livro está organizado em duas partes. A Parte I, Os fundamentos do aprendizado de máquina, 
abrange os seguintes tópicos:
• Os algoritmos de aprendizado mais comuns: regressão linear e polinomial, regressão logística, k-
vizinhos mais próximos, máquinas de vetores de suporte, árvores de decisão, florestas aleatórias 
e métodos de conjunto.
alidade.
Prefácio | xv
http://learnpython.org/
https://docs.python.org/3/tutorial/
http://numpy.org/
http://pandas.pydata.org/
http://matplotlib.org/
XVI | Prefácio
A primeira parte é baseada principalmente no Scikit-Learn, enquanto a segunda parte usa o TensorFlow.
Muitos recursos estão disponíveispara aprender sobre Machine Learning. Curso de ML de Andrew Ng no 
Coursera e o curso de Geoffrey Hinton sobre redes neurais e Deep Learning são incríveis, embora ambos 
exijam um investimento de tempo significativo (pense em meses).
• Técnicas de treinamento de redes neurais profundas. • 
Dimensionamento de redes neurais para grandes conjuntos 
de dados. • Aprendizagem por reforço.
• Joel Grus, Data Science from Scratch (O'Reilly). Este livro apresenta os fundamentos do Machine 
Learning e implementa alguns dos principais algoritmos em Python puro (do zero, como o nome 
sugere).
• Stephen Marsland, Aprendizado de Máquina: Uma Perspectiva Algorítmica (Chapman e Hall). Este 
livro é uma ótima introdução ao aprendizado de máquina, cobrindo uma ampla
Claro que também existem muitos outros livros introdutórios sobre Machine Learning, em particular:
• O que são redes neurais? Para que servem? • Construção 
e treinamento de redes neurais usando o TensorFlow. • As 
arquiteturas de redes neurais mais importantes: redes neurais feedforward, redes convolucionais, redes 
recorrentes, redes de memória de longo prazo (LSTM) e codificadores automáticos.
Por fim, o site Deep Learning tem uma boa lista de recursos para aprender mais.
A Parte II, Redes Neurais e Aprendizado Profundo, abrange os seguintes tópicos:
Há também muitos sites interessantes sobre Machine Learning, incluindo, é claro, o excepcional Guia do 
Usuário do Scikit-Learn. Você também pode desfrutar do Dataquest, que fornece tutoriais interativos muito 
bons e blogs de ML, como os listados no Quora.
Outros recursos
Não pule em águas profundas com muita pressa: embora o Deep Learning 
seja sem dúvida uma das áreas mais empolgantes do Machine Learning, 
você deve dominar os fundamentos primeiro. Além disso, a maioria dos 
problemas pode ser resolvida muito bem usando técnicas mais simples, como 
os métodos Random Forests e Ensemble (discutidos na Parte I). Deep 
Learning é mais adequado para problemas complexos, como reconhecimento 
de imagem, reconhecimento de fala ou processamento de linguagem natural, 
desde que você tenha dados suficientes, poder de computação e paciência.
https://www.coursera.org/learn/machine-learning/
https://www.coursera.org/learn/machine-learning/
https://www.coursera.org/course/neuralnets
https://www.coursera.org/course/neuralnets
http://shop.oreilly.com/product/0636920033400.do
http://deeplearning.net/
http://scikit-learn.org/stable/user_guide.html
https://www.dataquest.io/
http://goo.gl/GwtU3A
Este elemento significa uma dica ou sugestão.
• Stuart Russell e Peter Norvig, Inteligência Artificial: Uma Abordagem Moderna, 3ª Edição (Pearson). 
Este é um ótimo (e enorme) livro que cobre uma quantidade incrível de tópicos, incluindo Machine 
Learning. Isso ajuda a colocar o ML em perspectiva.
As seguintes convenções tipográficas são usadas neste livro:
• Yaser S. Abu-Mostafa, Malik Magdon-Ismail e Hsuan-Tien Lin, Learning from Data (AMLBook). Uma 
abordagem bastante teórica para ML, este livro fornece insights profundos, em particular sobre a 
compensação de viés/variância (consulte o Capítulo 4).
Itálico de largura constante 
Mostra o texto que deve ser substituído por valores fornecidos pelo usuário ou por valores 
determinados pelo contexto.
Largura constante em 
negrito Mostra comandos ou outro texto que deve ser digitado literalmente pelo usuário.
• Sebastian Raschka, Python Machine Learning (Packt Publishing). Também uma ótima introdução ao 
aprendizado de máquina, este livro utiliza as bibliotecas de software livre Python (Pylearn 2 e Theano).
Largura constante 
Usado para listas de programas, bem como dentro de parágrafos para se referir a elementos do 
programa, como nomes de variáveis ou funções, bancos de dados, tipos de dados, variáveis de 
ambiente, instruções e palavras-chave.
variedade de tópicos em profundidade, com exemplos de código em Python (também do zero, mas 
usando NumPy).
Por fim, uma ótima maneira de aprender é ingressar em sites de competição de ML, como Kaggle.com 
isso permitirá que você pratique suas habilidades em problemas do mundo real, com ajuda e insights de 
alguns dos melhores profissionais de ML existentes.
Itálico 
Indica novos termos, URLs, endereços de e-mail, nomes de arquivo e extensões de arquivo.
Prefácio | xvii
Convenções utilizadas neste livro
https://www.kaggle.com/
| Prefácioxviii
Material suplementar (exemplos de código, exercícios etc.) está disponível para download em https://
github.com/ageron/handson-ml.
Este elemento significa uma nota geral.
Este elemento indica um aviso ou cuidado.
Agradecemos, mas não exigimos, atribuição. Uma atribuição geralmente inclui o título, autor, 
editora e ISBN. Por exemplo: “Aprendizado de máquina prático com Scikit-Learn e 
TensorFlow por Aurélien Géron (O'Reilly). Copyright 2017 Aurélien Géron, 978-1-491-96229-9.”
Media, Harvard Business Review, Prentice Hall Professional, Addison-Wesley Professional, 
Microsoft Press, Sams, Que, Peachpit Press, Adobe, Focal Press, Cisco Press,
Os membros têm acesso a milhares de livros, vídeos de treinamento, Learning Paths, 
tutoriais interativos e listas de reprodução selecionadas de mais de 250 editoras, incluindo O'Reilly
Este livro está aqui para ajudá-lo a realizar seu trabalho. Em geral, se um código de exemplo 
for oferecido com este livro, você poderá usá-lo em seus programas e documentação. Você 
não precisa entrar em contato conosco para obter permissão, a menos que esteja 
reproduzindo uma parte significativa do código. Por exemplo, escrever um programa que 
usa vários blocos de código deste livro não requer permissão. A venda ou distribuição de um 
CD-ROM com exemplos dos livros da O'Reilly requer permissão. Responder a uma pergunta 
citando este livro e citando um código de exemplo não requer permissão. Incorporar uma 
quantidade significativa de código de exemplo deste livro na documentação do seu produto 
requer permissão.
Safári (anteriormente Safari Books Online) é uma plataforma de 
treinamento e referência baseada em membros para empresas, 
governos, educadores e indivíduos.
Usando exemplos de código
Safári O'Reilly
Se você acha que o uso de exemplos de código está fora do uso justo ou da permissão dada acima, 
sinta-se à vontade para nos contatar em permissions@oreilly.com.
https://github.com/ageron/handson-ml
http://oreilly.com/safari
mailto:permissions@oreilly.com
O'Reilly Media, Inc.
John Wiley & Sons, Syngress, Morgan Kaufmann, IBM Redbooks, Packt, Adobe Press, FT Press, 
Apress, Manning, New Riders, McGraw-Hill, Jones & Bartlett e Course Technology, entre outros.
Para obter mais informações sobre nossos livros, cursos, conferências e notícias, consulte nosso 
website em http://www.oreilly.com.
Sou incrivelmente grato a todas as pessoas incríveis que tiraram um tempo de suas vidas ocupadas 
para revisar meu livro com tantos detalhes. Agradeço a Pete Warden por responder a todas as 
minhas perguntas sobre o TensorFlow, revisar a Parte II, fornecer muitos insights interessantes e, 
claro,por fazer parte da equipe principal do TensorFlow. Você definitivamente deveria conferir
Envie comentários e perguntas sobre este livro para o editor:
Gostaria de agradecer aos meus colegas do Google, em particular à equipe de classificação de 
vídeos do YouTube, por me ensinar tanto sobre aprendizado de máquina. Eu nunca poderia ter 
começado este projeto sem eles. Agradecimentos especiais aos meus gurus pessoais de ML: 
Clément Courbet, Julien Dubois, Mathias Kende, Daniel Kitachewsky, James Pack, Alexander Pak, 
Anosh Raj, Vitor Sessak, Wiktor Tomczak, Ingrid von Glehn, Rich Washington e todos no YouTube 
Paris.
Para comentar ou fazer perguntas técnicas sobre este livro, envie um e-mail para 
bookquestions@oreilly.com .
Assista-nos no YouTube: http://www.youtube.com/oreillymedia
Temos uma página web para este livro, onde listamos errata, exemplos e qualquer informação 
adicional. Você pode acessar esta página em http://bit.ly/hands-on-machine-learning with-scikit-
learn-and-tensorflow.
1005 Gravenstein Highway North 
Sebastopol, CA 95472 
800-998-9938 (nos Estados Unidos ou Canadá) 
707-829-0515 (internacional ou local) 
707-829-0104 (fax)
Para obter mais informações, visite http://oreilly.com/safari.
Encontre-nos no Facebook: http://facebook.com/oreilly 
Siga-nos no Twitter: http://twitter.com/oreillymedia
Como entrar em contato conosco
Agradecimentos
Prefácio | xix
http://www.oreilly.com
mailto:bookquestions@oreilly.com
http://www.youtube.com/oreillymedia
http://bit.ly/hands-on-machine-learning-with-scikit-learn-and-tensorflow
http://oreilly.com/safari
http://facebook.com/oreilly
http://twitter.com/oreillymedia
E, claro, um gigantesco “obrigado” ao meu querido irmão Sylvain, que revisou cada capítulo, 
testou cada linha de código, forneceu feedback em praticamente todas as seções e me incentivou 
da primeira à última linha. Te amo bro!
Muito obrigado também a David Andrzejewski, que revisou a Parte I e forneceu feedback 
incrivelmente útil, identificando seções pouco claras e sugerindo como melhorá-las. Confira o site 
dele! Obrigado a Grégoire Mesnil, que revisou a Parte II e contribuiu com conselhos práticos 
muito interessantes sobre o treinamento de redes neurais.
Por último, mas não menos importante, sou infinitamente grato à minha amada esposa, 
Emmanuelle, e aos nossos três filhos maravilhosos, Alexandre, Rémi e Gabrielle, por me 
encorajarem a trabalhar arduamente neste livro, fazendo muitas perguntas (quem disse que você 
não pode ensinar redes neurais a uma criança de sete anos?), e até me trazer biscoitos e café. 
O que mais se pode sonhar?
Muito obrigado também à fantástica equipe da O'Reilly, em particular a Nicole Tache, que me 
deu um feedback perspicaz, sempre alegre, encorajador e prestativo. Agradeço também a Marie 
Beaugureau, Ben Lorica, Mike Loukides e Laurel Ruma por acreditarem neste projeto e me 
ajudarem a definir seu escopo. Obrigado a Matt Hacker e toda a equipe Atlas por responder a 
todas as minhas perguntas técnicas sobre formatação, asciidoc e LaTeX, e obrigado a Rachel 
Monaghan, Nick Adams e toda a equipe de produção por sua revisão final e suas centenas de 
correções.
o blog dele! Muito obrigado a Lukas Biewald por sua revisão minuciosa da Parte II: ele não deixou 
pedra sobre pedra, testou todo o código (e detectou alguns erros), fez muitas sugestões 
excelentes e seu entusiasmo foi contagiante. Você deveria dar uma olhada no blog dele e seus 
robôs legais! Agradecimentos a Justin Francis, que também revisou a Parte II minuciosamente, 
detectando erros e fornecendo ótimas percepções, em particular no Capítulo 16. Confira suas 
postagens no TensorFlow!
Agradeço também a Eddy Hung, Salim Sémaoune, Karim Matrah, Ingrid von Glehn, Iain Smears 
e Vincent Guilbeau por revisar a Parte I e fazer muitas sugestões úteis. E também gostaria de 
agradecer a meu sogro, Michel Tessier, ex-professor de matemática e agora um grande tradutor 
de Anton Chekhov, por me ajudar a resolver parte da matemática e notações deste livro e revisar 
a álgebra linear Jupyter. caderno.
xx | Prefácio
http://www.david-andrzejewski.com/
https://petewarden.com/
https://lukasbiewald.com/
https://goo.gl/Eu5u28
https://goo.gl/28ve8z
PARTE I
Aprendizado de máquina
Os fundamentos de
3
CAPÍTULO 1
Quando a maioria das pessoas ouve “Aprendizado de Máquina”, elas imaginam um robô: um mordomo 
confiável ou um Exterminador mortal, dependendo de quem você pergunta. Mas o aprendizado de 
máquina não é apenas uma fantasia futurista, ele já está aqui. Na verdade, ele existe há décadas em 
algumas aplicações especializadas, como o Reconhecimento Óptico de Caracteres (OCR). Mas o 
primeiro aplicativo de ML que realmente se tornou popular, melhorando a vida de centenas de milhões 
de pessoas, dominou o mundo na década de 1990: foi o filtro de spam.
Não é exatamente um Skynet autoconsciente, mas se qualifica tecnicamente como Aprendizado de 
Máquina (na verdade, ele aprendeu tão bem que você raramente precisa sinalizar um e-mail como 
spam). Ele foi seguido por centenas de aplicativos de ML que agora alimentam silenciosamente 
centenas de produtos e recursos que você usa regularmente, desde melhores recomendações até 
pesquisa por voz.
Então, antes de partirmos para explorar o continente do Machine Learning, vamos dar uma olhada no 
mapa e aprender sobre as principais regiões e os marcos mais notáveis: aprendizado supervisionado 
versus não supervisionado, aprendizado online versus batch, aprendizado baseado em instância 
versus aprendizado baseado em modelo . Em seguida, veremos o fluxo de trabalho de um projeto 
típico de ML, discutiremos os principais desafios que você pode enfrentar e abordaremos como avaliar 
e ajustar um sistema de aprendizado de máquina.
Este capítulo apresenta muitos conceitos fundamentais (e jargões) que todo cientista de dados deve 
saber de cor. Será uma visão geral de alto nível (o único capítulo sem muito código), tudo bastante 
simples, mas você deve certificar-se de que tudo esteja claro para você antes de prosseguir para o 
restante do livro. Então pegue um café e vamos começar!
Onde o aprendizado de máquina começa e onde termina? O que exatamente significa para uma 
máquina aprender alguma coisa? Se eu baixar uma cópia da Wikipedia, meu computador realmente 
“aprendeu” alguma coisa? É de repente mais inteligente? Neste capítulo, começaremos esclarecendo 
o que é Aprendizado de Máquina e por que você pode querer usá-lo.
O cenário de aprendizado de máquina
Diz-se que um programa de computador aprende com a experiência E em relação a alguma 
tarefa T e alguma medida de desempenho P, se seu desempenho em T, medido por P, melhora 
com a experiência E.
—Arthur Samuel, 1959
—Tom Mitchell, 1997
[Machine Learning é o] campo de estudo que dá aos computadores a capacidade de aprender 
sem serem explicitamente programados.
Se você já conhece todos os fundamentos do aprendizado de máquina, 
pode pular diretamente para o Capítulo 2. Se não tivercerteza, tente 
responder a todas as perguntas listadas no final do capítulo antes de prosseguir.
Machine Learning é a ciência (e a arte) de programar computadores para que eles possam aprender com os 
dados.
Nesse caso, a tarefa T é sinalizar spam para novos e-mails, a experiência E são os dados de treinamento e a 
medida de desempenho P precisa ser definida; por exemplo, você pode usar a proporção de emails classificados 
corretamente. Essa medida de desempenho específica é chamada de precisão e é frequentemente usada em 
tarefas de classificação.
E um mais orientado para a engenharia:
Se você apenas baixar uma cópia da Wikipedia, seu computador terá muito mais dados, mas não ficará melhor 
de repente em nenhuma tarefa. Portanto, não é Aprendizado de Máquina.
1. Primeiro, você deve observar como o spam normalmente se parece. Você pode notar que algumas palavras 
ou frases (como “4U”, “cartão de crédito”, “grátis” e “incrível”) tendem a aparecer bastante no assunto. 
Talvez você também perceba alguns outros padrões no nome do remetente, no corpo do e-mail e assim 
por diante.
Por exemplo, seu filtro de spam é um programa de aprendizado de máquina que pode aprender a sinalizar spam 
com base em exemplos de e-mails de spam (por exemplo, sinalizados pelos usuários) e exemplos de e-mails 
regulares (não spam, também chamados de “ham”). Os exemplos que o sistema usa para aprender são 
chamados de conjunto de treinamento. Cada exemplo de treinamento é chamado de instância de treinamento (ou amostra).
Considere como você escreveria um filtro de spam usando técnicas de programação tradicionais (Figura 1-1):
Aqui está uma definição um pouco mais geral:
4 | Capítulo 1: O Cenário do Machine Learning
Por que usar aprendizado de máquina?
O que é aprendizado de máquina?
Como o problema não é trivial, seu programa provavelmente se tornará uma longa lista de regras 
complexas – muito difíceis de manter.
3. Você testaria seu programa e repetiria as etapas 1 e 2 até que estivesse bom o suficiente.
preciso.
Figura 1-2. Abordagem de aprendizado de máquina
Em contraste, um filtro de spam baseado em técnicas de aprendizado de máquina aprende 
automaticamente quais palavras e frases são boas preditivas de spam, detectando padrões de 
palavras incomumente frequentes nos exemplos de spam em comparação com os exemplos de 
ham (Figura 1-2) . O programa é muito mais curto, mais fácil de manter e provavelmente mais
2. Você escreveria um algoritmo de detecção para cada um dos padrões observados e seu 
programa sinalizaria e-mails como spam se vários desses padrões fossem detectados.
Figura 1-1. A abordagem tradicional
Por que usar aprendizado de máquina? | 5
Além disso, se os spammers perceberem que todos os seus e-mails contendo “4U” estão bloqueados, eles 
podem começar a escrever “For U”. Um filtro de spam usando técnicas de programação tradicionais precisaria 
ser atualizado para sinalizar e-mails “Para U”. Se os spammers continuarem burlando seu filtro de spam, você 
precisará escrever novas regras para sempre.
Finalmente, o Machine Learning pode ajudar os humanos a aprender (Figura 1-4): os algoritmos de ML podem 
ser inspecionados para ver o que aprenderam (embora para alguns algoritmos isso possa ser complicado). 
Por exemplo, uma vez que o filtro de spam tenha sido treinado em spam suficiente, ele pode ser facilmente 
inspecionado para revelar a lista de palavras e combinações de palavras que acredita serem os melhores 
preditores de spam. Às vezes, isso revelará correlações insuspeitadas ou novas tendências e, assim, levará a 
uma melhor compreensão do problema.
Por outro lado, um filtro de spam baseado em técnicas de Machine Learning automaticamente percebe que 
“For U” se tornou incomumente frequente no spam sinalizado pelos usuários e começa a sinalizá-los sem sua 
intervenção (Figura 1-3) .
Outra área em que o Aprendizado de Máquina se destaca é para problemas que são muito complexos para 
abordagens tradicionais ou não possuem algoritmo conhecido. Por exemplo, considere o reconhecimento de 
fala: digamos que você queira começar simples e escrever um programa capaz de distinguir as palavras “um” 
e “dois”. Você pode notar que a palavra “dois” começa com um som agudo (“T”), então você pode codificar um 
algoritmo que mede a intensidade do som agudo e usá-lo para distinguir uns e dois. Obviamente, essa técnica 
não será dimensionada para milhares de palavras faladas por milhões de pessoas muito diferentes em 
ambientes ruidosos e em dezenas de idiomas. A melhor solução (pelo menos hoje) é escrever um algoritmo 
que aprenda por si só, dado muitos exemplos de gravações para cada palavra.
A aplicação de técnicas de ML para analisar grandes quantidades de dados pode ajudar a descobrir padrões 
que não eram imediatamente aparentes. Isso é chamado de mineração de dados.
Figura 1-3. Adaptando-se automaticamente à mudança
6 | Capítulo 1: O Cenário do Machine Learning
Figura 1-4. Machine Learning pode ajudar os humanos a aprender
• Problemas complexos para os quais não existe uma boa solução usando uma abordagem tradicional: as 
melhores técnicas de Machine Learning podem encontrar uma solução. • Ambientes 
flutuantes: um sistema de Machine Learning pode se adaptar a novos dados. • Obter insights sobre 
problemas complexos e grandes quantidades de dados.
• Se eles funcionam simplesmente comparando novos pontos de dados com pontos de dados conhecidos 
ou, em vez disso, detectam padrões nos dados de treinamento e criam um modelo preditivo, assim como 
os cientistas (aprendizagem baseada em instância versus baseada em modelo)
aprendizado)
ter.
• Se eles são ou não treinados com supervisão humana (supervisionado, não supervisionado, 
semissupervisionado e Aprendizado por Reforço) • Se eles podem 
ou não aprender de forma incremental em tempo real (online versus lote
• Problemas para os quais as soluções existentes exigem muito ajuste manual ou longas listas de regras: 
um algoritmo de aprendizado de máquina geralmente pode simplificar o código e executar apostas
Existem tantos tipos diferentes de sistemas de aprendizado de máquina que é útil classificá-los em categorias 
amplas com base em:
Esses critérios não são exclusivos; você pode combiná-los da maneira que quiser. Por exemplo, um filtro de 
spam de última geração pode aprender em tempo real usando uma rede neural profunda
Para resumir, Machine Learning é ótimo para:
Tipos de sistemas de aprendizado de máquina
Tipos de Sistemas de Aprendizado de Máquina | 7
modelo de trabalho treinado com exemplos de spam e ham; isso o torna um sistema de aprendizado supervisionado, baseado 
em modelo e on-line.
Aprendizado supervisionado/não supervisionado Os 
sistemas de aprendizado de máquina podem ser classificados de acordo com a quantidade e o tipo de supervisão que recebem 
durante o treinamento. Existem quatro categorias principais: aprendizado supervisionado,aprendizado não supervisionado, 
aprendizado semissupervisionado e aprendizado por reforço.
Aprendizado 
supervisionado No aprendizado supervisionado, os dados de treinamento que você alimenta ao algoritmo incluem as soluções 
desejadas, chamadas de rótulos (Figura 1-5).
Vejamos cada um desses critérios um pouco mais de perto.
Uma tarefa típica de aprendizado supervisionado é a classificação. O filtro de spam é um bom exemplo disso: ele é treinado com 
muitos e-mails de exemplo junto com sua classe (spam ou ham), e deve aprender a classificar novos e-mails.
Outra tarefa típica é prever um valor numérico de destino, como o preço de um carro, dado um conjunto de características 
(quilometragem, idade, marca etc.) chamadas de preditores. Esse tipo de tarefa é chamado de regressão (Figura 1.6).1 Para 
treinar o sistema, você precisa fornecer muitos exemplos de carros, incluindo seus preditores e rótulos (isto é, seus preços).
Figura 1-5. Um conjunto de treinamento rotulado para aprendizado supervisionado (por exemplo, classificação de spam)
1 Curiosidade: esse nome estranho é um termo estatístico introduzido por Francis Galton enquanto estudava o fato 
de que filhos de pessoas altas tendem a ser mais baixos que seus pais. Como as crianças eram mais baixas, ele 
chamou essa regressão à média. Esse nome foi então aplicado aos métodos que ele usou para analisar 
correlações entre variáveis.
8 | Capítulo 1: O Cenário do Machine Learning
2 Algumas arquiteturas de redes neurais podem ser não supervisionadas, como autoencoders e máquinas Boltzmann restritas. 
Eles também podem ser semi-supervisionados, como em redes de crenças profundas e pré-treinamento não supervisionado.
Tipos de Sistemas de Aprendizado de Máquina | 9
Em Machine Learning, um atributo é um tipo de dados (por exemplo, 
“Mileage”), enquanto um recurso tem vários significados dependendo do 
contexto, mas geralmente significa um atributo mais seu valor (por exemplo, 
“Mileage = 15.000”). No entanto, muitas pessoas usam as palavras atributo 
e recurso de forma intercambiável.
Observe que alguns algoritmos de regressão também podem ser usados para classificação e vice-
versa. Por exemplo, a regressão logística é comumente usada para classificação, pois pode gerar 
um valor que corresponde à probabilidade de pertencer a uma determinada classe (por exemplo, 
20% de chance de ser spam).
Aqui estão alguns dos algoritmos de aprendizado supervisionado mais importantes (abordados 
neste livro):
Figura 1-6. Regressão
• Árvores de Decisão e Florestas Aleatórias
• Redes neurais2
• k-Vizinhos mais próximos 
• Regressão linear • 
Regressão logística • 
Máquinas de vetores de suporte (SVMs)
• Visualização e redução de dimensionalidade
— Análise de Componentes Principais (PCA)
Aprendizado não 
supervisionado No aprendizado não supervisionado, como você pode imaginar, os dados de treinamento 
não são rotulados (Figura 1-7). O sistema tenta aprender sem um professor.
— Núcleo PCA
Figura 1-7. Um conjunto de treinamento não rotulado para aprendizado não supervisionado
— Incorporação linear local (LLE) — 
Incorporação estocástica de vizinhos com distribuição t (t-SNE)
Aqui estão alguns dos algoritmos de aprendizado não supervisionados mais importantes (abordaremos a 
redução de dimensionalidade no Capítulo 8):
• Aprendizagem de regra de associação
• Agrupamento
- A priori
— k-Means
— Eclat
— Análise Hierárquica de Cluster (HCA)
Por exemplo, digamos que você tenha muitos dados sobre os visitantes do seu blog. Você pode querer 
executar um algoritmo de agrupamento para tentar detectar grupos de visitantes semelhantes (Figura 
1-8). Em nenhum momento você informa ao algoritmo a que grupo pertence um visitante: ele encontra 
essas conexões sem a sua ajuda. Por exemplo, pode perceber que 40% de seus visitantes são homens 
que adoram histórias em quadrinhos e geralmente leem seu blog à noite, enquanto 20% são jovens 
amantes de ficção científica que o visitam nos fins de semana e assim por diante. Se você usar um 
algoritmo de agrupamento hierárquico, ele também poderá subdividir cada grupo em grupos menores. 
Isso pode ajudá-lo a direcionar suas postagens para cada grupo.
— Maximização da Expectativa
10 | Capítulo 1: O Cenário do Machine Learning
Tipos de Sistemas de Aprendizado de Máquina | 11
Figura 1-8. Agrupamento
Os algoritmos de visualização também são bons exemplos de algoritmos de aprendizado não 
supervisionado: você os alimenta com muitos dados complexos e não rotulados, e eles produzem 
uma representação 2D ou 3D de seus dados que podem ser facilmente plotados (Figura 1-9) . 
Esses algoritmos tentam preservar o máximo de estrutura possível (por exemplo, tentando evitar 
que clusters separados no espaço de entrada se sobreponham na visualização), para que você 
possa entender como os dados são organizados e talvez identificar padrões insuspeitos.
Figura 1-9. Exemplo de uma visualização t-SNE destacando clusters semânticos3
3 Observe como os animais estão bem separados dos veículos, como os cavalos estão perto dos cervos, mas longe dos pássaros,
e assim por diante. Figura reproduzida com permissão de Socher, Ganjoo, Manning e Ng (2013), “T-SNE 
visualization of the semantic word space”.
Por fim, outra tarefa não supervisionada comum é o aprendizado de regras de associação, em que 
o objetivo é pesquisar grandes quantidades de dados e descobrir relações interessantes entre 
atributos. Por exemplo, suponha que você possua um supermercado. Executar uma regra de 
associação em seus registros de vendas pode revelar que as pessoas que compram molho barbecue 
e batatas fritas também tendem a comprar bife. Assim, você pode querer colocar esses itens 
próximos uns dos outros.
Uma tarefa relacionada é a redução de dimensionalidade, na qual o objetivo é simplificar os dados 
sem perder muita informação. Uma maneira de fazer isso é mesclar vários recursos correlacionados 
em um. Por exemplo, a quilometragem de um carro pode estar muito correlacionada com sua idade, 
então o algoritmo de redução de dimensionalidade irá mesclá-los em um recurso que representa o 
desgaste do carro. Isso é chamado de extração de recursos.
Ainda outra importante tarefa não supervisionada é a detecção de anomalias – por exemplo, detectar 
transações de cartão de crédito incomuns para evitar fraudes, detectar defeitos de fabricação ou 
remover automaticamente outliers de um conjunto de dados antes de alimentá-lo para outro algoritmo 
de aprendizado. O sistema é treinado com instâncias normais e, quando vê uma nova instância, 
pode dizer se ela se parece com uma normal ou se é provavelmente uma anomalia (consulte a 
Figura 1-10).
Figura 1-10. Detecção de anomalia
Muitas vezes, é uma boa ideia tentar reduzir a dimensão de seus dados de 
treinamento usando um algoritmo de redução de dimensionalidade antes de 
alimentá-lo com outro algoritmo de aprendizado de máquina (como um algoritmo 
de aprendizado supervisionado).Ele funcionará muito mais rápido, os dados 
ocuparão menos espaço em disco e memória e, em alguns casos, também 
poderá funcionar melhor.
12 | Capítulo 1: O Cenário do Machine Learning
Alguns serviços de hospedagem de fotos, como o Google Fotos, são bons exemplos disso. Depois de carregar 
todas as suas fotos de família para o serviço, ele reconhece automaticamente que a mesma pessoa A aparece 
nas fotos 1, 5 e 11, enquanto outra pessoa B aparece nas fotos 2, 5 e 7. Esta é a parte não supervisionada do 
algoritmo (clustering). Agora tudo que o sistema precisa é que você diga quem são essas pessoas. Apenas uma 
etiqueta por pessoa,4 e é capaz de nomear todos em cada foto, o que é útil para pesquisar fotos.
A maioria dos algoritmos de aprendizado semissupervisionados são combinações de algoritmos não 
supervisionados e supervisionados. Por exemplo, redes de crenças profundas (DBNs) são baseadas em 
componentes não supervisionados chamados máquinas de Boltzmann restritas (RBMs) empilhadas umas sobre 
as outras. Os RBMs são treinados sequencialmente de maneira não supervisionada e, em seguida, todo o 
sistema é ajustado usando técnicas de aprendizado supervisionado.
Figura 1-11. Aprendizagem semisupervisionada
Aprendizado 
semisupervisionado Alguns algoritmos podem lidar com dados de treinamento parcialmente rotulados, 
geralmente muitos dados não rotulados e um pouco de dados rotulados. Isso é chamado de aprendizado 
semissupervisionado (Figura 1-11).
Aprendizagem por Reforço 
A Aprendizagem por Reforço é uma besta muito diferente. O sistema de aprendizado, chamado de agente neste 
contexto, pode observar o ambiente, selecionar e executar ações e obter recompensas em troca (ou penalidades 
na forma de recompensas negativas, como na Figura 1.12 ). Ele deve então aprender por si mesmo qual é a 
melhor estratégia, chamada de política, para obter a maior recompensa ao longo do tempo. Uma política define 
qual ação o agente deve escolher quando estiver em uma determinada situação.
4 É aí que o sistema funciona perfeitamente. Na prática, geralmente cria alguns clusters por pessoa e, às vezes, 
mistura duas pessoas parecidas; portanto, você precisa fornecer alguns rótulos por pessoa e limpar manualmente 
alguns clusters.
Tipos de Sistemas de Aprendizado de Máquina | 13
Aprendizado 
em lote No aprendizado em lote, o sistema é incapaz de aprender de forma incremental: ele 
deve ser treinado usando todos os dados disponíveis. Isso geralmente leva muito tempo e 
recursos de computação, por isso geralmente é feito offline. Primeiro o sistema é treinado, 
depois é lançado em produção e roda sem aprender mais; apenas aplica o que aprendeu. Isso 
é chamado de aprendizado único.
Por exemplo, muitos robôs implementam algoritmos de aprendizado por reforço para aprender 
a andar. O programa AlphaGo da DeepMind também é um bom exemplo de Aprendizagem por 
Reforço: chegou às manchetes em março de 2016, quando derrotou o campeão mundial Lee 
Sedol no jogo Go. Aprendeu sua política vencedora analisando milhões de jogos e depois 
jogando muitos jogos contra si mesmo. Observe que o aprendizado foi desativado durante os 
jogos contra o campeão; O AlphaGo estava apenas aplicando a política que havia aprendido.
Felizmente, todo o processo de treinamento, avaliação e lançamento de uma Máquina
O sistema de aprendizado pode ser automatizado com bastante facilidade (como mostrado na Figura 1-3), portanto, mesmo um
Se você deseja que um sistema de aprendizado em lote conheça novos dados (como um novo 
tipo de spam), é necessário treinar uma nova versão do sistema do zero no conjunto de dados 
completo (não apenas os novos dados, mas também os dados antigos ), pare o sistema antigo 
e substitua-o pelo novo.
Batch e Online Learning Outro 
critério usado para classificar os sistemas de Machine Learning é se o sistema pode ou não 
aprender de forma incremental a partir de um fluxo de dados recebidos.
Figura 1-12. Aprendizagem por Reforço
14 | Capítulo 1: O Cenário do Machine Learning
O aprendizado online é ótimo para sistemas que recebem dados como um fluxo contínuo (por exemplo, preços 
de ações) e precisam se adaptar às mudanças de forma rápida ou autônoma. Também é uma boa opção
Além disso, o treinamento no conjunto completo de dados requer muitos recursos de computação (CPU, espaço 
de memória, espaço em disco, E/S de disco, E/S de rede, etc.). Se você tiver muitos dados e automatizar seu 
sistema para treinar do zero todos os dias, isso acabará custando muito dinheiro. Se a quantidade de dados for 
enorme, pode até ser impossível usar um algoritmo de aprendizado em lote.
Figura 1-13. Aprendizagem online
Aprendizado 
online No aprendizado online, você treina o sistema de forma incremental, alimentando-o com instâncias de 
dados sequencialmente, individualmente ou por pequenos grupos chamados mini-lotes. Cada etapa de 
aprendizado é rápida e barata, de modo que o sistema pode aprender sobre os novos dados em tempo real, à 
medida que chegam (consulte a Figura 1-13).
Essa solução é simples e geralmente funciona bem, mas o treinamento usando o conjunto completo de dados 
pode levar muitas horas, então você normalmente treinaria um novo sistema apenas a cada 24 horas ou até 
mesmo semanalmente. Se o seu sistema precisa se adaptar a dados que mudam rapidamente (por exemplo, 
para prever preços de ações), então você precisa de uma solução mais reativa.
Felizmente, a melhor opção em todos esses casos é usar algoritmos capazes de aprender de forma incremental.
sistema de aprendizagem em lote pode se adaptar à mudança. Basta atualizar os dados e treinar uma nova 
versão do sistema do zero sempre que necessário.
Por fim, se o seu sistema precisar aprender de forma autônoma e tiver recursos limitados (por exemplo, um 
aplicativo para smartphone ou um rover em Marte), carregar grandes quantidades de dados de treinamento e 
consumir muitos recursos para treinar por horas a cada dia é um showstopper.
Tipos de Sistemas de Aprendizado de Máquina | 15
Figura 1-14. Usando o aprendizado on-line para lidar com grandes conjuntos de dados
Os algoritmos de aprendizado online também podem ser usados para treinar sistemas em grandes conjuntos de dados que não 
cabem na memória principal de uma máquina (isso é chamado de aprendizado fora do núcleo). O algoritmo carrega parte dos 
dados, executa uma etapa de treinamento nesses dados e repete o processo até executar todos os dados (consulte a Figura 1-14).
Por outro lado, se você definir uma taxa de aprendizado baixa, o sistema terá mais inércia; ou seja, aprenderá mais lentamente, 
mas também será menos sensível ao ruído nos novos dados ou a sequências de pontos de dados não representativos.
Um grande desafio com o aprendizado on-line é que, se dados incorretos forem alimentados ao sistema, o desempenho do sistema 
diminuirá gradualmente. Se estivermos falando de um sistema ativo,seus clientes perceberão. Por exemplo, dados incorretos 
podem vir de um sensor com defeito em um robô ou de alguém enviando spam para um mecanismo de pesquisa para tentar ter 
uma classificação alta na pesquisa
Um parâmetro importante dos sistemas de aprendizado on-line é a rapidez com que eles devem se adaptar às mudanças de dados: 
isso é chamado de taxa de aprendizado. Se você definir uma taxa de aprendizado alta, seu sistema se adaptará rapidamente aos 
novos dados, mas também tenderá a esquecer rapidamente os dados antigos (você não deseja que um filtro de spam sinalize 
apenas os últimos tipos de spam que foram exibidos) .
se você tiver recursos de computação limitados: uma vez que um sistema de aprendizado online tenha aprendido sobre novas 
instâncias de dados, ele não precisa mais delas, então você pode descartá-las (a menos que você queira reverter para um estado 
anterior e “reproduzir” o dados). Isso pode economizar uma quantidade enorme de espaço.
Todo esse processo geralmente é feito off-line (ou seja, não no sistema ao vivo), 
portanto aprendizado on-line pode ser um nome confuso. Pense nisso como um 
aprendizado incremental.
16 | Capítulo 1: O Cenário do Machine Learning
Existem duas abordagens principais para generalização: aprendizado baseado em instância e aprendizado baseado 
em modelo.
Isso é chamado de aprendizado baseado em instâncias: o sistema aprende os exemplos de cor e depois generaliza 
para novos casos usando uma medida de similaridade (Figura 1.15).
A maioria das tarefas de aprendizado de máquina trata de fazer previsões. Isso significa que, dado um número de 
exemplos de treinamento, o sistema precisa ser capaz de generalizar para exemplos que nunca viu antes. Ter uma boa 
medida de desempenho nos dados de treinamento é bom, mas insuficiente; o verdadeiro objetivo é ter um bom 
desempenho em novas instâncias.
Aprendizado baseado em instância versus aprendizado baseado em 
modelo Outra maneira de categorizar os sistemas de aprendizado de máquina é como eles generalizam.
Em vez de apenas sinalizar e-mails idênticos a e-mails de spam conhecidos, seu filtro de spam pode ser programado 
para também sinalizar e-mails muito semelhantes a e-mails de spam conhecidos. Isso requer uma medida de 
similaridade entre dois e-mails. Uma medida de similaridade (muito básica) entre dois e-mails pode ser contar o número 
de palavras que eles têm em comum. O sistema sinalizaria um e-mail como spam se ele tivesse muitas palavras em 
comum com um e-mail de spam conhecido.
resultados. Para reduzir esse risco, você precisa monitorar seu sistema de perto e desligar imediatamente o aprendizado 
(e possivelmente reverter para um estado de trabalho anterior) se detectar uma queda no desempenho. Você também 
pode querer monitorar os dados de entrada e reagir a dados anormais (por exemplo, usando um algoritmo de detecção 
de anomalias).
Aprendizagem baseada em 
instâncias Possivelmente a forma mais trivial de aprendizagem é simplesmente aprender de cor. Se você criasse um 
filtro de spam dessa maneira, ele apenas sinalizaria todos os e-mails idênticos aos e-mails que já foram sinalizados 
pelos usuários - não é a pior solução, mas certamente não é a melhor.
Figura 1-15. Aprendizagem baseada em instância
Tipos de Sistemas de Aprendizado de Máquina | 17
Aprendizado baseado em 
modelo Outra maneira de generalizar a partir de um conjunto de exemplos é construir um modelo desses exemplos e, em 
seguida, usar esse modelo para fazer previsões. Isso é chamado de aprendizado baseado em modelo (Figura 1.16).
Por exemplo, suponha que você queira saber se o dinheiro faz as pessoas felizes, então você baixa os dados do Better 
Life Index do site da OCDE bem como estatísticas sobre o PIB per capita do site do FMI. Então você une as tabelas e 
classifica por PIB per capita. A Tabela 1-1 mostra um trecho do que você obtém.
Vamos plotar os dados para alguns países aleatórios (Figura 1-17).
Figura 1-16. Aprendizagem baseada em modelo
Tabela 1-1. O dinheiro torna as pessoas mais felizes?
50.962
12.240 4.9
7.3
Coréia
Estados Unidos 55.805
27.195
7.2
5.8
França
18 | Capítulo 1: O Cenário do Machine Learning
País
37.675
PIB per capita (USD) Satisfação com a vida
6.5
Hungria
Austrália
https://goo.gl/0Eht9W
http://goo.gl/j1MSKe
Tipos de Sistemas de Aprendizado de Máquina | 19
5
Figura 1-17. você vê uma tendência aqui?
Equação 1-1. Um modelo linear simples
Este modelo tem dois parâmetros de modelo, ÿ0 e ÿ1 .
Parece haver uma tendência aqui! Embora os dados sejam ruidosos (isto é, parcialmente aleatórios), 
parece que a satisfação com a vida aumenta mais ou menos linearmente à medida que o PIB per 
capita do país aumenta. Então você decide modelar a satisfação com a vida como uma função linear 
do PIB per capita. Esta etapa é chamada de seleção de modelo: você selecionou um modelo linear de 
satisfação com a vida com apenas um atributo, PIB per capita (Equação 1-1).
Figura 1-18. Alguns modelos lineares possíveis
Ajustando esses parâmetros, você pode 
fazer seu modelo representar qualquer função linear, conforme mostrado na Figura 1-18.
5 Por convenção, a letra grega ÿ (theta) é freqüentemente usada para representar os parâmetros do modelo.
li f e_satis f ação = ÿ0 + ÿ1 × PIB_per_capita
7 Tudo bem se você ainda não entender todo o código; apresentaremos o Scikit-Learn nos próximos capítulos.
20 | Capítulo 1: O Cenário do Machine Learning
Agora o modelo ajusta os dados de treinamento o mais próximo possível (para um modelo linear), como você 
pode ver na Figura 1-19.
Como você pode saber quais valores farão seu modelo funcionar melhor? Para responder a essa pergunta, você 
precisa especificar uma medida de desempenho. Você pode definir uma função de utilidade (ou função de 
adequação) que mede o quão bom é o seu modelo ou pode definir uma função de custo que mede o quão ruim 
ele é. Para problemas de regressão linear, as pessoas normalmente usam uma função de custo que mede a 
distância entre as previsões do modelo linear e os exemplos de treinamento; o objetivo é minimizar essa distância.
Figura 1-19. O modelo linear que melhor se ajusta aos dados de treinamento
Você finalmente está pronto para executar o modelo para fazer previsões. Por exemplo, digamos que você queira 
saber o quão felizes os cipriotas estão, e os dados da OCDE não têm a resposta.
É aqui que entra o algoritmo de regressão linear: você o alimenta com seus exemplos de treinamento e ele 
encontra os parâmetros que fazem o modelo linear se ajustar melhor aos seus dados.
Felizmente, você pode usar seu modelo para fazer uma boa previsão: você procura o PIB per capita de Chipre, 
encontra $ 22.587 e, em seguida, aplica seu modelo e descobre que a satisfação com a vida provavelmente está 
em torno de 4,85 + 22.587 × 4,91 × 10- 5 = 5,96.
Isso é chamado de treinamento do modelo. Em nosso caso, o algoritmodescobre que os valores ótimos dos 
parâmetros são ÿ0 = 4,85 e ÿ1 = 4,91 × 10–5 .
Para aguçar seu apetite, o Exemplo 1-1 mostra o código Python que carrega os dados, os prepara,6 cria um 
gráfico de dispersão para visualização e então treina um modelo linear e faz uma previsão.7
Antes de usar seu modelo, você precisa definir os valores de parâmetro ÿ0 e ÿ1 .
6 O código assume que prepare_country_stats() já está definido: ele mescla os dados de PIB e satisfação com a 
vida em um único dataframe do Pandas.
Tipos de Sistemas de Aprendizado de Máquina | 21
com este:
Se você tivesse usado um algoritmo de aprendizado baseado em instância, 
teria descoberto que a Eslovênia tem o PIB per capita mais próximo ao de 
Chipre (US$ 20.732) e, como os dados da OCDE nos dizem que a 
satisfação com a vida dos eslovenos é de 5,7, você teria previu uma 
satisfação com a vida de 5,7 para Chipre. Se você diminuir um pouco o 
zoom e olhar para os dois países mais próximos, encontrará Portugal e 
Espanha com satisfações de vida de 5,1 e 6,5, respectivamente. Fazendo 
a média desses três valores, você obtém 5,77, que é bem próximo da sua 
previsão baseada em modelo. Este algoritmo simples é chamado de 
regressão k-Nearest Neighbors (neste exemplo, k = 3).
Substituir o modelo de regressão linear pela regressão de k-vizinhos mais 
próximos no código anterior é tão simples quanto substituir esta linha:
Exemplo 1-1. Treinando e executando um modelo linear usando o Scikit-Learn
# Prepare os dados 
country_stats = prepare_country_stats(oecd_bli, gdp_per_capita)
# Faça uma previsão para Chipre 
X_new = [[22587]] # PIB per capita de Chipre 
print(lin_reg_model.predict(X_new)) # outputs [[ 5.96242338]]
import matplotlib 
import matplotlib.pyplot as plt 
import numpy as np 
import pandas as pd 
import sklearn
X = np.c_[country_stats["PIB per capita"]] y = 
np.c_[country_stats[" Satisfação com a vida"]]
# Visualize os dados 
country_stats.plot(kind='scatter', x="PIB per capita", y='Satisfação com a vida') plt.show()
clf = sklearn.neighbors.KNeighborsRegressor(n_neighbors=3)
# Carregar os 
dados oecd_bli = pd.read_csv("oecd_bli_2015.csv", milhares=',') 
gdp_per_capita = pd.read_csv("gdp_per_capita.csv",thousands=',',delimiter='\t',
# Selecione um modelo 
linear lin_reg_model = sklearn.linear_model.LinearRegression()
clf = sklearn.linear_model.LinearRegression()
codificação='latin1', na_values="n/a")
# Treine o modelo 
lin_reg_model.fit(X, y)
22 | Capítulo 1: O Cenário do Machine Learning
• Você o treinou nos dados de treinamento (ou seja, o algoritmo de aprendizado procurou o
Resumindo:
valores de parâmetro de modelo que minimizam uma função de custo).
• Finalmente, você aplicou o modelo para fazer previsões sobre novos casos (isso é chamado de inferência), 
esperando que esse modelo generalize bem.
Resumindo, como sua principal tarefa é selecionar um algoritmo de aprendizado e treiná-lo com alguns dados, 
as duas coisas que podem dar errado são “algoritmos ruins” e “dados ruins”. Vamos começar com exemplos 
de dados incorretos.
• Você estudou os dados.
Quantidade insuficiente de dados de treinamento Para 
que uma criança aprenda o que é uma maçã, basta você apontar para uma maçã e dizer “maçã” (possivelmente 
repetindo esse procedimento algumas vezes). Agora a criança é capaz de reconhecer maçãs em todos os 
tipos de cores e formas. Gênio.
É assim que um projeto típico de aprendizado de máquina se parece. No Capítulo 2, você experimentará isso 
em primeira mão, passando por um projeto de ponta a ponta.
O aprendizado de máquina ainda não chegou lá; são necessários muitos dados para que a maioria dos 
algoritmos de Aprendizado de Máquina funcione corretamente. Mesmo para problemas muito simples, você 
normalmente precisa de milhares de exemplos, e para problemas complexos, como reconhecimento de 
imagem ou fala, você pode precisar de milhões de exemplos (a menos que você possa reutilizar partes de um 
modelo existente).
• Você selecionou um modelo.
Cobrimos muito terreno até agora: agora você sabe do que realmente se trata o aprendizado de máquina, por 
que é útil, quais são algumas das categorias mais comuns de sistemas de ML e como é um fluxo de trabalho 
de projeto típico. Agora vamos ver o que pode dar errado no aprendizado e impedir que você faça previsões 
precisas.
Se tudo correr bem, seu modelo fará boas previsões. Caso contrário, você pode precisar usar mais atributos 
(taxa de emprego, saúde, poluição do ar, etc.), obter mais ou melhores dados de treinamento de qualidade ou 
talvez selecionar um modelo mais poderoso (por exemplo, um modelo de Regressão Polinomial) .
Principais desafios do aprendizado de máquina
10 “A eficácia irracional dos dados,” Peter Norvig et al. (2009).
8 Por exemplo, saber se deve escrever “para”, “dois” ou “também”, dependendo do contexto.
9 Figura reproduzida com permissão de Banko e Brill (2001), “Learning Curves for Confusion Set Disamÿ
Principais Desafios do Aprendizado de Máquina | 23
A eficácia irracional dos dados
biguação”.
Figura 1-20. A importância dos dados versus algoritmos9
A ideia de que os dados importam mais do que os algoritmos para problemas complexos foi ainda 
mais popularizada por Peter Norvig et al. em um artigo intitulado “The Unreasonable Effectiveness of 
Data” publicado em 2009.10 Deve-se observar, no entanto, que conjuntos de dados de tamanho 
pequeno e médio ainda são muito comuns e nem sempre é fácil ou barato obter dados de treinamento 
extras; portanto, não abandone os algoritmos ainda.
Em um jornal famoso publicado em 2001, os pesquisadores da Microsoft Michele Banko e Eric Brill 
mostraram que algoritmos de aprendizado de máquina muito diferentes, incluindo alguns bastante 
simples, tiveram um desempenho quase idêntico em um problema complexo de desambiguação de 
linguagem natural8, uma vez que receberam dados suficientes (como você pode ver na Figura 1 -20).
Como os autores colocam: “esses resultados sugerem que podemos querer reconsiderar o 
compromisso entre gastar tempo e dinheiro no desenvolvimento de algoritmos versus gastá-lo no 
desenvolvimento de corpus”.
http://goo.gl/q6LaZ8
http://goo.gl/q6LaZ8
http://goo.gl/R5enIE
Um exemplo famoso de viés de amostragem 
Talvez o exemplo mais famoso de viés de amostragem tenha acontecido durante a eleição 
presidencial dos Estados Unidos em 1936, que colocou Landon contra Roosevelt: a Literary 
Digest realizou uma pesquisa muito grande, enviando correspondência para cerca de 10 milhões 
de pessoas. Obteve 2,4 milhões de respostas e previu com grande confiança que Landon obteria 57% dos votos.
Dados de treinamento não representativos 
Para generalizar bem, é crucial que seus dados de treinamento sejam representativos dos novos 
casos para os quais você deseja generalizar. Isso é verdade se você usa aprendizado baseado em 
instância ou aprendizado baseado em modelo.
24 | Capítulo 1: O Cenário do Machine Learning
Figura 1-21. Uma amostrade treinamento mais representativa
Ao usar um conjunto de treinamento não representativo, treinamos um modelo que provavelmente não fará 
previsões precisas, especialmente para países muito pobres e muito ricos.
Por exemplo, o conjunto de países que usamos anteriormente para treinar o modelo linear não era 
perfeitamente representativo; faltavam alguns países. A Figura 1-21 mostra a aparência dos dados quando 
você adiciona os países ausentes.
Se você treinar um modelo linear com esses dados, obterá a linha sólida, enquanto o modelo antigo é 
representado pela linha pontilhada. Como você pode ver, adicionar alguns países ausentes não apenas 
altera significativamente o modelo, mas também deixa claro que um modelo linear tão simples provavelmente 
nunca funcionará bem. Parece que os países muito ricos não são mais felizes do que os países 
moderadamente ricos (na verdade, eles parecem mais infelizes) e, inversamente, alguns países pobres 
parecem mais felizes do que muitos países ricos.
É crucial usar um conjunto de treinamento que seja representativo dos casos para os quais você deseja 
generalizar. Isso geralmente é mais difícil do que parece: se a amostra for muito pequena, você terá ruído 
de amostragem (ou seja, dados não representativos como resultado do acaso), mas mesmo amostras muito 
grandes podem não ser representativas se o método de amostragem for falho. Isso é chamado de viés de 
amostragem.
Principais Desafios do Aprendizado de Máquina | 25
Como diz o ditado: lixo entra, lixo sai. Seu sistema só será capaz de aprender se os dados de treinamento 
contiverem recursos relevantes suficientes e não muitos irrelevantes. Uma parte crítica do sucesso de um 
projeto de Machine Learning é criar um bom conjunto de recursos para treinar. Esse processo, chamado de 
engenharia de recursos, envolve:
• Se algumas instâncias forem claramente discrepantes, pode ser útil simplesmente descartá-las ou tentar 
corrigir os erros manualmente.
• Se algumas instâncias estiverem faltando alguns recursos (por exemplo, 5% de seus clientes não 
especificaram sua idade), você deve decidir se deseja ignorar esse atributo completamente, ignorar 
essas instâncias, preencher os valores ausentes (por exemplo, com a idade mediana), ou treinar um 
modelo com o recurso e um modelo sem ele, e assim por diante.
Em vez disso, Roosevelt venceu com 62% dos votos. A falha estava no método de amostragem da Literary Digest:
• Em segundo lugar, menos de 25% das pessoas que receberam a pesquisa responderam. Novamente, isso introduz um 
viés de amostragem, ao excluir pessoas que não se importam muito com política, pessoas que não gostam do Literary 
Digest e outros grupos-chave. Este é um tipo especial de viés de amostragem chamado viés de não resposta.
Aqui está outro exemplo: digamos que você queira construir um sistema para reconhecer vídeos de música funk. Uma maneira 
de construir seu conjunto de treinamento é pesquisar “música funk” no YouTube e usar os vídeos resultantes. Mas isso 
pressupõe que o mecanismo de pesquisa do YouTube retorne um conjunto de vídeos representativos de todos os videoclipes 
de funk no YouTube. Na realidade, é provável que os resultados da pesquisa sejam tendenciosos para artistas populares (e 
se você mora no Brasil, encontrará muitos vídeos de “funk carioca”, que não parecem nada com James Brown).
• Primeiro, para obter os endereços para enviar as pesquisas, o Literary Digest usou listas telefônicas, listas de assinantes 
de revistas, listas de sócios de clubes e coisas do gênero. Todas essas listas tendem a favorecer as pessoas mais 
ricas, que têm maior probabilidade de votar nos republicanos (daí Landon).
Por outro lado, de que outra forma você pode obter um grande conjunto de treinamento?
Recursos irrelevantes
Dados de baixa qualidade 
Obviamente, se seus dados de treinamento estiverem cheios de erros, discrepâncias e ruído (por 
exemplo, devido a medições de baixa qualidade), será mais difícil para o sistema detectar os padrões 
subjacentes, portanto, é menos provável que seu sistema executar bem. Muitas vezes, vale a pena 
gastar tempo limpando seus dados de treinamento. A verdade é que a maioria dos cientistas de dados 
gasta uma parte significativa de seu tempo fazendo exatamente isso. Por exemplo:
Figura 1-22. Sobreajustando os dados de treinamento
• Extração de recursos: combinando recursos existentes para produzir um mais útil (como vimos anteriormente, os 
algoritmos de redução de dimensionalidade podem ajudar).
A Figura 1-22 mostra um exemplo de um modelo polinomial de alto grau de satisfação com a vida que superajusta 
fortemente os dados de treinamento. Embora tenha um desempenho muito melhor nos dados de treinamento do que 
o modelo linear simples, você realmente confiaria em suas previsões?
Superajustando os dados de treinamento 
Digamos que você esteja visitando um país estrangeiro e o taxista o engane. Você pode ficar tentado a dizer que 
todos os taxistas daquele país são ladrões. Generalizar demais é algo que nós, humanos, fazemos com muita 
frequência e, infelizmente, as máquinas podem cair na mesma armadilha se não tomarmos cuidado. Em Machine 
Learning, isso é chamado de overfitting: significa que o modelo funciona bem nos dados de treinamento, mas não 
generaliza bem.
características.
Agora que vimos muitos exemplos de dados ruins, vamos ver alguns exemplos de algoritmos ruins.
• Seleção de recursos: selecionando os recursos mais úteis para treinar entre os existentes
Modelos complexos, como redes neurais profundas, podem detectar padrões sutis nos dados, mas se o conjunto de 
treinamento for ruidoso ou muito pequeno (o que introduz ruído de amostragem), é provável que o modelo detecte 
padrões no próprio ruído. Obviamente, esses padrões não serão generalizados para novas instâncias. Por exemplo, 
digamos que você alimente seu modelo de satisfação com a vida com muitos outros atributos, incluindo alguns pouco 
informativos, como o nome do país. Nesse caso, um modelo complexo pode detectar padrões como o fato de que 
todos os países nos dados de treinamento com aw em seu nome têm uma satisfação com a vida maior que 7: Nova 
Zelândia (7,3), Noruega (7,4), Suécia (7,2) , e Suíça (7,5). Quão confiante
• Criação de novos recursos por meio da coleta de novos dados.
26 | Capítulo 1: O Cenário do Machine Learning
Principais Desafios do Aprendizado de Máquina | 27
você acha que a regra W-satisfação se generaliza para Ruanda ou Zimbábue? Obviamente, esse 
padrão ocorreu nos dados de treinamento por puro acaso, mas o modelo não tem como dizer se 
um padrão é real ou simplesmente o resultado de ruído nos dados.
Restringir um modelo para torná-lo mais simples e reduzir o risco de overfitting é chamado de 
regularização. Por exemplo, o modelo linear que definimos anteriormente tem dois parâmetros, 
ÿ0 e ÿ1 . Isso dá ao algoritmo de aprendizado dois graus de liberdadepara adaptar o modelo aos 
dados de treinamento: ele pode ajustar a altura (ÿ0 ) e a inclinação (ÿ1 ) da linha. Se forçássemos 
ÿ1 = 0, o algoritmo teria apenas um grau de liberdade e teria muito mais dificuldade em ajustar os 
dados corretamente: tudo o que poderia fazer era mover a linha para cima ou para baixo para 
chegar o mais próximo possível das instâncias de treinamento, então acabaria em torno da média. 
Um modelo bem simples mesmo! Se permitirmos que o algoritmo modifique ÿ1, mas o forçarmos 
a mantê-lo pequeno, então o algoritmo de aprendizado terá efetivamente algo entre um e dois 
graus de liberdade. Ele produzirá um modelo mais simples do que com dois graus de liberdade, 
mas mais complexo do que com apenas um. Você deseja encontrar o equilíbrio certo entre ajustar 
os dados perfeitamente e manter o modelo simples o suficiente para garantir uma boa 
generalização.
A Figura 1-23 mostra três modelos: a linha pontilhada representa o modelo original que foi 
treinado com alguns países ausentes, a linha tracejada é nosso segundo modelo treinado com 
todos os países e a linha sólida é um modelo linear treinado com os mesmos dados de o primeiro 
modelo, mas com uma restrição de regularização. Você pode ver que a regularização forçou o 
modelo a ter uma inclinação menor, que se ajusta um pouco menos aos dados de treinamento 
nos quais o modelo foi treinado, mas na verdade permite que ele generalize melhor para novos exemplos.
são:
• Simplificar o modelo selecionando um com menos parâmetros (por exemplo, um 
modelo linear em vez de um modelo polinomial de alto grau), reduzindo o número 
de atributos nos dados de treinamento ou restringindo o modelo
O overfitting ocorre quando o modelo é muito complexo em relação à quantidade e ruído 
dos dados de treinamento. As possíveis soluções
e remover outliers)
• Para coletar mais dados de treinamento 
• Para reduzir o ruído nos dados de treinamento (por exemplo, corrigir erros de dados
A quantidade de regularização a ser aplicada durante o aprendizado pode ser controlada por um hiperparâmetro. 
Um hiperparâmetro é um parâmetro de um algoritmo de aprendizado (não do modelo). Como tal, não é afetado 
pelo próprio algoritmo de aprendizado; deve ser definido antes do treino e permanece constante durante o 
treino. Se você definir o hiperparâmetro de regularização para um valor muito grande, obterá um modelo quase 
plano (uma inclinação próxima de zero); o algoritmo de aprendizado quase certamente não superajustará os 
dados de treinamento, mas será menos provável que encontre uma boa solução. O ajuste de hiperparâmetros 
é uma parte importante da construção de um sistema de aprendizado de máquina (você verá um exemplo 
detalhado no próximo capítulo).
As principais opções para corrigir esse problema são:
parâmetro)
Recuando Agora você 
já sabe muito sobre Machine Learning. No entanto, passamos por tantos conceitos que você pode estar se 
sentindo um pouco perdido, então vamos dar um passo atrás e olhar para o quadro geral:
Underfitting dos dados de treinamento Como 
você pode imaginar, o underfitting é o oposto do overfitting: ocorre quando seu modelo é muito simples para 
aprender a estrutura subjacente dos dados. Por exemplo, um modelo linear de satisfação com a vida é propenso 
a subajuste; a realidade é apenas mais complexa do que o modelo, então suas previsões são imprecisas, 
mesmo nos exemplos de treinamento.
Figura 1-23. A regularização reduz o risco de overfitting
• Selecionando um modelo mais poderoso, com mais parâmetros • 
Alimentando melhores recursos para o algoritmo de aprendizado (engenharia de recursos) • 
Reduzindo as restrições no modelo (por exemplo, reduzindo a hiperregulação
28 | Capítulo 1: O Cenário do Machine Learning
Testando e Validando | 29
É comum usar 80% dos dados para treinamento e manter 20% para 
teste.
Uma opção melhor é dividir seus dados em dois conjuntos: o conjunto de treinamento e o conjunto de 
teste. Como esses nomes indicam, você treina seu modelo usando o conjunto de treinamento e o testa 
usando o conjunto de teste. A taxa de erro em novos casos é chamada de erro de generalização (ou erro 
fora da amostra) e, ao avaliar seu modelo no conjunto de teste, você obtém uma estimativa desse erro. 
Esse valor informa o desempenho do seu modelo em instâncias que nunca viu antes.
• Em um projeto de ML, você coleta dados em um conjunto de treinamento e alimenta o conjunto de 
treinamento para um algoritmo de aprendizado. Se o algoritmo for baseado em modelo, ele ajusta 
alguns parâmetros para ajustar o modelo ao conjunto de treinamento (ou seja, para fazer boas 
previsões no próprio conjunto de treinamento) e, com sorte, também será capaz de fazer boas 
previsões em novos casos. Se o algoritmo for baseado em instâncias, ele apenas memoriza os 
exemplos e usa uma medida de similaridade para generalizar para novas instâncias.
A única maneira de saber o quão bem um modelo irá generalizar para novos casos é realmente 
experimentá-lo em novos casos. Uma maneira de fazer isso é colocar seu modelo em produção e 
monitorar o desempenho dele. Isso funciona bem, mas se seu modelo for terrivelmente ruim, seus 
usuários reclamarão - não é a melhor ideia.
baseado em instância ou baseado em modelo, e assim por diante.
Há apenas um último tópico importante a ser abordado: depois de treinar um modelo, você não quer 
apenas “esperar” que ele generalize para novos casos. Você deseja avaliá-lo e ajustá-lo, se necessário. 
Vamos ver como.
• Aprendizado de máquina é fazer com que as máquinas melhorem em alguma tarefa aprendendo com 
os dados, em vez de ter que codificar regras explicitamente. • 
Existem muitos tipos diferentes de sistemas de ML: supervisionados ou não, em lote ou online,
Se o erro de treinamento for baixo (ou seja, seu modelo comete poucos erros no conjunto de treinamento), 
mas o erro de generalização for alto, isso significa que seu modelo está superajustando os dados de 
treinamento.
• O sistema não funcionará bem se o seu conjunto de treinamento for muito pequeno ou se os dados 
não forem representativos, ruidosos ou poluídos com recursos irrelevantes (entrada de lixo, saída 
de lixo). Por fim, seu modelo não precisa ser nem muito simples (caso em que será subajustado) 
nem muito complexo (nesse caso, será superajustado).
Testando e validando
30 | Capítulo 1: O Cenário do Machine Learning
Em um famoso artigo de 1996, 11 David Wolpert demonstrou que, se você não fizer 
absolutamente nenhuma suposição sobre os dados, não há razão para preferir um modelo 
a outro. Isso é chamado de teorema No Free Lunch (NFL). Para alguns conjuntos de dados, o melhor
Um modelo é uma versão simplificada das observações. As simplificações destinam-se a 
descartar os detalhes supérfluos que provavelmente não serão generalizados para novas 
instâncias. No entanto, para decidir quaisdados descartar e quais dados manter, você deve 
fazer suposições. Por exemplo, um modelo linear assume que os dados são fundamentalmente 
lineares e que a distância entre as instâncias e a linha reta é apenas ruído, que pode ser 
ignorado com segurança.
Agora suponha que o modelo linear generalize melhor, mas você deseja aplicar alguma regularização 
para evitar o overfitting. A questão é: como você escolhe o valor do hiperparâmetro de regularização? 
Uma opção é treinar 100 modelos diferentes usando 100 valores diferentes para esse hiperparâmetro. 
Suponha que você encontre o melhor valor de hiperparâmetro que produz um modelo com o menor 
erro de generalização, digamos apenas 5% de erro.
O problema é que você mediu o erro de generalização várias vezes no conjunto de teste e adaptou o 
modelo e os hiperparâmetros para produzir o melhor modelo para esse conjunto. Isso significa que é 
improvável que o modelo funcione tão bem em novos dados.
Para evitar “desperdiçar” muitos dados de treinamento em conjuntos de validação, uma técnica comum 
é usar a validação cruzada: o conjunto de treinamento é dividido em subconjuntos complementares e 
cada modelo é treinado em uma combinação diferente desses subconjuntos e validado em relação às 
partes restantes . Uma vez selecionados o tipo de modelo e os hiperparâmetros, um modelo final é 
treinado usando esses hiperparâmetros no conjunto de treinamento completo e o erro generalizado é 
medido no conjunto de teste.
Portanto, avaliar um modelo é bastante simples: basta usar um conjunto de teste. Agora suponha que 
você esteja hesitando entre dois modelos (digamos, um modelo linear e um modelo polinomial): como 
você pode decidir? Uma opção é treinar ambos e comparar o quão bem eles generalizam usando o 
conjunto de teste.
Então você lança este modelo em produção, mas infelizmente ele não funciona tão bem quanto o 
esperado e produz 15% de erros. O que acabou de acontecer?
Uma solução comum para este problema é ter um segundo conjunto de validação chamado de conjunto 
de validação. Você treina vários modelos com vários hiperparâmetros usando o conjunto de treinamento, 
seleciona o modelo e os hiperparâmetros com melhor desempenho no conjunto de validação e, quando 
estiver satisfeito com seu modelo, executa um único teste final no conjunto de teste para obter uma 
estimativa de o erro de generalização.
11 “A falta de distinções a priori entre algoritmos de aprendizagem”, D. Wolperts (1996).
Teorema do almoço grátis
http://goo.gl/3zaHIZ
Exercícios | 31
5. Você pode citar quatro tarefas não supervisionadas comuns?
ções?
6. Que tipo de algoritmo de Machine Learning você usaria para permitir que um robô caminhe em vários 
terrenos desconhecidos?
12. Qual é a diferença entre um parâmetro de modelo e um hiperparâmetro de um algoritmo de aprendizado?
7. Que tipo de algoritmo você usaria para segmentar seus clientes em vários
13. O que os algoritmos de aprendizado baseado em modelo procuram? Qual é a estratégia mais comum 
que eles usam para ter sucesso? Como eles fazem previsões?
grupos?
14. Você pode citar quatro dos principais desafios do aprendizado de máquina?
Neste capítulo, cobrimos alguns dos conceitos mais importantes em Aprendizado de Máquina. Nos próximos 
capítulos vamos mergulhar mais fundo e escrever mais código, mas antes disso, certifique-se de saber como 
responder às seguintes perguntas:
8. Você enquadraria o problema de detecção de spam como um problema de aprendizado supervisionado
15. Se seu modelo tem um ótimo desempenho nos dados de treinamento, mas generaliza mal para novas 
instâncias, o que está acontecendo? Você pode citar três soluções possíveis?
1. Como você definiria Machine Learning?
problema de aprendizado não supervisionado?
16. O que é um conjunto de teste e por que você deseja usá-lo?
2. Você pode citar quatro tipos de problemas em que ela se destaca?
9. O que é um sistema de aprendizagem online?
3. O que é um conjunto de treinamento rotulado?
10. O que é aprendizagem fora do núcleo?
4. Quais são as duas tarefas supervisionadas mais comuns?
11. Que tipo de algoritmo de aprendizado depende de uma medida de similaridade para fazer previsões
model é um modelo linear, enquanto para outros conjuntos de dados é uma rede neural. 
Não existe um modelo que a priori tenha garantia de funcionar melhor (daí o nome do 
teorema). A única maneira de saber com certeza qual modelo é o melhor é avaliar todos 
eles. Como isso não é possível, na prática você faz algumas suposições razoáveis sobre 
os dados e avalia apenas alguns modelos razoáveis. Por exemplo, para tarefas simples, 
você pode avaliar modelos lineares com vários níveis de regularização e, para um 
problema complexo, pode avaliar várias redes neurais.
exercícios
17. Qual é o propósito de um conjunto de validação?
18. O que pode dar errado se você ajustar hiperparâmetros usando o conjunto de teste?
As soluções para esses exercícios estão disponíveis no Apêndice A.
19. O que é validação cruzada e por que você a preferiria a um conjunto de validação?
32 | Capítulo 1: O Cenário do Machine Learning
1 O projeto de exemplo é totalmente fictício; o objetivo é apenas ilustrar as principais etapas de um Machine Learning
projeto, não para aprender nada sobre o negócio imobiliário.
Neste capítulo, você passará por um exemplo de projeto de ponta a ponta, fingindo ser um cientista de dados recém-
contratado em uma empresa imobiliária.1 Aqui estão as principais etapas pelas quais você passará:
4. Prepare os dados para algoritmos de aprendizado de máquina.
8. Inicie, monitore e mantenha seu sistema.
3. Descubra e visualize os dados para obter insights.
7. Apresente sua solução.
2. Obtenha os dados.
• Repositórios de dados abertos populares:
6. Ajuste seu modelo.
Quando você está aprendendo sobre Machine Learning, é melhor realmente experimentar dados do mundo real, não 
apenas conjuntos de dados artificiais. Felizmente, existem milhares de conjuntos de dados abertos para escolher, 
abrangendo todos os tipos de domínios. Aqui estão alguns lugares que você pode procurar para obter dados:
1. Olhe para o quadro geral.
5. Selecione um modelo e treine-o.
CAPÍTULO 2
Trabalhando com dados reais
33
Projeto de aprendizado de máquina de ponta a ponta
& Cartas de Probabilidade 33, no. 3 (1997): 291–297.
— Conjuntos de dados da AWS da Amazon
Neste capítulo, escolhemos o conjunto de dados California Housing Price do repositório StatLib2 (consulte a Figura 
2-1). Este conjunto de dados foi baseado em dados do censo da Califórnia de 1990. Não é exatamente recente (você 
ainda podia comprar uma boa casa na Bay Area na época), mas tem muitas qualidades para aprender, então vamos 
fingir que são dados recentes. Também adicionamos um atributo categórico e removemos alguns recursos para fins de 
ensino.
— Conjuntos de dados do Kaggle
• Outras páginas listando muitos repositórios de dados abertospopulares: — Lista 
da Wikipédia de conjuntos de dados de aprendizado de máquina 
— Pergunta do Quora.com — 
Subreddit de conjuntos de dados
— Repositório de aprendizado de máquina da UC Irvine
— http://dataportals.org/ — http://
opendatamonitor.eu/ — http://quandl.com/
• Meta portais (eles listam repositórios de dados abertos):
Figura 2-1. Preços de imóveis na Califórnia
2 O conjunto de dados original apareceu em R. Kelley Pace e Ronald Barry, “Sparse Spatial Autoregressions,” Statistics
34 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
http://aws.amazon.com/fr/datasets/
https://www.kaggle.com/datasets
https://goo.gl/SJHN2k
http://goo.gl/zDR78y
https://www.reddit.com/r/datasets
http://archive.ics.uci.edu/ml/
http://dataportals.org/
http://opendatamonitor.eu/
http://quandl.com/
Enquadre o problema
3 Uma informação fornecida a um sistema de aprendizado de máquina costuma ser chamada de sinal em referência ao método de Shannon
Como você é um cientista de dados bem organizado, a primeira coisa a 
fazer é retirar sua lista de verificação do projeto de aprendizado de máquina. 
Você pode começar com o do Apêndice B; deve funcionar razoavelmente 
bem para a maioria dos projetos de aprendizado de máquina, mas certifique-
se de adaptá-lo às suas necessidades. Neste capítulo, examinaremos 
muitos itens da lista de verificação, mas também pularemos alguns, porque 
são autoexplicativos ou porque serão discutidos em capítulos posteriores.
Olhe para o quadro grande
teoria da informação: você quer uma alta relação sinal/ruído.
Veja o quadro geral | 35
Seu modelo deve aprender com esses dados e ser capaz de prever o preço médio da habitação em qualquer 
distrito, considerando todas as outras métricas.
Seu chefe responde que o resultado do seu modelo (uma previsão do preço mediano da habitação de um 
distrito) será enviado para outro sistema de Aprendizado de Máquina (consulte a Figura 2-2), juntamente 
com muitos outros sinais. 3 Esse sistema de jusante determinará se vale a pena ou não investir em 
determinada área. Fazer isso certo é crítico, pois afeta diretamente as
Bem-vindo à Machine Learning Housing Corporation! A primeira tarefa que você deve realizar é construir um 
modelo de preços de moradias na Califórnia usando os dados do censo da Califórnia. Esses dados têm 
métricas como população, renda média, preço médio da habitação e assim por diante para cada grupo de 
quarteirões na Califórnia. Grupos de quarteirões são a menor unidade geográfica para a qual o US Census 
Bureau publica dados de amostra (um grupo de quarteirões geralmente tem uma população de 600 a 3.000 
pessoas). Vamos chamá-los apenas de “distritos” para abreviar.
A primeira pergunta a fazer ao seu chefe é qual é exatamente o objetivo do negócio; construir um modelo 
provavelmente não é o objetivo final. Como a empresa espera usar e se beneficiar desse modelo? Isso é 
importante porque determinará como você enquadrará o problema, quais algoritmos selecionará, qual medida 
de desempenho usará para avaliar seu modelo e quanto esforço deverá despender para ajustá-lo.
novo.
36 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Por outro lado, um componente quebrado pode passar despercebido por algum tempo se o 
monitoramento adequado não for implementado. Os dados ficam obsoletos e o desempenho geral 
do sistema cai.
Os componentes normalmente são executados de forma assíncrona. Cada componente extrai uma 
grande quantidade de dados, processa-os e despeja o resultado em outro armazenamento de dados 
e, algum tempo depois, o próximo componente no pipeline extrai esses dados e cospe sua própria 
saída e assim por diante. Cada componente é bastante independente: a interface entre os 
componentes é simplesmente o armazenamento de dados. Isso torna o sistema bastante simples de 
entender (com a ajuda de um gráfico de fluxo de dados), e diferentes equipes podem se concentrar 
em diferentes componentes. Além disso, se um componente quebrar, os componentes a jusante 
podem continuar a funcionar normalmente (pelo menos por um tempo) usando apenas a última 
saída do componente quebrado. Isso torna a arquitetura bastante robusta.
Figura 2-2. Um pipeline de aprendizado de máquina para investimentos imobiliários
A próxima pergunta a fazer é como é a solução atual (se houver). Muitas vezes, ele fornecerá um desempenho 
de referência, bem como insights sobre como resolver o problema.
Ok, com todas essas informações você está pronto para começar a projetar seu sistema.
Seu chefe responde que os preços da habitação no distrito são atualmente estimados manualmente por 
especialistas: uma equipe reúne informações atualizadas sobre um distrito (excluindo os preços médios da 
habitação) e usa regras complexas para chegar a uma estimativa. Isso é caro e demorado, e suas estimativas 
não são grandes; sua taxa de erro típica é de cerca de 15%.
Primeiro, você precisa enquadrar o problema: é supervisionado, não supervisionado ou Aprendizado por 
Reforço? É uma tarefa de classificação, uma tarefa de regressão ou outra coisa? Deve
Pipelines 
Uma sequência de componentes de processamento de dados é chamada de pipeline de dados. 
Pipelines são muito comuns em sistemas de Machine Learning, pois há muitos dados para manipular 
e muitas transformações de dados para aplicar.
h =
1
hRMSE ,
você usa técnicas de aprendizado em lote ou aprendizado on-line? Antes de continuar a ler, faça uma pausa 
e tente responder a essas perguntas por si mesmo.
A próxima etapa é selecionar uma medida de desempenho. Uma medida de desempenho típica para 
problemas de regressão é o Root Mean Square Error (RMSE). Ele mede o desvio padrão4 dos erros que o 
sistema comete em suas previsões. Por exemplo, um RMSE igual a 50.000 significa que cerca de 68% das 
previsões do sistema estão dentro de $ 50.000 do valor real e cerca de 95% das previsões estão dentro de 
$ 100.000 do valor real.5 A Equação 2-1 mostra a fórmula matemática para calcular o RMSE.
Você encontrou as respostas? Vejamos: é claramente uma tarefa típica de aprendizado supervisionado, 
pois você recebe exemplos de treinamento rotulados (cada instância vem com o resultado esperado, ou 
seja, o preço médio da habitação do distrito). Além disso, também é uma tarefa de regressão típica, já que 
você é solicitado a prever um valor. Mais especificamente, este é um problema de regressão multivariada, 
pois o sistema usará vários recursos para fazer uma previsão (ele usará a população do distrito, a renda 
mediana, etc.). No primeiro capítulo, você previu a satisfação com a vida com base em apenas uma 
característica, o PIB per capita, portanto, foi um problema de regressão univariada. Finalmente, não há fluxo 
contínuo de dados entrando no sistema, não há nenhuma necessidade particular de se ajustar rapidamente 
aos dados que mudam rapidamente e os dados são pequenos o suficiente para caber na memória, portanto,o aprendizado em lote simples deve funcionar bem.
Equação 2-1. Raiz do erro quadrático médio (RMSE)
m i = 1
eu
4 O desvio padrão, geralmente denotado por ÿ (a letra grega sigma), é a raiz quadrada da variância, que é a média do desvio quadrado da média.
5 Quando uma feição tem uma distribuição normal em forma de sino (também chamada de distribuição gaussiana), que é muito comum, a regra 
“68-95-99,7” se aplica: cerca de 68% dos valores caem dentro de 1ÿ da média, 95% em 2ÿ e 99,7% em 3ÿ.
2
eu ÿ y
m
Veja o quadro geral | 37
ÿ
Selecione uma medida de desempenho
Se os dados fossem enormes, você poderia dividir seu trabalho de 
aprendizado em lote em vários servidores (usando a técnica MapReduce, 
como veremos mais adiante) ou poderia usar uma técnica de 
aprendizado online.
1
2 T
1999 T
6 Lembre-se de que o operador de transposição transforma um vetor de coluna em um vetor de linha (e vice-versa).
1 T
2000T
38 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Notações
º
6
=
— Por exemplo, se o primeiro distrito no conjunto de dados estiver localizado na longitude –
118,29°, latitude 33,91° e tiver 1.416 habitantes com uma renda média de US$ 38.372 e 
o valor médio da casa for US$ 156.400 (ignorando os outros recursos por enquanto) , 
então:
= 156, 400
ÿ
ÿ118 . 29
• X é uma matriz contendo todos os valores de recursos (excluindo rótulos) de todas as 
instâncias na linha é igual à transposição
ÿ
ÿ
33 . 91
o conjunto de dados. Há uma linha por instância e o i de x 
(i), anotado (x (i)) T
Essa equação apresenta várias notações muito comuns de aprendizado de máquina que usaremos 
ao longo deste livro:
1, 416
ÿ118 . 29 33 . 91 1, 416 38, 372
• m é o número de instâncias no conjunto de dados em que você está medindo o RMSE.
38, 372
ÿ
— Por exemplo, se você estiver avaliando o RMSE em um conjunto de validação de 2.000 
distritos, então m = 2.000.
.
ÿ
(i) é um vetor de todos os valores de recurso (excluindo o rótulo) de i (i) é 
seu rótulo (o valor de saída desejado para aquela instância). o conjunto de dados, e y
=
— Por exemplo, se o primeiro distrito for como descrito, então a matriz X parece
=
ª instância em
e:
assim:
• x
1 
ano
m
eu
1k
,
• O cálculo da soma dos absolutos (MAE) corresponde à norma ÿ1 , notada ÿ · ÿ1 .
Equação 2-2. Erro Absoluto Médio
Embora o RMSE seja geralmente a medida de desempenho preferida para tarefas de regressão, 
em alguns contextos você pode preferir usar outra função. Por exemplo, suponha que existam 
muitos distritos discrepantes. Nesse caso, você pode considerar o uso do Erro Absoluto Médio 
(também chamado de Desvio Absoluto Médio; consulte a Equação 2-2):
. ÿ0 apenas fornece a cardinalidade do vetor (isto é,
• Calcular a raiz de uma soma de quadrados (RMSE) corresponde à norma euclidiana: é a 
noção de distância com a qual você está familiarizado. Também é chamada de norma ÿ2 , 
notada ÿ · ÿ2 (ou apenas ÿ · ÿ).
Tanto o RMSE quanto o MAE são formas de medir a distância entre dois vetores: o vetor de 
previsões e o vetor de valores alvo. Várias medidas de distância, ou normas, são possíveis:
kkk = v0 + v1 + ÿ + 
vn k o número de 
elementos), e ÿÿ dá o valor absoluto máximo no vetor. • Quanto maior o índice de norma, 
mais ele se concentra em grandes valores e negligencia os pequenos. É por isso que o 
RMSE é mais sensível a outliers do que o MAE. Mas quando
Às vezes é chamada de norma de Manhattan porque mede a distância entre dois pontos 
em uma cidade se você só puder viajar ao longo de quarteirões ortogonais da cidade. • 
Mais geralmente, a norma ÿk de um vetor v contendo n elementos é definida como
• RMSE(X,h) é a função de custo medida no conjunto de exemplos usando seu
recebe um vetor de características x (i) de uma instância, ele gera um valor 
previsto ÿ para essa instância (ÿ é pronunciado “y-hat”).
h = h
distrito é $ 158.400, então ÿ 
(1) distrito é ÿ = 2.000. – y
eu ÿ y
Usamos fonte itálica minúscula para valores escalares (como m ou y (i)) e nomes de funções 
(como h), fonte negrito minúscula para vetores (como x (i)) e fonte negrito maiúscula para matrizes 
(como X).
1
• h é a função de previsão do seu sistema, também chamada de hipótese. Quando seu sistema 
= h(x (i))
hipótese h.
m i = 1
— Por exemplo, se o seu sistema prevê que o preço médio da habitação no primeiro = h(x 
(1)) = 158.400. O erro de previsão para este
MAE ÿ
Veja o quadro geral | 39
(eu)
(1)
(1)
$ export ML_PATH="$HOME/ml" 
$ mkdir -p $ML_PATH
# Você pode alterar o caminho se preferir
7 A versão mais recente do Python 3 é recomendada. O Python 2.7+ também deve funcionar bem, mas está obsoleto.
Verifique as suposições Por 
fim, é uma boa prática listar e verificar as suposições feitas até agora (por você ou por outros); 
isso pode detectar problemas sérios desde o início. Por exemplo, os preços distritais gerados pelo 
seu sistema serão inseridos em um sistema de aprendizado de máquina downstream, e assumimos 
que esses preços serão usados como tal. Mas e se o sistema downstream realmente converter os 
preços em categorias (por exemplo, “barato”, “médio” ou “caro”) e então usar essas categorias em 
vez dos próprios preços? Nesse caso, acertar o preço não é nada importante; seu sistema só 
precisa acertar a categoria. Se for assim, o problema deveria ter sido enquadrado como uma 
tarefa de classificação, não uma tarefa de regressão. Você não quer descobrir isso depois de 
trabalhar em um sistema de regressão por meses.
Você precisará de vários módulos Python: Jupyter, NumPy, Pandas, Matplotlib e Scikit-Learn. Se 
você já tem o Jupyter rodando com todos esses módulos instalados, pode pular com segurança 
para “Baixar os dados” na página 43. Se você ainda não os tem, há muitas maneiras de instalá-los 
(e suas dependências). Você pode usar o sistema de empacotamento do seu sistema (por 
exemplo, apt-get no Ubuntu, ou MacPorts ou HomeBrew no
É hora de sujar as mãos. Não hesite em pegar seu laptop e percorrer os exemplos de 
código a seguir em um notebook Jupyter. O notebook Jupyter completo está disponível em 
https://github.com/ageron/handson-ml.
outliers são exponencialmente raros (como em uma curva em forma de sino), o RMSE 
funciona muito bem e geralmente é o preferido.
Felizmente, depois de conversar com a equipe responsável pelo sistema downstream, você está 
confiante de que eles realmente precisam dos preços reais, não apenas das categorias. Ótimo! Está 
tudo pronto, as luzes estão verdes e você pode começar a codificar agora!
Crie o espaço de trabalho 
Primeiro você precisa ter o Python instalado. Provavelmente já está instalado em seu sistema. 
Caso contrário, você pode obtê-lo em https://www.python.org/. 
7 Em seguida, você precisa criar um diretório de espaço de trabalho para seu código e conjuntos 
de dados do Machine Learning. Abra umterminal e digite os seguintes comandos (após os prompts $ ):
Obter os dados
40 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
https://github.com/ageron/handson-ml
https://www.python.org/
Criando um ambiente isolado
8 Mostraremos as etapas de instalação usando pip em um bash shell em um sistema Linux ou macOS. Pode ser necessário adaptar esses 
comandos ao seu próprio sistema. No Windows, recomendamos a instalação do Anaconda.
9 Você pode precisar ter direitos de administrador para executar este comando; em caso afirmativo, tente prefixá-lo com sudo.
macOS), instale uma distribuição Scientific Python como Anaconda e use seu sistema de 
empacotamento, ou apenas use o próprio sistema de empacotamento do Python, pip, que é 
incluído por padrão com os instaladores binários do Python (desde o Python 2.7.9).8 Você pode 
verifique se o pip está instalado digitando o seguinte comando:
Você deve certificar-se de ter uma versão recente do pip instalada, pelo menos> 1.4 para suportar 
a instalação do módulo binário (também conhecido como rodas). Para atualizar o módulo pip, 
digite:9
Novo executável python em [...]/ml/env/bin/python3.5 Também 
criando executável em [...]/ml/env/bin/python Instalando setuptools, 
pip, wheel...feito.
$ cd $ML_PATH 
$ virtualenv env 
Usando o prefixo base '[...]'
$ pip3 --versão pip 
9.0.1 de [...]/lib/python3.5/site-packages (python 3.5)
pip-9.0.1 instalado com sucesso
$ cd $ ML_PATH 
$ fonte env/bin/activate
virtualenv instalado com sucesso
$ pip3 install --upgrade pip Coletando 
pip [...]
$ pip3 install --user --upgrade virtualenv Coletando 
virtualenv [...]
Agora toda vez que você quiser ativar este ambiente, basta abrir um terminal e digitar:
Se você gostaria de trabalhar em um ambiente isolado (o que é fortemente recomendado 
para que você possa trabalhar em diferentes projetos sem ter versões de bibliotecas 
conflitantes), instale o virtualenv executando o seguinte comando pip:
Agora você pode criar um ambiente Python isolado digitando:
Enquanto o ambiente estiver ativo, qualquer pacote que você instalar usando o pip será 
instalado neste ambiente isolado, e o Python só terá acesso a estes pacotes (caso você 
também queira acessar os pacotes do site do sistema, deverá criar o ambiente
Obtenha os dados | 41
$ python3 -c "importar jupyter, matplotlib, numpy, pandas, scipy, sklearn"
$ pip3 install --upgrade jupyter matplotlib numpy pandas scipy scikit-learn Coletando jupyter 
Baixando jupyter-1.0.0-
py2.py3-none-any.whl
$ jupyter notebook [I 
15:24 NotebookApp] Servindo notebooks do diretório local: [...]/ml [I 15:24 NotebookApp] 
0 kernels ativos [I 15:24 NotebookApp] O Jupyter 
Notebook está sendo executado em: http:/ /localhost:8888/ [I 15:24 NotebookApp] Use Control-C para 
parar este servidor e desligar todos os kernels (duas vezes para pular a confirmação).
Coletando matplotlib [...]
10 Observe que o Jupyter pode lidar com várias versões do Python e até com muitas outras linguagens, como R ou
usando a opção --system-site-packages do virtualenv ). Confira a documentação do 
virtualenv para obter mais informações.
Não deve haver nenhuma saída e nenhum erro. Agora você pode iniciar o Jupyter digitando:
Agora você pode instalar todos os módulos necessários e suas dependências usando este simples 
comando pip:
Agora crie um novo notebook Python clicando no botão New e selecionando a versão adequada 
do Python10 (consulte a Figura 2-3).
Isso faz três coisas: primeiro, cria um novo arquivo de notebook chamado Untitled.ipynb em seu 
espaço de trabalho; em segundo lugar, ele inicia um kernel do Jupyter Python para executar este 
notebook; e terceiro, abre este notebook em uma nova guia. Você deve começar renomeando este 
notebook para “Housing” (isso irá renomear automaticamente o arquivo para Housing.ipynb) 
clicando em Untitled e digitando o novo nome.
Para verificar sua instalação, tente importar cada módulo assim:
Um servidor Jupyter agora está sendo executado em seu terminal, ouvindo a porta 8888. Você 
pode visitar esse servidor abrindo seu navegador da Web em http://localhost:8888/ (isso geralmente 
acontece automaticamente quando o servidor é iniciado). Você deve ver seu diretório de espaço 
de trabalho vazio (contendo apenas o diretório env se você seguiu as instruções anteriores do 
virtualenv).
Oitava.
42 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Obtenha os dados | 43
Um notebook contém uma lista de células. Cada célula pode conter código executável ou texto formatado. 
No momento, o notebook contém apenas uma célula de código vazia, denominada “In [1]:”. Tente digitar 
print("Hello world!") na célula e clique no botão play (veja a Figura 2-4) ou pressione Shift-Enter. Isso envia 
a célula atual para o kernel Python deste notebook, que a executa e retorna a saída. O resultado é exibido 
abaixo da célula, e como chegamos ao final do notebook, uma nova célula é criada automaticamente. 
Percorra o tour da interface do usuário no menu Ajuda do Jupyter para aprender o básico.
Em ambientes típicos, seus dados estariam disponíveis em um banco de dados relacional (ou algum outro 
armazenamento de dados comum) e espalhados por várias tabelas/documentos/arquivos. Para
Figura 2-4. Olá mundo notebook Python
Figura 2-3. Seu espaço de trabalho no Jupyter
Baixe os dados
HOUSING_URL = DOWNLOAD_ROOT + HOUSING_PATH + "/housing.tgz"
HOUSING_PATH = "conjuntos de dados/habitação"
csv_path = os.path.join(housing_path, "housing.csv") return 
pd.read_csv(csv_path)
tgz_path = os.path.join(housing_path, "housing.tgz") 
urllib.request.urlretrieve(housing_url, tgz_path) habitação_tgz = 
tarfile.open(tgz_path) 
habitação_tgz.extractall(path=housing_path) 
habitação_tgz.close()
DOWNLOAD_ROOT = "https://raw.githubusercontent.com/ageron/handson-ml/master/"
def load_housing_data(housing_path=HOUSING_PATH):
se não os.path.isdir(housing_path): 
os.makedirs(housing_path)
importar pandas como pd
import os 
import tarfile 
from six.moves import urllib
def fetch_housing_data(housing_url=HOUSING_URL, hosting_path=HOUSING_PATH):
caderno.
armazenamento de dados.
Para acessá-lo, primeiro você precisa obter suas credenciais e autorizações de acesso,11 e se familiarizar com 
o esquema de dados. Neste projeto, no entanto, as coisas são muito mais simples: você apenas baixará um 
único arquivo compactado, habitação.tgz, que contém um arquivo de valores separados por vírgula (CSV) 
chamado habitação.csv com todos os dados.
Agora vamos carregar os dados usando Pandas. Mais uma vez você deve escrever uma pequena função para 
carregar os dados:
Você pode usar seu navegador para baixá-lo e executar tar xzf habitação.tgz para descompactar o arquivo e 
extrair o arquivo CSV, mas é preferível criar uma pequena função para fazer isso. É útil principalmente se os 
dados mudam regularmente, pois permite que você escreva um pequeno script que pode ser executado sempre 
que precisar buscar os dados mais recentes (ou você pode configurar um trabalho agendado para fazerisso 
automaticamente em intervalos regulares). Automatizar o processo de busca de dados também é útil se você 
precisar instalar o conjunto de dados em várias máquinas.
Agora, quando você chama fetch_housing_data(), ele cria um diretório datasets/housing em seu espaço de 
trabalho, baixa o arquivohousing.tgz e extrai ohousing.csv dele neste diretório.
Aqui está a função para buscar os dados:12
11 Você também pode precisar verificar as restrições legais, como campos privados que nunca devem ser copiados para
12 Em um projeto real, você salvaria esse código em um arquivo Python, mas, por enquanto, basta escrevê-lo em seu Jupyter
44 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Obtenha os dados | 45
Figura 2-5. As cinco primeiras linhas no conjunto de dados
O método info() é útil para obter uma descrição rápida dos dados, em particular o número total de linhas 
e o tipo de cada atributo e o número de valores não nulos (consulte a Figura 2-6).
Esta função retorna um objeto Pandas DataFrame contendo todos os dados.
Vamos dar uma olhada nas cinco primeiras linhas usando o método head() do DataFrame (consulte a 
Figura 2-5).
Figura 2-6. Informações de habitação
Cada linha representa um distrito. Existem 10 atributos (você pode ver os 6 primeiros 
na captura de tela): longitude, latitude, hosting_median_age, total_rooms, total_bed 
rooms, population, agregados familiares, median_income, median_house_value e 
ocean_proximity.
Dê uma olhada rápida na estrutura de dados
46 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Existem 20.640 instâncias no conjunto de dados, o que significa que é bastante pequeno para 
os padrões do Machine Learning, mas é perfeito para começar. Observe que o atributo quartos 
total_bed tem apenas 20.433 valores não nulos, o que significa que 207 distritos não possuem 
esse recurso. Teremos que cuidar disso mais tarde.
Vamos ver os outros campos. O método describe() mostra um resumo dos atributos numéricos 
(Figura 2-7).
Figura 2-7. Resumo de cada atributo numérico
Todos os atributos são numéricos, exceto o campo ocean_proximity . Seu tipo é object, 
portanto pode conter qualquer tipo de objeto Python, mas como você carregou esses dados 
de um arquivo CSV, sabe que deve ser um atributo de texto. Quando você olhou para as cinco 
primeiras linhas, provavelmente notou que os valores naquela coluna eram repetitivos, o que 
significa que provavelmente é um atributo categórico. Você pode descobrir quais categorias 
existem e quantos distritos pertencem a cada categoria usando o método value_counts() :
As linhas de 25%, 50% e 75% mostram os percentis correspondentes: um percentil indica o 
valor abaixo do qual uma determinada porcentagem de observações em um grupo de 
observações cai. Por exemplo, 25% dos distritos têm uma idade_mediana_de habitação inferior a
<1H OCEAN 9136 INTERIOR 
6551 PERTO DO OCEANO 
2658
2290
>>> habitação["ocean_proximity"].value_counts()
PRÓXIMO DA BAÍA
ILHA 5
Nome: ocean_proximity, dtype: int64
As linhas de contagem, média, mínimo e máximo são autoexplicativas. Observe que os 
valores nulos são ignorados (portanto, por exemplo, a contagem de total_bedrooms é 
20.433, não 20.640). A linha padrão mostra o desvio padrão (que mede a dispersão dos valores).
18, enquanto 50% são inferiores a 29 e 75% são inferiores a 37. Estes são frequentemente 
chamados de percentil 25 (ou 1º quartil), mediana e percentil 75 (ou 3º quartil).
Outra maneira rápida de ter uma ideia do tipo de dados com os quais você está lidando é 
traçar um histograma para cada atributo numérico. Um histograma mostra o número de 
instâncias (no eixo vertical) que possuem um determinado intervalo de valores (no eixo 
horizontal). Você pode plotar esse atributo por vez ou pode chamar o método hist() em todo 
o conjunto de dados, e ele plotará um histograma para cada atributo numérico (consulte a 
Figura 2-8). Por exemplo, você pode ver que pouco mais de 800 distritos têm um 
median_house_value igual a cerca de US$ 500.000.
Figura 2-8. Um histograma para cada atributo numérico
%matplotlib inline # apenas em um notebook Jupyter importa 
matplotlib.pyplot como plt 
habitação.hist(bins=50, figsize=(20,15)) 
plt.show()
Obtenha os dados | 47
O método hist() depende do Matplotlib, que por sua vez depende de um back-
end gráfico especificado pelo usuário para desenhar em sua tela. Portanto, 
antes de poder plotar qualquer coisa, você precisa especificar qual back-end 
o Matplotlib deve usar. A opção mais simples é usar o comando mágico 
%matplotlib inline do Jupyter. Isso diz ao Jupyter para configurar o Matplotlib 
para que ele use o próprio back-end do Jupyter. Os gráficos são renderizados 
no próprio notebook. Observe que chamar show() é opcional em um notebook 
Jupyter, pois o Jupyter exibirá gráficos automaticamente quando uma célula 
for executada.
Observe algumas coisas nesses histogramas:
3. Esses atributos têm escalas muito diferentes. Discutiremos isso mais adiante neste capítulo, quando 
explorarmos o escalonamento de recursos.
Você precisa verificar com a equipe do cliente (a equipe que usará a saída do seu sistema) para 
ver se isso é um problema ou não. Se eles disserem que precisam de previsões precisas mesmo 
além de US$ 500.000, você terá basicamente duas opções: a. Colete rótulos 
adequados para os distritos cujos rótulos foram limitados. b. Remova esses 
distritos do conjunto de treinamento (e também do conjunto de teste, pois seu sistema não deve 
ser mal avaliado se prever valores acima de US$ 500.000).
1. Primeiro, o atributo de renda mediana não parece expresso em dólares americanos (USD). Depois 
de verificar com a equipe que coletou os dados, você é informado de que os dados foram 
dimensionados e limitados a 15 (na verdade, 15,0001) para rendas medianas mais altas e a 0,5 (na 
verdade, 0,4999) para rendas medianas mais baixas. Trabalhar com atributos pré-processados é 
comum em Machine Learning e não necessariamente é um problema, mas você deve tentar 
entender como os dados foram computados.
4. Finalmente, muitos histogramas têm cauda pesada: eles se estendem muito mais à direita da 
mediana do que à esquerda. Isso pode tornar um pouco mais difícil para alguns algoritmos de 
Machine Learning detectar padrões. Tentaremos transformar esses atributos mais tarde para ter 
distribuições mais em forma de sino.
Esperamos que agora você tenha uma melhor compreensão do tipo de dados com os quais está lidando.
2. A idade média da habitação e o valor médio da casa também foram limitados. Este último pode ser 
um problema sério, pois é seu atributo de destino (seus rótulos). Seus algoritmos de Machine 
Learning podem aprender que os preços nunca vão além desse limite.
48 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
importar numpy como np
def split_train_test(data, test_ratio): 
shuffled_indices = np.random.permutation(len(data))test_set_size = int(len(data) * test_ratio) test_indices 
= shuffled_indices[:test_set_size] train_indices = 
shuffled_indices[test_set_size:] return data.iloc 
[train_indices], data.iloc[test_indices]
>>> train_set, test_set = split_train_test(housing, 0.2) >>> 
print(len(train_set), "train +", len(test_set), "test") 16512 train + 4128 test
13 Muitas vezes você verá pessoas definirem a semente aleatória como 42. Esse número não tem nenhuma propriedade especial, além de ser
Espere! Antes de examinar mais os dados, você precisa criar um conjunto 
de teste, colocá-lo de lado e nunca olhá-lo.
Bem, isso funciona, mas não é perfeito: se você executar o programa novamente, ele gerará um conjunto 
de teste diferente! Com o tempo, você (ou seus algoritmos de aprendizado de máquina) verá todo o 
conjunto de dados, que é o que você deseja evitar.
Você pode então usar esta função assim:
Pode parecer estranho separar voluntariamente parte dos dados nesta fase. Afinal, você apenas deu uma 
olhada rápida nos dados e certamente deveria aprender muito mais sobre eles antes de decidir quais 
algoritmos usar, certo? Isso é verdade, mas seu cérebro é um incrível sistema de detecção de padrões, o 
que significa que ele é altamente propenso a superajuste: se você olhar para o conjunto de teste, poderá 
se deparar com algum padrão aparentemente interessante nos dados do teste que o leva a selecionar um 
tipo particular de modelo de aprendizado de máquina. Ao estimar o erro de generalização usando o conjunto 
de teste, sua estimativa será muito otimista e você iniciará um sistema que não funcionará tão bem quanto 
o esperado. Isso é chamado de viés de espionagem de dados.
Uma solução é salvar o conjunto de testes na primeira execução e carregá-lo nas execuções subsequentes. 
Outra opção é definir a semente do gerador de números aleatórios (por exemplo, np.ran dom.seed(42)) 13 
antes de chamar np.random.permutation(), para que sempre gere os mesmos índices embaralhados.
Criar um conjunto de teste é teoricamente bastante simples: basta escolher algumas instâncias 
aleatoriamente, normalmente 20% do conjunto de dados, e separá-las:
A resposta para a questão final da vida, do universo e de tudo.
Obtenha os dados | 49
Criar um conjunto de teste
50 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Aqui está uma implementação possível:
Infelizmente, o conjunto de dados de habitação não possui uma coluna identificadora. A solução 
mais simples é usar o índice da linha como ID:
Se você usar o índice de linha como um identificador exclusivo, precisará garantir que os novos 
dados sejam anexados ao final do conjunto de dados e que nenhuma linha seja excluída. Se isso 
não for possível, você pode tentar usar os recursos mais estáveis para criar um identificador exclusivo.
Mas ambas as soluções serão interrompidas na próxima vez que você buscar um conjunto de 
dados atualizado. Uma solução comum é usar o identificador de cada instância para decidir se ela 
deve ou não entrar no conjunto de teste (supondo que as instâncias tenham um identificador único 
e imutável). Por exemplo, você pode calcular um hash do identificador de cada instância, manter 
apenas o último byte do hash e colocar a instância no conjunto de teste se esse valor for menor ou 
igual a 51 (~20% de 256). Isso garante que o conjunto de teste permaneça consistente em várias 
execuções, mesmo se você atualizar o conjunto de dados. O novo conjunto de teste conterá 20% 
das novas instâncias, mas não conterá nenhuma instância que estava anteriormente no conjunto de treinamento.
Por exemplo, a latitude e a longitude de um distrito são garantidamente estáveis por alguns milhões 
de anos, então você pode combiná-las em um ID como este:14
O Scikit-Learn fornece algumas funções para dividir conjuntos de dados em vários subconjuntos de 
várias maneiras. A função mais simples é train_test_split, que faz praticamente a mesma coisa que 
a função split_train_test definida anteriormente, com alguns recursos adicionais. Primeiro, há um 
parâmetro random_state que permite definir a semente do gerador aleatório conforme explicado 
anteriormente e, segundo, você pode passar vários conjuntos de dados com um número idêntico 
de linhas e dividi-los nos mesmos índices (isso é muito útil, para exemplo, se você tiver um 
DataFrame separado para rótulos):
14 Na verdade, as informações de localização são bastante grosseiras e, como resultado, muitos distritos terão exatamente o 
mesmo ID, portanto, terminarão no mesmo conjunto (teste ou trem). Isso introduz algum viés de amostragem infeliz.
ids = data[id_column] 
in_test_set = ids.apply(lambda id_: test_set_check(id_, test_ratio, hash)) return 
data.loc[~in_test_set], data.loc[in_test_set]
habitação_com_id["id"] = habitação["longitude"] * 1000 + habitação["latitude"] train_set, 
test_set = split_train_test_by_id(housing_with_id, 0.2, "id")
def split_train_test_by_id(data, test_ratio, id_column, hash=hashlib.md5):
importar hashlib
habitação_with_id = habitação.reset_index() # adiciona uma coluna ̀index` 
train_set, test_set = split_train_test_by_id(housing_with_id, 0.2, "index")
def test_set_check(identifier, test_ratio, hash): return 
hash(np.int64(identifier)).digest()[-1] < 256 * test_ratio
de sklearn.model_selection import train_test_split
train_set, test_set = train_test_split(habitação, test_size=0,2, random_state=42)
Figura 2-9. Histograma de categorias de renda
A maioria dos valores de renda mediana está agrupada em torno de 2 a 5 (dezenas de milhares de 
dólares), mas algumas rendas medianas vão muito além de 6. É importante ter um número suficiente
Como a renda mediana é um atributo numérico contínuo, primeiro você precisa criar um atributo de 
categoria de renda. Vamos examinar o histograma de renda mediana mais de perto (consulte a Figura 
2-9):
Até agora, consideramos métodos de amostragem puramente aleatórios. Isso geralmente é bom se 
seu conjunto de dados for grande o suficiente (especialmente em relação ao número de atributos), 
mas se não for, você corre o risco de introduzir um viés de amostragem significativo. Quando uma 
empresa de pesquisa decide ligar para 1.000 pessoas para fazer algumas perguntas, ela não escolhe 
apenas 1.000 pessoas aleatoriamente em uma cabine telefônica. Eles tentam garantir que essas 
1.000 pessoas sejam representativas de toda a população. Por exemplo, a população dos EUA é 
composta por 51,3% de mulheres e 48,7% de homens, então uma pesquisa bem conduzida nos EUA 
tentaria manter essa proporção na amostra: 513 mulheres e 487 homens. Isso é chamado de 
amostragem estratificada: a população é dividida em subgrupos homogêneos chamados estratos, e o 
número certo de instâncias é amostrado de cada estrato para garantir que o conjunto de teste seja 
representativo da população geral. Se eles usassem amostragem puramente aleatória, haveria cerca 
de 12% de chance de amostrar um conjunto de teste assimétrico com menos de 49% demulheres ou 
mais de 54% de mulheres. De qualquer forma, os resultados da pesquisa seriam significativamente 
tendenciosos.
Suponha que você tenha conversado com especialistas que lhe disseram que a renda mediana é um 
atributo muito importante para prever os preços medianos da habitação. Você pode querer garantir 
que o conjunto de teste seja representativo das várias categorias de renda em todo o conjunto de dados.
Obtenha os dados | 51
Vamos ver se isso funcionou como esperado. Você pode começar observando as proporções da categoria de 
renda no conjunto de dados habitacional completo:
Com um código semelhante, você pode medir as proporções da categoria de renda no conjunto de teste.
número de instâncias em seu conjunto de dados para cada estrato, caso contrário, a estimativa da importância 
do estrato pode ser tendenciosa. Isso significa que você não deve ter muitos estratos e cada estrato deve ser 
grande o suficiente. O código a seguir cria um atributo de categoria de renda dividindo a renda mediana por 1,5 
(para limitar o número de categorias de renda) e arredondando para cima usando ceil (para ter categorias 
discretas) e, em seguida, mesclando todas as categorias maiores que 5 na categoria 5:
Agora você está pronto para fazer amostragem estratificada com base na categoria de renda. Para isso, você 
pode usar a classe StratifiedShuffleSplit do Scikit-Learn :
A Figura 2-10 compara as proporções da categoria de renda no conjunto de dados geral, no conjunto de teste 
gerado com amostragem estratificada e em um conjunto de teste gerado usando amostragem puramente 
aleatória. Como você pode ver, o conjunto de teste gerado usando amostragem estratificada tem proporções de 
categoria de renda quase idênticas às do conjunto de dados completo, enquanto o conjunto de teste gerado 
usando amostragem puramente aleatória é bastante distorcido.
Figura 2-10. Comparação de viés de amostragem de amostragem estratificada versus puramente aleatória
split = StratifiedShuffleSplit(n_splits=1, test_size=0.2, random_state=42) para train_index, test_index em 
split.split(habitação, habitação["income_cat"]):
0,114438 
0,039826
0,350581
5.0 
1.0 
Nome: income_cat, dtype: float64
de sklearn.model_selection importar StratifiedShuffleSplit
4.0
>>> habitação["income_cat"].value_counts() / len(habitação) 3.0
2.0
0,176308
strat_train_set = habitação.loc[train_index] strat_test_set = 
habitação.loc[test_index]
habitação["income_cat"] = np.ceil(housing["median_income"] / 1,5) 
habitação["income_cat"].where(housing["income_cat"] < 5, 5,0, inplace=True)
0,318847
52 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Descubra e visualize os dados para obter insights
Descubra e Visualize os Dados para Obter Insights | 53
estado:
Até agora, você deu apenas uma olhada rápida nos dados para obter uma compreensão geral do tipo de dados que está 
manipulando. Agora o objetivo é aprofundar um pouco mais.
Gastamos bastante tempo na geração de conjuntos de teste por um bom motivo: essa é uma parte frequentemente 
negligenciada, mas crítica de um projeto de aprendizado de máquina. Além disso, muitas dessas ideias serão úteis mais 
tarde, quando discutirmos a validação cruzada. Agora é hora de passar para a próxima etapa: explorar os dados.
Agora você deve remover o atributo income_cat para que os dados voltem ao original
Como há informações geográficas (latitude e longitude), é uma boa ideia criar um gráfico de dispersão de todos os distritos 
para visualizar os dados (Figura 2-11):
Primeiro, certifique-se de ter colocado o teste de lado e de estar apenas explorando o conjunto de treinamento. Além disso, 
se o conjunto de treinamento for muito grande, você pode querer amostrar um conjunto de exploração, para tornar as 
manipulações fáceis e rápidas. No nosso caso, o conjunto é bem pequeno, então você pode trabalhar diretamente no 
conjunto completo. Vamos criar uma cópia para que você possa brincar com ela sem prejudicar o conjunto de treinamento:
Figura 2-11. Um gráfico de dispersão geográfica dos dados
habitação = strat_train_set.copy()
set.drop(["income_cat"], axis=1, inplace=True)
para definir em (strat_train_set, strat_test_set):
habitação.plot(tipo="dispersão", x="longitude", y="latitude")
Visualizando Dados Geográficos
54 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Agora vamos olhar para os preços da habitação (Figura 2-13). O raio de cada círculo representa a 
população do distrito (opção s) e a cor representa o preço (opção c). Usaremos um mapa de cores pré-
definido (opção cmap) chamado jet, que varia do azul (valores baixos) ao vermelho (preços altos):15
Agora está muito melhor: você pode ver claramente as áreas de alta densidade, ou seja, a Bay Area e 
ao redor de Los Angeles e San Diego, além de uma longa linha de alta densidade no Central Valley, 
em particular em torno de Sacramento e Fresno.
fora.
Figura 2-12. Uma melhor visualização destacando áreas de alta densidade
Isso parece muito com a Califórnia, mas fora isso é difícil ver qualquer padrão em particular. Definir a 
opção alfa para 0,1 facilita muito a visualização dos locais onde há uma alta densidade de pontos de 
dados (Figura 2-12):
De forma mais geral, nossos cérebros são muito bons em identificar padrões em imagens, mas você 
pode precisar brincar com os parâmetros de visualização para fazer com que os padrões se destaquem.
habitação.plot(kind="scatter", x="longitude", y="latitude", alpha=0.4, 
s=housing["population"]/100, label="population", 
c="median_house_value", cmap =plt.get_cmap("jato"), colorbar=Verdadeiro,
) plt.legend()
habitação.plot(kind="scatter", x="longitude", y="latitude", alpha=0.1)
15 Se você estiver lendo isso em escala de cinza, pegue uma caneta vermelha e rabisque a maior parte da costa desde a Bay Area 
até San Diego (como você pode esperar). Você também pode adicionar uma mancha amarela ao redor de Sacramento.
1,000000
corr_matrix = habitação.corr()
>>> corr_matrix["median_house_value"].sort_values(ascending=False) median_house_value 
median_income total_rooms 
hosting_median_age 
domicílios
0,687170 
0,135231
0,114220
0,064702
Esta imagem diz-lhe que os preços das casas estão muito relacionados com a localização (por exemplo, 
perto do mar) e com a densidade populacional, como provavelmente já sabia.
Agora vamos ver quanto cada atributo se correlaciona com o valor médio da casa:
Provavelmente será útil usar um algoritmo de clustering para detectar os clusters principais e adicionar 
novos recursos que medem a proximidade dos centros dos clusters. O atributo de proximidade do 
oceano também pode ser útil, embora no norte da Califórnia os preços das moradias nos distritos 
costeiros não sejam muito altos, então não é uma regra simples.
Figura 2-13. Preços de imóveis na Califórnia
Como o conjunto de dados não é muito grande, você pode calcular facilmente o coeficiente de 
correlação padrão (também chamado de r de Pearson) entre cada par de atributos usandoo método 
corr() :
Descubra e Visualize os Dados para Obter Insights | 55
Procurando por correlações
56 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
-0,026699
0,047865
-0,047279
total_bedrooms 
população 
longitude 
latitude -0.142826 Nome: median_house_value, 
dtype: float64
O coeficiente de correlação mede apenas correlações lineares (“se x 
sobe, então y geralmente sobe/desce”). Ele pode perder completamente 
as relações não lineares (por exemplo, “se x está próximo de zero, então 
y geralmente sobe”). Observe como todos os gráficos da linha inferior 
têm um coeficiente de correlação igual a zero, apesar do fato de que 
seus eixos claramente não são independentes: esses são exemplos de 
relacionamentos não lineares. Além disso, a segunda linha mostra 
exemplos onde o coeficiente de correlação é igual a 1 ou –1; observe que 
isso não tem nada a ver com a inclinação. Por exemplo, sua altura em 
polegadas tem um coeficiente de correlação de 1 com sua altura em pés ou nanômetros.
Figura 2-14. Coeciente de correlação padrão de vários conjuntos de dados (fonte: Wikipedia; 
imagem de domínio público)
Outra maneira de verificar a correlação entre os atributos é usar a função scatter_matrix do Pandas , 
que plota cada atributo numérico em relação a todos os outros atributos numéricos. Como agora 
existem 11 atributos numéricos, você obteria 112 =
O coeficiente de correlação varia de –1 a 1. Quando está próximo de 1, significa que existe uma forte 
correlação positiva; por exemplo, o valor médio da casa tende a aumentar quando a renda média 
aumenta. Quando o coeficiente está próximo de –1, significa que existe uma forte correlação negativa; 
você pode ver uma pequena correlação negativa entre a latitude e o valor médio da casa (ou seja, os 
preços têm uma leve tendência a cair quando você vai para o norte). Finalmente, coeficientes próximos 
de zero significam que não há correlação linear. A Figura 2-14 mostra vários gráficos junto com o 
coeficiente de correlação entre seus eixos horizontal e vertical.
Figura 2-15. matriz de dispersão
A diagonal principal (do canto superior esquerdo ao canto inferior direito) estaria cheia de linhas retas se 
o Pandas plotasse cada variável contra si mesma, o que não seria muito útil. Então, em vez disso, o 
Pandas exibe um histograma de cada atributo (outras opções estão disponíveis; consulte a documentação 
do Pandas para obter mais detalhes).
O atributo mais promissor para prever o valor mediano da casa é a renda mediana, então vamos ampliar 
o gráfico de dispersão de correlação (Figura 2-16):
121 lotes, que não caberiam em uma página, então vamos nos concentrar apenas em alguns atributos 
promissores que parecem mais correlacionados com o valor médio da habitação (Figura 2-15):
scatter_matrix(habitação[atributos], figsize=(12, 8))
de pandas.tools.plotting import scatter_matrix
"housing_median_age"]
habitação.plot(kind="scatter", x="median_income", y="median_house_value", alpha=0.1)
atributos = ["median_house_value", "median_income", "total_rooms",
Descubra e Visualize os Dados para Obter Insights | 57
Uma última coisa que você pode querer fazer antes de preparar os dados para algoritmos de 
aprendizado de máquina é experimentar várias combinações de atributos. Por exemplo, o número 
total de cômodos em um distrito não é muito útil se você não souber quantos domicílios existem. O 
que você realmente quer é o número de cômodos por família.
Figura 2-16. Renda média versus valor médio da casa
Você pode tentar remover os distritos correspondentes para evitar que seus algoritmos aprendam a 
reproduzir essas peculiaridades de dados.
Experimentando combinações de atributos Espero que as 
seções anteriores tenham lhe dado uma ideia de algumas maneiras pelas quais você pode explorar 
os dados e obter insights. Você identificou algumas peculiaridades de dados que talvez queira limpar 
antes de alimentar os dados para um algoritmo de aprendizado de máquina e encontrou correlações 
interessantes entre atributos, em particular com o atributo de destino. Você também notou que 
alguns atributos têm uma distribuição de cauda pesada, então você pode querer transformá-los (por 
exemplo, calculando seu logaritmo). Claro, sua milhagem varia consideravelmente com cada projeto, 
mas as ideias gerais são semelhantes.
Este enredo revela algumas coisas. Primeiro, a correlação é realmente muito forte; você pode ver 
claramente a tendência ascendente e os pontos não estão muito dispersos. Em segundo lugar, o 
limite de preço que notamos anteriormente é claramente visível como uma linha horizontal em US$ 
500.000. Mas esse gráfico revela outras linhas retas menos óbvias: uma linha horizontal em torno 
de $ 450.000, outra em torno de $ 350.000, talvez uma em torno de $ 280.000 e algumas mais abaixo disso.
Da mesma forma, o número total de quartos por si só não é muito útil: você provavelmente deseja 
compará-lo com o número de quartos. E a população por domicílio também
58 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Preparar os dados para algoritmos de aprendizado de máquina
Ei, nada mal! O novo atributo bedroom_per_room está muito mais correlacionado com o valor médio da 
casa do que com o número total de cômodos ou quartos. Aparentemente, casas com uma relação quarto/
quarto menor tendem a ser mais caras. O número de cômodos por domicílio também é mais informativo do 
que o número total de cômodos em um distrito – obviamente, quanto maiores as casas, mais caras elas 
são.
parece ser uma combinação de atributos interessante de se olhar. Vamos criar esses novos atributos:
E agora vamos olhar para a matriz de correlação novamente:
• Isso permitirá reproduzir essas transformações facilmente em qualquer conjunto de dados (por 
exemplo, na próxima vez que você obtiver um 
novo conjunto de dados). • Você construirá gradualmente uma biblioteca de funções de transformação 
que poderá reutilizar 
em projetos futuros. • Você pode usar essas funções em seu sistema ativo para transformar os novos dados antes
Essa rodada de exploração não precisa ser absolutamente completa; o objetivo é começar com o pé direito 
e rapidamente obter insights que o ajudarão a obter um primeiro protótipo razoavelmente bom. Mas este é 
um processo iterativo: depois de colocar um protótipo em funcionamento, você pode analisar sua saída 
para obter mais informações e voltar a esta etapa de exploração.
É hora de preparar os dados para seus algoritmos de Machine Learning. Em vez de apenas fazer isso 
manualmente, você deve escrever funções para fazer isso, por vários bons motivos:
alimentando-o com seus algoritmos.
Preparar os dados para algoritmos de aprendizado de máquina | 59
0,687170
-0,260070
>>> corr_matrix = habitação.corr() >>> 
corr_matrix["median_house_value"].sort_values(ascending=False) median_house_value 
median_income 
rooms_per_household 
total_rooms 
hosting_median_age 
domicíliostotal_bedrooms 0,047865population_per_household 
-0,021984population -0,026699 longitude d latitude: 
float_type_room6 Name: median_house_value4 
Name: 
median_house_value4 
Name: median_house_value4
0,199343
0,135231
habitação["rooms_per_household"] = habitação["total_rooms"]/habitação["households"] 
habitação["bedrooms_per_room"] = habitação["total_bedrooms"]/housing["total_rooms"] 
habitação["population_per_household"]=habitação[" população"]/habitação["famílias"]
1,000000
0,114220 
0,064702
-0,047279 
-0,142826
• Defina os valores para algum valor (zero, média, mediana, etc.).
Se você escolher a opção 3, deverá calcular o valor mediano no conjunto de treinamento e usá-lo 
para preencher os valores ausentes no conjunto de treinamento, mas também não se esqueça de 
salvar o valor mediano que calculou. Você precisará dele mais tarde para substituir os valores 
ausentes no conjunto de teste quando quiser avaliar seu sistema e também quando o sistema for 
ativado para substituir os valores ausentes em novos dados.
O Scikit-Learn fornece uma classe útil para cuidar dos valores ausentes: Imputer. Aqui está como 
usá-lo. Primeiro, você precisa criar uma instância de Imputer , especificando que deseja substituir os 
valores ausentes de cada atributo pela mediana desse atributo:
Como a mediana só pode ser calculada em atributos numéricos, precisamos criar uma cópia dos 
dados sem o atributo de texto ocean_proximity:
Você pode fazer isso facilmente usando os métodos dropna(), drop() e fillna() do DataFrame :
• Isso permitirá que você experimente facilmente várias transformações e veja
Limpeza de dados 
A maioria dos algoritmos de aprendizado de máquina não pode funcionar com recursos ausentes, 
então vamos criar algumas funções para cuidar deles. Você notou anteriormente que o atributo 
total_bedrooms tem alguns valores ausentes, então vamos corrigir isso. Você tem três opções:
qual combinação de transformações funciona melhor.
• Livre-se dos distritos correspondentes.
• Livre-se de todo o atributo.
Mas primeiro vamos reverter para um conjunto de treinamento limpo (copiando strat_train_set mais 
uma vez) e vamos separar os preditores e os rótulos, pois não queremos necessariamente aplicar as 
mesmas transformações aos preditores e aos valores de destino (observe que drop() cria uma cópia 
dos dados e não afeta strat_train_set):
de sklearn.preprocessing import Imputer
núm_habitação = habitação.drop("ocean_proximity", eixo=1)
# opção 3
habitação = strat_train_set.drop("median_house_value", axis=1) 
hosting_labels = strat_train_set["median_house_value"].copy()
imputer = Imputer(estratégia="mediana")
habitação.dropna(subset=["total_bedrooms"]) # opção 1 
habitação.drop("total_bedrooms", axis=1) # opção 2 mediana = 
habitação["total_bedrooms"].median() 
habitação["total_bedrooms"].fillna (mediana)
60 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Projeto Scikit-Learn
,
Agora você pode ajustar a instância do imputador aos dados de treinamento usando o método fit() :
O imputador simplesmente calculou a mediana de cada atributo e armazenou o resultado em sua variável 
de instância statistics_ . Apenas o atributo total_bedrooms tinha valores ausentes, mas não podemos ter 
certeza de que não haverá valores ausentes em novos dados depois que o sistema for ativado, portanto, 
é mais seguro aplicar o imputer a todos os atributos numéricos:
O resultado é uma matriz Numpy simples contendo os recursos transformados. Se você quiser colocá-lo 
de volta em um Pandas DataFrame, é simples:
Agora você pode usar esse imputador “treinado” para transformar o conjunto de treinamento substituindo 
os valores ausentes pelas medianas aprendidas:
,
1164.
, 3.5414]),
408.
408.,
habitação_tr = pd.DataFrame(X, colunas=num_habitação.colunas)
, 3.5414])
34.26 ,
imputer.fit(housing_num)
,
29.
,
2119.
>>> imputer.statistics_ 
array([ -118.51 34.26 >>> 
housing_num.median().values 
array([ -118.51
,
433.
X = imputer.transform(housing_num)
29. ,
1164.
,2119.
,
433. ,
Todos os transformadores também possuem um método de conveniência chamado fit_transform()
— Estimadores. Qualquer objeto que possa estimar alguns parâmetros com base em um conjunto de 
dados é chamado de estimador (por exemplo, um imputador é um estimador). A própria estimativa 
é realizada pelo método fit() e leva apenas um conjunto de dados como parâmetro (ou dois para 
algoritmos de aprendizado supervisionado; o segundo conjunto de dados contém os rótulos). 
Qualquer outro parâmetro necessário para orientar o processo de estimativa é considerado um 
hiperparâmetro (como a estratégia de um imputador ) e deve ser definido como uma variável de 
instância (geralmente por meio de um parâmetro do construtor).
A API do Scikit-Learn é incrivelmente bem projetada. Os principais princípios de design são: 16
— Transformadores. Alguns estimadores (como um imputador) também podem transformar um 
conjunto de dados; estes são chamados de transformadores. Mais uma vez, a API é bem simples: 
a transformação é realizada pelo método transform() com o dataset a ser transformado como 
parâmetro. Ele retorna o conjunto de dados transformado. Essa transformação geralmente depende 
dos parâmetros aprendidos, como é o caso de um imputador.
• Consistência. Todos os objetos compartilham uma interface consistente e simples:
16 Para obter mais detalhes sobre os princípios de design, consulte “Design de API para software de aprendizado de máquina: 
experiências do projeto scikit-learn,” L. Buitinck, G. Louppe, M. Blondel, F. Pedregosa, A. Müller, et al. (2013).
Preparar os dados para algoritmos de aprendizado de máquina | 61
http://goo.gl/wL10sI
>>> from sklearn.preprocessing import LabelEncoder >>> 
codificador = LabelEncoder() >>> 
habitação_cat = habitação["ocean_proximity"] >>> 
habitação_cat_encoded = encoder.fit_transform(housing_cat) >>> 
habitação_cat_encoded 
array([1, 1, 4, ..., 1, 0, 3])
• Inspeção. Todos os hiperparâmetros do estimador são acessíveis diretamente por meio de 
variáveis de instância públicas (por exemplo, imputer.strategy) e todos os parâmetros aprendidos 
do estimador também são acessíveis por meio de variáveis de instância públicas com um sufixo 
de sublinhado (por exemplo, 
imputer.statistics_). • Não proliferação de classes. Os conjuntos de dados são representados 
como matrizes NumPy ou matrizes esparsas SciPy, em vez de classes caseiras. Hiperparâmetros 
são apenas strings ou números regulares do Python.
isso é equivalente a chamar fit() e depois transform() (mas às vezes fit_transform() é 
otimizado e executado muito mais rápido).
• Composição. Os blocos de construção existentes são reutilizados tanto quanto possível. Por 
exemplo, é fácil criar um estimador Pipeline a partir de uma sequência arbitrária de 
transformadores seguida de um estimador final, como veremos.
— Preditores. Finalmente, alguns estimadores são capazes de fazer previsões a partir de um 
conjunto de dados; eles são chamados de preditores. Por exemplo, o modelo 
LinearRegression do capítulo anterior era umpreditor: previa a satisfação com a vida dado 
o PIB per capita de um país. Um preditor tem um método predict() que pega um conjunto de 
dados de novas instâncias e retorna um conjunto de dados de previsões correspondentes. 
Ele também possui um método score() que mede a qualidade das previsões dadas a um 
conjunto de teste (e os rótulos correspondentes no caso de algoritmos de aprendizado 
supervisionado).17
• Padrões sensatos. O Scikit-Learn fornece valores padrão razoáveis para a maioria dos 
parâmetros, facilitando a criação rápida de um sistema de linha de base.
Manipulando atributos de texto e categóricos 
Anteriormente, deixamos de fora o atributo categórico ocean_proximity porque é um atributo de texto, 
portanto não podemos calcular sua mediana. A maioria dos algoritmos de Machine Learning prefere 
trabalhar com números de qualquer maneira, então vamos converter esses rótulos de texto em números.
O Scikit-Learn fornece um transformador para esta tarefa chamado LabelEncoder:
17 Alguns preditores também fornecem métodos para medir a confiança de suas previsões.
62 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
18 A função reshape() do NumPy permite que uma dimensão seja –1, o que significa “não especificado”: o valor é inferido
do comprimento da matriz e as dimensões restantes.
Isso é melhor: agora podemos usar esses dados numéricos em qualquer algoritmo de ML. Você 
pode ver o mapeamento que este codificador aprendeu usando o atributo classes_ (“<1H OCEAN” 
é mapeado para 0, “INLAND” é mapeado para 1, etc.):
Observe que a saída é uma matriz esparsa SciPy, em vez de uma matriz NumPy. Isso é muito útil 
quando você tem atributos categóricos com milhares de categorias. Depois de uma codificação 
quente, obtemos uma matriz com milhares de colunas e a matriz está cheia de zeros, exceto um 1 
por linha. Usar toneladas de memória principalmente para armazenar zeros seria um desperdício, 
então, em vez disso, uma matriz esparsa armazena apenas a localização dos elementos diferentes 
de zero. Você pode usá-lo principalmente como um array 2D normal,19 mas se realmente quiser 
convertê-lo em um array NumPy (denso), basta chamar o método toarray() :
Um problema com essa representação é que os algoritmos de ML assumirão que dois valores 
próximos são mais semelhantes do que dois valores distantes. Obviamente, este não é o caso 
(por exemplo, as categorias 0 e 4 são mais semelhantes do que as categorias 0 e 1). Para corrigir 
esse problema, uma solução comum é criar um atributo binário por categoria: um atributo igual a 
1 quando a categoria for “<1H OCEAN” (e 0 caso contrário), outro atributo igual a 1 quando a 
categoria for “INLAND” ( e 0 caso contrário), e assim por diante. Isso é chamado de codificação 
one-hot, porque apenas um atributo será igual a 1 (quente), enquanto os outros serão 0 (frio).
O Scikit-Learn fornece um codificador OneHotEncoder para converter valores categóricos inteiros 
em vetores one-hot. Vamos codificar as categorias como vetores one-hot. Observe que 
fit_transform() espera uma matriz 2D, mas habitação_cat_encoded é uma matriz 1D, portanto, 
precisamos remodelá-la:18
['<1H OCEANO' 'INTERIOR' 'ILHA' 'PRÓXIMO DA BAÍA' 'PRÓXIMO DO OCEANO']
...,
>>> from sklearn.preprocessing import OneHotEncoder >>> 
encoder = OneHotEncoder() >>> 
habitação_cat_1hot = encoder.fit_transform(housing_cat_encoded.reshape(-1,1)) >>> 
habitação_cat_1hot 
<16513x5 matriz esparsa do tipo '<class' numpy.float64'>'
>>> print(encoder.classes_)
>>> habitação_cat_1hot.toarray() 
array([[ 0., 1., 0., 0., 0.], [ 0., 1., 0., 0., 
0.], [ 0., 0 ., 0., 0., 1.],
com 16513 elementos armazenados no formato Compressed Sparse Row>
[ 0., 1., 0., 0., 0.],
19 Consulte a documentação do SciPy para obter mais detalhes.
Preparar os dados para algoritmos de aprendizado de máquina | 63
Transformadores personalizados
[0, 1, 0, 0, 0], [1, 0, 
0, 0, 0], [0, 0, 0, 1, 
0]])
[ 1., 0., 0., 0., 0.], [ 0., 0., 0., 1., 
0.]])
de sklearn.base import BaseEstimator, TransformerMixin
def transform(self, X, y=None):
...,
def fit(self, X, y=None): return 
self # nada mais a fazer
quartos_por_quarto = X[:, quartos_ix] / X[:, quartos_ix]
>>> from sklearn.preprocessing import LabelBinarizer >>> 
codificador = LabelBinarizer() >>> 
habitação_cat_1hot = encoder.fit_transform(housing_cat) >>> 
habitação_cat_1hot 
array([[0, 1, 0, 0, 0], [0, 1, 0, 
0, 0], [0, 0, 0, 0, 1],
class CombinedAttributesAdder(BaseEstimator, TransformerMixin):
def __init__(self, add_bedrooms_per_room = True): # no *args or **kargs 
self.add_bedrooms_per_room = add_bedrooms_per_room
quartos_por_casa = X[:, quartos_ix] / X[:, casa_ix] população_por_casa 
= X[:, população_ix] / X[:, casa_ix] se self.add_bedrooms_per_room:
quartos_ix, quartos_ix, população_ix, casa_ix = 3, 4, 5, 6
64 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Podemos aplicar ambas as transformações (de categorias de texto para categorias inteiras, 
depois de categorias inteiras para vetores únicos) de uma só vez usando a classe 
LabelBinarizer :
Observe que isso retorna uma matriz NumPy densa por padrão. Você pode obter uma matriz 
esparsa passando sparse_output=True para o construtor LabelBinarizer .
Embora o Scikit-Learn forneça muitos transformadores úteis, você precisará escrever o seu 
próprio para tarefas como operações de limpeza personalizadas ou combinação de atributos 
específicos. Você deseja que seu transformador funcione perfeitamente com as funcionalidades 
do Scikit-Learn (como pipelines) e, como o Scikit-Learn depende da tipagem de pato (não da 
herança), tudo o que você precisa é criar uma classe e implementar três métodos: fit() 
(retornando self), transform() e fit_transform(). Você pode obter o último gratuitamente 
simplesmente adicionando TransformerMixin como uma classe base. Além disso, se você 
adicionar BaseEstimator como uma classe base (e evitar *args e **kargs em seu construtor), 
você obterá dois métodos extras (get_params() e set_params()) que serão úteis para o ajuste 
automático de hiperparâmetros. Por exemplo, aqui está uma pequena classe de transformador 
que adiciona os atributos combinados que discutimos anteriormente:
attr_adder = CombinedAttributesAdder(add_bedrooms_per_room=False) 
hosting_extra_attribs = attr_adder.transform(housing.values)
outro:
return np.c_[X, quartos_por_domicílio, população_por_domicílio]
return np.c_[X, quartos_por_domicílio, população_por_domicílio, 
quartos_por_quarto]
Dimensionamento de 
recursos Uma das transformações mais importantes que você precisa aplicar aos seus dados é o 
dimensionamento de recursos. Com poucas exceções, os algoritmos de aprendizado de máquina não 
funcionam bem quando os atributos numéricos de entrada têm escalas muito diferentes. Este é o caso 
dos dados de habitação: o número total de cômodos varia de cerca de 6 a 39.320, enquanto as rendas 
medianas variam apenas de 0 a 15. Observe que dimensionar os valores-alvo geralmente não é necessário.
Háduas maneiras comuns de fazer com que todos os atributos tenham a mesma escala: dimensionamento 
mínimo-máximo e padronização.
A escala min-max (muitas pessoas chamam isso de normalização) é bastante simples: os valores são 
deslocados e redimensionados de modo que acabem variando de 0 a 1. Fazemos isso subtraindo o valor 
mínimo e dividindo pelo máximo menos o mínimo. O Scikit-Learn fornece um transformador chamado 
MinMaxScaler para isso. Ele tem um hiperparâmetro feature_range que permite alterar o intervalo se você 
não quiser 0–1 por algum motivo.
Neste exemplo, o transformador tem um hiperparâmetro, add_bedrooms_per_room, definido como True 
por padrão (geralmente é útil fornecer padrões sensatos). Este hiperparâmetro permitirá que você 
descubra facilmente se adicionar este atributo ajuda os algoritmos de Machine Learning ou não. De 
maneira mais geral, você pode adicionar um hiperparâmetro para bloquear qualquer etapa de preparação 
de dados sobre a qual não tenha 100% de certeza. Quanto mais você automatizar essas etapas de 
preparação de dados, mais combinações poderá experimentar automaticamente, tornando muito mais 
provável que você encontre uma ótima combinação (e economizando muito tempo).
A padronização é bem diferente: primeiro ela subtrai o valor médio (portanto, os valores padronizados 
sempre têm uma média zero) e depois divide pela variância para que a distribuição resultante tenha 
variância unitária. Ao contrário da escala min-max, a padronização não limita os valores a um intervalo 
específico, o que pode ser um problema para alguns algoritmos (por exemplo, as redes neurais geralmente 
esperam um valor de entrada variando de 0 a 1). No entanto, a padronização é muito menos afetada por 
outliers. Por exemplo, suponha que um distrito tenha uma renda mediana igual a 100 (por engano). A 
escala min-max esmagaria então todos os outros valores de 0–15 para 0–0,15, enquanto a padronização 
não seria muito afetada. O Scikit-Learn fornece um transformador chamado StandardScaler para 
padronização.
Preparar os dados para algoritmos de aprendizado de máquina | 65
66 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Como em todas as transformações, é importante ajustar os escaladores apenas aos 
dados de treinamento, não ao conjunto de dados completo (incluindo o conjunto de teste).
Só então você pode usá-los para transformar o conjunto de treinamento e o conjunto 
de teste (e novos dados).
Agora você tem um pipeline para valores numéricos e também precisa aplicar o LabelBi narizer 
nos valores categóricos: como juntar essas transformações em um único pipeline? O Scikit-Learn 
fornece uma classe FeatureUnion para isso. Você fornece uma lista de transformadores (que 
podem ser pipelines inteiros de transformadores) e, quando seu método transform() é chamado, 
ele executa o método transform() de cada transformador em paralelo, aguarda sua saída e, em 
seguida, os concatena e retorna o resultado ( e, claro, chamar seu método fit() chama todos os 
métodos fit() de cada transformador ). Um pipeline completo lidando com atributos numéricos e 
categóricos pode ser assim:
O pipeline expõe os mesmos métodos que o estimador final. Neste exemplo, o último estimador 
é um StandardScaler, que é um transformador, então o pipeline possui um método trans form() 
que aplica todas as transformações aos dados em sequência (ele também possui um método 
fit_transform que poderíamos ter usado em vez de chamando fit() e depois transform()).
O construtor Pipeline obtém uma lista de pares nome/estimador definindo uma sequência de 
etapas. Todos, exceto o último estimador, devem ser transformadores (ou seja, devem ter um 
método fit_transform() ). Os nomes podem ser o que você quiser.
Pipelines de transformação 
Como você pode ver, há muitas etapas de transformação de dados que precisam ser executadas 
na ordem correta. Felizmente, o Scikit-Learn fornece a classe Pipeline para ajudar com essas 
sequências de transformações. Aqui está um pequeno pipeline para os atributos numéricos:
Quando você chama o método fit() do pipeline , ele chama fit_transform() sequencialmente em 
todos os transformadores, passando a saída de cada chamada como parâmetro para a próxima 
chamada, até chegar ao estimador final, para o qual chama apenas o fit() método.
de sklearn.pipeline import Pipeline de 
sklearn.preprocessing import StandardScaler
])
habitação_num_tr = num_pipeline.fit_transform(housing_num)
num_pipeline = 
Pipeline([ ('imputer', Imputer(strategy="median")), 
('attribs_adder', CombinedAttributesAdder()), 
('std_scaler', StandardScaler()),
Preparar os dados para algoritmos de aprendizado de máquina | 67
,
de sklearn.base import BaseEstimator, TransformerMixin
])
[-0,99102923, 1,63234656, -0,92655887, ...,
classe DataFrameSelector(BaseEstimator, TransformerMixin):
0.
def __init__(self, attribute_names):
de sklearn.pipeline import FeatureUnion
>>> habitação_preparada = full_pipeline.fit_transform(casa) >>> 
habitação_preparada 
array([[ 0,73225807, -0,67331551, 0,58426443, ...,
,
self.attribute_names = attribute_names
num_attribs = list(housing_num) 
cat_attribs = ["ocean_proximity"]
0.
,
def fit(self, X, y=None): return 
self
num_pipeline = 
Pipeline([ ('seletor', DataFrameSelector(num_attribs)), 
('imputer', Imputer(strategy="median")), 
('attribs_adder', CombinedAttributesAdder()), ('std_scaler', 
StandardScaler()) ,
,
0.
])
],
0. 
[...] 
>>> habitação_preparada.forma 
(16513, 17)
cat_pipeline = Pipeline([ ('seletor', 
DataFrameSelector(cat_attribs)), ('label_binarizer', 
LabelBinarizer()),
],
])
0.
full_pipeline = FeatureUnion(transformer_list=[ ("num_pipeline", 
num_pipeline), ("cat_pipeline", 
cat_pipeline),
0.
20 Mas verifique o Pull Request #3886, que pode introduzir uma classe ColumnTransformer facilitando as transformações 
específicas de atributos. Você também pode executar pip3 install sklearn-pandas para obter uma classe DataFrameMapper 
com um objetivo semelhante.
E você pode executar todo o pipeline simplesmente:
Cada subpipeline começa com um transformador seletor: ele simplesmente transforma os dados 
selecionando os atributos desejados (numéricos ou categóricos), descartando o restante e convertendo 
o DataFrame resultante em um array NumPy. Não há nada no Scikit-Learn para lidar com Pandas 
DataFrames,20 então precisamos escrever um transformador personalizado simples para esta tarefa:
68 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
def transform(self, X): return 
X[self.attribute_names].values
de sklearn.linear_model import LinearRegression
Marcadores:
Previsões: 
>>> print("Labels:\t\t", list(some_labels))
>>> from sklearn.metrics import mean_squared_error >>> 
housing_predictions = lin_reg.predict(housing_prepared) >>> lin_mse = 
mean_squared_error(housing_labels, using_predictions) >>> lin_rmse = 
np.sqrt(lin_mse) >>> lin_rmse 
68628.413493824875
>>> alguns_dados = habitação.iloc[:5] 
>>> alguns_rótulos = rótulos_de habitação.iloc[:5] 
>>> alguns_dados_preparados = full_pipeline.transform(alguns_dados) 
>>>print("Previsões:\t", lin_reg.predict (alguns_dados_preparados))
[359400.0, 69700.0, 302100.0, 301300.0, 351900.0]
[ 303104. 44800. 308928. 294208. 368704.]
lin_reg = LinearRegression() 
lin_reg.fit(housing_prepared, housing_labels)
Treinando e avaliando no conjunto de treinamento A boa 
notícia é que, graças a todas essas etapas anteriores, as coisas agora serão muito mais simples do 
que você imagina. Vamos primeiro treinar um modelo de Regressão Linear, como fizemos no capítulo 
anterior:
Feito! Agora você tem um modelo de regressão linear funcional. Vamos experimentá-lo em algumas 
instâncias do conjunto de treinamento:
Afinal! Você estruturou o problema, obteve os dados e os explorou, experimentou um conjunto de 
treinamento e um conjunto de teste e escreveu pipelines de transformação para limpar e preparar 
seus dados para algoritmos de aprendizado de máquina automaticamente. Agora você está pronto 
para selecionar e treinar um modelo de Machine Learning.
Ok, isso é melhor do que nada, mas claramente não é uma boa pontuação: os valores médios de 
habitação_da maioria dos distritos variam entre US$ 120.000 e US$ 265.000, portanto, um erro típico 
de previsão de US$ 68.628 não é muito satisfatório. Este é um exemplo de um modelo que subajusta 
os dados de treinamento. Quando isso acontece, pode significar que os recursos não fornecem 
informações suficientes para fazer boas previsões ou que o modelo não é poderoso o suficiente. 
Como vimos no capítulo anterior, as principais formas de corrigir o underfitting são
Funciona, embora as previsões não sejam exatamente precisas (por exemplo, a segunda previsão 
está errada em mais de 50%!). Vamos medir o RMSE desse modelo de regressão em todo o conjunto 
de treinamento usando a função mean_squared_error do Scikit-Learn :
Selecione e treine um modelo
selecione um modelo mais poderoso, para alimentar o algoritmo de treinamento com melhores recursos 
ou para reduzir as restrições do modelo. Este modelo não é regularizado, então isso exclui a última 
opção. Você pode tentar adicionar mais recursos (por exemplo, o log da população), mas primeiro vamos 
tentar um modelo mais complexo para ver como funciona.
Agora que o modelo está treinado, vamos avaliá-lo no conjunto de treinamento:
Uma ótima alternativa é usar o recurso de validação cruzada do Scikit-Learn. O código a seguir executa 
a validação cruzada K-fold: divide aleatoriamente o conjunto de treinamento em 10 subconjuntos distintos 
chamados dobras, depois treina e avalia o modelo da Árvore de Decisão 10 vezes, escolhendo uma 
dobra diferente para avaliação a cada vez e treinando nas outras 9 dobras.
Melhor avaliação usando validação cruzada Uma forma 
de avaliar o modelo de Árvore de Decisão seria usar a função train_test_split para dividir o conjunto de 
treinamento em um conjunto de treinamento menor e um conjunto de validação, então treinar seus 
modelos contra o conjunto de treinamento menor e avaliá-los contra o conjunto de validação. É um pouco 
trabalhoso, mas nada muito difícil e funcionaria razoavelmente bem.
Como vimos anteriormente, você não quer tocar no conjunto de teste até que esteja pronto para lançar 
um modelo no qual esteja confiante, então você precisa usar parte do conjunto de treinamento para 
treinamento e parte para validação do modelo.
Espere o que!? Nenhum erro? Este modelo poderia realmente ser absolutamente perfeito? Obviamente, 
é muito mais provável que o modelo tenha superajustado mal os dados. Como você pode ter certeza?
O resultado é uma matriz contendo as 10 pontuações de avaliação:
Vamos treinar um DecisionTreeRegressor. Este é um modelo poderoso, capaz de encontrar 
relacionamentos não lineares complexos nos dados (as Árvores de Decisão são apresentadas com mais 
detalhes no Capítulo 6). O código deve parecer familiar agora:
tree_reg = DecisionTreeRegressor() 
tree_reg.fit(housing_prepared, hosting_labels)
>>> habitação_predições = tree_reg.predict(housing_prepared) >>> 
tree_mse = mean_squared_error(housing_labels, hosting_predictions) >>> tree_rmse 
= np.sqrt(tree_mse) >>> tree_rmse 0.0
de sklearn.tree import DecisionTreeRegressor
de sklearn.model_selection importar pontuações 
cross_val_score = cross_val_score(tree_reg, habitação_preparada, habitação_labels, 
pontuação="neg_mean_squared_error", cv=10)
rmse_scores = np.sqrt(-scores)
Selecione e treine um modelo | 69
>>> display_scores(tree_rmse_scores)
...
Pontuações: [ 74678.4916885 64766.2398337 69632.86942005 69166.67693232 
71486.76507766 73321.65695983 71860.04741226 71086.32691692
>>> lin_rmse_scores = np.sqrt(-lin_scores) >>> 
display_scores(lin_rmse_scores)
76934.2726093 69060.93319262]
Scores: [ 70423.5893262 65804.84913139 66620.84314068 72510.11362141 
66414.74423281 71958.89083606 67624.90198297 67825.36117664 
72512.36533141 68028.11688067]
Média: 71199,4280043 
Desvio padrão: 3202,70522793
Média: 68972.377566
>>> def display_scores(scores): 
print("Pontuações:", 
pontuações) print("Média:", 
pontuações.média()) print("Desvio padrão:", pontuações.std())
Desvio padrão: 2493,98819069
...
...
>>> lin_scores = cross_val_score(lin_reg, habitação_preparada, habitação_labels,
...
pontuação="neg_mean_squared_error", cv=10)
...
...
70 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Os recursos de validação cruzada do Scikit-Learn esperam uma função 
de utilidade (maior é melhor) em vez de uma função de custo (menor é 
melhor), então a função de pontuação é na verdade o oposto do MSE 
(ou seja, um valor negativo), que é por que o código anterior calcula 
-scores antes de calcular a raiz quadrada.
Vejamos os resultados:
É isso mesmo: o modelo de Árvore de Decisão está superajustado tão mal que tem um desempenho pior do 
que o modelo de Regressão Linear.
Agora, a Árvore de Decisão não parece tão boa quanto antes. Na verdade, parece ter um desempenho pior 
do que o modelo de Regressão Linear! Observe que a validação cruzada permite que você obtenha não 
apenas uma estimativa do desempenho de seu modelo, mas também uma medida de quão precisa é essa 
estimativa (ou seja, seu desvio padrão). A Árvore de Decisão tem uma pontuação de aproximadamente 
71.200, geralmente ±3.200. Você não teria essas informações se usasse apenas um conjunto de validação. 
Mas a validação cruzada tem o custo de treinar o modelo várias vezes, por isso nem sempre é possível.
Vamos tentar um último modelo agora: o RandomForestRegressor. Como veremos no Capítulo 7, as Florestas 
Aleatórias funcionam treinando muitas Árvores de Decisão em subconjuntos aleatórios dos recursos e, em 
seguida, calculando a média de suas previsões. Construir um modelo sobre muitos outros modelos é chamado 
de Ensemble Learning, e muitas vezes é uma ótima maneira de levar os algoritmos de ML ainda mais longe. 
Vamos pular a maior parte do código, pois é essencialmente o mesmo dos outros modelos:
Vamos calcular as mesmas pontuações para o modelo de regressão linear apenas para ter certeza:
Ajuste seu modelo | 71
>>> display_scores(forest_rmse_scores)de sklearn.externals import joblib
>>> from sklearn.ensemble import RandomForestRegressor >>> forest_reg = 
RandomForestRegressor() >>> forest_reg.fit(housing_prepared, 
hosting_labels) >>> [...] >>> forest_rmse 22542.396440343684
Scores: [ 53789.2879722 50256.19806622 52521.55342602 53237.44937943 52428.82176158 
55854.61222549 52158.02291609 50093.66125649 53240.80406125 52761.50852822]
joblib.dump(my_model, "my_model.pkl") # e posterior... 
my_model_loaded 
= joblib.load("my_model.pkl")
Média: 52634,1919593 
Desvio padrão: 1576,20472269
Você deve salvar todos os modelos que experimentar, para poder voltar 
facilmente a qualquer modelo que desejar. Certifique-se de salvar os 
hiperparâmetros e os parâmetros treinados, bem como as pontuações de 
validação cruzada e talvez as previsões reais também.
Isso permitirá que você compare facilmente as pontuações entre os tipos 
de modelo e compare os tipos de erros que eles cometem. Você pode 
facilmente salvar modelos Scikit-Learn usando o módulo pickle do Python 
ou usando sklearn.externals.joblib, que é mais eficiente na serialização 
de grandes matrizes NumPy:
Ajuste seu modelo
No entanto, antes de mergulhar muito mais fundo em Random Forests, você deve experimentar muitos 
outros modelos de várias categorias de algoritmos de Machine Learning (várias Support Vector Machines 
com diferentes kernels, possivelmente uma rede neural, etc.), sem gastar muito tempo ajustando os 
hiperparâmetros. O objetivo é selecionar alguns (dois a cinco) modelos promissores.
Vamos supor que agora você tenha uma lista restrita de modelos promissores. Agora você precisa 
ajustá-los. Vejamos algumas maneiras de fazer isso.
Uau, isso é muito melhor: Random Forests parece muito promissor. No entanto, observe que a pontuação 
no conjunto de treinamento ainda é muito menor do que nos conjuntos de validação, o que significa que 
o modelo ainda está superajustando o conjunto de treinamento. As possíveis soluções para o overfitting 
são simplificar o modelo, restringi-lo (ou seja, regularizá-lo) ou obter muito mais dados de treinamento.
]
floresta_reg = RandomForestRegressor()
param_grid = 
[ {'n_estimators': [3, 10, 30], 'max_features': [2, 4, 6, 8]}, {'bootstrap': 
[False], 'n_estimators': [3, 10], 'max_features': [2, 3, 4]},
grid_search.fit(housing_prepared, housing_labels)
>>> grid_search.best_params_ 
{'max_features': 6, 'n_estimators': 30}
grid_search = GridSearchCV(forest_reg, param_grid, cv=5, 
scoring='neg_mean_squared_error')
de sklearn.model_selection importar GridSearchCV
72 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Pesquisa em grade
Quando você não tem ideia de qual valor um hiperparâmetro deve ter, 
uma abordagem simples é tentar potências consecutivas de 10 (ou um 
número menor se desejar uma pesquisa mais refinada, conforme 
mostrado neste exemplo com o hiperparâmetro n_estimators ) .
Este param_grid diz ao Scikit-Learn para primeiro avaliar todas as combinações 3 × 4 = 12 
de n_estimators e valores de hiperparâmetros max_features especificados no primeiro dict 
(não se preocupe com o que esses hiperparâmetros significam por enquanto; eles serão 
explicados no Capítulo 7), então tente todas as combinações 2 × 3 = 6 de valores de 
hiperparâmetros no segundo dict, mas desta vez com o hiperparâmetro bootstrap definido 
como False em vez de True (que é o valor padrão para este hiperparâmetro).
Uma maneira de fazer isso seria mexer nos hiperparâmetros manualmente, até encontrar 
uma ótima combinação de valores de hiperparâmetros. Isso seria um trabalho muito tedioso 
e você pode não ter tempo para explorar muitas combinações.
Em vez disso, você deve fazer com que o GridSearchCV do Scikit-Learn procure por você. 
Tudo o que você precisa fazer é dizer quais hiperparâmetros você deseja experimentar e 
quais valores experimentar, e ele avaliará todas as combinações possíveis de valores de 
hiperparâmetros, usando validação cruzada. Por exemplo, o código a seguir procura a 
melhor combinação de valores de hiperparâmetros para RandomForestRegressor:
Ao todo, a pesquisa de grade explorará 12 + 6 = 18 combinações de valores de 
hiperparâmetro RandomForestRegressor e treinará cada modelo cinco vezes (já que 
estamos usando validação cruzada de cinco vezes). Em outras palavras, ao todo, serão 18 
× 5 = 90 rodadas de treinamento! Pode levar muito tempo, mas quando terminar, você 
poderá obter a melhor combinação de parâmetros como esta:
...
64912.0351358 {'max_features': 2, 'n_estimators': 3} 
55535.2786524 {'max_features': 2, 'n_estimators': 10} 
52940.2696165 {'max_features': 2, 'n_estimators': 30} 
60384.09084354 'n_estimators': 3} 52709.9199934 
{'max_features': 4, 'n_estimators': 10} 50503.5985321 
{'max_features': 4, 'n_estimators': 30} 59058.1153485 
{'max_features': 6, 'n_estimators': 3} 02292,7 52172,7 52172,7 
'max_features': 6, 'n_estimators': 10} 49958.9555932 
{'max_features': 6, 'n_estimators': 30} 59122.260006 
{'max_features': 8, 'n_estimators': 3} 52441.5896087 
{'max_features': 8, 'n_estimators ': 10} 50041.4899416 
{'max_features': 8, 'n_estimators': 30} 62371.1221202 {'bootstrap': 
False, 'max_features': 2, 'n_estimators': 3} 54572.2557534 {'bootstrap': False, 
'max_features': 2, 'n_estimators': 10} 59634.0533132 {'bootstrap': False, 'max_features': 
3, 'n_estimators': 3} 52456.0883904 {'bootstrap': False, 'max_features': 3, 'n_estimators': 
10} 58825.665239 { 'bootstrap': False, 'max_features': 4, 'n_estimators': 3} 52012.9945396 
{'bootstrap': False, 'max_features': 4, 'n_estimators': 10}
print(np.sqrt(-mean_score), params)
...
>>> grid_search.best_estimator_ 
RandomForestRegressor(bootstrap=True, critério='mse', max_depth=None, 
max_features=6, max_leaf_nodes=None, min_samples_leaf=1, 
min_samples_split=2, min_weight_fraction_leaf=0,0, 
n_estimators=30, n_jobs=1, oob_score=Falso, random_state=Nenhum, 
detalhado=0, warm_start=Falso)
>>> cvres = grid_search.cv_results_ ... for 
mean_score, params in zip(cvres["mean_test_score"], cvres["params"]):
Ajuste seu modelo | 73
Como 30 é o valor máximo de n_estimators que foi avaliado, você 
provavelmente deve avaliar valores mais altos também, pois a pontuação 
pode continuar a melhorar.
mance.
Se GridSearchCV for inicializado com refit=True (que é o padrão), assim 
que encontrar o melhor estimador usando validação cruzada, ele o treinará 
novamente em todo o conjunto de treinamento. Isso geralmente é uma boa 
ideia, pois fornecer mais dados provavelmente melhorará seu desempenho.
E, claro, as pontuações de avaliação também estão disponíveis:
Você também pode obter o melhor estimador diretamente:
Neste exemplo, obtemos a melhor solução definindo o hiperparâmetro max_features como 6 e o hiperparâmetro 
n_estimators como 30. A pontuação RMSE para essa combinação é 49.959, ligeiramente melhor do que a 
pontuação obtida anteriormente usando o método
Métodos de conjunto
Pesquisa aleatória
>>> feature_importances = grid_search.best_estimator_.feature_importances_ >>> array 
feature_importances 
([ 7.14156423e-02, 6.76139189e-02, 4.44260894e-02,
Abordaremos esse tópico com mais detalhesno Capítulo 7.
A abordagem de pesquisa de grade é boa quando você está explorando relativamente poucas 
combinações, como no exemplo anterior, mas quando o espaço de pesquisa de hiperparâmetros é 
grande, geralmente é preferível usar RandomizedSearchCV . Essa classe pode ser usada da mesma 
forma que a classe GridSearchCV , mas em vez de tentar todas as combinações possíveis, ela avalia 
um determinado número de combinações aleatórias selecionando um valor aleatório para cada 
hiperparâmetro a cada iteração. Essa abordagem tem dois benefícios principais:
• Você tem mais controle sobre o orçamento de computação que deseja alocar para pesquisa de 
hiperparâmetros, simplesmente definindo o número de iterações.
Outra forma de ajustar seu sistema é tentar combinar os modelos com melhor desempenho. O grupo 
(ou “conjunto”) geralmente terá um desempenho melhor do que o melhor modelo individual (assim 
como as Florestas Aleatórias funcionam melhor do que as Árvores de Decisão individuais das quais 
dependem), especialmente se os modelos individuais cometerem tipos de erros muito diferentes.
valores de hiperparâmetro padrão (que era 52.634). Parabéns, você ajustou com sucesso o seu melhor 
modelo!
• Se você permitir que a pesquisa aleatória seja executada por, digamos, 1.000 iterações, essa 
abordagem explorará 1.000 valores diferentes para cada hiperparâmetro (em vez de apenas 
alguns valores por hiperparâmetro com a abordagem de pesquisa em grade).
Analise os melhores modelos e seus erros Muitas vezes, 
você obterá bons insights sobre o problema inspecionando os melhores modelos. Por exemplo, o 
RandomForestRegressor pode indicar a importância relativa de cada atributo para fazer previsões 
precisas:
74 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
Não esqueça que você pode tratar algumas das etapas de preparação de dados 
como hiperparâmetros. Por exemplo, a pesquisa de grade descobrirá 
automaticamente se deve ou não adicionar um recurso sobre o qual você não 
tinha certeza (por exemplo, usando o hiperparâmetro add_bedrooms_per_room 
do seu transformador CombinedAttributesAdder ). Da mesma forma, pode ser 
usado para encontrar automaticamente a melhor maneira de lidar com outliers, 
recursos ausentes, seleção de recursos e muito mais.
final_model = grid_search.best_estimator_
X_test_prepared = full_pipeline.transform(X_test)
1.66308583e-02, 1.66076861e-02, 1.82402545e-02, 
1.63458761e-02, 3.26497987e-01, 6.04365775e-02, 
1.13055290e-01, 7.79324766e-02, 1.12166442e-02, 
1.53344918e-01, 8.41308969e-05, 2.68483884e-03, 
3.46681181e-03])
>>> extra_attribs = ["rooms_per_hhold", "pop_per_hhold", "bedrooms_per_room"] >>> 
cat_one_hot_attribs = list(encoder.classes_) >>> attribute 
= num_attribs + extra_attribs + cat_one_hot_attribs >>> 
sorted(zip(feature_importances, attribute) , reverse=True) 
[(0.32649798665134971, 'median_income'), 
(0.15334491760305854, 'INLAND'), 
(0.11305529021187399, 'pop_per_hhold'), 
(0.07793247662544775, 'bedrooms_per_room'), 
(0.071415642259275158, 'longitude'), 
(0.067613918945568688, ' latitude'), 
(0.060436577499703222, 'rooms_per_hhold'), 
(0.04442608939578685, 'housing_median_age'), 
(0.018240254462909437, 'population'), 
(0.01663085833886218, 'total_rooms'), 
(0.016607686091288865, 'total_bedrooms'), 
(0.016345876147580776, 'households' )
X_test = strat_test_set.drop("median_house_value", axis=1) y_test = 
strat_test_set["median_house_value"].copy()
Vamos exibir essas pontuações de importância ao lado de seus nomes de atributos correspondentes:
Com esta informação, você pode tentar descartar alguns dos recursos menos úteis (por exemplo, 
aparentemente apenas uma categoria ocean_proximity é realmente útil, então você pode tentar descartar 
as outras).
Avalie seu sistema no conjunto de teste Depois de 
ajustar seus modelos por um tempo, você finalmente terá um sistema com um desempenho suficientemente 
bom. Agora é a hora de avaliar o modelo final no conjunto de teste. Não há nada de especial nesse 
processo; apenas pegue os preditores e os rótulos do seu conjunto de teste, execute seu full_pipeline para 
transformar os dados (chame transform(), não fit_transform()!), e avalie o modelo final no conjunto de teste:
Você também deve observar os erros específicos que seu sistema comete e, em seguida, tentar entender 
por que ele os comete e o que poderia resolver o problema (adicionar recursos extras ou, pelo contrário, 
eliminar os não informativos, limpar valores discrepantes, etc. .).
Ajuste seu modelo | 75
76 | Capítulo 2: Projeto de aprendizado de máquina de ponta a ponta
final_predictions = final_model.predict(X_test_prepared)
final_mse = mean_squared_error(y_test, final_predictions) final_rmse 
= np.sqrt(final_mse) # => avalia para 48.209,6
Inicie, monitore e mantenha seu sistema
Você também deve certificar-se de avaliar a qualidade dos dados de entrada do sistema. Às vezes, o desempenho 
diminui ligeiramente devido a um sinal de baixa qualidade (por exemplo, um sensor com defeito enviando valores 
aleatórios ou a saída de outra equipe tornando-se obsoleta), mas pode demorar um pouco até que o desempenho 
do seu sistema diminua o suficiente para acionar um alerta. Se você monitorar as entradas do seu sistema, 
poderá perceber isso antes. Monitorar as entradas é particularmente importante para sistemas de aprendizagem 
online.
Agora vem a fase de pré-lançamento do projeto: você precisa apresentar sua solução (destacando o que 
aprendeu, o que funcionou e o que não funcionou, quais suposições foram feitas e quais são as limitações do 
seu sistema), documentar tudo e criar boas apresentações com visualizações claras e declarações fáceis de 
lembrar (por exemplo, “a renda mediana é o preditor número um dos preços das casas”).
Perfeito, você obteve aprovação para lançar! Você precisa preparar sua solução para produção, em particular 
conectando as fontes de dados de entrada de produção em seu sistema e escrevendo testes.
Avaliar o desempenho do seu sistema exigirá a amostragem das previsões do sistema e sua avaliação. Isso 
geralmente requer uma análise humana. Esses analistas podem ser especialistas de campo ou trabalhadores em 
uma plataforma de crowdsourcing (como Amazon Mechanical Turk ou CrowdFlower). De qualquer forma, você 
precisa conectar o pipeline de avaliação humana ao seu sistema.
O desempenho geralmente será um pouco pior do que o que você mediu usando a validação cruzada se você 
fez muitos ajustes de hiperparâmetros (porque seu sistema acaba ajustado para ter um bom desempenho nos 
dados de validação e provavelmente não terá um desempenho tão bom em conjuntos de dados desconhecidos) . 
Não é o caso neste exemplo, mas quando isso acontecer, você deve resistir à tentação de ajustar os 
hiperparâmetros para fazer os números parecerem bons no conjunto de teste; seria improvável que as melhorias 
se generalizassem para novos dados.
Por fim, geralmente você desejará treinar seus modelos regularmente usando dados novos. Você deve 
automatizar esse processo o máximopossível. Se não o fizer, você é muito
Você também precisa escrever código de monitoramento para verificar o desempenho ao vivo do seu sistema em 
intervalos regulares e disparar alertas quando ele cair. Isso é importante para detectar não apenas a quebra 
repentina, mas também a degradação do desempenho. Isso é bastante comum porque os modelos tendem a 
“apodrecer” à medida que os dados evoluem ao longo do tempo, a menos que os modelos sejam treinados 
regularmente em dados novos.
Usando o conjunto de dados de habitação deste capítulo:
Os algoritmos de Machine Learning também são importantes, é claro, mas provavelmente é preferível estar 
confortável com o processo geral e conhecer bem três ou quatro algoritmos, em vez de gastar todo o seu 
tempo explorando algoritmos avançados e não ter tempo suficiente no processo geral. .
Espero que este capítulo tenha lhe dado uma boa ideia de como é um projeto de aprendizado de máquina 
e mostrado algumas das ferramentas que você pode usar para treinar um ótimo sistema. Como você pode 
ver, grande parte do trabalho está na etapa de preparação de dados, na criação de ferramentas de 
monitoramento, na configuração de pipelines de avaliação humana e na automação do treinamento regular de modelos.
3. Tente adicionar um transformador no pipeline de preparação para selecionar apenas o mais
atributos importantes.
2. Tente substituir GridSearchCV por RandomizedSearchCV.
As soluções para esses exercícios estão disponíveis nos notebooks Jupyter on-line em https:// github.com/
ageron/handson-ml.
5. Explore automaticamente algumas opções de preparação usando GridSearchCV.
Qual é o desempenho do melhor preditor de SVR ?
provavelmente atualizará seu modelo apenas a cada seis meses (na melhor das hipóteses), e o desempenho 
do seu sistema pode flutuar severamente ao longo do tempo. Se o seu sistema for um sistema de 
aprendizado on-line, certifique-se de salvar instantâneos de seu estado em intervalos regulares para poder 
reverter facilmente para um estado de trabalho anterior.
Portanto, se você ainda não o fez, agora é uma boa hora para pegar um laptop, selecionar um conjunto de 
dados de seu interesse e tentar passar por todo o processo de A a Z. Um bom lugar para começar é em um 
site de competição como http://kaggle.com/: você terá um conjunto de dados para usar, um objetivo claro e 
pessoas com quem compartilhar a experiência.
1. Experimente um regressor Support Vector Machine (sklearn.svm.SVR), com vários hiperparâmetros, 
como kernel="linear" (com vários valores para o hiperparâmetro C ) ou kernel="rbf" (com vários valores 
para os hiperparâmetros C e gama ). Não se preocupe com o que esses hiperparâmetros significam 
por enquanto.
predição.
4. Tente criar um único pipeline que faça a preparação completa dos dados mais o final
Experimente!
exercícios
Experimente! | 77
https://github.com/ageron/handson-ml
https://github.com/ageron/handson-ml
http://kaggle.com/
MNIST
>>> from sklearn.datasets import fetch_mldata >>> 
mnist = fetch_mldata('MNIST original') >>> mnist
{'COL_NAMES': ['label', 'data'], 
'DESCR': 'mldata.org dataset: mnist-original', 'data': 
array([[0, 0, 0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 0, 0],
CAPÍTULO 3
No Capítulo 1 mencionamos que as tarefas de aprendizado supervisionado mais comuns são 
regressão (previsão de valores) e classificação (previsão de classes). No Capítulo 2 , exploramos 
uma tarefa de regressão, prevendo valores habitacionais, usando vários algoritmos, como 
Regressão Linear, Árvores de Decisão e Florestas Aleatórias (que serão explicadas com mais 
detalhes em capítulos posteriores). Agora voltaremos nossa atenção para os sistemas de 
classificação.
Neste capítulo, usaremos o conjunto de dados MNIST, que é um conjunto de 70.000 pequenas 
imagens de dígitos escritas à mão por alunos do ensino médio e funcionários do US Census 
Bureau. Cada imagem é rotulada com o dígito que representa. Esse conjunto foi tão estudado que 
costuma ser chamado de “Hello World” do Machine Learning: sempre que as pessoas criam um 
novo algoritmo de classificação, ficam curiosas para ver como ele se comportará no MNIST. 
Sempre que alguém aprende Machine Learning, mais cedo ou mais tarde ele aborda o MNIST.
O Scikit-Learn fornece muitas funções auxiliares para baixar conjuntos de dados populares. O 
MNIST é um deles. O código a seguir busca o conjunto de dados MNIST:1
1 Por padrão, o Scikit-Learn armazena em cache os conjuntos de dados baixados em um diretório chamado $HOME/scikit_learn_data.
79
Classificação
[0, 0, 0, ..., 0, 0, 0],
>>> X.shape 
(70000, 784) 
>>> y.shape 
(70000,)
plt.imshow(some_digit_image, cmap = matplotlib.cm.binary, 
interpolation="mais próximo") 
plt.axis("off") 
plt.show()
>>> X, y = mnist["dados"], mnist["alvo"]
some_digit = X[36000] 
some_digit_image = some_digit.reshape(28, 28)
[0, 0, 0, ..., 0, 0, 0], [0, 0, 
0, ..., 0, 0, 0], [0, 0, 0, ..., 0, 
0 , 0]], dtype=uint8), 'target': array([ 0., 0., 0., ..., 
9., 9., 9.])}
%matplotlib 
importação em linha 
matplotlib importação matplotlib.pyplot como plt
...,
recurso
Os conjuntos de dados carregados pelo Scikit-Learn geralmente têm uma estrutura de dicionário semelhante, 
incluindo:
• Uma chave de destino contendo uma matriz com os rótulos
• Uma chave DESCR descrevendo o conjunto de 
dados • Uma chave de dados contendo uma matriz com uma linha por instância e uma coluna por
Vejamos essas matrizes:
Existem 70.000 imagens e cada imagem possui 784 recursos. Isso ocorre porque cada imagem tem 28 × 28 pixels 
e cada recurso representa simplesmente a intensidade de um pixel, de 0 (branco) a 255 (preto). Vamos dar uma 
olhada em um dígito do conjunto de dados. Tudo o que você precisa fazer é pegar o vetor de recurso de uma 
instância, remodelá-lo para uma matriz de 28 × 28 e exibi-lo usando a função imshow() do Matplotlib :
Parece um 5 e, de fato, é isso que o rótulo nos diz:
80 | Capítulo 3: Classificação
2 Embaralhar pode ser uma má ideia em alguns contextos - por exemplo, se você estiver trabalhando com dados de séries temporais (como
MNIST | 81
X_train, X_test, y_train, y_test = X[:60000], X[60000:], y[:60000], y[60000:]
>>> y[36000] 
5,0
preços do mercado de ações ou condições climáticas). Exploraremos isso nos próximos capítulos.
Mas espere! Você sempre deve criar um conjunto de teste e separá-lo antes de inspecionar os dados de perto. 
Na verdade, o conjunto de dados MNIST já está dividido em um conjunto de treinamento (as primeiras 60.000 
imagens) e um conjunto de teste (as últimas 10.000 imagens):
Vamos também embaralhar o conjunto de treinamento; isso garantirá que todas as dobras de validação cruzada 
serão semelhantes (você não quer que uma dobra fique com alguns dígitos faltando). Além disso, alguns 
algoritmos de aprendizado são sensíveis à ordem das instâncias de treinamento e têm desempenho ruim se 
obtiverem muitas instâncias semelhantes seguidas. Embaralhar o conjunto de dados garanteque isso não 
aconteça:2
Figura 3-1. Alguns dígitos do conjunto de dados MNIST
A Figura 3-1 mostra mais algumas imagens do conjunto de dados MNIST para dar uma ideia da complexidade 
da tarefa de classificação.
82 | Capítulo 3: Classificação
y_train_5 = (y_train == 5) # Verdadeiro para todos os 5s, Falso para todos os outros dígitos. 
y_test_5 = (y_test == 5)
de sklearn.linear_model import SGDClassifier
importar numpy como np
X_train, y_train = X_train[shuffle_index], y_train[shuffle_index]
>>> sgd_clf.predict([some_digit]) 
array([ True], dtype=bool)
sgd_clf = SGDClassifier(random_state=42) 
sgd_clf.fit(X_train, y_train_5)
shuffle_index = np.random.permutation(60000)
Isso ocorre em parte porque o SGD lida com instâncias de treinamento de forma independente, uma de 
cada vez (o que também torna o SGD adequado para aprendizado online), como veremos mais adiante. 
Vamos criar um SGDClassifier e treiná-lo em todo o conjunto de treinamento:
Vamos simplificar o problema por enquanto e tentar identificar apenas um dígito – por exemplo, o número 
5. Este “detector 5” será um exemplo de classificador binário, capaz de distinguir entre apenas duas classes, 
5 e não-5. Vamos criar os vetores de destino para esta tarefa de classificação:
Agora você pode usá-lo para detectar imagens do número 5:
Ok, agora vamos escolher um classificador e treiná-lo. Um bom lugar para começar é com um classificador 
Stochastic Gradient Descent (SGD), usando a classe SGDClassifier do Scikit-Learn . Este classificador tem 
a vantagem de ser capaz de lidar com conjuntos de dados muito grandes de forma eficiente.
O classificador adivinha que esta imagem representa um 5 (Verdadeiro). Parece que acertou nesse caso 
em particular! Agora, vamos avaliar o desempenho deste modelo.
Avaliar um classificador costuma ser significativamente mais complicado do que avaliar um regressor; 
portanto, dedicaremos grande parte deste capítulo a esse tópico. Existem muitas medidas de desempenho 
disponíveis, então pegue outro café e prepare-se para aprender muitos novos conceitos e siglas!
O SGDClassifier depende da aleatoriedade durante o treinamento 
(daí o nome “estocástico”). Se você deseja resultados reproduzíveis, 
deve definir o parâmetro random_state .
Treinando um Classificador Binário
Medidas de Desempenho
A classe StratifiedKFold executa amostragem estratificada (conforme explicado no Capítulo 
2) para produzir dobras que contêm uma proporção representativa de cada classe. A cada 
iteração, o código cria um clone do classificador, treina esse clone nas dobras de 
treinamento e faz previsões na dobra de teste. Em seguida, ele conta o número de previsões 
corretas e gera a proporção de previsões corretas.
Implementando validação cruzada 
Ocasionalmente, você precisará de mais controle sobre o processo de validação cruzada 
do que cross_val_score() e funções semelhantes fornecem. Nesses casos, você mesmo 
pode implementar a validação cruzada; na verdade, é bastante simples. O código a seguir 
faz aproximadamente a mesma coisa que o código cross_val_score() anterior e imprime o 
mesmo resultado:
da importação do sklearn.model_selection StratifiedKFold 
do clone da importação do sklearn.base
X_train_folds = X_train[train_index] 
y_train_folds = (y_train_5[train_index])
X_test_fold = X_train[test_index] 
y_test_fold = (y_train_5[test_index])
para train_index, test_index em skfolds.split(X_train, y_train_5): clone_clf = 
clone(sgd_clf)
skfolds = StratifiedKFold(n_splits=3, random_state=42)
>>> from sklearn.model_selection import cross_val_score >>> 
cross_val_score(sgd_clf, X_train, y_train_5, cv=3, scoring="accuracy") array([ 0.9502 , 
0.96565, 0.96495])
clone_clf.fit(X_train_folds, y_train_folds) y_pred = 
clone_clf.predict(X_test_fold) n_correct = 
sum(y_pred == y_test_folds) print(n_correct / 
len(y_pred)) # imprime 0,9502, 0,96565 e 0,96495
Medindo a precisão usando a validação cruzada
Medidas de Desempenho | 83
Uma boa maneira de avaliar um modelo é usar validação cruzada, assim como você fez no Capítulo
ter 2.
Vamos usar a função cross_val_score() para avaliar seu modelo SGDClassifier usando a validação 
cruzada K-fold, com três dobras. Lembre-se que a validação cruzada K-fold significa dividir o 
conjunto de treinamento em K-folds (neste caso, três), então fazer previsões e avaliá-las em cada 
dobra usando um modelo treinado nas dobras restantes (consulte o Capítulo 2 ) :
84 | Capítulo 3: Classificação
Isso demonstra porque a precisão geralmente não é a medida de desempenho preferida para classificadores, 
especialmente quando você está lidando com conjuntos de dados distorcidos (ou seja, quando algumas classes são 
muito mais frequentes do que outras).
matriz.
Uma maneira muito melhor de avaliar o desempenho de um classificador é olhar para a matriz de confusão. A ideia 
geral é contar o número de vezes que instâncias da classe A são classificadas como classe B. Por exemplo, para 
saber o número de vezes que o classificador confundiu imagens de 5s com 3s, você procuraria na 5ª linha e 3ª 
coluna do confusão
Isso mesmo, tem mais de 90% de precisão! Isso ocorre simplesmente porque apenas cerca de 10% das imagens 
são 5s; portanto, se você sempre adivinhar que uma imagem não é um 5, estará certo cerca de 90% das vezes. Bate 
Nostradamus.
Assim como a função cross_val_score() , cross_val_predict() realiza validação cruzada K-fold, mas em vez de retornar 
as pontuações de avaliação, ela retorna as previsões feitas em cada dobra de teste. Isso significa que você obtém 
uma previsão limpa para cada instância no conjunto de treinamento (“limpa” significa que a previsão é feita por um 
modelo que nunca viu os dados durante o treinamento).
Isso parece incrível, não é? Bem, antes que você fique muito animado, vejamos um classificador muito burro que 
apenas classifica todas as imagens na classe “not-5”:
Você consegue adivinhar a precisão deste modelo? Vamos descobrir:
Uau! Acima de 95% de precisão (proporção de previsões corretas) em todas as dobras de validação cruzada?
Em vez disso, você pode usar a função cross_val_predict() :
Para calcular a matriz de confusão, primeiro você precisa ter um conjunto de previsões, para que possam ser 
comparadas com os alvos reais. Você poderia fazer previsões no conjunto de teste, mas vamos mantê-lo intacto por 
enquanto (lembre-se de que você deseja usar o conjunto de teste apenas no final do seu projeto, assim que tiver um 
classificador pronto para iniciar).
Matriz de Confusão
>>> never_5_clf = Never5Classifier() >>> 
cross_val_score(never_5_clf, X_train, y_train_5, cv=3, scoring="precisão") array([ 0,909
, 0,90715, 0,9128 ])
de sklearn.model_selection importar cross_val_predict
de sklearn.base importar BaseEstimator
y_train_pred = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3)
class Never5Classifier(BaseEstimator): def 
fit(self, X, y=None): pass def 
predict(self, X): return 
np.zeros((len(X), 1), dtype=bool)
precisão =
PT
PT + FN
TP + PF
PT
lembre-se =
FN é, obviamente, o número de falsosnegativos.
Cada linha em uma matriz de confusão representa uma classe real, enquanto cada coluna representa uma 
classe prevista. A primeira linha desta matriz considera imagens não-5 (a classe negativa): 53.272 delas 
foram classificadas corretamente como não-5s (são chamadas de verdadeiros negativos), enquanto as 
1.307 restantes foram erroneamente classificadas como 5s (falsos positivos). .
TP é o número de verdadeiros positivos e FP é o número de falsos positivos.
Equação 3-1. Precisão
A matriz de confusão fornece muitas informações, mas às vezes você pode preferir uma métrica mais 
concisa. Uma observação interessante é a precisão das previsões positivas; isso é chamado de precisão 
do classificador (Equação 3-1).
Uma maneira trivial de obter precisão perfeita é fazer uma única previsão positiva e garantir que ela esteja 
correta (precisão = 1/1 = 100%). Isso não seria muito útil, pois o classificador ignoraria todas as instâncias 
positivas, exceto uma. Portanto, a precisão é normalmente usada junto com outra métrica chamada recall, 
também chamada de sensibilidade ou taxa de verdadeiros positivos (TPR): essa é a proporção de instâncias 
positivas que são detectadas corretamente pelo classificador (Equação 3-2).
Agora você está pronto para obter a matriz de confusão usando a função confusion_matrix() . Basta passar 
as classes alvo (y_train_5) e as classes previstas (y_train_pred):
A segunda linha considera as imagens de 5s (a classe positiva): 1.077 foram erroneamente classificadas 
como não-5s (falsos negativos), enquanto as 4.344 restantes foram classificadas corretamente como 5s 
(verdadeiros positivos). Um classificador perfeito teria apenas verdadeiros positivos e verdadeiros negativos, 
então sua matriz de confusão teria valores diferentes de zero apenas em sua diagonal principal (canto 
superior esquerdo para canto inferior direito):
Equação 3-2. Lembrar
>>> from sklearn.metrics import confusion_matrix >>> 
confusion_matrix(y_train_5, y_train_pred) array([[53272, 
1307], [ 1077, 4344]])
>>> matriz_confusão(y_train_5, y_train_perfect_predictions) array([[54579, 
0], [ 0, 5421]])
Medidas de Desempenho | 85
1
2
1 
+ precisão de rechamada
FN + PF
86 | Capítulo 3: Classificação
Geralmente é conveniente combinar precisão e revocação em uma única métrica chamada pontuação F1 , 
especialmente se você precisar de uma maneira simples de comparar dois classificadores. A pontuação F1 
é a média harmônica de precisão e revocação (Equação 3-3). Enquanto a média regular trata todos os 
valores igualmente, a média harmônica dá muito mais peso aos valores baixos.
Quando afirma que uma imagem representa um 5, ela está correta apenas 77% das vezes. Além disso, 
detecta apenas 79% dos 5s.
Agora seu detector de 5 não parece tão brilhante quanto quando você olhou para sua precisão.
Figura 3-2. Uma matriz de confusão ilustrada
Equação 3-3. pontuação F1
Se você está confuso sobre a matriz de confusão, a Figura 3-2 pode ajudar.
Como resultado, o classificador só obterá uma pontuação F1 alta se tanto o recall quanto a precisão forem 
altos.
O Scikit-Learn fornece várias funções para calcular as métricas do classificador, incluindo precisão e 
recuperação:
>>> from sklearn.metrics import preciso_score, recall_score >>> 
precisos_score(y_train_5, y_pred) # == 4344 / (4344 + 1307) 0,76871350203503808 
>>> recall_score(y_train_5, 
y_train_pred) # == 4344 / (4344 + 1077) 0,79136690647482011
precisão × rechamada 
precisão + rechamada
2
F1 =
PT=
PT +
= 2 ×
Precisão e Recall
>>> de sklearn.metrics import f1_score >>> 
f1_score(y_train_5, y_pred) 
0,78468208092485547
Medidas de desempenho | 87
Para entender essa compensação, vamos ver como o SGDClassifier toma suas decisões de classificação. 
Para cada instância, ele calcula uma pontuação com base em uma função de decisão e, se essa 
pontuação for maior que um limite, atribui a instância à classe positiva ou à classe negativa. A Figura 
3-3 mostra alguns dígitos posicionados da pontuação mais baixa à esquerda até a pontuação mais alta 
à direita. Suponha que o limite de decisão esteja posicionado na seta central (entre os dois 5s): você 
encontrará 4 verdadeiros positivos (5s reais) à direita desse limite e um falso positivo (na verdade um 
6). Portanto, com esse limite, a precisão é de 80% (4 de 5). Mas de 6 5s reais, o classificador detecta 
apenas 4, então a rechamada é de 67% (4 de 6). Agora, se você aumentar o limite (mova-o para a seta 
à direita), o falso positivo (o 6) se torna um verdadeiro negativo, aumentando assim a precisão (até 
100% neste caso), mas um verdadeiro positivo se torna um falso negativo , diminuindo a rechamada 
para 50%. Por outro lado, diminuir o limite aumenta a rechamada e reduz a precisão.
Para calcular a pontuação F1 , basta chamar a função f1_score() :
A pontuação F1 favorece classificadores que possuem precisão e revocação semelhantes. Isso nem 
sempre é o que você quer: em alguns contextos você se preocupa mais com a precisão, e em outros 
contextos você realmente se preocupa com a recordação. Por exemplo, se você treinou um classificador 
para detectar vídeos seguros para crianças, provavelmente preferiria um classificador que rejeitasse 
muitos vídeos bons (recuperação baixa), mas mantivesse apenas os seguros (alta precisão), em vez de 
um classificador que tem um recall muito maior, mas permite que alguns vídeos realmente ruins 
apareçam em seu produto (nesses casos, você pode até querer adicionar um pipeline humano para 
verificar a seleção de vídeo do classificador). Por outro lado, suponha que você treine um classificador 
para detectar ladrões em imagens de vigilância: provavelmente não há problema se seu classificador 
tiver apenas 30% de precisão, desde que tenha 99% de recuperação (claro, os guardas de segurança 
receberão alguns alertas falsos, mas quase todos os ladrões de lojas serão pegos).
Infelizmente, você não pode ter as duas coisas: aumentar a precisão reduz o recall e vice-versa. Isso é 
chamado de tradeo de precisão/recall.
Compensação Precisão/Recall
O Scikit-Learn não permite definir o limite diretamente, mas fornece acesso às pontuações de 
decisão que ele usa para fazer previsões. Em vez de chamar o método predict() do classificador , 
você pode chamar seu método decision_function() , que retorna uma pontuação para cada 
instância e, em seguida, fazer previsões com base nessas pontuações usando qualquer limite 
desejado:
Isso confirma que aumentar o limite diminui a rechamada. A imagem realmente representa um 
5, e o classificador o detecta quando o limite é 0, mas o perde quando o limite é aumentado para 
200.000.
O SGDClassifier usa um limite igual a 0, então o código anterior retorna o mesmo resultado que 
o método predict() (ou seja, True). Vamos aumentar o limite:
Figura 3-3. Limiar de decisão e negociação de precisão/recallo
Agora, com essas pontuações, você pode calcular a precisão e a rechamada para todos os 
limitespossíveis usando a função precisão_recall_curve() :
Então, como você pode decidir qual limite usar? Para isso, primeiro você precisará obter as 
pontuações de todas as instâncias no conjunto de treinamento usando a função cross_val_predict() 
novamente, mas desta vez especificando que deseja retornar pontuações de decisão em vez de 
previsões:
>>> y_scores = sgd_clf.decision_function([some_digit])
método="decisão_função")
>>> y_scores 
array([ 161855.74572176]) 
>>> threshold = 0 
>>> y_some_digit_pred = (y_scores > threshold) 
array([ True], dtype=bool)
>>> threshold = 200000 
>>> y_some_digit_pred = (y_scores > threshold) >>> 
y_some_digit_pred 
array([False], dtype=bool)
y_scores = cross_val_predict(sgd_clf, X_train, y_train_5, cv=3,
88 | Capítulo 3: Classificação
Medidas de Desempenho | 89
de sklearn.metrics importar precisão_recall_curve
plot_precision_recall_vs_threshold(precisões, rechamadas, limiares) plt.show()
precisões, rechamadas, limites = precisão_recall_curve(y_train_5, y_scores)
def plot_precision_recall_vs_threshold(precisões, rechamadas, limites): plt.plot(limiares, 
precisões[:-1], "b--", label="Precisão") plt.plot(limiares, rechamadas[:-1], "g -", 
label="Recall") plt.xlabel("Threshold") plt.legend(loc="superior 
esquerdo") plt.ylim([0, 1])
Você pode se perguntar por que a curva de precisão é mais irregular 
do que a curva de rechamada na Figura 3-4. O motivo é que a precisão 
às vezes pode diminuir quando você aumenta o limite (embora, em 
geral, aumente). Para entender por que, olhe novamente para a Figura 
3-3 e observe o que acontece quando você começa no limiar central e 
move apenas um dígito para a direita: a precisão vai de 4/5 (80%) para 
3/4 (75% ). Por outro lado, a rechamada só pode diminuir quando o 
limiar é aumentado, o que explica por que sua curva parece suave.
Agora você pode simplesmente selecionar o valor limite que oferece a melhor compensação de precisão/
recuperação para sua tarefa. Outra maneira de selecionar uma boa compensação de precisão/recall é plotar a 
precisão diretamente em relação ao recolhimento, conforme mostrado na Figura 3-5.
Figura 3-4. Precisão e recall versus o limite de decisão
Por fim, você pode plotar a precisão e a rechamada como funções do valor limite usando
Matplotlib (Figura 3-4):
Se alguém disser "vamos atingir 99% de precisão", você deve perguntar: 
"em que recall?"
Você pode ver que a precisão realmente começa a cair acentuadamente em torno de 80% de recuperação. 
Você provavelmente desejará selecionar uma compensação de precisão/recall logo antes dessa queda - por 
exemplo, em torno de 60% de rechamada. Mas é claro que a escolha depende do seu projeto.
Ótimo, você tem um classificador de precisão de 90% (ou próximo o suficiente)! Como você pode ver, é 
bastante fácil criar um classificador com praticamente qualquer precisão desejada: basta definir um limite alto 
o suficiente e pronto. Hum, não tão rápido. Um classificador de alta precisão não é muito útil se sua revocação 
for muito baixa!
Vamos verificar a precisão e a recuperação dessas previsões:
Então, vamos supor que você decida almejar 90% de precisão. Você procura o primeiro gráfico (ampliando 
um pouco) e descobre que precisa usar um limite de cerca de 70.000. Para fazer previsões (no conjunto de 
treinamento por enquanto), em vez de chamar o método predict() do classificador , basta executar este código:
Figura 3-5. Precisão versus recall
y_train_pred_90 = (y_scores > 70000)
>>> precisão_score(y_train_5, y_train_pred_90) 
0,8998702983138781 
>>> recall_score(y_train_5, y_train_pred_90) 
0,63991883416343853
90 | Capítulo 3: Classificação
plot_roc_curve(fpr, tpr) 
plt.show()
def plot_roc_curve(fpr, tpr, label=Nenhum):
fpr, tpr, limiares = roc_curve(y_train_5, y_scores)
plt.plot(fpr, tpr, linewidth=2, label=label) plt.plot([0, 1], 
[0, 1], 'k--') plt.axis([0, 1, 0, 1 ]) 
plt.xlabel(' Taxa de falso 
positivo') plt.ylabel(' Taxa de verdadeiro 
positivo')
de sklearn.metrics import roc_curve
A curva ROC
Medidas de Desempenho | 91
Figura 3-6. curva ROC
A curva característica de operação do receptor (ROC) é outra ferramenta comum usada com 
classificadores binários. É muito semelhante à curva de precisão/recuperação, mas, em vez de 
plotar precisão versus rechamada, a curva ROC plota a taxa de verdadeiros positivos (outro nome 
para rechamada) em relação à taxa de falsos positivos. O FPR é a proporção de instâncias 
negativas que são incorretamente classificadas como positivas. É igual a um menos a taxa 
negativa verdadeira, que é a proporção de instâncias negativas classificadas corretamente como 
negativas. O TNR também é chamado de especificidade. Portanto, a curva ROC plota a 
sensibilidade (recall) versus 1 – especificidade.
Então você pode traçar o FPR contra o TPR usando Matplotlib. Este código produz o gráfico na 
Figura 3-6:
Para plotar a curva ROC, primeiro você precisa calcular o TPR e FPR para vários valores limite, 
usando a função roc_curve() :
Vamos treinar um RandomForestClassifier e comparar sua curva ROC e pontuação ROC AUC com o 
SGDClassifier. Primeiro, você precisa obter pontuações para cada instância no conjunto de treinamento. 
Mas, devido à forma como funciona (consulte o Capítulo 7), a classe de fier RandomForestClassi não possui 
um método decision_function() . Em vez disso, ele possui um método pre dict_proba() . Os classificadores 
do Scikit-Learn geralmente têm um ou outro. O método predict_proba() retorna um array contendo uma linha 
por instância e uma coluna por classe, cada uma contendo a probabilidade de que a instância dada pertença 
à classe dada (por exemplo, 70% de chance de que a imagem represente um 5):
Mas para traçar uma curva ROC, você precisa de pontuações, não de probabilidades. Uma solução simples 
é usar a probabilidade da classe positiva como pontuação:
Uma maneira de comparar classificadores é medir a área sob a curva (AUC). Um classificador perfeito terá 
um ROC AUC igual a 1, enquanto um classificador puramente aleatório terá um ROC AUC igual a 0,5. O 
Scikit-Learn fornece uma função para calcular o ROC AUC:
Mais uma vez, há uma compensação: quanto maior o recall (TPR), mais falsos positivos (FPR) o classificador 
produz. A linha pontilhada representa a curva ROC de um classificador puramente aleatório; um bom 
classificador fica o mais longe possível dessa linha (em direção ao canto superior esquerdo).
Como a curva ROC é tão semelhante à curva de precisão/recall (ou 
PR), você pode se perguntar como decidir qual delas usar. Como regra 
geral, você deve preferir a curva PR sempre que a classe positiva for 
rara ou quando você se preocupa mais com os falsos positivos do que 
com os falsos negativos, caso contrário, a curva ROC. Por exemplo, 
observando a curva ROC anterior (e a pontuação ROC AUC), você 
pode pensar que o classificador é realmente bom. Mas isso ocorre 
principalmente porque há poucos pontos positivos (5s) em comparação 
com os negativos (não-5s). Em contraste, a curvaPR deixa claro que o 
classificador tem espaço para melhorias (a curva pode estar mais 
próxima do canto superior direito).
92 | Capítulo 3: Classificação
de sklearn.ensemble import RandomForestClassifier
forest_clf = RandomForestClassifier(random_state=42) 
y_probas_forest = cross_val_predict(forest_clf, X_train, y_train_5, cv=3, 
method="predict_proba")
y_scores_forest = y_probas_forest[:, 1] # score = proba de classe positiva fpr_forest, 
tpr_forest, thresholds_forest = roc_curve(y_train_5,y_scores_forest)
>>> from sklearn.metrics import roc_auc_score >>> 
roc_auc_score(y_train_5, y_scores) 
0,97061072797174941
Classificação multiclasse
Figura 3-7. Comparando curvas ROC
Enquanto os classificadores binários distinguem entre duas classes, os classificadores multiclasse 
(também chamados de classificadores multinomiais) podem distinguir entre mais de duas classes.
Como você pode ver na Figura 3-7, a curva ROC do RandomForestClassifier parece muito melhor do 
que a do SGDClassifier: ela chega muito mais perto do canto superior esquerdo. Como resultado, sua 
pontuação ROC AUC também é significativamente melhor:
Tente medir as pontuações de precisão e recall: você deve encontrar 98,5% de precisão e 82,8% de 
recall. Não é tão ruim!
Esperamos que agora você saiba como treinar classificadores binários, escolher a métrica apropriada 
para sua tarefa, avaliar seus classificadores usando validação cruzada, selecionar a compensação de 
precisão/recuperação que atenda às suas necessidades e comparar vários modelos usando curvas 
ROC e pontuações ROC AUC . Agora vamos tentar detectar mais do que apenas os 5s.
Agora você está pronto para traçar a curva ROC. É útil plotar a primeira curva ROC também para ver 
como elas se comparam (Figura 3-7):
Classificação multiclasse | 93
>>> roc_auc_score(y_train_5, y_scores_forest) 
0,99312433660038291
plt.plot(fpr, tpr, "b:", label="SGD") 
plot_roc_curve(fpr_forest, tpr_forest, "Floresta aleatória") 
plt.legend(loc="canto inferior direito") 
plt.show()
Essa foi fácil! Este código treina o SGDClassifier no conjunto de treinamento usando as classes-alvo 
originais de 0 a 9 (y_train), em vez das classes-alvo 5-versus-all (y_train_5). Em seguida, faz uma previsão 
(correta neste caso). Nos bastidores, o Scikit-Learn realmente treinou 10 classificadores binários, obteve 
suas pontuações de decisão para a imagem e selecionou a classe com a pontuação mais alta.
Outra estratégia é treinar um classificador binário para cada par de dígitos: um para distinguir 0s e 1s, outro 
para distinguir 0s e 2s, outro para 1s e 2s, e assim por diante.
O Scikit-Learn detecta quando você tenta usar um algoritmo de classificação binária para uma tarefa de 
classificação multiclasse e executa OvA automaticamente (exceto para classificadores SVM para os quais 
usa OvO). Vamos tentar isso com o SGDClassifier:
Por exemplo, uma forma de criar um sistema que possa classificar as imagens de dígitos em 10 classes (de 
0 a 9) é treinar 10 classificadores binários, um para cada dígito (um detector 0, um detector 1, um detector 
2 , e assim por diante). Então, quando quiser classificar uma imagem, você obtém a pontuação de decisão 
de cada classificador para essa imagem e seleciona a classe cujo classificador gera a pontuação mais alta. 
Isso é chamado de estratégia um contra todos (OvA) (também chamada de um contra o resto).
Em vez de retornar apenas uma pontuação por instância, ela agora retorna 10 pontuações, uma por classe:
Alguns algoritmos (como os classificadores Support Vector Machine) escalam mal com o tamanho do 
conjunto de treinamento, portanto, para esses algoritmos, OvO é preferido, pois é mais rápido treinar muitos 
classificadores em pequenos conjuntos de treinamento do que treinar poucos classificadores em grandes 
conjuntos de treinamento. Para a maioria dos algoritmos de classificação binária, no entanto, OvA é o preferido.
Alguns algoritmos (como classificadores Random Forest ou classificadores Naive Bayes) são capazes de 
lidar diretamente com múltiplas classes. Outros (como classificadores Support Vector Machine ou 
classificadores lineares) são classificadores estritamente binários. No entanto, existem várias estratégias 
que você pode usar para executar a classificação multiclasse usando vários classificadores binários.
Para ver se esse é realmente o caso, você pode chamar o método decision_function() .
Isso é chamado de estratégia um contra um (OvO). Se houver N classes, você precisa treinar N × (N – 1) / 
2 classificadores. Para o problema MNIST, isso significa treinar 45 classificadores binários! Quando você 
deseja classificar uma imagem, você deve passar a imagem por todos os 45 classificadores e ver qual 
classe vence mais duelos. A principal vantagem do OvO é que cada classificador só precisa ser treinado na 
parte do conjunto de treinamento para as duas classes que ele deve distinguir.
>>> sgd_clf.fit(X_train, y_train) # y_train, não y_train_5 >>> 
sgd_clf.predict([some_digit]) array([ 5.])
>>> some_digit_scores = sgd_clf.decision_function([some_digit]) >>> 
some_digit_scores
94 | Capítulo 3: Classificação
Classificação multiclasse | 95
,
>>> from sklearn.multiclass import OneVsOneClassifier >>> 
ovo_clf = OneVsOneClassifier(SGDClassifier(random_state=42)) >>> 
ovo_clf.fit(X_train, y_train) >>> 
ovo_clf.predict([some_digit]) array([ 5. ]) 
>>> 
len(ovo_clf.estimators_) 45
0.
5.0
0.
array([[-311402.62954431, -363517.28355739, -446449.5306454
,
,
>>> forest_clf.fit(X_train, y_train) >>> 
forest_clf.predict([some_digit]) array([ 5.])
,
-183226.61023518, -414337.15339485, 161855.74572176, 
-452576.39616343, -471957.14962573, -518542.33997148, 
-536774.63961222]])
,
>>> forest_clf.predict_proba([some_digit]) 
array([[ 0.1, 0. , 0.8, 0.
>>> np.argmax(some_digit_scores) 5 
>>> sgd_clf.classes_ 
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) >>> sgd_clf.classes[5]
0.]])0. , 0,1, 0.
Quando um classificador é treinado, ele armazena a lista de classes de 
destino em seu atributo classes_ , ordenado por valor. Nesse caso, o índice 
de cada classe no array classes_ combina convenientemente com a própria 
classe (por exemplo, a classe no índice 5 é a classe 5), mas em geral você 
não terá tanta sorte.
A pontuação mais alta é de fato a correspondente à classe 5:
Se você deseja forçar o ScikitLearn a usar um contra um ou um contra todos, você pode usar 
as classes OneVsOneClassifier ou OneVsRestClassifier . Simplesmente crie uma instância e 
passe um classificador binário para seu construtor. Por exemplo, este código cria um 
classificador multiclasse usando a estratégia OvO, baseado em um SGDClassifier:
Desta vez, o Scikit-Learn não precisou executar OvA ou OvO porque os classificadores 
Random Forest podem classificar instâncias diretamente em várias classes. Você pode chamar 
predict_proba() para obter a lista de probabilidades que o classificador atribuiu a cada instância 
para cada classe:
Você pode ver que o classificador está bastante confiante sobre sua previsão: o 0,8 no 5º 
índice namatriz significa que o modelo estima uma probabilidade de 80% de que a imagem
Treinar um RandomForestClassifier é igualmente fácil:
Erro de análise
Obtém mais de 84% em todas as dobras de teste. Se você usasse um classificador aleatório, obteria 10% 
de precisão, portanto, essa não é uma pontuação tão ruim, mas você ainda pode fazer muito melhor. Por 
exemplo, simplesmente dimensionar as entradas (conforme discutido no Capítulo 2) aumenta a precisão acima
Claro, se este fosse um projeto real, você seguiria as etapas em sua lista de verificação do projeto de 
aprendizado de máquina (consulte o Apêndice B): explorando as opções de preparação de dados, 
experimentando vários modelos, selecionando os melhores e ajustando seus hiperparâmetros. medidores 
usando GridSearchCV e automatizando o máximo possível, como você fez no capítulo anterior. Aqui, 
assumiremos que você encontrou um modelo promissor e deseja encontrar maneiras de melhorá-lo. Uma 
maneira de fazer isso é analisar os tipos de erros que ele comete.
representa um 5. Ele também pensa que a imagem poderia ser um 0 ou um 3 (10% de chance cada).
90%:
Primeiro, você pode olhar para a matriz de confusão. Você precisa fazer previsões usando a função 
cross_val_predict() e, em seguida, chamar a função confusion_matrix() , exatamente como você fez 
anteriormente:
Agora é claro que você deseja avaliar esses classificadores. Como de costume, você deseja usar a 
validação cruzada. Vamos avaliar a precisão do SGDClassifier usando a função cross_val_score() :
>>> cross_val_score(sgd_clf, X_train, y_train, cv=3, scoring="precisão") array([ 0.84063187, 
0.84899245, 0.86652998])
9, 
25,
>>> X_train_scaled = scaler.fit_transform(X_train.astype(np.float64)) >>> 
cross_val_score(sgd_clf, X_train_scaled, y_train, cv=3, scoring="accuracy") array([ 0.91011798, 
0.90874544, 0.906636 ])
>>> y_train_pred = cross_val_predict(sgd_clf, X_train_scaled, y_train, cv=3) >>> conf_mx = 
confusion_matrix(y_train, y_train_pred) >>> conf_mx array([[5725, 
3, 24, 10, 10, 
39, 4] , [ 2, 6493, 43, 7, 10, 109, 8], [ 51, 60, 166, 13], 41, 5321, 104, 89, [ 47, 50, 141, 
92], 46, 141, 5342 , [ 19, 37, 86, 189], 29, 41, 10, 5366, [ 73, 45, 36, 193, 64, 
4582, 111, 30, 193, 94], [ 29, 34, 44, 2, 42, 85, 5627, 10, 45, 0], [ 25, 6, 5787, 15, 236], 24, 74, 32, 54, 
12, [ 52, 161, 73, 156, 10, 163, 61, 25, 5027, 123], [ 43, 2, 223, 82, 5240]]) 35, 26, 92, 178, 28,
49, 50, 40, 
5, 26, 87, 
1, 231, 40, 
9, 56,
>>> from sklearn.preprocessing import StandardScaler >>> 
scaler = StandardScaler()
96 | Capítulo 3: Classificação
São muitos números. Muitas vezes é mais conveniente olhar para uma representação de imagem da matriz 
de confusão, usando a função matshow() do Matplotlib :
Essa matriz de confusão parece razoavelmente boa, pois a maioria das imagens está na diagonal principal, 
o que significa que foram classificadas corretamente. Os 5s parecem um pouco mais escuros do que os 
outros dígitos, o que pode significar que há menos imagens de 5s no conjunto de dados ou que o 
classificador não funciona tão bem em 5s quanto em outros dígitos. Na verdade, você pode verificar que 
ambos são o caso.
Vamos focar a trama nos erros. Primeiro, você precisa dividir cada valor na matriz de confusão pelo número 
de imagens na classe correspondente, para poder comparar as taxas de erro em vez do número absoluto 
de erros (o que faria com que classes abundantes parecessem injustamente ruins):
Agora vamos preencher a diagonal com zeros para manter apenas os erros, e vamos plotar o resultado:
plt.matshow(conf_mx, cmap=plt.cm.gray) 
plt.show()
np.fill_diagonal(norm_conf_mx, 0) 
plt.matshow(norm_conf_mx, cmap=plt.cm.gray) 
plt.show()
row_sums = conf_mx.sum(axis=1, keepdims=True) 
norm_conf_mx = conf_mx / row_sums
Análise de Erros | 97
Por exemplo, vamos traçar exemplos de 3s e 5s:
Agora você pode ver claramente os tipos de erros cometidos pelo classificador. Lembre-se de que as 
linhas representam classes reais, enquanto as colunas representam classes previstas. As colunas das 
classes 8 e 9 são bastante brilhantes, o que indica que muitas imagens são classificadas erroneamente 
como 8 ou 9. Da mesma forma, as linhas para as classes 8 e 9 também são bastante brilhantes, 
informando que 8s e 9s são frequentemente confundidos com outros dígitos. Por outro lado, algumas 
linhas são bastante escuras, como a linha 1: isso significa que a maioria dos 1s são classificados 
corretamente (alguns são confundidos com 8s, mas isso é tudo). Observe que os erros não são 
perfeitamente simétricos; por exemplo, há mais 5s classificados erroneamente como 8s do que o inverso.
A análise de erros individuais também pode ser uma boa maneira de obter informações sobre o que seu 
classificador está fazendo e por que está falhando, mas é mais difícil e demorado.
A análise da matriz de confusão geralmente pode fornecer informações sobre maneiras de melhorar seu 
classificador. Olhando para este gráfico, parece que seus esforços devem ser gastos em melhorar a 
classificação de 8s e 9s, bem como corrigir a confusão específica de 3/5. Por exemplo, você pode tentar 
coletar mais dados de treinamento para esses dígitos. Ou você pode projetar novos recursos que 
ajudariam o classificador - por exemplo, escrever um algoritmo para contar o número de loops fechados 
(por exemplo, 8 tem dois, 6 tem um, 5 não tem nenhum). Ou você pode pré-processar as imagens (por 
exemplo, usando Scikit-Image, Pillow ou OpenCV) para destacar mais alguns padrões, como loops 
fechados.
plt.figure(figsize=(8,8)) 
plt.subplot(221); plot_digits(X_aa[:25], images_per_row=5) 
plt.subplot(222); plot_digits(X_ab[:25], images_per_row=5)
cl_a, cl_b = 3, 5
X_ab = X_train[(y_train == cl_a) & (y_train_pred == cl_b)]
X_bb = X_train[(y_train == cl_b) & (y_train_pred == cl_b)]
X_aa = X_train[(y_train == cl_a) & (y_train_pred == cl_a)]
X_ba = X_train[(y_train == cl_b) & (y_train_pred == cl_a)]
98 | Capítulo 3: Classificação
Os dois blocos 5×5 à esquerda mostram dígitos classificados como 3s, e os dois blocos 5×5 à 
direita mostram imagens classificadas como 5s. Alguns dos dígitos que o classificador errou (ou 
seja, nos blocos inferior esquerdo e superior direito) são tão mal escritos que até mesmo um 
humano teria dificuldade em classificá-los (por exemplo, o 5 na 8ª linha e na 1ª coluna realmente 
parece como um 3). No entanto, a maioria das imagens mal classificadas parecem erros óbvios 
para nós, e é difícil entender por que o classificador cometeu os erros que cometeu.3 O motivo é 
que usamos um SGDClassifier simples, que é um modelo linear. Tudo o que ele faz é atribuir um 
peso por classe a cada pixel e, quando vê uma nova imagem, apenas soma as intensidades de 
pixel ponderadas para obter uma pontuação para cada classe. Portanto, como 3s e 5s diferem 
apenas por alguns pixels, esse modelo os confundirá facilmente.
A principal diferença entre 3s e 5s é a posição da pequenalinha que une a linha superior ao arco 
inferior. Se você desenhar um 3 com a junção ligeiramente deslocada para a esquerda, o 
classificador poderá classificá-lo como um 5 e vice-versa. Em outras palavras, este classificador 
é bastante sensível ao deslocamento e rotação da imagem. Portanto, uma maneira de reduzir a 
confusão 3/5 seria pré-processar as imagens para garantir que elas estejam bem centralizadas e 
não muito giradas. Isso provavelmente ajudará a reduzir outros erros também.
pré-processamento complexo antes que qualquer informação chegue à nossa consciência, então o fato de parecer simples 
não significa que seja.
plt.subplot(223); plot_digits(X_ba[:25], images_per_row=5) 
plt.subplot(224); plot_digits(X_bb[:25], images_per_row=5) plt.show()
Análise de Erros | 99
3 Mas lembre-se de que nosso cérebro é um fantástico sistema de reconhecimento de padrões, e nosso sistema visual faz muitas
Ainda não entraremos no reconhecimento facial, mas vejamos um exemplo mais simples, apenas 
para fins de ilustração:
E dá certo! O dígito 5 de fato não é grande (Falso) e ímpar (Verdadeiro).
Esse código cria uma matriz y_multilabel contendo dois rótulos de destino para cada imagem de 
dígito: o primeiro indica se o dígito é grande ou não (7, 8 ou 9) e o segundo indica se é ímpar ou 
não. As próximas linhas criam uma instância KNeighborsClassifier (que suporta classificação 
multirótulo, mas nem todos os classificadores suportam) e nós a treinamos usando a matriz de 
destinos múltiplos. Agora você pode fazer uma previsão e observar que ela gera dois rótulos:
Isso pressupõe que todos os rótulos são igualmente importantes, o que pode não ser o caso. Em 
particular, se você tiver muito mais fotos de Alice do que de Bob ou Charlie, você pode querer dar 
mais peso à pontuação do classificador nas fotos de Alice. Uma opção simples é
Até agora, cada instância sempre foi atribuída a apenas uma classe. Em alguns casos, você pode 
querer que seu classificador gere várias classes para cada instância. Por exemplo, considere um 
classificador de reconhecimento facial: o que ele deve fazer se reconhecer várias pessoas na 
mesma foto? Claro que deve anexar uma etiqueta por pessoa que reconhece. Digamos que o 
classificador tenha sido treinado para reconhecer três rostos, Alice, Bob e Charlie; então, quando é 
mostrada uma foto de Alice e Charlie, ele deve exibir [1, 0, 1] (que significa “Alice sim, Bob não, 
Charlie sim”). Esse sistema de classificação que gera vários rótulos binários é chamado de sistema 
de classificação multirótulo.
Há muitas maneiras de avaliar um classificador multirrótulo, e selecionar a métrica certa realmente 
depende do seu projeto. Por exemplo, uma abordagem é medir a pontuação F1 para cada rótulo 
individual (ou qualquer outra métrica de classificador binário discutida anteriormente) e, em seguida, 
simplesmente calcular a pontuação média. Este código calcula a pontuação média da F1 em todos 
os rótulos:
Classificação multirrótulo
y_train_large = (y_train >= 7) 
y_train_odd = (y_train % 2 == 1) 
y_multilabel = np.c_[y_train_large, y_train_odd]
>>> knn_clf.predict([some_digit]) 
array([[False, True]], dtype=bool)
>>> y_train_knn_pred = cross_val_predict(knn_clf, X_train, y_train, cv=3) >>> 
f1_score(y_train, y_train_knn_pred, average="macro") 
0,96845540180280221
knn_clf = KNeighborsClassifier() 
knn_clf.fit(X_train, y_multilabel)
de sklearn.neighbors import KNeighborsClassifier
100 | Capítulo 3: Classificação
noise = rnd.randint(0, 100, (len(X_train), 784)) noise = 
rnd.randint(0, 100, (len(X_test), 784))
X_train_mod = X_train + ruído 
X_test_mod = X_test + ruído 
y_train_mod = X_train 
y_test_mod = X_test
4 O Scikit-Learn oferece algumas outras opções de média e métricas de classificador multirrótulo; consulte a documentação para
A linha entre classificação e regressão às vezes é tênue, como neste 
exemplo. Indiscutivelmente, prever a intensidade do pixel é mais 
semelhante à regressão do que à classificação. Além disso, os 
sistemas multisaída não se limitam a tarefas de classificação; você 
pode até ter um sistema que emita vários rótulos por instância, 
incluindo rótulos de classe e rótulos de valor.
O último tipo de tarefa de classificação que discutiremos aqui é chamado de classificação multiclasse 
multisaída (ou simplesmente classificação multisaída). É simplesmente uma generalização da classificação 
multirrótulo onde cada rótulo pode ser multiclasse (ou seja, pode ter mais de dois valores possíveis).
para dar a cada rótulo um peso igual ao seu suporte (ou seja, o número de instâncias com esse rótulo de 
destino). Para fazer isso, basta definir average="weighted" no código anterior.4
Vamos dar uma olhada em uma imagem do conjunto de teste (sim, estamos bisbilhotando os dados de 
teste, então você deve estar carrancudo agora):
Para ilustrar isso, vamos construir um sistema que remove o ruído das imagens. Ele tomará como entrada 
uma imagem de dígitos ruidosos e (espero) produzirá uma imagem de dígitos limpos, representada como 
uma matriz de intensidades de pixel, assim como as imagens MNIST. Observe que a saída do classificador 
é multirótulo (um rótulo por pixel) e cada rótulo pode ter vários valores (a intensidade do pixel varia de 0 a 
255). É, portanto, um exemplo de um sistema de classificação de múltiplas saídas.
Vamos começar criando os conjuntos de treinamento e teste pegando as imagens MNIST e adicionando 
ruído às suas intensidades de pixel usando a função randint() do NumPy . As imagens de destino serão as 
imagens originais:
Classificação de múltiplas saídas | 101
mais detalhes.
Classificação de múltiplas saídas
knn_clf.fit(X_train_mod, y_train_mod) 
clean_digit = knn_clf.predict([X_test_mod[some_index]]) 
plot_digit(clean_digit)
5 Você pode usar a função shift() do módulo scipy.ndimage.interpolation . Por exemplo, 
shift(image, [2, 1], cval=0) desloca a imagem 2 pixels para baixo e 1 pixel para a direita.
102 | Capítulo 3: Classificação
1. Tente construir um classificador para o conjunto de dados MNIST que atinja mais de 97% de precisão no 
conjunto de teste. Dica: o KNeighborsClassifier funciona muito bem para esta tarefa; você só precisa 
encontrar bons valores de hiperparâmetros (tente uma pesquisa de grade nos pesos e hiperparâmetros 
n_vizinhos ).
À esquerda está a imagem de entrada com ruído e à direita está a imagem de destino limpa. Agora vamos 
treinar o classificador e deixar limpo esta imagem:
Parece perto o suficiente do alvo! Isso conclui nosso tour de classificação. Esperamos que agora você saiba 
como selecionar boas métricas para tarefas de classificação, escolher a compensação de precisão/
recuperação apropriada, comparar classificadores e, de maneira mais geral, construir bons sistemas de 
classificação para uma variedade de tarefas.
Você deve observar que seu modelo tem um desempenho ainda melhor agora! Esta técnica de
2. Escreva uma função que pode deslocar uma imagem MNIST em qualquer direção(esquerda, direita, 
para cima ou para baixo) em um pixel.5 Em seguida, para cada imagem no conjunto de treinamento, 
crie quatro cópias deslocadas (uma por direção) e adicioná-los ao conjunto de treinamento. Finalmente, 
treine seu melhor modelo neste conjunto de treinamento expandido e meça sua precisão no conjunto de teste.
exercícios
4. Construa um classificador de spam (um exercício mais desafiador):
Seu pipeline de preparação deve transformar um email em um vetor (esparso) indicando a presença ou 
ausência de cada palavra possível. Por exemplo, se todos os e-mails contiverem apenas quatro palavras, 
“Olá”, “como”, “está”, “você”, então o e-mail “Olá, olá, olá você” seria convertido em um vetor [1, 0, 0 , 1] 
(significando [“Hello” está presente, “how” está ausente, “are” está ausente, “you” está presente]), ou [3, 0, 0, 
2] se você preferir contar o número de ocorrências de cada palavra.
3. Aborde o conjunto de dados do Titanic. Um ótimo lugar para começar é no Kaggle.
• Descompacte os conjuntos de dados e familiarize-se com o formato dos dados. • Divida 
os conjuntos de dados em um conjunto de treinamento e um conjunto 
de teste. • Escreva um pipeline de preparação de dados para converter cada e-mail em um vetor de recursos.
As soluções para esses exercícios estão disponíveis nos notebooks Jupyter on-line em https:// github.com/ageron/
handson-ml.
aumentar artificialmente o conjunto de treinamento é chamado de aumento de dados ou expansão do conjunto 
de treinamento.
conjuntos de dados.
com alta revocação e alta precisão.
• Faça o download de exemplos de spam e ham do arquivo público do Apache SpamAssassin
• Você pode querer adicionar hiperparâmetros ao seu pipeline de preparação para controlar se deve ou não 
remover cabeçalhos de e-mail, converter cada e-mail em letras minúsculas, remover pontuação, substituir 
todos os URLs por “URL”, substituir todos os números por “NÚMERO” ou até mesmo executar stemming (ou 
seja, aparar terminações de palavras; existem bibliotecas Python disponíveis para fazer isso). • Em seguida, 
experimente vários classificadores e veja se você 
pode criar um ótimo classificador de spam,
Exercícios | 103
https://www.kaggle.com/c/titanic
https://github.com/ageron/handson-ml
https://github.com/ageron/handson-ml
https://spamassassin.apache.org/publiccorpus/
https://spamassassin.apache.org/publiccorpus/
Modelos de Treinamento
CAPÍTULO 4
• Usando uma equação direta de “forma fechada” que calcula diretamente os parâmetros do modelo 
que melhor ajustam o modelo ao conjunto de treinamento (ou seja, os parâmetros do modelo que 
minimizam a função de custo sobre o conjunto de treinamento).
• Usando uma abordagem de otimização iterativa, chamada Gradient Descent (GD), que ajusta 
gradualmente os parâmetros do modelo para minimizar a função de custo sobre o conjunto de 
treinamento, eventualmente convergindo para o mesmo conjunto de parâmetros do primeiro método. 
Veremos algumas variantes de Gradient Descent que usaremos repetidamente quando estudarmos 
redes neurais na Parte II: Batch GD, Mini-batch GD e Stochastic GD.
Neste capítulo, começaremos examinando o modelo de Regressão Linear, um dos modelos mais simples 
que existe. Discutiremos duas maneiras muito diferentes de treiná-lo:
Até agora, tratamos os modelos de aprendizado de máquina e seus algoritmos de treinamento 
principalmente como caixas pretas. Se você passou por alguns dos exercícios dos capítulos anteriores, 
pode ter ficado surpreso com o quanto pode fazer sem saber nada sobre o que está por trás do capô: 
você otimizou um sistema de regressão, melhorou um classificador de imagem digital e você até construiu 
um classificador de spam do zero - tudo isso sem saber como eles realmente funcionam. De fato, em 
muitas situações você não precisa realmente conhecer os detalhes da implementação.
No entanto, ter um bom entendimento de como as coisas funcionam pode ajudá-lo a encontrar 
rapidamente o modelo apropriado, o algoritmo de treinamento correto a ser usado e um bom conjunto de 
hiperparâmetros para sua tarefa. Entender o que está por trás também ajudará você a depurar problemas 
e realizar análises de erros com mais eficiência. Por fim, a maioria dos tópicos discutidos neste capítulo 
será essencial para entender, construir e treinar redes neurais (discutidas na Parte II deste livro).
105
Haverá algumas equações matemáticas neste capítulo, usando 
noções básicas de álgebra linear e cálculo. Para entender essas 
equações, você precisará saber o que são vetores e matrizes, 
como transpô-los, o que é o produto escalar, o que é inversa de 
matriz e o que são derivadas parciais. Se você não estiver 
familiarizado com esses conceitos, consulte os tutoriais introdutórios 
de álgebra linear e cálculo disponíveis como notebooks Jupyter no 
material suplementar on-line. Para aqueles que são verdadeiramente 
alérgicos à matemática, você ainda deve ler este capítulo e 
simplesmente pular as equações; esperamos que o texto seja 
suficiente para ajudá-lo a entender a maioria dos conceitos.
y = ÿ0 + ÿ1 x1 + ÿ2 x2 + ÿ + ÿn xn
Equação 4-1. Previsão do modelo de regressão linear
Em seguida, veremos a regressão polinomial, um modelo mais complexo que pode ajustar conjuntos de dados 
não lineares. Uma vez que este modelo tem mais parâmetros do que a Regressão Linear, é mais propenso a 
sobreajustar os dados de treinamento, então veremos como detectar se este é ou não o caso, usando curvas 
de aprendizado, e depois veremos várias regularizações técnicas que podem reduzir o risco de overfitting do 
conjunto de treinamento.
No Capítulo 1, examinamos um modelo de regressão simples de satisfação com a vida: satisfação_vida = ÿ0 
+ ÿ1 × GDP_per_capita.
• ÿ é o valor previsto. • n é o 
número de feições.
Por fim, veremos mais dois modelos comumente usados para tarefas de classificação: Regressão Logística e 
Regressão Softmax.
Este modelo é apenas uma função linear do recurso de entrada GDP_per_capita. ÿ0 e ÿ1 são os parâmetros 
do modelo.
De modo mais geral, um modelo linear faz uma previsão simplesmente calculando uma soma ponderada dos 
recursos de entrada, mais uma constante chamada de termo de viés (também chamado de termo de 
interceptação), conforme mostrado na Equação 4-1 .
• xi é o i-ésimo valor do recurso. 
• ÿj é o j-ésimo parâmetro do modelo (incluindo o termo de viés ÿ0 e os pesos dos recursos
ÿ1 , ÿ2 , ÿ, ÿn ).
Regressão linear
106 | Capítulo 4: Modelos de Treinamento
y = hÿ = ÿ
1
MSE
m i = 1
Tÿ _, hÿ = eu ÿ y·
·
pesos ÿ1 a ÿn . • ÿ 
T é a transposta de ÿ (um vetor linha em vez de um vetor coluna). • x é o vetor 
de recursos da instância, contendo x0 a xn , com x0 sempre igual a 1.
Equação 4-3. Função de custo MSE para um modelo de regressão linear
A única diferença é que escrevemos hÿ em vez de apenas h para deixar claro que o modelo é 
parametrizado pelo vetor ÿ. Para simplificar as notações, escreveremosapenas MSE(ÿ) em vez de 
MSE(X, hÿ ).
• ÿ T · x é o produto escalar de ÿ T e x.
Isso pode ser escrito de forma muito mais concisa usando uma forma vetorizada, como mostrado na Equação
• hÿ é a função de hipótese, usando os parâmetros do modelo ÿ.
4-2.
A maioria dessas notações foi apresentada no Capítulo 2 (consulte “Notações” na página 38).
• ÿ é o vetor de parâmetro do modelo, contendo o termo de tendência ÿ0 e o recurso
Ok, esse é o modelo de Regressão Linear, então agora como o treinamos? Bem, lembre-se de que 
treinar um modelo significa definir seus parâmetros para que o modelo se ajuste melhor ao conjunto 
de treinamento. Para isso, primeiro precisamos de uma medida de quão bem (ou mal) o modelo se 
ajusta aos dados de treinamento. No Capítulo 2 , vimos que a medida de desempenho mais comum 
de um modelo de regressão é a Raiz do Erro Quadrático Médio (RMSE) (Equação 2-1). Portanto, para 
treinar um modelo de Regressão Linear, você precisa encontrar o valor de ÿ que minimiza o RMSE. 
Na prática, é mais simples minimizar o Erro Quadrático Médio (MSE) do que o RMSE, e leva ao 
mesmo resultado (porque o valor que minimiza uma função também minimiza sua raiz quadrada).1 O 
MSE de uma hipótese de Regressão Linear hÿ 
em um conjunto de treinamento X é calculado usando a Equação 4-3.
Equação 4-2. Previsão do modelo de regressão linear (forma vetorizada)
eu
m
T
medida utilizada para avaliar o modelo final. Isso geralmente ocorre porque essa função é mais fácil de calcular, porque 
possui propriedades de diferenciação úteis que faltam à medida de desempenho ou porque queremos restringir o modelo 
durante o treinamento, como veremos quando discutirmos a regularização.
2
1 Muitas vezes, um algoritmo de aprendizado tentará otimizar uma função diferente do desempenho
Regressão Linear | 107
ÿ
Equação 4-4. equação normal
Vamos gerar alguns dados de aparência linear para testar esta equação (Figura 4-1):
Figura 4-1. Conjunto de dados linear gerado aleatoriamente
A equação normal Para 
encontrar o valor de ÿ que minimiza a função de custo, existe uma solução de forma fechada — 
em outras palavras, uma equação matemática que fornece o resultado diretamente. Isso é 
chamado de Equação Normal (Equação 4-4).2
• ÿ é o valor de ÿ que minimiza a função custo.
• y é o vetor de valores alvo contendo y (1) a y .
·
livro.
T
2 A demonstração de que isso retorna o valor de ÿ que minimiza a função de custo está fora do escopo deste
Tÿ1
(m)
108 | Capítulo 4: Modelos de treinamento
importar numpy como np
X = 2 * np.random.rand(100, 1) y = 4 + 3 
* X + np.random.randn(100, 1)
ÿ = ··
Agora vamos calcular ÿ usando a equação normal. Usaremos a função inv() do módulo de álgebra 
linear do NumPy (np.linalg) para calcular o inverso de uma matriz e o método dot() para a 
multiplicação de matrizes:
A função real que usamos para gerar os dados é y = 4 + 3x0 + ruído gaussiano.
Agora você pode fazer previsões usando ÿ:
Vamos traçar as previsões deste modelo (Figura 4-2):
Figura 4-2. Previsões do modelo de regressão linear
Vamos ver o que a equação encontrou:
Teríamos esperado ÿ0 = 4 e ÿ1 = 3 em vez de ÿ0 = 3,865 e ÿ1 = 3,139. Perto o suficiente, mas o 
ruído tornou impossível recuperar os parâmetros exatos da função original.
X_b = np.c_[np.ones((100, 1)), X] # adicione x0 = 1 a cada instância theta_best 
= np.linalg.inv(X_b.T.dot(X_b)).dot(X_b.T ).ponto(y)
>>> X_new_b = np.c_[np.ones((2, 1)), X_new] # adiciona x0 = 1 a cada instância >>> 
y_predict = X_new_b.dot(theta_best) >>> 
y_predict 
array([[ 4.21509616 ], 
[ 9.75532293]])
>>> X_new = np.array([[0], [2]])
plt.plot(X_new, y_predict, "r-") plt.plot(X, 
y, "b.") plt.axis([0, 2, 0, 
15]) plt.show()
>>> theta_best 
array([[ 4.21509616], 
[ 2.77011339]])
Regressão Linear | 109
110 | Capítulo 4: Modelos de Treinamento
3
No lado positivo, essa equação é linear em relação ao número de instâncias no conjunto de 
treinamento (é O(m)), portanto, ela lida com grandes conjuntos de treinamento com eficiência, 
desde que caibam na memória.
Agora veremos maneiras muito diferentes de treinar um modelo de Regressão Linear, mais 
adequado para casos em que há um grande número de recursos ou muitas instâncias de 
treinamento para caber na memória.
Além disso, depois de treinar seu modelo de regressão linear (usando a equação normal ou 
qualquer outro algoritmo), as previsões são muito rápidas: a complexidade computacional é linear 
em relação ao número de instâncias nas quais você deseja fazer previsões e ao número de 
características. Em outras palavras, fazer previsões sobre o dobro de instâncias (ou o dobro de 
recursos) levará aproximadamente o dobro do tempo.
O código equivalente usando o Scikit-Learn é assim:3
) (dependendo da implementação). Em
Complexidade computacional A 
equação normal calcula o inverso de XT · X, que é uma matriz n × n (onde n é o número de 
recursos). A complexidade computacional de inverter tal matriz é tipicamente de cerca de O(n 2,4) 
a O(n outras palavras, se você dobrar o número 
de recursos, multiplicará o tempo de computação por aproximadamente 22,4 = 5,3 a 23 = 8.
>>> from sklearn.linear_model import LinearRegression >>> 
lin_reg = LinearRegression() >>> 
lin_reg.fit(X, y) >>> 
lin_reg.intercept_, lin_reg.coef_ 
(array([ 4.21509616]), array([[ 2.77011339]])) >>> 
lin_reg.predict(X_new) 
array([[ 4.21509616], 
[ 9.75532293]])
3 Observe que o Scikit-Learn separa o termo de viés (intercept_) dos pesos de recursos (coef_).
A equação normal fica muito lenta quando o número de feições 
aumenta (por exemplo, 100.000).
Gradiente descendente
Gradient Descent é um algoritmo de otimização muito genérico capaz de encontrar soluções ótimas para 
uma ampla gama de problemas. A ideia geral do Gradient Descent é ajustar os parâmetros iterativamente 
para minimizar uma função de custo.
Concretamente, você começa preenchendo ÿ com valores aleatórios (isso é chamado de inicialização 
aleatória), e depois melhora gradualmente, dando um pequeno passo de cada vez, cada passo tentando 
diminuir a função de custo (por exemplo, o MSE), até que o algoritmo convirja para um mínimo (consulte 
a Figura 4-3).
Um parâmetro importante no Gradient Descent é o tamanho dos passos, determinado pelo hiperparâmetro 
da taxa de aprendizado. Se a taxa de aprendizado for muito pequena, o algoritmo terá que passar por 
muitas iterações para convergir, o que levará muito tempo (consulte a Figura 4-4).
Suponha que você esteja perdido nas montanhas em meio a uma densa névoa; você só pode sentir a 
inclinação do solo abaixo de seus pés. Uma boa estratégia para chegar ao fundo do vale rapidamente é 
descer a ladeira na direção do declive mais acentuado. É exatamente isso que o Gradient Descent faz: 
mede o gradiente local da função de erro em relação ao vetor de parâmetro ÿ e vai na direção do 
gradiente descendente. Uma vez que o gradiente é zero,você atingiu um mínimo!
Figura 4-3. Gradiente descendente
Descida Gradiente | 111
Finalmente, nem todas as funções de custo parecem boas tigelas regulares. Pode haver buracos, cumes, planaltos e 
todo tipo de terrenos irregulares, tornando muito difícil a convergência ao mínimo. A Figura 4-6 mostra os dois principais 
desafios com o Gradient Descent: se a inicialização aleatória iniciar o algoritmo à esquerda, ele convergirá para um 
mínimo local, que não é tão bom quanto o mínimo global. Se começar à direita, levará muito tempo para cruzar o platô 
e, se você parar muito cedo, nunca atingirá o mínimo global.
Figura 4-4. Taxa de aprendizagem muito pequena
Figura 4-5. Taxa de aprendizado muito grande
Por outro lado, se a taxa de aprendizado for muito alta, você pode pular o vale e acabar do outro lado, possivelmente 
ainda mais alto do que antes. Isso pode fazer com que o algoritmo diverja, com valores cada vez maiores, deixando de 
encontrar uma boa solução (consulte a Figura 4-5).
112 | Capítulo 4: Modelos de Treinamento
Descida Gradiente | 113
Figura 4-6. Armadilhas de descida de gradiente
Na verdade, a função de custo tem a forma de uma tigela, mas pode ser uma tigela alongada se as feições tiverem 
escalas muito diferentes. A Figura 4-7 mostra o Gradient Descent em um conjunto de treinamento onde os recursos 
1 e 2 têm a mesma escala (à esquerda) e em um conjunto de treinamento onde o recurso 1 tem valores muito 
menores do que o recurso 2 (à direita).5
Figura 4-7. Gradient Descent com e sem recurso de dimensionamento
Felizmente, a função de custo MSE para um modelo de regressão linear é uma função convexa, o que significa 
que, se você escolher quaisquer dois pontos na curva, o segmento de linha que os une nunca cruzará a curva. Isso 
implica que não há mínimos locais, apenas um mínimo global. É também uma função contínua com uma inclinação 
que nunca muda abruptamente.4 Esses dois fatos têm uma grande consequência: a descida do gradiente é 
garantida para se aproximar arbitrariamente do mínimo global (se você esperar o suficiente e se a taxa de 
aprendizado não for muito alta). .
4 Tecnicamente falando, sua derivada é contínua de Lipschitz.
alongado ao longo do eixo ÿ1 .
5 Como o recurso 1 é menor, é necessária uma mudança maior em ÿ1 para afetar a função de custo, e é por isso que a tigela é
Ao usar Gradient Descent, você deve garantir que todos os recursos tenham 
uma escala semelhante (por exemplo, usando a classe StandardScaler do 
Scikit-Learn ), ou então levará muito mais tempo para convergir.
ÿ 2
MSE ÿ =
ÿÿj
ÿ ·
T
m i = 1
eu ÿ y
eu
m
eu
xj
Para implementar Gradient Descent, você precisa calcular o gradiente da função de custo em 
relação a cada parâmetro do modelo ÿj .
Como você pode ver, à esquerda o algoritmo Gradient Descent vai direto em direção ao 
mínimo, atingindo-o rapidamente, enquanto à direita ele primeiro vai em uma direção quase 
ortogonal à direção do mínimo global e termina com uma longa marcha por um vale quase 
plano. Eventualmente atingirá o mínimo, mas levará muito tempo.
Este diagrama também ilustra o fato de que treinar um modelo significa buscar uma combinação 
de parâmetros do modelo que minimize uma função de custo (sobre o conjunto de treinamento). 
É uma busca no espaço de parâmetros do modelo: quanto mais parâmetros um modelo tem, 
mais dimensões esse espaço tem, e mais difícil é a busca: procurar uma agulha em um 
palheiro de 300 dimensões é muito mais complicado do que em três dimensões . Felizmente, 
como a função de custo é convexa no caso da Regressão Linear, a agulha está simplesmente 
no fundo da tigela.
.
Em outras palavras, você precisa calcular 
quanto a função de custo mudará se você alterar ÿj apenas um pouquinho. Isso é chamado 
de derivada parcial. É como perguntar “qual é a inclinação da montanha sob meus pés se eu 
olhar para o leste?” e então fazendo a mesma pergunta olhando para o norte (e assim por 
diante para todas as outras dimensões, se você puder imaginar um universo com mais de três 
dimensões). A equação 4-5 calcula a derivada parcial da função de custo em relação ao 
parâmetro ÿ ter ÿj , 
notado MSE ÿ ÿÿ j
Equação 4-5. Derivadas parciais da função de custo
Em vez de calcular esses gradientes individualmente, você pode usar a Equação 4-6 para 
calculá-los todos de uma vez. O vetor gradiente, denominado ÿÿMSE(ÿ), contém todas as 
derivadas parciais da função de custo (uma para cada parâmetro do modelo).
114 | Capítulo 4: Modelos de Treinamento
ÿ
Descida de Gradiente em Lote
MSE ÿ 
ÿÿn
ÿÿ1ÿÿ MSE ÿ =
ÿ
ÿ
MSE ÿ
· ÿ ÿ
próximo passo ÿ
ÿÿ0
=
= ÿ ÿ ÿÿÿ MSE ÿ
ÿ
·
MSE ÿ
m
2
ÿ
theta = np.random.randn(2,1) # inicialização aleatória
para iteração no intervalo (n_iterações): 
gradientes = 2/m * X_b.T.dot(X_b.dot(theta) - y) theta = 
theta - eta * gradientes
eta = 0,1 # taxa de aprendizado 
n_iterations = 1000 m 
= 100
Descida Gradiente | 115
Equação 4-6. Vetor gradiente da função de custo
Equação 4-7. Etapa de descida do gradiente
Vejamos uma implementação rápida desse algoritmo:
Uma vez que você tenha o vetor gradiente, que aponta para cima, basta ir na direção oposta para descer. 
Isso significa subtrair ÿÿMSE(ÿ) de ÿ. É aqui que a taxa de aprendizado ÿ entra em ação:6 multiplique o 
vetor gradiente por ÿ para determinar o tamanho da etapa de descida (Equação 4-7).
T
6 Eta (ÿ) é a sétima letra do alfabeto grego.
Observe que esta fórmula envolve cálculos sobre todo o conjunto de 
treinamento X, a cada passo do Gradient Descent! É por isso que o 
algoritmo é chamado Batch Gradient Descent: ele usa todo o lote de dados 
de treinamento em cada etapa. Como resultado, é terrivelmente lento em 
conjuntos de treinamento muito grandes (mas veremos algoritmos de 
descida de gradiente muito mais rápidos em breve). No entanto, Gradient 
Descent escala bem com o número de feições; treinar um modelo de 
Regressão Linear quando há centenas de milhares de feições é muito mais 
rápido usando Descida de Gradiente do que usando a Equação Normal.
ÿ
À esquerda, a taxa de aprendizado é muito baixa: o algoritmo eventualmente chegará à solução, mas levará 
muito tempo. No meio, a taxa de aprendizado parece muito boa: em apenas algumas iterações, ela já 
convergiu para a solução. À direita, a taxa de aprendizado é muito alta: o algoritmo diverge, pulando por todos 
os lados e se afastando cada vez mais da solução a cada passo.
Isso não foi muito difícil! Vejamos o teta resultante:
Ei, isso é exatamente o que a Equação Normal encontrou! Gradient Descent funcionou perfeitamente. Mas e 
se você tivesse usado um eta de taxa de aprendizado diferente? A Figura 4-8 mostra os primeiros 10 passos 
do Gradient Descent usando três taxas de aprendizado diferentes (a linha tracejada representa o ponto inicial).
Você pode se perguntar como definir o número de iterações. Se formuito baixo, você ainda estará longe da 
solução ótima quando o algoritmo parar, mas se for muito alto, você perderá tempo enquanto os parâmetros 
do modelo não mudam mais. Uma solução simples é definir um número muito grande de iterações, mas 
interromper o algoritmo quando o vetor de gradiente se torna minúsculo – isto é, quando sua norma se torna 
menor do que um número minúsculo (chamado de tolerância) – porque isso acontece quando a descida do 
gradiente atingiu (quase) o mínimo.
Figura 4-8. Gradient Descent com várias taxas de aprendizagem
Para encontrar uma boa taxa de aprendizado, você pode usar a pesquisa em grade (consulte o Capítulo 2). 
No entanto, você pode querer limitar o número de iterações para que a pesquisa de grade possa eliminar 
modelos que demoram muito para convergir.
>>> theta 
array([[ 4.21509616], 
[ 2.77011339]])
116 | Capítulo 4: Modelos de treinamento
.
por 10 (para ter uma solução mais precisa), então o algoritmo terá
Em outras palavras, se você dividir
ÿ
O principal problema com Batch Gradient Descent é o fato de que ele usa todo o conjunto de 
treinamento para calcular os gradientes em cada etapa, o que o torna muito lento quando o conjunto 
de treinamento é grande. No extremo oposto, Stochastic Gradient Descent apenas escolhe uma 
instância aleatória no conjunto de treinamento a cada passo e calcula os gradientes com base 
apenas nessa única instância. Obviamente, isso torna o algoritmo muito mais rápido, pois possui 
muito poucos dados para manipular a cada iteração. Também possibilita o treinamento em grandes 
conjuntos de treinamento, pois apenas uma instância precisa estar na memória a cada iteração (o 
SGD pode ser implementado como um algoritmo fora do núcleo.7 )
Por outro lado, devido à sua natureza estocástica (ou seja, aleatória), esse algoritmo é muito menos 
regular do que o Batch Gradient Descent: em vez de diminuir suavemente até atingir o mínimo, a 
função de custo aumentará e diminuirá, diminuindo apenas em média - idade. Com o tempo, ele 
acabará ficando muito próximo do mínimo, mas, assim que chegar lá, continuará oscilando, nunca 
se acomodando (consulte a Figura 4-9). Então, uma vez que o algoritmo para, os valores finais dos 
parâmetros são bons, mas não ótimos.
Figura 4-9. Descida de Gradiente Estocástico
Taxa de convergência 
Quando a função de custo é convexa e sua inclinação não muda abruptamente (como é o caso 
da função de custo MSE), pode-se mostrar que Batch Gradient Descent com uma taxa de 
aprendizado fixa tem uma taxa de convergência de 
O a tolerância 
para executar cerca de 10 vezes mais iterações.
1
iterações
7 Algoritmos fora do núcleo são discutidos no Capítulo 1.
Descida Gradiente | 117
Descida de Gradiente Estocástico
Portanto, a aleatoriedade é boa para escapar de ótimos locais, mas ruim porque significa que o algoritmo nunca 
pode se estabelecer no mínimo. Uma solução para esse dilema é reduzir gradualmente a taxa de aprendizado. 
As etapas começam grandes (o que ajuda a progredir rapidamente e a escapar de mínimos locais), depois 
ficam cada vez menores, permitindo que o algoritmo se estabeleça no mínimo global. Este processo é chamado 
de recozimento simulado, porque se assemelha ao processo de recozimento na metalurgia, onde o metal 
fundido é resfriado lentamente. A função que determina a taxa de aprendizado em cada iteração é chamada de 
cronograma de aprendizado. Se a taxa de aprendizado for reduzida muito rapidamente, você pode ficar preso 
em um mínimo local ou até mesmo congelar no meio do caminho para o mínimo. Se a taxa de aprendizado for 
reduzida muito lentamente, você pode saltar em torno do mínimo por um longo tempo e acabar com uma 
solução abaixo do ideal se interromper o treinamento muito cedo.
Enquanto o código Batch Gradient Descent iterou 1.000 vezes em todo o conjunto de treinamento, esse código 
percorre o conjunto de treinamento apenas 50 vezes e chega a uma solução razoavelmente boa:
A Figura 4-10 mostra os primeiros 10 passos do treinamento (observe como os passos são irregulares).
Este código implementa a Descida de Gradiente Estocástico usando um cronograma de aprendizado simples:
Quando a função de custo é muito irregular (como na Figura 4-6), isso pode realmente ajudar o algoritmo a sair 
dos mínimos locais, de modo que a Descida Gradiente Estocástica tem uma chance melhor de encontrar o 
mínimo global do que a Descida Gradiente Batch.
Por convenção, iteramos por rodadas de iterações; cada rodada é chamada de época.
def learning_schedule(t): 
return t0 / (t + t1)
para epoch in range(n_epochs): 
for i in range(m): 
random_index = np.random.randint(m) xi = 
X_b[random_index:random_index+1] yi = 
y[random_index:random_index+1] 
gradientes = 2 * xi.T.dot(xi.dot(theta) - yi) eta = 
learning_schedule(epoch * m + i) theta = theta 
- eta * gradientes
n_epochs = 50 
t0, t1 = 5, 50 # hiperparâmetros do cronograma de aprendizado
theta = np.random.randn(2,1) # inicialização aleatória
>>> theta 
array([[ 4.21076011], 
[ 2.74856079]])
118 | Capítulo 4: Modelos de treinamento
Descida Gradiente | 119
Mais uma vez, você encontra uma solução muito próxima daquela retornada pela Equação Normal:
Figura 4-10. Descida do gradiente estocástico primeiros 10 passos
Para executar a regressão linear usando SGD com Scikit-Learn, você pode usar a classe SGDRe gressor , 
cujo padrão é otimizar a função de custo de erro quadrado. O código a seguir executa 50 epochs, começando 
com uma taxa de aprendizado de 0,1 (eta0=0,1), usando o cronograma de aprendizado padrão (diferente do 
anterior) e não usa nenhuma regularização (penalty=None; mais detalhes em isso brevemente):
O último algoritmo de descida de gradiente que veremos é chamado de descida de gradiente em minilote. É 
bastante simples de entender uma vez que você conhece o Batch and Stochastic Gradient Descent: a cada 
passo, em vez de calcular os gradientes com base no conjunto de treinamento completo (como no Batch GD) 
ou com base em apenas uma instância (como no Stochastic GD), Mini
Observe que, como as instâncias são selecionadas aleatoriamente, algumas instâncias podem ser 
selecionadas várias vezes por época, enquanto outras podem não ser selecionadas. Se você quiser ter 
certeza de que o algoritmo passa por todas as instâncias em cada época, outra abordagem é embaralhar o 
conjunto de treinamento, depois percorrê-lo instância por instância, embaralhar novamente e assim por diante. 
No entanto, isso geralmente converge mais lentamente.
from sklearn.linear_model import SGDRegressor 
sgd_reg = SGDRegressor(n_iter=50, penalty=None, eta0=0.1) 
sgd_reg.fit(X, y.ravel())
>>> sgd_reg.intercept_, sgd_reg.coef_ 
(array([ 4.18380366]), array([ 2.74205299]))
Descida de Gradiente em Minilote
2
0
8 Enquanto a Equação Normal só pode executar Regressão Linear, os algoritmos de Descida de Gradiente podem ser 
usados para treinar muitos outros modelos, como veremos.Regressão linear
Vamos comparar os algoritmos que discutimos até agora para Regressão Linear8 (lembre-se de que m é o número 
de instâncias de treinamento en é o número de recursos); consulte a Tabela 4-1.
No entanto, não se esqueça de que o Batch GD leva muito tempo para executar cada etapa, e o Stochastic GD e o 
Mini-batch GD também atingiriam o mínimo se você usasse um bom cronograma de aprendizado.
lote GD calcula os gradientes em pequenos conjuntos aleatórios de instâncias chamados mini lotes. A principal 
vantagem do Mini-batch GD sobre o Stochastic GD é que você pode obter um aumento de desempenho com a 
otimização de hardware das operações de matriz, especialmente ao usar GPUs.
Figura 4-11. Caminhos de descida de gradiente no espaço de parâmetros
O progresso do algoritmo no espaço de parâmetros é menos errático do que com SGD, especialmente com mini-
lotes razoavelmente grandes. Como resultado, o Mini-batch GD acabará andando um pouco mais perto do mínimo 
do que o SGD. Mas, por outro lado, pode ser mais difícil escapar de mínimos locais (no caso de problemas que 
sofrem de mínimos locais, ao contrário da Regressão Linear como vimos anteriormente). A Figura 4-11 mostra os 
caminhos percorridos pelos três algoritmos de descida de gradiente no espaço de parâmetros durante o treinamento. 
Todos eles terminam perto do mínimo, mas o caminho do Batch GD realmente para no mínimo, enquanto o Stochastic 
GD e o Mini-batch GD continuam andando.
Tabela 4-1. Comparação de algoritmos para Regressão Linear
Não
Sim
120 | Capítulo 4: Modelos de treinamento
NãoEquação Normal Rápida
Lento Rápido
Lento
Algoritmo
Lote GD
Large m Suporte out-of-core Large n Hyperparams Dimensionamento necessário Scikit-Learn
Não n / D
m = 100
SGDRegressor
X = 6 * np.random.rand(m, 1) - 3 y = 0,5 * 
X**2 + X + 2 + np.random.randn(m, 1)
Vejamos um exemplo. Primeiro, vamos gerar alguns dados não lineares, com base em uma equação 
quadrática simples9 (mais algum ruído; consulte a Figura 4-12):
Figura 4-12. Conjunto de dados não linear e com ruído gerado
E se seus dados forem realmente mais complexos do que uma simples linha reta? Surpreendentemente, 
você pode realmente usar um modelo linear para ajustar dados não lineares. Uma maneira simples de 
fazer isso é adicionar poderes de cada recurso como novos recursos e treinar um modelo linear nesse 
conjunto estendido de recursos. Essa técnica é chamada de Regressão Polinomial.
n / Dÿ2
Algoritmo
Sim
Large m Suporte out-of-core Large n Hyperparams Dimensionamento necessário Scikit-Learn
Sim
GD estocástico RápidoRápido
Rápido
ÿ2 Sim
Sim
Regressão polinomial | 121
Mini-lote GD rápido
Quase não há diferença após o treinamento: todos esses algoritmos 
acabam com modelos muito semelhantes e fazem previsões exatamente 
da mesma maneira.
9 Uma equação quadrática tem a forma y = ax2 + bx + c.
regressão polinomial
122 | Capítulo 4: Modelos de treinamento
2
2 + 1
. 78 quando na verdade o original + 0 . 93x1 + 1
X_poly agora contém o recurso original de X mais o quadrado desse recurso. Agora você pode ajustar um 
modelo LinearRegression a esses dados de treinamento estendidos (Figura 4-13):
Nada mal: o modelo estima y = 0 . 56x1 função foi y 
= 0 . 5x1
Claramente, uma linha reta nunca ajustará esses dados corretamente. Então, vamos usar a classe Poly 
nomialFeatures do Scikit-Learn para transformar nossos dados de treinamento, adicionando o quadrado 
(polinômio de 2º grau) de cada recurso no conjunto de treinamento como novos recursos (neste caso, há 
apenas um recurso):
Observe que, quando há vários recursos, a regressão polinomial é capaz de encontrar relacionamentos 
entre os recursos (algo que um modelo de regressão linear simples não pode fazer). Isso é possível pelo 
fato de PolynomialFeatures também adicionar todas as combinações de recursos até o grau especificado. 
Por exemplo, se houvesse
. 0x1 + 2 . 0 + ruído gaussiano.
Figura 4-13. Previsões do modelo de regressão polinomial
>>> from sklearn.preprocessing import PolynomialFeatures >>> 
poly_features = PolynomialFeatures(degree=2, include_bias=False)
>>> 
matriz X[0] ([-0.75275929])
>>> X_poly = poly_features.fit_transform(X)
>>> X_poly[0] 
array([-0.75275929, 0.56664654])
>>> lin_reg = LinearRegression() >>> 
lin_reg.fit(X_poly, y) >>> 
lin_reg.intercept_, lin_reg.coef_ 
(array([ 1.78134581]), array([[ 0.93366893, 0.56456263]]))
,
n + d ! 
características, onde n! é o 
d! n!
Curvas de aprendizado
3 a
É claro que esse modelo de regressão polinomial de alto grau está sobreajustando severamente 
os dados de treinamento, enquanto o modelo linear está subajustando-o. O modelo que 
generalizará melhor neste caso é o modelo quadrático. Faz sentido, já que os dados foram 
gerados usando um modelo quadrático, mas em geral você não saberá qual função gerou os 
dados, então como você pode decidir o quão complexo seu modelo deve ser? Como você pode 
saber se seu modelo está superajustando ou subajustando os dados?
,,
Figura 4-14. Regressão polinomial de alto grau
dois recursos a e b, PolynomialFeatures com grau=3 não apenas adicionaria os recursos a e b 
3 mas também as combinações ab, a 2b e ab2 .
Observe como o modelo polinomial de 300 graus se move para chegar o mais próximo possível 
das instâncias de treinamento.
Se você executar regressão polinomial de alto grau, provavelmente ajustará os dados de 
treinamento muito melhor do que com regressão linear simples. Por exemplo, a Figura 4-14 
aplica um modelo polinomial de 300 graus aos dados de treinamento anteriores e compara o 
resultado com um modelo linear puro e um modelo quadrático (polinomial de 2º grau).
b 2,2
Curvas de Aprendizagem | 123
PolynomialFeatures(degree=d) transforma uma matriz contendo 
n recursos em uma matriz 
contendo fatorial de n, igual a 1 × 2 × 3 × ÿ × n. Cuidado com a 
explosão combinatória do número de recursos!
Vejamos as curvas de aprendizado do modelo de regressão linear simples (uma linha reta;
No Capítulo 2 , você usou validação cruzada para obter uma estimativa do desempenho de generalização de 
um modelo. Se um modelo tiver um bom desempenho nos dados de treinamento, mas generalizar mal de 
acordo com as métricas de validação cruzada, seu modelo está superajustado. Se ele funcionar mal em 
ambos, então é underfitting. Essa é uma maneira de saber quando um modelo é muito simples ou muito 
complexo.
Para gerar os gráficos, basta treinar o modelo várias vezes em subconjuntos de tamanhos diferentes do 
conjunto de treinamento. O código a seguir define uma função que plota as curvas de aprendizado de um 
modelo com base em alguns dados de treinamento:
Figura 4-15):
Figura 4-15. Curvas de aprendizado
Outra maneira é olhar para as curvas de aprendizado: são gráficos do desempenho do modelo no conjunto de 
treinamento e no conjunto de validação em função do tamanho do conjunto de treinamento.
X_train, X_val, y_train, y_val = train_test_split(X,y, test_size=0.2) train_errors, 
val_errors = [], [] para m no intervalo(1, 
len(X_train)):
model.fit(X_train[:m], y_train[:m]) 
y_train_predict = model.predict(X_train[:m]) 
y_val_predict = model.predict(X_val) 
train_errors.append(mean_squared_error(y_train_predict, y_train[:m]) ) 
val_errors.append(mean_squared_error(y_val_predict, y_val)) 
plt.plot(np.sqrt(train_errors), "r-+", linewidth=2, label="train") 
plt.plot(np.sqrt(val_errors), "b-", largura da linha=3, etiqueta="val")
def plot_learning_curves(model, X, y):
lin_reg = LinearRegression() 
plot_learning_curves(lin_reg, X, y)
de sklearn.metrics importar mean_squared_error de 
sklearn.model_selection importar train_test_split
124 | Capítulo 4: Modelos de treinamento
Se o seu modelo estiver subajustando os dados de treinamento, adicionar 
mais exemplos de treinamento não ajudará. Você precisa usar um modelo 
mais complexo ou criar recursos melhores.
Curvas de Aprendizagem | 125
• Existe um espaço entre as curvas. Isso significa que o modelo tem um desempenho significativamente 
melhor nos dados de treinamento do que nos dados de validação, que é a marca registrada de um 
modelo de overfitting. No entanto, se você usasse um conjunto de treinamento muito maior, as 
duas curvas continuariam a se aproximar.
Isso merece um pouco de explicação. Primeiro, vejamos o desempenho nos dados de treinamento: 
quando há apenas uma ou duas instâncias no conjunto de treinamento, o modelo pode ajustá-las 
perfeitamente, por isso a curva começa em zero. Mas, à medida que novas instâncias são adicionadas 
ao conjunto de treinamento, torna-se impossível para o modelo ajustar os dados de treinamento 
perfeitamente, tanto porque os dados são ruidosos quanto porque não são lineares. Portanto, o erro nos 
dados de treinamento aumenta até atingir um platô, ponto no qual adicionar novas instâncias ao conjunto 
de treinamento não torna o erro médio muito melhor ou pior. Agora vamos ver o desempenho do modelo 
nos dados de validação. Quando o modelo é treinado em poucas instâncias de treinamento, ele é incapaz 
de generalizar adequadamente, razão pela qual o erro de validação é inicialmente muito grande. Então, 
à medida que o modelo recebe mais exemplos de treinamento, ele aprende e, assim, o erro de validação 
diminui lentamente. No entanto, mais uma vez, uma linha reta não pode fazer um bom trabalho de 
modelagem dos dados, então o erro acaba em um platô, muito próximo da outra curva.
Essas curvas de aprendizado se parecem um pouco com as anteriores, mas há duas diferenças muito 
importantes:
modelo.
Agora vamos ver as curvas de aprendizado de um modelo polinomial de 10º grau nos mesmos dados 
(Figura 4-16):
Essas curvas de aprendizado são típicas de um modelo de underfitting. Ambas as curvas atingiram um 
platô; eles estão próximos e razoavelmente altos.
• O erro nos dados de treinamento é muito menor do que com a Regressão Linear
))
de sklearn.pipeline import Pipeline
plot_learning_curves(polynomial_regression, X, y)
polynomial_regression = 
Pipeline(( ("poly_features", PolynomialFeatures(degree=10, include_bias=False)), 
("sgd_reg", LinearRegression()),
Uma maneira de melhorar um modelo de overfitting é alimentá-lo com mais dados 
de treinamento até que o erro de validação atinja o erro de treinamento.
10 Essa noção de viés não deve ser confundida com o termo de viés dos modelos lineares.
Figura 4-16. Curvas de aprendizagem para o modelo polinomial
A troca de viés/variância
126 | Capítulo 4: Modelos de treinamento
Um resultado teórico importante da estatística e do aprendizado de máquina é o fato de que o erro de 
generalização de um modelo pode ser expresso como a soma de três erros muito diferentes
Variância 
Essa parte se deve à sensibilidade excessiva do modelo a pequenas variações nos dados de 
treinamento. Um modelo com muitos graus de liberdade (como um modelo polinomial de alto 
grau) provavelmente terá alta variância e, portanto, sobreajustará os dados de treinamento.
erros:
Bias 
Esta parte do erro de generalização é devido a suposições erradas, como assumir que os dados 
são lineares quando na verdade são quadráticos. Um modelo de alto viés tem maior probabilidade 
de não ajustar os dados de treinamento.10
Modelos Lineares Regularizados
Modelos Lineares Regularizados | 127
2n
Aumentar a complexidade de um modelo normalmente aumentará sua variância e reduzirá seu viés.
Por outro lado, reduzir a complexidade de um modelo aumenta seu viés e reduz sua variância.
Erro irredutível 
Esta parte se deve ao ruído dos próprios dados. A única maneira de reduzir essa parte do erro 
é limpar os dados (por exemplo, consertar as fontes de dados, como sensores quebrados, ou 
detectar e remover outliers).
É por isso que é chamado de tradeoff.
O hiperparâmetro ÿ controla o quanto você deseja regularizar o modelo. Se ÿ = 0, então a 
regressão Ridge é apenas uma regressão linear. Se ÿ for muito grande, então todos os pesos terminam
Para um modelo linear, a regularização é normalmente obtida restringindo os pesos do modelo. 
Veremos agora Regressão Ridge, Regressão Lasso e Elastic Net, que implementam três maneiras 
diferentes de restringir os pesos.
é adicionado à função de custo.
Ridge Regression 
Ridge Regression (também chamado de regularização de Tikhonov) é uma versão regularizada 
da Regressão Linear: um termo de regularização igual a ÿÿi = 
1 ÿi Isso força o algoritmo de aprendizado não apenas a ajustar os dados, mas também a manter 
os pesos do modelo tão pequenos que possível. Observe que o termo de regularização só deve 
ser adicionado à função de custo durante o treinamento. Depois que o modelo for treinado, você 
deseja avaliar o desempenho do modelo usando a medida de desempenho não regularizada.
Como vimos nos Capítulos 1 e 2, uma boa maneira de reduzir o overfitting é regularizar o modelo 
(isto é, restringi-lo): quanto menos graus de liberdade ele tiver, mais difícil será para ele 
superajustar os dados. Por exemplo, uma maneira simples de regularizar um modelo polinomial é 
reduzir o número de graus polinomiais.
É bastante comum que a função de custo usada durante o treinamento 
seja diferente da medida de desempenho usada para teste. Além da 
regularização, outra razão pela qual eles podem ser diferentes é que 
uma boa função de custo de treinamento deve ter derivadas amigáveis 
à otimização, enquanto a medida de desempenho usada para teste 
deve ser o mais próximo possível do objetivo final. Um bom exemplo 
disso é um classificador treinado usando uma função de custo como a 
perda de log (discutida em um momento), mas avaliada usando precisão/
revocação.
2 ,
É importante dimensionar os dados (por exemplo, usando um StandardScaler) 
antes de executar a regressão Ridge, pois ela é sensível à escala dos recursos 
de entrada. Isso é verdade para a maioria dos modelos regularizados.
ÿ
A Figura 4-17 mostra vários modelos de Ridge treinados em alguns dados lineares usando diferentesvalores de ÿ. À esquerda, modelos simples de Ridge são usados, levando a previsões lineares. À 
direita, os dados são primeiro expandidos usando PolynomialFeatures(degree=10), depois são 
dimensionados usando um StandardScaler e, finalmente, os modelos Ridge são aplicados aos recursos 
resultantes: esta é a regressão polinomial com regularização Ridge. Observe como o aumento de ÿ 
leva a previsões mais achatadas (ou seja, menos extremas, mais razoáveis); isso reduz a variância do 
modelo, mas aumenta seu viés.
Equação 4-8. Função de custo de Regressão Ridge
Assim como na regressão linear, podemos realizar a regressão Ridge calculando uma equação de 
forma fechada ou executando a descida de gradiente. Os prós e os contras são os mesmos. A Equação 
4-9 mostra a solução de forma fechada (onde A é a matriz de identidade n × n13, exceto com um 0 na 
célula superior esquerda, correspondendo ao termo de viés).
muito perto de zero e o resultado é uma linha plana passando pela média dos dados. A Equação 4-8 
apresenta a função de custo Ridge Regression.11
Observe que o termo de viés ÿ0 não é regularizado (a soma começa em i = 1, não 0). Se definirmos w 
como o vetor de pesos de recursos (ÿ1 a ÿn ), então o termo de regularização é simplesmente igual a 
½(ÿ w ÿ2 ) onde ÿ · ÿ2 representa a norma ÿ2 do vetor de peso.12 Para descida de gradiente, apenas 
adicione ÿw ao vetor de gradiente MSE (Equação 4-6).
12 As normas são discutidas no Capítulo 2.
13 Uma matriz quadrada cheia de 0s, exceto 1s na diagonal principal (do canto superior esquerdo ao canto inferior direito).
J ÿ = MSE ÿ + ÿ 2 i = 1
n
11 É comum usar a notação J(ÿ) para funções de custo que não possuem nome abreviado; frequentemente usaremos essa 
notação no restante deste livro. O contexto deixará claro qual função de custo está sendo discutida.
ÿi
2
128 | Capítulo 4: Modelos de treinamento
1
T
14 Como alternativa, você pode usar a classe Ridge com o solucionador "sag" . Stochastic Average GD é uma variante do SGD.
T 
· + ÿ
ÿ1
Para mais detalhes, consulte a apresentação “Minimizar somas finitas com o algoritmo estocástico de gradiente médio ” por Mark 
Schmidt e outros. da Universidade da Colúmbia Britânica.
·
Equação 4-9. Solução de forma fechada de Regressão Ridge
Aqui está como executar Ridge Regression com Scikit-Learn usando uma solução de forma fechada 
(uma variante da Equação 4-9 usando uma técnica de fatoração de matriz por André-Louis
O hiperparâmetro de penalidade define o tipo de termo de regularização a ser usado. Especificar "l2" 
indica que você deseja que o SGD adicione um termo de regularização à função de custo igual à 
metade do quadrado da norma ÿ2 do vetor de peso: isso é simplesmente Regressão de Ridge.
Figura 4-17. Regressão Ridge
Cholesky):
E usando descida de gradiente estocástico: 14
·ÿ =
Modelos Lineares Regularizados | 129
>>> from sklearn.linear_model import Ridge >>> 
ridge_reg = Ridge(alpha=1, solver="cholesky") >>> 
ridge_reg.fit(X, y) >>> 
ridge_reg.predict([[1.5]]) 
array([[1.55071465]])
>>> sgd_reg = SGDRegressor(penalty="l2") >>> 
sgd_reg.fit(X, y.ravel()) >>> 
sgd_reg.predict([[1.5]]) 
array([[ 1.13500145]])
http://goo.gl/vxVyA2
http://goo.gl/vxVyA2
Equação 4-10. Função de custo de regressão de laço
A Figura 4-18 mostra a mesma coisa que a Figura 4-17 , mas substitui os modelos Ridge pelos modelos 
Lasso e usa valores ÿ menores.
Uma característica importante da Lasso Regression é que ela tende a eliminar completamente os pesos 
dos recursos menos importantes (ou seja, defini-los como zero). Por exemplo, a linha tracejada no 
gráfico à direita na Figura 4-18 (com ÿ = 10-7) parece quadrática, quase linear: todos os pesos para os 
recursos polinomiais de alto grau são iguais a zero. Em outras palavras, Lasso Regression executa 
automaticamente a seleção de recursos e gera um modelo esparso (ou seja, com poucos pesos de 
recursos diferentes de zero).
Lasso Regression 
Least Absolute Shrinkage and Selection Operator Regression (simplesmente chamada de Lasso 
Regression) é outra versão regularizada da Regressão Linear: assim como a Ridge Regression, ela 
adiciona um termo de regularização à função de custo, mas usa a norma ÿ1 do vetor de peso em vez 
de metade do quadrado da norma ÿ2 (consulte a Equação 4-10).
Você pode entender por que esse é o caso observando a Figura 4-19: no gráfico superior esquerdo, os 
contornos de fundo (elipses) representam uma função de custo MSE não regularizada (ÿ = 0) e os 
círculos brancos mostre o caminho Batch Gradient Descent com essa função de custo. Os contornos 
do primeiro plano (diamantes) representam a penalidade ÿ1 e os triângulos mostram o caminho BGD 
apenas para essa penalidade (ÿ ÿ ÿ). Observe como o caminho primeiro
Figura 4-18. Regressão de laço
130 | Capítulo 4: Modelos de treinamento
J ÿ = MSE ÿ + ÿ ÿ ÿi
n
eu = 1
Modelos Lineares Regularizados | 131
15 Você pode pensar em um vetor de subgradiente em um ponto não diferenciável como um vetor intermediário entre os vetores 
de gradiente em torno desse ponto.
Figura 4-19. Regularização Lasso versus Ridge
A Equação 4-11 mostra uma equação de vetor de subgradiente que você pode usar para Descida de 
Gradiente com a função de custo Lasso.
atinge ÿ1 = 0, então desce uma sarjeta até atingir ÿ2 = 0. No gráfico superior direito, os contornos 
representam a mesma função de custo mais uma penalidade de ÿ1 com ÿ = 0,5. O mínimo global está no 
eixo ÿ2 = 0. BGD primeiro atinge ÿ2 = 0, então rola pela sarjeta até atingir o mínimo global. Os dois gráficos 
inferiores mostram a mesma coisa, mas usam uma penalidade de ÿ2 . O mínimo regularizado está mais 
próximo de ÿ = 0 do que o mínimo não regularizado, mas os pesos não são totalmente eliminados.
A função de custo do laço não é diferenciável em ÿi = 0 (para i = 1, 2, ÿ, n), mas a descida do gradiente 
ainda funciona bem se você usar um vetor de subgradiente g 15 quando qualquer ÿi = 0.
Na função de custo Lasso, o caminho BGD tende a saltar pela sarjeta 
em direção ao final. Isso ocorre porque a inclinação muda 
abruptamente em ÿ2 = 0. Você precisa reduzir gradualmente a taxa 
de aprendizado para realmente convergir para o mínimo global.
J ÿ = MSE ÿ + rÿ ÿ ÿ ÿ
1 ÿ r
ÿ
ÿi +
sinal ÿn
2
sinal ÿ1 
sinal ÿ2 
g ÿ, J = ÿÿ MSE ÿ + ÿ
ÿ1 se ÿi < 0 
0 se ÿi = 0 onde sinal ÿi = +1 
se ÿi > 0
>>> from sklearn.linear_model import ElasticNet >>> 
elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5) >>> 
elastic_net.fit(X, y) >>> 
elastic_net.predict([[1.5]]) 
array( [1.54333232])
>>> from sklearn.linear_model import Lasso >>> 
lasso_reg = Lasso(alpha=0.1) >>> 
lasso_reg.fit(X, y) >>> 
lasso_reg.predict([[1.5]]) 
array([ 1.53788174])
Elastic Net é um meio termo entre Ridge Regression e Lasso Regression. O termo de regularização é 
uma mistura simples dos termos de regularização de Ridge e Lasso, e você pode controlar a proporção 
demistura r. Quando r = 0, Elastic Net é equivalente à Ridge Regression, e quando r = 1, é equivalente 
à Lasso Regression (consulte a Equação 4-12).
Aqui está um pequeno exemplo do Scikit-Learn usando a classe Lasso . Observe que você pode usar 
um SGDRegressor(penalty="l1").
Então, quando você deve usar Regressão Linear, Ridge, Lasso ou Elastic Net? Quase sempre é preferível 
ter pelo menos um pouco de regularização, então geralmente você deve evitar a regressão linear simples. 
Ridge é um bom padrão, mas se você suspeitar que apenas alguns recursos são realmente úteis, você 
deve preferir Lasso ou Elastic Net, pois eles tendem a reduzir os pesos dos recursos inúteis a zero, 
conforme discutimos. Em geral, o Elastic Net é preferível ao Lasso, pois o Lasso pode se comportar de 
forma irregular quando o número de recursos é maior que o número de instâncias de treinamento ou 
quando vários recursos estão fortemente correlacionados.
Equação 4-12. Função de custo líquido elástico
Equação 4-11. Vetor de subgradiente de regressão de laço
Aqui está um pequeno exemplo usando o ElasticNet do Scikit-Learn (l1_ratio corresponde à proporção 
de mistura r):
n
eu = 1
n
ÿi
eu = 1
2
132 | Capítulo 4: Modelos de treinamento
Rede Elástica
Isso indica que o modelo começou a sobreajustar os dados de treinamento. Com a parada antecipada, 
você simplesmente para de treinar assim que o erro de validação atingir o mínimo. É uma técnica de 
regularização tão simples e eficiente que Geoffrey Hinton a chamou de “belo almoço grátis”.
Aqui está uma implementação básica de parada antecipada:
Figura 4-20. Regularização de parada antecipada
Parada antecipada 
Uma maneira muito diferente de regularizar algoritmos de aprendizado iterativos, como o Gradient Descent, 
é interromper o treinamento assim que o erro de validação atingir um mínimo. Isso é chamado de parada 
antecipada. A Figura 4-20 mostra um modelo complexo (neste caso, um modelo de regressão polinomial 
de alto grau) sendo treinado usando descida de gradiente em lote. À medida que as épocas passam, o 
algoritmo aprende e seu erro de previsão (RMSE) no conjunto de treinamento diminui naturalmente, assim 
como seu erro de previsão no conjunto de validação. No entanto, depois de um tempo, o erro de validação 
para de diminuir e, na verdade, começa a aumentar.
Modelos Lineares Regularizados | 133
Com Stochastic e Mini-batch Gradient Descent, as curvas não são 
tão suaves e pode ser difícil saber se você atingiu o mínimo ou 
não. Uma solução é parar apenas depois que o erro de validação 
estiver acima do mínimo por algum tempo (quando você estiver 
confiante de que o modelo não terá melhor desempenho) e, em 
seguida, reverter os parâmetros do modelo até o ponto em que o 
erro de validação foi mínimo .
do clone de importação do sklearn.base
Equação 4-13. Probabilidade estimada do modelo de regressão logística (forma vetorizada)
Conforme discutimos no Capítulo 1, alguns algoritmos de regressão também podem ser usados 
para classificação (e vice-versa). A regressão logística (também chamada de regressão Logit) é 
comumente usada para estimar a probabilidade de uma instância pertencer a uma classe específica 
(por exemplo, qual é a probabilidade de que este e-mail seja spam?). Se a probabilidade estimada 
for maior que 50%, então o modelo prevê que a instância pertence a essa classe (chamada de 
classe positiva, rotulada como “1”), ou então prevê que não (ou seja, pertence à classe negativa , 
rotulado como “0”). Isso o torna um classificador binário.
Observe que com warm_start=True, quando o método fit() é chamado, ele apenas continua 
treinando de onde parou, em vez de reiniciar do zero.
A logística—também chamada de logit, notada ÿ(·)—é uma função sigmoide (isto é, em forma 
de S) que produz um número entre 0 e 1. É definida conforme mostrado na Equação 4-14 e 
na Figura 4-21 .
Estimando probabilidades 
Então, como isso funciona? Assim como um modelo de Regressão Linear, um modelo de Regressão 
Logística calcula uma soma ponderada dos recursos de entrada (mais um termo de viés), mas em 
vez de gerar o resultado diretamente como o modelo de Regressão Linear faz, ele gera a logística 
desse resultado (consulte a Equação 4-13).
p = hÿ = ÿÿ T
sgd_reg = SGDRegressor(n_iter=1, warm_start=Verdadeiro, penalidade=Nenhum,
Minimum_val_error = float("inf") 
best_epoch = Nenhum 
best_model = Nenhum 
para epoch in range(1000):
sgd_reg.fit(X_train_poly_scaled, y_train) # continua de onde parou y_val_predict = 
sgd_reg.predict(X_val_poly_scaled) val_error = 
mean_squared_error(y_val_predict, y_val) if val_error < 
Minimum_val_error: Minimum_val_error = 
val_error best_epoch = epoch best_reg
learning_rate="constante", eta0=0.0005)
·
134 | Capítulo 4: Modelos de treinamento
Regressão Logística
Equação 4-16. Função de custo de uma única instância de treinamento
Função de treinamento e custo Bom, 
agora você sabe como um modelo de regressão logística estima probabilidades e faz previsões. Mas como é 
treinado? O objetivo do treinamento é definir o vetor de parâmetros ÿ para que o modelo estime altas 
probabilidades para instâncias positivas (y = 1) e baixas probabilidades para instâncias negativas (y = 0). Essa 
ideia é capturada pela função de custo mostrada na Equação 4-16 para uma única instância de treinamento x.
Equação 4-15. Previsão do modelo de regressão logística
Uma vez que o modelo de Regressão Logística estimou a probabilidade p = hÿ (x) de que uma instância x 
pertence à classe positiva, ele pode fazer sua previsão ÿ facilmente (consulte a Equação 4-15).
Figura 4-21. função logística
Equação 4-14. função logística
Observe que ÿ(t) < 0,5 quando t < 0 e ÿ(t) ÿ 0,5 quando t ÿ 0, portanto, um modelo de regressão logística 
prevê 1 se ÿ T · x for positivo e 0 se for negativo.
Essa função de custo faz sentido porque – log(t) cresce muito quando t se aproxima de 0, então o custo será 
grande se o modelo estimar uma probabilidade próxima de 0 para um positivo
1
ÿ log p se y = 1, ÿ log 1 ÿ 
p se y = 0 .
cÿ =
ÿ t =
y =
0 se p < 0 . 5, 
1 se p ÿ 0 . 5 .
1 + exp ÿ t
Regressão Logística | 135
eu sou
eueu
m i = 1
eu ÿ y
xj
m
eu
m i = 1
eu
m
T 
ÿ ÿ
eu
Limites de Decisão
136 | Capítulo 4: Modelos de treinamento
A má notícia é que não há nenhuma equação de forma fechada conhecida para calcular o valor de ÿ que 
minimiza essa função de custo (não há equivalente da Equação Normal).
Equação 4-17. Função de custo de regressão logística (perda de log)
Mas a boa notícia é que essa função de custo é convexa, então o Gradient Descent (ou qualquer outro 
algoritmo de otimização) certamente encontrará o mínimo global (se a taxa de aprendizado não for muito 
grande e você esperar o suficiente). As derivadas parciais da função de custo em relação ao j-ésimo 
parâmetro do modelo ÿj são dadas pela Equação 4-18.
A função de custo sobre todo oconjunto de treinamento é simplesmente o custo médio sobre todas as 
instâncias de treinamento. Ela pode ser escrita em uma única expressão (como você pode verificar 
facilmente), chamada log loss, mostrada na Equação 4-17.
Vamos usar o conjunto de dados da íris para ilustrar a regressão logística. Este é um conjunto de dados 
famoso que contém o comprimento e a largura das sépalas e pétalas de 150 flores de íris de três espécies 
diferentes: Iris-Setosa, Iris-Versicolor e Iris-Virginica (consulte a Figura 4-22 ).
instância, e também será muito grande se o modelo estimar uma probabilidade próxima de 1 para uma 
instância negativa. Por outro lado, – log(t) está próximo de 0 quando t está próximo de 1, então o custo será 
próximo de 0 se a probabilidade estimada for próxima de 0 para uma instância negativa ou próxima de 1 
para uma instância positiva, que é precisamente o que queremos.
Essa equação se parece muito com a Equação 4-5: para cada instância, ela calcula o erro de previsão e o 
multiplica pelo jésimo valor do recurso e, em seguida, calcula a média de todas as instâncias de treinamento. 
Uma vez que você tenha o vetor de gradiente contendo todas as derivadas parciais, você pode usá-lo no 
algoritmo Batch Gradient Descent. É isso: agora você sabe como treinar um modelo de Regressão Logística. 
Para GD estocástico, é claro, você usaria apenas uma instância de cada vez e, para GD de minilote, usaria 
um minilote por vez.
Equação 4-18. Derivadas parciais da função de custo logístico
ÿ ·
Jÿ = ÿ + 1 ÿ y
Jÿ = 
ÿÿj
log 1 ÿ p
1
log p
1
ÿ
ÿ
16 Fotos reproduzidas das páginas correspondentes da Wikipedia. Foto de Iris-Virginica por Frank Mayfield 
(Creative Commons BY-SA 2.0), Foto Iris-Versicolor por D. Gordon E. Robertson (Creative Commons BY-SA 
3.0), e a foto Iris-Setosa é de domínio público.
Vamos tentar construir um classificador para detectar o tipo Iris-Virginica baseado apenas no recurso de largura 
da pétala. Primeiro vamos carregar os dados:
Vejamos as probabilidades estimadas do modelo para flores com larguras de pétalas variando de 0 a 3 cm 
(Figura 4-23):
Figura 4-22. Flores de três espécies de plantas de íris16
Agora vamos treinar um modelo de Regressão Logística:
>>> from sklearn import datasets >>> 
iris = datasets.load_iris() >>> 
list(iris.keys()) ['data', 
'target_names', 'feature_names', 'target', 'DESCR']
de sklearn.linear_model import LogisticRegression
>>> X = iris["data"][:, 3:] # largura da pétala >>> y = 
(iris["target"] == 2).astype(np.int) # 1 if Iris-Virginica, senão 0
X_new = np.linspace(0, 3, 1000).reshape(-1, 1) y_proba 
= log_reg.predict_proba(X_new) plt.plot(X_new, 
y_proba[:, 1], "g-", label="Iris -Virginica") plt.plot(X_new, y_proba[:, 0], 
"b--", label="Not Iris-Virginica") # + mais código Matplotlib para deixar a imagem 
bonita
log_reg = LogisticRegression() 
log_reg.fit(X, y)
Regressão Logística | 137
https://creativecommons.org/licenses/by-sa/2.0/
https://creativecommons.org/licenses/by-sa/2.0/
https://creativecommons.org/licenses/by-sa/3.0/
A largura das pétalas das flores Iris-Virginica (representadas por triângulos) varia de 1,4 cm a 2,5 
cm, enquanto as demais flores de íris (representadas por quadrados) geralmente possuem pétalas 
menores, variando de 0,1 cm a 1,8 cm. Observe que há um pouco de sobreposição. Acima de 
cerca de 2 cm, o classificador está altamente confiante de que a flor é uma Iris Virginica (ele gera 
uma alta probabilidade para essa classe), enquanto abaixo de 1 cm ele está altamente confiante 
de que não é uma Iris-Virginica (alta probabilidade para o “Não classe Iris-Virginica”). Entre esses 
extremos, o classificador não tem certeza. No entanto, se você pedir para prever a classe (usando 
o método predict() em vez do método predict_proba() ), ele retornará a classe mais provável. 
Portanto, existe um limite de decisão em torno de 1,6 cm onde ambas as probabilidades são 
iguais a 50%: se a largura da pétala for maior que 1,6 cm, o classificador irá prever que a flor é 
uma Iris Virginica, ou então irá prever que é não (mesmo que não seja muito confiante):
A Figura 4-24 mostra o mesmo conjunto de dados, mas desta vez exibindo dois recursos: largura 
e comprimento da pétala. Uma vez treinado, o classificador Logistic Regression pode estimar a 
probabilidade de que uma nova flor seja uma Iris-Virginica com base nessas duas características. 
A linha tracejada representa os pontos onde o modelo estima uma probabilidade de 50%: este é 
o limite de decisão do modelo. Observe que é um limite linear.17 Cada linha paralela representa 
os pontos onde o modelo produz uma probabilidade específica, de 15% (canto inferior esquerdo) 
a 90% (canto superior direito). Todas as flores além da linha superior direita têm mais de 90% de 
chance de serem Iris-Virginica de acordo com o modelo.
Figura 4-23. Probabilidades estimadas e limite de decisão
>>> log_reg.predict([[1.7], [1.5]]) array([1, 
0])
138 | Capítulo 4: Modelos de treinamento
17 É o conjunto dos pontos x tais que ÿ0 + ÿ1x1 + ÿ2x2 = 0, que define uma reta.
·s
Regressão Logística | 139
A ideia é bastante simples: quando dada uma instância x, o modelo Softmax Regression primeiro calcula uma pontuação 
sk (x) para cada classe k, então estima a probabilidade de cada classe aplicando a função somax (também chamada de 
exponencial normalizada) ao pontuações. A equação para calcular sk (x) deve parecer familiar, pois é exatamente como a 
equação para previsão de regressão linear (consulte a Equação 4-19).
Figura 4-24. Limite de decisão linear
Depois de calcular a pontuação de cada classe para a instância x, você pode estimar a probabilidade pk de que a instância 
pertença à classe k executando as pontuações por meio de
Regressão Softmax O modelo de 
Regressão Logística pode ser generalizado para suportar várias classes diretamente, sem a necessidade de treinar e 
combinar vários classificadores binários (conforme discutido no Capítulo 3). Isso é chamado de Regressão Somax, ou 
Regressão Logística Multinomial.
Todos esses vetores são 
normalmente armazenados como linhas em uma matriz de parâmetros ÿ.
Observe que cada classe tem seu próprio vetor de parâmetro dedicado ÿk .
Equação 4-19. Pontuação Somax para a classe k
Assim como os outros modelos lineares, os modelos de Regressão Logística podem ser regularizados usando penalidades 
ÿ1 ou ÿ2 . O Scikit-Learn na verdade adiciona uma penalidade de ÿ2 por padrão.
O hiperparâmetro que controla a força de regularização de um 
modelo Scikit-Learn LogisticRegression não é alfa (como em outros 
modelos lineares), mas seu inverso: C. Quanto maior o valor de C, 
menos o modelo é regularizado.
= ÿkk
T
= argmax kk
=
exp s j
y = argmax k
pk = ÿ
= argmax k
exp s k
sÿ ·
O classificador Softmax Regression prevê apenas uma classe por vez (ou 
seja, é multiclasse, não multisaída), portanto, deve ser usado apenas com 
classes mutuamente exclusivas, como diferentestipos de plantas. Você 
não pode usá-lo para reconhecer várias pessoas em uma foto.
• K é o número de classes.
a função softmax (Equação 4-20): ela calcula a exponencial de cada pontuação e depois as 
normaliza (dividindo pela soma de todas as exponenciais).
• O operador argmax retorna o valor de uma variável que maximiza uma função. Nesta equação, 
ele retorna o valor de k que maximiza a probabilidade estimada ÿ(s(x))k .
Equação 4-21. Previsão do classificador de regressão Somax
Assim como o classificador Logistic Regression, o classificador Softmax Regression prevê a classe 
com a probabilidade estimada mais alta (que é simplesmente a classe com a pontuação mais alta), 
conforme mostrado na Equação 4-21.
Agora que você sabe como o modelo estima probabilidades e faz previsões, vamos dar uma 
olhada no treinamento. O objetivo é ter um modelo que estime uma alta probabilidade para a 
classe alvo (e consequentemente uma baixa probabilidade para as demais classes). Minimizar a 
função de custo mostrada na Equação 4-22, chamada de entropia cruzada, deve levar a esse 
objetivo porque penaliza o modelo quando estima uma probabilidade baixa para uma classe alvo. 
A entropia cruzada é frequentemente usada para medir o quão bem um conjunto de probabilidades 
de classes estimadas corresponde às classes-alvo (usaremos novamente várias vezes nos 
capítulos seguintes).
• s(x) é um vetor contendo os escores de cada classe para a instância x. • 
ÿ(s(x))k é a probabilidade estimada de que a instância x pertença à classe k dados os escores 
de cada classe para aquela instância.
Equação 4-20. função somax
T
k
ÿkk
ÿj = 1
k
140 | Capítulo 4: Modelos de treinamento
y k m k = 1 i = 1
ÿÿ
log pk
Jÿ = k
k
pacote
m
m
m i = 1
ÿ y k
eu
eu
eu
eu eu
eu
Equação 4-22. Função de custo de entropia cruzada
• yk 
0.
O vetor gradiente desta função de custo em relação a ÿk é dado pela Equação 4-23:
Agora você pode calcular o vetor de gradiente para cada classe e, em seguida, usar Gradient Descent (ou 
qualquer outro algoritmo de otimização) para encontrar a matriz de parâmetros ÿ que minimiza a função de 
custo.
é igual a 1 se a classe de destino para a i-ésima instância for k; caso contrário, é igual a
Equação 4-23. Vetor gradiente de entropia cruzada para a classe k
Vamos usar a Regressão Softmax para classificar as flores da íris em todas as três classes. O 
LogisticRegression do Scikit Learn usa um contra todos por padrão quando você o treina em mais de duas 
classes, mas você pode definir o hiperparâmetro multi_class como "multinomial" para alterná-lo para Softmax 
Regression. Você também deve especificar um solucionador que suporte Softmax Regression, como o 
solucionador "lbfgs" (consulte a documentação do Scikit-Learn
Observe que quando há apenas duas classes (K = 2), esta função de custo é equivalente à função de custo 
da Regressão Logística (perda de log; ver Equação 4-17).
Jÿ = ÿ
1
A entropia cruzada mede o número médio de bits que você realmente envia por opção. Se 
sua suposição sobre o clima for perfeita, a entropia cruzada será igual à entropia do próprio 
clima (ou seja, sua imprevisibilidade intrínseca). Mas se suas suposições estiverem erradas 
(por exemplo, se chover com frequência), a entropia cruzada será maior em um valor 
chamado divergência de Kullback-Leibler.
1
Entropia cruzada 
A entropia cruzada originou-se da teoria da informação. Suponha que você queira transmitir 
com eficiência informações sobre o clima todos os dias. Se houver oito opções (ensolarado, 
chuvoso, etc.), você pode codificar cada opção usando 3 bits, pois 23 = 8. No entanto, se 
você acha que estará ensolarado quase todos os dias, seria muito mais eficiente codificar 
“ensolarado ” em apenas um bit (0) e as outras sete opções em 4 bits (começando com 1).
A entropia cruzada entre duas distribuições de probabilidade p e q é definida como H p, q 
= ÿ ÿx px log qx (pelo menos quando as distribuições são discretas).
Regressão Logística | 141
ÿ
ÿ
ÿ
142 | Capítulo 4: Modelos de treinamento
exercícios
1. Qual algoritmo de treinamento de regressão linear você pode usar se tiver um conjunto de 
treinamento com milhões de recursos?
Então, da próxima vez que você encontrar uma íris com pétalas de 5 cm de comprimento e 2 cm de 
largura, você pode pedir ao seu modelo para dizer que tipo de íris é, e ele responderá Iris-Virginica 
(classe 2) com 94,2% de probabilidade (ou Iris-Versicolor com 5,8% de probabilidade):
A Figura 4-25 mostra os limites de decisão resultantes, representados pelas cores de fundo. Observe 
que os limites de decisão entre quaisquer duas classes são lineares. A figura também mostra as 
probabilidades para a classe Iris-Versicolor, representada pelas linhas curvas (por exemplo, a linha 
marcada com 0,450 representa o limite de probabilidade de 45%). Observe que o modelo pode prever 
uma classe que tenha uma probabilidade estimada abaixo de 50%. Por exemplo, no ponto onde todos 
os limites de decisão se encontram, todas as classes têm uma probabilidade igual estimada de 33%.
2. Suponha que os recursos em seu conjunto de treinamento tenham escalas muito diferentes. Quais 
algoritmos podem sofrer com isso e como? O que você pode fazer sobre isso?
ção para mais detalhes). Ele também aplica a regularização ÿ2 por padrão, que você pode controlar 
usando o hiperparâmetro C.
Figura 4-25. Limites de decisão de regressão Somax
softmax_reg = LogisticRegression(multi_class="multinomial",solver="lbfgs", C=10) softmax_reg.fit(X, 
y)
>>> softmax_reg.predict([[5, 2]]) array([2]) 
>>> 
softmax_reg.predict_proba([[5, 2]]) 
array([[ 6.33134078e-07, 5.75276067e-02, 9.42471760e-01]])
X = iris["dados"][:, (2, 3)] # comprimento da pétala, largura da pétala 
y = iris["alvo"]
9. Suponha que você esteja usando Ridge Regression e perceba que o erro de treinamento e o erro de 
validação são quase iguais e razoavelmente altos. Você diria que o modelo sofre de alto viés ou 
alta variância? Você deve aumentar o hiperparâmetro de regularização ÿ ou reduzi-lo?
10. Por que você deseja usar:
3. O gradiente descendente pode ficar preso em um mínimo local ao treinar um modelo de regressão 
logística?
• Regressão Ridge em vez de Regressão Linear? • Laço em 
vez de regressão de crista? • Elastic Net em 
vez de Lasso?
4. Todos os algoritmos de descida de gradiente levam ao mesmo modelo, desde que você os deixe 
rodar por tempo suficiente?
11. Suponha que você queira classificar as fotos como externas/internas e diurnas/noturnas.
Você deve implementar dois classificadores Logistic Regression ou um classificador Softmax 
Regression?
5. Suponha que você use Batch Gradient Descent e plote o erro de validação em cada época. Se você 
perceber que o erro de validação aumenta consistentemente, o que provavelmente está 
acontecendo? Como você pode consertar isso?
6. É uma boa ideia parar a descida do gradiente de mini-lote imediatamentequando o valor
12. Implementar descida de gradiente em lote com parada antecipada para regressão Softmax
erro de dação aumenta?
(sem usar o Scikit-Learn).
7. Qual algoritmo de Gradient Descent (entre os que discutimos) alcançará a vizinhança da solução 
ótima mais rapidamente? Qual realmente irá convergir? Como você pode fazer os outros convergirem 
também?
As soluções para esses exercícios estão disponíveis no Apêndice A.
8. Suponha que você esteja usando regressão polinomial. Você traça as curvas de aprendizado e 
percebe que há uma grande lacuna entre o erro de treinamento e o erro de validação. O que está 
acontecendo? Quais são as três maneiras de resolver isso?
Exercícios | 143
Máquinas de vetores de suporte
145
CAPÍTULO 5
Este capítulo explicará os principais conceitos de SVMs, como usá-los e como eles funcionam.
A ideia fundamental por trás dos SVMs é melhor explicada com algumas imagens. A Figura 5-1 mostra parte do 
conjunto de dados da íris que foi introduzido no final do Capítulo 4. As duas classes podem ser facilmente 
separadas com uma linha reta (elas são linearmente separáveis).
Uma Support Vector Machine (SVM) é um modelo de aprendizado de máquina muito poderoso e versátil, capaz 
de realizar classificação linear ou não linear, regressão e até mesmo detecção de valores discrepantes. É um dos 
modelos mais populares em Machine Learning, e qualquer pessoa interessada em Machine Learning deve tê-lo 
em sua caixa de ferramentas. Os SVMs são particularmente adequados para a classificação de conjuntos de 
dados complexos, mas de tamanho pequeno ou médio.
O gráfico à esquerda mostra os limites de decisão de três possíveis classificadores lineares. O modelo cujo limite 
de decisão é representado pela linha tracejada é tão ruim que nem separa as classes adequadamente. Os outros 
dois modelos funcionam perfeitamente neste conjunto de treinamento, mas seus limites de decisão chegam tão 
perto das instâncias que esses modelos provavelmente não funcionarão tão bem em novas instâncias. Em 
contraste, a linha sólida no gráfico à direita representa o limite de decisão de um classificador SVM; esta linha 
não apenas separa as duas classes, mas também fica o mais longe possível das instâncias de treinamento mais 
próximas. Você pode pensar em um classificador SVM como ajustando a rua mais larga possível (representada 
pelas linhas tracejadas paralelas) entre as classes.
Isso é chamado de classificação de grande margem.
Classificação Linear SVM
Classificação de margem flexível Se 
impusermos estritamente que todas as instâncias estejam fora da rua e no lado direito, isso é chamado de 
classificação de margem rígida. Existem dois problemas principais com a classificação de margem rígida. Em 
primeiro lugar, só funciona se os dados forem linearmente separáveis e, em segundo lugar, é bastante sensível a 
outliers. A Figura 5-3 mostra o conjunto de dados da íris com apenas um outlier adicional: à esquerda, é impossível 
encontrar uma margem rígida e, à direita, o limite de decisão termina muito diferente daquele que vimos na Figura 
5-1 sem o outlier, e provavelmente não irá generalizar também.
Figura 5-1. Classificação de grande margem
Figura 5-2. Sensibilidade para escalas de recursos
Observe que adicionar mais instâncias de treinamento “fora da rua” não afetará em nada o limite de decisão: ele é 
totalmente determinado (ou “suportado”) pelas instâncias localizadas na borda da rua. Essas instâncias são chamadas 
de vetores de suporte (eles estão circulados na Figura 5-1).
SVMs são sensíveis às escalas de recursos, como você pode ver na Figura 5-2: no 
gráfico à esquerda, a escala vertical é muito maior que a escala horizontal, então a 
rua mais larga possível é quase horizontal.
Após o dimensionamento de recursos (por exemplo, usando o StandardScaler do 
Scikit-Learn), o limite de decisão parece muito melhor (no gráfico à direita).
146 | Capítulo 5: Máquinas de vetores de suporte
Nas classes SVM do Scikit-Learn, você pode controlar esse equilíbrio usando o hiperparâmetro C : um valor 
C menor leva a uma rua mais larga, mas a mais violações de margem. A Figura 5-4 mostra os limites de 
decisão e as margens de dois classificadores SVM de margem suave em um conjunto de dados não 
linearmente separável. À esquerda, usando um valor alto de C , o classificador faz menos violações de 
margem, mas acaba com uma margem menor. À direita, usando um valor C baixo , a margem é muito 
maior, mas muitas instâncias acabam na rua. No entanto, parece provável que o segundo classificador 
generalize melhor: de fato, mesmo neste conjunto de treinamento, ele comete menos erros de previsão, 
pois a maioria das violações de margem está realmente no lado correto do limite de decisão.
Para evitar esses problemas, é preferível usar um modelo mais flexível. O objetivo é encontrar um bom 
equilíbrio entre manter a rua o mais larga possível e limitar as violações de margem (ou seja, instâncias que 
terminam no meio da rua ou mesmo do lado errado). Isso é chamado de classificação de margem.
Figura 5-4. Menos violações de margem versus margem grande
O código Scikit-Learn a seguir carrega o conjunto de dados da íris, dimensiona os recursos e treina um 
modelo SVM linear (usando a classe LinearSVC com C = 0,1 e a perda de dobradiça
Figura 5-3. Sensibilidade de margem rígida para outliers
Se o seu modelo SVM estiver superajustado, você pode tentar regularizá-lo 
reduzindo C.
Classificação Linear SVM | 147
148 | Capítulo 5: Máquinas de vetores de suporte
função, descrita brevemente) para detectar flores Iris-Virginica. O modelo resultante é representado à 
direita da Figura 5-4.
Então, como de costume, você pode usar o modelo para fazer previsões:
Alternativamente, você pode usar a classe SVC , usando SVC(kernel="linear", C=1), mas é muito mais 
lento, especialmente com grandes conjuntos de treinamento, portanto não é recomendado. Outra opção 
é usar a classe SGDClassifier , com SGDClassifier(loss="hinge", alpha=1/(m*C)). Isso aplica a descida 
do gradiente estocástico regular (consulte o Capítulo 4) para treinar um classificador SVM linear. Ele não 
converge tão rápido quanto a classe LinearSVC , mas pode ser útil para lidar com grandes conjuntos de 
dados que não cabem na memória (treinamento fora do núcleo) ou para lidar com tarefas de classificação 
online.
Ao contrário dos classificadores de regressão logística, os classificadores SVM não 
fornecem probabilidades para cada classe.
A classe LinearSVC regulariza o termo de viés, então você deve centralizar o conjunto 
de treinamento primeiro subtraindo sua média. Isso é automático se você dimensionar 
os dados usando o StandardScaler. Além disso, certifique-se de definir o hiperparâmetro 
de perda como "dobradiça", pois não é o valor padrão. Finalmente, para um melhor 
desempenho, você deve definir o hiperparâmetro dual como Falso, a menos que haja 
maisrecursos do que instâncias de treinamento (discutiremos a dualidade mais adiante 
no capítulo).
svm_clf = 
Pipeline(( ("scaler", StandardScaler()), 
("linear_svc", LinearSVC(C=1, perda="dobradiça")),
>>> svm_clf.predict([[5.5, 1.7]]) array([ 1.])
import numpy as np 
from sklearn import datasets 
from sklearn.pipeline import Pipeline from 
sklearn.preprocessing import StandardScaler from 
sklearn.svm import LinearSVC
X = iris["data"][:, (2, 3)] # comprimento da pétala, largura da pétala y = 
(iris["target"] == 2).astype(np.float64) # Iris-Virginica
))
svm_clf.fit(X_scaled, y)
íris = conjuntos de dados.load_iris()
Classificação SVM não linear | 149
Classificação SVM não linear
2
polynomial_svm_clf = 
Pipeline(( ("poly_features", PolynomialFeatures(degree=3)), 
("scaler", StandardScaler()), 
("svm_clf", LinearSVC(C=10, loss="dobradiça"))
polynomial_svm_clf.fit(X, y)
from sklearn.datasets import make_moons 
from sklearn.pipeline import Pipeline from 
sklearn.preprocessing import PolynomialFeatures
))
o conjunto de dados 2D resultante é perfeitamente separável linearmente.
Para implementar essa ideia usando o Scikit-Learn, você pode criar um Pipeline contendo um transformador 
PolynomialFeatures (discutido em “Regressão polinomial” na página 121), seguido por um StandardScaler e um 
LinearSVC. Vamos testar isso no conjunto de dados das luas (consulte a Figura 5-6):
Embora os classificadores SVM lineares sejam eficientes e funcionem surpreendentemente bem em muitos casos, 
muitos conjuntos de dados não estão nem perto de serem linearmente separáveis. Uma abordagem para lidar com 
conjuntos de dados não lineares é adicionar mais recursos, como recursos polinomiais (como você fez no Capítulo 
4); em alguns casos, isso pode resultar em um conjunto de dados linearmente separável.
,
Figura 5-5. Adicionando recursos para tornar um conjunto de dados linearmente separável
Considere o gráfico à esquerda na Figura 5-5: ele representa um conjunto de dados simples com apenas um recurso 
x1 . Este conjunto de dados não é linearmente separável, como você pode ver. Mas se você adicionar um segundo 
recurso x2 = (x1 )
Kernel polinomial A 
adição de recursos polinomiais é simples de implementar e pode funcionar muito bem com todos 
os tipos de algoritmos de aprendizado de máquina (não apenas SVMs), mas em um baixo grau 
polinomial não pode lidar com conjuntos de dados muito complexos e, com um alto grau 
polinomial, cria um enorme número de features, tornando o modelo muito lento.
Este código treina um classificador SVM usando um kernel polinomial de 3º grau. Ele é 
representado à esquerda da Figura 5-7. À direita está outro classificador SVM usando um kernel 
polinomial de 10º grau. Obviamente, se o seu modelo estiver superajustado, você pode querer
Felizmente, ao usar SVMs, você pode aplicar uma técnica matemática quase milagrosa chamada 
truque do kernel (explicada em um momento). Isso torna possível obter o mesmo resultado como 
se você adicionasse muitos recursos polinomiais, mesmo com polinômios de grau muito alto, 
sem realmente precisar adicioná-los. Portanto, não há explosão combinatória do número de 
recursos, pois você não adiciona nenhum recurso. Este truque é implementado pela classe SVC . 
Vamos testá-lo no conjunto de dados das luas:
Figura 5-6. Classificador SVM linear usando recursos polinomiais
from sklearn.svm import SVC 
poly_kernel_svm_clf = Pipeline(( ("scaler", 
StandardScaler()), ("svm_clf", 
SVC(kernel="poly", grau=3, coef0=1, C=5))
))
poly_kernel_svm_clf.fit(X, y)
150 | Capítulo 5: Máquinas de vetores de suporte
2ÿÿ , ÿ = exp ÿÿ ÿ ÿ
Figura 5-7. Classificadores SVM com kernel polinomial
Equação 5-1. RBF gaussiano
reduzir o grau polinomial. Por outro lado, se estiver subajustado, você pode tentar aumentá-lo. O 
hiperparâmetro coef0 controla o quanto o modelo é influenciado por polinômios de alto grau versus 
polinômios de baixo grau.
É uma função em forma de sino variando de 0 (muito longe do ponto de referência) a 1 (no ponto de 
referência). Agora estamos prontos para calcular os novos recursos. Por exemplo, vejamos a instância 
x1 = –1: ela está localizada a uma distância de 1 do primeiro ponto de referência e 2 do segundo ponto 
de referência. Portanto, suas novas características são x2 = exp (–0,3 × 12 ) ÿ 0,74 e x3 = exp (–0,3 × 
22 ) ÿ 0,30. O gráfico à direita da Figura 5-8 mostra o conjunto de dados transformado (descartando 
os recursos originais). Como você pode ver, agora é linearmente separável.
Adicionando recursos de similaridade 
Outra técnica para lidar com problemas não lineares é adicionar recursos calculados usando uma 
função de similaridade que mede o quanto cada instância se assemelha a um determinado ponto de 
referência. Por exemplo, vamos pegar o conjunto de dados unidimensional discutido anteriormente e 
adicionar dois pontos de referência a ele em x1 = –2 e x1 = 1 (veja o gráfico à esquerda na Figura 
5-8). Em seguida, vamos definir a função de similaridade como sendo a Função Gaussiana de Base 
Radial (RBF) com ÿ = 0,3 (consulte a Equação 5-1).
Uma abordagem comum para encontrar os valores corretos dos hiperparâmetros é usar a 
pesquisa em grade (consulte o Capítulo 2). Frequentemente, é mais rápido fazer primeiro 
uma pesquisa de grade muito grosseira e, em seguida, uma pesquisa de grade mais 
refinada em torno dos melhores valores encontrados. Ter uma boa noção do que cada 
hiperparâmetro realmente faz também pode ajudá-lo a pesquisar na parte certa do espaço 
de hiperparâmetros.
Classificação SVM não linear | 151
rbf_kernel_svm_clf = Pipeline(( ("scaler", 
StandardScaler()), ("svm_clf", 
SVC(kernel="rbf", gama=5, C=0,001))
)) 
rbf_kernel_svm_clf.fit(X, y)
Você pode se perguntar como selecionar os pontos de referência. A abordagem mais simples é criar 
um ponto de referência no local de cada instância no conjunto de dados. Isso cria muitas dimensões 
e, portanto, aumenta as chances de que o conjunto de treinamento transformado seja linearmente 
separável. A desvantagem é que um conjunto de treinamento com m instâncias e n recursos é 
transformado em um conjunto de treinamento com m instâncias e m recursos (supondo que você 
descarte os recursos originais). Se seu conjunto de treinamento for muito grande, você terá um 
número igualmente grande de recursos.
Esse modelo é representado na parte inferior esquerda da Figura 5-9. Os outros gráficos mostram 
modelos treinados com diferentes valores de hiperparâmetros gama (ÿ) e C. O aumento de gama 
torna a curva em forma de sino mais estreita (consulte o gráfico esquerdo da Figura 5-8) e, como 
resultado, o intervalo de influência de cada instância é menor : o limite de decisão acaba sendo mais 
irregular, oscilando em torno de instâncias individuais. Por outro lado, um pequeno valor de gama 
torna a curva em forma de sino mais larga, de modo que as instâncias tenham uma gama maior de 
influência e o limite de decisão acaba sendo mais suave. Assim,ÿ age como um hiperparâmetro de 
regularização: se o seu modelo for overfitting, você deve reduzi-lo, e se for underfitting, você deve 
aumentá-lo (semelhante ao hiperparâmetro C ).
Figura 5-8. Recursos de similaridade usando o Gaussian RBF
Assim como o método de recursos polinomiais, o método de recursos de similaridade pode ser útil 
com qualquer algoritmo de aprendizado de máquina, mas pode ser computacionalmente caro 
calcular todos os recursos adicionais, especialmente em grandes conjuntos de treinamento. No 
entanto, mais uma vez o truque do kernel faz sua mágica SVM: torna possível obter um resultado 
semelhante como se você tivesse adicionado muitos recursos de similaridade, sem realmente 
precisar adicioná-los. Vamos tentar o kernel Gaussian RBF usando a classe SVC :
152 | Capítulo 5: Máquinas de vetores de suporte
Núcleo Gaussiano RBF
1 “Um Método de Descida de Coordenadas Duplas para SVM Linear em Grande Escala,” Lin et al. (2008).
Classificação SVM não linear | 153
Complexidade Computacional A 
classe LinearSVC é baseada na biblioteca liblinear, que implementa um algoritmo otimizado para SVMs 
lineares.1 Ele não suporta o truque do kernel, mas escala quase
Figura 5-9. Classificadores SVM usando um kernel RBF
Existem outros kernels, mas são usados muito mais raramente. Por exemplo, alguns kernels são 
especializados para estruturas de dados específicas. Os kernels de string são algumas vezes usados ao 
classificar documentos de texto ou sequências de DNA (por exemplo, usando o kernel de subsequência 
de string ou kernels baseados na distância de Levenshtein).
Então, se você tiver tempo livre e capacidade de computação, também poderá 
experimentar alguns outros kernels usando validação cruzada e pesquisa em 
grade, especialmente se houver kernels especializados para a estrutura de dados 
do seu conjunto de treinamento.
Com tantos kernels para escolher, como você pode decidir qual usar? Como regra 
geral, você deve sempre tentar o kernel linear primeiro (lembre-se de que 
LinearSVC é muito mais rápido que SVC(ker nel="linear")), especialmente se o 
conjunto de treinamento for muito grande ou se tiver muitos recursos. Se o conjunto 
de treinamento não for muito grande, você também deve tentar o kernel Gaussian 
RBF; funciona bem na maioria dos casos.
http://goo.gl/R635CH
http://goo.gl/R635CH
Sim
Não Sim
Sim
Não
Complexidade de tempo
SGDClassifier O(m × n)
O(m × n)
Sim
154 | Capítulo 5: Máquinas de vetores de suporte
Sim
Suporte fora do núcleo Escalonamento necessário Truque do kernel
Não
Aula
O(m² × n) a O(m³ × n) Não
LinearSVC
SVC
linearmente com o número de instâncias de treinamento e o número de features: sua complexidade de 
tempo de treinamento é aproximadamente O(m × n).
Como mencionamos anteriormente, o algoritmo SVM é bastante versátil: não apenas suporta 
classificação linear e não linear, mas também suporta regressão linear e não linear. O truque é 
inverter o objetivo: em vez de tentar ajustar a maior rua possível entre duas classes enquanto 
limita as violações de margem, a Regressão SVM tenta ajustar o maior número possível de 
instâncias na rua enquanto limita as violações de margem (ou seja, instâncias do rua). A largura 
da rua é controlada por um hiperparâmetro. A Figura 5-10 mostra dois modelos lineares de 
regressão SVM treinados em alguns
ÿ
A classe SVC é baseada na biblioteca libsvm, que implementa um algoritmo que suporta o truque 
do kernel.2 A complexidade do tempo de treinamento é geralmente entre O(m2 × n) e O(m3 × n). 
Infelizmente, isso significa que ele fica terrivelmente lento quando o número de instâncias de 
treinamento aumenta (por exemplo, centenas de milhares de instâncias). Este algoritmo é perfeito 
para conjuntos de treinamento complexos, mas pequenos ou médios. No entanto, ele escala bem 
com o número de recursos, especialmente com recursos esparsos (ou seja, quando cada instância 
possui poucos recursos diferentes de zero). Nesse caso, o algoritmo escala aproximadamente 
com o número médio de recursos diferentes de zero por instância. A Tabela 5-1 compara as 
classes de classificação SVM do Scikit-Learn.
dados lineares, um com margem grande ( = 1,5) e outro com margem pequena ( 0,5).
ÿ
ÿ
=
O algoritmo leva mais tempo se você precisar de uma precisão muito alta. Isso é controlado pelo 
hiperparâmetro de tolerância (chamado tol no Scikit-Learn). Na maioria das tarefas de classificação, 
a tolerância padrão é aceitável.
ter
ÿ
Tabela 5-1. Comparação de classes Scikit-Learn para classificação SVM
Regressão SVM
2 “Otimização Mínima Sequencial (SMO),” J. Platt (1998).
http://goo.gl/a8HkE3
ÿ
Adicionar mais instâncias de treinamento dentro da margem não afeta as previsões do modelo; assim, 
diz-se que o modelo é
Figura 5-11. Regressão SVM usando um kernel polinomial de 2º grau
Para lidar com tarefas de regressão não linear, você pode usar um modelo SVM com kernel. Por 
exemplo, a Figura 5-11 mostra a Regressão SVM em um conjunto de treinamento quadrático aleatório, 
usando um kernel polinomial de 2º grau. Há pouca regularização no gráfico da esquerda (ou seja, um 
grande valor de C ) e muito mais regularização no gráfico da direita (ou seja, um pequeno valor de C ).
Você pode usar a classe LinearSVR do Scikit-Learn para executar a Regressão SVM linear. O código a 
seguir produz o modelo representado à esquerda da Figura 5-10 (os dados de treinamento devem ser 
dimensionados e centralizados primeiro):
Figura 5-10. Regressão SVM
-insensível.
de sklearn.svm importar LinearSVR
svm_reg = LinearSVR(epsilon=1.5) 
svm_reg.fit(X, y)
Regressão SVM | 155
1 se · + b ÿ 0
y =
· + b < 0,0 se
sob o capô
Esta seção explica como os SVMs fazem previsões e como seus algoritmos de treinamento funcionam, 
começando com classificadores SVM lineares. Você pode ignorá-lo com segurança e ir direto para os 
exercícios no final deste capítulo se estiver apenas começando com Machine Learning e voltar mais 
tarde quando quiser obter uma compreensão mais profunda dos SVMs.
Primeiro, uma palavra sobre notações: no Capítulo 4 , usamos a convenção de colocar todos os 
parâmetros do modelo em um vetor ÿ, incluindo o termo de tendência ÿ0 e os pesos de recursos de 
entrada ÿ1 a ÿn , e adicionar uma entrada de tendência x0 = 1 para todas as instâncias . Neste 
capítulo, usaremos uma convenção diferente, que é mais conveniente (e mais comum) quando você 
está lidando com SVMs: o termo bias será chamado de b e o vetor de pesos de características será 
chamado de w . Nenhum recurso de polarização será adicionado aos vetores de recurso de entrada.
Equação 5-2. Previsão do classificador SVM linear
O código a seguir produz o modelo representado à esquerda da Figura 5.11 usando a classe SVR do 
Scikit-Learn (que suporta o truque do kernel). A classe SVR é o equivalente de regressão da classe 
SVC , e a classe LinearSVR é o equivalente de regressão da classe LinearSVC . Aclasse LinearSVR 
escala linearmente com o tamanho do conjunto de treinamento (assim como a classe LinearSVC ), 
enquanto a classe SVR fica muito lenta quando o conjunto de treinamento cresce (assim como a 
classe SVC ).
O modelo classificador linear SVM prevê a classe de uma nova instância x simplesmente calculando 
a função de decisão wT · x + b = w1 x1 + ÿ + wn xn + b: se o resultado for positivo, a classe prevista 
ÿ é a classe positiva (1), ou então é a classe negativa (0); veja a Equação 5-2.
T
T
SVMs também podem ser usados para detecção de outlier; consulte a documentação do 
Scikit-Learn para obter mais detalhes.
Função de Decisão e Previsões
de sklearn.svm importar SVR
svm_poly_reg = SVR(kernel="poly", grau=2, C=100, epsilon=0,1) 
svm_poly_reg.fit(X, y)
156 | Capítulo 5: Máquinas de vetores de suporte
Objetivo do treinamento 
Considere a inclinação da função de decisão: é igual à norma do vetor de peso, ÿ w ÿ. Se dividirmos essa inclinação 
por 2, os pontos onde a função de decisão é igual a ±1 estarão duas vezes mais distantes do limite de decisão. Em 
outras palavras, dividir a inclinação por 2 multiplicará a margem por 2. Talvez seja mais fácil visualizar isso em 2D 
na Figura 5-13. Quanto menor o vetor de ponderação w, maior a margem.
As linhas tracejadas representam os pontos onde a função de decisão é igual a 1 ou –1: são paralelas e à mesma 
distância do limite de decisão, formando uma margem ao seu redor. Treinar um classificador SVM linear significa 
encontrar o valor de w e b que tornam essa margem o mais ampla possível, evitando violações de margem (margem 
rígida) ou limitando-as (margem flexível).
A Figura 5-12 mostra a função de decisão que corresponde ao modelo à direita da Figura 5-4: é um plano 
bidimensional, pois esse conjunto de dados possui dois recursos (largura da pétala e comprimento da pétala). O 
limite de decisão é o conjunto de pontos onde a função de decisão é igual a 0: é a interseção de dois planos, que é 
uma linha reta (representada pela linha sólida grossa).3
Figura 5-12. Função de decisão para o conjunto de dados de íris
3 Mais geralmente, quando há n características, a função de decisão é um hiperplano n-dimensional, e o 
limite de decisão é um hiperplano (n – 1)-dimensional.
sob o capô | 157
·
,
·
(eu)
(eu) (eu)
1
22
1
seu quadrado), mas 2
1
2
Podemos, portanto, expressar o objetivo do classificador SVM linear de margem rígida como o problema 
de otimização restrita na Equação 5-3.
instâncias (se y 
instâncias.
margem. É aqui que entra o hiperparâmetro C : ele nos permite definir o tradeÿ
Para obter o objetivo de margem flexível, precisamos introduzir uma variável de folga ÿ (i) ÿ 0 para 
cada instância:4 ÿ (i) mede o quanto a instância i pode violar a margem. Agora temos dois objetivos 
conflitantes: tornar as variáveis de folga tão pequenas quanto possível para
Portanto, queremos minimizar ÿ w ÿ para obter uma margem grande. No entanto, se também quisermos 
evitar qualquer violação de margem (margem rígida), precisamos que a função de decisão seja maior 
que 1 para todas as instâncias de treinamento positivas e menor que -1 para instâncias de treinamento 
negativas. Se definirmos t (i) = 0) e t (i) = –1 para instâncias negativas (se y = 1 para positivo + b) ÿ 1 para todos
= 1), então podemos expressar essa restrição como t (i)(wT · x
Figura 5-13. Um vetor de peso menor resulta em uma margem maior
Equação 5-3. Objetivo do classificador SVM linear de margem rígida
wT · foi o menor possível para aumentar oreduzir as violações de margem, e fazer
4 Zeta (ÿ) é a oitava letra do alfabeto grego.
,
isto
T
eu
minimizar 
b 2
+ b ÿ 1 para i = 1, 2, ÿ, msujeito a t
1
158 | Capítulo 5: Máquinas de vetores de suporte
wT · w, que é igual a 
minimizar ÿ w ÿ. Isto porque dará o mesmo resultado (uma vez que os valores 
de w e b que minimizam um valor também minimizam metade de 1
em vez de
ÿ w ÿ 2 tem uma derivada boa e simples (é apenas
ÿ w ÿ 2estamos minimizando
w) enquanto ÿ w ÿ não é diferenciável em w = 0. Algoritmos de otimização 
funcionam muito melhor em funções diferenciáveis.
·
Equação 5-5. Problema de Programação Quadrática
(i) ÿ b (i) para i =
• np = n + 1, onde n é o número de recursos (o +1 é para o termo de viés).
entre esses dois objetivos. Isso nos dá o problema de otimização restrita na Equação 5-4.
Observe que a expressão A · p ÿ b na verdade define nc restrições: p (i) é o 
vetor contendo os elementos da i-ésima linha de A e b (i) é onde a 1, 2, ÿ, nc , o i-ésimo elemento 
de b.
Você pode verificar facilmente que, se definir os parâmetros QP da seguinte maneira, obterá o 
objetivo do classificador SVM linear de margem rígida:
Equação 5-4. Objetivo do classificador SVM linear de margem
berghe, otimização convexa (Cambridge, Reino Unido: Cambridge University Press, 2004) ou assista à série de palestras 
em vídeo de Richard Brown.
T · a
Programação quadrática Os 
problemas de hard margin e soft margin são ambos problemas de otimização quadrática convexa 
com restrições lineares. Tais problemas são conhecidos como problemas de Programação Quadrática 
(QP). Muitos solucionadores de prateleira estão disponíveis para resolver problemas de QP usando 
uma variedade de técnicas que estão fora do escopo deste livro.5 A formulação geral do problema é 
dada pela Equação 5-5.
Minimizar
· + Cÿ
e ÿ
+
ÿ
ÿ 0 para i = 1, 2,ÿ, m
·
×
onde
· ·
sujeito a
1
1 2
· ÿ
vetor ÿdimensional (np = número de parâmetros), é uma 
matriz np np ,
2
é um 
vetor np dimensional, é uma 
matriz np (nc = número de restrições), é um nc × np é um 
vetor nc dimensional.
+ b ÿ 1 ÿ ÿ
sob o capô | 159
m
i T 
sujeito a t
eu
eu = 1
eu
minimizar , b, ÿ
T
T
eu
T
5 Para aprender mais sobre Programação Quadrática, você pode começar lendo Stephen Boyd e Lieven Vandenÿ
eu
http://goo.gl/FGXuLw
http://goo.gl/rTo3Af
·
0
No entanto, para usar o truque do kernel, veremos um problema diferente de otimização restrita.
• f = 0, um vetor np -dimensional cheio de 0s. • b 
= 1, um vetor nc -dimensional cheio de 1s. = –t (i) 
ÿ (i), onde ÿ (i) é igual a x (i) com um recurso de viés extra ÿ
Equação 5-6. Forma dupla do objetivo SVM linear
= 1.
o termo viés).
Dado um problema de otimização restrito, conhecido como problema primal, é possível expressar 
um problema diferente, mas intimamente relacionado, chamado de problema dual. A solução para o 
problema dual tipicamente dá um limite inferior para a solução do problema primal, mas sob algumas 
condições pode até ter as mesmas soluções que o problema primal. Felizmente, o problema SVM 
atende a essas condições,6 então você pode optar por resolver o problema primal ou o problema 
dual; ambos terão a mesma solução. A Equação 5-6 mostra a forma dual do objetivo SVM linear (se 
você estiver interessado em saber como derivaro problema dual do problema primal, consulte o 
Apêndice C).
(i) • um
• nc = m, onde m é o número de instâncias de treinamento. • H 
é a matriz de identidade np × np , exceto com um zero na célula superior esquerda (para ignorar
Portanto, uma maneira de treinar um classificador SVM linear de margem rígida é apenas usar um 
solucionador QP pronto para uso, passando os parâmetros anteriores. O vetor p resultante conterá 
o termo de viés b = p0 e os pesos dos recursos wi = pi para i = 1, 2, ÿ, m. Da mesma forma, você 
pode usar um solucionador QP para resolver o problema de margem flexível (consulte os exercícios 
no final do capítulo).
ÿ
O Problema Duplo
sujeito a ÿ
ÿ
1
ÿ 0 para i = 1, 2, ÿ, m
ÿ ÿ
160 | Capítulo 5: Máquinas de vetores de suporte
m
eu ÿ
ji T
m
j
ÿ minimizar 2 i 
= 1 j = 1
eu
6 A função objetivo é convexa e as restrições de desigualdade são continuamente diferenciáveis e convexas
ji tt
m
eu = 1
funções.
eu ÿ
ÿ
1
ÿ = ÿ
= ÿ
=
·
O problema dual é mais rápido de resolver do que o primal quando o número de instâncias de 
treinamento é menor que o número de recursos. Mais importante, torna possível o truque do kernel, 
enquanto o primal não. Então, afinal, qual é esse truque do kernel?
Suponha que você queira aplicar uma transformação polinomial de 2º grau a um conjunto de 
treinamento bidimensional (como o conjunto de treinamento das luas) e, em seguida, treinar um 
classificador SVM linear no conjunto de treinamento transformado. A equação 5-8 mostra a função 
de mapeamento polinomial de 2º grau ÿ que você deseja aplicar.
Equação 5-7. Da solução dual à solução primal
Observe que o vetor transformado é tridimensional em vez de bidimensional.
Agora, vejamos o que acontece com alguns vetores bidimensionais, a e b, se aplicarmos esse 
mapeamento polinomial de 2º grau e, em seguida, calcularmos o produto escalar dos vetores 
transformados (consulte a Equação 5-9).
Equação 5-8. Mapeamento polinomial de segundo grau
Depois de encontrar o vetor ÿ que minimiza essa equação (usando um solucionador QP), você 
pode calcular eb que minimiza o problema primal usando a Equação 5-7.
x2
i T 1 ÿ 
t
eu
2
x2
i = 1 
eu
m
2
eu
b = 
ns
x1
ii t ÿ 
i = 
1
2x1x2 _ _
> 0
x1
m
ÿ
ÿ
Kernelized SVM
sob o capô | 161
T
2
2
a1
j
2
2
T
T
2a2 _
+ 2a1 b1 a2 b2 + a2
2
T
2 b1 b2
2
a1
a2
= a1 b1 + a2 b2
2
2
b2
2
d
2
isto
b1
2
T
b2
b1 
b2
b12 a1 a2
2
,
,
,
·
,
.
Equação 5-9. Truque do kernel para um mapeamento polinomial de 2º grau
· b)
Equação 5-10. Kernels comuns
· b)
.
Agora, aqui está o insight principal: se você aplicar a transformação ÿ a todas as instâncias de 
treinamento, o problema dual (consulte a Equação 5-6) conterá o produto escalar ÿ(x (i)) T ÿ(x (j) ). Mas 
se ÿ é a transformação polinomial de 2º grau definida na Equação 5-8,
· ÿ(b) = (a
A função K(a, b) = (a é chamada de kernel polinomial de 2º grau. No aprendizado de máquina, um kernel 
é uma função capaz de calcular o produto escalar ÿ(a) · ÿ(b) com base apenas nos vetores originais a e 
b, sem ter que calcular (ou mesmo conhecer) a transformação ÿ. A Equação 5-10 lista alguns dos kernels 
mais comumente usados.
Que tal isso? O produto escalar dos vetores transformados é igual ao quadrado do produto escalar dos 
vetores originais: ÿ(a)
·
·
então você pode substituir este produto escalar de vetores transformados simplesmente 
por Portanto, na verdade, você não precisa transformar as instâncias de treinamento: apenas substitua 
o produto escalar por seu quadrado na Equação 5-6 . O resultado será estritamente o mesmo como se 
você tivesse o problema de realmente transformar o conjunto de treinamento e ajustar um algoritmo 
SVM linear, mas esse truque torna todo o processo muito mais eficiente computacionalmente. Esta é a 
essência do truque do kernel.
=
RBF gaussiano: K
=
Sigmóide: K
· ÿ
= exp ÿÿ ÿ
·
= ·
T ·+r
=
= a1
·
= tanh ÿ
Linear: K
T ·+rPolinômio: K = ÿ
ÿ
162 | Capítulo 5: Máquinas de vetores de suporte
T
T 2
2
T
T
Ainda há uma ponta solta que devemos amarrar. A Equação 5-7 mostra como ir da solução dual 
para a solução primal no caso de um classificador SVM linear, mas se você aplicar o truque do 
kernel, acabará com equações que incluem ÿ(x (i)) . Na verdade, deve ter o mesmo número de 
dimensões que ÿ(x (i)), que pode ser enorme ou mesmo infinito, então você não pode calculá-lo. 
Mas como você pode fazer previsões sem saber? Bem, a boa notícia é que você pode inserir a 
fórmula da Equação 5-7 na função de decisão para uma nova instância x (n) e obter uma 
equação apenas com produtos escalares entre os vetores de entrada. Isso torna possível usar o 
truque do kernel, mais uma vez (Equação 5-11).
Equação 5-11. Fazendo previsões com um SVM kernelizado
Observe que, como ÿ (i) ÿ 0 apenas para vetores de suporte, fazer previsões envolve calcular (n) 
apenas com os vetores de suporte, não totalizando o produto escalar do novo vetor de 
entrada x as instâncias de treinamento. Claro, você também precisa calcular o termo de viés b, 
usando o mesmo truque (Equação 5-12).
=ÿ
,
Teorema de Mercer
T
m
n
> 0
n
ÿ
eu = 1
b
i = 1 
eu
n
n
eu
T ii t ÿ 
i = 
1
eu
,
T
n
m
eu eu
m
sob o capô | 163
h +b
ii t
K t ÿ
De acordo com o teorema de Mercer, se uma função K(a, b) respeita algumas condições 
matemáticas chamadas condições de Mercer (K deve ser contínua, simétrica em seus 
argumentos, então K(a, b) = K(b, a), etc. .), então existe uma função ÿ que mapeia a e b 
em outro espaço (possivelmente com dimensões muito maiores) tal que K(a, b) = ÿ(a) 
ÿ(b). Portanto, você pode usar K como um kernel, pois sabe que ÿ existe, mesmo que não 
saiba o que é ÿ. No caso do kernel Gaussian RBF, pode-se mostrar que ÿ realmente 
mapeia cada instância de treinamento para um espaço de dimensão infinita, então é bom 
que você não precise realmente realizar o mapeamento!
ÿ
= ÿ
= ÿ
·
i T 
· ÿ
· ÿ
Observe que alguns kernels usados com frequência (como o kernel Sigmoid) não respeitam 
todas as condições de Mercer, mas geralmente funcionam bem na prática.
ÿ
+b
· ÿ
ÿ
+b
+ b = ÿ
ÿ
ÿÿ
ÿ
,
·
Se você está começando a ter dor de cabeça, é perfeitamente normal: é um efeito colateral infeliz do truque do 
kernel.
Equação 5-13. Função de custo do classificador SVM linear
Antes de concluir este capítulo, vamos dar uma olhada rápida nos classificadores SVM on-line (lembre-se de que o 
aprendizado on-line significa aprender de forma incremental, geralmente à medida que novas instâncias chegam).
A primeira soma na função de custo levará o modelo a ter um vetor de peso pequeno w, levando a uma margem 
maior. A segunda soma calcula o total de todas as violações de margem. A violação de margem de uma instância 
é igual a 0 se estiver localizada fora da rua e no lado correto, ou então é proporcional à distância atéo lado correto 
da rua. Minimizar este termo garante que o modelo torne as violações de margem tão pequenas quanto possível
Equação 5-12. Calculando o termo de viés usando o truque do kernel
Para classificadores SVM lineares, um método é usar Gradient Descent (por exemplo, usando SGDClassifier) para 
minimizar a função de custo na Equação 5-13, que é derivada do problema primal. Infelizmente, ele converge muito 
mais lentamente do que os métodos baseados em QP.
1
1
Perda de 
dobradiça A função max(0, 1 – t) é chamada de função de perda de dobradiça (representada 
abaixo). É igual a 0 quando t ÿ 1. Sua derivada (inclinação) é igual a –1 se t < 1 e 0 se t > 1. Não 
é diferenciável em t = 1, mas exatamente como para Lasso Regression (consulte “ Lasso 
Regressão” na página 130), você ainda pode usar Gradient Descent usando qualquer subderivada 
em t = 0 (ou seja, qualquer valor entre –1 e 0).
1
+b
· ÿ · ÿ
+ C ÿ
=
=
J , b = 2 ·
i 1 ÿ t
1
i 1 ÿ t
SVMs on-line
164 | Capítulo 5: Máquinas de vetores de suporte
j t ÿ
ÿ
i T 
máx 0, 1 ÿ t i = 1
> 0
ÿ
ns j = 1 
j
> 0
m
m
i T 1 
ÿ t jj ÿ ÿ 
t ÿ j = 1
j K
eu
j
j
euT
ÿ
i = 1 
eu
ÿ > 0
m
eu
> 0
m
i = 1 
eu
m
eu
T
b = 
ns i = 1 
eu
ns
m
Exercícios | 165
1. Qual é a ideia fundamental por trás das Support Vector Machines?
8. Treine um LinearSVC em um conjunto de dados linearmente separável. Em seguida, treine um SVC e um 
SGDClassifier no mesmo conjunto de dados. Veja se você pode fazê-los produzir mais ou menos o mesmo 
modelo.
E uma probabilidade?
problema de classificador SVM linear usando um solucionador QP pronto para uso?
4. Um classificador SVM pode gerar uma pontuação de confiança ao classificar uma instância?
7. Como você deve definir os parâmetros QP (H, f, A e b) para resolver a margem flexível
Também é possível implementar SVMs com kernel online – por exemplo, usando “Incremental and Decremental 
SVM Learning”7 ou “Classificadores de Kernel Rápidos com Aprendizado Online e Ativo.”8 No entanto, eles são 
implementados em Matlab e C++. Para problemas não lineares de grande escala, você pode querer considerar 
o uso de redes neurais (consulte a Parte II).
3. Por que é importante dimensionar as entradas ao usar SVMs?
6. Digamos que você treinou um classificador SVM com um kernel RBF. Parece subajustar o conjunto de 
treinamento: você deve aumentar ou diminuir ÿ (gama)? E o C?
9. Treine um classificador SVM no conjunto de dados MNIST. Como os classificadores SVM são classificadores 
binários, você precisará usar um contra todos para classificar todos os 10 dígitos. Você pode
2. O que é um vetor de suporte?
5. Você deve usar a forma primal ou dual do problema SVM para treinar um modelo em um conjunto de 
treinamento com milhões de instâncias e centenas de recursos?
exercícios
7 "Aprendizagem de Máquina de Vetor de Suporte Incremental e Decremental," G. Cauwenberghs, T. Poggio (2001).
8 “Classificadores rápidos de kernel com aprendizado online e ativo”, A. Bordes, S. Ertekin, J. Weston, L. Bottou (2005).
http://goo.gl/JEqVui
http://goo.gl/JEqVui
https://goo.gl/hsoUHA
https://goo.gl/hsoUHA
deseja ajustar os hiperparâmetros usando pequenos conjuntos de validação para acelerar o processo. 
Que precisão você pode alcançar?
10. Treine um regressor SVM no conjunto de dados habitacionais da Califórnia.
As soluções para esses exercícios estão disponíveis no Apêndice A.
166 | Capítulo 5: Máquinas de vetores de suporte
from sklearn.datasets import load_iris from 
sklearn.tree import DecisionTreeClassifier
iris = load_iris()
tree_clf = DecisionTreeClassifier(max_depth=2) 
tree_clf.fit(X, y)
X = iris.data[:, 2:] # comprimento e largura da pétala y 
= iris.target
167
CAPÍTULO 6
As Árvores de Decisão também são os componentes fundamentais das Florestas Aleatórias (consulte o 
Capítulo 7), que estão entre os mais poderosos algoritmos de Aprendizado de Máquina disponíveis 
atualmente.
Assim como as SVMs, as Árvores de Decisão são algoritmos versáteis de Aprendizado de Máquina que 
podem executar tarefas de classificação e regressão, e até mesmo tarefas de múltiplas saídas. Eles são 
algoritmos muito poderosos, capazes de ajustar conjuntos de dados complexos. Por exemplo, no Capítulo 
2, você treinou um modelo DecisionTreeRegressor no conjunto de dados habitacional da Califórnia, 
ajustando-o perfeitamente (na verdade, superajustando-o).
Neste capítulo, começaremos discutindo como treinar, visualizar e fazer previsões com Árvores de 
Decisão. Em seguida, examinaremos o algoritmo de treinamento CART usado pelo Scikit-Learn e 
discutiremos como regularizar árvores e usá-las para tarefas de regressão. Finalmente, discutiremos 
algumas das limitações das Árvores de Decisão.
Para entender as Árvores de Decisão, vamos apenas construir uma e dar uma olhada em como ela faz 
previsões. O código a seguir treina um DecisionTreeClassifier no conjunto de dados da íris (consulte o 
Capítulo 4):
Treinando e visualizando uma árvore de decisão
Árvores de decisão
1 Graphviz é um pacote de software de visualização de gráficos de código aberto, disponível em http://www.graphviz.org/.
Figura 6-1. Árvore de decisão da íris
Você pode visualizar a Árvore de Decisão treinada usando primeiro o método export_graphviz() para gerar um arquivo de 
definição de gráfico chamado iris_tree.dot:
Em seguida, você pode converter esse arquivo .dot em vários formatos, como PDF ou PNG, usando a ferramenta de linha de 
comando dot do pacote graphviz.1 Essa linha de comando converte o arquivo .dot em um arquivo de imagem .png:
Sua primeira árvore de decisão se parece com a Figura 6-1.
de sklearn.tree import export_graphviz
)
$ ponto -Tpng iris_tree.dot -o iris_tree.png
export_graphviz( tree_clf, 
out_file=image_path("iris_tree.dot"), 
feature_names=iris.feature_names[2:], 
class_names=iris.target_names, 
rounded=Verdadeiro, preenchido=Verdadeiro
168 | Capítulo 6: Árvores de decisão
http://www.graphviz.org/
Uma das muitas qualidades das Árvores de Decisão é que elas requerem muito 
pouca preparação de dados. Em particular, eles não exigem dimensionamento 
ou centralização de recursos.
pi, k
n
Gi = 1 ÿ ÿ k = 1
2
Fazendo previsões
Fazendo previsões | 169
Vamos ver como a árvore representada na Figura 6-1 faz previsões. Suponha que você encontre 
uma flor de íris e queira classificá-la. Você começa no nó raiz (profundidade 0, no topo): este nó 
pergunta se o comprimento da pétala da flor é menor que 2,45 cm. Se for, você move para baixo 
para o nó filho esquerdo da raiz (profundidade 1, esquerda). Neste caso, é um nó folha (ou seja, 
não possui nenhum nó filho), então não faz nenhuma pergunta: você pode simplesmente olhar para 
a classe prevista para aquele nó e a Árvore de Decisão prevê que sua flor é uma Iris-Setosa 
(classe=setosa).
Equação 6-1. Gini impureza
Agora suponha que você encontre outra flor, mas desta vez o comprimento da pétala é maior que 
2,45 cm. Você deve desceraté o nó filho direito da raiz (profundidade 1, direita), que não é um nó 
folha, então ele faz outra pergunta: a largura da pétala é menor que 1,75 cm? Se for, então sua flor 
é provavelmente uma Iris-Versicolor (profundidade 2, à esquerda). Caso contrário, é provável que 
seja uma Iris-Virginica (profundidade 2, à direita). É muito simples.
O atributo samples de um nó conta a quantas instâncias de treinamento ele se aplica. Por exemplo, 
100 instâncias de treinamento têm comprimento de pétala maior que 2,45 cm (profundidade 1, 
direita), entre as quais 54 têm largura de pétala menor que 1,75 cm (profundidade 2, esquerda). O 
atributo de valor de um nó informa a quantas instâncias de treinamento de cada classe esse nó se 
aplica: por exemplo, o nó inferior direito se aplica a 0 Iris-Setosa, 1 Iris Versicolor e 45 Iris-Virginica. 
Finalmente, o atributo gini de um nodo mede sua impureza: um nodo é “puro” (gini=0) se todas as 
instâncias de treinamento às quais ele se aplica pertencem à mesma classe. Por exemplo, como o 
nó esquerdo de profundidade 1 se aplica apenas às instâncias de treinamento Iris-Setosa, ele é 
puro e sua pontuação gini é 0. A Equação 6-1 mostra como o algoritmo de treinamento calcula a 
pontuação gini Gi do i- ésimo nó. Por exemplo, o nodo esquerdo de profundidade 2 tem uma 
pontuação gini igual a 1 – (0/54)2 – (49/54)2 – (5/54)2 ÿ 0,168. Outra medida de impureza é 
discutida em breve.
• pi,k é a razão das instâncias da classe k entre as instâncias de treinamento no i- ésimo nó .
Interpretação do Modelo: Caixa Branca Versus Caixa Preta Como 
você pode ver, as Árvores de Decisão são bastante intuitivas e suas decisões são fáceis de 
interpretar. Esses modelos são freqüentemente chamados de modelos de caixa branca. Em 
contraste, como veremos, Florestas Aleatórias ou redes neurais são geralmente consideradas 
modelos de caixa preta. Eles fazem ótimas previsões e você pode verificar facilmente os cálculos 
que eles realizaram para fazer essas previsões; no entanto, geralmente é difícil explicar em termos 
simples por que as previsões foram feitas. Por exemplo, se uma rede neural diz que uma 
determinada pessoa aparece em uma foto, é difícil saber o que realmente contribuiu para essa 
previsão: o modelo reconheceu os olhos dessa pessoa? A boca dela? O nariz dela? Os sapatos 
dela? Ou até mesmo o sofá em que ela estava sentada? Por outro lado, as Árvores de Decisão 
fornecem regras de classificação agradáveis e simples que podem até ser aplicadas manualmente, 
se necessário (por exemplo, para classificação de flores).
170 | Capítulo 6: Árvores de decisão
O Scikit-Learn usa o algoritmo CART, que produz apenas árvores 
binárias: os nós não-folha sempre têm dois filhos (ou seja, as perguntas 
têm apenas respostas sim/não). Entretanto, outros algoritmos como ID3 
podem produzir Árvores de Decisão com nós que possuem mais de 
dois filhos.
A Figura 6-2 mostra os limites de decisão dessa Árvore de Decisão. A linha vertical grossa 
representa o limite de decisão do nó raiz (profundidade 0): comprimento da pétala = 2,45 cm.
Como a área esquerda é pura (somente Iris-Setosa), ela não pode mais ser dividida. No entanto, a 
área da direita é impura, de modo que o nó direito de profundidade 1 a divide na largura da pétala = 
1,75 cm (representada pela linha tracejada). Como max_depth foi definido como 2, a Árvore de 
Decisão para bem aí. No entanto, se você definir max_depth como 3, os dois nós de profundidade 
2 adicionariam outro limite de decisão (representado pelas linhas pontilhadas).
Figura 6-2. Limites de decisão da árvore de decisão
mesquerda mdireita
Gright
Gleft/right mede a impureza do subconjunto esquerdo/direito, é o número de 
instâncias no subconjunto esquerdo/direito. mesquerda/direita
O Algoritmo de Treinamento CART
Estimando probabilidades de classe
>>> tree_clf.predict_proba([[5, 1.5]]) array([[ 0. , 
0.90740741, 0.09259259]]) >>> tree_clf.predict([[5, 
1.5]]) array([1])
=
m
onde
J k, t k Gleft +m
Estimando probabilidades de classe | 171
Depois de dividir com sucesso o conjunto de treinamento em dois, ele divide os subconjuntos usando 
a mesma lógica, depois os sub-subconjuntos e assim por diante, recursivamente. Ele para de recorrer 
quando atinge a profundidade máxima (definida pelo hiperparâmetro max_depth ) ou se não 
consegue encontrar uma divisão que reduza a impureza. Alguns outros hiperparâmetros (descritos em um
Equação 6-2. Função de custo CART para classificação
Uma Árvore de Decisão também pode estimar a probabilidade de uma instância pertencer a uma 
determinada classe k: primeiro ela percorre a árvore para encontrar o nó folha para esta instância e 
então retorna a razão das instâncias de treinamento da classe k neste nó. Por exemplo, suponha 
que você encontrou uma flor cujas pétalas têm 5 cm de comprimento e 1,5 cm de largura. O nó folha 
correspondente é o nó esquerdo profundidade-2, então a Árvore de Decisão deve produzir as 
seguintes probabilidades: 0% para Iris-Setosa (0/54), 90,7% para Iris-Versicolor (49/54) e 9,3 % para 
Iris-Virginica (5/54). E, claro, se você pedir para prever a classe, ele deve gerar Iris-Versicolor (classe 
1), pois tem a maior probabilidade. Vamos verificar isso:
Perfeito! Observe que as probabilidades estimadas seriam idênticas em qualquer outro lugar no 
retângulo inferior direito da Figura 6-2 - por exemplo, se as pétalas tivessem 6 cm de comprimento e 
1,5 cm de largura (embora pareça óbvio que seria mais provável que fosse uma íris Virgínia neste 
caso).
O Scikit-Learn usa o algoritmo Classification And Regression Tree (CART) para treinar árvores de 
decisão (também chamadas de árvores “em crescimento”). A ideia é bastante simples: o algoritmo 
primeiro divide o conjunto de treinamento em dois subconjuntos usando um único recurso k e um 
limite tk (por exemplo, “comprimento da pétala ÿ 2,45 cm”). Como ele escolhe k e tk ? Ele procura o 
par (k, tk ) que produz os subconjuntos mais puros (ponderados por seu tamanho). A função de custo 
que o algoritmo tenta minimizar é dada pela Equação 6-2.
2 P é o conjunto de problemas que podem ser resolvidos em tempo polinomial. NP é o conjunto de problemas cujas soluções 
podem ser verificadas em tempo polinomial. Um problema NP-Difícil é um problema ao qual qualquer problema NP pode 
ser reduzido em tempo polinomial. Um problema NP-Completo é NP e NP-Difícil. Uma grande questão matemática em 
aberto é se P = NP ou não. Se P ÿ NP (o que parece provável), então nenhum algoritmo polinomial jamais será 
encontrado para qualquer problema NP-Completo (exceto talvez em um computador quântico).
172 | Capítulo 6: Árvores de decisão
Como você pode ver, o algoritmo CART é um algoritmo guloso: ele 
procura avidamente uma divisão ótima no nível superior e repete 
o processo em cada nível. Ele não verifica se a divisão levará ou 
não à menor impureza possível

Mais conteúdos dessa disciplina