Skip to content

cycles_extractor

cycles_extractor ¤

Cut a signal into production cycles.

Every process_* method returns one row per cycle with the columns cycle_start, cycle_end, cycle_uuid, is_complete and the canonical interval columns start, end, duration_seconds, uuid ("cycles:<method>") and source_uuid (the start signal). Rules shared by all methods:

  • Only the rows of start_uuid (and end_uuid) are read; other signals in the frame are ignored. A frame without a uuid column is taken as one pre-filtered signal.
  • Time columns keep the input's dtype (a tz-aware systime stays tz-aware).
  • An end closes the cycle that is open at that moment. At one timestamp, an end is applied before a start, so back-to-back cycles may share a timestamp (the end of one is the start of the next).
  • A second start while a cycle is open aborts the open cycle: it stays in the output with cycle_end = NaT and is_complete = False, and the end goes to the newer start. Cycles never overlap.
  • An end with no open cycle (for example before the first start) is ignored and counted in get_extraction_stats()["unmatched_ends"].
  • is_complete is True only when both boundaries were seen. A cycle with no end (the last one, or an aborted one) has cycle_end = NaT. A cycle that was already running at the first sample (its real start lies before the data) keeps its observed end but has is_complete = False.
  • Several start rows at the same timestamp are one start.
  • cycle_uuid is deterministic: the same signal, method and start time always give the same id, so ids are stable across runs and unique within a result.
  • No cycles: an empty frame with the full column set.

CycleExtractor ¤

CycleExtractor(
    dataframe: DataFrame,
    start_uuid: str,
    end_uuid: str | None = None,
    value_change_threshold: float = 0.0,
    *,
    time_column: str = "systime",
    uuid_column: str = "uuid"
)

Bases: Base

Class for processing cycles based on different criteria.

Initializes the class with the data and the UUIDs for cycle start and end.

Parameters:

Name Type Description Default
dataframe DataFrame

Input DataFrame with cycle data

required
start_uuid str

UUID for cycle start variable

required
end_uuid str | None

UUID for cycle end variable (defaults to start_uuid)

None
value_change_threshold float

Minimum threshold for considering a value change significant (default: 0.0)

0.0
time_column str

Timestamp column. Default "systime".

'systime'
uuid_column str

Signal identifier column. Default "uuid". A frame without it is taken as one pre-filtered signal.

'uuid'

Raises:

Type Description
ColumnNotFoundError

If dataframe has no time_column.

ValueError

If start_uuid is not a string.

process_persistent_cycle ¤

process_persistent_cycle() -> pd.DataFrame

Processes cycles where the value of the variable stays true during the cycle.

A cycle starts at a rising edge (False -> True) and ends at the next falling edge (True -> False), i.e. at the first False sample. A missing sample holds the previous state. A signal already True at its first sample gives a first cycle with is_complete = False.

Returns:

Type Description
DataFrame

One row per cycle (see the module docstring); empty, with the full column set, when no cycle is found.

process_trigger_cycle ¤

process_trigger_cycle() -> pd.DataFrame

Processes cycles triggered by a true pulse (true, then back to false).

Each trigger starts a cycle that ends at the next trigger. A trigger is a rising edge (False -> True); for a signal that is never False (an event log of True rows) every row is a trigger. The last trigger gives an incomplete cycle.

Returns:

Type Description
DataFrame

One row per cycle (see the module docstring); empty, with the full column set, when no cycle is found.

process_separate_start_end_cycle ¤

process_separate_start_end_cycle() -> pd.DataFrame

Processes cycles where different variables indicate cycle start and end.

Start events are the True events of start_uuid, end events the True events of end_uuid (a held True counts once, at its rising edge; a signal that is never False is an event log where every True row counts). An end closes the open cycle; a second start aborts it. When end_uuid equals start_uuid (or the frame has no uuid column), each event closes the previous cycle and opens the next.

Returns:

Type Description
DataFrame

One row per cycle (see the module docstring); empty, with the full column set, when no cycle is found.

process_step_sequence ¤

process_step_sequence(
    start_step: int, end_step: int
) -> pd.DataFrame

