runs
runs ¤
Vectorized run-length helpers.
Many detectors collapse consecutive equal values -- a boolean condition mask
or a state / identifier column -- into runs and then compute something per
run. The pandas idiom df.groupby((s != s.shift()).cumsum()) followed by a
Python loop over the groups costs tens of microseconds per run; these helpers
find the run boundaries with one comparison and aggregate per run with
ufunc.reduceat.
:func:run_bounds returns every run of equal consecutive values,
:func:true_runs only the runs where a boolean mask is True, and
:func:run_agg aggregates a value array per run.
Run boundaries follow the pandas idiom (s != s.shift()).cumsum() exactly:
a missing value (NaN, None, NaT, pd.NA) never equals anything,
so by default each missing value is a run of its own. Pass
nan_equal=True to merge consecutive missing values into one run instead.
(For nullable extension dtypes the idiom compares to <NA> next to a
missing value and groupby then drops those rows; :func:run_bounds keeps
them as runs of their own.)
Runs ¤
Bases: NamedTuple
Positional bounds of runs.
Attributes:
| Name | Type | Description |
|---|---|---|
starts |
_Ints
|
Position of the first element of each run. |
ends |
_Ints
|
Position one past the last element of each run (exclusive,
like a slice stop), so |
lengths |
_Ints
|
Number of elements per run ( |
run_bounds ¤
run_bounds(values: Any, *, nan_equal: bool = False) -> Runs
Find the runs of equal consecutive values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Any
|
A 1-d array, Series or Index of any dtype (numeric, boolean, datetime, string, object, categorical, nullable extension types). The order is taken as given; sort first if needed. |
required |
nan_equal
|
bool
|
|
False
|
Returns:
| Type | Description |
|---|---|
Runs
|
class: |
Runs
|
|
Runs
|
arrays. |
true_runs ¤
true_runs(mask: Any) -> Runs
Runs where a boolean mask is True.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
mask
|
Any
|
Boolean array or Series. Missing values (nullable boolean) count
as |
required |
Returns:
| Type | Description |
|---|---|
Runs
|
class: |
run_labels ¤
run_labels(runs: Runs) -> _Ints
Run number (0, 1, ...) per element covered by runs, in order.
For runs that tile the array (from :func:run_bounds) this is one label
per element; for :func:true_runs only the True elements are covered
(see :func:run_positions for their positions).
run_agg ¤
run_agg(
values: Any, runs: Runs, funcs: str | Iterable[str]
) -> Any
Aggregate values per run.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
values
|
Any
|
1-d array or Series aligned with the array the runs were found on (positionally). |
required |
runs
|
Runs
|
Runs from :func: |
required |
funcs
|
str | Iterable[str]
|
One aggregation name or several, from :data:
Numeric aggregations work in |
required |
Returns:
| Type | Description |
|---|---|
Any
|
One array (one entry per run) for a single name, else a dict of |
Any
|
name -> array. |
run_positions ¤
run_positions(runs: Runs) -> _Ints
Positions of all elements covered by runs, in order.
Aligned with :func:run_labels: element i of both belongs together.
run_argmax ¤
run_argmax(values: Any, runs: Runs) -> _Ints
Position of the first maximum of values in each run.
Like Series.idxmax() per run (NaN skipped), but returns positions.
A run whose values are all NaN gives its first position.
total_seconds ¤
total_seconds(deltas: Any) -> npt.NDArray[np.float64]
Seconds per timedelta, bit-identical to scalar Timedelta.total_seconds().
The scalar method computes days * 86400 + seconds + microseconds / 1e6
(dropping sub-microsecond precision); the vectorized
TimedeltaIndex.total_seconds() divides nanoseconds by 1e9, which
can differ in the last bit. Use this when replacing a per-row
(end - start).total_seconds() loop. NaT gives NaN.