← 網誌 · Mapear um milhão de acidentes de trânsito: seis erros que só aparecem depois de cometidos

Mapear um milhão de acidentes de trânsito: seis erros que só aparecem depois de cometidos

A terceira ferramenta deste domínio é um mapa de calor de acidentes de trânsito. Os dados são públicos e parece que basta baixar e usar. Este é o registro dos seis erros cometidos no caminho.

2026-08-20 作者 William Hsu

這篇講什麼
  1. Como são os dados
  2. 1. Uma linha é um envolvido, não um acidente
  3. 2. O maior ponto crítico de Taiwan fica em frente à prefeitura de Nova Taipé
  4. 3. Estes dados não servem para ranquear “o cruzamento mais perigoso”
  5. 4. Rebuscar a tela inteira a cada arraste
  6. 5. O banco de dados num bind mount ficou 74 vezes mais lento
  7. 6. Errei as cores duas vezes: uma tudo vermelho, outra tudo azul
  8. Ao ampliar, os pontos formavam uma grade regular
  9. Olhando para trás

Como são os dados

A Agência Nacional de Polícia de Taiwan publica no portal de dados abertos os acidentes com vítimas, caso a caso: o tipo A1 são mortes em até 24 horas e o A2 são feridos ou mortes após 24 horas. Usei os anos completos de 2024 e 2025 mais os dados móveis de 2026 até agosto.

O download é um zip; três anos descompactados dão 1,5 GB. Meu disco não aguentava, então toda a esteira lê direto do zip, sem gravar nada.

O mapa de calor pronto
O resultado: 1,01 milhão de acidentes, filtráveis por horário, tipo de veículo e só mortes

1. Uma linha é um envolvido, não um acidente

Um acidente tem tantas linhas quantos forem os envolvidos. Um carro que bate numa moto são duas linhas com a mesma hora, o mesmo local e as mesmas coordenadas; muda só o número do envolvido.

Removendo duplicatas, 2,28 milhões de linhas viram 1,01 milhão de acidentes, uma média de 2,26 envolvidos por caso. Contar linhas direto infla todos os números em mais do dobro.

2. O maior ponto crítico de Taiwan fica em frente à prefeitura de Nova Taipé

Na primeira vez que desenhei os dados, o ponto mais brilhante ficava em Banqiao, Nova Taipé, em 121.481, 25.009: mais de dois mil acidentes por ano empilhados num único lugar.

São as coordenadas do governo de Nova Taipé. Quando a geocodificação falha, o sistema recorre a um valor padrão, e esse padrão é a sede do governo daquele município. Os endereços dos acidentes nesse ponto espalham-se por 20 distritos: Sanxia, Bali, Pinglin e outros.

Detectar é simples: se os endereços de uma mesma coordenada cobrem três ou mais distritos, o ponto é falso. Um cruzamento de verdade não fica em Sanxia e em Bali ao mesmo tempo. No país inteiro apareceram 128 pontos assim e 17.784 acidentes, 1,76% do total.

A proporção não é grande, mas como tudo cai no mesmo lugar vira a maior mancha do mapa. Sem corrigir, a informação mais visível do mapa está errada.

3. Estes dados não servem para ranquear “o cruzamento mais perigoso”

Este não é problema de código: é a natureza do dado.

Taichung é a cidade com mais acidentes do país, 70.765 por ano. Mas entre os 200 maiores pontos críticos nacionais, Nova Taipé fica com 121 e Taichung com apenas 19.

O motivo é que cada município geocodifica de um jeito. A taxa de reaproveitamento de uma mesma coordenada é 1,38 em Nova Taipé e 1,01 na cidade de Taipé. Lá quase todo acidente tem coordenada própria, então um “ponto crítico” nunca se forma.

Qualquer ranking de cruzamentos perigosos feito com estes dados está ranqueando o comportamento de geocodificação de cada município, não o perigo. Por isso a ferramenta não tem placar, só estatística por área: num raio de 300 a 500 metros, um erro de coordenada de algumas dezenas de metros se dilui.

