Skip to content

Evaluation Measures

API Description
common_part_of_commuters Return the common part of commuters (CPC) between two flow arrays.
common_part_of_links Return the common part of links (CPL) between two flow arrays.
common_part_of_commuters_distance Return the common part of commuters by distance (CPCD).
r_squared Return the coefficient of determination R-squared.
rmse Return the root mean squared error between true and predicted values.
nrmse Return the normalized root mean squared error (RMSE / sum(true)).
information_gain Return the information gain of true over predicted values.
pearson_correlation Return the Pearson correlation coefficient and its two-tailed p-value.
spearman_correlation Return the Spearman rank-order correlation coefficient and its p-value.
kullback_leibler_divergence Return the Kullback-Leibler divergence between true and predicted values.
max_error Return the maximum signed error max(true_i - pred_i).
mse Return the mean squared error between true and predicted values.
jensen_shannon_divergence Return Jensen-Shannon divergence between two distributions.
matrix_jensen_shannon_divergence Return Jensen-Shannon divergence between two category matrices.
time_bin_matrix_jensen_shannon_divergence Return mean per-column Jensen-Shannon divergence for time-bin matrices.
histogram_jensen_shannon_divergence Bin two value arrays and return Jensen-Shannon divergence.
wasserstein_distance Return Rust-backed 1D Wasserstein distance between empirical samples.
column_distribution_jensen_shannon_divergence Compare grouped numeric column distributions with Jensen-Shannon divergence.
column_distribution_wasserstein_distance Compare grouped numeric column distributions with Rust-backed Wasserstein distance.
visits_per_user_jensen_shannon_divergence Compare grouped visits-per-user distributions with Jensen-Shannon divergence.
visits_per_user_wasserstein_distance Compare grouped visits-per-user distributions with Rust-backed Wasserstein distance.
od_matrix_common_part_of_commuters Return CPC between two OD matrices, aligning labels when available.
profile_metric_wasserstein_distance Compare a scalar profile metric column with Rust-backed Wasserstein distance.
radius_of_gyration_wasserstein_distance Compare radius-of-gyration distributions, optionally grouped by a column.
dwell_time_wasserstein_distance Compare dwell-time distributions in hours.
stvd_emd Compute the spatio-temporal Wasserstein distance between two distributions.
activity_distribution_jensen_shannon_divergence Compare categorical activity distributions with Jensen-Shannon divergence.
activity_transition_matrix_jensen_shannon_divergence Compare activity transition matrices with Jensen-Shannon divergence.
motif_distribution_jensen_shannon_divergence Discover daily motifs for two visit datasets and compare motif distributions.

fastmob.measures.evaluation

fastmob.measures.evaluation — distribution comparison and evaluation metrics.

activity_distribution_jensen_shannon_divergence(df1, df2, activity_col=None)

Compare categorical activity distributions with Jensen-Shannon divergence.

activity_transition_matrix_jensen_shannon_divergence(matrix1, matrix2, categories1=None, categories2=None)

Compare activity transition matrices with Jensen-Shannon divergence.

column_distribution_jensen_shannon_divergence(df1, df2, column, *, bin_size=1.0, hue=None, trip_start_col1=None, trip_start_col2=None, day_col1=None, day_col2=None, purpose_col=None, skip_day_period_creation=False)

Compare grouped numeric column distributions with Jensen-Shannon divergence.

column_distribution_wasserstein_distance(df1, df2, column, *, hue=None, trip_start_col1=None, trip_start_col2=None, day_col1=None, day_col2=None, purpose_col=None, skip_day_period_creation=False)

Compare grouped numeric column distributions with Rust-backed Wasserstein distance.

common_part_of_commuters(values1, values2)

Return the common part of commuters (CPC) between two flow arrays.

\[ \mathrm{CPC} = \frac{2 \sum_i \min(v_{1,i}, v_{2,i})} {\sum_i v_{1,i} + \sum_i v_{2,i}} \]

Parameters:

Name Type Description Default
values1

First array of flow values (e.g. observed commuter counts).

required
values2

Second array of flow values (e.g. predicted commuter counts).

required

Returns:

Type Description
float

