parent
089ceaff48
commit
a54c4e5f67
@ -0,0 +1,155 @@
|
||||
# História da aprendizagem automática
|
||||
|
||||

|
||||
> Sketchnote por [Tomomi Imura](https://www.twitter.com/girlie_mac)
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
---
|
||||
|
||||
[](https://youtu.be/N6wxM4wZ7V0 "ML para iniciantes - História da Aprendizagem Automática")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo curto sobre esta lição.
|
||||
|
||||
Nesta lição, vamos explorar os principais marcos na história da aprendizagem automática e da inteligência artificial.
|
||||
|
||||
A história da inteligência artificial (IA) como campo está entrelaçada com a história da aprendizagem automática, já que os algoritmos e avanços computacionais que sustentam a aprendizagem automática contribuíram para o desenvolvimento da IA. É útil lembrar que, embora esses campos como áreas distintas de investigação tenham começado a se cristalizar na década de 1950, importantes [descobertas algorítmicas, estatísticas, matemáticas, computacionais e técnicas](https://wikipedia.org/wiki/Timeline_of_machine_learning) precederam e se sobrepuseram a essa era. Na verdade, as pessoas têm pensado sobre essas questões há [centenas de anos](https://wikipedia.org/wiki/History_of_artificial_intelligence): este artigo discute os fundamentos intelectuais históricos da ideia de uma 'máquina pensante'.
|
||||
|
||||
---
|
||||
## Descobertas notáveis
|
||||
|
||||
- 1763, 1812 [Teorema de Bayes](https://wikipedia.org/wiki/Bayes%27_theorem) e seus predecessores. Este teorema e suas aplicações fundamentam a inferência, descrevendo a probabilidade de um evento ocorrer com base em conhecimento prévio.
|
||||
- 1805 [Teoria dos Mínimos Quadrados](https://wikipedia.org/wiki/Least_squares) pelo matemático francês Adrien-Marie Legendre. Esta teoria, que você aprenderá na nossa unidade de Regressão, ajuda no ajuste de dados.
|
||||
- 1913 [Cadeias de Markov](https://wikipedia.org/wiki/Markov_chain), nomeadas em homenagem ao matemático russo Andrey Markov, são usadas para descrever uma sequência de eventos possíveis com base em um estado anterior.
|
||||
- 1957 [Perceptron](https://wikipedia.org/wiki/Perceptron) é um tipo de classificador linear inventado pelo psicólogo americano Frank Rosenblatt que fundamenta avanços em aprendizagem profunda.
|
||||
|
||||
---
|
||||
|
||||
- 1967 [Vizinho Mais Próximo](https://wikipedia.org/wiki/Nearest_neighbor) é um algoritmo originalmente projetado para mapear rotas. No contexto de aprendizagem automática, é usado para detectar padrões.
|
||||
- 1970 [Retropropagação](https://wikipedia.org/wiki/Backpropagation) é usada para treinar [redes neurais feedforward](https://wikipedia.org/wiki/Feedforward_neural_network).
|
||||
- 1982 [Redes Neurais Recorrentes](https://wikipedia.org/wiki/Recurrent_neural_network) são redes neurais artificiais derivadas de redes neurais feedforward que criam gráficos temporais.
|
||||
|
||||
✅ Faça uma pequena pesquisa. Quais outras datas se destacam como marcos na história da aprendizagem automática e da IA?
|
||||
|
||||
---
|
||||
## 1950: Máquinas que pensam
|
||||
|
||||
Alan Turing, uma pessoa verdadeiramente notável que foi eleito [pelo público em 2019](https://wikipedia.org/wiki/Icons:_The_Greatest_Person_of_the_20th_Century) como o maior cientista do século XX, é creditado por ajudar a estabelecer as bases para o conceito de uma 'máquina que pode pensar'. Ele enfrentou críticos e sua própria necessidade de evidências empíricas desse conceito, em parte criando o [Teste de Turing](https://www.bbc.com/news/technology-18475646), que você explorará nas nossas lições de PNL.
|
||||
|
||||
---
|
||||
## 1956: Projeto de Pesquisa de Verão em Dartmouth
|
||||
|
||||
"O Projeto de Pesquisa de Verão em Dartmouth sobre inteligência artificial foi um evento seminal para a inteligência artificial como campo", e foi aqui que o termo 'inteligência artificial' foi cunhado ([fonte](https://250.dartmouth.edu/highlights/artificial-intelligence-ai-coined-dartmouth)).
|
||||
|
||||
> Todo aspecto de aprendizagem ou qualquer outra característica da inteligência pode, em princípio, ser descrito tão precisamente que uma máquina pode ser feita para simulá-lo.
|
||||
|
||||
---
|
||||
|
||||
O pesquisador principal, professor de matemática John McCarthy, esperava "prosseguir com base na conjectura de que todo aspecto de aprendizagem ou qualquer outra característica da inteligência pode, em princípio, ser descrito tão precisamente que uma máquina pode ser feita para simulá-lo." Os participantes incluíram outro luminar na área, Marvin Minsky.
|
||||
|
||||
O workshop é creditado por ter iniciado e incentivado várias discussões, incluindo "a ascensão de métodos simbólicos, sistemas focados em domínios limitados (primeiros sistemas especialistas) e sistemas dedutivos versus sistemas indutivos." ([fonte](https://wikipedia.org/wiki/Dartmouth_workshop)).
|
||||
|
||||
---
|
||||
## 1956 - 1974: "Os anos dourados"
|
||||
|
||||
Dos anos 1950 até meados dos anos 70, o otimismo era alto na esperança de que a IA pudesse resolver muitos problemas. Em 1967, Marvin Minsky afirmou confiantemente que "Dentro de uma geração ... o problema de criar 'inteligência artificial' será substancialmente resolvido." (Minsky, Marvin (1967), Computation: Finite and Infinite Machines, Englewood Cliffs, N.J.: Prentice-Hall)
|
||||
|
||||
A pesquisa em processamento de linguagem natural floresceu, a busca foi refinada e tornou-se mais poderosa, e o conceito de 'micro-mundos' foi criado, onde tarefas simples eram realizadas usando instruções em linguagem simples.
|
||||
|
||||
---
|
||||
|
||||
A pesquisa foi bem financiada por agências governamentais, avanços foram feitos em computação e algoritmos, e protótipos de máquinas inteligentes foram construídos. Algumas dessas máquinas incluem:
|
||||
|
||||
* [Shakey o robô](https://wikipedia.org/wiki/Shakey_the_robot), que podia se movimentar e decidir como realizar tarefas 'inteligentemente'.
|
||||
|
||||

|
||||
> Shakey em 1972
|
||||
|
||||
---
|
||||
|
||||
* Eliza, um dos primeiros 'chatterbots', podia conversar com pessoas e agir como um 'terapeuta' primitivo. Você aprenderá mais sobre Eliza nas lições de PNL.
|
||||
|
||||

|
||||
> Uma versão de Eliza, um chatbot
|
||||
|
||||
---
|
||||
|
||||
* "Blocks world" foi um exemplo de micro-mundo onde blocos podiam ser empilhados e organizados, e experimentos em ensinar máquinas a tomar decisões podiam ser testados. Avanços construídos com bibliotecas como [SHRDLU](https://wikipedia.org/wiki/SHRDLU) ajudaram a impulsionar o processamento de linguagem.
|
||||
|
||||
[](https://www.youtube.com/watch?v=QAJz4YKUwqw "blocks world com SHRDLU")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo: Blocks world com SHRDLU
|
||||
|
||||
---
|
||||
## 1974 - 1980: "Inverno da IA"
|
||||
|
||||
Por volta de meados dos anos 1970, tornou-se evidente que a complexidade de criar 'máquinas inteligentes' havia sido subestimada e que sua promessa, dada a potência computacional disponível, havia sido exagerada. O financiamento secou e a confiança na área diminuiu. Alguns problemas que impactaram a confiança incluíram:
|
||||
---
|
||||
- **Limitações**. A potência computacional era muito limitada.
|
||||
- **Explosão combinatória**. A quantidade de parâmetros necessários para treinar cresceu exponencialmente à medida que mais era exigido dos computadores, sem uma evolução paralela da potência e capacidade computacional.
|
||||
- **Escassez de dados**. Havia uma escassez de dados que dificultava o processo de testar, desenvolver e refinar algoritmos.
|
||||
- **Estamos fazendo as perguntas certas?**. As próprias perguntas que estavam sendo feitas começaram a ser questionadas. Pesquisadores começaram a enfrentar críticas sobre suas abordagens:
|
||||
- Os testes de Turing foram questionados por meio, entre outras ideias, da 'teoria da sala chinesa', que postulava que, "programar um computador digital pode fazê-lo parecer entender a linguagem, mas não poderia produzir compreensão real." ([fonte](https://plato.stanford.edu/entries/chinese-room/))
|
||||
- A ética de introduzir inteligências artificiais como o "terapeuta" ELIZA na sociedade foi desafiada.
|
||||
|
||||
---
|
||||
|
||||
Ao mesmo tempo, várias escolas de pensamento sobre IA começaram a se formar. Uma dicotomia foi estabelecida entre práticas de ["IA desleixada" vs. "IA organizada"](https://wikipedia.org/wiki/Neats_and_scruffies). Laboratórios _desleixados_ ajustavam programas por horas até obterem os resultados desejados. Laboratórios _organizados_ "focavam em lógica e resolução formal de problemas". ELIZA e SHRDLU eram sistemas _desleixados_ bem conhecidos. Nos anos 1980, à medida que surgia a demanda por tornar os sistemas de aprendizagem automática reproduzíveis, a abordagem _organizada_ gradualmente tomou a dianteira, pois seus resultados são mais explicáveis.
|
||||
|
||||
---
|
||||
## Sistemas especialistas nos anos 1980
|
||||
|
||||
À medida que a área crescia, seus benefícios para os negócios tornaram-se mais claros, e nos anos 1980 também ocorreu a proliferação de 'sistemas especialistas'. "Os sistemas especialistas estavam entre as primeiras formas verdadeiramente bem-sucedidas de software de inteligência artificial (IA)." ([fonte](https://wikipedia.org/wiki/Expert_system)).
|
||||
|
||||
Este tipo de sistema é na verdade _híbrido_, consistindo parcialmente de um motor de regras que define os requisitos de negócios e um motor de inferência que utiliza o sistema de regras para deduzir novos fatos.
|
||||
|
||||
Esta era também viu uma atenção crescente às redes neurais.
|
||||
|
||||
---
|
||||
## 1987 - 1993: "Resfriamento da IA"
|
||||
|
||||
A proliferação de hardware especializado para sistemas especialistas teve o efeito infeliz de se tornar muito especializado. O surgimento dos computadores pessoais também competiu com esses sistemas grandes, especializados e centralizados. A democratização da computação havia começado, e isso eventualmente abriu caminho para a explosão moderna de big data.
|
||||
|
||||
---
|
||||
## 1993 - 2011
|
||||
|
||||
Este período viu uma nova era para a aprendizagem automática e a IA resolverem alguns dos problemas causados anteriormente pela falta de dados e potência computacional. A quantidade de dados começou a aumentar rapidamente e a se tornar mais amplamente disponível, para o bem e para o mal, especialmente com o advento do smartphone por volta de 2007. A potência computacional expandiu-se exponencialmente, e os algoritmos evoluíram junto. A área começou a ganhar maturidade à medida que os dias livres do passado começaram a se cristalizar em uma verdadeira disciplina.
|
||||
|
||||
---
|
||||
## Hoje
|
||||
|
||||
Hoje, a aprendizagem automática e a IA tocam quase todas as partes de nossas vidas. Esta era exige uma compreensão cuidadosa dos riscos e dos potenciais efeitos desses algoritmos na vida humana. Como Brad Smith, da Microsoft, afirmou: "A tecnologia da informação levanta questões que vão ao cerne das proteções fundamentais dos direitos humanos, como privacidade e liberdade de expressão. Essas questões aumentam a responsabilidade das empresas de tecnologia que criam esses produtos. Em nossa visão, elas também exigem uma regulamentação governamental cuidadosa e o desenvolvimento de normas sobre usos aceitáveis" ([fonte](https://www.technologyreview.com/2019/12/18/102365/the-future-of-ais-impact-on-society/)).
|
||||
|
||||
---
|
||||
|
||||
Ainda não se sabe o que o futuro reserva, mas é importante entender esses sistemas computacionais e o software e os algoritmos que eles executam. Esperamos que este currículo o ajude a obter uma melhor compreensão para que você possa decidir por si mesmo.
|
||||
|
||||
[](https://www.youtube.com/watch?v=mTtDfKgLm54 "A história da aprendizagem profunda")
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo: Yann LeCun discute a história da aprendizagem profunda nesta palestra
|
||||
|
||||
---
|
||||
## 🚀Desafio
|
||||
|
||||
Aprofunde-se em um desses momentos históricos e aprenda mais sobre as pessoas por trás deles. Há personagens fascinantes, e nenhuma descoberta científica foi criada em um vácuo cultural. O que você descobre?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
---
|
||||
## Revisão e Estudo Individual
|
||||
|
||||
Aqui estão itens para assistir e ouvir:
|
||||
|
||||
[Este podcast onde Amy Boyd discute a evolução da IA](http://runasradio.com/Shows/Show/739)
|
||||
|
||||
[](https://www.youtube.com/watch?v=EJt3_bFYKss "A história da IA por Amy Boyd")
|
||||
|
||||
---
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Criar uma linha do tempo](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Criar uma linha do tempo
|
||||
|
||||
## Instruções
|
||||
|
||||
Usando [este repositório](https://github.com/Digital-Humanities-Toolkit/timeline-builder), crie uma linha do tempo sobre algum aspecto da história dos algoritmos, matemática, estatística, IA ou ML, ou uma combinação destes. Pode focar numa pessoa, numa ideia ou num longo período de pensamento. Certifique-se de adicionar elementos multimédia.
|
||||
|
||||
## Critérios de Avaliação
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| --------- | ------------------------------------------------ | --------------------------------------- | ---------------------------------------------------------------- |
|
||||
| | Uma linha do tempo publicada é apresentada como uma página no GitHub | O código está incompleto e não foi publicado | A linha do tempo está incompleta, pouco pesquisada e não foi publicada |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Explore a Caixa de Ferramentas de IA Responsável
|
||||
|
||||
## Instruções
|
||||
|
||||
Nesta lição, aprendeu sobre a Caixa de Ferramentas de IA Responsável, um "projeto de código aberto e orientado pela comunidade para ajudar cientistas de dados a analisar e melhorar sistemas de IA." Para esta tarefa, explore um dos [notebooks](https://github.com/microsoft/responsible-ai-toolbox/blob/main/notebooks/responsibleaidashboard/getting-started.ipynb) da RAI Toolbox e relate as suas descobertas num artigo ou apresentação.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| --------- | --------- | -------- | ----------------------- |
|
||||
| | Um artigo ou apresentação em PowerPoint é apresentado discutindo os sistemas do Fairlearn, o notebook que foi executado e as conclusões obtidas a partir da sua execução | Um artigo é apresentado sem conclusões | Nenhum artigo é apresentado |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,123 @@
|
||||
# Técnicas de Aprendizagem Automática
|
||||
|
||||
O processo de construir, utilizar e manter modelos de aprendizagem automática e os dados que eles utilizam é muito diferente de muitos outros fluxos de trabalho de desenvolvimento. Nesta lição, vamos desmistificar o processo e delinear as principais técnicas que precisa conhecer. Você irá:
|
||||
|
||||
- Compreender os processos que sustentam a aprendizagem automática a um nível elevado.
|
||||
- Explorar conceitos básicos como 'modelos', 'previsões' e 'dados de treino'.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
[](https://youtu.be/4NGM0U2ZSHU "ML para iniciantes - Técnicas de Aprendizagem Automática")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo curto sobre esta lição.
|
||||
|
||||
## Introdução
|
||||
|
||||
De forma geral, o processo de criação de processos de aprendizagem automática (ML) é composto por várias etapas:
|
||||
|
||||
1. **Definir a pergunta**. A maioria dos processos de ML começa com uma pergunta que não pode ser respondida por um programa condicional simples ou um motor baseado em regras. Estas perguntas geralmente giram em torno de previsões baseadas numa coleção de dados.
|
||||
2. **Recolher e preparar os dados**. Para responder à sua pergunta, precisa de dados. A qualidade e, por vezes, a quantidade dos seus dados determinarão o quão bem pode responder à pergunta inicial. Visualizar os dados é um aspeto importante desta fase. Esta fase também inclui dividir os dados em grupos de treino e teste para construir um modelo.
|
||||
3. **Escolher um método de treino**. Dependendo da sua pergunta e da natureza dos seus dados, precisa de escolher como deseja treinar um modelo para refletir melhor os seus dados e fazer previsões precisas. Esta é a parte do processo de ML que requer conhecimentos específicos e, muitas vezes, uma quantidade considerável de experimentação.
|
||||
4. **Treinar o modelo**. Usando os seus dados de treino, utilizará vários algoritmos para treinar um modelo que reconheça padrões nos dados. O modelo pode usar pesos internos que podem ser ajustados para privilegiar certas partes dos dados em detrimento de outras, a fim de construir um modelo melhor.
|
||||
5. **Avaliar o modelo**. Utiliza dados nunca antes vistos (os seus dados de teste) do conjunto recolhido para verificar o desempenho do modelo.
|
||||
6. **Ajustar parâmetros**. Com base no desempenho do modelo, pode refazer o processo utilizando diferentes parâmetros ou variáveis que controlam o comportamento dos algoritmos usados para treinar o modelo.
|
||||
7. **Prever**. Use novos dados de entrada para testar a precisão do modelo.
|
||||
|
||||
## Que pergunta fazer
|
||||
|
||||
Os computadores são particularmente habilidosos em descobrir padrões ocultos nos dados. Esta capacidade é muito útil para investigadores que têm perguntas sobre um determinado domínio que não podem ser facilmente respondidas criando um motor de regras condicionais. Dada uma tarefa atuarial, por exemplo, um cientista de dados pode ser capaz de construir regras manuais sobre a mortalidade de fumadores versus não fumadores.
|
||||
|
||||
Quando muitas outras variáveis são introduzidas na equação, no entanto, um modelo de ML pode revelar-se mais eficiente para prever taxas de mortalidade futuras com base no histórico de saúde passado. Um exemplo mais animador pode ser fazer previsões meteorológicas para o mês de abril numa determinada localização com base em dados que incluem latitude, longitude, alterações climáticas, proximidade ao oceano, padrões da corrente de jato, entre outros.
|
||||
|
||||
✅ Este [conjunto de slides](https://www2.cisl.ucar.edu/sites/default/files/2021-10/0900%20June%2024%20Haupt_0.pdf) sobre modelos meteorológicos oferece uma perspetiva histórica sobre o uso de ML na análise do clima.
|
||||
|
||||
## Tarefas pré-construção
|
||||
|
||||
Antes de começar a construir o seu modelo, há várias tarefas que precisa de completar. Para testar a sua pergunta e formar uma hipótese com base nas previsões de um modelo, precisa de identificar e configurar vários elementos.
|
||||
|
||||
### Dados
|
||||
|
||||
Para responder à sua pergunta com algum grau de certeza, precisa de uma boa quantidade de dados do tipo certo. Há duas coisas que precisa de fazer neste momento:
|
||||
|
||||
- **Recolher dados**. Tendo em mente a lição anterior sobre justiça na análise de dados, recolha os seus dados com cuidado. Esteja atento às fontes desses dados, a quaisquer preconceitos inerentes que possam ter e documente a sua origem.
|
||||
- **Preparar dados**. Há vários passos no processo de preparação de dados. Pode ser necessário reunir dados e normalizá-los se vierem de fontes diversas. Pode melhorar a qualidade e a quantidade dos dados através de vários métodos, como converter strings em números (como fazemos em [Clustering](../../5-Clustering/1-Visualize/README.md)). Também pode gerar novos dados com base nos originais (como fazemos em [Classificação](../../4-Classification/1-Introduction/README.md)). Pode limpar e editar os dados (como faremos antes da lição sobre [Aplicações Web](../../3-Web-App/README.md)). Por fim, pode ser necessário randomizar e embaralhar os dados, dependendo das suas técnicas de treino.
|
||||
|
||||
✅ Após recolher e processar os seus dados, reserve um momento para verificar se a sua estrutura permitirá abordar a pergunta pretendida. Pode ser que os dados não funcionem bem na sua tarefa, como descobrimos nas nossas lições de [Clustering](../../5-Clustering/1-Visualize/README.md)!
|
||||
|
||||
### Features e Target
|
||||
|
||||
Uma [feature](https://www.datasciencecentral.com/profiles/blogs/an-introduction-to-variable-and-feature-selection) é uma propriedade mensurável dos seus dados. Em muitos conjuntos de dados, é expressa como um cabeçalho de coluna, como 'data', 'tamanho' ou 'cor'. A sua variável de feature, geralmente representada como `X` no código, representa a variável de entrada que será usada para treinar o modelo.
|
||||
|
||||
Um target é aquilo que está a tentar prever. O target, geralmente representado como `y` no código, representa a resposta à pergunta que está a tentar fazer aos seus dados: em dezembro, qual será a **cor** das abóboras mais baratas? Em São Francisco, que bairros terão o melhor **preço** imobiliário? Às vezes, o target também é referido como atributo de rótulo.
|
||||
|
||||
### Selecionar a sua variável de feature
|
||||
|
||||
🎓 **Seleção de Features e Extração de Features** Como saber qual variável escolher ao construir um modelo? Provavelmente passará por um processo de seleção de features ou extração de features para escolher as variáveis certas para o modelo mais eficiente. No entanto, não são a mesma coisa: "A extração de features cria novas features a partir de funções das features originais, enquanto a seleção de features retorna um subconjunto das features." ([fonte](https://wikipedia.org/wiki/Feature_selection))
|
||||
|
||||
### Visualizar os seus dados
|
||||
|
||||
Um aspeto importante do conjunto de ferramentas de um cientista de dados é a capacidade de visualizar dados usando várias bibliotecas excelentes, como Seaborn ou MatPlotLib. Representar os seus dados visualmente pode permitir-lhe descobrir correlações ocultas que pode aproveitar. As suas visualizações também podem ajudá-lo a identificar preconceitos ou dados desequilibrados (como descobrimos em [Classificação](../../4-Classification/2-Classifiers-1/README.md)).
|
||||
|
||||
### Dividir o seu conjunto de dados
|
||||
|
||||
Antes de treinar, precisa de dividir o seu conjunto de dados em duas ou mais partes de tamanhos desiguais que ainda representem bem os dados.
|
||||
|
||||
- **Treino**. Esta parte do conjunto de dados é ajustada ao seu modelo para treiná-lo. Este conjunto constitui a maior parte do conjunto de dados original.
|
||||
- **Teste**. Um conjunto de teste é um grupo independente de dados, muitas vezes retirado dos dados originais, que utiliza para confirmar o desempenho do modelo construído.
|
||||
- **Validação**. Um conjunto de validação é um grupo independente menor de exemplos que utiliza para ajustar os hiperparâmetros ou a arquitetura do modelo, a fim de melhorá-lo. Dependendo do tamanho dos seus dados e da pergunta que está a fazer, pode não ser necessário construir este terceiro conjunto (como notamos em [Previsão de Séries Temporais](../../7-TimeSeries/1-Introduction/README.md)).
|
||||
|
||||
## Construir um modelo
|
||||
|
||||
Usando os seus dados de treino, o seu objetivo é construir um modelo, ou uma representação estatística dos seus dados, utilizando vários algoritmos para **treiná-lo**. Treinar um modelo expõe-no aos dados e permite-lhe fazer suposições sobre padrões percebidos que descobre, valida e aceita ou rejeita.
|
||||
|
||||
### Decidir sobre um método de treino
|
||||
|
||||
Dependendo da sua pergunta e da natureza dos seus dados, escolherá um método para treiná-lo. Explorando a [documentação do Scikit-learn](https://scikit-learn.org/stable/user_guide.html) - que usamos neste curso - pode descobrir várias formas de treinar um modelo. Dependendo da sua experiência, pode ter de experimentar vários métodos diferentes para construir o melhor modelo. É provável que passe por um processo em que os cientistas de dados avaliam o desempenho de um modelo alimentando-o com dados não vistos, verificando a precisão, preconceitos e outros problemas que degradam a qualidade, e selecionando o método de treino mais apropriado para a tarefa em questão.
|
||||
|
||||
### Treinar um modelo
|
||||
|
||||
Com os seus dados de treino, está pronto para 'ajustá-los' para criar um modelo. Notará que em muitas bibliotecas de ML encontrará o código 'model.fit' - é neste momento que envia a sua variável de feature como um array de valores (geralmente 'X') e uma variável target (geralmente 'y').
|
||||
|
||||
### Avaliar o modelo
|
||||
|
||||
Uma vez concluído o processo de treino (pode levar muitas iterações, ou 'épocas', para treinar um modelo grande), poderá avaliar a qualidade do modelo utilizando dados de teste para medir o seu desempenho. Estes dados são um subconjunto dos dados originais que o modelo ainda não analisou. Pode imprimir uma tabela de métricas sobre a qualidade do modelo.
|
||||
|
||||
🎓 **Ajuste do modelo**
|
||||
|
||||
No contexto da aprendizagem automática, o ajuste do modelo refere-se à precisão da função subjacente do modelo enquanto tenta analisar dados com os quais não está familiarizado.
|
||||
|
||||
🎓 **Subajuste** e **sobreajuste** são problemas comuns que degradam a qualidade do modelo, pois o modelo ajusta-se ou não suficientemente bem ou bem demais. Isso faz com que o modelo faça previsões muito alinhadas ou pouco alinhadas com os seus dados de treino. Um modelo sobreajustado prevê os dados de treino muito bem porque aprendeu os detalhes e o ruído dos dados em excesso. Um modelo subajustado não é preciso, pois não consegue analisar com precisão nem os dados de treino nem os dados que ainda não 'viu'.
|
||||
|
||||

|
||||
> Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
## Ajuste de parâmetros
|
||||
|
||||
Depois de concluir o treino inicial, observe a qualidade do modelo e considere melhorá-lo ajustando os seus 'hiperparâmetros'. Leia mais sobre o processo [na documentação](https://docs.microsoft.com/en-us/azure/machine-learning/how-to-tune-hyperparameters?WT.mc_id=academic-77952-leestott).
|
||||
|
||||
## Previsão
|
||||
|
||||
Este é o momento em que pode usar dados completamente novos para testar a precisão do seu modelo. Num cenário de ML 'aplicado', onde está a construir ativos web para usar o modelo em produção, este processo pode envolver a recolha de input do utilizador (um clique num botão, por exemplo) para definir uma variável e enviá-la ao modelo para inferência ou avaliação.
|
||||
|
||||
Nestes módulos, descobrirá como usar estes passos para preparar, construir, testar, avaliar e prever - todos os gestos de um cientista de dados e mais, à medida que progride na sua jornada para se tornar um engenheiro de ML 'full stack'.
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Desenhe um fluxograma refletindo os passos de um praticante de ML. Onde se encontra neste momento no processo? Onde prevê que encontrará dificuldades? O que lhe parece fácil?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão e Estudo Individual
|
||||
|
||||
Pesquise online entrevistas com cientistas de dados que discutam o seu trabalho diário. Aqui está [uma](https://www.youtube.com/watch?v=Z3IjgbbCEfs).
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Entrevistar um cientista de dados](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Entrevistar um cientista de dados
|
||||
|
||||
## Instruções
|
||||
|
||||
Na sua empresa, num grupo de utilizadores, ou entre os seus amigos ou colegas de estudo, converse com alguém que trabalhe profissionalmente como cientista de dados. Escreva um pequeno artigo (500 palavras) sobre as suas ocupações diárias. São especialistas ou trabalham de forma 'full stack'?
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| --------- | ----------------------------------------------------------------------------------- | ----------------------------------------------------------------- | ----------------------- |
|
||||
| | Um artigo com o comprimento correto, com fontes atribuídas, apresentado como um ficheiro .doc | O artigo tem atribuições inadequadas ou é mais curto do que o comprimento exigido | Nenhum artigo é apresentado |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,28 @@
|
||||
# Introdução ao aprendizado de máquina
|
||||
|
||||
Nesta seção do currículo, será apresentada uma introdução aos conceitos básicos que fundamentam o campo do aprendizado de máquina, o que ele é, além de aprender sobre sua história e as técnicas que os pesquisadores utilizam para trabalhar com ele. Vamos explorar juntos este novo mundo do aprendizado de máquina!
|
||||
|
||||

|
||||
> Foto por <a href="https://unsplash.com/@bill_oxford?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Bill Oxford</a> no <a href="https://unsplash.com/s/photos/globe?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||
|
||||
### Aulas
|
||||
|
||||
1. [Introdução ao aprendizado de máquina](1-intro-to-ML/README.md)
|
||||
1. [A história do aprendizado de máquina e da IA](2-history-of-ML/README.md)
|
||||
1. [Justiça e aprendizado de máquina](3-fairness/README.md)
|
||||
1. [Técnicas de aprendizado de máquina](4-techniques-of-ML/README.md)
|
||||
|
||||
### Créditos
|
||||
|
||||
"Introdução ao Aprendizado de Máquina" foi escrito com ♥️ por uma equipe de pessoas incluindo [Muhammad Sakib Khan Inan](https://twitter.com/Sakibinan), [Ornella Altunyan](https://twitter.com/ornelladotcom) e [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
"A História do Aprendizado de Máquina" foi escrito com ♥️ por [Jen Looper](https://twitter.com/jenlooper) e [Amy Boyd](https://twitter.com/AmyKateNicho)
|
||||
|
||||
"Justiça e Aprendizado de Máquina" foi escrito com ♥️ por [Tomomi Imura](https://twitter.com/girliemac)
|
||||
|
||||
"Técnicas de Aprendizado de Máquina" foi escrito com ♥️ por [Jen Looper](https://twitter.com/jenlooper) e [Chris Noring](https://twitter.com/softchris)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,230 @@
|
||||
# Introdução ao Python e Scikit-learn para modelos de regressão
|
||||
|
||||

|
||||
|
||||
> Sketchnote por [Tomomi Imura](https://www.twitter.com/girlie_mac)
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
> ### [Esta lição está disponível em R!](../../../../2-Regression/1-Tools/solution/R/lesson_1.html)
|
||||
|
||||
## Introdução
|
||||
|
||||
Nestes quatro módulos, irá aprender a construir modelos de regressão. Vamos discutir brevemente para que servem. Mas antes de começar, certifique-se de que tem as ferramentas certas para iniciar o processo!
|
||||
|
||||
Nesta lição, irá aprender a:
|
||||
|
||||
- Configurar o seu computador para tarefas locais de machine learning.
|
||||
- Trabalhar com Jupyter notebooks.
|
||||
- Utilizar Scikit-learn, incluindo a instalação.
|
||||
- Explorar regressão linear com um exercício prático.
|
||||
|
||||
## Instalações e configurações
|
||||
|
||||
[](https://youtu.be/-DfeD2k2Kj0 "ML para iniciantes - Configure as suas ferramentas para criar modelos de Machine Learning")
|
||||
|
||||
> 🎥 Clique na imagem acima para um vídeo curto sobre como configurar o seu computador para ML.
|
||||
|
||||
1. **Instale o Python**. Certifique-se de que o [Python](https://www.python.org/downloads/) está instalado no seu computador. Irá utilizar Python para muitas tarefas de ciência de dados e machine learning. A maioria dos sistemas já inclui uma instalação do Python. Existem também [Pacotes de Codificação Python](https://code.visualstudio.com/learn/educators/installers?WT.mc_id=academic-77952-leestott) úteis para facilitar a configuração para alguns utilizadores.
|
||||
|
||||
No entanto, algumas utilizações do Python requerem uma versão específica do software. Por isso, é útil trabalhar num [ambiente virtual](https://docs.python.org/3/library/venv.html).
|
||||
|
||||
2. **Instale o Visual Studio Code**. Certifique-se de que tem o Visual Studio Code instalado no seu computador. Siga estas instruções para [instalar o Visual Studio Code](https://code.visualstudio.com/) para uma instalação básica. Vai utilizar Python no Visual Studio Code neste curso, por isso pode ser útil rever como [configurar o Visual Studio Code](https://docs.microsoft.com/learn/modules/python-install-vscode?WT.mc_id=academic-77952-leestott) para desenvolvimento em Python.
|
||||
|
||||
> Familiarize-se com Python ao explorar esta coleção de [módulos de aprendizagem](https://docs.microsoft.com/users/jenlooper-2911/collections/mp1pagggd5qrq7?WT.mc_id=academic-77952-leestott)
|
||||
>
|
||||
> [](https://youtu.be/yyQM70vi7V8 "Configurar Python com Visual Studio Code")
|
||||
>
|
||||
> 🎥 Clique na imagem acima para um vídeo: usar Python no VS Code.
|
||||
|
||||
3. **Instale o Scikit-learn**, seguindo [estas instruções](https://scikit-learn.org/stable/install.html). Como precisa de garantir que utiliza Python 3, é recomendado que use um ambiente virtual. Note que, se estiver a instalar esta biblioteca num Mac com M1, existem instruções específicas na página acima.
|
||||
|
||||
4. **Instale o Jupyter Notebook**. Será necessário [instalar o pacote Jupyter](https://pypi.org/project/jupyter/).
|
||||
|
||||
## O seu ambiente de desenvolvimento para ML
|
||||
|
||||
Irá utilizar **notebooks** para desenvolver o seu código Python e criar modelos de machine learning. Este tipo de ficheiro é uma ferramenta comum para cientistas de dados e pode ser identificado pela extensão `.ipynb`.
|
||||
|
||||
Os notebooks são um ambiente interativo que permite ao programador tanto codificar como adicionar notas e escrever documentação em torno do código, o que é bastante útil para projetos experimentais ou de pesquisa.
|
||||
|
||||
[](https://youtu.be/7E-jC8FLA2E "ML para iniciantes - Configurar Jupyter Notebooks para começar a criar modelos de regressão")
|
||||
|
||||
> 🎥 Clique na imagem acima para um vídeo curto sobre este exercício.
|
||||
|
||||
### Exercício - trabalhar com um notebook
|
||||
|
||||
Nesta pasta, encontrará o ficheiro _notebook.ipynb_.
|
||||
|
||||
1. Abra o _notebook.ipynb_ no Visual Studio Code.
|
||||
|
||||
Um servidor Jupyter será iniciado com Python 3+. Encontrará áreas do notebook que podem ser `executadas`, ou seja, blocos de código. Pode executar um bloco de código selecionando o ícone que parece um botão de reprodução.
|
||||
|
||||
2. Selecione o ícone `md` e adicione um pouco de markdown com o seguinte texto: **# Bem-vindo ao seu notebook**.
|
||||
|
||||
Em seguida, adicione algum código Python.
|
||||
|
||||
3. Escreva **print('hello notebook')** no bloco de código.
|
||||
4. Selecione a seta para executar o código.
|
||||
|
||||
Deverá ver a seguinte saída:
|
||||
|
||||
```output
|
||||
hello notebook
|
||||
```
|
||||
|
||||

|
||||
|
||||
Pode intercalar o seu código com comentários para auto-documentar o notebook.
|
||||
|
||||
✅ Pense por um momento como o ambiente de trabalho de um programador web é diferente do de um cientista de dados.
|
||||
|
||||
## Começar com Scikit-learn
|
||||
|
||||
Agora que o Python está configurado no seu ambiente local e está confortável com Jupyter notebooks, vamos ficar igualmente confortáveis com o Scikit-learn (pronuncia-se `sci` como em `science`). O Scikit-learn fornece uma [API extensa](https://scikit-learn.org/stable/modules/classes.html#api-ref) para ajudá-lo a realizar tarefas de ML.
|
||||
|
||||
De acordo com o [site oficial](https://scikit-learn.org/stable/getting_started.html), "Scikit-learn é uma biblioteca de machine learning de código aberto que suporta aprendizagem supervisionada e não supervisionada. Também fornece várias ferramentas para ajuste de modelos, pré-processamento de dados, seleção e avaliação de modelos, entre outras utilidades."
|
||||
|
||||
Neste curso, irá utilizar Scikit-learn e outras ferramentas para construir modelos de machine learning para realizar o que chamamos de tarefas de 'machine learning tradicional'. Evitamos deliberadamente redes neurais e deep learning, pois estes tópicos serão abordados no nosso futuro currículo 'AI for Beginners'.
|
||||
|
||||
O Scikit-learn torna simples a construção e avaliação de modelos para uso. Ele é focado principalmente no uso de dados numéricos e contém vários conjuntos de dados prontos para uso como ferramentas de aprendizagem. Também inclui modelos pré-construídos para os alunos experimentarem. Vamos explorar o processo de carregar dados pré-embalados e usar um estimador para o primeiro modelo de ML com Scikit-learn com alguns dados básicos.
|
||||
|
||||
## Exercício - o seu primeiro notebook com Scikit-learn
|
||||
|
||||
> Este tutorial foi inspirado pelo [exemplo de regressão linear](https://scikit-learn.org/stable/auto_examples/linear_model/plot_ols.html#sphx-glr-auto-examples-linear-model-plot-ols-py) no site do Scikit-learn.
|
||||
|
||||
[](https://youtu.be/2xkXL5EUpS0 "ML para iniciantes - O seu primeiro projeto de regressão linear em Python")
|
||||
|
||||
> 🎥 Clique na imagem acima para um vídeo curto sobre este exercício.
|
||||
|
||||
No ficheiro _notebook.ipynb_ associado a esta lição, limpe todas as células pressionando o ícone da 'lixeira'.
|
||||
|
||||
Nesta secção, irá trabalhar com um pequeno conjunto de dados sobre diabetes que está incluído no Scikit-learn para fins de aprendizagem. Imagine que queria testar um tratamento para pacientes diabéticos. Modelos de Machine Learning podem ajudá-lo a determinar quais pacientes responderiam melhor ao tratamento, com base em combinações de variáveis. Mesmo um modelo de regressão muito básico, quando visualizado, pode mostrar informações sobre variáveis que o ajudariam a organizar os seus ensaios clínicos teóricos.
|
||||
|
||||
✅ Existem muitos tipos de métodos de regressão, e a escolha depende da resposta que procura. Se quiser prever a altura provável de uma pessoa com uma determinada idade, utilizaria regressão linear, pois está à procura de um **valor numérico**. Se estiver interessado em descobrir se um tipo de cozinha deve ser considerado vegan ou não, está à procura de uma **atribuição de categoria**, então utilizaria regressão logística. Aprenderá mais sobre regressão logística mais tarde. Pense um pouco sobre algumas perguntas que pode fazer aos dados e qual destes métodos seria mais apropriado.
|
||||
|
||||
Vamos começar esta tarefa.
|
||||
|
||||
### Importar bibliotecas
|
||||
|
||||
Para esta tarefa, iremos importar algumas bibliotecas:
|
||||
|
||||
- **matplotlib**. É uma ferramenta útil para [criação de gráficos](https://matplotlib.org/) e será usada para criar um gráfico de linha.
|
||||
- **numpy**. [numpy](https://numpy.org/doc/stable/user/whatisnumpy.html) é uma biblioteca útil para manipulação de dados numéricos em Python.
|
||||
- **sklearn**. Esta é a biblioteca [Scikit-learn](https://scikit-learn.org/stable/user_guide.html).
|
||||
|
||||
Importe algumas bibliotecas para ajudar nas suas tarefas.
|
||||
|
||||
1. Adicione as importações escrevendo o seguinte código:
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from sklearn import datasets, linear_model, model_selection
|
||||
```
|
||||
|
||||
Acima, está a importar `matplotlib`, `numpy` e está a importar `datasets`, `linear_model` e `model_selection` do `sklearn`. `model_selection` é usado para dividir os dados em conjuntos de treino e teste.
|
||||
|
||||
### O conjunto de dados sobre diabetes
|
||||
|
||||
O [conjunto de dados sobre diabetes](https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset) incluído possui 442 amostras de dados sobre diabetes, com 10 variáveis de características, algumas das quais incluem:
|
||||
|
||||
- age: idade em anos
|
||||
- bmi: índice de massa corporal
|
||||
- bp: pressão arterial média
|
||||
- s1 tc: T-Cells (um tipo de glóbulos brancos)
|
||||
|
||||
✅ Este conjunto de dados inclui o conceito de 'sexo' como uma variável de característica importante para a pesquisa sobre diabetes. Muitos conjuntos de dados médicos incluem este tipo de classificação binária. Pense um pouco sobre como categorizações como esta podem excluir certas partes da população de tratamentos.
|
||||
|
||||
Agora, carregue os dados X e y.
|
||||
|
||||
> 🎓 Lembre-se, isto é aprendizagem supervisionada, e precisamos de um alvo 'y' nomeado.
|
||||
|
||||
Numa nova célula de código, carregue o conjunto de dados sobre diabetes chamando `load_diabetes()`. O parâmetro `return_X_y=True` indica que `X` será uma matriz de dados e `y` será o alvo da regressão.
|
||||
|
||||
1. Adicione alguns comandos `print` para mostrar a forma da matriz de dados e o seu primeiro elemento:
|
||||
|
||||
```python
|
||||
X, y = datasets.load_diabetes(return_X_y=True)
|
||||
print(X.shape)
|
||||
print(X[0])
|
||||
```
|
||||
|
||||
O que está a receber como resposta é uma tupla. O que está a fazer é atribuir os dois primeiros valores da tupla a `X` e `y`, respetivamente. Saiba mais [sobre tuplas](https://wikipedia.org/wiki/Tuple).
|
||||
|
||||
Pode ver que estes dados têm 442 itens organizados em arrays de 10 elementos:
|
||||
|
||||
```text
|
||||
(442, 10)
|
||||
[ 0.03807591 0.05068012 0.06169621 0.02187235 -0.0442235 -0.03482076
|
||||
-0.04340085 -0.00259226 0.01990842 -0.01764613]
|
||||
```
|
||||
|
||||
✅ Pense um pouco sobre a relação entre os dados e o alvo da regressão. A regressão linear prevê relações entre a característica X e a variável alvo y. Consegue encontrar o [alvo](https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset) para o conjunto de dados sobre diabetes na documentação? O que este conjunto de dados está a demonstrar, dado o alvo?
|
||||
|
||||
2. Em seguida, selecione uma parte deste conjunto de dados para plotar, escolhendo a 3ª coluna do conjunto de dados. Pode fazer isso utilizando o operador `:` para selecionar todas as linhas e, em seguida, selecionando a 3ª coluna usando o índice (2). Também pode remodelar os dados para serem um array 2D - conforme necessário para plotagem - utilizando `reshape(n_rows, n_columns)`. Se um dos parâmetros for -1, a dimensão correspondente será calculada automaticamente.
|
||||
|
||||
```python
|
||||
X = X[:, 2]
|
||||
X = X.reshape((-1,1))
|
||||
```
|
||||
|
||||
✅ A qualquer momento, imprima os dados para verificar a sua forma.
|
||||
|
||||
3. Agora que tem os dados prontos para serem plotados, pode verificar se uma máquina pode ajudar a determinar uma divisão lógica entre os números neste conjunto de dados. Para isso, precisa de dividir tanto os dados (X) quanto o alvo (y) em conjuntos de teste e treino. O Scikit-learn tem uma forma simples de fazer isso; pode dividir os seus dados de teste num ponto específico.
|
||||
|
||||
```python
|
||||
X_train, X_test, y_train, y_test = model_selection.train_test_split(X, y, test_size=0.33)
|
||||
```
|
||||
|
||||
4. Agora está pronto para treinar o seu modelo! Carregue o modelo de regressão linear e treine-o com os seus conjuntos de treino X e y utilizando `model.fit()`:
|
||||
|
||||
```python
|
||||
model = linear_model.LinearRegression()
|
||||
model.fit(X_train, y_train)
|
||||
```
|
||||
|
||||
✅ `model.fit()` é uma função que verá em muitas bibliotecas de ML, como TensorFlow.
|
||||
|
||||
5. Em seguida, crie uma previsão utilizando os dados de teste, com a função `predict()`. Isto será usado para desenhar a linha entre os grupos de dados.
|
||||
|
||||
```python
|
||||
y_pred = model.predict(X_test)
|
||||
```
|
||||
|
||||
6. Agora é hora de mostrar os dados num gráfico. O Matplotlib é uma ferramenta muito útil para esta tarefa. Crie um scatterplot de todos os dados de teste X e y, e utilize a previsão para desenhar uma linha no local mais apropriado, entre os agrupamentos de dados do modelo.
|
||||
|
||||
```python
|
||||
plt.scatter(X_test, y_test, color='black')
|
||||
plt.plot(X_test, y_pred, color='blue', linewidth=3)
|
||||
plt.xlabel('Scaled BMIs')
|
||||
plt.ylabel('Disease Progression')
|
||||
plt.title('A Graph Plot Showing Diabetes Progression Against BMI')
|
||||
plt.show()
|
||||
```
|
||||
|
||||

|
||||
✅ Pensa um pouco sobre o que está a acontecer aqui. Uma linha reta está a passar por muitos pequenos pontos de dados, mas o que está realmente a fazer? Consegues perceber como deverias ser capaz de usar esta linha para prever onde um novo ponto de dados, ainda não visto, deveria encaixar em relação ao eixo y do gráfico? Tenta expressar em palavras a utilidade prática deste modelo.
|
||||
|
||||
Parabéns, construíste o teu primeiro modelo de regressão linear, criaste uma previsão com ele e exibiste-a num gráfico!
|
||||
|
||||
---
|
||||
## 🚀Desafio
|
||||
|
||||
Representa graficamente uma variável diferente deste conjunto de dados. Dica: edita esta linha: `X = X[:,2]`. Dado o objetivo deste conjunto de dados, o que consegues descobrir sobre a progressão da diabetes como doença?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Estudo Individual
|
||||
|
||||
Neste tutorial, trabalhaste com regressão linear simples, em vez de regressão univariada ou múltipla. Lê um pouco sobre as diferenças entre estes métodos ou dá uma olhada [neste vídeo](https://www.coursera.org/lecture/quantifying-relationships-regression-models/linear-vs-nonlinear-categorical-variables-ai2Ef).
|
||||
|
||||
Lê mais sobre o conceito de regressão e reflete sobre que tipo de perguntas podem ser respondidas com esta técnica. Faz este [tutorial](https://docs.microsoft.com/learn/modules/train-evaluate-regression-models?WT.mc_id=academic-77952-leestott) para aprofundar o teu entendimento.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Um conjunto de dados diferente](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,18 @@
|
||||
# Regressão com Scikit-learn
|
||||
|
||||
## Instruções
|
||||
|
||||
Consulte o [Linnerud dataset](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_linnerud.html#sklearn.datasets.load_linnerud) no Scikit-learn. Este conjunto de dados possui múltiplos [alvos](https://scikit-learn.org/stable/datasets/toy_dataset.html#linnerrud-dataset): 'Consiste em três variáveis de exercício (dados) e três variáveis fisiológicas (alvo) coletadas de vinte homens de meia-idade em um clube de fitness'.
|
||||
|
||||
Com as suas próprias palavras, descreva como criar um modelo de regressão que represente graficamente a relação entre a medida da cintura e o número de abdominais realizados. Faça o mesmo para os outros pontos de dados deste conjunto de dados.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critério | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| ------------------------------ | ----------------------------------- | ----------------------------- | -------------------------- |
|
||||
| Submeter um parágrafo descritivo | Um parágrafo bem escrito é submetido | Algumas frases são submetidas | Nenhuma descrição é fornecida |
|
||||
|
||||
---
|
||||
|
||||
**Aviso**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,449 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "lesson_1-R.ipynb",
|
||||
"provenance": [],
|
||||
"collapsed_sections": [],
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "ir",
|
||||
"display_name": "R"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "R"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "c18d3bd0bd8ae3878597e89dcd1fa5c1",
|
||||
"translation_date": "2025-09-03T19:42:25+00:00",
|
||||
"source_file": "2-Regression/1-Tools/solution/R/lesson_1-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"id": "YJUHCXqK57yz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Introdução à Regressão - Aula 1\n",
|
||||
"\n",
|
||||
"#### Colocando em Perspectiva\n",
|
||||
"\n",
|
||||
"✅ Existem muitos tipos de métodos de regressão, e qual você escolhe depende da resposta que está procurando. Se quiser prever a altura provável de uma pessoa com uma determinada idade, utilizaria `regressão linear`, pois está à procura de um **valor numérico**. Se estiver interessado em descobrir se um tipo de culinária deve ser considerado vegano ou não, está à procura de uma **atribuição de categoria**, então utilizaria `regressão logística`. Aprenderá mais sobre regressão logística mais adiante. Pense um pouco sobre algumas perguntas que pode fazer aos dados e qual desses métodos seria mais apropriado.\n",
|
||||
"\n",
|
||||
"Nesta seção, irá trabalhar com um [pequeno conjunto de dados sobre diabetes](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html). Imagine que queria testar um tratamento para pacientes diabéticos. Modelos de Machine Learning podem ajudar a determinar quais pacientes responderiam melhor ao tratamento, com base em combinações de variáveis. Mesmo um modelo de regressão muito básico, quando visualizado, pode mostrar informações sobre variáveis que ajudariam a organizar os seus ensaios clínicos teóricos.\n",
|
||||
"\n",
|
||||
"Dito isso, vamos começar esta tarefa!\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/encouRage.jpg\"\n",
|
||||
" width=\"630\"/>\n",
|
||||
" <figcaption>Arte por @allison_horst</figcaption>\n",
|
||||
"\n",
|
||||
"<!--<br>Arte por @allison_horst-->\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "LWNNzfqd6feZ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 1. Carregar o nosso conjunto de ferramentas\n",
|
||||
"\n",
|
||||
"Para esta tarefa, vamos precisar dos seguintes pacotes:\n",
|
||||
"\n",
|
||||
"- `tidyverse`: O [tidyverse](https://www.tidyverse.org/) é uma [coleção de pacotes R](https://www.tidyverse.org/packages) projetada para tornar a ciência de dados mais rápida, fácil e divertida!\n",
|
||||
"\n",
|
||||
"- `tidymodels`: O [tidymodels](https://www.tidymodels.org/) é uma [coleção de pacotes](https://www.tidymodels.org/packages/) para modelagem e aprendizagem automática.\n",
|
||||
"\n",
|
||||
"Pode instalá-los com o seguinte comando:\n",
|
||||
"\n",
|
||||
"`install.packages(c(\"tidyverse\", \"tidymodels\"))`\n",
|
||||
"\n",
|
||||
"O script abaixo verifica se tem os pacotes necessários para completar este módulo e instala-os caso algum esteja em falta.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "FIo2YhO26wI9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"source": [
|
||||
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n",
|
||||
"pacman::p_load(tidyverse, tidymodels)"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stderr",
|
||||
"text": [
|
||||
"Loading required package: pacman\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"id": "cIA9fz9v7Dss",
|
||||
"colab": {
|
||||
"base_uri": "https://localhost:8080/"
|
||||
},
|
||||
"outputId": "2df7073b-86b2-4b32-cb86-0da605a0dc11"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Agora, vamos carregar estes pacotes incríveis e torná-los disponíveis na nossa sessão atual de R. (Isto é apenas para ilustração, `pacman::p_load()` já fez isso por si)\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "gpO_P_6f9WUG"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# load the core Tidyverse packages\r\n",
|
||||
"library(tidyverse)\r\n",
|
||||
"\r\n",
|
||||
"# load the core Tidymodels packages\r\n",
|
||||
"library(tidymodels)\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "NLMycgG-9ezO"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 2. O conjunto de dados sobre diabetes\n",
|
||||
"\n",
|
||||
"Neste exercício, vamos demonstrar nossas habilidades de regressão fazendo previsões com um conjunto de dados sobre diabetes. O [conjunto de dados sobre diabetes](https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt) inclui `442 amostras` de dados relacionados à diabetes, com 10 variáveis preditoras, `idade`, `sexo`, `índice de massa corporal`, `pressão arterial média` e `seis medições de soro sanguíneo`, além de uma variável de resultado `y`: uma medida quantitativa da progressão da doença um ano após a linha de base.\n",
|
||||
"\n",
|
||||
"|Número de observações|442|\n",
|
||||
"|----------------------|:---|\n",
|
||||
"|Número de preditores|As primeiras 10 colunas são preditivas numéricas|\n",
|
||||
"|Resultado/Alvo|A coluna 11 é uma medida quantitativa da progressão da doença um ano após a linha de base|\n",
|
||||
"|Informação sobre os preditores|- idade em anos\n",
|
||||
"||- sexo\n",
|
||||
"||- bmi índice de massa corporal\n",
|
||||
"||- bp pressão arterial média\n",
|
||||
"||- s1 tc, colesterol sérico total\n",
|
||||
"||- s2 ldl, lipoproteínas de baixa densidade\n",
|
||||
"||- s3 hdl, lipoproteínas de alta densidade\n",
|
||||
"||- s4 tch, colesterol total / HDL\n",
|
||||
"||- s5 ltg, possivelmente logaritmo do nível de triglicerídeos no soro\n",
|
||||
"||- s6 glu, nível de açúcar no sangue|\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"> 🎓 Lembre-se, isto é aprendizagem supervisionada, e precisamos de um alvo chamado 'y'.\n",
|
||||
"\n",
|
||||
"Antes de poder manipular dados com R, é necessário importar os dados para a memória do R ou estabelecer uma conexão com os dados que o R possa usar para acessá-los remotamente.\n",
|
||||
"\n",
|
||||
"> O pacote [readr](https://readr.tidyverse.org/), que faz parte do Tidyverse, oferece uma maneira rápida e amigável de ler dados retangulares no R.\n",
|
||||
"\n",
|
||||
"Agora, vamos carregar o conjunto de dados sobre diabetes fornecido neste URL de origem: <https://www4.stat.ncsu.edu/~boos/var.select/diabetes.html>\n",
|
||||
"\n",
|
||||
"Além disso, faremos uma verificação básica nos nossos dados usando `glimpse()` e exibiremos as primeiras 5 linhas usando `slice()`.\n",
|
||||
"\n",
|
||||
"Antes de avançarmos, vamos também introduzir algo que você encontrará frequentemente no código R 🥁🥁: o operador pipe `%>%`\n",
|
||||
"\n",
|
||||
"O operador pipe (`%>%`) realiza operações em sequência lógica, passando um objeto adiante para uma função ou expressão de chamada. Você pode pensar no operador pipe como dizendo \"e então\" no seu código.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "KM6iXLH996Cl"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Import the data set\r\n",
|
||||
"diabetes <- read_table2(file = \"https://www4.stat.ncsu.edu/~boos/var.select/diabetes.rwrite1.txt\")\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Get a glimpse and dimensions of the data\r\n",
|
||||
"glimpse(diabetes)\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Select the first 5 rows of the data\r\n",
|
||||
"diabetes %>% \r\n",
|
||||
" slice(1:5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "Z1geAMhM-bSP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"`glimpse()` mostra-nos que estes dados têm 442 linhas e 11 colunas, sendo todas as colunas do tipo de dados `double`.\n",
|
||||
"\n",
|
||||
"<br>\n",
|
||||
"\n",
|
||||
"> glimpse() e slice() são funções do [`dplyr`](https://dplyr.tidyverse.org/). Dplyr, parte do Tidyverse, é uma gramática de manipulação de dados que fornece um conjunto consistente de verbos para ajudar a resolver os desafios mais comuns de manipulação de dados.\n",
|
||||
"\n",
|
||||
"<br>\n",
|
||||
"\n",
|
||||
"Agora que temos os dados, vamos focar numa única característica (`bmi`) como alvo para este exercício. Isto exigirá que selecionemos as colunas desejadas. Então, como fazemos isso?\n",
|
||||
"\n",
|
||||
"[`dplyr::select()`](https://dplyr.tidyverse.org/reference/select.html) permite-nos *selecionar* (e opcionalmente renomear) colunas num data frame.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "UwjVT1Hz-c3Z"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Select predictor feature `bmi` and outcome `y`\r\n",
|
||||
"diabetes_select <- diabetes %>% \r\n",
|
||||
" select(c(bmi, y))\r\n",
|
||||
"\r\n",
|
||||
"# Print the first 5 rows\r\n",
|
||||
"diabetes_select %>% \r\n",
|
||||
" slice(1:10)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "RDY1oAKI-m80"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 3. Dados de Treino e Teste\n",
|
||||
"\n",
|
||||
"É uma prática comum em aprendizagem supervisionada *dividir* os dados em dois subconjuntos: um conjunto (geralmente maior) para treinar o modelo e um conjunto menor \"reservado\" para verificar como o modelo se comportou.\n",
|
||||
"\n",
|
||||
"Agora que temos os dados prontos, podemos verificar se uma máquina pode ajudar a determinar uma divisão lógica entre os números neste conjunto de dados. Podemos usar o pacote [rsample](https://tidymodels.github.io/rsample/), que faz parte do framework Tidymodels, para criar um objeto que contém as informações sobre *como* dividir os dados, e depois usar mais duas funções do rsample para extrair os conjuntos de treino e teste criados:\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "SDk668xK-tc3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"set.seed(2056)\r\n",
|
||||
"# Split 67% of the data for training and the rest for tesing\r\n",
|
||||
"diabetes_split <- diabetes_select %>% \r\n",
|
||||
" initial_split(prop = 0.67)\r\n",
|
||||
"\r\n",
|
||||
"# Extract the resulting train and test sets\r\n",
|
||||
"diabetes_train <- training(diabetes_split)\r\n",
|
||||
"diabetes_test <- testing(diabetes_split)\r\n",
|
||||
"\r\n",
|
||||
"# Print the first 3 rows of the training set\r\n",
|
||||
"diabetes_train %>% \r\n",
|
||||
" slice(1:10)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "EqtHx129-1h-"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 4. Treinar um modelo de regressão linear com Tidymodels\n",
|
||||
"\n",
|
||||
"Agora estamos prontos para treinar o nosso modelo!\n",
|
||||
"\n",
|
||||
"No Tidymodels, especifica-se os modelos utilizando `parsnip()` ao definir três conceitos:\n",
|
||||
"\n",
|
||||
"- O **tipo** de modelo diferencia modelos como regressão linear, regressão logística, modelos de árvores de decisão, entre outros.\n",
|
||||
"\n",
|
||||
"- O **modo** do modelo inclui opções comuns como regressão e classificação; alguns tipos de modelo suportam ambos, enquanto outros têm apenas um modo.\n",
|
||||
"\n",
|
||||
"- O **motor** do modelo é a ferramenta computacional que será usada para ajustar o modelo. Muitas vezes, são pacotes R, como **`\"lm\"`** ou **`\"ranger\"`**\n",
|
||||
"\n",
|
||||
"Estas informações sobre o modelo são capturadas numa especificação de modelo, então vamos construir uma!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "sBOS-XhB-6v7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Build a linear model specification\r\n",
|
||||
"lm_spec <- \r\n",
|
||||
" # Type\r\n",
|
||||
" linear_reg() %>% \r\n",
|
||||
" # Engine\r\n",
|
||||
" set_engine(\"lm\") %>% \r\n",
|
||||
" # Mode\r\n",
|
||||
" set_mode(\"regression\")\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Print the model specification\r\n",
|
||||
"lm_spec"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "20OwEw20--t3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Depois de um modelo ter sido *especificado*, pode ser `estimado` ou `treinado` utilizando a função [`fit()`](https://parsnip.tidymodels.org/reference/fit.html), normalmente com uma fórmula e alguns dados.\n",
|
||||
"\n",
|
||||
"`y ~ .` significa que ajustaremos `y` como a quantidade/variável alvo prevista, explicada por todos os preditores/características, ou seja, `.` (neste caso, temos apenas um preditor: `bmi`).\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "_oDHs89k_CJj"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Build a linear model specification\r\n",
|
||||
"lm_spec <- linear_reg() %>% \r\n",
|
||||
" set_engine(\"lm\") %>%\r\n",
|
||||
" set_mode(\"regression\")\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Train a linear regression model\r\n",
|
||||
"lm_mod <- lm_spec %>% \r\n",
|
||||
" fit(y ~ ., data = diabetes_train)\r\n",
|
||||
"\r\n",
|
||||
"# Print the model\r\n",
|
||||
"lm_mod"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "YlsHqd-q_GJQ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"A partir do resultado do modelo, podemos observar os coeficientes aprendidos durante o treino. Eles representam os coeficientes da linha de melhor ajuste que nos proporciona o menor erro geral entre a variável real e a prevista.\n",
|
||||
"<br>\n",
|
||||
"\n",
|
||||
"## 5. Fazer previsões no conjunto de teste\n",
|
||||
"\n",
|
||||
"Agora que treinámos um modelo, podemos utilizá-lo para prever a progressão da doença y para o conjunto de dados de teste usando [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Isto será usado para traçar a linha entre os grupos de dados.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "kGZ22RQj_Olu"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Make predictions for the test set\r\n",
|
||||
"predictions <- lm_mod %>% \r\n",
|
||||
" predict(new_data = diabetes_test)\r\n",
|
||||
"\r\n",
|
||||
"# Print out some of the predictions\r\n",
|
||||
"predictions %>% \r\n",
|
||||
" slice(1:5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "nXHbY7M2_aao"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Woohoo! 💃🕺 Acabámos de treinar um modelo e utilizámo-lo para fazer previsões!\n",
|
||||
"\n",
|
||||
"Ao fazer previsões, a convenção do tidymodels é sempre produzir um tibble/data frame de resultados com nomes de colunas padronizados. Isto facilita a combinação dos dados originais com as previsões num formato utilizável para operações subsequentes, como a criação de gráficos.\n",
|
||||
"\n",
|
||||
"`dplyr::bind_cols()` une eficientemente várias data frames por coluna.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "R_JstwUY_bIs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Combine the predictions and the original test set\r\n",
|
||||
"results <- diabetes_test %>% \r\n",
|
||||
" bind_cols(predictions)\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"results %>% \r\n",
|
||||
" slice(1:5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "RybsMJR7_iI8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 6. Representar os resultados do modelo\n",
|
||||
"\n",
|
||||
"Agora é hora de ver isto visualmente 📈. Vamos criar um gráfico de dispersão com todos os valores de `y` e `bmi` do conjunto de teste e, em seguida, usar as previsões para desenhar uma linha no lugar mais apropriado, entre os agrupamentos de dados do modelo.\n",
|
||||
"\n",
|
||||
"O R tem vários sistemas para criar gráficos, mas o `ggplot2` é um dos mais elegantes e versáteis. Este permite compor gráficos **combinando componentes independentes**.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "XJbYbMZW_n_s"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Set a theme for the plot\r\n",
|
||||
"theme_set(theme_light())\r\n",
|
||||
"# Create a scatter plot\r\n",
|
||||
"results %>% \r\n",
|
||||
" ggplot(aes(x = bmi)) +\r\n",
|
||||
" # Add a scatter plot\r\n",
|
||||
" geom_point(aes(y = y), size = 1.6) +\r\n",
|
||||
" # Add a line plot\r\n",
|
||||
" geom_line(aes(y = .pred), color = \"blue\", size = 1.5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "R9tYp3VW_sTn"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"✅ Pensa um pouco sobre o que está a acontecer aqui. Uma linha reta está a passar por muitos pequenos pontos de dados, mas o que está realmente a fazer? Consegues perceber como deverias ser capaz de usar esta linha para prever onde um novo ponto de dados, ainda não visto, deveria encaixar em relação ao eixo y do gráfico? Tenta expressar em palavras a utilidade prática deste modelo.\n",
|
||||
"\n",
|
||||
"Parabéns, construíste o teu primeiro modelo de regressão linear, criaste uma previsão com ele e exibiste-a num gráfico!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "zrPtHIxx_tNI"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,217 @@
|
||||
# Construir um modelo de regressão usando Scikit-learn: preparar e visualizar dados
|
||||
|
||||

|
||||
|
||||
Infográfico por [Dasani Madipalli](https://twitter.com/dasani_decoded)
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
> ### [Esta lição está disponível em R!](../../../../2-Regression/2-Data/solution/R/lesson_2.html)
|
||||
|
||||
## Introdução
|
||||
|
||||
Agora que já está equipado com as ferramentas necessárias para começar a construir modelos de machine learning com Scikit-learn, está pronto para começar a fazer perguntas aos seus dados. Ao trabalhar com dados e aplicar soluções de ML, é muito importante saber como formular a pergunta certa para desbloquear adequadamente o potencial do seu conjunto de dados.
|
||||
|
||||
Nesta lição, irá aprender:
|
||||
|
||||
- Como preparar os seus dados para a construção de modelos.
|
||||
- Como usar o Matplotlib para visualização de dados.
|
||||
|
||||
## Fazer a pergunta certa aos seus dados
|
||||
|
||||
A pergunta que precisa de responder determinará o tipo de algoritmos de ML que irá utilizar. E a qualidade da resposta que obtém dependerá muito da natureza dos seus dados.
|
||||
|
||||
Veja os [dados](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/data/US-pumpkins.csv) fornecidos para esta lição. Pode abrir este ficheiro .csv no VS Code. Uma rápida análise mostra imediatamente que há espaços em branco e uma mistura de dados em formato texto e numérico. Há também uma coluna estranha chamada 'Package', onde os dados são uma mistura entre 'sacks', 'bins' e outros valores. Os dados, na verdade, estão um pouco desorganizados.
|
||||
|
||||
[](https://youtu.be/5qGjczWTrDQ "ML para iniciantes - Como analisar e limpar um conjunto de dados")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo curto sobre como preparar os dados para esta lição.
|
||||
|
||||
De facto, não é muito comum receber um conjunto de dados completamente pronto para criar um modelo de ML diretamente. Nesta lição, irá aprender como preparar um conjunto de dados bruto usando bibliotecas padrão do Python. Também aprenderá várias técnicas para visualizar os dados.
|
||||
|
||||
## Estudo de caso: 'o mercado de abóboras'
|
||||
|
||||
Nesta pasta encontrará um ficheiro .csv na pasta raiz `data` chamado [US-pumpkins.csv](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/data/US-pumpkins.csv), que inclui 1757 linhas de dados sobre o mercado de abóboras, organizados por cidade. Estes são dados brutos extraídos dos [Relatórios Padrão dos Mercados de Culturas Especiais](https://www.marketnews.usda.gov/mnp/fv-report-config-step1?type=termPrice) distribuídos pelo Departamento de Agricultura dos Estados Unidos.
|
||||
|
||||
### Preparar os dados
|
||||
|
||||
Estes dados estão em domínio público. Podem ser descarregados em vários ficheiros separados, por cidade, no site do USDA. Para evitar muitos ficheiros separados, concatenámos todos os dados das cidades num único ficheiro, portanto já _preparámos_ os dados um pouco. Agora, vamos analisar os dados mais de perto.
|
||||
|
||||
### Os dados das abóboras - primeiras conclusões
|
||||
|
||||
O que nota sobre estes dados? Já viu que há uma mistura de texto, números, espaços em branco e valores estranhos que precisa de interpretar.
|
||||
|
||||
Que pergunta pode fazer a estes dados, usando uma técnica de regressão? Que tal "Prever o preço de uma abóbora à venda durante um determinado mês"? Olhando novamente para os dados, há algumas alterações que precisa de fazer para criar a estrutura de dados necessária para esta tarefa.
|
||||
|
||||
## Exercício - analisar os dados das abóboras
|
||||
|
||||
Vamos usar o [Pandas](https://pandas.pydata.org/) (o nome significa `Python Data Analysis`), uma ferramenta muito útil para moldar dados, para analisar e preparar estes dados das abóboras.
|
||||
|
||||
### Primeiro, verificar datas em falta
|
||||
|
||||
Primeiro, precisará de tomar medidas para verificar se há datas em falta:
|
||||
|
||||
1. Converter as datas para um formato de mês (estas são datas dos EUA, então o formato é `MM/DD/YYYY`).
|
||||
2. Extrair o mês para uma nova coluna.
|
||||
|
||||
Abra o ficheiro _notebook.ipynb_ no Visual Studio Code e importe a folha de cálculo para um novo dataframe do Pandas.
|
||||
|
||||
1. Use a função `head()` para visualizar as primeiras cinco linhas.
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
pumpkins = pd.read_csv('../data/US-pumpkins.csv')
|
||||
pumpkins.head()
|
||||
```
|
||||
|
||||
✅ Que função usaria para visualizar as últimas cinco linhas?
|
||||
|
||||
1. Verifique se há dados em falta no dataframe atual:
|
||||
|
||||
```python
|
||||
pumpkins.isnull().sum()
|
||||
```
|
||||
|
||||
Há dados em falta, mas talvez isso não seja relevante para a tarefa em questão.
|
||||
|
||||
1. Para tornar o seu dataframe mais fácil de trabalhar, selecione apenas as colunas necessárias, usando a função `loc`, que extrai do dataframe original um grupo de linhas (passado como primeiro parâmetro) e colunas (passado como segundo parâmetro). A expressão `:` no caso abaixo significa "todas as linhas".
|
||||
|
||||
```python
|
||||
columns_to_select = ['Package', 'Low Price', 'High Price', 'Date']
|
||||
pumpkins = pumpkins.loc[:, columns_to_select]
|
||||
```
|
||||
|
||||
### Segundo, determinar o preço médio da abóbora
|
||||
|
||||
Pense em como determinar o preço médio de uma abóbora num determinado mês. Que colunas escolheria para esta tarefa? Dica: precisará de 3 colunas.
|
||||
|
||||
Solução: calcule a média das colunas `Low Price` e `High Price` para preencher a nova coluna Price e converta a coluna Date para mostrar apenas o mês. Felizmente, de acordo com a verificação acima, não há dados em falta para datas ou preços.
|
||||
|
||||
1. Para calcular a média, adicione o seguinte código:
|
||||
|
||||
```python
|
||||
price = (pumpkins['Low Price'] + pumpkins['High Price']) / 2
|
||||
|
||||
month = pd.DatetimeIndex(pumpkins['Date']).month
|
||||
|
||||
```
|
||||
|
||||
✅ Sinta-se à vontade para imprimir quaisquer dados que queira verificar usando `print(month)`.
|
||||
|
||||
2. Agora, copie os seus dados convertidos para um novo dataframe do Pandas:
|
||||
|
||||
```python
|
||||
new_pumpkins = pd.DataFrame({'Month': month, 'Package': pumpkins['Package'], 'Low Price': pumpkins['Low Price'],'High Price': pumpkins['High Price'], 'Price': price})
|
||||
```
|
||||
|
||||
Ao imprimir o seu dataframe, verá um conjunto de dados limpo e organizado, no qual pode construir o seu novo modelo de regressão.
|
||||
|
||||
### Mas espere! Há algo estranho aqui
|
||||
|
||||
Se olhar para a coluna `Package`, verá que as abóboras são vendidas em muitas configurações diferentes. Algumas são vendidas em medidas de '1 1/9 bushel', outras em '1/2 bushel', algumas por abóbora, outras por peso, e algumas em grandes caixas com larguras variadas.
|
||||
|
||||
> Parece que as abóboras são muito difíceis de pesar de forma consistente
|
||||
|
||||
Ao analisar os dados originais, é interessante notar que qualquer coisa com `Unit of Sale` igual a 'EACH' ou 'PER BIN' também tem o tipo `Package` por polegada, por bin ou 'each'. Parece que as abóboras são muito difíceis de pesar de forma consistente, então vamos filtrá-las selecionando apenas abóboras com a string 'bushel' na coluna `Package`.
|
||||
|
||||
1. Adicione um filtro no topo do ficheiro, sob a importação inicial do .csv:
|
||||
|
||||
```python
|
||||
pumpkins = pumpkins[pumpkins['Package'].str.contains('bushel', case=True, regex=True)]
|
||||
```
|
||||
|
||||
Se imprimir os dados agora, verá que está a obter apenas cerca de 415 linhas de dados contendo abóboras por bushel.
|
||||
|
||||
### Mas espere! Há mais uma coisa a fazer
|
||||
|
||||
Notou que a quantidade de bushel varia por linha? Precisa de normalizar os preços para mostrar o preço por bushel, então faça alguns cálculos para padronizá-lo.
|
||||
|
||||
1. Adicione estas linhas após o bloco que cria o dataframe new_pumpkins:
|
||||
|
||||
```python
|
||||
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1 1/9'), 'Price'] = price/(1 + 1/9)
|
||||
|
||||
new_pumpkins.loc[new_pumpkins['Package'].str.contains('1/2'), 'Price'] = price/(1/2)
|
||||
```
|
||||
|
||||
✅ De acordo com [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308), o peso de um bushel depende do tipo de produto, pois é uma medida de volume. "Um bushel de tomates, por exemplo, deve pesar 56 libras... Folhas e verduras ocupam mais espaço com menos peso, então um bushel de espinafre pesa apenas 20 libras." É tudo bastante complicado! Vamos evitar fazer uma conversão de bushel para libra e, em vez disso, calcular o preço por bushel. Todo este estudo sobre bushels de abóboras, no entanto, mostra como é muito importante entender a natureza dos seus dados!
|
||||
|
||||
Agora, pode analisar o preço por unidade com base na medida de bushel. Se imprimir os dados mais uma vez, verá como estão padronizados.
|
||||
|
||||
✅ Reparou que as abóboras vendidas por meio bushel são muito caras? Consegue descobrir porquê? Dica: abóboras pequenas são muito mais caras do que grandes, provavelmente porque há muito mais delas por bushel, dado o espaço não utilizado ocupado por uma grande abóbora oca para torta.
|
||||
|
||||
## Estratégias de Visualização
|
||||
|
||||
Parte do papel do cientista de dados é demonstrar a qualidade e a natureza dos dados com os quais está a trabalhar. Para isso, frequentemente criam visualizações interessantes, como gráficos, diagramas e tabelas, mostrando diferentes aspetos dos dados. Desta forma, conseguem mostrar visualmente relações e lacunas que, de outra forma, seriam difíceis de identificar.
|
||||
|
||||
[](https://youtu.be/SbUkxH6IJo0 "ML para iniciantes - Como visualizar dados com Matplotlib")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo curto sobre como visualizar os dados para esta lição.
|
||||
|
||||
As visualizações também podem ajudar a determinar a técnica de machine learning mais apropriada para os dados. Um gráfico de dispersão que parece seguir uma linha, por exemplo, indica que os dados são bons candidatos para um exercício de regressão linear.
|
||||
|
||||
Uma biblioteca de visualização de dados que funciona bem em notebooks Jupyter é [Matplotlib](https://matplotlib.org/) (que também viu na lição anterior).
|
||||
|
||||
> Obtenha mais experiência com visualização de dados nestes [tutoriais](https://docs.microsoft.com/learn/modules/explore-analyze-data-with-python?WT.mc_id=academic-77952-leestott).
|
||||
|
||||
## Exercício - experimentar com Matplotlib
|
||||
|
||||
Tente criar alguns gráficos básicos para exibir o novo dataframe que acabou de criar. O que um gráfico de linha básico mostraria?
|
||||
|
||||
1. Importe o Matplotlib no topo do ficheiro, sob a importação do Pandas:
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
```
|
||||
|
||||
1. Execute novamente todo o notebook para atualizar.
|
||||
1. No final do notebook, adicione uma célula para plotar os dados como um boxplot:
|
||||
|
||||
```python
|
||||
price = new_pumpkins.Price
|
||||
month = new_pumpkins.Month
|
||||
plt.scatter(price, month)
|
||||
plt.show()
|
||||
```
|
||||
|
||||

|
||||
|
||||
Este gráfico é útil? Há algo nele que o surpreenda?
|
||||
|
||||
Não é particularmente útil, pois apenas exibe os seus dados como uma dispersão de pontos num determinado mês.
|
||||
|
||||
### Torná-lo útil
|
||||
|
||||
Para que os gráficos exibam dados úteis, geralmente é necessário agrupar os dados de alguma forma. Vamos tentar criar um gráfico onde o eixo y mostra os meses e os dados demonstram a distribuição.
|
||||
|
||||
1. Adicione uma célula para criar um gráfico de barras agrupado:
|
||||
|
||||
```python
|
||||
new_pumpkins.groupby(['Month'])['Price'].mean().plot(kind='bar')
|
||||
plt.ylabel("Pumpkin Price")
|
||||
```
|
||||
|
||||

|
||||
|
||||
Este é um gráfico de visualização de dados mais útil! Parece indicar que o preço mais alto das abóboras ocorre em setembro e outubro. Isso corresponde às suas expectativas? Porquê ou porquê não?
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Explore os diferentes tipos de visualização que o Matplotlib oferece. Quais tipos são mais apropriados para problemas de regressão?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Explore as várias formas de visualizar dados. Faça uma lista das diferentes bibliotecas disponíveis e anote quais são melhores para determinados tipos de tarefas, por exemplo, visualizações 2D vs. visualizações 3D. O que descobre?
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Explorar visualização](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,13 @@
|
||||
# Explorando Visualizações
|
||||
|
||||
Existem várias bibliotecas disponíveis para visualização de dados. Crie algumas visualizações utilizando os dados de Abóbora desta lição com matplotlib e seaborn num notebook de exemplo. Quais bibliotecas são mais fáceis de usar?
|
||||
## Rubrica
|
||||
|
||||
| Critério | Exemplar | Adequado | Necessita Melhorias |
|
||||
| -------- | --------- | -------- | ------------------- |
|
||||
| | Um notebook é submetido com duas explorações/visualizações | Um notebook é submetido com uma exploração/visualização | Um notebook não é submetido |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,46 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.3-final"
|
||||
},
|
||||
"orig_nbformat": 2,
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3",
|
||||
"language": "python"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "1b2ab303ac6c604a34c6ca7a49077fc7",
|
||||
"translation_date": "2025-09-03T19:44:42+00:00",
|
||||
"source_file": "2-Regression/2-Data/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,666 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "lesson_2-R.ipynb",
|
||||
"provenance": [],
|
||||
"collapsed_sections": [],
|
||||
"toc_visible": true
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "ir",
|
||||
"display_name": "R"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "R"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "f3c335f9940cfd76528b3ef918b9b342",
|
||||
"translation_date": "2025-09-03T19:48:56+00:00",
|
||||
"source_file": "2-Regression/2-Data/solution/R/lesson_2-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Construir um modelo de regressão: preparar e visualizar dados\n",
|
||||
"\n",
|
||||
"## **Regressão Linear para Abóboras - Aula 2**\n",
|
||||
"#### Introdução\n",
|
||||
"\n",
|
||||
"Agora que já tem as ferramentas necessárias para começar a construir modelos de machine learning com Tidymodels e Tidyverse, está pronto para começar a fazer perguntas aos seus dados. Ao trabalhar com dados e aplicar soluções de ML, é muito importante saber como formular a pergunta certa para desbloquear adequadamente o potencial do seu conjunto de dados.\n",
|
||||
"\n",
|
||||
"Nesta aula, irá aprender:\n",
|
||||
"\n",
|
||||
"- Como preparar os seus dados para a construção de modelos.\n",
|
||||
"\n",
|
||||
"- Como usar `ggplot2` para visualização de dados.\n",
|
||||
"\n",
|
||||
"A pergunta que precisa de responder determinará o tipo de algoritmos de ML que irá utilizar. E a qualidade da resposta que obtém dependerá fortemente da natureza dos seus dados.\n",
|
||||
"\n",
|
||||
"Vamos ver isso através de um exercício prático.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/unruly_data.jpg\"\n",
|
||||
" width=\"700\"/>\n",
|
||||
" <figcaption>Arte por @allison_horst</figcaption>\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Pg5aexcOPqAZ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 1. Importar dados de abóboras e invocar o Tidyverse\n",
|
||||
"\n",
|
||||
"Vamos precisar dos seguintes pacotes para explorar esta lição:\n",
|
||||
"\n",
|
||||
"- `tidyverse`: O [tidyverse](https://www.tidyverse.org/) é uma [coleção de pacotes R](https://www.tidyverse.org/packages) projetada para tornar a ciência de dados mais rápida, fácil e divertida!\n",
|
||||
"\n",
|
||||
"Pode instalá-los com o seguinte comando:\n",
|
||||
"\n",
|
||||
"`install.packages(c(\"tidyverse\"))`\n",
|
||||
"\n",
|
||||
"O script abaixo verifica se tem os pacotes necessários para completar este módulo e instala-os caso algum esteja em falta.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "dc5WhyVdXAjR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n",
|
||||
"pacman::p_load(tidyverse)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "GqPYUZgfXOBt"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Agora, vamos ativar alguns pacotes e carregar os [dados](https://github.com/microsoft/ML-For-Beginners/blob/main/2-Regression/data/US-pumpkins.csv) fornecidos para esta lição!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "kvjDTPDSXRr2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Load the core Tidyverse packages\n",
|
||||
"library(tidyverse)\n",
|
||||
"\n",
|
||||
"# Import the pumpkins data\n",
|
||||
"pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\")\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Get a glimpse and dimensions of the data\n",
|
||||
"glimpse(pumpkins)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Print the first 50 rows of the data set\n",
|
||||
"pumpkins %>% \n",
|
||||
" slice_head(n =50)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "VMri-t2zXqgD"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Um rápido `glimpse()` mostra imediatamente que há espaços em branco e uma mistura de strings (`chr`) e dados numéricos (`dbl`). A `Date` é do tipo carácter e há também uma coluna estranha chamada `Package`, onde os dados são uma mistura entre `sacks`, `bins` e outros valores. Os dados, na verdade, estão um pouco desorganizados 😤.\n",
|
||||
"\n",
|
||||
"De facto, não é muito comum receber um conjunto de dados completamente pronto para usar e criar um modelo de ML diretamente. Mas não se preocupe, nesta lição, irá aprender como preparar um conjunto de dados bruto utilizando bibliotecas padrão do R 🧑🔧. Também irá aprender várias técnicas para visualizar os dados.📈📊\n",
|
||||
"<br>\n",
|
||||
"\n",
|
||||
"> Um lembrete: O operador pipe (`%>%`) realiza operações numa sequência lógica ao passar um objeto para uma função ou expressão. Pode pensar no operador pipe como dizendo \"e depois\" no seu código.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "REWcIv9yX29v"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 2. Verificar dados em falta\n",
|
||||
"\n",
|
||||
"Um dos problemas mais comuns que os cientistas de dados enfrentam é lidar com dados incompletos ou em falta. O R representa valores em falta, ou desconhecidos, com um valor especial chamado `NA` (Not Available).\n",
|
||||
"\n",
|
||||
"Então, como podemos saber se o data frame contém valores em falta?\n",
|
||||
"<br>\n",
|
||||
"- Uma forma direta seria usar a função base do R `anyNA`, que retorna os objetos lógicos `TRUE` ou `FALSE`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Zxfb3AM5YbUe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"pumpkins %>% \n",
|
||||
" anyNA()"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "G--DQutAYltj"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Ótimo, parece que há alguns dados em falta! Esse é um bom ponto de partida.\n",
|
||||
"\n",
|
||||
"- Outra forma seria usar a função `is.na()` que indica quais elementos individuais das colunas estão em falta com um valor lógico `TRUE`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "mU-7-SB6YokF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"pumpkins %>% \n",
|
||||
" is.na() %>% \n",
|
||||
" head(n = 7)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "W-DxDOR4YxSW"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Ok, trabalho concluído, mas com um conjunto de dados tão grande como este, seria ineficiente e praticamente impossível rever todas as linhas e colunas individualmente😴.\n",
|
||||
"\n",
|
||||
"- Uma forma mais intuitiva seria calcular a soma dos valores em falta para cada coluna:\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "xUWxipKYY0o7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"pumpkins %>% \n",
|
||||
" is.na() %>% \n",
|
||||
" colSums()"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "ZRBWV6P9ZArL"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Muito melhor! Faltam alguns dados, mas talvez isso não seja relevante para a tarefa em questão. Vamos ver que tipo de análise adicional pode surgir.\n",
|
||||
"\n",
|
||||
"> Além dos conjuntos incríveis de pacotes e funções, o R possui uma documentação muito boa. Por exemplo, use `help(colSums)` ou `?colSums` para saber mais sobre a função.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "9gv-crB6ZD1Y"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 3. Dplyr: Uma Gramática para Manipulação de Dados\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/dplyr_wrangling.png\"\n",
|
||||
" width=\"569\"/>\n",
|
||||
" <figcaption>Ilustração por @allison_horst</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<!--<br/>Ilustração por \\@allison_horst-->\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "o4jLY5-VZO2C"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"[`dplyr`](https://dplyr.tidyverse.org/), um pacote do Tidyverse, é uma gramática de manipulação de dados que oferece um conjunto consistente de verbos para ajudar a resolver os desafios mais comuns de manipulação de dados. Nesta seção, vamos explorar alguns dos verbos do dplyr!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "i5o33MQBZWWw"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### dplyr::select()\n",
|
||||
"\n",
|
||||
"`select()` é uma função do pacote `dplyr` que ajuda a escolher colunas para manter ou excluir.\n",
|
||||
"\n",
|
||||
"Para tornar o seu data frame mais fácil de trabalhar, elimine várias das suas colunas, utilizando `select()`, mantendo apenas as colunas necessárias.\n",
|
||||
"\n",
|
||||
"Por exemplo, neste exercício, a nossa análise irá envolver as colunas `Package`, `Low Price`, `High Price` e `Date`. Vamos selecionar estas colunas.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "x3VGMAGBZiUr"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Select desired columns\n",
|
||||
"pumpkins <- pumpkins %>% \n",
|
||||
" select(Package, `Low Price`, `High Price`, Date)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Print data set\n",
|
||||
"pumpkins %>% \n",
|
||||
" slice_head(n = 5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "F_FgxQnVZnM0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### dplyr::mutate()\n",
|
||||
"\n",
|
||||
"`mutate()` é uma função do pacote `dplyr` que ajuda a criar ou modificar colunas, mantendo as colunas existentes.\n",
|
||||
"\n",
|
||||
"A estrutura geral do `mutate` é:\n",
|
||||
"\n",
|
||||
"`data %>% mutate(new_column_name = what_it_contains)`\n",
|
||||
"\n",
|
||||
"Vamos experimentar o `mutate` utilizando a coluna `Date` e realizar as seguintes operações:\n",
|
||||
"\n",
|
||||
"1. Converter as datas (atualmente do tipo carácter) para um formato de mês (estas são datas dos EUA, então o formato é `MM/DD/YYYY`).\n",
|
||||
"\n",
|
||||
"2. Extrair o mês das datas para uma nova coluna.\n",
|
||||
"\n",
|
||||
"Em R, o pacote [lubridate](https://lubridate.tidyverse.org/) facilita o trabalho com dados de data e hora. Então, vamos usar `dplyr::mutate()`, `lubridate::mdy()`, `lubridate::month()` e ver como alcançar os objetivos acima. Podemos eliminar a coluna `Date`, já que não será mais necessária em operações subsequentes.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "2KKo0Ed9Z1VB"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Load lubridate\n",
|
||||
"library(lubridate)\n",
|
||||
"\n",
|
||||
"pumpkins <- pumpkins %>% \n",
|
||||
" # Convert the Date column to a date object\n",
|
||||
" mutate(Date = mdy(Date)) %>% \n",
|
||||
" # Extract month from Date\n",
|
||||
" mutate(Month = month(Date)) %>% \n",
|
||||
" # Drop Date column\n",
|
||||
" select(-Date)\n",
|
||||
"\n",
|
||||
"# View the first few rows\n",
|
||||
"pumpkins %>% \n",
|
||||
" slice_head(n = 7)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "5joszIVSZ6xe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Uhuu! 🤩\n",
|
||||
"\n",
|
||||
"A seguir, vamos criar uma nova coluna `Price`, que representa o preço médio de uma abóbora. Agora, vamos calcular a média das colunas `Low Price` e `High Price` para preencher a nova coluna Price.\n",
|
||||
"<br>\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "nIgLjNMCZ-6Y"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Create a new column Price\n",
|
||||
"pumpkins <- pumpkins %>% \n",
|
||||
" mutate(Price = (`Low Price` + `High Price`)/2)\n",
|
||||
"\n",
|
||||
"# View the first few rows of the data\n",
|
||||
"pumpkins %>% \n",
|
||||
" slice_head(n = 5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "Zo0BsqqtaJw2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Sim!💪\n",
|
||||
"\n",
|
||||
"\"Mas espera aí!\", dirás depois de examinar todo o conjunto de dados com `View(pumpkins)`, \"Há algo estranho aqui!\"🤔\n",
|
||||
"\n",
|
||||
"Se olhares para a coluna `Package`, as abóboras são vendidas em várias configurações diferentes. Algumas são vendidas em medidas de `1 1/9 bushel`, outras em medidas de `1/2 bushel`, algumas por abóbora, outras por peso, e algumas em grandes caixas com larguras variadas.\n",
|
||||
"\n",
|
||||
"Vamos verificar isto:\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "p77WZr-9aQAR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Verify the distinct observations in Package column\n",
|
||||
"pumpkins %>% \n",
|
||||
" distinct(Package)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "XISGfh0IaUy6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Incrível!👏\n",
|
||||
"\n",
|
||||
"As abóboras parecem ser muito difíceis de pesar de forma consistente, por isso vamos filtrá-las selecionando apenas as abóboras com a palavra *bushel* na coluna `Package` e colocar isso num novo quadro de dados `new_pumpkins`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "7sMjiVujaZxY"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### dplyr::filter() e stringr::str_detect()\n",
|
||||
"\n",
|
||||
"[`dplyr::filter()`](https://dplyr.tidyverse.org/reference/filter.html): cria um subconjunto dos dados contendo apenas as **linhas** que satisfazem as suas condições, neste caso, abóboras com a string *bushel* na coluna `Package`.\n",
|
||||
"\n",
|
||||
"[stringr::str_detect()](https://stringr.tidyverse.org/reference/str_detect.html): deteta a presença ou ausência de um padrão numa string.\n",
|
||||
"\n",
|
||||
"O pacote [`stringr`](https://github.com/tidyverse/stringr) fornece funções simples para operações comuns com strings.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "L8Qfcs92ageF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Retain only pumpkins with \"bushel\"\n",
|
||||
"new_pumpkins <- pumpkins %>% \n",
|
||||
" filter(str_detect(Package, \"bushel\"))\n",
|
||||
"\n",
|
||||
"# Get the dimensions of the new data\n",
|
||||
"dim(new_pumpkins)\n",
|
||||
"\n",
|
||||
"# View a few rows of the new data\n",
|
||||
"new_pumpkins %>% \n",
|
||||
" slice_head(n = 5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "hy_SGYREampd"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Pode ver que reduzimos para cerca de 415 linhas de dados contendo abóboras por alqueire.🤩 \n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "VrDwF031avlR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"#### dplyr::case_when()\n",
|
||||
"\n",
|
||||
"**Mas espera! Ainda há algo mais a fazer**\n",
|
||||
"\n",
|
||||
"Reparaste que a quantidade por alqueire varia por linha? É necessário normalizar os preços para que sejam apresentados por alqueire, e não por 1 1/9 ou 1/2 alqueire. Está na hora de fazer alguns cálculos para os padronizar.\n",
|
||||
"\n",
|
||||
"Vamos usar a função [`case_when()`](https://dplyr.tidyverse.org/reference/case_when.html) para *alterar* a coluna Price com base em algumas condições. `case_when` permite vectorizar múltiplas instruções `if_else()`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "mLpw2jH4a0tx"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Convert the price if the Package contains fractional bushel values\n",
|
||||
"new_pumpkins <- new_pumpkins %>% \n",
|
||||
" mutate(Price = case_when(\n",
|
||||
" str_detect(Package, \"1 1/9\") ~ Price/(1 + 1/9),\n",
|
||||
" str_detect(Package, \"1/2\") ~ Price/(1/2),\n",
|
||||
" TRUE ~ Price))\n",
|
||||
"\n",
|
||||
"# View the first few rows of the data\n",
|
||||
"new_pumpkins %>% \n",
|
||||
" slice_head(n = 30)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "P68kLVQmbM6I"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Agora podemos analisar o preço por unidade com base na sua medida em alqueires. Todo este estudo sobre alqueires de abóboras, no entanto, mostra como é `importante` `compreender a natureza dos seus dados`!\n",
|
||||
"\n",
|
||||
"> ✅ De acordo com [The Spruce Eats](https://www.thespruceeats.com/how-much-is-a-bushel-1389308), o peso de um alqueire depende do tipo de produto, já que é uma medida de volume. \"Um alqueire de tomates, por exemplo, deve pesar 56 libras... Folhas e verduras ocupam mais espaço com menos peso, então um alqueire de espinafre pesa apenas 20 libras.\" É tudo bastante complicado! Não vamos nos preocupar em fazer uma conversão de alqueires para libras e, em vez disso, vamos precificar por alqueire. Todo este estudo sobre alqueires de abóboras, no entanto, mostra como é muito importante compreender a natureza dos seus dados!\n",
|
||||
">\n",
|
||||
"> ✅ Reparaste que as abóboras vendidas por meio alqueire são muito caras? Consegues descobrir porquê? Dica: abóboras pequenas são muito mais caras do que as grandes, provavelmente porque há muito mais delas por alqueire, considerando o espaço não utilizado ocupado por uma grande abóbora oca para tartes.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "pS2GNPagbSdb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Agora, por pura diversão 💁♀️, vamos também mover a coluna Mês para a primeira posição, ou seja, `antes` da coluna `Pacote`.\n",
|
||||
"\n",
|
||||
"`dplyr::relocate()` é usado para alterar as posições das colunas.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "qql1SowfbdnP"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Create a new data frame new_pumpkins\n",
|
||||
"new_pumpkins <- new_pumpkins %>% \n",
|
||||
" relocate(Month, .before = Package)\n",
|
||||
"\n",
|
||||
"new_pumpkins %>% \n",
|
||||
" slice_head(n = 7)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "JJ1x6kw8bixF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Bom trabalho!👌 Agora tens um conjunto de dados limpo e organizado para construir o teu novo modelo de regressão!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "y8TJ0Za_bn5Y"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## 4. Visualização de dados com ggplot2\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/data-visualization.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Infografia por Dasani Madipalli</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<!--{width=\"600\"}-->\n",
|
||||
"\n",
|
||||
"Há um ditado *sábio* que diz o seguinte:\n",
|
||||
"\n",
|
||||
"> \"O gráfico simples trouxe mais informação à mente do analista de dados do que qualquer outro dispositivo.\" --- John Tukey\n",
|
||||
"\n",
|
||||
"Parte do papel do cientista de dados é demonstrar a qualidade e a natureza dos dados com os quais está a trabalhar. Para isso, muitas vezes criam visualizações interessantes, ou gráficos, diagramas e tabelas, que mostram diferentes aspetos dos dados. Desta forma, conseguem mostrar visualmente relações e lacunas que, de outra forma, seriam difíceis de identificar.\n",
|
||||
"\n",
|
||||
"As visualizações também podem ajudar a determinar a técnica de machine learning mais adequada para os dados. Um gráfico de dispersão que parece seguir uma linha, por exemplo, indica que os dados são bons candidatos para um exercício de regressão linear.\n",
|
||||
"\n",
|
||||
"O R oferece vários sistemas para criar gráficos, mas o [`ggplot2`](https://ggplot2.tidyverse.org/index.html) é um dos mais elegantes e versáteis. O `ggplot2` permite compor gráficos **combinando componentes independentes**.\n",
|
||||
"\n",
|
||||
"Vamos começar com um simples gráfico de dispersão para as colunas Price e Month.\n",
|
||||
"\n",
|
||||
"Neste caso, começaremos com [`ggplot()`](https://ggplot2.tidyverse.org/reference/ggplot.html), fornecendo um conjunto de dados e um mapeamento estético (com [`aes()`](https://ggplot2.tidyverse.org/reference/aes.html)) e, em seguida, adicionaremos camadas (como [`geom_point()`](https://ggplot2.tidyverse.org/reference/geom_point.html)) para gráficos de dispersão.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "mYSH6-EtbvNa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Set a theme for the plots\n",
|
||||
"theme_set(theme_light())\n",
|
||||
"\n",
|
||||
"# Create a scatter plot\n",
|
||||
"p <- ggplot(data = new_pumpkins, aes(x = Price, y = Month))\n",
|
||||
"p + geom_point()"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "g2YjnGeOcLo4"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"É um gráfico útil 🤷? Há algo nele que te surpreenda?\n",
|
||||
"\n",
|
||||
"Não é particularmente útil, pois tudo o que faz é mostrar os teus dados como uma dispersão de pontos num determinado mês.\n",
|
||||
"<br>\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Ml7SDCLQcPvE"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"### **Como torná-lo útil?**\n",
|
||||
"\n",
|
||||
"Para que os gráficos exibam dados úteis, normalmente é necessário agrupar os dados de alguma forma. Por exemplo, no nosso caso, calcular o preço médio das abóboras para cada mês proporcionaria mais insights sobre os padrões subjacentes nos nossos dados. Isso leva-nos a mais uma abordagem rápida do **dplyr**:\n",
|
||||
"\n",
|
||||
"#### `dplyr::group_by() %>% summarize()`\n",
|
||||
"\n",
|
||||
"A agregação agrupada em R pode ser facilmente calculada usando\n",
|
||||
"\n",
|
||||
"`dplyr::group_by() %>% summarize()`\n",
|
||||
"\n",
|
||||
"- `dplyr::group_by()` altera a unidade de análise do conjunto de dados completo para grupos individuais, como por mês.\n",
|
||||
"\n",
|
||||
"- `dplyr::summarize()` cria um novo data frame com uma coluna para cada variável de agrupamento e uma coluna para cada estatística resumida que especificares.\n",
|
||||
"\n",
|
||||
"Por exemplo, podemos usar `dplyr::group_by() %>% summarize()` para agrupar as abóboras com base na coluna **Month** e, em seguida, calcular o **preço médio** para cada mês.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "jMakvJZIcVkh"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Find the average price of pumpkins per month\r\n",
|
||||
"new_pumpkins %>%\r\n",
|
||||
" group_by(Month) %>% \r\n",
|
||||
" summarise(mean_price = mean(Price))"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "6kVSUa2Bcilf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Sucinto!✨\n",
|
||||
"\n",
|
||||
"Características categóricas, como meses, são melhor representadas utilizando um gráfico de barras 📊. As camadas responsáveis pelos gráficos de barras são `geom_bar()` e `geom_col()`. Consulte `?geom_bar` para saber mais.\n",
|
||||
"\n",
|
||||
"Vamos criar um agora!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Kds48GUBcj3W"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Find the average price of pumpkins per month then plot a bar chart\r\n",
|
||||
"new_pumpkins %>%\r\n",
|
||||
" group_by(Month) %>% \r\n",
|
||||
" summarise(mean_price = mean(Price)) %>% \r\n",
|
||||
" ggplot(aes(x = Month, y = mean_price)) +\r\n",
|
||||
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
|
||||
" ylab(\"Pumpkin Price\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "VNbU1S3BcrxO"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"🤩🤩Esta é uma visualização de dados mais útil! Parece indicar que o preço mais alto das abóboras ocorre em setembro e outubro. Isso corresponde às suas expectativas? Porquê ou porquê não?\n",
|
||||
"\n",
|
||||
"Parabéns por concluir a segunda lição 👏! Preparou os seus dados para a construção do modelo e, em seguida, descobriu mais informações através de visualizações!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "zDm0VOzzcuzR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,16 @@
|
||||
# Criar um Modelo de Regressão
|
||||
|
||||
## Instruções
|
||||
|
||||
Nesta lição, foi mostrado como construir um modelo utilizando Regressão Linear e Polinomial. Com base nesse conhecimento, encontre um conjunto de dados ou utilize um dos conjuntos integrados do Scikit-learn para criar um novo modelo. Explique no seu notebook por que escolheu a técnica utilizada e demonstre a precisão do seu modelo. Caso não seja preciso, explique o motivo.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critério | Exemplar | Adequado | Precisa de Melhorias |
|
||||
| -------- | ----------------------------------------------------------- | -------------------------- | -------------------------------- |
|
||||
| | apresenta um notebook completo com uma solução bem documentada | a solução está incompleta | a solução apresenta falhas ou erros |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,128 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Preços de Abóboras\n",
|
||||
"\n",
|
||||
"Carregue as bibliotecas necessárias e o conjunto de dados. Converta os dados para um dataframe contendo um subconjunto dos dados:\n",
|
||||
"\n",
|
||||
"- Obtenha apenas abóboras com preços por alqueire\n",
|
||||
"- Converta a data para um mês\n",
|
||||
"- Calcule o preço como uma média entre os preços altos e baixos\n",
|
||||
"- Converta o preço para refletir a quantidade por alqueire\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"import numpy as np\n",
|
||||
"from datetime import datetime\n",
|
||||
"\n",
|
||||
"pumpkins = pd.read_csv('../data/US-pumpkins.csv')\n",
|
||||
"\n",
|
||||
"pumpkins.head()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pumpkins = pumpkins[pumpkins['Package'].str.contains('bushel', case=True, regex=True)]\n",
|
||||
"\n",
|
||||
"columns_to_select = ['Package', 'Variety', 'City Name', 'Low Price', 'High Price', 'Date']\n",
|
||||
"pumpkins = pumpkins.loc[:, columns_to_select]\n",
|
||||
"\n",
|
||||
"price = (pumpkins['Low Price'] + pumpkins['High Price']) / 2\n",
|
||||
"\n",
|
||||
"month = pd.DatetimeIndex(pumpkins['Date']).month\n",
|
||||
"day_of_year = pd.to_datetime(pumpkins['Date']).apply(lambda dt: (dt-datetime(dt.year,1,1)).days)\n",
|
||||
"\n",
|
||||
"new_pumpkins = pd.DataFrame(\n",
|
||||
" {'Month': month, \n",
|
||||
" 'DayOfYear' : day_of_year, \n",
|
||||
" 'Variety': pumpkins['Variety'], \n",
|
||||
" 'City': pumpkins['City Name'], \n",
|
||||
" 'Package': pumpkins['Package'], \n",
|
||||
" 'Low Price': pumpkins['Low Price'],\n",
|
||||
" 'High Price': pumpkins['High Price'], \n",
|
||||
" 'Price': price})\n",
|
||||
"\n",
|
||||
"new_pumpkins.loc[new_pumpkins['Package'].str.contains('1 1/9'), 'Price'] = price/1.1\n",
|
||||
"new_pumpkins.loc[new_pumpkins['Package'].str.contains('1/2'), 'Price'] = price*2\n",
|
||||
"\n",
|
||||
"new_pumpkins.head()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Um gráfico de dispersão básico lembra-nos que só temos dados mensais de agosto a dezembro. Provavelmente precisamos de mais dados para conseguir tirar conclusões de forma linear.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"plt.scatter('Month','Price',data=new_pumpkins)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"plt.scatter('DayOfYear','Price',data=new_pumpkins)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.3-final"
|
||||
},
|
||||
"orig_nbformat": 2,
|
||||
"coopTranslator": {
|
||||
"original_hash": "b032d371c75279373507f003439a577e",
|
||||
"translation_date": "2025-09-03T19:16:20+00:00",
|
||||
"source_file": "2-Regression/3-Linear/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -0,0 +1,406 @@
|
||||
# Regressão logística para prever categorias
|
||||
|
||||

|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
> ### [Esta lição está disponível em R!](../../../../2-Regression/4-Logistic/solution/R/lesson_4.html)
|
||||
|
||||
## Introdução
|
||||
|
||||
Nesta última lição sobre Regressão, uma das técnicas básicas _clássicas_ de ML, vamos explorar a Regressão Logística. Esta técnica é usada para descobrir padrões e prever categorias binárias. Este doce é chocolate ou não? Esta doença é contagiosa ou não? Este cliente vai escolher este produto ou não?
|
||||
|
||||
Nesta lição, você aprenderá:
|
||||
|
||||
- Uma nova biblioteca para visualização de dados
|
||||
- Técnicas de regressão logística
|
||||
|
||||
✅ Aprofunde seu entendimento sobre como trabalhar com este tipo de regressão neste [módulo de aprendizado](https://docs.microsoft.com/learn/modules/train-evaluate-classification-models?WT.mc_id=academic-77952-leestott)
|
||||
|
||||
## Pré-requisito
|
||||
|
||||
Depois de trabalhar com os dados de abóbora, já estamos suficientemente familiarizados para perceber que há uma categoria binária com a qual podemos trabalhar: `Color`.
|
||||
|
||||
Vamos construir um modelo de regressão logística para prever, com base em algumas variáveis, _qual é a cor provável de uma abóbora_ (laranja 🎃 ou branca 👻).
|
||||
|
||||
> Por que estamos falando de classificação binária em uma lição sobre regressão? Apenas por conveniência linguística, já que a regressão logística é [na verdade um método de classificação](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), embora baseado em linearidade. Aprenda sobre outras formas de classificar dados no próximo grupo de lições.
|
||||
|
||||
## Definir a questão
|
||||
|
||||
Para nossos propósitos, vamos expressar isso como um binário: 'Branca' ou 'Não Branca'. Há também uma categoria 'listrada' em nosso conjunto de dados, mas há poucos exemplos dela, então não a utilizaremos. Ela desaparece quando removemos os valores nulos do conjunto de dados, de qualquer forma.
|
||||
|
||||
> 🎃 Curiosidade: às vezes chamamos as abóboras brancas de abóboras 'fantasma'. Elas não são muito fáceis de esculpir, então não são tão populares quanto as laranjas, mas têm um visual interessante! Assim, poderíamos reformular nossa questão como: 'Fantasma' ou 'Não Fantasma'. 👻
|
||||
|
||||
## Sobre regressão logística
|
||||
|
||||
A regressão logística difere da regressão linear, que você aprendeu anteriormente, em alguns aspectos importantes.
|
||||
|
||||
[](https://youtu.be/KpeCT6nEpBY "ML para iniciantes - Entendendo a Regressão Logística para Classificação de Machine Learning")
|
||||
|
||||
> 🎥 Clique na imagem acima para um breve vídeo sobre regressão logística.
|
||||
|
||||
### Classificação binária
|
||||
|
||||
A regressão logística não oferece os mesmos recursos que a regressão linear. A primeira oferece uma previsão sobre uma categoria binária ("branca ou não branca"), enquanto a segunda é capaz de prever valores contínuos, por exemplo, dado a origem de uma abóbora e o tempo de colheita, _quanto seu preço vai aumentar_.
|
||||
|
||||

|
||||
> Infográfico por [Dasani Madipalli](https://twitter.com/dasani_decoded)
|
||||
|
||||
### Outras classificações
|
||||
|
||||
Existem outros tipos de regressão logística, incluindo multinomial e ordinal:
|
||||
|
||||
- **Multinomial**, que envolve mais de uma categoria - "Laranja, Branca e Listrada".
|
||||
- **Ordinal**, que envolve categorias ordenadas, útil se quisermos ordenar nossos resultados logicamente, como nossas abóboras que são ordenadas por um número finito de tamanhos (mini,pequeno,médio,grande,xl,xxl).
|
||||
|
||||

|
||||
|
||||
### As variáveis NÃO precisam ser correlacionadas
|
||||
|
||||
Lembra como a regressão linear funcionava melhor com variáveis mais correlacionadas? A regressão logística é o oposto - as variáveis não precisam estar alinhadas. Isso funciona para este conjunto de dados, que tem correlações relativamente fracas.
|
||||
|
||||
### Você precisa de muitos dados limpos
|
||||
|
||||
A regressão logística fornecerá resultados mais precisos se você usar mais dados; nosso pequeno conjunto de dados não é ideal para esta tarefa, então tenha isso em mente.
|
||||
|
||||
[](https://youtu.be/B2X4H9vcXTs "ML para iniciantes - Análise e Preparação de Dados para Regressão Logística")
|
||||
|
||||
> 🎥 Clique na imagem acima para um breve vídeo sobre preparação de dados para regressão linear.
|
||||
|
||||
✅ Pense nos tipos de dados que se adaptariam bem à regressão logística.
|
||||
|
||||
## Exercício - organizar os dados
|
||||
|
||||
Primeiro, limpe os dados, removendo valores nulos e selecionando apenas algumas colunas:
|
||||
|
||||
1. Adicione o seguinte código:
|
||||
|
||||
```python
|
||||
|
||||
columns_to_select = ['City Name','Package','Variety', 'Origin','Item Size', 'Color']
|
||||
pumpkins = full_pumpkins.loc[:, columns_to_select]
|
||||
|
||||
pumpkins.dropna(inplace=True)
|
||||
```
|
||||
|
||||
Você sempre pode dar uma olhada no seu novo dataframe:
|
||||
|
||||
```python
|
||||
pumpkins.info
|
||||
```
|
||||
|
||||
### Visualização - gráfico categórico
|
||||
|
||||
Agora que você carregou o [notebook inicial](../../../../2-Regression/4-Logistic/notebook.ipynb) com os dados de abóbora novamente e os limpou para preservar um conjunto de dados contendo algumas variáveis, incluindo `Color`, vamos visualizar o dataframe no notebook usando uma biblioteca diferente: [Seaborn](https://seaborn.pydata.org/index.html), que é construída sobre o Matplotlib que usamos anteriormente.
|
||||
|
||||
Seaborn oferece algumas maneiras interessantes de visualizar seus dados. Por exemplo, você pode comparar distribuições dos dados para cada `Variety` e `Color` em um gráfico categórico.
|
||||
|
||||
1. Crie tal gráfico usando a função `catplot`, com os dados de abóbora `pumpkins`, e especificando um mapeamento de cores para cada categoria de abóbora (laranja ou branca):
|
||||
|
||||
```python
|
||||
import seaborn as sns
|
||||
|
||||
palette = {
|
||||
'ORANGE': 'orange',
|
||||
'WHITE': 'wheat',
|
||||
}
|
||||
|
||||
sns.catplot(
|
||||
data=pumpkins, y="Variety", hue="Color", kind="count",
|
||||
palette=palette,
|
||||
)
|
||||
```
|
||||
|
||||

|
||||
|
||||
Observando os dados, você pode ver como os dados de `Color` se relacionam com `Variety`.
|
||||
|
||||
✅ Dado este gráfico categórico, quais são algumas explorações interessantes que você pode imaginar?
|
||||
|
||||
### Pré-processamento de dados: codificação de características e rótulos
|
||||
|
||||
Nosso conjunto de dados de abóboras contém valores de string em todas as suas colunas. Trabalhar com dados categóricos é intuitivo para humanos, mas não para máquinas. Algoritmos de aprendizado de máquina funcionam bem com números. Por isso, a codificação é uma etapa muito importante na fase de pré-processamento de dados, pois permite transformar dados categóricos em dados numéricos, sem perder informações. Uma boa codificação leva à construção de um bom modelo.
|
||||
|
||||
Para codificação de características, existem dois tipos principais de codificadores:
|
||||
|
||||
1. Codificador ordinal: é adequado para variáveis ordinais, que são variáveis categóricas cujos dados seguem uma ordem lógica, como a coluna `Item Size` em nosso conjunto de dados. Ele cria um mapeamento em que cada categoria é representada por um número, que é a ordem da categoria na coluna.
|
||||
|
||||
```python
|
||||
from sklearn.preprocessing import OrdinalEncoder
|
||||
|
||||
item_size_categories = [['sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo']]
|
||||
ordinal_features = ['Item Size']
|
||||
ordinal_encoder = OrdinalEncoder(categories=item_size_categories)
|
||||
```
|
||||
|
||||
2. Codificador categórico: é adequado para variáveis nominais, que são variáveis categóricas cujos dados não seguem uma ordem lógica, como todas as características diferentes de `Item Size` em nosso conjunto de dados. É uma codificação one-hot, o que significa que cada categoria é representada por uma coluna binária: a variável codificada é igual a 1 se a abóbora pertence àquela `Variety` e 0 caso contrário.
|
||||
|
||||
```python
|
||||
from sklearn.preprocessing import OneHotEncoder
|
||||
|
||||
categorical_features = ['City Name', 'Package', 'Variety', 'Origin']
|
||||
categorical_encoder = OneHotEncoder(sparse_output=False)
|
||||
```
|
||||
|
||||
Então, `ColumnTransformer` é usado para combinar múltiplos codificadores em uma única etapa e aplicá-los às colunas apropriadas.
|
||||
|
||||
```python
|
||||
from sklearn.compose import ColumnTransformer
|
||||
|
||||
ct = ColumnTransformer(transformers=[
|
||||
('ord', ordinal_encoder, ordinal_features),
|
||||
('cat', categorical_encoder, categorical_features)
|
||||
])
|
||||
|
||||
ct.set_output(transform='pandas')
|
||||
encoded_features = ct.fit_transform(pumpkins)
|
||||
```
|
||||
|
||||
Por outro lado, para codificar o rótulo, usamos a classe `LabelEncoder` do scikit-learn, que é uma classe utilitária para ajudar a normalizar rótulos de forma que contenham apenas valores entre 0 e n_classes-1 (aqui, 0 e 1).
|
||||
|
||||
```python
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
|
||||
label_encoder = LabelEncoder()
|
||||
encoded_label = label_encoder.fit_transform(pumpkins['Color'])
|
||||
```
|
||||
|
||||
Depois de codificar as características e o rótulo, podemos mesclá-los em um novo dataframe `encoded_pumpkins`.
|
||||
|
||||
```python
|
||||
encoded_pumpkins = encoded_features.assign(Color=encoded_label)
|
||||
```
|
||||
|
||||
✅ Quais são as vantagens de usar um codificador ordinal para a coluna `Item Size`?
|
||||
|
||||
### Analisar relações entre variáveis
|
||||
|
||||
Agora que pré-processamos nossos dados, podemos analisar as relações entre as características e o rótulo para ter uma ideia de quão bem o modelo será capaz de prever o rótulo com base nas características.
|
||||
|
||||
A melhor maneira de realizar esse tipo de análise é plotando os dados. Usaremos novamente a função `catplot` do Seaborn para visualizar as relações entre `Item Size`, `Variety` e `Color` em um gráfico categórico. Para melhor plotar os dados, usaremos a coluna codificada `Item Size` e a coluna não codificada `Variety`.
|
||||
|
||||
```python
|
||||
palette = {
|
||||
'ORANGE': 'orange',
|
||||
'WHITE': 'wheat',
|
||||
}
|
||||
pumpkins['Item Size'] = encoded_pumpkins['ord__Item Size']
|
||||
|
||||
g = sns.catplot(
|
||||
data=pumpkins,
|
||||
x="Item Size", y="Color", row='Variety',
|
||||
kind="box", orient="h",
|
||||
sharex=False, margin_titles=True,
|
||||
height=1.8, aspect=4, palette=palette,
|
||||
)
|
||||
g.set(xlabel="Item Size", ylabel="").set(xlim=(0,6))
|
||||
g.set_titles(row_template="{row_name}")
|
||||
```
|
||||
|
||||

|
||||
|
||||
### Usar um gráfico de dispersão
|
||||
|
||||
Como `Color` é uma categoria binária (Branca ou Não), ela precisa de '[uma abordagem especializada](https://seaborn.pydata.org/tutorial/categorical.html?highlight=bar) para visualização'. Existem outras maneiras de visualizar a relação dessa categoria com outras variáveis.
|
||||
|
||||
Você pode visualizar variáveis lado a lado com gráficos do Seaborn.
|
||||
|
||||
1. Experimente um gráfico de dispersão ('swarm') para mostrar a distribuição de valores:
|
||||
|
||||
```python
|
||||
palette = {
|
||||
0: 'orange',
|
||||
1: 'wheat'
|
||||
}
|
||||
sns.swarmplot(x="Color", y="ord__Item Size", data=encoded_pumpkins, palette=palette)
|
||||
```
|
||||
|
||||

|
||||
|
||||
**Atenção**: o código acima pode gerar um aviso, já que o Seaborn pode falhar ao representar uma quantidade tão grande de pontos de dados em um gráfico de dispersão. Uma solução possível é diminuir o tamanho do marcador, usando o parâmetro 'size'. No entanto, esteja ciente de que isso afeta a legibilidade do gráfico.
|
||||
|
||||
> **🧮 Mostre-me a Matemática**
|
||||
>
|
||||
> A regressão logística baseia-se no conceito de 'máxima verossimilhança' usando [funções sigmoides](https://wikipedia.org/wiki/Sigmoid_function). Uma 'Função Sigmoide' em um gráfico tem a forma de um 'S'. Ela pega um valor e o mapeia para algo entre 0 e 1. Sua curva também é chamada de 'curva logística'. Sua fórmula é assim:
|
||||
>
|
||||
> 
|
||||
>
|
||||
> onde o ponto médio da sigmoide encontra-se no ponto 0 de x, L é o valor máximo da curva, e k é a inclinação da curva. Se o resultado da função for maior que 0.5, o rótulo em questão será atribuído à classe '1' da escolha binária. Caso contrário, será classificado como '0'.
|
||||
|
||||
## Construir seu modelo
|
||||
|
||||
Construir um modelo para encontrar essas classificações binárias é surpreendentemente simples no Scikit-learn.
|
||||
|
||||
[](https://youtu.be/MmZS2otPrQ8 "ML para iniciantes - Regressão Logística para classificação de dados")
|
||||
|
||||
> 🎥 Clique na imagem acima para um breve vídeo sobre construção de um modelo de regressão linear.
|
||||
|
||||
1. Selecione as variáveis que deseja usar em seu modelo de classificação e divida os conjuntos de treinamento e teste chamando `train_test_split()`:
|
||||
|
||||
```python
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
X = encoded_pumpkins[encoded_pumpkins.columns.difference(['Color'])]
|
||||
y = encoded_pumpkins['Color']
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
|
||||
|
||||
```
|
||||
|
||||
2. Agora você pode treinar seu modelo, chamando `fit()` com seus dados de treinamento, e imprimir o resultado:
|
||||
|
||||
```python
|
||||
from sklearn.metrics import f1_score, classification_report
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
|
||||
model = LogisticRegression()
|
||||
model.fit(X_train, y_train)
|
||||
predictions = model.predict(X_test)
|
||||
|
||||
print(classification_report(y_test, predictions))
|
||||
print('Predicted labels: ', predictions)
|
||||
print('F1-score: ', f1_score(y_test, predictions))
|
||||
```
|
||||
|
||||
Veja o desempenho do seu modelo. Não está ruim, considerando que você tem apenas cerca de 1000 linhas de dados:
|
||||
|
||||
```output
|
||||
precision recall f1-score support
|
||||
|
||||
0 0.94 0.98 0.96 166
|
||||
1 0.85 0.67 0.75 33
|
||||
|
||||
accuracy 0.92 199
|
||||
macro avg 0.89 0.82 0.85 199
|
||||
weighted avg 0.92 0.92 0.92 199
|
||||
|
||||
Predicted labels: [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 0
|
||||
0 0 0 0 0 1 0 1 0 0 1 0 0 0 0 0 1 0 1 0 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 0 0 0 1 1 0
|
||||
0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
|
||||
0 0 0 1 0 0 0 0 0 0 0 0 1 1]
|
||||
F1-score: 0.7457627118644068
|
||||
```
|
||||
|
||||
## Melhor compreensão via uma matriz de confusão
|
||||
|
||||
Embora você possa obter um relatório de desempenho [termos](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.classification_report.html?highlight=classification_report#sklearn.metrics.classification_report) imprimindo os itens acima, talvez consiga entender melhor seu modelo usando uma [matriz de confusão](https://scikit-learn.org/stable/modules/model_evaluation.html#confusion-matrix) para ajudar a avaliar como o modelo está se saindo.
|
||||
|
||||
> 🎓 Uma '[matriz de confusão](https://wikipedia.org/wiki/Confusion_matrix)' (ou 'matriz de erro') é uma tabela que expressa os verdadeiros vs. falsos positivos e negativos do seu modelo, avaliando assim a precisão das previsões.
|
||||
|
||||
1. Para usar uma matriz de confusão, chame `confusion_matrix()`:
|
||||
|
||||
```python
|
||||
from sklearn.metrics import confusion_matrix
|
||||
confusion_matrix(y_test, predictions)
|
||||
```
|
||||
|
||||
Veja a matriz de confusão do seu modelo:
|
||||
|
||||
```output
|
||||
array([[162, 4],
|
||||
[ 11, 22]])
|
||||
```
|
||||
|
||||
No Scikit-learn, as linhas (eixo 0) são os rótulos reais e as colunas (eixo 1) são os rótulos previstos.
|
||||
|
||||
| | 0 | 1 |
|
||||
| :---: | :---: | :---: |
|
||||
| 0 | TN | FP |
|
||||
| 1 | FN | TP |
|
||||
|
||||
O que está acontecendo aqui? Digamos que nosso modelo seja solicitado a classificar abóboras entre duas categorias binárias, categoria 'branca' e categoria 'não branca'.
|
||||
|
||||
- Se o modelo prevê uma abóbora como não branca e ela realmente pertence à categoria 'não branca', chamamos isso de verdadeiro negativo, mostrado pelo número no canto superior esquerdo.
|
||||
- Se o modelo prevê uma abóbora como branca e ela realmente pertence à categoria 'não branca', chamamos isso de falso negativo, mostrado pelo número no canto inferior esquerdo.
|
||||
- Se o modelo prevê uma abóbora como não branca e ela realmente pertence à categoria 'branca', chamamos isso de falso positivo, mostrado pelo número no canto superior direito.
|
||||
- Se o modelo prevê uma abóbora como branca e ela realmente pertence à categoria 'branca', chamamos isso de verdadeiro positivo, mostrado pelo número no canto inferior direito.
|
||||
|
||||
Como você deve ter imaginado, é preferível ter um número maior de verdadeiros positivos e verdadeiros negativos e um número menor de falsos positivos e falsos negativos, o que implica que o modelo está se saindo melhor.
|
||||
Como é que a matriz de confusão se relaciona com a precisão e o recall? Lembra-te, o relatório de classificação impresso acima mostrou precisão (0,85) e recall (0,67).
|
||||
|
||||
Precisão = tp / (tp + fp) = 22 / (22 + 4) = 0,8461538461538461
|
||||
|
||||
Recall = tp / (tp + fn) = 22 / (22 + 11) = 0,6666666666666666
|
||||
|
||||
✅ P: De acordo com a matriz de confusão, como se saiu o modelo? R: Não foi mau; há um bom número de verdadeiros negativos, mas também alguns falsos negativos.
|
||||
|
||||
Vamos rever os termos que vimos anteriormente com a ajuda do mapeamento TP/TN e FP/FN da matriz de confusão:
|
||||
|
||||
🎓 Precisão: TP/(TP + FP) A fração de instâncias relevantes entre as instâncias recuperadas (ex.: quais etiquetas foram bem classificadas)
|
||||
|
||||
🎓 Recall: TP/(TP + FN) A fração de instâncias relevantes que foram recuperadas, independentemente de terem sido bem classificadas ou não
|
||||
|
||||
🎓 f1-score: (2 * precisão * recall)/(precisão + recall) Uma média ponderada da precisão e do recall, sendo o melhor 1 e o pior 0
|
||||
|
||||
🎓 Suporte: O número de ocorrências de cada etiqueta recuperada
|
||||
|
||||
🎓 Precisão (Accuracy): (TP + TN)/(TP + TN + FP + FN) A percentagem de etiquetas previstas corretamente para uma amostra.
|
||||
|
||||
🎓 Macro Avg: O cálculo da média não ponderada das métricas para cada etiqueta, sem considerar o desequilíbrio entre etiquetas.
|
||||
|
||||
🎓 Weighted Avg: O cálculo da média das métricas para cada etiqueta, considerando o desequilíbrio entre etiquetas ao ponderá-las pelo seu suporte (o número de instâncias verdadeiras para cada etiqueta).
|
||||
|
||||
✅ Consegues pensar em qual métrica deves prestar atenção se quiseres que o teu modelo reduza o número de falsos negativos?
|
||||
|
||||
## Visualizar a curva ROC deste modelo
|
||||
|
||||
[](https://youtu.be/GApO575jTA0 "ML para principiantes - Análise do Desempenho da Regressão Logística com Curvas ROC")
|
||||
|
||||
|
||||
> 🎥 Clica na imagem acima para uma breve explicação sobre curvas ROC
|
||||
|
||||
Vamos fazer mais uma visualização para ver a chamada curva 'ROC':
|
||||
|
||||
```python
|
||||
from sklearn.metrics import roc_curve, roc_auc_score
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
%matplotlib inline
|
||||
|
||||
y_scores = model.predict_proba(X_test)
|
||||
fpr, tpr, thresholds = roc_curve(y_test, y_scores[:,1])
|
||||
|
||||
fig = plt.figure(figsize=(6, 6))
|
||||
plt.plot([0, 1], [0, 1], 'k--')
|
||||
plt.plot(fpr, tpr)
|
||||
plt.xlabel('False Positive Rate')
|
||||
plt.ylabel('True Positive Rate')
|
||||
plt.title('ROC Curve')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
Usando Matplotlib, desenha a [Curva Característica de Operação do Recetor](https://scikit-learn.org/stable/auto_examples/model_selection/plot_roc.html?highlight=roc) ou ROC do modelo. As curvas ROC são frequentemente usadas para obter uma visão do desempenho de um classificador em termos de verdadeiros positivos vs. falsos positivos. "As curvas ROC geralmente apresentam a taxa de verdadeiros positivos no eixo Y e a taxa de falsos positivos no eixo X." Assim, a inclinação da curva e o espaço entre a linha do meio e a curva são importantes: queres uma curva que rapidamente suba e ultrapasse a linha. No nosso caso, há falsos positivos no início, e depois a linha sobe e ultrapassa corretamente:
|
||||
|
||||

|
||||
|
||||
Por fim, usa a API [`roc_auc_score`](https://scikit-learn.org/stable/modules/generated/sklearn.metrics.roc_auc_score.html?highlight=roc_auc#sklearn.metrics.roc_auc_score) do Scikit-learn para calcular a 'Área Sob a Curva' (AUC):
|
||||
|
||||
```python
|
||||
auc = roc_auc_score(y_test,y_scores[:,1])
|
||||
print(auc)
|
||||
```
|
||||
O resultado é `0.9749908725812341`. Dado que o AUC varia de 0 a 1, queres um valor elevado, já que um modelo que acerta 100% nas suas previsões terá um AUC de 1; neste caso, o modelo é _bastante bom_.
|
||||
|
||||
Em futuras lições sobre classificações, vais aprender como iterar para melhorar os resultados do teu modelo. Mas, por agora, parabéns! Completaste estas lições sobre regressão!
|
||||
|
||||
---
|
||||
## 🚀Desafio
|
||||
|
||||
Há muito mais para explorar sobre regressão logística! Mas a melhor forma de aprender é experimentar. Encontra um conjunto de dados que se preste a este tipo de análise e constrói um modelo com ele. O que aprendes? dica: experimenta [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) para conjuntos de dados interessantes.
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Estudo Individual
|
||||
|
||||
Lê as primeiras páginas [deste artigo de Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) sobre alguns usos práticos da regressão logística. Pensa em tarefas que sejam mais adequadas para um ou outro tipo de regressão entre as que estudámos até agora. O que funcionaria melhor?
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Repetir esta regressão](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Repetir uma Regressão
|
||||
|
||||
## Instruções
|
||||
|
||||
Na aula, utilizaste um subconjunto dos dados de abóbora. Agora, volta aos dados originais e tenta usar todos eles, limpos e padronizados, para construir um modelo de Regressão Logística.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critério | Exemplar | Adequado | Necessita Melhorias |
|
||||
| --------- | ---------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------- |
|
||||
| | Um notebook é apresentado com um modelo bem explicado e com bom desempenho | Um notebook é apresentado com um modelo que tem desempenho mínimo | Um notebook é apresentado com um modelo de baixo desempenho ou nenhum |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,686 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Construir um modelo de regressão logística - Aula 4\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"#### **[Questionário pré-aula](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/15/)**\n",
|
||||
"\n",
|
||||
"#### Introdução\n",
|
||||
"\n",
|
||||
"Nesta última aula sobre Regressão, uma das técnicas básicas *clássicas* de ML, vamos explorar a Regressão Logística. Esta técnica é usada para descobrir padrões e prever categorias binárias. Este doce é chocolate ou não? Esta doença é contagiosa ou não? Este cliente vai escolher este produto ou não?\n",
|
||||
"\n",
|
||||
"Nesta aula, irá aprender:\n",
|
||||
"\n",
|
||||
"- Técnicas para regressão logística\n",
|
||||
"\n",
|
||||
"✅ Aprofunde o seu entendimento sobre como trabalhar com este tipo de regressão neste [módulo de aprendizagem](https://learn.microsoft.com/training/modules/introduction-classification-models/?WT.mc_id=academic-77952-leestott)\n",
|
||||
"\n",
|
||||
"## Pré-requisito\n",
|
||||
"\n",
|
||||
"Depois de trabalhar com os dados das abóboras, já estamos suficientemente familiarizados para perceber que há uma categoria binária com a qual podemos trabalhar: `Color`.\n",
|
||||
"\n",
|
||||
"Vamos construir um modelo de regressão logística para prever, com base em algumas variáveis, *qual é a cor provável de uma determinada abóbora* (laranja 🎃 ou branca 👻).\n",
|
||||
"\n",
|
||||
"> Por que estamos a falar de classificação binária numa aula sobre regressão? Apenas por conveniência linguística, já que a regressão logística é [na verdade um método de classificação](https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression), embora baseado em métodos lineares. Aprenda sobre outras formas de classificar dados no próximo grupo de aulas.\n",
|
||||
"\n",
|
||||
"Para esta aula, vamos precisar dos seguintes pacotes:\n",
|
||||
"\n",
|
||||
"- `tidyverse`: O [tidyverse](https://www.tidyverse.org/) é uma [coleção de pacotes R](https://www.tidyverse.org/packages) projetada para tornar a ciência de dados mais rápida, fácil e divertida!\n",
|
||||
"\n",
|
||||
"- `tidymodels`: O [tidymodels](https://www.tidymodels.org/) é uma [coleção de pacotes](https://www.tidymodels.org/packages/) para modelagem e aprendizagem automática.\n",
|
||||
"\n",
|
||||
"- `janitor`: O pacote [janitor](https://github.com/sfirke/janitor) oferece ferramentas simples para examinar e limpar dados desorganizados.\n",
|
||||
"\n",
|
||||
"- `ggbeeswarm`: O pacote [ggbeeswarm](https://github.com/eclarke/ggbeeswarm) fornece métodos para criar gráficos estilo \"beeswarm\" usando ggplot2.\n",
|
||||
"\n",
|
||||
"Pode instalá-los com o seguinte comando:\n",
|
||||
"\n",
|
||||
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"janitor\", \"ggbeeswarm\"))`\n",
|
||||
"\n",
|
||||
"Alternativamente, o script abaixo verifica se tem os pacotes necessários para completar este módulo e instala-os caso estejam em falta.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n",
|
||||
"\n",
|
||||
"pacman::p_load(tidyverse, tidymodels, janitor, ggbeeswarm)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## **Definir a pergunta**\n",
|
||||
"\n",
|
||||
"Para os nossos propósitos, vamos expressar isto como um binário: 'Branco' ou 'Não Branco'. Existe também uma categoria 'listado' no nosso conjunto de dados, mas há poucos exemplos dela, por isso não a utilizaremos. De qualquer forma, ela desaparece quando removemos os valores nulos do conjunto de dados.\n",
|
||||
"\n",
|
||||
"> 🎃 Curiosidade: às vezes chamamos as abóboras brancas de abóboras 'fantasma'. Elas não são muito fáceis de esculpir, por isso não são tão populares quanto as laranjas, mas têm um visual interessante! Assim, poderíamos reformular a nossa pergunta como: 'Fantasma' ou 'Não Fantasma'. 👻\n",
|
||||
"\n",
|
||||
"## **Sobre regressão logística**\n",
|
||||
"\n",
|
||||
"A regressão logística difere da regressão linear, que você aprendeu anteriormente, em alguns aspectos importantes.\n",
|
||||
"\n",
|
||||
"#### **Classificação binária**\n",
|
||||
"\n",
|
||||
"A regressão logística não oferece as mesmas funcionalidades que a regressão linear. A primeira fornece uma previsão sobre uma `categoria binária` (\"laranja ou não laranja\"), enquanto a segunda é capaz de prever `valores contínuos`, por exemplo, dado a origem de uma abóbora e o momento da colheita, *quanto o seu preço irá aumentar*.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Outras classificações\n",
|
||||
"\n",
|
||||
"Existem outros tipos de regressão logística, incluindo multinomial e ordinal:\n",
|
||||
"\n",
|
||||
"- **Multinomial**, que envolve mais de uma categoria - \"Laranja, Branco e Listado\".\n",
|
||||
"\n",
|
||||
"- **Ordinal**, que envolve categorias ordenadas, útil se quisermos organizar os resultados logicamente, como as nossas abóboras que são ordenadas por um número finito de tamanhos (mini,pequeno,médio,grande,xl,xxl).\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"#### **As variáveis NÃO precisam estar correlacionadas**\n",
|
||||
"\n",
|
||||
"Lembra como a regressão linear funcionava melhor com variáveis mais correlacionadas? A regressão logística é o oposto - as variáveis não precisam estar alinhadas. Isso funciona para este conjunto de dados, que tem correlações relativamente fracas.\n",
|
||||
"\n",
|
||||
"#### **Você precisa de muitos dados limpos**\n",
|
||||
"\n",
|
||||
"A regressão logística fornecerá resultados mais precisos se você usar mais dados; nosso pequeno conjunto de dados não é ideal para esta tarefa, então tenha isso em mente.\n",
|
||||
"\n",
|
||||
"✅ Pense nos tipos de dados que seriam adequados para regressão logística\n",
|
||||
"\n",
|
||||
"## Exercício - organizar os dados\n",
|
||||
"\n",
|
||||
"Primeiro, limpe os dados um pouco, removendo valores nulos e selecionando apenas algumas das colunas:\n",
|
||||
"\n",
|
||||
"1. Adicione o seguinte código:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load the core tidyverse packages\n",
|
||||
"library(tidyverse)\n",
|
||||
"\n",
|
||||
"# Import the data and clean column names\n",
|
||||
"pumpkins <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/2-Regression/data/US-pumpkins.csv\") %>% \n",
|
||||
" clean_names()\n",
|
||||
"\n",
|
||||
"# Select desired columns\n",
|
||||
"pumpkins_select <- pumpkins %>% \n",
|
||||
" select(c(city_name, package, variety, origin, item_size, color)) \n",
|
||||
"\n",
|
||||
"# Drop rows containing missing values and encode color as factor (category)\n",
|
||||
"pumpkins_select <- pumpkins_select %>% \n",
|
||||
" drop_na() %>% \n",
|
||||
" mutate(color = factor(color))\n",
|
||||
"\n",
|
||||
"# View the first few rows\n",
|
||||
"pumpkins_select %>% \n",
|
||||
" slice_head(n = 5)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Pode sempre dar uma olhadela ao seu novo dataframe utilizando a função [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html), como mostrado abaixo:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pumpkins_select %>% \n",
|
||||
" glimpse()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Vamos confirmar que, de facto, estaremos a resolver um problema de classificação binária:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Subset distinct observations in outcome column\n",
|
||||
"pumpkins_select %>% \n",
|
||||
" distinct(color)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Visualização - gráfico categórico\n",
|
||||
"Neste momento, já carregaste novamente os dados das abóboras e limpaste-os para preservar um conjunto de dados contendo algumas variáveis, incluindo Cor. Vamos visualizar o dataframe no notebook utilizando a biblioteca ggplot.\n",
|
||||
"\n",
|
||||
"A biblioteca ggplot oferece algumas formas interessantes de visualizar os teus dados. Por exemplo, podes comparar as distribuições dos dados para cada Variedade e Cor num gráfico categórico.\n",
|
||||
"\n",
|
||||
"1. Cria um gráfico deste tipo utilizando a função geombar, com os dados das abóboras, e especifica um mapeamento de cores para cada categoria de abóbora (laranja ou branca):\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "python"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Specify colors for each value of the hue variable\n",
|
||||
"palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n",
|
||||
"\n",
|
||||
"# Create the bar plot\n",
|
||||
"ggplot(pumpkins_select, aes(y = variety, fill = color)) +\n",
|
||||
" geom_bar(position = \"dodge\") +\n",
|
||||
" scale_fill_manual(values = palette) +\n",
|
||||
" labs(y = \"Variety\", fill = \"Color\") +\n",
|
||||
" theme_minimal()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Ao observar os dados, pode ver como os dados de Cor se relacionam com a Variedade.\n",
|
||||
"\n",
|
||||
"✅ Dado este gráfico categórico, que explorações interessantes consegue imaginar?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Pré-processamento de dados: codificação de características\n",
|
||||
"\n",
|
||||
"O nosso conjunto de dados de abóboras contém valores em formato de texto para todas as suas colunas. Trabalhar com dados categóricos é intuitivo para humanos, mas não para máquinas. Os algoritmos de aprendizagem automática funcionam bem com números. É por isso que a codificação é um passo muito importante na fase de pré-processamento de dados, pois permite transformar dados categóricos em dados numéricos, sem perder nenhuma informação. Uma boa codificação contribui para a construção de um bom modelo.\n",
|
||||
"\n",
|
||||
"Para a codificação de características, existem dois tipos principais de codificadores:\n",
|
||||
"\n",
|
||||
"1. Codificador ordinal: é adequado para variáveis ordinais, que são variáveis categóricas cujos dados seguem uma ordem lógica, como a coluna `item_size` no nosso conjunto de dados. Ele cria um mapeamento em que cada categoria é representada por um número, que corresponde à ordem da categoria na coluna.\n",
|
||||
"\n",
|
||||
"2. Codificador categórico: é adequado para variáveis nominais, que são variáveis categóricas cujos dados não seguem uma ordem lógica, como todas as características diferentes de `item_size` no nosso conjunto de dados. Trata-se de uma codificação one-hot, o que significa que cada categoria é representada por uma coluna binária: a variável codificada é igual a 1 se a abóbora pertence àquela variedade e 0 caso contrário.\n",
|
||||
"\n",
|
||||
"O Tidymodels oferece mais uma ferramenta interessante: [recipes](https://recipes.tidymodels.org/) - um pacote para pré-processamento de dados. Vamos definir uma `recipe` que especifica que todas as colunas preditoras devem ser codificadas em um conjunto de números inteiros, `prep` para estimar as quantidades e estatísticas necessárias para qualquer operação e, finalmente, `bake` para aplicar os cálculos a novos dados.\n",
|
||||
"\n",
|
||||
"> Normalmente, o recipes é usado como um pré-processador para modelagem, onde define quais passos devem ser aplicados a um conjunto de dados para prepará-lo para a modelagem. Nesse caso, é **altamente recomendado** que utilize um `workflow()` em vez de estimar manualmente uma receita usando prep e bake. Veremos tudo isso em breve.\n",
|
||||
">\n",
|
||||
"> No entanto, por agora, estamos a usar recipes + prep + bake para especificar quais passos devem ser aplicados a um conjunto de dados para prepará-lo para análise de dados e, em seguida, extrair os dados pré-processados com os passos aplicados.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Preprocess and extract data to allow some data analysis\n",
|
||||
"baked_pumpkins <- recipe(color ~ ., data = pumpkins_select) %>%\n",
|
||||
" # Define ordering for item_size column\n",
|
||||
" step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n",
|
||||
" # Convert factors to numbers using the order defined above (Ordinal encoding)\n",
|
||||
" step_integer(item_size, zero_based = F) %>%\n",
|
||||
" # Encode all other predictors using one hot encoding\n",
|
||||
" step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE) %>%\n",
|
||||
" prep(data = pumpkin_select) %>%\n",
|
||||
" bake(new_data = NULL)\n",
|
||||
"\n",
|
||||
"# Display the first few rows of preprocessed data\n",
|
||||
"baked_pumpkins %>% \n",
|
||||
" slice_head(n = 5)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"✅ Quais são as vantagens de usar um codificador ordinal para a coluna Item Size?\n",
|
||||
"\n",
|
||||
"### Analisar relações entre variáveis\n",
|
||||
"\n",
|
||||
"Agora que pré-processámos os nossos dados, podemos analisar as relações entre as características e o rótulo para ter uma ideia de quão bem o modelo será capaz de prever o rótulo com base nas características. A melhor forma de realizar este tipo de análise é através da visualização dos dados. \n",
|
||||
"Vamos utilizar novamente a função ggplot geom_boxplot_ para visualizar as relações entre Item Size, Variety e Color num gráfico categórico. Para representar melhor os dados, utilizaremos a coluna codificada Item Size e a coluna não codificada Variety.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Define the color palette\n",
|
||||
"palette <- c(ORANGE = \"orange\", WHITE = \"wheat\")\n",
|
||||
"\n",
|
||||
"# We need the encoded Item Size column to use it as the x-axis values in the plot\n",
|
||||
"pumpkins_select_plot<-pumpkins_select\n",
|
||||
"pumpkins_select_plot$item_size <- baked_pumpkins$item_size\n",
|
||||
"\n",
|
||||
"# Create the grouped box plot\n",
|
||||
"ggplot(pumpkins_select_plot, aes(x = `item_size`, y = color, fill = color)) +\n",
|
||||
" geom_boxplot() +\n",
|
||||
" facet_grid(variety ~ ., scales = \"free_x\") +\n",
|
||||
" scale_fill_manual(values = palette) +\n",
|
||||
" labs(x = \"Item Size\", y = \"\") +\n",
|
||||
" theme_minimal() +\n",
|
||||
" theme(strip.text = element_text(size = 12)) +\n",
|
||||
" theme(axis.text.x = element_text(size = 10)) +\n",
|
||||
" theme(axis.title.x = element_text(size = 12)) +\n",
|
||||
" theme(axis.title.y = element_blank()) +\n",
|
||||
" theme(legend.position = \"bottom\") +\n",
|
||||
" guides(fill = guide_legend(title = \"Color\")) +\n",
|
||||
" theme(panel.spacing = unit(0.5, \"lines\"))+\n",
|
||||
" theme(strip.text.y = element_text(size = 4, hjust = 0)) \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Usar um gráfico de enxame\n",
|
||||
"\n",
|
||||
"Como a cor é uma categoria binária (Branco ou Não), é necessário 'uma [abordagem especializada](https://github.com/rstudio/cheatsheets/blob/main/data-visualization.pdf) para visualização'.\n",
|
||||
"\n",
|
||||
"Experimente um `gráfico de enxame` para mostrar a distribuição da cor em relação ao tamanho do item.\n",
|
||||
"\n",
|
||||
"Vamos usar o [pacote ggbeeswarm](https://github.com/eclarke/ggbeeswarm), que fornece métodos para criar gráficos no estilo enxame usando ggplot2. Gráficos de enxame são uma forma de plotar pontos que normalmente se sobreporiam, posicionando-os lado a lado.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create beeswarm plots of color and item_size\n",
|
||||
"baked_pumpkins %>% \n",
|
||||
" mutate(color = factor(color)) %>% \n",
|
||||
" ggplot(mapping = aes(x = color, y = item_size, color = color)) +\n",
|
||||
" geom_quasirandom() +\n",
|
||||
" scale_color_brewer(palette = \"Dark2\", direction = -1) +\n",
|
||||
" theme(legend.position = \"none\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Agora que temos uma ideia da relação entre as categorias binárias de cor e o grupo maior de tamanhos, vamos explorar a regressão logística para determinar a provável cor de uma abóbora.\n",
|
||||
"\n",
|
||||
"## Construir o seu modelo\n",
|
||||
"\n",
|
||||
"Selecione as variáveis que deseja usar no seu modelo de classificação e divida os dados em conjuntos de treino e teste. [rsample](https://rsample.tidymodels.org/), um pacote do Tidymodels, fornece infraestrutura para uma divisão e reamostragem de dados eficiente:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Split data into 80% for training and 20% for testing\n",
|
||||
"set.seed(2056)\n",
|
||||
"pumpkins_split <- pumpkins_select %>% \n",
|
||||
" initial_split(prop = 0.8)\n",
|
||||
"\n",
|
||||
"# Extract the data in each split\n",
|
||||
"pumpkins_train <- training(pumpkins_split)\n",
|
||||
"pumpkins_test <- testing(pumpkins_split)\n",
|
||||
"\n",
|
||||
"# Print out the first 5 rows of the training set\n",
|
||||
"pumpkins_train %>% \n",
|
||||
" slice_head(n = 5)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"🙌 Estamos prontos para treinar um modelo ajustando as características de treino ao rótulo de treino (cor).\n",
|
||||
"\n",
|
||||
"Vamos começar por criar uma receita que especifica os passos de pré-processamento que devem ser realizados nos nossos dados para os preparar para a modelação, ou seja: codificar variáveis categóricas em um conjunto de inteiros. Tal como `baked_pumpkins`, criamos uma `pumpkins_recipe`, mas não usamos `prep` e `bake`, já que isso será incorporado num fluxo de trabalho, como verá em apenas alguns passos.\n",
|
||||
"\n",
|
||||
"Existem várias formas de especificar um modelo de regressão logística no Tidymodels. Consulte `?logistic_reg()`. Por agora, vamos especificar um modelo de regressão logística através do motor padrão `stats::glm()`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Create a recipe that specifies preprocessing steps for modelling\n",
|
||||
"pumpkins_recipe <- recipe(color ~ ., data = pumpkins_train) %>% \n",
|
||||
" step_mutate(item_size = ordered(item_size, levels = c('sml', 'med', 'med-lge', 'lge', 'xlge', 'jbo', 'exjbo'))) %>%\n",
|
||||
" step_integer(item_size, zero_based = F) %>% \n",
|
||||
" step_dummy(all_nominal(), -all_outcomes(), one_hot = TRUE)\n",
|
||||
"\n",
|
||||
"# Create a logistic model specification\n",
|
||||
"log_reg <- logistic_reg() %>% \n",
|
||||
" set_engine(\"glm\") %>% \n",
|
||||
" set_mode(\"classification\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Agora que temos uma receita e uma especificação do modelo, precisamos encontrar uma forma de combiná-las num único objeto que, primeiro, pré-processe os dados (prep+bake nos bastidores), ajuste o modelo aos dados pré-processados e também permita possíveis atividades de pós-processamento.\n",
|
||||
"\n",
|
||||
"No Tidymodels, este objeto prático é chamado de [`workflow`](https://workflows.tidymodels.org/) e armazena convenientemente os seus componentes de modelação.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Bundle modelling components in a workflow\n",
|
||||
"log_reg_wf <- workflow() %>% \n",
|
||||
" add_recipe(pumpkins_recipe) %>% \n",
|
||||
" add_model(log_reg)\n",
|
||||
"\n",
|
||||
"# Print out the workflow\n",
|
||||
"log_reg_wf\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Depois de um fluxo de trabalho ter sido *especificado*, um modelo pode ser `treinado` utilizando a função [`fit()`](https://tidymodels.github.io/parsnip/reference/fit.html). O fluxo de trabalho irá estimar uma receita e pré-processar os dados antes do treino, por isso não será necessário fazer isso manualmente utilizando prep e bake.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Train the model\n",
|
||||
"wf_fit <- log_reg_wf %>% \n",
|
||||
" fit(data = pumpkins_train)\n",
|
||||
"\n",
|
||||
"# Print the trained workflow\n",
|
||||
"wf_fit\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"O modelo imprime os coeficientes aprendidos durante o treino.\n",
|
||||
"\n",
|
||||
"Agora que treinámos o modelo utilizando os dados de treino, podemos fazer previsões nos dados de teste usando [parsnip::predict()](https://parsnip.tidymodels.org/reference/predict.model_fit.html). Vamos começar por usar o modelo para prever etiquetas para o nosso conjunto de teste e as probabilidades para cada etiqueta. Quando a probabilidade é superior a 0.5, a classe prevista é `WHITE`, caso contrário, é `ORANGE`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Make predictions for color and corresponding probabilities\n",
|
||||
"results <- pumpkins_test %>% select(color) %>% \n",
|
||||
" bind_cols(wf_fit %>% \n",
|
||||
" predict(new_data = pumpkins_test)) %>%\n",
|
||||
" bind_cols(wf_fit %>%\n",
|
||||
" predict(new_data = pumpkins_test, type = \"prob\"))\n",
|
||||
"\n",
|
||||
"# Compare predictions\n",
|
||||
"results %>% \n",
|
||||
" slice_head(n = 10)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Muito bom! Isto fornece mais detalhes sobre como funciona a regressão logística.\n",
|
||||
"\n",
|
||||
"### Melhor compreensão através de uma matriz de confusão\n",
|
||||
"\n",
|
||||
"Comparar cada previsão com o respetivo valor real (\"ground truth\") não é uma forma muito eficiente de determinar o quão bem o modelo está a prever. Felizmente, o Tidymodels tem mais algumas ferramentas úteis: [`yardstick`](https://yardstick.tidymodels.org/) - um pacote utilizado para medir a eficácia dos modelos através de métricas de desempenho.\n",
|
||||
"\n",
|
||||
"Uma métrica de desempenho associada a problemas de classificação é a [`matriz de confusão`](https://wikipedia.org/wiki/Confusion_matrix). Uma matriz de confusão descreve o desempenho de um modelo de classificação. Ela tabula quantos exemplos de cada classe foram corretamente classificados por um modelo. No nosso caso, mostrará quantas abóboras laranjas foram classificadas como laranjas e quantas abóboras brancas foram classificadas como brancas; a matriz de confusão também indica quantas foram classificadas nas categorias **erradas**.\n",
|
||||
"\n",
|
||||
"A função [**`conf_mat()`**](https://tidymodels.github.io/yardstick/reference/conf_mat.html) do yardstick calcula esta tabela cruzada de classes observadas e previstas.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Confusion matrix for prediction results\n",
|
||||
"conf_mat(data = results, truth = color, estimate = .pred_class)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Vamos interpretar a matriz de confusão. O nosso modelo foi solicitado a classificar abóboras entre duas categorias binárias, categoria `branca` e categoria `não-branca`.\n",
|
||||
"\n",
|
||||
"- Se o seu modelo prevê que uma abóbora é branca e ela pertence à categoria 'branca' na realidade, chamamos isso de um `verdadeiro positivo`, representado pelo número no canto superior esquerdo.\n",
|
||||
"\n",
|
||||
"- Se o seu modelo prevê que uma abóbora não é branca e ela pertence à categoria 'branca' na realidade, chamamos isso de um `falso negativo`, representado pelo número no canto inferior esquerdo.\n",
|
||||
"\n",
|
||||
"- Se o seu modelo prevê que uma abóbora é branca e ela pertence à categoria 'não-branca' na realidade, chamamos isso de um `falso positivo`, representado pelo número no canto superior direito.\n",
|
||||
"\n",
|
||||
"- Se o seu modelo prevê que uma abóbora não é branca e ela pertence à categoria 'não-branca' na realidade, chamamos isso de um `verdadeiro negativo`, representado pelo número no canto inferior direito.\n",
|
||||
"\n",
|
||||
"| Verdade |\n",
|
||||
"|:-------:|\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"| | | |\n",
|
||||
"|---------------|--------|-------|\n",
|
||||
"| **Previsto** | BRANCA | LARANJA |\n",
|
||||
"| BRANCA | VP | FP |\n",
|
||||
"| LARANJA | FN | VN |\n",
|
||||
"\n",
|
||||
"Como pode imaginar, é preferível ter um número maior de verdadeiros positivos e verdadeiros negativos e um número menor de falsos positivos e falsos negativos, o que implica que o modelo tem um desempenho melhor.\n",
|
||||
"\n",
|
||||
"A matriz de confusão é útil porque dá origem a outras métricas que podem ajudar-nos a avaliar melhor o desempenho de um modelo de classificação. Vamos analisar algumas delas:\n",
|
||||
"\n",
|
||||
"🎓 Precisão: `VP/(VP + FP)` definida como a proporção de positivos previstos que são realmente positivos. Também chamada de [valor preditivo positivo](https://en.wikipedia.org/wiki/Positive_predictive_value \"Positive predictive value\").\n",
|
||||
"\n",
|
||||
"🎓 Recall: `VP/(VP + FN)` definida como a proporção de resultados positivos em relação ao número de amostras que eram realmente positivas. Também conhecida como `sensibilidade`.\n",
|
||||
"\n",
|
||||
"🎓 Especificidade: `VN/(VN + FP)` definida como a proporção de resultados negativos em relação ao número de amostras que eram realmente negativas.\n",
|
||||
"\n",
|
||||
"🎓 Exatidão: `(VP + VN)/(VP + VN + FP + FN)` A percentagem de etiquetas previstas corretamente para uma amostra.\n",
|
||||
"\n",
|
||||
"🎓 Medida F: Uma média ponderada da precisão e do recall, sendo o melhor valor 1 e o pior valor 0.\n",
|
||||
"\n",
|
||||
"Vamos calcular estas métricas!\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Combine metric functions and calculate them all at once\n",
|
||||
"eval_metrics <- metric_set(ppv, recall, spec, f_meas, accuracy)\n",
|
||||
"eval_metrics(data = results, truth = color, estimate = .pred_class)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Visualizar a curva ROC deste modelo\n",
|
||||
"\n",
|
||||
"Vamos fazer mais uma visualização para observar a chamada [`curva ROC`](https://en.wikipedia.org/wiki/Receiver_operating_characteristic):\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Make a roc_curve\n",
|
||||
"results %>% \n",
|
||||
" roc_curve(color, .pred_ORANGE) %>% \n",
|
||||
" autoplot()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As curvas ROC são frequentemente utilizadas para obter uma visão do desempenho de um classificador em termos de verdadeiros positivos vs. falsos positivos. As curvas ROC geralmente apresentam a `Taxa de Verdadeiros Positivos`/Sensibilidade no eixo Y e a `Taxa de Falsos Positivos`/1-Especificidade no eixo X. Assim, a inclinação da curva e o espaço entre a linha do meio e a curva são importantes: o ideal é ter uma curva que rapidamente suba e ultrapasse a linha. No nosso caso, há falsos positivos no início, e depois a linha sobe e ultrapassa adequadamente.\n",
|
||||
"\n",
|
||||
"Por fim, vamos usar `yardstick::roc_auc()` para calcular a Área Sob a Curva. Uma forma de interpretar a AUC é como a probabilidade de o modelo classificar um exemplo positivo aleatório mais alto do que um exemplo negativo aleatório.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"vscode": {
|
||||
"languageId": "r"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Calculate area under curve\n",
|
||||
"results %>% \n",
|
||||
" roc_auc(color, .pred_ORANGE)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"O resultado é cerca de `0.975`. Dado que o AUC varia de 0 a 1, é desejável um valor elevado, já que um modelo que acerta 100% das suas previsões terá um AUC de 1; neste caso, o modelo é *bastante bom*.\n",
|
||||
"\n",
|
||||
"Nas próximas lições sobre classificações, aprenderás como melhorar os resultados do teu modelo (como lidar com dados desequilibrados neste caso).\n",
|
||||
"\n",
|
||||
"## 🚀Desafio\n",
|
||||
"\n",
|
||||
"Há muito mais para explorar sobre regressão logística! Mas a melhor forma de aprender é experimentar. Encontra um conjunto de dados que se preste a este tipo de análise e constrói um modelo com ele. O que aprendes? dica: experimenta [Kaggle](https://www.kaggle.com/search?q=logistic+regression+datasets) para conjuntos de dados interessantes.\n",
|
||||
"\n",
|
||||
"## Revisão & Estudo Individual\n",
|
||||
"\n",
|
||||
"Lê as primeiras páginas [deste artigo de Stanford](https://web.stanford.edu/~jurafsky/slp3/5.pdf) sobre algumas utilizações práticas da regressão logística. Reflete sobre tarefas que são mais adequadas para um ou outro tipo de regressão entre as que estudámos até agora. O que funcionaria melhor?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"anaconda-cloud": "",
|
||||
"kernelspec": {
|
||||
"display_name": "R",
|
||||
"langauge": "R",
|
||||
"name": "ir"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "r",
|
||||
"file_extension": ".r",
|
||||
"mimetype": "text/x-r-source",
|
||||
"name": "R",
|
||||
"pygments_lexer": "r",
|
||||
"version": "3.4.1"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "feaf125f481a89c468fa115bf2aed580",
|
||||
"translation_date": "2025-09-03T19:35:13+00:00",
|
||||
"source_file": "2-Regression/4-Logistic/solution/R/lesson_4-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,45 @@
|
||||
# Modelos de regressão para aprendizagem automática
|
||||
## Tema regional: Modelos de regressão para preços de abóboras na América do Norte 🎃
|
||||
|
||||
Na América do Norte, as abóboras são frequentemente esculpidas em rostos assustadores para o Halloween. Vamos descobrir mais sobre estes vegetais fascinantes!
|
||||
|
||||

|
||||
> Foto por <a href="https://unsplash.com/@teutschmann?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Beth Teutschmann</a> no <a href="https://unsplash.com/s/photos/jack-o-lanterns?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||
|
||||
## O que irá aprender
|
||||
|
||||
[](https://youtu.be/5QnJtDad4iQ "Vídeo de introdução à regressão - Clique para assistir!")
|
||||
> 🎥 Clique na imagem acima para um vídeo rápido de introdução a esta lição
|
||||
|
||||
As lições desta secção abordam os tipos de regressão no contexto da aprendizagem automática. Os modelos de regressão podem ajudar a determinar a _relação_ entre variáveis. Este tipo de modelo pode prever valores como comprimento, temperatura ou idade, revelando assim relações entre variáveis enquanto analisa pontos de dados.
|
||||
|
||||
Nesta série de lições, irá descobrir as diferenças entre regressão linear e logística, e quando deve preferir uma em vez da outra.
|
||||
|
||||
[](https://youtu.be/XA3OaoW86R8 "ML para principiantes - Introdução aos modelos de regressão para aprendizagem automática")
|
||||
|
||||
> 🎥 Clique na imagem acima para um vídeo curto que introduz os modelos de regressão.
|
||||
|
||||
Neste grupo de lições, irá preparar-se para começar tarefas de aprendizagem automática, incluindo configurar o Visual Studio Code para gerir notebooks, o ambiente comum para cientistas de dados. Irá descobrir o Scikit-learn, uma biblioteca para aprendizagem automática, e construir os seus primeiros modelos, focando-se nos modelos de regressão neste capítulo.
|
||||
|
||||
> Existem ferramentas úteis de baixo código que podem ajudá-lo a aprender a trabalhar com modelos de regressão. Experimente [Azure ML para esta tarefa](https://docs.microsoft.com/learn/modules/create-regression-model-azure-machine-learning-designer/?WT.mc_id=academic-77952-leestott)
|
||||
|
||||
### Lições
|
||||
|
||||
1. [Ferramentas do ofício](1-Tools/README.md)
|
||||
2. [Gestão de dados](2-Data/README.md)
|
||||
3. [Regressão linear e polinomial](3-Linear/README.md)
|
||||
4. [Regressão logística](4-Logistic/README.md)
|
||||
|
||||
---
|
||||
### Créditos
|
||||
|
||||
"ML com regressão" foi escrito com ♥️ por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
♥️ Contribuidores do quiz incluem: [Muhammad Sakib Khan Inan](https://twitter.com/Sakibinan) e [Ornella Altunyan](https://twitter.com/ornelladotcom)
|
||||
|
||||
O conjunto de dados de abóboras foi sugerido por [este projeto no Kaggle](https://www.kaggle.com/usda/a-year-of-pumpkin-prices) e os seus dados são provenientes dos [Relatórios Padrão dos Mercados Terminais de Culturas Especiais](https://www.marketnews.usda.gov/mnp/fv-report-config-step1?type=termPrice) distribuídos pelo Departamento de Agricultura dos Estados Unidos. Adicionámos alguns pontos relacionados com a cor com base na variedade para normalizar a distribuição. Estes dados estão em domínio público.
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.
|
||||
@ -0,0 +1,350 @@
|
||||
# Construir uma Aplicação Web para Utilizar um Modelo de ML
|
||||
|
||||
Nesta lição, vais treinar um modelo de ML com um conjunto de dados fora do comum: _avistamentos de OVNIs ao longo do último século_, provenientes da base de dados do NUFORC.
|
||||
|
||||
Vais aprender:
|
||||
|
||||
- Como 'pickle' um modelo treinado
|
||||
- Como usar esse modelo numa aplicação Flask
|
||||
|
||||
Continuaremos a usar notebooks para limpar os dados e treinar o modelo, mas podes levar o processo um passo adiante ao explorar como usar um modelo "no mundo real", por assim dizer: numa aplicação web.
|
||||
|
||||
Para isso, precisas de construir uma aplicação web utilizando Flask.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Construir uma aplicação
|
||||
|
||||
Existem várias formas de construir aplicações web para consumir modelos de machine learning. A arquitetura da tua aplicação web pode influenciar a forma como o modelo é treinado. Imagina que estás a trabalhar numa empresa onde o grupo de ciência de dados treinou um modelo que querem que utilizes numa aplicação.
|
||||
|
||||
### Considerações
|
||||
|
||||
Há muitas perguntas que precisas de fazer:
|
||||
|
||||
- **É uma aplicação web ou uma aplicação móvel?** Se estás a construir uma aplicação móvel ou precisas de usar o modelo num contexto de IoT, podes usar [TensorFlow Lite](https://www.tensorflow.org/lite/) e utilizar o modelo numa aplicação Android ou iOS.
|
||||
- **Onde o modelo vai residir?** Na nuvem ou localmente?
|
||||
- **Suporte offline.** A aplicação precisa de funcionar offline?
|
||||
- **Que tecnologia foi usada para treinar o modelo?** A tecnologia escolhida pode influenciar as ferramentas que precisas de usar.
|
||||
- **Usando TensorFlow.** Se estás a treinar um modelo com TensorFlow, por exemplo, esse ecossistema permite converter um modelo TensorFlow para uso numa aplicação web utilizando [TensorFlow.js](https://www.tensorflow.org/js/).
|
||||
- **Usando PyTorch.** Se estás a construir um modelo com uma biblioteca como [PyTorch](https://pytorch.org/), tens a opção de exportá-lo no formato [ONNX](https://onnx.ai/) (Open Neural Network Exchange) para uso em aplicações web JavaScript que podem utilizar o [Onnx Runtime](https://www.onnxruntime.ai/). Esta opção será explorada numa lição futura para um modelo treinado com Scikit-learn.
|
||||
- **Usando Lobe.ai ou Azure Custom Vision.** Se estás a usar um sistema ML SaaS (Software como Serviço) como [Lobe.ai](https://lobe.ai/) ou [Azure Custom Vision](https://azure.microsoft.com/services/cognitive-services/custom-vision-service/?WT.mc_id=academic-77952-leestott) para treinar um modelo, este tipo de software fornece formas de exportar o modelo para várias plataformas, incluindo construir uma API personalizada para ser consultada na nuvem pela tua aplicação online.
|
||||
|
||||
Também tens a oportunidade de construir uma aplicação web Flask completa que seria capaz de treinar o modelo diretamente no navegador. Isso também pode ser feito utilizando TensorFlow.js num contexto JavaScript.
|
||||
|
||||
Para os nossos propósitos, como temos trabalhado com notebooks baseados em Python, vamos explorar os passos necessários para exportar um modelo treinado de um notebook para um formato legível por uma aplicação web construída em Python.
|
||||
|
||||
## Ferramenta
|
||||
|
||||
Para esta tarefa, precisas de duas ferramentas: Flask e Pickle, ambas executadas em Python.
|
||||
|
||||
✅ O que é [Flask](https://palletsprojects.com/p/flask/)? Definido como um 'micro-framework' pelos seus criadores, Flask fornece as funcionalidades básicas de frameworks web utilizando Python e um motor de templates para construir páginas web. Dá uma olhada neste [módulo de aprendizagem](https://docs.microsoft.com/learn/modules/python-flask-build-ai-web-app?WT.mc_id=academic-77952-leestott) para praticar a construção com Flask.
|
||||
|
||||
✅ O que é [Pickle](https://docs.python.org/3/library/pickle.html)? Pickle 🥒 é um módulo Python que serializa e desserializa uma estrutura de objetos Python. Quando 'pickle' um modelo, estás a serializar ou achatar a sua estrutura para uso na web. Atenção: pickle não é intrinsecamente seguro, por isso tem cuidado se fores solicitado a 'des-picklar' um ficheiro. Um ficheiro pickled tem o sufixo `.pkl`.
|
||||
|
||||
## Exercício - limpar os dados
|
||||
|
||||
Nesta lição vais usar dados de 80.000 avistamentos de OVNIs, recolhidos pelo [NUFORC](https://nuforc.org) (Centro Nacional de Relatórios de OVNIs). Estes dados têm descrições interessantes de avistamentos de OVNIs, por exemplo:
|
||||
|
||||
- **Descrição longa de exemplo.** "Um homem emerge de um feixe de luz que brilha num campo de relva à noite e corre em direção ao estacionamento da Texas Instruments".
|
||||
- **Descrição curta de exemplo.** "as luzes perseguiram-nos".
|
||||
|
||||
A folha de cálculo [ufos.csv](../../../../3-Web-App/1-Web-App/data/ufos.csv) inclui colunas sobre a `cidade`, `estado` e `país` onde o avistamento ocorreu, a `forma` do objeto e a sua `latitude` e `longitude`.
|
||||
|
||||
No [notebook](../../../../3-Web-App/1-Web-App/notebook.ipynb) em branco incluído nesta lição:
|
||||
|
||||
1. Importa `pandas`, `matplotlib` e `numpy` como fizeste nas lições anteriores e importa a folha de cálculo de OVNIs. Podes dar uma olhada num conjunto de dados de exemplo:
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
ufos = pd.read_csv('./data/ufos.csv')
|
||||
ufos.head()
|
||||
```
|
||||
|
||||
1. Converte os dados de OVNIs para um pequeno dataframe com títulos novos. Verifica os valores únicos no campo `Country`.
|
||||
|
||||
```python
|
||||
ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']})
|
||||
|
||||
ufos.Country.unique()
|
||||
```
|
||||
|
||||
1. Agora, podes reduzir a quantidade de dados com que precisas de lidar ao eliminar valores nulos e importar apenas avistamentos entre 1-60 segundos:
|
||||
|
||||
```python
|
||||
ufos.dropna(inplace=True)
|
||||
|
||||
ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)]
|
||||
|
||||
ufos.info()
|
||||
```
|
||||
|
||||
1. Importa a biblioteca `LabelEncoder` do Scikit-learn para converter os valores de texto dos países para números:
|
||||
|
||||
✅ LabelEncoder codifica os dados alfabeticamente
|
||||
|
||||
```python
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
|
||||
ufos['Country'] = LabelEncoder().fit_transform(ufos['Country'])
|
||||
|
||||
ufos.head()
|
||||
```
|
||||
|
||||
Os teus dados devem parecer-se com isto:
|
||||
|
||||
```output
|
||||
Seconds Country Latitude Longitude
|
||||
2 20.0 3 53.200000 -2.916667
|
||||
3 20.0 4 28.978333 -96.645833
|
||||
14 30.0 4 35.823889 -80.253611
|
||||
23 60.0 4 45.582778 -122.352222
|
||||
24 3.0 3 51.783333 -0.783333
|
||||
```
|
||||
|
||||
## Exercício - construir o modelo
|
||||
|
||||
Agora podes preparar-te para treinar um modelo dividindo os dados em grupos de treino e teste.
|
||||
|
||||
1. Seleciona as três características que queres treinar como o teu vetor X, e o vetor y será o `Country`. Queres ser capaz de inserir `Seconds`, `Latitude` e `Longitude` e obter um id de país como retorno.
|
||||
|
||||
```python
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
Selected_features = ['Seconds','Latitude','Longitude']
|
||||
|
||||
X = ufos[Selected_features]
|
||||
y = ufos['Country']
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
|
||||
```
|
||||
|
||||
1. Treina o modelo utilizando regressão logística:
|
||||
|
||||
```python
|
||||
from sklearn.metrics import accuracy_score, classification_report
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
model = LogisticRegression()
|
||||
model.fit(X_train, y_train)
|
||||
predictions = model.predict(X_test)
|
||||
|
||||
print(classification_report(y_test, predictions))
|
||||
print('Predicted labels: ', predictions)
|
||||
print('Accuracy: ', accuracy_score(y_test, predictions))
|
||||
```
|
||||
|
||||
A precisão não é má **(cerca de 95%)**, o que não é surpreendente, já que `Country` e `Latitude/Longitude` estão correlacionados.
|
||||
|
||||
O modelo que criaste não é muito revolucionário, pois deverias ser capaz de inferir um `Country` a partir da sua `Latitude` e `Longitude`, mas é um bom exercício para tentar treinar a partir de dados brutos que limpaste, exportaste e depois usaste este modelo numa aplicação web.
|
||||
|
||||
## Exercício - 'pickle' o modelo
|
||||
|
||||
Agora, é hora de _picklar_ o modelo! Podes fazer isso em algumas linhas de código. Uma vez _pickled_, carrega o modelo pickled e testa-o contra um array de dados de exemplo contendo valores para segundos, latitude e longitude.
|
||||
|
||||
```python
|
||||
import pickle
|
||||
model_filename = 'ufo-model.pkl'
|
||||
pickle.dump(model, open(model_filename,'wb'))
|
||||
|
||||
model = pickle.load(open('ufo-model.pkl','rb'))
|
||||
print(model.predict([[50,44,-12]]))
|
||||
```
|
||||
|
||||
O modelo retorna **'3'**, que é o código de país para o Reino Unido. Incrível! 👽
|
||||
|
||||
## Exercício - construir uma aplicação Flask
|
||||
|
||||
Agora podes construir uma aplicação Flask para chamar o modelo e retornar resultados semelhantes, mas de uma forma mais visualmente agradável.
|
||||
|
||||
1. Começa por criar uma pasta chamada **web-app** ao lado do ficheiro _notebook.ipynb_ onde o teu ficheiro _ufo-model.pkl_ reside.
|
||||
|
||||
1. Nessa pasta, cria mais três pastas: **static**, com uma pasta **css** dentro dela, e **templates**. Deves agora ter os seguintes ficheiros e diretórios:
|
||||
|
||||
```output
|
||||
web-app/
|
||||
static/
|
||||
css/
|
||||
templates/
|
||||
notebook.ipynb
|
||||
ufo-model.pkl
|
||||
```
|
||||
|
||||
✅ Consulta a pasta de solução para ver a aplicação finalizada
|
||||
|
||||
1. O primeiro ficheiro a criar na pasta _web-app_ é o ficheiro **requirements.txt**. Tal como _package.json_ numa aplicação JavaScript, este ficheiro lista as dependências necessárias para a aplicação. No **requirements.txt** adiciona as linhas:
|
||||
|
||||
```text
|
||||
scikit-learn
|
||||
pandas
|
||||
numpy
|
||||
flask
|
||||
```
|
||||
|
||||
1. Agora, executa este ficheiro navegando até _web-app_:
|
||||
|
||||
```bash
|
||||
cd web-app
|
||||
```
|
||||
|
||||
1. No terminal, digita `pip install` para instalar as bibliotecas listadas no _requirements.txt_:
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
1. Agora, estás pronto para criar mais três ficheiros para finalizar a aplicação:
|
||||
|
||||
1. Cria **app.py** na raiz.
|
||||
2. Cria **index.html** na pasta _templates_.
|
||||
3. Cria **styles.css** na pasta _static/css_.
|
||||
|
||||
1. Desenvolve o ficheiro _styles.css_ com alguns estilos:
|
||||
|
||||
```css
|
||||
body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: 'Helvetica';
|
||||
background: black;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
letter-spacing: 1.4px;
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
input {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.grid {
|
||||
width: 300px;
|
||||
border: 1px solid #2d2d2d;
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.box {
|
||||
color: #fff;
|
||||
background: #2d2d2d;
|
||||
padding: 12px;
|
||||
display: inline-block;
|
||||
}
|
||||
```
|
||||
|
||||
1. Em seguida, desenvolve o ficheiro _index.html_:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>🛸 UFO Appearance Prediction! 👽</title>
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="grid">
|
||||
|
||||
<div class="box">
|
||||
|
||||
<p>According to the number of seconds, latitude and longitude, which country is likely to have reported seeing a UFO?</p>
|
||||
|
||||
<form action="{{ url_for('predict')}}" method="post">
|
||||
<input type="number" name="seconds" placeholder="Seconds" required="required" min="0" max="60" />
|
||||
<input type="text" name="latitude" placeholder="Latitude" required="required" />
|
||||
<input type="text" name="longitude" placeholder="Longitude" required="required" />
|
||||
<button type="submit" class="btn">Predict country where the UFO is seen</button>
|
||||
</form>
|
||||
|
||||
<p>{{ prediction_text }}</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
Dá uma olhada na utilização de templates neste ficheiro. Repara na sintaxe 'mustache' em torno das variáveis que serão fornecidas pela aplicação, como o texto de previsão: `{{}}`. Há também um formulário que envia uma previsão para a rota `/predict`.
|
||||
|
||||
Finalmente, estás pronto para construir o ficheiro Python que conduz o consumo do modelo e a exibição das previsões:
|
||||
|
||||
1. No `app.py` adiciona:
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from flask import Flask, request, render_template
|
||||
import pickle
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
model = pickle.load(open("./ufo-model.pkl", "rb"))
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def home():
|
||||
return render_template("index.html")
|
||||
|
||||
|
||||
@app.route("/predict", methods=["POST"])
|
||||
def predict():
|
||||
|
||||
int_features = [int(x) for x in request.form.values()]
|
||||
final_features = [np.array(int_features)]
|
||||
prediction = model.predict(final_features)
|
||||
|
||||
output = prediction[0]
|
||||
|
||||
countries = ["Australia", "Canada", "Germany", "UK", "US"]
|
||||
|
||||
return render_template(
|
||||
"index.html", prediction_text="Likely country: {}".format(countries[output])
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
app.run(debug=True)
|
||||
```
|
||||
|
||||
> 💡 Dica: quando adicionas [`debug=True`](https://www.askpython.com/python-modules/flask/flask-debug-mode) enquanto executas a aplicação web utilizando Flask, quaisquer alterações que fizeres na tua aplicação serão refletidas imediatamente sem necessidade de reiniciar o servidor. Atenção! Não habilites este modo numa aplicação em produção.
|
||||
|
||||
Se executares `python app.py` ou `python3 app.py` - o teu servidor web inicia localmente, e podes preencher um pequeno formulário para obter uma resposta à tua pergunta sobre onde os OVNIs foram avistados!
|
||||
|
||||
Antes de fazer isso, dá uma olhada nas partes do `app.py`:
|
||||
|
||||
1. Primeiro, as dependências são carregadas e a aplicação inicia.
|
||||
1. Depois, o modelo é importado.
|
||||
1. Em seguida, o index.html é renderizado na rota inicial.
|
||||
|
||||
Na rota `/predict`, várias coisas acontecem quando o formulário é enviado:
|
||||
|
||||
1. As variáveis do formulário são recolhidas e convertidas para um array numpy. Elas são então enviadas para o modelo e uma previsão é retornada.
|
||||
2. Os países que queremos exibir são re-renderizados como texto legível a partir do código de país previsto, e esse valor é enviado de volta ao index.html para ser renderizado no template.
|
||||
|
||||
Usar um modelo desta forma, com Flask e um modelo pickled, é relativamente simples. O mais difícil é entender qual é a forma dos dados que devem ser enviados ao modelo para obter uma previsão. Isso depende de como o modelo foi treinado. Este tem três pontos de dados que devem ser inseridos para obter uma previsão.
|
||||
|
||||
Num ambiente profissional, podes ver como é necessária uma boa comunicação entre as pessoas que treinam o modelo e aquelas que o consomem numa aplicação web ou móvel. No nosso caso, és apenas tu!
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Desafio
|
||||
|
||||
Em vez de trabalhar num notebook e importar o modelo para a aplicação Flask, poderias treinar o modelo diretamente dentro da aplicação Flask! Tenta converter o teu código Python no notebook, talvez depois de os dados serem limpos, para treinar o modelo dentro da aplicação numa rota chamada `train`. Quais são os prós e contras de seguir este método?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Existem muitas formas de construir uma aplicação web para consumir modelos de ML. Faz uma lista das formas como poderias usar JavaScript ou Python para construir uma aplicação web que aproveite o machine learning. Considera a arquitetura: o modelo deve permanecer na aplicação ou viver na nuvem? Se for o último caso, como o acederias? Desenha um modelo arquitetural para uma solução web aplicada de ML.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Experimenta um modelo diferente](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Experimente um modelo diferente
|
||||
|
||||
## Instruções
|
||||
|
||||
Agora que já criou uma aplicação web utilizando um modelo de Regressão treinado, utilize um dos modelos de uma lição anterior sobre Regressão para refazer esta aplicação web. Pode manter o estilo ou desenhá-la de forma diferente para refletir os dados das abóboras. Certifique-se de alterar os inputs para corresponder ao método de treino do seu modelo.
|
||||
|
||||
## Critérios de Avaliação
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita Melhorias |
|
||||
| -------------------------- | -------------------------------------------------------- | --------------------------------------------------------- | -------------------------------------- |
|
||||
| | A aplicação web funciona como esperado e está implementada na nuvem | A aplicação web contém falhas ou apresenta resultados inesperados | A aplicação web não funciona corretamente |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.
|
||||
@ -0,0 +1,267 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.0"
|
||||
},
|
||||
"orig_nbformat": 2,
|
||||
"kernelspec": {
|
||||
"name": "python37364bit8d3b438fb5fc4430a93ac2cb74d693a7",
|
||||
"display_name": "Python 3.7.0 64-bit ('3.7')"
|
||||
},
|
||||
"metadata": {
|
||||
"interpreter": {
|
||||
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
|
||||
}
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "5fa2e8f4584c78250ca9729b46562ceb",
|
||||
"translation_date": "2025-09-03T20:19:38+00:00",
|
||||
"source_file": "3-Web-App/1-Web-App/solution/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"source": [],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" datetime city state country shape \\\n",
|
||||
"0 10/10/1949 20:30 san marcos tx us cylinder \n",
|
||||
"1 10/10/1949 21:00 lackland afb tx NaN light \n",
|
||||
"2 10/10/1955 17:00 chester (uk/england) NaN gb circle \n",
|
||||
"3 10/10/1956 21:00 edna tx us circle \n",
|
||||
"4 10/10/1960 20:00 kaneohe hi us light \n",
|
||||
"\n",
|
||||
" duration (seconds) duration (hours/min) \\\n",
|
||||
"0 2700.0 45 minutes \n",
|
||||
"1 7200.0 1-2 hrs \n",
|
||||
"2 20.0 20 seconds \n",
|
||||
"3 20.0 1/2 hour \n",
|
||||
"4 900.0 15 minutes \n",
|
||||
"\n",
|
||||
" comments date posted latitude \\\n",
|
||||
"0 This event took place in early fall around 194... 4/27/2004 29.883056 \n",
|
||||
"1 1949 Lackland AFB, TX. Lights racing acros... 12/16/2005 29.384210 \n",
|
||||
"2 Green/Orange circular disc over Chester, En... 1/21/2008 53.200000 \n",
|
||||
"3 My older brother and twin sister were leaving ... 1/17/2004 28.978333 \n",
|
||||
"4 AS a Marine 1st Lt. flying an FJ4B fighter/att... 1/22/2004 21.418056 \n",
|
||||
"\n",
|
||||
" longitude \n",
|
||||
"0 -97.941111 \n",
|
||||
"1 -98.581082 \n",
|
||||
"2 -2.916667 \n",
|
||||
"3 -96.645833 \n",
|
||||
"4 -157.803611 "
|
||||
],
|
||||
"text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th>datetime</th>\n <th>city</th>\n <th>state</th>\n <th>country</th>\n <th>shape</th>\n <th>duration (seconds)</th>\n <th>duration (hours/min)</th>\n <th>comments</th>\n <th>date posted</th>\n <th>latitude</th>\n <th>longitude</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>0</th>\n <td>10/10/1949 20:30</td>\n <td>san marcos</td>\n <td>tx</td>\n <td>us</td>\n <td>cylinder</td>\n <td>2700.0</td>\n <td>45 minutes</td>\n <td>This event took place in early fall around 194...</td>\n <td>4/27/2004</td>\n <td>29.883056</td>\n <td>-97.941111</td>\n </tr>\n <tr>\n <th>1</th>\n <td>10/10/1949 21:00</td>\n <td>lackland afb</td>\n <td>tx</td>\n <td>NaN</td>\n <td>light</td>\n <td>7200.0</td>\n <td>1-2 hrs</td>\n <td>1949 Lackland AFB&#44 TX. Lights racing acros...</td>\n <td>12/16/2005</td>\n <td>29.384210</td>\n <td>-98.581082</td>\n </tr>\n <tr>\n <th>2</th>\n <td>10/10/1955 17:00</td>\n <td>chester (uk/england)</td>\n <td>NaN</td>\n <td>gb</td>\n <td>circle</td>\n <td>20.0</td>\n <td>20 seconds</td>\n <td>Green/Orange circular disc over Chester&#44 En...</td>\n <td>1/21/2008</td>\n <td>53.200000</td>\n <td>-2.916667</td>\n </tr>\n <tr>\n <th>3</th>\n <td>10/10/1956 21:00</td>\n <td>edna</td>\n <td>tx</td>\n <td>us</td>\n <td>circle</td>\n <td>20.0</td>\n <td>1/2 hour</td>\n <td>My older brother and twin sister were leaving ...</td>\n <td>1/17/2004</td>\n <td>28.978333</td>\n <td>-96.645833</td>\n </tr>\n <tr>\n <th>4</th>\n <td>10/10/1960 20:00</td>\n <td>kaneohe</td>\n <td>hi</td>\n <td>us</td>\n <td>light</td>\n <td>900.0</td>\n <td>15 minutes</td>\n <td>AS a Marine 1st Lt. flying an FJ4B fighter/att...</td>\n <td>1/22/2004</td>\n <td>21.418056</td>\n <td>-157.803611</td>\n </tr>\n </tbody>\n</table>\n</div>"
|
||||
},
|
||||
"metadata": {},
|
||||
"execution_count": 23
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"ufos = pd.read_csv('../data/ufos.csv')\n",
|
||||
"ufos.head()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 24,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array(['us', nan, 'gb', 'ca', 'au', 'de'], dtype=object)"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"execution_count": 24
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']})\n",
|
||||
"\n",
|
||||
"ufos.Country.unique()\n",
|
||||
"\n",
|
||||
"# 0 au, 1 ca, 2 de, 3 gb, 4 us"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 25,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"<class 'pandas.core.frame.DataFrame'>\nInt64Index: 25863 entries, 2 to 80330\nData columns (total 4 columns):\n # Column Non-Null Count Dtype \n--- ------ -------------- ----- \n 0 Seconds 25863 non-null float64\n 1 Country 25863 non-null object \n 2 Latitude 25863 non-null float64\n 3 Longitude 25863 non-null float64\ndtypes: float64(3), object(1)\nmemory usage: 1010.3+ KB\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"ufos.dropna(inplace=True)\n",
|
||||
"\n",
|
||||
"ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)]\n",
|
||||
"\n",
|
||||
"ufos.info()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 26,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
" Seconds Country Latitude Longitude\n",
|
||||
"2 20.0 3 53.200000 -2.916667\n",
|
||||
"3 20.0 4 28.978333 -96.645833\n",
|
||||
"14 30.0 4 35.823889 -80.253611\n",
|
||||
"23 60.0 4 45.582778 -122.352222\n",
|
||||
"24 3.0 3 51.783333 -0.783333"
|
||||
],
|
||||
"text/html": "<div>\n<style scoped>\n .dataframe tbody tr th:only-of-type {\n vertical-align: middle;\n }\n\n .dataframe tbody tr th {\n vertical-align: top;\n }\n\n .dataframe thead th {\n text-align: right;\n }\n</style>\n<table border=\"1\" class=\"dataframe\">\n <thead>\n <tr style=\"text-align: right;\">\n <th></th>\n <th>Seconds</th>\n <th>Country</th>\n <th>Latitude</th>\n <th>Longitude</th>\n </tr>\n </thead>\n <tbody>\n <tr>\n <th>2</th>\n <td>20.0</td>\n <td>3</td>\n <td>53.200000</td>\n <td>-2.916667</td>\n </tr>\n <tr>\n <th>3</th>\n <td>20.0</td>\n <td>4</td>\n <td>28.978333</td>\n <td>-96.645833</td>\n </tr>\n <tr>\n <th>14</th>\n <td>30.0</td>\n <td>4</td>\n <td>35.823889</td>\n <td>-80.253611</td>\n </tr>\n <tr>\n <th>23</th>\n <td>60.0</td>\n <td>4</td>\n <td>45.582778</td>\n <td>-122.352222</td>\n </tr>\n <tr>\n <th>24</th>\n <td>3.0</td>\n <td>3</td>\n <td>51.783333</td>\n <td>-0.783333</td>\n </tr>\n </tbody>\n</table>\n</div>"
|
||||
},
|
||||
"metadata": {},
|
||||
"execution_count": 26
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from sklearn.preprocessing import LabelEncoder\n",
|
||||
"\n",
|
||||
"ufos['Country'] = LabelEncoder().fit_transform(ufos['Country'])\n",
|
||||
"\n",
|
||||
"ufos.head()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 27,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"\n",
|
||||
"Selected_features = ['Seconds','Latitude','Longitude']\n",
|
||||
"\n",
|
||||
"X = ufos[Selected_features]\n",
|
||||
"y = ufos['Country']\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 28,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stderr",
|
||||
"text": [
|
||||
"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sklearn/linear_model/logistic.py:432: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.\n",
|
||||
" FutureWarning)\n",
|
||||
"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sklearn/linear_model/logistic.py:469: FutureWarning: Default multi_class will be changed to 'auto' in 0.22. Specify the multi_class option to silence this warning.\n",
|
||||
" \"this warning.\", FutureWarning)\n",
|
||||
" precision recall f1-score support\n",
|
||||
"\n",
|
||||
" 0 1.00 1.00 1.00 41\n",
|
||||
" 1 1.00 0.02 0.05 250\n",
|
||||
" 2 0.00 0.00 0.00 8\n",
|
||||
" 3 0.94 1.00 0.97 131\n",
|
||||
" 4 0.95 1.00 0.97 4743\n",
|
||||
"\n",
|
||||
" accuracy 0.95 5173\n",
|
||||
" macro avg 0.78 0.60 0.60 5173\n",
|
||||
"weighted avg 0.95 0.95 0.93 5173\n",
|
||||
"\n",
|
||||
"Predicted labels: [4 4 4 ... 3 4 4]\n",
|
||||
"Accuracy: 0.9512855209742895\n",
|
||||
"/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/sklearn/metrics/classification.py:1437: UndefinedMetricWarning: Precision and F-score are ill-defined and being set to 0.0 in labels with no predicted samples.\n",
|
||||
" 'precision', 'predicted', average, warn_for)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"from sklearn.model_selection import train_test_split\n",
|
||||
"from sklearn.metrics import accuracy_score, classification_report \n",
|
||||
"from sklearn.linear_model import LogisticRegression\n",
|
||||
"model = LogisticRegression()\n",
|
||||
"model.fit(X_train, y_train)\n",
|
||||
"predictions = model.predict(X_test)\n",
|
||||
"\n",
|
||||
"print(classification_report(y_test, predictions))\n",
|
||||
"print('Predicted labels: ', predictions)\n",
|
||||
"print('Accuracy: ', accuracy_score(y_test, predictions))\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 29,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"[3]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import pickle\n",
|
||||
"model_filename = 'ufo-model.pkl'\n",
|
||||
"pickle.dump(model, open(model_filename,'wb'))\n",
|
||||
"\n",
|
||||
"model = pickle.load(open('ufo-model.pkl','rb'))\n",
|
||||
"print(model.predict([[50,44,-12]]))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
# Crie uma aplicação web para usar o seu modelo de ML
|
||||
|
||||
Nesta secção do currículo, será introduzido a um tópico aplicado de ML: como guardar o seu modelo Scikit-learn como um ficheiro que pode ser utilizado para fazer previsões dentro de uma aplicação web. Depois de guardar o modelo, aprenderá como utilizá-lo numa aplicação web construída em Flask. Primeiro, irá criar um modelo utilizando alguns dados relacionados com avistamentos de OVNIs! Em seguida, irá construir uma aplicação web que permitirá introduzir um número de segundos juntamente com valores de latitude e longitude para prever qual país relatou ter visto um OVNI.
|
||||
|
||||

|
||||
|
||||
Foto por <a href="https://unsplash.com/@mdherren?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Michael Herren</a> em <a href="https://unsplash.com/s/photos/ufo?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||
|
||||
## Lições
|
||||
|
||||
1. [Crie uma Aplicação Web](1-Web-App/README.md)
|
||||
|
||||
## Créditos
|
||||
|
||||
"Crie uma Aplicação Web" foi escrito com ♥️ por [Jen Looper](https://twitter.com/jenlooper).
|
||||
|
||||
♥️ Os questionários foram escritos por Rohan Raj.
|
||||
|
||||
O conjunto de dados foi obtido de [Kaggle](https://www.kaggle.com/NUFORC/ufo-sightings).
|
||||
|
||||
A arquitetura da aplicação web foi sugerida em parte por [este artigo](https://towardsdatascience.com/how-to-easily-deploy-machine-learning-models-using-flask-b95af8fe34d4) e [este repositório](https://github.com/abhinavsagar/machine-learning-deployment) de Abhinav Sagar.
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes do uso desta tradução.
|
||||
@ -0,0 +1,304 @@
|
||||
# Introdução à classificação
|
||||
|
||||
Nestes quatro módulos, vais explorar um dos focos fundamentais do machine learning clássico - _classificação_. Vamos utilizar vários algoritmos de classificação com um conjunto de dados sobre as brilhantes culinárias da Ásia e da Índia. Espero que estejas com fome!
|
||||
|
||||

|
||||
|
||||
> Celebra as culinárias pan-asiáticas nestas lições! Imagem por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
Classificação é uma forma de [aprendizagem supervisionada](https://wikipedia.org/wiki/Supervised_learning) que tem muito em comum com técnicas de regressão. Se o machine learning consiste em prever valores ou nomes para coisas utilizando conjuntos de dados, então a classificação geralmente divide-se em dois grupos: _classificação binária_ e _classificação multicategorias_.
|
||||
|
||||
[](https://youtu.be/eg8DJYwdMyg "Introdução à classificação")
|
||||
|
||||
> 🎥 Clica na imagem acima para ver um vídeo: John Guttag do MIT apresenta a classificação
|
||||
|
||||
Lembra-te:
|
||||
|
||||
- **Regressão linear** ajudou-te a prever relações entre variáveis e a fazer previsões precisas sobre onde um novo ponto de dados se encaixaria em relação a essa linha. Por exemplo, podias prever _qual seria o preço de uma abóbora em setembro vs. dezembro_.
|
||||
- **Regressão logística** ajudou-te a descobrir "categorias binárias": a este preço, _esta abóbora é laranja ou não-laranja_?
|
||||
|
||||
A classificação utiliza vários algoritmos para determinar outras formas de identificar o rótulo ou classe de um ponto de dados. Vamos trabalhar com estes dados sobre culinárias para ver se, ao observar um grupo de ingredientes, conseguimos determinar a sua origem culinária.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
> ### [Esta lição está disponível em R!](../../../../4-Classification/1-Introduction/solution/R/lesson_10.html)
|
||||
|
||||
### Introdução
|
||||
|
||||
Classificação é uma das atividades fundamentais do investigador de machine learning e do cientista de dados. Desde a classificação básica de um valor binário ("este email é spam ou não?"), até à classificação e segmentação complexa de imagens utilizando visão computacional, é sempre útil conseguir organizar dados em classes e fazer perguntas sobre eles.
|
||||
|
||||
De forma mais científica, o teu método de classificação cria um modelo preditivo que te permite mapear a relação entre variáveis de entrada e variáveis de saída.
|
||||
|
||||

|
||||
|
||||
> Problemas binários vs. multicategorias para algoritmos de classificação. Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
Antes de começar o processo de limpeza dos dados, visualizá-los e prepará-los para as nossas tarefas de ML, vamos aprender um pouco sobre as várias formas como o machine learning pode ser utilizado para classificar dados.
|
||||
|
||||
Derivada da [estatística](https://wikipedia.org/wiki/Statistical_classification), a classificação utilizando machine learning clássico usa características, como `fumador`, `peso` e `idade`, para determinar _probabilidade de desenvolver X doença_. Como técnica de aprendizagem supervisionada semelhante aos exercícios de regressão que realizaste anteriormente, os teus dados estão rotulados e os algoritmos de ML utilizam esses rótulos para classificar e prever classes (ou 'características') de um conjunto de dados e atribuí-las a um grupo ou resultado.
|
||||
|
||||
✅ Tira um momento para imaginar um conjunto de dados sobre culinárias. Que tipo de perguntas um modelo multicategorias poderia responder? E um modelo binário? E se quisesses determinar se uma determinada culinária provavelmente utiliza feno-grego? E se quisesses ver se, dado um saco de compras cheio de anis-estrelado, alcachofras, couve-flor e rábano, conseguirias criar um prato típico indiano?
|
||||
|
||||
[](https://youtu.be/GuTeDbaNoEU "Cestos misteriosos malucos")
|
||||
|
||||
> 🎥 Clica na imagem acima para ver um vídeo. Todo o conceito do programa 'Chopped' é o 'cesto misterioso', onde os chefs têm de criar um prato com uma escolha aleatória de ingredientes. Certamente um modelo de ML teria ajudado!
|
||||
|
||||
## Olá 'classificador'
|
||||
|
||||
A pergunta que queremos fazer sobre este conjunto de dados de culinárias é, na verdade, uma **questão multicategorias**, já que temos várias possíveis culinárias nacionais com que trabalhar. Dado um conjunto de ingredientes, a qual destas muitas classes os dados pertencem?
|
||||
|
||||
O Scikit-learn oferece vários algoritmos diferentes para classificar dados, dependendo do tipo de problema que queres resolver. Nas próximas duas lições, vais aprender sobre alguns desses algoritmos.
|
||||
|
||||
## Exercício - limpar e equilibrar os dados
|
||||
|
||||
A primeira tarefa, antes de começar este projeto, é limpar e **equilibrar** os teus dados para obter melhores resultados. Começa com o ficheiro vazio _notebook.ipynb_ na raiz desta pasta.
|
||||
|
||||
A primeira coisa a instalar é [imblearn](https://imbalanced-learn.org/stable/). Este é um pacote do Scikit-learn que te permitirá equilibrar melhor os dados (vais aprender mais sobre esta tarefa em breve).
|
||||
|
||||
1. Para instalar `imblearn`, executa `pip install`, assim:
|
||||
|
||||
```python
|
||||
pip install imblearn
|
||||
```
|
||||
|
||||
1. Importa os pacotes necessários para importar os teus dados e visualizá-los, e também importa `SMOTE` de `imblearn`.
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib as mpl
|
||||
import numpy as np
|
||||
from imblearn.over_sampling import SMOTE
|
||||
```
|
||||
|
||||
Agora estás pronto para importar os dados.
|
||||
|
||||
1. A próxima tarefa será importar os dados:
|
||||
|
||||
```python
|
||||
df = pd.read_csv('../data/cuisines.csv')
|
||||
```
|
||||
|
||||
Utilizar `read_csv()` irá ler o conteúdo do ficheiro csv _cusines.csv_ e colocá-lo na variável `df`.
|
||||
|
||||
1. Verifica a forma dos dados:
|
||||
|
||||
```python
|
||||
df.head()
|
||||
```
|
||||
|
||||
As primeiras cinco linhas têm este aspeto:
|
||||
|
||||
```output
|
||||
| | Unnamed: 0 | cuisine | almond | angelica | anise | anise_seed | apple | apple_brandy | apricot | armagnac | ... | whiskey | white_bread | white_wine | whole_grain_wheat_flour | wine | wood | yam | yeast | yogurt | zucchini |
|
||||
| --- | ---------- | ------- | ------ | -------- | ----- | ---------- | ----- | ------------ | ------- | -------- | --- | ------- | ----------- | ---------- | ----------------------- | ---- | ---- | --- | ----- | ------ | -------- |
|
||||
| 0 | 65 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| 1 | 66 | indian | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| 2 | 67 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| 3 | 68 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
|
||||
| 4 | 69 | indian | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
|
||||
```
|
||||
|
||||
1. Obtém informações sobre estes dados chamando `info()`:
|
||||
|
||||
```python
|
||||
df.info()
|
||||
```
|
||||
|
||||
O teu output será semelhante a:
|
||||
|
||||
```output
|
||||
<class 'pandas.core.frame.DataFrame'>
|
||||
RangeIndex: 2448 entries, 0 to 2447
|
||||
Columns: 385 entries, Unnamed: 0 to zucchini
|
||||
dtypes: int64(384), object(1)
|
||||
memory usage: 7.2+ MB
|
||||
```
|
||||
|
||||
## Exercício - aprender sobre culinárias
|
||||
|
||||
Agora o trabalho começa a tornar-se mais interessante. Vamos descobrir a distribuição dos dados, por culinária.
|
||||
|
||||
1. Representa os dados como barras chamando `barh()`:
|
||||
|
||||
```python
|
||||
df.cuisine.value_counts().plot.barh()
|
||||
```
|
||||
|
||||

|
||||
|
||||
Existem um número finito de culinárias, mas a distribuição dos dados é desigual. Podes corrigir isso! Antes de o fazer, explora um pouco mais.
|
||||
|
||||
1. Descobre a quantidade de dados disponível por culinária e imprime-a:
|
||||
|
||||
```python
|
||||
thai_df = df[(df.cuisine == "thai")]
|
||||
japanese_df = df[(df.cuisine == "japanese")]
|
||||
chinese_df = df[(df.cuisine == "chinese")]
|
||||
indian_df = df[(df.cuisine == "indian")]
|
||||
korean_df = df[(df.cuisine == "korean")]
|
||||
|
||||
print(f'thai df: {thai_df.shape}')
|
||||
print(f'japanese df: {japanese_df.shape}')
|
||||
print(f'chinese df: {chinese_df.shape}')
|
||||
print(f'indian df: {indian_df.shape}')
|
||||
print(f'korean df: {korean_df.shape}')
|
||||
```
|
||||
|
||||
o output será semelhante a:
|
||||
|
||||
```output
|
||||
thai df: (289, 385)
|
||||
japanese df: (320, 385)
|
||||
chinese df: (442, 385)
|
||||
indian df: (598, 385)
|
||||
korean df: (799, 385)
|
||||
```
|
||||
|
||||
## Descobrir ingredientes
|
||||
|
||||
Agora podes aprofundar os dados e aprender quais são os ingredientes típicos por culinária. Deves limpar dados recorrentes que criam confusão entre culinárias, então vamos aprender sobre este problema.
|
||||
|
||||
1. Cria uma função `create_ingredient()` em Python para criar um dataframe de ingredientes. Esta função começará por eliminar uma coluna inútil e organizar os ingredientes pelo seu número:
|
||||
|
||||
```python
|
||||
def create_ingredient_df(df):
|
||||
ingredient_df = df.T.drop(['cuisine','Unnamed: 0']).sum(axis=1).to_frame('value')
|
||||
ingredient_df = ingredient_df[(ingredient_df.T != 0).any()]
|
||||
ingredient_df = ingredient_df.sort_values(by='value', ascending=False,
|
||||
inplace=False)
|
||||
return ingredient_df
|
||||
```
|
||||
|
||||
Agora podes usar essa função para ter uma ideia dos dez ingredientes mais populares por culinária.
|
||||
|
||||
1. Chama `create_ingredient()` e representa os dados chamando `barh()`:
|
||||
|
||||
```python
|
||||
thai_ingredient_df = create_ingredient_df(thai_df)
|
||||
thai_ingredient_df.head(10).plot.barh()
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Faz o mesmo para os dados japoneses:
|
||||
|
||||
```python
|
||||
japanese_ingredient_df = create_ingredient_df(japanese_df)
|
||||
japanese_ingredient_df.head(10).plot.barh()
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Agora para os ingredientes chineses:
|
||||
|
||||
```python
|
||||
chinese_ingredient_df = create_ingredient_df(chinese_df)
|
||||
chinese_ingredient_df.head(10).plot.barh()
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Representa os ingredientes indianos:
|
||||
|
||||
```python
|
||||
indian_ingredient_df = create_ingredient_df(indian_df)
|
||||
indian_ingredient_df.head(10).plot.barh()
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Finalmente, representa os ingredientes coreanos:
|
||||
|
||||
```python
|
||||
korean_ingredient_df = create_ingredient_df(korean_df)
|
||||
korean_ingredient_df.head(10).plot.barh()
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Agora, elimina os ingredientes mais comuns que criam confusão entre culinárias distintas, chamando `drop()`:
|
||||
|
||||
Toda a gente adora arroz, alho e gengibre!
|
||||
|
||||
```python
|
||||
feature_df= df.drop(['cuisine','Unnamed: 0','rice','garlic','ginger'], axis=1)
|
||||
labels_df = df.cuisine #.unique()
|
||||
feature_df.head()
|
||||
```
|
||||
|
||||
## Equilibrar o conjunto de dados
|
||||
|
||||
Agora que limpaste os dados, utiliza [SMOTE](https://imbalanced-learn.org/dev/references/generated/imblearn.over_sampling.SMOTE.html) - "Técnica de Sobreamostragem Sintética de Minorias" - para equilibrá-los.
|
||||
|
||||
1. Chama `fit_resample()`, esta estratégia gera novas amostras por interpolação.
|
||||
|
||||
```python
|
||||
oversample = SMOTE()
|
||||
transformed_feature_df, transformed_label_df = oversample.fit_resample(feature_df, labels_df)
|
||||
```
|
||||
|
||||
Ao equilibrar os teus dados, vais obter melhores resultados ao classificá-los. Pensa numa classificação binária. Se a maior parte dos teus dados pertence a uma classe, um modelo de ML vai prever essa classe com mais frequência, apenas porque há mais dados para ela. O equilíbrio dos dados elimina esta desigualdade.
|
||||
|
||||
1. Agora podes verificar os números de rótulos por ingrediente:
|
||||
|
||||
```python
|
||||
print(f'new label count: {transformed_label_df.value_counts()}')
|
||||
print(f'old label count: {df.cuisine.value_counts()}')
|
||||
```
|
||||
|
||||
O teu output será semelhante a:
|
||||
|
||||
```output
|
||||
new label count: korean 799
|
||||
chinese 799
|
||||
indian 799
|
||||
japanese 799
|
||||
thai 799
|
||||
Name: cuisine, dtype: int64
|
||||
old label count: korean 799
|
||||
indian 598
|
||||
chinese 442
|
||||
japanese 320
|
||||
thai 289
|
||||
Name: cuisine, dtype: int64
|
||||
```
|
||||
|
||||
Os dados estão limpos, equilibrados e muito deliciosos!
|
||||
|
||||
1. O último passo é guardar os teus dados equilibrados, incluindo rótulos e características, num novo dataframe que pode ser exportado para um ficheiro:
|
||||
|
||||
```python
|
||||
transformed_df = pd.concat([transformed_label_df,transformed_feature_df],axis=1, join='outer')
|
||||
```
|
||||
|
||||
1. Podes dar mais uma olhada nos dados utilizando `transformed_df.head()` e `transformed_df.info()`. Guarda uma cópia destes dados para uso em lições futuras:
|
||||
|
||||
```python
|
||||
transformed_df.head()
|
||||
transformed_df.info()
|
||||
transformed_df.to_csv("../data/cleaned_cuisines.csv")
|
||||
```
|
||||
|
||||
Este novo CSV pode agora ser encontrado na pasta de dados raiz.
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Este currículo contém vários conjuntos de dados interessantes. Explora as pastas `data` e vê se alguma contém conjuntos de dados que seriam apropriados para classificação binária ou multicategorias. Que perguntas farias a este conjunto de dados?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Estudo Individual
|
||||
|
||||
Explora a API do SMOTE. Para que casos de uso é mais adequado? Que problemas resolve?
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Explora métodos de classificação](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Explorar métodos de classificação
|
||||
|
||||
## Instruções
|
||||
|
||||
Na [documentação do Scikit-learn](https://scikit-learn.org/stable/supervised_learning.html) encontrarás uma longa lista de formas de classificar dados. Faz uma pequena caça ao tesouro nestes documentos: o teu objetivo é procurar métodos de classificação e associar um conjunto de dados deste currículo, uma pergunta que possas fazer sobre ele e uma técnica de classificação. Cria uma folha de cálculo ou tabela num ficheiro .doc e explica como o conjunto de dados funcionaria com o algoritmo de classificação.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplário | Adequado | Necessita de Melhorias |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| | é apresentado um documento que descreve 5 algoritmos juntamente com uma técnica de classificação. A descrição é bem explicada e detalhada. | é apresentado um documento que descreve 3 algoritmos juntamente com uma técnica de classificação. A descrição é bem explicada e detalhada. | é apresentado um documento que descreve menos de três algoritmos juntamente com uma técnica de classificação e a descrição não é bem explicada nem detalhada. |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,39 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": 3
|
||||
},
|
||||
"orig_nbformat": 2,
|
||||
"coopTranslator": {
|
||||
"original_hash": "d544ef384b7ba73757d830a72372a7f2",
|
||||
"translation_date": "2025-09-03T20:33:35+00:00",
|
||||
"source_file": "4-Classification/1-Introduction/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"source": [],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,723 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "lesson_10-R.ipynb",
|
||||
"provenance": [],
|
||||
"collapsed_sections": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "ir",
|
||||
"display_name": "R"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "R"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "2621e24705e8100893c9bf84e0fc8aef",
|
||||
"translation_date": "2025-09-03T20:39:15+00:00",
|
||||
"source_file": "4-Classification/1-Introduction/solution/R/lesson_10-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Construir um modelo de classificação: Deliciosas Cozinhas Asiáticas e Indianas\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "ItETB4tSFprR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Introdução à classificação: Limpar, preparar e visualizar os seus dados\n",
|
||||
"\n",
|
||||
"Nestes quatro módulos, irá explorar um dos focos fundamentais do machine learning clássico - *classificação*. Vamos percorrer o uso de vários algoritmos de classificação com um conjunto de dados sobre as brilhantes culinárias da Ásia e da Índia. Esperamos que esteja com fome!\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/pinch.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Celebre as culinárias pan-asiáticas nestas lições! Imagem por Jen Looper</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<!---->\n",
|
||||
"\n",
|
||||
"Classificação é uma forma de [aprendizagem supervisionada](https://wikipedia.org/wiki/Supervised_learning) que tem muito em comum com técnicas de regressão. Na classificação, treina-se um modelo para prever a que `categoria` um item pertence. Se o machine learning trata de prever valores ou nomes para coisas usando conjuntos de dados, então a classificação geralmente se divide em dois grupos: *classificação binária* e *classificação multicategorias*.\n",
|
||||
"\n",
|
||||
"Lembre-se:\n",
|
||||
"\n",
|
||||
"- **Regressão linear** ajudou-o a prever relações entre variáveis e fazer previsões precisas sobre onde um novo ponto de dados se encaixaria em relação àquela linha. Por exemplo, poderia prever valores numéricos como *qual seria o preço de uma abóbora em setembro vs. dezembro*.\n",
|
||||
"\n",
|
||||
"- **Regressão logística** ajudou-o a descobrir \"categorias binárias\": a este preço, *esta abóbora é laranja ou não-laranja*?\n",
|
||||
"\n",
|
||||
"A classificação utiliza vários algoritmos para determinar outras formas de identificar o rótulo ou classe de um ponto de dados. Vamos trabalhar com estes dados de culinária para ver se, ao observar um grupo de ingredientes, conseguimos determinar a sua origem culinária.\n",
|
||||
"\n",
|
||||
"### [**Questionário pré-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/19/)\n",
|
||||
"\n",
|
||||
"### **Introdução**\n",
|
||||
"\n",
|
||||
"A classificação é uma das atividades fundamentais do investigador de machine learning e do cientista de dados. Desde a classificação básica de um valor binário (\"este email é spam ou não?\"), até à classificação e segmentação complexa de imagens usando visão computacional, é sempre útil poder organizar dados em classes e fazer perguntas sobre eles.\n",
|
||||
"\n",
|
||||
"Para expressar o processo de forma mais científica, o seu método de classificação cria um modelo preditivo que permite mapear a relação entre variáveis de entrada e variáveis de saída.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/binary-multiclass.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Problemas binários vs. multicategorias para algoritmos de classificação. Infográfico por Jen Looper</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Antes de começar o processo de limpar os nossos dados, visualizá-los e prepará-los para as nossas tarefas de ML, vamos aprender um pouco sobre as várias formas como o machine learning pode ser utilizado para classificar dados.\n",
|
||||
"\n",
|
||||
"Derivada da [estatística](https://wikipedia.org/wiki/Statistical_classification), a classificação usando machine learning clássico utiliza características, como `fumador`, `peso` e `idade`, para determinar *probabilidade de desenvolver X doença*. Como uma técnica de aprendizagem supervisionada semelhante aos exercícios de regressão que realizou anteriormente, os seus dados são rotulados e os algoritmos de ML utilizam esses rótulos para classificar e prever classes (ou 'características') de um conjunto de dados e atribuí-los a um grupo ou resultado.\n",
|
||||
"\n",
|
||||
"✅ Tire um momento para imaginar um conjunto de dados sobre culinárias. O que um modelo multicategorias seria capaz de responder? O que um modelo binário seria capaz de responder? E se quisesse determinar se uma determinada culinária provavelmente utiliza feno-grego? E se quisesse ver se, dado um saco de compras cheio de anis-estrelado, alcachofras, couve-flor e rábano, conseguiria criar um prato típico indiano?\n",
|
||||
"\n",
|
||||
"### **Olá 'classificador'**\n",
|
||||
"\n",
|
||||
"A pergunta que queremos fazer a este conjunto de dados de culinária é, na verdade, uma questão **multicategorias**, já que temos várias possíveis culinárias nacionais com que trabalhar. Dado um lote de ingredientes, a qual destas muitas classes os dados se encaixam?\n",
|
||||
"\n",
|
||||
"O Tidymodels oferece vários algoritmos diferentes para classificar dados, dependendo do tipo de problema que deseja resolver. Nas próximas duas lições, aprenderá sobre alguns desses algoritmos.\n",
|
||||
"\n",
|
||||
"#### **Pré-requisitos**\n",
|
||||
"\n",
|
||||
"Para esta lição, precisaremos dos seguintes pacotes para limpar, preparar e visualizar os nossos dados:\n",
|
||||
"\n",
|
||||
"- `tidyverse`: O [tidyverse](https://www.tidyverse.org/) é uma [coleção de pacotes R](https://www.tidyverse.org/packages) projetada para tornar a ciência de dados mais rápida, fácil e divertida!\n",
|
||||
"\n",
|
||||
"- `tidymodels`: O [tidymodels](https://www.tidymodels.org/) é uma [coleção de pacotes](https://www.tidymodels.org/packages/) para modelagem e machine learning.\n",
|
||||
"\n",
|
||||
"- `DataExplorer`: O [pacote DataExplorer](https://cran.r-project.org/web/packages/DataExplorer/vignettes/dataexplorer-intro.html) foi criado para simplificar e automatizar o processo de EDA e geração de relatórios.\n",
|
||||
"\n",
|
||||
"- `themis`: O [pacote themis](https://themis.tidymodels.org/) fornece passos extras de receitas para lidar com dados desequilibrados.\n",
|
||||
"\n",
|
||||
"Pode instalá-los como:\n",
|
||||
"\n",
|
||||
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"DataExplorer\", \"here\"))`\n",
|
||||
"\n",
|
||||
"Alternativamente, o script abaixo verifica se tem os pacotes necessários para completar este módulo e instala-os caso estejam em falta.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "ri5bQxZ-Fz_0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\r\n",
|
||||
"\r\n",
|
||||
"pacman::p_load(tidyverse, tidymodels, DataExplorer, themis, here)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "KIPxa4elGAPI"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Mais tarde, iremos carregar estes pacotes incríveis e torná-los disponíveis na nossa sessão atual de R. (Isto é apenas para ilustração, `pacman::p_load()` já fez isso por si)\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "YkKAxOJvGD4C"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Exercício - limpar e equilibrar os seus dados\n",
|
||||
"\n",
|
||||
"A primeira tarefa, antes de começar este projeto, é limpar e **equilibrar** os seus dados para obter melhores resultados.\n",
|
||||
"\n",
|
||||
"Vamos conhecer os dados! 🕵️\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "PFkQDlk0GN5O"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Import data\r\n",
|
||||
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\r\n",
|
||||
"\r\n",
|
||||
"# View the first 5 rows\r\n",
|
||||
"df %>% \r\n",
|
||||
" slice_head(n = 5)\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "Qccw7okxGT0S"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Interessante! Pelo que parece, a primeira coluna é uma espécie de coluna `id`. Vamos obter um pouco mais de informações sobre os dados.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "XrWnlgSrGVmR"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Basic information about the data\r\n",
|
||||
"df %>%\r\n",
|
||||
" introduce()\r\n",
|
||||
"\r\n",
|
||||
"# Visualize basic information above\r\n",
|
||||
"df %>% \r\n",
|
||||
" plot_intro(ggtheme = theme_light())"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "4UcGmxRxGieA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"A partir dos resultados, podemos ver imediatamente que temos `2448` linhas e `385` colunas e `0` valores em falta. Também temos 1 coluna discreta, *cuisine*.\n",
|
||||
"\n",
|
||||
"## Exercício - aprender sobre cozinhas\n",
|
||||
"\n",
|
||||
"Agora o trabalho começa a tornar-se mais interessante. Vamos descobrir a distribuição dos dados, por cozinha.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "AaPubl__GmH5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Count observations per cuisine\r\n",
|
||||
"df %>% \r\n",
|
||||
" count(cuisine) %>% \r\n",
|
||||
" arrange(n)\r\n",
|
||||
"\r\n",
|
||||
"# Plot the distribution\r\n",
|
||||
"theme_set(theme_light())\r\n",
|
||||
"df %>% \r\n",
|
||||
" count(cuisine) %>% \r\n",
|
||||
" ggplot(mapping = aes(x = n, y = reorder(cuisine, -n))) +\r\n",
|
||||
" geom_col(fill = \"midnightblue\", alpha = 0.7) +\r\n",
|
||||
" ylab(\"cuisine\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "FRsBVy5eGrrv"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Existem um número finito de cozinhas, mas a distribuição dos dados é desigual. Pode resolver isso! Antes de o fazer, explore um pouco mais.\n",
|
||||
"\n",
|
||||
"De seguida, vamos atribuir cada cozinha ao seu próprio tibble e descobrir quantos dados estão disponíveis (linhas, colunas) por cozinha.\n",
|
||||
"\n",
|
||||
"> Um [tibble](https://tibble.tidyverse.org/) é uma versão moderna de um data frame.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/dplyr_filter.jpg\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Ilustração por @allison_horst</figcaption>\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "vVvyDb1kG2in"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Create individual tibble for the cuisines\r\n",
|
||||
"thai_df <- df %>% \r\n",
|
||||
" filter(cuisine == \"thai\")\r\n",
|
||||
"japanese_df <- df %>% \r\n",
|
||||
" filter(cuisine == \"japanese\")\r\n",
|
||||
"chinese_df <- df %>% \r\n",
|
||||
" filter(cuisine == \"chinese\")\r\n",
|
||||
"indian_df <- df %>% \r\n",
|
||||
" filter(cuisine == \"indian\")\r\n",
|
||||
"korean_df <- df %>% \r\n",
|
||||
" filter(cuisine == \"korean\")\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Find out how much data is available per cuisine\r\n",
|
||||
"cat(\" thai df:\", dim(thai_df), \"\\n\",\r\n",
|
||||
" \"japanese df:\", dim(japanese_df), \"\\n\",\r\n",
|
||||
" \"chinese_df:\", dim(chinese_df), \"\\n\",\r\n",
|
||||
" \"indian_df:\", dim(indian_df), \"\\n\",\r\n",
|
||||
" \"korean_df:\", dim(korean_df))"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "0TvXUxD3G8Bk"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## **Exercício - Descobrir os principais ingredientes por cozinha usando dplyr**\n",
|
||||
"\n",
|
||||
"Agora pode explorar mais profundamente os dados e descobrir quais são os ingredientes típicos de cada cozinha. Deve limpar os dados recorrentes que criam confusão entre as cozinhas, então vamos aprender sobre este problema.\n",
|
||||
"\n",
|
||||
"Crie uma função `create_ingredient()` em R que devolva um dataframe de ingredientes. Esta função começará por remover uma coluna pouco útil e organizar os ingredientes pelo seu número de ocorrências.\n",
|
||||
"\n",
|
||||
"A estrutura básica de uma função em R é:\n",
|
||||
"\n",
|
||||
"`myFunction <- function(arglist){`\n",
|
||||
"\n",
|
||||
"**`...`**\n",
|
||||
"\n",
|
||||
"**`return`**`(value)`\n",
|
||||
"\n",
|
||||
"`}`\n",
|
||||
"\n",
|
||||
"Uma introdução prática às funções em R pode ser encontrada [aqui](https://skirmer.github.io/presentations/functions_with_r.html#1).\n",
|
||||
"\n",
|
||||
"Vamos direto ao assunto! Vamos utilizar os [verbos dplyr](https://dplyr.tidyverse.org/) que temos vindo a aprender nas nossas lições anteriores. Como resumo:\n",
|
||||
"\n",
|
||||
"- `dplyr::select()`: ajuda a escolher quais **colunas** manter ou excluir.\n",
|
||||
"\n",
|
||||
"- `dplyr::pivot_longer()`: ajuda a \"alongar\" os dados, aumentando o número de linhas e diminuindo o número de colunas.\n",
|
||||
"\n",
|
||||
"- `dplyr::group_by()` e `dplyr::summarise()`: ajudam a encontrar estatísticas resumidas para diferentes grupos e colocá-las numa tabela organizada.\n",
|
||||
"\n",
|
||||
"- `dplyr::filter()`: cria um subconjunto dos dados contendo apenas as linhas que satisfazem as suas condições.\n",
|
||||
"\n",
|
||||
"- `dplyr::mutate()`: ajuda a criar ou modificar colunas.\n",
|
||||
"\n",
|
||||
"Confira este [tutorial *artístico* learnr](https://allisonhorst.shinyapps.io/dplyr-learnr/#section-welcome) de Allison Horst, que introduz algumas funções úteis de manipulação de dados no dplyr *(parte do Tidyverse)*.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "K3RF5bSCHC76"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Creates a functions that returns the top ingredients by class\r\n",
|
||||
"\r\n",
|
||||
"create_ingredient <- function(df){\r\n",
|
||||
" \r\n",
|
||||
" # Drop the id column which is the first colum\r\n",
|
||||
" ingredient_df = df %>% select(-1) %>% \r\n",
|
||||
" # Transpose data to a long format\r\n",
|
||||
" pivot_longer(!cuisine, names_to = \"ingredients\", values_to = \"count\") %>% \r\n",
|
||||
" # Find the top most ingredients for a particular cuisine\r\n",
|
||||
" group_by(ingredients) %>% \r\n",
|
||||
" summarise(n_instances = sum(count)) %>% \r\n",
|
||||
" filter(n_instances != 0) %>% \r\n",
|
||||
" # Arrange by descending order\r\n",
|
||||
" arrange(desc(n_instances)) %>% \r\n",
|
||||
" mutate(ingredients = factor(ingredients) %>% fct_inorder())\r\n",
|
||||
" \r\n",
|
||||
" \r\n",
|
||||
" return(ingredient_df)\r\n",
|
||||
"} # End of function"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "uB_0JR82HTPa"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Agora podemos usar a função para obter uma ideia dos dez ingredientes mais populares por cozinha. Vamos testá-la com `thai_df`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "h9794WF8HWmc"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Call create_ingredient and display popular ingredients\r\n",
|
||||
"thai_ingredient_df <- create_ingredient(df = thai_df)\r\n",
|
||||
"\r\n",
|
||||
"thai_ingredient_df %>% \r\n",
|
||||
" slice_head(n = 10)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "agQ-1HrcHaEA"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Na seção anterior, utilizámos `geom_col()`, vamos ver como pode usar `geom_bar` também, para criar gráficos de barras. Use `?geom_bar` para leitura adicional.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "kHu9ffGjHdcX"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Make a bar chart for popular thai cuisines\r\n",
|
||||
"thai_ingredient_df %>% \r\n",
|
||||
" slice_head(n = 10) %>% \r\n",
|
||||
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
||||
" geom_bar(stat = \"identity\", width = 0.5, fill = \"steelblue\") +\r\n",
|
||||
" xlab(\"\") + ylab(\"\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "fb3Bx_3DHj6e"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"id": "RHP_xgdkHnvM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Get popular ingredients for Japanese cuisines and make bar chart\r\n",
|
||||
"create_ingredient(df = japanese_df) %>% \r\n",
|
||||
" slice_head(n = 10) %>%\r\n",
|
||||
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
||||
" geom_bar(stat = \"identity\", width = 0.5, fill = \"darkorange\", alpha = 0.8) +\r\n",
|
||||
" xlab(\"\") + ylab(\"\")\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "019v8F0XHrRU"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"E quanto às cozinhas chinesas?\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "iIGM7vO8Hu3v"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Get popular ingredients for Chinese cuisines and make bar chart\r\n",
|
||||
"create_ingredient(df = chinese_df) %>% \r\n",
|
||||
" slice_head(n = 10) %>%\r\n",
|
||||
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
||||
" geom_bar(stat = \"identity\", width = 0.5, fill = \"cyan4\", alpha = 0.8) +\r\n",
|
||||
" xlab(\"\") + ylab(\"\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "lHd9_gd2HyzU"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"id": "ir8qyQbNH1c7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Get popular ingredients for Indian cuisines and make bar chart\r\n",
|
||||
"create_ingredient(df = indian_df) %>% \r\n",
|
||||
" slice_head(n = 10) %>%\r\n",
|
||||
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
||||
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#041E42FF\", alpha = 0.8) +\r\n",
|
||||
" xlab(\"\") + ylab(\"\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "ApukQtKjH5FO"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [],
|
||||
"metadata": {
|
||||
"id": "qv30cwY1H-FM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Get popular ingredients for Korean cuisines and make bar chart\r\n",
|
||||
"create_ingredient(df = korean_df) %>% \r\n",
|
||||
" slice_head(n = 10) %>%\r\n",
|
||||
" ggplot(aes(x = n_instances, y = ingredients)) +\r\n",
|
||||
" geom_bar(stat = \"identity\", width = 0.5, fill = \"#852419FF\", alpha = 0.8) +\r\n",
|
||||
" xlab(\"\") + ylab(\"\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "lumgk9cHIBie"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"A partir das visualizações de dados, podemos agora eliminar os ingredientes mais comuns que geram confusão entre diferentes cozinhas, utilizando `dplyr::select()`.\n",
|
||||
"\n",
|
||||
"Toda a gente adora arroz, alho e gengibre!\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "iO4veMXuIEta"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Drop id column, rice, garlic and ginger from our original data set\r\n",
|
||||
"df_select <- df %>% \r\n",
|
||||
" select(-c(1, rice, garlic, ginger))\r\n",
|
||||
"\r\n",
|
||||
"# Display new data set\r\n",
|
||||
"df_select %>% \r\n",
|
||||
" slice_head(n = 5)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "iHJPiG6rIUcK"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Pré-processamento de dados usando receitas 👩🍳👨🍳 - Lidando com dados desequilibrados ⚖️\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/recipes.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Ilustração por @allison_horst</figcaption>\n",
|
||||
"\n",
|
||||
"Dado que esta lição é sobre culinárias, temos de colocar `recipes` em contexto.\n",
|
||||
"\n",
|
||||
"O Tidymodels oferece mais um pacote interessante: `recipes` - um pacote para pré-processamento de dados.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "kkFd-JxdIaL6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Vamos dar uma olhada novamente na distribuição das nossas culinárias.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "6l2ubtTPJAhY"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Distribution of cuisines\r\n",
|
||||
"old_label_count <- df_select %>% \r\n",
|
||||
" count(cuisine) %>% \r\n",
|
||||
" arrange(desc(n))\r\n",
|
||||
"\r\n",
|
||||
"old_label_count"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "1e-E9cb7JDVi"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Como pode ver, há uma distribuição bastante desigual no número de cozinhas. As cozinhas coreanas são quase 3 vezes mais numerosas do que as tailandesas. Dados desequilibrados frequentemente têm efeitos negativos no desempenho do modelo. Pense numa classificação binária. Se a maior parte dos seus dados pertence a uma classe, um modelo de ML vai prever essa classe com mais frequência, simplesmente porque há mais dados disponíveis para ela. Equilibrar os dados corrige qualquer desvio e ajuda a eliminar esse desequilíbrio. Muitos modelos têm o melhor desempenho quando o número de observações é igual e, por isso, tendem a ter dificuldades com dados desequilibrados.\n",
|
||||
"\n",
|
||||
"Existem principalmente duas formas de lidar com conjuntos de dados desequilibrados:\n",
|
||||
"\n",
|
||||
"- adicionar observações à classe minoritária: `Over-sampling`, por exemplo, utilizando um algoritmo SMOTE\n",
|
||||
"\n",
|
||||
"- remover observações da classe maioritária: `Under-sampling`\n",
|
||||
"\n",
|
||||
"Vamos agora demonstrar como lidar com conjuntos de dados desequilibrados utilizando uma `recipe`. Uma recipe pode ser vista como um plano que descreve quais passos devem ser aplicados a um conjunto de dados para prepará-lo para análise de dados.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "soAw6826JKx9"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Load themis package for dealing with imbalanced data\r\n",
|
||||
"library(themis)\r\n",
|
||||
"\r\n",
|
||||
"# Create a recipe for preprocessing data\r\n",
|
||||
"cuisines_recipe <- recipe(cuisine ~ ., data = df_select) %>% \r\n",
|
||||
" step_smote(cuisine)\r\n",
|
||||
"\r\n",
|
||||
"cuisines_recipe"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "HS41brUIJVJy"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Vamos analisar os nossos passos de pré-processamento.\n",
|
||||
"\n",
|
||||
"- A chamada para `recipe()` com uma fórmula indica à receita os *papéis* das variáveis usando os dados de `df_select` como referência. Por exemplo, a coluna `cuisine` foi atribuída ao papel de `outcome`, enquanto as restantes colunas foram atribuídas ao papel de `predictor`.\n",
|
||||
"\n",
|
||||
"- [`step_smote(cuisine)`](https://themis.tidymodels.org/reference/step_smote.html) cria uma *especificação* de um passo da receita que gera sinteticamente novos exemplos da classe minoritária utilizando os vizinhos mais próximos desses casos.\n",
|
||||
"\n",
|
||||
"Agora, se quisermos ver os dados pré-processados, teremos de [**`prep()`**](https://recipes.tidymodels.org/reference/prep.html) e [**`bake()`**](https://recipes.tidymodels.org/reference/bake.html) a nossa receita.\n",
|
||||
"\n",
|
||||
"`prep()`: estima os parâmetros necessários a partir de um conjunto de treino que podem ser posteriormente aplicados a outros conjuntos de dados.\n",
|
||||
"\n",
|
||||
"`bake()`: aplica uma receita preparada às operações em qualquer conjunto de dados.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "Yb-7t7XcJaC8"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Prep and bake the recipe\r\n",
|
||||
"preprocessed_df <- cuisines_recipe %>% \r\n",
|
||||
" prep() %>% \r\n",
|
||||
" bake(new_data = NULL) %>% \r\n",
|
||||
" relocate(cuisine)\r\n",
|
||||
"\r\n",
|
||||
"# Display data\r\n",
|
||||
"preprocessed_df %>% \r\n",
|
||||
" slice_head(n = 5)\r\n",
|
||||
"\r\n",
|
||||
"# Quick summary stats\r\n",
|
||||
"preprocessed_df %>% \r\n",
|
||||
" introduce()"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "9QhSgdpxJl44"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Vamos agora verificar a distribuição das nossas culinárias e compará-las com os dados desequilibrados.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "dmidELh_LdV7"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Distribution of cuisines\r\n",
|
||||
"new_label_count <- preprocessed_df %>% \r\n",
|
||||
" count(cuisine) %>% \r\n",
|
||||
" arrange(desc(n))\r\n",
|
||||
"\r\n",
|
||||
"list(new_label_count = new_label_count,\r\n",
|
||||
" old_label_count = old_label_count)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "aSh23klBLwDz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Yum! Os dados estão limpos, equilibrados e muito deliciosos 😋!\n",
|
||||
"\n",
|
||||
"> Normalmente, uma receita é usada como um pré-processador para modelagem, onde define quais passos devem ser aplicados a um conjunto de dados para prepará-lo para a modelagem. Nesse caso, um `workflow()` é geralmente utilizado (como já vimos nas nossas lições anteriores) em vez de estimar manualmente uma receita.\n",
|
||||
">\n",
|
||||
"> Assim, normalmente não é necessário **`prep()`** e **`bake()`** receitas quando se utiliza tidymodels, mas estas são funções úteis para ter na sua caixa de ferramentas para confirmar que as receitas estão a fazer o que espera, como no nosso caso.\n",
|
||||
">\n",
|
||||
"> Quando se **`bake()`** uma receita preparada com **`new_data = NULL`**, obtém-se de volta os dados que foram fornecidos ao definir a receita, mas que passaram pelos passos de pré-processamento.\n",
|
||||
"\n",
|
||||
"Vamos agora guardar uma cópia destes dados para usar em lições futuras:\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "HEu80HZ8L7ae"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Save preprocessed data\r\n",
|
||||
"write_csv(preprocessed_df, \"../../../data/cleaned_cuisines_R.csv\")"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"id": "cBmCbIgrMOI6"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Este novo CSV pode agora ser encontrado na pasta raiz de dados.\n",
|
||||
"\n",
|
||||
"**🚀Desafio**\n",
|
||||
"\n",
|
||||
"Este currículo contém vários conjuntos de dados interessantes. Explore as pastas `data` e veja se alguma contém conjuntos de dados que seriam apropriados para classificação binária ou multi-classe. Que perguntas faria sobre este conjunto de dados?\n",
|
||||
"\n",
|
||||
"## [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/20/)\n",
|
||||
"\n",
|
||||
"## **Revisão & Estudo Individual**\n",
|
||||
"\n",
|
||||
"- Veja o [pacote themis](https://github.com/tidymodels/themis). Que outras técnicas poderíamos usar para lidar com dados desbalanceados?\n",
|
||||
"\n",
|
||||
"- Site de referência dos [modelos tidy](https://www.tidymodels.org/start/).\n",
|
||||
"\n",
|
||||
"- H. Wickham e G. Grolemund, [*R for Data Science: Visualize, Model, Transform, Tidy, and Import Data*](https://r4ds.had.co.nz/).\n",
|
||||
"\n",
|
||||
"#### OBRIGADO A:\n",
|
||||
"\n",
|
||||
"[`Allison Horst`](https://twitter.com/allison_horst/) por criar as ilustrações incríveis que tornam o R mais acolhedor e envolvente. Encontre mais ilustrações na sua [galeria](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
|
||||
"\n",
|
||||
"[Cassie Breviu](https://www.twitter.com/cassieview) e [Jen Looper](https://www.twitter.com/jenlooper) por criarem a versão original em Python deste módulo ♥️\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Arte por @allison_horst</figcaption>\n"
|
||||
],
|
||||
"metadata": {
|
||||
"id": "WQs5621pMGwf"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,14 @@
|
||||
# Estude os solucionadores
|
||||
## Instruções
|
||||
|
||||
Nesta lição, aprendeste sobre os vários solucionadores que combinam algoritmos com um processo de aprendizagem automática para criar um modelo preciso. Revê os solucionadores mencionados na lição e escolhe dois. Com as tuas próprias palavras, compara e contrasta esses dois solucionadores. Que tipo de problema eles resolvem? Como trabalham com diferentes estruturas de dados? Por que escolherias um em vez do outro?
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita Melhorar |
|
||||
| --------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------ | ---------------------------- |
|
||||
| | Um ficheiro .doc é apresentado com dois parágrafos, um sobre cada solucionador, comparando-os de forma reflexiva. | Um ficheiro .doc é apresentado com apenas um parágrafo | A tarefa está incompleta |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,41 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": 3
|
||||
},
|
||||
"orig_nbformat": 2,
|
||||
"coopTranslator": {
|
||||
"original_hash": "68829b06b4dcd512d3327849191f4d7f",
|
||||
"translation_date": "2025-09-03T20:19:58+00:00",
|
||||
"source_file": "4-Classification/2-Classifiers-1/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"source": [
|
||||
"# Construir Modelos de Classificação\n"
|
||||
],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,240 @@
|
||||
# Classificadores de culinária 2
|
||||
|
||||
Nesta segunda lição sobre classificação, vais explorar mais formas de classificar dados numéricos. Também vais aprender sobre as implicações de escolher um classificador em vez de outro.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
### Pré-requisitos
|
||||
|
||||
Assumimos que completaste as lições anteriores e tens um conjunto de dados limpo na tua pasta `data`, chamado _cleaned_cuisines.csv_, na raiz desta pasta de 4 lições.
|
||||
|
||||
### Preparação
|
||||
|
||||
Carregámos o teu ficheiro _notebook.ipynb_ com o conjunto de dados limpo e dividimo-lo em dataframes X e y, prontos para o processo de construção do modelo.
|
||||
|
||||
## Um mapa de classificação
|
||||
|
||||
Anteriormente, aprendeste sobre as várias opções disponíveis para classificar dados utilizando o guia da Microsoft. O Scikit-learn oferece um guia semelhante, mas mais detalhado, que pode ajudar ainda mais a restringir os estimadores (outro termo para classificadores):
|
||||
|
||||

|
||||
> Dica: [visita este mapa online](https://scikit-learn.org/stable/tutorial/machine_learning_map/) e explora os caminhos para ler a documentação.
|
||||
|
||||
### O plano
|
||||
|
||||
Este mapa é muito útil quando tens uma compreensão clara dos teus dados, pois podes 'percorrer' os seus caminhos até uma decisão:
|
||||
|
||||
- Temos >50 amostras
|
||||
- Queremos prever uma categoria
|
||||
- Temos dados rotulados
|
||||
- Temos menos de 100K amostras
|
||||
- ✨ Podemos escolher um Linear SVC
|
||||
- Se isso não funcionar, como temos dados numéricos:
|
||||
- Podemos tentar um ✨ KNeighbors Classifier
|
||||
- Se isso não funcionar, tentar ✨ SVC e ✨ Ensemble Classifiers
|
||||
|
||||
Este é um caminho muito útil a seguir.
|
||||
|
||||
## Exercício - dividir os dados
|
||||
|
||||
Seguindo este caminho, devemos começar por importar algumas bibliotecas para usar.
|
||||
|
||||
1. Importa as bibliotecas necessárias:
|
||||
|
||||
```python
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.svm import SVC
|
||||
from sklearn.ensemble import RandomForestClassifier, AdaBoostClassifier
|
||||
from sklearn.model_selection import train_test_split, cross_val_score
|
||||
from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report, precision_recall_curve
|
||||
import numpy as np
|
||||
```
|
||||
|
||||
1. Divide os teus dados de treino e teste:
|
||||
|
||||
```python
|
||||
X_train, X_test, y_train, y_test = train_test_split(cuisines_feature_df, cuisines_label_df, test_size=0.3)
|
||||
```
|
||||
|
||||
## Classificador Linear SVC
|
||||
|
||||
O clustering por Support-Vector (SVC) é um membro da família de técnicas de ML chamadas Support-Vector Machines (aprende mais sobre estas abaixo). Neste método, podes escolher um 'kernel' para decidir como agrupar os rótulos. O parâmetro 'C' refere-se à 'regularização', que regula a influência dos parâmetros. O kernel pode ser um de [vários](https://scikit-learn.org/stable/modules/generated/sklearn.svm.SVC.html#sklearn.svm.SVC); aqui definimos como 'linear' para garantir que utilizamos o Linear SVC. A probabilidade por padrão é 'falsa'; aqui definimos como 'verdadeira' para obter estimativas de probabilidade. Definimos o estado aleatório como '0' para embaralhar os dados e obter probabilidades.
|
||||
|
||||
### Exercício - aplicar um Linear SVC
|
||||
|
||||
Começa por criar um array de classificadores. Vais adicionar progressivamente a este array à medida que testamos.
|
||||
|
||||
1. Começa com um Linear SVC:
|
||||
|
||||
```python
|
||||
C = 10
|
||||
# Create different classifiers.
|
||||
classifiers = {
|
||||
'Linear SVC': SVC(kernel='linear', C=C, probability=True,random_state=0)
|
||||
}
|
||||
```
|
||||
|
||||
2. Treina o teu modelo utilizando o Linear SVC e imprime um relatório:
|
||||
|
||||
```python
|
||||
n_classifiers = len(classifiers)
|
||||
|
||||
for index, (name, classifier) in enumerate(classifiers.items()):
|
||||
classifier.fit(X_train, np.ravel(y_train))
|
||||
|
||||
y_pred = classifier.predict(X_test)
|
||||
accuracy = accuracy_score(y_test, y_pred)
|
||||
print("Accuracy (train) for %s: %0.1f%% " % (name, accuracy * 100))
|
||||
print(classification_report(y_test,y_pred))
|
||||
```
|
||||
|
||||
O resultado é bastante bom:
|
||||
|
||||
```output
|
||||
Accuracy (train) for Linear SVC: 78.6%
|
||||
precision recall f1-score support
|
||||
|
||||
chinese 0.71 0.67 0.69 242
|
||||
indian 0.88 0.86 0.87 234
|
||||
japanese 0.79 0.74 0.76 254
|
||||
korean 0.85 0.81 0.83 242
|
||||
thai 0.71 0.86 0.78 227
|
||||
|
||||
accuracy 0.79 1199
|
||||
macro avg 0.79 0.79 0.79 1199
|
||||
weighted avg 0.79 0.79 0.79 1199
|
||||
```
|
||||
|
||||
## Classificador K-Neighbors
|
||||
|
||||
K-Neighbors faz parte da família de métodos de ML "neighbors", que podem ser usados tanto para aprendizagem supervisionada como não supervisionada. Neste método, é criado um número pré-definido de pontos e os dados são agrupados em torno desses pontos, de forma que rótulos generalizados possam ser previstos para os dados.
|
||||
|
||||
### Exercício - aplicar o classificador K-Neighbors
|
||||
|
||||
O classificador anterior foi bom e funcionou bem com os dados, mas talvez possamos obter uma melhor precisão. Experimenta um classificador K-Neighbors.
|
||||
|
||||
1. Adiciona uma linha ao teu array de classificadores (adiciona uma vírgula após o item Linear SVC):
|
||||
|
||||
```python
|
||||
'KNN classifier': KNeighborsClassifier(C),
|
||||
```
|
||||
|
||||
O resultado é um pouco pior:
|
||||
|
||||
```output
|
||||
Accuracy (train) for KNN classifier: 73.8%
|
||||
precision recall f1-score support
|
||||
|
||||
chinese 0.64 0.67 0.66 242
|
||||
indian 0.86 0.78 0.82 234
|
||||
japanese 0.66 0.83 0.74 254
|
||||
korean 0.94 0.58 0.72 242
|
||||
thai 0.71 0.82 0.76 227
|
||||
|
||||
accuracy 0.74 1199
|
||||
macro avg 0.76 0.74 0.74 1199
|
||||
weighted avg 0.76 0.74 0.74 1199
|
||||
```
|
||||
|
||||
✅ Aprende sobre [K-Neighbors](https://scikit-learn.org/stable/modules/neighbors.html#neighbors)
|
||||
|
||||
## Classificador Support Vector
|
||||
|
||||
Os classificadores Support-Vector fazem parte da família [Support-Vector Machine](https://wikipedia.org/wiki/Support-vector_machine) de métodos de ML que são usados para tarefas de classificação e regressão. Os SVMs "mapeiam exemplos de treino para pontos no espaço" para maximizar a distância entre duas categorias. Dados subsequentes são mapeados neste espaço para que a sua categoria possa ser prevista.
|
||||
|
||||
### Exercício - aplicar um classificador Support Vector
|
||||
|
||||
Vamos tentar obter uma precisão um pouco melhor com um classificador Support Vector.
|
||||
|
||||
1. Adiciona uma vírgula após o item K-Neighbors e, em seguida, adiciona esta linha:
|
||||
|
||||
```python
|
||||
'SVC': SVC(),
|
||||
```
|
||||
|
||||
O resultado é muito bom!
|
||||
|
||||
```output
|
||||
Accuracy (train) for SVC: 83.2%
|
||||
precision recall f1-score support
|
||||
|
||||
chinese 0.79 0.74 0.76 242
|
||||
indian 0.88 0.90 0.89 234
|
||||
japanese 0.87 0.81 0.84 254
|
||||
korean 0.91 0.82 0.86 242
|
||||
thai 0.74 0.90 0.81 227
|
||||
|
||||
accuracy 0.83 1199
|
||||
macro avg 0.84 0.83 0.83 1199
|
||||
weighted avg 0.84 0.83 0.83 1199
|
||||
```
|
||||
|
||||
✅ Aprende sobre [Support-Vectors](https://scikit-learn.org/stable/modules/svm.html#svm)
|
||||
|
||||
## Classificadores Ensemble
|
||||
|
||||
Vamos seguir o caminho até ao fim, mesmo que o teste anterior tenha sido muito bom. Vamos experimentar alguns 'Classificadores Ensemble', especificamente Random Forest e AdaBoost:
|
||||
|
||||
```python
|
||||
'RFST': RandomForestClassifier(n_estimators=100),
|
||||
'ADA': AdaBoostClassifier(n_estimators=100)
|
||||
```
|
||||
|
||||
O resultado é muito bom, especialmente para Random Forest:
|
||||
|
||||
```output
|
||||
Accuracy (train) for RFST: 84.5%
|
||||
precision recall f1-score support
|
||||
|
||||
chinese 0.80 0.77 0.78 242
|
||||
indian 0.89 0.92 0.90 234
|
||||
japanese 0.86 0.84 0.85 254
|
||||
korean 0.88 0.83 0.85 242
|
||||
thai 0.80 0.87 0.83 227
|
||||
|
||||
accuracy 0.84 1199
|
||||
macro avg 0.85 0.85 0.84 1199
|
||||
weighted avg 0.85 0.84 0.84 1199
|
||||
|
||||
Accuracy (train) for ADA: 72.4%
|
||||
precision recall f1-score support
|
||||
|
||||
chinese 0.64 0.49 0.56 242
|
||||
indian 0.91 0.83 0.87 234
|
||||
japanese 0.68 0.69 0.69 254
|
||||
korean 0.73 0.79 0.76 242
|
||||
thai 0.67 0.83 0.74 227
|
||||
|
||||
accuracy 0.72 1199
|
||||
macro avg 0.73 0.73 0.72 1199
|
||||
weighted avg 0.73 0.72 0.72 1199
|
||||
```
|
||||
|
||||
✅ Aprende sobre [Classificadores Ensemble](https://scikit-learn.org/stable/modules/ensemble.html)
|
||||
|
||||
Este método de Machine Learning "combina as previsões de vários estimadores base" para melhorar a qualidade do modelo. No nosso exemplo, utilizámos Random Trees e AdaBoost.
|
||||
|
||||
- [Random Forest](https://scikit-learn.org/stable/modules/ensemble.html#forest), um método de média, constrói uma 'floresta' de 'árvores de decisão' com infusão de aleatoriedade para evitar overfitting. O parâmetro n_estimators é definido como o número de árvores.
|
||||
|
||||
- [AdaBoost](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.AdaBoostClassifier.html) ajusta um classificador a um conjunto de dados e, em seguida, ajusta cópias desse classificador ao mesmo conjunto de dados. Foca-se nos pesos dos itens classificados incorretamente e ajusta o ajuste para o próximo classificador corrigir.
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Cada uma destas técnicas tem um grande número de parâmetros que podes ajustar. Pesquisa os parâmetros padrão de cada uma e pensa no que ajustar esses parâmetros significaria para a qualidade do modelo.
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão e Autoestudo
|
||||
|
||||
Há muito jargão nestas lições, por isso tira um momento para rever [esta lista](https://docs.microsoft.com/dotnet/machine-learning/resources/glossary?WT.mc_id=academic-77952-leestott) de terminologia útil!
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Exploração de parâmetros](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução automática [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Exploração de Parâmetros
|
||||
|
||||
## Instruções
|
||||
|
||||
Existem muitos parâmetros que são definidos por padrão ao trabalhar com estes classificadores. O Intellisense no VS Code pode ajudá-lo a explorá-los. Adote uma das Técnicas de Classificação de ML desta lição e reentreine os modelos ajustando vários valores de parâmetros. Crie um notebook explicando por que algumas alterações melhoram a qualidade do modelo enquanto outras a prejudicam. Seja detalhado na sua resposta.
|
||||
|
||||
## Critérios de Avaliação
|
||||
|
||||
| Critério | Exemplar | Adequado | Necessita Melhorias |
|
||||
| -------- | --------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ----------------------------- |
|
||||
| | Um notebook é apresentado com um classificador completamente desenvolvido e seus parâmetros ajustados, com alterações explicadas em caixas de texto | Um notebook é apresentado parcialmente ou mal explicado | Um notebook contém erros ou falhas |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,650 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0,
|
||||
"metadata": {
|
||||
"colab": {
|
||||
"name": "lesson_12-R.ipynb",
|
||||
"provenance": [],
|
||||
"collapsed_sections": []
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "ir",
|
||||
"display_name": "R"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "R"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "fab50046ca413a38939d579f8432274f",
|
||||
"translation_date": "2025-09-03T20:30:42+00:00",
|
||||
"source_file": "4-Classification/3-Classifiers-2/solution/R/lesson_12-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "jsFutf_ygqSx"
|
||||
},
|
||||
"source": [
|
||||
"# Construir um modelo de classificação: Deliciosas Cozinhas Asiáticas e Indianas\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HD54bEefgtNO"
|
||||
},
|
||||
"source": [
|
||||
"## Classificadores de culinária 2\n",
|
||||
"\n",
|
||||
"Nesta segunda lição sobre classificação, vamos explorar `mais formas` de classificar dados categóricos. Também aprenderemos sobre as implicações de escolher um classificador em vez de outro.\n",
|
||||
"\n",
|
||||
"### [**Questionário pré-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/23/)\n",
|
||||
"\n",
|
||||
"### **Pré-requisitos**\n",
|
||||
"\n",
|
||||
"Assumimos que você completou as lições anteriores, já que vamos utilizar alguns conceitos aprendidos anteriormente.\n",
|
||||
"\n",
|
||||
"Para esta lição, precisaremos dos seguintes pacotes:\n",
|
||||
"\n",
|
||||
"- `tidyverse`: O [tidyverse](https://www.tidyverse.org/) é uma [coleção de pacotes R](https://www.tidyverse.org/packages) projetada para tornar a ciência de dados mais rápida, fácil e divertida!\n",
|
||||
"\n",
|
||||
"- `tidymodels`: O [tidymodels](https://www.tidymodels.org/) é uma [estrutura de pacotes](https://www.tidymodels.org/packages/) para modelagem e aprendizagem de máquina.\n",
|
||||
"\n",
|
||||
"- `themis`: O [pacote themis](https://themis.tidymodels.org/) fornece passos extras de receitas para lidar com dados desbalanceados.\n",
|
||||
"\n",
|
||||
"Você pode instalá-los com o seguinte comando:\n",
|
||||
"\n",
|
||||
"`install.packages(c(\"tidyverse\", \"tidymodels\", \"kernlab\", \"themis\", \"ranger\", \"xgboost\", \"kknn\"))`\n",
|
||||
"\n",
|
||||
"Alternativamente, o script abaixo verifica se você possui os pacotes necessários para completar este módulo e os instala caso estejam ausentes.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "vZ57IuUxgyQt"
|
||||
},
|
||||
"source": [
|
||||
"suppressWarnings(if (!require(\"pacman\"))install.packages(\"pacman\"))\n",
|
||||
"\n",
|
||||
"pacman::p_load(tidyverse, tidymodels, themis, kernlab, ranger, xgboost, kknn)"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "z22M-pj4g07x"
|
||||
},
|
||||
"source": [
|
||||
"## **1. Um mapa de classificação**\n",
|
||||
"\n",
|
||||
"Na nossa [lição anterior](https://github.com/microsoft/ML-For-Beginners/tree/main/4-Classification/2-Classifiers-1), tentámos responder à pergunta: como escolher entre vários modelos? Em grande parte, isso depende das características dos dados e do tipo de problema que queremos resolver (por exemplo, classificação ou regressão?).\n",
|
||||
"\n",
|
||||
"Anteriormente, aprendemos sobre as várias opções disponíveis para classificar dados utilizando o guia da Microsoft. O framework de Machine Learning em Python, Scikit-learn, oferece um guia semelhante, mas mais detalhado, que pode ajudar ainda mais a restringir os seus estimadores (outro termo para classificadores):\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/map.png\"\n",
|
||||
" width=\"700\"/>\n",
|
||||
" <figcaption></figcaption>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "u1i3xRIVg7vG"
|
||||
},
|
||||
"source": [
|
||||
"> Dica: [visite este mapa online](https://scikit-learn.org/stable/tutorial/machine_learning_map/) e clique ao longo do caminho para ler a documentação.\n",
|
||||
">\n",
|
||||
"> O [site de referência do Tidymodels](https://www.tidymodels.org/find/parsnip/#models) também oferece uma excelente documentação sobre diferentes tipos de modelos.\n",
|
||||
"\n",
|
||||
"### **O plano** 🗺️\n",
|
||||
"\n",
|
||||
"Este mapa é muito útil quando se tem uma compreensão clara dos seus dados, pois pode 'percorrer' os seus caminhos até chegar a uma decisão:\n",
|
||||
"\n",
|
||||
"- Temos \\>50 amostras\n",
|
||||
"\n",
|
||||
"- Queremos prever uma categoria\n",
|
||||
"\n",
|
||||
"- Temos dados rotulados\n",
|
||||
"\n",
|
||||
"- Temos menos de 100K amostras\n",
|
||||
"\n",
|
||||
"- ✨ Podemos escolher um Linear SVC\n",
|
||||
"\n",
|
||||
"- Se isso não funcionar, como temos dados numéricos\n",
|
||||
"\n",
|
||||
" - Podemos tentar um ✨ KNeighbors Classifier\n",
|
||||
"\n",
|
||||
" - Se isso não funcionar, tentar ✨ SVC e ✨ Ensemble Classifiers\n",
|
||||
"\n",
|
||||
"Este é um caminho muito útil para seguir. Agora, vamos direto ao assunto utilizando o framework de modelagem [tidymodels](https://www.tidymodels.org/): uma coleção consistente e flexível de pacotes R desenvolvidos para incentivar boas práticas estatísticas 😊.\n",
|
||||
"\n",
|
||||
"## 2. Dividir os dados e lidar com conjuntos de dados desequilibrados.\n",
|
||||
"\n",
|
||||
"Nas nossas lições anteriores, aprendemos que havia um conjunto de ingredientes comuns entre as nossas cozinhas. Além disso, havia uma distribuição bastante desigual no número de cozinhas.\n",
|
||||
"\n",
|
||||
"Vamos lidar com isso da seguinte forma:\n",
|
||||
"\n",
|
||||
"- Eliminando os ingredientes mais comuns que criam confusão entre cozinhas distintas, usando `dplyr::select()`.\n",
|
||||
"\n",
|
||||
"- Utilizando uma `recipe` que pré-processa os dados para prepará-los para a modelagem, aplicando um algoritmo de `over-sampling`.\n",
|
||||
"\n",
|
||||
"Já vimos isso na lição anterior, então deve ser tranquilo 🥳!\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "6tj_rN00hClA"
|
||||
},
|
||||
"source": [
|
||||
"# Load the core Tidyverse and Tidymodels packages\n",
|
||||
"library(tidyverse)\n",
|
||||
"library(tidymodels)\n",
|
||||
"\n",
|
||||
"# Load the original cuisines data\n",
|
||||
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/4-Classification/data/cuisines.csv\")\n",
|
||||
"\n",
|
||||
"# Drop id column, rice, garlic and ginger from our original data set\n",
|
||||
"df_select <- df %>% \n",
|
||||
" select(-c(1, rice, garlic, ginger)) %>%\n",
|
||||
" # Encode cuisine column as categorical\n",
|
||||
" mutate(cuisine = factor(cuisine))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Create data split specification\n",
|
||||
"set.seed(2056)\n",
|
||||
"cuisines_split <- initial_split(data = df_select,\n",
|
||||
" strata = cuisine,\n",
|
||||
" prop = 0.7)\n",
|
||||
"\n",
|
||||
"# Extract the data in each split\n",
|
||||
"cuisines_train <- training(cuisines_split)\n",
|
||||
"cuisines_test <- testing(cuisines_split)\n",
|
||||
"\n",
|
||||
"# Display distribution of cuisines in the training set\n",
|
||||
"cuisines_train %>% \n",
|
||||
" count(cuisine) %>% \n",
|
||||
" arrange(desc(n))"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "zFin5yw3hHb1"
|
||||
},
|
||||
"source": [
|
||||
"### Lidar com dados desequilibrados\n",
|
||||
"\n",
|
||||
"Dados desequilibrados frequentemente têm efeitos negativos no desempenho do modelo. Muitos modelos funcionam melhor quando o número de observações é igual e, por isso, tendem a ter dificuldades com dados desequilibrados.\n",
|
||||
"\n",
|
||||
"Existem principalmente duas formas de lidar com conjuntos de dados desequilibrados:\n",
|
||||
"\n",
|
||||
"- adicionar observações à classe minoritária: `Over-sampling`, por exemplo, utilizando um algoritmo SMOTE que gera novos exemplos sintéticos da classe minoritária com base nos vizinhos mais próximos desses casos.\n",
|
||||
"\n",
|
||||
"- remover observações da classe majoritária: `Under-sampling`\n",
|
||||
"\n",
|
||||
"Na nossa lição anterior, demonstrámos como lidar com conjuntos de dados desequilibrados utilizando uma `recipe`. Uma recipe pode ser vista como um plano que descreve quais passos devem ser aplicados a um conjunto de dados para prepará-lo para análise. No nosso caso, queremos ter uma distribuição igual no número de nossas cozinhas para o nosso `training set`. Vamos começar!\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "cRzTnHolhLWd"
|
||||
},
|
||||
"source": [
|
||||
"# Load themis package for dealing with imbalanced data\n",
|
||||
"library(themis)\n",
|
||||
"\n",
|
||||
"# Create a recipe for preprocessing training data\n",
|
||||
"cuisines_recipe <- recipe(cuisine ~ ., data = cuisines_train) %>%\n",
|
||||
" step_smote(cuisine) \n",
|
||||
"\n",
|
||||
"# Print recipe\n",
|
||||
"cuisines_recipe"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "KxOQ2ORhhO81"
|
||||
},
|
||||
"source": [
|
||||
"Agora estamos prontos para treinar modelos 👩💻👨💻!\n",
|
||||
"\n",
|
||||
"## 3. Para além dos modelos de regressão multinomial\n",
|
||||
"\n",
|
||||
"Na nossa lição anterior, analisámos os modelos de regressão multinomial. Vamos explorar alguns modelos mais flexíveis para classificação.\n",
|
||||
"\n",
|
||||
"### Máquinas de Vetores de Suporte\n",
|
||||
"\n",
|
||||
"No contexto de classificação, `Máquinas de Vetores de Suporte` são uma técnica de aprendizagem automática que tenta encontrar um *hiperplano* que \"melhor\" separa as classes. Vamos observar um exemplo simples:\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/svm.png\"\n",
|
||||
" width=\"300\"/>\n",
|
||||
" <figcaption>https://commons.wikimedia.org/w/index.php?curid=22877598</figcaption>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "C4Wsd0vZhXYu"
|
||||
},
|
||||
"source": [
|
||||
"H1~ não separa as classes. H2~ separa, mas apenas com uma margem pequena. H3~ separa-as com a margem máxima.\n",
|
||||
"\n",
|
||||
"#### Classificador Linear de Vetores de Suporte\n",
|
||||
"\n",
|
||||
"O clustering de Vetores de Suporte (SVC) é uma técnica derivada da família de máquinas de Vetores de Suporte (SVM) em Aprendizagem Automática. No SVC, o hiperplano é escolhido para separar corretamente `a maioria` das observações de treino, mas `pode classificar incorretamente` algumas observações. Ao permitir que alguns pontos fiquem do lado errado, o SVM torna-se mais robusto a outliers, proporcionando assim uma melhor generalização para novos dados. O parâmetro que regula esta violação é chamado de `cost`, que tem um valor padrão de 1 (consulte `help(\"svm_poly\")`).\n",
|
||||
"\n",
|
||||
"Vamos criar um SVC linear definindo `degree = 1` num modelo SVM polinomial.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "vJpp6nuChlBz"
|
||||
},
|
||||
"source": [
|
||||
"# Make a linear SVC specification\n",
|
||||
"svc_linear_spec <- svm_poly(degree = 1) %>% \n",
|
||||
" set_engine(\"kernlab\") %>% \n",
|
||||
" set_mode(\"classification\")\n",
|
||||
"\n",
|
||||
"# Bundle specification and recipe into a worklow\n",
|
||||
"svc_linear_wf <- workflow() %>% \n",
|
||||
" add_recipe(cuisines_recipe) %>% \n",
|
||||
" add_model(svc_linear_spec)\n",
|
||||
"\n",
|
||||
"# Print out workflow\n",
|
||||
"svc_linear_wf"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "rDs8cWNkhoqu"
|
||||
},
|
||||
"source": [
|
||||
"Agora que capturámos os passos de pré-processamento e a especificação do modelo num *workflow*, podemos avançar e treinar o SVC linear, avaliando os resultados ao mesmo tempo. Para métricas de desempenho, vamos criar um conjunto de métricas que avalie: `accuracy`, `sensitivity`, `Positive Predicted Value` e `F Measure`.\n",
|
||||
"\n",
|
||||
"> `augment()` irá adicionar coluna(s) com as previsões aos dados fornecidos.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "81wiqcwuhrnq"
|
||||
},
|
||||
"source": [
|
||||
"# Train a linear SVC model\n",
|
||||
"svc_linear_fit <- svc_linear_wf %>% \n",
|
||||
" fit(data = cuisines_train)\n",
|
||||
"\n",
|
||||
"# Create a metric set\n",
|
||||
"eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Make predictions and Evaluate model performance\n",
|
||||
"svc_linear_fit %>% \n",
|
||||
" augment(new_data = cuisines_test) %>% \n",
|
||||
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "0UFQvHf-huo3"
|
||||
},
|
||||
"source": [
|
||||
"#### Máquina de Vetores de Suporte\n",
|
||||
"\n",
|
||||
"A máquina de vetores de suporte (SVM) é uma extensão do classificador de vetores de suporte para acomodar uma fronteira não linear entre as classes. Essencialmente, as SVMs utilizam o *truque do kernel* para ampliar o espaço de características e assim se adaptar a relações não lineares entre as classes. Uma função kernel popular e extremamente flexível usada pelas SVMs é a *função de base radial.* Vamos ver como ela se comporta com os nossos dados.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "-KX4S8mzhzmp"
|
||||
},
|
||||
"source": [
|
||||
"set.seed(2056)\n",
|
||||
"\n",
|
||||
"# Make an RBF SVM specification\n",
|
||||
"svm_rbf_spec <- svm_rbf() %>% \n",
|
||||
" set_engine(\"kernlab\") %>% \n",
|
||||
" set_mode(\"classification\")\n",
|
||||
"\n",
|
||||
"# Bundle specification and recipe into a worklow\n",
|
||||
"svm_rbf_wf <- workflow() %>% \n",
|
||||
" add_recipe(cuisines_recipe) %>% \n",
|
||||
" add_model(svm_rbf_spec)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Train an RBF model\n",
|
||||
"svm_rbf_fit <- svm_rbf_wf %>% \n",
|
||||
" fit(data = cuisines_train)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Make predictions and Evaluate model performance\n",
|
||||
"svm_rbf_fit %>% \n",
|
||||
" augment(new_data = cuisines_test) %>% \n",
|
||||
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "QBFSa7WSh4HQ"
|
||||
},
|
||||
"source": [
|
||||
"Muito melhor 🤩!\n",
|
||||
"\n",
|
||||
"> ✅ Por favor veja:\n",
|
||||
">\n",
|
||||
"> - [*Support Vector Machines*](https://bradleyboehmke.github.io/HOML/svm.html), Hands-on Machine Learning with R\n",
|
||||
">\n",
|
||||
"> - [*Support Vector Machines*](https://www.statlearning.com/), An Introduction to Statistical Learning with Applications in R\n",
|
||||
">\n",
|
||||
"> para leitura adicional.\n",
|
||||
"\n",
|
||||
"### Classificadores de Vizinhos Mais Próximos\n",
|
||||
"\n",
|
||||
"O algoritmo *K*-nearest neighbor (KNN) prevê cada observação com base na sua *semelhança* com outras observações.\n",
|
||||
"\n",
|
||||
"Vamos ajustar um ao nosso conjunto de dados.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "k4BxxBcdh9Ka"
|
||||
},
|
||||
"source": [
|
||||
"# Make a KNN specification\n",
|
||||
"knn_spec <- nearest_neighbor() %>% \n",
|
||||
" set_engine(\"kknn\") %>% \n",
|
||||
" set_mode(\"classification\")\n",
|
||||
"\n",
|
||||
"# Bundle recipe and model specification into a workflow\n",
|
||||
"knn_wf <- workflow() %>% \n",
|
||||
" add_recipe(cuisines_recipe) %>% \n",
|
||||
" add_model(knn_spec)\n",
|
||||
"\n",
|
||||
"# Train a boosted tree model\n",
|
||||
"knn_wf_fit <- knn_wf %>% \n",
|
||||
" fit(data = cuisines_train)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Make predictions and Evaluate model performance\n",
|
||||
"knn_wf_fit %>% \n",
|
||||
" augment(new_data = cuisines_test) %>% \n",
|
||||
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "HaegQseriAcj"
|
||||
},
|
||||
"source": [
|
||||
"Parece que este modelo não está a ter um desempenho muito bom. Provavelmente, alterar os argumentos do modelo (ver `help(\"nearest_neighbor\")`) irá melhorar o desempenho do modelo. Certifique-se de experimentar.\n",
|
||||
"\n",
|
||||
"> ✅ Por favor veja:\n",
|
||||
">\n",
|
||||
"> - [Hands-on Machine Learning with R](https://bradleyboehmke.github.io/HOML/)\n",
|
||||
">\n",
|
||||
"> - [An Introduction to Statistical Learning with Applications in R](https://www.statlearning.com/)\n",
|
||||
">\n",
|
||||
"> para aprender mais sobre classificadores *K*-Nearest Neighbors.\n",
|
||||
"\n",
|
||||
"### Classificadores em ensemble\n",
|
||||
"\n",
|
||||
"Os algoritmos de ensemble funcionam combinando múltiplos estimadores base para produzir um modelo otimizado, seja através de:\n",
|
||||
"\n",
|
||||
"`bagging`: aplicação de uma *função de média* a uma coleção de modelos base\n",
|
||||
"\n",
|
||||
"`boosting`: construção de uma sequência de modelos que se complementam para melhorar o desempenho preditivo.\n",
|
||||
"\n",
|
||||
"Vamos começar por experimentar um modelo Random Forest, que constrói uma grande coleção de árvores de decisão e depois aplica uma função de média para obter um modelo geral melhor.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "49DPoVs6iK1M"
|
||||
},
|
||||
"source": [
|
||||
"# Make a random forest specification\n",
|
||||
"rf_spec <- rand_forest() %>% \n",
|
||||
" set_engine(\"ranger\") %>% \n",
|
||||
" set_mode(\"classification\")\n",
|
||||
"\n",
|
||||
"# Bundle recipe and model specification into a workflow\n",
|
||||
"rf_wf <- workflow() %>% \n",
|
||||
" add_recipe(cuisines_recipe) %>% \n",
|
||||
" add_model(rf_spec)\n",
|
||||
"\n",
|
||||
"# Train a random forest model\n",
|
||||
"rf_wf_fit <- rf_wf %>% \n",
|
||||
" fit(data = cuisines_train)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Make predictions and Evaluate model performance\n",
|
||||
"rf_wf_fit %>% \n",
|
||||
" augment(new_data = cuisines_test) %>% \n",
|
||||
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "RGVYwC_aiUWc"
|
||||
},
|
||||
"source": [
|
||||
"Bom trabalho 👏!\n",
|
||||
"\n",
|
||||
"Vamos também experimentar com um modelo de Árvore Reforçada.\n",
|
||||
"\n",
|
||||
"Árvore Reforçada define um método de conjunto que cria uma série de árvores de decisão sequenciais, onde cada árvore depende dos resultados das árvores anteriores, numa tentativa de reduzir o erro de forma incremental. Este método foca-se nos pesos dos itens classificados incorretamente e ajusta o modelo do próximo classificador para corrigir.\n",
|
||||
"\n",
|
||||
"Existem diferentes formas de ajustar este modelo (veja `help(\"boost_tree\")`). Neste exemplo, vamos ajustar Árvores Reforçadas através do motor `xgboost`.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "Py1YWo-micWs"
|
||||
},
|
||||
"source": [
|
||||
"# Make a boosted tree specification\n",
|
||||
"boost_spec <- boost_tree(trees = 200) %>% \n",
|
||||
" set_engine(\"xgboost\") %>% \n",
|
||||
" set_mode(\"classification\")\n",
|
||||
"\n",
|
||||
"# Bundle recipe and model specification into a workflow\n",
|
||||
"boost_wf <- workflow() %>% \n",
|
||||
" add_recipe(cuisines_recipe) %>% \n",
|
||||
" add_model(boost_spec)\n",
|
||||
"\n",
|
||||
"# Train a boosted tree model\n",
|
||||
"boost_wf_fit <- boost_wf %>% \n",
|
||||
" fit(data = cuisines_train)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Make predictions and Evaluate model performance\n",
|
||||
"boost_wf_fit %>% \n",
|
||||
" augment(new_data = cuisines_test) %>% \n",
|
||||
" eval_metrics(truth = cuisine, estimate = .pred_class)"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "zNQnbuejigZM"
|
||||
},
|
||||
"source": [
|
||||
"> ✅ Por favor veja:\n",
|
||||
">\n",
|
||||
"> - [Machine Learning for Social Scientists](https://cimentadaj.github.io/ml_socsci/tree-based-methods.html#random-forests)\n",
|
||||
">\n",
|
||||
"> - [Hands-on Machine Learning with R](https://bradleyboehmke.github.io/HOML/)\n",
|
||||
">\n",
|
||||
"> - [An Introduction to Statistical Learning with Applications in R](https://www.statlearning.com/)\n",
|
||||
">\n",
|
||||
"> - <https://algotech.netlify.app/blog/xgboost/> - Explora o modelo AdaBoost, que é uma boa alternativa ao xgboost.\n",
|
||||
">\n",
|
||||
"> para aprender mais sobre classificadores Ensemble.\n",
|
||||
"\n",
|
||||
"## 4. Extra - comparando múltiplos modelos\n",
|
||||
"\n",
|
||||
"Testámos vários modelos neste laboratório 🙌. Pode tornar-se cansativo ou trabalhoso criar muitos fluxos de trabalho a partir de diferentes conjuntos de pré-processadores e/ou especificações de modelos e depois calcular as métricas de desempenho uma a uma.\n",
|
||||
"\n",
|
||||
"Vamos ver se conseguimos resolver isso criando uma função que ajusta uma lista de fluxos de trabalho no conjunto de treino e depois retorna as métricas de desempenho com base no conjunto de teste. Vamos usar `map()` e `map_dfr()` do pacote [purrr](https://purrr.tidyverse.org/) para aplicar funções a cada elemento de uma lista.\n",
|
||||
"\n",
|
||||
"> As funções [`map()`](https://purrr.tidyverse.org/reference/map.html) permitem substituir muitos ciclos \"for\" por código que é mais conciso e mais fácil de ler. O melhor lugar para aprender sobre as funções [`map()`](https://purrr.tidyverse.org/reference/map.html) é o [capítulo de iteração](http://r4ds.had.co.nz/iteration.html) em R for Data Science.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "Qzb7LyZnimd2"
|
||||
},
|
||||
"source": [
|
||||
"set.seed(2056)\n",
|
||||
"\n",
|
||||
"# Create a metric set\n",
|
||||
"eval_metrics <- metric_set(ppv, sens, accuracy, f_meas)\n",
|
||||
"\n",
|
||||
"# Define a function that returns performance metrics\n",
|
||||
"compare_models <- function(workflow_list, train_set, test_set){\n",
|
||||
" \n",
|
||||
" suppressWarnings(\n",
|
||||
" # Fit each model to the train_set\n",
|
||||
" map(workflow_list, fit, data = train_set) %>% \n",
|
||||
" # Make predictions on the test set\n",
|
||||
" map_dfr(augment, new_data = test_set, .id = \"model\") %>%\n",
|
||||
" # Select desired columns\n",
|
||||
" select(model, cuisine, .pred_class) %>% \n",
|
||||
" # Evaluate model performance\n",
|
||||
" group_by(model) %>% \n",
|
||||
" eval_metrics(truth = cuisine, estimate = .pred_class) %>% \n",
|
||||
" ungroup()\n",
|
||||
" )\n",
|
||||
" \n",
|
||||
"} # End of function"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Fwa712sNisDA"
|
||||
},
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "3i4VJOi2iu-a"
|
||||
},
|
||||
"source": [
|
||||
"# Make a list of workflows\n",
|
||||
"workflow_list <- list(\n",
|
||||
" \"svc\" = svc_linear_wf,\n",
|
||||
" \"svm\" = svm_rbf_wf,\n",
|
||||
" \"knn\" = knn_wf,\n",
|
||||
" \"random_forest\" = rf_wf,\n",
|
||||
" \"xgboost\" = boost_wf)\n",
|
||||
"\n",
|
||||
"# Call the function\n",
|
||||
"set.seed(2056)\n",
|
||||
"perf_metrics <- compare_models(workflow_list = workflow_list, train_set = cuisines_train, test_set = cuisines_test)\n",
|
||||
"\n",
|
||||
"# Print out performance metrics\n",
|
||||
"perf_metrics %>% \n",
|
||||
" group_by(.metric) %>% \n",
|
||||
" arrange(desc(.estimate)) %>% \n",
|
||||
" slice_head(n=7)\n",
|
||||
"\n",
|
||||
"# Compare accuracy\n",
|
||||
"perf_metrics %>% \n",
|
||||
" filter(.metric == \"accuracy\") %>% \n",
|
||||
" arrange(desc(.estimate))\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "KuWK_lEli4nW"
|
||||
},
|
||||
"source": [
|
||||
"O pacote [**workflowset**](https://workflowsets.tidymodels.org/) permite aos utilizadores criar e ajustar facilmente um grande número de modelos, mas foi principalmente concebido para funcionar com técnicas de reamostragem, como a `validação cruzada`, uma abordagem que ainda iremos abordar.\n",
|
||||
"\n",
|
||||
"## **🚀Desafio**\n",
|
||||
"\n",
|
||||
"Cada uma destas técnicas tem um grande número de parâmetros que podem ser ajustados, como por exemplo `cost` em SVMs, `neighbors` em KNN, `mtry` (Preditores Selecionados Aleatoriamente) em Random Forest.\n",
|
||||
"\n",
|
||||
"Pesquise os parâmetros padrão de cada técnica e reflita sobre o que ajustar esses parâmetros significaria para a qualidade do modelo.\n",
|
||||
"\n",
|
||||
"Para saber mais sobre um modelo específico e os seus parâmetros, utilize: `help(\"model\")`, por exemplo, `help(\"rand_forest\")`.\n",
|
||||
"\n",
|
||||
"> Na prática, geralmente *estimamos* os *melhores valores* para estes parâmetros treinando vários modelos num `conjunto de dados simulado` e medindo o desempenho de todos esses modelos. Este processo é chamado de **otimização**.\n",
|
||||
"\n",
|
||||
"### [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/24/)\n",
|
||||
"\n",
|
||||
"### **Revisão & Estudo Individual**\n",
|
||||
"\n",
|
||||
"Há muito jargão nestas lições, por isso reserve um momento para rever [esta lista](https://docs.microsoft.com/dotnet/machine-learning/resources/glossary?WT.mc_id=academic-77952-leestott) de terminologia útil!\n",
|
||||
"\n",
|
||||
"#### AGRADECIMENTOS A:\n",
|
||||
"\n",
|
||||
"[`Allison Horst`](https://twitter.com/allison_horst/) por criar as ilustrações incríveis que tornam o R mais acolhedor e envolvente. Encontre mais ilustrações na sua [galeria](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
|
||||
"\n",
|
||||
"[Cassie Breviu](https://www.twitter.com/cassieview) e [Jen Looper](https://www.twitter.com/jenlooper) por criarem a versão original deste módulo em Python ♥️\n",
|
||||
"\n",
|
||||
"Boas aprendizagens,\n",
|
||||
"\n",
|
||||
"[Eric](https://twitter.com/ericntay), Embaixador Estudante Gold da Microsoft Learn.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
||||
" width=\"569\"/>\n",
|
||||
" <figcaption>Arte por @allison_horst</figcaption>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,320 @@
|
||||
# Construir uma Aplicação Web de Recomendação de Culinária
|
||||
|
||||
Nesta lição, vais construir um modelo de classificação utilizando algumas das técnicas que aprendeste em lições anteriores e com o delicioso conjunto de dados de culinária usado ao longo desta série. Além disso, vais criar uma pequena aplicação web para usar um modelo guardado, aproveitando o runtime web do Onnx.
|
||||
|
||||
Uma das utilizações mais práticas da aprendizagem automática é a construção de sistemas de recomendação, e hoje podes dar o primeiro passo nessa direção!
|
||||
|
||||
[](https://youtu.be/17wdM9AHMfg "ML Aplicada")
|
||||
|
||||
> 🎥 Clica na imagem acima para ver um vídeo: Jen Looper constrói uma aplicação web usando dados de culinária classificados
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
Nesta lição vais aprender:
|
||||
|
||||
- Como construir um modelo e guardá-lo como um modelo Onnx
|
||||
- Como usar o Netron para inspecionar o modelo
|
||||
- Como usar o teu modelo numa aplicação web para inferência
|
||||
|
||||
## Construir o teu modelo
|
||||
|
||||
Construir sistemas de ML aplicados é uma parte importante para aproveitar estas tecnologias nos sistemas empresariais. Podes usar modelos dentro das tuas aplicações web (e assim utilizá-los num contexto offline, se necessário) ao usar Onnx.
|
||||
|
||||
Numa [lição anterior](../../3-Web-App/1-Web-App/README.md), construíste um modelo de regressão sobre avistamentos de OVNIs, "pickled" o modelo e usaste-o numa aplicação Flask. Embora esta arquitetura seja muito útil, trata-se de uma aplicação Python full-stack, e os teus requisitos podem incluir o uso de uma aplicação JavaScript.
|
||||
|
||||
Nesta lição, podes construir um sistema básico baseado em JavaScript para inferência. Primeiro, no entanto, precisas de treinar um modelo e convertê-lo para uso com Onnx.
|
||||
|
||||
## Exercício - treinar modelo de classificação
|
||||
|
||||
Primeiro, treina um modelo de classificação usando o conjunto de dados de culinária limpo que utilizámos.
|
||||
|
||||
1. Começa por importar bibliotecas úteis:
|
||||
|
||||
```python
|
||||
!pip install skl2onnx
|
||||
import pandas as pd
|
||||
```
|
||||
|
||||
Vais precisar de '[skl2onnx](https://onnx.ai/sklearn-onnx/)' para ajudar a converter o teu modelo Scikit-learn para o formato Onnx.
|
||||
|
||||
1. Depois, trabalha com os teus dados da mesma forma que fizeste em lições anteriores, lendo um ficheiro CSV usando `read_csv()`:
|
||||
|
||||
```python
|
||||
data = pd.read_csv('../data/cleaned_cuisines.csv')
|
||||
data.head()
|
||||
```
|
||||
|
||||
1. Remove as duas primeiras colunas desnecessárias e guarda os dados restantes como 'X':
|
||||
|
||||
```python
|
||||
X = data.iloc[:,2:]
|
||||
X.head()
|
||||
```
|
||||
|
||||
1. Guarda os rótulos como 'y':
|
||||
|
||||
```python
|
||||
y = data[['cuisine']]
|
||||
y.head()
|
||||
|
||||
```
|
||||
|
||||
### Iniciar a rotina de treino
|
||||
|
||||
Vamos usar a biblioteca 'SVC', que tem boa precisão.
|
||||
|
||||
1. Importa as bibliotecas apropriadas do Scikit-learn:
|
||||
|
||||
```python
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.svm import SVC
|
||||
from sklearn.model_selection import cross_val_score
|
||||
from sklearn.metrics import accuracy_score,precision_score,confusion_matrix,classification_report
|
||||
```
|
||||
|
||||
1. Separa os conjuntos de treino e teste:
|
||||
|
||||
```python
|
||||
X_train, X_test, y_train, y_test = train_test_split(X,y,test_size=0.3)
|
||||
```
|
||||
|
||||
1. Constrói um modelo de classificação SVC como fizeste na lição anterior:
|
||||
|
||||
```python
|
||||
model = SVC(kernel='linear', C=10, probability=True,random_state=0)
|
||||
model.fit(X_train,y_train.values.ravel())
|
||||
```
|
||||
|
||||
1. Agora, testa o teu modelo, chamando `predict()`:
|
||||
|
||||
```python
|
||||
y_pred = model.predict(X_test)
|
||||
```
|
||||
|
||||
1. Imprime um relatório de classificação para verificar a qualidade do modelo:
|
||||
|
||||
```python
|
||||
print(classification_report(y_test,y_pred))
|
||||
```
|
||||
|
||||
Como vimos antes, a precisão é boa:
|
||||
|
||||
```output
|
||||
precision recall f1-score support
|
||||
|
||||
chinese 0.72 0.69 0.70 257
|
||||
indian 0.91 0.87 0.89 243
|
||||
japanese 0.79 0.77 0.78 239
|
||||
korean 0.83 0.79 0.81 236
|
||||
thai 0.72 0.84 0.78 224
|
||||
|
||||
accuracy 0.79 1199
|
||||
macro avg 0.79 0.79 0.79 1199
|
||||
weighted avg 0.79 0.79 0.79 1199
|
||||
```
|
||||
|
||||
### Converter o teu modelo para Onnx
|
||||
|
||||
Certifica-te de fazer a conversão com o número correto de tensores. Este conjunto de dados tem 380 ingredientes listados, por isso precisas de indicar esse número em `FloatTensorType`:
|
||||
|
||||
1. Converte usando um número de tensor de 380.
|
||||
|
||||
```python
|
||||
from skl2onnx import convert_sklearn
|
||||
from skl2onnx.common.data_types import FloatTensorType
|
||||
|
||||
initial_type = [('float_input', FloatTensorType([None, 380]))]
|
||||
options = {id(model): {'nocl': True, 'zipmap': False}}
|
||||
```
|
||||
|
||||
1. Cria o ficheiro onx e guarda-o como **model.onnx**:
|
||||
|
||||
```python
|
||||
onx = convert_sklearn(model, initial_types=initial_type, options=options)
|
||||
with open("./model.onnx", "wb") as f:
|
||||
f.write(onx.SerializeToString())
|
||||
```
|
||||
|
||||
> Nota, podes passar [opções](https://onnx.ai/sklearn-onnx/parameterized.html) no teu script de conversão. Neste caso, passámos 'nocl' como True e 'zipmap' como False. Como este é um modelo de classificação, tens a opção de remover ZipMap, que produz uma lista de dicionários (não necessário). `nocl` refere-se à inclusão de informações de classe no modelo. Reduz o tamanho do teu modelo ao definir `nocl` como 'True'.
|
||||
|
||||
Executar o notebook completo agora irá construir um modelo Onnx e guardá-lo nesta pasta.
|
||||
|
||||
## Visualizar o teu modelo
|
||||
|
||||
Os modelos Onnx não são muito visíveis no Visual Studio Code, mas há um software gratuito muito bom que muitos investigadores utilizam para visualizar o modelo e garantir que foi construído corretamente. Faz o download do [Netron](https://github.com/lutzroeder/Netron) e abre o ficheiro model.onnx. Podes ver o teu modelo simples visualizado, com os seus 380 inputs e o classificador listado:
|
||||
|
||||

|
||||
|
||||
Netron é uma ferramenta útil para visualizar os teus modelos.
|
||||
|
||||
Agora estás pronto para usar este modelo interessante numa aplicação web. Vamos construir uma aplicação que será útil quando olhares para o teu frigorífico e tentares descobrir qual combinação de ingredientes sobrantes podes usar para cozinhar um prato específico, conforme determinado pelo teu modelo.
|
||||
|
||||
## Construir uma aplicação web de recomendação
|
||||
|
||||
Podes usar o teu modelo diretamente numa aplicação web. Esta arquitetura também permite que o modelo seja executado localmente e até offline, se necessário. Começa por criar um ficheiro `index.html` na mesma pasta onde guardaste o teu ficheiro `model.onnx`.
|
||||
|
||||
1. Neste ficheiro _index.html_, adiciona a seguinte marcação:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<header>
|
||||
<title>Cuisine Matcher</title>
|
||||
</header>
|
||||
<body>
|
||||
...
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
1. Agora, dentro das tags `body`, adiciona uma pequena marcação para mostrar uma lista de caixas de seleção que refletem alguns ingredientes:
|
||||
|
||||
```html
|
||||
<h1>Check your refrigerator. What can you create?</h1>
|
||||
<div id="wrapper">
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="4" class="checkbox">
|
||||
<label>apple</label>
|
||||
</div>
|
||||
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="247" class="checkbox">
|
||||
<label>pear</label>
|
||||
</div>
|
||||
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="77" class="checkbox">
|
||||
<label>cherry</label>
|
||||
</div>
|
||||
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="126" class="checkbox">
|
||||
<label>fenugreek</label>
|
||||
</div>
|
||||
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="302" class="checkbox">
|
||||
<label>sake</label>
|
||||
</div>
|
||||
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="327" class="checkbox">
|
||||
<label>soy sauce</label>
|
||||
</div>
|
||||
|
||||
<div class="boxCont">
|
||||
<input type="checkbox" value="112" class="checkbox">
|
||||
<label>cumin</label>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding-top:10px">
|
||||
<button onClick="startInference()">What kind of cuisine can you make?</button>
|
||||
</div>
|
||||
```
|
||||
|
||||
Repara que cada caixa de seleção tem um valor. Este valor reflete o índice onde o ingrediente é encontrado de acordo com o conjunto de dados. A maçã, por exemplo, nesta lista alfabética, ocupa a quinta coluna, por isso o seu valor é '4', já que começamos a contar a partir de 0. Podes consultar a [folha de cálculo de ingredientes](../../../../4-Classification/data/ingredient_indexes.csv) para descobrir o índice de um determinado ingrediente.
|
||||
|
||||
Continuando o teu trabalho no ficheiro index.html, adiciona um bloco de script onde o modelo é chamado após o último `</div>`.
|
||||
|
||||
1. Primeiro, importa o [Onnx Runtime](https://www.onnxruntime.ai/):
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/onnxruntime-web@1.9.0/dist/ort.min.js"></script>
|
||||
```
|
||||
|
||||
> O Onnx Runtime é usado para permitir a execução dos teus modelos Onnx em uma ampla gama de plataformas de hardware, incluindo otimizações e uma API para uso.
|
||||
|
||||
1. Uma vez que o Runtime esteja em funcionamento, podes chamá-lo:
|
||||
|
||||
```html
|
||||
<script>
|
||||
const ingredients = Array(380).fill(0);
|
||||
|
||||
const checks = [...document.querySelectorAll('.checkbox')];
|
||||
|
||||
checks.forEach(check => {
|
||||
check.addEventListener('change', function() {
|
||||
// toggle the state of the ingredient
|
||||
// based on the checkbox's value (1 or 0)
|
||||
ingredients[check.value] = check.checked ? 1 : 0;
|
||||
});
|
||||
});
|
||||
|
||||
function testCheckboxes() {
|
||||
// validate if at least one checkbox is checked
|
||||
return checks.some(check => check.checked);
|
||||
}
|
||||
|
||||
async function startInference() {
|
||||
|
||||
let atLeastOneChecked = testCheckboxes()
|
||||
|
||||
if (!atLeastOneChecked) {
|
||||
alert('Please select at least one ingredient.');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// create a new session and load the model.
|
||||
|
||||
const session = await ort.InferenceSession.create('./model.onnx');
|
||||
|
||||
const input = new ort.Tensor(new Float32Array(ingredients), [1, 380]);
|
||||
const feeds = { float_input: input };
|
||||
|
||||
// feed inputs and run
|
||||
const results = await session.run(feeds);
|
||||
|
||||
// read from results
|
||||
alert('You can enjoy ' + results.label.data[0] + ' cuisine today!')
|
||||
|
||||
} catch (e) {
|
||||
console.log(`failed to inference ONNX model`);
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
Neste código, várias coisas estão a acontecer:
|
||||
|
||||
1. Criaste um array de 380 valores possíveis (1 ou 0) para serem definidos e enviados ao modelo para inferência, dependendo de se uma caixa de seleção de ingrediente está marcada.
|
||||
2. Criaste um array de caixas de seleção e uma forma de determinar se foram marcadas numa função `init` que é chamada quando a aplicação começa. Quando uma caixa de seleção é marcada, o array `ingredients` é alterado para refletir o ingrediente escolhido.
|
||||
3. Criaste uma função `testCheckboxes` que verifica se alguma caixa de seleção foi marcada.
|
||||
4. Usas a função `startInference` quando o botão é pressionado e, se alguma caixa de seleção estiver marcada, inicias a inferência.
|
||||
5. A rotina de inferência inclui:
|
||||
1. Configurar um carregamento assíncrono do modelo
|
||||
2. Criar uma estrutura Tensor para enviar ao modelo
|
||||
3. Criar 'feeds' que refletem o input `float_input` que criaste ao treinar o teu modelo (podes usar o Netron para verificar esse nome)
|
||||
4. Enviar esses 'feeds' ao modelo e aguardar uma resposta
|
||||
|
||||
## Testar a tua aplicação
|
||||
|
||||
Abre uma sessão de terminal no Visual Studio Code na pasta onde o teu ficheiro index.html está localizado. Certifica-te de que tens [http-server](https://www.npmjs.com/package/http-server) instalado globalmente e escreve `http-server` no prompt. Um localhost deve abrir e podes visualizar a tua aplicação web. Verifica qual culinária é recomendada com base em vários ingredientes:
|
||||
|
||||

|
||||
|
||||
Parabéns, criaste uma aplicação web de 'recomendação' com alguns campos. Dedica algum tempo a expandir este sistema!
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
A tua aplicação web é muito minimalista, por isso continua a expandi-la usando ingredientes e os seus índices a partir dos dados [ingredient_indexes](../../../../4-Classification/data/ingredient_indexes.csv). Quais combinações de sabores funcionam para criar um prato nacional específico?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Embora esta lição tenha apenas tocado na utilidade de criar um sistema de recomendação para ingredientes alimentares, esta área de aplicações de ML é muito rica em exemplos. Lê mais sobre como estes sistemas são construídos:
|
||||
|
||||
- https://www.sciencedirect.com/topics/computer-science/recommendation-engine
|
||||
- https://www.technologyreview.com/2014/08/25/171547/the-ultimate-challenge-for-recommendation-engines/
|
||||
- https://www.technologyreview.com/2015/03/23/168831/everything-is-a-recommendation/
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Constrói um novo sistema de recomendação](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Construir um recomendador
|
||||
|
||||
## Instruções
|
||||
|
||||
Com base nos exercícios desta lição, agora sabe como criar uma aplicação web em JavaScript utilizando Onnx Runtime e um modelo Onnx convertido. Experimente criar um novo recomendador usando dados destas lições ou obtidos de outras fontes (dê crédito, por favor). Pode criar, por exemplo, um recomendador de animais de estimação com base em vários atributos de personalidade, ou um recomendador de géneros musicais baseado no estado de espírito de uma pessoa. Seja criativo!
|
||||
|
||||
## Critérios de Avaliação
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| --------- | --------------------------------------------------------------------- | ------------------------------------- | --------------------------------- |
|
||||
| | Uma aplicação web e um notebook são apresentados, ambos bem documentados e funcionais | Um dos dois está em falta ou apresenta falhas | Ambos estão em falta ou apresentam falhas |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,39 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": 3
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"coopTranslator": {
|
||||
"original_hash": "2f3e0d9e9ac5c301558fb8bf733ac0cb",
|
||||
"translation_date": "2025-09-03T20:26:34+00:00",
|
||||
"source_file": "4-Classification/4-Applied/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"source": [],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
# Introdução à classificação
|
||||
|
||||
## Tema regional: Deliciosas culinárias asiáticas e indianas 🍜
|
||||
|
||||
Na Ásia e na Índia, as tradições culinárias são extremamente diversas e muito deliciosas! Vamos analisar dados sobre culinárias regionais para tentar entender os seus ingredientes.
|
||||
|
||||

|
||||
> Foto por <a href="https://unsplash.com/@changlisheng?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Lisheng Chang</a> no <a href="https://unsplash.com/s/photos/asian-food?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||
|
||||
## O que irá aprender
|
||||
|
||||
Nesta seção, irá aprofundar o seu estudo sobre Regressão e aprender sobre outros classificadores que pode usar para compreender melhor os dados.
|
||||
|
||||
> Existem ferramentas úteis de baixo código que podem ajudá-lo a aprender a trabalhar com modelos de classificação. Experimente [Azure ML para esta tarefa](https://docs.microsoft.com/learn/modules/create-classification-model-azure-machine-learning-designer/?WT.mc_id=academic-77952-leestott)
|
||||
|
||||
## Lições
|
||||
|
||||
1. [Introdução à classificação](1-Introduction/README.md)
|
||||
2. [Mais classificadores](2-Classifiers-1/README.md)
|
||||
3. [Outros classificadores](3-Classifiers-2/README.md)
|
||||
4. [ML aplicado: criar uma aplicação web](4-Applied/README.md)
|
||||
|
||||
## Créditos
|
||||
|
||||
"Introdução à classificação" foi escrito com ♥️ por [Cassie Breviu](https://www.twitter.com/cassiebreviu) e [Jen Looper](https://www.twitter.com/jenlooper)
|
||||
|
||||
O conjunto de dados sobre deliciosas culinárias foi obtido de [Kaggle](https://www.kaggle.com/hoandan/asian-and-indian-cuisines).
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,338 @@
|
||||
# Introdução à Clustering
|
||||
|
||||
Clustering é um tipo de [Aprendizagem Não Supervisionada](https://wikipedia.org/wiki/Unsupervised_learning) que parte do pressuposto de que um conjunto de dados não está rotulado ou que suas entradas não estão associadas a saídas predefinidas. Ele utiliza vários algoritmos para organizar dados não rotulados e fornecer agrupamentos com base nos padrões identificados nos dados.
|
||||
|
||||
[](https://youtu.be/ty2advRiWJM "No One Like You by PSquare")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo. Enquanto estuda machine learning com clustering, aproveite algumas faixas de Dance Hall nigeriano - esta é uma música muito bem avaliada de 2014 por PSquare.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
### Introdução
|
||||
|
||||
[Clustering](https://link.springer.com/referenceworkentry/10.1007%2F978-0-387-30164-8_124) é muito útil para exploração de dados. Vamos ver se ele pode ajudar a descobrir tendências e padrões na forma como o público nigeriano consome música.
|
||||
|
||||
✅ Reserve um momento para pensar sobre os usos do clustering. Na vida real, clustering acontece sempre que você tem uma pilha de roupa suja e precisa separar as roupas dos membros da sua família 🧦👕👖🩲. Em ciência de dados, clustering ocorre ao tentar analisar as preferências de um usuário ou determinar as características de qualquer conjunto de dados não rotulado. Clustering, de certa forma, ajuda a dar sentido ao caos, como uma gaveta de meias.
|
||||
|
||||
[](https://youtu.be/esmzYhuFnds "Introdução ao Clustering")
|
||||
|
||||
> 🎥 Clique na imagem acima para assistir a um vídeo: John Guttag do MIT apresenta clustering.
|
||||
|
||||
No ambiente profissional, clustering pode ser usado para determinar coisas como segmentação de mercado, identificando quais faixas etárias compram quais itens, por exemplo. Outro uso seria a detecção de anomalias, talvez para identificar fraudes em um conjunto de dados de transações com cartão de crédito. Ou você pode usar clustering para identificar tumores em um lote de exames médicos.
|
||||
|
||||
✅ Pense por um momento sobre como você pode ter encontrado clustering 'na prática', em um ambiente bancário, de e-commerce ou empresarial.
|
||||
|
||||
> 🎓 Curiosamente, a análise de clusters teve origem nos campos de Antropologia e Psicologia na década de 1930. Consegue imaginar como ela pode ter sido usada?
|
||||
|
||||
Alternativamente, você poderia usá-lo para agrupar resultados de pesquisa - por links de compras, imagens ou avaliações, por exemplo. Clustering é útil quando você tem um grande conjunto de dados que deseja reduzir e sobre o qual deseja realizar uma análise mais detalhada, então a técnica pode ser usada para aprender sobre os dados antes de construir outros modelos.
|
||||
|
||||
✅ Uma vez que seus dados estão organizados em clusters, você atribui a eles um Id de cluster, e essa técnica pode ser útil para preservar a privacidade de um conjunto de dados; você pode, em vez disso, referir-se a um ponto de dados pelo seu Id de cluster, em vez de por dados identificáveis mais reveladores. Consegue pensar em outros motivos pelos quais você preferiria usar um Id de cluster em vez de outros elementos do cluster para identificá-lo?
|
||||
|
||||
Aprofunde seu entendimento sobre técnicas de clustering neste [módulo de aprendizado](https://docs.microsoft.com/learn/modules/train-evaluate-cluster-models?WT.mc_id=academic-77952-leestott).
|
||||
|
||||
## Começando com clustering
|
||||
|
||||
[Scikit-learn oferece uma ampla gama](https://scikit-learn.org/stable/modules/clustering.html) de métodos para realizar clustering. O tipo que você escolhe dependerá do seu caso de uso. De acordo com a documentação, cada método tem vários benefícios. Aqui está uma tabela simplificada dos métodos suportados pelo Scikit-learn e seus casos de uso apropriados:
|
||||
|
||||
| Nome do método | Caso de uso |
|
||||
| :---------------------------- | :-------------------------------------------------------------------- |
|
||||
| K-Means | propósito geral, indutivo |
|
||||
| Propagação de afinidade | muitos clusters desiguais, indutivo |
|
||||
| Mean-shift | muitos clusters desiguais, indutivo |
|
||||
| Clustering espectral | poucos clusters iguais, transdutivo |
|
||||
| Clustering hierárquico Ward | muitos clusters restritos, transdutivo |
|
||||
| Clustering aglomerativo | muitos clusters restritos, distâncias não euclidianas, transdutivo |
|
||||
| DBSCAN | geometria não plana, clusters desiguais, transdutivo |
|
||||
| OPTICS | geometria não plana, clusters desiguais com densidade variável, transdutivo |
|
||||
| Misturas Gaussianas | geometria plana, indutivo |
|
||||
| BIRCH | grande conjunto de dados com outliers, indutivo |
|
||||
|
||||
> 🎓 Como criamos clusters tem muito a ver com como agrupamos os pontos de dados. Vamos explorar alguns vocabulários:
|
||||
>
|
||||
> 🎓 ['Transdutivo' vs. 'indutivo'](https://wikipedia.org/wiki/Transduction_(machine_learning))
|
||||
>
|
||||
> Inferência transdutiva é derivada de casos de treinamento observados que mapeiam para casos de teste específicos. Inferência indutiva é derivada de casos de treinamento que mapeiam para regras gerais que só então são aplicadas aos casos de teste.
|
||||
>
|
||||
> Um exemplo: Imagine que você tem um conjunto de dados parcialmente rotulado. Algumas coisas são 'discos', outras 'CDs', e algumas estão em branco. Sua tarefa é fornecer rótulos para os itens em branco. Se você escolher uma abordagem indutiva, treinaria um modelo procurando por 'discos' e 'CDs', e aplicaria esses rótulos aos dados não rotulados. Essa abordagem terá dificuldade em classificar coisas que são, na verdade, 'cassetes'. Uma abordagem transdutiva, por outro lado, lida com esses dados desconhecidos de forma mais eficaz, agrupando itens semelhantes e aplicando um rótulo ao grupo. Nesse caso, os clusters podem refletir 'coisas musicais redondas' e 'coisas musicais quadradas'.
|
||||
>
|
||||
> 🎓 ['Geometria não plana' vs. 'plana'](https://datascience.stackexchange.com/questions/52260/terminology-flat-geometry-in-the-context-of-clustering)
|
||||
>
|
||||
> Derivado da terminologia matemática, geometria não plana vs. plana refere-se à medida de distâncias entre pontos por métodos geométricos 'planos' ([Euclidianos](https://wikipedia.org/wiki/Euclidean_geometry)) ou 'não planos' (não Euclidianos).
|
||||
>
|
||||
>'Plana' neste contexto refere-se à geometria Euclidiana (partes da qual são ensinadas como 'geometria plana'), e não plana refere-se à geometria não Euclidiana. O que a geometria tem a ver com machine learning? Bem, como dois campos que têm raízes na matemática, deve haver uma maneira comum de medir distâncias entre pontos em clusters, e isso pode ser feito de forma 'plana' ou 'não plana', dependendo da natureza dos dados. [Distâncias Euclidianas](https://wikipedia.org/wiki/Euclidean_distance) são medidas como o comprimento de um segmento de linha entre dois pontos. [Distâncias não Euclidianas](https://wikipedia.org/wiki/Non-Euclidean_geometry) são medidas ao longo de uma curva. Se seus dados, visualizados, parecem não existir em um plano, você pode precisar usar um algoritmo especializado para lidar com isso.
|
||||
>
|
||||

|
||||
> Infográfico por [Dasani Madipalli](https://twitter.com/dasani_decoded)
|
||||
>
|
||||
> 🎓 ['Distâncias'](https://web.stanford.edu/class/cs345a/slides/12-clustering.pdf)
|
||||
>
|
||||
> Clusters são definidos por sua matriz de distâncias, ou seja, as distâncias entre pontos. Essa distância pode ser medida de algumas maneiras. Clusters Euclidianos são definidos pela média dos valores dos pontos e contêm um 'centroide' ou ponto central. As distâncias são, portanto, medidas pela distância até esse centroide. Distâncias não Euclidianas referem-se a 'clustroids', o ponto mais próximo de outros pontos. Clustroids, por sua vez, podem ser definidos de várias maneiras.
|
||||
>
|
||||
> 🎓 ['Restrito'](https://wikipedia.org/wiki/Constrained_clustering)
|
||||
>
|
||||
> [Clustering Restrito](https://web.cs.ucdavis.edu/~davidson/Publications/ICDMTutorial.pdf) introduz aprendizado 'semi-supervisionado' neste método não supervisionado. As relações entre pontos são marcadas como 'não pode vincular' ou 'deve vincular', então algumas regras são impostas ao conjunto de dados.
|
||||
>
|
||||
> Um exemplo: Se um algoritmo é liberado em um lote de dados não rotulados ou semi-rotulados, os clusters que ele produz podem ser de baixa qualidade. No exemplo acima, os clusters podem agrupar 'coisas musicais redondas', 'coisas musicais quadradas', 'coisas triangulares' e 'biscoitos'. Se forem dadas algumas restrições ou regras para seguir ("o item deve ser feito de plástico", "o item precisa ser capaz de produzir música"), isso pode ajudar a 'restringir' o algoritmo para fazer escolhas melhores.
|
||||
>
|
||||
> 🎓 'Densidade'
|
||||
>
|
||||
> Dados que são 'ruidosos' são considerados 'densos'. As distâncias entre pontos em cada um de seus clusters podem, ao serem examinadas, provar ser mais ou menos densas, ou 'aglomeradas', e assim esses dados precisam ser analisados com o método de clustering apropriado. [Este artigo](https://www.kdnuggets.com/2020/02/understanding-density-based-clustering.html) demonstra a diferença entre usar clustering K-Means vs. algoritmos HDBSCAN para explorar um conjunto de dados ruidoso com densidade de cluster desigual.
|
||||
|
||||
## Algoritmos de clustering
|
||||
|
||||
Existem mais de 100 algoritmos de clustering, e seu uso depende da natureza dos dados em questão. Vamos discutir alguns dos principais:
|
||||
|
||||
- **Clustering hierárquico**. Se um objeto é classificado por sua proximidade a um objeto próximo, em vez de a um mais distante, os clusters são formados com base na distância de seus membros para outros objetos. O clustering aglomerativo do Scikit-learn é hierárquico.
|
||||
|
||||

|
||||
> Infográfico por [Dasani Madipalli](https://twitter.com/dasani_decoded)
|
||||
|
||||
- **Clustering por centroide**. Este algoritmo popular exige a escolha de 'k', ou o número de clusters a serem formados, após o qual o algoritmo determina o ponto central de um cluster e reúne dados ao redor desse ponto. [Clustering K-means](https://wikipedia.org/wiki/K-means_clustering) é uma versão popular de clustering por centroide. O centro é determinado pela média mais próxima, daí o nome. A distância quadrada do cluster é minimizada.
|
||||
|
||||

|
||||
> Infográfico por [Dasani Madipalli](https://twitter.com/dasani_decoded)
|
||||
|
||||
- **Clustering baseado em distribuição**. Baseado em modelagem estatística, clustering baseado em distribuição centra-se em determinar a probabilidade de um ponto de dados pertencer a um cluster e atribuí-lo de acordo. Métodos de mistura Gaussianas pertencem a este tipo.
|
||||
|
||||
- **Clustering baseado em densidade**. Pontos de dados são atribuídos a clusters com base em sua densidade, ou seu agrupamento ao redor uns dos outros. Pontos de dados distantes do grupo são considerados outliers ou ruídos. DBSCAN, Mean-shift e OPTICS pertencem a este tipo de clustering.
|
||||
|
||||
- **Clustering baseado em grade**. Para conjuntos de dados multidimensionais, uma grade é criada e os dados são divididos entre as células da grade, criando assim clusters.
|
||||
|
||||
## Exercício - agrupe seus dados
|
||||
|
||||
Clustering como técnica é muito auxiliado por uma boa visualização, então vamos começar visualizando nossos dados musicais. Este exercício nos ajudará a decidir qual dos métodos de clustering devemos usar de forma mais eficaz para a natureza desses dados.
|
||||
|
||||
1. Abra o arquivo [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/notebook.ipynb) nesta pasta.
|
||||
|
||||
1. Importe o pacote `Seaborn` para uma boa visualização de dados.
|
||||
|
||||
```python
|
||||
!pip install seaborn
|
||||
```
|
||||
|
||||
1. Adicione os dados das músicas do arquivo [_nigerian-songs.csv_](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/data/nigerian-songs.csv). Carregue um dataframe com alguns dados sobre as músicas. Prepare-se para explorar esses dados importando as bibliotecas e exibindo os dados:
|
||||
|
||||
```python
|
||||
import matplotlib.pyplot as plt
|
||||
import pandas as pd
|
||||
|
||||
df = pd.read_csv("../data/nigerian-songs.csv")
|
||||
df.head()
|
||||
```
|
||||
|
||||
Verifique as primeiras linhas de dados:
|
||||
|
||||
| | nome | álbum | artista | género_principal_artista | data_lançamento | duração | popularidade | dançabilidade | acústica | energia | instrumentalidade | vivacidade | volume | discurso | tempo | assinatura_tempo |
|
||||
| --- | ------------------------ | ---------------------------- | ------------------- | ------------------------- | ---------------- | ------- | ------------ | ------------- | -------- | ------- | ------------------ | ---------- | -------- | ---------- | ------- | ---------------- |
|
||||
| 0 | Sparky | Mandy & The Jungle | Cruel Santino | r&b alternativo | 2019 | 144000 | 48 | 0.666 | 0.851 | 0.42 | 0.534 | 0.11 | -6.699 | 0.0829 | 133.015 | 5 |
|
||||
| 1 | shuga rush | EVERYTHING YOU HEARD IS TRUE | Odunsi (The Engine) | afropop | 2020 | 89488 | 30 | 0.71 | 0.0822 | 0.683 | 0.000169 | 0.101 | -5.64 | 0.36 | 129.993 | 3 |
|
||||
| 2 | LITT! | LITT! | AYLØ | indie r&b | 2018 | 207758 | 40 | 0.836 | 0.272 | 0.564 | 0.000537 | 0.11 | -7.127 | 0.0424 | 130.005 | 4 |
|
||||
| 3 | Confident / Feeling Cool | Enjoy Your Life | Lady Donli | nigerian pop | 2019 | 175135 | 14 | 0.894 | 0.798 | 0.611 | 0.000187 | 0.0964 | -4.961 | 0.113 | 111.087 | 4 |
|
||||
| 4 | wanted you | rare. | Odunsi (The Engine) | afropop | 2018 | 152049 | 25 | 0.702 | 0.116 | 0.833 | 0.91 | 0.348 | -6.044 | 0.0447 | 105.115 | 4 |
|
||||
|
||||
1. Obtenha algumas informações sobre o dataframe, chamando `info()`:
|
||||
|
||||
```python
|
||||
df.info()
|
||||
```
|
||||
|
||||
O resultado será semelhante a:
|
||||
|
||||
```output
|
||||
<class 'pandas.core.frame.DataFrame'>
|
||||
RangeIndex: 530 entries, 0 to 529
|
||||
Data columns (total 16 columns):
|
||||
# Column Non-Null Count Dtype
|
||||
--- ------ -------------- -----
|
||||
0 name 530 non-null object
|
||||
1 album 530 non-null object
|
||||
2 artist 530 non-null object
|
||||
3 artist_top_genre 530 non-null object
|
||||
4 release_date 530 non-null int64
|
||||
5 length 530 non-null int64
|
||||
6 popularity 530 non-null int64
|
||||
7 danceability 530 non-null float64
|
||||
8 acousticness 530 non-null float64
|
||||
9 energy 530 non-null float64
|
||||
10 instrumentalness 530 non-null float64
|
||||
11 liveness 530 non-null float64
|
||||
12 loudness 530 non-null float64
|
||||
13 speechiness 530 non-null float64
|
||||
14 tempo 530 non-null float64
|
||||
15 time_signature 530 non-null int64
|
||||
dtypes: float64(8), int64(4), object(4)
|
||||
memory usage: 66.4+ KB
|
||||
```
|
||||
|
||||
1. Verifique novamente se há valores nulos, chamando `isnull()` e verificando se a soma é 0:
|
||||
|
||||
```python
|
||||
df.isnull().sum()
|
||||
```
|
||||
|
||||
Tudo certo:
|
||||
|
||||
```output
|
||||
name 0
|
||||
album 0
|
||||
artist 0
|
||||
artist_top_genre 0
|
||||
release_date 0
|
||||
length 0
|
||||
popularity 0
|
||||
danceability 0
|
||||
acousticness 0
|
||||
energy 0
|
||||
instrumentalness 0
|
||||
liveness 0
|
||||
loudness 0
|
||||
speechiness 0
|
||||
tempo 0
|
||||
time_signature 0
|
||||
dtype: int64
|
||||
```
|
||||
|
||||
1. Descreva os dados:
|
||||
|
||||
```python
|
||||
df.describe()
|
||||
```
|
||||
|
||||
| | release_date | length | popularity | danceability | acousticness | energy | instrumentalness | liveness | loudness | speechiness | tempo | time_signature |
|
||||
| ----- | ------------ | ----------- | ---------- | ------------ | ------------ | -------- | ---------------- | -------- | --------- | ----------- | ---------- | -------------- |
|
||||
| count | 530 | 530 | 530 | 530 | 530 | 530 | 530 | 530 | 530 | 530 | 530 | 530 |
|
||||
| mean | 2015.390566 | 222298.1698 | 17.507547 | 0.741619 | 0.265412 | 0.760623 | 0.016305 | 0.147308 | -4.953011 | 0.130748 | 116.487864 | 3.986792 |
|
||||
| std | 3.131688 | 39696.82226 | 18.992212 | 0.117522 | 0.208342 | 0.148533 | 0.090321 | 0.123588 | 2.464186 | 0.092939 | 23.518601 | 0.333701 |
|
||||
| min | 1998 | 89488 | 0 | 0.255 | 0.000665 | 0.111 | 0 | 0.0283 | -19.362 | 0.0278 | 61.695 | 3 |
|
||||
| 25% | 2014 | 199305 | 0 | 0.681 | 0.089525 | 0.669 | 0 | 0.07565 | -6.29875 | 0.0591 | 102.96125 | 4 |
|
||||
| 50% | 2016 | 218509 | 13 | 0.761 | 0.2205 | 0.7845 | 0.000004 | 0.1035 | -4.5585 | 0.09795 | 112.7145 | 4 |
|
||||
| 75% | 2017 | 242098.5 | 31 | 0.8295 | 0.403 | 0.87575 | 0.000234 | 0.164 | -3.331 | 0.177 | 125.03925 | 4 |
|
||||
| max | 2020 | 511738 | 73 | 0.966 | 0.954 | 0.995 | 0.91 | 0.811 | 0.582 | 0.514 | 206.007 | 5 |
|
||||
|
||||
> 🤔 Se estamos a trabalhar com clustering, um método não supervisionado que não requer dados rotulados, por que estamos a mostrar estes dados com rótulos? Na fase de exploração de dados, eles são úteis, mas não são necessários para os algoritmos de clustering funcionarem. Poderíamos simplesmente remover os cabeçalhos das colunas e referir-nos aos dados pelo número da coluna.
|
||||
|
||||
Observe os valores gerais dos dados. Note que a popularidade pode ser '0', o que indica músicas que não têm classificação. Vamos remover esses valores em breve.
|
||||
|
||||
1. Use um gráfico de barras para descobrir os géneros mais populares:
|
||||
|
||||
```python
|
||||
import seaborn as sns
|
||||
|
||||
top = df['artist_top_genre'].value_counts()
|
||||
plt.figure(figsize=(10,7))
|
||||
sns.barplot(x=top[:5].index,y=top[:5].values)
|
||||
plt.xticks(rotation=45)
|
||||
plt.title('Top genres',color = 'blue')
|
||||
```
|
||||
|
||||

|
||||
|
||||
✅ Se quiser ver mais valores principais, altere o top `[:5]` para um valor maior ou remova-o para ver todos.
|
||||
|
||||
Note que, quando o género principal é descrito como 'Missing', isso significa que o Spotify não o classificou, então vamos eliminá-lo.
|
||||
|
||||
1. Elimine os dados ausentes filtrando-os:
|
||||
|
||||
```python
|
||||
df = df[df['artist_top_genre'] != 'Missing']
|
||||
top = df['artist_top_genre'].value_counts()
|
||||
plt.figure(figsize=(10,7))
|
||||
sns.barplot(x=top.index,y=top.values)
|
||||
plt.xticks(rotation=45)
|
||||
plt.title('Top genres',color = 'blue')
|
||||
```
|
||||
|
||||
Agora verifique novamente os géneros:
|
||||
|
||||

|
||||
|
||||
1. De longe, os três géneros principais dominam este conjunto de dados. Vamos concentrar-nos em `afro dancehall`, `afropop` e `nigerian pop`, e adicionalmente filtrar o conjunto de dados para remover qualquer valor de popularidade igual a 0 (o que significa que não foi classificado com uma popularidade no conjunto de dados e pode ser considerado ruído para os nossos propósitos):
|
||||
|
||||
```python
|
||||
df = df[(df['artist_top_genre'] == 'afro dancehall') | (df['artist_top_genre'] == 'afropop') | (df['artist_top_genre'] == 'nigerian pop')]
|
||||
df = df[(df['popularity'] > 0)]
|
||||
top = df['artist_top_genre'].value_counts()
|
||||
plt.figure(figsize=(10,7))
|
||||
sns.barplot(x=top.index,y=top.values)
|
||||
plt.xticks(rotation=45)
|
||||
plt.title('Top genres',color = 'blue')
|
||||
```
|
||||
|
||||
1. Faça um teste rápido para ver se os dados têm alguma correlação particularmente forte:
|
||||
|
||||
```python
|
||||
corrmat = df.corr(numeric_only=True)
|
||||
f, ax = plt.subplots(figsize=(12, 9))
|
||||
sns.heatmap(corrmat, vmax=.8, square=True)
|
||||
```
|
||||
|
||||

|
||||
|
||||
A única correlação forte é entre `energy` e `loudness`, o que não é muito surpreendente, dado que música alta geralmente é bastante energética. Fora isso, as correlações são relativamente fracas. Será interessante ver o que um algoritmo de clustering pode fazer com estes dados.
|
||||
|
||||
> 🎓 Note que correlação não implica causalidade! Temos prova de correlação, mas não prova de causalidade. Um [site divertido](https://tylervigen.com/spurious-correlations) tem alguns visuais que enfatizam este ponto.
|
||||
|
||||
Há alguma convergência neste conjunto de dados em torno da popularidade percebida de uma música e sua capacidade de dança? Um FacetGrid mostra que há círculos concêntricos que se alinham, independentemente do género. Poderia ser que os gostos nigerianos convergem a um certo nível de capacidade de dança para este género?
|
||||
|
||||
✅ Experimente diferentes pontos de dados (energia, loudness, speechiness) e mais ou diferentes géneros musicais. O que consegue descobrir? Veja a tabela `df.describe()` para observar a distribuição geral dos pontos de dados.
|
||||
|
||||
### Exercício - distribuição de dados
|
||||
|
||||
Estes três géneros são significativamente diferentes na perceção da sua capacidade de dança, com base na sua popularidade?
|
||||
|
||||
1. Examine a distribuição de dados dos nossos três géneros principais para popularidade e capacidade de dança ao longo de um eixo x e y dado.
|
||||
|
||||
```python
|
||||
sns.set_theme(style="ticks")
|
||||
|
||||
g = sns.jointplot(
|
||||
data=df,
|
||||
x="popularity", y="danceability", hue="artist_top_genre",
|
||||
kind="kde",
|
||||
)
|
||||
```
|
||||
|
||||
Pode descobrir círculos concêntricos em torno de um ponto geral de convergência, mostrando a distribuição dos pontos.
|
||||
|
||||
> 🎓 Note que este exemplo usa um gráfico KDE (Kernel Density Estimate) que representa os dados usando uma curva de densidade de probabilidade contínua. Isso permite interpretar os dados ao trabalhar com múltiplas distribuições.
|
||||
|
||||
Em geral, os três géneros alinham-se vagamente em termos de sua popularidade e capacidade de dança. Determinar clusters nestes dados vagamente alinhados será um desafio:
|
||||
|
||||

|
||||
|
||||
1. Crie um gráfico de dispersão:
|
||||
|
||||
```python
|
||||
sns.FacetGrid(df, hue="artist_top_genre", height=5) \
|
||||
.map(plt.scatter, "popularity", "danceability") \
|
||||
.add_legend()
|
||||
```
|
||||
|
||||
Um gráfico de dispersão dos mesmos eixos mostra um padrão semelhante de convergência.
|
||||
|
||||

|
||||
|
||||
Em geral, para clustering, pode usar gráficos de dispersão para mostrar clusters de dados, por isso dominar este tipo de visualização é muito útil. Na próxima lição, vamos pegar neste conjunto de dados filtrado e usar clustering k-means para descobrir grupos nestes dados que parecem sobrepor-se de formas interessantes.
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Em preparação para a próxima lição, crie um gráfico sobre os vários algoritmos de clustering que pode descobrir e usar num ambiente de produção. Que tipos de problemas o clustering está a tentar resolver?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão e Autoestudo
|
||||
|
||||
Antes de aplicar algoritmos de clustering, como aprendemos, é uma boa ideia entender a natureza do seu conjunto de dados. Leia mais sobre este tópico [aqui](https://www.kdnuggets.com/2019/10/right-clustering-algorithm.html)
|
||||
|
||||
[Este artigo útil](https://www.freecodecamp.org/news/8-clustering-algorithms-in-machine-learning-that-all-data-scientists-should-know/) explica os diferentes comportamentos de vários algoritmos de clustering, dados diferentes formatos de dados.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Pesquise outras visualizações para clustering](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Pesquisar outras visualizações para clustering
|
||||
|
||||
## Instruções
|
||||
|
||||
Nesta lição, trabalhou com algumas técnicas de visualização para compreender como representar os seus dados em preparação para o clustering. Os gráficos de dispersão, em particular, são úteis para identificar grupos de objetos. Pesquise diferentes formas e diferentes bibliotecas para criar gráficos de dispersão e documente o seu trabalho num notebook. Pode usar os dados desta lição, de outras lições ou dados que obtenha por conta própria (por favor, credite a sua fonte no notebook). Plote alguns dados utilizando gráficos de dispersão e explique o que descobriu.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| --------- | ------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------- |
|
||||
| | Um notebook é apresentado com cinco gráficos de dispersão bem documentados | Um notebook é apresentado com menos de cinco gráficos de dispersão e está menos bem documentado | Um notebook incompleto é apresentado |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,50 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.3"
|
||||
},
|
||||
"orig_nbformat": 2,
|
||||
"kernelspec": {
|
||||
"name": "python383jvsc74a57bd0e134e05457d34029b6460cd73bbf1ed73f339b5b6d98c95be70b69eba114fe95",
|
||||
"display_name": "Python 3.8.3 64-bit (conda)"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "40e0707e96b3e1899a912776006264f9",
|
||||
"translation_date": "2025-09-03T20:01:45+00:00",
|
||||
"source_file": "5-Clustering/1-Visualize/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"source": [],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,500 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## **Música Nigeriana extraída do Spotify - uma análise**\n",
|
||||
"\n",
|
||||
"Clustering é um tipo de [Aprendizagem Não Supervisionada](https://wikipedia.org/wiki/Unsupervised_learning) que parte do pressuposto de que um conjunto de dados não está rotulado ou que suas entradas não estão associadas a saídas predefinidas. Ele utiliza vários algoritmos para analisar dados não rotulados e fornecer agrupamentos com base nos padrões identificados nos dados.\n",
|
||||
"\n",
|
||||
"[**Questionário pré-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/27/)\n",
|
||||
"\n",
|
||||
"### **Introdução**\n",
|
||||
"\n",
|
||||
"[Clustering](https://link.springer.com/referenceworkentry/10.1007%2F978-0-387-30164-8_124) é muito útil para explorar dados. Vamos ver se ele pode ajudar a descobrir tendências e padrões no modo como o público nigeriano consome música.\n",
|
||||
"\n",
|
||||
"> ✅ Reserve um minuto para pensar sobre os usos do clustering. Na vida real, clustering acontece sempre que você tem uma pilha de roupa suja e precisa separar as roupas dos membros da sua família 🧦👕👖🩲. Na ciência de dados, clustering ocorre ao tentar analisar as preferências de um usuário ou determinar as características de qualquer conjunto de dados não rotulado. Clustering, de certa forma, ajuda a dar sentido ao caos, como uma gaveta de meias.\n",
|
||||
"\n",
|
||||
"No ambiente profissional, clustering pode ser usado para determinar coisas como segmentação de mercado, identificando quais faixas etárias compram determinados itens, por exemplo. Outro uso seria a detecção de anomalias, talvez para identificar fraudes em um conjunto de dados de transações com cartão de crédito. Ou você pode usar clustering para identificar tumores em um lote de exames médicos.\n",
|
||||
"\n",
|
||||
"✅ Pense por um momento sobre como você pode ter encontrado clustering 'na prática', em um contexto bancário, de e-commerce ou empresarial.\n",
|
||||
"\n",
|
||||
"> 🎓 Curiosamente, a análise de clusters teve origem nos campos de Antropologia e Psicologia na década de 1930. Consegue imaginar como ela pode ter sido utilizada?\n",
|
||||
"\n",
|
||||
"Alternativamente, você poderia usá-lo para agrupar resultados de pesquisa - por links de compras, imagens ou avaliações, por exemplo. Clustering é útil quando você tem um grande conjunto de dados que deseja reduzir e sobre o qual deseja realizar uma análise mais detalhada, então a técnica pode ser usada para aprender sobre os dados antes de construir outros modelos.\n",
|
||||
"\n",
|
||||
"✅ Uma vez que seus dados estejam organizados em clusters, você atribui a eles um Id de cluster, e essa técnica pode ser útil para preservar a privacidade de um conjunto de dados; você pode, em vez disso, referir-se a um ponto de dados pelo seu Id de cluster, em vez de por dados identificáveis mais reveladores. Consegue pensar em outros motivos pelos quais você preferiria usar um Id de cluster em vez de outros elementos do cluster para identificá-lo?\n",
|
||||
"\n",
|
||||
"### Começando com clustering\n",
|
||||
"\n",
|
||||
"> 🎓 A forma como criamos clusters tem muito a ver com a maneira como agrupamos os pontos de dados. Vamos explorar alguns termos:\n",
|
||||
">\n",
|
||||
"> 🎓 ['Transdutivo' vs. 'indutivo'](https://wikipedia.org/wiki/Transduction_(machine_learning))\n",
|
||||
">\n",
|
||||
"> Inferência transdutiva é derivada de casos de treinamento observados que mapeiam para casos de teste específicos. Inferência indutiva é derivada de casos de treinamento que mapeiam para regras gerais que só então são aplicadas aos casos de teste.\n",
|
||||
">\n",
|
||||
"> Um exemplo: Imagine que você tem um conjunto de dados parcialmente rotulado. Alguns itens são 'discos', outros 'CDs', e alguns estão em branco. Sua tarefa é fornecer rótulos para os itens em branco. Se você escolher uma abordagem indutiva, treinaria um modelo procurando por 'discos' e 'CDs' e aplicaria esses rótulos aos dados não rotulados. Essa abordagem teria dificuldade em classificar itens que na verdade são 'cassetes'. Uma abordagem transdutiva, por outro lado, lida com esses dados desconhecidos de forma mais eficaz, agrupando itens semelhantes e aplicando um rótulo ao grupo. Nesse caso, os clusters poderiam refletir 'coisas musicais redondas' e 'coisas musicais quadradas'.\n",
|
||||
">\n",
|
||||
"> 🎓 ['Geometria plana' vs. 'não plana'](https://datascience.stackexchange.com/questions/52260/terminology-flat-geometry-in-the-context-of-clustering)\n",
|
||||
">\n",
|
||||
"> Derivado da terminologia matemática, geometria plana vs. não plana refere-se à medida de distâncias entre pontos por métodos geométricos 'planos' ([Euclidianos](https://wikipedia.org/wiki/Euclidean_geometry)) ou 'não planos' (não Euclidianos).\n",
|
||||
">\n",
|
||||
"> 'Plano' neste contexto refere-se à geometria Euclidiana (partes da qual são ensinadas como geometria 'plana'), e 'não plano' refere-se à geometria não Euclidiana. O que a geometria tem a ver com aprendizado de máquina? Bem, como dois campos que têm raízes na matemática, deve haver uma maneira comum de medir distâncias entre pontos em clusters, e isso pode ser feito de forma 'plana' ou 'não plana', dependendo da natureza dos dados. [Distâncias Euclidianas](https://wikipedia.org/wiki/Euclidean_distance) são medidas como o comprimento de um segmento de linha entre dois pontos. [Distâncias não Euclidianas](https://wikipedia.org/wiki/Non-Euclidean_geometry) são medidas ao longo de uma curva. Se seus dados, visualizados, parecem não existir em um plano, você pode precisar usar um algoritmo especializado para lidar com eles.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/flat-nonflat.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Infográfico por Dasani Madipalli</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"> 🎓 ['Distâncias'](https://web.stanford.edu/class/cs345a/slides/12-clustering.pdf)\n",
|
||||
">\n",
|
||||
"> Clusters são definidos por sua matriz de distâncias, ou seja, as distâncias entre pontos. Essa distância pode ser medida de algumas maneiras. Clusters Euclidianos são definidos pela média dos valores dos pontos e contêm um 'centroide' ou ponto central. As distâncias são medidas pela distância até esse centroide. Distâncias não Euclidianas referem-se a 'clustroids', o ponto mais próximo de outros pontos. Clustroids, por sua vez, podem ser definidos de várias maneiras.\n",
|
||||
">\n",
|
||||
"> 🎓 ['Com restrições'](https://wikipedia.org/wiki/Constrained_clustering)\n",
|
||||
">\n",
|
||||
"> [Clustering com restrições](https://web.cs.ucdavis.edu/~davidson/Publications/ICDMTutorial.pdf) introduz aprendizado 'semi-supervisionado' neste método não supervisionado. As relações entre pontos são marcadas como 'não pode vincular' ou 'deve vincular', então algumas regras são impostas ao conjunto de dados.\n",
|
||||
">\n",
|
||||
"> Um exemplo: Se um algoritmo é liberado em um lote de dados não rotulados ou semi-rotulados, os clusters que ele produz podem ser de baixa qualidade. No exemplo acima, os clusters podem agrupar 'coisas musicais redondas', 'coisas musicais quadradas', 'coisas triangulares' e 'biscoitos'. Se forem dadas algumas restrições ou regras para seguir (\"o item deve ser feito de plástico\", \"o item precisa ser capaz de produzir música\"), isso pode ajudar a 'restringir' o algoritmo para fazer escolhas melhores.\n",
|
||||
">\n",
|
||||
"> 🎓 'Densidade'\n",
|
||||
">\n",
|
||||
"> Dados que são 'ruidosos' são considerados 'densos'. As distâncias entre pontos em cada um de seus clusters podem, ao serem examinadas, ser mais ou menos densas, ou 'aglomeradas', e assim esses dados precisam ser analisados com o método de clustering apropriado. [Este artigo](https://www.kdnuggets.com/2020/02/understanding-density-based-clustering.html) demonstra a diferença entre usar clustering K-Means e algoritmos HDBSCAN para explorar um conjunto de dados ruidoso com densidade de cluster desigual.\n",
|
||||
"\n",
|
||||
"Aprofunde seu entendimento sobre técnicas de clustering neste [módulo de aprendizado](https://docs.microsoft.com/learn/modules/train-evaluate-cluster-models?WT.mc_id=academic-77952-leestott)\n",
|
||||
"\n",
|
||||
"### **Algoritmos de clustering**\n",
|
||||
"\n",
|
||||
"Existem mais de 100 algoritmos de clustering, e seu uso depende da natureza dos dados em questão. Vamos discutir alguns dos principais:\n",
|
||||
"\n",
|
||||
"- **Clustering hierárquico**. Se um objeto é classificado pela sua proximidade a um objeto próximo, em vez de um mais distante, os clusters são formados com base na distância entre seus membros. O clustering hierárquico é caracterizado pela combinação repetida de dois clusters.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/hierarchical.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Infográfico por Dasani Madipalli</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- **Clustering por centroide**. Este algoritmo popular requer a escolha de 'k', ou o número de clusters a serem formados, após o qual o algoritmo determina o ponto central de um cluster e reúne dados ao redor desse ponto. [Clustering K-means](https://wikipedia.org/wiki/K-means_clustering) é uma versão popular de clustering por centroide que separa um conjunto de dados em K grupos predefinidos. O centro é determinado pela média mais próxima, daí o nome. A distância quadrada do cluster é minimizada.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/centroid.png\"\n",
|
||||
" width=\"600\"/>\n",
|
||||
" <figcaption>Infográfico por Dasani Madipalli</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- **Clustering baseado em distribuição**. Baseado em modelagem estatística, o clustering baseado em distribuição centra-se em determinar a probabilidade de um ponto de dados pertencer a um cluster e atribuí-lo de acordo. Métodos de mistura Gaussiana pertencem a este tipo.\n",
|
||||
"\n",
|
||||
"- **Clustering baseado em densidade**. Pontos de dados são atribuídos a clusters com base na sua densidade, ou no agrupamento ao redor uns dos outros. Pontos de dados distantes do grupo são considerados outliers ou ruído. DBSCAN, Mean-shift e OPTICS pertencem a este tipo de clustering.\n",
|
||||
"\n",
|
||||
"- **Clustering baseado em grade**. Para conjuntos de dados multidimensionais, uma grade é criada e os dados são divididos entre as células da grade, criando assim clusters.\n",
|
||||
"\n",
|
||||
"A melhor maneira de aprender sobre clustering é experimentá-lo você mesmo, e é isso que você fará neste exercício.\n",
|
||||
"\n",
|
||||
"Vamos precisar de alguns pacotes para concluir este módulo. Você pode instalá-los com: `install.packages(c('tidyverse', 'tidymodels', 'DataExplorer', 'summarytools', 'plotly', 'paletteer', 'corrplot', 'patchwork'))`\n",
|
||||
"\n",
|
||||
"Alternativamente, o script abaixo verifica se você tem os pacotes necessários para completar este módulo e os instala para você caso algum esteja faltando.\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\r\n",
|
||||
"\r\n",
|
||||
"pacman::p_load('tidyverse', 'tidymodels', 'DataExplorer', 'summarytools', 'plotly', 'paletteer', 'corrplot', 'patchwork')\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Exercício - agrupe os seus dados\n",
|
||||
"\n",
|
||||
"O clustering como técnica é muito beneficiado por uma boa visualização, por isso vamos começar por visualizar os nossos dados de música. Este exercício vai ajudar-nos a decidir qual dos métodos de clustering devemos usar de forma mais eficaz, tendo em conta a natureza destes dados.\n",
|
||||
"\n",
|
||||
"Vamos começar rapidamente importando os dados.\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Load the core tidyverse and make it available in your current R session\r\n",
|
||||
"library(tidyverse)\r\n",
|
||||
"\r\n",
|
||||
"# Import the data into a tibble\r\n",
|
||||
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv\")\r\n",
|
||||
"\r\n",
|
||||
"# View the first 5 rows of the data set\r\n",
|
||||
"df %>% \r\n",
|
||||
" slice_head(n = 5)\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Às vezes, podemos querer um pouco mais de informação sobre os nossos dados. Podemos observar os `dados` e a `sua estrutura` utilizando a função [*glimpse()*](https://pillar.r-lib.org/reference/glimpse.html):\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Glimpse into the data set\r\n",
|
||||
"df %>% \r\n",
|
||||
" glimpse()\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Bom trabalho!💪\n",
|
||||
"\n",
|
||||
"Podemos observar que `glimpse()` fornece o número total de linhas (observações) e colunas (variáveis), seguido pelas primeiras entradas de cada variável numa linha após o nome da variável. Além disso, o *tipo de dados* da variável é apresentado imediatamente após o nome da variável dentro de `< >`.\n",
|
||||
"\n",
|
||||
"`DataExplorer::introduce()` pode resumir esta informação de forma organizada:\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Describe basic information for our data\r\n",
|
||||
"df %>% \r\n",
|
||||
" introduce()\r\n",
|
||||
"\r\n",
|
||||
"# A visual display of the same\r\n",
|
||||
"df %>% \r\n",
|
||||
" plot_intro()\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Fantástico! Acabámos de descobrir que os nossos dados não têm valores em falta.\n",
|
||||
"\n",
|
||||
"Enquanto estamos nisto, podemos explorar estatísticas comuns de tendência central (por exemplo, [média](https://en.wikipedia.org/wiki/Arithmetic_mean) e [mediana](https://en.wikipedia.org/wiki/Median)) e medidas de dispersão (por exemplo, [desvio padrão](https://en.wikipedia.org/wiki/Standard_deviation)) utilizando `summarytools::descr()`\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Describe common statistics\r\n",
|
||||
"df %>% \r\n",
|
||||
" descr(stats = \"common\")\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Vamos analisar os valores gerais dos dados. Note que a popularidade pode ser `0`, o que indica músicas que não têm classificação. Vamos removê-las em breve.\n",
|
||||
"\n",
|
||||
"> 🤔 Se estamos a trabalhar com clustering, um método não supervisionado que não requer dados rotulados, por que estamos a mostrar estes dados com rótulos? Na fase de exploração de dados, eles são úteis, mas não são necessários para que os algoritmos de clustering funcionem.\n",
|
||||
"\n",
|
||||
"### 1. Explorar géneros populares\n",
|
||||
"\n",
|
||||
"Vamos descobrir os géneros mais populares 🎶 contando o número de vezes que aparecem.\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Popular genres\r\n",
|
||||
"top_genres <- df %>% \r\n",
|
||||
" count(artist_top_genre, sort = TRUE) %>% \r\n",
|
||||
"# Encode to categorical and reorder the according to count\r\n",
|
||||
" mutate(artist_top_genre = factor(artist_top_genre) %>% fct_inorder())\r\n",
|
||||
"\r\n",
|
||||
"# Print the top genres\r\n",
|
||||
"top_genres\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Isso correu bem! Dizem que uma imagem vale mais do que mil linhas de um data frame (na verdade, ninguém diz isso 😅). Mas percebes a ideia, certo?\n",
|
||||
"\n",
|
||||
"Uma forma de visualizar dados categóricos (variáveis de texto ou fatores) é utilizando gráficos de barras. Vamos criar um gráfico de barras com os 10 géneros principais:\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Change the default gray theme\r\n",
|
||||
"theme_set(theme_light())\r\n",
|
||||
"\r\n",
|
||||
"# Visualize popular genres\r\n",
|
||||
"top_genres %>%\r\n",
|
||||
" slice(1:10) %>% \r\n",
|
||||
" ggplot(mapping = aes(x = artist_top_genre, y = n,\r\n",
|
||||
" fill = artist_top_genre)) +\r\n",
|
||||
" geom_col(alpha = 0.8) +\r\n",
|
||||
" paletteer::scale_fill_paletteer_d(\"rcartocolor::Vivid\") +\r\n",
|
||||
" ggtitle(\"Top genres\") +\r\n",
|
||||
" theme(plot.title = element_text(hjust = 0.5),\r\n",
|
||||
" # Rotates the X markers (so we can read them)\r\n",
|
||||
" axis.text.x = element_text(angle = 90))\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Agora é muito mais fácil identificar que temos géneros `missing` 🧐!\n",
|
||||
"\n",
|
||||
"> Uma boa visualização irá mostrar-lhe coisas que não esperava ou levantar novas questões sobre os dados - Hadley Wickham e Garrett Grolemund, [R For Data Science](https://r4ds.had.co.nz/introduction.html)\n",
|
||||
"\n",
|
||||
"Nota: quando o género principal é descrito como `Missing`, isso significa que o Spotify não o classificou, por isso vamos eliminá-lo.\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Visualize popular genres\r\n",
|
||||
"top_genres %>%\r\n",
|
||||
" filter(artist_top_genre != \"Missing\") %>% \r\n",
|
||||
" slice(1:10) %>% \r\n",
|
||||
" ggplot(mapping = aes(x = artist_top_genre, y = n,\r\n",
|
||||
" fill = artist_top_genre)) +\r\n",
|
||||
" geom_col(alpha = 0.8) +\r\n",
|
||||
" paletteer::scale_fill_paletteer_d(\"rcartocolor::Vivid\") +\r\n",
|
||||
" ggtitle(\"Top genres\") +\r\n",
|
||||
" theme(plot.title = element_text(hjust = 0.5),\r\n",
|
||||
" # Rotates the X markers (so we can read them)\r\n",
|
||||
" axis.text.x = element_text(angle = 90))\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"A partir da pequena exploração de dados, aprendemos que os três géneros principais dominam este conjunto de dados. Vamos concentrar-nos em `afro dancehall`, `afropop` e `nigerian pop`, e adicionalmente filtrar o conjunto de dados para remover qualquer entrada com um valor de popularidade igual a 0 (o que significa que não foi classificada com uma popularidade no conjunto de dados e pode ser considerada ruído para os nossos propósitos):\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"nigerian_songs <- df %>% \r\n",
|
||||
" # Concentrate on top 3 genres\r\n",
|
||||
" filter(artist_top_genre %in% c(\"afro dancehall\", \"afropop\",\"nigerian pop\")) %>% \r\n",
|
||||
" # Remove unclassified observations\r\n",
|
||||
" filter(popularity != 0)\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Visualize popular genres\r\n",
|
||||
"nigerian_songs %>%\r\n",
|
||||
" count(artist_top_genre) %>%\r\n",
|
||||
" ggplot(mapping = aes(x = artist_top_genre, y = n,\r\n",
|
||||
" fill = artist_top_genre)) +\r\n",
|
||||
" geom_col(alpha = 0.8) +\r\n",
|
||||
" paletteer::scale_fill_paletteer_d(\"ggsci::category10_d3\") +\r\n",
|
||||
" ggtitle(\"Top genres\") +\r\n",
|
||||
" theme(plot.title = element_text(hjust = 0.5))\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Vamos verificar se existe alguma relação linear aparente entre as variáveis numéricas no nosso conjunto de dados. Esta relação é quantificada matematicamente pelo [estatístico de correlação](https://en.wikipedia.org/wiki/Correlation).\n",
|
||||
"\n",
|
||||
"O estatístico de correlação é um valor entre -1 e 1 que indica a força de uma relação. Valores acima de 0 indicam uma correlação *positiva* (valores altos de uma variável tendem a coincidir com valores altos da outra), enquanto valores abaixo de 0 indicam uma correlação *negativa* (valores altos de uma variável tendem a coincidir com valores baixos da outra).\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Narrow down to numeric variables and fid correlation\r\n",
|
||||
"corr_mat <- nigerian_songs %>% \r\n",
|
||||
" select(where(is.numeric)) %>% \r\n",
|
||||
" cor()\r\n",
|
||||
"\r\n",
|
||||
"# Visualize correlation matrix\r\n",
|
||||
"corrplot(corr_mat, order = 'AOE', col = c('white', 'black'), bg = 'gold2') \r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Os dados não estão fortemente correlacionados, exceto entre `energy` e `loudness`, o que faz sentido, dado que música alta geralmente é bastante energética. `Popularity` tem uma correspondência com `release date`, o que também faz sentido, já que músicas mais recentes provavelmente são mais populares. Comprimento e energia parecem ter uma correlação também.\n",
|
||||
"\n",
|
||||
"Será interessante ver o que um algoritmo de clustering pode fazer com esses dados!\n",
|
||||
"\n",
|
||||
"> 🎓 Note que correlação não implica causalidade! Temos prova de correlação, mas nenhuma prova de causalidade. Um [site divertido](https://tylervigen.com/spurious-correlations) tem alguns visuais que enfatizam este ponto.\n",
|
||||
"\n",
|
||||
"### 2. Explorar a distribuição dos dados\n",
|
||||
"\n",
|
||||
"Vamos fazer perguntas mais subtis. Os géneros são significativamente diferentes na perceção da sua capacidade de dança, com base na sua popularidade? Vamos examinar a distribuição dos dados dos nossos três principais géneros em relação à popularidade e capacidade de dança ao longo de um eixo x e y usando [gráficos de densidade](https://www.khanacademy.org/math/ap-statistics/density-curves-normal-distribution-ap/density-curves/v/density-curves).\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# Perform 2D kernel density estimation\r\n",
|
||||
"density_estimate_2d <- nigerian_songs %>% \r\n",
|
||||
" ggplot(mapping = aes(x = popularity, y = danceability, color = artist_top_genre)) +\r\n",
|
||||
" geom_density_2d(bins = 5, size = 1) +\r\n",
|
||||
" paletteer::scale_color_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
||||
" xlim(-20, 80) +\r\n",
|
||||
" ylim(0, 1.2)\r\n",
|
||||
"\r\n",
|
||||
"# Density plot based on the popularity\r\n",
|
||||
"density_estimate_pop <- nigerian_songs %>% \r\n",
|
||||
" ggplot(mapping = aes(x = popularity, fill = artist_top_genre, color = artist_top_genre)) +\r\n",
|
||||
" geom_density(size = 1, alpha = 0.5) +\r\n",
|
||||
" paletteer::scale_fill_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
||||
" paletteer::scale_color_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
||||
" theme(legend.position = \"none\")\r\n",
|
||||
"\r\n",
|
||||
"# Density plot based on the danceability\r\n",
|
||||
"density_estimate_dance <- nigerian_songs %>% \r\n",
|
||||
" ggplot(mapping = aes(x = danceability, fill = artist_top_genre, color = artist_top_genre)) +\r\n",
|
||||
" geom_density(size = 1, alpha = 0.5) +\r\n",
|
||||
" paletteer::scale_fill_paletteer_d(\"RSkittleBrewer::wildberry\") +\r\n",
|
||||
" paletteer::scale_color_paletteer_d(\"RSkittleBrewer::wildberry\")\r\n",
|
||||
"\r\n",
|
||||
"\r\n",
|
||||
"# Patch everything together\r\n",
|
||||
"library(patchwork)\r\n",
|
||||
"density_estimate_2d / (density_estimate_pop + density_estimate_dance)\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Observamos que há círculos concêntricos que se alinham, independentemente do género. Será que os gostos nigerianos convergem a um certo nível de dançabilidade para este género?\n",
|
||||
"\n",
|
||||
"De forma geral, os três géneros alinham-se em termos de popularidade e dançabilidade. Determinar agrupamentos nestes dados pouco alinhados será um desafio. Vamos ver se um gráfico de dispersão pode ajudar nisso.\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [
|
||||
"# A scatter plot of popularity and danceability\r\n",
|
||||
"scatter_plot <- nigerian_songs %>% \r\n",
|
||||
" ggplot(mapping = aes(x = popularity, y = danceability, color = artist_top_genre, shape = artist_top_genre)) +\r\n",
|
||||
" geom_point(size = 2, alpha = 0.8) +\r\n",
|
||||
" paletteer::scale_color_paletteer_d(\"futurevisions::mars\")\r\n",
|
||||
"\r\n",
|
||||
"# Add a touch of interactivity\r\n",
|
||||
"ggplotly(scatter_plot)\r\n"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"Um gráfico de dispersão dos mesmos eixos mostra um padrão semelhante de convergência.\n",
|
||||
"\n",
|
||||
"De forma geral, para clustering, pode-se usar gráficos de dispersão para mostrar agrupamentos de dados, por isso dominar este tipo de visualização é muito útil. Na próxima lição, vamos pegar estes dados filtrados e usar o clustering k-means para descobrir grupos neste conjunto de dados que parecem se sobrepor de maneiras interessantes.\n",
|
||||
"\n",
|
||||
"## **🚀 Desafio**\n",
|
||||
"\n",
|
||||
"Em preparação para a próxima lição, crie um gráfico sobre os vários algoritmos de clustering que pode descobrir e usar num ambiente de produção. Que tipos de problemas o clustering está tentando resolver?\n",
|
||||
"\n",
|
||||
"## [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/28/)\n",
|
||||
"\n",
|
||||
"## **Revisão e Estudo Individual**\n",
|
||||
"\n",
|
||||
"Antes de aplicar algoritmos de clustering, como aprendemos, é uma boa ideia entender a natureza do seu conjunto de dados. Leia mais sobre este tópico [aqui](https://www.kdnuggets.com/2019/10/right-clustering-algorithm.html).\n",
|
||||
"\n",
|
||||
"Aprofunde o seu entendimento sobre técnicas de clustering:\n",
|
||||
"\n",
|
||||
"- [Treinar e Avaliar Modelos de Clustering usando Tidymodels e amigos](https://rpubs.com/eR_ic/clustering)\n",
|
||||
"\n",
|
||||
"- Bradley Boehmke & Brandon Greenwell, [*Hands-On Machine Learning with R*](https://bradleyboehmke.github.io/HOML/)*.*\n",
|
||||
"\n",
|
||||
"## **Tarefa**\n",
|
||||
"\n",
|
||||
"[Investigue outras visualizações para clustering](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/assignment.md)\n",
|
||||
"\n",
|
||||
"## AGRADECIMENTOS A:\n",
|
||||
"\n",
|
||||
"[Jen Looper](https://www.twitter.com/jenlooper) por criar a versão original em Python deste módulo ♥️\n",
|
||||
"\n",
|
||||
"[`Dasani Madipalli`](https://twitter.com/dasani_decoded) por criar as ilustrações incríveis que tornam os conceitos de machine learning mais interpretáveis e fáceis de entender.\n",
|
||||
"\n",
|
||||
"Boas aprendizagens,\n",
|
||||
"\n",
|
||||
"[Eric](https://twitter.com/ericntay), Gold Microsoft Learn Student Ambassador.\n"
|
||||
],
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos pela precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"anaconda-cloud": "",
|
||||
"kernelspec": {
|
||||
"display_name": "R",
|
||||
"language": "R",
|
||||
"name": "ir"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "r",
|
||||
"file_extension": ".r",
|
||||
"mimetype": "text/x-r-source",
|
||||
"name": "R",
|
||||
"pygments_lexer": "r",
|
||||
"version": "3.4.1"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "99c36449cad3708a435f6798cfa39972",
|
||||
"translation_date": "2025-09-03T20:06:44+00:00",
|
||||
"source_file": "5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 1
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,252 @@
|
||||
# K-Means clustering
|
||||
|
||||
## [Pre-lecture quiz](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
Nesta lição, vais aprender a criar clusters utilizando Scikit-learn e o conjunto de dados de música nigeriana que importaste anteriormente. Vamos abordar os fundamentos do K-Means para Clustering. Lembra-te de que, como aprendeste na lição anterior, existem várias formas de trabalhar com clusters e o método que utilizas depende dos teus dados. Vamos experimentar o K-Means, pois é a técnica de clustering mais comum. Vamos começar!
|
||||
|
||||
Termos que vais aprender:
|
||||
|
||||
- Pontuação de Silhouette
|
||||
- Método do cotovelo
|
||||
- Inércia
|
||||
- Variância
|
||||
|
||||
## Introdução
|
||||
|
||||
[K-Means Clustering](https://wikipedia.org/wiki/K-means_clustering) é um método derivado do domínio do processamento de sinais. É utilizado para dividir e agrupar conjuntos de dados em 'k' clusters utilizando uma série de observações. Cada observação trabalha para agrupar um determinado ponto de dados mais próximo do seu 'média' mais próxima, ou o ponto central de um cluster.
|
||||
|
||||
Os clusters podem ser visualizados como [diagramas de Voronoi](https://wikipedia.org/wiki/Voronoi_diagram), que incluem um ponto (ou 'semente') e a sua região correspondente.
|
||||
|
||||

|
||||
|
||||
> Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
O processo de clustering K-Means [executa-se em três etapas](https://scikit-learn.org/stable/modules/clustering.html#k-means):
|
||||
|
||||
1. O algoritmo seleciona um número k de pontos centrais ao amostrar do conjunto de dados. Depois disso, ele repete:
|
||||
1. Atribui cada amostra ao centróide mais próximo.
|
||||
2. Cria novos centróides ao calcular o valor médio de todas as amostras atribuídas aos centróides anteriores.
|
||||
3. Em seguida, calcula a diferença entre os novos e os antigos centróides e repete até que os centróides se estabilizem.
|
||||
|
||||
Uma desvantagem do uso do K-Means é o facto de que precisas de estabelecer 'k', ou seja, o número de centróides. Felizmente, o 'método do cotovelo' ajuda a estimar um bom valor inicial para 'k'. Vais experimentá-lo em breve.
|
||||
|
||||
## Pré-requisito
|
||||
|
||||
Vais trabalhar no ficheiro [_notebook.ipynb_](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/notebook.ipynb) desta lição, que inclui a importação de dados e a limpeza preliminar que fizeste na última lição.
|
||||
|
||||
## Exercício - preparação
|
||||
|
||||
Começa por dar outra olhada nos dados das músicas.
|
||||
|
||||
1. Cria um boxplot, chamando `boxplot()` para cada coluna:
|
||||
|
||||
```python
|
||||
plt.figure(figsize=(20,20), dpi=200)
|
||||
|
||||
plt.subplot(4,3,1)
|
||||
sns.boxplot(x = 'popularity', data = df)
|
||||
|
||||
plt.subplot(4,3,2)
|
||||
sns.boxplot(x = 'acousticness', data = df)
|
||||
|
||||
plt.subplot(4,3,3)
|
||||
sns.boxplot(x = 'energy', data = df)
|
||||
|
||||
plt.subplot(4,3,4)
|
||||
sns.boxplot(x = 'instrumentalness', data = df)
|
||||
|
||||
plt.subplot(4,3,5)
|
||||
sns.boxplot(x = 'liveness', data = df)
|
||||
|
||||
plt.subplot(4,3,6)
|
||||
sns.boxplot(x = 'loudness', data = df)
|
||||
|
||||
plt.subplot(4,3,7)
|
||||
sns.boxplot(x = 'speechiness', data = df)
|
||||
|
||||
plt.subplot(4,3,8)
|
||||
sns.boxplot(x = 'tempo', data = df)
|
||||
|
||||
plt.subplot(4,3,9)
|
||||
sns.boxplot(x = 'time_signature', data = df)
|
||||
|
||||
plt.subplot(4,3,10)
|
||||
sns.boxplot(x = 'danceability', data = df)
|
||||
|
||||
plt.subplot(4,3,11)
|
||||
sns.boxplot(x = 'length', data = df)
|
||||
|
||||
plt.subplot(4,3,12)
|
||||
sns.boxplot(x = 'release_date', data = df)
|
||||
```
|
||||
|
||||
Estes dados são um pouco ruidosos: ao observar cada coluna como um boxplot, podes ver valores atípicos.
|
||||
|
||||

|
||||
|
||||
Poderias percorrer o conjunto de dados e remover esses valores atípicos, mas isso tornaria os dados bastante reduzidos.
|
||||
|
||||
1. Por agora, escolhe quais colunas vais usar para o teu exercício de clustering. Escolhe aquelas com intervalos semelhantes e codifica a coluna `artist_top_genre` como dados numéricos:
|
||||
|
||||
```python
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
le = LabelEncoder()
|
||||
|
||||
X = df.loc[:, ('artist_top_genre','popularity','danceability','acousticness','loudness','energy')]
|
||||
|
||||
y = df['artist_top_genre']
|
||||
|
||||
X['artist_top_genre'] = le.fit_transform(X['artist_top_genre'])
|
||||
|
||||
y = le.transform(y)
|
||||
```
|
||||
|
||||
1. Agora precisas de escolher quantos clusters vais segmentar. Sabes que existem 3 géneros musicais que extraímos do conjunto de dados, então vamos tentar 3:
|
||||
|
||||
```python
|
||||
from sklearn.cluster import KMeans
|
||||
|
||||
nclusters = 3
|
||||
seed = 0
|
||||
|
||||
km = KMeans(n_clusters=nclusters, random_state=seed)
|
||||
km.fit(X)
|
||||
|
||||
# Predict the cluster for each data point
|
||||
|
||||
y_cluster_kmeans = km.predict(X)
|
||||
y_cluster_kmeans
|
||||
```
|
||||
|
||||
Vês um array impresso com clusters previstos (0, 1 ou 2) para cada linha do dataframe.
|
||||
|
||||
1. Usa este array para calcular uma 'pontuação de silhouette':
|
||||
|
||||
```python
|
||||
from sklearn import metrics
|
||||
score = metrics.silhouette_score(X, y_cluster_kmeans)
|
||||
score
|
||||
```
|
||||
|
||||
## Pontuação de Silhouette
|
||||
|
||||
Procura uma pontuação de silhouette mais próxima de 1. Esta pontuação varia de -1 a 1, e se a pontuação for 1, o cluster é denso e bem separado dos outros clusters. Um valor próximo de 0 representa clusters sobrepostos com amostras muito próximas da fronteira de decisão dos clusters vizinhos. [(Fonte)](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam)
|
||||
|
||||
A nossa pontuação é **0.53**, ou seja, está no meio. Isso indica que os nossos dados não são particularmente adequados para este tipo de clustering, mas vamos continuar.
|
||||
|
||||
### Exercício - construir um modelo
|
||||
|
||||
1. Importa `KMeans` e inicia o processo de clustering.
|
||||
|
||||
```python
|
||||
from sklearn.cluster import KMeans
|
||||
wcss = []
|
||||
|
||||
for i in range(1, 11):
|
||||
kmeans = KMeans(n_clusters = i, init = 'k-means++', random_state = 42)
|
||||
kmeans.fit(X)
|
||||
wcss.append(kmeans.inertia_)
|
||||
|
||||
```
|
||||
|
||||
Existem algumas partes aqui que merecem explicação.
|
||||
|
||||
> 🎓 range: Estas são as iterações do processo de clustering.
|
||||
|
||||
> 🎓 random_state: "Determina a geração de números aleatórios para a inicialização dos centróides." [Fonte](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html#sklearn.cluster.KMeans)
|
||||
|
||||
> 🎓 WCSS: "soma dos quadrados dentro do cluster" mede a distância média quadrada de todos os pontos dentro de um cluster ao centróide do cluster. [Fonte](https://medium.com/@ODSC/unsupervised-learning-evaluating-clusters-bd47eed175ce).
|
||||
|
||||
> 🎓 Inércia: Os algoritmos K-Means tentam escolher centróides para minimizar a 'inércia', "uma medida de quão internamente coerentes são os clusters." [Fonte](https://scikit-learn.org/stable/modules/clustering.html). O valor é adicionado à variável wcss em cada iteração.
|
||||
|
||||
> 🎓 k-means++: Em [Scikit-learn](https://scikit-learn.org/stable/modules/clustering.html#k-means), podes usar a otimização 'k-means++', que "inicializa os centróides para estarem (geralmente) distantes uns dos outros, levando a resultados provavelmente melhores do que a inicialização aleatória."
|
||||
|
||||
### Método do cotovelo
|
||||
|
||||
Anteriormente, deduziste que, como segmentaste 3 géneros musicais, deverias escolher 3 clusters. Mas será que é mesmo o caso?
|
||||
|
||||
1. Usa o 'método do cotovelo' para ter certeza.
|
||||
|
||||
```python
|
||||
plt.figure(figsize=(10,5))
|
||||
sns.lineplot(x=range(1, 11), y=wcss, marker='o', color='red')
|
||||
plt.title('Elbow')
|
||||
plt.xlabel('Number of clusters')
|
||||
plt.ylabel('WCSS')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
Usa a variável `wcss` que construíste no passo anterior para criar um gráfico que mostra onde está a 'curvatura' no cotovelo, indicando o número ótimo de clusters. Talvez seja mesmo **3**!
|
||||
|
||||

|
||||
|
||||
## Exercício - exibir os clusters
|
||||
|
||||
1. Experimenta o processo novamente, desta vez definindo três clusters, e exibe os clusters como um scatterplot:
|
||||
|
||||
```python
|
||||
from sklearn.cluster import KMeans
|
||||
kmeans = KMeans(n_clusters = 3)
|
||||
kmeans.fit(X)
|
||||
labels = kmeans.predict(X)
|
||||
plt.scatter(df['popularity'],df['danceability'],c = labels)
|
||||
plt.xlabel('popularity')
|
||||
plt.ylabel('danceability')
|
||||
plt.show()
|
||||
```
|
||||
|
||||
1. Verifica a precisão do modelo:
|
||||
|
||||
```python
|
||||
labels = kmeans.labels_
|
||||
|
||||
correct_labels = sum(y == labels)
|
||||
|
||||
print("Result: %d out of %d samples were correctly labeled." % (correct_labels, y.size))
|
||||
|
||||
print('Accuracy score: {0:0.2f}'. format(correct_labels/float(y.size)))
|
||||
```
|
||||
|
||||
A precisão deste modelo não é muito boa, e a forma dos clusters dá-te uma pista do porquê.
|
||||
|
||||

|
||||
|
||||
Estes dados são demasiado desequilibrados, pouco correlacionados e há demasiada variância entre os valores das colunas para formar bons clusters. Na verdade, os clusters que se formam provavelmente são fortemente influenciados ou enviesados pelas três categorias de géneros que definimos acima. Foi um processo de aprendizagem!
|
||||
|
||||
Na documentação do Scikit-learn, podes ver que um modelo como este, com clusters não muito bem demarcados, tem um problema de 'variância':
|
||||
|
||||

|
||||
> Infográfico do Scikit-learn
|
||||
|
||||
## Variância
|
||||
|
||||
A variância é definida como "a média das diferenças quadradas em relação à média" [(Fonte)](https://www.mathsisfun.com/data/standard-deviation.html). No contexto deste problema de clustering, refere-se a dados em que os números do nosso conjunto tendem a divergir um pouco demais da média.
|
||||
|
||||
✅ Este é um ótimo momento para pensar em todas as formas de corrigir este problema. Ajustar os dados um pouco mais? Usar colunas diferentes? Utilizar um algoritmo diferente? Dica: Experimenta [escalar os teus dados](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/) para normalizá-los e testar outras colunas.
|
||||
|
||||
> Experimenta este '[calculador de variância](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)' para entender melhor o conceito.
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Passa algum tempo com este notebook, ajustando os parâmetros. Consegues melhorar a precisão do modelo ao limpar mais os dados (removendo valores atípicos, por exemplo)? Podes usar pesos para dar mais importância a determinadas amostras de dados. O que mais podes fazer para criar melhores clusters?
|
||||
|
||||
Dica: Experimenta escalar os teus dados. Há código comentado no notebook que adiciona escalonamento padrão para fazer com que as colunas de dados se assemelhem mais em termos de intervalo. Vais perceber que, embora a pontuação de silhouette diminua, a 'curvatura' no gráfico do cotovelo suaviza-se. Isso acontece porque deixar os dados sem escala permite que dados com menos variância tenham mais peso. Lê mais sobre este problema [aqui](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226).
|
||||
|
||||
## [Post-lecture quiz](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Dá uma olhada num Simulador de K-Means [como este](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/). Podes usar esta ferramenta para visualizar pontos de dados de amostra e determinar os seus centróides. Podes editar a aleatoriedade dos dados, o número de clusters e o número de centróides. Isso ajuda-te a ter uma ideia de como os dados podem ser agrupados?
|
||||
|
||||
Além disso, consulta [este documento sobre K-Means](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) da Stanford.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Experimenta diferentes métodos de clustering](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Experimente diferentes métodos de clustering
|
||||
|
||||
## Instruções
|
||||
|
||||
Nesta lição, aprendeste sobre o clustering K-Means. Por vezes, o K-Means não é adequado para os teus dados. Cria um notebook utilizando dados destas lições ou de outra fonte (dá crédito à fonte) e apresenta um método de clustering diferente que NÃO utilize K-Means. O que aprendeste?
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critério | Exemplar | Adequado | Necessita Melhorias |
|
||||
| --------- | --------------------------------------------------------------- | -------------------------------------------------------------------- | ---------------------------- |
|
||||
| | Um notebook é apresentado com um modelo de clustering bem documentado | Um notebook é apresentado sem boa documentação e/ou incompleto | Trabalho incompleto é submetido |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,640 @@
|
||||
{
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 0,
|
||||
"metadata": {
|
||||
"anaconda-cloud": "",
|
||||
"kernelspec": {
|
||||
"display_name": "R",
|
||||
"language": "R",
|
||||
"name": "ir"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": "r",
|
||||
"file_extension": ".r",
|
||||
"mimetype": "text/x-r-source",
|
||||
"name": "R",
|
||||
"pygments_lexer": "r",
|
||||
"version": "3.4.1"
|
||||
},
|
||||
"colab": {
|
||||
"name": "lesson_14.ipynb",
|
||||
"provenance": [],
|
||||
"collapsed_sections": [],
|
||||
"toc_visible": true
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "ad65fb4aad0a156b42216e4929f490fc",
|
||||
"translation_date": "2025-09-03T20:16:16+00:00",
|
||||
"source_file": "5-Clustering/2-K-Means/solution/R/lesson_15-R.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "GULATlQXLXyR"
|
||||
},
|
||||
"source": [
|
||||
"## Explore K-Means clustering usando R e princípios de dados organizados.\n",
|
||||
"\n",
|
||||
"### [**Questionário pré-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/29/)\n",
|
||||
"\n",
|
||||
"Nesta lição, vais aprender a criar clusters utilizando o pacote Tidymodels e outros pacotes do ecossistema R (vamos chamá-los de amigos 🧑🤝🧑), e o conjunto de dados de música nigeriana que importaste anteriormente. Vamos abordar os fundamentos do K-Means para Clustering. Lembra-te de que, como aprendeste na lição anterior, existem várias formas de trabalhar com clusters e o método que utilizas depende dos teus dados. Vamos experimentar o K-Means, pois é a técnica de clustering mais comum. Vamos começar!\n",
|
||||
"\n",
|
||||
"Termos que vais aprender:\n",
|
||||
"\n",
|
||||
"- Pontuação de Silhueta\n",
|
||||
"\n",
|
||||
"- Método do Cotovelo\n",
|
||||
"\n",
|
||||
"- Inércia\n",
|
||||
"\n",
|
||||
"- Variância\n",
|
||||
"\n",
|
||||
"### **Introdução**\n",
|
||||
"\n",
|
||||
"[K-Means Clustering](https://wikipedia.org/wiki/K-means_clustering) é um método derivado do domínio do processamento de sinais. É utilizado para dividir e agrupar conjuntos de dados em `k clusters` com base em semelhanças nas suas características.\n",
|
||||
"\n",
|
||||
"Os clusters podem ser visualizados como [Diagramas de Voronoi](https://wikipedia.org/wiki/Voronoi_diagram), que incluem um ponto (ou 'semente') e a sua região correspondente.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/voronoi.png\"\n",
|
||||
" width=\"500\"/>\n",
|
||||
" <figcaption>Infográfico por Jen Looper</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"O clustering K-Means segue os seguintes passos:\n",
|
||||
"\n",
|
||||
"1. O cientista de dados começa por especificar o número desejado de clusters a serem criados.\n",
|
||||
"\n",
|
||||
"2. Em seguida, o algoritmo seleciona aleatoriamente K observações do conjunto de dados para servir como os centros iniciais dos clusters (ou seja, os centróides).\n",
|
||||
"\n",
|
||||
"3. Depois, cada uma das observações restantes é atribuída ao centróide mais próximo.\n",
|
||||
"\n",
|
||||
"4. A seguir, a nova média de cada cluster é calculada e o centróide é movido para essa média.\n",
|
||||
"\n",
|
||||
"5. Agora que os centros foram recalculados, cada observação é novamente verificada para ver se pode estar mais próxima de um cluster diferente. Todos os objetos são novamente reatribuídos utilizando as médias atualizadas dos clusters. Os passos de atribuição de clusters e atualização dos centróides são repetidos iterativamente até que as atribuições de clusters deixem de mudar (ou seja, quando se alcança a convergência). Normalmente, o algoritmo termina quando cada nova iteração resulta em um movimento insignificante dos centróides e os clusters tornam-se estáticos.\n",
|
||||
"\n",
|
||||
"<div>\n",
|
||||
"\n",
|
||||
"> Nota que, devido à randomização das observações iniciais k utilizadas como centróides iniciais, podemos obter resultados ligeiramente diferentes cada vez que aplicamos o procedimento. Por esta razão, a maioria dos algoritmos utiliza vários *inícios aleatórios* e escolhe a iteração com o menor WCSS. Assim, é fortemente recomendado executar o K-Means com vários valores de *nstart* para evitar um *ótimo local indesejável.*\n",
|
||||
"\n",
|
||||
"</div>\n",
|
||||
"\n",
|
||||
"Esta curta animação utilizando a [arte](https://github.com/allisonhorst/stats-illustrations) de Allison Horst explica o processo de clustering:\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/kmeans.gif\"\n",
|
||||
" width=\"550\"/>\n",
|
||||
" <figcaption>Arte por @allison_horst</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"Uma questão fundamental que surge no clustering é esta: como sabes quantos clusters deves separar nos teus dados? Uma desvantagem do uso do K-Means é o facto de que precisas de estabelecer `k`, ou seja, o número de `centróides`. Felizmente, o `método do cotovelo` ajuda a estimar um bom valor inicial para `k`. Vais experimentá-lo em breve.\n",
|
||||
"\n",
|
||||
"### \n",
|
||||
"\n",
|
||||
"**Pré-requisito**\n",
|
||||
"\n",
|
||||
"Vamos começar exatamente de onde parámos na [lição anterior](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb), onde analisámos o conjunto de dados, fizemos várias visualizações e filtrámos o conjunto de dados para observações de interesse. Certifica-te de que o revisitas!\n",
|
||||
"\n",
|
||||
"Vamos precisar de alguns pacotes para completar este módulo. Podes instalá-los com: `install.packages(c('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork'))`\n",
|
||||
"\n",
|
||||
"Alternativamente, o script abaixo verifica se tens os pacotes necessários para completar este módulo e instala-os para ti caso alguns estejam em falta.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "ah_tBi58LXyi"
|
||||
},
|
||||
"source": [
|
||||
"suppressWarnings(if(!require(\"pacman\")) install.packages(\"pacman\"))\n",
|
||||
"\n",
|
||||
"pacman::p_load('tidyverse', 'tidymodels', 'cluster', 'summarytools', 'plotly', 'paletteer', 'factoextra', 'patchwork')\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "7e--UCUTLXym"
|
||||
},
|
||||
"source": [
|
||||
"Vamos começar com tudo!\n",
|
||||
"\n",
|
||||
"## 1. Uma dança com dados: Reduzir aos 3 géneros musicais mais populares\n",
|
||||
"\n",
|
||||
"Este é um resumo do que fizemos na lição anterior. Vamos explorar e analisar alguns dados!\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "Ycamx7GGLXyn"
|
||||
},
|
||||
"source": [
|
||||
"# Load the core tidyverse and make it available in your current R session\n",
|
||||
"library(tidyverse)\n",
|
||||
"\n",
|
||||
"# Import the data into a tibble\n",
|
||||
"df <- read_csv(file = \"https://raw.githubusercontent.com/microsoft/ML-For-Beginners/main/5-Clustering/data/nigerian-songs.csv\", show_col_types = FALSE)\n",
|
||||
"\n",
|
||||
"# Narrow down to top 3 popular genres\n",
|
||||
"nigerian_songs <- df %>% \n",
|
||||
" # Concentrate on top 3 genres\n",
|
||||
" filter(artist_top_genre %in% c(\"afro dancehall\", \"afropop\",\"nigerian pop\")) %>% \n",
|
||||
" # Remove unclassified observations\n",
|
||||
" filter(popularity != 0)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Visualize popular genres using bar plots\n",
|
||||
"theme_set(theme_light())\n",
|
||||
"nigerian_songs %>%\n",
|
||||
" count(artist_top_genre) %>%\n",
|
||||
" ggplot(mapping = aes(x = artist_top_genre, y = n,\n",
|
||||
" fill = artist_top_genre)) +\n",
|
||||
" geom_col(alpha = 0.8) +\n",
|
||||
" paletteer::scale_fill_paletteer_d(\"ggsci::category10_d3\") +\n",
|
||||
" ggtitle(\"Top genres\") +\n",
|
||||
" theme(plot.title = element_text(hjust = 0.5))\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "b5h5zmkPLXyp"
|
||||
},
|
||||
"source": [
|
||||
"🤩 Isso correu bem!\n",
|
||||
"\n",
|
||||
"## 2. Mais exploração de dados.\n",
|
||||
"\n",
|
||||
"Quão limpos estão estes dados? Vamos verificar a existência de valores atípicos utilizando boxplots. Vamos concentrar-nos em colunas numéricas com menos valores atípicos (embora seja possível limpar os valores atípicos). Os boxplots podem mostrar o intervalo dos dados e ajudar a escolher quais colunas usar. Note que os boxplots não mostram a variância, um elemento importante para dados bem agrupáveis. Por favor, veja [esta discussão](https://stats.stackexchange.com/questions/91536/deduce-variance-from-boxplot) para leitura adicional.\n",
|
||||
"\n",
|
||||
"[Boxplots](https://en.wikipedia.org/wiki/Box_plot) são usados para representar graficamente a distribuição de dados `numéricos`, então vamos começar por *selecionar* todas as colunas numéricas juntamente com os géneros musicais populares.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "HhNreJKLLXyq"
|
||||
},
|
||||
"source": [
|
||||
"# Select top genre column and all other numeric columns\n",
|
||||
"df_numeric <- nigerian_songs %>% \n",
|
||||
" select(artist_top_genre, where(is.numeric)) \n",
|
||||
"\n",
|
||||
"# Display the data\n",
|
||||
"df_numeric %>% \n",
|
||||
" slice_head(n = 5)\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "uYXrwJRaLXyq"
|
||||
},
|
||||
"source": [
|
||||
"Veja como o auxiliar de seleção `where` torna isso fácil 💁? Explore outras funções semelhantes [aqui](https://tidyselect.r-lib.org/).\n",
|
||||
"\n",
|
||||
"Como vamos criar um boxplot para cada característica numérica e queremos evitar o uso de loops, vamos reformular os nossos dados para um formato *mais longo* que nos permitirá tirar proveito de `facets` - subgráficos que exibem cada subconjunto dos dados.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "gd5bR3f8LXys"
|
||||
},
|
||||
"source": [
|
||||
"# Pivot data from wide to long\n",
|
||||
"df_numeric_long <- df_numeric %>% \n",
|
||||
" pivot_longer(!artist_top_genre, names_to = \"feature_names\", values_to = \"values\") \n",
|
||||
"\n",
|
||||
"# Print out data\n",
|
||||
"df_numeric_long %>% \n",
|
||||
" slice_head(n = 15)\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "-7tE1swnLXyv"
|
||||
},
|
||||
"source": [
|
||||
"Muito mais longo! Agora é hora de alguns `ggplots`! Então, que `geom` vamos usar?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "r88bIsyuLXyy"
|
||||
},
|
||||
"source": [
|
||||
"# Make a box plot\n",
|
||||
"df_numeric_long %>% \n",
|
||||
" ggplot(mapping = aes(x = feature_names, y = values, fill = feature_names)) +\n",
|
||||
" geom_boxplot() +\n",
|
||||
" facet_wrap(~ feature_names, ncol = 4, scales = \"free\") +\n",
|
||||
" theme(legend.position = \"none\")\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "EYVyKIUELXyz"
|
||||
},
|
||||
"source": [
|
||||
"Agora podemos ver que estes dados estão um pouco ruidosos: ao observar cada coluna como um boxplot, é possível identificar valores atípicos. Poderíamos percorrer o conjunto de dados e remover esses valores atípicos, mas isso tornaria os dados bastante reduzidos.\n",
|
||||
"\n",
|
||||
"Por agora, vamos escolher quais colunas utilizaremos para o nosso exercício de clustering. Vamos selecionar as colunas numéricas com intervalos semelhantes. Poderíamos codificar o `artist_top_genre` como numérico, mas vamos descartá-lo por enquanto.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "-wkpINyZLXy0"
|
||||
},
|
||||
"source": [
|
||||
"# Select variables with similar ranges\n",
|
||||
"df_numeric_select <- df_numeric %>% \n",
|
||||
" select(popularity, danceability, acousticness, loudness, energy) \n",
|
||||
"\n",
|
||||
"# Normalize data\n",
|
||||
"# df_numeric_select <- scale(df_numeric_select)\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "D7dLzgpqLXy1"
|
||||
},
|
||||
"source": [
|
||||
"## 3. Computação de clustering k-means em R\n",
|
||||
"\n",
|
||||
"Podemos calcular k-means em R utilizando a função integrada `kmeans`, veja `help(\"kmeans()\")`. A função `kmeans()` aceita um data frame com todas as colunas numéricas como seu argumento principal.\n",
|
||||
"\n",
|
||||
"O primeiro passo ao usar clustering k-means é especificar o número de clusters (k) que serão gerados na solução final. Sabemos que existem 3 géneros musicais que extraímos do conjunto de dados, então vamos tentar com 3:\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "uC4EQ5w7LXy5"
|
||||
},
|
||||
"source": [
|
||||
"set.seed(2056)\n",
|
||||
"# Kmeans clustering for 3 clusters\n",
|
||||
"kclust <- kmeans(\n",
|
||||
" df_numeric_select,\n",
|
||||
" # Specify the number of clusters\n",
|
||||
" centers = 3,\n",
|
||||
" # How many random initial configurations\n",
|
||||
" nstart = 25\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Display clustering object\n",
|
||||
"kclust\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "hzfhscWrLXy-"
|
||||
},
|
||||
"source": [
|
||||
"O objeto kmeans contém várias informações que estão bem explicadas em `help(\"kmeans()\")`. Por agora, vamos concentrar-nos em algumas. Vemos que os dados foram agrupados em 3 clusters com tamanhos de 65, 110, 111. O resultado também contém os centros dos clusters (médias) para os 3 grupos ao longo das 5 variáveis.\n",
|
||||
"\n",
|
||||
"O vetor de clustering é a atribuição de cluster para cada observação. Vamos usar a função `augment` para adicionar a atribuição de cluster ao conjunto de dados original.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "0XwwpFGQLXy_"
|
||||
},
|
||||
"source": [
|
||||
"# Add predicted cluster assignment to data set\n",
|
||||
"augment(kclust, df_numeric_select) %>% \n",
|
||||
" relocate(.cluster) %>% \n",
|
||||
" slice_head(n = 10)\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "NXIVXXACLXzA"
|
||||
},
|
||||
"source": [
|
||||
"Perfeito, acabámos de dividir o nosso conjunto de dados em 3 grupos. Então, quão bom é o nosso agrupamento 🤷? Vamos dar uma olhada no `Silhouette score`.\n",
|
||||
"\n",
|
||||
"### **Silhouette score**\n",
|
||||
"\n",
|
||||
"[A análise de Silhouette](https://en.wikipedia.org/wiki/Silhouette_(clustering)) pode ser usada para estudar a distância de separação entre os clusters resultantes. Este score varia de -1 a 1, e se o score estiver próximo de 1, o cluster é denso e bem separado dos outros clusters. Um valor próximo de 0 representa clusters sobrepostos com amostras muito próximas da fronteira de decisão dos clusters vizinhos. [fonte](https://dzone.com/articles/kmeans-silhouette-score-explained-with-python-exam).\n",
|
||||
"\n",
|
||||
"O método de silhouette médio calcula a média do silhouette das observações para diferentes valores de *k*. Um score médio de silhouette elevado indica um bom agrupamento.\n",
|
||||
"\n",
|
||||
"A função `silhouette` no pacote de cluster é usada para calcular a largura média do silhouette.\n",
|
||||
"\n",
|
||||
"> O silhouette pode ser calculado com qualquer [métrica de distância](https://en.wikipedia.org/wiki/Distance \"Distance\"), como a [distância Euclidiana](https://en.wikipedia.org/wiki/Euclidean_distance \"Euclidean distance\") ou a [distância Manhattan](https://en.wikipedia.org/wiki/Manhattan_distance \"Manhattan distance\"), que discutimos na [lição anterior](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/1-Visualize/solution/R/lesson_14-R.ipynb).\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "Jn0McL28LXzB"
|
||||
},
|
||||
"source": [
|
||||
"# Load cluster package\n",
|
||||
"library(cluster)\n",
|
||||
"\n",
|
||||
"# Compute average silhouette score\n",
|
||||
"ss <- silhouette(kclust$cluster,\n",
|
||||
" # Compute euclidean distance\n",
|
||||
" dist = dist(df_numeric_select))\n",
|
||||
"mean(ss[, 3])\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "QyQRn97nLXzC"
|
||||
},
|
||||
"source": [
|
||||
"A nossa pontuação é **0,549**, ou seja, bem no meio. Isto indica que os nossos dados não são particularmente adequados para este tipo de agrupamento. Vamos ver se conseguimos confirmar esta suspeita visualmente. O [pacote factoextra](https://rpkgs.datanovia.com/factoextra/index.html) fornece funções (`fviz_cluster()`) para visualizar agrupamentos.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "7a6Km1_FLXzD"
|
||||
},
|
||||
"source": [
|
||||
"library(factoextra)\n",
|
||||
"\n",
|
||||
"# Visualize clustering results\n",
|
||||
"fviz_cluster(kclust, df_numeric_select)\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "IBwCWt-0LXzD"
|
||||
},
|
||||
"source": [
|
||||
"A sobreposição nos clusters indica que os nossos dados não são particularmente adequados para este tipo de clustering, mas vamos continuar.\n",
|
||||
"\n",
|
||||
"## 4. Determinar o número ideal de clusters\n",
|
||||
"\n",
|
||||
"Uma questão fundamental que frequentemente surge no clustering K-Means é esta: sem etiquetas de classe conhecidas, como saber quantos clusters usar para separar os seus dados?\n",
|
||||
"\n",
|
||||
"Uma forma de tentar descobrir é usar uma amostra de dados para `criar uma série de modelos de clustering` com um número crescente de clusters (por exemplo, de 1 a 10) e avaliar métricas de clustering como o **Silhouette score.**\n",
|
||||
"\n",
|
||||
"Vamos determinar o número ideal de clusters calculando o algoritmo de clustering para diferentes valores de *k* e avaliando o **Within Cluster Sum of Squares** (WCSS). O total de soma de quadrados dentro do cluster (WCSS) mede a compacidade do clustering, e queremos que seja o menor possível, com valores mais baixos significando que os pontos de dados estão mais próximos.\n",
|
||||
"\n",
|
||||
"Vamos explorar o efeito de diferentes escolhas de `k`, de 1 a 10, neste clustering.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "hSeIiylDLXzE"
|
||||
},
|
||||
"source": [
|
||||
"# Create a series of clustering models\n",
|
||||
"kclusts <- tibble(k = 1:10) %>% \n",
|
||||
" # Perform kmeans clustering for 1,2,3 ... ,10 clusters\n",
|
||||
" mutate(model = map(k, ~ kmeans(df_numeric_select, centers = .x, nstart = 25)),\n",
|
||||
" # Farm out clustering metrics eg WCSS\n",
|
||||
" glanced = map(model, ~ glance(.x))) %>% \n",
|
||||
" unnest(cols = glanced)\n",
|
||||
" \n",
|
||||
"\n",
|
||||
"# View clustering rsulsts\n",
|
||||
"kclusts\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "m7rS2U1eLXzE"
|
||||
},
|
||||
"source": [
|
||||
"Agora que temos o total da soma dos quadrados dentro dos clusters (tot.withinss) para cada algoritmo de clustering com centro *k*, utilizamos o [método do cotovelo](https://en.wikipedia.org/wiki/Elbow_method_(clustering)) para encontrar o número ideal de clusters. O método consiste em traçar o WCSS como uma função do número de clusters e escolher o [cotovelo da curva](https://en.wikipedia.org/wiki/Elbow_of_the_curve \"Cotovelo da curva\") como o número de clusters a ser utilizado.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "o_DjHGItLXzF"
|
||||
},
|
||||
"source": [
|
||||
"set.seed(2056)\n",
|
||||
"# Use elbow method to determine optimum number of clusters\n",
|
||||
"kclusts %>% \n",
|
||||
" ggplot(mapping = aes(x = k, y = tot.withinss)) +\n",
|
||||
" geom_line(size = 1.2, alpha = 0.8, color = \"#FF7F0EFF\") +\n",
|
||||
" geom_point(size = 2, color = \"#FF7F0EFF\")\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "pLYyt5XSLXzG"
|
||||
},
|
||||
"source": [
|
||||
"O gráfico mostra uma grande redução no WCSS (ou seja, maior *coerência*) à medida que o número de clusters aumenta de um para dois, e uma redução adicional notável de dois para três clusters. Depois disso, a redução torna-se menos acentuada, resultando num `cotovelo` 💪 no gráfico por volta de três clusters. Isto é uma boa indicação de que existem dois a três clusters de pontos de dados razoavelmente bem separados.\n",
|
||||
"\n",
|
||||
"Podemos agora avançar e extrair o modelo de clustering onde `k = 3`:\n",
|
||||
"\n",
|
||||
"> `pull()`: usado para extrair uma única coluna\n",
|
||||
">\n",
|
||||
"> `pluck()`: usado para indexar estruturas de dados como listas\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "JP_JPKBILXzG"
|
||||
},
|
||||
"source": [
|
||||
"# Extract k = 3 clustering\n",
|
||||
"final_kmeans <- kclusts %>% \n",
|
||||
" filter(k == 3) %>% \n",
|
||||
" pull(model) %>% \n",
|
||||
" pluck(1)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"final_kmeans\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "l_PDTu8tLXzI"
|
||||
},
|
||||
"source": [
|
||||
"Ótimo! Vamos visualizar os clusters obtidos. Que tal adicionar um pouco de interatividade usando `plotly`?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "dNcleFe-LXzJ"
|
||||
},
|
||||
"source": [
|
||||
"# Add predicted cluster assignment to data set\n",
|
||||
"results <- augment(final_kmeans, df_numeric_select) %>% \n",
|
||||
" bind_cols(df_numeric %>% select(artist_top_genre)) \n",
|
||||
"\n",
|
||||
"# Plot cluster assignments\n",
|
||||
"clust_plt <- results %>% \n",
|
||||
" ggplot(mapping = aes(x = popularity, y = danceability, color = .cluster, shape = artist_top_genre)) +\n",
|
||||
" geom_point(size = 2, alpha = 0.8) +\n",
|
||||
" paletteer::scale_color_paletteer_d(\"ggthemes::Tableau_10\")\n",
|
||||
"\n",
|
||||
"ggplotly(clust_plt)\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "6JUM_51VLXzK"
|
||||
},
|
||||
"source": [
|
||||
"Talvez esperássemos que cada grupo (representado por cores diferentes) tivesse géneros distintos (representados por formas diferentes).\n",
|
||||
"\n",
|
||||
"Vamos analisar a precisão do modelo.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"metadata": {
|
||||
"id": "HdIMUGq7LXzL"
|
||||
},
|
||||
"source": [
|
||||
"# Assign genres to predefined integers\n",
|
||||
"label_count <- results %>% \n",
|
||||
" group_by(artist_top_genre) %>% \n",
|
||||
" mutate(id = cur_group_id()) %>% \n",
|
||||
" ungroup() %>% \n",
|
||||
" summarise(correct_labels = sum(.cluster == id))\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# Print results \n",
|
||||
"cat(\"Result:\", label_count$correct_labels, \"out of\", nrow(results), \"samples were correctly labeled.\")\n",
|
||||
"\n",
|
||||
"cat(\"\\nAccuracy score:\", label_count$correct_labels/nrow(results))\n"
|
||||
],
|
||||
"execution_count": null,
|
||||
"outputs": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "C50wvaAOLXzM"
|
||||
},
|
||||
"source": [
|
||||
"A precisão deste modelo não é má, mas também não é excelente. Pode ser que os dados não sejam adequados para o K-Means Clustering. Estes dados são demasiado desequilibrados, pouco correlacionados e há muita variância entre os valores das colunas para formar clusters eficazes. Na verdade, os clusters que se formam provavelmente são fortemente influenciados ou enviesados pelas três categorias de género que definimos acima.\n",
|
||||
"\n",
|
||||
"Ainda assim, foi um processo de aprendizagem interessante!\n",
|
||||
"\n",
|
||||
"Na documentação do Scikit-learn, pode-se ver que um modelo como este, com clusters pouco bem definidos, tem um problema de 'variância':\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/problems.png\"\n",
|
||||
" width=\"500\"/>\n",
|
||||
" <figcaption>Infográfico do Scikit-learn</figcaption>\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"## **Variância**\n",
|
||||
"\n",
|
||||
"A variância é definida como \"a média das diferenças quadradas em relação à média\" [fonte](https://www.mathsisfun.com/data/standard-deviation.html). No contexto deste problema de clustering, refere-se aos dados em que os números do nosso conjunto tendem a divergir um pouco demais da média.\n",
|
||||
"\n",
|
||||
"✅ Este é um ótimo momento para pensar em todas as formas de corrigir este problema. Ajustar os dados um pouco mais? Usar colunas diferentes? Utilizar um algoritmo diferente? Dica: Experimente [escalar os seus dados](https://www.mygreatlearning.com/blog/learning-data-science-with-k-means-clustering/) para normalizá-los e testar outras colunas.\n",
|
||||
"\n",
|
||||
"> Experimente este '[calculador de variância](https://www.calculatorsoup.com/calculators/statistics/variance-calculator.php)' para compreender melhor o conceito.\n",
|
||||
"\n",
|
||||
"------------------------------------------------------------------------\n",
|
||||
"\n",
|
||||
"## **🚀Desafio**\n",
|
||||
"\n",
|
||||
"Dedique algum tempo a este notebook, ajustando os parâmetros. Consegue melhorar a precisão do modelo ao limpar mais os dados (removendo outliers, por exemplo)? Pode usar pesos para dar mais importância a determinadas amostras de dados. O que mais pode fazer para criar clusters melhores?\n",
|
||||
"\n",
|
||||
"Dica: Experimente escalar os seus dados. Há código comentado no notebook que adiciona escalonamento padrão para fazer com que as colunas de dados se assemelhem mais em termos de intervalo. Vai perceber que, embora o score de silhueta diminua, o 'cotovelo' no gráfico suaviza-se. Isto acontece porque deixar os dados sem escala permite que dados com menos variância tenham mais peso. Leia mais sobre este problema [aqui](https://stats.stackexchange.com/questions/21222/are-mean-normalization-and-feature-scaling-needed-for-k-means-clustering/21226#21226).\n",
|
||||
"\n",
|
||||
"## [**Questionário pós-aula**](https://gray-sand-07a10f403.1.azurestaticapps.net/quiz/30/)\n",
|
||||
"\n",
|
||||
"## **Revisão & Autoestudo**\n",
|
||||
"\n",
|
||||
"- Dê uma olhada num Simulador de K-Means [como este](https://user.ceng.metu.edu.tr/~akifakkus/courses/ceng574/k-means/). Pode usar esta ferramenta para visualizar pontos de dados de amostra e determinar os seus centróides. Pode editar a aleatoriedade dos dados, o número de clusters e o número de centróides. Isto ajuda-o a ter uma ideia de como os dados podem ser agrupados?\n",
|
||||
"\n",
|
||||
"- Além disso, veja [este documento sobre K-Means](https://stanford.edu/~cpiech/cs221/handouts/kmeans.html) da Stanford.\n",
|
||||
"\n",
|
||||
"Quer testar as suas novas competências de clustering em conjuntos de dados que se adaptam bem ao K-Means clustering? Veja:\n",
|
||||
"\n",
|
||||
"- [Treinar e Avaliar Modelos de Clustering](https://rpubs.com/eR_ic/clustering) usando Tidymodels e amigos\n",
|
||||
"\n",
|
||||
"- [Análise de Cluster K-Means](https://uc-r.github.io/kmeans_clustering), UC Business Analytics R Programming Guide\n",
|
||||
"\n",
|
||||
"- [Clustering K-Means com princípios de dados organizados](https://www.tidymodels.org/learn/statistics/k-means/)\n",
|
||||
"\n",
|
||||
"## **Tarefa**\n",
|
||||
"\n",
|
||||
"[Experimente diferentes métodos de clustering](https://github.com/microsoft/ML-For-Beginners/blob/main/5-Clustering/2-K-Means/assignment.md)\n",
|
||||
"\n",
|
||||
"## AGRADECIMENTOS A:\n",
|
||||
"\n",
|
||||
"[Jen Looper](https://www.twitter.com/jenlooper) por criar a versão original em Python deste módulo ♥️\n",
|
||||
"\n",
|
||||
"[`Allison Horst`](https://twitter.com/allison_horst/) por criar as ilustrações incríveis que tornam o R mais acolhedor e envolvente. Encontre mais ilustrações na sua [galeria](https://www.google.com/url?q=https://github.com/allisonhorst/stats-illustrations&sa=D&source=editors&ust=1626380772530000&usg=AOvVaw3zcfyCizFQZpkSLzxiiQEM).\n",
|
||||
"\n",
|
||||
"Boas aprendizagens,\n",
|
||||
"\n",
|
||||
"[Eric](https://twitter.com/ericntay), Embaixador Estudante Gold da Microsoft Learn.\n",
|
||||
"\n",
|
||||
"<p >\n",
|
||||
" <img src=\"../../images/r_learners_sm.jpeg\"\n",
|
||||
" width=\"500\"/>\n",
|
||||
" <figcaption>Arte por @allison_horst</figcaption>\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,33 @@
|
||||
# Modelos de clustering para aprendizagem automática
|
||||
|
||||
Clustering é uma tarefa de aprendizagem automática que procura encontrar objetos semelhantes entre si e agrupá-los em grupos chamados clusters. O que diferencia o clustering de outras abordagens na aprendizagem automática é que tudo acontece de forma automática; na verdade, é justo dizer que é o oposto da aprendizagem supervisionada.
|
||||
|
||||
## Tópico regional: modelos de clustering para o gosto musical do público nigeriano 🎧
|
||||
|
||||
O público diversificado da Nigéria tem gostos musicais igualmente variados. Usando dados extraídos do Spotify (inspirado por [este artigo](https://towardsdatascience.com/country-wise-visual-analysis-of-music-taste-using-spotify-api-seaborn-in-python-77f5b749b421)), vamos analisar algumas músicas populares na Nigéria. Este conjunto de dados inclui informações sobre o 'danceability', 'acousticness', volume, 'speechiness', popularidade e energia de várias músicas. Será interessante descobrir padrões nesses dados!
|
||||
|
||||

|
||||
|
||||
> Foto de <a href="https://unsplash.com/@marcelalaskoski?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Marcela Laskoski</a> no <a href="https://unsplash.com/s/photos/nigerian-music?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||
|
||||
Nesta série de lições, vais descobrir novas formas de analisar dados utilizando técnicas de clustering. O clustering é particularmente útil quando o teu conjunto de dados não tem etiquetas. Se tiver etiquetas, então técnicas de classificação, como as que aprendeste em lições anteriores, podem ser mais úteis. Mas, em casos onde procuras agrupar dados não etiquetados, o clustering é uma ótima forma de descobrir padrões.
|
||||
|
||||
> Existem ferramentas úteis de baixo código que podem ajudar-te a aprender a trabalhar com modelos de clustering. Experimenta [Azure ML para esta tarefa](https://docs.microsoft.com/learn/modules/create-clustering-model-azure-machine-learning-designer/?WT.mc_id=academic-77952-leestott)
|
||||
|
||||
## Lições
|
||||
|
||||
1. [Introdução ao clustering](1-Visualize/README.md)
|
||||
2. [Clustering com K-Means](2-K-Means/README.md)
|
||||
|
||||
## Créditos
|
||||
|
||||
Estas lições foram escritas com 🎶 por [Jen Looper](https://www.twitter.com/jenlooper) com revisões úteis de [Rishit Dagli](https://rishit_dagli) e [Muhammad Sakib Khan Inan](https://twitter.com/Sakibinan).
|
||||
|
||||
O conjunto de dados [Nigerian Songs](https://www.kaggle.com/sootersaalu/nigerian-songs-spotify) foi obtido no Kaggle, extraído do Spotify.
|
||||
|
||||
Exemplos úteis de K-Means que ajudaram na criação desta lição incluem esta [exploração de íris](https://www.kaggle.com/bburns/iris-exploration-pca-k-means-and-gmm-clustering), este [notebook introdutório](https://www.kaggle.com/prashant111/k-means-clustering-with-python) e este [exemplo hipotético de ONG](https://www.kaggle.com/ankandash/pca-k-means-clustering-hierarchical-clustering).
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,170 @@
|
||||
# Introdução ao processamento de linguagem natural
|
||||
|
||||
Esta lição aborda uma breve história e conceitos importantes do *processamento de linguagem natural* (PLN), um subcampo da *linguística computacional*.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Introdução
|
||||
|
||||
O PLN, como é comumente conhecido, é uma das áreas mais conhecidas onde o aprendizado de máquina foi aplicado e utilizado em softwares de produção.
|
||||
|
||||
✅ Consegue pensar em algum software que utiliza diariamente e que provavelmente tem algum PLN integrado? E os seus programas de processamento de texto ou as aplicações móveis que usa regularmente?
|
||||
|
||||
Você aprenderá sobre:
|
||||
|
||||
- **A ideia de línguas**. Como as línguas se desenvolveram e quais foram as principais áreas de estudo.
|
||||
- **Definição e conceitos**. Também aprenderá definições e conceitos sobre como os computadores processam texto, incluindo análise sintática, gramática e identificação de substantivos e verbos. Há algumas tarefas de codificação nesta lição, e vários conceitos importantes são introduzidos, que você aprenderá a programar nas próximas lições.
|
||||
|
||||
## Linguística computacional
|
||||
|
||||
A linguística computacional é uma área de pesquisa e desenvolvimento que, ao longo de muitas décadas, estuda como os computadores podem trabalhar com línguas, compreendê-las, traduzi-las e até mesmo se comunicar com elas. O processamento de linguagem natural (PLN) é um campo relacionado, focado em como os computadores podem processar línguas "naturais", ou seja, humanas.
|
||||
|
||||
### Exemplo - ditado no telemóvel
|
||||
|
||||
Se alguma vez ditou algo para o seu telemóvel em vez de escrever ou fez uma pergunta a um assistente virtual, a sua fala foi convertida em texto e depois processada ou *analisada* a partir da língua que falou. As palavras-chave detectadas foram então processadas num formato que o telemóvel ou assistente pudesse compreender e agir.
|
||||
|
||||

|
||||
> Compreensão linguística real é difícil! Imagem por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
### Como é que esta tecnologia é possível?
|
||||
|
||||
Isto é possível porque alguém escreveu um programa de computador para o fazer. Há algumas décadas, alguns escritores de ficção científica previram que as pessoas falariam principalmente com os seus computadores, e que os computadores entenderiam sempre exatamente o que elas queriam dizer. Infelizmente, revelou-se um problema mais difícil do que muitos imaginavam e, embora hoje seja um problema muito mais bem compreendido, ainda existem desafios significativos para alcançar um processamento de linguagem natural "perfeito" no que diz respeito a compreender o significado de uma frase. Este é um problema particularmente difícil quando se trata de entender humor ou detectar emoções como sarcasmo numa frase.
|
||||
|
||||
Neste momento, talvez se lembre das aulas escolares em que o professor abordava as partes da gramática numa frase. Em alguns países, os alunos aprendem gramática e linguística como uma disciplina dedicada, mas em muitos, esses tópicos estão incluídos como parte do aprendizado de uma língua: seja a sua primeira língua na escola primária (aprendendo a ler e escrever) ou talvez uma segunda língua no ensino secundário. Não se preocupe se não for um especialista em diferenciar substantivos de verbos ou advérbios de adjetivos!
|
||||
|
||||
Se tem dificuldade em distinguir entre o *presente simples* e o *presente contínuo*, não está sozinho. Isso é um desafio para muitas pessoas, mesmo falantes nativos de uma língua. A boa notícia é que os computadores são muito bons em aplicar regras formais, e você aprenderá a escrever código que pode *analisar* uma frase tão bem quanto um humano. O maior desafio que examinará mais tarde é compreender o *significado* e o *sentimento* de uma frase.
|
||||
|
||||
## Pré-requisitos
|
||||
|
||||
Para esta lição, o principal pré-requisito é ser capaz de ler e compreender a língua desta lição. Não há problemas matemáticos ou equações para resolver. Embora o autor original tenha escrito esta lição em inglês, ela também foi traduzida para outras línguas, então pode estar a ler uma tradução. Há exemplos onde são usados vários idiomas diferentes (para comparar as diferentes regras gramaticais de diferentes línguas). Estes *não* são traduzidos, mas o texto explicativo é, então o significado deve ser claro.
|
||||
|
||||
Para as tarefas de codificação, usará Python e os exemplos utilizam Python 3.8.
|
||||
|
||||
Nesta seção, precisará e usará:
|
||||
|
||||
- **Compreensão de Python 3**. Compreensão da linguagem de programação Python 3, esta lição utiliza entrada, loops, leitura de ficheiros e arrays.
|
||||
- **Visual Studio Code + extensão**. Usaremos o Visual Studio Code e sua extensão para Python. Também pode usar um IDE de Python à sua escolha.
|
||||
- **TextBlob**. [TextBlob](https://github.com/sloria/TextBlob) é uma biblioteca simplificada de processamento de texto para Python. Siga as instruções no site do TextBlob para instalá-lo no seu sistema (instale também os corpora, conforme mostrado abaixo):
|
||||
|
||||
```bash
|
||||
pip install -U textblob
|
||||
python -m textblob.download_corpora
|
||||
```
|
||||
|
||||
> 💡 Dica: Pode executar Python diretamente em ambientes do VS Code. Consulte a [documentação](https://code.visualstudio.com/docs/languages/python?WT.mc_id=academic-77952-leestott) para mais informações.
|
||||
|
||||
## Conversando com máquinas
|
||||
|
||||
A história de tentar fazer os computadores entenderem a linguagem humana remonta a décadas, e um dos primeiros cientistas a considerar o processamento de linguagem natural foi *Alan Turing*.
|
||||
|
||||
### O 'teste de Turing'
|
||||
|
||||
Quando Turing estava a pesquisar *inteligência artificial* na década de 1950, ele considerou se um teste de conversação poderia ser dado a um humano e a um computador (via correspondência escrita) onde o humano na conversa não tivesse certeza se estava a conversar com outro humano ou com um computador.
|
||||
|
||||
Se, após um certo tempo de conversa, o humano não conseguisse determinar se as respostas vinham de um computador ou não, então poderia dizer-se que o computador estava *a pensar*?
|
||||
|
||||
### A inspiração - 'o jogo da imitação'
|
||||
|
||||
A ideia para isso veio de um jogo de festa chamado *O Jogo da Imitação*, onde um interrogador está sozinho numa sala e tem a tarefa de determinar quais das duas pessoas (noutra sala) são homem e mulher, respetivamente. O interrogador pode enviar notas e deve tentar pensar em perguntas cujas respostas escritas revelem o género da pessoa misteriosa. Claro, os jogadores na outra sala tentam enganar o interrogador, respondendo de forma a confundir ou induzir em erro, enquanto dão a aparência de responder honestamente.
|
||||
|
||||
### Desenvolvendo Eliza
|
||||
|
||||
Na década de 1960, um cientista do MIT chamado *Joseph Weizenbaum* desenvolveu [*Eliza*](https://wikipedia.org/wiki/ELIZA), uma "terapeuta" computorizada que fazia perguntas ao humano e dava a impressão de entender as suas respostas. No entanto, embora Eliza pudesse analisar uma frase e identificar certos construtos gramaticais e palavras-chave para dar uma resposta razoável, não se podia dizer que *entendia* a frase. Se Eliza recebesse uma frase no formato "**Eu estou** <u>triste</u>", poderia reorganizar e substituir palavras na frase para formar a resposta "Há quanto tempo **você está** <u>triste</u>".
|
||||
|
||||
Isso dava a impressão de que Eliza entendia a declaração e estava a fazer uma pergunta de seguimento, enquanto na realidade estava apenas a mudar o tempo verbal e a adicionar algumas palavras. Se Eliza não conseguisse identificar uma palavra-chave para a qual tivesse uma resposta, daria uma resposta aleatória que poderia ser aplicável a muitas declarações diferentes. Eliza podia ser facilmente enganada, por exemplo, se um utilizador escrevesse "**Você é** uma <u>bicicleta</u>", ela poderia responder "Há quanto tempo **eu sou** uma <u>bicicleta</u>?", em vez de uma resposta mais razoável.
|
||||
|
||||
[](https://youtu.be/RMK9AphfLco "Conversando com Eliza")
|
||||
|
||||
> 🎥 Clique na imagem acima para um vídeo sobre o programa original ELIZA
|
||||
|
||||
> Nota: Pode ler a descrição original de [Eliza](https://cacm.acm.org/magazines/1966/1/13317-elizaa-computer-program-for-the-study-of-natural-language-communication-between-man-and-machine/abstract) publicada em 1966 se tiver uma conta ACM. Alternativamente, leia sobre Eliza na [wikipedia](https://wikipedia.org/wiki/ELIZA)
|
||||
|
||||
## Exercício - programar um bot de conversação básico
|
||||
|
||||
Um bot de conversação, como Eliza, é um programa que solicita a entrada do utilizador e parece entender e responder de forma inteligente. Ao contrário de Eliza, o nosso bot não terá várias regras que lhe dão a aparência de uma conversa inteligente. Em vez disso, o nosso bot terá apenas uma habilidade: manter a conversa com respostas aleatórias que possam funcionar em quase qualquer conversa trivial.
|
||||
|
||||
### O plano
|
||||
|
||||
Os seus passos ao construir um bot de conversação:
|
||||
|
||||
1. Imprimir instruções a aconselhar o utilizador sobre como interagir com o bot
|
||||
2. Iniciar um loop
|
||||
1. Aceitar a entrada do utilizador
|
||||
2. Se o utilizador pedir para sair, então sair
|
||||
3. Processar a entrada do utilizador e determinar a resposta (neste caso, a resposta é uma escolha aleatória de uma lista de possíveis respostas genéricas)
|
||||
4. Imprimir a resposta
|
||||
3. Voltar ao passo 2
|
||||
|
||||
### Construindo o bot
|
||||
|
||||
Vamos criar o bot a seguir. Começaremos por definir algumas frases.
|
||||
|
||||
1. Crie este bot em Python com as seguintes respostas aleatórias:
|
||||
|
||||
```python
|
||||
random_responses = ["That is quite interesting, please tell me more.",
|
||||
"I see. Do go on.",
|
||||
"Why do you say that?",
|
||||
"Funny weather we've been having, isn't it?",
|
||||
"Let's change the subject.",
|
||||
"Did you catch the game last night?"]
|
||||
```
|
||||
|
||||
Aqui está um exemplo de saída para orientar (a entrada do utilizador está nas linhas que começam com `>`):
|
||||
|
||||
```output
|
||||
Hello, I am Marvin, the simple robot.
|
||||
You can end this conversation at any time by typing 'bye'
|
||||
After typing each answer, press 'enter'
|
||||
How are you today?
|
||||
> I am good thanks
|
||||
That is quite interesting, please tell me more.
|
||||
> today I went for a walk
|
||||
Did you catch the game last night?
|
||||
> I did, but my team lost
|
||||
Funny weather we've been having, isn't it?
|
||||
> yes but I hope next week is better
|
||||
Let's change the subject.
|
||||
> ok, lets talk about music
|
||||
Why do you say that?
|
||||
> because I like music!
|
||||
Why do you say that?
|
||||
> bye
|
||||
It was nice talking to you, goodbye!
|
||||
```
|
||||
|
||||
Uma possível solução para a tarefa está [aqui](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/1-Introduction-to-NLP/solution/bot.py)
|
||||
|
||||
✅ Pare e reflita
|
||||
|
||||
1. Acha que as respostas aleatórias poderiam "enganar" alguém a pensar que o bot realmente o entende?
|
||||
2. Que recursos o bot precisaria para ser mais eficaz?
|
||||
3. Se um bot pudesse realmente "entender" o significado de uma frase, precisaria "lembrar-se" do significado das frases anteriores numa conversa também?
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Escolha um dos elementos de "pare e reflita" acima e tente implementá-lo em código ou escreva uma solução no papel usando pseudocódigo.
|
||||
|
||||
Na próxima lição, aprenderá sobre várias outras abordagens para analisar linguagem natural e aprendizado de máquina.
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão e autoestudo
|
||||
|
||||
Consulte as referências abaixo como oportunidades de leitura adicional.
|
||||
|
||||
### Referências
|
||||
|
||||
1. Schubert, Lenhart, "Computational Linguistics", *The Stanford Encyclopedia of Philosophy* (Spring 2020 Edition), Edward N. Zalta (ed.), URL = <https://plato.stanford.edu/archives/spr2020/entries/computational-linguistics/>.
|
||||
2. Princeton University "About WordNet." [WordNet](https://wordnet.princeton.edu/). Princeton University. 2010.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Procure um bot](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Procure um bot
|
||||
|
||||
## Instruções
|
||||
|
||||
Os bots estão por toda parte. A sua tarefa: encontre um e adote-o! Pode encontrá-los em sites, em aplicações bancárias e ao telefone, por exemplo, quando liga para empresas de serviços financeiros para obter conselhos ou informações sobre contas. Analise o bot e veja se consegue confundi-lo. Se conseguir confundir o bot, por que acha que isso aconteceu? Escreva um pequeno relatório sobre a sua experiência.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplary | Adequado | Precisa de Melhorias |
|
||||
| --------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | --------------------- |
|
||||
| | Uma página completa é escrita, explicando a presumida arquitetura do bot e descrevendo a sua experiência com ele | O relatório está incompleto ou não é bem pesquisado | Nenhum relatório é submetido |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,219 @@
|
||||
# Tarefas e técnicas comuns de processamento de linguagem natural
|
||||
|
||||
Para a maioria das tarefas de *processamento de linguagem natural*, o texto a ser processado deve ser dividido, examinado e os resultados armazenados ou cruzados com regras e conjuntos de dados. Essas tarefas permitem ao programador derivar o _significado_, a _intenção_ ou apenas a _frequência_ de termos e palavras em um texto.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
Vamos explorar técnicas comuns usadas no processamento de texto. Combinadas com aprendizagem automática, essas técnicas ajudam a analisar grandes volumes de texto de forma eficiente. Antes de aplicar ML a essas tarefas, no entanto, vamos entender os problemas enfrentados por um especialista em NLP.
|
||||
|
||||
## Tarefas comuns em NLP
|
||||
|
||||
Existem diferentes maneiras de analisar um texto com o qual você está trabalhando. Há tarefas que você pode realizar e, através delas, é possível compreender o texto e tirar conclusões. Normalmente, essas tarefas são realizadas em sequência.
|
||||
|
||||
### Tokenização
|
||||
|
||||
Provavelmente, a primeira coisa que a maioria dos algoritmos de NLP precisa fazer é dividir o texto em tokens ou palavras. Embora isso pareça simples, lidar com pontuação e delimitadores de palavras e frases em diferentes idiomas pode tornar o processo complicado. Pode ser necessário usar vários métodos para determinar as demarcações.
|
||||
|
||||

|
||||
> Tokenizando uma frase de **Orgulho e Preconceito**. Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
### Embeddings
|
||||
|
||||
[Word embeddings](https://wikipedia.org/wiki/Word_embedding) são uma forma de converter seus dados textuais em valores numéricos. Os embeddings são feitos de maneira que palavras com significados semelhantes ou usadas juntas fiquem agrupadas.
|
||||
|
||||

|
||||
> "Tenho o maior respeito pelos seus nervos, eles são meus velhos amigos." - Word embeddings para uma frase de **Orgulho e Preconceito**. Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
✅ Experimente [esta ferramenta interessante](https://projector.tensorflow.org/) para explorar word embeddings. Ao clicar em uma palavra, aparecem clusters de palavras semelhantes: 'brinquedo' agrupa-se com 'disney', 'lego', 'playstation' e 'console'.
|
||||
|
||||
### Parsing & Marcação de Partes do Discurso
|
||||
|
||||
Cada palavra que foi tokenizada pode ser marcada como uma parte do discurso - substantivo, verbo ou adjetivo. A frase `a rápida raposa vermelha saltou sobre o cão castanho preguiçoso` pode ser marcada como POS, por exemplo, raposa = substantivo, saltou = verbo.
|
||||
|
||||

|
||||
|
||||
> Parsing de uma frase de **Orgulho e Preconceito**. Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
Parsing é o reconhecimento de quais palavras estão relacionadas umas às outras em uma frase - por exemplo, `a rápida raposa vermelha saltou` é uma sequência de adjetivo-substantivo-verbo que é separada da sequência `cão castanho preguiçoso`.
|
||||
|
||||
### Frequência de Palavras e Frases
|
||||
|
||||
Um procedimento útil ao analisar um grande corpo de texto é construir um dicionário de cada palavra ou frase de interesse e quantas vezes ela aparece. A frase `a rápida raposa vermelha saltou sobre o cão castanho preguiçoso` tem uma frequência de palavras de 2 para "a".
|
||||
|
||||
Vamos analisar um texto de exemplo onde contamos a frequência de palavras. O poema The Winners de Rudyard Kipling contém o seguinte verso:
|
||||
|
||||
```output
|
||||
What the moral? Who rides may read.
|
||||
When the night is thick and the tracks are blind
|
||||
A friend at a pinch is a friend, indeed,
|
||||
But a fool to wait for the laggard behind.
|
||||
Down to Gehenna or up to the Throne,
|
||||
He travels the fastest who travels alone.
|
||||
```
|
||||
|
||||
Como as frequências de frases podem ser sensíveis ou não a maiúsculas, a frase `um amigo` tem uma frequência de 2, `o` tem uma frequência de 6 e `viaja` tem uma frequência de 2.
|
||||
|
||||
### N-grams
|
||||
|
||||
Um texto pode ser dividido em sequências de palavras de um comprimento definido, uma única palavra (unigrama), duas palavras (bigramas), três palavras (trigramas) ou qualquer número de palavras (n-grams).
|
||||
|
||||
Por exemplo, `a rápida raposa vermelha saltou sobre o cão castanho preguiçoso` com um valor de n-gram de 2 produz os seguintes n-grams:
|
||||
|
||||
1. a rápida
|
||||
2. rápida raposa
|
||||
3. raposa vermelha
|
||||
4. vermelha saltou
|
||||
5. saltou sobre
|
||||
6. sobre o
|
||||
7. o cão
|
||||
8. cão castanho
|
||||
9. castanho preguiçoso
|
||||
|
||||
Pode ser mais fácil visualizar isso como uma janela deslizante sobre a frase. Aqui está para n-grams de 3 palavras, o n-gram está em negrito em cada frase:
|
||||
|
||||
1. <u>**a rápida raposa**</u> vermelha saltou sobre o cão castanho preguiçoso
|
||||
2. a **<u>rápida raposa vermelha</u>** saltou sobre o cão castanho preguiçoso
|
||||
3. a rápida **<u>raposa vermelha saltou</u>** sobre o cão castanho preguiçoso
|
||||
4. a rápida raposa **<u>vermelha saltou sobre</u>** o cão castanho preguiçoso
|
||||
5. a rápida raposa vermelha **<u>saltou sobre o</u>** cão castanho preguiçoso
|
||||
6. a rápida raposa vermelha saltou **<u>sobre o cão</u>** castanho preguiçoso
|
||||
7. a rápida raposa vermelha saltou sobre <u>**o cão castanho**</u> preguiçoso
|
||||
8. a rápida raposa vermelha saltou sobre o **<u>cão castanho preguiçoso</u>**
|
||||
|
||||

|
||||
|
||||
> Valor de n-gram de 3: Infográfico por [Jen Looper](https://twitter.com/jenlooper)
|
||||
|
||||
### Extração de Frases Nominais
|
||||
|
||||
Na maioria das frases, há um substantivo que é o sujeito ou objeto da frase. Em inglês, muitas vezes é identificável por ter 'a', 'an' ou 'the' antes dele. Identificar o sujeito ou objeto de uma frase através da 'extração da frase nominal' é uma tarefa comum em NLP ao tentar entender o significado de uma frase.
|
||||
|
||||
✅ Na frase "Não consigo fixar a hora, ou o local, ou o olhar ou as palavras, que lançaram a base. Faz muito tempo. Eu estava no meio antes de perceber que tinha começado.", consegue identificar as frases nominais?
|
||||
|
||||
Na frase `a rápida raposa vermelha saltou sobre o cão castanho preguiçoso` há 2 frases nominais: **rápida raposa vermelha** e **cão castanho preguiçoso**.
|
||||
|
||||
### Análise de Sentimento
|
||||
|
||||
Uma frase ou texto pode ser analisado para determinar o sentimento, ou quão *positivo* ou *negativo* ele é. O sentimento é medido em *polaridade* e *objetividade/subjetividade*. A polaridade é medida de -1.0 a 1.0 (negativo a positivo) e de 0.0 a 1.0 (mais objetivo a mais subjetivo).
|
||||
|
||||
✅ Mais tarde, aprenderá que existem diferentes maneiras de determinar o sentimento usando aprendizagem automática, mas uma delas é ter uma lista de palavras e frases categorizadas como positivas ou negativas por um especialista humano e aplicar esse modelo ao texto para calcular um score de polaridade. Consegue perceber como isso funcionaria em algumas circunstâncias e menos em outras?
|
||||
|
||||
### Flexão
|
||||
|
||||
A flexão permite que você pegue uma palavra e obtenha o singular ou plural dela.
|
||||
|
||||
### Lematização
|
||||
|
||||
Um *lema* é a raiz ou palavra principal de um conjunto de palavras, por exemplo, *voou*, *voa*, *voando* têm como lema o verbo *voar*.
|
||||
|
||||
Existem também bases de dados úteis disponíveis para o pesquisador de NLP, como:
|
||||
|
||||
### WordNet
|
||||
|
||||
[WordNet](https://wordnet.princeton.edu/) é uma base de dados de palavras, sinônimos, antônimos e muitos outros detalhes para cada palavra em vários idiomas. É incrivelmente útil ao tentar construir traduções, verificadores ortográficos ou ferramentas de linguagem de qualquer tipo.
|
||||
|
||||
## Bibliotecas de NLP
|
||||
|
||||
Felizmente, você não precisa construir todas essas técnicas sozinho, pois existem excelentes bibliotecas Python disponíveis que tornam o NLP muito mais acessível para desenvolvedores que não são especializados em processamento de linguagem natural ou aprendizagem automática. As próximas lições incluem mais exemplos dessas bibliotecas, mas aqui aprenderá alguns exemplos úteis para ajudá-lo na próxima tarefa.
|
||||
|
||||
### Exercício - usando a biblioteca `TextBlob`
|
||||
|
||||
Vamos usar uma biblioteca chamada TextBlob, pois ela contém APIs úteis para lidar com esses tipos de tarefas. TextBlob "baseia-se nos ombros gigantes do [NLTK](https://nltk.org) e [pattern](https://github.com/clips/pattern), e funciona bem com ambos." Ela possui uma quantidade considerável de ML embutida em sua API.
|
||||
|
||||
> Nota: Um [Guia de Introdução](https://textblob.readthedocs.io/en/dev/quickstart.html#quickstart) útil está disponível para TextBlob e é recomendado para desenvolvedores Python experientes.
|
||||
|
||||
Ao tentar identificar *frases nominais*, TextBlob oferece várias opções de extratores para encontrar frases nominais.
|
||||
|
||||
1. Veja o `ConllExtractor`.
|
||||
|
||||
```python
|
||||
from textblob import TextBlob
|
||||
from textblob.np_extractors import ConllExtractor
|
||||
# import and create a Conll extractor to use later
|
||||
extractor = ConllExtractor()
|
||||
|
||||
# later when you need a noun phrase extractor:
|
||||
user_input = input("> ")
|
||||
user_input_blob = TextBlob(user_input, np_extractor=extractor) # note non-default extractor specified
|
||||
np = user_input_blob.noun_phrases
|
||||
```
|
||||
|
||||
> O que está acontecendo aqui? [ConllExtractor](https://textblob.readthedocs.io/en/dev/api_reference.html?highlight=Conll#textblob.en.np_extractors.ConllExtractor) é "Um extrator de frases nominais que usa chunk parsing treinado com o corpus de treinamento ConLL-2000." ConLL-2000 refere-se à Conferência de Aprendizagem Computacional de Linguagem Natural de 2000. Cada ano a conferência hospedava um workshop para resolver um problema difícil de NLP, e em 2000 foi chunking de frases nominais. Um modelo foi treinado no Wall Street Journal, com "as seções 15-18 como dados de treinamento (211727 tokens) e a seção 20 como dados de teste (47377 tokens)". Pode consultar os procedimentos usados [aqui](https://www.clips.uantwerpen.be/conll2000/chunking/) e os [resultados](https://ifarm.nl/erikt/research/np-chunking.html).
|
||||
|
||||
### Desafio - melhorando seu bot com NLP
|
||||
|
||||
Na lição anterior, você construiu um bot de perguntas e respostas muito simples. Agora, tornará Marvin um pouco mais simpático ao analisar sua entrada para sentimento e imprimir uma resposta que corresponda ao sentimento. Também precisará identificar uma `noun_phrase` e perguntar sobre ela.
|
||||
|
||||
Os passos para construir um bot conversacional melhor:
|
||||
|
||||
1. Imprimir instruções aconselhando o utilizador sobre como interagir com o bot
|
||||
2. Iniciar loop
|
||||
1. Aceitar entrada do utilizador
|
||||
2. Se o utilizador pedir para sair, então sair
|
||||
3. Processar a entrada do utilizador e determinar a resposta de sentimento apropriada
|
||||
4. Se uma frase nominal for detectada no sentimento, pluralizá-la e pedir mais informações sobre esse tópico
|
||||
5. Imprimir resposta
|
||||
3. Voltar ao passo 2
|
||||
|
||||
Aqui está o trecho de código para determinar o sentimento usando TextBlob. Note que há apenas quatro *gradientes* de resposta de sentimento (poderia haver mais, se desejar):
|
||||
|
||||
```python
|
||||
if user_input_blob.polarity <= -0.5:
|
||||
response = "Oh dear, that sounds bad. "
|
||||
elif user_input_blob.polarity <= 0:
|
||||
response = "Hmm, that's not great. "
|
||||
elif user_input_blob.polarity <= 0.5:
|
||||
response = "Well, that sounds positive. "
|
||||
elif user_input_blob.polarity <= 1:
|
||||
response = "Wow, that sounds great. "
|
||||
```
|
||||
|
||||
Aqui está um exemplo de saída para orientá-lo (entrada do utilizador está nas linhas que começam com >):
|
||||
|
||||
```output
|
||||
Hello, I am Marvin, the friendly robot.
|
||||
You can end this conversation at any time by typing 'bye'
|
||||
After typing each answer, press 'enter'
|
||||
How are you today?
|
||||
> I am ok
|
||||
Well, that sounds positive. Can you tell me more?
|
||||
> I went for a walk and saw a lovely cat
|
||||
Well, that sounds positive. Can you tell me more about lovely cats?
|
||||
> cats are the best. But I also have a cool dog
|
||||
Wow, that sounds great. Can you tell me more about cool dogs?
|
||||
> I have an old hounddog but he is sick
|
||||
Hmm, that's not great. Can you tell me more about old hounddogs?
|
||||
> bye
|
||||
It was nice talking to you, goodbye!
|
||||
```
|
||||
|
||||
Uma possível solução para a tarefa está [aqui](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/2-Tasks/solution/bot.py)
|
||||
|
||||
✅ Verificação de Conhecimento
|
||||
|
||||
1. Acha que as respostas simpáticas poderiam 'enganar' alguém a pensar que o bot realmente os compreendeu?
|
||||
2. Identificar a frase nominal torna o bot mais 'crível'?
|
||||
3. Por que extrair uma 'frase nominal' de uma frase seria algo útil?
|
||||
|
||||
---
|
||||
|
||||
Implemente o bot na verificação de conhecimento anterior e teste-o com um amigo. Ele consegue enganá-lo? Consegue tornar seu bot mais 'crível'?
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Escolha uma tarefa na verificação de conhecimento anterior e tente implementá-la. Teste o bot com um amigo. Ele consegue enganá-lo? Consegue tornar seu bot mais 'crível'?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Nas próximas lições, aprenderá mais sobre análise de sentimento. Pesquise esta técnica interessante em artigos como estes no [KDNuggets](https://www.kdnuggets.com/tag/nlp)
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Fazer um bot responder](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Fazer um Bot responder
|
||||
|
||||
## Instruções
|
||||
|
||||
Nas lições anteriores, programaste um bot básico com quem podes conversar. Este bot dá respostas aleatórias até que digas 'adeus'. Consegues tornar as respostas um pouco menos aleatórias e fazer com que o bot responda a coisas específicas, como 'porquê' ou 'como'? Pensa um pouco sobre como o machine learning poderia tornar este tipo de trabalho menos manual à medida que expandes o teu bot. Podes usar as bibliotecas NLTK ou TextBlob para facilitar as tuas tarefas.
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critério | Exemplar | Adequado | Necessita Melhorias |
|
||||
| --------- | -------------------------------------------- | ------------------------------------------------ | ----------------------- |
|
||||
| | Um novo ficheiro bot.py é apresentado e documentado | Um novo ficheiro bot é apresentado, mas contém erros | Nenhum ficheiro é apresentado |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Licença poética
|
||||
|
||||
## Instruções
|
||||
|
||||
Neste [notebook](https://www.kaggle.com/jenlooper/emily-dickinson-word-frequency) pode encontrar mais de 500 poemas de Emily Dickinson previamente analisados quanto ao sentimento utilizando a análise de texto do Azure. Usando este conjunto de dados, analise-o utilizando as técnicas descritas na lição. O sentimento sugerido de um poema corresponde à decisão do serviço mais sofisticado do Azure? Porquê ou porquê não, na sua opinião? Há algo que o surpreenda?
|
||||
|
||||
## Rubrica
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita de Melhorias |
|
||||
| --------- | ------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------ |
|
||||
| | Um notebook é apresentado com uma análise sólida de uma amostra do autor | O notebook está incompleto ou não realiza a análise | Nenhum notebook é apresentado |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,100 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": 3
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"coopTranslator": {
|
||||
"original_hash": "27de2abc0235ebd22080fc8f1107454d",
|
||||
"translation_date": "2025-09-03T20:58:04+00:00",
|
||||
"source_file": "6-NLP/3-Translation-Sentiment/solution/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from textblob import TextBlob\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# You should download the book text, clean it, and import it here\n",
|
||||
"with open(\"pride.txt\", encoding=\"utf8\") as f:\n",
|
||||
" file_contents = f.read()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"book_pride = TextBlob(file_contents)\n",
|
||||
"positive_sentiment_sentences = []\n",
|
||||
"negative_sentiment_sentences = []"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"for sentence in book_pride.sentences:\n",
|
||||
" if sentence.sentiment.polarity == 1:\n",
|
||||
" positive_sentiment_sentences.append(sentence)\n",
|
||||
" if sentence.sentiment.polarity == -1:\n",
|
||||
" negative_sentiment_sentences.append(sentence)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"The \" + str(len(positive_sentiment_sentences)) + \" most positive sentences:\")\n",
|
||||
"for sentence in positive_sentiment_sentences:\n",
|
||||
" print(\"+ \" + str(sentence.replace(\"\\n\", \"\").replace(\" \", \" \")))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"print(\"The \" + str(len(negative_sentiment_sentences)) + \" most negative sentences:\")\n",
|
||||
"for sentence in negative_sentiment_sentences:\n",
|
||||
" print(\"- \" + str(sentence.replace(\"\\n\", \"\").replace(\" \", \" \")))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,408 @@
|
||||
# Análise de sentimentos com avaliações de hotéis - processamento de dados
|
||||
|
||||
Nesta seção, vais utilizar as técnicas das lições anteriores para realizar uma análise exploratória de dados num conjunto de dados extenso. Depois de compreender bem a utilidade das várias colunas, vais aprender:
|
||||
|
||||
- como remover as colunas desnecessárias
|
||||
- como calcular novos dados com base nas colunas existentes
|
||||
- como guardar o conjunto de dados resultante para uso no desafio final
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
### Introdução
|
||||
|
||||
Até agora aprendeste que os dados textuais são bastante diferentes dos dados numéricos. Quando o texto é escrito ou falado por humanos, pode ser analisado para encontrar padrões, frequências, sentimentos e significados. Esta lição leva-te a um conjunto de dados real com um desafio real: **[515K Hotel Reviews Data in Europe](https://www.kaggle.com/jiashenliu/515k-hotel-reviews-data-in-europe)**, que inclui uma [licença CC0: Domínio Público](https://creativecommons.org/publicdomain/zero/1.0/). Os dados foram extraídos de Booking.com a partir de fontes públicas. O criador do conjunto de dados foi Jiashen Liu.
|
||||
|
||||
### Preparação
|
||||
|
||||
Vais precisar de:
|
||||
|
||||
* Capacidade de executar notebooks .ipynb usando Python 3
|
||||
* pandas
|
||||
* NLTK, [que deves instalar localmente](https://www.nltk.org/install.html)
|
||||
* O conjunto de dados disponível no Kaggle [515K Hotel Reviews Data in Europe](https://www.kaggle.com/jiashenliu/515k-hotel-reviews-data-in-europe). Tem cerca de 230 MB descompactado. Faz o download para a pasta raiz `/data` associada a estas lições de NLP.
|
||||
|
||||
## Análise exploratória de dados
|
||||
|
||||
Este desafio assume que estás a construir um bot de recomendação de hotéis usando análise de sentimentos e pontuações de avaliações de hóspedes. O conjunto de dados que vais utilizar inclui avaliações de 1493 hotéis diferentes em 6 cidades.
|
||||
|
||||
Usando Python, um conjunto de dados de avaliações de hotéis e a análise de sentimentos do NLTK, podes descobrir:
|
||||
|
||||
* Quais são as palavras e frases mais frequentemente usadas nas avaliações?
|
||||
* As *tags* oficiais que descrevem um hotel correlacionam-se com as pontuações das avaliações (por exemplo, há mais avaliações negativas para um hotel específico por *Famílias com crianças pequenas* do que por *Viajantes solitários*, talvez indicando que é mais adequado para *Viajantes solitários*)?
|
||||
* As pontuações de sentimentos do NLTK "concordam" com a pontuação numérica do avaliador?
|
||||
|
||||
#### Conjunto de dados
|
||||
|
||||
Vamos explorar o conjunto de dados que descarregaste e guardaste localmente. Abre o ficheiro num editor como o VS Code ou até mesmo no Excel.
|
||||
|
||||
Os cabeçalhos no conjunto de dados são os seguintes:
|
||||
|
||||
*Hotel_Address, Additional_Number_of_Scoring, Review_Date, Average_Score, Hotel_Name, Reviewer_Nationality, Negative_Review, Review_Total_Negative_Word_Counts, Total_Number_of_Reviews, Positive_Review, Review_Total_Positive_Word_Counts, Total_Number_of_Reviews_Reviewer_Has_Given, Reviewer_Score, Tags, days_since_review, lat, lng*
|
||||
|
||||
Aqui estão agrupados de forma que possam ser mais fáceis de examinar:
|
||||
##### Colunas do hotel
|
||||
|
||||
* `Hotel_Name`, `Hotel_Address`, `lat` (latitude), `lng` (longitude)
|
||||
* Usando *lat* e *lng* podes criar um mapa com Python mostrando as localizações dos hotéis (talvez codificado por cores para avaliações negativas e positivas)
|
||||
* Hotel_Address não parece ser muito útil para nós, e provavelmente será substituído por um país para facilitar a ordenação e pesquisa
|
||||
|
||||
**Colunas de meta-avaliação do hotel**
|
||||
|
||||
* `Average_Score`
|
||||
* De acordo com o criador do conjunto de dados, esta coluna é a *Pontuação média do hotel, calculada com base no último comentário do último ano*. Parece uma forma incomum de calcular a pontuação, mas são os dados extraídos, então podemos aceitá-los como estão por agora.
|
||||
|
||||
✅ Com base nas outras colunas deste conjunto de dados, consegues pensar noutra forma de calcular a pontuação média?
|
||||
|
||||
* `Total_Number_of_Reviews`
|
||||
* O número total de avaliações que este hotel recebeu - não está claro (sem escrever algum código) se isto se refere às avaliações no conjunto de dados.
|
||||
* `Additional_Number_of_Scoring`
|
||||
* Isto significa que foi dada uma pontuação de avaliação, mas o avaliador não escreveu uma avaliação positiva ou negativa.
|
||||
|
||||
**Colunas de avaliação**
|
||||
|
||||
- `Reviewer_Score`
|
||||
- Este é um valor numérico com, no máximo, 1 casa decimal entre os valores mínimos e máximos de 2.5 e 10
|
||||
- Não é explicado porque 2.5 é a pontuação mínima possível
|
||||
- `Negative_Review`
|
||||
- Se um avaliador não escreveu nada, este campo terá "**No Negative**"
|
||||
- Nota que um avaliador pode escrever uma avaliação positiva na coluna de avaliação negativa (por exemplo, "não há nada de mau neste hotel")
|
||||
- `Review_Total_Negative_Word_Counts`
|
||||
- Contagens mais altas de palavras negativas indicam uma pontuação mais baixa (sem verificar a sentimentalidade)
|
||||
- `Positive_Review`
|
||||
- Se um avaliador não escreveu nada, este campo terá "**No Positive**"
|
||||
- Nota que um avaliador pode escrever uma avaliação negativa na coluna de avaliação positiva (por exemplo, "não há nada de bom neste hotel")
|
||||
- `Review_Total_Positive_Word_Counts`
|
||||
- Contagens mais altas de palavras positivas indicam uma pontuação mais alta (sem verificar a sentimentalidade)
|
||||
- `Review_Date` e `days_since_review`
|
||||
- Pode ser aplicada uma medida de frescura ou desatualização a uma avaliação (avaliações mais antigas podem não ser tão precisas quanto as mais recentes porque a gestão do hotel mudou, ou foram feitas renovações, ou foi adicionada uma piscina, etc.)
|
||||
- `Tags`
|
||||
- Estas são descritores curtos que um avaliador pode selecionar para descrever o tipo de hóspede que era (por exemplo, solitário ou família), o tipo de quarto que teve, a duração da estadia e como a avaliação foi submetida.
|
||||
- Infelizmente, usar estas tags é problemático, verifica a seção abaixo que discute a sua utilidade.
|
||||
|
||||
**Colunas do avaliador**
|
||||
|
||||
- `Total_Number_of_Reviews_Reviewer_Has_Given`
|
||||
- Isto pode ser um fator num modelo de recomendação, por exemplo, se conseguires determinar que avaliadores mais prolíficos, com centenas de avaliações, eram mais propensos a serem negativos do que positivos. No entanto, o avaliador de qualquer avaliação específica não é identificado com um código único e, portanto, não pode ser ligado a um conjunto de avaliações. Existem 30 avaliadores com 100 ou mais avaliações, mas é difícil ver como isto pode ajudar o modelo de recomendação.
|
||||
- `Reviewer_Nationality`
|
||||
- Algumas pessoas podem pensar que certas nacionalidades são mais propensas a dar uma avaliação positiva ou negativa devido a uma inclinação nacional. Tem cuidado ao construir tais visões anedóticas nos teus modelos. Estes são estereótipos nacionais (e às vezes raciais), e cada avaliador foi um indivíduo que escreveu uma avaliação com base na sua experiência. Esta pode ter sido filtrada por muitas lentes, como as suas estadias anteriores em hotéis, a distância percorrida e o seu temperamento pessoal. Pensar que a nacionalidade foi a razão para uma pontuação de avaliação é difícil de justificar.
|
||||
|
||||
##### Exemplos
|
||||
|
||||
| Average Score | Total Number Reviews | Reviewer Score | Negative <br />Review | Positive Review | Tags |
|
||||
| -------------- | ---------------------- | ---------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ----------------------------------------------------------------------------------------- |
|
||||
| 7.8 | 1945 | 2.5 | Este não é atualmente um hotel, mas um local de construção. Fui aterrorizado desde cedo pela manhã e durante todo o dia com ruídos de construção inaceitáveis enquanto descansava após uma longa viagem e trabalhava no quarto. Pessoas estavam a trabalhar o dia todo, ou seja, com martelos pneumáticos nos quartos adjacentes. Pedi para mudar de quarto, mas não havia nenhum quarto silencioso disponível. Para piorar, fui cobrado em excesso. Fiz o check-out à noite, pois tinha um voo muito cedo e recebi uma fatura apropriada. Um dia depois, o hotel fez outra cobrança sem o meu consentimento, acima do preço reservado. É um lugar terrível. Não te castigues reservando aqui. | Nada. Lugar terrível. Fica longe. | Viagem de negócios. Casal. Quarto duplo standard. Ficou 2 noites. |
|
||||
|
||||
Como podes ver, este hóspede não teve uma estadia feliz neste hotel. O hotel tem uma boa pontuação média de 7.8 e 1945 avaliações, mas este avaliador deu-lhe 2.5 e escreveu 115 palavras sobre como a sua estadia foi negativa. Se não escreveu nada na coluna Positive_Review, podes deduzir que não houve nada positivo, mas ainda assim escreveu 7 palavras de aviso. Se apenas contássemos palavras em vez do significado ou sentimento das palavras, poderíamos ter uma visão distorcida da intenção do avaliador. Estranhamente, a sua pontuação de 2.5 é confusa, porque se a estadia no hotel foi tão má, por que dar qualquer ponto? Investigando o conjunto de dados de perto, vais ver que a pontuação mínima possível é 2.5, não 0. A pontuação máxima possível é 10.
|
||||
|
||||
##### Tags
|
||||
|
||||
Como mencionado acima, à primeira vista, a ideia de usar `Tags` para categorizar os dados faz sentido. Infelizmente, estas tags não são padronizadas, o que significa que num dado hotel, as opções podem ser *Single room*, *Twin room* e *Double room*, mas no próximo hotel, são *Deluxe Single Room*, *Classic Queen Room* e *Executive King Room*. Podem ser a mesma coisa, mas há tantas variações que a escolha torna-se:
|
||||
|
||||
1. Tentar alterar todos os termos para um único padrão, o que é muito difícil, porque não está claro qual seria o caminho de conversão em cada caso (por exemplo, *Classic single room* mapeia para *Single room*, mas *Superior Queen Room with Courtyard Garden or City View* é muito mais difícil de mapear)
|
||||
|
||||
1. Podemos adotar uma abordagem de NLP e medir a frequência de certos termos como *Solo*, *Business Traveller* ou *Family with young kids* conforme se aplicam a cada hotel, e incluir isso na recomendação
|
||||
|
||||
As tags geralmente (mas nem sempre) são um único campo contendo uma lista de 5 a 6 valores separados por vírgulas alinhados a *Tipo de viagem*, *Tipo de hóspedes*, *Tipo de quarto*, *Número de noites* e *Tipo de dispositivo em que a avaliação foi submetida*. No entanto, como alguns avaliadores não preenchem cada campo (podem deixar um em branco), os valores nem sempre estão na mesma ordem.
|
||||
|
||||
Como exemplo, considera *Tipo de grupo*. Existem 1025 possibilidades únicas neste campo na coluna `Tags`, e infelizmente apenas algumas delas referem-se a um grupo (algumas são o tipo de quarto, etc.). Se filtrares apenas as que mencionam família, os resultados contêm muitos resultados do tipo *Family room*. Se incluíres o termo *with*, ou seja, contares os valores *Family with*, os resultados são melhores, com mais de 80.000 dos 515.000 resultados contendo a frase "Family with young children" ou "Family with older children".
|
||||
|
||||
Isto significa que a coluna tags não é completamente inútil para nós, mas será necessário algum trabalho para torná-la útil.
|
||||
|
||||
##### Pontuação média do hotel
|
||||
|
||||
Existem algumas peculiaridades ou discrepâncias no conjunto de dados que não consigo entender, mas são ilustradas aqui para que estejas ciente delas ao construir os teus modelos. Se conseguires descobrir, por favor, avisa-nos na seção de discussão!
|
||||
|
||||
O conjunto de dados tem as seguintes colunas relacionadas à pontuação média e ao número de avaliações:
|
||||
|
||||
1. Hotel_Name
|
||||
2. Additional_Number_of_Scoring
|
||||
3. Average_Score
|
||||
4. Total_Number_of_Reviews
|
||||
5. Reviewer_Score
|
||||
|
||||
O único hotel com mais avaliações neste conjunto de dados é *Britannia International Hotel Canary Wharf* com 4789 avaliações de um total de 515.000. Mas se olharmos para o valor `Total_Number_of_Reviews` deste hotel, é 9086. Podes deduzir que há muitas mais pontuações sem avaliações, então talvez devêssemos adicionar o valor da coluna `Additional_Number_of_Scoring`. Esse valor é 2682, e adicioná-lo a 4789 dá-nos 7471, que ainda está 1615 abaixo do `Total_Number_of_Reviews`.
|
||||
|
||||
Se considerares a coluna `Average_Score`, podes deduzir que é a média das avaliações no conjunto de dados, mas a descrição do Kaggle é "*Pontuação média do hotel, calculada com base no último comentário do último ano*". Isso não parece muito útil, mas podemos calcular a nossa própria média com base nas pontuações das avaliações no conjunto de dados. Usando o mesmo hotel como exemplo, a pontuação média do hotel é dada como 7.1, mas a pontuação calculada (pontuação média do avaliador *no* conjunto de dados) é 6.8. Isto é próximo, mas não o mesmo valor, e só podemos supor que as pontuações dadas nas avaliações `Additional_Number_of_Scoring` aumentaram a média para 7.1. Infelizmente, sem forma de testar ou provar essa suposição, é difícil usar ou confiar em `Average_Score`, `Additional_Number_of_Scoring` e `Total_Number_of_Reviews` quando são baseados em, ou referem-se a, dados que não temos.
|
||||
|
||||
Para complicar ainda mais, o hotel com o segundo maior número de avaliações tem uma pontuação média calculada de 8.12 e a `Average_Score` do conjunto de dados é 8.1. Esta pontuação correta é uma coincidência ou o primeiro hotel é uma discrepância?
|
||||
|
||||
Na possibilidade de que estes hotéis possam ser um caso isolado, e que talvez a maioria dos valores se alinhem (mas alguns não por alguma razão), vamos escrever um pequeno programa a seguir para explorar os valores no conjunto de dados e determinar o uso correto (ou não uso) dos valores.
|
||||
> 🚨 Uma nota de precaução
|
||||
>
|
||||
> Ao trabalhar com este conjunto de dados, irá escrever código que calcula algo a partir do texto sem ter de ler ou analisar o texto diretamente. Esta é a essência do NLP, interpretar significado ou sentimento sem que seja necessário um humano fazê-lo. No entanto, é possível que acabe por ler algumas das críticas negativas. Recomendo que não o faça, porque não é necessário. Algumas delas são disparatadas ou irrelevantes, como críticas negativas a hotéis do tipo "O tempo não estava bom", algo que está fora do controlo do hotel, ou de qualquer pessoa. Mas há também um lado sombrio em algumas críticas. Por vezes, as críticas negativas são racistas, sexistas ou preconceituosas em relação à idade. Isto é lamentável, mas esperado num conjunto de dados extraído de um site público. Alguns utilizadores deixam críticas que podem ser consideradas de mau gosto, desconfortáveis ou perturbadoras. É melhor deixar que o código avalie o sentimento do que lê-las e ficar incomodado. Dito isto, é uma minoria que escreve tais coisas, mas elas existem na mesma.
|
||||
## Exercício - Exploração de dados
|
||||
### Carregar os dados
|
||||
|
||||
Já chega de examinar os dados visualmente, agora vais escrever algum código e obter respostas! Esta secção utiliza a biblioteca pandas. A tua primeira tarefa é garantir que consegues carregar e ler os dados CSV. A biblioteca pandas tem um carregador rápido de CSV, e o resultado é colocado num dataframe, como nas lições anteriores. O CSV que estamos a carregar tem mais de meio milhão de linhas, mas apenas 17 colunas. O pandas oferece muitas formas poderosas de interagir com um dataframe, incluindo a capacidade de realizar operações em cada linha.
|
||||
|
||||
A partir daqui, nesta lição, haverá trechos de código e algumas explicações sobre o código, bem como discussões sobre o significado dos resultados. Usa o _notebook.ipynb_ incluído para o teu código.
|
||||
|
||||
Vamos começar por carregar o ficheiro de dados que vais utilizar:
|
||||
|
||||
```python
|
||||
# Load the hotel reviews from CSV
|
||||
import pandas as pd
|
||||
import time
|
||||
# importing time so the start and end time can be used to calculate file loading time
|
||||
print("Loading data file now, this could take a while depending on file size")
|
||||
start = time.time()
|
||||
# df is 'DataFrame' - make sure you downloaded the file to the data folder
|
||||
df = pd.read_csv('../../data/Hotel_Reviews.csv')
|
||||
end = time.time()
|
||||
print("Loading took " + str(round(end - start, 2)) + " seconds")
|
||||
```
|
||||
|
||||
Agora que os dados estão carregados, podemos realizar algumas operações sobre eles. Mantém este código no topo do teu programa para a próxima parte.
|
||||
|
||||
## Explorar os dados
|
||||
|
||||
Neste caso, os dados já estão *limpos*, o que significa que estão prontos para trabalhar e não têm caracteres noutras línguas que possam causar problemas a algoritmos que esperam apenas caracteres em inglês.
|
||||
|
||||
✅ Poderás ter de trabalhar com dados que requerem algum processamento inicial para os formatar antes de aplicar técnicas de NLP, mas não desta vez. Se tivesses de o fazer, como lidarias com caracteres não ingleses?
|
||||
|
||||
Tira um momento para garantir que, uma vez carregados os dados, consegues explorá-los com código. É muito fácil querer focar nas colunas `Negative_Review` e `Positive_Review`. Elas estão preenchidas com texto natural para os teus algoritmos de NLP processarem. Mas espera! Antes de mergulhares no NLP e na análise de sentimentos, deves seguir o código abaixo para verificar se os valores fornecidos no conjunto de dados correspondem aos valores que calculas com pandas.
|
||||
|
||||
## Operações no dataframe
|
||||
|
||||
A primeira tarefa nesta lição é verificar se as seguintes afirmações estão corretas, escrevendo algum código que examine o dataframe (sem o alterar).
|
||||
|
||||
> Tal como em muitas tarefas de programação, há várias formas de completar isto, mas um bom conselho é fazê-lo da forma mais simples e fácil possível, especialmente se for mais fácil de entender quando voltares a este código no futuro. Com dataframes, há uma API abrangente que frequentemente terá uma forma eficiente de fazer o que precisas.
|
||||
|
||||
Trata as seguintes perguntas como tarefas de codificação e tenta respondê-las sem olhar para a solução.
|
||||
|
||||
1. Imprime a *forma* do dataframe que acabaste de carregar (a forma é o número de linhas e colunas).
|
||||
2. Calcula a contagem de frequência para as nacionalidades dos revisores:
|
||||
1. Quantos valores distintos existem na coluna `Reviewer_Nationality` e quais são eles?
|
||||
2. Qual é a nacionalidade de revisor mais comum no conjunto de dados (imprime o país e o número de revisões)?
|
||||
3. Quais são as 10 nacionalidades mais frequentes e a sua contagem de frequência?
|
||||
3. Qual foi o hotel mais revisado para cada uma das 10 nacionalidades de revisores mais frequentes?
|
||||
4. Quantas revisões existem por hotel (contagem de frequência de hotel) no conjunto de dados?
|
||||
5. Embora exista uma coluna `Average_Score` para cada hotel no conjunto de dados, também podes calcular uma pontuação média (obtendo a média de todas as pontuações dos revisores no conjunto de dados para cada hotel). Adiciona uma nova coluna ao teu dataframe com o cabeçalho `Calc_Average_Score` que contém essa média calculada.
|
||||
6. Algum hotel tem o mesmo valor (arredondado a 1 casa decimal) para `Average_Score` e `Calc_Average_Score`?
|
||||
1. Tenta escrever uma função Python que receba uma Série (linha) como argumento e compare os valores, imprimindo uma mensagem quando os valores não forem iguais. Depois usa o método `.apply()` para processar cada linha com a função.
|
||||
7. Calcula e imprime quantas linhas têm valores "No Negative" na coluna `Negative_Review`.
|
||||
8. Calcula e imprime quantas linhas têm valores "No Positive" na coluna `Positive_Review`.
|
||||
9. Calcula e imprime quantas linhas têm valores "No Positive" na coluna `Positive_Review` **e** valores "No Negative" na coluna `Negative_Review`.
|
||||
|
||||
### Respostas em código
|
||||
|
||||
1. Imprime a *forma* do dataframe que acabaste de carregar (a forma é o número de linhas e colunas).
|
||||
|
||||
```python
|
||||
print("The shape of the data (rows, cols) is " + str(df.shape))
|
||||
> The shape of the data (rows, cols) is (515738, 17)
|
||||
```
|
||||
|
||||
2. Calcula a contagem de frequência para as nacionalidades dos revisores:
|
||||
|
||||
1. Quantos valores distintos existem na coluna `Reviewer_Nationality` e quais são eles?
|
||||
2. Qual é a nacionalidade de revisor mais comum no conjunto de dados (imprime o país e o número de revisões)?
|
||||
|
||||
```python
|
||||
# value_counts() creates a Series object that has index and values in this case, the country and the frequency they occur in reviewer nationality
|
||||
nationality_freq = df["Reviewer_Nationality"].value_counts()
|
||||
print("There are " + str(nationality_freq.size) + " different nationalities")
|
||||
# print first and last rows of the Series. Change to nationality_freq.to_string() to print all of the data
|
||||
print(nationality_freq)
|
||||
|
||||
There are 227 different nationalities
|
||||
United Kingdom 245246
|
||||
United States of America 35437
|
||||
Australia 21686
|
||||
Ireland 14827
|
||||
United Arab Emirates 10235
|
||||
...
|
||||
Comoros 1
|
||||
Palau 1
|
||||
Northern Mariana Islands 1
|
||||
Cape Verde 1
|
||||
Guinea 1
|
||||
Name: Reviewer_Nationality, Length: 227, dtype: int64
|
||||
```
|
||||
|
||||
3. Quais são as 10 nacionalidades mais frequentes e a sua contagem de frequência?
|
||||
|
||||
```python
|
||||
print("The highest frequency reviewer nationality is " + str(nationality_freq.index[0]).strip() + " with " + str(nationality_freq[0]) + " reviews.")
|
||||
# Notice there is a leading space on the values, strip() removes that for printing
|
||||
# What is the top 10 most common nationalities and their frequencies?
|
||||
print("The next 10 highest frequency reviewer nationalities are:")
|
||||
print(nationality_freq[1:11].to_string())
|
||||
|
||||
The highest frequency reviewer nationality is United Kingdom with 245246 reviews.
|
||||
The next 10 highest frequency reviewer nationalities are:
|
||||
United States of America 35437
|
||||
Australia 21686
|
||||
Ireland 14827
|
||||
United Arab Emirates 10235
|
||||
Saudi Arabia 8951
|
||||
Netherlands 8772
|
||||
Switzerland 8678
|
||||
Germany 7941
|
||||
Canada 7894
|
||||
France 7296
|
||||
```
|
||||
|
||||
3. Qual foi o hotel mais revisado para cada uma das 10 nacionalidades de revisores mais frequentes?
|
||||
|
||||
```python
|
||||
# What was the most frequently reviewed hotel for the top 10 nationalities
|
||||
# Normally with pandas you will avoid an explicit loop, but wanted to show creating a new dataframe using criteria (don't do this with large amounts of data because it could be very slow)
|
||||
for nat in nationality_freq[:10].index:
|
||||
# First, extract all the rows that match the criteria into a new dataframe
|
||||
nat_df = df[df["Reviewer_Nationality"] == nat]
|
||||
# Now get the hotel freq
|
||||
freq = nat_df["Hotel_Name"].value_counts()
|
||||
print("The most reviewed hotel for " + str(nat).strip() + " was " + str(freq.index[0]) + " with " + str(freq[0]) + " reviews.")
|
||||
|
||||
The most reviewed hotel for United Kingdom was Britannia International Hotel Canary Wharf with 3833 reviews.
|
||||
The most reviewed hotel for United States of America was Hotel Esther a with 423 reviews.
|
||||
The most reviewed hotel for Australia was Park Plaza Westminster Bridge London with 167 reviews.
|
||||
The most reviewed hotel for Ireland was Copthorne Tara Hotel London Kensington with 239 reviews.
|
||||
The most reviewed hotel for United Arab Emirates was Millennium Hotel London Knightsbridge with 129 reviews.
|
||||
The most reviewed hotel for Saudi Arabia was The Cumberland A Guoman Hotel with 142 reviews.
|
||||
The most reviewed hotel for Netherlands was Jaz Amsterdam with 97 reviews.
|
||||
The most reviewed hotel for Switzerland was Hotel Da Vinci with 97 reviews.
|
||||
The most reviewed hotel for Germany was Hotel Da Vinci with 86 reviews.
|
||||
The most reviewed hotel for Canada was St James Court A Taj Hotel London with 61 reviews.
|
||||
```
|
||||
|
||||
4. Quantas revisões existem por hotel (contagem de frequência de hotel) no conjunto de dados?
|
||||
|
||||
```python
|
||||
# First create a new dataframe based on the old one, removing the uneeded columns
|
||||
hotel_freq_df = df.drop(["Hotel_Address", "Additional_Number_of_Scoring", "Review_Date", "Average_Score", "Reviewer_Nationality", "Negative_Review", "Review_Total_Negative_Word_Counts", "Positive_Review", "Review_Total_Positive_Word_Counts", "Total_Number_of_Reviews_Reviewer_Has_Given", "Reviewer_Score", "Tags", "days_since_review", "lat", "lng"], axis = 1)
|
||||
|
||||
# Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found
|
||||
hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')
|
||||
|
||||
# Get rid of all the duplicated rows
|
||||
hotel_freq_df = hotel_freq_df.drop_duplicates(subset = ["Hotel_Name"])
|
||||
display(hotel_freq_df)
|
||||
```
|
||||
| Hotel_Name | Total_Number_of_Reviews | Total_Reviews_Found |
|
||||
| :----------------------------------------: | :---------------------: | :-----------------: |
|
||||
| Britannia International Hotel Canary Wharf | 9086 | 4789 |
|
||||
| Park Plaza Westminster Bridge London | 12158 | 4169 |
|
||||
| Copthorne Tara Hotel London Kensington | 7105 | 3578 |
|
||||
| ... | ... | ... |
|
||||
| Mercure Paris Porte d Orleans | 110 | 10 |
|
||||
| Hotel Wagner | 135 | 10 |
|
||||
| Hotel Gallitzinberg | 173 | 8 |
|
||||
|
||||
Podes notar que os resultados *contados no conjunto de dados* não correspondem ao valor em `Total_Number_of_Reviews`. Não está claro se este valor no conjunto de dados representa o número total de revisões que o hotel teve, mas nem todas foram recolhidas, ou algum outro cálculo. `Total_Number_of_Reviews` não é usado no modelo devido a esta falta de clareza.
|
||||
|
||||
5. Embora exista uma coluna `Average_Score` para cada hotel no conjunto de dados, também podes calcular uma pontuação média (obtendo a média de todas as pontuações dos revisores no conjunto de dados para cada hotel). Adiciona uma nova coluna ao teu dataframe com o cabeçalho `Calc_Average_Score` que contém essa média calculada. Imprime as colunas `Hotel_Name`, `Average_Score` e `Calc_Average_Score`.
|
||||
|
||||
```python
|
||||
# define a function that takes a row and performs some calculation with it
|
||||
def get_difference_review_avg(row):
|
||||
return row["Average_Score"] - row["Calc_Average_Score"]
|
||||
|
||||
# 'mean' is mathematical word for 'average'
|
||||
df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
|
||||
|
||||
# Add a new column with the difference between the two average scores
|
||||
df["Average_Score_Difference"] = df.apply(get_difference_review_avg, axis = 1)
|
||||
|
||||
# Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel)
|
||||
review_scores_df = df.drop_duplicates(subset = ["Hotel_Name"])
|
||||
|
||||
# Sort the dataframe to find the lowest and highest average score difference
|
||||
review_scores_df = review_scores_df.sort_values(by=["Average_Score_Difference"])
|
||||
|
||||
display(review_scores_df[["Average_Score_Difference", "Average_Score", "Calc_Average_Score", "Hotel_Name"]])
|
||||
```
|
||||
|
||||
Podes também questionar-te sobre o valor de `Average_Score` e porque é que às vezes é diferente da pontuação média calculada. Como não podemos saber porque é que alguns dos valores coincidem, mas outros têm uma diferença, é mais seguro, neste caso, usar as pontuações das revisões que temos para calcular a média nós mesmos. Dito isto, as diferenças são geralmente muito pequenas. Aqui estão os hotéis com a maior diferença entre a média do conjunto de dados e a média calculada:
|
||||
|
||||
| Average_Score_Difference | Average_Score | Calc_Average_Score | Hotel_Name |
|
||||
| :----------------------: | :-----------: | :----------------: | ------------------------------------------: |
|
||||
| -0.8 | 7.7 | 8.5 | Best Western Hotel Astoria |
|
||||
| -0.7 | 8.8 | 9.5 | Hotel Stendhal Place Vend me Paris MGallery |
|
||||
| -0.7 | 7.5 | 8.2 | Mercure Paris Porte d Orleans |
|
||||
| -0.7 | 7.9 | 8.6 | Renaissance Paris Vendome Hotel |
|
||||
| -0.5 | 7.0 | 7.5 | Hotel Royal Elys es |
|
||||
| ... | ... | ... | ... |
|
||||
| 0.7 | 7.5 | 6.8 | Mercure Paris Op ra Faubourg Montmartre |
|
||||
| 0.8 | 7.1 | 6.3 | Holiday Inn Paris Montparnasse Pasteur |
|
||||
| 0.9 | 6.8 | 5.9 | Villa Eugenie |
|
||||
| 0.9 | 8.6 | 7.7 | MARQUIS Faubourg St Honor Relais Ch teaux |
|
||||
| 1.3 | 7.2 | 5.9 | Kube Hotel Ice Bar |
|
||||
|
||||
Com apenas 1 hotel tendo uma diferença de pontuação maior que 1, significa que provavelmente podemos ignorar a diferença e usar a pontuação média calculada.
|
||||
|
||||
6. Calcula e imprime quantas linhas têm valores "No Negative" na coluna `Negative_Review`.
|
||||
|
||||
7. Calcula e imprime quantas linhas têm valores "No Positive" na coluna `Positive_Review`.
|
||||
|
||||
8. Calcula e imprime quantas linhas têm valores "No Positive" na coluna `Positive_Review` **e** valores "No Negative" na coluna `Negative_Review`.
|
||||
|
||||
```python
|
||||
# with lambdas:
|
||||
start = time.time()
|
||||
no_negative_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" else False , axis=1)
|
||||
print("Number of No Negative reviews: " + str(len(no_negative_reviews[no_negative_reviews == True].index)))
|
||||
|
||||
no_positive_reviews = df.apply(lambda x: True if x['Positive_Review'] == "No Positive" else False , axis=1)
|
||||
print("Number of No Positive reviews: " + str(len(no_positive_reviews[no_positive_reviews == True].index)))
|
||||
|
||||
both_no_reviews = df.apply(lambda x: True if x['Negative_Review'] == "No Negative" and x['Positive_Review'] == "No Positive" else False , axis=1)
|
||||
print("Number of both No Negative and No Positive reviews: " + str(len(both_no_reviews[both_no_reviews == True].index)))
|
||||
end = time.time()
|
||||
print("Lambdas took " + str(round(end - start, 2)) + " seconds")
|
||||
|
||||
Number of No Negative reviews: 127890
|
||||
Number of No Positive reviews: 35946
|
||||
Number of both No Negative and No Positive reviews: 127
|
||||
Lambdas took 9.64 seconds
|
||||
```
|
||||
|
||||
## Outra forma
|
||||
|
||||
Outra forma de contar itens sem Lambdas, e usar sum para contar as linhas:
|
||||
|
||||
```python
|
||||
# without lambdas (using a mixture of notations to show you can use both)
|
||||
start = time.time()
|
||||
no_negative_reviews = sum(df.Negative_Review == "No Negative")
|
||||
print("Number of No Negative reviews: " + str(no_negative_reviews))
|
||||
|
||||
no_positive_reviews = sum(df["Positive_Review"] == "No Positive")
|
||||
print("Number of No Positive reviews: " + str(no_positive_reviews))
|
||||
|
||||
both_no_reviews = sum((df.Negative_Review == "No Negative") & (df.Positive_Review == "No Positive"))
|
||||
print("Number of both No Negative and No Positive reviews: " + str(both_no_reviews))
|
||||
|
||||
end = time.time()
|
||||
print("Sum took " + str(round(end - start, 2)) + " seconds")
|
||||
|
||||
Number of No Negative reviews: 127890
|
||||
Number of No Positive reviews: 35946
|
||||
Number of both No Negative and No Positive reviews: 127
|
||||
Sum took 0.19 seconds
|
||||
```
|
||||
|
||||
Podes ter notado que há 127 linhas que têm ambos os valores "No Negative" e "No Positive" nas colunas `Negative_Review` e `Positive_Review`, respetivamente. Isso significa que o revisor deu ao hotel uma pontuação numérica, mas optou por não escrever uma revisão positiva ou negativa. Felizmente, isto é uma pequena quantidade de linhas (127 de 515738, ou 0,02%), então provavelmente não vai enviesar o nosso modelo ou resultados numa direção particular, mas talvez não esperasses que um conjunto de dados de revisões tivesse linhas sem revisões, por isso vale a pena explorar os dados para descobrir linhas como esta.
|
||||
|
||||
Agora que exploraste o conjunto de dados, na próxima lição vais filtrar os dados e adicionar alguma análise de sentimentos.
|
||||
|
||||
---
|
||||
## 🚀Desafio
|
||||
|
||||
Esta lição demonstra, como vimos em lições anteriores, quão importante é entender os teus dados e as suas peculiaridades antes de realizar operações sobre eles. Dados baseados em texto, em particular, requerem uma análise cuidadosa. Explora vários conjuntos de dados ricos em texto e vê se consegues descobrir áreas que poderiam introduzir enviesamento ou sentimentos distorcidos num modelo.
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Segue [este percurso de aprendizagem sobre NLP](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-77952-leestott) para descobrir ferramentas que podes experimentar ao construir modelos baseados em fala e texto.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[NLTK](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,10 @@
|
||||
# NLTK
|
||||
|
||||
## Instruções
|
||||
|
||||
NLTK é uma biblioteca bem conhecida para uso em linguística computacional e NLP. Aproveite esta oportunidade para ler o '[livro do NLTK](https://www.nltk.org/book/)' e experimentar os seus exercícios. Nesta tarefa não avaliada, terá a oportunidade de conhecer esta biblioteca mais a fundo.
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,174 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": 3
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"coopTranslator": {
|
||||
"original_hash": "2d05e7db439376aa824f4b387f8324ca",
|
||||
"translation_date": "2025-09-03T20:57:46+00:00",
|
||||
"source_file": "6-NLP/4-Hotel-Reviews-1/solution/notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# EDA\n",
|
||||
"import pandas as pd\n",
|
||||
"import time"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def get_difference_review_avg(row):\n",
|
||||
" return row[\"Average_Score\"] - row[\"Calc_Average_Score\"]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load the hotel reviews from CSV\n",
|
||||
"print(\"Loading data file now, this could take a while depending on file size\")\n",
|
||||
"start = time.time()\n",
|
||||
"df = pd.read_csv('../../data/Hotel_Reviews.csv')\n",
|
||||
"end = time.time()\n",
|
||||
"print(\"Loading took \" + str(round(end - start, 2)) + \" seconds\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# What shape is the data (rows, columns)?\n",
|
||||
"print(\"The shape of the data (rows, cols) is \" + str(df.shape))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# value_counts() creates a Series object that has index and values\n",
|
||||
"# in this case, the country and the frequency they occur in reviewer nationality\n",
|
||||
"nationality_freq = df[\"Reviewer_Nationality\"].value_counts()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# What reviewer nationality is the most common in the dataset?\n",
|
||||
"print(\"The highest frequency reviewer nationality is \" + str(nationality_freq.index[0]).strip() + \" with \" + str(nationality_freq[0]) + \" reviews.\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# What is the top 10 most common nationalities and their frequencies?\n",
|
||||
"print(\"The top 10 highest frequency reviewer nationalities are:\")\n",
|
||||
"print(nationality_freq[0:10].to_string())\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# How many unique nationalities are there?\n",
|
||||
"print(\"There are \" + str(nationality_freq.index.size) + \" unique nationalities in the dataset\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# What was the most frequently reviewed hotel for the top 10 nationalities - print the hotel and number of reviews\n",
|
||||
"for nat in nationality_freq[:10].index:\n",
|
||||
" # First, extract all the rows that match the criteria into a new dataframe\n",
|
||||
" nat_df = df[df[\"Reviewer_Nationality\"] == nat] \n",
|
||||
" # Now get the hotel freq\n",
|
||||
" freq = nat_df[\"Hotel_Name\"].value_counts()\n",
|
||||
" print(\"The most reviewed hotel for \" + str(nat).strip() + \" was \" + str(freq.index[0]) + \" with \" + str(freq[0]) + \" reviews.\") \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# How many reviews are there per hotel (frequency count of hotel) and do the results match the value in `Total_Number_of_Reviews`?\n",
|
||||
"# First create a new dataframe based on the old one, removing the uneeded columns\n",
|
||||
"hotel_freq_df = df.drop([\"Hotel_Address\", \"Additional_Number_of_Scoring\", \"Review_Date\", \"Average_Score\", \"Reviewer_Nationality\", \"Negative_Review\", \"Review_Total_Negative_Word_Counts\", \"Positive_Review\", \"Review_Total_Positive_Word_Counts\", \"Total_Number_of_Reviews_Reviewer_Has_Given\", \"Reviewer_Score\", \"Tags\", \"days_since_review\", \"lat\", \"lng\"], axis = 1)\n",
|
||||
"# Group the rows by Hotel_Name, count them and put the result in a new column Total_Reviews_Found\n",
|
||||
"hotel_freq_df['Total_Reviews_Found'] = hotel_freq_df.groupby('Hotel_Name').transform('count')\n",
|
||||
"# Get rid of all the duplicated rows\n",
|
||||
"hotel_freq_df = hotel_freq_df.drop_duplicates(subset = [\"Hotel_Name\"])\n",
|
||||
"print()\n",
|
||||
"print(hotel_freq_df.to_string())\n",
|
||||
"print(str(hotel_freq_df.shape))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# While there is an `Average_Score` for each hotel according to the dataset, \n",
|
||||
"# you can also calculate an average score (getting the average of all reviewer scores in the dataset for each hotel)\n",
|
||||
"# Add a new column to your dataframe with the column header `Calc_Average_Score` that contains that calculated average. \n",
|
||||
"df['Calc_Average_Score'] = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)\n",
|
||||
"# Add a new column with the difference between the two average scores\n",
|
||||
"df[\"Average_Score_Difference\"] = df.apply(get_difference_review_avg, axis = 1)\n",
|
||||
"# Create a df without all the duplicates of Hotel_Name (so only 1 row per hotel)\n",
|
||||
"review_scores_df = df.drop_duplicates(subset = [\"Hotel_Name\"])\n",
|
||||
"# Sort the dataframe to find the lowest and highest average score difference\n",
|
||||
"review_scores_df = review_scores_df.sort_values(by=[\"Average_Score_Difference\"])\n",
|
||||
"print(review_scores_df[[\"Average_Score_Difference\", \"Average_Score\", \"Calc_Average_Score\", \"Hotel_Name\"]])\n",
|
||||
"# Do any hotels have the same (rounded to 1 decimal place) `Average_Score` and `Calc_Average_Score`?\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,380 @@
|
||||
# Análise de sentimentos com avaliações de hotéis
|
||||
|
||||
Agora que exploraste o conjunto de dados em detalhe, é hora de filtrar as colunas e usar técnicas de NLP no conjunto de dados para obter novos insights sobre os hotéis.
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
### Operações de Filtragem e Análise de Sentimentos
|
||||
|
||||
Como provavelmente já reparaste, o conjunto de dados tem alguns problemas. Algumas colunas estão preenchidas com informações inúteis, outras parecem incorretas. Mesmo que estejam corretas, não é claro como foram calculadas, e as respostas não podem ser verificadas de forma independente pelos teus próprios cálculos.
|
||||
|
||||
## Exercício: mais um pouco de processamento de dados
|
||||
|
||||
Limpa os dados um pouco mais. Adiciona colunas que serão úteis mais tarde, altera os valores em outras colunas e elimina certas colunas completamente.
|
||||
|
||||
1. Processamento inicial de colunas
|
||||
|
||||
1. Elimina `lat` e `lng`
|
||||
|
||||
2. Substitui os valores de `Hotel_Address` pelos seguintes valores (se o endereço contiver o nome da cidade e do país, altera para apenas a cidade e o país).
|
||||
|
||||
Estas são as únicas cidades e países no conjunto de dados:
|
||||
|
||||
Amesterdão, Países Baixos
|
||||
|
||||
Barcelona, Espanha
|
||||
|
||||
Londres, Reino Unido
|
||||
|
||||
Milão, Itália
|
||||
|
||||
Paris, França
|
||||
|
||||
Viena, Áustria
|
||||
|
||||
```python
|
||||
def replace_address(row):
|
||||
if "Netherlands" in row["Hotel_Address"]:
|
||||
return "Amsterdam, Netherlands"
|
||||
elif "Barcelona" in row["Hotel_Address"]:
|
||||
return "Barcelona, Spain"
|
||||
elif "United Kingdom" in row["Hotel_Address"]:
|
||||
return "London, United Kingdom"
|
||||
elif "Milan" in row["Hotel_Address"]:
|
||||
return "Milan, Italy"
|
||||
elif "France" in row["Hotel_Address"]:
|
||||
return "Paris, France"
|
||||
elif "Vienna" in row["Hotel_Address"]:
|
||||
return "Vienna, Austria"
|
||||
|
||||
# Replace all the addresses with a shortened, more useful form
|
||||
df["Hotel_Address"] = df.apply(replace_address, axis = 1)
|
||||
# The sum of the value_counts() should add up to the total number of reviews
|
||||
print(df["Hotel_Address"].value_counts())
|
||||
```
|
||||
|
||||
Agora podes consultar dados a nível de país:
|
||||
|
||||
```python
|
||||
display(df.groupby("Hotel_Address").agg({"Hotel_Name": "nunique"}))
|
||||
```
|
||||
|
||||
| Hotel_Address | Hotel_Name |
|
||||
| :--------------------- | :--------: |
|
||||
| Amesterdão, Países Baixos | 105 |
|
||||
| Barcelona, Espanha | 211 |
|
||||
| Londres, Reino Unido | 400 |
|
||||
| Milão, Itália | 162 |
|
||||
| Paris, França | 458 |
|
||||
| Viena, Áustria | 158 |
|
||||
|
||||
2. Processar colunas de meta-avaliação dos hotéis
|
||||
|
||||
1. Elimina `Additional_Number_of_Scoring`
|
||||
|
||||
1. Substitui `Total_Number_of_Reviews` pelo número total de avaliações para aquele hotel que estão realmente no conjunto de dados
|
||||
|
||||
1. Substitui `Average_Score` pela nossa própria pontuação calculada
|
||||
|
||||
```python
|
||||
# Drop `Additional_Number_of_Scoring`
|
||||
df.drop(["Additional_Number_of_Scoring"], axis = 1, inplace=True)
|
||||
# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values
|
||||
df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')
|
||||
df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)
|
||||
```
|
||||
|
||||
3. Processar colunas de avaliação
|
||||
|
||||
1. Elimina `Review_Total_Negative_Word_Counts`, `Review_Total_Positive_Word_Counts`, `Review_Date` e `days_since_review`
|
||||
|
||||
2. Mantém `Reviewer_Score`, `Negative_Review` e `Positive_Review` como estão
|
||||
|
||||
3. Mantém `Tags` por agora
|
||||
|
||||
- Faremos algumas operações adicionais de filtragem nas tags na próxima seção e depois as tags serão eliminadas
|
||||
|
||||
4. Processar colunas de avaliadores
|
||||
|
||||
1. Elimina `Total_Number_of_Reviews_Reviewer_Has_Given`
|
||||
|
||||
2. Mantém `Reviewer_Nationality`
|
||||
|
||||
### Colunas de Tags
|
||||
|
||||
A coluna `Tag` é problemática, pois é uma lista (em formato de texto) armazenada na coluna. Infelizmente, a ordem e o número de subsecções nesta coluna nem sempre são os mesmos. É difícil para um humano identificar as frases corretas de interesse, porque há 515.000 linhas e 1427 hotéis, e cada um tem opções ligeiramente diferentes que um avaliador poderia escolher. É aqui que o NLP se destaca. Podes analisar o texto e encontrar as frases mais comuns, e contá-las.
|
||||
|
||||
Infelizmente, não estamos interessados em palavras isoladas, mas em frases compostas (por exemplo, *Viagem de negócios*). Executar um algoritmo de distribuição de frequência de frases compostas em tantos dados (6762646 palavras) poderia levar um tempo extraordinário, mas sem olhar para os dados, pareceria que isso é uma despesa necessária. É aqui que a análise exploratória de dados é útil, porque já viste uma amostra das tags como `[' Viagem de negócios ', ' Viajante sozinho ', ' Quarto individual ', ' Ficou 5 noites ', ' Enviado de um dispositivo móvel ']`, podes começar a perguntar se é possível reduzir drasticamente o processamento que tens de fazer. Felizmente, é - mas primeiro precisas seguir alguns passos para determinar as tags de interesse.
|
||||
|
||||
### Filtragem de tags
|
||||
|
||||
Lembra-te de que o objetivo do conjunto de dados é adicionar sentimentos e colunas que te ajudem a escolher o melhor hotel (para ti ou talvez para um cliente que te encarregue de criar um bot de recomendação de hotéis). Precisas perguntar-te se as tags são úteis ou não no conjunto de dados final. Aqui está uma interpretação (se precisasses do conjunto de dados para outros fins, tags diferentes poderiam permanecer/ser excluídas da seleção):
|
||||
|
||||
1. O tipo de viagem é relevante e deve permanecer
|
||||
2. O tipo de grupo de hóspedes é importante e deve permanecer
|
||||
3. O tipo de quarto, suíte ou estúdio em que o hóspede ficou é irrelevante (todos os hotéis têm basicamente os mesmos quartos)
|
||||
4. O dispositivo no qual a avaliação foi enviada é irrelevante
|
||||
5. O número de noites que o avaliador ficou *poderia* ser relevante se atribuísses estadias mais longas a gostar mais do hotel, mas é um pouco forçado e provavelmente irrelevante
|
||||
|
||||
Em resumo, **mantém 2 tipos de tags e remove as outras**.
|
||||
|
||||
Primeiro, não queres contar as tags até que estejam num formato melhor, o que significa remover os colchetes e aspas. Podes fazer isso de várias maneiras, mas queres a mais rápida, pois pode levar muito tempo para processar muitos dados. Felizmente, o pandas tem uma maneira fácil de realizar cada um desses passos.
|
||||
|
||||
```Python
|
||||
# Remove opening and closing brackets
|
||||
df.Tags = df.Tags.str.strip("[']")
|
||||
# remove all quotes too
|
||||
df.Tags = df.Tags.str.replace(" ', '", ",", regex = False)
|
||||
```
|
||||
|
||||
Cada tag torna-se algo como: `Viagem de negócios, Viajante sozinho, Quarto individual, Ficou 5 noites, Enviado de um dispositivo móvel`.
|
||||
|
||||
A seguir, encontramos um problema. Algumas avaliações, ou linhas, têm 5 colunas, outras 3, outras 6. Isso é resultado de como o conjunto de dados foi criado e difícil de corrigir. Queres obter uma contagem de frequência de cada frase, mas elas estão em ordens diferentes em cada avaliação, então a contagem pode estar errada e um hotel pode não receber uma tag atribuída que merecia.
|
||||
|
||||
Em vez disso, vais usar a ordem diferente a nosso favor, porque cada tag é composta por várias palavras, mas também separada por uma vírgula! A maneira mais simples de fazer isso é criar 6 colunas temporárias com cada tag inserida na coluna correspondente à sua ordem na tag. Podes então fundir as 6 colunas numa grande coluna e executar o método `value_counts()` na coluna resultante. Ao imprimir isso, verás que havia 2428 tags únicas. Aqui está uma pequena amostra:
|
||||
|
||||
| Tag | Contagem |
|
||||
| ------------------------------ | -------- |
|
||||
| Viagem de lazer | 417778 |
|
||||
| Enviado de um dispositivo móvel| 307640 |
|
||||
| Casal | 252294 |
|
||||
| Ficou 1 noite | 193645 |
|
||||
| Ficou 2 noites | 133937 |
|
||||
| Viajante sozinho | 108545 |
|
||||
| Ficou 3 noites | 95821 |
|
||||
| Viagem de negócios | 82939 |
|
||||
| Grupo | 65392 |
|
||||
| Família com crianças pequenas | 61015 |
|
||||
| Ficou 4 noites | 47817 |
|
||||
| Quarto duplo | 35207 |
|
||||
| Quarto duplo padrão | 32248 |
|
||||
| Quarto duplo superior | 31393 |
|
||||
| Família com crianças mais velhas| 26349 |
|
||||
| Quarto duplo deluxe | 24823 |
|
||||
| Quarto duplo ou twin | 22393 |
|
||||
| Ficou 5 noites | 20845 |
|
||||
| Quarto duplo ou twin padrão | 17483 |
|
||||
| Quarto duplo clássico | 16989 |
|
||||
| Quarto duplo ou twin superior | 13570 |
|
||||
| 2 quartos | 12393 |
|
||||
|
||||
Algumas das tags comuns como `Enviado de um dispositivo móvel` não são úteis para nós, então pode ser inteligente removê-las antes de contar a ocorrência de frases, mas é uma operação tão rápida que podes deixá-las e ignorá-las.
|
||||
|
||||
### Remover tags de duração da estadia
|
||||
|
||||
Remover estas tags é o passo 1, reduzindo ligeiramente o número total de tags a serem consideradas. Nota que não as removes do conjunto de dados, apenas escolhes removê-las da consideração como valores a contar/manter no conjunto de dados de avaliações.
|
||||
|
||||
| Duração da estadia | Contagem |
|
||||
| ------------------ | -------- |
|
||||
| Ficou 1 noite | 193645 |
|
||||
| Ficou 2 noites | 133937 |
|
||||
| Ficou 3 noites | 95821 |
|
||||
| Ficou 4 noites | 47817 |
|
||||
| Ficou 5 noites | 20845 |
|
||||
| Ficou 6 noites | 9776 |
|
||||
| Ficou 7 noites | 7399 |
|
||||
| Ficou 8 noites | 2502 |
|
||||
| Ficou 9 noites | 1293 |
|
||||
| ... | ... |
|
||||
|
||||
Há uma enorme variedade de quartos, suítes, estúdios, apartamentos e assim por diante. Todos significam mais ou menos a mesma coisa e não são relevantes para ti, então remove-os da consideração.
|
||||
|
||||
| Tipo de quarto | Contagem |
|
||||
| ------------------------------- | -------- |
|
||||
| Quarto duplo | 35207 |
|
||||
| Quarto duplo padrão | 32248 |
|
||||
| Quarto duplo superior | 31393 |
|
||||
| Quarto duplo deluxe | 24823 |
|
||||
| Quarto duplo ou twin | 22393 |
|
||||
| Quarto duplo ou twin padrão | 17483 |
|
||||
| Quarto duplo clássico | 16989 |
|
||||
| Quarto duplo ou twin superior | 13570 |
|
||||
|
||||
Finalmente, e isto é encantador (porque não exigiu muito processamento), ficarás com as seguintes tags *úteis*:
|
||||
|
||||
| Tag | Contagem |
|
||||
| --------------------------------------------- | -------- |
|
||||
| Viagem de lazer | 417778 |
|
||||
| Casal | 252294 |
|
||||
| Viajante sozinho | 108545 |
|
||||
| Viagem de negócios | 82939 |
|
||||
| Grupo (combinado com Viajantes com amigos) | 67535 |
|
||||
| Família com crianças pequenas | 61015 |
|
||||
| Família com crianças mais velhas | 26349 |
|
||||
| Com um animal de estimação | 1405 |
|
||||
|
||||
Poderias argumentar que `Viajantes com amigos` é o mesmo que `Grupo` mais ou menos, e seria justo combinar os dois como acima. O código para identificar as tags corretas está no [notebook de Tags](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb).
|
||||
|
||||
O passo final é criar novas colunas para cada uma destas tags. Depois, para cada linha de avaliação, se a coluna `Tag` corresponder a uma das novas colunas, adiciona um 1, caso contrário, adiciona um 0. O resultado final será uma contagem de quantos avaliadores escolheram este hotel (em agregado) para, por exemplo, negócios vs lazer, ou para levar um animal de estimação, e esta é uma informação útil ao recomendar um hotel.
|
||||
|
||||
```python
|
||||
# Process the Tags into new columns
|
||||
# The file Hotel_Reviews_Tags.py, identifies the most important tags
|
||||
# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends,
|
||||
# Family with young children, Family with older children, With a pet
|
||||
df["Leisure_trip"] = df.Tags.apply(lambda tag: 1 if "Leisure trip" in tag else 0)
|
||||
df["Couple"] = df.Tags.apply(lambda tag: 1 if "Couple" in tag else 0)
|
||||
df["Solo_traveler"] = df.Tags.apply(lambda tag: 1 if "Solo traveler" in tag else 0)
|
||||
df["Business_trip"] = df.Tags.apply(lambda tag: 1 if "Business trip" in tag else 0)
|
||||
df["Group"] = df.Tags.apply(lambda tag: 1 if "Group" in tag or "Travelers with friends" in tag else 0)
|
||||
df["Family_with_young_children"] = df.Tags.apply(lambda tag: 1 if "Family with young children" in tag else 0)
|
||||
df["Family_with_older_children"] = df.Tags.apply(lambda tag: 1 if "Family with older children" in tag else 0)
|
||||
df["With_a_pet"] = df.Tags.apply(lambda tag: 1 if "With a pet" in tag else 0)
|
||||
|
||||
```
|
||||
|
||||
### Salvar o ficheiro
|
||||
|
||||
Finalmente, salva o conjunto de dados como está agora com um novo nome.
|
||||
|
||||
```python
|
||||
df.drop(["Review_Total_Negative_Word_Counts", "Review_Total_Positive_Word_Counts", "days_since_review", "Total_Number_of_Reviews_Reviewer_Has_Given"], axis = 1, inplace=True)
|
||||
|
||||
# Saving new data file with calculated columns
|
||||
print("Saving results to Hotel_Reviews_Filtered.csv")
|
||||
df.to_csv(r'../data/Hotel_Reviews_Filtered.csv', index = False)
|
||||
```
|
||||
|
||||
## Operações de Análise de Sentimentos
|
||||
|
||||
Nesta última seção, vais aplicar análise de sentimentos às colunas de avaliação e salvar os resultados num conjunto de dados.
|
||||
|
||||
## Exercício: carregar e salvar os dados filtrados
|
||||
|
||||
Nota que agora estás a carregar o conjunto de dados filtrado que foi salvo na seção anterior, **não** o conjunto de dados original.
|
||||
|
||||
```python
|
||||
import time
|
||||
import pandas as pd
|
||||
import nltk as nltk
|
||||
from nltk.corpus import stopwords
|
||||
from nltk.sentiment.vader import SentimentIntensityAnalyzer
|
||||
nltk.download('vader_lexicon')
|
||||
|
||||
# Load the filtered hotel reviews from CSV
|
||||
df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')
|
||||
|
||||
# You code will be added here
|
||||
|
||||
|
||||
# Finally remember to save the hotel reviews with new NLP data added
|
||||
print("Saving results to Hotel_Reviews_NLP.csv")
|
||||
df.to_csv(r'../data/Hotel_Reviews_NLP.csv', index = False)
|
||||
```
|
||||
|
||||
### Remover palavras irrelevantes
|
||||
|
||||
Se fosses executar a Análise de Sentimentos nas colunas de Avaliação Negativa e Avaliação Positiva, poderia levar muito tempo. Testado num portátil de teste poderoso com CPU rápida, levou 12 - 14 minutos dependendo da biblioteca de sentimentos usada. Esse é um tempo (relativamente) longo, então vale a pena investigar se isso pode ser acelerado.
|
||||
|
||||
Remover palavras irrelevantes, ou palavras comuns em inglês que não alteram o sentimento de uma frase, é o primeiro passo. Ao removê-las, a análise de sentimentos deve ser mais rápida, mas não menos precisa (já que as palavras irrelevantes não afetam o sentimento, mas sim desaceleram a análise).
|
||||
|
||||
A avaliação negativa mais longa tinha 395 palavras, mas após remover as palavras irrelevantes, ficou com 195 palavras.
|
||||
|
||||
Remover as palavras irrelevantes também é uma operação rápida, removê-las de 2 colunas de avaliação em mais de 515.000 linhas levou 3,3 segundos no dispositivo de teste. Pode levar um pouco mais ou menos tempo para ti, dependendo da velocidade do CPU do teu dispositivo, RAM, se tens um SSD ou não, e alguns outros fatores. A relativa rapidez da operação significa que, se melhorar o tempo de análise de sentimentos, então vale a pena fazer.
|
||||
|
||||
```python
|
||||
from nltk.corpus import stopwords
|
||||
|
||||
# Load the hotel reviews from CSV
|
||||
df = pd.read_csv("../../data/Hotel_Reviews_Filtered.csv")
|
||||
|
||||
# Remove stop words - can be slow for a lot of text!
|
||||
# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches
|
||||
# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends
|
||||
start = time.time()
|
||||
cache = set(stopwords.words("english"))
|
||||
def remove_stopwords(review):
|
||||
text = " ".join([word for word in review.split() if word not in cache])
|
||||
return text
|
||||
|
||||
# Remove the stop words from both columns
|
||||
df.Negative_Review = df.Negative_Review.apply(remove_stopwords)
|
||||
df.Positive_Review = df.Positive_Review.apply(remove_stopwords)
|
||||
```
|
||||
|
||||
### Realizar análise de sentimentos
|
||||
|
||||
Agora deves calcular a análise de sentimentos para ambas as colunas de avaliação negativa e positiva, e armazenar o resultado em 2 novas colunas. O teste da análise de sentimentos será compará-lo com a pontuação do avaliador para a mesma avaliação. Por exemplo, se a análise de sentimentos indicar que a avaliação negativa teve um sentimento de 1 (sentimento extremamente positivo) e um sentimento de 1 na avaliação positiva, mas o avaliador deu ao hotel a pontuação mais baixa possível, então ou o texto da avaliação não corresponde à pontuação, ou o analisador de sentimentos não conseguiu reconhecer o sentimento corretamente. Deves esperar que algumas pontuações de sentimentos estejam completamente erradas, e muitas vezes isso será explicável, por exemplo, a avaliação pode ser extremamente sarcástica: "Claro que ADOREI dormir num quarto sem aquecimento" e o analisador de sentimentos pensa que isso é um sentimento positivo, mesmo que um humano ao ler saiba que é sarcasmo.
|
||||
NLTK fornece diferentes analisadores de sentimento para aprender, e você pode substituí-los e verificar se o sentimento é mais ou menos preciso. A análise de sentimento VADER é utilizada aqui.
|
||||
|
||||
> Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, junho de 2014.
|
||||
|
||||
```python
|
||||
from nltk.sentiment.vader import SentimentIntensityAnalyzer
|
||||
|
||||
# Create the vader sentiment analyser (there are others in NLTK you can try too)
|
||||
vader_sentiment = SentimentIntensityAnalyzer()
|
||||
# Hutto, C.J. & Gilbert, E.E. (2014). VADER: A Parsimonious Rule-based Model for Sentiment Analysis of Social Media Text. Eighth International Conference on Weblogs and Social Media (ICWSM-14). Ann Arbor, MI, June 2014.
|
||||
|
||||
# There are 3 possibilities of input for a review:
|
||||
# It could be "No Negative", in which case, return 0
|
||||
# It could be "No Positive", in which case, return 0
|
||||
# It could be a review, in which case calculate the sentiment
|
||||
def calc_sentiment(review):
|
||||
if review == "No Negative" or review == "No Positive":
|
||||
return 0
|
||||
return vader_sentiment.polarity_scores(review)["compound"]
|
||||
```
|
||||
|
||||
Mais tarde, no seu programa, quando estiver pronto para calcular o sentimento, pode aplicá-lo a cada avaliação da seguinte forma:
|
||||
|
||||
```python
|
||||
# Add a negative sentiment and positive sentiment column
|
||||
print("Calculating sentiment columns for both positive and negative reviews")
|
||||
start = time.time()
|
||||
df["Negative_Sentiment"] = df.Negative_Review.apply(calc_sentiment)
|
||||
df["Positive_Sentiment"] = df.Positive_Review.apply(calc_sentiment)
|
||||
end = time.time()
|
||||
print("Calculating sentiment took " + str(round(end - start, 2)) + " seconds")
|
||||
```
|
||||
|
||||
Isso leva aproximadamente 120 segundos no meu computador, mas pode variar em cada máquina. Se quiser imprimir os resultados e verificar se o sentimento corresponde à avaliação:
|
||||
|
||||
```python
|
||||
df = df.sort_values(by=["Negative_Sentiment"], ascending=True)
|
||||
print(df[["Negative_Review", "Negative_Sentiment"]])
|
||||
df = df.sort_values(by=["Positive_Sentiment"], ascending=True)
|
||||
print(df[["Positive_Review", "Positive_Sentiment"]])
|
||||
```
|
||||
|
||||
A última coisa a fazer com o ficheiro antes de utilizá-lo no desafio é salvá-lo! Também deve considerar reorganizar todas as suas novas colunas para que sejam fáceis de trabalhar (para um humano, é uma mudança estética).
|
||||
|
||||
```python
|
||||
# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)
|
||||
df = df.reindex(["Hotel_Name", "Hotel_Address", "Total_Number_of_Reviews", "Average_Score", "Reviewer_Score", "Negative_Sentiment", "Positive_Sentiment", "Reviewer_Nationality", "Leisure_trip", "Couple", "Solo_traveler", "Business_trip", "Group", "Family_with_young_children", "Family_with_older_children", "With_a_pet", "Negative_Review", "Positive_Review"], axis=1)
|
||||
|
||||
print("Saving results to Hotel_Reviews_NLP.csv")
|
||||
df.to_csv(r"../data/Hotel_Reviews_NLP.csv", index = False)
|
||||
```
|
||||
|
||||
Deve executar todo o código do [notebook de análise](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/3-notebook.ipynb) (depois de ter executado [o notebook de filtragem](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb) para gerar o ficheiro Hotel_Reviews_Filtered.csv).
|
||||
|
||||
Para recapitular, os passos são:
|
||||
|
||||
1. O ficheiro do conjunto de dados original **Hotel_Reviews.csv** é explorado na lição anterior com [o notebook de exploração](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/4-Hotel-Reviews-1/solution/notebook.ipynb)
|
||||
2. Hotel_Reviews.csv é filtrado pelo [notebook de filtragem](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb), resultando em **Hotel_Reviews_Filtered.csv**
|
||||
3. Hotel_Reviews_Filtered.csv é processado pelo [notebook de análise de sentimento](https://github.com/microsoft/ML-For-Beginners/blob/main/6-NLP/5-Hotel-Reviews-2/solution/3-notebook.ipynb), resultando em **Hotel_Reviews_NLP.csv**
|
||||
4. Utilize Hotel_Reviews_NLP.csv no Desafio de NLP abaixo
|
||||
|
||||
### Conclusão
|
||||
|
||||
Quando começou, tinha um conjunto de dados com colunas e informações, mas nem tudo podia ser verificado ou utilizado. Explorou os dados, filtrou o que não precisava, converteu etiquetas em algo útil, calculou as suas próprias médias, adicionou algumas colunas de sentimento e, com sorte, aprendeu coisas interessantes sobre o processamento de texto natural.
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Desafio
|
||||
|
||||
Agora que tem o seu conjunto de dados analisado para sentimento, veja se consegue usar estratégias que aprendeu neste currículo (talvez clustering?) para determinar padrões relacionados ao sentimento.
|
||||
|
||||
## Revisão e Estudo Individual
|
||||
|
||||
Faça [este módulo do Learn](https://docs.microsoft.com/en-us/learn/modules/classify-user-feedback-with-the-text-analytics-api/?WT.mc_id=academic-77952-leestott) para aprender mais e usar diferentes ferramentas para explorar o sentimento em texto.
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Experimente um conjunto de dados diferente](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,16 @@
|
||||
# Experimente um conjunto de dados diferente
|
||||
|
||||
## Instruções
|
||||
|
||||
Agora que aprendeu a usar o NLTK para atribuir sentimento a texto, experimente um conjunto de dados diferente. Provavelmente precisará realizar algum processamento de dados, por isso crie um notebook e documente o seu raciocínio. O que descobre?
|
||||
|
||||
## Critérios de Avaliação
|
||||
|
||||
| Critérios | Exemplar | Adequado | Necessita Melhorar |
|
||||
| --------- | ---------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ---------------------- |
|
||||
| | Um notebook completo e um conjunto de dados são apresentados com células bem documentadas explicando como o sentimento é atribuído | O notebook carece de boas explicações | O notebook apresenta falhas |
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,172 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.0"
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3.7.0 64-bit ('3.7')"
|
||||
},
|
||||
"interpreter": {
|
||||
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "033cb89c85500224b3c63fd04f49b4aa",
|
||||
"translation_date": "2025-09-03T20:58:24+00:00",
|
||||
"source_file": "6-NLP/5-Hotel-Reviews-2/solution/1-notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pandas as pd\n",
|
||||
"import time\n",
|
||||
"import ast"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def replace_address(row):\n",
|
||||
" if \"Netherlands\" in row[\"Hotel_Address\"]:\n",
|
||||
" return \"Amsterdam, Netherlands\"\n",
|
||||
" elif \"Barcelona\" in row[\"Hotel_Address\"]:\n",
|
||||
" return \"Barcelona, Spain\"\n",
|
||||
" elif \"United Kingdom\" in row[\"Hotel_Address\"]:\n",
|
||||
" return \"London, United Kingdom\"\n",
|
||||
" elif \"Milan\" in row[\"Hotel_Address\"]: \n",
|
||||
" return \"Milan, Italy\"\n",
|
||||
" elif \"France\" in row[\"Hotel_Address\"]:\n",
|
||||
" return \"Paris, France\"\n",
|
||||
" elif \"Vienna\" in row[\"Hotel_Address\"]:\n",
|
||||
" return \"Vienna, Austria\" \n",
|
||||
" else:\n",
|
||||
" return row.Hotel_Address\n",
|
||||
" "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load the hotel reviews from CSV\n",
|
||||
"start = time.time()\n",
|
||||
"df = pd.read_csv('../../data/Hotel_Reviews.csv')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# dropping columns we will not use:\n",
|
||||
"df.drop([\"lat\", \"lng\"], axis = 1, inplace=True)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Replace all the addresses with a shortened, more useful form\n",
|
||||
"df[\"Hotel_Address\"] = df.apply(replace_address, axis = 1)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Drop `Additional_Number_of_Scoring`\n",
|
||||
"df.drop([\"Additional_Number_of_Scoring\"], axis = 1, inplace=True)\n",
|
||||
"# Replace `Total_Number_of_Reviews` and `Average_Score` with our own calculated values\n",
|
||||
"df.Total_Number_of_Reviews = df.groupby('Hotel_Name').transform('count')\n",
|
||||
"df.Average_Score = round(df.groupby('Hotel_Name').Reviewer_Score.transform('mean'), 1)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Process the Tags into new columns\n",
|
||||
"# The file Hotel_Reviews_Tags.py, identifies the most important tags\n",
|
||||
"# Leisure trip, Couple, Solo traveler, Business trip, Group combined with Travelers with friends, \n",
|
||||
"# Family with young children, Family with older children, With a pet\n",
|
||||
"df[\"Leisure_trip\"] = df.Tags.apply(lambda tag: 1 if \"Leisure trip\" in tag else 0)\n",
|
||||
"df[\"Couple\"] = df.Tags.apply(lambda tag: 1 if \"Couple\" in tag else 0)\n",
|
||||
"df[\"Solo_traveler\"] = df.Tags.apply(lambda tag: 1 if \"Solo traveler\" in tag else 0)\n",
|
||||
"df[\"Business_trip\"] = df.Tags.apply(lambda tag: 1 if \"Business trip\" in tag else 0)\n",
|
||||
"df[\"Group\"] = df.Tags.apply(lambda tag: 1 if \"Group\" in tag or \"Travelers with friends\" in tag else 0)\n",
|
||||
"df[\"Family_with_young_children\"] = df.Tags.apply(lambda tag: 1 if \"Family with young children\" in tag else 0)\n",
|
||||
"df[\"Family_with_older_children\"] = df.Tags.apply(lambda tag: 1 if \"Family with older children\" in tag else 0)\n",
|
||||
"df[\"With_a_pet\"] = df.Tags.apply(lambda tag: 1 if \"With a pet\" in tag else 0)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# No longer need any of these columns\n",
|
||||
"df.drop([\"Review_Date\", \"Review_Total_Negative_Word_Counts\", \"Review_Total_Positive_Word_Counts\", \"days_since_review\", \"Total_Number_of_Reviews_Reviewer_Has_Given\"], axis = 1, inplace=True)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Saving results to Hotel_Reviews_Filtered.csv\n",
|
||||
"Filtering took 23.74 seconds\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Saving new data file with calculated columns\n",
|
||||
"print(\"Saving results to Hotel_Reviews_Filtered.csv\")\n",
|
||||
"df.to_csv(r'../../data/Hotel_Reviews_Filtered.csv', index = False)\n",
|
||||
"end = time.time()\n",
|
||||
"print(\"Filtering took \" + str(round(end - start, 2)) + \" seconds\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,137 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.0"
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3.7.0 64-bit ('3.7')"
|
||||
},
|
||||
"interpreter": {
|
||||
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "341efc86325ec2a214f682f57a189dfd",
|
||||
"translation_date": "2025-09-03T20:58:41+00:00",
|
||||
"source_file": "6-NLP/5-Hotel-Reviews-2/solution/2-notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load the hotel reviews from CSV (you can )\n",
|
||||
"import pandas as pd \n",
|
||||
"\n",
|
||||
"df = pd.read_csv('../../data/Hotel_Reviews_Filtered.csv')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# We want to find the most useful tags to keep\n",
|
||||
"# Remove opening and closing brackets\n",
|
||||
"df.Tags = df.Tags.str.strip(\"[']\")\n",
|
||||
"# remove all quotes too\n",
|
||||
"df.Tags = df.Tags.str.replace(\" ', '\", \",\", regex = False)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# removing this to take advantage of the 'already a phrase' fact of the dataset \n",
|
||||
"# Now split the strings into a list\n",
|
||||
"tag_list_df = df.Tags.str.split(',', expand = True)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Remove leading and trailing spaces\n",
|
||||
"df[\"Tag_1\"] = tag_list_df[0].str.strip()\n",
|
||||
"df[\"Tag_2\"] = tag_list_df[1].str.strip()\n",
|
||||
"df[\"Tag_3\"] = tag_list_df[2].str.strip()\n",
|
||||
"df[\"Tag_4\"] = tag_list_df[3].str.strip()\n",
|
||||
"df[\"Tag_5\"] = tag_list_df[4].str.strip()\n",
|
||||
"df[\"Tag_6\"] = tag_list_df[5].str.strip()\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Merge the 6 columns into one with melt\n",
|
||||
"df_tags = df.melt(value_vars=[\"Tag_1\", \"Tag_2\", \"Tag_3\", \"Tag_4\", \"Tag_5\", \"Tag_6\"])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"The shape of the tags with no filtering: (2514684, 2)\n",
|
||||
" index count\n",
|
||||
"0 Leisure trip 338423\n",
|
||||
"1 Couple 205305\n",
|
||||
"2 Solo traveler 89779\n",
|
||||
"3 Business trip 68176\n",
|
||||
"4 Group 51593\n",
|
||||
"5 Family with young children 49318\n",
|
||||
"6 Family with older children 21509\n",
|
||||
"7 Travelers with friends 1610\n",
|
||||
"8 With a pet 1078\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Get the value counts\n",
|
||||
"tag_vc = df_tags.value.value_counts()\n",
|
||||
"# print(tag_vc)\n",
|
||||
"print(\"The shape of the tags with no filtering:\", str(df_tags.shape))\n",
|
||||
"# Drop rooms, suites, and length of stay, mobile device and anything with less count than a 1000\n",
|
||||
"df_tags = df_tags[~df_tags.value.str.contains(\"Standard|room|Stayed|device|Beds|Suite|Studio|King|Superior|Double\", na=False, case=False)]\n",
|
||||
"tag_vc = df_tags.value.value_counts().reset_index(name=\"count\").query(\"count > 1000\")\n",
|
||||
"# Print the top 10 (there should only be 9 and we'll use these in the filtering section)\n",
|
||||
"print(tag_vc[:10])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,260 @@
|
||||
{
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.0"
|
||||
},
|
||||
"orig_nbformat": 4,
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3.7.0 64-bit ('3.7')"
|
||||
},
|
||||
"interpreter": {
|
||||
"hash": "70b38d7a306a849643e446cd70466270a13445e5987dfa1344ef2b127438fa4d"
|
||||
},
|
||||
"coopTranslator": {
|
||||
"original_hash": "705bf02633759f689abc37b19749a16d",
|
||||
"translation_date": "2025-09-03T20:58:56+00:00",
|
||||
"source_file": "6-NLP/5-Hotel-Reviews-2/solution/3-notebook.ipynb",
|
||||
"language_code": "pt"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2,
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stderr",
|
||||
"text": [
|
||||
"[nltk_data] Downloading package vader_lexicon to\n[nltk_data] /Users/jenlooper/nltk_data...\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"output_type": "execute_result",
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"execution_count": 9
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import time\n",
|
||||
"import pandas as pd\n",
|
||||
"import nltk as nltk\n",
|
||||
"from nltk.corpus import stopwords\n",
|
||||
"from nltk.sentiment.vader import SentimentIntensityAnalyzer\n",
|
||||
"nltk.download('vader_lexicon')\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"vader_sentiment = SentimentIntensityAnalyzer()\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# There are 3 possibilities of input for a review:\n",
|
||||
"# It could be \"No Negative\", in which case, return 0\n",
|
||||
"# It could be \"No Positive\", in which case, return 0\n",
|
||||
"# It could be a review, in which case calculate the sentiment\n",
|
||||
"def calc_sentiment(review): \n",
|
||||
" if review == \"No Negative\" or review == \"No Positive\":\n",
|
||||
" return 0\n",
|
||||
" return vader_sentiment.polarity_scores(review)[\"compound\"] \n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Load the hotel reviews from CSV\n",
|
||||
"df = pd.read_csv(\"../../data/Hotel_Reviews_Filtered.csv\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Remove stop words - can be slow for a lot of text!\n",
|
||||
"# Ryan Han (ryanxjhan on Kaggle) has a great post measuring performance of different stop words removal approaches\n",
|
||||
"# https://www.kaggle.com/ryanxjhan/fast-stop-words-removal # using the approach that Ryan recommends\n",
|
||||
"start = time.time()\n",
|
||||
"cache = set(stopwords.words(\"english\"))\n",
|
||||
"def remove_stopwords(review):\n",
|
||||
" text = \" \".join([word for word in review.split() if word not in cache])\n",
|
||||
" return text\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Remove the stop words from both columns\n",
|
||||
"df.Negative_Review = df.Negative_Review.apply(remove_stopwords) \n",
|
||||
"df.Positive_Review = df.Positive_Review.apply(remove_stopwords)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Removing stop words took 5.77 seconds\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"end = time.time()\n",
|
||||
"print(\"Removing stop words took \" + str(round(end - start, 2)) + \" seconds\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Calculating sentiment columns for both positive and negative reviews\n",
|
||||
"Calculating sentiment took 201.07 seconds\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"# Add a negative sentiment and positive sentiment column\n",
|
||||
"print(\"Calculating sentiment columns for both positive and negative reviews\")\n",
|
||||
"start = time.time()\n",
|
||||
"df[\"Negative_Sentiment\"] = df.Negative_Review.apply(calc_sentiment)\n",
|
||||
"df[\"Positive_Sentiment\"] = df.Positive_Review.apply(calc_sentiment)\n",
|
||||
"end = time.time()\n",
|
||||
"print(\"Calculating sentiment took \" + str(round(end - start, 2)) + \" seconds\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
" Negative_Review Negative_Sentiment\n",
|
||||
"186584 So bad experience memories I hotel The first n... -0.9920\n",
|
||||
"129503 First charged twice room booked booking second... -0.9896\n",
|
||||
"307286 The staff Had bad experience even booking Janu... -0.9889\n",
|
||||
"452092 No WLAN room Incredibly rude restaurant staff ... -0.9884\n",
|
||||
"201293 We usually traveling Paris 2 3 times year busi... -0.9873\n",
|
||||
"... ... ...\n",
|
||||
"26899 I would say however one night expensive even d... 0.9933\n",
|
||||
"138365 Wifi terribly slow I speed test network upload... 0.9938\n",
|
||||
"79215 I find anything hotel first I walked past hote... 0.9938\n",
|
||||
"278506 The property great location There bakery next ... 0.9945\n",
|
||||
"339189 Guys I like hotel I wish return next year Howe... 0.9948\n",
|
||||
"\n",
|
||||
"[515738 rows x 2 columns]\n",
|
||||
" Positive_Review Positive_Sentiment\n",
|
||||
"137893 Bathroom Shower We going stay twice hotel 2 ni... -0.9820\n",
|
||||
"5839 I completely disappointed mad since reception ... -0.9780\n",
|
||||
"64158 get everything extra internet parking breakfas... -0.9751\n",
|
||||
"124178 I didnt like anythig Room small Asked upgrade ... -0.9721\n",
|
||||
"489137 Very rude manager abusive staff reception Dirt... -0.9703\n",
|
||||
"... ... ...\n",
|
||||
"331570 Everything This recently renovated hotel class... 0.9984\n",
|
||||
"322920 From moment stepped doors Guesthouse Hotel sta... 0.9985\n",
|
||||
"293710 This place surprise expected good actually gre... 0.9985\n",
|
||||
"417442 We celebrated wedding night Langham I commend ... 0.9985\n",
|
||||
"132492 We arrived super cute boutique hotel area expl... 0.9987\n",
|
||||
"\n",
|
||||
"[515738 rows x 2 columns]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"df = df.sort_values(by=[\"Negative_Sentiment\"], ascending=True)\n",
|
||||
"print(df[[\"Negative_Review\", \"Negative_Sentiment\"]])\n",
|
||||
"df = df.sort_values(by=[\"Positive_Sentiment\"], ascending=True)\n",
|
||||
"print(df[[\"Positive_Review\", \"Positive_Sentiment\"]])\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Reorder the columns (This is cosmetic, but to make it easier to explore the data later)\n",
|
||||
"df = df.reindex([\"Hotel_Name\", \"Hotel_Address\", \"Total_Number_of_Reviews\", \"Average_Score\", \"Reviewer_Score\", \"Negative_Sentiment\", \"Positive_Sentiment\", \"Reviewer_Nationality\", \"Leisure_trip\", \"Couple\", \"Solo_traveler\", \"Business_trip\", \"Group\", \"Family_with_young_children\", \"Family_with_older_children\", \"With_a_pet\", \"Negative_Review\", \"Positive_Review\"], axis=1)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Saving results to Hotel_Reviews_NLP.csv\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"print(\"Saving results to Hotel_Reviews_NLP.csv\")\n",
|
||||
"df.to_csv(r\"../../data/Hotel_Reviews_NLP.csv\", index = False)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"\n---\n\n**Aviso Legal**: \nEste documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante ter em conta que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.\n"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
@ -0,0 +1,29 @@
|
||||
# Introdução ao processamento de linguagem natural
|
||||
|
||||
O processamento de linguagem natural (PLN) é a capacidade de um programa de computador entender a linguagem humana tal como é falada e escrita — referida como linguagem natural. É um componente da inteligência artificial (IA). O PLN existe há mais de 50 anos e tem raízes no campo da linguística. Todo o campo é direcionado a ajudar as máquinas a compreender e processar a linguagem humana. Isso pode ser usado para realizar tarefas como correção ortográfica ou tradução automática. Tem uma variedade de aplicações no mundo real em diversos campos, incluindo pesquisa médica, motores de busca e inteligência empresarial.
|
||||
|
||||
## Tópico regional: Línguas e literatura europeias e hotéis românticos da Europa ❤️
|
||||
|
||||
Nesta seção do currículo, será introduzido um dos usos mais difundidos do aprendizado de máquina: o processamento de linguagem natural (PLN). Derivado da linguística computacional, esta categoria de inteligência artificial é a ponte entre humanos e máquinas através de comunicação por voz ou texto.
|
||||
|
||||
Nestes módulos, aprenderemos os fundamentos do PLN construindo pequenos bots conversacionais para entender como o aprendizado de máquina ajuda a tornar essas conversas cada vez mais 'inteligentes'. Você viajará no tempo, conversando com Elizabeth Bennett e Mr. Darcy do clássico romance de Jane Austen, **Orgulho e Preconceito**, publicado em 1813. Depois, aprofundará seus conhecimentos aprendendo sobre análise de sentimentos através de avaliações de hotéis na Europa.
|
||||
|
||||

|
||||
> Foto por <a href="https://unsplash.com/@elaineh?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Elaine Howlin</a> no <a href="https://unsplash.com/s/photos/pride-and-prejudice?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>
|
||||
|
||||
## Aulas
|
||||
|
||||
1. [Introdução ao processamento de linguagem natural](1-Introduction-to-NLP/README.md)
|
||||
2. [Tarefas e técnicas comuns de PLN](2-Tasks/README.md)
|
||||
3. [Tradução e análise de sentimentos com aprendizado de máquina](3-Translation-Sentiment/README.md)
|
||||
4. [Preparando os seus dados](4-Hotel-Reviews-1/README.md)
|
||||
5. [NLTK para análise de sentimentos](5-Hotel-Reviews-2/README.md)
|
||||
|
||||
## Créditos
|
||||
|
||||
Estas aulas de processamento de linguagem natural foram escritas com ☕ por [Stephen Howell](https://twitter.com/Howell_MSFT)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,6 @@
|
||||
Descarregue os dados de avaliação do hotel para esta pasta.
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, esteja ciente de que traduções automáticas podem conter erros ou imprecisões. O documento original no seu idioma nativo deve ser considerado a fonte oficial. Para informações críticas, recomenda-se uma tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas resultantes do uso desta tradução.
|
||||
@ -0,0 +1,190 @@
|
||||
# Introdução à previsão de séries temporais
|
||||
|
||||

|
||||
|
||||
> Sketchnote por [Tomomi Imura](https://www.twitter.com/girlie_mac)
|
||||
|
||||
Nesta lição e na próxima, vais aprender um pouco sobre previsão de séries temporais, uma parte interessante e valiosa do repertório de um cientista de ML que é um pouco menos conhecida do que outros tópicos. A previsão de séries temporais é como uma espécie de "bola de cristal": com base no desempenho passado de uma variável, como o preço, podes prever o seu valor potencial futuro.
|
||||
|
||||
[](https://youtu.be/cBojo1hsHiI "Introdução à previsão de séries temporais")
|
||||
|
||||
> 🎥 Clica na imagem acima para ver um vídeo sobre previsão de séries temporais
|
||||
|
||||
## [Questionário pré-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
É um campo útil e interessante com valor real para os negócios, dado a sua aplicação direta em problemas de preços, inventário e questões de cadeia de abastecimento. Embora técnicas de aprendizagem profunda tenham começado a ser usadas para obter mais insights e prever melhor o desempenho futuro, a previsão de séries temporais continua a ser um campo amplamente informado por técnicas clássicas de ML.
|
||||
|
||||
> O currículo útil de séries temporais da Penn State pode ser encontrado [aqui](https://online.stat.psu.edu/stat510/lesson/1)
|
||||
|
||||
## Introdução
|
||||
|
||||
Suponha que geres uma rede de parquímetros inteligentes que fornecem dados sobre a frequência e duração de uso ao longo do tempo.
|
||||
|
||||
> E se pudesses prever, com base no desempenho passado do parquímetro, o seu valor futuro de acordo com as leis de oferta e procura?
|
||||
|
||||
Prever com precisão quando agir para alcançar o teu objetivo é um desafio que pode ser abordado com previsão de séries temporais. Não seria agradável para as pessoas serem cobradas mais em horários de pico quando procuram um lugar para estacionar, mas seria uma forma eficaz de gerar receita para limpar as ruas!
|
||||
|
||||
Vamos explorar alguns dos tipos de algoritmos de séries temporais e começar um notebook para limpar e preparar alguns dados. Os dados que vais analisar foram retirados da competição de previsão GEFCom2014. Consistem em 3 anos de valores horários de carga elétrica e temperatura entre 2012 e 2014. Dado os padrões históricos de carga elétrica e temperatura, podes prever valores futuros de carga elétrica.
|
||||
|
||||
Neste exemplo, vais aprender a prever um passo temporal à frente, usando apenas dados históricos de carga. Antes de começar, no entanto, é útil entender o que está a acontecer nos bastidores.
|
||||
|
||||
## Algumas definições
|
||||
|
||||
Ao encontrar o termo "séries temporais", precisas de entender o seu uso em vários contextos diferentes.
|
||||
|
||||
🎓 **Séries temporais**
|
||||
|
||||
Em matemática, "uma série temporal é uma série de pontos de dados indexados (ou listados ou representados graficamente) em ordem temporal. Mais comumente, uma série temporal é uma sequência tomada em pontos sucessivos igualmente espaçados no tempo." Um exemplo de série temporal é o valor de fecho diário do [Dow Jones Industrial Average](https://wikipedia.org/wiki/Time_series). O uso de gráficos de séries temporais e modelagem estatística é frequentemente encontrado em processamento de sinais, previsão do tempo, previsão de terremotos e outros campos onde eventos ocorrem e pontos de dados podem ser representados ao longo do tempo.
|
||||
|
||||
🎓 **Análise de séries temporais**
|
||||
|
||||
A análise de séries temporais é a análise dos dados de séries temporais mencionados acima. Os dados de séries temporais podem assumir formas distintas, incluindo "séries temporais interrompidas", que detectam padrões na evolução de uma série temporal antes e depois de um evento interruptor. O tipo de análise necessário para a série temporal depende da natureza dos dados. Os dados de séries temporais podem assumir a forma de séries de números ou caracteres.
|
||||
|
||||
A análise a ser realizada utiliza uma variedade de métodos, incluindo domínio de frequência e domínio temporal, linear e não linear, entre outros. [Saiba mais](https://www.itl.nist.gov/div898/handbook/pmc/section4/pmc4.htm) sobre as várias formas de analisar este tipo de dados.
|
||||
|
||||
🎓 **Previsão de séries temporais**
|
||||
|
||||
A previsão de séries temporais é o uso de um modelo para prever valores futuros com base em padrões exibidos por dados previamente recolhidos à medida que ocorreram no passado. Embora seja possível usar modelos de regressão para explorar dados de séries temporais, com índices temporais como variáveis x num gráfico, esses dados são melhor analisados usando tipos especiais de modelos.
|
||||
|
||||
Os dados de séries temporais são uma lista de observações ordenadas, diferente de dados que podem ser analisados por regressão linear. O mais comum é o ARIMA, um acrónimo que significa "Autoregressive Integrated Moving Average".
|
||||
|
||||
[Modelos ARIMA](https://online.stat.psu.edu/stat510/lesson/1/1.1) "relacionam o valor presente de uma série com valores passados e erros de previsão passados." Eles são mais apropriados para analisar dados no domínio temporal, onde os dados são ordenados ao longo do tempo.
|
||||
|
||||
> Existem vários tipos de modelos ARIMA, sobre os quais podes aprender [aqui](https://people.duke.edu/~rnau/411arim.htm) e que vais abordar na próxima lição.
|
||||
|
||||
Na próxima lição, vais construir um modelo ARIMA usando [Séries Temporais Univariadas](https://itl.nist.gov/div898/handbook/pmc/section4/pmc44.htm), que se concentram numa variável que muda o seu valor ao longo do tempo. Um exemplo deste tipo de dados é [este conjunto de dados](https://itl.nist.gov/div898/handbook/pmc/section4/pmc4411.htm) que regista a concentração mensal de CO2 no Observatório Mauna Loa:
|
||||
|
||||
| CO2 | YearMonth | Year | Month |
|
||||
| :-----: | :-------: | :---: | :---: |
|
||||
| 330.62 | 1975.04 | 1975 | 1 |
|
||||
| 331.40 | 1975.13 | 1975 | 2 |
|
||||
| 331.87 | 1975.21 | 1975 | 3 |
|
||||
| 333.18 | 1975.29 | 1975 | 4 |
|
||||
| 333.92 | 1975.38 | 1975 | 5 |
|
||||
| 333.43 | 1975.46 | 1975 | 6 |
|
||||
| 331.85 | 1975.54 | 1975 | 7 |
|
||||
| 330.01 | 1975.63 | 1975 | 8 |
|
||||
| 328.51 | 1975.71 | 1975 | 9 |
|
||||
| 328.41 | 1975.79 | 1975 | 10 |
|
||||
| 329.25 | 1975.88 | 1975 | 11 |
|
||||
| 330.97 | 1975.96 | 1975 | 12 |
|
||||
|
||||
✅ Identifica a variável que muda ao longo do tempo neste conjunto de dados.
|
||||
|
||||
## Características dos dados de séries temporais a considerar
|
||||
|
||||
Ao observar dados de séries temporais, podes notar que eles possuem [certas características](https://online.stat.psu.edu/stat510/lesson/1/1.1) que precisas levar em conta e mitigar para entender melhor os seus padrões. Se considerares os dados de séries temporais como potencialmente fornecendo um "sinal" que desejas analisar, essas características podem ser vistas como "ruído". Muitas vezes, será necessário reduzir esse "ruído" compensando algumas dessas características usando técnicas estatísticas.
|
||||
|
||||
Aqui estão alguns conceitos que deves conhecer para trabalhar com séries temporais:
|
||||
|
||||
🎓 **Tendências**
|
||||
|
||||
Tendências são definidas como aumentos e diminuições mensuráveis ao longo do tempo. [Lê mais](https://machinelearningmastery.com/time-series-trends-in-python). No contexto de séries temporais, trata-se de como usar e, se necessário, remover tendências da tua série temporal.
|
||||
|
||||
🎓 **[Sazonalidade](https://machinelearningmastery.com/time-series-seasonality-with-python/)**
|
||||
|
||||
Sazonalidade é definida como flutuações periódicas, como picos de vendas durante as férias, por exemplo. [Dá uma olhada](https://itl.nist.gov/div898/handbook/pmc/section4/pmc443.htm) em como diferentes tipos de gráficos exibem sazonalidade nos dados.
|
||||
|
||||
🎓 **Outliers**
|
||||
|
||||
Outliers são valores que estão muito distantes da variância padrão dos dados.
|
||||
|
||||
🎓 **Ciclo de longo prazo**
|
||||
|
||||
Independentemente da sazonalidade, os dados podem exibir um ciclo de longo prazo, como uma recessão económica que dura mais de um ano.
|
||||
|
||||
🎓 **Variância constante**
|
||||
|
||||
Ao longo do tempo, alguns dados exibem flutuações constantes, como o uso de energia durante o dia e a noite.
|
||||
|
||||
🎓 **Mudanças abruptas**
|
||||
|
||||
Os dados podem exibir uma mudança abrupta que pode precisar de análise adicional. O encerramento repentino de negócios devido à COVID, por exemplo, causou mudanças nos dados.
|
||||
|
||||
✅ Aqui está um [exemplo de gráfico de séries temporais](https://www.kaggle.com/kashnitsky/topic-9-part-1-time-series-analysis-in-python) mostrando o gasto diário em moeda dentro de um jogo ao longo de alguns anos. Consegues identificar alguma das características listadas acima nesses dados?
|
||||
|
||||

|
||||
|
||||
## Exercício - começando com dados de uso de energia
|
||||
|
||||
Vamos começar a criar um modelo de séries temporais para prever o uso futuro de energia com base no uso passado.
|
||||
|
||||
> Os dados neste exemplo foram retirados da competição de previsão GEFCom2014. Consistem em 3 anos de valores horários de carga elétrica e temperatura entre 2012 e 2014.
|
||||
>
|
||||
> Tao Hong, Pierre Pinson, Shu Fan, Hamidreza Zareipour, Alberto Troccoli e Rob J. Hyndman, "Probabilistic energy forecasting: Global Energy Forecasting Competition 2014 and beyond", International Journal of Forecasting, vol.32, no.3, pp 896-913, julho-setembro, 2016.
|
||||
|
||||
1. Na pasta `working` desta lição, abre o ficheiro _notebook.ipynb_. Começa por adicionar bibliotecas que te ajudarão a carregar e visualizar os dados.
|
||||
|
||||
```python
|
||||
import os
|
||||
import matplotlib.pyplot as plt
|
||||
from common.utils import load_data
|
||||
%matplotlib inline
|
||||
```
|
||||
|
||||
Nota que estás a usar os ficheiros da pasta `common` incluída, que configuram o teu ambiente e tratam do download dos dados.
|
||||
|
||||
2. Em seguida, examina os dados como um dataframe chamando `load_data()` e `head()`:
|
||||
|
||||
```python
|
||||
data_dir = './data'
|
||||
energy = load_data(data_dir)[['load']]
|
||||
energy.head()
|
||||
```
|
||||
|
||||
Podes ver que há duas colunas representando data e carga:
|
||||
|
||||
| | load |
|
||||
| :-----------------: | :----: |
|
||||
| 2012-01-01 00:00:00 | 2698.0 |
|
||||
| 2012-01-01 01:00:00 | 2558.0 |
|
||||
| 2012-01-01 02:00:00 | 2444.0 |
|
||||
| 2012-01-01 03:00:00 | 2402.0 |
|
||||
| 2012-01-01 04:00:00 | 2403.0 |
|
||||
|
||||
3. Agora, representa os dados graficamente chamando `plot()`:
|
||||
|
||||
```python
|
||||
energy.plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
|
||||
plt.xlabel('timestamp', fontsize=12)
|
||||
plt.ylabel('load', fontsize=12)
|
||||
plt.show()
|
||||
```
|
||||
|
||||

|
||||
|
||||
4. Agora, representa graficamente a primeira semana de julho de 2014, fornecendo-a como entrada para o `energy` no padrão `[data inicial]:[data final]`:
|
||||
|
||||
```python
|
||||
energy['2014-07-01':'2014-07-07'].plot(y='load', subplots=True, figsize=(15, 8), fontsize=12)
|
||||
plt.xlabel('timestamp', fontsize=12)
|
||||
plt.ylabel('load', fontsize=12)
|
||||
plt.show()
|
||||
```
|
||||
|
||||

|
||||
|
||||
Um gráfico bonito! Dá uma olhada nesses gráficos e vê se consegues determinar alguma das características listadas acima. O que podemos concluir ao visualizar os dados?
|
||||
|
||||
Na próxima lição, vais criar um modelo ARIMA para fazer algumas previsões.
|
||||
|
||||
---
|
||||
|
||||
## 🚀Desafio
|
||||
|
||||
Faz uma lista de todas as indústrias e áreas de estudo que consegues pensar que poderiam beneficiar da previsão de séries temporais. Consegues pensar numa aplicação dessas técnicas nas artes? Em Econometria? Ecologia? Retalho? Indústria? Finanças? Onde mais?
|
||||
|
||||
## [Questionário pós-aula](https://ff-quizzes.netlify.app/en/ml/)
|
||||
|
||||
## Revisão & Autoestudo
|
||||
|
||||
Embora não os abordemos aqui, redes neurais são por vezes usadas para melhorar os métodos clássicos de previsão de séries temporais. Lê mais sobre isso [neste artigo](https://medium.com/microsoftazure/neural-networks-for-forecasting-financial-and-economic-time-series-6aca370ff412)
|
||||
|
||||
## Tarefa
|
||||
|
||||
[Visualiza mais séries temporais](assignment.md)
|
||||
|
||||
---
|
||||
|
||||
**Aviso Legal**:
|
||||
Este documento foi traduzido utilizando o serviço de tradução por IA [Co-op Translator](https://github.com/Azure/co-op-translator). Embora nos esforcemos para garantir a precisão, é importante notar que traduções automáticas podem conter erros ou imprecisões. O documento original na sua língua nativa deve ser considerado a fonte autoritária. Para informações críticas, recomenda-se a tradução profissional realizada por humanos. Não nos responsabilizamos por quaisquer mal-entendidos ou interpretações incorretas decorrentes da utilização desta tradução.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue