rdt 1.4.2.dev0__tar.gz → 1.5.0__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 (95) hide show
  1. {rdt-1.4.2.dev0 → rdt-1.5.0}/CONTRIBUTING.rst +5 -71
  2. {rdt-1.4.2.dev0 → rdt-1.5.0}/HISTORY.md +34 -0
  3. {rdt-1.4.2.dev0 → rdt-1.5.0}/PKG-INFO +35 -1
  4. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/__init__.py +74 -5
  5. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/categorical.py +3 -3
  6. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/pii.py +2 -2
  7. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/performance.py +6 -6
  8. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/base.py +62 -9
  9. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/boolean.py +19 -7
  10. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/datetime.py +36 -14
  11. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/null.py +41 -25
  12. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/numerical.py +58 -23
  13. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/pii/anonymizer.py +3 -3
  14. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt.egg-info/PKG-INFO +35 -1
  15. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt.egg-info/SOURCES.txt +0 -6
  16. {rdt-1.4.2.dev0 → rdt-1.5.0}/setup.cfg +1 -1
  17. {rdt-1.4.2.dev0 → rdt-1.5.0}/setup.py +1 -1
  18. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/contributing.py +0 -69
  19. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/test_hyper_transformer.py +67 -14
  20. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/test_transformers.py +6 -6
  21. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/test_boolean.py +30 -7
  22. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/test_datetime.py +48 -3
  23. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/test_numerical.py +49 -10
  24. rdt-1.5.0/tests/unit/test___init__.py +194 -0
  25. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/test_hyper_transformer.py +2 -0
  26. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_base.py +89 -6
  27. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_boolean.py +17 -4
  28. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_datetime.py +27 -101
  29. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_null.py +145 -210
  30. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_numerical.py +37 -135
  31. rdt-1.4.2.dev0/rdt/_addons.py +0 -26
  32. rdt-1.4.2.dev0/tests/quality/__init__.py +0 -1
  33. rdt-1.4.2.dev0/tests/quality/dataset_info.csv +0 -465
  34. rdt-1.4.2.dev0/tests/quality/test_quality.py +0 -251
  35. rdt-1.4.2.dev0/tests/quality/utils.py +0 -55
  36. rdt-1.4.2.dev0/tests/unit/test___init__.py +0 -40
  37. rdt-1.4.2.dev0/tests/unit/test__addons.py +0 -45
  38. {rdt-1.4.2.dev0 → rdt-1.5.0}/AUTHORS.rst +0 -0
  39. {rdt-1.4.2.dev0 → rdt-1.5.0}/LICENSE +0 -0
  40. {rdt-1.4.2.dev0 → rdt-1.5.0}/MANIFEST.in +0 -0
  41. {rdt-1.4.2.dev0 → rdt-1.5.0}/README.md +0 -0
  42. {rdt-1.4.2.dev0 → rdt-1.5.0}/RELEASE.md +0 -0
  43. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/errors.py +0 -0
  44. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/hyper_transformer.py +0 -0
  45. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/__init__.py +0 -0
  46. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/__init__.py +0 -0
  47. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/base.py +0 -0
  48. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/boolean.py +0 -0
  49. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/datetime.py +0 -0
  50. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/numerical.py +0 -0
  51. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/text.py +0 -0
  52. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/datasets/utils.py +0 -0
  53. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/performance/profiling.py +0 -0
  54. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/__init__.py +0 -0
  55. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/addons/addons_setup.py +0 -0
  56. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/categorical.py +0 -0
  57. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/pii/__init__.py +0 -0
  58. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/pii/utils.py +0 -0
  59. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/text.py +0 -0
  60. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt/transformers/utils.py +0 -0
  61. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt.egg-info/dependency_links.txt +0 -0
  62. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt.egg-info/not-zip-safe +0 -0
  63. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt.egg-info/requires.txt +0 -0
  64. {rdt-1.4.2.dev0 → rdt-1.5.0}/rdt.egg-info/top_level.txt +0 -0
  65. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/__init__.py +0 -0
  66. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/code_style.py +0 -0
  67. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/datasets/tests/test_boolean.py +0 -0
  68. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/datasets/tests/test_categorical.py +0 -0
  69. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/datasets/tests/test_datetime.py +0 -0
  70. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/datasets/tests/test_numerical.py +0 -0
  71. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/datasets/tests/test_utils.py +0 -0
  72. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/__init__.py +0 -0
  73. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/__init__.py +0 -0
  74. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/pii/__init__.py +0 -0
  75. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/pii/test_anonymizer.py +0 -0
  76. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/test_base.py +0 -0
  77. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/test_categorical.py +0 -0
  78. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/integration/transformers/test_text.py +0 -0
  79. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/performance/README.md +0 -0
  80. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/performance/__init__.py +0 -0
  81. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/performance/test_performance.py +0 -0
  82. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/performance/tests/__init__.py +0 -0
  83. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/performance/tests/test_profiling.py +0 -0
  84. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/__init__.py +0 -0
  85. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/__init__.py +0 -0
  86. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/addons/__init__.py +0 -0
  87. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/addons/identity/__init__.py +0 -0
  88. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/addons/identity/test_identity.py +0 -0
  89. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/pii/__init__.py +0 -0
  90. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/pii/test_anonymizer.py +0 -0
  91. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/pii/test_utils.py +0 -0
  92. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test___init__.py +0 -0
  93. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_categorical.py +0 -0
  94. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_text.py +0 -0
  95. {rdt-1.4.2.dev0 → rdt-1.5.0}/tests/unit/transformers/test_utils.py +0 -0
