[{"content":"Agente que replica o design e a estrutura de qualquer site público em código HTML/CSS. Ideal para quem quer usar um layout existente como ponto de partida sem começar do zero. O agente analisa a página, extrai os componentes visuais e gera um template funcional e editável.\n","externalUrl":"https://github.com/JCodesMore/ai-website-cloner-template","permalink":"/agentic/criacao-conteudo-design/ai-website-cloner/","section":"Agentic AI","summary":"Agente que replica o design e a estrutura de qualquer site público em código HTML/CSS. Ideal para quem quer usar um layout existente como ponto de partida sem começar do zero. O agente analisa a página, extrai os componentes visuais e gera um template funcional e editável.\n","title":"AI Website Cloner","type":"agentic"},{"content":"Comprime a comunicação ao extremo pra gastar menos tokens.\nComplemento: Para comprimir o que entra no LLM (saída de tools, logs, chunks de RAG), veja o Headroom — os dois juntos cobrem os dois lados do pipeline de tokens.\n","externalUrl":"https://github.com/juliusbrussee/caveman","permalink":"/agentic/contexto-tokens-custos/caveman/","section":"Agentic AI","summary":"Comprime a comunicação ao extremo pra gastar menos tokens.\nComplemento: Para comprimir o que entra no LLM (saída de tools, logs, chunks de RAG), veja o Headroom — os dois juntos cobrem os dois lados do pipeline de tokens.\n","title":"Caveman","type":"agentic"},{"content":"Skill que transforma o Claude Code em um assistente de blog completo. A partir de um briefing ou conjunto de notas, gera o rascunho do post, aplica a formatação do template do blog e organiza o frontmatter de SEO. Permite que o autor foque no conteúdo e na revisão, delegando a estruturação e a publicação inicial ao agente.\n","externalUrl":"https://github.com/AgriciDaniel/claude-blog","permalink":"/agentic/criacao-conteudo-design/claude-blog/","section":"Agentic AI","summary":"Skill que transforma o Claude Code em um assistente de blog completo. A partir de um briefing ou conjunto de notas, gera o rascunho do post, aplica a formatação do template do blog e organiza o frontmatter de SEO. Permite que o autor foque no conteúdo e na revisão, delegando a estruturação e a publicação inicial ao agente.\n","title":"Claude Blog","type":"agentic"},{"content":"Servidor MCP que analisa um repositório e constrói um grafo de dependências entre arquivos, funções e módulos. Disponibiliza esse contexto estrutural para o LLM durante revisões de código, permitindo sugestões mais fundamentadas e alinhadas à arquitetura real do projeto. Útil em codebases grandes onde o LLM precisa de contexto além do arquivo atual.\nFundamentos de teoria dos grafos aplicados: Grafos bonitos em R.\nVer também: O Graphify resolve o mesmo problema de forma diferente — gera uma representação compacta standalone do codebase em vez de expor o grafo via MCP.\n","externalUrl":"https://github.com/tirth8205/code-review-graph","permalink":"/agentic/desenvolvimento-automacao-ia/code-review-graph/","section":"Agentic AI","summary":"Servidor MCP que analisa um repositório e constrói um grafo de dependências entre arquivos, funções e módulos. Disponibiliza esse contexto estrutural para o LLM durante revisões de código, permitindo sugestões mais fundamentadas e alinhadas à arquitetura real do projeto. Útil em codebases grandes onde o LLM precisa de contexto além do arquivo atual.\nFundamentos de teoria dos grafos aplicados: Grafos bonitos em R.\nVer também: O Graphify resolve o mesmo problema de forma diferente — gera uma representação compacta standalone do codebase em vez de expor o grafo via MCP.\n","title":"Code Review Graph","type":"agentic"},{"content":"Servidor MCP para gerenciamento de contexto entre sessões de agentes. Isola o estado de cada tarefa para evitar que informações de sessões anteriores contaminem a conversa atual, reduzindo tokens desnecessários e melhorando a precisão das respostas. Especialmente útil em fluxos com múltiplos agentes ou tarefas encadeadas que compartilham o mesmo modelo.\n","externalUrl":"https://github.com/mksglu/context-mode","permalink":"/agentic/contexto-tokens-custos/context-mode/","section":"Agentic AI","summary":"Servidor MCP para gerenciamento de contexto entre sessões de agentes. Isola o estado de cada tarefa para evitar que informações de sessões anteriores contaminem a conversa atual, reduzindo tokens desnecessários e melhorando a precisão das respostas. Especialmente útil em fluxos com múltiplos agentes ou tarefas encadeadas que compartilham o mesmo modelo.\n","title":"Context Mode","type":"agentic"},{"content":"Servidor MCP mantido pela Upstash que resolve um dos problemas mais comuns com agentes de código: o LLM sugerir métodos removidos ou renomeados em versões recentes de uma biblioteca. O Context7 intercepta a chamada, busca a documentação oficial e versionada da lib em questão e a injeta diretamente no contexto — sem precisar colar docs no chat manualmente.\nComplementa o Code Review Graph na cobertura de contexto: enquanto o Graph fornece a estrutura interna do projeto, o Context7 fornece o contrato externo das dependências.\nVer também: Para pré-processar documentos e convertê-los em documentação estruturada antes de injetá-los como contexto, veja o MinerU.\n","externalUrl":"https://github.com/upstash/context7","permalink":"/agentic/desenvolvimento-automacao-ia/context7/","section":"Agentic AI","summary":"Servidor MCP mantido pela Upstash que resolve um dos problemas mais comuns com agentes de código: o LLM sugerir métodos removidos ou renomeados em versões recentes de uma biblioteca. O Context7 intercepta a chamada, busca a documentação oficial e versionada da lib em questão e a injeta diretamente no contexto — sem precisar colar docs no chat manualmente.\nComplementa o Code Review Graph na cobertura de contexto: enquanto o Graph fornece a estrutura interna do projeto, o Context7 fornece o contrato externo das dependências.\n","title":"Context7","type":"agentic"},{"content":"Em vez de alimentar o LLM com arquivos inteiros para ele entender a estrutura do projeto, o Graphify representa o codebase como um grafo de conhecimento — nós são arquivos, funções e módulos; arestas são dependências, chamadas e importações. O LLM consulta o grafo para localizar o contexto relevante sem ler código desnecessário, reduzindo drasticamente os tokens consumidos em tarefas de navegação e entendimento de código.\nDiferente do Code Review Graph — que expõe o grafo via MCP para o LLM consultar durante revisões de código — o Graphify é uma ferramenta standalone: você o executa para gerar uma representação compacta do projeto que cabe no contexto, substituindo a leitura de arquivos brutos.\n","externalUrl":"https://github.com/Graphify-Labs/graphify","permalink":"/agentic/documentos-conhecimento/graphify/","section":"Agentic AI","summary":"Em vez de alimentar o LLM com arquivos inteiros para ele entender a estrutura do projeto, o Graphify representa o codebase como um grafo de conhecimento — nós são arquivos, funções e módulos; arestas são dependências, chamadas e importações. O LLM consulta o grafo para localizar o contexto relevante sem ler código desnecessário, reduzindo drasticamente os tokens consumidos em tarefas de navegação e entendimento de código.\nDiferente do Code Review Graph — que expõe o grafo via MCP para o LLM consultar durante revisões de código — o Graphify é uma ferramenta standalone: você o executa para gerar uma representação compacta do projeto que cabe no contexto, substituindo a leitura de arquivos brutos.\n","title":"Graphify","type":"agentic"},{"content":"Ferramenta open source de extração de documentos para uso em pipelines de IA. Converte PDFs complexos (com tabelas, fórmulas e layouts mistos) e arquivos do Office em markdown ou JSON limpo e estruturado. Muito útil como etapa de pré-processamento antes de indexar documentos em uma base vetorial ou alimentar um agente com conhecimento corporativo.\nVer também: O wiki-llm usa exatamente este tipo de output como entrada para montar uma wiki com RAG sobre os documentos convertidos.\n","externalUrl":"https://github.com/opendatalab/MinerU","permalink":"/agentic/documentos-conhecimento/mineru/","section":"Agentic AI","summary":"Ferramenta open source de extração de documentos para uso em pipelines de IA. Converte PDFs complexos (com tabelas, fórmulas e layouts mistos) e arquivos do Office em markdown ou JSON limpo e estruturado. Muito útil como etapa de pré-processamento antes de indexar documentos em uma base vetorial ou alimentar um agente com conhecimento corporativo.\nVer também: O wiki-llm usa exatamente este tipo de output como entrada para montar uma wiki com RAG sobre os documentos convertidos.\n","title":"MinerU","type":"agentic"},{"content":"Utilitário Windows que cria um espelho em tempo real de qualquer janela do sistema em um painel flutuante e sempre visível (always-on-top). Não usa IA, mas é uma ferramenta de produtividade valiosa para quem monitora múltiplas saídas ao mesmo tempo — como terminais de agentes, dashboards e logs — sem precisar alternar entre janelas. Compatível com Windows 10/11.\n","externalUrl":"https://github.com/LorenzCK/OnTopReplica","permalink":"/agentic/produtividade-utilitarios-desktop/ontopreplica/","section":"Agentic AI","summary":"Utilitário Windows que cria um espelho em tempo real de qualquer janela do sistema em um painel flutuante e sempre visível (always-on-top). Não usa IA, mas é uma ferramenta de produtividade valiosa para quem monitora múltiplas saídas ao mesmo tempo — como terminais de agentes, dashboards e logs — sem precisar alternar entre janelas. Compatível com Windows 10/11.\n","title":"OnTopReplica","type":"agentic"},{"content":"Ferramenta que automatiza a produção de vídeos curtos a partir de um roteiro em texto. O pipeline combina geração de imagens com IA, narração por text-to-speech e montagem automática de cenas. Ideal para criar vídeos explicativos, shorts e conteúdo de redes sociais sem precisar editar manualmente.\nVer também: O Voicebox resolve a parte da narração de forma isolada: clona uma voz e gera o áudio que entra como narração em vídeo no pipeline do OpenMontage.\n","externalUrl":"https://github.com/calesthio/OpenMontage","permalink":"/agentic/criacao-conteudo-design/openmontage/","section":"Agentic AI","summary":"Ferramenta que automatiza a produção de vídeos curtos a partir de um roteiro em texto. O pipeline combina geração de imagens com IA, narração por text-to-speech e montagem automática de cenas. Ideal para criar vídeos explicativos, shorts e conteúdo de redes sociais sem precisar editar manualmente.\nVer também: O Voicebox resolve a parte da narração de forma isolada: clona uma voz e gera o áudio que entra como narração em vídeo no pipeline do OpenMontage.\n","title":"OpenMontage","type":"agentic"},{"content":"Skill focada em simplificação radical de código. Aplica o princípio YAGNI de forma agressiva: remove abstrações prematuras, questiona cada nova dependência e refatora código existente para a solução mais simples que funciona. Complementa o honey-for-devs com um foco específico em redução de complexidade acumulada no codebase.\nVer também: O Improve é o passo anterior natural: audita o codebase e gera um plano priorizado antes de qualquer refatoração.\n","externalUrl":"https://github.com/DietrichGebert/ponytail","permalink":"/agentic/desenvolvimento-automacao-ia/ponytail/","section":"Agentic AI","summary":"Skill focada em simplificação radical de código. Aplica o princípio YAGNI de forma agressiva: remove abstrações prematuras, questiona cada nova dependência e refatora código existente para a solução mais simples que funciona. Complementa o honey-for-devs com um foco específico em redução de complexidade acumulada no codebase.\nVer também: O Improve é o passo anterior natural: audita o codebase e gera um plano priorizado antes de qualquer refatoração.\n","title":"Ponytail","type":"agentic"},{"content":"CLI que exibe o consumo de tokens e o custo acumulado de sessões do Claude Code diretamente no terminal. Apresenta breakdown por modelo, projeto e intervalo de tempo, facilitando o controle de gastos em fluxos de trabalho agentic intensivos. Essencial para quem usa Claude Code com frequência e quer visibilidade de custo sem acessar o painel da Anthropic.\nVeja arquitetura multiagente em prática: Equipe de agentes de IA para análise do Bitcoin.\nVer também: Para monitorar o status de sessões paralelas do Claude Code (não o custo), veja o Vantage — os dois juntos cobrem observabilidade completa.\n","externalUrl":"https://github.com/ccusage/ccusage","permalink":"/agentic/contexto-tokens-custos/ccusage/","section":"Agentic AI","summary":"CLI que exibe o consumo de tokens e o custo acumulado de sessões do Claude Code diretamente no terminal. Apresenta breakdown por modelo, projeto e intervalo de tempo, facilitando o controle de gastos em fluxos de trabalho agentic intensivos. Essencial para quem usa Claude Code com frequência e quer visibilidade de custo sem acessar o painel da Anthropic.\nVeja arquitetura multiagente em prática: Equipe de agentes de IA para análise do Bitcoin.\n","title":"ccusage","type":"agentic"},{"content":"Skill que permite ao Claude Code criar diagramas de arquitetura, fluxos e organogramas em formato Draw.io diretamente a partir de uma descrição textual. Gera o arquivo .drawio/.xml que pode ser aberto e editado na ferramenta normalmente. Ideal para documentar arquiteturas de sistemas, fluxos de dados e pipelines sem sair do terminal.\n","externalUrl":"https://github.com/Agents365-ai/drawio-skill","permalink":"/agentic/criacao-conteudo-design/drawio-skill/","section":"Agentic AI","summary":"Skill que permite ao Claude Code criar diagramas de arquitetura, fluxos e organogramas em formato Draw.io diretamente a partir de uma descrição textual. Gera o arquivo .drawio/.xml que pode ser aberto e editado na ferramenta normalmente. Ideal para documentar arquiteturas de sistemas, fluxos de dados e pipelines sem sair do terminal.\n","title":"Draw.io","type":"agentic"},{"content":"Servidor MCP desenvolvido em parceria pela Anthropic e GitHub. Dá ao agente acesso completo à API do GitHub com escopo controlado por token pessoal: abre e revisa pull requests, cria e fecha issues, lê logs do GitHub Actions, busca código em repositórios e inspeciona o histórico de commits.\nFecha o loop do workflow agêntico de desenvolvimento: o agente escreve o código, abre o PR, monitora a CI e corrige o que falhou — tudo sem sair do terminal.\nVer também: Para enriquecer revisões com o contexto estrutural do repositório, veja o Code Review Graph — mapeia dependências entre arquivos e módulos e expõe o grafo para o LLM.\n","externalUrl":"https://github.com/github/github-mcp-server","permalink":"/agentic/desenvolvimento-automacao-ia/github-mcp/","section":"Agentic AI","summary":"Servidor MCP desenvolvido em parceria pela Anthropic e GitHub. Dá ao agente acesso completo à API do GitHub com escopo controlado por token pessoal: abre e revisa pull requests, cria e fecha issues, lê logs do GitHub Actions, busca código em repositórios e inspeciona o histórico de commits.\nFecha o loop do workflow agêntico de desenvolvimento: o agente escreve o código, abre o PR, monitora a CI e corrige o que falhou — tudo sem sair do terminal.\n","title":"GitHub MCP","type":"agentic"},{"content":"Comprime saída de ferramentas, logs e chunks de RAG antes de chegar no LLM (60-95% menos tokens, mesma resposta).\nComplemento: Se o objetivo é também comprimir as respostas do LLM (não só a entrada), veja o Caveman — os dois juntos cobrem os dois lados do pipeline de tokens.\n","externalUrl":"https://github.com/headroomlabs-ai/headroom","permalink":"/agentic/contexto-tokens-custos/headroom/","section":"Agentic AI","summary":"Comprime saída de ferramentas, logs e chunks de RAG antes de chegar no LLM (60-95% menos tokens, mesma resposta).\nComplemento: Se o objetivo é também comprimir as respostas do LLM (não só a entrada), veja o Caveman — os dois juntos cobrem os dois lados do pipeline de tokens.\n","title":"Headroom","type":"agentic"},{"content":"Skill que pós-processa textos gerados por LLMs para soar como escrita humana natural em inglês. Remove padrões típicos de AI-speak — listas excessivas, frases genéricas, tom corporativo — e substitui por construções mais diretas, variadas e com personalidade. Útil antes de publicar qualquer conteúdo gerado por IA em blog, email ou redes sociais.\nVersão em português: O Humanizer PT-BR aplica o mesmo processo para textos em português do Brasil.\n","externalUrl":"https://github.com/jpeggdev/humanize-writing","permalink":"/agentic/criacao-conteudo-design/humanize-writing/","section":"Agentic AI","summary":"Skill que pós-processa textos gerados por LLMs para soar como escrita humana natural em inglês. Remove padrões típicos de AI-speak — listas excessivas, frases genéricas, tom corporativo — e substitui por construções mais diretas, variadas e com personalidade. Útil antes de publicar qualquer conteúdo gerado por IA em blog, email ou redes sociais.\nVersão em português: O Humanizer PT-BR aplica o mesmo processo para textos em português do Brasil.\n","title":"Humanize Writing","type":"agentic"},{"content":"Skill de planejamento que instrui o Claude Code a primeiro auditar o estado atual do codebase — identificando dívidas técnicas, inconsistências e oportunidades de simplificação — e só então propor um plano de ação priorizado. Evita que o agente comece a refatorar sem visão do conjunto, resultando em mudanças mais coesas e com maior impacto real.\nVer também: O Ponytail complementa o Improve na execução: enquanto o Improve planeja o que melhorar, o Ponytail aplica YAGNI radical para remover o que não deveria existir.\n","externalUrl":"https://github.com/shadcn/improve","permalink":"/agentic/desenvolvimento-automacao-ia/improve/","section":"Agentic AI","summary":"Skill de planejamento que instrui o Claude Code a primeiro auditar o estado atual do codebase — identificando dívidas técnicas, inconsistências e oportunidades de simplificação — e só então propor um plano de ação priorizado. Evita que o agente comece a refatorar sem visão do conjunto, resultando em mudanças mais coesas e com maior impacto real.\nVer também: O Ponytail complementa o Improve na execução: enquanto o Improve planeja o que melhorar, o Ponytail aplica YAGNI radical para remover o que não deveria existir.\n","title":"Improve","type":"agentic"},{"content":"Skill que transforma o Claude Code em um parceiro de brainstorming estruturado. Dado um problema ou ideia, o agente gera múltiplas abordagens possíveis, avalia os trade-offs de cada uma e recomenda o caminho mais promissor com justificativa clara. Útil antes de iniciar qualquer implementação não trivial onde a direção ainda não está definida.\n","externalUrl":"https://github.com/obra/superpowers","permalink":"/agentic/desenvolvimento-automacao-ia/superpowers/","section":"Agentic AI","summary":"Skill que transforma o Claude Code em um parceiro de brainstorming estruturado. Dado um problema ou ideia, o agente gera múltiplas abordagens possíveis, avalia os trade-offs de cada uma e recomenda o caminho mais promissor com justificativa clara. Útil antes de iniciar qualquer implementação não trivial onde a direção ainda não está definida.\n","title":"Superpowers","type":"agentic"},{"content":"Solução de OCR (reconhecimento óptico de caracteres) baseada em modelos de visão e linguagem (VLM). Extrai texto de imagens, PDFs escaneados e documentos com layouts complexos com alta precisão e sem restrições de volume. Roda localmente, sem enviar documentos para serviços externos — ideal para documentos sensíveis ou fluxos com grande volume de páginas.\nVer também: Para documentos digitais nativos (PDFs não escaneados, Word, Excel), o MinerU oferece extração mais estruturada com suporte a tabelas e fórmulas.\n","externalUrl":"https://github.com/baidu/Unlimited-OCR","permalink":"/agentic/documentos-conhecimento/unlimited-ocr/","section":"Agentic AI","summary":"Solução de OCR (reconhecimento óptico de caracteres) baseada em modelos de visão e linguagem (VLM). Extrai texto de imagens, PDFs escaneados e documentos com layouts complexos com alta precisão e sem restrições de volume. Roda localmente, sem enviar documentos para serviços externos — ideal para documentos sensíveis ou fluxos com grande volume de páginas.\nVer também: Para documentos digitais nativos (PDFs não escaneados, Word, Excel), o MinerU oferece extração mais estruturada com suporte a tabelas e fórmulas.\n","title":"Unlimited-OCR","type":"agentic"},{"content":"Menu bar do macOS que mostra, num relance, o status de várias sessões do Claude Code rodando em paralelo.\nVer também: O ccusage complementa o Vantage mostrando o consumo de tokens e custo acumulado de cada sessão — juntos cobrem observabilidade completa do Claude Code.\n","externalUrl":"https://github.com/ibrahimyaacob92/vantage","permalink":"/agentic/produtividade-utilitarios-desktop/vantage/","section":"Agentic AI","summary":"Menu bar do macOS que mostra, num relance, o status de várias sessões do Claude Code rodando em paralelo.\nVer também: O ccusage complementa o Vantage mostrando o consumo de tokens e custo acumulado de cada sessão — juntos cobrem observabilidade completa do Claude Code.\n","title":"Vantage","type":"agentic"},{"content":"Estúdio de voz open source para geração e clonagem de áudio com IA. Permite clonar uma voz a partir de poucos segundos de áudio, ditar texto em voz natural e exportar narrações em alta qualidade. Útil para criadores de conteúdo, desenvolvedores de agentes de voz e quem quer produzir audiobooks ou tutoriais narrados sem depender de APIs pagas.\nTutorial relacionado: Audiobooks com IA — de PDF ao áudio com edge-tts.\n","externalUrl":"https://github.com/jamiepine/voicebox","permalink":"/agentic/criacao-conteudo-design/voicebox/","section":"Agentic AI","summary":"Estúdio de voz open source para geração e clonagem de áudio com IA. Permite clonar uma voz a partir de poucos segundos de áudio, ditar texto em voz natural e exportar narrações em alta qualidade. Útil para criadores de conteúdo, desenvolvedores de agentes de voz e quem quer produzir audiobooks ou tutoriais narrados sem depender de APIs pagas.\nTutorial relacionado: Audiobooks com IA — de PDF ao áudio com edge-tts.\n","title":"Voicebox","type":"agentic"},{"content":"Ferramenta de linha de comando que converte uma coleção de documentos locais em uma wiki navegável e consultável. O LLM resume cada página, organiza a taxonomia automaticamente e expõe um chat com RAG por cima. Ideal para equipes que querem criar uma base de conhecimento interna consultável por linguagem natural sem enviar dados para a nuvem.\nVeja como usar um LLM local como backend em LLM local com Qwen e LangChain.\nVer também: O MinerU converte PDFs e documentos do Office em markdown estruturado — formato ideal para alimentar o pipeline de indexação do wiki-llm.\n","externalUrl":"https://github.com/LeoBR84p/wiki_llm","permalink":"/agentic/documentos-conhecimento/wiki-llm/","section":"Agentic AI","summary":"Ferramenta de linha de comando que converte uma coleção de documentos locais em uma wiki navegável e consultável. O LLM resume cada página, organiza a taxonomia automaticamente e expõe um chat com RAG por cima. Ideal para equipes que querem criar uma base de conhecimento interna consultável por linguagem natural sem enviar dados para a nuvem.\nVeja como usar um LLM local como backend em LLM local com Qwen e LangChain.\n","title":"wiki-llm","type":"agentic"},{"content":"Skill que instrui o Claude Code a seguir o princípio YAGNI (You Aren\u0026rsquo;t Gonna Need It) e a preferir APIs nativas e stdlib antes de introduzir dependências externas. Produz o menor código que resolve o problema e responde com mensagens curtas e diretas, sem filler nem hedging. Reduz tokens gerados e o tempo gasto revisando código desnecessário.\n","externalUrl":"https://github.com/Green-PT/honey-for-devs","permalink":"/agentic/contexto-tokens-custos/honey-for-devs/","section":"Agentic AI","summary":"Skill que instrui o Claude Code a seguir o princípio YAGNI (You Aren’t Gonna Need It) e a preferir APIs nativas e stdlib antes de introduzir dependências externas. Produz o menor código que resolve o problema e responde com mensagens curtas e diretas, sem filler nem hedging. Reduz tokens gerados e o tempo gasto revisando código desnecessário.\n","title":"Honey for Devs","type":"agentic"},{"content":"Versão em português brasileiro da skill de humanização de escrita. Reescreve textos gerados por LLMs para soar natural em pt-BR, eliminando padrões típicos de AI-speak como listas excessivas, tom genérico e formalidade artificial. Especialmente útil para posts de blog, redes sociais e comunicações profissionais que precisam soar autênticos.\nTutorial sobre NLP em português com LLM: Detecção de Linguagem Tóxica com Gemma e LangChain.\nVersão em inglês: O Humanize Writing aplica o mesmo processo para textos em inglês.\n","externalUrl":"https://github.com/mackswendhell/humanizer-pt-br","permalink":"/agentic/criacao-conteudo-design/humanizer-pt-br/","section":"Agentic AI","summary":"Versão em português brasileiro da skill de humanização de escrita. Reescreve textos gerados por LLMs para soar natural em pt-BR, eliminando padrões típicos de AI-speak como listas excessivas, tom genérico e formalidade artificial. Especialmente útil para posts de blog, redes sociais e comunicações profissionais que precisam soar autênticos.\nTutorial sobre NLP em português com LLM: Detecção de Linguagem Tóxica com Gemma e LangChain.\nVersão em inglês: O Humanize Writing aplica o mesmo processo para textos em inglês.\n","title":"Humanizer PT-BR","type":"agentic"},{"content":"Servidor MCP oficial da Microsoft que expõe o Playwright para agentes de IA via accessibility tree — não via seletores CSS ou XPath, que quebram a cada redesign. O agente enxerga a página como um leitor de tela: botões, campos, links e seus rótulos semânticos. Permite navegar, interagir com formulários, tirar screenshots e verificar se uma mudança de UI foi aplicada corretamente.\nÚtil para agentes que precisam validar deploys na ponta, preencher sistemas legados sem API ou executar testes de aceitação visual sem sair do terminal.\nVer também: O AI Website Cloner usa automação web com objetivo específico: analisa uma página pública e gera um template HTML/CSS editável do design.\n","externalUrl":"https://github.com/microsoft/playwright-mcp","permalink":"/agentic/desenvolvimento-automacao-ia/playwright-mcp/","section":"Agentic AI","summary":"Servidor MCP oficial da Microsoft que expõe o Playwright para agentes de IA via accessibility tree — não via seletores CSS ou XPath, que quebram a cada redesign. O agente enxerga a página como um leitor de tela: botões, campos, links e seus rótulos semânticos. Permite navegar, interagir com formulários, tirar screenshots e verificar se uma mudança de UI foi aplicada corretamente.\nÚtil para agentes que precisam validar deploys na ponta, preencher sistemas legados sem API ou executar testes de aceitação visual sem sair do terminal.\n","title":"Playwright MCP","type":"agentic"},{"content":"RTK (Rust Token Killer) atua como proxy transparente entre o terminal e o AI assistant: intercepta a saída de comandos como git status, cargo test, ls e pacotes de cloud, filtra o ruído e entrega ao LLM apenas o essencial. O resultado são 60–90% menos tokens por operação, sem mudar nada no fluxo de trabalho.\nSuporta 100+ comandos e se integra via hooks nativos com Claude Code, Copilot e outros assistentes. Binário único em Rust, zero dependências.\nComplemento: Para comprimir o que sai do LLM (respostas verbosas), veja o Caveman. Para monitorar o custo acumulado, veja o CCUsage.\n","externalUrl":"https://github.com/rtk-ai/rtk","permalink":"/agentic/contexto-tokens-custos/rtk/","section":"Agentic AI","summary":"RTK (Rust Token Killer) atua como proxy transparente entre o terminal e o AI assistant: intercepta a saída de comandos como git status, cargo test, ls e pacotes de cloud, filtra o ruído e entrega ao LLM apenas o essencial. O resultado são 60–90% menos tokens por operação, sem mudar nada no fluxo de trabalho.\nSuporta 100+ comandos e se integra via hooks nativos com Claude Code, Copilot e outros assistentes. Binário único em Rust, zero dependências.\n","title":"RTK","type":"agentic"},{"content":"Skill que calibra o Claude Code para aplicar critérios subjetivos de qualidade de código — legibilidade, coerência com o estilo do projeto, ausência de over-engineering e naming consistente. Vai além da correção técnica: o objetivo é que o código gerado pareça escrito por um desenvolvedor experiente que conhece o projeto, não por um modelo genérico.\nVer também: O Honey for Devs complementa o Taste Skill aplicando YAGNI e stdlib-first — critério de qualidade sobre o que se adiciona, não só sobre o que já existe.\n","externalUrl":"https://github.com/leonxlnx/taste-skill","permalink":"/agentic/criacao-conteudo-design/taste-skill/","section":"Agentic AI","summary":"Skill que calibra o Claude Code para aplicar critérios subjetivos de qualidade de código — legibilidade, coerência com o estilo do projeto, ausência de over-engineering e naming consistente. Vai além da correção técnica: o objetivo é que o código gerado pareça escrito por um desenvolvedor experiente que conhece o projeto, não por um modelo genérico.\nVer também: O Honey for Devs complementa o Taste Skill aplicando YAGNI e stdlib-first — critério de qualidade sobre o que se adiciona, não só sobre o que já existe.\n","title":"Taste Skill","type":"agentic"},{"content":"Skill de otimização de contexto que instrui o Claude Code a identificar e eliminar ghost tokens — informações redundantes, instruções repetidas e contexto irrelevante que consomem espaço na janela sem contribuir para a resposta. Complementa ferramentas de compressão de input como Headroom e Caveman, atuando na curadoria ativa do que entra no prompt.\nVer também: Para isolar o contexto entre sessões e evitar acúmulo de tokens entre tarefas diferentes, veja o Context Mode — gestão de contexto no nível do servidor MCP.\n","externalUrl":"https://github.com/alexgreensh/token-optimizer","permalink":"/agentic/contexto-tokens-custos/token-optimizer/","section":"Agentic AI","summary":"Skill de otimização de contexto que instrui o Claude Code a identificar e eliminar ghost tokens — informações redundantes, instruções repetidas e contexto irrelevante que consomem espaço na janela sem contribuir para a resposta. Complementa ferramentas de compressão de input como Headroom e Caveman, atuando na curadoria ativa do que entra no prompt.\nVer também: Para isolar o contexto entre sessões e evitar acúmulo de tokens entre tarefas diferentes, veja o Context Mode — gestão de contexto no nível do servidor MCP.\n","title":"Token Optimizer","type":"agentic"},{"content":"","date":"17 de julho de 2026","externalUrl":null,"permalink":"/tags/ciencia-de-dados/","section":"Tags","summary":"","title":"Ciencia-De-Dados","type":"tags"},{"content":" IA \u0026amp; Assistente de Código Onde a IA entra de verdade no editor: assistente de código e controle do que eu gasto com ele.\nEssencial Claude Code\nAnthropic\nLê o projeto, edita arquivos e roda comandos sozinho, direto no terminal ou no editor. Uso pra quase tudo hoje.\nVer na Marketplace Claude Code Usage Tracker\nYahya Shareef\nMostra quanto eu já gastei de Claude Code direto na barra de status. Sem abrir outra aba pra descobrir a surpresa no fim do mês.\nVer na Marketplace Codex\nOpenAI\nO agente de código da OpenAI, direto no editor. Uso pra comparar com o Claude Code em tarefas do dia a dia.\nVer na Marketplace Python, R \u0026amp; Ciência de Dados A base do trabalho com dados, em Python e em R: notebooks, formatação automática e o que evita rodar script na mão.\nEssencial Python\nMicrosoft\nSuporte oficial a Python: roda, debuga e troca de ambiente virtual sem sair do editor.\nVer na Marketplace Essencial Pylance\nMicrosoft\nIntelliSense rápido e checagem de tipos pra Python. Ajuda bastante quando o projeto cresce e fica difícil de navegar sem ele.\nVer na Marketplace Black Formatter\nMicrosoft\nFormata o código Python no padrão Black ao salvar. Acaba com a discussão sobre estilo de código.\nVer na Marketplace Essencial Jupyter\nMicrosoft\nRoda notebooks .ipynb dentro do editor mesmo, com gráficos e variáveis aparecendo inline.\nVer na Marketplace R\nREditorSupport\nSuporte à linguagem R: terminal integrado, ajuda inline e visualização de dataframe. Resquício da época do blogdown, mas ainda uso direto.\nVer na Marketplace Markdown \u0026amp; Escrita Pra quem escreve mais Markdown do que código: sumário automático e aviso quando a formatação sai torta.\nMarkdown All in One\nYu Zhang\nAtalhos de formatação, sumário automático e preview pra quem escreve em Markdown o dia inteiro.\nVer na Marketplace markdownlint\nDavid Anson\nAponta problema de formatação e estilo no Markdown enquanto eu escrevo, antes de virar bagunça no preview.\nVer na Marketplace Produtividade \u0026amp; Qualidade Detalhes que economizam clique: caminho de arquivo, execução rápida e diagrama sem trocar de programa.\nPath Intellisense\nChristian Kohler\nAutocompleta caminho de arquivo ao digitar. Evita erro bobo de digitação em import.\nVer na Marketplace Code Runner\nJun Han\nRoda o arquivo ou o trecho selecionado com um atalho, em qualquer linguagem, sem precisar configurar nada antes.\nVer na Marketplace Draw.io Integration\nHenning Dieterichs\nCria e edita diagrama .drawio direto no editor. Não preciso abrir outro programa só pra desenhar uma caixinha.\nVer na Marketplace GitHub Actions\nGitHub\nValida e dá autocomplete nos workflows de CI. Ajuda a não quebrar o deploy só por causa de um YAML mal indentado.\nVer na Marketplace Visual \u0026amp; Interface A cara do editor: ícone por tipo de arquivo e interface em português.\nMaterial Icon Theme\nPhilipp Kief\nÍcone diferente por tipo de arquivo e pasta. Acho as coisas na árvore de arquivos bem mais rápido assim.\nVer na Marketplace Portuguese (Brazil) Language Pack\nMicrosoft\nTraduz a interface do VS Code pra português do Brasil.\nVer na Marketplace Se você também mexe com ciência de dados e IA, os canais do YouTube que eu recomendo e as bases de dados públicas complementam bem essa lista.\n","date":"17 de julho de 2026","externalUrl":null,"permalink":"/resources/vscode-extensions/","section":"Recursos","summary":" IA \u0026 Assistente de Código Onde a IA entra de verdade no editor: assistente de código e controle do que eu gasto com ele.\n","title":"Extensões do VSCode que eu uso","type":"vscode-extensions"},{"content":"Formado em Estatística e Probabilidade, atuo como Cientista de Dados com foco em Machine Learning e Inteligência Artificial desde 2017. Criei este blog para compartilhar soluções, técnicas e ferramentas que fazem parte da minha jornada.\n","date":"17 de julho de 2026","externalUrl":null,"permalink":"/","section":"Fellipe Gomes","summary":"Formado em Estatística e Probabilidade, atuo como Cientista de Dados com foco em Machine Learning e Inteligência Artificial desde 2017. Criei este blog para compartilhar soluções, técnicas e ferramentas que fazem parte da minha jornada.\n","title":"Fellipe Gomes","type":"page"},{"content":"","date":"17 de julho de 2026","externalUrl":null,"permalink":"/tags/ferramentas/","section":"Tags","summary":"","title":"Ferramentas","type":"tags"},{"content":"","date":"17 de julho de 2026","externalUrl":null,"permalink":"/tags/produtividade/","section":"Tags","summary":"","title":"Produtividade","type":"tags"},{"content":"","date":"17 de julho de 2026","externalUrl":null,"permalink":"/tags/python/","section":"Tags","summary":"","title":"Python","type":"tags"},{"content":"Coisas que me ajudaram de verdade ao longo dos anos: livros, ferramentas, gente que eu acompanho. Não é lista de afiliado, é o que eu indicaria pra um amigo começando na área.\n","date":"17 de julho de 2026","externalUrl":null,"permalink":"/resources/","section":"Recursos","summary":"Coisas que me ajudaram de verdade ao longo dos anos: livros, ferramentas, gente que eu acompanho. Não é lista de afiliado, é o que eu indicaria pra um amigo começando na área.\n","title":"Recursos","type":"resources"},{"content":"","date":"17 de julho de 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"17 de julho de 2026","externalUrl":null,"permalink":"/tags/vscode/","section":"Tags","summary":"","title":"Vscode","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/aprendizado/","section":"Tags","summary":"","title":"Aprendizado","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/bitcoin/","section":"Tags","summary":"","title":"Bitcoin","type":"tags"},{"content":"Link do app: https://bitcoindebrief.com/\nNewsletter diária automatizada que resume tudo sobre Bitcoin em 3 minutos, todo dia de manhã (6h, horário de Brasília).\nO que traz # Preço em tempo real e variação em 24h/7 dias Indicadores técnicos (RSI, Bandas de Bollinger, médias móveis) traduzidos em português simples Indicadores macroeconômicos (CPI, PIB, desemprego) que afetam o preço do Bitcoin Sentimento de mercado (Fear \u0026amp; Greed Index, dominância do Bitcoin) 5 notícias curadas das principais fontes de cripto do dia Fontes de dados # Coleta automatizada via API: Binance, CoinGecko, FRED (Federal Reserve Economic Data), Glassnode e CoinDesk.\nModelo de negócio # Gratuito durante o lançamento (até 15/07/2026); depois R$9,99/mês, com acesso vitalício grátis para os early adopters.\nComo foi construído # A inteligência de mercado que alimenta esta newsletter foi desenvolvida como um projeto open source. Veja o post completo com o código, a arquitetura dos agentes e o passo a passo de como montar um sistema igual: Equipe Multiagente de IA para Análise do Bitcoin.\n","date":"6 de julho de 2026","externalUrl":"https://bitcoindebrief.com/","permalink":"/projects/bitcoindebrief/","section":"Projetos","summary":"Link do app: https://bitcoindebrief.com/\nNewsletter diária automatizada que resume tudo sobre Bitcoin em 3 minutos, todo dia de manhã (6h, horário de Brasília).\nO que traz # Preço em tempo real e variação em 24h/7 dias Indicadores técnicos (RSI, Bandas de Bollinger, médias móveis) traduzidos em português simples Indicadores macroeconômicos (CPI, PIB, desemprego) que afetam o preço do Bitcoin Sentimento de mercado (Fear \u0026 Greed Index, dominância do Bitcoin) 5 notícias curadas das principais fontes de cripto do dia Fontes de dados # Coleta automatizada via API: Binance, CoinGecko, FRED (Federal Reserve Economic Data), Glassnode e CoinDesk.\n","title":"Bitcoin Debrief","type":"projects"},{"content":"O YouTube é um ótimo lugar para aprender isso na prática. Eu colecionei aqui canais que costumam valer a pena, desde os clássicos que explicam do zero até os que acompanham as novidades mais quentes do campo.\nFundamentos e Matemática Se você quer começar do zero, esses são os canais que mais ajudam a fazer a matemática fazer sentido.\nDestaque 3Blue1Brown\n@3blue1brown\nNão é só bonito de ver. Ele faz você entender o que está acontecendo, em vez de só memorizar fórmulas.\nAcessar canal StatQuest\n@statquest\nEle vai do básico ao mais complicado sem parecer que está falando de outro planeta. Muito bom para estatística e ML.\nAcessar canal Machine Learning \u0026amp; Deep Learning Para quem quer ver como os modelos realmente funcionam, sem ficar só no hype.\nDestaque Andrej Karpathy\n@AndrejKarpathy\nSe você quer entender LLMs de verdade, esse é um dos nomes mais úteis. Ele mistura teoria, intuição e código.\nAcessar canal Yannic Kilcher\n@YannicKilcher\nPapers sem enrolação. Ele lê os artigos em voz alta e ajuda a separar o que importa do que é só ruído.\nAcessar canal Two Minute Papers\n@TwoMinutePapers\nCurto, direto e bom para acompanhar o que saiu de novo sem perder muito tempo.\nAcessar canal IA Generativa \u0026amp; Agentes Aqui entra o lado mais prático: prompts, agentes, RAG e ferramentas que já aparecem em projetos reais.\nDestaque AI Jason\n@AIJasonZ\nUm dos mais úteis quando você quer ver agentes e workflows sendo montados de forma concreta.\nAcessar canal Sam Witteveen\n@samwitteveenai\nBom para quem quer ir além do básico e entender como essas ferramentas se encaixam no dia a dia.\nAcessar canal Matt Wolfe\n@mreflow\nÚtil para ficar de olho nas ferramentas, modelos e novidades sem virar uma leitura interminável.\nAcessar canal Fireship\n@Fireship\nRápido, objetivo e com humor. Dá para aprender bastante em poucos minutos.\nAcessar canal Python e Dados Python, SQL, notebooks e análise de dados com foco no que realmente aparece no trabalho.\nSentdex\n@sentdex\nMuito bom para ver Python sendo usado em problemas reais, não só em exemplos limpos.\nAcessar canal Rob Mulla\n@robmulla\nEle mostra o processo completo, inclusive os erros e os ajustes. Isso ajuda bastante.\nAcessar canal Ken Jee\n@KenJee_ds\nBom para quem quer entender carreira, portfólio e como entrar no mercado com mais clareza.\nAcessar canal Em Português Se você prefere aprender em português, esses canais costumam ser bons para acompanhar o assunto sem perder a profundidade.\nDestaque Mario Filho\n@mariofilhoml\nUm dos nomes mais sólidos no Brasil para quem quer aprender machine learning de forma prática.\nAcessar canal Dunossauro\n@dunossauro\nEle explica bem e faz parecer menos assustador. Bom para quem gosta de aprender com alguém que conversa de verdade.\nAcessar canal Hashtag Programação\n@HashtagProgramacao\nMuito bom para quem está começando em dados e quer conteúdo prático em português.\nAcessar canal Código Fonte TV\n@codigofonte\nMais voltado para contexto, carreira e tecnologia em geral, mas vale muito a pena.\nAcessar canal Pesquisa \u0026amp; Entrevistas Entrevistas longas, debates e conversas com pessoas que realmente construíram a área.\nLex Fridman\n@lexfridman\nLongas, mas quase sempre valem a pena. Ele consegue colocar o assunto em contexto e mostrar o lado humano das ideias.\nAcessar canal Destaque Dwarkesh Patel\n@DwarkeshPatel\nSe você gosta de pensar mais a fundo, esse é um dos melhores. As conversas tendem a ser mais densas e menos superficiais.\nAcessar canal Machine Learning Street Talk\n@MachineLearningStreetTalk\nBom para quem quer ouvir pesquisadores e pessoas do campo discutir ideias, não só produtos.\nAcessar canal AI Explained\n@aiexplained-official\nMais focado em desmontar hype e explicar o que mudou de fato.\nAcessar canal Se você está procurando datasets para praticar o que aprende nesses canais, confira também a lista de bancos de dados públicos.\n","date":"6 de julho de 2026","externalUrl":null,"permalink":"/resources/youtube-channels/","section":"Recursos","summary":"O YouTube é um ótimo lugar para aprender isso na prática. Eu colecionei aqui canais que costumam valer a pena, desde os clássicos que explicam do zero até os que acompanham as novidades mais quentes do campo.\nFundamentos e Matemática Se você quer começar do zero, esses são os canais que mais ajudam a fazer a matemática fazer sentido.\n","title":"Canais do YouTube para Cientistas de Dados","type":"youtube-channels"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/carreira/","section":"Tags","summary":"","title":"Carreira","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/data-science/","section":"Tags","summary":"","title":"Data-Science","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/freelance/","section":"Tags","summary":"","title":"Freelance","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/ia/","section":"Tags","summary":"","title":"Ia","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/machine-learning/","section":"Tags","summary":"","title":"Machine Learning","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/programacao/","section":"Tags","summary":"","title":"Programacao","type":"tags"},{"content":"Apps e dashboards que fui construindo ao longo do tempo, a maioria em Shiny. Alguns nasceram pra resolver um problema meu, outros só pra testar uma ideia. O código da maioria está no GitHub.\n","date":"6 de julho de 2026","externalUrl":null,"permalink":"/projects/","section":"Projetos","summary":"Apps e dashboards que fui construindo ao longo do tempo, a maioria em Shiny. Alguns nasceram pra resolver um problema meu, outros só pra testar uma ideia. O código da maioria está no GitHub.\n","title":"Projetos","type":"projects"},{"content":" Onde eu procuraria hoje # Trabalho remoto deixou de ser novidade. Agora o desafio é achar os lugares certos, sem perder tempo com listas improvisadas e plataformas que não fazem sentido para o seu perfil.\nNo Brasil # Plataforma Para quê Remotar Voltada para trabalho remoto no Brasil Trampos Forte em tecnologia, direta para quem já sabe o que procura Vagas.com Boa opção para home office e vagas híbridas Freelancing internacional # Plataforma Para quê Upwork Porta de entrada mais ampla para clientes do mundo todo Toptal Mais seletiva, projetos melhores e remuneração mais alta Fiverr Ótimo para serviços bem definidos e entregas curtas Workana Forte para clientes latam e projetos bem segmentados Vagas CLT e contratos remotos # Plataforma Para quê Remote OK Agregador com bastante movimento e boa leitura rápida Landing Jobs Tecnologia e empresas internacionais We Work Remotely Comunidade forte e muita cultura remota Nichos específicos # Plataforma Para quê italki Para ensinar idiomas online Utest Para quem quer entrar em QA e testes Crossover Vagas full-time remotas em empresas americanas O que eu faria hoje # Se eu estivesse começando agora, faria assim:\nUsaria Remotar e Trampos para encontrar oportunidades no Brasil. Checaria Upwork e Toptal se o foco fosse freelancing internacional. Acompanharia Remote OK para ver vagas com mais rapidez. Montaria um perfil claro em cada plataforma, com portfólio, GitHub, Behance ou um site simples. Dicas que realmente fazem diferença # Tenha um portfólio atualizado. Isso pesa mais do que parecer “disponível para tudo”. Comunicação escrita conta bastante. Uma descrição clara e respostas objetivas ajudam muito. Defina seus horários. Flexibilidade não significa estar disponível 24 horas por dia. Cuidado com golpes. Se alguém pede pagamento para te contratar, já é um sinal de alerta. Para freelas, use contrato claro. Isso evita dor de cabeça depois. A melhor plataforma nem sempre é a maior. Muitas vezes, é a que combina melhor com o tipo de trabalho que você quer fazer.\n","date":"6 de julho de 2026","externalUrl":null,"permalink":"/resources/remote-work/","section":"Recursos","summary":"Onde eu procuraria hoje # Trabalho remoto deixou de ser novidade. Agora o desafio é achar os lugares certos, sem perder tempo com listas improvisadas e plataformas que não fazem sentido para o seu perfil.\nNo Brasil # Plataforma Para quê Remotar Voltada para trabalho remoto no Brasil Trampos Forte em tecnologia, direta para quem já sabe o que procura Vagas.com Boa opção para home office e vagas híbridas Freelancing internacional # Plataforma Para quê Upwork Porta de entrada mais ampla para clientes do mundo todo Toptal Mais seletiva, projetos melhores e remuneração mais alta Fiverr Ótimo para serviços bem definidos e entregas curtas Workana Forte para clientes latam e projetos bem segmentados Vagas CLT e contratos remotos # Plataforma Para quê Remote OK Agregador com bastante movimento e boa leitura rápida Landing Jobs Tecnologia e empresas internacionais We Work Remotely Comunidade forte e muita cultura remota Nichos específicos # Plataforma Para quê italki Para ensinar idiomas online Utest Para quem quer entrar em QA e testes Crossover Vagas full-time remotas em empresas americanas O que eu faria hoje # Se eu estivesse começando agora, faria assim:\n","title":"Trabalho remoto","type":"resources"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/trabalho-remoto/","section":"Tags","summary":"","title":"Trabalho Remoto","type":"tags"},{"content":"","date":"6 de julho de 2026","externalUrl":null,"permalink":"/tags/youtube/","section":"Tags","summary":"","title":"Youtube","type":"tags"},{"content":"","date":"4 de julho de 2026","externalUrl":null,"permalink":"/tags/estatistica/","section":"Tags","summary":"","title":"Estatistica","type":"tags"},{"content":"","date":"4 de julho de 2026","externalUrl":null,"permalink":"/tags/livros/","section":"Tags","summary":"","title":"Livros","type":"tags"},{"content":" Estatística e fundamentos A base de tudo. Os livros que sustentam tudo que veio depois, de regressão a redes neurais.\n🇺🇸 EN Comece por aqui An Introduction to Statistical Learning (Python)\nJames, Witten, Hastie, Tibshirani\nSe fosse pra indicar um só pra começar, seria esse. Teoria o suficiente pra entender o porquê, e código pra rodar hoje à noite.\nVer na Amazon 🇺🇸 EN An Introduction to Statistical Learning (R)\nJames, Witten, Hastie, Tibshirani\nO ISLP em R. Se você prefere R ao Python, começa aqui: mesmas ideias, exemplos em R.\nVer na Amazon 🇺🇸 EN The Elements of Statistical Learning\nHastie, Tibshirani, Friedman\nO irmão pesado do ISLP. Ninguém lê de capa a capa: você abre quando precisa encarar a matemática de frente.\nVer na Amazon 🇺🇸 EN Statistical Rethinking\nRichard McElreath\nEnsina bayesiana como raciocínio, não como fórmula decorada. Poucos livros mudaram tanto o jeito que eu penso inferência.\nVer na Amazon 🇺🇸 EN Doing Bayesian Data Analysis\nJohn Kruschke\nO tutorial de bayesiana com R, JAGS e Stan. Didático o suficiente para iniciantes, rigoroso o suficiente para quem quer entender o que está fazendo. Par ideal com o Statistical Rethinking.\nVer na Amazon 🇺🇸 EN Statistical Inference via Data Science\nChester Ismay e Albert Y. Kim\nInferência via tidyverse e moderndive. Ótimo ponto de entrada pra quem já sabe R básico e quer entender estatística de verdade.\nVer na Amazon 🇺🇸 EN Beyond Multiple Linear Regression\nPaul Roback e Julie Legler\nQuando a regressão linear simples não resolve. Modelos mistos, dados de contagem, séries — tudo num volume só.\nVer na Amazon 🇧🇷 PT-BR Estatística Básica\nBussab e Morettin\nO clássico das faculdades brasileiras. Base sem firula, do jeito que formou gerações inteiras.\nVer na Amazon 🇺🇸 EN Practical Nonparametric Statistics\nW. J. Conover\nO texto de referência em estatística não paramétrica. Cobre os principais testes para amostras independentes, pareadas e ANOVA não paramétrica.\nVer na Amazon 🇺🇸 EN Applied Multivariate Statistical Analysis\nRichard A. Johnson e Dean W. Wichern\nA referência em análise multivariada. PCA, análise fatorial, clustering e discriminante num volume só — o livro que ficou na minha mesa durante o mestrado.\nVer na Amazon 🇺🇸 EN Probability and Statistics\nMorris H. DeGroot e Mark J. Schervish\nO tratamento mais rigoroso de probabilidade e inferência que existe em língua inglesa. Referência obrigatória pra quem quer entender estatística de verdade.\nVer na Amazon 🇺🇸 EN An Introduction to Probability Theory and Its Applications\nWilliam Feller\nClássico absoluto. Feller constrói a teoria de probabilidade do zero com rigor e elegância. Ainda hoje é a referência que ninguém conseguiu superar.\nVer na Amazon 🇧🇷 PT-BR Probabilidade e Variáveis Aleatórias\nMarcos Nascimento Magalhães\nA referência brasileira em probabilidade. Rigoroso sem ser inacessível — ideal pra quem quer ir além da estatística descritiva e entender a teoria por trás.\nVer na Amazon 🇺🇸 EN Markov Chain Monte Carlo: Stochastic Simulation for Bayesian Inference\nDani Gamerman e Hedibert F. Lopes\nO livro brasileiro de MCMC. Cobre teoria e prática do amostrador de Gibbs ao HMC com rigor matemático. Referência obrigatória pra quem quer implementar bayesiana de verdade.\nVer na Amazon 🇺🇸 EN Statistical Inference: An Integrated Approach\nHelio S. Migon, Dani Gamerman e Francisco Louzada\nInferência integrando as escolas frequentista e bayesiana num só volume. Escrito por brasileiros, com exposição clara das distribuições condicionais completas e modelos hierárquicos.\nVer na Amazon 🇧🇷 PT-BR Estatística Não Paramétrica para as Ciências do Comportamento\nSidney Siegel\nO clássico da estatística não paramétrica nas ciências do comportamento. Apresenta os testes mais relevantes com exemplos detalhados.\nVer na Amazon 🇧🇷 PT-BR Ruído: Uma Falha no Julgamento Humano\nKahneman, Sibony, Sunstein\nNão é só o viés que atrapalha: é a variação aleatória nas nossas decisões. Leitura obrigatória pra quem trabalha com previsão.\nVer na Amazon 🇺🇸 EN Exploratory Data Analysis\nJohn Wilder Tukey\nO livro que batizou a AED. Tukey definiu em 1977 o que significa olhar pra dados antes de modelar — as ideias ainda são o ponto de partida de qualquer análise séria.\nVer na Amazon 🇧🇷 PT-BR Modelos Lineares Generalizados e Aplicações\nGauss M. Cordeiro, Clarice G. B. Demétrio e Rafael A. Moral\nGLM bem-ensinado, em português. Família exponencial, estimação, inferência, diagnóstico e aplicações a dados contínuos e discretos — com código R.\nVer na Amazon 🇧🇷 PT-BR Análise de Sobrevivência: Teoria e Aplicações em Saúde\nCarvalho, Andreozzi, Codeço, Campos, Barbosa, Shimakura\nA referência brasileira de análise de sobrevivência na saúde. De Kaplan-Meier ao modelo de Cox, com exemplos em R e dados reais de epidemiologia.\nVer na Amazon 🇧🇷 PT-BR Análise de Sobrevivência Aplicada\nEnrico A. Colosimo e Suely R. Giolo\nDados que terminam antes da hora são a norma em saúde e engenharia. Este é o livro que explica por que você não pode ignorar os censurados — e o que fazer com eles.\nVer na Amazon 🇺🇸 EN Introduction to Reliability Engineering\nE. E. Lewis\nQuando a pergunta não é \u0026#39;o modelo ajustou bem\u0026#39; mas \u0026#39;o sistema vai falhar quando?\u0026#39;. A base teórica de confiabilidade para estatísticos que trabalham com dados de falha e tempo de vida.\nVer na Amazon Acaso, probabilidade e decisão Você lê num fim de semana e passa a enxergar dados, sorte e risco de outro jeito.\n🇧🇷 PT-BR Estatística: O Que É, Para Que Serve, Como Funciona\nCharles Wheelan\nEstatística de ler na praia, com humor. Ótimo presente pra quem tem medo de número.\nVer na Amazon 🇧🇷 PT-BR Como Mentir com Estatística\nDarrell Huff\nSetenta anos de idade e continua atual. Depois dele, todo gráfico bonito vira suspeito.\nVer na Amazon 🇧🇷 PT-BR O Andar do Bêbado\nLeonard Mlodinow\nQuanto do que a gente chama de mérito é acaso disfarçado? Mais do que dá vontade de admitir.\nVer na Amazon 🇧🇷 PT-BR Uma Senhora Toma Chá...\nDavid Salsburg\nA história da estatística contada quase como romance. Vai bem mais rápido do que a cara sugere.\nVer na Amazon 🇧🇷 PT-BR O Sinal e o Ruído\nNate Silver\nSobre por que quase toda previsão erra feio. No Kindle custa menos que um café.\nVer na Amazon 🇧🇷 PT-BR Iludidos pelo Acaso\nNassim Nicholas Taleb\nTaleb antes da fama. Sobre confundir sorte com talento, o vício preferido da nossa área.\nVer na Amazon 🇧🇷 PT-BR Rápido e Devagar: Duas Formas de Pensar\nDaniel Kahneman\nUm Nobel sobre os dois sistemas que decidem por você sem avisar. Denso, mas rende cada página.\nVer na Amazon R Foi por aqui que eu comecei. Se você vive de R, esses livros levam do arroz com feijão ao domínio real da linguagem.\n🇧🇷 PT-BR Comece por aqui R para Data Science\nHadley Wickham e Garrett Grolemund\nSe você mexe com R, comece por aqui. Tidyverse bem ensinado, e em português.\nVer na Amazon 🇺🇸 EN Advanced R\nHadley Wickham\nOnde o R para de ser ferramenta e vira linguagem de verdade. O salto pra escrever código que os outros copiam.\nVer na Amazon 🇺🇸 EN ggplot2: Elegant Graphics for Data Analysis\nHadley Wickham\nA gramática dos gráficos pela mão de quem a inventou. Gráfico bom deixa de depender de sorte.\nVer na Amazon 🇺🇸 EN Tidy Modeling with R\nMax Kuhn e Julia Silge\nModelagem com tidymodels do jeito certo. Do pré-processamento ao tuning, tudo em sintaxe arrumada.\nVer na Amazon 🇺🇸 EN Text Mining with R\nJulia Silge e David Robinson\nAnálise de texto com tidytext. NLP acessível em R, com exemplos que fazem sentido.\nVer na Amazon 🇺🇸 EN R Graphics Cookbook (2nd Edition)\nWinston Chang\nReceitas prontas de ggplot2. Você vê o gráfico que quer e encontra o código direto.\nVer na Amazon 🇺🇸 EN R Markdown Cookbook\nYihui Xie, Christophe Dervieux, Emily Riederer\nTudo que o R Markdown consegue fazer. Livro de referência, não de leitura linear.\nVer na Amazon 🇺🇸 EN Geocomputation with R\nLovelace, Nowosad, Muenchow\nDados espaciais, mapas e análise geográfica em R. sf, terra e ggplot2 juntos num volume.\nVer na Amazon 🇺🇸 EN Efficient R Programming\nColin Gillespie e Robin Lovelace\nCódigo R rápido e escalável. Profiling, paralelismo e boas práticas que pouca gente ensina.\nVer na Amazon 🇺🇸 EN Engineering Production-Grade Shiny Apps\nFay, Rochette, Guyader, Girard\nAlém do app que roda no laptop. Arquitetura de Shiny sério pra ir pra produção de verdade.\nVer na Amazon 🇺🇸 EN Applied Econometrics with R\nChristian Kleiber e Achim Zeileis\nO livro do pacote AER. Regressão, Tobit, dados de contagem e séries temporais em R — com os dados do artigo incluídos no pacote. Referência obrigatória pra econometria aplicada em R.\nVer na Amazon Python, Data Science e Engenharia Do primeiro pandas ao código que sobe pra produção. O caminho de quem quer virar engenheiro, não só analista.\n🇧🇷 PT-BR Python Fluente (vol. 1)\nLuciano Ramalho\nPython de gente grande, escrito por um brasileiro. Passa do \u0026#34;funciona\u0026#34; pro \u0026#34;entendi por quê\u0026#34;. (Este é o vol. 1 da edição em três partes.)\nVer na Amazon 🇧🇷 PT-BR Python para Análise de Dados\nWes McKinney\nPandas explicado por quem escreveu o pandas. Desses que ficam abertos na mesa o dia todo.\nVer na Amazon 🇧🇷 PT-BR Guia do Python para Data Science\nJake VanderPlas\nNumPy, pandas, scikit-learn e matplotlib num volume só. Livro de bancada.\nVer na Amazon 🇧🇷 PT-BR Comece por aqui Mãos à Obra: Aprendizado de Máquina com Scikit-Learn, Keras e TensorFlow\nAurélien Géron\nO prático de ML que eu mais indico. Sai do zero e chega no deploy, sempre com código do lado.\nVer na Amazon 🇧🇷 PT-BR Engenharia de Software para Cientistas de Dados\nCatherine Nelson\nA ponte entre o notebook e o sistema que roda em produção. O livro que faltava pra ciência de dados virar engenharia.\nVer na Amazon Machine Learning e Deep Learning Depois do básico, é aqui que a coisa fica séria. Do essencial que cabe na mochila ao modelo que aguenta produção.\n🇺🇸 EN Comece por aqui The Hundred-Page Machine Learning Book\nAndriy Burkov\nCem páginas, zero enrolação. É o que eu mando pra quem chega perguntando por onde começar em ML.\nVer na Amazon 🇧🇷 PT-BR Machine Learning: Guia de Referência Rápida\nMatt Harrison\nCanivete suíço do dia a dia. Uma receita rápida pra cada tarefa chata de ML.\nVer na Amazon 🇧🇷 PT-BR Projetando Sistemas de Machine Learning\nChip Huyen\nML que sobrevive fora do notebook bonito. É o que separa júnior de sênior na prática.\nVer na Amazon 🇺🇸 EN Fairness and Machine Learning\nBarocas, Hardt, Narayanan\nO que é um modelo justo? Como medir e corrigir discriminação algorítmica. Leitura obrigatória pra quem coloca modelo em produção.\nVer na Amazon 🇺🇸 EN Interpretable Machine Learning\nChristoph Molnar\nSHAP, LIME, PDP — tudo que você precisa pra explicar qualquer modelo. Disponível online de graça.\nVer na Amazon 🇺🇸 EN Feature Engineering and Selection\nMax Kuhn e Kjell Johnson\nEngenharia de features bem feita resolve metade do problema. Max Kuhn explica como.\nVer na Amazon 🇺🇸 EN Ensemble Methods for Machine Learning\nGautam Kunapuli\nBagging, boosting, stacking explicados do zero. Boa referência pra entender o que faz o XGBoost funcionar.\nVer na Amazon 🇺🇸 EN Imbalanced Classification with Python\nJason Brownlee\nOversampling, undersampling, cost-sensitive learning — o guia pra quando seus dados são tortos.\nVer na Amazon 🇧🇷 PT-BR Introdução a Mineração de Dados com aplicações em R\nLeandro Augusto da Silva\nIntrodução prática à mineração de dados com R. Cobre agrupamento, classificação, regressão e validação de modelos — base para quem quer ir além da estatística clássica.\nVer na Amazon 🇺🇸 EN Deep Learning\nGoodfellow, Bengio, Courville\nA referência de deep learning. Tem de graça no site oficial, mas o impresso vira consulta de estante.\nVer na Amazon LLMs e Agentes de IA A fronteira, e onde este blog anda passando a maior parte do tempo. Do transformer por dentro ao produto de IA que roda.\n🇺🇸 EN Build a Large Language Model (From Scratch)\nSebastian Raschka\nUm LLM montado linha por linha. Não conheço jeito melhor de entender o que roda por baixo do capô.\nVer na Amazon 🇺🇸 EN Comece por aqui Hands-On Large Language Models\nJay Alammar e Maarten Grootendorst\nLLM na prática, com as ilustrações que fazem o transformer finalmente clicar.\nVer na Amazon 🇺🇸 EN AI Engineering\nChip Huyen\nO mais atual pra quem constrói produto com IA generativa. Caro, mas você paga pelo timing.\nVer na Amazon 🇺🇸 EN Natural Language Processing with Transformers\nTunstall, von Werra, Wolf\nHugging Face pelos próprios autores da Hugging Face. Do fine-tuning ao deploy.\nVer na Amazon Séries Temporais Dados que dependem do tempo precisam de um tratamento diferente. Os dois livros mais importantes da área.\n🇺🇸 EN Forecasting: Principles and Practice\nRob J Hyndman e George Athanasopoulos\nA referência em séries temporais. Disponível online de graça e melhor que a maioria dos cursos.\nVer na Amazon 🇺🇸 EN Forecasting: Principles and Practice, the Pythonic Way\nNixtla\nA versão Python do FPP3, com statsmodels e neuralforecast. Ideal pra quem prefere Python ao R.\nVer na Amazon 🇧🇷 PT-BR Análise de Séries Temporais: Modelos Lineares Univariados\nPedro A. Morettin e Clélia M. C. Toloi\nA referência brasileira em séries temporais. A definição que toda graduação de estatística no Brasil aprendeu. Vol 1 cobre modelos lineares univariados — ARIMA, sazonalidade, tendência.\nVer na Amazon Visualização de Dados Dados bem comunicados valem mais que dados certos. Os princípios por trás de um gráfico que convence.\n🇺🇸 EN Fundamentals of Data Visualization\nClaus O. Wilke\nPrincípios de visualização independente de ferramenta. Wilke explica o porquê de cada escolha gráfica. Disponível online de graça.\nVer na Amazon Dados, sociedade e negócios Modelo bom sem contexto vira problema. Dois livros pra pensar no impacto e no valor do que a gente constrói.\n🇧🇷 PT-BR Algoritmos de Destruição em Massa\nCathy O\u0026#39;Neil\nO lado sombrio dos modelos. Leia antes de subir qualquer algoritmo que decide sobre gente.\nVer na Amazon 🇧🇷 PT-BR Data Science para Negócios\nFoster Provost e Tom Fawcett\nConecta a técnica ao que vira dinheiro. Ensina a pensar como quem aprova o orçamento.\nVer na Amazon Ciência de Dados Onde os dados encontram o mundo real. Livros que ampliam o olhar além dos modelos.\n🇧🇷 PT-BR A Cor dos Dados\nAna Paula Gonzalez Torres\nSobre o que os dados revelam e o que escondem. Leitura que muda como você vê os conjuntos de dados.\nVer na Amazon 🇧🇷 PT-BR A Lógica do Cisne Negro\nNassim Nicholas Taleb\nSobre eventos raros de impacto imenso. Completa a trilogia da incerteza de Taleb, ao lado de Iludidos pelo Acaso.\nVer na Amazon 🇧🇷 PT-BR A Cauda Longa\nChris Anderson\nPor que nichos vencem. A ideia que mudou como pensamos distribuições e mercados digitais.\nVer na Amazon Comunicação, consultoria e carreira A parte que ninguém ensina na graduação e que decide sua carreira. Como comunicar, ganhar confiança e resolver o problema certo.\n🇧🇷 PT-BR Storytelling com Dados\nCole Nussbaumer Knaflic\nSeus gráficos param de só existir e passam a convencer. Curto e prático.\nVer na Amazon 🇺🇸 EN The Trusted Advisor\nMaister, Green e Galford\nComo virar a pessoa que o cliente escuta de verdade. Pra quem vive de consultoria, paga o preço fácil.\nVer na Amazon 🇧🇷 PT-BR Comece pelo Porquê\nSimon Sinek\nPor que umas ideias grudam e outras não. Muda a forma como você apresenta o próprio trabalho.\nVer na Amazon 🇧🇷 PT-BR O Princípio da Pirâmide\nBarbara Minto\nComo estruturar qualquer texto pra ser entendido de primeira. A consultoria de elite usa isso há décadas.\nVer na Amazon 🇧🇷 PT-BR Apaixone-se pelo Problema, Não pela Solução\nUri Levine\nDo fundador do Waze. Resolva o problema certo antes de escrever a primeira linha de código.\nVer na Amazon Carreira e Liderança Crescer sem perder o lado técnico. Como exercer liderança e impacto real sem precisar de cargo de gestor.\n🇺🇸 EN Staff Engineer: Leadership Beyond the Management Track\nWill Larson\nO manual do engenheiro que cresce sem virar gestor. Influência técnica, arquitetura e liderança sem autoridade formal.\nVer na Amazon 🇺🇸 EN The Secrets of Consulting\nGerald M. Weinberg\nOs princípios por trás de qualquer projeto de consultoria bem-sucedido. Ainda atual décadas depois.\nVer na Amazon 🇺🇸 EN Modeling Mindsets\nChristoph Molnar\nComo escolher o modelo certo pro problema certo. Vai além da técnica e entra no raciocínio por trás das decisões de modelagem.\nVer na Amazon ","date":"4 de julho de 2026","externalUrl":null,"permalink":"/books/","section":"Fellipe Gomes","summary":" Estatística e fundamentos A base de tudo. Os livros que sustentam tudo que veio depois, de regressão a redes neurais.\n","title":"Livros que recomendo para cientistas de dados","type":"books"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/agent-ai/","section":"Tags","summary":"","title":"Agent-Ai","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/apple-silicon/","section":"Tags","summary":"","title":"Apple-Silicon","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/categories/fundamentos-de-data-science/","section":"Categories","summary":"","title":"Fundamentos De Data Science","type":"categories"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/gguf/","section":"Tags","summary":"","title":"Gguf","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/categories/inteligencia-artificial/","section":"Categories","summary":"","title":"Inteligência Artificial","type":"categories"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/langchain/","section":"Tags","summary":"","title":"Langchain","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/langchain-series/","section":"Tags","summary":"","title":"Langchain-Series","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/llama-cpp/","section":"Tags","summary":"","title":"Llama-Cpp","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/llm/","section":"Tags","summary":"","title":"Llm","type":"tags"},{"content":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing → LLM Local com Qwen sem APIs Por que rodar LLMs localmente? Nos últimos anos, o mundo dos modelos de linguagem de grande porte (LLMs) deixou de ser um território exclusivo das gigantes americanas. Uma leva de modelos open-weight de origem chinesa como o Qwen (Alibaba), o DeepSeek e o Yi chegaram com qualidade surpreendente e, mais importante, com pesos disponíveis publicamente. Li sobre alguns deles em um post que apareceu no meu LinkedIn e fiquei curioso para testar: será que dá para rodar um desses modelos localmente no meu Mac e ainda plugar ele num agente LangChain funcional?\nMas porque alguém escolheria rodar um LLM localmente ao invés de simplesmente chamar uma API? A resposta vai depender da necessidade do usuário:\nPrivacidade de dados: nenhum token sai da sua máquina. Para dados sensíveis como contratos, código proprietário, prontuários e isso pode ser um requisito não negociável. Custo zero de inferência: sem cobrança por token, sem surpresas no cartão de crédito no fim do mês. Funcionamento offline: avião, servidor sem acesso externo, ambiente air-gapped. O modelo simplesmente roda. Controle total: você decide qual versão do modelo usa, quando atualiza, como configura. Claro que esse caminho tem seus trade-offs. Hardware limitado significa que modelos maiores (70B+) estão fora de alcance sem uma GPU dedicada. A quantização (processo de reduzir a precisão dos pesos de 32 bits para 4 ou 8 bits) é o que torna possível rodar modelos de bilhões de parâmetros em hardware consumer, mas com alguma perda de qualidade e latência, que costuma ser maior do que a de uma API otimizada em data center. Mas para prototipagem, estudos e contextos onde privacidade importa, essa equação ainda faz muito sentido.\n📌 Em posts anteriores usei o GPT-4o-mini via API da OpenAI para construir agentes. Aqui vamos por um caminho diferente: zero API externa, zero custo, tudo rodando localmente.\nTL;DR\nO llama-server expõe um LLM local (Qwen2.5-4B, quantizado em GGUF) com uma API compatível com a da OpenAI. Basta trocar a openai_api_base do ChatOpenAI do LangChain para apontar pro servidor local. O agente usa @tool para chamadas de função e response_format com Pydantic para saída estruturada, sem gastar um centavo em API. O ecossistema: Qwen2.5, GGUF e llama.cpp O modelo: Qwen2.5 O Qwen2.5 é uma família de modelos desenvolvida pela Alibaba, disponível em múltiplos tamanhos (0.5B até 72B parâmetros) e com versões especializadas para código, matemática e visão computacional. Para este projeto, escolhi o Qwen2.5-4B-Instruct que tem um ponto de equilíbrio razoável entre capacidade e consumo de memória para um MacBook caseiro com Apple Silicon.\nSe você quer entender o que tem dentro desse tipo de modelo, não só como usar, o Build a Large Language Model (From Scratch), do Raschka, monta um LLM linha por linha. Não conheço jeito melhor de entender o que roda por baixo do capô.\nO formato: GGUF O GGUF é o formato padrão para rodar modelos quantizados via llama.cpp. Ele empacota os pesos do modelo junto com os metadados necessários para inferência em um único arquivo portátil. A escolha da variante de quantização define o trade-off entre tamanho e qualidade:\nVariante Precisão Tamanho (4B) Qualidade q4_k_m 4 bits ~2.5 GB boa q5_k_m 5 bits ~3.1 GB melhor q8_0 8 bits ~4.5 GB próxima do original Para este experimento usei q4_k_m, que cabe confortavelmente na memória unificada do M1 e ainda entrega respostas coesas.\nA infraestrutura: llama.cpp + llama-server O llama.cpp é uma biblioteca de inferência em C++ otimizada para rodar LLMs em hardware commodity, incluindo suporte a aceleração via Metal no Apple Silicon. Um setup_environment.sh do projeto já automatiza toda a configuração:\n# Instalar llama.cpp via Homebrew # (com suporte a Metal para Apple Silicon) brew install llama.cpp # Instalar dependências Python (versões pinadas no requirements.txt) pip install -r requirements.txt # Baixar o modelo do Hugging Face huggingface-cli download Qwen/Qwen2.5-4B-Instruct-GGUF \\ qwen2.5-4b-instruct-q4_k_m.gguf \\ --local-dir ~/.hf_cache/ O requirements.txt do repositório já traz as versões exatas utilizadas neste projeto:\nlangchain==1.2.10 langchain_openai==1.1.10 langchain-core==1.2.13 langchain-community==0.4.1 langgraph==1.0.8 llama-cpp-python==0.3.16 huggingface_hub==1.4.1 pydantic==2.12.5 Com o modelo baixado, subir o servidor é uma única linha:\n# Subir um servidor local com interface compatível com a API OpenAI llama-server \\ -m ~/.hf_cache/qwen2.5-4b-instruct-q4_k_m.gguf \\ --port 8000 \\ -ngl 1 A flag -ngl 1 ativa o offload de uma camada para a GPU via Metal, nesse caso suficiente para nosso teste aproveitar a aceleração do M1 sem saturar a memória (o usual é ngl -99 ou ngl-1 para usar todas as camadas). A partir daí, o servidor expõe um endpoint REST em http://localhost:8000/v1 com a mesma interface da API da OpenAI. Esse detalhe é o que torna tudo o que vem a seguir possível.\nConectando ao LangChain via API OpenAI-compatible O LangChain tem uma abstração chamada ChatOpenAI que, por padrão, aponta para os servidores da OpenAI, mas aceita uma openai_api_base customizada. Basta trocar a URL base e o ecossistema inteiro funciona sem alteração nenhuma:\nfrom langchain_openai import ChatOpenAI model = ChatOpenAI( model=\u0026quot;qwen2.5-4b-instruct\u0026quot;, openai_api_base=\u0026quot;http://localhost:8000/v1\u0026quot;, openai_api_key=\u0026quot;not-needed\u0026quot;, temperature=0, ) Duas observações sobre esta configuração:\nopenai_api_key=\"not-needed\": o llama-server não implementa autenticação, então qualquer string serve. O campo apenas precisa estar preenchido para satisfazer a validação do cliente. temperature=0: tecnicamente, determinismo total em LLMs envolve outros fatores (como seed e top_k), mas manter temperature=0 elimina a amostragem aleatória e aproxima o modelo de uma resposta “mais racional” ou “menos criativa”. Definindo ferramentas com @tool A Anthropic publicou um guia sobre construção de agentes eficazes em 2024 que eu acho uma das melhores referências práticas disponíveis. A definição deles é direta ao ponto: agentes são sistemas onde o LLM dirige dinamicamente o próprio fluxo de execução, escolhendo quais ações tomar e em que ordem e é exatamente o que vamos construir aqui.\nO mecanismo central é o Tool Calling: o LLM recebe uma lista de funções disponíveis (com nomes, parâmetros e descrições) e decide, a cada passo, qual chamar e com quais argumentos. O Python executa a função e devolve o resultado para o LLM, que então decide o próximo passo. Esse ciclo continua até o objetivo ser atingido.\nNo LangChain, o decorator @tool transforma qualquer função Python em uma ferramenta que o LLM pode invocar. O ponto crítico são os docstrings: é a partir deles que o modelo entende para que serve cada função. Uma descrição ruim leva a chamadas erradas ou desnecessárias.\nimport math from langchain.tools import tool @tool def multiply(a: float, b: float) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Multiplica dois números.\u0026quot;\u0026quot;\u0026quot; return a * b @tool def add(a: float, b: float) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Soma dois números.\u0026quot;\u0026quot;\u0026quot; return a + b @tool def divide(a: float, b: float) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Divide dois números.\u0026quot;\u0026quot;\u0026quot; return a / b @tool def sqrt(x: float) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Calcula a raiz quadrada de um número.\u0026quot;\u0026quot;\u0026quot; return math.sqrt(x) @tool def power(base: float, exponent: float) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Eleva um número à potência especificada.\u0026quot;\u0026quot;\u0026quot; return math.pow(base, exponent) @tool def absolute(x: float) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Calcula o valor absoluto de um número.\u0026quot;\u0026quot;\u0026quot; return abs(x) @tool def round_number(x: float, digits: int = 0) -\u0026gt; float: \u0026quot;\u0026quot;\u0026quot;Arredonda um número para o número especificado de casas decimais.\u0026quot;\u0026quot;\u0026quot; return round(x, digits) tools = [add, multiply, divide, sqrt, power, absolute, round_number] As operações matemáticas são deliberadamente simples, mas o ponto aqui não é o problema em si, mas demonstrar o padrão arquitetural. Basta substituir sqrt por buscar_dados_de_mercado ou absolute por consultar_base_de_conhecimento e a lógica é exatamente a mesma.\nOutro elemento importante é o system_prompt. Aqui ele tem um papel muito específico: proibir explicitamente que o LLM calcule diretamente, forçando toda aritmética a passar pelas tools Python. Isso garante precisão computacional e auditabilidade enquanto cada operação tem uma entrada e saída rastreável.\nYou are a strict mathematical agent. - Respect parentheses. - Follow PEMDAS. - Use tools for ALL computations. - Never compute directly. - Return structured output only. Essa separação entre raciocínio (responsabilidade do LLM) e execução (responsabilidade do Python) é uma das ideias centrais no design de agentes robustos.\nSaída estruturada com Pydantic Por padrão, LLMs retornam texto livre. Em pipelines de produção isso pode ser um problema: difícil de parsear, inconsistente entre execuções, incompatível com sistemas downstream.\nO LangChain suporta structured output via Pydantic: você define um schema e passa via response_format. O modelo é instruído a produzir exatamente aquele formato:\nfrom pydantic import BaseModel, Field class MathResult(BaseModel): result: float = Field(..., description=\u0026quot;Final numerical result\u0026quot;) O schema aqui é simples com um único campo float. Mas o padrão é o mesmo que usei no post sobre análise de ligações de telemarketing, onde o schema RelatorioLigacao tinha dezenas de campos aninhados (sentimento, tipo de ligação, resultado, respostas criativas). A lógica é idêntica; a complexidade do schema depende do problema.\nCriando e executando o agente com streaming Antes do código, vale visualizar como as peças se encaixam: llama-server expõe o Qwen2.5 localmente, o LangChain fala com ele via ChatOpenAI, e o agente orquestra o ciclo de tool calling até devolver a resposta estruturada. Nenhuma dessas setas sai da máquina.\nEsse padrão de agente local (LLM + tools + saída tipada) é o mesmo que uso em outros projetos da seção de IA agêntica, onde reúno skills, apps e MCP servers organizados por finalidade — vale a visita se quiser ver o padrão aplicado em outros contextos.\nCom todas as peças prontas, a montagem do agente é direta:\nfrom langchain.agents import create_agent agent = create_agent( model=model, tools=tools, system_prompt=\u0026quot;\u0026quot;\u0026quot; You are a strict mathematical agent. - Respect parentheses. - Follow PEMDAS. - Use tools for ALL computations. - Never compute directly. - Return structured output only. \u0026quot;\u0026quot;\u0026quot;, response_format=MathResult, ) Para executar, uso agent.stream() com stream_mode=\"updates\". Essa configuração expõe cada etapa do ciclo de raciocínio como um evento separado sendo uma forma de observabilidade nativa que dispensa ferramentas extras como o LangSmith para entender o que o agente está fazendo:\ninput_payload = { \u0026quot;messages\u0026quot;: [ { \u0026quot;role\u0026quot;: \u0026quot;user\u0026quot;, \u0026quot;content\u0026quot;: \u0026quot;Calcule: (sqrt(16) + pow(2,3)) / abs(-4)\u0026quot; } ] } final_result = None for event in agent.stream(input_payload, stream_mode=\u0026quot;updates\u0026quot;): if \u0026quot;model\u0026quot; in event: model_step = event[\u0026quot;model\u0026quot;] for message in model_step.get(\u0026quot;messages\u0026quot;, []): if message.tool_calls: for call in message.tool_calls: print(f\u0026quot;[MODEL → TOOL CALL] {call[\u0026#39;name\u0026#39;]} args={call[\u0026#39;args\u0026#39;]}\u0026quot;) if \u0026quot;tools\u0026quot; in event: tool_step = event[\u0026quot;tools\u0026quot;] for message in tool_step.get(\u0026quot;messages\u0026quot;, []): print(f\u0026quot;[TOOL RESULT] {message.content}\u0026quot;) if \u0026quot;structured_response\u0026quot; in event: final_result = event[\u0026quot;structured_response\u0026quot;].result print(\u0026quot;\\nFinal Result:\u0026quot;, final_result) O loop distingue três tipos de evento:\n\"model\": o LLM tomou uma decisão e quer chamar uma tool. \"tools\": a tool foi executada e devolveu um resultado. \"structured_response\": o agente encerrou o ciclo e emitiu a resposta final tipada. Para a expressão (sqrt(16) + pow(2,3)) / abs(-4), o agente resolve em 6 chamadas sequenciais, respeitando a ordem de precedência:\n[MODEL → TOOL CALL] sqrt args={\u0026#39;x\u0026#39;: 16} [TOOL RESULT] 4.0 [MODEL → TOOL CALL] power args={\u0026#39;base\u0026#39;: 2, \u0026#39;exponent\u0026#39;: 3} [TOOL RESULT] 8.0 [MODEL → TOOL CALL] add args={\u0026#39;a\u0026#39;: 4.0, \u0026#39;b\u0026#39;: 8.0} [TOOL RESULT] 12.0 [MODEL → TOOL CALL] absolute args={\u0026#39;x\u0026#39;: -4} [TOOL RESULT] 4.0 [MODEL → TOOL CALL] divide args={\u0026#39;a\u0026#39;: 12.0, \u0026#39;b\u0026#39;: 4.0} [TOOL RESULT] 3.0 [MODEL → TOOL CALL] round_number args={\u0026#39;x\u0026#39;: 3.0, \u0026#39;digits\u0026#39;: 2} [TOOL RESULT] 3.0 Final Result: 3.0 O resultado \\(\\frac{\\sqrt{16} + 2^3}{|-4|} = \\frac{4 + 8}{4} = 3.0\\) está correto, e cada etapa do raciocínio é rastreável. Isso é o que torna esse padrão valioso: não apenas o resultado final, mas a cadeia de decisões que levou até ele.\nPerguntas frequentes Preciso de GPU para rodar um LLM local? Não é obrigatório, mas ajuda muito. Neste post, a flag -ngl 1 do llama-server ativa o offload de camadas para a GPU via Metal em Apple Silicon. Em CPU pura o modelo ainda roda, só que mais lento.\nUm modelo quantizado (GGUF) perde muita qualidade? Alguma perda existe, mas costuma ser pequena para quantizações como q4_k_m ou q5_k_m, que equilibram tamanho e qualidade. Para tarefas bem definidas, como o agente matemático deste post, a diferença raramente é perceptível.\nDá para usar o mesmo código do LangChain com qualquer LLM local? Sim, desde que o servidor local exponha uma API compatível com a da OpenAI, como o llama-server. Basta trocar a openai_api_base e o nome do modelo; o restante do código do agente (tools, saída estruturada, streaming) permanece igual.\nConclusão O que começou como curiosidade depois de ler sobre modelos se transformou em uma stack que pode ser replicável sem necessidade de super máquinas. A combinação llama.cpp + GGUF + API OpenAI-compatible fornece um acesso a LLMs locais de um jeito que, há dois anos, seria impensável em hardware consumer.\nDá para construir um agente funcional, auditável e com saída tipada sem pagar nada, sem enviar dados para terceiros e sem depender de conexão com a internet. Para cenários onde privacidade e custo são requisitos (e isso inclui boa parte dos projetos corporativos reais) essa stack passou de curiosidade para uma opção viável. Mesmo que a empresa forneça licença para APIs pagas, bastaria mudar o modelo que toda stack continua funcional.\nO agente matemático é só um exemplo, mas o padrão LLM local + tools Python + structured output + streaming observável é a estrutura que pode ser usada em outros contextos como ferramentas de acesso a APIs internas, consulta a bases de conhecimento privadas, processamento de documentos sensíveis.\nPara outro tipo de aplicação criativa de IA, sem envolver agentes, veja o post sobre como gerar arte com DALL·E e modelos similares. Se quiser ir além e construir uma wiki consultável com RAG sobre uma pilha de documentos locais, o wiki-llm usa exatamente este padrão de LLM local.\n","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/post/2026-02-21-qwen-local-agent/","section":"Posts","summary":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing → LLM Local com Qwen sem APIs Por que rodar LLMs localmente? Nos últimos anos, o mundo dos modelos de linguagem de grande porte (LLMs) deixou de ser um território exclusivo das gigantes americanas. Uma leva de modelos open-weight de origem chinesa como o Qwen (Alibaba), o DeepSeek e o Yi chegaram com qualidade surpreendente e, mais importante, com pesos disponíveis publicamente. Li sobre alguns deles em um post que apareceu no meu LinkedIn e fiquei curioso para testar: será que dá para rodar um desses modelos localmente no meu Mac e ainda plugar ele num agente LangChain funcional?\n","title":"LLM local com Qwen e LangChain: agente sem APIs externas","type":"post"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/open-source/","section":"Tags","summary":"","title":"Open-Source","type":"tags"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/post/","section":"Posts","summary":"","title":"Posts","type":"post"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/categories/programacao-e-ferramentas/","section":"Categories","summary":"","title":"Programação E Ferramentas","type":"categories"},{"content":"","date":"26 de fevereiro de 2026","externalUrl":null,"permalink":"/tags/qwen/","section":"Tags","summary":"","title":"Qwen","type":"tags"},{"content":"Última atualização: 27 de novembro de 2025\n1. Aceitação dos Termos # Ao acessar e usar este blog, você aceita automaticamente estes termos de uso. Se não concordar com algum dos termos, por favor, não use o site.\n2. Uso Permitido # Este blog é destinado a:\nAprendizado sobre Data Science e Machine Learning Consulta a tutoriais e exemplos práticos Uso educacional e profissional do conteúdo 3. Conteúdo # 3.1 Propriedade Intelectual # Todo o conteúdo original deste blog (textos, códigos, imagens) é de propriedade do autor, salvo quando indicado de forma diferente.\n3.2 Uso do Conteúdo # ✅ Permitido: Compartilhar links para os posts ✅ Permitido: Citar trechos com devida atribuição ✅ Permitido: Usar códigos para aprendizado ❌ Proibido: Copiar conteúdo integral sem autorização ❌ Proibido: Usar conteúdo para fins comerciais sem permissão 4. Comentários e Interações # Ao comentar no blog, você se compromete a:\nManter o respeito e cordialidade Não publicar conteúdo ofensivo ou spam Não compartilhar informações pessoais sensíveis 5. Links Externos # Este blog pode conter links para sites externos. Não nos responsabilizamos pelo conteúdo ou práticas de privacidade desses sites.\n6. Publicidade # Este site pode exibir anúncios personalizados através do Google AdSense. Consulte nossa Política de Privacidade para mais informações sobre cookies e dados coletados.\n7. Isenção de Responsabilidade # O conteúdo deste blog é fornecido \u0026ldquo;como está\u0026rdquo;, sem garantias de qualquer tipo. As informações são para fins educacionais e não constituem aconselhamento profissional.\n8. Modificações # Reservamos o direito de modificar estes termos a qualquer momento. Mudanças significativas serão notificadas através do próprio blog.\n9. Contato # Para questões sobre estes termos, entre em contato através da página de contato.\n10. Lei Aplicável # Estes termos são regidos pelas leis brasileiras.\n","date":"27 de novembro de 2025","externalUrl":null,"permalink":"/termos/","section":"Fellipe Gomes","summary":"Última atualização: 27 de novembro de 2025\n1. Aceitação dos Termos # Ao acessar e usar este blog, você aceita automaticamente estes termos de uso. Se não concordar com algum dos termos, por favor, não use o site.\n2. Uso Permitido # Este blog é destinado a:\n","title":"Termos de Uso","type":"page"},{"content":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin → Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Por que analisar ligações de telemarketing com IA? Quem nunca recebeu aquela ligação de telemarketing no momento mais inoportuno? Seja oferecendo um cartão de crédito, cobrando uma dívida ou tentando vender internet, essas ligações fazem parte do nosso cotidiano. Mas você já parou para pensar na quantidade de informações valiosas que existem nessas conversas?\nPara empresas que operam call centers, analisar essas ligações manualmente é uma tarefa hercúlea. Imagine ter que ouvir centenas ou milhares de ligações por dia para:\nAvaliar a qualidade do atendimento Identificar problemas recorrentes Detectar possíveis fraudes Treinar equipes com base em casos reais Garantir compliance e conformidade legal TL;DR\nO pipeline combina Whisper (transcrição), Pyannote.audio (diarização de speakers) e LangChain com GPT da OpenAI (extração estruturada com Pydantic) para analisar ligações de telemarketing. O agente extrai automaticamente sentimento do cliente e do atendente, tipo de ligação, resultado, problemas identificados e respostas criativas, tudo em formato JSON estruturado. Em menos de 4 minutos, o pipeline processou 13 ligações e extraiu insights que levariam horas para analistas humanos descobrirem. O desafio vai além da transcrição de textos Analisar ligações de telemarketing apresenta desafios que vão muito além da simples transcrição de áudio para texto. O grande volume de dados, a necessidade de identificar corretamente quem está falando em áudios mono (onde todas as vozes estão em um único canal) e a extração de informações relevantes a partir de conversas não estruturadas tornam o processo complexo e exigem soluções especializadas.\nEntre os principais obstáculos técnicos estão: converter fala em texto com precisão mesmo diante de sotaques e ruídos, diarizar os speakers (diferenciar atendente e cliente), transformar transcrições em dados estruturados (como sentimento, tipo de ligação e problemas), além de garantir escalabilidade para processar milhares de ligações de forma eficiente, preferencialmente utilizando recursos como GPU.\nSolução técnica: Abordagem em 4 etapas Enquanto estudava para trablhar em um projeto com desafio semelhante, desenvolvi um pipeline em Python integrando três tecnologias de ponta, com foco em soluções gratuitas para estudo e prova de conceito. O projeto abrangeu desde a aquisição das ligações até a extração de insights estruturados, utilizando recursos pagos em ambiente de produção, mas priorizando ferramentas acessíveis para pesquisa e validação.\nFluxo de trabalho completo As etapas principais foram:\nColeta e preparação dos dados: Download e segmentação dos áudios com yt_dlp, pydub e ffmpeg. Transcrição dos áudios: Diarização/segmentação por locutor: Utilizando o modelo de diarização do Pyannote.audio Reconhecimento automático de fala (ASR): Modelos gratuitos do Whisper da OpenAI hospedados na Hugging Face. Análise interpretativa: Extração de informações estruturadas com GPT da OpenAI e o framework LangChain . Abordagem analítica: Exploração dos dados, criação de dashboards e, eventualmente, construção de modelos preditivos (por exemplo, prever se a venda foi concluída). Tecnologias Utilizadas:\nWhisper (OpenAI): Modelo state-of-the-art para transcrição de áudio Pyannote.audio: Framework especializado em diarização de speakers LangChain: Framework de LLMs para extração estruturada Python: Orquestração de todo o pipeline Google Colab: Ambiente com GPU gratuita Este post vai cobrir apenas a terceira etapa do pipeline: a análise interpretativa das transcrições. Vamos mostrar como transformar o texto bruto das ligações em informações estruturadas e acionáveis usando agentes de GenAI, detalhando o processo de extração automática de sentimentos, problemas, resultados e respostas criativas a partir das conversas, um tema que já explorei em outro contexto na análise de sentimentos com um LLM de código aberto.\nDados utilizados Para este experimento, selecionei alguns vídeos de esquetes de comédia sobre telemarketing disponíveis no YouTube e extraí um arquivo de áudio para cada ligação, segmentando as conversas individualmente. Veja um exemplo:\nSeu navegador não suporta áudio. A transcrição dos áudios foi realizada utilizando Whisper para reconhecimento de fala e Pyannote para diarização dos locutores. Desenvolvi um script que integra essas ferramentas utilizando recursos de GPU em ambientes como Kaggle e Google Colab, o que permite processar grandes volumes de áudio gratuitamente, uma abordagem parecida com a que usei ao criar um agente com LLM local sem depender de APIs pagas.\nVeja como ficou o resultado após a atribuição dos speakers no pós-processamento:\nSPEAKER_00: Eu gostaria de falar com o Eliel Clayton de Oliveira. SPEAKER_01: Ele não tá, tá pra fazenda. Liga amanhã, ele deixou o celular. SPEAKER_00: Ah, tudo bem. Eu posso deixar o telefone pra contato com ele no internet? Quem é você? Você é namorada dele? Não, eu sou uma da assessoria de cobrança. SPEAKER_01: Da onde? Da outra fazenda? Da fazenda Bonança? SPEAKER_00: Não, senhora. Eu sou da assessoria da bebê financeira. Ah, estavam então da Bahia, né? Vou falar pra ele que ligaram pra ele então, tá? SPEAKER_01: É da bebê financeira, assessoria da bebê financeira. SPEAKER_00: Você teve um bebê com ele? Aonde você tá, minha filha? Não, senhora, assessoria da bebê financeira. SPEAKER_01: Estão falando que tem uma mulher que tem um bebê do Eliel. SPEAKER_00: Acho melhor você ligar amanhã então, pra ver com ele, pra ver o DNA. ⚠️ Naturalmente, todo modelo de transcrição apresenta uma taxa de acerto que pode variar de acordo com a qualidade do áudio, sotaques e presença de ruídos.\nNeste post o foco está na construção do agente de análise interpretativa, assumindo que as transcrições já estão disponíveis e prontas para uso. Na versão do projeto que foi para produção, utilizamos uma ferramenta diferente para a etapa de transcrição, mas como prova de conceito até que achei o resultado bem descente.\nAnálise estruturada com Agente de GenAI É aqui que a mágica realmente acontece: com o poder do LangChain e o recurso de Structured Output, conseguimos transformar transcrições brutas de ligações em dados estruturados e acionáveis. Em vez de apenas ler textos longos e desorganizados, extraímos automaticamente sentimentos, problemas, resultados e até respostas criativas. Tudo pronto para análise, visualização ou integração com sistemas de negócio.\nSe você quer entender o que realmente acontece dentro desse \"motor de raciocínio\" que o LLM representa aqui, o Build a Large Language Model (From Scratch), do Sebastian Raschka, é o livro que mais me ajudou a enxergar por baixo do capô.\nA ideia central se baseia no conceito de saída estruturada (Pydantic models) para fornecer ferramentas que forçam o modelo a devolver um JSON consistente que depois é facilmente consumido por pipelines e dashboards.\nSchema Pydantic (Ver código) # Análise de Sentimento class SentimentoLigacao(BaseModel): \u0026quot;\u0026quot;\u0026quot;Análise de sentimento da ligação.\u0026quot;\u0026quot;\u0026quot; sentimento_cliente: Literal[\u0026quot;positivo\u0026quot;, \u0026quot;neutro\u0026quot;, \u0026quot;negativo\u0026quot;, \u0026quot;irritado\u0026quot;] sentimento_atendente: Literal[\u0026quot;profissional\u0026quot;, \u0026quot;neutro\u0026quot;, \u0026quot;agressivo\u0026quot;, \u0026quot;impaciente\u0026quot;] nivel_conflito: Literal[\u0026quot;baixo\u0026quot;, \u0026quot;medio\u0026quot;, \u0026quot;alto\u0026quot;] # Informações da Ligação class InformacaoLigacao(BaseModel): \u0026quot;\u0026quot;\u0026quot;Informações extraídas da ligação.\u0026quot;\u0026quot;\u0026quot; tipo_ligacao: Literal[\u0026quot;cobranca\u0026quot;, \u0026quot;oferta_produto\u0026quot;, \u0026quot;suporte\u0026quot;, \u0026quot;pesquisa\u0026quot;, \u0026quot;fraude\u0026quot;] empresa_mencionada: Optional[str] = None produto_servico: Optional[str] = None resultado_ligacao: Literal[\u0026quot;sucesso\u0026quot;, \u0026quot;recusa\u0026quot;, \u0026quot;desligou\u0026quot;, \u0026quot;nao_resolvido\u0026quot;, \u0026quot;fraude_detectada\u0026quot;] cliente_interessado: bool # Identificação de Problemas class ProblemaIdentificado(BaseModel): \u0026quot;\u0026quot;\u0026quot;Problemas identificados na ligação.\u0026quot;\u0026quot;\u0026quot; tem_problema: bool tipo_problema: Optional[Literal[\u0026quot;cobranca_indevida\u0026quot;, \u0026quot;cancelamento\u0026quot;, \u0026quot;atendimento_ruim\u0026quot;, \u0026quot;fraude\u0026quot;, \u0026quot;outro\u0026quot;]] = None descricao_problema: Optional[str] = None requer_followup: bool # Respostas Criativas class RespostasCriativas(BaseModel): \u0026quot;\u0026quot;\u0026quot;Respostas criativas ou inusitadas do cliente.\u0026quot;\u0026quot;\u0026quot; teve_resposta_criativa: bool tipo_resposta: Optional[Literal[\u0026quot;humor\u0026quot;, \u0026quot;desculpa_criativa\u0026quot;, \u0026quot;contra_ataque\u0026quot;, \u0026quot;confusao_proposital\u0026quot;]] = None citacao: Optional[str] = None # Schema agregador: um único resultado que engloba todos class RelatorioLigacao(BaseModel): \u0026quot;\u0026quot;\u0026quot;Relatório consolidado da ligação. Preencha apenas os blocos aplicáveis.\u0026quot;\u0026quot;\u0026quot; sentimento: Optional[SentimentoLigacao] = None informacao: Optional[InformacaoLigacao] = None problema: Optional[ProblemaIdentificado] = None respostas_criativas: Optional[RespostasCriativas] = None Para criar o agente de análise interpretativa, encapsulamos toda a configuração do modelo de linguagem, defindo o schema de saída estruturada e estabelecendo as instruções para que o agente atue como um verdadeiro especialista em ligações de telemarketing. Com essa abordagem, garantimos que apenas informações realmente presentes na transcrição sejam extraídas, tornando o processo robusto, auditável e pronto para uso em escala, ou seja, para protótipos ou aplicações em produção.\nInstanciando o agente (exemplo)\ndef instance_agent(api_key: str): model = ChatOpenAI(model=\u0026quot;gpt-4o\u0026quot;, api_key=api_key, temperature=0) agent = create_agent( model=model, tools=[], response_format=ToolStrategy( schema=RelatorioLigacao, handle_errors=True ), system_prompt=( \u0026quot;Você é um especialista em análise de ligações de telemarketing.\\n\u0026quot; \u0026quot;Dado uma transcrição, preencha somente os blocos do relatório que fizerem sentido.\\n\u0026quot; \u0026quot;- Se não houver problema, deixe \u0026#39;problema\u0026#39; como null.\\n\u0026quot; \u0026quot;- Se não houver respostas criativas, deixe \u0026#39;respostas_criativas\u0026#39; como null.\\n\u0026quot; \u0026quot;- Seja conservador: só preencha quando tiver evidência no texto.\u0026quot; ), ) return agent agent = instance_agent(api_key=OPENAI_API_KEY) result = agent.invoke({ \u0026quot;messages\u0026quot;: [{\u0026quot;role\u0026quot;: \u0026quot;user\u0026quot;, \u0026quot;content\u0026quot;: transcriptions[\u0026#39;audio_00\u0026#39;]}] }) result[\u0026quot;structured_response\u0026quot;].model_dump() Veja qual foi a saída obtida aplicando no nosso exemplo de áudio:\n{ \u0026#39;sentimento\u0026#39;: { \u0026#39;sentimento_cliente\u0026#39;: \u0026#39;irritado\u0026#39;, \u0026#39;sentimento_atendente\u0026#39;: \u0026#39;impaciente\u0026#39;, \u0026#39;nivel_conflito\u0026#39;: \u0026#39;alto\u0026#39; }, \u0026#39;informacao\u0026#39;: { \u0026#39;tipo_ligacao\u0026#39;: \u0026#39;cobranca\u0026#39;, \u0026#39;empresa_mencionada\u0026#39;: None, \u0026#39;produto_servico\u0026#39;: None, \u0026#39;resultado_ligacao\u0026#39;: \u0026#39;nao_resolvido\u0026#39;, \u0026#39;cliente_interessado\u0026#39;: False }, \u0026#39;problema\u0026#39;: None, \u0026#39;respostas_criativas\u0026#39;: { \u0026#39;teve_resposta_criativa\u0026#39;: True, \u0026#39;tipo_resposta\u0026#39;: \u0026#39;humor\u0026#39;, \u0026#39;citacao\u0026#39;: \u0026#39;Eu agora, eu tô tomando é uma Heineken, uma hora dessa. Tá entendendo?\u0026#39; } } Loop para processar todos os áudios (Ver código) extractions = {} for file_name, transcription in transcriptions.items(): analysis = agent.invoke({\u0026quot;messages\u0026quot;: [{\u0026quot;role\u0026quot;: \u0026quot;user\u0026quot;, \u0026quot;content\u0026quot;: transcription}]}) structured = analysis.get(\u0026quot;structured_response\u0026quot;) extracted = structured.model_dump() if structured is not None else None extractions[file_name] = extracted # Salvar cache da execução with open(os.path.join(path_extractions, f\u0026quot;{file_name}.json\u0026quot;), \u0026quot;w\u0026quot;, encoding=\u0026quot;utf-8\u0026quot;) as fh: json.dump(extracted, fh, ensure_ascii=False, indent=2) Insights estruturados Após processar todos os áudios podemos criar um dashboard que transforma as extrações em KPIs acionáveis, permitindo visualizar rapidamente métricas como taxa de ligações não resolvidas, distribuição dos tipos de ligação, níveis de conflito, frequência de respostas criativas e outros indicadores essenciais para tomada de decisão e melhoria contínua dos processos. Ver código do Dashboard import pandas as pd import matplotlib.pyplot as plt import seaborn as sns from matplotlib.patches import Rectangle import numpy as np # criar DataFrame a partir do dicionário de extrações df = pd.DataFrame.from_dict(extractions, orient=\u0026#39;index\u0026#39;) # garantir que campos nulos sejam tratados como dicts vazios para normalização for col in [\u0026#39;sentimento\u0026#39;, \u0026#39;informacao\u0026#39;, \u0026#39;problema\u0026#39;, \u0026#39;respostas_criativas\u0026#39;]: df[col] = df[col].apply(lambda x: x if isinstance(x, dict) else {}) # normalizar cada bloco e juntar sent_df = pd.json_normalize(df[\u0026#39;sentimento\u0026#39;]).add_prefix(\u0026#39;sentimento_\u0026#39;) info_df = pd.json_normalize(df[\u0026#39;informacao\u0026#39;]).add_prefix(\u0026#39;informacao_\u0026#39;) prob_df = pd.json_normalize(df[\u0026#39;problema\u0026#39;]).add_prefix(\u0026#39;problema_\u0026#39;) resp_df = pd.json_normalize(df[\u0026#39;respostas_criativas\u0026#39;]).add_prefix(\u0026#39;respostas_\u0026#39;) df_extractions = pd.concat([sent_df, info_df, prob_df, resp_df], axis=1) df_extractions.index = df.index df_extractions.index.name = \u0026#39;file\u0026#39; df_extractions.reset_index(inplace=True) # Configurar estilo sns.set_style(\u0026quot;white\u0026quot;) plt.rcParams.update({ \u0026#39;figure.facecolor\u0026#39;: \u0026#39;white\u0026#39;, \u0026#39;axes.facecolor\u0026#39;: \u0026#39;white\u0026#39;, \u0026#39;savefig.facecolor\u0026#39;: \u0026#39;white\u0026#39; }) sns.set_palette(\u0026quot;husl\u0026quot;) # Criar figura com subplots fig = plt.figure(figsize=(14, 12)) gs = fig.add_gridspec(4, 4, hspace=0.4, wspace=0.4) # Cores personalizadas colors_main = [\u0026#39;#FF6B6B\u0026#39;, \u0026#39;#4ECDC4\u0026#39;, \u0026#39;#45B7D1\u0026#39;, \u0026#39;#FFA07A\u0026#39;, \u0026#39;#98D8C8\u0026#39;, \u0026#39;#F7DC6F\u0026#39;] colors_sentiment = {\u0026#39;neutro\u0026#39;: \u0026#39;#95E1D3\u0026#39;, \u0026#39;irritado\u0026#39;: \u0026#39;#F38181\u0026#39;, \u0026#39;profissional\u0026#39;: \u0026#39;#4A90E2\u0026#39;} colors_conflict = {\u0026#39;baixo\u0026#39;: \u0026#39;#A8E6CF\u0026#39;, \u0026#39;medio\u0026#39;: \u0026#39;#FFD93D\u0026#39;, \u0026#39;alto\u0026#39;: \u0026#39;#FF6B6B\u0026#39;} # ============= TÍTULO PRINCIPAL ============= fig.suptitle(\u0026#39;Análise de Ligações de Telemarketing com Agent\u0026#39;, fontsize=28, fontweight=\u0026#39;bold\u0026#39;, y=0.9) # ============= 1. MÉTRICAS PRINCIPAIS (agora vem primeiro) ============= ax7 = fig.add_subplot(gs[0, :]) ax7.axis(\u0026#39;off\u0026#39;) # Calcular métricas total_ligacoes = len(df_extractions) taxa_criatividade = (df_extractions[\u0026#39;respostas_teve_resposta_criativa\u0026#39;].sum() / total_ligacoes) * 100 taxa_irritacao = (df_extractions[\u0026#39;sentimento_sentimento_cliente\u0026#39;] == \u0026#39;irritado\u0026#39;).sum() / total_ligacoes * 100 taxa_nao_resolvido = (df_extractions[\u0026#39;informacao_resultado_ligacao\u0026#39;] == \u0026#39;nao_resolvido\u0026#39;).sum() / total_ligacoes * 100 taxa_conflito_alto = (df_extractions[\u0026#39;sentimento_nivel_conflito\u0026#39;] == \u0026#39;alto\u0026#39;).sum() / total_ligacoes * 100 # Criar caixas de métricas metrics = [ (\u0026#39;Total de Ligações\u0026#39;, f\u0026#39;{total_ligacoes}\u0026#39;, \u0026#39;#4A90E2\u0026#39;), (\u0026#39;Taxa de Criatividade\u0026#39;, f\u0026#39;{taxa_criatividade:.1f}%\u0026#39;, \u0026#39;#4ECDC4\u0026#39;), (\u0026#39;Taxa de Irritação\u0026#39;, f\u0026#39;{taxa_irritacao:.1f}%\u0026#39;, \u0026#39;#FF6B6B\u0026#39;), (\u0026#39;Não Resolvidos\u0026#39;, f\u0026#39;{taxa_nao_resolvido:.1f}%\u0026#39;, \u0026#39;#FFA07A\u0026#39;), (\u0026#39;Conflito Alto\u0026#39;, f\u0026#39;{taxa_conflito_alto:.1f}%\u0026#39;, \u0026#39;#F38181\u0026#39;) ] x_positions = np.linspace(0.05, 0.85, len(metrics)) for i, (label, value, color) in enumerate(metrics): rect = Rectangle((x_positions[i], 0.25), 0.15, 0.5, facecolor=color, linewidth=3, transform=ax7.transAxes, zorder=2) ax7.add_patch(rect) ax7.text(x_positions[i] + 0.075, 0.58, value, ha=\u0026#39;center\u0026#39;, va=\u0026#39;center\u0026#39;, fontsize=22, fontweight=\u0026#39;bold\u0026#39;, color=\u0026#39;white\u0026#39;, transform=ax7.transAxes, zorder=3) ax7.text(x_positions[i] + 0.075, 0.18, label, ha=\u0026#39;center\u0026#39;, va=\u0026#39;center\u0026#39;, fontsize=11, fontweight=\u0026#39;bold\u0026#39;, transform=ax7.transAxes, zorder=3, wrap=True) # ============= 2. SENTIMENTO DO CLIENTE ============= ax1 = fig.add_subplot(gs[1, 0:2]) sentimento_counts = df_extractions[\u0026#39;sentimento_sentimento_cliente\u0026#39;].value_counts() # usar cinza para \u0026quot;neutro\u0026quot; (case-insensitive), caso contrário usar palette existente neutral_color = \u0026#39;#B0B0B0\u0026#39; colors_sent = [ neutral_color if str(x).strip().lower() == \u0026#39;neutro\u0026#39; else colors_sentiment.get(x, \u0026#39;#95E1D3\u0026#39;) for x in sentimento_counts.index ] sent_labels = [str(x).replace(\u0026#39;_\u0026#39;, \u0026#39; \u0026#39;).upper() for x in sentimento_counts.index] bars1 = ax1.bar(sent_labels, sentimento_counts.values, color=colors_sent, linewidth=2) ax1.set_title(\u0026#39;Sentimento do Cliente\u0026#39;, fontsize=16, fontweight=\u0026#39;bold\u0026#39;, pad=15) ax1.set_ylabel(\u0026#39;\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) ax1.set_xlabel(\u0026#39;\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) for bar in bars1: height = bar.get_height() ax1.text(bar.get_x() + bar.get_width()/2., height, f\u0026#39;{int(height)}\u0026#39;, ha=\u0026#39;center\u0026#39;, va=\u0026#39;bottom\u0026#39;, fontsize=14, fontweight=\u0026#39;bold\u0026#39;) ax1.grid(axis=\u0026#39;y\u0026#39;, alpha=0.3) # aumentar limite do eixo y em 5% max_h1 = max(bar.get_height() for bar in bars1) ax1.set_ylim(0, max_h1 * 1.15) # ============= 3. NÍVEL DE CONFLITO ============= ax2 = fig.add_subplot(gs[1, 2:4]) conflito_counts = df_extractions[\u0026#39;sentimento_nivel_conflito\u0026#39;].value_counts() colors_conf = [colors_conflict.get(x, \u0026#39;#A8E6CF\u0026#39;) for x in conflito_counts.index] conf_labels = [str(x).replace(\u0026#39;_\u0026#39;, \u0026#39; \u0026#39;).upper() for x in conflito_counts.index] bars2 = ax2.bar(conf_labels, conflito_counts.values, color=colors_conf, linewidth=2) ax2.set_title(\u0026#39;Nível de Conflito\u0026#39;, fontsize=16, fontweight=\u0026#39;bold\u0026#39;, pad=15) ax2.set_ylabel(\u0026#39;\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) ax2.set_xlabel(\u0026#39;\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) for bar in bars2: height = bar.get_height() ax2.text(bar.get_x() + bar.get_width()/2., height, f\u0026#39;{int(height)}\u0026#39;, ha=\u0026#39;center\u0026#39;, va=\u0026#39;bottom\u0026#39;, fontsize=14, fontweight=\u0026#39;bold\u0026#39;) ax2.grid(axis=\u0026#39;y\u0026#39;, alpha=0.3) # aumentar limite do eixo y em 5% if len(bars2) \u0026gt; 0: max_h2 = max(bar.get_height() for bar in bars2) ax2.set_ylim(0, max_h2 * 1.15) # ============= 4. TIPO DE LIGAÇÃO ============= ax3 = fig.add_subplot(gs[2, 0:2]) tipo_counts = df_extractions[\u0026#39;informacao_tipo_ligacao\u0026#39;].value_counts() explode = [0.05 if i == 0 else 0 for i in range(len(tipo_counts))] wedges, texts, autotexts = ax3.pie(tipo_counts.values, labels=tipo_counts.index, autopct=\u0026#39;%1.1f%%\u0026#39;, colors=colors_main, explode=explode, startangle=90, textprops={\u0026#39;fontsize\u0026#39;: 11}) ax3.set_title(\u0026#39;Tipo de Ligação\u0026#39;, fontsize=16, fontweight=\u0026#39;bold\u0026#39;, pad=15) for autotext in autotexts: autotext.set_color(\u0026#39;white\u0026#39;) autotext.set_fontsize(12) # ============= 5. RESULTADO DA LIGAÇÃO ============= ax4 = fig.add_subplot(gs[2, 2:4]) resultado_counts = df_extractions[\u0026#39;informacao_resultado_ligacao\u0026#39;].value_counts() res_labels = [str(x).replace(\u0026#39;_\u0026#39;, \u0026#39; \u0026#39;).upper() for x in resultado_counts.index] bars4 = ax4.barh(res_labels, resultado_counts.values, color=colors_main[:len(resultado_counts)], linewidth=2) ax4.set_title(\u0026#39;Resultado da Ligação\u0026#39;, fontsize=16, fontweight=\u0026#39;bold\u0026#39;, pad=15) ax4.set_xlabel(\u0026#39;\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) for i, bar in enumerate(bars4): width = bar.get_width() ax4.text(width, bar.get_y() + bar.get_height()/2., f\u0026#39; {int(width)}\u0026#39;, ha=\u0026#39;left\u0026#39;, va=\u0026#39;center\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) ax4.grid(axis=\u0026#39;x\u0026#39;, alpha=0.3) # ============= 6. RESPOSTAS CRIATIVAS ============= ax5 = fig.add_subplot(gs[3, 0:2]) criativas_counts = df_extractions[\u0026#39;respostas_teve_resposta_criativa\u0026#39;].fillna(False).astype(bool).value_counts() counts5 = [criativas_counts.get(True, 0), criativas_counts.get(False, 0)] labels5 = [\u0026#39;Com Resposta\\nCriativa\u0026#39;, \u0026#39;Sem Resposta\\nCriativa\u0026#39;] colors_criativas = [\u0026#39;#4ECDC4\u0026#39;, \u0026#39;#FF6B6B\u0026#39;] wedges5, texts5, autotexts5 = ax5.pie(counts5, labels=labels5, autopct=\u0026#39;%1.1f%%\u0026#39;, colors=colors_criativas, startangle=90, textprops={\u0026#39;fontsize\u0026#39;: 12}) ax5.set_title(\u0026#39;Respostas Criativas\u0026#39;, fontsize=16, fontweight=\u0026#39;bold\u0026#39;, pad=15) for autotext in autotexts5: autotext.set_color(\u0026#39;white\u0026#39;) autotext.set_fontsize(13) # ============= 7. TIPOS DE RESPOSTA CRIATIVA ============= ax6 = fig.add_subplot(gs[3, 2:4]) tipo_resposta = df_extractions[\u0026#39;respostas_tipo_resposta\u0026#39;].dropna().value_counts() tipo_labels = [str(x).replace(\u0026#39;_\u0026#39;, \u0026#39; \u0026#39;).upper() for x in tipo_resposta.index] bars6 = ax6.barh(tipo_labels, tipo_resposta.values, color=colors_main[:len(tipo_resposta)], linewidth=2) ax6.set_title(\u0026#39;Tipos de Resposta Criativa\u0026#39;, fontsize=16, fontweight=\u0026#39;bold\u0026#39;, pad=15) ax6.set_xlabel(\u0026#39;\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) for i, bar in enumerate(bars6): width = bar.get_width() ax6.text(width, bar.get_y() + bar.get_height()/2., f\u0026#39; {int(width)}\u0026#39;, ha=\u0026#39;left\u0026#39;, va=\u0026#39;center\u0026#39;, fontsize=12, fontweight=\u0026#39;bold\u0026#39;) ax6.grid(axis=\u0026#39;x\u0026#39;, alpha=0.3) plt.show() Fluxo de trabalho completo Benefícios Práticos e ROI Mensurável Para equipes que operam call centers e compliance, os ganhos são claros:\nAutomação de QA (Análise de 100% das ligações vs. amostragem manual); Redução drástica no tempo de análise; Detecção precoce de problemas e fraudes; Treinamento baseado em casos reais e dados; Evidências estruturadas para auditoria; KPIs em tempo real e otimização de scripts (A/B testing). Para empresas, isso significa decisões mais rápidas, menos custos com retrabalho e ROI tangível na operação.\nÉtica, licença e privacidade O dataset aqui usado é público (sketches de comédia) e foi apenas para fins pessoal/educacional. Para qualquer uso comercial:\nVerifique licença dos materiais originais; Obtenha consentimento quando necessário; Anonimizar dados pessoais; Adotar práticas de privacidade e conformidade (LGPD / GDPR). Conclusão: O futuro da análise de conversas O que começou como um experimento com ligações de telemarketing se transformou em uma demonstração poderosa do que é possível quando combinamos as melhores tecnologias de IA disponíveis hoje. Em menos de 4 minutos, processamos 13 ligações e extraímos insights que levariam horas para analistas humanos descobrirem.\nRecursos adicionais Tutoriais Complementares:\nMeu post sobre Agentes Multiagente - LangChain em ação Detecção de Linguagem Tóxica - LLMs para análise de texto Análise de Sentimentos com LLM - Processamento de linguagem natural Perguntas frequentes Quais tecnologias compõem o pipeline de análise de ligações de telemarketing?\nO pipeline combina Whisper da OpenAI para transcrição, Pyannote.audio para diarização de speakers e LangChain com GPT para extração estruturada, orquestrados em Python usando GPU gratuita no Google Colab.\nQue tipo de informação o agente de GenAI extrai das ligações?\nUsando schemas Pydantic, o agente extrai sentimento do cliente e do atendente, tipo de ligação, resultado, problemas identificados e respostas criativas, tudo em formato JSON estruturado.\nQuanto tempo o pipeline levou para processar as ligações de teste?\nEm menos de 4 minutos, o pipeline processou 13 ligações e extraiu insights que levariam horas para analistas humanos descobrirem manualmente.\n","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/post/2025-10-26-telemarketing-agent/","section":"Posts","summary":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin → Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Por que analisar ligações de telemarketing com IA? Quem nunca recebeu aquela ligação de telemarketing no momento mais inoportuno? Seja oferecendo um cartão de crédito, cobrando uma dívida ou tentando vender internet, essas ligações fazem parte do nosso cotidiano. Mas você já parou para pensar na quantidade de informações valiosas que existem nessas conversas?\n","title":"Análise de ligações de telemarketing com Whisper e LangChain","type":"post"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/call-center/","section":"Tags","summary":"","title":"Call-Center","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/gpt-4/","section":"Tags","summary":"","title":"Gpt-4","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/nlp/","section":"Tags","summary":"","title":"Nlp","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/sentiment-analysis/","section":"Tags","summary":"","title":"Sentiment-Analysis","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/speech-to-text/","section":"Tags","summary":"","title":"Speech-to-Text","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/telemarketing/","section":"Tags","summary":"","title":"Telemarketing","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/categories/texto-e-nlp/","section":"Categories","summary":"","title":"Texto E NLP","type":"categories"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/voice-analytics/","section":"Tags","summary":"","title":"Voice-Analytics","type":"tags"},{"content":"","date":"26 de novembro de 2025","externalUrl":null,"permalink":"/tags/whisper/","section":"Tags","summary":"","title":"Whisper","type":"tags"},{"content":"","date":"4 de maio de 2025","externalUrl":null,"permalink":"/tags/analise-dados/","section":"Tags","summary":"","title":"Analise-Dados","type":"tags"},{"content":"","date":"4 de maio de 2025","externalUrl":null,"permalink":"/tags/crypto/","section":"Tags","summary":"","title":"Crypto","type":"tags"},{"content":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma → Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Por que Analisar o Mercado Bitcoin com Agentes de IA? O cenário do bitcoin sempre foi meio intrigante. Foi lançado há 16 anos mas até hoje ninguém sabe ao certo quem está por trás do projeto — o criador, conhecido apenas pelo pseudônimo Satoshi Nakamoto, nunca revelou sua identidade. Além disso o bitcoin foi a primeira e ainda é a mais conhecida aplicação da tecnologia Blockchain, que revolucionou a forma como lidamos com registros digitais e segurança dos dados. Sua natureza descentralizada e sua notória volatilidade o tornam um ativo único.\nQuem não se lembra da história das pizzas compradas por 10.000 BTC, que hoje valeriam uma fortuna? Mesmo que variações dessa magnitude sejam improváveis, eventos programados como o Halving – que reduz pela metade a emissão de novas moedas a cada quatro anos, simulando a escassez de metais preciosos – continuam a impactar significativamente sua oferta e, historicamente, seu preço.\nMas como saber o momento certo de comprar ou vender? A resposta não é simples. O preço do Bitcoin é influenciado por uma miríade de fatores: dados on-chain (movimentações na própria blockchain), o cenário macroeconômico global (inflação, taxas de juros), o sentimento do mercado e a análise técnica tradicional (padrões gráficos e indicadores). Analisar isoladamente qualquer um desses aspectos oferece uma visão incompleta. A verdadeira compreensão exige uma abordagem holística, combinando diferentes perspectivas.\nTL;DR\nA equipe de agentes de IA é dividida em 4 papéis: Data Fetcher, Data Analyst, Market Strategist e Client Manager, cada um com uma função específica no fluxo. A orquestração usa Python, LangChain, LangGraph e GPT-4o-mini como motor de raciocínio, com execução automatizada via GitHub Actions a cada 4 horas. Alertas com a análise final são enviados via Telegram, e o LangSmith é usado para monitorar e depurar cada passo da execução dos agentes. Se quiser ver como a análise de Bitcoin evoluiu, confira também a abordagem puramente estatística em R de 2017 e o bot de alertas com ML de 2020 — a diferença de complexidade vs. poder analítico é visível.\nFoi pensando nisso, e inspirado pelos recentes avanços em modelos de linguagem grandes (LLMs) e frameworks de agentes, que surgiu a ideia: E se eu delegar essa tarefa repetitiva e complexa a uma equipe de assistentes de IA? E se a IA pudesse não apenas coletar e analisar os dados, mas também interpretar o cenário e sugerir ações alinhadas a uma estratégia de investimento de longo prazo, como a acumulação gradual de Bitcoin?\nÉ aqui que entram os Agentes de IA. Pense neles como sistemas autônomos que utilizam um LLM (como os modelos GPT da OpenAI) como seu “cérebro” ou motor de raciocínio. Eles podem interagir com ferramentas, processar informações e tomar decisões para atingir um objetivo específico. Em nosso caso, o objetivo será fornecer uma análise de mercado inteligente e automatizada, transformando dados brutos em insights acionáveis de alto nível. Se você quiser rodar esse tipo de agente sem depender de APIs pagas, também explorei como criar um agente com LLM local em um post posterior.\nSe esse conceito de LLM como \"cérebro\" ainda parece abstrato, o Hands-On Large Language Models tem as ilustrações que mais me ajudaram a visualizar o que tá rolando por trás.\nArquitetura da Solução: Uma Equipe de Agentes de IA Generativa Em vez de um único agente monolítico tentando fazer tudo, o trabalho foi dividido em etapas lógicas, cada uma atribuída a um agente com um papel bem definido. Essa abordagem modular não só organiza melhor o processo, mas também facilita a manutenção e a evolução de cada componente:\nEsse tipo de decisão de arquitetura é o que o AI Engineering, da Chip Huyen, discute bem: como estruturar um sistema de IA generativa de verdade, não só um script que funciona uma vez.\nData Fetcher: Coleta dados brutos de diversas APIs (cotações, on-chain, macro, técnicos). Data Analyst: Interpreta os dados brutos e gera um relatório técnico formatado. Market Strategist: Sintetiza a análise técnica, identifica tendências e gera recomendações táticas. Client Manager: Avalia a estratégia sob a ótica do objetivo do “cliente” (acumulação de longo prazo) e decide se um alerta é necessário. Esses agentes utilizam tools (funções Python) para acessar APIs como Blockchain.com, Yahoo Finance, CoinGecko, FRED, etc. A orquestração é feita com o GitHub Actions que aciona a execução de todo o fluxo de trabalho todo dia - a cada 4 horas - executando o projeto que foi todo escrito em Python, LangChain (para os blocos de construção dos agentes), LangGraph (para o fluxo de trabalho), usando GPT-4o-mini como motor de raciocínio, Telegram como um canal para envio de alertas e LangSmith para monitoramento e depuração de cada passo da execução dos agentes.\n📌 Clique aqui para ler meu post sobre como criar bots no Telegram. Fluxo de trabalho completo Construindo o Workflow com LangGraph Para orquestrar a interação entre os agentes de forma robusta, foi utilizado o LangGraph, uma biblioteca sobre o LangChain para criar aplicações LLM stateful e com múltiplos atores. Ele permite definir fluxos de trabalho como grafos, controlando explicitamente a sequência e permitindo futuras ramificações ou ciclos.\n📌 Os conceitos básicos são:\nNós (Nodes): As unidades de trabalho (nossos agentes). Arestas (Edges): As conexões que definem o fluxo de dados e controle entre os nós. Montar o grafo envolve definir o estado compartilhado, adicionar os nós e conectar as arestas. LangGraph oferece diferentes maneiras de definir essa estrutura. Abaixo, tem um exemplo conceitual usando tanto a a GraphAPI, que é bastante explícita, quanto a Functional API, que é mais direta ao ponto:\nGraph API (Conceitual) Functional API (Conceitual)\nfrom langgraph.graph import StateGraph, START, END from typing_extensions import TypedDict # Definir o Estado do Grafo class State(TypedDict): topic: str # Input do Data Fetcher raw_data: str # Saída do Data Fetcher analysis_report: str # Saída do Data Analyst strategy_synthesis: str # Saída do Market Strategist manager_decision: str # Saída do Client Manager # Definir os Nós (Agentes/Funções) # Supondo que as funções já foram definidas def data_fetcher(state: State): # ... return {\u0026quot;raw_data\u0026quot;: \u0026quot;dados coletados...\u0026quot;} def data_analyst(state: State): ... def market_strategist(state: State): ... def client_manager(state: State): ... def send_telegram_message(message_body): ... # Construir o Grafo workflow = StateGraph(State) # Adicionar os nós workflow.add_node(\u0026quot;fetcher\u0026quot;, data_fetcher) workflow.add_node(\u0026quot;analyst\u0026quot;, data_analyst) workflow.add_node(\u0026quot;strategist\u0026quot;, market_strategist) workflow.add_node(\u0026quot;manager\u0026quot;, client_manager) # Definir Arestas (o fluxo sequencial) workflow.add_edge(START, \u0026quot;fetcher\u0026quot;) workflow.add_edge(\u0026quot;fetcher\u0026quot;, \u0026quot;analyst\u0026quot;) workflow.add_edge(\u0026quot;analyst\u0026quot;, \u0026quot;strategist\u0026quot;) workflow.add_conditional_edges(\u0026quot;strategist\u0026quot;, manager_decision, { \u0026quot;ALERTAR_CLIENTE\u0026quot;: \u0026quot;send_telegram_message\u0026quot;, \u0026quot;NAO_ALERTAR\u0026quot;: END }) # Compilar o grafo em um objeto executável chain = workflow.compile() # Executar (exemplo) state = chain.invoke({\u0026quot;topic\u0026quot;: \u0026quot;btc\u0026quot;}) from langgraph.func import entrypoint, task # Tasks/Agents @task def data_fetcher(topic: str) -\u0026gt; dict: ... @task def data_analyst(state: State): ... @task def market_strategist(state: State): ... @task def client_manager(state: State): ... def plot_btc_analysis(): ... def send_telegram_photo(fig): ... def send_telegram_message(message_body): ... # Exemplo conceitual com abordagem funcional (usando decoradores) @entrypoint() def chaining_workflow(topic: str): data_fetched = data_fetcher(topic).result() analyst_report = data_analyst(data_fetched).result() strategist_report = market_strategist(analyst_report).result() if \u0026#39;ALERTAR\u0026#39; in client_manager(strategist_report).result(): fig = plot_btc_analysis() asyncio.run(send_telegram_photo(fig)) asyncio.run(send_telegram_message(strategist_report)) return \u0026quot;Entrar em contato\u0026quot; return \u0026quot;Não entrar em contato\u0026quot; def run_chaining_workflow(topic: str, stream_mode: str = \u0026quot;updates\u0026quot;): return chaining_workflow.stream(topic, stream_mode=stream_mode) # Invoke logger.info(\u0026quot;Iniciando o workflow...\\n\u0026quot;) for step in run_chaining_workflow(\u0026quot;\u0026quot;, stream_mode=\u0026quot;updates\u0026quot;): for key, value in step.items(): logger.info(f\u0026quot;[ {key} ]\\n{\u0026#39;=\u0026#39; * 80}\\n{value}\\n\u0026quot;) logger.info(\u0026quot;Workflow finalizado.\u0026quot;) Este controle fino do fluxo, seja pela API explícita ou por abordagens mais funcionais, é uma das grandes vantagens do LangGraph para sistemas multi-agentes, que ainda permite uma integração com o LangSmith para acompanhamento detalhado do fluxo de “raciocínio” dos agentes. Para mais detalhes, consulte a documentação oficial.\nMergulhando nos Agentes: Prompts e Ferramentas Vamos ver rapidamente como cada agente funciona, focando nos prompts e ferramentas:\nAgente 1: Data Fetcher (O Pesquisador) Fluxo de trabalho do Data Researcher Ver código from pydantic import BaseModel, Field from langchain.schema.messages import HumanMessage, ToolMessage from langgraph.func import task from langchain_openai import ChatOpenAI from tools.fetch_data_btc import fetch_data_btc from tools.fetch_data_onchain import fetch_data_onchain from tools.fetch_data_macroeconomic import fetch_data_macroeconomic from tools.fetch_data_market import fetch_data_market from tools.fetch_data_tecnical import fetch_data_tecnical llm = ChatOpenAI(model=\u0026quot;gpt-4o-mini\u0026quot;, temperature=0) @task def data_fetcher(topic: str): class StructuredJsonOutput(BaseModel): btc_data: str = Field(None, description=\u0026quot;Bitcoin data and USD to BRL exchange rate\u0026quot;) onchain_data: str = Field(None, description=\u0026quot;On-chain Bitcoin data\u0026quot;) macroeconomic_data: str = Field(None, description=\u0026quot;Macroeconomic data\u0026quot;) market_data: str = Field(None, description=\u0026quot;Market sentiment and Bitcoin-related metrics\u0026quot;) tecnical_data: str = Field(None, description=\u0026quot;technical analysis indicators for Bitcoin\u0026quot;) structured_llm = llm.with_structured_output(StructuredJsonOutput) instructions = \u0026quot;Você é um pesquisador responsável por coletar dados de diferentes fontes sobre o mercado de Bitcoin e gerar um output no formato json.\u0026quot; tools = [ fetch_data_btc, fetch_data_onchain, fetch_data_macroeconomic, fetch_data_market, fetch_data_tecnical ] tools_by_name = {tool.name: tool for tool in tools} llm_with_tools = llm.bind_tools(tools) messages = [HumanMessage(instructions)] ai_msg = llm_with_tools.invoke(messages) messages.append(ai_msg) for tool_call in ai_msg.tool_calls: selected_tool = tools_by_name[tool_call[\u0026quot;name\u0026quot;].lower()] tool_output = selected_tool.invoke(tool_call[\u0026quot;args\u0026quot;]) messages.append(ToolMessage(tool_output, tool_call_id=tool_call[\u0026quot;id\u0026quot;])) messages.append(structured_llm.invoke(messages)) return messages[-1].model_dump_json(indent=3) Objetivo: Coletar dados brutos e atualizados de diversas fontes sobre o Bitcoin, abrangendo cotações, indicadores on-chain, dados macroeconômicos e técnicos. Funcionamento: Este agente não calcula nem interpreta, ele apenas orquestra a chamada de várias tools (funções Python que interagem com APIs externas). Essa função do LangChain permite que o LLM, ao receber a instrução inicial (“colete os dados sobre o mercado de Bitcoin”), analise as ferramentas disponíveis e decida quais delas chamar e com quais argumentos. Após as ferramentas retornarem seus resultados, usamos llm.with_structured_output(StructuredJsonOutput) para instruir o LLM a consolidar todas as informações coletadas em um único objeto JSON estruturado. Isso garante que a saída do Data Fetcher seja consistente e fácil de processar pelo próximo agente. Agente 2: Data Analyst (O Intérprete) Fluxo de trabalho do Data Analyst Ver código from langgraph.func import task from langchain.prompts import ChatPromptTemplate, FewShotChatMessagePromptTemplate from langchain_openai import ChatOpenAI from prompts.data_analyst_example import input_example, output_example llm = ChatOpenAI(model=\u0026quot;gpt-4\u0026quot;, temperature=0.7) @task def data_analyst(report: str): input = f\u0026quot;\u0026quot;\u0026quot; Você é um analista financeiro experiente em Cryptomoedas e especialista em Bitcoin. Analise as tendências do cenário do Bitcoin hoje com base no json \\ delimitado por três crases (```): \\``` {report} \\``` Siga rigorosamente as instruções abaixo: - ... \u0026quot;\u0026quot;\u0026quot; examples = [ {\u0026quot;input\u0026quot;: input_example, \u0026quot;output\u0026quot;: output_example}, ] example_prompt = ChatPromptTemplate.from_messages([ (\u0026quot;human\u0026quot;, \u0026quot;{input}\u0026quot;), (\u0026quot;ai\u0026quot;, \u0026quot;{output}\u0026quot;), ]) few_shot_prompt = FewShotChatMessagePromptTemplate( example_prompt=example_prompt, examples=examples, ) prompt_system = \u0026quot;Você é um analista financeiro experiente em Criptomoedas e especialista em Bitcoin.\u0026quot; final_prompt = ChatPromptTemplate.from_messages([ (\u0026quot;system\u0026quot;, prompt_system), few_shot_prompt, (\u0026quot;human\u0026quot;, \u0026quot;{input}\u0026quot;), ]) chain = final_prompt | llm msg = chain.invoke(input=input) return msg.content Objetivo: Receber o JSON de dados brutos do Data Fetcher e transformá-lo em um relatório analítico coeso, formatado em Markdown, interpretando cada indicador e explicando seu possível impacto. Prompt Engineering em Ação: Este agente é um ótimo exemplo de como guiar um LLM para tarefas complexas de formatação e interpretação. Instruções Detalhadas: O prompt define explicitamente o papel do agente (“analista financeiro experiente”), o formato desejado (Markdown, bullet points, negrito), o tom (“equilibrado e menos técnico”), e regras específicas (mencionar preços em USD e BRL, usar sinal de menos para variações negativas, seguir a estrutura do exemplo). Estratégia Few-Shot: Para garantir que o LLM siga o formato e o estilo de interpretação desejados, utilizamos a técnica Few-Shot (semelhante como fiz em um post anterior). Fornecemos um exemplo completo de um input (um JSON de dados similar ao que o Data Fetcher produziria) e o output correspondente (o relatório em Markdown formatado e interpretado). Isso é feito usando FewShotChatMessagePromptTemplate do LangChain, que insere o exemplo diretamente no contexto do prompt final. Cadeia LCEL: O prompt final é construído usando a LangChain Expression Language (LCEL), combinando o prompt do sistema (definindo o papel), o prompt Few-Shot (com o exemplo) e o prompt humano (contendo as instruções e o JSON de dados brutos atual). Agente 3: Market Strategist (O Conselheiro) Fluxo de trabalho do Market Strategist Ver código from langgraph.func import task from langchain.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI llm = ChatOpenAI(temperature=0.7) @task def market_strategist(analyst_report: str): \u0026quot;\u0026quot;\u0026quot; Gera recomendações de posicionamento com base na análise do Data Analyst. \u0026quot;\u0026quot;\u0026quot; input = f\u0026quot;\u0026quot;\u0026quot; Seu papel é analisar o relatório técnico fornecido no formatado em Markdown e transformar\\ em uma síntese estratégica e executiva, com alertas, insights e orientações táticas de alto nível. \\``` markdown {analyst_report} \\``` Siga rigorosamente as instruções abaixo: - ... \u0026quot;\u0026quot;\u0026quot; prompt = ChatPromptTemplate.from_messages([ (\u0026quot;system\u0026quot;, \u0026quot;Você é um estrategista de mercado sênior, com ampla experiência em ativos digitais e especialização em Bitcoin.\u0026quot;), (\u0026quot;human\u0026quot;, \u0026quot;{input}\u0026quot;) ]) chain = prompt | llm msg = chain.invoke(input=input) return msg.content Objetivo: Ler o relatório técnico detalhado do Data Analyst e interpretar as informações em uma síntese estratégica e executiva. O foco é identificar a tendência geral, destacar sinais chave e fornecer recomendações táticas claras. Prompt: O prompt para este agente é crucial para mudar o nível da análise. Ele instrui o LLM a agir como um “estrategista de mercado sênior”, focando em: Resumo: Extrair os pontos mais críticos. Tendência: Classificar o mercado (alta, baixa, neutro). Sinais: Identificar indicadores de otimismo ou cautela. Recomendações: Gerar orientações práticas e acionáveis (“isso indica que…”, “logo, é prudente…”). Raciocínio: Explicitar o processo de pensamento com CoT (Chain-of-Thought) que levou às conclusões antes de apresentar a síntese final. Tom: Consultivo, direto e profissional. Agente 4: Client Manager (O Porteiro) Fluxo de trabalho do Client Manager Ver código from langgraph.func import task from langchain.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI llm = ChatOpenAI(temperature=0.7) @task def client_manager(final_report: str): \u0026quot;\u0026quot;\u0026quot; Avalia o relatório estratégico e decide se deve ou não alertar o cliente. A decisão final é binária: ALERTAR_CLIENTE ou NÃO_ALERTAR. \u0026quot;\u0026quot;\u0026quot; input = f\u0026quot;\u0026quot;\u0026quot; Objetivo do cliente: Acumular Bitcoins no longo prazo, investindo mensalmente nas melhores janelas de oportunidade. Seu papel é avaliar o relatório abaixo e decidir se há motivos suficientes para alertar o cliente: \\``` markdown {final_report} \\``` Siga rigorosamente as instruções abaixo: - ... \u0026quot;\u0026quot;\u0026quot; prompt = ChatPromptTemplate.from_messages([ (\u0026quot;system\u0026quot;, \u0026quot;Você é um Client Manager, especializado em comunicação estratégica com clientes de alto valor.\u0026quot;), (\u0026quot;human\u0026quot;, \u0026quot;{input}\u0026quot;) ]) chain = prompt | llm msg = chain.invoke(input=input) return msg.content Objetivo: Avaliar a síntese estratégica do Market Strategist à luz do objetivo específico do cliente (acumulação de longo prazo) e tomar uma decisão binária: a situação atual justifica um alerta ou não? Prompt: Este prompt é focado na tomada de decisão. Contexto do Cliente: Define claramente o objetivo (“Acumular Bitcoins no longo prazo, investindo mensalmente nas melhores janelas de oportunidade.”). Critérios de Alerta: Especifica o que procurar (mudança relevante de tendência, risco/oportunidade claros, indicadores extremos, recomendações urgentes). Raciocínio Obrigatório: Exige que o agente explique seu processo de pensamento CoT (Chain-of-Thought) antes da decisão final. Output Binário: A resposta final deve ser apenas a palavra ALERTAR ou NÃO_ALERTAR em maiúsculas, precedida pelo raciocínio. Desafios, Aprendizados e Observabilidade Construir agentes envolve desafios:\nPrompt Engineering: É uma arte iterativa. Clareza, exemplos (Few-Shot) e estrutura são essenciais. Orquestração (LangGraph): Gerenciar o estado e o fluxo entre nós exige atenção. Integração de Ferramentas: Descrições claras das tools são vitais para o LLM usá-las corretamente. Observabilidade: Identificar falhas em fluxos complexos pode ser difícil. Ferramentas como o LangSmith são extremamente úteis na monitoramento dos agentes, permitindo rastrear e depurar cada passo de sua execução, chamadas de LLM e uso de ferramentas. Ele oferece uma visão clara do que está acontecendo “por baixo dos panos”, facilitando a identificação de gargalos ou erros.\nPrint da tela do LangSmith do projeto Conclusão Criamos uma equipe de agentes IA capaz de automatizar a complexa análise do mercado Bitcoin, usando LangChain e LangGraph para orquestração. O sistema coleta dados, interpreta, gera estratégias e decide sobre alertas, transformando dados brutos em insights acionáveis. Veja como é o alerta recebido no Telegram:\nPrint das telas do bot no Telegram. Este projeto demonstra o potencial dos agentes para automatizar tarefas repetitivas que envolvem a tomada de decisões com um certo “raciocínio”. Os próximos passos podem envolver refinar prompts, adicionar mais ferramentas, integrar mais visualizações ou implementar notificações ativas.\nQuer ver o resultado final em produção? A equipe de agentes deste post alimenta a Bitcoin Debrief, uma newsletter diária automatizada com análise de mercado Bitcoin direto na sua caixa de entrada às 6h.\nReferências LangChain - Documentação LangGraph - Documentação LangSmith - Documentação OpenAI API Plataform OpenAI - Prompt Engineering Guide OpenAI - A Practical Guide to Building Agents LangGraph Tutorial - Building Agentic Workflows LangChain Blog - How to think about agent frameworks Perguntas frequentes Quais agentes compõem a equipe de análise do Bitcoin? São quatro agentes: Data Fetcher (coleta dados brutos), Data Analyst (interpreta e gera relatório técnico), Market Strategist (sintetiza tendências e recomendações) e Client Manager (decide se um alerta deve ser enviado).\nQuais tecnologias foram usadas para orquestrar os agentes? O projeto usa Python, LangChain para os blocos de construção dos agentes, LangGraph para o fluxo de trabalho, GPT-4o-mini como motor de raciocínio, GitHub Actions para execução automatizada e LangSmith para monitoramento.\nComo o sistema envia os alertas gerados pela análise? Os alertas com a síntese estratégica são enviados por um bot do Telegram, sempre que o agente Client Manager decide que a situação justifica notificar o cliente.\n","date":"4 de maio de 2025","externalUrl":null,"permalink":"/post/2025-05-04-bitcoin-agent/","section":"Posts","summary":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma → Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Por que Analisar o Mercado Bitcoin com Agentes de IA? O cenário do bitcoin sempre foi meio intrigante. Foi lançado há 16 anos mas até hoje ninguém sabe ao certo quem está por trás do projeto — o criador, conhecido apenas pelo pseudônimo Satoshi Nakamoto, nunca revelou sua identidade. Além disso o bitcoin foi a primeira e ainda é a mais conhecida aplicação da tecnologia Blockchain, que revolucionou a forma como lidamos com registros digitais e segurança dos dados. Sua natureza descentralizada e sua notória volatilidade o tornam um ativo único.\n","title":"Equipe Multiagente com LangChain e LangGraph para Análise do Bitcoin","type":"post"},{"content":"","date":"4 de maio de 2025","externalUrl":null,"permalink":"/tags/inteligencia-artificial/","section":"Tags","summary":"","title":"Inteligencia-Artificial","type":"tags"},{"content":"","date":"4 de maio de 2025","externalUrl":null,"permalink":"/tags/langgraph/","section":"Tags","summary":"","title":"Langgraph","type":"tags"},{"content":"","date":"4 de maio de 2025","externalUrl":null,"permalink":"/tags/langsmith/","section":"Tags","summary":"","title":"Langsmith","type":"tags"},{"content":"","date":"4 de maio de 2025","externalUrl":null,"permalink":"/tags/mercado-financeiro/","section":"Tags","summary":"","title":"Mercado-Financeiro","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/acessibilidade/","section":"Tags","summary":"","title":"Acessibilidade","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/aprendizado-de-maquina/","section":"Tags","summary":"","title":"Aprendizado-De-Maquina","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/audio/","section":"Tags","summary":"","title":"Audio","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/audiobook/","section":"Tags","summary":"","title":"Audiobook","type":"tags"},{"content":" Por que Audiobooks? O Que São Audiobooks Criados com IA? Como criar seu audiobook com IA Preparar o arquivo de texto Traduzir conteúdo para PT-BR (opcional) Convertendo o Texto em Áudio com IA FAQ Questões de Ética e Legalidade Conclusão Por que Audiobooks? Pela sua forma conveniente de consumir conhecimento e entretenimento, os audiobooks estão se tornando cada vez mais populares. Conforme a última pesquisa da Câmara Brasileira do Livro, os livros digitais cresceram 15% de 2021 para 2022. Dentre os 13 mil títulos digitais publicados em 2022, 12% eram audiolivros. Embora o livro físico sempre vá existir, nem sempre temos o tempo necessário para ler todas as obras de nossa lista.\nAdquiri o hábito de ouvir audiobooks há quase 10 anos, especialmente enquanto realizo tarefas que não exigem atenção plena, como dirigir, pedalar, malhar ou até mesmo em tarefas domésticas. Hoje em dia existem muitas opções de plataformas para consumir conteúdo em áudio no mercado, incluindo opções gratuitas disponíveis na internet. No entanto, com o passar do tempo, já me peguei diversas vezes escolhendo um título aleatório, pois não encontrava os livros que realmente queria ouvir. Entendo que para criar um audiobook de qualidade pode ser um processo caro e demorado, mas, felizmente, os avanços da inteligência artificial (IA) trouxeram novas possibilidades e foi então que comecei a pesquisar formas acessíveis e eficientes de converter livros do meu interesse em audiobooks utilizando IA.\nNeste post, compartilharei o método mais eficaz que encontrei após extensas pesquisas sobre como transformar qualquer texto em um áudio com alta qualidade, utilizando ferramentas de IA gratuitas. Abordaremos um mini-projeto desde a preparação do arquivo de texto até a geração do áudio final. É mais uma aplicação prática de IA generativa, na mesma linha de outros posts em que explorei a extração de informações de imagens com IA generativa e a geração de arte com inteligência artificial.\nTL;DR\nO pipeline: extrair o texto (PDF/EPUB/HTML) → traduzir se necessário → converter em áudio com TTS. A biblioteca edge-tts (gratuita) entrega vozes naturais em português, como a pt-BR-AntonioNeural. Sempre confira os direitos autorais do livro antes de converter e distribuir. O Que São Audiobooks Criados com IA? Audiobooks gerados com IA utilizam ferramentas de text-to-speech (TTS) para converter texto em áudio. Diferentemente das gravações tradicionais, que dependem de narradores humanos, os audiobooks com IA são criados digitalmente por meio de modelos avançados que geram vozes cada vez mais naturais. Essa abordagem apresenta algumas vantagens e desvantagens em relação às gravações convencionais:\n✅ Vantagens:\nEconomia de tempo: O processo é automatizado e muito mais rápido Acessibilidade: Permite adaptar conteúdos para diferentes idiomas e públicos, como pessoas com deficiência visual tenham acesso a mais conteúdo Personalização: Possibilidade de escolher vozes que melhor atendam ao estilo ou objetivo da leitura ❌ Desvantagens:\nFalta de emoção e naturalidade: Podem soar robóticas ou sem a entonação expressiva de um narrador humano Dificuldade com palavras complexas e entonação: Pronuncias de nomes próprios, termos técnicos ou palavras estrangeiras de forma inadequada Limitações na adaptação do texto: Narrativas que exigem pausas dramáticas ou interpretações específicas, a IA pode não captar nuances essenciais para a experiência do ouvinte Embora os audiobooks gerados por IA sejam uma solução prática e acessível, eles ainda não substituem completamente a qualidade e a emoção transmitidas por um narrador profissional. A escolha entre um audiobook tradicional ou criado por IA dependerá da sua necessidade e da disponibilidade.\nComo criar seu audiobook com IA O primeiro passo para criar um audiobook é organizar o conteúdo que será convertido em áudio, garantindo que esteja bem formatado. Os formatos de arquivo mais comuns incluem:\nPDF: Formato mais comum de livros e também o que pode ser o mais trabalhoso por conter elementos como rodapés, numeração de páginas e títulos que precisam ser tratados de maneira diferente para cada livro. EPUB: Formato mais comum para eBooks que contém formatação rica e relativamente padronizada, o que facilita na reciclagem de códigos para importação e tratamento HTML: Pode ser que exista uma versão do livro gratuita na internet então com técnicas de webscrapping podemos capturar o conteúdo do livro e transforma-lo em um audio-book 📌 Dica importante: Antes de gerar o áudio, revise o conteúdo extraído para garantir que títulos, subtítulos, parágrafos e listas estejam formatados corretamente, para ter uma experiência de escuta mais fluida.\nPreparar o arquivo de texto Cada formato de arquivo exige um pré-processamento específico. Para este exemplo, utilizarei o livro Fairness and Machine Learning: Limitations and Opportunities, pois, além de estar disponível gratuitamente na internet sob a licença Creative Commons BY-NC-ND 4.0, é uma excelente leitura sobre as implicações sociais e éticas das decisões automatizadas, um conhecimento essencial para profissionais de IA e dados. (Inclusive, fiz um post no LinkedIn sobre esse livro no último ano.)\nVamos carregar o código que desenvolvi para realizar o scraping do conteúdo:\n%%capture !wget -O scraper_fairmlbook.py \u0026quot;https://gist.githubusercontent.com/gomesfellipe/91a76531858e51fd69e72fb862499a67/raw/f1ae0374268b3190b41480e937c966cab793aa51/scraper_fairmlbook.py\u0026quot; import scraper_fairmlbook Agora, utilizamos a função para extrair o conteúdo:\nbook = scraper_fairmlbook.extrair_conteudo_livro(\u0026#39;https://fairmlbook.org/\u0026#39;) book {\u0026#39;introduction\u0026#39;: \u0026#39;Introduction\\n\\nOur success, happiness, and wellbeing are neve... \u0026#39;legitimacy\u0026#39;: \u0026quot;When is automated decision making legitimate?\\n\\nThese three sce... \u0026#39;classification\u0026#39;: \u0026#39;Classification\\n\\nThe goal of classification is to leverage ... \u0026#39;relative\u0026#39;: \u0026quot;Relative notions of fairness\\n\\nIn Chapter 3, we considered a rang... \u0026#39;causal\u0026#39;: \u0026#39;Causality\\n\\nOur starting point is the difference between an observa... \u0026#39;legal\u0026#39;: \u0026#39;Understanding United States anti-discrimination law\\n\\nIn this chapte... \u0026#39;testing\u0026#39;: \u0026#39;Testing discrimination in practice\\n\\nIn previous chapters, we have... \u0026#39;broader-view\u0026#39;: \u0026#39;A broader view of discrimination\\n\\nMachine learning systems d... \u0026#39;datasets\u0026#39;: \u0026#39;Datasets\\n\\nIt’s become commonplace to point out that machine lear... Utilizarei apenas as 5 primeiras linhas do livro como exemplo mas note que nesse ponto qualquer objeto do tipo string já possibilita a execução do restante do mini-projeto.\n# Obter as primeiras 5 linhas do texto de introdução text = \u0026quot;\\n\u0026quot;.join(book[\u0026#39;introduction\u0026#39;].split(\u0026#39;\\n\u0026#39;)[0:5]) + \u0026quot;\\n\\n...\u0026quot; print(text) Introduction Our success, happiness, and wellbeing are never fully of our own making. Others’ decisions can profoundly affect the course of our lives: whether to admit us to a particular school, offer us a job, or grant us a mortgage. Arbitrary, inconsistent, or faulty decision-making thus raises serious concerns because it risks limiting our ability to achieve the goals that we have set for ourselves and access the opportunities for which we are qualified. So how do we ensure that these decisions are made the right way and for the right reasons? While there’s much to value in fixed rules, applied consistently, good decisions take available evidence into account. We expect admissions, employment, and lending decisions to rest on factors that are relevant to the outcome of interest. ... Traduzir conteúdo para PT-BR (opcional) Este livro está em inglês mas caso o texto original esteja em qualquer outro idioma que não dominamos, a tradução para português pode ser uma forma de ampliar seu acesso. Para isso, utilizaremos a ferramenta de tradução baseada em IA deep-translator que é uma ferramenta flexível, gratuita e ilimitada para traduzir entre diferentes idiomas usando vários tradutores. Obtive bons resultados com a API do Google Tradutor, bastando dividir o texto em blocos menores para atender ao limite de caracteres da API.\nfrom deep_translator import GoogleTranslator tradutor = GoogleTranslator(source=\u0026#39;auto\u0026#39;, target=\u0026#39;portuguese\u0026#39;) texto = tradutor.translate(text) print(texto) Introdução Nosso sucesso, felicidade e bem-estar nunca são totalmente de nossa responsabilidade. As decisões dos outros podem afetar profundamente o curso de nossas vidas: seja para nos admitir em uma escola específica, nos oferecer um emprego ou nos conceder uma hipoteca. A tomada de decisões arbitrária, inconsistente ou falha, portanto, levanta sérias preocupações porque corre o risco de limitar nossa capacidade de atingir as metas que definimos para nós mesmos e acessar as oportunidades para as quais estamos qualificados. Então, como garantimos que essas decisões sejam tomadas da maneira certa e pelos motivos certos? Embora haja muito a valorizar em regras fixas, aplicadas consistentemente, boas decisões levam em consideração as evidências disponíveis. Esperamos que as decisões de admissão, emprego e empréstimo se baseiem em fatores que sejam relevantes para o resultado do interesse. ... Convertendo o Texto em Áudio com IA Com o texto pronto, é hora de usar ferramentas de text-to-speech (TTS) para gerar o áudio. Existem diversas opções disponíveis, como:\nHugging Face que é uma plataforma colaborativa que democratiza o acesso à recursos de IA gTTS (Google Text-to-Speech) tts-OpenAI que cobra $15 para cada 1 Milhão de tokens (opnião: eu esperava mais qualidade pelo preço que eles cobram) edge-tts que permite usar a função de text-to-speech do Microsoft Edge utilizando código Python Para este mini-projeto utilizaremos o edge-tts, que é conhecida por sua alta qualidade e vozes naturais. IMHO, dos que eu testei, essa biblioteca foi a que apresentou os melhores resultados. A voz escolhida foi pt-BR-AntonioNeural, que proporciona uma leitura bem fluida e não é tão robótica. Tenho certeza que você já ouviu a voz desse modelo em algum lugar.\nimport edge_tts communicate = edge_tts.Communicate(texto, \u0026quot;pt-BR-AntonioNeural\u0026quot;) communicate.save_sync(\u0026quot;audiobook.mp3\u0026quot;) Após executar o modelo o arquivo de áudio audiobook.mp3 estará pronto e disponível no seu diretório de trabalho!\nSeu navegador não suporta reprodução de áudio. Dicas para melhorar a qualidade do audiobook Para garantir uma boa experiência, seguem algumas dicas para melhorar a qualidade final do audiobook:\nFaça a revisão do áudio para identificar possíveis erros das etapas anteriores Pós-processamentos: Eliminar ruídos Ajustar volumes Ajustar velocidade Adicionar música de fundo (Escolha músicas isentas de direitos autorais para enriquecer a narrativa) Caso esteja recebendo o erro ConnectionTimeoutError, existem algumas formar de tentar contornar como:\nReinstalar o pacote para a versão mais recente e aguardar alguns minutos para tentar novamente Dividir o texto em trechos com menos caracteres para gerar os segmentos do áudio e combiná-los depois Aguardar algumas horas e tentar novamente Perguntas frequentes Qual a melhor biblioteca gratuita de text-to-speech para português? Neste teste, o edge-tts (que usa o motor de voz do Microsoft Edge via Python) entregou o resultado mais natural em português, com a voz pt-BR-AntonioNeural, sem custo e sem limite de caracteres como algumas APIs pagas.\nÉ legal converter qualquer livro em audiobook? Depende dos direitos autorais. Livros de domínio público (Domínio Público, Project Gutenberg) podem ser convertidos livremente. Para livros protegidos por direitos autorais, é preciso verificar os termos de uso ou obter autorização do autor ou editora antes de converter e, principalmente, antes de distribuir.\nUm audiobook gerado por IA soa tão bem quanto um narrador humano? Chega perto, mas ainda não substitui completamente. Vozes sintéticas modernas como as do edge-tts são bem naturais para textos informativos e técnicos, mas ainda carecem da entonação expressiva de um narrador humano profissional em gêneros como romance ou poesia.\nQuestões de Ética e Legalidade Antes de converter qualquer livro em áudio, garante que você tem as devidas permissões para utilizá-lo dessa forma. Muitos livros estão protegidos por direitos autorais e sua reprodução ou adaptação sem autorização pode infringir leis de propriedade intelectual. Para evitar problemas legais:\nPrefira conteúdos de domínio público: Livros cujos direitos autorais já expiraram podem ser utilizados livremente. Projetos como o Domínio Público e o Project Gutenberg oferecem acervos gratuitos. Consulte os termos de uso: Alguns eBooks permitem a conversão para audiobooks apenas para fins pessoais, enquanto outros proíbem essa prática. Verifique sempre as regras do autor ou da editora. Obtenha autorização do detentor dos direitos: Caso um livro esteja protegido por direitos autorais, entre em contato com o autor ou a editora para solicitar permissão antes de convertê-lo. Ainda não é possível dizer que a IA substitui 100% os narradores humanos profissionais, pois apesar dos avanços, vozes sintéticas ainda carecem de emoção e expressividade. Para determinados gêneros literários, como romances ou poesias, a narração humana pode proporcionar uma experiência mais envolvente.\nConclusão Criar audiobooks com inteligência artificial é uma maneira revolucionária de otimizar o tempo e ampliar o acesso ao conhecimento e histórias. A combinação de ferramentas gratuitas, como edge-tts e Google Translate API, permitem que qualquer um transforme livros e artigos em áudio. Para quem quiser eliminar completamente a dependência de serviços externos, também é possível rodar LLMs localmente com Qwen como etapa de pré-processamento ou tradução.\nNo entanto, precisamos equilibrar os benefícios da inovação com a responsabilidade ética e legal. Respeitar os direitos autorais, considerar o impacto no mercado de narradores profissionais e garantir que o conteúdo gerado tenha qualidade e integridade para o uso consciente da tecnologia.\nSair de um script que funciona no meu notebook pra algo que resolve o problema de verdade é sempre o passo mais difícil. O Engenharia de Software para Cientistas de Dados, da Catherine Nelson, foi o livro que mais me ajudou a pensar essa ponte.\nSe utilizada de maneira responsável, a IA pode ser uma poderosa aliada na acessibilidade do conhecimento, proporcionando novas formas de aprendizado e entretenimento para um público cada vez maior.\nPara explorar geração de voz com ainda mais controle, o Voicebox é um estúdio open source que permite clonar vozes, ditar e criar áudio com IA — um complemento natural para quem quer ir além do edge-tts.\n","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/post/2025-02-02-book-to-audiobook/","section":"Posts","summary":" Por que Audiobooks? O Que São Audiobooks Criados com IA? Como criar seu audiobook com IA Preparar o arquivo de texto Traduzir conteúdo para PT-BR (opcional) Convertendo o Texto em Áudio com IA FAQ Questões de Ética e Legalidade Conclusão Por que Audiobooks? Pela sua forma conveniente de consumir conhecimento e entretenimento, os audiobooks estão se tornando cada vez mais populares. Conforme a última pesquisa da Câmara Brasileira do Livro, os livros digitais cresceram 15% de 2021 para 2022. Dentre os 13 mil títulos digitais publicados em 2022, 12% eram audiolivros. Embora o livro físico sempre vá existir, nem sempre temos o tempo necessário para ler todas as obras de nossa lista.\n","title":"Audiobooks com IA Gratuitamente: do PDF ao Áudio com edge-tts","type":"post"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/automacao/","section":"Tags","summary":"","title":"Automacao","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/book/","section":"Tags","summary":"","title":"Book","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/conversao-de-texto-em-audio/","section":"Tags","summary":"","title":"Conversao-De-Texto-Em-Audio","type":"tags"},{"content":"","date":"2 de fevereiro de 2025","externalUrl":null,"permalink":"/tags/deep-learning/","section":"Tags","summary":"","title":"Deep-Learning","type":"tags"},{"content":"Última atualização: 26 de novembro de 2024\n1. Informações Gerais # Este site é operado por Fellipe Carvalho Gomes. Em todo o site, os termos \u0026ldquo;nós\u0026rdquo;, \u0026ldquo;nos\u0026rdquo; e \u0026ldquo;nosso\u0026rdquo; se referem ao Fellipe Carvalho Gomes. Este site oferece informações, tutoriais e conteúdo sobre Data Science, Machine Learning e Estatística.\n2. Informações que Coletamos # 2.1 Informações Coletadas Automaticamente # Quando você visita nosso site, coletamos automaticamente certas informações sobre seu dispositivo, incluindo:\nInformações sobre seu navegador web Endereço IP Fuso horário Cookies instalados em seu dispositivo 2.2 Google Analytics # Utilizamos o Google Analytics para entender como os visitantes usam nosso site. O Google Analytics coleta informações como:\nPáginas visitadas Tempo gasto no site Localização geográfica (cidade/país) Dispositivo e navegador utilizados 3. Google AdSense # 3.1 Publicidade # Este site utiliza o Google AdSense para exibir anúncios. O Google pode usar cookies para exibir anúncios baseados em suas visitas anteriores a este site ou outros sites.\n3.2 Cookies de Publicidade # Você pode desativar a publicidade personalizada visitando as Configurações de Anúncios do Google.\n4. Comentários (Disqus) # Se você deixar um comentário em nosso site através do Disqus, certas informações podem ser coletadas, incluindo:\nNome fornecido E-mail (não será publicado) Conteúdo do comentário Endereço IP 5. Como Usamos suas Informações # Usamos as informações coletadas para:\nMelhorar a experiência do usuário Analisar o tráfego do site Personalizar conteúdo Exibir anúncios relevantes Responder a comentários e dúvidas 6. Compartilhamento de Informações # Não vendemos, trocamos ou transferimos suas informações pessoais para terceiros, exceto:\nGoogle Analytics (análise de tráfego) Google AdSense (publicidade) Disqus (sistema de comentários) 7. Cookies # 7.1 O que são Cookies # Cookies são pequenos arquivos que um site ou seu provedor de serviços transfere para o disco rígido do seu computador através do seu navegador.\n7.2 Como Usamos Cookies # Entender e salvar suas preferências Compilar dados agregados sobre tráfego e interação do site Melhorar a experiência do usuário 7.3 Gerenciar Cookies # Você pode desativar cookies através das configurações do seu navegador. No entanto, isso pode afetar a funcionalidade do site.\n8. Links Externos # Ocasionalmente, incluímos links para produtos ou sites de terceiros. Estes sites têm políticas de privacidade independentes e não assumimos responsabilidade pelo conteúdo ou atividades destes sites.\n9. Segurança # Implementamos medidas de segurança para manter a segurança de suas informações pessoais quando você acessa nosso site.\n10. Doações PIX # Se você fizer uma doação via PIX:\nNão coletamos informações da transação A transação é processada diretamente pelo seu banco Podemos receber apenas o valor e data da doação 11. Conformidade com LGPD # Este site está em conformidade com a Lei Geral de Proteção de Dados (LGPD - Lei 13.709/2018).\n11.1 Seus Direitos # Você tem o direito de:\nAcessar suas informações pessoais Corrigir informações incorretas Excluir suas informações Portabilidade de dados Revogar consentimento 12. Menores de Idade # Este site não coleta intencionalmente informações de menores de 18 anos. Se descobrirmos que coletamos informações de um menor, excluiremos essas informações imediatamente.\n13. Alterações nesta Política # Reservamos o direito de modificar esta política de privacidade a qualquer momento. Alterações entrarão em vigor imediatamente após a publicação no site.\n14. Contato # Se você tiver dúvidas sobre esta Política de Privacidade, entre em contato:\nEmail: gomes.fellipe1@gmail.com Site: https://gomesfellipe.github.io/ Formulário de Contato: /contact/ Observação: Esta política de privacidade foi criada para atender aos requisitos básicos do Google AdSense e LGPD. Para sites comerciais ou que coletam mais informações pessoais, recomenda-se consultar um advogado especializado.\n","date":"26 de novembro de 2024","externalUrl":null,"permalink":"/privacy/","section":"Fellipe Gomes","summary":"Última atualização: 26 de novembro de 2024\n1. Informações Gerais # Este site é operado por Fellipe Carvalho Gomes. Em todo o site, os termos “nós”, “nos” e “nosso” se referem ao Fellipe Carvalho Gomes. Este site oferece informações, tutoriais e conteúdo sobre Data Science, Machine Learning e Estatística.\n2. Informações que Coletamos # 2.1 Informações Coletadas Automaticamente # Quando você visita nosso site, coletamos automaticamente certas informações sobre seu dispositivo, incluindo:\n","title":"Política de Privacidade","type":"page"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/chatgpt/","section":"Tags","summary":"","title":"Chatgpt","type":"tags"},{"content":" Caso de Uso de IA Generativa: Extração de Informações de Imagens com o Modelo Llava GenAI refere-se a modelos de inteligência artificial capazes de gerar conteúdo novo e criativo a partir de dados de entrada. Seu uso está revolucionando a maneira como processamos dados não estruturados, como imagens, áudios, textos, vídeos, etc. Trabalhar com modelos pré-treinados (i.e., que já foram treinados com grandes conjuntos de dados) e adaptá-los para necessidades específicas tem sido um divisor de águas.\nNeste post, vamos explorar a utilização do modelo Llava (Large Language and Vision Assistant) para extrair rótulos descritivos de imagens e também discutir como comparar a qualidade das previsões geradas com métricas específicas para avaliar a performance desse tipo de modelo.\nTL;DR\nO modelo Llava (Large Language and Vision Assistant) é uma alternativa de código aberto ao GPT-4 Vision, treinada para gerar descrições textuais a partir de imagens. O teste usou uma amostra de 10 imagens do dataset COCO-2017 e a versão de 7 bilhões de parâmetros do LLaVA 1.5, avaliada com as métricas BLEU, ROUGE-L, METEOR e BERTScore. As métricas baseadas em n-gramas subestimaram a qualidade das legendas geradas, enquanto o BERTScore (baseado em embeddings semânticos) mostrou resultados significativamente superiores. Para contexto sobre outros casos de uso de IA generativa multimodal, veja também conversão de PDF para audiobook com edge-tts e como rodar um LLM local no Mac sem APIs.\nPor que o Modelo Llava? O modelo Llava é uma alternativa de código aberto ao GPT-4 Vision da OpenAI (que se destaca neste domínio, mas sua aplicação é restrita devido sua natureza proprietária e comercial) que foi treinado em grandes conjuntos de dados multimodais, sendo capaz de compreender e gerar descrições textuais para imagens.\nEssa capacidade de “conversar com imagens” tendo o mesmo “poder” de um LLM, possibilita seu uso em muitas soluções desenvolvidas por cientistas de dados no mundo real, como:\nClassificação de produtos em e-commerce: geração de descrições detalhadas de roupas, acessórios, eletrônicos, etc. Detecção de defeitos em linhas de produção: identificação de falhas em produtos para automação e controle de qualidade. Diagnóstico médico por imagens: auxiliar na detecção precoce de doenças a partir de descrições detalhadas de imagens médicas. Reconhecimento de placas de carros: transcrição automática de textos de placas e características de veículos. Identificação de sinais de trânsito: aplicação em veículos autônomos para navegação e identificação de sinais. Análise de alimentos para calcular nutrição: extração automática de informações nutricionais de fotos ou rótulos de alimentos. Identificação de animais em câmeras de vida selvagem: gerar descrições detalhadas de animais detectados, ajudando pesquisadores a automatizar o monitoramento da vida selvagem. Detecção de aglomerações em eventos: analisar imagens de câmeras de segurança para identificar a presença de grandes grupos de pessoas em eventos ou lugares públicos, útil em gestão de multidões ou para questões de segurança. Dataset COCO-2017 O COCO (Common Objects in Context) é um dataset amplamente utilizado em visão computacional. Ele é um dos maiores conjuntos de imagens do dia a dia com objetos em diferentes contextos, com anotações detalhadas fornecidas por humanos como tags, caixa delimitadora, polígono que segmenta a imagem detectando objetos bem como sua descrição. Isso o torna ideal para testar o desempenho desse tipo de modelo para geração de legendas.\nImagem do COCO Dataset com e sem anotação obtida na seção exploratória das imagens Preparando o Ambiente Utilizei o ambiente do Kaggle para desenvolvimento deste notebook, que disponibiliza a utilização de GPUs. Através do Hardware Accelerator utilizaremos a NVIDIA TESLA P100 GPU.\nExpandir código %%capture !pip -qqq install bitsandbytes accelerate rouge-score pycocoevalcap bert_score !pip install -U nltk import os import re import json import pandas as pd import numpy as np from tqdm import tqdm import seaborn as sns import matplotlib.pyplot as plt from PIL import Image import requests from io import BytesIO from IPython.display import HTML import base64 import torch from transformers import pipeline, AutoProcessor, BitsAndBytesConfig from nltk.translate.bleu_score import sentence_bleu from rouge_score import rouge_scorer from bert_score import score as bert_score from nltk.translate.meteor_score import meteor_score from transformers import logging import warnings logging.set_verbosity_error() warnings.filterwarnings(\u0026quot;ignore\u0026quot;, \u0026quot;use_inf_as_na\u0026quot;) Carregar dados Por fins de praticidade para este post, selecionei uma amostra de 10 imagens aleatórias do dataset COCO - (Common Objects in Context) no site https://cocodataset.org (onde é possível ter uma descrição detalhada do conjunto de dados, incluindo seu paper para aprofundamento), para avaliar o desempenho do modelo.\nExpandir código df_sample = pd.DataFrame({ \u0026#39;coco_url\u0026#39;: [ \u0026#39;http://images.cocodataset.org/train2017/000000058822.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000530396.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000097916.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000418492.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000022304.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000295999.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000406616.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000370926.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000005612.jpg\u0026#39;, \u0026#39;http://images.cocodataset.org/train2017/000000146436.jpg\u0026#39; ], \u0026#39;caption\u0026#39;: [ \u0026#39;A laptop sitting on a desk with a cell phone and mouse.\u0026#39;, \u0026#39;A black bear walking through the grass field.\u0026#39;, \u0026#39;a person who is surfing in the ocean.\u0026#39;, \u0026#39;A young boy standing on a sandy beach holding a flag.\u0026#39;, \u0026#39;A man surfing on a wave in the ocean.\u0026#39;, \u0026#39;A herd of cows, grazing in a field.\u0026#39;, \u0026#39;There is a cutting board and knife with chopped apples and carrots.\u0026#39;, \u0026#39;A long yellow school bus is parked on a city street.\\n\u0026#39;, \u0026#39;A black and white horse standing in the middle of a field.\u0026#39;, \u0026#39;A man in a red jacket looking at his phone.\u0026#39; ]}) # Função para verificar se o caminho é uma URL def is_url(path): return path.startswith(\u0026#39;http://\u0026#39;) or path.startswith(\u0026#39;https://\u0026#39;) # Função simplificada para gerar o thumbnail e convertê-lo em base64 diretamente def process_image(path): try: if is_url(path): # Se for uma URL, baixar a imagem response = requests.get(path) response.raise_for_status() # Verifica se houve algum erro no download image = Image.open(BytesIO(response.content)) # Abrir a imagem do conteúdo da resposta else: # Se for um caminho local, abrir a imagem diretamente image = Image.open(path) # Criar uma miniatura da imagem (thumbnail) com tamanho máximo de 150x150 image.thumbnail((150, 150), Image.LANCZOS) # Salvar a imagem em um buffer de memória e convertê-la para base64 with BytesIO() as buffer: image.save(buffer, \u0026#39;jpeg\u0026#39;) image_base64 = base64.b64encode(buffer.getvalue()).decode() # Retornar a string HTML com a imagem embutida no formato base64 return f\u0026#39;\u0026lt;img src=\u0026quot;data:image/jpeg;base64,{image_base64}\u0026quot;\u0026gt;\u0026#39; except Exception as e: # Em caso de erro, retornar uma string vazia ou uma mensagem de erro return f\u0026quot;\u0026lt;p\u0026gt;Erro ao carregar imagem: {e}\u0026lt;/p\u0026gt;\u0026quot; # Aplicar o processamento de imagens diretamente no DataFrame df_sample[\u0026#39;image\u0026#39;] = df_sample[\u0026#39;coco_url\u0026#39;].map(process_image) # Pode ser URL ou caminho local # Exibir as legendas e imagens formatadas em HTML HTML(df_sample[[\u0026#39;image\u0026#39;, \u0026#39;coco_url\u0026#39;, \u0026#39;caption\u0026#39;]].head().to_html(escape=False)) Caso você precise de mais imagens para testar, também é possível encontrar uma versão disponibilizada no Kaggle .\nCarregar modelo Utilizaremos uma versão de 7 bilhões de parâmetros do modelo “LLaVA 1.5” (Language and Vision Assistant), disponível no HuggingFace (Uma plataforma onde a comunidade de Machine Learning colabora com modelos, dados e aplicações) treinada para tarefas de geração de texto a partir de imagens.\n%%time model_id = \u0026quot;llava-hf/llava-1.5-7b-hf\u0026quot; # Configuração de quantização do modelo, que permite reduzir o uso de memória sem # comprometer muito a precisão. Aqui estamos configurando para usar quantização em 4 bits. quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type=\u0026quot;nf4\u0026quot;, bnb_4bit_compute_dtype=torch.bfloat16 ) # Criação de um pipeline de processamento de imagens para geração de texto # O pipeline é configurado para a tarefa \u0026quot;image-to-text\u0026quot; pipe = pipeline( \u0026quot;image-to-text\u0026quot;, model=model_id, model_kwargs={ \u0026quot;quantization_config\u0026quot;: quantization_config, \u0026quot;low_cpu_mem_usage\u0026quot;: True } ) # Carregar o processador associado responsável por pré-processar # as imagens de entrada e preparar os dados para serem inseridos no modelo processor = AutoProcessor.from_pretrained(model_id) CPU times: user 28.7 s, sys: 28.1 s, total: 56.8 s Wall time: 6min 26s 📌 Nota: A quantização é uma técnica para reduzir o tamanho do modelo, perdendo um pouco de performance para otimizar o desempenho e rodar em máquinas com memória limitada.\nPrompt Engineering Uma ampla variedade de técnicas poderiam ser aplicadas para desenvolver prompts mais eficazes (inclusive com LangChain, como fiz no último post) ou especializar o modelo com ajuste fino visando obter resultados otimizados. No entanto, como este não é o foco do post, usarei um prompt simples e direto para estabelecer um baseline para avaliar as capacidades do modelo com o mínimo de esforço.\n# Cada valor em \u0026quot;content\u0026quot; tem que ser uma lista de dicionário com os tipos (\u0026quot;text\u0026quot;, \u0026quot;image\u0026quot;) conversation = [ { \u0026quot;role\u0026quot;: \u0026quot;user\u0026quot;, \u0026quot;content\u0026quot;: [ {\u0026quot;type\u0026quot;: \u0026quot;text\u0026quot;, \u0026quot;text\u0026quot;: \u0026quot;Describe this image in a few words:\u0026quot;}, {\u0026quot;type\u0026quot;: \u0026quot;image\u0026quot;}, ] }, ] # Formata a conversa (que pode incluir texto e imagens) no formato correto que o modelo entende. prompt = processor.apply_chat_template(conversation, add_generation_prompt=True) O prompt deve ser especificado no seguinte formato:\nUSER: \u0026lt;image\u0026gt; \u0026lt;prompt\u0026gt; ASSISTANT: Inferência Com o modelo devidamente configurado e o prompt ajustado, estamos prontos para executar o pipeline de inferência. A vantagem de utilizar pipelines é que eles abstraem boa parte da codificação complexa, proporcionando uma interface simples e eficiente. Essa API versátil é dedicada a várias tarefas, como NER (Reconhecimento de Entidades), Análise de Sentimentos, Extração de Features e Question Answering.\nfor i in tqdm(range(df_sample.shape[0])): # preparar objetos do loop coco_url = df_sample.iloc[i][\u0026#39;coco_url\u0026#39;] caption = df_sample.iloc[i][\u0026#39;caption\u0026#39;] index = df_sample.iloc[i].name # Obter imagem response = requests.get(coco_url) image = Image.open(BytesIO(response.content)) # Realizar a inferência usando o pipeline e o prompt gerado outputs = pipe(image, prompt=prompt, generate_kwargs={\u0026quot;max_new_tokens\u0026quot;: 32}) # Processar o texto gerado para extrair a parte relevante result = outputs[0][\u0026#39;generated_text\u0026#39;].split(\u0026#39;ASSISTANT:\u0026#39;, 1)[1].strip() # Adicionar o resultado da inferência à nova coluna \u0026#39;llm\u0026#39; do DataFrame df_sample.loc[index, \u0026#39;llm\u0026#39;] = result 100%|██████████| 10/10 [00:41\u0026lt;00:00, 4.20s/it] Após a execução do modelo, veja como ficaram os resultados:\nExpandir código # Função para destacar as palavras def highlight_diff(caption, llm): # Divide as frases em palavras caption_words = caption.replace(\u0026quot;.\u0026quot;, \u0026quot;\u0026quot;).split() llm_words = llm.replace(\u0026quot;.\u0026quot;, \u0026quot;\u0026quot;).split() # Converte as palavras em conjuntos para encontrar a interseção caption_set = set(caption_words) llm_set = set(llm_words) # Calcula as palavras que não estão na interseção caption_highlighted = \u0026quot; \u0026quot;.join([f\u0026#39;\u0026lt;span style=\u0026quot;color:red\u0026quot;\u0026gt;{word}\u0026lt;/span\u0026gt;\u0026#39; if word not in llm_set else word for word in caption_words]) llm_highlighted = \u0026quot; \u0026quot;.join([f\u0026#39;\u0026lt;span style=\u0026quot;color:red\u0026quot;\u0026gt;{word}\u0026lt;/span\u0026gt;\u0026#39; if word not in caption_set else word for word in llm_words]) return caption_highlighted, llm_highlighted # Aplica a função a cada linha do DataFrame e cria novas colunas df_sample[\u0026#39;highlighted_caption\u0026#39;], df_sample[\u0026#39;highlighted_llm\u0026#39;] = zip(*df_sample.apply(lambda row: highlight_diff(row[\u0026#39;caption\u0026#39;], row[\u0026#39;llm\u0026#39;]), axis=1)) # Exibir o DataFrame formatado com HTML HTML(df_sample[[\u0026#39;image\u0026#39;, \u0026#39;highlighted_caption\u0026#39;, \u0026#39;highlighted_llm\u0026#39;]].to_html(escape=False)) Destaquei em vermelho as palavras que diferem entre a legenda original do dataset e a previsão gerada pelo nosso modelo de linguagem.\n💭 Apesar de algumas diferenças sutis entre as duas versões, como ‘looking at his phone’ e ‘looking at his cell phone’, a ideia principal permanece bastante coerente com o que vemos nas imagens. Em alguns casos, como no item 3, a descrição gerada pelo modelo, ‘holding a kite’, parece até mais apropriada do que a fornecida pelo dataset, ‘holding a flag’.\nAgora, o próximo passo será quantificar essas diferenças de maneira numérica.\nAvaliar modelo Para medir a precisão das legendas geradas, aplicaremos quatro métricas amplamente usadas:\nEsse tipo de avaliação de output de LLM em produção é um dos temas centrais do AI Engineering, da Chip Huyen. É caro, mas é o livro mais atual que encontrei pra quem constrói produto de verdade com IA generativa.\nBLEU (Bilingual Evaluation Understudy Score): Amplamente utilizada para medir a qualidade de traduções automáticas, mede a sobreposição de n-gramas entre a tradução gerada por um modelo e as traduções de referência, atribuindo uma pontuação que varia de 0 a 1 (aplica também um fator de penalização para evitar que traduções curtas sejam favorecidas); ROUGE-L (Recall-Oriented Understudy for Gisting Evaluation): Muito utilizado em tarefa de sumarização de textos, considera a sequência mais longa de palavras que aparecem em ambas as referências e previsões, medindo a capacidade de preservar a ordem das palavras; METEOR (Metric for Evaluation of Translation with Explicit ORdering): Baseada na média harmônica da precisão e recall de n-gramas, com recall ponderado mais alto do que a precisão. Essa métrica METEOR foi projetada para corrigir alguns dos problemas (como encontrar sinônimos) nas métricas BLEU e ROGUE; BERTScore: Usa embeddings (representações semânticas) obtidas a partir do modelo BERT para comparar a similaridade semântica entre as descrições geradas e as de referência. Expandir código # Funções para calcular as métricas def calcular_bleu(referencias, previsao): return sentence_bleu([referencias.split(\u0026quot; \u0026quot;)], previsao.split(\u0026quot; \u0026quot;),weights = [1]) def calcular_rouge(referencias, previsao): scorer = rouge_scorer.RougeScorer([\u0026#39;rougeL\u0026#39;], use_stemmer=True) return scorer.score(referencias, previsao)[\u0026#39;rougeL\u0026#39;].fmeasure def calcular_meteor(referencias, previsao): return meteor_score([referencias.split(\u0026quot; \u0026quot;)], previsao.split(\u0026quot; \u0026quot;)) def calcular_bertscore(referencias, previsao): P, R, F1 = bert_score([previsao], [referencias], lang=\u0026quot;en\u0026quot;, verbose=True) return F1.mean().item() %%capture # Avaliar as amostras no DataFrame resultados = [] for i, row in df_sample.iterrows(): referencias = row[\u0026#39;caption\u0026#39;].replace(\u0026quot;.\u0026quot;, \u0026quot;\u0026quot;) previsao = row[\u0026#39;llm\u0026#39;].replace(\u0026quot;.\u0026quot;, \u0026quot;\u0026quot;) bleu = calcular_bleu(referencias, previsao) rouge = calcular_rouge(referencias, previsao) meteor = calcular_meteor(referencias, previsao) bert = calcular_bertscore(referencias, previsao) resultados.append([referencias, previsao, bleu, rouge, meteor, bert]) # Converter os resultados para um DataFrame df_resultados = pd.DataFrame(resultados, columns=[\u0026#39;caption\u0026#39;, \u0026#39;llm\u0026#39;, \u0026#39;BLEU\u0026#39;, \u0026#39;ROUGE\u0026#39;, \u0026#39;METEOR\u0026#39;, \u0026#39;BERTScore\u0026#39;]) Vejamos os resultados:\nExpandir código # Configurar o tema do Seaborn sns.set_theme(style=\u0026quot;white\u0026quot;, rc={\u0026quot;axes.facecolor\u0026quot;: (0, 0, 0, 0)}) # Reformatar o DataFrame para o formato long df_long = df_resultados[[\u0026#39;BLEU\u0026#39;, \u0026#39;ROUGE\u0026#39;, \u0026#39;METEOR\u0026#39;, \u0026#39;BERTScore\u0026#39;]].melt(var_name=\u0026quot;Métrica\u0026quot;, value_name=\u0026quot;Valor\u0026quot;) # Calcular a média de cada métrica mean_values = df_long.groupby(\u0026#39;Métrica\u0026#39;)[\u0026#39;Valor\u0026#39;].mean().reset_index() # Inicializar o objeto FacetGrid pal = sns.cubehelix_palette(len(df_long[\u0026#39;Métrica\u0026#39;].unique()), rot=-.25, light=.7) g = sns.FacetGrid(df_long, row=\u0026quot;Métrica\u0026quot;, hue=\u0026quot;Métrica\u0026quot;, aspect=6, height=1.5, palette=pal) # Desenhar as densidades g.map(sns.kdeplot, \u0026quot;Valor\u0026quot;, bw_adjust=.5, clip_on=False, fill=True, alpha=1, linewidth=1.5) g.map(sns.kdeplot, \u0026quot;Valor\u0026quot;, clip_on=False, color=\u0026quot;w\u0026quot;, lw=2, bw_adjust=.5) # Adicionar linha de referência g.refline(y=0, linewidth=2, linestyle=\u0026quot;-\u0026quot;, color=None, clip_on=False) # Função para rotular o gráfico def label(x, color, label): ax = plt.gca() # Localizar a média correspondente à métrica mean_value = mean_values[mean_values[\u0026#39;Métrica\u0026#39;] == label][\u0026#39;Valor\u0026#39;].values[0] ax.text(0, .4, f\u0026quot;{label} (Média: {mean_value:.2f})\u0026quot;, fontweight=\u0026quot;bold\u0026quot;, color=color, ha=\u0026quot;left\u0026quot;, va=\u0026quot;center\u0026quot;, transform=ax.transAxes, fontsize=20) g.map(label, \u0026quot;Valor\u0026quot;) # Ajustar espaçamento entre subplots manualmente g.figure.subplots_adjust(hspace=0.2) # Remover detalhes desnecessários dos eixos g.set_titles(\u0026quot;\u0026quot;) g.set(yticks=[], ylabel=\u0026quot;\u0026quot;) g.despine(bottom=True, left=True) # Configurar o eixo x g.set(xlim=(0.4, 1), xticks=np.arange(0.4, 1.05, 0.1)) # Limites e ticks do eixo x # Remover rótulos do eixo x em cada subplot for ax in g.axes.flat: ax.set_xlabel(\u0026quot;\u0026quot;) # Remover rótulo do eixo x ax.tick_params(axis=\u0026#39;x\u0026#39;, labelsize=16) # Aumentar o tamanho da fonte dos ticks do eixo x # Exibir o gráfico plt.show() 📌 Insights ao Avaliar as Métricas do Modelo: As métricas baseadas em n-grams e na correspondência de palavras mostraram desempenho subestimado. Embora o modelo tenha apresentado algumas variações na escolha das palavras, as frases geradas mantiveram um sentido geral muito semelhante ao que é retratado nas imagens.\nPor outro lado, a métrica baseada em embeddings, que avalia o significado semântico das frases, apresentou resultados significativamente superiores. Essa abordagem se mostrou mais congruente em avaliar a similaridade das descrições geradas e a descrição informada do conteúdo visual das imagens.\nÉ importante ressaltar que nosso prompt foi mantido na forma mais simples possível e que o conjunto de dados abrange um escopo bastante amplo. Com isso, acredito que o modelo ainda tem muito potencial para oferecer resultados ainda mais robustos, sem a necessidade de ajustes finos, em tarefas mais específicas.\nConclusão O uso da GenAI com o modelo Llava oferece uma solução eficiente para a extração de features de imagens em Python, possibilitando a criação de descrições ricas e detalhadas. Ao comparar a qualidade das saídas com métricas como BLEU, podemos garantir que o modelo esteja oferecendo resultados satisfatórios para as necessidades do projeto.\nSe você deseja automatizar processos de análise de imagens, explorar a criação de modelos customizados ou otimizar a organização de dados visuais, a utilização de GenAI com modelos como o Llava pode ser um divisor de águas em seus projetos.\nSe este conteúdo foi útil, continue acompanhando o blog para mais tutoriais sobre inteligência artificial e Python!\nSe o objetivo é extrair texto e estrutura de PDFs ou documentos do Office (não apenas imagens) para alimentar agentes, o MinerU resolve exatamente esse problema, convertendo documentos em markdown/JSON prontos para uso.\nReferências https://huggingface.co/llava-hf/llava-1.5-7b-hf https://github.com/haotian-liu/LLaVA https://colab.research.google.com/drive/1qsl6cd2c8gGtEW1xV5io7S8NHh-Cp1TV?usp=sharing#scrollTo=6Bx8iu9jOssW https://cocodataset.org/#explore https://www.kaggle.com/datasets/awsaf49/coco-2017-dataset/ Perguntas frequentes O que é o modelo Llava e para que serve?\nLlava (Large Language and Vision Assistant) é um modelo multimodal de código aberto, alternativa ao GPT-4 Vision, treinado para compreender imagens e gerar descrições textuais a partir delas.\nQual dataset foi usado para testar o modelo?\nFoi usada uma amostra de 10 imagens aleatórias do dataset COCO-2017 (Common Objects in Context), que contém anotações detalhadas fornecidas por humanos.\nQuais métricas avaliam a qualidade das legendas geradas por IA?\nO post aplicou BLEU, ROUGE-L, METEOR e BERTScore. As métricas de n-gramas subestimaram a qualidade, enquanto o BERTScore, baseado em embeddings semânticos, teve desempenho significativamente superior.\n","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/post/2024-09-27-image-text-to-text/","section":"Posts","summary":" Caso de Uso de IA Generativa: Extração de Informações de Imagens com o Modelo Llava GenAI refere-se a modelos de inteligência artificial capazes de gerar conteúdo novo e criativo a partir de dados de entrada. Seu uso está revolucionando a maneira como processamos dados não estruturados, como imagens, áudios, textos, vídeos, etc. Trabalhar com modelos pré-treinados (i.e., que já foram treinados com grandes conjuntos de dados) e adaptá-los para necessidades específicas tem sido um divisor de águas.\n","title":"Extração de informações de imagens com IA Generativa","type":"post"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/genai/","section":"Tags","summary":"","title":"Genai","type":"tags"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/ia-generativa/","section":"Tags","summary":"","title":"Ia-Generativa","type":"tags"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/llama/","section":"Tags","summary":"","title":"Llama","type":"tags"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/llama2/","section":"Tags","summary":"","title":"Llama2","type":"tags"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/llava/","section":"Tags","summary":"","title":"Llava","type":"tags"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/tags/lmm/","section":"Tags","summary":"","title":"Lmm","type":"tags"},{"content":"","date":"27 de setembro de 2024","externalUrl":null,"permalink":"/categories/machine-learning/","section":"Categories","summary":"","title":"Machine Learning","type":"categories"},{"content":"","date":"26 de maio de 2024","externalUrl":null,"permalink":"/tags/classification/","section":"Tags","summary":"","title":"Classification","type":"tags"},{"content":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 → Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Caso de Uso de IA Generativa: Detecção de Linguagem Tóxica em Mídias Sociais Neste post, realizaremos a tarefa de detecção de linguagem tóxica em mídias sociais usando o modelo Gemma de IA generativa do Google com o framework LangChain. Vamos explorar como o texto de entrada afeta a saída do modelo e faremos alguma engenharia de prompts para direcioná-lo à tarefa necessária.\nTL;DR\nClassificamos tweets em português como tóxicos ou não usando o Gemma-7b-it quantizado, sem nenhum fine-tuning. Um prompt few-shot dinâmico seleciona os exemplos mais similares semanticamente a cada tweet, via SemanticSimilarityExampleSelector + Chroma. A cadeia prompt | llm | parse do LangChain encapsula todo o pipeline de classificação. Setup Utilizaremos o ambiente do Kaggle para desenvolvimento deste notebook, que disponibiliza a utilização de GPUs. Através do Hardware Accelerator utilizaremos a NVIDIA TESLA P100 GPU.\nInstalar e carregar dependencias Vamos instalar as bibliotecas accelerate e bitsandbytes que possibilitam a quantização de LLMs e algumas bibliotecas do framework LangChain\n!pip install accelerate !pip install -i https://pypi.org/simple/ bitsandbytes !pip install langchain langchain_huggingface langchain_community langchain_chroma Carregar bibliotecas import pandas as pd import torch import re from sklearn.metrics import accuracy_score, confusion_matrix import matplotlib.pyplot as plt import seaborn as sns from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig, pipeline from langchain_huggingface import HuggingFacePipeline from langchain_core.prompts.few_shot import PromptTemplate, FewShotPromptTemplate from langchain_core.example_selectors import SemanticSimilarityExampleSelector from langchain_community.embeddings import HuggingFaceEmbeddings from langchain_chroma import Chroma Carregar funções auxiliares Carregar uma função para limpeza simples dos tweets.\nClique aqui para ver os códigos def clean_tweet(text): \u0026quot;\u0026quot;\u0026quot; src: https://github.com/lrdsouza/told-br-classifier \u0026quot;\u0026quot;\u0026quot; text = text.replace(\u0026#39;rt @user\u0026#39;, \u0026#39;\u0026#39;) text = text.replace(\u0026#39;@user\u0026#39;, \u0026#39;\u0026#39;) pattern = re.compile(\u0026#39;[^a-zA-Z0-9\\sáéíóúàèìòùâêîôûãõçÁÉÍÓÚÀÈÌÒÙÂÊÎÔÛÃÕÇ]\u0026#39;) text = re.sub(r\u0026#39;http\\S+\u0026#39;, \u0026#39;\u0026#39;, text) text = pattern.sub(r\u0026#39; \u0026#39;, text) text = text.replace(\u0026#39;\\n\u0026#39;, \u0026#39; \u0026#39;) text = \u0026#39; \u0026#39;.join(text.split()) return text Carregar dados Vamos utilizar o conjunto de dados TolD-br, um recurso interessante para o estudo da toxicidade em conteúdos online em português brasileiro. Este dataset foi utilizado na competição ML Olympiad - Toxic Language (PTBR) Detection, organizada pelo TensorFlow UGSP no Kaggle este ano. A competição convidou entusiastas de dados, cientistas e pesquisadores a desenvolverem modelos de machine learning capazes de classificar tweets em português brasileiro como tóxicos ou não tóxicos.\ntrain = pd.read_csv(\u0026quot;/kaggle/input/ml-olympiad-toxic-language-ptbr-detection/train (2).csv\u0026quot;) test = pd.read_csv(\u0026quot;/kaggle/input/ml-olympiad-toxic-language-ptbr-detection/test (4).csv\u0026quot;) sub = pd.read_csv(\u0026quot;/kaggle/input/ml-olympiad-toxic-language-ptbr-detection/sample_submission.csv\u0026quot;) Selecionar uma amostra para auxiliar no desenvolvimento do prompt para utilização em novos dados:\nvalid = train.sample(n=100, random_state=123) Preparar dados Aplicar limpeza básica para preparar os tweets.\nClique aqui para ver os códigos train[\u0026#39;text\u0026#39;] = train.text.apply(lambda x: clean_tweet(x)) valid[\u0026#39;text\u0026#39;] = valid.text.apply(lambda x: clean_tweet(x)) test[\u0026#39;text\u0026#39;] = test.text.apply(lambda x: clean_tweet(x)) Carregar Modelo Neste notebook, faremos uso de um modelo da família Gemma, desenvolvida pelo Google, que consiste em modelos leves e de código aberto construídos com base em pesquisas e tecnologias empregadas no desenvolvimento dos modelos Gemini\n📌 Nota: Para utilizar o modelo é necessário consentir com a licença do Gemma com o preenchimento de um formulário disponível na página do modelo.\nUtilizaremos a implementação do Gemma-7b-instruct, que é uma variante ajustada por instrução (IT) que pode ser usada para bate-papo e/ou seguir instruções.\n# Caminho para o modelo disponível pelo ambiente do Kaggle model_path = \u0026quot;/kaggle/input/gemma/transformers/1.1-7b-it/1/\u0026quot; # Definir configuracoes de quantizacao para reduzir # o tamanho do modelo perdendo pouca performance quantization_config = BitsAndBytesConfig( load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type=\u0026quot;nf4\u0026quot;, bnb_4bit_compute_dtype=torch.bfloat16 ) # Instanciar o tokenizador do LLM tokenizer = AutoTokenizer.from_pretrained(model_path) # Instanciar o LLM model = AutoModelForCausalLM.from_pretrained( model_path, quantization_config=quantization_config, low_cpu_mem_usage=True, device_map=\u0026quot;auto\u0026quot; ) Vamos carregar também um modelo de embedding que utilizaremos para auxiliar na construção do nosso prompt:\nembeddings = HuggingFaceEmbeddings(model_name=\u0026quot;all-MiniLM-L6-v2\u0026quot;) Preparar modelo Os modelos da Hugging Face podem ser facilmente executados localmente utilizando a classe HuggingFacePipeline. O Hugging Face Model Hub é um repositório que abriga mais de 120 mil modelos, 20 mil conjuntos de dados e 50 mil aplicativos de demonstração (Spaces), todos de código aberto e disponíveis publicamente. Esta plataforma online permite que as pessoas colaborem facilmente e construam modelos de machine learning juntas.\n# Instanciar um pipeline transformers pipe = pipeline( model=model, tokenizer=tokenizer, task=\u0026quot;text-generation\u0026quot;, max_new_tokens=1, ) # Passar o pipeline para a classe do LangChain llm = HuggingFacePipeline(pipeline=pipe) Prompt Engineering Para resolver este problema, criaremos um template de prompt que utiliza a estratégia few-shot, que pode ser construído a partir de um conjunto de exemplos. O conjunto de exemplos será dinâmico, sendo construído com base em tweets que possuem a maior similaridade semantica com o tweet de entrada.\nO Natural Language Processing with Transformers, escrito pelos próprios autores da Hugging Face, é a referência que mais consulto pra esse tipo de pipeline, do fine-tuning ao deploy.\nPreparar exemplos Selecionaremos os exemplos candidatos do conjunto de dados de treino que não estejam no dataset de validação. Cada exemplo de entrada deve ser um dicionário onde:\nkey: o nome das variáveis de inputs do prompt; values: os valores dos inputs. # indices de instancias que nao estao no dataset de validacao (evitar leak) idx_train_examples = train.loc[~train.index.isin(valid.index)].index # organizar a lista com os exemplos candidatos examples = [{\u0026#39;tweet\u0026#39;: train.text[i], \u0026#39;label\u0026#39;: str(train.label[i])} for i in idx_train_examples] Criar template para os exemplos com PromptTemplate Agora precisamos instanciar um PromptTemplate para nosso prompt, que recebe um template das instruções que desejamos passar para o LLM e os inputs que alimentam este template:\nexample_template = \u0026quot;\u0026quot;\u0026quot; Tweet: {tweet} Label: {label} \u0026quot;\u0026quot;\u0026quot; # Instanciar o exemplo de prompt example_prompt = PromptTemplate( input_variables=[\u0026quot;tweet\u0026quot;, \u0026quot;label\u0026quot;], template=example_template ) Inserir exemplos com ExampleSelector Agora vamos instanciar SemanticSimilarityExampleSelector para selecionar exemplos com base em sua semelhança com a entrada. Ele usa um modelo de embedding para calcular a similaridade entre a entrada e os exemplos de few-shot, bem como um armazenamento de vetores Chroma para realizar a pesquisa do vizinho mais próximo de maneira eficiente.\nexample_selector = SemanticSimilarityExampleSelector.from_examples( examples = examples, embeddings = embeddings, vectorstore_cls = Chroma, k=3, ) Aumentar o número de vizinhos mais próximos não garantirá necessariamente resultados melhores. Normalmente k=6 no máximo já é suficiente. Se não conseguir bons resultados assim, já seria mais indicado realizar um ajuste fino mesmo.\nPreparar o FewShotPromptTemplate Finalmente, vamos definir a formatação para a apresentação dos exemplos e, em seguida, usar FewShotPromptTemplate para para gerar o template final que será utilizado como prompt com base nos valores de entrada.\nprefix = \u0026quot;\u0026quot;\u0026quot;The following tweets are written in Brazilian Portuguese. \\n\\ You are a tweet classifier that identifies \\ toxic language as 1 and non-toxic language as 0. \\n\\ Here are some examples:\u0026quot;\u0026quot;\u0026quot; suffix = \u0026quot;\u0026quot;\u0026quot; Tweet: {tweet} Label: \u0026quot;\u0026quot;\u0026quot; prompt = FewShotPromptTemplate( example_selector=example_selector, example_prompt=example_prompt, prefix=prefix, suffix=suffix, example_separator=\u0026#39;\\n\u0026#39;, input_variables=[\u0026quot;tweet\u0026quot;], ) Vejamos como será a formatação do prompt para a classificação de cada tweet:\nprint(prompt.format(tweet=valid.head(1).text.values[0])) ## The following tweets are written in Brazilian Portuguese. ## You are a tweet classifier that identifies toxic language as 1 and non-toxic language as 0. ## Here are some examples: ## ## Tweet: caralho eu tenho q fazer alguma coisa mt importante mas eu esqueci o que é então n deve ser importante ## Label: 1 ## ## Tweet: caralho as pessoas fazem me sentir a pessoa mais bosta e odiada possível eu tô bem ## Label: 0 ## ## Tweet: tenho quase certeza que isso e um homem escroto fingindo ser mulher kkkkkkkkk por um momento eu tbm pensei nisso ## Label: 0 ## ## Tweet: vei se um filho faz isso cmg eu pego o sanduíche e enfio no cu dele ## Label: Definir Custom Output Parsers Para concluir a cadeia, vamos definir uma função que funcione como um Custom Output Parser, que será responsável por pegar a saída do LLM e transformá-la no formato mais adequado para nosso caso. Precisamos apenas do último caractere que será retornado pelo LLM.\ndef parse(response): \u0026quot;\u0026quot;\u0026quot;Retorna apenas o ultimo caracter da saída do LLM\u0026quot;\u0026quot;\u0026quot; return int(response[-1:]) Definir Cadeira LangChain Chains referem-se à sequências de chamadas - seja para um LLM, uma etapa de pré-processamento de dados, tools, ou ainda etapas de pós-processamento do output gerado pelo modelo. As cadeias construídas desta forma são boas porque oferecem suporte nativo a streaming, assíncrono e inferência em batchs para uso.\nchain = prompt | llm | parse Vamos testar o comportamento da nossa cadeia em 1 tweet:\nprint(f\u0026quot;\u0026quot;\u0026quot;Tweet: {valid.head(1).text.values[0]} Label: {valid.head(1).label.values[0]} Predict: {chain.invoke({\u0026#39;tweet\u0026#39;: valid.head(1).text.values[0]})}\u0026quot;\u0026quot;\u0026quot;) ## Tweet: vei se um filho faz isso cmg eu pego o sanduíche e enfio no cu dele ## Label: 1 ## Predict: 1 Claramente um conteúdo tóxico e que foi classificado corretamente. Mas como queremos realizar a chamada da nossa cadeia para diversos tweets do dataset de test, utilizaremos o método .batch() que executa a cadeia para uma lista de entradas:\n%%time valid[\u0026#39;predict\u0026#39;] = chain.batch([{\u0026#39;tweet\u0026#39;: x} for x in valid.text]) ## CPU times: user 1min 26s, sys: 24.8 s, total: 1min 51s ## Wall time: 1min 50s Avaliar resultados Como a métrica de avaliação da competição era a acurácia, vamos dar uma olhada em como ficou a matriz de confusão:\nClique aqui para ver o código do gráfico # Calcular métricas cm = confusion_matrix(valid.label, valid.predict) acc=accuracy_score(valid.label, valid.predict) # Configurações de estilo do seaborn sns.set(font_scale=1.2) plt.figure(figsize=(5, 3)) # Plotar Matriz de Confusão para o método Vader em inglês sns.heatmap(cm, annot=True, fmt=\u0026#39;d\u0026#39;, cmap=\u0026#39;binary\u0026#39;, cbar=False,vmin=0, vmax=50, xticklabels=[\u0026#39;Não Tóxico\u0026#39;, \u0026#39;Tóxico\u0026#39;], yticklabels=[\u0026#39;Não Tóxico\u0026#39;, \u0026#39;Tóxico\u0026#39;]) plt.title(f\u0026#39;Matriz de Confusão\\nAcurácia: {acc:.0%}\u0026#39;, fontsize=22) plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.xlabel(\u0026#39;Previsto\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Real\u0026#39;, fontsize=14) plt.show() Conclusão Embora nosso objetivo não fosse alcançar a perfeição em termos de acurácia, até que o resultado foi satisfatório, dado o potencial dessa ferramenta para resolver uma ampla gama de problemas com poucas modificações nos códigos. Existem muitos outros caminhos a serem explorados (inclusive recomendo assistir à live no YouTube em que os vencedores apresentaram soluções muito mais eficientes), nosso foco aqui foi praticar, aplicar e documentar alguns conceitos interessantes e úteis sobre LLMs e LangChain.\nPara outros exemplos práticos de LLMs e agentes de IA, veja os posts sobre análise de sentimentos com o Llama 2 e sobre rodar um agente com LLM local de graça.\nReferencias https://www.kaggle.com/competitions/ml-olympiad-toxic-language-ptbr-detection https://www.kaggle.com/models/google/gemma/transformers https://huggingface.co/google/gemma-1.1-7b-it https://python.langchain.com/v0.1/docs/modules/model_io/prompts/few_shot_examples/ Perguntas frequentes É preciso fazer fine-tuning para classificar texto com um LLM? Não necessariamente. Este post usa apenas prompt engineering few-shot, sem nenhum ajuste dos pesos do modelo, e já obtém um resultado satisfatório. O fine-tuning tende a ajudar mais quando o few-shot atinge um teto de qualidade.\nO que é um Example Selector no LangChain? É o componente que escolhe, dinamicamente, quais exemplos incluir no prompt few-shot. O SemanticSimilarityExampleSelector usa embeddings para selecionar os exemplos mais parecidos semanticamente com a entrada atual, em vez de usar sempre os mesmos exemplos fixos.\nPor que quantizar o modelo (4-bit) antes de usá-lo? A quantização reduz bastante o consumo de memória do modelo, trocando um pouco de precisão numérica por viabilidade prática, o que permite rodar um LLM de 7 bilhões de parâmetros em GPUs mais modestas, como a usada neste post no Kaggle.\n","date":"26 de maio de 2024","externalUrl":null,"permalink":"/post/2024-05-26-detec-o-de-linguagem-t-xica-com-o-llm-gemma-e-langchain/","section":"Posts","summary":" Série: LangChain — Agentes com Python — ver índice\nAnálise de Sentimentos com Llama2 → Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Caso de Uso de IA Generativa: Detecção de Linguagem Tóxica em Mídias Sociais Neste post, realizaremos a tarefa de detecção de linguagem tóxica em mídias sociais usando o modelo Gemma de IA generativa do Google com o framework LangChain. Vamos explorar como o texto de entrada afeta a saída do modelo e faremos alguma engenharia de prompts para direcioná-lo à tarefa necessária.\n","title":"Detecção de Linguagem Tóxica com o LLM Gemma e LangChain","type":"post"},{"content":"","date":"26 de maio de 2024","externalUrl":null,"permalink":"/tags/gemma/","section":"Tags","summary":"","title":"Gemma","type":"tags"},{"content":"","date":"26 de maio de 2024","externalUrl":null,"permalink":"/tags/google/","section":"Tags","summary":"","title":"Google","type":"tags"},{"content":"","date":"26 de maio de 2024","externalUrl":null,"permalink":"/tags/kaggle/","section":"Tags","summary":"","title":"Kaggle","type":"tags"},{"content":"","date":"26 de maio de 2024","externalUrl":null,"permalink":"/tags/prophet/","section":"Tags","summary":"","title":"Prophet","type":"tags"},{"content":" TL;DR\nO modelo Llama2-7b-chat-hf foi executado localmente via Hugging Face Transformers para classificar textos como positivos, negativos ou neutros, sem custo de API. A abordagem foi avaliada contra o VADER (léxico clássico de análise de sentimentos) em um conjunto de avaliações de filmes em inglês, usando acurácia como métrica. O Llama2 superou o VADER na captura de ironia e contexto, mas com latência significativamente maior — evidenciando o trade-off entre profundidade semântica e velocidade de inferência. Série: LangChain — Agentes com Python — ver índice\n→ Análise de Sentimentos com Llama2 Detecção de Linguagem Tóxica com Gemma Equipe Multiagente para Bitcoin Agente para Ligações de Telemarketing LLM Local com Qwen sem APIs Por que Análise de Sentimentos? Por que Large Language Models? O que faremos aqui? Mãos a obra! Iniciar ambiente de trabalho Carregar dados Informações gerais Análise Exploratória Análise de Sentimentos Resultado Final Conclusão e Discussão Referências Por que Análise de Sentimentos? Compreender os sentimentos por trás de grandes volumes de texto tornou-se essencial, pois em um mundo cada vez mais digitalizado, a capacidade de compreender as respostas e emoções em larga escala das pessoas diante de produtos, eventos ou tópicos específicos não é apenas valiosa por fornecer insights, mas também se tornou uma necessidade para alavancar negócios e tornar-se cada vez mais competitivo.\nAnálise de sentimento, também chamada de mineração de opinião, é o campo de estudo que analisa as opiniões, sentimentos, avaliações, apreciações, atitudes e emoções das pessoas em relação a entidades como produtos, serviços, organizações, indivíduos, questões, eventos, tópicos e seus atributos. Liu 2020\nPor que Large Language Models? A abordagem comum para resolver problemas de NLP envolviam a aplicação de text mining, embeddings como word2vec e GloVe (Global Vectors for Word Representation) e técnicas de Machine Learning, onde modelos como Random Forest, SVM, Naive Bayes, KNN, Ensembles e até mesmo Regressão eram frequentemente utilizados para classificar textos. Além disso, o uso de redes neurais recorrentes (RNNs) sempre foi uma alternativa valiosa, especialmente em situações que demandavam o processamento de dados sequenciais, sendo a LSTM (Long Short-Term Memory) uma variante eficaz para lidar com o desafio conhecido como vanishing gradient.\nJá no cenário atual de modelos pré-treinados, o BERT (Bidirectional Encoder Representations from Transformers) também teve bastante destaque nesse domínio antes da ascensão do ChatGPT, demonstrando a viabilidade como um método gerador de texto e mostraram o poder que as redes neurais têm para gerar longas sequências de texto que antes pareciam inatingíveis.\nGPT-3 supera seus antecessores em termos de contagem de parâmetros\nEmbora já existam há algum tempo, os LLMs ganharam a mídia através do ChatGPT, interface de chat da OpenAI para modelos LLM GPT-3 lançado em 2020, com 175 milhões de parâmetros, que já teve uma série de avanços significativos nos últimos anos como seu irmão maior, o GPT-4 lançado em 2023 conta com incríveis 100 trílhões de parâmetros.\nThe comparison between GPT-3 and GPT-4 based on the number of parameters used in their architecture\nModelos com mais de 100 bilhões de parâmetros já podem ser considerados muito grandes, com conhecimento mundial muito rico. Esses modelos maiores conseguem “aprender” ainda mais informações sobre muitas coisas sobre fisica, filosofia, ciência, programação, etc sendo cada vez mais úteis para ajudar em tarefas que envolvam conhecimento profundo ou raciocinio complexo, sendo um bom “parceiro” para brainstorming.\n⚠️ Atenção! Afirmar que maiores modelos são sempre melhores não é verdade. O tempo de processamento, latência e o custo também irão aumentar, por isso abordagens alternativas também devem ser consideradas.\nComo funcionam os LLMs? Os LLMs são modelos de Machine Learning que usam algoritmos de Deep Learning para processar e compreender a linguagem natural, gerando texto de maneira eficaz. Esses modelos são treinados com grandes volumes de dados da internet, adquirindo a capacidade de identificar padrões na composição de palavras e frases. A idéia básica por trás desses modelos é que são capazes de gerar texto prevendo repetidamente a próxima palavra oferecendo resultados rápidos e diversas aplicações práticas em várias áreas\nO Hands-On Large Language Models, do Jay Alammar, tem as ilustrações que mais me ajudaram a entender isso de fato, o transformer explicado de um jeito que finalmente clica.\nAplicações Diferentemente de uma ferramenta de busca como o Google, o ChatGPT não recupera informações, mas cria frases e textos completos em tempo real com base no processamento de um imenso volume de dados, veja alguns exemplos de uso para diferentes tarefas:\n✍️ Escrita: Colaboração em brainstorming, sugerindo nomes; Elaboração de templates para comunicados e e-mails; Tradução automática. 📖 Leitura: Revisão de textos; Sumarização de artigos extensos; Análise de sentimentos, possibilitando a criação de dashboards para acompnhamento ao longo do tempo (tarefa próxima da detecção de linguagem tóxica com LLMs, que também é uma classificação de texto). 💬 Conversa: Diálogos e aconselhamentos; Coaching de carreira; Planejamento de viagens; Sugestões de receitas; Conversação interativa com documentos PDF; Atendimento ao cliente; Realização de pedidos. O que faremos aqui? Nosso objetivo aqui é realizar uma análise de sentimentos para classificar sentenças como positivas ou negativas utilizando algum LLM pré-treinado. Embora a OpenAI já tenha sido uma organização sem fins lucrativos que lançava seus projetos como código aberto, desde o lançamento do ChatGPT ela se tornou uma empresa que mantém a propriedade de seus códigos fonte. Isso significa que apesar da facilidade de criar aplicações, modelos mais poderosos e relativamente baratos, desenvolvedores de IA não podem modificar o GPT-3 para atender às nossa necessidades específicas ou incorporá-lo em seus próprios projetos de maneira livre e gratuita. Portanto teremos de recorrer à alternativas não tão(*) open source como o Llama 2 da Meta que permite total controle sobre o modelo, rodar em nosso próprio computador/servidor e nós dá o controle sobre a privacidade dos nossos dados.\n(*) “Código aberto” 🤔 Não é totalmente código aberto pois por mais que a Meta tenha disponibilizado o modelo treinado para uso livre, ele não compartilha os dados de treinamento do modelo ou o código usado para treiná-lo.\nMãos a obra! Iniciar ambiente de trabalho Primeiramente vamos carregar todas as dependencias necessárias para executar os códigos a seguir:\nimport pandas as pd import numpy as np import seaborn as sns import matplotlib.pyplot as plt from wordcloud import WordCloud from PIL import Image from nltk.corpus import stopwords from collections import Counter from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix, accuracy_score from llama_cpp import Llama from tqdm.notebook import tqdm tqdm.pandas() Carregar dados Utilizaremos uma versão traduzida do dataset IMdb para o português, um conjunto de dados do Internet Movie Database (IMDB), que é uma das maiores e mais abrangentes bases de dados online sobre filmes e programas de televisão.\nTL;DR\nO post usa o LLM open source Llama 2 (7B) para classificar sentimentos em resenhas do IMDb traduzidas para português, comparando o resultado com o método léxico VADER/LeIA. A acurácia do Llama 2 superou o VADER em cerca de 20 pontos percentuais em inglês e 11,53 pontos percentuais em português. Como o Llama 2 é um modelo de 7 bilhões de parâmetros, já é considerado suficiente para tarefas de classificação de sentimento sem exigir modelos maiores e mais caros. #Importar todo conjunto de dados df = pd.read_csv(\u0026#39;input/imdb-reviews-pt-br.csv\u0026#39;, index_col=\u0026#39;id\u0026#39;) # Obter amostra de tamanho 100 _, df = train_test_split(df, test_size=100, random_state=42, shuffle=True) Informações gerais Esse dataset inclui avaliações e críticas de filmes feitas por usuários do IMDB, bem como informações sobre os próprios filmes, como título, ano de lançamento, gênero, etc. Para nossa finalidade para tarefa de análise de sentimentos, utilizaremos os seguintes dados:\nid text_en text_pt sentiment 12534 This was unusual: a modern-day film which… Isso era incomum: um filme moderno que era… pos 35447 Some of my old friends suggested me to wat… Alguns dos meus velhos amigos sugeriram qu… neg 20281 What a pleasure. This is really a parody. … Que prazer. Isto é realmente uma paródia. S… pos … … … … 34241 WOW!I just was given this film from a frie… WOW! Acabei de receber este filme de um am… neg 12896 This film offers many delights and surprise… Este filme oferece muitas delícias e surp… pos 19748 Over the years Ive watched this movie many… Ao longo dos anos, assisti a esse filme mu… pos Onde:\nid: Identificador; text_en: texto em inglês; text_pt: texto em português; sentiment: rótulo do texto, que pode ser pos ou neg. Análise Exploratória Distribuição dos sentimentos na amostra Primeiro vamos entender como ficou distribuída a proporção dos sentimentos na amostra coletada:\nClique aqui para ver o código do gráfico # Contagem absoluta contagem_absoluta = df[\u0026#39;sentiment\u0026#39;].value_counts() # Contagem relativa contagem_relativa = df[\u0026#39;sentiment\u0026#39;].value_counts(normalize=True) * 100 # Criar gráfico de barras fig, ax = plt.subplots(figsize=(6, 4)) barras = plt.bar(contagem_absoluta.index, contagem_absoluta, color=[\u0026#39;green\u0026#39;, \u0026#39;red\u0026#39;]) # Adicionar texto nas barras for barra, abs_value, rel_value in zip(barras, contagem_absoluta, contagem_relativa): yval = barra.get_height() ax.text(barra.get_x() + barra.get_width()/2, yval, f\u0026#39;{abs_value} ({rel_value:.1f}%)\u0026#39;, ha=\u0026#39;center\u0026#39;, va=\u0026#39;bottom\u0026#39;, color=\u0026#39;black\u0026#39;, fontsize=12) # Adicionar rótulos e título plt.xlabel(\u0026#39;Sentimento\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Frequência absoluta\u0026#39;, fontsize=14) plt.title(\u0026#39;Quantidade de textos de cada sentimento \\nem uma amostra de tamanho 100\u0026#39;, fontsize=16, x=0.5, y=1.1) plt.xticks(fontsize=12) plt.yticks(fontsize=12) # Remover bordas da parte superior e direita ax.spines[\u0026#39;top\u0026#39;].set_visible(False) ax.spines[\u0026#39;right\u0026#39;].set_visible(False) # Ajustar layout plt.tight_layout() # Salvar imagem plt.savefig(f\u0026quot;img/freq_sentiment.png\u0026quot;, bbox_inches=\u0026#39;tight\u0026#39;) # Exibir o gráfico plt.show() 📌 Interpretação: Coletei uma amostra aleatória simples de tamanho n=100 de todas as reviews que contém aproximadamente metade de cada sentimento para diminuir o tempo computacional de execução no meu computador.\nPalavras mais frequentes para cada sentimento Núvens de palavras das resenhas dos filmes que foram anotadas como positivos e como negativos nas duas linguas disponíveis no dataset:\nClique aqui para ver o código das Wordclouds def generate_wordcloud(df, language=\u0026#39;en\u0026#39;): # Definir stopwords para o idioma escolhido if language == \u0026#39;en\u0026#39;: stop_words_pos = stop_words_neg = set(stopwords.words(\u0026#39;english\u0026#39;)) stop_words_pos.update([\u0026quot;film\u0026quot;, \u0026quot;movie\u0026quot;, \u0026quot;one\u0026quot;]) stop_words_neg.update([\u0026quot;character\u0026quot;, \u0026quot;like\u0026quot;, \u0026quot;really\u0026quot;, \u0026quot;make\u0026quot;, \u0026quot;see\u0026quot;]) elif language == \u0026#39;pt\u0026#39;: stop_words_pos = stop_words_neg = set(stopwords.words(\u0026#39;portuguese\u0026#39;)) stop_words_pos.update([\u0026quot;filme\u0026quot;, \u0026quot;filmes\u0026quot;, \u0026quot;todo\u0026quot;, \u0026quot;tão\u0026quot;, \u0026quot;pode\u0026quot;, \u0026quot;todos\u0026quot;]) stop_words_neg.update([\u0026quot;filme\u0026quot;, \u0026quot;filmes\u0026quot;, \u0026quot;todo\u0026quot;, \u0026quot;tão\u0026quot;, \u0026quot;filme\u0026quot;, \u0026quot;coisa\u0026quot;, \u0026quot;realmente\u0026quot;]) else: raise ValueError(\u0026quot;Language must be \u0026#39;en\u0026#39; or \u0026#39;pt\u0026#39;.\u0026quot;) # Concatenar textos positivos e negativos txt_pos = \u0026quot; \u0026quot;.join(review for review in df[df.sentiment == \u0026#39;pos\u0026#39;][f\u0026#39;text_{language}\u0026#39;]) txt_neg = \u0026quot; \u0026quot;.join(review for review in df[df.sentiment == \u0026#39;neg\u0026#39;][f\u0026#39;text_{language}\u0026#39;]) # Carregar máscaras de imagem mask_pos = np.array(Image.open(f\u0026quot;img/pos.png\u0026quot;)) mask_neg = np.array(Image.open(f\u0026quot;img/neg.png\u0026quot;)) # Gerar nuvens de palavras positivas e negativas wordcloud_positivo = WordCloud( stopwords=stop_words_pos, random_state=42, background_color=\u0026quot;white\u0026quot;, color_func=lambda *args, **kwargs: \u0026quot;green\u0026quot;, contour_color=\u0026#39;black\u0026#39;, contour_width=1, max_font_size=100, min_font_size=15, max_words=200, mask=mask_pos ).generate(txt_pos) wordcloud_negativo = WordCloud( stopwords=stop_words_neg, random_state=42, background_color=\u0026quot;white\u0026quot;, color_func=lambda *args, **kwargs: \u0026quot;red\u0026quot;, contour_color=\u0026#39;black\u0026#39;, contour_width=1, max_font_size=100, min_font_size=15, max_words=200, mask=mask_neg ).generate(txt_neg) # Configurações do plot plt.figure(figsize=(7, 14)) # Plotar nuvem de palavras positivas plt.subplot(1, 2, 1) plt.imshow(wordcloud_positivo, interpolation=\u0026#39;bilinear\u0026#39;) plt.axis(\u0026#39;off\u0026#39;) plt.title(\u0026#39;Positivo\u0026#39;, fontsize=20, color=\u0026#39;green\u0026#39;) # Plotar nuvem de palavras negativas plt.subplot(1, 2, 2) plt.imshow(wordcloud_negativo, interpolation=\u0026#39;bilinear\u0026#39;) plt.axis(\u0026#39;off\u0026#39;) plt.title(\u0026#39;Negativo\u0026#39;, fontsize=20, color=\u0026#39;red\u0026#39;) # Ajustar layout plt.tight_layout() # Salvar a nuvem de palavras como imagem plt.savefig(f\u0026quot;img/wordcloud_{language}.png\u0026quot;, bbox_inches=\u0026#39;tight\u0026#39;) # Exibir a nuvem de palavras plt.show() # Exemplo de uso para o idioma inglês generate_wordcloud(df, language=\u0026#39;en\u0026#39;) # Exemplo de uso para o idioma português generate_wordcloud(df, language=\u0026#39;pt\u0026#39;) Núvem de palavras mais frequentes das resenhas em 🇺🇲 Inglês\nNúvem de palavras mais frequentes das resenhas em 🇧🇷 Português\n📌 Interpretação: Como esperado, mesmo com a mudança na língua, a frequência das palavras é exibida de maneira muito similar de acordo com cada sentimento.\nAnálise de Sentimentos Família Llama 2 de Large Language Models (LLMs) Nesta seção, exploraremos o Llama 2, um modelo de código aberto, e discutiremos as vantagens e desvantagens em relação aos LLMs de código fechado ou remotos.\nTamanho do modelo Para saber qual modelo utilizar, primeiramente precisamos ter em mente algumas noções sobre a quantidade de parâmetros e tamanhos dos LLM. No geral:\n1 Bilhão:\nBons em correspondência de padrões e algum conhecimento básico do mundo (como por exemplo classificar avaliações por sentimento)\n10 Bilhões:\nMaior conhecimento mundial, conhecem mais fatos esotéricos sobre o mundo e melhoram em seguir instruções básicas (bom para chatbot para pedidos de comida);\n100+ Bilhões: Muito grandes, com conhecimento mundial muito rico, saberão coisas sobre física, filosofia, ciência e assim por diante e serão melhores em raciocínios complexos (tarefas que envolvem conhecimento profundo ou raciocínio complexo, parceiro para brainstorming)\nPara uma análise de sentimentos simples, não é necessário um modelo com 100 bilhões de parâmetros. Modelos menores, como os com 7 bilhões de parâmetros, podem ser suficientes e menos computacionalmente exigentes.\nCódigo aberto ou fechado Embora próximos, os LLMs de código aberto ainda não conseguem igualar o poder e a precisão dos aplicativos de código fechado disponíveis comercialmente, como GPT-4 e Bard (Gemini). Mesmo sendo menos poderosos, existem alguns prós e contras pelos quais podemos pesar na hora de escolher a melhor opção:\nOpen Source\nTotal controle sobre o modelo Pode rodar em nosso próprio computador/servidor Controle sobre a privacidade dos dados Closed\nFácil de criar aplicações Maiores e mais poderosos Relativamente barato Existe um certo risco de depender do fornecedor Utilizaremos a abordagem de código aberto por ser mais prática para fins de estudos, pois além de gratuita, não exige internet, registros ou chaves de API.\nUso remoto ou local Podemos interagir com o modelo de linguagem grande (LLM) do Llama 2 via API da Hugging Face, seguindo as instruções do repositório oficial da Meta ou podemos baixar os arquivos do modelo em formato GGML para o Llama 2 7B Chat do Meta Llama 2. Os formatos GGML são utilizados para inferência de CPU + GPU usando o principamente o pacote llama-cpp-python.\nPara mais informações sobre como configurar o modelo consulte este link\ndef load_llama_model(model_path=\u0026quot;./input/llama-2-7b-chat.ggmlv3.q2_K.bin\u0026quot;, language=\u0026#39;en\u0026#39;, seed=42): # Determinar o tamanho da janela de contexto com base no idioma if language == \u0026#39;en\u0026#39;: context_window = df.text_en.map(len).max() elif language == \u0026#39;pt\u0026#39;: context_window = df.text_pt.map(len).max() else: raise ValueError(\u0026quot;Language must be \u0026#39;en\u0026#39; or \u0026#39;pt\u0026#39;.\u0026quot;) # Carregar o modelo Llama return Llama(model_path=model_path, verbose=False, n_ctx=context_window, seed=seed) Para obter os melhores resultados, devemos ser o mais claro e específicos possível nas interações. Porém devemos iniciar com um prompt simples e rápido para ir direcionando o modelo na direção desejada e avaliando os resultados obtidos e ajustando gradualmente o prompt para refinar e aprimorar a resposta desejada\ndef classify_sentiment_llama(text, llama_model): # Construir a prompt para o modelo Llama prompt = f\u0026#39;\u0026#39;\u0026#39; \\ Q: Answer with just one word, \\ does the following text express a \\ positive or negative feeling? \\ {text} \\ A:\u0026#39;\u0026#39;\u0026#39; # Obter a saída do modelo Llama output = llama_model(prompt, max_tokens=3) return output[\u0026quot;choices\u0026quot;][0][\u0026quot;text\u0026quot;] Com nosso prompt definido, já podemos carregar o modelo:\n# Carregar o modelo Llama para o idioma desejado llama_model = load_llama_model(language=\u0026#39;en\u0026#39;) ## llama.cpp: loading model from ./llama-2-7b-chat.ggmlv3.q2_K.bin ## llama_model_load_internal: format = ggjt v3 (latest) ## llama_model_load_internal: n_vocab = 32000 ## llama_model_load_internal: n_ctx = 4320 ## llama_model_load_internal: n_embd = 4096 ## llama_model_load_internal: n_mult = 256 ## llama_model_load_internal: n_head = 32 ## llama_model_load_internal: n_head_kv = 32 ## llama_model_load_internal: n_layer = 32 ## llama_model_load_internal: n_rot = 128 ## llama_model_load_internal: n_gqa = 1 ## llama_model_load_internal: rnorm_eps = 5.0e-06 ## llama_model_load_internal: n_ff = 11008 ## llama_model_load_internal: freq_base = 10000.0 ## llama_model_load_internal: freq_scale = 1 ## llama_model_load_internal: ftype = 10 (mostly Q2_K) ## llama_model_load_internal: model size = 7B ## llama_model_load_internal: ggml ctx size = 0.08 MB ## llama_model_load_internal: mem required = 2733.66 MB (+ 2160.00 MB per state) ## llama_new_context_with_model: kv self size = 2160.00 MB ## llama_new_context_with_model: compute buffer total size = 295.35 MB Após instanciar o modelo, basta aplicá-lo em nossa base de dados. (apliquei o mesmo modelo tanto para as reviews e português quanto em inglês).\ndf[\u0026#39;sentiment_llm_en\u0026#39;] = df.text_en.progress_apply(lambda x: classify_sentiment_llama(x, llama_model)) Como este modelo é o mais básico e não alteramos nenhum parâmetro (como por exemplo temperature, que determina se o output será mais aleatório ou mais previsível) pode ser que a saída não saia padronizada e necessite de algum pós-processamento. Vejamos como foram os outputs do LLM:\nClique aqui para ver o código do gráfico # Contagem da frequência das classificações sentiment_llm_counts = df.groupby(\u0026#39;sentiment\u0026#39;).sentiment_llm_en.value_counts().reset_index(name=\u0026#39;n\u0026#39;) # Organizar as categorias pela frequência total order = df.sentiment_llm_en.value_counts().reset_index(name=\u0026#39;n\u0026#39;) order = order.sort_values(by=\u0026#39;n\u0026#39;, ascending=False)[\u0026#39;index\u0026#39;] # Configurações de estilo do seaborn sns.set(style=\u0026quot;whitegrid\u0026quot;) # Criar o gráfico de barras plt.figure(figsize=(12, 4)) ax = sns.barplot(x=sentiment_llm_counts.sentiment_llm_en, y=sentiment_llm_counts.n, hue=sentiment_llm_counts.sentiment, order=order, palette=[\u0026quot;red\u0026quot;, \u0026quot;green\u0026quot;]) # Adicionar rótulos e título plt.ylim([0, 25]) plt.xticks(fontsize=12, rotation=90) plt.yticks(fontsize=12) ax.set_xlabel(\u0026#39;Anotação de sentimento das resenhas\u0026#39;, fontsize=14) ax.set_ylabel(\u0026#39;Frequência\u0026#39;, fontsize=14) ax.set_title(\u0026#39;Frequência dos sentimentos classificados pelo LLM em Inglês\\nem relação aos sentimentos já anotados da base\u0026#39;, fontsize=20) # Adicionar anotações nas barras for p in ax.patches: ax.annotate(f\u0026#39;{p.get_height()}\u0026#39;, (p.get_x() + p.get_width() / 2., p.get_height()), ha=\u0026#39;center\u0026#39;, va=\u0026#39;baseline\u0026#39;, fontsize=10, color=\u0026#39;black\u0026#39;, xytext=(0, 5), textcoords=\u0026#39;offset points\u0026#39;) plt.legend(loc=\u0026quot;upper right\u0026quot;, title = \u0026quot;Label real\u0026quot;) # Remover bordas da parte superior e direita ax.spines[\u0026#39;top\u0026#39;].set_visible(False) ax.spines[\u0026#39;right\u0026#39;].set_visible(False) ax.grid(False) # Salvar a nuvem de palavras como imagem plt.savefig(f\u0026quot;img/freq_class_llm_en.png\u0026quot;, bbox_inches=\u0026#39;tight\u0026#39;) # Exibir o gráfico plt.show() 📌 Interpretação: É possível observar que o modelo pré-treinado conseguiu reconhecer de maneira bastante coerente o sentimento dos trechos para as categorias pos e neg, porém, não vieram padronizadas exatamente como solicitamos ao modelo.\nComo a saída não foi padronizada, vamos realizar algum pós-processamento para padronizar as classes como pos ou neg para possibilitar avaliar o desempenho do modelo com base em métricas de classificação.\nconditions = [ (df.sentiment_llm_en.str.contains(\u0026#39;(?i)(?:pos|fun)\u0026#39;)), (df.sentiment_llm_en.str.contains(\u0026#39;(?i)(?:neg|horrible|melanchol)\u0026#39;)) ] pd.crosstab(df.sentiment, np.select(conditions, [\u0026#39;pos\u0026#39;, \u0026#39;neg\u0026#39;], default=\u0026#39;other\u0026#39;)) Com os outputs padronizados em duas classes, podemos verificar como foi a acurácia do modelo.\nDesempenho Como estamos diante de um problema de classificação, avaliaremos o desempenho do modelo com matrizes de confusão para entender a as taxas de acerto e calcular a acurácia pois o dataset é balanceado.\nClique aqui para ver o código do gráfico # Matrizes de Confusão conditions = [ (df.sentiment_llm_en.str.contains(\u0026#39;(?i)(?:pos|fun|good|comedy)\u0026#39;)), (df.sentiment_llm_en.str.contains(\u0026#39;(?i)(?:neg|melanchol|absurd|horrible)\u0026#39;)) ] cm_llm_en = confusion_matrix(df.sentiment, np.select(conditions, [\u0026#39;pos\u0026#39;, \u0026#39;neg\u0026#39;], default=\u0026#39;other\u0026#39;)) accuracy_llm_en = accuracy_score(df.sentiment, np.select(conditions, [\u0026#39;pos\u0026#39;, \u0026#39;neg\u0026#39;], default=\u0026#39;other\u0026#39;)) conditions = [ (df.sentiment_llm_pt.str.contains(\u0026#39;(?i)(?:pos)\u0026#39;)), (df.sentiment_llm_pt.str.contains(\u0026#39;(?i)(?:neg|horrível)\u0026#39;)) ] cm_llm_pt = confusion_matrix(df.sentiment, np.select(conditions, [\u0026#39;pos\u0026#39;, \u0026#39;neg\u0026#39;], default=\u0026#39;other\u0026#39;)) accuracy_llm_pt = accuracy_score(df.sentiment, np.select(conditions, [\u0026#39;pos\u0026#39;, \u0026#39;neg\u0026#39;], default=\u0026#39;other\u0026#39;)) # Configurações de estilo do seaborn sns.set(font_scale=1.2) plt.figure(figsize=(12, 5)) # Plotar Matriz de Confusão para o modelo de LLM em inglês plt.subplot(1, 2, 1) sns.heatmap(cm_llm_en, annot=True, fmt=\u0026#39;d\u0026#39;, cmap=\u0026#39;binary\u0026#39;, cbar=False, vmin=0, vmax=50, xticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;], yticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;]) plt.title(f\u0026#39;Matriz de Confusão (Vader - Inglês)\\nAcurácia: {accuracy_llm_en:.0%}\u0026#39;, fontsize=22) plt.xlabel(\u0026#39;Previsto\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Real\u0026#39;, fontsize=14) plt.xticks(fontsize=12) plt.yticks(fontsize=12) # Plotar Matriz de Confusão para o modelo de LLM em português plt.subplot(1, 2, 2) sns.heatmap(cm_llm_pt, annot=True, fmt=\u0026#39;d\u0026#39;, cmap=\u0026#39;binary\u0026#39;, cbar=False,vmin=0, vmax=50, xticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;], yticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;]) plt.title(f\u0026#39;Matriz de Confusão (Vader - Português)\\nAcurácia: {accuracy_llm_pt:.0%}\u0026#39;, fontsize=22) plt.xlabel(\u0026#39;Previsto\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Real\u0026#39;, fontsize=14) plt.xticks(fontsize=12) plt.yticks(fontsize=12) # Ajustar layout plt.tight_layout() # Salvar a nuvem de palavras como imagem plt.savefig(f\u0026quot;img/cm_llm.png\u0026quot;, bbox_inches=\u0026#39;tight\u0026#39;) # Exibir o gráfico plt.show() 📌 Interpretação: A acurácia geral para a língua Inglesa foi superior quando aplicado o mesmo modelo para a língua portuguesa. Vale lembrar que este modelo foi treinado em Inglês e estamos utilizado a menor das opções.\nO desempenho deste modelo é muito interessante, principalmente por já ser pré treinado, não sendo necessário gastar tanto tempo na sua construção mas para afirmar que este modelo é bom precisamos entender qual seria o resultado para resolver este problemas se utilizassemos a abordagem mais simples possível.\nVader O VADER (Valence Aware Dictionary and sEntiment Reasoner) é uma abordagem mais simples e rápida em comparação aos LLMs. Não requer o treinamento de um modelo, mas depende de léxicos de palavras relacionadas a sentimentos. Pode ser facilmente utilizado via bibliotecas de código aberto em Python, como vaderSentiment para inglês e LeIA (Léxico para Inferência Adaptada) para português.\nA abordagem é direta: no léxico (uma coleção de palavras), cada palavra já possui uma nota atribuída. Ao passar um documento (frase), retorna um dicionário com o escore de polaridade com base no escore das palavras no texto. O dicionário inclui o valor do sentimento geral normalizado (compound), variando de -1 (extremamente negativo) a +1 (extremamente positivo). Esse valor pode ser usado para descrever o sentimento predominante no texto, considerando os seguintes limites:\nSentimento positivo: compound \u0026gt;= 0.05 Sentimento negativo: compound \u0026lt;= -0.05 Sentimento neutro: (compound \u0026gt; -0.05) e (compound \u0026lt; 0.05) Clique aqui para ver a função utilizada para classificar o sentimento com base no escore compound # Função para classificar o sentimento com base no compound score def classify_sentiment_vader(text, language=\u0026#39;en\u0026#39;): # Definir método que será utilizado if language==\u0026#39;en\u0026#39;: from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer elif language == \u0026#39;pt\u0026#39;: from leia import SentimentIntensityAnalyzer else: raise ValueError(\u0026quot;Language must be \u0026#39;en\u0026#39; or \u0026#39;pt\u0026#39;.\u0026quot;) # Instanciar a ferramenta para análise de sentimentos analyzer = SentimentIntensityAnalyzer() # Realiza a análise de sentimentos e obtém o compound score compound_score = analyzer.polarity_scores(text)[\u0026#39;compound\u0026#39;] # Classifica o sentimento com base no compound score if compound_score \u0026gt;= 0.05: return \u0026#39;pos\u0026#39; elif compound_score \u0026lt;= -0.05: return \u0026#39;neg\u0026#39; else: return \u0026#39;neu\u0026#39; # Criando uma nova coluna \u0026#39;sentimento_vader\u0026#39; df[\u0026#39;sentiment_vader_en\u0026#39;] = df.text_en.apply(lambda x: classify_sentiment_vader(x, \u0026#39;en\u0026#39;)) df[\u0026#39;sentiment_vader_pt\u0026#39;] = df.text_pt.apply(lambda x: classify_sentiment_vader(x, \u0026#39;pt\u0026#39;)) A execução do código é bem rápida, sendo útil para referência como baseline ou em casos em que temos baixo recurso computacional e um grande volume de dados para classificar.\nDesempenho Como estamos diante de um problema de classificação, avaliaremos o desempenho do modelo com matrizes de confusão para entender a as taxas de acerto e calcular a acurácia pois o dataset é balanceado.\nClique aqui para ver o código do gráfico # Matrizes de Confusão cm_vader_en = confusion_matrix(df.sentiment, df.sentiment_vader_en) cm_vader_pt = confusion_matrix(df.sentiment, df.sentiment_vader_pt) # Acurácias accuracy_vader_en = accuracy_score(df.sentiment, df.sentiment_vader_en) accuracy_vader_pt = accuracy_score(df.sentiment, df.sentiment_vader_pt) # Configurações de estilo do seaborn sns.set(font_scale=1.2) plt.figure(figsize=(12, 5)) # Plotar Matriz de Confusão para o método Vader em inglês plt.subplot(1, 2, 1) sns.heatmap(cm_vader_en, annot=True, fmt=\u0026#39;d\u0026#39;, cmap=\u0026#39;binary\u0026#39;, cbar=False,vmin=0, vmax=50, xticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;], yticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;]) plt.title(f\u0026#39;Matriz de Confusão (Vader - Inglês)\\nAcurácia: {accuracy_vader_en:.0%}\u0026#39;, fontsize=22) plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.xlabel(\u0026#39;Previsto\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Real\u0026#39;, fontsize=14) # Plotar Matriz de Confusão para o método Vader em português plt.subplot(1, 2, 2) sns.heatmap(cm_vader_pt, annot=True, fmt=\u0026#39;d\u0026#39;, cmap=\u0026#39;binary\u0026#39;, cbar=False,vmin=0, vmax=50, xticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;], yticklabels=[\u0026#39;Negativo\u0026#39;, \u0026#39;Neutro\u0026#39;, \u0026#39;Positivo\u0026#39;]) plt.title(f\u0026#39;Matriz de Confusão (Vader - Português)\\nAcurácia: {accuracy_vader_pt:.0%}\u0026#39;, fontsize=22) plt.xticks(fontsize=12) plt.yticks(fontsize=12) plt.xlabel(\u0026#39;Previsto\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Real\u0026#39;, fontsize=14) # Ajustar layout plt.tight_layout() # Salvar a nuvem de palavras como imagem plt.savefig(f\u0026quot;img/cm_vader.png\u0026quot;, bbox_inches=\u0026#39;tight\u0026#39;) # Exibir o gráfico plt.show() 📌 Interpretação: A acurácia geral do método foi praticamente o mesmo para ambas as linguas. Na lingua inglesa observamos mais casos de falsos positivos (22%), já na lingua portuguesa observamos mais casos de falsos negativos (14%).\nEssa abordagem é boa para ser utilizada como baseline pois quase todas as abordagens tradicionais de Machine Learning para a tarefa de análise de sentimentos necessitam de tempo para desenvolvimento, treino, validação e sustentação de modelos.\nResultado Final Avaliamos o desempenho de ambas as abordagens para determinar se o uso do LLM justificou-se em comparação com a abordagem mais simples para a execução da tarefa de análise de sentimentos.\nClique aqui para ver o código do gráfico models = ( \u0026quot;Inglês\u0026quot;, \u0026quot;Português\u0026quot;, ) weight_counts = { \u0026quot;Vader\u0026quot;: np.array([accuracy_vader_en, accuracy_vader_pt]), \u0026quot;LLM\u0026quot;: np.array([accuracy_llm_en-accuracy_vader_en, accuracy_llm_pt-accuracy_vader_pt]), } fig, ax = plt.subplots() bottom = np.zeros(2) colors=[\u0026quot;#b4dbe6\u0026quot;, \u0026quot;#024b7a\u0026quot;] for (boolean, weight_count), col in zip(weight_counts.items(), colors): p = ax.bar(models, weight_count, width=0.5, label=boolean, bottom=bottom, color=col) bottom += weight_count # Formatar eixos plt.ylim([0, 1.1]) plt.xlabel(\u0026#39;Idioma das resenhas dos filmes\u0026#39;, fontsize=14) plt.ylabel(\u0026#39;Ganho de Acurácia\u0026#39;, fontsize=14) plt.title(\u0026quot;Comparação do ganho de acurácia \\ndo LLM em relação ao Vader\u0026quot;, fontsize=16, x=0.5) plt.xticks(fontsize=12) plt.yticks(fontsize=12) # Legenda ax.legend(loc=\u0026quot;upper right\u0026quot;, title=\u0026#39;Método utilizado\u0026#39;) #specify order of items in legend handles, labels = plt.gca().get_legend_handles_labels() order = [1, 0] plt.legend([handles[idx] for idx in order],[labels[idx] for idx in order]) accs=[x*100 for x in [accuracy_vader_en, accuracy_vader_pt, accuracy_llm_en, accuracy_llm_pt]] for p, acc in zip(ax.patches, accs): width, height = p.get_width(), p.get_height() x, y = p.get_xy() ax.text(x+width/2, y+(height/2) - 0.01, \u0026#39;{:.0f} %\u0026#39;.format(acc), horizontalalignment=\u0026#39;center\u0026#39;, verticalalignment=\u0026#39;center\u0026#39;, color=\u0026#39;white\u0026#39;, fontsize=18) # Adicionar setas e textos na figura plt.arrow(0.3, 0.62, 0, 0.16, head_width = 0.05, width = 0.015, color=\u0026#39;black\u0026#39;) plt.text(0.2, 0.9, \u0026#39;+20,0%\u0026#39;, fontsize = 20) plt.arrow(0.7, 0.63, 0, 0.09, head_width = 0.05, width = 0.015, color=\u0026#39;black\u0026#39;) plt.text(0.6, 0.84, \u0026#39;+11,53%\u0026#39;, fontsize = 20) # Remover bordas da parte superior e direita ax.spines[\u0026#39;top\u0026#39;].set_visible(False) ax.spines[\u0026#39;right\u0026#39;].set_visible(False) ax.spines[\u0026#39;bottom\u0026#39;].set_visible(True) ax.spines[\u0026#39;left\u0026#39;].set_visible(True) ax.grid(visible=None) ax.set_facecolor(\u0026#39;white\u0026#39;) # Ajustar layout plt.tight_layout() # Salvar a nuvem de palavras como imagem plt.savefig(f\u0026quot;img/acc_comparation.png\u0026quot;, bbox_inches=\u0026#39;tight\u0026#39;) # Exibir o gráfico plt.show() 📌 Interpretação: A acurácia geral foi consideravelmente maior para o modelo Llama2 em ambas as línguas, mesmo sendo treinado principalmente em dados da língua inglesa.\nConclusão e Discussão Os avanços tecnológicos na área são verdadeiramente impressionantes e evidenciam a rápida evolução da inteligência artificial. É importante estarmos sempre atentos a essas mudanças, pois a área de LLMs está em constante crescimento e melhorias significativas são desenvolvidas diariamente.\nEm meio a tantos avanços, também é importante reconhecer as limitações desses modelos. Um dos desafios é o corte de conhecimento (knowledge cutoffs), o que significa que o modelo é treinado até uma determinada data, como 2022, portanto não possui conhecimento sobre eventos ou desenvolvimentos que ocorreram após essa data. Além disso, os LLMs estão sujeitos a “hallucinations”, ou seja, podem inventar informações em um tom muito confiante, o que pode levar a resultados imprecisos ou até mesmo prejudiciais.\nOutras limitações incluem restrições no input e output dos modelos, o que pode tornar difícil lidar com grandes volumes de dados ou fornecer resultados completos de uma só vez. Além disso, os LLMs geralmente não funcionam bem com dados estruturados, como tabelas, e podem reproduzir vieses e toxicidade presentes na sociedade, o que levanta preocupações éticas e sociais importantes.\nPortanto, enquanto exploramos esse vasto campo das redes neurais, é essencial abordar essas limitações e desenvolver soluções que permitam o uso ético e responsável dessas poderosas ferramentas de IA.\nPara outras aplicações práticas de IA com texto e imagem, veja os posts sobre extração de informações de imagens com o modelo Llava e sobre como criar audiobooks com IA.\nPara ver essa mesma abordagem aplicada em produção — análise de ligações de telemarketing com Whisper, Pyannote e LangChain — confira o post Agente para análise interpretativa de ligações de telemarketing.\nReferências Large-scale language models for innovation and technology intelligence: sentiment analysis on news articles Análise de sentimentos com redes neurais recorrentes LSTM Generative AI for Everyone - Andrew Ng - Coursera Course Run Llama 2 Locally with Python Perguntas frequentes O Llama 2 é realmente um LLM de código aberto?\nNão totalmente. Embora a Meta disponibilize o modelo treinado para uso livre, ela não compartilha os dados de treinamento nem o código usado para treiná-lo.\nO Llama 2 teve desempenho melhor que o VADER na análise de sentimentos?\nSim. A acurácia do Llama 2 foi consideravelmente maior nas duas línguas testadas, com ganho de cerca de 20 pontos percentuais em inglês e 11,53 em português em relação ao VADER.\nQual dataset foi usado para testar a análise de sentimentos?\nFoi usada uma amostra de 100 resenhas de uma versão traduzida do dataset IMDb para o português, com sentimentos rotulados como positivo ou negativo.\n","date":"20 de abril de 2024","externalUrl":null,"permalink":"/post/2024-04-20-sentiment-analysis-llama2/","section":"Posts","summary":" TL;DR\nO modelo Llama2-7b-chat-hf foi executado localmente via Hugging Face Transformers para classificar textos como positivos, negativos ou neutros, sem custo de API. A abordagem foi avaliada contra o VADER (léxico clássico de análise de sentimentos) em um conjunto de avaliações de filmes em inglês, usando acurácia como métrica. O Llama2 superou o VADER na captura de ironia e contexto, mas com latência significativamente maior — evidenciando o trade-off entre profundidade semântica e velocidade de inferência. Série: LangChain — Agentes com Python — ver índice\n","title":"Análise de Sentimentos com um \"ChatGPT\" de Código Aberto","type":"post"},{"content":"","date":"20 de abril de 2024","externalUrl":null,"permalink":"/tags/gam/","section":"Tags","summary":"","title":"Gam","type":"tags"},{"content":"","date":"20 de abril de 2024","externalUrl":null,"permalink":"/tags/redes-neurais/","section":"Tags","summary":"","title":"Redes-Neurais","type":"tags"},{"content":"Posts desta série, do mais básico ao mais avançado:\nAnálise de Sentimentos com Llama2 de Código Aberto — fundamentos: LLM open source + análise de texto Detecção de Linguagem Tóxica com Gemma e LangChain — classificação com prompt engineering Equipe Multiagente de IA para Análise do Bitcoin — LangGraph: múltiplos agentes orquestrados Agente para Análise de Ligações de Telemarketing — produção: Whisper + Pyannote + LangChain Agente com LLM Local sem APIs Externas — local: Qwen + llama.cpp + GGUF ","date":"20 de abril de 2024","externalUrl":null,"permalink":"/resources/langchain-series/","section":"Recursos","summary":"Posts desta série, do mais básico ao mais avançado:\nAnálise de Sentimentos com Llama2 de Código Aberto — fundamentos: LLM open source + análise de texto Detecção de Linguagem Tóxica com Gemma e LangChain — classificação com prompt engineering Equipe Multiagente de IA para Análise do Bitcoin — LangGraph: múltiplos agentes orquestrados Agente para Análise de Ligações de Telemarketing — produção: Whisper + Pyannote + LangChain Agente com LLM Local sem APIs Externas — local: Qwen + llama.cpp + GGUF ","title":"Série LangChain — Agentes com Python","type":"resources"},{"content":"","date":"30 de maio de 2023","externalUrl":null,"permalink":"/tags/catboost/","section":"Tags","summary":"","title":"Catboost","type":"tags"},{"content":"","date":"30 de maio de 2023","externalUrl":null,"permalink":"/tags/data-mining/","section":"Tags","summary":"","title":"Data-Mining","type":"tags"},{"content":"","date":"30 de maio de 2023","externalUrl":null,"permalink":"/tags/modelagem/","section":"Tags","summary":"","title":"Modelagem","type":"tags"},{"content":"","date":"30 de maio de 2023","externalUrl":null,"permalink":"/tags/pratica/","section":"Tags","summary":"","title":"Pratica","type":"tags"},{"content":"","date":"30 de maio de 2023","externalUrl":null,"permalink":"/tags/r/","section":"Tags","summary":"","title":"R","type":"tags"},{"content":" Introdução Definição do problema de negócio Soluções Estratégia analítica Decisões sobre a target Processamento dos Dados Dados Externos Feature Engineering Modelos Ensemble Post Processing Considerações Finais Introdução O TFUG - TensorFlow Users Group de São Paulo lançou uma nova competição no Kaggle onde o objetivo era desenvolver modelos para previsão de diagnóstico de síndromes respiratórias, que é um tema relacionado com um dos 17 tópicos de Desenvolvimento Sustentável das Nações Unidas - Boa saúde e bem-estar.\nModelo que decide sobre diagnóstico é modelo que pesa. O Fairness and Machine Learning é leitura obrigatória sempre que o algoritmo que a gente constrói toca em gente de verdade.\nComo um cientista de dados, acredito que seja muito importante continuarmos aprimorando nossas habilidades e conhecimentos. Competições como essa são muito divertidas e possibilitam que testemos nossos limites em um ambiente competitivo e colaborativo, além de ser uma grande oportunidade para nos desafiarmos e aprender uns com os outros.\nTive o enorme prazer de conquistar o primeiro lugar, dessa vez com meu grande amigo Kaike, parceiro de competições de longa data que trouxe grande sinergia para a solução final com a contribuição de seu modelo (compartilhado abertamente no Kaggle).\nAqui estão alguns dos prêmios recebidos:\nComo nesta competição havia bastante trabalho a ser feito e tivemos apenas 1 mês para trabalhar na solução, foi preciso fazer uma boa gestão do código e do tempo de desenvolvimento.\nTL;DR\n1º lugar na ML Olympiad (Kaggle), prevendo o agente causador de síndromes respiratórias. Modelos individuais por classe superaram um único modelo multiclasse, sobretudo nas classes mais desbalanceadas. O pós-processamento (threshold otimizado por classe) foi o maior diferencial do score final. Definição do problema de negócio O objetivo desta competição consistiu em predizer qual o agente causador da síndrome respiratória aguda grave com base nos dados e sintomas dos pacientes.\nEsta tarefa pode ser enquadrada como um problema supervisionado de classificação multinomial (com múltiplos outputs) na qual as previsões são, de certa forma, dependentes da entrada umas das outras (o paciente só pode ter registrado uma das doenças).\nA validação da solução foi feita utilizando a métrica Macro (or Mean) F1-Score, que é basicamente a média do F1 calculado sobre as previsões de cada nota.\nSoluções Ambas soluções (minha e do Kaike) foram compartilhadas no Kaggle:\nML Olympiad - 1º Lugar - Catboost + Pos Process (Fellipe) ML Olypiads - 1º Lugar - LightGBM Binary Ensemble (Kaike) ML Olympiad - 1º Lugar - Blending (combinação das soluções em um emsemble) Disponibilizamos também a solução em formato de vídeo, gravado em um meetup com duração de 1 hora e meia para o canal do TensorFlow UGSP no Youtube no link: https://youtu.be/6HPJn38NF3w\nEstratégia analítica Nas seções abaixo apresento o racional por trás da minha solução, como chegamos nos 5 melhores modelos individuais (para cada doença respiratória) que utilizei em um ensemble para chegar ao primeiro lugar, bem como a estratégia de pós processamento que com que o score melhorasse significativamente.\nDecisões sobre a target A primeira decisão importante era definir como enquadrar o problema; se utilizaríamos 1 modelo multiclasse ou diferentes modelos para cada classe.\nEm todos os testes que fizemos, os modelos individuais superaram o F1-Score Macro de um modelo único. Como 3 das classes eram bastante desbalanceadas, acredito que modelos especializados nesses casos conseguiram captar melhor suas nuances.\nProcessamento dos Dados Como optamos por unificar os resultados apenas na reta final, meu pré-processamento foi muito diferente do feito pelo Kaike e isso foi fundamental para que as estimativas dos nossos modelos tivessem baixa correlação. Não focarei aqui no meu pré-processamento, pois não acho que foi o diferencial para atingir um score superior a 0.6 (quem tiver curiosidade está tudo bem documentado nos notebooks compartilhados).\nDados Externos O fato de não termos as informações do ano em que esses dados foram coletados dificultou na busca de bases externas, pois indicadores socioeconômicos e de saúde variam bastante ao longo do tempo.\nFizemos alguns testes utilizando o Atlas do Desenvolvimento Humano (ADH), mas não tivemos muito sucesso, pois esses dados estão muito defasados (1991-2010). Também tentamos acrescentar a informação de latitude e longitude de cada município, mas isso não trouxe uma melhora substancial no nosso score.\nFeature Engineering Outra etapa em que investimos bastante tempo foi para criar novas variáveis.\nNovamente, nossa engenharia de recursos foi feita de maneira separada para que nossos modelos aprendessem aspectos diferentes dos dados. Abaixo, compartilho algumas das features que desenvolvi apenas para o meu modelo:\nPresença de sintomas relacionados à Target; Se tomografia era típica do COVID; Intervalo de idade com mais casos; Idade discretizada; Diferença entre a semana de notificação e primeiros sintomas; Novas features baseadas nas contagens de algumas features categóricas; etc. Modelos Além de pré-processamentos e feature engineering diferentes, também utilizamos modelos e mecanismos de tunning diferentes, o que ajudou para que nossas estimativas tivessem baixa correlação. Eu usei o Catboost como modelo final, já o Kaike optou por um LightGBM com tuning de hiperparametros.\nEnsemble Calculamos a média das probabilidades previstas de cada modelo para cada classe antes de selecionar a classe que tivesse a maior probabilidade.\nComo nossas previsões tinham baixa correlação, conseguimos ser bem sucedidos no ensemble combinando nossas submissões com score ~0.6 alcançando ~0.61 na tabela pública.\nPost Processing Acredito que o diferencial dessa competição estava no pós processamento.\nQuando avaliamos o score do modelo de cada classe, também calculamos um threshold que maximizava os respectivos F1.\nObservamos que nosso modelo para a classe 5 apresentava um F1 muito superior às demais classes com esse threshold otimizado, então fizemos o seguinte:\nCalculamos as probabilidades individuais para cada classe; Selecionamos a classe que tinha maior probabilidade estimada em cada instância; Pegamos a classificação binária da classe 5 com o threshold otimizado e aplicamos a seguinte condição: Se o modelo da classe 5 estimou que y5[i]==1, então yfinal[i] é 5, caso contrário, use a classe de maior probabilidade entre as outras 4. (Em outras palavras: np.where(y5_test_class==1, 5, sub.CLASSI_FIN)) Considerações Finais Foi uma competição muito interessante e desafiadora. Agradeço imensamente ao TFUG por organizar o evento e a todos os participantes que contribuíram para o aprendizado coletivo. Foi uma ótima oportunidade de aprendizado e troca de experiências.\nEspero que minha solução possa ser útil para outros projetos e desafios futuros.\nPara outras soluções completas de competições no Kaggle, veja os posts sobre o Porto Seguro Data Challenge e sobre a competição de qualidade da educação.\nPerguntas frequentes Por que usar um modelo por classe em vez de um único modelo multiclasse? Porque, neste problema, os modelos individuais por classe superaram o F1-Score Macro de um único modelo multiclasse, especialmente nas classes mais desbalanceadas, onde um modelo especializado captura melhor as nuances daquela classe específica.\nQual foi o principal diferencial para vencer a competição? O pós-processamento: calcular um threshold otimizado por classe e aplicar uma regra de prioridade (se o modelo da classe com melhor F1 previsse positivo, usar essa classe; caso contrário, usar a de maior probabilidade entre as demais) rendeu mais ganho de score do que ajustes no pré-processamento ou nos modelos.\nPor que combinar duas soluções diferentes em um ensemble? Porque os dois pré-processamentos foram feitos de forma independente, gerando previsões com baixa correlação entre si. Combinar previsões pouco correlacionadas costuma reduzir o erro do conjunto mais do que combinar soluções parecidas.\n","date":"30 de maio de 2023","externalUrl":null,"permalink":"/post/2023-05-30-solucao-final-ensure-healthy-lives-kaggle-competition/","section":"Posts","summary":" Introdução Definição do problema de negócio Soluções Estratégia analítica Decisões sobre a target Processamento dos Dados Dados Externos Feature Engineering Modelos Ensemble Post Processing Considerações Finais Introdução O TFUG - TensorFlow Users Group de São Paulo lançou uma nova competição no Kaggle onde o objetivo era desenvolver modelos para previsão de diagnóstico de síndromes respiratórias, que é um tema relacionado com um dos 17 tópicos de Desenvolvimento Sustentável das Nações Unidas - Boa saúde e bem-estar.\n","title":"Solução Final - ML Olympiad [1º lugar]","type":"post"},{"content":"","date":"8 de agosto de 2022","externalUrl":null,"permalink":"/tags/dalle2/","section":"Tags","summary":"","title":"Dalle2","type":"tags"},{"content":"","date":"8 de agosto de 2022","externalUrl":null,"permalink":"/tags/dataart/","section":"Tags","summary":"","title":"Dataart","type":"tags"},{"content":"","date":"8 de agosto de 2022","externalUrl":null,"permalink":"/tags/gan/","section":"Tags","summary":"","title":"Gan","type":"tags"},{"content":" Introdução DALL·E 2 Instruções de Uso Parâmetros Exemplos DALL·E Mini e Stable Diffusion Exemplos Opções Alternativas VQGAN+CLIP Mais Parâmetros Mais Exemplos Discussão Filosófica Conclusão Referências Introdução Você já deve ter ouvido falar sobre uma inteligência artificial que gera artes super-realistas a partir de textos e imagens. Hoje em dia já existem algumas opções como DALL·E 2 (da OpenAI/Google) e a Make-A-Scene (da Meta), e essas ferramentas são capazes de gerar versões e estilos diferentes de uma dada imagem ou ainda criar uma imagem com apenas uma breve descrição do resultado desejado. As imagens podem ser tão aleatórias quanto um “gato de óculos e uma coroa” (em homenagem ao dia dos gatos):\nImagem gerada por gomesfellipe utilizando DALL·E 2 Não vou entrar na teoria por trás dos algoritmos pois além do artigo oficial, existe bastante conteúdo sobre o assunto disponível na internet. Neste post focarei mais em fazer alguns comentários sobre o que andei estudando e compartilhar algumas dicas úteis sobre como escrever os “parâmetros” ou “queries” para sistemas DALL·E 2 (ou alternativos). Se você prefere ver IA generativa aplicada a problemas práticos de dados — como extrair texto de imagens de notas fiscais —, veja o post sobre extração de informações de imagens com IA generativa.\nNão posso prometer que depois de ler este post você estará imediatamente capaz de criar artes incríveis utilizando IA até porque eu também sou iniciante no assunto, mas terá algum conhecimento básico para poder trabalhar e desenvolver ainda mais suas habilidades. Para ser honesto, uma vez que acostumamos, não é muito difícil de usar. Não há necessidade de escrever nenhuma linha de código para utilizar a DALL·E 2 nem as outras arquiteturas que apresentarei neste post (no máximo ajustar alguns hiperparâmetros, caso queira).\nTL;DR\nO post explica como usar DALL·E 2, DALL·E Mini e Stable Diffusion para gerar arte a partir de texto, sem escrever código. Traz dicas práticas de como escrever \"parâmetros\" (prompts) descritivos, incluindo exemplos comparando prompts vagos e detalhados. Apresenta o VQGAN+CLIP como alternativa gratuita via Google Colab para quem ainda não tinha acesso ao DALL·E 2. DALL·E 2 A OpenAI lançou em Janeiro de 2021 o DALL·E e um ano depois, sua segunda geração que constrói imagens mais realistas e precisas, com resolução 4x maior. DALL·E 2 começou como um projeto de pesquisa e agora está disponível em versão beta para aqueles que entrarem na waitlist. Eles pedem algumas informações como redes sociais e intenções de uso. No meu caso, demorou uns 2/3 meses para liberação, quando recebi um e-mail com meu acesso:\nO modelo não está finalizado pois existem diversas mitigações de segurança que a equipe da OpenAI ainda vem trabalhando:\nPrevinir geração de imagens violentas, limitando a capacidade do DALL·E 2 ao remover conteúdo explicito dos dados de treinamento e minimizando a exposição do algoritmo à estes conceitos; Restringir conteúdos políticos evitando seu uso indevido (ex.: fake news); Implantação em fases, limitando o número de acessos para usuários confiáveis e a medida que ganharem confiança, liberam a versão beta para mais pessoas. 🚨 Atenção\nPara quem quiser ir brincando com esse tipo de rede neural enquanto não recebe o acesso, leia até o final pois apresentarei algumas alternativas!\nInstruções de Uso Ainda existe muita discussão sobre o assunto na comunidade e ainda não consolidou-se um “guia definitivo de como usar a ferramenta”, as dicas que darei aqui foram baseadas em experimentos que fiz e pesquisas na internet (referências no final do post). Tentarei fornecer uma boa quantidade de informações organizadas que sejam fáceis de entender, mas também útil para ajudá-lo a entender como a IA interpreta a frase que você escreve como input.\nParâmetros Os “parâmetros” que usamos para definir e descrever os detalhes/estilos/objetos/ambiente etc que estão na imagem são a chave. Essas são as instruções ou descrições que “dizem” ao algoritmo o que você deseja ver na imagem.\nÉ preciso escrever a frase de uma maneira que a IA entenda claramente. Você se familiarizará com a maneira de escrever parâmetros ao longo do tempo com a prática (caso tenha tempo, veja este vídeo de como ensinar linguagem de programação para uma criança, que da uma bela intuição de como devemos pensar).\nPara começar, precisamos decidir qual é a imagem. É uma pintura? uma fotografia? um desenho de uma linha? Primeiro decidimos o meio da imagem e depois o assunto da imagem. O que vai ter na pintura? Existe uma história a ser contada para descrever visualmente para a IA para que ela esteja na imagem? De que é a imagem?\nSe a imagem que você deseja produzir for replicar uma arte (um desenho, pintura, etc. de algo), então você deve pensar no estilo de arte de um artista que você gosta ou qual estilo de arte se adequaria ao tema ou sentimento da peça de arte você está tentando criar.\nExemplos A seguir veremos alguns exemplos de como fazer e como não fazer a “query para gerar as imagens.”\nPara criar uma pintura no estilo de alguém você escreveria algo assim nos parâmetros :“A digital art of a happy dog in a desert with pyramids in the background and planets in the sky” (Uma arte digital de um cachorro feliz em um deserto com pirâmides ao fundo e planetas no céu):\nNote que o modelo entende bem o que são os elementos e como eles se posicionam (à frente, atrás, acima, abaixo, direita, esquerda, etc). Além disso, como não especifiquei se era dia/noite nem se o fundo seria um universo, as cores ficaram confusas. Um azul escuro (quase preto) onde estão os planetas e um azul claro (como dia) para o fundo do deserto.\nImagem gerada por gomesfellipe utilizando DALL·E 2 Se a imagem não for de uma obra de arte/pintura, não iniciamos a frase com o meio (esboço/pintura/qualquer que seja), em vez disso, começamos a frase descrevendo imediatamente a cena da maneira mais gramaticalmente correta possível (que seja difícil de entender errado).\nVeja um exemplo que vi na internet, dizer algo como “Um homem e uma mulher de vestido vermelho ao lado de um cavalo” pode ser mal interpretado pela IA, pois o homem e a mulher podem estar no vestido vermelho ou com roupas vermelhas, além de faltar mais detalhes do que estamos imaginando. Veja como ficou o exemplo gerado:\nImagem gerada por gomesfellipe utilizando DALL·E 2 Até que o resultado não ficou tão ruim, com pelo menos uma imagem com o rapaz de camisa branca. Mas não era exatamente essa cena que tinha em mente, vamos tentar descrever melhor a cena que gostariamos de ver: “Um homem de terno preto e uma mulher de lindo vestido vermelho ao lado de seu majestoso cavalo marrom enquanto observam o pôr do sol”:\nImagem gerada por gomesfellipe utilizando DALL·E 2 Nós já estavamos vendo essa cena mentalmente, mas simplesmente não a havíamos descrito bem o suficiente. Então sempre pense nas descrições dessa maneira, tentando explicar uma fotografia para uma criança de dez anos de uma forma que provavelmente seria capaz de desenhá-la ou algo muito parecido sem ver a foto.\nAlém de descrever bem as fotos, existem alguns tipos de palavras-chave que podem ajudar a melhorar os detalhes, veja alguns bastante populares que criam resultados surpreendentes: “4k”, “Unreal engine”, “Ray tracing”, “Fotorrealismo”, “Hiper-realismo”.\n⭐️ Sucesso!\nAgora, juntando todas essas dicas, acho que você está pronto para tentar construir seus próprios “parâmetros”.\nDALL·E Mini e Stable Diffusion Ainda não tenho acesso ao DALL·E 2 e agora?\nBom, a OpenAI apresentou o primeiro (e impressionante) modelo para gerar imagens com DALL·E, certo? A partir daí a comunidade ficou enlouquecida e muitos cientistas de dados tentaram reproduzir os resultados inspirados no artigo oficial.\nA versão mais promissora que encontrei foi a DALL·E mini, desenvolvida por craiyon.com que é é um modelo de IA capaz de gerar figuras formidáveis a partir de qualquer input de texto. Além disso eles estão trabalhando na versão “DALL·E mega” que possui diversas melhorias nos otimizadores, na arquitetura em geral e treinada em datasets maiores (uma versão beta ja pode ser importada via Python).\nAlém desta, outro lançamento público anunciado recentemente (e muito promissor) foi o Stable Difusion, que após incansáveis revisões jurídicas, éticas e de tecnologia, lançaram o modelo e um aplicativo web pronto para uso, com licença permissiva para uso comercial e não comercial. Essa explosão de modelos open-source foi o que abriu caminho para eu aplicar LLMs como Gemma via LangChain em problemas práticos de NLP.\nÉ muito legal ver nestas ferramentas, o fruto de muitas horas de esforço coletivo para criar um único arquivo que comprime a “informação visual da humanidade” em alguns gigabytes!\nExemplos Veja algumas imagens geradas tentando descrever sentimentos:\n“Felicidade” “Amor” “Solidão” Imagens geradas por gomesfellipe utilizando DALL·E Mini\nA idéia de gerar estas imagens era tentar entender como uma IA “pensaria” sobre estes termos mas, para surpresa de ninguém, os resultados foram muito próximos de uma busca no Google (dado que o modelo foi treinado em conjuntos de dados públicos). É possível notar também alguns “bugs” como o último smile e um “coração duplo”.\nMesmo assim, achei interessante as paletas de cores apresentadas com cores mais “alegres” para felicidade (como verde, azul, branco e o amarelo dos “smiles”), um vermelho/rosa para amor e solidão em tons de cinza.\nEssa rede tem algumas limitações com rostos e acabam sendo meio distorcidas (segundo os desenvolvedores, é uma limitação atual do codificador de imagem mas eles já estão trabalhando nisso). Veja a seguir uma comparação do resultado da DALL·E 2 vs DALL mini para a frase “Uma sereia nadando em um mar de fogo”:\nImagens geradas por gomesfellipe utilizando DALL·E Mini\nA imagem gerada pela DALL·E mini tem uma resolução mais baixa e demorou um pouco mais para ser processada. Um ponto interessante é como mesmo esse modelo “menor” já é capaz de entender um “mar” e gerar o reflexo na água. Os “rostos” gerados pela DALL·E mini muitas vezes são comparados com “sonhos” e até mesmo meio assustadores enquanto que a DALL·E 2 conseguiu entregar uma imagem que, apesar de meio “caricata”, até que ficou bastante detalhada.\nOpções Alternativas Depois que o artigo com a ideia principal foi divulgado, a comunidade começou a desenvolver diversas redes que trabalhassem de forma semelhante. Nenhuma das redes conseguiu ser tão realistas quando a DALL·E mas fica aquela coisa meio psicodelica que se parece mesmo com um sonho.\nExistem diversas versões, como por exemplo:\nVQGAN+CLIP (focaremos nesta); CLIP-GLaSS; BigGAN + CLIP + CMA-ES; Disco Diffusion v4.1; Um app para Windows que usa a própria RAM do pc; Midjourney; Dentre outras… Todos os notebooks que estão na lista acima são hospedados no Google Collab e podem ser executados sem nenhum tipo de pré-configuração de ambiente. O modelo mais popular (e o que eu utilizei mais) acabou sendo a VQGAN+CLIP que foi inicialmente escrito em espanhol e depois em inglês.\nVQGAN+CLIP Apesar de muito democrática, o problema de hospedar esses notebooks no Google Collab é que se você estiver usando um usuário gratuito, descobrirá que a GPU e RAM são bem limitada. Algumas imagens precisavam de até 5h para serem geradas e mesmo assim o resultado não ficava bom (ri muito com alguns resultados 😂), enquanto que as imagens geradas com o uso da GPU rodavam em alguns minutos e dava para ver que a rede conseguia “ir mais longe”, alcançando imagens com resolução melhor.\nVeja a seguir uma imagem que criei a partir de uma foto da Amora (minha cachorrinha) como “chute inicial”:\n” A happy dog in the desert:200 | sunset in the background:100 | planets in the sky:100 | by Salvador Dali:100 | turtle:-100 | city:-100 | buildings:-200”\nImagem gerada por gomesfellipe utilizando VQGAN+CLIP Particularmente, gostei bastante do resultado final mas não foi tão fácil utilizando esta rede. Antes de submeter a imagem no notebook, precisei remover o fundo para remover qualquer tipo de ruído pois a rede não é capaz de distinguir o que é um cachorro, o que é meu braço ou o armário ao fundo e os resultados ficavam muito estranhas. Além disso fiz uma colagem (no Power Point mesmo) com alguns elementos que eu gostaria que estivessem na imagem data determinar suas posições.\n⚠️ Alerta!\nEu tinha muito claro em minha mente aonde gostaria que os elementos estivessem posicionados, porém, esta etapa de colagem dos elementos é completamente opcional! É uma forma de “guiar” a rede para resultados que estamos procurando, parando em determinada interação e ajustando a posição de elementos (muito útil para arrumar algumas estranhezas que aparecem em rostos) e inputando novamente como imagem inicial.\nAlém disso, você deve ter notado a presença de pipes “|” e uns valores (como dicionários do Python). A idéia é que as palavras-chave que você colocar entre cada um desses pipes influenciará bastante na imagem final e até mesmo remover coisas que não desejamos.\nA primeira sentença é definida automaticamente como 100 “unidades”. Logo em seguida, as próximas sentenças receberão apenas 1 “unidade”. O ideal é colocar o “valor” associado aquela “chave” que representa o quão “proeminente” será aquele elemento na imagem.\nNote ainda que eu tentei evitar que o modelo incluí-se novos elementos como uma cidade que estava se formando ao fundo ou uma tartaruga no canto esquerdo informando valores negativos para estes elementos que nãa gostaria que aparecessem.\nEstes notebooks não salvam seus resultados, quando você atualizar a página, outra seção será iniciada e todo o trabalho será perdido! Então quando gostar de alguma imagem, não esqueça de salvá-la!\n💡 Dica\nNem sempre a última imagem gerada no processo é a que nós mais gostamos, então vale a pena conferir como foi o processo de aprendizagem em “épocas” anteriores.\nMais Parâmetros Praticamente todos esses notebooks possuem os mesmos parâmetros então passarei por alguns que considero interessantes para se ter uma noção geral de como funciona:\nmodel: há várias opções de modelos treinados em conjuntos de dados específicos para diferentes tarefas, como por exemplo:\nImagens com diferentes texturas: imagenet_1024, imagenet_16384, sflckr, coco; Imagens com estilos de arte: wikiart_1024, wikiart_16384; Rostos com diferentes traços: faceshq, ffhq, celebahq; inicial_image: podemos ter uma idéia de elementos que gostaríamos que estivesse na imagem e então criar uma imagem para usar como “chute inicial” para direcionar o trabalho da rede;\nseed: é bom colocar um número aleatório (maior que zero) para garantir que o desenvolvimento da imagem seja reprodutível;\nmax_interactions: é o número de vezes que o modelo vai “trabalhar” na imagem. Pode ser limitado, a menos que você pague pelo Google Collab Pro (aí da para colocar um valor bem alto e avaliar um bom ponto de parada após alguns experimentos).\nheight e width: a altura e a largura são colocadas automaticamente em 600 e 600. Pode ser que demore um pouco então para quem estiver usando a versão free pode ser útil abaixar para cerca de 200 de largura e altura para aliviar no processamento da imagem e permitir mais iterações.\nMais Exemplos Veja um exemplo de arte gerada a partir de um quadro, onde a tecnologia atua como um colaborador criativo em vez de uma ferramenta básica:\nEsta pintura é intitulada como “Desolate Civilisation” e é composta por 9 pinturas futuristas criadas e montadas utilizando VQGAN+CLIP para se assemelhar à Mona Lisa (via NightCafe Studio).\nInteressante como o autor divide a tarefa em 9 “minitarefas”, facilitando assim a produção da imagem toda (além de dar um toque artístico bem interessante).\nDesolate Civilisation - NightCafe Studio Discussão Filosófica Estas novas abordagens estão mudando definitivamente a natureza dos processos criativos. Além de nós, meros mortais não-desenhistas, os artistas também podem se beneficiar destas tecnologias como fonte de inspiração, seja gerando imagens aleatórias sobre coisas que vêm em mente ou ainda “tunar” suas obras, mesclando com diferentes elementos ou tipos de estilos.\nApesar de interessante, para pessoas questionadoras, pode surgir alguma questão filosófica como: será que isto é arte? Existem muitas definições de arte e seu significado varia conforme a época ou cultura.\nLi diferentes definições e refleti bastante sobre o assunto, e a definição que mais me agradou foi a de Immanuel Kant (um dos meus filósofos favoritos), que sugere que: “a arte diferencia-se da natureza por ser uma atividade racional e livre. Assim, uma teia de aranha, embora possa parecer bela, não é uma obra de arte, já que se trata de uma tarefa mecânica e natural. A arte também se diferencia da ciência, já que para se produzir uma obra de arte não basta ter conhecimento sobre um determinado assunto - é preciso ter habilidade para fazer. Kant define a arte estética como aquela cuja finalidade imediata é o sentimento do prazer, não apenas o prazer ligado às sensações, mas também o prazer da reflexão.”\nImagem gerada por gomesfellipe utilizando DALL·E 2 Imagino que, pelo menos hoje em dia e por um bom tempo, a IA por si só não conseguirá produzir arte, pois até então todos esses modelos estão “aprendendo” com os inputs que fornecemos e produzindo outputs que pedimos. Isso é uma limitação de uma “inteligência artificial fraca” não sendo capaz de executar a atividade artística “livremente”, além de que sua finalidade imediata não tem haver com prazer de reflexão nenhuma.\nEnquanto continuamos a filosofar e especular sobre a definição de arte, podemos usar estes modelos para ajudar na criação de valor com as “artes” mais necessárias no mundo capitalista que vivemos. Veja como fica “Uma foto em 4k de um carro futurista em um salão todo branco e vazio”:\nImagem gerada por gomesfellipe utilizando DALL·E 2 Essas imagens mostram como podemos usar estes modelos para produzir protótipos de bens de consumo, páginas iniciais de sites ou até pôsteres de filmes (imagina “Futuristic Fast and Furious” 😅 😂).\nConclusão Todos esses experimentos me fizeram entender melhor o que é possível e o que não é possível de fazer, mas me deixaram com muitas dúvidas de questões filosóficas sobre o que é a arte em si no sentido mais amplo 🤯.\nNo futuro, gostaria de explorar novas formas de me divertir, criar arte e encontrar caminhos para usar essa nova tecnologia para facilitar o trabalho das pessoas e, quem sabe, até monetizar!\nSe você é novo em inteligência artificial, vale a pena conferir também esta visão geral de ciência de dados para quem quer começar, e mais adiante explorei outro tipo de rede neural aplicada a texto em análise de sentimentos com um \"ChatGPT\" de código aberto. Continuando com IA generativa aplicada a imagens, escrevi também sobre extração de dados de imagens com visão computacional e, no limite oposto do espectro, sobre orquestrar uma equipe de agentes de IA para análise do Bitcoin.\nEspero que tenham gostado, qualquer crítica ou sugestão será muito bem vinda!\nAbraços!\nFellipe Gomes\nReferências https://www.reddit.com/r/bigsleep/comments/p15fis/tutorial_an_introduction_for_newbies_to_using_the/ https://openai.com/dall-e-2/ https://github.com/openai/DALL-E/blob/master/notebooks/usage.ipynb https://colab.research.google.com/drive/1go6YwMFe5MX6XM9tv-cnQiSTU50N9EeT#scrollTo=ZdlpRFL8UAlW https://www.artstation.com/blogs/stijn/B276/ai-sketches-with-vqgan-and-clip-for-concept-art https://arxiv.org/abs/2204.06125 https://arxiv.org/abs/2203.13131 https://www.artstation.com/blogs/stijn/B276/ai-sketches-with-vqgan-and-clip-for-concept-art https://huggingface.co/spaces/dalle-mini/dalle-mini https://github.com/borisdayma/dalle-mini https://wandb.ai/dalle-mini/dalle-mini/reports/DALL-E-mini-Generate-images-from-any-text-prompt--VmlldzoyMDE4NDAy https://stability.ai/blog/stable-diffusion-announcement https://siliconangle.com/2022/07/14/metas-latest-generative-ai-system-creates-stunning-images-sketches-text/ https://creator.nightcafe.studio/create https://michaelis.uol.com.br/moderno-portugues/busca/portugues-brasileiro/arte https://www.significados.com.br/arte/ Perguntas frequentes É preciso saber programar para gerar arte com IA?\nNão. O post mostra que não há necessidade de escrever nenhuma linha de código para usar o DALL·E 2 ou as outras arquiteturas apresentadas, no máximo ajustando alguns hiperparâmetros.\nQuais ferramentas de IA para gerar imagens são apresentadas no post?\nSão apresentados o DALL·E 2 da OpenAI, o DALL·E Mini (craiyon.com), o Stable Diffusion e alternativas como VQGAN+CLIP, CLIP-GLaSS e Midjourney.\nO que são os \"parâmetros\" usados para gerar imagens com IA?\nSão as instruções ou descrições textuais que dizem ao algoritmo o que deve aparecer na imagem, incluindo estilo, elementos, ambiente e posicionamento.\n","date":"8 de agosto de 2022","externalUrl":null,"permalink":"/post/2022-08-08-dataart-primeiros-passos/","section":"Posts","summary":" Introdução DALL·E 2 Instruções de Uso Parâmetros Exemplos DALL·E Mini e Stable Diffusion Exemplos Opções Alternativas VQGAN+CLIP Mais Parâmetros Mais Exemplos Discussão Filosófica Conclusão Referências Introdução Você já deve ter ouvido falar sobre uma inteligência artificial que gera artes super-realistas a partir de textos e imagens. Hoje em dia já existem algumas opções como DALL·E 2 (da OpenAI/Google) e a Make-A-Scene (da Meta), e essas ferramentas são capazes de gerar versões e estilos diferentes de uma dada imagem ou ainda criar uma imagem com apenas uma breve descrição do resultado desejado. As imagens podem ser tão aleatórias quanto um “gato de óculos e uma coroa” (em homenagem ao dia dos gatos):\n","title":"Gerando arte com Inteligência Artificial","type":"post"},{"content":"","date":"8 de agosto de 2022","externalUrl":null,"permalink":"/tags/vqgan-clip/","section":"Tags","summary":"","title":"Vqgan-Clip","type":"tags"},{"content":"","date":"19 de abril de 2022","externalUrl":null,"permalink":"/tags/regressao/","section":"Tags","summary":"","title":"Regressao","type":"tags"},{"content":" Introdução Definição do problema de negócio Análise Exploratória (em R) Estrutura da base Ano da base de dados Target Machine Learning (em Python) Importar dependencias Carregar dados Modelagem Submissão Considerações Finais Introdução No final de Janeiro desde ano (2022) o TFUG - TensorFlow Users Group de São Paulo lançou uma competição no Kaggle para prever as notas do enem que tem relação com um dos 17 tópicos de Desenvolvimento Sustentável das Nações Unidas - Educação de Qualidade.\nAlém de divertido, o desafio foi repleto de possibilidades e bastante desafiador! Todos os competidores que trabalharam duro em pleno mês de carnaval estão de parabéns! 😅 😂\nEste resultado veio logo depois de outra competição em que cheguei ao 3º lugar no Porto Seguro Data Challenge, e mais tarde consegui repetir o desempenho conquistando o 1º lugar em outra edição da ML Olympiad.\nAqui estão alguns dos prêmios recebidos:\nComo nesta competição havia bastante trabalho a ser feito e tivemos apenas 1 mês para trabalhar na solução, foi preciso fazer uma boa gestão do código e do tempo de desenvolvimento.\nNas seções abaixo apresento o racional por trás da minha solução bem como os 5 melhores modelos individuais (para cada nota) que utilizei em um ensemble para chegar ao segundo lugar.\nTL;DR\nSolução que alcançou o 2º lugar na ML Olympiad de qualidade da educação, prevendo 5 notas do ENEM (Ciências da Natureza, Ciências Humanas, Linguagens e Códigos, Matemática e Redação). Modelagem feita em Python com CatBoost e LightGBM, com feature engineering intensivo e dados externos como o Atlas do Desenvolvimento Humano e o Censo Escolar. A validação usou a métrica MCRMSE e o pós-processamento atribuiu nota zero aos alunos ausentes na prova, etapa decisiva para o resultado final. Definição do problema de negócio O objetivo desta competição consistiu em prever as notas dos alunos(as) nas provas: Ciências da Natureza, Ciências Humanas, Linguagens e Códigos, Matemática e Redação.\nApesar das notas serem calculadas de maneira independente, a partir de modelos de TRI (Teoria de Resposta ao Item) que levam em consideração a performance em um caderno específico e na dificuldade de cada questão, o mesmo aluno realiza todas as provas em um curto período de tempo.\nPortanto, esta tarefa pode ser enquadrada como um problema supervisionado de regressão com múltiplos outputs na qual as previsões são, de certa forma, dependentes da entrada umas das outras.\nA validação da solução foi feita utilizando a métrica Mean Columnwise Root Mean Squared Error – MCRMSE, que é basicamente a média do RMSE calculado sobre as previsões de cada nota.\nAnálise Exploratória (em R) Convido o leitor a conferir o notebook publicado no Kaggle com a análise exploratória completa. Aqui irei trazer apenas alguns dos principais insights que encontrei durante a etapa de análise exploratória.\nEstrutura da base Veja a seguir qual a estrutura geral da base de dados:\nÉ notório que existem dados faltantes e que parece haver algum padrão. Vejamos com mais detalhse:\n💡 Insights!\nExistem dados missing nas 5 targets que queremos prever e note que existe uma relação tanto entre as provas de Matemática e Ciências da Natuerza quanto nas de Ciências Humanas, Linguagens e Códigos e Redação, o que parece ocorrer devido a ausência do aluno incrito em comparecer a realização da prova no respectivo dia.\nAno da base de dados Essa informação não estava explicitamente disponível, mas após analisar a idade dos participantes em relação ao ano em que concluíram o ensino médio, foi possível identificar que tratavam-se dos dados de 2019, veja:\nEssa informação poderia ser útil na hora de buscar dados externos (permitido nesta competição).\n💡 Insights!\n→ Atenção aos outliers: É no mínimo estranho uma pessoa que formou em 2007 ter 17 anos;\n→ Como ninguém concluiu a escola no ano de 2019 e a média das idades vai diminuindo quanto mais próximo de 2018, parece que estes dados são de 2019. Essa informção poderia ser útil na hora de procurar por bases externas.\nTarget A primeira decisão importante era definir como enquadrar o problema; se seriam múltiplos modelos independentes ou modelos com saídas dependentes.\nPrimeiramente vejamos como eram as distribuições das notas por caderno:\nAo olhar estas distribuições foram surgindo várias idéias! Cheguei até a tentar modelos estatísticos GAM considerando a resposta como uma distribuição Beta (transformando as targets no intervalo [0,1]) mas acabou não apresentando bons resultados para a competição.. acho que seria necessário um pouco mais de preparação nos dados.\nApesar das notas do enem serem calculadas via TRI (Teoria de Resposta ao Item) que considera as notas independentes, parece existir alguma correlação entre as notas, veja:\nAs targets da nota de Línguas e Códigos e Ciências Humanas pareciam possuir uma correlação “interessante”, mas, após testar modelos de múltiplas respostas dependentes para cada dia (com e sem a nota da redação), em nenhum de meus testes superou (de maneira consistente) o desempenho de modelos que considerassem as saídas independentes. Portanto foquei em criar 5 modelos independentes.\nMachine Learning (em Python) Toda a rotina de pré-processamento dos dados, feature engineering, modelagem, ensamble e pós-processamento foi realizada utilizando a linguagem Python para cada uma das 5 notas. Trouxe apenas o modelo final neste post mas, para chegar até aqui foram necessário muitos testes!\nBoa parte do repertório de feature engineering que uso em competições vem do Feature Engineering and Selection, do Max Kuhn. Vale muito a leitura pra quem quer subir de posição no leaderboard.\nImportar dependencias Carregar pacotes Python:\n# data prep import numpy as np import pandas as pd # pre process from sklearn.preprocessing import MinMaxScaler # modeling from sklearn.model_selection import train_test_split from catboost import CatBoostRegressor # plots import seaborn as sns import matplotlib.pyplot as plt Confira a baixo as funções desenvolvidas para a solução deste problema\n(Clique aqui para expandir as funções) def prep_data_questionarios(df): \u0026#39;\u0026#39;\u0026#39; Converte dados de questionario para ordinal \u0026#39;\u0026#39;\u0026#39; # escolaridade pai to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: 5, \u0026#39;G\u0026#39;: 6, \u0026#39;H\u0026#39;: -1} df.loc[:, \u0026#39;Q001\u0026#39;] = df.loc[:, \u0026#39;Q001\u0026#39;].map(to_map).astype(int) # escolaridade mae to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: 5, \u0026#39;G\u0026#39;: 6, \u0026#39;H\u0026#39;: -1} df.loc[:, \u0026#39;Q002\u0026#39;] = df.loc[:, \u0026#39;Q002\u0026#39;].map(to_map).astype(int) # ocupacao pai to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: -1} df.loc[:, \u0026#39;Q003\u0026#39;] = df.loc[:, \u0026#39;Q003\u0026#39;].map(to_map).astype(int) # ocupacao mae to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: -1} df.loc[:, \u0026#39;Q004\u0026#39;] = df.loc[:, \u0026#39;Q004\u0026#39;].map(to_map).astype(int) # renda da familia to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;:5, \u0026#39;G\u0026#39;:6, \u0026#39;H\u0026#39;:7, \u0026#39;I\u0026#39;:8, \u0026#39;J\u0026#39;:9, \u0026#39;K\u0026#39;:10,\u0026#39;L\u0026#39;:11, \u0026#39;M\u0026#39;:12, \u0026#39;N\u0026#39;:13, \u0026#39;O\u0026#39;:14, \u0026#39;P\u0026#39;:15, \u0026#39;Q\u0026#39;:16} df.loc[:, \u0026#39;Q006\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map(to_map).astype(int) # empregado domestico to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3} df.loc[:, \u0026#39;Q007\u0026#39;] = df.loc[:, \u0026#39;Q007\u0026#39;].map(to_map).astype(int) # banheiro to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q008\u0026#39;] = df.loc[:, \u0026#39;Q008\u0026#39;].map(to_map).astype(int) # qnt de quartos to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q009\u0026#39;] = df.loc[:, \u0026#39;Q009\u0026#39;].map(to_map).astype(int) # qnt de carros to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q010\u0026#39;] = df.loc[:, \u0026#39;Q010\u0026#39;].map(to_map).astype(int) # qnt de motocicleta to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q011\u0026#39;] = df.loc[:, \u0026#39;Q011\u0026#39;].map(to_map).astype(int) # qnt de geladeira to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q012\u0026#39;] = df.loc[:, \u0026#39;Q012\u0026#39;].map(to_map).astype(int) # qnt de freezer to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q013\u0026#39;] = df.loc[:, \u0026#39;Q013\u0026#39;].map(to_map).astype(int) # qnt de maquina de lavar roupa to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q014\u0026#39;] = df.loc[:, \u0026#39;Q014\u0026#39;].map(to_map).astype(int) # qnt de maquina de secar roupa to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q015\u0026#39;] = df.loc[:, \u0026#39;Q015\u0026#39;].map(to_map).astype(int) # qnt de microondas to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q016\u0026#39;] = df.loc[:, \u0026#39;Q016\u0026#39;].map(to_map).astype(int) # qnt de maquina de lavar louca to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q017\u0026#39;] = df.loc[:, \u0026#39;Q017\u0026#39;].map(to_map).astype(int) # tem aspirador de po to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1} df.loc[:, \u0026#39;Q018\u0026#39;] = df.loc[:, \u0026#39;Q018\u0026#39;].map(to_map).astype(int) # qtd tv colorida to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q019\u0026#39;] = df.loc[:, \u0026#39;Q019\u0026#39;].map(to_map).astype(int) # tem dvd to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1} df.loc[:, \u0026#39;Q020\u0026#39;] = df.loc[:, \u0026#39;Q020\u0026#39;].map(to_map).astype(int) # tem tv por assinatura to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1} df.loc[:, \u0026#39;Q021\u0026#39;] = df.loc[:, \u0026#39;Q021\u0026#39;].map(to_map).astype(int) # qtd telefone celular to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q022\u0026#39;] = df.loc[:, \u0026#39;Q022\u0026#39;].map(to_map).astype(int) # qtd telefone fixo to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1} df.loc[:, \u0026#39;Q023\u0026#39;] = df.loc[:, \u0026#39;Q023\u0026#39;].map(to_map).astype(int) # qtd computador to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4} df.loc[:, \u0026#39;Q024\u0026#39;] = df.loc[:, \u0026#39;Q024\u0026#39;].map(to_map).astype(int) # tem acesso a internet to_map = {\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1} df.loc[:, \u0026#39;Q025\u0026#39;] = df.loc[:, \u0026#39;Q025\u0026#39;].map(to_map).astype(int) return(df) def fe_questionario(df): \u0026#39;\u0026#39;\u0026#39; Gerar novas features artificiais baseadas nos dados de questionario \u0026#39;\u0026#39;\u0026#39; df.loc[:, \u0026quot;Q021+Q006\u0026quot;] = df[\u0026quot;Q021\u0026quot;] + df[\u0026quot;Q006\u0026quot;] df.loc[:, \u0026quot;Q018+Q006\u0026quot;] = df[\u0026quot;Q018\u0026quot;] + df[\u0026quot;Q006\u0026quot;] df.loc[:, \u0026quot;Q018+Q008\u0026quot;] = df[\u0026quot;Q018\u0026quot;] + df[\u0026quot;Q008\u0026quot;] df.loc[:, \u0026quot;Q010+Q018\u0026quot;] = df[\u0026quot;Q010\u0026quot;] + df[\u0026quot;Q018\u0026quot;] df.loc[:, \u0026quot;Q018+Q024\u0026quot;] = df[\u0026quot;Q018\u0026quot;] + df[\u0026quot;Q024\u0026quot;] df.loc[:, \u0026quot;Q018*Q006\u0026quot;] = df[\u0026quot;Q018\u0026quot;] * df[\u0026quot;Q006\u0026quot;] df.loc[:, \u0026quot;Q010*Q018\u0026quot;] = df[\u0026quot;Q010\u0026quot;] * df[\u0026quot;Q018\u0026quot;] return df def fe_mun(data): \u0026#39;\u0026#39;\u0026#39; Gerar novas features a partir das localizacoes de municipio \u0026#39;\u0026#39;\u0026#39; for c in list(data.columns[data.dtypes==\u0026#39;category\u0026#39;]): data.loc[:, c] = data.loc[:, c].astype(\u0026#39;object\u0026#39;) data.loc[:, \u0026#39;FE_MUNICIPIO_PROVA_x_MUNICIPIO_RESIDENCIA\u0026#39;] = np.where(data.NO_MUNICIPIO_PROVA == data.NO_MUNICIPIO_RESIDENCIA , 1, 0) data.loc[:, \u0026#39;FE_MUNICIPIO_PROVA_x_MUNICIPIO_NASCIMENTO\u0026#39;] = np.where(data.NO_MUNICIPIO_PROVA == data.NO_MUNICIPIO_NASCIMENTO , 1, 0) data.loc[:, \u0026#39;FE_MUNICIPIO_PROVA_x_MUNICIPIO_ESC\u0026#39;] = np.where(data.NO_MUNICIPIO_PROVA == data.NO_MUNICIPIO_ESC , 1, 0) data.loc[:, \u0026#39;FE_MUNICIPIO_RESIDENCIA_x_MUNICIPIO_NASCIMENTO\u0026#39;] = np.where(data.NO_MUNICIPIO_RESIDENCIA == data.NO_MUNICIPIO_NASCIMENTO , 1, 0) data.loc[:, \u0026#39;FE_MUNICIPIO_RESIDENCIA_x_MUNICIPIO_ESC\u0026#39;] = np.where(data.NO_MUNICIPIO_RESIDENCIA == data.NO_MUNICIPIO_ESC , 1, 0) data.loc[:, \u0026#39;FE_MUNICIPIO_NASCIMENTO_x_MUNICIPIO_ESC\u0026#39;] = np.where(data.NO_MUNICIPIO_RESIDENCIA == data.NO_MUNICIPIO_ESC , 1, 0) for c in list(data.columns[data.dtypes==\u0026#39;object\u0026#39;]): data.loc[:, c] = data.loc[:, c].astype(\u0026#39;category\u0026#39;) return data def fe_in(df): \u0026#39;\u0026#39;\u0026#39; Gerar features a partir das indicadoras \u0026#39;\u0026#39;\u0026#39; df.loc[:, \u0026#39;IN_DEFICIT_ATENCAO+IN_TEMPO_ADICIONAL\u0026#39;] = df[\u0026quot;IN_DEFICIT_ATENCAO\u0026quot;] + df[\u0026quot;IN_TEMPO_ADICIONAL\u0026quot;] df.loc[:, \u0026#39;IN_LEDOR+IN_TRANSCRICAO\u0026#39;] = df[\u0026quot;IN_LEDOR\u0026quot;] + df[\u0026quot;IN_TRANSCRICAO\u0026quot;] return df def prep_co_escola(df): \u0026#39;\u0026#39;\u0026#39; Converter codigo da escola para categorico \u0026#39;\u0026#39;\u0026#39; df.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = [str(x) for x in df.CO_ESCOLA] df.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = np.where(df[\u0026#39;CO_ESCOLA\u0026#39;]==\u0026#39;nan\u0026#39;, np.nan, df[\u0026#39;CO_ESCOLA\u0026#39;]) df.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = df.loc[:, \u0026#39;CO_ESCOLA\u0026#39;].astype(\u0026#39;category\u0026#39;) return df def fe_extra(df): \u0026#39;\u0026#39;\u0026#39; Gerar novas features \u0026#39;\u0026#39;\u0026#39; df.loc[:, \u0026quot;FE_IDADE_DISCRETA\u0026quot;] = pd.cut(df.NU_IDADE, (0, 15, 18, 23, 36, 60, 120), labels=[\u0026#39;ADOLESCENTE\u0026#39;,\u0026#39;ADOLESCENTE_2\u0026#39;, \u0026#39;JOVEM\u0026#39;,\u0026#39;JOVEM_2\u0026#39;, \u0026#39;ADULTO\u0026#39;, \u0026#39;IDOSO\u0026#39;]).astype(\u0026#39;category\u0026#39;) df.loc[:, \u0026#39;FE_OCUPACAO_PAIS\u0026#39;] = df.Q003 + df.Q004 df.loc[:, \u0026#39;FE_ESCOLARIDADE_PAIS\u0026#39;] = df.Q001 + df.Q002 df.loc[:, \u0026#39;FE_RENDA_POR_PESSOA\u0026#39;] = df.Q006 / df.Q005 df.loc[:, \u0026#39;FE_CELULAR_POR_PESSOA\u0026#39;] = df.Q022 / df.Q005 df.loc[:, \u0026#39;FE_COMPUTADOR_POR_PESSOA\u0026#39;] = df.Q024 / df.Q005 df.loc[:, \u0026#39;FE_VISAO_RUIM\u0026#39;] = df[[\u0026#39;IN_BAIXA_VISAO\u0026#39;, \u0026#39;IN_CEGUEIRA\u0026#39;, \u0026#39;IN_VISAO_MONOCULAR\u0026#39;, \u0026#39;IN_SURDO_CEGUEIRA\u0026#39;]].max(axis=1) df.loc[:, \u0026#39;FE_AUDICAO_RUIM\u0026#39;] = df[[\u0026#39;IN_SURDEZ\u0026#39;, \u0026#39;IN_DEFICIENCIA_AUDITIVA\u0026#39;, \u0026#39;IN_SURDO_CEGUEIRA\u0026#39;]].max(axis=1) df.loc[:, \u0026#39;FE_TDAH_MAIS_TEMPO\u0026#39;] = df.IN_TEMPO_ADICIONAL + df.IN_DEFICIT_ATENCAO df.loc[:, \u0026#39;FE_TDAH_MEDICADO\u0026#39;] = np.where((df.IN_DEFICIT_ATENCAO==1)\u0026amp;(df.IN_MEDICAMENTOS==1), 1, 0) df.loc[:, \u0026#39;FE_RECURSO_VISAO\u0026#39;] = df[[\u0026#39;IN_BRAILLE\u0026#39;, \u0026#39;IN_AMPLIADA_24\u0026#39;, \u0026#39;IN_AMPLIADA_18\u0026#39;, \u0026#39;IN_LEDOR\u0026#39;, \u0026#39;IN_MAQUINA_BRAILE\u0026#39;, \u0026#39;IN_LAMINA_OVERLAY\u0026#39;]].max(axis=1) df.loc[:, \u0026#39;FE_RECURSO_SURDEZ\u0026#39;] = df[[\u0026#39;IN_LIBRAS\u0026#39;, \u0026#39;IN_LEITURA_LABIAL\u0026#39;, \u0026#39;IN_TRANSCRICAO\u0026#39;]].max(axis=1) acess = [\u0026#39;IN_ACESSO\u0026#39;, \u0026#39;IN_MESA_CADEIRA_RODAS\u0026#39;, \u0026#39;IN_MESA_CADEIRA_SEPARADA\u0026#39;, \u0026#39;IN_APOIO_PERNA\u0026#39;, \u0026#39;IN_CADEIRA_ESPECIAL\u0026#39;, \u0026#39;IN_CADEIRA_CANHOTO\u0026#39;, \u0026#39;IN_CADEIRA_ACOLCHOADA\u0026#39;, \u0026#39;IN_MOBILIARIO_OBESO\u0026#39;, \u0026#39;IN_SALA_INDIVIDUAL\u0026#39;, \u0026#39;IN_SALA_ESPECIAL\u0026#39;, \u0026#39;IN_SALA_ACOMPANHANTE\u0026#39;, \u0026#39;IN_MOBILIARIO_ESPECIFICO\u0026#39;, \u0026#39;IN_MATERIAL_ESPECIFICO\u0026#39;] df.loc[:, \u0026#39;FE_ACESSIBILIDADE\u0026#39;] = df[acess].max(axis=1) return df Carregar features artificiais extraídas através de um modelo KNN. Não apresentarei o código aqui (talvez fique para um próximo post) mas a idéia é basicamente a seguinte:\n🧪 Feature Extraction com KNN\nAjuste um KNeighborsRegressor encontrando os K-vizinhos mais próximos de cada instância out-of-fold via validação cruzada (para evitar data leak) nos dados de treino e depois ajuste um modelo em todos os dados de treino para obter os K-vizinhos mais próximos nos dados de teste.\nQuem sabe no futuro faço um post compartilhando esta estratégia com mais detalhes.\nknn_train = pd.read_csv(\u0026quot;../input/knn/KNN_feat_train_CH_LC.csv\u0026quot;) knn_test = pd.read_csv(\u0026quot;../input/knn/KNN_feat_test_CH_LC.csv\u0026quot;) knn_train_cn_mt = pd.read_csv(\u0026quot;../input/knn/KNN_feat_train_CN_MT.csv\u0026quot;) knn_test_cn_mt = pd.read_csv(\u0026quot;../input/knn/KNN_feat_test_CN_MT.csv\u0026quot;) knn_train_rd = pd.read_csv(\u0026quot;../input/knn/KNN_feat_train_RD.csv\u0026quot;) knn_test_rd = pd.read_csv(\u0026quot;../input/knn/KNN_feat_test_RD.csv\u0026quot;) Carregar dados Importar uma versão do dataset no formato .parquet que foi compactada com um truque para otimizar o consumo de memória disponibilizada pelos organizadores neste notebook.\ntrain = pd.read_parquet(\u0026#39;train.parquet\u0026#39;) test = pd.read_parquet(\u0026#39;test.parquet\u0026#39;) sub = pd.read_csv(\u0026#39;../input/qualityeducation/sample_submission.csv\u0026#39;) Definir objetos com targets\ntargets = [\u0026#39;NU_NOTA_LC\u0026#39;, \u0026#39;NU_NOTA_CH\u0026#39;, \u0026#39;NU_NOTA_CN\u0026#39;, \u0026#39;NU_NOTA_MT\u0026#39;, \u0026#39;NU_NOTA_REDACAO\u0026#39;] presencas = [\u0026#39;TP_PRESENCA_LC\u0026#39;, \u0026#39;TP_PRESENCA_CH\u0026#39;, \u0026#39;TP_PRESENCA_CN\u0026#39;, \u0026#39;TP_PRESENCA_MT\u0026#39;, \u0026#39;TP_STATUS_REDACAO\u0026#39;] ⚠️ Atenção:\nA feature de presença é muito importante no pós-processamento para atribuir nota zero aos alunos que não foram realizar a prova mas não faz sentido mantê-la nos dados de treino pois será sempre constante.\nDados externos Dados Externos utilizados:\nAtlas do Desenvolvimento Humano (ADH) Esta base tinha muita informação legal mas sua cobertura temporal estava bastante defasada (1991 - 2010) o que pode adicionar algum ruído ao modelo.\nAs features selecionadas (sem muito critério) desta base foram:\nextra1 = pd.read_csv(\u0026quot;municipio.csv\u0026quot;) extra1 = extra1[extra1.ano==2010] features_extra1 = [\u0026#39;expectativa_vida\u0026#39;, \u0026#39;razao_dependencia\u0026#39;, \u0026#39;expectativa_anos_estudo\u0026#39;, \u0026#39;taxa_analfabetismo_11_a_14\u0026#39;, \u0026#39;taxa_analfabetismo_15_a_17\u0026#39;, \u0026#39;taxa_analfabetismo_18_mais\u0026#39;, \u0026#39;taxa_atraso_0_basico\u0026#39;, \u0026#39;taxa_atraso_0_fundamental\u0026#39;, \u0026#39;taxa_atraso_0_medio\u0026#39;, \u0026#39;taxa_freq_bruta_medio\u0026#39;, \u0026#39;taxa_freq_liquida_medio\u0026#39;, \u0026#39;taxa_freq_medio_18_24\u0026#39;, \u0026#39;taxa_freq_medio_6_14\u0026#39;, \u0026#39;indice_gini\u0026#39;,\u0026#39;prop_pobreza_extrema\u0026#39;, \u0026#39;prop_pobreza\u0026#39;, \u0026#39;prop_renda_10_ricos\u0026#39;, \u0026#39;prop_renda_20_pobres\u0026#39;, \u0026#39;razao_10_ricos_40_pobres\u0026#39;,\u0026#39;renda_pc\u0026#39; , \u0026#39;renda_pc_quintil_1\u0026#39;, \u0026#39;indice_theil\u0026#39;, \u0026#39;prop_trabalhadores_conta_proria\u0026#39;, \u0026#39;prop_empregadores\u0026#39;, \u0026#39;prop_ocupados_agropecuaria\u0026#39;, \u0026#39;prop_ocupados_comercio\u0026#39;, \u0026#39;prop_ocupados_construcao\u0026#39;, \u0026#39;prop_ocupados_formalizacao\u0026#39;, \u0026#39;prop_ocupados_medio\u0026#39;, \u0026#39;prop_ocupados_servicos\u0026#39;, \u0026#39;prop_ocupados_superior\u0026#39;, \u0026#39;prop_ocupados_renda_0\u0026#39;, \u0026#39;renda_media_ocupados\u0026#39;, \u0026#39;indice_treil_trabalho\u0026#39;, \u0026#39;taxa_ocupados_carteira\u0026#39;, \u0026#39;taxa_agua_encanada\u0026#39;, \u0026#39;taxa_banheiro_agua_encanada\u0026#39;, \u0026#39;taxa_coleta_lixo\u0026#39;, \u0026#39;taxa_energia_eletrica\u0026#39;, \u0026#39;taxa_agua_esgoto_inadequados\u0026#39;, \u0026#39;taxa_criancas_dom_sem_fund\u0026#39;, \u0026#39;pea\u0026#39;, \u0026#39;indice_escolaridade\u0026#39;, \u0026#39;indice_frequencia_escolar\u0026#39;, \u0026#39;idhm\u0026#39;, \u0026#39;idhm_e\u0026#39;, \u0026#39;idhm_l\u0026#39;, \u0026#39;idhm_r\u0026#39;] extra1 = extra1[[\u0026#39;id_municipio\u0026#39;]+features_extra1] train = pd.merge(train, extra1, how=\u0026#39;left\u0026#39;, left_on=\u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, right_on=\u0026#39;id_municipio\u0026#39;) test = pd.merge(test, extra1, how=\u0026#39;left\u0026#39;, left_on=\u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, right_on=\u0026#39;id_municipio\u0026#39;) Microdados do Censo Escolar da Educacação Básica Base disponível no mesmo site dos dados da competição e que trás informações muito ricas das escolas do Brasil. Infelizmente quase 75% da informação da escola do aluno era missing então esta base não conseguiu alavancar os ganhos do modelo de maneira considerável.\nNesta base foquei principalmente nas features utilizadas para calcular o IIE (Índice de Estrutura da Escola) que se baseia nos seguintes componentes:\nComponente 1: Pedagógica (IEE_Pedagógico): Componente 2: Básica (IEE_Básico): Componente 3: Tecnológica (IEE_Tecnológico): Qualificação do docente (formação acadêmica dos professores) Água filtrada (binária) Número de computadores por aluno (computadores disponíveis para uso dos alunos) Número de alunos por sala Acesso à rede pública de energia (binária) Número de equipamentos multimídia por aluno Número de funcionários por aluno Acesso à rede pública de esgoto (binária) Acesso a internet (binária) Quadra de esportes coberta (binária) Coleta periódica de lixo (binária) Laboratório de Ciências (binária) Biblioteca (binária) Banheiro dentro do prédio (binária) Laboratório de Informática (binária) Fonte # Importar dados extra2 = pd.read_csv(\u0026#39;microdados_ed_basica_2021.csv\u0026#39;, error_bad_lines=False, sep=\u0026#39;;\u0026#39;, encoding=\u0026#39;latin1\u0026#39;, dtype={\u0026#39;CO_ORGAO_REGIONAL\u0026#39;: \u0026#39;str\u0026#39;}) extra2 = extra2[extra2.isnull().sum(axis=1) / extra2.shape[1] \u0026lt; .9] # Tratamento nas features extra2.loc[:, \u0026#39;QT_TOTAL_ALUNOS\u0026#39;] = extra2[[\u0026#39;QT_MAT_BAS_ND\u0026#39;, \u0026#39;QT_MAT_BAS_BRANCA\u0026#39;, \u0026#39;QT_MAT_BAS_PRETA\u0026#39;, \u0026#39;QT_MAT_BAS_PARDA\u0026#39;, \u0026#39;QT_MAT_BAS_AMARELA\u0026#39;, \u0026#39;QT_MAT_BAS_INDIGENA\u0026#39;]].sum(axis=1).fillna(0) extra2.loc[:, \u0026#39;QT_TOTAL_PROFESSORES\u0026#39;] = (extra2.QT_DOC_BAS + extra2.QT_DOC_INF + extra2.QT_DOC_INF_CRE + extra2.QT_DOC_INF_PRE + extra2.QT_DOC_FUND + extra2.QT_DOC_FUND_AI + extra2.QT_DOC_FUND_AF + extra2.QT_DOC_MED + extra2.QT_DOC_PROF + extra2.QT_DOC_PROF_TEC + extra2.QT_DOC_EJA + extra2.QT_DOC_EJA_FUND + extra2.QT_DOC_EJA_MED + extra2.QT_DOC_ESP + extra2.QT_DOC_ESP_CC + extra2.QT_DOC_ESP_CE).fillna(0) extra2.loc[:, \u0026#39;QT_SALAS_UTILIZADAS\u0026#39;] = (extra2.loc[:, \u0026#39;QT_TOTAL_ALUNOS\u0026#39;] / extra2.QT_SALAS_UTILIZADAS).fillna(0) extra2.loc[:, \u0026#39;QT_COMP_DISP_ALUNO\u0026#39;] = extra2.QT_DESKTOP_ALUNO + extra2.QT_COMP_PORTATIL_ALUNO + extra2.QT_TABLET_ALUNO # Selecao de faetures importantes features_extra2 = [\u0026#39;CO_ENTIDADE\u0026#39;, \u0026#39;QT_SALAS_UTILIZADAS\u0026#39;, \u0026#39;QT_TOTAL_PROFESSORES\u0026#39;, \u0026#39;IN_QUADRA_ESPORTES_COBERTA\u0026#39;, \u0026#39;IN_BIBLIOTECA\u0026#39;, \u0026#39;IN_AGUA_POTAVEL\u0026#39;, \u0026#39;IN_ENERGIA_REDE_PUBLICA\u0026#39;, \u0026#39;IN_ESGOTO_REDE_PUBLICA\u0026#39;, \u0026#39;IN_LIXO_SERVICO_COLETA\u0026#39;, \u0026#39;IN_BANHEIRO\u0026#39;, \u0026#39;QT_COMP_DISP_ALUNO\u0026#39;, \u0026#39;QT_EQUIP_MULTIMIDIA\u0026#39;, \u0026#39;IN_INTERNET\u0026#39;, \u0026#39;IN_LABORATORIO_CIENCIAS\u0026#39;, \u0026#39;IN_LABORATORIO_INFORMATICA\u0026#39;] extra2 = extra2[features_extra2] # Remover outliers for c in list(extra2.iloc[:, 1:].columns): trs = extra2.loc[extra2[c]!=88888, c].quantile(.99) extra2.loc[(extra2[c]==88888)|(extra2[c]\u0026gt;trs), c] = trs #Normalizar para calcular IEE scaler = MinMaxScaler() to_iee = scaler.fit_transform(extra2.iloc[:, 1:]) to_iee = pd.DataFrame(to_iee, columns=extra2.iloc[:, 1:].columns) # Calcular IEE e componentes extra2.loc[:, \u0026#39;COMP1\u0026#39;] = to_iee[[\u0026#39;QT_SALAS_UTILIZADAS\u0026#39;, \u0026#39;QT_TOTAL_PROFESSORES\u0026#39;, \u0026#39;IN_QUADRA_ESPORTES_COBERTA\u0026#39;, \u0026#39;IN_BIBLIOTECA\u0026#39;]].sum(axis=1) extra2.loc[:, \u0026#39;COMP2\u0026#39;] = to_iee[[\u0026#39;IN_AGUA_POTAVEL\u0026#39;, \u0026#39;IN_ENERGIA_REDE_PUBLICA\u0026#39;, \u0026#39;IN_ESGOTO_REDE_PUBLICA\u0026#39;, \u0026#39;IN_LIXO_SERVICO_COLETA\u0026#39;, \u0026#39;IN_BANHEIRO\u0026#39;]].sum(axis=1) extra2.loc[:, \u0026#39;COMP3\u0026#39;] = to_iee[[\u0026#39;QT_COMP_DISP_ALUNO\u0026#39;, \u0026#39;QT_EQUIP_MULTIMIDIA\u0026#39;, \u0026#39;IN_INTERNET\u0026#39;, \u0026#39;IN_LABORATORIO_CIENCIAS\u0026#39;, \u0026#39;IN_LABORATORIO_INFORMATICA\u0026#39;]].sum(axis=1) extra2.loc[:, \u0026#39;IEE\u0026#39;] = extra2.COMP1 + extra2.COMP2 + extra2.COMP3 train = pd.merge(train, extra2, how=\u0026#39;left\u0026#39;, left_on=\u0026#39;CO_ESCOLA\u0026#39;, right_on=\u0026#39;CO_ENTIDADE\u0026#39;).drop(\u0026#39;CO_ENTIDADE\u0026#39;, axis=1) test = pd.merge(test, extra2, how=\u0026#39;left\u0026#39;, left_on=\u0026#39;CO_ESCOLA\u0026#39;, right_on=\u0026#39;CO_ENTIDADE\u0026#39;).drop(\u0026#39;CO_ENTIDADE\u0026#39;, axis=1) Modelagem Testei muitos modelos e muitas abordagens (inclusive com finalidade de estudo). Foram modelos estatísticos (GAM considerando a distribuição Beta(0,1)), redes neurais (TabNet) e árvores mas no final das contas os que tiveram melhor custo/benefício foram o LightGBM e o CatBoost.\nSobre o tuning, tomei a decisão de não investir muito em otimização automática de hiperparâmetros pois o tempo era curto e os ganhos seriam pequenos comparados com o potencial ganho com a variedade de features que poderiam ser geradas, então fiz apenas alguns testes manuais conforme via necessidade.\nPre processing A etapa que investi bastante tempo foi para criar novas variáveis. A seguir trago algumas features construídas que foram utilizadas em determinados modelos, a partir dos dados disponíveis:\nRenda somada dos pais; Nível de ocupação somado dos pais; Renda dividido pelo número de pessoas na casa; Quantidade de celulares por pessoa na casa; Quantidade de computadores por pessoa na casa; Se a pessoa possui visão ruim (se possui baixa visão, cegueira ou monocular); Se a pessoa possui audição ruim (Surdez, deficiência auditiva); Se o aluno possui TDAH e toma medicamento controlado; Se o aluno possui TDAH e teve mais tempo de prova; Se precisou de recurso de visão ou audição (libras, baile, etc); Se o município que nasceu é o mesmo da escola; Se o município que fez a prova é o mesmo da escola; Se o município da prova é o mesmo da residência; Nota média dos alunos da respectiva escola nas outras provas (*); Renda média dos alunos da respectiva escola (*). (*) Estas features precisaram ser calculadas de maneira muito cuidadosa para não causar algum tipo de data leak!\nPost Processing Essa base tinha uma pegadinha que fazia muita diferença no resultado final. Existem duas possibilidades de um aluno tirar zero em uma prova: errar tudo ou não comparecer.\nComo temos a informação da presença do aluno na prova (o que na prática seria meio estranho) bastava dar zero para os alunos faltantes na hora de prever nos dados de teste para submeter.\nLinguagens e Códigos Definir finalidade de algumas colunas:\n# colunas que serao dropadas to_drop = [\u0026#39;IN_PROVA_DEITADO\u0026#39;, \u0026#39;NU_INSCRICAO\u0026#39;, \u0026#39;CO_MUNICIPIO_ESC\u0026#39;, \u0026#39;CO_UF_NASCIMENTO\u0026#39;, \u0026#39;CO_UF_RESIDENCIA\u0026#39;, \u0026#39;CO_UF_ESC\u0026#39;, \u0026#39;CO_UF_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, \u0026#39;CO_MUNICIPIO_NASCIMENTO\u0026#39;] # definir target e presenca target = \u0026quot;NU_NOTA_LC\u0026quot; presenca = \u0026quot;TP_PRESENCA_LC\u0026quot; # demais notas para dropar (menos ch) notas = list(set(targets)-set([target, \u0026#39;NU_NOTA_CH\u0026#39;])) Pré-processamento nos dados de treino\nX = train.copy() X.loc[:, \u0026#39;knn_feature\u0026#39;] = knn_train.knn_oof X = X.drop(to_drop, axis=1) X = X[X[presenca]==1] X = X[~X[target].isnull()] X = X.loc[:, ~X.columns.isin([target]+[presenca]+notas)] X.loc[:, \u0026#39;FE_RENDA\u0026#39;] = X.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1000, \u0026#39;C\u0026#39;:1500, \u0026#39;D\u0026#39;:2000, \u0026#39;E\u0026#39;:2500, \u0026#39;F\u0026#39;:3000, \u0026#39;G\u0026#39;:4000, \u0026#39;H\u0026#39;:5000, \u0026#39;I\u0026#39;:6000, \u0026#39;J\u0026#39;:7000,\u0026#39;K\u0026#39;:8000,\u0026#39;L\u0026#39;:9000, \u0026#39;M\u0026#39;:10000, \u0026#39;N\u0026#39;:12000, \u0026#39;O\u0026#39;:15000, \u0026#39;P\u0026#39;:20000, \u0026#39;Q\u0026#39;:30000}).astype(int) X = prep_data_questionarios(X) X = fe_mun(X) X = fe_questionario(X) X = fe_in(X) X = prep_co_escola(X) X = fe_extra(X) y = train.loc[(train[presenca]==1)\u0026amp;(~train[target].isnull()), target].astype(np.float64) Pré-processamento nos dados de teste\nX_test = test.copy() X_test.loc[:, \u0026#39;knn_feature\u0026#39;] = knn_test.knn_test X_test = X_test.drop(to_drop, axis=1) X_test = X_test.loc[:, ~X_test.columns.isin([presenca])] X_test.loc[:, \u0026#39;FE_RENDA\u0026#39;] = X_test.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1000, \u0026#39;C\u0026#39;:1500, \u0026#39;D\u0026#39;:2000, \u0026#39;E\u0026#39;:2500, \u0026#39;F\u0026#39;:3000, \u0026#39;G\u0026#39;:4000, \u0026#39;H\u0026#39;:5000, \u0026#39;I\u0026#39;:6000, \u0026#39;J\u0026#39;:7000, \u0026#39;K\u0026#39;:8000,\u0026#39;L\u0026#39;:9000, \u0026#39;M\u0026#39;:10000, \u0026#39;N\u0026#39;:12000, \u0026#39;O\u0026#39;:15000, \u0026#39;P\u0026#39;:20000, \u0026#39;Q\u0026#39;:30000}).astype(int) X_test = prep_data_questionarios(X_test) X_test = fe_mun(X_test) X_test = fe_questionario(X_test) X_test = fe_in(X_test) X_test = prep_co_escola(X_test) X_test = fe_extra(X_test) Feature engineering separada para evitar data leak:\n# calcular estatisticas nos dados de treino co_escola_renda_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).FE_RENDA.mean() co_escola_idade_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_IDADE.mean() co_escola_nota_ch = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_NOTA_CH.mean() X = X.drop(\u0026#39;NU_NOTA_CH\u0026#39;, axis=1) # instanciar objeto com as estatisticas por escola co_escola_aux = pd.DataFrame({ \u0026#39;CO_ESCOLA\u0026#39;: co_escola_renda_media.index, \u0026#39;FE_ESCOLA_RENDA_MEDIA\u0026#39;: co_escola_renda_media, \u0026#39;FE_IDADE_MEDIA\u0026#39;: co_escola_idade_media, \u0026#39;FE_NOTA_CH\u0026#39;: co_escola_nota_ch }).reset_index(drop=True) # Concatenar estatisticas nas bases de treino e teste X = pd.merge(X, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) X_test = pd.merge(X_test, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) # Codigo da escola para categorico X.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) X_test.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) # Features de contagem X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X_test.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X.NO_MUNICIPIO_RESIDENCIA.map({x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X_test.NO_MUNICIPIO_RESIDENCIA.map({ x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X.NO_MUNICIPIO_NASCIMENTO.map({ x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X_test.NO_MUNICIPIO_NASCIMENTO.map({x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) Ajustar modelo:\ncat_feat = X.columns[X.dtypes==\u0026#39;category\u0026#39;] cat_indices = [X.columns.get_loc(x) for x in cat_feat] for c in list(cat_feat): X.loc[:, c] = X.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_test.loc[:, c] = X_test.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_train, X_eval, y_train, y_eval = train_test_split(X, y, test_size=0.1, random_state=SEED) clf = CatBoostRegressor(random_state=314, cat_features=cat_indices, verbose=0, loss_function = \u0026quot;RMSE\u0026quot;, od_type = \u0026quot;Iter\u0026quot;, od_wait = 100, iterations=3000, use_best_model=True) clf.fit(X, y, eval_set = (X_eval, y_eval), verbose=False, plot=True) Salvar previsões:\nsub.loc[:, \u0026#39;NU_NOTA_LC\u0026#39;] = clf.predict(X_test) # alunos que nao foram fazer a prova tiraram zero sub.loc[test.TP_PRESENCA_LC!=1, \u0026#39;NU_NOTA_LC\u0026#39;] = 0 Comparar distribuição da target nos dados de treino com relação às previsões do modelo:\nsns.kdeplot(train.loc[:, target], shade=True, color=\u0026#39;r\u0026#39;, clip=[0,1000]) sns.kdeplot(sub.loc[:, target], shade=True, color=\u0026#39;b\u0026#39;, clip=[0,1000]) plt.legend(labels=[\u0026#39;train\u0026#39;, \u0026#39;predict\u0026#39;]) plt.title(target) Ciências Humanas Novas features desenvolvidas especificamente para este modelo:\ndef fe_ch(df): df.loc[:, \u0026#39;FE_RENDA\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1000, \u0026#39;C\u0026#39;:1500, \u0026#39;D\u0026#39;:2000, \u0026#39;E\u0026#39;:2500, \u0026#39;F\u0026#39;:3000, \u0026#39;G\u0026#39;:4000, \u0026#39;H\u0026#39;:5000, \u0026#39;I\u0026#39;:6000, \u0026#39;J\u0026#39;:7000, \u0026#39;K\u0026#39;:8000,\u0026#39;L\u0026#39;:9000, \u0026#39;M\u0026#39;:10000, \u0026#39;N\u0026#39;:12000, \u0026#39;O\u0026#39;:15000, \u0026#39;P\u0026#39;:20000, \u0026#39;Q\u0026#39;:30000}).astype(int) df.loc[:, \u0026#39;FE_NU_IDADE*TP_ANO_CONCLUIU\u0026#39;] = df.TP_ANO_CONCLUIU * df.NU_IDADE df.loc[:, \u0026#39;FE_Q002+Q024\u0026#39;] = df.loc[:, \u0026#39;Q002\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: 5, \u0026#39;G\u0026#39;: 6, \u0026#39;H\u0026#39;: -1}).astype(int) + df.loc[:, \u0026#39;Q024\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4}).astype(int) df.loc[:, \u0026#39;FE_SCORE\u0026#39;] = (1/df.TP_ANO_CONCLUIU) + np.sqrt(df.NU_IDADE) + np.where(df.TP_ESCOLA==3, 1, 0) return df Definir finalidade de algumas colunas:\n# colunas que serao dropadas to_drop = [\u0026#39;IN_PROVA_DEITADO\u0026#39;, \u0026#39;NU_INSCRICAO\u0026#39;, \u0026#39;CO_MUNICIPIO_ESC\u0026#39;, \u0026#39;CO_UF_NASCIMENTO\u0026#39;, \u0026#39;CO_UF_RESIDENCIA\u0026#39;, \u0026#39;CO_UF_ESC\u0026#39;, \u0026#39;CO_UF_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, \u0026#39;CO_MUNICIPIO_NASCIMENTO\u0026#39;] # definir target e presenca target = \u0026quot;NU_NOTA_CH\u0026quot; presenca = \u0026quot;TP_PRESENCA_CH\u0026quot; # demais notas para dropar (menos lc) notas = list(set(targets)-set([target, \u0026#39;NU_NOTA_LC\u0026#39;])) Pré-processamento nos dados de treino\nX = train.copy() X.loc[:, \u0026#39;knn_feature\u0026#39;] = knn_train.knn_oof X = X.drop(to_drop, axis=1) X = X[X[presenca]==1] X = X[~X[target].isnull()] X = X.loc[:, ~X.columns.isin([target]+[presenca]+notas)] X = fe_ch(X) X = prep_data_questionarios(X) X = fe_mun(X) X = fe_questionario(X) #X = fe_in(X) X = prep_co_escola(X) X = fe_extra(X) y = train.loc[(train[presenca]==1)\u0026amp;(~train[target].isnull()), target].astype(np.float64) Pré-processamento nos dados de teste\nX_test = test.copy() X_test.loc[:, \u0026#39;knn_feature\u0026#39;] = knn_test.knn_test X_test = X_test.drop(to_drop, axis=1) X_test = X_test.loc[:, ~X_test.columns.isin([presenca])] X_test = fe_ch(X_test) X_test = prep_data_questionarios(X_test) X_test = fe_mun(X_test) X_test = fe_questionario(X_test) #X_test = fe_in(X_test) X_test = prep_co_escola(X_test) X_test = fe_extra(X_test) Feature engineering separada para evitar data leak:\n# calcular estatisticas nos dados de treino co_escola_renda_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).FE_RENDA.mean() co_escola_idade_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_IDADE.mean() co_escola_nota_lc = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_NOTA_LC.mean() X = X.drop(\u0026#39;NU_NOTA_LC\u0026#39;, axis=1) # instanciar objeto com as estatisticas por escola co_escola_aux = pd.DataFrame({ \u0026#39;CO_ESCOLA\u0026#39;: co_escola_renda_media.index, \u0026#39;FE_ESCOLA_RENDA_MEDIA\u0026#39;: co_escola_renda_media, \u0026#39;FE_IDADE_MEDIA\u0026#39;: co_escola_idade_media, \u0026#39;FE_NOTA_LC\u0026#39;: co_escola_nota_lc }).reset_index(drop=True) # Concatenar estatisticas nas bases de treino e teste X = pd.merge(X, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) X_test = pd.merge(X_test, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) # Codigo da escola para categorico X.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) X_test.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) # Features de contagem X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X_test.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X.NO_MUNICIPIO_RESIDENCIA.map({x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X_test.NO_MUNICIPIO_RESIDENCIA.map({ x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X.NO_MUNICIPIO_NASCIMENTO.map({ x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X_test.NO_MUNICIPIO_NASCIMENTO.map({x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) Ajustar modelo:\n%%time cat_feat = X.columns[X.dtypes==\u0026#39;category\u0026#39;] cat_indices = [X.columns.get_loc(x) for x in cat_feat] for c in list(cat_feat): X.loc[:, c] = X.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_test.loc[:, c] = X_test.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_train, X_eval, y_train, y_eval = train_test_split(X, y, test_size=0.1, random_state=SEED) clf = CatBoostRegressor(random_state=314, cat_features=cat_indices, verbose=0, loss_function = \u0026quot;RMSE\u0026quot;, od_type = \u0026quot;Iter\u0026quot;, od_wait = 100,iterations=3000, use_best_model=True) clf.fit(X, y, eval_set = (X_eval, y_eval), verbose=False, plot=True) Salvar previsões:\nsub.loc[:, \u0026#39;NU_NOTA_CH\u0026#39;] = clf.predict(X_test) # alunos que nao foram fazer a prova tiraram zero sub.loc[test.TP_PRESENCA_CH!=1, \u0026#39;NU_NOTA_CH\u0026#39;] = 0 Comparar distribuição da target nos dados de treino com relação às previsões do modelo:\nsns.kdeplot(train.loc[:, target], shade=True, color=\u0026#39;r\u0026#39;, clip=[0,1000]) sns.kdeplot(sub.loc[:, target], shade=True, color=\u0026#39;b\u0026#39;, clip=[0,1000]) plt.legend(labels=[\u0026#39;train\u0026#39;, \u0026#39;predict\u0026#39;]) plt.title(target) Ciências da Natureza Novas features desenvolvidas especificamente para este modelo:\ndef fe_cn(df): df.loc[:, \u0026#39;FE_RENDA\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1000, \u0026#39;C\u0026#39;:1500, \u0026#39;D\u0026#39;:2000, \u0026#39;E\u0026#39;:2500, \u0026#39;F\u0026#39;:3000, \u0026#39;G\u0026#39;:4000, \u0026#39;H\u0026#39;:5000, \u0026#39;I\u0026#39;:6000, \u0026#39;J\u0026#39;:7000, \u0026#39;K\u0026#39;:8000,\u0026#39;L\u0026#39;:9000, \u0026#39;M\u0026#39;:10000, \u0026#39;N\u0026#39;:12000, \u0026#39;O\u0026#39;:15000, \u0026#39;P\u0026#39;:20000, \u0026#39;Q\u0026#39;:30000}).astype(int) df.loc[:, \u0026#39;FE_NU_IDADE*TP_ANO_CONCLUIU\u0026#39;] = df.TP_ANO_CONCLUIU * df.NU_IDADE df.loc[:, \u0026#39;FE_Q002+Q024\u0026#39;] = df.loc[:, \u0026#39;Q002\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: 5, \u0026#39;G\u0026#39;: 6, \u0026#39;H\u0026#39;: -1}).astype(int) + df.loc[:, \u0026#39;Q024\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4}).astype(int) df.loc[:, \u0026#39;FE_SCORE\u0026#39;] = (1/df.TP_ANO_CONCLUIU) + np.sqrt(df.NU_IDADE) + np.where(df.TP_ESCOLA==3, 1, 0) df.loc[:, \u0026#39;FE_UF_ESCOLA\u0026#39;] = df.SG_UF_ESC.map({ \u0026#39;AM\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;RR\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;AP\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;PA\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;TO\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;RO\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;AC\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;MA\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;PI\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;CE\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;RN\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;PE\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;PB\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;SE\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;AL\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;BA\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;MT\u0026#39;: \u0026#39;CentroOeste\u0026#39;, \u0026#39;MS\u0026#39;: \u0026#39;CentroOeste\u0026#39;, \u0026#39;GO\u0026#39;: \u0026#39;CentroOeste\u0026#39;, \u0026#39;SP\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;RJ\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;ES\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;MG\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;PR\u0026#39;: \u0026#39;Sul\u0026#39;, \u0026#39;RS\u0026#39;: \u0026#39;Sul\u0026#39;, \u0026#39;SC\u0026#39;: \u0026#39;Sul\u0026#39;}).astype(\u0026#39;category\u0026#39;) return df Definir finalidade de algumas colunas:\n# colunas que serao dropadas to_drop = [\u0026#39;IN_PROVA_DEITADO\u0026#39;, \u0026#39;NU_INSCRICAO\u0026#39;, \u0026#39;CO_MUNICIPIO_ESC\u0026#39;, \u0026#39;CO_UF_NASCIMENTO\u0026#39;, \u0026#39;CO_UF_RESIDENCIA\u0026#39;, \u0026#39;CO_UF_ESC\u0026#39;, \u0026#39;CO_UF_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, \u0026#39;CO_MUNICIPIO_NASCIMENTO\u0026#39;] # definir target e presenca target = \u0026quot;NU_NOTA_CN\u0026quot; presenca = \u0026quot;TP_PRESENCA_CN\u0026quot; # demais notas para dropar (menos mt) notas = list(set(targets)-set([target, \u0026#39;NU_NOTA_MT\u0026#39;])) Pré-processamento nos dados de treino\nX = train.copy() X = X.drop(to_drop, axis=1) X = X[X[presenca]==1] X = X[~X[target].isnull()] X = X.loc[:, ~X.columns.isin([target]+[presenca]+notas)] X = fe_cn(X) X = prep_data_questionarios(X) X = fe_mun(X) X = fe_questionario(X) X = fe_in(X) X = prep_co_escola(X) X = fe_extra(X) y = train.loc[(train[presenca]==1)\u0026amp;(~train[target].isnull()), target].astype(np.float64) Pré-processamento nos dados de teste\nX_test = test.copy() X_test = X_test.drop(to_drop, axis=1) X_test = X_test.loc[:, ~X_test.columns.isin([presenca])] X_test = fe_cn(X_test) X_test = prep_data_questionarios(X_test) X_test = fe_mun(X_test) X_test = fe_questionario(X_test) X_test = fe_in(X_test) X_test = prep_co_escola(X_test) X_test = fe_extra(X_test) Feature engineering separada para evitar data leak:\n# calcular estatisticas nos dados de treino co_escola_renda_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).FE_RENDA.mean() co_escola_idade_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_IDADE.mean() co_escola_nota_mt = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_NOTA_MT.mean() X = X.drop(\u0026#39;NU_NOTA_MT\u0026#39;, axis=1) # instanciar objeto com as estatisticas por escola co_escola_aux = pd.DataFrame({ \u0026#39;CO_ESCOLA\u0026#39;: co_escola_renda_media.index, \u0026#39;FE_ESCOLA_RENDA_MEDIA\u0026#39;: co_escola_renda_media, \u0026#39;FE_IDADE_MEDIA\u0026#39;: co_escola_idade_media, \u0026#39;FE_NOTA_MT\u0026#39;: co_escola_nota_mt }).reset_index(drop=True) # Concatenar estatisticas nas bases de treino e teste X = pd.merge(X, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) X_test = pd.merge(X_test, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) # Codigo da escola para categorico X.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) X_test.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) # Features de contagem X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X_test.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X.NO_MUNICIPIO_RESIDENCIA.map({x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X_test.NO_MUNICIPIO_RESIDENCIA.map({ x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X.NO_MUNICIPIO_NASCIMENTO.map({ x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X_test.NO_MUNICIPIO_NASCIMENTO.map({x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) Ajustar modelo:\n%%time cat_feat = X.columns[X.dtypes==\u0026#39;category\u0026#39;] cat_indices = [X.columns.get_loc(x) for x in cat_feat] for c in list(cat_feat): X.loc[:, c] = X.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_test.loc[:, c] = X_test.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_train, X_eval, y_train, y_eval = train_test_split(X, y, test_size=0.1, random_state=SEED) clf = CatBoostRegressor(random_state=314, cat_features=cat_indices, verbose=0, loss_function = \u0026quot;RMSE\u0026quot;, od_type = \u0026quot;Iter\u0026quot;, od_wait = 100,iterations=3000, use_best_model=True) clf.fit(X, y, eval_set = (X_eval, y_eval), verbose=False, plot=True) Salvar previsões:\nsub.loc[:, \u0026#39;NU_NOTA_CN\u0026#39;] = clf.predict(X_test) # alunos que nao foram fazer a prova tiraram zero sub.loc[test.TP_PRESENCA_CN!=1, \u0026#39;NU_NOTA_CN\u0026#39;] = 0 Comparar distribuição da target nos dados de treino com relação às previsões do modelo:\nsns.kdeplot(train.loc[:, target], shade=True, color=\u0026#39;r\u0026#39;, clip=[0,1000]) sns.kdeplot(sub.loc[:, target], shade=True, color=\u0026#39;b\u0026#39;, clip=[0,1000]) plt.legend(labels=[\u0026#39;train\u0026#39;, \u0026#39;predict\u0026#39;]) plt.title(target) Matemática Novas features desenvolvidas especificamente para este modelo:\ndef fe_mt(df): df.loc[:, \u0026#39;FE_RENDA\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1000, \u0026#39;C\u0026#39;:1500, \u0026#39;D\u0026#39;:2000, \u0026#39;E\u0026#39;:2500, \u0026#39;F\u0026#39;:3000, \u0026#39;G\u0026#39;:4000, \u0026#39;H\u0026#39;:5000, \u0026#39;I\u0026#39;:6000, \u0026#39;J\u0026#39;:7000, \u0026#39;K\u0026#39;:8000,\u0026#39;L\u0026#39;:9000, \u0026#39;M\u0026#39;:10000, \u0026#39;N\u0026#39;:12000, \u0026#39;O\u0026#39;:15000, \u0026#39;P\u0026#39;:20000, \u0026#39;Q\u0026#39;:30000}).astype(int) df.loc[:, \u0026#39;FE_NU_IDADE*TP_ANO_CONCLUIU\u0026#39;] = df.TP_ANO_CONCLUIU * df.NU_IDADE df.loc[:, \u0026#39;FE_Q002+Q024\u0026#39;] = df.loc[:, \u0026#39;Q002\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: 5, \u0026#39;G\u0026#39;: 6, \u0026#39;H\u0026#39;: -1}).astype(int) + df.loc[:, \u0026#39;Q024\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4}).astype(int) df.loc[:, \u0026#39;FE_SCORE\u0026#39;] = (1/df.TP_ANO_CONCLUIU) + np.sqrt(df.NU_IDADE) + np.where(df.TP_ESCOLA==3, 1, 0) df.loc[:, \u0026#39;FE_UF_ESCOLA\u0026#39;] = df.SG_UF_ESC.map({\u0026#39;AM\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;RR\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;AP\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;PA\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;TO\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;RO\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;AC\u0026#39;:\u0026#39;Norte\u0026#39;, \u0026#39;MA\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;PI\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;CE\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;RN\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;PE\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;PB\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;SE\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;AL\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;BA\u0026#39;:\u0026#39;Nordeste\u0026#39;, \u0026#39;MT\u0026#39;: \u0026#39;CentroOeste\u0026#39;, \u0026#39;MS\u0026#39;: \u0026#39;CentroOeste\u0026#39;, \u0026#39;GO\u0026#39;: \u0026#39;CentroOeste\u0026#39;, \u0026#39;SP\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;RJ\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;ES\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;MG\u0026#39;: \u0026#39;Sudeste\u0026#39;, \u0026#39;PR\u0026#39;: \u0026#39;Sul\u0026#39;, \u0026#39;RS\u0026#39;: \u0026#39;Sul\u0026#39;, \u0026#39;SC\u0026#39;: \u0026#39;Sul\u0026#39;}).astype(\u0026#39;category\u0026#39;) return df Definir finalidade de algumas colunas:\n# colunas que serao dropadas to_drop = [\u0026#39;IN_PROVA_DEITADO\u0026#39;, \u0026#39;NU_INSCRICAO\u0026#39;, \u0026#39;CO_MUNICIPIO_ESC\u0026#39;, \u0026#39;CO_UF_NASCIMENTO\u0026#39;, \u0026#39;CO_UF_RESIDENCIA\u0026#39;, \u0026#39;CO_UF_ESC\u0026#39;, \u0026#39;CO_UF_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, \u0026#39;CO_MUNICIPIO_NASCIMENTO\u0026#39;] # definir target e presenca target = \u0026quot;NU_NOTA_MT\u0026quot; presenca = \u0026quot;TP_PRESENCA_MT\u0026quot; # demais notas para dropar (menos cn) notas = list(set(targets)-set([target, \u0026#39;NU_NOTA_CN\u0026#39;])) Pré-processamento nos dados de treino\nX = train.copy() X = X.drop(to_drop, axis=1) X = X[X[presenca]==1] X = X[~X[target].isnull()] X = X.loc[:, ~X.columns.isin([target]+[presenca]+notas)] X = fe_mt(X) X = prep_data_questionarios(X) X = fe_mun(X) #X = fe_questionario(X) #X = fe_in(X) X = prep_co_escola(X) X = fe_extra(X) y = train.loc[(train[presenca]==1)\u0026amp;(~train[target].isnull()), target].astype(np.float64) Pré-processamento nos dados de teste\nX_test = test.copy() X_test = X_test.drop(to_drop, axis=1) X_test = X_test.loc[:, ~X_test.columns.isin([presenca])] X_test = fe_mt(X_test) X_test = prep_data_questionarios(X_test) X_test = fe_mun(X_test) #X_test = fe_questionario(X_test) #X_test = fe_in(X_test) X_test = prep_co_escola(X_test) X_test = fe_extra(X_test) Feature engineering separada para evitar data leak:\n# calcular estatisticas nos dados de treino co_escola_renda_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).FE_RENDA.mean() co_escola_idade_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_IDADE.mean() co_escola_nota_cn = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_NOTA_CN.mean() X = X.drop(\u0026#39;NU_NOTA_CN\u0026#39;, axis=1) # instanciar objeto com as estatisticas por escola co_escola_aux = pd.DataFrame({ \u0026#39;CO_ESCOLA\u0026#39;: co_escola_renda_media.index, \u0026#39;FE_ESCOLA_RENDA_MEDIA\u0026#39;: co_escola_renda_media, \u0026#39;FE_IDADE_MEDIA\u0026#39;: co_escola_idade_media, \u0026#39;FE_NOTA_CN\u0026#39;: co_escola_nota_cn }).reset_index(drop=True) # Concatenar estatisticas nas bases de treino e teste X = pd.merge(X, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) X_test = pd.merge(X_test, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) # Codigo da escola para categorico X.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) X_test.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) # Features de contagem X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X_test.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X.NO_MUNICIPIO_RESIDENCIA.map({x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X_test.NO_MUNICIPIO_RESIDENCIA.map({ x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X.NO_MUNICIPIO_NASCIMENTO.map({ x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X_test.NO_MUNICIPIO_NASCIMENTO.map({x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) Ajustar modelo:\n%%time cat_feat = X.columns[X.dtypes==\u0026#39;category\u0026#39;] cat_indices = [X.columns.get_loc(x) for x in cat_feat] for c in list(cat_feat): X.loc[:, c] = X.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_test.loc[:, c] = X_test.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_train, X_eval, y_train, y_eval = train_test_split(X, y, test_size=0.1, random_state=SEED) clf = CatBoostRegressor(random_state=314, cat_features=cat_indices, verbose=0, loss_function = \u0026quot;RMSE\u0026quot;, od_type = \u0026quot;Iter\u0026quot;, od_wait = 100,iterations=3000, use_best_model=True) clf.fit(X, y, eval_set = (X_eval, y_eval), verbose=False, plot=True) Salvar previsões:\nsub.loc[:, \u0026#39;NU_NOTA_MT\u0026#39;] = clf.predict(X_test) # alunos que nao foram fazer a prova tiraram zero sub.loc[test.TP_PRESENCA_CN!=1, \u0026#39;NU_NOTA_MT\u0026#39;] = 0 Comparar distribuição da target nos dados de treino com relação às previsões do modelo:\nsns.kdeplot(train.loc[:, target], shade=True, color=\u0026#39;r\u0026#39;, clip=[0,1000]) sns.kdeplot(sub.loc[:, target], shade=True, color=\u0026#39;b\u0026#39;, clip=[0,1000]) plt.legend(labels=[\u0026#39;train\u0026#39;, \u0026#39;predict\u0026#39;]) plt.title(target) Redação Novas features desenvolvidas especificamente para este modelo:\ndef fe_rd(df): df.loc[:, \u0026#39;FE_RENDA\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1000, \u0026#39;C\u0026#39;:1500, \u0026#39;D\u0026#39;:2000, \u0026#39;E\u0026#39;:2500, \u0026#39;F\u0026#39;:3000, \u0026#39;G\u0026#39;:4000, \u0026#39;H\u0026#39;:5000, \u0026#39;I\u0026#39;:6000, \u0026#39;J\u0026#39;:7000, \u0026#39;K\u0026#39;:8000,\u0026#39;L\u0026#39;:9000, \u0026#39;M\u0026#39;:10000, \u0026#39;N\u0026#39;:12000, \u0026#39;O\u0026#39;:15000, \u0026#39;P\u0026#39;:20000, \u0026#39;Q\u0026#39;:30000}).astype(int) df.loc[:, \u0026#39;FE_NU_IDADE*TP_ANO_CONCLUIU\u0026#39;] = df.TP_ANO_CONCLUIU * df.NU_IDADE df.loc[:, \u0026#39;FE_Q002+Q024\u0026#39;] = df.loc[:, \u0026#39;Q002\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;: 5, \u0026#39;G\u0026#39;: 6, \u0026#39;H\u0026#39;: -1}).astype(int) + df.loc[:, \u0026#39;Q024\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4}).astype(int) df.loc[:, \u0026#39;FE_SCORE\u0026#39;] = (1/df.TP_ANO_CONCLUIU) + np.sqrt(df.NU_IDADE) + np.where(df.TP_ESCOLA==3, 1, 0) df.loc[:, \u0026#39;FE_RENDA_FAMILIA_+_IDADE\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;:5, \u0026#39;G\u0026#39;:6, \u0026#39;H\u0026#39;:7, \u0026#39;I\u0026#39;:8, \u0026#39;J\u0026#39;:9, \u0026#39;K\u0026#39;:10,\u0026#39;L\u0026#39;:11, \u0026#39;M\u0026#39;:12, \u0026#39;N\u0026#39;:13, \u0026#39;O\u0026#39;:14, \u0026#39;P\u0026#39;:15, \u0026#39;Q\u0026#39;:16}).astype(int) + df.NU_IDADE df.loc[:, \u0026#39;FE_RENDA_FAMILIA_+_ANO_CONCLUIU\u0026#39;] = df.loc[:, \u0026#39;Q006\u0026#39;].map({\u0026#39;A\u0026#39;:0, \u0026#39;B\u0026#39;:1, \u0026#39;C\u0026#39;:2, \u0026#39;D\u0026#39;:3, \u0026#39;E\u0026#39;:4, \u0026#39;F\u0026#39;:5, \u0026#39;G\u0026#39;:6, \u0026#39;H\u0026#39;:7, \u0026#39;I\u0026#39;:8, \u0026#39;J\u0026#39;:9, \u0026#39;K\u0026#39;:10,\u0026#39;L\u0026#39;:11, \u0026#39;M\u0026#39;:12, \u0026#39;N\u0026#39;:13, \u0026#39;O\u0026#39;:14, \u0026#39;P\u0026#39;:15, \u0026#39;Q\u0026#39;:16}).astype(int)+ df.TP_ANO_CONCLUIU return df Definir finalidade de algumas colunas:\n# colunas que serao dropadas to_drop = [\u0026#39;IN_PROVA_DEITADO\u0026#39;, \u0026#39;NU_INSCRICAO\u0026#39;, \u0026#39;CO_MUNICIPIO_ESC\u0026#39;, \u0026#39;CO_UF_NASCIMENTO\u0026#39;, \u0026#39;CO_UF_RESIDENCIA\u0026#39;, \u0026#39;CO_UF_ESC\u0026#39;, \u0026#39;CO_UF_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_PROVA\u0026#39;, \u0026#39;CO_MUNICIPIO_RESIDENCIA\u0026#39;, \u0026#39;CO_MUNICIPIO_NASCIMENTO\u0026#39;] # definir target e presenca target = \u0026quot;NU_NOTA_REDACAO\u0026quot; presenca = \u0026quot;TP_STATUS_REDACAO\u0026quot; # demais notas para dropar notas = list(set(targets)-set([target])) Pré-processamento nos dados de treino\nX = train.copy() X = X.drop(to_drop, axis=1) X = X[X[presenca]==1] X = X[~X[target].isnull()] X = X.loc[:, ~X.columns.isin([target]+[presenca]+notas)] X = fe_rd(X) X = prep_data_questionarios(X) X = fe_mun(X) #X = fe_questionario(X) X = fe_in(X) X = prep_co_escola(X) X = fe_extra(X) y = train.loc[(train[presenca]==1)\u0026amp;(~train[target].isnull()), target].astype(np.float64) Pré-processamento nos dados de teste\nX_test = test.copy() X_test = X_test.drop(to_drop, axis=1) X_test = X_test.loc[:, ~X_test.columns.isin([presenca])] X_test = fe_rd(X_test) X_test = prep_data_questionarios(X_test) X_test = fe_mun(X_test) #X_test = fe_questionario(X_test) X_test = fe_in(X_test) X_test = prep_co_escola(X_test) X_test = fe_extra(X_test) Feature engineering separada para evitar data leak:\n# calcular estatisticas nos dados de treino co_escola_renda_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).FE_RENDA.mean() co_escola_idade_media = X.groupby(\u0026#39;CO_ESCOLA\u0026#39;).NU_IDADE.mean() # instanciar objeto com as estatisticas por escola co_escola_aux = pd.DataFrame({ \u0026#39;CO_ESCOLA\u0026#39;: co_escola_renda_media.index, \u0026#39;FE_ESCOLA_RENDA_MEDIA\u0026#39;: co_escola_renda_media, \u0026#39;FE_IDADE_MEDIA\u0026#39;: co_escola_idade_media }).reset_index(drop=True) # Concatenar estatisticas nas bases de treino e teste X = pd.merge(X, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) X_test = pd.merge(X_test, co_escola_aux, how=\u0026#39;left\u0026#39;, on=\u0026#39;CO_ESCOLA\u0026#39;) # Codigo da escola para categorico X.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) X_test.loc[:, \u0026#39;CO_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.astype(\u0026#39;object\u0026#39;).astype(\u0026#39;category\u0026#39;) # Features de contagem X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_PROVA\u0026#39;] = X_test.NO_MUNICIPIO_PROVA.map({x: y for x, y in zip(X.NO_MUNICIPIO_PROVA.value_counts().index.values, X.NO_MUNICIPIO_PROVA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X.NO_MUNICIPIO_RESIDENCIA.map({x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_RESIDENCIA\u0026#39;] = X_test.NO_MUNICIPIO_RESIDENCIA.map({ x: y for x, y in zip(X.NO_MUNICIPIO_RESIDENCIA.value_counts().index.values, X.NO_MUNICIPIO_RESIDENCIA.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X.NO_MUNICIPIO_NASCIMENTO.map({ x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_MUNICIPIO_NASCIMENTO\u0026#39;] = X_test.NO_MUNICIPIO_NASCIMENTO.map({x: y for x, y in zip(X.NO_MUNICIPIO_NASCIMENTO.value_counts().index.values, X.NO_MUNICIPIO_NASCIMENTO.value_counts().values)}) X.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) X_test.loc[:, \u0026#39;FE_COUNT_ESCOLA\u0026#39;] = X_test.CO_ESCOLA.map({x: y for x, y in zip(X.CO_ESCOLA.value_counts().index.values, X.CO_ESCOLA.value_counts().values)}) Ajustar modelo:\n%%time cat_feat = X.columns[X.dtypes==\u0026#39;category\u0026#39;] cat_indices = [X.columns.get_loc(x) for x in cat_feat] for c in list(cat_feat): X.loc[:, c] = X.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_test.loc[:, c] = X_test.loc[:, c].astype(object).fillna(\u0026quot;XXX\u0026quot;).astype(\u0026quot;category\u0026quot;) X_train, X_eval, y_train, y_eval = train_test_split(X, y, test_size=0.1, random_state=SEED) clf = CatBoostRegressor(random_state=314, cat_features=cat_indices, verbose=0, loss_function = \u0026quot;RMSE\u0026quot;, od_type = \u0026quot;Iter\u0026quot;, od_wait = 100,iterations=3000, use_best_model=True) clf.fit(X, y, eval_set = (X_eval, y_eval), verbose=False, plot=True) Salvar previsões:\nsub.loc[:, \u0026#39;NU_NOTA_REDACAO\u0026#39;] = clf.predict(X_test) # alunos que nao foram fazer a prova tiraram zero sub.loc[test.TP_STATUS_REDACAO!=1, \u0026#39;NU_NOTA_REDACAO\u0026#39;] = 0 Comparar distribuição da target nos dados de treino com relação às previsões do modelo:\nsns.kdeplot(train.loc[:, target], shade=True, color=\u0026#39;r\u0026#39;, clip=[0,1000]) sns.kdeplot(sub.loc[:, target], shade=True, color=\u0026#39;b\u0026#39;, clip=[0,1000]) plt.legend(labels=[\u0026#39;train\u0026#39;, \u0026#39;predict\u0026#39;]) plt.title(target) Submissão Veja a seguir como ficou a distribuição das previsões comparada à distribuição da target nos dados de treino:\nplt.figure(figsize=(16, 5)) notas = [\u0026#39;NU_NOTA_CH\u0026#39;, \u0026#39;NU_NOTA_CN\u0026#39;, \u0026#39;NU_NOTA_MT\u0026#39;, \u0026#39;NU_NOTA_LC\u0026#39;, \u0026#39;NU_NOTA_REDACAO\u0026#39;] for i in range(len(notas)): plt.subplot(1, 5, i+1) sns.kdeplot(train.loc[:, notas[i]], shade=True, color=\u0026#39;r\u0026#39;, clip=[0,1000]) sns.kdeplot(sub.loc[:, notas[i]], shade=True, color=\u0026#39;b\u0026#39;, clip=[0,1000]) plt.legend(labels=[\u0026#39;train\u0026#39;, \u0026#39;predict\u0026#39;]) plt.title(notas[i]) plt.tight_layout() plt.show() Acredito que talvez um tuning do modelo poderia trazer mais qualidade às previsões mas com o tempo limitado não pude investir muito nesta etapa.\nConsiderações Finais Em resumo, essas foram as principais idéias para a solução da competição e acredito que um dos segredos era focar em feature engineering por 2 motivos:\nA base era muito grande e o processo de tuning seria muito custoso (a não ser que tenha um ótimo computador a disposição); Os atributos não eram anônimos, o que dá muita informação de contexto. Agradeço aos organizadores e à todos os participantes que tornaram esta competição tão divertida! Por mais competições como esta, que valorizam a comunidade brasileira de Data Science!\nEspero que tenham gostado e até logo!\nAbraços!\nFellipe Gomes\nPerguntas frequentes Qual algoritmo foi usado na solução que ficou em 2º lugar na ML Olympiad?\nA modelagem final foi feita em Python com CatBoost, testado ao lado de LightGBM, redes neurais TabNet e modelos GAM, sendo o CatBoost o de melhor custo-benefício.\nComo o problema de previsão das notas do ENEM foi estruturado?\nFoi tratado como um problema supervisionado de regressão com múltiplos outputs, resolvido com 5 modelos independentes, um para cada nota (CH, CN, LC, MT e Redação).\nQual métrica foi usada para validar o modelo?\nA validação usou o MCRMSE (Mean Columnwise Root Mean Squared Error), que calcula a média do RMSE das previsões de cada uma das cinco notas.\n","date":"19 de abril de 2022","externalUrl":null,"permalink":"/post/2022-04-20-solucao-final-education-quality-kaggle-competition/","section":"Posts","summary":" Introdução Definição do problema de negócio Análise Exploratória (em R) Estrutura da base Ano da base de dados Target Machine Learning (em Python) Importar dependencias Carregar dados Modelagem Submissão Considerações Finais Introdução No final de Janeiro desde ano (2022) o TFUG - TensorFlow Users Group de São Paulo lançou uma competição no Kaggle para prever as notas do enem que tem relação com um dos 17 tópicos de Desenvolvimento Sustentável das Nações Unidas - Educação de Qualidade.\n","title":"Solução Final - ML Olympiad [2º lugar]","type":"post"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/ggplot2/","section":"Tags","summary":"","title":"Ggplot2","type":"tags"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/grafo/","section":"Tags","summary":"","title":"Grafo","type":"tags"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/rstudio/","section":"Tags","summary":"","title":"Rstudio","type":"tags"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/strings/","section":"Tags","summary":"","title":"Strings","type":"tags"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/text-mining/","section":"Tags","summary":"","title":"Text-Mining","type":"tags"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/tidyverse/","section":"Tags","summary":"","title":"Tidyverse","type":"tags"},{"content":" Introdução e contexto O que são Grafos? Como contruir um? Carregar dependências Fonte dos dados NER - Named Entity Recognition Preparar dados Bônus Conclusão Outras bibliotecas para construção de grafos Introdução e contexto Durante os anos de 2020 e 2021 fiz um MBA Executivo em Business Analytics e Big Data na FGV e uma das disciplinas que gostei bastante abordou a análise de mídias sociais com técnicas de mineração de texto e processamento de linguagem natural.\nNo trabalho final fomos desafiados a extrair dados da internet via api ou scraping, aplicar a metodologia apropriada para extrair informações de interesse e contruir um Grafo.\nComo esse gráfico deu mais de trabalho do que eu esperava e fiquei bem satisfeito com o resultado final, resolvi fazer uma nova análise para praticar e publicar aqui no blog, espero que gostem!\nTL;DR\nO post usa web scraping do G1 - Globo, reconhecimento de entidades (NER) com Spacy e os pacotes igraph, tidygraph e ggraph para montar um grafo em R. O grafo final mapeia relações entre pessoas e organizações citadas em notícias de economia do Brasil, retendo apenas combinações que ocorreram mais de 3 vezes. Como bônus, o autor também construiu um grafo a partir de ~27GB de tweets sobre a CPI da pandemia, com código disponível no GitHub. O que são Grafos? 📎 Segundo o Wikipedia:\n“A teoria dos grafos é um ramo da matemática que estuda as relações entre os objetos de um determinado conjunto”\nSão muito úteis para análises de redes sociais, redes de amizades ou qualquer rede com relações de dependências. Existem muitos tipos de grafos como conectados, desconectados, esparsos, densos, direcionados, não direcionados e por ai vai…\nAlém disso existe toda uma nomenclatura específica, mas não entrarei em detalhes teóricos neste post pois também estou estudado sobre o tema! Caso queira aprofundar na teoria por trás recomendo este material gratuito muito bom!\nComo contruir um? No curso que fiz aprendemos a mexer no Gephi para a contrução desses Grafos (ferramenta incrível, diga-se de passagem) porém ouvi dizer diversas vezes, tanto dentro quanto fora da FGV, que R e Python eram muito limitados para construção de Grafos bonitos e que esse software sempre a melhor opção.\nApesar do enorme potencial do Gephi, fiquei um pouco entediado estudando-o pois não sou grande fã de ferramentas point-and-click e quando o professor falou que a escolha da ferramenta para a construção do Grafo era livre, resolvi tentar fazê-lo em R!\nCarregar dependências Pacotes utilizados neste post:\nBoa parte do trabalho de organizar os dados coletados depende de técnicas de manipulação de dados com dplyr, além de rotinas de manipulação de strings e text mining para tratar os textos extraídos.\nlibrary(rvest) # web scrapping library(dplyr) # manipulate data library(purrr) # functional prog library(stringr) # str toolkit library(spacyr) # ner library(igraph) # base graph library(tidygraph) # tidy graph library(ggraph) # plot graph Fonte dos dados Os dados utilizados neste post foram coletados via web scrapping do site do G1 - Globo. Optei por trabalhar com textos jornalísticos neste post pois apresentam a vantagem de serem bem escritos, o que facilita na tarefa de mineração de texto.\nTambém fiz um grafo analisando tweets sobre a CPI da pandemia que será apresentado como bônus no final deste post e para quem tiver curiosidade de conferir os códigos vai notar que foi necessário um tratamento muito mais extensivo para corrigir os nomes de cada um dos senadores, deputados e personagens políticos detectados.\nConfira abaixo todos os códigos necessários para realizar tal extração:\n(Clique aqui para exibir as funções scrape_post_links e scrape_post_body ) # Funcao para coletar os links de cada noticia scrape_post_links \u0026lt;- function(site) { cat(paste0(site, \u0026quot;\\n\u0026quot;)) source_html \u0026lt;- read_html(site) links \u0026lt;- source_html %\u0026gt;% html_nodes(\u0026quot;div.widget--info__text-container\u0026quot;) %\u0026gt;% html_nodes(\u0026quot;a\u0026quot;) %\u0026gt;% html_attr(\u0026quot;href\u0026quot;) links \u0026lt;- links[!is.na(links)] return(links) } # Funcao para coletar o texto da materia em cada link scrape_post_body \u0026lt;- function(site) { text \u0026lt;- tryCatch({ cat(paste0(site, \u0026quot;\\n\u0026quot;)) body \u0026lt;- site %\u0026gt;% read_html %\u0026gt;% html_nodes(\u0026quot;article\u0026quot;) %\u0026gt;% html_nodes(\u0026quot;p.content-text__container\u0026quot;) %\u0026gt;% html_text %\u0026gt;% paste(collapse = \u0026#39;\u0026#39;) }, error = function(e){ cat(paste(\u0026quot;ERRO 404\u0026quot;, \u0026quot;\\n\u0026quot;)) body \u0026lt;- NA }) return(body) } # criar matriz de adjacencias get_adjacent_list \u0026lt;- function(edge_list) { gtools::combinations(length(edge_list), 2, edge_list) } # raiz root \u0026lt;- \u0026quot;https://g1.globo.com/busca/?q=economia+brasil\u0026quot; # gerar links das proximas 100 paginas all_pages \u0026lt;- c(root, paste0(root, \u0026quot;\u0026amp;page=\u0026quot;, 1:50)) # coletar os links dos posts de cada pagina all_links \u0026lt;- map(all_pages, scrape_post_links) %\u0026gt;% unlist() # extrair urls cleaned_links \u0026lt;- map_chr(all_links, ~{ .x %\u0026gt;% urltools::param_get() %\u0026gt;% pull(u) %\u0026gt;% urltools::url_decode() }) # reter apenas links que falam de economia cleaned_links \u0026lt;- cleaned_links %\u0026gt;% .[str_detect(., \u0026quot;g1.globo.com/economia\u0026quot;)] # nao reter links do globoplay cleaned_links \u0026lt;- cleaned_links %\u0026gt;% .[!str_detect(., \u0026quot;globoplay\u0026quot;)] # coletar conteudo de cada link data \u0026lt;- map_chr(cleaned_links, scrape_post_body) %\u0026gt;% unique() NER - Named Entity Recognition Utilizaremos um modelo de reconhecimento de entidades pré-treinado fornecido pela Spacy (que fornece essa e muitas outras soluções interessantes quando se trata de processamento de linguagem natural).\nSe text mining em R te interessa, o Text Mining with R, da Julia Silge com o David Robinson, é o livro que mais uso como referência pra esse tipo de análise com tidytext.\nPrimeiramente vamos configurar o spacyr na máquina para utilizar o modelo pré treinado para reconhecimento de entidades em português:\n# Executar apenas 1 vez spacyr::spacy_install() spacy_download_langmodel(\u0026quot;pt_core_news_sm\u0026quot;) Inicializar modelo pré-treinado em português:\nspacy_initialize(model=\u0026quot;pt_core_news_sm\u0026quot;) Aplicar modelo carregado para o reconhecimento de entidades:\nentities \u0026lt;- spacy_extract_entity(data) Filtrar apenas entidades cujo tipo são pessoas ou organizações:\nfiltered_entities \u0026lt;- entities %\u0026gt;% filter(ent_type==\u0026#39;ORG\u0026#39;| ent_type==\u0026#39;PER\u0026#39;) Preparar dados Precisamos criar uma lista de arestas:\nedges \u0026lt;- filtered_entities %\u0026gt;% group_by(doc_id) %\u0026gt;% summarise(entities = paste(text, collapse = \u0026quot;,\u0026quot;)) %\u0026gt;% pull(entities) %\u0026gt;% str_split(\u0026quot;,\u0026quot;) %\u0026gt;% map(~unique(unlist(.x))) %\u0026gt;% .[map_dbl(., length) != 1] Agora criaremos a matriz de adjacências, que envolvem todas as combinações 2 a 2 das entidades detectadas em cada notícia:\nadjacent_matrix \u0026lt;- map_dfr(edges, ~ as.data.frame(get_adjacent_list(.x))) %\u0026gt;% as_tibble() %\u0026gt;% set_names(c(\u0026#39;item1\u0026#39;, \u0026#39;item2\u0026#39;)) Aplicaremos algum tratamento para padronizar as entidades, reter apenas combinações que aconteceram pelo menos 3 vezes e remover algum resíduo que veio no processo de NER:\n# Padronizar entidades adjacent_matrix \u0026lt;- adjacent_matrix %\u0026gt;% mutate_all(~.x %\u0026gt;% str_replace_all(\u0026quot;Fundação Getulio Vargas\u0026quot;, \u0026quot;FGV\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;FMI\u0026quot;, \u0026quot;Fundo Monetário Internacional\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;Paulo Guedes\u0026quot;, \u0026quot;Guedes\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;Estados Unidos( da Am[ée]rica)?\u0026quot;, \u0026quot;EUA\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;Donald Trump\u0026quot;, \u0026quot;Trump\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;CEF\u0026quot;, \u0026quot;Caixa Econômica Federal\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;CMN\u0026quot;, \u0026quot;Conselho Monetário Nacional\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;Cl[áa]udio Considera\u0026quot;, \u0026quot;Cláudio\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;OCDE\u0026quot;, \u0026quot;Organização para a Cooperação e Desenvolvimento Econômico\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;(André )?Brandão\u0026quot;, \u0026quot;André Brandão\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;(Maur[ií]cio )?Macri\u0026quot;, \u0026quot;Mauricio Macri\u0026quot;) %\u0026gt;% str_remove_all(\u0026quot;^(?i)(no|de)\\\\s\u0026quot;) ) # remover residuos { entities_to_drop \u0026lt;- c(\u0026quot;Assine\u0026quot;, \u0026quot;Google Podcasts\u0026quot;, \u0026quot;Spotify\u0026quot;, \u0026quot;Focus do\u0026quot;, \u0026quot;Focus\u0026quot;, \u0026quot;Segundo\u0026quot;, \u0026quot;Ninguém\u0026quot;, \u0026quot;Haverá\u0026quot;, \u0026quot;G1\u0026quot;, \u0026quot;Começa\u0026quot;, \u0026quot;LEIA\u0026quot;, \u0026quot;R$\u0026quot;, \u0026quot;Considera\u0026quot;, \u0026quot;Caixa Aqui\u0026quot;) weighted_edgelist \u0026lt;- adjacent_matrix %\u0026gt;% filter_at(1:2, ~ !.x %in% entities_to_drop) %\u0026gt;% group_by(item1, item2) %\u0026gt;% summarise(n=n()) %\u0026gt;% ungroup() %\u0026gt;% filter(n\u0026gt;3) } Definir alguns objetos para o grafo:\n# Instanciar objeto das setas a \u0026lt;- grid::arrow(type = \u0026quot;closed\u0026quot;, length = unit(.15, \u0026quot;inches\u0026quot;)) # Definir pesos conforme numero de ocorrencias subt \u0026lt;- weighted_edgelist # Instanciar objeto dos vertices vert \u0026lt;- subt %\u0026gt;% tidyr::gather(item, word, item1, item2) %\u0026gt;% group_by(word) %\u0026gt;% summarise(n = sum(n)) # Obter componentes para colorir os clusters do grafo tidy_graph_components \u0026lt;- subt %\u0026gt;% select(item1, item2) %\u0026gt;% as.matrix() %\u0026gt;% graph.edgelist(directed = FALSE) %\u0026gt;% as_tbl_graph() %\u0026gt;% activate(\u0026quot;edges\u0026quot;) %\u0026gt;% # definir pesos como numero de ocorrencias mutate(weight = subt$n) %\u0026gt;% activate(\u0026quot;nodes\u0026quot;) %\u0026gt;% # obter clusters: mutate(component = as.factor(tidygraph::group_edge_betweenness())) # outros tipos de agrupamentos: # tidygraph.data-imaginist.com/reference/group_graph.html # Atualizar vertice para incluir grupos vert \u0026lt;- vert %\u0026gt;% left_join( as.data.frame(activate(tidy_graph_components, \u0026quot;nodes\u0026quot;)) %\u0026gt;% rename(word = name)) Finalmente, vamos criar o grafo utilizando ggplot2:\nset.seed(1) subt %\u0026gt;% graph_from_data_frame(vertices = vert) %\u0026gt;% # https://www.data-imaginist.com/2017/ggraph-introduction-layouts/ # layouts ggraph(layout = \u0026quot;fr\u0026quot;) + geom_edge_link(aes(edge_alpha = n, edge_width = n), show.legend = FALSE, arrow = a, end_cap = circle(.07, \u0026#39;inches\u0026#39;), color = \u0026quot;#D9D9D9A0\u0026quot;) + geom_node_point() + geom_node_text(aes(label = name, size = n, alpha = n, color = component),# color = \u0026quot;#EAFF00\u0026quot;, repel = TRUE, point.padding = unit(0.2, \u0026quot;lines\u0026quot;), show.legend = F) + scale_size(range = c(2,10)) + scale_alpha(range = c(0.5,1))+ theme_dark() + theme( panel.background = element_rect(fill = \u0026quot;#2D2D2D\u0026quot;), legend.key = element_rect(fill = \u0026quot;#2D2D2D\u0026quot;) ) + theme_graph(background = \u0026quot;black\u0026quot;) 📌 Interpretação\nEste grafo resume algumas informações interessantes sobre como o cenário da economia no brasil estava no dia 30 de novembro de 2021. Vejamos alguns pontos relevantes que podem ser envontrados no cenário atual:\n☞ Bolsa familia\nO Auxílio Brasil é referido como o “Novo Bolsa Família” pelos jornais e por isso deve ter sido criada tal relação no Grafo. Já a Caixa Econômica Federal é o agente que executa os pagamentos.\n☞ Guedes\nPaulo Guedes é nosso atual ministro da economia e envolta de seu nome aparecem diversos assuntos que estão em pauta atualmente como a PEC dos precatórios, (a privatização da) Petrobrás, Copom, IPCA, Auxílio Brasil dentre outros.\n☞ Fundo Monetário Internacional\nO FMI trabalha para melhorar as economias dos países e além da Argentina estar endividada e em acordo com o FMI, é época de eleição, o que explica haver alguns personagens de sua política relacionados.\nSalvar localmente em alta resolução:\nggsave(filename = \u0026#39;grafo.png\u0026#39;, width = 8, height = 6, device=\u0026#39;png\u0026#39;, dpi=700) O legal de salvar em alta resolução é poder dar zoom e navegar pelo grafo!\nBônus Antes de criar este post trabalhei em um outro grafo com banco de dados de aproximadamente 27GB de tweets coletados e fornecidos gentilmente pelo Janderson Toth (Para quem não o conheçe, recomendo fortemente segui-lo no linkedin pois ele tem compartilhado uma série de posts com insights obtidos destes dados!)\nPara quem tiver interesse, o código está disponível no github!\nConclusão Convenhamos que, de fato, criar um grafo no R não é uma tarefa super simples. No Gelphi é possível criar grafos até mais bonitos que este, porém, no longo prazo, ganhamos em produtividade e em escalabilidade pois poderíamos reaproveitar muito código e tranquilamente desenvolver uma rotina para criar novos grafos a partir de dados streaming, por exemplo, automatizando todo o processo!\nPara ver essa abordagem de text mining aplicada em um dashboard interativo, confira o Dashboard de Text Mining de Mídias Sociais e o App de Wordcloud, dois projetos em R construídos com técnicas similares de NLP e análise de texto.\nGrafos também são muito úteis em análise de texto — veja como foram usados em conjunto com análise de sentimentos no contexto Brasil x Argentina.\nOutras bibliotecas para construção de grafos Depois de conversar com algumas pessoas que leram o post, achei que merecia um update com mais idéias de mais bibliotecas que poderiam ter sido utilizadas:\ncheddar bipartite ggbipart diagrameR visNetwork Perguntas frequentes É possível criar grafos bonitos em R?\nSim. O post mostra que é possível construir grafos elaborados em R usando igraph, tidygraph e ggraph, embora exija mais esforço do que ferramentas como o Gephi.\nQuais pacotes de R foram usados para construir o grafo?\nForam usados rvest para web scraping, spacyr para NER, e igraph, tidygraph e ggraph para montar e plotar o grafo.\nDe onde vieram os dados usados no grafo?\nOs dados foram coletados via web scraping de notícias de economia do site G1 - Globo, processados com reconhecimento de entidades para identificar pessoas e organizações citadas.\n","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/post/2021-12-03-grafos-em-r/","section":"Posts","summary":" Introdução e contexto O que são Grafos? Como contruir um? Carregar dependências Fonte dos dados NER - Named Entity Recognition Preparar dados Bônus Conclusão Outras bibliotecas para construção de grafos Introdução e contexto Durante os anos de 2020 e 2021 fiz um MBA Executivo em Business Analytics e Big Data na FGV e uma das disciplinas que gostei bastante abordou a análise de mídias sociais com técnicas de mineração de texto e processamento de linguagem natural.\n","title":"Vou te provar que da para fazer Grafos bonitos em R!","type":"post"},{"content":"","date":"3 de dezembro de 2021","externalUrl":null,"permalink":"/tags/web-scraping/","section":"Tags","summary":"","title":"Web-Scraping","type":"tags"},{"content":"","date":"1 de novembro de 2021","externalUrl":null,"permalink":"/tags/knn/","section":"Tags","summary":"","title":"Knn","type":"tags"},{"content":"","date":"1 de novembro de 2021","externalUrl":null,"permalink":"/tags/optuna/","section":"Tags","summary":"","title":"Optuna","type":"tags"},{"content":"","date":"1 de novembro de 2021","externalUrl":null,"permalink":"/tags/shap/","section":"Tags","summary":"","title":"Shap","type":"tags"},{"content":" Introdução Definição do problema de negócio Análise Exploratória (em R) Machine Learning (em Python) Importar dependências Stage 0: Feature Extraction com KNN Stage 1: Tuning XGBoost com Optuna Stage 2: Calcular Out-Of-Fold SHAP values Stage 3: Modelo Final com AutoGluon Conclusão Referências Introdução Em Agosto e 2021 a Porto Seguro lançou um desafio no Kaggle que consistia em estimar a propensão de aquisição de novos produtos. Tratava-se de um problema de classificação e foi bem desafiador principalmente por 2 motivos:\nTodas as features da base de ddos eram anonimas; A métrica de avaliação foi a F1 Score (sensível à um ponto de corte) Via Giphy Depois de 2 longos meses e dezenas de notebooks desenvolvidos, muitas submissões frustradas e muitas horas a menos de sono, cheguei em uma solução final que envole um blending de modelos e pseudo-labels e quando a competição acabou, percebi que uma solução mais simples de implementar teria um resultado privado ainda maior do que o notebook que selecionei. 😅\n⚠️ Atenção!\nNeste post abordarei uma solução mais simples e eficiente mas caso tenha interesse em conferir a solução final completa (um grande frankstein), já está publica la no github.\nEste notebook é uma reescritura do meu notebook publicado no Kaggle em linguagem Python. Para quem acompanha meus posts de R pode achar meio estranho este notebook mas convido-o a tentar entender a solução pois foi desenvolvida pela perspectiva de um usuário nativo de R.\nTL;DR\nO post apresenta a solução que ficou em 3º lugar no Porto Seguro Data Challenge, competição de classificação hospedada no Kaggle. O pipeline combina feature extraction com KNN, tuning de XGBoost via Optuna, SHAP values out-of-fold e um modelo final com AutoGluon. A métrica de avaliação foi o F1 Score, o que exigiu calcular o ponto de corte ótimo para converter probabilidades em classes. Espero que gostem! 🤘\nDefinição do problema de negócio Segundo a descrição da competição:\nVocê provavelmente já recebeu uma ligação de telemarketing oferecendo um produto que você não precisa. Essa situação de estresse é minimizada quando você oferece um produto que o cliente realmente precisa. Nessa competição você será desafiado a construir um modelo que prediz a probabilidade de aquisição de um produto.\nSobre a métrica de avaliação:\nO critério utilizado para definição da melhor solução será o F1-Score, veja sua formula:\n\\[ F_1 = 2 \\times \\frac{precision \\times recall}{precision + recall} \\]\nNote que tanto a Precision quanto a Recall precisam de um ponto de corte para obter as classes e por isso busquei otmizar as métricas ROC-AUC e Log Loss para obter estimativas de probabilidades com qualidade para finalmente calcular os pontos de corte que maximizam a F1.\nAnálise Exploratória (em R) Antes de partir para modelagem fiz uma análise exploratória utilizando a linguagem R. Neste post tratarei de maneira bem breve e quem tiver interesse em conferir mais detalhes bem como os códigos dos gráficos basta acessar o notebook que deixei aberto no Kaggle.\nVeja alguns gráficos:\n📌 Interpretação: Categóricas: Qualitativo nominal: Possuem muitas classes, poderia ser o nome do produto, região, um texto o que torna o desafio ainda maior para criar novas features; Qualitativo ordinal: Basicamente deixei como veio pois já tava como numerico; Numéricas: Quantitativo continua: Todas estão normalizadas (0, 1), algumas são bimodais, algumas assimétricas a direita (pode ser tempo ate alguma coisa); Quantitativo discreto: Sem muito o que fazer, observação apenas a feature var52 que parece idade Dados missing: Parece haver algum padrão na maneira como os dados missing ocorrem e tentei substituir os -999 por NaN, imputar a média, a mediana e via outros modelos Não achei que seria muito produtivo ficar adivinhando o que poderia ser cada feature pois praticamente todos as transformações e novas features que gerei não superavam o resultado do modelo ajustado nos dados da maneira que vinham portanto procurei investir mais tempo na modelagem mesmo.\nMachine Learning (em Python) Veja a estratégia de modelagem de maneira visual:\nImportar dependências Carregar pacotes do Python\n# general packages import pandas as pd import numpy as np import time # knn features from gokinjo import knn_kfold_extract from gokinjo import knn_extract # ml tools from sklearn.model_selection import StratifiedKFold, KFold from sklearn.metrics import f1_score, log_loss, roc_auc_score # models from catboost import CatBoostClassifier from xgboost import XGBClassifier # optimization import optuna # interpretable ml import shap # automl from autogluon.tabular import TabularPredictor # ignore specific warnings import warnings warnings.filterwarnings(\u0026quot;ignore\u0026quot;, message=\u0026quot;ntree_limit is deprecated, use `iteration_range` or model slicing instead.\u0026quot;) Definir funções auxiliares para calcular o ponto de corte que maximiza a F1:\ndef get_threshold(y_true, y_pred): thresholds = np.arange(0.0, 1.0, 0.01) f1_scores = [] for thresh in thresholds: f1_scores.append( f1_score(y_true, [1 if m\u0026gt;thresh else 0 for m in y_pred])) f1s = np.array(f1_scores) return thresholds[f1s.argmax()] def custom_f1(y_true, y_pred): max_f1_threshold = get_threshold(y_true, y_pred) y_pred = np.where(y_pred\u0026gt;max_f1_threshold, 1, 0) return f1_score(y_true, y_pred) Carregar dados da competição:\n# load data train = pd.read_csv(\u0026#39;../input/porto-seguro-data-challenge/train.csv\u0026#39;).drop(\u0026#39;id\u0026#39;, axis=1) test = pd.read_csv(\u0026#39;../input/porto-seguro-data-challenge/test.csv\u0026#39;).drop(\u0026#39;id\u0026#39;, axis=1) sample_submission = pd.read_csv(\u0026#39;../input/porto-seguro-data-challenge/submission_sample.csv\u0026#39;) meta = pd.read_csv(\u0026#39;../input/porto-seguro-data-challenge/metadata.csv\u0026#39;) # get data types cat_nom = [x for x in meta.iloc[1:-1, :].loc[(meta.iloc[:,1]==\u0026quot;Qualitativo nominal\u0026quot;)].iloc[:,0]] cat_ord = [x for x in meta.iloc[1:-1, :].loc[(meta.iloc[:,1]==\u0026quot;Qualitativo ordinal\u0026quot;)].iloc[:,0]] num_dis = [x for x in meta.iloc[1:-1, :].loc[(meta.iloc[:,1]==\u0026quot;Quantitativo discreto\u0026quot;)].iloc[:,0]] num_con = [x for x in meta.iloc[1:-1, :].loc[(meta.iloc[:,1]==\u0026quot;Quantitativo continua\u0026quot;)].iloc[:,0]] Stage 0: Feature Extraction com KNN Esta técnica gera \\(k \\times c\\) novas features, onde \\(c\\) é o número de classes da target. As novas features são calculadas a partir das distâncias entre as observações e seus k vizinhos mais próximos dentro de cada classe;\nO valor para os \\(K\\) vizinhos mais próximos selecionado foi \\(K=1\\) e para isso utilizei a biblioteca gokinjo que foi inspirada nas idéias apresentadas na solução vencedora do Otto Group Product Classification Challenge.\n# convert to numpy because gokinjo expects np arrays X = train[cat_nom+cat_ord+num_dis+num_con].to_numpy() y = train.y.to_numpy() X_test = test[cat_nom+cat_ord+num_dis+num_con].to_numpy() # extract on train data KNN_feat_train = knn_kfold_extract(X, y, k=1, normalize=\u0026#39;standard\u0026#39;) print(\u0026quot;KNN features for training set, shape: \u0026quot;, np.shape(KNN_feat_train)) # extract on test data KNN_feat_test = knn_extract(X, y, X_test, k=1, normalize=\u0026#39;standard\u0026#39;) print(\u0026quot;KNN features for test set, shape: \u0026quot;, np.shape(KNN_feat_test)) # convert to dataframe knn_feat_train = pd.DataFrame(KNN_feat_train, columns=[\u0026quot;knn\u0026quot;+str(x) for x in range(knn_feat_train.shape[1])]) knn_feat_test = pd.DataFrame(KNN_feat_test, columns=[\u0026quot;knn\u0026quot;+str(x) for x in range(knn_feat_test.shape[1])]) ## KNN features for training set, shape: (14123, 2) ## KNN features for test set, shape: (21183, 2) Stage 1: Tuning XGBoost com Optuna Testei e otimizei muitos modelos como XGBoost, NGBoost, LightGBM, CatBoost, TabNet, HistGradientBoosting e algumas DNNs e em todos os casos (exceto DNNs) utilizei o Optuna para a seleção dos hiperparâmetros.\nTambém inclui nas tentativas iniciais de otimização alguns métodos de remostrarem como Random Under Sampling, Smote, Tomek, Adasyn dentre outros mas não tive muito sucesso.. apenas a combinação Tomek + CatBoost pareceu trazer algum ganho.\nClaro que minhas tentativas não foram exautivas e devido ao tempo limitado acabei selecionando o XGBoost que foi o que apresentou as melhores métricas depois de otimizado e também o CatBoost com alguns hiperparâmetros fixos para serem a base deste pipeline.\nPrincipais Informações 📌 :\nNenhum pré-processamento; KFold K=10; Otimização de hiperparâmetros com Optuna; Loss do XGBoost: Log Loss; Loss do Otimizador: Log Loss; Sem resampling; Previsão final com a probabilidade média de 10 seeds diferentes X_test = test[cat_nom+cat_ord+num_dis+num_con] X = train[cat_nom+cat_ord+num_dis+num_con] y = train.y K=10 SEED=314 kf = KFold(n_splits=K, random_state=SEED, shuffle=True) fixed_params = { \u0026#39;random_state\u0026#39;: 9, \u0026quot;objective\u0026quot;: \u0026quot;binary:logistic\u0026quot;, \u0026quot;eval_metric\u0026quot;: \u0026#39;logloss\u0026#39;, \u0026#39;use_label_encoder\u0026#39;:False, \u0026#39;n_estimators\u0026#39;:10000, } def objective(trial): hyperparams = { \u0026#39;clf\u0026#39;:{ \u0026quot;booster\u0026quot;: trial.suggest_categorical(\u0026quot;booster\u0026quot;, [\u0026quot;gbtree\u0026quot;]), \u0026quot;lambda\u0026quot;: trial.suggest_float(\u0026quot;lambda\u0026quot;, 1e-8, 5.0, log=True), \u0026quot;alpha\u0026quot;: trial.suggest_float(\u0026quot;alpha\u0026quot;, 1e-8, 5.0, log=True) } } if hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;booster\u0026quot;] == \u0026quot;gbtree\u0026quot; or hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;booster\u0026quot;] == \u0026quot;dart\u0026quot;: hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;max_depth\u0026quot;] = trial.suggest_int(\u0026quot;max_depth\u0026quot;, 1, 9) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;eta\u0026quot;] = trial.suggest_float(\u0026quot;eta\u0026quot;, 0.01, 0.1, log=True) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;gamma\u0026quot;] = trial.suggest_float(\u0026quot;gamma\u0026quot;, 1e-8, 1.0, log=True) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;grow_policy\u0026quot;] = trial.suggest_categorical(\u0026quot;grow_policy\u0026quot;, [\u0026quot;depthwise\u0026quot;, \u0026quot;lossguide\u0026quot;]) hyperparams[\u0026#39;clf\u0026#39;][\u0026#39;min_child_weight\u0026#39;] = trial.suggest_int(\u0026#39;min_child_weight\u0026#39;, 5, 20) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;subsample\u0026quot;] = trial.suggest_float(\u0026quot;subsample\u0026quot;, 0.03, 1) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;colsample_bytree\u0026quot;] = trial.suggest_float(\u0026quot;colsample_bytree\u0026quot;, 0.03, 1) hyperparams[\u0026#39;clf\u0026#39;][\u0026#39;max_delta_step\u0026#39;] = trial.suggest_float(\u0026#39;max_delta_step\u0026#39;, 0, 10) if hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;booster\u0026quot;] == \u0026quot;dart\u0026quot;: hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;sample_type\u0026quot;] = trial.suggest_categorical(\u0026quot;sample_type\u0026quot;, [\u0026quot;uniform\u0026quot;, \u0026quot;weighted\u0026quot;]) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;normalize_type\u0026quot;] = trial.suggest_categorical(\u0026quot;normalize_type\u0026quot;, [\u0026quot;tree\u0026quot;, \u0026quot;forest\u0026quot;]) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;rate_drop\u0026quot;] = trial.suggest_float(\u0026quot;rate_drop\u0026quot;, 1e-8, 1.0, log=True) hyperparams[\u0026#39;clf\u0026#39;][\u0026quot;skip_drop\u0026quot;] = trial.suggest_float(\u0026quot;skip_drop\u0026quot;, 1e-8, 1.0, log=True) params = dict(**fixed_params, **hyperparams[\u0026#39;clf\u0026#39;]) xgb_oof = np.zeros(X.shape[0]) for fold, (train_idx, val_idx) in enumerate(kf.split(X=X, y=y)): X_train = X.iloc[train_idx] y_train = y.iloc[train_idx] X_val = X.iloc[val_idx] y_val = y.iloc[val_idx] model = XGBClassifier(**params) model.fit(X_train, y_train, eval_set=[(X_val, y_val)], early_stopping_rounds=150, verbose=False) xgb_oof[val_idx] = model.predict_proba(X_val)[:,1] del model return log_loss(y, xgb_oof) Como no Kaggle existe o limite de aproximadamente 8h para executar um notebook, coloquei um limite de 7.5 horas para a busca de hiperparâmetros:\nstudy_xgb = optuna.create_study(direction=\u0026#39;minimize\u0026#39;) study_xgb.optimize(objective, timeout=60*60*7.5, gc_after_trial=True) Resultados da busca:\nprint(\u0026#39;-\u0026gt; Number of finished trials: \u0026#39;, len(study_xgb.trials)) print(\u0026#39;-\u0026gt; Best trial:\u0026#39;) trial = study_xgb.best_trial print(\u0026#39;\\tValue: {}\u0026#39;.format(trial.value)) print(\u0026#39;-\u0026gt; Params: \u0026#39;) trial.params ## -\u0026gt; Number of finished trials: 197 ## -\u0026gt; Best trial: ## Value: 0.3028443879614926 ## -\u0026gt; Params: ## {\u0026#39;booster\u0026#39;: \u0026#39;gbtree\u0026#39;, ## \u0026#39;lambda\u0026#39;: 9.012384508756378e-07, ## \u0026#39;alpha\u0026#39;: 0.7472040331088792, ## \u0026#39;max_depth\u0026#39;: 5, ## \u0026#39;eta\u0026#39;: 0.01507605562231303, ## \u0026#39;gamma\u0026#39;: 1.0214961302342215e-08, ## \u0026#39;grow_policy\u0026#39;: \u0026#39;lossguide\u0026#39;, ## \u0026#39;min_child_weight\u0026#39;: 5, ## \u0026#39;subsample\u0026#39;: 0.9331005225916879, ## \u0026#39;colsample_bytree\u0026#39;: 0.25392142363325004, ## \u0026#39;max_delta_step\u0026#39;: 5.685109389498008} Acompanhar o histórico de cada etapa da otimização:\nplot_optimization_history(study_xgb) Avaliar as combinações de hiperparâmetros mais bem sucedidas:\noptuna.visualization.plot_parallel_coordinate(study_xgb) Quais hiperparâmetros tiveram mais impacto na modelagem:\nplot_param_importances(study_xgb) Após as 7.5 horas de busca, a melhor combinação encontrada para o XGBoost foi a seguinte:\n# After 7.5 hours... study_xgb = {\u0026#39;booster\u0026#39;: \u0026#39;gbtree\u0026#39;, \u0026#39;lambda\u0026#39;: 9.012384508756378e-07, \u0026#39;alpha\u0026#39;: 0.7472040331088792, \u0026#39;max_depth\u0026#39;: 5, \u0026#39;eta\u0026#39;: 0.01507605562231303, \u0026#39;gamma\u0026#39;: 1.0214961302342215e-08, \u0026#39;grow_policy\u0026#39;: \u0026#39;lossguide\u0026#39;, \u0026#39;min_child_weight\u0026#39;: 5, \u0026#39;subsample\u0026#39;: 0.9331005225916879, \u0026#39;colsample_bytree\u0026#39;: 0.25392142363325004, \u0026#39;max_delta_step\u0026#39;: 5.685109389498008} Preparar lista de hiperparâmetros do XGBoost:\nfinal_params_xgb = dict() final_params_xgb[\u0026#39;clf\u0026#39;]=dict(**fixed_params, **study_xgb) Stage 2: Calcular Out-Of-Fold SHAP values Após obter a melhor combinação de hiperparâmetros para o XGBoost e encontrar resultados formidáveis com o CatBoost modificando apenas alguns hiperparâmetros, resolvi tentar utilizar a informação adquirida pelo SHAP values desses modelos como entrada para novos modelos.\nSe SHAP ainda parece uma caixa preta, o Interpretable Machine Learning, do Christoph Molnar, explica tanto SHAP quanto LIME e PDP com bastante clareza (e está disponível de graça online também).\nAlgumas vantagens de se usar o shap values como um método de encoder dos dados, segundo este notebook publicado no Kaggle (muito interessante por sinal):\nNormaliza os dados; Mais ou menos Linearizado pois as features são transformadas em suas importâncias; Recursos categóricos codificados de maneira mais inteligente (A codificação não é linear e depende de outros recursos da amostra); Tratamento mais inteligente para valores missing. Para evitar data leak, o SHAP values foi calculado em cima dos dados out-of-fold para os dados de treino e a média da previsão de todos os fold nos dados de teste.\nDefinir estratégia de validação cruzada:\nX_test = test[cat_nom+cat_ord+num_dis+num_con] X = train[cat_nom+cat_ord+num_dis+num_con] y = train.y K=15 # number of bins with Sturge’s rule SEED=123 kf = StratifiedKFold(n_splits=K, random_state=SEED, shuffle=True) XGBoost Obter out-of-fold SHAP do modelo XGBoost tunado:\nshap1_oof = np.zeros((X.shape[0], X.shape[1])) shap1_test = np.zeros((X_test.shape[0], X_test.shape[1])) model_shap1_oof = np.zeros(X.shape[0]) for fold, (train_idx, val_idx) in enumerate(kf.split(X=X, y=y)): print(f\u0026quot;➜ FOLD :{fold}\u0026quot;) X_train = X.iloc[train_idx] y_train = y.iloc[train_idx] X_val = X.iloc[val_idx] y_val = y.iloc[val_idx] start = time.time() model = XGBClassifier(**final_params_xgb[\u0026#39;clf\u0026#39;]) model.fit(X_train, y_train, eval_set=[(X_val, y_val)], early_stopping_rounds=150, verbose=False) model_shap1_oof[val_idx] += model.predict_proba(X_val)[:,1] print(\u0026quot;Final F1 :\u0026quot;, custom_f1(y_val, model_shap1_oof[val_idx])) print(\u0026quot;Final AUC :\u0026quot;, roc_auc_score(y_val, model_shap1_oof[val_idx])) print(\u0026quot;Final LogLoss:\u0026quot;, log_loss(y_val, model_shap1_oof[val_idx])) explainer = shap.TreeExplainer(model) shap1_oof[val_idx] = explainer.shap_values(X_val) shap1_test += explainer.shap_values(X_test) / K print(f\u0026quot;elapsed: {time.time()-start:.2f} sec\\n\u0026quot;) shap1_oof = pd.DataFrame(shap1_oof, columns = [x+\u0026quot;_shap1\u0026quot; for x in X.columns]) shap1_test = pd.DataFrame(shap1_test, columns = [x+\u0026quot;_shap1\u0026quot; for x in X_test.columns]) print(\u0026quot;Final F1 :\u0026quot;, custom_f1(y, model_shap1_oof)) print(\u0026quot;Final AUC :\u0026quot;, roc_auc_score(y, model_shap1_oof)) print(\u0026quot;Final LogLoss:\u0026quot;, log_loss(y, model_shap1_oof)) ## ➜ FOLD :0 ## Final F1 : 0.7032967032967034 ## Final AUC : 0.902330627099664 ## Final LogLoss: 0.2953604946129216 ## elapsed: 62.58 sec ## ## ➜ FOLD :1 ## Final F1 : 0.6193853427895981 ## Final AUC : 0.8613101903695408 ## Final LogLoss: 0.34227429854659686 ## elapsed: 45.96 sec ## ## ➜ FOLD :2 ## Final F1 : 0.6793478260869567 ## Final AUC : 0.8945898656215007 ## Final LogLoss: 0.3085819148842589 ## elapsed: 58.84 sec ## ## ➜ FOLD :3 ## Final F1 : 0.7073791348600509 ## Final AUC : 0.9058020716685331 ## Final LogLoss: 0.2881665477053405 ## elapsed: 62.24 sec ## ## ➜ FOLD :4 ## Final F1 : 0.7239583333333334 ## Final AUC : 0.9053121500559911 ## Final LogLoss: 0.29320601468396107 ## elapsed: 93.74 sec ## ## ➜ FOLD :5 ## Final F1 : 0.7009803921568627 ## Final AUC : 0.9076567749160134 ## Final LogLoss: 0.2872539995859452 ## elapsed: 73.34 sec ## ## ➜ FOLD :6 ## Final F1 : 0.6736292428198434 ## Final AUC : 0.8822788353863381 ## Final LogLoss: 0.320014158050091 ## elapsed: 55.16 sec ## ## ➜ FOLD :7 ## Final F1 : 0.7135416666666666 ## Final AUC : 0.9016657334826428 ## Final LogLoss: 0.29617989833438774 ## elapsed: 74.49 sec ## ## ➜ FOLD :8 ## Final F1 : 0.7135135135135134 ## Final AUC : 0.8893825776158104 ## Final LogLoss: 0.29351621553572266 ## elapsed: 93.71 sec ## ## ➜ FOLD :9 ## Final F1 : 0.7391304347826086 ## Final AUC : 0.9064054944284814 ## Final LogLoss: 0.28033187155768635 ## elapsed: 95.65 sec ## ## ➜ FOLD :10 ## Final F1 : 0.684863523573201 ## Final AUC : 0.9031046324199313 ## Final LogLoss: 0.29823173886367804 ## elapsed: 64.70 sec ## ## ➜ FOLD :11 ## Final F1 : 0.704225352112676 ## Final AUC : 0.8882052000840984 ## Final LogLoss: 0.30525241732057884 ## elapsed: 50.06 sec ## ## ➜ FOLD :12 ## Final F1 : 0.6666666666666666 ## Final AUC : 0.8905529469479291 ## Final LogLoss: 0.313654842143217 ## elapsed: 78.45 sec ## ## ➜ FOLD :13 ## Final F1 : 0.6500000000000001 ## Final AUC : 0.8745111780783517 ## Final LogLoss: 0.3300786509821235 ## elapsed: 59.54 sec ## ## ➜ FOLD :14 ## Final F1 : 0.7135416666666666 ## Final AUC : 0.9063284042329526 ## Final LogLoss: 0.29314716930177404 ## elapsed: 70.28 sec ## ## Final F1 : 0.6822461331540014 ## Final AUC : 0.8945288307257988 ## Final LogLoss: 0.30301717097927483 CatBoost Obter out-of-fold SHAP do modelo CatBoost + features extratídas via KNN:\nX = pd.concat([X, knn_feat_train], axis=1) X_test = pd.concat([X_test, knn_feat_test], axis=1) shap2_oof = np.zeros((X.shape[0], X.shape[1])) shap2_test = np.zeros((X_test.shape[0], X_test.shape[1])) model_shap2_oof = np.zeros(X.shape[0]) for fold, (train_idx, val_idx) in enumerate(kf.split(X=X, y=y)): print(f\u0026quot;➜ FOLD :{fold}\u0026quot;) X_train = X.iloc[train_idx] y_train = y.iloc[train_idx] X_val = X.iloc[val_idx] y_val = y.iloc[val_idx] start = time.time() model = CatBoostClassifier(random_seed=SEED, verbose = 0, n_estimators=10000, loss_function= \u0026#39;Logloss\u0026#39;, use_best_model=True, eval_metric= \u0026#39;Logloss\u0026#39;) model.fit(X_train, y_train, eval_set = [(X_val,y_val)], early_stopping_rounds = 100, verbose = False) model_shap2_oof[val_idx] += model.predict_proba(X_val)[:,1] print(\u0026quot;Final F1 :\u0026quot;, custom_f1(y_val, model_shap2_oof[val_idx])) print(\u0026quot;Final AUC :\u0026quot;, roc_auc_score(y_val, model_shap2_oof[val_idx])) print(\u0026quot;Final LogLoss:\u0026quot;, log_loss(y_val, model_shap2_oof[val_idx])) explainer = shap.TreeExplainer(model) shap2_oof[val_idx] = explainer.shap_values(X_val) shap2_test += explainer.shap_values(X_test) / K print(f\u0026quot;elapsed: {time.time()-start:.2f} sec\\n\u0026quot;) shap2_oof = pd.DataFrame(shap2_oof, columns = [x+\u0026quot;_shap\u0026quot; for x in X.columns]) shap2_test = pd.DataFrame(shap2_test, columns = [x+\u0026quot;_shap\u0026quot; for x in X_test.columns]) print(\u0026quot;Final F1 :\u0026quot;, custom_f1(y, model_shap2_oof)) print(\u0026quot;Final AUC :\u0026quot;, roc_auc_score(y, model_shap2_oof)) print(\u0026quot;Final LogLoss:\u0026quot;, log_loss(y, model_shap2_oof)) ## ➜ FOLD :0 ## Final F1 : 0.6972010178117048 ## Final AUC : 0.8954157334826428 ## Final LogLoss: 0.29952314366911725 ## elapsed: 22.84 sec ## ## ➜ FOLD :1 ## Final F1 : 0.6348448687350835 ## Final AUC : 0.8628429451287795 ## Final LogLoss: 0.3407490151943705 ## elapsed: 12.59 sec ## ## ➜ FOLD :2 ## Final F1 : 0.6809651474530831 ## Final AUC : 0.8949538073908175 ## Final LogLoss: 0.3066089330852162 ## elapsed: 18.03 sec ## ## ➜ FOLD :3 ## Final F1 : 0.702247191011236 ## Final AUC : 0.9107992721164613 ## Final LogLoss: 0.2877216893570601 ## elapsed: 15.66 sec ## ## ➜ FOLD :4 ## Final F1 : 0.7131367292225201 ## Final AUC : 0.9018687010078387 ## Final LogLoss: 0.2976481761596595 ## elapsed: 29.35 sec ## ## ➜ FOLD :5 ## Final F1 : 0.7055837563451777 ## Final AUC : 0.909231522956327 ## Final LogLoss: 0.28834373773423566 ## elapsed: 15.35 sec ## ## ➜ FOLD :6 ## Final F1 : 0.6631578947368421 ## Final AUC : 0.8796402575587906 ## Final LogLoss: 0.32303153676573987 ## elapsed: 19.13 sec ## ## ➜ FOLD :7 ## Final F1 : 0.6997389033942559 ## Final AUC : 0.901637737961926 ## Final LogLoss: 0.2985978485411335 ## elapsed: 23.30 sec ## ## ➜ FOLD :8 ## Final F1 : 0.6965699208443271 ## Final AUC : 0.8825565912117177 ## Final LogLoss: 0.3009859242847037 ## elapsed: 20.19 sec ## ## ➜ FOLD :9 ## Final F1 : 0.7435897435897436 ## Final AUC : 0.9042469689536757 ## Final LogLoss: 0.28276851015512977 ## elapsed: 24.39 sec ## ## ➜ FOLD :10 ## Final F1 : 0.6767676767676767 ## Final AUC : 0.902712173242694 ## Final LogLoss: 0.29999812838692497 ## elapsed: 16.14 sec ## ## ➜ FOLD :11 ## Final F1 : 0.7013698630136986 ## Final AUC : 0.8865022075828719 ## Final LogLoss: 0.3081393413008847 ## elapsed: 13.50 sec ## ## ➜ FOLD :12 ## Final F1 : 0.6630434782608696 ## Final AUC : 0.8920456934613498 ## Final LogLoss: 0.31338640296724246 ## elapsed: 24.48 sec ## ## ➜ FOLD :13 ## Final F1 : 0.6485148514851485 ## Final AUC : 0.8689887167986544 ## Final LogLoss: 0.3369797070301582 ## elapsed: 17.17 sec ## ## ➜ FOLD :14 ## Final F1 : 0.7108753315649867 ## Final AUC : 0.8994743850304856 ## Final LogLoss: 0.301420230674656 ## elapsed: 16.51 sec ## ## Final F1 : 0.6823234134098244 ## Final AUC : 0.892656043550729 ## Final LogLoss: 0.305726567456891 train = pd.concat([train, shap1_oof], axis=1) test = pd.concat([test, shap1_test], axis=1) train = pd.concat([train, shap2_oof], axis=1) test = pd.concat([test, shap2_test], axis=1) Stage 3: Modelo Final com AutoGluon AutoGluon é um AutoML desenvolvido pela Amazon muito fácil de utilizar (no melhor estilo sklearn com métodos .fit() e .predict()).\nPrincipais Informações 📌 :\nInputs: Dataset original + knn features + Shapt values do XGBoost tunado e do CatBoost; Loss do XGBoost: Log Loss; Loss do CatBoost: AUC; Loss do AutoGluon: Log Loss; Tempo de processamento: 7h30m 💡 Insight Um recurso muito útil do AutoGluon é poder acessar as previsões out-of-folds, o que facilita no cálculo do threshold que maximiza a F1 Score.\npredictor = TabularPredictor(label=\u0026quot;y\u0026quot;, problem_type=\u0026#39;binary\u0026#39;, eval_metric=\u0026quot;log_loss\u0026quot;, path=\u0026#39;./AutoGlon/\u0026#39;, verbosity=1) predictor.fit(train, presets=\u0026#39;best_quality\u0026#39;, time_limit=60*60*7.5) results = predictor.fit_summary() ## *** Summary of fit() *** ## Estimated performance of each model: ## model score_val pred_time_val fit_time pred_time_val_marginal fit_time_marginal stack_level can_infer fit_order ## 0 WeightedEnsemble_L2 -0.299310 30.410467 8888.826963 0.001654 2.456810 2 True 14 ## 1 CatBoost_BAG_L1 -0.301038 3.051793 2376.887100 3.051793 2376.887100 1 True 7 ## 2 WeightedEnsemble_L3 -0.301722 194.034947 22907.669139 0.001541 2.008858 3 True 26 ## 3 LightGBMXT_BAG_L2 -0.302135 131.534432 17201.299530 1.378576 389.400378 2 True 15 ## 4 LightGBMXT_BAG_L1 -0.302562 3.570399 969.385833 3.570399 969.385833 1 True 3 ## 5 CatBoost_BAG_L2 -0.302646 131.912474 17619.939451 1.756617 808.040299 2 True 19 ## 6 LightGBM_BAG_L2 -0.303002 131.422007 17281.518763 1.266150 469.619612 2 True 16 ## 7 LightGBM_BAG_L1 -0.303264 2.964433 1038.037160 2.964433 1038.037160 1 True 4 ## 8 XGBoost_BAG_L1 -0.303471 4.475003 2036.551052 4.475003 2036.551052 1 True 11 ## 9 NeuralNetFastAI_BAG_L1 -0.304455 19.917584 3434.894841 19.917584 3434.894841 1 True 10 ## 10 XGBoost_BAG_L2 -0.304499 132.757505 17834.135370 2.601648 1022.236218 2 True 23 ## 11 NeuralNetFastAI_BAG_L2 -0.306339 142.018741 18777.287244 11.862885 1965.388093 2 True 22 ## 12 LightGBMLarge_BAG_L2 -0.306606 131.701429 18260.504603 1.545573 1448.605452 2 True 25 ## 13 NeuralNetMXNet_BAG_L2 -0.308237 177.769179 19273.211899 47.613322 2461.312748 2 True 24 ## 14 LightGBMLarge_BAG_L1 -0.309686 3.042399 2629.185346 3.042399 2629.185346 1 True 13 ## 15 ExtraTreesEntr_BAG_L2 -0.314045 132.017535 16815.886061 1.861679 3.986910 2 True 21 ## 16 RandomForestEntr_BAG_L2 -0.314454 132.061970 16843.769642 1.906114 31.870490 2 True 18 ## 17 ExtraTreesGini_BAG_L2 -0.314960 132.123651 16816.087081 1.967794 4.187930 2 True 20 ## 18 NeuralNetMXNet_BAG_L1 -0.317156 81.677096 4258.886806 81.677096 4258.886806 1 True 12 ## 19 RandomForestGini_BAG_L2 -0.321702 132.035970 16835.326491 1.880114 23.427339 2 True 17 ## 20 ExtraTreesEntr_BAG_L1 -0.323283 1.794093 4.051307 1.794093 4.051307 1 True 9 ## 21 RandomForestEntr_BAG_L1 -0.324296 1.966043 33.380685 1.966043 33.380685 1 True 6 ## 22 ExtraTreesGini_BAG_L1 -0.325897 1.796291 3.748723 1.796291 3.748723 1 True 8 ## 23 RandomForestGini_BAG_L1 -0.328218 1.778995 22.705248 1.778995 22.705248 1 True 5 ## 24 KNeighborsDist_BAG_L1 -1.070156 2.010938 2.075571 2.010938 2.075571 1 True 2 ## 25 KNeighborsUnif_BAG_L1 -1.071373 2.110790 2.109480 2.110790 2.109480 1 True 1 ## Number of models trained: 26 ## Types of models trained: ## {\u0026#39;StackerEnsembleModel_RF\u0026#39;, \u0026#39;StackerEnsembleModel_NNFastAiTabular\u0026#39;, \u0026#39;WeightedEnsembleModel\u0026#39;, \u0026#39;StackerEnsembleModel_XGBoost\u0026#39;, \u0026#39;StackerEnsembleModel_CatBoost\u0026#39;, \u0026#39;StackerEnsembleModel_KNN\u0026#39;, \u0026#39;StackerEnsembleModel_LGB\u0026#39;, \u0026#39;StackerEnsembleModel_XT\u0026#39;, \u0026#39;StackerEnsembleModel_TabularNeuralNet\u0026#39;} ## Bagging used: True (with 10 folds) ## Multi-layer stack-ensembling used: True (with 3 levels) ## Feature Metadata (Processed): ## (raw dtype, special dtypes): ## (\u0026#39;float\u0026#39;, []) : 152 | [\u0026#39;var55\u0026#39;, \u0026#39;var56\u0026#39;, \u0026#39;var57\u0026#39;, \u0026#39;var58\u0026#39;, \u0026#39;var59\u0026#39;, ...] ## (\u0026#39;int\u0026#39;, []) : 48 | [\u0026#39;var1\u0026#39;, \u0026#39;var2\u0026#39;, \u0026#39;var3\u0026#39;, \u0026#39;var4\u0026#39;, \u0026#39;var5\u0026#39;, ...] ## (\u0026#39;int\u0026#39;, [\u0026#39;bool\u0026#39;]) : 6 | [\u0026#39;var27\u0026#39;, \u0026#39;var31\u0026#39;, \u0026#39;var44\u0026#39;, \u0026#39;var49\u0026#39;, \u0026#39;var50\u0026#39;, ...] ## Plot summary of models saved to file: ./AutoGlon/SummaryOfModels.html ## *** End of fit() summary *** Nota: Os resultados podem variar devido à natureza estocástica do algoritmo ou procedimento de avaliação.\n# get final predictions y_oof = predictor.get_oof_pred_proba().iloc[:,1] y_pred = predictor.predict_proba(test).iloc[:,1] final_threshold = get_threshold(train.y, y_oof) final_threshold ## 0.31 print(\u0026quot;Final F1 :\u0026quot;, custom_f1(y, y_oof)) print(\u0026quot;Final AUC :\u0026quot;, roc_auc_score(y, y_oof)) print(\u0026quot;Final LogLoss:\u0026quot;, log_loss(y, y_oof)) ## Final F1 : 0.6846193682030037 ## Final AUC : 0.8961328807692966 ## Final LogLoss: 0.2993098559321765 Após submissão:\nConclusão Gostaria de agradecer imensamente ao time do Porto Seguro pela iniciativa, pois esse tipo de competição (tão detalhada e desafiadora) não tem sido muito comum no Brasil e é muito importante para fomentar a comunidade brasileira de ciência de dados!\nSabemos que o “mundo real” é diferente do mundo das competições (onde buscamos o melhor score a todo custo) porém, na minha visão, não deixa de ser um ótimo exercício para treinar o raciocínio analítico.. além de ser muito empolgante e divertido!\nTive o enorme prazer de trocar idéias e conhecer pessoas fora da curva bem como me tornar fã de alguns competidores! A cada semana q passava o nível estava cada vez mais alto!\nCom certeza este pipeline poderia ser muito melhor, sinto que poderia ter gasto mais tempo com feature engineering e tido mais paciencia com alguns modelos. Tentei fazer o melhor que pude com o tempo disponível e me sinto muito grato pela experiência de apresentar os resultados e aprender bastante com a solução dos top colocados.\nNão acaba por aqui! Agora é hora de voltar aos estudos, continuar praticando com as TPS’s do Kaggle e, quem sabe, ir melhor na próxima!\nPara outras competições que venci depois desta, veja a solução da ML Olympiad de saúde pública. E para lidar com dados desbalanceados como os desta competição usando o framework tidymodels, veja este post sobre otimização de pipelines com workflowsets.\nReferências https://github.com/momijiame/gokinjo https://www.kaggle.com/melanie7744/tps6-boost-your-score-with-knn-features https://www.kaggle.com/c/otto-group-product-classification-challenge/discussion/14335 https://www.kaggle.com/pavelvod/gbm-supervised-pretraining Perguntas frequentes Qual foi o resultado da equipe do autor no Porto Seguro Data Challenge?\nA solução simplificada apresentada no post ficou em 3º lugar na competição, hospedada no Kaggle pela Porto Seguro.\nQual métrica de avaliação foi usada na competição?\nFoi usado o F1 Score, que exige um ponto de corte para transformar probabilidades em classes, por isso o autor otimizou ROC-AUC e Log Loss antes de calcular esse threshold.\nQuais técnicas compõem o pipeline final de modelagem?\nO pipeline combina feature extraction com KNN (pacote gokinjo), tuning de hiperparâmetros do XGBoost com Optuna, cálculo de SHAP values out-of-fold do XGBoost e CatBoost, e um modelo final treinado com AutoGluon.\n","date":"1 de novembro de 2021","externalUrl":null,"permalink":"/post/2021-11-01-solucao-final-porto-seguro-data-challenge/","section":"Posts","summary":" Introdução Definição do problema de negócio Análise Exploratória (em R) Machine Learning (em Python) Importar dependências Stage 0: Feature Extraction com KNN Stage 1: Tuning XGBoost com Optuna Stage 2: Calcular Out-Of-Fold SHAP values Stage 3: Modelo Final com AutoGluon Conclusão Referências Introdução Em Agosto e 2021 a Porto Seguro lançou um desafio no Kaggle que consistia em estimar a propensão de aquisição de novos produtos. Tratava-se de um problema de classificação e foi bem desafiador principalmente por 2 motivos:\n","title":"Solução Final - Porto Seguro Data Challenge [3º lugar]","type":"post"},{"content":"","date":"1 de novembro de 2021","externalUrl":null,"permalink":"/tags/threshold-movel/","section":"Tags","summary":"","title":"Threshold-Movel","type":"tags"},{"content":"","date":"28 de junho de 2021","externalUrl":null,"permalink":"/tags/imbalanced-data/","section":"Tags","summary":"","title":"Imbalanced-Data","type":"tags"},{"content":" O problema envolvendo dados desbalanceados Objetivo Dependências Preparar dados Breve análise exploratória Modelagem Baselines Preparar Pipeline de dados com workflowsets Benchmark Conclusão Referências O problema envolvendo dados desbalanceados A tarefa de classificação com dados desbalanceados é muito comum na vida real podendo variar desde um leve viés até um enorme desequilíbrio na distribuição da classe de interesse. Problemas mais comuns envolvem:\nDetecção de fraude; Previsão de inadimplência; Identificador de spam; Busca por anomalias/outliers; Detecção de possíveis roubos/furtos/vulnerabilidades; Previsão de churn; etc Este tipo de tarefa representa um enorme desafio para modelagem preditiva pois a maioria dos algoritmos de machine learning foram projetados sob suposição de haver um número igual de exemplos para cada classe de interesse.\nE isso é um grande problema pois normalmente estamos interessados em prever a classe minoritária e para isso é preciso tomar uma série de decisões, como por exemplo: métrica utilizada, método para validação cruzada, adoção (ou não) do uso de métodos de reamostragem, quais algoritmos utilizar, qual será o threshold, etc\nLidar com dados desbalanceados é um assunto longo portanto tentarei dar mais atenção apenas em um hack para encontrar a melhor forma de se aplicar o balanceamento dos dados. Não pretendo me aprofundar na teoria envolvida na escolha das métricas neste post, caso o leitor deseje se aprofundar sobre a teoria envolvida com classificação que envolve dados desbalanceados, sugiro a leitura do livro: Imbalanced Classification with Python - Choose Better Metrics, Balance Skewed Classes and Apply Cost-Sensitive Learning e consultar os links de referência no final do post).\nTL;DR\nO pacote workflowsets testa várias combinações de pré-processamento (oversampling, undersampling) x modelo de uma vez. Comparado a um modelo nulo e a um modelo base sem balanceamento, nem sempre o balanceamento melhora a métrica escolhida. Tomek Links e ADASYN se saíram melhor que o SMOTE neste dataset específico. Objetivo Utilizaremos neste post o pacote workflowsets a fim de otimizar o pipeline de reamostragem da base para lidar com o desbalanceamento dos dados.\nPara efeitos de comparação, utilizarei como referência o (excelente) post escrito recentemente pela Julia Silge em seu blog que também aborda o problema de dados desbalanceados utilizando um conjunto de dados de uma competição do Kaggle. Utilizarei a mesma configuração de pré-processamento adotado em seu post para que a comparação seja justa.\nPortanto, nosso objetivo de modelagem será prever se uma colisão com animais selvagens resultou em danos a aeronave.\nQuem quiser entender o ecossistema tidymodels com mais calma, o Tidy Modeling with R, da Julia Silge com o Max Kuhn, é a referência que uso pra situar cada peça do workflow (pré-processamento, tuning, tudo).\n⚠️ Este dataset é rico em possibilidades para diferentes tipos de pré processamentos e por isso convido o leitor a analisá-lo com maior profundidade e também a compartilhar seus resultados!\nDependências Primeiro vamos carregar as bibliotecas necessárias e algumas funções desenvolvidas para o post\nlibrary(tidyverse) # ds toolkit library(tidymodels) # ml toolkit library(baguette) # bag_tree library(themis) # imbalanced library(workflowsets) # opt pipelines library(patchwork) # arrange plots doParallel::registerDoParallel() theme_set(theme_bw()) (Clique aqui para ver as funções print_table e conf_mat_plot importadas) # Para o print de tabelas print_table \u0026lt;- function(x, round=0, cv=F, wf=F, bm=F, ...){ if(round\u0026gt;0) x \u0026lt;- x %\u0026gt;% mutate_if(is.numeric, ~round(.x, round)) if(cv==T){ columns_spec = list( .metric = reactable::colDef(minWidth = 75), .estimator = reactable::colDef(minWidth = 70), .config = reactable::colDef(minWidth = 120) ) } else if(wf==T){ columns_spec = list( wflow_id = reactable::colDef(minWidth = 100), .metric = reactable::colDef(minWidth = 100), preprocessor = reactable::colDef(minWidth = 110), rank = reactable::colDef(minWidth = 50), n = reactable::colDef(minWidth = 50) ) }else if (bm==T){ columns_spec = list( wflow_id = reactable::colDef(minWidth = 130), model = reactable::colDef(minWidth = 80) ) }else{ columns_spec = NULL } reactable::reactable(x, striped = T, bordered = T, highlight = T, pagination = F, resizable = T, columns = columns_spec, ...) } # Para plot da matriz de confusao e distribuicoes de probabilidade conf_mat_plot \u0026lt;- function(x, null_model = FALSE){ p1 \u0026lt;- x %\u0026gt;% select(.pred_class, damaged) %\u0026gt;% table() %\u0026gt;% conf_mat() %\u0026gt;% autoplot(type = \u0026quot;heatmap\u0026quot;)+ labs(title = \u0026quot;Matriz de confusão\u0026quot;) p2 \u0026lt;- x %\u0026gt;% ggplot() + geom_density(aes(x = .pred_damage, fill = damaged), alpha = 0.5)+ labs(title = \u0026quot;Distribuições de probabilidade previstas\u0026quot;, subtitle = \u0026quot;por classe\u0026quot;)+ scale_x_continuous(limits = 0:1)+ scale_fill_brewer(palette=\u0026quot;Set1\u0026quot;) p1 | p2 } Em seguida vamos importar os dados provenientes da competição Inclass do Kaggle SLICED s01e02 - Predict whether an aircraft strike with wildlife causes damage. Para mais informações consulte a documentação e dicionário dos dados.\ndf \u0026lt;- read_csv(\u0026quot;train.csv\u0026quot;) Note que carregamos apenas os dados de treino pois os dados de teste não possuem a target.\nPreparar dados Tratar a variável target damaged e avaliar sua distribuição:\ndf \u0026lt;- df %\u0026gt;% mutate(damaged = if_else(damaged==1, \u0026quot;damage\u0026quot;, \u0026quot;not_damage\u0026quot;) %\u0026gt;% factor(levels = c(\u0026quot;damage\u0026quot;, \u0026quot;not_damage\u0026quot;))) (Clique aqui para ver o código do gráfico abaixo) p1 \u0026lt;- df %\u0026gt;% count(damaged) %\u0026gt;% ggplot(aes(x=rev(damaged), y=n, fill=damaged))+ geom_bar(stat = \u0026quot;identity\u0026quot;)+ scale_fill_brewer(palette=\u0026quot;Set1\u0026quot;)+ theme(legend.position = \u0026quot;bottom\u0026quot;)+ labs(y=\u0026quot;Número de instâncias\u0026quot;, x = \u0026quot;\u0026quot;) p2 \u0026lt;- df %\u0026gt;% count(damaged) %\u0026gt;% arrange(desc(damaged)) %\u0026gt;% mutate(prop = n / sum(n)) %\u0026gt;% mutate(ypos = cumsum(prop)- 0.5*prop )%\u0026gt;% ggplot(aes(x=\u0026quot;\u0026quot;, y=prop, fill=damaged)) + geom_bar(stat=\u0026quot;identity\u0026quot;, width=1) + coord_polar(\u0026quot;y\u0026quot;, start=0) + theme_void() + theme(legend.position=\u0026quot;none\u0026quot;) + geom_text(aes(y = ypos, label = paste(scales::comma(n, big.mark = \u0026quot;.\u0026quot;), scales::comma(n/sum(n), big.mark = \u0026quot;.\u0026quot;, suffix = \u0026quot;%\u0026quot; ),sep = \u0026quot;\\n\u0026quot;) ), color = \u0026quot;white\u0026quot;, size=6) + scale_fill_brewer(palette=\u0026quot;Set1\u0026quot;) p1 + p2 Veja que estamos diante de um problema que existem aproximadamente 9 casos de dano para cada 100 eventos observados.\nBreve análise exploratória Vamos iniciar a exploratória com uma avaliação geral dos dados brutos\nDataExplorer::plot_intro(df, ggtheme = theme_bw(), theme_config = list(legend.position = \u0026quot;bottom\u0026quot;)) Primeira informação que chama atenção é que quase 1/4 desses dados é faltante. Vamos olhar a estrutura dessa base de maneira mais aprofundada:\ndf %\u0026gt;% sample_frac(0.01) %\u0026gt;% visdat::vis_dat() Parece existir algum padrão nos dados faltantes (que coocorrem em diveros atributos). Além disso algumas colunas estão quase inteiramente vazias e serão descartadas no processo de modelagem.\nUma visão geral das classes das features categóricas:\ndf %\u0026gt;% select(-damaged, -id)%\u0026gt;% mutate_all(as.factor) %\u0026gt;% inspectdf::inspect_cat() %\u0026gt;% inspectdf::show_plot() Algumas features possuem muitas classes e caso seja feita a transformação one-hot-encoding (estratégia amplamente utilizada para lidar com features categóricas) sem algum cuidado, o desempenho da maioria dos modelos de machine learning pode ser prejudicado por tornar a base analítica muito esparsa.\nUma visão geral das classes das features numéricas em relação a target:\nnum_columns \u0026lt;- c(df %\u0026gt;% select_if(is.numeric) %\u0026gt;% colnames(), \u0026#39;damaged\u0026#39;) df%\u0026gt;% select_at(num_columns) %\u0026gt;% select(-id) %\u0026gt;% gather(key, value, -damaged) %\u0026gt;% ggplot(aes(y=damaged, x=value))+ geom_boxplot()+ facet_wrap(~key, ncol=5, scales = \u0026quot;free_x\u0026quot;)+ labs(x = \u0026quot;\u0026quot;, y=\u0026quot;\u0026quot;) Parece que algumas features possuem comportamentos diferentes quando avaliados segundo a target. Além disso é possível notar que as features aircraft_mass, distance, engine4_position, engines, height e speed apresentam outliers.\nModelagem Finalmente chegamos a modelagem!\nPrimeiro vamos definir um esquema de reamostragem (com estratificação) que será utilizado para avaliar os modelos e as métricas de qualidade.\nset.seed(123) bird_folds \u0026lt;- vfold_cv(df, v = 5, strata = damaged) bird_metrics \u0026lt;- metric_set(mn_log_loss, accuracy, sensitivity, specificity) Nossos conjuntos de pipelines necessitarão de um pré-processador base que será comum a todos como camada inicial. Para isso utilizaremos o mesmo definido no post de referência.\nbase_rec \u0026lt;- recipe(damaged ~ ., data = df) %\u0026gt;% step_select( damaged, flight_impact, precipitation, visibility, flight_phase, engines, incident_year, incident_month, species_id, engine_type, aircraft_model, species_quantity, height, speed) %\u0026gt;% step_novel(all_nominal_predictors()) %\u0026gt;% step_other(all_nominal_predictors(), threshold = 0.01) %\u0026gt;% step_unknown(all_nominal_predictors()) %\u0026gt;% step_impute_median(all_numeric_predictors()) %\u0026gt;% step_zv(all_predictors()) Baselines Para efeitos de comparação, vamos ajustar 2 modelos que serão utilizados como baselines para saber se a complexidade que estamos adicionando no modelo está realmente trazendo algum ganho na performance do modelo. Os modelos serão:\nModelo nulo: um modelo que sempre prevê a classe majoritária; Modelo de base: Bagged Decision Tree sem adicionar pré-processamento para compensar o desequilíbrio de classe. Modelo nulo Avaliando modelo nulo via validação cruzada:\nnull_spec \u0026lt;- null_model(mode = \u0026quot;classification\u0026quot;) %\u0026gt;% set_engine(\u0026quot;parsnip\u0026quot;) null_wf \u0026lt;- workflow() %\u0026gt;% add_recipe(base_rec) %\u0026gt;% add_model(null_spec) null_rs \u0026lt;- fit_resamples( object = null_wf, resamples = bird_folds, metrics = bird_metrics, control = control_resamples(save_pred = TRUE) ) collect_metrics(null_rs) %\u0026gt;% print_table(round = 5, cv = T) Qualquer modelo com desempenho pior do que este deve ser descartado. Vejamos a matriz de confusão:\ncollect_predictions(null_rs) %\u0026gt;% conf_mat_plot() Modelo de base Agora vamos ajusta o modelo Bagged Decision Tree sem o pré-processamento para compensar o desequilíbrio de classe:\nbag_spec \u0026lt;- bag_tree(min_n = 10) %\u0026gt;% set_engine(\u0026quot;rpart\u0026quot;, times = 25) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) imb_wf \u0026lt;- workflow() %\u0026gt;% add_recipe(base_rec) %\u0026gt;% add_model(bag_spec) set.seed(123) imb_rs \u0026lt;- fit_resamples( imb_wf, resamples = bird_folds, metrics = bird_metrics, control = control_resamples(save_pred = TRUE) ) collect_metrics(imb_rs) %\u0026gt;% print_table(round = 5, cv = T) Apesar do elevado número de falsos negativos, este modelo já esta com um desempenho razoável em comparaçãao ao modelo nulo e o número de verdadeiros positivos já é quase o dobro do número de falsos positivos. Veja na matriz de confusão abaixo:\ncollect_predictions(imb_rs) %\u0026gt;% conf_mat_plot() Preparar Pipeline de dados com workflowsets A escolha do método de amostragem dos dados é tão importante quanto a escolha do modelo preditivo que será utilizado pois o desempenho pode ser enganosamente otimista visto que o algoritmo de bagging não esta usando nenhuma estratégia de subamostragem aleatória da classe majoritária em cada amostra de bootstrap para equilibrar as duas classes.\nExistem muitos métodos para amostragem de dados e não há um método único que seja melhor em todos os problemas de classificação (assim como não existe o “melhor modelo”) portanto, utilizaremos este pacote para testar diferentes métodos e também tunar seus hiperparâmetros.\nOversampling Estes métodos duplicam ou sintetizam novos dados da classe minoritária. Deve ser usado com cautela pois na vida real pode gerar alguns dados que não condizem com a relidade ou criar tantas instâncias que acaba consumindo muito mais tempo de processamento.\nRandom Oversampling Este método simplesmente duplica aleatóriamente exemplos da classe minoritária. Vamos tunar esta proporção buscando números reais no intervalo [0.5,1].\nrec_up \u0026lt;- base_rec %\u0026gt;% step_upsample(damaged, over_ratio = tune()) params_up \u0026lt;- rec_up %\u0026gt;% parameters() %\u0026gt;% update(over_ratio = mixture(c(0.5, 1))) SMOTE - Synthetic Minority Oversampling Technique O SMOTE funciona gerando novos dados sintétios baseados em exemplos selecionando que estão “próximos”. Vamos tunar tanto a proporção de dados que serão gerados quanto a quantidade de vizinhos selecionados, buscando números reais e inteiros no intervalo [0.5,1] e [1, 10], respectivamente.\nrec_smote \u0026lt;- base_rec %\u0026gt;% step_dummy(all_nominal_predictors()) %\u0026gt;% step_smote(damaged, over_ratio = tune(), neighbors = tune()) params_smote \u0026lt;- rec_smote %\u0026gt;% parameters() %\u0026gt;% update(over_ratio = mixture(c(0.5, 1)), neighbors = neighbors()) ADASYN - Adaptive Synthetic Sampling O ADASYN é uma extensão do SMOTE que busca propor melhorias. Vamos tunar os mesmos parâmetros definidos no SMOTE.\nrec_adasyn \u0026lt;- base_rec %\u0026gt;% step_dummy(all_nominal_predictors()) %\u0026gt;% step_adasyn(damaged, over_ratio = tune(), neighbors = tune()) params_adasyn \u0026lt;- rec_adasyn %\u0026gt;% parameters() %\u0026gt;% update(over_ratio = mixture(c(0.5, 1)), neighbors = neighbors()) Undersampling São técnicas que excluem ou selecionam um subconjunto de exemplos da classe majoritária e existem dezenas (se não centenas) desses métodos. Neste post utilizaremos só 3 mas existem outros implementados em outras bibliotecas (em R e em Python).\nRandom Undersampling Este é o método mais simples e envolve a exclusão aleatória de algumas instâncias da classe majoritária. Vamos tunar esta proporção de frequências da minoritária para a majoritária.\nrec_down \u0026lt;- base_rec %\u0026gt;% step_downsample(damaged, under_ratio = tune()) params_down \u0026lt;- rec_down %\u0026gt;% parameters() %\u0026gt;% update(under_ratio = deg_free()) Near Miss Undersampling Este algoritmo se baseia em métodos de KNN selecionando exemplos da classe majoritária que tem menor distância média dos k exemplos mais próximos. Vamos tunar tanto a proporção quanto o número de vizinhos utilizados.\nrec_nearmiss \u0026lt;- base_rec %\u0026gt;% step_dummy(all_nominal_predictors()) %\u0026gt;% step_nearmiss(damaged, under_ratio = tune(), neighbors = tune()) params_nearmiss \u0026lt;- rec_nearmiss %\u0026gt;% parameters() %\u0026gt;% update(under_ratio = deg_free(), neighbors = neighbors()) Tomek Links Undersampling Este algoritmo que tenta excluir instâncias que sejam próximas e que possuam classes diferentes, buscando diminuir a ambiguidade dos dados. Não vamos tunar nenhum hiperparâmetro aqui.\nSe esse zoológico de técnicas de balanceamento (SMOTE, ADASYN, Tomek) ainda confunde um pouco, o Imbalanced Classification with Python organiza bem quando usar cada uma, mesmo que os exemplos sejam em Python.\nrec_tomek \u0026lt;- base_rec %\u0026gt;% step_dummy(all_nominal_predictors()) %\u0026gt;% step_tomek(damaged) Preparar pipeline de dados Agora que todos pipelines de dados candidatos estão definidos, vamos combinar tudo em um único objeto com workflow_set:\nchi_models \u0026lt;- workflow_set( preproc = list(upsample = rec_up, smote = rec_smote, adasyn = rec_adasyn, downsample = rec_down, nearmiss = rec_nearmiss, tomek = rec_tomek), models = list(bag_spec = bag_spec), cross = TRUE ) Utilizar a função option_add para adicionar as informações dos intervalos definidos para cada hiperparâmetro:\nchi_models \u0026lt;- chi_models %\u0026gt;% option_add(param_info = params_up, id = \u0026quot;upsample_bag_spec\u0026quot;) %\u0026gt;% option_add(param_info = params_smote, id = \u0026quot;smote_bag_spec\u0026quot;) %\u0026gt;% option_add(param_info = params_adasyn, id = \u0026quot;adasyn_bag_spec\u0026quot;) %\u0026gt;% option_add(param_info = params_down, id = \u0026quot;downsample_bag_spec\u0026quot;) %\u0026gt;% option_add(param_info = params_nearmiss, id = \u0026quot;nearmiss_bag_spec\u0026quot;) Finalmente, vamos ajustar todos os modelos utilizando o método simples para fazer a busca dos melhores hiperparâmetros em grids de 20 valores aleatórios e calcular os scores via validação cruzada (esta parte pode demorar bastante tempo):\nset.seed(123) chi_models \u0026lt;- chi_models %\u0026gt;% workflow_map(\u0026quot;tune_grid\u0026quot;, resamples = bird_folds, grid = 20, metrics = bird_metrics, control = control_resamples(save_pred = TRUE), verbose = TRUE) Vejamos os resultados:\nrank_results(chi_models, rank_metric = \u0026quot;mn_log_loss\u0026quot;, select_best = TRUE) %\u0026gt;% select(-.config) %\u0026gt;% mutate(wflow_id = str_remove(wflow_id, \u0026quot;_bag_spec\u0026quot;)) %\u0026gt;% print_table(round = 5, wf=T, height = 300, filterable = T) Matriz de confusão do modelo com menor logloss:\ncollect_predictions(chi_models) %\u0026gt;% filter(wflow_id == \u0026quot;tomek_bag_spec\u0026quot;) %\u0026gt;% conf_mat_plot() Benchmark Comparando os resultados dos modelos ajustados:\n(Clique aqui para ver o código que cria o objeto benchmark) benchmark \u0026lt;- bind_rows( mutate(collect_metrics(null_rs), wflow_id = \u0026quot;default\u0026quot;, model = \u0026quot;null_model\u0026quot;) %\u0026gt;% select(.metric, mean, wflow_id, model) %\u0026gt;% spread(.metric, mean) , mutate(collect_metrics(imb_rs), wflow_id = \u0026quot;default\u0026quot;, model = \u0026quot;bag_tree\u0026quot;) %\u0026gt;% select(.metric, mean, wflow_id, model) %\u0026gt;% spread(.metric, mean) , rank_results(chi_models, rank_metric = \u0026quot;mn_log_loss\u0026quot;, select_best = TRUE) %\u0026gt;% filter(wflow_id==\u0026quot;smote_bag_spec\u0026quot;) %\u0026gt;% select(.metric, mean, wflow_id, model) %\u0026gt;% spread(.metric, mean) , rank_results(chi_models, rank_metric = \u0026quot;mn_log_loss\u0026quot;, select_best = TRUE) %\u0026gt;% filter(rank==1) %\u0026gt;% select(.metric, mean, wflow_id, model) %\u0026gt;% spread(.metric, mean) ) benchmark %\u0026gt;% print_table(round = 5, bm = T) Como no post da Julia, a logloss e a precisão dos modelos que utilizaram métodos de balanceamento dos dados pioraram em relação ao modelo de Bagged Decision Tree sem o uso desses pipelines. Apesar da piora em relação ao modelo de base nota-se que outros métodos como Tomek Links e Adasyn se saíram ligeiramente melhores do que o Smote (além disso vimos que o Smote com sua configuração default não necessariamente produrizá os melhores resultados).\nEste tipo de performance é muito comum e até esperado visto que estamos avaliando o modelo através de uma única métrica (com os mesmos pontos de corte e com o mesmo algoritmo). Normalmente no mundo real monitoramos diversas métricas e experimentamos mais configurações de hiperparâmetros de diferentes modelos com diferentes pipelines.\nConclusão Assim como não existe melhor modelo, não existe melhor técnica de balanceamento de dados. Portanto, na busca de melhores resultados nós podemos tentar otimizar qual abordagem será utilizada bem como seus hiperparâmetros (em conjunto com os hiperparâmetros dos modelos em questão).\nEsta abordagem em R é nova para mim (estou mais acostumado a utilizar em Python com o método sklearn.pipeline.Pipeline em conjunto com a biblioteca imblearn) então qualquer crítica e sugestão de melhoria será muito bem vinda! Basta entrar em contato ou deixar aqui nos comentários!\nPara outros exemplos de modelagem preditiva com engenharia de atributos, veja os posts sobre as soluções do Porto Seguro Data Challenge e da competição de qualidade da educação, ambas no Kaggle.\nPerguntas frequentes Balancear os dados sempre melhora o modelo? Não necessariamente. Neste post, os pipelines com balanceamento tiveram logloss e precisão piores que o modelo base sem balanceamento, ao avaliar por uma única métrica. O balanceamento ajuda mais quando a métrica de negócio realmente penaliza a classe minoritária, como recall em detecção de fraude.\nOversampling ou undersampling: qual escolher? Depende do volume de dados. Com poucos exemplos da classe minoritária, oversampling (como SMOTE) evita perder informação, mas pode gerar dados sintéticos pouco realistas. Com bastante dado da classe majoritária, undersampling é mais barato computacionalmente, mas descarta informação real.\nO que o pacote workflowsets resolve que o tidymodels sozinho não resolve? O workflowsets combina múltiplas receitas de pré-processamento com múltiplos modelos automaticamente, testando todas as combinações de uma vez via workflow_map(). Sem ele, seria preciso escrever e ajustar cada combinação de receita e modelo manualmente.\nBons estudos e espero que gostem! 🚀\nReferências https://www.tidyverse.org/blog/2021/03/workflowsets-0-0-1/ https://www.kaggle.com/c/sliced-s01e02-xunyc5 https://juliasilge.com/blog/sliced-aircraft/ https://topepo.github.io/caret/subsampling-for-class-imbalances.html https://machinelearningmastery.com/bagging-and-random-forest-for-imbalanced-classification/ https://machinelearningmastery.com/what-is-imbalanced-classification/ https://machinelearningmastery.com/framework-for-imbalanced-classification-projects/ https://machinelearningmastery.com/data-sampling-methods-for-imbalanced-classification/ ","date":"28 de junho de 2021","externalUrl":null,"permalink":"/post/2021-06-28-imbalanced-workflowsets/","section":"Posts","summary":" O problema envolvendo dados desbalanceados Objetivo Dependências Preparar dados Breve análise exploratória Modelagem Baselines Preparar Pipeline de dados com workflowsets Benchmark Conclusão Referências O problema envolvendo dados desbalanceados A tarefa de classificação com dados desbalanceados é muito comum na vida real podendo variar desde um leve viés até um enorme desequilíbrio na distribuição da classe de interesse. Problemas mais comuns envolvem:\n","title":"Otimizando pipelines que envolvem dados desbalanceados","type":"post"},{"content":"","date":"28 de junho de 2021","externalUrl":null,"permalink":"/tags/random-forest/","section":"Tags","summary":"","title":"Random-Forest","type":"tags"},{"content":"","date":"28 de junho de 2021","externalUrl":null,"permalink":"/tags/tidymodels/","section":"Tags","summary":"","title":"Tidymodels","type":"tags"},{"content":"","date":"28 de junho de 2021","externalUrl":null,"permalink":"/tags/tunning/","section":"Tags","summary":"","title":"Tunning","type":"tags"},{"content":"","date":"24 de maio de 2021","externalUrl":null,"permalink":"/tags/big-data/","section":"Tags","summary":"","title":"Big-Data","type":"tags"},{"content":" Ciência de dados é a área que combina programação, matemática, estatística e conhecimento de contexto para extrair soluções escondidas em grandes massas de dados desorganizados. Com a quantidade de dados produzida a cada instante e o poder computacional cada vez mais barato, ela ganhou um espaço enorme no mercado. Para ter ideia da escala, projeta-se que, até 2025, o mundo gere cerca de 175 zettabytes de dados por ano (IDC, Data Age 2025).\nEste texto nasceu de uma palestra que dei no Ramo Estudantil IEEE da UFF, em abril de 2021. A apresentação completa, de cerca de uma hora, está logo abaixo, e o restante do post organiza por escrito as mesmas ideias:\nAssista à palestra no YouTube: https://www.youtube.com/watch?v=9UWhZ1s3Ybc\nTL;DR\nO que é: a interseção entre programação, estatística/matemática e contexto de negócio para tirar valor de dados. A base: estatística e manipulação de dados pesam mais que o algoritmo da vez. Como começar: estatística, uma linguagem (R ou Python) e projetos reais valem mais que cursos isolados. O que é ciência de dados, afinal? Ciência de dados é a disciplina que usa métodos científicos, processos e algoritmos para extrair conhecimento de dados estruturados e não estruturados. Na prática, ela vive na interseção de três competências: programação (para coletar, limpar e processar dados), matemática e estatística (para modelar e quantificar incerteza) e domínio do problema (para fazer as perguntas certas e interpretar os resultados).\nGosto de descrever assim: estatística sem programação não escala, programação sem estatística vira chute com confiança, e as duas sem contexto produzem respostas tecnicamente corretas para perguntas erradas. O cientista de dados é quem segura essas três pontas ao mesmo tempo. Não precisa ser o melhor do mundo em nenhuma delas, mas precisa transitar entre todas.\nÉ um campo amplo, e ninguém domina tudo. Há quem foque em engenharia de dados, quem prefira modelagem estatística, quem se especialize em machine learning ou em visualização. Tudo bem. Esta visão geral é o mapa, não o território inteiro.\nQual o papel da estatística? A estatística é a espinha dorsal da ciência de dados: é ela que separa um padrão real de uma coincidência. Antes de qualquer modelo sofisticado, o trabalho começa entendendo a distribuição das variáveis, as relações entre elas e a incerteza por trás de cada número. Pulei essa etapa muitas vezes no início, e o resultado foi sempre o mesmo: modelo bonito, conclusão errada.\nBoa parte do dia a dia é análise exploratória. Olhar os dados antes de modelar evita os erros mais caros. Já escrevi em detalhe sobre os tipos de correlações entre variáveis e sobre análise multivariada em R, porque é nessa fase que se descobre o que o dado realmente diz, ou deixa de dizer.\nTem também a parte menos glamourosa: manipular e limpar dados, que costuma consumir a maior fatia do tempo. Não tem mágica. Aprender a manipular tabelas com fluidez, como mostro no post sobre manipulação de dados com o dplyr, é o tipo de habilidade que paga dividendos todos os dias.\nMachine learning, em poucas palavras Machine learning é o ramo em que, em vez de programar regras explícitas, deixamos o algoritmo aprender padrões a partir de exemplos. Se a estatística clássica pergunta \"qual a relação entre X e Y?\", o machine learning costuma perguntar \"dado X, qual o melhor palpite para Y?\", priorizando a capacidade de acertar em dados novos.\nOs problemas se dividem em grandes grupos. No aprendizado supervisionado, temos exemplos rotulados e queremos prever um rótulo (classificação) ou um número (regressão). No não supervisionado, buscamos estrutura sem rótulos, como agrupar clientes parecidos. Modelos baseados em árvores, que detalho no post sobre modelos em árvore, são um ótimo ponto de partida: poderosos e interpretáveis.\nUm engano comum é achar que machine learning substitui estatística. Não substitui. Um modelo que acerta 95% pode ser inútil se os erros caírem todos no grupo que mais importa. Foi sobre essa ponte entre objetivo de negócio e métrica técnica que falei no post sobre SMART e machine learning. A métrica certa depende da pergunta, e definir a pergunta ainda é trabalho humano.\nOnde a ciência de dados é aplicada? A ciência de dados aparece em praticamente todo setor: crédito e seguros (risco e fraude), varejo (recomendação e previsão de demanda), saúde (diagnóstico e triagem), marketing (segmentação) e operações (manutenção preditiva). O denominador comum é simples: existe uma decisão repetitiva que pode melhorar se você aprender com o histórico.\nCompetições são uma forma honesta de praticar com problemas reais. Documentei aqui no blog duas soluções completas: o Porto Seguro Data Challenge, sobre risco no setor de seguros, e a competição de qualidade da educação no Kaggle. Em ambos, o que decidiu o resultado não foi o algoritmo mais exótico, e sim a engenharia de atributos e a validação bem feita. O modelo costuma ser a parte mais fácil.\nA palestra: \"O bom filho à casa torna!\" No dia 23 de abril de 2021 tive o enorme prazer de apresentar no Ramo Estudantil IEEE UFF um pouco da minha visão sobre as áreas que compõem a ciência de dados, com alguns cases. Sou muito grato à organização pelo cuidado e pelo capricho do evento, e fiquei feliz de poder retornar (apesar do momento de pandemia) à universidade que mudou minha vida e contribuir um pouquinho com quem está chegando.\nOs temas foram, em resumo, os mesmos que estruturam este texto: o que é ciência de dados, o papel da estatística, big data, machine learning, aplicações e dicas de carreira. Tentei deixar a apresentação leve, recheada de memes e linguagem acessível. Se você pulou o vídeo no topo do post, vale a pena voltar nele.\nAtualização (2026): da estatística aos agentes Nota acrescentada em 2026. Desde esta palestra, em 2021, o campo andou rápido. Os modelos de linguagem (LLMs) e os agentes de IA ampliaram muito o que dá para construir, e hoje é possível experimentar bastante sem gastar quase nada. Já mostrei por aqui como rodar um agente com LLM local de graça, como montar um agente para análise de Bitcoin e um agente de telemarketing, além de análise de sentimentos com o Llama 2. A base, porém, continua a mesma desta visão geral: dados, estatística e clareza sobre o problema. As ferramentas é que ficaram muito mais poderosas.\nSe esse panorama todo te deixou com vontade de ler mais sobre algum desses temas, separei numa página de livros a curadoria dos que realmente li e uso, de estatística básica a LLMs.\nPerguntas frequentes Preciso de faculdade para ser cientista de dados? Ajuda, mas não é obrigatória. O mercado valoriza portfólio e capacidade de resolver problemas reais acima do diploma. Uma base sólida de estatística e programação, somada a dois ou três projetos públicos bem documentados, abre muitas portas, especialmente em vagas júnior.\nR ou Python: qual aprender primeiro? Qualquer um dos dois. Python domina em produção; R é imbatível em análise estatística e visualização. A fluência em uma linguagem importa muito mais que a escolha entre elas, e quem aprende uma migra para a outra com facilidade. Comece pela que o seu nicho usar mais.\nQual a diferença entre cientista de dados e analista de dados? O analista foca em descrever o que aconteceu, com relatórios e dashboards. O cientista de dados vai além e modela o que deve acontecer ou a melhor decisão a tomar, usando estatística e machine learning. As fronteiras são borradas e variam por empresa, mas a profundidade em modelagem separa os dois.\n","date":"24 de maio de 2021","externalUrl":null,"permalink":"/post/2021-05-24-ciencia-de-dados-uma-visao-geral/","section":"Posts","summary":"Ciência de dados é a área que combina programação, matemática, estatística e conhecimento de contexto para extrair soluções escondidas em grandes massas de dados desorganizados. Com a quantidade de dados produzida a cada instante e o poder computacional cada vez mais barato, ela ganhou um espaço enorme no mercado. Para ter ideia da escala, projeta-se que, até 2025, o mundo gere cerca de 175 zettabytes de dados por ano (IDC, Data Age 2025).\n","title":"Ciência de Dados: Uma Visão Geral Para Quem Quer Começar","type":"post"},{"content":"Link do repositório no github: https://github.com/gomesfellipe/spleeteR\nPacote em R que encapsula o Spleeter, ferramenta da Deezer para separação de fontes de áudio, permitindo isolar vocais e instrumentais de uma música direto do R.\nO que faz # Separa uma faixa de áudio em componentes (2, 4 ou 5 stems), como vocais, baixo, bateria e outros instrumentos, usando modelos pré-treinados baseados em TensorFlow.\nInstalação # R reticulate::py_install(c(\u0026#34;spleeter\u0026#34;), forge = TRUE) remotes::install_github(\u0026#34;gomesfellipe/spleeteR\u0026#34;) Uso # R spleeteR::separator(audio_path = \u0026#34;\u0026lt;audio_file\u0026gt;\u0026#34;, n_stem = 2) Gera os arquivos separados (vocals.wav, accompaniment.wav, etc.) em uma pasta de saída.\n","date":"14 de março de 2021","externalUrl":null,"permalink":"/projects/spleeter/","section":"Projetos","summary":"Link do repositório no github: https://github.com/gomesfellipe/spleeteR\nPacote em R que encapsula o Spleeter, ferramenta da Deezer para separação de fontes de áudio, permitindo isolar vocais e instrumentais de uma música direto do R.\nO que faz # Separa uma faixa de áudio em componentes (2, 4 ou 5 stems), como vocais, baixo, bateria e outros instrumentos, usando modelos pré-treinados baseados em TensorFlow.\n","title":"spleeteR","type":"projects"},{"content":"","date":"4 de março de 2021","externalUrl":null,"permalink":"/tags/lightgbm/","section":"Tags","summary":"","title":"Lightgbm","type":"tags"},{"content":" Qualidade de sono? 🤨 Como funciona aplicativo Sleep Cycle? Objetivo 🎯 Explorar dados 🔎 Limpeza e preparação dos dados Imputar dados de fontes externas Insights Reter dados Modelagem 🚀 Amostragem Engenharia de recursos Modelo Nulo (Baseline) Árvore de decisões Random Forest LightGBM Seleção do modelo 🤔 Previsão em dados novos 💫 Conclusão 🍻 Referências 🧳 Qualidade de sono? 🤨 Sim, exatamente! Neste post analisaremos dados de um tracking que venho fazendo desde 2017 com informações relacionadas à um sono de qualidade.\nTL;DR\nOs dados vêm do app Sleep Cycle, usado desde 2017, com variáveis como frequência cardíaca, passos, tempo na cama e humor ao acordar (mood). A target é desbalanceada: o objetivo é prever a probabilidade de acordar de mal humor (Ruim) nos dias em que esse dado não foi registrado, usando undersampling com Tomek Links e métrica logloss. Depois de comparar árvore de decisão, Random Forest e LightGBM, o LightGBM ajustado (tunning) teve o melhor desempenho geral e foi o modelo escolhido para prever os dias faltantes. Boas noites de sono nos tornam mais felizes, mais saudáveis, mais inteligentes, mais dispostos e evita problemas de cansaço, falta de concentração, depressão e ansiedade.\nResumindo, a nossa qualidade de vida está diretamente ligada à qualidade do nosso sono, pois ao dormir nosso corpo realiza funções extremamente importantes como por exemplo o fortalecimento do sistema imunológico, secreção e liberação de hormônios, consolidação da memória, entre outras1.\nVia Giphy Alguns fatores podem auxiliar a determinar se uma noite foi bem dormida como por exemplo: a regularidade do horário de dormir e de acordar, a frequência cardíaca (bpm), número de passos dados no dia, tempo na cama, tempo antes de dormir, ronco, tipo de clima etc..\nVia Gyiphy Felizmente, existe um aplicativo chamado Sleep Cycle que é capaz de trackear todas essas informações durante o uso do app, dentre outras funcionalidades. Desde 2017 tenho acompanhado meu sono através dele, principalmente pela funcionalidade de rastreio dos padrões de sono para despertar durante sua fase mais leve, sem um despertador convencional e tenho curtido bastante!\nA proposta principal do aplicativo é monitorar os sinais do corpo para nos despertar suavemente quando estivermos no estágio de sono mais leve possível, pois acordar durante o sono leve é como acordar naturalmente descansado!\nComo funciona aplicativo Sleep Cycle? Tradução livre de How Sleep Cycle works:\n“O funcionamento básico desse aplicativo se baseia que nos mexemos predominantemente durante o sono leve. Já durante o sono pesado, os músculos tendem a permanecer relaxados, e em sono REM a movimentação muscular abaixo do pescoço fica paralizada.\nAssim sendo é possível selecionar um horário que gostaria de acordar, como de 6:30 até 7:00, e o aplicativo rastreará os movimentos na cama para acordar apenas quando entrar em sono leve durnte este período.\nDessa forma, estaríamos aumentando as chances de acordar mais bem-disposto, já que seu sono foi interrompido em uma fase mais leve de descanso.”\nEm um sono regular, os picos do gráfico representam os ciclos completos do sono, incluindo todas as fases. Já em um sono irregular, esses ciclos se tornam mais fragmentados, indicando que o usuário provavelmente não descansou tão bem.\nEsta é a principal informação coletada no aplicativo e que permite um “despertar tranquilo”!\nObjetivo 🎯 Apesar do aplicativo captar diversos dados sobre a noite de sono, o “humor ao acordar” é uma informação fornecida pelo usuário assim que desativa o alarme, quando a seguinte tela é exibida:\nComo houveram diversos dias em que utilizei o aplicativo mas não assinalei o humor (seja por ter desativado o recurso por algum tempo ou simplesmente por ter ignorado 😅) vamos trabalhar para responder a seguinte pergunta:\nQual foi a probabilidade de ter acordado de mal humor durante o período de tracking do app, nos dias cujo esse dado é faltante?\nOnde mal humor será a classe positiva da target, traduzido nos dados da seguinte forma:\n\\[ mood= \\begin{cases} Bom, \u0026amp; \\text{se}\\ mood = Bom \\\\ Ruim, \u0026amp; \\text{c.c}\\ \\end{cases} \\]\nLogo, mood será binária, avaliando se o humor foi Bom ou Ruim ao acordar, onde Ruim a combinação do status 😑 (Ok) e 😡 (Mau) e será a classe mais importante para controlar os erros de previsão.\nTomei a liberdade de fazer essa transformação pois desde o início do uso do app, marco como Ruim apenas quando realmente não descansei de forma satisfatória. Isso pode ter ocorrido por diversos fatores, como por exemplo: acordar após um pesadelo; acordar com barulho da rua ou de casa; acordar meio doente ou passando mal e por ai vai..\nPor enquanto, estas informações serão suficientes. Vejamos na análise exploratória como se apresenta a variável target e quais dados disponíveis para atingir tal objetivo.\nExplorar dados 🔎 Carregar as dependências:\nlibrary(tidyverse) # datascience toolkit library(lubridate) # manipule date library(patchwork) # grid ggplot library(tidymodels) # machine learning toolkit library(reactable) # print tables library(treesnip) # lightgbm # Definir tema para ggplot theme_set(theme_bw()) Vamos carregar funções que foram desenvolvidas ao longo das análises para facilitar tanto na apresentação dos resultados quanto na portabilidade dos códigos (bastando pequenos ajustes para “reciclá-los” ♻️):\n(Clique aqui para exibir as funções customizadas) # Para o print de tabelas print_table \u0026lt;- function(x, round=0, evalue_model = F, ...){ if(round\u0026gt;0) x \u0026lt;- x %\u0026gt;% mutate_if(is.numeric, ~round(.x, round)) if(evalue_model == T){ reactable::reactable(x, striped = T, bordered = T, highlight = T, pagination = F, width = 800, defaultColDef = colDef(minWidth = 85), defaultSorted = list(auc_pr = \u0026quot;desc\u0026quot;), columns = list( model = colDef(minWidth = 110), tp = colDef(minWidth = 40), fp = colDef(minWidth = 40), fn = colDef(minWidth = 40), tn = colDef(minWidth = 40)), ...) }else{ reactable::reactable(x, striped = T, bordered = T, width = 800, highlight = T, pagination = F, ...) } } # Graficos de features numericas plot_num \u0026lt;- function(data, num_feature, title = NULL, bins = 30, legend = NULL){ if(is.null(title)) title = num_feature data = data %\u0026gt;% filter(!is.na(mood)) p_shapiro = round(shapiro.test(data$air_pressure_pa)$p.value, 5) p1 \u0026lt;- data %\u0026gt;% ggplot(aes_string(x = num_feature, fill = \u0026quot;mood\u0026quot;))+ geom_histogram(aes(y=..density..), bins = bins, alpha = 0.5, show.legend = ifelse(!is.null(legend), T, F))+ geom_density(alpha = 0.5, show.legend = ifelse(!is.null(legend), T, F))+ labs(y = \u0026quot;\u0026quot;, x= \u0026quot;\u0026quot;, title = title)+ scale_fill_viridis_d(end = 0.8, direction = 1) if(!is.null(legend)){ p1 = p1 + theme(legend.position = legend) } p2 \u0026lt;- data %\u0026gt;% ggplot(aes_string(x = num_feature))+ geom_boxplot(aes(y = \u0026quot;\u0026quot;, color = mood), show.legend = F)+ labs(y = \u0026quot;\u0026quot;, x= \u0026quot;\u0026quot;, caption = paste0(\u0026quot;Shapiro-Wilk normality test: \u0026quot;, ifelse(p_shapiro == 0, \u0026quot;P\u0026lt;0.05\u0026quot;, p_shapiro) ))+ scale_color_viridis_d(end = 0.8, direction = 1) p1 / p2 + plot_layout(heights = c(4/5, 1/5)) } # Graficos de features categoricas plot_cat \u0026lt;- function(data, cat_feature, title = NULL, label = TRUE, legend = NULL){ data = data %\u0026gt;% filter(!is.na(mood)) valor_p = round(chisq.test(data %\u0026gt;% pull(cat_feature), data$mood, simulate.p.value = T)$p.value, 5) to_plot = data %\u0026gt;% count(!!as.name(cat_feature), mood) %\u0026gt;% group_by(!!as.name(cat_feature)) final_plot = to_plot %\u0026gt;% mutate(prop = n/sum(n), lab = paste0(round(prop*100, 2), \u0026quot;%\u0026quot;)) %\u0026gt;% ggplot()+ geom_bar(aes_string(x = cat_feature, y = \u0026quot;n\u0026quot;, fill = \u0026quot;mood\u0026quot;), stat = \u0026quot;identity\u0026quot;, alpha = 0.7, position = position_dodge2(0.9), show.legend = ifelse(!is.null(legend), T, F))+ scale_fill_viridis_d(end = 0.8, direction = 1)+ labs(title = title, y = \u0026quot;\u0026quot;, caption = paste0(\u0026quot;Pearson\u0026#39;s Chi-squared test: \u0026quot;, valor_p)) if(label == TRUE){ final_plot = final_plot+ geom_label(aes_string(x = cat_feature, y = \u0026quot;n\u0026quot;, label = \u0026quot;lab\u0026quot;), position = position_dodge2(0.9), show.legend = F) } if(!is.null(legend)){ final_plot = final_plot + theme(legend.position = legend) } return(final_plot) } # Grafico interativo de features temporais plot_dygraph \u0026lt;- function(x, order.by, feature, title = NULL){ x %\u0026gt;% xts::xts(order.by = order.by) %\u0026gt;% .[,feature] %\u0026gt;% dygraphs::dygraph(main = title) %\u0026gt;% dygraphs::dyRangeSelector() } # Calcula o ponto de corte que maximiza a funcao f beta threshold_max \u0026lt;- function(x){ fbeta \u0026lt;- function(precision, recall){ (beta+1)*(precision*recall)/(beta*(precision+recall)) } # https://machinelearningmastery.com/fbeta-measure-for-machine-learning/ # F05: + precision - recall # F1 : + precision + recall # F2 : - precision + recall beta = 0.5 x %\u0026gt;% pr_curve(mood, .pred_Ruim) %\u0026gt;% mutate(fbeta = fbeta(precision, recall) ) %\u0026gt;% filter(fbeta == max(fbeta, na.rm = T)) } # Plot da matriz de confusao e da funcao das funcoes de densidade estimadas conf_mat_plot \u0026lt;- function(x, null_model = FALSE){ trs \u0026lt;- threshold_max(x)$.threshold if(null_model==FALSE){ x \u0026lt;- x %\u0026gt;% mutate(.pred_class = ifelse(.pred_Ruim \u0026gt;= trs, \u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;) %\u0026gt;% factor(levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) } p1 \u0026lt;- x %\u0026gt;% select(.pred_class, mood) %\u0026gt;% table() %\u0026gt;% conf_mat() %\u0026gt;% autoplot(type = \u0026quot;heatmap\u0026quot;)+ labs(title = \u0026quot;Matriz de Confusao\u0026quot;, subtitle = paste0(\u0026quot;Threshold max F0.5: \u0026quot;, round(trs, 4))) p2 \u0026lt;- x %\u0026gt;% ggplot() + geom_density(aes(x = .pred_Ruim, fill = mood), alpha = 0.5)+ labs(title = \u0026quot;Distribuições de probabilidade previstas\u0026quot;, subtitle = \u0026quot;por classe\u0026quot;)+ scale_x_continuous(limits = 0:1)+ geom_vline(aes(xintercept = trs, color = \u0026quot;threshold max F0.5\u0026quot;), linetype = 2) + scale_color_manual(name = \u0026quot;\u0026quot;, values = c(`threshold max F0.5` = \u0026quot;red\u0026quot;))+ scale_fill_viridis_d(end = 0.7, direction = 1) p1 | p2 } # Conjunto de metricas utilizadas para avaliar os modelos evalue_model \u0026lt;- function(x, model = \u0026quot;\u0026quot;, null_model=FALSE){ trs \u0026lt;- threshold_max(x)$.threshold if(null_model==FALSE){ x \u0026lt;- x %\u0026gt;% mutate(.pred_class = ifelse(.pred_Ruim \u0026gt;= trs, \u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;) %\u0026gt;% factor(levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) } cm \u0026lt;- x %\u0026gt;% select(.pred_class, mood) %\u0026gt;% table() tibble( model = model, tp = cm[1,1], fp = cm[1,2], fn = cm[2,1], tn = cm[2,2], auc_roc = yardstick::roc_auc(x, mood, `.pred_Ruim`)$.estimate, auc_pr = yardstick::pr_auc(x, mood, `.pred_Ruim`)$.estimate, logloss = yardstick::mn_log_loss_vec(x$mood, x$.pred_Ruim), f1 = yardstick::f_meas_vec(x$mood, x$.pred_class, beta = 1), f05 = yardstick::f_meas_vec(x$mood, x$.pred_class, beta = 0.5), f2 = yardstick::f_meas_vec(x$mood, x$.pred_class, beta = 2), precision = yardstick::precision_vec(x$mood, x$.pred_class), recall = yardstick::recall_vec(x$mood, x$.pred_class), trs_fbeta = trs ) } plot_auc \u0026lt;- function(x){ p1 \u0026lt;- x %\u0026gt;% group_by(model) %\u0026gt;% roc_curve(mood, .pred_Ruim) %\u0026gt;% ggplot(aes(x = 1 - specificity, y = sensitivity, color = model)) + geom_line(size = 1, alpha = 0.5, show.legend = F) + geom_abline(lty = 2, alpha = 0.5, color = \u0026quot;gray50\u0026quot;, size = 1.3)+ labs(title = \u0026quot;AUC\u0026quot;)+ scale_color_viridis_d(direction = 1) p2 \u0026lt;- x %\u0026gt;% group_by(model) %\u0026gt;% pr_curve(mood, .pred_Ruim) %\u0026gt;% ggplot(aes(x = recall, y = precision, color = model)) + geom_line(size = 1.15, alpha = 0.5) + # geom_abline(slope = -1, intercept = 1, lty = 2, alpha = 0.5, color = \u0026quot;gray50\u0026quot;, size = 1.2)+ labs(title = \u0026quot;PR AUC\u0026quot;)+ theme(legend.position = \u0026quot;right\u0026quot;)+ scale_color_viridis_d(direction = 1) (p1 | p2) } Importar os dados obtidos no app SleepCycle e padronizar nomes das colunas:\nsleep \u0026lt;- read_csv2(\u0026quot;sleepdata.csv\u0026quot;) %\u0026gt;% janitor::clean_names(case = \u0026quot;snake\u0026quot;) A seguir, uma tabela com uma descrição do conteúdo de cada coluna:\nColuna Descrição curta Descrição detalhada start Início Início do monitoramento end Fim Fim do monitoramento sleep_quality Qualidade do Sono Qualidade do sono é baseada em: tempo que passa a dormir, movimentos durante a noite e momentos em que está totalmente desperto regularity Regularidade Informa sobre a regularidade do horário de dormir e de acordar durante um período de tempo. Quanto maior, mais regular tem sido o horário de acordar e dormir e isso pode resultar em um sono melhor mood 🎯 Humor Humor informado no app ao acordar: 😃 (Bom), 😑 (Ok), 😡 (Mau), ⛔ (Não informado) heart_rate_bpm Frequência cardíaca (bpm) - steps Passos Quantos passos dá por dia (bom a partir de 10.000 passos por dia) alarm_mode Modo de alarme Alarme ligado ou apenas monitoramento air_pressure_pa Pressão do Ar (Pa) - city Cidade - movements_per_hour Movimentos por hora - time_in_bed_seconds Tempo na cama (segundos) - time_asleep_seconds Tempo adormecido (segundos) - time_before_sleep_seconds Tempo antes de dormir (segundos) - window_start Início da janela Início do modo soneca window_stop Fim da janela Fim do modo soneca did_snore Ronco Detector de ruídos (pode captar outros barulhos que não seja ronco) snore_time Hora do ronco - weather_temperature_c Temperatura (°C) - weather_type Tipo de clima - notes Notas Alguma nota ao acordar Limpeza e preparação dos dados Vamos realizar uma limpeza inicial, preparando os dados para possibilitar as análise em um objeto tibble minimamente arrumado:\nsleep \u0026lt;- sleep %\u0026gt;% # fix target mutate(mood = case_when(mood == \u0026quot;Bom\u0026quot; ~ \u0026quot;Bom\u0026quot;, mood == \u0026quot;Mau\u0026quot; ~ \u0026quot;Ruim\u0026quot;, mood == \u0026quot;Ok\u0026quot; ~ \u0026quot;Ruim\u0026quot;, is.na(mood) ~ NA_character_), mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% # fix window mutate_at(c(\u0026quot;window_start\u0026quot;, \u0026quot;window_stop\u0026quot;), ~ifelse(is.na(.x), end, .x)) %\u0026gt;% # fix string % mutate_at(c(\u0026quot;sleep_quality\u0026quot;, \u0026quot;regularity\u0026quot;), ~ .x %\u0026gt;% str_remove(\u0026quot;%\u0026quot;) %\u0026gt;% as.numeric() ) %\u0026gt;% # fix heart_rate_bpm e criar bug indicator mutate(heart_rate_bug = ifelse(heart_rate_bpm == 0, \u0026quot;sim\u0026quot;, \u0026quot;nao\u0026quot;)) %\u0026gt;% mutate(heart_rate_bpm = ifelse(heart_rate_bpm == 0, NA_integer_, heart_rate_bpm)) %\u0026gt;% # fix dados de soneca mutate(snore_time = as.numeric(snore_time), did_snore = ifelse(did_snore == TRUE, \u0026quot;sim\u0026quot;, \u0026quot;nao\u0026quot;)) %\u0026gt;% # fix para numerico mutate_at(c(\u0026quot;time_before_sleep_seconds\u0026quot;, \u0026quot;time_asleep_seconds\u0026quot;, \u0026quot;time_in_bed_seconds\u0026quot;), ~as.numeric(.x) ) %\u0026gt;% # fix movements_per_hour para double mutate(movements_per_hour = as.double(movements_per_hour)) %\u0026gt;% # fix weather_type mutate(weather_type = factor(weather_type, levels = c(\u0026quot;No weather\u0026quot;, \u0026quot;Rain\u0026quot;, \u0026quot;Rainy showers\u0026quot;, \u0026quot;Cloudy\u0026quot;, \u0026quot;Partly cloudy\u0026quot;, \u0026quot;Fair\u0026quot;, \u0026quot;Sunny\u0026quot;), ordered = TRUE)) %\u0026gt;% mutate_at(c(\u0026quot;weather_temperature_c\u0026quot;, \u0026quot;air_pressure_pa\u0026quot;), ~ as.numeric(.x) %\u0026gt;% if_else(. == 0, NA_real_, .)) %\u0026gt;% # remover unused columns select(-one_of(c(\u0026quot;city\u0026quot;, \u0026quot;notes\u0026quot;))) %\u0026gt;% select(mood, everything()) %\u0026gt;% arrange(end) Qual a estrutura geral dos dados? Será que existe algum padrão nos dados ausentes?\nsleep %\u0026gt;% arrange(end) %\u0026gt;% mutate(Date = as.Date(end))%\u0026gt;% # complete(Date = seq.Date(min(Date), max(Date), by=\u0026quot;day\u0026quot;)) %\u0026gt;% visdat::vis_dat() Os dados ausentes ocorrem tanto espalhados (heart_rate_bpm) quanto em sequência (air_pressure_pa, weather_temperature_c, mood) portando, adotaremos as seguintes estratégias para inputar dados ausentes:\nair_pressure_pa: Será obtidos no site data.rio/datasets e caso ainda exista dados ausentes, será preenchido com as médias móveis dos últimos 7 dias; weather_temperature_c: Mesma estratégia do item (1); heart_rate_bpm: Cálculo das médias móveis dos últimos 7 dias; mood: Como é a target, as instâncias aonde is.na(mood) serão retidas para estimação após o ajuste do modelo. Imputar dados de fontes externas O preenchimento das features air_pressure_pa, weather_temperature_c serão realizados a partir do download de dados públicos do Rio de Janeiro no link: data.rio/datasets. Para obter este dado utilizaremos a função get_rj_data() desenvolvida para este post, que está omitida mas para quem tiver interesse basta conferir clicando no item abaixo:\n(Código da função get_rj_data()) get_rj_data \u0026lt;- function(){ if(!file.exists(\u0026quot;rj_data.rds\u0026quot;)){ url \u0026lt;- \u0026quot;https://opendata.arcgis.com/datasets/5b1bf5c3e5114564bbf9b7a372b85e17_2.csv?outSR=%7B%22latestWkid%22%3A4326%2C%22wkid%22%3A4326%7D\u0026quot; download.file(url, \u0026quot;rj_data.csv\u0026quot;) rj_data \u0026lt;- readr::read_csv(\u0026quot;rj_data.csv\u0026quot;) saveRDS(rj_data, \u0026quot;rj_data.rds\u0026quot;) }else{ rj_data \u0026lt;- readRDS(\u0026quot;rj_data.rds\u0026quot;) } # preparar dados de pressao atmosferica e temperatura no periodo desejado rj_data \u0026lt;- rj_data %\u0026gt;% mutate(Data = ymd_hms(Data)) %\u0026gt;% filter(Data \u0026gt;= min(sleep$start) \u0026amp; Data \u0026lt;= max(sleep$start)) %\u0026gt;% group_by(Data = as.Date(Data)) %\u0026gt;% summarise(air_pressure_pa = mean(Pres/10, rm.na=T), weather_temperature_c = mean(Temp, rm.na=T)) return(rj_data) } Com acesso aos dados, hora de combinar as bases e preencher os dados faltantes:\nsleep \u0026lt;- sleep %\u0026gt;% mutate(Data = as.Date(start)) %\u0026gt;% # to numeric mutate_at(c(\u0026quot;weather_temperature_c\u0026quot;, \u0026quot;air_pressure_pa\u0026quot;), ~ as.numeric(.x) %\u0026gt;% if_else(. == 0, NA_real_, .)) %\u0026gt;% # join Rio data left_join(get_rj_data() , by = c(\u0026quot;Data\u0026quot;)) %\u0026gt;% # fill with new data mutate(air_pressure_pa = ifelse(is.na(air_pressure_pa.x), air_pressure_pa.y, air_pressure_pa.x)) %\u0026gt;% mutate(weather_temperature_c = ifelse(is.na(weather_temperature_c.x), weather_temperature_c.y, weather_temperature_c.x)) %\u0026gt;% # remove aux columns select(-air_pressure_pa.x, -air_pressure_pa.y, -weather_temperature_c.x, -weather_temperature_c.y, -Data) Insights Nesta seção vamos responder algumas perguntas com dados!\nstart e end Qual a média mensal de horas dormidas e que horas costumo acordar, em média, mensalmente ao longo desses anos?\n(Código para gráfco abaixo) dy1 \u0026lt;- sleep %\u0026gt;% complete(start = seq.Date(min(as.Date(start)), max(as.Date(start)), by=\u0026quot;day\u0026quot;)) %\u0026gt;% mutate(dif_sleep_hours = as.numeric(end - start)/60) %\u0026gt;% mutate(dif_sleep_hours = zoo::rollmean(dif_sleep_hours, k = 30, fill = NA)) %\u0026gt;% plot_dygraph(order.by = .$start, feature = \u0026#39;dif_sleep_hours\u0026#39;) dy2 \u0026lt;- sleep %\u0026gt;% complete(start = seq.Date(min(as.Date(start)), max(as.Date(start)), by=\u0026quot;day\u0026quot;)) %\u0026gt;% mutate(end_hour = hour(end)) %\u0026gt;% mutate(end_hour = zoo::rollmean(end_hour, k = 30, fill = NA)) %\u0026gt;% plot_dygraph(order.by = .$start, feature = \u0026#39;end_hour\u0026#39;) ⚠️ Note que existem alguns espaços vazios, que correspondem aos dias que o app não foi utilizado.\nwindow_start e window_stop Quanto tempo costumo usar o modo “soneca” ao longo da semana? E aos finais de semana?\n(Código para gráfco abaixo) p \u0026lt;- sleep %\u0026gt;% mutate(mood = ifelse(is.na(mood), \u0026quot;NA\u0026quot;, as.character(mood)) %\u0026gt;% factor(levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;NA\u0026quot;, \u0026quot;Bom\u0026quot;))) %\u0026gt;% mutate(nap_minutes = (window_stop - window_start) / 30, final_de_semana = lubridate::wday(start) %in% c(1, 7)) %\u0026gt;% count(mood, final_de_semana, nap_minutes) %\u0026gt;% group_by(mood, final_de_semana) %\u0026gt;% mutate( fnap_minutes = case_when( nap_minutes == 0 ~ \u0026quot;Sem modo soneca\u0026quot;, nap_minutes == 20 ~ \u0026quot;20 minutos\u0026quot;, nap_minutes == 30 ~ \u0026quot;30 minutos\u0026quot;, nap_minutes == 60 ~ \u0026quot;1 hora\u0026quot;), fnap_minutes = reorder(fnap_minutes, nap_minutes), final_de_semana = ifelse(final_de_semana == T, \u0026quot;Final de semena\u0026quot;, \u0026quot;Dia de semana\u0026quot;), label = paste0( n, \u0026quot; (\u0026quot;, round(n/sum(n)*100, 2), \u0026quot;%)\u0026quot;) ) %\u0026gt;% ggplot(aes(x = fnap_minutes, y = n, label = label, fill = mood))+ geom_bar(stat = \u0026quot;identity\u0026quot;, alpha = 0.8)+ scale_fill_viridis_d(end = 0.7, direction = 1)+ # ggrepel::geom_label_repel(aes(label = label))+ labs(x = \u0026quot;\u0026quot;, y = \u0026quot;\u0026quot;)+ facet_wrap(~final_de_semana)+ theme(axis.text.x = element_text(angle = 30, hjust=1)) p %\u0026gt;% plotly::ggplotly() %\u0026gt;% plotly::config(displayModeBar = F) Como era de se esperar, os dias em que mood==\"Ruim\" ocorrem mais quando o modo soneca não é ativado pois acaba mesmo sendo menos propício a voltar a dormir. Outro detalhe é que muitas vezes usei o soneca por um tempo muito prolongado! (😱 pelo menos mood==\"Bom\" na maioria desses casos!)\nJá nos finais de semana, ocorre pouquíssimo mood== \"Ruim\" e praticamente não há uso do alarme e quando há, não utiliza soneca.\nweather_type e alarm_mode Será que o humor ao acordar esta relacionado com o tipo de clima ou com o modo utilizado no alarme?\np1 \u0026lt;- plot_cat(sleep, cat_feature=\u0026quot;weather_type\u0026quot;, title = \u0026quot;Tipo de clima\u0026quot;, label = F)+ theme(axis.text.x = element_text(angle = 30, hjust=1)) p2 \u0026lt;- plot_cat(sleep, cat_feature=\u0026quot;alarm_mode\u0026quot;, title = \u0026quot;Modo de alarme\u0026quot;, label = F, legend = \u0026quot;right\u0026quot;) p1 | p2 Nota-se que não existem evidências estatisticas para afimar que essas features (sozinhas) estão associadas à target, porém como serão utilizados modelos baseados em árvores que experimentam diversas combinações de features, vamos manter na base e deixar o modelo decidir como usar.\nsleep_quality e time_in_bed_seconds A qualidade de sono e o tempo da cama estão normalmente distribuídos em torno de uma média?\np1 \u0026lt;- sleep %\u0026gt;% plot_num(\u0026quot;sleep_quality\u0026quot;) p2 \u0026lt;- sleep %\u0026gt;% plot_num(\u0026quot;time_in_bed_seconds\u0026quot;, legend = \u0026quot;right\u0026quot;) p1 | p2 Existem alguns registros em que o tempo na cama é menor que 10.000 segundos (~3horas) o que corresponde aos pequenos cochilos que registrei no app. Não foram muitos registros mas talvez seja útil na modelagem pois existem ocorrências de humor (mood) Bom e Ruim ali.\nComo a correlação de spearman entre estas duas feautures é muito alta (0.8705) é possível notar que baixa qualidade do sono esta altamente correlacionada com o tempo na cama.\nMais uma pergunta sobre estas features: Como a média mensal da qualidade do sono e do tempo na cama em horas estão distribuídos ao longo do tempo?\n(Código para gráfco abaixo) dy1 \u0026lt;- sleep %\u0026gt;% complete(start = seq.Date(min(as.Date(start)), max(as.Date(start)), by=\u0026quot;day\u0026quot;)) %\u0026gt;% mutate(sleep_quality = zoo::rollmean(sleep_quality, k = 30, fill = NA)) %\u0026gt;% plot_dygraph(order.by = .$start, feature = \u0026#39;sleep_quality\u0026#39;) dy2 \u0026lt;- sleep %\u0026gt;% complete(start = seq.Date(min(as.Date(start)), max(as.Date(start)), by=\u0026quot;day\u0026quot;)) %\u0026gt;% mutate(time_in_bed_seconds = zoo::rollmean(time_in_bed_seconds, k = 30, fill = NA)) %\u0026gt;% mutate(time_in_bed_seconds = time_in_bed_seconds / 60 / 60) %\u0026gt;% plot_dygraph(order.by = .$start, feature = \u0026#39;time_in_bed_seconds\u0026#39;) Reter dados Antes de iniciar o processo de modelagem, será necessário reter dados aonde mood é NA, pois faremos as previsões nestes dados apenas após o ajuste e seleção do modelo final.\nnew_sleep \u0026lt;- sleep %\u0026gt;% filter(is.na(mood)) sleep \u0026lt;- sleep %\u0026gt;% filter(!is.na(mood)) Modelagem 🚀 Hora de criar alguns modelos para estimar a probabilidade das classes da target: mood.\nComo estamos diante de um cenário onde os dados estão desbalanceados, será necessário tomar algumas decisões muito importantes (sim, cientistas de dados precisam tomar decisões o tempo inteiro). Neste caso, as questões são as seguintes:\nQual a classe mais importante? Qual a métrica será utilizada para selecionar os modelos? Qual será o threshold? Qual será estratégia para lidar com o desbalanceamento? Quais métricas serão monitoradas? A classe mais importante para nossa previsão é a positiva, ou seja, mood==\"Ruim\". Sendo assim desejamos evitar falsos positivos, decisão que só fica clara depois de uma boa análise exploratória combinada com a definição do objetivo do modelo.\nA métrica utilizada para selecionar os modelos será a logloss. Esta é uma métrica probabilistica que foca na incerteza que o modelo tem nas previsões e penaliza as previsões que estão erradas2.\nApós calibrar a probabilidade, estabeleceremos um ponto de corte que maximizar a medida F-Beta, (que é uma abstração da medida F1, média harmônica entre Precision e Recall) onde Beta = 0.5. Essa medida tem o efeito de aumentar a importância da Precision e diminui a importância do Recall. 3\nParra lidar com o desbalanceamento da target, utilizaremos o método de undersampling chamado ** Tomek Links **4. Este método faz uma amostragem da classe majoritária de forma “mais esperta” que uma simples amostragem aleatória.\nPor fim, a principal métrica que será monitorada será a AUC-PR5 (Area Under Precision Recall Curve). Ela é uma espécie de AUC que cálculada a área sobre a Precision x Recall. Essa métrica é preferível neste caso pois foca maisn na classe positiva e a ROC AUC tente a superestimar os valores nesse caso.\nAmostragem Para preparar os dados para modelagem vamos dividir os dados em treino (70%) e teste (30%).\nset.seed(123456789) # treino e teste sleep_split \u0026lt;- initial_split(data = sleep, strata = mood, prop = 0.7) sleep_train \u0026lt;- training(sleep_split) sleep_test \u0026lt;- testing(sleep_split) Além disso, vamos dividir o conjunto de treino em 4 folds para obter resultados de validação cruzada. Este valor corresponde metade da quantidade em que mood==\"Ruim\" nos dados teste.\nset.seed(123456789) k_fold \u0026lt;- sleep_test %\u0026gt;% count(mood) %\u0026gt;% filter(mood==\u0026quot;Ruim\u0026quot;) %\u0026gt;% pull(n) sleep_folds \u0026lt;- sleep_train %\u0026gt;% rsample::vfold_cv(v = round(k_fold/2), repeats = 10, strata = mood) A decisão de utilizar o valor de k como metade do tamanho da classe minoritária foi uma decisão pessoal, não sei se é ótima mas foi conveniente neste caso.\nComo ficou dividido:\n(Código para tabela abaixo) tab \u0026lt;- full_join(sleep_train %\u0026gt;% count(mood) %\u0026gt;% mutate(prop = n/sum(n)*100), sleep_test %\u0026gt;% count(mood) %\u0026gt;% mutate(prop = n/sum(n)*100), by = \u0026quot;mood\u0026quot;) %\u0026gt;% print_table(round = 2, columns = list( n.x = colDef(name = \u0026quot;N\u0026quot;), prop.x = colDef(name = \u0026quot;(%)\u0026quot;, align = \u0026quot;left\u0026quot;), n.y = colDef(name = \u0026quot;N\u0026quot;), prop.y = colDef(name = \u0026quot;(%)\u0026quot;, align = \u0026quot;left\u0026quot;) ), columnGroups = list( colGroup(name = \u0026quot;Train\u0026quot;, columns = c(\u0026quot;n.x\u0026quot;, \u0026quot;prop.x\u0026quot;)), colGroup(name = \u0026quot;Test\u0026quot;, columns = c(\u0026quot;n.y\u0026quot;, \u0026quot;prop.y\u0026quot;)) )) tab ☠️ A quantidade reduzida de dados para teste reflete a baixa quantidade de dados no geral!\nEngenharia de recursos Hora de criar o objeto que vai conter todos os passos do pré-processamento necessário! Esse passo é muito importante pois algumas estatísticas precisam ser calculadas nos dados de treino isoladamente para não “dar pistas” para modelo sobre as informações contidas nos dados de teste, comprometendo o desempenho do modelo em novos dados.\nDe forma semelhante (mas não igual) ao sklearn.pipeline.Pipeline, disponível para Python, na linguagem R existe o pacote recipes que permite a criação de “receitas” com a função recipe() e que pode ser utilizada em um workflow() para treinar o modelo na sequência.\nSendo assim, algumas das operações realizadas no préprocessamento do modelo:\nBoa parte desse trabalho de criar feature em cima de feature eu aprendi lendo o Feature Engineering and Selection, do Max Kuhn. Metade do trabalho de modelagem é isso aqui, e o livro explica bem o porquê de cada escolha.\nCriar feature: ano; Criar feature: mes; Criar feature: dia da semana; Criar feature: dia do mes; Criar feature: hora que acordou; Criar feature: final de semana; Criar feature: tempo dormindo;; Criar feature: tempo de soneca Criar feature: quarentena; Inputar média movel semanal para preencher as features de weather_temperature_c e air_pressure_pa no RJ; Transformar categóricas em dummy; Remover colunas com dados inválidos para modelo (timestamp); Preencher os dados faltantes de heart_rate_bpm utilizando o algorítmo knn com 2 vizinhos mais próximos; Aplicar o algoritmo Tomek Links, que é um método de undersampling. Caso queira saber mais sobre métodos de undersampling para tratar dados desbalanceados sugiro a leitura deste excelente post! (Os códigos estão em Python porém a explicação da teoria é o que importa neste caso). O Imbalanced Classification with Python, do Jason Brownlee, é uma referência mais completa sobre o assunto, mesmo pra quem usa R no dia a dia como eu.\nPreparar objeto recipe que contém um conjunto de etapas para pré-processamento de dados:\nsleep_recipe \u0026lt;- recipe(mood~., data = sleep_train) %\u0026gt;% step_ordinalscore(weather_type) %\u0026gt;% step_mutate( ano = factor(year(end)), mes = month(end), dia_semana = wday(end) %\u0026gt;% ifelse(. == 7, 0, .), dia_mes = mday(end), end_hour = hour(end), final_de_semana = ifelse(lubridate::wday(start) %in% c(1, 7), \u0026quot;sim\u0026quot;, \u0026quot;nao\u0026quot;) %\u0026gt;% as.factor(), dif_sleep_hours = as.numeric(end - start)/60, dif_nap = as.numeric(window_stop - window_start) / 60, quarentena = ifelse(start \u0026gt; dmy(\u0026quot;20/03/2020\u0026quot;), \u0026quot;sim\u0026quot;, \u0026quot;nao\u0026quot;) %\u0026gt;% as.factor(), nap_minutes = (window_stop - window_start) / 30 ) %\u0026gt;% step_mutate_at(c(\u0026quot;weather_temperature_c\u0026quot;, \u0026quot;air_pressure_pa\u0026quot;), fn = ~ imputeTS::na_ma(.x, k = 7, weighting = \u0026quot;simple\u0026quot;)) %\u0026gt;% step_dummy(all_nominal(), -all_outcomes()) %\u0026gt;% step_mutate_at(starts_with(\u0026quot;ano\u0026quot;), # Fix 2018 nos novos dados fn = ~ ifelse(is.na(.x), 0, .x)) %\u0026gt;% step_rm(start, end, window_start, window_stop)%\u0026gt;% step_knnimpute(heart_rate_bpm, neighbors = 2) %\u0026gt;% themis::step_tomek(mood) %\u0026gt;% prep() # bake(sleep_recipe, new_data = NULL) Finalmente! 🥵\nCom os dados devidamente preparados, vamos ligar as turbinas e partir para modelagem!\ndoParallel::registerDoParallel(4) Modelo Nulo (Baseline) Este não é o tipo de modelo que serve para resolver problemas reais mas pode servir como um bom baseline (“pior que isso não fica”) pois ele vai prever apenas a classe majoritária, e com base nisso, poderemos comparar as métricas de performance do ajuste para saber se nossos modelos estão (no mínimo) performando melhor que um modelo que classifica unicamente 1 classe,\nnull_model \u0026lt;- null_model(mode = \u0026quot;classification\u0026quot;) %\u0026gt;% set_engine(\u0026quot;parsnip\u0026quot;) Definir o objeto workflow:\nnull_wflow_bas \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(null_model) Realizar ajuste final nos dados de treino:\nnull_final_fit_bas \u0026lt;- null_wflow_bas %\u0026gt;% last_fit(sleep_split) Coletar previsões nos dados de teste:\nnull_test_preds_bas \u0026lt;- collect_predictions(null_final_fit_bas) Avaliar desempenho do modelo nos dados de teste:\nnull_test_preds_bas %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot(null_model = T) Modelo nulo pronto! Vamos para a modelagem propriamente dita!\nÁrvore de decisões Este algorítimo é um ótimo ponto de partida pois possui alta explicabilidade, gerando um plot intuitivo e muito fácil de interpretar. As features que aparecem no topo são as mais importantes e cada nó seguinte é gerado a partir de regras que otimizam a divisão dos dados daquele ramo. Já falei com mais detalhes sobre esse tipo de algoritmo baseado em árvores em outro post por aqui.\nExistem recursos interessantes ao trabalhar com árvores, como determinar uma regra de parada ou ainda deixar a árvore crescer e depois realizar a poda. Primeiramente vamos ajusta uma árvore de decisões default e em seguida realizar algum tipo de tunning para tentar obter resultados melhores.\nDefault Os parâmetros default foram definidos baseados na documentação oficial do pacote rpart em https://cran.r-project.org/web/packages/rpart/rpart.pdf e o de/para para definição dos parâmetros na página do pacote parsnip em https://parsnip.tidymodels.org/reference/decision_tree.html\ntree_model_bas \u0026lt;- decision_tree( cost_complexity = 0.01, # cp tree_depth = 30, # maxdepth min_n = 20 # minsplit ) %\u0026gt;% set_engine(\u0026quot;rpart\u0026quot;) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) Definir o objeto workflow:\ntree_wflow_bas \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(tree_model_bas) Ajustar modelo via validação cruzada:\ntree_res_bas \u0026lt;- fit_resamples( tree_wflow_bas, sleep_folds, metrics = metric_set(pr_auc, roc_auc, mn_log_loss), control = control_resamples(save_pred = TRUE) ) # Salvar \u0026quot;cache\u0026quot; da otimizacao saveRDS(tree_res_bas, \u0026quot;tree_res_bas.rds\u0026quot;) Finalizar o modelo:\n# Finalizar workflow com parametros selecionados (default nesse caso) tree_final_wflow_bas \u0026lt;- finalize_workflow( tree_wflow_bas, select_best(tree_res_bas, metric = \u0026#39;mn_log_loss\u0026#39;) ) # Realizar ajuste final nos dados de treino tree_final_fit_bas \u0026lt;- tree_final_wflow_bas %\u0026gt;% last_fit(sleep_split) # Coletar previsões nos dados de teste tree_test_preds_bas \u0026lt;- collect_predictions(tree_final_fit_bas) Vejamos como ficou o modelo baseline:\n(Código do objeto tre_model_bas) tre_model_bas \u0026lt;- tree_final_fit_bas$.workflow[[1]] %\u0026gt;% pull_workflow_fit() rattle::fancyRpartPlot(tre_model_bas$fit, sub = NULL, cex = 0.6) Note que o modelo default se baseia nas features time_before_sleep_seconds e steps. Talvez, com outra combinação de parâmetros seja possível conseguir um modelo uma árvore um pouco maior com resultado igual/melhor.\nComo são apenas duas features, é possível visualizar os regras de classificação a partir de um gráfio de dispersão\nsleep_train %\u0026gt;% ggplot(aes(time_before_sleep_seconds, steps)) + parttree::geom_parttree(data = tre_model_bas$fit, alpha = 0.3) + geom_jitter(aes(color = mood), alpha = 0.7) + scale_color_viridis_d(end = 0.8, direction = 1) Vamos avaliar desempenho do modelo nos dados de teste:\ntree_test_preds_bas %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot() O modelo não esta muito bom… mas também não esta muito ruim para começar! 😅\nCoram 5/8 acertos para classe de interesse, vamos tentar fazer o tunning deste modelo!\nTunning Definir o modelo que será utilizado:\ntree_model_tun \u0026lt;- decision_tree( min_n = tune(), cost_complexity = tune(), tree_depth = tune() ) %\u0026gt;% set_engine(\u0026quot;rpart\u0026quot;) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) # tree_model_tun %\u0026gt;% translate() Definir o objeto workflow:\ntree_wflow_tun \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(tree_model_tun) O grid utilizado foi alterado para tentar previnir que a árvore tenha apenas o nó raiz pois o grid default, combinado com o threshold, estava gerando um “cotoco”.\nmin_n: [1, 5] cost_complexity: (transformed scale): [-10, -1] tree_depth: [10, 20] Definir um grid aleatório para otimização dos hiperparâmetros:\ntree_params \u0026lt;- tree_model_tun %\u0026gt;% parameters() %\u0026gt;% update( min_n = min_n(c(1, 5)), cost_complexity = cost_complexity(), tree_depth = tree_depth(c(10, 20)) ) tree_grid \u0026lt;-grid_regular(tree_params, levels = 3) Ajustar modelo:\ntree_res_tun \u0026lt;- tree_wflow_tun %\u0026gt;% tune_grid( resamples = sleep_folds, grid = tree_grid, metrics = metric_set(roc_auc, mn_log_loss, pr_auc), control = control_grid(save_pred = TRUE) ) # Salvar cache da otimizacao # saveRDS(tree_res_tun, \u0026quot;tree_res_tun.rds\u0026quot;) Impacto de cada hiperparâmetro no resultado das métricas cálculadas para cada modelo:\n(Código do gráfico) id_best_model \u0026lt;- show_best(tree_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) %\u0026gt;% slice(1) %\u0026gt;% pull(.config) plot_tree_tun \u0026lt;- tree_res_tun %\u0026gt;% collect_metrics() %\u0026gt;% mutate(best_model = if_else(.config == id_best_model, \u0026quot;BestModel\u0026quot;, \u0026quot;Try\u0026quot;) # cost_complexity = log(cost_complexity)-10 ) %\u0026gt;% select(.metric, mean, best_model, cost_complexity:min_n) %\u0026gt;% pivot_longer(cost_complexity:min_n, values_to = \u0026quot;value\u0026quot;, names_to = \u0026quot;parameter\u0026quot; ) %\u0026gt;% mutate(parameter = case_when( parameter == \u0026quot;cost_complexity\u0026quot; ~ \u0026quot;Cost-Complexity Parameter\u0026quot;, parameter == \u0026quot;tree_depth\u0026quot; ~ \u0026quot;Tree Depth\u0026quot;, parameter == \u0026quot;min_n\u0026quot; ~ \u0026quot;Minimal Node Size\u0026quot;, ))%\u0026gt;% { ggplot(., aes(value, mean, color = best_model)) + geom_point(alpha = 0.6, show.legend = FALSE) + geom_point(data = subset(., best_model == \u0026#39;BestModel\u0026#39;), size = 4, shape = 3)+ scale_color_manual(values = c(\u0026quot;red\u0026quot;, \u0026quot;black\u0026quot;))+ facet_grid(.metric~parameter, scales = \u0026quot;free\u0026quot;) + labs(x = NULL, y = NULL) } # Codigo para mesmo grafico sem cor para melhor modelo: # autoplot(tree_res_tun) plot_tree_tun %\u0026gt;% plotly::ggplotly()%\u0026gt;% plotly::layout(showlegend = FALSE) %\u0026gt;% plotly::config(displayModeBar = F) 5 Melhores resultados:\nshow_best(tree_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) %\u0026gt;% select(-.estimator, -n, -.config) ## # A tibble: 5 x 6 ## cost_complexity tree_depth min_n .metric mean std_err ## \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 0.1 10 1 mn_log_loss 1.64 0.212 ## 2 0.1 15 1 mn_log_loss 1.64 0.212 ## 3 0.1 20 1 mn_log_loss 1.64 0.212 ## 4 0.1 10 3 mn_log_loss 1.64 0.212 ## 5 0.1 15 3 mn_log_loss 1.64 0.212 Finalizar o modelo com o conjunto de parâmetros encontrados no processo de otimização:\n# finalizar workflow definindo modelo final tree_final_wflow_tun \u0026lt;- finalize_workflow( tree_wflow_tun, select_best(tree_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) ) # Realizar ajuste final nos dados de treino tree_final_fit_tun \u0026lt;- tree_final_wflow_tun %\u0026gt;% last_fit(sleep_split) # Coletar previsões nos dados de teste tree_test_preds_tun \u0026lt;- collect_predictions(tree_final_fit_tun) Vejamos como ficou foi o ajuste do modelo utilizando a configuração obtida no após o tunning final:\n(Código do gráfico) tre_model_tun \u0026lt;- pull_workflow_fit(tree_final_fit_tun$.workflow[[1]]) rattle::fancyRpartPlot(tre_model_tun$fit, sub = NULL, cex = 0.6) Avaliar desempenho do modelo nos dados de teste:\ntree_test_preds_tun %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot() Ao comparar o modelo default com o modelo após o tunning é possível notar que o número de verdadeiros positivos foi menor porém o número de fasos positivos tbm foi menor devido ao elevado trs_fbeta encontrado (maximizando F0.5).\nNo geral, o modelo tunado ficou pior que o modelo default mas como o modelo de árvore de deciões costuma ser bem instável, ainda mais em um cenário de dados desbalanceados vamos apenas guardar estes resultados e dar mais um passo, combinando diversas árvore de decisões!\nRandom Forest O Random Forest é um algoritmo que (de forma simplificada) realiza bootstrap em cima de árvores de decisões (modelos que utilizamos anteriormente) construindo modelos de árvores de decisões em diferentes amostras com diferentes combinações de features e assim uma previsão final é feita após uma “votação entre os modelos”.\nDefault Os parâmetros default foram definidos baseados na documentação oficial do pacote ranger em https://cran.r-project.org/web/packages/ranger/ranger.pdf e o de/para para definição dos parâmetros na página do pacote parsnip em https://parsnip.tidymodels.org/reference/rand_forest.html\n# raiz quadrada do numero de features n_col = ncol(juice(sleep_recipe)) rf_model_bas \u0026lt;- rand_forest( mtry = sqrt(n_col) %\u0026gt;% floor(), # mtry trees = 500, # num.trees min_n = 1 # min.node.size ) %\u0026gt;% set_engine(\u0026quot;ranger\u0026quot;, num.threads = 4, importance = \u0026quot;permutation\u0026quot;) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) Definir o objeto workflow:\nrf_wflow_bas \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(rf_model_bas) Ajustar modelo via validação cruzada:\nrf_res_bas \u0026lt;- fit_resamples( rf_wflow_bas, sleep_folds, metrics = metric_set(roc_auc, mn_log_loss, pr_auc), control = control_resamples(save_pred = TRUE) ) Finalizar o modelo com o conjunto de parâmetros encontrados no processo de otimização:\n# Finalizar workflow com parametros selecionados (default nesse caso) rf_final_wflow_bas \u0026lt;- finalize_workflow( rf_wflow_bas, select_best(rf_res_bas, metric = \u0026#39;mn_log_loss\u0026#39;) ) # Realizar ajuste final nos dados de treino rf_final_fit_bas \u0026lt;- rf_final_wflow_bas %\u0026gt;% last_fit(sleep_split) # Coletar previsões nos dados de teste rf_test_preds_bas \u0026lt;- collect_predictions(rf_final_fit_bas) Avaliar desempenho do modelo nos dados de teste:\nrf_test_preds_bas %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot() Este modelo não fez nenhuma previsão de falso positivo! Porém note que o trs_fbeta ficou bastante alto, o que deve ter ocorrido como reflexo do elevado logloss que indicaria que a incerteza que o modelo tem nas previsões esta alta.\nTunning Definir o modelo que será utilizado:\nrf_model_tun \u0026lt;- rand_forest( mtry = tune(), trees = tune(), min_n = tune() ) %\u0026gt;% set_engine(\u0026quot;ranger\u0026quot;, num.threads = 4, importance = \u0026quot;permutation\u0026quot;) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) # tree_model %\u0026gt;% translate() Definir o objeto workflow:\nrf_wflow_tun \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(rf_model_tun) O grid utilizado tentará valores superiores e inferiores ao número de árvores default do algoritmo e vamos incluir o valor 1 ao min_n pois árvores mais longas neste método podem ser úteis. O mtry será calculado baseado nas informações do dataset de treino.\ntrees: [100, 900] min_n: [1, 40] mtry: [1, 20] Definir técnica de otimização de hiperparâmetros\nrf_grid \u0026lt;-grid_max_entropy( trees() %\u0026gt;% range_set(c(100, 900)), # Default Range: [1, 2000] min_n() %\u0026gt;% range_set(c(1, 40)), # Default Range: [2, 40] finalize(mtry(), sleep_train), size = 30) Ajustar modelo:\nrf_res_tun \u0026lt;- rf_wflow_tun %\u0026gt;% tune_grid( resamples = sleep_folds, grid = rf_grid, metrics = metric_set(roc_auc, mn_log_loss, pr_auc), control = control_grid(save_pred = TRUE) ) # Salvar cache da otimizacao saveRDS(rf_res_tun, \u0026quot;rf_res_tun.rds\u0026quot;) Impacto de cada hiperparâmetro no resultado das métricas cálculadas para cada modelo:\n(Código do gráfico) id_best_model \u0026lt;- show_best(rf_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) %\u0026gt;% slice(1) %\u0026gt;% pull(.config) plot_rf_tun \u0026lt;- rf_res_tun %\u0026gt;% collect_metrics() %\u0026gt;% mutate(best_model = if_else(.config == id_best_model, \u0026quot;BestModel\u0026quot;, \u0026quot;Try\u0026quot;)) %\u0026gt;% select(.metric, mean, best_model, mtry:min_n) %\u0026gt;% pivot_longer(mtry:min_n, values_to = \u0026quot;value\u0026quot;, names_to = \u0026quot;parameter\u0026quot; ) %\u0026gt;% mutate(parameter = case_when( parameter == \u0026quot;mtry\u0026quot; ~ \u0026quot;Randomly Selected Predictors\u0026quot;, parameter == \u0026quot;min_n\u0026quot; ~ \u0026quot;Minimal Node Size\u0026quot;, parameter == \u0026quot;trees\u0026quot; ~ \u0026quot;# Trees\u0026quot; )) %\u0026gt;% { ggplot(., aes(value, mean, color = best_model)) + geom_point(alpha = 0.6, show.legend = FALSE) + geom_point(data = subset(., best_model == \u0026#39;BestModel\u0026#39;), size = 4, shape = 3)+ scale_color_manual(values = c(\u0026quot;red\u0026quot;, \u0026quot;black\u0026quot;))+ facet_grid(.metric~parameter, scales = \u0026quot;free\u0026quot;) + labs(x = NULL, y = NULL) } # Codigo para mesmo grafico sem cor para melhor modelo: # autoplot(rf_res_tun) plot_rf_tun %\u0026gt;% plotly::ggplotly()%\u0026gt;% plotly::layout(showlegend = FALSE) %\u0026gt;% plotly::config(displayModeBar = F) Melhores resultados:\nshow_best(rf_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) %\u0026gt;% select(-.estimator, -n, -.config) Finalizar o modelo com o conjunto de parâmetros encontrados no processo de otimização:\n# finalizar workflow definindo modelo final rf_final_wflow_tun \u0026lt;- finalize_workflow( rf_wflow_tun, select_best(rf_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) ) # Realizar ajuste final nos dados de treino rf_final_fit_tun \u0026lt;- rf_final_wflow_tun %\u0026gt;% last_fit(sleep_split) # Coletar previsões nos dados de teste rf_test_preds_tun \u0026lt;- collect_predictions(rf_final_fit_tun) Vejamos como ficou foi o ajuste do modelo utilizando a configuração obtida no após o tunning final:\nAvaliar desempenho do modelo nos dados de teste:\nrf_test_preds_tun %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot() Note que apesar do maior número de Verdadeiros Positivos, este modelo apresentou um Falso Positivo. Parece estranho pois é exatamente o que queriamos evitar porém é possível notar que o logloss foi bem inferior e o trs_fbeta está bem mais razoavel agora.\nImportancia de cada feature conforme o modelo:\nvip::vip(pull_workflow_fit(rf_final_fit_tun$.workflow[[1]])) Diferente do modelo baseado em 1 unica árvore de decisões, a feature steps não foi tão importante assim. A time_asleep_seconds foi a mais importante mas com a ordem de grandeza muito próxima de time_before_sleep_seconds.\nRandom Forest é um excelente modelo e poderíamos investir mais tempo tentando otimizando sua performance mas para este post acho que já esta suficiente. Vamos para o próximo modelo! 😍\nLightGBM Este modelo consiste em um método de boosting. Também é baseado nos modelos de árvore de decisões, mas, diferentemente do Random Forest, suas árvores são calculadas em sequência, “aprendendo” com o erro das árvores anteriores.\nA mecânica do LightGBM é um pouco diferente do XGBoost. Não entrarei em detalhes sobre a teoria neste post até porque a documentação oficial no github em https://github.com/microsoft/LightGBM é bastante rica, e seus recursos são muito bem apresentados neste link: https://github.com/microsoft/LightGBM/blob/master/docs/Features.rst\nLinks úteis para consulta ao trabalhar com este algoritmo:\nDocumentação oficial: https://lightgbm.readthedocs.io/en/latest/ Excelente post: https://machinelearningmastery.com/light-gradient-boosted-machine-lightgbm-ensemble/ Documentação oficial do pacote treesnip: https://curso-r.github.io/treesnip/articles/working-with-lightgbm-catboost.html Repositório no github do pacote treesnip: https://github.com/curso-r/treesnip Ótimo link para consulta dos parâmetros: https://sites.google.com/view/lauraepp/parameters Default Os parâmetros default foram definidos baseados na documentação oficial do pacote lightgbm em https://lightgbm.readthedocs.io/en/latest/ e o de/para para definição dos parâmetros na página do (incrível 🤩) pacote treesnip em https://github.com/curso-r/treesnip/blob/master/R/lightgbm.R\nlgbm_model_bas \u0026lt;- parsnip::boost_tree( mode = \u0026quot;classification\u0026quot;, trees = 100, # num_iterations learn_rate = 0.1, # fixo min_n = 20, # min_data_in_leaf tree_depth = 6, # max_depth sample_size = 1, # bagging_fraction mtry = 1, # feature_fraction loss_reduction = 0 # min_gain_to_split ) %\u0026gt;% set_engine(\u0026quot;lightgbm\u0026quot;, nthread = 4, importance = \u0026quot;permutation\u0026quot;) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) Definir o objeto workflow:\nlgbm_wflow_bas \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(lgbm_model_bas) Ajustar modelo via validação cruzada:\nlgbm_res_bas \u0026lt;- fit_resamples( lgbm_wflow_bas, sleep_folds, metrics = metric_set(roc_auc, mn_log_loss, pr_auc), control = control_resamples(save_pred = TRUE) ) saveRDS(lgbm_res_bas, \u0026quot;lgbm_res_bas.rds\u0026quot;) Finalizar o modelo com o conjunto de parâmetros encontrados no processo de otimização:\n# Finalizar workflow com parametros selecionados (default nesse caso) lgbm_final_wflow_bas \u0026lt;- finalize_workflow( lgbm_wflow_bas, select_best(lgbm_res_bas, metric = \u0026#39;mn_log_loss\u0026#39;) ) # Realizar ajuste final nos dados de treino lgbm_final_fit_bas \u0026lt;- lgbm_final_wflow_bas %\u0026gt;% last_fit(sleep_split) # Coletar previsões nos dados de teste lgbm_test_preds_bas \u0026lt;- collect_predictions(lgbm_final_fit_bas) Avaliar desempenho do modelo nos dados de teste:\nlgbm_test_preds_bas %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot() Tunning Para o tunning vamos utilizar uma estratégia um pouco diferente. Vamos fixar o número de árvores trees e a taxa de aprendizado learning_rate pois vamos separar mais uma pequena parte dos dados para usar o recurso early_stopping. Esta opção basicamente “trava” o crescimento da árvore caso o modelo não melhore a performance a partir da n-ésima iteração.\nlgbm_model_tun \u0026lt;- parsnip::boost_tree( mode = \u0026quot;classification\u0026quot;, trees = 700, # autotune com early stopping learn_rate = 0.01, # early stopping min_n = tune(), # min_data_in_leaf tree_depth = tune(), # max_depth sample_size = 1, # bagging_fraction, n funciona com goss mtry = tune(), # feature_fraction loss_reduction = tune() # min_gain_to_split ) %\u0026gt;% set_engine(\u0026quot;lightgbm\u0026quot;, nthread = 4, # parametros para early stopping early_stop = 30, validation = .20, eval_metric = \u0026quot;mn_log_loss\u0026quot;, importance = \u0026quot;permutation\u0026quot; # feature_fraction = tune(\u0026quot;feature_fraction\u0026quot;) ) %\u0026gt;% set_mode(\u0026quot;classification\u0026quot;) # tree_model %\u0026gt;% translate() Definir o objeto workflow:\nlgbm_wflow_tun \u0026lt;- workflow() %\u0026gt;% add_recipe(sleep_recipe) %\u0026gt;% add_model(lgbm_model_tun) Definir grid para otimização de hiperparâmetros baseados nas sugestões de github/Laurae2 em uma issue no repositório oficial do modelo\nlightgbm_params \u0026lt;- dials::parameters( # learn_rate(), # learning_rate # trees() # num_iterations min_n(), # min_data_in_leaf tree_depth(c(2, 63)), # max_depth # sample_prop(c(0.4, 1)), # bagging_fraction (vai para sample_size) mtry(), # feature_fraction loss_reduction() # min_gain_to_split ) lgbm_grid \u0026lt;- lightgbm_params %\u0026gt;% finalize(sleep_train) %\u0026gt;% grid_max_entropy(size = 30) Ajustar modelo:\nlgbm_res_tun \u0026lt;- lgbm_wflow_tun %\u0026gt;% tune_grid( resamples = sleep_folds, grid = lgbm_grid, metrics = metric_set(roc_auc, mn_log_loss, pr_auc), control = control_grid(save_pred = TRUE) ) # Salvar cache da otimizacao saveRDS(lgbm_res_tun, \u0026quot;lgbm_res_tun.rds\u0026quot;) Impacto de cada hiperparâmetro no resultado das métricas cálculadas para cada modelo:\n(Código do gráfico) id_best_model \u0026lt;- show_best(lgbm_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;)[1, ] %\u0026gt;% pull(.config) plot_lgbm_tun \u0026lt;- lgbm_res_tun %\u0026gt;% collect_metrics() %\u0026gt;% mutate(best_model = if_else(.config == id_best_model, \u0026quot;BestModel\u0026quot;, \u0026quot;Try\u0026quot;)) %\u0026gt;% select(.metric, mean, best_model, mtry:loss_reduction) %\u0026gt;% pivot_longer(mtry:loss_reduction, values_to = \u0026quot;value\u0026quot;, names_to = \u0026quot;parameter\u0026quot; ) %\u0026gt;% { ggplot(., aes(value, mean, color = best_model)) + geom_point(alpha = 0.6, show.legend = FALSE) + geom_point(data = subset(., best_model == \u0026#39;BestModel\u0026#39;), size = 4, shape = 3)+ scale_color_manual(values = c(\u0026quot;red\u0026quot;, \u0026quot;black\u0026quot;))+ facet_grid(.metric~parameter, scales = \u0026quot;free\u0026quot;) + labs(x = NULL, y = NULL) } # Codigo para mesmo grafico sem cor para melhor modelo: # autoplot(lgbm_res_tun) plot_lgbm_tun %\u0026gt;% plotly::ggplotly()%\u0026gt;% plotly::layout(showlegend = FALSE) %\u0026gt;% plotly::config(displayModeBar = F) Melhores resultados:\nshow_best(lgbm_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) %\u0026gt;% select(-.estimator, -n, -.config) ## # A tibble: 5 x 7 ## mtry min_n tree_depth loss_reduction .metric mean std_err ## \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 2 35 28 0.000000000108 mn_log_loss 0.259 0.00888 ## 2 1 16 5 0.00000160 mn_log_loss 0.267 0.0100 ## 3 4 28 31 0.000507 mn_log_loss 0.272 0.0111 ## 4 5 39 62 0.000164 mn_log_loss 0.273 0.00955 ## 5 2 14 19 0.0642 mn_log_loss 0.274 0.0138 Finalizar o modelo com o conjunto de parâmetros encontrados no processo de otimização:\n# finalizar workflow definindo modelo final lgbm_final_wflow_tun \u0026lt;- finalize_workflow( lgbm_wflow_tun, select_best(lgbm_res_tun, metric = \u0026#39;mn_log_loss\u0026#39;) ) # Realizar ajuste final nos dados de treino lgbm_final_fit_tun \u0026lt;- lgbm_final_wflow_tun %\u0026gt;% last_fit(sleep_split) # Coletar previsões nos dados de teste lgbm_test_preds_tun \u0026lt;- collect_predictions(lgbm_final_fit_tun) Vejamos como ficou foi o ajuste do modelo utilizando a configuração obtida no após o tunning final:\nAvaliar desempenho do modelo nos dados de teste:\nlgbm_test_preds_tun %\u0026gt;% mutate(mood = factor(mood, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;), ordered = TRUE)) %\u0026gt;% conf_mat_plot() Que maravilha! Modelos acertaram mais a classe de interesse do que os anteriores (apesar do default ainda apresentar alta proporção de falsos positivos). Note ainda que o LightGBM após o tunning apresentou as melhores métricas no geral (melhor AUC-PR, menor logloss e um bom equilíbrio no trade-off de Precision x Recall).\nVejamos quais as features mais importantes no ajuste do modelo:\nlgbm_imp_tun \u0026lt;- lightgbm::lgb.importance(lgbm_final_fit_tun$.workflow[[1]]$fit$fit$fit, percentage = T) lgbm_imp_tun%\u0026gt;% mutate(Feature = reorder(Feature, Gain)) %\u0026gt;% ggplot(aes(x = Feature, y = Gain))+ geom_bar(stat = \u0026quot;identity\u0026quot;)+ labs(y = \u0026quot;Importance\u0026quot;, x= \u0026quot;\u0026quot;)+ coord_flip() Seleção do modelo 🤔 Comparar os modelos de forma visual com os gráficos da ROC AUC e da PR AUC:\n(Código do gráfico) auc_plots \u0026lt;- bind_rows( null_test_preds_bas %\u0026gt;% mutate(model = \u0026quot;null baseline\u0026quot;), tree_test_preds_bas %\u0026gt;% mutate(model = \u0026quot;rpart default\u0026quot;), tree_test_preds_tun %\u0026gt;% mutate(model = \u0026quot;rpart tunning\u0026quot;), rf_test_preds_bas %\u0026gt;% mutate(model = \u0026quot;rf default\u0026quot;), rf_test_preds_tun %\u0026gt;% mutate(model = \u0026quot;rf tunning\u0026quot;), lgbm_test_preds_bas %\u0026gt;% mutate(model = \u0026quot;lgbm default\u0026quot;), lgbm_test_preds_tun %\u0026gt;% mutate(model = \u0026quot;lgbm tunning\u0026quot;) ) %\u0026gt;% plot_auc() + plot_annotation(title = \u0026#39;Resultados nos dados de teste\u0026#39;, theme = theme(plot.title = element_text(hjust = 0.4))) auc_plots Apenas olhando o gráfico não da para fazer uma análise conclusiva, vejamos as medidas de qualidade (ordenado por auc_pr):\n(Código da tabela) test_results \u0026lt;- bind_rows( evalue_model(null_test_preds_bas, model = \u0026quot;null baseline\u0026quot;, null_model = TRUE), evalue_model(tree_test_preds_bas, model = \u0026quot;rpart default\u0026quot;), evalue_model(tree_test_preds_tun, model = \u0026quot;rpart tunning\u0026quot;), evalue_model(rf_test_preds_bas, model = \u0026quot;rf default\u0026quot;), evalue_model(rf_test_preds_tun, model = \u0026quot;rf tunning\u0026quot;), evalue_model(lgbm_test_preds_bas, model = \u0026quot;lgbm default\u0026quot;), evalue_model(lgbm_test_preds_tun, model = \u0026quot;lgbm tunning\u0026quot;) ) %\u0026gt;% print_table(round = 4, evalue_model = T) test_results model tp fp fn tn auc_roc auc_pr logloss f1 f05 f2 precision recall trs_fbeta lgbm tunning 6 1 2 72 0.8699 0.7804 0.2190 0.8000 0.8333 0.7692 0.8571 0.7500 0.5937 rf default 4 0 4 73 0.8399 0.6916 0.6613 0.6667 0.8333 0.5556 1.0000 0.5000 0.7140 rf tunning 5 1 3 72 0.8493 0.6658 0.2722 0.7143 0.7812 0.6579 0.8333 0.6250 0.3888 null baseline 0 0 8 73 0.5000 0.5494 0.3236 0.0000 0.1141 lgbm default 6 3 2 70 0.8527 0.5038 0.2313 0.7059 0.6818 0.7317 0.6667 0.7500 0.4286 rpart default 5 9 3 64 0.7312 0.4471 0.3267 0.4545 0.3906 0.5435 0.3571 0.6250 0.5714 rpart tunning 4 7 4 66 0.7243 0.4390 0.3399 0.4211 0.3846 0.4651 0.3636 0.5000 0.7857 O modelo LightGBM após o processo de tunning foi o que apresentou as melhores medidas no geral. Note que o LightGBM com os parâmetro default ficou pior do que o modelo nulo 😱! Isso mostra como o processo de tunning pode ser importante. Além disso note que o modelo rf baseline apresentou o segundo maior AUC-PR mas o pior logloss (note que o threshold está muito alto e as demais métricas não ficaram muito boas).\nPortanto, apenas os modelos LightGBM e Random Forest apresentaram resultados melhores que um modelo nulo (sempre estima a classe majoritária) e como o LightGBM foi o mais satisfatório, este será o modelo selecionado. 😎\nPrevisão em dados novos 💫 Obter as previsões nos novos dados:\ntrs_final \u0026lt;- evalue_model(lgbm_test_preds_tun, model = \u0026quot;lgbm tunning\u0026quot;)$trs_fbeta final \u0026lt;- predict(lgbm_final_fit_tun$.workflow[[1]], new_sleep, type = \u0026quot;prob\u0026quot;) %\u0026gt;% mutate(.pred_class = ifelse(.pred_Ruim \u0026gt;= trs_final, \u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;)) # new_sleep %\u0026gt;% filter(final$.pred_class == \u0026quot;Ruim\u0026quot;) Comparar a quantidade de previsões de cada classe com o conjunto de treino/teste:\n(Código para tabela abaixo) tab \u0026lt;- full_join(sleep_train %\u0026gt;% count(mood) %\u0026gt;% mutate(prop = n/sum(n)*100), sleep_test %\u0026gt;% count(mood) %\u0026gt;% mutate(prop = n/sum(n)*100), by = \u0026quot;mood\u0026quot;) %\u0026gt;% full_join(final %\u0026gt;% count(mood = .pred_class) %\u0026gt;% mutate(prop = n/sum(n)*100)) %\u0026gt;% print_table(round = 2, columns = list( n.x = colDef(name = \u0026quot;N\u0026quot;), prop.x = colDef(name = \u0026quot;(%)\u0026quot;, align = \u0026quot;left\u0026quot;), n.y = colDef(name = \u0026quot;N\u0026quot;), prop.y = colDef(name = \u0026quot;(%)\u0026quot;, align = \u0026quot;left\u0026quot;), n = colDef(name = \u0026quot;N\u0026quot;), prop = colDef(name = \u0026quot;(%)\u0026quot;, align = \u0026quot;left\u0026quot;) ), columnGroups = list( colGroup(name = \u0026quot;Train\u0026quot;, columns = c(\u0026quot;n.x\u0026quot;, \u0026quot;prop.x\u0026quot;)), colGroup(name = \u0026quot;Test\u0026quot;, columns = c(\u0026quot;n.y\u0026quot;, \u0026quot;prop.y\u0026quot;)), colGroup(name = \u0026quot;New Data\u0026quot;, columns = c(\u0026quot;n\u0026quot;, \u0026quot;prop\u0026quot;)) )) tab (Código do cálculo das medidas abaixo) # ref: https://en.wikipedia.org/wiki/Sensitivity_and_specificity # Obter medidas da matriz de confusao tp = evalue_model(lgbm_test_preds_tun, model = \u0026quot;lgbm tunning\u0026quot;)$tp tn = evalue_model(lgbm_test_preds_tun, model = \u0026quot;lgbm tunning\u0026quot;)$tn fn = evalue_model(lgbm_test_preds_tun, model = \u0026quot;lgbm tunning\u0026quot;)$fn fp = evalue_model(lgbm_test_preds_tun, model = \u0026quot;lgbm tunning\u0026quot;)$fn # true positive rate tpr = tp / (tp + fn) # false negative rate fnr = 1 - tpr #false positive rate fpr = fp / (fp + tn) Como nosso modelo foi otimizado para ser menos “alarmista” (com uma Taxa de Falso Positivo: 2.7%) é possível que o modelo tenha deixado passar alguns dias em que mood==\"Ruim\" (Taxa de Falso Negativo: 25%). Não vejo isto como um grande problema pois dado a pequena quantidade de dados disponíveis até que o resultado para a classe de interesse estava bem razoável (Taxa de Verdadeiro Positivo: 75%).\nPara não alongar aida mais o post com análise exploratória das previsões, vamos comparar como foram as previsões nestes novos dados em relação aos dados utilizados para treinar o modelo e ver se, pelo menos visualmente, o modelo esteja conseguindo prever de semelhante ao padrão de dados conhecidos.\nA técnica UMAP será utilizada com a finalidade de reduzir a dimensionalidade para visualização:\n(Código para gráfico abaixo) # Treinar UMAP: sleep_umap \u0026lt;- juice(sleep_recipe) %\u0026gt;% select(-mood) %\u0026gt;% umap::umap() # Aplicar em novos dados: new_data \u0026lt;- bake(sleep_recipe, new_sleep) %\u0026gt;% select(-mood) new_data_umap \u0026lt;- predict(sleep_umap, new_data) # Preparar plot comparando treino com novos dados: umap_plot \u0026lt;- bind_rows( sleep_umap$layout %\u0026gt;% as_tibble() %\u0026gt;% bind_cols(juice(sleep_recipe) %\u0026gt;% select(mood)) %\u0026gt;% bind_cols(dataset = \u0026quot;Train\u0026quot;) , new_data_umap %\u0026gt;% as_tibble() %\u0026gt;% mutate(mood = factor(final$.pred_class, levels = c(\u0026quot;Ruim\u0026quot;, \u0026quot;Bom\u0026quot;))) %\u0026gt;% bind_cols(dataset = \u0026quot;New Data\u0026quot;) ) %\u0026gt;% mutate(dataset = factor(dataset, levels = c(\u0026quot;New Data\u0026quot;, \u0026quot;Train\u0026quot;))) %\u0026gt;% { ggplot(., aes(x = V1, y = V2, color = mood, shape = mood))+ geom_point(show.legend = F)+ geom_point(aes(x = V1, y = V2, color = mood), data = subset(., mood == \u0026#39;Ruim\u0026#39;), size = 2, shape = 3)+ labs(x = \u0026quot;\u0026quot;, y = \u0026quot;\u0026quot;, title = \u0026quot;UMAP (Uniform Manifold Approximation and Projection)\u0026quot;)+ scale_color_viridis_d(end = 0.8, direction = 1)+ # scale_size_manual(values=c(2,5))+ theme(legend.position = \u0026quot;bottom\u0026quot;)+ facet_wrap(~dataset) } umap_plot %\u0026gt;% plotly::ggplotly()%\u0026gt;% plotly::layout(showlegend = FALSE) %\u0026gt;% plotly::config(displayModeBar = F) Parece que o modelo fez previsões nos novos dados em um padrão específico dos dados (à direita) enquanto que nos dados de treino podemos observar alguma informação da classe Ruim na massa de dados à esquerda. Isso pode estar acontecendo devido ao foco que demos para minimizar falsos positivos. É uma boa indicação para analisar melhor o padrão que o modelo esta aprendendo em relação aos falsos negativos.\nConclusão 🍻 Apesar da pequena quantidade dados dados disponíveis, conseguimos ajustar um modelo razoável para prever a qualidade de sono em dias que não foram registrados!\nUtilizamos diversas técnicas de Machine Leaning combinadas em dados reais (que não são nada comportados) e, obviamente, para colocar um modelo em produção na vida real seria necessário aplicar mais uma série de análises, além de entender como o modelo está funcionando, aplicando técnicas de XAI (Explainable AI) mas isso pode ser assunto para um futuro post, hora de dormir! 😴\nEspero que este pequeno “case” seja útil para você! Para mim foi ótimo combinar a prática do uso do pacote tidymodels para resolver um problema com dados reais com um estudo que me trouxe mais auto-conhecmento e um monte de insights pessoais.\nVia Giphy Referências 🧳 https://juliasilge.com/blog/wind-turbine/ https://juliasilge.com/blog/hotels-recipes/ https://juliasilge.com/blog/xgboost-tune-volleyball/ http://www.rebeccabarter.com/blog/2020-03-25_machine_learning/ https://machinelearningmastery.com/imbalanced-classification-with-python/ https://machinelearningmastery.com/threshold-moving-for-imbalanced-classification/ https://machinelearningmastery.com/undersampling-algorithms-for-imbalanced-classification/ https://machinelearningmastery.com/fbeta-measure-for-machine-learning/ https://sites.google.com/view/lauraepp/parameters https://github.com/microsoft/LightGBM/issues/695 A importância de dormir bem — USP Espaço Aberto Tour of Evaluation Metrics for Imbalanced Classification — Machine Learning Mastery ROC Curves and Precision-Recall Curves for Imbalanced Classification — Machine Learning Mastery Perguntas frequentes Qual foi a fonte dos dados de sono usados no modelo?\nOs dados vêm do aplicativo Sleep Cycle, usado desde 2017, que registra variáveis como frequência cardíaca, passos, tempo na cama, ronco e o humor relatado ao acordar (mood).\nComo o problema de dados desbalanceados foi tratado?\nFoi usado o método de undersampling Tomek Links para lidar com o desbalanceamento da target mood, além da escolha de um threshold que maximiza a medida F-Beta (Beta = 0.5), priorizando a precisão.\nQual modelo teve o melhor desempenho para prever o humor ao acordar?\nO LightGBM após o processo de tunning apresentou as melhores métricas no geral, incluindo a maior AUC-PR. Ele foi o modelo escolhido para prever o humor nos dias em que esse dado não foi registrado.\n","date":"4 de março de 2021","externalUrl":null,"permalink":"/post/2021-02-28-qualidade-do-sono-machine-learning/","section":"Posts","summary":" Qualidade de sono? 🤨 Como funciona aplicativo Sleep Cycle? Objetivo 🎯 Explorar dados 🔎 Limpeza e preparação dos dados Imputar dados de fontes externas Insights Reter dados Modelagem 🚀 Amostragem Engenharia de recursos Modelo Nulo (Baseline) Árvore de decisões Random Forest LightGBM Seleção do modelo 🤔 Previsão em dados novos 💫 Conclusão 🍻 Referências 🧳 Qualidade de sono? 🤨 Sim, exatamente! Neste post analisaremos dados de um tracking que venho fazendo desde 2017 com informações relacionadas à um sono de qualidade.\n","title":"Prevendo a qualidade do sono utilizando Machine Learning","type":"post"},{"content":"Link do app publicado: https://gomes555.shinyapps.io/diaversario/\nLink do repositório no github: https://github.com/gomesfellipe/diaversario\nApp simples para calcular quantidade de dias de vida.\nPara utiliza-lo basta inserir a data do nascimento como mostra a imagem:\nHow to # Códigos para calcular as medidas:\nR : R born \u0026lt;- as.Date(\u0026#34;1993-12-14\u0026#34;) today \u0026lt;- Sys.Date() # Quantos dias de vida difftime(today, born) # Completa 10.000 dias de vida em: born+days(10000) # Faltam difftime(born+days(10000), today) Python: Python from datetime import datetime, timedelta today = datetime.today() born = datetime.strptime(\u0026#39;1993-12-14\u0026#39;, \u0026#39;%Y-%m-%d\u0026#39;) # Quantos dias de vida print(\u0026#34;Time difference of\u0026#34;, str((today-born).days), \u0026#34;days\u0026#34;) # Completa 10.000 dias de vida em: str(born + timedelta(days=10000)) # Faltam print(\u0026#34;Time difference of\u0026#34;,str((born + timedelta(days=10000) - today).days), \u0026#34;days\u0026#34;) ","date":"4 de fevereiro de 2021","externalUrl":null,"permalink":"/projects/diaversario/","section":"Projetos","summary":"Link do app publicado: https://gomes555.shinyapps.io/diaversario/\nLink do repositório no github: https://github.com/gomesfellipe/diaversario\nApp simples para calcular quantidade de dias de vida.\nPara utiliza-lo basta inserir a data do nascimento como mostra a imagem:\nHow to # Códigos para calcular as medidas:\nR : R born \u003c- as.Date(\"1993-12-14\") today \u003c- Sys.Date() # Quantos dias de vida difftime(today, born) # Completa 10.000 dias de vida em: born+days(10000) # Faltam difftime(born+days(10000), today) Python: Python from datetime import datetime, timedelta today = datetime.today() born = datetime.strptime('1993-12-14', '%Y-%m-%d') # Quantos dias de vida print(\"Time difference of\", str((today-born).days), \"days\") # Completa 10.000 dias de vida em: str(born + timedelta(days=10000)) # Faltam print(\"Time difference of\",str((born + timedelta(days=10000) - today).days), \"days\")","title":"diaversario","type":"projects"},{"content":"","date":"17 de julho de 2020","externalUrl":null,"permalink":"/tags/acoes/","section":"Tags","summary":"","title":"Acoes","type":"tags"},{"content":"Link do repositório no github: https://github.com/gomesfellipe/acompanhacoes\nO objetivo do pacote acompanhacoes é permitir a portabilidade de um dashboard desenvolvido para o acompanhamento de ativos de diferentes naturezas de forma prática no dia a dia. A idéia deste shiny foi inspirada neste post do meu blog.\nO Dashboard é uma POC (proof of concept) de uma ferramenta que possibilita o acompanhamento automatizado da tabela financeira de um portifólio com a coleta de dados de cotações em tempo real, incluindo cálculo de Ganho/Perda (caso decida fazer a desmontagem no tempo atual) e análise automatizada do portifólio.\nO app shiny foi desenvolvido utilizando o framework golem que trás uma série de configurações e facilitam na hora de implementar o app em produção. O app possui um script Dockerfile que é gerado automaticamente utilizando a função golem::add_dockerfile().\nOs dados são obtidos utilizando a função quantmod::getQuote(\u0026quot;\u0026lt;stock\u0026gt;\u0026quot;) para obter dados em tempo real (com defasagem de 15 minutos) e utilizando a função quantmod::(\u0026quot;\u0026lt;stock\u0026gt;\u0026quot;, get = \u0026quot;stock.prices\u0026quot;, from = first_day_year) intradiários fornecidos pela api do Yahoo Finance das cotações do dia anterior.\nInstalação # Para instalar a versão de desenvolvimento do aplicativo execute o comando:\nR devtools::install_github(\u0026#34;gomesfellipe/acompanhacoes\u0026#34;, INSTALL_opts = \u0026#39;--no-lock\u0026#39;) Ou faça o download da pasta do repositório e execute:\nR devtools::install(\u0026#34;/path_to/acompanhacoes\u0026#34;) Uso # Após instalar o pacote, execute os comandos para executar o dashboard no R:\nR library(acompanhacoes) run_app() Veja como é a tela inicial do dashboard:\nPara acessar o dashboard no meu servidor consulte: https://gomes555.shinyapps.io/acompanhacoes/\nAssim que o dashboard for aberto, serão exibidos resultados para um portfólio arbitrário fornecido como exemplo, exibindo tabelas financeiras com as seguitnes informações:\nCampo Subcampo Descrição Medotologia Montagem Cotação inicio Valor no momento da compra input Montagem Quantidade Quantidade de lotes comprados input Montagem Volume Inicio Volume total da compra cot_ini * qtd Desmontagem Cotacao Atual Valor do ativo no momento atual real-time Desmontagem Volume Atual Volume total atual cot_atual * qtd Resultado Ganho/Perda Valor de ganho/perda caso venda hoje vol_atual - vol_ini Resultado Resultado Bruno Porcentagem de lucro ganho_perda / vol_ini * 100 A próxima seção trará as informações necessárias para se realizar a carga no Dashboad.\nInput # O dashboard tem 3 abordagens quanto ao input dos dados:\nSem input: O dashboard vai carregar a carteira exemplo que utilizei neste post do meu blog; Input manual: O dashboard vai exibir as estatísticas baseadas no input do usuário; Usuário vip: O dashboard vai exibir a carteira \u0026ldquo;reservada\u0026rdquo;, pré-definida pelo desenvolvedor, após fornecer sua chave de acesso. Sempre que alguma dessas três ações forem executadas, os dados das cotações informadas no input serão coletados utilizando funções do pacote quantmod, que fornecem as cotações via api do Yahoo Finance.\nAs seções a seguir ajudarão a entender como utiliza-los.\n1. Sem input # O Dashboard carrega o conjunto de dados acompanhacoes::input_exemplo no momento que é inicializado com a finalidade de servir como exemplo e apresentação da ferramenta. Veja qual o formato do arquivo:\nSaída \u0026gt; acompanhacoes::input_exemplo # A tibble: 3 x 3 symbol cot_ini qtd \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; 1 TUPY3.SA 24.4 200 2 ELET3.SA 19.7 150 3 BTC-USD 31747. 0.032 Obs.: Carteira elaborada de forma arbitrária para servir como exemplo\n2. Input manual # O arquivo fornecido como input para o Dashboard precisa conter a palavra \u0026ldquo;portfolio\u0026rdquo; (como por exemplo: input_portfolio.txt) e estar no seguinte formato:\nSaída symbol, cot_ini, qtd TUPY3.SA, 24.4, 200 ELET3.SA, 19.7, 150 PTBL3.SA, 5.80, 100 MGLU3.SA, 35.33, 100 TOTS3.SA, 19.28, 200 BTC-USD, 28000, 0.01 BTC-USD, 31747, 0.032 BTC-USD, 49499.37, 0.0101 Após definir sua cateira com os valores pagos no momento da compra e informar a quantidade comprada clique na lupa 🔎 para buscar o arquivo ou arraste para o campo indicado:\nSendo assim, os resultados serão exibidos em tempo real de forma automática.\nObs.: O exemplo apresentado no gif é do arquivo portfolio_vip.txt, que é carteira elaborada de forma arbitrária para servir como exemplo.\n3. Usuário vip! ⭐ (Opcional) # Para habilitar o vip talvez pareça um pouco mais complicado porém pode ser um recurso muito útil para ajudar a acompanhar o investimentos pois possui a vantagem de permitir o acesso ao portfolio de forma protegida (eu mesmo tenho usado no meu dia a dia e aceito sugestões de melhora nesse mecanismo para facilitar a experiência do usuário). Trata-se de configurar dois arquivos no diretório raiz de modo que o dashboard só irá carregar caso seja informada a senha de acesso.\nOs dois arquivos de configuração são:\nportifolio_vip.txt: Um arquivo na extensão txt com informações da cotação no momento da compra e a quantidade adquirida. Existe um arquivo de exemplo no repositório de forma que o desenvolvedor possa adaptar para sua carteira.\nDica: Sugiro que o inclua o .txt no seu .gitignore caso deseje manter a privacidade da sua carteira na hora de fazer o versionamento);\nvip.rds: Um objeto R do tipo vetor que contenha um ou mais elementos que serão utilizados como chave de acesso do arquivo portifolio_vip.txt.\nPara criar o vetor defina a raíz do diretório como diretório de trabalho e execute os comandos:\nSaída vip \u0026lt;- c(\u0026#34;senha\u0026#34;) saveRDS(vip, vip.rds) Com estes dois arquivos definidos na pasta raiz do diretório do dashboard, execute os comandos para executar o Dashboard:\nSaída library(acompanhacoes) run_app() Parabéns! Se chegou té aqui agora você possui um Dashboard com um panorama geral de informações (quase) em tempo real para auxiliar na tomada de decisão no momento da desmontagem de algum ativo!\nDica: Caso queria publicar esse dashboard com 1 linha de código basta criar um usuário no site https://www.shinyapps.io/, seguir a instruções e subir a aplicação utilizando rsconnect::deployApp().\nEstatísticas da carteira # Esta seção ainda esta em desenvolvimento e totalmente aberta à sugestões. Veja como é a tela de Estatísticas da carteira:\n(Em desenvolvimento)\nDisclaimer # Os arquivos aqui apresentados não representam meu portfólio e também não estou sugerindo estas opções de carteiras. Para saber a origem deste input consulte o post do meu blog onde utilizo estes ativos como exemplo na construção de uma portfólio fictício. A idéia é que o usuário entre com os dados do seu portfólio para cada compra efetuada.\nA responsabilidade de manter a privacidade da carteira é totalmente do usuário, mantenha o arquivo portifolio_vip.txt salvo em seu computador local e caso use controle de versões inclua este arquivo no seu arquivo .gitignore.\nNenhum arquivo inputado será persistido.\nPróximos passos # Para saber quais serão os próximos passos e saber como você pode contribuir com o desenvolvimento deste pacote consulte a aba de Projects do github.\nO pacote ainda esta em fase de desenvolvimento e quando estiver completo será submetido ao CRAN!\nLicença # Sinta-se a vontade para utilizar, reproduzir e modificar o código respeitando os termos da licença.\n","date":"17 de julho de 2020","externalUrl":null,"permalink":"/projects/acompanhacoes/","section":"Projetos","summary":"Link do repositório no github: https://github.com/gomesfellipe/acompanhacoes\nO objetivo do pacote acompanhacoes é permitir a portabilidade de um dashboard desenvolvido para o acompanhamento de ativos de diferentes naturezas de forma prática no dia a dia. A idéia deste shiny foi inspirada neste post do meu blog.\nO Dashboard é uma POC (proof of concept) de uma ferramenta que possibilita o acompanhamento automatizado da tabela financeira de um portifólio com a coleta de dados de cotações em tempo real, incluindo cálculo de Ganho/Perda (caso decida fazer a desmontagem no tempo atual) e análise automatizada do portifólio.\n","title":"AcompanhAções","type":"projects"},{"content":"","date":"17 de julho de 2020","externalUrl":null,"permalink":"/tags/dashboard/","section":"Tags","summary":"","title":"Dashboard","type":"tags"},{"content":"","date":"17 de julho de 2020","externalUrl":null,"permalink":"/tags/financas/","section":"Tags","summary":"","title":"Financas","type":"tags"},{"content":"","date":"25 de março de 2020","externalUrl":null,"permalink":"/tags/bolsa-de-valores/","section":"Tags","summary":"","title":"Bolsa-De-Valores","type":"tags"},{"content":" Por que investir? Como esta sua situação financeira? Caso tenha alguma reserva pode ser interessante pensar em investimentos pois a poupança já não é mais garantia de lucro no longo prazo, não acredita?\nEstamos no final do primeiro trimestre de 2020 e desde 2019 já liam-se notícias como esta abaixo que levam à reflexão sobre reeducação financeira pois alertam sobre a necessidade da busca por novas oportunidades de investimento.\nFonte: https://noticias.r7.com/economia/economize/poupanca-em-baixa-exige-busca-por-novos-investimentos-em-2020-25122019 TL;DR\nO post mostra como montar uma carteira de investimentos combinando renda fixa e renda variável usando a Regra dos 80. Um modelo Prophet, do Facebook, é treinado para prever o comportamento de ações e do Bitcoin a partir de séries históricas. Ao final, um bot no Telegram envia automaticamente uma tabela financeira com ganhos e perdas da carteira em tempo real. Para uma visão histórica da análise de mercado de criptomoedas com R, veja este post de 2017. A evolução desse tipo de análise levou ao desenvolvimento de agentes de IA multiagente para Bitcoin em 2025.\nCom a finalidade de fomentar um pouco a discussão sobre investimentos, trouxe nesse post algumas sugestões e idéias de como elaborar uma carteira e otimizar as escolhas para equilibrar risco em novos investimentos combinando elementos de estatística, machine learning e programação em R.\nAo final do post criaremos um robô no telegram que coletará os dados das cotações adquiridas, aplicará o modelo Prophet do Facebook para forecast e analisará a desmontagem da carteira segundo os critérios estabelecidos e enviará mensagens para nós com uma tabela financeira automatizada via Telegram como mostra na animação:\nAVISO: Este post não tem como finalidade ser um guia de investimentos (Já existem muitas consultorias especializadas nisso por ai). Todos as decisões tomadas como diversificação da carteira, seleção de ações e critérios para desmontagem da carteira são exemplos e servem para ilustrar algumas possibilidades que um cientista de dados têm na hora de desenvolver ferramentas para auxiliar à tomada de decisão.\nDiferença de poupar e investir De acordo com um especialista entrevistado pela InfoMoney:\n“Poupar é guardar dinheiro para usar no futuro, comprar alguma coisa com ele. Investimento é juntar dinheiro, não mexer nele, para que este gere rendimentos e aí sim, usar os lucros mais para frente. É o recomendado para quem quer viver de renda no futuro, por exemplo” (…) InfoMoney - Ago 2015 Ou seja, poupar é acumular agora para utilizar depois, e normalmente envolve mudança de hábitos, pois requer uma redução nos gastos pessoais e familiares, já investir é usar esse dinheiro poupado em aplicações que rendam.\nComo todo mundo sabe, não existe investimento sem risco e este risco deve ser controlado e utilizado a nosso favor de forma que gere alguma segurança financeira.\nMontagem da carteira Não colocar todos os ovos na mesma cesta significa que você deve diversificar o seu investimento. Provavelmente você já ouviu essa frase alguma vez na vida e ela certamente faz sentido!\nDiversificar a carteira irá proteger seus investimentos diminuindo o risco pois, imagine só, você investe todo o seu dinheiro em uma empresa e ela passa por alguma crise assim seu dinheiro estará todo comprometido!\nExistem diversos motivos para se diversificar a carteira mas acho que essa metáfora dos ovos já resume bem pois acredito que ninguém queira perder tudo em uma queda.\nComo dividir a carteira? Dependendo do risco que você deseja se expor existem muitas formas de preparar a carteira mas a idéias principal consiste em atingir um equilíbrio entre dois tipos de investimento:\nRenda fixa: Menor exposição, menor risco (ex.: CDI, Selic e TR) Renda variável: Maior exposição, maior risco (ex: Ações, Commodities, Imóveis) Para ajudar a dividir a carteira de investimentos neste post utilizaremos a chamada Regra (ou Lei) dos 80. A estratégia é a seguinte: subtraia da sua idade o número 80. O resultado dessa conta vai indicar o percentual a ser investido em renda variável. Por exemplo, no meu caso: tenho 26 anos, portanto \\(80-26 = 54\\%\\) deverá ser investido em renda variável. Aos 53 anos esse percentual vai cairá para a metade, \\(27\\%\\).\nA idéias principal por trás desta regra que é que a cada ano que passa, 1% do montante da renda variável deva ser direcionado para a renda fixa.\nPara testar diferentes valores seguindo esta regra desenvolvi uma função que se chama montagem80() (que já está disponível no github). Vejamos alguns resultados para diferentes cenários e vamos selecionar um para seguir com a montagem da carteira:\n# https://gist.github.com/gomesfellipe/a74710a63b3c8637166b538ad2f460f5 devtools::source_gist(\u0026quot;a74710a63b3c8637166b538ad2f460f5\u0026quot;, quiet = T) 1. Entrada de R$20.000,00 👈\nmontagem80(entrada = 20000, idade = 26) ## • Entrada: R$R$20.000,00 ## └─ Renda fixa: R$9.200,00 ## └─ Renda variavel: R$10.800,00 ## (Acao + Cryptomoeda): ## R$9.720,00 + R$1.080,00 2. R$ 5.000,00 em ações\nmontagem80(variavel = 10800, idade = 53) ## • Entrada: R$R$40.000,00 ## └─ Renda fixa: R$29.200,00 ## └─ Renda variavel: R$10.800,00 ## (Acao + Cryptomoeda): ## R$9.720,00 + R$1.080,00 Utilizaremos a primeira (1.) configuração que esta assinalada em vermelho como exemplo, onde:\nEntrada: R$20.000,00 Renda fixa: R$9.200,00 Renda Variável (Acoes): R$9.720,00 Renda Variável (Crypt): R$1.080,00 Note que a entrada deve ser o dobro na segunda (2.) configuração caso deseje investir R$10.800,00 (que é o valor sugerido aos 26 anos para uma entrada de R$20.000,00)\nApós definir a quantidade a ser investida é hora de planejar a próxima etapa: a diversificação.\nDiversificação da carteira A diversificação é uma técnica para gestão do risco que visa distribuir o capital investido em uma variedade de investimentos dentro de da nossa carteira.\nAssim, o risco do portfólio é consideravelmente reduzido pois reduzimos a volatividade e criamos um equilíbrio onde um desempenho positivo de um ativo neutraliza as baixas ocorridas em outras aplicações.\nvia GIPHY Além disso a diversificação pode ser tanto coma renda variável quanto com a renda fixa. Mas lembre-se, não existe uma receita mais eficiente!\nRenda fixa Normalmente, também diversificamos nossa renda fixa porém como gostaria de focar nas análises de renda variável utilizaremos o simulador disponível no site https://verios.com.br/ neste link para selecionar apenas um título:\nFonte: https://simulador-tesouro-direto.verios.com.br/ Como exemplo, escolhi o Tesouro Prefixado 2015 (LTN), note que com essa escolha o lucro planejado seria de quase 3 mil reais nos próximos 5 anos.\nAVISO: Lembrando que esta seleção é apenas um exemplo e existem diversas informações a serem levadas em conta ao se fazer esta escolha além de se poder diversificar também. Convido o leitor a procurar saber mais sobre os tipos, prós e contras do Tesouro Direto.\nRenda variável Para elaboração da parte da renda variável da carteira selecionei duas ações que são inversamente correlacionadas (de forma totalmente arbitrária) baseado no excelente post \"Estudo de correlação entre ações da Bolsa de Valores de São Paulo\" escrito por Victor Gomes onde o autor faz um estudo de correlações das séries históricas de ações de diferentes setores.\nAlém disso, o Bitcoin será selecionado para completar a carteira de renda variável como um ativo de alto risco com bastante volatividade. Mas você deve estar se perguntando, por que assumir este risco?\nExistem muitas histórias de pessoas que ficaram milionárias com o Bitcoin pela sua valorização inesperada ao longo do tempo, como por exemplo o adolescente que ficou milionário aos 18 anos usando bitcoins após fazer aposta com os pais.\nEntão eu acho que 10% dessa nossa carteira (não esqueça que podemos ter mais de uma carteira) é um risco que pode valer a pena correr e por isso vou incluí-lo.\nPortanto, para este exemplo consideramos:\nTUPY3.SA: Tupy ELET3.SA: Centrais Eletricas Brasileiras SA BTC-USD: Bitcoin portifolio = c(\u0026quot;TUPY3.SA\u0026quot;,\u0026quot;ELET3.SA\u0026quot;, \u0026quot;BTC-USD\u0026quot;) AVISO: Volto a frisar que as escolhas das ações foram feitas de forma arbitrária. Estamos em tempos de incerteza atualmente por conta do corona vírus (espero que todos fiquem bem) o que leva algumas escolhas à serem ainda mais complexas e imprevisíveis.\nObter dados A aquisição das série históricas das cotações destes ativos desde 01/01/2016 foram obtidas utilizando o pacote tidyquant que nos retorna os dados das cotações das ações informadas em formato “arrumado” (ou seja, familiar com funções do tidyverse), veja:\nlibrary(tidyquant) # aquisicao de dados financeiros stocks \u0026lt;-map_df(portifolio, ~tq_get(.x, get = \u0026quot;stock.prices\u0026quot;, from = \u0026quot; 2016-01-01\u0026quot;)) saveRDS(stocks, \u0026quot;stocks.rds\u0026quot;) Veja as linhas iniciais do dataset obtido:\nstocks %\u0026gt;% head() %\u0026gt;% kable2() Existem uma série de vantagens de se trabalhar com os dados neste formato em R, veremos o porque nas próximas seções.\nArrumar dataset O formato tsibble é um formato moderno para se trabalhar com séries temporais trazendo a filosofia do tidyverse para os dados de séries temporais facilitando o fluxo de trabalho.\nDiversos outros pacotes podem ser combinados utilizando os dados no formato do pacote tsibble como os pacotes fable e o prophet (sugiro a leitura para quem nao conhece) para aplicação de modelagem de séries temporais.\nVeja como é o fluxo ao trabalhar com objetos do tipo tsibble\nFonte: https://blog.earo.me/2018/12/20/reintro-tsibble/ library(tsibble) # series temporais arrumadas tbl_stocks \u0026lt;- stocks %\u0026gt;% as_tsibble(key = symbol, index = date) Após importar e arrumar o dataset, seguimos para os próximos passos.\nTransformar Após converter para tsibble, vamos preencher alguns gaps da bolsa como por exemplo os finais de semana (quando a bolsa de valores fica fechada) com o mesmo valor do dia anterior (Para este exemplo vamos fazer esse preenchimento dos gaps do final de semana mas não é sempre é necessário):\ntbl_stocks \u0026lt;- tbl_stocks %\u0026gt;% fill_gaps() %\u0026gt;% tidyr::fill(c(open, high, low, close, volume, adjusted),.direction = \u0026quot;down\u0026quot;) Com os dados arrumados vamos a algumas visualizações.\nVisualizar Vejamos qual foi o comportamento das séries históricas que coletamos desde o início de 2016:\nlibrary(forecast) # series temporais library(fpp3) # series temporais d2 \u0026lt;- tbl_stocks %\u0026gt;% group_by(symbol) %\u0026gt;% summarise(y = mean(close)) autoplot(tbl_stocks)+ geom_line(aes(group = symbol), color = \u0026quot;black\u0026quot;, show.legend = F) + facet_wrap(~symbol, scales = \u0026quot;free_y\u0026quot;, ncol = 1)+ geom_ma(n=6*30, color = \u0026quot;red\u0026quot;) + theme(legend.position = \u0026quot;none\u0026quot;)+ labs(subtitle = \u0026quot;média móvel n = 6 meses\u0026quot;, caption = \u0026quot;gomesfellipe.github.io\u0026quot;) Note que a série do Bitcoin é a mais imprevisível, houve um pico em 2018 mas após isso não houve nenhum grande pico como aquele. Em breve ocorrerá o Halving (a contagem regressiva pode acompanhada neste link) que é um processo de choque de oferta e ocorre aproximadamente a cada 4 anos e pode ser uma boa oportunidade de retorno.\nAs duas séries da bolsa de valores não parecem ter uma correlação muito forte, os picos ocorrem de forma alternada e isto pode ser uma característica boa para a carteira pois caso uma delas entre em crise a outra poderá estar em uma fase boa.\nNota: Esta queda abrupta que ocorreu na bolsa no início de 2020 é o reflexo da Pandemia CODVID-19 que já começou a apresentar alguns casos no Brasil e isso certamente tem gerando muita incerteza na bolsa de valores. Nem eu nem ninguém sabe o que pode acontecer, estou na torcida para que todos fiquem bem e pelo sucesso na contenção desse vírus! Correlações Para estudar melhor as conjecturas formadas ao observar o comportamento das séries histórias (de que os picos e vales se alternam) vamos conferir olhada nos gráficos de dispersão e coeficientes de correlação de Spearman:\npoints_loess \u0026lt;- function(data, mapping){ ggplot(data = data, mapping = mapping) + geom_point(alpha = 0.3,size=0.5) + geom_smooth(method = \u0026quot;loess\u0026quot;) } tbl_stocks %\u0026gt;% as_tibble() %\u0026gt;% select(symbol, date, close) %\u0026gt;% spread(key = symbol, value = close) %\u0026gt;% GGally::ggpairs(columns = 2:4, upper = list(continuous = GGally::wrap(\u0026quot;cor\u0026quot;, method = \u0026quot;spearman\u0026quot;)), lower = list(continuous = points_loess)) Note que a relação entre TUPY3 e ELET3 não é linear e além disso essa correlação é fraca, o que pode ser benéfico para o portfólio pois uma possível queda em uma não parece não ter tanto impacto na outra.\nAlém disso note que a correlação do BTC-USD com TUPY3 e ELET3 é moderada e mesmo apresentando este valores numéricos, o Bitcoin é um ativo negociado em escala global e é de um setor totalmente diferente das outras ações.\nAVISO: Essa análise meramente numérica não é o suficiente para detectar uma relação de causa, pois correlação não implica causalidade. Isto que dizer que poda haver uma causa em comum para ambas ou que seja uma correlação espúria. Quando se trata da bolsa de valores é necessário também conhecer um pouco sobre a situação e história da empresa na qual se investe.\nForecast com Prophet do Facebook Poderíamos utilizar uma série de modelos estatísticos, econométricos e de machine learning utilizando tanto as funções nativas do R base ou pacote forecast quanto as funções desenvolvidas para trabalhar de maneira “arrumada” com tsibble (incluindo modelos baseados em árvores, como discutido em um estudo sobre modelos de aprendizagem baseados em árvores) mas resolvi fazer uma abordagem diferente neste post escolhendo o modelo disponibilizado pelo Facebook.\nFonte: https://facebook.github.io/prophet/\nO Prophet é um software de código aberto disponibilizado pela equipe de Data Science do Facebook que fornece um procedimento para realização de previsões de dados de séries temporais.\nSegundo a documentação oficial, (em tradução livre):\nO Prophet tem como “base em um modelo aditivo no qual tendências não lineares se ajustam à sazonalidade anual, semanal e diária, além de efeitos de férias. Funciona melhor com séries temporais que têm fortes efeitos sazonais e várias temporadas de dados históricos. O Profeta é robusto para a falta de dados e mudanças na tendência, e geralmente lida bem com outliers”.\nEste modelo me pareceu uma boa opção para exemplificar a etapa da modelagem de séries temporais deste post. Vamos ver o que o modelo do Facebook tem a nos dizer sobre o futuro das nossas ações.\nDivisão entre treino e teste em séries temporais Assim como em uma tarefa de machine learning que não envolvem dados temporais, no caso de séries temporais, quando desejamos avaliar o ajuste do nosso modelo também dividimos o dataset em treino e teste porém utilizamos a data como índice.\nVeja como serão divididas nossas séries históricas:\ntreino: inicio da série até 18/11/20; teste: de 18/11/2020 até o final da série histórica (2 meses atrás) h = 30 * 2 data_split \u0026lt;- Sys.Date() - h tbl_stocks_train \u0026lt;- tbl_stocks %\u0026gt;% filter(date \u0026lt;= data_split) %\u0026gt;% select(symbol, date, close) tbl_stocks_test \u0026lt;- tbl_stocks %\u0026gt;% filter(date \u0026gt; data_split) %\u0026gt;% select(symbol, date, close) Após dividir os dados em treino e teste já estamos habilitados à utilizar o modelo. Note que, por default, o modelo espera duas colunas nomeadas como ds: data da série e y: variável target da série.\nAlém disso faremos uma previsão 6 meses a frente dos dados de teste para entender qual a tendência o modelo estaria adotando.\nlibrary(prophet) prophet_results \u0026lt;- tbl_stocks_train %\u0026gt;% rename(ds = date, y = close) %\u0026gt;% nest(data = c(ds, y)) %\u0026gt;% mutate(pmodel = map(data, ~ prophet(.x, daily.seasonality=TRUE)) )%\u0026gt;% mutate(pprediction = map(pmodel, ~.x %\u0026gt;% make_future_dataframe(periods = h + 30*6) %\u0026gt;% predict(.x,.))) Veja os resultados do ajuste do modelo:\nlibrary(patchwork) pmap(list( x = prophet_results$pprediction, y = split(tbl_stocks_train, tbl_stocks_train$symbol), z = split(tbl_stocks_test, tbl_stocks_test$symbol), w = prophet_results$symbol ),function(x, y, z, w){ x %\u0026gt;% as_tibble() %\u0026gt;% mutate(ds=as_date(ds)) %\u0026gt;% select(ds, trend, yhat, yhat_lower, yhat_upper) %\u0026gt;% ggplot() + geom_line(aes(x=ds, y=yhat, color=\u0026quot;blue\u0026quot;), show.legend = F) + geom_line(data=y, aes(x=date, y=close, color=\u0026quot;black\u0026quot;), show.legend = F) + geom_line(data=z, aes(x=date, y=close, color=\u0026quot;red\u0026quot;), show.legend = T) + geom_ribbon(aes(x=ds, ymin=yhat_lower, ymax=yhat_upper), alpha=0.2) + scale_x_date(#limits = c(as.Date(\u0026quot;2018-06-01\u0026quot;), Sys.Date() + 30*12), date_breaks = \u0026quot;6 month\u0026quot;, date_labels = \u0026quot;%m/%Y\u0026quot;) + theme_bw()+ labs(y = w, x = \u0026quot;\u0026quot;, caption = \u0026quot;gomesfellipe.github.io\u0026quot;)+ scale_colour_manual(values=c(\u0026quot;black\u0026quot;,\u0026quot;blue\u0026quot;,\u0026quot;red\u0026quot;), name=\u0026quot;\u0026quot;, labels=c(\u0026quot;treino\u0026quot;,\u0026quot;modelo\u0026quot;,\u0026quot;teste\u0026quot;))+ theme(legend.position = c(1-0.8,1-0.2), legend.background = element_rect(fill=alpha(\u0026#39;lightgrey\u0026#39;, 0.2)), legend.direction = \u0026quot;horizontal\u0026quot;) } ) %\u0026gt;% {.[[1]] / .[[2]] / .[[3]]} ggsave(\u0026quot;prophet.png\u0026quot;) # salvar para o bot retornar este resultado! Parece interessante..\nVeja que a linha azul (modelo ajustado) se ajusta bem à linha preta (dados de treino) acompanhando a série histórica e captando algumas tendências não lineares.\nPorém note que a linha azul se perde completamente da linha vermelha (dados de teste) no início de 2020 e acho isso muito razoável pois dificilmente algum modelo iria prever os efeitos de uma Pandemia utilizando apenas a série histórica do ativo.\nNote ainda que a linha azul se estende até o final de 2020 (previsões para os próximos 6 meses) o que sugere que a série possuía esta tendencia positiva ao longo dos anos, segundo o modelo Prophet .\nAviso: Existem várias maneiras de estudar e melhorar a qualidade do ajuste deste modelo mas como o objetivo deste post não é este deixo como aviso para o leitor. Para quem quiser se aprofundar nessa avaliação, vale conferir os pacotes do R para avaliar o ajuste de modelos.\nCom a interpretação dos resultados concluída.. vamos às compras!\nComprando ações Após toda essa exemplificação de como podem ser feitas as análises para a elaboração da carteira chegou a hora das compras.\nSuponha que tivéssemos realizado nossas compra no fechamento do dia 2018-12-01, quando os valores de fechamento das cotações eram as seguintes:\ntbl_stocks %\u0026gt;% filter(date == \u0026quot;2018-12-01\u0026quot;) %\u0026gt;% mutate(close = cell_spec(moeda_real(close), \u0026quot;html\u0026quot;, color = \u0026quot;blue\u0026quot;, bold = T)) %\u0026gt;% mutate_at(c(3:5, 8), ~moeda_real(.x)) %\u0026gt;% kable2() Neste dia a cotação para ELET3 era R$24,42 e TUPY3 era R$19,73 e suponha que tenhamos comprado 200 lotes de ELET3 e 150 fracionários de TUPY, totalizando R$7.843,64 (próximo ao que tinhaamos planejado no inicio do estudo)\nVamos guardar estes valores:\ncot_inicio = filter(tbl_stocks, date == \u0026quot;2018-12-01\u0026quot;, symbol != \u0026quot;BTC-USD\u0026quot;) %\u0026gt;% pull(close) qtd_inicio = c(elet = 200, tupy = 150) Note que o valor do Bitcoin está em dólares, para obter o valor em reais (R$) daquele dia vamos utilizar a API do Mercado Bitcoin. Como não existe nenhum pacote que forneça estes dados diretamente no R, a requisição será feita normalmente via API com o pacote jsonlite:\nlibrary(jsonlite) # requisicao de api url \u0026lt;- glue::glue(\u0026quot;https://www.mercadobitcoin.net/api/BTC/day-summary/2019/12/01/\u0026quot;) safe_fromJSON \u0026lt;- purrr:::safely(fromJSON, as.numeric(NA)) consulta \u0026lt;- safe_fromJSON(url)$result %\u0026gt;% map_dfc(~.x) consulta %\u0026gt;% select(-date) %\u0026gt;% mutate_all(~moeda_real(.x)) %\u0026gt;% mutate(closing = cell_spec(closing, \u0026quot;html\u0026quot;, color = \u0026quot;blue\u0026quot;)) %\u0026gt;% kable2() O preço de fechamento foi de R$31.747,38 e suponhamos que tenha sido este o valor pago no dia. (Parece que neste dia o dólar estava em torno de R$4,03)\nPara completar esta carteira fictícia vamos adquirir 0,0032 do valor de um Bitcoin\ncot_inicio[3] \u0026lt;- consulta$closing qtd_inicio[3] \u0026lt;- 0.032 Portanto, ao valor de R$31.747,38 compramos 0.032 Bitcoin totalizando R$1.015,92 completando nossa carteira.\nTabela financeira Semelhante a uma planilha financeira, criaremos uma tabela financeira automatizada que receberá como input os valores da montagem e calculará automaticamente os valores do desmontagem no tempo atual utilizando dados de APIs abertas.\n“Aquilo que não se pode medir, não se pode melhorar”. Físico irlandês William Thomson Primeiro é necessário obter os valores mais recentes das cotações das acoes que compramos na bolsa e para isto será necessário utilizar outro pacote pois o tidyquant só fornece os dados em frequência diária.\nUtilizaremos portanto, o pacote alphavantager que fornece dados de finanças da API gratuita Alpha Vantage no formato arrumados e também foi desenvolvida pela Business Science (mesmo criados do pacote tidyquant).\nAviso: Na documentação da api do Alphavantage recomenda-se a solicitações de API com moderação, suportando até 5 solicitações de API por minuto e 500 solicitações por dia para obter o melhor desempenho no servidor. Caso deseje segmentar um volume maior de chamadas da API, confira a associação premium..\nJá para a coleta da cotação em tempo real do Bitcoin em reais (R$), utilizaremos novamente a api do mercado bitcoin.\n# Importar dados da bolsa de valores ================================== library(alphavantager) # api streaming bovespa AV_API_KEY = Sys.getenv(\u0026quot;AV_API_KEY\u0026quot;) av_api_key(AV_API_KEY) consulta_acoes \u0026lt;- map_df(portifolio[1:2], ~{ alphavantager::av_get(symbol = .x, av_fun = \u0026quot;TIME_SERIES_INTRADAY\u0026quot;, interval = \u0026quot;1min\u0026quot;, # \u0026quot;1min\u0026quot;, \u0026quot;5min\u0026quot;, \u0026quot;15min\u0026quot;, \u0026quot;30min\u0026quot; ou \u0026quot;60min\u0026quot; outputsize = \u0026quot;compact\u0026quot;) %\u0026gt;% # \u0026quot;full\u0026quot; bind_cols(stock = rep(.x, nrow(.))) }) # Impotar dados do bitcoin ============================================ coin \u0026lt;- \u0026quot;BTC\u0026quot; method \u0026lt;- \u0026quot;ticker\u0026quot; url \u0026lt;- glue::glue(\u0026quot;https://www.mercadobitcoin.net/api/{coin}/{method}/\u0026quot;) safe_fromJSON \u0026lt;- safely(fromJSON, as.numeric(NA)) consulta_bitcoin \u0026lt;- safe_fromJSON(url)$result$ticker %\u0026gt;% as_tibble() %\u0026gt;% transmute(timestamp = lubridate::ymd_hms(as.POSIXct(date, origin=\u0026quot;1970-01-01\u0026quot;)), open, high, low, close = sell, volume = NA, stock = \u0026quot;BTC.BR\u0026quot;) %\u0026gt;% mutate_at(c(\u0026#39;open\u0026#39;, \u0026#39;high\u0026#39;, \u0026#39;low\u0026#39;, \u0026#39;close\u0026#39;), ~as.numeric(.x)) # Combinar resultados das consultas ================================== consulta_atual \u0026lt;- bind_rows( consulta_acoes %\u0026gt;% group_by(stock) %\u0026gt;% filter(timestamp == last(timestamp)), consulta_bitcoin ) # Salvar consulta ==================================================== saveRDS(consulta_atual, \u0026quot;consulta_atual.rds\u0026quot;) Resultados da consulta atual (após combinar a requisição da bolsa de valores e do Mercado Bitcoin):\nconsulta_atual %\u0026gt;% mutate_at(2:4, ~moeda_real(.x)) %\u0026gt;% mutate_if(is.numeric, ~ifelse(is.na(.x), \u0026quot;-\u0026quot;, format(.x, digits = 2))) %\u0026gt;% mutate(close = cell_spec(moeda_real(close), \u0026quot;html\u0026quot;, color = \u0026quot;blue\u0026quot;)) %\u0026gt;% kable2() Com os valores da Montagem organizados e os valores da Desmontagem coletados em tempo real já podemos construir nossa tabela financeira automatizada.\nA tabela contém:\nValores de cotação e quantidade adquiridas de cada uma no momento da montagem da carteira; Valores de cada cotação no momento atual com suas respectivas quantidades disponíveis; Resultados de o ganho (ou perda) seguido do resultado bruto caso realize a venda agora; Última coluna indica se vale a pena vender ou não aquela cotação considerando que o valor de venda é superior ao valor de compra. Aviso: Essa operação de vender o ativo caso o preço da venda seja maior que o da compra é apenas um exemplo. Poderíamos utilizar diversas estatísticas para determinar o momento da operação porém adotei esta apenas para ilustrar o funcionamento da tabela financeira, o limite de opções é a sua criatividade!\nVeja a tabela final com os resultados atualizados em tempo real:\nporcentagem \u0026lt;- function(x){paste0(round(x,2), \u0026quot;%\u0026quot;)} # Funcao auxiliar # Tabela resultado financas \u0026lt;- tibble( ativo = portifolio, cot_inicio = cot_inicio, qtd_inicio = qtd_inicio, vol_inicio = cot_inicio * qtd_inicio, cot_atual = consulta_atual$close, qtd_atual = qtd_inicio, vol_atual = cot_atual * qtd_atual, ganho_perda = vol_atual - vol_inicio, resultado_bruto = ganho_perda / vol_inicio * 100 ) tabela \u0026lt;- financas %\u0026gt;% mutate( cot_inicio = moeda_real(cot_inicio), cot_atual = moeda_real(cot_atual), vol_inicio = moeda_real(vol_inicio), vol_atual = moeda_real(vol_atual), qtd_inicio = round(qtd_inicio,4), qtd_atual = round(qtd_atual,4), ` ` = ifelse(ganho_perda \u0026gt; 0,\u0026quot;\\u2713\u0026quot;, \u0026quot;\\u2718\u0026quot;) , cot_atual = cell_spec(cot_atual, \u0026quot;html\u0026quot;, color = \u0026quot;blue\u0026quot;), ganho_perda = cell_spec(moeda_real(ganho_perda), \u0026quot;html\u0026quot;, color = ifelse(ganho_perda \u0026gt; 0, \u0026quot;green\u0026quot;, \u0026quot;red\u0026quot;)), resultado_bruto = cell_spec(porcentagem(resultado_bruto), \u0026quot;html\u0026quot;, color = ifelse(resultado_bruto \u0026gt; 0, \u0026quot;green\u0026quot;, \u0026quot;red\u0026quot;))) %\u0026gt;% `colnames\u0026lt;-`(stringr::str_replace_all(colnames(.), \u0026quot;(_|[[:space:]])\u0026quot;, \u0026quot;\\n\u0026quot;)) %\u0026gt;% # Exibicao kable(format = \u0026quot;html\u0026quot;, escape = F) %\u0026gt;% kable_styling(c(\u0026quot;striped\u0026quot;, \u0026quot;bordered\u0026quot;, \u0026quot;hover\u0026quot;, \u0026quot;responsive\u0026quot;), full_width = T, font_size = 12) %\u0026gt;% add_header_above(c(\u0026quot; \u0026quot;, \u0026quot;Montagem\u0026quot; = 3, \u0026quot;Desmontagem / Atual\u0026quot; = 3, \u0026quot;Resultado\u0026quot; = 3)) tabela Agora que já possuímos nossa requisição completa e arrumada em tempo real precisamos ter acesso a esta informação de forma dinâmica também e para isso utilizaremos o bot do Telegram.\nBot Telegram Depois de muitas decisões tomadas enfim chegamos ao bot! Espero que tenha notado que montar uma carteira não é uma tarefa fácil pois envolve exposição ao risco e também exige certo acompanhamento do mercado.\nPara criar um bot no Telegram basta seguir os passos do readme do pacote telegram disponibilizado no Github ou seguir os passos desse excelente post do curso-r que me inspirou a uns anos atras e hoje me auxiliou novamente para criar este bot. Ao concluir a etapa de configuração teremos um novo contado no Telegram, o nosso bot!\nCom a configuração no aplicativo do Telegram concluída, o primeiro passo para configurar as ações do bot no R é iniciar um objeto TGBot declarando o id do seu bot. No meu caso o bot se chama Stocks e o id é fgstockbot.\nCom o R conectado ao bot do Telegram já somos capazes de criar um conjunto de regras de forma que o bot nos retorne as informações que desejamos.\nDesenvolveremos a função report_stocks() que programa o bot para realizar o seguinte algoritmo:\nCarregar dependências e conectar chaves de acesso Conferir se a bolsa de valores esta aberta Requisição das cotações da bolsa de valores em real-time Requisição da cotação do Bitcoin em real-time Combinar resultados Inserir resultados da coleta na tabela financeira Se o valor de algum volume atual seja maior que o volume inicial: Calcular valores de desmontagem Preparar layout da tabela financeira Salvar resultados Enviar via Telegram Aguardar 20 minutos para a próxima requisição Repetir todo o processo Parece complicado mas é tranquilo pois todos os códigos de cada uma destas tarefas já foram desenvolvidos nas seções anteriores e serão apenas combinados. A função report_stocks() já esta disponível no github, veja a baixo:\n(A frequência adotata como default pela função tenta fazer a requisição com a maior frequência possível na api do Alphavantage)\nApós todas as devidas configurações, basta carregar a função e executar para obter o seguinte resultado:\n# https://gist.github.com/gomesfellipe/357af0735d2aedca60146a7655e33929 devtools::source_gist(\u0026quot;357af0735d2aedca60146a7655e33929\u0026quot;,quiet = T) # Executar bot_report_stocks(portifolio = portifolio, cot_inicio = cot_inicio, qtd_inicio = qtd_inicio) E assim obtemos um feedback através do nosso Smartphone ou Smartwatch em tempo real sobre o desempenho da nossa carteira!\nConclusão e próximos passos Neste post criamos um bot que coleta os dados e faz análises disponibilizando-as em tempo real no Telegram. Porém vimos também o quão difícil pode ser a montagem de uma carteira e as análises envolvendo séries históricas de ativos.\nDiante dos resultados obtidos aqui existe uma grande gama de opções de inovações para trabalhos futuros como:\nProgramar o bot para responder a uma menssagem rápida no smartwatch com o valor de uma previsão; Desenvolver um Shiny parametrizando o bot para consultar análises em tempo real; Hospedar a rotina em um servidor para operacionalizar o bot (caso tenha dúvidas de como se iniciar um RStudio Server u um Shiny Server consulte este post do blog); Criar uma API com plumber para fornecer os resultados; Treinar modelo utilizando mais dados, mais variáveis explicativas e tuning dos parâmetros; Criar pacote com um robô mais geral para responder diferentes consultas. Espero que tenha gostado qualquer dúvida deixe nos comentários!\nReferências https://www.infomoney.com.br/minhas-financas/brasileiros-nao-sabem-a-diferenca-entre-poupar-e-investir-afirma-especialista-2/ https://www.btgpactualdigital.com/blog/investimentos/diversificacao-de-investimentos https://www.btgpactualdigital.com/blog/coluna-gustavo-cerbasi/defina-sua-estrategia-entre-renda-fixa-ou-variavel https://blog.earo.me/2018/12/20/reintro-tsibble/ https://www.tradingcomdados.com/post/2017/07/09/estudo-de-correla%C3%A7%C3%A3o-entre-a%C3%A7%C3%B5es-da-bolsa-de-valores-de-s%C3%A3o-paulo https://www.business-science.io/code-tools/2017/10/28/demo_week_h2o.html https://www.infomoney.com.br/mercados/adolescente-fica-milionario-aos-18-anos-usando-bitcoins-apos-fazer-aposta-com-os-pais/ https://www.infomoney.com.br/onde-investir/halving-conheca-o-processo-que-pode-levar-o-bitcoin-a-uma-nova-explosao-de-preco/ https://cran.r-project.org/web/packages/telegram/README.html Forecasting: Principles and Practice — Hyndman \u0026amp; Athanasopoulos https://www.curso-r.com/blog/2017-08-19-r-telegram-bitcoin/ https://www.curso-r.com/blog/2017-08-19-r-telegram-bitcoin/ Perguntas frequentes Qual modelo foi usado para prever o comportamento das ações e do Bitcoin?\nFoi usado o Prophet, modelo de código aberto disponibilizado pela equipe de Data Science do Facebook, que se ajusta bem a séries com sazonalidade forte e é robusto a dados faltantes e outliers.\nQual regra foi usada para dividir a carteira entre renda fixa e renda variável?\nFoi usada a Regra dos 80: subtrai-se a idade do investidor de 80, e o resultado indica o percentual a ser investido em renda variável.\nComo o bot desenvolvido no post entrega os resultados ao usuário?\nO bot foi criado no Telegram com o pacote telegram do R e envia periodicamente uma tabela financeira automatizada com ganhos e perdas da carteira, coletada via APIs em tempo real.\n","date":"25 de março de 2020","externalUrl":null,"permalink":"/post/2020-03-25-investment-alert/","section":"Posts","summary":" Por que investir? Como esta sua situação financeira? Caso tenha alguma reserva pode ser interessante pensar em investimentos pois a poupança já não é mais garantia de lucro no longo prazo, não acredita?\n","title":"Bot com Machine Learning para alertas de investimento","type":"post"},{"content":"","date":"25 de março de 2020","externalUrl":null,"permalink":"/tags/correlacao/","section":"Tags","summary":"","title":"Correlacao","type":"tags"},{"content":"","date":"25 de março de 2020","externalUrl":null,"permalink":"/tags/dplyr/","section":"Tags","summary":"","title":"Dplyr","type":"tags"},{"content":"","date":"25 de março de 2020","externalUrl":null,"permalink":"/tags/reports/","section":"Tags","summary":"","title":"Reports","type":"tags"},{"content":" Problema de negócio Uma tarefa comum no dia a dia de um estatístico (ou cientista de dados) é a elaboração de relatórios para passar ao restante da equipe e/ou tomadores de decisão os resultados encontrados e muitas vezes essa tarefa pode parecer desgastante quando os relatórios são muitos extensos e repetitivos.\nCom a linguagem R, escrever relatórios estatísticos utilizando RMarkdown acaba sendo a escolha padrão por ser tão simples transformar as análises em documentos, apresentações e dashboards de alta qualidade com poucas linhas de código.\nAssim, combinando conceitos de programação, como o Loop no R e a linguagem Markdown para produção de relatórios, temos uma poderosa ferramenta para Automação de relatórios.\nO R Markdown Cookbook é o livro que fica aberto na minha mesa toda vez que preciso lembrar algum truque desses de geração de relatório.\nTL;DR\nA função knit_child() compila um relatório RMarkdown \"filho\" a partir de um \"mestre\", permitindo repeti-lo em loop. Combinada com nest(), cada iteração do loop processa um subconjunto dos dados (aqui, um ano do dataset gapminder). O resultado são N relatórios idênticos em estrutura, cada um com os dados do seu próprio grupo, sem copiar e colar. Entendendo o problema Suponha que o seguinte gráfico seja apresentado à você:\nEste gráfico animado apresenta a evolução da esperança de vida ao nascer (em anos) em relação ao PIB per capita (em US$, ajustado pela inflação) de 141 países dos 5 continentes durante o período de 1952 até 2007, a cada 5 anos.\nEntraremos em mais detalhes sobre as informações deste gráfico a seguir.\nFonte dos dados Os dados utilizados neste problema foram importados através do pacote gapminder que é um projeto que utiliza dados do site Gapminder.org.\nSegundo sua descrição no site:\n“Gapminder é uma fundação independente sueca sem afiliações políticas, religiosas ou econômicas. (…)”\nNo site é possível obter dados gratuitos para se obter estatísticas confiáveis e além dos disso a Fundação Gapminder apresenta alguns outros projetos como o Dollar Street que apresenta 30.000 fotos de 264 famílias em 50 países classificados por renda.\nNa página do projeto é possível ver e comparar os mais variados aspectos da população ao redor do mundo que vão desde casas, itens mais amados, carros até banheiros, comida de pets e bebidas alcoólicas.\nO pacote fornece dados da Fundação Gapminder como: valores de expectativa de vida, PIB per capta e população, a cada cinco anos, de 1952 a 2007 (total de 12 anos). Veja as primeiras 5 linhas da base de dados contidos no pacote:\n# Base de dados utilizada head(gapminder) ## # A tibble: 6 x 6 ## country continent year lifeExp pop gdpPercap ## \u0026lt;fct\u0026gt; \u0026lt;fct\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; ## 1 Afghanistan Asia 1952 28.8 8425333 779. ## 2 Afghanistan Asia 1957 30.3 9240934 821. ## 3 Afghanistan Asia 1962 32.0 10267083 853. ## 4 Afghanistan Asia 1967 34.0 11537966 836. ## 5 Afghanistan Asia 1972 36.1 13079460 740. ## 6 Afghanistan Asia 1977 38.4 14880372 786. Essa base de dados possui 1705 linhas de 6 variáveis, onde:\ncountry: factor com 142 levels continent: factor com 5 levels year: sequencia de 1952 até 2007 a cada 5 anos lifeExp: esperança de vida ao nascer, em anos pop: população gdpPercap: PIB per capita (em US$, ajustado pela inflação) Comportamento geral dos dados Antes de começar a fazer os relatórios para cada ano, vamos reproduzir a animação apresentada para nós com o comportamento temporal utilizando o pacote gganimate:\n# Carregar pacotes library(ggplot2) library(dplyr) library(gapminder) library(scales) library(gganimate) # Definir tema: theme_set(theme_bw()) # Funcao para customizar legendas: custom_legend \u0026lt;- function(x){comma(x, big.mark = \u0026quot;.\u0026quot;,decimal.mark = \u0026quot;,\u0026quot;)} # Comportamento geral: gapminder %\u0026gt;% filter(country!=\u0026quot;Kuwait\u0026quot;) %\u0026gt;% # remover 1 pais outlier ggplot(aes(x = gdpPercap, y = lifeExp, size = pop, label = country, color = continent, alpha= log(gdpPercap))) %+% geom_point(show.legend = F) %+% geom_text(show.legend = F, size = 3, nudge_y = -0.7) %+% scale_size_continuous(labels = custom_legend) %+% scale_x_continuous(labels = custom_legend) %+% geom_smooth(se=F, color = \u0026quot;black\u0026quot;, show.legend = F, method = \u0026quot;lm\u0026quot;) %+% transition_time(year) %+% scale_color_brewer(palette = \u0026quot;Dark2\u0026quot;) %+% labs(title = \u0026quot;Year: {frame_time}\u0026quot;) Analisando esta animação é possível notar:\nJapão é o país que possui a maior expectativa de vida ao longo de todos os anos; Os países do contínente africano são os que apresentam expectativa de vida mais baixa e pior gdpPercap. A Arábia Saudita teve sua gdpPercap aumentada até 1978 porém a partir daí diminiu bastante. O país com maior gdpPercap e expectativa de vida na América é o Estados Unidos; A Noruega foi o país que mais se destacou com os valores mais elevados e estáveis ao longo destes 55 anos. Obs[1]: Kuwait foi removida para este gráfico animado pois é um país outlier. Segundo o Wikipédia:\n”O Kuwait tem um PIB (PPC) de US$ 167,9 bilhões[96] e uma renda per capita de US$ 81 800,[96] o que o torna o quinto país mais rico do mundo.[52] O índice de desenvolvimento humano (IDH) do Kuwait é de 0,816, um dos mais elevados do Oriente Médio e do mundo árabe. Com uma taxa de crescimento do PIB de 5,7%, o Kuwait tem uma das economias que mais crescem na região.[96]”\nPara quem tiver curiosidade, os dados de Kuwait podem ser obtidos da seguinte forma:\ngapminder %\u0026gt;% filter(country == \u0026quot;Kuwait\u0026quot;) ## # A tibble: 12 x 6 ## country continent year lifeExp pop gdpPercap ## \u0026lt;fct\u0026gt; \u0026lt;fct\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; ## 1 Kuwait Asia 1952 55.6 160000 108382. ## 2 Kuwait Asia 1957 58.0 212846 113523. ## 3 Kuwait Asia 1962 60.5 358266 95458. ## 4 Kuwait Asia 1967 64.6 575003 80895. ## 5 Kuwait Asia 1972 67.7 841934 109348. ## 6 Kuwait Asia 1977 69.3 1140357 59265. ## 7 Kuwait Asia 1982 71.3 1497494 31354. ## 8 Kuwait Asia 1987 74.2 1891487 28118. ## 9 Kuwait Asia 1992 75.2 1418095 34933. ## 10 Kuwait Asia 1997 76.2 1765345 40301. ## 11 Kuwait Asia 2002 76.9 2111561 35110. ## 12 Kuwait Asia 2007 77.6 2505559 47307. Resolvendo o problema de negócio Para resolver o problema de se fazer uma análise sobre a expectativa de vida, PIB per capta e população, para cada continente, para cada ano disponível, (ou seja, analisar de 1952 a 2007 a cada cinco anos) faremos um total de 12 relatórios.\nIsso é muito para se arriscar usar ctrl+c e ctrl+v 12 vezes e depois caso precise de alguma mudança, alterar o relatório 12 vezes.\nPortanto utilizaremos uma estratégia parecida com a que apresentei no último post sobre como Hackear o R com a estratégia Split-Apply-Combine.\nPrimeiramente vamos separar nosso dataset por ano utilizando a função tidyr::nest():\nlibrary(tidyr) # funcao nest # separar por ano: nested_gapminder \u0026lt;- gapminder %\u0026gt;% nest(-year) Selecionei um dos anos como exemplo e utilizei os objetos nested_gapminder$year[1] e nested_gapminder$data[[1]] para desenvolver uma função que realizasse todas as análises que eu precisasse.\nEssa função foi salva em um script separado chamado analise.R e pode ser encontrada neste link. Para carregar a função localmente basta utilizar a função source(), veja;\nsource(\u0026quot;analise_gapminder.R\u0026quot;) Veja nas seções a seguir os outputs da função antes de encapsulá-la em um arquivo RMarkdown (.Rmd) para fazer o looping:\nResultados para o ano 2007 A seguir vamos criar o objeto x que será o data set referente ao ano title. Em seguida vamos aplicar a função carregada anteriormente para obter os resultados das análises e salvar no objeto resutls\nlibrary(magrittr) # pipe %$% # Obter resultados x \u0026lt;- nested_gapminder %\u0026gt;% filter(year == 2007) %\u0026gt;% unnest() title \u0026lt;- nested_gapminder %\u0026gt;% filter(year == 2007) %$% year results \u0026lt;- analise_gapminder(x, title) Vejamos como o Brasil esta em relação aos outros países com um gráfico que resume os resultados do modelo ajustado:\nresults$grafico_geral_regressao Comportamento dos dados por Continente\nresults$grafico_por_continente Após ajustar o modelo de regressão, vamos obter algumas estatísticas descritivas com mais gráficos informativos!\nO gráfico abaixo apresenta uma Regressão Local (LOESS) com destaque nos países que tiveram gdpPercap e lifeExp acima da média\nresults$grafico_zoom_acima_media E agora podemos conferir um gráfico que apresenta uma Regressão Local (LOESS) com destaque nos países que tiveram gdpPercap e lifeExp acima da média\nresults$grafico_zoom_abaixo_media Maravilha! Muitas informações interessantes mas não resolvemos o problema por inteiro. Resta aplicar as mesmas análises para os demais anos do nosso dataset.\nAutomatizar as analises para os próximos anos A linha a seguir é a que realiza toda a mágica!\nA função knit_child() compila o código R e retorna uma saída pura (Latex, html ou word sem código R), então se fizermos um looping da seguinte maneira teremos replicado nossas análises para todos os demais anos:\nrmarkdown::render(\u0026quot;gapminder_automatico_master.Rmd\u0026quot;) Veja o conteúdo do script gapminder_automatico_master.Rmd:\nNote que este script chama outro arquivo .Rmd chamado gapminder_automatico_child.Rmd, que tem o seguinte conteúdo:\nO looping gera um PDF com os 12 relatórios, um por ano, cada um repetindo os mesmos gráficos e tabelas vistos acima para 2007. Veja o resultado:\nConclusão A Abordagem para criar chunks filhos de RMarkdown com a função knit_child() abre muitas portas para análises de dados! Neste post fizemos um exemplo simples de automação de relatórios porém esses resultados podem ser cada vez mais customizáveis e utilizados em RPA - Robotic Process Automation - de forma que seja possível automatizar processos que antes só poderiam ser executados por humanos!\nPerguntas frequentes O que faz a função knit_child() no RMarkdown? Ela compila um documento RMarkdown \"filho\" dentro de um relatório \"mestre\" e retorna a saída já processada (HTML, PDF ou Word, sem o código R visível). Chamada dentro de um loop, ela permite gerar um relatório repetido para cada grupo de dados sem duplicar código.\nEssa técnica de automação serve só para o dataset gapminder? Não. A técnica é genérica: qualquer situação em que o mesmo relatório precisa ser repetido para diferentes cortes dos dados (por ano, por região, por produto) se beneficia do mesmo padrão de nest() + knit_child() em loop.\nVale a pena para relatórios que só serão gerados uma vez? Geralmente não compensa o esforço inicial de estruturar o script mestre/filho para um relatório único. O ganho aparece quando o mesmo relatório precisa ser reexecutado, seja para múltiplos grupos de uma vez, seja periodicamente com dados atualizados.\nReferencias https://cran.r-project.org/web/packages/gganimate/vignettes/gganimate.html https://cran.r-project.org/web/packages/ggforce/vignettes/Visual_Guide.html https://cran.r-project.org/web/packages/ggExtra/vignettes/ggExtra.html https://cran.r-project.org/web/packages/gapminder/gapminder.pdf https://www.gapminder.org/data/ https://stackoverflow.com/questions/43873345/knit-child-in-a-loop-variable-as-title Apendice Função analise.R Veja o conteúdo da função analise.R preparada para esta analise:\n# Funcao para analise por ano: analise_gapminder \u0026lt;- function(x, title){ # Carregar dependencias: require(broom) require(ggforce) require(ggpmisc) require(ggExtra) # Funcao para customizar legendas: custom_legend \u0026lt;- function(x){comma(x, big.mark = \u0026quot;.\u0026quot;,decimal.mark = \u0026quot;,\u0026quot;)} # Obter dados do Brasil: brazil \u0026lt;- x %\u0026gt;% filter(country == \u0026quot;Brazil\u0026quot;) # Resultados do ajuste de regressao --------------------------------------- mytable \u0026lt;- lm(lifeExp ~ gdpPercap, data = x) %\u0026gt;% tidy() %\u0026gt;% mutate_if(is.numeric, ~round(.x, 4)) %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;Termo\u0026quot;, \u0026quot;Estimativa\u0026quot;, \u0026quot;Desv.Pad.\u0026quot;, \u0026quot;Estatistica\u0026quot;, \u0026quot;Valor p\u0026quot;)) # r2: r2 \u0026lt;- round(summary(lm(lifeExp ~ gdpPercap, data = x))$r.squared,4)*100 # residuos do modelo: res \u0026lt;- lm(lifeExp ~ gdpPercap, data = x)$residuals # resutado para teste de kolmogorov-smirnov ks_test \u0026lt;- ks.test(res, \u0026quot;pnorm\u0026quot;, mean(res), sd(res))$p.value %\u0026gt;% round(5) # Grafico geral com regressao e boxplots ---------------------------------- grafico_geral_regressao \u0026lt;- x %\u0026gt;% ggplot(aes(x = gdpPercap, y = lifeExp, size = pop, label = country, color = country)) %+% geom_point(show.legend = F) %+% geom_text(show.legend = F, size = 3, nudge_y = -0.5) %+% scale_size_continuous(labels = custom_legend) %+% scale_x_log10(labels = custom_legend) %+% scale_color_manual(values = country_colors) %+% geom_smooth(se=F, color = \u0026quot;black\u0026quot;, show.legend = F, method = \u0026quot;lm\u0026quot;) %+% annotate(\u0026quot;segment\u0026quot;, color=\u0026quot;blue\u0026quot;, arrow=arrow(length=unit(0.05,\u0026quot;npc\u0026quot;)), x=brazil$gdpPercap, xend=brazil$gdpPercap, y=brazil$lifeExp-6, yend=brazil$lifeExp-1) %+% annotate(\u0026quot;text\u0026quot;, color=\u0026quot;blue\u0026quot;, label = \u0026quot;Brasil\u0026quot;, x=brazil$gdpPercap, y=brazil$lifeExp-7) %+% labs(title = paste0(title, \u0026quot;: lifeExp ~ gdpPercap\u0026quot;), subtitle = \u0026quot;Regressão linear e destaque no Brasil\u0026quot;, caption = paste0(\u0026quot;R² do modelo: \u0026quot;, r2, \u0026quot;\\n\u0026quot;,\u0026quot;p valor para ks.test: \u0026quot;, ks_test), x = \u0026quot;gdpPercap (Transformação log10)\u0026quot;) %+% annotate(geom = \u0026quot;table\u0026quot;, x = Inf, y = -Inf, label = list(mytable), vjust = 0, hjust = 1) %\u0026gt;% ggMarginal(type = \u0026quot;boxplot\u0026quot;, fill=\u0026quot;transparent\u0026quot;,size = 10) # Comportamento separado por continente ----------------------------------- grafico_por_continente \u0026lt;- x %\u0026gt;% filter(continent != \u0026quot;Oceania\u0026quot;) %\u0026gt;% ggplot(aes(x = gdpPercap, y = lifeExp, size = pop, label = country, color = country)) %+% geom_point(show.legend = F) %+% geom_text(show.legend = F, size = 3, nudge_y = -0.5) %+% facet_wrap(~continent, scales = \u0026quot;free\u0026quot;) %+% scale_x_continuous(labels = custom_legend) %+% scale_color_manual(values = country_colors) %+% geom_smooth(method = \u0026quot;lm\u0026quot;, color = \u0026quot;black\u0026quot;, se=F, show.legend = F) %+% labs(title = paste0(title, \u0026quot;: lifeExp ~ gdpPercap, por continente\u0026quot;)) # Acima da media ---------------------------------------------------------- grafico_zoom_acima_media \u0026lt;- x %\u0026gt;% ggplot(aes(x = gdpPercap, y = lifeExp, size = pop, label = country, color = country)) %+% geom_point(show.legend = F) %+% geom_text(show.legend = F, size = 3, nudge_y = -0.5) %+% scale_size_continuous(labels = custom_legend) %+% scale_x_continuous(labels = custom_legend) %+% scale_color_manual(values = country_colors) %+% facet_zoom(y = lifeExp \u0026gt; median(x$lifeExp), x = gdpPercap \u0026gt; median(x$gdpPercap), split = T) %+% geom_smooth(se=F, color = \u0026quot;red\u0026quot;, show.legend = F, method = \u0026quot;loess\u0026quot;) %+% labs(title = paste0(title, \u0026quot;: lifeExp ~ gdpPercap com zoom nos países acima da mediana\u0026quot;)) # Abaixo da media --------------------------------------------------------- grafico_zoom_abaixo_media \u0026lt;- x %\u0026gt;% ggplot(aes(x = gdpPercap, y = lifeExp, size = pop, label = country, color = country)) %+% geom_point(show.legend = F) %+% geom_text(show.legend = F, size = 3, nudge_y = -0.5) %+% scale_size_continuous(labels = custom_legend) %+% scale_x_continuous(labels = custom_legend) %+% scale_color_manual(values = country_colors) %+% facet_zoom(y = lifeExp \u0026lt; median(x$lifeExp), x = gdpPercap \u0026lt; median(x$gdpPercap), split = T) %+% geom_smooth(se=F, color = \u0026quot;red\u0026quot;, show.legend = F, method = \u0026quot;loess\u0026quot;) %+% labs(title = paste0(title, \u0026quot;: lifeExp ~ gdpPercap com zoom nos países abaixo da mediana\u0026quot;)) # Output ------------------------------------------------------------------ list( brazil = brazil, mytable = mytable, r2 = r2, grafico_geral_regressao = grafico_geral_regressao, grafico_por_continente = grafico_por_continente, grafico_zoom_acima_media = grafico_zoom_acima_media, grafico_zoom_abaixo_media = grafico_zoom_abaixo_media, ks_test = ks_test ) } ","date":"13 de setembro de 2019","externalUrl":null,"permalink":"/post/2019-09-13-relatorios-automaticos-com-rmarkdown/","section":"Posts","summary":" Problema de negócio Uma tarefa comum no dia a dia de um estatístico (ou cientista de dados) é a elaboração de relatórios para passar ao restante da equipe e/ou tomadores de decisão os resultados encontrados e muitas vezes essa tarefa pode parecer desgastante quando os relatórios são muitos extensos e repetitivos.\nCom a linguagem R, escrever relatórios estatísticos utilizando RMarkdown acaba sendo a escolha padrão por ser tão simples transformar as análises em documentos, apresentações e dashboards de alta qualidade com poucas linhas de código.\n","title":"Como automatizar relatórios longos e repetitivos com RMarkdown","type":"post"},{"content":"","date":"13 de setembro de 2019","externalUrl":null,"permalink":"/tags/otimizacao/","section":"Tags","summary":"","title":"Otimizacao","type":"tags"},{"content":"","date":"13 de setembro de 2019","externalUrl":null,"permalink":"/tags/relatorios/","section":"Tags","summary":"","title":"Relatorios","type":"tags"},{"content":"","date":"13 de setembro de 2019","externalUrl":null,"permalink":"/tags/rmarkdown/","section":"Tags","summary":"","title":"Rmarkdown","type":"tags"},{"content":"","date":"5 de abril de 2019","externalUrl":null,"permalink":"/tags/flextable/","section":"Tags","summary":"","title":"Flextable","type":"tags"},{"content":" O método split-apply-combine Geralmente em uma análise de dados precisamos compreender, além do comportamento geral dos dados, o seu comportamento de acordo com alguns segmentos.\nNo famoso paper The Split-Apply-Combine Strategy for Data Analysis, Hadley Wickham descreve a abordagem “split-apply-combine” (dividir-aplicar-combinar) como uma das mais comuns em uma análise de dados. Em R essa tarefa pode ser feita por diversos caminhos, veja alguns dos modos de se fazer utilizando funções base do R e abordagens mais antigas:\nsplit() + lapply() + do.call(rbind, ...) ddply() do pacote plyr group_by + do() split() + map_dfr() Todos esses exemplos atendem à maioria dos casos que deseja-se utilizar a abordagem “split-apply-combine”, porém, veja por exemplo este tópico na community.rstudio.com criado no final de 2017 em que ocorre um comunicado que a função do() será descontinuada\nOu ainda, confira quando foi o último lançamento de atualização do pacote plyr no CRAN (foi em junho de 2016).\nCom a proposta de mais eficiência e legibilidade do código, atualmente existem maneiras mais sofisticadas e modernas de se realizar esta tarefa com pacotes que foram atualizados já este ano de 2019. Veja nas seções a seguir o aumento de produtividade que é possível se obter combinando os pacotes dplyr, tidyr e purrr da coleção de pacotes do tidyverse.\nTL;DR\nSplit-apply-combine: divide os dados em grupos, aplica uma função em cada um, combina os resultados. Para casos simples, group_by() + summarise() do dplyr já resolve. Para funções mais complexas (modelos, gráficos, tabelas por grupo), nest() + map() + unnest() do tidyr/purrr generalizam a estratégia. Usando só o dplyr Usamos “split-apply-combine” implicitamente o tempo todo quando utilizamos as funções groupy_by() + summarise() do pacote dplyr\nPoderíamos facilmente reproduzir o exemplo da imagem do post com os seguintes comandos:\nlibrary(dplyr) data \u0026lt;- tibble(x = c(\u0026quot;A\u0026quot;, \u0026quot;A\u0026quot;, \u0026quot;B\u0026quot;, \u0026quot;B\u0026quot;, \u0026quot;C\u0026quot;, \u0026quot;C\u0026quot;), y = c(0,1,2,3,4,5)) data %\u0026gt;% # input data group_by(x) %\u0026gt;% # split summarise(data = mean(y)) # apply/combine ## # A tibble: 3 x 2 ## x data ## \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; ## 1 A 0.5 ## 2 B 2.5 ## 3 C 4.5 Essa sequência de códigos aplica a abordagem implicitamente, agrupando os dados de acordo com a variável selecionada e em seguida aplicando a operação e combinando os resultados em uma matriz resumida\nUsando dplyr + tidyr + purrr Poderíamos ter realizado a mesma operação de forma explícita com o auxílio das funções nest(), map(), mutate() e unnest() dos pacotes dplyr tidyr e purrr, veja:\n# Pacotes necessários library(tidyr) library(purrr) # Dados data \u0026lt;- tibble(x = c(\u0026quot;A\u0026quot;, \u0026quot;A\u0026quot;, \u0026quot;B\u0026quot;, \u0026quot;B\u0026quot;, \u0026quot;C\u0026quot;, \u0026quot;C\u0026quot;), y = c(0,1,2,3,4,5)) # Codigos data %\u0026gt;% # Input Data nest(-x) %\u0026gt;% # Split mutate(data = map(data, ~mean(.x$y))) %\u0026gt;% # Apply unnest() # Combine ## # A tibble: 3 x 2 ## x data ## \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; ## 1 A 0.5 ## 2 B 2.5 ## 3 C 4.5 Note que obtemos a mesma saída do código anterior\nSplit-Apply-Combine com funções complexas Você deve estar se perguntando:\n“Tá, eu tenho um atalho para usar a estratégia ”split-apply-combine” com pacote dplyr, por que eu preciso usar os dados aninhados?”\nTrabalhar com dados aninhados permite aplicar qualquer tipo de função em partições do conjunto de dados e juntar os resultados em um objeto do tipo tibble cujo print() é um “método aprimorado que os torna mais fáceis de usar com grandes conjuntos de dados contendo objetos complexos”.\nVeja o seguinte exemplo:\nPrimeiramente, imagine que você queira calcular a média de mpg por cyl dos dados mtcars (nativos do R), bastaria utilizar a sequência de códigos:\nmtcars %\u0026gt;% # input data group_by(cyl) %\u0026gt;% # split summarise(media = mean(mpg)) # apply/combine ## # A tibble: 3 x 2 ## cyl media ## \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 4 26.7 ## 2 6 19.7 ## 3 8 15.1 Vejamos a seguir o uso da estratégia em situações mais complexas\nEm ajustes de modelos E se precisássemos calcular algo mais elaborado, como por exemplo ajustar \\(k=3\\) regressões lineares: \\(y_k= b_{0_k} + b_{1_k}*x_k\\) (com \\(y_k=\\) mpg, \\(x_k=\\)disp para cada \\(k=\\)cyl) para estudar os coeficientes estimados, o que aconteceria se utilizássemos o código abaixo ?\nSpoiler: Note que pelo fato da saída da função lm não retornar apenas uma única variável para sumarizar obteremos um Error:\nmtcars %\u0026gt;% # input data group_by(cyl) %\u0026gt;% # split summarise(lm = lm(mpg ~ disp)) # apply/combine ## Error: Problem with `summarise()` input `lm`. ## x Input `lm` must be a vector, not a `lm` object. ## ℹ Input `lm` is `lm(mpg ~ disp)`. ## ℹ The error occurred in group 1: cyl = 4. O erro nos diz: “A coluna lm deve ter o comprimento 1, não 12” ou seja, o resultado precisa ser um valor de resumo e não todo o resultado do ajuste dos modelos.\nAgora vejamos utilizando a abordagem split-apply-combine que irá nos permitir aplicar qualquer tipo de função nos dados agrupados por pela variável cyl:\nas_tibble(mtcars) %\u0026gt;% # input data nest(-cyl) %\u0026gt;% # split mutate(lm = map(data, ~lm(mpg ~ disp, data = .x) %\u0026gt;% broom::tidy())) %\u0026gt;% # apply unnest(lm) # combine ## # A tibble: 6 x 7 ## cyl data term estimate std.error statistic p.value ## \u0026lt;dbl\u0026gt; \u0026lt;list\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 6 \u0026lt;tibble [7 × 10]\u0026gt; (Intercept) 19.1 2.91 6.55 0.00124 ## 2 6 \u0026lt;tibble [7 × 10]\u0026gt; disp 0.00361 0.0156 0.232 0.826 ## 3 4 \u0026lt;tibble [11 × 10]\u0026gt; (Intercept) 40.9 3.59 11.4 0.00000120 ## 4 4 \u0026lt;tibble [11 × 10]\u0026gt; disp -0.135 0.0332 -4.07 0.00278 ## 5 8 \u0026lt;tibble [14 × 10]\u0026gt; (Intercept) 22.0 3.35 6.59 0.0000259 ## 6 8 \u0026lt;tibble [14 × 10]\u0026gt; disp -0.0196 0.00932 -2.11 0.0568 Com o auxílio do pacote broom obtemos saídas de dados arrumados e juntamos os resultados finais da regressão em uma única tabela de maneira prática.\nNa construção de gráficos Veja um outro exemplo de uso aplicando uma função para criar gráficos, agora com ggplot:\nlibrary(ggplot2) library(gridExtra) plot_list \u0026lt;- mtcars %\u0026gt;% # input data nest(-cyl) %\u0026gt;% # split/apply ↓ mutate(plots = map(data, ~ggplot(.x, aes(x=disp, y=mpg))+geom_point()+geom_smooth(method = \u0026quot;lm\u0026quot;))) %$% plots # magrittr # Combine para printar: invoke(grid.arrange,plot_list, ncol=1) # ou: grid.arrange(grobs = plot_list, ncol=1) # Combine para salvar: walk2(paste0(\u0026quot;plot\u0026quot;,1:3,\u0026quot;.png\u0026quot;), plot_list, ~ggsave(.x,.y)) Criando tabelas Por fim, um exemplo utilizando o pacote flextable.\nUtilizaremos a função flextable_custom() que adaptei para gerar uma tabela já customizada com o pacote flextable e a função save_flextable() inspirada em uma pergunta que fiz no stackoverflow sobre Como salvar uma tabela flextable como png no R?.\nVeja:\nlibrary(flextable) source(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/flextable_custom.R\u0026quot;) source(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/save_flextable.R\u0026quot;) tabela_list \u0026lt;- head(mtcars,7) %\u0026gt;% # input data nest(-cyl) %$% data %\u0026gt;% # apply map(~flextable_custom(.x)) # apply / combine # Veja a tabela: tabela_list[[1]] # Combine para salvar: walk2(paste0(\u0026quot;tab\u0026quot;,1:3,\u0026quot;.png\u0026quot;), tabela_list, ~save_flextable(.y,.x)) Conclusão Vimos aqui como funciona a estratégia e alguns exemplos de uso, porém, existem infinitas outras aplicações para esse tipo de abordagem com os dados arrumados. Dependendo da tarefa esta abordagem pode ser bem produtiva e poupar muitas linhas de código!\nNota acrescentada em 2026: versões mais recentes do tidyr mudaram um pouco a sintaxe do nest()/unnest() em relação ao usado neste post (por exemplo, especificando a coluna aninhada com data = -x em vez de só -x). O princípio de dividir, aplicar e combinar continua o mesmo.\nPara ver essa estratégia aplicada em um caso real de automação, veja o post sobre como automatizar relatórios repetitivos com RMarkdown.\nPerguntas frequentes Quando split-apply-combine é melhor que um loop for? Quando a tarefa se encaixa no padrão \"para cada grupo, faça X e junte os resultados\". O código fica mais legível, mais fácil de paralelizar e evita o gerenciamento manual de índices e acumuladores típico de um loop for.\nPor que usar nest() em vez de só group_by() + summarise()? group_by() + summarise() só funciona quando o resultado de cada grupo é um único valor resumo. Quando o resultado é algo mais complexo (um modelo ajustado, um gráfico, uma tabela), é preciso nest() para guardar cada subconjunto de dados como um elemento de lista e aplicar a função com map().\nO pacote plyr ainda deve ser usado? Não é recomendado para projetos novos. O plyr parou de receber grandes atualizações, e as mesmas tarefas hoje são cobertas com mais eficiência pela combinação de dplyr, tidyr e purrr do tidyverse.\nReferências Além das referências deixarem aqui algumas sugestões de leitura:\nhttps://github.com/tidyverse/purrr https://tibble.tidyverse.org/ https://vita.had.co.nz/papers/plyr.pdf https://adv-r.hadley.nz/functionals.html#purrr-style https://davisvaughan.github.io/furrr/ ","date":"5 de abril de 2019","externalUrl":null,"permalink":"/post/2019-04-05-split-apply-combine/","section":"Posts","summary":" O método split-apply-combine Geralmente em uma análise de dados precisamos compreender, além do comportamento geral dos dados, o seu comportamento de acordo com alguns segmentos.\nNo famoso paper The Split-Apply-Combine Strategy for Data Analysis, Hadley Wickham descreve a abordagem “split-apply-combine” (dividir-aplicar-combinar) como uma das mais comuns em uma análise de dados. Em R essa tarefa pode ser feita por diversos caminhos, veja alguns dos modos de se fazer utilizando funções base do R e abordagens mais antigas:\n","title":"Hackeando o R: estratégia split-apply-combine","type":"post"},{"content":"","date":"5 de abril de 2019","externalUrl":null,"permalink":"/tags/split-aply-combine/","section":"Tags","summary":"","title":"Split-Aply-Combine","type":"tags"},{"content":"","date":"5 de abril de 2019","externalUrl":null,"permalink":"/tags/tabelas/","section":"Tags","summary":"","title":"Tabelas","type":"tags"},{"content":"","date":"26 de dezembro de 2018","externalUrl":null,"permalink":"/tags/retrospectiva/","section":"Tags","summary":"","title":"Retrospectiva","type":"tags"},{"content":"","date":"26 de dezembro de 2018","externalUrl":null,"permalink":"/tags/shiny/","section":"Tags","summary":"","title":"Shiny","type":"tags"},{"content":" Até que um dia.. Agora em dezembro encerro um desafio pessoal de fazer pelo menos um post por mês durante o ano de 2018 e estou muito animado com o término deste ciclo! Espero ter contribuído um pouquinho com a comunidade de Estatística e Ciência de Dados que está maior a cada dia e cada vez mais importante.\nA ideia de fazer um blog começou quando me deparei que tinha muitos scripts e rotinas guardados de alguns estudos sobre programação e estatística tanto sobre os assuntos da faculdade quanto sobre estudos avulsos de programação em R. Guardar os scripts de maneira organizada para relembrar e tentar fixar melhor alguns conceitos já vistos pode ser uma boa idéia acelerando o processo de busca por soluções para problemas computacionais do dia a dia.\nDesde o início da graduação tomei o hábito de guardar todos meus arquivos no Dropbox (que é excelente ferramenta, inclusive porque é possível integrar com o R/Shiny). Até que um dia me dei conta de que estava acumulando cada vez mais scripts e relatórios em meu dropbox e além de não ser muito prático o acesso aos scripts, acaba não sendo muito dinâmico no compartilhamento com os membros da equipe, então passei a utilizar o Github para hospedar meus códigos, projetos, funções e estudos que poderiam tornar-se públicos e assim facilitar na hora de compartilhar algum código ou receber algum feedback.\nAlém do Github, o RPubs também foi útil para publicação de alguns trabalhos/projetos durante a graduação e alguns testes e contribuições nas competições e conjuntos de dados do Kaggle (além de bisbilhotar as resoluções dos top players) para aprender de uma maneira diferente um pouquinho mais a cada dia. Já no caso de trabalhos privados (solo ou em equipe), o Bitbucket também tem se mostrado uma ótima ferramenta.\nPassei a receber feedback sobre meus códigos, sugestões de melhorias e isso me motivou a continuar e persistir nos posts independente de monografia, estágio, trabalho, ou qualquer outro compromisso super importante. Firmei esse desafio pessoal e abaixo será possível conferir um pouco de como foi minha evolução, algumas técnicas e curiosidades que aprendi e achei que valia a pena compartilhar com a comunidade.\nAnálise de sobrevivência com dados do jogo PUBG disponíveis no Kaggle Calcular a probabilidade de um indivíduo sobreviver e também encontrar fatores de risco de morte em um intervalo de tempo. Foram realizadas estatísticas descritivas e o ajuste de modelos de sobrevivência como o de Kaplan-Meier e o Modelo de regressão de riscos proporcionais de Cox.\nSeu app, RStudio e Shiny Server na nuvem do Google Aprendemos como dar início à uma máquina virtual rodando Linux Ubuntu 16.04 no servidor do Google Cloud. Com nossa máquina virtual na configuração desejada somos capazes de dar início ao nosso próprio RStudio Server e também nosso Shiny Server para facilitar a entrega de nossas aplicações, como a que foi criada de exemplo no post para acompanhar as cotações e algumas ações de bolsas de valores americanas.\nCom que frequência ocorrem acidentes na ponte Rio-Niterói? Neste post utilizamos os dados públicos fornecidos pela polícia rodoviária federal para responder algumas perguntas relacionadas à ocorrência de acidentes. Será que o número de acidentes vem diminuindo? Será que a instalação de câmeras de segurança reduziu o número de acidentes? Uma breve análise de caráter descritivo irá ajudar a entender o comportamento dos dados e permitir novas reflexões.\nUm estudo sobre modelos de aprendizagem baseados em árvores com desafio do Kaggle Utilizamos a base de dados da competição do Kaggle House Prices: Advanced Regression Techniques para colocar em prática alguns dos conhecimentos adquiridos estudando sobre algoritmos como árvore de decisão, random forest, gradient boost machine e por fim uma regressão linear para comparar os resultados obtidos.\nAjustando um modelo de regressão linear bayesiano do zero Neste post são realizados os cálculos das distribuições condicionais completas a posteriori (DCCP) para cada parâmetro do ajuste de um modelo de regressão linear bayesiano para poder implementar o algoritmo do amostrador de Gibbs em dados simulados (para conferir a qualidade do ajuste do modelo) e em dados reais. Este post é o resumo de uma das aplicações que fiz em um projeto de iniciação à pesquisa que deixei disponível no Github.\nBrasil x Argentina, tidytext e machine learning Nesta época eu estava estudando o livro da Julia Silge depois de uma palestra que assisti no SER 2018 e aproveitando o embalo da copa do mundo resolvi conferir os dados do twitter disponibilizados através da API do Twitter naquela época para uma aplicação de análise de sentimentos utilizando a abordagem tidytext. Além disso foram utilizados os modelos knn, random forest, naive bayes e um modelo de regressão logístico para um estudo sobre classificação em análises de texto com o pacote caret.\nAED de forma rápida e um pouco de machine learning Este post veio para lembrar como a análise exploratória em R não precisa sempre ser uma tarefa longa e trabalhosa. Com o pacote SmartEAD é possível gerar muitos gráficos com poucas linhas de código. Ao longo do post algumas tarefas de machine learning são executadas, como k-means (tarefa não-supervisionada de agrupamento), um modelo de regressão linear com stepwise (tarefa supervisionado de regressão) e um modelo random forest (tarefa supervisionada de classificação).\nSéries temporais com Google Trends e R Como é fácil obter dados do Google Trends para analisá-los no RStudio. Obtivemos algumas séries e duas delas chamaram mais a atenção: a popularidade do termo Big Data (que está aumentando) e a popularidade do termo Estatística que estava diminuindo. Realizamos a decomposição da série, realizamos alguns testes estatísticos para detectar significância dos componentes das séries e foram ajustados modelos de Holt Winters para tentar prever o comportamento destas séries no próximo ano.\nProduzindo e formatando um documento Word direto em R O bom de programar em R é que não precisamos nos limitar apenas à ferramenta, podemos importar e exportar arquivos em diferentes formatos e entregar nossos resultados de muitas maneiras. Neste post é mostrado como exportar seus relatórios em Word utilizando um template.\nO que são cheatsheets, gamificação e por que aprender R é tão divertido? A aprendizagem é um processo que nunca acaba e neste post mostro algumas maneiras de estudar R e estatística se divertindo! Falamos o que são as CheatSheets, cursos da DataCamp, onde é possível ter cursos altamente práticos com os desenvolvedores dos principais pacotes utilizando em Ciência de Dados e falamos sobre a plataforma Kaggle, um verdadeiro playground para Cientistas de dados que podem disputar por posições em um rank mundial e compartilhar códigos e análises para ter o feedback de outros cientistas de dados ao redor do mundo.\nCarnaval e mapas interativos com R Era fevereiro, véspera de carnaval e grande parte das pessoas no Rio de Janeiro gostariam de responder a seguinte pergunta: \"Onde estão os blocos?\". Neste post construímos mapas interativos com o uso do pacote leaflet e em poucas linhas de código foi possível mapear os blocos ao redor do Rio de Janeiro facilitando assim a vida do folião carioca.\nO paradoxo dos aniversários com simulação e probabilidade A probabilidade é contra intuitiva. Existem diversos exemplos clássicos de probabilidade que nos mostram como pode ser enganosa nossa intuição ao tratar com a incerteza. Neste post utilizamos de simulação e de teoria das probabilidades para mostrar como a probabilidade de duas pessoas fazerem aniversário no mesmo dia em uma sala de aula aumenta muito rápido conforme aumentamos o número de alunos nessa sala.\nTabelas incríveis com R As saídas do console do R podem não ser a melhor forma de entregar suas valiosas análises. Quando estamos numa situação de negócios ou consultoria a apresentação dos dados também é muito importante e o R não fica para trás nisso! Neste post vimos como alguns pacotes como o DT, knitr, kableExtra, formattable, sparkline e rhandsontable podem tornar a apresentação de nossas tabelas muito mais elegantes.\nAnálise multivariada com R Em tempos de Big Data esse campo da estatística torna-se cada vez mais importante. Saber lidar com grandes volumes e variedades de dados pode ser muito importante e neste post vimos um pouco sobre técnicas de estatística multivariada como PCA, Análise Fatorial, Clusterização com agrupamento hierárquico e com k-means.\nPacotes do R para avaliar o ajuste de modelos O Modelo de regressão linear é uma ótima ferramenta para qualquer estatístico, ele é altamente interpretável e a avaliação de seu desempenho pode ser feita de forma meticulosa. Neste post utilizamos os pacotes GGally e o ggfortify para fazer diagnósticos bem elaborados sobre as premissas que sustentam o uso de tais modelos.\nAlém disso… Além dos posts acima, também já passou por aqui:\nPosts mais antigos Além dos posts acima que ficaram em destaque, por aqui também foram postados:\nAjustando modelos bayesianos com JAGS Manipulação de strings e text mining Criando relatórios com template Tufte Manipulando dados com dplyr Analisando o mercado de criptomoedas com R Gerenciando arquivos do Dropbox com R Tipos de relações entre variáveis Tipos de correlações Aplicativos Shiny Esses são os aplicativos para uso público que desenvolvi (alguns ainda em faze de aprendizagem) que contam com os códigos hospedados no Github, além deles desenvolvi uma porção de aplicações que estão hospedadas no Bitbucket porém como são privados não poderei compartilha-las aqui:\nDashboard com textmining de mídias sociais App para criação de núvens de palavras cusmomizadas App para acompanhar cotações de ações da bolsa de valores americana (e algumas ações BR) App para rápica aplicação de componentes principais e do algoritmo de machine learning k-means Iniciação à Pesquisa: Este foi um estudo sobre modelagem hierárquica sob a ótica da escola bayesiana para me preparar para escrever minha monografia, que contou com uma aplicação deste modelo na vida real:\nProjeto de Iniciação à Pesquisa: Modelos Hierárquicos Bayesianos Writer da ENSINA.AI Esse ano também recebi um convite inesperado de participar como escritor contribuidor da página ENSINA.AI no medium, que tem como compromisso trazer ao público: Tudo sobre Inteligência Artificial em Português. Fiquei muito feliz com o convite pois já acompanhava a página e os posts sempre são muito bons! Os posts que contribui foram:\nCom que frequência ocorrem acidentes na ponte Rio-Niterói? Seu app, RStudio e Shiny na nuvem do Google Um estudo sobre modelos de aprendizagem baseados em árvores com desafio do Kaggle Ajustando um modelo de regressão linear bayesiano do zero Extras : Bancos de dados públicos - Apresentando alguns sites que disponibilizam dados públicos Sobre ombros de gigantes - Algumas frases de pensadores que me inspiram Boas festas! Agora o ano está se encerrando e assim se encerra mais um ciclo, estou muito satisfeito pois aprendi muita coisa nova, interagi com muita gente inteligente e me diverti demais na produção deste blog.\nForam diversos desafios pois no começo foi bem complicado entender como manipular html, css e controlar as versões dos códigos no git pois era tudo muito novo mas o desafio valeu a pena, hoje aprendi um pouquinho sobre essas e outras ferramentas que um estatístico não vê na graduação e foi bem proveitoso em meus trabalhos. Se consegui ajudar pelo menos uma pessoa já atingi minha meta, se ajudei duas pessoas então consegui dobrar essa meta!\nTL;DR\nO post é uma retrospectiva do desafio pessoal de publicar pelo menos um post por mês durante todo o ano de 2018. Ao longo do ano o autor passou a usar Github, RPubs, Kaggle e Bitbucket para organizar e compartilhar códigos, scripts e projetos. Em 2019 o desafio mensal não continuaria, mas o blog seguiria em ritmo mais calmo com novas ideias de posts. Se souber exatamente o que fazer, qual a vantagem de fazê-lo? - Pablo Picasso\nAgora no ano de 2019 \"fazer pelo menos um post por mês\" não estará em meus planos, mas já tenho diversas ideias de posts e continuarei escrevendo em um ritmo um pouco mais calmo pois os estudos estão cada vez mais difíceis!\nEspero que tenham gostado do conteúdo e obrigado por toda ajuda direta ou indiretamente de cada membro da comunidade que fez valer a pena cada minuto de esforço!\nPerguntas frequentes Qual foi o desafio pessoal do autor durante o ano de 2018?\nO desafio foi publicar pelo menos um post por mês ao longo de todo o ano de 2018, ciclo que se encerrou em dezembro daquele ano.\nQuais ferramentas o autor passou a usar para organizar seus scripts e projetos?\nEle passou a usar o Github para hospedar códigos e projetos públicos, o RPubs para publicar trabalhos, o Kaggle para competições e o Bitbucket para projetos privados.\nO desafio de postar mensalmente continuaria em 2019?\nNão, o autor decidiu que em 2019 não manteria o compromisso de um post por mês, optando por escrever em um ritmo mais calmo devido aos estudos.\n","date":"26 de dezembro de 2018","externalUrl":null,"permalink":"/post/2018-12-26-retrospectiva/","section":"Posts","summary":" Até que um dia.. Agora em dezembro encerro um desafio pessoal de fazer pelo menos um post por mês durante o ano de 2018 e estou muito animado com o término deste ciclo! Espero ter contribuído um pouquinho com a comunidade de Estatística e Ciência de Dados que está maior a cada dia e cada vez mais importante.\n","title":"Um ano de blog! Retrospectiva de 2018 em Data Science","type":"post"},{"content":" Análise de sobrevivência e PUBG Análise de sobrevivência é um termo que se refere a situações médicas e é caracterizada pela sua variável resposta, que pode ser apresentada de três formas: probabilidade de sobrevivência, taxa de incidêcia e taxa de incidência acumulada.\nNa engenharia este termo também é conhecido como confiabilidade, no entanto, condições parecidas podem ocorrer em (inusitadas) outras áreas.\nPUBG é um jogo online multiplayer de batalha em que 100 jogadores são lançados em uma ilha e tem como objetivo principal sobreviver, a área de jogo diminui progressivamente, confinando os sobreviventes a um espaço cada vez menor e forçando encontros e o vencedor é o último jogador (ou time) a permanecer vivo.\nUm único jogo dura aproximadamente de 30-35 minutos e neste tempo o jogador coleta itens (arma, cura, boost), abate outros jogadores, comete e leva dano de seus adversários, pode dirigir veículos dentre outras ações enquanto tentam sobrevier ao mesmo tempo.\nAssim como no post sobre gamificação e o ranking de competições do Kaggle, a dinâmica de sobrevivência do PUBG também tem seu apelo de disputa entre os jogadores. Questões que surgiram em mente após um período de estudos de análise de sobrevivência e confiabilidade e ouvindo pessoas falarem sobre esta modalidade de jogo:\nO que interefere na probabilidade de um indivíduo sobreviver? O que tem efeito no risco de um jogador ser abatido em um intervalo de tempo? Faremos uma abordagem estatística aqui, após uma breve análise exploratória os dados serão avaliados utilizando o modelo de Kaplan-Meier, que é um estimador de forma não paramétrica para a função de sobrevivência e o modelo semiparamétrico de regressão de riscos proporcionais de Cox.\nTL;DR\nTratamos cada morte no PUBG como um \"evento\" e o tempo de sobrevivência do jogador como a variável resposta. Kaplan-Meier estima a curva de sobrevivência; o teste log-rank compara curvas entre grupos. O modelo de Cox ajustado mostra que performance e distância percorrida reduzem o risco de morte, enquanto dirigir aumenta. A Base de dados A base de dados utilizada foi obtida através do Kaggle em “PUBG Match Deaths and Statistics”: https://www.kaggle.com/skihikingkevin/pubg-match-deaths que conta com mais de 65 milhões de registros de mortes no jogo PlayerUnknown Battleground’s matches - PUBG.\nExiste uma versão deste post no kaggle e além desta base, existe uma competição em andamento que vai até o dia 30 de Janeiro no link:https://www.kaggle.com/c/pubg-finish-placement-prediction que desafia os jogadores a prever o posicionamento do vencedor em percentil, onde 1 corresponde ao 1º lugar e 0 corresponde ao último lugar do jogo. Fiz uma participação com um script testando os resultados do algorítmo xgboost com caret e também testei uns ajustes com random forest utilizando o tidyverse, na mesma linha do outro desafio do Kaggle que resolvi com modelos baseados em árvore. Esses scripts são abertos e estão prontos para uso, não me renderam a melhor posição mas a intensão aqui é, principalmente, aprender e testar os métodos pois São muitas possibilidade para aprender e praticar. Voltando a base de dados:\nSegundo a descrição da base no kaggle:\nagg_match_stats_x.csv fornece informações de correspondência mais agregadas sobre os dados de mortes, como tamanho da fila, fpp/tpp, morte do jogador, etc.\nAs colunas são as seguintes:\nmatch_id : O id único de correspondência gerado por pubg.op.gg. É possível fazer uma junção disso com os dados das mortes para ver todas as informações party_size : o número máximo de jogadores por equipe. por exemplo, 2 implica que era um sistema de fila dupla player_dist_ride : unidades de distancia total (metros?) que o jogador percorreu em um veículo player_dist_walk : unidades de distancia total (metros?) percorrida pelo jogador a pé match_mode : se o jogo foi jogado em primeira pessoa (fpp) ou em terceira pessoa (tpp) team_placement : a classificação final da equipe dentro da partida player_dmg : Total de pontos de vida que o jogador distribuiu player_assists : Número de assistências que o jogador marcou game_size : o número total de equipes que estavam no jogo player_dbno : Número de knockdowns que o jogador marcou player_kills : Número de mortes que o jogador marcou team_id : o ID da equipe à qual o jogador pertencia date : a data e a hora em que a partida ocorreu player_name : nome do jogador A rotinas abaixo carregam os pacotes, funções customizadas e salva em extensão .rdsuma amostra da base de dados utilizadas ao longo do post:\n# Carregar pacotes -------------------------------------------------------- packages \u0026lt;- c(\u0026quot;data.table\u0026quot;, \u0026quot;dplyr\u0026quot;, \u0026quot;purrr\u0026quot;, \u0026quot;survival\u0026quot; , \u0026quot;survminer\u0026quot;, \u0026quot;ggfortify\u0026quot;,\u0026quot;GGally\u0026quot;, \u0026quot;ggplot2\u0026quot;,\u0026quot;moments\u0026quot;, \u0026quot;gridExtra\u0026quot;,\u0026quot;ggExtra\u0026quot;, \u0026quot;cowplot\u0026quot;,\u0026quot;lubridate\u0026quot;, \u0026quot;scales\u0026quot;, \u0026quot;knitr\u0026quot;, \u0026quot;kableExtra\u0026quot;, \u0026quot;grid\u0026quot;, \u0026quot;broom\u0026quot;, \u0026quot;formattable\u0026quot;, \u0026quot;grid\u0026quot;) purrr::walk(packages,library, character.only = TRUE, warn.conflicts = FALSE) rm(packages) # Funcoes customizadas do github ------------------------------------------ source(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/inicio_e_fim_da_base.R\u0026quot;) source(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/grafico_descritivo.R\u0026quot;) source(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/sumario_custom_num.R\u0026quot;) # Opcoes do documento ----------------------------------------------------- # options(scipen = 99999) # Tema dos graficos ------------------------------------------------------- theme_set(theme_bw()+ theme(axis.text.x = element_text(size=17), axis.text.y = element_text(size=17), axis.title.y = element_text(size=20), legend.position = \u0026quot;bottom\u0026quot;)) # Tema das tabelas kable -------------------------------------------------- kable2 \u0026lt;- function(x,linhas=NULL,colunas=NULL, ...){ k \u0026lt;- kable(x,digits = 4,...) %\u0026gt;% kable_styling(bootstrap_options = \u0026quot;striped\u0026quot;, full_width = F) %\u0026gt;% kable_styling(c(\u0026quot;striped\u0026quot;, \u0026quot;bordered\u0026quot;)) if (!is.null(linhas)) { # destque na linha: k \u0026lt;- k %\u0026gt;% row_spec(linhas, bold = T, color = \u0026quot;white\u0026quot;, background = \u0026quot;#FFE8BD\u0026quot;) } if (!is.null(colunas)) { # destque na colunas: k \u0026lt;- k %\u0026gt;% column_spec(colunas,bold=T, color=\u0026quot;white\u0026quot;, background = \u0026quot;#FFE8BD\u0026quot;) } k %\u0026gt;% scroll_box(width = \u0026quot;850px\u0026quot;) } Em uma análise de sobrevivência é comum a presença de observações censuradas, (isto é, quando ocorre a perda de informação decorrente de não se ter observado a data de ocorrência do desfecho). No caso dessa base de dados não existe uma variável que define a censura, pois apenas a morte do jogador é registrada e é possível que se os jogadores se desconectarem do jogo mesmo que não sejam mortos seja contado como morte de qualquer jeito. Os detalhes por trás da aquisição de dados não trazem essa informação portanto pode não ser possível distinguir a censura do desfecho e isso é um detalhe relevante que deve ser levado em conta.\n# Carregar base ----------------------------------------------------------- set.seed(2) # reprodutivel pubg_tpp1 \u0026lt;- # Informacoes dos criterios de selecao no corpo do texto map_df(paste0(\u0026quot;agg_match_stats_\u0026quot;,0:4,\u0026quot;.csv\u0026quot;), ~ fread(.x, showProgress = T, data.table = T)[match_mode == \u0026quot;tpp\u0026quot; \u0026amp; party_size == 1 \u0026amp; year(date) == 2018 \u0026amp; player_dist_walk\u0026gt;10 \u0026amp; player_dmg != 0 ][, !c(\u0026quot;match_mode\u0026quot;,\u0026quot;party_size\u0026quot;,\u0026quot;game_size\u0026quot;,\u0026quot;date\u0026quot;, \u0026quot;team_id\u0026quot;,\u0026quot;player_dbno\u0026quot;, \u0026quot;team_placement\u0026quot;), with=FALSE][,player_survive_time := player_survive_time/60] %\u0026gt;% group_by(match_id) %\u0026gt;% do(sample_n(.,1)) %\u0026gt;% ungroup() ) # Salvar base coletada ---------------------------------------------------- saveRDS(pubg_tpp1,\u0026quot;pubg_tpp1.rds\u0026quot;) Descrição da rotina acima e os critérios para a seleção da amostra:\npercorre as 5 bases disponíveis: paste0(\"agg_match_stats_\",0:4,\".csv\") seleciona partidas em terceira pessoa: match_mode == \"tpp\" com tamanho da equipe = 1 (individual): party_size == 1 do ano de 2018: year(date) == 2018 andaram mais que 10 unidades de distancia (metros?): player_dist_walk\u0026gt;10 fizeram algum dano (evitar jogadores ausentes): player_dmg != 0\nremove colunas não utilizadas na analise converte do tempo para minutos: player_survive_time := player_survive_time/60 agrupa por partida: group_by(match_id) seleciona um jogador de cada partida: do(sample_n(.,1)) Note que apenas um jogador de cada partida é selecionado na intenção de obter independência entre observações, isso reduziu drasticamente seu tamanho. Agora que a base já foi importada e filtrada, faremos a leitura de 200 linhas aleatórias com a finalidade de diminuir o tempo computacional das operações realizadas em seguida.\nset.seed(1) pubg_tpp1 \u0026lt;- readRDS(\u0026quot;pubg_tpp1.rds\u0026quot;) %\u0026gt;% sample_n(200)%\u0026gt;% select(-one_of(c(\u0026quot;match_id\u0026quot;, \u0026quot;player_name\u0026quot;))) Veja a seguir de forma visual como as variáveis numéricas se correlacionam:\npubg_tpp1 %\u0026gt;% rev %\u0026gt;% grafico_descritivo() Variável resposta Vejamos o que acontece ao analisar o tempo de sobrevivência de cada jogador\nA seguir, a distribuição da variável resposta player_survive_time :\nplot_grid(pubg_tpp1 %\u0026gt;% ggplot(aes(x=player_survive_time))+ geom_histogram(aes(y = ..density..), bins = 30, fill=\u0026quot;white\u0026quot;, color=\u0026quot;black\u0026quot;)+ geom_density(alpha=.2, fill=\u0026quot;white\u0026quot;)+ scale_x_continuous(labels = scales::comma, limits = c(0,40), breaks = seq(0,40,5))+ labs(x=\u0026quot;\u0026quot;,y=\u0026quot;\u0026quot;, title = \u0026quot;Tempo de sobrevivência dos jogadores selecionados\u0026quot;) , pubg_tpp1 %\u0026gt;% ggplot(aes(x=\u0026quot; \u0026quot;, y=player_survive_time))+ geom_boxplot()+ labs(x=\u0026quot;\u0026quot;)+ coord_flip() , ncol = 1, nrow = 2, align = \u0026quot;v\u0026quot;, rel_heights = c(3,1)) Note que possue uma assimetria positiva\nData Wrangling Primeiramente, vejamos as variáveis se relacionam entre si e com a variável resposta com os coeficientes de correlação de Pearson:\n# Correlations pubg_tpp1 %\u0026gt;% select_if(is.numeric) %\u0026gt;% cor() %\u0026gt;% corrplot::corrplot(method = \u0026quot;number\u0026quot;,type = \u0026quot;upper\u0026quot;,diag = F, order = \u0026quot;hclust\u0026quot;,number.cex = 0.7, title = \u0026quot;Correlation correlated numerics\u0026quot;, mar=c(0,0,1,0)) É possível notar que apenas a variável player_assists não correlaciona-se com a variável resposta nem com as demais variáveis e player_dmg e player_kills são fortemente correlacionadas, isso indica que pode ser interessante remover uma delas ou juntar toda essa informação em uma única variável, veremos…\nAlém disso nota-se que a distância percorrida a pé é fortemente correlacionada com a variável resposta enquanto que a distância de quem andou de carro não é tão correlacionada. Uma transformação na variável player_dist_ride para uma dummy drive indicando se o indivíduo dirigiu ou não pode representar melhor esta informação.\nVejamos algumas características peculiares:\npubg_tpp1 %\u0026gt;% select(player_kills, player_dist_ride, player_assists) %\u0026gt;% map_dfr(~quantile(.x, probs = seq(0,1,0.25)) %\u0026gt;% round(2)) %\u0026gt;% t %\u0026gt;% tidy() %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;variável\u0026quot;,percent(seq(0,1,0.25)))) %\u0026gt;% kable2() Praticamente metade da amostra não registrou abates nem possui marcação de player_dist_ride. Como a variável player_dmg apresentou correlação com a variável resposta player_survive_time, vamos fazer algumas transformações:\nCriar uma variável dummy drive se jogador usou carro Somar a player_dist_ride e player_dist_walk em uma única variável: player_dist Juntar player_kills, player_dmg e player_assists em uma única variável: player_performance Player performance Como criar a variável player_performance?\nTentei inventar uma metodologia e com certeza devem existir maneiras mais eficientes de se fazer isso, porém, deixa eu explicar o que eu pensei, considere a formula:\n\\[ Playerperformance = log(WPlayerDmg + WPlayerAssists + WPlayerKills) \\]\nonde:\n\\[ WPlayerKills = log(PlayerKills+0.5)\\\\ WPlayerDmg = log(PlayerDmg)\\\\ WPlayerAssists = PlayerAssists \\]\nNote que:\n\\(WPlayerAssists\\): Não é feita qualquer transformação; \\(WPlayerDmg\\): A distribuição fica “quase simétrica” após a transformação log; \\(WPlayerKills\\): adiciona-se 0.5 para poder tirar o log pois podem existir zeros nessa variável e além disso, quem não marcou abate será penalizado com \\(-1\\) na soma final do score: player_performance. Veja a seguir de forma visual a distribuição das variáveis que farão parte da variável player_performance na parte de cima e na parte inferior o que acontece após sua soma, gerando a nova variável player_performance :\nperformance \u0026lt;- tibble(w_player_kills = log(pubg_tpp1$player_kills+0.5), w_player_dmg = log(pubg_tpp1$player_dmg), w_player_assists = pubg_tpp1$player_assists) %\u0026gt;% mutate(player_performance = log(w_player_dmg + w_player_assists + w_player_kills)) grid.arrange( performance %\u0026gt;% select(-player_performance) %\u0026gt;% tidyr::gather() %\u0026gt;% ggplot(aes(x=value))+ geom_histogram(aes(y = ..density..), bins = 30, fill=\u0026quot;white\u0026quot;, color=\u0026quot;black\u0026quot;)+ geom_density(alpha=.2, fill=\u0026quot;white\u0026quot;)+ scale_x_continuous(labels = scales::comma, limits = c(-1.5,8), breaks = seq(-1,8,1))+ labs(x=\u0026quot;\u0026quot;, y=\u0026quot;\u0026quot;)+ theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank())+ facet_wrap(~key, scales = \u0026quot;free\u0026quot;) , performance %\u0026gt;% select(player_performance) %\u0026gt;% tidyr::gather() %\u0026gt;% ggplot(aes(x=value))+ geom_histogram(aes(y = ..density..), fill=\u0026quot;white\u0026quot;, color=\u0026quot;black\u0026quot;,bins = 15)+ geom_density(alpha=.2, fill=\u0026quot;white\u0026quot;)+ scale_x_continuous(limits = c(-1.,2.5), breaks = seq(-1,3,0.5))+ labs(x=\u0026quot;\u0026quot;, y=\u0026quot;\u0026quot;, title = \u0026quot;performance\u0026quot;), ncol=1 ) Transformações na base A seguir faremos as mudanças diretamente no dataset que estamos trabalhando:\npubg_tpp1 \u0026lt;- pubg_tpp1 %\u0026gt;% mutate(player_dist = log(player_dist_ride + player_dist_walk)) %\u0026gt;% mutate(player_assists_d = if_else(player_assists ==0, 0, 1)) %\u0026gt;% mutate(player_performance = performance$player_performance )%\u0026gt;% mutate(drive = ifelse(player_dist_ride==0, \u0026quot;no\u0026quot;, \u0026quot;yes\u0026quot;) %\u0026gt;% as.factor()) %\u0026gt;% mutate(player_kills_d = ifelse(player_kills==0, \u0026quot;no\u0026quot;, \u0026quot;yes\u0026quot;) %\u0026gt;% as.factor()) A manipulação acima cria as seguintes variáveis:\nplayer_dist como o log da soma de player_dist_ride e player_dist_walk player_assists_d como uma dummy: 1 se o jogador deu assistência; 0 c.c. player_performaec como a combinação de player_dmg, player_assists e player_kills drive como uma dummy: 1 se o jogador dirigiu; 0 c.c. player_kills_d como uma dummy: 1 se jogador matou alguém; 0 c.c. Vejamos como ocorre a distribuição das variáveis numéricas após as transformações:\ng1 \u0026lt;- pubg_tpp1 %\u0026gt;% # select_if(~ !length(table(.x))==2 \u0026amp; is.numeric(.x)) %\u0026gt;% colnames() %\u0026gt;% select(player_survive_time,player_performance,player_dist) %\u0026gt;% colnames() %\u0026gt;% map2(c(\u0026quot;Densidade\u0026quot;, \u0026quot;\u0026quot;, \u0026quot;\u0026quot;), ~ plot_grid( pubg_tpp1 %\u0026gt;% ggplot(aes_string(x=.x)) + geom_histogram(aes(y=..density..),colour=\u0026quot;black\u0026quot;, fill=\u0026quot;white\u0026quot;, bins = 15) + geom_density(alpha=.2, fill=\u0026quot;lightgrey\u0026quot;) + scale_x_continuous()+ ggtitle(.x)+ labs(x=\u0026quot;\u0026quot;, y=.y)+ theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()) , pubg_tpp1 %\u0026gt;% ggplot(aes_string(, y=.x))+ geom_boxplot(aes(x=\u0026quot; \u0026quot;))+ labs(x=\u0026quot;\u0026quot;, y=\u0026quot;\u0026quot;)+ coord_flip()+ theme(axis.title.x=element_blank(), axis.text.x=element_blank(), axis.ticks.x=element_blank()), ncol = 1, nrow = 2, align = \u0026quot;v\u0026quot;, rel_heights = c(3,1) ) ) dat \u0026lt;- pubg_tpp1 %\u0026gt;% select_if(~.x %\u0026gt;% table %\u0026gt;% length == 2) %\u0026gt;% mutate_at(2,~if_else(.x==0, \u0026quot;no\u0026quot;, \u0026quot;yes\u0026quot;)) %\u0026gt;% .[,-1] g2 \u0026lt;- map2(colnames(dat), c( \u0026quot;Porcentagem\u0026quot;, \u0026quot;\u0026quot;,\u0026quot;\u0026quot;), ~ dat[,.x] %\u0026gt;% tidyr::gather() %\u0026gt;% group_by(key, value) %\u0026gt;% summarise(n = n()) %\u0026gt;% mutate(prop = n/sum(n)) %\u0026gt;% ggplot(aes(x = key, y = prop,fill = value)) + geom_bar(position = \u0026quot;fill\u0026quot;,stat = \u0026quot;identity\u0026quot;, alpha=0.7) + scale_y_continuous(labels = percent_format())+ labs(x=\u0026quot;\u0026quot;, y = .y)+ scale_fill_manual(values = c(\u0026quot;grey\u0026quot;, \u0026quot;#FCC14B\u0026quot;), name = \u0026quot;Legenda:\u0026quot;) ) grid.arrange(g1[[1]], g1[[2]], g1[[3]],g2[[1]], g2[[2]], g2[[3]], ncol=3, heights=c(3/5, 2/5)) Apos a transformação a distribuição e demais informações dos dados, vejamos novamente a distribuição das variáveis da amostra com os gráficos de dispersão, densidade e correlações levando em conta se dirigiu ou não:\ngrafico_descritivo(x = pubg_tpp1, colNames = c(\u0026#39;player_survive_time\u0026#39;, \u0026quot;player_performance\u0026quot;, \u0026#39;player_dist\u0026#39;, \u0026#39;player_assists_d\u0026#39;,\u0026quot;player_kills_d\u0026quot;, \u0026#39;drive\u0026#39;), color=\u0026#39;drive\u0026#39;, colors = c(\u0026quot;grey\u0026quot;, \u0026quot;#FCC14B\u0026quot;)) O fato do jogador ter dirigido ou não exibiu padrões interessantes, pode ser que seja significante no ajuste do modelo final.\nAnálise de sobrevivencia O passo inicial de qualquer análise estatística consiste em uma descrição dos dados e o principal componente da análise descritiva envolvendo dados de tempo de vida é a função de sobrevivência: \\(S(t) = P(T\u0026gt;t)\\), que determina a probabilidade de um indivíduo sobreviver por mais do que um determinado tempo \\(t\\), ou por no mínimo um tempo igual a \\(t\\).\nA descrição dos dados já foi realizada, agora faremos a descrição envolvendo a função de sobrevivência.\nKaplan-Meier Para isso existem algumas alternativas como o estimador de Kaplan-Meier, que utiliza os conceitos de independência e de probabilidade condicional para deduzir a probabilidade de sobreviver até o tempo \\(t\\).\nPra quem quer ir além do básico de Kaplan-Meier e regressão de Cox, o An Introduction to Statistical Learning tem um capítulo bem didático sobre análise de sobrevivência que ajuda a fechar essa base teórica.\nVeja a seguir são ajustados os modelos univariados de Kaplan-Meier para cada uma das coivaráveis da amostra:\nsurv \u0026lt;- Surv(pubg_tpp1$player_survive_time) resultado_km \u0026lt;- list(geral = survfit(surv ~ 1 ,data = pubg_tpp1), player_assists_d = survfit(surv ~ player_assists_d ,data = pubg_tpp1), drive = survfit(surv ~ drive,data = pubg_tpp1 ), player_kills_d = survfit(surv ~ player_kills_d,data = pubg_tpp1)) Veja os resultados da função de sobrevivência sem levar em consideração nenhuma das coivaráveis:\nsurv_summary(resultado_km[[1]], pubg_tpp1) %\u0026gt;% .[1:5,-ncol(.)] %\u0026gt;% cbind(variable = \u0026quot;Geral\u0026quot;) %\u0026gt;% select(variable, everything())%\u0026gt;% kable2() A função surv_summary() retorna um quadro de dados com as seguintes colunas:\ntime: o tempo em que a curva tem um passo. n.risk: o número de sujeitos em risco em t. n.evento: o número de eventos que ocorrem no tempo t. n.censor: número de eventos censurados. surv: estimativa da probabilidade de sobrevivência. std.err: erro padrão de sobrevivência. superior: extremidade superior do intervalo de confiança inferior: extremidade inferior do intervalo de confiança estratos: indica a estratificação da estimativa de curvas. Os níveis de estratos (um fator) são os rótulos das curvas (se houver). Log-rank Além da análise visual das estimativas é importante comparar as curvas de sobrevivência com testes de hipóteses para obter-se significância estatística para nossas afirmações.\nO teste log rank é um teste não paramétrico, que não faz suposições sobre as distribuições de sobrevivência. Essencialmente, o teste log rank compara o número observado de eventos em cada grupo com o que seria esperado se a hipótese nula fosse verdadeira. Considere então \\(H_0: S_1(t)=S_2(t)\\) para todo \\(t\\) no período de acompanhamento (ou seja, se as curvas de sobrevivência fossem idênticas). A estatística utilizada no teste é um \\(T\\) com distribuição aproximadamente \\(\\chi^2\\) com 1 grau de liberdade.\nO objeto criado abaixo guarda o valor p para o teste de log-rank de cada em cada um dos modelos:\nresultado_log_rank \u0026lt;- c(geral = \u0026quot;\u0026quot;, player_assists_d=round(1-pchisq(survdiff(surv~player_assists_d,data = pubg_tpp1)$chisq,1),5), drive=round(1-pchisq(survdiff(surv~drive,data=pubg_tpp1)$chisq,1),5), player_kills_d=round(1-pchisq(survdiff(surv~player_kills_d,data=pubg_tpp1)$chisq,1),5) ) Os gráficos gerados a partir dos modelos ajustados acima bem como o resultado dos testes de log-rank são exibidos na imagem a seguir:\nsurvplot \u0026lt;- map2(resultado_km, case_when(resultado_log_rank == \u0026#39;0\u0026#39; ~ \u0026quot;log-rank: \\n p \u0026lt; 0,00001\u0026quot;, resultado_log_rank == \u0026quot;\u0026quot; ~ \u0026quot;log-rank não se aplica\u0026quot;, resultado_log_rank != \u0026#39;0\u0026#39; | resultado_log_rank != \u0026#39;\u0026#39; ~ paste0(\u0026quot;log-rank: \\n p =\u0026quot;,as.numeric(resultado_log_rank))), ~ autoplot(.x)+ ggtitle(stringr::str_remove_all(names(.x$strata)[1],\u0026quot;(=no|=yes)\u0026quot;))+ annotate(\u0026quot;label\u0026quot;,y = 0.20, x = 5, label = .y, size = 4, colour = \u0026quot;red\u0026quot;,hjust=0.1)+ scale_fill_manual(values = c(\u0026quot;grey\u0026quot;, \u0026quot;#FCC14B\u0026quot;))+ scale_color_manual(values = c(\u0026quot;grey\u0026quot;, \u0026quot;#FCC14B\u0026quot;))+ theme(legend.position = c(0.85,0.7))+ scale_x_continuous(limits = c(0,30), breaks = seq(0,30,5)) ) grid.arrange(survplot[[1]], survplot[[2]] ,survplot[[3]], survplot[[4]], ncol=2) O eixo horizontal (eixo x) representa o tempo em minutos, e o eixo vertical (eixo y) mostra a probabilidade de sobrevivência ou a proporção de jogadores que sobrevivem. As linhas representam curvas de sobrevivência dos dois grupos.\nUma queda vertical nas curvas indica um evento. No tempo zero, a probabilidade de sobrevivência é de 1,0 (ou 100% dos jogadores vivos).\nInterpretação: Pelo gráfico, aparentemente não existe diferença no tempo de sobrevivência com estratificação dos dados de acordo com quem deu assistência ou não, já para o teste que compara igualdade de funções de sobrevivência das demais variáveis, existem evidencias estatísticas para rejeitar a hipótese de que não há diferença na sobrevida entre os dois grupos\nFunção de risco (hazard) ou taxa de falha Função de risco (hazard) ou taxa de falha é o risco “instantâneo” denotada por \\(\\lambda(t)\\) é uma taxa, não uma probabilidade e pode assumir qualquer valor real maior que zero.\nNo exemplo representa a taxa de incidência ou risco acumulado para um indivíduo morrer até o momento \\(t\\), dado que sobreviveu até este momento. É muito informativa quando comparada com a função de sobrevivência pois diferentes \\(S(t)\\) podem ter formas semelhantes, enquanto que respectivas \\(\\lambda(t)\\) podem diferir drasticamente.\nsurvplot \u0026lt;- map(resultado_km , ~ ggsurvplot(.x, conf.int = TRUE, palette = c(\u0026quot;grey\u0026quot;, \u0026quot;#FCC14B\u0026quot;), risk.table = F,break.time.by = 5, fun = \u0026quot;cumhaz\u0026quot;,title = stringr::str_remove_all(names(.x$strata)[1],\u0026quot;(=no|=yes)\u0026quot;)) ) arrange_ggsurvplots(survplot, print = TRUE, ncol = 2, nrow = 2) O risco cumulativo \\(H( t)\\) pode ser interpretado como a força cumulativa da mortalidade. Em outras palavras, corresponde ao número de eventos que seriam esperados para cada indivíduo pelo tempo t se o evento fosse um processo repetitivo.\nModelo de cox É caracterizado pela presença dos coeficientes \\(\\beta\\)s que medem os efeitos (semelhantes à análise de regressão logística múltipla e linear múltipla) das variáveis explicativas sobre a função de risco. Em um modelo de regressão de riscos proporcionais de Cox, a medida do efeito é a taxa de risco, que é o risco de falha, dado que o participante sobreviveu até um tempo específico.\nAlgumas das suposições para o correto uso do modelo de regressão de riscos proporcionais de Co incluem:\nindependência dos tempos de sobrevivência entre indivíduos distintos na amostra, relação multiplicativa entre os preditores e o risco, uma taxa de risco constante ao longo do tempo. O modelo de riscos proporcionais de Cox é chamado de modelo semi-paramétrico , porque não há suposições sobre o formato da função de risco de linha de base. No entanto, existem outras suposições, como observado acima.\nÉ possível utilizar as estatísticas de Wald, da razão de verossimilhança e escore para fazer inferências sobre os parâmetros do modelo\nVeja a seguir a significância dos coeficiente estimado em modelos univariados para cada variável candidata ao modelo:\n# Modelos univariados covariates \u0026lt;- c(\u0026quot;player_kills\u0026quot;,\u0026quot;player_dist_ride\u0026quot;,\u0026quot;player_performance\u0026quot;, \u0026quot;player_dist_walk\u0026quot;,\u0026quot;player_dmg\u0026quot;, \u0026quot;player_dist\u0026quot;, \u0026quot;player_assists_d\u0026quot;,\u0026quot;drive\u0026quot;, \u0026quot;player_kills_d\u0026quot;) univ_formulas \u0026lt;- map(covariates,~ as.formula(paste(\u0026#39;Surv(player_survive_time) ~\u0026#39;, .x))) univ_models \u0026lt;- map( univ_formulas, ~coxph(.x, data = pubg_tpp1)) # estrair resultados map2_df(univ_models, covariates, function(x,y){ x = summary(x) p.value = signif(x$wald[\u0026quot;pvalue\u0026quot;], digits=2) wald.test = signif(x$wald[\u0026quot;test\u0026quot;], digits=2) beta = signif(x$coef[1], digits=2);#coeficient beta HR = signif(x$coef[2], digits=2);#exp(beta) HR.confint.lower = signif(x$conf.int[,\u0026quot;lower .95\u0026quot;], 2) HR.confint.upper = signif(x$conf.int[,\u0026quot;upper .95\u0026quot;],2) HR = paste0(HR, \u0026quot; (\u0026quot;, HR.confint.lower, \u0026quot;-\u0026quot;, HR.confint.upper, \u0026quot;)\u0026quot;) res = tibble(y,beta, HR, wald.test, p.value) colnames(res) = c(\u0026quot;covariates\u0026quot;,\u0026quot;beta\u0026quot;, \u0026quot;HR (95% CI for HR)\u0026quot;, \u0026quot;wald.test\u0026quot;, \u0026quot;p.value\u0026quot;) res }) %\u0026gt;% kable2(linhas = 7) Modelo de Cox usando uma variável categórica retorna uma razão de risco, que, acima de 1 indica uma covariável que está positivamente associada à probabilidade do evento e, portanto, negativamente associada ao tempo de sobrevida. O oposto vale para HR menor que um e HR = 1 indica que a covariável não tem efeito.\nfinal_model \u0026lt;- coxph(Surv(player_survive_time) ~ player_performance+player_dist+drive, data = pubg_tpp1,x=T,method=\u0026quot;breslow\u0026quot;) summary(final_model) ## Call: ## coxph(formula = Surv(player_survive_time) ~ player_performance + ## player_dist + drive, data = pubg_tpp1, x = T, method = \u0026quot;breslow\u0026quot;) ## ## n= 200, number of events= 200 ## ## coef exp(coef) se(coef) z Pr(\u0026gt;|z|) ## player_performance -0.7469 0.4738 0.1787 -4.179 2.92e-05 *** ## player_dist -1.7599 0.1721 0.1150 -15.307 \u0026lt; 2e-16 *** ## driveyes 0.8832 2.4186 0.2091 4.225 2.39e-05 *** ## --- ## Signif. codes: 0 \u0026#39;***\u0026#39; 0.001 \u0026#39;**\u0026#39; 0.01 \u0026#39;*\u0026#39; 0.05 \u0026#39;.\u0026#39; 0.1 \u0026#39; \u0026#39; 1 ## ## exp(coef) exp(-coef) lower .95 upper .95 ## player_performance 0.4738 2.1105 0.3338 0.6726 ## player_dist 0.1721 5.8117 0.1374 0.2156 ## driveyes 2.4186 0.4135 1.6055 3.6434 ## ## Concordance= 0.883 (se = 0.008 ) ## Likelihood ratio test= 362.7 on 3 df, p=\u0026lt;2e-16 ## Wald test = 274 on 3 df, p=\u0026lt;2e-16 ## Score (logrank) test = 407.8 on 3 df, p=\u0026lt;2e-16 No modelo ajustado note-se que existe uma associação negativa entre player_performance e mortalidade e entre player_dist e mortalidade (ou seja, o risco de morte diminui para jogadores que percorrem maiores distâncias e possuem melhor performance).\nAs estimativas dos parâmetros representam o aumento no log esperado do risco relativo para cada aumento de uma unidade no preditor, mantendo os outros preditores constantes.\nPara interpretabilidade, calcularemos as taxas de risco exponenciando das estimativas dos parâmetros. Para a player_performance, \\(exp(-0.7469196)= 0.4738239\\). Isso implica que diminui para \\(47.38\\) do valor original do risco esperado em relação a um aumento de uma unidade na performance, mantendo as demais variáveis constantes. A interpretação de player_dist em escala logarítimica é feita de maneira semelhante.`\nJá para os jogadores onde drive = 1 (que dirigiram durante a partida) existe uma relação positiva, como \\(exp(0.8831835)= 2.4185871\\). O risco esperado corresponde à \\(2.4185871\\) do valor original nos que dirigiram em comparação aos que não dirigiram, mantendo as demais variáveis constantes.\nmap2_df(1:3,final_model$coefficients %\u0026gt;% names(),~ tibble( variable = .y, beta = signif(summary(final_model)$coef[.x,1], digits=2), #coeficient beta HR = signif(summary(final_model)$coef[.x,2], digits=2), #exp(beta) HR.confint.lower = signif(summary(final_model)$conf.int[.x,\u0026quot;lower .95\u0026quot;], 2), HR.confint.upper = signif(summary(final_model)$conf.int[.x,\u0026quot;upper .95\u0026quot;],2)) %\u0026gt;% mutate(HR= paste0(HR, \u0026quot; (\u0026quot;, HR.confint.lower, \u0026quot;-\u0026quot;, HR.confint.upper, \u0026quot;)\u0026quot;) ) ) %\u0026gt;% kable2() Em suma:\nHR = 1: sem efeito HR \u0026lt;1: Redução do risco HR\u0026gt; 1: aumento do risco Resíduos de Martingal e Deviance Como foi visto, o modelo de regressão de riscos proporcionais de Cox faz diversas suposições que precisam ser conferidas após o ajuste do modelo para chegar a qualidade de seus resultados pois um modelo mais ajustado pode trazer resultados enganosos e que não façam sentido algum\nGráficos dos resíduos Martingal ou deviance contra os tempos fornecem uma forma de verificar a adequação do modelo ajustado, bem como ajudar na detecção de observações atípicas.\nDeviance\nEsses resíduos, que são uma tentativa de tornar os resíduos Martingal mais simétricos em torno do zero, facilitam, em geral, a detecção de pontos atípicos (outliers). Se o modelo for apropriado, esses resíduos devem apresentar um comportamento aleatório em torno de zero.\nMartingal\nEsses resíduos são vistos como uma estimativa do numero de falhas em excesso observada nos dados mas não predito pelo modelo. Os mesmos são usados, em geral, para examinar a melhor forma funcional (linear, quadrática, etc.) para uma dada covariavel em um modelo de regressão assumido para os dados do estudo.\nres \u0026lt;- tibble(residuo_deviance = resid(final_model,type=\u0026quot;deviance\u0026quot;) , residuo_martingal = resid(final_model,type=\u0026quot;martingal\u0026quot;), linear_predictors = final_model$linear.predictors) # Graficos: grid.arrange( ggplot(res, aes(x=linear_predictors, y=residuo_martingal))+ geom_point()+geom_hline(yintercept=0, color=\u0026#39;coral\u0026#39;)+ylab(\u0026quot;Resíduos Martingual\u0026quot;), ggplot(res, aes(x=linear_predictors, y=residuo_deviance))+ geom_point()+geom_hline(yintercept=0, color=\u0026#39;coral\u0026#39;)+ylab(\u0026quot;Deviance\u0026quot;), ncol=2 ) Interpretação:\nMartingal: Parecido com deviance mais acentuado; Deviance: Modelo não eh tao ruim assim, se fosse um modelo linear talvez deveríamos tomar cuidado. Residuos de Schoenfeld Em princípio, os resíduos de Schoenfeld são independentes do tempo. Um gráfico que mostra um padrão não aleatório contra o tempo é evidência de violação da suposição de hipótese.\nPara testar a suposição de riscos proporcionais:\nfinal_model %\u0026gt;% cox.zph %\u0026gt;% ggcoxzph A partir da inspeção gráfica, não há padrão com o tempo. A suposição de riscos proporcionais parece ser suportada pelas covariáveis\nConsiderações finais Como era de se esperar, o risco de ser abatido diminui para jogadores que possuem melhor performance e também para os jogadores que percorrem maiores distâncias (o que mostra que ficar parado no jogo em uma zona pode não ser a melhor ideia, já é quanto mais se movimenta maior a quantidade de itens que podem ser coletados).\nInteressante notar que a curva de sobrevivência para os jogadores que dirigiram apresenta resultado oposto ao risco esperado nos que dirigiram, isso ocorre pois esses dois modelos calculam medidas diferentes.\nPerguntas frequentes O que a curva de Kaplan-Meier mostra exatamente? Mostra a probabilidade estimada de \"sobreviver\" (não sofrer o evento) além de cada instante de tempo, sem exigir suposições sobre a forma da distribuição. No caso do PUBG, é a proporção de jogadores ainda vivos a cada minuto de partida.\nQual a diferença entre a curva de sobrevivência e a função de risco (hazard)? A curva de sobrevivência mostra a probabilidade acumulada de não sofrer o evento até um tempo t. A função de risco mostra a taxa instantânea de o evento ocorrer naquele momento, dado que o indivíduo sobreviveu até ali. Duas curvas de sobrevivência parecidas podem ter funções de risco bem diferentes.\nPor que usar o modelo de Cox em vez de uma regressão logística comum? Porque o modelo de Cox incorpora diretamente o tempo até o evento, não apenas se o evento ocorreu ou não. Isso permite lidar com observações censuradas (quando o desfecho não foi observado até o fim do período) e estimar como cada variável afeta a taxa de risco ao longo do tempo, não só a chance final.\nReferências Carvalho,M.A., Andreozzi,V.L., Codec¸o,C.T., Campos,D.P., Barbosa,M.T.S., Shimakura,S.E., Análise de sobrevivência: Teoria e aplicações em saúde, Segunda Edição, Editora FIOCRUZ, Rio de Janeiro, 2011. Colosimo,E.A., Giolo,S.R., Análise de sobrevivência aplicada, ABE-Projeto Fisher, São Paulo, 2010 Lewis,E.E., Introduction to reliability engineering, John Wiley, New York, 1987 http://sphweb.bumc.bu.edu/otlt/MPH-Modules/BS/BS704_Survival/BS704_Survival6.html http://www.sthda.com/english/wiki/cox-model-assumptions Cuiriosidades / Leituras futuras:\nEvaluating Random Forests for Survival Analysis Using Prediction Error Curves: https://www.jstatsoft.org/article/view/v050i11 randomForestSRC: https://cran.r-project.org/web/packages/randomForestSRC/index.html WTTE-RNN - Less hacky churn prediction: https://ragulpr.github.io/2016/12/22/WTTE-RNN-Hackless-churn-modeling/ Weibull Time To Event Recurrent Neural Network: https://github.com/ragulpr/wtte-rnn/ Neural Networks as Statistical Methods in Survival Analysis: https://www.stats.ox.ac.uk/pub/bdr/NNSM.pdf Continuous and Discrete Time Survival Analysis: Neural Network Approaches: http://pcwww.liv.ac.uk/~afgt/eleuteri_lyon07.pdf Cox Proportional Hazards Model - h2O Documentation: http://s3.amazonaws.com/h2o-release/h2o/master/1579/docs-website/datascience/coxph.html Introduction to H2OCoxPH: https://www.slideshare.net/0xdata/introduction-to-h2ocoxph ","date":"28 de novembro de 2018","externalUrl":null,"permalink":"/post/2018-11-28-pubg-sobrevivencia-kaggle/","section":"Posts","summary":" Análise de sobrevivência e PUBG Análise de sobrevivência é um termo que se refere a situações médicas e é caracterizada pela sua variável resposta, que pode ser apresentada de três formas: probabilidade de sobrevivência, taxa de incidêcia e taxa de incidência acumulada.\nNa engenharia este termo também é conhecido como confiabilidade, no entanto, condições parecidas podem ocorrer em (inusitadas) outras áreas.\nPUBG é um jogo online multiplayer de batalha em que 100 jogadores são lançados em uma ilha e tem como objetivo principal sobreviver, a área de jogo diminui progressivamente, confinando os sobreviventes a um espaço cada vez menor e forçando encontros e o vencedor é o último jogador (ou time) a permanecer vivo.\n","title":"Análise de sobrevivência com dados do PUBG no Kaggle","type":"post"},{"content":"","date":"28 de novembro de 2018","externalUrl":null,"permalink":"/tags/analise-de-sobrevivencia/","section":"Tags","summary":"","title":"Analise-De-Sobrevivencia","type":"tags"},{"content":"","date":"28 de novembro de 2018","externalUrl":null,"permalink":"/tags/gamificacao/","section":"Tags","summary":"","title":"Gamificacao","type":"tags"},{"content":"","date":"28 de novembro de 2018","externalUrl":null,"permalink":"/tags/modelagem-estatistica/","section":"Tags","summary":"","title":"Modelagem-Estatistica","type":"tags"},{"content":"","date":"28 de novembro de 2018","externalUrl":null,"permalink":"/tags/survivor/","section":"Tags","summary":"","title":"Survivor","type":"tags"},{"content":"Link do repositório no github: https://github.com/gomesfellipe/app_acoes\nAplicativo para visualizar acoes com os pacotes highcharter e quantmod\nDemonstração: # Fonte de dados # Os simbolos foram coletados com a função stockSymbols() e também foram acrescentadas outros simbolos manualmente, são eles:\nBTC-USD ETH-USD LTC-USD XRP-USD ADA-USD CIEL3F.SA ITSA4.SA PETR4.SA BBDC4F.SA PCAR4F.SA ABEV3.SA BVMF3.SA Próximos passos # Conseguir de forma automática os simbolos de todas as ações IBOVESPA\n","date":"12 de novembro de 2018","externalUrl":null,"permalink":"/projects/app_acoes/","section":"Projetos","summary":"Link do repositório no github: https://github.com/gomesfellipe/app_acoes\nAplicativo para visualizar acoes com os pacotes highcharter e quantmod\nDemonstração: # Fonte de dados # Os simbolos foram coletados com a função stockSymbols() e também foram acrescentadas outros simbolos manualmente, são eles:\nBTC-USD ETH-USD LTC-USD XRP-USD ADA-USD CIEL3F.SA ITSA4.SA PETR4.SA BBDC4F.SA PCAR4F.SA ABEV3.SA BVMF3.SA Próximos passos # Conseguir de forma automática os simbolos de todas as ações IBOVESPA\n","title":"App ações (simples)","type":"projects"},{"content":"","date":"27 de outubro de 2018","externalUrl":null,"permalink":"/tags/google-cloud/","section":"Tags","summary":"","title":"Google-Cloud","type":"tags"},{"content":"","date":"27 de outubro de 2018","externalUrl":null,"permalink":"/tags/rstudio-server/","section":"Tags","summary":"","title":"Rstudio-Server","type":"tags"},{"content":"","date":"27 de outubro de 2018","externalUrl":null,"permalink":"/tags/series-temporais/","section":"Tags","summary":"","title":"Series-Temporais","type":"tags"},{"content":"","date":"27 de outubro de 2018","externalUrl":null,"permalink":"/tags/servidor/","section":"Tags","summary":"","title":"Servidor","type":"tags"},{"content":" ⚠️ Nota de atualização (2026): Este post usa Ubuntu 16.04 LTS (EOL desde 2021), RStudio Server (renomeado para Posit Workbench) e Shiny Server na instância f1-micro do Google Cloud. Os passos gerais ainda funcionam, mas o Ubuntu mínimo recomendado hoje é o 22.04 LTS e os pacotes de instalação do RStudio/Posit mudaram de URL. Para instâncias novas, consulte a documentação atual do Posit Workbench.\nObjetivo do post Uma das várias maneiras de se implementar o RStudio Server e o Shiny Server é através de serviços de nuvem que fornecem máquinas virtuais. Empresas gigantes no mercado como Amazon Web Services (AWS), Microsoft, Google, IBM, Oracle etc têm investido pesado nestes serviços e a escolha de qual cloud utilizar deve ser feita de acordo com a necessidade do usuário pois cada uma delas oferecem diferentes preços com diferentes custos/benefícios.\nNo final deste post teremos além do nosso próprio RStudio Server, esse app no Shiny Server que exibe em um gráfico das cotações encontradas via função função quantmod::stockSymbols() com os pacotes highcharter e quantmod:\nNota: Algum conhecimento em Linux e Git pode ser útil, particularmente ainda tenho muito a aprender sobre ambos e devem existir outras maneiras mais eficientes de se realizar estas tarefas. Essa é uma forma relativamente simples e ao final do post deixarei os links que utilizei como referência para escrever este post.\nNota², segundo o desenvolvedor do pacote highcharter: “Highcharts (www.highcharts.com) é um produto de software da Highsoft que não é livre para uso comercial e governamental”.\nTL;DR\nO post ensina a hospedar RStudio Server e Shiny Server em uma máquina virtual Ubuntu 16.04 na nuvem do Google. Usa o Google Cloud (com o período de teste grátis de $300) e a instância f1-micro, que custa cerca de $0,006 por hora. Ao final, o app de exemplo com cotações de ações, feito com highcharter e quantmod, fica disponível publicamente no Shiny Server. Gloogle cloud A serviço que escolhi para este exemplo foi o Google Cloud, que oferece um período de um ano de Teste Grátis com $300 para utilizar nos serviços dentre outras opções, mas isso não quer dizer que seja a melhor de todas, sinta-se a vontade para utilizar os mesmos passos apresentados aqui nos demais serviços, entendendo, claro, suas peculiaridades.\nDentre algumas vantagens sobre o uso de nuvem, temos:\nMaior produtividade, pois possibilita rápido acesso à sua área de trabalho; Permite o desenvolvedor trabalhar de qualquer lugar com acesso à internet; Permite colaboração rápida, pois os membros da equipe podem contribuir e acessar projetos ao mesmo tempo em que os dados são armazenados na nuvem em vez de em seus computadores Protegido pelos principais especialistas segurança do Google; Controle e flexibilidade, o desenvolvedor tem controle sobre a tecnologia que deseja usar, sobre os dados e caso decida não usar mais o serviço, é possível retirar seus dados da nuvem do Google. Compute Engine Compute Engine é um dos produtos oferecidos pelo Google. Também conhecido como infraestrutura como serviço (IaaS), pode ser usada para executar altas cargas de trabalho em larga escala em máquinas virtuais, no nosso caso este produto que possibilita o uso das máquinas virtuais.\nIniciar uma instância na Google Cloud Platform Primeiramente, acesse https://cloud.google.com/ e se inscreva no recurso de nuvem, após isso acesse https://console.cloud.google.com e percorra o caminho:\nMenu de navegação → Compute Engine → Instâncias de VMs\nNesta página existe o \"Botão Criar instância no Google Cloud Console\", clique nele para iniciar a configuração da VM. Na página que abrir será solicitado a dar um nome a sua VM (pode ser qualquer nome que te agrade). O Google tem data centers em quase todo o mundo e para este caso selecionei a Região us-east1 (Carolina do Sul) e a Zona deixei o default us-east1-b.“saiba mais” do Google.\nDependendo de quão poderoso o servidor precisa ser é possível selecionar a capacidade da RAM e do disco rígido na seção Tipo de Máquina, como este é um exemplo para prova de conceito selecionei a opção micro(1 vCPU compartilhado) - 0.6 GB de memória, f1-micro pois custa cerca de $ 0,006 por hora e as “primeiras 744 horas para uso da instância de tipo f1-micro são gratuitas”, segundo o Google. No Disco de inicialização selecionei a Imagen do SO Ubuntu 16.04 LTS que tenho um pouco mais de familiaridade e não mexi nas demais configurações dessa seção, mas antes de finalizar, selecione a opção Permitir tráfego HTTP na opção de Firewall e clique no botão criar.\nSegundo o guia Acessando o RStudio Server Open-Source e o Guia do Administrador - Shiny Server Open Source v0.4.1o RStudio Server e o Shiny Server serão escutados nas portas 8787 e 3838 respectivamente, portanto, antes de começar a usar a VM é necessário Configurando regras de firewall para permitir acesso através destas portas.\nNavegue até a seção Rede VPC e selecione a opção Regras de firewall. Clique no botão \"Criar regra de firewall no Google Cloud\". No formulário que abrir dê um nome e uma descrição à regra do firewall (‘rstudio’ está bom), deixe os botões de opção Direção de tráfego e Ação ao corresponder como padrão (Entrada e Permitir). Para a opção Destinos, escolhi Conta de serviço especificado, sendo a Conta de serviço de destino Compute Engine default service account. Se você quiser filtrar os IPs que podem acessar o aplicativo, insira-o no campo Intervalos de IP de origem, como estamos sob uma prova de conceito, inseri a rota quad-zero: 0.0.0.0/0, o que permite acesso de todos os IPs em todas as portas nessa máquina. Na opção Protocolos e Portos selecione o botão de opção Protocolos e portas específicas e no campo digite o tcp: 8787. Por fim, clique no botão criar.\nFaça o procedimento exatamente da mesma maneira, mas com um novo nome (‘shiny’ está bom) e digite ‘tcp: 3838’ em vez de ‘tcp: 8787’. Clique em criar e note que agora abrimos duas portas para usar no aplicativo.\nNota: Os passos para iniciar uma instância na Cloud do Google foram inspirados no seguinte post: https://datarunsdeep.com.au/blog/building-r-shiny-app-google-cloud-display-bigquery-data\nInicie a máquina virtual Ótimo! Agora a VM já deve estar pronta para uso, o mesmo tipo de infraestrutura que já usei para rodar coletas de séries temporais como em Séries temporais com Google Trends e R, e o jeito mais simples de utilizá-la é clicando no botão \"SSH\" na página de Instâncias de VMs e aguardar a máquina iniciar\nVamos às configurações!\nObter senha para super usuário O primeiro passo será obter a senha para usuário root\nsudo passwd Após determinar a senha, alterne para este usuário e conceda a permissão de super usuário para evitar trabalhar como root:\nsu root passwd gomes_fellipe1 gpasswd -a gomes_fellipe1 sudo su gomes_fellipe1 Agora meu usuário tem permissão de super usuário e uma senha para utilizar para acessar o RStudio Server.\nExibir sua VM em um navegador Se você utilizar o comando\ncurl ipinfo.io/ip o endereço IP externo será exibido no console, porém se digitar este caminho no browser ainda não será possível acessar sua máquina. Para isso, instale o Nginx (que é um servidor web leve) com os comandos:\nsudo apt-get update sudo apt-get -y install nginx Agora se você digitar o endereço IP externo da sua máquina no browser será possível ver a tela de saudação do nginx!\nCriar um arquivo swap Seguindo a recomendação do post Implantando um servidor Shiny Server e RStudio seguro em uma máquina virtual gratuita do Google Cloud e as instruções do link https://digitizor.com/create-swap-file-ubuntu-linux/, podemos criar um arquivo swap pois a instância f1-micro não tem RAM suficiente e pode ser que alguns pacotes não possam ser instalados por falta de memória.\ncd / sudo dd if=/dev/zero of=swapfile bs=1M count=3000 sudo mkswap swapfile sudo swapon swapfile sudo nano etc/fstab # Adicione a linha a seguir no arquivo que abrir /swapfile none swap sw 0 0 cat /proc/meminfo Instalar o R Para instalar o R apenas segui os passos apresentados em https://deanattali.com/2015/05/09/setup-rstudio-shiny-server-digital-ocean/ com os códigos:\nsudo sh -c \u0026#39;echo \u0026quot;deb http://cran.rstudio.com/bin/linux/ubuntu xenial/\u0026quot; \u0026gt;\u0026gt; /etc/apt/sources.list\u0026#39; gpg --keyserver keyserver.ubuntu.com --recv-key E084DAB9 gpg -a --export E084DAB9 | sudo apt-key add - sudo apt-get update sudo apt-get -y install r-base Agora o R está pronto para uso, basta escrever R no console para iniciá-lo.\nDependências e pacotes Antes de instalar outros pacotes podemos iniciar instalando o devtools pois esse pacote permite instalar a versão do desenvolvedores de alguns pacotes do R que estão disponíveis no GitHub. Para instalar as dependências do devtools:\nsudo apt-get -y install libcurl4-gnutls-dev libxml2-dev libssl-dev Tudo certo, agora já é possível instalar pacotes tanto do CRAN quando do GitHub. Além do devtools instalaremos mais dois pacotes que serão utilizados pelo aplicativo exemplo deste post:\nsudo su - -c \u0026quot;R -e \\\u0026quot;install.packages(c(\u0026#39;devtools\u0026#39;,\u0026#39;rmarkdown\u0026#39;, \u0026#39;quantmod\u0026#39;), repos=\u0026#39;http://cran.rstudio.com/\u0026#39;)\\\u0026quot;\u0026quot; sudo su - -c \u0026quot;R -e \\\u0026quot;devtools::install_github(\u0026quot;jbkunst/highcharter\u0026quot;)\\\u0026quot;\u0026quot; Importante: Note que ao instalar os pacotes do R no terminal os pacotes são instalados como usuário root, o que significa que os pacotes serão instalados em uma biblioteca global e estarão disponíveis para todos os usuários da máquina.\nInstalar o RStudio Server Neste ponto já temos uma máquina virtual como R instalado e estamos preparados para dar início ao nosso RStudio Server! Para instalar entre na página de download do RStudio em: https://www.rstudio.com/products/rstudio/download-server/ e siga os passos de instalação. No meu caso bastou rodar:\nsudo apt-get install gdebi-core wget https://download2.rstudio.org/rstudio-server-1.1.456-amd64.deb sudo gdebi rstudio-server-1.1.456-amd64.deb Pronto, agora já possuímos nosso próprio RStudio Server na nuvem! Para acessá-lo basta utilizar a porta 8787 através de seu IP externo (que pode ser obtido com o comando: curl ipinfo.io/ip, como mencionado anteriormente). Portanto, acesse algo como: http://35.237.234.123:8787 (este link direcionará para a máquina virtual que criei no exemplo deste post) e você será direcionado para uma tela de login:\nÉ possível fazer o login no RStudio Server com qualquer usuário que esteja cadastrado em sua máquina virtual, no meu caso eu faço o login com o nome de usuário gomes_fellipe1 e a senha que defini para meu usuário ao criar a máquina.\nÉ possível criar um novo usuário para acessar o RStudio Server via terminal da máquina virtual com:\nadduser novo_usuario Caso seu objetivo seja apenas o de ter seu próprio RStudio Server Parabéns! Já está disponível e pronto para uso! A seguir trataremos de como instalar e como efetuar algumas configurações básicas de um Shiny Server, mesmo que você não seja desenvolvedor desse tipo de app sugiro que instale o servidor mesmo assim pois ele também pode ser usado para hospedar seus documentos interativos como arquivos Rmarkdown!\nInstalar o Shiny Server Aplicativos Shiny são incríveis e sua aplicabilidade é tamanha que poderia dedicar uma série de posts exclusivamente para falar sobre essa ferramenta. Dedico uma enorme parte do meu tempo de trabalho atualmente no desenvolvimento de aplicativos Shiny e ao terminar todas as etapas de um “típico projeto de ciencia de dados” a etapa da entrega dos resultados pode ser bastante crítica e um aplicativo Shiny é capaz de trazer interatividade às suas análises.\nExistem diversas opções de entrega, entre elas:\nFazer um rápido deploy no http://www.shinyapps.io/; Hospedar no now, como apresentado na página do curso-r em: https://www.curso-r.com/blog/2018-03-05-shiny-now/; Dockerizar o app com a imagem https://hub.docker.com/u/rocker/ e disponibilizá-lo na rede interna de sua empresa; Criar um executável via R e Inno Setup (um instalador para programas do Windows), como ilustrado em: https://www.ficonsulting.com/filabs/RInno; Dentre tantas outras… No caso deste post, estamos criando nosso próprio servidor e assim teremos controle tanto do desempenho da máquina hospedada quanto do uso do Shiny Server propriamente dito. Esse mesmo servidor pode hospedar, por exemplo, aplicativos com mapas interativos como os que fizemos em Carnaval e mapas interativos com R.\nConsulte a página de download do Shiny Server em: https://www.rstudio.com/products/shiny/download-server/ para saber qual a versão mais recente para instalar no seu computador (note que será necessário instalar o pacote do shiny como mencionado anteriormente), no meu caso foi:\nsudo su - -c \u0026quot;R -e \\\u0026quot;install.packages(\u0026#39;shiny\u0026#39;, repos=\u0026#39;https://cran.rstudio.com/\u0026#39;)\\\u0026quot;\u0026quot; sudo apt-get install gdebi-core wget https://download3.rstudio.org/ubuntu-14.04/x86_64/shiny-server-1.5.9.923-amd64.deb sudo gdebi shiny-server-1.5.9.923-amd64.deb O Shiny Server está agora instalado e em execução. Supondo que correu tudo bem você já poderá acessar a página inicial padrão do Shiny Server, que inclui algumas instruções e dois aplicativos Shiny, veja em (na minha máquina de exemplo): http://35.237.234.123:3838 (Note que eu não configurei um IP externo fixo neste app por se tratar de uma prova de conceito, como ele pode alterar para um IP aleatório quando eu reiniciar a máquina então fiz um backup no http://www.shinyapps.io/ no endereço: https://gomesfellipe.shinyapps.io/app_acoes/ para manter este DEMO no caso dessa máquina específica não estar mais no ar futuramente)\nAlguns comandos úteis para configurar o status do servidor:\nsudo systemctl start shiny-server sudo systemctl stop shiny-server sudo systemctl restart shiny-server Importante:\nO arquivo de configuração do servidor está em: /etc/shiny-server/shiny-server.conf; A página inicial do Shiny Server estará em: /srv/shiny-server/index.html (normalmente removemos esta página ou incluir um outro html para customizá-la); Todos aplicativos Shiny com o nome app.R que você colocar em /srv/shiny-server/ serão entendidos pelo servidor como um aplicativo Shiny; Todos aplicativos serão executados como usuário shiny o que implica que qualquer pacote necessário em um aplicativo shiny deverá estar na biblioteca global ou na biblioteca do usuário shiny. Existem diversas formas de lidar com esse aspecto da configuração inicial do servidor então deixarei algumas referências ao final do post para quem tiver a necessidade de maior customização e controle do servidor; Para visualizar os logs durante o desenvolvimento do aplicativo será necessário adicionar as linhas preserve_logs true;e sanitize_errors false; ao arquivo de configuração do servidor (e reiniciar o servidor em seguida) e assim os logs do servidor estarão disponíveis em /var/log/shiny-server.log. Adicionar aplicativos ao Shiny Server via Github Como já foi dito, qualquer aplicativo Shiny colocado na pasta /srv/shiny-server/ será automaticamente exibido como um Shiny app na página principal do servidor. Além da opção de desenvolver um um aplicativo diretamente pelo RStudio Server e salvar nesta pasta podemos clonar algum app hospedado no GitHub ou no BitBucket para esta pasta.\nPrimeiramente vamos instalar o git e realizar as configurações iniciais:\nsudo apt-get -y install git git config --global user.email \u0026quot;you@example.com\u0026quot; git config --global user.name \u0026quot;Your Name\u0026quot; Agora vamos nos deslocar para a pasta srv/shiny-server/ e remover a página index.html pois não estamos mais interessados em ver a página de exemplo do Shiny Server:\ncd /srv/shiny-server sudo rm index.html Em seguida já é possível clonar seu repositório do GitHub ou do BitBucket diretamente para esta pasta (Lembrete: o arquivo que executa o app deve ser nomeado como app.R!), veja:\nsudo git clone https://github.com/gomesfellipe/app_acoes.git O legal de administrar suas aplicações via GitHub ou do BitBucket é que o código hospedado pode ser trabalhado e “commitado” de qualquer outro lugar do mundo e para atualizar no servidor basta utilizar o comando sudo git pull na pasta do app que o diretório local será atualizado com as modificações realizadas no repositório remoto.\nPronto, se utilizar o comando ls já será possível ver a pasta clonada no diretório local:\nAo acessar o app teremos:\nO código para gerar este app é:\nNota¹: O código do app e as dependências podem ser obtidas em: https://github.com/gomesfellipe/app_acoes e para executá-lo diretamente do seu terminal basta utilizar o comando:\nshiny::runGitHub(\u0026quot;gomesfellipe/app_acoes\u0026quot;) Nota²: Caso queira incluir seu aplicativo Shiny em alguma página Web ou relatório é simples, utilizando um pouco de html é só o incluí no seu arquivo RMarkdown utilizando algo parecido com:\n\u0026lt;iframe width=\u0026quot;450\u0026quot; height=\u0026quot;400\u0026quot; scrolling=\u0026quot;no\u0026quot; frameborder=\u0026quot;no\u0026quot; src=\u0026quot;sua_url\u0026quot;\u0026gt; \u0026lt;/iframe\u0026gt; Tudo Pronto? Definitivamente não! Implementamos um app bem básico mas existem intermináveis desafios que não foram abordados nesse rápido post como a instalação do Latex para o Shiny Server, o uso de contêineres Docker, senha para os aplicativos shiny, definir um IP estático, todas as outras dependências que podem ser requisitadas na instalação de pacotes específicos etc.. É aquela história, quanto mais a gente estuda mais coisa aparece para estudar mas esse é justamente o legal de tudo, que nunca fica fácil!\nReferências e sugestões: https://cloud.google.com/getting-started/?hl=pt-br https://support.rstudio.com/hc/en-us/articles/200552306-Getting-Started http://rstudio.github.io/shiny-server/os/0.4.0/ https://deanattali.com/2015/05/09/setup-rstudio-shiny-server-digital-ocean/ https://datarunsdeep.com.au/blog/building-r-shiny-app-google-cloud-display-bigquery-data https://shiny.rstudio.com/gallery/authentication-and-database.html http://www.simoncoulombe.com/2018/05/07/protected_free_shiny/ https://www.brettory.com/2018/02/embedding-a-shiny-app-in-blogdown/ https://www.keycdn.com/support/413-request-entity-too-large https://auth0.com/blog/adding-authentication-to-shiny-server/ https://gist.github.com/jjesusfilho/6a3ec38016f7e120e9a2cf2b49e42962 https://gist.github.com/jjesusfilho/7b7001745cbb8f7b1ad36e7bfe5d43e8 https://curso-r.github.io/auth0/ Perguntas frequentes Qual sistema operacional foi usado na máquina virtual do Google Cloud?\nFoi usada a imagem Ubuntu 16.04 LTS no disco de inicialização da instância, escolhida por familiaridade do autor com essa distribuição.\nQuanto custa manter uma instância f1-micro no Google Cloud?\nA instância f1-micro (1 vCPU compartilhado, 0.6 GB de memória) custa cerca de $0,006 por hora, e as primeiras 744 horas de uso desse tipo são gratuitas, segundo o Google.\nQuais portas precisam ser liberadas no firewall para RStudio Server e Shiny Server?\nÉ necessário criar regras de firewall liberando a porta tcp:8787 para o RStudio Server e a porta tcp:3838 para o Shiny Server.\n","date":"27 de outubro de 2018","externalUrl":null,"permalink":"/post/2018-10-27-server-cloud/","section":"Posts","summary":" ⚠️ Nota de atualização (2026): Este post usa Ubuntu 16.04 LTS (EOL desde 2021), RStudio Server (renomeado para Posit Workbench) e Shiny Server na instância f1-micro do Google Cloud. Os passos gerais ainda funcionam, mas o Ubuntu mínimo recomendado hoje é o 22.04 LTS e os pacotes de instalação do RStudio/Posit mudaram de URL. Para instâncias novas, consulte a documentação atual do Posit Workbench.\nObjetivo do post Uma das várias maneiras de se implementar o RStudio Server e o Shiny Server é através de serviços de nuvem que fornecem máquinas virtuais. Empresas gigantes no mercado como Amazon Web Services (AWS), Microsoft, Google, IBM, Oracle etc têm investido pesado nestes serviços e a escolha de qual cloud utilizar deve ser feita de acordo com a necessidade do usuário pois cada uma delas oferecem diferentes preços com diferentes custos/benefícios.\n","title":"Seu app, RStudio e Shiny Server na nuvem do Google","type":"post"},{"content":"","date":"29 de setembro de 2018","externalUrl":null,"permalink":"/tags/acidentes/","section":"Tags","summary":"","title":"Acidentes","type":"tags"},{"content":" Perguntas Estudar em outra cidade têm suas vantagens e desvantagens, durante toda a graduação atravessei Baía de Guanabara pela Ponte Presidente Costa e Silva, (popularmente conhecida como Ponte Rio–Niterói) assim como todas as pessoas que fazem esse trajeto diariamente e diante de tanta beleza natural com a vista panorâmica da Baía como os espetáculos proporcionados pelo pôr do sol, os pássaros ou a beleza inegável do Pão de Açúcar também é notável a beleza fruto da maior habilidade humana: a criatividade. Temos o cristo, todos aqueles grandes barcos, o Porto do Rio de Janeiro com todas aquelas obras de Engenharia, ou até mesmo a própria Ponte, que por si só já é intrigante.\nEm contrapartida, dentre as desvantagens está a enorme frequência de engarrafamentos, o custo, o tempo gasto no trajeto e ao refletir sobre a velocidade dos carros na travessia da Ponte e a quantidade de acidentes que ocorrem na me deparei com os seguinte questionamentos:\nO número de acidentes na ponte é diário?\nO número de acidentes na ponte têm diminuído?\nA instalação das câmeras de segurança diminuiu o número de acidentes?\nEm janeiro de 2018 anunciava-se no jornal: “radares da Ponte Rio-Niterói começam a multar” e como já faz algum tempo que a ponte é monitorada com câmeras de segurança surge a suspeita se o número de acidentes têm diminuído e na vontade de tirar minhas próprias conclusões recorri ao que há de mais abundante por ai: os dados e com o uso de técnicas simples de Estatística iniciei minha “investigação” para obter possíveis respostas para essas perguntas.\nTL;DR\nOs dados vêm da PRF (Dados Abertos), filtrados para o trecho BR-101, Km 321-334, que corresponde à Ponte Rio-Niterói. O número de acidentes não se mostrou diário nos últimos 10 anos analisados, e o comportamento dos dados sugere uma diminuição ao longo do tempo. Em 2015, ano da notícia sobre o monitoramento por câmeras, houve uma queda expressiva no número de registros de acidentes. Pacotes utilizados nesta análise:\nlibrary(grid) # textGrob() library(dplyr) # Manipulacao dos dados library(purrr) # Programacao Funcional library(stringr) # Manipulacao de strings library(magrittr) # Pipes library(leaflet) # Mapa interativo library(leaflet.extras) # + leaflet library(ggplot2) # graficos elegantes library(lubridate) # manipulacao de data library(data.table) # fred() library(forecast) # tslm() library(ggfortify) # autoplot() library(gridExtra) # + ggplot2 library(zoo) # rollmean library(broom) # tidy() augment() glance() library(knitr) # kable() library(kableExtra) # scroll_box library(formattable) # color_bar() Fonte dos dados Os dados para realizar esta pesquisa foram obtidos no site da Polícia Rodoviária Federal, que disponibiliza uma sessão de Dados Abertos que segundo o site: “não possui restrição de licenças, patentes ou mecanismos de controle, de modo a estarem livremente disponíveis para serem utilizados e redistribuídos à vontade”. Na sessão de Acidentes é possível encontrar os registros de acidentes no formato csv ao longo dos anos.\nDiscussão: Para saber se de fato o número de acidentes na ponte Rio-Niterói ocorre diariamente seria necessário que todos os casos fossem registrados ou elaborar alguma forma de fazer inferência para obter significância estatística para esta resposta baseado na amostra de ocorrências registradas. Ainda é possível que ocorram subnotificações pois pode ser que alguns casos como uma leve batida entre dois carros não tenham sido registrados pela PRF.\nReflexão: Uma sugestão para contornar esse problema de subnotifação (caso de fato exista) poderia ser o desenvolvimento de um algorítimo de Inteligência Artificial baseado em Deep Learning para captar através das imagens das câmeras de segurança a ocorrência dos acidentes, classifica-los e armazenar em uma base de dados de forma automatizada além de notificar às autoridades..\nDada as circunstâncias, vejamos o que os dados disponibilizados pela PRF têm à revelar (o mapa interativo mais adiante usa a mesma técnica de geocodificação com leaflet que mostrei no post sobre blocos de carnaval). Após baixar todos os dados, bastou fazer a leitura com os comandos:\n# Importar / Arrumar / Limpar base \u0026lt;- paste0(\u0026quot;datatran\u0026quot;,2008:2018,\u0026quot;/\u0026quot;,\u0026quot;datatran\u0026quot;,2008:2018,\u0026quot;.csv\u0026quot;) %\u0026gt;% map(~.x %\u0026gt;% fread(sep = \u0026quot;;\u0026quot;,dec=\u0026quot;,\u0026quot;)%\u0026gt;% mutate(km = as.character(km), br = as.character(br)) %\u0026gt;% mutate_if(is.character, ~.x %\u0026gt;% enc2native() %\u0026gt;% abjutils::rm_accent() %\u0026gt;% tolower() %\u0026gt;% str_replace_all(\u0026quot;/\u0026quot;,\u0026quot;-\u0026quot;) %\u0026gt;% str_replace_all(\u0026quot;,\u0026quot;,\u0026quot;\\\\.\u0026quot;) ) %\u0026gt;% mutate(data_inversa = if_else(is.na(dmy(data_inversa)), ymd(data_inversa), dmy(data_inversa)) , km = as.numeric(km), br = as.numeric(br), id = as.character(id), dia_semana = str_remove_all(dia_semana,\u0026quot;-feira\u0026quot;) ) %\u0026gt;% filter(br==101 \u0026amp; km\u0026gt;=321 \u0026amp; km\u0026lt;334) %\u0026gt;% .[str_detect(.$municipio,\u0026quot;(niteroi|rio de janeiro)\u0026quot;),] ) # Salvar base arrumada: saveRDS(base, \u0026#39;base.RDS\u0026#39;) Nota: A única pasta que tinha a base com nome diferente das demais foi no ano de 2016, do qual foi preciso renomear o arquivo datatran2016_atual.csv para datatran2016.csv.\nDiante de tantos dados, foi necessário fazer um filtro para obter apenas os dados da ponte Rio- Niterói.\nSegundo o Google, o “endereço” da ponte é BR-101, Km 321-334, portanto foi aplicado um filtro que levasse em conta essa informação.\nAnálises preliminares Com a base de dados arrumada e salva em no objeto base.RDS fica mais fácil fazer análises rápidas depois de reiniciar o R e a leitura dos dados também será mais veloz.\nbase \u0026lt;- readRDS(\u0026quot;base.RDS\u0026quot;) Primeiramente, um breve resumo dos dados com algumas informações gerais dos últimos 10 anos:\nbase %\u0026gt;% map_df( ~.x %\u0026gt;% select(dia_semana,classificacao_acidente, mortos, feridos, veiculos)) %\u0026gt;% map_if(is.character,as.factor) %\u0026gt;% bind_cols() %\u0026gt;% SmartEDA::ExpCatViz(target=NULL, fname=NULL, margin=2, Page = c(2,2)) ## $`0` Nota-se que o maior número de acidentes ocorre na sexta-feira, praticamente todos os acidentes não tiveram mortos e em 78% dos acidentes não houveram vítimas. A maioria dos acidentes foi colisão entre dois carros.\nOs tipos de acidentes que ocorreram foram:\nbase %\u0026gt;% map_df( ~.x %\u0026gt;% select(causa_acidente, tipo_acidente)) %\u0026gt;% map_if(is.character,as.factor) %\u0026gt;% as_tibble %\u0026gt;% group_by(causa_acidente) %\u0026gt;% dplyr::summarise(n=n()) %\u0026gt;% mutate(n = color_bar(\u0026quot;lightgrey\u0026quot;)(n)) %\u0026gt;% kable(escape = F) %\u0026gt;% kable_styling(\u0026quot;hover\u0026quot;,full_width = F) %\u0026gt;% scroll_box( height = \u0026quot;200px\u0026quot;) causa_acidente n agressao externa 1 animais na pista 4 avarias e-ou desgaste excessivo no pneu 5 condutor dormindo 4 defeito mecanico em veiculo 210 defeito mecanico no veiculo 26 defeito na via 9 desobediencia a sinalizacao 48 desobediencia as normas de transito pelo condutor 9 dormindo 58 falta de atencao 1697 falta de atencao a conducao 146 falta de atencao do pedestre 4 ingestao de alcool 59 ingestao de alcool 5 mal subito 4 nao guardar distancia de seguranca 677 nao guardar distancia de seguranca 39 objeto estatico sobre o leito carrocavel 3 outras 5118 pista escorregadia 5 restricao de visibilidade 2 ultrapassagem indevida 21 velocidade incompativel 62 velocidade incompativel 5 Mapa Ao investigar a base nota-se que apenas os últimos dois anos (2018 e 2017) informam as coordenadas geográficas, portando para criar o mapa com o pacote leaflet foram selecionados apenas os dados referentes ao ano de 2018 e 2017:\nbase[10:11] %\u0026gt;% map_df(~.x %\u0026gt;% select(id, data_inversa, horario, br,km, causa_acidente, tipo_acidente, latitude, longitude) %\u0026gt;% mutate(latitude = as.numeric(latitude), longitude = as.numeric(longitude) ) ) %\u0026gt;% leaflet() %\u0026gt;% addTiles() %\u0026gt;% addMarkers(~longitude, ~latitude, clusterOptions = markerClusterOptions(), label = ~paste0(data_inversa,\u0026quot;-\u0026quot;,horario,\u0026quot;\\n Causa: \u0026quot;,causa_acidente,\u0026quot;\\nTipo: \u0026quot;,tipo_acidente))%\u0026gt;% addResetMapButton()%\u0026gt;% addProviderTiles(providers$OpenStreetMap.Mapnik) Note que existem diversas ocorrências que apresentaram coordenadas geográficas fora dos limites da Ponte o que sugere que a amostra selecionada pode conter informações das redondezas. Estas informações serão avaliadas em conjunto com os dados referentes aos 13km da BR-101 que selecionamos.\nSérie temporal Segundo @Morettin:\nDef.: Uma série temporal é qualquer conjunto de observações ordenadas no tempo\nOs objetivos da análise de séries temporais são, em geral:\nInvestigar o mecanismo gerador da série temporal Fazer previsões de valores futuros da série (podem ser a curto prazo ou a longo prazo) Descrever apenas o comportamento da série, neste caso a construção do gráfico, a verificação da existência de tendências, ciclos e variações sazonais, a construção de histogramas e diagramas de dispersão etc podem ser ferramentas úteis Procurar periodicidade relevante nos dados Etimologicamente (prae e videre), a palavra previsão sugere que se quer ver uma coisa antes que ela exista. Alguns autores preferem a palavra predição, para indicar algo que deverá existir no futuro. Ainda outros utilizam o termo projeção porém nosso objetivo neste post não será ajustar um modelo preditivo e sim um modelo descritivo que possibilite estudar o comportamento da série.\nApós tomar uma intuição de como ocorrem os acidentes de maneira espacial na amostra, para responder a pergunta “O número de acidentes é diário?” precisamos obter a informação temporal dos dados e a melhor forma de visualizar este comportamento inicialmente é com um gráfico.\nNúmero de acidentes por dia nos últimos 10 anos Veja a seguir o número de acidentes, por id, diariamente e duas curvas de médias móveis com k = 30 e com k = 30*6 :\ng1 \u0026lt;- base %\u0026gt;% map_df(~.x%\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente) ) %\u0026gt;% dplyr::group_by(data_inversa)%\u0026gt;% dplyr::summarise(n=n())%\u0026gt;% mutate(rMM=rollmean(n,30, na.pad=TRUE, align=\u0026quot;left\u0026quot;)) %\u0026gt;% mutate(rMY=rollmean(n,30*6, na.pad=TRUE, align=\u0026quot;left\u0026quot;)) %\u0026gt;% tidyr::gather(medida,valor,n:rMY) %\u0026gt;% ggplot(aes(x=data_inversa, y=valor,col=medida)) + geom_line() + scale_colour_manual(name=\u0026quot;Legenda:\u0026quot;,values=c(\u0026quot;black\u0026quot;,\u0026quot;red\u0026quot;,\u0026quot;blue\u0026quot;), labels = c(\u0026#39;Acidentes\u0026#39;,\u0026#39;Médias móveis k=30\u0026#39;, \u0026#39;Médias móveis k=30*6\u0026#39;)) + theme_bw() + labs(y= \u0026#39;Número de acidentes\u0026#39;, x = \u0026#39;Data\u0026#39;, subtitle = \u0026quot;Por dia\u0026quot;, title= \u0026#39;Número de acidentes na Ponte Rio-Niterói\u0026#39;, caption = \u0026quot;Fonte dos dados:\\nhttps://www.prf.gov.br/portal/dados-abertos/acidentes\\nhttps://gomesfellipe.github.io/\u0026quot;,col=\u0026quot;\u0026quot;) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + scale_y_continuous(breaks=seq(0,15,1)) g1 + scale_x_date(date_breaks = \u0026#39;6 months\u0026#39;,limits = as.Date(c(\u0026quot;2008-02-01\u0026quot;,\u0026quot;2018-12-01\u0026quot;)), expand = c(0.01,0.01)) + theme(legend.position = c(0.85,0.7), legend.background = element_rect(fill=alpha(\u0026#39;lightgrey\u0026#39;, 0.2))) Este gráfico esta um pouco carregado com a informação levando em conta o número de acidentes por dia mas mesmo assim já é possível notar algumas informações como:\nExistem diversos dias que não houveram acidentes registrados pela PRF (diversos pontos tocam o eixo x) No ano de 2015 houve uma grotesca diminuição no registros do número de acidentes (o que será que aconteceu?) A primeira pergunta parece ter sido respondida: O número de acidentes não parece ter sido diário nos últimos 10 anos segundo esses dados (e supondo que não houve subnotificação).\nJá a hipótese levantada com a segunda pergunta parece ser verdadeira pois o comportamento dos dados sugerem ter havido a diminuição no número de acidentes.\nVeja a seguir outra rápida análise exploratória para checar como se distribuem os número de acidentes ano longo dos anos e dos meses com alguns box-plots:\nbp1 \u0026lt;- base %\u0026gt;% map_df(~.x%\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente) ) %\u0026gt;% dplyr::group_by(data_inversa)%\u0026gt;% dplyr::summarise(n=n()) %\u0026gt;% tidyr::gather(medida,valor,n) %\u0026gt;% ggplot(aes(x=factor(year(data_inversa)), y=valor,col=medida)) + geom_jitter(col=\u0026quot;darkgrey\u0026quot;,alpha=0.3)+ geom_boxplot(col=\u0026quot;black\u0026quot;,alpha=0.3)+ theme_bw() + labs(y= \u0026#39;Número de acidentes\u0026#39;,x=\u0026quot;\u0026quot;) + theme(axis.text.x = element_text(angle = 30, hjust = 1)) + scale_y_continuous(breaks=seq(0,15,1))+ geom_vline(xintercept = 8.5, linetype=\u0026quot;dotted\u0026quot;, color = \u0026quot;red\u0026quot;, size=1.5) + annotate(\u0026quot;label\u0026quot;,y = 7, x = 8.5, label = \u0026quot;Comportamentos \\n diferentes\u0026quot;, size = 4, colour = \u0026quot;red\u0026quot;,hjust=0.1) bp2 \u0026lt;- base %\u0026gt;% map_df(~.x%\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente)) %\u0026gt;% filter(year(data_inversa)\u0026lt;2016) %\u0026gt;% dplyr::group_by(data_inversa) %\u0026gt;% dplyr::summarise(n=n()) %\u0026gt;% tidyr::gather(medida,valor,n) %\u0026gt;% ggplot(aes(x=factor(months(data_inversa), levels = months(base[[1]]$data_inversa) %\u0026gt;% unique), y=valor,col=medida)) + geom_jitter(col=\u0026quot;darkgrey\u0026quot;,alpha=0.3)+ geom_boxplot(color=\u0026quot;black\u0026quot;,alpha=0.3)+ theme_bw() + labs(y= \u0026#39;Número de acidentes\u0026#39;, title = \u0026#39;Dados de 2008 até 2015\u0026#39;,x=\u0026quot;\u0026quot;, col=\u0026quot;\u0026quot;) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + scale_y_continuous(breaks=seq(0,15,1))+ theme(legend.position = c(0.85,0.7)) bp3 \u0026lt;- base %\u0026gt;% map_df(~.x%\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente) ) %\u0026gt;% filter(year(data_inversa)\u0026gt;=2016) %\u0026gt;% dplyr::group_by(data_inversa) %\u0026gt;% dplyr::summarise(n=n()) %\u0026gt;% tidyr::gather(medida,valor,n) %\u0026gt;% ggplot(aes(x=factor(months(data_inversa), levels = months(base[[1]]$data_inversa) %\u0026gt;% unique), y=valor,col=medida)) + geom_jitter(col=\u0026quot;darkgrey\u0026quot;,alpha=0.3)+ geom_boxplot(color=\u0026quot;black\u0026quot;,alpha=0.3)+ theme_bw() + labs(y= \u0026#39;\u0026#39;, title = \u0026#39;Dados de 2016 até 2018\u0026#39;,x=\u0026quot;\u0026quot;,col=\u0026quot;\u0026quot;) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + scale_y_continuous(breaks=seq(0,15,1))+ theme(legend.position = c(0.85,0.7)) bp2 \u0026lt;- arrangeGrob(bp2,bp3,ncol=2) grid.arrange(bp1,bp2, top = \u0026quot;Boxplots do número de acidentes na Ponte Rio-Niterói\u0026quot;, bottom = textGrob(\u0026quot;Fonte dos dados:\\nhttps://www.prf.gov.br/portal/dados-abertos/acidentes\\nhttps://gomesfellipe.github.io/\u0026quot;, gp = gpar(fontface = 3, fontsize = 9), hjust = 1,x = 1 )) É possível notar que antes de 2016 todos aos boxplots apresentaram medianas parecidas enquanto que após o ano de 2016 parece haver mais acidentes apenas nos primeiros meses do ano.\nPara responder a última pergunta vamos analisar com mais detalhes a série para entender melhor seu comportamento.\nNúmero de acidentes por dia nos últimos 10 anos agrupados por ano Veja a mesma informação do gráfico do número de acidentes na Ponte Rio-Niterói por dia, porém separado para cada ano:\ng1 + facet_wrap( ~ year(data_inversa), scales = \u0026quot;free_x\u0026quot;) + ggtitle(\u0026quot;Número de acidentes na Ponte Rio-Niterói de acordo com o ano, por dia\u0026quot;) + scale_x_date(date_breaks = \u0026#39;1 month\u0026#39;) + theme(legend.position = c(0.85, 0.1)) Agora ficou evidente que a partir do ano de 2015 o número de acidentes na Ponte Rio-Niterói foi reduzido e manteve-se abaixo do número médio registrado nos anos anteriores.\nMas o que aconteceu em 2015? Já que em 2015 houve este comportamento tão brusco resolvi procurar no Google por notícias de acidentes na Ponte Rio-Niterói neste período e em uma breve pesquisa me deparei com a seguinte notícia:\nEssa afirmação na manchete, que houve “redução de quase 60% após o videomonitoramento” é intrigante e seria interessante conseguir achar algum resultado concordante.\nNa notícia \" Monitoramento com câmeras ajuda a reduzir acidentes na Ponte Rio-Niterói \" um inspetor da PRF faz a seguinte declaração:\n“(…) Ajuda a amplificar o nosso poder de visualização das infrações que são cometidas. Concequentemente reduz o numero de acidentes por conta da presença quase que em todo trecho, ao mesmo tempo, da PRF”\nNúmero de acidentes por mês nos últimos 10 anos agrupados Como o gráfico ficou carregado ao levar em consideração o número de acidentes ao longo dos dias, a mesma informação será agrupada por mês.\nVejamos visualmente os dados fornecidos pela PRF e o dia em que a notícia foi atualizada:\ng2 \u0026lt;- base %\u0026gt;% map_df(~.x %\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente) %\u0026gt;% mutate_if(is.character,~ dmy(.x) )) %\u0026gt;% group_by(month=floor_date(data_inversa, \u0026quot;1 month\u0026quot;)) %\u0026gt;% summarise(n = n()) %\u0026gt;% ggplot(aes(x=month, y=n)) + geom_line() + geom_point() + theme_bw() + labs(y= \u0026#39;Número de acidentes\u0026#39;, x = \u0026#39;Data\u0026#39;, title= \u0026#39;Número de acidentes na Ponte Rio-Niterói\u0026#39;, subtitle = \u0026quot;Por mês\u0026quot;, caption = \u0026quot;Fonte dos dados: \\nhttp://glo.bo/210j8gF \\nhttps://www.prf.gov.br/portal/dados-abertos/acidentes\\nhttps://gomesfellipe.github.io/\u0026quot;) + scale_y_continuous(breaks=seq(0,150,25)) g2 + geom_segment(x = as.Date(\u0026quot;2015-11-13\u0026quot;), xend = as.Date(\u0026quot;2015-11-13\u0026quot;), y=0,yend=100, linetype=\u0026quot;dashed\u0026quot;, col=\u0026quot;red\u0026quot;) + geom_text(aes(y = 100, x = as.Date(\u0026quot;2015-11-13\u0026quot;), label = \u0026quot;G1 em 17/11/2015 :\\n\\\u0026quot;Monitoramento com câmeras\\n ajuda a reduzir acidentes\\n na Ponte Rio-Niterói\\\u0026quot;\u0026quot;) ,hjust=-0.1) + scale_x_date(date_breaks = \u0026#39;6 month\u0026#39;) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) De fato, visualmente é possível notar uma aparente diminuição no ano do qual a notícia foi divulgada mas será que é possível identificar algum tipo de tendência a partir destes dados?\nNúmero de acidentes por mês nos últimos 10 anos agrupados por ano Vejamos a seguir o gráfico separado por cada ano para comparar o comportamento dos dados:\ng2 + # geom_smooth(method = \u0026quot;lm\u0026quot;, se = F, aes(col = \u0026quot;blue\u0026quot;)) + facet_wrap( ~ year(month), scales = \u0026quot;free_x\u0026quot;) + scale_colour_manual(name=\u0026quot; \u0026quot;, values=c(\u0026quot;blue\u0026quot;),labels=c(\u0026quot;Regressão Linear\u0026quot;)) + theme(legend.position = c(0.88,0.20)) Neste gráfico vemos que dos anos de 2008 à 2014 os dados se comportam de forma parecida em torno de 100 à 75 acidentes. Porém em 2015 o número de acidentes termina por volta de 25 e este número se mantém ao longo dos anos.\nAjuste do modelo descritivo Para entender melhor essa tendência apresentada em 2015 será ajustado modelo de regressão linear simples conforme metodologia apresentada em @tend, que utilizam o tempo como variável explicativa e entender qual foi a variação do número de acidentes médios por mês.\nO método utilizado para avaliar a tendência consiste em um ajuste de tendência em função do tempo (\\(t\\)) com um modelo de regressão linear de maneira que:\n\\[ Y_{i} = \\beta_0 + \\beta_1 t_i + \\epsilon_{i} \\]\nem que:\n\\(Y_i\\): Tendência para o número de acidentes médios por mês no instante \\(i\\) \\(t_i\\): i-ésimo instante de tempo \\(\\beta_0\\): Intercepto do modelo (valor de \\(Y_i\\) quando \\(t_i=0\\)) \\(\\beta_1\\): Inclinação da reta ajustada (efeito da variável \\(t_i\\)) \\(\\epsilon_i \\sim N(0,\\sigma^2)\\) onde \\(\\sigma^2\\) é constante Este modelo de regressão linear mede a variação da tendência para diferentes valores de intervalo de tempo na faixa de interesse. O ajuste é interpretado de acordo com a inclinação da reta formada pelos diferentes valores de referência em relação a respectiva tendência pode não ser o melhor método para a previsão mas pode ajudar a entender o comportamento da série como análise descritiva.\nto_lm \u0026lt;- base %\u0026gt;% map_df(~.x%\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente)%\u0026gt;% mutate_if(is.character,~ dmy(.x) )) %\u0026gt;% group_by(data_inversa=floor_date(data_inversa, \u0026quot;1 month\u0026quot;)) %\u0026gt;% summarise(n = n()) %\u0026gt;% filter(data_inversa \u0026gt;= \u0026quot;2015-01-01\u0026quot; \u0026amp; data_inversa \u0026lt; \u0026quot;2016-01-01\u0026quot;) y \u0026lt;- to_lm %$% n %\u0026gt;% ts(start = c(2015, 01, 01)) g2 + geom_smooth(method=\u0026#39;lm\u0026#39;,se=F,aes(col=I(\u0026quot;darkred\u0026quot;))) + geom_smooth(data=to_lm, aes(x=data_inversa, y=n,col=I(\u0026quot;blue\u0026quot;)), method = \u0026quot;lm\u0026quot;,se=F) + scale_colour_manual(name=NULL, values=c(\u0026quot;red\u0026quot;,\u0026quot;blue\u0026quot;,\u0026quot;darkred\u0026quot;),labels=c( \u0026quot;Regressão Linear para 2015\u0026quot;, \u0026quot;Regressão Linear para todo período\u0026quot;, \u0026quot;Notícia\u0026quot; )) + theme(legend.position = c(0.2,0.18)) + geom_segment(x = as.Date(\u0026quot;2015-11-13\u0026quot;), xend = as.Date(\u0026quot;2015-11-13\u0026quot;), y=0, yend=100, linetype=\u0026quot;dashed\u0026quot;, aes(col=I(\u0026quot;red\u0026quot;))) + geom_text(aes(y = 100, x = as.Date(\u0026quot;2015-11-13\u0026quot;), label = \u0026quot;G1 em 17/11/2015 :\\n\\\u0026quot;Monitoramento com câmeras\\n ajuda a reduzir acidentes\\n na Ponte Rio-Niterói\\\u0026quot; \u0026quot;) ,hjust=-0.1) + scale_x_date(date_breaks = \u0026#39;6 month\u0026#39;) + theme(axis.text.x = element_text(angle = 45, hjust = 1), legend.background = element_rect(fill=alpha(\u0026#39;lightgrey\u0026#39;, 0.2))) Antes de conferir os resultados do ajuste do modelo, veja o resultado para o teste de sequências (Wald-Wolfowitz) que tem como hipótese alternativa \\(H_1:\\) existe tendência na série\nrandtests::runs.test(y) ## ## Runs Test ## ## data: y ## statistic = -3.0277, runs = 2, n1 = 6, n2 = 6, n = 12, p-value = ## 0.002465 ## alternative hypothesis: nonrandomness Ao nível de significância de \\(\\alpha :\\) 0.05 rejeita-se a hipótese nula de que esta série não apresenta tendência no período selecionado (2015).\nOutra hipótese importante para conferir é sobre a normalidade da variável resposta, a seguir será aplicado o teste de Shapiro-wilk que tem como hipótese nula de que os dados possuem distribuição normal:\nshapiro.test(y) ## ## Shapiro-Wilk normality test ## ## data: y ## W = 0.9702, p-value = 0.9129 De acordo com este teste, não existem evidências estatísticas para se rejeitar a hipótese da normalidade dos dados, portanto, para uma análise mais detalhada o modelo ajustado no período de 2015 pode ser obtido da seguinte maneira:\nfit \u0026lt;- tslm(y ~ trend, data = y) Com o modelo está salvo no objeto fit, sua informação será incrementada no gráfico da regressão de 2015 para facilitar o entendimento dos resultados:\ng1 \u0026lt;- base %\u0026gt;% map_df(~.x%\u0026gt;% select(id, data_inversa, causa_acidente, tipo_acidente)) %\u0026gt;% group_by(data_inversa=floor_date(data_inversa, \u0026quot;1 month\u0026quot;)) %\u0026gt;% dplyr::summarise(n=n()) %\u0026gt;% ggplot(aes(x=data_inversa, y=n)) + geom_line() + theme_bw() + labs(y= \u0026#39;Número de acidentes\u0026#39;, x = \u0026#39;Data\u0026#39;, subtitle = \u0026quot;Por dia\u0026quot;, title= \u0026#39;Número de acidentes na Ponte Rio-Niterói\u0026#39;, caption = \u0026quot;Fonte dos dados:\\nhttp://glo.bo/210j8gF\\nhttps://www.prf.gov.br/portal/dados-abertos/acidentes\\nhttps://gomesfellipe.github.io/\u0026quot;) + theme(axis.text.x = element_text(angle = 45, hjust = 1)) + scale_y_continuous(breaks=seq(0,100,25)) + annotate(\u0026quot;text\u0026quot;, x=as.Date(\u0026quot;2015-08-13\u0026quot;), y = 75, label = paste(\u0026quot;Modelo teórico: Yi = β^0 + β1 ti + ei:\\nEstimador do Nº de acidentes =\u0026quot;,round(fit$coefficients[1],2),round(fit$coefficients[2],2),\u0026quot;* Mês\u0026quot;)) t \u0026lt;- fit %\u0026gt;% tidy() %\u0026gt;% bind_cols(r2=c(glance(fit)[[1]] %\u0026gt;% round(4),\u0026quot;-\u0026quot;), confint_tidy(fit)) %\u0026gt;% mutate_if(is.numeric,~ round(.x,4)) %\u0026gt;% mutate(term = c(\u0026quot;Intercepto\u0026quot;, \u0026quot;Tendência\u0026quot;)) %\u0026gt;% set_names(c(\u0026quot;Coef.\u0026quot;, \u0026quot;Estimativa\u0026quot;, \u0026quot;Erro Padrão\u0026quot;, \u0026quot;Estatística\u0026quot;, \u0026quot;Valor P\u0026quot;, \u0026quot;R²\u0026quot;,\u0026quot;Lim. Inf.\u0026quot;, \u0026quot;Lim. Sup.\u0026quot;)) # Funcao auxiliar para colorir a celula g \u0026lt;- tableGrob(t,rows = NULL) find_cell \u0026lt;- function(table, row, col, name=\u0026quot;core-fg\u0026quot;){ # Fonte: # https://cran.r-project.org/web/packages/gridExtra/vignettes/tableGrob.html l \u0026lt;- table$layout which(l$t==row \u0026amp; l$l==col \u0026amp; l$name==name) } ind \u0026lt;- find_cell(g, 3, 2, \u0026quot;core-bg\u0026quot;) g$grobs[ind][[1]][[\u0026quot;gp\u0026quot;]] \u0026lt;- gpar(fill=\u0026quot;darkolivegreen1\u0026quot;, col = \u0026quot;darkolivegreen4\u0026quot;, lwd=5) g1 + scale_x_date(date_breaks = \u0026#39;1 months\u0026#39;, limits = as.Date(c(\u0026quot;2015-01-01\u0026quot;,\u0026quot;2015-12-01\u0026quot;)), expand = c(0.01,0.01)) + geom_smooth(data=to_lm, aes(x=data_inversa, y=n), method = \u0026quot;lm\u0026quot;,col=\u0026quot;red\u0026quot;,se=F)+ annotation_custom(grob = g , ymax=220,xmin=as.Date(\u0026quot;2015-04-01\u0026quot;)) Nota-se que o coeficiente estimado para determinar a variação do número de acidentes ao aumentar a variável explicativa trend em uma unidade se apresenta de maneira significante, isto quer dizer que parece existir relação linear estatisticamente significante entre o mês da observação e a variável resposta.\nAlém disso é possível notar que para cada aumento de uma unidade da tred (ou seja, no decorrer de 1 mês), o valor esperado no número de acidentes observados naquele mês diminui em aproximadamente 4.7972.\nComo -4.7972 x 12 = -57.5664 então o número de acidentes esperados decresce para aproximadamente 57.57% do valor original conforme a variável tred aumentou em 12 unidades (em 1 ano).\nVeja o resultado para o teste de Shapiro - wilk para avaliar a hipótese de normalidade dos resíduos do modelo, os resíduos padronizados(quociente entre o resíduo e a estimativa do seu desvio padrão) e os resíduos studentizados, que levam em conta o \\(h\\) (medida de alavancagem ou \" leverage\") em sua medida:\nbind_cols( residuals = fit$residuals, rstandard = rstandard(fit), rstudent = rstudent(fit) ) %\u0026gt;% map_dbl(~shapiro.test(.x)$p.value) %\u0026gt;% tidy() %\u0026gt;% set_names(c(\u0026quot;Medida\u0026quot;, \u0026quot;Valor p\u0026quot;)) %\u0026gt;% kable(escape = F) %\u0026gt;% kable_styling(\u0026quot;hover\u0026quot;,full_width = F) Medida Valor p residuals 0.1166788 rstandard 0.1801799 rstudent 0.0058696 Não existem evidências para rejeitar a hipótese de que os resíduos do modelo e os resíduos padronizados seguem distribuição normal. Já para os resíduos studentizados rejeita-se a hipótese de normalidade e como o valor de R² não foi muito alto (66.51%), indicando que a reta ajustada explica parcialmente a variação dos dados então pode ser interessante estudar com mais detalhes qual foi a influência do número de acidentes em cada mês no ajuste do modelo calculando as medias de influência para cada observação do modelo.\nUma observação é considerada influente caso sua exclusão no ajuste do modelo de regressão cause uma mudança substancial na análise de regressão e para identificar essas observações serão utilizadas as mesmas medidas utilizadas no post que fiz sobre Pacotes do R para avaliar o ajuste de modelos.\nDe maneira visual e com medidas de influência do valor observado para cada mês no ajuste do modelo:\nt1 \u0026lt;- influence.measures(fit) %$% infmat %\u0026gt;% as_tibble() %\u0026gt;% map_df(~.x %\u0026gt;% round(4)) %\u0026gt;% mutate(mes = 1:12) %\u0026gt;% select(mes,everything()) %\u0026gt;% set_names(c(\u0026quot;Mês\u0026quot;,\u0026quot;DF β1\u0026quot;,\u0026quot;DF β2\u0026quot;,\u0026quot; DFFit\u0026quot;,\u0026quot; CovRatio\u0026quot;,\u0026quot; D.Cook\u0026quot;,\u0026quot; h\u0026quot;)) g \u0026lt;- tableGrob(t1,rows = NULL) ind \u0026lt;- map_dbl(1:7, ~find_cell(g, 6, .x, \u0026quot;core-bg\u0026quot;)) walk(ind, function(i) g$grobs[i][[1]][[\u0026quot;gp\u0026quot;]] \u0026lt;\u0026lt;- gpar(fill = \u0026quot;darkolivegreen1\u0026quot;, col = \u0026quot;darkolivegreen1\u0026quot;, lwd = 5) ) # g2 \u0026lt;- # ggplot2::autoplot(fit, print=F,suppressMessages=T) + # theme_bw() # # gn \u0026lt;- arrangeGrob(g2[[1]], g2[[2]], g2[[3]], g2[[4]], g2[[5]], g2[[6]]) # # grid.arrange(gn, g, ncol=2) grid.arrange(g) A tabela apresenta um resumo das medidas de inflencia de cada variável, segundo @gauss:\nDF Beta: Alteração no vetor estimado β ao se retirar o i-ésimo ponto da análise\nDF Fit: Alteração provocada no valor ajustado pela retirada da observação i\nCovRatio: Expressa o relação de covariância\nD.Cook: Medida de afastamento das estimativas ao retirar i e também considera o resíduo estudentizado internamente\nh: Elementos da diagonal da matriz H É possível notar que no mês 5 (Maio) foi o mês que provocaria a maior alteração provocada no valor ajustado após sua retirada. Outra medida importante é a Distância de Cook que indica o quão atípica a observação \\(i\\) se apresenta no ajuste do modelo combinando os resíduos estudentizados e as medidas de alavancagem possibilitando examinar observações que influenciam bastante as estimativas dos parâmetros.\nEm geral, se \\(D_i\u0026gt;1\\) o ponto é excessivamente influente mas como no geral as observações apresentaram valor muito inferior a 1 então a eliminação de qualquer uma dessas variáveis não vai alterar substancialmente as estimativas dos parâmetros porém nós podemos examinar quaisquer observações cujo \\(D_i\\) seja muito maior em relação aos demais valores estimados para \\(D_i\\) com mais cuidado para entender qual foi foi sua influência no ajuste do modelo:\n# Como a funcao augment do broom nao parece mais suportar o modelo ajustado por tslm, vamos ajustar na mão o modelo com a tendencia para criar o gráfico: to_lm \u0026lt;- to_lm %\u0026gt;% mutate(trend = 1:nrow(.)) fit_lm \u0026lt;- lm(y ~ trend, data = to_lm) fit_lm %\u0026gt;% broom::augment() %\u0026gt;% mutate(col = if_else(.resid==max(.resid), T, F))%\u0026gt;% mutate(trend = factor(months(base[[1]]$data_inversa) %\u0026gt;% unique, levels = months(base[[1]]$data_inversa) %\u0026gt;% unique) ) %\u0026gt;% ggplot(aes(x=trend,y=.resid,col=col,label=trend)) + geom_point() + geom_label(vjust = -0.25) + theme_bw() + scale_y_continuous(limits=c(-20,35),breaks = seq(-20,35,5)) + scale_color_manual(values=c(\u0026quot;black\u0026quot;, \u0026quot;red\u0026quot;)) + geom_hline(yintercept = 0,linetype=\u0026quot;dashed\u0026quot;,col=\u0026quot;red\u0026quot;) + theme(legend.position=\u0026quot;none\u0026quot;) + labs(y=\u0026quot;Resíduos\u0026quot;, x=\u0026quot;Valores ajustados\u0026quot;, title=\u0026quot;Resíduos vs Ajuste\u0026quot;) De fato o valor ajustado para o mês de maior é muito diferente do valor real observado, o que implica que houve um comportamento atípico que pode ser confirmado ao voltar no gráfico da série temporal e constatar um comportamento diferente (o número de acidente aumentou em relação ao anterior) e fugindo da tendência geral dos dados.\nPróximos passos Uma das outras idéias que tive para a analisar estes dados conforme avançava com o estudo foi de cruza-los com o fluxo de carros na ponte para ter uma ideia de proporção mas essa ideia fica como sugestão para quem também tiver curiosidade sobre este assunto pois a intensão deste post é fazer uma análise de caráter introdutório para mostrar como é possível obter insights através dos dados com o uso da Estatística.\nAlém disso gostaria de incentivar todo o pessoal que gosta de dados e tiverem dúvidas sobre questões da vida, o universo e tudo mais a procurarem sempre por respostas mas tomar muito cuidado ao tirar conclusões! Este, por exemplo, foi um estudo de caráter introdutório e descritivo e obviamente existe uma porção de outras maneiras de estudar estes dados e como estamos diante de tanta abundância, basta uma pergunta que a investigação pode ser iniciada e se sempre temos a resposta para tudo nosso cérebro nunca entra “no modo de busca”. É importante sempre questionar respostas!\nReferências Notícia do G1: Monitoramento com câmeras ajuda a reduzir acidentes na Ponte Rio-Niterói\nCORDEIRO, G. M. Modelos de Regressão: Diagnóstico e Seleção de Variáveis. Notas de Aula. Recife: UFPE, 2002.\nMORETTIN, P. A.; TOLOI, C. M. C. Análise de Séries Temporais: Modelos Lineares Univariados. 2. ed. São Paulo: Edgard Blücher, 2006.\nPerguntas frequentes O número de acidentes na Ponte Rio-Niterói ocorre diariamente?\nNão, segundo os dados da PRF analisados nos últimos 10 anos os acidentes não se mostraram diários, considerando que não houve subnotificação de ocorrências.\nO número de acidentes na ponte tem diminuído ao longo dos anos?\nO comportamento dos dados sugere que sim. Houve uma queda expressiva nos registros a partir de 2015, ano em que passou a haver monitoramento por câmeras de segurança.\nDe onde vêm os dados usados na análise?\nOs dados são públicos, disponibilizados pela Polícia Rodoviária Federal na sessão de Dados Abertos, filtrados para o trecho BR-101, Km 321 a 334, que corresponde à Ponte Rio-Niterói.\n","date":"29 de setembro de 2018","externalUrl":null,"permalink":"/post/2018-09-29-freq-acidente-ponte-rio-niteroi/","section":"Posts","summary":" Perguntas Estudar em outra cidade têm suas vantagens e desvantagens, durante toda a graduação atravessei Baía de Guanabara pela Ponte Presidente Costa e Silva, (popularmente conhecida como Ponte Rio–Niterói) assim como todas as pessoas que fazem esse trajeto diariamente e diante de tanta beleza natural com a vista panorâmica da Baía como os espetáculos proporcionados pelo pôr do sol, os pássaros ou a beleza inegável do Pão de Açúcar também é notável a beleza fruto da maior habilidade humana: a criatividade. Temos o cristo, todos aqueles grandes barcos, o Porto do Rio de Janeiro com todas aquelas obras de Engenharia, ou até mesmo a própria Ponte, que por si só já é intrigante.\n","title":"Com que frequência ocorrem acidentes na ponte Rio-Niterói?","type":"post"},{"content":"","date":"29 de setembro de 2018","externalUrl":null,"permalink":"/tags/leaflet/","section":"Tags","summary":"","title":"Leaflet","type":"tags"},{"content":"","date":"29 de setembro de 2018","externalUrl":null,"permalink":"/tags/mapa/","section":"Tags","summary":"","title":"Mapa","type":"tags"},{"content":"","date":"29 de setembro de 2018","externalUrl":null,"permalink":"/tags/ponte-rio-niteroi/","section":"Tags","summary":"","title":"Ponte-Rio-Niteroi","type":"tags"},{"content":"","date":"31 de agosto de 2018","externalUrl":null,"permalink":"/tags/caret/","section":"Tags","summary":"","title":"Caret","type":"tags"},{"content":"","date":"31 de agosto de 2018","externalUrl":null,"permalink":"/tags/decisiontree/","section":"Tags","summary":"","title":"Decisiontree","type":"tags"},{"content":" Kaggle Segundo o Wikipédia: “Kaggle é a maior comunidade mundial de cientistas de dados e machine learning.” Aprendo muito estudando as resoluções de alguns competidores pois lá é possível conferir tanto as metodologias utilizadas pelos competidores quando os códigos e é notável o cuidado dos participantes para que seja possível a reprodutibilidade dos resultados, o que pode impulsionar o aprendizado.\nO Kaggle trabalha com a ideia de gamificação, que é um assunto do qual já escrevi em um post sobre gamificação e porque aprender R é tão divertido e gosto deste conceito de se criar jogos para motivar e engajar as pessoas em atividades profissionais e a ideia de se estar em um jogo possibilita doses de motivação especialmente a quem gosta de competir.\nA plataforma é focada em competições que envolvem modelagem preditiva, que julgam apenas o seu desempenho preditivo, embora a inteligibilidade não deixe de ser importante. Neste post farei também a modelagem descritiva com modelos de aprendizagem baseados em árvores, na qual o principal objetivo será obter informações sobre os dados para o ajuste dos modelos preditivos que iremos submeter à competição do Kaggle House Prices: Advanced Regression Techniques.\nTL;DR\nO post usa o dataset Ames Housing (Kaggle) para prever o preço de venda de casas com 79 variáveis explicativas, comparando árvore de decisão, bagging, Random Forest, GBM e regressão linear. Entre os algoritmos testados, o GBM (Gradient Boosting) apresentou o melhor resultado, com Rsquared de 0,889 e RMSE de 0,1331 na validação cruzada de 5 folds. A variável OverallQual foi consistentemente a mais importante em todos os modelos baseados em árvore, seguida por GrLivArea e YearBuilt. A diferença entre modelos preditivos e descritivos não é tão rigorosa assim pois algumas das técnicas podem ser utilizadas para ambos e geralmente um modelo pode servir para ambos os propósitos (mesmo que de de forma insuficiente).\nAlém dos modelos de machine learning baseados em árvores, também será ajustado um modelo de regressão linear multivariado para compararmos os resultados dos ajustes e submeter nossas previsões no site do kaggle.\nOs modelos baseados em árvores são um ótimo ponto de partida em machine learning, um dos pilares que apresento na introdução à ciência de dados para quem está começando.\nOs pacotes que serão utilizados serão os seguintes:\nlibrary(purrr) # Programacao funciona library(broom) # Arrumar outputs library(dplyr) # Manipulacao de dados library(magrittr) # pipes library(funModeling) # df_status() library(plyr) # revalue() library(gridExtra) # Juntar ggplots library(reshape) # funcao melt() library(rpart) # Arvore de Decisoes library(rpart.plot) # Plot da Arvore de Decisoes library(data.table) # aux na manipulacao do heatmap library(readr) # Leitura da base de dados library(stringr) # Manipulacao de strings library(ggplot2) # Graficos elegantes library(caret) # Machine Learning library(GGally) # up ggplot library(ggfortify) # autoplot() Base de dados A base de dados deste post vem de uma competição ótima para estudantes de ciência de dados de dados com alguma experiência com R ou Python e noções básicas de machine learning e estatística.\nPode ser útil para aqueles que desejam expandir seu conjunto de habilidades em uma tarefa de regressão, quando a variável \\(y\\) que desejamos estimar é do tipo numérico (contínuo ou discreto).\nTrata-se do conjunto de dados Ames Housing que foi compilado por Dean De Cock para uso em educação de ciência de dados.\ntrain \u0026lt;- read_csv(\u0026quot;train.csv\u0026quot;) test \u0026lt;- read_csv(\u0026quot;test.csv\u0026quot;) full \u0026lt;- bind_rows(train, test) id \u0026lt;- test$Id full %\u0026lt;\u0026gt;% select(-Id) Descrição da Competição Traduzido do site oficial do kaggle:\n\"Peça a um comprador que descreva a casa dos seus sonhos, e eles provavelmente não começarão com a altura do teto do porão ou a proximidade de uma ferrovia leste-oeste. Mas o conjunto de dados desta competição de playground prova que muito mais influencia as negociações de preço do que o número de quartos ou uma cerca branca.\nCom 79 variáveis explicativas descrevendo (quase) todos os aspectos de casas residenciais em Ames, Iowa, esta competição desafia você a prever o preço final de cada casa.\"\nPortanto, primeiramente vamos entender o comportamento da variável resposta, depois buscar quais dessas 79 variáveis explicativas são mais importantes para representar a variação do preço de venda das casas através dos métodos baseados em árvores e por fim ajustar os modelos propostos e submeter nossas estimativas no site!\nAnálise exploratória dos dados Antes de pensar em ajustar algum modelo é extremamente necessário entender como se comportam os dados, portanto, tanto a variável resposta quanto as variáveis explicativas serão avaliadas.\nVariável resposta: SalePrice - o preço de venda da propriedade em dólares. Essa é a variável de destino que estamos tentando prever.\nNote que a distribuição dos dados referentes ao preço de venda se distribui de maneira assimétrica e não possuem evidências de normalidade dos dados. Apesar dos métodos baseados em árvore se tratarem de técnicas não paramétricas essa transformação será feita pois ao final deste post desejo comparar os resultados com um modelo de regressão linear múltipla.\nÁrvore de decisão Uma técnica muito popular que é mais comumente usada para resolver tarefas de classificação de dados porém a árvore conhecida como CART (Classification and Regression Trees)(Breiman, 1986) lida com todos os tipos de atributos (incluindo atributos numéricos que são tratados a partir da criação de intervalos). Para seu ajuste é possível realizar podas e produzir árvores binárias.\nA construção da árvore é realizada por meio do algoritmo que iterativamente analisa os atributos descritivos de um conjunto de dados previamente rotulado. Sua popularidade como apoio para a tomada de decisão se deve principalmente ao fato da fácil visualização do conhecimento gerado e o fácil entendimento.\nOutra característica legal da árvore de decisões é que ela permite ajustar um modelo sem um pré-processamento detalhado, pois é fácil de ajustar, aceita valores faltantes e é de fácil interpretação, veja:\nlibrary(rpart) control \u0026lt;- rpart.control(minsplit =10, # o número mínimo de observações em um nó cp = 0.006 # parametro de complexidade q controla o tamanho da arvore ) rpartFit \u0026lt;- rpart(exp(SalePrice) ~ . , train, method = \u0026quot;anova\u0026quot;, control = control) rpart.plot::rpart.plot(rpartFit,cex = 0.6) No topo, vemos o primeiro nó com 100% das observações, que representa o total da base (100%). Em seguida, vemos que a primeira variável que determina o preço de venda das casas SalePrice é a variável OverallQual. As casas que apresentaram OverallQual \u0026lt; 7.5 ocorrem em maior proporção do que as que tiveram OverallQual\u0026gt;7.5. A interpretação pode continuar dessa forma recursivamente.\nÉ possível notar que as variáveis OverallQual,Neighborhood,1stFlrSF,2ndFlrSF,GrLivArea, BsmtFinSF1 foram as que melhor representaram os dados de acordo com os parâmetros que determinamos para ajustar esta árvore, vejamos com mais detalhes se existe relação linear e intensidade e direção dessa relação com o coeficiente de correlação de Pearson entre estas variáveis dois a dois e em relação à variável resposta:\ndevtools::source_url(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/correlations_for_ggpairs.R\u0026quot;) train %\u0026gt;% select(SalePrice,OverallQual,`1stFlrSF`,`2ndFlrSF`,GrLivArea,BsmtFinSF1) %\u0026gt;% ggpairs(lower = list(continuous = my_fn))+ theme_bw() Com esta figura temos muitas informações, destaca-se que todas essas variáveis possuem algum tipo de relação linear com a variável resposta, a menor correlação observada foi com o BsmtFinSF1 e a variável que apresentou a maior correlação foi a OverallQual. Atenção para a correlação entre SalePrice e OverallQual, pois Overallqual parece ser uma variável ordinal e uma outra medida de correlação que melhor representaria esta relação é o coeficiente de correlação de Spearman, veja:\ncor(full$SalePrice, full$OverallQual, method = \u0026quot;spearman\u0026quot;, use = \u0026quot;complete.obs\u0026quot;) ## [1] 0.8098286 Um pouco diferente do resultado da correlação de Pearson pois avalia relações lineares, já a correlação de Spearman avalia relações monótonas, sejam elas lineares ou não.\nAnálise exploratória e input de NAs Arrumar a base de dados é uma tarefa longa e que geralmente consome grande parte no tempo em um projeto de ciência de dados. Não adianta usar o algorítimo mais poderoso de machine learning se a base de dados não estiver arrumada de maneira que possibilite a análise dos dados.\nPara obter informações da amostra, confira no link do dataset da competição no Kaggle. Na página é possível conferir a descrição da amostra e nela nota-se que alguns dos valores faltantes possuem significado, então é necessário rotulá-los para que o R possa interpretar estes valores da maneira correta.\nStatus da amostra Conferindo o status da amostra com a função df_status() do pacote funModeling:\nfull %\u0026gt;% df_status(print_results = F) %\u0026gt;% as_tibble() %\u0026gt;% arrange(-p_na, -p_zeros) ## # A tibble: 80 x 9 ## variable q_zeros p_zeros q_na p_na q_inf p_inf type unique ## \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 PoolQC 0 0 2909 99.7 0 0 character 3 ## 2 MiscFeature 0 0 2814 96.4 0 0 character 4 ## 3 Alley 0 0 2721 93.2 0 0 character 2 ## 4 Fence 0 0 2348 80.4 0 0 character 4 ## 5 SalePrice 0 0 1459 50.0 0 0 numeric 663 ## 6 FireplaceQu 0 0 1420 48.6 0 0 character 5 ## 7 LotFrontage 0 0 486 16.6 0 0 numeric 128 ## 8 GarageYrBlt 0 0 159 5.45 0 0 numeric 103 ## 9 GarageFinish 0 0 159 5.45 0 0 character 3 ## 10 GarageQual 0 0 159 5.45 0 0 character 5 ## # … with 70 more rows Note que as variáveis problemáticas foram ordenadas de forma decrescente (maior número de dados faltantes e zeros) vamos tratar uma de cada vez partindo da variável mais crítica\nPool PoolQC é a variável que possui mais NA e a descrição da base informa que: PoolQC: qualidade da piscina\nEx Excelente Gd Good TA Média / Típica Fa Pequena NA sem piscina É possível observar que se trata de uma variável ordinal, portanto vamos criar uma variável auxiliar (pois esta descrição se repete em outras variáveis):\n# Criando variável auxilar ordinal Qualidade \u0026lt;- c(\u0026#39;None\u0026#39; = 0, \u0026#39;Po\u0026#39; = 1, \u0026#39;Fa\u0026#39; = 2, \u0026#39;TA\u0026#39; = 3, \u0026#39;Gd\u0026#39; = 4, \u0026#39;Ex\u0026#39; = 5) full %\u0026lt;\u0026gt;% mutate(PoolQC = ifelse(PoolQC %\u0026gt;% is.na, \u0026quot;None\u0026quot;, PoolQC) %\u0026gt;% as.factor() ) %\u0026gt;% mutate(PoolQC = as.integer(revalue(PoolQC, Qualidade))) Além disso, existe outra variável relacionada à piscina, veja:\nfull %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Pool\u0026quot;)]) %\u0026gt;% table ## PoolQC ## PoolArea 1 2 3 4 ## 0 0 0 0 2906 ## 144 1 0 0 0 ## 228 1 0 0 0 ## 368 0 0 0 1 ## 444 0 0 0 1 ## 480 0 0 1 0 ## 512 1 0 0 0 ## 519 0 1 0 0 ## 555 1 0 0 0 ## 561 0 0 0 1 ## 576 0 0 1 0 ## 648 0 1 0 0 ## 738 0 0 1 0 ## 800 0 0 1 0 full %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Pool\u0026quot;)]) %\u0026gt;% map(~sum(is.na(.x))) ## $PoolArea ## [1] 0 ## ## $PoolQC ## [1] 0 # Arrumando inconsistëncias: full %\u0026lt;\u0026gt;% mutate(PoolQC = ifelse(PoolQC == 0 \u0026amp; PoolArea !=0, 2, PoolQC)) # Arrumando inconsistëncias: full %\u0026lt;\u0026gt;% mutate(Pool = ifelse(PoolQC == 0 \u0026amp; PoolArea ==0, \u0026quot;no\u0026quot;, \u0026quot;yes\u0026quot;)) Misc Se referem aos recursos diversos\nfull %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Misc\u0026quot;)], SalePrice ) %\u0026gt;% map(~sum(is.na(.x))) ## $MiscFeature ## [1] 2814 ## ## $MiscVal ## [1] 0 ## ## $SalePrice ## [1] 1459 MiscFeature: recurso diverso não coberto em outras categorias\nElevador elev Gar2 2nd Garage (se não for descrito na seção de garagem) Othr Outro Galpão derramado (mais de 100 SF) TenC Campo de ténis NA Nenhum Desta vez não se trata de uma variável ordinal, vejamos:\nfull %\u0026lt;\u0026gt;% mutate(MiscFeature = if_else(MiscFeature %\u0026gt;% is.na, \u0026quot;None\u0026quot;, MiscFeature) %\u0026gt;% as.factor) # Breve resumo: g1 \u0026lt;- full %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Misc\u0026quot;)], SalePrice) %\u0026gt;% ggplot(aes(y=MiscVal,x= reorder(MiscFeature, -MiscVal,FUN = median) ,fill=MiscFeature))+ geom_boxplot()+ theme_bw() + scale_fill_viridis_d() + labs(x = \u0026quot;Recurso Diverso\u0026quot;) g2 \u0026lt;- full %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Misc\u0026quot;)], SalePrice) %\u0026gt;% ggplot(aes(y=SalePrice,x= reorder(MiscFeature, -MiscVal,FUN = median) ,fill=MiscFeature))+ geom_boxplot()+ theme_bw() + scale_fill_viridis_d() + labs(x = \u0026quot;Preço de Venda\u0026quot;) grid.arrange(g1, g2) rm(g1,g2) Além disso, MiscVal: Valor do recurso variado\nAlley Alley: Tipo de acesso ao beco para a propriedade\nGrvl Cascalho Pave pavimentado NA Nenhum acesso de beco Basta realizar o input:\nfull %\u0026lt;\u0026gt;% mutate(Alley = Alley %\u0026gt;% str_replace_na(\u0026quot;None\u0026quot;)) %\u0026gt;% mutate(Alley = as.factor(Alley)) full[!is.na(full$SalePrice),] %\u0026gt;% select(Alley, SalePrice) %\u0026gt;% ggplot(aes(y=SalePrice,x= reorder(Alley, -SalePrice,FUN = median) ,fill=Alley))+ geom_boxplot()+ theme_bw() + scale_fill_viridis_d() + labs(x = \u0026quot;tipo de Acesso\u0026quot;) Fence Fence: qualidade da cerca\nGdPrv Boa privacidade MnPrv minima privacidade GdWo boa madeira MnWw Mínima Madeira / Fio NA Sem cerca Input será da seguinte forma:\nfull %\u0026lt;\u0026gt;% mutate(Fence = Fence %\u0026gt;% str_replace_na(\u0026quot;None\u0026quot;)) full[1:nrow(train),] %\u0026gt;% select(Fence, SalePrice) %\u0026gt;% ggplot(aes(y=SalePrice,x= reorder(Fence, -SalePrice, median) ,fill=Fence))+ geom_boxplot()+ theme_bw() + scale_fill_viridis_d() + labs(x = \u0026quot;tipo de Acesso\u0026quot;) full %\u0026lt;\u0026gt;% mutate(Fence = as.factor(Fence)) Aparentemente não parece existir uma relação ordinal sobre o tipo de cerca quanto ao pre;o de venda da casa, portanto foi convertida para fator\nFirePlace Variáveis relacionadas com lareira. Segundo a descrição, temos:\nfull %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Fireplace\u0026quot;)], SalePrice) ## # A tibble: 2,919 x 3 ## Fireplaces FireplaceQu SalePrice ## \u0026lt;dbl\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;dbl\u0026gt; ## 1 0 \u0026lt;NA\u0026gt; 12.2 ## 2 1 TA 12.1 ## 3 1 TA 12.3 ## 4 1 Gd 11.8 ## 5 1 TA 12.4 ## 6 0 \u0026lt;NA\u0026gt; 11.9 ## 7 1 Gd 12.6 ## 8 2 TA 12.2 ## 9 2 TA 11.8 ## 10 2 TA 11.7 ## # … with 2,909 more rows Fireplaces: Numero de lareiras\nFireplaceQu: Qualidade da lareira\nEx Excellente - Excepcional Lareira de Alvenaria Gd Boa - Lareira de alvenaria no nível principal TA Média - lareira pré-fabricada na sala principal ou Lareira de alvenaria no porão Fa Pequena - Lareira pré-fabricada no porão Po Pobre - Fogão Ben Franklin NA sem lareira Nota-se que se trata de uma variável ordinal de acordo com a qualidade, portanto:\nfull %\u0026lt;\u0026gt;% mutate(FireplaceQu = if_else(FireplaceQu %\u0026gt;% is.na, \u0026quot;None\u0026quot;, FireplaceQu) ) %\u0026gt;% mutate(FireplaceQu = as.integer(revalue(FireplaceQu, Qualidade))) Conferindo se existem inconsistências:\nfull %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Fireplace\u0026quot;)]) %\u0026gt;% table ## FireplaceQu ## Fireplaces 0 1 2 3 4 5 ## 0 1420 0 0 0 0 0 ## 1 0 46 63 495 627 37 ## 2 0 0 10 92 112 5 ## 3 0 0 1 4 5 1 ## 4 0 0 0 1 0 0 Lot full %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Lot\u0026quot;)], SalePrice) %\u0026gt;% map_dbl(~sum(is.na(.x))) ## LotFrontage LotArea LotShape LotConfig SalePrice ## 486 0 0 0 1459 Segundo a descrição:\nLotFrontage: Ruas linearmente conectadas à propriedade\nLotArea : Tamanho do lote em pés quadrados\nLotShape: forma geral da propriedade\nRegue Regular\nIR1 ligeiramente irregular IR2 moderadamente irregular IR3 Irregular LotConfig: configuração de lote\nInside Lote muito para dentro Corner Canto de esquina CulDSac Cul-de-sac FR2 Frente em 2 lados da propriedade FR3 Frente em 3 lados da propriedade Input para o LotFrontage será feito considerando a configuração do lote, veja:\ninputsLot \u0026lt;- full %\u0026gt;% select(LotFrontage, LotConfig) %\u0026gt;% group_by(LotConfig) %\u0026gt;% dplyr::summarise(Media = mean(LotFrontage, na.rm = T), Mediana = median(LotFrontage, na.rm = T)) full$LotFrontage[is.na(full$LotFrontage) \u0026amp; full$LotConfig == inputsLot$LotConfig[1]] \u0026lt;- inputsLot$Mediana[1] full$LotFrontage[is.na(full$LotFrontage) \u0026amp; full$LotConfig == inputsLot$LotConfig[2]] \u0026lt;- inputsLot$Mediana[2] full$LotFrontage[is.na(full$LotFrontage) \u0026amp; full$LotConfig == inputsLot$LotConfig[3]] \u0026lt;- inputsLot$Mediana[3] full$LotFrontage[is.na(full$LotFrontage) \u0026amp; full$LotConfig == inputsLot$LotConfig[4]] \u0026lt;- inputsLot$Mediana[4] full$LotFrontage[is.na(full$LotFrontage) \u0026amp; full$LotConfig == inputsLot$LotConfig[5]] \u0026lt;- inputsLot$Mediana[5] Arrumando variáveis nominais e ordinais:\nfull %\u0026lt;\u0026gt;% mutate(LotShape = as.integer(revalue(full$LotShape, c(\u0026#39;IR3\u0026#39;=0, \u0026#39;IR2\u0026#39;=1, \u0026#39;IR1\u0026#39;=2, \u0026#39;Reg\u0026#39;=3)))) Garages Variáveis relacionadas, segundo a descrição, temos:\nfull %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Garage\u0026quot;)], SalePrice) %\u0026gt;% map_dbl(~sum(is.na(.x))) ## GarageType GarageYrBlt GarageFinish GarageCars GarageArea GarageQual ## 157 159 159 1 1 159 ## GarageCond SalePrice ## 159 1459 GarageType: localização da garagem\n2Types Mais de um tipo de garagem Attchd anexa a casa Basement tipo porao BuiltIn (garagem parte da casa - normalmente tem sala acima da garagem) CarPort Porta do carro Detchd nao anexa a casa NA Sem Garagem GarageYrBlt: garagem do ano foi construída\nGarageFinish: acabamento interior da garagem\nFin Finished RFn Áspero Finalizado\nUnf inacabado NA Sem Garagem GarageCars: Tamanho da garagem na capacidade do carro\nGarageArea: Tamanho da garagem em pés quadrados\nGarageQual: GarageQuality\nEx Excelente Gd Good TA Típico / Médio FA Justo Po Poor NA Sem Garagem GarageCond: condição de garagem\nEx Excelente Gd Good TA Típico / Médio Fa Justo Po Poor NA Sem Garagem full %\u0026lt;\u0026gt;% mutate(GarageType = if_else(GarageType %\u0026gt;% is.na, \u0026quot;None\u0026quot;, GarageType) ) %\u0026gt;% mutate(GarageYrBlt = if_else(GarageYrBlt %\u0026gt;% is.na,YearBuilt, GarageYrBlt) ) %\u0026gt;% mutate(GarageFinish = if_else(GarageFinish %\u0026gt;% is.na, \u0026quot;None\u0026quot;, GarageFinish) ) %\u0026gt;% mutate(GarageFinish = as.integer(revalue(GarageFinish, c(\u0026#39;None\u0026#39;=0, \u0026#39;Unf\u0026#39;=1, \u0026#39;RFn\u0026#39;=2, \u0026#39;Fin\u0026#39;=3)))) %\u0026gt;% mutate(GarageCars = ifelse(GarageCars %\u0026gt;% is.na, 0, GarageCars) ) %\u0026gt;% mutate(GarageArea = ifelse(GarageArea %\u0026gt;% is.na, 0, GarageArea)) %\u0026gt;% mutate(GarageQual = if_else(GarageQual %\u0026gt;% is.na, \u0026quot;None\u0026quot;, GarageQual)) %\u0026gt;% mutate(GarageQual = as.integer(revalue(GarageQual, Qualidade))) %\u0026gt;% mutate(GarageCond = if_else(GarageCond %\u0026gt;% is.na, \u0026quot;None\u0026quot;, GarageCond)) %\u0026gt;% mutate(GarageCond = as.integer(revalue(GarageCond, Qualidade))) table(full$GarageCond) ## ## 0 1 2 3 4 5 ## 159 14 74 2654 15 3 Bsmt full %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)], SalePrice) %\u0026gt;% map_dbl(~sum(is.na(.x))) ## BsmtQual BsmtCond BsmtExposure BsmtFinType1 BsmtFinSF1 BsmtFinType2 ## 81 82 82 79 1 80 ## BsmtFinSF2 BsmtUnfSF TotalBsmtSF BsmtFullBath BsmtHalfBath SalePrice ## 1 1 1 2 2 1459 BsmtQual: Avalia a altura do porão\nEx Excelente (100+ polegadas)\nGd Bom (90-99 polegadas) TA Típica (80-89 polegadas) Fa Justo (70-79 polegadas) Po Pobre (\u0026lt;70 polegadas NA Sem Porão BsmtCond: Avalia o estado geral do porão\nEx Excelente Gd Bom TA Típica - umidade ligeira permitida Fa Razoável - umidade ou alguma rachadura ou sedimentação Po Insuficiente - Craqueamento severo, sedimentação ou umidade NA Sem Porão BsmtExposure: Refere-se a paralisações ou paredes no nível do jardim\nGd Good Exposição Av Média Exposição (níveis divididos ou foyers normalmente pontuação média ou acima)\nMn Exposição Mínima No Não Exposição NA Sem porão BsmtFinType1: Avaliação da área acabada do porão\nGLQ Bons Viver ALQ Média Living Quarters BLQ Abaixo da média Living Quarters\nRec Média Rec Room LwQ Baixa Qualidade Unf unfinshed NA nenhum porão BsmtFinSF1: pes quadrados do tipo 1 terminado\nBsmtFinType2: Avaliação do porão área terminado (se vários tipos)\nGLQ Bons aposentos ALQ Medianos BLQ abaixo da media Rec Aposentos média qualidade LwQ Baixa Qualidade Unf Não Sem Porão BsmtFinSF2: Pés quadrados acabados do Tipo 2\nBsmtUnfSF: Pés quadrados inacabados da área do porão\nTotalBsmtSF: Total pés quadrados da área do porão\nInput das variáveis não numéricas com None e convertendo para ordinal as variáveis com relação de ordem. Para os faltantes das variáveis numéricas foram imputados o valor 0 (zeros).\n# Categóricos: full[,names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)]] \u0026lt;- full[,names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)]] %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)]) %\u0026gt;% mutate_if( ~ !is.numeric(.x) , ~ ifelse(is.na(.x), \u0026quot;None\u0026quot;, .x)) %\u0026gt;% mutate(BsmtQual = as.integer(revalue(BsmtQual, Qualidade))) %\u0026gt;% mutate(BsmtCond = as.integer(revalue(BsmtCond, Qualidade))) %\u0026gt;% mutate(BsmtExposure = as.integer(revalue(BsmtExposure, c(\u0026#39;None\u0026#39;=0, \u0026#39;No\u0026#39;=1, \u0026#39;Mn\u0026#39;=2, \u0026#39;Av\u0026#39;=3, \u0026#39;Gd\u0026#39;=4)))) %\u0026gt;% mutate(BsmtFinType1 = as.integer(revalue(BsmtFinType1,c(\u0026#39;None\u0026#39;=0, \u0026#39;Unf\u0026#39;=1, \u0026#39;LwQ\u0026#39;=2, \u0026#39;Rec\u0026#39;=3, \u0026#39;BLQ\u0026#39;=4, \u0026#39;ALQ\u0026#39;=5, \u0026#39;GLQ\u0026#39;=6)))) # Numéricos: full[,names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)]] \u0026lt;- full[,names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)]] %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;Bsmt\u0026quot;)]) %\u0026gt;% mutate_if( ~ is.numeric(.x) , ~ ifelse(is.na(.x), 0, .x)) MasVnr full %\u0026gt;% select(names(full)[names(full) %\u0026gt;% str_detect(\u0026quot;MasVnr\u0026quot;)], SalePrice) %\u0026gt;% map_dbl(~sum(is.na(.x))) ## MasVnrType MasVnrArea SalePrice ## 24 23 1459 MasVnrType: Alvenaria tipo de verniz\nBrkCmn Brick Common BrkFace Face de tijolos CBlock Bloco cinza None Nenhum Stone Pedra MasVnrArea: Área de folheado de alvenaria em pés quadrados\nfull %\u0026lt;\u0026gt;% mutate(MasVnrType = if_else(is.na(MasVnrType), \u0026quot;None\u0026quot;, MasVnrType)) %\u0026gt;% mutate(MasVnrType = as.integer(revalue(MasVnrType, c(\u0026#39;None\u0026#39;=0, \u0026#39;BrkCmn\u0026#39;=0, \u0026#39;BrkFace\u0026#39;=1, \u0026#39;Stone\u0026#39;=2)))) %\u0026gt;% mutate(MasVnrArea = if_else(is.na(MasVnrArea), 0, 1)) Variáveis restantes com poucos NA A estratégia adotada para imputar estes dados será tomada de maneira arbitrária. Os valores faltantes serão preenchidos com o valor comum mais frequente daquela variável. As variáveis que restam são:\nfull %\u0026gt;% df_status(print_results = F) %\u0026gt;% as_tibble() %\u0026gt;% arrange(-p_na, -p_zeros) ## # A tibble: 81 x 9 ## variable q_zeros p_zeros q_na p_na q_inf p_inf type unique ## \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 SalePrice 0 0 1459 50.0 0 0 numeric 663 ## 2 MSZoning 0 0 4 0.14 0 0 character 5 ## 3 Utilities 0 0 2 0.07 0 0 character 2 ## 4 Functional 0 0 2 0.07 0 0 character 7 ## 5 Exterior1st 0 0 1 0.03 0 0 character 15 ## 6 Exterior2nd 0 0 1 0.03 0 0 character 16 ## 7 Electrical 0 0 1 0.03 0 0 character 5 ## 8 KitchenQual 0 0 1 0.03 0 0 character 4 ## 9 SaleType 0 0 1 0.03 0 0 character 9 ## 10 PoolArea 2906 99.6 0 0 0 0 numeric 14 ## # … with 71 more rows Vejamos:\nMSZoning: Identifica a classificação geral de zoneamento da venda.\nSerá convertida para fator, variável nominal KitchenQual: Qualidade da cozinha\nSerá convertida para ordinal Utilities: Tipo de utilidade disponível\nSerá removida Functional: Funcionalidade doméstica\nSerá considerada como ordinal Exterior1st: revestimento Exterior em casa\nConvertida para fator, variável nominal Electrical: Sistema elétrico\nConvertida para fator, variável nominal SaleType: Tipo de venda\nConvertida para fator, variável nominal full \u0026lt;- full %\u0026gt;% mutate(MSZoning = ifelse(is.na(MSZoning), full$MSZoning %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last, MSZoning)) %\u0026gt;% mutate(MSZoning = as.factor(MSZoning)) %\u0026gt;% mutate(KitchenQual = ifelse(is.na(KitchenQual), full$KitchenQual %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last, KitchenQual)) %\u0026gt;% mutate(KitchenQual = as.integer(revalue(as.character(full$KitchenQual), Qualidade))) %\u0026gt;% select(-Utilities) %\u0026gt;% mutate(Exterior1st = ifelse(is.na(Exterior1st), full$Exterior1st %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last, Exterior1st)) %\u0026gt;% mutate(Exterior1st = as.factor(Exterior1st)) %\u0026gt;% mutate(Exterior2nd = ifelse(is.na(Exterior2nd), full$Exterior2nd %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last, Exterior2nd)) %\u0026gt;% mutate(Exterior2nd = as.factor(Exterior2nd)) %\u0026gt;% mutate(Electrical = ifelse(is.na(Electrical), full$Electrical %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last, Electrical)) %\u0026gt;% mutate(Electrical = as.factor(Electrical)) %\u0026gt;% mutate(SaleType = ifelse(is.na(SaleType ), full$SaleType %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last, SaleType )) %\u0026gt;% mutate(SaleType = as.factor(SaleType )) full[is.na(full$Functional),\u0026quot;Functional\u0026quot;] \u0026lt;- full$Functional %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last full$Functional = as.integer(revalue(full$Functional, c(\u0026#39;Sal\u0026#39;=0, \u0026#39;Sev\u0026#39;=1, \u0026#39;Maj2\u0026#39;=2, \u0026#39;Maj1\u0026#39;=3, \u0026#39;Mod\u0026#39;=4, \u0026#39;Min2\u0026#39;=5, \u0026#39;Min1\u0026#39;=6, \u0026#39;Typ\u0026#39;=7))) full[is.na(full$KitchenQual),\u0026quot;KitchenQual\u0026quot;] \u0026lt;- full$KitchenQual %\u0026gt;% table %\u0026gt;% sort %\u0026gt;% names %\u0026gt;% last %\u0026gt;% as.numeric() full$KitchenQual = as.integer(revalue(as.character(full$KitchenQual), Qualidade)) # full[is.na(full$Electrical),\u0026quot;Electrical\u0026quot;] \u0026lt;- 3 to_remove \u0026lt;- full %\u0026gt;% map(~table(.x) %\u0026gt;% length()) %\u0026gt;% .[.== 1] %\u0026gt;% names() full \u0026lt;- full %\u0026gt;% select(-one_of(to_remove)) Status da base no momento:\nfull %\u0026gt;% df_status(print_results = F) %\u0026gt;% as_tibble() %\u0026gt;% arrange(-p_na,-p_zeros, type) ## # A tibble: 79 x 9 ## variable q_zeros p_zeros q_na p_na q_inf p_inf type unique ## \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 SalePrice 0 0 1459 50.0 0 0 numeric 663 ## 2 PoolArea 2906 99.6 0 0 0 0 numeric 14 ## 3 3SsnPorch 2882 98.7 0 0 0 0 numeric 31 ## 4 LowQualFinSF 2879 98.6 0 0 0 0 numeric 36 ## 5 MiscVal 2816 96.5 0 0 0 0 numeric 38 ## 6 BsmtHalfBath 2744 94 0 0 0 0 numeric 3 ## 7 ScreenPorch 2663 91.2 0 0 0 0 numeric 121 ## 8 BsmtFinSF2 2572 88.1 0 0 0 0 numeric 272 ## 9 EnclosedPorch 2460 84.3 0 0 0 0 numeric 183 ## 10 HalfBath 1834 62.8 0 0 0 0 numeric 3 ## # … with 69 more rows Transformando o character para factor:\nfull %\u0026lt;\u0026gt;% mutate_if(is.character, as.factor) Transformando novamente nossa base de treino e de teste:\ntrain \u0026lt;- full[1:nrow(train),] %\u0026gt;% as.data.frame() test \u0026lt;- full[(nrow(train)+1):nrow(full),] %\u0026gt;% select(-SalePrice) %\u0026gt;% as.data.frame() # # Input Missing # train_miss_model = preProcess(train, \u0026quot;knnImpute\u0026quot;) # train = predict(train_miss_model, train) # test = predict(train_miss_model, test) # # train$SalePrice \u0026lt;- y Machine Learning com algorítmos de aprendizagem baseados em árvores Os métodos baseados em árvores fornecem modelos preditivos de alta precisão, estabilidade e facilidade de interpretação. Ao contrário dos modelos lineares, eles são capazes de lidar bem com relações não-lineares além de poderem ser adaptados para resolver tanto problemas de classificação quanto problemas de regressão.\nO Mãos à Obra, do Géron, continua sendo o livro prático de ML que mais indico pra quem quer sair do zero e chegar num modelo funcionando de verdade.\nAlgoritmos como árvores de decisão, random forest e “gradient boosting” estão sendo muito usados em todos os tipos de problemas de data science e é notável o uso desses algorítimos para resolver os desafios do Kaggle, como fiz também em outro desafio ao usar modelos baseados em árvore para estudar a sobrevivência de jogadores em partidas do PUBG. Para resolver este problema utilizaremos estes três algoritmos e ao final, pegando carona na seleção de variáveis para os algoritmos de árvore, será ajustado um modelo de regressão linear para compararmos e conferirmos a significância estatística de cada uma das variáveis.\nVarImp com Random Forest Um dos benefícios da floresta aleatória é o poder de lidar com grande conjunto de dados com maior dimensionalidade e identificar as variáveis a importância das variáveis, que pode ser uma característica muito útil porém deve ser feita com cautela.\nVeja uma reflexão (traduzida) da nota de Leo Breiman (Universidade da Califórnia em Berkeley)\n“Uma nota filosófica: RF é um exemplo de uma ferramenta que é útil para fazer análises de dados científicos; Mas os algoritmos mais inteligentes não substituem a inteligência humana e o conhecimento dos dados do problema; Pegue a saída de florestas aleatórias não como verdade absoluta, mas como suposições geradas por um computador inteligente que podem ser úteis para levar a uma compreensão mais profunda do problema.”\nO ajuste da árvore será feito com o pacote caret e o estudo de estimativas de erro foi definido como o Out of bag que remove a necessidade de um conjunto de teste pois é o erro médio de previsão em cada amostra de treinamento \\(x_i\\) , usando apenas as árvores que não tinham \\(x_i\\) em sua amostra de bootstrap.\nset.seed(1) control \u0026lt;- trainControl(method = \u0026quot;oob\u0026quot;,verboseIter = F) rfFit1 \u0026lt;- train(SalePrice ~. , data=train, method=\u0026quot;rf\u0026quot;, metric = \u0026quot;Rsquared\u0026quot;, trControl = control, preProcess = c(\u0026quot;knnImpute\u0026quot;) ) randomForest::varImpPlot(rfFit1$finalModel) rfFit1$finalModel$importance %\u0026gt;% as.data.frame %\u0026gt;% mutate(row = rownames(.)) %\u0026gt;% arrange(desc(IncNodePurity)) %\u0026gt;% as_tibble() ## # A tibble: 217 x 2 ## IncNodePurity row ## \u0026lt;dbl\u0026gt; \u0026lt;chr\u0026gt; ## 1 77.9 OverallQual ## 2 35.0 GrLivArea ## 3 14.8 YearBuilt ## 4 11.5 KitchenQual ## 5 9.75 TotalBsmtSF ## 6 9.29 GarageCars ## 7 6.74 `1stFlrSF` ## 8 6.33 GarageArea ## 9 5.02 ExterQualTA ## 10 4.04 BsmtFinSF1 ## # … with 207 more rows Após inspecionar a importância das variáveis vamos selecionar as seguintes variáveis:\nfull %\u0026lt;\u0026gt;% select( SalePrice , Neighborhood, OverallQual , GrLivArea , YearBuilt , KitchenQual, GarageCars , GarageArea , `1stFlrSF` , ExterQual , BsmtFinSF1 , FireplaceQu, BsmtQual , `2ndFlrSF` , CentralAir , GarageFinish, YearRemodAdd, FullBath, GarageYrBlt, Fireplaces , LotFrontage , BsmtUnfSF , TotalBsmtSF , BsmtFinType1, OpenPorchSF, GarageType , BsmtExposure, OverallCond , TotalBsmtSF , LotArea ) Portanto, vamos definir novamente o conjunto de dados de treino e de teste:\ntrain \u0026lt;- full[1:nrow(train),] %\u0026gt;% as.data.frame() test \u0026lt;- full[(nrow(train)+1):nrow(full),-1] %\u0026gt;% as.data.frame() Variáveis numéricas Após a seleção dessas variáveis, vamos entender como elas estão correlacionadas dois a dois com o coeficiente de correlação de pearson, exibindo a matrix em um Heatmap (ou mapa de calor ), que é uma representação gráfica de dados em que os valores individuais contidos em uma matriz representados como cores.\ncormat \u0026lt;- full %\u0026gt;% select(SalePrice, everything()) %\u0026gt;% select_if(is.numeric) %\u0026gt;% as.data.frame() %\u0026gt;% cor(use = \u0026quot;na.or.complete\u0026quot;) %\u0026gt;% melt cormat %\u0026gt;% ggplot( aes(reorder(Var1,value), reorder(Var2,value), fill=value))+ geom_tile(color=\u0026quot;white\u0026quot;)+ scale_fill_gradient2(low=\u0026quot;blue\u0026quot;, high=\u0026quot;red\u0026quot;, mid=\u0026quot;white\u0026quot;, midpoint=0, limit=c(-1,1), space=\u0026quot;Lab\u0026quot;, name=\u0026quot;Pearson\\nCorrelation\u0026quot;)+ theme_bw()+ theme(axis.text.x=element_text(angle=45, vjust=1, size=10, hjust=1))+ coord_fixed()+ labs(x=\u0026quot;\u0026quot;,y=\u0026quot;\u0026quot;) É possível notar que existem variáveis explicativas correlacionadas o que indica que a presença de algumas variáveis pode possivelmente interferir no ajuste final do modelo linear multivariado.\nVariáveis categóricas Já a relação das varáveis categóricas não podem ser calculada com o coeficiente de correlação calculado anteriormente, para avaliar como elas estão associadas será calculado a medida de associação V de Cramér. Novamente a matrix dos resultados serão novamente apresentados em um Heatmap (ou mapa de calor ) que foi inspirado neste post (neste post também é apresentada uma função para o cálculo da matrix, adaptei de forma que se tornasse mais geral e disponibilizei no meu github neste link).\n# Carrega funcao que calcula o V de Cramer: devtools::source_url(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/cv_test.R\u0026quot;) # Carrega a funcao que realiza as interações dos calculos dois a dois: devtools::source_url(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/interaction_all.R\u0026quot;) Veja:\ncvmat \u0026lt;- train %\u0026gt;% select_if(~!is.numeric(.x)) %\u0026gt;% as.data.table() %\u0026gt;% interaction_all(cv_test) %\u0026gt;% as_tibble() cvmat %\u0026gt;% ggplot( aes(variable_x, variable_y, fill=v_cramer))+ geom_tile(color=\u0026quot;white\u0026quot;)+ scale_fill_gradient2(low=\u0026quot;blue\u0026quot;, high=\u0026quot;red\u0026quot;, mid=\u0026quot;white\u0026quot;, midpoint=0, limit=c(-1,1), space=\u0026quot;Lab\u0026quot;, name=\u0026quot;Cramer\u0026#39;s V\u0026quot;)+ theme_bw()+ theme(axis.text.x=element_text(angle=45, vjust=1, size=10, hjust=1))+ coord_fixed()+ labs(x=\u0026quot;\u0026quot;,y=\u0026quot;\u0026quot;) Ajustando modelos Arvore de decisao O modelo de árvore de decisão já foi comentado e deixei algumas referências ao final do post portanto vejamos a seguir o ajusto no R. Segundo a documentação:\ncp: parâmetro de complexidade. No nosso caso isso significa que o \\(R^2\\) total deve aumentar em cp em cada etapa. O principal papel desse parâmetro é economizar tempo de computação removendo as divisões que obviamente não valem a pena. Essencialmente, informamos ao programa que qualquer divisão que não melhore o ajuste por cp provavelmente será eliminada por validação cruzada, e que, portanto, o programa não precisa buscá-la.\nPara pesquisa de grade existem duas maneiras de ajustar um algoritmo no pacote caret: permitir que o sistema faça isso automaticamente ou especificar o tuneGride manualmente onde cada parâmetro do algoritmo pode ser especificado como um vetor de valores possíveis. Confira o ajuste manual em R:\nset.seed(1) control \u0026lt;- trainControl(method = \u0026quot;cv\u0026quot;, number = 5,verboseIter = F) tunegrid \u0026lt;- expand.grid(cp=seq(0.001, 0.01, 0.001)) rpartFit2 \u0026lt;- train(y=train$SalePrice, x=train[,-1], method=\u0026quot;rpart\u0026quot;, trControl=control, tuneGrid=tunegrid, metric = \u0026quot;Rsquared\u0026quot; ) rpartFit2 ## CART ## ## 1460 samples ## 28 predictor ## ## No pre-processing ## Resampling: Cross-Validated (5 fold) ## Summary of sample sizes: 1169, 1169, 1168, 1168, 1166 ## Resampling results across tuning parameters: ## ## cp RMSE Rsquared MAE ## 0.001 0.1918932 0.7757730 0.1386651 ## 0.002 0.1943654 0.7690391 0.1410967 ## 0.003 0.2016485 0.7513005 0.1457213 ## 0.004 0.2029596 0.7462748 0.1457752 ## 0.005 0.2098812 0.7279462 0.1534384 ## 0.006 0.2090073 0.7291130 0.1539830 ## 0.007 0.2110066 0.7227211 0.1544402 ## 0.008 0.2120734 0.7198280 0.1555415 ## 0.009 0.2142488 0.7143975 0.1570535 ## 0.010 0.2148236 0.7126454 0.1575360 ## ## Rsquared was used to select the optimal model using the largest value. ## The final value used for the model was cp = 0.001. Podemos conferir os resultados novamente de maneira visual:\nrpart.plot(rpartFit2$finalModel, cex = 0.5) Gerando arquivo para submissão no kaggle:\nid %\u0026gt;% cbind(predict(rpartFit2, test) %\u0026gt;% exp) %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;Id\u0026quot;, \u0026quot;SalePrice\u0026quot;)) %\u0026gt;% write.csv(\u0026quot;rpartFit2.csv\u0026quot;,row.names = F) Bagging “Bagging” é usado quando desejamos reduzir a variação de uma árvore de decisão. Ela combina o resultado de vários modelos onde todas as variáveis são considerados para divisão um nó. Em R:\nset.seed(1) control \u0026lt;- trainControl(method = \u0026quot;cv\u0026quot;, number = 5,verboseIter = F) treebagFit \u0026lt;- train(y=train$SalePrice, x=train[,-1], method = \u0026quot;treebag\u0026quot;, metric = \u0026quot;Rsquared\u0026quot;, trControl=control ) treebagFit ## Bagged CART ## ## 1460 samples ## 28 predictor ## ## No pre-processing ## Resampling: Cross-Validated (5 fold) ## Summary of sample sizes: 1169, 1169, 1168, 1168, 1166 ## Resampling results: ## ## RMSE Rsquared MAE ## 0.1831872 0.7946059 0.1288626 Note que o \\(R^2\\) aumentou e o \\(RMSE\\) diminuiu após o uso desta técnica.\nResultados para enviar para o Kaggle:\nid %\u0026gt;% cbind(predict(treebagFit, test)%\u0026gt;% exp) %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;Id\u0026quot;, \u0026quot;SalePrice\u0026quot;)) %\u0026gt;% write.csv(\u0026quot;treebagFit.csv\u0026quot;,row.names = F) Random Forest A principal diferença entre “bagging” e o algoritmo Random Forest é que em randomForest, apenas um subconjunto de características é selecionado aleatoriamente em cada divisão em uma árvore de decisão enquanto que no bagging todos os recursos são usados.\nPara pesquisa de grade especificaremos um vetor com os possíveis valores, pois o default adotado para o parâmetro mtry é mtry = p/3 (Número de variáveis amostradas aleatoriamente como candidatos em cada divisão), onde p é o número de variáveis e pode ser que o modelo se ajuste melhor aos dados ao utilizar outro valor.\nVeja:\nset.seed(1) tunegrid \u0026lt;- expand.grid(mtry = seq(4, ncol(train) * 0.8, 2)) control \u0026lt;- trainControl(method = \u0026quot;cv\u0026quot;, number = 5,verboseIter = F) rfFit \u0026lt;- train(SalePrice ~. , data=train, method=\u0026quot;rf\u0026quot;, metric = \u0026quot;Rsquared\u0026quot;, tuneGrid=tunegrid, trControl=control ) rfFit ## Random Forest ## ## 1460 samples ## 28 predictor ## ## No pre-processing ## Resampling: Cross-Validated (5 fold) ## Summary of sample sizes: 1169, 1169, 1168, 1168, 1166 ## Resampling results across tuning parameters: ## ## mtry RMSE Rsquared MAE ## 4 0.1455656 0.8781772 0.09755474 ## 6 0.1417368 0.8817193 0.09435674 ## 8 0.1405084 0.8826370 0.09350712 ## 10 0.1395367 0.8834153 0.09290816 ## 12 0.1385338 0.8845102 0.09181049 ## 14 0.1386865 0.8840165 0.09223527 ## 16 0.1381776 0.8846283 0.09155563 ## 18 0.1384532 0.8837305 0.09222536 ## 20 0.1380863 0.8840803 0.09173754 ## 22 0.1383788 0.8835938 0.09189772 ## ## Rsquared was used to select the optimal model using the largest value. ## The final value used for the model was mtry = 16. Note que o \\(R^2\\) aumentou e o \\(RMSE\\) apresentou resultados ainda mais satisfatórios.\nVeja visualmente a importância de ada variável:\nrandomForest::varImpPlot(rfFit$finalModel) Resultados para enviar para o Kaggle:\nid %\u0026gt;% cbind(predict(rfFit, test) %\u0026gt;% exp) %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;Id\u0026quot;, \u0026quot;SalePrice\u0026quot;)) %\u0026gt;% write.csv(\u0026quot;rfFit.csv\u0026quot;,row.names = F) GBM Diferentemente do “bagging”, o “boosting” é uma técnica de ensemble (conjunto) na qual os preditores não são feitos independentemente, mas sequencialmente. Na imagem a seguir é possível ver uma representação visual dessa diferença:\nA imagem foi obtida neste artigo: Gradient Boosting from scratch, recomendo a leitura pois da uma boa intuição de como o algoritmo funciona. Se quiser entender bagging, boosting e stacking com mais profundidade, o Ensemble Methods for Machine Learning explica bem o que acontece por trás de algoritmos como o próprio GBM e o XGBoost.\nPara a pesquisa de grade vamos permitir que o sistema faça isso automaticamente configurando apenas o tuneLength para indicar o número de valores diferentes para cada parâmetro do algoritmo.\nset.seed(1) control \u0026lt;- trainControl(method = \u0026quot;cv\u0026quot;, number = 5,verboseIter = F) gbmFit \u0026lt;- train(SalePrice~.,data=train, method = \u0026quot;gbm\u0026quot;, trControl=control, tuneLength=5, metric = \u0026quot;Rsquared\u0026quot;, verbose = FALSE ) gbmFit ## Stochastic Gradient Boosting ## ## 1460 samples ## 28 predictor ## ## No pre-processing ## Resampling: Cross-Validated (5 fold) ## Summary of sample sizes: 1169, 1169, 1168, 1168, 1166 ## Resampling results across tuning parameters: ## ## interaction.depth n.trees RMSE Rsquared MAE ## 1 50 0.1736970 0.8346902 0.12145158 ## 1 100 0.1474386 0.8663694 0.10371271 ## 1 150 0.1400060 0.8775141 0.09804851 ## 1 200 0.1381902 0.8803999 0.09607709 ## 1 250 0.1375854 0.8817130 0.09502881 ## 2 50 0.1511051 0.8640075 0.10557294 ## 2 100 0.1379357 0.8815852 0.09546142 ## 2 150 0.1360260 0.8846503 0.09326628 ## 2 200 0.1355702 0.8852090 0.09248558 ## 2 250 0.1362827 0.8841734 0.09254710 ## 3 50 0.1434808 0.8743589 0.09910961 ## 3 100 0.1363881 0.8838715 0.09355652 ## 3 150 0.1346606 0.8868808 0.09163759 ## 3 200 0.1339427 0.8880370 0.09062153 ## 3 250 0.1336666 0.8886732 0.08979366 ## 4 50 0.1376575 0.8824442 0.09516571 ## 4 100 0.1334392 0.8884173 0.09192150 ## 4 150 0.1330866 0.8890336 0.09156893 ## 4 200 0.1334706 0.8886198 0.09096598 ## 4 250 0.1335809 0.8884950 0.09101981 ## 5 50 0.1384852 0.8813449 0.09535954 ## 5 100 0.1350803 0.8863344 0.09231165 ## 5 150 0.1340246 0.8878172 0.09112111 ## 5 200 0.1342892 0.8874590 0.09088714 ## 5 250 0.1349331 0.8867525 0.09104875 ## ## Tuning parameter \u0026#39;shrinkage\u0026#39; was held constant at a value of 0.1 ## ## Tuning parameter \u0026#39;n.minobsinnode\u0026#39; was held constant at a value of 10 ## Rsquared was used to select the optimal model using the largest value. ## The final values used for the model were n.trees = 150, interaction.depth = ## 4, shrinkage = 0.1 and n.minobsinnode = 10. Note que este foi o modelo que apresentou os melhores resultados quanto só \\(R^2\\) e ao \\(RMSE\\) em comparação com os outros modelos.\nSubmissão para Kaggle:\nid %\u0026gt;% cbind(predict(gbmFit, test) %\u0026gt;% exp) %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;Id\u0026quot;, \u0026quot;SalePrice\u0026quot;)) %\u0026gt;% write.csv(\u0026quot;gbmFit.csv\u0026quot;, row.names = F) Regressão Linear Por fim faremos o ajuste de um modelo de regressão linear multivariado utilizando o pacote caret.\nUtilizaremos validação cruzada separando nossa amostra em 5 e utilizaremos o método lmStepAIC que realiza a seleção do modelo escalonado pelo critério de informação de Akaike - AIC.\nset.seed(1) control \u0026lt;- trainControl(method = \u0026quot;cv\u0026quot;, number = 5,verboseIter = F) lmFit \u0026lt;- train(SalePrice~.,data=train, method = \u0026quot;lmStepAIC\u0026quot;, trControl=control, metric = \u0026quot;Rsquared\u0026quot;,trace=F ) lmFit ## Linear Regression with Stepwise Selection ## ## 1460 samples ## 28 predictor ## ## No pre-processing ## Resampling: Cross-Validated (5 fold) ## Summary of sample sizes: 1169, 1169, 1168, 1168, 1166 ## Resampling results: ## ## RMSE Rsquared MAE ## 0.147716 0.8632513 0.09574552 Note que o ajuste do modelo se apresenta de maneira satisfatória com \\(R^2\\) e \\(RMSE\\) semelhantes aos modelos de bagging e boosting e além disso, diferente dos modelos baseados em árvore, com este ajuste é possível notar a significância estatística de cada parâmetro ajustado, o que possibilita tanto o uso tanto como modelo preditivo quanto como modelo descritivo. Veja:\nggcoef( lmFit$finalModel, #O modelo a ser conferido vline_color = \u0026quot;red\u0026quot;, #Reta em zero errorbar_color = \u0026quot;blue\u0026quot;, #Cor da barra de erros errorbar_height = .25, shape = 18, #Altera o formato dos pontos centrais size=2, #Altera o tamanho do ponto color=\u0026quot;black\u0026quot;, exclude_intercept = TRUE, #Altera a cor do ponto mapping = aes(x = estimate, y = term, size = p.value))+ scale_size_continuous(trans = \u0026quot;reverse\u0026quot;)+ #Essa linha faz com que inverta o tamanho theme_bw() Note que o intercepto \\(\\beta_0\\) foi retirado da imagem pois é muito superior aos demais coeficientes. Note também que \\(\\beta_i\\) informa quão sensível é \\(y\\), no caso log(SalePrice) às variações de cara umas das \\(x_{i,j}\\) variáveis explicativas. Mais concretamente, se \\(x_{i,j}\\) aumenta em uma unidade, o valor de \\(y\\) varia em \\(\\beta_1\\) unidades.\nUma rápida Análise dos Resíduos:\nlmFit$finalModel %\u0026gt;% autoplot(which = 1:2) + theme_bw() É possível notar que parece haver alguns outliers em ambas as figuras. Na primeira é possível notar uma nuvem de pontos aleatórios em torno de zero porém na segunda figura nota-se que alguns valores não estão de acordo com os quantils teóricos de uma distribuição normal, o que pode prejudicar nossa interpretação dos coeficientes do modelo. Vamos encerrar o modelo por aqui mesmo e ver como ele se sai na competição do Kaggle, preparando a submissão:\nid %\u0026gt;% cbind(predict(lmFit, test) %\u0026gt;% exp ) %\u0026gt;% `colnames\u0026lt;-`(c(\u0026quot;Id\u0026quot;, \u0026quot;SalePrice\u0026quot;)) %\u0026gt;% write.csv(\u0026quot;lmFit.csv\u0026quot;,row.names = F) O score obtido com esta submissão no Kaggle foi muito próximo dos modelos baseados e árvore e o tempo computacional para este ajuste foi bem menor.\nComparando ajustes Vejamos a seguir uma comparação entre estes modelos com as funções fornecidas pelo pacote `caret:.\nresamps \u0026lt;- resamples(list(rpart = rpartFit2, treebag = treebagFit, rf = rfFit, gbm = gbmFit, lm = lmFit )) bwplot(resamps) Com este gráfico é possível notar que o modelo de regressão linear múltipla apresentou resultados semelhantes aos de bagging e boosting.\nÉ importante frisar que a maneira como as variáveis foram selecionadas para o modelo de regressão linear múltipla através da importância das variáveis obtida com o modelo randomForest não é um padrão e existem diversos outros modos estatísticos de se de determinar a significância e a relação das variáveis para o modelo.\nUm possível problema neste método é que não detecta a multicolinearidade, que ocorre quando as variáveis explicativas estão fortemente correlacionadas entre si e a análise de regressão linear pode ficar confusa e desprovida de significado, pois há dificuldade em distinguir o efeito de uma ou outra variável explicativa sobre a variável resposta \\(Y\\) devido à variâncias muito elevadas ou sinais inconsistentes.\nEssa proposta de aprender se divertindo e de maneira produtiva me deixa muito empolgado, espero que tenham se divertido como eu me diverti fazendo este post!\nPara outro exemplo de modelagem preditiva, desta vez prevendo a qualidade do sono com árvores e outros algoritmos, veja este post.\nPerguntas frequentes Qual dataset foi usado neste estudo de modelos baseados em árvores?\nFoi usado o conjunto de dados Ames Housing, do desafio House Prices: Advanced Regression Techniques do Kaggle, com 79 variáveis explicativas para prever o preço de venda de casas em Ames, Iowa.\nQual algoritmo apresentou o melhor desempenho entre os testados?\nO GBM (Gradient Boosting) apresentou os melhores resultados, com Rsquared de 0,889 e RMSE de 0,1331, superando árvore de decisão, bagging, Random Forest e regressão linear stepwise.\nQuais variáveis mais influenciam o preço de venda das casas segundo o Random Forest?\nSegundo o gráfico de importância de variáveis (VarImp) do Random Forest, OverallQual foi a variável mais relevante, seguida por GrLivArea, YearBuilt e KitchenQual.\nReferências: DataCamp Course:Machine Learning with Tree-Based Models in R Data Science for Business Learn ML Algorithms by coding: Decision Trees DataCamp Tutorials: Decision Trees in R The caret Package - Max Kuhn Um tutorial completo sobre modelagem baseada em árvores de decisão (códigos R e Python) Tuning Machine Learning Models Using the Caret R Package Gradient Boosting from scratch Tune Machine Learning Algorithms in R (random forest case study) Random Forests - Leo Breiman and Adele Cutler An Introduction to Recursive Partitioning Using the RPART Routines - CRAN ","date":"31 de agosto de 2018","externalUrl":null,"permalink":"/post/2018-08-31-modelos-em-arvore/","section":"Posts","summary":" Kaggle Segundo o Wikipédia: “Kaggle é a maior comunidade mundial de cientistas de dados e machine learning.” Aprendo muito estudando as resoluções de alguns competidores pois lá é possível conferir tanto as metodologias utilizadas pelos competidores quando os códigos e é notável o cuidado dos participantes para que seja possível a reprodutibilidade dos resultados, o que pode impulsionar o aprendizado.\nO Kaggle trabalha com a ideia de gamificação, que é um assunto do qual já escrevi em um post sobre gamificação e porque aprender R é tão divertido e gosto deste conceito de se criar jogos para motivar e engajar as pessoas em atividades profissionais e a ideia de se estar em um jogo possibilita doses de motivação especialmente a quem gosta de competir.\n","title":"Modelos baseados em árvore no R: desafio Ames Housing do Kaggle","type":"post"},{"content":"","date":"28 de julho de 2018","externalUrl":null,"permalink":"/tags/bayes/","section":"Tags","summary":"","title":"Bayes","type":"tags"},{"content":"","date":"28 de julho de 2018","externalUrl":null,"permalink":"/tags/jags/","section":"Tags","summary":"","title":"Jags","type":"tags"},{"content":" Modelagem estatística e as duas grandes escolas de inferência Através da modelagem estatística é possível tomar decisões sobre diversos assuntos de interesse como por exemplo na análise de risco de crédito, previsões de quantidade de chuva em um dado local, estimativas de erros ou falhas de um novo produto ou serviço além de diversas áreas como na Educação, Economia, nas Ciências Sociais, Saúde etc.\nMuitas vezes os parâmetros das distribuições em estudo podem ser desconhecidos e existe o desejo de se inferir sobre eles. Existem duas grandes escolas de inferência: a clássica e a bayesiana. A clássica trata esses parâmetros como quantidades fixas e não atribui distribuição a eles, a estimação desses parâmetros é dada através da função de verossimilhança, enquanto que na escola bayesiana atribui-se uma distribuição, chamada de distribuição a priori, ao conjunto de parâmetros desconhecidos quantificando a sua crença sobre esse conjunto e a estimação dos parâmetros é dada através da distribuição à posteriori, que é proporcional ao produto da função de verossimilhança com a distribuição a priori.\nSe essa diferença entre as duas escolas ainda não fez muito sentido na prática, o Statistical Rethinking foi o livro que mais me ajudou a entender bayesiana como raciocínio e não só como conta.\nO interesse pela modelagem estatística através da abordagem bayesiana surgiu a partir de um projeto de iniciação científica quando cursava o 6º período do curso de Graduação em Estatística que tinha como objetivo o cálculo e apresentação de estatísticas descritivas para ajudar uma pesquisadora. Após obter os resultados da análise exploratória e descritiva, notei, junto com meu orientador, que havia possibilidade de dar continuidade ao estudo a partir de uma abordagem estatística mais elaborada. Sendo assim, outro projeto de iniciação científica foi iniciado em seguida com a finalidade de me preparar para utilizar um modelo linear hierárquico bayesiano sob os dados disponibilizados pela pesquisadora em minha monografia.\nTL;DR\nO post implementa na mão, via amostrador de Gibbs, um modelo linear bayesiano com priori não informativa, usando 30.000 simulações e burn-in de 15.000. Para dados simulados (N=1000, com β0=1, β1=0,5 e τ=2), as estimativas bayesianas ficaram muito próximas dos valores reais e dos obtidos pelo modelo clássico via lm(). Para dados reais (dataset cars), o modelo bayesiano estimou β0=8,2839 e β1=0,1656, resultados praticamente idênticos aos do ajuste clássico por mínimos quadrados. Caso tenha interesse em conferir o projeto com o estudo sobre modelos hierárquicos bayesianos, disponibilizei os resultados e os códigos em meu github neste repositório. Neste post farei uma breve introdução sobre o ajuste de um modelo linear bayesiano simples e os resultados obtidos (utilizando uma distribuição a priori não informativa). Os resultados obtidos serão comparados com os resultados obtidos com o ajuste de um modelo de regressão linear através da abordagem clássica.\nDistribuição a priori Para o estudo, optou-se pela utilização de valores elevados para variância a priori (também consideradas como “não informativas”, fazendo uma analogia à modelos clássicos) obtendo ajustes que atribuem maior importância à informação provinda da amostra.\nPortanto com valores elevados para variância da distribuição a priori (consideradas como “não informativas”) foram obtida a distribuição a posteriori de um parâmetro \\(\\theta\\) que contém toda a informação probabilística a respeito deste parâmetro e quando a forma analítica dessa distribuição é conhecida o gráfico da fdp pode ilustrar o comportamento probabilístico do parâmetro de interesse e auxiliar em alguma tomada de decisão, porém, quando a forma analítica não é conhecida ou é muito custosa de ser obtida, pode-se recorrer a métodos de simulação tais como os métodos MCMC.\nAmostrador de Gibbs - método MCMC Com os avanços dos métodos de MCMC, surgiu o amostrador de Gibbs, proposto por @GemanGeman e tornou-se popular por @GelfandSmith, falo um pouco mais sobre o algoritmo no texto do projeto.\nComo a convergência ocorre após o aquecimento (ou burn-in), é comum usar os valores de \\(\\theta^{(a)}\\), \\(\\theta^{(a+t)}\\), \\(\\theta^{(a+2t)}\\),… para compor a amostra de \\(\\theta\\), sendo \\(a-1\\) o número de iterações iniciais do aquecimento e \\(t\\) o espaçamento utilizado para diminuir a autocorrelação dos parâmetros. Maiores detalhes podem ser vistos em @Gamerman06. Para uma abordagem alternativa usando um software dedicado a MCMC, também escrevi um post sobre como ajustar modelos bayesianos com JAGS.\nAo que interessa O objetivo deste post é apresentar e comparar os resultados do ajuste de um modelo linear bayesiano simples utilizando uma distribuição a priori não informativa com o modelo de regressão linear simples para dados simulados e para dados reais.\nDiversas funções foram criadas ao longo o estudo para conferir o comportamento das cadeias geradas e os resultados do ajuste do modelo, aproveitarei essas funções para este post importando do repositório no github da seguinte maneira:\npath_to_dep \u0026lt;- \u0026quot;https://raw.githubusercontent.com/gomesfellipe/projeto_modelos_hierarquicos_bayesianos/master/dependencies.R\u0026quot; devtools::source_url(path_to_dep, encoding=\u0026quot;UTF-8\u0026quot;) Ajuste do modelo para dados simulados Suponha então um exemplo em que a população de interesse tenha distribuição normal com média \\(\\beta_0 + \\beta_1 X\\), sendo \\(\\beta_0\\) e \\(\\beta_1\\) desconhecidos e variância \\(\\sigma^2\\) desconhecida. Seja \\(\\tau=\\frac{1}{\\sigma^2}\\) o parâmetro chamado de precisão.\nO parâmetro \\(\\beta_0\\) é conhecido como intercepto ou coeficiente linear e o \\(\\beta_1\\) como coeficiente angular. Além disso, suponha que as unidades dessa população sejam iid. Dessa forma, tem-se que as unidades dessa população tem a seguinte distribuição:\n\\[ Y_i \\stackrel{iid}{\\sim} N(\\beta_0 + \\beta_1 X_i,\\frac{1}{\\tau}), \\]\nonde \\(i=1,...,N\\).\nPara o estudo do modelo primeiramente foi utilizado um conjunto de dados simulados utilizando uma amostra de tamanho \\(N=1000\\) e com os seguintes parâmetros “desconhecidos” dos quais desejamos estimar: \\(\\beta_0 = 1\\), \\(\\beta_1 = 0,5\\), \\(\\tau = 2\\). A amostra será simulada segundo a variável aleatória: \\(X_i ~ N(0,1)\\) e em seguida os parâmetros deste modelo, denotados por \\(\\theta = (\\beta_0, \\beta_1, \\tau)\\) foram estimados usando o paradigma Bayesiano.\nGerando a amostra A amostra que foi simulada foi obtida da seguinte maneira:\n# Amostra que sera utilizada: set.seed(12) n \u0026lt;- 1000 # N=1000 b0 \u0026lt;- 1 # \\beta_0 = 1 b1 \u0026lt;- 0.5 # \\beta_1 = 0,5 tau \u0026lt;- 2 # \\tau = 2 e x \u0026lt;- rnorm(n) # X_i ~ N(0,1), logo: y \u0026lt;- b0 + b1 * x + rnorm(n,0,sqrt(1/tau)) Obtendo-se uma amostra de tamanho \\(n\\), pode-se inferir sob os parâmetros desconhecidos \\(\\theta = (\\beta_0, \\beta_1, \\tau)\\) através da distribuição a posteriori e para obter essa distribuição faz-se necessário calcular a função de verossimilhança, que pode ser obtida da seguinte forma:\n\\[ p(y| \\beta_0, \\beta_1 , \\tau) =\\prod^n_{i=1} p(y_i | \\beta_0, \\beta_1, \\tau ) \\]\nportanto\n\\[ p(y| \\beta_0, \\beta_1 , \\tau) = \\prod_{i=1}^n \\frac{ \\sqrt{\\tau} }{ \\sqrt{2\\pi} } exp { - \\frac{\\tau}{2} ( y_i - \\beta_0 - \\beta_1 x_i )^2 } \\]\nonde \\(y = (y_1, ..., y_n)\\) é a amostra coletada. O valor p para o teste de Shapiro para conferir a suposição de normalidade da variável resposta foi de 0.6181791 enquanto que o valor p para conferir a normalidade da variável explicativa foi de 0.7413229.\nDistribuição a priori Durante o estudo diversos valores os parâmetros a priori foram selecionados para que fosse possível avaliar a sensibilidade da qualidade da escolha da distribuição priori, aqui será apresentado os resultados obtidos com valores elevados para variância a priori (também consideradas como “não informativas”, fazendo uma analogia à modelos clássicos) que ajusta o modelo atribuindo maior importância à informação provinda da amostra.\nConsidere a priori que os parâmetros sejam independentes e que\n\\[ \\beta_0 \\sim N(m_0,\\sigma_0^2), \\\\ \\beta_1 \\sim N(m_1,\\sigma_1^2) \\mbox{ e } \\\\ \\tau \\sim G(a,b). \\]\nPortanto, para a estimação foram utilizados os seguintes hiperparâmetros : \\(m_0 = m_1 = 0\\), \\(\\sigma_0^2 = \\sigma_1^2 = 100\\), \\(a=0,1\\) e \\(b=0,1\\)\nNo R:\n#Parametros para b0 ~ N(mu0, sig0) mu0 \u0026lt;- 0 sig0 \u0026lt;- 1000 #Parametros para b1 ~ N(mu1, sig1) mu1 \u0026lt;- 0 sig1 \u0026lt;- 1000 #Parametros para tau ~ G(a,b) a \u0026lt;- 0.1 b \u0026lt;- 0.1 Dessa forma, tem-se que a distribuição conjunta a priori possui a seguinte forma:\n\\[ p(\\beta_0, \\beta_1 , \\tau) \\propto exp\\Big\\{-\\frac{1}{2\\sigma_0^2}( \\beta_0 - m_0)^2\\Big\\} exp\\Big\\{-\\frac{1}{2\\sigma_1^2}( \\beta_1 - m_1)^2\\Big\\} \\tau^{a-1}exp \\{-b \\tau\\}. \\]\nDistribuição a posteriori Combinando a função de verossimilhança com a distribuição a priori, obtêm-se a distribuição a posteriori que é proporcional a:\n\\[ p(\\beta_0, \\beta_1 , \\tau|y) \\propto \\tau^{\\frac{n}{2}+a-1} exp \\left\\{ -\\frac{\\tau}{2} \\sum^n_{i=1} (y_i - \\beta_0 - \\beta_1 x_i)^2 - b\\tau - \\frac{1}{2\\sigma_0^2}(\\beta_0-m_0)^2 \\right\\} \\times exp\\left\\{- \\frac{1}{2\\sigma_1^2}(\\beta_1-m_1)^2 \\right\\} . \\]\nNote que essa distribuição é multivariada e não possui forma analítica conhecida. Sendo assim, recorre-se aos métodos de MCMC para se obter amostras dessa distribuição. E então faz-se necessário obter as DCCP de \\(\\beta_0\\), \\(\\beta_1\\) e \\(\\tau\\).\nImplementando o amostrador de Gibbs O tamanho da cadeia foi de 30000 simulações e o burn-in (ou amostra de aquecimento) utilizado considerada após o ajuste foi de 15000. no R:\nnsim \u0026lt;- 3*10000 burnin \u0026lt;- nsim / 2 cadeia.b0 \u0026lt;- rep(0,nsim) cadeia.b1 \u0026lt;- rep(0,nsim) cadeia.tau \u0026lt;- rep(0,nsim) # Chutes iniciais: cadeia.b0[1] \u0026lt;- 0 cadeia.b1[1] \u0026lt;- 0 cadeia.tau[1] \u0026lt;- 1 Calculos para implementar o algoritimo na mão Para a implementação do algoritmo, fez-se necessário o cálculo das distribuições condicionais completas a posteriori (DCCP), primeiramente veja os resultados obtidos para \\(\\tau\\):\nDCCP de \\(\\tau\\): \\[ \\tau|y_1, ...,y_n,\\beta_0, \\beta_1 \\sim Gama ( \\frac{n}{2}+a,b+\\frac{1}{2} \\sum^n_{i=1}(y_i-\\beta_0-\\beta_1 x_i)^2 ) \\]\nEm seguida, veja o resultado obtido para \\(\\beta_0\\), o coeficiente linear da reta, isto é, a altura em que a reta de regressão intercepta o eixo dos \\(Y\\)’s:\nDCCP de \\(\\beta_0\\): \\[ \\beta_0 | y_1,...,y_n , \\tau,\\beta_1 \\sim N(\\dfrac{(\\tau\\sum^n_{i=1}y_i - \\tau\\beta_1\\sum^n_{i=1}x_i +\\frac{m_0}{\\sigma_0^2})}{ \\tau n + \\frac{1}{\\sigma_0^2}}, (n\\tau + \\frac{1}{\\sigma_0^2} )^{-1}) \\]\nPor fim, veja o resultado obtido para \\(\\beta_1\\), é o coeficiente angular da reta, ou seja, é o a variação esperada na variável \\(Y\\) quando a variável explicativa é acrescida de 1 unidade:\nDCCP de \\(\\beta_1\\): \\[ \\beta_1 | y_1,...,y_n , \\tau,\\beta_0 \\sim N(\\frac{\\tau\\sum^n_{i=1}x_i y_i - \\tau\\beta_0\\sum^n_{i=1}x_i + \\frac{m_1}{\\sigma_1^2}}{\\tau \\sum^n_{i=1}x_i^2 + \\frac{1}{\\sigma_1^2}}, ( \\tau \\sum^n_{i=1}x_i^2 + \\frac{1}{\\sigma_1^2} )^{-1}) \\]\nAgora que todas as distribuições condicionais completas estão calculadas o algorítimo já pode ser implementado, no R foi feito da seguinte maneira: (note que as linhas que foram comentadas executariam uma barra de carregamento, com ilustrado em seguida)\n# pb \u0026lt;- txtProgressBar(min = 0, max = nsim, style = 3) # iniciando barra de processo for (k in 2:nsim){ #Cadeia tau cadeia.tau[k] \u0026lt;- rgamma(1, (n/2) + a, b + (sum((y - cadeia.b0[k-1] - (cadeia.b1[k-1]*x))^2)/2)) # Cadeia B0 c0 \u0026lt;- (n*cadeia.tau[k]) + (1/sig0) m0 \u0026lt;- (cadeia.tau[k]*sum(y) - (cadeia.tau[k]*cadeia.b1[k-1]*sum(x)) + (mu0/sig0))/c0 cadeia.b0[k] \u0026lt;- rnorm(1, m0, 1/sqrt(c0)) # Cadeia B1 c1 \u0026lt;- (sum(x^2)*cadeia.tau[k]) + (1/sig1) m1 \u0026lt;- ((cadeia.tau[k]*sum(x*y)) - (cadeia.tau[k]*cadeia.b0[k]*sum(x)) + (mu1/sig1))/c1 cadeia.b1[k] \u0026lt;- rnorm(1, m1, 1/sqrt(c1)) # setTxtProgressBar(pb, k) }# ;close(pb) #Encerrando barra de processo Resultados da cadeia A seguir definiremos a variável inds que indica os valores após a amostra de aquecimento (ou burn-in), a variável real que contém os valores reais utilizados para gerar a amostra para conferir se o modelo foi capaz de recuperá-los, os nomes dos parâmetros e os resultados das cadeias foram agregados em uma matriz:\n# Juntando resultados: inds \u0026lt;- seq(burnin, nsim) # Definindo os indices real \u0026lt;- c(b0, b1, tau) name \u0026lt;- c(expression(beta[0]), expression(beta[1]), expression(tau)) results \u0026lt;- cbind(cadeia.b0, cadeia.b1, cadeia.tau) %\u0026gt;% as.data.frame() %\u0026gt;% .[inds, ] %T\u0026gt;% head Histograma e densidade A figura abaixo apresenta os histogramas junto com as densidades de três cadeias obtidas ao se inicializar o amostrador em pontos diferentes de todos os parâmetros contidos em \\(\\theta\\) e uma linha vermelha indicará o valor do real parâmetro utilizado para estimar a cadeia.\ng1 \u0026lt;- hist_den(results[,1],name = name[1], p = real[1]) g2 \u0026lt;- hist_den(results[,2],name = name[2], p = real[2]) g3 \u0026lt;- hist_den(results[,3],name = name[3], p = real[3]) grid.arrange(g1,g2,g3,ncol=1) Cadeia A figura abaixo apresenta os traços das cadeias dos parâmetros amostrados exibindo o intervalo de credibilidade com a linha pontilhada em azul e o valor verdadeiro do parâmetro em vermelho. Note que há indícios de convergência.\n# Cadeia cadeia(results, name, real) é possível notar que todos os intervalos de credibilidade contêm o parâmetro populacional real utilizado para gerar a amostra.\nAutocorrelação A figura abaixo apresenta os gráficos de autocorrelação, que indicam se houve a influência dos “valores vizinhos” dos parâmetros amostrados. Note que parece haver independência entre as interações.\n# ACF FAC(results) é possível notar que nenhuma das cadeias apresentaram estimativas autocorrelacionada\nEstimativas Agora que já foi verificado que a cadeia se comportou de maneira satisfatória, veja os resultados obtidos sobre as estimativas dos parâmetros através do algoritmo. apresenta os resumos a posteriori dos parâmetros amostrados.\ncoef \u0026lt;- coeficientes(results, real = real) %\u0026gt;% as.data.frame() print(coef) ## Média Desv. Pad. IC inf IC sup Real ## b0 1.0244 0.0230 0.9792 1.0697 1.0 ## b1 0.4933 0.0241 0.4464 0.5409 0.5 ## tau 1.9001 0.0850 1.7371 2.0695 2.0 Como se trata de uma amostra simulada é possível comparar as estimativas com os valores reais que geraram a amostra e os valores estão muito próximos da média (todos eles estão incluídos no intervalo de credibilidade).\nComparando com o modelo linear clássico Agora que os resultados sob o paradigma bayesiano já foram conferidos será ajustado um modelo de regressão linear simples pelo método dos mínimos quadrados através da função lm() sob o paradigma clássico para comparar com os resultados de um modelo de regressão linear simples sob o paradigma bayesiano utilizando os resultados calculados.\n# Reta do modelo classico plot(x, y) modelo.classico \u0026lt;- lm(y ~ 1 + x) a.classico \u0026lt;- modelo.classico$coefficients[1] b.classico \u0026lt;- modelo.classico$coefficients[2] abline(a \u0026lt;- a.classico, b = b.classico, col = \u0026quot;blue\u0026quot;) O modelo estimado para estes dados sob o paradigma da inferência clássica foi o seguinte: \\(\\hat{y} = 1.0245 x + 0,4933\\), o que mostra que as estimativas de \\(\\beta_0\\) e \\(\\beta_1\\) foram muito parecidas com as estimativas sob o paradigma da inferência bayesiana.\n# Reta do modelo bayesiano plot(x, y) a.bayes \u0026lt;- mean(results[, 1]) b.bayes \u0026lt;- mean(results[, 2]) abline(a = a.bayes, b = b.bayes, col = \u0026quot;red\u0026quot;) A figura apresenta o gráfico de dispersão entre as variáveis da amostra simulada e as retas dos ajustes de ambos os modelos:\nlibrary(stringr) library(ggplot2) library(ggExtra) # Texto da imagem text.classico \u0026lt;- str_c(\u0026quot;Modelo Classico: \u0026quot;,\u0026quot;y = \u0026quot;,round(a.classico,4),\u0026quot; x + \u0026quot;,round(b.classico,4)) text.bayes \u0026lt;- str_c(\u0026quot;Modelo Bayesiano: \u0026quot;,\u0026quot;y = \u0026quot;,round(a.bayes,4),\u0026quot; x + \u0026quot;,round(b.bayes,4)) # Gerando o e ambos: cbind(y, x) %\u0026gt;% as.data.frame %\u0026gt;% ggplot(aes(y = y, x = x)) + geom_point() + geom_smooth(method = \u0026quot;lm\u0026quot;, se = F, col = \u0026quot;red\u0026quot;) + theme_classic() + geom_abline(slope = b.bayes, intercept = a.bayes, col = \u0026quot;blue\u0026quot;) + labs(title = \u0026quot;\u0026quot;, x = \u0026quot;Covariável\u0026quot;, y = \u0026quot;Reposta\u0026quot;) Agora que os resultados no algoritmo já foram conferidos e avaliados de maneira satisfatória utilizando os dados simulados, é a vez de fazer o ajuste para dados reais.\nAjuste do modelo para dados reais O conjunto de dados que será utilizado como exemplo foi disponibilizado por @Ezekiel_cars e hoje faz parte do conjunto de banco de dados nativos do R (a base de dados pode ser obtida ao escrever cars no console). Os dados informam a velocidade dos carros e as distâncias tomadas para parar, esses dados foram registrados na década de 1920 e são de grande utilidade didática até os dias de hoje.\nConsidere que deseja-se modelar a velocidade dos carros de acordo com as distâncias tomadas para parar, portanto a variável resposta será a velocidade e a variável explicativa do modelo será a distância tomada para parar.\nAmostra utilizada y \u0026lt;- cars$speed x \u0026lt;- cars$dist n \u0026lt;- nrow(cars) o valor p para o teste de Shapiro para conferir a suposição de normalidade da variável resposta foi de 0.4576319 enquanto que o valor p para conferir a normalidade da variável explicativa foi de 0.0390997\nDistribuição a priori Serão utilizados os mesmos valores que foram propostos na simulação como hiperparametros e chutes iniciais para a cadeia, o código usado foi exatamente o mesmo.\nResultados da cadeia Definiremos novamente a variável inds que indica os valores após a amostra de aquecimento (ou burn-in), desta vez não haverá a variável real pois não conhecemos os valores reais utilizados para gerar a amostra para conferir se o modelo foi capaz de recuperá-los. Desta vez utilizaremos a variável classico, que guarda os valores obtidos com o ajuste do modelo linear pela abordagem clássica.\n# Juntando resultados: inds \u0026lt;- seq(burnin, nsim) # Definindo os indices results \u0026lt;- cbind(cadeia.b0, cadeia.b1, cadeia.tau) %\u0026gt;% as.data.frame() %\u0026gt;% .[inds, ] classico \u0026lt;- c(coefficients(lm(cars)), 1 / var(lm(cars)$residuals)) name \u0026lt;- c(expression(beta[0]), expression(beta[1]), expression(tau)) Histograma e densidade A figura abaixo exibe os histogramas com as densidades de três cadeias obtidas ao se iniciar o amostrador em pontos diferentes de todos os parâmetros \\(\\theta\\) mas dessa vez sem a linha vermelha que indicava o valor do parâmetro real pois agora ele é desconhecido.\ng1 \u0026lt;- hist_den(results[, 1], name = name[1]) g2 \u0026lt;- hist_den(results[, 2], name = name[2]) g3 \u0026lt;- hist_den(results[, 3], name = name[3]) grid.arrange(g1, g2, g3, ncol = 1) Nota-se que ambas as cadeias convergiram uma mesma distribuição e que as últimas três cadeias apresentaram valores próximos.\nCadeias A figura abaixo apresenta os traços das cadeias dos parâmetros amostrados. Note que há indícios de convergência.\ncadeia(results,name) Autocorrelação A Figura abaixo apresenta os gráficos de autocorrelação dos parâmetros amostrados.\nFAC(results) É possível notar que apenas nas primeiras defasagens das cadeias das estimativas para os parâmetros \\(\\beta_0\\) e \\(\\beta_1\\) se apresentaram de forma autocorrelacionada e que a partir dessa defasagem o gráfico de autocorrelação se apresentou de forma desejável.\nEstimativas Como todas as características da cadeia gerada foram avaliadas de maneira satisfatória agora será possível conferir o ajuste dos parâmetros de maneira mais segura pois já foi constatada a convergência da cadeia\nComparando com o modelo linear clássico Agora que os resultados sob o paradigma bayesiano já foram conferidos novamente será ajustado um modelo de regressão linear simples pelo método dos mínimos quadrados sob o paradigma clássico para comparar com os resultados do um modelo de regressão linear simples sob o paradigma bayesiano utilizando os resultados calculados na seção.\n# Reta do modelo classico plot(x, y) modelo.classico \u0026lt;- lm(y ~ 1 + x) a.classico \u0026lt;- modelo.classico$coefficients[1] b.classico \u0026lt;- modelo.classico$coefficients[2] abline(a \u0026lt;- a.classico, b = b.classico, col = \u0026quot;blue\u0026quot;) # Reta do modelo bayesiano plot(x, y) a.bayes \u0026lt;- mean(results[, 1]) b.bayes \u0026lt;- mean(results[, 2]) abline(a = a.bayes, b = b.bayes, col = \u0026quot;red\u0026quot;) A Tabela abaixo apresenta o resumo a posteriori dos parâmetros estimados da cadeia e note que esta tabela não conta com a coluna dos valores reais como no exemplo anterior e sim as estimativas sob o paradigma clássico.\ncoef \u0026lt;- coeficientes(results,real = classico) %\u0026gt;% as.data.frame() print(coef) ## Média Desv. Pad. IC inf IC sup Real ## b0 8.2374 0.8481 6.5848 9.9239 8.2839 ## b1 0.1663 0.0170 0.1326 0.1997 0.1656 ## tau 0.1083 0.0214 0.0699 0.1542 0.1025 O modelo estimado sob este paradigma pode ser escrito da seguinte maneira: \\(\\hat{y} = 8,2839 x + 0,1656\\), ou seja, os valores de \\(\\beta_0\\) e de \\(\\beta_1\\) novamente foram muito próximos dos parâmetros obtidos ao estimar sob o paradigma clássico.\nComparando de forma visual A Figura ilustra o gráfico de dispersão dos dados citados acima, com a intenção de exibir quanto uma variável é afetada por outra, onde no eixo vertical representa a velocidade do carro e no eixo horizontal a distância tomada para parar.\nAlém do comportamento das variáveis, neste gráfico é exibido também os resultados obtidos do ajuste ao se utilizar o método de mínimos quadrados (representada pela linha em vermelho) para estimar os parâmetros e o ajuste do modelo ao se utilizar o método apresentado acima em (representada pela linha azul).\n# Texto da imagem text.classico \u0026lt;- str_c(\u0026quot;Modelo Classico: \u0026quot;,\u0026quot;y = \u0026quot;,round(a.classico,4),\u0026quot; x + \u0026quot;,round(b.classico,4)) text.bayes \u0026lt;- str_c(\u0026quot;Modelo Bayesiano: \u0026quot;,\u0026quot;y = \u0026quot;,round(a.bayes,4),\u0026quot; x + \u0026quot;,round(b.bayes,4)) #Gerando o scatter.plot cbind(y, x) %\u0026gt;% as.data.frame %\u0026gt;% ggplot(aes(y = y, x = x)) + geom_point() + geom_smooth(method = \u0026quot;lm\u0026quot;, se = F, col = \u0026quot;red\u0026quot;) + theme_classic() + geom_abline(slope = b.bayes, intercept = a.bayes, col = \u0026quot;blue\u0026quot;) + labs(title = \u0026quot;Relação entre a Distância e a Velocidade com \\nreta do modelo linear clássico vs bayesiano\u0026quot;, x = \u0026quot;Distância\u0026quot;, y = \u0026quot;Velocidade\u0026quot;) É possível notar que os coeficientes calculados foram muito parecidos, mesmo apresentando pequenas diferenças decimais no valor dos coeficientes ainda é possível notar que as retas estão basicamente sobrepostas, ou seja, os valores estimados em ambas as abordagens foram praticamente os mesmos.\nApesar dos valores dos ajustes terem apresentado basicamente os mesmo resultados, a maneira de se conferir a qualidade do ajuste é diferente em ambas as abordagens. Enquanto sob o paradigma clássico o ajuste do modelo pode ser checado ao avaliar os pre-supostos quanto à distribuição dos resíduos, como recomenda @GaussClarice, ao utilizar um método de MCMC faz-se necessário conferir também outros aspectos como por exemplo se houve convergência da cadeias além do comportamento das autocorrelações, vide @migon. Para outras técnicas de diagnóstico de modelos sob o paradigma clássico, veja este post sobre pacotes do R para avaliar o ajuste de modelos.\nConclusão O uso do algorítmo para simular os dados da implementação do modelo hierárquico bayesiano envolveu diversas etapas. Inicialmente foi necessária a revisão de literatura para a compreensão dos métodos que seriam utilizados na implementação do algoritmo, bem como em seu desenvolvimento. Essa pesquisa funcionou de maneira muito didática, de forma que a cada semana a abordagem pudesse envolver maior grau de complexidade.\nDurante o estudo, diversos valores de parâmetros a priori foram selecionados para que fosse possível avaliar a sensibilidade da qualidade da escolha da distribuição a priori. Observou-se que valores elevados para variância a priori (também consideradas como “não informativas” - fazendo uma analogia à modelos clássicos) obtiveram melhores ajustes atribuindo maior importância à informação provinda da amostra.\nO estudo com dados simulados facilitou o entendimento do algoritmo pois foi possível notar com facilidade a inadequabilidade das escolhas das prioris, que resultavam em estimativas muito distante do parâmetro populacional que gerou a amostra.\nPerguntas frequentes Quantas iterações foram usadas no amostrador de Gibbs deste post?\nForam utilizadas 30.000 simulações (nsim = 3*10000), com burn-in de 15.000 iterações descartadas antes de compor a amostra final da distribuição a posteriori.\nAs estimativas do modelo bayesiano ficaram próximas do modelo clássico?\nSim. Tanto para os dados simulados quanto para os dados reais do dataset cars, as estimativas de β0 e β1 obtidas pelo modelo bayesiano foram muito próximas das obtidas pelo ajuste clássico via mínimos quadrados com lm().\nQual distribuição a priori foi utilizada no ajuste do modelo?\nFoi utilizada uma distribuição a priori não informativa, com valores elevados de variância (σ0² = σ1² = 100) para os coeficientes β0 e β1, e uma distribuição Gama(0,1; 0,1) para o parâmetro de precisão τ.\nReferências CORDEIRO, G. M.; DEMÉTRIO, C. G. B.; MORAL, R. A. Modelos Lineares Generalizados e Aplicações. São Paulo: Edgard Blücher, 2024. (Notas de aula originais: UFLA, 2007.)\nEZEKIEL, M. Methods of Correlation Analysis. New York: John Wiley \u0026amp; Sons, 1930.\nGAMERMAN, D.; LOPES, H. F. Markov Chain Monte Carlo: Stochastic Simulation for Bayesian Inference. 2. ed. Boca Raton: Chapman \u0026amp; Hall/CRC, 2006.\nGELFAND, A. E.; SMITH, A. F. M. Sampling-based approaches to calculating marginal densities. Journal of the American Statistical Association, v. 85, n. 410, p. 398–409, 1990.\nGEMAN, S.; GEMAN, D. Stochastic relaxation, Gibbs distributions, and the Bayesian restoration of images. IEEE Transactions on Pattern Analysis and Machine Intelligence, v. 6, n. 6, p. 721–741, 1984.\nMIGON, H. S.; GAMERMAN, D.; LOUZADA, F. Statistical Inference: An Integrated Approach. 2. ed. Boca Raton: CRC Press, 2014.\n","date":"28 de julho de 2018","externalUrl":null,"permalink":"/post/2018-07-28-modelo-bayesiano-do-zero/","section":"Posts","summary":" Modelagem estatística e as duas grandes escolas de inferência Através da modelagem estatística é possível tomar decisões sobre diversos assuntos de interesse como por exemplo na análise de risco de crédito, previsões de quantidade de chuva em um dado local, estimativas de erros ou falhas de um novo produto ou serviço além de diversas áreas como na Educação, Economia, nas Ciências Sociais, Saúde etc.\nMuitas vezes os parâmetros das distribuições em estudo podem ser desconhecidos e existe o desejo de se inferir sobre eles. Existem duas grandes escolas de inferência: a clássica e a bayesiana. A clássica trata esses parâmetros como quantidades fixas e não atribui distribuição a eles, a estimação desses parâmetros é dada através da função de verossimilhança, enquanto que na escola bayesiana atribui-se uma distribuição, chamada de distribuição a priori, ao conjunto de parâmetros desconhecidos quantificando a sua crença sobre esse conjunto e a estimação dos parâmetros é dada através da distribuição à posteriori, que é proporcional ao produto da função de verossimilhança com a distribuição a priori.\n","title":"Modelo Bayesiano do Zero","type":"post"},{"content":"","date":"28 de julho de 2018","externalUrl":null,"permalink":"/tags/modelos-generalizados/","section":"Tags","summary":"","title":"Modelos-Generalizados","type":"tags"},{"content":"","date":"28 de julho de 2018","externalUrl":null,"permalink":"/tags/modelos-lineares/","section":"Tags","summary":"","title":"Modelos-Lineares","type":"tags"},{"content":"","date":"28 de julho de 2018","externalUrl":null,"permalink":"/tags/probabilidade/","section":"Tags","summary":"","title":"Probabilidade","type":"tags"},{"content":" Brasil vs Argentina e Text Mining A copa do mundo esta ai novamente e como não poderia ser diferente, com ela surgem novos quintilhões de bytes todos os dias, saber analisar esses dados é um grande desafio pois a maioria dessa informação se encontra de forma não estruturada e além do desafio de captar esses dados ainda existem mais desafios que podem ser ainda maiores, como o de processá-los e obter respostas deles.\nDada a rivalidade histórica entre Brasil e Argentina achei que seria interessante avaliar como anda o comportamento das pessoas do Brasil nas mídias sociais em relação a esses dois países. Para o post não ficar muito longo, escolhi que iria recolher informações apenas do Twitter devido a praticidade, foram coletados os últimos 4.000 tweets com o termo “brasil” e os últimos “4.000” tweets com o termo “argentina” no Twitter através da sua API com o pacote os twitteR e ROAuth. O código pode ser conferido neste link.\nAnálise de textos sempre foi um tema que me interessou muito, no final do ano de 2017 quando era estagiário me pediram para ajudar em uma pesquisa que envolvia a análise de palavras criando algumas nuvens de palavras. Pesquisando sobre técnicas de textmining descobri tantas abordagens diferentes que resolvi juntar tudo que tinha encontrado em uma única função (que será apresentada a seguir) para a confecção dessas nuvens, utilizarei esta função para ter uma primeira impressão dos dados.\nTL;DR\nForam coletados 4.000 tweets com o termo \"brasil\" e 4.000 tweets com o termo \"argentina\" via API do Twitter, usando os pacotes twitteR e ROAuth. A análise de sentimentos usou o léxico do pacote lexiconPT e a abordagem tidy do livro Text Mining with R, incluindo TF-IDF e bigramas. Na etapa de Machine Learning, o modelo Random Forest obteve acurácia de 100% no teste, seguido de perto pelo GLM (regressão logística) com 99,8% e menor tempo computacional. Além disso, como seria um problema a tarefa de criar as nuvens de palavras só poderia ser realizada por alguém com conhecimento em R, na época estava começando meus estudo sobre shiny e como treinamento desenvolvi um app que esta hospedado no link: https://gomesfellipe.shinyapps.io/appwordcloud/ e o código esta aberto e disponível para quem se interessar no meu github neste link\nPorém, após ler e estudar o livro Text Mining with R - A Tidy Approach por Silge; Robinson (2018) hoje em dia eu olho para trás e vejo que poderia ter feito tanto a função quanto o aplicativo de maneira muito mais eficiente portanto esse post trás alguns dos meus estudos sobre esse livro maravilhoso e também algum estudo sobre Machine Learning com o pacote caret\nImportando a dados Como já foi dito, a base de dados foi obtida através da API do twitter e o código pode ser obtido neste link. Para quem quiser revisar os fundamentos de manipulação de dados usados aqui, escrevi um post específico sobre como manipular dados com dplyr.\nlibrary(dplyr) library(kableExtra) library(magrittr) base \u0026lt;- read.csv(\u0026quot;original_books.csv\u0026quot;) %\u0026gt;% as_tibble() Nuvem de palavras rápida com função customizada Para uma primeira impressão dos dados, vejamos o que retorna uma nuvem de palavras criada com a função wordcloud_sentiment() que desenvolvi antes de conhecer a “A Tidy Approach” para Text Mining:\ndevtools::source_url(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/wordcloud_sentiment.R\u0026quot;) # Obtendo nuvem e salvando tabela num objeto com nome teste: df \u0026lt;- wordcloud_sentiment(base$text, type = \u0026quot;text\u0026quot;, sentiment = F, excludeWords = c(\u0026quot;nao\u0026quot;,letters,LETTERS), ngrams = 2, tf_idf = F, max = 100, freq = 10, horizontal = 0.9, textStemming = F, print=T) Não poderia esquecer, além da nuvem, a função também retorna um dataframe com a frequência das palavras:\ndf %\u0026gt;% as_tibble() ## # A tibble: 29,064 x 2 ## words freq ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; ## 1 = \u0026quot;2795\u0026quot; ## 2 brasil copa \u0026quot;2061\u0026quot; ## 3 copa mundo \u0026quot;1959\u0026quot; ## 4 hat trick \u0026quot;1327\u0026quot; ## 5 = hoje \u0026quot;1248\u0026quot; ## 6 hoje brasil \u0026quot;1215\u0026quot; ## 7 mundo \u0026quot; 852\u0026quot; ## 8 isl ndia \u0026quot; 820\u0026quot; ## 9 pra copa \u0026quot; 813\u0026quot; ## 10 estreia brasil \u0026quot; 782\u0026quot; ## # … with 29,054 more rows E outra função interessante é a de criar uma nuvem a partir de um webscraping muito (muito mesmo) introdutório, para isso foi pegar todo o texto da página sobre a copa do mundo no Wikipédia, veja:\n# Obtendo nuvem e salvando tabela num objeto com nome teste: df_html \u0026lt;- wordcloud_sentiment(\u0026quot;https://pt.wikipedia.org/wiki/Copa_do_Mundo_FIFA\u0026quot;, type = \u0026quot;url\u0026quot;, sentiment = F, excludeWords = c(\u0026quot;nao\u0026quot;,letters,LETTERS), ngrams = 2, tf_idf = F, max = 100, freq = 6, horizontal = 0.9, textStemming = F, print=T) Essa função é bem “prematura,” existem infinitas maneiras de melhorar ela e não alterei ela ainda por falta de tempo.\nA Tidy Approach O formato tidy, em que cada linha corresponde a uma observação e cada coluna à uma variável, veja:\nAgora a tarefa será simplificada com a abordagem tidy, além das funções do livro Text Mining with R utilizarei a função clean_tweets que adaptei inspirado nesse post dessa pagina: Quick guide to mining twitter with R quando estudava sobre textmining.\nArrumando e transformando a base de dados Utilizando as funções do pacote tidytext em conjunto com os pacotes stringr e abjutils, será possível limpar e arrumar a base de dados.\nAlém disso serão removidas as stop words de nossa base, com a função stopwords::stopwords(\"pt\") podemos obter as stopwords da nossa língua\nlibrary(stringr) library(tidytext) library(abjutils) devtools::source_url(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/clean_tweets.R\u0026quot;) original_books = base %\u0026gt;% mutate(text = clean_tweets(text) %\u0026gt;% enc2native() %\u0026gt;% rm_accent()) #Removendo stopwords: excludewords=c(\u0026quot;[:alpha:]\u0026quot;,\u0026quot;[:alnum:]\u0026quot;,\u0026quot;[:digit:]\u0026quot;,\u0026quot;[:xdigit:]\u0026quot;,\u0026quot;[:space:]\u0026quot;,\u0026quot;[:word:]\u0026quot;, LETTERS,letters,1:10, \u0026quot;hat\u0026quot;,\u0026quot;trick\u0026quot;,\u0026quot;bc\u0026quot;,\u0026quot;de\u0026quot;,\u0026quot;tem\u0026quot;,\u0026quot;twitte\u0026quot;,\u0026quot;fez\u0026quot;, \u0026#39;pra\u0026#39;,\u0026quot;vai\u0026quot;,\u0026quot;ta\u0026quot;,\u0026quot;so\u0026quot;,\u0026quot;ja\u0026quot;,\u0026quot;rt\u0026quot;) stop_words = data_frame(word = c(stopwords::stopwords(\u0026quot;pt\u0026quot;), excludewords)) tidy_books \u0026lt;- original_books %\u0026gt;% unnest_tokens(word, text) %\u0026gt;% anti_join(stop_words) Portando a base de dados após a limpeza e a remoção das stop words:\n#Palavras mais faladas: tidy_books %\u0026gt;% count(word, sort = TRUE) ## # A tibble: 3,900 x 2 ## word n ## \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 copa 6993 ## 2 brasil 4164 ## 3 argentina 3487 ## 4 mundo 2030 ## 5 hoje 1825 ## 6 letras 1562 ## 7 messi 1493 ## 8 estreia 1107 ## 9 est 866 ## 10 isl 828 ## # … with 3,890 more rows #Apos a limpeza, caso precise voltar as frases: original_books = tidy_books%\u0026gt;% group_by(book,line)%\u0026gt;% summarise(text=paste(word,collapse = \u0026quot; \u0026quot;)) Palavras mais frequentes Vejamos as palavras mais faladas nessa pesquisa:\nlibrary(ggplot2) tidy_books %\u0026gt;% count(word, sort = TRUE) %\u0026gt;% filter(n \u0026gt; 400) %\u0026gt;% mutate(word = reorder(word, n)) %\u0026gt;% ggplot(aes(word, n, fill = I(\u0026quot;yellow\u0026quot;), colour = I(\u0026quot;green\u0026quot;))) + geom_col(position=\u0026quot;dodge\u0026quot;) + xlab(NULL) + labs(title = \u0026quot;Frequencia total das palavras pesquisadas\u0026quot;)+ coord_flip()+ theme( panel.background = element_rect(fill = \u0026quot;#74acdf\u0026quot;, colour = \u0026quot;lightblue\u0026quot;, size = 0.5, linetype = \u0026quot;solid\u0026quot;), panel.grid.major = element_line(size = 0.5, linetype = \u0026#39;solid\u0026#39;, colour = \u0026quot;white\u0026quot;), panel.grid.minor = element_line(size = 0.25, linetype = \u0026#39;solid\u0026#39;, colour = \u0026quot;white\u0026quot;) ) Palavras mais frequentes para cada termo Vejamos as nuvens de palavras mais frequentes de acordo com cada um dos termos pesquisados:\n#Criando nuvem de palavra: library(wordcloud) par(mfrow=c(1,2)) tidy_books %\u0026gt;% filter(book==\u0026quot;br\u0026quot;)%\u0026gt;% count(word) %\u0026gt;% with(wordcloud(word, n, max.words = 100,random.order = F,min.freq = 15,random.color = F,colors = c(\u0026quot;#009b3a\u0026quot;, \u0026quot;#fedf00\u0026quot;,\u0026quot;#002776\u0026quot;),scale = c(2,1),rot.per = 0.05)) tidy_books %\u0026gt;% filter(book==\u0026quot;arg\u0026quot;)%\u0026gt;% count(word) %\u0026gt;% with(wordcloud(word, n, max.words = 100,min.freq = 15,random.order = F,random.color = F,colors = c(\u0026quot;#75ade0\u0026quot;, \u0026quot;#ffffff\u0026quot;,\u0026quot;#f6b506\u0026quot;),scale = c(2,1),rot.per = 0.05)) par(mfrow=c(1,1)) Análise de sentimentos A análise de sentimentos utilizando a abordagem tidy foi possível graças ao pacote lexiconPT, que esta disponível no CRAN e que conheci ao ler o post: “O Sensacionalista e Text Mining: Análise de sentimento usando o lexiconPT” do blog Paixão por dados que gosto tanto de acompanhar.\n# Analise de sentimentos: library(lexiconPT) sentiment = data.frame(word = sentiLex_lem_PT02$term , polarity = sentiLex_lem_PT02$polarity) %\u0026gt;% mutate(sentiment = if_else(polarity\u0026gt;0,\u0026quot;positive\u0026quot;,if_else(polarity\u0026lt;0,\u0026quot;negative\u0026quot;,\u0026quot;neutro\u0026quot;)), word = as.character(word)) %\u0026gt;% as_tibble() library(tidyr) book_sentiment \u0026lt;- tidy_books %\u0026gt;% inner_join(sentiment) %\u0026gt;% count(book,word, index = line , sentiment) %\u0026gt;% spread(sentiment, n, fill = 0) %\u0026gt;% mutate(sentiment = positive - negative) %T\u0026gt;% print ## # A tibble: 2,953 x 7 ## book word index negative neutro positive sentiment ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 arg abandonar 857 1 0 0 -1 ## 2 arg absurdo 849 1 0 0 -1 ## 3 arg absurdo 1863 1 0 0 -1 ## 4 arg afogado 2275 1 0 0 -1 ## 5 arg afogado 3659 1 0 0 -1 ## 6 arg alegria 1134 0 0 1 1 ## 7 arg almo 186 0 0 1 1 ## 8 arg almo 2828 0 0 1 1 ## 9 arg almo 3433 0 0 1 1 ## 10 arg almo 3569 0 0 1 1 ## # … with 2,943 more rows Cada palavra possui um valor associado a sua polaridade , vejamos como ficou distribuído o número de palavras de cada sentimento de acordo com cada termo escolhido para a pesquisa:\nbook_sentiment%\u0026gt;% count(sentiment,book)%\u0026gt;% arrange(book) %\u0026gt;% ggplot(aes(x = factor(sentiment),y = n,fill=book))+ geom_bar(stat=\u0026quot;identity\u0026quot;,position=\u0026quot;dodge\u0026quot;)+ facet_wrap(~book) + theme_bw()+ scale_fill_manual(values=c(\u0026quot;#75ade0\u0026quot;, \u0026quot;#009b3a\u0026quot;)) Comparando sentimentos dos termos de pesquisa Para termos associados a palavra “Brasil” no twitter:\n# Nuvem de comparação: library(reshape2) tidy_books %\u0026gt;% filter(book==\u0026quot;br\u0026quot;)%\u0026gt;% inner_join(sentiment) %\u0026gt;% count(word, sentiment, sort = TRUE) %\u0026gt;% acast(word ~ sentiment, value.var = \u0026quot;n\u0026quot;, fill = 0) %\u0026gt;% comparison.cloud(colors = c(\u0026quot;red\u0026quot;, \u0026quot;gray80\u0026quot;,\u0026quot;green\u0026quot;), max.words = 200) Para termos associados a palavra “Argentina” no twitter:\ntidy_books %\u0026gt;% filter(book==\u0026quot;arg\u0026quot;)%\u0026gt;% inner_join(sentiment) %\u0026gt;% count(word, sentiment, sort = TRUE) %\u0026gt;% acast(word ~ sentiment, value.var = \u0026quot;n\u0026quot;, fill = 0) %\u0026gt;% comparison.cloud(colors = c(\u0026quot;red\u0026quot;, \u0026quot;gray80\u0026quot;,\u0026quot;green\u0026quot;), max.words = 200) Proporção de palavras positivas e negativas por texto # Proporção de palavras negativas: bingnegative \u0026lt;- sentiment %\u0026gt;% filter(sentiment == \u0026quot;negative\u0026quot;) bingpositive \u0026lt;- sentiment %\u0026gt;% filter(sentiment == \u0026quot;positive\u0026quot;) wordcounts \u0026lt;- tidy_books %\u0026gt;% group_by(book, line) %\u0026gt;% summarize(words = n()) Para negativas; tidy_books %\u0026gt;% semi_join(bingnegative) %\u0026gt;% group_by(book, line) %\u0026gt;% summarize(negativewords = n()) %\u0026gt;% left_join(wordcounts, by = c(\u0026quot;book\u0026quot;, \u0026quot;line\u0026quot;)) %\u0026gt;% mutate(ratio = negativewords/words) %\u0026gt;% top_n(5) %\u0026gt;% ungroup() %\u0026gt;% arrange(desc(ratio)) %\u0026gt;% filter(book==\u0026quot;br\u0026quot;) ## # A tibble: 5 x 5 ## book line negativewords words ratio ## \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; ## 1 br 2003 1 3 0.333 ## 2 br 2775 1 3 0.333 ## 3 br 2580 2 7 0.286 ## 4 br 126 1 4 0.25 ## 5 br 2335 1 4 0.25 A frase mais negativa do brasil e da argentina::\nbase %\u0026gt;% filter(book==\u0026quot;br\u0026quot;,line==2580) %\u0026gt;% mutate(text = as.character(text))%\u0026gt;% select(text) %\u0026gt;% c() ## $text ## [1] \u0026quot;um medo? \\x97 de nois criar expectativa e o Brasil perder a copa https://t.co/0chcNWHh0m\u0026quot; base %\u0026gt;% filter(book==\u0026quot;arg\u0026quot;,line==572) %\u0026gt;% mutate(text = as.character(text))%\u0026gt;% select(text) %\u0026gt;% c() ## $text ## [1] \u0026quot;RT @DavidmeMelo: @SantiiSanchez16 @Flamengo Perder a copa para o time mais sujo e mais corrupto da argentina \\xe9 assim mesmo https://t.co/zIC\\x85\u0026quot; Para positivas: tidy_books %\u0026gt;% semi_join(bingpositive) %\u0026gt;% group_by(book, line) %\u0026gt;% summarize(positivewords = n()) %\u0026gt;% left_join(wordcounts, by = c(\u0026quot;book\u0026quot;, \u0026quot;line\u0026quot;)) %\u0026gt;% mutate(ratio = positivewords/words) %\u0026gt;% top_n(5) %\u0026gt;% ungroup() %\u0026gt;% arrange(desc(ratio)) ## # A tibble: 22 x 5 ## book line positivewords words ratio ## \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; ## 1 arg 2120 3 9 0.333 ## 2 br 2374 1 3 0.333 ## 3 arg 3272 2 7 0.286 ## 4 arg 2301 1 4 0.25 ## 5 br 126 1 4 0.25 ## 6 br 553 2 8 0.25 ## 7 br 1499 2 8 0.25 ## 8 br 2054 2 8 0.25 ## 9 br 2591 1 4 0.25 ## 10 arg 2130 1 5 0.2 ## # … with 12 more rows A frase mais positiva do brasil e da argentina:\nbase %\u0026gt;% filter(book==\u0026quot;br\u0026quot;,line==2374) %\u0026gt;% mutate(text = as.character(text))%\u0026gt;% select(text) %\u0026gt;% c() ## $text ## [1] \u0026quot;Tirei Brasil, \\xe9 uma honra https://t.co/OgNCot4Wu0\u0026quot; base %\u0026gt;% filter(book==\u0026quot;arg\u0026quot;,line==2120) %\u0026gt;% mutate(text = as.character(text))%\u0026gt;% select(text) %\u0026gt;% c() ## $text ## [1] \u0026quot;@_LeoFerreiraH Quero que a Argentina passe para possivelmente enfrentar o Brasil, ganhar da Argentina j\\xe1 \\xe9 bom, na\\x85 https://t.co/bxHJUeGVpc\u0026quot; TF-IDF Segundo Silge; Robinson (2018) no livro tidytextminig:\nThe statistic tf-idf is intended to measure how important a word is to a document in a collection (or corpus) of documents, for example, to one novel in a collection of novels or to one website in a collection of websites.\nTraduzido pelo Google tradutor:\nA estatística tf-idf destina-se a medir a importância de uma palavra para um documento em uma coleção (ou corpus) de documentos, por exemplo, para um romance em uma coleção de romances ou para um site em uma coleção de sites.\nMatematicamente:\n\\[ idf(\\text{term}) = \\ln{\\left(\\frac{n_{\\text{documents}}}{n_{\\text{documents containing term}}}\\right)} \\]\nE que com o pacote tidytext podemos obter usando o comando bind_tf_idf(), veja:\n# Obtendo numero de palavras book_words \u0026lt;- original_books %\u0026gt;% unnest_tokens(word, text) %\u0026gt;% count(book, word, sort = TRUE) %\u0026gt;% ungroup()%\u0026gt;% anti_join(stop_words) total_words \u0026lt;- book_words %\u0026gt;% group_by(book) %\u0026gt;% summarize(total = sum(n)) book_words \u0026lt;- left_join(book_words, total_words) # tf-idf: book_words \u0026lt;- book_words %\u0026gt;% bind_tf_idf(word, book, n) book_words %\u0026gt;% arrange(desc(tf_idf)) ## # A tibble: 4,773 x 7 ## book word n total tf idf tf_idf ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 br letras 1562 30429 0.0513 0.693 0.0356 ## 2 br ansioso 688 30429 0.0226 0.693 0.0157 ## 3 arg classificou 666 40781 0.0163 0.693 0.0113 ## 4 arg segundo 654 40781 0.0160 0.693 0.0111 ## 5 arg especialistas 649 40781 0.0159 0.693 0.0110 ## 6 arg nalti 649 40781 0.0159 0.693 0.0110 ## 7 arg repito 649 40781 0.0159 0.693 0.0110 ## 8 br icon 248 30429 0.00815 0.693 0.00565 ## 9 arg ncio 287 40781 0.00704 0.693 0.00488 ## 10 arg penalti 284 40781 0.00696 0.693 0.00483 ## # … with 4,763 more rows O que nos trás algo como: “termos mais relevantes.”\nVisualmente:\nbook_words %\u0026gt;% arrange(desc(tf_idf)) %\u0026gt;% mutate(word = factor(word, levels = rev(unique(word)))) %\u0026gt;% group_by(book) %\u0026gt;% top_n(15) %\u0026gt;% ungroup %\u0026gt;% ggplot(aes(word, tf_idf, fill = book)) + geom_col(show.legend = FALSE) + labs(x = NULL, y = \u0026quot;tf-idf\u0026quot;) + facet_wrap(~book, ncol = 2, scales = \u0026quot;free\u0026quot;) + coord_flip()+ theme_bw()+ scale_fill_manual(values=c(\u0026quot;#75ade0\u0026quot;, \u0026quot;#009b3a\u0026quot;)) bi grams OS bi grams são sequencias de palavras, a seguir será procurada as sequencias de duas palavras, o que nos permite estudar um pouco melhor o contexto do seu uso.\n# Bi grams book_bigrams \u0026lt;- original_books %\u0026gt;% unnest_tokens(bigram, text, token = \u0026quot;ngrams\u0026quot;, n = 2) book_bigrams %\u0026gt;% count(bigram, sort = TRUE) ## # A tibble: 15,106 x 3 ## # Groups: book [2] ## book bigram n ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 br brasil copa 2039 ## 2 br copa mundo 1459 ## 3 br hoje brasil 1215 ## 4 arg argentina copa 1122 ## 5 arg isl ndia 818 ## 6 br estreia brasil 764 ## 7 br ansioso estreia 684 ## 8 br est ansioso 680 ## 9 arg classificou argentina 660 ## 10 arg copa segundo 649 ## # … with 15,096 more rows Separando as coluna de bi grams:\nbigrams_separated \u0026lt;- book_bigrams %\u0026gt;% separate(bigram, c(\u0026quot;word1\u0026quot;, \u0026quot;word2\u0026quot;), sep = \u0026quot; \u0026quot;) bigrams_filtered \u0026lt;- bigrams_separated %\u0026gt;% filter(!word1 %in% stop_words$word) %\u0026gt;% filter(!word2 %in% stop_words$word) # new bigram counts: bigram_counts \u0026lt;- bigrams_filtered %\u0026gt;% count(word1, word2, sort = TRUE) bigram_counts ## # A tibble: 15,106 x 4 ## # Groups: book [2] ## book word1 word2 n ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 br brasil copa 2039 ## 2 br copa mundo 1459 ## 3 br hoje brasil 1215 ## 4 arg argentina copa 1122 ## 5 arg isl ndia 818 ## 6 br estreia brasil 764 ## 7 br ansioso estreia 684 ## 8 br est ansioso 680 ## 9 arg classificou argentina 660 ## 10 arg copa segundo 649 ## # … with 15,096 more rows Caso seja preciso juntar novamente:\nbigrams_united \u0026lt;- bigrams_filtered %\u0026gt;% unite(bigram, word1, word2, sep = \u0026quot; \u0026quot;) bigrams_united ## # A tibble: 71,208 x 2 ## # Groups: book [2] ## book bigram ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; ## 1 arg isl ndia ## 2 arg ndia pouco ## 3 arg pouco mil ## 4 arg mil habitantes ## 5 arg habitantes montaram ## 6 arg montaram sele ## 7 arg sele est ## 8 arg est copa ## 9 arg copa fizeram ## 10 arg fizeram gol ## # … with 71,198 more rows Analisando bi grams com tf-idf Também é possível aplicar a transformação tf-idf em bigrams, veja:\n#bi grams com tf idf bigram_tf_idf \u0026lt;- bigrams_united %\u0026gt;% count(book, bigram) %\u0026gt;% bind_tf_idf(bigram, book, n) %\u0026gt;% arrange(desc(tf_idf)) bigram_tf_idf ## # A tibble: 15,106 x 6 ## # Groups: book [2] ## book bigram n tf idf tf_idf ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;dbl\u0026gt; ## 1 br hoje brasil 1215 0.0399 0.693 0.0277 ## 2 br ansioso estreia 684 0.0225 0.693 0.0156 ## 3 br est ansioso 680 0.0223 0.693 0.0155 ## 4 br letras letras 620 0.0204 0.693 0.0141 ## 5 arg classificou argentina 660 0.0162 0.693 0.0112 ## 6 arg copa segundo 649 0.0159 0.693 0.0110 ## 7 arg messi repito 649 0.0159 0.693 0.0110 ## 8 arg repito classificou 649 0.0159 0.693 0.0110 ## 9 arg segundo especialistas 649 0.0159 0.693 0.0110 ## 10 br brasil letras 313 0.0103 0.693 0.00713 ## # … with 15,096 more rows Analisando contexto de palavras negativas: Uma das abordagens interessantes ao estudar as bi-grams é a de avaliar o contexto das palavras negativas, veja:\nbigrams_separated %\u0026gt;% filter(word1 == \u0026quot;nao\u0026quot;) %\u0026gt;% count(word1, word2, sort = TRUE) ## # A tibble: 35 x 4 ## # Groups: book [2] ## book word1 word2 n ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 br nao copa 10 ## 2 arg nao abrir 3 ## 3 arg nao convoca 3 ## 4 arg nao ruim 3 ## 5 br nao acredito 2 ## 6 arg nao achei 1 ## 7 arg nao acordem 1 ## 8 arg nao argentina 1 ## 9 arg nao assisti 1 ## 10 arg nao compara 1 ## # … with 25 more rows not_words \u0026lt;- bigrams_separated %\u0026gt;% filter(word1 == \u0026quot;nao\u0026quot;) %\u0026gt;% inner_join(sentiment, by = c(word2 = \u0026quot;word\u0026quot;)) %\u0026gt;% count(word2, sentiment, sort = TRUE) %\u0026gt;% ungroup() not_words ## # A tibble: 3 x 4 ## book word2 sentiment n ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; ## 1 arg ruim negative 3 ## 2 arg vencer positive 1 ## 3 br amistoso positive 1 A palavra não antes de uma palavra “positiva,” como por exemplo “não gosto” pode ser anulada ao somar-se suas polaridades (“não” = - 1, “gosto” = +1 e “não gosto” = -1 + 1) o leva a necessidade de ser tomar um cuidado especial com essas palavras em uma análise de texto mais detalhada, veja de forma visual:\nnot_words %\u0026gt;% mutate(sentiment=ifelse(sentiment==\u0026quot;positive\u0026quot;,1,ifelse(sentiment==\u0026quot;negative\u0026quot;,-1,0)))%\u0026gt;% mutate(contribution = n * sentiment) %\u0026gt;% arrange(desc(abs(contribution))) %\u0026gt;% head(20) %\u0026gt;% mutate(word2 = reorder(word2, contribution)) %\u0026gt;% ggplot(aes(word2, n * sentiment, fill = n * sentiment \u0026gt; 0)) + geom_col() + xlab(\u0026quot;Words preceded by \\\u0026quot;not\\\u0026quot;\u0026quot;) + ylab(\u0026quot;Sentiment score * number of occurrences\u0026quot;) + coord_flip()+ theme_bw() Machine Learning Estava pesquisando sobre algorítimos recomendados para a análise de texto quando encontrei um artigo da data camp chamado: Lyric Analysis with NLP \u0026amp; Machine Learning with R, do qual a autora expõe a seguinte tabela:\nPortanto resolvi fazer uma brincadeira e ajustar 4 dos modelos propostos para a tarefa supervisionada de classificação: K-NN, Tress (tentarei o ajuste do algorítimo Random Forest), Logistic Regression (Modelo estatístico) e Naive-Bayes (por meio do cálculo de probabilidades condicionais) para ver se conseguia recuperar a classificação de quais os termos de pesquisa que eu utilizei para obter esses dados\nAlém de técnicas apresentadas no livro do pacote caret, por Kuhn (2018), muito do que apliquei aqui foi baseado no livro “Introdução a mineração de dados” por Silva; Peres; Boscarioli (2016), que foi bastante útil na minha introdução sobre o tema Machine Learning.\nVou utilizar uma função chamada plot_pred_type_distribution(),apresentada neste post de titulo: Illustrated Guide to ROC and AUC e fiz uma pequena alteração para que ela funcionasse para o dataset deste post . A função adaptada pode ser encontrada neste link no meu github e a função original neste link do github do autor.\nPacote caret Basicamente o ajuste de todos os modelos envolveram o uso do pacote caret e muitos dos passos aqui foram baseados nas instruções fornecidas no livro do pacote. O pacote facilita bastante o ajuste dos parâmetros no ajuste de modelos.\nTransformar e arrumar Uma solução do kaggle para o desafio Toxic Comment Classification Challenge me chamou atenção, do qual o participante da competição criou colunas que sinalizassem os caracteres especiais de cada frase, utilizarei esta técnica para o ajuste e novamente utilizarei o pacote de léxicos do apresentado no post do blog Paixão por dados\nVeja a base transformada e arrumada:\n# Ref: https://cfss.uchicago.edu/text_classification.html # https://www.r-bloggers.com/illustrated-guide-to-roc-and-auc/ devtools::source_url(\u0026quot;https://raw.githubusercontent.com/gomesfellipe/functions/master/plot_pred_type_distribution.R\u0026quot;) base \u0026lt;- base %\u0026gt;% mutate(length = str_length(text), ncap = str_count(text, \u0026quot;[A-Z]\u0026quot;), ncap_len = ncap / length, nexcl = str_count(text, fixed(\u0026quot;!\u0026quot;)), nquest = str_count(text, fixed(\u0026quot;?\u0026quot;)), npunct = str_count(text, \u0026quot;[[:punct:]]\u0026quot;), nword = str_count(text, \u0026quot;\\\\w+\u0026quot;), nsymb = str_count(text, \u0026quot;\u0026amp;|@|#|\\\\$|%|\\\\*|\\\\^\u0026quot;), nsmile = str_count(text, \u0026quot;((?::|;|=)(?:-)?(?:\\\\)|D|P))\u0026quot;), text = clean_tweets(text) %\u0026gt;% enc2native() %\u0026gt;% rm_accent())%\u0026gt;% unnest_tokens(word, text) %\u0026gt;% anti_join(stop_words)%\u0026gt;% group_by(book,line,length, ncap, ncap_len, nexcl, nquest, npunct, nword, nsymb, nsmile)%\u0026gt;% summarise(text=paste(word,collapse = \u0026quot; \u0026quot;)) %\u0026gt;% select(text,everything())%T\u0026gt;% print() ## # A tibble: 7,995 x 12 ## # Groups: book, line, length, ncap, ncap_len, nexcl, nquest, npunct, nword, ## # nsymb [7,995] ## text book line length ncap ncap_len nexcl nquest npunct nword nsymb ## \u0026lt;chr\u0026gt; \u0026lt;chr\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;dbl\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; \u0026lt;int\u0026gt; ## 1 isl … arg 1 NA 7 NA 0 0 6 24 1 ## 2 pau … arg 2 108 6 0.0556 0 0 2 20 1 ## 3 mess… arg 3 NA 10 NA 0 0 3 24 1 ## 4 minu… arg 4 NA 2 NA 0 0 2 24 1 ## 5 requ… arg 5 129 23 0.178 0 0 15 21 1 ## 6 bras… arg 6 NA 11 NA 0 0 12 20 1 ## 7 dupl… arg 7 123 84 0.683 0 0 8 21 1 ## 8 mess… arg 8 NA 10 NA 0 0 3 24 1 ## 9 mess… arg 9 NA 10 NA 0 0 3 24 1 ## 10 mess… arg 10 NA 10 NA 0 0 3 24 1 ## # … with 7,985 more rows, and 1 more variable: nsmile \u0026lt;int\u0026gt; Após arrumar e transformar as informações que serão utilizadas na classificação, será criado um corpus sem a abordagem tidy para obter a matriz de documentos e termos, e depois utilizar a coluna de classificação, veja:\nlibrary(tm) #Pacote de para text mining corpus \u0026lt;- Corpus(VectorSource(base$text)) #Criando a matrix de termos: book_dtm = DocumentTermMatrix(corpus, control = list(minWordLength=2,minDocFreq=3)) %\u0026gt;% weightTfIdf(normalize = T) %\u0026gt;% # Transformação tf-idf com pacote tm removeSparseTerms( sparse = .95) # obtendo matriz esparsa com pacote tm #Transformando em matrix, permitindo a manipulacao: matrix = as.matrix(book_dtm) dim(matrix) ## [1] 7995 18 Pronto, agora já podemos juntar tudo em um data frame e separa em treino e teste para a classificação dos textos obtidos do twitter:\n#Criando a base de dados: full=data.frame(cbind( base[,\u0026quot;book\u0026quot;], matrix, base[,-c(1:3)] )) %\u0026gt;% na.omit() Treino e teste Será utilizado tanto o método de hold-out e de cross-validation\nset.seed(825) particao = sample(1:2,nrow(full), replace = T,prob = c(0.7,0.3)) train = full[particao==1,] test = full[particao==2,] library(caret) Ajustando modelos KNN É uma técnica de aprendizado baseado em instância, isto quer dizer que a classificação de uma observação com a classe desconhecida é realizada a partir da comparação com outras observações cada vez que uma observação é apresentado ao modelo e também é conhecido como “lazy evaluation,” já que um modelo não é induzido previamente.\nDiversas medidas de distância podem ser utilizadas, utilizarei aqui a euclideana e além disso a escolha do parâmetro \\(k\\) (de k vizinhos mais próximos) deve ser feita com cuidado pois um \\(k\\) pequeno pode expor o algorítimo a uma alta sensibilidade a um ruído.\nUtilizarei aqui o pacote caret como ferramenta para o ajuste deste modelo pois ela permite que eu configure que seja feita a validação cruzada em conjunto com a padronização, pois esses complementos beneficiam no ajuste de modelos que calculam distâncias.\n# knn ------- set.seed(825) antes = Sys.time() book_knn \u0026lt;- train(book ~., data=train, method = \u0026quot;knn\u0026quot;, trControl = trainControl(method = \u0026quot;cv\u0026quot;,number = 10), # validacao cruzada preProc = c(\u0026quot;center\u0026quot;, \u0026quot;scale\u0026quot;)) time_knn \u0026lt;- Sys.time() - antes Sys.time() - antes ## Time difference of 2.465522 secs plot(book_knn) previsao = predict(book_knn, test) confusionMatrix(previsao, factor(test$book)) ## Confusion Matrix and Statistics ## ## Reference ## Prediction arg br ## arg 105 8 ## br 5 371 ## ## Accuracy : 0.9734 ## 95% CI : (0.955, 0.9858) ## No Information Rate : 0.7751 ## P-Value [Acc \u0026gt; NIR] : \u0026lt;2e-16 ## ## Kappa : 0.9245 ## ## Mcnemar\u0026#39;s Test P-Value : 0.5791 ## ## Sensitivity : 0.9545 ## Specificity : 0.9789 ## Pos Pred Value : 0.9292 ## Neg Pred Value : 0.9867 ## Prevalence : 0.2249 ## Detection Rate : 0.2147 ## Detection Prevalence : 0.2311 ## Balanced Accuracy : 0.9667 ## ## \u0026#39;Positive\u0026#39; Class : arg ## df = cbind(fit = if_else(previsao==\u0026quot;br\u0026quot;,1,0), class = if_else(test$book==\u0026quot;br\u0026quot;,1,0)) %\u0026gt;% as.data.frame() plot_pred_type_distribution(df,0.5) Como podemos ver, segundo a validação cruzada realizada com o pacote caret, o número 5 de vizinhos mais próximos foi o que apresentou o melhor resultado. Além disso o modelo apresentou uma acurácia de 97,18% e isto parece bom dado que a sensibilidade (taxa de verdadeiros positivos) e a especificidade (taxa de verdadeiros negativos) foram altas também, o que foi reforçado com o gráfico ilustrado da matriz de confusão.\nO tempo computacional para o ajuste do modelo foi de:2.46385908126831 segundos\nRandom Forest O modelo de Random Forest tem se tornado muito popular devido ao seu bom desempenho e pela sua alta capacidade de se adaptar aos dados. O modelo funciona através da combinação de várias árvores de decisões e no seu ajuste alguns parâmetros precisam ser levados em conta. Fiz um estudo mais aprofundado sobre modelos baseados em árvores que detalha melhor esses algoritmos.\nO parâmetro que sera levado em conta para o ajuste será apenas o ntree, que representa o número de árvores ajustadas. Este parâmetro deve ser escolhido com cuidado pois pode ser tão grande quanto você quiser e continua aumentando a precisão até certo ponto porém pode ser mais limitado pelo tempo computacional disponível.\nset.seed(824) # Random Forest antes = Sys.time() book_rf \u0026lt;- train(book ~., data=train, method = \u0026quot;rf\u0026quot;,trace=F, ntree = 200, trControl = trainControl(method = \u0026quot;cv\u0026quot;,number = 10)) time_rf \u0026lt;- Sys.time() - antes Sys.time() - antes ## Time difference of 8.994044 secs library(randomForest) varImpPlot(book_rf$finalModel) previsao = predict(book_rf, test) confusionMatrix(previsao, factor(test$book)) ## Confusion Matrix and Statistics ## ## Reference ## Prediction arg br ## arg 110 0 ## br 0 379 ## ## Accuracy : 1 ## 95% CI : (0.9925, 1) ## No Information Rate : 0.7751 ## P-Value [Acc \u0026gt; NIR] : \u0026lt; 2.2e-16 ## ## Kappa : 1 ## ## Mcnemar\u0026#39;s Test P-Value : NA ## ## Sensitivity : 1.0000 ## Specificity : 1.0000 ## Pos Pred Value : 1.0000 ## Neg Pred Value : 1.0000 ## Prevalence : 0.2249 ## Detection Rate : 0.2249 ## Detection Prevalence : 0.2249 ## Balanced Accuracy : 1.0000 ## ## \u0026#39;Positive\u0026#39; Class : arg ## # https://www.r-bloggers.com/illustrated-guide-to-roc-and-auc/ df = cbind(fit = if_else(previsao==\u0026quot;br\u0026quot;,1,0), class = if_else(test$book==\u0026quot;br\u0026quot;,1,0)) %\u0026gt;% as.data.frame() plot_pred_type_distribution(df,0.5) Segundo o gráfico de importância, parece que as palavras “brasil,” “argentina,” “copa” e “messi” foram as que apresentaram maior impacto do preditor (lembrando que essa medida não é um efeito específico), o que mostra que a presença das palavras que estamos utilizando para classificar tiveram um impacto na classificação bastante superior aos demais.\nQuanto a acurácia, o random forest apresentou valor um pouco maior do que o do algorítimo K-NN e além disso apresentou altos valores para a sensibilidade (taxa de verdadeiros positivos) e a especificidade (taxa de verdadeiros negativos), o que foi reforçado com o gráfico ilustrado da matriz de confusão, porém o tempo computacional utilizado para ajustar este modelo foi muito maior, o que leva a questionar se esse pequeno aumento na taxa de acerto vale a pena aumentando tanto no tempo de processamento (outra alternativa seria diminuir o tamanho do número de árvores para ver se melhoraria na qualidade do ajuste).\nO tempo computacional para o ajuste do modelo foi de: 8.99299788475037 segundos\nNaive Bayes Este é um algorítimo que trata-se de um classificador estatístico baseado no Teorema de Bayes e recebe o nome de ingênuo (naive) porque pressupõe que o valor de um atributo que exerce algum efeito sobre a distribuição da variável resposta é independente do efeito que outros atributos.\nO cálculo para a classificação é feito por meio do cálculo de probabilidades condicionais, ou seja, probabilidade de uma observação pertencer a cada classe dado os exemplares existentes no conjunto de dados usado para o treinamento.\n# Naive Bayes ---- set.seed(825) antes = Sys.time() book_nb \u0026lt;- train(book ~., data=train, method= \u0026quot;nb\u0026quot;, laplace =1, trControl = trainControl(method = \u0026quot;cv\u0026quot;,number = 10)) time_nb \u0026lt;- Sys.time() - antes Sys.time() - antes ## Time difference of 7.141471 secs previsao = predict(book_nb, test) confusionMatrix(previsao, factor(test$book)) ## Confusion Matrix and Statistics ## ## Reference ## Prediction arg br ## arg 108 6 ## br 2 373 ## ## Accuracy : 0.9836 ## 95% CI : (0.968, 0.9929) ## No Information Rate : 0.7751 ## P-Value [Acc \u0026gt; NIR] : \u0026lt;2e-16 ## ## Kappa : 0.9537 ## ## Mcnemar\u0026#39;s Test P-Value : 0.2888 ## ## Sensitivity : 0.9818 ## Specificity : 0.9842 ## Pos Pred Value : 0.9474 ## Neg Pred Value : 0.9947 ## Prevalence : 0.2249 ## Detection Rate : 0.2209 ## Detection Prevalence : 0.2331 ## Balanced Accuracy : 0.9830 ## ## \u0026#39;Positive\u0026#39; Class : arg ## # https://www.r-bloggers.com/illustrated-guide-to-roc-and-auc/ df = cbind(fit = if_else(previsao==\u0026quot;br\u0026quot;,1,0), class = if_else(test$book==\u0026quot;br\u0026quot;,1,0)) %\u0026gt;% as.data.frame() plot_pred_type_distribution(df,0.5) Apesar a aparente acurácia alta, o valor calculado para a especificidade (verdadeiros negativos) foi elevado o que aponta que o ajuste do modelo não se apresentou de forma eficiente\nO tempo computacional foi de 7.1403751373291 segundos\nGLM - Logit Este é um modelo estatístico que já abordei aqui no blog no post sobre AED de forma rápida e um pouco de machine learning e seguindo a recomendação do artigo da datacamp vejamos quais resultados obtemos com o ajuste deste modelo:\n# Modelo logístico ---- set.seed(825) antes = Sys.time() book_glm \u0026lt;- train(book ~., data=train, method = \u0026quot;glm\u0026quot;, # modelo generalizado family = binomial(link = \u0026#39;logit\u0026#39;), # Familia Binomial ligacao logit trControl = trainControl(method = \u0026quot;cv\u0026quot;, number = 10)) # validacao cruzada time_glm \u0026lt;- Sys.time() - antes Sys.time() - antes ## Time difference of 1.378149 secs library(ggfortify) autoplot(book_glm$finalModel, which = 1:6, data = train, colour = \u0026#39;book\u0026#39;, label.size = 3, ncol = 3) + theme_classic() previsao = predict(book_glm, test) confusionMatrix(previsao, factor(test$book)) ## Confusion Matrix and Statistics ## ## Reference ## Prediction arg br ## arg 109 0 ## br 1 379 ## ## Accuracy : 0.998 ## 95% CI : (0.9887, 0.9999) ## No Information Rate : 0.7751 ## P-Value [Acc \u0026gt; NIR] : \u0026lt;2e-16 ## ## Kappa : 0.9941 ## ## Mcnemar\u0026#39;s Test P-Value : 1 ## ## Sensitivity : 0.9909 ## Specificity : 1.0000 ## Pos Pred Value : 1.0000 ## Neg Pred Value : 0.9974 ## Prevalence : 0.2249 ## Detection Rate : 0.2229 ## Detection Prevalence : 0.2229 ## Balanced Accuracy : 0.9955 ## ## \u0026#39;Positive\u0026#39; Class : arg ## df = cbind(fit = if_else(previsao==\u0026quot;br\u0026quot;,1,0), class = if_else(test$book==\u0026quot;br\u0026quot;,1,0)) %\u0026gt;% as.data.frame() plot_pred_type_distribution(df,0.5) Comparando modelos Agora que temos 4 modelos ajustados e cada um apresentando resultados diferentes, vejamos qual deles seria o mais interessante para caso fosse necessário recuperar a classificação dos termos pesquisados através da API, veja a seguir um resumo das medidas obtidas:\n# \u0026quot;Dados esses modelos, podemos fazer declarações estatísticas sobre suas diferenças de desempenho? Para fazer isso, primeiro coletamos os resultados de reamostragem usando resamples.\u0026quot; - caret resamps \u0026lt;- resamples(list(knn = book_knn, rf = book_rf, nb = book_nb, glm = book_glm)) summary(resamps) ## ## Call: ## summary.resamples(object = resamps) ## ## Models: knn, rf, nb, glm ## Number of resamples: 10 ## ## Accuracy ## Min. 1st Qu. Median Mean 3rd Qu. Max. NA\u0026#39;s ## knn 0.9553571 0.9821824 0.9823009 0.9831305 0.9889381 1 0 ## rf 0.9823009 1.0000000 1.0000000 0.9973451 1.0000000 1 0 ## nb 0.9107143 0.9623894 0.9823009 0.9768726 1.0000000 1 0 ## glm 0.9910714 0.9911504 1.0000000 0.9964523 1.0000000 1 0 ## ## Kappa ## Min. 1st Qu. Median Mean 3rd Qu. Max. NA\u0026#39;s ## knn 0.8730734 0.9500663 0.9512773 0.9530901 0.9691458 1 0 ## rf 0.9513351 1.0000000 1.0000000 0.9926689 1.0000000 1 0 ## nb 0.7791798 0.8998204 0.9525409 0.9398109 1.0000000 1 0 ## glm 0.9752868 0.9753544 1.0000000 0.9901350 1.0000000 1 0 Como podemos ver, o modelo que apresentou a menor acurácia e o menor coeficiente kappa foi o Naive Bayes enquanto que o que apresentou as maiores medidas de qualidade do ajuste foi o modelo ajustado com o algorítimo Random Forest e tanto o modelo ajustado pelo algorítimo knn quanto o modelo linear generalizado com função de ligação “logit” também apresentaram acurácia e coeficiente kappa próximos do apresentado no ajuste do Random Forest.\nPortanto, apesar dos ajustes, caso dois modelos não apresentem diferença estatisticamente significante e o tempo computacional gasto para o ajuste de ambos for muito diferente pode ser que ser que tenhamos um modelo candidato para:\nc( knn= time_knn,rf = time_rf,nb = time_nb,glm = time_glm) ## Time differences in secs ## knn rf nb glm ## 2.463859 8.992998 7.140375 1.377073 O modelo linear generalizado foi o que apresentou o menor tempo computacional e foi o que apresentou o terceiro maior registro para os as medidas de qualidade do ajuste dos modelos, portanto esse modelo será avaliado com mais cuidado em seguida para saber se ele será o modelo selecionado\nObs.: Sou suspeito para falar mas dentre esses modelos eu teria preferência por este modelo de qualquer maneira por não se tratar de uma “caixa preta,” da qual todos os efeitos de cada parâmetro ajustado podem ser interpretado, além de obter medidas como razões de chance que ajudam bastante na compreensão dos dados.\nComparando de forma visual:\nsplom(resamps) Assim fica mais claro o como o ajuste dos modelos Random Forest, K-NN e GLM se destacaram quando avaliados em relação a acurácia apresentada.\nVejamos a seguir como foi a distribuição dessas medidas de acordo com cada modelo através de boxplots:\nbwplot(resamps) Note que além de apresentar os ajustes com menor acurácia (e elevada taxa de falsos negativos) o algorítimo Naive Bayes foi o que apresentou a maior variação interquartil das medidas de qualidade do ajuste do modelo.\nPara finalizar a análise visual vamos obter as diferenças entre os modelos com a função diff() e em seguida conferir de maneira visual o comportamento dessas informações:\ndifValues \u0026lt;- diff(resamps) # plot: bwplot(difValues) Observe que tanto o modelo logístico quando o ajuste com o algorítimo K-NN apresentaram valores muito próximos dos valores do ajuste do Random Forest e como já vimos o Random Forest foi o modelo que levou maior tempo computacional para ser ajustado, portanto vamos conferir a seguir se existe diferença estatisticamente significante entre os valores obtidos através de cada um dos ajustes e decidir qual dos modelos se apresentou de maneira mais adequada para nosso caso:\nresamps$values %\u0026gt;% select_if(is.numeric) %\u0026gt;% purrr::map(function(x) shapiro.test(x)) ## $`knn~Accuracy` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.87602, p-value = 0.1174 ## ## ## $`knn~Kappa` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.87418, p-value = 0.1118 ## ## ## $`rf~Accuracy` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.53165, p-value = 8.564e-06 ## ## ## $`rf~Kappa` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.53234, p-value = 8.727e-06 ## ## ## $`nb~Accuracy` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.80077, p-value = 0.01482 ## ## ## $`nb~Kappa` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.81793, p-value = 0.02392 ## ## ## $`glm~Accuracy` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.6429, p-value = 0.0001803 ## ## ## $`glm~Kappa` ## ## Shapiro-Wilk normality test ## ## data: x ## W = 0.64123, p-value = 0.0001722 Como a hipótese de normalidade não foi rejeitada para nenhuma das amostras de acurácias registradas, vejamos se existe diferença estatisticamente significante entre as médias dessas medidas de qualidade para cada modelo:\nt.test(resamps$values$`rf~Accuracy`,resamps$values$`knn~Accuracy`, paired = T) ## ## Paired t-test ## ## data: resamps$values$`rf~Accuracy` and resamps$values$`knn~Accuracy` ## t = 3.9961, df = 9, p-value = 0.003129 ## alternative hypothesis: true difference in means is not equal to 0 ## 95 percent confidence interval: ## 0.0061678 0.0222614 ## sample estimates: ## mean of the differences ## 0.0142146 Rejeita a hipótese de que as médias das acurácias calculadas para o ajuste do algorítimo Random Forest e K-NN foram iguais\nt.test(resamps$values$`rf~Accuracy`,resamps$values$`glm~Accuracy`, paired = T) ## ## Paired t-test ## ## data: resamps$values$`rf~Accuracy` and resamps$values$`glm~Accuracy` ## t = 0.43326, df = 9, p-value = 0.675 ## alternative hypothesis: true difference in means is not equal to 0 ## 95 percent confidence interval: ## -0.003768926 0.005554640 ## sample estimates: ## mean of the differences ## 0.0008928571 Novamente, rejeita-se a hipótese de que as médias das acurácias calculadas para o ajuste do algorítimo Random Forest e do modelo de logístico foram iguais\nt.test(resamps$values$`knn~Accuracy`,resamps$values$`glm~Accuracy`, paired = T) ## ## Paired t-test ## ## data: resamps$values$`knn~Accuracy` and resamps$values$`glm~Accuracy` ## t = -4.0077, df = 9, p-value = 0.003074 ## alternative hypothesis: true difference in means is not equal to 0 ## 95 percent confidence interval: ## -0.020841197 -0.005802292 ## sample estimates: ## mean of the differences ## -0.01332174 Já para a comparação entre as médias das acurácias calculadas para o algorítimo K-NN e para o modelo logístico não houve evidências estatísticas para se rejeitas a hipótese de que ambas as médias são iguais, o que nos sugere o modelo logístico como o segundo melhor candidato como modelo de classificação para este problema com estes dados.\nEntão a escolha ficará a critério do que é mais importante. Caso o tempo computacional fosse uma medida que tivesse mais importância do que a pequena superioridade de acurácia apresentada pelo algorítimo Random Forest, escolheria o modelo logístico, porém como neste caso os 7.61592507362366 segundos a mais para ajustar o modelo não fazem diferença para mim, fico com o modelo Random Forest.\nEste post trás alguns dos conceitos que venho estudado e existem muitos tópicos apresentados aqui que podem (e devem) ser estudados com mais profundidade, espero que tenha gostado!\nPerguntas frequentes Quantos tweets foram coletados para comparar Brasil e Argentina?\nForam coletados os últimos 4.000 tweets contendo o termo \"brasil\" e os últimos 4.000 tweets contendo o termo \"argentina\", obtidos via API do Twitter com os pacotes twitteR e ROAuth.\nQual modelo de Machine Learning teve o melhor desempenho na classificação dos tweets?\nO Random Forest apresentou a maior acurácia, com 100% no conjunto de teste, seguido de perto pelo modelo GLM (regressão logística), que teve acurácia de 99,8% e o menor tempo computacional entre os quatro modelos testados.\nQual pacote foi usado para a análise de sentimentos em português?\nFoi usado o pacote lexiconPT, disponível no CRAN, que fornece um léxico de polaridade em português permitindo classificar palavras como positivas, negativas ou neutras.\nReferências obs.: links mensionados no corpo do texto\nKuhn, Max. 2018. The Caret Package. https://topepo.github.io/caret/index.html. Silge; Robinson, Julia; David. 2018. Text Mining with R: A Tidy Approach. O'Reilly Media. Silva; Peres; Boscarioli, Leandro Augusto; Sarajane Marques; Clodis. 2016. Introdução à Mineração de Dados: Com Aplicações em R. Vol. 3. Elsevier Editora Ltda. ","date":"24 de junho de 2018","externalUrl":null,"permalink":"/post/2018-06-24-brasil-argentina-tidytext-ml/","section":"Posts","summary":" Brasil vs Argentina e Text Mining A copa do mundo esta ai novamente e como não poderia ser diferente, com ela surgem novos quintilhões de bytes todos os dias, saber analisar esses dados é um grande desafio pois a maioria dessa informação se encontra de forma não estruturada e além do desafio de captar esses dados ainda existem mais desafios que podem ser ainda maiores, como o de processá-los e obter respostas deles.\n","title":"Brasil x Argentina, tidytext e Machine Learning","type":"post"},{"content":"","date":"24 de junho de 2018","externalUrl":null,"permalink":"/tags/twitter/","section":"Tags","summary":"","title":"Twitter","type":"tags"},{"content":" A análise exploratória dos dados A análise exploratória dos dados (AED) foi um termo que ganhou bastante popularidade quando Tukey publicou o livro Exploratory Data Analysis em 1977 que tratava uma “busca por conhecimento antes da análise de dados de fato”. Ocorre quando busca-se obter informações ocultas sobre os dados, tais como: variação, anomalias, distribuição, tendências, padrões e relações\nAo iniciar uma análise de dados, começamos pela AED para a partir dai decidir como buscar qual solução para o problema. É importante frisar que a AED e a construção de gráficos não são a mesma coisa, mesmo a AED sendo altamente baseada em produção de gráficos como de dispersão, histogramas, boxplots etc.\nPor vezes a AED no R pode envolver a produção de longos scripts utilizando funções como as do pacote ggplot2 e mesmo sabendo que desejamos sempre criar o gráfico de maneira mais informativa e atraente possível, as vezes precisamos ter uma noção geral dos dados de forma rápida, não necessariamente tão detalhada e customizada de cara.\nTL;DR\nO pacote SmartEDA permite gerar uma AED completa com poucas linhas de código, incluindo a opção de um relatório extenso em apenas um comando (ExpReport()). O post usa a base A Theory of Extramarital Affairs, publicada pela The University of Chicago Press, cobrindo os 3 cenários de EDA do pacote: sem variável alvo, alvo contínuo e alvo categórico. Além da EDA, o post ajusta um modelo de regressão linear (stepwise AIC) e um Random Forest, comparando accuracy e kappa entre as abordagens. A vezes queremos apenas ter uma primeira impressão dos dados e em seguida pensar em quais os gráficos mais se adequariam para a entrega dos resultados que mesmo as funções base do R dependendo do caso também envolvem a confecção de longos scripts.\nExistem pacotes que auxiliam na hora de se fazer uma rápida análise exploratória, como o skimr e o DataExplorer. Porém estava pesquisando de existiam mais opções para uma rápida abordagem de AED e me deparei com esta vinheta, por Dayanand, Kiran, Ravi.\nEssa vinheta apresenta o pacote SmartEAD que trás uma série de funções que auxiliam na AED de forma bem prática. O pacote está disponível no CRAN.\nPara testar o pacote foi utilizada uma base de dados do artigo A Theory of Extramarital Affairs, publicado pela The University of Chicago Press.\nGostei tanto da proposta do pacote que resolvi preparar este post que conta com a explanação de alguns tópicos apresentados pelo autor, algumas explicações da teoria estatística apresentada na análise descritiva e exploratória dos dados e além da aplicação de algumas técnicas estatísticas e de machine learning para o entendimento da base de dados.\nSmartEDA Como ele pode ajudá-lo a criar uma análise de dados exploratória? O SmartEDA inclui várias funções personalizadas para executar uma análise exploratória inicial em qualquer dado de entrada. A saída gerada pode ser obtida em formato resumido e gráfico e os resultados também podem ser exportados como relatórios.\nO pacote SmartEDA ajuda a construir uma boa base de compreensão de dados, algumas de suas funcionalidades são:\nO pacote SmartEDA fará com que você seja capaz de aplicar diferentes tipos de EDA sem ter que lembre-se dos diferentes nomes dos pacotes R e escrever longos scripts R com esforço manual para preparar o relatório da EDA, permitindo o entendimento dos dados de maneira mais rápida Não há necessidade de categorizar as variáveis em caractere, numérico, fator etc. As funções do SmartEDA categorizam automaticamente todos os recursos no tipo de dados correto (caractere, numérico, fator etc.) com base nos dados de entrada. O pacote SmartEDA ajuda a obter a análise completa dos dados exploratórios apenas executando a função em vez de escrever um longo código r.\nCarregando o pacote: # install.packages(\u0026quot;SmartEDA\u0026quot;) library(\u0026quot;SmartEDA\u0026quot;) outros pactes que serão utilizados no post (incluindo um script com algumas funções, que estará disponível no meu github neste link).\nlibrary(knitr) # Para tabelas interativas library(DT) # Para tabelas interativas library(dplyr) # Para manipulacao de dados library(plotly) # Para gerar uma tabela library(psych) # para análise fatorial source(\u0026quot;functions.R\u0026quot;) # script com funcoes customizadas Base de dados utilizada: Estava à procura de uma base de dados para testar as funcionalidades do pacote SmartEAD quando um colega de trabalho me mostrou um artigo chamado A Theory of Extramarital Affairs, publicado pela The University of Chicago Press. Neste artigo é desenvolvido um modelo pelo estimador de Tobit que explica a alocação de um tempo do indivíduo entre o trabalho e dois tipos de atividades de lazer: tempo passou com o cônjuge e tempo gasto com o amante.\nNão conhecia o modelo proposto e em uma rápida pesquisa no Google notei que alguns dos dados utilizados nesse artigo estão disponíveis no pacote AER de Econometria Aplicada com R, que contém funções, conjuntos de dados, exemplos, demonstrações e vinhetas para o livro Applied Econometrics with R e como esses dados já foram tratados e estão “prontos para análise”, resolvi usar essa amostra pela conveniência.\nPortanto farei aqui uma análise exploratória e ao final de cada caso (sem variável reposta, com variável resposta numérica e com variável resposta binária), para ter uma breve intuição de como se comportam os dados irei primeiro utilizar um algorítimo de machine learning não supervisionado para o agrupamento das observações (sem considerar q já conhecemos a variável resposta), depois ajustar um* modelo de regressão linear simples* considerando a variável resposta como numérica e por fim o ajuste de um algorítimo de machine learning supervisonado de classificação após discretizar a variável resposta.\nA base de dados pode ser conferida a seguir:\nlibrary(AER) data(Affairs) Affairs %\u0026gt;% rmarkdown::paged_table() Neste post, a análise de dados será feita considerando a variável affairs (Quantas vezes envolvido em caso extraconjugal no último ano (aparentemente em 1977)) e a base de dados conta com as variáveis gênero, idade, anos de casado, se tem crianças, religiosidade, educação, ocupação e como avalia o casamento.\nInformações detalhadas podem ser conferidas na tabela a seguir, retirada do artigo apresentado:\nObs.: Essa tabela foi feita com o pacote plotly, o código pode ser conferido aqui.\nVisão geral dos dados Entendendo as dimensões do conjunto de dados, nomes de variáveis, resumo geral, variáveis ausentes e tipos de dados de cada variável com a função ExpData(), se o argumento Type = 1, visualização dos dados (os nomes das colunas são “Descrições”, “Obs.”), já se Type = 2, estrutura dos dados (os nomes das colunas são “S.no”, “VarName”, “VarClass”, “VarType”) :\n# Visao geral dos dados - Type = 1 ExpData(data=Affairs, type=1) # O tipo 1 é uma visão geral dos dados ## Descriptions Value ## 1 Sample size (nrow) 601 ## 2 No. of variables (ncol) 9 ## 3 No. of numeric/interger variables 7 ## 4 No. of factor variables 2 ## 5 No. of text variables 0 ## 6 No. of logical variables 0 ## 7 No. of identifier variables 0 ## 8 No. of date variables 0 ## 9 No. of zero variance variables (uniform) 0 ## 10 %. of variables having complete cases 100% (9) ## 11 %. of variables having \u0026gt;0% and \u0026lt;50% missing cases 0% (0) ## 12 %. of variables having \u0026gt;=50% and \u0026lt;90% missing cases 0% (0) ## 13 %. of variables having \u0026gt;=90% missing cases 0% (0) Conferindo o nome das variáveis e os tipos de cada uma:\n# Estrutura dos dados - Type = 2 ExpData(data=Affairs, type=2) # O tipo 2 é a estrutura dos dados ## Index Variable_Name Variable_Type Per_of_Missing No_of_distinct_values ## 1 1 affairs numeric 0 6 ## 2 2 gender factor 0 2 ## 3 3 age numeric 0 9 ## 4 4 yearsmarried numeric 0 8 ## 5 5 children factor 0 2 ## 6 6 religiousness integer 0 5 ## 7 7 education numeric 0 7 ## 8 8 occupation integer 0 7 ## 9 9 rating integer 0 5 Esta função fornece visão geral e estrutura dos quadros de dados.\nAnálise exploratória dos dados As funções a seguir apresentam a saída EDA para 3 casos diferentes de análise exploratória dos dados, são elas:\nA variável de destino não está definida\nA variável alvo é contínua\nA variável de destino é categórica\nPara fins ilustrativos, será feita inicialmente uma análise considerando que não existe variável resposta, em seguida será considerada a variável affairs como variável resposta e por fim, será feita uma transformação nesta variável resposta numérica de forma que ela seja discretizada da seguinte maneira:\n\\[ 1 \\text{ se já houve caso extraconjugal} \\\\ 0 \\text{ se não houve caso extraconjugal} \\]\nRelatório em uma linha Caso o interesse seja apenas ter uma noção geral dos dados de forma extremamente rápida, basta rodar a linha de código abaixo:\nExpReport(Affairs,op_file = \u0026quot;teste.html\u0026quot;) Antes de começar a explanar cada um dos casos, achei que seria legal frisar que além de tudo que será apresentado, existe a opção de se obter um relatório extenso sobre a análise exploratória dos dados em apenas uma linha!\nExemplo para o caso 1: a variável de destino não está definida Para ilustrar o primeiro caso, onde a variável destino não é definida, vamos supor que não existe uma variável alvo na nossa base de dados e estamos interessados em simplesmente obter uma visão geral enquanto pensamos em quais técnicas estatísticas serão utilizadas para avaliar nosso dataset.\nResumo das variáveis numéricas Resumo de de todas as variáveis numéricas:\nExpNumStat (Affairs, by = \u0026quot;A\u0026quot;, # Agrupar por A (estatísticas resumidas por Todos), G (estatísticas resumidas por grupo), GA (estatísticas resumidas por grupo e Geral) gp = NULL, # variável de destino, se houver, padrão NULL MesofShape = 2, # Medidas de formas (assimetria e curtose). Outlier = TRUE, # Calcular o limite inferior, o limite superior e o número de outliers round = 2) # Arredondar ## Vname Group ## 1 1 All Podemos ver que não existem variáveis negativas e a única variável que apresentou “zero” foi a variável resposta. Nenhum registro como Inf ou como NA e além das medidas descritivas também podemos notar as medidas de skweness e kurtosis. Alguns comentários sobre essas medidas:\nMedidas de forma para dar uma avaliação detalhada dos dados. Explica a quantidade e a direção do desvio.\nKurotsis explica o quão alto e afiado é o pico central (Achatamento). Skewness não tem unidades: mas um número, como um escore z (medida da assimetria) Onde:\nKurtose:\nA curtose é uma medida de forma que caracteriza o achatamento da curva da função de distribuição de probabilidade, Assim:\nSe o valor da curtose for = 0 (ou 3, pela segunda definição), então tem o mesmo achatamento que a distribuição normal. Chama-se a estas funções de mesocúrticas Se o valor é \u0026gt; 0 (ou \u0026gt; 3), então a distribuição em questão é mais alta (afunilada) e concentrada que a distribuição normal. Diz-se que esta função probabilidade é leptocúrtica, ou que a distribuição tem caudas pesadas (o significado é que é relativamente fácil obter valores que não se aproximam da média a vários múltiplos do desvio padrão) Se o valor é \u0026lt; 0 (ou \u0026lt; 3), então a função de distribuição é mais “achatada” que a distribuição normal. Chama-se-lhe platicúrtica Skewness:\nO Skewness mede a assimetria das caudas da distribuição. Distribuições assimétricas que tem uma cauda mais “pesada” que a outra apresentam obliquidade. Distribuições simétricas tem obliquidade zero. Assim:\nSe v\u0026gt;0, então a distribuição tem uma cauda direita (valores acima da média) mais pesada Se v\u0026lt;0, então a distribuição tem uma cauda esquerda (valores abaixo da média) mais pesada Se v=0, então a distribuição é aproximadamente simétrica (na terceira potência do desvio em relação à média). Distribuições de variáveis numéricas Representação gráfica de todos os recursos numéricos com gráfico de densidade (uni variada):\n# Nota: Variável excluída (se o valor único da variável for menor ou igual a 10 [im = 10]) ExpNumViz(Affairs, Page=c(2,2), # padrão de saída. sample=NULL) # seleção aleatória de plots ## $`0` Exibidos os gráficos com as densidades das variáveis numéricas. Como podemos ver a maioria da amostra não registrou caso extraconjugal, a maioria tem de 12 ou mais anos de casado. A média amostral da idade dos indivíduos é de aproximadamente 32 anos apresentando leve assimetria com cauda a direita. As demais variáveis podem ser conferidas visualmente.\nResumo de variáveis categóricas Essa função selecionará automaticamente variáveis categóricas e gerará frequência ou tabelas cruzadas com base nas entradas do usuário. A saída inclui contagens, porcentagens, total de linhas e total de colunas.\nFrequência para todas as variáveis independentes categóricas:\nExpCTable(Affairs, Target=NULL) ## Variable Valid Frequency Percent CumPercent ## 1 gender female 315 52.41 52.41 ## 2 gender male 286 47.59 100.00 ## 3 gender TOTAL 601 NA NA ## 4 children no 171 28.45 28.45 ## 5 children yes 430 71.55 100.00 ## 6 children TOTAL 601 NA NA ## 7 affairs 0 451 75.04 75.04 ## 8 affairs 1 34 5.66 80.70 ## 9 affairs 12 38 6.32 87.02 ## 10 affairs 2 17 2.83 89.85 ## 11 affairs 3 19 3.16 93.01 ## 12 affairs 7 42 6.99 100.00 ## 13 affairs TOTAL 601 NA NA ## 14 age 17.5 6 1.00 1.00 ## 15 age 22 117 19.47 20.47 ## 16 age 27 153 25.46 45.93 ## 17 age 32 115 19.13 65.06 ## 18 age 37 88 14.64 79.70 ## 19 age 42 56 9.32 89.02 ## 20 age 47 23 3.83 92.85 ## 21 age 52 21 3.49 96.34 ## 22 age 57 22 3.66 100.00 ## 23 age TOTAL 601 NA NA ## 24 yearsmarried 0.125 11 1.83 1.83 ## 25 yearsmarried 0.417 10 1.66 3.49 ## 26 yearsmarried 0.75 31 5.16 8.65 ## 27 yearsmarried 1.5 88 14.64 23.29 ## 28 yearsmarried 10 70 11.65 34.94 ## 29 yearsmarried 15 204 33.94 68.88 ## 30 yearsmarried 4 105 17.47 86.35 ## 31 yearsmarried 7 82 13.64 99.99 ## 32 yearsmarried TOTAL 601 NA NA ## 33 religiousness 1 48 7.99 7.99 ## 34 religiousness 2 164 27.29 35.28 ## 35 religiousness 3 129 21.46 56.74 ## 36 religiousness 4 190 31.61 88.35 ## 37 religiousness 5 70 11.65 100.00 ## 38 religiousness TOTAL 601 NA NA ## 39 education 12 44 7.32 7.32 ## 40 education 14 154 25.62 32.94 ## 41 education 16 115 19.13 52.07 ## 42 education 17 89 14.81 66.88 ## 43 education 18 112 18.64 85.52 ## 44 education 20 80 13.31 98.83 ## 45 education 9 7 1.16 99.99 ## 46 education TOTAL 601 NA NA ## 47 occupation 1 113 18.80 18.80 ## 48 occupation 2 13 2.16 20.96 ## 49 occupation 3 47 7.82 28.78 ## 50 occupation 4 68 11.31 40.09 ## 51 occupation 5 204 33.94 74.03 ## 52 occupation 6 143 23.79 97.82 ## 53 occupation 7 13 2.16 99.98 ## 54 occupation TOTAL 601 NA NA ## 55 rating 1 16 2.66 2.66 ## 56 rating 2 66 10.98 13.64 ## 57 rating 3 93 15.47 29.11 ## 58 rating 4 194 32.28 61.39 ## 59 rating 5 232 38.60 99.99 ## 60 rating TOTAL 601 NA NA Obs.: NA significa Not Applicable\nDistribuições de variáveis categóricas Essa função varre automaticamente cada variável e cria um gráfico de barras para variáveis categóricas.\nGráficos de barra para todas as variáveis categóricas\nExpCatViz(Affairs, fname=NULL, # Nome do arquivo de saida, default é pdf clim=10,# categorias máximas a incluir nos gráficos de barras. margin=2,# índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em colunas Page = c(2,1), # padrao de saida sample=4) # seleção aleatória de plot ## $`0` Machine Lerning usando algorítimo não supervisionado de agrupamento Apenas para efeitos ilustrativos, como estamos supondo que não temos a variável resposta vou remover a coluna affairs do data set e considerarei apenas as variáveis numéricas para fazer uma análise multivariada com o algorítimo de machine learning kmeans.\nA função plot_kmeans() pode ser encontrada em meu github no repositório aberto de funções.\nVejamos os resultados:\nplot_kmeans(Affairs[,-c(1)] %\u0026gt;% select_if(is.numeric) , 2) Como podemos observar, foram detectados dois grupos no conjunto de dados. O ideal agora seria fazer uma AED desses clusters identificados e avaliar qual o comportamento dos grupos formados mas como essa variável foi omitida e a seguir discutiremos a avaliação da base diante de da variável resposta, deixo essas análises aos curiosos de plantão.\nMais informações sobre análise multivariava podem ser encontrada no meu post sobre Análise Multivariada com r e também em um kernel que escrevi para a plataforma kaggle.\nAlém disso disponibilizo uma aplicação Shiny que criei a algum tempo para PCA (Análise de componentes Principais) e tarefa de machine learning com agrupamento nenste link.\nExemplo para o caso 2: A variável de destino é contínua Agora vamos considerar que estamos diante de um desfecho onde a variável alvo é contínua, para isso será considerada a variável affairs como variável alvo.\nResumo da variável dependente contínua Descrição da variável affairs:\nsummary(Affairs[,\u0026quot;affairs\u0026quot;]) ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## 0.000 0.000 0.000 1.456 0.000 12.000 Resumo das variáveis numéricas Estatísticas de resumo quando a variável dependente é contínua Preço.\nExpNumStat(Affairs, by=\u0026quot;A\u0026quot;, # Agrupar por A (estatísticas resumidas por Todos), G (estatísticas resumidas por grupo), GA (estatísticas resumidas por grupo e Geral) Qnt=seq(0,1,0.1), # padrão NULL. Quantis especificados [c (0,25,0,75) encontrarão os percentis 25 e 75] MesofShape=1, # Medidas de formas (assimetria e curtose) Outlier=TRUE, # Calcular limite superior , inferior e numero de outliers round=2) # Arredondamento ## Vname Group ## 1 1 All #Se a variável de destino for contínua, as estatísticas de resumo adicionarão a coluna de correlação (Correlação entre a variável de destino e todas as variáveis independentes) Distribuições de variáveis numéricas Representação gráfica de todas as variáveis numéricas com gráficos de dispersão (bivariada)\nGráfico de dispersão entre todas as variáveis numéricas e a variável de destino affairs. Esta trama ajuda a examinar quão bem uma variável alvo está correlacionada com variáveis dependentes.\nVariável dependente é affairs (contínuo).\nExpNumViz(Affairs, target=\u0026quot;affairs\u0026quot;, # Variavel alvo nlim=4, # a variável numérica com valor exclusivo é maior que 4 Page=c(2,2), # formato de saida sample=NULL) # selecionado aleatoriamente 8 gráficos de dispersão ## $`0` Resumo de variáveis categóricas Resumo de variáveis categóricas de acordo com a frequência para todas as variáveis independentes categóricas por Affairs\n##bin=4, descretized 4 categories based on quantiles ExpCTable(Affairs, Target=\u0026quot;affairs\u0026quot;) ## VARIABLE CATEGORY affairs:(-0.012,4] affairs:(4,8] affairs:(8,12] TOTAL ## 1 gender female 273 22 20 315 ## 2 gender male 248 20 18 286 ## 3 gender TOTAL 521 42 38 601 ## 4 children no 157 7 7 171 ## 5 children yes 364 35 31 430 ## 6 children TOTAL 521 42 38 601 ## 7 affairs 0 451 0 0 451 ## 8 affairs 1 34 0 0 34 ## 9 affairs 12 0 0 38 38 ## 10 affairs 2 17 0 0 17 ## 11 affairs 3 19 0 0 19 ## 12 affairs 7 0 42 0 42 ## 13 affairs TOTAL 521 42 38 601 ## 14 age 17.5 4 0 2 6 ## 15 age 22 112 4 1 117 ## 16 age 27 138 9 6 153 ## 17 age 32 95 11 9 115 ## 18 age 37 71 8 9 88 ## 19 age 42 44 6 6 56 ## 20 age 47 19 1 3 23 ## 21 age 52 17 2 2 21 ## 22 age 57 21 1 0 22 ## 23 age TOTAL 521 42 38 601 ## 24 yearsmarried 0.125 11 0 0 11 ## 25 yearsmarried 0.417 10 0 0 10 ## 26 yearsmarried 0.75 29 0 2 31 ## 27 yearsmarried 1.5 85 2 1 88 ## 28 yearsmarried 10 57 8 5 70 ## 29 yearsmarried 15 165 17 22 204 ## 30 yearsmarried 4 94 9 2 105 ## 31 yearsmarried 7 70 6 6 82 ## 32 yearsmarried TOTAL 521 42 38 601 ## 33 religiousness 1 37 5 6 48 ## 34 religiousness 2 138 14 12 164 ## 35 religiousness 3 105 13 11 129 ## 36 religiousness 4 177 6 7 190 ## 37 religiousness 5 64 4 2 70 ## 38 religiousness TOTAL 521 42 38 601 ## 39 education 12 36 2 6 44 ## 40 education 14 139 6 9 154 ## 41 education 16 108 5 2 115 ## 42 education 17 72 9 8 89 ## 43 education 18 94 11 7 112 ## 44 education 20 67 9 4 80 ## 45 education 9 5 0 2 7 ## 46 education TOTAL 521 42 38 601 ## 47 occupation 1 101 6 6 113 ## 48 occupation 2 13 0 0 13 ## 49 occupation 3 39 5 3 47 ## 50 occupation 4 60 4 4 68 ## 51 occupation 5 177 12 15 204 ## 52 occupation 6 120 13 10 143 ## 53 occupation 7 11 2 0 13 ## 54 occupation TOTAL 521 42 38 601 ## 55 rating 1 11 1 4 16 ## 56 rating 2 43 8 15 66 ## 57 rating 3 80 9 4 93 ## 58 rating 4 169 18 7 194 ## 59 rating 5 218 6 8 232 ## 60 rating TOTAL 521 42 38 601 Distribuições de variáveis categóricas Essa função varre automaticamente cada variável e cria um gráfico de barras para variáveis categóricas.\nGráficos de barra para todas as variáveis categóricas\nExpCatViz(Affairs, target=\u0026quot;affairs\u0026quot;, # Variavel target fname=NULL, # Nome do arquivo de saida, default é pdf clim=10,# categorias máximas a incluir nos gráficos de barras. margin=2,# índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em colunas Page = c(2,1), # padrao de saida sample=4) # seleção aleatória de plot ## $`0` Avaliando a correlação entre as variáveis library(ggplot2) library(dplyr) library(GGally) data(\u0026quot;Affairs\u0026quot;) #Correlaçoes cruzadas Affairs%\u0026gt;% select(age:rating,affairs)%\u0026gt;% ggpairs(lower = list(continuous = my_fn,combo=wrap(\u0026quot;facethist\u0026quot;, binwidth=1), continuous=wrap(my_bin, binwidth=0.25)),aes(fill=affairs))+theme_bw() ggcorr(Affairs,label = T,nbreaks = 5,label_round = 4) Modelo de regressão linear usando stepwiseAIC Por fim, vamos ajustar um modelo de regressão linear para entender quais são as variáveis significativas para explicar a variação da variável resposta e qual o efeito de cada uma dessas variáveis explicativas no nosso desfecho. Técnicas de correlação e modelagem como essas também aparecem em aplicações mais práticas, como no bot que desenvolvi para enviar alertas de Machine Learning sobre ações e bitcoin direto no smartphone.\nCom o R base é possível ajustar um modelo de regressão linear simples utilizando a função lm() e em seguida usar a função step() para utilizar técnicas como stepwise, porém como quero utilizar também a técnica de validação cruzada. Para isso vou utilizar o pacote caret, muito famoso por facilitar o ajuste de modelos de machine learning (ou mesmo modelos estatísticos tradicionais).\nAlém disso estou usando as transformações center(), que subtrai a média dos dados e scale() divide pelo desvio padrão.\ndata(\u0026quot;Affairs\u0026quot;) library(caret) set.seed(123) index \u0026lt;- sample(1:2,nrow(Affairs),replace=T,prob=c(0.8,0.2)) train = Affairs[index==1,] %\u0026gt;%as.data.frame() test = Affairs[index==2,] %\u0026gt;%as.data.frame() # Setando os parâmetros para o controle do ajuste do modelo: fitControl \u0026lt;- trainControl(method = \u0026quot;repeatedcv\u0026quot;, # 10fold cross validation number = 10, repeats=5 # do 5 repititições of cv ) # Regressão Linear com Stepwise set.seed(825) lmFit \u0026lt;- train(affairs ~ ., data = train, method = \u0026quot;lmStepAIC\u0026quot;, trControl = fitControl, preProc = c(\u0026quot;center\u0026quot;, \u0026quot;scale\u0026quot;),trace=F) summary(lmFit) ## ## Call: ## lm(formula = .outcome ~ age + yearsmarried + religiousness + ## occupation + rating, data = dat) ## ## Residuals: ## Min 1Q Median 3Q Max ## -5.1452 -1.7819 -0.7601 0.2719 11.3518 ## ## Coefficients: ## Estimate Std. Error t value Pr(\u0026gt;|t|) ## (Intercept) 1.4146 0.1401 10.096 \u0026lt; 2e-16 *** ## age -0.6890 0.2291 -3.007 0.002779 ** ## yearsmarried 1.1058 0.2302 4.804 2.09e-06 *** ## religiousness -0.5121 0.1455 -3.519 0.000475 *** ## occupation 0.3858 0.1445 2.669 0.007858 ** ## rating -0.7830 0.1470 -5.326 1.55e-07 *** ## --- ## Signif. codes: 0 \u0026#39;***\u0026#39; 0.001 \u0026#39;**\u0026#39; 0.01 \u0026#39;*\u0026#39; 0.05 \u0026#39;.\u0026#39; 0.1 \u0026#39; \u0026#39; 1 ## ## Residual standard error: 3.07 on 474 degrees of freedom ## Multiple R-squared: 0.144, Adjusted R-squared: 0.135 ## F-statistic: 15.95 on 5 and 474 DF, p-value: 1.542e-14 Como podemos ver as variáveis Idade, Anos de casado, religiosidade, ocupação e como avaliam o próprio relacionamento se apresentaram significantes\nComo o \\(R^2=0,144\\), conclui-se que \\(14,4%\\) da variação da quantidade de vezes que foi envolvida em caso extraconjugal no último ano é explicada pelo modelo ajustado.\nObservando a coluna das estimativas, podemos notar o quanto varia a quantidade de vezes que foi envolvido em caso extraconjugal ao aumentar em 1 unidade cada uma das variáveis explicativas.\nAlém disso o valor p obtido através da estatística F foi menor do que \\(\\alpha = 0.05\\), o que implica que pelo menos uma das variáveis explicativas tem relação significativa com a variável resposta.\nSelecionando apenas as variáveis selecionadas com o ajuste do modelo:\ntrain=as.data.frame(train[,c(1,3,4,6,8,9)]) test=as.data.frame(test[,c(1,3,4,6,8,9)]) Diagnóstico do modelo Existem varias formas e técnicas de se avaliar o ajuste de um modelo e como o foco deste post é apresentar as utilidades do pacote SmartEAD irei fazer uma avaliação muito breve sobre os resíduos, apresento mais algumas maneiras no post sobre pacotes do R para avaliar o ajuste de modelos.\nAvaliando residuos library(GGally) # calculate all residuals prior to display residuals \u0026lt;- lapply(train[2:ncol(train)], function(x) { summary(lm(affairs ~ x, data = train))$residuals }) # add a \u0026#39;fake\u0026#39; column train$Residual \u0026lt;- seq_len(nrow(train)) # calculate a consistent y range for all residuals y_range \u0026lt;- range(unlist(residuals)) # plot the data ggduo( train, 2:6, c(1,7), types = list(continuous = lm_or_resid) )+ theme_bw() train=train%\u0026gt;% select(-Residual) Neste gráfico é possível observar como se comportam os ajustes de modelos lineares de cada variável explicativa em relação à variável resposta e além disso na segunda linha é possível notar o comportamento dos resíduos no modelo.\nUma das suposições do ajuste de um modelo linear normal é de que \\(\\epsilon \\sim N(0,\\sigma^2)\\) e visualmente parece que essa condição não deve ser atendida, pois esperaríamos algo como uma “nuvem” aleatória de pontos em torno de zero.\nResiduos e medidas de influencia Além da suposição da normalidade dos resíduos, existem ainda mais detalhes do comportamento desses erros, uma breve apresentação no gráfico a seguir:\nlibrary(ggfortify) autoplot(lmFit$finalModel, which = 1:6, data = train, colour = \u0026#39;affairs\u0026#39;, label.size = 3, ncol = 3)+theme_classic() Pelo que parece no gráfico com título “Normal Q-Q”, as variáveis associadas à variável resposta com valores acima de 6 se comportam de forma inesperadas quando comparadas com os quantis teóricos.\nExemplo para o caso 3: a variável de destino é categórica Para finalizar a avaliação da base de dados, a Variável alvo será discretizado de tal forma:\n\\[ 1 = \\text{se affairs} \u0026gt; 0\\\\ 0 = c.c. \\]\nEssa transformação será utilizada apenas com fins ilustrativos do algorítimo de árvore de decisões, que está ficando muito comum na ciência de dados como uma tarefa supervisionada de machine learning.\nAffairs = Affairs %\u0026gt;% mutate(daffairs = ifelse(Affairs$affairs!=0,1,0)) %\u0026gt;% mutate(daffairs = as.factor(daffairs))%\u0026gt;% select(-affairs) levels(Affairs$daffairs) = c(\u0026quot;Não\u0026quot;, \u0026quot;Sim\u0026quot;) Resumo das variáveis numéricas Resumo de todas as variáveis numéricas\nExpNumStat(Affairs, by=\u0026quot;A\u0026quot;, # Agrupar por A (estatísticas resumidas por Todos), G (estatísticas resumidas por grupo), GA (estatísticas resumidas por grupo e Geral) gp=\u0026quot;daffairs\u0026quot;, # Variavel alvo Qnt=seq(0,1,0.1), # padrão NULL. Quantis especificados [c (0,25,0,75) encontrarão os percentis 25 e 75] MesofShape=1, # Medidas de formas (assimetria e curtose) Outlier=TRUE, # Calcular limite superior , inferior e numero de outliers round=2) # Arredondamento ## Vname Group ## 1 1 All Distribuições de variáveis numéricas Box plots para todas as variáveis numéricas vs variável dependente categórica - Comparação bivariada apenas com categorias\nBoxplot para todos os atributos numéricos por cada categoria de affair\nExpNumViz(Affairs, target=\u0026quot;daffairs\u0026quot;) # amostra de variaveis para o resumo ## [[1]] ## ## [[2]] ## ## [[3]] ## ## [[4]] ## ## [[5]] ## ## [[6]] Resumo das variáveis categóricas Tabulação cruzada com variável de destino com tabelas customizadas entre todas as variáveis independentes categóricas e a variável de destino daffairs:\nExpCTable(Affairs, Target=\u0026quot;daffairs\u0026quot;, # variavel alvo margin=1, # 1 para proporcoes por linha, 2 para colunas clim=10, # maximo de categorias consideradas por frequencia/ custom table round=2, # arredondar per=F) # valores percentuais. Tabela padrão dará contagens. ## VARIABLE CATEGORY daffairs:Não daffairs:Sim TOTAL ## 1 gender female 243 72 315 ## 2 gender male 208 78 286 ## 3 gender TOTAL 451 150 601 ## 4 children no 144 27 171 ## 5 children yes 307 123 430 ## 6 children TOTAL 451 150 601 ## 7 age 17.5 3 3 6 ## 8 age 22 101 16 117 ## 9 age 27 117 36 153 ## 10 age 32 77 38 115 ## 11 age 37 65 23 88 ## 12 age 42 38 18 56 ## 13 age 47 16 7 23 ## 14 age 52 15 6 21 ## 15 age 57 19 3 22 ## 16 age TOTAL 451 150 601 ## 17 yearsmarried 0.125 10 1 11 ## 18 yearsmarried 0.417 9 1 10 ## 19 yearsmarried 0.75 28 3 31 ## 20 yearsmarried 1.5 76 12 88 ## 21 yearsmarried 10 49 21 70 ## 22 yearsmarried 15 142 62 204 ## 23 yearsmarried 4 78 27 105 ## 24 yearsmarried 7 59 23 82 ## 25 yearsmarried TOTAL 451 150 601 ## 26 religiousness 1 28 20 48 ## 27 religiousness 2 123 41 164 ## 28 religiousness 3 86 43 129 ## 29 religiousness 4 157 33 190 ## 30 religiousness 5 57 13 70 ## 31 religiousness TOTAL 451 150 601 ## 32 education 12 31 13 44 ## 33 education 14 119 35 154 ## 34 education 16 95 20 115 ## 35 education 17 62 27 89 ## 36 education 18 79 33 112 ## 37 education 20 60 20 80 ## 38 education 9 5 2 7 ## 39 education TOTAL 451 150 601 ## 40 occupation 1 90 23 113 ## 41 occupation 2 10 3 13 ## 42 occupation 3 32 15 47 ## 43 occupation 4 47 21 68 ## 44 occupation 5 160 44 204 ## 45 occupation 6 104 39 143 ## 46 occupation 7 8 5 13 ## 47 occupation TOTAL 451 150 601 ## 48 rating 1 8 8 16 ## 49 rating 2 33 33 66 ## 50 rating 3 66 27 93 ## 51 rating 4 146 48 194 ## 52 rating 5 198 34 232 ## 53 rating TOTAL 451 150 601 Distribuições de variáveis categóricas Gráfico de barras empilhadas com barras verticais ou horizontais para todas as variáveis categóricas\nExpCatViz(Affairs, target=\u0026quot;daffairs\u0026quot;, fname=NULL, # Nome do arquivo de saida, default é pdf clim=10,# categorias máximas a incluir nos gráficos de barras. margin=2,# índice, 1 para proporções baseadas em linha e 2 para proporções baseadas em colunas Page = c(2,1), # padrao de saida sample=4) # seleção aleatória de plot ## $`0` Valor da informação IV é o peso da evidência e valores da informação, \\(ln(odss) \\times(pct0 - pct1)\\) onde \\(pct1 =\\frac{\\text{\u0026quot;boas observações\u0026quot;}}{\\text{\u0026quot;total boas observações\u0026quot;}}\\); \\(pct0 = \\frac{\u0026quot;\\text{observações ruins\u0026quot;} }{ \\text{\u0026quot;total de observações ruins\u0026quot;}}\\) e $odds = $\nExpCatStat(Affairs %\u0026gt;% mutate(daffairs = if_else(daffairs==\u0026quot;Não\u0026quot;, 0, 1)) , Target=\u0026quot;daffairs\u0026quot;, result = \u0026quot;IV\u0026quot;) %\u0026gt;% select(-one_of(\u0026quot;Target\u0026quot;,\u0026quot;Ref_1\u0026quot;,\u0026quot;Ref_0\u0026quot;)) ## Variable Class Out_1 Out_0 TOTAL Per_1 Per_0 Odds WOE IV ## 1 gender.1 female 72 243 315 0.48 0.54 0.79 -0.12 0.01 ## 2 gender.2 male 78 208 286 0.52 0.46 1.27 0.12 0.01 ## 3 children.1 no 27 144 171 0.18 0.32 0.47 -0.58 0.08 ## 4 children.2 yes 123 307 430 0.82 0.68 2.14 0.19 0.03 ## 5 age.1 17.5 3 3 6 0.02 0.01 3.05 0.69 0.01 ## 6 age.2 22 16 101 117 0.11 0.22 0.41 -0.69 0.08 ## 7 age.3 27 36 117 153 0.24 0.26 0.90 -0.08 0.00 ## 8 age.4 32 38 77 115 0.25 0.17 1.65 0.39 0.03 ## 9 age.5 37 23 65 88 0.15 0.14 1.08 0.07 0.00 ## 10 age.6 42 18 38 56 0.12 0.08 1.48 0.41 0.02 ## 11 age.7 47 7 16 23 0.05 0.04 1.33 0.22 0.00 ## 12 age.8 52 6 15 21 0.04 0.03 1.21 0.29 0.00 ## 13 age.9 57 3 19 22 0.02 0.04 0.46 -0.69 0.01 ## 14 yearsmarried.1 0.125 1 10 11 0.01 0.02 0.30 -0.69 0.01 ## 15 yearsmarried.2 0.417 1 9 10 0.01 0.02 0.33 -0.69 0.01 ## 16 yearsmarried.3 0.75 3 28 31 0.02 0.06 0.31 -1.11 0.04 ## 17 yearsmarried.4 1.5 12 76 88 0.08 0.17 0.43 -0.76 0.07 ## 18 yearsmarried.5 10 21 49 70 0.14 0.11 1.34 0.24 0.01 ## 19 yearsmarried.6 15 62 142 204 0.41 0.31 1.53 0.28 0.03 ## 20 yearsmarried.7 4 27 78 105 0.18 0.17 1.05 0.06 0.00 ## 21 yearsmarried.8 7 23 59 82 0.15 0.13 1.20 0.14 0.00 ## 22 religiousness.1 1 20 28 48 0.13 0.06 2.32 0.77 0.05 ## 23 religiousness.2 2 41 123 164 0.27 0.27 1.00 0.00 0.00 ## 24 religiousness.3 3 43 86 129 0.29 0.19 1.71 0.43 0.04 ## 25 religiousness.4 4 33 157 190 0.22 0.35 0.53 -0.46 0.06 ## 26 religiousness.5 5 13 57 70 0.09 0.13 0.66 -0.37 0.01 ## 27 education.1 12 13 31 44 0.09 0.07 1.29 0.25 0.00 ## 28 education.2 14 35 119 154 0.23 0.26 0.85 -0.13 0.00 ## 29 education.3 16 20 95 115 0.13 0.21 0.58 -0.48 0.04 ## 30 education.4 17 27 62 89 0.18 0.14 1.38 0.25 0.01 ## 31 education.5 18 33 79 112 0.22 0.18 1.33 0.20 0.01 ## 32 education.6 20 20 60 80 0.13 0.13 1.00 0.00 0.00 ## 33 education.7 9 2 5 7 0.01 0.01 1.21 0.00 0.00 ## 34 occupation.1 1 23 90 113 0.15 0.20 0.73 -0.29 0.01 ## 35 occupation.2 2 3 10 13 0.02 0.02 0.90 0.00 0.00 ## 36 occupation.3 3 15 32 47 0.10 0.07 1.45 0.36 0.01 ## 37 occupation.4 4 21 47 68 0.14 0.10 1.40 0.34 0.01 ## 38 occupation.5 5 44 160 204 0.29 0.35 0.75 -0.19 0.01 ## 39 occupation.6 6 39 104 143 0.26 0.23 1.17 0.12 0.00 ## 40 occupation.7 7 5 8 13 0.03 0.02 1.91 0.41 0.00 ## 41 rating.1 1 8 8 16 0.05 0.02 3.12 0.92 0.03 ## 42 rating.2 2 33 33 66 0.22 0.07 3.57 1.14 0.17 ## 43 rating.3 3 27 66 93 0.18 0.15 1.28 0.18 0.01 ## 44 rating.4 4 48 146 194 0.32 0.32 0.98 0.00 0.00 ## 45 rating.5 5 34 198 232 0.23 0.44 0.37 -0.65 0.14 Testes estatísticos Além de toda a informação visual e das estatísticas descritivas, ainda contamos com alguma função que fornece estatísticas resumidas para todas as colunas de caracteres ou categóricas no data frame\nExpCatStat(Affairs %\u0026gt;% mutate(daffairs = if_else(daffairs==\u0026quot;Não\u0026quot;, 0, 1)), Target=\u0026quot;daffairs\u0026quot;, # variavel alvo result = \u0026quot;Stat\u0026quot;) # resumo de estatisticas ## Variable Target Unique Chi-squared p-value df IV Value Cramers V ## 1 gender daffairs 2 1.334 0.248 1 0.02 0.05 ## 2 children daffairs 2 10.055 0.002 1 0.11 0.13 ## 3 age daffairs 9 17.771 0.023 8 0.15 0.17 ## 4 yearsmarried daffairs 8 17.177 0.016 7 0.17 0.17 ## 5 religiousness daffairs 5 19.354 0.001 4 0.16 0.18 ## 6 education daffairs 7 7.057 0.316 6 0.06 0.11 ## 7 occupation daffairs 7 6.718 0.348 6 0.04 0.11 ## 8 rating daffairs 5 41.433 0.000 4 0.35 0.26 ## Degree of Association Predictive Power ## 1 Very Weak Not Predictive ## 2 Weak Somewhat Predictive ## 3 Weak Somewhat Predictive ## 4 Weak Somewhat Predictive ## 5 Weak Somewhat Predictive ## 6 Weak Not Predictive ## 7 Weak Not Predictive ## 8 Moderate Highly Predictive Os critérios usados para classificação de poder preditivo variável categórico são\nSe o valor da informação for \u0026lt;0,03, então, poder de previsão = “Não Preditivo”\nSe o valor da informação é de 0,3 a 0,1, então o poder preditivo = “um pouco preditivo”\nSe o valor da informação for de 0,1 a 0,3, então, poder preditivo = “Medium Predictive”\nSe o valor da informação for\u0026gt; 0.3, então, poder preditivo = “Altamente Preditivo”\nNota para a variável rating que segundo essas regras, demonstrou alto poder preditivo.\nMachine Learning com Random Forest O algorítimo supervisionado de machine learning conhecido como Random Forest é uma grande caixa preta. Apresenta resultados muito robustos pois combina o resultado de várias árvores de decisões e pode ser facilmente aplicada com o pacote caret. Para quem quiser se aprofundar em modelos baseados em árvores, escrevi um estudo mais completo sobre esse tema com um desafio real do Kaggle.\nNo livro do pacote caret o algorítimo é apresentado da seguinte maneira: “segundo o pacote do R: Para cada árvore, a precisão da previsão na parte fora do saco dos dados é registrada. Então, o mesmo é feito após a permutação de cada variável preditora. A diferença entre as duas precisões é calculada pela média de todas as árvores e normalizada pelo erro padrão. Para a regressão, o MSE é calculado nos dados fora da bolsa para cada árvore e, em seguida, o mesmo é computado após a permutação de uma variável. As diferenças são calculadas e normalizadas pelo erro padrão. Se o erro padrão é igual a 0 para uma variável, a divisão não é feita.”\nNão entrarei em muitos detalhes sobre o algorítimo pois esta parte é apenas um demonstrativo dos diferentes cenários de análise exploratória dos dados. Serão comentadas apenas algumas métricas utilizadas.\nAjuste com o algorítimo Random Forest:\nlibrary(caret) set.seed(1) index \u0026lt;- sample(1:2,nrow(Affairs),replace=T,prob=c(0.8,0.2)) train = Affairs[index==1,] %\u0026gt;%as.data.frame() test = Affairs[index==2,] %\u0026gt;%as.data.frame() # Setando os parâmetros para o controle do ajuste do modelo: fitControl \u0026lt;- trainControl(method = \u0026quot;repeatedcv\u0026quot;, # 10fold cross validation number = 10 ) # Random Forest set.seed(825) antes = Sys.time() rfFit \u0026lt;- train(daffairs ~ ., data = train, method = \u0026quot;rf\u0026quot;, trControl = fitControl, trace=F, preProc = c(\u0026quot;center\u0026quot;, \u0026quot;scale\u0026quot;)) antes - Sys.time() # Para saber quanto tempo durou o ajuste ## Time difference of -13.38876 secs Resultados do ajuste:\nrfFit ## Random Forest ## ## 484 samples ## 8 predictor ## 2 classes: \u0026#39;Não\u0026#39;, \u0026#39;Sim\u0026#39; ## ## Pre-processing: centered (8), scaled (8) ## Resampling: Cross-Validated (10 fold, repeated 1 times) ## Summary of sample sizes: 436, 436, 435, 435, 435, 436, ... ## Resampling results across tuning parameters: ## ## mtry Accuracy Kappa ## 2 0.7539966 0.1369868 ## 5 0.7292942 0.1727691 ## 8 0.7231718 0.1613695 ## ## Accuracy was used to select the optimal model using the largest value. ## The final value used for the model was mtry = 2. Accurary e Kappa\nEssas são as métricas padrão usadas para avaliar algoritmos em conjuntos de dados de classificação binária.\nAccuray: é a porcentagem de classificar corretamente as instâncias fora de todas as instâncias. É mais útil em uma classificação binária do que problemas de classificação de várias classes, porque pode ser menos claro exatamente como a precisão é dividida entre essas classes (por exemplo, você precisa ir mais fundo com uma matriz de confusão). Kappa ou Kappa de Cohen é como a precisão da classificação, exceto que é normalizado na linha de base da chance aleatória em seu conjunto de dados. É uma medida mais útil para usar em problemas que têm um desequilíbrio nas classes (por exemplo, divisão de 70 a 30 para as classes 0 e 1 e você pode atingir 70% de precisão prevendo que todas as instâncias são para a classe 0). A seguir a “Variable Importance” de cada variável:\nrfImp = varImp(rfFit);rfImp ## rf variable importance ## ## Overall ## rating 100.00 ## age 94.66 ## religiousness 85.77 ## education 78.99 ## yearsmarried 67.41 ## occupation 62.48 ## gendermale 6.94 ## childrenyes 0.00 plot(rfImp) A função dimensiona automaticamente as pontuações de importância entre 0 e 100, os escores de importância da variável em Random Forest são medidas agregadas. Eles apenas quantificam o impacto do preditor, não o efeito específico, para isso utilizamos o ajuste um modelo paramétrico onde conseguimos estimar termos estruturais.\nÉ claro que existem muitos adentos a serem feitos tanto na forma como os dados foram apresentados no ajuste do modelo linear e no Random Forest, mas como a finalidade do post continua sendo apresentar o pacote SmartEAD, encerrarei a avaliação por aqui.\nCaso alguém queira entender com mais detalhes a avaliação de modelos de machine learning, talvez o livro do pacote caret seja uma alternativa interessante para ter uma noção geral.\nTodos os modelos estão errados, alguns são úteis - George Box\nNão conseguimos nenhum modelo útil que quantificasse as incertezas nas modelagens deste post mas conseguimos executar praticamente todas as funções do pacote SmartEAD e foi muito útil para conhecer a base em poucas linhas, obrigado Dayanand Ubrangala, Kiran R. e Ravi Prasad Kondapalli!\nReferências TUKEY, J. W. Exploratory Data Analysis. Reading: Addison-Wesley, 1977. KLEIBER, C.; ZEILEIS, A. Applied Econometrics with R. New York: Springer, 2008. Perguntas frequentes O que é o pacote SmartEDA e para que ele serve?\nO SmartEDA é um pacote do R disponível no CRAN que reúne funções prontas para realizar a análise exploratória de dados (AED) de forma rápida, cobrindo desde visão geral do dataset até gráficos de variáveis numéricas e categóricas.\nÉ possível gerar um relatório completo de AED com uma única linha de código?\nSim. A função ExpReport() gera um relatório extenso em HTML sobre a base de dados executando apenas um comando, como mostrado no post com ExpReport(Affairs, op_file = \"teste.html\").\nQual base de dados foi usada para ilustrar o SmartEDA?\nFoi usada a base Affairs, do artigo A Theory of Extramarital Affairs, publicado pela The University of Chicago Press, contendo variáveis como idade, anos de casado, religiosidade e ocupação.\n","date":"26 de maio de 2018","externalUrl":null,"permalink":"/post/2018-05-26-smarteademachinelearning/","section":"Posts","summary":" A análise exploratória dos dados A análise exploratória dos dados (AED) foi um termo que ganhou bastante popularidade quando Tukey publicou o livro Exploratory Data Analysis em 1977 que tratava uma “busca por conhecimento antes da análise de dados de fato”. Ocorre quando busca-se obter informações ocultas sobre os dados, tais como: variação, anomalias, distribuição, tendências, padrões e relações\n","title":"AED de forma rápida e um pouco de Machine Learning","type":"post"},{"content":"","date":"26 de maio de 2018","externalUrl":null,"permalink":"/tags/analise-multivariada/","section":"Tags","summary":"","title":"Analise-Multivariada","type":"tags"},{"content":"","date":"26 de maio de 2018","externalUrl":null,"permalink":"/tags/kmeans/","section":"Tags","summary":"","title":"Kmeans","type":"tags"},{"content":"","date":"26 de maio de 2018","externalUrl":null,"permalink":"/tags/pca/","section":"Tags","summary":"","title":"Pca","type":"tags"},{"content":"","date":"12 de abril de 2018","externalUrl":null,"permalink":"/tags/google-trends/","section":"Tags","summary":"","title":"Google-Trends","type":"tags"},{"content":" Google Trends O Google Trends é uma ferramenta gratuita, muito poderosa e que pode ser implementada para ajudar em nossas estratégias de análises.\nAtravés dele temos acesso a uma gigantesca base de dados que reúne os temas mais pesquisados na plataforma da Google possibilitando acessar dados de busca desde o ano de 2004.\nAtravés de suas séries temporais podemos avaliar a presença de pedrões, obter noções de tendência, sazonalidade e até mesmo arriscar algumas previsões.\nHoje quero trazer aqui como podemos utilizar a API de dados do google trends diretamente de dentro do R de forma visual e estatística.\nTL;DR\nO pacote gtrendsR permite acessar a API do Google Trends diretamente do R, com dados de busca disponíveis desde 2004. Na análise da popularidade do termo \"Estatística\" no Brasil, o teste de sequências (Wald-Wolfowitz) indicou tendência de queda ao longo do tempo. Foi ajustado um modelo de amortecimento exponencial de Holt-Winters para capturar a sazonalidade anual identificada na série. #Google Trends no R\nPara obtermos o acesso à base de dados da Google, primeiro precisamos instalar o pacote gtrendsR. Podemos utilizar o comando para baixar diretamente do CRAN, ou pelo link do github.\n#Instalando direto do CRAN: install.packages(\u0026quot;gtrendsR\u0026quot;) #Obtendo a versão de desenvolvimento do github: install.packages(\u0026quot;devtools\u0026quot;) devtools::install_github(\u0026#39;PMassicotte/gtrendsR\u0026#39;, ref = \u0026#39;new-api\u0026#39;) Este pacote funciona como uma interface para obter e exibir as informações coletadas pelo Google Trends, além de retornar a representação geográfica das ocorrências pesquisadas.\nCasa exista dúvidas, no CRAN existe o manual do pacote com maiores informações. Se você prefere rodar esses scripts em um ambiente na nuvem em vez do seu computador local, mostrei em outro post como colocar o RStudio e o Shiny Server na nuvem do Google.\nCom o pacote instalado já podemos carregar para dar início ao uso:\nlibrary(gtrendsR) Série temporal do Google A série temporal do Google Trends nos fornecem números que representam o interesse pelo termo pesquisado. O valor 100 é o pico de maior popularidade, assim quanto mais próximo de 100, mais popular o termo foi enquanto um valor próximo de 50 significa que o termo teve metade de sua popularidade. Da mesma maneira ocorre com os valores próximo de 0, que significa que o termo teve menos de 1% da popularidade de pico\nObtendo a série temporal Para especificar a busca, precisamos preencher os seguintes campos (Nota: alguns deles têm default e não precisam ser preenchidos):\ndata_scientist \u0026lt;- gtrends(c(\u0026quot;Aprendizado de Máquina\u0026quot;, \u0026quot;Big Data\u0026quot;, \u0026quot;R Linguagem de programação\u0026quot;, \u0026quot;Estatística\u0026quot;), geo = c(\u0026quot;BR\u0026quot;), #default para todo o mundo, podemos utilizar também: c(\u0026quot;BR\u0026quot;, \u0026quot;US\u0026quot;) time = \u0026quot;2004-01-01 2014-12-31\u0026quot;, #Data inicial Data final gprop = c(\u0026quot;web\u0026quot;), #Opções: \u0026quot;news\u0026quot;,\u0026quot;images\u0026quot;, \u0026quot;froogle\u0026quot;, \u0026quot;youtube\u0026quot; category = 0, #Zero é defaul, uma lista de categorias pode ser conferida abaixo hl = \u0026quot;pt-BR\u0026quot; ) Acessando os dados obtidos:\n💡 Amostra dos dados retornados por gtrends() — a estrutura completa tem ~528 linhas (4 termos × 132 meses). Aqui as primeiras linhas de cada termo:\ndate hits keyword geo gprop 2004-01-010Aprendizado de MáquinaBRweb 2004-02-010Aprendizado de MáquinaBRweb 2004-01-014Big DataBRweb 2004-02-012Big DataBRweb 2004-01-010R Linguagem de programaçãoBRweb 2004-02-010R Linguagem de programaçãoBRweb 2004-01-0162EstatísticaBRweb 2004-02-0167EstatísticaBRweb 2005-06-0172EstatísticaBRweb 2014-12-0151EstatísticaBRweb A coluna hits é normalizada de 0 a 100 (100 = pico histórico do termo na região/período).\nManipulando o formato das datas de busca Exemplos retirados do manual do pacote de como é possível alterar o formato das datas de busca:\n## Playing with time format gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;now 1-H\u0026quot;) # última hora gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;now 4-H\u0026quot;) # últimas 4 horas gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;now 1-d\u0026quot;) # último dia gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;today 1-m\u0026quot;) # últimos 30 dias gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;today 3-m\u0026quot;) # últimos 90 dias gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;today 12-m\u0026quot;) # últimos 12 meses gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;today+5-y\u0026quot;) # últimos 5 anos (default) gtrends(c(\u0026quot;R Studio\u0026quot;, \u0026quot;Machine Learning\u0026quot;), time = \u0026quot;all\u0026quot;) # desde 2004 Visualizando os resultados: Após isso, já podemos conferir qual foi o comportamento dos dados que selecionamos desde 2004 com a função o plot():\nplot(data_scientist) Observe como a popularidade da pesquisa pelo termo “Estatística” vem diminuindo conforme o tempo.\nÉ no mínimo curioso, pois com o aumento da popularidade do termo “Big Data” (que definido da maneira mais simples envolve o aumento no volume, velocidade e variedade dos dados de forma absurda) o uso da estatística (tanto teórica como computacional) sido cada vez mais requisitada!\nAnalises estatísticas Agora que já obtemos os dados do google trends, além da visualização também podemos aplicar toda a teoria de séries temporais que já conhecemos.\no comportamento da popularidade do termo “Estatística” se apresentou de forma muito interessante, vejamos com mais detalhes o o que esses dados têm a dizer:\nlibrary(dplyr) #Selecionando apenas as observações referêntes ao termo \u0026quot;Estatística\u0026quot; Estatistica=data_scientist$interest_over_time%\u0026gt;% filter(keyword==\u0026quot;Estatística\u0026quot;) Elementos da decomposição de uma Série Temporal Consideramos as observações \\({Z_t,t = 1,...,N}\\) de uma série temporal, um modelo de decomposição consiste em escrever \\(Z_t\\) como uma soma de três componentes não-observáveis,\n\\[ Z_t=T+S+R \\] onde:\n\\(T\\) : Tendência \\(S\\) : Sazonalidade (repetição de um fenômeno no período de tempo) \\(R\\) : Aleatória (espera-se que seja um \\(RB\\)) Para decomposição de séries temporais inicialmente vamos criar estes objetos que identificamos na base de dados:\nts=ts(as.numeric(Estatistica$hits),freq=12) ts_dec=decompose(ts) Com os objetos em mão, vejamos os resultados da decomposição:\nplot(ts_dec) Com isso somos capazes de criar modelos que possam acompanhar o comportamento da série e interpretar suas características.\nTendências Inicialmente vamos supor que a componente sazonal \\(S_t\\) não esteja presente.\nHá vários métodos para estimar \\(T_t\\), exemplos:\najustar uma função do tempo, como um polinômio, uma exponencial ouuma função suave de \\(t\\); suavizar (ou filtrar) os valores da série ao redor de um ponto, para estimar a tendência naquele ponto suavizar os valores da série através de sucessivos ajustes de retas de mínimos quadrados ponderados (“lowess”) Testes para tendência Vamos considerar as hipóteses:\n\\[ H_0: \\text{não existe tendência} \\\\ H_1: \\text{existe tendência} \\]\nPara avaliar estas hipóteses temos uma série de testes disponíveis mas aqui utilizei apenas um, veja:\nTeste de sequências (Wald-Wolfowitz) randtests::runs.test(ts) ## ## Runs Test ## ## data: ts ## statistic = -9.4058, runs = 12, n1 = 65, n2 = 63, n = 128, p-value \u0026lt; ## 2.2e-16 ## alternative hypothesis: nonrandomness O teste de sequências forneceu uma evidência de que realmente existe uma tendência da série de dados referênte à popularidade do termo “Estatística” nas mídias sociais do Google.\nSazonalidade É dificíl definir tanto do ponto de vista conceitual como estatístico dizer o que seja sazonalidade.\nEmpiricamente, consideramos como sazonais os fenômenos que ocorrem regularmente de tempos em tempos.\nTestes para a sazonalidade Para avaliar a sazonaldade podemos utiizar alguem teste que avalie as hipóteses:\n\\[ H_0: \\text{Todos os anos possuem funções de distribuição iguais} \\\\ H_1: \\text{Ao menos dois dos anos possuem funções de distribuição diferentes} \\] A base de dados é a seguinte:\ndata=data.frame(cbind(serie=as.numeric(ts),mes_ano=rep(seq(1,12),11))) kruskal.test(data=data,serie~mes_ano) ## ## Kruskal-Wallis rank sum test ## ## data: serie by mes_ano ## Kruskal-Wallis chi-squared = 12.461, df = 11, p-value = 0.33 Como o valor p sugere significância estatística e além disso visualmente confirmamos a sensação de ocorrer a sazonalidade, não parece haver evidências suficientes para rejeitar a hipótese nula de que todas os anos possuem funções de distribuição iguais, implicando assim uma sazonalidade anual com tendência negativa para a popularidade do termo “Estatística” pesquisado na web.\nComo nossos dados confirmam sazonalidade e encontramos uma tendência, vou arriscar aqui de brincadeira ajustar um modelo pelo método de amortecimento exponencial de Holt-Winters (para dados com sazonalidade) só para ter uma perspectiva de como a estatística é immportante.\nMétodo de Amortecimento exponencial de Holt-Winters (dados com sazonalidade) Este modelo ajuda a descobrir padrão de comportamento complexos. A previsao deste modelo é feita de acordo com a série que pode ser Sazonal Aditiva ou Sazonal Multiplicativa.\nÉ uma adaptação do modelo de amortecimento exponencial de Holt-Winters para dados com sazonalidade. Um parâmtro será incluído nas equações e teremos um novo parâmtro que será a constante de amortecimento dos fatores sazonais\nNo R, considerando a série sazonal aditiva (por default do R):\najuste_com_sazonalidade\u0026lt;-HoltWinters(ts) plot(ajuste_com_sazonalidade) Note que o ajuste de Holt-Winters obtem melhores resultados para valores mais próximos, pois atribui maior peso para observações mais recentes.\nCom a função forecast() podemos obter previsoes do modelo, veja:\nlibrary(forecast) previsao_com_sazonalidade\u0026lt;-forecast(ajuste_com_sazonalidade,h = 12) plot(previsao_com_sazonalidade) Muito a fazer Trouxe aqui algumas idéias de como a combinação de alguns pacotes junto a artíficios estatísticos podem revelar insformações interessantes, os dados da popularidade de termos de pesquisa do Google são livres para qualquer pessoa e podem gerar insights poderosos para a tomada de decisão, agora com mais uma nova ferramenta poderosa na caixinha basta colocar a mão na massa! Essas séries temporais de buscas também podem ser cruzadas com outras fontes públicas, como fiz na análise do mercado de criptomoedas com R.\nReferência MORETTIN, P.A; TOLOI, C.M. Análise de Séries Temporais. São Paulo, Blucher, 2006\nPerguntas frequentes Como acessar os dados do Google Trends diretamente do R?\nInstale o pacote gtrendsR via CRAN ou GitHub e use a função gtrends(), informando os termos de busca, geografia, período e tipo de busca desejados.\nDesde quando o Google Trends disponibiliza dados históricos?\nA base de dados do Google Trends reúne informações de busca desde o ano de 2004, com valores normalizados de 0 a 100 representando o interesse pelo termo pesquisado.\nComo testar se existe tendência ou sazonalidade em uma série do Google Trends?\nO teste de sequências (Wald-Wolfowitz) avalia a presença de tendência, enquanto o teste de Kruskal-Wallis pode ser usado para avaliar se há sazonalidade entre os meses do ano.\n","date":"12 de abril de 2018","externalUrl":null,"permalink":"/post/2018-04-12-google-trends-e-r/","section":"Posts","summary":" Google Trends O Google Trends é uma ferramenta gratuita, muito poderosa e que pode ser implementada para ajudar em nossas estratégias de análises.\nAtravés dele temos acesso a uma gigantesca base de dados que reúne os temas mais pesquisados na plataforma da Google possibilitando acessar dados de busca desde o ano de 2004.\nAtravés de suas séries temporais podemos avaliar a presença de pedrões, obter noções de tendência, sazonalidade e até mesmo arriscar algumas previsões.\n","title":"Séries temporais com Google Trends e R","type":"post"},{"content":" Link do repositório no github: https://github.com/gomesfellipe/appwordcloud\nLink de acesso ao app: https://gomesfellipe.shinyapps.io/appwordcloud/\nNOVA VERSÃO DA NUVEM DE PALAVRAS!!\nNova versão conta agora com a tabela de frequências dos termos identificados na análise!\nEsta pasta conta com os seguintes arquivos:\nBase de dados (obtida através do social searcher):\nbase.csv - exemplo de base de dados como input do aplicativo (obs.: codificação UTF-8) Complementos:\nwordcloud_sentiment.R - Função criada para gerar nuvens de palavras com tecnicas textmining de maneira simples e facil install_packages.R - Script para auxiliar na instalação dos pacotes necessários para rodar o aplicativo Código do aplicativo:\nappwordcloud.Rmd - Este é o código responsável por rodar o aplicativo Motivação para o aplicativo # Inicialmente uma função foi desenvolvida com finalidade de se criar nuvens de palavras em conjunto com técnicas de textmining de forma dinâmica, o nome da função é wordcloud_sentiment() e seu código e os parâmetros para seu uso podem ser conferidos no arquivo wordcloud_sentiment.R.\nCom essa função foi possível que a criação de nuvens de palavras com técnicas de textmining se tornasse uma tarefa mais ágil, porém o conhecimento prévio de R para sua implementação seria recomendado caso necessite de alguma manutenção. Diante disto a ideia de uma abordagem mais interativa mostrou-se interessante, a seguir é possível conferir como foi sua implementação.\nPacotes utilizados: # Os pacotes utilizados incluindo algumas referências:\nflexdashboard: Pacote para gerar o aplicativo como dashboard ( manual do pacote ) stringr: Pacote para manipulação de strings (bom manual para manipular strings ) dplyr: Pacote para manipulação de dados (Cheat Sheet para Data Wrangling) tm: Pacote de para text mining (manual do CRAN) wordcloud: Pacote para nuvem de palavras (bom manual para text mining, wordcloud e sentimentos) readxl: Pacote para leitura de dados Excel (github tidyverse ) tidytext: Manipulação de textos (e-book tidytextmining) reshape2: Manipulação de dados ( github do hadley ) lexiconPT: Importar palavras de sentimentos ( CRAN ) memoise: Cache resultados de uma função (github memoise) SnowballC: Para steamming (manual do CRAN ) purrr: Ferramentas de programação funcional (cheat Sheet para funcoes apply) DT: Renderizar tabela ( manual do pacote ) ngram: Busca por sequencias de palavras (guia para ngram no R ) Instalando os pacotes # A instalação de todos esses pacotes pode ser realizada em apenas 1 passo, para mais informações consultar o documento install_packages.R e seguir as instruções de instalação\nInstruções # Obs.: As funções da nova versão são basicamente as mesmas da versão antiga. A novidade está na tabela de frequências dos termos identificados com disponibilidade para download.\nInput da base de dados # Para dar início a construção da nuvem de palavras selecione o arquivo (em formato csv com codificação UTF-8) que contenha apenas duas colunas em que:\n* Coluna1: usuario * Coluna2: texto exemplo de base\nStopwords # Para remover palavras da nuvem de palavras (chamadas de stopwords), basta inseri-las, separadas por vírgula, na caixa \u0026ldquo;Removendo palavras\u0026rdquo;. Exemplo de como devem ser incluidas as palavras:\nnao, dele, dela, nos Sentimentos # Na opção \u0026ldquo;Marque se deseja usar cor para sentimentos\u0026rdquo; a cor da nuvem é baseada em um dicionário léxico do qual um conjunto de palavras já foram pré-classificadas como positiva, negativa ou neutra. Por default a nuvem já começa com esta opção marcada.\nTextSteamming (remover sufixos) # Com a opção \u0026ldquo;Marque se deseja usar \u0026lsquo;Text Steamming\u0026rsquo;(remover sufixos)\u0026rdquo; marcada, a função SnowballC::wordStem(x,lang=\u0026quot;portuguese) será utilizada de forma que as palavras em portugues do Brasil tenham seus sufixos removidos, o que influencia na análise de forma que, por exemplo, as palavras \u0026ldquo;conhecimento\u0026rdquo;, \u0026ldquo;conhecer\u0026rdquo;, \u0026ldquo;conhecemos\u0026rdquo;, \u0026ldquo;conheci\u0026rdquo; sejam agregadas em um único termo: \u0026ldquo;conhec\u0026rdquo;, veja:\nObs.: Para efetuar a mudança, clique em \u0026ldquo;Atualizar nuvem\u0026rdquo;\nTF-IDF # A opção \u0026ldquo;Marque se deseja usar a transformação tf-idf\u0026rdquo; realizará q transformação if-idf na matriz de termos que não considera mais a frequência (ou contagem) de termos de modo que as palavras tenham \u0026ldquo;pesos\u0026rdquo; atribuídos que levam em consideração não só a frequência das palavras no corpus, mas também a frequência das palavras nos diferentes documentos (cada linha da base de dados). Este valor agora será encarregado de fornecer a \u0026ldquo;relevância\u0026rdquo; daquele termo no corpus.\nObs.: Para efetuar a mudança, clique em \u0026ldquo;Atualizar nuvem\u0026rdquo;\nSalvando a Wordcloud # Para salvar, basta clicar sobre a imagem e salvar, veja:\nFazendo o Download (novidade!) # Agora o usuário pode baixar também a tabela de frequência dos termos identificados clicanco no botão download\n","date":"7 de abril de 2018","externalUrl":null,"permalink":"/projects/appwordcloud/","section":"Projetos","summary":" Link do repositório no github: https://github.com/gomesfellipe/appwordcloud\nLink de acesso ao app: https://gomesfellipe.shinyapps.io/appwordcloud/\nNOVA VERSÃO DA NUVEM DE PALAVRAS!!\nNova versão conta agora com a tabela de frequências dos termos identificados na análise!\nEsta pasta conta com os seguintes arquivos:\nBase de dados (obtida através do social searcher):\nbase.csv - exemplo de base de dados como input do aplicativo (obs.: codificação UTF-8) Complementos:\nwordcloud_sentiment.R - Função criada para gerar nuvens de palavras com tecnicas textmining de maneira simples e facil install_packages.R - Script para auxiliar na instalação dos pacotes necessários para rodar o aplicativo Código do aplicativo:\n","title":"Aplicativo para construir Wordcloud","type":"projects"},{"content":"","date":"7 de março de 2018","externalUrl":null,"permalink":"/tags/macro/","section":"Tags","summary":"","title":"Macro","type":"tags"},{"content":" Relatórios de alta qualidade só com \\(\\LaTeX\\)? Como já mencionei no post sobre tabelas incríveis com R, a tarefa de um estatístico (ou Data Scientist, em sua versão diluída e mais comercial) vai muito além do planejamento, análises, inferência, sumarização e interpretação de observações para fornecer a melhor informação possível a partir do dados disponíveis. A produção final dos relatórios é fundamental e na grande maioria das vezes utiliza-se a linguagem \\(\\LaTeX\\), mas será que ela é realmente a única opção?\nA escrita para a produção de documentação técnica e científica de alta qualidade é tão importante que até o Facebook permite usar a linguagem \\(\\LaTeX\\) no messenger. Normalmente para gerar arquivos em \\(\\LaTeX\\) existem muitas opções de softwares ou mesmo opções online como o overleaf ou o sharelatex que permitem escrever os documentos online com compilação em tempo real e armazenamento automático na nuvem. Para esse tipo de relatório escrito puramente em \\(\\LaTeX\\), as funções dos pacotes stargazer, xtable, pander dentre outros, podem ser muito úteis na tarefa de produzir as tabelas dos resultados obtidos das análises em R para o formato \\(\\LaTeX\\).\nAlém desses softwares a linguagem \\(\\LaTeX\\) pode ser utilizada diretamente de dentro do R em duas opções: O documento R Sweave e o documento Rmarkdown. Se for em Rmarkdown será necessária algumas configurações, como por exemplo algumas vezes a opção results = \"asis\" deve ser incluída nos chunks que deseja-se renderizar as tabelas \\(\\LaTeX\\), caso seja R Sweave, pode ser que essa documentação ajude, pois as configurações dos chunks podem ser diferentes das configurações utilizadas em R markdown).\nTL;DR\nRmd to docx: a opção nativa do R já produz um Word formatado, com estilo controlado por um reference_docx. Grmd::docx_document: gera o documento em HTML e abre no Word sem perder a formatação de tabelas mais elaboradas. Uma macro no Word (VBA) resolve ajustes finos, como o tamanho das tabelas, que o R sozinho não cobre. Porém, não basta obter informação através dos dados e com técnicas específicas transformá-los em conhecimento, geralmente tal conhecimento será destinado para alguma finalidade e não necessariamente a pessoa que irá receber nossos resultados vai desejar um documento em PDF ou html, além de não trabalhar com \\(\\LaTeX\\) nem conhecer as linguagens de programação muito utilizadas por nós, como R ou Markdown. Na verdade isso nem é mesmo uma obrigação para quem contrata serviços de analytics.\nRelatórios em Word A partir do momento que é assumida a responsabilidade do entendimento da informação que passamos, acaba sendo necessário sair da nossa zona de conforto e aprender a falar na língua de quem nos ouve, para que a informação seja passada da maneira mais clara possível.\nÉ muito comum criarmos nossas figuras e tabelas super elegantes e rechear nossos relatórios com as mais espertas interpretações a cerca dos resultados e compilar tudo em um arquivo .PDF (geralmente ao se utilizar \\(\\LaTeX\\)) ou mesmo em .html (muito comum ao se utilizar Rmarkdown), porém muitas vezes nossos resultados serão reaproveitados em documentos escritos em outros formatos e uma das escolhas optadas em escala mundial é escrever documentos em Word.\nGeralmente quem trabalha com programação está sempre atento a otimizar seus processos, portanto integrar nossos resultados do R com um documento em Word é uma tarefa que pode ser muito útil dependendo da finalidade dos nossos dados.\nExistem extensões para escrever \\(\\LaTeX\\) diretamente no word, como por exemplo o TexPoint que permite escrever invocações e definições de macro \\(\\LaTeX\\) junto com seu texto normal ou o Aurora que é um programa de edição de texto que permite introduzir funções matemáticas complexas em texto de modo a esboçar relatórios e outras mensagens com caracteres únicos e equações. Particularmente nunca usei nenhuma das duas opções mas elas estão aí para quem quiser testar.\nA extensão para word chamada GrindEQ™ Math Utilities que permite fazer a conversão do documento \\(\\LaTeX\\) para word já foi muito útil para mim, porém muitas vezes ocorriam bugs na formatação e com a finalidade de focar os esforços nas análises e não na formatação, uma busca por alguma maneira de que a isso pudesse ser feito totalmente em R e o arquivo final ser um documento word já formatado pareceu interessante.\nEm algumas pesquisas descobri que existem diversas outras maneiras de se produzir um documento Word através do R, vou apresentar aqui duas maneiras com alguns truques, mas sintam-se a vontade para dar sugestões de outras maneiras de se fazer isso nos comentários, será de grande ajuda!\n1º método: Rmd to docx O primeiro método envolve o uso da opção nativa do R de produzir esse tipo de documento. Segundo este guia disponível pela RStudio basta selecionar o tipo de arquivo Rmarkdown da seguinte maneira:\nEntão selecione o formato Word para o documento, e se desejar já pode alterar o nome do título e autor do documento (não é obrigado a fazer isso nesse momento)\nUm novo documento será exibido com o preâmbulo default para esse tipo de arquivo. O interessante aqui é que você pode compilar seu documento, alterar o estilo e salvar na mesma pasta do arquivo que você está trabalhando, de forma que as alterações no estilo sejam salvas e utilizadas como referência ao incluir no preâmbulo o nome deste documento como no exemplo a seguir:\n--- title: \u0026quot;Título do trabalho\u0026quot; author: \u0026quot;Fellipe\u0026quot; date: \u0026quot; 06 de março de 2018\u0026quot; output: word_document: reference_docx: word-styles-reference-01.docx --- Outros recursos interessantes são os de formatar tabelas e figuras. Para formatar as tabelas podemos utilizar os pacotes que já usávamos em documentos \\(\\LaTeX\\) para PDF ou Rmd para html. como por exemplo veja uma tabela simples produzida por códigos em R gerando uma tabela em Word usando a função kable:\nMuitas outras opções podem ser utilizadas, mais informações podem ser conferidas na documentação no site da RStudio ou então conferir as opções de formatação utilizando a função knitr::kable() e o pacote kableExtra no manual do pacote kableExtra.\nPara alterar as dimensões de todas as figuras do documento ou mesmo incluir um sumário também basta alterar as especificações do preâmbulo, como por exemplo:\n--- title: \u0026quot;Título do trabalho\u0026quot; author: \u0026quot;Fellipe\u0026quot; date: \u0026quot; 06 de março de 2018\u0026quot; output: word_document reference_docx: word-styles-reference-01.docx fig_width: 7 fig_height: 4 fig_caption: true toc: true --- Muito simples gerar o arquivo diretamente em Word!\n2º método: Grmd::docx_document Mesmo com a simplicidade oferecida pelo recurso nativo do R, não parece ser possível formatar as tabelas da maneira mais elaborara utilizando essas funções, fiz um post falando sobre como criar tabelas incríveis com R porém a maioria das opções dos pacotes apresentados lá servem apenas para documentos no formato html.\nPesquisando se havia algum jeito de criar o documento em html que pudesse ser aberto no Word encontrei um pacote disponível no github chamado Grmd. Sua finalidade é trabalhar com a publicação rápida, escrevendo o documento como normalmente em RMarkdown e permitindo que o documento html gerado possa ser aberto em Word sem problemas de formatação!\nPor exemplo, uma formatação da tabela e elaborção de imagem que é bem tranquilo de se fazer em html com o knitr::kable() e com ggplot::ggplot():\ndt \u0026lt;- mtcars[1:5, 1:6] #Tabela gerada: kable(dt, \u0026quot;html\u0026quot;, caption= \u0026quot;Título\u0026quot;, align = c(\u0026quot;l\u0026quot;,\u0026quot;r\u0026quot;,\u0026quot;l\u0026quot;,\u0026quot;r\u0026quot;,\u0026quot;l\u0026quot;,\u0026quot;r\u0026quot;,\u0026quot;l\u0026quot;))%\u0026gt;% kable_styling(full_width = F) %\u0026gt;% add_header_above(c(\u0026quot; \u0026quot; = 1, \u0026quot;Group 1\u0026quot; = 2, \u0026quot;Group 2\u0026quot; = 2, \u0026quot;Group 3\u0026quot; = 2))%\u0026gt;% group_rows(\u0026quot;Grupo A\u0026quot;,1,3)%\u0026gt;% group_rows(\u0026quot;Grupo B\u0026quot;,4,5) Table 1: Título Group 1 Group 2 Group 3 mpg cyl disp hp drat wt Grupo A Mazda RX4 21.0 6 160 110 3.90 2.620 Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 Datsun 710 22.8 4 108 93 3.85 2.320 Grupo B Hornet 4 Drive 21.4 6 258 110 3.08 3.215 Hornet Sportabout 18.7 8 360 175 3.15 3.440 library(tidyr) library(ggplot2) n=nrow(mtcars) rbind( cbind(gather(mtcars[,1:2]*10),Grupo=rep(\u0026quot;Grupo1\u0026quot;,n)), cbind(gather(mtcars[,3:4]),Grupo=rep(\u0026quot;Grupo2\u0026quot;,n)), cbind(gather(mtcars[,5:6]*100),Grupo=rep(\u0026quot;Grupo3\u0026quot;,n)) )%\u0026gt;% ggplot(aes( fill=key, x=value))+ geom_bar(position=\u0026quot;dodge\u0026quot;)+ coord_flip()+ facet_wrap(~Grupo,ncol = 1)+ xlab(\u0026quot;Banco mtcars adaptado para exemplo\u0026quot;)+theme(axis.text.x = element_text(size=18)) + theme_set(theme_gray(base_size = 13))+theme(axis.title.y = element_text(size = rel(1.2)))+theme_bw() Pode ser muito útil utilizar da mesma praticidade de construir as tabelas em html nos documentos words. Utilizando o pacote Grmd, ao abrir o documento no Word a tabela e figura acima serão exibidas da seguinte maneira:\nPara utilizar o pacote basta instala-lo através da função devtools::install_github(\"gforge/Grmd\"), após o pacote instalado é só modificar onde estiver escrito output:word_document no preâmbulo por Grmd::docx_document e ficar tranquilo, porque todas as funcionalidades apresentadas acima continuam funcionando! Veja o exemplo acima alterado:\n--- title: \u0026quot;Título do trabalho\u0026quot; author: \u0026quot;Fellipe\u0026quot; date: \u0026quot; 06 de março de 2018\u0026quot; output: word_document reference_docx: word-styles-reference-01.docx fig_width: 7 fig_height: 4 fig_caption: true toc: true --- Portanto ao deixar o preâmbulo dessa nova maneira, seu documento será renderizado em html e poderá ser aberto e editado como documento Word tranquilamente! Assim a pessoa que receber o relatório final estará em contato direto com suas análises em um formato que seja amigável para ela e ela se sinta confortável em editar, copiar, colar ou fazer o que bem entender!\nAtenção! Pois no github do desenvolvedor possui um aviso de que o pacote “provavelmente será fundido com o pacote Gmisc”, portanto é bom ficar atento a possíveis alterações!\nDica para casos extremos A principal dica quando não sabemos resolver um problema é: MANTENHA A CALMA! Mesmo com todas essas opções, ainda existem casos que nenhum esses artifícios será o bastante! Para isso muitas vezes é preciso explorar o desconhecido e usar a criatividade!\nUm problema prático que eu tive e precisava solucionar em um tempo razoavelmente curto era que de as margens das tabelas que eu criei não cabiam de maneira satisfatória na página. Diante disso pesquisei bastante e me lembrei que assim como o Excel, o Word também possui Macros! Portanto pesquisando mais um pouco na internet encontrei este artigo que ensina como formatar tabelas e figuras em documentos .docx!\nNo artigo é apresentada uma Macro para formatar as tabelas então depois de pesquisar um pouco e fazer algumas alterações foi bem útil para resolver meu problema com o tamanho da letra e a posição das tabelas! A Macro adaptada foi a seguinte:\nSub FormatTables() Dim tbl As Table For Each tbl In ActiveDocument.Tables tbl.AutoFormat wdTableFormatList6 tbl.Range.Font.Name = \u0026quot;Arial\u0026quot; tbl.Range.Font.Size = 6 tbl.Range.ParagraphFormat.SpaceBefore = 1 tbl.Range.ParagraphFormat.SpaceAfter = 2 tbl.Range.Cells.SetHeight RowHeight:=18, HeightRule:=wdRowHeightExactly Next End Sub Esta macro formata todas as tabelas o documento, selecionando o estilo TableFormatList6, a fonte Arial com o tamanho 6 e altera os espaçamentos de parágrafos, resumindo todo esse processo em um único botão\nFoco nas análises Após usar o o recurso Grmd::docx_document em conjunto com a Macro FormatTables foi possível focar nas análises dos resultados e deixar a tarefa de formatação muito mais ágil, porém este método não é definitivo e a busca por novas maneiras de fazer e otimizar esse e outros tipos de tarefas integradas com R continua!\nSe o formato final que você precisa é PDF em vez de Word, veja também o post sobre o template Tufte no RMarkdown, outra forma de sair da formatação padrão sem sair do R.\nPerguntas frequentes Dá para gerar um Word direto do R sem instalar nada além do RStudio? Sim. Basta escolher output: word_document no cabeçalho YAML de um arquivo RMarkdown. É o recurso nativo do R, sem depender de pacotes externos como o Grmd.\nComo manter o estilo visual (fontes, cores) do meu Word corporativo? Use a opção reference_docx no cabeçalho YAML, apontando para um arquivo .docx com o estilo desejado já configurado. O RMarkdown usa esse arquivo como referência de formatação ao gerar o documento final.\nPor que usar o pacote Grmd em vez do word_document nativo? O word_document nativo tem limitações para formatar tabelas de forma elaborada (cores, agrupamentos). O Grmd contorna isso gerando o documento em HTML, que o Word abre e edita sem perder essa formatação.\n","date":"7 de março de 2018","externalUrl":null,"permalink":"/post/2018-03-07-word-e-r-2/","section":"Posts","summary":" Relatórios de alta qualidade só com \\(\\LaTeX\\)? Como já mencionei no post sobre tabelas incríveis com R, a tarefa de um estatístico (ou Data Scientist, em sua versão diluída e mais comercial) vai muito além do planejamento, análises, inferência, sumarização e interpretação de observações para fornecer a melhor informação possível a partir do dados disponíveis. A produção final dos relatórios é fundamental e na grande maioria das vezes utiliza-se a linguagem \\(\\LaTeX\\), mas será que ela é realmente a única opção?\n","title":"Produzindo e formatando um documento Word direto em R","type":"post"},{"content":"","date":"7 de março de 2018","externalUrl":null,"permalink":"/tags/word/","section":"Tags","summary":"","title":"Word","type":"tags"},{"content":" Link do repositório no github: https://github.com/gomesfellipe/appPCAkmeans\nLink de acesso do app : https://gomesfellipe.shinyapps.io/appPCAkmeans/\nEsta pasta conta com os seguintes arquivos:\nBase de dados iris (base de dados nativa do R)\nbase-iris.csv - exemplo de base de dados como imput do aplicativo Código do aplicativo:\nappPCAkmeans.Rmd - Script do código responsável por rodar o aplicativo Agrupamento - Machine Learning # A análise de componentes principais e a busca por clusters é uma tarefa muito comum quando não conhecemos a classificação.\nA tarefa de agrupamento (muitas vezes também chamada de clustering) pode ser compreendida como um processo que torna possível descobrir relações entre exemplares de um conjunto de dados que contam com uma série de características (atributos descritivos) porém não há presença de um rótulo associado (classe) a cada exemplar.\nDe maneira geral as análises realizadas por algorítimos de machine learning que implementam técnicas de agrupamento buscam por diferenças ou por similaridades entre exemplares, quantificadas por meio de medidas de distância (quanto menor a distância entre dois exemplares, maior será a similaridade), portanto uma estrutura de grupos é formada de maneira que a similaridade intragrupos tenha sido maximizada, e a similaridade intergrupos tenha sido minimizada.\nQuando esse processo de minimização é feito por um algorítimo de Machine Learning, é considerado um processo indutivo e não supervisionado - também conhecido como treinamento não supervisionado ou ainda como aprendizado não supervisionado\nReferência: Introdução a Mineração de Dados com aplicações em R\nObs.: Aqui nesse github existe um repósitório chamado Livro_Introducao_a_Mineracao_de_Dados que contém algumas das funções e idéias adquiridas ao estudar esse livro.\nAlém do post no meu blog que falo sobre Análise multivariada em R\nPacotes utilizados: # Pacotes utilizados no app:\nlibrary(shiny) - Renderizar o aplicativo library(ggplot2) - Criar gráficos elegantes library(ggfortify) - Criar gráficos de análises com ggplot library(DT) - Renderizar tabelas elegantes e práticas library(plotly) - Transforma ggplot em interativo Instruções # Carregamento # Este aplicativo permite que usuário selecione qualquer base pessoal para realizar a análise de componentes principais e executar o agrupamento de dados por partição Kmeans. Pode ser um arquivo do tipo csv, txt ou mesmo excel, caso seja um arquivo excel é necessário informar em qual planílha se encotram os dados\nAnálise de componentes principais # A análsie de componentes principais foi realizada com a função prcomp(), para mais informações sobre seu uso consultar o manual.\nA análise é basicamente a mesma que a executada com a função princomp, porém o retorno da função é diferente, veja:\nprcomp() princomp() Descrição sdev sdev Desvios-padrão dos principais componentes rotation loadings A matriz de loadinds (carregamentos) das variáveis (as colunas são eigenvectors) center center A variável means (significa que foram resgatados) scale scale Escala aplicada a cada variável x scores As coordenadas dos indivíduos (observações) nos componentes principais Seu uso no aplicativo:\nMétodo não hierárquico de agrupamento K-means # Esta é uma das mais populares abordagens de agrupamento de dados por partição. A partir de uma escolha inicial para os centróides, o algorítmo procede verificando quais exemplares são mais similares a quais centroides.\nVantagens: # Tendem a maximizar a dispersão entre os centros de gravidade dos clusters (mantem os clusters bem separados) Simplicidade de cálculo, calcula somente as distâncias entre os objetos e os centros de gravidade dos clusters Desvantagens: # Depende dos conjuntos de sementes iniciais, principalmente se a seleção das sementes é aleatória Não há garantias de um agrupamento ótimo dos objetos Clustes # Note que é possível variar o número de clusters de interesse\nDownload # Para fazer o download da versão estatica dos gráficos do aplicativo basta clicar no botão de Download\nAvaliando os resultados com clvalid::clvalid() # Este pacote faz os calculos das medidas que avaliam se os clusters são compactos, bem separados e estáveis.\nVejamos os tipos de medidas:\nMedidas de validação:\nconectividade: relativa ao grau de vizinhança entre objetos em um mesmo cluster, varia entre 0 e infinito e quanto menor melhor. silhueta: homogeneidade interna, assume valores entre -1 e 1 e quanto mais próximo de 1 melhor. índice de Dunn: quantifica a separação entre os agrupamentos, assume valores entre 0 e 1 e quanto maior melhor. Medidas de estabilidade:\nAPN - average proportion of non-overlap: proporção média de observações não classificadas no mesmo cluster nos casos com dados completos e incompletos. Assume valor no intervalo [0,1], próximos de 0 indicam agrupamentos consistentes. AD - average distance: distância média entre observações classificadas no mesmo cluster nos casos com dados completos e incompletos. Assume valores não negativos, sendo preferíveis valores próximos de zero. ADM - average distance between means: distância média entre os centroides quando as observações estão em um mesmo cluster. Assume valores não negativos, sendo preferíveis valores próximos de zero. FOM - figure of merit: medida do erro cometido ao usar os centroides como estimativas das observações na coluna removida. Assume valores não negativos, sendo preferíveis valores próximos de zero. Referências:\nhttp://www.jstatsoft.org/v25/i04/paper\nhttp://cran.r-project.org/web/packages/clValid/clValid.pdf\nIntrodução a Mineração de Dados com aplicações em R\nMais informações sobre a avaliação dos resultados do agrupamento podem ser conferidas em um post que falo sobre Análise multivariada em R\n","date":"2 de março de 2018","externalUrl":null,"permalink":"/projects/apppcakmeans/","section":"Projetos","summary":" Link do repositório no github: https://github.com/gomesfellipe/appPCAkmeans\nLink de acesso do app : https://gomesfellipe.shinyapps.io/appPCAkmeans/\nEsta pasta conta com os seguintes arquivos:\nBase de dados iris (base de dados nativa do R)\nbase-iris.csv - exemplo de base de dados como imput do aplicativo Código do aplicativo:\nappPCAkmeans.Rmd - Script do código responsável por rodar o aplicativo Agrupamento - Machine Learning # A análise de componentes principais e a busca por clusters é uma tarefa muito comum quando não conhecemos a classificação.\n","title":"Aplicativo para análise multivariada","type":"projects"},{"content":"","date":"17 de fevereiro de 2018","externalUrl":null,"permalink":"/tags/cheatsheets/","section":"Tags","summary":"","title":"Cheatsheets","type":"tags"},{"content":" Você costuma ler o manual? Quando éramos crianças, geralmente não tínhamos o costume de ler o manual das coisas, não é mesmo? Particularmente eu sempre gostei de aprender como as coisas funcionavam diretamente com a prática para poder usá-las depois. Adorava buscar entender como as coisas se encaixavam ao montar os brinquedinhos do kinder-ovo sem ler as instruções ou criar diferentes combinações com lego customizados, por exemplo. Acredito que isso seja da natureza de toda criança!\nTL;DR\nCheatSheets da RStudio/Posit resumem pacotes inteiros numa página, para consulta rápida. DataCamp e Kaggle aplicam gamificação (pontos, medalhas, competição) para tornar o aprendizado mais engajante. Aprender R fica mais leve combinando prática direta com boas referências, sem abrir mão do manual quando travar. Acontece que com o passar dos anos vamos adquirindo conhecimento e começamos a perceber que quanto mais aprendemos maior a quantidade de coisas novas que ainda temos a aprender.\nEspecialmente ao ler noticias do tipo: “Einstein estava certo a cem anos atrás!” depois de ele já ter tomado nota das ondas gravitacionais a tantos anos.. Um dever de casa que durou 100 anos foi deixado por um gênio e isso serve para nos lembra como somos “pequenos”, o quanto é importante seguir boas referências nos apoiando em ombros de gigantes para enxergar mais longe!\n(Quem ai aos 22 anos, desenvolveu o cálculo infinitesimal, as bases da teoria das cores, contribuiu com o estudo da ótica, formulou conceitos sobre as leis do movimento planetário e virou lenda com um famoso incidente da maçã que levou a formular a teoria da gravidade? Será que Isaac Newton conhece alguem?)\nIsso faz pensar em como é importante ouvir (ou ler) quem entende do assunto para darmos nossos próximos passos\nMas o R tem manual? Seja estudando estatística, programação em R, qualquer outra matéria ou mesmo configurando seu relógio, montando um daqueles móveis complicados ou que seja montando um avião! Nem tudo precisa ser um quebra cabeça, não importa o quão ávido por saber, consultar o manual (ou um livro se torna uma tarefa fundamental para darmos o próximo passo!\nA medida que vamos avançando no aprendendizado da linguagem R, mais consultas ao “Help” vão sendo realizadas. Isso ocorre também quando avançamos no estudo de qualquer área, acaba sendo natural elevar o número de consultas ao “manual”.\nAcontece que nem sempre encontramos explicações detalhadas ou suficientes no Help para solucionar nossos problemas e em busca de mais detalhes e referencias quase sempre podemos encontrar vignettes (que são guias longos para os pacotes, geralmente com exemplos reprodutíveis e algumas dicas para o uso) em uma breve pesquisa escrevendo: “Nome do pacote” + “CRAN” na busca do Google e geralmente logo no inicio já existe uma ou mais referências além do Help do RStudio no CRAN disponibilizado pelos desenvolvedores dos pacotes.\nAprendendo com a prática Algo muito legal disponibilizado pela RStudio dentre os recursos em seu site oficial são as CheatSheets e a aprendizagem online onde é apresentada a DataCamp que tornam fácil aprender e usar alguns dos pacotes mais utilizados unindo a ideia da “consulta ao manual” e a ideia de se aprender na prática.\nAlém desses recursos ainda existe kaggle que funciona quase como uma plataforma de “jogos com a ciência de dados” onde competidores comparam resultados dos ajustes de seus modelos, análises descrtias e relatórios valendo premios em dinheiro!\nDivertido como quando eramos crianças!\nVeja a seguir uma breve explicação e referências para acessar esses recursos\nCheatsheets Ao longo do tempo novas cheatsheets vão sendo adicionadas e todas elas estão disponíveis para download, além disso qualquer pessoa que quiser contribuir com a comunidade é convidado pelos desenvolvedores a enviar suas próprias CheatSheets!\nTodas as CheatSheets apresentadas abaixo estão disponíveis no repositório de CheatSheets :\nExemplos do básico: Informações básicas e fundamentais para o uso da IDE do RStudio e o uso da linguagem podem ser encontrados nessas CheatSheets:\nRStudio IDE\nBasics R\nAdvanced R Cheatsheet → Advanced R\nExemplos de recursos: Existem também algumas CheatSheets para auxiliar no uso dos recursos oferecidos pela RStudio como por exemplo a para RMarkdown e Shinny:\nRMarkdown Cheatsheet → RMarkdown\nGuia de Referência RMarkdown → Guia de Referencia para RMarkdown\nShiny (veja o catálogo oficial de cheatsheets)\nExemplos de utilidades Além das funcionalidades e recursos básicos disponíveis pela equipe da RStudio ainda contamos com uma enorme quantidade de pacotes que estão sendo desenvolvidos a todo momento com a finalidade de melhorar o desempenho de nossos programas e projetos, a seguir alguns exemplos de CheatSheets de pacotes que são bastante úteis no dia a dia do programador estatístico:\nExemplos de fornecidos pela RStudio stringr - Para facilitar a manipulação de strings\npurrr - Pacote com ferramentas de programação funcional\ndplyr - Para facilidade e velocidade na manipulação de dados\nggplot2 - Para apresentações visuais elegantes e práticas\nreadr - Para facilitar a tarefa de importar arquivos\ndevtools - Possibilitando o usuário criar seus próprios pacotes\nDentre muitos outros disponíveis no link para galeria de CheatSheets\nExemplos fornecidos por contribuidores Como mostrado anteriormente, o pacote devtools possibilita que qualquer usuário crie e disponibilize seus próprios pacotes, então além dos pacotes a comunidade também contribuiu com diversas cheatsheets, veja algumas delas:\ncaret - Pacote muito famoso quando o assunto é Machine Learning\nleaflet - Para criar mapas interativos com facilidade\n\\(\\LaTeX\\) - Linguagem muito útil e fácil para escrever muitos tipos de documentos\nComo podemos ver são muitas opções para consulta, ao encontrar o que nos torna mais confortável enquanto aprendemos a linguagem torna-se possível dar passos mais largos\nAprendizagem Online e a gamificação A gamificação é um conceito que vem sendo introduzido após a introdução da tecnologia na história. A idéia de se criar jogos para motivar e engajar as pessoas em atividades profissionais e a idéia de se estar em um jogo possibilita doses de motivação especialmente a quem gosta de competir.\nDataCamp No site oficial da RStudio encontramos além das cheatsheets, dentre seus recursos existe a opção de aprendizagem online onde é apresentada a DataCamp que é o primeiro e um dos mais importantes líderes em divulgar e ensinar Data Science, oferecendo treinamento baseado em habilidades, inovação técnica pioneira e cursos oferecidos pelos melhores educadores do mundo em data science!(Descrição deles no site)\nApesar do site ser pago, existem diversas opções de cursos gratuitos para quem esta começando e é muito simples e fácil aprender pelo site. Ao cumprir com exercícios e terminar os cursos o usuário ganha xp (pontos de experiencia) que registram sua evolução. Pode ser um ótimo investimento para aprender com os melhores do mundo e o legal de tudo isso é que nunca fica fácil!\nKaggle O kaggle é um playground para cientistas de dados, nele existem diversas modalidades e dentre elas uma das das que eu acho mais interessante são as competições de machine learning onde pessoas e empresas interessadas em adquirir ou até comparar seus resultados com os modelos feitos por uma enorme comunidade programando em diferentes linguagens estão testando para saber quem treina o modelo mais preciso e é possível acompanhar o código e o raciocínio de cientistas de dados do mundo inteiro de maneira muito simples!\nTambém existe a recompensa com pontos de experiencia para passar de nível, congratulação com medalhas dentre outras recopensas semelhantes ao dos games.\nExistem os famosos datasets que são os bancos de dados fornecidos pelos usuários da plataforma e os kernels é um ótimo lugar para compartilhar seu trabalho e debater sobre resultados de projetos e idéias de aplicações de outras pessoas\nAo contrário da DataCamp, o Kaggle é gratuito e existem competições pagando até $100.000,00 para a pesosa (ou equipe) que apresentar os resultados mais satisfatórios!!\nPara refletir.. “Há três métodos de ganhar sabedoria: primeiro, por reflexão, que é o mais nobre; segundo, por imitação, que é o mais fácil; e o terceiro, por experiência, que é o mais amargo.” - Confúcio\nEssa passagem de Confúcio deixa claro que não existe só um jeito de se aprender, com um mix de maneiras de se obter conhecimento fica um pouco menos difícil encontrar a sabedoria: estudar, exercitar e praticar se torna divertido quando se trata de programar em R!\nSe você quer colocar a prática em ação, os posts sobre a solução do Porto Seguro Data Challenge e sobre a competição de qualidade da educação, ambos no Kaggle, mostram esse aprendizado prático em projetos reais.\nPerguntas frequentes Onde encontro as cheatsheets oficiais do R? No catálogo de cheatsheets da Posit (antiga RStudio), que reúne referências rápidas para o RStudio, RMarkdown, dplyr, ggplot2 e dezenas de outros pacotes, todas gratuitas para download.\nDataCamp ou Kaggle: por onde começar? Para aprender do zero com trilhas guiadas e exercícios corrigidos, o DataCamp (pago, com cursos gratuitos) é mais estruturado. Para praticar em problemas reais, comparar soluções e competir, o Kaggle é gratuito e mais indicado depois de já ter alguma base.\nGamificação realmente ajuda a aprender programação? Ajuda como motivação, não como atalho: pontos, medalhas e rankings mantêm o engajamento ao longo do tempo, mas o aprendizado em si ainda vem da prática repetida e de errar bastante. É um empurrão psicológico, não uma técnica de ensino por si só.\n","date":"17 de fevereiro de 2018","externalUrl":null,"permalink":"/post/2018-02-17-cheatsheet-gamificacao-r/","section":"Posts","summary":" Você costuma ler o manual? Quando éramos crianças, geralmente não tínhamos o costume de ler o manual das coisas, não é mesmo? Particularmente eu sempre gostei de aprender como as coisas funcionavam diretamente com a prática para poder usá-las depois. Adorava buscar entender como as coisas se encaixavam ao montar os brinquedinhos do kinder-ovo sem ler as instruções ou criar diferentes combinações com lego customizados, por exemplo. Acredito que isso seja da natureza de toda criança!\n","title":"CheatSheets e gamificação: aprender R de forma divertida","type":"post"},{"content":"","date":"17 de fevereiro de 2018","externalUrl":null,"permalink":"/tags/datacamp/","section":"Tags","summary":"","title":"Datacamp","type":"tags"},{"content":" Onde estão os blocos? Fevereiro começando e o carnaval já está ai, especialmente se você mora no Rio de Janeiro já deve ter passado por algum bloco e a pergunta que todo mundo faz no carnaval pelo menos uma vez é: “Onde tem bloco?”.\nTL;DR\nUsamos ggmap para geocodificar (transformar endereço em latitude/longitude) os blocos de carnaval. O pacote leaflet (com leaflet.extras) plota tudo num mapa interativo. A limpeza de texto usa a função ajustar_nomes() do post sobre manipulação de strings. Baseado nessa pergunta resolvi fazer esse post especial, vamos utilizar os pacotes ggmap e leaflet para buscar as coordenadas geográficas do endereço dos blocos e representa-los num mapa agradável de navegar\nAlém disso utilizaremos o pacote leaflet.extras que conta com muitas opções para personaliza-lo.\nAo final do post você estará pronto para criar um mapa como (ou muito melhor) que esse:\nObtendo os dados Existem diversas maneiras de se descobrir via R informações como: aonde estão os blocos de carnaval, os endereços que ocorrem, suas coordenadas geográficas etc mas por conveniência vou utilizar essa base de dados obtida neste link com informações sobre os blocos que irão ocorrer no Rio de Janeiro que já foi disponibilizada como uma planilha de Excel.\nCaso tenha interesse em praticar a busca por outras localidades, talvez este post do blog curso-r sobre a API de busca do Google e este tópico no stackoverflow sobre como fazer a busca por localização baseado nas cordenadas (inverso da geocode() com revgeocode()) possam ser úteis)\nlibrary(readxl) base \u0026lt;- read_excel(\u0026quot;Agenda_BL_Rua_Carnaval_Rio-2018_Imprensa.xlsx\u0026quot;) Tratamento das strings Uma vez obtida a base de dados, os nomes das variáveis serão ajustadas de tal forma que possibilite sua manipulação. Para tal será utilizada a função ajustar_nomes() apresentada em um post que falo um pouco sobre Manipulação de strings e text mining.\nnames(base)=ajustar_nomes(names(base));names(base) ## [1] \u0026quot;bloco\u0026quot; \u0026quot;bairro\u0026quot; ## [3] \u0026quot;regiao\u0026quot; \u0026quot;data\u0026quot; ## [5] \u0026quot;data_relativa\u0026quot; \u0026quot;concentracao\u0026quot; ## [7] \u0026quot;desfile\u0026quot; \u0026quot;final\u0026quot; ## [9] \u0026quot;local_da_concentracao\u0026quot; \u0026quot;percurso\u0026quot; ## [11] \u0026quot;publico_estimado\u0026quot; \u0026quot;ano_do_primeiro_desfile\u0026quot; ## [13] \u0026quot;lon\u0026quot; \u0026quot;lat\u0026quot; A seguir a limpeza das strings que carregam a informação de onde será cada bloco também precisa passar por um processo de “limpeza” para possibilitar a busca pelas localizações com a função geocode().\nPara esse tipo de limpeza geralmente o uso de regex/expressão regular (que nada mais é que uma ótima forma de identificar cadeias de strings) facilita muito a forma como o computador entende e processa o que desejamos executar.\nAlém de todo material gratuito disponível na internet com uma simples busca no Google, para aprender a utilizar regex em suas aplicações de text mining essa Cheatsheet pode ser útil para uma consulta rápida.\nVeja a segui um exemplo de limpeza simples:\nbase$local_da_concentracao=base$local_da_concentracao%\u0026gt;% stringr::str_trim() %\u0026gt;% #Remove espaços em branco sobrando stringr::str_to_lower() %\u0026gt;% #Converte todas as strings para minusculo rm_accent() %\u0026gt;% #Remove acentos com a funcao disponível em * stringr::str_replace_all(\u0026quot;[/\u0026#39; \u0026#39;.()]\u0026quot;, \u0026quot; \u0026quot;) %\u0026gt;% #Substitui os caracteres especiais por \u0026quot; \u0026quot; stringr::str_replace_all(\u0026quot;_+\u0026quot;, \u0026quot; \u0026quot;) %\u0026gt;% #Substitui os caracteres especiais por \u0026quot; \u0026quot; stringr::str_replace(\u0026quot;_$\u0026quot;, \u0026quot; \u0026quot;)%\u0026gt;% #Remove o caracter especiais stringr::str_replace(\u0026quot;, esquina.*\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% #Remove a palavra \u0026quot;esquina\u0026quot; e tudo que vier depois dela stringr::str_replace(\u0026quot;n[º°].*\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% #Remove as strings \u0026quot;nº\u0026quot; e \u0026quot;n°\u0026quot; e tudo que vier depois delas stringr::str_replace(\u0026quot;em frente a.*\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% #Remove a sentença \u0026quot;em frente a\u0026quot; e tudo que vier depois dela stringr::str_replace_all(\u0026quot;[0-9]\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% #Remove numeros stringr::str_replace_all(\u0026quot;[:punct:]\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% #Remove pontuacao stringr::str_c(\u0026quot; rio de janeiro\u0026quot;) #Inclui a string \u0026quot;rio de janeiro\u0026quot;, que sera util em diante base=na.omit(base) #Remove linhas que contenham NA link para página do stackoverflow sobre a função rm_accent() Feita a limpeza completa da base agora vamos criar uma nova coluna com a tag que irá aparecer no mapa:\nfor(i in 1:nrow(base)){ base$label[i]=str_c(\u0026quot;Bloco: \u0026quot;,base$bloco[i],\u0026quot; - \u0026quot;,\u0026quot;Bairro: \u0026quot;,base$bairro[i],\u0026quot; - \u0026quot;,\u0026quot;Regiao: \u0026quot;, base$regiao, \u0026quot;Data: \u0026quot;, base$data[i], \u0026quot; - \u0026quot;, \u0026quot;Concentração\u0026quot;, str_sub(base$concentracao[i], start = 11) ) } O pacote ggmap Este pacote além de possuir uma coleção de funções para visualizar dados espaciais e modelos em cima de mapas estáticos de várias fontes on-line (por exemplo, Google Maps e Stamen Maps), inclui ferramentas comuns a essas tarefas, incluindo funções de geolocalização e roteamento.\nUtilizaremos a função de geolocalização com um loop pelos endereços para obter a latitude e longitude de cada endereço e adiciona-os a base de dados em novas colunas lat e lon, veja:\nlibrary(ggmap) for(i in 1:nrow(base)){ Print(\u0026quot;Buscando...\u0026quot;) result \u0026lt;- geocode(base$local_da_concentracao[i], output = \u0026quot;latlona\u0026quot;, source = \u0026quot;google\u0026quot;) base$lon[i] \u0026lt;- as.numeric(result[1]) base$lat[i] \u0026lt;- as.numeric(result[2]) } Obtendo algumas coordenadas geográficas para marcar no mapa:\nlon_copacabana=geocode(\u0026quot;Av. Atlantica\u0026quot;)[1] lat_copacabana=geocode(\u0026quot;Av. Atlantica\u0026quot;)[2] lon_ipanema=geocode(\u0026quot;Av. Vieira Souto\u0026quot;)[1] lat_ipanema=geocode(\u0026quot;Av. Vieira Souto\u0026quot;)[2] lon_lapa=geocode(\u0026quot;Rua da Lapa\u0026quot;)[1] lat_lapa=geocode(\u0026quot;Rua da Lapa\u0026quot;)[2] lon_paqueta=geocode(\u0026quot;Ilha de Paqueta\u0026quot;)[1] lat_paqueta=geocode(\u0026quot;Ilha de Paqueta\u0026quot;)[2] Agora basta utilizar o pacote leaflet em conjunto com o pacote leaflet.extras para criar o mapa:\n(Mais detalhes de como formatar seu mapa estão disponíveis na página do pacote no github)\nlibrary(leaflet) library(leaflet.extras) base%\u0026gt;% filter(lat\u0026lt;(-7)\u0026amp;lat\u0026lt;(-22)\u0026amp;lon\u0026gt;(-57)\u0026amp;lon\u0026lt;(-43.1))%\u0026gt;% #Removendo algumas cordenadas equivocadas leaflet() %\u0026gt;% #carrega o leaflet addTiles() %\u0026gt;% #adiciona as camadas de mapas de acordo com o zoom addMarkers(lng = ~lon, lat = ~lat,popup=~label, #mapeia a base de dados de acordo com as respectivas lat e lon clusterOptions = markerClusterOptions())%\u0026gt;% addResetMapButton() %\u0026gt;% #Adiciona botão para resetar mapa addPulseMarkers( lng=lon_copacabana , lat=lat_copacabana, #Endereço da orla de copacabana label=\u0026#39;Praia de Copacabana\u0026#39;, icon = makePulseIcon(heartbeat = 0.5))%\u0026gt;% addPulseMarkers( lng=lon_ipanema , lat=lat_ipanema, #Endereço da orla de ipanema label=\u0026#39;Praia de Ipanema\u0026#39;, icon = makePulseIcon(heartbeat = 0.5))%\u0026gt;% addPulseMarkers( lng=lon_lapa , lat=lat_lapa, #Endereço da lapa label=\u0026#39;Lapa\u0026#39;, icon = makePulseIcon(heartbeat = 0.5))%\u0026gt;% addPulseMarkers( lng=lon_paqueta , lat=lat_paqueta, #Endereço da ilha de paquetá label=\u0026#39;Ilha de Paquetá\u0026#39;, icon = makePulseIcon(heartbeat = 0.5)) Caso tenha interesse em consultar as informações da base de dados dos blocos que vão ocorrer no Rio de Janeiro para saber qual o bloco mais próximo de você e aproveitar o carnaval carioca a consulta pode ser feita a seguir:\nbloco bairro regiao data data_relativa concentracao desfile final local_da_concentracao percurso publico_estimado ano_do_primeiro_desfile label lon lat Xodó da Piedade Piedade Zona Norte 2 2018-01-07 Domingo - 5 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua mario carpenter rio de janeiro PARADO 1500 1972 Bloco: Xodó da Piedade - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-01-07 - Concentração 16:00:00 -43.29748 -22.88827 Bloco do Limão Jardim América Zona Norte 2 2018-01-13 Sábado - 4 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca rivadavia c maia rio de janeiro Parado 800 2010 Bloco: Bloco do Limão - Bairro: Jardim América - Regiao: Zona Norte 2Data: 2018-01-13 - Concentração 16:00:00 NA NA Seu Kuka é Eu do Grajaú Grajaú Tijuca e Adj 2018-01-13 Sábado – 4 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 largo maria martha ward rio de janeiro Parado 1200 2008 Bloco: Seu Kuka é Eu do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-01-13 - Concentração 16:00:00 -43.25977 -22.92039 Unidos do Rego Barros Santo Cristo Centro 2018-01-13 Terça de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua rego barros rio de janeiro Rua Rego Barros até o fim da rua Nabuco de Freitas, e termina na Rua Rego Barros 400 2012 Bloco: Unidos do Rego Barros - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-01-13 - Concentração 16:00:00 -43.19703 -22.90343 Vou Treinar e Volto Já Tijuca Tijuca e Adj 2018-01-13 Sábado - 4 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 rua martins pena rio de janeiro Rua Martins Pena, Rua Afonso Pena, Rua Haddock Lobo, Rua Campos Sales, Rua Martins Pena 500 2010 Bloco: Vou Treinar e Volto Já - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-01-13 - Concentração 15:00:00 -43.21803 -22.91739 Banda da Zulmira Maracanã Tijuca e Adj 2018-01-14 Domingo - 4 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 praca niteroi rua dona zulmira e rua felipe camarao rio de janeiro Parado 400 2014 Bloco: Banda da Zulmira - Bairro: Maracanã - Regiao: Zona Norte 2Data: 2018-01-14 - Concentração 14:00:00 NA NA Xodó da Piedade Piedade Zona Norte 2 2018-01-14 Domingo - 4 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua mario carpenter rio de janeiro PARADO 1500 1972 Bloco: Xodó da Piedade - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-01-14 - Concentração 16:00:00 -43.29748 -22.88827 Banda de Ipanema - Ensaio Ipanema Zona Sul 2018-01-20 Sábado - 3 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:30:00 1899-12-31 21:00:00 praca general osorio rio de janeiro Praça General Osório - Parado 5000 1965 Bloco: Banda de Ipanema - Ensaio - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 15:00:00 -43.19782 -22.98518 Bloco Carnavalesco Sempre Vila Vila isabel Tijuca e Adj 2018-01-20 Sábado – 3 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua sousa franco rio de janeiro Início na Rua Sousa Franco com a esquina Torres Homem, Término na Rua Sousa Franco com 28 de Setembro 1000 2018 Bloco: Bloco Carnavalesco Sempre Vila - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 14:00:00 NA NA Bloco do Limão Jardim América Zona Norte 2 2018-01-20 Sábado - 3 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca rivadavia c maia rio de janeiro Parado 800 2010 Bloco: Bloco do Limão - Bairro: Jardim América - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 16:00:00 NA NA Chame Gente São Conrado Zona Sul 2018-01-20 Domingo - 2 semanas antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 av prefeito mendes de moraes rio de janeiro Av. Prefeito Mendes de Moraes, da Rua Herbert Moses até o Hotel Golden Tulip 20000 2007 Bloco: Chame Gente - Bairro: São Conrado - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 08:00:00 -43.26461 -22.99947 É Pequeno mas não amolece Recreio dos Bandeirantes Barra/JPA 2018-01-20 Sábado - 3 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca professor henrique niremberg rio de janeiro Parado 500 2009 Bloco: É Pequeno mas não amolece - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 14:00:00 -43.46680 -23.02006 Larga a Onça, Alfredo! - Ensaio Laranjeiras Zona Sul 2018-01-20 Sábado - 3 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 praca sao salvador rio de janeiro Parado 2000 2008 Bloco: Larga a Onça, Alfredo! - Ensaio - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 15:00:00 NA NA Os “20” de Ouro do Mestre Odilon Ilha do Governador Zona Norte 3 2018-01-20 Sábado - 3 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 estrada do rio jequia posto necker pinto rio de janeiro Segue pela Estrada Rio Jequiá, Rua Maldonado, e Pça Iaiá Garcia 1500 2017 Bloco: Os “20” de Ouro do Mestre Odilon - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 16:00:00 NA NA Põe na Quentinha? Centro Centro 2018-01-20 Sábado – 13semanas antes do Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 rua conselheiro saraiva rio de janeiro Parado 1500 2015 Bloco: Põe na Quentinha? - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 13:00:00 -43.17828 -22.89841 Seu Kuka é Eu do Grajaú Grajaú Tijuca e Adj 2018-01-20 Sábado – 3 semanas antes do Carnaval 1899-12-31 16:00:00 1900-01-01 16:00:00 1900-01-01 22:00:00 largo maria martha ward rio de janeiro Parado 1200 2008 Bloco: Seu Kuka é Eu do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 16:00:00 -43.25977 -22.92039 TPM - Turma da Paz de Madureira Madureira Zona Norte 1 2018-01-20 Sábado - 2 semanas antes do Carnaval 1899-12-31 13:30:00 1899-12-31 17:30:00 1899-12-31 19:00:00 rio de janeiro Segue a Estrada do Portela até antes do Shopping Madureira. 500 2013 Bloco: TPM - Turma da Paz de Madureira - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-01-20 - Concentração 13:30:00 -43.17290 -22.90685 Banda do Jiló Tijuca Tijuca e Adj 2018-01-21 Domingo - 3 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 rua pinto de figueiredo rio de janeiro Parado 1000 2004 Bloco: Banda do Jiló - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-01-21 - Concentração 14:00:00 -43.23611 -22.92492 Divas do Recreio Recreio dos Bandeirantes Barra/JPA 2018-01-21 Domingo - 2 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 16:30:00 1899-12-31 21:00:00 quiosque e meio rio de janeiro Parado 3000 2014 Bloco: Divas do Recreio - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-01-21 - Concentração 15:00:00 -43.46226 -23.02702 Só Caminha Botafogo Zona Sul 2018-01-21 Domingo - 3 semanas antes do Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 largo dos leoes rio de janeiro Largo dos Leões, Rua Marques, Rua Capistrano de Abreu, Rua Conde de Irajá e Largo dos Leões 2000 2010 Bloco: Só Caminha - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-01-21 - Concentração 12:00:00 NA NA Xodó da Piedade Piedade Zona Norte 2 2018-01-21 Domingo - 3 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua mario carpenter rio de janeiro PARADO 1500 1972 Bloco: Xodó da Piedade - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-01-21 - Concentração 16:00:00 -43.29748 -22.88827 O Fervo Estácio Centro 2018-01-23 Terça-feira - 2 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua maia de lacerda rio de janeiro Rua Maia de Lacerda, da esquina da Rua Estácio de Sá até a Rua Sampaio Ferraz e termina na rua Quintino do Vale 500 2016 Bloco: O Fervo - Bairro: Estácio - Regiao: Zona Norte 2Data: 2018-01-23 - Concentração 14:00:00 -43.20601 -22.91710 Discípulos do Oswaldo Manguinhos Zona Norte 2 2018-01-24 Quarta-feira 2 semanas antes do Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua rosa da fonseca rio de janeiro Rua Rosa da Fonseca Rua Castro Tavares, Rua Sizenando Nabuco e Rua Rosa da Fonseca 1000 2002 Bloco: Discípulos do Oswaldo - Bairro: Manguinhos - Regiao: Zona Norte 2Data: 2018-01-24 - Concentração 17:00:00 -43.24853 -22.87420 Vestiu uma Camisinha Listrada e Saiu por Aí Centro Centro 2018-01-26 Sexta-feira - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 buraco do lume rio de janeiro Parado 2000 1992 Bloco: Vestiu uma Camisinha Listrada e Saiu por Aí - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-01-26 - Concentração 16:00:00 NA NA Amigos da Esquina Engenho de Dentro Zona Norte 2 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 rua de fevereiro rio de janeiro Parado 1000 2004 Bloco: Amigos da Esquina - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 15:00:00 -43.30096 -22.89715 Areia Leblon Zona Sul 2018-01-27 Sábado - 2 semana antes do Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 rua dias ferreira entre a avenida bartolomeu mitre e a rua general urquiza rio de janeiro Parado 3500 2003 Bloco: Areia - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 09:00:00 NA NA Banda de Ipanema Ipanema Zona Sul 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:30:00 1899-12-31 21:00:00 rua jangadeiros rio de janeiro Rua Gomes Carneiro, Avenida Vieira Souto, Rua Joana Angélica e Rua Visconde de Pirajá, até a Praça General Osório 50000 1965 Bloco: Banda de Ipanema - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 15:00:00 NA NA Bloco Carnavalesco Bunda Rachada Ramos Zona Norte 3 2018-01-27 sábado - 2 semanas antes do carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua romero zander n rio de janeiro rua romero zander n. 363, Av. dos campeoes n.569 2000 2001 Bloco: Bloco Carnavalesco Bunda Rachada - Bairro: Ramos - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.25396 -22.85694 Bloco do Cocoloko Barra da Tijuca Barra/JPA 2018-01-27 Sexta-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 10:00:00 1899-12-31 16:00:00 lucio costa rio de janeiro Parado 15000 2016 Bloco: Bloco do Cocoloko - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 10:00:00 -43.39362 -23.01303 Bloco do Limão Jardim América Zona Norte 2 2018-01-27 Sábado - 2 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca rivadavia c maia rio de janeiro Parado 800 2010 Bloco: Bloco do Limão - Bairro: Jardim América - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 NA NA Cacique de Higienópolis Higienópolis Zona Norte 2 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua tamiarana rio de janeiro Parado 500 2012 Bloco: Cacique de Higienópolis - Bairro: Higienópolis - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.26525 -22.87606 Cadê Meu Beijo? Ilha do Governador Zona Norte 3 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 21:00:00 rua luis sa rio de janeiro Parado 2000 2014 Bloco: Cadê Meu Beijo? - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 15:00:00 -43.20278 -22.79958 Calma Amor Irajá Zona Norte 1 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 praca ferreira souto rio de janeiro Parado 5000 2010 Bloco: Calma Amor - Bairro: Irajá - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.32897 -22.82782 Carmelitas (ENSAIO) Centro Centro 2018-01-27 Sabado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 praca tiradentes rio de janeiro PARADO 800 1990 Bloco: Carmelitas (ENSAIO) - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 NA NA Cordão do Prata Preta Gamboa Centro 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 17:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 praca coronel assumpcao praca da harmonia rio de janeiro Parado 800 2005 Bloco: Cordão do Prata Preta - Bairro: Gamboa - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 17:00:00 -43.19164 -22.89552 Deixa a Língua no Varal Tijuca Tijuca e Adj 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua barao de mesquita rio de janeiro Rua Barão de Mesquita, Rua Deputado Soares Filho, Praça Hilda, Rua Pareto, Rua Almirante Cochrane, Rua Santo Afonso, Rua Pinto de Figueiredo, Av. Maracanã e Rua Barão de Mesquita 136 500 2008 Bloco: Deixa a Língua no Varal - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.24249 -22.92423 Desliga da Justiça Gávea Zona Sul 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 praca santos dumont rio de janeiro Parado 5000 2010 Bloco: Desliga da Justiça - Bairro: Gávea - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 08:00:00 NA NA É Pequeno mas não amolece Recreio dos Bandeirantes Barra/JPA 2018-01-27 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca professor henrique niremberg rio de janeiro Parado 500 2009 Bloco: É Pequeno mas não amolece - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 14:00:00 -43.46680 -23.02006 GB Bloco Laranjeiras Zona Sul 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praca jardim laranjeiras rua general glicerio rio de janeiro Rua General Glicério, Rua General Cristóvão Barcelos, retornando à Praça Jardim Laranjeiras 5000 2007 Bloco: GB Bloco - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 13:00:00 -43.19168 -22.94090 Imprensa Que Eu Gamo Laranjeiras Zona Sul 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 rua gago coutinho rio de janeiro Rua Gago Coutinho, Largo do Machado, Rua das Laranjeiras e Rua Gago Coutinho 15000 1996 Bloco: Imprensa Que Eu Gamo - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 13:00:00 -43.18117 -22.93131 Liga de Blocos e Bandas da Zona Portuária Saúde Centro 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 praca coronel assuncao praca da harmonia rio de janeiro Rua Sacadura Cabral, da Praça da Harmonia até o Largo São Francisco da Prainha 1500 2008 Bloco: Liga de Blocos e Bandas da Zona Portuária - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 10:00:00 -43.19164 -22.89552 Nem Muda Nem Sai de Cima Tijuca Tijuca e Adj 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua garibaldi rio de janeiro Rua Garibaldi, Rua Pinto Guedes, Praça Xavier de Brito, Rua Otávio Kelly, Rua Conde de Bonfim e Rua Garibaldi, voltando ao local de concentração 1000 1995 Bloco: Nem Muda Nem Sai de Cima - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.24575 -22.93326 Panela Preta de Curicica Curicica Barra/JPA 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua joao bruno lobo rio de janeiro Rua João Bruno Lobo, nº 38 - Parado 1000 2011 Bloco: Panela Preta de Curicica - Bairro: Curicica - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 14:00:00 -43.38295 -22.95338 Pra que Juízo Vila da Penha Zona Norte 1 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 largo do bicao rio de janeiro Av. Braz de Pina (Altura do Mc Donalds) seguindo até a Rua Oliveira Belo 2000 2018 Bloco: Pra que Juízo - Bairro: Vila da Penha - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.30946 -22.84408 Primeiro Amor São Conrado Barra/JPA 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 13:00:00 rio de janeiro Saindo do Golfe Clube até o final 6000 2013 Bloco: Primeiro Amor - Bairro: São Conrado - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 08:00:00 -43.17290 -22.90685 Se Concentra mas Não Sai e Caldeirão Campo Grande Zona Oeste 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua ministro carlos medeiros rio de janeiro Parado 500 2010 Bloco: Se Concentra mas Não Sai e Caldeirão - Bairro: Campo Grande - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.53589 -22.88051 Se Deixar Eu Boto Pavuna Zona Norte 1 2018-01-27 Sábado - 2 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua sargento manoel chagas com rua capitao gouveia rio de janeiro Parado 1200 2012 Bloco: Se Deixar Eu Boto - Bairro: Pavuna - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 17:00:00 NA NA Seu Kuka é Eu do Grajaú Grajaú Tijuca e Adj 2018-01-27 Sábado – 2 semanas antes do Carnaval 1899-12-31 16:00:00 1900-01-02 16:00:00 1900-01-02 22:00:00 largo maria martha ward rio de janeiro Parado 1200 2008 Bloco: Seu Kuka é Eu do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 16:00:00 -43.25977 -22.92039 Spanta Neném Lagoa Zona Sul 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 10:00:00 1899-12-31 13:00:00 1899-12-31 16:00:00 corte do cantagalo rio de janeiro Ciclovia da Lagoa, do Corte do Cantagalo até o Clube Caiçaras 5000 2003 Bloco: Spanta Neném - Bairro: Lagoa - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 10:00:00 -43.19385 -22.97667 Vira-Lata São Conrado Zona Sul 2018-01-27 Sábado - 2 semanas antes do Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 rio de janeiro Saindo do Golfe Clube até o final 5000 2009 Bloco: Vira-Lata - Bairro: São Conrado - Regiao: Zona Norte 2Data: 2018-01-27 - Concentração 13:00:00 NA NA Alegria Sem Ressaca Copacabana Zona Sul 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 09:00:00 1899-12-31 09:00:00 1899-12-31 12:00:00 av atlantica rio de janeiro Parado 500 2007 Bloco: Alegria Sem Ressaca - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 09:00:00 -43.18147 -22.96953 Banda Amigos da Barra Barra da Tijuca Barra/JPA 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 av lucio costa barramares rio de janeiro Segue na Av. Lucio Costa até a altura da Praça do Ó 5000 2017 Bloco: Banda Amigos da Barra - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 13:00:00 -43.32828 -23.01094 Banda da Saens Pena Tijuca Tijuca e Adj 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 praca saens pena rio de janeiro Parado 200 2005 Bloco: Banda da Saens Pena - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 15:00:00 -43.23196 -22.92420 Bigodinho Esticado Méier Zona Norte 2 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 rua adriano rio de janeiro Parado 400 2010 Bloco: Bigodinho Esticado - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 15:00:00 -43.28871 -22.89989 Bloco do Demorô Cidade Nova Centro 2018-01-28 Domingo - 2 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 praca coronel castelo branco rio de janeiro Parado 300 2016 Bloco: Bloco do Demorô - Bairro: Cidade Nova - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 14:00:00 NA NA Bloco dos Gambás Rio Comprido Centro 2018-01-28 Domingo – 2 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua aristides lobo rio de janeiro Rua Aristides Lobo até a esquina da Rua Maia de Lacerda, Retorno Aristides Lobo 217 1000 2013 Bloco: Bloco dos Gambás - Bairro: Rio Comprido - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 14:00:00 -43.20868 -22.92058 Calma, Calma Sua Piranha Botafogo Zona Sul 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 rua visconde de caravelas rio de janeiro Rua Visconde de Caravelas, da Rua Real Grandeza até a Rua Capitão Salomão 500 2006 Bloco: Calma, Calma Sua Piranha - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 08:00:00 -43.19508 -22.95684 Chinelo de Dedo Centro Centro 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua do mercado rio de janeiro Parado 1000 2015 Bloco: Chinelo de Dedo - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 16:00:00 -43.17489 -22.90189 Coração das Meninas Saúde Centro 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 largo da prainha rio de janeiro Rua Sacadura Cabral ao Largo da Prainha até Praça da Harmonia 500 1964 Bloco: Coração das Meninas - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 16:00:00 -43.18428 -22.89770 Fala Meu Louro Santo Cristo Centro 2018-01-28 Sábado - 2 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua waldemar dutra rio de janeiro Rua Waldemar Dutra, Praça do Santo Cristo, Rua da América, Rua Barão da Gamboa, Rua Cardoso Marinho, Rua Santo Cristo e Rua Waldemar Dutra. 800 1938 Bloco: Fala Meu Louro - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 14:00:00 -43.20039 -22.90082 Foliões do Rio Ilha do Governador Zona Norte 3 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 praca jerusalem rio de janeiro Av. Alves Câmara Junior (Praia da Bica), da Praça Jerusalém até o nº 819 (Quiosque 22) 3500 2014 Bloco: Foliões do Rio - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 12:00:00 -43.20120 -22.81882 Independente do Morro do Pinto Santo Cristo Centro 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua farnese rio de janeiro Rua Farnese, Rua Saldanha Marinho, Rua Mariano Procópio, Rua Sara, Rua Mont Alverne 500 1973 Bloco: Independente do Morro do Pinto - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 14:00:00 -43.20318 -22.90436 Me Esquece Jardim Botânico Zona Sul 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 rua jardim botanico rio de janeiro Rua Jardim Botânico, da Rua Pacheco Leão até a Praça Santos Dumont 5000 2004 Bloco: Me Esquece - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 09:00:00 -43.21732 -22.96402 MultiBloco (Ensaio) Lapa Centro 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 15:30:00 1899-12-31 16:00:00 1899-12-31 18:30:00 rua dos invalidos rio de janeiro Parado 250 2009 Bloco: MultiBloco (Ensaio) - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 15:30:00 -43.18491 -22.91157 Pra Se Apaixonar Quintino Bocaiúva Zona Norte 1 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua vital rio de janeiro Parado 4000 2013 Bloco: Pra Se Apaixonar - Bairro: Quintino Bocaiúva - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 16:00:00 NA NA Se Cair Eu Como Ilha do Governador Zona Norte 3 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 16:00:00 praca da freguesia rio de janeiro Orla da Praia da Guanabara até a Praça do Bananal (Pedra da Onça) 3000 2011 Bloco: Se Cair Eu Como - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 10:00:00 -43.34370 -22.94059 Tudo Nosso Tamo Junto Copacabana Zona Sul 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 13:00:00 1899-12-31 13:00:00 1899-12-31 19:00:00 rua ronald de carvalho rio de janeiro Parado 300 2016 Bloco: Tudo Nosso Tamo Junto - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 13:00:00 -43.17694 -22.96491 Volta, Alice Laranjeiras Zona Sul 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 rua alice rio de janeiro Rua Alice, do nº 1 ao nº 550 - esquina com Mario Portela 5000 2005 Bloco: Volta, Alice - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 08:00:00 -43.19463 -22.93538 Xodó da Piedade Piedade Zona Norte 2 2018-01-28 Domingo - 2 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua mario carpenter rio de janeiro PARADO 1500 1972 Bloco: Xodó da Piedade - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-01-28 - Concentração 16:00:00 -43.29748 -22.88827 Discípulos do Oswaldo Manguinhos Zona Norte 2 2018-01-31 Quarta-feira 1 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua rosa da fonseca rio de janeiro Rua Rosa da Fonseca Rua Castro Tavares, Rua Sizenando Nabuco e Rua Rosa da Fonseca 1000 2002 Bloco: Discípulos do Oswaldo - Bairro: Manguinhos - Regiao: Zona Norte 2Data: 2018-01-31 - Concentração 17:00:00 NA NA Batuke Nuclear Centro Centro 2018-02-01 Quinta-feira - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua da candelaria rio de janeiro Parado 500 2007 Bloco: Batuke Nuclear - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-01 - Concentração 18:00:00 NA NA Inova que eu Gosto Flamengo Zona Sul 2018-02-01 Quinta-feira 1 semanas antes do Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua barao do flamengo rio de janeiro Rua Barão do Flamengo, da esquina com Praia do Flamengo até a Rua Senador Vergueiro 2000 2008 Bloco: Inova que eu Gosto - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-01 - Concentração 17:00:00 -43.17597 -22.93308 Badalo de Santa Teresa Santa Teresa Centro 2018-02-02 Sexta-feira - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 largo das neves rio de janeiro Parado 1000 1972 Bloco: Badalo de Santa Teresa - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-02 - Concentração 16:00:00 NA NA É Pequeno, mas vai Crescer Centro Centro 2018-02-02 Sexta-feira - 1 semana antes do Carnaval 1899-12-31 17:30:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua alexandre mackenzie esquina com rua senador pompeu rio de janeiro Parado 400 2005 Bloco: É Pequeno, mas vai Crescer - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-02 - Concentração 17:30:00 NA NA Ih, É Carnaval! Urca Zona Sul 2018-02-02 Sexta-feira - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 av pasteur rio de janeiro Segue pela Av. Pasteur anumero 250 até a Praça Medalha Milagrosa 5000 2003 Bloco: Ih, É Carnaval! - Bairro: Urca - Regiao: Zona Norte 2Data: 2018-02-02 - Concentração 18:00:00 -43.17341 -22.95237 Molha o Pé das Oito Centro Centro 2018-02-02 Sexta-feira - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 buraco do lume rio de janeiro Rua São José, Rua Rodrigo Solva, Rua da Assembléia, Rua do Carmo e Rua São José 500 2010 Bloco: Molha o Pé das Oito - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-02 - Concentração 18:00:00 -43.17511 -22.90502 Ninho dos Cobras Centro Centro 2018-02-02 Sexta-feira - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 19:30:00 1899-12-31 22:00:00 largo sao francisco da prainha rio de janeiro PARADO 800 2013 Bloco: Ninho dos Cobras - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-02 - Concentração 18:00:00 -43.18428 -22.89770 Aconteceu Santa Teresa Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1900-01-04 16:00:00 1900-01-04 18:00:00 1900-01-04 22:00:00 rua aurea rio de janeiro Parado 1000 2000 Bloco: Aconteceu - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.18873 -22.92238 Alegria do Sapê Bento Ribeiro Zona Norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 rua picui rio de janeiro Rua Picui 895 até o número 500, Largo do Sapê e volta 800 2016 Bloco: Alegria do Sapê - Bairro: Bento Ribeiro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 NA NA Amigos da Esquina Engenho de Dentro Zona Norte 2 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua pernambuco rio de janeiro Rua Pernambuco, Rua Barbacena e Rua Pernambuco 1000 2004 Bloco: Amigos da Esquina - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 18:00:00 -43.29923 -22.89870 Amigos da Sueca da Pedro Américo Catete Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 21:30:00 rua pedro americo rio de janeiro Parado 1000 2010 Bloco: Amigos da Sueca da Pedro Américo - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 17:00:00 -43.18153 -22.92421 Aquilah Madureira Zona norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 16:30:00 1899-12-31 19:30:00 parque de madureira portao rio de janeiro Parque de Madureira portão 03, saindo pela pista até o portão 02 e retornando pelo mesmo local 450 2012 Bloco: Aquilah - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.35897 -22.84939 Banda Bandida Copacabana Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua rodolfo dantas rio de janeiro Rua Rodolfo Dantas, Rua Barata Ribeiro, Rua Hilário de Gouveia, Avenida Nossa Senhora de Copacabana e volta Rua Rodolfo Dantas 2000 1977 Bloco: Banda Bandida - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.17892 -22.96607 Banda da Penha Penha Zona Norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 largo da rua couto rio de janeiro Parado 1000 2014 Bloco: Banda da Penha - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.23597 -22.89044 Banda de Vila Isabel Vila isabel Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca rio de janeiro Barão do São Francisco, Teodoro da Silva, Gonzaga Bastos, 28 de Setembro pista de direita até Visconde de abaeté 3000 1977 Bloco: Banda de Vila Isabel - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.17359 -22.90309 Banda do Pechincha Pechincha Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 largo do pechincha rio de janeiro Estrada do Pau Ferro, do nº 15 ao nº 240 10000 2003 Bloco: Banda do Pechincha - Bairro: Pechincha - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 12:00:00 -43.35473 -22.92881 Banda do Tijuca Tênis Clube Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 tijuca tenis clube rio de janeiro R. conde do bonfim , R. Pareto, R. santo afonso, R. general Roca, R. conde do bonfim . 1000 1975 Bloco: Banda do Tijuca Tênis Clube - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 17:00:00 -43.23484 -22.92681 Banda Haddock Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua afonso pena rio de janeiro Rua Afonso Pena, Rua Haddock Lobo, Rua Campos Sales, Doutor Satamini, São Francisco Xavier, Largo da Segunda-feira, Rua Haddock Lobo e Rua Afonso Pena 2200 1984 Bloco: Banda Haddock - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.21880 -22.91777 Batuke de Ciata Saúde Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 praca coronel assuncao praca da harmonia rio de janeiro Rua Sacadura Cabral, Rua Argemiro Bulcao, Pedra do Sal. 500 2015 Bloco: Batuke de Ciata - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.19164 -22.89552 Batuke Imperial São Cristóvão Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 praca carmela dutra rio de janeiro Praça Carmela Dutra, Rua Gal Almeiro de Moura, Rua Teixeira Junior, Rua São Januário, Rua Gal Argolo, Rua Gal José Cristino, Largo do Viana 800 2018 Bloco: Batuke Imperial - Bairro: São Cristóvão - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.22935 -22.88982 Batuquebato centro centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 praca xv rio de janeiro Parado 800 2016 Bloco: Batuquebato - Bairro: centro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 09:00:00 -43.17359 -22.90309 Blocão da Tijuca Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 13:00:00 praca saens pena rio de janeiro PARADO 500 2016 Bloco: Blocão da Tijuca - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 09:00:00 -43.23196 -22.92420 Bloco Brasil Leme Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 12:00:00 1899-12-31 12:00:00 1899-12-31 18:00:00 praca almirante julio de noronha rio de janeiro Praça Almirante Julio de Noronha - Parado 10000 2007 Bloco: Bloco Brasil - Bairro: Leme - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 12:00:00 -43.16543 -22.96175 Bloco D’ Samba Recreio dos Bandeirantes Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 posto do recreio rio de janeiro Posto 10 do Recreio ao Posto 9. 3000 2016 Bloco: Bloco D’ Samba - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 10:00:00 NA NA Bloco da Ansiedade Centro Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 boulevard olimpico rio de janeiro NA 5000 1997 Bloco: Bloco da Ansiedade - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.18108 -22.89662 Bloco da Familha Ilha do Governador Zona Norte 3 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 praia da bica rio de janeiro Praça Jerusalém seguindo até o Rei do Bacalhau 2500 2018 Bloco: Bloco da Familha - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.19842 -22.81857 Bloco da Mamadeira Botafogo Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 praca parque general leandro rio de janeiro Parado 200 2003 Bloco: Bloco da Mamadeira - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.17456 -22.95547 Bloco da Pracinha Jardim Botânico Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 14:00:00 praca pio xi rio de janeiro Parado 500 2006 Bloco: Bloco da Pracinha - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 10:00:00 -43.21734 -22.96133 Bloco da Sá Pereira Infantil Botafogo Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 rua capistrano de abreu rio de janeiro Rua Capistrano de Abreu, Rua Conde de Irajá, Largo dos Leões, Rua São Clemente, Rua Marques e Rua Capistrano de Abreu 600 1990 Bloco: Bloco da Sá Pereira Infantil - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 08:00:00 -43.19582 -22.95443 Bloco da Saara Centro Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praca do mascate rio de janeiro Parado 300 2018 Bloco: Bloco da Saara - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 NA NA Bloco da Urubuzada Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praca afonso pena rio de janeiro Praça Afonso Pena, Rua Campos Sales, Rua Mariz e Barros, R. Afonso Pena terminando na Praça novamente. 1000 2008 Bloco: Bloco da Urubuzada - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.21816 -22.91806 Bloco do Balde Sulacap Zona Oeste 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 20:30:00 praca h rua antonio de mendonca rio de janeiro Saída Rua Antonio de Mendonça, Rua Teofilo Guimarães, Rua Gonçalo Rollemberg, Rua Barbara Heliodor, Rua Teodoro Sampaio, Rua Oliveira Martins, Rua Maria Grham, Para na Praça Nino Roland, Retorno, Maria Grham, Rua Oliveira Martins, Rua Teodoro Sampaio, Rua Guilherme Francisco Cruz, Rua Olimpio de Castro e término na Rua Antonio de Mendonça. 500 1968 Bloco: Bloco do Balde - Bairro: Sulacap - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 17:00:00 NA NA Bloco do Cocoloko Barra da Tijuca Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 lucio costa rio de janeiro Parado 15000 2016 Bloco: Bloco do Cocoloko - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 NA NA Bloco do Esporte Clube Jardim Guanabara Ilha do Governador Zona Norte 3 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 praca jerusalem rio de janeiro Prç. Jerusalém em frente ao E.C. Jardim Guanabara, Praia da bica até o Rei do bacalhau, entra na rua babaçu, retornando pela rua Mangalo, rua Henrique Lacombe em direçao a praia da Bica, seguindo até a praça jerusalém. 800 2000 Bloco: Bloco do Esporte Clube Jardim Guanabara - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 08:00:00 -43.20120 -22.81882 Bloco do Ipê Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 18:00:00 rua alm cochrane rio de janeiro Vira na Rua Dulce até a Rua São Francisco Xavier retornando a origem. 150 2008 Bloco: Bloco do Ipê - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.22771 -22.92081 Bloco do Limão Jardim América Zona Norte 2 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca rivadavia c maia rio de janeiro Parado 800 2010 Bloco: Bloco do Limão - Bairro: Jardim América - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 NA NA Bloco do Rock Centro Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 largo de sao francisco rio de janeiro Parado 2000 2014 Bloco: Bloco do Rock - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 18:00:00 -43.18111 -22.90520 Bloco dos Mendigos Copacabana Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 15:00:00 rua bulhoes de carvalho rio de janeiro Rua Bulhões de Carvalho, Rua Rainha Elizabeth, Rua Teresa Aragão, Rua Gomes Carneiro e Rua Bulhões de Carvalho 3000 2006 Bloco: Bloco dos Mendigos - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 10:00:00 -43.19351 -22.98470 Boca Aberta Bonsucesso Zona Norte 2 2018-02-03 Quarta- feira- 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca da nova holanda rio de janeiro Rua Sargento Silva nunes, Rua Principal, Rua São Jorge 400 2014 Bloco: Boca Aberta - Bairro: Bonsucesso - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -41.77393 -22.35894 Butano na Bureta Maracanã Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 13:00:00 1899-12-31 19:00:00 rua senador furtado rio de janeiro Rua Senador Furtado, da Rua Pará até a Avenida Radial Oeste, voltando pela Senador Furtado até a concentração 1000 2009 Bloco: Butano na Bureta - Bairro: Maracanã - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.21869 -22.91168 Calma Amor Irajá Zona Norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 praca ferreira souto rio de janeiro Parado 5000 2010 Bloco: Calma Amor - Bairro: Irajá - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.32897 -22.82782 Carmelitas (ENSAIO) Centro Centro 2018-02-03 Sabado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 praca tiradentes rio de janeiro PARADO 800 1990 Bloco: Carmelitas (ENSAIO) - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -41.50799 -17.86413 Céu na Terra Santa Teresa Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 07:00:00 1899-12-31 08:00:00 1899-12-31 11:00:00 largo dos guimaraes rio de janeiro Rua Pascoal Carlos Magno, Rua Monte Alegre, Rua Oriente, Rua Progresso, Largo das Neves 7000 2001 Bloco: Céu na Terra - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 07:00:00 NA NA Confraria da Bebidinha Abolição Zona Norte 2 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 rua da abolicao rio de janeiro Saindo da Rua da Abolição, 671 (Calçada do Banco Itaú) pela Rua da Abolição até a esquina da Rua Mario Carpenter e retorno pela Rua Abolição até o local da Concentração 1000 2008 Bloco: Confraria da Bebidinha - Bairro: Abolição - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.29638 -22.88781 É Pequeno mas não amolece Recreio dos Bandeirantes Barra/JPA 2018-02-03 Sábado - 2 semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca professor henrique niremberg rio de janeiro Parado 500 2009 Bloco: É Pequeno mas não amolece - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 NA NA Embalo da Barão Praça Seca Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 rua barao rio de janeiro Parado 500 2003 Bloco: Embalo da Barão - Bairro: Praça Seca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.35215 -22.89882 Encosta que Ele Cresce Vista Alegre Zona Norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua ribadejo rio de janeiro Rua Ribadejo, Estrada da Água Grande 800 até o 1525, supermercado intercontinental e retorna do outro lado 1000 2006 Bloco: Encosta que Ele Cresce - Bairro: Vista Alegre - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 NA NA Eu Amo a Lapa Lapa Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 praca cardeal camara arcos da lapa rio de janeiro Parado 1000 2007 Bloco: Eu Amo a Lapa - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.17996 -22.91304 Eu Não Venho Mais Aqui Abolição Zona Norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua gaspar rio de janeiro Rua Ferreira Leite, da Rua Gaspar até a Rua Glaziou, retornando ao local de concentração 300 2011 Bloco: Eu Não Venho Mais Aqui - Bairro: Abolição - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.29785 -22.87997 Fla Master Barra da Tijuca Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 av lucio costa rio de janeiro Parado 1000 2016 Bloco: Fla Master - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 12:00:00 -43.39362 -23.01303 Fuzuê… Só Alegria Pra Você! Del Castilho Zona Norte 2 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua chapadinha rio de janeiro Rua Chapadinha, Rua Lagoa Verde, Rua Lagoa Clara, Rua Lagoa Redonda, Rua Chapadinha e Rua Palmeira do Norte 2000 2004 Bloco: Fuzuê… Só Alegria Pra Você! - Bairro: Del Castilho - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 NA NA Ilha Encosta que Ele Cresce Ilha do Governador Zona Norte 3 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 21:00:00 praca jerusalem rio de janeiro Av. Alves Câmara Junior (Praia da Bica), da Praça Jerusalém até o nº 1.191 (Farol da Ilha) 900 2010 Bloco: Ilha Encosta que Ele Cresce - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.20120 -22.81882 Imaginô? Agora Amassa! Leblon Zona Sul 2018-02-03 Sexta - 1 semana antes do Carnaval 1899-12-31 07:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 rua jose linhares rio de janeiro Rua José Linhares, Avenida Ataulfo de Paiva, seguindo até a esquina da Carlos Góis 10000 2003 Bloco: Imaginô? Agora Amassa! - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 07:00:00 NA NA Já Comi Pior Pagando Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua leite de abreu rio de janeiro PARADO 1000 2010 Bloco: Já Comi Pior Pagando - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 NA NA Lexa – Vem Que To Querendo Bangu Zona Oeste 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 praca da fe rio de janeiro Parado 2000 2018 Bloco: Lexa – Vem Que To Querendo - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.46467 -22.88198 Me Engana Que Eu Gosto Botafogo Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca joia valansi rio de janeiro Parado 1000 1985 Bloco: Me Engana Que Eu Gosto - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.18379 -22.94535 Mini Bloco Tijuca Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 09:00:00 1899-12-31 09:00:00 1899-12-31 14:00:00 praca xavier de brito rio de janeiro Parado 900 2013 Bloco: Mini Bloco - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 09:00:00 NA NA Mistura de Santa Santa Teresa Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 mirante do rato molhado rio de janeiro Segue pela Rua Aprazível até dispersar na lateral do Castelo São Valentim na parte alta da Rua Almirante Alexandrino. 500 2014 Bloco: Mistura de Santa - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 17:00:00 -43.18664 -22.92389 Morde e Pica Toda Hora Jacarepaguá Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 rua jorge faraj rio de janeiro Parado 200 2012 Bloco: Morde e Pica Toda Hora - Bairro: Jacarepaguá - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.39277 -22.97223 Os Monarcas Ilha do Governador Zona Norte 3 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praia da engenhoca quiosque rio de janeiro Subida Rua Paramopama, retornando pela Praça Iaiá Garcia, pela Fernando da Fonseca, Rua do Airão até a Praia da Engenhoca 500 2003 Bloco: Os Monarcas - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.17094 -22.82154 Parei de Beber, Não de Mentir! Curicica Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 praca do bandolim rio de janeiro Parado 3000 2009 Bloco: Parei de Beber, Não de Mentir! - Bairro: Curicica - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 15:00:00 -43.38358 -22.95797 Pérola da Guanabara Ilha de Paquetá Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 praca sao roque rio de janeiro Parado 10000 2011 Bloco: Pérola da Guanabara - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.11057 -22.75631 Pinto Sarado Santo Cristo Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 travessa sara rio de janeiro Travessa Sara, Rua Atilia, Rua Orestes, Rua Sara, Rua Santo Cristo, Rua da América e Rua Barão da Gamboa. 1500 2007 Bloco: Pinto Sarado - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.20367 -22.90172 Plantão Bom é Sambaia Vila isabel Tijuca e Adj 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 13:00:00 1899-12-31 17:00:00 praca maracana rio de janeiro Parado 100 2011 Bloco: Plantão Bom é Sambaia - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.23593 -22.91327 Põe na Quentinha? Centro Centro 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 rua conselheiro saraiva rio de janeiro Parado 1500 2015 Bloco: Põe na Quentinha? - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.17828 -22.89841 Pra que Juízo Vila da Penha Zona Norte 1 2018-02-03 Sábado - 1 semanas antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 largo do bicao rio de janeiro Av. Braz de Pina (Altura do Mc Donalds) seguindo até a Rua Oliveira Belo 2000 2018 Bloco: Pra que Juízo - Bairro: Vila da Penha - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.30946 -22.84408 Rio Pandeiro Laranjeiras Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 13:00:00 1899-12-31 19:00:00 praca sao salvador rio de janeiro Parado 600 2010 Bloco: Rio Pandeiro - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 13:00:00 -43.18082 -22.93400 Se Deixar Eu Boto Pavuna Zona Norte 1 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua sargento manoel chagas com rua capitao gouveia rio de janeiro Parado 1200 2012 Bloco: Se Deixar Eu Boto - Bairro: Pavuna - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 17:00:00 NA NA Serrote Afiado Engenho da Rainha Zona Norte 2 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua mario ferreira rio de janeiro Rua Mario Ferreira, Rua Ferreira de Menezes, Rua pereira pinto, Rua Carlos Gonçalves Penna. 1000 2004 Bloco: Serrote Afiado - Bairro: Engenho da Rainha - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.29556 -22.87108 Seu Kuka é Eu do Grajaú Grajaú Tijuca e Adj 2018-02-03 Sábado – 1 semana antes do Carnaval 1899-12-31 16:00:00 1900-01-03 16:00:00 1900-01-03 22:00:00 largo maria martha ward rio de janeiro Parado 1200 2008 Bloco: Seu Kuka é Eu do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 -43.25977 -22.92039 Simpatia é Quase Amor Ipanema Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 teixeira de melo praia rio de janeiro Rua Teixeira de Melo e Avenida Vieira Souto até a Henrique Dumont 300000 1985 Bloco: Simpatia é Quase Amor - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 14:00:00 -43.19866 -22.98531 Só o Cume Interessa Urca Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 13:00:00 1899-12-31 16:00:00 praca general tiburcio rio de janeiro PARADO 300 2005 Bloco: Só o Cume Interessa - Bairro: Urca - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 10:00:00 -43.16549 -22.95523 Vem Mamar Jacarepaguá Barra/JPA 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 largo da capela rio de janeiro Parado 300 2014 Bloco: Vem Mamar - Bairro: Jacarepaguá - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 16:00:00 NA NA Xupa Mas Não Baba Laranjeiras Zona Sul 2018-02-03 Sábado - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 rua alice rio de janeiro Rua Alice, do nº 1 ao nº 550 - esquina com Mario Portela 800 1989 Bloco: Xupa Mas Não Baba - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-03 - Concentração 10:00:00 -43.19463 -22.93538 Acorda e vem Brincar Vila Valqueire Barra/JPA 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 13:00:00 1899-12-31 16:00:00 rua das dalias rio de janeiro Rua das Dálias, Rua das Verbenas, Rua das Camélias e Rua das Dálias 1000 2007 Bloco: Acorda e vem Brincar - Bairro: Vila Valqueire - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 10:00:00 -43.36476 -22.87965 Bailinho do Capitão Trombeta Ilha do Governador Zona Norte 3 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 12:00:00 praca iaia garcia rio de janeiro Parado 100 2018 Bloco: Bailinho do Capitão Trombeta - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 08:00:00 -43.16952 -22.82582 Banda da Amizade Lapa Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua tadeu kosciusco rio de janeiro Rua Tadeu Kosciusko, Carlos Sampaio, Washington Luiz, Conselheiro Josino, Henrique Valadares, Cruz Vermelha, Carlos Sampaio e Rua Tadeu Kosciusko 1000 1999 Bloco: Banda da Amizade - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.18837 -22.91445 Banda da Barra Barra da Tijuca Barra/JPA 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 12:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 rio de janeiro Saindo do Bondinho da Barra até a Praça do Ó 50000 1984 Bloco: Banda da Barra - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 12:00:00 -43.17290 -22.90685 Banda da Praça Afonso Pena Tijuca Tijuca e Adj 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 praca afonso pena rio de janeiro Praça Afonso Pena, Rua Professor Satamini, Rua São Francisco Xavier, Largo da 2ª Feira, Rua Haddock Lobo, Rua Campos Sales e Praca Afonso Pena 1000 1996 Bloco: Banda da Praça Afonso Pena - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.21816 -22.91806 Banda da Praia da Bica Ilha do Governador Zona Norte 3 2018-02-04 Sábado - 1- semanas antes do Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 quiosque piratas praia da bica rio de janeiro Parado 3000 2001 Bloco: Banda da Praia da Bica - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.18961 -22.82171 Banda do Arroxo Copacabana Zona Sul 2018-02-04 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 rua belford roxo com ministro viveiro de castro rio de janeiro Rua Belford Roxo, Rua Felipe de Oliveira, Av. Pricesa Isabel, Ministro Viveiro de Castro e Belford Roxo 1500 1983 Bloco: Banda do Arroxo - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.17630 -22.96395 Bigode Esticado Méier Zona Norte 2 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 rua adriano rio de janeiro Rua Adriano 300, Rua Magalhães Couto, Rua Intendente Cunha Menezes e Rua Adriano. 1000 1999 Bloco: Bigode Esticado - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.28871 -22.89989 Blocão de Copacabana Copacabana Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 09:00:00 1899-12-31 09:00:00 1899-12-31 11:30:00 posto de copacabana sofitel rio de janeiro Av Atlantica do Posto 6 ao posto 5 1000 2004 Bloco: Blocão de Copacabana - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 09:00:00 -43.19187 -22.98717 Bloco da Chaleira do Vidigal Leblon Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 av delfim moreira com jardim de alah rio de janeiro Av. Delfim Moreira com Jardim de Alah até o final da Avenida. (Posto 12) 700 1995 Bloco: Bloco da Chaleira do Vidigal - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.21579 -22.98355 Bloco da Preta Centro Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 av presidente antonio carlos rio de janeiro Segue pela Av. Pres. Antonio Carlos até o Ministerio da Fazenda. 500000 2010 Bloco: Bloco da Preta - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 08:00:00 NA NA Bloco das Cacheadas Tijuca Tijuca e Adj 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 rua barao de mesquita rio de janeiro Rua Barão de Mesquita, Rua General Roca, Rua Desembargador Izidro, e Praça Saens Peña 3000 2008 Bloco: Bloco das Cacheadas - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 10:00:00 NA NA Bloco Favela Méier Zona Norte 2 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 praca agripino grieco rio de janeiro Parado 500 2018 Bloco: Bloco Favela - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.27981 -22.90170 Bloco Tapa na Peteca Bonsucesso Zona Norte 3 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 r joao araujo rio de janeiro Concentração na Rua João Araújo S/N em frente a Associação dos moradores, segue em direção a rua principal, vira a direita na rua Teixeira Ribeiro, segue até o número 650 2000 2008 Bloco: Bloco Tapa na Peteca - Bairro: Bonsucesso - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.24393 -22.85239 Boka de Espuma Botafogo Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua marques de olinda rio de janeiro Rua Marquês de Olinda, Rua Muniz Barreto, Rua São Clemente, Rua Bambina e Rua Marquês de Olinda 30000 1984 Bloco: Boka de Espuma - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.18436 -22.94374 Chora Me Liga Aterro do Flamengo Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 13:00:00 aterro do flamengo altura da praca luis de camoes coreto modernista rio de janeiro Segue pelo Aterro do Flamengo, com dispersão na Av. Infante Dom Henrique 85 aterro do Flamengo 40000 2009 Bloco: Chora Me Liga - Bairro: Aterro do Flamengo - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 08:00:00 NA NA Empolga às 9 Ipanema Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rio de janeiro Parado 2500 2003 Bloco: Empolga às 9 - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 NA NA Escravos da Mauá Saúde Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 barao de tefe entre venezuela e boulevard olimpico rio de janeiro Barão de Tefé (entre Venezuela e Boulevard Olímpico), Venezuela, Sacadura Cabral e Barão de Tefé 27 10000 1993 Bloco: Escravos da Mauá - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.18108 -22.89662 Eu Choro Curto Mas Rio Comprido Rio Comprido Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua aristides lobo rio de janeiro Rua Aristides Lobo seguindo pela mesma até a Rua Maia de Lacerda, fazendo meia volta e retornando até o ponto de origem. 1000 2009 Bloco: Eu Choro Curto Mas Rio Comprido - Bairro: Rio Comprido - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.20868 -22.92058 Fala Bobagem Vila da Penha Zona Norte 1 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca paulo setubal rio de janeiro Desfile no entorno da Praça Paulo Setúbal 900 2011 Bloco: Fala Bobagem - Bairro: Vila da Penha - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.31117 -22.84179 Filhos de Ismael Estácio Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 praca compositor ismael silva rio de janeiro Segue pela Rua Frei Caneca, Rua Visc. De Pirassununga, Rua Salvador de Sá, Rua do Estácio retorno na Rua São Carlos, Rua do Estácio até a origem. 2000 2018 Bloco: Filhos de Ismael - Bairro: Estácio - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 NA NA Fogo e Paixão Centro Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 largo de sao francisco rio de janeiro Parado 10000 2011 Bloco: Fogo e Paixão - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 08:00:00 -43.18111 -22.90520 Foliões da ABRACES Copacabana Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 14:00:00 constante ramos com domingos ferreira rio de janeiro Saindo da esquina da Contante Ramos com Domingos Ferreira, andar até orla e seguir Av. Atlântica até o posto 2 1000 2018 Bloco: Foliões da ABRACES - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 09:00:00 -43.18799 -22.97427 Foliões da Prainha Saúde Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 10:00:00 1899-12-31 16:00:00 largo sao francisco da prainha rio de janeiro Parado 500 2014 Bloco: Foliões da Prainha - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 10:00:00 -43.18428 -22.89770 Fuzuê da Ilha Ilha do Governador Zona Norte 3 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praca do grego rio de janeiro Rua Uça, da Praça do Grego até a Rua Engenheiro Rozauro Zambrano, voltando ao local de concentração 500 2009 Bloco: Fuzuê da Ilha - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.20304 -22.81710 Garganta Seca de Irajá Irajá Zona Norte 1 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 rua manoel de araujo rio de janeiro Rua Manoel de Araújo, Rua Hanibal Porto até a Estrada da Água Grande 700 2001 Bloco: Garganta Seca de Irajá - Bairro: Irajá - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 13:00:00 NA NA Gigantes da Lira (infantil) Laranjeiras Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 14:00:00 praca jardim laranjeiras rua general glicerio rio de janeiro Rua General Glicério, Rua General Cristóvão Barcelos, retornando à Praça Jardim Laranjeiras 6000 1999 Bloco: Gigantes da Lira (infantil) - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 08:00:00 -43.19168 -22.94090 GRBC Deixa Que Eu Te Atravesso Brás de Pina Zona Norte 1 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 rua rio preto rio de janeiro Rua Rio Preto, Rua Brasiléia, Rua Alm. Ingran Margini, Rua Dezoito de Setembro, Rua Valdemar Magrini, até Rua Rio Preto 1000 2016 Bloco: GRBC Deixa Que Eu Te Atravesso - Bairro: Brás de Pina - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.24372 -22.85050 Incha Rola Anil Barra/JPA 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua araticum rio de janeiro Rua Araticum, Estrada de Jacarepaguá e Praça Jornalista Geysa Boscoli 1500 2001 Bloco: Incha Rola - Bairro: Anil - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.32991 -22.96052 Larga a Onça, Alfredo! Laranjeiras Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua ipiranga rio de janeiro Rua Ipiranga, Rua Esteves Junior e Praça São Salvador 2000 2008 Bloco: Larga a Onça, Alfredo! - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.18189 -22.93477 Malandragem do Porto Santo Cristo Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua nabuco de freitas com marques de sapucai rio de janeiro Parado 300 2015 Bloco: Malandragem do Porto - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.19680 -22.91145 Morde e Pica Toda Hora Jacarepaguá Barra/JPA 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 rua jorge faraj rio de janeiro Parado 200 2012 Bloco: Morde e Pica Toda Hora - Bairro: Jacarepaguá - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.39277 -22.97223 Onda Carioca Recreio dos Bandeirantes Barra/JPA 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 16:00:00 praca dr eurico alencastro massot rio de janeiro Parado 700 2018 Bloco: Onda Carioca - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 10:00:00 -43.48243 -23.02311 Pipoca e Guanará Tijuca Tijuca e Adj 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 praca xavier de brito rio de janeiro Parado 500 2013 Bloco: Pipoca e Guanará - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.24349 -22.93197 Pipoca no Mel Gamboa Centro 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 praca coronel assumpcao praca da harmonia rio de janeiro Rua Sacadura Cabral, Rua do Livramento, Rua Rivadavia Correa, Rua Pedro Ernesto e retorna para Praça da Harmonia 1000 2010 Bloco: Pipoca no Mel - Bairro: Gamboa - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 14:00:00 -43.19164 -22.89552 Quem Num Guenta Bebe Água Laranjeiras Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 rua gago coutinho rio de janeiro PARADO 4000 2004 Bloco: Quem Num Guenta Bebe Água - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 12:00:00 -43.18117 -22.93131 Quem Vai Vai, Quem Não Vai Não Cagueta! Ilha do Governador Zona Norte 3 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca jerusalem rio de janeiro Praça Jerusalem, Praia da Bica até Quiosque do Mexicano 1000 2010 Bloco: Quem Vai Vai, Quem Não Vai Não Cagueta! - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 18:00:00 -43.20120 -22.81882 Se não quiser me dar, me empresta Ipanema Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 praia de ipanema posto rio de janeiro Praia de Ipanema, do Posto 8 até o Quiosque da Rua Vinicius de Moraes 3000 2000 Bloco: Se não quiser me dar, me empresta - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 13:00:00 -43.20287 -22.98697 Suvaco do Cristo Jardim Botânico Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 13:00:00 rua jardim botanico rio de janeiro Rua Jardim Botânico, da Rua Faro até a Praça Santos Dumont 35000 1986 Bloco: Suvaco do Cristo - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 08:00:00 -43.21732 -22.96402 Tá Pirando, Pirado, Pirou! Urca Zona Sul 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 av pasteur rio de janeiro Av. Pasteur, do Instituto Benjamim Constant até a Praca General Tibúrcio 3000 2005 Bloco: Tá Pirando, Pirado, Pirou! - Bairro: Urca - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 13:00:00 -43.17341 -22.95237 Tamo Junto in Folia Padre Miguel Zona Oeste 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua marechal marciano rio de janeiro Parado 60000 2005 Bloco: Tamo Junto in Folia - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.44713 -22.86969 Timoneiros da Viola Oswaldo Cruz Zona Norte 1 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 praca paulo da portela rio de janeiro Parado 50000 2012 Bloco: Timoneiros da Viola - Bairro: Oswaldo Cruz - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 13:00:00 -43.34437 -22.86782 Tira a Roupa Neném Quintino Bocaiúva Zona Norte 1 2018-02-04 Domingo – 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua cupertino rio de janeiro Avenida Dom Helder Camara, a partir da Rua da Pedreira a Rua Amália 4000 2013 Bloco: Tira a Roupa Neném - Bairro: Quintino Bocaiúva - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.32125 -22.88557 Toco Crú Pegando Fogo Recreio dos Bandeirantes Barra/JPA 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 posto do recreio rio de janeiro Posto 10 do Recreio ao Posto 9. 10000 2018 Bloco: Toco Crú Pegando Fogo - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 12:00:00 -43.48295 -23.01784 Unidos da Ribeira Ilha do Governador Zona Norte 3 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praca iaia garcia rio de janeiro Praça Iaiá Garcia, Rua Fernandes da Fonseca, Rua Paramopama e Praça Iaiá Garcia 2000 1974 Bloco: Unidos da Ribeira - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 13:00:00 -43.16952 -22.82582 Vai Tomar no Grajaú Grajaú Tijuca e Adj 2018-02-04 Domingo -1 semana antes do Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 av engenheiro richard rio de janeiro Av Engenheiro Richard, Praça Edmundo Rego, Av Engenheiro Richard 800 2009 Bloco: Vai Tomar no Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 15:00:00 -43.26337 -22.92214 Xodó da Piedade Piedade Zona Norte 2 2018-02-04 Domingo - 1 semana antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua mario carpenter rio de janeiro PARADO 1500 1972 Bloco: Xodó da Piedade - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-02-04 - Concentração 16:00:00 -43.29748 -22.88827 Zona Mental Bangu Zona Oeste 2018-02-06 Terça - antes do carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 17:00:00 praca de guilherme da silveira rio de janeiro Rua Guilherme da Silveira, Rua Sidney, Rua Figueiredo Camargo (Ponto Chic), Rua Santana, Marechal Mariano, e Retorna para a praça Guilherme pela Rua Ribeiro Dantas 350 2015 Bloco: Zona Mental - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-06 - Concentração 14:00:00 -43.45652 -22.87456 Banda do Tio Marco Piedade Zona Norte 2 2018-02-07 Quarta-feira antes do Carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 largo da rua porto valter rio de janeiro RUA PORTO VALTER, RUA PADRE NOBREGA, RUA ANTONIO VARGAS, RUA GONÇALO COELHO, RUA SOUZA CERQUEIRA, Av don Helder Camara, Padre Nobrega, Porto valter 3000 1990 Bloco: Banda do Tio Marco - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-02-07 - Concentração 19:00:00 -43.31279 -22.88312 Distribui Sem Juízo Centro Centro 2018-02-07 Quarta-feira - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua da quitanda entre a rua sete de setembro e a rua da assembleia rio de janeiro Parado 1000 2017 Bloco: Distribui Sem Juízo - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-07 - Concentração 18:00:00 -43.17577 -22.90469 Regula Mas Libera Centro Centro 2018-02-07 Quarta-feira - 1 semana antes do Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua teofilo otoni rio de janeiro Parado 500 2014 Bloco: Regula Mas Libera - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-07 - Concentração 18:00:00 NA NA Banda da Rua do Mercado Centro Centro 2018-02-08 Quinta-feira antes do Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua do mercado rio de janeiro Rua do Mercado, Simbolo Olimpico, Rua do Mercado 8000 1999 Bloco: Banda da Rua do Mercado - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-08 - Concentração 18:00:00 -43.17489 -22.90189 Batuke Nuclear Centro Centro 2018-02-08 Quinta-feira antes do Carnaval 1900-01-01 18:00:00 1900-01-01 18:00:00 1900-01-01 22:00:00 rua da candelaria rio de janeiro Parado 500 2007 Bloco: Batuke Nuclear - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-08 - Concentração 18:00:00 -43.17745 -22.90024 Bloco dus Impussivi Centro Centro 2018-02-08 Quinta-feira antes do Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua lelio gama rio de janeiro Rua Lélio Gama, Av. chile, Rua Senador Dantas , Rua Lélio Gama 2000 2003 Bloco: Bloco dus Impussivi - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-08 - Concentração 18:00:00 -43.17854 -22.90952 Chroma Aqui Na Minha Mão Centro Centro 2018-02-08 Quinta-feira – Semana pré carnaval 1900-01-01 18:00:00 1900-01-01 18:00:00 1900-01-01 22:00:00 rua dos arcos entre a fundicao e lavradio rio de janeiro Parado 100 2014 Bloco: Chroma Aqui Na Minha Mão - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-08 - Concentração 18:00:00 NA NA Loucura Suburbana Engenho de Dentro Zona Norte 2 2018-02-08 Quinta-feira antes do Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 instituto municipal nise da silveira rua ramiro magalhaes rio de janeiro Rua Ramiro Magalhães, Rua Gustavo Riedel, Rua Pernambuco, Praça Rio Grande do Norte, Rua Ana Leonídia, Rua Gustavo Riedel e Rua Ramiro Magalhães 1000 2001 Bloco: Loucura Suburbana - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-08 - Concentração 16:00:00 -43.30072 -22.90097 Banda do Jiló Tijuca Tijuca e Adj 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 rua pinto de figueiredo rio de janeiro Rua Pinto de Figueiredo, Avenida Maracanã, Rua Barão de Mesquita, Rua General Roca, Rua Conde de Bonfim e Rua Pinto de Figueiredo 1000 2004 Bloco: Banda do Jiló - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 -43.23611 -22.92492 Banda do Lido Copacabana Zona Sul 2018-02-09 Sexta-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua ronald de carvalho entre a rua viveiros de castro e av nossa senhora de copacabana rio de janeiro Av. Nossa Senhora de Copacabana, Av. Prado Junior, Av. Atlântica, Av. Duvivier até a Rua Rolnald Carvalho 3000 1961 Bloco: Banda do Lido - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 16:00:00 NA NA Bloco da Sorveteria Pedra de Guaratiba Zona Oeste 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão N283 até 464 300 2015 Bloco: Bloco da Sorveteria - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 NA NA Bloco das Piranhas do Jefinho Pedra de Guaratiba Zona Oeste 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão, da Praça São Pedro até a Rua Saião Lobato 700 1985 Bloco: Bloco das Piranhas do Jefinho - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 NA NA Bloco do Rock Ilha do Governador Zona Norte 3 2018-02-09 Sexta-feira de Carnaval 1899-12-31 19:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praca iaia garcia rio de janeiro Parado 1000 2014 Bloco: Bloco do Rock - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 19:00:00 -43.16952 -22.82582 Bloco dos Aposentados Centro Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 buraco do lume rio de janeiro Segue pelaGraça Aranha, Rua Santa Luzia, Rua México e Buraco do Leme 1200 1991 Bloco: Bloco dos Aposentados - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 17:00:00 NA NA Bloco Sinfônico Centro Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 praca mercado municipal rio de janeiro Parado 30000 2018 Bloco: Bloco Sinfônico - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 17:00:00 -43.17359 -22.90309 Boêmios da Lapa Lapa Centro 2018-02-09 Domingo pós Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praca cardeal camara arcos da lapa rio de janeiro Parado 2000 2003 Bloco: Boêmios da Lapa - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 17:00:00 -43.17996 -22.91304 Caldeirão do Coqueiro Santíssimo Zona Oeste 2018-02-09 Sexta-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca do coqueiro rio de janeiro Parado 500 2010 Bloco: Caldeirão do Coqueiro - Bairro: Santíssimo - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 16:00:00 -43.84643 -22.91743 Carmelitas Santa Teresa Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 esquina da ladeira de santa teresa com rua dias de barros rio de janeiro Esquina da ladeira de Santa Teresa com Rua Dias de Barros, segundo até o Largo dos Guimarães 800 1990 Bloco: Carmelitas - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 13:00:00 NA NA Cata Latas do Grajaú Grajaú Tijuca e Adj 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca nobel rio de janeiro Parado 450 2011 Bloco: Cata Latas do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 -43.25953 -22.92681 Eco Bloco do Rio Lapa Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 largo de sao francisco tiradentes rio de janeiro PARADO 3000 2013 Bloco: Eco Bloco do Rio - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 -42.97786 -22.82114 Embaixadores da Folia Centro Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 buraco do lume rio de janeiro Parado 8000 2001 Bloco: Embaixadores da Folia - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 -43.17511 -22.90502 Escorrega Mas Não Cai Saúde Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praca coronel assuncao praca da harmonia rio de janeiro Rua Sacadura Cabral, Rua Aníbal Falcão, Rua Coelho e Castro, Rua Edgard Gordilho e Largo São Francisco da Prainha 1000 2008 Bloco: Escorrega Mas Não Cai - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 16:00:00 -43.19164 -22.89552 Eu Sou Eu, Jacaré é Bicho D’ Água Vila isabel Tijuca e Adj 2018-02-09 Sexta-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 esquina de visc abaete com torres homem rio de janeiro Parado 900 2000 Bloco: Eu Sou Eu, Jacaré é Bicho D’ Água - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 16:00:00 -43.24451 -22.91378 Meia Dúzia de Gatos Pingados Bangu Zona Oeste 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 20:00:00 avenida conego vasconcelos rio de janeiro Calçadão de Bangu, até Largo de Bangu (igreja) 300 2015 Bloco: Meia Dúzia de Gatos Pingados - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 -43.46479 -22.88199 Rio de Janeiro Bangu Zona Oeste 2018-02-09 Sexta-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 praca lucio leite da costa rio de janeiro Praça Lucio Leite da Costa, Rua Walter Cardoso, Rua Oliveira Ribeiro, Rua Silva Cardoso, Rua Santa Cecília e Praça da Fé 1800 2018 Bloco: Rio de Janeiro - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 15:00:00 NA NA Rola Preguiçosa - Tarda mas não falha Ipanema Zona Sul 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 23:00:00 rua maria quiteria rio de janeiro Rua Maria Quitéria, Av. Visconde de Pirajá e Rua Vinícius de Moraes 15000 1993 Bloco: Rola Preguiçosa - Tarda mas não falha - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 NA NA Senta que Eu empurro Catete Zona Sul 2018-02-09 Sexta-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua dois de dezembro rio de janeiro Rua Artur Bernardes em frente ao nº26, Rua Bento Lisboa, Rua Dois de Dezembro e finalizando na esquina da Rua do Catete em frente ao restaurante Paraíso do Chopp 2500 2008 Bloco: Senta que Eu empurro - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 18:00:00 -43.17668 -22.92988 Te Vejo Por Dentro… Sou da Radiologia Lapa Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua joaquim silva rio de janeiro Parado 1000 2015 Bloco: Te Vejo Por Dentro… Sou da Radiologia - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 17:00:00 -43.17904 -22.91521 Unidos do Chapadão Ramos Zona Norte 3 2018-02-09 Sexta-feira de Carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 travessa dos campeoes rio de janeiro Travessa dos Campeões, Avenida dos Campeões até o nº 1,Rua Sargento Gerreira, TV. Horácio, Rua João Romariz, TV. Sargento Gerreira voltando a Travessa dos Campeões 800 2009 Bloco: Unidos do Chapadão - Bairro: Ramos - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 19:00:00 -43.25340 -22.85434 Vestiu uma Camisinha Listrada e Saiu por Aí Centro Centro 2018-02-09 Sexta-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 largo da carioca rio de janeiro Largo da Carioca, 13 de Maio e Cinelandia 2000 1992 Bloco: Vestiu uma Camisinha Listrada e Saiu por Aí - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-09 - Concentração 16:00:00 -41.85609 -22.45156 Aconteceu Santa Teresa Centro 2018-02-10 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1900-01-04 18:00:00 1900-01-04 22:00:00 rua aurea rio de janeiro Largo das Neves, Rua Progresso, Rua Oriente, Rua Aurea 1000 2000 Bloco: Aconteceu - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.18873 -22.92238 Afro Dan Ara Vila isabel Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 20:00:00 boulevard de setembro rio de janeiro Boulevard 28 de Setembro, da Rua Visconde de Abaeté até a Praça Barão de Drummond, voltando pelo Boulevard 28 de Setembro até a Visconde de Abaeté 300 2011 Bloco: Afro Dan Ara - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 -43.24258 -22.91521 Amigos da Esquina Engenho de Dentro Zona Norte 2 2018-02-10 Sábado de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua pernambuco rio de janeiro Rua Pernambuco, Rua Barbacena e Rua Pernambuco 1000 2004 Bloco: Amigos da Esquina - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 18:00:00 -43.29923 -22.89870 Amigos da Esquina de Madureira - Fla Esquina Madureira Zona Norte 1 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 praca de magno rio de janeiro Parado 500 2017 Bloco: Amigos da Esquina de Madureira - Fla Esquina - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.17457 -22.78744 Amigos da Joaquim Méier Méier Zona Norte 2 2018-02-10 Sábado de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua joaquim meier rio de janeiro Rua Joaquim Méier, Rua Guaju, Rua Oliveira, Rua Dias da Cruz até a José Veríssimo, retornando pela Rua Dias da Cruz, Rua Oliveira, Rua Guaju e Rua Joaquim Méier 4000 2000 Bloco: Amigos da Joaquim Méier - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 18:00:00 -43.28086 -22.90609 Amigos do Catete Catete Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua dois de dezembro rio de janeiro Rua do Catete, Rua Pedro Américo, Rua Bento Lisboa, Rua Dois de Dezembro, voltando ao local de concentração 1000 2000 Bloco: Amigos do Catete - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.17668 -22.92988 Amigos do Wilson Alicate Praça da Bandeira Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua sao valetim rio de janeiro Parado 400 2015 Bloco: Amigos do Wilson Alicate - Bairro: Praça da Bandeira - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.21186 -22.91258 Associação Cultural e Bloco Cidade Nova Cidade Nova Centro 2018-02-10 Sábado de Carnaval 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 18:00:00 rua julio do carmo rio de janeiro Parado 250 2018 Bloco: Associação Cultural e Bloco Cidade Nova - Bairro: Cidade Nova - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 11:00:00 -43.20146 -22.91029 Banda da Penha Penha Zona Norte 1 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1900-01-01 20:00:00 1900-01-01 22:00:00 largo da rua couto rio de janeiro Parado 1000 2014 Bloco: Banda da Penha - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.23597 -22.89044 Banda de Bangu Bangu Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 19:00:00 1899-12-31 20:00:00 av conego vasconcelos rio de janeiro Desce a Av. Conego Vasconcelos, entra na Rua Oliveira Ribeiro, desce a Rua Silva Cardoso, entra na Rua Santa Cecília, Sobe a Conego Vasconcelos e encerra no número 1029 200 2008 Bloco: Banda de Bangu - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.46479 -22.88199 Banda de Ipanema Ipanema Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 17:30:00 1899-12-31 21:00:00 rua jangadeiros rio de janeiro Rua Gomes Carneiro, Avenida Vieira Souto, Rua Joana Angélica e Rua Visconde de Pirajá, até a Praça General Osório 90000 1965 Bloco: Banda de Ipanema - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.19684 -22.98468 Banda do Largo da 2ª Feira Tijuca Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua conde de bonfim rio de janeiro PARADO 6000 1990 Bloco: Banda do Largo da 2ª Feira - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 NA NA Banda do Mackenzie Méier Zona Norte 2 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua dias da cruz rio de janeiro Rua Dias da Cruz, do nº 561 até a Rua Magalhães Couto, retornando ao local de concentração 1500 1980 Bloco: Banda do Mackenzie - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.28835 -22.90464 Banda Sá Ferreira Copacabana Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 calcadao da rua sa ferreira com av atlantica rio de janeiro Rua Sá Ferreira, Bulhões de Carvalho, Francisco Otaviano, Av. Atlântica com Sá Ferreira 2000 1940 Bloco: Banda Sá Ferreira - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 NA NA Blocão da Barra Barra da Tijuca Barra/JPA 2018-02-10 Sábado de Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 13:00:00 praca do o rio de janeiro Parado 700 2014 Bloco: Blocão da Barra - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 10:00:00 -43.17359 -22.90309 Bloco Afro Zimbauê da Ilha Ilha do Governador Zona Norte 3 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 18:00:00 praca da freguesia rio de janeiro Segue pela Praia da Guanabara e Pça Nossa Senhora da Ajuda. 300 2017 Bloco: Bloco Afro Zimbauê da Ilha - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.34370 -22.94059 Bloco Boemios do Catruz Pedra de Guaratiba Zona Oeste 2018-02-10 sabado de carnaval 1899-12-31 21:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2010 Bloco: Bloco Boemios do Catruz - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 21:00:00 NA NA Bloco Carnavalesco Infantil Sementes do Samba Vila isabel Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 19:00:00 av de setembro rio de janeiro Segue pela 28 de Setembro até a esquina da Rua Visconde de Abaeté 600 2015 Bloco: Bloco Carnavalesco Infantil Sementes do Samba - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.25428 -22.92102 bloco carnavalesco pombo correio Vila isabel Tijuca e Adj 2018-02-10 sábado de carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua visconde de abaete n rio de janeiro R. visconde de abaete, R. teodoro da silva, R. gonzaga bastos, Av. boulevard 28 de setembro, R. rocha fragoso. 1500 1994 Bloco: bloco carnavalesco pombo correio - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 NA NA Bloco Confetes e Serpentinas Pedra de Guaratiba zona oeste 2018-02-10 sabado de carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2016 Bloco: Bloco Confetes e Serpentinas - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 19:00:00 NA NA Bloco do Barbas Botafogo Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 15:30:00 1899-12-31 19:30:00 rua assis bueno rio de janeiro Rua Arnaldo Quintela, Rua da Passagem e Rua General Góes Monteiro 5000 1985 Bloco: Bloco do Barbas - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.18454 -22.95689 Bloco do Camelo Ilha de Paquetá Centro 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 praia jose bonifacio rio de janeiro Praia José Bonifacio e Furkim Werneck 400 1984 Bloco: Bloco do Camelo - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 NA NA Bloco do Show do Antonio Carlos Glória Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 09:00:00 1899-12-31 12:30:00 1899-12-31 15:00:00 rua do russel rio de janeiro Rua do Russel, Largo da Glória, Av. Augusto Severo (junto as edificções), Rua Mestre Valentim e Av. Luis de Vasconcelos (junto ao Passeio). 3000 2002 Bloco: Bloco do Show do Antonio Carlos - Bairro: Glória - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 09:00:00 -43.17424 -22.92209 Bloco do Tamanco Padre Miguel Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 11:00:00 1899-12-31 13:00:00 1899-12-31 17:00:00 rua d rio de janeiro Rua D, Figueiredo Camargo até o campo do Bangu e volta 3500 2013 Bloco: Bloco do Tamanco - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 11:00:00 -43.44958 -22.87323 Bloco dos Serragens Ilha de Paquetá Centro 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 rua adelaide alambari rio de janeiro Rua Adelaide Alambari, Rua Alambari Luz, Praia da Moreninha, Rua Principe Regente, Praça Bom Jesus. 500 2007 Bloco: Bloco dos Serragens - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.10675 -22.75160 Bloco Guri da Barra Barra da Tijuca Barra/JPA 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 praca do pomar rio de janeiro Parado 300 2018 Bloco: Bloco Guri da Barra - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 NA NA Cachorrão de Bangu Bangu Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua de fevereiro santa cecilia rio de janeiro Rua 12 de Fevereiro, Rua Santa Cecília, Rangel Pestana 200 2006 Bloco: Cachorrão de Bangu - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.18389 -22.95742 Caldeirão do Coqueiro Santíssimo Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca do coqueiro rio de janeiro Parado 500 2010 Bloco: Caldeirão do Coqueiro - Bairro: Santíssimo - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.84643 -22.91743 Cantinho do Urubu Madureira Zona Norte 1 2018-02-10 Sábado de Carnaval 1899-12-31 20:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 estrada do portela rio de janeiro Parado 1000 2013 Bloco: Cantinho do Urubu - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 20:00:00 NA NA Carioca da Gema Lapa Centro 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 21:00:00 rua dos arcos rio de janeiro Rua dos Arcos, 24 - em frente à Fundição Progresso (Parado em palco montado em frente a Fundição) 1000 2006 Bloco: Carioca da Gema - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.18127 -22.91218 Carrossel de Emoções Barra da Tijuca Barra/JPA 2018-02-10 Sábado de Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 arena blocos rio de janeiro Parado 100000 2016 Bloco: Carrossel de Emoções - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 08:00:00 -42.00857 -22.88121 Céu na Terra Santa Teresa Centro 2018-02-10 Sábado de Carnaval 1899-12-31 07:00:00 1899-12-31 08:00:00 1899-12-31 11:00:00 largo dos guimaraes rio de janeiro Rua Alm. Alexandrino, Largo do Curvelo 7000 2001 Bloco: Céu na Terra - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 07:00:00 -43.18603 -22.92155 Chora 10 Tijuca Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua sao miguel rio de janeiro Rua São Miguel, Rua Santa Carolina, Avenida Maracanã, Rua São Rafael e Rua São Miguel 1000 2011 Bloco: Chora 10 - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.25154 -22.93948 Ciganas Feiticeiras de Olaria Olaria Zona Norte 3 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua paranhos rio de janeiro Rua João Rego, Rua Delfim Carlos, Rua Paranhos até origem. 1000 1995 Bloco: Ciganas Feiticeiras de Olaria - Bairro: Olaria - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 -43.27050 -22.85436 Confraria do Peru Sadio Leme Zona Sul 2018-02-10 Segunda-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 avenida atlantica rio de janeiro Avenida Atlântica, seguindo até a esquina da Princesa Isabel e retornando pela Av. Atlantica até o Posto 01 1500 2004 Bloco: Confraria do Peru Sadio - Bairro: Leme - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.18147 -22.96953 Coração das Crianças Rocinha Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua nova antiga rua rio de janeiro Rua 4 até Cidade Nova 600 1978 Bloco: Coração das Crianças - Bairro: Rocinha - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 18:00:00 -42.81217 -22.70245 Cordão Alegria da Tijuca Tijuca Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua afonso pena entre haddock lobo e doutor satamini rio de janeiro Rua Afonso Pena, Rua Haddock Lobo, Rua Campos Sales, Doutor Satamini, Largo da Segunda-feira, Rua Haddock Lobo e Rua Afonso Pena 15000 2001 Bloco: Cordão Alegria da Tijuca - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 18:00:00 NA NA Cordão da Bola Preta Centro Centro 2018-02-10 Sábado de Carnaval 1899-12-31 07:00:00 1899-12-31 09:00:00 1899-12-31 14:00:00 av presidente antonio carlos rio de janeiro Segue pela Av. Pres. Antonio Carlos até o Ministerio da Fazenda. 1500000 1919 Bloco: Cordão da Bola Preta - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 07:00:00 -43.17297 -22.90778 Cordão do Prata Preta Gamboa Centro 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca coronel assumpcao praca da harmonia rio de janeiro Praça da Harmonia, Sacadura Cabral e Largo São Francisco da Prainha 800 2005 Bloco: Cordão do Prata Preta - Bairro: Gamboa - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.19164 -22.89552 Deita Mas Não Dorme Taquara Barra/JPA 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua caituba rio de janeiro Parado 500 2009 Bloco: Deita Mas Não Dorme - Bairro: Taquara - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 NA NA Diversão Brasileira Tijuca Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 praca xavier de brito rio de janeiro Parado 1200 2011 Bloco: Diversão Brasileira - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.24349 -22.93197 D’Jorge Senador Camará Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua marco sete rio de janeiro Parado 600 2018 Bloco: D’Jorge - Bairro: Senador Camará - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 18:00:00 NA NA Dois Pra Lá, Dois Pra Cá Botafogo Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 rua alvaro ramos rio de janeiro Álvaro Ramos, R. General Goes Monteiro, Av. Lauro Sodré, Túnel Novo (lado esquerdo), Av. Princesa isabel e Av. Atlântica 1000 1991 Bloco: Dois Pra Lá, Dois Pra Cá - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 08:00:00 -43.18285 -22.95693 Empolga às 9 Copacabana Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 avenida atlantica rio de janeiro Avenida Atlântica, da Av. Rainha Elizabeth até a Rua Constate Ramos 2500 2003 Bloco: Empolga às 9 - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 09:00:00 -43.18147 -22.96953 Escangalha! Jardim Botânico Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 rua jardim botanico rio de janeiro Rua Jardim Botânico, da Rua Pacheco Leão até a Praça Santos Dumont 7000 2007 Bloco: Escangalha! - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 08:00:00 -43.21732 -22.96402 Estica do Flamengo Flamengo Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca sandro moreira rio de janeiro Parado 1700 2008 Bloco: Estica do Flamengo - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.17805 -22.93682 Fiquei Firme Saúde Centro 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca americo brum rio de janeiro Praça Américo Brum, Ladeira do Barroso, Ladeira do Livramento, Rua Sacadura Cabral e Largo São Francisco da Prainha 500 2010 Bloco: Fiquei Firme - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 -43.17643 -22.91097 Fogo na Cueca Copacabana Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 rua anita garibaldi rio de janeiro Rua Anita Garibaldi, Rua Maestro Francisco Braga, passa em frente ao Bar Pontinho, Rua Décio Vilares, Pça Vereador Rocha Leão, Rua Henrique Oswald, termina Rua Santa Clara, 431 1100 1998 Bloco: Fogo na Cueca - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.18858 -22.96845 Fome Zero Madureira Zona Norte 1 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 rua domingos fernandes rio de janeiro Rua Domingos Fernandes, Rua Leopoldina de Oliveira, Rua Nunes de Souza e Rua Domingos Fernandes 1000 2009 Bloco: Fome Zero - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.33975 -22.86587 Galo da Santa Clara Copacabana Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua henrique oswald rio de janeiro Parado 1500 2011 Bloco: Galo da Santa Clara - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 -43.19235 -22.96420 Harmonia de Copacabana Copacabana Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 avenida atlantica esquina da siqueira campos rio de janeiro Avenida Atlantica da Siqueira Campos até a Rua República do Perú e retornando a Concentração. 4000 2001 Bloco: Harmonia de Copacabana - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.18619 -22.96693 Maravilhas do Porto Saúde Centro 2018-02-10 Sábado de Carnaval 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 16:00:00 largo sao francisco da prainha rio de janeiro Parado 400 2012 Bloco: Maravilhas do Porto - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 11:00:00 -43.18428 -22.89770 MultiBloco Lapa Centro 2018-02-10 Sábado de Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 rua do senado rio de janeiro Gomes Freire Rua do Resende 1250 2009 Bloco: MultiBloco - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 08:00:00 -43.18708 -22.90996 Na Hora Que Se Vê Ilha do Governador Zona Norte 3 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 praia da rosa rio de janeiro Praia da Rosa, Avenida do Magistério, Rua Aristarco Ramos, Estrada do Dendê e Praia da Rosa, voltando ao local de concentração 400 2015 Bloco: Na Hora Que Se Vê - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 -43.18907 -22.79209 Na Pressão Eu Vou Campo Grande Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 avenida cesario de melo rio de janeiro Rua Coronel Agostinho, Rua Viúva Dantas, seguindo até a esquina da José Ferreira 1000 2000 Bloco: Na Pressão Eu Vou - Bairro: Campo Grande - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 12:00:00 -43.60256 -22.91426 New Kids On The Bloco São Conrado Zona Sul 2018-02-10 Domingo de Carnaval 1899-12-31 08:00:00 1899-12-31 08:00:00 1899-12-31 14:00:00 sao conrado rio de janeiro Parado 5000 2014 Bloco: New Kids On The Bloco - Bairro: São Conrado - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 08:00:00 -43.26941 -22.99865 Nós 4 Na Pista Ilha do Governador Zona Norte 3 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praia da engenhoca final rio de janeiro PARADO 500 2015 Bloco: Nós 4 Na Pista - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.17094 -22.82154 O Remédio é o Samba Copacabana Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 avenida atlantica com xavier silveira rio de janeiro Concentra na esquina da Av. Atlântica com a Xavier da Silveira e segue em direção ao posto 6, retornando ao local da concentração 1000 2001 Bloco: O Remédio é o Samba - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 -43.19323 -22.97617 Olha Pá Mim Tijuca Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca afonso pena rio de janeiro Parado 500 2016 Bloco: Olha Pá Mim - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 -43.21816 -22.91806 Oswaldo Cruz Maravilha Oswaldo Cruz Zona Norte 1 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 estrada do portela imperio serrano rio de janeiro Estrada do Portela Império Serrano até a praça Paulo da Portela 3000 1993 Bloco: Oswaldo Cruz Maravilha - Bairro: Oswaldo Cruz - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.33672 -22.87397 Pinta Mas Não Borra Botafogo Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 16:30:00 1899-12-31 17:30:00 1899-12-31 20:30:00 rua voluntarios da patria rio de janeiro Rua Voluntários da Pátria, nº 34, Rua São Clemente, nº 1, Rua Nelson Mandela e Rua Voluntários da Pátria até o nº 34 7000 2007 Bloco: Pinta Mas Não Borra - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:30:00 -43.18980 -22.95332 Rebarbas Botafogo Zona Sul 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 praca mauro duarte rio de janeiro Parado 2500 2002 Bloco: Rebarbas - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 NA NA Rir Pra Não Chorar Recreio dos Bandeirantes Barra/JPA 2018-02-10 Sábado de Carnaval 1899-12-31 10:00:00 1899-12-31 10:00:00 1899-12-31 12:00:00 posto rio de janeiro Av. Lúcio Costa do Posto 10 ao 9 700 2018 Bloco: Rir Pra Não Chorar - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 10:00:00 -43.18991 -22.95568 Semente do Amanhã São Cristóvão Centro 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 rua sao luiz gonzaga rio de janeiro Rua São Luiz Gonzaga 966, Largo da Cancela e Dispersão na Av. Rotary Internacional na Entrada da Quinta da Boa Vista 500 2012 Bloco: Semente do Amanhã - Bairro: São Cristóvão - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.23028 -22.90019 Seu Kuka é Eu do Grajaú Grajaú Tijuca e Adj 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 largo maria martha ward rio de janeiro Rua Teodoro da Silva, Rua José Vicente, Rua Meira Vasconcelos, Rua Faria de Brito, Rua Barão de Mesquita e Largo Irma Maria Marta Ward 1200 2008 Bloco: Seu Kuka é Eu do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.25977 -22.92039 Sou Cheio de Amor Recreio dos Bandeirantes Barra/JPA 2018-02-10 Sábado de Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 21:00:00 av lucio costa barramares rio de janeiro Avenida Lucio Costa 3300 até a Praça do Ó 600 2014 Bloco: Sou Cheio de Amor - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 15:00:00 -43.32828 -23.01094 Terreirada Cearense São Cristóvão Centro 2018-02-10 Sábado de Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 quinta da boa vista rio de janeiro Quinta da Boa Vista - Parado 2500 2012 Bloco: Terreirada Cearense - Bairro: São Cristóvão - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 13:00:00 -43.22402 -22.90509 Tigres do Coqueiro Pedra de Guaratiba Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão Nº283 até o Nº427 300 2007 Bloco: Tigres do Coqueiro - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 17:00:00 NA NA Turma do Gato Futebol e Samba Pilares Zona Norte 2 2018-02-10 Sábado de Carnaval 1899-12-31 12:00:00 1899-12-31 17:00:00 1899-12-31 18:00:00 rua djalma dutra rio de janeiro Rua Djalma Dutra, Av. Dom Hélder Câmara e Av. João Ribeiro 2000 2001 Bloco: Turma do Gato Futebol e Samba - Bairro: Pilares - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 12:00:00 -43.29505 -22.88363 Unidos da Travessa Miracema Méier Zona Norte 2 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 19:00:00 1899-12-31 20:00:00 travessa miracema rio de janeiro Travessa Miracema, Rua Dias da Cruz até a Magalhães Couto, retornando pela Dias da Cruz até a Travessa Miracema 1200 2018 Bloco: Unidos da Travessa Miracema - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 NA NA Vamos que Vamos Campo Grande Zona Oeste 2018-02-10 Sábado de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua santo amando rio de janeiro Rua Santo Amando, Rua Damião de Goes, Rua São Potito, Rua Henri Dunant e retorno a origem 600 2017 Bloco: Vamos que Vamos - Bairro: Campo Grande - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 16:00:00 -43.54996 -22.90484 Vem Comigo Vila Cosmos Zona Norte 1 2018-02-10 Sábado de Carnaval 1899-12-31 14:00:00 1899-12-31 17:30:00 1899-12-31 19:00:00 rua itacambira c av meriti rio de janeiro Rua Alecrim, Rua Itacambira com Rua Imbiaça. 1200 2000 Bloco: Vem Comigo - Bairro: Vila Cosmos - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 14:00:00 NA NA Verde e Branco do Zumbi Ilha do Governador Zona Norte 3 2018-02-10 Sábado de Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 16:00:00 rua peixoto de carvalho rio de janeiro Rua Peixoto de Carvalho, Praia do Zumbi, Rua Pojuca, Estrada do Rio Jequiá, Rua Gaspar de Souza e Rua Peixoto de Carvalho 600 2001 Bloco: Verde e Branco do Zumbi - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 10:00:00 -43.17574 -22.82129 Virilha de Minhoca Bangu Zona oeste 2018-02-10 Sábado de Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua fonseca rio de janeiro Rua fonseca, rua oliveira ribeiro, Av. Cônego de Vasconcelos, Rua Santa Cecilia, Rua Fonseca 6000 2002 Bloco: Virilha de Minhoca - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-10 - Concentração 18:00:00 -43.46555 -22.88198 10+ Malandros Bangu Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 12:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 rua bela flor rio de janeiro Rua Bela Flor, Rua Figueiredo Camargo com deslocamento até a Rua Cherburgo (Ponto Chic) 2000 2012 Bloco: 10+ Malandros - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 12:00:00 -43.46061 -22.86983 A Nega Indoidou Centro Centro 2018-02-11 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua alvaro alvim rio de janeiro Parado 1000 2012 Bloco: A Nega Indoidou - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.17630 -22.91111 Afoxé Filhos de Gandhi Gamboa Centro 2018-02-11 Domingo de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca da harmonia rio de janeiro Rua Sacadura Cabral, Rua Camerino e Praça dos Estivadores 500 1952 Bloco: Afoxé Filhos de Gandhi - Bairro: Gamboa - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 17:00:00 -43.19164 -22.89552 Ai, Que Vergonha! São Conrado Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 avenida prefeito mendes de moraes rio de janeiro Avenida Prefeito Mendes de Moraes, Avenida Aquarela do Brasil e Rua Berta Lutz 80 900 2007 Bloco: Ai, Que Vergonha! - Bairro: São Conrado - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.26461 -22.99947 Alegria de Palmares Jardim Palmares Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 18:00:00 bar do jaco rio de janeiro Início: Rua Soldado Elias de Souza, Rua Felisbino dos Santos, Rua Soldado Julio de Vasconcelos, Caio Basílio Junior e volta para a Rua Elias de Souza 500 2010 Bloco: Alegria de Palmares - Bairro: Jardim Palmares - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.64019 -22.88752 Alegria de Quintino Quintino Bocaiúva Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 rua olina rio de janeiro Rua Olina, Rua Barros Leite, Elias da Silva, Nerval de Gouveia e finaliza na Praça de Quintino 300 2005 Bloco: Alegria de Quintino - Bairro: Quintino Bocaiúva - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -43.31653 -22.89148 Amigos da Esquina de Madureira - Fla Esquina Madureira Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1900-01-01 19:00:00 1899-12-31 21:00:00 praca de magno rio de janeiro Parado 500 2017 Bloco: Amigos da Esquina de Madureira - Fla Esquina - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.17457 -22.78744 Areia Leblon Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 posto rio de janeiro Sai do posto 12 até o posto 11 10000 2003 Bloco: Areia - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 08:00:00 -43.18991 -22.95568 Badalo de Santa Teresa Santa Teresa Centro 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 17:30:00 1899-12-31 22:00:00 rua monte alegre rio de janeiro Segue pela Rua do Oriente, Rua Progresso até dispersar no Largo das Neves 1000 1972 Bloco: Badalo de Santa Teresa - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.18810 -22.91964 Bafo do Peru Padre Miguel Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua tapiranga largo rio de janeiro Rua Tapiranga, Rua Icote, Rua Ceriba, Rua Pedro Melo, Rua Maria Rosa, Largo da Tapiranga 800 2008 Bloco: Bafo do Peru - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 17:00:00 NA NA Balanço do Pinto Tijuca Tijuca e Adj 2018-02-11 Domingo de Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua pinto de figueiredo rio de janeiro Rua Pinto de Figueiredo, Avenida Maracanã, Rua Barão de Mesquita, Rua General Roca, Rua Conde de Bonfim e Rua Pinto de Figueiredo 1000 2009 Bloco: Balanço do Pinto - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 17:00:00 -43.23611 -22.92492 Bambas do Catete Catete Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 praca do poeta rio de janeiro Praça do Poeta - Parado 1000 2002 Bloco: Bambas do Catete - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.19243 -22.98542 Banda da Amizade Lapa Centro 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua tadeu kosciusco rio de janeiro Rua Tadeu Kosciusko, Carlos Sampaio, Washington Luiz, Conselheiro Josino, Henrique Valadares, Cruz Vermelha, Carlos Sampaio e Rua Tadeu Kosciusko 1000 1999 Bloco: Banda da Amizade - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.18837 -22.91445 Banda da Conceição Saúde Centro 2018-02-11 Domingo de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca major valo rio de janeiro Praça major Valo, Ladeira João Homem, Rua Sacadura Cabral, Rua São Francisco da Prainha, Pedra do Sal, Jogo da Bola, Preça Major Valo 500 1971 Bloco: Banda da Conceição - Bairro: Saúde - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 17:00:00 -43.18296 -22.89871 Banda da Glória Glória Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua da gloria rio de janeiro Parado 500 1974 Bloco: Banda da Glória - Bairro: Glória - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.17705 -22.91921 Banda da Inválidos Lapa Centro 2018-02-11 Domingo de Carnaval 1899-12-31 16:30:00 1899-12-31 18:30:00 1899-12-31 22:00:00 rua dos invalidos entre av mem de sa e henrique valadares rio de janeiro Rua dos Inválidos, Rua do Senado, Rua Ubaldino do Amaral, Av.Henrique Valadares, Rua dos Inválidos; 1000 1976 Bloco: Banda da Inválidos - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:30:00 NA NA Banda da Penha Penha Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1900-01-02 20:00:00 1900-01-02 22:00:00 largo da rua couto rio de janeiro Parado 1000 2014 Bloco: Banda da Penha - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.23597 -22.89044 Banda do Bairro de Fátima Bairro de Fátima Centro 2018-02-11 Domingo de Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 praca presidente aguirre cerda rio de janeiro Praça Presidente Aguirre Cerda, Av. Nossa Senhora de Fatima, Rua Tadeu Kosciusko, Rua do Resende, Rua Ubaldino do Amaral, Washington, Rua Tadeu Kosciusko, Av. Nossa Senhora de Fátima. 900 1977 Bloco: Banda do Bairro de Fátima - Bairro: Bairro de Fátima - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 10:00:00 -43.18816 -22.91783 Banda do Lidinho Copacabana Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 praca do lido rio de janeiro Praça do Lido - Parado 1000 1969 Bloco: Banda do Lidinho - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.17602 -22.96549 Banda do Recreio Recreio dos Bandeirantes Barra/JPA 2018-02-11 Domingo de Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 posto rio de janeiro Posto 10 do Recreio ao Posto 9. 3000 2005 Bloco: Banda do Recreio - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 13:00:00 -43.18991 -22.95568 Banda Du Rio Copacabana Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 posto de copacabana rio de janeiro Segue pela Av. Atlântica até altura da Rua Miguel Lemos 5000 2017 Bloco: Banda Du Rio - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 08:00:00 -43.18618 -22.97355 Bangalafumenga Aterro do Flamengo Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 proximo ao monumento dos pracinhas rio de janeiro Parado 60000 1998 Bloco: Bangalafumenga - Bairro: Aterro do Flamengo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 08:00:00 -43.17344 -22.91662 Batalha dos Blocos Recreio dos Bandeirantes Barra/JPA 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praia do recreio posto rio de janeiro Parado 4000 2017 Bloco: Batalha dos Blocos - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.47132 -23.03247 Birita mas num cai Madureira Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 bar do julio fragoso rio de janeiro Início: Julio Fragoso, Clara Nunes, Estrada do Portela – Retorno: Praça Paulo Portela, Estrada do Portela, Clara Nunes, Julio Fragoso. 600 2017 Bloco: Birita mas num cai - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.34316 -22.87160 Bloco Boemios do Catruz Pedra de Guaratiba Zona Oeste 2018-02-11 Domingo de carnaval 1899-12-31 21:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2010 Bloco: Bloco Boemios do Catruz - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 21:00:00 NA NA Bloco Chega Mais Piedade Zona Norte 2 2018-02-11 Domingo de Carnaval 1899-12-31 15:30:00 1899-12-31 16:00:00 1899-12-31 21:00:00 rua padre manoel da nobrega rio de janeiro Início: Padre Manoel de Nobrega Nº114, Av Dom Helder Câmara por 600 metros, retorna no sentido Cascadura 3500 2004 Bloco: Bloco Chega Mais - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:30:00 -43.31359 -22.88016 Bloco Confetes e Serpentinas Pedra de Guaratiba zona oeste 2018-02-11 Domingo de Carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2016 Bloco: Bloco Confetes e Serpentinas - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 19:00:00 NA NA Bloco da Chaleira do Vidigal Leblon Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 av delfim moreira esquina com jardim de alah rio de janeiro Av. Delfim Moreira com Jardim de Alah até o final da Avenida. (Posto 12) 700 1995 Bloco: Bloco da Chaleira do Vidigal - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 NA NA Bloco da Coroinha Pedra de Guaratiba Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão n°216 ao n°579 200 2007 Bloco: Bloco da Coroinha - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 17:00:00 NA NA Bloco do Boi “Só Falta Você!” Pedra de Guaratiba Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 18:00:00 1899-12-31 18:50:00 1899-12-31 22:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão até o final da rua 200 2010 Bloco: Bloco do Boi “Só Falta Você!” - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 18:00:00 NA NA Bloco do Pente Ilha do Governador Zona Norte 3 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca dos bancarios rio de janeiro Praça dos Bancários, Av. das Enxadas, Praia dos Bancários 1500 2014 Bloco: Bloco do Pente - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.18112 -22.79034 Bloco dos Palhacinhos Brás de Pina Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 19:30:00 1899-12-31 22:00:00 estrada do quitungo rio de janeiro Estrada do Quitungo, do nº 1221 ate no 1970 e retorna a origem. 800 2015 Bloco: Bloco dos Palhacinhos - Bairro: Brás de Pina - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.30222 -22.83173 Bloco Quilombo Cafundá Astrogilda Vargem Grande Barra/JPA 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 concentracao na comunidade quilombo astrogilda rio de janeiro Concentração na comunidade Quilombo Astrogilda, núcleo Cafunda Dramice, Bar Cantinho da Serra, Bar do na Boa e finalizando pela estrada do Macuiba até o largo de Vargem Grande 200 2017 Bloco: Bloco Quilombo Cafundá Astrogilda - Bairro: Vargem Grande - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 NA NA Bloco Só Te Pegando Barra da Tijuca Barra/JPA 2018-02-11 domingo de carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 av lucio costa posto rio de janeiro Parado 500 2010 Bloco: Bloco Só Te Pegando - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 NA NA Boi de Anchieta Anchieta Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca nossa senho de nazare rio de janeiro Praça Nazaré, Rua Motorista Luiz de Abreu, Avenida Nazaré, Rua Motoriasta Luiz de Abreu, Praça Nazaré 2000 1945 Bloco: Boi de Anchieta - Bairro: Anchieta - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 NA NA Bonecas Deslumbradas de Olaria Olaria Zona Norte 3 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua conselheiro paulino rio de janeiro Rua Conselheiro Paulino, Rua Antônio Rêgo, Rua Lígia, Rua Wandelkok e Rua Conselheiro Paulino 4000 1977 Bloco: Bonecas Deslumbradas de Olaria - Bairro: Olaria - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.26833 -22.85271 Buda da Barra Barra da Tijuca Barra/JPA 2018-02-11 Domingo de Carnaval 1899-12-31 09:00:00 1899-12-31 13:00:00 1899-12-31 15:00:00 rio de janeiro Saindo do Bondinho da Barra até a Praça do Ó 1000 1970 Bloco: Buda da Barra - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 09:00:00 -43.17290 -22.90685 Cabrito Mamador Ilha do Governador Zona Norte 3 2018-02-11 Domingo de Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 rua sao sebastiao rio de janeiro Estrada do Dendê, Rua Prof. Hilarião da Rocha, Rua Capanema, Av. Paranapuan, Estrada do Dendê e Rua São Sebastião 1500 2017 Bloco: Cabrito Mamador - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 10:00:00 -43.24495 -22.85002 Cachorro Cansado Flamengo Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca jose de alencar rio de janeiro Praça José de Alencar, Rua Marquês de Abrantes, Rua Marquês de Paraná, Rua Senador Vergueiro, Rua Barão do Flamengo e Praça José de Alencar 10000 1987 Bloco: Cachorro Cansado - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.17721 -22.93319 Caldeirão do Coqueiro Santíssimo Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca do coqueiro rio de janeiro Parado 500 2010 Bloco: Caldeirão do Coqueiro - Bairro: Santíssimo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 NA NA Cantinho do Urubu Madureira Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 20:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 estrada do portela rio de janeiro Parado 1000 2013 Bloco: Cantinho do Urubu - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 20:00:00 -43.34309 -22.86879 Choppinho da Paula Freitas com Boca Maldita Copacabana Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua paula freitas rio de janeiro Av. Atlântica com Paula Freitas, até a Rodolfo Dantas e retorna ao local de origem. 2000 1994 Bloco: Choppinho da Paula Freitas com Boca Maldita - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 NA NA Coração das Crianças Rocinha Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua nova antiga rua rio de janeiro Rua 4 até Cidade Nova 600 1978 Bloco: Coração das Crianças - Bairro: Rocinha - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 18:00:00 -42.81217 -22.70245 Cordão do Boitatá Centro Centro 2018-02-11 Domingo de Carnaval 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 17:00:00 praca xv rio de janeiro Parado 50000 1997 Bloco: Cordão do Boitatá - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 11:00:00 -43.17359 -22.90309 Deita Mas Não Dorme Taquara Barra/JPA 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua caituba rio de janeiro Parado 500 2009 Bloco: Deita Mas Não Dorme - Bairro: Taquara - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -43.37610 -22.91704 É do Pandeiro! Laranjeiras Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 praca sao salvador rio de janeiro Parado 300 2002 Bloco: É do Pandeiro! - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 NA NA Explosão de Paquetá Ilha de Paquetá Centro 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 19:30:00 praca sao roque rio de janeiro Rua Padre Juvenal, Rua Dr. Aristão, Curva da Pedra, Rua José Bonifácio, Rua Furkin Werneck, Praça das Barcas. 600 2018 Bloco: Explosão de Paquetá - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 NA NA Fanfarani Botafogo Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 praca chaim weizman rio de janeiro Praça Chaim Weizman - Parado 850 2009 Bloco: Fanfarani - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.18205 -22.94116 Fanfinha Botafogo Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 13:00:00 praca chaim weizman rio de janeiro Praça Chaim Weizman - Parado 600 2011 Bloco: Fanfinha - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 09:00:00 -43.18205 -22.94116 Folia do Galo Copacabana Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 13:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 rua julio de castilho esquina com rua raul pompeia rio de janeiro R. julio de castilho, raul pompeia, Rua francisco otaviano, av. atlantica esquina c/ julio de castilho 4000 2009 Bloco: Folia do Galo - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 13:00:00 -43.19176 -22.98447 Fome Zero Madureira Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 rua dagmar da fonseca rio de janeiro Rua Dagmar da Fonseca, Av. Edgard Ramero, Est. Do Portela, e retorna a origem. 1000 2009 Bloco: Fome Zero - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -43.33910 -22.87401 Gladiadores de Copacabana Copacabana Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 avenida atlantica rio de janeiro Avenida Atlântica, da Rua Constante Ramos até a Rua Hilário de Gouveia 2000 2007 Bloco: Gladiadores de Copacabana - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 NA NA Império da Folia Catete Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua bento lisboa rio de janeiro Rua Bento Lisboa, Rua Dois de Dezembro, Rua do Catete, Rua Pedro Américo e Rua Bento Lisboa até a esquina da Tavares Bastos 800 2003 Bloco: Império da Folia - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.17935 -22.92785 Laranjada Samba Clube Laranjeiras Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 praca jardim laranjeiras rua general glicerio rio de janeiro Rua General Glicério, Rua General Cristóvão Barcelos, retornando à Praça Jardim Laranjeiras 900 2003 Bloco: Laranjada Samba Clube - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 09:00:00 NA NA Marcha Nerd Tijuca Tijuca e Adj 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 praca xavier de brito rio de janeiro Parado 900 2013 Bloco: Marcha Nerd - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -43.24349 -22.93197 Maresia Botafogo Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 14:00:00 enseada de botafogo rio de janeiro PARADO 200 2016 Bloco: Maresia - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 11:00:00 NA NA Mau Mau de Bangu Bangu Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua acanto rio de janeiro Rua Acanto, Rua Ajuará, Rua Minuanos, Rua Imaruí, Rua da Fábrica, Rua dos Açudes, Rua Oliveira Ribeiro, Rua Bangu, Rua Santa Cecília e Praça da Fé 500 1997 Bloco: Mau Mau de Bangu - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 17:00:00 NA NA Mocidade de Santíssimo Santíssimo Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 19:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 rua augusto brandao rio de janeiro Concentração Augusto Brandão e dando início ao desfile na rua Teixeira Campos e terminando na Rua Alves Dias 1000 2016 Bloco: Mocidade de Santíssimo - Bairro: Santíssimo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 19:00:00 -43.51062 -22.87706 Perereca do Grajaú Grajaú Tijuca e Adj 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:30:00 praca edmundo rego rio de janeiro Avenida Engenheiro Richard, atravessa a Barão do Bom Retiro, Rua Teodoro da Silva, Rua José Vicente, Rua Meira de Vasconcelos, Rua Farias de Brito e Largo do Verdun 1000 1977 Bloco: Perereca do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.26409 -22.92249 Piranhas da Senador Nabuco Vila isabel Tijuca e Adj 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca barao de drummond rio de janeiro Boulevard 28 de Setembro, da Praça Barão de Drummond até esquina com Rua Visconde de Abaeté, retornando pelo Boulevard 28 de Setembro, Rua Luis Barbosa, Rua Torres Homem e Praça Noel Rosa 1000 1980 Bloco: Piranhas da Senador Nabuco - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.25058 -22.91714 Porre Certo Praça Seca Barra/JPA 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 rua carima rio de janeiro Rua Parintins, Rua Florianópolis, Rua Urucuia, Rua Luiz Beltrão, Rua Parintins e Rua Carimã 500 2003 Bloco: Porre Certo - Bairro: Praça Seca - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -43.35824 -22.89536 Que Merda é Essa?! Ipanema Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 10:00:00 1899-12-31 14:30:00 1899-12-31 16:00:00 rua garcia d avila rio de janeiro Rua Garcia D’avila, Avenida Vieira Souto, seguindo até O Jardim de Alah 2000 1995 Bloco: Que Merda é Essa?! - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 10:00:00 -43.20919 -22.98344 Queima de Bangu Bangu Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua agricola rio de janeiro Rua Santa Cecília, seguindo até a Rua Fonseca (Dispersão) 500 1957 Bloco: Queima de Bangu - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.45873 -22.88032 Quem Me Viu Mentiu Ilha do Governador Zona Norte 3 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca jerusalem rio de janeiro Segue pela Praia da Bica Av. Alm. Alves Câmara Junior até o numero 986 2000 2017 Bloco: Quem Me Viu Mentiu - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 NA NA Quer Swingar Vem Pra Cá Vila isabel Tijuca e Adj 2018-02-11 Domingo de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 14:00:00 praca barao de drumond rio de janeiro Parado 1000 2018 Bloco: Quer Swingar Vem Pra Cá - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 09:00:00 -43.25058 -22.91714 Raízes da Vila da Penha Vila da Penha Zona Norte 1 2018-02-11 Domingo de Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 rua sao joao gualberto rio de janeiro Rua São João Gualberto, Rua General Silveira Sobrinho, Rua Oliveira Belo, Rua Alice Tibiriça e Rua São João Gualberto 900 2007 Bloco: Raízes da Vila da Penha - Bairro: Vila da Penha - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 13:00:00 -43.30874 -22.84203 Simpatia é Quase Amor Ipanema Zona Sul 2018-02-11 NA 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 teixeira de melo praia rio de janeiro Rua Teixeira de Melo e Avenida Vieira Souto até a Henrique Dumont 300000 1985 Bloco: Simpatia é Quase Amor - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -43.19866 -22.98531 Só Cachaça Santo Cristo Centro 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua nabuco de freitas rio de janeiro Rua Nabuco de Freitas (ida e volta) 500 2013 Bloco: Só Cachaça - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 -43.20040 -22.90451 Thriller Elétrico Vila isabel Tijuca e Adj 2018-02-11 Domingo de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 13:00:00 praca barao de drummond rio de janeiro Parado 3000 2013 Bloco: Thriller Elétrico - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 08:00:00 -43.25058 -22.91714 Toca Rauuul! Centro Centro 2018-02-11 Domingo de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca tiradentes rio de janeiro PARADO 1000 2012 Bloco: Toca Rauuul! - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 -41.50799 -17.86413 Toco-Xona Flamengo Zona Sul 2018-02-11 Domingo de Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 praia do flamengo campo de terra rio de janeiro Parado 2000 2008 Bloco: Toco-Xona - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 10:00:00 NA NA Toma Uma Ilha de Paquetá Centro 2018-02-11 Domingo de Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praia da moreninha rio de janeiro Praia da Moreninha, Rua Doutor Lacerda, Praia José Bonifácio, Praça Furquim Werneck e Praça Pintor Pedro Bruno 400 2005 Bloco: Toma Uma - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 18:00:00 -43.11269 -22.75423 Vai Tomar no Azul Engenho de Dentro Zona Norte 2 2018-02-11 Domingo de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 21:00:00 rua pernambuco rio de janeiro Parado 500 2009 Bloco: Vai Tomar no Azul - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 15:00:00 -43.29923 -22.89870 Vem Comigo Vila Cosmos Zona Norte 1 2018-02-11 Segunda-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 17:30:00 1899-12-31 19:00:00 rua itacambira c av meriti rio de janeiro Rua Alecrim, Rua Itacambira com Rua Imbiaça. 1200 2000 Bloco: Vem Comigo - Bairro: Vila Cosmos - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 14:00:00 NA NA Vem Que Eu Te Abraço Padre Miguel Zona Oeste 2018-02-11 Domingo de Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 17:00:00 rua da caridade rio de janeiro Saindo da Rua da Caridade, Rua Figueiredo e voltando para a Rua da Caridade 800 2015 Bloco: Vem Que Eu Te Abraço - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 12:00:00 -43.45009 -22.87328 Vermelho e Branco da Colônia Z-10 Ilha do Governador Zona Norte 3 2018-02-11 Domingo de Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 15:00:00 praca sao pedro rio de janeiro Praça São Pedro, Praia do Jequiá, Rua Maldonado, Praça Iaiá Garcia, Rua Fernandes da Fonseca Rua Paramopama, Praia do Zumbi, Rua Pojuca, e Dispersão na Rua Rio Jequiá. 5000 2003 Bloco: Vermelho e Branco da Colônia Z-10 - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 09:00:00 NA NA Virilha de Minhoca Bangu Zona oeste 2018-02-11 Domingode Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua fonseca rio de janeiro Rua fonseca, rua oliveira ribeiro, Av. Cônego de Vasconcelos, Rua Santa Cecilia, Rua Fonseca 6000 2002 Bloco: Virilha de Minhoca - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 18:00:00 NA NA Xodó da Piedade Piedade Zona Norte 2 2018-02-11 Domingo de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua mario carpenter rio de janeiro Rua Mario Carpenter, Rua Leopoldina, Rua João Pinheiro, Av. Dom Helder Camara, Rua Ferreira Sampaio, Rua Ernesto Nunes, Angelina e finaliza na Rua Mario Carpenter 1500 1972 Bloco: Xodó da Piedade - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-02-11 - Concentração 16:00:00 NA NA Acabou o Amor Ilha do Governador Zona Norte 3 2018-02-12 Segunda-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua domingos mundin rio de janeiro Rua Domingos Mundin e Rua Euzebio de Farias 26 500 2015 Bloco: Acabou o Amor - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 18:00:00 -43.18624 -22.79505 Aconteceu Santa Teresa Centro 2018-02-12 Sábado - 1 semana antes do Carnaval 1899-12-31 16:00:00 1900-01-04 18:00:00 1900-01-04 22:00:00 rua aurea rio de janeiro Largo dos Guimarães, Rua Paschoal , Rua Carlos Magno, Rua Monte Alegre, Rua Aurea 1000 2000 Bloco: Aconteceu - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.18873 -22.92238 Afoxé Filhos de Gandhi Copacabana Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 posto de copacabana rio de janeiro Av. Atlântica do Posto 6 ao Posto 4 2000 1952 Bloco: Afoxé Filhos de Gandhi - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.18618 -22.97355 Afoxé Raizes Africanas Copacabana Zona Sul 2018-02-12 Segunda de Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 posto de copacabana rio de janeiro Concentração Colonia dos pescadores, Xavier da Silveira 150 2007 Bloco: Afoxé Raizes Africanas - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 -43.18618 -22.97355 Afroreggae Centro Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 15:00:00 presidente antonio carlos rio de janeiro Av. Presidente Antonio Carlos até a Rua Araujo Porto Alegre 80000 2006 Bloco: Afroreggae - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 09:00:00 -43.17297 -22.90778 Alegria do São Bento Padre Miguel Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua sidney rio de janeiro Esquina da Rua Sidney Nº40, Rua Figueiredo camargo e retorna para a Rua Sidney Nº40 800 2014 Bloco: Alegria do São Bento - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 17:00:00 NA NA Amigos da Esquina de Madureira - Fla Esquina Madureira Zona Norte 1 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1900-01-02 19:00:00 1899-12-31 21:00:00 praca de magno rio de janeiro Parado 500 2017 Bloco: Amigos da Esquina de Madureira - Fla Esquina - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.17457 -22.78744 Arteiros da Glória Glória Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua da gloria rio de janeiro Rua da Glória, Rua do Catete, Rua Antonio Mendes Campos, Largo da Glória, Av. Augusto Severo e Rua da Glória 2000 2007 Bloco: Arteiros da Glória - Bairro: Glória - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.17705 -22.91921 Associação Carnavalesca Infiéis Centro Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 largo alexandre herculano rio de janeiro Parado 1000 2008 Bloco: Associação Carnavalesca Infiéis - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 NA NA Balança Meu Catete Catete Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua do catete rio de janeiro Rua do Catete, Rua Pedro Américo, Rua Bento Lisboa, Rua Dois de Dezembro e Rua do Catete, até a esquina com a Buarque de Macedo, retornando ao local de concentração 4000 2011 Bloco: Balança Meu Catete - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 -43.17663 -22.92707 Balanço do Jamelão Andaraí Tijuca e Adj 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua botucatu rio de janeiro Rua Botucatu, Rua Rosa e Silva, Rua Caçapava, Rua Uberaba, Rua Botucatu, Rua Barão de Mesquita 600 2007 Bloco: Balanço do Jamelão - Bairro: Andaraí - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.25684 -22.92662 Bambas do Curuzu São Cristóvão Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua curuzu rio de janeiro Rua Curuzu, Rua Alves Monte, Rua Coronel Cabrita, Praça Argentina, Rua Coronel Brandão e Rua Tuiuti - Curuzu 1500 2007 Bloco: Bambas do Curuzu - Bairro: São Cristóvão - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.23042 -22.89628 Banda Clube Nobre do Bairro Peixoto Copacabana Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 av atlantica rio de janeiro Parado 700 1997 Bloco: Banda Clube Nobre do Bairro Peixoto - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 11:00:00 -43.18147 -22.96953 Banda da Amizade Lapa Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua tadeu kosciusco rio de janeiro Parado 1000 1999 Bloco: Banda da Amizade - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 -43.18837 -22.91445 Banda da Constança Barbosa - Galo do Méier Méier Zona Norte 2 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua constanca barbosa rio de janeiro Rua Constança Barbosa, Rua Manuela Barbosa, Rua Dias da Cruz, Rua Magalhães Couto e Rua Manuela Barbosa 1000 2014 Bloco: Banda da Constança Barbosa - Galo do Méier - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 -43.28062 -22.90113 Banda da Inválidos Lapa Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:30:00 1899-12-31 18:30:00 1899-12-31 22:00:00 rua dos invalidos entre av mem de sa e henrique valadares rio de janeiro Rua dos Inválidos, Rua do Senado, Rua Ubaldino do Amaral, Av.Henrique Valadares, Rua dos Inválidos; 1000 1976 Bloco: Banda da Inválidos - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:30:00 NA NA Banda da Penha Penha Zona Norte 1 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1900-01-03 20:00:00 1900-01-03 22:00:00 largo da rua couto rio de janeiro Parado 1000 2014 Bloco: Banda da Penha - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.23597 -22.89044 Banda de Ipanema Infantil Ipanema Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 14:30:00 1899-12-31 16:00:00 1899-12-31 19:30:00 praca general osorio rio de janeiro Praça General Osório - Parado 10000 1965 Bloco: Banda de Ipanema Infantil - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:30:00 -43.19782 -22.98518 Banda do Riviera Barra da Tijuca Barra/JPA 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 rua rosalinda brant condominio riviera rio de janeiro Rua Rosalinda Brant, Rua Celso Kelly, Rua Afrânio Costa, Rua Professor Dulcídio Cardoso e Rua Rosalinda Brant 2500 2007 Bloco: Banda do Riviera - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 -43.33886 -23.00407 Banda Inimigos da Bebida Ilha do Governador Zona Norte 3 2018-02-12 Segunda-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 praca comandante mege rio de janeiro Saindo da Praça Comandante Magé, Rua Altinópolis, Beira da Praia da Bandeira, seguindo em direção ao Detran, dobrando no Fórum da Ilha do Governador e encerrando na Praça Comandante Megé 900 2012 Bloco: Banda Inimigos da Bebida - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 10:00:00 -43.17928 -22.80726 Batalha dos Blocos Recreio dos Bandeirantes Barra/JPA 2018-02-12 Segunda-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 praia do recreio posto rio de janeiro Parado 4000 2017 Bloco: Batalha dos Blocos - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 10:00:00 -43.47132 -23.03247 Batucada Abençoada Copacabana Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 12:00:00 concentracao rio de janeiro Posto 6 ao posto 5 3000 2018 Bloco: Batucada Abençoada - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 08:00:00 -43.26088 -22.88215 Bloco Afro Afoxé Ile Ala Copacabana Zona Sul 2018-02-12 Segunda de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 posto de copacabana rio de janeiro Av. Atlântica do Posto 6 ao Posto 4 500 2015 Bloco: Bloco Afro Afoxé Ile Ala - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 -43.18969 -22.98324 Bloco Boemios do Catruz Pedra de Guaratiba Zona Oeste 2018-02-12 Segunda-feira de carnaval 1899-12-31 21:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2010 Bloco: Bloco Boemios do Catruz - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 21:00:00 NA NA Bloco Chega Mais Piedade Zona Norte 2 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:30:00 1899-12-31 16:00:00 1899-12-31 21:00:00 rua padre manoel da nobrega rio de janeiro Início: Padre Manoel de Nobrega Nº114, Av Dom Helder Câmara por 600 metros, retorna no sentido Cascadura 3500 2004 Bloco: Bloco Chega Mais - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:30:00 -43.31359 -22.88016 Bloco Confetes e Serpentinas Pedra de Guaratiba zona oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2016 Bloco: Bloco Confetes e Serpentinas - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 19:00:00 NA NA Bloco da Colônia Z-3 Ilha de Paquetá Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 praia jose bonifacio rio de janeiro Praia José Bonifácio, Rua Furquim Werneck e Praça Pintor Pedro Bruno 2000 2012 Bloco: Bloco da Colônia Z-3 - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 17:00:00 -43.11011 -22.76268 Bloco de Segunda Humaitá Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua marques atras da cobal do humaita rio de janeiro Rua Marques, Voluntários da Pátria, Rua Martins Ferreira, Rua São Clemente e Rua Marques 5000 1987 Bloco: Bloco de Segunda - Bairro: Humaitá - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.19685 -22.95503 Bloco do Boi “Só Falta Você!” Pedra de Guaratiba Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1900-01-01 18:00:00 1900-01-01 18:50:00 1900-01-01 22:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão até o final da rua 200 2010 Bloco: Bloco do Boi “Só Falta Você!” - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 18:00:00 NA NA Bloco Estratégia Centro Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 largo de sao francisco de paula rio de janeiro Parado 5000 2012 Bloco: Bloco Estratégia - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.18111 -22.90520 Bloco Virtual Leme Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 08:30:00 1899-12-31 09:00:00 1899-12-31 13:30:00 praca almirante julio de noronha rio de janeiro Seque pela Av. Atlantica até a praça Julio de Noronha 5000 2001 Bloco: Bloco Virtual - Bairro: Leme - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 08:30:00 -43.16543 -22.96175 Boca Maldita Copacabana Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua paula freitas esquina com av atlantica rio de janeiro Av. Atlântica com Paula Freitas, até a Rodolfo Dantas e retorna ao local de origem. 3000 1981 Bloco: Boca Maldita - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 NA NA Boêmios de Sepetiba Sepetiba Zona Oeste 2018-02-12 Terça-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praia de sepetiba bar do zezinho rio de janeiro Praia de Sepetiba, Estrada São Tarcísio, Rua Paranabi, Rua Aristides Gouveia e Rua José Higaskino 500 2008 Bloco: Boêmios de Sepetiba - Bairro: Sepetiba - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 18:00:00 -43.69547 -22.98437 Boi de Anchieta Anchieta Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca nossa senho de nazare rio de janeiro Praça Nazaré, Rua Motorista Luiz de Abreu, Avenida Nazaré, Rua Motoriasta Luiz de Abreu, Praça Nazaré 2000 1945 Bloco: Boi de Anchieta - Bairro: Anchieta - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.39860 -22.82179 Caldeirão do Coqueiro Santíssimo Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca do coqueiro rio de janeiro Parado 500 2010 Bloco: Caldeirão do Coqueiro - Bairro: Santíssimo - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.84643 -22.91743 Cantinho do Urubu Madureira Zona Norte 1 2018-02-12 Segunda-feira de Carnaval 1899-12-31 20:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 estrada do portela rio de janeiro Parado 1000 2013 Bloco: Cantinho do Urubu - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 20:00:00 -43.34309 -22.86879 Carvalho em Pé Botafogo Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 rua visconde de caravelas rio de janeiro PARADO 700 2011 Bloco: Carvalho em Pé - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 10:00:00 -43.19508 -22.95684 Chouriço Alegre Oswaldo Cruz Zona Norte 1 2018-02-12 Segunda-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 18:00:00 beco henedina rio de janeiro Beco do henedina, rua Henrique de Melo, beco manoel aires , Beco do henedina. 200 2017 Bloco: Chouriço Alegre - Bairro: Oswaldo Cruz - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 -43.35347 -22.86838 Ciganas Feiticeiras de Olaria Olaria Zona Norte 3 2018-02-12 Segunda-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua paranhos rio de janeiro Rua João Rego, Rua Delfim Carlos, Rua Paranhos até origem. 1000 1995 Bloco: Ciganas Feiticeiras de Olaria - Bairro: Olaria - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 17:00:00 -43.27050 -22.85436 Coração das Crianças Rocinha Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua nova antiga rua rio de janeiro Rua 4 até Cidade Nova 600 1978 Bloco: Coração das Crianças - Bairro: Rocinha - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 18:00:00 NA NA Cordão do Boitatá Centro Centro 2018-02-12 Segunda de Carnaval 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 17:00:00 praca xv rio de janeiro Parado 50000 1997 Bloco: Cordão do Boitatá - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 11:00:00 -43.17359 -22.90309 Deita Mas Não Dorme Taquara Barra/JPA 2018-02-12 Segunda-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua caituba rio de janeiro Parado 500 2009 Bloco: Deita Mas Não Dorme - Bairro: Taquara - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 -43.37610 -22.91704 Dinossauros Nacionais Centro Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 12:00:00 1899-12-31 13:00:00 1899-12-31 16:00:00 largo de sao francisco de paula rio de janeiro Largo de São Francisco - Parado 5000 2013 Bloco: Dinossauros Nacionais - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 12:00:00 -43.18111 -22.90520 Divas do Recreio Recreio dos Bandeirantes Barra/JPA 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 16:30:00 1899-12-31 21:00:00 avenida lucio costa quiosque terapia rio de janeiro Avenida Lucio Costa, Segue até o Posto 9 e retorna a origem 3000 2014 Bloco: Divas do Recreio - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 -43.45617 -23.02508 Engata no Centro Lapa Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 rua ubaldino do amaral entre rua carlos de carvalho e rua do senado rio de janeiro Parado 500 2016 Bloco: Engata no Centro - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 NA NA Estica do Flamengo Flamengo Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca sandro moreira rio de janeiro Praça Sandro Moreira, Rua Marquês de Abrantes, Rua Marquês do Paraná, Rua Senador Vergueiro, Retrona na Praça José de Alencar com a Rua Marquês de Abrantes e finaliza na Praça Sandro Moreira 1700 2008 Bloco: Estica do Flamengo - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 NA NA Fúria de Bangu Bangu Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua boiobi rio de janeiro Rua Francisco Barreto, Rio Biobi, Silva Rua Banguense, Rangel Pestana, Silva Cardoso, Santa Cecília, encerrando na praça da Fé. 500 2011 Bloco: Fúria de Bangu - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 15:00:00 -43.47347 -22.88561 Lagarto Mama de Campo Grande Campo Grande Zona Oeste 2018-02-12 Segunda de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 17:00:00 av glicinia com estrada do cabucu rio de janeiro Av. Glicinia até entrada do Lameirão 2800 2011 Bloco: Lagarto Mama de Campo Grande - Bairro: Campo Grande - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 -43.54223 -22.91400 Largo do Machadinho, Mas Não Largo do Suquinho Catete Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 09:00:00 1899-12-31 09:00:00 1899-12-31 14:00:00 largo do machado rio de janeiro Largo do Machado - Parado 2000 2011 Bloco: Largo do Machadinho, Mas Não Largo do Suquinho - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 09:00:00 -43.17891 -22.93054 Leão da Pedra Santo Cristo Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua rego barros rio de janeiro Rua Rego Barro e retorna pela Rua Nabuco de Freitas até a origem 300 2012 Bloco: Leão da Pedra - Bairro: Santo Cristo - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 NA NA Mocidade Unida de Magalhães Bastos Magalhães Bastos Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 20:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 estrada general canrobert da costa rio de janeiro Estrada General Canrobert da Costa sentido Vila Militar até Bonina e retorna a origem 1500 2010 Bloco: Mocidade Unida de Magalhães Bastos - Bairro: Magalhães Bastos - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 20:00:00 -43.42047 -22.87563 Não deixe o Rock morrer Botafogo Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 rua alvaro ramos rio de janeiro Inicio na Rua Alvaro Ramos, Assis Bueno, Arnaldo Quintela, Rua da Passagem, Rua Alvaro Ramos. 1500 2018 Bloco: Não deixe o Rock morrer - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 NA NA Nova Geração do Zumbi Ilha do Governador Zona Norte 3 2018-02-12 Segunda-feira de Carnaval 1899-12-31 11:00:00 1899-12-31 13:00:00 1899-12-31 17:00:00 rua serrao rio de janeiro Rua Peixoto de Carvalho, Estrada do Rio Jequiá, Rua Maldonado, Rua Fernandes da Fonseca, Rua Paramopama, Est. Do Jequiá, Peixoto de Carvalho 10000 2008 Bloco: Nova Geração do Zumbi - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 11:00:00 NA NA Os 300 Padre Miguel Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:30:00 1899-12-31 17:00:00 1899-12-31 22:00:00 largo da tapiranga rio de janeiro Largo da Tapiranga, Rua Maria Rosa, Rua Japeju, Rua Tapiranga e Largo da Tapiranga 1000 2014 Bloco: Os 300 - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:30:00 -43.44612 -22.88209 Papo de Cachaça Méier Zona Norte 2 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua dias da cruz rio de janeiro Rua Dias da Cruz, do nº 269 ao nº 111, retornando ao local de concentração 600 2010 Bloco: Papo de Cachaça - Bairro: Méier - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 NA NA Pede Passagem Jardim Botânico Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 rua jardim botanico rio de janeiro Rua Jardim Botânico, da Rua Pacheco Leão até a Praça Santos Dumont 1000 2005 Bloco: Pede Passagem - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 10:00:00 -43.21732 -22.96402 Pega Rex Social Clube Ipanema Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 praca nossa senhora da paz rio de janeiro PARADO 600 2008 Bloco: Pega Rex Social Clube - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 NA NA Picada de Primeira Lapa Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua dos arcos rio de janeiro Parado 3000 2009 Bloco: Picada de Primeira - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 -43.18127 -22.91218 Polvo da Ilha Ilha do Governador Zona Norte 3 2018-02-12 Segunda-feira de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 praca iaia garcia rio de janeiro Praça Iaiá Garcia, Rua Maldonado, Estrada do Rio Jequiá, Rua Serrão, Rua Peixoto de Carvalho, Praia do Zumbi, Rua Paramopama e Praça Iaiá Garcia 500 2005 Bloco: Polvo da Ilha - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 09:00:00 -43.16952 -22.82582 Quem Num Guenta Bebe Água Ilha de Paquetá Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 12:30:00 1899-12-31 15:00:00 1899-12-31 18:30:00 praia dos tamoios rio de janeiro Rua Praia do Tamoios, Rua Furkin Werneck, Rua Pinheiro Freire, Rua Principe Regente, Rua Doutor Aristão e Praia das Moreninhas. 500 2018 Bloco: Quem Num Guenta Bebe Água - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 12:30:00 -43.10836 -22.75875 Raízes da Vila da Penha Vila da Penha Zona Norte 1 2018-02-12 Segunda-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 rua sao joao gualberto rio de janeiro Rua São João Gualberto, Rua General Silveira Sobrinho, Rua Oliveira Belo, Rua Alice Tibiriça e Rua São João Gualberto 900 2007 Bloco: Raízes da Vila da Penha - Bairro: Vila da Penha - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 13:00:00 -43.30874 -22.84203 Raízes do Varandão Vila isabel Tijuca e Adj 2018-02-12 Segunda-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 blv de setembro pista da direita rio de janeiro Segue pelo Boulevard em frente a quadra da U. de vila isabel, contorna a praça barao de Drumond, entra na rua Barão de Cotegipe, Rua Mendes Tavares 73. bar varandão 500 2015 Bloco: Raízes do Varandão - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 16:00:00 NA NA Sargento Pimenta Aterro do Flamengo Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 aterro do flamengo entre o mam e a marina da gloria rio de janeiro Parado 60000 2011 Bloco: Sargento Pimenta - Bairro: Aterro do Flamengo - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 08:00:00 NA NA Seca Copo Ilha do Governador Zona Norte 3 2018-02-12 Segunda-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 rua monjolos rio de janeiro Rua Monjolos, Praia da Pitangueiras, Rua Formosa, Est. Rio Jequiá, Rua Monjolos e volta a concentração 900 2010 Bloco: Seca Copo - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 13:00:00 -43.17991 -22.81683 Sem Noção Lapa Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 17:00:00 rua dos arcos rio de janeiro Rua dos Arcos, Rua do Lavradio, Rua do Senado, Rua dos Inválidos, Rua da Relação até Av. Gomes Freire 2000 2010 Bloco: Sem Noção - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 12:00:00 -43.18127 -22.91218 Sou Cheio de Amor Copacabana Zona Sul 2018-02-12 Segunda de Carnaval 1899-12-31 11:00:00 1899-12-31 13:00:00 1899-12-31 16:00:00 av atlantica rio de janeiro Parado 1000 2013 Bloco: Sou Cheio de Amor - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 11:00:00 NA NA Tigres do Coqueiro Pedra de Guaratiba Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão Nº283 até o Nº427 300 2007 Bloco: Tigres do Coqueiro - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 17:00:00 NA NA Turbilhão Carioca Lagoa Zona Sul 2018-02-12 Segunda-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 parque dos patins rio de janeiro Parado 1000 2009 Bloco: Turbilhão Carioca - Bairro: Lagoa - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 10:00:00 -43.21645 -22.97227 Turma do Copo Ilha de Paquetá Centro 2018-02-12 Segunda-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praia jose bonifacio rio de janeiro Praia José Bonifacio e Rua Furkim Werneck 400 1992 Bloco: Turma do Copo - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 17:00:00 -43.11011 -22.76268 Vem Comigo Vila Cosmos Zona Norte 1 2018-02-12 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 17:30:00 1899-12-31 19:00:00 rua itacambira c av meriti rio de janeiro Rua Alecrim, Rua Itacambira com Rua Imbiaça. 1200 2000 Bloco: Vem Comigo - Bairro: Vila Cosmos - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 14:00:00 NA NA Vermelho e Preto Coirmãos Padre Miguel Zona Oeste 2018-02-12 Segunda-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:30:00 1899-12-31 22:00:00 rua helianto rio de janeiro Rua Helianto, Rua Olimpia Esteves, Rua Vila Nova e retorna para Helianto. 500 2015 Bloco: Vermelho e Preto Coirmãos - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 17:00:00 NA NA Virilha de Minhoca Bangu Zona oeste 2018-02-12 Segunda de Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua fonseca rio de janeiro Rua fonseca, rua oliveira ribeiro, Av. Cônego de Vasconcelos, Rua Santa Cecilia, Rua Fonseca 6000 2002 Bloco: Virilha de Minhoca - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-12 - Concentração 18:00:00 -43.46555 -22.88198 A Rocha da Gávea Gávea Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 08:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 praca santos dumont rio de janeiro Praça Santos Dumont, Rua Marquês de São Vicente, Rua Vice-Governador Rubens Berardo e Terminal da PUC 900 2003 Bloco: A Rocha da Gávea - Bairro: Gávea - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 08:00:00 -43.22605 -22.97321 Acadêmicos do Engenho de Dentro Engenho de Dentro Zona Norte 2 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua venancio ribeiro rio de janeiro Rua Venâncio Ribeiro, Rua Maria Paula, Rua Catulo CearenSe e Rua Adolfo Bergamini 1000 2011 Bloco: Acadêmicos do Engenho de Dentro - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.29969 -22.90754 Alegria do Guarabu Ilha do Governador Zona Norte 3 2018-02-13 Terça-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 rua luis gomes pedreira rio de janeiro Rua Luis Gomes, Rua Inhoverá, Rua Dr. leon Roussoulieres, Rua Tramandaí, Rua Estocolmo, Rua Genebra, Rua Catalpa, Rua Flamarion, Rua Berna e Rua Luis Gomes 1000 2012 Bloco: Alegria do Guarabu - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 13:00:00 -42.21456 -22.82914 Amigos da Esquina de Madureira - Fla Esquina Madureira Zona Norte 1 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1900-01-03 19:00:00 1899-12-31 21:00:00 praca de magno rio de janeiro Parado 500 2017 Bloco: Amigos da Esquina de Madureira - Fla Esquina - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.17457 -22.78744 Amigos da Onça Ilha do Governador Zona Norte 3 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 praca manoel bandeira rio de janeiro Praça Manoel Bandeira, Avenida Paranapuan e Marques de Muritiba, até o nº 685 900 2012 Bloco: Amigos da Onça - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.18046 -22.80473 Amigos da Sueca da Pedro Américo Catete Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 21:30:00 rua pedro americo rio de janeiro Rua Pedro Américo, Rua Bento Lisboa, Rua Dois de Dezembro, Rua do Catete e Rua Pedro Américo 950 2010 Bloco: Amigos da Sueca da Pedro Américo - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.18153 -22.92421 Amigos do Zé Cosmos Zona Oeste 2018-02-13 Terça de Carnaval 1899-12-31 19:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 rua beira rio rio de janeiro Rua Beira Rio, Rua Independência, Rua Itagiba, Rua Curaré, Rua Cosmos, Rua Guarujá. 500 2013 Bloco: Amigos do Zé - Bairro: Cosmos - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 19:00:00 -43.24872 -22.88033 Bafo do Peru Padre Miguel Zona Oeste 2018-02-13 Terça - antes do carnaval 1900-01-01 17:00:00 1900-01-01 18:00:00 1900-01-01 22:00:00 rua tapiranga largo rio de janeiro Rua Tapiranga, Rua Icote, Rua Ceriba, Rua Pedro Melo, Rua Maria Rosa, Largo da Tapiranga 800 2008 Bloco: Bafo do Peru - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 NA NA Bagunça Meu Coreto Laranjeiras Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 praca sao salvador rio de janeiro Praça São Salvador, Rua São Salvador, Rua Ipiranga, Rua Paissandu, Rua Senador Correa e Praca São Salvador 900 2005 Bloco: Bagunça Meu Coreto - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 09:00:00 -43.18082 -22.93400 Baile do Negrão Madureira Zona Norte 1 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:30:00 1899-12-31 21:00:00 viaduto negrao de lima rio de janeiro Saindo da Rua Carvalho de Souza 241 indo até o palanque Rua dos Peixinhos Rua Edgard Romero 81 5000 2007 Bloco: Baile do Negrão - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.33519 -22.87648 Bambas do Catete Catete Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 praca do poeta rio de janeiro Rua do Catete, Rua Pedro Américo, Rua Bento Lisboa, Rua Dois de Dezembro e Rua do Catete até a Silveira Martins 1000 2002 Bloco: Bambas do Catete - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.19243 -22.98542 Bambas do Curuzu São Cristóvão Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua curuzu rio de janeiro Parado 1500 2007 Bloco: Bambas do Curuzu - Bairro: São Cristóvão - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.23042 -22.89628 Banana Com Queijo Realengo Zona Oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 21:00:00 rua tecobe rio de janeiro Rua Tecobé, Rua ibitú, Rua João Luso, Rua Ocabí, Rua Silva Neto, Rua Iguarim, Rua Acú, Rua Mirim, Rua Tecobé 275 Término 1000 2013 Bloco: Banana Com Queijo - Bairro: Realengo - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.43870 -22.89656 Banda da Amizade Lapa Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 rua tadeu kosciusco rio de janeiro Rua Tadeu Kosciusko, Rua do Rezende, Rua Ubaldino de Amaral, Rua Washington Luiz, Rua Conselheiro Josino, Av. Henrique Valadares, Praça da Cruz Vermelha, Rua Carlos Sampaio e Rua Tadeu Kosciusko 1000 1999 Bloco: Banda da Amizade - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.18837 -22.91445 Banda da Glória Glória Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua da gloria rio de janeiro Rua da Glória 180, Rua Américo, Rua do catete, Rua da Glória 1000 1974 Bloco: Banda da Glória - Bairro: Glória - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.17705 -22.91921 Banda da Inválidos Lapa Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:30:00 1899-12-31 18:30:00 1899-12-31 22:00:00 rua dos invalidos entre av mem de sa e henrique valadares rio de janeiro Rua dos Inválidos, Rua do Senado, Rua Ubaldino do Amaral, Av.Henrique Valadares, Rua dos Inválidos; 1000 1976 Bloco: Banda da Inválidos - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:30:00 NA NA Banda da Nega Recreio dos Bandeirantes Barra/JPA 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 av lucio costa rio de janeiro Parado 1000 2014 Bloco: Banda da Nega - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.39362 -23.01303 Banda da Penha Penha Zona Norte 2 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1900-01-04 20:00:00 1900-01-04 22:00:00 largo da rua couto rio de janeiro Parado 1000 2014 Bloco: Banda da Penha - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.23597 -22.89044 Banda da Saens Pena Tijuca Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua desembargador izidro rio de janeiro Rua Desembargador Izidro, Rua Abelardo Barbosa, Rua Conde de Bonfim, Rua Pareto, Rua Almirante Cochrane, Rua Santo Afonso e Rua General Roca 1000 2005 Bloco: Banda da Saens Pena - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.23371 -22.92831 Banda das Quengas Lapa Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 no meio da rua washington luiz rio de janeiro Parado 15000 1990 Bloco: Banda das Quengas - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 NA NA Banda de Ipanema Ipanema Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:30:00 1899-12-31 21:00:00 rua jangadeiros rio de janeiro Rua Gomes Carneiro, Avenida Vieira Souto, Rua Joana Angélica e Rua Visconde de Pirajá, até a Praça General Osório 90000 1965 Bloco: Banda de Ipanema - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.19684 -22.98468 Banda do Andaraí Andaraí Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua maxwell rio de janeiro Segue na Rua Maxwell até o Largo do Verdun. 500 2017 Bloco: Banda do Andaraí - Bairro: Andaraí - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.24381 -22.92019 Banda do Largo da 2ª Feira Tijuca Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 rua conde de bonfim rio de janeiro Rua Conde de Bonfim, Rua Haddock Lobo, Rua Campos Salles, Rua Doutor Satamini, Rua São Francisco Xavier e Rua Conde de Bonfim até o nº 25 6000 1990 Bloco: Banda do Largo da 2ª Feira - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.24015 -22.93210 Banda do Peru Pelado Copacabana Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 avenida atlantica rio de janeiro Rua República do Peru, Rua Barata Ribeiro, Rua Siqueira Campos e Avenida Atlântica até a esquina com República do Peru 1500 2009 Bloco: Banda do Peru Pelado - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.18147 -22.96953 Banda Haddock Tijuca Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua afonso pena rio de janeiro PARADO 2200 1984 Bloco: Banda Haddock - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.21880 -22.91777 Banguçando o Coreto Bangu Zona Oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua abaete rio de janeiro Rua Abaeté, Rua Santa Cecília, seguindo até Rua Fonseca. 1000 2010 Bloco: Banguçando o Coreto - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 NA NA Batalha dos Blocos Recreio dos Bandeirantes Barra/JPA 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praia do recreio posto rio de janeiro Parado 4000 2017 Bloco: Batalha dos Blocos - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.47132 -23.03247 Batuke de Batom Ilha do Governador Zona Norte 3 2018-02-13 Terça-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 praca iaia garcia rio de janeiro Rua Fernandes da Fonseca, Rua Paramopama, retorno a origem. 2000 2013 Bloco: Batuke de Batom - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 10:00:00 NA NA Bicho Solto com Desculpa pra Beber Humaitá Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 estacionamento da cobal do humaita rio de janeiro Voluntários da Pátria, Rua Conde de Irajá, Largo dos Leões e Rua Marques 3000 2003 Bloco: Bicho Solto com Desculpa pra Beber - Bairro: Humaitá - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.19509 -22.95540 Birita mas num cai Madureira Zona Norte 1 2018-02-13 Terça de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 bar do julio fragoso rio de janeiro Início: Julio Fragoso, Clara Nunes, Estrada do Portela – Retorno: Praça Paulo Portela, Estrada do Portela, Clara Nunes, Julio Fragoso. 600 2017 Bloco: Birita mas num cai - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.34316 -22.87160 Blockn Roll \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; Ilha do Governador \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; Zona Norte 3 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; 2018-02-13 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; Terça-feira de Carnaval \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; 1899-12-31 17:00:00 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; 1899-12-31 18:00:00 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; 1899-12-31 22:00:00 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; praca iaia garcia rio de janeiro \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; Praça Iaiá Garcia - Parado \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:right;\"\u0026gt; 800 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:right;\"\u0026gt; 2009 \u0026lt;/td\u0026gt; \u0026lt;td style=\"text-align:left;\"\u0026gt; Bloco: Blockn Roll - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.16952 -22.82582 Bloco Boemios do Catruz Pedra de Guaratiba Zona Oeste 2018-02-13 terça-feia de carnaval 1899-12-31 21:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2010 Bloco: Bloco Boemios do Catruz - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 21:00:00 NA NA Bloco Confetes e Serpentinas Pedra de Guaratiba zona oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2016 Bloco: Bloco Confetes e Serpentinas - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 19:00:00 NA NA Bloco da Coroinha Pedra de Guaratiba Zona Oeste 2018-02-13 Terça de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão n°216 ao n°579 200 2007 Bloco: Bloco da Coroinha - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 NA NA Bloco da Gold / Giro do Arar Centro Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 15:00:00 av pres antonio carlos rio de janeiro Segue pela Av. Pres. Antonio Carlos até o Ministerio da Fazenda. 5000 2014 Bloco: Bloco da Gold / Giro do Arar - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 09:00:00 -43.17297 -22.90778 Bloco do Boi “Só Falta Você!” Pedra de Guaratiba Zona Oeste 2018-02-13 Terça-feira de Carnaval 1900-01-02 18:00:00 1900-01-02 18:50:00 1900-01-02 22:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão até o final da rua 200 2010 Bloco: Bloco do Boi “Só Falta Você!” - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 18:00:00 NA NA Bloco do galho Guaratiba Zona Oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:30:00 1899-12-31 17:30:00 1899-12-31 22:00:00 rua abilio barreto inicio rio de janeiro Rua Abílio Barreto do início ao final da rua. 600 1979 Bloco: Bloco do galho - Bairro: Guaratiba - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:30:00 NA NA Bloco do Limão Jardim América Zona Norte 2 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca rivadavia c maia rio de janeiro Praça Andrade Neves, Rua Monsenhor Castelo Branco, Rua Ministro Artur Costa, Rua George Bizet, Rua Franz Liszt, Rua Debussy, Rua Ministro Artur Costa, Rua Viana do Casteloo e Praça Andrade Neves 800 2010 Bloco: Bloco do Limão - Bairro: Jardim América - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 NA NA Bloco do UHH! Copacabana Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 praca serzedelo correa rio de janeiro Parado 250 2008 Bloco: Bloco do UHH! - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.18373 -22.96950 Bloco dos Cachaças Barra da Tijuca Barra/JPA 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 av lucio costa rio de janeiro Avenida Lucio Costa, em frente ao nº 3604 - Calçadão da praia 1000 2008 Bloco: Bloco dos Cachaças - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.39362 -23.01303 Bloco dos Primos Ilha de Paquetá Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 17:30:00 1899-12-31 22:00:00 praca ex combatentes rio de janeiro Praia da Moreninha, Rua José Bonifácio, Rua Furkin Werneck, Praça Pintor Pedro Bueno. 500 2014 Bloco: Bloco dos Primos - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.07364 -22.83190 Bloco Só Te Pegando Barra da Tijuca Barra/JPA 2018-02-13 terça de carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 21:00:00 av lucio costa posto rio de janeiro Parado 500 2010 Bloco: Bloco Só Te Pegando - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 NA NA Boi de Anchieta Anchieta Zona Oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca nossa senho de nazare rio de janeiro Praça Nazaré, Rua Motorista Luiz de Abreu, Avenida Nazaré, Rua Motoriasta Luiz de Abreu, Praça Nazaré 2000 1945 Bloco: Boi de Anchieta - Bairro: Anchieta - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.39860 -22.82179 Bonecas Deslumbradas de Olaria Olaria Zona Norte 3 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua conselheiro paulino rio de janeiro Rua Conselheiro Paulino, Rua João Rêgo, Paranapanema, Rua Delfim Carlos, Praca Belmonte, Rua João Rêgo e Rua Conselheiro Paulino 4000 1977 Bloco: Bonecas Deslumbradas de Olaria - Bairro: Olaria - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.26833 -22.85271 Cabeça de Chave Copacabana Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua duvivier rio de janeiro Parado 2500 1982 Bloco: Cabeça de Chave - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.17800 -22.96537 Cachorro Cansado Flamengo Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca jose de alencar rio de janeiro Praça José de Alencar, Rua Marquês de Abrantes, Rua Marquês de Paraná, Rua Senador Vergueiro, Rua Barão do Flamengo e Praça José de Alencar 10000 1987 Bloco: Cachorro Cansado - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -43.17721 -22.93319 Caldeirão do Coqueiro Santíssimo Zona Oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca do coqueiro rio de janeiro Parado 500 2010 Bloco: Caldeirão do Coqueiro - Bairro: Santíssimo - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 NA NA Canela Fina Quintino Bocaiúva Zona Norte 1 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua pedro reis rio de janeiro Rua Pedro Reis, Argentina Reis, Travessa Guerra, João Barbalho, 21 de Abril, Nervalde Gouveia, Praça de Quintino 200 2011 Bloco: Canela Fina - Bairro: Quintino Bocaiúva - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 NA NA Cantinho do Urubu Madureira Zona Norte 2 2018-02-13 Terça-feira de Carnaval 1900-01-01 20:00:00 1900-01-01 20:00:00 1899-12-31 22:00:00 estrada do portela rio de janeiro Parado 1000 2013 Bloco: Cantinho do Urubu - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 20:00:00 -43.34309 -22.86879 Cardosão de Laranjeiras Laranjeiras Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 11:00:00 1899-12-31 13:00:00 1899-12-31 19:00:00 rua cardoso junior rio de janeiro Rua Cardoso Júnior, da Rua das Laranjeiras até a Quadra da Cardoso Júnior 700 1970 Bloco: Cardosão de Laranjeiras - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 11:00:00 -43.18877 -22.93959 Carmelitas Santa Teresa Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 largo do curvelo rio de janeiro Saindo do largo do Curvelo, seguindo até altura do Nº200 da Rua Joaquim Murtinho 800 1990 Bloco: Carmelitas - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 08:00:00 -43.62277 -22.92242 Cata Latas do Grajaú Grajaú Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 21:00:00 1899-12-31 22:00:00 praca nobel rio de janeiro Rua Saviana, Rua Rosa e Silva, Rua Campinas, Rua Uberaba, Rua Botucatu, Rua Barão de Mesquita e Largo do Verdun 2500 2011 Bloco: Cata Latas do Grajaú - Bairro: Grajaú - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 18:00:00 -43.25953 -22.92681 Cheiro na Testa Santa Teresa Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 11:00:00 1899-12-31 13:00:00 1899-12-31 17:00:00 largo dos guimaraes rio de janeiro Largo dos Guimarães, Rua Paschoal Carlos Magno, Rua Monte Alegre até a esquina com a Rua Áurea 1000 2008 Bloco: Cheiro na Testa - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 11:00:00 -43.18603 -22.92155 Chifrorosso Rocinha Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua rio de janeiro Rua 2 até a Estrada da Gavea 436 e retornando até origem 500 1985 Bloco: Chifrorosso - Bairro: Rocinha - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 19:00:00 -43.94066 -19.92645 Clube do Samba Copacabana Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 18:00:00 1899-12-31 19:30:00 avenida atlantica rio de janeiro Avenida Atlântica, da Rua Santa Clara indo em direção ao posto 6 - Constante Ramos - Barão de Ipanema - Bolivar - Xavier da Silveira - Miguel Lemos - Djalma Urich - Sá Ferreira 1000 1980 Bloco: Clube do Samba - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.18147 -22.96953 Cornos e Simpatizantes Manguinhos Zona Norte 2 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 av dos democraticos rio de janeiro Caminho dos Democráticos próximo a Suípa ate Av. dos Democráticos altura Rua José Rubino. 600 2007 Bloco: Cornos e Simpatizantes - Bairro: Manguinhos - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.25729 -22.87540 Deita Mas Não Dorme Taquara Barra/JPA 2018-02-13 Segunda-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua caituba rio de janeiro Parado 500 2009 Bloco: Deita Mas Não Dorme - Bairro: Taquara - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.37610 -22.91704 Dragões da Riachuelo Bairro de Fátima Centro 2018-02-13 Terça-feira de Carnaval 1900-01-01 14:30:00 1900-01-01 15:00:00 1900-01-01 18:00:00 rua do senado rio de janeiro Parado 200 2011 Bloco: Dragões da Riachuelo - Bairro: Bairro de Fátima - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:30:00 NA NA É Tudo ou Nada?! Humaitá Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 12:00:00 1899-12-31 12:00:00 1899-12-31 15:00:00 estacionamento da cobal do humaita rio de janeiro Voluntários da Pátria, Rua Conde de Irajá, Largo dos Leões e Rua Marques 3000 2008 Bloco: É Tudo ou Nada?! - Bairro: Humaitá - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 12:00:00 -43.19509 -22.95540 Embalo de Santa Tereza Santa Teresa Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 16:30:00 1899-12-31 19:30:00 largo do franca rio de janeiro Segue na Rua Alm. Alexandrino até o Largo do Vista Alegre seguindo até o Largo dos Guimarães onde dispersa. 800 2002 Bloco: Embalo de Santa Tereza - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.19549 -22.92984 Empurra que Pega do Leblon Leblon Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 av delfim moreira rio de janeiro Av. Delfim Moreira do Posto 12 até o posto 11 15000 1990 Bloco: Empurra que Pega do Leblon - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 13:00:00 -43.22156 -22.98700 Enxota que Eu Vou Centro Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca tiradentes rio de janeiro Parado 500 2008 Bloco: Enxota que Eu Vou - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 -41.50799 -17.86413 Fecha Bar Ilha de Paquetá Centro 2018-02-13 Terça-feira de Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praia jose bonifacio rio de janeiro Praia José Bonifácio, Rua Furquim Werneck, Rua Príncipe Regente, volta para José Bonifácio 500 1984 Bloco: Fecha Bar - Bairro: Ilha de Paquetá - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 18:00:00 -43.11011 -22.76268 G.R.B.C. Meu Peru é Seu Piedade Zona Norte 1 2018-02-13 Terça-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 r padre manuel da nobrega rio de janeiro R. Padre Manoel da Nobrega, Av. D. Helder Camara , retorno na R. Bernardino de Campos, Av. D. H. Camara, R. Souza Cerqueira, R. Gonçalo Coelho, R. Antonio Vargas e R. Padre Manoel da Nobrega. 300 2018 Bloco: G.R.B.C. Meu Peru é Seu - Bairro: Piedade - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 13:00:00 NA NA Gambá Cheiroso Jacarepaguá Barra/JPA 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 17:00:00 1899-12-31 22:00:00 rua bruno giorgi s n anfiteatro rio de janeiro Parado 1000 2017 Bloco: Gambá Cheiroso - Bairro: Jacarepaguá - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 NA NA Largo do Machado, Mas Não Largo do Copo Catete Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 largo do machado rio de janeiro Largo do Machado, Rua do Catete, Arthur Bernardes, Bento Lisboa, Ministro Tavares de Lira, Conde de Baependi, Rua do Catete e Largo do Machado 2000 2007 Bloco: Largo do Machado, Mas Não Largo do Copo - Bairro: Catete - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.17891 -22.93054 Meu Bem, Volto Já Leme Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 avenida princesa isabel esquina com ministro viveiros de castro rio de janeiro Avenida Princesa Isabel, Avenida Atlântica, seguindo até a Pedra do Leme 1000 1996 Bloco: Meu Bem, Volto Já - Bairro: Leme - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.17905 -22.96516 Mocidade Dependente de Deus Aterro do Flamengo Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 18:00:00 praia do flamengo a rio de janeiro PRAIA DO FLAMENGO, RUA PAISSANDÚ, RUA SENADOR VERGUEIRO, RUA DO CATETE, RUA SILVEIRA MARTINS, RETORNA A ORIGEM 800 1992 Bloco: Mocidade Dependente de Deus - Bairro: Aterro do Flamengo - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.17411 -22.93020 Muceludos de Padre Miguel Padre Miguel Zona Oeste 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 rua pedro melo rio de janeiro Segue pela Rua Japeju, Rua Olimpia Esteves, Rua Murundú, Rua Ceriba, Rua Maria Rosa, Largo da Tapiranga 300 2016 Bloco: Muceludos de Padre Miguel - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.44331 -22.88376 Mulheres da Vila Vila isabel Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 15:00:00 1899-12-31 17:00:00 1899-12-31 19:30:00 boulevard de setembro rio de janeiro Boulevard 28 de Setembro, esquina c/ Rua Gonzaga Bastos, seguindo pela 28 de setembro até a escola Vila Isabel 500 2011 Bloco: Mulheres da Vila - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 15:00:00 -43.24258 -22.91521 Ninho dos Cobras Madureira Zona Norte 1 2018-02-13 Terça-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 18:00:00 1899-12-31 19:00:00 rua carvalho de souza embaixo do viaduto de madureira rio de janeiro Rua Carvalho de Souza, Av. Ministro Edgard Romero e Estrada do Portela até a Rua Dagmar da Fonseca 800 2013 Bloco: Ninho dos Cobras - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 13:00:00 -43.33480 -22.87610 Orquestra Voadora Aterro do Flamengo Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 22:00:00 aterro do flamengo altura da praca luis de camoes coreto modernista rio de janeiro Segue pelo Aterro do Flamengo, com dispersão na Av. Infante Dom Henrique 85 aterro do Flamengo 80000 2008 Bloco: Orquestra Voadora - Bairro: Aterro do Flamengo - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 13:00:00 NA NA Quero Exibir Meu Longa Tijuca Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 10:00:00 1899-12-31 11:30:00 1899-12-31 16:00:00 praca gabriel soares rio de janeiro Praça Gabriel Soares, Rua José Higino, Rua Conde de Bonfim, Rua Henry Ford, Rua Desembargador Isidro, Praça Gabriel Soares 480 2013 Bloco: Quero Exibir Meu Longa - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 10:00:00 -43.23425 -22.93132 Raízes da Vila da Penha Vila da Penha Zona Norte 1 2018-02-13 Terça-feira de Carnaval 1899-12-31 13:00:00 1899-12-31 15:00:00 1899-12-31 19:00:00 rua sao joao gualberto rio de janeiro Rua São João Gualberto, Rua General Silveira Sobrinho, Rua Oliveira Belo, Rua Alice Tibiriça e Rua São João Gualberto 900 2007 Bloco: Raízes da Vila da Penha - Bairro: Vila da Penha - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 13:00:00 NA NA Rio Maracatu Ipanema Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 avenida vieira souto rio de janeiro Avenida Vieira Souto, do Posto 8 até o posto 9 5000 1998 Bloco: Rio Maracatu - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 08:00:00 NA NA Se Me Der, Eu Como! Tijuca Tijuca e Adj 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 praca da medalha milagrosa rio de janeiro Rua do Matoso, Rua Haddock Lobo, Rua Barão de Ubá, Rua Joaquim Palhares, Barão de Iguatemi. 3000 2004 Bloco: Se Me Der, Eu Como! - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.21262 -22.91639 Sobrinhos do Tio Bio Leblon Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 posto rio de janeiro Sai do posto 12 até o posto 11 3000 2006 Bloco: Sobrinhos do Tio Bio - Bairro: Leblon - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 09:00:00 -43.18991 -22.95568 Tribo Cacuia Ilha do Governador Zona Norte 3 2018-02-13 Terça-feira de Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 estrada do cacuia c estrada do galeao rio de janeiro Estrada do Galeão até Rua Mileto Maciel retorna pelo mesmo percurso até Rua Sargento João Lopes c/ Estrada do Cacuia 10000 2001 Bloco: Tribo Cacuia - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 16:00:00 NA NA Tudubloco Madureira Zona Norte 1 2018-02-13 Terça de Carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 14:00:00 parque madureira rio de janeiro Parado 10000 2018 Bloco: Tudubloco - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 09:00:00 NA NA Último Gole Lagoa Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 parque dos patins rio de janeiro PARADO 3000 1997 Bloco: Último Gole - Bairro: Lagoa - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 -43.21645 -22.97227 Unidos do Complexo do Alemão Bonsucesso Zona Norte 3 2018-02-13 Terça-feira de Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 20:00:00 rua nova brasilia rio de janeiro Rua Nova Brasília 02 até a Praça do Terço N°5 1000 2012 Bloco: Unidos do Complexo do Alemão - Bairro: Bonsucesso - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 17:00:00 -43.26571 -22.91639 Vagalume O Verde Jardim Botânico Zona Sul 2018-02-13 Terça-feira de Carnaval 1899-12-31 08:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 rua jardim botanico rio de janeiro Rua Jardim Botânico, da Rua Pacheco Leão até a Praça Santos Dumont 10000 2005 Bloco: Vagalume O Verde - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 08:00:00 -43.21732 -22.96402 Vem Comigo Vila Cosmos Zona Norte 1 2018-02-13 Quarta-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 17:30:00 1899-12-31 19:00:00 rua itacambira c av meriti rio de janeiro Rua Alecrim, Rua Itacambira com Rua Imbiaça. 1200 2000 Bloco: Vem Comigo - Bairro: Vila Cosmos - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 14:00:00 NA NA Virilha de Minhoca Bangu Zona oeste 2018-02-13 Terça de Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua fonseca rio de janeiro Rua fonseca, rua oliveira ribeiro, Av. Cônego de Vasconcelos, Rua Santa Cecilia, Rua Fonseca 6000 2002 Bloco: Virilha de Minhoca - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-13 - Concentração 18:00:00 -43.46555 -22.88198 Ainda Aguento Ilha do Governador Zona Norte 3 2018-02-14 Quarta-feira de Cinzas 1899-12-31 11:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 praia da engenhoca rio de janeiro Rua Praia da Engenhoca, Rua Novo Airão, Rua Fernandes da Fonseca, Pça Iaiá Garcia e retorna para origem pelo trajeto inverso. 800 2008 Bloco: Ainda Aguento - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 11:00:00 -43.17094 -22.82154 Amigos da Onça Flamengo Zona Sul 2018-02-14 Quarta - Feira de Cinzas 1899-12-31 06:00:00 1899-12-31 07:00:00 1899-12-31 12:00:00 praia do flamengo rio de janeiro Pista interna da Praia do Flamengo 20000 2012 Bloco: Amigos da Onça - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 06:00:00 -43.17411 -22.93020 Amigos da Velha Guarda Recreio dos Bandeirantes Barra/JPA 2018-02-14 Quarta-feira de Cinzas 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 av lucio costa quiosque terapia rio de janeiro Parado 1000 2017 Bloco: Amigos da Velha Guarda - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 14:00:00 -43.45617 -23.02508 Banda do Village Ilha do Governador Zona Norte 3 2018-02-14 Quarta-feira de Cinzas 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 rua luiz sa altura do numero rio de janeiro Parado 1500 2009 Bloco: Banda do Village - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 16:00:00 NA NA Batalha dos Blocos Recreio dos Bandeirantes Barra/JPA 2018-02-14 quarta-feira de cinzas 1899-12-31 10:00:00 1899-12-31 10:00:00 1899-12-31 14:00:00 praia do recreio posto rio de janeiro Parado 4000 2017 Bloco: Batalha dos Blocos - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 10:00:00 NA NA Batuque das Meninas Laranjeiras Zona Sul 2018-02-14 Quarta-feira de Cinzas 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 21:00:00 praca largo do machado rio de janeiro Largo do Machado - Parado 200 2010 Bloco: Batuque das Meninas - Bairro: Laranjeiras - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 15:00:00 -43.17857 -22.93080 Bloco da Apuração dos Embaixadores da Folia Lapa Centro 2018-02-14 Quarta-feira de Cinzas 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 18:30:00 av gomes freire rio de janeiro Parado 500 2001 Bloco: Bloco da Apuração dos Embaixadores da Folia - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 14:00:00 -43.18396 -22.91056 Chave de Ouro Engenho de Dentro Zona Norte 2 2018-02-14 Quarta-feira de Cinzas 1899-12-31 15:00:00 1899-12-31 16:00:00 1899-12-31 18:00:00 rua adolfo bergamini chave de ouro rio de janeiro Rua Adolfo Bergamini, Rua Ana Leonidia , Rua Dr. Bulhões, Rua Borja Reis e Rua Adolfo Bergamini, voltando ao Chave de Ouro 800 2014 Bloco: Chave de Ouro - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 15:00:00 -43.29740 -22.90417 Guri da Merck Taquara Barra/JPA 2018-02-14 Quarta-feira de Cinzas 1899-12-31 16:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 praca albert sabin praca da merck rio de janeiro PARADO 1000 2013 Bloco: Guri da Merck - Bairro: Taquara - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 16:00:00 -43.36864 -22.93452 Me Enterra na Quarta Santa Teresa Centro 2018-02-14 Quarta - Feira de Cinzas 1899-12-31 15:30:00 1899-12-31 17:00:00 1899-12-31 21:30:00 praca odilio costa rio de janeiro Segue pela Rua Áurea até Rua Alm. Alexandrino, Rua Joaquim Murtinho e Largo do Curvello. 1500 2003 Bloco: Me Enterra na Quarta - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 15:30:00 -43.47398 -23.01844 Os Filhos da P! Lagoa Zona Sul 2018-02-14 Quarta-feira de Cinzas 1899-12-31 14:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 parque das figueiras rio de janeiro PARADO 5000 2016 Bloco: Os Filhos da P! - Bairro: Lagoa - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 14:00:00 -43.21783 -22.97536 Planta na Mente Lapa Centro 2018-02-14 Quarta-feira de Cinzas 1899-12-31 15:20:00 1899-12-31 16:20:00 1899-12-31 21:20:00 praca cardeal camara arcos da lapa rio de janeiro Rua dos Arcos, Rua do Lavradio, Rua do Senado, Rua Pedro I, Rua Visconde do Rio Branco e Praça Tiradentes 1000 2011 Bloco: Planta na Mente - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-14 - Concentração 15:20:00 -43.17996 -22.91304 Bangay Folia Padre Miguel Zona Oeste 2018-02-16 Sexta-feira após o Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua sidney com rua figueiredo camargo rio de janeiro Rua Sidney com Figueiredo Camargo, Rua Figueiredo Camargo com Ponto Chic, Rua Figueiredo Camargo com Rua D 500 2017 Bloco: Bangay Folia - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-16 - Concentração 16:00:00 -43.45581 -22.87158 Bloco Confetes e Serpentinas Pedra de Guaratiba Zona Oeste 2018-02-16 sexta-feira pós carnaval 1899-12-31 19:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca dr raul capello barrozo rio de janeiro Parado 1500 2016 Bloco: Bloco Confetes e Serpentinas - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-16 - Concentração 19:00:00 NA NA Bloco do Brow Ilha do Governador Zona Norte 3 2018-02-16 Sexta-feira após o Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 praca iaia garcia rio de janeiro Parado 1500 2015 Bloco: Bloco do Brow - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-16 - Concentração 18:00:00 -43.16952 -22.82582 Só Tamborins Lapa Centro 2018-02-16 Sexta-feira após o Carnaval 1899-12-31 18:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 travessa do mosqueira rio de janeiro Rua Visconde de Maranguape, Rua da Lapa, Rua da Glória, seguindo até o Largo da Glória 2500 2007 Bloco: Só Tamborins - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-16 - Concentração 18:00:00 -43.17917 -22.91413 Bafafá Ipanema Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 09:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 praia de ipanema posto rio de janeiro PARADO 20000 2003 Bloco: Bafafá - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 09:00:00 -43.20287 -22.98697 Banda da Penha Penha Zona Norte 2 2018-02-17 Terça-feira de Carnaval 1899-12-31 16:00:00 1900-01-04 20:00:00 1900-01-04 22:00:00 largo da rua couto rio de janeiro Parado 1000 2014 Bloco: Banda da Penha - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 16:00:00 -43.23597 -22.89044 Banda de Ipanema - HOMENAGEM Ipanema Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 15:00:00 1899-12-31 17:30:00 1899-12-31 21:00:00 praca general osorio rio de janeiro Praça General Osório - Parado 5000 1965 Bloco: Banda de Ipanema - HOMENAGEM - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 15:00:00 -43.19782 -22.98518 Banda Devassa Penha Zona Norte 1 2018-02-17 Sábado após o Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua patagonia rio de janeiro Rua Patagônia, Rua Quito, Rua Montevidéu, Rua Nicarágua e Rua Patagônia 4000 2011 Bloco: Banda Devassa - Bairro: Penha - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 16:00:00 -43.27647 -22.83933 Bater Funk Recreio dos Bandeirantes Barra/JPA 2018-02-17 Sábado após o Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 17:00:00 posto do recreio rio de janeiro Avenida Lucio Costa dos Postos 10 ao 09 5000 2018 Bloco: Bater Funk - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 13:00:00 -43.48295 -23.01784 Berço do Samba Lapa Centro 2018-02-17 Sábado após o Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 praca cardeal camara arcos da lapa rio de janeiro Parado 5000 2006 Bloco: Berço do Samba - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 16:00:00 -43.17996 -22.91304 Bloco da Ressaca Pedra de Guaratiba Zona Oeste 2018-02-17 Sábado Após o Carnaval 1899-12-31 17:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua barros de alarcao praca sao pedro rio de janeiro Rua Barros de Alarcão N283 até 464 300 2007 Bloco: Bloco da Ressaca - Bairro: Pedra de Guaratiba - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 17:00:00 NA NA Bloco das Poderosas Centro Centro 2018-02-17 Sábado após o Carnaval 1899-12-31 07:00:00 1899-12-31 09:00:00 1899-12-31 13:00:00 av pres antonio carlos rio de janeiro Segue pela Av. Pres. Antonio Carlos até o Ministerio da Fazenda. 200000 2016 Bloco: Bloco das Poderosas - Bairro: Centro - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 07:00:00 -43.17297 -22.90778 Bloco EVA Barra da Tijuca Barra/JPA 2018-02-17 Sábado após o Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 arena blocos rio de janeiro Parado 10000 2018 Bloco: Bloco EVA - Bairro: Barra da Tijuca - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 10:00:00 -42.00857 -22.88121 Chulé de Santa Santa Teresa Centro 2018-02-17 Sábado depois do Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 15:00:00 largo do curvelo rio de janeiro Parado 200 2017 Bloco: Chulé de Santa - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 10:00:00 -43.62277 -22.92242 Ciganas Feiticeiras de Olaria Olaria Zona Norte 3 2018-02-17 Sábado após o Carnaval 1899-12-31 17:00:00 1899-12-31 19:00:00 1899-12-31 21:00:00 rua paranhos rio de janeiro Rua João Rego, Rua Delfim Carlos, Rua Paranhos até origem. 1000 1995 Bloco: Ciganas Feiticeiras de Olaria - Bairro: Olaria - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 17:00:00 -43.27050 -22.85436 É Pequeno mas não amolece Recreio dos Bandeirantes Barra/JPA 2018-02-17 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 praca professor henrique niremberg rio de janeiro Praça Professor Henrique Niremberg, Rua Professora Isolina Sartore, Rua Joaquim da Silveira, José Afonso Neto e Praça Professor Henrique Niremberg 500 2009 Bloco: É Pequeno mas não amolece - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.46680 -23.02006 Eu Amo Cerveja Lapa Centro 2018-02-17 Sábado após o Carnaval 1899-12-31 13:00:00 1899-12-31 13:00:00 1899-12-31 17:00:00 praca cardeal camara arcos da lapa rio de janeiro Parado 1000 2017 Bloco: Eu Amo Cerveja - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 13:00:00 -43.17996 -22.91304 Fuzuê… Só Alegria Pra Você! Del Castilho Zona Norte 2 2018-02-17 Sábado após o Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua chapadinha rio de janeiro Rua Chapadinha, Rua Lagoa Verde, Rua Lagoa Clara, Rua Lagoa Redonda, Rua Chapadinha e Rua Palmeira do Norte 2000 2004 Bloco: Fuzuê… Só Alegria Pra Você! - Bairro: Del Castilho - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 16:00:00 -43.27098 -22.87268 GRBC Deixa Que Eu Te Atravesso Brás de Pina Zona Norte 1 2018-02-17 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 rua rio preto rio de janeiro Rua Rio Preto, Rua Brasiléia, Rua Alm. Ingran Margini, Rua Dezoito de Setembro, Rua Valdemar Magrini, até Rua Rio Preto 1000 2016 Bloco: GRBC Deixa Que Eu Te Atravesso - Bairro: Brás de Pina - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.24372 -22.85050 Mistura de Santa Santa Teresa Centro 2018-02-17 Sábado após o Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 mirante do rato molhado rio de janeiro Segue pela Rua Aprazível até dispersar na lateral do Castelo São Valentim na parte alta da Rua Almirante Alexandrino. 500 2014 Bloco: Mistura de Santa - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 17:00:00 -43.18664 -22.92389 Mulheres de Chico Leme Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 15:00:00 1899-12-31 15:00:00 1899-12-31 20:00:00 praia do leme proximo ao costao rio de janeiro Parado 50000 2007 Bloco: Mulheres de Chico - Bairro: Leme - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 15:00:00 NA NA O Fervo Estácio Centro 2018-02-17 Sábado após o Carnaval 1900-01-01 14:00:00 1900-01-01 18:00:00 1900-01-01 20:00:00 rua maia de lacerda rio de janeiro Rua Maia de Lacerda, da esquina da Rua Estácio de Sá até a Rua Sampaio Ferraz e termina na rua Quintino do Vale 500 2016 Bloco: O Fervo - Bairro: Estácio - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.20601 -22.91710 Os 300 Padre Miguel Zona Oeste 2018-02-17 Sábado Após o Carnaval 1899-12-31 16:30:00 1899-12-31 17:00:00 1899-12-31 22:00:00 largo da tapiranga rio de janeiro Largo da Tapiranga, Rua Maria Rosa, Rua Japeju, Rua Tapiranga e Largo da Tapiranga 1000 2014 Bloco: Os 300 - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 16:30:00 -43.44612 -22.88209 Pela Saco Botafogo Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 17:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca corumba rio de janeiro Praça Corumbá, Rua São Clemente, Rua Real Grandeza, Rua Voluntários da Pátria, Rua da Matriz e Praça Corumbá 5000 2001 Bloco: Pela Saco - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 17:00:00 -43.19263 -22.95018 Quizomba Lapa Centro 2018-02-17 Sábado após o Carnaval 1899-12-31 09:00:00 1899-12-31 10:00:00 1899-12-31 15:00:00 rua do riachuelo rio de janeiro Rua Riachuelo, Av. Mem de Sá, Rua Teixeira de Freitas, Av. Augusto Severo 5000 2002 Bloco: Quizomba - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 09:00:00 -43.18691 -22.91493 Se Essa Rua Fosse Minha Flamengo Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 praca sandro moreira rio de janeiro PARADO 1500 2017 Bloco: Se Essa Rua Fosse Minha - Bairro: Flamengo - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 10:00:00 -43.17805 -22.93682 Sem Saída Botafogo Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 20:00:00 rua general severiano rio de janeiro Rua General Severiano, Rua Venceslau Brás, Av. Pasteur e Rua Bartolomeu Portela 1200 2009 Bloco: Sem Saída - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.17830 -22.95340 Sepulta Carnaval Engenho de Dentro Zona Norte 2 2018-02-17 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 20:00:00 rua ana leonidia rio de janeiro Rua Ana Leonídia, Rua Dr. Bulhões, Rua Borja Reis, Rua Adolfo Bergamini, Rua Pernambuco, Rua Dr. Bulhões e Rua Ana Leonídia 1000 2003 Bloco: Sepulta Carnaval - Bairro: Engenho de Dentro - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.29766 -22.90050 Sufridos de Copacabana Copacabana Zona Sul 2018-02-17 Sábado após o Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 22:00:00 praca manuel campos da paz rua ianga rio de janeiro Parado 400 2009 Bloco: Sufridos de Copacabana - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 16:00:00 NA NA Superbacana Tijuca Tijuca e Adj 2018-02-17 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 praca afonso pena rio de janeiro Parado 600 2017 Bloco: Superbacana - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.21816 -22.91806 Vaca Atolada dos Embaixadores da Folia Lapa Centro 2018-02-17 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 17:00:00 1899-12-31 18:30:00 av gomes freire rio de janeiro Parado 800 2001 Bloco: Vaca Atolada dos Embaixadores da Folia - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 14:00:00 -43.18396 -22.91056 Vem Comigo Cachaçada Ilha do Governador Zona Norte 3 2018-02-17 Sábado após o Carnaval 1899-12-31 13:00:00 1899-12-31 17:00:00 1899-12-31 19:00:00 rua paramopama rio de janeiro Rua Paramopama, do Restaurante Bom Demais até a Praça da Ribeira, contornando a Praça e voltando ao local de concentração 1500 2007 Bloco: Vem Comigo Cachaçada - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-17 - Concentração 13:00:00 NA NA 7 de Paus Vila isabel Tijuca e Adj 2018-02-18 Domingo após o Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 av de setembro c rua visc de abaete rio de janeiro Boulevard 28 de Setembro, da Rua Visconde de Abaeté até a Praça Barão de Drummond 1000 2007 Bloco: 7 de Paus - Bairro: Vila isabel - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 16:00:00 NA NA Aí Sim Tijuca Tijuca e Adj 2018-02-18 Sábado após o Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 praca xavier de brito rio de janeiro Parado 800 2017 Bloco: Aí Sim - Bairro: Tijuca - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 14:00:00 -43.24349 -22.93197 Bangay Folia Bangu Zona Oeste 2018-02-18 Domingo após o Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua de fevereiro santa cecilia rio de janeiro Rua 12 de Fevereiro, Rua Santa Cecília, Rua Bangu 500 2017 Bloco: Bangay Folia - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 16:00:00 -43.18389 -22.95742 Bloco Galasextou São Cristóvão Centro 2018-02-18 Domingo após o Carnaval 1899-12-31 16:00:00 1899-12-31 20:00:00 1899-12-31 22:00:00 rua general almerio de moura estacionamento rio de janeiro Segue Rua Teixeira Junior, Rua São Januário, Rua Francisco Palheta, Rua Ricardo Machado e retorna ao destino. 1500 2017 Bloco: Bloco Galasextou - Bairro: São Cristóvão - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 16:00:00 NA NA Boêmios da Lapa Lapa Centro 2018-02-18 Sexta-feira de Carnaval 1899-12-31 14:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 rua joaquim silva rio de janeiro Parado 1000 2003 Bloco: Boêmios da Lapa - Bairro: Lapa - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 14:00:00 NA NA Boka de Espuma Botafogo Zona Sul 2018-02-18 Domingo após o Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua marques de olinda rio de janeiro Rua Marquês de Olinda, Rua Muniz Barreto, Rua São Clemente, Rua Bambina e Rua Marquês de Olinda 30000 1984 Bloco: Boka de Espuma - Bairro: Botafogo - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 16:00:00 -43.18436 -22.94374 Bonde da Folia Santa Teresa Centro 2018-02-18 Domingo após o Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 18:00:00 rua fonseca guimaraes rio de janeiro Rua Fonseca Guimarães, Rua Paschoal Carlos Magno, Rua almirante Alexandrino, Rua Dias de Barros e Largo do Curvelo 500 2009 Bloco: Bonde da Folia - Bairro: Santa Teresa - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 12:00:00 -43.18703 -22.92026 Broxadão Copacabana Zona Sul 2018-02-18 Domingo após o Carnaval 1899-12-31 14:00:00 1899-12-31 16:00:00 1899-12-31 18:00:00 avenida atlantica rio de janeiro Avenida Atlântica, da Figueiredo de Magalhães até a República do Peru, retornando ao local de concentração 700 2010 Bloco: Broxadão - Bairro: Copacabana - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 14:00:00 -43.18147 -22.96953 Conjunto Habitacional Barangal Ipanema Zona Sul 2018-02-18 Domingo após o Carnaval 1899-12-31 09:00:00 1899-12-31 10:30:00 1899-12-31 15:00:00 avenida vieira souto rio de janeiro Avenida Vieira Souto, do Posto 9 a Sala Cecília Meirelles, retornando ao Posto 9 150 2002 Bloco: Conjunto Habitacional Barangal - Bairro: Ipanema - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 09:00:00 -43.20497 -22.98656 Fofoqueiros de Plantão Jardim Botânico Zona Sul 2018-02-18 Domingo após o Carnaval 1899-12-31 10:00:00 1899-12-31 12:00:00 1899-12-31 16:00:00 rua jardim botanico rio de janeiro Segue pela Rua Jardim Botânico até a Pracá Santos Dumont 5000 2008 Bloco: Fofoqueiros de Plantão - Bairro: Jardim Botânico - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 10:00:00 NA NA Giro do Arar Madureira Zona Norte 1 2018-02-18 Domingo pós carnaval 1899-12-31 09:00:00 1899-12-31 11:00:00 1899-12-31 15:00:00 parque madureira rio de janeiro Parque Madureira 10000 2013 Bloco: Giro do Arar - Bairro: Madureira - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 09:00:00 -43.34562 -22.86340 Monobloco Aterro do Flamengo Zona Sul 2018-02-18 Domingo após o Carnaval 1899-12-31 06:00:00 1899-12-31 09:00:00 1899-12-31 12:00:00 aterro do flamengo altura da praca luis de camoes coreto modernista rio de janeiro Segue pelo Aterro do Flamengo, com dispersão na Av. Infante Dom Henrique 85 aterro do Flamengo 200000 2000 Bloco: Monobloco - Bairro: Aterro do Flamengo - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 06:00:00 NA NA Papudinho do Rio Comprido Rio Comprido Centro 2018-02-18 Domingo após o Carnaval 1899-12-31 12:00:00 1899-12-31 14:00:00 1899-12-31 20:00:00 praca condessa paulo de frontin rio de janeiro Praça Condessa Paulo de Frontin, Rua Estrela, Rua Itapiru, Rua Caetano Martins, Rua Campos da Paz, Rua Aristides Lobo e Praça Condessa Paulo de Frontin 100 1994 Bloco: Papudinho do Rio Comprido - Bairro: Rio Comprido - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 12:00:00 -43.20880 -22.92463 Quem Vai Vai, Quem Não Vai Não Cagueta! Ilha do Governador Zona Norte 3 2018-02-18 Domingo após o Carnaval 1899-12-31 18:00:00 1899-12-31 18:00:00 1899-12-31 21:00:00 praca jerusalem rio de janeiro Praça Jerusalem, Praia da Bica até Quiosque do Mexicano 1000 2010 Bloco: Quem Vai Vai, Quem Não Vai Não Cagueta! - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 18:00:00 -43.20120 -22.81882 Seu Veneno Me Alimenta Recreio dos Bandeirantes Barra/JPA 2018-02-18 Domingo após o Carnaval 1899-12-31 13:00:00 1899-12-31 14:00:00 1899-12-31 19:00:00 posto do recreio rio de janeiro Posto 10 do Recreio ao Posto 9. 5000 2018 Bloco: Seu Veneno Me Alimenta - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 13:00:00 -43.45748 -23.02471 Tamo Junto in Folia Padre Miguel Zona Oeste 2018-02-18 Domingo após o Carnaval 1899-12-31 16:00:00 1899-12-31 18:00:00 1899-12-31 22:00:00 rua figueiredo camargo com rua irere rio de janeiro Parado 60000 2005 Bloco: Tamo Junto in Folia - Bairro: Padre Miguel - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 16:00:00 -43.45501 -22.87162 Tô no Recreio Recreio dos Bandeirantes Barra/JPA 2018-02-18 Domingo após o Carnaval 1899-12-31 16:00:00 1899-12-31 16:00:00 1899-12-31 19:00:00 avenida lucio costa rio de janeiro Avenida Lucio Costa, do Posto 10 até entrada da Praia da Reserva 1000 2009 Bloco: Tô no Recreio - Bairro: Recreio dos Bandeirantes - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 16:00:00 -43.39362 -23.01303 União dos Blocos da Ilha do Governador Ilha do Governador Zona Norte 3 2018-02-18 Domingo após o Carnaval 1899-12-31 10:00:00 1899-12-31 10:00:00 1899-12-31 16:00:00 praca iaia garcia rio de janeiro PARADA 2000 2010 Bloco: União dos Blocos da Ilha do Governador - Bairro: Ilha do Governador - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 10:00:00 -43.16952 -22.82582 Virilha de Minhoca Bangu Zona oeste 2018-02-18 Sábado Após o Carnaval 1899-12-31 18:00:00 1899-12-31 19:00:00 1899-12-31 22:00:00 rua fonseca rio de janeiro Rua fonseca, rua oliveira ribeiro, Av. Cônego de Vasconcelos, Rua Santa Cecilia, Rua Fonseca 6000 2002 Bloco: Virilha de Minhoca - Bairro: Bangu - Regiao: Zona Norte 2Data: 2018-02-18 - Concentração 18:00:00 -43.46555 -22.88198 Cheers! Além da combinação de elementos de circo, fantasias e toda a festa na rua que permite às pessoas perderem um pouco sua individualidade cotidiana e experimentarem um sentido diferente de unidade social, o carnaval envolve também a produção cultural e desfile de escolas de samba!\nDado esses diferentes aspectos de folia que envolvem o carnaval, com um olhar mais analítico a onipresença dos dados pode ser notada e por vezes conter informações relevantes.\nEspero que o post tenha sido útil e desejo um bom carnaval a todos!\nPerguntas frequentes Como transformar um endereço em coordenadas no R? Use a função geocode() do pacote ggmap, que consulta um serviço de geocodificação e devolve latitude e longitude a partir do texto do endereço. É o mesmo princípio usado neste post para posicionar cada bloco de carnaval no mapa.\nQual pacote usar para mapas interativos no R? O leaflet é a opção mais direta para mapas interativos em HTML, com zoom, popups e camadas. O leaflet.extras complementa com recursos extras de personalização, como os usados neste post.\nEsse código funciona para qualquer cidade, não só carnaval? Sim. A técnica (geocodificar endereços e plotar num leaflet) serve para qualquer base de dados com endereços: encontrar o restaurante mais próximo, mapear pontos de venda, visualizar ocorrências geográficas de qualquer tipo.\n","date":"1 de fevereiro de 2018","externalUrl":null,"permalink":"/post/2018-02-01-leaflet-carnaval/","section":"Posts","summary":" Onde estão os blocos? Fevereiro começando e o carnaval já está ai, especialmente se você mora no Rio de Janeiro já deve ter passado por algum bloco e a pergunta que todo mundo faz no carnaval pelo menos uma vez é: “Onde tem bloco?”.\nTL;DR\nUsamos ggmap para geocodificar (transformar endereço em latitude/longitude) os blocos de carnaval. O pacote leaflet (com leaflet.extras) plota tudo num mapa interativo. A limpeza de texto usa a função ajustar_nomes() do post sobre manipulação de strings. Baseado nessa pergunta resolvi fazer esse post especial, vamos utilizar os pacotes ggmap e leaflet para buscar as coordenadas geográficas do endereço dos blocos e representa-los num mapa agradável de navegar\n","title":"Carnaval e mapas interativos com R","type":"post"},{"content":" Dashboard text mining v1 # Link do repositório no github: https://github.com/gomesfellipe/dashboard-text-mining-1\nLink de acesso ao dashboard : https://gomesfellipe.shinyapps.io/dashboard-text-mining-1/\nMotivação # Elaborar este dashboard foi uma tarefa que decidi executar pois me foi perguntado se era possível \u0026ldquo;alguma coisa\u0026rdquo; com os dados obtidos através da ferramenta Social Searcher responsável por captar informações de diferentes mídias sociais sob algum tópico de interesse.\nDecidi então praticar a criação de dashboards com R e juntei algumas abordagens simples de text mining em um dashboard produzido através do pacote flexdashboard, disponível no CRAN.\nPortanto este dashboard não foi programado para funcionar de maneira genérica, as diversas funcionalidades devem ser adaptadas caso seja utilizado para analisar novas bases.\nArquivos # Esta pasta contém os seguintes arquivos:\nCódigo responsável por gerar o dashboard\ndashboard-text-mining-1.Rmd Bases:\nbase.xlsx - exemplo de dados obtidos com a ferramenta Social Searcher\nsentimentos.csv - base com classificação de sentimentos (lexical)\nFunções:\ncatch_error.R cleanTweets.R cleanTweetsAndRemoveNAs.R html_to_text.R plot_kmeans.R rm_accent.R rquery_wordcloud.R score.sentiment.R Mais informações sobre funções de textmining podem ser obtidas neste link ou no repositório deste guia no github\nDashboard # Este dashboard conta com 5 abas. Além da base de dados obtida com o Social Searcher, também foi utilizada o pacote lexiconPT que conta com alguns datasets léxicos para análise de texto em português. Com essa duas bases foi computada a interseção e os sentimentos de cada palavra foram registrados (qualquer nova palavra pode ser adicionada ao dicionário léxico posteriormente para enriquecer a apresentação visual).\n\u0026ldquo;Sem remover sufixos\u0026rdquo; # A primeira parte do dashboard apresenta 4 nuvens de palavras, na parte superior a primeira nuvem não foi feita a transformação tf-idf, já na nuvem a direita essa transformação foi feita e ambas dispostas lado a lado para avaliar o efeito da transformação no shape da nuvem.\nJá as nuvens da parte inferior são versões das nuvens acima, realizando a análise lexical.\nCom os botões é possível controlar a frequência minima e o número máximo de palavras na nuvem.\nAlém disso, ao lado da barra lateral dos botões é possível conferir a frequência de palavras únicas e também sequencias de palavras, que foram computadas com a ajuda do pacote RWeka (ferramenta interessante para aplicações de machine learning e data mining).\n\u0026ldquo;Removendo sufixos\u0026rdquo; # A segunda aba possui basicamente as mesmas características da primeira, porém nesta seção foi realizada a retirada dos radicais com a função SnowballC::wordStem(), veja:\n\u0026ldquo;Associação entre palavras\u0026rdquo; # A terceira aba é responsável por trazer o resultados do comando tm::findAssocs que busca associações entre palavras em um document-term ou uma term-document, do pacote tm, muito famoso quando o assunto é text mining.\n\u0026ldquo;Agrupamento\u0026rdquo; # Para efeito de ilustração do que pode ser feito, nesta aba foi feita uma análise de clusters calculando a distância euclideana e agrupando os dados de acordo com o método de Ward.\nO dendograma pode ser apresentado de muitas formas diferentes, então nesta apresentação coloquei à direita a representação convencional e à direita o mesmo dendograma é apresentado de maneira \u0026ldquo;aberta\u0026rdquo; e colorida, facilitando a visualização dos grupos formados.\n\u0026ldquo;k-means\u0026rdquo; # Na última aba foi apresentado uma aplicação do algorítimo k-means, uma técnica simples de agrupamento utilizado em procedimentos não supervisionados de machine learning.\nEm conjunto com a função ggplotly do pacote plotly fica muito simples tornar esta imagem interativa, veja:\n","date":"27 de janeiro de 2018","externalUrl":null,"permalink":"/projects/dashboard-text-mining-1/","section":"Projetos","summary":"Dashboard text mining v1 # Link do repositório no github: https://github.com/gomesfellipe/dashboard-text-mining-1\nLink de acesso ao dashboard : https://gomesfellipe.shinyapps.io/dashboard-text-mining-1/\nMotivação # Elaborar este dashboard foi uma tarefa que decidi executar pois me foi perguntado se era possível “alguma coisa” com os dados obtidos através da ferramenta Social Searcher responsável por captar informações de diferentes mídias sociais sob algum tópico de interesse.\n","title":"Dashboard com textmining de mídias sociais","type":"projects"},{"content":" Curiosidades sobre a teoria das probabilidades TL;DR\nNum grupo de apenas 23 pessoas, a probabilidade de duas fazerem aniversário no mesmo dia já passa de 50%. O resultado é contraintuitivo; resolvemos de duas formas: analítica (abordagem clássica) e por simulação em R (abordagem frequentista). Uma simulação com 5000 turmas confirma a fórmula teórica. O uso de cálculo de probabilidades para avaliar incertezas já é utilizado a centenas de anos. Foram tantas áreas que se encontraram aplicações (como na medicina, jogos de azar, previsão do tempo…) que hoje não restam dúvidas de que os dados são onipresentes, ainda mais em plena era da informação.\nOs conceitos de chances e de incertezas são tão antigos quando a própria civilização. Pessoas sempre tiveram que lidar com incertezas sobre o clima, suprimento de alimentos, suprimentos de água, risco de vida e tantas outras ameaças ao ser humano que o esforço para reduzir essas incertezas e seus efeitos passou a ser muito importante.\nA ideia do jogo tem uma longa história,já no egito antigo em 2000 a.c foram encontrados em tumbas (dados cúbicos com marcações praticamente idênticas às de dados modernos (wikipedia)).\nSegundo DeGroot (n.d.), a teoria da probabilidade foi desenvolvida de forma constante desde o século XVII e tem sido amplamente aplicada em diversos campos de estudo. Hoje, a teoria da probabilidade é uma ferramenta importante na maioria das áreas de engenharia, ciência e gestão.\nMuitos pesquisadores estão ativamente envolvidos na descoberta e no estabelecimento de novas aplicações de probabilidade em campos de química, meteorologia, fotografia de satélites, marketing, previsão de terremoto, comportamento humano, design de sistemas informáticos, finanças, genética e lei.\nConceitos e interpretações para probabilidades Além das muitas aplicações formais da teoria da probabilidade, o conceito de probabilidade entra em nossa vida cotidiana e conversa.\nMuitas vezes ouvimos e usamos expressões como “Provavelmente vai chover a amanhã à noite,” “É muito provável que o onibus atrase,” ou “As chances são altas de não poder se juntar a nós para almoçar esta tarde.” Cada uma dessas expressões é baseada no conceito da probabilidade de que algum evento específico ocorrerá.\nExistem três abordagens atualmente, as duas primeiras são:\nClássica Se refere à subconjuntos unitários equiprováveis\n\\(P(A)=\\dfrac{\\text{Número de elementos de }A}{\\text{Número de elementos de }\\Omega}\\)\nFrequentista ou Estatística Considera o limite de frequências relativas como o valor de probabilidade\n\\(P(A)=lim_{n \\rightarrow \\infty} \\frac{n_A}{n}\\)\nonde \\(n_A\\) é o nº de ocorrências de \\(A\\) em \\(n\\) repetições independentes do experimento\nDefinição de probabilidade Segundo Magalhães (n.d.), as definições acima possuem o apelo da intuição e permanecem sendo usadas para resolver inúmeros problemas, entretanto elas não são suficientes para uma formulação matemática rigorosa da probabilidade.\nAproximadamente em 1930 A. N. Kolmogorov apresentou um conjunto de axiomas matemáticos para definir probabilidade, permitindo incluir as definições anteriores como casos particulares.\nPorém, como o verdadeiro significado da probabilidade ainda é um assunto altamente polêmico e está envolvido em muitas discussões filosóficas atuais sobre as bases da estatística e quando se trata de probabilidades, não adianta utilizar apenas a intuição pois nosso cérebro vai da bug!\nA probabilidade é extremamente contra intuitiva e seu estudo deve sempre envolver uma vasta gama de exercícios para treinar nosso raciocínio analítico. Existem diversos problemas práticos que já ilustraram isso e um ótimo exemplo que todo mundo que já fez um curso básico de probabilidade já conhece, o Paradóxo do aniversário\nO paradoxo do aniversário (ou problema dos aniversários - Feller[68]) Exemplo retirado do livro do Feller (n.d.), questiona:\n“Num grupo de \\(n\\) pessoas, qual é a probabilidade de pelo menos duas delas fazerem aniversário no mesmo dia?”\nEsse problema surpreende todo mundo porque dependendo do valor de \\(n\\) pessoas, a probabilidade é bastante alta! Segundo veremos a probabilidade de isso ocorrer em uma turma de 23 pessoas ou mais escolhidas aleatoriamente é maior que 50%!\nQual aluno de qualquer turma de probabilidade que nunca foi desafiado numa aposta pelo professor que tinha dois alunos com mesma data de aniversário na sala de aula e se deu conta que perderia em poucos minutos?\nVamos resolver esse problema tanto pela abordagem clássica quanto pela abordagem frequentista, para utilizar a segunda abordagem dados de muitas turmas de variados tamanhos serão simulados utilizando o R e podemos comparar os resultados e buscar alguma evidência de que os dados se distribuem de forma semelhante!\nObs: Simular dados permitem imitar o funcionamento de, praticamente, qualquer tipo de operação ou processo (sistemas) do mundo real!\nProbabilidade Considerando o ano com 365 dias, podemos assumir que \\(n\u0026lt;365\\) primeiramente devemos definir o espaço amostral \\(\\Omega\\) que será o conjunto de todas as sequências formadas com as datas dos aniversários (associamos cada data a um dos 365 dias do ano), defini-se:\nexperimento: observar o aniversário de n pessoas\n\\[ \\Omega = \\{ (1,1,...,1),(1,2,53,...,201),(24,27,109,...,200),... \\} \\]\nportanto, sua cardinalidade será:\n\\[ \\#\\Omega = 365^n \\]\nDefinindo o evento:\n\\[ A = \\text{pelo meno 2 alunos fazendo aniversário no mesmo dia em uma turma de tamanho }n \\] Observa-se que é um evento complicado de se calcular. Uma prática muito comum na teoria das probabilidades nestes casos é estudar o complementar do evento de interesse, veja:\n\\[ A^c = \\text{nenhum dos alunos fazenndo aniversário no mesmo dia em uma turma de tamanho }n \\]\nAgora basta fazer a conta:\n\\[ P(A^c)=\\frac{\\#A^c}{\\#\\Omega}=\\frac{365 \\times 364 \\times ... \\times (365-n+1)}{365^n}=\\frac{365!}{365^n (365-n)!} \\]\nsegundo propriedades , se o evento é o complementar de todos n serem diferentes consequentemente o seguinte resultado é verdadeiro:\n\\[ p(A)=1- \\frac{365!}{365^n (365-n)!} \\]\nAgora que já sabemos a probabilidade de pelo menos duas pessoas fazerem aniversário no mesmo dia em uma turma de \\(n\\) alunos, vejamos o comportamento deste ajuste e uma tabela com possíveis valores de \\(n\\):\nEm R:\nUtilizando expansão em série de Taylor (mais informações):\nbirthday=function(x){ a=1-exp(-(x^2)/(2*365)) return(a) } birthday(23) ## [1] 0.5155095 n P 5 0.0336668 15 0.2652457 25 0.5752117 35 0.8132683 45 0.9375864 55 0.9841381 65 0.9969349 75 0.9995496 85 0.9999497 Em Python (função retirada do wikpédia para comparar os resultados):\ndef birthday(x): p = (1.0/365)**x for i in range((366-x),366): p *= i return 1-p print(\u0026quot;%1.7f\u0026quot; %(birthday(23))) #Arredondando para o mesmo numero de casas decimais default do R ## 0.5072972 Tanto a aproximação do R quanto a do Python obtiveram resultados semelhantes\nVejamos como é o comportamento da curva teórica e as estimações:\nNote que segundo a distribuição teórica, confirmamos que a probabilidade do evento ocorrer em uma turma de 23 pessoas ou mais escolhidas aleatoriamente é maior que 50%!\nSimulação Segundo o wikipédia, a simulação “consiste em empregar formalizações em computadores, como expressões matemáticas ou especificações mais ou menos formalizadas, com o propósito de imitar um processo ou operação do mundo real”\nNossa simulação irá consistir em imitar o comportamento de um processo do mundo real utilizando o seguinte código para simular o experimento de observar o aniversário de \\(n\\) pessoas milhares de vezes:\nN\u0026lt;- 5000 #Numero de simulacoes do experimento prob=0 for(n in 2:100){ #Para n variand de 2 até 50 cont_a=0 #Inicia o contador M=matrix(NA, N, n) #Delara uma matriz varia com as dimensoes desejadas for(i in 1:N){ #indice i que percorre todas as N linhas simuladas M[i,] = sample(1:365, n, replace = T) #Sorteio de uma amosra de tamanho n de numeros de 1 a 365 linha=M[i,] #objeto linha recebe a linha simulada tab=table(linha) #objeto tab guarda a tabela de frequencias dessa amostra if(length(tab)\u0026lt;n){ #se o tamanho da tabela de frequencias for menor que o tamanho da turma cont_a=cont_a+1 #contador recebe 1 pois duas pessoas fizeram aniversario no mesmo dia } } prob[n]=cont_a/N #a probabilidade será a proporcao de pessoas que fazem aniversario no mesmo dia observadas em N amostra simuladas } prob[23] ## [1] 0.5088 Notamos que o resultado observado é muito próximo do resultado calculado de acordo com a probabilidade teoria para a chance de se se encontrar pelo menos 2 pessoas que fazem aniversário em uma turma de 23 pessoas (novamente ultrapassou os 50%!!!)\nPara efeito de comparação visual com a resolução anterior:\nn P 5 5 0.0236 15 15 0.2470 25 25 0.5754 35 35 0.8172 45 45 0.9390 55 55 0.9862 65 65 0.9982 75 75 0.9996 85 85 1.0000 Comparando Por fim, vejamos de forma visual se o comportamento dos resultados simulados estão de acordo com o resultado teórico calculado:\nComo podemos ver o comportamento dos dados simulados foi muito similar ao da curva teórica calculada.\nModelagem e simulação em probabilidade Existe uma vasta gama de aplicações de simulações como em projetos de análises de sistemas de manufatura, avaliação de requisitos não funcionais de hardware e software, avaliação de novas armas e táticas militares, reposição de estoque, projeto de sistemas de transporte, avaliações de serviços, aplicações estatísticas de cadeias MCMC…\nUm simulador permite testar várias alternativas a um custo geralmente mais baixo do que no mundo real, possibilitando o melhor entendimento sobre o problema! Simulação e probabilidade são fundamentos da ciência de dados; para uma abordagem probabilística de modelagem, veja o post sobre ajuste de modelos pela abordagem bayesiana.\nEsse tipo de coincidência que parece impossível mas não é tão rara assim é meio que o assunto central do Iludidos pelo Acaso, do Taleb. Um livro que muda a forma como você olha pra \"sorte\" e \"talento\".\nPerguntas frequentes Por que bastam 23 pessoas para a chance passar de 50%? Porque o que importa não é o número de pessoas, e sim o número de pares possíveis, que cresce rápido. Com 23 pessoas há 253 pares (23 vezes 22 dividido por 2), e cada par é uma chance de coincidência. É essa explosão combinatória que engana a intuição.\nQual a diferença entre resolver por probabilidade e por simulação? A abordagem clássica usa a fórmula do evento complementar (todos com datas diferentes) para chegar à probabilidade exata. A simulação sorteia milhares de turmas aleatórias e conta a frequência de coincidências. Neste post, as duas convergem para o mesmo valor.\nO paradoxo dos aniversários tem aplicação prática? Sim. Ele é a base do \"birthday attack\" em criptografia: a mesma matemática das colisões de aniversário explica por que encontrar duas entradas com o mesmo hash é bem mais fácil do que a intuição sugere.\nReferências DeGroot, Morris H. \u0026amp; Schervish, Mark J. Probability and Statistics. 4ª ed. Feller, William. An Introduction to Probability Theory and Its Applications. Vol. 1. Magalhães, Marcos N. Probabilidade e Variáveis Aleatórias. Vol. 1. ","date":"20 de janeiro de 2018","externalUrl":null,"permalink":"/post/2018-01-20-simulacao-e-probabilidade/","section":"Posts","summary":" Curiosidades sobre a teoria das probabilidades TL;DR\nNum grupo de apenas 23 pessoas, a probabilidade de duas fazerem aniversário no mesmo dia já passa de 50%. O resultado é contraintuitivo; resolvemos de duas formas: analítica (abordagem clássica) e por simulação em R (abordagem frequentista). Uma simulação com 5000 turmas confirma a fórmula teórica. O uso de cálculo de probabilidades para avaliar incertezas já é utilizado a centenas de anos. Foram tantas áreas que se encontraram aplicações (como na medicina, jogos de azar, previsão do tempo…) que hoje não restam dúvidas de que os dados são onipresentes, ainda mais em plena era da informação.\n","title":"O paradoxo dos aniversários com simulação e probabilidade","type":"post"},{"content":"","date":"20 de janeiro de 2018","externalUrl":null,"permalink":"/tags/simulacao/","section":"Tags","summary":"","title":"Simulacao","type":"tags"},{"content":"","date":"20 de janeiro de 2018","externalUrl":null,"permalink":"/tags/teoria/","section":"Tags","summary":"","title":"Teoria","type":"tags"},{"content":" Importância da apresentação dos dados O trabalho de quem analisa dados vai muito além de planejar, resumir e interpretar observações: apresentar bem os resultados é parte essencial de qualquer projeto ou pesquisa. Não é à toa que já existe até uma área dentro da ciência de dados focada nisso, com o título de \"Data Artist\".\nAlém dos pacotes que ajudam a apresentar as figuras geradas nas análises (como mostrei nos posts sobre a qualidade do ajuste de modelos e sobre avaliar o ajuste pela abordagem bayesiana), contamos com pacotes que apresentam tabelas de forma elegante e até interativa.\nSeja escrevendo relatórios em \\(\\LaTeX\\), RMarkdown ou até um aplicativo Shiny, este post reúne algumas alternativas para deixar essas tabelas bonitas e informativas. Se você também cuida da formatação do documento em si, veja o post sobre o template Tufte no RMarkdown.\nTL;DR\nDT e rhandsontable: tabelas interativas, ótimas para HTML e Shiny. formattable e kableExtra: formatação condicional (cores, barras, ícones) em tabelas estáticas. sparkline: mini gráficos embutidos direto nas células. Pacote DT O pacote DT é uma excelente opção quando se trata de incluir tabelas de dados em relatórios Rmarkdown, o pacote esta hospedado neste link no github, veja a seguir um simples exemplo de uso:\n# install.packages(\u0026quot;DT\u0026quot;) #caso ainda nao tenha o pacote instalado DT::datatable(iris[1:20, c(5, 1:4)], rownames = FALSE) Com este link do manual no CRAN é possível entender melhor o funcionamento do pacote e conferir mais exemplos de uso.\nPacote formattable Este pacote é repleto de funcionalidades interessantes para a formatação dos resultados dispostos em tabelas, também está hospedado no github, podendo ser instalado pelo CRAN ou com os comandos:\n# Instalando pelo github # library(devtools) # devtools::install_github(\u0026quot;renkun-ken/formattable\u0026quot;) library(formattable) Com o pacote carregado vamos conferir algumas das funcionalidades básicas:\n#Exemplo de formatação para resultados de porcentagem: percent(c(0.1, 0.02, 0.03, 0.12)) ## [1] 10.00% 2.00% 3.00% 12.00% #Exemplo de formatação para resultados de na casa do milhar: accounting(c(1000, 500, 200, -150, 0, 1200)) ## [1] 1,000.00 500.00 200.00 (150.00) 0.00 1,200.00 Vamos criar um data.frame para ilustrar algumas das funcionalidades do pacote:\n#criando um data.frame df \u0026lt;- data.frame( id = 1:10, Nomes = c(\u0026quot;Sofia\u0026quot;, \u0026quot;Kiara\u0026quot;, \u0026quot;Dunki\u0026quot;, \u0026quot;Edgar\u0026quot;, \u0026quot;Emilia\u0026quot;,\u0026quot;Gertrudes\u0026quot;, \u0026quot;Genovena\u0026quot;, \u0026quot;Champanhe\u0026quot;, \u0026quot;Amora\u0026quot;, \u0026quot;Penelope\u0026quot;), Kilos = accounting(c(20000, 30000, 50000, 70000, 47000,80000,45000,35000,20000,25000), format = \u0026quot;d\u0026quot;), Crescimento = percent(c(0.1, 0.2, 0.5, 0.95, 0.97,0.45,0.62,0.57,0.37, 0.3), format = \u0026quot;d\u0026quot;), Suficiente = formattable(c(T, F, T, F, T,F,F,T,T,F), \u0026quot;Sim\u0026quot;, \u0026quot;Não\u0026quot;)) Com esses resultados, vejamos um exemplo de tabela que pode ser criada para apresentar esses resultados com o pacote:\nformattable(df, list( id = color_tile(\u0026quot;white\u0026quot;, \u0026quot;orange\u0026quot;), Suficiente = formatter(\u0026quot;span\u0026quot;, style = x ~ ifelse(x == T, style(color = \u0026quot;green\u0026quot;, font.weight = \u0026quot;bold\u0026quot;), NA)), area(col = c(Kilos)) ~ normalize_bar(\u0026quot;lightgrey\u0026quot;, 0.2), Crescimento = formatter(\u0026quot;span\u0026quot;, style = x ~ style(color = ifelse(rank(-x) \u0026lt;= 3, \u0026quot;green\u0026quot;, \u0026quot;gray\u0026quot;)), x ~ sprintf(\u0026quot;%.2f (rank: %02g)\u0026quot;, x, rank(-x))) )) id Nomes Kilos Crescimento Suficiente 1 Sofia 20,000 0.10 (rank: 10) Sim 2 Kiara 30,000 0.20 (rank: 09) Não 3 Dunki 50,000 0.50 (rank: 05) Sim 4 Edgar 70,000 0.95 (rank: 02) Não 5 Emilia 47,000 0.97 (rank: 01) Sim 6 Gertrudes 80,000 0.45 (rank: 06) Não 7 Genovena 45,000 0.62 (rank: 03) Não 8 Champanhe 35,000 0.57 (rank: 04) Sim 9 Amora 20,000 0.37 (rank: 07) Sim 10 Penelope 25,000 0.30 (rank: 08) Não Para entender melhor o funcionamento do pacote e conferir mais exemplo de uso confira o manual de introdução ao pacote e manual do pacote, ambos disponíveis no CRAN.\nO pacote knitr e kabbleExtra O pacote knitr permite o uso da função kable() que produz tabelas parecidas com as apresentadas com o pacote DT, porém trás diversas outras funcionalidades que podem ser combinadas com as funcionalidades de outros pacotes, como o kableExtra e até mesmo o formattable apresentado acima.\nOs exemplos aqui apresentados foram retirados (sem alterações) do manual do pacote no CRAN\n#Carregando pacotes library(knitr) library(kableExtra) #Carregando pacote para ajudar na manipulação dos dados: library(dplyr) mtcars[1:10, 1:2] %\u0026gt;% mutate( car = row.names(.), # Você não precisa de formato = \u0026quot;html\u0026quot; se você já definiu opções (knitr.table.format) mpg = cell_spec(mpg, \u0026quot;html\u0026quot;, color = ifelse(mpg \u0026gt; 20, \u0026quot;red\u0026quot;, \u0026quot;blue\u0026quot;)), cyl = cell_spec(cyl, \u0026quot;html\u0026quot;, color = \u0026quot;white\u0026quot;, align = \u0026quot;c\u0026quot;, angle = 45, background = factor(cyl, c(4, 6, 8), c(\u0026quot;#666666\u0026quot;, \u0026quot;#999999\u0026quot;, \u0026quot;#BBBBBB\u0026quot;)))) %\u0026gt;% select(car, mpg, cyl) %\u0026gt;% kable(\u0026quot;html\u0026quot;, escape = F) %\u0026gt;% kable_styling(\u0026quot;striped\u0026quot;, full_width = F) car mpg cyl Mazda RX4 21 6 Mazda RX4 Wag 21 6 Datsun 710 22.8 4 Hornet 4 Drive 21.4 6 Hornet Sportabout 18.7 8 Valiant 18.1 6 Duster 360 14.3 8 Merc 240D 24.4 4 Merc 230 22.8 4 Merc 280 19.2 6 #Outro exemplo colorido legal: iris[1:10, ] %\u0026gt;% mutate_if(is.numeric, function(x) { cell_spec(x, \u0026quot;html\u0026quot;, bold = T, color = spec_color(x, end = 0.9), font_size = spec_font_size(x)) }) %\u0026gt;% mutate(Species = cell_spec( Species, \u0026quot;html\u0026quot;, color = \u0026quot;white\u0026quot;, bold = T, background = spec_color(1:10, end = 0.9, option = \u0026quot;A\u0026quot;, direction = -1) )) %\u0026gt;% kable(\u0026quot;html\u0026quot;, escape = F, align = \u0026quot;c\u0026quot;) %\u0026gt;% kable_styling(\u0026quot;striped\u0026quot;, full_width = F) Sepal.Length Sepal.Width Petal.Length Petal.Width Species 5.1 3.5 1.4 0.2 setosa 4.9 3 1.4 0.2 setosa 4.7 3.2 1.3 0.2 setosa 4.6 3.1 1.5 0.2 setosa 5 3.6 1.4 0.2 setosa 5.4 3.9 1.7 0.4 setosa 4.6 3.4 1.4 0.3 setosa 5 3.4 1.5 0.2 setosa 4.4 2.9 1.4 0.2 setosa 4.9 3.1 1.5 0.1 setosa Mais um exemplo, dessa vez integrando com o pacote formattable:\n#Integrando com formattable suppressMessages(library(formattable)) mtcars[1:5, 1:4] %\u0026gt;% mutate( car = row.names(.), mpg = color_tile(\u0026quot;white\u0026quot;, \u0026quot;orange\u0026quot;)(mpg), cyl = cell_spec(cyl, \u0026quot;html\u0026quot;, angle = (1:5)*60, background = \u0026quot;red\u0026quot;, color = \u0026quot;white\u0026quot;, align = \u0026quot;center\u0026quot;), disp = ifelse(disp \u0026gt; 200, cell_spec(disp, \u0026quot;html\u0026quot;, color = \u0026quot;red\u0026quot;, bold = T), cell_spec(disp, \u0026quot;html\u0026quot;, color = \u0026quot;green\u0026quot;, italic = T)), hp = color_bar(\u0026quot;lightgreen\u0026quot;)(hp) ) %\u0026gt;% select(car, everything()) %\u0026gt;% kable(\u0026quot;html\u0026quot;, escape = F) %\u0026gt;% kable_styling(\u0026quot;hover\u0026quot;, full_width = F) %\u0026gt;% column_spec(5, width = \u0026quot;3cm\u0026quot;) %\u0026gt;% add_header_above(c(\u0026quot; \u0026quot;, \u0026quot;Hello\u0026quot; = 2, \u0026quot;World\u0026quot; = 2)) Hello World car mpg cyl disp hp Mazda RX4 21.0 6 160 110 Mazda RX4 Wag 21.0 6 160 110 Datsun 710 22.8 4 108 93 Hornet 4 Drive 21.4 6 258 110 Hornet Sportabout 18.7 8 360 175 O pacote sparkline O sparkline é um pacote ótimo para enriquecer as apresentações de forma que possibilita incluir “mini gráficos” como boxplots, gráfico de linhas ou barras diretamente nas tabelas, como se fosse uma coluna do data.frame!\nSeu funcionamento é bem simples e poderoso, apresento aqui alguns exemplo de uso, caso queira conferir mais detalhes, pode conferir o manual do pacote no CRAN ou esta página.\n# library(devtools) # install_github(\u0026#39;htmlwidgets/sparkline\u0026#39;) #Carregando o pacote: library(htmlwidgets) library(sparkline) #Exemplos de uso: x = rnorm(20) sparkline(x) sparkline(x, type = \u0026#39;bar\u0026#39;) sparkline(x, type = \u0026#39;box\u0026#39;) Exemplo de tabela para rmarkdown, a partir dessa sequência de códigos markdown e R:\n#Seja: set.seed(1234) x = rnorm(10) y = rnorm(10) #Ao digitar isso: | Var. | Sparkline | Boxplot | Bar |-------|-------------------|-------------------------------|------------------------------ | x | `r sparkline(x)` | `r sparkline(x, type =\u0026#39;box\u0026#39;)` |`r sparkline(x, type = \u0026#39;bar\u0026#39;)` | y | `r sparkline(y)` | `r sparkline(y, type =\u0026#39;box\u0026#39;)` |`r sparkline(y, type = \u0026#39;bar\u0026#39;)` Exibe isso:\nO pacote rhandsontable Mais um pacote repleto de funcionalidades que permitem a implementação de tabelas elegantes para a apresentação de projetos e pesquisas. Por se tratar de um htmlwidgets, este pacote em especial é uma boa opção quando deseja-se apresentar tabela sem documentos no formato html ou com aplicativos shiny por exemplo.\nPrimeiramente apresentarei aqui primeiramente um exemplo com tabela de correlações utilizando formatação condicional:\n#Carregando o pacote: library(rhandsontable) #Tabela para correlações rhandsontable(cor(iris[,-5]), readOnly = TRUE, width = 750, height = 300) %\u0026gt;% hot_cols(renderer = \u0026quot; function (instance, td, row, col, prop, value, cellProperties) { Handsontable.renderers.TextRenderer.apply(this, arguments); if (row == col) { td.style.background = \u0026#39;lightgrey\u0026#39;; } else if (col \u0026gt; row) { td.style.background = \u0026#39;grey\u0026#39;; td.style.color = \u0026#39;grey\u0026#39;; } else if (value \u0026lt; -0.75) { td.style.background = \u0026#39;pink\u0026#39;; } else if (value \u0026gt; 0.75) { td.style.background = \u0026#39;lightgreen\u0026#39;; } }\u0026quot;) Como este pacote possui muitas funcionalidades, apresentarei mais três exemplos baseados nas instruções do pacote e caso queira entender melhor o funcionamento e obter mais exemplos, consultar o manual no CRAN\n#Tabela com mini gráficos #criando um data.frame df \u0026lt;- data.frame( id = 1:10, Nomes = c(\u0026quot;Sofia\u0026quot;, \u0026quot;Kiara\u0026quot;, \u0026quot;Dunki\u0026quot;, \u0026quot;Edgar\u0026quot;, \u0026quot;Aline\u0026quot;,\u0026quot;Gertrudes\u0026quot;, \u0026quot;Genovena\u0026quot;, \u0026quot;Champanhe\u0026quot;, \u0026quot;Pérola\u0026quot;, \u0026quot;Penelope\u0026quot;), Kilos = accounting(c(20000, 30000, 50000, 70000, 47000,80000,45000,35000,20000,25000), format = \u0026quot;d\u0026quot;), Crescimento = percent(c(0.1, 0.2, 0.5, 0.95, 0.97,0.45,0.62,0.57,0.37, 0.3), format = \u0026quot;d\u0026quot;), Suficiente = c(T, F, T, F, T,F,F,T,T,F)) #E os gráficos de barra: df$chart = c(sapply(1:5, function(x) jsonlite::toJSON(list(values=rnorm(10,10,10), options = list(type = \u0026quot;bar\u0026quot;)))), sapply(1:5, function(x) jsonlite::toJSON(list(values=rnorm(10,10,10), options = list(type = \u0026quot;line\u0026quot;))))) rhandsontable(df, rowHeaders = NULL, width = 550, height = 300) %\u0026gt;% hot_col(\u0026quot;chart\u0026quot;, renderer = htmlwidgets::JS(\u0026quot;renderSparkline\u0026quot;)) Também podemos incluir comentários em células específicas da tabela utilizando este pacote, veja:\n(Para ver os comentários basta passar o mouse sobre a célula com a marcação vermelha na borda)\n#Incluindo comentarios: comments = matrix(ncol = ncol(df), nrow = nrow(df)) comments[1, 1] = \u0026quot;Exemplo de comentário\u0026quot; comments[2, 2] = \u0026quot;Outro exemplo de comentario\u0026quot; rhandsontable(df, comments = comments, width = 550, height = 300)%\u0026gt;% hot_col(\u0026quot;chart\u0026quot;, renderer = htmlwidgets::JS(\u0026quot;renderSparkline\u0026quot;)) Caso a tabela dos dados seja muito grande, também podemos utilizar o pacote para gerar a tabela com a barra de rolar\n#Tabela com barra de rolar para grande base de dados rhandsontable(mtcars, rowHeaderWidth = 200, width = 700, height = 550) Relatórios muito mais bonitos Com essas lindas tabelas seus relatórios serão irresistíveis, até quem não entende de estatística vai passar a gostar depois de ver tanta beleza com números! Espero que tenha gostado do conteúdo, caso queira acrescentar ou reportar algo basta entrar em contato.\nSe quiser conferir outros posts que passaram por aqui ao longo do ano, dá uma olhada na retrospectiva anual do blog.\nPerguntas frequentes Qual pacote usar para tabelas interativas no R? Para tabelas interativas, o DT é a opção mais direta em relatórios HTML e o rhandsontable é ótimo quando você quer células editáveis, comentários ou uso em aplicativos Shiny. Ambos geram tabelas navegáveis sem que você precise escrever JavaScript.\nComo adicionar cores ou barras nas células de uma tabela? Use o formattable ou o kableExtra. Eles permitem formatação condicional: pintar o fundo por valor, colorir o texto, adicionar barras proporcionais e ícones. É o caminho para tabelas estáticas em PDF ou HTML com destaque visual nos números que importam.\nDá para colocar gráficos dentro de uma tabela? Sim. O pacote sparkline insere mini gráficos (linha, barra ou boxplot) direto nas células, como se fossem uma coluna do data.frame. É uma forma compacta de mostrar tendência ou distribuição sem ocupar espaço com um gráfico separado.\n","date":"12 de janeiro de 2018","externalUrl":null,"permalink":"/post/2018-01-12-tabelas-incriveis-com-r/","section":"Posts","summary":" Importância da apresentação dos dados O trabalho de quem analisa dados vai muito além de planejar, resumir e interpretar observações: apresentar bem os resultados é parte essencial de qualquer projeto ou pesquisa. Não é à toa que já existe até uma área dentro da ciência de dados focada nisso, com o título de \"Data Artist\".\nAlém dos pacotes que ajudam a apresentar as figuras geradas nas análises (como mostrei nos posts sobre a qualidade do ajuste de modelos e sobre avaliar o ajuste pela abordagem bayesiana), contamos com pacotes que apresentam tabelas de forma elegante e até interativa.\n","title":"Tabelas Incríveis com R","type":"post"},{"content":" Análise Multivariada Esse é o primeiro post do ano e como no ano de 2017 falou-se tanto das maravilhas computacionais desta onda do Big Data e em contra partida, identificamos que deste 2004 a popularidade pelo termo “estatística” vem diminuindo como mostrei em uma breve pesquisa neste post sobre a API do googletrends sinto que existe uma necessidade de se ampliar também a divulgação dos métodos estatísticos pois o aprofundamento na teoria é fundamental (é muito fácil achar resultados sem fundamento apenas “apertando botão”), como as ferramentas da estatística multivariada que muitas vezes servem como soluções para essas grandes quantidades de dados\nDiversas vezes nos deparamos com bases de dados que envolvem além de muitas observações, muitas variáveis, especialmente nas análises de fenômenos ou processos sociais, psicológicos, educacionais e econômicos bem como na área da química, biologia, geologia, marketing, medicina, medicina veterinária, dentre muitas outras.\nCom as ferramentas estatísticas da análise multivariada somos capazes de identificar muitos elementos que podem ter relevância na análise dos dados, dois exemplos de ferramentas importantes são as que permitem encontrar fatores que não são diretamente observáveis com base em um conjunto de variáveis observáveis e as que permitem agrupar conjuntos de dados que possuem características semelhantes com algorítimos computacionais (chamados de aprendizados não-supervisionados ou semi-supervisionados em machine learning) e a partir dai estudar as novas classificações.\nNeste post será apresentado algumas soluções para o caso em que existe a necessidade de avaliar um grande conjunto de dados com muitas variáveis e não temos muitas informações a respeito.\nTL;DR\nA análise fatorial identifica fatores não observáveis que explicam a correlação entre um conjunto de variáveis, usando testes como Bartlett e KMO para validar a matriz de correlação. A análise de componentes principais (PCA) resume a variabilidade dos dados em componentes não correlacionados, visualizados com biplot e scree-plot. Os métodos de clustering hierárquico e K-means agrupam observações semelhantes, validados por medidas como silhueta, índice de Dunn e conectividade. Se você está chegando agora na área, pode valer a pena começar por uma visão geral da ciência de dados e depois voltar aqui para se aprofundar na parte multivariada.\nAnálise Fatorial Na análise fatorial buscamos fatores que explicam parte da variância total dos dados, os fatores são as somas das variâncias originais.\nObjetivo da análise fatorial: Procura identificar fatores que não são diretamente observáveis, com base em um conjunto de variáveis observáveis.\nExplicar a correlação ou covariância, entre um conjunto de variáveis, em termos de um número limitado de variáveis não-observáveis, chamadas de fatores ou variáveis latentes.\nEm casos nos quais se tem um número grande de variáveis medidas e correlacionadas entre si, seria possível identificar-se um número menor de variáveis alternativas, não correlacionadas e que de algum modo sumarizassem as informações principais das variáveis originais.\nA partir do momento em que os fatores são identificados, seus valores numéricos, chamados de escores, podem ser obtidos para cada elemento amostral. Conseqüentemente, estes escores podem ser utilizados em outras análises que envolvam outras técnicas estatísticas, como análise de regressão ou análise de variância, por exemplo.\nEtapas para realização Computação da matriz de correlações para as variáveis originais;\nExtração de fatores\nRotação dos fatores para tonar a interpretação mais fácil;\nCálculo dos escores dos fatores\nMatriz de Correlação: Teste de Bartlett - a hipótese nula da matriz de correlação ser uma matriz identidade ( \\(| R | = 1\\) ), isto é, avalia se os componentes fora da diagonal principal são zero. O resultado significativo indica que existem algumas relações entre as variáveis. No R:\nBartlett.sphericity.test \u0026lt;- function(x) { method \u0026lt;- \u0026quot;Teste de esfericidade de Bartlett\u0026quot; data.name \u0026lt;- deparse(substitute(x)) x \u0026lt;- subset(x, complete.cases(x)) # Omitindo valores faltantes n \u0026lt;- nrow(x) p \u0026lt;- ncol(x) chisq \u0026lt;- (1-n+(2*p+5)/6)*log(det(cor(x))) df \u0026lt;- p*(p-1)/2 p.value \u0026lt;- pchisq(chisq, df, lower.tail=FALSE) names(chisq) \u0026lt;- \u0026quot;X-squared\u0026quot; names(df) \u0026lt;- \u0026quot;df\u0026quot; return(structure(list(statistic=chisq, parameter=df, p.value=p.value, method=method, data.name=data.name), class=\u0026quot;htest\u0026quot;)) } Bartlett.sphericity.test(dados) ## ## Teste de esfericidade de Bartlett ## ## data: dados ## X-squared = 2590.3, df = 55, p-value \u0026lt; 2.2e-16 Teste KMO (Kaiser-Meyer-Olkin) - avalia a adequação do tamanho amostra. Varia entre 0 e 1, onde: zero indica inadequado para análise fatorial, aceitável se for maior que 0.5, recomendado acima de 0.8. No R:\nkmo = function(x) { x = subset(x, complete.cases(x)) r = cor(x) r2 = r^2 i = solve(r) d = diag(i) p2 = (-i/sqrt(outer(d, d)))^2 diag(r2) \u0026lt;- diag(p2) \u0026lt;- 0 KMO = sum(r2)/(sum(r2)+sum(p2)) MSA = colSums(r2)/(colSums(r2)+colSums(p2)) return(list(KMO=KMO, MSA=MSA)) } kmo(dados) ## $KMO ## [1] 0.5942236 ## ## $MSA ## A B C D E F G H ## 0.6789278 0.9151657 0.6897541 0.3385536 0.8699746 0.3632508 0.5172135 0.4878681 ## I J K ## 0.4901580 0.4895023 0.4686937 Tipos de correlação: Nem sempre é possível utilizar a correlação de pearson, porém, existem diversas outras maneiras de se saber qual a correlação dos dados. Podemos utilizar correlações como de Spearman, Policórica, etc.. Já fiz um post onde explico os diferentes tipos de relações entre os tipos de variáveis e os tipos de correlações possíveis para avaliar a relação dessas variáveis.\nAqui um outro exemplo de como utilizar a correlação parcial\npartial.cor \u0026lt;- function (x) { R \u0026lt;- cor(x) RI \u0026lt;- solve(R) D \u0026lt;- 1/sqrt(diag(RI)) Rp \u0026lt;- -RI * (D %o% D) diag(Rp) \u0026lt;- 0 rownames(Rp) \u0026lt;- colnames(Rp) \u0026lt;- colnames(x) Rp } mat_anti_imagem \u0026lt;- -partial.cor(dados[,1:10]) mat_anti_imagem ## A B C D E F ## A 0.000000000 -0.25871349 -0.872167400 0.01668860 -0.04245837 -0.011036934 ## B -0.258713494 0.00000000 -0.204228090 0.05621580 0.09801359 0.060189694 ## C -0.872167400 -0.20422809 0.000000000 -0.02459342 -0.00482831 -0.008201211 ## D 0.016688604 0.05621580 -0.024593418 0.00000000 -0.18602037 0.806258927 ## E -0.042458373 0.09801359 -0.004828310 -0.18602037 0.00000000 -0.140784264 ## F -0.011036934 0.06018969 -0.008201211 0.80625893 -0.14078426 0.000000000 ## G 0.006994874 -0.12746560 0.045529480 -0.75073120 -0.32160010 -0.792991683 ## H -0.071792191 0.03375700 0.059785980 -0.03196914 0.08903510 0.001496987 ## I 0.055698412 -0.03720345 -0.040061304 0.08243832 -0.03925037 0.084673934 ## J -0.042609593 0.06775755 0.004145341 -0.06024239 0.05806892 -0.001404078 ## G H I J ## A 0.006994874 -0.071792191 0.05569841 -0.042609593 ## B -0.127465596 0.033756995 -0.03720345 0.067757550 ## C 0.045529480 0.059785980 -0.04006130 0.004145341 ## D -0.750731196 -0.031969142 0.08243832 -0.060242391 ## E -0.321600101 0.089035097 -0.03925037 0.058068923 ## F -0.792991683 0.001496987 0.08467393 -0.001404078 ## G 0.000000000 -0.025016441 -0.05943429 0.009961615 ## H -0.025016441 0.000000000 -0.55229599 0.044929237 ## I -0.059434295 -0.552295987 0.00000000 0.056248550 ## J 0.009961615 0.044929237 0.05624855 0.000000000 Extração de fatores via componentes principais Determinado o número de fatores necessários para representar os dados\nTambém é determinado o método que será utilizado, o mais utilizado é a análise de componentes principais\nEstimação do número de fatores m Estimação do número de fatores m\nPara a estimação de m, bastará extrair-se os autovalores da matriz de correlação amostral.\nObserva-se quais autovalores são os mais importantes em termos de grandeza numérica.\nos autovalores refletem a importância do fator se o número de fatores for igual ao número de variáveis então a soma dos autovetores é igual a soma das variâncias (pois cada variância será igual a 1).\nPortanto a razão $ / 2 var $ indica proporção da variabilidade total explicada pelo fator\nCritérios:\nA análise da proporção da variância total relacionada com cada autovalor (\\(\\lambda_i\\)). Permanecem aqueles autovalores que maiores proporções da variância total e, portanto, o valor de m será igual ao número de autovalores retidos;\nA comparação do valor numérico de (\\(\\lambda_i\\)) com o valor 1. O valor de m será igual ao número de autovalores maiores ou iguais a 1.\nObservação do gráfico scree-plot, que dispõe os valores de (\\(\\lambda_i\\)) ordenados em ordem decrescente. Por este critério, procura-se no gráfico um “ponto de salto”, que estaria representando um decréscimo de importância em relação à variância total. O valor de m seria então igual ao número de autovalores anteriores ao “ponto de salto”.\nAnálise de componentes Principais: Fatores são obtidos através da decomposição espectral da matriz de correlações, resultado em cargas fatoriais que indicam o quanto cada variável está associada a cada fator e os autovalores associados a cada um dos fatores envolvidos\nSão formadas combinações lineares das variáveis observadas.\nO primeiro componente principal consiste na combinação que responde pela maior quantidade de variância na amostra.\nO segundo componente responde pela segunda maior variância na amostra e não é correlacionado com o primeiro componente.\nSucessivos componentes explicam progressivamente menores porções de variância total da amostra e todos são não correlacionados uns aos outros.\nNo R a análise de componentes principais pode ser realizada com as funções nativas prcomp() e a visualização pode ser realizada com a função biplot nativa do R ou com a função autoplot() do pacote ggfortify apresentado em um posto que eu comento sobre ajustes de modelos lineares.\nNeste exemplo utilizaremos as funções de código aberto encontrei nesse github que permite elaborar o gráfico baseado em funções do ggplot, além disso também carregaremos o pacote deste Github. Veja:\nSe quiser aprofundar em PCA e clustering com mais rigor estatístico, o An Introduction to Statistical Learning (na versão em R) explica bem o porquê matemático por trás dessas técnicas, não só o \"como fazer\".\nlibrary(ggplot2) library(ggfortify) library(ggbiplot) #Componentes principais: acpcor=prcomp(dados, scale = TRUE) summary(acpcor) ## Importance of components: ## PC1 PC2 PC3 PC4 PC5 PC6 PC7 ## Standard deviation 1.7205 1.5835 1.2745 1.2107 1.02156 0.72100 0.6634 ## Proportion of Variance 0.2691 0.2280 0.1477 0.1333 0.09487 0.04726 0.0400 ## Cumulative Proportion 0.2691 0.4971 0.6447 0.7780 0.87285 0.92011 0.9601 ## PC8 PC9 PC10 PC11 ## Standard deviation 0.4953 0.33061 0.25079 0.14588 ## Proportion of Variance 0.0223 0.00994 0.00572 0.00193 ## Cumulative Proportion 0.9824 0.99235 0.99807 1.00000 ggbiplot(acpcor, obs.scale = 1, var.scale = 1, ellipse = TRUE, circle = TRUE) + scale_color_discrete(name = \u0026#39;\u0026#39;) + theme(legend.direction = \u0026#39;horizontal\u0026#39;, legend.position = \u0026#39;top\u0026#39;) # autoplot(acpcor, label = TRUE, label.size = 1, # loadings = TRUE, loadings.label = TRUE, loadings.label.size = 3) Para a observação do gráfico scree-plot podemos utilizar os comandos a seguir (com funções nativas do R ou mesmo com funções personalizadas como a que eu acabei de comentar disponivel nesse github\n#Com Funcao nativa do R: # plot(1:ncol(dados), acpcor$sdev^2, type = \u0026quot;b\u0026quot;, xlab = \u0026quot;Componente\u0026quot;, # ylab = \u0026quot;Variância\u0026quot;, pch = 20, cex.axis = 1.3, cex.lab = 1.3) #Ou funcao personalizada com ggplot2: ggscreeplot(acpcor) Rotação Algumas variáveis são mais correlacionadas com alguns fatores do que outras.\nEm alguns casos, a interpretação dos fatores originais pode não ser tarefa muito fácil devido à aparição de coeficientes de grandeza numérica similar, e não desprezível, em vários fatores diferentes.\nO propósito da rotação é obter uma estrutura simples.\nEm uma estrutura simples, cada fator tem carga alta somente para algumas variáveis, tornando mais fácil a sua identificação.\nTipos: Varimax, Quartimax, Equamax\nAplicando a Varimax:\nk \u0026lt;- 6 #6 fatores selecionados carfat = acpcor$rotation[, 1:k] %*% diag(acpcor$sdev[1:k]) carfatr = varimax(carfat) Comunalidade Índices atribuídos a variável original que expressam em % o quanto da variabilidade de cada variável é explicada pelo modelo\nDesigna-se por comunalidade (\\(h^{2}_i\\))a proporção da variância de cada variável explicada pelos fatores comuns.\nAs comunalidades variam entre 0 e 1, sendo 0 quando os fatores comuns não explicam nenhuma variância da variável e 1 quando explicam toda a sua variância.\nQuando o valor das comunalidades é menor que 0,6 deve-se pensar em: aumentar a amostra, eliminar as variáveis.\nInterpretar o modelo Feito pelas cargas fatoriais que são os parâmetros do modelo\nFatores expressam as covariâncias entre cada fator e as variáveis originais\nVarimax ajuda a interpretar o modelo\nRotações ortogonais (para dependente) ; Rotações oblíquas (para independentes)\nClusters Técnica estatística multivariada que tem como objetivo organizar um conjunto de objetos em um determinado nº de subconjuntos mutuamente exclusivos (clusters), de tal forma que os objetos em um mesmo cluster sejam semelhantes entre si,porém diferentes dos objetos nos outros clusters\nEtapas para análise de clusters, que são comuns em qualquer análise (KDD):\nSeleção dos objetos a serem agrupados Definir conjunto de atributos que caracterizam os objetos Medida de dissimilaridade Seleção de um algoritmo de agregação Definição do número de clusters Interpretação e validação dos clusters Critérios para a seleção:\nSelecionar variáveis diferentes entre si Variáveis padronizadas (padronização mais comum é a Z-score) Existem algumas abordagens para a utilização das técnicas de análises de clusters, as diferenças entre os métodos hierárquicos e os não hierárquicos são as seguintes:\nMétodos Hierárquicos são preferidos quando:\nSerão analisadas varias alternativas de agrupamento. O tamanho da amostra é moderado ( de 300 a 1000 objetos ) Métodos não-hierárquicos são preferidos quando:\nO número de grupos é conhecido. Presença dos outliers, desde que os métodos não-hierárquicos são menos influenciados por outliers. Há um grande nº de objetos a serem agrupados. Método hierárquico de agrupamento É realizado em dois passos, o primeiro deles calcula-se a matriz de similaridade com o uso da função dist() (existem diversos tipos de distâncias que podem ser utilizadas aqui), o método utilizado será o de Ward (também poderíamos escolher o método da menor distância, maior distância ou a distância média).\nVantagens:\nRápidos e exigem menos tempo de processamento. Apresentam resultados para diferentes níveis de agregação. Desvantagens:\nAlocação de um objeto em um cluster é irrevogável Impacto substancial dos outliers ( apesar do Ward ser o menos susceptível) Não apropriados para analisar uma amostra muito extensa, pois a medida que o tamanho da amostra aumenta, a necessidade de armazenamento das distâncias cresce drasticamente Para bases grandes é melhor não usar este método pois precisa da matriz de distâncias.\nDentre os métodos, a menor distância pode ser ruim em muitas situações, pois coloca muitos objetos no mesmo cluster.\nGeralmente utiliza-se o dendograma para a visualização dos clusters.\n#Construindo a matriz de similaridade: matriz_similaridade = dist(iris[,-5], #Conjunto de dados utilizados \u0026quot;euclidean\u0026quot; #medida de distância utilizada ) #Construindo o agrupamento hierárquico aglomerativo: agrupamento = hclust(matriz_similaridade, #Matriz de similaridade calculada \u0026quot;ward.D\u0026quot; #Método de agrupamento ) #Converte hclust em dendrograma e plot: hcd \u0026lt;- as.dendrogram(agrupamento) library(ggdendro) # Tipo pode ser \u0026quot;rectangle\u0026quot; ou \u0026quot;triangle\u0026quot; dend_data \u0026lt;- dendro_data(hcd, type = \u0026quot;rectangle\u0026quot;) # o que esta contido em dend_data: names(dend_data) ## [1] \u0026quot;segments\u0026quot; \u0026quot;labels\u0026quot; \u0026quot;leaf_labels\u0026quot; \u0026quot;class\u0026quot; plot(agrupamento,xlab=\u0026quot;Matriz de similaridade\u0026quot;,main = \u0026quot;Dendograma\u0026quot;, cex = 0.3) #Construindo representacao de grupos - geração de vetores: grupos = cutree(agrupamento, #Variável calculada em hclust 3 #Quantidade de grupos desejados ) #Construindo o dendograma: rect.hclust(agrupamento, k=3, border=\u0026quot;red\u0026quot;) Existem diversas outras maneiras de se visualizar dendogramas, veja a seguir um outro exemplo utilizando o pacote ape:\nlibrary(ape) plot(as.phylo(agrupamento), type = \u0026quot;unrooted\u0026quot;, cex = 0.6, no.margin = TRUE) Para mais informações de métodos de plot de dendogramas,talvez essa página possa ser útil.\nMétodo não hierárquico de agrupamento K-means Esta é uma das mais populares abordagens de agrupamento de dados por partição. A partir de uma escolha inicial para os centroides, o algoritmo procede verificando quais exemplares são mais similares a quais centroides.\nVantagens:\nTendem a maximizar a dispersão entre os centros de gravidade dos clusters (mantem os clusters bem separados) Simplicidade de cálculo, calcula somente as distâncias entre os objetos e os centros de gravidade dos clusters Desvantagens:\nDepende dos conjuntos de sementes iniciais, principalmente se a seleção das sementes é aleatória Não há garantias de um agrupamento ótimo dos objetos #Construindo o agrupamento por particionamento: c = kmeans(iris[,-5], #Conjunto de dados utilizados 2, #Número de grupos a ser descoberto iter.max=5 #Número máximo de iterações permitido no algorítmo ) Para efeito de visualização, podemos utilizar a seguinte função que encontra dois fatores principais a partir da análise fatorial e às utiliza como eixos\nplot_kmeans = function(df, clusters, runs) { suppressMessages(library(psych)) suppressMessages(library(ggplot2)) #cluster tmp_k = kmeans(df, centers = clusters, nstart = 100) #factor tmp_f = fa(df, 2, rotate = \u0026quot;none\u0026quot;) #collect data tmp_d = data.frame(matrix(ncol=0, nrow=nrow(df))) tmp_d$cluster = as.factor(tmp_k$cluster) tmp_d$fact_1 = as.numeric(tmp_f$scores[, 1]) tmp_d$fact_2 = as.numeric(tmp_f$scores[, 2]) tmp_d$label = rownames(df) #plot g = ggplot(tmp_d, aes(fact_1, fact_2, color = cluster)) + geom_point() + geom_text(aes(label = label), size = 3, vjust = 1, color = \u0026quot;black\u0026quot;) return(g) } plot_kmeans(iris[,-5], 3) Análise exploratória dos clusters Não vou me estender nessa parte, mas é bom esclarecer que após encontrar os clusters e de extrema importância realizar a análise exploratória deles para entender os comportamentos dos grupos identificados.\n#Conferindo os grupos formados: c$cluster%\u0026gt;% table() ## . ## 1 2 ## 53 97 c$cluster%\u0026gt;% table()%\u0026gt;% barplot(main=\u0026quot;Frequências dos clusters\u0026quot;, names.arg=c(\u0026quot;Cluster 1\u0026quot;, \u0026quot;Cluster 2\u0026quot;)) Medidas de validação e estabilidade pseudo-F O número adequado de clusters (k) deve ser maximizar o pseudo-F:\n\\[ pseudo-F = \\dfrac{ \\dfrac{BSS}{k-1} } { \\dfrac{WSS}{N-k}} =\\dfrac{\\textrm{Quadrado médio entre clusters}}{\\textrm{Quadrado médio dentro dos clusters}} \\]\nlibrary(clvalid) Este pacote faz os cálculos das medidas que avaliam se os clusters são compactos, bem separados e estáveis.\nVejamos os tipos de medidas:\nMedidas de validação:\nconectividade: relativa ao grau de vizinhança entre objetos em um mesmo cluster, varia entre 0 e infinito e quanto menor melhor. silhueta: homogeneidade interna, assume valores entre -1 e 1 e quanto mais próximo de 1 melhor. índice de Dunn: quantifica a separação entre os agrupamentos, assume valores entre 0 e 1 e quanto maior melhor. Medidas de estabilidade:\nAPN - average proportion of non-overlap: proporção média de observações não classificadas no mesmo cluster nos casos com dados completos e incompletos. Assume valor no intervalo [0,1], próximos de 0 indicam agrupamentos consistentes. AD - average distance: distância média entre observações classificadas no mesmo cluster nos casos com dados completos e incompletos. Assume valores não negativos, sendo preferíveis valores próximos de zero. ADM - average distance between means: distância média entre os centroides quando as observações estão em um mesmo cluster. Assume valores não negativos, sendo preferíveis valores próximos de zero. FOM - figure of merit: medida do erro cometido ao usar os centroides como estimativas das observações na coluna removida. Assume valores não negativos, sendo preferíveis valores próximos de zero. library(clValid) #Medidas de validação: valida=clValid(iris[1:4],3,clMethods=c(\u0026quot;hierarchical\u0026quot;,\u0026quot;kmeans\u0026quot;),validation=\u0026quot;internal\u0026quot;) summary(valida) ## ## Clustering Methods: ## hierarchical kmeans ## ## Cluster sizes: ## 3 ## ## Validation Measures: ## 3 ## ## hierarchical Connectivity 4.4770 ## Dunn 0.1378 ## Silhouette 0.5542 ## kmeans Connectivity 10.0917 ## Dunn 0.0988 ## Silhouette 0.5528 ## ## Optimal Scores: ## ## Score Method Clusters ## Connectivity 4.4770 hierarchical 3 ## Dunn 0.1378 hierarchical 3 ## Silhouette 0.5542 hierarchical 3 #Medidas de estabilidade; valida=clValid(iris[1:4],3,clMethods=c(\u0026quot;hierarchical\u0026quot;,\u0026quot;kmeans\u0026quot;),validation=\u0026quot;stability\u0026quot;) summary(valida) ## ## Clustering Methods: ## hierarchical kmeans ## ## Cluster sizes: ## 3 ## ## Validation Measures: ## 3 ## ## hierarchical APN 0.0912 ## AD 1.0596 ## ADM 0.3680 ## FOM 0.4209 ## kmeans APN 0.0630 ## AD 0.9390 ## ADM 0.1131 ## FOM 0.3935 ## ## Optimal Scores: ## ## Score Method Clusters ## APN 0.0630 kmeans 3 ## AD 0.9390 kmeans 3 ## ADM 0.1131 kmeans 3 ## FOM 0.3935 kmeans 3 Gráfico da silhueta: library(cluster) #Construindo a matriz de similaridade: matriz_similaridade = dist(iris[,-5], #Conjunto de dados utilizados \u0026quot;euclidean\u0026quot; #medida de distância utilizada ) #Construindo o agrupamento hierárquico aglomerativo: agrupamento = hclust(matriz_similaridade, #Matriz de similaridade calculada \u0026quot;ward.D\u0026quot; #Método de agrupamento ) silhueta =silhouette(cutree(agrupamento,k=3),dist(iris[,-5])) plot(silhueta,main=\u0026quot;\u0026quot;) summary(silhueta) ## Silhouette of 150 units in 3 clusters from silhouette.default(x = cutree(agrupamento, k = 3), dist = dist(iris[, from -5])) : ## Cluster sizes and average silhouette widths: ## 50 64 36 ## 0.7994998 0.4115006 0.4670305 ## Individual silhouette widths: ## Min. 1st Qu. Median Mean 3rd Qu. Max. ## -0.09013 0.39933 0.56701 0.55416 0.77690 0.85493 Muitas opções Como podemos observar, a análise de agrupamentos é um método exploratório. É útil para organizar conjuntos de dados que contam com características semelhantes.\nÉ uma das principais técnicas da mineração de dados e já conta com grande variedade de algoritmos.\nOutra forma de visualizar relações entre muitas variáveis (ou entidades) é através de grafos, tema que exploro em outro post, com web scraping e ggplot2.\nReferências Johnson, Richard A. \u0026amp; Wichern, Dean W. Applied Multivariate Statistical Analysis. 6ª ed. Prentice Hall, 2007. Perguntas frequentes Qual a diferença entre análise fatorial e análise de componentes principais?\nA análise fatorial busca fatores latentes não observáveis que expliquem a correlação entre variáveis, enquanto a PCA cria combinações lineares que maximizam a variância explicada dos dados.\nComo escolher entre clustering hierárquico e K-means?\nMétodos hierárquicos são preferidos com amostras moderadas (300 a 1000 objetos) e quando se quer avaliar várias alternativas de agrupamento; o K-means é melhor quando o número de grupos já é conhecido e há muitos objetos ou outliers.\nComo validar se o número de clusters escolhido é adequado?\nPode-se usar medidas como o pseudo-F, a silhueta (entre -1 e 1, quanto mais próximo de 1 melhor) e o índice de Dunn, além de medidas de estabilidade como APN, AD, ADM e FOM.\n","date":"4 de janeiro de 2018","externalUrl":null,"permalink":"/post/2018-01-04-analise-multivariada-em-r/","section":"Posts","summary":" Análise Multivariada Esse é o primeiro post do ano e como no ano de 2017 falou-se tanto das maravilhas computacionais desta onda do Big Data e em contra partida, identificamos que deste 2004 a popularidade pelo termo “estatística” vem diminuindo como mostrei em uma breve pesquisa neste post sobre a API do googletrends sinto que existe uma necessidade de se ampliar também a divulgação dos métodos estatísticos pois o aprofundamento na teoria é fundamental (é muito fácil achar resultados sem fundamento apenas “apertando botão”), como as ferramentas da estatística multivariada que muitas vezes servem como soluções para essas grandes quantidades de dados\n","title":"Análise Multivariada com R","type":"post"},{"content":"","date":"4 de janeiro de 2018","externalUrl":null,"permalink":"/tags/clustering/","section":"Tags","summary":"","title":"Clustering","type":"tags"},{"content":"","date":"24 de dezembro de 2017","externalUrl":null,"permalink":"/tags/ggally/","section":"Tags","summary":"","title":"Ggally","type":"tags"},{"content":"","date":"24 de dezembro de 2017","externalUrl":null,"permalink":"/tags/ggfortify/","section":"Tags","summary":"","title":"Ggfortify","type":"tags"},{"content":" Funções do R para avaliar o ajuste de modelos Traduzindo:\n“Essencialmente, todos os modelos estão errados, mas alguns são úteis” - George E. P. Box\nSe você estuda estatística provavelmente já deve saber quem é este simpático senhor. Box teve grande contribuição para a estatística. Foi aluno do Ronald Aylmer Fisher e ainda se casou com a filha dele!\nLendo um artigo sobre a vida de Fisher um parágrafo me chamou atenção com uma fala de sua filha, que dizia o seguinte:\n“Joan Fisher Box, filha de Fisher, em seu livro sobre a vida do pai, se referindo à péssima classificação dele em francês, escreveu: “… ele nunca teve muita paciência com irrelevâncias.” (Box, 1978)\"\nFico imaginando o tamanho da contribuição desdes crânios para a comunidade se tivessem acesso a tantos mecanismos que temos hoje em dia e o que eles achariam relevantes..\nTL;DR\nO pacote GGally oferece funções como ggcoef, ggduo, ggnostic, ggpairs e ggscatmat para avaliar coeficientes, correlações e diagnósticos de modelos. O pacote ggfortify disponibiliza uma versão em ggplot2 dos gráficos de diagnóstico tradicionais do plot(modelo) do R. A função influence.measures() ajuda a identificar observações influentes através de estatísticas como DFBeta, DFFit, CovRatio, distância de Cook e valores de alavancagem (h). Para o bom ajuste de um modelo, certamente; a inferência, as análises de desvios, os critérios de seleção de um modelo, conferir comportamento dos resíduos e avaliação das estatísticas de diagnósticos são muito relevantes.\nNo CRAN já contamos com muitos pacotes disponíveis para nos auxiliar nessas avaliações, portanto vou mostrar aqui alguns pacotes com funções que já me ajudaram muito em avaliações de modelos indo além das funções nativas do R e do pacote ggplot2 (Um excelente pacote para apresentações elegantes e práticas de resultados visuais). Se seu interesse for em modelos bayesianos, também detalhei como construir um modelo bayesiano do zero e como ajustar modelos bayesianos com JAGS em outros posts.\nGGally Este pacote é sensacional, existem funções muito relevantes nele para melhorar a nossa experiência com ajuste de modelos, as funções apresentadas aqui são baseadas na página de documentação GGally, lá você pode conferir a documentação completa.\nPrimeiramente vamos carregar o pacote:\nlibrary(GGally) Carregado o pacote, vejamos as principais funções que podem nos auxiliar.\nGGally::ggcoef O objetivo da função GGally::ggcoef é traçar rapidamente os coeficientes de um modelo.\nPara um modelo linear:\nreg \u0026lt;- lm(Sepal.Length ~ Sepal.Width + Petal.Length + Petal.Width, data = iris) ggcoef(reg) Para um modelo logístico podemos utilizar o argumento exponentiate = TRUE e além disso, somos capazes de fazer diversas alterações no gráfico utilizando o ggcoef() veja alguns exemplo de argumentos que podem ser usados para personalizar como barras de erro e a linha vertical são plotadas:\n#Ajustando o modelo: d \u0026lt;- as.data.frame(Titanic) log.reg \u0026lt;- glm(Survived ~ Sex + Age + Class, family = binomial, data = d, weights = d$Freq) #Elaborando o gráfico ggcoef( log.reg, #O modelo a ser conferido exponentiate = TRUE, #Para avaliar o modelo logístico vline_color = \u0026quot;red\u0026quot;, #Reta em zero #vline_linetype = \u0026quot;solid\u0026quot;, #Altera a linha de referência errorbar_color = \u0026quot;blue\u0026quot;, #Cor da barra de erros errorbar_height = .25, shape = 18, #Altera o formato dos pontos centrais #size=3, #Altera o tamanho do ponto color=\u0026quot;black\u0026quot;, #Altera a cor do ponto mapping = aes(x = estimate, y = term, size = p.value))+ scale_size_continuous(trans = \u0026quot;reverse\u0026quot;) #Essa linha faz com que inverta o tamanho GGally::ggduo O objetivo desta função é exibir dois dados agrupados em uma matriz de plotagem. Isso é útil para análise de correlação canônica, análise de séries temporais múltiplas e análise de regressão.\nOs dados do exemplo apresentados aqui podem ser encontrados neste link\ndata(psychademic) head(psychademic) ## locus_of_control self_concept motivation read write math science sex ## 1 -0.84 -0.24 4 54.8 64.5 44.5 52.6 female ## 2 -0.38 -0.47 3 62.7 43.7 44.7 52.6 female ## 3 0.89 0.59 3 60.6 56.7 70.5 58.0 male ## 4 0.71 0.28 3 62.7 56.7 54.7 58.0 male ## 5 -0.64 0.03 4 41.6 46.3 38.4 36.3 female ## 6 1.11 0.90 2 62.7 64.5 61.4 58.0 female psych_variables \u0026lt;- attr(psychademic, \u0026quot;psychology\u0026quot;) academic_variables \u0026lt;- attr(psychademic, \u0026quot;academic\u0026quot;) ggduo( psychademic, psych_variables, academic_variables, types = list(continuous = \u0026quot;smooth_lm\u0026quot;), title = \u0026quot;Correlação entre as variáveis psicológicas e academicas\u0026quot;, xlab = \u0026quot;Psicológicos\u0026quot;, ylab = \u0026quot;Academicas\u0026quot; ) Uma vez que o ggduo não tem uma seção superior para exibir os valores de correlação, podemos usar uma função personalizada para adicionar a informação nas parcelas contínuas.\nCriando uma função personalizada para informar a correlação entre as observações:\nlm_with_cor \u0026lt;- function(data, mapping, ..., method = \u0026quot;pearson\u0026quot;) { x \u0026lt;- eval(mapping$x, data) y \u0026lt;- eval(mapping$y, data) cor \u0026lt;- cor(x, y, method = method) ggally_smooth_lm(data, mapping, ...) + ggplot2::geom_label( data = data.frame( x = min(x, na.rm = TRUE), y = max(y, na.rm = TRUE), lab = round(cor, digits = 3) ), mapping = ggplot2::aes(x = x, y = y, label = lab), hjust = 0, vjust = 1, size = 5, fontface = \u0026quot;bold\u0026quot;, inherit.aes = FALSE # do not inherit anything from the ... ) } Portanto:\nggduo( psychademic, psych_variables, academic_variables, types = list(continuous = \u0026quot;smooth_lm\u0026quot;), title = \u0026quot;Correlação entre variáveis acadêmica e psicológica\u0026quot;, xlab = \u0026quot;Psicológica\u0026quot;, ylab = \u0026quot;Academica\u0026quot; )+ theme(legend.position = \u0026quot;bottom\u0026quot;) Para avaliar resíduos da uma regressão ajustada para cada uma das variáveis explanatórias vs. as variáveis explanatórias:\ndados \u0026lt;- datasets::swiss # Criando uma coluna \u0026quot;fake\u0026quot;: dados$Residual \u0026lt;- seq_len(nrow(dados)) # Calculando todos os resíduos que serão exibidos: colunas=2:6 #Informe as colunas que contem as variaveis explanatorias residuals \u0026lt;- lapply(dados[colunas], function(x) { summary(lm(Fertility ~ x, data = dados))$residuals }) # Calculando um intervalo constante para todos os resíduos y_range \u0026lt;- range(unlist(residuals)) # Função modificada para mostrar os resíduos: lm_or_resid \u0026lt;- function(data, mapping, ..., line_color = \u0026quot;red\u0026quot;, line_size = 1) { if (as.character(mapping$y) != \u0026quot;Residual\u0026quot;) { return(ggally_smooth_lm(data, mapping, ...)) } # Criando os resíduos para apresentar: resid_data \u0026lt;- data.frame( x = data[[as.character(mapping$x)]], y = residuals[[as.character(mapping$x)]] ) ggplot(data = data, mapping = mapping) + geom_hline(yintercept = 0, color = line_color, size = line_size) + ylim(y_range) + geom_point(data = resid_data, mapping = aes(x = x, y = y), ...) } # Plote os dados: ggduo( dados, 2:6, c(1,7), types = list(continuous = lm_or_resid) ) GGally::ggnostic O ggnostic é um wrapper de exibição para ggduo que exibe diagnósticos de modelo completo para cada variável explicativa dada.\nPor padrão, o ggduo exibe os valores residuais, o sigma do modelo de “leave-one-out”, os pontos de alavanca e a distância de Cook em relação a cada variável explicativa.\nAs linhas da matriz de plotagem podem ser expandidas para incluir valores ajustados, erro padrão dos valores ajustados, resíduos padronizados e qualquer uma das variáveis de resposta.\nSe o modelo for um modelo linear, os asteriscos (*) são adicionados de acordo com a significância anova de cada variável explicativa.\nA maioria das parcelas diagnósticas contêm linhas de referência para ajudar a determinar se o modelo está adequadamente instalado\nOlhando para os conjuntos de dados do conjunto de dados state.x77 ajustaremos um modelo de regressão múltipla para a expectativa de vida.\n#Dados que serão utilizados no exemplos: state \u0026lt;- as.data.frame(state.x77) #Arrumando o nome das variaveis: colnames(state)[c(4, 6)] \u0026lt;- c(\u0026quot;Life.Exp\u0026quot;, \u0026quot;HS.Grad\u0026quot;) # Ajustando o modelo completo: model \u0026lt;- lm(Life.Exp ~ ., data = state) # Executando o stepwise para encontrar o melhor ajuste model \u0026lt;- step(model, trace = FALSE) Executando o diagnóstico deste modelo com a função ggnostic():\n# look at model diagnostics ggnostic(model) Para acessar as variáveis influentes do modelo podemos utilizar a função influence.measures(), veja:\nsummary(influence.measures(model)) ## Potentially influential observations of ## lm(formula = Life.Exp ~ Population + Murder + HS.Grad + Frost, data = state) : ## ## dfb.1_ dfb.Pplt dfb.Mrdr dfb.HS.G dfb.Frst dffit cov.r cook.d ## Alaska 0.41 0.18 -0.40 -0.35 -0.16 -0.50 1.36_* 0.05 ## California 0.04 -0.09 0.00 -0.04 0.03 -0.12 1.81_* 0.00 ## Hawaii -0.03 -0.57 -0.28 0.66 -1.24_* 1.43_* 0.74 0.36 ## Nevada 0.40 0.14 -0.42 -0.29 -0.28 -0.52 1.46_* 0.05 ## New York 0.01 -0.06 0.00 0.00 -0.01 -0.07 1.44_* 0.00 ## hat ## Alaska 0.25 ## California 0.38_* ## Hawaii 0.24 ## Nevada 0.29 ## New York 0.23 Esta função retorna as seguintes estatísticas:\nDFBeta DFFit CovRatio D.Cook h Alteração no vetor estimado \\(\\hat \\beta\\) ao se retirar o i-ésimo ponto da análise Alteração provocada no valor ajustado pela retirada da observação \\(i\\) Expressa o relação de covariancia Medida de afastamento das estimativas ao retirar \\(i\\) e também considera o resíduo estudentizado internamente Elementos da diagonal da matriz H Vejamos então um exemplo de matriz de matriz de diagnóstico completo.\nAs seguintes linhas de código exibirão uma matriz de diagnóstico para o mesmo modelo:\n#Ajustando um modelo de exemplo: flea_model \u0026lt;- step(lm(head ~ ., data = flea), trace = FALSE) Todas as colunas possíveis e usando ggally_smooth() para exibir os pontos ajustados e as variáveis de resposta temos:\n# default output ggnostic(flea_model, # mapping = ggplot2::aes(color = species), #Para colorir segundo um fator columnsY = c(\u0026quot;head\u0026quot;, \u0026quot;.fitted\u0026quot;, \u0026quot;.se.fit\u0026quot;, \u0026quot;.resid\u0026quot;, \u0026quot;.std.resid\u0026quot;, \u0026quot;.hat\u0026quot;, \u0026quot;.sigma\u0026quot;, \u0026quot;.cooksd\u0026quot;), continuous = list(default = ggally_smooth, .fitted = ggally_smooth) ) GGally::ggpairs O ggpairs é uma forma especial de uma ggmatrix que produz uma comparação pairwise de dados multivariados. Por padrão, o ggpairs fornece duas comparações diferentes de cada par de colunas e exibe a densidade ou a contagem da variável respectiva ao longo da diagonal. Com diferentes configurações de parâmetros, a diagonal pode ser substituída pelos valores do eixo e rótulos variáveis.\n#Funcao de correlacoes my_fn \u0026lt;- function(data, mapping, method=\u0026quot;lm\u0026quot;, ...){ p \u0026lt;- ggplot(data = data, mapping = mapping) + geom_point() + geom_smooth(method=method, ...) p } data(tips, package = \u0026quot;reshape\u0026quot;) #Correlaçoes cruzadas ggpairs(tips, lower = list(continuous = my_fn)) Existem muitos recursos ocultos dentro dos ggpairs() e muitos exemplos podem ser conferidos na internet para obter o máximo do ggpairs().\nGGally::ggscatmat A principal função é ggscatmat. É semelhante a ggpairs(), mas funciona apenas para dados multivariados puramente numéricos.\nÉ mais rápido que ggpairs, porque é necessário fazer menos escolhas.\nEle cria uma matriz com diagramas de dispersão na diagonal inferior, densidades na diagonal e correlações escritas na diagonal superior.\nA sintaxe é inserir o conjunto de dados, as colunas que deseja traçar, uma coluna de cores e um nível alfa.\ndata(flea) ggscatmat(flea, columns = 2:4, color=\u0026quot;species\u0026quot;, alpha=0.8) ggfottify Outra opção interessante para avaliar o ajuste dos modelos é o pacote ggfottify. Ele disponibiliza uma interface de traçado (como a função plot(modelo_ajustado)) de análise e gráficos em um estilo unificado, porém usando ggplot2.\nVamos então dar início carregando o pacote:\nlibrary(ggfortify) Veja a seguir alguns dos gráficos disponíveis no R para a análise de resíduos:\nautoplot(flea_model, which = 1:6, ncol = 3, label.size = 3) Especificando as opções de plot\nAlgumas propriedades desses gráficos podem ser alteradas. Por exemplo, a opção colour = 'dodgerblue3' é para pontos de dados, o smooth.colour = 'black' é para linhas de suavização e ad.colour = 'blue' é para opções adicionais.\nVeja ainda que ncol e nrow controlam o layout.\nautoplot(flea_model, which = 1:6, colour = \u0026#39;dodgerblue3\u0026#39;, smooth.colour = \u0026#39;black\u0026#39;, smooth.linetype = \u0026#39;dashed\u0026#39;, ad.colour = \u0026#39;blue\u0026#39;, label.size = 3, label.n = 5, label.colour = \u0026#39;blue\u0026#39;, ncol = 3) Além disso, você pode usar nomes de colunas para essas propriedades, vamos separar os grupos de machos e fêmeas por cores:\nautoplot(flea_model, which = 1:6, data = flea, colour = \u0026#39;species\u0026#39;, label.size = 3, ncol = 3) O que será que os crânios da estatística fariam diante de tantos recursos?\nPerguntas frequentes Qual pacote do R usar para avaliar rapidamente os coeficientes de um modelo?\nO GGally::ggcoef traça rapidamente os coeficientes de modelos lineares e logísticos, permitindo personalizar cores, formatos e barras de erro.\nComo identificar observações influentes em um modelo ajustado?\nA função influence.measures() retorna estatísticas como DFBeta, DFFit, CovRatio, distância de Cook (D.Cook) e alavancagem (h) para cada observação.\nQual a diferença entre GGally e ggfortify para diagnóstico de modelos?\nO GGally oferece funções como ggduo, ggnostic e ggpairs para matrizes de diagnóstico, enquanto o ggfortify recria os gráficos tradicionais de plot(modelo) usando a sintaxe do ggplot2.\n","date":"24 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-24-diagnostico-de-modelo/","section":"Posts","summary":" Funções do R para avaliar o ajuste de modelos Traduzindo:\n“Essencialmente, todos os modelos estão errados, mas alguns são úteis” - George E. P. Box\nSe você estuda estatística provavelmente já deve saber quem é este simpático senhor. Box teve grande contribuição para a estatística. Foi aluno do Ronald Aylmer Fisher e ainda se casou com a filha dele!\nLendo um artigo sobre a vida de Fisher um parágrafo me chamou atenção com uma fala de sua filha, que dizia o seguinte:\n","title":"Pacotes do R para avaliar o ajuste de modelos","type":"post"},{"content":" Inferência bayesiana Imagem da Internet\nQuando estamos falando de Inferência nosso objetivo normalmente é tentar verificar alguma informação sobre uma quantidade desconhecida.\nTL;DR\nNa inferência bayesiana, o parâmetro é tratado como aleatório e sua \"crença\" é representada por uma distribuição de probabilidade. O pacote R2jags ajusta modelos bayesianos no R chamando o JAGS (amostrador de Gibbs). O mcmcplots e o superdiag diagnosticam a convergência das cadeias MCMC. Para isso devemos utilizar toda informação disponível, seja ela objetiva ou subjetiva (isto é, vinda de umam amostra ou de algum conhecimento préveo ou intuitivo)\nSegundo o ponto de vista Bayesiano essa informação subjetiva também será incorporada na análise graças ao teorema de bayes.\nFoi o Statistical Rethinking, do McElreath, que me fez realmente entender bayesiana como um jeito de raciocinar e não só como fórmula pra decorar. Recomendo bastante pra quem tá começando a mexer com isso agora.\nComo no ponto de vista Bayesiano atribuímos aleatoriedade ao parâmetro, nossa “crença” será representada por uma distribuição de probabilidade (ou modelo probabilístico)\nTeorema de bayes: \\[ p(\\theta|x)=\\frac{p(x,\\theta)}{p(x)}=\\frac{p(x|\\theta)p(\\theta)}{p(x)} \\]\nonde:\n\\(p(x|\\theta)\\): função de verossimilhança (modelo) \\(p(\\theta)\\): distribuição a priori \\(p(x)\\): distribuição marginal de \\(x\\). A estimação muitas vezes envolve o cálculo de integrais nada simples analiticamente porém, alguns algorítimos como o amostrador de Gibbs pode relizar aproximações muito relevantes.\nModelo linear bayesiano Para entender como funciona o modelo bayesiano, primeiramente vamos começar com algo bem simples, suponha:\n\\[ Y_i \\sim N(\\mu_i,\\tau) \\] onde \\(\\mu\\) é definido como \\(\\mu_i= X \\mathbf{\\beta}\\).\nIncialmente vamos considerar que não existe relação nenhuma, então utilizaremos a priori:\n\\[ \\beta \\sim N(0,\\tau_{\\beta}) \\]\nonde \\(\\tau\\) é conhecido.\nNem sempre é uma tarefa simples determinar a distribuição posteri de um modelo bayesiano e é neste ponto que o pacote jagsserá bastante útil (existem outras alternativas como o WinBugs, OpenBugs, Stan, mas aqui resolvi trazer apenas o jags por possuir vantagens bem interessantes.)\nJags O pacote R2jags é exatamente o que seu nome significa: “Just Another Gibbs Sampler”. Possui as mesmas funcionalidades do nosso querido OpenBugs possibilitando também que seja utilizado inteiramente dentro do ambiente R.\nAssim como o OpenBugs, ele também trabalha chamando o software oficial que precisa ser baixado no site.\nPara começar a utilizar basta baixar o pacote e acessá-lo na biblioteca:\nlibrary(R2jags) Declarando o modelo A base de dados que será utilizada para ajustar o modelo será a base nativa do R chamada trees:\nX\u0026lt;-trees[,1:2] #Matriz de variáveis explanatórias Y\u0026lt;- trees[,3] #Vetor da variável resposta p \u0026lt;- ncol(X) #p é o número de parâmetros do modelo (nesse caso é o número de colunas) n \u0026lt;- nrow(X) #n é o número de observações do modelo O modelo deve estar declarado e salvo em um arquivo .txt (ou mesmo um outro arquivo .r) da seguinte maneira:\n### Declarando o modelo Bayesiano sink(\u0026quot;linreg.txt\u0026quot;) cat(\u0026quot; model { # Prioris for(j in 1:p) { beta[j] ~ dnorm(mu.beta, tau.beta) } sigma ~ dunif(0, 100) tau \u0026lt;- 1/ (sigma * sigma) # Verossimilhança for (i in 1:n) { y[i] ~ dnorm(mu[i], tau) mu[i] \u0026lt;- inprod(X[i,], beta) } } \u0026quot;,fill=TRUE) sink() Uma vez que o modelo esta declarado, é a hora de nomear os parametros da função que fará o ajuste do modelo\n#Parametros da Priori mu.beta \u0026lt;- 0 tau.beta \u0026lt;- 0.001 #Set Working Directory wd \u0026lt;- getwd() # Junte os dados em uma lista win.data \u0026lt;- list(X=X,y=Y,p=p,n=n,mu.beta=mu.beta,tau.beta=tau.beta) # Função de inicialização inits \u0026lt;- function(){ list(beta=rnorm(p), sigma = rlnorm(1))} # Os parametros que desejamos estimar params \u0026lt;- c(\u0026quot;beta\u0026quot;,\u0026quot;sigma\u0026quot;,\u0026quot;tau\u0026quot;) # Caracteristicas do MCMC n.burnin \u0026lt;- 500 #Número de iterações que serão descartadas n.thin \u0026lt;- 10 #para economizar memória e tempo de computação se n.iter for grande n.post \u0026lt;- 5000 n.chains \u0026lt;- 3 #Número de cadeias n.iter \u0026lt;- n.burnin + n.thin*n.post #Número de iterações Implementando o modelo Após ter em mãos todos esses resultados, já podemos ajustar o modelo com o comando jags(), veja:\nbayes.mod.fit \u0026lt;-jags(data = win.data, inits = inits, parameters = params, model.file = \u0026quot;linreg.txt\u0026quot;, # O arquivo \u0026quot;linreg.txt\u0026quot; deve estar no mesmo diretório n.iter = n.iter, n.thin=n.thin, n.burnin=n.burnin, n.chains=n.chains, working.directory=wd,DIC = T) ## Compiling model graph ## Resolving undeclared variables ## Allocating nodes ## Graph information: ## Observed stochastic nodes: 31 ## Unobserved stochastic nodes: 3 ## Total graph size: 166 ## ## Initializing model print(bayes.mod.fit, dig = 3) ## Inference for Bugs model at \u0026quot;linreg.txt\u0026quot;, fit using jags, ## 3 chains, each with 50500 iterations (first 500 discarded), n.thin = 10 ## n.sims = 15000 iterations saved ## mu.vect sd.vect 2.5% 25% 50% 75% 97.5% Rhat n.eff ## beta[1] 5.045 0.435 4.183 4.757 5.043 5.324 5.916 1.001 15000 ## beta[2] -0.478 0.078 -0.633 -0.527 -0.477 -0.427 -0.324 1.001 15000 ## sigma 6.448 0.904 4.995 5.805 6.335 6.970 8.502 1.001 15000 ## tau 0.025 0.007 0.014 0.021 0.025 0.030 0.040 1.001 15000 ## deviance 201.924 2.682 198.881 199.970 201.244 203.149 208.856 1.001 7200 ## ## For each parameter, n.eff is a crude measure of effective sample size, ## and Rhat is the potential scale reduction factor (at convergence, Rhat=1). ## ## DIC info (using the rule, pD = var(deviance)/2) ## pD = 3.6 and DIC = 205.5 ## DIC is an estimate of expected predictive error (lower deviance is better). Com os resultados em mãos podemos avaliar o ajuste do modelo, o jags nos fornece os intervalos de credibilidade e o Rhat, que é a convergência da cadeia, a princípio vamos apenas considerar o fato de que quanto mais próximo de 1, melhor são as estimativas.\nNão vou me extender neste post com a interpretação do modelo pois o objetivo esta sendo mostrar a funcionalidade do jags em conjunto com o R.\nDiagnósticos do modelo com mcmcplots Para o diagnóstico do modelo podemos utilizar o pacote mcmcplots que fornece de maneira bem agradável os resultados gerados pelo amostrador, primeiramente vamos carregar o pacote:\nlibrary(mcmcplots) Em seguida precisar informar para o R que o resultado do algorítimo se trata de um objeto mcmc, portanto:\nbayes.mod.fit.mcmc \u0026lt;- as.mcmc(bayes.mod.fit) summary(bayes.mod.fit.mcmc) ## ## Iterations = 1:49991 ## Thinning interval = 10 ## Number of chains = 3 ## Sample size per chain = 5000 ## ## 1. Empirical mean and standard deviation for each variable, ## plus standard error of the mean: ## ## Mean SD Naive SE Time-series SE ## beta[1] 5.04490 0.435344 3.555e-03 3.555e-03 ## beta[2] -0.47754 0.077588 6.335e-04 6.335e-04 ## deviance 201.92383 2.682384 2.190e-02 2.144e-02 ## sigma 6.44763 0.903646 7.378e-03 7.359e-03 ## tau 0.02542 0.006784 5.539e-05 5.524e-05 ## ## 2. Quantiles for each variable: ## ## 2.5% 25% 50% 75% 97.5% ## beta[1] 4.18250 4.75721 5.04333 5.32437 5.91642 ## beta[2] -0.63255 -0.52732 -0.47726 -0.42674 -0.32376 ## deviance 198.88143 199.97019 201.24393 203.14881 208.85648 ## sigma 4.99470 5.80492 6.33492 6.96990 8.50193 ## tau 0.01383 0.02058 0.02492 0.02968 0.04008 O pacote nos fornece alguns tipos de gráficos para diagnóstico\ncaterplot(bayes.mod.fit.mcmc) #Observando todas as estimativas caterplot(bayes.mod.fit.mcmc,parms = params) #Observando as estimativas de todos os parâmetros menos o desvio denplot(bayes.mod.fit.mcmc) #Densidade das estimativas de cada cadeia traplot(bayes.mod.fit.mcmc,greek = T) #Avaliando a convergência E por fim, para diagnósticos rápidos, pode produzir arquivos html com traço, densidade e autocorrelação.\nO comando traça tudo em uma página e os arquivos serão exibidos em seu navegador de internet padrão.\nmcmcplot(bayes.mod.fit.mcmc) Vai retornar um relatório resumido para todos os parâmetros como nesta imagem da internet como:\nComo o objetivo do post é trazer a funcionalidade do pacote, vou apenas deixar ilustrado quais são algumas das funções mais comumente utilizadas para avaliar estatísticamente o desempenho dos modelos.\nDiagnosticos estatísticos do modelo:\n#Mais diagnosticos: gelman.plot(bayes.mod.fit.mcmc) geweke.diag(bayes.mod.fit.mcmc) ## [[1]] ## ## Fraction in 1st window = 0.1 ## Fraction in 2nd window = 0.5 ## ## beta[1] beta[2] deviance sigma tau ## -1.6717 1.1790 -0.4485 0.1854 -0.6815 ## ## ## [[2]] ## ## Fraction in 1st window = 0.1 ## Fraction in 2nd window = 0.5 ## ## beta[1] beta[2] deviance sigma tau ## 0.37278 -0.36960 -0.24342 -0.08007 0.30725 ## ## ## [[3]] ## ## Fraction in 1st window = 0.1 ## Fraction in 2nd window = 0.5 ## ## beta[1] beta[2] deviance sigma tau ## -0.15725 0.19911 -0.08445 -0.34043 0.35357 geweke.plot(bayes.mod.fit.mcmc) raftery.diag(bayes.mod.fit.mcmc) ## [[1]] ## ## Quantile (q) = 0.025 ## Accuracy (r) = +/- 0.005 ## Probability (s) = 0.95 ## ## Burn-in Total Lower bound Dependence ## (M) (N) (Nmin) factor (I) ## beta[1] 20 39950 3746 10.70 ## beta[2] 20 36200 3746 9.66 ## deviance 20 37410 3746 9.99 ## sigma 20 38030 3746 10.20 ## tau 20 36800 3746 9.82 ## ## ## [[2]] ## ## Quantile (q) = 0.025 ## Accuracy (r) = +/- 0.005 ## Probability (s) = 0.95 ## ## Burn-in Total Lower bound Dependence ## (M) (N) (Nmin) factor (I) ## beta[1] 20 38030 3746 10.20 ## beta[2] 20 36800 3746 9.82 ## deviance 20 37410 3746 9.99 ## sigma 20 37410 3746 9.99 ## tau 20 35610 3746 9.51 ## ## ## [[3]] ## ## Quantile (q) = 0.025 ## Accuracy (r) = +/- 0.005 ## Probability (s) = 0.95 ## ## Burn-in Total Lower bound Dependence ## (M) (N) (Nmin) factor (I) ## beta[1] 20 37410 3746 9.99 ## beta[2] 20 38030 3746 10.20 ## deviance 20 37410 3746 9.99 ## sigma 30 40620 3746 10.80 ## tau 20 39300 3746 10.50 heidel.diag(bayes.mod.fit.mcmc) ## [[1]] ## ## Stationarity start p-value ## test iteration ## beta[1] passed 1 0.292 ## beta[2] passed 1 0.455 ## deviance passed 1 0.733 ## sigma passed 1 0.881 ## tau passed 1 0.816 ## ## Halfwidth Mean Halfwidth ## test ## beta[1] passed 5.0481 0.012089 ## beta[2] passed -0.4780 0.002155 ## deviance passed 201.8829 0.073069 ## sigma passed 6.4367 0.024544 ## tau passed 0.0255 0.000187 ## ## [[2]] ## ## Stationarity start p-value ## test iteration ## beta[1] passed 1 0.246 ## beta[2] passed 1 0.249 ## deviance passed 1 0.967 ## sigma passed 1 0.950 ## tau passed 1 0.770 ## ## Halfwidth Mean Halfwidth ## test ## beta[1] passed 5.0386 0.011955 ## beta[2] passed -0.4765 0.002134 ## deviance passed 201.9023 0.068414 ## sigma passed 6.4571 0.025014 ## tau passed 0.0253 0.000188 ## ## [[3]] ## ## Stationarity start p-value ## test iteration ## beta[1] passed 1 0.657 ## beta[2] passed 1 0.690 ## deviance passed 1 0.544 ## sigma passed 1 0.813 ## tau passed 1 0.873 ## ## Halfwidth Mean Halfwidth ## test ## beta[1] passed 5.0480 0.012156 ## beta[2] passed -0.4781 0.002163 ## deviance passed 201.9863 0.076685 ## sigma passed 6.4491 0.025385 ## tau passed 0.0254 0.000188 Diagnostico de convergencia rapida: superdiag Uma função muito conveniente para analisar representações numéricas de diagnósticos em um ajuste é o pacote superdiag de Tsai, Gill e Rapkin, 2012 que trás uma série de estatísticas para avaliar o desempenho dos ajustes do modelo.\nlibrary(superdiag) superdiag(bayes.mod.fit.mcmc, burnin = 100) ## Number of chains = 3 ## Number of iterations = 5000 per chain before discarding the burn-in period ## Burn-in period = 100 per chain ## Sample size in total = 14703 ## ## ****************** The Geweke diagnostic: ****************** ## Windows: ## chain 1 chain 2 chain 3 ## From start 0.1 0.5420 0.2999 ## From stop 0.5 0.3511 0.6893 ## ## Z-scores: ## chain 1 chain 2 chain 3 ## beta[1] -1.85586 0.3331 -1.66699 ## beta[2] 1.57605 -0.2271 1.53584 ## deviance 0.02463 0.3356 -1.14324 ## sigma -0.15363 -0.8820 -0.33962 ## tau -0.09745 0.9937 0.01232 ## ## *************** The Gelman-Rubin diagnostic: *************** ## Potential scale reduction factors: ## Point est. Upper C.I. ## beta[1] 1.0001 1.001 ## beta[2] 1.0000 1.000 ## deviance 1.0009 1.002 ## sigma 1.0002 1.001 ## tau 0.9999 1.000 ## ## Multivariate psrf: 1.0005 ## ## ************* The Heidelberger-Welch diagnostic ************ ## Chain 1: ## epsilon=0.1, alpha=0.05 ## Stationarity start p-value ## test iteration ## beta[1] passed 1 0.1576 ## beta[2] passed 1 0.2864 ## deviance passed 1 0.8399 ## sigma passed 1 0.8207 ## tau passed 1 0.7405 ## ## Halfwidth Mean Halfwidth ## test ## beta[1] passed 5.04671 0.012211 ## beta[2] passed -0.47775 0.002177 ## deviance passed 201.89097 0.074094 ## sigma passed 6.43566 0.024772 ## tau passed 0.02549 0.000189 ## ## Chain 2: ## epsilon=0.079, alpha=0.1 ## Stationarity start p-value ## test iteration ## beta[1] passed 1 0.3032 ## beta[2] passed 1 0.3259 ## deviance passed 1 0.9562 ## sigma passed 1 0.7462 ## tau passed 1 0.5362 ## ## Halfwidth Mean Halfwidth ## test ## beta[1] passed 5.03850 0.0120853 ## beta[2] passed -0.47646 0.0021574 ## deviance passed 201.90084 0.0693125 ## sigma passed 6.45467 0.0252168 ## tau passed 0.02536 0.0001894 ## ## Chain 3: ## epsilon=0.054, alpha=0.005 ## Stationarity start p-value ## test iteration ## beta[1] passed 1 0.5489 ## beta[2] passed 1 0.5665 ## deviance passed 1 0.5038 ## sigma passed 1 0.8038 ## tau passed 1 0.8898 ## ## Halfwidth Mean Halfwidth ## test ## beta[1] passed 5.04719 0.0122925 ## beta[2] passed -0.47794 0.0021858 ## deviance passed 201.98956 0.0775537 ## sigma passed 6.44893 0.0256817 ## tau passed 0.02544 0.0001937 ## ## *************** The Raftery-Lewis diagnostic *************** ## Chain 1: ## Convergence eps = 0.001 ## Quantile (q) = 0.025 ## Accuracy (r) = +/- 0.005 ## Probability (s) = 0.95 ## ## Burn-in Total Lower bound Dependence ## (M) (N) (Nmin) factor (I) ## beta[1] 30 40170 3746 10.70 ## beta[2] 20 36340 3746 9.70 ## deviance 20 38200 3746 10.20 ## sigma 20 38200 3746 10.20 ## tau 20 36950 3746 9.86 ## ## Chain 2: ## Convergence eps = 5e-04 ## Quantile (q) = 0.25 ## Accuracy (r) = +/- 0.001 ## Probability (s) = 0.99 ## ## You need a sample size of at least 1244044 with these values of q, r and s ## ## Chain 3: ## Convergence eps = 0.005 ## Quantile (q) = 0.25 ## Accuracy (r) = +/- 5e-04 ## Probability (s) = 0.999 ## ## You need a sample size of at least 8120675 with these values of q, r and s ## ## ************* The Hellinger distance diagnostic ************ ## Between chains: ## Min Max ## beta[1] 0.01735 0.02915 ## beta[2] 0.02015 0.02620 ## deviance 0.03155 0.03413 ## sigma 0.01858 0.02731 ## tau 0.01538 0.02810 ## ## Within chain 1: ## 980 1960 2940 3920 ## beta[1] 0.05231 0.03952 0.04017 0.04259 ## beta[2] 0.04261 0.05034 0.04320 0.04782 ## deviance 0.05880 0.04060 0.06297 0.04311 ## sigma 0.03871 0.03667 0.06465 0.04285 ## tau 0.03668 0.03996 0.03633 0.04083 ## ## Within chain 2: ## 980 1960 2940 3920 ## beta[1] 0.03098 0.04075 0.04281 0.03887 ## beta[2] 0.03050 0.03770 0.03887 0.04216 ## deviance 0.04541 0.03992 0.03390 0.04730 ## sigma 0.04660 0.03876 0.03090 0.02866 ## tau 0.03648 0.03773 0.02967 0.03589 ## ## Within chain 3: ## 980 1960 2940 3920 ## beta[1] 0.03356 0.03988 0.03146 0.02986 ## beta[2] 0.03425 0.04729 0.03175 0.03219 ## deviance 0.05894 0.03553 0.05018 0.04509 ## sigma 0.04392 0.04245 0.03858 0.03760 ## tau 0.04089 0.03458 0.04512 0.03047 Para finalizar, outra função que pode ser útil pata atualizando o modelo, se necessário - por exemplo, se não houver convergência ou pouca convergencia:\nbayes.mod.fit.upd \u0026lt;- update(bayes.mod.fit, n.iter=1000) bayes.mod.fit.upd \u0026lt;- autojags(bayes.mod.fit) Muito a estudar Assim como toda a Estatística, inferência bayesiana não funciona se a teoria não for aplicada corretamente. É uma ferramenta muito poderosa e necessita ser usada com cautela pois demanda bastante o uso de metodologias estatísticas.\nComo dizia o tio Ben: “grandes poderes trazem grandes responsabilidades” então vamos tomar cuidado com os resultados que encontramos. Para outras formas de avaliar e apresentar o ajuste de modelos, veja os posts sobre análise multivariada e sobre tabelas para apresentar resultados. Para ver os cálculos por trás de um modelo bayesiano implementados do zero (sem o JAGS), veja este outro post.\nAtualização (2026) Nota acrescentada em 2026. O JAGS continua funcionando e é uma ótima porta de entrada para MCMC, mas quem está começando um projeto novo hoje frequentemente prefere o Stan (via rstan ou o pacote brms, que gera o código Stan automaticamente a partir de uma sintaxe parecida com lm()). A lógica de priori, verossimilhança e diagnóstico de convergência deste post vale para qualquer um dos dois.\nPerguntas frequentes Qual a diferença entre estatística bayesiana e frequentista? Na abordagem frequentista, o parâmetro é fixo e desconhecido, e a incerteza está na amostra. Na bayesiana, o parâmetro é tratado como uma variável aleatória com uma distribuição de probabilidade (a priori), atualizada pelos dados observados via o teorema de Bayes para gerar a distribuição posterior.\nComo sei se minha cadeia MCMC convergiu? O indicador mais usado é o Rhat (fator de redução de escala potencial): valores próximos de 1 indicam convergência. Complementarmente, o pacote mcmcplots permite inspecionar visualmente o traço das cadeias, e testes como Geweke e Heidelberger-Welch (do pacote superdiag) formalizam esse diagnóstico.\nPreciso instalar algo além do R para usar JAGS? Sim. O JAGS é um software externo (não é só um pacote R) e precisa ser baixado e instalado separadamente antes de carregar o R2jags no R, que funciona como uma interface para chamá-lo.\nReferencias Uma primeira olhada em estatística bayesiana e linguagem BUGS por Augusto Ribas - blog Recologia KRUSCHKE, J. K. Doing Bayesian Data Analysis: A Tutorial with R, JAGS, and Stan. 2. ed. Academic Press / Elsevier, 2014. ","date":"18 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-18-bayesiana-jags-mcmcplot/","section":"Posts","summary":" Inferência bayesiana Imagem da Internet\nQuando estamos falando de Inferência nosso objetivo normalmente é tentar verificar alguma informação sobre uma quantidade desconhecida.\nTL;DR\nNa inferência bayesiana, o parâmetro é tratado como aleatório e sua \"crença\" é representada por uma distribuição de probabilidade. O pacote R2jags ajusta modelos bayesianos no R chamando o JAGS (amostrador de Gibbs). O mcmcplots e o superdiag diagnosticam a convergência das cadeias MCMC. Para isso devemos utilizar toda informação disponível, seja ela objetiva ou subjetiva (isto é, vinda de umam amostra ou de algum conhecimento préveo ou intuitivo)\n","title":"Ajustando Modelos Bayesianos com JAGS e MCMC no R","type":"post"},{"content":" Manipulação de strings e Text mining Estudamos números e mais números na graduação de estatística (não sei nem se ainda consigo enxergar algarismos gregos como letras) e mesmo assim um problema frequente na vida de quem trabalha com dados é a manipulação de variáveis do tipo string.\nTL;DR\nstringr: sintaxe consistente para str_replace(), str_split(), str_sub() e mais. tm: cria e limpa um corpus de texto, gera matriz de termos e TF-IDF. SnowballC: extrai o radical das palavras (stemming) em português e outras línguas. Uma variável do tipo string é uma variável do tipo texto e esse tipo de objeto costuma causar alguns problemas na análise de dados se não forem devidamente tratados.\nDesde modificações em nomes de colunas em data.frames até as mais espertas aplicações de text mining com corpus, a limpeza e manipulação de strings é quase sempre necessária\nCriando funções Antes de apresentar alguns pacotes com funções úteis para manipular strings, gostaria de comentar que pode ser bem útil desenvolvermos funções para nosso próprio uso, não é raro realizarmos o mesmo procedimento em diferentes etapas das análises, o que pode tornar o código desorganizado ou poluído com tantas linhas repetidas.\nTrago aqui de exemplo uma função que encontrei recentemente para remover acentos no stackoverflow que já me ajudou bastante, veja a função:\nrm_accent \u0026lt;- function(str,pattern=\u0026quot;all\u0026quot;) { # Rotinas e funções úteis V 1.0 # rm.accent - REMOVE ACENTOS DE PALAVRAS # Função que tira todos os acentos e pontuações de um vetor de strings. # Parâmetros: # str - vetor de strings que terão seus acentos retirados. # patterns - vetor de strings com um ou mais elementos indicando quais acentos deverão ser retirados. # Para indicar quais acentos deverão ser retirados, um vetor com os símbolos deverão ser passados. # Exemplo: pattern = c(\u0026quot;´\u0026quot;, \u0026quot;^\u0026quot;) retirará os acentos agudos e circunflexos apenas. # Outras palavras aceitas: \u0026quot;all\u0026quot; (retira todos os acentos, que são \u0026quot;´\u0026quot;, \u0026quot;`\u0026quot;, \u0026quot;^\u0026quot;, \u0026quot;~\u0026quot;, \u0026quot;¨\u0026quot;, \u0026quot;ç\u0026quot;) if(!is.character(str)) str \u0026lt;- as.character(str) pattern \u0026lt;- unique(pattern) if(any(pattern==\u0026quot;Ç\u0026quot;)) pattern[pattern==\u0026quot;Ç\u0026quot;] \u0026lt;- \u0026quot;ç\u0026quot; symbols \u0026lt;- c( acute = \u0026quot;áéíóúÁÉÍÓÚýÝ\u0026quot;, grave = \u0026quot;àèìòùÀÈÌÒÙ\u0026quot;, circunflex = \u0026quot;âêîôûÂÊÎÔÛ\u0026quot;, tilde = \u0026quot;ãõÃÕñÑ\u0026quot;, umlaut = \u0026quot;äëïöüÄËÏÖÜÿ\u0026quot;, cedil = \u0026quot;çÇ\u0026quot; ) nudeSymbols \u0026lt;- c( acute = \u0026quot;aeiouAEIOUyY\u0026quot;, grave = \u0026quot;aeiouAEIOU\u0026quot;, circunflex = \u0026quot;aeiouAEIOU\u0026quot;, tilde = \u0026quot;aoAOnN\u0026quot;, umlaut = \u0026quot;aeiouAEIOUy\u0026quot;, cedil = \u0026quot;cC\u0026quot; ) accentTypes \u0026lt;- c(\u0026quot;´\u0026quot;,\u0026quot;`\u0026quot;,\u0026quot;^\u0026quot;,\u0026quot;~\u0026quot;,\u0026quot;¨\u0026quot;,\u0026quot;ç\u0026quot;) if(any(c(\u0026quot;all\u0026quot;,\u0026quot;al\u0026quot;,\u0026quot;a\u0026quot;,\u0026quot;todos\u0026quot;,\u0026quot;t\u0026quot;,\u0026quot;to\u0026quot;,\u0026quot;tod\u0026quot;,\u0026quot;todo\u0026quot;)%in%pattern)) # opcao retirar todos return(chartr(paste(symbols, collapse=\u0026quot;\u0026quot;), paste(nudeSymbols, collapse=\u0026quot;\u0026quot;), str)) for(i in which(accentTypes%in%pattern)) str \u0026lt;- chartr(symbols[i],nudeSymbols[i], str) return(str) } Criar nossas próprias funções é muito simples em R e eu encorajo a todos a começarem a trabalhar com funções próprias também (além das nativas do R), pois o programa fica muito mais dinâmico e limpo.\nO pacote stringr Além do pacote dplyr, mais uma vez Hadley Wickham trás uma solução bastante útil para facilitar nossa vida de programador estatístico (ou cientista de dados se preferir, seguindo as “tendências da moda” de “data scientist”) com o pacote stringr, que possui uma sintaxe consistente, permitindo a manipulação de textos com muito mais facilidade.\nSeu uso consiste em uma variedade de utilidades que podem ser consultadas diretamente de dentro do R ao escrever str_ (após carregar o pacote) e aguardar um instante que a seguinte lista de funções será exibida:\nPortanto, inicialmente vamos carregar o pacote:\nlibrary(stringr) Com o pacote carregado já podemos fazer o uso de algumas das funções que são bem úteis.\nArrumando titulos de base de dados É muito comum que os cabeçalhos de uma base de dados venha repleta de caracteres especiais como este exemplo:\nnomes=c(\u0026#39;Aniversário\u0026#39;, \u0026#39;Situação\u0026#39;, \u0026#39;Raça\u0026#39;, \u0026#39;IMC\u0026#39;, \u0026#39;Tipo físico\u0026#39;, \u0026#39;tabaco por dia (cig/dia)\u0026#39;, \u0026#39;Alcool (dose/semana)\u0026#39;, \u0026#39;Drogas/g\u0026#39;, \u0026#39;Café/dia\u0026#39;, \u0026#39;Suco/dia\u0026#39;);nomes ## [1] \u0026quot;Aniversário\u0026quot; \u0026quot;Situação\u0026quot; ## [3] \u0026quot;Raça\u0026quot; \u0026quot;IMC\u0026quot; ## [5] \u0026quot;Tipo físico\u0026quot; \u0026quot;tabaco por dia (cig/dia)\u0026quot; ## [7] \u0026quot;Alcool (dose/semana)\u0026quot; \u0026quot;Drogas/g\u0026quot; ## [9] \u0026quot;Café/dia\u0026quot; \u0026quot;Suco/dia\u0026quot; Unindo as funções deste pacote com a sintaxe do pacote dplyr podemos elaborar uma função que irá facilitar bastante nas chamadas das colunas do data.frame na hora da análise, veja:\najustar_nomes=function(x){ x%\u0026gt;% stringr::str_trim() %\u0026gt;% #Remove espaços em branco sobrando stringr::str_to_lower() %\u0026gt;% #Converte todas as strings para minusculo rm_accent() %\u0026gt;% #Remove os acentos com a funcao criada acima stringr::str_replace_all(\u0026quot;[/\u0026#39; \u0026#39;.()]\u0026quot;, \u0026quot;_\u0026quot;) %\u0026gt;% #Substitui os caracteres especiais por \u0026quot;_\u0026quot; stringr::str_replace_all(\u0026quot;_+\u0026quot;, \u0026quot;_\u0026quot;) %\u0026gt;% #Substitui os caracteres especiais por \u0026quot;_\u0026quot; stringr::str_replace(\u0026quot;_$\u0026quot;, \u0026quot;\u0026quot;) #Substitui o caracter especiais por \u0026quot;_\u0026quot; } nomes=ajustar_nomes(nomes) nomes ## [1] \u0026quot;aniversario\u0026quot; \u0026quot;situacao\u0026quot; \u0026quot;raca\u0026quot; ## [4] \u0026quot;imc\u0026quot; \u0026quot;tipo_fisico\u0026quot; \u0026quot;tabaco_por_dia_cig_dia\u0026quot; ## [7] \u0026quot;alcool_dose_semana\u0026quot; \u0026quot;drogas_g\u0026quot; \u0026quot;cafe_dia\u0026quot; ## [10] \u0026quot;suco_dia\u0026quot; Função str_replace() e str_replace_all() Esse é o tipo de função que é utilizada com frequência. Utilizada para substituir ou remover uma (ou todas) as ocorrências de determinado carácter no objeto, suponha a seguinte situação:\nexemplo \u0026lt;- c(\u0026quot;o esperto\u0026quot;, \u0026quot;o doido\u0026quot;, \u0026quot;o normal\u0026quot;) Para remover a primeira vogal de cada string:\nstr_replace(exemplo, \u0026quot;[aeiou]\u0026quot;, \u0026quot;\u0026quot;) ## [1] \u0026quot; esperto\u0026quot; \u0026quot; doido\u0026quot; \u0026quot; normal\u0026quot; Para substitui todas as vogais por \"_\"\nstr_replace_all(exemplo, \u0026quot;[aeiou]\u0026quot;, \u0026quot;_\u0026quot;) ## [1] \u0026quot;_ _sp_rt_\u0026quot; \u0026quot;_ d__d_\u0026quot; \u0026quot;_ n_rm_l\u0026quot; Considere este novo exemplo:\nexemplo2 \u0026lt;- \u0026quot;O- ffffzx2, faifavuvuifoovvv fovvo\u0026quot; Para substitui o primeiro f (ou f’s) por “v”:\nexemplo2 \u0026lt;- str_replace(exemplo2, \u0026quot;f+\u0026quot;, \u0026quot;v\u0026quot;) exemplo2 ## [1] \u0026quot;O- vzx2, faifavuvuifoovvv fovvo\u0026quot; Para substituir todos os v’s (em sequência ou não) por “c”:\nexemplo2 \u0026lt;- str_replace_all(exemplo2, \u0026quot;v+\u0026quot;, \u0026quot;c\u0026quot;) exemplo2 ## [1] \u0026quot;O- czx2, faifacucuifooc foco\u0026quot; Função str_split() e str_split_fixed() Essas funções separam uma string em várias de acordo com um separador.\nfrase \u0026lt;- \u0026#39;Analisar palavras é muito legal. Apesar de todos os desafios as informações que podemos extrair podem revelar informações incrívelmente úteis. Esse exemplo esta sendo escrito pois vamos retirar cada frase desse paragrafo separadamente.\u0026#39; str_split(frase, fixed(\u0026#39;.\u0026#39;)) ## [[1]] ## [1] \u0026quot;Analisar palavras é muito legal\u0026quot; ## [2] \u0026quot; Apesar de todos os desafios as informações que podemos extrair podem revelar informações incrívelmente úteis\u0026quot; ## [3] \u0026quot; Esse exemplo esta sendo escrito pois vamos retirar cada frase desse paragrafo separadamente\u0026quot; ## [4] \u0026quot;\u0026quot; Função str_sub() Para obter uma parte fixa de uma string podemos utilizar o comando str_sub() da seguinte maneira:\n#Suponha as seguintes palavras: words=c(\u0026quot;00-casados\u0026quot;, \u0026quot;01-casamento\u0026quot;, \u0026quot;02-emprego\u0026quot;, \u0026quot;03-empregado\u0026quot;) Selecionado apenas do quarto até o último caracteres da string:\nstr_sub(words, start = 4) # começa no 4 caractere ## [1] \u0026quot;casados\u0026quot; \u0026quot;casamento\u0026quot; \u0026quot;emprego\u0026quot; \u0026quot;empregado\u0026quot; Selecionando apenas os dois primeiros caracteres da string:\nstr_sub(words, end = 2) # termina no 2 caractere ## [1] \u0026quot;00\u0026quot; \u0026quot;01\u0026quot; \u0026quot;02\u0026quot; \u0026quot;03\u0026quot; Para obter caracteres utilizando o sinal de negação -\n#Suponha: words \u0026lt;- c(\u0026quot;casamento-01\u0026quot;, \u0026quot;emprego-02\u0026quot;, \u0026quot;empregado-03\u0026quot;) str_sub(words, end = -4) #Seleciona todos os valores menos os últimos 3 ## [1] \u0026quot;casamento\u0026quot; \u0026quot;emprego\u0026quot; \u0026quot;empregado\u0026quot; str_sub(words, start = -2) #Seleciona todos os valores até o segundo valor ## [1] \u0026quot;01\u0026quot; \u0026quot;02\u0026quot; \u0026quot;03\u0026quot; Também é possível utilizar os argumentos end e start conjuntamente, veja\n#É possível usar os argumentos start e end conjuntamente. words \u0026lt;- c(\u0026quot;__casamento__\u0026quot;, \u0026quot;__emprego__\u0026quot;, \u0026quot;__empregado__\u0026quot;) str_sub(words, start=3, end=-3) ## [1] \u0026quot;casamento\u0026quot; \u0026quot;emprego\u0026quot; \u0026quot;empregado\u0026quot; A manipulação de strings é uma tarefa bem trabalhosa e algumas vezes até complexa porém cada desafio que surge ajuda bastante a entender esse mecanismo para manipulação de strings.\nPacote tm O pacote tm é um clássico para o text mining em R, quando os dados se apresentam de forma não estrutura, necessitam de uma preparação prévia que pode ser considerada um tipo de pré-processamento.\nInicialmente, carregando o pacote:\nlibrary(tm) Em bases de dados textuais, conhecidos como corpus ou corpora são tratado como “documentos” e cada “documento” em um corpus pode assumir diferentes características em relação ao tamanho do texto (sequências de caracteres), tipo de conteúdo (assunto abordado), língua na qual é escrito ou tipo de linguagem adotada dentro outros exemplos.\nA transformação de um corpus em um conjunto de dados que possa ser submetido à procedimentos de análise consiste em um processo que gera uma representação capaz de descrever cada documento em termos de suas características.\nPara criar um corpus a partir de um data.frame basta utilizar o seguinte comando:\n#Criando o corpus para o tratamento das variaveis com pacote library(tm): corpus \u0026lt;- Corpus(DataframeSource(x)) A seguir veremos algumas dos possíveis procedimentos para a manipulação de dados em um corpus.\nLimpeza de um corpus Uma sequência de comando interessantes para a limpeza de um corpus que já utilizei bastante é a seguinte:\n#Realizando a limpeza da base de dados: #Acrescentar mais stopwords para retirada; #novas=c() #Tratamento do corpus tratar_corpus=function(x){ x%\u0026gt;% tm_map(stripWhitespace)%\u0026gt;% #remover excessos de espaços em branco tm_map(removePunctuation)%\u0026gt;% #remover pontuacao tm_map(removeNumbers)%\u0026gt;% #remover numeros tm_map(removeWords, c(stopwords(\u0026quot;portuguese\u0026quot;),novas))%\u0026gt;% #remmover as stopwords,crie um vetor chamado \u0026quot;novas\u0026quot; para incluir novas stopwords tm_map(stripWhitespace)%\u0026gt;% #remover excessos de espaços em branco novamente tm_map(removeNumbers) #remover numeros novamente # tm_map(content_transformer(tolower))%\u0026gt;% #colocar todos caracteres como minusculo #tm_map(stemDocument) #Extraindo os radicais } corpus=tratar_corpus(corpus) #inspect(corpus[[3]]) #Leitura de algum documento específico Para criar a matriz de termos podemos utilizar o comando:\n#Criando a matrix de termos: corpus_tf=TermDocumentMatrix(corpus, control = list(minWordLength=2,minDocFreq=5)) Caso precise trabalhar com a transformação tf-idf basta utilizar:\n#Caso precise utilizar a medida tf-idf em um corpus: corpus_tf_idf=weightTfIdf(corpus_tf,normalize=T) Obtendo uma matriz de frequências a partir de um corpos Criando uma matriz para facilitar a manipulação dos dados\n#Transformando em matrix para permitir a manipulação: matriz = as.matrix(corpus_tf) #organizar os dados de forma decrescente matriz = sort(rowSums(matriz), decreasing=T) #criando um data.frame para a matriz matriz = data.frame(word=names(matriz), freq = matriz) Caso seja necessário conferir visualmente as palavras mais mencionadas, também podemos utilizar gráficos, como por exemplo:\n#Vejamos os primeiros 10 registros: head(matriz, n=10) ## word freq ## anos anos 242 ## pra pra 226 ## site site 156 ## cadastro cadastro 134 ## faz faz 124 ## fazer fazer 124 ## ver ver 114 ## todo todo 110 ## consegue consegue 102 ## gente gente 100 #Vejamos visualmente: head(matriz, n=10) %\u0026gt;% ggplot(aes(word, freq)) + geom_bar(stat = \u0026quot;identity\u0026quot;, color = \u0026quot;black\u0026quot;, fill = \u0026quot;#87CEFA\u0026quot;) + geom_text(aes(hjust = 1.3, label = freq)) + coord_flip() + labs(title = \u0026quot;20 Palavras mais mensionadas\u0026quot;, x = \u0026quot;Palavras\u0026quot;, y = \u0026quot;Número de usos\u0026quot;) N-gram Dictionary com RWeka Embora a análise de palavras realizada neste documento seja útil para a exploração inicial, o cientista de dados precisará construir um dicionário de bigrams, trigrams e quatro grams, coletivamente chamados de n-grams, que são frases de n palavras.\n“O Weka tem como objectivo agregar algoritmos provenientes de diferentes abordagens/paradigmas na sub-área da inteligência artificial dedicada ao estudo de aprendizagem de máquina.”-Wikipedia\nCarregando o pacote RWeka:\nlibrary(rJava) suppressMessages(library(RWeka)) BigramTokenizer \u0026lt;- function(x) NGramTokenizer(x, Weka_control(min = 2, max = 2)) TrigramTokenizer \u0026lt;- function(x) NGramTokenizer(x, Weka_control(min = 3, max = 3)) FourgramTokenizer \u0026lt;- function(x) NGramTokenizer(x, Weka_control(min = 4, max = 4)) Como exemplo, criaremos um dicionário de trigrams (frases de três palavras) e a função para construir um dicionário de n-gramas utilizando o pacote tm e o RWeka é:\n# tokenize into tri-grams trigram.Tdm \u0026lt;- tm::TermDocumentMatrix(corpus, control = list(tokenize = TrigramTokenizer)) Criando uma matriz para facilitar a manipulação dos dados\n#Transformando em matrix para permitir a manipulação: matriz = as.matrix(trigram.Tdm) #organizar os dados de forma decrescente matriz = sort(rowSums(matriz), decreasing=T) #criando um data.frame para a matriz matriz = data.frame(word=names(matriz), freq = matriz) #Vejamos os primeiros 20 registros: head(matriz, n=10) #Vejamos visualmente: head(matriz, n=10) %\u0026gt;% ggplot(aes(word, freq)) + geom_bar(stat = \u0026quot;identity\u0026quot;, color = \u0026quot;black\u0026quot;, fill = \u0026quot;#87CEFA\u0026quot;) + geom_text(aes(hjust = 1.3, label = freq)) + coord_flip() + labs(title = \u0026quot;20 frases mais mensionadas\u0026quot;, x = \u0026quot;Palavras\u0026quot;, y = \u0026quot;Número de usos\u0026quot;) Parece que este pacote parou de funcionar temporariamente, uma alternativa a este pacote pode ser o ngram e seu uso pode ser da seguinte forma:\nlibrary(ngram) ngrams=3 temp=ngram::ngram(ngram::concatenate(corpus),ngrams) # Objeto temporario recebe objeto que guarda sequencias temp=get.phrasetable(temp) # Obtendo tabela de sequencias do objeto acima temp$ngrams=temp$ngrams%\u0026gt;% # Limpeza das sequencias obtidas: str_replace_all(pattern = \u0026quot;^([A-Za-z] [A-Za-z])+\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% # Remover sequencias de apenas 1 letras str_replace_all(pattern = \u0026quot;[:punct:]\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% # Remover caracteres especiais str_replace_all(pattern = \u0026quot;\\n\u0026quot;,\u0026quot;\u0026quot;)%\u0026gt;% # Remover o marcador de \u0026quot;nova linha\u0026quot; str_trim() # Remover espaços em branco sobrando #Apos a limpeza.. temp=temp[temp$ngrams!=\u0026quot;\u0026quot;,] # Selecionando apenas as linhas que contenham informacao temp=temp%\u0026gt;% # Novamente manipulando o objeto que contem a tabela de sequencias group_by(ngrams) %\u0026gt;% # Agrupando por \u0026quot;ngrams\u0026quot; (sequencias obtidas) summarise(freq=sum(freq))%\u0026gt;% # Resumir as linhas repetidas pela soma das frequencias arrange(desc(freq))%\u0026gt;% # Organizando da maior para a menos frequencia as.matrix() # Alterando o tipo de objeto para matrix rownames(temp)=str_c(temp[,1]) # O nome das linhas passa a ser a sequencia correspondente v=sort(temp[,2],decreasing = T) # Retorna um objeto com as frequencias em ordem decrescente e linhas nomeadas data.frame(words = names(v),freq=v)%\u0026gt;% head(n=25)%\u0026gt;% ggplot(aes(words, freq)) + geom_bar(stat = \u0026quot;identity\u0026quot;, color = \u0026quot;black\u0026quot;, fill = \u0026quot;#87CEFA\u0026quot;) + geom_text(aes(hjust = 1.3, label = freq)) + coord_flip() + labs(title = \u0026quot;25 frases mais mensionadas\u0026quot;, x = \u0026quot;Palavras\u0026quot;, y = \u0026quot;Número de usos\u0026quot;) Package ‘SnowballC’ Caso seja necessário retirar o radical de um vetor de strings podemos utilizar a função ´wordStem´ do pacote SnowballC, caso queria conferir, existe o manual do pacote no CRAN\nwords=c(\u0026quot;casados\u0026quot;, \u0026quot;casamento\u0026quot;, \u0026quot;emprego\u0026quot;, \u0026quot;empregado\u0026quot;) SnowballC::getStemLanguages() ## [1] \u0026quot;arabic\u0026quot; \u0026quot;basque\u0026quot; \u0026quot;catalan\u0026quot; \u0026quot;danish\u0026quot; \u0026quot;dutch\u0026quot; ## [6] \u0026quot;english\u0026quot; \u0026quot;finnish\u0026quot; \u0026quot;french\u0026quot; \u0026quot;german\u0026quot; \u0026quot;greek\u0026quot; ## [11] \u0026quot;hindi\u0026quot; \u0026quot;hungarian\u0026quot; \u0026quot;indonesian\u0026quot; \u0026quot;irish\u0026quot; \u0026quot;italian\u0026quot; ## [16] \u0026quot;lithuanian\u0026quot; \u0026quot;nepali\u0026quot; \u0026quot;norwegian\u0026quot; \u0026quot;porter\u0026quot; \u0026quot;portuguese\u0026quot; ## [21] \u0026quot;romanian\u0026quot; \u0026quot;russian\u0026quot; \u0026quot;spanish\u0026quot; \u0026quot;swedish\u0026quot; \u0026quot;tamil\u0026quot; ## [26] \u0026quot;turkish\u0026quot; SnowballC::wordStem(words, language = \u0026quot;portuguese\u0026quot;) ## [1] \u0026quot;cas\u0026quot; \u0026quot;casament\u0026quot; \u0026quot;empreg\u0026quot; \u0026quot;empreg\u0026quot; Para um exemplo aplicado de text mining com tidytext e machine learning em textos, veja o post sobre análise de sentimentos no Twitter durante a Copa do Mundo.\nAtualização (2026) Nota acrescentada em 2026. O RWeka depende do Java e, como o texto original já indicava, costuma dar trabalho para manter funcionando. Hoje as alternativas mais usadas para text mining em R são o quanteda e o tidytext, que cobrem tokenização, n-grams e matrizes de termos sem a dependência do Java. A lógica de limpeza e stemming deste post continua igual.\nPerguntas frequentes Qual a diferença entre stringr e as funções base do R para strings? O stringr padroniza a sintaxe (todas as funções começam com str_ e recebem a string como primeiro argumento), o que facilita encadear com o operador pipe. As funções base (gsub, substr) fazem o mesmo, mas com nomes e ordens de argumento menos consistentes entre si.\nComo remover acentos de um vetor de strings no R? Não existe uma função nativa direta, mas a função rm_accent() apresentada neste post resolve isso usando chartr() para trocar cada caractere acentuado pelo equivalente sem acento. É útil sobretudo para padronizar nomes de colunas.\nVale a pena aprender o pacote tm hoje? Os conceitos (corpus, limpeza, matriz de termos, TF-IDF) continuam válidos e são a base de qualquer pipeline de text mining. Para projetos novos, vale considerar também o quanteda, que tende a ser mais rápido e com manutenção mais ativa.\n","date":"17 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-17-string/","section":"Posts","summary":" Manipulação de strings e Text mining Estudamos números e mais números na graduação de estatística (não sei nem se ainda consigo enxergar algarismos gregos como letras) e mesmo assim um problema frequente na vida de quem trabalha com dados é a manipulação de variáveis do tipo string.\nTL;DR\nstringr: sintaxe consistente para str_replace(), str_split(), str_sub() e mais. tm: cria e limpa um corpus de texto, gera matriz de termos e TF-IDF. SnowballC: extrai o radical das palavras (stemming) em português e outras línguas. Uma variável do tipo string é uma variável do tipo texto e esse tipo de objeto costuma causar alguns problemas na análise de dados se não forem devidamente tratados.\n","title":"Manipulação de Strings e Text Mining","type":"post"},{"content":" Além da limpeza da base de dados, das análises e da aplicação de metodologias estatísticas, escrever relatórios é uma tarefa indispensável e que ocupa boa parte do tempo de quem trabalha com dados. Como disse Khalil Gibran, é preciso transformar em palavras aquilo que já conhecemos em pensamentos. O problema é que ninguém quer gastar tempo precioso de análise brigando com a formatação do documento.\nÉ aí que entram os templates. O pacote tufte, disponível no CRAN, resolve isso para quem escreve em RMarkdown: ele traz um layout pronto, elegante e focado no conteúdo, para você formatar menos e analisar mais. Este post mostra o que é esse estilo, como instalar e como usar os recursos que o tornam diferente.\nTL;DR\nO pacote tufte traz o estilo de Edward Tufte para o RMarkdown, com três formatos de saída: tufte_html, tufte_handout (PDF) e tufte_book (PDF). A marca registrada é a margem lateral larga, onde ficam notas, pequenas figuras e tabelas sem interromper a leitura do texto principal. Para PDF é preciso usar latex_engine: xelatex no YAML, o que garante suporte a acentos em relatórios escritos em português. O que é o estilo Tufte? O estilo Tufte é inspirado nos livros de Edward Tufte, referência mundial em visualização de dados. A marca registrada é uma margem lateral larga: em vez de jogar as notas para o rodapé, elas ficam ao lado do texto, na mesma linha em que são citadas. Isso vale também para pequenas figuras e tabelas, que podem morar na margem sem interromper a leitura.\nO resultado é um documento limpo, com tipografia sóbria e pouca distração visual. A ideia por trás é simples: tirar do caminho tudo que não é conteúdo. Para relatórios técnicos, material didático e artigos, esse formato costuma comunicar melhor do que o layout tradicional de uma coluna só, com notas espremidas no pé da página.\nO pacote tufte no R Procurando uma solução na página do RStudio, me deparei com o pacote tufte no CRAN. Ele adapta o estilo Tufte para arquivos RMarkdown, com três formatos de saída:\ntufte_html: gera uma página HTML, ótima para publicar na web. tufte_handout: gera um PDF via LaTeX, no formato clássico de handout do Tufte. tufte_book: gera um livro em PDF, para documentos mais longos. Para instalar, basta uma linha:\ninstall.packages(\u0026quot;tufte\u0026quot;) Exemplo do handout Tufte. Imagem do manual do pacote tufte.\nCriando um documento Com o pacote instalado, criar um documento é direto no RStudio: acesse File \u0026gt; New File \u0026gt; R Markdown..., escolha a opção From Template e selecione o template do Tufte. Um novo arquivo já abre com a estrutura pronta para você preencher.\nCriando um documento a partir do template. Imagem do manual do pacote.\nO preâmbulo (YAML) O cabeçalho YAML é onde você escolhe o formato de saída e alguns ajustes. Um exemplo cobrindo os três formatos:\n--- title: \u0026quot;Título\u0026quot; subtitle: \u0026quot;Subtítulo\u0026quot; author: \u0026quot;Autor\u0026quot; date: \u0026quot;`r Sys.Date()`\u0026quot; output: tufte::tufte_html: default tufte::tufte_handout: highlight: tango latex_engine: xelatex citation_package: natbib tufte::tufte_book: latex_engine: xelatex bibliography: skeleton.bib link-citations: yes --- Dois pontos que valem atenção: o latex_engine: xelatex é o que garante o suporte a acentos no PDF, algo importante para relatórios em português, e o citation_package: natbib cuida das citações a partir do arquivo .bib. Fora isso, é só escrever e deixar o template cuidar da aparência.\nNotas e figuras na margem O recurso que dá identidade ao estilo é a margem. Alguns comandos que você vai usar bastante:\nNota lateral numerada: uma nota de rodapé comum já vira nota na margem. Escreva texto^[sua nota aqui] e ela aparece ao lado, numerada. Nota na margem sem número: use a função inline `r margin_note(\"sua nota\")`. Figura na margem: no chunk, adicione a opção fig.margin = TRUE. Figura em largura total: use fig.fullwidth = TRUE para a imagem ocupar texto e margem. São detalhes pequenos, mas é o que transforma um relatório comum em um documento com cara de publicação profissional. E o melhor: você continua escrevendo em RMarkdown normal, misturando texto, código e resultados, sem sair do fluxo. Se quiser dar um passo atrás e automatizar a geração desses relatórios, escrevi também sobre relatórios automáticos com RMarkdown.\nQuando vale a pena usar? O template Tufte brilha em relatórios técnicos, material didático, notas de aula e artigos, ou seja, tudo que é feito para ser lido com calma e se beneficia das notas de margem. Como escrever relatórios é parte central do trabalho de quem faz ciência de dados, ter um formato bonito e reaproveitável economiza muito tempo ao longo do ano. Se o formato final que você precisa é Word em vez de PDF, veja também o post sobre como produzir e formatar um documento Word direto do R.\nNão é a melhor escolha para tudo, claro. Para dashboards interativos, apresentações de slides ou documentos com muitas figuras que precisam de largura total, outros formatos se encaixam melhor. Mas para o relatório do dia a dia, é difícil achar algo com essa relação entre esforço e elegância.\nAtualização (2026): e o Quarto? Nota acrescentada em 2026. O RMarkdown continua funcionando normalmente, mas hoje o Quarto é o sucessor natural dele e também oferece um formato no estilo Tufte. Se você está começando um projeto novo, vale conhecer o Quarto: a lógica é a mesma, e boa parte do que está aqui se aplica quase sem mudança.\nPerguntas frequentes Preciso saber LaTeX para usar o template Tufte? Não. Para a saída em HTML (tufte_html) você não precisa de LaTeX nenhum. Para gerar PDF (tufte_handout), é preciso ter uma distribuição LaTeX instalada, mas você não escreve LaTeX na mão: o RMarkdown cuida da conversão a partir do seu texto.\nFunciona com acentos, para relatórios em português? Sim. Na saída HTML os acentos funcionam direto. Para o PDF, use latex_engine: xelatex no preâmbulo, como no exemplo acima. O xelatex lida bem com a acentuação e evita os erros clássicos de codificação de caracteres do LaTeX tradicional.\nDevo escolher tufte_html ou tufte_handout? Depende do destino do documento. Se ele vai para a web ou para leitura na tela, o tufte_html é mais prático e não exige LaTeX. Se o objetivo é um PDF para imprimir ou distribuir formalmente, o tufte_handout entrega o visual clássico dos handouts do Tufte.\n","date":"14 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-14-criando-relatorios-com-template-tufte/","section":"Posts","summary":"Além da limpeza da base de dados, das análises e da aplicação de metodologias estatísticas, escrever relatórios é uma tarefa indispensável e que ocupa boa parte do tempo de quem trabalha com dados. Como disse Khalil Gibran, é preciso transformar em palavras aquilo que já conhecemos em pensamentos. O problema é que ninguém quer gastar tempo precioso de análise brigando com a formatação do documento.\nÉ aí que entram os templates. O pacote tufte, disponível no CRAN, resolve isso para quem escreve em RMarkdown: ele traz um layout pronto, elegante e focado no conteúdo, para você formatar menos e analisar mais. Este post mostra o que é esse estilo, como instalar e como usar os recursos que o tornam diferente.\n","title":"Criando Relatórios com o Template Tufte no R (RMarkdown)","type":"post"},{"content":"","date":"14 de dezembro de 2017","externalUrl":null,"permalink":"/tags/tufte/","section":"Tags","summary":"","title":"Tufte","type":"tags"},{"content":" O pacote dplyr A análise exploratória dos dados é uma tarefa de bastante relevância para entendermos a natureza dos dados e o tempo de análise é sempre muito precioso. É necessária bastante curiosidade e criatividade para fazer uma boa análise exploratória dos dados pois é difícil receber aqueles dados bonitinhos igual aos nativos do banco de dados do R.\nA manipulação de dados é uma das etapas que mais consomem tempo em qualquer projeto, como comento no panorama da ciência de dados que escrevi para quem está começando. Aqui o foco é numa das ferramentas centrais para essa tarefa.\nExistem diversos pacotes para as mais variadas necessidades dos cientistas de dados (ou qualquer pessoa que precise fazer alguma análise ou programação estatística) disponíveis no CRAN e hoje quero registrar aqui algumas das funcionalidades do pacote dplyr que são muito úteis.\nÉ um dos pacotes mais poderosos e populares do R, desenvolvido por Hadley Wickham, faz a exploração de dados e permite a manipulação de dados de forma fácil e rápida no R.\nSegundo sua descrição no CRAN, o dplyr é definido como uma ferramenta rápida e consistente para trabalhar com data.frames como objetos, tanto na memória quanto fora da memória. Vamos conferir então o que de tão especial tem nesse pacote.\nTL;DR\nO operador pipe %\u0026gt;% encadeia operações no formato x %\u0026gt;% f(), lido como \"pegue x e aplique f\". filter(), select(), arrange(), mutate() e summarise() cobrem a maioria das tarefas de manipulação de dados. inner_join(), left_join() e afins combinam bases diferentes por uma chave comum. Operador pipe: %\u0026gt;% O operador %\u0026gt;% é uma opção incrivelmente útil para a manipulação dos dados, funcionando com uma lógica diferente da nativa do R, que executa funções no formato f(x), o pipe permite que façamos operações no formato x %\u0026gt;% f() que basicamente funciona da maneira como raciocinamos: “Pega esse objeto e executa isso, depois isso, depois isso…” Realiza múltiplas ações sem guardar os passos intermediários.\nVamos começar carregando o pacote:\n# Carregando o pacote dplyr suppressMessages(library(dplyr)) Selecionando n linhas aleatorias: função sample_n() # Selecionando 5 linhas aleatoriamente df%\u0026gt;% sample_n(5) Removendo linhas duplicadas: função distinct() Baseado em todas as variáveis # excluindo linhas iguais df%\u0026gt;% distinct() Baseado em uma variável # excluindo linhas que possuem Datas iguais df%\u0026gt;% distinct(Datas) Baseado em mais de uma variável # excluindo linhas que possuem ano e consumo iguais df%\u0026gt;% distinct(ano, consumo) Selecionando colunas (variáveis): função select() # Selecionando a variavel ano e todas as variáveis de sucesso até tonalidade na df df%\u0026gt;% select(ano, sucesso:tonalidade) # Selecionando todas as variaveis com exceção de ano e id df%\u0026gt;% select(-c(ano,id)) # Selecionando todas as variaveis cujo nome inicia com e df%\u0026gt;% select(starts_with(\u0026quot;a\u0026quot;)) Podem ser úteis também ends_with() e contains(). Reordenando as as colunas das variáveis: função select() # reorganiza o data frame, iniciando com a variável Datas e depois as demais df%\u0026gt;% select(Datas,everything()) Renomeando variáveis: função rename() # Renomeando a variável Datas para micro df%\u0026gt;% rename(Dia = Datas) Selecionando um subconjunto de linhas que satisfazem uma ou mais condições: função filter() # Selecionando somente os indivíduos do sexo masculino df%\u0026gt;% filter( sexo == \u0026quot;Masculino\u0026quot;) # Selecionando somente os indivíduos do sexo masculino e branco df%\u0026gt;% filter( sexo == \u0026quot;Masculino\u0026quot; \u0026amp; tonalidade == \u0026quot;Branco\u0026quot;) # Selecionando somente os indivíduos com consumo de 1 a 3 anos e 4 a 7 anos df%\u0026gt;% filter( consumo %in% c(\u0026quot;1 a 3\u0026quot;,\u0026quot;4 a 7\u0026quot;)) # Selecionando indivíduos que ou são homens solteiros ou são mulheres casadas df%\u0026gt;% filter( (estado_civil==\u0026quot;Solteiro\u0026quot; \u0026amp; sexo ==\u0026quot;Masculino\u0026quot;) | (estado_civil==\u0026quot;Casado\u0026quot; \u0026amp; sexo ==\u0026quot;Feminino\u0026quot;) ) Ordenando seus data frames: função arrange() # Ordenando os dados pela variável ano de forma crescente df%\u0026gt;% arrange( ano ) # Ordenando os dados pela variável ano e consumo df%\u0026gt;% arrange( ano ,consumo) # Ordenando os dados pela variável ano de forma decrescente df%\u0026gt;% arrange( desc(ano) ) Criando uma nova variável: função mutate() e transmute() # Criando a variável ano ao quadrado df%\u0026gt;% mutate( ano2 = ano**2 ) # Criando a variável Dia e a variável Mes df%\u0026gt;% mutate( Dia = substring(Datas,1,2), Mes = substring(mensalidade,1,1) ) # Se você quiser somente manter as variáveis criadas df18 = transmute(mensalidade = substring(Datas,1,2), Mes = substring(mensalidade,1,1) ) Resumindo variáveis: função summarize() # Calculando a media e a mediana da variável ano df%\u0026gt;% summarise( media.ano = mean(ano), mediana.ano = median(ano)) Resumindo variáveis por grupo: função group_by() e summarize() # Calculando a media da variável ano para as combinações entre sexo, consumo e estado civil e a frequencia de indivíduos em cada combinação df%\u0026gt;% group_by(sexo, consumo, estado_civil)%\u0026gt;% summarise(media.ano = mean(ano),frequencia=n()) # Calculando a media da variável ano para as combinações entre ano legal, consumo e estado civil e a frequencia de indivíduos em cada combinação df%\u0026gt;% group_by(id, consumo, estado_civil)%\u0026gt;% summarise(media.ano = mean(ano),frequencia=n()) Mais exemplos com o operador pipe Portanto, o operador %\u0026gt;% realiza múltiplas ações sem guardar os passos intermediários. Mais alguns exemplos:\n# Selecionando as variáveis ano e id df %\u0026gt;% select(ano,id) df %\u0026gt;% select(-estado_civil) %\u0026gt;% filter(sexo==\u0026quot;Masculino\u0026quot;) %\u0026gt;% group_by(tonalidade,consumo) %\u0026gt;% summarise(maximo=max(ano),media=mean(ano)) Aplicando funções em linhas df%\u0026gt;% mutate(ano2 = ano**2 )%\u0026gt;% rowwise() %\u0026gt;% mutate(Max= max(ano:ano2)) %\u0026gt;% select(ano,ano2,Max) Fazendo a união de banco de dados distintos Combinando duas bases de dados O pacote dplyr possui um conjunto de funções que nos auxiliam a combinar dos data frames do nosso interesse.\ninner_join # Função inner_join: Combina as duas bases incluindo todas as variáveis de ambas as bases e todas as linhas comuns as duas bases inner_join(df1,df2,by=\u0026quot;ID\u0026quot;) inner_join(df1,df3,by=c(\u0026quot;ID\u0026quot;=\u0026quot;Identificacao\u0026quot;)) left_join # Função left_join: Combina as duas bases incluindo todas as variáveis de ambas as bases e todas as linhas da base a esquerda left_join(df1,df2,by=\u0026quot;ID\u0026quot;) right_join # Função right_join: Combina as duas bases incluindo todas as variáveis de ambas as bases e todas as linhas da base a direita right_join(df1,df2,by=\u0026quot;ID\u0026quot;) full_join # Função full_join: Combina as duas bases incluindo todas as variáveis de ambas as bases e todas as linhas de ambas as bases full_join(df1,df2,by=\u0026quot;ID\u0026quot;) semi_join # Função semi_join: Combina as duas bases incluindo as variáveis da basea a esquerda e todas as linhas comuns as duas bases semi_join(df1,df2,by=\u0026quot;ID\u0026quot;) anti_join # Função anti_join: Combina as duas bases incluindo as variáveis da base a esquerda e todas as linhas que não são comuns as duas bases anti_join(df1,df2,by=\u0026quot;ID\u0026quot;) Combinando dados verticalmente Juntando por linhas comuns com intersect #Criando uma base com as linhas comus as duas bases intersect(d1,d2) Juntando todas as linhas com union #Criando uma base unindo todas as linhas das duas bases union(d1,d3) Base com linhas distintas nas duas bases com setdiff #Criando uma base com as linhas distintas nas duas bases setdiff(d1,d3) Empilhando duas bases uma sobre a outra com rbind #Empilhando duas bases, uma em cima da outra rbind(d1,d3) Empilhando duas bases lado a lado com cbind #Empilhando duas bases, uma ao lado da outra cbind(d3,d4) É realmente impressionante como este pacote pode impulsionar nossas habilidades na manipulação de dados! Espero que a partir de hoje o %\u0026gt;% não seja mais visto coisa “esquisita”\nPara outras ferramentas do dia a dia de quem manipula dados, veja os posts sobre como criar tabelas para apresentar resultados e sobre a estratégia split-apply-combine, que combina o dplyr com o purrr para tarefas mais complexas.\nPerguntas frequentes Qual a diferença entre filter() e select() no dplyr? filter() seleciona linhas que satisfazem uma condição (por exemplo, sexo == \"Masculino\"). select() seleciona colunas pelo nome. Os dois se combinam livremente no mesmo pipe para reduzir tanto linhas quanto colunas de uma vez.\nO que o operador pipe (%\u0026gt;%) faz exatamente? Ele passa o resultado de uma expressão como primeiro argumento da próxima função, permitindo escrever x %\u0026gt;% f() %\u0026gt;% g() em vez de g(f(x)). O código fica na ordem em que você pensa a operação: pegue x, faça isso, depois isso.\nComo combinar duas bases de dados diferentes com dplyr? Use uma das funções de join: inner_join() mantém só as linhas que existem nas duas bases, left_join() mantém todas as linhas da base à esquerda, full_join() mantém todas as linhas de ambas. A escolha depende de qual base é \"a referência\" da combinação.\n","date":"7 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-07-manipulando-dados-com-dplyr/","section":"Posts","summary":" O pacote dplyr A análise exploratória dos dados é uma tarefa de bastante relevância para entendermos a natureza dos dados e o tempo de análise é sempre muito precioso. É necessária bastante curiosidade e criatividade para fazer uma boa análise exploratória dos dados pois é difícil receber aqueles dados bonitinhos igual aos nativos do banco de dados do R.\nA manipulação de dados é uma das etapas que mais consomem tempo em qualquer projeto, como comento no panorama da ciência de dados que escrevi para quem está começando. Aqui o foco é numa das ferramentas centrais para essa tarefa.\n","title":"Manipulando dados com dplyr","type":"post"},{"content":" ⚠️ Aviso (2026): Os pacotes e APIs usados neste post são de 2017 e foram descontinuados: o coinmarketcapr passou a exigir chave de API paga e a API da BlinkTrade foi encerrada. A lógica de extrair, tratar e monitorar dados no R ainda é válida — veja a versão moderna com agentes de IA em Equipe Multiagente para Análise do Bitcoin.\nAs cryptomoedas Quem acompanha os jornais já deve ter notado que o mercado de cryptomoedas vem crescendo rapidamente, e grandes canais de informação já cobrem o assunto. A cotação do Bitcoin já pode ser acompanhada nos maiores sites do mercado financeiro. Diante de tantas novidades, vale entender como a programação pode ajudar a explorar temas tão recentes.\nSurge então a pergunta: como o R pode nos ajudar a analisar cryptomoedas? Vejamos o que encontramos no CRAN.\nTL;DR\nO pacote coinmarketcapr extrai preço e capitalização de mercado das principais cryptomoedas. O jsonlite consome APIs de cotação direto no R. Com um loop simples dá para montar um monitor de preços do Bitcoin que atualiza sozinho. Pacote coinmarketcapr Tem disponível no CRAN o pacote coinmarketcapr que nos permite extrair e monitorar o preço e o limite de mercado das cryptomoedas da API do coinmarketcap.com\nPrimeiramente precisamos instalar o pacote:\ninstall.packages(\u0026quot;coinmarketcapr\u0026quot;) library(coinmarketcapr) Maiores ocorrências O pacote conta com a função plot_top_5_currencies() que já apresenta de brinde um gráfico de barras com as 5 principais cryptomoedas do mercado, veja:\nplot_top_5_currencies() Detalhes do mercado Os resultados ficam disponíveis para quem quiser interpretar. É importante notar que isso não nos da a imagem de como o mercado está dividido entre várias cryptomoedas, então vamos obter os dados completos de várias cryptomoedas:\nmercado_hoje \u0026lt;- get_marketcap_ticker_all() head(mercado_hoje[,1:8]) Visualmente Após extrair os dados completos de várias cryptomoedas, vamos visualizar essa distribuição através de um treemap com os códigos:\nlibrary(treemap) base \u0026lt;- na.omit(mercado_hoje[,c(\u0026#39;id\u0026#39;,\u0026#39;market_cap_usd\u0026#39;)]) base$market_cap_usd \u0026lt;- as.numeric(base$market_cap_usd) base$formatted_market_cap \u0026lt;- paste0(base$id,\u0026#39;\\n\u0026#39;,\u0026#39;$\u0026#39;,format(base$market_cap_usd,big.mark = \u0026#39;,\u0026#39;,scientific = F, trim = T)) treemap(base, index = \u0026#39;formatted_market_cap\u0026#39;, vSize = \u0026#39;market_cap_usd\u0026#39;, title = \u0026#39;Cryptocurrency Market Cap\u0026#39;, fontsize.labels=c(12, 8), palette=\u0026#39;RdYlGn\u0026#39;) Vou deixar as interpretações para os analistas de mercado, mas como um cientista de dados, muitos (muitos mesmo) insights podem ser extraídos dos dados acima e pode ser interessante analisar esse mercado\nPacote jsonlite para avaliar Bitcoins O pacote jsonlite disponível no CRAN trás série de recursos flexíveis, robustos e de alto desempenho para trabalhar o R com JSON conjuntamente. O pacote é capaz de interagir com API da Web e isso vai ser o recurso que precisamos aqui.\nTrazendo o foco para os Bitcoins, existe mais de uma maneira de se extrair os dados do mercado que possam trazer grandes insights. Vamos conferir aqui como este pacote pode ajudar nesta tarefa.\nInicialmente precisamos instalar e carregar o pacote:\n#install.packages(\u0026quot;jsonlite\u0026quot;) library(jsonlite) suppressMessages(library(tidyverse)) #Para manipulação de dados Com o pacote carregado já podemos realizar uma consulta diretamente de dentro do R com o comando safe_fromJSON().\nOs preços da bitcoin são fornecidos pela API da BlinkTrade que é bem simples usar, basta pegar o json que a url do código abaixo solta.\nAproveito e dou um tapinha para deixar em forma de data.frame e com a data de consulta junto.\nsafe_fromJSON = safely(fromJSON, as.numneric(NA)) nova_consulta_list = safe_fromJSON(\u0026quot;http://api.blinktrade.com/api/v1/BRL/ticker?crypto_currency=BTC\u0026quot;) nova_consulta = nova_consulta_list$result %\u0026gt;% as.tibble %\u0026gt;% mutate(timestamp = lubridate::now()) nova_consulta Loop infinito para acompanhar os preço Existe um universo de infinitas possibilidades para acompanhar estes dados, trago aqui um loop infinito (while(TRUE)) composto por um , um data.frame histórico.RData, um tempo entre uma consulta e outra (30 segundos por padrão) e a consulta propriamente dita. Veja:\n#Inicializa o historico.RData historico = nova_consulta save(historico, file = \u0026quot;historico.RData\u0026quot;) Dando início ao loop:\n#loop infinito while(TRUE){ #pega a cotacao do bitcoin brasil (BTCBRL) da API do blinktrade nova_consulta_list = safe_fromJSON(\u0026quot;http://api.blinktrade.com/api/v1/BRL/ticker?crypto_currency=BTC\u0026quot;) #verifica se a API retornou uma lista if(\u0026quot;list\u0026quot; %in% class(nova_consulta_list$result)){ nova_consulta = nova_consulta_list$result %\u0026gt;% as.tibble %\u0026gt;% mutate(timestamp = lubridate::now()) # # # espaco reservado para as regras! # # #guarda a consulta historico = bind_rows(historico, nova_consulta) save(historico, file = \u0026quot;historico.RData\u0026quot;) } #condicoes #Exemplo: #if(nova_consulta$buy \u0026gt; 14600 \u0026amp; nova_consulta$last \u0026lt; 14500){ # #Fazer alguma coisa # # #} } Também podemos acompanhar graficamente incluindo um gráfico dentro do loop, veja:\nwhile(TRUE){ #pega a cotacao do bitcoin brasil (BTCBRL) da API do blinktrade nova_consulta_list = safe_fromJSON(\u0026quot;http://api.blinktrade.com/api/v1/BRL/ticker?crypto_currency=BTC\u0026quot;) #verifica se a API retornou uma lista if(\u0026quot;list\u0026quot; %in% class(nova_consulta_list$result)){ nova_consulta = nova_consulta_list$result %\u0026gt;% as.tibble %\u0026gt;% mutate(timestamp = lubridate::now()) # # # espaco reservado para as regras! # # #guarda a consulta historico = bind_rows(historico, nova_consulta) save(historico, file = \u0026quot;historico.RData\u0026quot;) } #Cria um gráfico; ggplot(historico %\u0026gt;% gather(indicador, valor, high, low, buy, sell, last))+ geom_line(aes(x=timestamp, y=valor, color=indicador)) #condicoes #if(nova_consulta$buy \u0026gt; 14600 \u0026amp; nova_consulta$last \u0026lt; 14500){ # # Fazer alguma coisa # #} } Este gráfico retornará algo como:\nEste gráfico será atualizado em tempo real!\nAtualização (2026) Nota acrescentada em 2026. Os pacotes e APIs deste post são de 2017 e mudaram bastante: o coinmarketcapr passou a exigir uma chave de API do CoinMarketCap, e a API da BlinkTrade usada para o Bitcoin foi descontinuada. A lógica continua válida: extrair dados de uma API, tratar no R e monitorar em loop. Para uma versão moderna da ideia, veja como montei um agente de IA para análise de Bitcoin.\nPerguntas frequentes Qual pacote usar para dados de cryptomoedas no R? Para um panorama rápido do mercado (ranking e capitalização), o coinmarketcapr resolve com poucas linhas. Para consultar qualquer API de cotação e ter controle total sobre os dados, o jsonlite é o mais flexível, lendo o JSON direto para um data.frame.\nDá para monitorar o preço do Bitcoin em tempo real no R? Sim. Um loop while(TRUE) que consulta a API de cotação a cada intervalo (por exemplo, 30 segundos), guarda o histórico e atualiza um gráfico já resolve. É a base de um monitor simples, e o ponto onde você encaixaria regras de alerta ou de compra e venda.\nO código deste post ainda funciona hoje? Em parte. A lógica continua válida, mas as fontes mudaram: o coinmarketcapr agora exige chave de API e a BlinkTrade foi descontinuada. Troque a fonte de dados por uma API atual e o restante do fluxo segue igual.\n","date":"4 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-04-analisando-o-mercado-de-cryptomoedas-com-r/","section":"Posts","summary":" ⚠️ Aviso (2026): Os pacotes e APIs usados neste post são de 2017 e foram descontinuados: o coinmarketcapr passou a exigir chave de API paga e a API da BlinkTrade foi encerrada. A lógica de extrair, tratar e monitorar dados no R ainda é válida — veja a versão moderna com agentes de IA em Equipe Multiagente para Análise do Bitcoin.\nAs cryptomoedas Quem acompanha os jornais já deve ter notado que o mercado de cryptomoedas vem crescendo rapidamente, e grandes canais de informação já cobrem o assunto. A cotação do Bitcoin já pode ser acompanhada nos maiores sites do mercado financeiro. Diante de tantas novidades, vale entender como a programação pode ajudar a explorar temas tão recentes.\n","title":"Analisando o mercado de cryptomoedas com R","type":"post"},{"content":"","date":"4 de dezembro de 2017","externalUrl":null,"permalink":"/tags/cryptomoedas/","section":"Tags","summary":"","title":"Cryptomoedas","type":"tags"},{"content":"","date":"4 de dezembro de 2017","externalUrl":null,"permalink":"/tags/dropbox/","section":"Tags","summary":"","title":"Dropbox","type":"tags"},{"content":" ⚠️ Nota (2026): Este post foi reescrito. A versão original usava o pacote rdrop2, que dependia da API v1 do Dropbox — descontinuada desde setembro de 2023. O conteúdo abaixo mostra a abordagem atual com httr2 + API v2. A versão original foi preservada em index-old.html neste mesmo bundle para consulta.\nArmazenar arquivos na nuvem é prática comum, e o Dropbox é um dos serviços mais usados para isso. Saber interagir com esses arquivos por código é uma habilidade valiosa para quem trabalha com dados: automatizar o vai e vem de arquivos economiza tempo, elimina erro manual e permite integrar fontes de dados externas em pipelines reprodutíveis.\nÉ parte do trabalho de ciência de dados integrar as fontes onde os dados moram. Neste post mostro como fazer isso usando o pacote httr2 diretamente com a API v2 do Dropbox — a única API ativa desde que a v1 foi encerrada. O código é um pouco mais verboso do que o rdrop2 de antigamente, mas é completamente independente de pacotes de terceiros específicos do Dropbox e segue um padrão aplicável a qualquer API REST.\nTL;DR\nO pacote rdrop2 usava a API v1 do Dropbox, descontinuada em 2023 — não funciona mais. A alternativa atual é httr2 com OAuth2 PKCE contra a API v2 do Dropbox. Com menos de 50 linhas de código você autentica, lista, sobe, baixa e lê arquivos CSV diretamente no R. O token pode ser salvo em disco e reutilizado em sessões futuras sem nova autenticação interativa. Por que o rdrop2 parou de funcionar? O pacote rdrop2 foi durante anos a solução padrão para integrar Dropbox com R. O problema é que ele usava a API v1 do Dropbox, que foi oficialmente encerrada em setembro de 2023. Desde então, qualquer chamada feita por esse pacote retorna erro 400 ou 401. O pacote não foi atualizado para a v2, e não há perspectiva clara de que isso aconteça.\nA boa notícia é que a API v2 do Dropbox é bem documentada, usa OAuth2 padrão e o httr2 — disponível no CRAN desde 2022 e mantido pela equipe do tidyverse — tem suporte nativo a esse fluxo de autenticação. A migração leva menos de uma hora.\nConfiguração inicial: criando o app no Dropbox Antes de qualquer código, você precisa registrar um app no painel de desenvolvedores do Dropbox para obter as credenciais de acesso.\nAcesse dropbox.com/developers/apps e clique em Create app. Escolha Scoped access → Full Dropbox (ou App folder se preferir acesso restrito a uma pasta). Dê um nome ao seu app (ex.: meu-r-dropbox). Na aba Settings do app, copie o App key e o App secret. Em OAuth2 → Redirect URIs, adicione http://localhost:1410/ (porta padrão usada pelo httr2 para o fluxo de código de autorização local). Na aba Permissions, habilite ao menos: files.content.read, files.content.write, files.metadata.read. Com as credenciais em mãos, adicione-as ao seu .Renviron — nunca as coloque direto no código:\nusethis::edit_r_environ() # Adicione as linhas abaixo e salve: # DROPBOX_APP_KEY=sua_chave_aqui # DROPBOX_APP_SECRET=seu_segredo_aqui Reinicie a sessão do R para que as variáveis sejam lidas.\nAutenticação OAuth2 com httr2 O httr2 implementa o fluxo Authorization Code with PKCE, que é o recomendado pelo Dropbox para apps que rodam localmente. Na primeira execução, uma janela do navegador abre para você autorizar o app; o token retorna automaticamente para a sessão R.\nlibrary(httr2) # Definindo o cliente OAuth2 dropbox_client \u0026lt;- oauth_client( id = Sys.getenv(\u0026quot;DROPBOX_APP_KEY\u0026quot;), secret = Sys.getenv(\u0026quot;DROPBOX_APP_SECRET\u0026quot;), token_url = \u0026quot;https://api.dropboxapi.com/oauth2/token\u0026quot;, name = \u0026quot;dropbox-r-client\u0026quot; ) # Autenticação interativa (abre o navegador uma única vez) token \u0026lt;- oauth_flow_auth_code( client = dropbox_client, auth_url = \u0026quot;https://www.dropbox.com/oauth2/authorize\u0026quot;, pkce = TRUE ) Salvando e reutilizando o token Para não precisar autorizar no navegador toda vez que iniciar uma sessão, salve o token em disco e carregue-o nas sessões seguintes:\n# Salvar (faça isso uma vez após o oauth_flow_auth_code) saveRDS(token, \u0026quot;~/.dropbox_token.rds\u0026quot;) # Carregar em sessões futuras token \u0026lt;- readRDS(\u0026quot;~/.dropbox_token.rds\u0026quot;) Uma ressalva de segurança: esse arquivo .rds é uma credencial de acesso à sua conta. Adicione o caminho ao .gitignore e nunca o publique junto com o código.\nListando arquivos e pastas O endpoint /2/files/list_folder retorna os itens de um diretório. Passamos a string vazia \u0026quot;\u0026quot; para listar a raiz:\nlist_dropbox \u0026lt;- function(path = \u0026quot;\u0026quot;, token) { request(\u0026quot;https://api.dropboxapi.com/2/files/list_folder\u0026quot;) |\u0026gt; req_auth_bearer_token(token$access_token) |\u0026gt; req_body_json(list(path = path)) |\u0026gt; req_perform() |\u0026gt; resp_body_json() } # Listar raiz resultado \u0026lt;- list_dropbox(\u0026quot;\u0026quot;, token) # Ver apenas os nomes sapply(resultado$entries, `[[`, \u0026quot;name\u0026quot;) # Filtrar só pastas entries \u0026lt;- resultado$entries pastas \u0026lt;- Filter(function(e) e[[\u0026quot;.tag\u0026quot;]] == \u0026quot;folder\u0026quot;, entries) sapply(pastas, `[[`, \u0026quot;name\u0026quot;) Fazendo upload de um arquivo O upload usa o endpoint de conteúdo (content.dropboxapi.com) e envia o arquivo como bytes brutos no corpo da requisição. Os metadados (caminho de destino, modo de conflito) vão no cabeçalho Dropbox-API-Arg como JSON:\nupload_dropbox \u0026lt;- function(local_path, dropbox_path, token) { request(\u0026quot;https://content.dropboxapi.com/2/files/upload\u0026quot;) |\u0026gt; req_auth_bearer_token(token$access_token) |\u0026gt; req_headers( `Dropbox-API-Arg` = jsonlite::toJSON( list(path = dropbox_path, mode = \u0026quot;overwrite\u0026quot;, autorename = FALSE), auto_unbox = TRUE ), `Content-Type` = \u0026quot;application/octet-stream\u0026quot; ) |\u0026gt; req_body_raw(readBin(local_path, raw(), file.info(local_path)$size)) |\u0026gt; req_perform() } # Exemplo: enviar o dataset trees write.csv(trees, \u0026quot;trees.csv\u0026quot;) upload_dropbox(\u0026quot;trees.csv\u0026quot;, \u0026quot;/trees.csv\u0026quot;, token) Fazendo download de um arquivo O download segue a mesma lógica: o caminho do arquivo no Dropbox vai no cabeçalho Dropbox-API-Arg e o corpo da resposta contém os bytes do arquivo:\ndownload_dropbox \u0026lt;- function(dropbox_path, local_path, token) { request(\u0026quot;https://content.dropboxapi.com/2/files/download\u0026quot;) |\u0026gt; req_auth_bearer_token(token$access_token) |\u0026gt; req_headers( `Dropbox-API-Arg` = jsonlite::toJSON( list(path = dropbox_path), auto_unbox = TRUE ) ) |\u0026gt; req_perform() |\u0026gt; resp_body_raw() |\u0026gt; writeBin(local_path) } # Exemplo: baixar trees.csv do Dropbox download_dropbox(\u0026quot;/trees.csv\u0026quot;, \u0026quot;trees_local.csv\u0026quot;, token) Lendo um CSV direto do Dropbox para o R Uma das operações mais úteis em pipelines de dados é ler um arquivo da nuvem sem precisar salvá-lo em disco. A função abaixo faz o download como texto e passa direto para read.csv() via textConnection():\nread_csv_dropbox \u0026lt;- function(dropbox_path, token) { raw_text \u0026lt;- request(\u0026quot;https://content.dropboxapi.com/2/files/download\u0026quot;) |\u0026gt; req_auth_bearer_token(token$access_token) |\u0026gt; req_headers( `Dropbox-API-Arg` = jsonlite::toJSON( list(path = dropbox_path), auto_unbox = TRUE ) ) |\u0026gt; req_perform() |\u0026gt; resp_body_string() read.csv(textConnection(raw_text)) } # Exemplo: ler trees.csv direto do Dropbox new_trees \u0026lt;- read_csv_dropbox(\u0026quot;/trees.csv\u0026quot;, token) head(new_trees) Se o seu arquivo usa separadores ou codificações específicas, você pode passar os mesmos argumentos extras que passaria para read.csv() — por exemplo sep = \u0026quot;;\u0026quot; ou encoding = \u0026quot;latin1\u0026quot;.\nComparação com o rdrop2 (abordagem antiga) A tabela abaixo mostra lado a lado a sintaxe do rdrop2 e a equivalente com httr2 + API v2, para as operações mais comuns:\nOperação rdrop2 (API v1 — descontinuada) httr2 + API v2 (atual) Autenticação drop_auth() oauth_flow_auth_code(client, auth_url, pkce = TRUE) Salvar token saveRDS(token, \u0026quot;token.rds\u0026quot;) saveRDS(token, \u0026quot;~/.dropbox_token.rds\u0026quot;) Listar arquivos drop_dir() list_dropbox(\u0026quot;\u0026quot;, token) (função customizada) Upload drop_upload(\u0026quot;trees.csv\u0026quot;) upload_dropbox(\u0026quot;trees.csv\u0026quot;, \u0026quot;/trees.csv\u0026quot;, token) Download drop_download(\u0026quot;trees.csv\u0026quot;) download_dropbox(\u0026quot;/trees.csv\u0026quot;, \u0026quot;local.csv\u0026quot;, token) Ler CSV direto drop_read_csv(\u0026quot;trees.csv\u0026quot;) read_csv_dropbox(\u0026quot;/trees.csv\u0026quot;, token) A principal diferença prática é que com httr2 você escreve funções wrapper explícitas, mas em compensação não depende de um pacote específico que pode ficar desatualizado. Uma vez que você entende o padrão de request() |\u0026gt; req_* |\u0026gt; req_perform() |\u0026gt; resp_*(), ele se aplica a qualquer API REST — não só ao Dropbox.\nPerguntas frequentes Preciso autenticar toda vez que uso o httr2 com o Dropbox? Não. Você autentica uma vez com oauth_flow_auth_code(), salva o token com saveRDS() e reusa nas próximas sessões carregando esse arquivo com readRDS(). Lembre de tratar o token como uma credencial: nunca o versione no Git nem o publique junto com o código. Se o token expirar (tokens offline do Dropbox são de longa duração, mas podem ser revogados), basta repetir o fluxo de autenticação.\nDá para ler um arquivo do Dropbox sem salvar em disco? Sim. A função read_csv_dropbox() apresentada neste post baixa o conteúdo como texto e passa direto para read.csv() via textConnection(), sem criar nenhum arquivo temporário explicitamente. Isso é especialmente útil em pipelines automatizados onde você não quer gerenciar arquivos intermediários.\nO httr2 suporta arquivos grandes no upload? Para arquivos pequenos e médios, req_body_raw() funciona bem. Para arquivos maiores que 150 MB o Dropbox recomenda o endpoint de upload session (/2/files/upload_session/start, /2/files/upload_session/append_v2, /2/files/upload_session/finish), que divide o envio em partes. O httr2 suporta isso com múltiplas chamadas — o padrão é o mesmo, apenas com mais requisições encadeadas.\n","date":"4 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-04-gerenciando-arquivos-do-dropbox-com-r/","section":"Posts","summary":" ⚠️ Nota (2026): Este post foi reescrito. A versão original usava o pacote rdrop2, que dependia da API v1 do Dropbox — descontinuada desde setembro de 2023. O conteúdo abaixo mostra a abordagem atual com httr2 + API v2. A versão original foi preservada em index-old.html neste mesmo bundle para consulta.\nArmazenar arquivos na nuvem é prática comum, e o Dropbox é um dos serviços mais usados para isso. Saber interagir com esses arquivos por código é uma habilidade valiosa para quem trabalha com dados: automatizar o vai e vem de arquivos economiza tempo, elimina erro manual e permite integrar fontes de dados externas em pipelines reprodutíveis.\n","title":"Gerenciando arquivos do Dropbox com R e httr2: a abordagem moderna","type":"post"},{"content":" Tipos de relações Vimos no último post sobre tipos de correlações quais tipos de medidas de correlação e associação podem ser calculadas para identificar o grau de associação (ou dependência) entre as variáveis. Um exemplo prático dessas técnicas aplicadas a dados reais pode ser visto na análise do mercado de criptomoedas com R.\nJá sabemos que esses coeficientes variam entre 0 e 1 ou entre -1 e +1, de maneira que a proximidade de zero indique a falta de associação entre elas.\nPorém o que fazer com tantas métricas? Qual o cálculo mais aconselhado para as relações dois a dois de cada tipo de variáveis (medidas, quantidades, nomes, classes com algum tipo de ordem ou hierarquia)?\nNão basta chegar no R e fazer um pairs(dados) junto com cor(dados) e olhar aquele monte de números sem saber se eles apresentam algum resultado realmente relevante embasado na teoria estatística.\nTL;DR\nA escolha da medida de correlação depende do tipo das duas variáveis envolvidas: numérica, ordinal ou nominal. Para pares numérica x numérica normais e lineares usa-se Pearson; sem normalidade ou linearidade, Spearman ou Kendall. Para pares nominais usam-se qui-quadrado, teste exato de Fisher e medidas de associação como V de Crámer e Kappa. Vejamos então os tipos de relações possíveis e quais tipos de medidas podem ser utilizadas a seguir.\nNumérica x Numérica Tipos de medidas que podem ser utilizadas:\nPearson (Intensidade de relacionamento linear) Spearman (Relação monotônica entre dados emparelhados) Kendall (Correlação entre duas variáveis ordinais de amostras pequenas) Graficamente Um jeito informal e intuitivo de avaliar a relação é verificar se existe relação linear entre as variáveis, além de identificar se esta relação é positiva, negativa ou inexistente.\nDuas variaveis Algumas opções de como avaliar graficamente duas variáveis:\n## `geom_smooth()` using formula \u0026#39;y ~ x\u0026#39; Mais de duas variáveis Quando existe a presença de mais de duas variáveis em estudo podemos utilizar outras características gráficas além do eixo x e y para identificar padrões, veja:\nNormalidade A suposição de normalidade é amplamente utilizada na estatística.\nGraficamente Avaliando a normalidade de forma visual com alguns comandos do ggplot:\n### Verificando a Normalidade Através do Histograma # Criando um painel com o espaço de 4 gráficos par(mfrow=c(2,2)) #preenchendo os quatro espaços com 4 histogramas (um para cada variável) histogram=function(x){ hist(x,prob=T) lines(density(x),col=\u0026quot;red\u0026quot;) curve(dnorm(x,mean(x), sd(x)),add=T,col=\u0026quot;blue\u0026quot;) } histogram(dados$GASTEDU) histogram(dados$GASAUDE) histogram(dados$GASLAZER) histogram(dados$IDADE) QQ-plot Compara os quantis dos dados com os quantis de uma normal padrão\npar(mfrow=c(2,2)) ### Verificando a Normalidade Através do QQplot qq = function(x){ qqnorm(x,main = \u0026quot;\u0026quot;, xlab = \u0026quot;Quantis teóricos N(0,1)\u0026quot;, pch = 20) qqline(x, lty = 1, col = \u0026quot;red\u0026quot;) } qq(dados$IDADE) qq(dados$GASAUDE) qq(dados$GASLAZER) qq(dados$GASTEDU) QQ plot com envelope Incluindo uma região de aceitação, para cada ponto constroi o intervalo de confiança\n#Envelope envelope\u0026lt;-function(x){ n \u0026lt;- length(x) nsim \u0026lt;- 100 # Número de simulações conf \u0026lt;- 0.95 # Coef. de confiança # Dados simulados ~ normal dadossim \u0026lt;- matrix(rnorm(n*nsim, mean = mean(x), sd = sd(x)), nrow = n) dadossim \u0026lt;- apply(dadossim,2,sort) # Limites da banda e média infsup\u0026lt;-apply(dadossim,1,quantile, probs = c((1 - conf) / 2,(1 + conf) / 2)) xbsim \u0026lt;- rowMeans(dadossim) faixay \u0026lt;- range(x, dadossim) qq0 \u0026lt;- qqnorm(x, main = \u0026quot;\u0026quot;, xlab = \u0026quot;Quantis teóricos N(0,1)\u0026quot;, pch = 20, ylim = faixay) eixox \u0026lt;- sort(qq0$x) lines(eixox, xbsim) lines(eixox, infsup[1,], col = \u0026quot;red\u0026quot;) lines(eixox, infsup[2,], col = \u0026quot;red\u0026quot;) } par(mfrow=c(2,2)) envelope(dados$GASTEDU) envelope(dados$GASAUDE) envelope(dados$GASLAZER) envelope(dados$IDADE) Testes A seguir, diversos testes de hipóteses para avaliar:\n\\[ H_0: \\text{Dados Normais} \\\\ H_1: \\text{Dados Não Normais} \\]\nA seguir uma função que criei colocando logo uma variedade de testes para fornecer diferentes evidências para nossa hipótese:\nnormalidade\u0026lt;-function(x){ t1 \u0026lt;- ks.test(x, \u0026quot;pnorm\u0026quot;,mean(x), sd(x)) # KS t2 \u0026lt;- lillie.test(x) # Lilliefors t3 \u0026lt;- cvm.test(x) # Cramér-von Mises t4 \u0026lt;- shapiro.test(x) # Shapiro-Wilk t5 \u0026lt;- sf.test(x) # Shapiro-Francia t6 \u0026lt;- ad.test(x) # Anderson-Darling t7\u0026lt;-pearson.test(x) # Pearson Test of Normality testes \u0026lt;- c(t1$method, t2$method, t3$method, t4$method, t5$method,t6$method,t7$method) valorp \u0026lt;- c(t1$p.value, t2$p.value, t3$p.value, t4$p.value, t5$p.value,t6$p.value,t7$p.value) resultados \u0026lt;- cbind(valorp) rownames(resultados) \u0026lt;- testes print(resultados, digits = 4) } normalidade(dados$GASAUDE) ## valorp ## One-sample Kolmogorov-Smirnov test 0.9238 ## Lilliefors (Kolmogorov-Smirnov) normality test 0.6494 ## Cramer-von Mises normality test 0.6605 ## Shapiro-Wilk normality test 0.6297 ## Shapiro-Francia normality test 0.6286 ## Anderson-Darling normality test 0.6346 ## Pearson chi-square normality test 0.3249 Dados normais + Relação linear Quando os dados são normais e a relação entre variáveis é linear, podemos utilizar os mesmos testes já comentados:\nPearson Spearman (amostras maiores) Kendall (amostras pequenas) Coeficiente de Correlação de Pearson \\(\\rho\\) No R:\n#Matriz de correlações: cor(dados$GASTEDU,dados$GASAUDE) ## [1] 0.77825 Como saber se a correlação é significativa?\n\\[ H_0: \\text{Não existe correlação} \\\\ H_1: \\text{Existe correlação} \\]\nAplicando o teste:\n#Teste de correlação: cor.test(dados$GASTEDU,dados$GASAUDE,method = \u0026quot;pearson\u0026quot;) Dados não normais e/ou sem relação linear Quando os dados não se apresentam conforme a distribuição normal ou não apresentam relação linear, temos disponíveis o cálculo das seguintes correlações:\nSpearman (amostras maiores) kendall (amostras pequenas) Coeficiente de Correlação de Spearman \\(\\rho\\) Ideal quando temos variáveis medidas apenas em uma escala ordinal.\nExecutando no R:\n#Teste de correlação: cor.test(dados$GASTEDU,dados$GASAUDE,method = \u0026quot;spearman\u0026quot;) Coeficiente de Correlação de Kendall (\\(\\tau\\) de kendall) Coeficiente de Kendall é, muitas vezes, interpretado como uma medida de concordância entre dois conjuntos de classificações relativas a um conjunto de objetos de estudo.\nVamos considerar apenas os 20 primeiros elementos da amostra:\nAplicação no R:\n#Teste de correlação: cor.test(dados2$IDADE,dados2$GASAUDE,method = \u0026quot;kendall\u0026quot;) Ordinal x Ordinal Tipos de correlações possíveis para calcular:\nSpearman (amostras maiores) kendall (amostras pequenas) Exemplo de uso de Spearman no R:\ncor(dados$ESCOLAR, dados$RENDA, method = \u0026quot;spearman\u0026quot;) cor.test(dados$ESCOLAR, dados$RENDA, method = \u0026quot;spearman\u0026quot;) Exemplo de uso de Kendall com uma amostra menor:\ncor(dados2$ESCOLAR, dados2$RENDA, method = \u0026quot;kendall\u0026quot;) cor.test(dados2$ESCOLAR, dados2$RENDA, method = \u0026quot;kendall\u0026quot;) Numérica x Ordinal Independente de ser normal ou não\nSpearman (amostras maiores) Kendall (amostras pequenas) Comparações de grupos (Testes de Hipóteses) Exemplo de uso de Spearman no R:\ncor(dados$IDADE, dados$RENDA, method = \u0026quot;spearman\u0026quot;) cor.test(dados$IDADE, dados$RENDA, method = \u0026quot;spearman\u0026quot;) Exemplo de uso de Kendall com uma amostra menor:\ncor(dados2$IDADE, dados2$RENDA, method = \u0026quot;kendall\u0026quot;) cor.test(dados2$IDADE, dados2$RENDA, method = \u0026quot;kendall\u0026quot;) Nominal x Nominal Os termos nível nominal de medida ou escala nominal são utilizadas para se referir a àqueles dados que só podem ser categorizados. No sentido estrito, não existe uma medida ou escala envolvida, o que existe é apenas uma contagem.\nVamos avaliar a profissão e o estado civil primeiramente, precisamos da tabela de contingência.\nTabelas de Contingência (ou tabelas de freqüência de dupla entrada) são tabelas em que as frequências correspondem a duas classificações, uma classificação está nas linhas da tabela e a outra está nas colunas. Veja:\ntab=ftable(as.factor(dados$PROFI), as.factor(dados$ESTCIVIL), dnn=c(\u0026quot;Profissão\u0026quot;, \u0026quot;EStado Civil\u0026quot;)) tab ## EStado Civil 1 2 3 4 ## Profissão ## 1 26 13 29 1 ## 2 24 6 21 0 Qui-quadrado de independencia \\[ H_0: \\text{São independentes (Não associadas)} \\\\ H_1: \\text{Não são independentes (São associadas) } \\]\nExecutando o teste:\nchisq.test(dados$PROFI, dados$ESTCIVIL) ## ## Pearson\u0026#39;s Chi-squared test ## ## data: dados$PROFI and dados$ESTCIVIL ## X-squared = 2.2905, df = 3, p-value = 0.5143 OBS: Correção de YAKES quando existe alguma frequência esperada menor do que 5, veja:\nTeste exato de fisher O teste qui-quadrado quando aplicado a amostras pequenas, como por exemplo com tamanho inferior a 20, veja:\nfisher.test(dados2$PROFI, dados2$ESTCIVIL) ## ## Fisher\u0026#39;s Exact Test for Count Data ## ## data: dados2$PROFI and dados2$ESTCIVIL ## p-value = 0.5226 ## alternative hypothesis: two.sided Medidas de associação os testes fornecem apenas a resposta se as variáveis estão ou não correlacionadas. Para saber a intensidade desta relação, utilizam-se medidas de associação.\nConsidere as seguintes medidas:\n\\(\\mathbf{\\phi}\\) (phi) (é o R de pearson quando aplicado a tabelas 2x2) V de Crámer Coeficiente de contingência Ambos variam de 0 (ausência de associação) a 1 (associação muito forte).\n#Comando para tabela cruzada: tab \u0026lt;- xtabs(~ PROFI + ESTCIVIL, data = dados) #Calcular as medidas de associação da tabela: summary(assocstats(tab)) ## ## Call: xtabs(formula = ~PROFI + ESTCIVIL, data = dados) ## Number of cases in table: 120 ## Number of factors: 2 ## Test for independence of all factors: ## Chisq = 2.2905, df = 3, p-value = 0.5143 ## Chi-squared approximation may be incorrect ## X^2 df P(\u0026gt; X^2) ## Likelihood Ratio 2.6823 3 0.44324 ## Pearson 2.2905 3 0.51435 ## ## Phi-Coefficient : NA ## Contingency Coeff.: 0.137 ## Cramer\u0026#39;s V : 0.138 #phi (r aplicado na Tabela de 2x2 --\u0026gt; Phi) cor(dados$PROFI,dados$ESTCIVIL) ## [1] -0.06972599 Kappa É uma medida de concordância.\nObs: Também pode ser utilizado o coeficiente de Kappa ponderado (pesquisar)\n#Kappa medico1\u0026lt;-sample(0:1,10, replace=T) medico2\u0026lt;-sample(0:1,10, replace=T) #Kappa.test(x, y=NULL, conf.level=0.95) fmsb::Kappa.test(medico1,medico2) ## $Result ## ## Estimate Cohen\u0026#39;s kappa statistics and test the null hypothesis that ## the extent of agreement is same as random (kappa=0) ## ## data: medico1 and medico2 ## Z = -1.2649, p-value = 0.897 ## 95 percent confidence interval: ## -0.9680515 0.1680515 ## sample estimates: ## [1] -0.4 ## ## ## $Judgement ## [1] \u0026quot;No agreement\u0026quot; Nominal x Ordinal Vamos avaliar a profissão e o estado civil primeiramente, precisamos da tabela de contingência:\ntab=ftable(as.factor(dados$PROFI), as.factor(dados$RENDA), dnn=c(\u0026quot;Profissão\u0026quot;, \u0026quot;Renda\u0026quot;)) tab ## Renda 1 2 3 4 ## Profissão ## 1 4 52 9 4 ## 2 0 30 17 4 Qui-quadrado de independencia \\[ H_0: \\text{São independentes (Não associadas)} \\\\ H_1: \\text{Não são independentes (São associadas) } \\]\nExecutando o teste:\nchisq.test(dados$PROFI, dados$RENDA) ## ## Pearson\u0026#39;s Chi-squared test ## ## data: dados$PROFI and dados$RENDA ## X-squared = 9.8864, df = 3, p-value = 0.01956 OBS: Correção de YAKES quando existe alguma frequência esperada menor do que 5, veja:\nTeste exato de fisher O teste qui-quadrado quando aplicado a amostras pequenas, como por exemplo com tamanho inferior a 20, veja:\nfisher.test(dados2$PROFI, dados2$RENDA) ## ## Fisher\u0026#39;s Exact Test for Count Data ## ## data: dados2$PROFI and dados2$RENDA ## p-value = 1 ## alternative hypothesis: two.sided Medidas de associação os testes fornecem apenas a resposta se as variáveis estão ou não correlacionadas. Para saber a intensidade desta relação, utilizam-se medidas de associação.\nConsidere as seguintes medidas:\n\\(\\mathbf{\\phi}\\) (phi) (é o R de pearson quando aplicado a tabelas 2x2) V de Crámer Coeficiente de contingência Ambos variam de 0 (ausência de associação) a 1 (associação muito forte).\n#Comando para tabela cruzada: tab \u0026lt;- xtabs(~ PROFI + RENDA, data = dados) #Calcular as medidas de associação da tabela: summary(assocstats(tab)) ## ## Call: xtabs(formula = ~PROFI + RENDA, data = dados) ## Number of cases in table: 120 ## Number of factors: 2 ## Test for independence of all factors: ## Chisq = 9.886, df = 3, p-value = 0.01956 ## Chi-squared approximation may be incorrect ## X^2 df P(\u0026gt; X^2) ## Likelihood Ratio 11.3123 3 0.010152 ## Pearson 9.8864 3 0.019557 ## ## Phi-Coefficient : NA ## Contingency Coeff.: 0.276 ## Cramer\u0026#39;s V : 0.287 #phi (r aplicado na Tabela de 2x2 --\u0026gt; Phi) cor(dados$PROFI,dados$RENDA) ## [1] 0.231198 Kappa Testa a concordância entre duas pessoas (a hipótese nula é de que a concordância é zero)\n#Kappa medico1\u0026lt;-sample(0:1,10, replace=T) medico2\u0026lt;-sample(0:1,10, replace=T) #Kappa.test(x, y=NULL, conf.level=0.95) fmsb::Kappa.test(medico1,medico2) ## $Result ## ## Estimate Cohen\u0026#39;s kappa statistics and test the null hypothesis that ## the extent of agreement is same as random (kappa=0) ## ## data: medico1 and medico2 ## Z = 0.2538, p-value = 0.3998 ## 95 percent confidence interval: ## -0.4998102 0.6479584 ## sample estimates: ## [1] 0.07407407 ## ## ## $Judgement ## [1] \u0026quot;Slight agreement\u0026quot; Dicotônica x Ordinal Uma variável dicotômica é uma variável qualitativa que só possui duas categorias.\nPortanto a mesma abordagem utilizada em:\nDicotômica x Ordinal = Nominal x Ordinal = Nominal x Nominal\nNominal x Numérca \\(R^2\\) do ajuste de modelos lineares Pode-se ajustar um modelo de regressão linear simples e avaliar seu coeficiente de determinação, veja:\n#R2: summary(lm(dados$GASAUDE~dados$ESTCIVIL))$r.squared ## [1] 0.0001015817 Bisserial = Pearson O pearson aplicada em uma relação de variável dicotômica com uma variável ordinal\nComparações de Grupos Quando por exemplo, trabalha-se com “renda por grupo”, existem muitas abordagens como o teste t ou anova como opções de testes paramétricos e muito mais\nCorrelação parcial Controlando variável numérica Pode ser que queremos estudar a correlação entre x e y, porém existem uma variável z que também está correlacionada com alguma das duas variáveis, veja:\n## `geom_smooth()` using formula \u0026#39;y ~ x\u0026#39; ## [1] 0.7821115 ## `geom_smooth()` using formula \u0026#39;y ~ x\u0026#39; ## [1] 0.7476177 ## [1] 0.7821115 ## `geom_smooth()` using formula \u0026#39;y ~ x\u0026#39; ## [1] 0.77825 Isto implica que a variável educação é uma variável de confusão, veja as correlações:\n## Registered S3 method overwritten by \u0026#39;GGally\u0026#39;: ## method from ## +.gg ggplot2 O que acontece com a associação entre lazer e saúde quando controlamos a variável de confusão educação?\n# correlação LAZER vc SAÚDE controlando o EDUCAÇÃO (correlação parcial de primeira ordem = um variável para controlar) rp\u0026lt;-ggm::pcor(c(\u0026quot;GASLAZER\u0026quot;, \u0026quot;GASAUDE\u0026quot;, \u0026quot;GASTEDU\u0026quot;),var(dados)) #controlando A EDUCAÇÃO #Significância da Correlação Parcial #Coeficiente de Determinação com base no Coef. de Pearson r\u0026lt;-cor(dados$GASLAZER,dados$GASAUDE) #sem controlar o lazer #Coeficiente de Determinação com base na correlação parcial pcor.test(rp,1,length(dados$GASAUDE)) #\u0026quot;1\u0026quot; porque só usamos uma variável de controle ## $tval ## [1] 5.922106 ## ## $df ## [1] 117 ## ## $pvalue ## [1] 3.259388e-08 data.frame(\u0026quot;Sem correção\u0026quot;=r^2, \u0026quot;Com correção\u0026quot;=rp^2) ## Sem.correção Com.correção ## 1 0.6116985 0.2306242 Controlando variável Qualitativa A variável de controle (ou qualquer uma delas) pode ser dicotômica (categórica)\n#Visualmente: ggplot(data = dados, aes(x = GASLAZER, y = GASAUDE,colour = as.factor(PROFI))) + geom_point() #Sem controlar: r=cor(dados$GASLAZER, dados$GASAUDE) rp\u0026lt;-pcor(c(\u0026quot;GASLAZER\u0026quot;, \u0026quot;GASAUDE\u0026quot;, \u0026quot;PROFI\u0026quot;),var(dados)) data.frame(\u0026quot;Sem correção\u0026quot;=r^2, \u0026quot;Com correção\u0026quot;=rp^2) ## Sem.correção Com.correção ## 1 0.6116985 0.6162497 Referências CONOVER, W. J. Pratical Nonparametric Statistics SIEGEL, S. Estatística Não Paramétrica para as Ciências do Comportamento BUSSAB, W. de O.;MORETTIN, P. A. Estatística básica. 5 ed. Perguntas frequentes Qual medida de correlação usar entre duas variáveis numéricas?\nSe os dados forem normais e a relação for linear, use Pearson. Caso contrário, prefira Spearman (amostras maiores) ou Kendall (amostras pequenas).\nComo avaliar a associação entre duas variáveis nominais?\nUse o teste qui-quadrado de independência ou o teste exato de Fisher para amostras pequenas, e complemente com medidas de associação como V de Crámer ou coeficiente de contingência.\nO que é correlação parcial e para que serve?\nÉ a correlação entre duas variáveis controlando o efeito de uma terceira variável de confusão, permitindo identificar se parte da relação observada é explicada por essa terceira variável.\n","date":"2 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-02-tipos-de-relacoes-entre-variaveis/","section":"Posts","summary":" Tipos de relações Vimos no último post sobre tipos de correlações quais tipos de medidas de correlação e associação podem ser calculadas para identificar o grau de associação (ou dependência) entre as variáveis. Um exemplo prático dessas técnicas aplicadas a dados reais pode ser visto na análise do mercado de criptomoedas com R.\nJá sabemos que esses coeficientes variam entre 0 e 1 ou entre -1 e +1, de maneira que a proximidade de zero indique a falta de associação entre elas.\n","title":"Tipos de relações entre variáveis","type":"post"},{"content":"Encontrar dados confiáveis é metade do trabalho em qualquer projeto de análise, visualização ou aprendizado de máquina. A melhor forma de ganhar tempo é começar com fontes bem documentadas, com contexto claro e com exemplos práticos de uso.\nKey Takeaways\nComece por fontes brasileiras e internacionais com boa documentação e metadados claros. Prefira datasets com descrição do schema, licenciamento e contexto de coleta. Para projetos reais, vale separar as bases por tema, facilidade de uso e tipo de análise. Onde começar # Se eu estivesse escolhendo hoje, eu começaria por três tipos de fonte: repositórios governamentais, plataformas especializadas em datasets e bases voltadas para áreas específicas como saúde, economia ou visão computacional. Essa divisão costuma ser mais útil do que tentar guardar tudo em uma única lista.\nComece pelo seu objetivo # Se você quer encontrar um dataset rapidamente, a melhor forma é pensar no problema que quer resolver. A tabela abaixo ajuda a escolher o caminho mais direto.\nSe o seu objetivo é Comece por Análise econômica e social IPEA DATA, IBGE, Banco Central, OECD, Banco Mundial Saúde, educação e demografia Datasus, Microdados do ENEM, Life expectancy, HealthData.gov Machine learning e NLP Kaggle, UCI, OpenML, NLP Datasets, Paperswithcode Visão computacional MiniPlaces, The car brands dataset, The Planet dataset Ensino e projetos introdutórios Palmer Penguins, Datasaurus, Pokemon, Baby Names Dados para economia, governo e sociedade # Essa é a melhor seção para quem quer trabalhar com indicadores públicos, finanças, demografia ou políticas públicas.\nRecurso Área Descrição IPEA DATA Economia Séries históricas e indicadores sociais, econômicos e setoriais. IBGE Demografia Fonte principal para censos, pesquisas e estatísticas do Brasil. Banco Central Finanças Séries sobre inflação, juros, câmbio e atividade econômica. Portal da transparência Governo Gastos públicos, contratos e despesas de órgãos federais. Portal brasileiro de dados abertos Governo Catálogo nacional de datasets abertos do governo brasileiro. OECD Economia internacional Estatísticas comparativas entre países membros da OCDE. Banco Mundial Desenvolvimento Dados globais sobre economia, saúde, educação e desenvolvimento. Dados do Governo do Canadá Governo Portal de dados abertos do governo canadense. Dados do Governo do Reino Unido Governo Portal público do Reino Unido com muitos datasets abertos. Dados da União Europeia Governo Catálogo europeu de dados abertos e estatísticas. Dados do Censo dos EUA Demografia Dados socioeconômicos e demográficos do censo americano. Dados para saúde, educação e demografia # Útil para projetos acadêmicos, análise social ou estudos de comportamento populacional.\nRecurso Área Descrição Datasus Saúde Dados públicos sobre morbidade, mortalidade e acesso a serviços de saúde. Microdados do ENEM Educação Microdados do ENEM para análise educacional. HealthData.gov Saúde Dados públicos sobre saúde e indicadores governamentais. Life expectancy (WHO) Saúde Base com indicadores de expectativa de vida e fatores socioeconômicos. World Happiness Report Bem-estar Indicadores de felicidade e qualidade de vida por país. Baby Names Demografia Frequência de nomes de bebês por ano. Dados para machine learning e NLP # Para quem quer treinar modelos, praticar ciência de dados ou explorar problemas reais.\nRecurso Área Descrição Kaggle Geral Plataforma com milhares de datasets, competições e notebooks. UCI Machine Learning Repository ML Repositório clássico e muito usado em estudos de aprendizado de máquina. OpenML ML Biblioteca aberta com datasets e tarefas para experimentos. NLP Datasets NLP Repositório de datasets para processamento de linguagem natural. Paperswithcode IA Coleção de datasets usados em papers e benchmarks. Data Driven Datasets Ciência de dados Problemas reais com dados ligados a causas sociais e ambientais. Kaggle Kernels Educação Ambiente para reproduzir análises e explorar notebooks públicos. Datasets – Google AI IA Coleção de datasets úteis para pesquisa em machine learning. Amazon Public Datasets Computação Repositórios públicos da Amazon para dados e benchmarks. Copa KDD Data mining Conjuntos usados em competições históricas de mineração de dados. Dados para visão computacional # Para projetos com imagens, classificação e reconhecimento visual, essas bases costumam ser um bom ponto de partida.\nRecurso Tema Descrição MiniPlaces Imagens Base pequena e útil para classificação de cenas. The car brands dataset Imagens Conjunto de imagens de marcas de carros para classificação visual. The Planet dataset: Understanding the Amazon Sensoriamento remoto Dados satelitais usados para segmentação e análise ambiental. Fruit datasets Imagens Coleção de imagens de frutas para classificação e visão computacional. Santa or not dataset (code) Imagens Dataset simples para treinar um classificador binário de imagens. Reconhecimento de Faces Visão computacional Bases de imagens para reconhecimento facial. Datasets para ensino e projetos introdutórios # Esta lista costuma ser útil para aprender estatística, explorar dados com pouco contexto técnico e montar pequenos projetos.\nRecurso Tema Descrição Palmer Penguins Biologia Dataset clássico e visualmente atrativo para ensinar estatística. Datasaurus Estatística Exemplo famoso de como gráficos podem esconder diferenças. Pokemon Jogos Dataset de personagens e características do universo Pokémon. Cereal Alimentos Dados sobre cereais matinais para análise exploratória. Spotify Música Grande base com características de músicas e popularidade. Disney Plus Shows Entretenimento Dataset de séries e filmes da plataforma Disney+. Strange Sightings with Bigfoot and UFO / UFO Sightings Curiosidades Dados de relatos de avistamentos para explorar análise de texto. YaRrr! Estatística Pacote em R com dados e exemplos divertidos para ensinar estatística. Como escolher um dataset # Antes de baixar qualquer base, vale verificar se ela traz: descrição clara das colunas, contexto de coleta, licenciamento, frequência de atualização e exemplos de uso. Dados muito interessantes, mas mal documentados, costumam virar um problema depois.\nSe você estiver montando um projeto rápido, eu começaria pelos repositórios brasileiros e pelos datasets de Kaggle, porque a documentação e a variedade de exemplos ajudam bastante. Para análise mais séria, vale combinar uma base governamental com uma fonte complementar em um repositório mais técnico.\nPara aprender a trabalhar com esses dados, uma boa pedida é seguir os canais do YouTube para cientistas de dados recomendados no blog.\n","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/resources/public-datasets/","section":"Recursos","summary":"Encontrar dados confiáveis é metade do trabalho em qualquer projeto de análise, visualização ou aprendizado de máquina. A melhor forma de ganhar tempo é começar com fontes bem documentadas, com contexto claro e com exemplos práticos de uso.\nKey Takeaways\nComece por fontes brasileiras e internacionais com boa documentação e metadados claros. Prefira datasets com descrição do schema, licenciamento e contexto de coleta. Para projetos reais, vale separar as bases por tema, facilidade de uso e tipo de análise. Onde começar # Se eu estivesse escolhendo hoje, eu começaria por três tipos de fonte: repositórios governamentais, plataformas especializadas em datasets e bases voltadas para áreas específicas como saúde, economia ou visão computacional. Essa divisão costuma ser mais útil do que tentar guardar tudo em uma única lista.\n","title":"Bancos de dados públicos","type":"resources"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/ciencia-de-dados/","section":"Tags","summary":"","title":"Ciência De Dados","type":"tags"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/cramer/","section":"Tags","summary":"","title":"Cramer","type":"tags"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/dados-abertos/","section":"Tags","summary":"","title":"Dados Abertos","type":"tags"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/datasets/","section":"Tags","summary":"","title":"Datasets","type":"tags"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/kappa/","section":"Tags","summary":"","title":"Kappa","type":"tags"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/qui-quadrado/","section":"Tags","summary":"","title":"Qui-Quadrado","type":"tags"},{"content":"Essas são algumas das frases que me impactaram de alguma forma e que eu carrego para a minha vida:\n\u0026ldquo;Com organização e tempo, acha-se o segredo de fazer tudo e bem feito.\u0026rdquo; - Pitágoras\n\u0026ldquo;A imaginação é mais importante que o conhecimento.\u0026rdquo; - Albert Einstein\n\u0026ldquo;Na vida, não existe nada a temer, mas a entender.\u0026rdquo; - Marie Curie\n\u0026ldquo;A matemática foi o alfabeto com o qual Deus escreveu o universo.\u0026rdquo;- Galileu Galilei\n\u0026ldquo;Quem sou eu? Ora, é impossível responder porque o tempo todo e preciso tornar-se quem se é!\u0026rdquo; - Friedrich Nietzsche\n\u0026ldquo;Há verdadeiramente duas coisas diferentes: saber e crer que se sabe. A ciência consiste em saber; em crer que se sabe reside a ignorância.\u0026rdquo; - Hipócrates\n\u0026ldquo;Faça as coisas o mais simples que você puder, porém não restrinja às mais simples.\u0026rdquo; - Albert Einstein\n\u0026ldquo;Pouco conhecimento faz com que as pessoas se sintam orgulhosas. Muito conhecimento, com que se sintam humildes.\u0026rdquo; - Leonardo da Vinci\n\u0026ldquo;De todos os animais selvagens, o homem jovem é o mais difícil de domar.\u0026rdquo; - Platão\n\u0026ldquo;Ajuda o teu semelhante a levantar a carga, mas não a levá-la.\u0026rdquo; - Pitágoras\n\u0026ldquo;É preciso cuidar do que é permanente, não só com o corpo mas também com a mente\u0026rdquo; - Vinícius de Moraes\n\u0026ldquo;A melhor maneira de ser feliz é contribuir para a felicidade dos outros.\u0026rdquo; - Robert Baden-Powell\n\u0026ldquo;Você não pode ensinar nada a ninguem, mas pode ajudar as pessoas a descobrirem por si mesmas.\u0026rdquo; - Galileu Galilei\n\u0026ldquo;Conhece-te a ti mesmo.\u0026rdquo; - Sócrates\n\u0026ldquo;Aquele que ousa perder uma hora de seu tempo não sabe o valor da vida.\u0026rdquo; - Charles Darwin\n\u0026ldquo;Em algum lugar, alguma coisa incrível está esperando para ser descoberta.\u0026rdquo; - Carl Sagan\n\u0026ldquo;Ninguém que é curioso é idiota. As pessoas que não perguntam permanecem ignorantes para o resto de suas vidas.\u0026rdquo; - Neil DeGrasse Tyson\n\u0026ldquo;Muitas pessoas devem a grandeza de suas vidas aos problemas que tiveram de vencer.\u0026rdquo; ― Robert Baden-Powell\n\u0026ldquo;Construímos muros demais e pontes de menos.\u0026rdquo; - Issac Newton\n\u0026ldquo;É muito comum que as pessoas trabalhem duro na coisa errada. Trabalhar na coisa certa é, provavelmente, mais importante do que trabalhar duro\u0026rdquo; - Caterina Fake\n\u0026ldquo;Deixe o mundo um pouco melhor do que encontrou.\u0026rdquo; - Robert Baden-Powell\n\u0026ldquo;Daria tudo que sei em troca da metade do que ignoro.\u0026rdquo; - Descartes\n\u0026ldquo;Podemos julgar o coração de um homem pela forma como ele trata os animais.\u0026rdquo; - Immanuel Kant\n\u0026ldquo;A melhor maneira de prever o futuro é criá-lo\u0026rdquo; - Peter Drucker\n\u0026ldquo;O talento nos é dado, mas é o trabalho que o transforma em genialidade\u0026rdquo; - Anna Pavlova\n","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/resources/shoulders-of-giants/","section":"Recursos","summary":"Essas são algumas das frases que me impactaram de alguma forma e que eu carrego para a minha vida:\n“Com organização e tempo, acha-se o segredo de fazer tudo e bem feito.” - Pitágoras\n“A imaginação é mais importante que o conhecimento.” - Albert Einstein\n“Na vida, não existe nada a temer, mas a entender.” - Marie Curie\n“A matemática foi o alfabeto com o qual Deus escreveu o universo.”- Galileu Galilei\n","title":"Sobre ombros de gigantes","type":"resources"},{"content":"","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/tags/teste-fisher/","section":"Tags","summary":"","title":"Teste-Fisher","type":"tags"},{"content":" Correlações Tipos de Variáveis Tipos de Correlações Coeficiente de Correlação de Pearson Coeficiente de Correlação de Spearman \\(\\rho\\) Coeficiente de Correlação de Kendall (\\(\\tau\\) de kendall) Qui-quadrado de independencia Teste exato de fisher Medidas de associação \\(\\phi\\) (phi) (é o R de pearson quando aplicado a tabelas 2x2) V de Crámer Coeficiente de contingência Kappa Mãos a obra Referências Correlações De maneira geral, quando estamos interessados em avaliar o grau de associação entre duas variáveis calculamos os coeficientes de associação ou correlação entre variáveis.\nTL;DR\nPearson: relação linear entre duas variáveis quantitativas. Spearman/Kendall: relação entre variáveis ordinais, sem exigir normalidade. Qui-quadrado/Fisher/Phi/Cramér/Kappa: associação entre variáveis categóricas. Correlação nunca implica causalidade. Essas medidas descrevem por meio de um único número a associação (ou dependência) entre duas variáveis.\nDe modo a facilitar a compreensão, esses coeficientes geralmente variam entre 0 e 1 ou entre -1 e +1, de maneira que a proximidade de zero indique a falta de associação entre elas.\nExistem muitas medidas disponíveis para quantificar a associação entre variáveis, porém, um primeiro conceito que deve ser levado em conta é: quais são os tipos de variáveis?\nSe você quiser entender de onde vem toda essa base antes de sair aplicando fórmula, o livro Estatística Básica, do Bussab e Morettin, ainda é a referência que mais uso quando preciso relembrar o porquê por trás de um teste.\nTipos de Variáveis Existem dois tipos de variáveis que podem ser abordadas de maneiras diferentes, veja:\nQuantitativas\nContinua: Medidas (Peso, altura, renda, dinheiro, comprimento) Discreta: Contagem (qnt. de coisas) Qualitativas\nNominais: Nomes Ordinais: Quando é possível ordenar os arquivos E para cada relação ou associação que buscamos calcular, existe um tipo diferente de coeficiente, mas de maneira geral, todos eles possuem tais características em comum:\nTipos de Correlações Coeficientes de correlação informam:\nIntensidade Fortemente relacionadas (Valores próximos de 1 ou -1) Fracamente relacionadas (Valores próximos de 0) Direção Positiva (Se ambas as variáveis crescem no mesmo sentido) Negativa (Se as variáveis crescem em sentidos opostos) Significância IMPORTANTE: CORRELAÇÃO NÃO INDICA RELAÇÃO DE CAUSALIDADE\nE além dos coeficientes de correlação, existem outras medidas de associação igualmente importantes, veja:\nCoeficiente de Correlação de Pearson Sejam duas variáveis X e Y, ambas quantitativas, preferencialmente contínuas. A existência de relação linear entre essas variáveis pode ser detectada com auxílio do Diagrama de Dispersão, mas, também, com auxílio do Coeficiente de Correlação Linear de Pearson.\nCoeficiente de Correlação de Spearman \\(\\rho\\) Utilizado quando não existe normalidade e/ou não existe relação linear, deve ser usado quando não se deseja utilizar nenhuma suposição de normalidade ou da presença de qualquer outra distribuição para a variável ou para a estatística de teste.\nEste coeficiente se baseia nos postos das observações dentro de cada variável e se baseia sobre as diferenças entre os postos observados, nas variáveis X e Y, para um mesmo objeto de estudo.\nIdeal quando temos variáveis medidas apenas em uma escala ordinal.\nCoeficiente de Correlação de Kendall (\\(\\tau\\) de kendall) O coeficiente de correlação Tau de Kendall serve para verificar se existe correlação entre duas variáveis ordinais. É um método adequado quando amostras têm tamanhos reduzidos, pois o método é mais preciso. E pode ser estendido a correlações parciais, quando o efeito de uma terceira variável, que age sobre X e Y, é retirado antes de determinar se X e Y estão relacionadas.\nCoeficiente de Kendall é, muitas vezes, interpretado como uma medida de concordância entre dois conjuntos de classificações relativas a um conjunto de objetos de estudo.\nQui-quadrado de independencia Utiliza-se esta prova quando os dados da pesquisa se apresentam sob forma de frequências em categorias discretas. Pode aplicar a prova \\(\\chi^2\\) para determinar a significância de diferenças entre dois grupos independentes e conseqüentemente, com respeito a frequências relativas com que os componentes do grupo se enquadram nas diversas categorias.\nSuas hipóteses:\n\\[ \\begin{aligned} H_0\u0026: \\text{São independentes (Não associadas)} \\\\ H_1\u0026: \\text{Não são independentes (São associadas)} \\end{aligned} \\]\nTeste exato de fisher O teste qui-quadrado quando aplicado a amostras pequenas, como por exemplo com tamanho inferior a 20, veja:\nMedidas de associação os testes fornecem apenas a resposta se as variáveis estão ou não correlacionadas. Para saber a intensidade desta relação, utilizam-se medidas de associação.\nConsidere as seguintes medidas:\n\\(\\phi\\) (phi) (é o R de pearson quando aplicado a tabelas 2x2) O coeficiente phi é uma medida de associação entre duas variáveis binárias. A interpretação é similar a de um coeficiente de correlação. Duas variáveis binárias são consideradas positivamente associadas se a maior parte dos dados (frequências) cai ao longo das células da diagonal (a e d maiores que b e c). E serão consideradas negativamente associadas se a maior parte dos dados cai fora da diagonal.\nV de Crámer O coeficiente V de Cramer serve para medir associação em tabelas não quadradas.\nCoeficiente de contingência O Coeficiente de Contingência C é uma medida de associação, relacionada à estatística de teste do teste qui-quadrado, e ajustada para diferentes tamanhos de amostra. Ele também está diretamente relacionado à estatística de teste do teste qui-quadrado e ao Coeficiente Phi (possui as mesmas vantagens e desvantagens de Phi).\nAmbos variam de 0 (ausência de associação) a 1 (associação muito forte).\nKappa O coeficiente Kappa é uma medida de concordância inter observador e mede o grau de concordância além do que seria esperado só por conta do acaso. Muitas vezes é usado no lugar do teste de McNemar.\nObs: Também pode ser utilizado o coeficiente de Kappa ponderado\nMãos a obra É impressionante a gama de opções que já existe para avaliarmos variáveis por diversas perspectivas!\nÉ bom ressaltar que é extremamente fácil se perder no meio de tantos resultados em tantas situações possíveis, por isso meu próximo post irá tratar justamente dos diferentes tipos de relações entre variáveis e quais tipos de medidas são possíveis para cada caso, até a próxima!\nPara aplicar essas correlações em análises com muitas variáveis ao mesmo tempo, veja o post sobre análise multivariada em R. Se o assunto probabilidade te interessa, veja também o paradoxo dos aniversários com simulação e probabilidade.\nPerguntas frequentes Quando usar Pearson em vez de Spearman? Use Pearson quando as duas variáveis são quantitativas, a relação entre elas é aproximadamente linear e não há razão para suspeitar de outliers fortes. Use Spearman quando essa suposição de linearidade ou normalidade não se sustenta, ou quando as variáveis são ordinais.\nQual a diferença entre qui-quadrado e o teste exato de Fisher? Os dois testam independência entre variáveis categóricas, mas o qui-quadrado depende de uma aproximação que exige amostras razoavelmente grandes. O teste exato de Fisher é mais indicado para amostras pequenas (por exemplo, abaixo de 20 observações), onde a aproximação do qui-quadrado perde precisão.\nCorrelação alta significa que uma variável causa a outra? Não. Correlação mede associação estatística, não causalidade. Duas variáveis podem estar fortemente correlacionadas por coincidência, por uma terceira variável que afeta ambas, ou por uma relação causal real, e o coeficiente de correlação sozinho não distingue esses casos.\nReferências CONOVER, W. J. Pratical Nonparametric Statistics SIEGEL, S. Estatística Não Paramétrica para as Ciências do Comportamento BUSSAB, W. de O. ;MORETTIN, P. A. Estatística básica. 5 ed. ","date":"1 de dezembro de 2017","externalUrl":null,"permalink":"/post/2017-12-01-tipos-de-correlacoes/","section":"Posts","summary":" Correlações Tipos de Variáveis Tipos de Correlações Coeficiente de Correlação de Pearson Coeficiente de Correlação de Spearman \\(\\rho\\) Coeficiente de Correlação de Kendall (\\(\\tau\\) de kendall) Qui-quadrado de independencia Teste exato de fisher Medidas de associação \\(\\phi\\) (phi) (é o R de pearson quando aplicado a tabelas 2x2) V de Crámer Coeficiente de contingência Kappa Mãos a obra Referências Correlações De maneira geral, quando estamos interessados em avaliar o grau de associação entre duas variáveis calculamos os coeficientes de associação ou correlação entre variáveis.\n","title":"Tipos de Correlações em R","type":"post"},{"content":"Ferramentas e recursos que fazem parte do meu setup de IA agêntica, organizados por finalidade: skills, apps, MCP servers e utilitários para cada etapa do fluxo de trabalho com agentes.\n","externalUrl":null,"permalink":"/agentic/","section":"Agentic AI","summary":"Ferramentas e recursos que fazem parte do meu setup de IA agêntica, organizados por finalidade: skills, apps, MCP servers e utilitários para cada etapa do fluxo de trabalho com agentes.\n","title":"Agentic AI","type":"agentic"},{"content":"Fale comigo por e-mail: gomes.fellipe1@gmail.com\nOu pelas redes sociais no rodapé do site. Disponível para projetos freelance em Data Science, Machine Learning e agentes de IA.\n","externalUrl":null,"permalink":"/contact/","section":"Fellipe Gomes","summary":"Fale comigo por e-mail: gomes.fellipe1@gmail.com\nOu pelas redes sociais no rodapé do site. Disponível para projetos freelance em Data Science, Machine Learning e agentes de IA.\n","title":"Contato","type":"page"},{"content":"Ferramentas para controlar o uso de contexto, reduzir desperdícios de tokens e acompanhar consumo e custos — da compressão manual de prompts a estratégias nativas como prompt caching.\n","externalUrl":null,"permalink":"/agentic/contexto-tokens-custos/","section":"Agentic AI","summary":"Ferramentas para controlar o uso de contexto, reduzir desperdícios de tokens e acompanhar consumo e custos — da compressão manual de prompts a estratégias nativas como prompt caching.\n","title":"Contexto, tokens e custos","type":"agentic"},{"content":"Recursos para criar interfaces, diagramas, textos, blogs, áudio e vídeo com apoio de ferramentas e agentes.\n","externalUrl":null,"permalink":"/agentic/criacao-conteudo-design/","section":"Agentic AI","summary":"Recursos para criar interfaces, diagramas, textos, blogs, áudio e vídeo com apoio de ferramentas e agentes.\n","title":"Criação, conteúdo e design","type":"agentic"},{"content":"Ainda estou organizando essa lista com calma. Quero indicar apenas os cursos que eu de fato fiz e que valeram o tempo investido. Assim que estiver pronta, ela aparecerá aqui.\n","externalUrl":null,"permalink":"/courses/","section":"Fellipe Gomes","summary":"Ainda estou organizando essa lista com calma. Quero indicar apenas os cursos que eu de fato fiz e que valeram o tempo investido. Assim que estiver pronta, ela aparecerá aqui.\n","title":"Cursos","type":"page"},{"content":"Recursos para revisão de código, planejamento, qualidade de implementação, documentação técnica e integrações MCP.\n","externalUrl":null,"permalink":"/agentic/desenvolvimento-automacao-ia/","section":"Agentic AI","summary":"Recursos para revisão de código, planejamento, qualidade de implementação, documentação técnica e integrações MCP.\n","title":"Desenvolvimento e automação com IA","type":"agentic"},{"content":"Ferramentas para extrair informações de documentos e transformar conteúdos em bases, wikis e grafos de conhecimento.\n","externalUrl":null,"permalink":"/agentic/documentos-conhecimento/","section":"Agentic AI","summary":"Ferramentas para extrair informações de documentos e transformar conteúdos em bases, wikis e grafos de conhecimento.\n","title":"Documentos e conhecimento","type":"agentic"},{"content":"Aplicativos que ajudam a organizar janelas, projetos, sessões e fluxos de trabalho no desktop.\n","externalUrl":null,"permalink":"/agentic/produtividade-utilitarios-desktop/","section":"Agentic AI","summary":"Aplicativos que ajudam a organizar janelas, projetos, sessões e fluxos de trabalho no desktop.\n","title":"Produtividade e utilitários desktop","type":"agentic"},{"content":"Venho atuando com IA e Machine Learning desde 2017 em todo o ciclo analítico: coleta e tratamento de dados, análises automatizadas, visualizações profissionais, modelagem estatística e preditiva e desenvolvimento de produtos de IA em setores como varejo, agrícola, bens de consumo, energia, saúde, mineração, pesquisa econômica e TI.\nAtualmente, atuo na Accenture em projetos voltados à área de Supply Chain, onde exploro o potencial da IA aplicada a desafios reais de negócio. Sou graduado em Estatística pela UFF e possuo MBA em Data Science pela FGV. Alcancei a categoria de Kaggle Master e ganhei algumas competições na plataforma.\n9 anosem Data Science Kaggle Masterdesde 2020 8 setoresde atuação 3 pódioscompetições nacionais Seguir no LinkedIn\nReconhecimentosKaggle Master (desde mai/2020)1º lugar — ML Olympiad (SRAG) ↗2º lugar — ML Olympiad (ENEM) ↗3º lugar — Porto Seguro Data Challenge ↗Destaque — competição do Hospital Israelita Albert Einstein (Kaggle) ↗Palestrante IEEE/UFF ↗ · Mentor no programa Start e em hackathons FormaçãoMBA em Data Science \u0026amp; Business Analytics\nFundação Getulio Vargas (FGV), 2020Bacharelado em Probabilidade e Estatística\nUniversidade Federal Fluminense (UFF), 2018 Experiência Accenture Data Science SpecialistJan 2024 – Atual Data Science Senior AnalystJan 2022 – Dez 2023 Data Science AnalystAgo 2020 – Dez 2021 FGV IBRE — Instituto Brasileiro de Economia Cientista de Dados (Pleno e Júnior)Abr 2018 – Jul 2020 Dataprev Estágio em EstatísticaFev 2017 – Mar 2018 Competências Linguagens \u0026amp; FerramentasPythonRSQLGitLangChain Machine Learning \u0026amp; IAMachine LearningDeep LearningIA GenerativaLLMsAgentes de IANLPText MiningClusteringForecastingDetecção de Anomalias Dados \u0026amp; ArquiteturaBig DataDatabricksArquitetura de SoluçõesSoftware EngineeringOtimizaçãoWeb ScrapingAnálise GeoespacialDashboardsR/Shiny Estatística \u0026amp; ComunicaçãoEstatísticaModelagem EstatísticaAmostragemStorytelling ","externalUrl":null,"permalink":"/about/","section":"Fellipe Gomes","summary":"Venho atuando com IA e Machine Learning desde 2017 em todo o ciclo analítico: coleta e tratamento de dados, análises automatizadas, visualizações profissionais, modelagem estatística e preditiva e desenvolvimento de produtos de IA em setores como varejo, agrícola, bens de consumo, energia, saúde, mineração, pesquisa econômica e TI.\nAtualmente, atuo na Accenture em projetos voltados à área de Supply Chain, onde exploro o potencial da IA aplicada a desafios reais de negócio. Sou graduado em Estatística pela UFF e possuo MBA em Data Science pela FGV. Alcancei a categoria de Kaggle Master e ganhei algumas competições na plataforma.\n","title":"Sobre","type":"page"}]