Skip to content

prior

Prior specification helpers.

This module provides helpers for constructing brms-compatible prior specifications and for querying the default priors implied by a model.

Notes

Executed inside the worker process that hosts the embedded R session.

Classes

PriorSpec dataclass

Python representation of a brms prior specification.

This dataclass provides a typed interface to brms::prior_string() arguments, allowing Python developers to specify priors with IDE autocomplete and type checking. Use the prior() factory function to create instances.

Attributes:

Name Type Description
prior str

Prior distribution as string (e.g., "normal(0, 1)", "exponential(2)").

class_ (str, optional)

Parameter class: "b" (fixed effects), "sd" (group SD), "Intercept", "sigma", "cor", etc.

coef (str, optional)

Specific coefficient name for class-level priors.

group (str, optional)

Grouping variable for hierarchical effects.

dpar (str, optional)

Distributional parameter (e.g., "sigma", "phi", "zi").

resp (str, optional)

Response variable for multivariate models.

nlpar (str, optional)

Non-linear parameter name.

lb (float, optional)

Lower bound for truncated priors.

ub (float, optional)

Upper bound for truncated priors.

See Also

prior : Factory function to create PriorSpec instances. brms::prior_string : R documentation

Examples:

Create prior specifications (prefer using prior()):

from brmspy.types import PriorSpec

# Fixed effect prior
p1 = PriorSpec(prior="normal(0, 1)", class_="b")

# Group-level SD prior
p2 = PriorSpec(prior="exponential(2)", class_="sd", group="patient")

# Coefficient-specific prior with bounds
p3 = PriorSpec(prior="normal(0, 1)", class_="b", coef="age", lb=0)
Source code in brmspy/types/brms_results.py
@dataclass(frozen=True)
class PriorSpec:
    """
    Python representation of a brms prior specification.

    This dataclass provides a typed interface to `brms::prior_string()` arguments,
    allowing Python developers to specify priors with IDE autocomplete and type
    checking. Use the [`prior()`][brmspy.brms.prior] factory function to create
    instances.

    Attributes
    ----------
    prior : str
        Prior distribution as string (e.g., ``"normal(0, 1)"``, ``"exponential(2)"``).
    class_ : str, optional
        Parameter class: ``"b"`` (fixed effects), ``"sd"`` (group SD),
        ``"Intercept"``, ``"sigma"``, ``"cor"``, etc.
    coef : str, optional
        Specific coefficient name for class-level priors.
    group : str, optional
        Grouping variable for hierarchical effects.
    dpar : str, optional
        Distributional parameter (e.g., ``"sigma"``, ``"phi"``, ``"zi"``).
    resp : str, optional
        Response variable for multivariate models.
    nlpar : str, optional
        Non-linear parameter name.
    lb : float, optional
        Lower bound for truncated priors.
    ub : float, optional
        Upper bound for truncated priors.

    See Also
    --------
    prior : Factory function to create `PriorSpec` instances.
    brms::prior_string : [R documentation](https://paulbuerkner.com/brms/reference/prior_string.html)

    Examples
    --------
    Create prior specifications (prefer using [`prior()`][brmspy.brms.prior]):

    ```python
    from brmspy.types import PriorSpec

    # Fixed effect prior
    p1 = PriorSpec(prior="normal(0, 1)", class_="b")

    # Group-level SD prior
    p2 = PriorSpec(prior="exponential(2)", class_="sd", group="patient")

    # Coefficient-specific prior with bounds
    p3 = PriorSpec(prior="normal(0, 1)", class_="b", coef="age", lb=0)
    ```
    """

    prior: str
    class_: str | None = None
    coef: str | None = None
    group: str | None = None
    dpar: str | None = None
    resp: str | None = None
    nlpar: str | None = None
    lb: float | None = None
    ub: float | None = None

    def to_brms_kwargs(self) -> dict[str, Any]:
        """
        Convert PriorSpec to keyword arguments for brms::prior_string().

        Maps Python dataclass fields to R function arguments, handling
        the `class_` -> `class` parameter name conversion.

        Returns
        -------
        dict
            Keyword arguments ready for brms::prior_string()

        Examples
        --------
        ```python
        from brmspy import prior
        p = prior("normal(0, 1)", class_="b", coef="age")
        kwargs = p.to_brms_kwargs()
        print(kwargs)
        # {'prior': 'normal(0, 1)', 'class': 'b', 'coef': 'age'}
        ```
        """
        out: dict[str, Any] = {"prior": self.prior}
        if self.class_ is not None:
            out["class"] = self.class_
        if self.coef is not None:
            out["coef"] = self.coef
        if self.group is not None:
            out["group"] = self.group
        if self.dpar is not None:
            out["dpar"] = self.dpar
        if self.resp is not None:
            out["resp"] = self.resp
        if self.nlpar is not None:
            out["nlpar"] = self.nlpar
        if self.lb is not None:
            out["lb"] = self.lb
        if self.ub is not None:
            out["ub"] = self.ub
        return out

Attributes

prior instance-attribute
class_ = None class-attribute instance-attribute
coef = None class-attribute instance-attribute
group = None class-attribute instance-attribute
dpar = None class-attribute instance-attribute
resp = None class-attribute instance-attribute
nlpar = None class-attribute instance-attribute
lb = None class-attribute instance-attribute
ub = None class-attribute instance-attribute

Functions

to_brms_kwargs()

Convert PriorSpec to keyword arguments for brms::prior_string().

Maps Python dataclass fields to R function arguments, handling the class_ -> class parameter name conversion.

Returns:

Type Description
dict

Keyword arguments ready for brms::prior_string()

Examples:

