Examples#
A simple example#
To understand what dags does, let’s look at a few functions that do simple calculations.
def f(x, y):
return x**2 + y**2
def g(y, z):
return 0.5 * y * z
def h(f, g):
return g / f
Combine with a single target#
Assume that we are interested in a function that calculates h, given x, y and z.
We could hardcode this function as:
def hardcoded_combined(x, y, z):
_f = f(x, y)
_g = g(y, z)
return h(_f, _g)
hardcoded_combined(x=1, y=2, z=3)
0.6
Instead, we can use dags to construct the same function:
from dags import concatenate_functions
combined = concatenate_functions([h, f, g], targets="h")
combined(x=1, y=2, z=3)
0.6
Importantly, the order in which the functions are passed into concatenate_functions
does not matter!
Combine with multiple targets#
Assume that we want the same combined h function as before but we also need intermediate outputs. And we would like to have them as a dictionary. We can do this as follows:
combined = concatenate_functions(
[h, f, g],
targets=["h", "f", "g"],
return_type="dict",
)
combined(x=1, y=2, z=3)
{"h": 0.6, "f": 5, "g": 3.0}
Renaming the output of a function#
So far, the name of the output of the function was determined from the __name__
attribute of each function. This is not enough if you want to use dags to create
functions with exchangeable parts. Let’s assume we have two implementations of f
and want to create combined functions for both versions.
import numpy as np
def f_standard(x, y):
return x**2 + y**2
def f_numpy(x, y):
return np.square(x) + np.square(y)
We can do that as follows:
combined_standard = concatenate_functions(
{"f": f_standard, "g": g, "h": h},
targets="h",
)
combined_numpy = concatenate_functions(
{"f": f_numpy, "g": g, "h": h},
targets="h",
)
In fact, this ability to switch out components was the primary reason we wrote dags. This functionality has, for example, been used in GETTSIM, a framework to simulate reforms to the German tax and transfer system.
Renaming the input of functions#
Sometimes, we want to re-use a general function inside dags, but the arguments of that function don’t have the correct names. For example, we might have a general implementation that we could re-use for f:
def sum_of_squares(a, b):
return a**2 + b**2
Instead of writing a wrapper like:
def f(x, y):
return sum_of_squares(a=x, b=y)
We can simply rename the arguments programmatically:
from dags.signature import rename_arguments
functions = {
"f": rename_arguments(sum_of_squares, mapper={"a": "x", "b": "y"}),
"g": g,
"h": h,
}
combined = concatenate_functions(functions, targets="h")
combined(x=1, y=2, z=3)
0.6