A filosofia do Tidyverse

Explore os princípios de design do tidyverse: consistência, pipes, funções especializadas e as vantagens e desvantagens dessa abordagem gramatical para programação em R.
tidyverse
data-science
R
filosofia
Published

August 16, 2025

A filosofia do tidyverse

A filosofia geral do tidyverse toma muito emprestado da gramática. As funções têm nomes de verbos que costumam ser intuitivos e são encadeados via “pipes”1 que funcionam como conectivos numa frase. Em tese, isto torna o código mais legível e até mais didático. A tarefa de renomear colunas, criar variáveis e calcular uma média nos grupos torna-se “linear” no mesmo sentido em que uma frase com sujeito-verbo-objeto é linear.

Pipes

O pipe, essencialmente, carrega o resultado de uma função adiante numa cadeia de comandos: objeto |> função1 |> função2 |> função3. Isto tem duas vantagens: primeiro, evita que você use funções compostas que são lidas “de dentro para fora” como exp(mean(log(x))); e, segundo, dispensa a criação de objetos intermediários “inúteis” que estão ali somente para segurar um valor que não vai ser utilizado mais adiante.

model <- lm(log(AirPassengers) ~ time(AirPassengers))

#> Função composta
mean(exp(fitted(model)))
#> Usando pipes
model |> fitted() |> exp() |> mean()
#> Usando objetos intermediários
x1 <- fitted(model)
x2 <- exp(x1)
x3 <- mean(x2)

Num contexto de manipulação de dados pode-se ter algo como o código abaixo.

tab_vendas_cidade <- dados |>
  #> Renomeia colunas
  rename(date = data, city = cidade, variable = vendas, value = valor) |>
  #> Transforma colunas
  mutate(
    value = value / 1000,
    date = readr::parse_date(date, format = "%Y-%b%-d", locale = readr::locale("pt")),
    year = lubridate::year(date)
    ) |>
  #> Agrupa pela coluna year e calcula algumas estatísticas
  group_by(year) |>
  summarise(
    total = sum(value),
    count = n()
  )

Em base-R o mesmo código ficaria algo como o descrito abaixo.

names(dados) <- c("date", "city", "variable", "value")

dados$value <- dados$value / 1000
dados$date <- readr::parse_date(
  dados$date, format = "%Y-%b%-d", locale = readr::locale("pt")
  )
dados$year <- lubridate::year(dados$date)

tab_vendas_cidade <- tapply(
  dados$value,
  dados$city,
  \(x) {data.frame(total = sum(x), count = length(x))}
  )

Há um tempo atrás argumentava-se contra o uso de “pipes”, pois estes dificultavam a tarefa de encontrar bugs no código. Isto continua sendo parcialmente verdade, mas as funções do tidyvserse atualmente têm mensagens de erro bastante ricas e permitem encontrar a fonte do erro com relativa facilidade. Ainda assim, não se recomenda encadear funções em excesso, i.e., pipes com 10 funções ou mais2.

Funções

Outra filosofia do tidyverse é de que tarefas rotineiras devem ser transformadas em funções específicas. Neste sentido, os pacotes dplyr, tidyr e afins são recheados de funções, às vezes com nomes muito semelhantes e com usos redundantes. As funções starts_with e ends_with, por exemplo, são casos específicos da função matches. Há funções que permitem até duas formas de grafia como summarise e summarize. Outras como slice_min e slice_max são convenientes mas são literalmente: arrange + slice.

Somando somente os dois principais pacotes, dplyr e tidyr, há 360 funções disponíveis. Contraste isto com o data.table que permite fazer 95% das transformações de dados somente com dt[i, j, by = c(), .SDcols = cols].

Mesmo as funções base do R costumam ser mais sucintas do que códigos em tidyverse. No exemplo abaixo, a função tapply consegue o mesmo resultado que o código mais extenso feito com dplyr.

tapply(mtcars$mpg, mtcars$cyl, mean)

mtcars |>
  group_by(cyl) |>
  summarise(avg = mean(cyl))

As vantagens do tidyverse se tornam mais evidentes com o tempo. De fato, o pacote permite abstrações muito poderosas, e eventualmente, pode-se fazer um código centenas de vezes mais sucinto combinando as suas funções. Em outros casos, as funções do tidyverse são simplesmente muito convenientes.

Tome a starts_with, por exemplo, que seleciona as colunas que começam de uma certa forma. Suponha uma tabela simples em que há múltiplas colunas cujos nomes começam com a letra “x”. O código em tidyverse é muito mais limpo que o código em base-R.

df <- df |>
  select(date, starts_with("x"))

df <- df[, c("date", names(df)[grep("^x", names(df))])]
df <- df[, c("date", names(df)[stringr::str_detect(names(df), "^x")])]

O exemplo abaixo é inspirado neste post, que mostra como calcular lags de uma série de tempo que esteja em um data.frame. Calcular defasagens de uma série de tempo é uma tarefa um pouco árdua quando se usa somente funções base. O código abaixo mostra não somente a elegância do tidyverse mas também a facilidade em se criar funções a partir do tidyverse.

calculate_lags <- function(df, var, lags) {

 map_lag <- lags |> map(~partial(lag, n = .x))
 out <- df |>
   mutate(
     across(.cols = {{var}},
            .fns = map_lag,
            .names = "{.col}_lag{lags}")
     )

 return(out)
}

df <- data.frame(
  date = time(AirPassengers),
  value = as.numeric(AirPassengers)
)

df |> calculate_lags(value, 1:3) |> head()
#       date value value_lag1 value_lag2 value_lag3
# 1 1949.000   112         NA         NA         NA
# 2 1949.083   118        112         NA         NA
# 3 1949.167   132        118        112         NA
# 4 1949.250   129        132        118        112
# 5 1949.333   121        129        132        118
# 6 1949.417   135        121        129        132

