Skip to main content

Library for parameter processing and validation with a focus on computational modeling projects

Project description

ParamTools

Define, update, and validate your model's parameters.

Install using pip:

pip install paramtools

Install using conda:

conda install -c conda-forge paramtools

Usage

Subclass paramtools.Parameters and define your model's parameters:

import paramtools


class Params(paramtools.Parameters):
    defaults = {
        "schema": {
            "labels": {
                "date": {
                    "type": "date",
                    "validators": {
                        "range": {
                            "min": "2020-01-01",
                            "max": "2021-01-01",
                            "step": {"months": 1}
                        }
                    }
                }
            },
        },
        "a": {
            "title": "A",
            "type": "int",
            "value": [
                {"date": "2020-01-01", "value": 2},
                {"date": "2020-10-01", "value": 8},
            ],
            "validators": {
                "range" : {
                    "min": 0, "max": "b"
                }
            }
        },
        "b": {
            "title": "B",
            "type": "float",
            "value": [{"date": "2020-01-01", "value": 10.5}]
        }
    }

Access parameter values

Access values using .sel:

params = Params()

params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 2},
  {'date': datetime.date(2020, 10, 1), 'value': 8},
])

Look up parameter values using a pandas-like api:

from datetime import date

result = params.sel["a"]["date"] == date(2020, 1, 1)
result
QueryResult([
  {'date': datetime.date(2020, 1, 1), 'value': 2}
])
result.isel[0]["value"]
2

Adjust and validate parameter values

Add a new value:

params.adjust({"a": [{"date": "2020-11-01", "value": 22}]})

params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 2},
  {'date': datetime.date(2020, 10, 1), 'value': 8},
  {'date': datetime.date(2020, 11, 1), 'value': 22},
])

Update an existing value:

params.adjust({"a": [{"date": "2020-01-01", "value": 3}]})

params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 3},
  {'date': datetime.date(2020, 10, 1), 'value': 8},
  {'date': datetime.date(2020, 11, 1), 'value': 22},
])

Update all values:

params.adjust({"a": 7})

params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 7},
  {'date': datetime.date(2020, 10, 1), 'value': 7},
  {'date': datetime.date(2020, 11, 1), 'value': 7},
])

Errors on values that are out of range:

params.adjust({"a": -1})
---------------------------------------------------------------------------

ValidationError                           Traceback (most recent call last)

<ipython-input-8-f8f1b7f6cd9a> in <module>
----> 1 params.adjust({"a": -1})


~/Paramtools/paramtools/parameters.py in adjust(self, params_or_path, ignore_warnings, raise_errors, extend_adj, clobber)
    253             least one existing value item's corresponding label values.
    254         """
--> 255         return self._adjust(
    256             params_or_path,
    257             ignore_warnings=ignore_warnings,


~/Paramtools/paramtools/parameters.py in _adjust(self, params_or_path, ignore_warnings, raise_errors, extend_adj, is_deserialized, clobber)
    371             not ignore_warnings and has_warnings
    372         ):
--> 373             raise self.validation_error
    374
    375         # Update attrs for params that were adjusted.


ValidationError: {
    "errors": {
        "a": [
            "a -1 < min 0 "
        ]
    }
}
params = Params()

params.adjust({"a": [{"date": "2020-01-01", "value": 11}]})
---------------------------------------------------------------------------

ValidationError                           Traceback (most recent call last)

<ipython-input-9-cc8a21f044d8> in <module>
      1 params = Params()
      2
----> 3 params.adjust({"a": [{"date": "2020-01-01", "value": 11}]})


~/Paramtools/paramtools/parameters.py in adjust(self, params_or_path, ignore_warnings, raise_errors, extend_adj, clobber)
    253             least one existing value item's corresponding label values.
    254         """
--> 255         return self._adjust(
    256             params_or_path,
    257             ignore_warnings=ignore_warnings,


~/Paramtools/paramtools/parameters.py in _adjust(self, params_or_path, ignore_warnings, raise_errors, extend_adj, is_deserialized, clobber)
    371             not ignore_warnings and has_warnings
    372         ):
--> 373             raise self.validation_error
    374
    375         # Update attrs for params that were adjusted.


ValidationError: {
    "errors": {
        "a": [
            "a[date=2020-01-01] 11 > max 10.5 b[date=2020-01-01]"
        ]
    }
}

Errors on invalid values:

params = Params()

params.adjust({"b": "abc"})
---------------------------------------------------------------------------

ValidationError                           Traceback (most recent call last)

<ipython-input-10-8373a2715e38> in <module>
      1 params = Params()
      2
----> 3 params.adjust({"b": "abc"})


