Tag

projeto do r Archives - Análise Macro

Como automatizar scripts de R usando o GitHub Actions

By | Data Science

Se você tem um script de R para executar uma determinada rotina em uma frequência predeterminada, talvez seja interessante investir em economia de tempo automatizando essa tarefa. Nesse tutorial demonstramos como utilizar o GitHub Actions para rodar scripts de R automaticamente, se livrando de qualquer trabalho manual e repetitivo.

São diversos os contextos e aplicações nos quais a automatização de um script de R pode ser útil, dentre os principais exemplos destaca-se:

  • Relatórios dinâmicos com R Markdown
  • Atualização de dashboards
  • Extração e atualização de uma base de dados
  • Web scrapping de uma página
  • Rotinas de robustez contra erros em pacotes

Muitos desses exemplos, e a depender do contexto, requerem que o usuário de R execute o script em uma frequência mensal, semanal, diária ou até mesmo de 1 em 1 hora. Dessa forma, a automatização não é apenas interessante, mas vital para um bom fluxo de trabalho.

Vamos pegar um desses exemplos como demonstração nesse tutorial: faremos um web-scrapping da página de criptomoedas do site TradingView para obter dados de cotações, volume, retornos %, etc. e, adicionalmente, criaremos uma dashboard básica com esses dados para demonstrar uma possibilidade de uso. Por fim, automatizaremos esse processo de modo que a dashboard seja atualizada de hora em hora.

Pré-requisitos

Antes de começar, para esse tutorial deve-se cumprir os seguintes pré-requisitos (pule essa etapa se você já os cumpre):

Se houverem dificuldades com o Git, principalmente se for a primeira vez, recomendo fortemente dar uma lida no Happy Git and GitHub for the useR, que é um tutorial de como usar o Git e GitHub integrado ao R/RStudio.

Criar um pacote

O primeiro passo é criar um pacote R que vai conter nosso script na forma de uma função. Mas não se assuste, é mais fácil do que parece pois, felizmente, a comunidade de R já criou diversas ferramentas para facilitar esse processo. Ao final, utilizaremos a função para a rotina de web-scrapping dos dados de criptomoedas, da mesma forma que a maioria dos pacotes de coleta de dados funcionam.

Aqui utilizamos o pacote usethis para criar um pacote básico. Basta passar para função create_package o caminho (path) de onde se deseja armazenar os arquivos que serão gerados, no nosso caso ficará dentro de uma pasta chamada cryptoscrap.

usethis::create_package("cryptoscrap")

Uma nova sessão do R será aberta com um R Project já pré configurado e com os arquivos mínimos do nosso pacote.

Em sequência, abrimos o arquivo DESCRIPTION recém criado e preenchemos algumas informações básicas como título do pacote, descrição, informações de autor, etc. e, opcionalmente pode ser utilizado uma licença como a MIT (neste caso pode ser usado a função usethis::use_mit_license()). Para saber mais sobre esse preenchimento básico, assim como outras informações sobre desenvolvimento de pacotes, recomendo conferir o livro do Hadley Wickham e Jenny Bryan intitulado R Packages.

Finalizado esse procedimento inicial, podemos prosseguir para o script de R.

Escrever um script de R

Conforme mencionado, faremos um web-scrapping de uma tabela com dados de criptomoedas provenientes do TradingView. Utilizaremos apenas dois pacotes nesta etapa, o rvest e o purrr, e colocaremos a rotina dentro de uma função que será solicitada na dashboard mais adiante.

Para começar a criar a função usamos novamente o pacote usethis, gerando um novo arquivo de scripts dentro da pasta R do nosso projeto (entre aspas o nome do arquivo .R que será gerado):

usethis::use_r("crypt_scrap")

No novo arquivo .R criado escrevemos nossa função:

crypt_scrap <- function() {

# Crytocurrency page URL
crypto_url <- rvest::read_html(
"https://www.tradingview.com/markets/cryptocurrencies/prices-all/"
)

# Get raw data from URL
crypto_raw <- rvest::html_nodes(crypto_url, css = "table")

# Convert from list to tibble
crypto_table <- rvest::html_table(crypto_raw)
crypto_table <- purrr::pluck(crypto_table, 1)
crypto_table <- purrr::set_names(
crypto_table,
c(
"Name", 
"Mkt Cap",
"FD Mkt Cap",
"Last", 
"Avail. Coins", 
"Total Coins",
"Traded Vol", 
"Chg %"
)
)

# Return tibble
return(crypto_table)
}

