Catalog PyPI
Back to packageRELEASE DETAILS

0.4.0

PyPI

activitymodel

Occupant activity calendars from the French time-use survey: diary library, census matching, annual calendars

Published14 Oct 2026
Direct dependencies11
Transitive dependenciesNot calculated

README

Version 0.4.0 documentation

activitymodel

Occupant activity calendars for building energy simulation, built from the French time-use survey (INSEE Enquête Emploi du temps 2009-2010, PROGEDO-ADISP doi:10.13144/lil-0695).

activitymodel is a pure library: it never resolves a data path at import time and never fetches data. It is used by three packages at three moments:

momentwho imports itwhat it does
dataset build (Snakemake, maintainers)buildingdata pipelineactivitymodel.pipeline.build_library turns the ADISP delivery into a diary library (four parquet tables) that buildingdata uploads to GCS
census dataset buildbuildingdata pipeline / buildingmodelharmonise_census_individuals puts INSEE RP indcvi individuals in the same vocabulary the library was built with
simulationbuilding_eloadassign_clusters + generate_calendar turn the occupants of a district into a year of 10-minute activity codes per occupant

It replaces the two prototypes activity_clustering and activity-occupant-association; doc/design.md records what was wrong with them and why each part looks the way it does now.

Quick start

import polars as pl
import activitymodel as am

# 1. (pipeline) build the library from the survey files, once
from activitymodel.pipeline import LibraryBuildOptions, build_library
library = build_library("/data/edt2010", LibraryBuildOptions())
library.write("/data/buildingdata_pipeline/processed/activity_library")

# 2. (anywhere) load it back - buildingdata will serve the four tables
library = am.DiaryLibrary.read("/data/buildingdata_pipeline/processed/activity_library")

# 3. (simulation) harmonise census occupants and generate a year
occupants = am.harmonise_census_individuals(pl.read_parquet("indcvi_slice.parquet"))
occupants = occupants.with_row_index("occupant_id")
calendar = am.generate_calendar(library, occupants, year=2024, seed=42)

calendar.day_index.shape        # (n_occupants, 366)  int32 pointers into the day pool
codes = calendar.codes(0, 500)  # (500, 52704) uint8, detailed activities, Europe/Paris clock
long = calendar.to_long(0, 500) # occupant-major polars frame with an Enum activity column
python -m activitymodel.pipeline /data/edt2010 out/ --weekday 16 --saturday 10 --sunday 10

What is in the box

activitymodel/
  taxonomy.py      the 24 detailed activities, their ACTPR codes, the coarser levels
                   (presence = building_eload's, macro, mid)
  vocabulary.py    shared socio-demographic categories, age bands, matching ladder
  harmonise.py     survey individuals / census individuals -> shared vocabulary
  survey/          read the ADISP files, code the diaries (location and day-kind aware)
  clustering.py    one-hot + PCA + Ward (or weighted k-means), k-selection curves
  library.py       DiaryLibrary: the published dataset, its schema and validation
  matching.py      occupants -> (cluster_weekday, cluster_saturday, cluster_sunday)
  calendar.py      day sampling, French public holidays, AnnualCalendar
  diagnostics/     activity profiles, matrix distances, association scores,
                   hold-out validation of the matching against the uniform pool
  pipeline.py      build_library() and the command line
  tests/           synthetic fixtures; `-m integration` runs on the real files
doc/
  design.md            gap analysis of the prototypes and the decisions taken
  dataset_contract.md  the four tables, their columns, dtypes and invariants
  integration.md       what changes in buildingdata, buildingmodel,
                       buildingcalibration and building_eload, in order
  integration/         reference snippets for those changes

Measured on the real data (Paris, RP 2021, library 16/10/10 clusters)

stepresult
library build (26,056 diaries, Ward on 50 components)29 s wall
assign_clusters on 663,781 occupants1.3 s; 95.3 % (weighted) matched at the finest level
generate_calendar for 20,105 occupants, 20241.6 s, 28 MiB of day_index
codes() for 500 occupant-years25 MiB, 0.01 s
total-variation distance, matched Paris weekday profile vs national weighted survey0.048

Install

uv venv --python 3.12 .venv
uv pip install -e ".[dev,survey,fast]"
.venv/bin/python -m pytest -q

Extras: survey (pandas, to read the Stata delivery), fast (fastcluster), analysis (scikit-learn, matplotlib), dev.

Licence and data

Code: MIT. The survey is available on request from PROGEDO-ADISP and is not redistributable; the diary library holds no survey row (days are detached from people, people are aggregated into cells of at least five respondents). See doc/dataset_contract.md.

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 13

Native requirements
11 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
numpy
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
numpy>=1.24runtime
polars
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
polars!=1.43.0,!=1.44.0,>=1.0runtime
pyarrow
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
pyarrow>=14.0runtime
scipy
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
scipy>=1.10runtime
pandas
Environment
{
  "extras": "",
  "marker": "extra == \"survey\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
pandas>=2.0; extra == "survey"runtime
fastcluster
Environment
{
  "extras": "",
  "marker": "extra == \"fast\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
fastcluster>=1.2; extra == "fast"runtime
scikit-learn
Environment
{
  "extras": "",
  "marker": "extra == \"analysis\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
scikit-learn>=1.3; extra == "analysis"runtime
matplotlib
Environment
{
  "extras": "",
  "marker": "extra == \"analysis\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
matplotlib>=3.7; extra == "analysis"runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest>=8.0; extra == "dev"runtime
pytest-cov
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest-cov; extra == "dev"runtime
ruff
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
ruff; extra == "dev"runtime
pandas
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
pandas>=2.0; extra == "dev"runtime
fastcluster
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": "<4.0.0,>=3.10",
  "evaluation": "NOT_EVALUATED"
}
fastcluster>=1.2; extra == "dev"runtime

Distribution files

1 collected
activitymodel-0.4.0-py3-none-any.whl

bdist_wheel · 54.09 KB · Python py3

Source file

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 18:37 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:cfd1c05c7b00919007c2eeb311f072fdba6bc29c6b7cd05e8ea41fbc14f5c1ed

Other collected versions

View all collected versions →