Processes cycles based on a step sequence, where specific integer values denote cycle start and end.

Parameters:

Name Type Description Default
start_step int

value_integer step that opens a cycle when the signal enters it.

required
end_step int

value_integer step that closes the open cycle when the signal enters it.

required

Returns:

Type Description
DataFrame

One row per cycle (see the module docstring); cycle_end is NaT for a cycle that never closes. A step held over several samples is entered once; a missing sample holds the previous step. With start_step == end_step each entry closes the previous cycle and opens the next.

process_state_change_cycle ¤

process_state_change_cycle() -> pd.DataFrame

Processes cycles where the start of a new cycle is the end of the previous cycle.

Every sample of the signal is a boundary: a cycle runs from one sample to the next later one. The first cycle starts at the first sample, whose state began before the data, so it is marked incomplete.

Returns:

Type Description
DataFrame

One row per cycle (see the module docstring); empty, with the full column set, when no cycle is found.

process_value_change_cycle ¤

process_value_change_cycle() -> pd.DataFrame

Processes cycles where a change in the value indicates a new cycle.

A sample is a boundary when one of its value columns differs from the previous sample: numbers by more than value_change_threshold (compared sample to sample), bools and strings by any change. A missing value holds the previous one. The first sample is a boundary too; its cycle began before the data and is marked incomplete.

Returns:

Type Description
DataFrame

One row per cycle (see the module docstring); empty, with the full column set, when no cycle is found.

validate_cycles ¤

validate_cycles(
    cycle_df: DataFrame,
    min_duration: str = "1s",
    max_duration: str = "1h",
    warn: bool = True,
) -> pd.DataFrame

Validate cycles based on duration constraints.

Parameters:

Name Type Description Default
cycle_df DataFrame

DataFrame with cycle data (output from process_* methods)

required
min_duration str

Minimum acceptable cycle duration (default: '1s')

'1s'
max_duration str

Maximum acceptable cycle duration (default: '1h')

'1h'
warn bool

Whether to emit a :class:~ts_shape.errors.DataQualityWarning for invalid cycles (default: True)

True

Returns:

Type Description
DataFrame

A copy of cycle_df with cycle_duration (Timedelta), duration_seconds, is_valid and validation_issue ("", "incomplete_cycle", "too_short;" or "too_long;"). Incomplete cycles are invalid; the duration bounds are inclusive. An empty input gives an empty frame with these columns.

detect_overlapping_cycles ¤

detect_overlapping_cycles(
    cycle_df: DataFrame, resolve: str = "flag"
) -> pd.DataFrame

Detect and optionally resolve overlapping cycles.

Two cycles overlap when one starts strictly before the other ends, so back-to-back cycles sharing a timestamp do not overlap. Only cycles with a known end are compared.

Parameters:

Name Type Description Default
cycle_df DataFrame

DataFrame with cycle data

required
resolve str

How to handle overlaps - 'flag' (mark only), 'keep_first' (earliest start wins), 'keep_last' (latest start wins), 'keep_longest' (longest wins). Resolution is greedy, so the kept cycles never overlap and a cycle is dropped only when it overlaps a kept one.

'flag'

Returns:

Type Description
DataFrame

cycle_df sorted by cycle_start with a has_overlap column; for a keep_* strategy the dropped cycles are removed.

Raises:

Type Description
ValueError

For an unknown resolve.

suggest_method ¤

suggest_method() -> dict[str, Any]

Suggest the best cycle extraction method based on data characteristics.

Analyzes the start signal's rows to recommend extraction method(s).

Returns:

Type Description
dict[str, Any]

Dictionary with method suggestions and reasoning

get_extraction_stats ¤

get_extraction_stats() -> dict[str, Any]

Get statistics about the last cycle extraction.

Returns:

Type Description
dict[str, Any]

Dictionary with total_cycles, complete_cycles, incomplete_cycles, unmatched_starts (cycles without an end), unmatched_ends (ends with no open cycle), partial_first_cycles, overlapping_cycles (from the last detect_overlapping_cycles), warnings, success_rate and configuration.

reset_stats ¤

reset_stats() -> None

Reset extraction statistics.