
Oi, habrozhiteli! Muitos usuários usam R para tarefas específicas - aqui para construir um histograma, para realizar uma análise de regressão ou executar outras operações separadas relacionadas ao processamento estatístico de dados. Mas este livro foi escrito para aqueles que desejam desenvolver software em R. As habilidades de programação dos leitores pretendidos deste livro podem variar de uma qualificação profissional a “Eu fiz um curso de programação na faculdade”, mas a chave é escrever código R para fins específicos . (Um conhecimento completo de estatística geralmente não é necessário.)
Alguns exemplos de leitores que podem se beneficiar deste livro:
- Um analista (por exemplo, trabalhando em um hospital ou agência governamental) que precisa emitir regularmente relatórios estatísticos e desenvolver programas para esse fim.
- Um cientista envolvido no desenvolvimento de uma metodologia estatística - novos ou integrando métodos existentes em procedimentos integrados. A metodologia precisa ser codificada para que possa ser usada na comunidade de pesquisa.
- Especialistas em marketing, suporte jurídico, jornalismo, publicação, etc., envolvidos no desenvolvimento de código para a construção de representações gráficas complexas de dados.
- Programadores profissionais com experiência em desenvolvimento de software atribuídos a projetos relacionados à análise estatística.
- Alunos estudando estatística e processamento de dados.
Portanto, este livro não é uma referência aos inúmeros métodos estatísticos do maravilhoso pacote R. De fato, ele é dedicado à programação e lida com questões de programação que raramente são encontradas em outros livros sobre R. Mesmo tópicos fundamentais são considerados do ponto de vista da programação. Alguns exemplos dessa abordagem:
- Este livro contém seções dos "Exemplos avançados". Geralmente, eles fornecem funções de uso geral completas em vez de partes isoladas de código com base em dados específicos. Além disso, algumas dessas funções podem ser úteis no seu trabalho diário com R. Ao estudar esses exemplos, você aprenderá não apenas como construções R específicas funcionam, mas também como combiná-las em programas úteis. Em muitos casos, forneço descrições de soluções alternativas e respondo à pergunta: "Por que isso foi feito dessa maneira?"
- O material é apresentado levando em consideração a percepção do programador. Por exemplo, ao descrever quadros de dados, não apenas afirmo que o quadro de dados em R é uma lista, mas também aponto as consequências desse fato do ponto de vista da programação. Também no texto, R é comparado com outros idiomas onde pode ser útil (para leitores que falam esses idiomas).
- A depuração desempenha um papel crucial na programação em qualquer idioma, mas a maioria dos livros sobre R não menciona esse tópico. Neste livro, dediquei um capítulo inteiro às ferramentas de depuração, usei o princípio de "exemplos avançados" e apresentei demonstrações totalmente desenvolvidas de como os programas são depurados na realidade.
- Atualmente, os computadores com vários núcleos têm aparecido em todos os lares, e a programação de processadores gráficos (GPUs) está produzindo uma revolução imperceptível no campo da computação científica. Cada vez mais aplicativos R requerem quantidades muito grandes de computação, e o processamento paralelo tornou-se relevante para os programadores R. Um capítulo inteiro é dedicado a esse tópico no livro, além de descrever a mecânica, também são fornecidos exemplos avançados.
- Um capítulo separado fala sobre como usar informações sobre implementação interna e outros aspectos do R para acelerar o trabalho do código R.
- Um dos capítulos se concentra na interface do R com outras linguagens de programação como C e Python. Mais uma vez, é dada atenção especial a exemplos avançados e recomendações para depuração.
Trecho. 7.8.4 Quando as variáveis globais devem ser usadas?
Não há consenso sobre o uso de variáveis globais na comunidade de programadores. Obviamente, não há resposta certa para a pergunta colocada no título desta seção, pois é uma questão de preferências e estilo pessoais. No entanto, muitos programadores acreditam que uma proibição completa de variáveis globais, defendida por muitos professores de programação, seria desnecessariamente difícil. Nesta seção, examinamos os possíveis benefícios das variáveis globais no contexto das estruturas R. O termo "variável global" significa qualquer variável que esteja na hierarquia do ambiente acima do nível do código de interesse.
O uso de variáveis globais em R é mais comum do que você poderia esperar. Surpreendentemente, R usa variáveis globais muito amplamente em sua implementação interna (tanto no código C quanto nas funções R). Portanto, o operador de super-atribuição << - é usado em muitas funções da biblioteca de R (embora normalmente seja usado para gravar em uma variável localizada apenas um nível acima na hierarquia de variáveis). O código multiencadeado e o código GPU usados para escrever programas rápidos (consulte o capítulo 16) geralmente usam variáveis globais que fornecem o principal mecanismo de interação entre executores paralelos.
Agora, para concretude, voltemos a um exemplo anterior da seção 7.7:
f <- function(lxxyy) { # lxxyy — , x y ... lxxyy$x <- ... lxxyy$y <- ... return(lxxyy) } # x y lxy$x <- ... lxy$y <- ... lxy <- f(lxy) # x y ... <- lxy$x ... <- lxy$y
Como mencionado anteriormente, esse código pode se tornar complicado, especialmente se xey forem listas.
Por outro lado, dê uma olhada em um esquema alternativo usando variáveis globais:
f <- function() { ... x <<- ... y <<- ... } # x y x <-... y <-... f() # x y # x y ... <- x ... <- y
Talvez a segunda versão seja muito mais limpa, menos volumosa e não exija manipulação de lista. O código claro geralmente cria menos problemas de gravação, depuração e manutenção.
Por esses motivos - para simplificar e reduzir o volume do código -, decidimos usar variáveis globais em vez de retornar listas no código DES fornecido anteriormente. Considere este exemplo em mais detalhes.
Duas variáveis globais foram usadas (ambas são listas que contêm informações diferentes): a variável sim está associada ao código da biblioteca e a variável mm1glbls está associada ao código de aplicativo específico M / M / 1. Vamos começar com o sim.
Até os programadores restritos a variáveis globais concordam que o uso de tais variáveis pode ser justificado se forem verdadeiramente globais - no sentido em que são amplamente utilizados no programa. Tudo isso está relacionado à variável sim do exemplo DES: é usada no código da biblioteca (em schedevnt (), getnextevnt () e dosim ()) e no código M / M / 1 (em mm1reactevnt ()). Neste exemplo em particular, as chamadas subseqüentes para o sim são limitadas à leitura, mas a gravação é possível em algumas situações. Um exemplo típico desse tipo é uma possível implementação de cancelamento de evento. Por exemplo, essa situação pode ocorrer ao modelar o princípio “mais cedo dos dois”: dois eventos são planejados e, quando um deles ocorre, o outro deve ser cancelado.
Assim, o uso do sim como variável global parece justificado. No entanto, se recusássemos resolutamente a usar variáveis globais, o sim poderia ser colocado em uma variável local dentro do dosim (). Esta função passará sim no argumento de todas as funções mencionadas no parágrafo anterior (schedevnt (), getnextevnt (), etc.), e cada uma dessas funções retornará uma variável sim modificada.
Por exemplo, linha 94:
reactevnt(head)
convertido para o seguinte formulário:
sim <- reactevnt(head)
Depois disso, a seguinte linha deve ser adicionada à função mm1reactevnt () associada a um aplicativo específico:
return(sim)
Você pode fazer algo semelhante ao mm1glbls incluindo no dosim () uma variável local com o nome (por exemplo) appvars. Mas se isso for feito com duas variáveis, elas deverão ser colocadas na lista para que ambas possam ser retornadas da função, como no exemplo acima da função f (). E então surge a estrutura volumosa de listas dentro de listas, mencionada acima, ou melhor, listas dentro de listas dentro de listas.
Por outro lado, os oponentes do uso de variáveis globais percebem que a simplicidade do código não é em vão. Eles estão preocupados que, durante o processo de depuração, haja dificuldades em encontrar locais onde a variável global altere o valor, pois a alteração pode ocorrer em qualquer lugar do programa. Parece que no mundo dos editores de texto modernos e das ferramentas de desenvolvimento integradas que ajudarão a encontrar todas as ocorrências de uma variável, o problema vai além do caminho (o artigo original pedindo para se recusar a usar variáveis globais foi publicado em 1970!). No entanto, esse fator deve ser levado em consideração.
Outro problema mencionado pelos críticos é encontrado ao chamar uma função de várias partes não relacionadas de um programa com valores diferentes. Por exemplo, imagine que a função f () seja chamada de diferentes partes do programa, com cada chamada recebendo seus próprios valores x e y em vez de um valor para cada. O problema pode ser resolvido criando vetores de valores x e y nos quais cada instância de f () no seu programa possui um elemento separado. No entanto, isso perderá a simplicidade do uso de variáveis globais.
Esses problemas são encontrados não apenas em R, mas também em um contexto mais geral. No entanto, em R, o uso de variáveis globais no nível superior cria um problema adicional, pois o usuário nesse nível geralmente possui muitas variáveis. Existe o perigo de que o código que utiliza variáveis globais possa substituir acidentalmente uma variável completamente estranha pelo mesmo nome.
Obviamente, o problema é facilmente resolvido - basta escolher nomes longos para variáveis globais vinculadas a um aplicativo específico. No entanto, os ambientes também fornecem um compromisso razoável, como na situação a seguir para o exemplo do DES.
Dentro da função dosim (), a linha
sim <<- list()
pode ser substituído por uma string
assign("simenv",new.env(),envir=.GlobalEnv)
Ele cria um novo ambiente referenciado pela variável simenv no nível superior. Esse ambiente serve como um contêiner para encapsular variáveis globais que podem ser acessadas por chamadas para get () e assign (). Por exemplo, strings
if (is.null(sim$evnts)) { sim$evnts <<- newevnt
em schedevnt () assume o formato
if (is.null(get("evnts",envir=simenv))) { assign("evnts",newevnt,envir=simenv)
Sim, esta solução também é complicada, mas pelo menos não é tão complicada quanto as listas dentro de listas dentro de listas. E protege contra gravação acidental em uma variável estranha no nível superior. O uso do operador de super-atribuição ainda fornece código menos complicado, mas essa troca deve ser levada em consideração.
Como sempre, não há um estilo de programação único que ofereça os melhores resultados em todas as situações. Uma solução com variáveis globais é outra opção que deve ser incluída no seu arsenal de ferramentas de programação.
7.8.5 Curto-circuito
Deixe-me lembrá-lo de que o fechamento de R consiste em argumentos e no corpo da função em conjunto com o ambiente no momento da chamada. O fato de possibilitar o ambiente está envolvido no paradigma de programação, que usa o conceito, também chamado de encerramento (há alguma sobrecarga de terminologia aqui).
Um fechamento é uma função que cria uma variável local e, em seguida, cria outra função que acessa essa variável. A descrição é muito abstrata, então é melhor dar um exemplo.
1 > counter 2 function () { 3 ctr <- 0 4 f <- function() { 5 ctr <<- ctr + 1 6 cat("this count currently has value",ctr,"\n") 7 } 8 return(f) 9 }
Vamos verificar como esse código funciona antes de mergulhar nos detalhes da implementação:
> c1 <- counter() > c2 <- counter() > c1 function() { ctr <<- ctr + 1 cat("this count currently has value",ctr,"\n") } <environment: 0x8d445c0> > c2 function() { ctr <<- ctr + 1 cat("this count currently has value",ctr,"\n") } <environment: 0x8d447d4> > c1() this count currently has value 1 > c1() this count currently has value 2 > c2() this count currently has value 1 > c2() this count currently has value 2 > c2() this count currently has value 3 > c1() this count currently has value 3
Aqui, a função counter () é chamada duas vezes e os resultados são atribuídos c1 e c2. Como esperado, essas duas variáveis consistem em funções, ou seja, cópias de f (). No entanto, f () acessa a variável ctr através do operador de super atribuição, e essa variável será uma variável com o nome especificado local para counter (), pois será a primeira no caminho na hierarquia do ambiente. Faz parte do ambiente f () e, como tal, é empacotado no que retorna ao lado da chamada do contador (). O ponto principal é que, com chamadas diferentes para counter (), a variável ctr estará em ambientes diferentes (no ambiente de exemplo, ela foi armazenada na memória nos endereços 0x8d445c0 e 0x8d447d4). Em outras palavras, chamadas diferentes para counter () criarão instâncias fisicamente diferentes de ctr.
Como resultado, as funções c1 () e c2 () funcionam como contadores completamente independentes. Isso pode ser visto no exemplo em que cada função é chamada várias vezes.
»Mais informações sobre o livro podem ser encontradas no
site do editor»
Conteúdo»
TrechoCupom de 25% de desconto para vendedores ambulantes -
RApós o pagamento da versão em papel do livro, uma versão eletrônica do livro é enviada por e-mail.