Quando empreendo um projeto R de qualquer complexidade, meus scripts rapidamente ficam longos e confusos.
Quais são algumas práticas que posso adotar para que meu código sempre seja um prazer trabalhar? Estou pensando em coisas como
- Colocação de funções nos arquivos de origem
- Quando dividir algo em outro arquivo de origem
- O que deve estar no arquivo mestre
- Usando funções como unidades organizacionais (se vale a pena, pois R dificulta o acesso ao estado global)
- Práticas de recuo / quebra de linha.
- Tratar (como {?
- Coloque coisas como)} em 1 ou 2 linhas?
Basicamente, quais são suas regras práticas para organizar grandes scripts R?
r
package
conventions
code-organization
project-organization
Dan Goldstein
fonte
fonte
ProjectTemplate
pacote.Respostas:
A resposta padrão é usar pacotes - consulte o manual Writing R Extensions , bem como diferentes tutoriais na Web.
Te dá
R CMD check
Apenas atropelar
source()
o código funciona para trechos muito curtos. Todo o resto deve estar em um pacote - mesmo que você não planeje publicá-lo, pois você pode escrever pacotes internos para repositórios internos.Quanto à parte 'como editar', o manual R Internals possui excelentes padrões de codificação R na Seção 6. Caso contrário, eu costumo usar padrões no modo ESS do Emacs .
Atualização 13 de agosto de 2008: David Smith acabou de publicar um blog sobre o Google R Style Guide .
fonte
Eu gosto de colocar funcionalidades diferentes em seus próprios arquivos.
Mas eu não gosto do sistema de pacotes de R. É bastante difícil de usar.
Eu prefiro uma alternativa leve, colocar as funções de um arquivo dentro de um ambiente (o que qualquer outro idioma chama de "espaço para nome") e anexá-lo. Por exemplo, eu criei um grupo de funções 'util' da seguinte forma:
Isto é tudo em um arquivo util.R . Quando você o origina, você obtém o ambiente 'util' para que você possa ligar
util$bgrep()
e assim; além disso, aattach()
ligação o torna tão justobgrep()
e funciona diretamente. Se você não colocasse todas essas funções em seu próprio ambiente, elas poluiriam o namespace de nível superior do intérprete (aquele que éls()
exibido).Eu estava tentando simular o sistema do Python, onde cada arquivo é um módulo. Seria melhor ter isso, mas isso parece bom.
fonte
sys.source
:MyEnv <- attach(NULL, name=s_env); sys.source(file, MyEnv)
. Eu até declaro (em seu próprio ambiente!) Na inicialização, uma funçãosys.source2
que procurará se um ambiente com o mesmo nome já estiver aqui e o alimenta em vez de criar um novo. Torna a adição de funções pessoais rápida, fácil e meio organizada :-)Isso pode parecer um pouco óbvio, especialmente se você é um programador, mas eis como eu penso sobre unidades de código lógicas e físicas.
Não sei se esse é o seu caso, mas quando estou trabalhando no R, raramente começo com um grande programa complexo em mente. Normalmente começo em um script e separo o código em unidades logicamente separáveis, geralmente usando funções. O código de manipulação e visualização de dados é colocado em suas próprias funções, etc. E essas funções são agrupadas em uma seção do arquivo (manipulação de dados na parte superior, visualização, etc.). Por fim, você deseja pensar em como facilitar a manutenção do script e diminuir a taxa de defeitos.
O quão fino / grosso você faz suas funções variará e existem várias regras básicas: por exemplo, 15 linhas de código, ou "uma função deve ser responsável por executar uma tarefa identificada por seu nome", etc. Sua milhagem varia . Como o R não suporta chamada por referência, geralmente sou capaz de tornar minhas funções muito refinadas quando envolve a passagem de quadros de dados ou estruturas similares. Mas isso pode ser uma compensação excessiva por alguns erros de desempenho tolos quando eu comecei com R.
Quando extrair unidades lógicas em suas próprias unidades físicas (como arquivos de origem e agrupamentos maiores, como pacotes)? Eu tenho dois casos Primeiro, se o arquivo ficar muito grande e rolar entre unidades logicamente não relacionadas é um aborrecimento. Segundo, se eu tiver funções que possam ser reutilizadas por outros programas. Geralmente começo colocando algumas unidades agrupadas, como funções de manipulação de dados, em um arquivo separado. Eu posso então originar este arquivo de qualquer outro script.
Se você estiver implantando suas funções, precisará começar a pensar em pacotes. Eu não implanto código R na produção ou para reutilização por outras pessoas por várias razões (brevemente: a cultura organizacional prefere outros idiomas, preocupações com desempenho, GPL, etc.). Além disso, costumo refinar e adicionar constantemente às minhas coleções de arquivos de origem, e prefiro não lidar com pacotes quando faço uma alteração. Portanto, você deve verificar as outras respostas relacionadas ao pacote, como Dirk, para obter mais detalhes nesta frente.
Por fim, acho que sua pergunta não é necessariamente particular para R. Eu realmente recomendaria a leitura de Code Complete, de Steve McConnell, que contém muita sabedoria sobre esses problemas e práticas de codificação em geral.
fonte
Eu concordo com o conselho de Dirk! IMHO, organizar seus programas de scripts simples a pacotes documentados é, para Programação em R, como alternar do Word para o TeX / LaTeX para escrever. Eu recomendo dar uma olhada nos muito úteis Criando Pacotes R: um tutorial de Friedrich Leisch.
fonte
Minha resposta concisa:
Acredito que R seja cada vez mais utilizado na produção, portanto, a necessidade de código reutilizável é maior do que antes. Acho o intérprete muito mais robusto do que antes. Não há dúvida de que R é 100-300x mais lento que C, mas geralmente o gargalo está concentrado em algumas linhas de código, que podem ser delegadas ao C / C ++. Eu acho que seria um erro delegar os pontos fortes de R na manipulação de dados e análise estatística para outro idioma. Nesses casos, a penalidade de desempenho é baixa e, em qualquer caso, vale a pena a economia no esforço de desenvolvimento. Se apenas o tempo de execução fosse o problema, estaríamos todos escrevendo assembler.
fonte
Eu pretendo descobrir como escrever pacotes, mas não investi tempo. Para cada um dos meus miniprojetos, mantenho todas as minhas funções de baixo nível em uma pasta chamada 'functions /' e as origino em um espaço para nome separado que eu criei explicitamente.
As seguintes linhas de código criarão um ambiente chamado "myfuncs" no caminho de pesquisa, se ele ainda não existir (usando o anexo), e o preencherão com as funções contidas nos arquivos .r no meu diretório 'functions /' (usando sys.source). Eu costumo colocar essas linhas na parte superior do meu script principal destinado à "interface do usuário" a partir da qual as funções de alto nível (invocando as funções de baixo nível) são chamadas.
Quando você faz alterações, sempre pode recolocá-las nas mesmas linhas ou usar algo como
para avaliar adições / modificações no ambiente que você criou.
É kludgey eu sei, mas evita ter que ser formal demais sobre isso (mas se você tiver a chance, eu incentivo o sistema de pacotes - espero que eu migre dessa maneira no futuro).
Quanto às convenções de codificação, essa é a única coisa que eu tenho visto em relação à estética (eu gosto e sigo livremente, mas não uso muitas chaves no R):
http://www1.maths.lth.se/help/R/RCC/
Existem outras "convenções" relacionadas ao uso de [, drop = FALSE] e <- como o operador de atribuição sugeriu em várias apresentações (geralmente na palestra) no useR! conferências, mas não acho que nenhuma delas seja rigorosa (embora o [, drop = FALSE] seja útil para programas em que você não tem certeza da contribuição esperada).
fonte
Conte-me como outra pessoa a favor dos pacotes. Eu admito que sou muito pobre em escrever páginas de manual e vinhetas até se / quando eu precisar (isto é, ser lançado), mas isso é uma maneira realmente útil de agrupar a fonte doe. Além disso, se você levar a sério a manutenção do seu código, os pontos que Dirk menciona todos entram em plya.
fonte
Eu também concordo. Use a função package.skeleton () para começar. Mesmo que você ache que seu código nunca poderá ser executado novamente, isso pode ajudar a motivá-lo a criar um código mais geral que pode economizar seu tempo mais tarde.
Quanto ao acesso ao ambiente global, isso é fácil com o operador << -, embora seja desencorajado.
fonte
Como ainda não aprendi a escrever pacotes, sempre me organizei fornecendo sub-scripts. É semelhante a escrever aulas, mas não tão envolvido. Não é programaticamente elegante, mas acho que desenvolvo análises ao longo do tempo. Depois de ter uma seção grande que funciona, geralmente a movo para um script diferente e apenas a origino, pois ela usará os objetos da área de trabalho. Talvez eu precise importar dados de várias fontes, classificar todas elas e encontrar as interseções. Eu poderia colocar essa seção em um script adicional. No entanto, se você deseja distribuir seu "aplicativo" para outras pessoas, ou ele usa alguma entrada interativa, um pacote provavelmente é uma boa rota. Como pesquisador, raramente preciso distribuir meu código de análise, mas muitas vezes preciso aumentá-lo ou ajustá-lo.
fonte
Também tenho procurado o Santo Graal do fluxo de trabalho certo para montar um projeto de grande porte. Eu encontrei no ano passado este pacote chamado rsuite e, certamente, era o que eu procurava. Este pacote R foi desenvolvido explicitamente para a implantação de grandes projetos de R, mas descobri que ele pode ser usado para projetos R menores, médios e grandes. Vou dar links para exemplos do mundo real em um minuto (abaixo), mas primeiro eu quero explicar o novo paradigma de construção de projectos de I com
rsuite
.Nota. Não sou o criador ou desenvolvedor do
rsuite
.Temos feito projetos errados com o RStudio; o objetivo não deve ser a criação de um projeto ou pacote, mas de um escopo maior. No rsuite, você cria um superprojeto ou projeto mestre, que mantém os projetos e pacotes R padrão, em todas as combinações possíveis.
Por ter um superprojeto R, você não precisa mais do Unix
make
para gerenciar os níveis mais baixos dos projetos R; você usa scripts R na parte superior. Deixe-me te mostrar. Ao criar um projeto mestre do rsuite, você obtém esta estrutura de pastas:A pasta
R
é onde você coloca seus scripts de gerenciamento de projetos, os que serão substituídosmake
.A pasta
packages
é a pasta ondersuite
contém todos os pacotes que compõem o superprojeto. Você também pode copiar e colar um pacote que não está acessível na Internet, e o rsuite também o compilará.a pasta
deployment
é ondersuite
gravará todos os binários do pacote que foram indicados nosDESCRIPTION
arquivos dos pacotes . Assim, isso faz, por si só, você projetar um tempo acumulado totalmente reproduzível.rsuite
vem com um cliente para todos os sistemas operacionais. Eu testei todos eles. Mas você também pode instalá-lo como umaddin
para o RStudio.rsuite
também permite criar umaconda
instalação isolada em sua própria pastaconda
. Este não é um ambiente, mas uma instalação física do Python derivada do Anaconda em sua máquina. Isso funciona em conjunto com os R'sSystemRequirements
, dos quais você pode instalar todos os pacotes Python desejados, a partir de qualquer canal conda que desejar.Você também pode criar repositórios locais para extrair pacotes R quando estiver offline ou desejar criar a coisa toda mais rapidamente.
Se desejar, também é possível criar o projeto R como um arquivo zip e compartilhá-lo com os colegas. Ele será executado, desde que seus colegas tenham a mesma versão R instalada.
Outra opção é construir um contêiner de todo o projeto no Ubuntu, Debian ou CentOS. Portanto, em vez de compartilhar um arquivo zip com a construção do seu projeto, você compartilha todo o
Docker
contêiner com o seu projeto pronto para execução.Eu tenho experimentado muito
rsuite
procurando a reprodutibilidade total e evito depender dos pacotes que se instala no ambiente global. Isso está errado porque, assim que você instala uma atualização de pacote, o projeto, mais frequentemente, para de funcionar, especialmente aqueles pacotes com chamadas muito específicas para uma função com determinados parâmetros.A primeira coisa que comecei a experimentar foi com e-
bookdown
books. Eu nunca tive a sorte de ter um livro para sobreviver ao teste do tempo por mais de seis meses. Então, o que fiz foi converter o projeto original de bookdown para seguir arsuite
estrutura. Agora, não preciso me preocupar em atualizar meu ambiente R global, porque o projeto possui seu próprio conjunto de pacotes nadeployment
pasta.A próxima coisa que fiz foi criar projetos de aprendizado de máquina, mas no
rsuite
caminho. Um mestre, orquestrando o projeto na parte superior e todos os subprojetos e pacotes para estar sob o controle do mestre. Realmente muda a maneira como você codifica com R, tornando-o mais produtivo.Depois disso, comecei a trabalhar em um novo pacote chamado
rTorch
. Isso foi possível, em grande parte, por causa dersuite
; permite que você pense e se torne grande.Um conselho embora. Aprender
rsuite
não é fácil. Por apresentar uma nova maneira de criar projetos de R, é difícil. Não desanime nas primeiras tentativas, continue subindo a ladeira até você conseguir. Requer conhecimento avançado do seu sistema operacional e do seu sistema de arquivos.Espero que um dia
RStudio
nos permita gerar projetos de orquestração, comorsuite
acontece no menu. Seria maravilhoso.Ligações:
Repo RSuite GitHUb
bookdown r4ds
keras e tutorial brilhante
moderndive-book-rsuite
interpretable_ml-rsuite
IntroMachineLearningWithR-rsuite
clark-intro_ml-rsuite
hyndman-bookdown-rsuite
statistics_rethinking-rsuite
fread-benchmarks-rsuite
dataviz-rsuite
tutorial-segmentação-h2o-varejo
telco-customer-churn-tutorial
sclerotinia_rsuite
fonte
R é bom para uso interativo e pequenos scripts, mas eu não o usaria para um programa grande. Eu usaria uma linguagem mainstream para a maior parte da programação e a envolvia em uma interface R.
fonte
Rcpp
pacote, incluindo o código C ++ nos programas R, torna-se bastante simples. Portanto, a reescrita de certas partes do código R pode ser integrada ao R com bastante facilidade. Além disso, o advento do RStudio introduziu um IDE para R, embora talvez ainda não seja tão poderoso quanto o Visual Studio.