R e tidyverse: um fluxo de análise reproduzível

R
tidyverse
Dados organizados
Reprodutibilidade
Finanças

Tutorial prático para importar, organizar, transformar e combinar dados em R, com foco em projetos reproduzíveis e aplicações em Finanças.

Autor
Afiliação

Prof. Dr. Washington S. da Silva

Data de Publicação

27 julho 2026

1 Para quem é este tutorial

Este material é uma introdução prática ao uso de R com o tidyverse para análises reproduzíveis. Ele foi organizado a partir de exemplos, exercícios e erros recorrentes da disciplina Introdução à Ciência de Dados ministrada no Mestrado Profissional em Administração do IFMG em 2026.

Use-o se você já instalou R e RStudio e quer construir análises de dados com mais segurança. Para instalar ou configurar ferramentas, consulte antes os tutoriais de RStudio, Quarto e Git/GitHub. Para formatar a parte textual de relatórios, consulte o tutorial de Markdown.

NotaAo final, você deverá conseguir
  • organizar um projeto e usar caminhos relativos;
  • importar e inspecionar um arquivo CSV;
  • transformar, resumir e ordenar dados com dplyr;
  • converter dados do formato amplo para o longo com pivot_longer();
  • combinar tabelas com left_join() e conferir as chaves usadas na combinação;
  • construir uma sequência encadeada de etapas de análise (pipeline), testar seus resultados e localizar erros elementares antes de entregar um trabalho.
ImportanteComo usar este material

Digite e adapte os exemplos em um projeto RStudio próprio. Não tente apenas ler o código. Ao fim de cada seção, altere pelo menos um parâmetro, filtro ou variável e confira o efeito no resultado.

2 O fluxo que vamos seguir

Uma análise aplicada raramente começa por uma função isolada. Em geral, ela segue esta sequência:

  1. definir uma pergunta e abrir o projeto correto;
  2. importar e inspecionar os dados;
  3. preparar a estrutura necessária para a análise;
  4. transformar e resumir os dados;
  5. conferir se o resultado responde à pergunta.

O tidyverse é um conjunto de pacotes com funções de nomes e usos padronizados para essas etapas. O pacote readr importa arquivos; dplyr transforma e combina tabelas; tidyr organiza formatos; e tibble ajuda a criar e visualizar tabelas. O comando abaixo carrega esse conjunto e o pacote here, usado para localizar arquivos dentro do projeto.

library(here)
library(tidyverse)

Antes do primeiro uso neste computador, instale os dois pacotes necessários na aba Console do RStudio:

# instala, uma única vez, os pacotes usados neste tutorial
install.packages(c("tidyverse", "here"))

Em cada nova sessão, carregue-os com library(tidyverse) e library(here), como no código anterior. Não coloque install.packages() no início de scripts ou relatórios: isso torna a execução lenta e menos previsível.

3 Projeto, arquivos e caminhos

Um projeto reproduzível separa arquivos de dados, scripts e relatórios. Uma estrutura inicial simples é:

meu-projeto/
├── data/
│   ├── raw/       # dados recebidos ou baixados
│   └── clean/     # dados preparados pelo seu código
├── scripts/       # scripts R
├── relatorios/    # arquivos .qmd e produtos finais
└── meu-projeto.Rproj

Abra o arquivo .Rproj antes de começar. Evite setwd() e caminhos absolutos como C:/Users/...: eles normalmente funcionam apenas no seu computador.

Com here(), um caminho é descrito a partir da raiz do projeto:

# define um caminho relativo a partir da raiz do projeto
agencias_csv <- here("data/raw/agencias.csv")

Antes de importar, confirme que você abriu o projeto correto e que o arquivo está realmente em data/raw/. Uma mensagem de “arquivo não encontrado” quase sempre indica um destes dois problemas.

4 Importar e inspecionar antes de analisar

Este tutorial usa três arquivos sintéticos, preparados exclusivamente para fins didáticos. Baixe-os e salve-os na pasta data/raw/ de um projeto RStudio seu:

Cada linha de agencias.csv identifica uma agência; credito_trimestral.csv registra seu volume de crédito por trimestre; e inadimplencia.csv registra a taxa de inadimplência para cada combinação agência–trimestre. O fluxo mínimo é definir o caminho, importar e inspecionar imediatamente:

Arquivo Unidade de observação Informação principal
agencias.csv uma agência cidade e número de cooperados
credito_trimestral.csv uma agência crédito em cada trimestre, em milhares de reais fictícios
inadimplencia.csv uma agência–trimestre taxa de inadimplência em proporção: 0.021 corresponde a 2,1%

