xyt_gps - inventaire initial des fonctions et parametres¶
Archive de conception
Cette page est une note de travail initiale. Elle peut contenir des noms prévus ou déplacés. Pour l'API actuelle à utiliser, voir API Python et les guides de démarrage.
Date : 2026-06-09
Positionnement recommande¶
Le packaging est possible et pertinent, a condition de partir d'un perimetre resserre :
xyt_gpsdoit d'abord automatiser le pipeline Declic actuel, fonde sur des exports GPS structurés deja structures.- Le vieux package
xytpeut fournir des idees, des fonctions utilitaires et des tests synthetiques, mais ne doit pas etre repris tel quel. - La detection complete depuis des points GPS bruts non segmentes doit rester hors MVP, car le pipeline actuel part surtout de
Storyline,Trips,JourneysetUserStatistics.
Éléments récupérables depuis archive/legacy-code/xyt-main-archive¶
| Module archive | Elements utiles | Statut pour xyt_gps |
|---|---|---|
fake_data_generator.py |
generation de legs, staypoints, waypoints synthetiques | utile pour tests, a simplifier et rendre deterministe |
gps_data_processor.py |
lissage, distance haversine, segmentation, detection de modes | hors MVP Declic ; garder comme reference si on traite un jour des points bruts |
gps_data_privacy.py |
obfuscation, agregation spatio-temporelle, utility metric | module optionnel futur privacy |
gps_analytics.py |
verify_columns, split overnight, clustering de lieux, metriques journalières |
certaines idees utiles, mais a refactoriser fortement |
gps_to_graph.py |
graphes de motifs de mobilite | module analytique futur, pas dans WP1/WP2 MVP |
gps_to_actionspace.py |
espaces d'action, ellipses, covariance | module analytique futur, pas dans MVP |
xyt_plot.py |
carte Folium | à fusionner plus tard avec archive/legacy-code/xyt_dynamite/xyt_to_map.py si nécessaire |
Objets de configuration¶
ProjectConfig¶
Parametres :
| Parametre | Type | Defaut propose | Role |
|---|---|---|---|
experiment_name |
str |
aucun | nom analytique de l'etude |
provider |
str |
"motiontag" |
fournisseur des exports |
provider_project_name |
str |
aucun | nom dans les fichiers MotionTag |
period_start |
date |
aucun | debut de periode d'import |
period_end |
date |
aucun | fin de periode d'import |
timezone |
str |
"Europe/Zurich" |
fuseau local |
raw_dir |
Path |
aucun | dossier des exports bruts |
work_dir |
Path |
"work" |
sorties intermediaires |
export_dir |
Path |
"exports" |
livrables |
target_crs |
str |
"EPSG:4326" |
CRS final |
metric_crs |
str |
"EPSG:2056" |
CRS pour distances metriques |
phase_dates |
dict[str, tuple[date, date]] |
{} |
phases avant, pendant, apres |
tracking_thresholds |
TrackingThresholds |
seuils package | jours minimum par phase et suivi total minimal |
spatial_quality_thresholds |
SpatialQualityThresholds |
seuils package | points aberrants, perte de signal, outliers par quantile |
matching_thresholds |
MatchingThresholds |
seuils package | tolerance de matching temporel et parametres map-matching |
paths |
GpsExportPaths | None |
None |
chemins explicites si detection automatique impossible |
external_geodata |
ExternalGeodataConfig | None |
None |
cantons, pays, zones excursions |
sociodemo_path |
Path | None |
None |
donnees sociodemographiques |
mappings |
MobilityMappings via mode_purpose_mapping() |
mappings package | modes et motifs par source/table/niveau |
save_intermediate |
bool |
False |
ecrire les etapes internes |
overwrite |
bool |
False |
ecraser les sorties existantes |
TrackingThresholds¶
Parametres :
| Parametre | Type | Defaut propose | Role |
|---|---|---|---|
min_days_by_phase |
Mapping[str, int] |
{} |
seuils par phase, a definir selon le protocole |
min_total_tracked_days |
int |
7 |
seuil minimal livre dans le contexte Declic prefiguration |
round_to_full_weeks |
bool |
True |
arrondir aux semaines completes |
SpatialQualityThresholds¶
Parametres :
| Parametre | Type | Defaut propose | Role |
|---|---|---|---|
max_consecutive_point_distance_m |
float | None |
None |
seuil de saut GPS aberrant, a completer par projet |
max_relative_signal_loss |
float | None |
None |
seuil de perte de signal relative, a completer par projet |
outlier_quantiles_by_mode |
tuple[float, ...] |
(0.98, 0.99) |
quantiles Q98 et Q99 par mode |
MatchingThresholds¶
Parametres :
| Parametre | Type | Defaut propose | Role |
|---|---|---|---|
leg_trip_journey_tolerance |
str |
"5s" |
tolerance temporelle pour les jointures legs/trips/journeys |
osrm_max_points_per_chunk |
int |
99 |
taille maximale des chunks OSRM |
google_directions_fallback |
bool |
False |
fallback Google Directions desactive par defaut |
RawSampleConfig¶
Parametres :
| Parametre | Type | Defaut propose | Role |
|---|---|---|---|
mode |
"users" ou "rows" |
aucun | strategie d'echantillonnage |
n |
int |
aucun | nombre d'utilisateurs ou de lignes par table |
random_state |
int | None |
42 |
reproductibilite du tirage |
chunksize |
int |
100_000 |
taille de lecture CSV pour by_users sur gros exports |
user_id_column |
str |
"user_id" |
colonne identifiant personne, ou IDNO selon source |
user_statistics_id_column |
str |
"id" |
colonne identifiant dans UserStatistics |
storyline_type_column |
str |
"type" |
colonne permettant d'identifier les Track |
track_type_value |
str |
"Track" |
valeur de type correspondant aux legs |
Constructeurs pratiques :
xyt.RawSampleConfig.by_users(5, random_state=42, chunksize=100_000)
xyt.RawSampleConfig.random_rows(1000, random_state=42)
by_users lit d'abord les identifiants depuis storyline, puis filtre les CSV par chunks. random_rows reste un echantillonnage en memoire, utile pour inspecter rapidement le format mais moins coherent relationnellement.
mode_purpose_mapping() / MobilityMappings¶
mode_purpose_mapping() est le constructeur recommandé dans les notebooks.
Il retourne une dataclass MobilityMappings.
Parametres :
| Parametre | Role |
|---|---|
storyline_purpose_niv1 |
mapping des motifs des lignes Stay dans storyline |
storyline_mode_niv1 |
agregation niveau 1 des modes MotionTag Mode::* |
storyline_mode_niv2 |
agregation niveau 2 des modes MotionTag Mode::* |
storyline_mode_mrmt |
nomenclature compatible MRMT pour les modes MotionTag |
trip_purpose_mrmt |
mapping des motifs Trips / Journeys |
trip_mode_niv1 |
agregation niveau 1 des modes Trips / Journeys |
trip_mode_niv2 |
agregation niveau 2 des modes Trips / Journeys |
trip_mode_mrmt |
nomenclature compatible MRMT pour Trips / Journeys |
default_mode |
categorie de repli pour un mode inconnu |
default_purpose |
categorie de repli pour un motif inconnu |
Fonctions publiques MVP¶
Convention de nommage¶
Les noms publics doivent décrire l'objet produit ou l'action métier, pas l'implémentation interne.
Exemples :
| Préférer | Éviter | Raison |
|---|---|---|
build_user_selection_table() |
build_user_filter_matrix() |
l'utilisateur lit une table de sélection avant de filtrer ; "matrix" décrit mal l'usage |
filter_mobility_dataset_by_users() |
filter_all_tables() |
le périmètre et la clé de filtrage sont explicites |
add_signal_quality_flags() |
signal_quality() |
la fonction ajoute des colonnes de décision, pas seulement un calcul |
Un ancien nom peut rester temporairement comme alias si un exemple ou un notebook l'a déjà utilisé, mais la documentation doit privilégier le nom le plus lisible.
Import¶
infer_gps_export_paths(config: ProjectConfig) -> GpsExportPaths
load_gps_export(config: ProjectConfig, *, sample: RawSampleConfig | None = None, validate: bool = True, must_exist: bool = True) -> RawGpsData
load_sample_gps(path: Path | None = None, *, user_id: str = "sample_user", max_rows: int | None = None) -> RawGpsData
load_gps_source(config: ProjectConfig, *, sample: RawSampleConfig | None = None, namespace_ids: bool = True) -> RawGpsData
load_gps_sources(configs: list[ProjectConfig], *, sample: RawSampleConfig | None = None, namespace_ids: bool = True) -> RawGpsData
concat_raw_gps_data(raws: list[RawGpsData]) -> RawGpsData
load_sociodemo(path: Path, *, user_id_col: str = "user_id") -> pd.DataFrame
load_external_geodata(config: ProjectConfig) -> ExternalGeodata
Parametres importants :
| Fonction | Parametres |
|---|---|
load_gps_export |
config.csv_sep, sample, validate, must_exist |
load_sample_gps |
path, user_id, max_rows, validate |
load_gps_sources |
configs, namespace_ids, validate, must_exist, sample |
infer_gps_export_paths |
provider_project_name, period_start, period_end, raw_dir, noms alternatifs StorylineWithTripId / StorylineWithUserAnnotations |
Colonnes ajoutees lors d'un import multi-source :
| Colonne | Role |
|---|---|
xyt_source_id |
identifiant stable de la source, construit a partir de experiment_name et period |
experiment_name |
nom analytique de l'experimentation |
motiontag_project_name |
nom du projet cote fournisseur GPS |
period |
periode d'export |
raw_id, raw_user_id, raw_trip_id |
identifiants originaux conserves avant namespacing |
Validation¶
validate_columns(df: pd.DataFrame, required: list[str], *, dataset_name: str) -> None
validate_crs(gdf: gpd.GeoDataFrame, expected_crs: str, *, dataset_name: str) -> None
drop_nans_if_low_rate(df: pd.DataFrame, columns: list[str], *, threshold: float = 0.01) -> pd.DataFrame
validate_dataset(dataset: MobilityDataset, schema: MobilitySchema) -> ValidationReport
Parsing et harmonisation¶
parse_ewkb(value: str)
parse_date_columns(df: pd.DataFrame, columns: list[str], *, utc: bool = True) -> pd.DataFrame
assign_phase(value, phases: Iterable[Phase], *, default: str = "Other") -> str
mode_purpose_mapping(**kwargs) -> MobilityMappings
apply_storyline_mappings(storyline: pd.DataFrame, mappings: MobilityMappings) -> pd.DataFrame
apply_trip_journey_mappings(trips: pd.DataFrame, journeys: pd.DataFrame, mappings: MobilityMappings) -> tuple[pd.DataFrame, pd.DataFrame]
Préparation des données¶
prepare_storyline(storyline: pd.DataFrame, config: ProjectConfig) -> gpd.GeoDataFrame
prepare_trips(trips: pd.DataFrame, config: ProjectConfig) -> pd.DataFrame
prepare_journeys(journeys: pd.DataFrame, config: ProjectConfig) -> pd.DataFrame
prepare_mobility_dataset(raw: RawGpsData, config: ProjectConfig, **options) -> MobilityDataset
prepare_mobility_datasets(configs: list[ProjectConfig], *, sample: RawSampleConfig | None = None, namespace_ids: bool = True) -> MobilityDataset
concat_mobility_datasets(datasets: list[MobilityDataset]) -> MobilityDataset
split_storyline(storyline: gpd.GeoDataFrame) -> tuple[gpd.GeoDataFrame, gpd.GeoDataFrame]
clean_leg_geometries(legs: gpd.GeoDataFrame, *, drop_discontinuous: bool = True) -> gpd.GeoDataFrame
add_user_id_day(legs: pd.DataFrame) -> pd.DataFrame
build_track_trip_journey_map(legs, trips, journeys, *, tolerance: str = "5s") -> pd.DataFrame
build_legs_staypoints_map(legs, staypoints, *, tolerance: str = "5s") -> pd.DataFrame
build_user_stats(storyline: pd.DataFrame, config: ProjectConfig, *, user_statistics=None, sociodemo=None, weights=None, weight_col: str = "weight", default_weight: float = 1.0) -> pd.DataFrame
add_excursion_stats_to_user_stats(user_stats: pd.DataFrame, legs: pd.DataFrame, *, excursion_col: str = "excursion") -> pd.DataFrame
Qualite GPS et nettoyage spatial¶
calculate_user_tracking_stats(storyline: pd.DataFrame) -> pd.DataFrame
resample_missing_stays(storyline: gpd.GeoDataFrame, config: ProjectConfig) -> tuple[gpd.GeoDataFrame, pd.DataFrame]
calculate_tracking_periods(user_stats: pd.DataFrame, config: ProjectConfig) -> pd.DataFrame
flag_tracking_quality(user_stats: pd.DataFrame, config: ProjectConfig) -> pd.DataFrame
build_tracking_quality_report(user_stats: pd.DataFrame) -> pd.DataFrame
select_valid_tracking_users(user_stats: pd.DataFrame) -> pd.Index
build_user_selection_table(user_stats: pd.DataFrame, *, require_tracking_quality: bool = False, exclude_bad_signal_users: bool = True, max_low_quality_legs_share: float | None = None) -> pd.DataFrame
select_analysis_users(selection_table: pd.DataFrame, *, quality_column: str = "analysis_user_ok") -> pd.Index
filter_table_by_users(df: pd.DataFrame, user_ids, *, user_id_column: str = "user_id") -> pd.DataFrame
filter_mobility_dataset_by_users(dataset: MobilityDataset, user_ids) -> MobilityDataset
clean_leg_geometries(legs: gpd.GeoDataFrame, *, drop_discontinuous: bool = True) -> gpd.GeoDataFrame
add_signal_loss_metrics(legs: gpd.GeoDataFrame, config: ProjectConfig) -> gpd.GeoDataFrame
flag_low_quality_legs_by_mode(legs: gpd.GeoDataFrame, config: ProjectConfig, *, mode_col: str | None = None) -> gpd.GeoDataFrame
add_signal_quality_flags(legs: gpd.GeoDataFrame, config: ProjectConfig, *, mode_col: str | None = None) -> gpd.GeoDataFrame
add_signal_quality_to_user_stats(user_stats: pd.DataFrame, legs: pd.DataFrame, *, signal_quality_computed: bool | None = None) -> pd.DataFrame
identify_bad_signal_users(legs: gpd.GeoDataFrame, *, quantile_threshold: float = 0.995) -> pd.Index
add_spatial_zone_labels(table: pd.DataFrame, zones, *, zone_label_col: str, output_col: str) -> gpd.GeoDataFrame
add_leg_origin_destination_zones(legs: pd.DataFrame, zones, *, zone_label_col: str) -> gpd.GeoDataFrame
classify_leg_relation_to_area(legs: pd.DataFrame, *, area=None, area_path=None, center=None, radius_m=None) -> gpd.GeoDataFrame
add_trip_origin_destination_from_legs(trips, legs, map_track_trip_journey) -> pd.DataFrame
add_journey_origin_destination_from_trips(journeys, trips, map_track_trip_journey) -> pd.DataFrame
Filtres¶
filter_users_by_tracking(user_stats, *, min_days: dict[str, int]) -> pd.DataFrame
filter_legs(legs, user_stats, *, filters: FilterConfig) -> gpd.GeoDataFrame
build_filter_report(before, after, *, rules: FilterConfig) -> FilterReport
Parametres de FilterConfig :
| Parametre | Role |
|---|---|
min_unique_days |
exclure suivis trop courts |
min_coverage_ratio |
exclure couverture temporelle faible |
min_segments_per_day |
exclure activite GPS insuffisante |
exclude_bad_signal_users |
retirer utilisateurs a mauvais signal |
exclude_low_quality_legs |
retirer legs signales |
exclude_airplane |
retirer avion |
outlier_rule |
None, quantile_98, quantile_99 |
territory |
None, "GE", "VD", "panel" |
include_visitors |
inclure visiteurs non residents |
Enrichissements¶
add_co2_occupancy_metrics(legs, *, journeys=None, map_track_trip_journey=None, config=None, mode_col="mode", distance_col=None, journey_purpose_col="main_purpose_mrmt", prefer_observed_occupancy=None, occupancy_col=None) -> pd.DataFrame
add_health_metrics(legs, *, health_config: HealthConfig) -> pd.DataFrame
map_match_osrm(legs, *, osrm_config: OSRMConfig) -> gpd.GeoDataFrame
map_match_google(legs, *, google_config: GoogleDirectionsConfig) -> gpd.GeoDataFrame
Parametres :
| Config | Parametres |
|---|---|
CO2OccupancyConfig |
factors_g_per_km, occupancy_by_distance_and_purpose, default_occupancy, car_modes, apply_occupancy_to_car_modes, prefer_observed_occupancy, occupancy_col |
HealthConfig |
weight_kg, walk_speed_thresholds, bike_speed_thresholds, mets_by_mode_intensity |
OSRMConfig |
base_url_by_mode, profile_by_mode, max_points, request_timeout, retry_count, enabled |
GoogleDirectionsConfig |
api_key, mode_by_motiontag_mode, request_timeout, retry_count, cost_guard_max_requests, enabled |
Indicateurs de mobilité¶
build_person_day_indicators(dataset: MobilityDataset, *, mode_col: str = "mode_niv1", trips_mode_col: str | None = None, distance_col: str | None = None, include_zero_days: bool = True, include_excursions: bool = True, include_airplane: bool = False, config: ProjectConfig | None = None) -> pd.DataFrame
build_person_phase_indicators(person_day: pd.DataFrame, *, user_stats: pd.DataFrame | None = None, weight_col: str = "weight") -> pd.DataFrame
build_population_indicators(person_phase: pd.DataFrame, *, use_weights: bool = True, weight_col: str = "weight") -> pd.DataFrame
compute_mobility_indicators(dataset: MobilityDataset, *, mode_col: str = "mode_niv1", trips_mode_col: str | None = None, distance_col: str | None = None, include_zero_days: bool = True, include_excursions: bool = True, include_airplane: bool = False, use_weights: bool = True, weight_col: str = "weight", config: ProjectConfig | None = None) -> IndicatorResult
population_indicator_summary(indicators: IndicatorResult | pd.DataFrame) -> pd.DataFrame
Indicateurs initiaux :
| Indicateur | Unite | Source | Methode |
|---|---|---|---|
distance_km |
km | legs | somme journaliere par mode, moyenne phase |
travel_time_min |
min | legs | somme journaliere par mode, moyenne phase |
trip_count |
nombre | trips | somme journaliere par mode principal, moyenne phase |
leg_count |
nombre | legs | nombre d'étapes journalier par mode, moyenne phase |
co2 |
kg | futur module CO2 | somme journaliere par mode, moyenne phase |
co2_direct |
kg | futur module CO2 | somme journaliere par mode, moyenne phase |
calories |
kcal | futur module santé | somme journaliere par mode, moyenne phase |
mets |
METs | futur module santé | moyenne journaliere par mode, moyenne phase |
Tables produites par compute_mobility_indicators() :
| Table | Grain | Role |
|---|---|---|
person_day |
utilisateur, date, phase, mode | table de contrôle et de comparaison avec les notebooks |
person_phase |
utilisateur, phase, mode | moyenne journalière par utilisateur |
population |
phase, mode | synthèse population avec n_users |
IndicatorResult.metadata conserve les options de calcul et quelques ordres de grandeur : nombre d’utilisateurs, jours-utilisateurs, nombre moyen d’étapes par jour-utilisateur, prise en compte des excursions, filtrage préalable, jours sans déplacement et pondération.
Export¶
write_mobility_dataset(dataset: MobilityDataset, output_dir: Path, *, formats: tuple[str, ...] = ("csv", "geojson"), extra_tables: Mapping[str, pd.DataFrame] | None = None, selection_table: pd.DataFrame | None = None) -> pd.DataFrame
export_mobility_tables(...) -> pd.DataFrame
write_indicator_result(indicators: IndicatorResult, output_dir: Path, *, formats: tuple[str, ...] = ("parquet", "csv")) -> pd.DataFrame
Formats pris en charge par write_mobility_dataset() : csv, geojson,
parquet, pickle ou pkl, xlsx.
extra_tables permet d'écrire des tables de construction comme
user_presence, participation_grid ou participation_summary sans modifier
la structure de MobilityDataset.
Exports spatiaux pour dashboard¶
add_time_slices(table, *, time_slices=None, datetime_col="started_at", output_col="time_slice", timezone="Europe/Zurich") -> pd.DataFrame
legs_to_h3_points(legs, *, h3_resolution=9, sample_distance_m=None, max_points_per_leg=None) -> gpd.GeoDataFrame
aggregate_h3_frequencies(h3_points, *, group_cols=None) -> pd.DataFrame
build_h3_count_matrix(h3_points, *, dimension_sets=..., metrics=("point_count", "trip_count")) -> pd.DataFrame
build_spatial_analytics_tables(dataset_or_legs, *, h3_resolution=9, config=None, frequency_group_cols=None, count_dimension_sets=..., count_metrics=("point_count", "trip_count")) -> dict[str, pd.DataFrame]
write_spatial_analytics_tables(tables, output_dir, *, formats=("parquet", "csv")) -> pd.DataFrame
write_spatial_analytics_exports(dataset_or_legs, output_dir, *, h3_resolution=9, frequency_group_cols=None, sample_distance_m=None, formats=("parquet", "csv")) -> pd.DataFrame
write_duckdb_spatial_database(tables, database_path, *, load_spatial=True, require_spatial_extension=False) -> pd.DataFrame
Ces fonctions sont optionnelles et nécessitent requirements-analytics.txt
pour H3 ou DuckDB. add_time_slices() ajoute les périodes HPM, HC, HPS
ou des tranches horaires propres au projet. legs_to_h3_points() extrait les
sommets des géométries de legs, ou échantillonne les lignes si
sample_distance_m est défini. build_h3_count_matrix() produit une table
large avec des colonnes de counts par mode, motif et tranche horaire. Le
résultat sert à produire des cartes de fréquentation par cellule H3.
GeoParquet reste le format recommandé pour conserver les tables, tandis que
DuckDB sert aux requêtes SQL locales et aux prototypes de dashboard.
Visualisation de contrôle¶
plot_gps_traces(dataset_or_legs, *, staypoints=None, user_ids=None, sample_n=None, color_by="mode_niv1", save_path=None)
plot_h3_frequency_map(h3_frequency, *, h3_col="h3_cell", value_col="point_count", max_cells=2500, save_path=None)
Ces fonctions sont des outils d'inspection notebook. Elles dépendent de l'extra
optionnel viz et ne font pas partie du pipeline obligatoire.
plot_h3_frequency_map() dépend aussi de h3, donc de
requirements-analytics.txt.
Formats initiaux :
| Donnee | Format interne | Format livrable |
|---|---|---|
legs |
Parquet | GeoJSON |
staypoints |
Parquet | GeoJSON |
trips |
Parquet | CSV |
journeys |
Parquet | CSV |
user_stats |
CSV ou Parquet | CSV |
occupancy_co2 |
Parquet | CSV |
health |
Parquet | CSV |
public_transport |
Parquet | CSV |
leg_points_h3 |
GeoParquet | CSV ou DuckDB |
h3_frequency |
Parquet | CSV ou DuckDB |
| dictionnaire variables | Parquet optionnel | XLSX |
Fonctions a differer¶
Ces fonctions sont utiles mais ne doivent pas bloquer le packaging initial :
generate_synthetic_declic_gps(...)
obfuscate_locations(...)
aggregate_privacy_grid(...)
split_overnight_staypoints(...)
cluster_activity_locations(...)
build_mobility_graphs(...)
compute_action_space(...)
plot_gps(...)
plot_action_space(...)
API publique courte visee¶
import xyt_gps as xyt
config = xyt.ProjectConfig(...)
raw = xyt.load_gps_export(config)
mobility = xyt.prepare_mobility_dataset(raw, config)
indicators = xyt.compute_mobility_indicators(mobility, mode_col="mode_niv2")
xyt.write_mobility_dataset(mobility, "Data/Output/2-transformed-data/experiment-a", formats=["parquet", "csv"])
xyt.write_indicator_result(indicators, "Data/Output/3-enriched-data/experiment-a", formats=["csv", "parquet"])