Generation Models
Flow models
| API | Description | Example |
|---|---|---|
Gravity |
Gravity model: flows between places from their sizes and the distance between them. | Fit and run a gravity model |
Gravity.fit |
Fit the Gravity model parameters to observed flows via Poisson regression. | Fit and run a gravity model |
Gravity.fit_statistics |
Goodness-of-fit statistics of the last fit. | The distance decay, with a confidence interval |
Gravity.fit_summary |
The fitted parameters with standard errors, confidence intervals and p-values. | The distance decay, with a confidence interval |
Gravity.generate |
Generate synthetic flows with the Gravity model. | Fit and run a gravity model |
Radiation |
Radiation model: flows between places from their populations and the opportunities in between. | Flows |
Radiation.generate |
Generate synthetic flows with the Radiation model. | Flows |
Individual trajectory models
| API | Description | Example |
|---|---|---|
EPR |
Exploration and Preferential Return (EPR) trajectory generator. | Exploration and preferential return |
EPR.generate |
Simulate agents from start_date to end_date. |
Exploration and preferential return |
DensityEPR |
Density-EPR (d-EPR) trajectory generator. | Exploration and preferential return |
DensityEPR.generate |
Simulate agents from start_date to end_date. |
Exploration and preferential return |
SpatialEPR |
Spatial-EPR (s-EPR) trajectory generator. | Exploration and preferential return |
SpatialEPR.generate |
Simulate agents from start_date to end_date. |
Exploration and preferential return |
Ditras |
DITRAS (DIary-based TRAjectory Simulator) modelling framework. | Realistic daily rhythm |
Ditras.generate |
Simulate agents from start_date to end_date. |
Realistic daily rhythm |
MarkovDiaryGenerator |
Markov diary learner and generator: when a person is at home or away, hour by hour. | Realistic daily rhythm |
MarkovDiaryGenerator.fit |
Learn the Markov mobility diary from real trajectories. | Realistic daily rhythm |
MarkovDiaryGenerator.generate |
Generate a synthetic mobility diary. | Realistic daily rhythm |
Social trajectory models
| API | Description | Example |
|---|---|---|
GeoSim |
GeoSim social trajectory generator. | Social ties |
GeoSim.generate |
Simulate a socially connected population from start_date to end_date. |
Social ties |
STS_epr |
STS-EPR (Spatial, Temporal, and Social EPR) trajectory generator. | Social ties |
STS_epr.generate |
Simulate a socially connected population from start_date to end_date. |
Social ties |
Next-location prediction
| API | Description | Example |
|---|---|---|
NextLocationPredictor |
Order-k Markov next-location predictor with optional backoff. | Predict the next place |
NextLocationPredictor.evaluate |
Holdout-last-n_holdout accuracy over the data given to fit. |
Predict the next place |
NextLocationPredictor.fit |
Fit one Markov model per user from each user's location-id sequence. | Predict the next place |
NextLocationPredictor.predict |
Predict each fitted user's single most likely next location. | Predict the next place |
NextLocationPredictor.predict_proba |
Predict each fitted user's next location(s) from their own training history's tail. | Predict the next place |
The fastmob.models package mirrors the original scikit-mobility generation API. Model implementations accept pandas or Narwhals-compatible eager dataframes and may convert inputs to pandas internally.
Only Gravity.fit() needs Statsmodels for Poisson-GLM fitting:
Flow Models
Fitting flows with custom column names
Gravity.fit accepts a FlowDataFrame with an attached Locations catalogue,
or a dataframe or FlowDataFrame with the catalogue passed as locations=.
The origin and destination values must match its location IDs, and the catalogue
must contain the selected relevance column (population or another measure of
location size). For an existing pandas table flows_df with columns Area_O,
Area_D, and Weight_Day, and a prepared locations catalogue:
from fastmob.core import FlowDataFrame
from fastmob.models import Gravity
flows = FlowDataFrame(flows_df, locations=locations)
model = Gravity()
model.fit(
flows,
origin_col="Area_O",
destination_col="Area_D",
flow_col="Weight_Day",
relevance_column="relevance",
)
For an OD table without an attached catalogue, pass it directly:
model.fit(flows_df, locations=locations, origin_col="Area_O",
destination_col="Area_D", flow_col="Weight_Day")
An explicit locations argument takes precedence over an attached catalogue.
The default names are origin, destination, and flow. Alternatively,
FlowDataFrame can rename input columns to those defaults using its origin,
destination, and flow constructor arguments; in that case use the default
names when fitting. See the worked example
for preparing locations and interpreting a fit.
Gravity
Gravity model: flows between places from their sizes and the distance between them.
The Gravity model of human migration. In its original formulation, the probability \(T_{ij}\) of moving from location \(i\) to location \(j\) is proportional to [Z1946]:
where \(P_i\) and \(P_j\) are the populations (or relevances) of locations \(i\) and \(j\) and \(r_{ij}\) is the distance between them. The general form is [BBGJLLMRST2018]:
where \(K\) is a constant and \(f(r_{ij})\) is a deterrence function — a decreasing function of distance commonly modelled as a power law or exponential.
Singly constrained variant. When the total outflow \(O_i\) from each origin is known, the model estimates destinations only:
Globally constrained variant. Only the total flow of the whole system is fixed, through a single constant \(K\):
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
deterrence_func_type
|
str
|
The deterrence function to use. Accepted values: |
'power_law'
|
deterrence_func_args
|
list
|
Arguments for the deterrence function. For |
None
|
origin_exp
|
float
|
Exponent applied to the origin's relevance (only used in the globally
constrained model). The default is |
1.0
|
destination_exp
|
float
|
Exponent applied to the destination's relevance. The default is |
1.0
|
gravity_type
|
str
|
The model variant. Accepted values: |
'singly constrained'
|
name
|
str
|
Human-readable label for this model instance. The default is
|
'Gravity model'
|
Attributes:
| Name | Type | Description |
|---|---|---|
deterrence_func_type |
str
|
The deterrence function in use. |
deterrence_func_args |
list
|
Arguments for the deterrence function. |
origin_exp |
float
|
Exponent applied to the origin's relevance. |
destination_exp |
float
|
Exponent applied to the destination's relevance. |
gravity_type |
str
|
The model variant ( |
name |
str
|
Human-readable label of this model instance. |
Notes
The places are given as a Locations catalogue (Locations.from_tessellation builds one from a table with
a tile id, latitude, longitude, a relevance column and, to generate flows, a total outflow column).
Examples:
>>> import pandas as pd
>>> from fastmob.core import Locations
>>> from fastmob.models import Gravity
>>> tessellation = pd.DataFrame({
... "tile_id": [0, 1, 2, 3],
... "lat": [40.71, 41.88, 37.77, 33.44],
... "lng": [-74.01, -87.62, -122.42, -112.07],
... "relevance": [1_000_000, 2_700_000, 880_000, 1_600_000],
... "tot_outflow": [100_000, 250_000, 90_000, 150_000],
... })
>>> locations = Locations.from_tessellation(tessellation, tile_id_col="tile_id", lat_col="lat", lng_col="lng")
>>> gravity = Gravity(gravity_type="singly constrained")
>>> print(gravity)
Gravity(name="Gravity model", deterrence_func_type="power_law", deterrence_func_args=[-2.0], origin_exp=1.0, destination_exp=1.0, gravity_type="singly constrained")
>>> flows = gravity.generate(locations, out_format="flows")
>>> int(round(flows.to_pandas()["flow"].sum()))
590000
References
.. [Z1946] Zipf, G. K. (1946). The P1 P2/D Hypothesis: On the Intercity Movement of Persons. American Sociological Review, 11(6), 677–686. .. [W1971] Wilson, A. G. (1971). A family of spatial interaction models, and associated developments. Environment and Planning A, 3(1), 1–32. .. [BBGJLLMRST2018] Barbosa, H. et al. (2018). Human mobility: Models and applications. Physics Reports, 734, 1–74.
See Also
Radiation
fit(flow_df, relevance_column=RELEVANCE, robust=True, include_zeros=True, *, origin_col='origin', destination_col='destination', flow_col=FLOW, locations=None, origin_relevance_column=None, destination_relevance_column=None, cov_type=None)
Fit the Gravity model parameters to observed flows via Poisson regression.
Uses a Generalised Linear Model (GLM) with a Poisson family and log link to
estimate destination_exp and deterrence_func_args (and
origin_exp for the globally constrained variant) from real flows
[FM1982].
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
flow_df
|
FlowDataFrame or dataframe
|
Observed flows. Supply a |
required |
relevance_column
|
str
|
Name of the column of the locations catalogue that holds the location
relevance (e.g. population). It is used for the origin and the destination unless
|
RELEVANCE
|
robust
|
bool
|
Report heteroskedasticity-robust (sandwich) standard errors and confidence intervals. Real flows are
usually overdispersed relative to the Poisson model, which makes the model-based errors too small;
the point estimates are the same either way. Default True. |
True
|
include_zeros
|
bool
|
Add every pair of locations that is missing from |
True
|
origin_col
|
str
|
Name of the origin column in the flow table. Default |
'origin'
|
destination_col
|
str
|
Name of the destination column in the flow table. Default |
'destination'
|
flow_col
|
str
|
Name of the flow column in the flow table. Default |
FLOW
|
locations
|
Locations
|
Location catalogue to use for fitting. When supplied, it takes precedence over a catalogue
attached to |
None
|
origin_relevance_column
|
str
|
Column of the catalogue with the size of the origin (the outflow side, for example residents or
departures). Default: |
None
|
destination_relevance_column
|
str
|
Column of the catalogue with the size of the destination (the inflow side, for example jobs or
arrivals). Default: |
None
|
cov_type
|
('nonrobust', 'HC0', 'HC1')
|
Covariance estimator of the standard errors. |
"nonrobust"
|
Raises:
| Type | Description |
|---|---|
ImportError
|
If statsmodels is not installed (only the globally constrained variant needs it). |
AttributeError
|
If no |
TypeError
|
If |
KeyError
|
If a selected flow column is missing. |
ValueError
|
If the design matrix is rank-deficient (too few distinct origins or distances), |
Notes
Modifies deterrence_func_args, destination_exp, and (for the globally
constrained variant) origin_exp in-place.
After fitting, fit_summary returns the estimates with standard errors, 95% confidence intervals and
p-values, and fit_statistics the number of flows used, the log-likelihood, the deviance, the
pseudo R-squared and the dispersion. For "power_law" the distance coefficient is the exponent
gamma of flow ∝ distance^gamma (negative: flows fall with distance); for "exponential"
the table reports the decay rate lambda of exp(-lambda * distance) in km^-1 (positive: flows fall with
distance). Relevance that is itself made of the flows (for example check-ins counted in the destination)
makes the destination exponent partly circular; prefer an independent size such as population or jobs.
References
- [FM1982] Flowerdew, R. & Murray, A. (1982). A method of fitting the gravity model based on the Poisson distribution. Journal of Regional Science, 22(2), 191–202.
- [ST2006] Santos Silva, J. M. C. & Tenreyro, S. (2006). The log of gravity. The Review of Economics and Statistics, 88(4), 641–658.
Examples:
>>> import pandas as pd
>>> from fastmob.core import Locations
>>> from fastmob.models import Gravity
>>> places = pd.DataFrame({
... "tile_id": range(6),
... "lat": [45.0, 45.1, 45.3, 45.2, 45.6, 45.5],
... "lng": [7.0, 7.4, 7.1, 7.9, 7.6, 7.2],
... "relevance": [9_000, 7_000, 5_000, 3_000, 8_000, 6_000],
... "tot_outflow": [60_000, 50_000, 40_000, 30_000, 70_000, 45_000],
... })
>>> locations = Locations.from_tessellation(places, tile_id_col="tile_id", lat_col="lat", lng_col="lng")
>>> observed = Gravity(deterrence_func_args=[-2.0]).generate(locations, out_format="flows")
>>> model = Gravity()
>>> model.fit(observed)
>>> round(model.deterrence_func_args[0], 2)
-2.0
>>> model.fit_summary().column("parameter").to_pylist()
['destination_exp', 'distance_coefficient']
fit_statistics()
Goodness-of-fit statistics of the last fit.
Returns:
| Type | Description |
|---|---|
dict
|
|
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
fit_summary()
The fitted parameters with standard errors, confidence intervals and p-values.
Returns:
| Type | Description |
|---|---|
Table
|
One row per model parameter with |
Raises:
| Type | Description |
|---|---|
RuntimeError
|
If |
generate(locations, tot_outflows_column=TOT_OUTFLOW, relevance_column=RELEVANCE, out_format='flows', random_state=None)
Generate synthetic flows with the Gravity model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locations
|
Locations
|
Global locations on which to run the model. They must provide a
relevance column and, for |
required |
tot_outflows_column
|
str
|
Name of the column containing the total outflow per location. Required
when |
TOT_OUTFLOW
|
relevance_column
|
str
|
Name of the column containing the location relevance (e.g. population).
The default is |
RELEVANCE
|
out_format
|
str
|
Format of the output. Accepted values:
The default is |
'flows'
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A dataframe with columns |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
Worked example: Fit and run a gravity model · The distance decay, with a confidence interval
Radiation
Radiation model: flows between places from their populations and the opportunities in between.
The radiation model for human migration. The model assumes that a traveller's destination choice follows two steps: each opportunity at every location is assigned a random fitness drawn from a distribution \(P(z)\), and the traveller accepts the closest opportunity whose fitness exceeds a threshold drawn from the same distribution. The resulting average flow from \(i\) to \(j\) is [SGMB2012]:
where \(O_i\) is the total outflow from location \(i\), \(m_i\) (\(m_j\)) is the relevance (e.g. population) at the origin (destination), \(s_{ij}\) is the total relevance within the circle of radius \(r_{ij}\) centred on \(i\) excluding origin and destination, and \(M = \sum_i m_i\) is the total system relevance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label for this model instance. The default is
|
'Radiation model'
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
Notes
Generation accepts Locations with global location IDs
and numeric centre coordinates.
Examples:
>>> import pandas as pd
>>> from fastmob.core import Locations
>>> from fastmob.models import Radiation
>>> locations = Locations(pd.DataFrame({
... "tile_id": [0, 1, 2, 3],
... "lat": [40.71, 41.88, 37.77, 33.44],
... "lng": [-74.01, -87.62, -122.42, -112.07],
... "relevance": [1_000_000, 2_700_000, 880_000, 1_600_000],
... "tot_outflow": [100_000, 250_000, 90_000, 150_000],
... }))
>>> radiation = Radiation()
>>> rad_flows = radiation.generate(locations, tot_outflows_column="tot_outflow",
... relevance_column="relevance",
... out_format="flows_sample")
>>> print(rad_flows.head())
References
.. [SGMB2012] Simini, F., González, M. C., Maritan, A. & Barabási, A.-L. (2012). A universal model for mobility and migration patterns. Nature, 484(7392), 96–100. .. [MSJB2013] Masucci, A. P., Serras, J., Johansson, A. & Batty, M. (2013). Gravity versus radiation models: On the importance of scale and heterogeneity in commuting flows. Physical Review E, 88(2), 022812.
See Also
Gravity
generate(locations, tot_outflows_column=TOT_OUTFLOW, relevance_column=RELEVANCE, out_format='flows', random_state=None)
Generate synthetic flows with the Radiation model.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
locations
|
Locations
|
Global locations on which to run the model. Must include a relevance
column; the total-outflow column is
required when |
required |
tot_outflows_column
|
str
|
Name of the column containing the total outflow per location. Required
when |
TOT_OUTFLOW
|
relevance_column
|
str
|
Name of the column containing the location relevance (e.g. population).
The default is |
RELEVANCE
|
out_format
|
str
|
Format of the output. Accepted values:
The default is |
'flows'
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A dataframe with columns |
Raises:
| Type | Description |
|---|---|
KeyError
|
If |
ValueError
|
If |
Worked example: Flows
Individual Trajectory Models
EPR
Exploration and Preferential Return (EPR) trajectory generator.
The EPR model generates synthetic individual mobility trajectories based on two competing mechanisms drawn from empirical observations of human travel patterns [SKWB2010]:
Waiting time choice. The time \(\Delta t\) between consecutive moves is drawn from a truncated power law:
Action selection. With probability \(P_{\text{new}} = \rho S^{-\gamma}\), where \(S\) is the number of distinct previously visited locations, the agent explores a new location; otherwise it returns to a previously visited one.
Exploration. The new location \(j \neq i\) is chosen with probability
proportional to the gravity-model score \(p_{ij}\) derived from
gravity_singly.
Return. A previously visited location \(i\) is chosen with probability \(\Pi_i = f_i\), proportional to its visitation frequency.
This class is the base for DensityEPR, SpatialEPR, and
Ditras.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label for this model instance. The default is
|
'EPR model'
|
rho
|
float
|
Exploration parameter \(\rho \in (0, 1]\) in
\(P_{\text{new}} = \rho S^{-\gamma}\). Controls the overall tendency
to explore new locations. The default is |
0.6
|
gamma
|
float
|
Return-penalty exponent \(\gamma \geq 0\) in
\(P_{\text{new}} = \rho S^{-\gamma}\). Larger values cause agents to
return more frequently as they accumulate visited locations. The default is
|
0.21
|
beta
|
float
|
Tail exponent \(\beta\) of the waiting-time distribution. The default
is |
0.8
|
tau
|
int
|
Characteristic time scale \(\tau\) (in hours) of the waiting-time
distribution. The default is |
17
|
min_wait_time_minutes
|
int
|
Minimum waiting time between two moves, in minutes. The default is |
20
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
rho |
float
|
The exploration parameter \(\rho\). |
gamma |
float
|
The return-penalty exponent \(\gamma\). |
beta |
float
|
The waiting-time tail exponent \(\beta\). |
tau |
int
|
The waiting-time scale \(\tau\) (in hours). |
min_wait_time |
float
|
Minimum waiting time in hours ( |
spatial_tessellation_ |
DataFrame or None
|
The tessellation used in the last |
trajectories_ |
list
|
Raw trajectory records produced by the last |
References
.. [SKWB2010] Song, C., Koren, T., Wang, P. & Barabási, A.-L. (2010). Modelling the scaling properties of human mobility. Nature Physics, 6, 818–823.
See Also
DensityEPR, SpatialEPR, Ditras
generate(start_date, end_date, spatial_tessellation, gravity_singly=None, n_agents=1, starting_locations=None, relevance_column=RELEVANCE, random_state=None)
Simulate agents from start_date to end_date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
Timestamp or datetime
|
Start time of the simulation. |
required |
end_date
|
Timestamp or datetime
|
End time of the simulation. |
required |
spatial_tessellation
|
DataFrame or GeoDataFrame
|
Division of the territory into locations. Must include either a
|
required |
gravity_singly
|
Gravity or None
|
A singly constrained |
None
|
n_agents
|
int
|
Number of agents to simulate. The default is |
1
|
starting_locations
|
list of int or None
|
One starting tessellation index per agent. Length must equal
|
None
|
relevance_column
|
str
|
Name of the column in |
RELEVANCE
|
random_state
|
int or None
|
Seed for the random number generator, enabling reproducible results.
The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Synthetic trajectories with columns |
Raises:
| Type | Description |
|---|---|
IndexError
|
If |
TypeError
|
If |
AttributeError
|
If |
Worked example: Exploration and preferential return
DensityEPR
Bases: EPR
Density-EPR (d-EPR) trajectory generator.
The d-EPR model weights exploratory moves according to a gravity model that
accounts for location relevance (e.g. population density) [PSRPGB2015][PSR2016]. EPR explores with the same gravity score, so DensityEPR and
EPR produce the same trajectories for equal inputs and seed; this class is
provided under the name used in the literature. The four mechanisms are:
Waiting time choice. The waiting time \(\Delta t\) between two moves is drawn from \(P(\Delta t) \sim \Delta t^{-1-\beta} \exp(-\Delta t/\tau)\).
Action selection. With probability \(P_{\text{new}} = \rho S^{-\gamma}\), where \(S\) is the number of distinct previously visited locations, the agent explores a new location; otherwise it returns to a previously visited one.
Exploration. If the agent at location \(i\) explores, the destination \(j \neq i\) is selected with probability proportional to the gravity score:
where \(n_{i(j)}\) is the relevance of location \(i(j)\) and \(r_{ij}\) is their Haversine distance. The set of visited locations \(S\) grows by 1.
Return. A previously visited location \(i\) is chosen with probability proportional to its visitation frequency: \(\Pi_i = f_i\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label. The default is |
'Density EPR model'
|
rho
|
float
|
Exploration parameter \(\rho \in (0, 1]\). The default is |
0.6
|
gamma
|
float
|
Return-penalty exponent \(\gamma \geq 0\). The default is |
0.21
|
beta
|
float
|
Waiting-time tail exponent \(\beta\). The default is |
0.8
|
tau
|
int
|
Waiting-time scale \(\tau\) in hours. The default is |
17
|
min_wait_time_minutes
|
int
|
Minimum waiting time between moves, in minutes. The default is |
20
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
rho |
float
|
The exploration parameter \(\rho\). |
gamma |
float
|
The return-penalty exponent \(\gamma\). |
beta |
float
|
The waiting-time tail exponent \(\beta\). |
tau |
int
|
The waiting-time scale \(\tau\) (in hours). |
min_wait_time |
float
|
Minimum waiting time in hours. |
Notes
spatial_tessellation accepts any eager dataframe (pandas, polars, …). If
a relevance column is absent, all locations are treated as equally relevant.
Examples:
>>> import pandas as pd
>>> from fastmob.models import DensityEPR
>>> tessellation = pd.DataFrame({
... "tile_id": [0, 1, 2, 3],
... "lat": [40.71, 41.88, 37.77, 33.44],
... "lng": [-74.01, -87.62, -122.42, -112.07],
... "relevance": [0.40, 0.30, 0.18, 0.12],
... })
>>> start = pd.Timestamp("2020-01-01 08:00:00")
>>> end = pd.Timestamp("2020-01-14 08:00:00")
>>> tdf = DensityEPR().generate(start, end, tessellation, n_agents=2, random_state=0)
>>> print(tdf.head())
References
.. [PSRPGB2015] Pappalardo, L. et al. (2015). Returners and Explorers dichotomy in human mobility. Nature Communications, 6, 8166. .. [PSR2016] Pappalardo, L., Simini, F. & Rinzivillo, S. (2016). Human Mobility Modelling: exploration and preferential return meet the gravity model. Procedia Computer Science, 83. .. [SKWB2010] Song, C., Koren, T., Wang, P. & Barabási, A.-L. (2010). Modelling the scaling properties of human mobility. Nature Physics, 6, 818–823.
See Also
EPR, SpatialEPR, Ditras
generate(start_date, end_date, spatial_tessellation, gravity_singly=None, n_agents=1, starting_locations=None, relevance_column=RELEVANCE, random_state=None)
Simulate agents from start_date to end_date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
Timestamp or datetime
|
Start time of the simulation. |
required |
end_date
|
Timestamp or datetime
|
End time of the simulation. |
required |
spatial_tessellation
|
DataFrame or GeoDataFrame
|
Division of the territory into locations. Must include either a
|
required |
gravity_singly
|
Gravity or None
|
A singly constrained |
None
|
n_agents
|
int
|
Number of agents to simulate. The default is |
1
|
starting_locations
|
list of int or None
|
One tessellation index per agent as the starting position. If |
None
|
relevance_column
|
str
|
Column in |
RELEVANCE
|
random_state
|
int or None
|
Random seed for reproducibility. The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Synthetic trajectories with columns |
Worked example: Exploration and preferential return
SpatialEPR
Bases: EPR
Spatial-EPR (s-EPR) trajectory generator.
The s-EPR model is a distance-only variant of DensityEPR that ignores
location relevance during exploration [PSRPGB2015][PSR2016] [SKWB2010]. The
four mechanisms are:
Waiting time choice. The waiting time \(\Delta t\) between two moves is drawn from \(P(\Delta t) \sim \Delta t^{-1-\beta} \exp(-\Delta t/\tau)\).
Action selection. With probability \(P_{\text{new}} = \rho S^{-\gamma}\), where \(S\) is the number of distinct previously visited locations, the agent explores a new location; otherwise it returns to a previously visited one.
Exploration. If the agent at location \(i\) explores, the unvisited destination \(j \neq i\) is selected inversely proportional to squared distance only:
Return. A previously visited location \(i\) is chosen with probability proportional to its visitation frequency: \(\Pi_i = f_i\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label. The default is |
'Spatial EPR model'
|
rho
|
float
|
Exploration parameter \(\rho \in (0, 1]\). The default is |
0.6
|
gamma
|
float
|
Return-penalty exponent \(\gamma \geq 0\). The default is |
0.21
|
beta
|
float
|
Waiting-time tail exponent \(\beta\). The default is |
0.8
|
tau
|
int
|
Waiting-time scale \(\tau\) in hours. The default is |
17
|
min_wait_time_minutes
|
int
|
Minimum waiting time between moves, in minutes. The default is |
20
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
rho |
float
|
The exploration parameter \(\rho\). |
gamma |
float
|
The return-penalty exponent \(\gamma\). |
beta |
float
|
The waiting-time tail exponent \(\beta\). |
tau |
int
|
The waiting-time scale \(\tau\) (in hours). |
min_wait_time |
float
|
Minimum waiting time in hours. |
Notes
spatial_tessellation accepts any eager dataframe (pandas, polars, …). The
relevance_column parameter is accepted for API compatibility but is not
used — all location relevances are treated as equal in the spatial phase.
Examples:
>>> import pandas as pd
>>> from fastmob.models import SpatialEPR
>>> tessellation = pd.DataFrame({
... "tile_id": [0, 1, 2, 3],
... "lat": [40.71, 41.88, 37.77, 33.44],
... "lng": [-74.01, -87.62, -122.42, -112.07],
... })
>>> start = pd.Timestamp("2020-01-01 08:00:00")
>>> end = pd.Timestamp("2020-01-14 08:00:00")
>>> tdf = SpatialEPR().generate(start, end, tessellation, n_agents=2, random_state=0)
>>> print(tdf.head())
References
.. [PSRPGB2015] Pappalardo, L. et al. (2015). Returners and Explorers dichotomy in human mobility. Nature Communications, 6, 8166. .. [PSR2016] Pappalardo, L., Simini, F. & Rinzivillo, S. (2016). Human Mobility Modelling: exploration and preferential return meet the gravity model. Procedia Computer Science, 83. .. [SKWB2010] Song, C., Koren, T., Wang, P. & Barabási, A.-L. (2010). Modelling the scaling properties of human mobility. Nature Physics, 6, 818–823.
See Also
EPR, DensityEPR, Ditras
generate(start_date, end_date, spatial_tessellation, gravity_singly=None, n_agents=1, starting_locations=None, random_state=None)
Simulate agents from start_date to end_date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
Timestamp or datetime
|
Start time of the simulation. |
required |
end_date
|
Timestamp or datetime
|
End time of the simulation. |
required |
spatial_tessellation
|
DataFrame or GeoDataFrame
|
Division of the territory into locations. |
required |
gravity_singly
|
Gravity or None
|
A singly constrained |
None
|
n_agents
|
int
|
Number of agents to simulate. The default is |
1
|
starting_locations
|
list of int or None
|
One tessellation index per agent as the starting position. The default
is |
None
|
random_state
|
int or None
|
Random seed for reproducibility. The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Synthetic trajectories with columns |
Worked example: Exploration and preferential return
Ditras
Bases: EPR
DITRAS (DIary-based TRAjectory Simulator) modelling framework.
DITRAS simulates spatio-temporal mobility patterns by combining two probabilistic models [PS2018]:
Phase 1 — Mobility Diary Generation. A MarkovDiaryGenerator produces
a mobility diary \(D(t)\) that encodes the temporal pattern of an agent's
routine (home vs. away at each hour).
Phase 2 — Trajectory Generation. The mobility diary drives a
DensityEPR-like spatial mechanism: diary slots labelled 0 map the
agent back to its home location; other slots trigger an EPR exploration/return
step to assign a physical location.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diary_generator
|
MarkovDiaryGenerator
|
A fitted |
required |
name
|
str
|
Human-readable label. The default is |
'Ditras model'
|
rho
|
float
|
Exploration parameter \(\rho \in (0, 1]\) for the spatial phase.
The default is |
0.3
|
gamma
|
float
|
Return-penalty exponent \(\gamma \geq 0\) for the spatial phase.
The default is |
0.21
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
rho |
float
|
The exploration parameter \(\rho\). |
gamma |
float
|
The return-penalty exponent \(\gamma\). |
Notes
spatial_tessellation accepts any eager dataframe (pandas, polars, …). The
diary generator must be fitted via MarkovDiaryGenerator.fit before
passing it to this class.
Examples:
>>> import pandas as pd
>>> from fastmob.models import Ditras
>>> from fastmob.models import MarkovDiaryGenerator
>>> # Build a minimal diary generator (normally trained on real trajectories)
>>> mdg = MarkovDiaryGenerator()
>>> tessellation = pd.DataFrame({
... "tile_id": [0, 1, 2, 3],
... "lat": [40.71, 41.88, 37.77, 33.44],
... "lng": [-74.01, -87.62, -122.42, -112.07],
... "relevance": [0.40, 0.30, 0.18, 0.12],
... })
>>> start = pd.Timestamp("2020-01-01 08:00:00")
>>> end = pd.Timestamp("2020-01-14 08:00:00")
>>> ditras = Ditras(mdg)
>>> tdf = ditras.generate(start, end, tessellation,
... relevance_column="relevance", n_agents=2,
... random_state=0)
>>> print(tdf.head())
References
.. [PS2018] Pappalardo, L. & Simini, F. (2018). Data-driven generation of spatio-temporal routines in human mobility. Data Mining and Knowledge Discovery, 32, 787–829.
See Also
DensityEPR, MarkovDiaryGenerator
generate(start_date, end_date, spatial_tessellation, gravity_singly=None, n_agents=1, starting_locations=None, relevance_column=RELEVANCE, random_state=None)
Simulate agents from start_date to end_date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
Timestamp or datetime
|
Start time of the simulation. |
required |
end_date
|
Timestamp or datetime
|
End time of the simulation. |
required |
spatial_tessellation
|
DataFrame or GeoDataFrame
|
Division of the territory into locations. Must include either a
|
required |
gravity_singly
|
Gravity or None
|
A singly constrained |
None
|
n_agents
|
int
|
Number of agents to simulate. The default is |
1
|
starting_locations
|
list of int or None
|
One tessellation index per agent as the starting (home) location. If
|
None
|
relevance_column
|
str
|
Column in |
RELEVANCE
|
random_state
|
int or None
|
Random seed for reproducibility. The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Synthetic trajectories with columns |
Worked example: Realistic daily rhythm
MarkovDiaryGenerator
Markov diary learner and generator: when a person is at home or away, hour by hour.
A Mobility Diary Learner (MDL) learns hourly temporal mobility patterns from
real individual trajectories and then synthesises new mobility diaries [PS2018].
A diary \(D(t)\) is a sequence of abstract locations (0 = home,
1, 2, … = non-home destinations in decreasing visitation-frequency order)
at hourly resolution.
The learner translates each individual's trajectory into an abstract time series and builds a Markov chain \(MD(t)\) over 48 states: 24 hours of the day \(\times\) 2 typicality values (1 = at the typical/home location, 0 = away). Transition probabilities are estimated by counting state-to-state transitions across all individuals.
A fitted MarkovDiaryGenerator can be passed to Ditras or
STS_epr to drive their temporal pattern.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label for this instance. The default is |
'Markov diary'
|
granularity_minutes
|
int
|
Temporal resolution of a diary slot, in minutes. Must be a positive
divisor of 1440. The default is |
60
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this instance. |
markov_chain_ |
ndarray or None
|
Flattened CDF matrix built after |
time_slot_length |
str
|
Length of each time slot (fixed at |
Notes
The fit method accepts any pandas-compatible dataframe. The trajectory
must contain a datetime column (auto-detected) and a user-ID column (uid
by default).
Examples:
>>> import pandas as pd
>>> from fastmob.models import MarkovDiaryGenerator
>>> # Normally you would pass a real trajectory TrajDataFrame here.
>>> # This example uses an unfitted generator (home-only diary).
>>> mdg = MarkovDiaryGenerator()
>>> diary = mdg.generate(72, pd.Timestamp("2020-01-01 00:00:00"), random_state=0)
>>> print(diary.head())
References
.. [PS2018] Pappalardo, L. & Simini, F. (2018). Data-driven generation of spatio-temporal routines in human mobility. Data Mining and Knowledge Discovery, 32, 787–829.
See Also
Ditras, STS_epr
fit(traj, n_individuals, lid='location')
Learn the Markov mobility diary from real trajectories.
Builds a 48-state Markov chain from the first n_individuals users in
traj. Each state encodes an hour of the day (0–23) and a typicality
value (1 = home, 0 = away). The resulting transition probabilities are
stored in markov_chain_.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame
|
Mobility trajectories. Must contain a datetime column and a |
required |
n_individuals
|
int
|
Number of individuals from |
required |
lid
|
str
|
Name of the column containing the location cluster identifier. The
default is |
'location'
|
Notes
Modifies the internal Markov chain in-place. Call before passing this
instance to Ditras or STS_epr.
generate(diary_length, start_date, random_state=None)
Generate a synthetic mobility diary.
Samples a sequence of hourly abstract locations from the fitted Markov chain and returns a compact representation where consecutive identical locations are collapsed to a single row.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diary_length
|
int
|
Length of the diary in time slots (equal to hours when
|
required |
start_date
|
Timestamp or datetime
|
Starting timestamp for the diary. |
required |
random_state
|
int or None
|
Random seed for reproducibility. The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
A dataframe with columns:
|
Notes
If fit has not been called, a trivial diary is generated where the
agent stays at home (abstract_location == 0) for the entire period.
Worked example: Realistic daily rhythm
Social Trajectory Models
GeoSim
GeoSim social trajectory generator.
GeoSim generates synthetic individual mobility trajectories by combining the EPR exploration/return mechanism with a social influence layer [THSG2015]. Each agent is embedded in a social network, and with probability \(\alpha\) it consults a social contact when choosing its next location.
Waiting time choice. The time \(\Delta t\) between moves is drawn from:
Action selection. With probability \(P_{\text{exp}} = \rho S^{-\gamma}\), where \(S\) is the number of distinct previously visited locations, the agent explores a new location; otherwise it returns. At that point, with probability \(\alpha\) a social contact influences the location choice (Social); with probability \(1 - \alpha\) the agent acts alone (Individual).
Individual Exploration. An unvisited location is selected uniformly at random from the set \(\text{exp}(a)\) of all unvisited locations for agent \(a\). The set \(S\) grows by 1.
Social Exploration. A social contact \(c\) is selected with probability proportional to the cosine mobility similarity between \(a\) and \(c\). A location is then selected from \(\text{exp}(a) \cap \text{ret}(c)\) with probability proportional to \(c\)'s visitation frequency. The set \(S\) grows by 1.
Individual Return. A previously visited location \(j \in \text{ret}(a)\) is selected with probability proportional to its visitation frequency \(\Pi_j = f_j\).
Social Return. A social contact \(c\) is selected (as in Social Exploration). A location from \(\text{ret}(a) \cap \text{ret}(c)\) is selected proportionally to \(c\)'s visitation frequency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label. The default is |
'GeoSim'
|
rho
|
float
|
Exploration parameter \(\rho \in (0, 1]\). The default is |
0.6
|
gamma
|
float
|
Return-penalty exponent \(\gamma \geq 0\). The default is |
0.21
|
alpha
|
float
|
Social influence probability \(\alpha \in [0, 1]\). The default is
|
0.2
|
beta
|
float
|
Waiting-time tail exponent \(\beta\). The default is |
0.8
|
tau
|
int
|
Waiting-time scale \(\tau\) in hours. The default is |
17
|
min_wait_time_hours
|
float
|
Minimum waiting time between moves, in hours. The default is |
1
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
rho |
float
|
The exploration parameter \(\rho\). |
gamma |
float
|
The return-penalty exponent \(\gamma\). |
alpha |
float
|
The social influence probability \(\alpha\). |
beta |
float
|
The waiting-time tail exponent \(\beta\). |
tau |
int
|
The waiting-time scale \(\tau\) (in hours). |
min_wait_time_hours |
float
|
Minimum waiting time in hours. |
Notes
spatial_tessellation accepts any pandas-compatible eager dataframe. It must
contain either a geometry column or explicit lat / lng columns.
When social_graph="random" a random geometric graph is generated
automatically; alternatively, pass an edge list to define specific social
connections.
References
.. [PSRPGB2015] Pappalardo, L. et al. (2015). Returners and Explorers dichotomy in human mobility. Nature Communications, 6, 8166. .. [PSR2016] Pappalardo, L., Simini, F. & Rinzivillo, S. (2016). Human Mobility Modelling: exploration and preferential return meet the gravity model. Procedia Computer Science, 83. .. [SKWB2010] Song, C., Koren, T., Wang, P. & Barabási, A.-L. (2010). Modelling the scaling properties of human mobility. Nature Physics, 6, 818–823. .. [THSG2015] Toole, J. et al. (2015). Coupling Human Mobility and Social Ties. Journal of the Royal Society Interface, 12, 20141128.
See Also
EPR, SpatialEPR, Ditras, STS_epr
generate(start_date, end_date, spatial_tessellation, social_graph='random', n_agents=500, dt_update_mobSim=24 * 7, indipendency_window=0.5, random_state=None)
Simulate a socially connected population from start_date to end_date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
Timestamp or datetime
|
Start time of the simulation. |
required |
end_date
|
Timestamp or datetime
|
End time of the simulation. |
required |
spatial_tessellation
|
DataFrame or GeoDataFrame
|
Division of the territory into locations. Must include either a
|
required |
social_graph
|
``"random"`` or list of (uid, uid) tuples
|
Social network for the simulated agents.
The default is |
'random'
|
n_agents
|
int
|
Number of agents when |
500
|
dt_update_mobSim
|
float
|
Interval in hours between social-graph mobility-similarity updates.
The default is |
24 * 7
|
indipendency_window
|
float
|
Time window in hours that must elapse before an agent's move can affect
other agents' social choices. The default is |
0.5
|
random_state
|
int or None
|
Random seed for reproducibility. The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Synthetic trajectories with columns |
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
TypeError
|
If |
Worked example: Social ties
STS_epr
STS-EPR (Spatial, Temporal, and Social EPR) trajectory generator.
STS-EPR extends GeoSim by incorporating a temporal diary (via
MarkovDiaryGenerator) and a gravity-weighted individual exploration
mechanism [CRP2020]. Each agent follows a pre-generated mobility diary that
dictates when to move (home vs. away), while the social and EPR mechanisms
determine where to go.
Action selection. With probability
\(P_{\text{exp}} = \rho S^{-\gamma}\) the agent explores a new location;
otherwise it returns. With probability \(\alpha\) a social contact influences
the destination (Social); with probability \(1 - \alpha\) the agent acts
alone (Individual). Diary entries with abstract_location == 0 always force a
return to the home location.
Individual Exploration. An unvisited location \(j \neq i\) is selected with probability proportional to the gravity score:
where \(r_{i(j)}\) is location relevance and \(d_{ij}\) is the Haversine distance.
Social Exploration. A social contact \(c\) is selected with probability proportional to cosine mobility similarity. A location from \(\text{exp}(a) \cap \text{ret}(c)\) is chosen proportionally to \(c\)'s visitation frequency.
Individual Return. A previously visited location \(j \in \text{ret}(a)\) is chosen with probability \(\Pi_j = f_j\).
Social Return. As in Social Exploration, but from \(\text{ret}(a) \cap \text{ret}(c)\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Human-readable label. The default is |
'STS-EPR'
|
rho
|
float
|
Exploration parameter \(\rho \in (0, 1]\). The default is |
0.6
|
gamma
|
float
|
Return-penalty exponent \(\gamma \geq 0\). The default is |
0.21
|
alpha
|
float
|
Social influence probability \(\alpha \in [0, 1]\). The default is
|
0.2
|
Attributes:
| Name | Type | Description |
|---|---|---|
name |
str
|
Human-readable label of this model instance. |
rho |
float
|
The exploration parameter \(\rho\). |
gamma |
float
|
The return-penalty exponent \(\gamma\). |
alpha |
float
|
The social influence probability \(\alpha\). |
Notes
spatial_tessellation must contain at least 3 tiles and a relevance column.
The MarkovDiaryGenerator must be fitted before being passed to
generate.
References
.. [PSRPGB2015] Pappalardo, L. et al. (2015). Returners and Explorers dichotomy in human mobility. Nature Communications, 6, 8166. .. [PSR2016] Pappalardo, L., Simini, F. & Rinzivillo, S. (2016). Human Mobility Modelling: exploration and preferential return meet the gravity model. Procedia Computer Science, 83. .. [SKWB2010] Song, C., Koren, T., Wang, P. & Barabási, A.-L. (2010). Modelling the scaling properties of human mobility. Nature Physics, 6, 818–823. .. [THSG2015] Toole, J. et al. (2015). Coupling Human Mobility and Social Ties. Journal of the Royal Society Interface, 12, 20141128. .. [CRP2020] Cornacchia, G., Rossetti, G. & Pappalardo, L. (2020). Modelling Human Mobility considering Spatial, Temporal and Social Dimensions. .. [PS2018] Pappalardo, L. & Simini, F. (2018). Data-driven generation of spatio-temporal routines in human mobility. Data Mining and Knowledge Discovery, 32, 787–829.
See Also
GeoSim, Ditras, MarkovDiaryGenerator
generate(start_date, end_date, spatial_tessellation, diary_generator, social_graph='random', n_agents=500, rsl=False, distance_matrix=None, relevance_column=None, min_relevance=0.1, dt_update_mobSim=24 * 7, indipendency_window=0.5, random_state=None)
Simulate a socially connected population from start_date to end_date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
start_date
|
Timestamp or datetime
|
Start time of the simulation. |
required |
end_date
|
Timestamp or datetime
|
End time of the simulation. |
required |
spatial_tessellation
|
DataFrame or GeoDataFrame
|
Division of the territory into locations. Must include either a
|
required |
diary_generator
|
MarkovDiaryGenerator
|
A fitted |
required |
social_graph
|
``"random"`` or list of (uid, uid) tuples
|
Social network for the agents.
The default is |
'random'
|
n_agents
|
int
|
Number of agents when |
500
|
rsl
|
bool
|
If |
False
|
distance_matrix
|
ndarray or None
|
Pre-computed |
None
|
relevance_column
|
str or None
|
Name of the column in |
None
|
min_relevance
|
float
|
Value substituted for any zero-relevance location to avoid division by
zero. The default is |
0.1
|
dt_update_mobSim
|
float
|
Interval in hours between social-graph mobility-similarity updates.
The default is |
24 * 7
|
indipendency_window
|
float
|
Time window in hours before an agent's move can influence others.
The default is |
0.5
|
random_state
|
int or None
|
Random seed for reproducibility. The default is |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Synthetic trajectories with columns |
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If |
IndexError
|
If |
Worked example: Social ties
Next-location prediction
NextLocationPredictor
Order-k Markov next-location predictor with optional backoff.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
order
|
int
|
Markov chain order: number of most-recent locations used as
context. |
1
|
backoff
|
bool
|
When an exact order- |
True
|
Examples:
>>> import pandas as pd
>>> from fastmob.models import NextLocationPredictor
>>> df = pd.DataFrame({
... "uid": ["u1"] * 6,
... "location_id": ["A", "B", "C", "A", "B", "C"],
... "started_at": pd.date_range("2020-01-01", periods=6, freq="h"),
... })
>>> model = NextLocationPredictor(order=1).fit(df)
>>> model.predict()["location_id"].tolist()
['A']
evaluate(top_k=1, n_holdout=1)
Holdout-last-n_holdout accuracy over the data given to fit.
For each user with more than n_holdout observations, walks
forward through the held-out tail one step at a time: at each step,
fits a model on every prior observation (train portion plus any
already-revealed holdout steps -- never the true value being
predicted) and checks whether the true next location is among the
top-top_k predictions. Accuracy is averaged over every
(user, step) pair across every user and step.
This evaluates directly against fit's own input rather than
a separate held-out dataframe, since fastmob's Staypoints/
Locations pipeline already produces one canonical per-user
location sequence -- there is no second, independently-loaded test
sequence to compare against in the common case.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
top_k
|
int
|
Number of ranked candidates checked per prediction. Default |
1
|
n_holdout
|
int
|
Number of most-recent observations per user to hold out and
evaluate against. Users with |
1
|
Returns:
| Type | Description |
|---|---|
float
|
Fraction of (user, holdout step) pairs where the true next
location was among the top- |
fit(traj, location_col=None, uid_col=None, started_at_col=None)
Fit one Markov model per user from each user's location-id sequence.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
dataframe or Staypoints
|
Source data; any Narwhals-compatible eager backend, or a
|
required |
location_col
|
str
|
Column holding each row's location identifier. Auto-detected when None. |
None
|
uid_col
|
str
|
User-ID column. Auto-detected when None; when absent, the whole frame is treated as one user. |
None
|
started_at_col
|
str
|
Datetime column to sort each user's sequence by. When None,
rows are assumed already in chronological order per user
(matching |
None
|
Returns:
| Type | Description |
|---|---|
NextLocationPredictor
|
|
predict(top_k=1)
Predict each fitted user's single most likely next location.
Returns:
| Type | Description |
|---|---|
DataFrame
|
One row per user: columns |
predict_proba(top_k=1)
Predict each fitted user's next location(s) from their own training history's tail.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
top_k
|
int
|
Number of ranked candidates to return per user. Default |
1
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
One row per |
Worked example: Predict the next place