# Creating your own pdf#

A core feature of zfit is the ability to create custom pdfs and functions in an simple and straightforward way.

There are two main possibilities to create a custom pdf, an easier for most use-cases and an advanced way..

## The simple way#

While the same works for functions, an example with a PDF is shown here

```
import numpy as np
import zfit
from zfit import z
```

```
/home/docs/checkouts/readthedocs.org/user_builds/zfit/envs/latest/lib/python3.8/site-packages/zfit/__init__.py:62: UserWarning: TensorFlow warnings are by default suppressed by zfit. In order to show them, set the environment variable ZFIT_DISABLE_TF_WARNINGS=0. In order to suppress the TensorFlow warnings AND this warning, set ZFIT_DISABLE_TF_WARNINGS=1.
warnings.warn(
```

```
/home/docs/checkouts/readthedocs.org/user_builds/zfit/envs/latest/lib/python3.8/site-packages/tensorflow_addons/utils/ensure_tf_install.py:53: UserWarning: Tensorflow Addons supports using Python ops for all Tensorflow versions above or equal to 2.8.0 and strictly below 2.11.0 (nightly versions are not supported).
The versions of TensorFlow you are currently using is 2.11.0 and is not supported.
Some things might work, some things might not.
If you were to encounter a bug, do not file an issue.
If you want to make sure you're using a tested and supported configuration, either change the TensorFlow version or the TensorFlow Addons's version.
You can find the compatibility matrix in TensorFlow Addon's readme:
https://github.com/tensorflow/addons
warnings.warn(
```

```
class MyGauss(zfit.pdf.ZPDF):
_N_OBS = 1 # dimension, can be omitted
_PARAMS = ['mean', 'std'] # the name of the parameters
def _unnormalized_pdf(self, x):
x = z.unstack_x(x) # returns a list with the columns: do x, y, z = z.unstack_x(x) for 3D
mean = self.params['mean']
std = self.params['std']
return z.exp(- ((x - mean)/std)**2)
```

Done. Now we can use our pdf already!

```
obs = zfit.Space('obs1', limits=(-3, 6))
data_np = np.random.random(size=1000)
data = zfit.data.Data.from_numpy(array=data_np, obs=obs)
```

Create two parameters and an instance of your own pdf

```
mean = zfit.Parameter("mean", 1.)
std = zfit.Parameter("std", 1.)
my_gauss = MyGauss(obs=obs, mean=mean, std=std)
```

```
probs = my_gauss.pdf(data)
```

```
probs_np = zfit.run(probs)
print(probs_np[:20])
```

```
[0.2603526 0.22185739 0.53765694 0.55440227 0.23965349 0.56418128
0.23270662 0.441085 0.38860562 0.56175658 0.38245255 0.56244126
0.52882103 0.47512278 0.5580549 0.56405825 0.39417902 0.29292409
0.31678946 0.23429832]
```

```
```

We could improve our PDF by registering an integral

```
def gauss_integral_from_any_to_any(limits, params, model):
lower, upper = limits.limit1d
mean = params['mean']
std = params['std']
# write your integral here
return 42. # dummy integral, must be a scalar!
```

```
limits = zfit.Space(axes=0, limits=(zfit.Space.ANY_LOWER, zfit.Space.ANY_UPPER))
MyGauss.register_analytic_integral(func=gauss_integral_from_any_to_any, limits=limits)
```

### n-dimensional#

## Advanced Custom PDF#

Subclass BasePDF. The `_unnormalized_pdf`

has to be overriden and, in addition, the `__init__`

.

Any of the public main methods (`pdf`

, `integrate`

, `partial_integrate`

etc.) can **always** be overriden by implementing the function with a leading underscore, e.g. implement `_pdf`

to directly controls `pdf`

, the API is the same as the public function without the name. In case, during execution of your own method, it is found to be a bad idea to have overridden the default methods, throwing a `NotImplementedError`

will restore the default behavior.

```
# TOBEDONE
```