Os valores e as entidades são fictícios. Eles servem para praticar o fluxo de análise, não para descrever uma instituição real.

# define o caminho relativo para o arquivo csv
# usando a função here() do pacote here
agencias_csv <- here("data/raw/agencias.csv")

# importa o arquivo csv com a função readr do pacote readr
# e armazena os dados no objeto agencias
agencias <- read_csv(agencias_csv)

# exibe visão geral dos dados importados
glimpse(agencias)

# visualiza as primeiras linhas da tabela
head(agencias)

glimpse() mostra o número de linhas, o nome e o tipo das colunas. Use-o antes de escrever um pipeline: ele evita erros causados por nomes diferentes, colunas lidas como texto ou valores ausentes inesperados.

DicaPerguntas de inspeção

Antes de transformar uma tabela, responda: qual é a unidade de observação, ou seja, o que cada linha representa? Quais colunas identificam uma observação? Há valores faltantes? Os nomes e tipos das colunas são os que você espera?

5 Tibbles, pipes e uma pergunta analítica

Uma tibble é uma tabela usada pelo tidyverse. Ela exibe os dados de modo mais compacto que uma data.frame tradicional. A função tribble() é uma forma prática de digitar pequenas tabelas manualmente, útil em exemplos e testes. Para manter este exemplo autossuficiente, criaremos uma base simulada de indicadores anuais:

# cria uma tibble simulada de indicadores anuais
indicadores <- tribble(
  ~empresa,        ~setor,        ~ano, ~ativo_total, ~resultado_liquido,
  "Alfa Energia",  "Energia",    2025,      820000,              49200,
  "Beta Varejo",   "Varejo",     2025,      460000,              13800,
  "Gama Saúde",    "Saúde",      2025,      610000,              42700,
  "Delta Varejo",  "Varejo",     2025,      390000,               7800,
  "Épsilon Banco", "Financeiro", 2025,     1250000,              87500
)

# verifica a estrutura da tibble criada
glimpse(indicadores)

O pipe nativo |> lê-se como “e então”. Ele permite escrever um pipeline, ou seja, uma sequência encadeada de etapas de análise. A pergunta abaixo é: quais empresas têm retorno sobre ativos (ROA, do inglês return on assets) acima de 5%, ordenadas do maior para o menor?

# calcula o ROA, seleciona empresas com rentabilidade acima de 5%
# e organiza o resultado do maior para o menor ROA
empresas_rentaveis <- indicadores |>
  mutate(roa = resultado_liquido / ativo_total) |>
  filter(roa > 0.05) |>
  select(empresa, setor, ativo_total, resultado_liquido, roa) |>
  arrange(desc(roa))

# exibe o objeto que responde à pergunta analítica
empresas_rentaveis

Cada verbo tem uma função específica:

Verbo Pergunta que ajuda a responder
select() Quais colunas são relevantes?
filter() Quais linhas atendem à condição?
mutate() Que nova variável preciso calcular?
arrange() Em que ordem devo ver o resultado?
group_by() + summarise() Como resumir grupos de observações?
AvisoNão pule a atribuição

Um pipeline só altera um objeto se você atribuir o resultado. O código abaixo apenas exibe uma nova tabela; ele não modifica indicadores.

# este pipeline apenas exibe uma nova tabela; não altera indicadores
indicadores |>
  mutate(roa = resultado_liquido / ativo_total)

Quando quiser conservar o resultado, atribua-o a um nome claro, como em indicadores_com_roa <- ....

6 Agrupar e resumir

Agora responda à pergunta: qual é o ativo total e o ROA médio simples por setor?

# calcula o ROA e resume número de empresas, ativo e ROA médio simples por setor
resumo_setor <- indicadores |>
  mutate(roa = resultado_liquido / ativo_total) |>
  group_by(setor) |>
  summarise(
    empresas = n(),
    ativo_total = sum(ativo_total),
    roa_medio_simples = mean(roa)
  ) |>
  arrange(desc(roa_medio_simples))

# exibe o resumo por setor
resumo_setor

group_by() não produz, sozinho, uma tabela resumida; ele altera o modo como o próximo verbo opera. summarise() é que reduz várias linhas a uma ou mais estatísticas por grupo. Neste exemplo, cada linha de resumo_setor representa um setor.

Como conferência, o resultado deve ter quatro linhas. Os setores Financeiro e Saúde têm ROA médio simples de 7%; Energia, de 6%; e Varejo, de 2,5%. O setor Varejo tem duas empresas e ativo total de 850.000.

NotaMédia simples não é ROA agregado