from brmspy import prior
p = prior("normal(0, 1)", class_="b", coef="age")
kwargs = p.to_brms_kwargs()
print(kwargs)
# {'prior': 'normal(0, 1)', 'class': 'b', 'coef': 'age'}
Source code in brmspy/types/brms_results.py
def to_brms_kwargs(self) -> dict[str, Any]:
    """
    Convert PriorSpec to keyword arguments for brms::prior_string().

    Maps Python dataclass fields to R function arguments, handling
    the `class_` -> `class` parameter name conversion.

    Returns
    -------
    dict
        Keyword arguments ready for brms::prior_string()

    Examples
    --------
    ```python
    from brmspy import prior
    p = prior("normal(0, 1)", class_="b", coef="age")
    kwargs = p.to_brms_kwargs()
    print(kwargs)
    # {'prior': 'normal(0, 1)', 'class': 'b', 'coef': 'age'}
    ```
    """
    out: dict[str, Any] = {"prior": self.prior}
    if self.class_ is not None:
        out["class"] = self.class_
    if self.coef is not None:
        out["coef"] = self.coef
    if self.group is not None:
        out["group"] = self.group
    if self.dpar is not None:
        out["dpar"] = self.dpar
    if self.resp is not None:
        out["resp"] = self.resp
    if self.nlpar is not None:
        out["nlpar"] = self.nlpar
    if self.lb is not None:
        out["lb"] = self.lb
    if self.ub is not None:
        out["ub"] = self.ub
    return out
__init__(prior, class_=None, coef=None, group=None, dpar=None, resp=None, nlpar=None, lb=None, ub=None)

RListVectorExtension dataclass

Generic result container with R objects.

Attributes:

Name Type Description
r ListVector

R object from brms

Source code in brmspy/types/brms_results.py
@dataclass
class RListVectorExtension:
    """Generic result container with R objects.

    Attributes
    ----------
    r : robjects.ListVector
        R object from brms
    """

    r: ProxyListSexpVector

Attributes

r instance-attribute

Functions

__init__(r)

FormulaConstruct dataclass

A composite formula expression built from parts.

FormulaConstruct stores a tree of nodes (FormulaPart and/or R objects) representing expressions combined with +. It is primarily created by calling the public formula helpers exposed by brmspy.brms.

Notes

The + operator supports grouping:

  • a + b + c becomes a single summand (one “group”)
  • (a + b) + (a + b) becomes two summands (two “groups”)

Use iter_summands() to iterate over these groups in a deterministic way.

Source code in brmspy/types/formula_dsl.py
@dataclass
class FormulaConstruct:
    """
    A composite formula expression built from parts.

    `FormulaConstruct` stores a tree of nodes (`FormulaPart` and/or R objects)
    representing expressions combined with `+`. It is primarily created by
    calling the public formula helpers exposed by [`brmspy.brms`][brmspy.brms].

    Notes
    -----
    The `+` operator supports grouping:

    - `a + b + c` becomes a single summand (one “group”)
    - `(a + b) + (a + b)` becomes two summands (two “groups”)

    Use [`iter_summands()`][brmspy.types.formula_dsl.FormulaConstruct.iter_summands]
    to iterate over these groups in a deterministic way.
    """

    _parts: list[Node]

    @classmethod
    def _formula_parse(cls, obj: Other) -> "FormulaConstruct":
        """
        Convert a supported value into a `FormulaConstruct`.

        Parameters
        ----------
        obj
            One of: `FormulaConstruct`, `FormulaPart`, string (interpreted as `bf(<string>)`),
            or `ProxyListSexpVector`.

        Returns
        -------
        FormulaConstruct
        """
        if isinstance(obj, FormulaConstruct):
            return obj
        if isinstance(obj, ProxyListSexpVector):
            return FormulaConstruct(_parts=[obj])
        if isinstance(obj, FormulaPart):
            return FormulaConstruct(_parts=[obj])
        if isinstance(obj, str):
            part = FormulaPart(_fun="bf", _args=[obj], _kwargs={})
            return FormulaConstruct(_parts=[part])
        raise TypeError(
            f"Cannot parse object of type {type(obj)!r} into FormulaConstruct"
        )

    def __add__(self, other: Other):
        """
        Combine two formula expressions with `+`.

        Parameters
        ----------
        other
            Value to add. Strings are treated as `bf(<string>)`.

        Returns
        -------
        FormulaConstruct
            New combined expression.
        """
        if isinstance(other, (FormulaPart, str, ProxyListSexpVector)):
            other = FormulaConstruct._formula_parse(other)

        if not isinstance(other, FormulaConstruct):
            raise ArithmeticError(
                "When adding values to formula, they must be FormulaConstruct or parseable to FormulaConstruct"
            )

        if len(other._parts) <= 1:
            return FormulaConstruct(_parts=self._parts + other._parts)
        else:
            return FormulaConstruct(_parts=[self._parts, other._parts])

    def __radd__(self, other: Other) -> "FormulaConstruct":
        """Support `"y ~ x" + bf("z ~ 1")` by coercing the left operand."""
        return self._formula_parse(other) + self

    def iter_summands(self) -> Iterator[Summand]:
        """
        Iterate over arithmetic groups (summands).

        Returns
        -------
        Iterator[tuple[FormulaPart | ProxyListSexpVector, ...]]
            Each yielded tuple represents one summand/group.

        Examples
        --------
        ```python
        from brmspy.brms import bf, gaussian, set_rescor

        f = bf("y ~ x") + gaussian() + set_rescor(True)
        for summand in f.iter_summands():
            print(summand)
        ```
        """

        def _groups(node: Node) -> Iterator[list[FormulaPart | ProxyListSexpVector]]:
            # Leaf node: single bf/family/etc
            if isinstance(node, (FormulaPart, ProxyListSexpVector)):
                return ([node],)  # one group with one element

            if isinstance(node, list):
                # If any child is a list, this node represents a "+"
                # between sub-expressions, so recurse into each child.
                if any(isinstance(child, list) for child in node):
                    for child in node:
                        yield from _groups(child)
                else:
                    # All children are leaves -> one summand
                    out: list[FormulaPart | ProxyListSexpVector] = []
                    for child in node:
                        if isinstance(child, (FormulaPart, ProxyListSexpVector, Sexp)):
                            child = cast(FormulaPart | ProxyListSexpVector, child)
                            out.append(child)
                        else:
                            raise TypeError(
                                f"Unexpected leaf node type in FormulaConstruct: {type(child)!r}"
                            )
                    yield out
                return

            raise TypeError(f"Unexpected node type in FormulaConstruct: {type(node)!r}")

        # self._parts is always a list[Node]
        for group in _groups(self._parts):
            yield tuple(group)

    # Make __iter__ return summands by default
    def __iter__(self) -> Iterator[Summand]:
        """Alias for [`iter_summands()`][brmspy.types.formula_dsl.FormulaConstruct.iter_summands]."""
        return self.iter_summands()

    def iterate(self) -> Iterator[FormulaPart | ProxyListSexpVector]:
        """
        Iterate over all leaf nodes in left-to-right order.

        This flattens the expression tree, unlike
        [`iter_summands()`][brmspy.types.formula_dsl.FormulaConstruct.iter_summands], which
        respects grouping.

        Returns
        -------
        Iterator[FormulaPart | ProxyListSexpVector]
        """

        def _walk(node: Node) -> Iterator[FormulaPart | ProxyListSexpVector]:
            if isinstance(node, FormulaPart):
                yield node
            elif isinstance(node, ProxyListSexpVector):
                yield node
            elif isinstance(node, list):
                for child in node:
                    yield from _walk(child)
            else:
                raise TypeError(
                    f"Unexpected node type in FormulaConstruct: {type(node)!r}"
                )

        for root in self._parts:
            yield from _walk(root)

    def __str__(self) -> str:
        return self._pretty(self._parts)

    def _pretty(self, node, _outer=True) -> str:
        if isinstance(node, FormulaPart):
            return str(node)

        if isinstance(node, (ProxyListSexpVector, Sexp)):
            return _sexp_to_str(node)

        if isinstance(node, list):
            # Pretty-print each child
            rendered = [self._pretty(child, _outer=False) for child in node]

            # If only one child, no parentheses needed
            if len(rendered) == 1:
                return rendered[0]

            # Multiple children → join with " + "
            inner = " + ".join(rendered)
            if _outer:
                return inner
            else:
                return f"({inner})"

        raise TypeError(f"Unexpected node type {type(node)!r} in pretty-printer")

    def __repr__(self) -> str:
        return self.__str__()

