2  Preparação de dados

Antes de avançar para a análise, os dados recolhidos passam por um conjunto de etapas de preparação e validação, que garantem a consistência e qualidade da informação utilizada.

Os procedimentos descritos neste capítulo cobrem a parte inicial do código disponível em scripts/02_prioritise.

2.1 Filtragem temporal do GTFS

O feed GTFS completo abrange tipicamente vários meses ou anos de operação. Para a análise, foi selecionado um dia de referência que representa as condições típicas de operação (neste caso, uma quarta-feira útil de um período sem feriados ou condições especiais). A filtragem é feita com recurso à biblioteca tidytransit (Poletti et al. 2026):

gtfs <- tidytransit::filter_feed_by_date(gtfs, extract_date = region$gtfs_day)

Esta operação retém apenas as linhas, paragens e percursos com viagens no dia selecionado, reduzindo significativamente a dimensão dos dados e tornando a análise mais focada.

2.2 Manipulação customizada do GTFS

Quando os dados de origem requerem ajustes específicos (por exemplo, correção de identificadores, remoção de serviços especiais, ou unificação de feeds de múltiplos operadores), é aplicada uma função de manipulação customizada, definida no ficheiro de parâmetros como gtfs_manipulate. O feed resultante, já manipulado e filtrado, é guardado separadamente para referência.

No caso da Carris Metropolitana, foi aplicada uma função para filtrar o feed por área de operação GTFShift::filter_by_agency() e remover os identificadores associados aos planos de operação, para permitir a associação com os dados do OSM (que não têm este identificador).

manipulate_carris_met <- function(gtfs) {
  # Remove all text from [ to ] from gtfs$shape_ids, which are present in Carris Metropolitana *feed* and cause issues in matching with OSM shapes
  gtfs$shapes$shape_id <- stringr::str_replace_all(gtfs$shapes$shape_id, "\\[.*\\]", "")
  gtfs$trips$shape_id <- stringr::str_replace_all(gtfs$trips$shape_id, "\\[.*\\]", "")
  gtfs$trips$trip_id <- stringr::str_replace_all(gtfs$trips$trip_id, "\\[.*\\]", "")
  gtfs$stop_times$trip_id <- stringr::str_replace_all(gtfs$stop_times$trip_id, "\\[.*\\]", "")
  return(gtfs)
}

manipulate_carris_met_area_1 <- function(gtfs) {
  gtfs <- manipulate_carris_met(gtfs)
  gtfs <- GTFShift::filter_by_agency(gtfs, id = 41)
  return(gtfs)
}

manipulate_carris_met_area_2 <- function(gtfs) {
  gtfs <- manipulate_carris_met(gtfs)
  gtfs <- GTFShift::filter_by_agency(gtfs, id = 42)
  return(gtfs)
}

manipulate_carris_met_area_3 <- function(gtfs) {
  gtfs <- manipulate_carris_met(gtfs)
  gtfs <- GTFShift::filter_by_agency(gtfs, id = 43)
  return(gtfs)
}

manipulate_carris_met_area_4 <- function(gtfs) {
  gtfs <- manipulate_carris_met(gtfs)
  gtfs <- GTFShift::filter_by_agency(gtfs, id = 44)
  return(gtfs)
}

2.3 Associação GTFS–OSM

A associação entre as geometrias do GTFS e a rede viária do OSM é o núcleo metodológico do processo de preparação. Apesar de existirem atributos nas relações OSM (gtfs:shape_id e gtfs:route_id) que permitem esta correspondência direta, estes não estavam definidos na rede da Carris Metropolitana. Para ultrapassar esta lacuna, foi aplicado o algoritmo de correspondência geométrica GTFShift::osm_shapes_match_routes(), utilizando o código disponível em scripts/01_osm_match.

Foi possível obter uma correspondência para 98,96% das geometrias GTFS (shapes), que correspondem a 96,76% das viagens realizadas em hora de ponta. Os resultados desta correspondência estão disponíveis em U-Shift/busclar. Posteriormente, estes resultados foram utilizados para atualizar o OSM com os atributos em falta, recorrendo ao código documentado em GTFShift: Update OSM data.

