Skip to content

root_cause_correlation

root_cause_correlation ¤

Event-driven root-cause ranking: which signal led the events we detected?

:class:~ts_shape.events.correlation.anomaly_correlation.AnomalyCorrelationEvents works signal-to-signal: it z-scores every signal, finds anomalies, and asks which signal's anomalies tend to come first. That is undirected discovery, and it can only rank signals whose own anomalies were detectable.

This detector runs the directed version. It takes the events another detector already produced -- an SPC violation, a downtime interval, a scrap booking -- and asks, for each candidate signal, whether that signal moves before those events, and by how much lead time. Only non-negative lags are tested: a cause precedes its effect, and searching negative lags would happily "explain" a stoppage with the temperature drop it caused.

Correlation is computed against a binary onset series on a resampled grid. Scanning many lags and keeping the strongest is a multiple comparison, so the p-value of the winning lag is Bonferroni-corrected by the number of lags tested: without that, noise scanned over 30 lags looks "significant" about as often as not, and every candidate would be promoted to root cause.

RootCauseCorrelationEvents ¤

RootCauseCorrelationEvents(
    dataframe: DataFrame,
    *,
    event_uuid: str = "corr:root_cause",
    value_column: str = "value_double",
    time_column: str = "systime",
    uuid_column: str = "uuid"
)

Bases: Base

Correlation: rank candidate causes for a set of detected events.

trigger_events is any detector's output — the onset timestamp is read from systime (point events) or start (interval/summary events)::

stops = LongDowntimeEvents(df, ...).detect_long_downtime(min_gap="10min")
rc = RootCauseCorrelationEvents(df)
rc.rank_causes(stops, ["temp:spindle", "press:hydraulic", "flow:coolant"])

Methods: - rank_causes: Ranked causal candidates with lag and p-value. - top_cause: Single-row verdict naming the best-supported candidate. - lag_profile: Correlation-vs-lag curve for one candidate signal.

Initialize the root-cause ranker.

Parameters:

Name Type Description Default
dataframe DataFrame

Timeseries frame holding the candidate signals.

required
event_uuid str

UUID stamped on emitted rows.

'corr:root_cause'
value_column str

Column holding the numeric readings.

'value_double'
time_column str

Timestamp column.

'systime'
uuid_column str

Column identifying the signal.

'uuid'

rank_causes ¤

rank_causes(
    trigger_events: DataFrame,
    candidate_uuids: list[str],
    *,
    window: str = "1min",
    max_lag: int = 30,
    p_threshold: float = 0.05,
    trigger_uuid: str | None = None,
    trigger_event_type: str | None = None,
    only_significant: bool = False
) -> pd.DataFrame

Rank candidate signals by how strongly they lead the trigger events.

Parameters:

Name Type Description Default
trigger_events DataFrame

Event frame whose onsets are being explained.

required
candidate_uuids list[str]

Signals to test as possible causes.

required
window str

Grid resolution (offset string); also the unit of max_lag.

'1min'
max_lag int

Largest lead tested, in window periods.

30
p_threshold float

Bonferroni-corrected p-value at or below which a candidate is marked significant.

0.05
trigger_uuid str | None

Identifier of the triggering signal, for the audit trail. Defaults to the source_uuid carried by trigger_events when it has one.

None
trigger_event_type str | None

Label of the triggering event. Defaults to the uuid carried by trigger_events when it has one.

None
only_significant bool

Drop candidates above p_threshold.

False

Returns:

Type Description
DataFrame

Static-shape DataFrame, ranked by absolute correlation:

DataFrame

uuid, trigger_event_type, trigger_uuid,

DataFrame

candidate_uuid, correlation_coefficient, lag_seconds,

DataFrame

p_value (raw, at the winning lag), p_value_adjusted

DataFrame

(Bonferroni over the lag scan), significant, sample_count,

DataFrame

trigger_count, rank, method.

top_cause ¤

top_cause(
    trigger_events: DataFrame,
    candidate_uuids: list[str],
    *,
    window: str = "1min",
    max_lag: int = 30,
    p_threshold: float = 0.05,
    trigger_uuid: str | None = None,
    trigger_event_type: str | None = None
) -> pd.DataFrame

Name the best-supported cause, or report that none qualifies.

Only significant candidates are eligible: when no candidate clears p_threshold the row still comes back — with top_cause_uuid set to None and the tested counts filled in — so a search that found nothing is visible rather than silently empty.

Parameters:

Name Type Description Default
trigger_events DataFrame

Event frame whose onsets are being explained.

required
candidate_uuids list[str]

Signals to test as possible causes.

required
window str

Grid resolution (offset string); also the unit of max_lag.

'1min'
max_lag int

Largest lead tested, in window periods.

30
p_threshold float

Significance level for eligibility.

0.05
trigger_uuid str | None

See :meth:rank_causes.

None
trigger_event_type str | None

See :meth:rank_causes.

None

Returns:

Type Description
DataFrame

Static-shape DataFrame with a single row: uuid,

DataFrame

trigger_event_type, trigger_uuid, top_cause_uuid,

DataFrame

top_cause_lag_seconds, top_cause_correlation, p_value,

DataFrame

p_value_adjusted, confidence, candidates_tested,

DataFrame

candidates_significant, trigger_count, method.

lag_profile ¤

lag_profile(
    trigger_events: DataFrame,
    candidate_uuid: str,
    *,
    window: str = "1min",
    max_lag: int = 30
) -> pd.DataFrame

Correlation against the trigger onsets at every tested lag.

The curve is the diagnostic behind :meth:rank_causes: a genuine cause peaks at one lead time and falls away, while a spurious match tends to wander without a clear peak. p_value here is the raw per-lag value — the whole point of the profile is to see every lag, so no multiple-comparison correction is applied; use :meth:rank_causes for the corrected verdict.

Parameters:

Name Type Description Default
trigger_events DataFrame

Event frame whose onsets are being explained.

required
candidate_uuid str

The signal to profile.

required
window str

Grid resolution (offset string); also the unit of max_lag.

'1min'
max_lag int

Largest lead tested, in window periods.

30

Returns:

Type Description
DataFrame

Static-shape DataFrame, one row per lag: uuid,

DataFrame

candidate_uuid, lag_seconds, correlation,

DataFrame

p_value, sample_count, is_best_lag, method.