Skip to content

Commit bf934f7

Browse files
docs: update notebooks for release (#218)
1 parent 53dccaf commit bf934f7

10 files changed

Lines changed: 3031 additions & 2489 deletions

docs/notebook_source/01_your_first_anonymization.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
41
# ---
52
# jupyter:
63
# jupytext:
@@ -15,6 +12,10 @@
1512
# ---
1613

1714
# %% [markdown]
15+
# <!--
16+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17+
# SPDX-License-Identifier: Apache-2.0
18+
# -->
1819
# # 🕵️ Your First Anonymization
1920
#
2021
# Detect sensitive entities and replace them with LLM-generated substitutes --

docs/notebook_source/02_inspecting_detected_entities.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
41
# ---
52
# jupyter:
63
# jupytext:
@@ -15,6 +12,10 @@
1512
# ---
1613

1714
# %% [markdown]
15+
# <!--
16+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17+
# SPDX-License-Identifier: Apache-2.0
18+
# -->
1819
# # 🕵️ Inspecting Detected Entities
1920
#
2021
# Dig into the entity detection pipeline output -- what was detected,
@@ -26,6 +27,10 @@
2627
# We use **Annotate** mode because it preserves the original text while tagging each entity
2728
# with its label, making it ideal for reviewing detection quality.
2829
#
30+
# > **Privacy warning:** `Annotate` does not anonymize the text. Sensitive values
31+
# > remain in the output, so use it only for inspection -- not as a privacy-safe
32+
# > production strategy.
33+
#
2934
# #### 📚 What you'll learn
3035
#
3136
# - Run the detection pipeline and inspect its output using Annotate mode
@@ -100,13 +105,15 @@
100105
# %% [markdown]
101106
# ## 📋 Columns
102107
#
103-
# - `trace_dataframe` contains all internal columns from the pipeline
104-
# (detection, validation, replacement, etc.).
108+
# - `result.dataframe["final_entities"]` is the stable, public entity output.
109+
# - `trace_dataframe` contains internal pipeline columns for deeper debugging;
110+
# those underscore-prefixed columns may change between releases.
105111

106112
# %%
107-
df = result.trace_dataframe
108-
print(f"Records: {len(df)}")
109-
print(f"Columns: {list(df.columns)}")
113+
trace_df = result.trace_dataframe
114+
final_entities = result.dataframe["final_entities"]
115+
print(f"Records: {len(trace_df)}")
116+
print(f"Columns: {list(trace_df.columns)}")
110117

111118
# %% [markdown]
112119
# ## 🎯 Detected entities
@@ -116,7 +123,7 @@
116123

117124
# %%
118125
row_idx = 0
119-
raw = df.loc[row_idx, "_detected_entities"]
126+
raw = final_entities.iloc[row_idx]
120127
entities = raw["entities"] if isinstance(raw, dict) else raw
121128
print(f"Record {row_idx}: {len(entities)} entities detected\n")
122129

@@ -132,7 +139,7 @@
132139

133140
# %%
134141
label_counts = Counter()
135-
for raw in df["_detected_entities"]:
142+
for raw in final_entities:
136143
entity_list = raw["entities"] if isinstance(raw, dict) else raw
137144
for entity in entity_list:
138145
label_counts[entity["label"]] += 1
@@ -152,7 +159,7 @@
152159

153160
# %%
154161
source_counts = Counter()
155-
for raw in df["_detected_entities"]:
162+
for raw in final_entities:
156163
entity_list = raw["entities"] if isinstance(raw, dict) else raw
157164
for entity in entity_list:
158165
source_counts[entity.get("source", "unknown")] += 1
@@ -168,7 +175,7 @@
168175

169176
# %%
170177
row_idx = 0
171-
raw_bv = df.loc[row_idx, "_entities_by_value"]
178+
raw_bv = trace_df.loc[row_idx, "_entities_by_value"]
172179
by_value = raw_bv["entities_by_value"] if isinstance(raw_bv, dict) else raw_bv
173180
print(f"Record {row_idx}: {len(by_value)} unique entity values\n")
174181

docs/notebook_source/03_choosing_a_replacement_strategy.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
41
# ---
52
# jupyter:
63
# jupytext:
@@ -15,6 +12,10 @@
1512
# ---
1613

1714
# %% [markdown]
15+
# <!--
16+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17+
# SPDX-License-Identifier: Apache-2.0
18+
# -->
1819
# # 🕵️ Choosing a Replacement Strategy
1920
#
2021
# Four [replace mode](../../concepts/replace/) strategies compared side-by-side on the same data.
@@ -25,6 +26,7 @@
2526
# | **Redact** | Label-based markers (`[REDACTED_FIRST_NAME]`) |
2627
# | **Annotate** | Tags entities but keeps original text |
2728
# | **Hash** | Deterministic hash digest |
29+
#
2830
# #### 📚 What you'll learn
2931
#
3032
# - Compare **Redact**, **Annotate**, **Hash**, and **Substitute** on the same input

docs/notebook_source/04_rewriting_biographies.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
41
# ---
52
# jupyter:
63
# jupytext:
@@ -15,16 +12,22 @@
1512
# ---
1613

1714
# %% [markdown]
15+
# <!--
16+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17+
# SPDX-License-Identifier: Apache-2.0
18+
# -->
1819
# # 🕵️ Rewriting Biographies
1920
#
2021
# Instead of replacing entities with tokens, rewrite mode generates a
21-
# privacy-safe transformation of the entire text. The pipeline:
22+
# privacy-safe transformation of the entire text. The `run()` / `preview()` pipeline:
2223
#
2324
# 1. Detects entities (same as replace mode, plus latent entity detection)
2425
# 2. Classifies the domain and assigns sensitivity dispositions
2526
# 3. Generates a rewritten version that obscures sensitive entities
2627
# 4. Evaluates quality (utility) and privacy (leakage) with an automated repair loop
27-
# 5. Runs a final optional LLM judge for informational scores
28+
#
29+
# Afterward, a separate optional `evaluate()` call runs LLM judges for
30+
# detection validity and holistic privacy, quality, and style scores.
2831
#
2932
#
3033
# #### 📚 What you'll learn
@@ -103,6 +106,8 @@
103106
protect="All direct identifiers and quasi-identifier combinations (names, locations, employers, dates)",
104107
preserve="Career trajectory, educational background, and professional accomplishments",
105108
),
109+
risk_tolerance="low",
110+
max_repair_iterations=3,
106111
),
107112
)
108113