Attributes

_parts instance-attribute

Functions

_formula_parse(obj) classmethod

Convert a supported value into a FormulaConstruct.

Parameters:

Name Type Description Default
obj Other

One of: FormulaConstruct, FormulaPart, string (interpreted as bf(<string>)), or ProxyListSexpVector.

required

Returns:

Type Description
FormulaConstruct
Source code in brmspy/types/formula_dsl.py
@classmethod
def _formula_parse(cls, obj: Other) -> "FormulaConstruct":
    """
    Convert a supported value into a `FormulaConstruct`.

    Parameters
    ----------
    obj
        One of: `FormulaConstruct`, `FormulaPart`, string (interpreted as `bf(<string>)`),
        or `ProxyListSexpVector`.

    Returns
    -------
    FormulaConstruct
    """
    if isinstance(obj, FormulaConstruct):
        return obj
    if isinstance(obj, ProxyListSexpVector):
        return FormulaConstruct(_parts=[obj])
    if isinstance(obj, FormulaPart):
        return FormulaConstruct(_parts=[obj])
    if isinstance(obj, str):
        part = FormulaPart(_fun="bf", _args=[obj], _kwargs={})
        return FormulaConstruct(_parts=[part])
    raise TypeError(
        f"Cannot parse object of type {type(obj)!r} into FormulaConstruct"
    )
__add__(other)

Combine two formula expressions with +.

Parameters:

Name Type Description Default
other Other

Value to add. Strings are treated as bf(<string>).

required

Returns:

Type Description
FormulaConstruct

New combined expression.

Source code in brmspy/types/formula_dsl.py
def __add__(self, other: Other):
    """
    Combine two formula expressions with `+`.

    Parameters
    ----------
    other
        Value to add. Strings are treated as `bf(<string>)`.

    Returns
    -------
    FormulaConstruct
        New combined expression.
    """
    if isinstance(other, (FormulaPart, str, ProxyListSexpVector)):
        other = FormulaConstruct._formula_parse(other)

    if not isinstance(other, FormulaConstruct):
        raise ArithmeticError(
            "When adding values to formula, they must be FormulaConstruct or parseable to FormulaConstruct"
        )

    if len(other._parts) <= 1:
        return FormulaConstruct(_parts=self._parts + other._parts)
    else:
        return FormulaConstruct(_parts=[self._parts, other._parts])
__radd__(other)

Support "y ~ x" + bf("z ~ 1") by coercing the left operand.

Source code in brmspy/types/formula_dsl.py
def __radd__(self, other: Other) -> "FormulaConstruct":
    """Support `"y ~ x" + bf("z ~ 1")` by coercing the left operand."""
    return self._formula_parse(other) + self
iter_summands()

Iterate over arithmetic groups (summands).

Returns:

Type Description
Iterator[tuple[FormulaPart | ProxyListSexpVector, ...]]

Each yielded tuple represents one summand/group.

Examples:

from brmspy.brms import bf, gaussian, set_rescor

f = bf("y ~ x") + gaussian() + set_rescor(True)
for summand in f.iter_summands():
    print(summand)