Em sequência, devemos adicionar as dependências do nosso pacote, ou seja, estes dois pacotes que estamos utilizando na nossa função. Isso faz com que, ao carregar localmente o pacote que estamos criando por exemplo, estes dois pacotes externos também sejam carregados para a sessão do R ao utilizar a função crypt_scrap que criamos.

Para adicionar as dependências é muito simples:

usethis::use_package("rvest")
usethis::use_package("purrr")

Agora já temos um rascunho de pacote pronto para ser testado! Para testar, é importante verificar se a função está funcionando localmente. Outro teste que pode ser feito é através do pacote devtools, que oferece ferramentas para desenvolvimento de pacotes com uma série de parametrizações úteis que indicam se o pacote e suas funções seguem as regras e recomendações gerais do CRAN. Para isso basta rodar:

devtools::check()

Ao final dos testes é indicado se houve errors, warnings ou notes. Se estiver tudo ok, o que foi o caso, podemos prosseguir.

Criar um repositório no GitHub

Agora vamos criar um repositório no GitHub para hospedar nosso pacote com os arquivos. Tudo que precisa ser feito é:

  1. Estar logado no GitHub
  2. Clicar no botão New
  3. Definir um nome do repositório (aqui usamos crypto_scrap)
  4. Clicar em Create repository

Opcionalmente pode ser incluído uma descrição, similar ao que preenchemos no arquivo DESCRIPTION do nosso pacote.

Em seguida o GitHub criará um link para o repositório criado, direcionando para esta página, onde aparecerão alguns comandos em Git que podemos utilizar para integrar nosso projeto local com o repositório. Tudo que precisamos fazer é copiar o código que aparece na sugestão intitulada "…or create a new repository on the command line" e colar no Terminal do RStudio para fazer a configuração necessária. No nosso exemplo executamos o código abaixo:

echo "# crypto_scrap" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/schoulten/crypto_scrap.git
git push -u origin main

Com efeito, nossa pasta de pacote local estará configurada como um repositório Git e assim já podemos subir nossos arquivos (fazer o push) para o GitHub. Para isso, executamos no Terminal:

git add .
git commit -m "adding package"
git push

Ao voltarmos na página do GitHub, dando uma atualizada na página, todos os nossos arquivos locais também estarão lá disponíveis.

Criar uma dashboard

Agora vamos deixar o GitHub em stand by para voltar ao R e criar uma dashboard com os dados das criptomoedas. Nesse exemplo vamos criar uma dashboard estática contendo apenas uma tabela com os dados (bem básico), e utilizamos o pacote flexdashboard para tal. Os códigos em .rmd para gerar a dashboard podem ser conferidos nesse link. O resultado é esse:

Criado o nosso "produto final", podemos partir para a etapa final de automatização.

Usar o renv para gerenciar dependências

Em seguida, fazemos um passo adicional em nosso projeto que é criar um arquivo renv.lock que conterá uma série de configurações de gerenciamento de dependências do nosso projeto/pacote. O que basicamente isso significa é que será tirada uma "foto" do estado atual de configurações, pacotes, dependências que estamos utilizando, para que o projeto seja reprodutível em outro ambiente, como o GitHub Actions.

Esse assunto é bastante complexo e não é o foco aqui se aprofundar no tema, de modo que tudo que precisa ser feito é executar no Console:

renv::init()
renv::snapshot()

Agendar tarefa com o GitHub Actions

Como pode ter sido observado, criamos um fluxo de trabalho aqui:

  • Temos um pacote com uma função para extrair dados de criptomoedas
  • Usamos essa função em uma dashboard que gera uma tabela com os dados

Agora o que queremos é delegar esse fluxo de trabalho para que o GitHub Actions faça isso automaticamente para nós, em uma periodicidade de 60 em 60 minutos, já que os dados oferecem essa tempestividade.