~/Paramtools/paramtools/parameters.py in adjust(self, params_or_path, ignore_warnings, raise_errors, extend_adj, clobber)
    253             least one existing value item's corresponding label values.
    254         """
--> 255         return self._adjust(
    256             params_or_path,
    257             ignore_warnings=ignore_warnings,


~/Paramtools/paramtools/parameters.py in _adjust(self, params_or_path, ignore_warnings, raise_errors, extend_adj, is_deserialized, clobber)
    371             not ignore_warnings and has_warnings
    372         ):
--> 373             raise self.validation_error
    374
    375         # Update attrs for params that were adjusted.


ValidationError: {
    "errors": {
        "b": [
            "Not a valid number: abc."
        ]
    }
}

Extend parameter values using label definitions

Extend values using label_to_extend:

params = Params(label_to_extend="date")
params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 2},
  {'date': datetime.date(2020, 2, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 3, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 4, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 5, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 6, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 7, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 8, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 9, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 10, 1), 'value': 8},
  {'date': datetime.date(2020, 11, 1), 'value': 8, '_auto': True},
  {'date': datetime.date(2020, 12, 1), 'value': 8, '_auto': True},
  {'date': datetime.date(2021, 1, 1), 'value': 8, '_auto': True},
])

Updates to values are carried through to future dates:

params.adjust({"a": [{"date": "2020-4-01", "value": 9}]})

params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 2},
  {'date': datetime.date(2020, 2, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 3, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 4, 1), 'value': 9},
  {'date': datetime.date(2020, 5, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 6, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 7, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 8, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 9, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 10, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 11, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 12, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2021, 1, 1), 'value': 9, '_auto': True},
])

Use clobber to only update values that were set automatically:

params = Params(label_to_extend="date")
params.adjust(
    {"a": [{"date": "2020-4-01", "value": 9}]},
    clobber=False,
)

# Sort parameter values by date for nicer output
params.sort_values()
params.sel["a"]
Values([
  {'date': datetime.date(2020, 1, 1), 'value': 2},
  {'date': datetime.date(2020, 2, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 3, 1), 'value': 2, '_auto': True},
  {'date': datetime.date(2020, 4, 1), 'value': 9},
  {'date': datetime.date(2020, 5, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 6, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 7, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 8, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 9, 1), 'value': 9, '_auto': True},
  {'date': datetime.date(2020, 10, 1), 'value': 8},
  {'date': datetime.date(2020, 11, 1), 'value': 8, '_auto': True},
  {'date': datetime.date(2020, 12, 1), 'value': 8, '_auto': True},
  {'date': datetime.date(2021, 1, 1), 'value': 8, '_auto': True},
])

NumPy integration

Access values as NumPy arrays with array_first:

params = Params(label_to_extend="date", array_first=True)

params.a
array([2, 2, 2, 2, 2, 2, 2, 2, 2, 8, 8, 8, 8])
params.a * params.b
array([21., 21., 21., 21., 21., 21., 21., 21., 21., 84., 84., 84., 84.])

Only get the values that you want:

arr = params.to_array("a", date=["2020-01-01", "2020-11-01"])
arr
array([2, 8])

Go back to a list of dictionaries:

params.from_array("a", arr, date=["2020-01-01", "2020-11-01"])
[{'date': datetime.date(2020, 1, 1), 'value': 2},
 {'date': datetime.date(2020, 11, 1), 'value': 8}]

Documentation

Full documentation available at paramtools.dev.

Contributing

Contributions are welcome! Checkout CONTRIBUTING.md to get started.

Credits

ParamTools is built on top of the excellent marshmallow JSON schema and validation framework. I encourage everyone to check out their repo and documentation. ParamTools was modeled off of Tax-Calculator's parameter processing and validation engine due to its maturity and sophisticated capabilities.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

paramtools-0.20.0.tar.gz (52.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

paramtools-0.20.0-py3-none-any.whl (57.4 kB view details)

Uploaded Python 3

File details

Details for the file paramtools-0.20.0.tar.gz.

File metadata

  • Download URL: paramtools-0.20.0.tar.gz
  • Upload date:
  • Size: 52.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for paramtools-0.20.0.tar.gz
Algorithm Hash digest
SHA256 5ab1413d2ab77b63681525021b1a469144c8236ab8ec90161e87ea3b59027225
MD5 34da9c928e58a39a5590e3f183e735f6
BLAKE2b-256 1f602ca610c8711ea03cdee99df5c8008e5362c1428873f1d4db1f890b7ff672

See more details on using hashes here.

File details

Details for the file paramtools-0.20.0-py3-none-any.whl.

File metadata

  • Download URL: paramtools-0.20.0-py3-none-any.whl
  • Upload date:
  • Size: 57.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.3

File hashes

Hashes for paramtools-0.20.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3b79b80c5dae6c1340eb827ed4d34014e68a98403acea9ba549497ec4b6d80a0
MD5 faca67b6a38ea268142e96763e0168b3
BLAKE2b-256 cbe9fe4fcbcf8a2dffb6bdae9a5c307e31d327a4269d035978e56c0d49db2152

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page