Source code in brmspy/types/formula_dsl.py
def iter_summands(self) -> Iterator[Summand]:
    """
    Iterate over arithmetic groups (summands).

    Returns
    -------
    Iterator[tuple[FormulaPart | ProxyListSexpVector, ...]]
        Each yielded tuple represents one summand/group.

    Examples
    --------
    ```python
    from brmspy.brms import bf, gaussian, set_rescor

    f = bf("y ~ x") + gaussian() + set_rescor(True)
    for summand in f.iter_summands():
        print(summand)
    ```
    """

    def _groups(node: Node) -> Iterator[list[FormulaPart | ProxyListSexpVector]]:
        # Leaf node: single bf/family/etc
        if isinstance(node, (FormulaPart, ProxyListSexpVector)):
            return ([node],)  # one group with one element

        if isinstance(node, list):
            # If any child is a list, this node represents a "+"
            # between sub-expressions, so recurse into each child.
            if any(isinstance(child, list) for child in node):
                for child in node:
                    yield from _groups(child)
            else:
                # All children are leaves -> one summand
                out: list[FormulaPart | ProxyListSexpVector] = []
                for child in node:
                    if isinstance(child, (FormulaPart, ProxyListSexpVector, Sexp)):
                        child = cast(FormulaPart | ProxyListSexpVector, child)
                        out.append(child)
                    else:
                        raise TypeError(
                            f"Unexpected leaf node type in FormulaConstruct: {type(child)!r}"
                        )
                yield out
            return

        raise TypeError(f"Unexpected node type in FormulaConstruct: {type(node)!r}")

    # self._parts is always a list[Node]
    for group in _groups(self._parts):
        yield tuple(group)
__iter__()

Alias for iter_summands().

Source code in brmspy/types/formula_dsl.py
def __iter__(self) -> Iterator[Summand]:
    """Alias for [`iter_summands()`][brmspy.types.formula_dsl.FormulaConstruct.iter_summands]."""
    return self.iter_summands()
iterate()

Iterate over all leaf nodes in left-to-right order.

This flattens the expression tree, unlike iter_summands(), which respects grouping.

Returns:

Type Description
Iterator[FormulaPart | ProxyListSexpVector]
Source code in brmspy/types/formula_dsl.py
def iterate(self) -> Iterator[FormulaPart | ProxyListSexpVector]:
    """
    Iterate over all leaf nodes in left-to-right order.

    This flattens the expression tree, unlike
    [`iter_summands()`][brmspy.types.formula_dsl.FormulaConstruct.iter_summands], which
    respects grouping.

    Returns
    -------
    Iterator[FormulaPart | ProxyListSexpVector]
    """

    def _walk(node: Node) -> Iterator[FormulaPart | ProxyListSexpVector]:
        if isinstance(node, FormulaPart):
            yield node
        elif isinstance(node, ProxyListSexpVector):
            yield node
        elif isinstance(node, list):
            for child in node:
                yield from _walk(child)
        else:
            raise TypeError(
                f"Unexpected node type in FormulaConstruct: {type(node)!r}"
            )

    for root in self._parts:
        yield from _walk(root)
__str__()
Source code in brmspy/types/formula_dsl.py
def __str__(self) -> str:
    return self._pretty(self._parts)
_pretty(node, _outer=True)
Source code in brmspy/types/formula_dsl.py
def _pretty(self, node, _outer=True) -> str:
    if isinstance(node, FormulaPart):
        return str(node)

    if isinstance(node, (ProxyListSexpVector, Sexp)):
        return _sexp_to_str(node)

    if isinstance(node, list):
        # Pretty-print each child
        rendered = [self._pretty(child, _outer=False) for child in node]

        # If only one child, no parentheses needed
        if len(rendered) == 1:
            return rendered[0]

        # Multiple children → join with " + "
        inner = " + ".join(rendered)
        if _outer:
            return inner
        else:
            return f"({inner})"

    raise TypeError(f"Unexpected node type {type(node)!r} in pretty-printer")
__repr__()
Source code in brmspy/types/formula_dsl.py
def __repr__(self) -> str:
    return self.__str__()
__init__(_parts)

Functions

_execute_formula(formula)

Source code in brmspy/_brms_functions/formula.py
def _execute_formula(formula: FormulaConstruct | Sexp | str) -> Sexp:
    import rpy2.robjects as ro

    if isinstance(formula, Sexp):
        return formula
    if isinstance(formula, str):
        formula = FormulaConstruct._formula_parse(formula)

    # Must run for formula functions, e.g me() to register
    ro.r("library(brms)")

    fun_add = cast(Callable[[Sexp, Sexp], Sexp], ro.r("function (a, b) a + b"))

    result: Sexp | None = None
    for summand in formula:
        subresult: Sexp = py_to_r(summand[0])
        for part in summand[1:]:
            subresult = fun_add(subresult, py_to_r(part))

        if result is None:
            result = subresult
        else:
            result = fun_add(result, subresult)

    assert result is not None
    return result

kwargs_r(kwargs)

Convert Python keyword arguments to R-compatible format.

Convenience function that applies py_to_r() to all values in a keyword arguments dictionary, preparing them for R function calls.

Parameters:

Name Type Description Default
kwargs dict or None

Dictionary of keyword arguments where values may be Python objects (dicts, lists, DataFrames, arrays, etc.)

required

Returns:

Type Description
dict

Dictionary with same keys but R-compatible values, or empty dict if None

Notes

This is a thin wrapper around py_to_r() that operates on dictionaries. It's commonly used to prepare keyword arguments for R function calls via rpy2.

Examples:

from brmspy.helpers.conversion import kwargs_r
import pandas as pd
import numpy as np

# Prepare kwargs for R function
py_kwargs = {
    'data': pd.DataFrame({'y': [1, 2], 'x': [1, 2]}),
    'prior': {'b': [0, 1]},
    'chains': 4,
    'iter': 2000
}

r_kwargs = kwargs_r(py_kwargs)
# All values converted to R objects
# Can now call: r_function(**r_kwargs)
See Also

py_to_r : Underlying conversion function for individual values brmspy.brms.fit : Uses this to prepare user kwargs for R