Além disso, 26,2% dos endereços dizem “a 0,0 metro em frente à rua X”, que é o ponto de referência de um trecho, não o local do acidente. Dá para ler no nível da rua; no nível do cruzamento, não.

4. Rebuscar a tela inteira a cada arraste

A primeira API recebia um bbox: o front-end mandava os limites do mapa e o back-end devolvia aquela área. Funcionava, mas arrastar um pixel gera outro bbox, outra URL e uma recarga completa que nem o navegador nem a CDN conseguem cachear. Uma resposta medida deu 954 KB.

Dividindo o mapa em tiles fixos, a URL virou /api/cells/{z}/{x}/{y}. URL fixa é cacheável, e ao arrastar só se buscam os blocos recém-revelados:

5. O banco de dados num bind mount ficou 74 vezes mais lento

No ambiente de desenvolvimento estava tudo bem; na produção a mesma consulta levava 5,5 segundos.

Na produção a pasta é montada (bind mount) do host Windows dentro do contêiner Docker. O SQLite faz muitas leituras pequenas e aleatórias, e esse padrão é péssimo sobre um bind mount. A mesma consulta, de três formas:

Desempenho do bind mount
A mesma consulta, 74 vezes pior — o problema não é o código, é onde o arquivo mora

A solução é copiar o banco sequencialmente para o sistema de arquivos do próprio contêiner na inicialização e usar essa cópia. Leitura sequencial é rápida: 122 MB levam alguns segundos. Esse problema é invisível na máquina de desenvolvimento e só aparece depois do deploy.

6. Errei as cores duas vezes: uma tudo vermelho, outra tudo azul

Os pesos do mapa de calor são relativos, então como o número de acidentes vira um peso de 0 a 1 decide a leitura do mapa inteiro.

A primeira tentativa ficou toda vermelha: ao migrar a API de bbox para blocos, perdi o campo do peso. O front não via nada, tratava como não definido e dava peso máximo a cada célula, tivesse ela 1 acidente ou 300.

A segunda ficou toda azul: usei o percentil 97 como escala cheia. Só que esta distribuição é extremamente enviesada — na visão nacional a célula mediana tem 38 acidentes e a maior tem 15.601, um fator de 400. Com o percentil 97 no denominador, 97% das células ficam perto de zero.

A versão final tira o logaritmo em relação ao máximo. A célula mediana fica em 0,38, uma de quinhentos em 0,64 e a maior em 1,0 — e a faixa intermediária finalmente se abre.

Ao ampliar, os pontos formavam uma grade regular

Um usuário avisou que, no nível da rua, os pontos pareciam suspeitosamente regulares e não batiam com as vias.

Porque eu desenhava o centro de cada célula. Desenhe o centro de uma célula de 13 metros e, no nível da rua, você vê a grade — e as ruas, claro, não passam pelo meio de todas as células.

A correção foi reconstruir o banco guardando também a soma das coordenadas dos acidentes de cada célula, para a consulta devolver o centro de massa real daquela célula. Agora os pontos caem sobre as ruas e seguem a malha viária.

Olhando para trás

Dos seis, só o quarto e o quinto eram problemas técnicos; o resto veio de supor que o dado estava limpo. Os dados abertos do governo são até bons — campos detalhados, atualização frequente — mas foram desenhados para uso administrativo, e esse uso não é desenhar mapas. As coordenadas foram acrescentadas depois, por um processo com lógica própria, e essa lógica é inofensiva na estatística e fatal num mapa.

Da próxima vez que eu receber um conjunto de dados abertos, vou olhar de onde vieram os valores mais extremos antes de desenhar qualquer coisa.

這篇文章寫的是本站實際的實作與量測。工具本身在老照片動起來與變老變年輕,都可以直接試。

← 上一篇把一支影片的生成時間從 80 秒壓到 43 秒:每一個試過的做法與實測數字

看其他文章