CPC in the range [0, 1] where 1 indicates perfect agreement.

Examples:

>>> from fastmob import common_part_of_commuters
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(common_part_of_commuters(observed, predicted), 3))
0.95

common_part_of_commuters_distance(values1, values2)

Return the common part of commuters by distance (CPCD).

Bins both distance arrays into histograms with bin width 2 and returns the fraction of values1 that overlaps with values2 bin-by-bin:

\[ \mathrm{CPCD} = \frac{\sum_k \min(\mathrm{hist}_{1,k}, \mathrm{hist}_{2,k})} {\sum_i v_{1,i}} \]

Parameters:

Name Type Description Default
values1

First array of distance values (e.g. observed commuting distances in km).

required
values2

Second array of distance values (e.g. predicted commuting distances in km).

required

Returns:

Type Description
float

CPCD value; 0.0 when values1 sums to zero or there is no bin overlap.

Examples:

>>> from fastmob import common_part_of_commuters_distance
>>> observed = [1, 2, 4, 8]
>>> predicted = [1, 3, 5, 9]
>>> print(round(common_part_of_commuters_distance(observed, predicted), 3))
0.2

Return the common part of links (CPL) between two flow arrays.

CPL counts links that are active (\(> 0\)) in both arrays and normalises by the total number of active links across both arrays:

\[ \mathrm{CPL} = \frac{2 \left|\{i : v_{1,i} > 0 \land v_{2,i} > 0\}\right|} {\left|\{i : v_{1,i} > 0\}\right| + \left|\{i : v_{2,i} > 0\}\right|} \]

Parameters:

Name Type Description Default
values1

First array of flow values.

required
values2

Second array of flow values.

required

Returns:

Type Description
float

CPL in the range [0, 1] where 1 means identical link sets.

Examples:

>>> from fastmob import common_part_of_links
>>> observed = [10, 0, 30, 0]
>>> predicted = [5, 7, 0, 0]
>>> print(round(common_part_of_links(observed, predicted), 3))
0.5

dwell_time_wasserstein_distance(df1, df2, duration_col=None, *, hue=None, day_col1=None, day_col2=None, purpose_col=None)

Compare dwell-time distributions in hours.

histogram_jensen_shannon_divergence(values1, values2, bin_size=1.0)

Bin two value arrays and return Jensen-Shannon divergence.

information_gain(true, pred)

Return the information gain (KL divergence variant) of true over pred.

\[ \mathrm{IG} = \sum_i \frac{y_i}{N} \log\left(\frac{y_i}{\hat{y}_i}\right) \]

where \(N = \sum_i y_i\).

Parameters:

Name Type Description Default
true

Ground truth target values (must be positive).

required
pred

Estimated target values (must be positive).

required

Returns:

Type Description
float

Information gain value; 0.0 when the distributions are identical.

Examples:

>>> from fastmob import information_gain
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(information_gain(observed, predicted), 3))
0.005

jensen_shannon_divergence(distribution1, distribution2)

Return Jensen-Shannon divergence between two distributions.

The result matches the historical comparison behavior based on scipy.spatial.distance.jensenshannon(...) ** 2.

kullback_leibler_divergence(true, pred)

Return the Kullback–Leibler divergence \(D_\mathrm{KL}(\mathrm{true}\,\|\,\mathrm{pred})\).

\[ D_\mathrm{KL}(P \,\|\, Q) = \sum_k p_k \log\left(\frac{p_k}{q_k}\right) \]

Computed via scipy.stats.entropy.

Parameters:

Name Type Description Default
true

Probability distribution P (reference).

required
pred

Probability distribution Q (approximation).

required

Returns:

Type Description
float

KL divergence; 0.0 when the distributions are identical.

Raises:

Type Description
ImportError

When scipy is not installed.

Examples:

>>> from fastmob import kullback_leibler_divergence
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(kullback_leibler_divergence(observed, predicted), 3))
0.005

matrix_jensen_shannon_divergence(matrix1, matrix2, categories1=None, categories2=None)

Return Jensen-Shannon divergence between two category matrices.

max_error(true, pred)

Return the maximum signed error max(true_i - pred_i).

