Individual Measures
| API | Description |
|---|---|
distance_straight_line |
Return the total trajectory length (km) for each user. |
frequency_rank |
Return the frequency rank of each distinct location for every user. |
home_location |
Return the most-visited nighttime location for each user. |
individual_mobility_network |
Return the individual mobility network as a directed edge-list DataFrame. |
jump_lengths |
Compute jump lengths (km) for each user in the trajectory. |
k_radius_of_gyration |
Compute the k-radius of gyration (km) for each user in the trajectory. |
location_frequency |
Return visit frequency for each distinct location per user. |
max_distance_from_home |
Return the maximum Haversine distance (km) from each user's home location. |
maximum_distance |
Return the maximum distance (km) covered in a single movement for each user. |
number_of_locations |
Return the number of distinct locations visited by each user. |
number_of_visits |
Return the total number of trajectory points (visits) for each user. |
radius_of_gyration |
Compute the radius of gyration (km) for each user in the trajectory. |
random_entropy |
Return the random entropy of mobility for each user. |
real_entropy |
Return the real (true) entropy of mobility for each user. |
recency_rank |
Return the recency rank of each distinct location for every user. |
uncorrelated_entropy |
Return the uncorrelated entropy of mobility for each user. |
waiting_times |
Return the waiting times (seconds) between consecutive GPS fixes for each user. |
activity_transition_matrix |
Compute the activity transition matrix for a visits DataFrame. |
daily_activity_distribution |
Compute a daily activity distribution matrix over fixed time bins. |
visit_purpose_distribution |
Compute visit-purpose counts and percentages. |
regularity |
Compute regularity per user. |
diversity |
Compute trajectory diversity per user using suffix-array entropy. |
trajectory_entropy |
Compute Kontoyiannis entropy of mobility trajectories per user. |
trajectory_predictability |
Compute per-user maximum predictability via Fano's inequality. |
discover_daily_motifs_from_agents |
Discover daily mobility motifs for all agents in a dataset. |
distance_straight_line(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the total trajectory length (km) for each user.
The distance straight line \(d_{SL}\) travelled by an individual \(u\) is the sum of Haversine distances between consecutive GPS fixes in the time-ordered trajectory [WTDED2015]_:
where \(n_u\) is the number of recorded points for \(u\), \(r_j\) is the \(j\)-th point as a \((lat, lng)\) pair, and \(dist\) is the Haversine distance between two points.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and ordered by datetime within each user, then use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import distance_straight_line
>>> result = distance_straight_line(df)
>>> print(result.round({"distance_straight_line": 3}).head().to_string(index=False))
uid distance_straight_line
0 374531.472
1 774347.886
2 86036.423
References
- [WTDED2015] Williams, N. E., Thomas, T. A., Dunbar, M., Eagle, N. & Dobra, A. (2015) Measures of Human Mobility Using Mobile Phone Records Enhanced with GIS Data. PLOS ONE 10(7): e0133630. https://doi.org/10.1371/journal.pone.0133630
See Also
jump_lengths : Individual jump distances between consecutive points. maximum_distance : Largest single jump length per user.
frequency_rank(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the frequency rank of each distinct location for every user.
The frequency rank K_f(r_i) of location r_i is 1 if it is the
most frequently visited location, 2 if it is the second-most frequently
visited, and so on. Ties in visit count are broken by the order they
appear after sorting (stable), matching the skmob reference implementation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import frequency_rank
>>> result = frequency_rank(df)
>>> print(result.head().to_string(index=False))
uid lat lng frequency_rank
0 39.762146 -104.982480 1
0 39.891077 -105.068532 2
0 39.739154 -104.984703 3
0 39.891586 -105.068463 4
0 39.827022 -105.143191 5
References
- [BDEM2015] Barbosa, H., de Lima-Neto, F. B., Evsukoff, A., Menezes, R. (2015) The effect of recency to human mobility, EPJ Data Science 4(21), https://epjdatascience.springeropen.com/articles/10.1140/epjds/s13688-015-0059-8
home_location(traj, *, start_night=22, end_night=7, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the most-visited nighttime location for each user.
The home location \(h(u)\) of an individual \(u\) is the location
visited most often during the nighttime window
[start_night, 24) ∪ [0, end_night) [CBTDHVSB2012] [PSO2012]:
where \(r_i\) is a location visited by \(u\), \(t(r_i)\) is the time of the visit, and \(t_{\text{start}}\) / \(t_{\text{end}}\) bound the nighttime window. When a user has no nighttime records, the most-visited location across all hours is used as a fallback.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
start_night
|
int
|
Hour (0–23) at which the nighttime window begins. Default: 22. |
22
|
end_night
|
int
|
Hour (0–23) at which the nighttime window ends (exclusive). Default: 7. |
7
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import home_location
>>> result = home_location(df)
>>> print(result.round({"lat": 3, "lng": 3}).head().to_string(index=False))
uid lat lng
0 39.891 -105.069
1 37.630 -122.411
2 39.739 -104.985
References
- [CBTDHVSB2012] Csaji, B. C., Browet, A., Traag, V. A., Delvenne, J.-C., Huens, E., Van Dooren, P., Smoreda, Z. & Blondel, V. D. (2012) Exploring the Mobility of Mobile Phone Users. Physica A: Statistical Mechanics and its Applications 392(6), 1459-1473, https://www.sciencedirect.com/science/article/pii/S0378437112010059
- [PSO2012] Phithakkitnukoon, S., Smoreda, Z. & Olivier, P. (2012) Socio-geography of human mobility: A study using longitudinal mobile phone data. PLOS ONE 7(6): e39253. https://doi.org/10.1371/journal.pone.0039253
See Also
max_distance_from_home : Maximum distance from the inferred home location.
individual_mobility_network(traj, *, self_loops=False, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the individual mobility network as a directed edge-list DataFrame.
An Individual Mobility Network (IMN) of an individual \(u\) is a directed weighted graph \(G_u = (V, E)\) where \(V\) is the set of distinct visited locations and \(E\) is the set of directed trips between locations [RGNPPG2014] [BL2012] [SQBB2010]_. The edge weight function
returns the number of times \(u\) travelled that edge.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
self_loops
|
bool
|
When |
False
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and ordered by datetime within each user, then use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per directed edge with columns
|
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import individual_mobility_network
>>> result = individual_mobility_network(df)
>>> print(result.round({"lat_origin": 3, "lng_origin": 3, "lat_dest": 3, "lng_dest": 3}).head().to_string(index=False))
uid lat_origin lng_origin lat_dest lng_dest n_trips
0 37.775 -122.419 37.601 -122.382 1
0 37.601 -122.382 37.615 -122.390 1
0 37.615 -122.390 39.879 -104.682 1
0 39.879 -104.682 39.739 -104.985 1
0 39.739 -104.985 39.762 -104.982 19
References
- [RGNPPG2014] Rinzivillo, S., Gabrielli, L., Nanni, M., Pappalardo, L., Pedreschi, D. & Giannotti, F. (2012) The purpose of motion: Learning activities from Individual Mobility Networks. Proceedings of the 2014 IEEE International Conference on Data Science and Advanced Analytics, 312-318, https://ieeexplore.ieee.org/document/7058090
- [BL2012] Bagrow, J. P. & Lin, Y.-R. (2012) Mesoscopic Structure and Social Aspects of Human Mobility. PLOS ONE 7(5): e37676. https://doi.org/10.1371/journal.pone.0037676
- [SQBB2010] Song, C., Qu, Z., Blumm, N. & Barabasi, A. L. (2010) Limits of Predictability in Human Mobility. Science 327(5968), 1018-1021, https://science.sciencemag.org/content/327/5968/1018
jump_lengths(traj, merge=False, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Compute jump lengths (km) for each user in the trajectory.
A jump length is the Haversine distance (in km) between consecutive GPS fixes for the same user, sorted by datetime.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory data; any Narwhals-compatible eager dataframe (pandas, polars, …). Must have columns for datetime, latitude, and longitude. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
merge
|
bool
|
When True, return flat jump lengths across all users using a backend-appropriate array object. When False (default), return a per-user dataframe. |
False
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and ordered by datetime within each user, then use the presorted contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame or array - like
|
When |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import jump_lengths
>>> result = jump_lengths(df)
>>> preview = result.assign(n_jumps=result["jump_lengths"].str.len())
>>> print(preview[["uid", "n_jumps"]].head().to_string(index=False))
uid n_jumps
0 2098
1 1209
2 1690
References
- [BHG2006] Brockmann, D., Hufnagel, L. & Geisel, T. (2006) The scaling laws of human travel. Nature 439, 462-465, https://www.nature.com/articles/nature04292
- [GHB2008] Gonzalez, M. C., Hidalgo, C. A. & Barabasi, A. L. (2008) Understanding individual human mobility patterns. Nature, 453, 779-782, https://www.nature.com/articles/nature06958.
- [PRQPG2013] Pappalardo, L., Rinzivillo, S., Qu, Z., Pedreschi, D. & Giannotti, F. (2013) Understanding the patterns of car travel. European Physics Journal Special Topics 215(1), 61-73, https://link.springer.com/article/10.1140%2Fepjst%2Fe2013-01715-5
See Also
maximum_distance : Largest single jump length per user. distance_straight_line : Sum of all jump lengths per user.
k_radius_of_gyration(traj, k=2, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Compute the k-radius of gyration (km) for each user in the trajectory.
The k-radius of gyration is the radius of gyration computed using only the k most-visited locations for each user. Formally:
where \(r_\mathrm{cm}\) is the weighted center of mass over the top-k locations and \(w_i\) is the visit count of location \(i\).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory data; any Narwhals-compatible eager dataframe (pandas, polars, ...). Must have columns for datetime, latitude, and longitude. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
k
|
int
|
Number of most-visited locations to consider. Defaults to 2. Valid range: \([2, +\infty)\). |
2
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import k_radius_of_gyration
>>> result = k_radius_of_gyration(df, k=2)
>>> print(result.round({"k_radius_of_gyration": 3}).head().to_string(index=False))
uid k_radius_of_gyration
0 7.859
1 4.069
2 5.794
References
- [PSRPGB2015] Pappalardo, L., Simini, F. Rinzivillo, S., Pedreschi, D. Giannotti, F. & Barabasi, A. L. (2015) Returners and Explorers dichotomy in human mobility. Nature Communications 6, https://www.nature.com/articles/ncomms9166
See Also
radius_of_gyration : Radius of gyration over all visited locations.
location_frequency(traj, normalize=True, as_ranks=False, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return visit frequency for each distinct location per user.
The visitation frequency \(f(r_i)\) of location \(r_i\) for individual \(u\) is the probability of visiting that location [SKWB2010] [PF2018]:
where \(n(r_i)\) is the number of visits to location \(r_i\) by
\(u\), and \(n_u\) is the total number of data points in
\(u\)'s trajectory. When normalize=False, raw visit counts
\(n(r_i)\) are returned instead.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
normalize
|
bool
|
When |
True
|
as_ranks
|
bool
|
When |
False
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame or list
|
When |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import location_frequency
>>> result = location_frequency(df)
>>> print(result.round({"location_frequency": 3}).head().to_string(index=False))
uid lat lng location_frequency
0 39.762146 -104.982480 0.102
0 39.891077 -105.068532 0.065
0 39.739154 -104.984703 0.060
0 39.891586 -105.068463 0.034
0 39.827022 -105.143191 0.025
References
- [SKWB2010] Song, C., Koren, T., Wang, P. & Barabasi, A.L. (2010) Modelling the scaling properties of human mobility. Nature Physics 6, 818-823, https://www.nature.com/articles/nphys1760
- [PF2018] Pappalardo, L. & Simini, F. (2018) Data-driven generation of spatio-temporal routines in human mobility. Data Mining and Knowledge Discovery 32, 787-829, https://link.springer.com/article/10.1007/s10618-017-0548-4
See Also
frequency_rank : Rank locations by visit frequency (1 = most visited). visits_per_location : Total visits per location across all users (collective measure).
max_distance_from_home(traj, *, start_night=22, end_night=7, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the maximum Haversine distance (km) from each user's home location.
The maximum distance from home \(dh_{max}(u)\) of an individual \(u\) is defined as [CM2015]_:
where \(n_u\) is the number of recorded points for \(u\),
\(r_i\) is a location as a \((lat, lng)\) pair, \(h(u)\) is
the home location of \(u\) (see :func:home_location), and
\(dist\) is the Haversine distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
start_night
|
int
|
Hour (0–23) at which the nighttime window begins. Forwarded to
:func: |
22
|
end_night
|
int
|
Hour (0–23) at which the nighttime window ends (exclusive). Forwarded
to :func: |
7
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import max_distance_from_home
>>> result = max_distance_from_home(df)
>>> print(result.round({"max_distance_from_home": 3}).head().to_string(index=False))
uid max_distance_from_home
0 11286.959
1 12800.565
2 11282.764
References
- [CM2015] Canzian, L. & Musolesi, M. (2015) Trajectories of depression: unobtrusive monitoring of depressive states by means of smartphone mobility traces analysis. Proceedings of the 2015 ACM International Joint Conference on Pervasive and Ubiquitous Computing, 1293-1304, https://dl.acm.org/citation.cfm?id=2805845
See Also
home_location : Inferred home location from nighttime visits. maximum_distance : Largest single jump length per user.
maximum_distance(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the maximum distance (km) covered in a single movement for each user.
The maximum distance \(d_{max}\) travelled by an individual \(u\) is the largest Haversine distance between any two consecutive GPS fixes in the time-ordered trajectory [WTDED2015] [LBH2012]:
where \(n_u\) is the number of recorded points for \(u\), \(r_i\) and \(r_{i+1}\) are two consecutive points as \((lat, lng)\) pairs, and \(dist\) is the Haversine distance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and ordered by datetime within each user, then use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import maximum_distance
>>> result = maximum_distance(df)
>>> print(result.round({"maximum_distance": 3}).head().to_string(index=False))
uid maximum_distance
0 11294.452
1 12804.913
2 11286.761
References
- [WTDED2015] Williams, N. E., Thomas, T. A., Dunbar, M., Eagle, N. & Dobra, A. (2015) Measures of Human Mobility Using Mobile Phone Records Enhanced with GIS Data. PLOS ONE 10(7): e0133630. https://doi.org/10.1371/journal.pone.0133630
- [LBH2012] Lu, X., Bengtsson, L. & Holme, P. (2012) Predictability of population displacement after the 2010 haiti earthquake. Proceedings of the National Academy of Sciences 109 (29) 11576-11581; https://doi.org/10.1073/pnas.1203882109
See Also
jump_lengths : All jump distances between consecutive points. distance_straight_line : Sum of all jump lengths per user.
number_of_locations(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the number of distinct locations visited by each user.
A distinct location is a unique exact (lat, lng) pair — matching the
skmob convention of float equality without spatial clustering.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import number_of_locations
>>> result = number_of_locations(df)
>>> print(result.head().to_string(index=False))
uid number_of_locations
0 542
1 97
2 427
References
- [GHB2008] Gonzalez, M. C., Hidalgo, C. A. & Barabasi, A. L. (2008) Understanding individual human mobility patterns. Nature, 453, 779-782, https://www.nature.com/articles/nature06958.
number_of_visits(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the total number of trajectory points (visits) for each user.
A "visit" is defined as one row in the trajectory dataframe after null
removal. The result is the row count per user — identical to the skmob
number_of_visits individual measure.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import number_of_visits
>>> result = number_of_visits(df)
>>> print(result.head().to_string(index=False))
uid number_of_visits
0 2099
1 1210
2 1691
radius_of_gyration(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Compute the radius of gyration (km) for each user in the trajectory.
The radius of gyration captures how far a user typically roams from their center of mass. Formally:
where \(r_\mathrm{cm}\) is the arithmetic mean of the user's lat/lng coordinates.
Radius of gyration is order-independent, so chronological sorting is not required for correctness; grouping rows by user is what matters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory data; any Narwhals-compatible eager dataframe (pandas, polars, …). Must have columns for datetime, latitude, and longitude. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import radius_of_gyration
>>> result = radius_of_gyration(df)
>>> print(result.round({"radius_of_gyration": 3}).head().to_string(index=False))
uid radius_of_gyration
0 1564.439
1 2467.777
2 1600.452
References
- [GHB2008] Gonzalez, M. C., Hidalgo, C. A. & Barabasi, A. L. (2008) Understanding individual human mobility patterns. Nature, 453, 779-782, https://www.nature.com/articles/nature06958.
- [PRQPG2013] Pappalardo, L., Rinzivillo, S., Qu, Z., Pedreschi, D. & Giannotti, F. (2013) Understanding the patterns of car travel. European Physics Journal Special Topics 215(1), 61-73, https://link.springer.com/article/10.1140%2Fepjst%2Fe2013-01715-5
See Also
k_radius_of_gyration : Radius of gyration restricted to the k most-visited locations.
random_entropy(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None)
Return the random entropy of mobility for each user.
Random entropy is defined as \(\log_2(n)\), where \(n\) is the number of
distinct locations visited by the user. A location is a unique exact
(lat, lng) pair — matching the skmob convention (float equality,
no spatial clustering).
This is the maximum possible entropy for a user who visits \(n\) distinct places, assuming all locations are equally likely.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import random_entropy
>>> result = random_entropy(df)
>>> print(result.round({"random_entropy": 3}).head().to_string(index=False))
uid random_entropy
0 9.082
1 6.600
2 8.738
References
- [EP2009] Eagle, N. & Pentland, A. S. (2009) Eigenbehaviors: identifying structure in routine. Behavioral Ecology and Sociobiology 63(7), 1057-1066, https://link.springer.com/article/10.1007/s00265-009-0830-6
- [SQBB2010] Song, C., Qu, Z., Blumm, N. & Barabasi, A. L. (2010) Limits of Predictability in Human Mobility. Science 327(5968), 1018-1021, https://science.sciencemag.org/content/327/5968/1018
See Also
uncorrelated_entropy : Entropy weighted by visit frequency (ignores temporal order). real_entropy : Entropy that captures temporal order and frequency of visits.
Real entropy of individual mobility trajectories (Kontoyiannis estimator).
real_entropy(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None)
Return the real (true) entropy of mobility for each user.
Real entropy is estimated using the Kontoyiannis (1998) Lempel-Ziv
entropy rate estimator applied to the sequence of visited locations.
Each location is encoded as the exact (lat, lng) float pair using
bitwise equality — matching the skmob convention (no spatial clustering).
The estimator captures both the frequency and the order of visits, unlike random entropy (which ignores order) and uncorrelated entropy (which ignores temporal correlations).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import real_entropy
>>> result = real_entropy(df)
>>> print(result.round({"real_entropy": 3}).head().to_string(index=False))
uid real_entropy
0 4.905
1 2.200
2 4.683
References
- [SQBB2010] Song, C., Qu, Z., Blumm, N. & Barabasi, A. L. (2010) Limits of Predictability in Human Mobility. Science 327(5968), 1018-1021, https://science.sciencemag.org/content/327/5968/1018
See Also
random_entropy : Maximum possible entropy assuming uniform visitation. uncorrelated_entropy : Entropy weighted by visit frequency (ignores temporal order).
recency_rank(traj, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the recency rank of each distinct location for every user.
The recency rank K_s(r_i) of location r_i is 1 if it is the most
recently visited location, 2 if it is the second-most recently visited, and
so on. Ties (multiple visits to the same (lat, lng) pair) are resolved
by keeping only the latest visit for each location before ranking.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and ordered by datetime within each user, then use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import recency_rank
>>> result = recency_rank(df)
>>> print(result.head().to_string(index=False))
uid lat lng recency_rank
0 39.891383 -105.070814 1
0 39.891077 -105.068532 2
0 39.750469 -104.999073 3
0 39.752713 -104.996337 4
0 39.752508 -104.996637 5
References
- [BDEM2015] Barbosa, H., de Lima-Neto, F. B., Evsukoff, A., Menezes, R. (2015) The effect of recency to human mobility, EPJ Data Science 4(21), https://epjdatascience.springeropen.com/articles/10.1140/epjds/s13688-015-0059-8
uncorrelated_entropy(traj, *, normalize=False, datetime_col=None, lat_col=None, lng_col=None, uid_col=None)
Return the uncorrelated entropy of mobility for each user.
Uncorrelated entropy is the Shannon entropy over the distribution of visit probabilities across distinct locations:
where \(p_i\) is the fraction of visits to location \(i\) out of the
user's total visits. A location is a unique exact (lat, lng) pair.
When normalize=True the result is divided by \(\log_2(n)\) (the
random entropy) so the output lies in [0, 1]. If the user visits
only one distinct location the entropy is 0; dividing by 0 is avoided
by returning 0 directly.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
normalize
|
bool
|
When True, divide the Shannon entropy by \(\log_2(n_\mathrm{distinct})\)
to normalise into |
False
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import uncorrelated_entropy
>>> result = uncorrelated_entropy(df)
>>> print(result.round({"uncorrelated_entropy": 3}).head().to_string(index=False))
uid uncorrelated_entropy
0 7.442
1 3.650
2 6.908
References
- [EP2009] Eagle, N. & Pentland, A. S. (2009) Eigenbehaviors: identifying structure in routine. Behavioral Ecology and Sociobiology 63(7), 1057-1066, https://link.springer.com/article/10.1007/s00265-009-0830-6
- [SQBB2010] Song, C., Qu, Z., Blumm, N. & Barabasi, A. L. (2010) Limits of Predictability in Human Mobility. Science 327(5968), 1018-1021, https://science.sciencemag.org/content/327/5968/1018
- [PVGSPG2016] Pappalardo, L., Vanhoof, M., Gabrielli, L., Smoreda, Z., Pedreschi, D. & Giannotti, F. (2016) An analytical framework to nowcast well-being using mobile phone data. International Journal of Data Science and Analytics 2(75), 75-92, https://link.springer.com/article/10.1007/s41060-016-0013-2
See Also
random_entropy : Maximum possible entropy assuming uniform visitation. real_entropy : Entropy that captures temporal order and frequency of visits.
waiting_times(traj, merge=False, *, datetime_col=None, lat_col=None, lng_col=None, uid_col=None, presorted=False)
Return the waiting times (seconds) between consecutive GPS fixes for each user.
A waiting time (or inter-time) \(\Delta t\) is the elapsed time between two consecutive trajectory points of individual \(u\) [SKWB2010] [PF2018]:
where \(r_i\) and \(r_{i+1}\) are two consecutive points in the time-ordered trajectory and \(t(r)\) is the time when \(u\) visited point \(r\). Users with fewer than 2 points receive an empty list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
traj
|
DataFrame - like
|
Trajectory dataframe; any Narwhals-compatible eager backend (pandas, polars, …). Must have datetime, latitude, and longitude columns. A user-ID column is optional; when absent the whole frame is treated as a single individual. |
required |
merge
|
bool
|
When |
False
|
datetime_col
|
str or None
|
Explicit datetime column name. Auto-detected when None. |
None
|
lat_col
|
str or None
|
Explicit latitude column name. Auto-detected when None. |
None
|
lng_col
|
str or None
|
Explicit longitude column name. Auto-detected when None. |
None
|
uid_col
|
str or None
|
Explicit user-ID column name. Auto-detected when None. |
None
|
presorted
|
bool
|
When True, trust that rows are already grouped by user and ordered by datetime within each user, then use the contiguous fast path. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame or array - like
|
When |
Examples:
>>> import pandas as pd
>>> import fastmob
>>> url = fastmob.utils.constants.BRIGHTKITE_SAMPLE
>>> df = pd.read_csv(
... url,
... sep="\t",
... header=0,
... nrows=5000,
... names=["uid", "datetime", "lat", "lng", "location id"],
... )
>>> df["datetime"] = pd.to_datetime(df["datetime"], errors="coerce")
>>> df["location_id"] = df["location id"].astype("string")
>>> df = df.dropna(subset=["uid", "datetime", "lat", "lng"])[
... ["uid", "datetime", "lat", "lng", "location_id"]
... ]
>>> print(df.head().to_string(index=False))
uid datetime lat lng location_id
0 2010-10-16 06:02:04+00:00 39.891383 -105.070814 7a0f88982aa015062b95e3b4843f9ca2
0 2010-10-16 03:48:54+00:00 39.891077 -105.068532 dd7cd3d264c2d063832db506fba8bf79
0 2010-10-14 18:25:51+00:00 39.750469 -104.999073 9848afcc62e500a01cf6fbf24b797732f8963683
0 2010-10-14 00:21:47+00:00 39.752713 -104.996337 2ef143e12038c870038df53e0478cefc
0 2010-10-13 23:31:51+00:00 39.752508 -104.996637 424eb3dd143292f9e013efa00486c907
>>> from fastmob import waiting_times
>>> result = waiting_times(df)
>>> preview = result.assign(n_waiting_times=result["waiting_times"].str.len())
>>> print(preview[["uid", "n_waiting_times"]].head().to_string(index=False))
uid n_waiting_times
0 2098
1 1209
2 1690
References
- [SKWB2010] Song, C., Koren, T., Wang, P. & Barabasi, A.L. (2010) Modelling the scaling properties of human mobility. Nature Physics 6, 818-823, https://www.nature.com/articles/nphys1760
- [PF2018] Pappalardo, L. & Simini, F. (2018) Data-driven generation of spatio-temporal routines in human mobility. Data Mining and Knowledge Discovery 32, 787-829, https://link.springer.com/article/10.1007/s10618-017-0548-4
Compute the activity transition matrix for a visits DataFrame.
Counts how often each activity-type transition (from -> to) occurs across all users, then normalises to percentages. Returns a square DataFrame with activity labels as both index and columns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with at least an activity column and, optionally, a user-ID and timestamp column. |
required |
activity_col
|
str or None
|
Column name for the activity/purpose type. Auto-detected if None. |
None
|
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if None. |
None
|
timestamp_col
|
str or None
|
Column name for the visit timestamp used for sorting. Auto-detected if None (rows are used in their current order when no timestamp is found). |
None
|
day_col
|
str or None
|
Column name for the day-of-week string. Auto-detected if None. |
None
|
day_filter
|
str or None
|
One of |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
Transition matrix as percentages. Pandas inputs return a pandas matrix
with activity labels as index/columns; other backends return a native
dataframe with an |
Raises:
| Type | Description |
|---|---|
ValueError
|
When |
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import activity_transition_matrix
>>> visits = pd.DataFrame(
... {
... "user_id": ["u1", "u1", "u1", "u2", "u2", "u2"],
... "start_timestamp": pd.to_datetime(
... [
... "2020-01-01 08:00",
... "2020-01-01 09:00",
... "2020-01-01 18:00",
... "2020-01-01 07:30",
... "2020-01-01 12:00",
... "2020-01-01 19:00",
... ]
... ),
... "purpose": ["HOME", "WORK", "HOME", "HOME", "SHOP", "HOME"],
... }
... )
>>> result = activity_transition_matrix(visits)
>>> print(result.round(1).to_string())
HOME SHOP WORK
HOME 0.0 25.0 25.0
SHOP 25.0 0.0 0.0
WORK 25.0 0.0 0.0
Compute a daily activity distribution matrix over fixed time bins.
Compute visit-purpose counts and percentages.
Missing activity columns and null activity values are recoverable: the
affected visits are labelled with unknown_label and a warning is emitted.
Compute intermittancy and degree of return per user using vectorized operations.
For each user, partitions the visit sequence into alternating blocks of explorations (new places) and returns (revisits or home/work visits). Then computes summary statistics over those blocks. By default, stay intervals are reconstructed into 5-minute trajectory slices when start and end timestamp columns are available.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with visit rows. |
required |
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if None. |
None
|
location_id_col
|
str or None
|
Column name for the location ID. Auto-detected if None. |
None
|
datetime_col
|
str or None
|
Column name for visit timestamps. Auto-detected if None. Required when
|
None
|
cold_start_strategy
|
str
|
How to initialize "known" places.
|
'frequency'
|
known_suffixes
|
tuple of str
|
Used only when |
('_HOME', '_WORK')
|
use_trajectory
|
bool
|
If True, and both start and end timestamp columns are available, expand
each stay into observed 5-minute slices from |
True
|
impute_gaps
|
bool
|
If True, and trajectory reconstruction is possible, fill missing
5-minute slices between each user's first and last observed slice using
per-user anchors inferred from observed locations: hours 2-5 use the
most frequent nighttime location, hour 10 uses the most frequent
location at 10, and hours 14-16 use the most frequent afternoon
location. Missing slices outside those windows, or inside a window with
no inferred anchor, remain absent. Ignored when |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns
|
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import intermittance_and_degree_of_return
>>> visits = pd.DataFrame(
... {
... "user_id": ["u1", "u1", "u1", "u1", "u2", "u2", "u2"],
... "start_timestamp": pd.to_datetime(
... [
... "2020-01-01 08:00",
... "2020-01-01 09:00",
... "2020-01-01 18:00",
... "2020-01-02 08:00",
... "2020-01-01 07:30",
... "2020-01-01 12:00",
... "2020-01-01 19:00",
... ]
... ),
... "location_id": ["home", "work", "home", "gym", "home", "shop", "home"],
... }
... )
>>> result = intermittance_and_degree_of_return(visits, cold_start_strategy="none")
>>> print(result.round(3).to_string(index=False))
user_id intermittency degree_of_return mean_return mean_exploration
u1 2.5 0.588 1.0 1.5
u2 3.0 0.464 1.0 2.0
Compute intermittency and degree of return, then cluster users into mobility profiles.
Calls :func:intermittance_and_degree_of_return to get per-user statistics, then
applies a Rust clustering kernel on the degree_of_return values to assign each
user to one of three profiles:
- routiners — high degree of return; mostly revisit familiar places.
- regulars — balanced mix of exploration and return.
- scouters — low degree of return; mostly explore new places.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with visit rows. |
required |
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if |
None
|
location_id_col
|
str or None
|
Column name for the location ID. Auto-detected if |
None
|
datetime_col
|
str or None
|
Column name for visit timestamps. Auto-detected if |
None
|
cold_start_strategy
|
str
|
How to initialize known places. Passed directly to
:func: |
'frequency'
|
known_suffixes
|
tuple of str
|
Location ID suffixes treated as known (only used when
|
('_HOME', '_WORK')
|
clustering_method
|
str
|
|
'kmeans'
|
random_seed
|
int
|
Seed for the clustering algorithm — ensures reproducible results. |
42
|
n_iterations
|
int
|
Maximum iterations for the clustering algorithm. |
300
|
impute_gaps
|
bool
|
If True, pass through to :func: |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Raises:
| Type | Description |
|---|---|
ValueError
|
If fewer than 3 users are present (cannot form 3 clusters), or if
an unknown |
ImportError
|
If the compiled |
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import exploration_profiling
>>> rows = []
>>> patterns = {
... "u1": ["a", "b", "c", "d", "a"],
... "u2": ["a", "b", "a", "c", "a", "d"],
... "u3": ["a", "a", "b", "a", "c", "a"],
... "u4": ["a", "b", "c", "a", "b", "c"],
... "u5": ["a", "b", "a", "b", "a", "b"],
... }
>>> for uid, locations in patterns.items():
... for i, location in enumerate(locations):
... rows.append(
... {
... "user_id": uid,
... "start_timestamp": pd.Timestamp("2020-01-01") + pd.Timedelta(hours=i),
... "location_id": location,
... }
... )
>>> visits = pd.DataFrame(rows)
>>> result = exploration_profiling(visits, cold_start_strategy="none", random_seed=7)
>>> print(result.round(3).to_string(index=False))
user_id intermittency degree_of_return mean_return mean_exploration profile
u1 5.000 0.245 1.0 4.000 scouters
u2 2.333 0.644 1.0 1.333 regulars
u3 2.000 0.785 1.0 1.000 regulars
u4 6.000 0.785 3.0 3.000 regulars
u5 6.000 1.107 4.0 2.000 routiners
Regularity measure for visit trajectories.
regularity(visits, user_id_col=None, location_id_col=None, location_type_col=None)
Compute regularity per user.
Regularity measures how repetitively a user visits the same places. It is defined as:
regularity = 1 - (unique_locations / total_visits)
where unique_locations is the count of distinct
(location_id, location_type) pairs (or just distinct location_id
values when location_type_col is None), and total_visits is the
row count for the user.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with visit rows. |
required |
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if None. |
None
|
location_id_col
|
str or None
|
Column name for the location ID. Auto-detected if None. |
None
|
location_type_col
|
str or None
|
Column name for the location type / activity purpose.
Auto-detected if None; set explicitly to |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import regularity
>>> visits = pd.DataFrame(
... {
... "user_id": ["u1", "u1", "u1", "u1", "u2", "u2", "u2"],
... "location_id": ["home", "work", "home", "gym", "home", "shop", "home"],
... }
... )
>>> result = regularity(visits)
>>> print(result.round(3).to_string(index=False))
user_id regularity
u1 0.250
u2 0.333
Low-level suffix-array diversity primitive.
fast_diversity(sequence)
Compute the diversity of a sequence using suffix arrays.
Maps elements to integer codes, builds a suffix array and LCP array via
pydivsufsort, then returns distinct_substrings / total_substrings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sequence
|
iterable
|
An iterable of hashable elements. |
required |
Returns:
| Type | Description |
|---|---|
float
|
A value in |
Raises:
| Type | Description |
|---|---|
ImportError
|
When |
Examples:
Trajectory diversity measure using suffix-array entropy.
diversity(visits, user_id_col=None, location_id_col=None, location_type_col=None)
Compute trajectory diversity per user using suffix-array entropy.
Per-user: factorize the composite location string
(location_id + "_" + location_type when location_type_col is not
None; otherwise just location_id), then call :func:fast_diversity on
the integer codes.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with visit rows. |
required |
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if None. |
None
|
location_id_col
|
str or None
|
Column name for the location ID. Auto-detected if None. |
None
|
location_type_col
|
str or None
|
Column name for the location type / activity purpose.
Auto-detected if None; set explicitly to |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import diversity
>>> visits = pd.DataFrame(
... {
... "user_id": ["u1", "u1", "u1", "u1", "u2", "u2", "u2"],
... "location_id": ["home", "work", "home", "gym", "home", "shop", "home"],
... }
... )
>>> result = diversity(visits)
>>> print(result.round(3).to_string(index=False))
user_id diversity
u1 0.900
u2 0.833
Compute Kontoyiannis entropy of mobility trajectories per user.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with visit rows. |
required |
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if None. |
None
|
location_id_col
|
str or None
|
Column name for the location ID. Auto-detected if None. |
None
|
location_type_col
|
str or None
|
Column name for the location type / activity purpose. Auto-detected
if None; set explicitly to |
None
|
timestamp_col
|
str or None
|
Column name for ordering visits. Auto-detected if None; when no timestamp column is found the row order is preserved. |
None
|
normalized
|
bool
|
When True (default), divide raw entropy by |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns |
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import trajectory_entropy
>>> visits = pd.DataFrame(
... {
... "user_id": ["u1", "u1", "u1", "u1", "u2", "u2", "u2"],
... "start_timestamp": pd.to_datetime(
... [
... "2020-01-01 08:00",
... "2020-01-01 09:00",
... "2020-01-01 18:00",
... "2020-01-02 08:00",
... "2020-01-01 07:30",
... "2020-01-01 12:00",
... "2020-01-01 19:00",
... ]
... ),
... "location_id": ["home", "work", "home", "gym", "home", "shop", "home"],
... }
... )
>>> result = trajectory_entropy(visits)
>>> print(result.round(3).to_string(index=False))
user_id entropy
u1 0.8
u2 1.0
Compute per-user maximum predictability via Fano's inequality.
Follows the Song et al. (2010) approach: estimate real entropy using Kontoyiannis (1998), then solve Fano's inequality for the maximum predictability upper bound.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
visits
|
DataFrame - like
|
A DataFrame (any Narwhals-compatible backend) with visit rows. |
required |
user_id_col
|
str or None
|
Column name for the user ID. Auto-detected if None. |
None
|
location_id_col
|
str or None
|
Column name for the location ID. Auto-detected if None. |
None
|
location_type_col
|
str or None
|
Column name for the location type / activity purpose. Auto-detected
if None; set explicitly to |
None
|
timestamp_col
|
str or None
|
Column name for ordering visits. Auto-detected if None. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame or DataFrame
|
One row per user with columns
|
Examples:
>>> import pandas as pd
>>> from fastmob.measures.individual import trajectory_predictability
>>> visits = pd.DataFrame(
... {
... "user_id": ["u1", "u1", "u1", "u1", "u2", "u2", "u2"],
... "start_timestamp": pd.to_datetime(
... [
... "2020-01-01 08:00",
... "2020-01-01 09:00",
... "2020-01-01 18:00",
... "2020-01-02 08:00",
... "2020-01-01 07:30",
... "2020-01-01 12:00",
... "2020-01-01 19:00",
... ]
... ),
... "location_id": ["home", "work", "home", "gym", "home", "shop", "home"],
... }
... )
>>> result = trajectory_predictability(visits)
>>> print(result.round(3).to_string(index=False))
user_id real_entropy predictability n_unique_locations n_steps
u1 1.600 0.333 3 4
u2 1.585 0.500 2 3
Discover daily mobility motifs for all agents in a dataset.
For each user-day, builds a directed mobility graph (with primary-home forced to node 0) and returns its canonical motif ID. Graph construction and canonicalization run in Rust; users are processed in parallel via Rayon.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
df
|
DataFrame - like
|
Input visits DataFrame (any backend). Must contain at minimum user_id, location_id, purpose, start_timestamp, and end_timestamp columns (or their auto-detected equivalents). |
required |
user_id_col
|
str or None
|
User identifier column. Auto-detected if None. |
None
|
location_id_col
|
str or None
|
Location identifier column. Auto-detected if None. |
None
|
purpose_col
|
str or None
|
Activity purpose column ( |
None
|
timestamp_col
|
str or None
|
Start-time column. Defaults to |
None
|
end_timestamp_col
|
str or None
|
End-time column. Defaults to |
None
|
duration_col
|
str or None
|
Duration column used for primary-home selection. Defaults to
|
None
|
Returns:
| Type | Description |
|---|---|
tuple[DataFrame or DataFrame, DataFrame or DataFrame]
|
daily_motifs_df: one row per user-day with columns
motif_distribution_df: one row per distinct motif with columns
|
Examples:
>>> import pandas as pd
>>> df = pd.DataFrame({
... "agent_id": ["u1", "u1", "u1"],
... "location_id": ["home", "work", "home"],
... "purpose": ["HOME", "WORK", "HOME"],
... "start_timestamp": pd.to_datetime(["2020-01-01 00:00", "2020-01-01 09:00", "2020-01-01 18:00"]),
... "end_timestamp": pd.to_datetime(["2020-01-01 08:00", "2020-01-01 17:00", "2020-01-01 23:00"]),
... })
>>> daily_df, dist_df = discover_daily_motifs_from_agents(df)