Types#

Type aliases and protocols used in the lymph package.

lymph.types.does_contain_in_order(sequence: Sequence, items: Sequence) bool[source]#

Check if sequence contains items in the same order (gaps allowed).

>>> does_contain_in_order(["ipsi", "TtoII", "spread"], ["ipsi", "spread"])
True
>>> does_contain_in_order(["ipsi", "TtoII", "spread"], ["spread", "ipsi"])
False
lymph.types.search_nested(mapping: Mapping, keys: Sequence[str], raise_keyerror: bool = True) list[float][source]#

Search a nested mapping given a sequence of keys.

The first of the keys is used to access the first level of the mapping. If no such key is found, it searches all the values of the first level if they have the first of the keys. Returns all matching values.

If nothing is found a KeyError is raised unless raise_keyerror is False.

>>> nested = {"a": {"x": 0.1, "y": 0.2, "z": 0.3}, "b": {"x": 0.4}}
>>> search_nested(nested, ["b", "x"])
[0.4]
>>> search_nested(nested, ["x"])
[0.1, 0.4]
>>> search_nested(nested, ["z"])
[0.3]
>>> search_nested(nested, ["c"])
Traceback (most recent call last):
...
KeyError: 'c'
>>> search_nested(nested, ["c"], raise_keyerror=False)
[]
>>> search_nested(nested, ["a", "x", "foo"])
Traceback (most recent call last):
...
TypeError: Expected `Mapping`, but got mapping=0.1. Too many keys?
exception lymph.types.DataWarning[source]#

Bases: UserWarning

Warnings related to potential data issues.

exception lymph.types.InvalidParamNameWarning[source]#

Bases: UserWarning

Issues when an invalid parameter name is used.

exception lymph.types.ExtraParamsError(extra_param_names: set[str])[source]#

Bases: Exception

Exception raised when additional unrecognized parameters are passed.

lymph.types.create_alias_map(all_params: Iterable[str], named_params: Iterable[str]) dict[str, list[str]][source]#

Create a mapping from named params to valid param names.

>>> all_params = ["TtoII_spread", "TtoIII_spread", "IItoIII_spread", "late_p"]
>>> named_params = ["spread", "TtoIII_spread"]
>>> create_alias_map(all_params, named_params)   
{'spread': ['TtoII_spread', 'TtoIII_spread', 'IItoIII_spread'],
 'TtoIII_spread': ['TtoIII_spread']}
lymph.types.reverse_alias_map(aliases: dict[str, Sequence[str]]) dict[str, str][source]#

Reverse mapping from param aliases to valid param names.

>>> aliases = {
...     "spread": ["TtoII_spread", "TtoIII_spread", "IItoIII_spread"],
...     "TtoIII_spread": ["TtoIII_spread"],
... }
>>> reverse_alias_map(aliases)   
{'TtoII_spread': 'spread',
 'TtoIII_spread': 'TtoIII_spread',
 'IItoIII_spread': 'spread'}
class lymph.types.HasSetParams(*args, **kwargs)[source]#

Bases: Protocol

Protocol for classes that have a set_params method.

set_params(*args: float, **kwargs: float) tuple[float][source]#

Set the parameters of the class.

class lymph.types.HasGetParams(*args, **kwargs)[source]#

Bases: Protocol

Protocol for classes that have a get_params method.

get_params(as_dict: bool = True, as_flat: bool = True) tuple[float] | dict[str, float][source]#

Return the parameters of the class.

lymph.types.GraphDictType#

Type alias for a graph dictionary.

A dictionary of this form specifies the structure of the underlying graph. Example:

>>> graph_dict = {
...     ("tumor", "T"): ["I", "II", "III"],
...     ("lnl", "I"): ["II"],
...     ("lnl", "II"): ["III"],
...     ("lnl", "III"): [],
... }
lymph.types.ParamsType = collections.abc.Iterable[float] | dict[str, float]#

Type alias for how parameters are passed around.

This is e.g. the type that the Model.get_params() method returns.

lymph.types.InvolvementIndicator#

Type alias for how to encode lymphatic involvement for a single lymph node level.

The choices "micro", "macro", and "notmacro" are only relevant for the trinary models.

alias of Literal[False, 0, ‘healthy’, True, 1, ‘involved’, ‘micro’, ‘macro’, ‘notmacro’]

lymph.types.PatternType#

Type alias for an involvement pattern.

An involvement pattern is a dictionary with keys for the lymph node levels and values for the involvement of the respective lymph nodes. The values are either True, False, or None, which means that the involvement is unknown.

TODO: Document the new possibilities to specify trinary involvment. See matrix.compute_encoding()

>>> pattern = {"I": True, "II": False, "III": None}
lymph.types.DiagnosisType#

Type alias for a diagnosis, which is an involvement pattern per diagnostic modality.

>>> diagnosis = {
...     "CT": {"I": True, "II": False, "III": None},
...     "MRI": {"I": True, "II": True, "III": None},
... }
class lymph.types.Model[source]#

Bases: ABC