Parameters:

Name Type Description Default
true

Ground truth target values.

required
pred

Estimated target values.

required

Returns:

Type Description
float

Maximum element-wise difference true - pred.

Examples:

>>> from fastmob import max_error
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(max_error(observed, predicted), 3))
3.0

motif_distribution_jensen_shannon_divergence(visits1, visits2, *, user_id_col1=None, user_id_col2=None, location_id_col=None)

Discover daily motifs for two visit datasets and compare motif distributions.

mse(true, pred)

Return the mean squared error between true and predicted values.

Parameters:

Name Type Description Default
true

Ground truth target values.

required
pred

Estimated target values.

required

Returns:

Type Description
float

Non-negative MSE; 0.0 is the best possible value.

Examples:

>>> from fastmob import mse
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(mse(observed, predicted), 3))
6.5

nrmse(true, pred)

Return the normalized root mean squared error (RMSE / sum(true)).

Parameters:

Name Type Description Default
true

Ground truth target values.

required
pred

Estimated target values.

required

Returns:

Type Description
float

Non-negative NRMSE; 0.0 is the best possible value.

Examples:

>>> from fastmob import nrmse
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(nrmse(observed, predicted), 3))
0.025

od_matrix_common_part_of_commuters(od1, od2)

Return CPC between two OD matrices, aligning labels when available.

pearson_correlation(true, pred)

Return the Pearson correlation coefficient and its two-tailed p-value.

Parameters:

Name Type Description Default
true

Ground truth values.

required
pred

Predicted values.

required

Returns:

Type Description
tuple[float, float]

(Pearson r, two-tailed p-value).

Raises:

Type Description
ImportError

When scipy is not installed.

Examples:

>>> from fastmob import pearson_correlation
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> r, p_value = pearson_correlation(observed, predicted)
>>> print(round(r, 3), round(p_value, 3))
0.975 0.025

profile_metric_wasserstein_distance(df1, df2, metric_col)

Compare a scalar profile metric column with Rust-backed Wasserstein distance.

r_squared(true, pred)

Return the coefficient of determination R².

\[ R^2 = 1 - \frac{SS_\mathrm{res}}{SS_\mathrm{tot}} \]

where

\[ SS_\mathrm{tot} = \sum_i (y_i - \bar{y})^2 \]

Parameters:

Name Type Description Default
true

Ground truth target values.

required
pred

Estimated target values.

required

Returns:

Type Description
float

R² score. Best possible value is 1.0; can be negative.

Examples:

>>> from fastmob import r_squared
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(r_squared(observed, predicted), 3))
0.948

radius_of_gyration_wasserstein_distance(df1, df2, radius_col='radius_of_gyration_km', grouping_col=None)

Compare radius-of-gyration distributions, optionally grouped by a column.

rmse(true, pred)

Return the root mean squared error between true and predicted values.

Parameters:

Name Type Description Default
true

Ground truth target values.

required
pred

Estimated target values.

required

Returns:

Type Description
float

Non-negative RMSE; 0.0 is the best possible value.

Examples:

>>> from fastmob import rmse
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> print(round(rmse(observed, predicted), 3))
2.55

spearman_correlation(true, pred)

Return the Spearman rank-order correlation coefficient and its p-value.

Parameters:

Name Type Description Default
true

Ground truth values.

required
pred

Predicted values.

required

Returns:

Type Description
tuple[float, float]

(Spearman rho, two-tailed p-value).

Raises:

Type Description
ImportError

When scipy is not installed.

Examples:

>>> from fastmob import spearman_correlation
>>> observed = [10, 20, 30, 40]
>>> predicted = [12, 18, 33, 37]
>>> rho, p_value = spearman_correlation(observed, predicted)
>>> print(round(rho, 3), round(p_value, 3))
1.0 0.0

stvd_emd(dist_a, dist_b, alpha=10.0, cyclical_period=1440.0, num_projections=50, *, time_col=None, weight_col=None, centroid_col=None)

Compute the spatio-temporal Wasserstein distance between two distributions.

