Note
Go to the end to download the full example code.
Entity Metric: Combined distance#
This example demonstrates how a distance involving several features can be defined. For that, a combined entity metric proposes to combine several entity metrics. The proposed implementation makes a linear combinaison of several metric values computed between two entity features.
Note
It is also possible to implement your custom metric which can involve several features. This is also to be considered to improve the computational efficiency of your workflow.
Setup#
import polars as pl
from tanat import build_states
from tanat.dataset import simulate_states
from tanat.metric.entity import (
HammingEntityMetric,
L2EntityMetric,
CombinedEntityMetric,
)
Generate synthetic data#
We generate a sequence with entities described by two features: score is a numerical attribute, while status is a categorical attribute.
N_IDS = 10
SEED = 42
raw_df = simulate_states(
n_ids=N_IDS,
seq_length_range=(3, 8),
features=["score", "status"],
seed=SEED,
)
pool = build_states(
temporal_data=raw_df,
id_column="id",
start_column="start",
end_column="end",
)
# HammingEntityMetric requires Categorical features
pool.cast_features({"status": pl.Categorical})
print(pool)
┌─ State SequenceStore
│
│ Step 1/4: Sorting & preparing data
│
│ Step 2/4: Building sequence index
│
│ Step 3/4: Writing entity & time index features
│
│ Step 4/4: Computing & writing metadata
│
└─ Done (10 sequences · 51 entities · 0.00s)
┌────────────────────────────────────────────────┐
│ StateSequencePool Summary │
└────────────────────────────────────────────────┘
Overview
─────────────────────────
Sequences 10
Store /home/runner/.tanat/_quick_state_f0901351
id_column id
Time Index
─────────────────────────
Type Datetime(time_unit='us', time_zone=None) [2002-11-11 21:19:37.764236 → 2025-01-01 00:00:00]
Columns ['start', 'end']
t0 position=0, anchor=start
Entity Features (2)
─────────────────────────
• score Numerical [5 → 98]
• status Categorical (5 categories)
Create the entity metrics#
In our scenario, we want to compare entities using both the score and the status. Then, we will first define metrics between entities for each feature, and then combine them.
metric_score = HammingEntityMetric(entity_feature="status")
metric_status = L2EntityMetric(entity_feature="score")
metric = CombinedEntityMetric(
metrics_config=[
metric_score.to_config(),
metric_status.to_config(),
],
agg="mean",
)
# .. warning::
#
# Note that the CombinedEntityMetric waits for configurations
# in the metrics configs, but not the metric itself.
Compute distance between individual entities#
ids = pool.unique_ids
seq_a = pool[ids[0]]
seq_b = pool[ids[1]]
# Extract first entity from each sequence
ent_a, ent_b = seq_a[0], seq_b[0]
# Entity A
print(ent_a)
┌────────────────────────────────────────────────┐
│ StateEntity Summary │
└────────────────────────────────────────────────┘
Overview
─────────────────────────
Sequence ID 1
Rank 0
Entity Features
─────────────────────────
score 53
status D
# Entity B
print(ent_b)
┌────────────────────────────────────────────────┐
│ StateEntity Summary │
└────────────────────────────────────────────────┘
Overview
─────────────────────────
Sequence ID 2
Rank 0
Entity Features
─────────────────────────
score 77
status C
# Compute Hamming distance
dist = metric(ent_a, ent_b)
print(f"\nCombined distance: {dist}")
Combined distance: 0.5329594872968643
Try multiple pairs#
print("\nDistances between random entity pairs:")
print("-" * 40)
for i in range(5):
seq_1 = pool[ids[i]]
seq_2 = pool[ids[i + 1]]
# Compare first entities from each sequence
e1, e2 = seq_1[0], seq_2[0]
d = metric(e1, e2)
print(
f"Pair {i+1}: {e1['score']!r:5}/{e1['status']!r:5} vs {e2['score']!r:5}/{e2['status']!r:5} → {d:.1f}"
)
Distances between random entity pairs:
----------------------------------------
Pair 1: 53 /'D' vs 77 /'C' → 0.5
Pair 2: 77 /'C' vs 51 /'A' → 0.5
Pair 3: 51 /'A' vs 41 /'B' → 0.5
Pair 4: 41 /'B' vs 23 /'A' → 0.6
Pair 5: 23 /'A' vs 86 /'B' → 0.8
Total running time of the script: (0 minutes 0.066 seconds)