GradualDrift#

class capymoa.stream.drift.GradualDrift[source]#

Bases: Drift

A drift where two concepts overlap over a window of instances.

The location can be given in either of two mutually exclusive ways, which describe the same drift:

>>> from capymoa.stream.drift import GradualDrift
>>> print(GradualDrift(position=100, width=10))
GradualDrift(position=100, start=95, end=105, width=10)
>>> print(GradualDrift(start=95, end=105))
GradualDrift(position=100, start=95, end=105, width=10)

start and end mark where the transition is centred, not where the concepts stop overlapping. The default ramp is the logistic MOA uses, 1 / (1 + exp(-4 (n - position) / width)), which reaches 0.12 at start and 0.88 at end and approaches 0 and 1 only asymptotically. So roughly 12% of instances at the nominal end still come from the older concept, and a few continue to appear well beyond it. A ramp that saturates exactly at the window edges is a different function, not a different width.

transition_function chooses the ramp across the window: "sigmoid" (the default, scaled so the transition completes within the window), "linear", or a callable mapping progress through the window – 0.0 at the start, 1.0 at the end – to the probability of the new concept. A callable is clipped at the window edges, so a ramp that has not finished by the end of the window is cut off there. To spread a transition over more instances, widen the window rather than stretching the function.

>>> print(GradualDrift(position=100, width=10, transition_function="linear"))
GradualDrift(position=100, start=95, end=105, width=10)

A third form gives the drift a length and lets DriftStream work out where it lands from the concepts around it – see Concept:

>>> unplaced = GradualDrift(num_instances=500)
>>> unplaced.width, unplaced.position
(500, None)

Supplying neither style, or only half of one, is an error – rather than building a drift with no location:

>>> GradualDrift(position=100)
Traceback (most recent call last):
    ...
ValueError: GradualDrift needs exactly one of ``position`` and ``width``, ``start`` and ``end``, or ``num_instances``, to locate the drift. Got position=100.
>>> GradualDrift(position=100, start=95)
Traceback (most recent call last):
    ...
ValueError: GradualDrift needs exactly one of ``position`` and ``width``, ``start`` and ``end``, or ``num_instances``, to locate the drift. Got position=100, start=95.
__init__(
position=None,
width=None,
start=None,
end=None,
*,
num_instances=None,
transition_function='sigmoid',
random_seed=1,
)[source]#

Construct a drift in a DriftStream.

Parameters:
  • position – The location of the drift in terms of the number of instances processed prior to it occurring.

  • width – The size of the window of change. A width of 0 or 1 corresponds to an abrupt drift.

  • random_seed – Seed for random number generation, defaults to 1. Keyword-only, so a leftover positional argument from the removed alpha parameter fails at the call site rather than silently becoming the seed.