Importando vários arquivos de excel simultaneamente e transformando em dataframe

Olá,
Estou trabalhando com as bases da SSP/SP e no site para vários crimes. O site não permite baixar o ano inteiro em uma única planilha de excel. É preciso exportar mês a mês.
http://www.ssp.sp.gov.br/transparenciassp/Consulta.aspx
São planilhas com a mesma ordem e o mesmo número de coluna, mas número de linhas diferentes.

Queria saber se há um modo de ler e empilhar estes arquivos de uma só vez, mantendo apenas o rótulo de variáveis da primeira planilha na importação.

Muito obrigado.

1 Curtida

Uma coisa que você pode fazer é uma função que faz a leitura e seleciona as colunas corretas da base. Depois, você pode usar o purrr::map_dfr() para aplicar essa função a cada arquivo e depois empilhar

Fiz um exemplo aqui, com as bases de feminicídio de janeiro até abril de 2021.

library(magrittr)

arquivos <- c(
  "DadosBO_2021_1(FEMINICÍDIO).xls", 
  "DadosBO_2021_2(FEMINICÍDIO).xls", 
  "DadosBO_2021_3(FEMINICÍDIO).xls", 
  "DadosBO_2021_4(FEMINICÍDIO).xls"
)

le_arquivo_e_seleciona <- function(arquivo) {
  base_bruta <- read.delim(
    arquivo,
    fileEncoding = "UTF-16LE",
    sep = "\t",
    header = TRUE,
    stringsAsFactors = FALSE
  )
  base_selecionada <- base_bruta %>% 
    tibble::as_tibble() %>% 
    janitor::clean_names() %>% 
    dplyr::select(ano_bo:flagrante, bairro, cidade)
}


dados_empilhados <- arquivos %>% 
  # isso aqui adiciona um nome em cada item do vetor
  # para que o .id= funcione do jeito esperado
  purrr::set_names() %>% 
  purrr::map_dfr(le_arquivo_e_seleciona, .id = "arquivo")

dados_empilhados
#> # A tibble: 106 x 15
#>    arquivo   ano_bo num_bo numero_boletim bo_iniciado  bo_emitido dataocorrencia
#>    <chr>      <int>  <int> <chr>          <chr>        <chr>      <chr>         
#>  1 DadosBO_…   2021      2 2/2021         01/01/2021 … 01/01/202… 01/01/2021    
#>  2 DadosBO_…   2021      3 3/2021         02/01/2021 … 02/01/202… 02/01/2021    
#>  3 DadosBO_…   2021      3 3/2021         02/01/2021 … 02/01/202… 02/01/2021    
#>  4 DadosBO_…   2021     29 29/2021        03/01/2021 … 03/01/202… 02/01/2021    
#>  5 DadosBO_…   2021     29 29/2021        03/01/2021 … 03/01/202… 02/01/2021    
#>  6 DadosBO_…   2021      4 4/2021         04/01/2021 … 04/01/202… 04/01/2021    
#>  7 DadosBO_…   2021      4 4/2021         04/01/2021 … 04/01/202… 04/01/2021    
#>  8 DadosBO_…   2021      4 4/2021         04/01/2021 … 04/01/202… 04/01/2021    
#>  9 DadosBO_…   2021     91 91/2021        04/01/2021 … 05/01/202… 04/01/2021    
#> 10 DadosBO_…   2021     91 91/2021        04/01/2021 … 05/01/202… 04/01/2021    
#> # … with 96 more rows, and 8 more variables: horaocorrencia <chr>,
#> #   peridoocorrencia <chr>, datacomunicacao <chr>, dataelaboracao <chr>,
#> #   bo_autoria <chr>, flagrante <chr>, bairro <chr>, cidade <chr>

Created on 2021-05-30 by the reprex package (v2.0.0)

5 Curtidas

Bom dia.
Tentei reproduzir o código (pois precisarei de algo semelhante) e deu o seguinte erro:

Error in scan(file, what = “”, sep = sep, quote = quote, nlines = 1, quiet = TRUE, :
valor de ‘sep’ inválido: deve ter um byte

Sabe o que é? Pelo que entendi é erro no separador. É isso mesmo? como corrigir?
valeu,

@pvieiradeoliveira,

Não tenho certeza, mas pode ser que o separador / encoding para o arquivo que você está tentando ler não seja o mesmo que deve ser usado nos arquivos da SSP.

Se puder, mande uma reprex() do seu erro. Dessa forma conseguimos ver mais facilmente em qual linha que deu problema, e como corrigir.

@jtrecenti, estou utilizando os mesmos arquivos que vc expôs no exemplo (SSP - DadosBO_2021_1(FEMINICÍDIO).xls, DadosBO_2021_2(FEMINICÍDIO).xls, DadosBO_2021_3(FEMINICÍDIO).xls e DadosBO_2021_4(FEMINICÍDIO).xls)

Por isso que não entendi,
valeu,

Oi Julio, tudo bem?
Tentei adaptar o código e reproduzir mas deu este erro. Tô usando as bases de latrocínio.
Error in file(file, “rt”, encoding = fileEncoding) :
argumento ‘description’ inválido

Me parece que as bases de latrocinio e feminicídio são exportadas de um jeito diferente que as bases de Roubo de veículos ou de celulares que usamos em aula (cujo separador era TAB).

Antes de tentar empilhar, quando estava treinando apenas e usando a base só do mês de janeiro eu consegui ler com o readxl::read_excel . Algo que não foi possível fazer com a base de roubo de veículos…
Eu acho que o erro tá aí e no enconding, mas não consegui corrigir. :slightly_frowning_face:

Bruno,

Segue aqui uma tentativa que funcionou por aqui. O lado ruim é que, dessa forma, vão ser pulados os arquivos cuja leitura não for possível:

 # library(tidyverse)
library(magrittr)

# Import -----------------------------------------------------------------------

# tenho uma pasta com todos os arquivos baixados da SSP
# vou fazer uma lista com todos os nomes de arquivo
lista_arquivos <- fs::dir_info("data-raw/xls/") %>% 
  dplyr::select(path)


# da lista geral, vou selecionar os que dizem respeito a latrocínio e
# feminicídio

lista_latrocinio <- lista_arquivos %>% 
  # colocar (?i) significa que ignora maiúsculas e minúsculas
  dplyr::filter(stringr::str_detect(path, "(?i)latrocinio")) %>% 
  dplyr::pull(path)

lista_feminicidio <- lista_arquivos %>% 
  dplyr::filter(stringr::str_detect(path, "(?i)feminicidio")) %>% 
  dplyr::pull(path)

# cria a função pra ler os arquivos

ler_utf16 <- function (arquivo) {
  
  
read.delim(
  arquivo,
  fileEncoding = "UTF-16LE",
  sep = "\t",
  header = TRUE,
  stringsAsFactors = FALSE
) %>%  #transforma em tibble
    tibble::as_tibble() %>% 
    # transforma todas as colunas em character pra compatibilidade
    dplyr::mutate(dplyr::across(.fns = as.character)) %>% 
    # informa a origem dos dados
    dplyr::mutate(arquivo_origem = arquivo)

}

## monta a base

base_latrocinio <- lista_latrocinio %>% 
  # usa map para replicar pra todos os arquivos da lista
  purrr::map_dfr(
    # pula se der erro
    purrr::possibly(
      .f = ~ler_utf16(.x),
      # se der erro vai retornar vazio
      otherwise = NULL)
    )

base_feminicidio <- lista_feminicidio %>% 
  # usa map para replicar pra todos os arquivos da lista
  purrr::map_dfr(
    # pula se der erro
    purrr::possibly(
      .f = ~ler_utf16(.x),
      # se der erro vai retornar vazio
      otherwise = NULL))
2 Curtidas

obrigado meu caro. Funcionou aqui. Valeu pela ajuda!

1 Curtida