@@ -175,10 +175,9 @@ class uses. In some cases, integration tests may also be required. More details
175
175
  found below.
176
176
 
177
177
  If the transformer adds a previously unsupported `sdtype` to RDT, then more steps will need
178
- to be taken for the quality and performance tests. A new `DatasetGenerator` class may need to
179
- be created for the `sdtype`. You may also need to find a real world dataset containing this
180
- `sdtype` and request for it to be added. More details for these steps can be found below in
181
- the `Transformer Performance`_ and `Transformer Quality`_ sections respectively.
178
+ to be taken for performance tests. A new `DatasetGenerator` class may need to be created for
179
+ the `sdtype`. More details for these steps can be found below in the `Transformer Performance`_
180
+ section.
182
181
 
183
182
  Transformer Validations
184
183
  ~~~~~~~~~~~~~~~~~~~~~~~
@@ -418,64 +417,6 @@ of the transformer.
418
417
  Fix any performance issues that are reported. If there are no errors but performance
419
418
  can be improved, this function should be used for reference.
420
419
 
421
- .. _Transformer Quality:
422
-
423
- Transformer Quality
424
- """""""""""""""""""
425
-
426
- To assess the quality of a transformer, we run quality tests that apply the Transformer
427
- on all the real world datasets that contain the Transformer input sdtype. The quality tests
428
- look at how well the original correlations are preserved by using transformed data to train
429
- regression models that predict other columns in the data. We compare the transformer's quality
430
- results to that of other transformers of the same sdtype.
431
-
432
- .. _Adding a Dataset:
433
-
434
- Adding a Dataset
435
- ****************
436
-
437
- If the transformer you are creating adds a new sdtype, then a dataset with that sdtype may need to
438
- be added for the quality tests. This only needs to be done if the transformer being added is
439
- expected to preserve or expose relationships in the data. This can be done using the following
440
- steps:
441
-
442
- 1. Find a dataset containing the sdtype your transformer uses as an input.
443
-
444
- 2. Test your transformer against this dataset by loading it into a ``DataFrame`` and using the
445
- ``get_transformer_regression_scores`` in the ``test_quality`` package::
446
-
447
- from tests.quality.test_quality import get_transformer_regression_scores
448
- get_transformer_regression_scores(data, sdtype, dataset_name, [transformer])
449
-
450
- 3. If the scores are higher than the ``TEST_THRESHOLD`` in the ``test_quality`` package, contact
451
- one of the `RDT core contributors`_ on GitHub and ask them to add the dataset. Once this is
452
- done, the quality tests should pass.
453
-
454
- Validating Quality
455
- ******************
456
-
457
- Validate the quality of your transformer using the ``validate_transformer_quality`` function.
458
- This function returns a ``pandas.DataFrame`` containing the scores attained by the transformer
459
- on each dataset, how that score compares to average and whether or not it is acceptable.
460
-
461
- .. code-block:: Python
462
-
463
- In [1]: from tests.contributing import validate_transformer_quality
464
-
465
- In [2]: results = validate_transformer_quality('rdt.transformers.FrequencyEncoder') # Replace FrequencyEncoder with your transformer
466
- Validating Quality Tests for transformer FrequencyEncoder
467
-
468
- SUCCESS: The quality tests were successful.
469
-
470
- In [3]: results
471
- Out [3]:
472
- Dataset Score Compared To Average Acceptable
473
- 0 adult 0.223325 0.443181 True
474
- 1 student_placements 0.457490 0.994631 True
475
- 2 student_placements_pii 0.457490 0.988428 True
476
-
477
- Fix any quality issues that are reported.
478
-
479
420
  Finalize Your Transformer
