Skip to content

fastmob

fastmob logo

fastmob is a high-performance reimplementation of the skmob mobility-analysis library.

It exposes the same measure API but replaces the Python/pandas internals with a Rust extension (via PyO3) for compute-heavy kernels, and wraps the Python layer with Narwhals so any eager dataframe (pandas, polars, …) is accepted as input.

Key Features

  • Backend-agnostic: pass a pandas, polars, or any other Narwhals-compatible DataFrame — fastmob works without changes.

  • Rust-accelerated core: 500x median speedup due to rust parallelized and zero-copy operations.

  • Drop-in API: function signatures mirror the original skmob library so migration is straightforward.

  • Measured validation: correctness tests, Python coverage, profiling, and standalone speed benchmarks make compatibility and performance claims reproducible.

  • Zero-Copy: Fastkit-Mobility process the data where it lives. Instead of copying, it directly access your dataframe in the memory, saving memory and making the processing faster.

  • Lightweight: Python wheels ship compact, release-ready binaries.

Installation

pip install fastmob

Validation and Performance

fastmob is tested as both a compatibility project and a performance project. The correctness suite covers the Python package, exercises pandas and Polars inputs, and includes optional comparisons with skmob where those dependencies are installed. The benchmark suite uses standalone perf-counter scripts on representative mobility workloads, including Brightkite-derived data slices.

Quick Example

import pandas as pd
from fastmob import jump_lengths

df = pd.DataFrame({
    "uid": ["alice", "alice", "alice", "bob", "bob"],
    "datetime": pd.date_range("2020-01-01", periods=5, freq="h"),
    "lat": [41.9, 42.0, 42.1, 40.7, 40.8],
    "lng": [12.5, 12.5, 12.5, -74.0, -74.0],
})

result = jump_lengths(df)
print(result)

Getting Started

Requirements

  • Python >= 3.9
  • Rust toolchain (for building from source)

Install from PyPI

pip install fastmob
uv add fastmob
pip install "fastmob[generation]"

Install for Development (from source)

git clone https://github.com/gefgu/fastmob.git
cd fastmob
bash scripts/setup_env.sh
source .venv/bin/activate
maturin develop
uv sync --extra docs
uv run --extra docs zensical serve
uv run --extra docs zensical build

Development requires uv and a Rust toolchain. After setup the compiled Rust extension (.so) is placed directly in fastmob/, so the package is importable from the repo root without a separate pip install.

Column Name Auto-Detection

fastmob auto-detects required columns by scanning a priority list:

Semantic role Accepted column names (in order)
datetime datetime, check-in_time, timestamp, time
latitude lat, latitude
longitude lng, lon, longitude
user ID (optional) uid, user, user_id

When a user-ID column is absent, the entire dataframe is treated as a single individual.

You can also pass column names explicitly via keyword arguments (datetime_col, lat_col, lng_col, uid_col).

Your First Measure: jump_lengths

import pandas as pd
from fastmob import jump_lengths

# Build a minimal trajectory dataframe
df = pd.DataFrame({
    "uid": ["alice", "alice", "alice"],
    "datetime": pd.date_range("2020-01-01", periods=3, freq="h"),
    "lat": [0.0, 1.0, 2.0],
    "lng": [0.0, 0.0, 0.0],
})

# Compute jump lengths (Haversine distances in km between consecutive points)
result = jump_lengths(df)
print(result)
# uid  jump_lengths
# alice  [111.19..., 111.19...]

Using Polars

fastmob is backend-agnostic. Pass a polars DataFrame and you get a polars DataFrame back:

import polars as pl
from fastmob import jump_lengths

df = pl.DataFrame({
    "uid": ["alice", "alice", "alice"],
    "datetime": ["2020-01-01 00:00:00", "2020-01-01 01:00:00", "2020-01-01 02:00:00"],
    "lat": [0.0, 1.0, 2.0],
    "lng": [0.0, 0.0, 0.0],
}).with_columns(pl.col("datetime").str.to_datetime())

result = jump_lengths(df)  # returns a polars DataFrame

Optional Extras

Extra Installs Used by
ai scikit-learn cluster
fitting scipy fit_values_to_truncated_powerlaw
diversity pydivsufsort diversity measures (future)
generation scipy, powerlaw, statsmodels, python-igraph, tqdm fastmob.models generation APIs
docs mkdocs, mkdocs-material, mkdocstrings[python] documentation build

Install an extra with:

pip install "fastmob[fitting]"
# or with uv:
uv sync --extra fitting

Generation Models

import pandas as pd
from fastmob.models import Gravity, SpatialEPR

tessellation = pd.DataFrame({
    "tile_id": [0, 1, 2],
    "lat": [45.0, 45.1, 45.2],
    "lng": [7.0, 7.1, 7.2],
    "relevance": [5, 6, 7],
    "tot_outflow": [10, 12, 14],
})

flows = Gravity().generate(tessellation, out_format="probabilities")

start = pd.Timestamp("2020-01-01 00:00:00")
end = pd.Timestamp("2020-01-01 06:00:00")
trajectories = SpatialEPR().generate(start, end, tessellation, n_agents=2, random_state=0)