Nested loop com o pacote purrr no R

O pacote purrr é um dos pilares do tidyverse, ao lado do dplyr e do operador pipe em termos de utilidade e generalização. Um de seus principais objetivos é facilitar a intenção de fazer um loop com a sintaxe envolvida. Ao invés de ter que escrever um monte de códigos tediosos do tipo "for-loop" - que pouco diz ao leitor sobre o que o loop faz -, a função map do purrr pode ser lida quase como inglês puro e se encaixa perfeitamente em operações encadeadas (pipe).

Mas isso não é tudo que o purrr tem a oferecer. O pacote vai muito além das funcionalidades map, walk e suas variantes, ajudando ainda mais no trabalho com listas. Neste exercício vamos utilizar algumas dessas funcionalidades do purrr para aplicações do tipo nested loop.

Primeiro vamos entender o nested loop com um exemplo mínimo, sem usar o pacote purrr. Vamos supor que você tenha dois vetores numéricos de tamanhos diferentes e que você queira todas as combinações possíveis dos valores de ambos os vetores, concatenando os valores em um único vetor separado por um hífen. Isso poderia ser feito com o controle de fluxo for:


# Nested loop
for (i in 1:2) {
for (j in 1:4) {
print(paste(i, j, sep = "-"))
}
}

## [1] "1-1"
## [1] "1-2"
## [1] "1-3"
## [1] "1-4"
## [1] "2-1"
## [1] "2-2"
## [1] "2-3"
## [1] "2-4"

Com o purrr poderíamos fazer a mesma operação com a função walk neste contexto, onde o .y do loop de dentro é o vetor numérico 1:2 do loop de fora:


library(purrr)

# Nested loop
walk(1:2, ~walk(1:4, ~print(paste(.y, .x, sep = "-")), .y = .x))

## [1] "1-1"
## [1] "1-2"
## [1] "1-3"
## [1] "1-4"
## [1] "2-1"
## [1] "2-2"
## [1] "2-3"
## [1] "2-4"

Uma outra opção seria, em verdade, evitar o nested loop, já que é de leitura dificultosa e requer um trabalho adicional desnecessário. Portanto, seguindo o conselho do pai da linguagem de programação C++, Bjarne Stroustrup:

To become significantly more reliable, code must become more transparent. In particular, nested conditions and loops must be viewed with great suspicion. Complicated control flows confuse programmers. Messy code often hides bugs.

Poríamos criar antes uma combinação de valores usando a função cross2 e então iterar esses elementos em um loop:


library(magrittr)

cross2(1:2, 1:4) %>%
walk(
~print(paste(.[[1]], .[[2]], sep = "-"))
)

## [1] "1-1"
## [1] "2-1"
## [1] "1-2"
## [1] "2-2"
## [1] "1-3"
## [1] "2-3"
## [1] "1-4"
## [1] "2-4"

Muito melhor, concorda?

Agora vamos a um exemplo prático da vida real. Suponha que você esteja trabalhando com os dados desagregados da inflação brasileira, medida pelo IPCA do IBGE e que precise coletar esses dados usando sua API através do pacote sidrar no R. A coleta dos dados pela API tem uma limitação de 50 mil observações por requisição, portanto você precisa criar uma estratégia para coletar esses dados sem ultrapassar esse limite da API.

Uma maneira de fazer isso, não a melhor, é justamente através de um nested loop. Para operacionalizar vamos coletar os dados do IPCA provenientes das tabelas 1419 e 7060 e suas variáveis do SIDRA/IBGE:


library(sidrar)

# Vetor com códigos das tabelas do IPCA
tables <- c("Tabela 1419" = 1419, "Tabela 7060" = 7060)

# Vetor com códigos das variáveis da tabela
variables <- c(
"IPCA - Variacao mensal (%)" = 63,
"IPCA - Peso mensal" = 66,
"IPCA - Variação acumulada no ano (%)" = 69,
"IPCA - Variação acumulada em 12 meses (%)" = 2265
)

# Coletar dados com nested loop
ipca <- tables %>%
map_dfr(
~map_dfr(
.x = variables,
~get_sidra(
x = .y, # vetor de códigos das tabelas (tables)
variable = .x, # vetor de códigos das variáveis (variables)
period = "all"
),
.y = .x
)
)

A outra possibilidade é gerar primeiro uma lista com combinações entre os códigos de tabelas e códigos das variáveis e, então, iterar estes elementos em um único loop:


library(dplyr)

# Coletar dados iterando combinações no loop
ipca2 <- cross2(tables, variables) %>%
map_dfr(
~get_sidra(
x = .[[1]],
variable = .[[2]],
period = "all"
)
)

# Verificar se resultados são equivalentes
all.equal(
arrange(ipca, `Mês`),
arrange(ipca2, `Mês`)
)

## [1] TRUE

Vale enfatizar que eu apenas arranhei a superfície do assunto neste texto, mas espero ter pelo menos instigado você a fazer sua própria investigação sobre o que o purrr pode oferecer, além de tornar as iterações mais legíveis, principalmente para os casos de nested loop.

 

Compartilhe esse artigo

Facebook
Twitter
LinkedIn
WhatsApp
Telegram
Email
Print

Comente o que achou desse artigo

Outros artigos relacionados

Como automatizar tarefas repetitivas usando Python? Um exemplo para largar o Excel

Manter relatórios diários com dados e análises atualizados é um desafio, pois envolve várias etapas: coleta de dados, tratamento de informações, produção de análises e atualização de relatório. Para superar este desafio algumas ferramentas como Python + Quarto + GitHub podem ser usadas para automatizar tudo que for automatizável. Neste artigo mostramos um exemplo com dados do mercado financeiro.

Criando um Dashboard de análise de Ações no Python

Um Dashboard é um painel de controle que consolida uma variedade de informações sobre um determinado objeto de estudo em um ou mais painéis. Ele simplifica significativamente o processo de análise de dados, oferecendo uma visão global e fácil de entender. Uma maneira simples de construir um Dashboard para acompanhar uma ação específica é utilizando duas ferramentas: Quarto e Python. Neste post, mostramos o resultado da criação de um Dashboard de Ação.

Analisando séries temporais no Python e esquecendo de vez o Excel

Séries temporais representam uma disciplina extremamente importante em diversas áreas, principalmente na economia e na ciência de dados. Mas, afinal, como lidar com esses dados que se apresentam ao longo do tempo? Neste exercício, demonstraremos como compreender uma série temporal e como o Python se destaca como uma das melhores ferramentas para analisar esse tipo de dado.

como podemos ajudar?

Preencha os seus dados abaixo e fale conosco no WhatsApp

Boletim AM

Preencha o formulário abaixo para receber nossos boletins semanais diretamente em seu e-mail.