Source code in brmspy/helpers/_rpy2/_conversion.py
def kwargs_r(kwargs: dict | None) -> dict:
    """
    Convert Python keyword arguments to R-compatible format.

    Convenience function that applies py_to_r() to all values in a
    keyword arguments dictionary, preparing them for R function calls.

    Parameters
    ----------
    kwargs : dict or None
        Dictionary of keyword arguments where values may be Python objects
        (dicts, lists, DataFrames, arrays, etc.)

    Returns
    -------
    dict
        Dictionary with same keys but R-compatible values, or empty dict if None

    Notes
    -----
    This is a thin wrapper around `py_to_r()` that operates on dictionaries.
    It's commonly used to prepare keyword arguments for R function calls via rpy2.

    Examples
    --------

    ```python
    from brmspy.helpers.conversion import kwargs_r
    import pandas as pd
    import numpy as np

    # Prepare kwargs for R function
    py_kwargs = {
        'data': pd.DataFrame({'y': [1, 2], 'x': [1, 2]}),
        'prior': {'b': [0, 1]},
        'chains': 4,
        'iter': 2000
    }

    r_kwargs = kwargs_r(py_kwargs)
    # All values converted to R objects
    # Can now call: r_function(**r_kwargs)
    ```

    See Also
    --------
    py_to_r : Underlying conversion function for individual values
    brmspy.brms.fit : Uses this to prepare user kwargs for R
    """
    if kwargs is None:
        return {}
    return {k: py_to_r(v) for k, v in kwargs.items()}

py_to_r(obj)

Convert arbitrary Python objects to R objects via rpy2.

Comprehensive converter that handles nested structures (dicts, lists), DataFrames, arrays, and scalars. Uses rpy2's converters with special handling for dictionaries (→ R named lists) and lists of dicts.

Parameters:

Name Type Description Default
obj any

Python object to convert. Supported types: - None → R NULL - dict → R named list (ListVector), recursively - list/tuple of dicts → R list of named lists - list/tuple (other) → R vector or list - pd.DataFrame → R data.frame - np.ndarray → R vector/matrix - scalars (int, float, str, bool) → R atomic types

required

Returns:

Type Description
rpy2 R object

R representation of the Python object

Notes

Conversion Rules:

  1. None: → R NULL
  2. DataFrames: → R data.frame (via pandas2ri)
  3. Dictionaries: → R named list (ListVector), recursively converting values
  4. Lists of dicts: → R list with 1-based indexed names containing named lists
  5. Other lists/tuples: → R vectors or lists (via rpy2 default)
  6. NumPy arrays: → R vectors/matrices (via numpy2ri)
  7. Scalars: → R atomic values

Recursive Conversion:

Dictionary values are recursively converted, allowing nested structures:

{'a': {'b': [1, 2, 3]}}    list(a = list(b = c(1, 2, 3)))

List of Dicts:

Lists containing only dicts are converted to R lists with 1-based indexing:

[{'x': 1}, {'x': 2}]    list("1" = list(x = 1), "2" = list(x = 2))

Examples:

from brmspy.helpers.conversion import py_to_r
import numpy as np
import pandas as pd

# Scalars
py_to_r(5)        # R: 5
py_to_r("hello")  # R: "hello"
py_to_r(None)     # R: NULL

# Arrays
py_to_r(np.array([1, 2, 3]))  # R: c(1, 2, 3)

# DataFrames
df = pd.DataFrame({'x': [1, 2], 'y': [3, 4]})
py_to_r(df)  # R: data.frame(x = c(1, 2), y = c(3, 4))
See Also

r_to_py : Convert R objects back to Python kwargs_r : Convert keyword arguments dict for R function calls brmspy.brms.fit : Uses this for converting data to R

Source code in brmspy/helpers/_rpy2/_converters/_dispatch.py
def py_to_r(obj: PyObject) -> Sexp:
    """
    Convert arbitrary Python objects to R objects via rpy2.

    Comprehensive converter that handles nested structures (dicts, lists),
    DataFrames, arrays, and scalars. Uses rpy2's converters with special
    handling for dictionaries (→ R named lists) and lists of dicts.

    Parameters
    ----------
    obj : any
        Python object to convert. Supported types:
        - None → R NULL
        - dict → R named list (ListVector), recursively
        - list/tuple of dicts → R list of named lists
        - list/tuple (other) → R vector or list
        - pd.DataFrame → R data.frame
        - np.ndarray → R vector/matrix
        - scalars (int, float, str, bool) → R atomic types

    Returns
    -------
    rpy2 R object
        R representation of the Python object

    Notes
    -----
    **Conversion Rules:**

    1. **None**: → R NULL
    2. **DataFrames**: → R data.frame (via pandas2ri)
    3. **Dictionaries**: → R named list (ListVector), recursively converting values
    4. **Lists of dicts**: → R list with 1-based indexed names containing named lists
    5. **Other lists/tuples**: → R vectors or lists (via rpy2 default)
    6. **NumPy arrays**: → R vectors/matrices (via numpy2ri)
    7. **Scalars**: → R atomic values

    **Recursive Conversion:**

    Dictionary values are recursively converted, allowing nested structures:
    ```python
    {'a': {'b': [1, 2, 3]}}  →  list(a = list(b = c(1, 2, 3)))
    ```

    **List of Dicts:**

    Lists containing only dicts are converted to R lists with 1-based indexing:
    ```python
    [{'x': 1}, {'x': 2}]  →  list("1" = list(x = 1), "2" = list(x = 2))
    ```

    Examples
    --------

    ```python
    from brmspy.helpers.conversion import py_to_r
    import numpy as np
    import pandas as pd

    # Scalars
    py_to_r(5)        # R: 5
    py_to_r("hello")  # R: "hello"
    py_to_r(None)     # R: NULL

    # Arrays
    py_to_r(np.array([1, 2, 3]))  # R: c(1, 2, 3)

    # DataFrames
    df = pd.DataFrame({'x': [1, 2], 'y': [3, 4]})
    py_to_r(df)  # R: data.frame(x = c(1, 2), y = c(3, 4))
    ```

    See Also
    --------
    r_to_py : Convert R objects back to Python
    kwargs_r : Convert keyword arguments dict for R function calls
    brmspy.brms.fit : Uses this for converting data to R
    """
    import rpy2.robjects as ro

    if obj is None:
        return ro.NULL

    if isinstance(obj, ro.Sexp):
        return obj

    if isinstance(obj, RListVectorExtension) and isinstance(obj.r, ro.Sexp):
        return obj.r

    _type = type(obj)
    converter = None

    if _type in _registry._PY2R_CONVERTERS:
        # O(1) lookup first
        converter = _registry._PY2R_CONVERTERS[_type]
    else:
        for _type, _con in _registry._PY2R_CONVERTERS.items():
            if isinstance(obj, _type):
                converter = _con
                break

    assert len(_registry._PY2R_CONVERTERS) > 0, "NO PY2R CONVERTERS"
    assert (
        converter
    ), "object fallback must be in place in __init__.py! This is an issue with the library, not the user!"
    return converter(obj)

