DriftStream#
- class capymoa.stream.drift.DriftStream[source]#
Bases:
StreamA stream composed of concepts separated by drifts.
The stream is defined as a list that alternates concepts and drifts, starting and ending with a concept. There are two forms, and a definition must use one or the other throughout.
Positions – each drift says where it happens:
>>> from capymoa.stream.drift import DriftStream, AbruptDrift, GradualDrift >>> from capymoa.stream.generator import SEA >>> stream = DriftStream(stream=[ ... SEA(function=1), ... AbruptDrift(position=5000), ... SEA(function=3), ... GradualDrift(position=10000, width=2000), ... SEA(function=1), ... ]) >>> stream.get_num_drifts() 2
Ranges – each concept says how long it lasts, and the drifts are placed by what surrounds them. Every concept is wrapped in
Concept, drifts carry no position, and aGradualDriftgives its length instead of a width:>>> from capymoa.stream.drift import Concept >>> stream = DriftStream(stream=[ ... Concept(SEA(function=1), num_instances=5000), ... AbruptDrift(), ... Concept(SEA(function=3), num_instances=5000), ... GradualDrift(num_instances=2000), ... Concept(SEA(function=1), num_instances=1000), ... ]) >>> for drift in stream.get_drifts(): ... print(drift) AbruptDrift(position=5000) GradualDrift(position=11000, start=10000, end=12000, width=2000)
The two cannot be combined. A range definition does not say where its drifts land, so a position supplied alongside it would describe a location the rest of the definition contradicts. Mixing them is rejected rather than resolved by guesswork.
Use
describe()to see how many instances each concept actually contributed, which around aGradualDriftis not what the declared lengths suggest.Composition happens in Python: instances are drawn from the concept selected for the current position, and across a
GradualDriftthe choice is a per-instance draw against the transition ramp. Earlier versions delegated this to MOA’sConceptDriftStream, which meant every concept had to be a MOA-backed stream.DriftStreamis therefore a plainStreamrather than aMOAStream. Where a MOA object is genuinely needed – to hand the stream to MOA code, or to print a MOA CLI – useto_moa_stream(), which builds the equivalent nestedConceptDriftStream. That conversion needs every concept to be MOA-backed, so it is offered explicitly instead of being the implementation.- __init__(schema=None, CLI=None, moa_stream=None, stream=None)[source]#
Initialize the stream.
- Parameters:
schema – The schema of the stream. Taken from the first concept when not given.
CLI – Command Line Interface string describing a MOA
ConceptDriftStream. Kept for backward compatibility; the stream is then backed by MOA rather than composed in Python.moa_stream – A pre-configured
ConceptDriftStreamfrom MOA, used together withCLI.stream – The list of concepts and drifts to compose, alternating and starting with a concept.
- __iter__() Iterator[_AnyInstance][source]#
Get an iterator over the stream.
This will NOT restart the stream if it has already been iterated over. Please use the
restart()method to restart the stream.- Yield:
An iterator over the stream.
- __next__() _AnyInstance[source]#
Get the next instance in the stream.
- Returns:
The next instance in the stream.
- describe(horizon: int = None) str[source]#
A readable summary of where the first
num_instancescome from.Intended for reporting a stream in a paper or notebook, where the drift positions alone do not say how much of each concept was actually seen.
- Parameters:
horizon – How many instances to account for. Defaults to the length the definition implies, which the report labels as exact or estimated.
- Returns:
A table of concepts, their counts and shares, followed by the drifts. When the stream was defined with lengths, the declared length is shown alongside for comparison.
- get_concept_counts(horizon: int = None)[source]#
How many of the first
num_instancescome from each concept.Around an
AbruptDriftthis follows from the definition, but around aGradualDriftthe concepts overlap and the split is a property of the transition ramp, which can keep drawing from the older concept past the nominal end of the window. This reports what actually happens.The stream does not need to be run. Each transition decides using only its own seeded generator and its own counter – the instances never enter the decision – so the routing is replayed with fresh generators and reproduces the same branch pattern without generating any data. That makes it exact rather than an estimate, and fast enough to ask about millions of instances.
>>> from capymoa.stream.drift import Concept, DriftStream, GradualDrift >>> from capymoa.stream.generator import SEA >>> stream = DriftStream(stream=[ ... Concept(SEA(function=1), num_instances=1000), ... GradualDrift(num_instances=500), ... Concept(SEA(function=3), num_instances=500), ... ]) >>> stream.get_concept_counts(2000) [1251, 749]
- Parameters:
horizon – How many instances to account for, counted from the start of the stream. Defaults to the length the definition implies – exact for the range form, estimated for the position form, whose final concept is open-ended.
- Returns:
One count per concept, in the order they were defined. Concepts appearing more than once are counted separately.
- get_moa_stream()[source]#
Return the backing MOA stream, if there is one.
A Python-composed
DriftStreamhas no single MOA object behind it. Useto_moa_stream()to build one.
- next_instance()[source]#
Return the next instance in the stream.
- Raises:
ValueError – If the machine learning task is neither a regression nor a classification task.
- Returns:
A labeled instances or a regression depending on the schema.
- to_moa_stream()[source]#
Build the equivalent MOA
ConceptDriftStream.Provided for interoperability with MOA code and for inspecting the generated CLI. Requires every concept to be MOA-backed, which is the restriction Python composition exists to remove – so this raises when the stream contains a concept MOA cannot represent.
- Returns:
A
MOAStreamwrapping the nestedConceptDriftStream.
- property length#
How many instances the stream produces, if that is known.
A range definition states its own length – every concept and gradual drift contributes its declared number of instances – and the stream ends there. A position definition has an open-ended final concept, so this is
None.
- property moa_stream#
The backing MOA stream object, or
Nonewhen composed in Python.Kept so a
DriftStreambuilt from a MOA CLI still works with code that reaches for the attribute directly, such as the optimised evaluation loops.