# `GradualDrift`

### *class* capymoa.stream.drift.GradualDrift[[source]](https://github.com/adaptive-machine-learning/CapyMOA/blob/3e255b1/src/capymoa/stream/drift.py#L826)

Bases: [`Drift`](capymoa.stream.drift.Drift.md#capymoa.stream.drift.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:

```pycon
>>> 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.

```pycon
>>> 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`](capymoa.stream.drift.DriftStream.md#capymoa.stream.drift.DriftStream) work
out where it lands from the concepts around it – see [`Concept`](capymoa.stream.drift.Concept.md#capymoa.stream.drift.Concept):

```pycon
>>> 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:

```pycon
>>> 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.
```

```pycon
>>> 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]](https://github.com/adaptive-machine-learning/CapyMOA/blob/3e255b1/src/capymoa/stream/drift.py#L879)

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.