r_to_py(obj, shm=None)

Convert R objects to Python objects via rpy2.

Comprehensive converter that handles R lists (named/unnamed), vectors, formulas, and language objects. Provides sensible Python equivalents for all R types with special handling for edge cases.

Parameters:

Name Type Description Default
obj rpy2 R object

R object to convert to Python

required

Returns:

Type Description
any

Python representation of the R object: - R NULL → None - Named list → dict (recursively) - Unnamed list → list (recursively) - Length-1 vector → scalar (int, float, str, bool) - Length-N vector → list of scalars - Formula/Language object → str (descriptive representation) - Other objects → default rpy2 conversion or str fallback

Notes

Conversion Rules:

  1. R NULL: → Python None
  2. Atomic vectors (numeric, character, logical):
  3. Length 1: → Python scalar (int, float, str, bool)
  4. Length >1: → Python list of scalars
  5. Named lists (ListVector with names): → Python dict, recursively
  6. Unnamed lists: → Python list, recursively
  7. Formulas (e.g., y ~ x): → String representation
  8. Language objects (calls, expressions): → String representation
  9. Functions: → String representation
  10. Everything else: Try default rpy2 conversion, fallback to string

Recursive Conversion:

List elements and dictionary values are recursively converted:

list(a = list(b = c(1, 2)))    {'a': {'b': [1, 2]}}

Safe Fallback:

R language objects, formulas, and functions are converted to descriptive strings rather than attempting complex conversions that might fail.

Examples:

from brmspy.helpers.conversion import r_to_py
import rpy2.robjects as ro

# R NULL
r_to_py(ro.NULL)  # None

# Scalars
r_to_py(ro.IntVector([5]))    # 5
r_to_py(ro.FloatVector([3.14]))  # 3.14
r_to_py(ro.StrVector(["hello"]))  # "hello"

# Vectors
r_to_py(ro.IntVector([1, 2, 3]))  # [1, 2, 3]
See Also

py_to_r : Convert Python objects to R brmspy.brms.summary : Returns Python-friendly summary dict

Source code in brmspy/helpers/_rpy2/_converters/_dispatch.py
def r_to_py(obj: Sexp, shm: ShmPool | None = None) -> PyObject:
    """
    Convert R objects to Python objects via rpy2.

    Comprehensive converter that handles R lists (named/unnamed), vectors,
    formulas, and language objects. Provides sensible Python equivalents
    for all R types with special handling for edge cases.

    Parameters
    ----------
    obj : rpy2 R object
        R object to convert to Python

    Returns
    -------
    any
        Python representation of the R object:
        - R NULL → None
        - Named list → dict (recursively)
        - Unnamed list → list (recursively)
        - Length-1 vector → scalar (int, float, str, bool)
        - Length-N vector → list of scalars
        - Formula/Language object → str (descriptive representation)
        - Other objects → default rpy2 conversion or str fallback

    Notes
    -----
    **Conversion Rules:**

    1. **R NULL**: → Python None
    2. **Atomic vectors** (numeric, character, logical):
       - Length 1: → Python scalar (int, float, str, bool)
       - Length >1: → Python list of scalars
    3. **Named lists** (ListVector with names): → Python dict, recursively
    4. **Unnamed lists**: → Python list, recursively
    5. **Formulas** (e.g., `y ~ x`): → String representation
    6. **Language objects** (calls, expressions): → String representation
    7. **Functions**: → String representation
    8. **Everything else**: Try default rpy2 conversion, fallback to string

    **Recursive Conversion:**

    List elements and dictionary values are recursively converted:
    ```R
    list(a = list(b = c(1, 2)))  →  {'a': {'b': [1, 2]}}
    ```

    **Safe Fallback:**

    R language objects, formulas, and functions are converted to descriptive
    strings rather than attempting complex conversions that might fail.

    Examples
    --------

    ```python
    from brmspy.helpers.conversion import r_to_py
    import rpy2.robjects as ro

    # R NULL
    r_to_py(ro.NULL)  # None

    # Scalars
    r_to_py(ro.IntVector([5]))    # 5
    r_to_py(ro.FloatVector([3.14]))  # 3.14
    r_to_py(ro.StrVector(["hello"]))  # "hello"

    # Vectors
    r_to_py(ro.IntVector([1, 2, 3]))  # [1, 2, 3]
    ```

    See Also
    --------
    py_to_r : Convert Python objects to R
    brmspy.brms.summary : Returns Python-friendly summary dict
    """
    import rpy2.robjects as ro

    from brmspy._singleton._shm_singleton import _get_shm

    if obj is ro.NULL:
        return None

    _type = type(obj)
    converter = None

    if shm is None:
        shm = _get_shm()

    if _type in _registry._R2PY_CONVERTERS:
        # O(1) lookup first
        converter = _registry._R2PY_CONVERTERS[_type]
    else:
        for _type, _con in _registry._R2PY_CONVERTERS.items():
            if isinstance(obj, _type):
                converter = _con
                break

    assert len(_registry._R2PY_CONVERTERS) > 0, "NO R2PY CONVERTERS"
    assert (
        converter
    ), "object fallback must be in place in __init__.py! This is an issue with the library, not the user!"
    return converter(obj, shm)

prior(prior, class_=None, coef=None, group=None, dpar=None, resp=None, nlpar=None, lb=None, ub=None, **kwargs)

Create a brms-style prior specification.

This function mirrors the behavior of brms::prior_string() and allows specifying priors for regression parameters, group-level effects, nonlinear parameters, distributional parameters, and more — using a typed Python interface. All arguments correspond directly to the parameters of prior_string() in brms.