Desvantagens

O lado negativo da abordagem “gramatical” é que para não-falantes de inglês muitas destas vantagens são despercebidas3 e o resultado é somente um código “verborrágico”, cheio de funções. Além disso, pode-se argumentar que há ambiguidades inerentes na linguagem. A função filter, por exemplo, é utilizada para filtrar as linhas de um data.frame, mas podia, igualmente, chamar-se select, que selecionaria as linhas de um data.frame. A função select, contudo, é usada para selecionar as colunas de um data.frame.

Um fato particularmente irritante do tidyverse é a frequência com que os pacotes mudam. Na maior parte das vezes, as mudanças são positivas, mas isto faz com que o código escrito em tidyverse não seja sustentável ao longo do tempo.

Eu demorei um bom tempo para entender as funções tidyr::gather e tidyr::spread e, atualmente, ambas foram descontinuadas e substituídas pelas funções pivot_longer e pivot_wider4. As funções mutate_if, mutate_at e similares do dplyr foram todas suprimidas pela sinataxe mais geral do across. A função tidyr::separate agora está sendo substituída por separate_wider_position e separate_wider_delim.

Mesmo um código bem escrito há poucos anos atrás tem grandes chances de não funcionar mais porque as funções foram alteradas ou descontinuadas. Em 2021, Wickham discutiu este problema abertamente numa palestra. Desde então, o tidyverse tem melhorado a sua política de manutenção de funções.

A velocidade e eficiência das funções do tidyverse pode ser um problema, mas atualmente existem diversas boas soluções como o já citado tidytable. Particularmente, são raras as situações em que a velocidade do tidyverse me incomoda.

Atualmente, parece haver um consenso crescente de que a melhor forma de começar a aprender R é começando pelo tidyverse; esta visão não é livre de críticos como de Norm Matloff, professor de estatística da UC Davis. Essencialmente, Matloff considera que o tidyverse é muito complexo para iniciantes: há muitas funções para se aprender e o incentivo à programação funcional torna o código muito abstrato. O tidyverse também esconde o uso do base-R e não ensina operadores básicos como [[ e $. Matloff também considera que “pipes” prejudicam o aprendizado pois dificultam a tarefa de encontrar a fonte dos erros no código.

Encontrando o equilíbrio

A realidade é que tanto os defensores quanto os críticos do tidyverse têm pontos válidos. O ideal não é escolher um “lado”, mas entender as forças e limitações de cada abordagem.

Quando usar tidyverse

O tidyverse brilha em:

  • Análise exploratória de dados: A combinação dplyr + ggplot2 é imbatível para explorar dados rapidamente
  • Relatórios e análises reprodutíveis: A legibilidade do código facilita a manutenção
  • Ensino e aprendizado: A sintaxe intuitiva acelera a curva de aprendizado
  • Trabalho colaborativo: Código mais padronizado facilita o trabalho em equipe

Quando considerar base-R

Base-R pode ser preferível para:

  • Performance crítica: Operações simples em grandes datasets
  • Pacotes e funções: Reduz dependências externas
  • Estatística avançada: Muitos métodos estatísticos usam estruturas base-R
  • Programação de sistemas: Controle fino sobre memória e performance

Conclusão: Uma ferramenta, não uma religião

O tidyverse é um conjunto de pacotes excepcionalmente bem projetados que revolucionaram a forma como fazemos análise de dados em R. Sua filosofia gramatical, consistência sintática e foco na experiência do usuário o tornam uma ferramenta poderosa, especialmente para cientistas de dados e analistas.

As principais contribuições do tidyverse foram:

  1. Democratização: Tornou R mais acessível para não-programadores
  2. Padronização: Criou convenções consistentes em um ecossistema tradicionalmente fragmentado
  3. Produtividade: Permitiu análises complexas com menos código
  4. Comunidade: Fomentou uma comunidade vibrante de usuários e desenvolvedores

Contudo, é importante reconhecer que:

  • Tidyverse não substitui completamente o conhecimento de base-R
  • A escolha da ferramenta deve depender do contexto e objetivos
  • Fluência em ambas as abordagens torna você um programador R mais completo

Minha recomendação

Para a maioria dos casos, especialmente em ciência de dados, o tidyverse oferece a melhor combinação de produtividade, legibilidade e facilidade de aprendizado. Mas invista tempo aprendendo base-R também - você será um programador R mais versátil e capaz.

Como disse o próprio Hadley Wickham: “O tidyverse não é uma tentativa de substituir R, mas de torná-lo mais consistente e expressivo”.

Próximos passos na série

Recursos para aprofundar

Para entender a filosofia do tidyverse: - Tidy Tools Manifesto - Os princípios oficiais - Design Principles - Guia de design detalhado

Para base-R: - Grolemund, G. Hands-on programming with R - Wickham, H. Advanced R (1ª ed.) - A primeira edição cobre mais base-R

Para críticas construtivas: - TidyverseSkeptic - Perspectiva alternativa de Norm Matloff

Footnotes

  1. Para saber mais sobre pipes e a diferença entre o novo pipe nativo |> e o pipe |> do magrittr veja meu post sobre o assunto.↩︎

  2. Para mais sobre pipes consulte o meu post sobre o assunto.↩︎

  3. No fundo, isto é ainda mais um incentivo para aprender inglês.↩︎

  4. Tecnicamente, elas foram “superseded”, ou suplatandas. Isto significa que elas continuam existindo exatamente da forma como sempre existiram e que não receberão mais atualizações.↩︎