Dubious is a Python library for propagating uncertainty through numerical computations
Project description
Dubious
Dubious is a Python library for propagating uncertainty through numerical computations. Instead of collapsing uncertain values into single numbers early, Dubious lets you represent values as probability distributions, combine them with normal arithmetic operations, and only evaluate the resulting uncertainty when you ask for it.
from dubious import Normal, Beta, Uncertain, Context
normal = Normal(5, 4)
normal2 = Normal(10,2)
x = Uncertain(normal) + Uncertain(normal2)
print(f"variance: {x.var()} mean: {x.mean()} q(0.05): {x.quantile(0.05)}")
Rounded output: variance: 19.9, mean: 15, q(0.05): 7.7
The core idea behind Dubious is lazy uncertainty propagation. We build a graph of operations applied to uncertain values, and traverse it upon sampling. You can construct complex expressions from uncertain inputs in a simple and readable manner, and evaluate the result using Monte Carlo simulations.
By default, distributions are assumed to be independent. We can correlate two uncertain objects using a.corr(b,rho), implemented via Gaussian copula (see notes for details).
After applying any numerical operations to Uncertain objects, sampling and evaluation only occur when calling a function like mean(), quantile() or sample() is called.
Full documentation can be found at: https://dubious.readthedocs.io/en/latest/api/modules.html
Installation
With python v3.9+ pip install dubious
Caveats
- If several instances of the same
Uncertainobject are involved in an operation these are assumed to represent the same variable so the samples used to calculate these values for each will be identical. - Correlation between Uncertain objects is currently implemented using Gaussian Copula. This rank based correlation and the rho value used to correlate different objects is NOT the same as the pearson coefficient. Copula based correlation is accurate across most of the distribution, but in the 99th and 1st percentiles we underestimate by about 3%. This under-estimation continues to grow further into the tails.
- RNG can be controlled via
Sampler()objects, these can be constructed using either a seed, or asubstratum.Generator()object and passed into any function that uses MC sampling methods. Alternitvely, you can call freeze on a context object to ensure the same samples are used for subsequent methods.
Classes
Distribution():
Currently supporting Normal, LogNormal, Beta and Uniform distributions. Distribution objects also support using other distribution objects for their parameters, although this may lead to unexpected behaviour in cases where parameters can become negative. These cases currently throw a warning and are clamped to 1e-06, but the onus is on the user to ensure that input distributions will provide statistically correct results.
For each you distribution can get mean(), var(), quantile, cdf() and sample().
Uncertain():
Uncertain objects are the wrapper for distributions that allow them to be used like numeric values. Alongside being able to perform numeric operations on these uncertain objects, they support the same properties as standard distributions (mean, variance, sampling and quantile). You can apply the exact same operations on these objects you might apply to real data, and easily calculate the propagated uncertainty that comes from using several unreliable input values.
To ensure the same output after repeated calls, Uncertain objects support freeze() and unfreeze(), although this only freezes a single Uncertain object. It is recommended to instead freeze the entire context for truly deterministic results.
Get a summary of metrics via summary() or check input sensitivity via sensitivity(). local_sensitivity() allows you to pass a dict of uncertain objects and corresponding values, returning the sensitivity at that specific neighbourhood within the sample space.
Context():
Context objects own the graph through which we track computations. You can add uncertain objects from different contexts, but be aware that this creates a new context in the process. To avoid this, create all new uncertain objects with ctx = Your context object. You can also easily get a reference to a newly created Context via ctx = my_uncertain_object.ctx.
Context objects also support freeze() and unfreeze(), freezing results through context objects is recommended for most cases.
Some examples:
from dubious.distributions import Normal
from dubious import Uncertain, Context
ctx = Context()
length_dist = Normal(10, 1)
length = Uncertain(length_dist, ctx=ctx)
width_dist = Normal(5, 0.5)
width = Uncertain(width_dist, ctx=ctx)
#Compute area uncertainty using normal arithmetic
area = length * width
print("Mean area:", area.mean())
print("Variance:", area.var())
print("Some samples:", area.sample(5))
We can also use distribution and uncertain objects as parameters.
from dubious.distributions import Normal, Beta
from dubious import Uncertain, Context
ctx = Context()
#We can define distribution parameters with other distributions.
normal = Normal(10, 1)
beta = Beta(3,normal)
x = Uncertain(normal, ctx=ctx)
y = Uncertain(beta, ctx=ctx)
x = x*y
print(x.sample(5))
#We can also use uncertain objects to define parameters.
normal3 = Normal(y+2, 3)
print(normal3.mean())
An example of correlation:
#two non-Gaussian marginals correlated using copula
from dubious.distributions import Beta, LogNormal
from dubious import Uncertain, Context
ctx = Context()
conv = Uncertain(Beta(20,80), ctx=ctx)
traffic = Uncertain(LogNormal(8.0,0.4), ctx=ctx)
conv.corr(traffic, 0.7)
sales = conv * traffic
print(f"Mean: {sales.mean()}")
print(f"p10, p90: {sales.quantile(0.1)}, {sales.quantile(0.9)}")
Mean: 685.30,
p10, p90: 282.88, 1185.69
Correlated uncertainty propagation currently matches a Gaussian-copula reference to within ~0.25% relative error on tail quantiles. See benchmarks/cor_benchmark.py
0.4.1
Internal changes only.
0.4
Added
- Local sensitivity function shows the sensitivty at a specifed region within the sample space.
- Draw and float methods. Uncertain objects can now be used like floats, calling redraw on the context will cycle to the next value else the same random value will be used.
- Median method for uncertain objects.
- Gamma Distribution
Changed
- When frozen, Monte Carlo methods will default to the value of n the node / context was frozen at. Previously the different defaults for mean var etc. would error unless n was specified manually to be the same value of n frozen with.
- Changed from numpy to ironforest as the libraries back end.
0.3
Added
- Added correlation via Gaussian Copula
- Added
freeze()andunfreeze()functions to uncertain and context objects. They will ensure the same set of samples is used for all function calls while frozen. Context freezing is recommended in most cases as it freezes every random node in the graph as well as constants. Freezing uncertain objects individually will lead to semi-random behaviour that isn't as useful in most cases. - Benchmarks and additional testing
- Documentation now on https://dubious.readthedocs.io/
Changed
- Changed import structure. Instead of everything living in the main name space, we have core, distributions and umath.
- Seeds defaulted to 0 which meant that everything was deterministic by default. We now default as random and only when a seed or rng object is provided are outputs deterministic.
Fixed
0.2
Added
- Context objects now handle graph ownership and can be merged, e.g. Uncertain objects from different contexts can be used together.
- Uncertain objects and Distributions now inherit from Sampleable and can both be used as input parameters
- Added log, sin, cos, tan, asin, acos and atan operations for Uncertain objects in umath. Umath functions also support normal numbers.
Fixed
- Some functions had inconsistent requirements regarding numpy generators. Now all do not require one but give the option of either providing one or a seed.
0.1.1
Fixed
- 0.1 release had a major bug making most uncertain methods unusable on other machines... oops
0.1
- First release
Added
Distribution objects
- Normal,
- LogNormal
- Uniform
- Beta
- Support for using distribution objects as params
- Uncertain objects
- Standard arithmetic through dunder methods
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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dubious-0.4.1.tar.gz.
File metadata
- Download URL: dubious-0.4.1.tar.gz
- Upload date:
- Size: 22.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef513a30f2ccee2fa4d3ee00f2bc30e56f38e1e77677fe118086540a54f95b74
|
|
| MD5 |
ed6b760ec9b91991d187842136b35ab0
|
|
| BLAKE2b-256 |
58b9888f5d321ad5d9642088f5aa998d77d51681fb24359e58af2b2867817c22
|
Provenance
The following attestation bundles were made for dubious-0.4.1.tar.gz:
Publisher:
publish.yml on Flynn500/dubious
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dubious-0.4.1.tar.gz -
Subject digest:
ef513a30f2ccee2fa4d3ee00f2bc30e56f38e1e77677fe118086540a54f95b74 - Sigstore transparency entry: 983862412
- Sigstore integration time:
-
Permalink:
Flynn500/dubious@073c63cd6b87351fe117cd3d413a5f241fc36a94 -
Branch / Tag:
- Owner: https://github.com/Flynn500
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@073c63cd6b87351fe117cd3d413a5f241fc36a94 -
Trigger Event:
release
-
Statement type:
File details
Details for the file dubious-0.4.1-py3-none-any.whl.
File metadata
- Download URL: dubious-0.4.1-py3-none-any.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9c2a9e90f31c29880ef2f9b044553e57d8670258b7fa13f7ab06cd3b97cc7a6
|
|
| MD5 |
7eedd0b549282093eb686a0414c81182
|
|
| BLAKE2b-256 |
6cb8a5a32a2d3e3be6eca80265bfe5bcf83c9c7e68432f75843be9cc049c3a34
|
Provenance
The following attestation bundles were made for dubious-0.4.1-py3-none-any.whl:
Publisher:
publish.yml on Flynn500/dubious
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dubious-0.4.1-py3-none-any.whl -
Subject digest:
b9c2a9e90f31c29880ef2f9b044553e57d8670258b7fa13f7ab06cd3b97cc7a6 - Sigstore transparency entry: 983862413
- Sigstore integration time:
-
Permalink:
Flynn500/dubious@073c63cd6b87351fe117cd3d413a5f241fc36a94 -
Branch / Tag:
- Owner: https://github.com/Flynn500
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@073c63cd6b87351fe117cd3d413a5f241fc36a94 -
Trigger Event:
release
-
Statement type: