-
Aula 11 - Pacotes e tópicos extras
2015-02-11
SourceCriação de pacotes
Criação de pacotes
Baseado no livro r-pkgs do Hadley
Vantagens
- Economia de tempo para tarefas futuras
- Forma de organização pré-estabelecida
- Contribuir e aproveitar contribuições da comunidade
Filosofia
- Tudo que pode ser automatizado, deve ser automatizado
- Utilização do pacote
devtools
como base para criação de pacotes - Trabalhar menos com os detalhes (estrutura, etc.) e mais com funcionalidades (funções úteis, etc).
- Se for necessário trabalhar com coisas mais complexas, ler Writing R extensions
Pré-requisitos
- Pacotes
devtools
,roxygen2
,testthat
,knitr
- R e RStudio atualizados (recomenda-se preview version do RStudio)
- Instalar versão
dev
dodevtools
devtools::install_github('hadley/devtools')
Pré-requisitos
- No Windows, instalar o Rtools
- No Mac, instalar o XCode
- No linux, instalar o pacote de desenvolvimento
r-base-dev
. No Ubuntu, basta digitar
sudo apt-get install r-base-dev
- Verifique se está tudo certo digitando
devtools::has_devel()
.
Exemplo
- Crie um projeto pelo RStudio e selecione "R project".
Estrutura
Essa é a estrutura mínima para criar um pacote.
- Tudo dentro de uma pasta
DESCRIPTION
: Metadados do pacote.NAMESPACE
: Importante para jogar pacote no CRAN.R/
: Pasta onde fica o código Rman/
: Pasta onde fica a documentaçãoxxx.Rproj
: Seu projeto (não é necessário).
Tipos / estados dos pacotes
- Source (código fonte)
- Bundled (
.tar.gz
) - Binary (binário, compactado)
- Installed (binário, descompactado numa pasta)
- In memory (depois de dar
library()
ourequire()
)
Código R
- Todo o código em
R
fica aqui - Tudo é baseado em funções. Crie objetos, principalmente funções, e não use coisas como
View()
- Melhor workflow: Editar R -> Ctrl+Shift+L -> Teste no console -> Editar R -> ...
- Organizando funções: dividir arquivos por temas, e manter um padrão de títulos e conteúdos
- Não use
library()
,require()
nemsource()
,setwd()
, etc. Ao invés disso, coloque dependências na documentação.
Documentação
Arquivo
DESCRIPTION
- Definir
Imports
,Suggests
, e usar o::
. devtools::use_package()
- Versões
(>= 0.3)
,devtools::numeric_version()
Depends
(versões de R).Authors@R
- Licensas
Documentação
Documentação dos objetos
- Ensina o usuário a usar o pacote
- Facilmente construído, colocando headers nas funções do R e usando
devtools::document()
- Começar com
#'
- workflow: Adicionar documentação em
roxygen
-> chamardevtools::document()
-> visualizar documentação com?
-> Adicionar documentação emroxygen
-> ... - Tags com
@tag
(ex:@param
). - Primeira sentença é o título. Segundo parágrafo é uma descrição. Os outos parágrafos vão para Details.
Vignettes
- Útil para dar uma explicação geral de um pacote
- Facilmente construído usando RMarkdown
- Geralmente usado para pacotes mais complexos
Testes
- Pacote
testthat
, do Hadley. devtools::use_testthat()
- Defina o que você quer testar (função e parâmetros), e o que você espera de resultado
- workflow: mude códigos ->
devtools::test()
-> repita.
library(stringr) context("String Length") test_that("str_length is a number of characters", { expect_equal(str_length('a'), 1) expect_equal(str_length('ab'), 2) expect_equal(str_length('abc'), 3) })
Namespace
- Só é necessário se preocupar com isso se você quiser colocar seu pacote no CRAN.
imports
eexports
.- Search path, load e attach
requireNamespace()
dá load e não attach.- Geralmente também é criado usando
devtools::document()
eroxygen2
. - Use
@export
para fazer sua função ficar disponível para o usuário via::
- Use
@importFrom pkg fun
para importar funções no NAMESPACE (não recomendável) - Use Depends se você quiser dar attach de um pacote e usar suas funções (no DESCRIPTION).
Dados externos
- Três maneiras de incluir dados no pacote.
- Arquivos binários (
.RData
) na pastadata/
. Utilizardevtools::usedata()
- Dados utilizados internamente pelas funções em
R/sysdata.rda
- Dados em texto (csv, excel, etc), na pasta
inst/extdata
- Documentar dados é semelhante a documentar funções, adicionando
@format
e@source
- Não é necessário usar
@export
Código compulado (C, C++, etc)
- Usar o pacote
RCpp
- Programar em
C
eC++
foge do escopo do curso - Usando o RStudio e abrindo um novo arquivo, é possível visualizar um template.
- Usar Ctrl+Shift+B ao invés de
devtools::load_all()
Melhores práticas
Git e GitHub
- Versionamento
- Colaboração
- Funciona como um website para seu pacote
Tópico extra: web crawling
Filosofia
- Se não tem dados, faça o download dos dados
- Automatizar acessos a websites
- É necessário aprender a passear pelos sites (crawling) e trabalhar com os arquivos HTML (scraping)
- Podemos ter uma lista do que queremos inicialmente ou não
Pacotes
- Pacotes
RCurl
eXML
do Duncan. - Pacotes
httr
ervest
do Hadley. - Pacote
RSelenium
(não funciona muito bem ainda)
Requisições GET e POST
GET
: Pede por informação do servidorPOST
: Envia infomações para o servidor- Para mais detalhes, ver aqui
Cookies, viewstate, etc.
- É bem comum que os sites não queiram que um computador acesse facilmente seus documentos
- Muitas vezes é preciso mostrar que o usuário "clicou" nos campos necessários para acessar um documento
ASP
,ASPX
,JSP
entre outros imprimem valores emtags
na própria página acessada para minimizar acesso automatizado
Captcha
- Atrapalha a vida dos web crawlers
- Muitas vezes é difícil de ser quebrado
- Geralmente são utilizados métodos de machine learning para extrair palavras de imagens
- Exemplo, serviço deathbycaptcha
Exemplo: Sabesp
- Exemplo no R
rm_accent <- function (x) gsub("`|\\'", "", iconv(x, to = "ASCII//TRANSLIT")) renomear <- function(x, ...) { names(x) <- eval(substitute(c(...))) x } baixa_sabesp <- function(x) { link <- 'http://www2.sabesp.com.br/mananciais/DivulgacaoSiteSabesp.aspx' txt <- GET(link) viewstate <- txt %>% content('text') %>% html %>% html_node('#__VIEWSTATE') %>% html_attr('value') eventval <- txt %>% content('text') %>% html %>% html_node('#__EVENTVALIDATION') %>% html_attr('value') data <- as.Date(x) dados <- list(cmbDia=day(data), cmbMes=month(data), cmbAno=year(data), Imagebutton1.x='0', Imagebutton1.y='0', '__VIEWSTATE'=viewstate, '__EVENTVALIDATION'=eventval) r <- POST(link, body=dados, cookies=unlist(txt$cookies)) try({ nomes <- r %>% content('text') %>% html(encoding='UTF-8') %>% html_nodes('img') %>% html_attr('src') nomes <- nomes %>% `[`(!str_detect(nomes, 'jpg')) %>% str_match('/(.+)\\.gif') %>% `[`(,2) d <- r %>% content('text') %>% html(encoding='UTF-8') %>% html_node('#tabDados') %>% html_table(fill=TRUE) %>% renomear('titulo', 'info') %>% select(1:2) %>% filter(titulo!='') %>% mutate(titulo=rm_accent(gsub(' +', '_', titulo)), lugar=rep(nomes, each=4), info=gsub('[^0-9.]', '', gsub(',', '.', info))) %>% spread(titulo, info, convert=TRUE) %>% mutate(volume_armazenado=volume_armazenado/100) return(d) }) return(data.frame()) } datas <- today() - days(0:3650) d_sabesp <- datas %>% as.character %>% data.frame(data=., stringsAsFactors=F) %>% group_by(data) %>% do(baixa_sabesp(as.character(.))) %>% ungroup