Portanto, o que faremos na prática é:

  • Criar um arquivo (workflow) que agenda uma tarefa no GitHub Actions
  • Especificar um intervalo de agendamento da tarefa
  • Configurar o ambiente R no GH Actions
  • Executar script de web-scrapping + atualização da dashboard
  • Salvar (commit e push) os resultados

Importante: a indentação do código é importante aqui, se tiver dificuldade em identificar os espaçamentos corretos, confira neste link como ficou o resultado final dessa parte do nosso código.

Criar arquivo de workflow do GitHub Actions

Primeiro precisamos criar o arquivo de workflow, que conterá toda a rotina do que queremos que o GitHub Actions execute. Ele deve estar dentro de uma pasta .github/workflows a partir da raiz do projeto que estamos trabalhando e ter uma extensão .yaml. Em nosso exemplo, ficou assim:

├── .github
│ ├── workflows
│ ├── update.yaml

O nome do arquivo update.yaml pode ser qualquer um.

Especificar um intervalo de agendamento da tarefa

Utilizaremos um agendador de tarefas denominado "CRON" para executar periodicamente nossos códigos.

A parte mais importante para se compreender é como especificar o intervalo de tempo com o qual estamos trabalhando utilizando uma expressão: o script deve ser executado a cada 5 minutos? De hora em hora? Diariamente? Mensalmente? Para cada uma dessas possibilidades há uma expressão específica de configuração e neste link podemos encontrar alguns exemplos dessas expressões para tomar como base.

Em nosso caso, como queremos a execução de 60 em 60 minutos, usamos a expressão "0 * * * *". No arquivo de workflow a sintaxe é conforme abaixo, logo nas primeiras linhas:

on:
push:
branches:
- main
- master
schedule:
- cron: "0 * * * *"

Configurar o ambiente R no GH Actions

Em seguida, vamos configurar uma sessão de R no servidor do GitHub Actions, já que, basicamente, o GH Actions é nada mais do que um computador localizado em algum lugar do mundo que o GitHub nos disponibiliza para executarmos algo nele, em nosso caso são scripts de R. A abordagem aqui utilizada se baseia em alguns templates fornecidos pela equipe do r-lib.

Resumidamente, esta parte do arquivo de workflow:

- Especifica o tipo de sistema operacional a ser usado (usaremos Windows)
- Define as variáveis de ambiente R e configura a autenticação de acesso ao repositório GitHub
- Instala o R
- Instala/restaura os pacotes necessários

name: Dashboard update
jobs:
Dashboard-update:
runs-on: windows-latest
env:
GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v2
- uses: r-lib/actions/setup-r@v1
- name: Cache packages
uses: actions/cache@v2
with:
path: ~\AppData\Local\renv
key: ${{ runner.os }}-renv-${{ hashFiles('**/renv.lock') }}
restore-keys: |
${{ runner.os }}-renv-
- name: Restore packages
run: |
if (!requireNamespace("renv", quietly = TRUE)) install.packages("renv")
renv::restore()
shell: Rscript {0}
- name: Install workflow dependencies
run: |
install.packages(c("rcmdcheck", "sessioninfo", "devtools"))
shell: Rscript {0}

Executar script de web-scrapping + atualização da dashboard

Com o R configurado, agora executa-se os scripts que escrevemos. No nosso exemplo, a função de web-scrapping do pacote que criamos será chamada dentro do arquivo .rmd que gera a dashboard.

- name: Install pandoc
run: |
choco install pandoc
- name: Render Rmarkdown/Update data
run: |
devtools::load_all()
rmarkdown::render("index.Rmd")
shell: Rscript {0}

Salvar (commit e push) os resultados

Até aqui o workflow terá gerado uma nova dashboard com os dados de criptomoedas atualizada, mas tudo isso (esses arquivos) estarão no servidor do GitHub Actions. Portanto, precisamos, por fim, fazer o commit & push dessas atualizações para o nosso repositório do GitHub. Isso é feito conforme abaixo:

- name: Commit and push
run: |
git config --local user.email "actions@github.com"
git config --local user.name "GitHub Actions"
git add .
git commit -m "Dashboard update"
git push

- name: Session info
run: |
options(width = 500)
pkgs <- installed.packages()[, "Package"]
sessioninfo::session_info(pkgs, include_base = TRUE)
shell: Rscript {0}