Each input is a DataFrame representing a spatial-temporal distribution with columns for a time bin (HH:MM string), a weight/volume value, and a centroid geometry in a projected coordinate system. Centroids may be WKT strings ('POINT (x y)') or objects with .x / .y attributes.

Distances are computed using sliced Wasserstein over a 4D embedding (x, y, r*cos(theta), r*sin(theta)) where r = alpha * cyclical_period / (2*pi) and theta = 2*pi*(t / cyclical_period).

Parameters:

Name Type Description Default
dist_a Any

Any Narwhals-compatible eager DataFrame (pandas, polars, …).

required
dist_b Any

Any Narwhals-compatible eager DataFrame (pandas, polars, …).

required
alpha float

Space-time tradeoff: 1 minute equals alpha metres. Default 10.0.

10.0
cyclical_period float

Wrap-around period in minutes. Default 1440 (one day).

1440.0
num_projections int

Number of random projections used by sliced Wasserstein. Must be > 0. Larger values improve stability at higher computational cost.

50
time_col str | None

Explicit time column name. Auto-detected when None.

None
weight_col str | None

Explicit weight column name. Auto-detected when None.

None
centroid_col str | None

Explicit centroid column name. Auto-detected when None.

None

Returns:

Type Description
float

Spatio-temporal Wasserstein distance in metres.

Examples:

>>> import pandas as pd
>>> from fastmob.measures.evaluation import stvd_emd
>>> dist_a = pd.DataFrame(
...     {
...         "time_bin": ["08:00", "08:10"],
...         "mean_volume": [2.0, 1.0],
...         "centroid": ["POINT (0 0)", "POINT (100 0)"],
...     }
... )
>>> dist_b = pd.DataFrame(
...     {
...         "time_bin": ["08:00", "08:10"],
...         "mean_volume": [1.0, 2.0],
...         "centroid": ["POINT (0 0)", "POINT (200 0)"],
...     }
... )
>>> print(round(stvd_emd(dist_a, dist_b, num_projections=10), 3))
19.052

time_bin_matrix_jensen_shannon_divergence(matrix1, matrix2, categories1=None, categories2=None)

Return mean per-column Jensen-Shannon divergence for time-bin matrices.

trajectory_common_part_of_commuters(traj_a, traj_b, resolution=9, *, datetime_col_a=None, lat_col_a=None, lng_col_a=None, uid_col_a=None, datetime_col_b=None, lat_col_b=None, lng_col_b=None, uid_col_b=None)

Compute trajectory CPC from sparse H3 OD flows without materialising an OD matrix.

Rows are ordered by user and datetime. Invalid coordinates, null required fields, missing destinations, and self-loops are excluded before comparing OD edge counts.

trajectory_common_part_of_commuters_multi(traj_a, traj_b, resolutions=(7, 8, 9), *, datetime_col_a=None, lat_col_a=None, lng_col_a=None, uid_col_a=None, datetime_col_b=None, lat_col_b=None, lng_col_b=None, uid_col_b=None)

Compute trajectory CPC at multiple H3 resolutions, preparing each trajectory's inputs only once instead of once per resolution.

Equivalent to calling :func:trajectory_common_part_of_commuters once per resolution, but the dataframe conversion, column detection, datetime casting, null-dropping, and time-ordered user-range construction done by _trajectory_cpc_inputs are resolution-independent and were otherwise being redone for every resolution -- tripling cost (or more) on large trajectories for no benefit, since only the final H3-binning kernel call actually depends on resolution.

visits_per_user_jensen_shannon_divergence(df1, df2, *, hue=None, user_id_col1=None, user_id_col2=None, bin_size=1.0, trip_start_col=None, day_col1=None, day_col2=None, purpose_col=None, skip_day_period_creation=False)

Compare grouped visits-per-user distributions with Jensen-Shannon divergence.

visits_per_user_wasserstein_distance(df1, df2, *, hue=None, user_id_col1=None, user_id_col2=None, trip_start_col=None, day_col1=None, day_col2=None, purpose_col=None, skip_day_period_creation=False)

Compare grouped visits-per-user distributions with Rust-backed Wasserstein distance.

wasserstein_distance(values1, values2)

Return Rust-backed 1D Wasserstein distance between empirical samples.