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)

Gallery generated by Sphinx-Gallery