@@ -41,6 +41,7 @@ def __init__(
4141 allow_negative_predictions : bool = False ,
4242 granularity : Granularity = None ,
4343 single_use_exog_prefixes : list [str ] = None ,
44+ exogs__disallow_negative_coefficient : list [str ] = None ,
4445 ):
4546 """Parameters
4647 ----------
@@ -72,6 +73,8 @@ def __init__(
7273 will be used as an independent variable.
7374 Once the best fit using a variable with a given prefix is found, the other variables with the same
7475 prefix will not be used as independent variables.
76+ exogs__disallow_negative_coefficient : list of str, default=None
77+ List of variable names for which the coefficient is not allowed to be negative.
7578 """
7679 self .data = data .copy ()
7780 if y not in self .data .columns :
@@ -87,6 +90,7 @@ def __init__(
8790 self .allow_negative_predictions = allow_negative_predictions
8891 self .granularity = granularity
8992 self .single_use_exog_prefixes = single_use_exog_prefixes
93+ self .exogs__disallow_negative_coefficient = exogs__disallow_negative_coefficient
9094 self ._fit = None
9195 self ._list_of_fits = []
9296 self .list_of_cverrors = []
@@ -161,6 +165,15 @@ def _do_analysis_no_cross_validation(self):
161165 ref_fit .model .formula .rhs_termlist + [term ],
162166 )
163167 fit = fm .ols (model_desc , data = self .data ).fit ()
168+
169+ # Check if the coefficient of the variable is allowed to be negative
170+ if (
171+ self .exogs__disallow_negative_coefficient is not None
172+ and x in self .exogs__disallow_negative_coefficient
173+ and fit .params [x ] < 0
174+ ):
175+ continue
176+
164177 if fit .bic < best_bic :
165178 best_bic = fit .bic
166179 best_fit = fit
@@ -174,20 +187,20 @@ def _do_analysis_no_cross_validation(self):
174187 ref_fit .model .formula .rhs_termlist ,
175188 ):
176189 break
177- else :
178- self ._list_of_fits .append (best_fit )
179- all_model_terms_dict .pop (best_x )
180-
181- # Check if `best_x` starts with a prefix that should only be used once
182- # If so, remove all other variables with the same prefix from the list of candidates
183- if self .single_use_exog_prefixes :
184- for prefix in self .single_use_exog_prefixes :
185- if best_x .startswith (prefix ):
186- all_model_terms_dict = {
187- k : v
188- for k , v in all_model_terms_dict .items ()
189- if not k .startswith (prefix )
190- }
190+
191+ self ._list_of_fits .append (best_fit )
192+ all_model_terms_dict .pop (best_x )
193+
194+ # Check if `best_x` starts with a prefix that should only be used once
195+ # If so, remove all other variables with the same prefix from the list of candidates
196+ if self .single_use_exog_prefixes :
197+ for prefix in self .single_use_exog_prefixes :
198+ if best_x .startswith (prefix ):
199+ all_model_terms_dict = {
200+ k : v
201+ for k , v in all_model_terms_dict .items ()
202+ if not k .startswith (prefix )
203+ }
191204
192205 self ._fit = self ._list_of_fits [- 1 ]
193206
0 commit comments