Index
eventlog ¤
ts-shape canonical event-log package.
A lightweight, pm4py-compatible (XES + OCEL 2.0) representation of detector output. ts-shape itself adds no process-mining dependencies — the columns match the specs verbatim so users can hand the resulting DataFrames to pm4py / Disco / Celonis / OCEL viewers directly.
Typical use::
from ts_shape.eventlog import (
to_event_log, concat, to_event_log_xes, to_event_log_ocel,
)
from ts_shape.events.production.machine_state import MachineStateEvents
from ts_shape.events.quality.outlier_detection import OutlierDetectionEvents
state_log = to_event_log(
MachineStateEvents(df, run_state_uuid="m").detect_run_idle(),
detector="MachineStateEvents.detect_run_idle",
)
outlier_log = to_event_log(
OutlierDetectionEvents(df, value_column="value_double").detect_outliers_zscore(),
detector="OutlierDetectionEvents.detect_outliers_zscore",
)
log = concat(state_log, outlier_log)
xes_df = to_event_log_xes(log, case_object_type="asset")
tables = to_event_log_ocel(log) # OCEL2Tables(events, objects, relations, ...)
LambdaDetector ¤
LambdaDetector(spec: RuleSpec)
Runnable form of a :class:RuleSpec.
evaluate ¤
evaluate(dataframe: DataFrame) -> pd.DataFrame
Apply the rule to dataframe and return a detector frame.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
Input DataFrame the rule's trigger expression is evaluated on. |
required |
Returns:
| Type | Description |
|---|---|
DataFrame
|
Detector frame whose layout depends on the rule's shape |
DataFrame
|
(see :func: |
to_event_log ¤
to_event_log(
dataframe: DataFrame,
*,
objects: Mapping[str, object] | None = None,
qualifiers: Mapping[str, str] | None = None
) -> EventLog
Evaluate the rule on dataframe and normalize the result to an event log.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
Input DataFrame the rule is evaluated on. |
required |
objects
|
Mapping[str, object] | None
|
Optional OCEL object bindings, mapping an object type to a
column name, callable, Series or scalar; passed through to
:func: |
None
|
qualifiers
|
Mapping[str, str] | None
|
Optional mapping of object type to the relation qualifier written for that type. None leaves qualifiers empty. |
None
|
Returns:
| Type | Description |
|---|---|
EventLog
|
The canonical :class: |
RuleSpec
dataclass
¤
RuleSpec(
id: str,
class_name: str,
method_name: str,
pack: str,
shape: str,
archetype: str,
template: str,
trigger: TriggerSpec,
produces_objects: tuple[str, ...] = ("asset",),
severity_field: str | None = None,
value_field: str | None = None,
standard_attrs: Mapping[str, object] = dict(),
)
A complete lambda-rule definition.
Required fields mirror the built-in REGISTRY contract — class_name
is synthesized (must start with Lambda) so the rule slots into the
same (class, method) -> LabelRule table as the 290 built-ins.
TriggerSpec
dataclass
¤
TriggerSpec(
expression: str,
min_duration_s: float | None = None,
group_by: tuple[str, ...] = (),
)
When does the rule fire?
expression is evaluated against the input DataFrame by the
AST-restricted compiler in :mod:.expression. It must produce a
boolean Series aligned with the input rows.
min_duration_s and group_by are only meaningful for
shape="interval" rules: consecutive True rows are coalesced
(per group) and the resulting interval is dropped if shorter than
min_duration_s seconds.
UnsafeExpression ¤
Bases: ValueError
Raised when a trigger expression contains a disallowed AST node.
EventLog
dataclass
¤
EventLog(
events: DataFrame = schema.empty_events(),
objects: DataFrame = schema.empty_objects(),
relations: DataFrame = schema.empty_relations(),
o2o: DataFrame = schema.empty_o2o(),
object_changes: DataFrame = schema.empty_object_changes(),
)
Canonical ts-shape event log in OCEL 2.0 shape.
Five relational tables, mirroring the OCEL 2.0 standard:
events— one row per detected event (+ event attributes),objects— the objects events refer to (ocel:oid/ocel:type),relations— event-to-object (E2O) relations with qualifiers,o2o— object-to-object relations with qualifiers,object_changes— time-varying object attribute values.
objects / relations are empty when the source detector has no
natural object association (e.g. a global cross-signal correlation
statistic); o2o / object_changes are empty unless supplied. Use
:attr:has_objects to check before calling :func:to_event_log_xes.
Example
Built by :func:~ts_shape.to_event_log from a detector's output:
import ts_shape df = ts_shape.make_timeseries(["temp"], n_outliers=3) out = ts_shape.OutlierDetectionEvents(df, "value_double").detect_outliers_zscore() log = ts_shape.to_event_log( ... out, detector="OutlierDetectionEvents.detect_outliers_zscore") len(log.events), log.has_objects (4, True) log.events[["ocel:activity", "ocel:timestamp"]].head(2) ocel:activity ocel:timestamp 0 quality.outlier.zscore 2025-01-01 01:34:30+00:00 1 quality.outlier.zscore 2025-01-01 03:21:00+00:00
filter_by_pack ¤
filter_by_pack(pack: str) -> EventLog
Return a sub-log containing only the events emitted by one pack.
Objects, relations, object-to-object links, and object changes are restricted to those referenced by the kept events.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
pack
|
str
|
Pack name to match against the |
required |
Returns:
| Type | Description |
|---|---|
EventLog
|
A new EventLog restricted to the matching events. |
filter_by_object ¤
filter_by_object(
oid: str, type_: str | None = None
) -> EventLog
Return a sub-log containing only the events related to one object.
Events are selected through the event-to-object relations table;
the other tables are restricted to the objects those events use.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
oid
|
str
|
Object identifier ( |
required |
type_
|
str | None
|
Optional object type ( |
None
|
Returns:
| Type | Description |
|---|---|
EventLog
|
A new EventLog restricted to the events related to the object. |
ObjectSpec
dataclass
¤
ObjectSpec(
uuid: str,
object_type: str,
value_column: str = "value_string",
min_duration: str | None = None,
id_template: str = "{value}",
attributes: Mapping[str, str] = dict(),
)
Declares that one signal carries the identity of one object type.
Attributes:
| Name | Type | Description |
|---|---|---|
uuid |
str
|
The signal ( |
object_type |
str
|
OCEL object type, e.g. |
value_column |
str
|
Column carrying the id ( |
min_duration |
str | None
|
Optional minimum presence (e.g. |
id_template |
str
|
How to render the object id from the raw value. Supports
|
attributes |
Mapping[str, str]
|
|
OCEL2Tables
dataclass
¤
OCEL2Tables(
events: DataFrame,
objects: DataFrame,
relations: DataFrame,
o2o: DataFrame,
object_changes: DataFrame,
)
The five OCEL 2.0 relational tables produced from an :class:EventLog.
LabelRule
dataclass
¤
LabelRule(
template: str,
pack: str,
shape: str = "point",
produces_objects: tuple[str, ...] = ("asset",),
severity_field: str | None = None,
value_field: str | None = None,
drop_fields: tuple[str, ...] = (),
standard_attrs: Mapping[str, object] = dict(),
)
How one detector method's output maps onto OCEL events.
See the module docstring for the meaning of template, pack,
shape, and produces_objects. severity_field and
value_field name legacy columns read into the severity and value
attributes, drop_fields lists legacy columns to discard, and
standard_attrs maps standard attribute keys to a legacy column name
or a literal value.
clear_overrides ¤
clear_overrides(
class_name: str | None = None,
method_name: str | None = None,
) -> None
Remove registered override(s).
- No arguments: clear every registration (typical test teardown).
- Both arguments: clear that specific
(class, method)only. - Class name only: clear every override on that class.
Deprecated class and method names (e.g. CycleTimeTracking) resolve
to their current names, like :func:register_adapter. Has no effect if
the targeted entries are already absent.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
class_name
|
str | None
|
Detector class name; None clears every registration. |
None
|
method_name
|
str | None
|
Method name; None clears every method of |
None
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
has_override ¤
has_override(class_name: str, method_name: str) -> bool
Return True iff a custom adapter is registered for (class, method).
register_adapter ¤
register_adapter(
class_name: str, method_name: str
) -> Callable[[AdapterFn], AdapterFn]
Register a custom adapter for a specific (class, method).
The function will be called with (detector_frame, *, rule, detector,
objects, qualifiers).
align_columns ¤
align_columns(*logs: EventLog) -> list[EventLog]
Reindex every log's events table to the union of their columns.
Each returned :class:EventLog exposes an identical, identically-ordered
set of event columns — the canonical core first (in emit order), then the
remaining attribute columns sorted for determinism. Columns absent from a
given log are added and filled with NA, so the frames can be appended or
stacked directly without a column mismatch. objects and relations
already have fixed schemas and are returned unchanged.
Returns a list parallel to the inputs. An empty call returns [].
to_event_log_xes ¤
to_event_log_xes(
eventlog: EventLog,
*,
case_object_type: str = "asset",
lifecycle: str = "single"
) -> pd.DataFrame
Flatten the event log into an XES-style DataFrame.
A trace is built per object of case_object_type — each event linked
to that object becomes one (or two) rows in the trace.
lifecycle="single" — interval events become one row with
lifecycle:transition="complete". time:timestamp is the
interval-end; start_timestamp is exposed verbatim.
lifecycle="two_row" — interval events expand into a start row
(using ts_shape:start_timestamp) and a complete row, paired by
concept:instance.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
eventlog
|
EventLog
|
The event log to flatten. |
required |
case_object_type
|
str
|
Object type whose objects become the traces. |
'asset'
|
lifecycle
|
str
|
|
'single'
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
DataFrame with |
DataFrame
|
|
DataFrame
|
when the log links operators), sorted by case and time. |
Raises:
| Type | Description |
|---|---|
ValueError
|
When the log has no objects, no object of
|
describe ¤
describe(detector: str) -> dict[str, Any]
Return everything ts-shape knows about a detector method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
detector
|
str
|
|
required |
Returns:
| Type | Description |
|---|---|
dict[str, Any]
|
A dict with |
dict[str, Any]
|
class: |
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
dict[str, Any]
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If |
KeyError
|
If the method has no taxonomy entry. |
compile_expression ¤
compile_expression(
expression: str,
) -> Callable[[pd.DataFrame], pd.Series]
Compile a trigger expression to a vectorized boolean mask function.
Python's and / or / not / in, chained comparisons and
min / max over columns are rejected here, with a hint to the
element-wise &, |, ~ and column.isin([...]).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
expression
|
str
|
The trigger, e.g. |
required |
Returns:
| Type | Description |
|---|---|
Callable[[DataFrame], Series]
|
A callable that takes a DataFrame and returns a boolean Series |
Callable[[DataFrame], Series]
|
aligned with its rows (missing -> False). |
Raises:
| Type | Description |
|---|---|
UnsafeExpression
|
For disallowed or non-element-wise syntax. The
callable raises :class: |
load_dicts ¤
load_dicts(
entries: Iterable[Mapping[str, Any]],
) -> list[LambdaDetector]
Compile and register an iterable of dict rules, all or nothing.
Every rule is validated and its trigger compiled before any is registered; if one fails, the rules registered by this call are removed again and the error is raised.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
entries
|
Iterable[Mapping[str, Any]]
|
Rule mappings with the :class: |
required |
Returns:
| Name | Type | Description |
|---|---|---|
One |
list[LambdaDetector]
|
class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a malformed rule, a duplicate registration or an
expression that does not compile (:class: |
load_yaml ¤
load_yaml(path: str | Path) -> list[LambdaDetector]
Load and register every rule under a YAML file's rules: key.
YAML is imported lazily so :mod:ts_shape.eventlog does not gain a
hard runtime dependency on PyYAML for users who only use built-in
detectors. Install ts-shape[yaml] to enable this loader, or use
:func:load_dicts with a hand-built list.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str | Path
|
Path to a YAML file with a top-level |
required |
Returns:
| Name | Type | Description |
|---|---|---|
One |
list[LambdaDetector]
|
class: |
Raises:
| Type | Description |
|---|---|
ImportError
|
When PyYAML is not installed. |
ValueError
|
When the file has no |
register_lambda_rule ¤
register_lambda_rule(spec: RuleSpec) -> LambdaDetector
Register spec in REGISTRY + ARCHETYPE_BY_METHOD; return runnable detector.
The trigger expression is compiled here, so a bad expression fails at registration rather than at the first evaluation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
spec
|
RuleSpec
|
The rule to register. |
required |
Returns:
| Type | Description |
|---|---|
LambdaDetector
|
The runnable :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the spec is malformed, the expression does not compile
(:class: |
run_backtest ¤
run_backtest(
detector: LambdaDetector,
dataframe: DataFrame,
*,
objects: Mapping[str, object] | None = None,
qualifiers: Mapping[str, str] | None = None
) -> BacktestResult
Run detector over dataframe and summarize hit counts.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
detector
|
LambdaDetector
|
The registered lambda rule. |
required |
dataframe
|
DataFrame
|
Input frame the rule is evaluated on. |
required |
objects
|
Mapping[str, object] | None
|
Object bindings passed to the event-log adapter. |
None
|
qualifiers
|
Mapping[str, str] | None
|
Relation qualifier per object type. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
BacktestResult
|
class: |
BacktestResult
|
per asset, and the full event log. |
unregister_lambda_rule ¤
unregister_lambda_rule(
class_name: str, method_name: str
) -> None
Remove a rule previously installed by :func:register_lambda_rule.
Used by tests to keep the global REGISTRY clean between cases. No-op if the rule was not registered. Deprecated class / method names resolve to their current names, as in the registry lookup.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
class_name
|
str
|
The rule's class name. |
required |
method_name
|
str
|
The rule's method name. |
required |
to_event_log ¤
to_event_log(
dataframe: DataFrame,
*,
detector: str,
objects: Mapping[str, object] | None = None,
qualifiers: Mapping[str, str] | None = None,
o2o: TableInput = None,
object_changes: TableInput = None,
validate: bool = True,
timestamp: object | None = None
) -> EventLog
Normalize a detector frame (a detector's output DataFrame) into the canonical event log.
Timestamps: tz-aware times are converted to UTC; naive times are taken
to be UTC (localize them first if they are local wall-clock times).
Interval rows that end before they start are dropped with a
:class:~ts_shape.errors.DataQualityWarning.
Event ids (ocel:eid) are content-based: a hash of the detector, the
row's source_uuid, its timestamps, the activity and every other
column of the row. They are reproducible across runs, independent of
row order, and the same detector on two machines does not collide.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
The detector frame. |
required |
detector
|
str
|
|
required |
objects
|
Mapping[str, object] | None
|
Binds OCEL object types to, per type:
Types listed in the rule's |
None
|
qualifiers
|
Mapping[str, str] | None
|
Relation qualifier per object type. |
None
|
o2o
|
TableInput
|
OCEL 2.0 object-to-object relations, a DataFrame or iterable of
dict rows with |
None
|
object_changes
|
TableInput
|
Time-varying object attributes with |
None
|
validate
|
bool
|
Check the result against the canonical schema. |
True
|
timestamp
|
object | None
|
Timestamp of the events of a |
None
|
Returns:
| Type | Description |
|---|---|
EventLog
|
The canonical :class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
For a malformed |
KeyError
|
When the detector has no taxonomy entry, or the frame lacks the time columns of its shape. |
attach_objects ¤
attach_objects(
event_log: EventLog,
dataframe: DataFrame,
specs: Sequence[ObjectSpec],
*,
qualifiers: Mapping[str, str] | None = None,
uuid_column: str = "uuid",
time_column: str = "systime",
hierarchy: Mapping[str, str] | None = None,
infer_o2o: bool = True,
validate: bool = True
) -> EventLog
Link an existing event log to detected objects by temporal containment.
For every event, any object whose presence interval contains the event
timestamp is linked with an event-to-object (E2O) relation. The detected
objects, o2o and object_changes are merged in. This enriches the
output of any event detector — no per-detector changes required. See
:func:detect_objects for hierarchy (declared part_of edges).
This is a convenience over :func:relate: it first segments dataframe into an
object-interval table via :func:object_intervals, then relates the events
to it. When you already hold an interval/object table, call :func:relate
directly and skip the raw signals.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_log
|
EventLog
|
The events to link. |
required |
dataframe
|
DataFrame
|
Long-format frame with the id signals. |
required |
specs
|
Sequence[ObjectSpec]
|
Which signal carries which object type. |
required |
qualifiers
|
Mapping[str, str] | None
|
Relation qualifier per object type. |
None
|
uuid_column
|
str
|
Signal identifier column. |
'uuid'
|
time_column
|
str
|
Timestamp column. |
'systime'
|
hierarchy
|
Mapping[str, str] | None
|
Child type -> parent type for |
None
|
infer_o2o
|
bool
|
Derive object-to-object relations. |
True
|
validate
|
bool
|
Check the result against the canonical schema. |
True
|
Returns:
| Type | Description |
|---|---|
EventLog
|
|
derive_o2o ¤
derive_o2o(
intervals: DataFrame,
*,
hierarchy: Mapping[str, str] | None = None
) -> pd.DataFrame
Derive object-to-object (O2O) relations from an interval table.
Public entry point over the overlap kernel: a declared hierarchy
(child type -> parent type) yields part_of from each child presence to
the parent presence it overlaps longest; without one, overlapping objects
of different types get the symmetric co_occurs qualifier (one row per
pair, the type that sorts first in ocel:oid).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
intervals
|
DataFrame
|
Object table with |
required |
hierarchy
|
Mapping[str, str] | None
|
Child type -> parent type. |
None
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
The OCEL 2.0 |
detect_objects ¤
detect_objects(
dataframe: DataFrame,
specs: Sequence[ObjectSpec],
*,
uuid_column: str = "uuid",
time_column: str = "systime",
hierarchy: Mapping[str, str] | None = None,
infer_o2o: bool = True,
validate: bool = True
) -> EventLog
Detect object instances and build their OCEL 2.0 tables.
Produces an :class:EventLog with no events — only objects, o2o
(object-to-object relations), and object_changes (presence lifecycle +
captured attributes). Compose it with event-detector logs via
:func:~ts_shape.eventlog.concat.concat.
hierarchy maps a child object type to its parent type
(e.g. {"serial": "batch", "batch": "work_order"}). A compositional
part_of relation is asserted only along these declared edges: each
child presence is part of the parent presence it overlaps longest —
because part_of cannot be inferred from time alone (a long-running tool
temporally contains every batch without owning it). Without a declared
hierarchy, overlapping objects of different types get the honest,
symmetric co_occurs qualifier instead. Set infer_o2o=False to skip
object-to-object relations entirely.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
Long-format frame with the id signals. |
required |
specs
|
Sequence[ObjectSpec]
|
Which signal carries which object type. |
required |
uuid_column
|
str
|
Signal identifier column. |
'uuid'
|
time_column
|
str
|
Timestamp column. |
'systime'
|
hierarchy
|
Mapping[str, str] | None
|
Child type -> parent type for |
None
|
infer_o2o
|
bool
|
Derive object-to-object relations. |
True
|
validate
|
bool
|
Check the result against the canonical schema. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
An |
EventLog
|
class: |
EventLog
|
and no events. |
Raises:
| Type | Description |
|---|---|
ColumnNotFoundError
|
When |
link_events_to_objects ¤
link_events_to_objects(
events: DataFrame,
intervals: DataFrame,
*,
qualifiers: Mapping[str, str] | None = None,
key_columns: Sequence[str] | None = None,
contain: bool = True
) -> pd.DataFrame
Derive all event-to-object (E2O) relations from two lists.
Takes an OCEL events table and an object/interval table (oid,
type and, for temporal linking, start / end) and returns the
OCEL 2.0 relations table -- with no access to the raw signals. Two
complementary strategies are unioned and de-duplicated on
(eid, oid, type):
- temporal containment (
contain, default on): link an event to every object whose presence contains the event timestamp. Presence is half-open[start, end)when another presence of the same signal (uuidcolumn) or, without one, of the same type starts atend— so an event at a hand-over instant belongs to the incoming object only — and closed[start, end]otherwise (the last presence).NaTbounds are open. Requiresstart/endcolumns. - key match (opt-in via
key_columns): link an event to the object whoseoidequals the value in one of the event'skey_columns-- for events that already name their object (e.g. abatchattribute).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
events
|
DataFrame
|
OCEL events table with |
required |
intervals
|
DataFrame
|
Object table with |
required |
qualifiers
|
Mapping[str, str] | None
|
Maps an object |
None
|
key_columns
|
Sequence[str] | None
|
Event columns whose value is an object id. Integral
floats (an integer id column with gaps) match |
None
|
contain
|
bool
|
Link by temporal containment. |
True
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
The OCEL 2.0 |
Raises:
| Type | Description |
|---|---|
ColumnNotFoundError
|
When |
object_intervals ¤
object_intervals(
dataframe: DataFrame,
specs: Sequence[ObjectSpec],
*,
uuid_column: str = "uuid",
time_column: str = "systime"
) -> pd.DataFrame
Extract one presence interval per object presence from id signals.
Returns a tidy frame with columns oid, type, start, end,
duration_seconds, uuid (the id signal), source_uuid (of the id
signal, when the frame has that column) plus one column per captured
attribute (its value at the presence start). Times are UTC.
Each id signal is run-length encoded: an id is present from its first
sample until the next value on the same signal (next id, or an empty /
missing reading). A signal whose last reading is still an id keeps that
object present until the last timestamp of the frame. An id that
re-appears later yields another row with the same oid. An empty frame
or no matching signal gives an empty frame with the full column set.
object_specs_from_metadata ¤
object_specs_from_metadata(
metadata: DataFrame,
*,
type_field: str = "object_type",
value_column_field: str = "object_value_column",
uuid_column: str = "uuid"
) -> list[ObjectSpec]
Build :class:ObjectSpec list from per-signal metadata tags.
Scans a metadata table (e.g. MetadataJsonLoader.to_df()) for a column
naming the object type per signal — so new object types are onboarded by
tagging metadata, not by writing code. The uuid may be the index or a
column; the type/value-column fields are matched directly or with a
config_ / config. prefix (mkdocs metadata flattening).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
metadata
|
DataFrame
|
Metadata table, one row per signal. |
required |
type_field
|
str
|
Field naming the object type of a signal; rows without one are skipped. |
'object_type'
|
value_column_field
|
str
|
Field naming the signal's id column (default
|
'object_value_column'
|
uuid_column
|
str
|
Column (or index name) holding the signal uuid. |
'uuid'
|
Returns:
| Name | Type | Description |
|---|---|---|
One |
list[ObjectSpec]
|
class: |
list[ObjectSpec]
|
no uuid or type field. |
Raises:
| Type | Description |
|---|---|
ValueError
|
When a value-column entry is not an id column. |
relate ¤
relate(
event_log: EventLog,
intervals: DataFrame,
*,
hierarchy: Mapping[str, str] | None = None,
qualifiers: Mapping[str, str] | None = None,
key_columns: Sequence[str] | None = None,
infer_o2o: bool = True,
validate: bool = True
) -> EventLog
Assemble a full OCEL 2.0 log from an event list and an object list.
This is the automated relationship step: given an existing event_log
(with events) and an intervals table describing objects -- columns
oid, type and, for temporal linking, start / end (plus any
attribute columns) -- it derives all relations and returns a validated
:class:EventLog whose five tables are ready to ingest into an OCEL 2.0
database:
objectsfrom the distinct(oid, type)pairs,relations(E2O) via :func:link_events_to_objects(temporal containment, plus optionalkey_columnsmatching),o2ovia :func:derive_o2o(declaredpart_ofhierarchyor symmetricco_occurs),object_changes(lifecycle + captured attributes).
A missing start / end (NaT) means the presence is unbounded on
that side (e.g. an object that is still active). Every column other than
oid / type / start / end / duration_seconds / uuid / source_uuid is an
attribute, recorded at the presence start.
Unlike :func:attach_objects, no raw signals or :class:ObjectSpec are
needed -- you bring the two lists, ts-shape derives the relationships.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
event_log
|
EventLog
|
The events to link. |
required |
intervals
|
DataFrame
|
Object table with |
required |
hierarchy
|
Mapping[str, str] | None
|
Child type -> parent type for |
None
|
qualifiers
|
Mapping[str, str] | None
|
Relation qualifier per object type. |
None
|
key_columns
|
Sequence[str] | None
|
Event columns that name an object id directly. |
None
|
infer_o2o
|
bool
|
Derive object-to-object relations. |
True
|
validate
|
bool
|
Check the result against the canonical schema. |
True
|
Returns:
| Type | Description |
|---|---|
EventLog
|
The validated five-table :class: |
Raises:
| Type | Description |
|---|---|
ColumnNotFoundError
|
When |
to_event_log_ocel ¤
to_event_log_ocel(
eventlog: EventLog, *, pm4py: bool = False
) -> OCEL2Tables
Return the OCEL 2.0 tables as an :class:OCEL2Tables bundle.
The canonical schema already uses OCEL 2.0 column names, so by default
this is a pass-through with defensive copy() calls to prevent caller
mutation.
With pm4py=True two tables are reshaped for pm4py's OCEL object:
relations gains ocel:activity and ocel:timestamp of each
event, and object_changes is widened — ocel:value is replaced by
one column per distinct ocel:field holding the new value on that
field's rows (a field named like a base column, e.g. ocel:type,
gets the column <name>_field and a
:class:~ts_shape.errors.DataQualityWarning). The other tables are
unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
eventlog
|
EventLog
|
The event log to export. |
required |
pm4py
|
bool
|
Reshape |
False
|
Returns:
| Type | Description |
|---|---|
OCEL2Tables
|
The five tables as :class: |
empty_o2o ¤
empty_o2o() -> pd.DataFrame
Return an empty object-to-object relations table with the canonical columns and dtypes.
Returns:
| Type | Description |
|---|---|
DataFrame
|
A zero-row DataFrame with the expected object-to-object relations schema. |
empty_object_changes ¤
empty_object_changes() -> pd.DataFrame
Return an empty object changes table with the canonical columns and dtypes.
Returns:
| Type | Description |
|---|---|
DataFrame
|
A zero-row DataFrame with the expected object changes schema. |
register_object_type ¤
register_object_type(name: str) -> None
Register a custom OCEL object type so adapters can emit it.
validate ¤
validate(eventlog: EventLog) -> None
Raise ValueError if the event log violates the canonical schema.