INFOSIGA-SP is the São Paulo State Traffic Incident Information and Management System, maintained by DETRAN-SP. It publishes open occurrence records from 2015 onward. Coverage and definitions vary over time: 2015–2018 covers fatal crashes only, and the events table also contains notifications that have not yet been confirmed as crashes.
infosigasp downloads and imports those records. It
handles what makes the raw files awkward to read directly.
;) separate the
fields.DD/MM/YYYY.INFOSIGA-SP organises its data into three linked tables.
sinistros — occurrence records. One
row per confirmed crash or notification, with the date, time, location
(including latitude/longitude), road attributes and a breakdown of how
many vehicles and victims were involved, by type and severity.pessoas — people (victims).
One row per person involved, with demographic attributes, injury
severity and, for fatalities, the date and place of death.veiculos — vehicles. One row
per vehicle involved, with make/model, manufacturing and model years,
colour and type.All three share the id_sinistro key, so they can be
joined together; pessoas and veiculos
additionally share id_veiculo.
The main entry point is read_infosiga(). The first call
downloads the source archive (about 120 MB) into a per-user cache;
subsequent calls read from that cache, so you only pay the download cost
once. In interactive use, the package asks for confirmation before that
first download.
read_infosiga() separates tabular import, type parsing
and cleaning through the processing argument.
| mode | result |
|---|---|
"raw" |
Every field is character. Empty strings, whitespace, sentinels and malformed representations remain visible. |
"typed" |
Documented dates, times and numeric fields receive R classes; other source values remain unchanged. |
"clean" |
The default. Applies the cleaning pipeline after typed import. |
Every mode decodes Latin-1 to UTF-8, parses the CSV structure and combines the period files. Raw mode is therefore a lossless tabular representation rather than a byte-for-byte copy of the source archive.
Choose the mode according to the task: use "raw" to
audit source values, "typed" to parse documented classes
while retaining source labels and padding, and the default
"clean" mode for most analysis. All modes retain import
diagnostics in attr(x, "problems"); typed and clean modes
replace values that fail their declared parser with NA,
while raw mode preserves the field text.
raw <- read_infosiga("sinistros", processing = "raw")
typed <- read_infosiga("sinistros", processing = "typed")
clean <- read_infosiga("sinistros", processing = "clean")Typed mode parses full dates to Date, times to
hms, numeric fields to integer or double, and empty fields
to NA. Identifiers remain character to preserve leading
zeros and avoid integer overflow.
Clean mode then applies the following transformations:
ano_mes_*
columns (published as "YYYY/MM") become first-of-month
Date values.nacionalidade ships as
"BRASILEIRA "); untrimmed, those values break
grouping and joins."NAO DISPONIVEL"
(“not available”) marker becomes NA (trimming runs first,
so space-padded markers are caught).dia_da_semana: Domingo < … <
Sábado (the Brazilian week starts on Sunday);turno: MADRUGADA < MANHA
< TARDE < NOITE;gravidade_lesao (victims): LEVE <
GRAVE < FATAL;faixa_etaria_demografica /
faixa_etaria_legal: age bands in order.tp_sinistro_* columns ("S" / empty) become
logical, so you can sum() or filter them
directly. The categorical tp_sinistro_primario stays
text.qtd_* entries remain
NA, including when another vehicle or injury-severity count
is available for the same crash. Clean mode does not infer that an
unreported count is zero.tempo_sinistro_obito
(days from crash to death) becomes integer, and
numero_logradouro loses the spurious trailing
".0" the export appends ("193.0").NA. The buffer
retains plausible near-border records, while the spatial test rejects
extreme malformed values, (0, 0) placeholders and points
elsewhere inside the state’s rectangular extent. No rows are dropped;
typed and raw modes preserve the coordinates before this
validation.Before converting an ordinal, flag or integer column, clean mode validates its observed representations. If it finds an unexpected value, it preserves the entire column and warns; the class can therefore remain character after an upstream change.
These safeguards apply to closed-domain conversions, not to every
parsed column. For example, a malformed numeric coordinate can become
NA during the typed import and will be listed in
attr(x, "problems").
dia_da_semana is an ordered factor, so a weekday
tabulation comes out in calendar order rather than alphabetically.
Clean mode does not harmonize nominal categories beyond its
documented missing-value rule. Select only the harmonizations you need
with standardize.
veiculos <- read_infosiga("veiculos", standardize = "cores")
sort(table(veiculos$cor_veiculo), decreasing = TRUE)Vehicle colour is the clearest case. The source carries dozens of distinct values for about sixteen real colours, because two upstream systems coexist in every year, one upper-case and one title-cased, and the two disagree on gender agreement.
| source values | standardized |
|---|---|
PRETA, Preta |
Preta |
BRANCA, Branco |
Branca |
VERMELHA, Vermelho |
Vermelha |
Note that toupper() alone will not merge
Branca and Branco. Detailed liveries and
multi-tone values remain unchanged because grouping them would be an
analytical recode rather than label harmonization.
The remaining changes are listed below.
"municipios". Municipality names take
their official IBGE spelling, matched by cod_ibge; INFOSIGA
administrative-region names receive consistent accents and case without
changing their classification."profissoes". Occupations are
title-cased, which merges values that differ only by capitalisation.
Known nonresponse markers—including variants of
"NAO INFORMADA", "SEM INFORMACAO" and
"DESCONHECIDO"—become NA.Use standardize = c("municipios", "profissoes") to
combine options, or standardize = "all" for every option
applicable to the selected dataset. profissao keeps its
unaccented spelling and occupations stay ungrouped because no
authoritative list covers these free-text values. Standardization
requires processing = "clean".
Always join on cod_ibge, never on the name. IBGE and
INFOSIGA-SP spell nine municipalities differently. Eight contain an
apostrophe that INFOSIGA-SP renders as a space
("Santa Bárbara d'Oeste" against
"SANTA BARBARA D OESTE"), and IBGE’s
"São Luiz do Paraitinga" appears as
"SAO LUIS DO PARAITINGA". A name join loses all nine
silently. cod_ibge is also the standard Brazilian
municipality key, so it joins INFOSIGA-SP to census and population data.
Those are the denominators that turn crash counts into crash
rates.
The package ships a small sample of each dataset so you can inspect the columns without any network access.
sample_path <- system.file("extdata", "sinistros_sample.csv", package = "infosigasp")
sample <- readr::read_delim(
sample_path,
delim = ";",
show_col_types = FALSE
)
dim(sample)
#> [1] 100 48
names(sample)
#> [1] "id_sinistro" "tipo_registro"
#> [3] "data_sinistro" "ano_sinistro"
#> [5] "mes_sinistro" "dia_sinistro"
#> [7] "hora_sinistro" "ano_mes_sinistro"
#> [9] "dia_da_semana" "turno"
#> [11] "logradouro" "numero_logradouro"
#> [13] "tipo_via" "tipo_local"
#> [15] "latitude" "longitude"
#> [17] "cod_ibge" "municipio"
#> [19] "regiao_administrativa" "administracao"
#> [21] "conservacao" "circunscricao"
#> [23] "tp_sinistro_primario" "qtd_pedestre"
#> [25] "qtd_bicicleta" "qtd_motocicleta"
#> [27] "qtd_automovel" "qtd_onibus"
#> [29] "qtd_caminhao" "qtd_veic_outros"
#> [31] "qtd_veic_nao_disponivel" "qtd_gravidade_fatal"
#> [33] "qtd_gravidade_grave" "qtd_gravidade_leve"
#> [35] "qtd_gravidade_ileso" "qtd_gravidade_nao_disponivel"
#> [37] "tp_sinistro_atropelamento" "tp_sinistro_colisao_frontal"
#> [39] "tp_sinistro_colisao_traseira" "tp_sinistro_colisao_lateral"
#> [41] "tp_sinistro_colisao_transversal" "tp_sinistro_colisao_outros"
#> [43] "tp_sinistro_choque" "tp_sinistro_capotamento"
#> [45] "tp_sinistro_engavetamento" "tp_sinistro_tombamento"
#> [47] "tp_sinistro_outros" "tp_sinistro_nao_disponivel"INFOSIGA-SP publishes one continuous series from 2015 onward, but
what the series contains has changed over time. These are
properties of the source data, not import artefacts, so
infosigasp reports them rather than correcting them.
Several will quietly invalidate an analysis that looks perfectly
reasonable. ?read_infosiga carries the full list; the two
below catch people out most often.
Non-fatal records begin in 2019. Before that, every row is a fatal crash. Counting crashes per year over the whole series therefore produces a roughly 20-fold jump in 2019 that reflects only the expansion of data collection.
| year | fatal crashes | non-fatal crashes |
|---|---|---|
| 2015 | 5,942 | 0 |
| 2018 | 4,869 | 0 |
| 2019 | 4,804 | 116,412 |
| 2023 | 5,166 | 135,329 |
Those counts come from a 2026 release and shift as DETRAN-SP revises
the data. The break in 2019 does not move. The same break appears in
pessoas, where the LEVE and GRAVE
injury levels simply do not occur before 2019.
So for any trend that reaches back before 2019, restrict to fatalities.
library(dplyr)
read_infosiga("sinistros") |>
filter(tipo_registro == "SINISTRO FATAL") |>
count(ano_sinistro)Otherwise, start the series in 2019 by filtering
ano_sinistro >= 2019 after importing the data.
sinistros rows are notificationstipo_registro distinguishes confirmed crashes from
"NOTIFICACAO", a reported event not yet confirmed as a
crash. Notifications are about a third of all rows, so treating every
row as a crash overstates the total considerably.
DETRAN-SP reclassifies records as it validates them, so the newest months carry an unusually high share of notifications. The last month or two of any release is also incomplete. Drop the tail of the series before reading anything into a recent trend.
tempo_sinistro_obito is capped at 30
days, the standard convention for attributing a death to a
crash. Fatality counts here are 30-day counts.qtd_* vehicle columns disagree with the
veiculos row count for a small share of crashes.
Pick one definition and say which. (The qtd_gravidade_*
columns do match pessoas exactly.)pessoas
row. Use a left join to keep them.The imported data are ordinary tibbles, so any tidyverse (or base R) workflow applies. Here is a count of traffic fatalities per year from the victims dataset.
library(dplyr)
deaths_by_year <- read_infosiga("pessoas") |>
filter(gravidade_lesao == "FATAL") |>
count(ano_obito, name = "deaths") |>
arrange(ano_obito)
deaths_by_yearThat series is safe to read across all years because it counts only fatalities, the one thing collected consistently since 2015.
Fatalities also break down by the type of victim (driver, passenger, pedestrian).
read_infosiga("pessoas") |>
filter(gravidade_lesao == "FATAL") |>
count(tipo_de_vitima, sort = TRUE)sinistros carries latitude and longitude as numeric
columns, so you can map crash locations directly or aggregate them by
municipality (municipio / cod_ibge).
The package stores the source archive and canonical clean results in the operating-system user cache. A clean result is reused only when its source checksum and cleaning-schema version still match. Standardizations are applied after loading that result and do not create additional artifacts.
DETRAN-SP updates the archive monthly. Use
refresh = TRUE to replace your local copy with the latest
available version and return the requested dataset.
read_infosiga() always imports every available year.
Filter the returned tibble when you need a shorter period.
You can point the cache somewhere else for a session (or permanently
via your .Rprofile) with the
infosigasp.cache_dir option.
Inspect cache contents with infosiga_cache_info().
Remove processed results while retaining the source archive with
clear_infosiga_cache(), or pass source = TRUE
to remove both. For a read that should neither use nor create a
processed artifact, set cache = FALSE.
dictionary_infosiga() opens the package’s searchable
online data dictionary. Pass "sinistros",
"pessoas" or "veiculos" to open the
corresponding section, or use source = "official" to visit
the INFOSIGA-SP source website.
DETRAN-SP publishes the data under a Creative Commons Attribution 4.0 licence. When you publish results based on these data, please cite INFOSIGA-SP / DETRAN-SP as the source, https://infosiga.detran.sp.gov.br/.