Abstract base class for models.

This class provides a scaffold for the methods that any model for lymphatic tumor progression should implement.

property named_params: Sequence[str]#

Sequence of parameter names that may be changed.

Only parameter names are allowed that would also be recognized by the set_params() method. For example, "TtoII_spread" or "late_p" could be valid named parameters. Even global parameters like "spread" work.

Warning

The order is important: If the named_params are set to e.g. ["TtoII_spread", "spread"], then the "spread" parameter will override the "TtoII_spread".

This exists for reproducibility reasons: It allows for a subset of parameters to be set via a special method (set_named_params()). Subsequently, only these parameters can be set via that method, both using positional and keyword arguments.

A use case for this is parameter sampling. E.g., someone samples only a subset of parameters and stores these as an unnamed array along with a list of the parameters names they correspond to. Without the named_params and the set_named_params() method, it would be tricky to load those values back into the model.

See also

This issue on GitHub provides more information for the rationale behind this mixin.

abstract get_params(as_dict: bool = True, as_flat: bool = True) Iterable[float] | dict[str, float][source]#

Return the parameters of the model.

The parameters are returned as a dictionary if as_dict is True, and as an iterable of floats otherwise. The argument as_flat determines whether the returned dict is flat or nested. This is helpful, because a model may call the get_params method of other instances, which can be fused to get a flat dictionary.

abstract set_params(*args: float, **kwargs: float) tuple[float][source]#

Set the parameters of the model.

The parameters may be passed as positional or keyword arguments. The positional arguments are used up one by one by the set_params methods the model calls. Keyword arguments override the positional arguments.

get_named_params(as_dict: bool = True) Iterable[float] | dict[str, float][source]#

Get the values of the named_params.

Note

Unlike the general get_params() method, this method does not support the keyword argument as_flat. The returned dictionary (if as_dict=True) will always be flat.

set_named_params(*args, **kwargs) None[source]#

Set the values of the named_params.

Note

Positional arguments are overwritten by keyword arguments, which must only contain keys that are in named_params.

get_num_dims() int[source]#

Return the number of dimensions of the parameter space.

This is either the total number of settable parameters in the model or - if specified - the number of named_params.

abstract state_dist(t_stage: str, mode: Literal['HMM', 'BN'] = 'HMM') ndarray[source]#

Return the prior state distribution of the model.

The state distribution is the probability of the model being in any of the possible hidden states.

obs_dist(given_state_dist: ndarray | None = None, t_stage: str = 'early', mode: Literal['HMM', 'BN'] = 'HMM') ndarray[source]#

Return the distribution over observational states.

If given_state_dist is None, it will first compute the state_dist() using the arguments t_stage and mode (which are otherwise ignored). Then it multiplies the distribution over (hidden) states with the specificity and sensitivity values stored in the model (see modalities.Composite()) and marginalizes over the hidden states.

abstract load_patient_data(patient_data: DataFrame) None[source]#

Load patient data in LyProX format into the model.

abstract likelihood(given_params: Iterable[float] | dict[str, float] | None = None, log: bool = True) float[source]#

Return the likelihood of the model given the parameters.

The likelihood is returned in log space if log is True, and in linear space otherwise. The parameters may be passed as positional or keyword arguments. They are then passed to the set_params() method first.

abstract posterior_state_dist(given_params: Iterable[float] | dict[str, float] | None = None, given_state_dist: ndarray | None = None, given_diagnosis: dict[str, dict[str, Literal[False, 0, 'healthy', True, 1, 'involved', 'micro', 'macro', 'notmacro'] | None]] | None = None) ndarray[source]#

Return the posterior state distribution using the given_diagnosis.

The posterior state distribution is the probability of the model being in a certain state given the diagnosis. The given_params are passed to the set_params() method. Alternatively to parameters, one may also pass a given_state_dist, which is effectively the precomputed prior from calling state_dist().

marginalize(involvement: dict[str, dict[str, Literal[False, 0, 'healthy', True, 1, 'involved', 'micro', 'macro', 'notmacro'] | None]] | None = None, given_state_dist: ndarray | None = None, t_stage: str = 'early', mode: Literal['HMM', 'BN'] = 'HMM') float[source]#

Marginalize given_state_dist over matching involvement patterns.

Any state that matches the provided involvement pattern is marginalized over. For this, the matrix.compute_encoding() function is used.

If given_state_dist is None, it will be computed by calling state_dist() with the given t_stage and mode. These arguments are ignored if given_state_dist is provided.

abstract risk(involvement: dict[str, Literal[False, 0, 'healthy', True, 1, 'involved', 'micro', 'macro', 'notmacro'] | None] | None = None, given_params: Iterable[float] | dict[str, float] | None = None, given_state_dist: ndarray | None = None, given_diagnosis: dict[str, dict[str, Literal[False, 0, 'healthy', True, 1, 'involved', 'micro', 'macro', 'notmacro'] | None]] | None = None) float[source]#

Return the risk of involvement, given params/state_dist and diagnosis.