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.
Files changed (43) hide show
  1. {rdt-1.15.0.dev0/rdt.egg-info → rdt-1.15.1.dev0}/PKG-INFO +3 -2
  2. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/pyproject.toml +1 -1
  3. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/__init__.py +1 -1
  4. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/base.py +3 -3
  5. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/anonymizer.py +35 -25
  6. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/utils.py +9 -7
  7. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0/rdt.egg-info}/PKG-INFO +3 -2
  8. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/LICENSE +0 -0
  9. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/README.md +0 -0
  10. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/errors.py +0 -0
  11. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/hyper_transformer.py +0 -0
  12. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/__init__.py +0 -0
  13. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/__init__.py +0 -0
  14. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/base.py +0 -0
  15. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/boolean.py +0 -0
  16. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/categorical.py +0 -0
  17. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/datetime.py +0 -0
  18. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/id.py +0 -0
  19. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/numerical.py +0 -0
  20. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/pii.py +0 -0
  21. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/text.py +0 -0
  22. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/datasets/utils.py +0 -0
  23. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/performance.py +0 -0
  24. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/performance/profiling.py +0 -0
  25. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/__init__.py +0 -0
  26. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/_validators.py +0 -0
  27. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/boolean.py +0 -0
  28. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/categorical.py +0 -0
  29. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/datetime.py +0 -0
  30. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/id.py +0 -0
  31. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/null.py +0 -0
  32. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/numerical.py +0 -0
  33. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/__init__.py +0 -0
  34. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/anonymization.py +0 -0
  35. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/pii/utils.py +0 -0
  36. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt/transformers/text.py +0 -0
  37. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/SOURCES.txt +0 -0
  38. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/dependency_links.txt +0 -0
  39. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/entry_points.txt +0 -0
  40. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/requires.txt +0 -0
  41. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/rdt.egg-info/top_level.txt +0 -0
  42. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/setup.cfg +0 -0
  43. {rdt-1.15.0.dev0 → rdt-1.15.1.dev0}/tests/test_tasks.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: rdt
3
- Version: 1.15.0.dev0
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.0.dev0"
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}',
@@ -4,7 +4,7 @@
4
4
 
5
5
  __author__ = 'DataCebo, Inc.'
6
6
  __email__ = 'info@sdv.dev'
7
- __version__ = '1.15.0.dev0'
7
+ __version__ = '1.15.1.dev0'
8
8
 
9
9
 
10
10
  import sys
@@ -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
- reverse_transformed = np.array([], dtype=object)
240
- if self.missing_value_generation == 'random':
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
- if sample_size < num_nans + self._data_cardinality:
253
- unique_categories = self._get_unique_categories(sample_size - num_nans)
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 - 1
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
- # Doesn't contain numbers
273
+ # Empty dataset
274
274
  if len(roundable_data) == 0:
275
275
  return None
276
276
 
277
- # Doesn't contain decimal digits
278
- if (roundable_data == roundable_data.astype(int)).all():
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
- if (roundable_data == roundable_data.round(MAX_DECIMALS)).all():
283
- for decimal in range(MAX_DECIMALS + 1):
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.2
1
+ Metadata-Version: 2.4
2
2
  Name: rdt
3
- Version: 1.15.0.dev0
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