480
421
  """""""""""""""""""""""""
481
422
 
@@ -496,7 +437,6 @@ above. It also prints a table summarizing the results of all these checks.
496
437
  Unit Tests Yes The unit tests are correct and run successfully.
497
438
  Integration tests Yes The integration tests run successfully.
498
439
  Performance Tests Yes The performance of the transformer is acceptable.
499
- Quality tests Yes The output data quality is acceptable.
500
440
  Clean Repository Yes There are no unexpected changes in the repository.
501
441
 
502
442
  SUCCESS: The Pull Request can be made!
@@ -528,14 +468,8 @@ Summary of Steps to Add a New Transformer
528
468
  10. Run the ``validate_transformer_performance`` function and fix any errors reported.
529
469
  If there are no errors but performance can be improved, this function should be used for
530
470
  reference.
531
- 11. If this transformer is expected to help preserve relationships in the data, run the
532
- ``validate_transformer_quality`` function. If the quality is too low, make the
533
- necessary enhancements to the transformer.
534
- 12. If the quality tests fail because there is no dataset for the transformer's sdtype,
535
- follow the steps in the `Adding a Dataset`_ section to add a real world dataset
536
- containing the new sdtype to the quality tests.
537
- 13. Run the ``validate_pull_request`` function as a final check and fix any errors reported.
538
- 14. After all the previous steps pass, all the new and modified files can be committed and pushed
471
+ 11. Run the ``validate_pull_request`` function as a final check and fix any errors reported.
472
+ 12. After all the previous steps pass, all the new and modified files can be committed and pushed
539
473
  to github, and a Pull Request can be submitted. Follow the steps in the
540
474
  `Pull Request Guidelines`_ section to submit your Pull Request.
541
475
 
@@ -1,5 +1,39 @@
1
1
  # History
2
2
 