mean(roa) dá o mesmo peso a cada empresa. Portanto, ele responde à pergunta sobre a média dos ROAs das empresas, e não necessariamente sobre a rentabilidade do conjunto de ativos do setor. Para calcular o ROA agregado, some primeiro o resultado líquido e o ativo total; depois divida um pelo outro:

# calcula o ROA agregado a partir dos totais de cada setor
resumo_setor_agregado <- indicadores |>
  group_by(setor) |>
  summarise(
    resultado_liquido = sum(resultado_liquido),
    ativo_total = sum(ativo_total),
    roa_agregado = resultado_liquido / ativo_total
  ) |>
  arrange(desc(roa_agregado))

# exibe o resumo com o ROA agregado por setor
resumo_setor_agregado

7 Criar categorias com transparência

Classificações são úteis, mas os critérios precisam aparecer no código. Neste exemplo, a coluna faixa_roa documenta uma regra simples de análise:

# calcula o ROA e classifica cada empresa conforme os limites definidos
indicadores_classificados <- indicadores |>
  mutate(
    roa = resultado_liquido / ativo_total,
    faixa_roa = case_when(
      roa >= 0.08 ~ "Alta",
      roa >= 0.04 ~ "Intermediária",
      TRUE        ~ "Baixa"
    )
  )

# conta empresas em cada faixa de rentabilidade
indicadores_classificados |>
  count(faixa_roa)

Em case_when(), as condições são testadas de cima para baixo. Por isso, a ordem importa: a faixa mais restritiva vem primeiro. O caso final TRUE ~ ... garante que nenhuma observação fique sem classificação por acidente.

AvisoRegra didática, não modelo de risco

Os limites usados em faixa_roa e, mais adiante, em risco são regras simples para praticar código. Eles não estimam risco financeiro e não devem orientar decisões reais sem definição substantiva, validação e informações adequadas.

8 Dados amplos e dados longos

Planilhas gerenciais frequentemente armazenam trimestres em colunas. Isso é conveniente para leitura humana, mas dificulta agrupamentos e gráficos. Importe o arquivo de crédito, que está nesse formato amplo:

# define o caminho relativo do arquivo de crédito trimestral
credito_csv <- here("data/raw/credito_trimestral.csv")

# importa os dados no formato amplo
credito_amplo <- read_csv(credito_csv)

# verifica a estrutura antes da reorganização
glimpse(credito_amplo)

pivot_longer() transforma as colunas trimestrais em duas variáveis: uma para o trimestre e outra para o volume de crédito.

# transforma as colunas trimestrais em duas variáveis: trimestre e volume de crédito
credito_longo <- credito_amplo |>
  pivot_longer(
    cols = -id_agencia,
    names_to = "trimestre",
    values_to = "volume_credito"
  )

# exibe os dados reorganizados no formato longo
credito_longo

Depois dessa transformação, cada linha representa uma combinação agência–trimestre. Essa unidade de observação precisa orientar todos os joins, cálculos e resumos posteriores.

Como conferência, credito_longo deve ter 12 linhas: três agências em quatro trimestres. Ele deve conter as colunas id_agencia, trimestre e volume_credito.

9 Combinar tabelas sem perder o controle

Um join é uma combinação de informações de tabelas diferentes. Uma chave é a coluna, ou conjunto de colunas, usado para identificar e alinhar registros entre tabelas. O cadastro agencias já foi importado acima; agora importe a tabela de inadimplência trimestral:

# define o caminho relativo do arquivo de inadimplência trimestral
inadimplencia_csv <- here("data/raw/inadimplencia.csv")

# importa os dados de inadimplência
inadimplencia <- read_csv(inadimplencia_csv)

# verifica a estrutura dos dados importados
glimpse(inadimplencia)

Como agencias tem uma linha por agência, a chave id_agencia basta no primeiro join. Já credito_longo e inadimplencia têm uma linha por agência–trimestre; a chave precisa conter as duas colunas. left_join() preserva todas as linhas da tabela que inicia o pipeline e acrescenta as informações correspondentes da outra tabela.

# acrescenta o cadastro das agências usando a chave id_agencia
# acrescenta a inadimplência usando a chave composta agência-trimestre
# e cria indicadores de crédito por cooperado e de risco
dados_completos <- credito_longo |>
  left_join(agencias, by = "id_agencia") |>
  left_join(inadimplencia, by = c("id_agencia", "trimestre")) |>
  mutate(
    credito_por_cooperado = volume_credito / cooperados,
    risco = case_when(
      taxa_inadimplencia < 0.03 ~ "Baixo",
      taxa_inadimplencia < 0.045 ~ "Moderado",
      TRUE ~ "Alto"
    )
  )

# verifica a estrutura final após os joins e as novas variáveis
glimpse(dados_completos)