Parameters:

Name Type Description Default
prior str

The prior definition as a string, exactly as brms expects it. Examples include ::

"normal(0, 1)"
"student_t(3, 0, 1.5)"
"exponential(2)"
"lkj(2)"
required
class_ str

Parameter class (e.g. "b", "sd", "Intercept"). This corresponds to class in brms. class cannot be used as a parameter in Python (reserved keyword), so class_ is used instead.

None
coef str

Coefficient name for class-level effects.

None
group str

Grouping variable for hierarchical/multilevel effects.

None
dpar str

Distributional parameter (e.g. "sigma" or "phi").

None
resp str

Response variable name for multivariate models.

None
nlpar str

Nonlinear parameter name if using nonlinear formulas.

None
lb float

Lower bound for truncated priors.

None
ub float

Upper bound for truncated priors.

None
**kwargs Any

Any additional keyword arguments supported by brms::prior_string(). These are forwarded unchanged.

{}

Returns:

Type Description
PriorSpec

A typed prior specification object used by brmspy.brms.brm() and brmspy.brms.make_stancode().

See Also

brms::prior_string : R documentation

Notes

This function does not validate the prior expression string itself — validation occurs inside brms.

Examples:

from brmspy.brms import prior

p_intercept = prior("student_t(3, 0, 1.95)", class_="Intercept")
p_slope = prior("normal(0, 1)", class_="b", coef="age")
p_sd = prior("exponential(2)", class_="sd", group="region")
p_trunc = prior("normal(0, 1)", class_="b", coef="income", lb=0)
Source code in brmspy/_brms_functions/prior.py
def prior(
    prior: str,
    class_: str | None = None,
    coef: str | None = None,
    group: str | None = None,
    dpar: str | None = None,
    resp: str | None = None,
    nlpar: str | None = None,
    lb: float | None = None,
    ub: float | None = None,
    **kwargs: Any,
) -> PriorSpec:
    """
    Create a brms-style prior specification.

    This function mirrors the behavior of ``brms::prior_string()`` and allows
    specifying priors for regression parameters, group-level effects, nonlinear
    parameters, distributional parameters, and more — using a typed Python
    interface. All arguments correspond directly to the parameters of
    ``prior_string()`` in brms.

    Parameters
    ----------
    prior : str
        The prior definition as a string, exactly as brms expects it.
        Examples include ::

            "normal(0, 1)"
            "student_t(3, 0, 1.5)"
            "exponential(2)"
            "lkj(2)"

    class_ : str, optional
        Parameter class (e.g. ``"b"``, ``"sd"``, ``"Intercept"``).
        This corresponds to ``class`` in brms. ``class`` cannot be used as a
        parameter in Python (reserved keyword), so ``class_`` is used instead.

    coef : str, optional
        Coefficient name for class-level effects.

    group : str, optional
        Grouping variable for hierarchical/multilevel effects.

    dpar : str, optional
        Distributional parameter (e.g. ``"sigma"`` or ``"phi"``).

    resp : str, optional
        Response variable name for multivariate models.

    nlpar : str, optional
        Nonlinear parameter name if using nonlinear formulas.

    lb : float, optional
        Lower bound for truncated priors.

    ub : float, optional
        Upper bound for truncated priors.

    **kwargs
        Any additional keyword arguments supported by ``brms::prior_string()``.
        These are forwarded unchanged.

    Returns
    -------
    PriorSpec
        A typed prior specification object used by `brmspy.brms.brm()` and
        `brmspy.brms.make_stancode()`.

    See Also
    --------
    brms::prior_string : [R documentation](https://paulbuerkner.com/brms/reference/prior_string.html)

    Notes
    -----
    This function does **not** validate the prior expression string itself —
    validation occurs inside brms.

    Examples
    --------
    ```python
    from brmspy.brms import prior

    p_intercept = prior("student_t(3, 0, 1.95)", class_="Intercept")
    p_slope = prior("normal(0, 1)", class_="b", coef="age")
    p_sd = prior("exponential(2)", class_="sd", group="region")
    p_trunc = prior("normal(0, 1)", class_="b", coef="income", lb=0)
    ```
    """
    if "class" in kwargs:
        kwargs["class_"] = kwargs["class"]

    return PriorSpec(
        prior=prior,
        class_=class_,
        coef=coef,
        group=group,
        dpar=dpar,
        resp=resp,
        nlpar=nlpar,
        lb=lb,
        ub=ub,
        **kwargs,
    )

get_prior(formula, data=None, family='gaussian', **kwargs)

Get default priors for a model specification.

Wrapper around R brms::get_prior().

Returns a DataFrame with default priors for each parameter class in the specified brms model. Useful for reviewing and customizing priors before fitting.

Parameters:

Name Type Description Default
formula str or FormulaConstruct

Model formula (e.g. "y ~ x + (1|group)") or a composed formula.

required
data DataFrame or dict

Dataset containing model variables. Required for data-dependent priors

None
family str or ListSexpVector

Distribution family (e.g., "gaussian", "poisson", "binomial")

"gaussian"
**kwargs

Additional arguments passed to brms::get_prior() (e.g., autocor, data2, knots, drop_unused_levels)

{}

Returns:

Type Description
DataFrame

DataFrame with columns: prior, class, coef, group, resp, dpar, nlpar, lb, ub, source. Each row represents a parameter or parameter class that can have a custom prior.

See Also

default_prior : Generic function for getting default priors prior : Create custom prior specifications brms::get_prior : R documentation

Examples:

from brmspy import brms
from brmspy.brms import prior

priors_df = brms.get_prior("y ~ x", data=df)

custom_priors = [
    prior("normal(0, 0.5)", class_="b"),
    prior("exponential(2)", class_="sigma"),
]

