all functions format for func

all functions format for func#

In modeldag, there are 4 different funtional forms that are accepted as input of the func parameter:

model = {'a': {'func': func, 'kwargs': dict, 'as': None_str_list'},
         'b': {'func': func, 'kwargs': dict, 'as': None_str_list'}
         }

It is also flexible on where the function can be defined (see below #Function locations)

For each of them, ModelDag.draw() will know how to fill the dataframe columns.

Functional form#

Random variate

these func accept size as input and return a 1d-array of size size. The returned array is the random variable you drew.

Transformation

these func takes a variable as input and returns a same-size variable. modeldag has no drawing to do, just accept the new function as input.

1d-pdf

these func accept xx but not size and tt returns two variable: xx shape (M) and pdf shape (M,). modeldag will draw``N=size`` variables from xx using pdf as weight.

2d-pdf

these func accept xx but not size and tt returns two variable: xx shape (M) and pdf shape (size, M). modeldag will draw N=1 variable from xx for each of pdf entries, making this N=size variable.

Here are some examples

import modeldag
import numpy as np

# your own function (here a random draw)
def func_rvs(size, coef=1, low=0, high=np.pi):
    """ the quadratic sum between value*scale and floor """
    values = np.random.uniform(size=size)
    return np.cos(values)

# model construction | a and b are independent
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": func_rvs,
              "kwargs": {}}
        }

# create the DAG
dag = modeldag.ModelDAG(model)
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)
_images/func_random.png
import modeldag
import numpy as np

# your own function (here a deterministic transformation)
def func_transformation(value, scale=0.05, floor=0.2):
    """ the quadratic sum between value*scale and floor """
    return np.sqrt( (value*scale)**2 + floor**2)

# model construction | b predictibly depends on a
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": func_transformation,
              "kwargs": {"value":"@a"}}
        }

# create the DAG
dag = modeldag.ModelDAG(model)
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)
_images/func_transformation.png
import modeldag
import numpy as np
from scipy import stats

# your own function (here a 1d PDF)
def func_1dpdf(mean=2, scale=2, xx="-5:10:0.05"):
    """ a PDF with parameters that depends on an input variable-array

    model: $pdf_2d = N(mean*power, scale)$

    Returns
    -------
    list
        - xx: shape M
        - pdf: shape (size==len(mean), M)
    """
    xx = eval(f"np.r_[{xx}]")
    pdf_ = stats.norm.pdf(xx, loc=mean, scale=scale)
    return xx, pdf_ # shapes: M, (M,)

# model construction | a and b are independent
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": func_1dpdf,
              "kwargs": {"mean":2}
             }
        }

# create the DAG
dag = modeldag.ModelDAG(model)
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)
_images/func_1dpdf.png
import modeldag
import numpy as np
from scipy import stats

# your own function (here a 2d PDF)
def func_2dpdf(mean, power=1, scale=2, xx="-5:10:0.05"):
    """ a PDF with parameters that depends on an input variable-array

    model: $pdf_2d = N(mean*power, scale)$

    Returns
    -------
    list
        - xx: shape M
        - pdf: shape (size==len(mean), M)
    """
    xx = eval(f"np.r_[{xx}]")
    mean = np.atleast_2d(mean).T
    pdf_ = stats.norm.pdf(xx, loc=mean*power, scale=scale)
    return xx, pdf_ # shapes: M, (len(mean), M)

# model construction | b depends on a
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": func_2dpdf,
              "kwargs": {"mean":"@a", "power":10}
              }
        }

# create the DAG
dag = modeldag.ModelDAG(model)
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)
_images/func_2dpdf.png

Function locations#

ModelDag accepts obj= as input. This way you can define use any method from your input object as a model func. If so, pass it a a string in the model definition. The string format can also be used for any function from the namespace. Otherwise, simply directly provide the function itself. All with work the same. Remark that the namespace is checked prior the object.

import modeldag
import numpy as np

# your function
def foo(value, scale=0.03, floor=0.2):
    return np.sqrt( (value*scale)**2 + floor**2)

# model construction | foo already defined
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": foo,
              "kwargs": {"value":"@a"}
              }
        }

# create the DAG
dag = modeldag.ModelDAG(model)
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)
import modeldag
import numpy as np

# model construction | string for any func in your namespace
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": "np.random.uniform", # string
              "kwargs": {"low":0, "high":1}
              }
        }

# create the DAG
dag = modeldag.ModelDAG(model)
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)
import modeldag
import numpy as np

# Define a class
class MyClass():

    def __init__(self, floor=0.2):
        """ """
        self.floor = floor

    def foo_from_class(self, value, scale=0.03):
        """ """
        return np.sqrt( (value*scale)**2 + self.floor**2)

# model construction | string for any method in the input object
model = {"a": {"func": np.random.uniform,
              "kwargs": {"low":0, "high":1}
              },
        "b": {"func": "foo_from_class", # as string
              "kwargs": {"value":"@a"}
              }
        }

# create the DAG, while inputing a class or class instance.
dag = modeldag.ModelDAG(model, obj=MyClass(floor=0.2) )
data = dag.draw(1_000)
_ = data.plot.scatter("a","b", s=1)