Como conferência, dados_completos deve manter 12 linhas e não pode ter valores ausentes em taxa_inadimplencia. Com estes dados, a classificação de risco produz apenas as categorias "Baixo" e "Moderado".

ImportanteConfira as chaves antes do join

Um join com chave incompleta pode duplicar linhas silenciosamente. Antes de unir tabelas, descubra a unidade de observação de cada uma. Depois, compare o número esperado de linhas e procure valores ausentes nas novas colunas. Após count(), a coluna n informa quantas linhas existem em cada combinação.

# verifica se há mais de uma linha por combinação agência-trimestre
credito_longo |> count(id_agencia, trimestre) |> filter(n > 1)

# aplica a mesma verificação à tabela de inadimplência
inadimplencia |> count(id_agencia, trimestre) |> filter(n > 1)

Se esses comandos retornarem linhas, a combinação agência–trimestre não é única e deve ser entendida antes do left_join().

10 Checklist de confiabilidade

Antes de considerar uma análise pronta, faça estas verificações:

  1. Abra o projeto RStudio correto; não use setwd().
  2. Reinicie a sessão do R e execute o script de cima para baixo.
  3. Use glimpse() após importar e após uma combinação relevante de tabelas.
  4. Imprima os objetos que respondem à pergunta analítica.
  5. Confira se as chaves utilizadas na combinação representam a unidade de cada linha.
  6. Dê nomes específicos a objetos; não reutilize resultado para coisas diferentes.
  7. Só então registre a alteração no Git e atualize o repositório remoto.

Esse processo simples previne problemas comuns: objeto criado com um nome e usado com outro, coluna esquecida em uma chave composta, filtro aplicado à tabela errada e código que funciona apenas porque há objetos antigos na memória.

11 Exercícios para praticar

Resolva em um script novo, sem copiar uma solução completa. Use os exemplos anteriores como referência, mas escreva e teste cada etapa.

  1. A partir de dados_completos, produza uma tabela por cidade com volume de crédito total, inadimplência média e número de agências. Ordene pelo volume total.
  2. Altere os limites da classificação de risco e explique, em comentário, qual decisão de gestão essa nova regra representaria.
  3. Crie uma pequena tabela com uma meta trimestral por agência e una-a a dados_completos. Antes do join, escreva qual deve ser a chave e quantas linhas você espera no resultado.
  4. Crie um arquivo Quarto curto que descreva uma das análises, inclua o código e apresente uma conclusão de três frases. Execute as células uma a uma e renderize o HTML.
DicaPróximo passo

O tidyverse ajuda a preparar dados e comunicar análises; ele não substitui o raciocínio substantivo, estatístico ou econométrico. Ao iniciar uma análise, comece pela pergunta de pesquisa e use o código para tornar o caminho até a resposta explícito, verificável e reproduzível.

12 Leituras e documentação de apoio

Esta seção serve para continuar o estudo depois de executar o tutorial. Ela não substitui a prática: use-a para esclarecer uma dúvida específica, ampliar um tópico ou revisar um conceito antes de aplicá-lo em seu próprio projeto.

12.1 Leitura estruturante

R para Ciência de Dados é a referência principal para este tutorial (Wickham, Çetinkaya-Rundel e Grolemund, 2023). O livro aprofunda o fluxo de trabalho, a transformação, a organização, a importação e as combinações de dados apresentados aqui. A tradução em português é particularmente adequada para consultar esses temas; comece pelos capítulos 2 a 7 e, quando precisar combinar tabelas, pelo capítulo 19.

Para quem ainda precisa consolidar fundamentos da linguagem R — objetos, vetores, tipos de dados, condicionais, funções e depuração — a leitura adequada é Introdução à Linguagem R: seus fundamentos e sua prática (Faria, 2024). Esse estudo é complementar e deve ser feito de forma autônoma quando a formação prévia não for suficiente para acompanhar este tutorial.

12.2 Documentação para consulta pontual

As documentações oficiais são mais úteis quando você já tem uma pergunta concreta ou uma mensagem de erro para investigar:

  • here: caminhos relativos e raiz do projeto;
  • readr: importação de arquivos de texto, inclusive CSV;
  • dplyr: transformação, agrupamento e combinação de tabelas;
  • tidyr: organização de dados entre formatos amplo e longo.

13 Referências

FARIA, P. D. Introdução à Linguagem R: seus fundamentos e sua prática. 5. ed. Belo Horizonte: [s.n.], 2024.
WICKHAM, H.; ÇETINKAYA-RUNDEL, M.; GROLEMUND, G. R for Data Science: Import, Tidy, Transform, Visualize, and Model Data. 2. ed. [s.l.] O’Reilly Media, 2023.