fit = brms.brm("y ~ x", data=df, priors=custom_priors, chains=4)
Source code in brmspy/_brms_functions/prior.py
def get_prior(
    formula: str | FormulaConstruct, data=None, family="gaussian", **kwargs
) -> pd.DataFrame:
    """
    Get default priors for a model specification.

    Wrapper around R ``brms::get_prior()``.

    Returns a DataFrame with default priors for each parameter class in the specified
    brms model. Useful for reviewing and customizing priors before fitting.

    Parameters
    ----------
    formula : str or FormulaConstruct
        Model formula (e.g. ``"y ~ x + (1|group)"``) or a composed formula.
    data : pd.DataFrame or dict, optional
        Dataset containing model variables. Required for data-dependent priors
    family : str or ListSexpVector, default="gaussian"
        Distribution family (e.g., "gaussian", "poisson", "binomial")
    **kwargs
        Additional arguments passed to brms::get_prior()
        (e.g., autocor, data2, knots, drop_unused_levels)

    Returns
    -------
    pd.DataFrame
        DataFrame with columns: prior, class, coef, group, resp, dpar, nlpar, lb, ub, source.
        Each row represents a parameter or parameter class that can have a custom prior.

    See Also
    --------
    default_prior : Generic function for getting default priors
    prior : Create custom prior specifications
    brms::get_prior : [R documentation](https://paulbuerkner.com/brms/reference/get_prior.html)

    Examples
    --------
    ```python
    from brmspy import brms
    from brmspy.brms import prior

    priors_df = brms.get_prior("y ~ x", data=df)

    custom_priors = [
        prior("normal(0, 0.5)", class_="b"),
        prior("exponential(2)", class_="sigma"),
    ]

    fit = brms.brm("y ~ x", data=df, priors=custom_priors, chains=4)
    ```
    """
    import rpy2.robjects as ro

    formula_obj = _execute_formula(formula)

    r_get_prior = cast(Callable, ro.r("brms::get_prior"))
    collected_args = kwargs_r(
        {"formula": formula_obj, "data": data, "family": family, **kwargs}
    )

    df_r = r_get_prior(**collected_args)
    df = pd.DataFrame(cast(Any, r_to_py(df_r)))

    return df

default_prior(object, data=None, family='gaussian', **kwargs)

Get default priors for brms model parameters (generic function).

Wrapper around R brms::default_prior().

Generic function to retrieve default prior specifications for all parameters in a brms model. Accepts formula objects, brmsformula objects, or other model specification objects. This is the generic version of get_prior().

Parameters:

Name Type Description Default
object str, FormulaResult, or ListSexpVector

Model specification: formula string, brmsformula object, mvbrmsformula, or any object that can be coerced to these classes

required
data DataFrame or dict

Dataset containing model variables. Required for data-dependent priors

None
family str or ListSexpVector

Distribution family (e.g., "gaussian", "poisson", "binomial"). Can be a list of families for multivariate models

"gaussian"
**kwargs

Additional arguments passed to brms::get_prior() (e.g., autocor, data2, knots, drop_unused_levels, sparse)

{}

Returns:

Type Description
DataFrame

DataFrame with columns: prior, class, coef, group, resp, dpar, nlpar, lb, ub, source. Each row specifies a parameter class with its default prior. The 'prior' column is empty except for internal defaults.

See Also

get_prior : Convenience function with formula parameter prior : Create custom prior specifications brms::default_prior : R documentation

Examples:

Get default priors for a Poisson model:

from brmspy import brms

priors = brms.default_prior(
    object="count ~ zAge + zBase * Trt + (1|patient)",
    data=epilepsy,
    family="poisson"
)
print(priors)

Use with formula object:

from brmspy import brms

f = brms.formula("y ~ x + (1|group)")
priors = brms.default_prior(f, data=df, family="gaussian")
Source code in brmspy/_brms_functions/prior.py
def default_prior(
    object: RListVectorExtension | ListSexpVector | FormulaConstruct | str,
    data=None,
    family="gaussian",
    **kwargs,
) -> pd.DataFrame:
    """
    Get default priors for brms model parameters (generic function).

    Wrapper around R ``brms::default_prior()``.

    Generic function to retrieve default prior specifications for all parameters
    in a brms model. Accepts formula objects, brmsformula objects, or other model
    specification objects. This is the generic version of get_prior().

    Parameters
    ----------
    object : str, FormulaResult, or ListSexpVector
        Model specification: formula string, brmsformula object, mvbrmsformula,
        or any object that can be coerced to these classes
    data : pd.DataFrame or dict, optional
        Dataset containing model variables. Required for data-dependent priors
    family : str or ListSexpVector, default="gaussian"
        Distribution family (e.g., "gaussian", "poisson", "binomial").
        Can be a list of families for multivariate models
    **kwargs
        Additional arguments passed to brms::get_prior()
        (e.g., autocor, data2, knots, drop_unused_levels, sparse)

    Returns
    -------
    pd.DataFrame
        DataFrame with columns: prior, class, coef, group, resp, dpar, nlpar, lb, ub, source.
        Each row specifies a parameter class with its default prior. The 'prior' column
        is empty except for internal defaults.

    See Also
    --------
    get_prior : Convenience function with formula parameter
    prior : Create custom prior specifications
    brms::default_prior : [R documentation](https://paulbuerkner.com/brms/reference/default_prior.html)

    Examples
    --------
    Get default priors for a Poisson model:

    ```python
    from brmspy import brms

    priors = brms.default_prior(
        object="count ~ zAge + zBase * Trt + (1|patient)",
        data=epilepsy,
        family="poisson"
    )
    print(priors)
    ```

    Use with formula object:

    ```python
    from brmspy import brms

    f = brms.formula("y ~ x + (1|group)")
    priors = brms.default_prior(f, data=df, family="gaussian")
    ```
    """
    import rpy2.robjects as ro

    r_get_prior = cast(Callable, ro.r("brms::get_prior"))
    collected_args = kwargs_r({"data": data, "family": family, **kwargs})

    obj_resolved = object
    if isinstance(object, FormulaConstruct):
        obj_resolved = _execute_formula(object)

    df_r = r_get_prior(py_to_r(obj_resolved), **collected_args)
    df = pd.DataFrame(cast(Any, r_to_py(df_r)))

    return df