Uma vez estabelecida a ligação entre as geometrias GTFS e a rede viária OSM e atualizada a última fonte com os identificadores correspondentes, foi aplicado o método GTFShift::prioritise_lanes(), que permite calcular, para cada segmento de via e hora do dia, os seguintes indicadores:

  1. Atributos da infraestrutura, extraídos de cada segmento do OSM (segmento da via), como número de vias, existência de coredor bus, ou existência de vias para estacionamento;
  2. Frequência de serviço, calculada por hora e por segmento de via, agregando todas as linhas e percursos que o percorrem.

O resultado é um conjunto de dados com a combinação entre segmentos de via e as horas do dia, contendo os atributos de infraestrutura e os indicadores de serviço correspondentes.

2.4 Filtragem e validação dos dados GTFS-RT

Os dados de GTFS-RT são submetidos a um conjunto de filtros de qualidade antes de serem utilizados no cálculo de velocidades. A validação é feita utilizando o método rt_collection_speed_from_shape_distance_progression(), em três fases sequenciais:

1.ª validação — por atualização individual:

Parâmetro Descrição Valor
THRESHOLD_TIME_BETWEEN_UPDATES_MAX Intervalo máximo aceitável entre duas atualizações consecutivas da mesma viagem 90 s
THRESHOLD_DISTANCE_TO_GEOMETRY_MAX Distância máxima entre a posição GPS reportada e a geometria do percurso (descarta posições com erro elevado) 50 m
THRESHOLD_SPEED_MAX Velocidade máxima aceitável (descarta valores físicamente impossíveis) 140 km/h

2.ª validação — por viagem:

Parâmetro Descrição Valor
THRESHOLD_UPDATES_PER_TRIP_MIN_MARGIN Rácio mínimo entre atualizações recebidas e atualizações esperadas (duração da viagem ÷ intervalo máximo). Garante que a viagem tem cobertura temporal suficiente para estimar velocidade 0,7 (70%)

3.ª validação — posição ao longo do percurso:

Parâmetro Descrição Valor
THRESHOLD_EDGE_DISTANCE_DISCARD Margem de exclusão nas extremidades do percurso: são descartadas as atualizações nos primeiros e últimos metros do trajeto, onde o veículo está tipicamente em arranque ou em paragem terminal 100 m

Após aplicação de todos os filtros, as atualizações GTFS-RT válidas são projetadas na rede viária OSM e associadas aos segmentos de via correspondentes (GTFShift::project_points_along_geometry()), para posterior cálculo das métricas de velocidade.

Esta é calculada ao nível do segmento, considerando a relação entre a progressão em tempo e distância ao longo da geometria do percurso para cada atualização GTFS-RT (GTFShift::rt_average_speed()), mas também ao nível das viagens, relacionando o tempo e a distância totais do percurso (velocidade comercial, GTFShift::get_trip_speed_profile()). Os dois primeiros métodos enumerados anteriormente são encapsulados pelo método GTFShift::rt_extend_prioritisation().

2.5 Associação de dados de procura

Os dados de procura são associados à rede viária através de uma junção entre as linhas GTFS e os segmentos de via. Para cada segmento (way_osm_id) e hora, é calculada a procura total como a soma da procura de todas as linhas que o percorrem:

priotitization_demand <- prioritisation |>
  st_drop_geometry() |>
  select(way_osm_id, hour, routes) |>
  tidyr::unnest(routes) |>
  left_join(route_demand |> select(route_id, demand),
            by = c("routes" = "route_id")) |>
  group_by(way_osm_id, hour) |>
  summarise(demand = sum(demand, na.rm = TRUE), .groups = "drop")

Como a procura é um valor diário (não horário) e para a totalidade da linha (em ambos os sentidos), este valor sobrestima o número de passageiros que efetivamente atravessa cada segmento, uma vez que nem todos os passageiros frequentam a totalidade da linha, podendo embarcar ou desembarcar nas suas paragens intermédias, o que não é capturado pelos dados disponíveis.