rdt 1.15.0.dev0__tar.gz → 1.15.1.dev0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {rdt-1.15.0.dev0/rdt.egg-info → rdt-1.15.1.dev0}/PKG-INFO +3 -2
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/pyproject.toml +1 -1
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/__init__.py +1 -1
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/base.py +3 -3
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/anonymizer.py +35 -25
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/utils.py +9 -7
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0/rdt.egg-info}/PKG-INFO +3 -2
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/LICENSE +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/README.md +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/errors.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/hyper_transformer.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/__init__.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/__init__.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/base.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/boolean.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/categorical.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/datetime.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/id.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/numerical.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/pii.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/text.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/utils.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/performance.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/profiling.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/__init__.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/_validators.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/boolean.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/categorical.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/datetime.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/id.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/null.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/numerical.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/__init__.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/anonymization.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/utils.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/text.py +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/SOURCES.txt +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/dependency_links.txt +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/entry_points.txt +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/requires.txt +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/top_level.txt +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/setup.cfg +0 -0
- {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/tests/test_tasks.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: rdt
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.1.dev0
|
|
4
4
|
Summary: Reversible Data Transforms
|
|
5
5
|
Author-email: "DataCebo, Inc." <info@sdv.dev>
|
|
6
6
|
License: BSL-1.1
|
|
@@ -70,6 +70,7 @@ Requires-Dist: coverage<8,>=4.5.12; extra == "dev"
|
|
|
70
70
|
Requires-Dist: tox<5,>=2.9.1; extra == "dev"
|
|
71
71
|
Requires-Dist: tabulate<1,>=0.8.9; extra == "dev"
|
|
72
72
|
Requires-Dist: invoke; extra == "dev"
|
|
73
|
+
Dynamic: license-file
|
|
73
74
|
|
|
74
75
|
<div align="center">
|
|
75
76
|
<br/>
|
|
@@ -144,7 +144,7 @@ collect_ignore = ['pyproject.toml']
|
|
|
144
144
|
exclude_lines = ['NotImplementedError()']
|
|
145
145
|
|
|
146
146
|
[tool.bumpversion]
|
|
147
|
-
current_version = "1.15.
|
|
147
|
+
current_version = "1.15.1.dev0"
|
|
148
148
|
parse = '(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.(?P<release>[a-z]+)(?P<candidate>\d+))?'
|
|
149
149
|
serialize = [
|
|
150
150
|
'{major}.{minor}.{patch}.{release}{candidate}',
|
|
@@ -327,19 +327,19 @@ class BaseTransformer:
|
|
|
327
327
|
custom_args = []
|
|
328
328
|
args = inspect.getfullargspec(self.__init__)
|
|
329
329
|
keys = args.args[1:]
|
|
330
|
-
defaults = args.defaults or []
|
|
331
|
-
defaults = dict(zip(keys, defaults))
|
|
332
330
|
instanced = {
|
|
333
331
|
key: getattr(self, key)
|
|
334
332
|
for key in keys
|
|
335
333
|
if key != 'model_missing_values' and hasattr(self, key) # Remove after deprecation
|
|
336
334
|
}
|
|
337
335
|
|
|
336
|
+
defaults = args.defaults or []
|
|
337
|
+
defaults = dict(zip(keys, defaults))
|
|
338
338
|
if defaults == instanced:
|
|
339
339
|
return f'{class_name}()'
|
|
340
340
|
|
|
341
341
|
for arg, value in instanced.items():
|
|
342
|
-
if defaults[arg] != value:
|
|
342
|
+
if arg not in defaults or defaults[arg] != value:
|
|
343
343
|
custom_args.append(f'{arg}={repr(value)}')
|
|
344
344
|
|
|
345
345
|
args_string = ', '.join(custom_args)
|
|
@@ -155,6 +155,7 @@ class AnonymizedFaker(BaseTransformer):
|
|
|
155
155
|
|
|
156
156
|
self.missing_value_generation = missing_value_generation
|
|
157
157
|
self._nan_frequency = 0.0
|
|
158
|
+
self._unique_categories = None
|
|
158
159
|
|
|
159
160
|
@classmethod
|
|
160
161
|
def get_supported_sdtypes(cls):
|
|
@@ -192,11 +193,11 @@ class AnonymizedFaker(BaseTransformer):
|
|
|
192
193
|
faker_attr = self.faker.unique
|
|
193
194
|
else:
|
|
194
195
|
faker_attr = self.faker
|
|
196
|
+
|
|
195
197
|
except AttributeError:
|
|
196
198
|
faker_attr = self.faker.unique if self.enforce_uniqueness else self.faker
|
|
197
199
|
|
|
198
200
|
result = getattr(faker_attr, self.function_name)(**self.function_kwargs)
|
|
199
|
-
|
|
200
201
|
if isinstance(result, Iterable) and not isinstance(result, str):
|
|
201
202
|
result = ', '.join(map(str, result))
|
|
202
203
|
|
|
@@ -236,39 +237,47 @@ class AnonymizedFaker(BaseTransformer):
|
|
|
236
237
|
|
|
237
238
|
def _reverse_transform_cardinality_rule_match(self, sample_size):
|
|
238
239
|
"""Reverse transform the data when the cardinality rule is 'match'."""
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
num_nans = int(self._nan_frequency * sample_size)
|
|
242
|
-
reverse_transformed = np.concatenate([
|
|
243
|
-
reverse_transformed,
|
|
244
|
-
np.full(num_nans, np.nan),
|
|
245
|
-
])
|
|
246
|
-
else:
|
|
247
|
-
num_nans = 0
|
|
240
|
+
num_nans = self._calculate_num_nans(sample_size)
|
|
241
|
+
reverse_transformed = self._generate_nans(num_nans)
|
|
248
242
|
|
|
249
243
|
if sample_size <= num_nans:
|
|
250
244
|
return reverse_transformed
|
|
251
245
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
reverse_transformed = np.concatenate([
|
|
255
|
-
reverse_transformed,
|
|
256
|
-
unique_categories,
|
|
257
|
-
])
|
|
258
|
-
else:
|
|
259
|
-
unique_categories = self._get_unique_categories(self._data_cardinality)
|
|
260
|
-
num_copies = sample_size - self._data_cardinality - num_nans
|
|
261
|
-
copies = np.random.choice(unique_categories, num_copies)
|
|
262
|
-
reverse_transformed = np.concatenate([
|
|
263
|
-
reverse_transformed,
|
|
264
|
-
unique_categories,
|
|
265
|
-
copies,
|
|
266
|
-
])
|
|
246
|
+
remaining_samples = sample_size - num_nans
|
|
247
|
+
sampled_values = self._generate_cardinality_match_values(remaining_samples)
|
|
267
248
|
|
|
249
|
+
reverse_transformed = np.concatenate([reverse_transformed, sampled_values])
|
|
268
250
|
np.random.shuffle(reverse_transformed)
|
|
269
251
|
|
|
270
252
|
return reverse_transformed
|
|
271
253
|
|
|
254
|
+
def _calculate_num_nans(self, sample_size):
|
|
255
|
+
"""Calculate the number of NaN values to generate."""
|
|
256
|
+
if self.missing_value_generation == 'random':
|
|
257
|
+
return int(self._nan_frequency * sample_size)
|
|
258
|
+
|
|
259
|
+
return 0
|
|
260
|
+
|
|
261
|
+
def _generate_nans(self, num_nans):
|
|
262
|
+
"""Generate an array of NaN values."""
|
|
263
|
+
return np.full(num_nans, np.nan, dtype=object)
|
|
264
|
+
|
|
265
|
+
def _generate_cardinality_match_values(self, remaining_samples):
|
|
266
|
+
"""Generate sampled values while ensuring each unique category appears at least once."""
|
|
267
|
+
# Backwards compatibility requires us to generate the values at this point
|
|
268
|
+
if self._unique_categories is None:
|
|
269
|
+
self._unique_categories = self._get_unique_categories(self._data_cardinality)
|
|
270
|
+
|
|
271
|
+
unique_categories = np.array(self._unique_categories)
|
|
272
|
+
if remaining_samples <= len(unique_categories):
|
|
273
|
+
return np.random.choice(unique_categories, remaining_samples, replace=False)
|
|
274
|
+
|
|
275
|
+
# Ensure all unique categories appear at least once
|
|
276
|
+
extra_samples_needed = remaining_samples - len(unique_categories)
|
|
277
|
+
extra_samples = np.random.choice(unique_categories, extra_samples_needed, replace=True)
|
|
278
|
+
|
|
279
|
+
return np.concatenate((unique_categories, extra_samples))
|
|
280
|
+
|
|
272
281
|
def _reverse_transform(self, data):
|
|
273
282
|
"""Generate new anonymized data using a ``faker.provider.function``.
|
|
274
283
|
|
|
@@ -328,6 +337,7 @@ class AnonymizedFaker(BaseTransformer):
|
|
|
328
337
|
raise TransformerInputError(
|
|
329
338
|
'Cardinality "match" rule must specify a cardinality value.'
|
|
330
339
|
)
|
|
340
|
+
|
|
331
341
|
self._data_cardinality = cardinality
|
|
332
342
|
self._nan_frequency = nan_frequency
|
|
333
343
|
|
|
@@ -15,7 +15,7 @@ import sre_parse # isort:skip
|
|
|
15
15
|
|
|
16
16
|
LOGGER = logging.getLogger(__name__)
|
|
17
17
|
|
|
18
|
-
MAX_DECIMALS = sys.float_info.dig
|
|
18
|
+
MAX_DECIMALS = sys.float_info.dig
|
|
19
19
|
DEPRECATED_SDTYPES_MAPPING = {'text': 'id'}
|
|
20
20
|
|
|
21
21
|
|
|
@@ -270,17 +270,19 @@ def learn_rounding_digits(data):
|
|
|
270
270
|
data = data.to_numpy()
|
|
271
271
|
roundable_data = data[~(np.isinf(data.astype(float)) | pd.isna(data))]
|
|
272
272
|
|
|
273
|
-
#
|
|
273
|
+
# Empty dataset
|
|
274
274
|
if len(roundable_data) == 0:
|
|
275
275
|
return None
|
|
276
276
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
return 0
|
|
277
|
+
if roundable_data.dtype == 'object':
|
|
278
|
+
roundable_data = roundable_data.astype(float)
|
|
280
279
|
|
|
281
280
|
# Try to round to fewer digits
|
|
282
|
-
|
|
283
|
-
|
|
281
|
+
highest_int = int(np.max(np.abs(roundable_data)))
|
|
282
|
+
most_digits = len(str(highest_int)) if highest_int != 0 else 0
|
|
283
|
+
max_decimals = max(0, MAX_DECIMALS - most_digits)
|
|
284
|
+
if (roundable_data == roundable_data.round(max_decimals)).all():
|
|
285
|
+
for decimal in range(max_decimals + 1):
|
|
284
286
|
if (roundable_data == roundable_data.round(decimal)).all():
|
|
285
287
|
return decimal
|
|
286
288
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: rdt
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.1.dev0
|
|
4
4
|
Summary: Reversible Data Transforms
|
|
5
5
|
Author-email: "DataCebo, Inc." <info@sdv.dev>
|
|
6
6
|
License: BSL-1.1
|
|
@@ -70,6 +70,7 @@ Requires-Dist: coverage<8,>=4.5.12; extra == "dev"
|
|
|
70
70
|
Requires-Dist: tox<5,>=2.9.1; extra == "dev"
|
|
71
71
|
Requires-Dist: tabulate<1,>=0.8.9; extra == "dev"
|
|
72
72
|
Requires-Dist: invoke; extra == "dev"
|
|
73
|
+
Dynamic: license-file
|
|
73
74
|
|
|
74
75
|
<div align="center">
|
|
75
76
|
<br/>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|