Add Segment

Add a new categorical segment column to the eventstream.

Exactly one of rules, func, sql, funnel_events, or time_range must be provided — unless name is already listed in schema.custom_cols, in which case passing none of them promotes that existing column to a segment in place, without recomputing its values.

Usage

# ordered CASE-WHEN rules over an existing column
stream.add_segment("region", rules=[
    ["country", "=", "US", "domestic"],
    ["country", "in", "('GB', 'DE', 'FR')", "europe"],
    ["other"],
])

# the deepest funnel step each path completed in order
stream.add_segment("funnel", funnel_events=["add_to_cart", "shipping_details", "purchase"])

# "inside" / "outside" a time window
stream.add_segment("incident", time_range=("2024-03-10", "2024-03-17"))

# a DuckDB SELECT returning one label per row
stream.add_segment("device", sql="SELECT CASE WHEN platform = 'mobile' THEN 'mobile' ELSE 'web' END FROM eventstream")

# promote a column that is already in the eventstream, keeping its values
stream.add_segment("returned")

How it works

A segment column stores one label per event row, which is what lets a segment be either static (the same label along a whole path) or dynamic (changing as the path goes on). See Segments for what that distinction buys you.

rules — CASE-WHEN over existing columns

Conditions are tried in order; the last entry is the fallback label.

Before — a country column that came along with the source data:

user_ideventcountry
u1homeUS
u1cartUS
u2homeDE
u2cartDE
stream.add_segment("region", rules=[
    ["country", "=", "US", "domestic"],
    ["international"],
])

After:

user_ideventcountryregion
u1homeUSdomestic
u1cartUSdomestic
u2homeDEinternational
u2cartDEinternational

Write string values unquoted"US", not "'US'" — since they get quoted for you. The one exception is op="in", whose value is passed through to SQL as-is and so must be a complete tuple: ["country", "in", "('GB', 'DE', 'FR')", "europe"].

funnel_events — how deep did this path get

Labels each path with the deepest funnel step it completed in order. This is the mode that turns a funnel drop-off into a comparable group.

Before — four paths against an add_to_cart → checkout → purchase funnel:

  • u1: home → add_to_cart → checkout → purchase
  • u2: home → add_to_cart → checkout
  • u3: home → checkout → purchase (skipped add_to_cart)
  • u4: home
stream.add_segment("funnel", funnel_events=["add_to_cart", "checkout", "purchase"])

After — one label per path, written onto every one of its events:

pathfunnel
u1purchase
u2checkout
u3out_of_funnel
u4out_of_funnel

Note u3: it reached both checkout and purchase, but never completed add_to_cart first, so the strictly ordered funnel gives it no credit at all. Paths that never complete even the first step are labelled out_of_funnel.

time_range — inside vs outside a window

stream.add_segment("incident", time_range=("2024-03-10", "2024-03-17"))

Every event is labelled inside or outside by its own timestamp, so a user active both during and after an incident contributes to both groups. That is what makes this the right tool for "how did behaviour change during X?" — see Segments.

func and sql — anything else

func receives the raw DataFrame and returns one label per row, in row order; sql is a DuckDB SELECT over the eventstream alias returning a single column, also one value per row in order.

Promoting an existing column

If the column is already in the eventstream — it rode along from the source data as a custom column — call add_segment with just the name and no mode argument. Its values are kept as they are and the column becomes a segment.

stream.add_segment("returned")

Parameters

ParameterTypeDescription
namestrName of the new segment column.
ruleslist, optionalCASE-WHEN rules. A list of conditions plus a final else entry: Example: [["country", "=", "US", "domestic"], ["international"]].
funccallable, optionalA function that accepts the raw pandas DataFrame and returns a collection of segment labels with the same length and order as the eventstream rows.
sqlstr, optionalDuckDB SQL SELECT statement that reads from the eventstream table alias and returns exactly one column — the segment label for each row. Row count and order must match the eventstream. Example: "SELECT CASE WHEN platform = 'mobile' THEN 'mobile' ELSE 'web' END FROM eventstream".
funnel_eventslist of str, optionalOrdered list of at least 2 event names defining a strict, ordered ("closed") funnel. A path is assigned funnel_events[k] if there exists an increasing sequence of event occurrences matching funnel_events[0], funnel_events[1], ..., funnel_events[k] in that order (later steps may be reached via any qualifying occurrence, not necessarily the first or last one — earlier events occurring again after a later step was reached don't un-complete it). A path is assigned the highest such k; if it never completes even funnel_events[0], it is labeled out_of_funnel. Segment values (in ascending funnel order): out_of_funnel, then each event name from funnel_events[0] to funnel_events[-1].
time_rangetuple or list, optional(start, end) — two timestamps (string or pd.Timestamp) bounding an inclusive interval over schema.timestamp_col. Each event is labeled inside if its timestamp falls within [start, end], otherwise outside.
path_colstr, optionalPath ID column override for funnel_events mode; defaults to schema.path_col.

Values rules

  • Each condition entry is [column, op, value, label] — translates to WHEN <column> <op> <value> THEN <label> in SQL. A string value is quoted for you, so write "US", not "'US'" — the exception is op="in", whose value is inserted raw and must therefore be a complete SQL tuple: "('GB', 'DE', 'FR')".
  • The last entry is [else_label] — the ELSE branch label.