3
+ ## 1.5.0 - 2023-06-01
4
+
5
+ This release adds a new parameter called `missing_value_generation` to the initialization of certain transformers to specify how missing values should be created. The parameter can be used in the `FloatFormatter`, `BinaryEncoder`, `UnixTimestampEncoder`, `OptimizedTimestampEncoder`, `GaussianNormalizer` and `ClusterBasedNormalizer`. Additionally, it fixes a bug that was causing every column that had nulls to generate them in the same place.
6
+
7
+ ### Deprecations
8
+
9
+ * The `model_missing_values` parameter is being deprecated in favor of the new `missing_value_generation` parameter.
10
+
11
+ ### Bugs
12
+
13
+ * Fix randomization when creating null values - Issue [#639](https://github.com/sdv-dev/RDT/issues/639) by @fealho
14
+
15
+ ### New Features
16
+
17
+ * Allow a no-op handling strategy for missing values (nulls) - Issue [#644](https://github.com/sdv-dev/RDT/issues/644) by @pvk-developer
18
+ * Add add-on detection for premium transformers - Issue [#646](https://github.com/sdv-dev/RDT/issues/646) by @frances-h
19
+
20
+ ### Maintenance
21
+
22
+ * Performance tests still fragile - Issue [#641](https://github.com/sdv-dev/RDT/issues/641) by @fealho
23
+ * Investigate removing quality tests - Issue [#642](https://github.com/sdv-dev/RDT/issues/642) by @amontanez24
24
+
25
+ ## 1.4.2 - 2023-05-02
26
+
27
+ This release fixes a bug that caused datetime and numerical transformers to crash if a column was all NaNs. Additionally, it adds support for Pandas 2.0!
28
+
29
+ ### Bugs
30
+
31
+ * Numerical & datetime transformers crash if the entire column is null - Issue [#637](https://github.com/sdv-dev/RDT/issues/637) by @fraces-h
32
+
33
+ ### Maintenance
34
+
35
+ * Remove upper bound for pandas - Issue [#633](https://github.com/sdv-dev/RDT/issues/633) by @pvk-developer
36
+
3
37
  ## 1.4.1 - 2023-04-25
4
38
 
5
39
  This release patches an issue that prevented the `RegexGenerator` from working with regexes that had a very large number of possible combinations.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rdt
3
- Version: 1.4.2.dev0
3
+ Version: 1.5.0
4
4
  Summary: Reversible Data Transforms
5
5
  Home-page: https://github.com/sdv-dev/RDT
6
6
  Author: DataCebo, Inc.
@@ -226,6 +226,40 @@ for specific needs.
226
226
 
227
227
  # History
228
228
 
229
+ ## 1.5.0 - 2023-06-01
230
+
231
+ This release adds a new parameter called `missing_value_generation` to the initialization of certain transformers to specify how missing values should be created. The parameter can be used in the `FloatFormatter`, `BinaryEncoder`, `UnixTimestampEncoder`, `OptimizedTimestampEncoder`, `GaussianNormalizer` and `ClusterBasedNormalizer`. Additionally, it fixes a bug that was causing every column that had nulls to generate them in the same place.
232
+
233
+ ### Deprecations
234
+
235
+ * The `model_missing_values` parameter is being deprecated in favor of the new `missing_value_generation` parameter.
236
+
237
+ ### Bugs
238
+
239
+ * Fix randomization when creating null values - Issue [#639](https://github.com/sdv-dev/RDT/issues/639) by @fealho
240
+
241
+ ### New Features
242
+
243
+ * Allow a no-op handling strategy for missing values (nulls) - Issue [#644](https://github.com/sdv-dev/RDT/issues/644) by @pvk-developer
244
+ * Add add-on detection for premium transformers - Issue [#646](https://github.com/sdv-dev/RDT/issues/646) by @frances-h
245
+
246
+ ### Maintenance
247
+
248
+ * Performance tests still fragile - Issue [#641](https://github.com/sdv-dev/RDT/issues/641) by @fealho
249
+ * Investigate removing quality tests - Issue [#642](https://github.com/sdv-dev/RDT/issues/642) by @amontanez24
250
+
251
+ ## 1.4.2 - 2023-05-02
252
+
253
+ This release fixes a bug that caused datetime and numerical transformers to crash if a column was all NaNs. Additionally, it adds support for Pandas 2.0!
254
+
255
+ ### Bugs
256
+
257
+ * Numerical & datetime transformers crash if the entire column is null - Issue [#637](https://github.com/sdv-dev/RDT/issues/637) by @fraces-h
258
+
259
+ ### Maintenance
260
+
261
+ * Remove upper bound for pandas - Issue [#633](https://github.com/sdv-dev/RDT/issues/633) by @pvk-developer
262
+
229
263
  ## 1.4.1 - 2023-04-25
230
264
 
231
265
  This release patches an issue that prevented the `RegexGenerator` from working with regexes that had a very large number of possible combinations.
@@ -5,14 +5,18 @@
5
5
 
6
6
  __author__ = 'DataCebo, Inc.'
7
7
  __email__ = 'info@sdv.dev'
8
- __version__ = '1.4.2.dev0'
8
+ __version__ = '1.5.0'
9
9
 
10
10
 
11
+ import sys
12
+ import warnings
13
+ from operator import attrgetter
14
+
11
15
  import numpy as np
12
16
  import pandas as pd
17
+ from pkg_resources import iter_entry_points
13
18
 
14
19
  from rdt import transformers
15
- from rdt._addons import _find_addons
16
20
  from rdt.hyper_transformer import HyperTransformer
17
21
 
18
22
  __all__ = [
@@ -23,9 +27,6 @@ __all__ = [
23
27
  RANDOM_SEED = 42
24
28
 
25
29
 
26
- _find_addons(group='rdt_modules', parent_globals=globals())
27
-
28
-
29
30
  def get_demo(num_rows=5):
30
31
  """Generate demo data with multiple sdtypes.
31
32
 
@@ -92,3 +93,71 @@ def get_demo(num_rows=5):
92
93
  'dollars_spent': dollars_spent
93
94
  })
94
95
  ], ignore_index=True)
96
+
97
+
98
+ def _get_addon_target(addon_path_name):
99
+ """Find the target object for the add-on.
100
+
101
+ Args:
102
+ addon_path_name (str):
103
+ The add-on's name. The add-on's name should be the full path of valid Python
104
+ identifiers (i.e. importable.module:object.attr).
105
+
106
+ Returns:
107
+ tuple:
108
+ * object:
109
+ The base module or object the add-on should be added to.
110
+ * str:
111
+ The name the add-on should be added to under the module or object.
112
+ """
113
+ module_path, _, object_path = addon_path_name.partition(':')
114
+ module_path = module_path.split('.')
115
+
116
+ if module_path[0] != __name__:
117
+ msg = f"expected base module to be '{__name__}', found '{module_path[0]}'"
118
+ raise AttributeError(msg)
119
+
120
+ target_base = sys.modules[__name__]
121
+ for submodule in module_path[1:-1]:
122
+ target_base = getattr(target_base, submodule)
123
+
124
+ addon_name = module_path[-1]
125
+ if object_path:
126
+ if len(module_path) > 1 and not hasattr(target_base, module_path[-1]):
127
+ msg = f"cannot add '{object_path}' to unknown submodule '{'.'.join(module_path)}'"
128
+ raise AttributeError(msg)
129
+
130
+ if len(module_path) > 1:
131
+ target_base = getattr(target_base, module_path[-1])
132
+
133
+ split_object = object_path.split('.')
134
+ addon_name = split_object[-1]
135
+
136
+ if len(split_object) > 1:
137
+ target_base = attrgetter('.'.join(split_object[:-1]))(target_base)
138
+
139
+ return target_base, addon_name
140
+
141
+
142
+ def _find_addons():
143
+ """Find and load all RDT add-ons."""
144
+ group = 'rdt_modules'
145
+ for entry_point in iter_entry_points(group=group):
146
+ try:
147
+ addon = entry_point.load()
148
+ except Exception: # pylint: disable=broad-exception-caught
149
+ msg = f'Failed to load "{entry_point.name}" from "{entry_point.module_name}".'
150
+ warnings.warn(msg)
151
+ continue
152
+
153
+ try:
154
+ addon_target, addon_name = _get_addon_target(entry_point.name)
155
+ except AttributeError as error:
156
+ msg = f"Failed to set '{entry_point.name}': {error}."
157
+ warnings.warn(msg)
158
+ continue
159
+
160
+ setattr(addon_target, addon_name, addon)
161
+
162
+
163
+ _find_addons()
@@ -335,7 +335,7 @@ class UniqueIntegerGenerator(CategoricalGenerator):
335
335
  'memory': 500000.0
336
336
  },
337
337
  'reverse_transform': {
338
- 'time': 0.0004,
338
+ 'time': 0.0005,
339
339
  'memory': 1000000.0,
340
340
  }
341
341
  }
@@ -362,7 +362,7 @@ class UniqueIntegerNaNsGenerator(CategoricalGenerator):
362
362
  'memory': 1000000.0
363
363
  },
364
364
  'reverse_transform': {
365
- 'time': 0.0004,
365
+ 'time': 0.0005,
366
366
  'memory': 1000000.0,
367
367
  }
368
368
  }
@@ -389,7 +389,7 @@ class UniqueStringGenerator(CategoricalGenerator):
389
389
  'memory': 500000.0
390
390
  },
391
391
  'reverse_transform': {
392
- 'time': 0.0004,
392
+ 'time': 0.0005,
393
393
  'memory': 1000000.0,
394
394
  }
395
395
  }
@@ -36,7 +36,7 @@ class RandomStringGenerator(PIIGenerator):
36
36
  'memory': 500.0
37
37
  },
38
38
  'reverse_transform': {
39
- 'time': 2e-05,
39
+ 'time': 3e-05,
40
40
  'memory': 1000.0,
41
41
  }
42
42
  }
@@ -63,7 +63,7 @@ class RandomStringNaNsGenerator(PIIGenerator):
63
63
  'memory': 1000.0
64
64
  },
65
65
  'reverse_transform': {
66
- 'time': 2e-05,
66
+ 'time': 3e-05,
67
67
  'memory': 1000.0,
68
68
  }
69
69
  }
@@ -11,22 +11,22 @@ DATASET_SIZES = [1000, 10000, 100000]
11
11
  TRANSFORMER_ARGS = {
12
12
  'BinaryEncoder': {
13
13
  'missing_value_replacement': -1,
14
- 'model_missing_values': True
14
+ 'missing_value_generation': 'from_column'
15
15
  },
16
16
  'UnixTimestampEncoder': {
17
- 'model_missing_values': True
17
+ 'missing_value_generation': 'from_column'
18
18
  },
19
19
  'OptimizedTimestampEncoder': {
20
- 'model_missing_values': True
20
+ 'missing_value_generation': 'from_column'
21
21
  },
22
22
  'FloatFormatter': {
23
- 'model_missing_values': True
23
+ 'missing_value_generation': 'from_column'
24
24
  },
25
25
  'GaussianNormalizer': {
26
- 'model_missing_values': True
26
+ 'missing_value_generation': 'from_column'
27
27
  },
28
28
  'ClusterBasedNormalizer': {
29
- 'model_missing_values': True
29
+ 'missing_value_generation': 'from_column'
30
30
  },
31
31
  }
32
32
 
@@ -1,6 +1,7 @@
1
1
  """BaseTransformer module."""
2
2
  import abc
3
3
  import contextlib
4
+ import hashlib
4
5
  import inspect
5
6
  import warnings
6
7
  from functools import wraps
@@ -8,6 +9,8 @@ from functools import wraps
8
9
  import numpy as np
9
10
  import pandas as pd
10
11
 
12
+ from rdt.errors import TransformerInputError
13
+
11
14
 
12
15
  @contextlib.contextmanager
13
16
  def set_random_states(random_states, method_name, set_model_random_state):
@@ -65,21 +68,21 @@ class BaseTransformer:
65
68
  INPUT_SDTYPE = None
66
69
  SUPPORTED_SDTYPES = None
67
70
  IS_GENERATOR = None
68
- INITIAL_FIT_STATE = np.random.RandomState(seed=21)
69
- INITIAL_TRANSFORM_STATE = np.random.RandomState(seed=80)
70
- INITIAL_REVERSE_TRANSFORM_STATE = np.random.RandomState(seed=130)
71
+ INITIAL_FIT_STATE = np.random.RandomState(42)
71
72
 
72
73
  columns = None
73
74
  column_prefix = None
74
75
  output_columns = None
76
+ random_seed = 42
75
77
  missing_value_replacement = None
78
+ missing_value_generation = None
76
79
 
77
80
  def __init__(self):
78
81
  self.output_properties = {None: {'sdtype': 'float', 'next_transformer': None}}
79
82
  self.random_states = {
80
83
  'fit': self.INITIAL_FIT_STATE,
81
- 'transform': self.INITIAL_TRANSFORM_STATE,
82
- 'reverse_transform': self.INITIAL_REVERSE_TRANSFORM_STATE
84
+ 'transform': None,
85
+ 'reverse_transform': None
83
86
  }
84
87
 
85
88
  def set_random_state(self, state, method_name):
@@ -100,9 +103,41 @@ class BaseTransformer:
100
103
 
101
104
  def reset_randomization(self):
102
105
  """Reset the random state for ``reverse_transform``."""
103
- self.set_random_state(self.INITIAL_FIT_STATE, 'fit')
104
- self.set_random_state(self.INITIAL_TRANSFORM_STATE, 'transform')
105
- self.set_random_state(self.INITIAL_REVERSE_TRANSFORM_STATE, 'reverse_transform')
106
+ self.random_states = {
107
+ 'fit': self.INITIAL_FIT_STATE,
108
+ 'transform': np.random.RandomState(self.random_seed),
109
+ 'reverse_transform': np.random.RandomState(self.random_seed + 1)
110
+ }
111
+
112
+ @property
113
+ def model_missing_values(self):
114
+ """Return whether or not a new column is being used to model missing values."""
115
+ warnings.warn(
116
+ "Future versions of RDT will not support the 'model_missing_values' parameter. "
117
+ "Please switch to using the 'missing_value_generation' parameter instead.",
118
+ FutureWarning
119
+ )
120
+ return self.missing_value_generation == 'from_column'
121
+
122
+ def _set_missing_value_generation(self, missing_value_generation):
123
+ if missing_value_generation not in (None, 'from_column', 'random'):
124
+ raise TransformerInputError(
125
+ "'missing_value_generation' must be one of the following values: "
126
+ "None, 'from_column' or 'random'."
127
+ )
128
+
129
+ self.missing_value_generation = missing_value_generation
130
+
131
+ def _set_model_missing_values(self, model_missing_values):
132
+ warnings.warn(
133
+ "Future versions of RDT will not support the 'model_missing_values' parameter. "
134
+ "Please switch to using the 'missing_value_generation' parameter to select your "
135
+ 'strategy.', FutureWarning
136
+ )
137
+ if model_missing_values is True:
138
+ self._set_missing_value_generation('from_column')
139
+ elif model_missing_values is False:
140
+ self._set_missing_value_generation('random')
106
141
 
107
142
  def _set_missing_value_replacement(self, default, missing_value_replacement):
108
143
  if missing_value_replacement is None:
@@ -297,7 +332,11 @@ class BaseTransformer:
297
332
  keys = args.args[1:]
298
333
  defaults = args.defaults or []
299
334
  defaults = dict(zip(keys, defaults))
300
- instanced = {key: getattr(self, key) for key in keys}
335
+ instanced = {
336
+ key: getattr(self, key)
337
+ for key in keys
338
+ if key != 'model_missing_values' # Remove after deprecation
339
+ }
301
340
 
302
341
  if defaults == instanced:
303
342
  return f'{class_name}()'
@@ -318,6 +357,19 @@ class BaseTransformer:
318
357
  """
319
358
  raise NotImplementedError()
320
359
 
360
+ def _set_seed(self, data):
361
+ hash_value = self.get_input_column()
362
+ for value in data.head(5):
363
+ hash_value += str(value)
364
+
365
+ hash_value = int(hashlib.sha256(hash_value.encode('utf-8')).hexdigest(), 16)
366
+ self.random_seed = hash_value % ((2 ** 32) - 1) # maximum value for a seed
367
+ self.random_states = {
368
+ 'fit': self.INITIAL_FIT_STATE,
369
+ 'transform': np.random.RandomState(self.random_seed),
370
+ 'reverse_transform': np.random.RandomState(self.random_seed + 1)
371
+ }
372
+
321
373
  @random_state
322
374
  def fit(self, data, column):
323
375
  """Fit the transformer to a ``column`` of the ``data``.
@@ -329,6 +381,7 @@ class BaseTransformer:
329
381
  Column name. Must be present in the data.
330
382
  """
331
383
  self._store_columns(column, data)
384
+ self._set_seed(data)
332
385
  columns_data = self._get_columns_data(data, self.columns)
333
386
  self._fit(columns_data)
334
387
  self._build_output_columns(data)
@@ -21,19 +21,31 @@ class BinaryEncoder(BaseTransformer):
21
21
  replace them with the most common value.
22
22
  Defaults to ``mode``.
23
23
  model_missing_values (bool):
24
- Whether to create a new column to indicate which values were null or not. The column
25
- will be created only if there are null values. If ``True``, create the new column if
26
- there are null values. If ``False``, do not create the new column even if there
27
- are null values. Defaults to ``False``.
24
+ **DEPRECATED** Whether to create a new column to indicate which values were null or
25
+ not. The column will be created only if there are null values. If ``True``, create
26
+ the new column if there are null values. If ``False``, do not create the new column
27
+ even if there are null values. Defaults to ``False``.
28
+ missing_value_generation (str or None):
29
+ The way missing values are being handled. There are three strategies:
30
+
31
+ * ``random``: Randomly generates missing values based on the percentage of
32
+ missing values.
33
+ * ``from_column``: Creates a binary column that describes whether the original
34
+ value was missing. Then use it to recreate missing values.
35
+ * ``None``: Do nothing with the missing values on the reverse transform. Simply
36
+ pass whatever data we get through.
28
37
  """
29
38
 
30
39
  INPUT_SDTYPE = 'boolean'
31
40
  null_transformer = None
32
41
 
33
- def __init__(self, missing_value_replacement='mode', model_missing_values=False):
42
+ def __init__(self, missing_value_replacement='mode', model_missing_values=None,
43
+ missing_value_generation='random'):
34
44
  super().__init__()
45
+ self._set_missing_value_generation(missing_value_generation)
35
46
  self._set_missing_value_replacement('mode', missing_value_replacement)
36
- self.model_missing_values = model_missing_values
47
+ if model_missing_values is not None:
48
+ self._set_model_missing_values(model_missing_values)
37
49
 
38
50
  def _fit(self, data):
39
51
  """Fit the transformer to the data.
@@ -44,7 +56,7 @@ class BinaryEncoder(BaseTransformer):
44
56
  """
45
57
  self.null_transformer = NullTransformer(
46
58
  self.missing_value_replacement,
47
- self.model_missing_values
59
+ self.missing_value_generation
48
60
  )
49
61
  self.null_transformer.fit(data)
50
62
  if self.null_transformer.models_missing_values():
@@ -22,23 +22,35 @@ class UnixTimestampEncoder(BaseTransformer):
22
22
  are given, replace them with the corresponding aggregation.
23
23
  Defaults to ``mean``.
24
24
  model_missing_values (bool):
25
- Whether to create a new column to indicate which values were null or not. The column
26
- will be created only if there are null values. If ``True``, create the new column if
27
- there are null values. If ``False``, do not create the new column even if there
28
- are null values. Defaults to ``False``.
25
+ **DEPRECATED** Whether to create a new column to indicate which values were null or
26
+ not. The column will be created only if there are null values. If ``True``, create
27
+ the new column if there are null values. If ``False``, do not create the new column
28
+ even if there are null values. Defaults to ``False``.
29
29
  datetime_format (str):
30
30
  The strftime to use for parsing time. For more information, see
31
31
  https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior.
32
+ missing_value_generation (str or None):
33
+ The way missing values are being handled. There are three strategies:
34
+
35
+ * ``random``: Randomly generates missing values based on the percentage of
36
+ missing values.
37
+ * ``from_column``: Creates a binary column that describes whether the original
38
+ value was missing. Then use it to recreate missing values.
39
+ * ``None``: Do nothing with the missing values on the reverse transform. Simply
40
+ pass whatever data we get through.
32
41
  """
33
42
 
34
43
  INPUT_SDTYPE = 'datetime'
35
44
  null_transformer = None
36
45
 
37
- def __init__(self, missing_value_replacement='mean', model_missing_values=False,
38
- datetime_format=None):
46
+ def __init__(self, missing_value_replacement='mean', model_missing_values=None,
47
+ datetime_format=None, missing_value_generation='random'):
39
48
  super().__init__()
40
49
  self._set_missing_value_replacement('mean', missing_value_replacement)
41
- self.model_missing_values = model_missing_values
50
+ self._set_missing_value_generation(missing_value_generation)
51
+ if model_missing_values is not None:
52
+ self._set_model_missing_values(model_missing_values)
53
+
42
54
  self.datetime_format = datetime_format
43
55
  self._dtype = None
44
56
 
@@ -94,7 +106,7 @@ class UnixTimestampEncoder(BaseTransformer):
94
106
  transformed = self._transform_helper(data)
95
107
  self.null_transformer = NullTransformer(
96
108
  self.missing_value_replacement,
97
- self.model_missing_values
109
+ self.missing_value_generation
98
110
  )
99
111
  self.null_transformer.fit(transformed)
100
112
  if self.null_transformer.models_missing_values():
@@ -156,20 +168,30 @@ class OptimizedTimestampEncoder(UnixTimestampEncoder):
156
168
  are given, replace them with the corresponding aggregation.
157
169
  Defaults to ``mean``.
158
170
  model_missing_values (bool):
159
- Whether to create a new column to indicate which values were null or not. The column
160
- will be created only if there are null values. If ``True``, create the new column if
161
- there are null values. If ``False``, do not create the new column even if there
162
- are null values. Defaults to ``False``.
171
+ **DEPRECATED** Whether to create a new column to indicate which values were null or
172
+ not. The column will be created only if there are null values. If ``True``, create
173
+ the new column if there are null values. If ``False``, do not create the new column
174
+ even if there are null values. Defaults to ``False``.
163
175
  datetime_format (str):
164
176
  The strftime to use for parsing time. For more information, see
165
177
  https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior.
178
+ missing_value_generation (str or None):
179
+ The way missing values are being handled. There are three strategies:
180
+
181
+ * ``random``: Randomly generates missing values based on the percentage of
182
+ missing values.
183
+ * ``from_column``: Creates a binary column that describes whether the original
184
+ value was missing. Then use it to recreate missing values.
185
+ * ``None``: Do nothing with the missing values on the reverse transform. Simply
186
+ pass whatever data we get through.
166
187
  """
167
188
 
168
189
  divider = None
169
190
 
170
- def __init__(self, missing_value_replacement=None, model_missing_values=False,
171
- datetime_format=None):
191
+ def __init__(self, missing_value_replacement=None, model_missing_values=None,
192
+ datetime_format=None, missing_value_generation='random'):
172
193
  super().__init__(missing_value_replacement=missing_value_replacement,
194
+ missing_value_generation=missing_value_generation,
173
195
  model_missing_values=model_missing_values,
174
196
  datetime_format=datetime_format)
175
197