def fit(self, df, group=None): """ Fits a loose, tight, beta, and p combinations model. If you pass in update group it will override the initial parameters with new initial parameters based on the df you pass. Args: df: group: (str) passing in the group will update the initialization dictionary (not replacing the old one) for this particular fit. Returns: """ if group is not None: init_dict = self.update_init_model(df=df, group=group) else: init_dict = deepcopy(self.init_dict) for param in ['beta', 'p']: for fit_type in ['loose', 'tight']: model_arg_dict = deepcopy( getattr(self, f'{param}_model_kwargs')) fit_arg_dict = deepcopy( getattr(self, f'{fit_type}_{param}_fit_dict')) model = CurveModel(df=df, **model_arg_dict) fe_init, re_init = compute_starting_params( init_dict[param][fit_type]) fit_arg_dict.update(fe_init=fe_init, re_init=re_init) model.fit_params(**fit_arg_dict) setattr(self, f'{fit_type}_{param}_model', model)
class BasicModel(ModelPipeline): def __init__(self, fit_dict, **basic_model_kwargs): """ Generic class for a function to produce predictions from a model with the following attributes. Args: predict_group: (str) which group to make predictions for fit_dict: keyword arguments to CurveModel.fit_params() **basic_model_kwargs: keyword arguments to CurveModel.__init__() """ super().__init__() self.fit_dict = fit_dict self.basic_model_kwargs = basic_model_kwargs self.mod = None def refresh(self): self.mod = None def fit(self, df): self.mod = CurveModel(df=df, **self.basic_model_kwargs) self.mod.fit_params(**self.fit_dict) def predict(self, times, predict_space, predict_group='all'): predictions = self.mod.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) return predictions
class BasicModel(ModelPipeline): def __init__(self, fit_dict, basic_model_dict, **pipeline_kwargs): """ Generic class for a function to produce predictions from a model with the following attributes. Args: **pipeline_kwargs: keyword arguments for the base class of ModelPipeline predict_group: (str) which group to make predictions for fit_dict: keyword arguments to CurveModel.fit_params() basic_model_dict: additional keyword arguments to the CurveModel class col_obs_se: (str) of observation standard error col_covs: List[str] list of names of covariates to put on the parameters param_names (list{str}): Names of the parameters in the specific functional form. link_fun (list{function}): List of link functions for each parameter. var_link_fun (list{function}): List of link functions for the variables including fixed effects and random effects. """ super().__init__(**pipeline_kwargs) self.fit_dict = fit_dict self.basic_model_dict = basic_model_dict self.basic_model_dict.update({'col_obs_se': self.col_obs_se}) generator_kwargs = pipeline_kwargs for arg in self.pop_cols: generator_kwargs.pop(arg) self.basic_model_dict.update(**generator_kwargs) self.mod = None self.setup_pipeline() def refresh(self): self.mod = None def fit(self, df, group=None): self.mod = CurveModel(df=df, **self.basic_model_dict) self.mod.fit_params(**self.fit_dict) def predict(self, times, predict_space, predict_group): predictions = self.mod.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) return predictions
class TightLooseBetaPModel(ModelPipeline): def __init__(self, loose_beta_fit_dict, tight_beta_fit_dict, loose_p_fit_dict, tight_p_fit_dict, beta_model_extras=None, p_model_extras=None, blend_start_t=2, blend_end_t=30, **basic_model_kwargs): """ Produces two tight-loose models as a convex combination between the two of them, and then averages Args: loose_beta_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() for the loose beta model tight_beta_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() fro the tight beta model loose_p_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() for the loose p model tight_p_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() fro the tight p model beta_model_extras: (optional) dictionary of keyword arguments to override the basic_model_kwargs for the beta model p_model_extras: (optional) dictionary of keyword arguments to override the basic_model_kwargs for the p model blend_start_t: (int) the time to start blending tight and loose blend_end_t: (int) the time to stop blending tight and loose predict_group: (str) which group to make predictions for **basic_model_kwargs: keyword arguments to the basic model """ super().__init__() self.beta_model_kwargs = basic_model_kwargs self.p_model_kwargs = basic_model_kwargs if beta_model_extras is not None: self.beta_model_kwargs = self.beta_model_kwargs.update( beta_model_extras) if p_model_extras is not None: self.p_model_kwargs = self.p_model_kwargs.update(p_model_extras) self.loose_beta_fit_dict = loose_beta_fit_dict self.tight_beta_fit_dict = tight_beta_fit_dict self.loose_p_fit_dict = loose_p_fit_dict self.tight_p_fit_dict = tight_p_fit_dict self.blend_start_t = blend_start_t self.blend_end_t = blend_end_t self.loose_beta_model = None self.tight_beta_model = None self.loose_p_model = None self.tight_p_model = None def refresh(self): self.loose_beta_model = None self.tight_beta_model = None self.loose_p_model = None self.tight_p_model = None def fit(self, df): self.loose_beta_model = CurveModel(df=df, **self.beta_model_kwargs) self.tight_beta_model = CurveModel(df=df, **self.beta_model_kwargs) self.loose_p_model = CurveModel(df=df, **self.p_model_kwargs) self.tight_p_model = CurveModel(df=df, **self.p_model_kwargs) self.loose_beta_model.fit_params(**self.loose_beta_fit_dict) self.tight_beta_model.fit_params(**self.tight_beta_fit_dict) self.loose_p_model.fit_params(**self.loose_p_fit_dict) self.tight_p_model.fit_params(**self.tight_p_fit_dict) def predict(self, times, predict_space, predict_group='all'): loose_beta_predictions = self.loose_beta_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) tight_beta_predictions = self.tight_beta_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) loose_p_predictions = self.loose_p_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) tight_p_predictions = self.tight_p_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) beta_predictions = convex_combination(t=times, pred1=tight_beta_predictions, pred2=loose_beta_predictions, pred_fun=predict_space, start_day=self.blend_start_t, end_day=self.blend_end_t) p_predictions = convex_combination(t=times, pred1=tight_p_predictions, pred2=loose_p_predictions, pred_fun=predict_space, start_day=self.blend_start_t, end_day=self.blend_end_t) averaged_predictions = model_average(pred1=beta_predictions, pred2=p_predictions, w1=0.5, w2=0.5, pred_fun=predict_space) return averaged_predictions
class TightLooseBetaPModel(ModelPipeline): def __init__(self, loose_beta_fit_dict, tight_beta_fit_dict, loose_p_fit_dict, tight_p_fit_dict, basic_model_dict, beta_model_extras=None, p_model_extras=None, blend_start_t=2, blend_end_t=30, **pipeline_kwargs): """ Produces two tight-loose models as a convex combination between the two of them, and then averages Args: **pipeline_kwargs: keyword arguments for the base class of ModelPipeline loose_beta_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() for the loose beta model tight_beta_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() fro the tight beta model loose_p_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() for the loose p model tight_p_fit_dict: dictionary of keyword arguments to CurveModel.fit_params() fro the tight p model basic_model_dict: additional keyword arguments to the CurveModel class col_obs_se: (str) of observation standard error col_covs: List[str] list of names of covariates to put on the parameters param_names (list{str}): Names of the parameters in the specific functional form. link_fun (list{function}): List of link functions for each parameter. var_link_fun (list{function}): List of link functions for the variables including fixed effects and random effects. beta_model_extras: (optional) dictionary of keyword arguments to override the basic_model_kwargs for the beta model p_model_extras: (optional) dictionary of keyword arguments to override the basic_model_kwargs for the p model blend_start_t: (int) the time to start blending tight and loose blend_end_t: (int) the time to stop blending tight and loose """ super().__init__(**pipeline_kwargs) generator_kwargs = pipeline_kwargs for arg in self.pop_cols: generator_kwargs.pop(arg) self.basic_model_dict = basic_model_dict self.basic_model_dict.update(**generator_kwargs) self.basic_model_dict.update({'col_obs_se': self.col_obs_se}) self.beta_model_kwargs = self.basic_model_dict self.p_model_kwargs = self.basic_model_dict if beta_model_extras is not None: self.beta_model_kwargs = self.beta_model_kwargs.update( beta_model_extras) if p_model_extras is not None: self.p_model_kwargs = self.p_model_kwargs.update(p_model_extras) self.loose_beta_fit_dict = loose_beta_fit_dict self.tight_beta_fit_dict = tight_beta_fit_dict self.loose_p_fit_dict = loose_p_fit_dict self.tight_p_fit_dict = tight_p_fit_dict self.blend_start_t = blend_start_t self.blend_end_t = blend_end_t self.loose_beta_model = None self.tight_beta_model = None self.loose_p_model = None self.tight_p_model = None self.setup_pipeline() def refresh(self): self.loose_beta_model = None self.tight_beta_model = None self.loose_p_model = None self.tight_p_model = None def fit(self, df): self.loose_beta_model = CurveModel(df=df, **self.beta_model_kwargs) self.tight_beta_model = CurveModel(df=df, **self.beta_model_kwargs) self.loose_p_model = CurveModel(df=df, **self.p_model_kwargs) self.tight_p_model = CurveModel(df=df, **self.p_model_kwargs) self.loose_beta_model.fit_params(**self.loose_beta_fit_dict) self.tight_beta_model.fit_params(**self.tight_beta_fit_dict) self.loose_p_model.fit_params(**self.loose_p_fit_dict) self.tight_p_model.fit_params(**self.tight_p_fit_dict) def predict(self, times, predict_space, predict_group): loose_beta_predictions = self.loose_beta_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) tight_beta_predictions = self.tight_beta_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) loose_p_predictions = self.loose_p_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) tight_p_predictions = self.tight_p_model.predict( t=times, group_name=predict_group, prediction_functional_form=predict_space) beta_predictions = convex_combination(t=times, pred1=tight_beta_predictions, pred2=loose_beta_predictions, pred_fun=predict_space, start_day=self.blend_start_t, end_day=self.blend_end_t) p_predictions = convex_combination(t=times, pred1=tight_p_predictions, pred2=loose_p_predictions, pred_fun=predict_space, start_day=self.blend_start_t, end_day=self.blend_end_t) averaged_predictions = model_average(pred1=beta_predictions, pred2=p_predictions, w1=0.5, w2=0.5, pred_fun=predict_space) return averaged_predictions
class BasicModelWithInit(BasicModel): def __init__(self, smart_init_options=None, **kwargs): if smart_init_options is None: smart_init_options = {} self.smart_init_options = smart_init_options super().__init__(**kwargs) if self.fit_dict['options']: self.smart_init_options = { **self.fit_dict['options'], **self.smart_init_options } self.init_dict = None self.mod = None def run_init_model(self): self.init_dict = self.get_init_dict(df=self.all_data, groups=self.groups) def update_init_model(self, df, group): """ Update the initial model with a re-fit model from the specified group. Returns a new copy of the init dict Args: df: (pd.DataFrame) data used to update the init model group: (str) the group to update Returns: """ new_init_dict = deepcopy(self.init_dict) new_init_dict.update(self.get_init_dict(df=df, groups=[group])) return new_init_dict def get_init_dict(self, df, groups): """ Run the init model for each location. Args: df: (pd.DataFrame) data frame to fit the model that will be subset by group groups: (str) groups to get in the dict Returns: (dict) dictionary of fixed effects keyed by group """ model = CurveModel(df=df, **self.basic_model_dict) init_fit_dict = deepcopy(self.fit_dict) init_fit_dict.update(options=self.smart_init_options) init_dict = get_initial_params(groups=groups, model=model, fit_arg_dict=init_fit_dict) return init_dict def fit(self, df, group=None): """ Fits a loose, tight, beta, and p combinations model. If you pass in update group it will override the initial parameters with new initial parameters based on the df you pass. Args: df: group: (str) passing in the group will update the initialization dictionary (not replacing the old one) for this particular fit. Returns: """ if group is not None: init_dict = self.update_init_model(df=df, group=group) else: init_dict = deepcopy(self.init_dict) fit_dict = deepcopy(self.fit_dict) fe_init, re_init = compute_starting_params(init_dict) fit_dict.update(fe_init=fe_init, re_init=re_init) self.mod = CurveModel(df=df, **self.basic_model_dict) self.mod.fit_params(**fit_dict) def refresh(self): self.mod = None