"""This module contains the code to for applying contact policies."""
import itertools
from typing import Any
from typing import Dict
from typing import Optional
from typing import Union
import pandas as pd
from sid.time import timestamp_to_sid_period
from sid.validation import validate_return_is_series_or_ndarray
[docs]def compute_pseudo_effect_sizes_of_policies(
policies: Dict[str, Dict[str, Any]], states: Optional[pd.DataFrame] = None
) -> Dict[str, Dict[str, Union[float, pd.Series]]]:
"""Compute pseudo effect sizes of policies.
This function returns either the multiplicand of a policy or computes a pseudo
effect size by passing a :class:`pandas.Series` with booleans set to ``True`` to the
policy function. The effect size is the average of the returned
:class:`pandas.Series`.
How is the effect size interpreted.
1. The effect is an average treatment effect on the whole population since this
simple approach cannot infer which share of the population is affected by the
policy.
2. The pseudo effect size can be interpreted as an effect on the average of
contacts for this contact model.
Parameters
----------
policies : Dict[str, Dict[str, Any]]
A policy dictionary.
states : pd.DataFrame, optional
The states.
Returns
-------
effects : Dict[str, Dict[str, Union[float, pd.Series]]]
A dictionary containing for each contact model the mean effect size and a raw
effect size if a pseudo effect was computed.
"""
states = states.copy(deep=True) if isinstance(states, pd.DataFrame) else states
effects = {}
for name, policy in policies.items():
date = _find_date_where_policy_is_active(policy)
if states is not None:
states["date"] = date
states["period"] = timestamp_to_sid_period(date)
index = range(1_000) if states is None else states.index
if policy.get("affected_contact_model") is None:
contacts = pd.Series(index=index, data=True).to_frame()
else:
contacts = pd.Series(
index=index, data=True, name=policy["affected_contact_model"]
)
if callable(policy["policy"]):
result = policy["policy"](contacts=contacts, states=states, seed=0)
result = result.iloc[:, 0] if isinstance(result, pd.DataFrame) else result
result = result.astype("float") if result.dtype == "object" else result
effects[name] = {"raw_effect": result, "mean": result.mean()}
else:
effects[name] = {"mean": policy["policy"]}
return effects
[docs]def _find_date_where_policy_is_active(policy):
return policy.get("start", policy.get("end", pd.Timestamp("2020-03-09")))