Salvar resultados no repositório

Ok, o trabalho duro já passou, agora só falta fazermos um novo check em nosso pacote, verificar se está tudo ok e salvo e subir as últimas modificações para o repositório do GitHub.

Primeiro o check no Console do RStudio:

devtools::check()

Apareceram 2 notes e para corrigir adicionamos as seguintes linhas no arquivo .Rbuildignore:

index.Rmd
index.html
^\.github$

Agora podemos prosseguimos com o commit & push, no Terminal do RStudio:

git add .
git commit -m "create pkg, dash and workflow"
git push

Ao visitarmos novamente a página do nosso repositório criado no site do GitHub, veremos todas as modificações realizadas.  E pronto!

Além disso, no botão "Actions" do repositório aparecerá o nosso workflow desenhado para executar toda essa rotina que trabalhamos aqui, de hora em hora. Portanto, estamos por fim "livres" de trabalho manual e o nosso produto final, uma dashboard, está totalmente automatizada. Legal, não?!

Recomendo esperar até 24 horas para verificar se o workflow está funcionando, pois o GitHub pode ter um delay para começar a executar toda a rotina definida.

O resultado final desse exemplo disponibilizei neste repositório e a dashboard pode ser acessada por este link.

Ressalvas

Esse tutorial introdutório resumiu demasiadamente diversos pontos que merecem atenção, de modo que, possivelmente, não cobre alguns possíveis obstáculos que podem surgir ao longo do desenvolvimento de um projeto desses. Recomendamos utilizar exaustivamente as documentações dos pacotes e ferramentas aqui utilizadas, de modo a entender mais profundamente o que está sendo feito.

Por fim, eu adoraria saber como como foi a experiência individual ao tentar reproduzir esse tutorial. Sinta-se livre para mandar um feedback, caro leitor(a).

 

5 dicas de R que gostaria de ter recebido no início

By | Data Science

Se você está começando a aprender sobre R agora, ou até mesmo se já possui algum conhecimento, mas sente que chegou em um ponto de "estagnação", esse texto é pra você. Aqui reúno cinco dicas e aprendizados que passei a adotar que ajudam na curva de aprendizado da linguagem, mas que não foram tão óbvias no início.

1. Use um guia de estilo (style guide)

Guias de estilo são importantes e devem ser encarados como nossos amigos na hora de escrever um código. Em outras palavras, assim como a pontuação e acentuação correta, os guias de estilo tornamascoisasmaisfaceisdeler.

Boas referências sobre guia de estilo podem ser encontradas no  Tidyverse Style Guide, escrito pelo Hadley Wickham, que foi baseado no Google's R Style Guide. Uma leitura desses guias é certamente proveitosa, pois reúnem um compilado de boas práticas para escrever códigos em R, contemplando temas como sintaxe, nomes de objetos, indentação do código, controle de fluxo, etc.

Eu posso garantir que não é nada de outro mundo, e tornará sua vida no R mais fácil a longo prazo.

2. Otimize o RStudio

Você certamente já se deparou com arquivos Rhistory em suas pastas de códigos de R ou mensagens, um tanto quanto incomodativas, sobre salvar objetos usando .Rdata. Apesar de ser um comportamento com boa intenção da configuração padrão do RStudio - ou seja, tentar evitar a perda de comandos e objetos de uma sessão do R - não traz muitos benefícios e, em geral, esses recursos devem ser deixados de lado. Há pouco controle sobre o comportamento desses arquivos que são gerados automaticamente pelo programa, além de outras desvantagens, o que certamente não é o ideal para qualquer código que preze pela reprodutibilidade.

Portanto, e partindo do princípio de que um código reprodutível é idealmente organizado em um arquivo .R, desabilitar o .Rhistory e o .Rdata tornará sua experiência no RStudio menos contraproducente. Para desabilitar esses recursos é simples: navegue por Tools > Global Options > General e desmarque as opções:

- Restore .RData into workspace at startup
- Always save history (even when not saving .RData)

Além disso, o tema visual padrão do RStudio é uma tela branca não muito convidativa para quem passa algumas longas horas olhando para ela. Felizmente podemos modificar o visual do programa de modo a adaptá-lo às preferências do usuário. Na mesma tela de configuração indicada acima, no menu Appearance, é possível escolher outros temas com cores diferentes. Você pode testar e modificar para verificar com qual tema se adapta melhor, eu utilizo o tema "Cobalt" atualmente.

