22
33import abc
44import copy
5- from typing import Union , Optional
5+ from typing import List , Union , Optional
66
77import numpy as np # type: ignore
88from scipy .special import logsumexp # type: ignore
99from scipy .stats import norm # type: ignore
1010
11+ from frouros .callbacks .streaming .base import BaseCallbackStreaming
1112from frouros .detectors .concept_drift .streaming .change_detection .base import (
1213 BaseChangeDetection ,
1314 BaseChangeDetectionConfig ,
@@ -122,8 +123,8 @@ def var_params(self):
122123class BOCDConfig (BaseChangeDetectionConfig ):
123124 """BOCD (Bayesian Online Change Detection) [adams2007bayesian]_ configuration.
124125
125- :param model: BOCD model, (e.g. :class:`frouros.detectors.concept_drift.streaming.change_detection.bocd.GaussianUnknownMean`)
126- :type model: BaseBOCDModel
126+ :param model: BOCD model, defaults to None. If None, :class:`frouros.detectors.concept_drift.streaming.change_detection.bocd.GaussianUnknownMean` is used.
127+ :type model: Optional[ BaseBOCDModel]
127128 :param hazard: hazard value, defaults to 0.01
128129 :type hazard: float
129130 :param min_num_instances: minimum numbers of instances to start looking for changes, defaults to 30
@@ -136,9 +137,11 @@ class BOCDConfig(BaseChangeDetectionConfig):
136137 arXiv preprint arXiv:0710.3742 (2007).
137138 """ # noqa: E501
138139
140+ model_type = GaussianUnknownMean
141+
139142 def __init__ ( # noqa: D107
140143 self ,
141- model : BaseBOCDModel = GaussianUnknownMean , # type: ignore
144+ model : Optional [ BaseBOCDModel ] = None , # type: ignore
142145 hazard : float = 0.01 ,
143146 min_num_instances : int = 30 ,
144147 ) -> None :
@@ -166,20 +169,23 @@ def model(self, model: BaseBOCDModel) -> None:
166169 :type model: BaseBOCDModel
167170 :raises TypeError: if model is not an instance of BaseModel
168171 """
169- if not isinstance (model , BaseBOCDModel ):
170- raise TypeError (
171- f"model must be an instance of BaseModel, not { type (model )} "
172- )
173- self ._model = model
172+ if model is not None :
173+ if not isinstance (model , BaseBOCDModel ):
174+ raise TypeError (
175+ f"model must be an instance of BaseModel, not { type (model )} "
176+ )
177+ self ._model = model
178+ else :
179+ self ._model = self .model_type ()
174180
175181
176182class BOCD (BaseChangeDetection ):
177183 """BOCD (Bayesian Online Change Detection) [adams2007bayesian]_ detector.
178184
179- :param config: configuration object of the detector
180- :type config: BOCDConfig
181- :param callbacks: list of callbacks, defaults to None
182- :type callbacks: list, optional
185+ :param config: configuration object of the detector, defaults to None. If None, the default configuration of :class:`BOCDConfig` is used.
186+ :type config: Optional[ BOCDConfig]
187+ :param callbacks: callbacks, defaults to None
188+ :type callbacks: Optional[Union[BaseCallbackStreaming, List[BaseCallbackStreaming]]]
183189
184190 :Note:
185191 Adapted from the implementation in https://github.com/gwgundersen/bocd.
@@ -192,14 +198,13 @@ class BOCD(BaseChangeDetection):
192198
193199 :Example:
194200
195- >>> from frouros.detectors.concept_drift import BOCD, BOCDConfig
196- >>> from frouros.detectors.concept_drift.streaming.change_detection.bocd import GaussianUnknownMean
201+ >>> from frouros.detectors.concept_drift import BOCD
197202 >>> import numpy as np
198203 >>> np.random.seed(seed=31)
199204 >>> dist_a = np.random.normal(loc=0.2, scale=0.01, size=1000)
200205 >>> dist_b = np.random.normal(loc=0.8, scale=0.04, size=1000)
201206 >>> stream = np.concatenate((dist_a, dist_b))
202- >>> detector = BOCD(config=BOCDConfig(model=GaussianUnknownMean()) )
207+ >>> detector = BOCD()
203208 >>> for i, value in enumerate(stream):
204209 ... _ = detector.update(value=value)
205210 ... if detector.drift:
@@ -211,9 +216,11 @@ class BOCD(BaseChangeDetection):
211216 config_type = BOCDConfig # type: ignore
212217
213218 def __init__ ( # noqa: D107
214- self ,
215- config : BOCDConfig ,
216- callbacks : list = None ,
219+ self ,
220+ config : Optional [BOCDConfig ] = None ,
221+ callbacks : Optional [
222+ Union [BaseCallbackStreaming , List [BaseCallbackStreaming ]]
223+ ] = None ,
217224 ) -> None :
218225 super ().__init__ (
219226 config = config ,
0 commit comments