# Orakel

Orakel is a small Python library of regression models based on NumPy and Scipy.

## Purpose

The analysis and evaluation of experimental data are often influenced by artefacts or signal noise. Yet, the observed processes can often be described by mathematical models. Orakel provides implementations of various regression models that are suited for analysing enzyme kinetics and biological processes, such as bacterial growth.

## Use

Orakel is intended to be used within a script or processing pipeline.

The following functions are implemented:

- `exponential_decay`: exponential decay with optional non-zero asymptote (controlled by boolean flag `non_zero_asymptote`)
- `double_exponential_decay`: double exponential decay with optional non-zero asymptote (controlled by boolean flag `non_zero_asymptote`)
- `gompertz`: Gompertz' generalised logistic function
- `richards`: Richards generalised logistic function
- `michaelis_menten`: the Michaelis-Menten function
- `schnell_mendoza`: explicit form of the Michaelis-Menten equation using Lambert's W function
-  `power_function`: the power function

For modelling and predictions based on these functions, all except the Schnell-Mendoza function can be used within the class `NonlinearRegression`. The Schnell-Mendoza function is not implemented as fitting-class, as its numerical complexity makes it particularly difficult to find suitable model parameters automatically without tight constraints.

After initialising the class (set `non_zero_asymptote=True`, to allow for exponential decays with non-zero asymptote), the model is fitted using `fit(x, y)`. Predictions with the fitted model are made using `predict(x_new)`. As an example, a model for exponential decay is fitted and used for predictions:

```python
import numpy as np

from orakel.predict import exponential_decay, NonlinearRegression

x = np.linspace(0, 3)
y_true = exponential_decay(x, 1, 1.5)

rng = np.random.default_rng()
noise = rng.normal(0, .05, y_true.shape)
y_sample = y_true + noise

model = NonlinearRegression('exponential_decay')
model.fit(x, y_sample)
y_pred = model.predict(x)
```

While the array for the independent variable must be one-dimensional, the dependent variable can be of shape (n_samples, n_points). The array returned by predict is always of this shape.

## Further information

Orakel is primarily the product of personal interest and an attempt to document findings. For this reason, it cannot be considered stable. However, if you find it helpful, you are welcome to use it.