@@ -125,6 +130,11 @@
125130
preview.display_record(1)
126131

127132
# %% [markdown]
133+
# > **How to interpret leakage:** Leakage is measured against the sensitivity
134+
# > disposition. Details marked `leave_as_is` may remain without increasing
135+
# > `leakage_mass`. If an output retains something you expected the privacy goal
136+
# > to protect, inspect the Entity Disposition table.
137+
#
128138
# ## 🚀 Full run
129139
#
130140
# - `result.dataframe` has user-facing columns: rewritten text, scores, and the review flag.
@@ -145,6 +155,8 @@
145155
# ## 🚩 Filter by review flag
146156
#
147157
# - Records where automated metrics exceed thresholds are flagged for manual review.
158+
# - `needs_human_review` is threshold-based, so a record can have small nonzero
159+
# leakage without being flagged.
148160
# - Use this to prioritize human attention on the records that need it most.
149161
# - See [Working with flagged records](../../concepts/rewrite/#working-with-flagged-records)
150162
# for guidance on diagnosing and resolving flagged records.
@@ -159,6 +171,9 @@
159171
# ## 🔬 Evaluate (optional)
160172
#
161173
# Call `evaluate()` to run LLM-as-judge scoring on the rewrite result — detection validity and three quality rubrics (privacy, quality, style).
174+
# Evaluation makes additional LLM calls per record. For larger datasets, evaluate
175+
# a preview first; this tutorial evaluates all 25 rows to demonstrate the complete workflow.
176+
# This holistic judge is independent of pipeline leakage scoring, so their assessments may differ.
162177
# See [Evaluation](../../concepts/evaluation/#rewrite-evaluation) for details.
163178

164179
# %%

docs/notebook_source/05_rewriting_legal_documents.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2-
# SPDX-License-Identifier: Apache-2.0
3-
41
# ---
52
# jupyter:
63
# jupytext:
@@ -15,6 +12,10 @@
1512
# ---
1613

1714
# %% [markdown]
15+
# <!--
16+
# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
17+
# SPDX-License-Identifier: Apache-2.0
18+
# -->
1819
# # 🕵️ Rewriting Legal Documents
1920
#
2021
# Rewriting legal text (TAB dataset) with a domain-specific privacy goal
@@ -115,6 +116,8 @@
115116
# ## 🎛️ Configure
116117
#
117118
# - `Detect(entity_labels=...)` overrides the default entity set with legal-specific labels.
119+
# The explicit list is a strict allowlist for both detection and LLM augmentation:
120+
# labels not included here are filtered out, so include every entity type you need.
118121
# - `PrivacyGoal` tells the rewriter what to **protect** (identifiers, case numbers,
119122
# institutional references) and what to **preserve** (legal reasoning, statutory references,
120123
# ruling structure).
@@ -153,9 +156,16 @@
153156
preview.display_record(1)
154157

155158
# %% [markdown]
159+
# > **How to interpret leakage:** Leakage is measured against the sensitivity
160+
# > disposition. Details marked `leave_as_is` may remain without increasing
161+
# > `leakage_mass`. If an output retains something you expected the privacy goal
162+
# > to protect, inspect the Entity Disposition table.
163+
#
156164
# ## 🚀 Full run
157165
#
158166
# - `result.dataframe` has user-facing columns: rewritten text, scores, and the review flag.
167+
# - This notebook uses `risk_tolerance="minimal"`, which applies stricter repair
168+
# and review thresholds than notebook 04.
159169

160170
# %%
161171
result = anonymizer.run(config=config, data=input_data)
@@ -169,6 +179,8 @@
169179
# ## 🚩 Filter by review flag
170180
#
171181
# - Records where automated metrics exceed thresholds are flagged for manual review.
182+
# - The repair loop stops after `max_repair_iterations`; records that still need
183+
# repair remain flagged for human review but are not pipeline failures.
172184
# - Use this to prioritize human attention on the records that need it most.
173185
# - See [Working with flagged records](../../concepts/rewrite/#working-with-flagged-records)
174186
# for guidance on diagnosing and resolving flagged records.
@@ -183,6 +195,9 @@
183195
# ## 🔬 Evaluate (optional)
184196
#
185197
# Call `evaluate()` to run LLM-as-judge scoring on the rewrite result — detection validity and three quality rubrics (privacy, quality, style).
198+
# Evaluation makes additional LLM calls per record. For larger datasets, evaluate
199+
# a preview first; this tutorial evaluates all 25 rows to demonstrate the complete workflow.
200+
# This holistic judge is independent of pipeline leakage scoring, so their assessments may differ.
186201
# See [Evaluation](../../concepts/evaluation/#rewrite-evaluation) for details.
187202

188203
# %%

0 commit comments

Comments
 (0)