Note
Go to the end to download the full example code.
Entity Metric: L2 Distance#
This example demonstrates the L2 entity metric, which measures the distance between two individual entities (single point-in-time observations) based on numerical feature.
Note
The L2 metric computed the squared difference of values. When the value is normalized, it computes twice the squared difference over the sum of square. This value does not belongs in [0,1].
Setup#
from tanat import build_states
from tanat.dataset import simulate_states
from tanat.metric.entity import L2EntityMetric
Generate synthetic data#
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",
)
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_a67c04d6
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 String [len 1 → 1]
Create L2 entity metric#
metric_norm = L2EntityMetric(entity_feature="score")
metric = L2EntityMetric(entity_feature="score", normalize=False)
print(metric)
L2EntityMetric(settings=L2Settings(entity_feature='score', nan_cost=1.0, normalize=False))
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"\nL2 distance: {dist}")
L2 distance: 576.0
Try multiple pairs#
print("\nDistances between random entity pairs ('normalized' or not):")
print("-" * 50)
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)
d_n = metric_norm(e1, e2)
print(f"Pair {i+1}: {e1['score']!r:5} vs {e2['score']!r:5} → {d_n:.1f} / {d:.1f}")
Distances between random entity pairs ('normalized' or not):
--------------------------------------------------
Pair 1: 53 vs 77 → 0.1 / 576.0
Pair 2: 77 vs 51 → 0.1 / 676.0
Pair 3: 51 vs 41 → 0.0 / 100.0
Pair 4: 41 vs 23 → 0.1 / 324.0
Pair 5: 23 vs 86 → 0.5 / 3969.0
Create L2 entity metric without entity feature#
In case no entity feature is provided while an EntityMetric is defined, then the first time there is an attempt to compute a metric, the metric self-define the entity feature as the “first” numerical feature that is found. An error is raised if no numerical feature is found.
# no entity feature defined
metric = L2EntityMetric()
print(metric)
# Compute L2 distance between two entity features
dist = metric(ent_a, ent_b)
# the "score" feature has been identified as a numerical feature
# compatible with the L2 metric
print(metric)
L2EntityMetric(settings=L2Settings(entity_feature=None, nan_cost=1.0, normalize=True))
L2EntityMetric(settings=L2Settings(entity_feature='score', nan_cost=1.0, normalize=True))
Total running time of the script: (0 minutes 0.055 seconds)