We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Event Structure

Every (well-built) event record should have these columns:

Column Purpose Example
timestamp When it happened 2024-03-15 14:22:01
user_id Who did it user_4821
event_type What they did purchase
properties Extra context {"amount": 29.99, "plan": "pro"}

If the event can occur without authentication, like a pageview, then the user_id might be an anonymous identifier like a cookie ID, device ID, or unique request ID instead.

The properties column is the most interesting. It stores event-specific details in a fairly loose key-value format. A purchase event might have amount and plan properties, while a pageview event might have url and referrer properties.

While you could have a separate table for each event type with its own columns, many organizations take a less strict approach so that it's easier to add new event types and properties without changing the schema.

Handling Properties

Properties often arrive as JSON strings, and in our case, we'll parse them with json.loads() to turn them into Python dictionaries.

events = pd.DataFrame(
    {
        "event_type": ["page_view", "page_view"],
        "properties": [
            '{"url": "/pricing", "referrer": "google"}',
            '{"url": "/docs", "referrer": "newsletter"}',
        ],
    }
)

parsed = events["properties"].apply(json.loads)
events["has_referrer"] = parsed.apply(lambda props: props.get("referrer") is not None)

The apply() method runs the parsing function on each row's properties value. After parsing, each row is a normal dictionary, so you can inspect it or extract values safely.

Alternatively, you can use pd.json_normalize() to expand a column of dicts into separate columns in one step:

props_df = pd.json_normalize(events["properties"].apply(json.loads))
events = pd.concat([events, props_df], axis=1)

The pd.concat() function stitches the original event columns and the normalized property columns back together.

Always handle missing keys with dict.get() to avoid errors when events don't have certain properties. Missing keys will return None automatically.

Assignment

SnackStack events carry a JSON blob of extra context in their properties column, and the analytics team can't filter or aggregate on it until it's broken out into real columns.

Complete the parse_event_properties function. It accepts an events DataFrame whose properties column holds JSON strings and returns a copy with new amount and plan columns.