3. Aprenda a generalizar tarefas

Se você precisa repetir um código mais do que duas vezes em um determinado projeto, é melhor você criar uma função que generalize a ação sendo executada. No final das contas, serão menos linhas e mais fácil de ler.

Esse princípio, proferido e seguido por diversos programadores, é um ponto de inflexão quando programamos em R ou qualquer outra linguagem. A ideia básica é trazer facilidade, agilidade e eficiência para as rotinas de programação, algo que é usualmente ignorado nos primeiros passos em uma nova linguagem.

Quando optamos por duplicar um determinado código, por exemplo, o tratamento de um conjunto de dados ou as configurações de saída de um gráfico, estamos explicitamente dificultando a atualização e manutenção desse código, já que a mesma modificação teria que ser feita em mais de uma linha ao longo do código. Com uma função, que executa a mesma tarefa, é mais simples fazer a manutenção do código, bastando modificá-la uma única vez. Apesar de haver um custo de aprendizado maior, escrever funções tornará suas rotinas mais robustas, além de haver ganhos de economia de tempo.

Mas não há motivo para se apavorar e perder tempo criando funções para tudo, comece pelo básico. Uma boa referência sobre esse assunto pode ser o livro Advanced R do Hadley Wickham, que tem um capítulo dedicado ao tema.

4. Leia (e escreva) a documentação

É comum receber dúvidas de iniciantes ou ler postagens em fóruns com perguntas que são facilmente encontradas digitando "?nome_da_função" no Console. Apesar de ser um comportamento intuitivo, não é recomendável procurar respostas em outras pessoas sem antes instigar em si próprio um pouquinho de instinto investigativo. Nesse ponto entram as documentações, que nada mais são do que guias descritivos sobre um determinado pacote e/ou função.

Não cair na tentação de enviar a dúvida para um amigo ou conhecido, mas, antes, ir pesquisar sobre a documentação do pacote é uma maneira educada de atingir maior independência na linguagem. Portanto, use e abuse das documentações pois, certamente, a pessoa que escreveu a documentação teve bastante trabalho e pensou nos detalhes e dúvidas que poderiam surgir com o uso do objeto da documentação.

Dentro dessa dica também é importante não menosprezar o uso dos comentários em um código. Não há necessidade de poluir o código com comentários, mas também não há razão para ter medo de usá-los, e isso facilita a vida de outras pessoas que podem vir a ter acesso ao seu código.

5. Reprodutibilidade é importante

Especialmente quando trabalhando com dados e problemas do mundo real em uma equipe, o usuário de R precisa pensar, e escrever, de uma maneira que a solução que se quer encontrar seja replicável para outras pessoas, do contrário não haverá sentido em compartilhar sua análise ou código. Esse é um princípio básico do método científico.

Uma boa aplicação desse princípio são os chamados arquivos de projeto ou .Rproj no RStudio, que permitem criarmos uma estrutura e configuração comum de pastas que podem ser usadas para determinado script de R. Isso é importante pois facilita a utilização do código por outros usuários, já que embute configurações globais como encoding, caminhos de pastas e diretórios de trabalho, etc. Portanto, uma boa prática ao iniciar um novo projeto ou código, por exemplo uma análise de dados, que será disponibilizado para outras pessoas/ambientes, é utilizar o pacote usethis para criar um novo projeto através de uma simples função:


usethis::create_project("nome_do_projeto")

A função cria um novo arquivo de projeto já com uma estrutura de pasta organizada para armazenar scripts, rápido e fácil. O pacote também oferece outras funcionalidades diversas para otimizar a organização de projetos, pacotes, etc., com especial importância para a reprodutibilidade. Vale a pena explorar e aprender sobre.

E, por fim, mas não menos importante: aproveite e faça os cursos da Análise Macro, pois eles irão facilitar e acelerar a sua curva de aprendizado da linguagem R!

 

Receba diretamente em seu e-mail gratuitamente nossas promoções especiais
e conteúdos exclusivos sobre Análise de Dados!

Assinar Gratuitamente