Skip to content

Commit 628e8e1

Browse files
committed
Better handling of safe values
1 parent 07a1757 commit 628e8e1

7 files changed

Lines changed: 21 additions & 6 deletions

File tree

docs/development.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ Activate `poetry` environment: `poetry shell`. (can skip, then prepend `poetry r
1010
- Test: `pytest .`
1111
- Check: `flake8 . && mypy . && black --check . && isort . --check`
1212

13+
To filter out acceptable lines:
14+
`poetry run flake8 . | findstr /v "E501" | findstr /v "F405" | findstr /v "F403"`
15+
1316
### Creating a new release
1417

1518
First, update the project's version by editing the `[tool.poetry]` section from the `pyproject.toml` file.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ profile = "black"
1717

1818
[tool.poetry]
1919
name = "syndiffix"
20-
version = "1.0.7"
20+
version = "1.0.8"
2121
description = "Python implementation of the SynDiffix synthetic data generation mechanism."
2222
authors = ["Open Diffix <hello@open-diffix.org>"]
2323
readme = "README.md"

syndiffix/anonymizer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ def _flatten_contributions(pid_contributions: PidContributions, context: Anonymi
152152
top_count = _random_uniform(top_interval, _mix_seed("top", flat_seed))
153153

154154
top_group_sum = sum(
155-
contribution for _, contribution in sorted_value_counts[outlier_count : (outlier_count + top_count)]
155+
contribution for _, contribution in sorted_value_counts[outlier_count: (outlier_count + top_count)]
156156
)
157157
top_group_average = top_group_sum / top_count
158158

syndiffix/bucket.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def _refine_buckets(node: Node, harvested_nodes: BucketsCache, count: int, unsaf
202202

203203
def _harvest_leaf(leaf: Leaf, harvested_nodes: BucketsCache, unsafe_rng: Random) -> Buckets:
204204
low_threshold = leaf.context.anonymization_context.anonymization_params.low_count_params.low_threshold
205-
if leaf.is_over_threshold(low_threshold):
205+
if leaf.is_over_threshold(low_threshold) or leaf.value_is_safe():
206206
if leaf.is_singularity() or leaf.dimensions() == 1:
207207
return [Bucket(tuple(leaf.bucket_intervals()), leaf.noisy_count())]
208208
else:

syndiffix/forest.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import math
44
import random
5+
from typing import Optional
56

67
import numpy as np
78
import numpy.typing as npt
@@ -31,12 +32,17 @@ def __init__(
3132
counters_factory: CountersFactory,
3233
pids: DataFrame,
3334
data: DataFrame,
35+
value_safe_columns_array: Optional[list[bool]] = None,
3436
) -> None:
3537
self.anonymization_params = anonymization_params
3638
self.bucketization_params = bucketization_params
3739
self.counters_factory = counters_factory
3840
self.orig_pids = pids
3941
self.orig_data = data
42+
if value_safe_columns_array is None:
43+
self.value_safe_columns_array = [False] * len(data.columns)
44+
else:
45+
self.value_safe_columns_array = value_safe_columns_array
4046
self.unsafe_rng = random.Random(0)
4147

4248
assert len(pids) == len(data)
@@ -73,7 +79,7 @@ def __init__(
7379
snapped_intervals = list(self.snapped_intervals)
7480
for i in range(self.dimensions):
7581
combination = (ColumnId(i),)
76-
tree = self._build_tree(combination).push_down_1dim_root()
82+
tree = self._build_tree(combination, self.value_safe_columns_array[i]).push_down_1dim_root()
7783
snapped_intervals[i] = tree.snapped_intervals[0]
7884
self._tree_cache[combination] = tree # Cache the flattened version of the tree.
7985
self.snapped_intervals = tuple(snapped_intervals)
@@ -86,7 +92,7 @@ def _get_subnodes(self, upper_combination: Combination) -> Subnodes:
8692
for sub_combination in sub_combinations
8793
)
8894

89-
def _build_tree(self, combination: Combination) -> Node:
95+
def _build_tree(self, combination: Combination, value_safe_flag: bool = False) -> Node:
9096
subnodes = self._get_subnodes(combination)
9197

9298
# Hash column names into the tree's base bucket seed.
@@ -112,6 +118,7 @@ def _build_tree(self, combination: Combination) -> Node:
112118
self.bucketization_params,
113119
row_limit,
114120
self.counters_factory,
121+
value_safe_flag,
115122
)
116123

117124
root_intervals = get_items_combination(combination, self.snapped_intervals)

syndiffix/synthesizer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ def __init__(
111111
counters_factory,
112112
pids,
113113
apply_convertors(self.column_convertors, raw_data),
114+
value_safe_columns_array=self.value_safe_columns_array,
114115
)
115116

116117
self.clusters, self.entropy_1dim = clustering.build_clusters(self.forest)

syndiffix/tree.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class Context:
2424
bucketization_params: BucketizationParams
2525
row_limit: int
2626
counters_factory: CountersFactory
27+
value_safe_flag: bool
2728

2829

2930
Subnodes = tuple[Union["Node", None], ...]
@@ -47,6 +48,9 @@ def __init__(
4748
def dimensions(self) -> int:
4849
return len(self.context.combination)
4950

51+
def value_is_safe(self) -> bool:
52+
return self.context.value_safe_flag
53+
5054
def update_pids(self, row: RowId) -> None:
5155
self.entity_counter.add(self.context.pid_data[row])
5256

@@ -148,7 +152,7 @@ def _should_split(self, depth: int) -> bool:
148152
(depth <= depth_threshold or len(self.rows) >= self.context.row_limit)
149153
and not self.is_stub
150154
and not self.is_singularity()
151-
and self.is_over_threshold(low_threshold)
155+
and (self.is_over_threshold(low_threshold) or self.value_is_safe())
152156
)
153157

154158
def add_row(self, depth: int, row: RowId) -> Node:

0 commit comments

Comments
 (0)