From 85c58e0e6c348dca12cb2a93d1969ed1c0075b35 Mon Sep 17 00:00:00 2001 From: ksneab7 <91956551+ksneab7@users.noreply.github.com> Date: Mon, 7 Aug 2023 14:09:28 -0400 Subject: [PATCH] Update docs to 0.10.3 (#1011) * Add docs to `multiprocess` option in StructuredOptions. (#999) (#1001) * Update multiprocess docs. * Default settings added to docs * Fix hyperlink to profiler options (#1003) * update * EOF line * Add docs for `num_quantiles` option for histogram_and_quantiles. (#991) (#993) * Add docs for `num_quantiles` option for histgram_and_quantiles. * Slight readability change * 0.10.3 generation of docs round 4 --------- Co-authored-by: clee1152 Co-authored-by: jacob-buehler <86370501+jacob-buehler@users.noreply.github.com> --- docs/0.10.3/doctrees/API.doctree | Bin 0 -> 3801 bytes .../add_new_model_to_data_labeler.doctree | Bin 0 -> 40612 bytes .../column_name_labeler_example.doctree | Bin 0 -> 35588 bytes docs/0.10.3/doctrees/data_labeling.doctree | Bin 0 -> 51637 bytes docs/0.10.3/doctrees/data_reader.doctree | Bin 0 -> 65282 bytes docs/0.10.3/doctrees/data_readers.doctree | Bin 0 -> 32150 bytes ...ataprofiler.data_readers.avro_data.doctree | Bin 0 -> 53655 bytes ...ataprofiler.data_readers.base_data.doctree | Bin 0 -> 38505 bytes ...dataprofiler.data_readers.csv_data.doctree | Bin 0 -> 60445 bytes .../dataprofiler.data_readers.data.doctree | Bin 0 -> 17090 bytes ...taprofiler.data_readers.data_utils.doctree | Bin 0 -> 166492 bytes .../dataprofiler.data_readers.doctree | Bin 0 -> 4751 bytes ...er.data_readers.filepath_or_buffer.doctree | Bin 0 -> 23326 bytes ...taprofiler.data_readers.graph_data.doctree | Bin 0 -> 54908 bytes ...ataprofiler.data_readers.json_data.doctree | Bin 0 -> 56476 bytes ...profiler.data_readers.parquet_data.doctree | Bin 0 -> 52869 bytes ...ler.data_readers.structured_mixins.doctree | Bin 0 -> 12097 bytes ...ataprofiler.data_readers.text_data.doctree | Bin 0 -> 51851 bytes docs/0.10.3/doctrees/dataprofiler.doctree | Bin 0 -> 5979 bytes .../doctrees/dataprofiler.dp_logging.doctree | Bin 0 -> 11370 bytes ...rofiler.labelers.base_data_labeler.doctree | Bin 0 -> 220582 bytes .../dataprofiler.labelers.base_model.doctree | Bin 0 -> 156461 bytes ...ofiler.labelers.char_load_tf_model.doctree | Bin 0 -> 90531 bytes ...labelers.character_level_cnn_model.doctree | Bin 0 -> 101599 bytes ...belers.classification_report_utils.doctree | Bin 0 -> 84114 bytes ...rofiler.labelers.column_name_model.doctree | Bin 0 -> 66841 bytes ...ataprofiler.labelers.data_labelers.doctree | Bin 0 -> 248437 bytes ...aprofiler.labelers.data_processing.doctree | Bin 0 -> 565765 bytes .../doctrees/dataprofiler.labelers.doctree | Bin 0 -> 11233 bytes ...ataprofiler.labelers.labeler_utils.doctree | Bin 0 -> 545872 bytes .../dataprofiler.labelers.regex_model.doctree | Bin 0 -> 73328 bytes .../dataprofiler.labelers.utils.doctree | Bin 0 -> 12980 bytes ...er.profilers.base_column_profilers.doctree | Bin 0 -> 76419 bytes ...ofilers.categorical_column_profile.doctree | Bin 0 -> 61390 bytes ...profilers.column_profile_compilers.doctree | Bin 0 -> 178393 bytes ...filers.data_labeler_column_profile.doctree | Bin 0 -> 66421 bytes ....profilers.datetime_column_profile.doctree | Bin 0 -> 48159 bytes .../doctrees/dataprofiler.profilers.doctree | Bin 0 -> 5238 bytes ...ler.profilers.float_column_profile.doctree | Bin 0 -> 84250 bytes ...aprofiler.profilers.graph_profiler.doctree | Bin 0 -> 37821 bytes .../dataprofiler.profilers.helpers.doctree | Bin 0 -> 13352 bytes ...r.profilers.helpers.report_helpers.doctree | Bin 0 -> 20133 bytes ...profiler.profilers.histogram_utils.doctree | Bin 0 -> 4361 bytes ...filer.profilers.int_column_profile.doctree | Bin 0 -> 81817 bytes ...ataprofiler.profilers.json_decoder.doctree | Bin 0 -> 85194 bytes ...ataprofiler.profilers.json_encoder.doctree | Bin 0 -> 25519 bytes ...r.profilers.numerical_column_stats.doctree | Bin 0 -> 84175 bytes ...ler.profilers.order_column_profile.doctree | Bin 0 -> 47478 bytes ...profiler.profilers.profile_builder.doctree | Bin 0 -> 268990 bytes ...rofiler.profilers.profiler_options.doctree | Bin 0 -> 757736 bytes ...aprofiler.profilers.profiler_utils.doctree | Bin 0 -> 221850 bytes ...iler.profilers.text_column_profile.doctree | Bin 0 -> 106277 bytes ...ilers.unstructured_labeler_profile.doctree | Bin 0 -> 30575 bytes ...rofilers.unstructured_text_profile.doctree | Bin 0 -> 28381 bytes .../dataprofiler.profilers.utils.doctree | Bin 0 -> 2343 bytes .../doctrees/dataprofiler.reports.doctree | Bin 0 -> 4198 bytes .../dataprofiler.reports.graphs.doctree | Bin 0 -> 3236 bytes .../dataprofiler.reports.utils.doctree | Bin 0 -> 13944 bytes .../doctrees/dataprofiler.rng_utils.doctree | Bin 0 -> 5342 bytes .../doctrees/dataprofiler.settings.doctree | Bin 0 -> 3158 bytes ...rofiler.validators.base_validators.doctree | Bin 0 -> 26747 bytes .../doctrees/dataprofiler.validators.doctree | Bin 0 -> 4215 bytes .../doctrees/dataprofiler.version.doctree | Bin 0 -> 3171 bytes docs/0.10.3/doctrees/environment.pickle | Bin 0 -> 644754 bytes docs/0.10.3/doctrees/examples.doctree | Bin 0 -> 4722 bytes docs/0.10.3/doctrees/graph_data_demo.doctree | Bin 0 -> 26343 bytes docs/0.10.3/doctrees/graphs.doctree | Bin 0 -> 25599 bytes docs/0.10.3/doctrees/index.doctree | Bin 0 -> 63422 bytes docs/0.10.3/doctrees/install.doctree | Bin 0 -> 11886 bytes docs/0.10.3/doctrees/labeler.doctree | Bin 0 -> 46412 bytes .../doctrees/merge_profile_list.doctree | Bin 0 -> 11827 bytes docs/0.10.3/doctrees/modules.doctree | Bin 0 -> 2683 bytes .../add_new_model_to_data_labeler.ipynb | 488 + .../column_name_labeler_example.ipynb | 364 + .../doctrees/nbsphinx/data_reader.ipynb | 689 + .../doctrees/nbsphinx/graph_data_demo.ipynb | 271 + docs/0.10.3/doctrees/nbsphinx/labeler.ipynb | 650 + .../nbsphinx/merge_profile_list.ipynb | 159 + docs/0.10.3/doctrees/nbsphinx/overview.ipynb | 470 + .../nbsphinx/popmon_dp_loader_example.ipynb | 416 + .../doctrees/nbsphinx/profiler_example.ipynb | 577 + .../nbsphinx/regex_labeler_from_scratch.ipynb | 444 + .../unstructured_profiler_example.ipynb | 436 + docs/0.10.3/doctrees/overview.doctree | Bin 0 -> 39429 bytes .../doctrees/popmon_dp_loader_example.doctree | Bin 0 -> 27533 bytes docs/0.10.3/doctrees/profiler.doctree | Bin 0 -> 215496 bytes docs/0.10.3/doctrees/profiler_example.doctree | Bin 0 -> 47461 bytes .../regex_labeler_from_scratch.doctree | Bin 0 -> 42414 bytes .../unstructured_profiler_example.doctree | Bin 0 -> 36890 bytes docs/0.10.3/html/.buildinfo | 4 + docs/0.10.3/html/API.html | 293 + docs/0.10.3/html/_images/DL-Flowchart.png | Bin 0 -> 7609 bytes .../html/_images/histogram_example_0.png | Bin 0 -> 14056 bytes .../html/_images/histogram_example_1.png | Bin 0 -> 11387 bytes .../html/_images/histogram_example_2.png | Bin 0 -> 12592 bytes .../missing_value_barchart_example_0.png | Bin 0 -> 24758 bytes .../missing_value_matrix_example_0.png | Bin 0 -> 37730 bytes docs/0.10.3/html/_sources/API.rst.txt | 16 + .../add_new_model_to_data_labeler.nblink.txt | 3 + .../column_name_labeler_example.nblink.txt | 3 + .../html/_sources/data_labeling.rst.txt | 365 + .../html/_sources/data_reader.nblink.txt | 3 + .../0.10.3/html/_sources/data_readers.rst.txt | 164 + ...ataprofiler.data_readers.avro_data.rst.txt | 7 + ...ataprofiler.data_readers.base_data.rst.txt | 7 + ...dataprofiler.data_readers.csv_data.rst.txt | 7 + .../dataprofiler.data_readers.data.rst.txt | 7 + ...taprofiler.data_readers.data_utils.rst.txt | 7 + ...er.data_readers.filepath_or_buffer.rst.txt | 7 + ...taprofiler.data_readers.graph_data.rst.txt | 7 + ...ataprofiler.data_readers.json_data.rst.txt | 7 + ...profiler.data_readers.parquet_data.rst.txt | 7 + .../dataprofiler.data_readers.rst.txt | 30 + ...ler.data_readers.structured_mixins.rst.txt | 7 + ...ataprofiler.data_readers.text_data.rst.txt | 7 + .../_sources/dataprofiler.dp_logging.rst.txt | 7 + ...rofiler.labelers.base_data_labeler.rst.txt | 7 + .../dataprofiler.labelers.base_model.rst.txt | 7 + ...ofiler.labelers.char_load_tf_model.rst.txt | 7 + ...labelers.character_level_cnn_model.rst.txt | 7 + ...belers.classification_report_utils.rst.txt | 7 + ...rofiler.labelers.column_name_model.rst.txt | 7 + ...ataprofiler.labelers.data_labelers.rst.txt | 7 + ...aprofiler.labelers.data_processing.rst.txt | 7 + ...ataprofiler.labelers.labeler_utils.rst.txt | 7 + .../dataprofiler.labelers.regex_model.rst.txt | 7 + .../_sources/dataprofiler.labelers.rst.txt | 30 + .../dataprofiler.labelers.utils.rst.txt | 7 + ...er.profilers.base_column_profilers.rst.txt | 7 + ...ofilers.categorical_column_profile.rst.txt | 7 + ...profilers.column_profile_compilers.rst.txt | 7 + ...filers.data_labeler_column_profile.rst.txt | 7 + ....profilers.datetime_column_profile.rst.txt | 7 + ...ler.profilers.float_column_profile.rst.txt | 7 + ...aprofiler.profilers.graph_profiler.rst.txt | 7 + ...r.profilers.helpers.report_helpers.rst.txt | 7 + .../dataprofiler.profilers.helpers.rst.txt | 20 + ...profiler.profilers.histogram_utils.rst.txt | 7 + ...filer.profilers.int_column_profile.rst.txt | 7 + ...ataprofiler.profilers.json_decoder.rst.txt | 7 + ...ataprofiler.profilers.json_encoder.rst.txt | 7 + ...r.profilers.numerical_column_stats.rst.txt | 7 + ...ler.profilers.order_column_profile.rst.txt | 7 + ...profiler.profilers.profile_builder.rst.txt | 7 + ...rofiler.profilers.profiler_options.rst.txt | 7 + ...aprofiler.profilers.profiler_utils.rst.txt | 7 + .../_sources/dataprofiler.profilers.rst.txt | 39 + ...iler.profilers.text_column_profile.rst.txt | 7 + ...ilers.unstructured_labeler_profile.rst.txt | 7 + ...rofilers.unstructured_text_profile.rst.txt | 7 + .../dataprofiler.profilers.utils.rst.txt | 7 + .../dataprofiler.reports.graphs.rst.txt | 7 + .../_sources/dataprofiler.reports.rst.txt | 21 + .../dataprofiler.reports.utils.rst.txt | 7 + .../_sources/dataprofiler.rng_utils.rst.txt | 7 + .../0.10.3/html/_sources/dataprofiler.rst.txt | 28 + .../_sources/dataprofiler.settings.rst.txt | 7 + ...rofiler.validators.base_validators.rst.txt | 7 + .../_sources/dataprofiler.validators.rst.txt | 20 + .../_sources/dataprofiler.version.rst.txt | 7 + docs/0.10.3/html/_sources/examples.rst.txt | 24 + .../html/_sources/graph_data_demo.nblink.txt | 3 + docs/0.10.3/html/_sources/graphs.rst.txt | 196 + docs/0.10.3/html/_sources/index.rst.txt | 580 + docs/0.10.3/html/_sources/install.rst.txt | 138 + docs/0.10.3/html/_sources/labeler.nblink.txt | 6 + .../_sources/merge_profile_list.nblink.txt | 3 + docs/0.10.3/html/_sources/modules.rst.txt | 7 + docs/0.10.3/html/_sources/overview.nblink.txt | 3 + .../popmon_dp_loader_example.nblink.txt | 3 + docs/0.10.3/html/_sources/profiler.rst.txt | 962 ++ .../html/_sources/profiler_example.nblink.txt | 3 + .../regex_labeler_from_scratch.nblink.txt | 3 + .../unstructured_profiler_example.nblink.txt | 3 + .../_static/DataProfilerLogoLightTheme.png | Bin 0 -> 118089 bytes docs/0.10.3/html/_static/basic.css | 904 ++ docs/0.10.3/html/_static/custom.css | 50 + docs/0.10.3/html/_static/doctools.js | 323 + .../html/_static/documentation_options.js | 12 + docs/0.10.3/html/_static/file.png | Bin 0 -> 286 bytes .../images/DataProfilerDarkLogoLong.png | Bin 0 -> 20019 bytes .../images/DataProfilerLogoLightTheme.png | Bin 0 -> 118089 bytes .../images/DataProfilerLogoLightThemeLong.png | Bin 0 -> 177437 bytes .../images/branching_workflow_diagram.png | Bin 0 -> 131890 bytes .../_static/images/histogram_example_0.png | Bin 0 -> 14056 bytes .../_static/images/histogram_example_1.png | Bin 0 -> 11387 bytes .../_static/images/histogram_example_2.png | Bin 0 -> 12592 bytes .../missing_value_barchart_example_0.png | Bin 0 -> 24758 bytes .../images/missing_value_matrix_example_0.png | Bin 0 -> 37730 bytes docs/0.10.3/html/_static/jquery-3.5.1.js | 10872 ++++++++++++++++ docs/0.10.3/html/_static/jquery.js | 2 + docs/0.10.3/html/_static/language_data.js | 297 + docs/0.10.3/html/_static/minus.png | Bin 0 -> 90 bytes docs/0.10.3/html/_static/plus.png | Bin 0 -> 90 bytes docs/0.10.3/html/_static/pygments.css | 75 + docs/0.10.3/html/_static/pygments_dark.css | 85 + docs/0.10.3/html/_static/scripts/main.js | 2 + docs/0.10.3/html/_static/scripts/main.js.map | 1 + docs/0.10.3/html/_static/searchtools.js | 522 + .../html/_static/styles/furo-extensions.css | 2 + .../_static/styles/furo-extensions.css.map | 1 + docs/0.10.3/html/_static/styles/furo.css | 2 + docs/0.10.3/html/_static/styles/furo.css.map | 1 + docs/0.10.3/html/_static/underscore-1.13.1.js | 2042 +++ docs/0.10.3/html/_static/underscore.js | 6 + .../html/add_new_model_to_data_labeler.html | 935 ++ .../html/add_new_model_to_data_labeler.ipynb | 488 + .../html/column_name_labeler_example.html | 820 ++ .../html/column_name_labeler_example.ipynb | 364 + docs/0.10.3/html/data_labeling.html | 615 + docs/0.10.3/html/data_reader.html | 1101 ++ docs/0.10.3/html/data_reader.ipynb | 689 + docs/0.10.3/html/data_readers.html | 452 + .../dataprofiler.data_readers.avro_data.html | 409 + .../dataprofiler.data_readers.base_data.html | 371 + .../dataprofiler.data_readers.csv_data.html | 438 + .../html/dataprofiler.data_readers.data.html | 310 + .../dataprofiler.data_readers.data_utils.html | 656 + ...filer.data_readers.filepath_or_buffer.html | 321 + .../dataprofiler.data_readers.graph_data.html | 415 + .../html/dataprofiler.data_readers.html | 324 + .../dataprofiler.data_readers.json_data.html | 420 + ...ataprofiler.data_readers.parquet_data.html | 405 + ...ofiler.data_readers.structured_mixins.html | 304 + .../dataprofiler.data_readers.text_data.html | 410 + docs/0.10.3/html/dataprofiler.dp_logging.html | 298 + docs/0.10.3/html/dataprofiler.html | 383 + ...taprofiler.labelers.base_data_labeler.html | 909 ++ .../dataprofiler.labelers.base_model.html | 675 + ...aprofiler.labelers.char_load_tf_model.html | 491 + ...er.labelers.character_level_cnn_model.html | 512 + ....labelers.classification_report_utils.html | 451 + ...taprofiler.labelers.column_name_model.html | 451 + .../dataprofiler.labelers.data_labelers.html | 980 ++ ...dataprofiler.labelers.data_processing.html | 1412 ++ docs/0.10.3/html/dataprofiler.labelers.html | 360 + .../dataprofiler.labelers.labeler_utils.html | 2641 ++++ .../dataprofiler.labelers.regex_model.html | 486 + .../html/dataprofiler.labelers.utils.html | 308 + ...filer.profilers.base_column_profilers.html | 457 + ....profilers.categorical_column_profile.html | 449 + ...er.profilers.column_profile_compilers.html | 677 + ...profilers.data_labeler_column_profile.html | 446 + ...ler.profilers.datetime_column_profile.html | 405 + ...ofiler.profilers.float_column_profile.html | 546 + ...dataprofiler.profilers.graph_profiler.html | 382 + .../html/dataprofiler.profilers.helpers.html | 333 + ...iler.profilers.helpers.report_helpers.html | 324 + ...ataprofiler.profilers.histogram_utils.html | 287 + docs/0.10.3/html/dataprofiler.profilers.html | 341 + ...profiler.profilers.int_column_profile.html | 539 + .../dataprofiler.profilers.json_decoder.html | 546 + .../dataprofiler.profilers.json_encoder.html | 363 + ...iler.profilers.numerical_column_stats.html | 535 + ...ofiler.profilers.order_column_profile.html | 401 + ...ataprofiler.profilers.profile_builder.html | 891 ++ ...taprofiler.profilers.profiler_options.html | 2395 ++++ ...dataprofiler.profilers.profiler_utils.html | 824 ++ ...rofiler.profilers.text_column_profile.html | 587 + ...rofilers.unstructured_labeler_profile.html | 347 + ...r.profilers.unstructured_text_profile.html | 355 + .../html/dataprofiler.profilers.utils.html | 264 + .../html/dataprofiler.reports.graphs.html | 265 + docs/0.10.3/html/dataprofiler.reports.html | 297 + .../html/dataprofiler.reports.utils.html | 290 + docs/0.10.3/html/dataprofiler.rng_utils.html | 270 + docs/0.10.3/html/dataprofiler.settings.html | 265 + ...taprofiler.validators.base_validators.html | 353 + docs/0.10.3/html/dataprofiler.validators.html | 314 + docs/0.10.3/html/dataprofiler.version.html | 265 + docs/0.10.3/html/examples.html | 426 + docs/0.10.3/html/genindex.html | 3430 +++++ docs/0.10.3/html/graph_data_demo.html | 708 + docs/0.10.3/html/graph_data_demo.ipynb | 271 + docs/0.10.3/html/graphs.html | 487 + docs/0.10.3/html/index.html | 743 ++ docs/0.10.3/html/install.html | 387 + docs/0.10.3/html/labeler.html | 956 ++ docs/0.10.3/html/labeler.ipynb | 650 + docs/0.10.3/html/merge_profile_list.html | 637 + docs/0.10.3/html/merge_profile_list.ipynb | 159 + docs/0.10.3/html/modules.html | 298 + docs/0.10.3/html/objects.inv | Bin 0 -> 28981 bytes docs/0.10.3/html/overview.html | 848 ++ docs/0.10.3/html/overview.ipynb | 470 + .../0.10.3/html/popmon_dp_loader_example.html | 803 ++ .../html/popmon_dp_loader_example.ipynb | 416 + docs/0.10.3/html/profiler.html | 1409 ++ docs/0.10.3/html/profiler_example.html | 948 ++ docs/0.10.3/html/profiler_example.ipynb | 577 + docs/0.10.3/html/py-modindex.html | 604 + .../html/regex_labeler_from_scratch.html | 857 ++ .../html/regex_labeler_from_scratch.ipynb | 444 + docs/0.10.3/html/search.html | 266 + docs/0.10.3/html/searchindex.js | 1 + .../html/unstructured_profiler_example.html | 835 ++ .../html/unstructured_profiler_example.ipynb | 436 + .../dataprofiler.profilers.profiler_utils.rst | 7 + docs/source/dataprofiler.profilers.rst | 2 +- docs/source/dataprofiler.rng_utils.rst | 7 + docs/source/dataprofiler.rst | 1 + docs/source/index.rst | 3 + docs/source/profiler.rst | 9 +- docs/update_documentation.py | 10 + index.html | 2 +- profiler_options.html | 1 + 306 files changed, 77208 insertions(+), 3 deletions(-) create mode 100644 docs/0.10.3/doctrees/API.doctree create mode 100644 docs/0.10.3/doctrees/add_new_model_to_data_labeler.doctree create mode 100644 docs/0.10.3/doctrees/column_name_labeler_example.doctree create mode 100644 docs/0.10.3/doctrees/data_labeling.doctree create mode 100644 docs/0.10.3/doctrees/data_reader.doctree create mode 100644 docs/0.10.3/doctrees/data_readers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.avro_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.base_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.csv_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.data_utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.filepath_or_buffer.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.graph_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.json_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.parquet_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.structured_mixins.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.data_readers.text_data.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.dp_logging.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.base_data_labeler.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.base_model.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.char_load_tf_model.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.character_level_cnn_model.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.classification_report_utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.column_name_model.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.data_labelers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.data_processing.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.labeler_utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.regex_model.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.labelers.utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.base_column_profilers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.categorical_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.column_profile_compilers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.data_labeler_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.datetime_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.float_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.graph_profiler.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.helpers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.helpers.report_helpers.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.histogram_utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.int_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.json_decoder.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.json_encoder.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.numerical_column_stats.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.order_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.profile_builder.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.profiler_options.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.profiler_utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.text_column_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.unstructured_labeler_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.unstructured_text_profile.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.profilers.utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.reports.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.reports.graphs.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.reports.utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.rng_utils.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.settings.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.validators.base_validators.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.validators.doctree create mode 100644 docs/0.10.3/doctrees/dataprofiler.version.doctree create mode 100644 docs/0.10.3/doctrees/environment.pickle create mode 100644 docs/0.10.3/doctrees/examples.doctree create mode 100644 docs/0.10.3/doctrees/graph_data_demo.doctree create mode 100644 docs/0.10.3/doctrees/graphs.doctree create mode 100644 docs/0.10.3/doctrees/index.doctree create mode 100644 docs/0.10.3/doctrees/install.doctree create mode 100644 docs/0.10.3/doctrees/labeler.doctree create mode 100644 docs/0.10.3/doctrees/merge_profile_list.doctree create mode 100644 docs/0.10.3/doctrees/modules.doctree create mode 100644 docs/0.10.3/doctrees/nbsphinx/add_new_model_to_data_labeler.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/column_name_labeler_example.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/data_reader.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/graph_data_demo.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/labeler.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/merge_profile_list.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/overview.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/popmon_dp_loader_example.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/profiler_example.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/regex_labeler_from_scratch.ipynb create mode 100644 docs/0.10.3/doctrees/nbsphinx/unstructured_profiler_example.ipynb create mode 100644 docs/0.10.3/doctrees/overview.doctree create mode 100644 docs/0.10.3/doctrees/popmon_dp_loader_example.doctree create mode 100644 docs/0.10.3/doctrees/profiler.doctree create mode 100644 docs/0.10.3/doctrees/profiler_example.doctree create mode 100644 docs/0.10.3/doctrees/regex_labeler_from_scratch.doctree create mode 100644 docs/0.10.3/doctrees/unstructured_profiler_example.doctree create mode 100644 docs/0.10.3/html/.buildinfo create mode 100644 docs/0.10.3/html/API.html create mode 100644 docs/0.10.3/html/_images/DL-Flowchart.png create mode 100644 docs/0.10.3/html/_images/histogram_example_0.png create mode 100644 docs/0.10.3/html/_images/histogram_example_1.png create mode 100644 docs/0.10.3/html/_images/histogram_example_2.png create mode 100644 docs/0.10.3/html/_images/missing_value_barchart_example_0.png create mode 100644 docs/0.10.3/html/_images/missing_value_matrix_example_0.png create mode 100644 docs/0.10.3/html/_sources/API.rst.txt create mode 100644 docs/0.10.3/html/_sources/add_new_model_to_data_labeler.nblink.txt create mode 100644 docs/0.10.3/html/_sources/column_name_labeler_example.nblink.txt create mode 100644 docs/0.10.3/html/_sources/data_labeling.rst.txt create mode 100644 docs/0.10.3/html/_sources/data_reader.nblink.txt create mode 100644 docs/0.10.3/html/_sources/data_readers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.avro_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.base_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.csv_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.data_utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.filepath_or_buffer.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.graph_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.json_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.parquet_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.structured_mixins.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.data_readers.text_data.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.dp_logging.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.base_data_labeler.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.base_model.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.char_load_tf_model.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.character_level_cnn_model.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.classification_report_utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.column_name_model.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.data_labelers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.data_processing.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.labeler_utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.regex_model.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.labelers.utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.base_column_profilers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.categorical_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.column_profile_compilers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.data_labeler_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.datetime_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.float_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.graph_profiler.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.report_helpers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.histogram_utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.int_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.json_decoder.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.json_encoder.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.numerical_column_stats.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.order_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.profile_builder.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_options.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.text_column_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_labeler_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_text_profile.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.profilers.utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.reports.graphs.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.reports.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.reports.utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.rng_utils.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.settings.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.validators.base_validators.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.validators.rst.txt create mode 100644 docs/0.10.3/html/_sources/dataprofiler.version.rst.txt create mode 100644 docs/0.10.3/html/_sources/examples.rst.txt create mode 100644 docs/0.10.3/html/_sources/graph_data_demo.nblink.txt create mode 100644 docs/0.10.3/html/_sources/graphs.rst.txt create mode 100644 docs/0.10.3/html/_sources/index.rst.txt create mode 100644 docs/0.10.3/html/_sources/install.rst.txt create mode 100644 docs/0.10.3/html/_sources/labeler.nblink.txt create mode 100644 docs/0.10.3/html/_sources/merge_profile_list.nblink.txt create mode 100644 docs/0.10.3/html/_sources/modules.rst.txt create mode 100644 docs/0.10.3/html/_sources/overview.nblink.txt create mode 100644 docs/0.10.3/html/_sources/popmon_dp_loader_example.nblink.txt create mode 100644 docs/0.10.3/html/_sources/profiler.rst.txt create mode 100644 docs/0.10.3/html/_sources/profiler_example.nblink.txt create mode 100644 docs/0.10.3/html/_sources/regex_labeler_from_scratch.nblink.txt create mode 100644 docs/0.10.3/html/_sources/unstructured_profiler_example.nblink.txt create mode 100644 docs/0.10.3/html/_static/DataProfilerLogoLightTheme.png create mode 100644 docs/0.10.3/html/_static/basic.css create mode 100644 docs/0.10.3/html/_static/custom.css create mode 100644 docs/0.10.3/html/_static/doctools.js create mode 100644 docs/0.10.3/html/_static/documentation_options.js create mode 100644 docs/0.10.3/html/_static/file.png create mode 100644 docs/0.10.3/html/_static/images/DataProfilerDarkLogoLong.png create mode 100644 docs/0.10.3/html/_static/images/DataProfilerLogoLightTheme.png create mode 100644 docs/0.10.3/html/_static/images/DataProfilerLogoLightThemeLong.png create mode 100644 docs/0.10.3/html/_static/images/branching_workflow_diagram.png create mode 100644 docs/0.10.3/html/_static/images/histogram_example_0.png create mode 100644 docs/0.10.3/html/_static/images/histogram_example_1.png create mode 100644 docs/0.10.3/html/_static/images/histogram_example_2.png create mode 100644 docs/0.10.3/html/_static/images/missing_value_barchart_example_0.png create mode 100644 docs/0.10.3/html/_static/images/missing_value_matrix_example_0.png create mode 100644 docs/0.10.3/html/_static/jquery-3.5.1.js create mode 100644 docs/0.10.3/html/_static/jquery.js create mode 100644 docs/0.10.3/html/_static/language_data.js create mode 100644 docs/0.10.3/html/_static/minus.png create mode 100644 docs/0.10.3/html/_static/plus.png create mode 100644 docs/0.10.3/html/_static/pygments.css create mode 100644 docs/0.10.3/html/_static/pygments_dark.css create mode 100644 docs/0.10.3/html/_static/scripts/main.js create mode 100644 docs/0.10.3/html/_static/scripts/main.js.map create mode 100644 docs/0.10.3/html/_static/searchtools.js create mode 100644 docs/0.10.3/html/_static/styles/furo-extensions.css create mode 100644 docs/0.10.3/html/_static/styles/furo-extensions.css.map create mode 100644 docs/0.10.3/html/_static/styles/furo.css create mode 100644 docs/0.10.3/html/_static/styles/furo.css.map create mode 100644 docs/0.10.3/html/_static/underscore-1.13.1.js create mode 100644 docs/0.10.3/html/_static/underscore.js create mode 100644 docs/0.10.3/html/add_new_model_to_data_labeler.html create mode 100644 docs/0.10.3/html/add_new_model_to_data_labeler.ipynb create mode 100644 docs/0.10.3/html/column_name_labeler_example.html create mode 100644 docs/0.10.3/html/column_name_labeler_example.ipynb create mode 100644 docs/0.10.3/html/data_labeling.html create mode 100644 docs/0.10.3/html/data_reader.html create mode 100644 docs/0.10.3/html/data_reader.ipynb create mode 100644 docs/0.10.3/html/data_readers.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.avro_data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.base_data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.csv_data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.data_utils.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.filepath_or_buffer.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.graph_data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.json_data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.parquet_data.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.structured_mixins.html create mode 100644 docs/0.10.3/html/dataprofiler.data_readers.text_data.html create mode 100644 docs/0.10.3/html/dataprofiler.dp_logging.html create mode 100644 docs/0.10.3/html/dataprofiler.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.base_data_labeler.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.base_model.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.char_load_tf_model.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.character_level_cnn_model.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.classification_report_utils.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.column_name_model.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.data_labelers.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.data_processing.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.labeler_utils.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.regex_model.html create mode 100644 docs/0.10.3/html/dataprofiler.labelers.utils.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.base_column_profilers.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.categorical_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.column_profile_compilers.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.data_labeler_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.datetime_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.float_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.graph_profiler.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.helpers.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.helpers.report_helpers.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.histogram_utils.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.int_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.json_decoder.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.json_encoder.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.numerical_column_stats.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.order_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.profile_builder.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.profiler_options.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.profiler_utils.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.text_column_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.unstructured_labeler_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.unstructured_text_profile.html create mode 100644 docs/0.10.3/html/dataprofiler.profilers.utils.html create mode 100644 docs/0.10.3/html/dataprofiler.reports.graphs.html create mode 100644 docs/0.10.3/html/dataprofiler.reports.html create mode 100644 docs/0.10.3/html/dataprofiler.reports.utils.html create mode 100644 docs/0.10.3/html/dataprofiler.rng_utils.html create mode 100644 docs/0.10.3/html/dataprofiler.settings.html create mode 100644 docs/0.10.3/html/dataprofiler.validators.base_validators.html create mode 100644 docs/0.10.3/html/dataprofiler.validators.html create mode 100644 docs/0.10.3/html/dataprofiler.version.html create mode 100644 docs/0.10.3/html/examples.html create mode 100644 docs/0.10.3/html/genindex.html create mode 100644 docs/0.10.3/html/graph_data_demo.html create mode 100644 docs/0.10.3/html/graph_data_demo.ipynb create mode 100644 docs/0.10.3/html/graphs.html create mode 100644 docs/0.10.3/html/index.html create mode 100644 docs/0.10.3/html/install.html create mode 100644 docs/0.10.3/html/labeler.html create mode 100644 docs/0.10.3/html/labeler.ipynb create mode 100644 docs/0.10.3/html/merge_profile_list.html create mode 100644 docs/0.10.3/html/merge_profile_list.ipynb create mode 100644 docs/0.10.3/html/modules.html create mode 100644 docs/0.10.3/html/objects.inv create mode 100644 docs/0.10.3/html/overview.html create mode 100644 docs/0.10.3/html/overview.ipynb create mode 100644 docs/0.10.3/html/popmon_dp_loader_example.html create mode 100644 docs/0.10.3/html/popmon_dp_loader_example.ipynb create mode 100644 docs/0.10.3/html/profiler.html create mode 100644 docs/0.10.3/html/profiler_example.html create mode 100644 docs/0.10.3/html/profiler_example.ipynb create mode 100644 docs/0.10.3/html/py-modindex.html create mode 100644 docs/0.10.3/html/regex_labeler_from_scratch.html create mode 100644 docs/0.10.3/html/regex_labeler_from_scratch.ipynb create mode 100644 docs/0.10.3/html/search.html create mode 100644 docs/0.10.3/html/searchindex.js create mode 100644 docs/0.10.3/html/unstructured_profiler_example.html create mode 100644 docs/0.10.3/html/unstructured_profiler_example.ipynb create mode 100644 docs/source/dataprofiler.profilers.profiler_utils.rst create mode 100644 docs/source/dataprofiler.rng_utils.rst create mode 100644 profiler_options.html diff --git a/docs/0.10.3/doctrees/API.doctree b/docs/0.10.3/doctrees/API.doctree new file mode 100644 index 0000000000000000000000000000000000000000..d39852d7698a422e98ee5f0233956586559611eb GIT binary patch literal 3801 zcmcIn-EJJW6_zaRucVc%#7>i1&D3rTJFRvdAQy$xpeP&^P1SCU{M{7llsm&+Qkoe~ zNshDv62!eoVFSDid)Gceo**yLcWBK4@n$nBBsikZY-iArJ1&0*!zF8pW1t-C&{G}g^Z{*8_$63pChr=NJ&Et0;TGlzWrcbn%d{SuGbN6rYSm7?yi4vj|g!pb{ zBrU(Xagi?;6B3lTFjk30|r#+cLedaSf|> z?a`yrM~X@{I#(GblTq|Wm`ia+Bdtd7eGp2T3pIL&X!2N!DNm>z;TAP2Pmkc#P%3SU z3G11T!YMAY207MZZRhblY_>Gl30>MUTR7|i!S42lbnYN4g`ZmwJdPi;fc>2Plx?xw zWA^H}m=JaV$k^ejWiR6YCjNhf|5r|J!G6N-L;Y^4&hD^RPqzKLdcc6pB+1#b`9FQg zXn-dKTm>pmxDI%xMet^j5}pN-NOO?^IrT88Jy*X7{y-)a7~so661-1I>{ld<`yZ2p z$3zRMhNW8%%nxc~fzq$x_S@ebrMK8^k50Qr%cIowE*Dw61X3A3wt?Idk(P8he%0Rp z3kM6zSegz%l-%d?y|H;22oWThPo<$-AjLe0_V0FVZmw+CddlzJSlLUeNcgRnR<@RG>Vrsf6na4EO%#}(fBDqgr(|aT`?PG7v_AC(-`^>Z% zk7LyQGqYFS*9f{KK;yph9RPt4*=KB5nU}s*1q=m+BPcAtt$tBmy$v6+I}VmjGl&Z5 zm@BM!YHW6EiRZSl=_;x<&t@R)>kSD{r4Jogv5k5x5b&DD+5NHU&1goYt5M`y4@pCn zCTWhvPH85@-RD^Lt7Rb*to9Iw&@r#ug}Igs>6JByQz3LFG+o*RRC|sGkrUy3DrD-w z8z_`O9-_irXHmHF$E5^h;w9lF*DS309~P?vRYQRDj)TPB(f=d1ROj@-vdX? zEo++rDYOU|B6H34*}b?(^RUS}py~x^8&qZ_aTo4;382lCi~T~BD_X=NoTo0I4p1mU z(Qx^sPZ8AD1y{Vx&;2mwicAvcNcGB2T@CDx*@ZI-`A{)>#n4bHrWhWnDCTq`}>Xm{I_KWIn5U(@7&pSk_o}{8Mlu)HFq)Gy>Cw{P?v8ZvxqYoJMPAoMd6< zR&7QLfl-T7J@saoP7|2uX)-|x#g53k<_HOyhD~iYj1{WfWymvgpsq4a<{{%Vmf#=B zyPXJ^_q!@3sItEnC~5_uUhwO3873kkWeYJ!5yMOoA@F6f0c8&%PM;S!Ot`VocY=xp z&^939*%UcYv%;a{39#a--T_53iBYImu*E1Q$!F$9ln8PjQj8`^h*?!qKPNslTQs|{ zAbry<`2huq^x|2}k?=Y!M^Qg4UWXy1i^i;qR6sX$v!^*+k(Og7#JFwREZVLtFrhjY zKecR^DARG9mFzQiq)g8V^i>YfTsL^C*r6NKjxddV!tNGkZ#f#?@?OM2R_-mhzLdD4 ztM$q^FH1^2G%iFhort6fuvdL?P1tDnR&MOoR{f#FmHR=SQaiT3v3^&zgXRuOh(zHE z-kP0ABneQ459kSJ~A7#Cu#+=yaFXTtC)5N>Pn#wYU!dyRr50Y zRr$*UKOOGAQ(!iYP%r^U;c&b^D5DxU$R7r`G5p_d2F}-?r~dVmf8xN`PyRKui}?|Q z;MxA>#>V#GB@_4bq5VQ#OsJ0KgT~e zr@RH^UVo0>H$XUh4JW<@g3THNplWs+mwip|R6{37Xy$$&_G8!3D(-i2D<;GL0nJ9V AegFUf literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/add_new_model_to_data_labeler.doctree b/docs/0.10.3/doctrees/add_new_model_to_data_labeler.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f2de0cd26e5745f4c1f7f977b51b2f35109ec31b GIT binary patch literal 40612 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 YfV7w#Z=G^Y*J*Hz#sTtYwyWj;14g+S2><{9 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/data_labeling.doctree b/docs/0.10.3/doctrees/data_labeling.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bd24dd10adc988a5048eeb9185e4190fff64be5b GIT binary patch literal 51637 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

?p2f+5W|3TpG-pJTj5;%U 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%0DoKVnG5r6N|PLuk>hN)y%qy*BiEsFmJ@szg5| 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.data.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.data.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f605b792f32784cc48964d8632d8947c60d9d097 GIT binary patch literal 17090 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.data_utils.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.data_utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..59b559361ebf99553a2d90cc05a30b21f19eb9a7 GIT binary patch literal 166492 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 QXUiHm(+H!?C1Ldc2M=zIy8r+H literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f15edeef32528fe431764dc67101f6fdb83a3c8a GIT binary patch literal 4751 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≥kM09Kpdj(9VfYV({k+)_dpu1>xCuf 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.graph_data.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.graph_data.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dfe388c7dd945111ffc5ce718891e8c8cf70bd23 GIT binary patch literal 54908 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 Hb@BfJxIG6W literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.json_data.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.json_data.doctree new file mode 100644 index 0000000000000000000000000000000000000000..490d5dc7333522cde4cc28b8575ef7ff89d2ade9 GIT binary patch literal 56476 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.parquet_data.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.parquet_data.doctree new file mode 100644 index 0000000000000000000000000000000000000000..248920fa17d2f2d6f1e8e2cf44e011f4364e9195 GIT binary patch literal 52869 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�`SX)QH~#E5dpgZc({A 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.data_readers.text_data.doctree b/docs/0.10.3/doctrees/dataprofiler.data_readers.text_data.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c7758ced8a782fa77cae8a91ef45f6fe41c6a363 GIT binary patch literal 51851 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.dp_logging.doctree b/docs/0.10.3/doctrees/dataprofiler.dp_logging.doctree new file mode 100644 index 0000000000000000000000000000000000000000..fb9c1e84bc1f7340ff9a8289d956c12c549e388b GIT binary patch literal 11370 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 Rp`A171WS!Qu^4w+{{w%G4G#bS literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.labelers.base_data_labeler.doctree b/docs/0.10.3/doctrees/dataprofiler.labelers.base_data_labeler.doctree new file mode 100644 index 0000000000000000000000000000000000000000..991322e16aaf4e14b5ed1f9a355a2253bb319fda GIT binary patch literal 220582 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 NzYrp$0=>%0e*vnPiShsd literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.labelers.base_model.doctree b/docs/0.10.3/doctrees/dataprofiler.labelers.base_model.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bfee3ade1f5f526bda9c57463fa78e5e19037d4a GIT binary patch literal 156461 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.labelers.character_level_cnn_model.doctree b/docs/0.10.3/doctrees/dataprofiler.labelers.character_level_cnn_model.doctree new file mode 100644 index 0000000000000000000000000000000000000000..92475302d761e22f2b7bb52636ad9b1d5c2d8152 GIT binary patch literal 101599 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

9|$TT<)FJO?wHj7Ap^sa`>}c{MnBly&39lr`}( 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 F`d`nN;IaS! literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.labelers.data_processing.doctree b/docs/0.10.3/doctrees/dataprofiler.labelers.data_processing.doctree new file mode 100644 index 0000000000000000000000000000000000000000..511f8508690044557a961581dbdecc285ddb71cd GIT binary patch literal 565765 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

    P)1kdyu`S<_}=hhHN`cC6`7D9`b=7p;Q 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.labelers.regex_model.doctree b/docs/0.10.3/doctrees/dataprofiler.labelers.regex_model.doctree new file mode 100644 index 0000000000000000000000000000000000000000..04c246362a71d9c50540cc14f60c8f80c315062f GIT binary patch literal 73328 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%0AG1KzRpQ12HFO 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 DOhxHU literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.labelers.utils.doctree b/docs/0.10.3/doctrees/dataprofiler.labelers.utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..8cadfa4632baa5db37b9e181e85b57b475b86629 GIT binary patch literal 12980 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.base_column_profilers.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.base_column_profilers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0549556ea9a0b983862234bb10a1571c3889b3cf GIT binary patch literal 76419 zcmdsg3zQsJb)ZJl{PY>gk}L2KL_f ztM^{LdR^5$Lo(xYJnE`?pZo5;?|$Fs{?UgoST(W=|BE+;?V#Q~KI>Jh%~sV9d+|iI zRp~DH&8T;>xASLv_w{Dt$&Pm{Y;`*ozZb895|yCdsCN8j?_e*U!s1cA5zg}ZaC`%9*hQK!T7=6OfVUbM)j!SE1%-iuku2_bakuIU1*kW?X+t3hTjQ$SOLnf-R~bq zK(dPcT#rHsU2KiV+8)3Z^@7vl$+8?ouqGbkueT1E5sVqf zxTanWaXjOdh8KqL5`K?1y#@AbqS|dI5A$B-NXM^XnQlBDd57^+FW3}J2OEMjgEhg9 zxUuKX5XQ0RNZ9nf`8}13%k55!0A|8Hx7<=Nd2a#EAC*z~LSS=$!#J+`CwH%T5neU;|hKm>Vvakh`~94(sSYe^Wpys z;s2dDT)p;hfR{L4y3;ONCa!>a8rR4W+U7xlbua8a;Z!QQE& z*sJ+o)b04?`Ht7D1R4VONL1~yBd~p94v`ONXdW)LYQ;tkm>&VmPsWqLecs`Y*A5iy z#}{1PYDQkY8I~AxmKga;0;Uq>wpqsR+jAFB*#2t3+Lesw_627lXJ^tHk^CB9&E3_)-q*Aaju8l``@5>279FGR>8Mxl8w!_O+V+u2QRw(m9+f zVd-1w1OHaKoEF(hxp4-d*hKsCn$1?^86rI%W0(`1D;^Wh90STV@^NN7d3>QU7q&fA zFca;L52Ev^-$RBa&`OQV)K4!LsbHlyPENq-28L5mx2Q9OiVa5NLUL0|jDodv^1MBp zJTvin;IZ963kqkv5y7S;r_a8sM1p&Qw<4|XOK26`ON9}Pcao0R9PE}fs|rrCebT{x zp9|~>1e?J;fn8^V`(7KkTPV0F%NP8}?=|=Y&^vy&7P;y5b5_@fRGPUCf!D{fStCx%}Ufw&Hj-& zK`!{E_xh--*LJ$s&+uNi$0H@9sSm471s@gSKVFx}Gl{1SZNFIsNnbt=mYITDZUAkM z*FYts{b$tnvlS=UzkaRSS^z!Xi&wW#fYk&qq7!Y9R-<%I^k|XD>m2r@9_tAVf)jJh zBI?Dvif9WIfhXozyZewXPXmUY1iDx-^rSk1;14B+M(&mLxz`x<_tYxJp#L<*6G)w` zz5%4Ki5?}I*P@ouyCkFFY&d#V?NJ5Q!CxzQUelT18%fOtkn+l&wjgoV| zQBHwNh`8Sbbo^Hs_bD;%_?*7_l(T5UzT>=#Ad!65CKB1{#+r2$-IaA4{ z?hdTXAUa6%BK@LLS(&h>rECq3lr;aWONts?^g1`V3boV;t8!8Byf#nOuKMy3xshSk zGI0E&4P3!~<~$@-qgI}&*awK*6Y{9L?;NNk+n@;zn>ptrAA&K}oXl)NIcM`#@o7?1 zwc38ii&`B;_QxZai#Z0r^x5^W69w@|E2XK(Nvty6X9fTbCgZVslSUd;ZB6B((AE|q z`QP0DfgMoux{auO)N6Eo9k_UF*lo94ov0ixc%A4i-4;eQ9t7P%PN^^(NLR>g$hZCl zKLmo1+vVKWQ|cV_FwOum6|f+Bpsm3o1Mv;PkDg{X#$$u&$Kd&3ES{)!8x3XwokS&B z4R#&_gF(z4Dx%6Qj==sy5P6}|uHaVL;|fT` zW7Mvy6t<5PBZ2$_bfVY^!X8@>P5Z~&je4aX^&X@Jj(MFX{8a2R@@1@?SX;qKO`=Wd zEI|Fyry+o{%>7WDB9ymahJabTs&pXXf_M$^dC$#z*DumMpsY%s0}_ZyNTyax4!vU7 zd6o={vi4?dn#N{rak3fm_s9y=xE}+?Mr$*Rtv5hRx!9V#h;6FO`ckN>Fe@`^Gg+0a zhT@b*$r^Io-U>fYG2r>ecC{f^-!tOkk^O6jMR82^610%(CMM*)f z#TsYbv)2iX_QM)8_vU}fE{BK*ViP}^hml^hC{ zD~F1VgS?py{s8{N>=pFZBqZ~#>WLJjiji_2f?ArngXSuBmUizh?ZX!^PmoY3F+&JI zF!KUJ#oPuc!(3}M4=WAxaFMV^DFXCioya|`80A;k_AB*Tz0!LiCA82WIL3w@!ar2$ ztS-$YQih@tKdCb_v2{2hSH+vfaQuaK;Dz;29ncuV2{V7T$Kp{R)ccH1bo0iT{^Y$3 z=$HbXT~rnDOo3PgIt>=-?k7134U>1nA1lr<>O&;LMt1hY*Y!1r4v; zN|$Qey21C8T^=*~NvBzLi*ug}ryepXb7iC_m$tPGSv z3J%2kA#GPi8kS~;G)qb{?F>nz8-{FbR)D2vlcac*<31!TEFt@R@gkl^A4JcJDa}$x zi;oz5*B!6y_=`YtaSDy(geJ5KJ@xHnW9b zEQ&&%l1V8ybiX7X=1JiqOf2fxk|34%_{lTvt)kNDjZXMFO#Xlz7ok+9q;dVx;1Y#n8Dcg~G8$ z_8^dUWF%-L7XgBn(5*cqZL`l(qmsL{oIune+|B2t)ge^V&F5SPju?yDf|ugMGRq1N zxkHErwnBt5+Mc7NWO8zVA?&W)#KkdSo?|7L_>=;#=R*ey+zH;fu=trvK11%dyelj3 zv`9Z!LfOIpW)VD#;QtY?hB z!?tRe561RMAJKm@y3!StDhm;Go)>tSf}UMe6`O_f0*^q$*_flow?tbiFOb4oMqa>D z?%X^qBoP?sl4rXRp$(KNZY4`z`FJa2$=NeyvYniP41fEMj90LE|U+Lg19 ze3nC}v*1Z+PG!$*MnG_R-tTd&lz-}Pqv==Jdja7esU(DHZ2u^MjP2inAkP(n9F)T} z`36OudxV@IIKo9H$a+SQ63d}6zd(B@$4m*cdUOE7{J0ol3R_!evxqmq^1rc?HDDD&hgs1L=8W$-ncO@Q87uJ`YVp{rx zM$;Ke$5@bA52cf7Fy82Qawh(IE#QFckiX7?UyC0$zpdMbFt@*`f%EHz4V*KWh6tU% zD{Z9A@_|-sW!T*X>r3WfOJuX^g^(xf__H!Nc@hS=Nd_yPQMjg8tO$OwtWw;yshW;!($3N8-R1M0RI> z6a104U^7P0{(^kG!-$)N+KW`1QDVrGvOCEx$s2vp4>$)M*yAhjf=YQK=O1u)V2}0i z4lDs2{Gu8!%BZIuvy$P#u)`rV<*cJ)>LW(a*+zw`2pz#jXW#jPZl@?A3`krw%T`80 z8ek~mqD8##x)D-OwAEb^89##isAj@a5xyC-MEQ`>qcwWVlOjr+1Pie~*LS(m(s zeN2-Vcvr&eG-QG@d6}WSqVW7L37*rDv;Kaw8YSx+INLO)D!A+n$ z-GQ^cQd^g1Zl$JX3GGX2Y0{7xK4H8}PJT zO?MkIU5|@xHb*XOne+!a8>k!oN~0S$g?LQtKTxof-kP)zJHXgC{dG$tldmWqj` zFqRP$vy|JM;t`3ZIQ6fB`B8eG}Y2WLvO3nxHMS9>x?tK8KV^Iix&C&*&q znh?rzK3ZJueEkcj8?dS}y)xsI&fe8Djh%E!zln$=4?&|#XsWyT8f{3l)mO+2r^fn8P9v+auIyww zM+Eg@-xB9Fv5ko(z@_D$qoia~@+5XYO`gcjDcp`H@5dT!E995t5VBOq-GM!l%sa3|lJSdbPAQS(wK%ib z*bNsI3=H;BANx&4TiN1Q^&=gzVb)2$0O0i$hent7Ag~)7p!xDHj0~Iub}o$U3xl>W za+FFp!H4`wNB%u-SO!=c$w1Uqq0LCcSozsD>?`3mVbEc$+&0toSh-?LS~$;QS^kQ1 z@G8)GIgfUdkMkbRH+B(vwhcc)GWkB}ktMWeZJ}o_%Y`|+tV7R2O)*pO2V5yztyy(B z=M*<*S#@cNcvSdB5ZzuQa+< zzltXm<6mJ@Iz$W*L&lNmxLhqAc-T*+)=ZFu z5jIe)Fr>(!wf<7hJt~wB0`*mCnJuk^iHzauyJW5Si_1BEpp%7X5t69&l=+ zMjH}0#bekBUda(`#t1U(MIJB0H=I9`n8P+(3%pdaw|gy?5*m>`=wp0`bBq~LgttMZ zyitUQ+#T4X2)qMJ6al}eT&_eBrf{|;vykJ$uo*C*Ks_!U4ZmSDn>~3{RqqNY&`$EX zb-$KEXZEhv-**FQMW>Ehh_G(9U=-cP#mx&M`Y<$!;!(=!_Oi?z_qUVK*cLM3NbR20j%k zrbSi%vKUFWnR9w1d25zYZ{b91SzXHg4<~8{h%;OJ%s1gb2C%rcf^npZu(J(U36{xz z&=5-)c0MOfhgrk;$H|AQDOQ%l!}hduQ=o4cdJmjj3rG3Nv*JqV(U(Zrg8R+DjD~x^ zyv_-TB|-!;^cyu9r!HJivNd@YS$dj0lbf@VPI%(L3Z&ClITEY^?ZrNO;5$VyE+X3h z4=e59&TCdgdoo@>50@+Wk^M|%JUMw1Pg^d-6$1;(A-oW}sYk&$j`%A35tn|!SA0nchT8pEdCL^>c8HIoJMc|6M zxQzu0N;B6a0d}e?_bHDW+JtF?VsVyEQ z%BZyX6hfVOezj_-XU}4B#?2?_(5)H-KdIfAUWG1O*CJlTL}U*-)L%B5%T^1D2Kh4z zUUt!eXW|pka5i?R24SetN4W-4D`JrJw?4+d9%PK11Wql|*RTE8L3;k@MZ<0?Btc%t zi(ufrloU#_UWOF1lzZji^HI_=9-VU6e?`5Oh7MY zWEUS<*2Me<*x=$qW&K(TdNLD!W^jF0!bN|Xa0MF#&IaBa^9D8ESYLpfvX1)u;rtF%G_isUvoCcEZ_txK^ditW2LjCnYw6VZ8;Mu@%9mdVeo>otf+qKAG$GGpGsgCwv->cVfWL1!9pZoO z1F`EGp@fSRh?5&2Hk&NYKul8H_5$i=pSASfG_JYXgAV@G1}FR5GlJ`&Qr@KYneGnk zNmky0CFO`;)aj}$!&wJ0HooSKB5KBTRly{%tUGzR(PFj$P;CIm3Y^rs6YHh#WR@Y( zGDiHOjWJg?`$nUdF%CPT-9Y5dW*>0(twgi4aF}u(W9ICti9#114c+eITcfA~oRB8C zo@9)Y$3UW`EGB7f^El~+d<8_rQY0S7=$%&N1!x`&7|bkkF+wwPPjSK2HzW6(C>WJ% zr3*=YRj9UV^@iVBglniR%BjGe)W2XbVP-^G{!E_n@ z%f^6ord00*?tkI+$v$i?FT76Q4E!Oes@x3R_Zn+L?*{&Ps6|s&luz09z(eB)*&VOB zUP-nWowUfiG?kZe=e2{k_YZmJwRO^2`25oVBIonh4Lpr(of(TD{{Z_@oP}(z?{^#a z?^C4e^;PfB!SkPostV8Nx((aL@r#Tp&i~}&h$FTSP;!pCN|WV`risZmiE^^%O?Id) zznc>R_%aEmUFp0YyWOcTc<7K)*OMNLP48+3XA_UmK(>*gwnb=3ic9iMgms$y6$e>3 z+1a#5OyW|H6(>ooR2$@4Y(CcqshZH`pBP>Ku_#^0cd-V$Q9BvY((lC_+vpNLs_*~? z5|PX`SV`JoAjjQ@|DA)rne(P>=Emr`!M+~dbZ*eqFr+TDa8Ue0>@%P_s*%!*OYoB_ zp%X(3qQPJZ=}9wj-!_igH5K0WC z5?Cn&WhAgHm_=1^`;Pqbs4{stn?Y@?rupC;S-pbeRTCx(!-bB2#sK*UclLY@$uybqy9^dvHg+yn2HASS|`OnTLKp_zeZAg;__sk}*@%X>NZSR+C~ zj;p{$17PG>XsVnemvt35yT9ZyfP-bpzJR~z#&P<~%#txlIPA6G9(WyPypCpwi@zUqeJyTMW^Vs8IxKXaSnLc0zV4qGU&{6bq!!4fL_ca`|5OLHZ0KlTA!Kzxu( z5?Fu?H&Ka&x2k~;8#-z=D&awnvj<&<&jN!CYSRC-th*wvX2o-AliYjjCrm@GhLha> zEsG2Q?;ts$!?-||hh>bnI=5UaDQ?wK_N42TPzg}0|TUn}IkkjQG9>CoGqEAV0K>pQv)uAA#rosCyx>FmtfM}5quxG{2N-a<*!>ZA2X=Pn9az{Mzhtocl&&~9 zM$+6nA<7vO^J7NS22GW95jnXq=_ofheI$k1?2UY%bHi)LEbkzV6}B%@XO1V_Jru_X z>tqOQWS`UWoEugbHjEkRja;d$14!`-f=2XkMTmz?^cgdJ-qjv>*}!K9FJE;i{9_}&593O31PP( z1Rc5yO}+~qto$4$r641BAfczpZMo@~HzbfAjfCv57(yUd&9a79l(6i5mdyvOz zcx&!KtEtwTp;oeN4A@TOqmRLdjC?eH((E5Y+Ufad+wLGf9@{55X=t?WA)_l@J*W~A zLFWe{{1OE{yQpe970Oe;9~yQdkLIZ*=2Cg;6yh@S)RuDR=3yj>yEs>IkVs}vi8wbM z116ECNz@0qNC%$H#u=q1qbyB|b9fKYqKmf8@lT;Sl|!?60m0?l93R6<`31l>)DmIj zMXIV0o{s%vLLd8gAjtnN0y*8C_6$XxdxV@IIKo9Hh_*|SPiyU+95bEIFBBP`Ak4pD zrTl~`Y=&*xoR?cv$wB@bfR*!*4}K(Rf7!7fKyg`QVir#HFDGUpVy_Uph62Biym|>EbTCSSL-5FLLTM`lLEU9@F;D80)>93^;x;ONr#TGsMZXAt$VBm0> zCAM!Ki#B*T{#ZZ5+rSczqR8RLG_tPt!6WiKev+*A(9g%_@!rlN7XhIyT3r`C7*)k+`u1r`_r31h1ry&CvX9k_`BFb7=Pc&M{^jntd-+ z${T=xkGlhVq=9AE(%k)$6N{q*cJPSZt!F=y>V*b0^MimvnB z9oW&yJFti@{E{KM20lIeGNVlc2MTR+PSt{P>r#eJ%V_b7Hd-Zrm3@Hr?M5wQJa&}3 zfdFc!r5;;9rK|g@yYC#h%(La#Df-w*j0xssWDDjQ2j&J2m0*CDQ0EJJeA z4aoo*5(c1wPlb?afz`h(W=L$-ot`1Fo>5J$&NMSx%j&%OJ5JQ7(ZQVa+}daERN+Sf z9GCNMq*H9@N)SzM2UW4O=@e}ZR1W_UgAXh8Snd7XM(CR$DttUP_o)iklblYTK`w{G z4{|d*3lgo!W3`{+Ncf4Qk^Z&_#znC5d91X9ySEv~YLiuPu9mUa$bBB_zt!>C<6Crl z#jrdSrJ=?)p8ys z86(Fn82IK{+W18iAQ{P3OS!x!W6KFpUqQv57Y5x!;E$G7K za+dbT4H{*OTIXCAYZQK)BFd^x@RP<3PJ!3=IPJ%b=CT1-)XASv@Un{zJRiRZ4LcD; z)d|CnrcUBMCu)CvkYREvxDmXs)$~Pj+!ki|?jSvXXVDOxicyg76~HlYU`iaN7%)Q| zS;`G@9(E$3hG+zw4HK&VLhB=aXps_H&L+j7+AmP~mOX{ARlc|Z4ey+J?r$-vc{iLQ zYg*xDzuLt+k3wp^rRcxPh8S@yhr)oxLPim1gz~wW4 zENiV;N+pYE#w7`v_La{%CZCo#DZXqb!6*4DHbZ$Op|BPV8)NIPj8M@xoxQ7>5<4A} zeiOk;J_C&|ZH6K@(}N{JQxhvuFwh+=f5ZuBO;9Ly;yJhbQMc2iTUa<_iqp;54i7M&Fa2E=D|JjxZi|Z2mP>zr+yuX-`w%r ztxmM)OGOv_C}>qd+1|0J%9cT!scV_Ea@`<^cHh)`~y7ER74k=SonM zs)$5MjfwY6M~O!rbFYy&D6XOs{E=5g`>G(h8hGl?-J`6-% zY1#xJu1tKL4f{%dSJ;KP(8o5}^@To)Norv}dWMcZ_|H2BuL7Ny`DiD(neTJ?hA*~4 z+c1#enOq31Ev;pIK|ZA`HbbuvrAAHRot#yyrm(u1dy3n_O!rB{*L*D*k$eYRo+f|G zI}l+ZLnJAaf?K&O3A@iH*iCQL?!Q5E-K}{0t{?fGPzXEqmBckQ)kaR&wU-moBINob z1aJqpGBOs}C=OBGW)hTUP&N5plkU+*Llie?R}t)mdebk};p}{Frmo{>*p$Mc)ooNu z^M1)cUTJizezgQwzTqZNmA{Pp>FqWL4@TQR>L}Wt8%1hd_FI4>>jIoD&|Jm>9Q>r2 z5{BT`6N%#-fr7~LSqJ|jqfs}7`7)dt3S@RsRRa`ShO-+QcA|;qO(l*}IlUB$GIDyB za@Q{wlS%x>i`FEFJQLzXmt`$d*wlwe=*jcU9M0IB!TTT3qS>U!R(bGV2r40^ogj;# zg3ujOfLMa}SHQ?(NAMoMvyeguf67*{C$79gcBIFLxdCF*Uz%y z_^8&(p^ssgIk@q?S@l9VYPaLh)=>S-UIQCYufty~q%hpUkW|LaC>LHTu?H^7l{a#N zQWf`$z#^(t&1P+3U}FIN-Lls5HZ24*n9&IFo<}42qmH>pBo2y4BNF_PU%_UKXv78i zc!%k>BqC9yni`dul-&t!sl3q#{W0gDGvW^)fl7Jf51(;&V2?lW4lMBp{GzhA5`UO> z%u0p_!@z)~x3i9psi%ydvnQ5nE;ynU&c1W|k&jba7{J(r7!0e~YD)+N^v+M&npGST zQ5L;(8}sYl`Ox>mWvp2kx?P>bKU{1Q4-H>#Hu!!%dWmp?jbsU9kas|9|Hk12E~2{+ z-}uw3=zl!nwycBYLJhI})Vnyl^^GfRy^~sGYK~0?7p&hTTa)v)gS?z3FT;Ow#UcopOscPYCe*Tq1a5#286g4uq_U~GWmpdhY&Hiktex}+IU%Tx z>>1q{+EY<;=>G8_!J8@A*+o^YUnodWfrg!kqd@|RwN#KGg|v(yfu-E$6sJf;#p!P# zN6a=7oss3XU)u+5irbFUAg9}YagJ8G+b(8*A-7$KW;rV@Zu?Py!R5B&cjmUA!e7*F zr@xlQZ9m9v9jp%OdRmrvX*c04?sX09`uc&dYv_A0D{G&wOiPl|eXm&jBOsJ2fArbz zK5FO>WZn4Bmt{iV!T_@jjntb>)<&#@<$a}lOLB+B3~q=?U4-_y#0QT@rM)kDAdQqb zR5X9hsHIb2fV5n(LvIjhs+&g4d)-pQ$#sy%-@Aun_kP_#0C;Ik+IF~%oZ({TJg7`< zQi)kVxxErLl58a*yhsc|CG&@T8L@^;m((P`2k(~FCCMjK&_2d930B-3r>V|QaelSB zB$*4+P>1tHbfN)JoE9o7i|E`p$?XB&Wx8`O{-U~*{#qK{i3vmxHRmEPSob1Wr#Ih? zd{{)cxHriOfQN{CYbQwCgn!b9p+_gQFChJs7rHdR(J6x5`t({^cLm)fmmtp2smb~k zyEc8J#73qzWliV=IAl~CTAi{^aw`A?TNUG`m!K+ugy7^22)3aBu7Gz-s{ry(2%!X4 z&XsoxV^T$M6=$4*6@h2~6oG}BxfQ{C01l=I-iyDeBA~yPMiIO@sxQF(3o}dRMcuxb zEzeSDhfo3M_e*{94h;D}n!E<#&!2R`bBgni@Va%u?7ED#ePC<@(Bdn5c~fH-Yu=z&p8Q%%wKsd zNd^9gILizy@I?b4@GW%AE%5&i;9vs(JNSzVeEMr?1b#INI=)vehhA+duaSP^;)?wQ z<{^ZC-+R;*)X>PfdI9Nr^CKt%?VYX;#(&Bci*T!hHL~ssy2V{XpQ#k&Mhd$xuw5b~ zTPe^cbQ+vxR2yC?&`xsu0tj|qrI65^oQ_}{O5sOKt`rJQ4xt*JS~=E=Dq&c*dKG7% zffa;k02G9Urnwcw%>V~e5U;~uR6)>RP6d%f5=|FW30^(5UPvkOJpRT= z7jLP-Mb6DuF7J!SDy?P> zh6xy{SK-JIzg9mE_DnqGb)!}}c@?j&15<6Rb{E>P0+%x$AeO$U1J8Auu$dQ{*+ky} zcAFuRKY7&-{cg2YKE8k~wb?)3ZiRkXtx3705|xkE!#ZQpO=90L41_~DE+#~#gM_|#@a8?25G!FwK zHZT&~d+n-k{PSo$)%M$EKnuSX61v%dZ%{&%aeBn1Ad1@I+@3whjvbqApMdS!&DmDx z@SduFbPtpa_w?e^u?7VNYLp{?0SFZVVJ6`H?(_Fv0+^lZ)G9_d_$KM*OwmmQn^?lx zx*yeOH$k+}fG#E@Zysh5n9{wQCgL5ylM7`zJtg?%u#Ft@V7xgz(Tu#~<)D5zXu$vI zUN&0D`WwOpuM?Hu(uH{)0;0CkXZBcbv??A)?T$(Sn|>-lcsAbv%M^uB`$)G9T}**c zis}*IpUHs-fqPn&db0*RAOyn}6cu52UN5)VUzmrj;$d_G`U-sTeIJZZufT0XN6P+! zS8tTPYPI82$?!nD#%~_&L7FO_U?KwMB(N9Ux(IuKfSH){Oqt;{=m^*)0!az1Q1xqJ z?>-P>+FQ)E($~;hO+LWR=~}%?-;d)<_M22tyBvZ)VLXYiqZ4gfnSR(82It(@o1x!9 z&%7#_jK{bqFGcbwq+21ZljL+>MZIh-HZWQb7h2Wc1E?bZ4Eln!*Qw=V;`G=d5HNgL z_69lAgF%fv3ump7uj8MK*1(^=_~-6X_*2F|4~@Z}58$8gnfnplpzlfH&A1l$fF%V>tBwt`d`4ECCVI4}buDxC_U(?CAzTTu;~-Mj^beikgQDX~qe& F{~xsPbSD4+ literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.categorical_column_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.categorical_column_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4e30ef0e0acfe59fc730016da18ab7da406626ca GIT binary patch literal 61390 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.column_profile_compilers.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.column_profile_compilers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0d207a39704f8dbd7c9cf63cf89bc64f8d9365a0 GIT binary patch literal 178393 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

    G-bhO+g>FsU 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 P&eqWd5Z025;o|=T%`%M& literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.datetime_column_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.datetime_column_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0d714732c80e563db42aba368cc5c995bd923745 GIT binary patch literal 48159 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.float_column_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.float_column_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..ab6de748542be7a5a9b11d95ceee78c747d2bbcf GIT binary patch literal 84250 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%0Ab&^H`EFYq4mO`=w@u`#qSs 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 z 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 Svd(FPynW&rDF}(0EB^yjdzQZd literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.helpers.report_helpers.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.helpers.report_helpers.doctree new file mode 100644 index 0000000000000000000000000000000000000000..1307f664fea183ccb60500cc8a6c43bd3f4aa836 GIT binary patch literal 20133 zcmdU1ZHyh)S>6xt$6ed&uVm9;JDoriU#s5T1d_BkZj;JQscLB(B@I8Cn(6G!xjQqS zJ99f9_Aa6%r7GCfDI$1KlOkFneng5C(jWYb6bafwk&pl(0V%2wAn}6=5J>&gLc{Z( znK}2&+?l!euH6c+w7WCs^F7b|an5 zne>?-r#I8HpG!ZRc6lc>u0=r-nk?lrC}G-;XNAm9FQ@g*auRg;DK^SWvW!`{=QA#CI@W3b7E>SR&|Akc0gho&B#eo4T z;?zFIJGvy>p681>wOjmv=lCq$O12HYV#IOiY$q{BNu!!~tcXUiWO_yvAra3DzR}N~ zmaSwkeAzb4DLErMZGPB@ji#ZB#~#WvM=uJ6rpg#-rJG=uCGAkmbA*%!|7opWWW0o;AAor_6)7vM z>I`f!a`ec7RU(B@%J5It^waf|z8tl_69&m3ICoYySJjGq^Y_;dNJw*J9N zl91Uh2s9u>Rtm zmCR&kx9^>g1_n)f%cuh5ewC%9IWBtX(Vy`S5Mj7x#e z^hvg@w)?K8c4cKDRHTgh2%0r@C7N}4Wi-Fmj3%G;Q$v+rg6;PJ+be>(cL}VBqyf!C z38tRX`i#$>FX+Hix!13^^*R{s^$+u2*Z8bfY3dcVDf_F10mnj&)^N1$gDn{_--3J3R%i+KHSOVe+TAVb1MP1gw5_tb_I;aV-vV>t}p zE@+c-b%4s11=c+=J2Rs;JDF_Re>W5?`|XlQWu2%pWq-FuO57vpxQyWQ1(Rl}4%DrMqG2s4h(7iK!rVEnK!G01RQ^IcmA4MVbL}1cLk%3!jmfU7t!&giv0WSMAkDe?_eTDextpE=~0+akw-viRpdWur}EZe z_^b8~esVChDDuCw)7S>WSiN(vQ{z?DQ>tAy$Y%rx8CHxbU!iq+uuYzN; ze%oH;%e}<�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 Ik!)}LA9c&n-2eap literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.histogram_utils.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.histogram_utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..aee23d9d197e3dc63bbf27c48d724476b63ceae7 GIT binary patch literal 4361 zcmdT{-)|hZ5tc3ANv9tt$&USEIX$B=svy#Bg5;ra4K#)mpskB@(8L9jz*um1c}GUO z%Pq;3?ob$L9}GAE9|D+p%RkaTr+-A>ilX1_-mdP{IF^k(Gy+ao4u|B-Hy>w)f9rhr zpWT(}&+V8($b33vNs_CC8}HT=6_**$t$*R)`MZDW4_r^PQ=>{9bMIE55eu0nn&ST)fs8$70MJgGwS%IADa zCj76$GhbPSZLhg*!C;5=V$b!$)^M@vx^sI+?n)|i?nh z;*=Q!A-+2~%j&Q7q%6(`5sQyCACpe$)-0RQlovbVrq~kuVpZI7#0G0bSgGS{LbJK-_Q-eu6`N8?B#a zJD~IFV#JAP$SoYH3@NrryFl#VwcLfb7hll2gq(3xe6?uK%L(YZFtgOsizmdzFUXNH z;;$mCc!UeJ`h%R9+(&ea8AaI&K1gNEbAw_6Bh8C5iu0S{32XAoTLj2!oIXo{G0Ty4jcjCiWMEK>-Alh%XcscU3MZ+!< z`M)-iFD@E+B3M-;7Z)6edv2#q*GE-#^Sr583sZx7iZw-yj^DtJtF__cur7x`X8ODr z5Qnt(lIzE%rmi7udxWhrUnDP^z z`iGa@hG1zs?6^HXmB7lP{+dRq<2nhC$_b9^pE8{TD`;rWGDvz>vzU`p{<-VRyeMsm z%!bUKPrU1uc6{{fBO~#>zdRXot(6W1%M-Lmz?n>qEqXvz+T~q3)h^!MIyZA}3-J%v zuQxq2pjo=VJaKNN+a(7KP!hl=g+tzLr!1e8Y{CI|g7Iav!0wvnvC>JH@B-w(G1Om; zTo)y63?Bi9Owb7Ov7CC*b$wP^6`qOQWeG-YCn#cJ%Q~Q12_y)obB3;XX2hpmK1G|!!^M>qMPeJCNF!^0?u3anlu_Zx+{(4)Hi$#F1!oNS&#FEi zl$ooARI95l`38OA5cIpGgYeRB3F5tpw?aDvKlkWLfj0RBEKFr4t^dQyKmXNn{el;0 zisx02+}R>Y#9%$$4L4{~^$by`uGf)%0V83JVyn03gH z?!5OQknQVneC`;MoE@{@9AlNjD@JlVu8t8lOL0WcvItiwvBE!Gceg;uENt&)Ykp`7 zV#qgc*UZq#OhX|jBE=8ny^<>8{g%lXZrNW-TxtWLu2tiD7^W&_b7*hH0zGGpz}J@z zC|3|-^>JC?2zqf<&!~A4_y+7zvCPNdK$8`&Ql2nnw5+$wvxq0Ss56`;IJemCdYmeD z9C9>GX^2;#=G9B+xm)G=2|b(KdYvC|Awe&^I3x&fL(BApBj4avv4?{|7mGv7P>_`1jAOkuKf#BJV2DwquF3OsE6MT0-fi(W|4g zD5>=jGw?KvRN7LxQhn>3u+{D@?bvHhtrlHf+8<>?TdGUf&+j##S#cXkez7VkwRyK0 zt270l-~+1P+Jm|L1!Dfp{|VO@4=^MIJjo66Zhc^z1DC{`t+-<9rp)8COptoigh;xP OP@0}+G-@62diXDa#hQ}< literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.int_column_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.int_column_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..4500bbf00a0e92ae0d4397abf906fb7b3557f291 GIT binary patch literal 81817 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 D>t*pL literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.json_decoder.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.json_decoder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a81a33749e7b5de82233f7096738177e1176f000 GIT binary patch literal 85194 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.json_encoder.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.json_encoder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..808fafd93d55675a275d6b4fe183dc69e531bcbb GIT binary patch literal 25519 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.numerical_column_stats.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.numerical_column_stats.doctree new file mode 100644 index 0000000000000000000000000000000000000000..5bfa5994e51b7b8a2809168096fdbf3a7c32a4f0 GIT binary patch literal 84175 zcmeHw3z!^Nb*4s-k!JL=WJ$Iek7?Urjlde&27(a}zhq-0kYvkXC&p>lbl0f+s;9f@ zs@B8UiTPLu8!9~Fh6RHSA7|2gg7Ldh5uv`PSd(QFYaQoO{l>=bZcB*Bxu#ylTbR3j8nH9JFio=80LaT5Yzfe$b27 zRa=$rg5L~#_w;tXs&{*DCYtDY$Aeb4Q}KJz3P@3@)f?50-|XGoi#B2Mu-*t}MgFyc zUkU52rpjJhQyZ_Xy}372n~2tg^|0X^pQ0THpt4TA;x$TFv>M%oX6bO~g+UKeT>Sw6@alf&gB^^O~l&z@OGtyKVhr&Z`{l`16>i8?6n!BlxLT+gzKfZK$1D zTUDEm7WTX}@H@etqe0X6=Jr%BEVnx?2D}OO96Vg^`0ZA(XP*~(hdQnKdc*JR0fK`) zoX|a0_yEc2!>oJ&7E4~0E5xgEfV`UR1kmQQ_OI;D)mB7n>dmTu!eBAye(lN7#@gAy z)N|qgr^5d`;s0IOUSL_LPOY4YR=2%+rx!hIp;hfR{O6Vm5z>pE$@A?lmaR5^AnbYF z+S6;h4Fw@?6JjR%#Xx_b49jN#SApcZ4$+lne8ZG#F zydKs{^)M)P{Gg4!>X=``@)v?x-amFMM#;KIT>;X#jH~m3+F96XQnd($cL`|yQWKig zHxS+|w|3H8r8d>>FyjFT4oq6~5^oN)$AkV2eX?Fz@WWcGTACqaQmQwLDb%iBba|mZ zH0!Fp=k8b!EuD^)(k#?PFm9=pX)7mR*x1q#-OG~VFI~h;VqzP(qyt&(48Yvs){%Di_ds(EfL()0j z>#+KClHceec`K1jUdIppPNNR7h9Ro0$&SM*mwiy>%##ay8!;EVZaL1Ub+RtW8~wuO z$A{AS5sfu_o+&Ss)d!&A?{>sQRckw0>qDZ}9nn}R zR@D2=qG}(MjwxCvjg#c@hPL0Vf&(g_fN0d~{P$L3da+UX%^t?mFmM2U=|z*+&suXB;rA?y z5RDJWhT0En;}Ph1qd`5PMxMa0O(P}y$AGdq6e8&@H>H(UGc*ToGL)IAU8+>*%*#C( z+w3iI{_efSj8<+TwVJ8zh}Mc!S}*mh+7#OgqeoMLYJaK9-=1DDgvVWhGsULhpDYE4#!2xj z#dX){G3& z(<^Jr_G7(M>>5#hZ93;rsaDP+{G4l=^|0bJsRPz)?eym!QD&XZJ=`|F(C8wMhG z6*N@yIa54rBUQw06t`IrwA)!`cyASs#OkWixbQlx3FSm-T`E`fsU@gb}{uQO(_W&;uw-(_hK>Bo;RuXY;iQ1yL!hLo2vKqq3XWc{Z6W26yv7q0Y%kyqgQ_( zkiT!ytC%rH18YSyx@BzIasRwgO2-ZKeWe4sv&a0M`|E@lZj#a-yD3KKW7&kd#ULt3vg6`G9YTz%)hl^e);})F$-cn}8-(33EaCQQ z?B-a*PRnjs7Q5{zD7y!ybPyW#ZBb}Ns|};7u+=ffRnge<746TD(SBhj?a^2(fmX0R zn5AF01*#^Z@p_Xc*$k9uHAV=M8vet!QCDRX1enmg*KLI5V_u`{+r&ku2HkeM)d|bN zg4YRO(QV;`9tMJJpGk9!=|;bm{tQq7_HpWP_Sn*di)2~=2Ap0-*TP;6MRA0Ht${~2 z4u33<#U|lRQEUW30k#3l`vdrc;VvKo!uQh9=}vgf$3bipJW2yD!$Lhax;KUdq;&W> zzzgJbql^ZFS3eTUDX8h5yi7z0*WbcBT@D;+H)t3fVy2|l4}vP-elq4|Rv{%x38TJF#e558)hI82UU8kR4bL8#+ZJ{$x-i zV9nc!b#{L+4YLC5lG^+}$ZBZwDy$|NK$nMSj!b?`c$W`LWp{6k0xz^Ab0(?SAVJ94~MufXzT8_<~ijgNQilfg)=q_V5l`}pQI(Z0J z0pWbCSSYt6GGD2tKtWUNUyHPZ{en0CXZVkbE755wV&+=alL=xC8}kAIOO$3rXs58k zU8UW-1>zXcGALAMZHN%w7Au=@B6yRSD}qIC9as%zR0(h}$1mlOLjAT|zGD?MBGvm? z-UHnMuCc1m*DJldT=5M0qHS2<6gvg}AveCVG!t`p_{pqNN2EgBE22|myZnWA%?s** z*|JmOJd;gKez4m*8>=|oQ({BT=MC9K4M|UG28BHAbhu5z;cbkAT>u5Mr@)^yR^ptl z=Hu9|er((kttmZv$33x$aw@@M_l~H)f+@!3NGqr`>*(i&r`X0mY()vIhcr+)_Otl3 zh^d&E^fBHge?m#qg@sA~4^Jwsk94F1&wm_3;g)8Gj0#I?r7f&$+c#ukvs~ZIC8NsP zs`h5ghR6lSdP+x>2m`vAnue}d^LqF&kN;4LLw5C5D8W?gGE>U}sBc$!qt7hm2@JtH zLjCp3&m>sv(rq*?MCJ=e@+`-5q`GT>OM!-NKD z9BY8F3TQ!-g+!C-kFVLGFQz(}*!gYJijUnEYt9F=o8v|ivxxxmlALsbZlB4n+d#OAV1Shs>IuH)=zgD_68(9rgav`xK>O{#@PMc+)eIRu_l?FfI=4o z=;JU7Vts1&L)>VA%}4xic^DCbNNyDp>draf%hZKk===DB111ZA=v8Tn78YNzMJw4R zlvlDr2NocD^>0823-Rf3eCn#FWAJ1yGvLlgtoj(((OxHp-!r?0_qKdZ3%J@B4(nf;xU{CEb(!k+NhUNx44;e#ct%&%l!j2D1=$qCkWwjEU%hk|FTU5_h>~`UR zX26@~YU}|9Ed58t$?ayI0rh8L;er|LLZs8p4{bx(W=OTj2LFuIej`_b3Q3XC+#=ZP zG@9n>&*|$(mbK%E4L90Fm@HwO1(4p7WjRU}!&}L4sc*V#I&g6r7sx)M*papzah&^4S5WYu zfJPn^yceG+D4?gs2@0;oU80?Eq%px&!^Q-hrXfOteM!?M+S&0JTF3lywI1LGtZI3_ z;T_pqnrp$X$mf@?@*05;2x3ai0PD4pS8|{wf7*TMA&{CmMzal7_K^KSl{fnAl8zW8 zqhbNWIsLiMnX4DM<;`L)THEHTMoP{7(U##il^mR*gnK#L*B}#&i$5(bUzD+&?FZQv zxQFDT0>^3{{9@{yv4C$isy1)CW5iA$?Y93sR+g>5gM?93N$xP}F=At^)=ZA4Fa#XY z1*Q+oSgUl}8k>K1?d*9_OniZ%T&$EW6rkZslZG{9VWcXGUpD`DWz%wPoR*(e@Pw?qP=TFT^c&6t#mI`bRjoq*{WheNV`BGOT$aeuHi4AYIrj z-h`jc(k(RIUoKa?My1=J4XnW}B{=2;(~5MHVkrSnEA;3Vt`Z2=?|bx)cf`ne^p5)q z5~88k=+a>ug{xuih$#~=bu%3&1Ba>1`>;0~w#^%BPPaQ5AbGiOne$MO$&d!AKI5W*pA=?rQ~o2S4f1NuD@pLxTO^?)jt|GiW|z}wpan^{%CXO+qt=8t^qg# zx%Bc-ea1P(k6*3$c}Mi(k#b12ZN%k*?#5~F*GHzlebP{kyHWre8rb$xkiDEW5JCm4*l_MG@)g<7`UIygC`51IomJ4vj?;LQw z4W9^brKiOKTn|?3^YbHxTZdllgcJ<{w!R@b2BkK(VA`jHClcZjgL`RBvG~#Hf8JoC z%F)maJ*~_uz;L5EbbCz8kFyq?W|q+UoLOl*pZtyBnDPQokfD4LvSRiz3XH;4M|Ygd0IB5#+W^)7V3&}YtyMfgKbFC_v=3`n_f3(MFmN& za5&#qj*GKvD9(|Bt8S9q;8KNAnYr7Iq_;nt)+}zsdSs@~r>G=gHF@WwDw%|4&PQc; z3!uT8kFwUYy4LS@vnd&1Hi{D%h>F< z{;UysY&Ocp0nIxW0aq4zHp;Q@fuc$P;^+tgE*P4)c)c*vppn@}2wZp-9J?hZo#q7w z&v$kO{xLk~&%L_~`u_kqm2G2xjIy6%pUABO*hXA-wzT(Jh(Q2}=%b?TAfkb=aC5t$ zh%n4oiq~YDzg&dT643b~W||iLy+0a$$O`q<-a)-?xFirC+C(VEstAO`#8_Mf>ELu8 zKiJ53Y~&ys9(!xI{n6ZQH}Rf7f?Q6l`+M+#uW$U0L-MM+x zO7Skrl^pC;ye4h;-7{rV?7MxKi*gWfFLtw>fZv}}(vi&qT(r*C*K}P#a>Xpb9?X>A zDm>Y-Lm2i9C|@IWy>B`#wZ2I~VpkMt8bP#|LXNC(z>pZSV8jx$z<6QRtaqyUWY4`K z&6AS*P0W;Eay*B#|z~%8f$K~ILPlU_U(<0&W3qBm$JM=bW zFzM{hg7cR!*^pJx?(CCPWoXp?Q5#}F2p-~f<&{9eHDu#nQPH)oo}>Yk=bpfW_y+% zf9;u4hTHa*93O4UzMn~%IYxJjQ`4laA^Rj0`os^FiSOXVm%(mZu21~*sZR+BIY;_> zV^FkJtN_5geC>r=KkE9V)PVgGE0|(G&#ei_V?4>~LCnF4{HY=`-5y|kCFY%Fo1hS- z(^`Lw4Zv{44)+JHnddDN(!*`VC-QLgl;Yt8!Qe{=-UECP?+5!8^Kw8@s+Z&DChO#J z2j+xrBpWhQ({{#i2qJnl-Y8|F*!Afkjp8n1r^>a|T?Da@%(UquBvZ*n;18Q=dsXv` zy9muX_8crG<|5YPsa7|UD^TG6#=Rx;txe0-nY5%i1s4^%Q?qlR(0>P~fSg_?PJ!zc zVT(@@5^_2Pb1TAbf`7py_(51-@Iqf5>V>`hCb%0w>@UVWhst3T%%!x4RgtbKHkVt0 zgfCehU7kc!)}k2*_Eifyg_%{q6_?4#9xuXT2@r&sX<8VG{($dk2<@Pr%mlkkJ&^%s z>UTwIl$r#z}uIF+ckNbBMU=*3&7ePtTv{1M_*dTTJk7ML^Y zQ6crutX+ax(zX=>v!t(5YV82Ci1nGlKBnMs*2JU?_US1l*cXxSptlNLyWm&rBL=jF z-q+7*8Y0+tY3;KnDl0k%kf?|g9lFa(k0)1D_+I+AxpwLAQ^wafNhWbl;ld9Am4z5fI zDfJEZOIOMup8_{-!Cdiu|Ab0U*-cpc6#Mnusv<-B|v-i8K{2%-u96v$^8%dr;}kSGO&=`wV!bW$udlp zy|qx7Dy^)Nrz1@LG>{9&&SqfJn1Y9?e~(XuNz>EfgsF#*;eKh@RzFfq`s!g1ppsOj zhN{u$m-P8ex_uONWz4`nDX|f2R%aeO=3cQL3{UF8)@gy;FF_@FuI0sl4YRMam9y9OytA?gpi=Gu58@MfKzd5?fP&y*W@WDp!fMq&Hc}rrG+4uFO80TCY!~=GrQ2GM^7_7yL#5pJeFC4z_t8_D@8bjy zM5W_epYnRd5>(1P;@S8_9+95XJR&D}D35rw+X-86Y2&Y!N0d}8SC6RMH-JafnFsfX z&&}OAOpo|%m1~K6M9spuN7P@0M^rDAfgz9hBE^d09#ONAU4zAp)+64SNm-glbkU?O z7`qS(ed0Z$;{EdQh^jdfaukxv>k(!C*a%U2#Q0~Wuq?!irdTJpW=N0t49vmDh%H5I zdh`t0lWj@_s_U3{z;G}graeSoS z@%mwB3|$nadP;7dvUatcmz;KU*D$!dc|d7{%UY({q<5-Z(N~xB6sVh>G1s%ror=35 z_ea&k$tC@vVwa1_+0%5I)$GGq%xGQGr!y(*FMdsvHX-a@D0GosQr?~+-P5wvQW_7v zLrBo+s?0q!FMOdNiWO5OFrlqR7q-!8J1Te9RQW9)xV)+cE8km3I^Kf0YeEh8MpmBc zE9}2xTc+4|ax10qhRf3k?Oy}D_?8y$ZE!ZSyqE#Z3Ys5vo5ziZ;j-An-MO&i!4c+j za5}$VJ>rWSS@cpl9-mBJ)oSpQjI@N|e4{puHpBWcpRRdn`bWUO!jHDs3E?h~POA&2 zAKmJAT9el-KuWk805l{#-f~rjuT{~LaP14-55lulpdcu4zSU7BsH6d%r$q1TR0$lO zE}JrWxC=)r@Yj?=7KC@sNLqABlh-suzte8Py(GL|Zo^%gPe;0A34yMm3U{9%onqnh z|7S0Wdi3noeg7YM-~Un3zR&&vbDXt*Ep(Ru36K47A#vG<>{oyb@d6++bsTWke}Sgj z*e2JgbC4{Etx+G}2vp|9yyU{nRhVg7_}KnyV$Vp`ak+j!BZZPgl#vK{d|Hu)&_c>> zkfWbe#C{)aaL$F4D{_=7Zt>Kz=HZtPRdBRp206wsN%~dAe^3xR;|yP)nz@kjGN6(V zlPkF=*Q!kX7Q(%4*2qnE&W(VdssJu%Ya#OsCk1ecoVb{XVs0Uij_=bO`xZoPvn0?EH zD>d&}9SgugjqY6RI(WCp1Bfhjl7oh&J4ZoMW}X3Q2CvdP(13)-z$ zb9Opfi(jnP8kg4GCIvfoTdcF)AIlYMkDKM$M1ZuDR?l@S$A_}(&cRFe7jV!!F*@`* zNBpoC@p^K1cHWX$2g_7s2j{s4=Drr?%bCs2ycQ)}*I{5(>{^t+&ZcC5Yf(6XF@73? zOd72IY4KVVS9HfNf{Wl)fOl##M&&`iLm8cEZCm$mnXEBkft>x^S!ZrN{W*}61wjhF zvI~JFDeTgWX7_`uSY&vj)NdrGP6J$K!ytkx-X)@2Csbk1Y3@1Xbzmw=;SGH5k_B*Y zFM6nYtLb%4!d=xcyG1vaOFLdTpVDsj)Xk(K=i)zk@qB>6r}81TyV~v#=*(`;Lll z$jut_sJCgzWu1>9?@2!lALuN*ZJPXPcbc~h zQu{px7|dP;iF2Me$leNR2V-#NnEC^QG%^p1SK-iCs4qR+%zbE(dOro3vSJZadkZo5 zGlMdhJ+u-!HAff|WAtwg(ni5s2=?R0MdBCBexzKQc9qu{i zh-q5;P#-y>!8(AgonrebDLV-N*q+639oKRQp)|8kgYe`w#Cu#YgP<_8`j%?oQ0qZ}^~A zVMgc52~xh0QH@IjSX|le;#$P2T0fgBt=5!W$$@KcE7DAIWN(2SSpf;!N+CUD$B3m@ z@Hq017ipdx1bzfF<(J~tBo@Z4am;vvL2)HjG9zdDNN$1$bu>;Q`a7P7NtWq;55!LD z@%jGgqp<#Tb z3Oy~(N|i%RZ(+m>_x2$kA;ZL3`4G%Dy9=1>05l0GfLOD`1AgG(%DwSf=befN zVufkalsP8W_r!A9Tps|%FE+7`MAN`wtZ#F2P1aqN-5mF1T{aQ9C+lv^uG;{*OgCUI z*hmDwMJMZcOVX{UoLs`24t1Yl=ON{>1)7`T-6GF`q?rzMOa79-VO?}(0@1e!)o{*s znL9kOSQc}Pt6knt^|1Qe6BD4r4LkJI=qNTH zNwS78<&NDVy408*UuS&*Bd%ZAw&Zc4CWBb;U#PrGeDjfJR?K|sspA>vh-TAPdqfzY zh=xqA3FjTLY(pDxUP*2Xj%4Sx;9AIRBa$7n;E#b0EV2d9(tByXm-a3xL;uKj|4ekO zfo-=e0BpBIXt{0oJ`gy!-B;oh*=~AT9NT>@T&oJl1h;%3;HBqG<@L zeOfXA7e&TQ_8R>f%!c@78|&Z14w$;$D?8l&4V5?g(t7 zo@h&rWaqWiTEeV>WXCM^OX1xjTk2F@mu7l-Xdc<<8-!*IY@=lXV51%4%59?`06Msh zeh)s8ji#r?vC%h#wT=&aSp#qWR}C;RC>z3FJI0Gv!7;17KK>DGxAo4p;C~{tW{`0E zlPd2L2TUxM#qIc9tJTOrOde58NVnrugw6M_$FdD?$ElLs5jT>Z*N$sBvo9gpF+2Vd zc(=%QyiXsH)_iGWCbkxmP5+qCl7VfyEC6h}Lv*=q`pQ$KO<#piWYg(sacugv-8MwY z{>-l7LvI+#)LK;lOoqPmhto8KA%9ge@D}Z?&X)t2dG>?7uxPPa^@7<-tK-k|ce97- z6P-CQZP`UI}Rcw-x^GePj_p}vXnnsDpsD%TRfmq$vUyn{ZG zU|hZjFAUt1KW)}MT`_^X2;0_YkCHS4+0(EXs$ZW#@RU5N!)2@Y@aE4nV{FWyP*o{i z(QoVqUzXY6l;a4V51C-%*qF0UKaSvFb_MP^Yf*t?uO)slb=zq58L1tTb0N86AR~v( zB|lcHtrljFN}K$y{gA%MZK@eH=Z*_Jl0u9W_uf^`&;B##xR3lfu40YpeQ7grTc%6p z?QNNtjKU5&pwXerwFUh8Q44rz`f{tmYxBuVZVh#bOe+RE6-ry=2+?s#W~G|L$mnp;6He*xjj^D zR4`vDw$s|%hl}uBE*AbgW||f;NZO83z2y5!6&jRgQavc&|2YqvkTLetxK>*(_pNCNTH~MJS=Q_RobJIk#dU#f2E0DPAVl+M}H|yLWabvDRMtXvILs zTKly?Zj`as9=~%ey@pSOyU^3(;4Z&W56bhfopL1SLE_^1dPN@yIrMS4lDHutn5QKn z7+LDfiM=JjLI`FtAYYA@tQ8HCqhIw~85i=duL41tx{}_}ONE%B8rlAVdO z8`tSC94pZ;YzDqjv7$IyqS?safW^enl5s9$EKH9XlwzBiM|6olj5 zkSQ<1@saEb+z5xLz=3e!7gH+@goAb;P}~s-?0)!StfX}PHp2*W$$kvAD7O3I z&xnVyO5OMb=SI4%mi-U$iTho}8qt$Xi}-{~$!vULwK5`z{V>KC=^0+9D749ZRs3eSrXm_ChS}C0MFC;y$xmg^KhY@;^!3M|ypy>zC^D zr4uE%Et9;u8p>xSQHsf)v>j{)z;XCb>KdP9Ks>#CJQ&TvZ5Qna%dN+^&8y(xiE}QP zz4(H209!!@18{;TYr)Vp>~@+#3E2-<%0Q|MXD`T;Dytyrhi=6JAHCxpSn;EG+}E#a zNQsr_OqrcbJ3zLJE5^>Eiowpq9B1uc1zM%K`UD^z&n-f!9Q<62nWjY?(I4?R<3wqO z$B(-)j>H2=;C!_ZE|4PO#ZZil(Be>TV$GrUR>>(sV@g{*pBv_MzL^#rIib-D?)F}Q1 zxB!KAcR_KcW~EEmKpXDEO!+(9R`6}ovz5Rs zHe2cx9M>l;2G>^*#fOW~Ot{1ch-ukv6QaPjjaU=~kBInhMVcpV;3JqRzeozly+6oJ zlxYdrt&lC};c5}5slP4wK9t!9WFn#eRsVFd{~`AZ2|cs-OE5}$PB~?gok@UEGI~_P zbbwLB)eJBSzjH9^v>g(RqNl|Hqi%!<7`6e9Vi8ariW+(?5GQR2AZo@5L}7DB1Vdc_ zBFblh<B|gt41r%SdBj1bVI^w7D4TRubqL@$|fYJy@MFyZ8>rI3)k?_;fUZ@}q zC0}o{OQ=U*@aaq!_ylgvKjL>3{FI$Y8DsVZtaXb0xu{$QJh8rKbP{C!(qAKDv;K36 z^#=UZGT^7{o$%9DUL&yZCwDRfrOJapy)uSBxeL{G8vv9$sj44S<_4g?%@yODMHPd6 z19NZyO7ryz0HA(Ygi<;9`X88STEr0}2B6q=5X_6kCW*3#Kp*^?SLAGVKAI zfoy~0Pzi%c7UA_!W*=da&|lX-oy4J#dxeCaX#*q%r#W2Ad8&6re~YjRi|gFfE!nN97xLx zV{OTX6d1SUzWbu#Zp6#f=?2|ay4HwnSBE| zxyTsS*?mpDx=(MpSz21z^DWVt`=VOEc15ds3^q!Yn%#x=Nw|}&Q}^Z?uw?~Sc;MaU zrS?hKW!@}>C)>XMs_?Esvnzwaj-zHzv2Jb!mq^&Mlv_uz;R)F-_1Yplm*bV!V5Vu| zL;FKF7lV^5&2Z%+9fIWyq*wTZc1b}3Sj`9OR;l@wqowoUU$1!t4xxvTAhxuqkH>vy z?)I4IMGJB{!JW6mhZJxJKUuyqX2fl9XHqv`#tY^v)fXso{79_mbccguU$NNe!$fL& zQq#{Cf_gp%1!ppg26miNcB5A#Xds)*f7lKE@*oWrGRb83gwiirz46AT;d_J7@ZAE; zW?z8BImglL`;ay-vms1K;A#o2Ou^M0=}t@Qg^FKMY7(&C@e;MOPeafvk6W6IXs@)`)tBN#Q%H;~oq^L{CWdk6d zXt-!md0Zwh!@OK3b~;5Dqa;)8#v-Jd@)!qsTo0LZ$^%5@6k(V_YSHynFEx(EvN+47&n4Y_z7* z@PeS{o0|bx09oiWr|x$Zb@UXcuC^h`xtZGYq8$(x@Jo4i^ZOll)1^F6m)MPKq>wj2 z@)TZeC+yeVbu*1&CTml*RXiA}oe#EVWtQ$l<3X$2sX%mfK6LBaShT6q?R5NRSQhUO zL>uIrM!o6x4n*tVq=XRGd88Sh~( zlSqMNsF8oxFE(`icB=!|Li@-3MsNShXtL%t)Xz217XL&Ycm?}EyMau!CR$VV=ekFr zyiLcwP7`VVCyZfKXXhDzy0)3GnHBG{)uPoqt|Tup<_eWv{(mN^11 zR5=P}$~q|3#wv_P;ovZ#c)(bCfzwf)CQScBft%?KaJLzt z`1PxH;CHL7@`(jhsZ;zD?N;F9YD<-qw4@T2kJW=ZSJBPoYCXVVFEpe%55hPQt(6_3 zc7C)08WTVlfK9)xCVbl{l9ll?)}VKDFWP}mPzfCOfN4O&SXvcCzP{rfS3f~Tw_vXV z&1oJ1MQqd;>S6CiEB@yHu8B6a{dO7H;zMt&5X&~;8;ldm*gc|BEezYi-aUJcA3r|J zN9D7v&XGM;|JWW#8SLpr+c5``0y)ZXbvXzs1i`F>_q(5Z!83ugn>zEAST*=YS97MU zCWONwgW0+t&QmqDaG?QJOoZMX^rC85>+N3`O@mG@lvVdsPKn~_#gClb)$uh&=XT(3(4JPM-kb*=kcMF^nu?%1XQw;GUzqdZc-8PE)K&BS5K7x# zflcB^%l?8_ZJoyb z1XZZ|^Fi-+Fk;qQybg$7LuvEs$2fM2D!pHeFZnZj3;LIP;7<@u;A@PBFcEz?5Y*1T z9R|wy9X!qR;OhEuacWlL-ufp)!rIy3I-W=Ho9WY{HT7Vj1saRd-s4!-boBnEGY0`P z42XLH11Qd{-CR4uUX5P*F8p%>JUP1^|7>0jf41SDkKvyO@lP}kf8KkcRRC%Tn#JFsy_M;>x|(lzI9*KQm3qP| zaYEKgnYLQxgX`>s=&QHK%MxE!M3dkRDy=SB>|V4ULZb$BFlYlr1Z%Gl@9zQizq5B8 y*fY2a8!ROBrT`ofuTVJ!>-Bo|n!4`#IvfYpt%5CX9YGU5Sw+7kOgz`3+5ZP-Pt!2~ literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.order_column_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.order_column_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..a0c949c029c5f1f1aa6c294d45889850b9fd85cd GIT binary patch literal 47478 zcmdsAd5k1idEaA>o!Q%7JJ_?c6xgu6_U;VWfUWg`*K2IA*P30~I5u)jyQaHls%pEt zny%_S9A7{%cBq8IO-N8coK_$R93Udxc1S`J5h4^qxP%nvpG1l{A}qllQS$rVRqs_- zRaf`SfCfw6sebj2?|$F=-uGTTI{xlcpWnd#i+6@?*K3`fv+MO%PXWVV>UU#!Q8=soLD|9;H{Hd_z z*o*VEmsi`Jzz1Ez`4e|mJ5Dx95~-|{iV+ zs5h^uH=jwp_PN7Ec+jA=Yz0e0p$w{T1l6bFDF~ju+_BrPM)~;WW5f$f0ASfIyKye` zLTf4LSYVTP+N*c%h6Q$7XS@h1XaS6FjWDT;Rsd>_E5e1V)?K18M?v!=TwE92eWVn* zazZS6HKckyu|`T1STx72m^4GVXqxIU5rY1(MDdZML6ca#*l?^0GY??kFrspx7r$x< zy_ieJ>t(CRU#t%mF%TgMgNYi$6jRgmM9vHwFpuC(HS}OjNeQ$%@k~OI%4K$EIXq}x zcG;;j^mKqJNCiFbWbN%%D~RmW^b=2Twn=4@KNDq`fVecvDMLJUw%Irwwr!dWx3oJB z4E<@RM>=u}y)26vU>);l8>b{30-D#P6X1@=2ZxbjN$lYonJjrUpCy%eD`e#m=+B^x zw-eBe&Fr_M&vWkYx(^b69!~hq(`*`KBpIh}@w314H$&XhhVb>Qlx+Uae^SsPVzHyZ&^R)ea&EgH1dKj>HapiZvU zm%{O9sQ3{;_c1wJ#9O415v2N*db8;=MHPB9A^d(mgzgtJiSiu``;6**f?GC81o_h( zb+7v z-~X_6n2m7w{)eM;ZSulSc7iB?t9HMTgbU+IQ8VFvQsmC~=WpDwLFW+c%(k`zx39Ha zJ&U!2u3;Ayj|LBOvf)AX?S|IMw`c@fBwZM9k>Dl3U|OB=FHHeqI(TsS86@$h_Boo! z&K=@pHCP0-^0!A!#hNv3uhsMCF-AOz0?-|^t6+4z6(!Eu zcEhWAQSS*>0h50Vk5lmAg%J5$sWI^2@70>2BMFBU7IRfD2f zi$UaCOO3#eLJP|pzK#mjnq_r6Rrb$cAPi>w+XW)-Y{~VDTkRu(X0%dkV-k-YY#?q) zxMhJ8Yc{EH^%0V4=uSLQ54c#@&`&%G6UfBcuhUQF3uwP5TLE9aKS4aZpBWE|C(IJm z;rWj$yu z1TE*F6|~92hoNTGPVisWb?mKN5j0e1(%l#4QvOr|#f;?}OG}e<7~t*u52;r1r`O4% zOrtC!MuhHIrJ9Wcwd8fi1-m^d=B_Oz{5;z-fNtW=yrF_s7T5+2H?}+7waOoahU6Bvn-lu}g!6 z)usOlj0mPBioLgJ9_v%`Nl{yJQ2jO)?y_PMW~=&3(FlApWhGy!uPz*;P*(UzS&~a{ zbjj70#M|_Fp5dP@Qf57qE(@vdM-r`m{WgazD`B@WdZ$1rVoe^wAWunHV&ipEHt=L( zf2tV!%(#SK%qt8%6;F6AwyCCtq`0mL=O9bTA1Q=|B6&-8w-HrO+l{VcP7m?+gN9%qBB;bWqAg%)UG8RQ7+5uI$a+zB_mm7-qz*~*1ZYOg_a}!JX3choXa4#jKw7J2v!tNrAk5ZaIzd2MfuhAN- zx!T{j8CcKw|0e(|9ot&Z>XpfbYwvK_-f9c6MVrzjh#4&U=&-%_(21-wu2*v{L?dl_ zMd=p2p5n&JI!U;)i*scM{mIomU2~+YZKoFdj&BA_GqJq&G@ex1`q!g9Ql{iALT!hO;^Ay2K94&z~c4RMQkxSQ8t>C z(KbZ{sA7Yr+21@dDlZ~rt;(G&)#!kA=#aHQ1u!O&%LQ6EPDq3hyFFFJD1z3q)@wX4 z&hxs`RAHMcVcV&BOJ1$_c$N=9#`tbdxI6KO&48P%N@9W;Bj}Z`6ow-wq+vt6OCseo z+pdj7C>^Z{P8LQ1c#iU?$?!L%#>tT}F{u%Z57K)4_U0hrblAG>(uv&b008#tY zqOeQ<7`g)-H<#%3CSH|hvGhJ<%K7l;dDVj@dcBNSmHvrzIY-`byp;sTs^l!KgRCrO zZDnMs#B8KZUOQqZb4+H93X{vMR^tfW;BT?$H_035zYPbcZgS5K$#q$f^rZ5N3lBU`d#bWo!cRSt}9 z&5*R|26dRS>qj+Z90oIyVkl#Fy>83|MjfXaoOY^pFQl~gdUdH`FCRue4^AUoXWeW! zLI-}?^;X?O&K?iwCZ-QTA)<;@WckxnVoyknw6?>TKS#BVKfeympCk`6fJqj>iwD!3 zlQh{MEZd}_ZI$iG8b#QxzQ7LHN4f5=CIr`VSjKyP#( zTqDXDNj4)whGUMt_TdM;N>{ z$U#h;f^>jbx)Zcle>RKg8T9^rkT0M=rD7T6bkb?Pbv<`7 zmRulk21_o-B2`)s9$E5V)>l;VU#XSFdhl38So9)AVzyp8Gz@)ZJoz$eG%KZuX292I z0B|_9oh2`8Zni2kIXQNVMZ(Atv!cMN(_x<`jw@Rpj-?7WZCXaqLO19(>eixTIcIB) zZXHKP#ny-}brmycmOc3k!eqZRNpxdr66tZF^U*5VSEeDUZJwLHr}D3Sxl=!%x=J4Ry7+5e36V{jN=6=Ds_ewZlyun>iul;rQCQBmfY z6dPLRe4EwP;Ji3rwgpZJ_!GRY6l(d?MB(S7pzu=$R_S!)O%p{bQy5O*BW10a>5Z<3 zS~y{=rudvH84e1C71-*^q{j;iVf_^@}BQs|A2d5RDDM+oLq4NcQk$cJKR z;8x(hZj@t|x+Kk%_ z%jmaar5d0r+vp&|~vr=l$beY>xhCV?IxcqdwAMpM3q7dg=s zdS%S#{d1`qO-TaOIZn(EQ$3m!eM(Pc9OZiq!u+Z$iKF}oeHW8S#8EhzOmsIQiJvbh z@T6=4TZ}zF3Zi0+K~$dL(k922KTQB8CQaVulTV9SZAPP_6@X4@|7SpPh_tUQ=zC;J zZ#rm6bm`GVb>AqcmZbG&XtW%eJ)1+%k23VZHKg*(S3qU|7w}!BKx+pkm_Xk$3Z|UM zv`9)Pu+kgdw4hFA0&7OSmzK1xic@jf7MRG><0Xz=Mw}13B{Tjrz@$iLNWDa|>z7&8 z;#uVmzBaZhHzhG5HlxT8KBc-+RD-sP%%dh9i{09Vt0KwmNvOo+H#N)1HMd~5{HbWh zcpjDJd9h-PxP6<+JviN;21~DWamZM;nWlG)$Rib#|1e>HBGqFl`}Y`wFu&?b?BCna zcQKj7OvA}!qPrQ!rR6ct zJZ027yaGj4T#Z-K3ye}4uEA!kIe;O3W~{JFnVkHE62?*NtB{jka$n^sZbt|1<4)co zawvqAQ@<6RnVI{=Py#GY1U*lU2CONx9o$Rg`Db=%uf7~;2kmYHSpjvm<6o+-LLn|y z9WpVs#k8^cW{$5>XZ#7Y7&NsB?h!dwnR{C~_bfeO+9*>bU|ifk40>{9cquh1&&AzG z!Kme+5(R4;g7Lj5*r_8x`(@LQY-<@`UQZWsg!=ZqN81mEjUE!aO=IJzDM z%H~)yZek$(N6_h7$K5kUmu5>ktFgYth(+4pC>S#^(thVW;|9VkKepCxE#{I8alChph#MsVs&38zNMa8#afv1k14VMr@|s&7%FS)rpj z(e}hMhVMp}D(_1p(iMFUotAV(Y5bC2#y3m!D!dFy@S(g6sZWX={a%K=)<@`5R*Kft zl=L&E>4~Liv8T21Gj6GSOG~SAbZO*Mm;^zthp{dX#c_<-R9SF*^ikb4Vr;-g$@q4U zu%(zxhxo#e)|Yr#khzV}s}EM=*- z>z${`X|1JS4abDToE-VOd3DAW{U*6u+l_vuB&14Bk+?>&HOsloNj|#@jo@~ay-4y{ z;TVM(LwqEP`lUCL=#4JRTISa1_gF)9vf~3IcWF|)ngTk1`C~*81|2sW8M<9q$%$98ZnfmZeIh1{d%v^HU!TycYeA%YB-*FeF>fj+eKsNw zGvG=K`a258C=_%)QkJ08n;b#kVN!^bCR>2F$f_x_JeBG_#a}H2Ybc3Kh8sr2K9oi7 z{C)e+7s6ghZZT5-ehN6i7saOHe!XxgeHA5Z3Ik>iETagGtIbkvedHY;4+8Hd7r&$!z2RrpTzNRlhA9T$eH%6MxLV zf(S?Ms{a!lZ`2ac<+f|KNyw7(OA7J-70USw0Z7prQjkraK+U2?LP!5%P-v~=O~%C_ z%o7*ECcz&Tw3!t$J}_u=!!1sWzSHIKtK;CJ78U{n|9R@@h47rCI z%}QX&!!11Mc@@k0Knh5N&l*vN2fO4igHwV_{O~5ezA7A*k=rYV#3OeBE;fcC5!*fT z(4t5u!EL#FM5HVk*SV`iuOhA^Wk)dyHZO@z#ry3x7T@iTM`{yvqjoo~;T8-iU0)I0e>)Lv#{UEQGt4<{DO6)*Dm z^%20!cfUSLPb@0Mo^qm60$d{Rs9z*H)@>sI;;c$+YUFEmI1IVbDZb<_`b1Hv1!m?1 zM)jpCz6Oe0TMr|Lt5vtdxmwV1=6KoMo$M9ASZA~VkXYd)`$Q8G4IbH%Kb2In*v?l9 zMY1@y^99v*UEU`k$-^RcNp$DZGK}KJI0?;^Z=~PHGo^--#$78h`Sh=f)-mH{-bb=La(2Xl;z6P8{Ot<0hfz%^?;Eh+x;wPWK!&xsew(Od}N=rVEkbgWY06! zq+rTkCUM%Dwp#~ZUkdzFR<{|;23iUv>g#`lXw|ye=whV}aZdyzksTBBsKDG>($FTuLCUZWVd2zsEQH=|5g$M+>csX8pO(Cea}~n*hdAoEy<_{X^_&R=!EaQt3sHQbgRVLrgtQ`Ihpaj0pudeiY(fDSk=NV z<=rxOv8sblSC-85cn00+LYU880$1cff0-JUSK{;e>`>Q(O47H@e3$Sb^EJ5ftzp1s z0f%ogx)q}*xIyR*T2PDYvdePA$X^!9YLqFInGyQQFz89H{5Lf!&lTe{I{ChtQO$&M zY+G5`(Jh1jUcg!Y{9tSVP|8GX09-}BlvL3FWqd9r5=7gfM50)iMGQ(#*F)tNNry_Y zx<9vwlei#;LoDDioU1@99>ZZzIWZg&+!!@}b36RGD#gr3zZO}Y?MDvt4I^g5AhyE6 zSV0hHj~>KH`oq$u;wDj+Eyf#6L`i|ELMIDVs5sJcyJ{PMaUEtdCnRFA7A=vOedbjd z$w`r^l-g>pD%>+8AKFq+E`%xfJE55Wdg_1%P88L@1!Zf!YRZ-$vPhIlyw3T^)*#0O zYcdynMfslcc01Vt3|t16v>* zgcaB}W7m=Qm9lFCKPUC4g86brGbh(#d-lhw?Yhhg;6{EtrFa6gRNMF~>(HS$ z2$h-#H{tFtuwVoB?F|xIm9l%;=@T#=6_5cT8i}>`!tTlUD8*6<#ZjZLfzOIg` z9y#73!B~NvHrC5Ye<>rq#dre~lN6Zt;>|)JMp>UcqS~&@b$UXglx^m@yA*G!WE$sp zDZGn}b5;iMds8h}$vO|8=}st=HO~o~{dW@lDf9dQ%GTOEXA8Zw&Fe8pqzNB0%nu65 z7}+q(4q%uwxK!FO|2^Q~hWQ`pi5X`0v^IwMSmZU4cD*VN^mU^;&nu7; z+2iq~7$!yhGA;3QLIOsy#6MDPe{E)%P$+AL6CV3N zCHPZj_4ek%34%Xmq_0NVS{vzH1(2qCJ%%z& z5o8AYu#k_D4Yuq620MdSr49CDfP;I?Z>1+@u-Q|g!Oq{g0Gs5-?*sTIH@7+d+v(Ai zCI+GZ7;fv2$Jr;cvaZab*BrW@f{s0

    >jGml2PJNA=4m1X-6(OmwTNddWfe?X4Kxm#L-H^q;KrX&?*kvGa@HKw}3A-iEl@)fAgatDV=^3hI_Md;1E zdIz^_23>quh7@&F7in$T88r5tna^(~eYag9i@s*I-|HdhP0J6K0$QGeMVrCKQIJ7N7L%u$3 z5z2&PA~u1{B(x+fM7{m|h4{%F#0M_KFEGVqsh4hbOm$CI-Epv?MN9h|G$?&EP#Ug` zjF8y$gQZFdm=pe8uMC4s(JdgP}GhVFDWg?EwYT^Xj}NJ zJ~|vVYyIU`yV7oz2Wl;hGCr_)Nmr#lP+C0H*c>&>!_jb~xwYKd7`6MW(9+_*(g`%? z`bu)GKo+mI#R@emqki#QOcGhkJ4{hmn4OH>WXRU?pUIRM*D@vrt>sin$%c@AP{*)` z_ZXyAyBid8p0H<=6ZUYWRv!ypwez8FH@euWrRY**2&b?7rA0={8p$eDm3HZkGsCpu z_W7tHO|P6lBp=fWlIvh%$;K)lEy znw4(-JBj8wd#YNkT^v_Vm3jC5)L(;g*N^%zIhrTCKIHfP)1f0oE0!5KrpP1L=E44) zsiYND$L5>|cW*%dnH6qf(oA>Bhd4VSE8krR_Ib|aglNv#?va~s z^7EPwyveUP`%vU2pLS3~qva-_va|fWc$05p@v0N9uJq!Y@HjIK%DGh5cbO9xzLc1G z&n!0>vfwXZWh*iC97hulVggzYoA z<{QgSt2A3tsnP~r)cVnOR2pnHhD&j)Q74X0YmIuPxwTZQgMO+N4GoG5w%~GtisPG+ zg1h67c@r|IU&wvt=eKin)O2NM4iNNS`bIWnn3bPrA8Y1c5XxaYnHoa=Bv4Gmyf22} zmtPUyg@t;UcxriS7k)+f*NWu%ur~^1wcCfGRD2xF4`Cdr`(s+lhakan<%da%bd!}V zRJB>IU#zFK8db4J=JS$v@+s0odsbOE3BB0+71ZrU6VpyoG%3S%YA2^oQ*meSzBE$S zNFJJb=uWm;_)m4E>|Ue;^PrGxMn|EcO=h)iVW2g*Ex|qR~2b` z#ROvc=nk;#jO6*&A|s_p#xtY-EDBR(-eS`P8}dzPBu~A)RE{$nQgz1<=CCJR-|Pzf zJ0z?73Vb_?cI z?;oLVH=5W^L(!xTHz$(kZAAvl+R58&sN#TaH6|^>-9;Mz^7vs|*FVJfgkjpmopgG% zaVJB*4uWus4Ls?f5;%nDy~^id7v)SxhKD(;ogPWJIi&?H^;1{#*LhR8uR~U(THoQqErx?eZbWEqOzAuJ>(KqSjFa6bb zOs-ISSXj%VkvvZs5%Dcc){fhAvE3d|(rrg-nu)MxBUt!N5e-N>DLfqs?+ek$>6GUf7mqjpYevLh<^_pqtSRly%XJ(+_+=!8Y=d=UH69e>xGT5uZh3DM-A zhHt0SP)O(Q>39C|5Y%$P>StJ}hpj=2wq25qCt0-4--n=th)&Ny2~SZPQRgW-Jxa3X z->w9T((`8c?yPtMV5gy-v5^0ar?&)VA=(sB<2By>lEvr1+Wa_{e(ky}w z<;*IX{eANDalskU7&QCo?q<+Ua%WDQRRjsnoXv|_H3-hjp}X#AotT4)&S&Fa#GMoQ zYhpy_HQaH1NB{&)(n`%Nk3}Oh5J^LYZ^?arVX=9&)+bI zyX}D>6CXs>$$U_oF1wZRaTC=WSP;gEG~Mr=?(Br`OzO9E%pf_0?NSQNti31+A z*ww}BPrbs;_FT7qk_P!Fei6i%~_ zS|t2#hXD_6_a3%<_tu0`stSSG!+Zh~ES8s;r0f`3Zmk-Kr1CV1Z-$6r-_UAQcYc|R zqhg1-RJn)r(4JKmZUS{J@%>P@8%<2pBG8nvA=9x0LpQoqG34700v_nSO7|v%Hizhv zZpoProH=$WkBiMymo!GQ=4%o?b;d74bu#JNsYlWv{uvAT^M-&}1k|d+zkuM%iGLZ` z59iGa7&V#9ouNdI0+CN9VrQHuGf*wu7cxA~@DIX5{*zif;K3WbdnYrj_z^&>zx}cy z;6awNGnRD>nOi&x^lHykF-2Y-W-;7wo;q7AXkS*HjFB|##g)?`>XyCw5cB!kDuOQi zh$Oy-G!?WIoUL;mITxOSbmUxS7bI@bkrNVg7?)r=)sVjz21YgH^J&~VEIzcxE^0(mm z#8T^4=Sp+yzCR|)Zuh!x11d8Cf9G3pOO@7XykBQNS@S)URmip8;NETPpm2{2#;r z+=OPk#_@S)zny4iEoF~BfO*3XIeoT@`*Ffhu*T7Zpeaj)Q5*iLQu_jD$BUx~xS-b3 z{?3-7EeZg^MA39g#kg!QCI2hb?M4$*%m_4P zbjdoFY`SDazJ*Q_5i2fn=L7Dq*PZT*HjVHdIY^Z>C%6(kH7D1Ttoa(@8Pvv`lM4SS zMof;=v%6ICvr_$pzyO0ox0oc9LlthiVsSfW8^^$X}n;?P-PI@MXd z0meynR^%_I&dN#4F?+AY<1<0`MASgFU@vt)Y!A|TCHVTJy*o|xj{K$fE)CL|w$NK$ zmCPGqHlIs5Bais%OVhY0F;=M_0Oyti&m))mUDfXDRLW|rOJIwf;-Z&iMyoN}?2pE( zOMrB$J0^4cN1M&4-Y&E6Ym=S$m!Voc8e5ypf-R>FF0Wf-$*u#9{?T@AsMQCqjq2^F zJ}{QdII}V|8nwo*9%FB+c3GRu-VoKJW~JR|LiyRCwTr;F_V5V&m_wT>L){zUXBYc9 z+8lykJGUGC<@J^RjhG6}O^1Fpw~i&d4K^C>dZQgliEDODc5X%eZSb92-ZI!|4v)c? zx#$LbqzoQ+hoNW-s_dp;qM?XB;ngX#MC0sBiA(O0y2Qf*j4LG7Mj4x0{vz2nRKG zc`~htY&M$ZDhPw{4iE5*U4aV5aLj6xYiy!X@|%EFg=+&5{;ArEfK87 zeoBk@Wj(}lDdX};O4W9Iq_uL{vdx<}_l<0AR~z-dMsvfmfoRh*$k|#pmh6EgNLQdl zxgCMWdsus8U@sqyEPc)E4h784Z4UNp&ES``nT5QWcB26cy%x0xNi)^<@DMaHyIoli zt7xEI9a}Ri=>eJ?E{o+Ux?gUMAcb6!%xi6}w<}x9)!K&Y5d07HJ8h_eq`y;ZxB?69 z!ckb)EkM-n{+l!QBf1d;`JMeF4lu&|CyyGlKG~ z0Sq8m^%?-jA^7e70RDjB&;tRiK=9+&0{AI{cnN?8g0q$ZcsqhaUk6|Xg8w)ez^@T3 zITXOb2;Oo8fHM)4Rsh%^!Lf?(}A08U46;rReIAvm@S;Ef2re*u6WA-KCAzgMSC$2M8{B7k~)CDgO(=Is~u19KbRJKf40J zFAywF033i|{xtv=BDnSa0B%F@{(l1S0R*k<0Bk{Uzy|>=L9p?903!(Y`v`zu1b5yD z;EM=u{1||n5nTGu0N#aQ`7HpBK(P7a04_$b{8RW1LFv-~UW4Ez1XDf(;4^ms_!k6! z_#A*gAsDy|Kn=lLz6jt<1btruupGe?Uk30Lg8lCXa1erB?gj8F1b_YpfF17x@CbsR zA^3-H0(c*ShrSKq-w-_f9RNQ;aL0E6+=bx7-ve+Hf`cCda5#b|zYpMP1P4A0pbx>L zj{^8Pg5jS6Xd*c0=K#tGUjI0NRS16h1c2WnSoS1csMt&&2!DfNS>+-#$4zK32HOW7gm0_m^6F^aO?STd)- zF*F1lDvSY605jjfzF!U7-Mh!uf&4OpPF5ivPpbujCpOp%JKo&Z))t66{Bw5a69@KW z6;&?ooWhV!1XIA;XL3?7e|+AC?^08&pK}1+7s8l2_-K)(XH8A90KEq4&4DG z7ROIxKf2=$@RN3jq`>~V7w9g335nca1`{Mwbk08`MHEF7p+9jCVNF*NF$cUThaqAX zl<-2t)Px~o`Wx4+I~7QXAA!jjIZ_rm(NM}m!;!~>$hxsa#Mh!^)lnTPIu8g&=c|3u zIfbD!o(?5A_7R}9ML8*|lhwsEah+75BJ%iPL>|)-BBizY+2fV9c_RE|YZFtp z;o3Ye7zgM0;()KscoCFHX$S|%NlRXsSsYBZg}Egdm!rP8%v+dw^fb8^=GDQ7d~ZjH zlosZ*=O_#F3i!zuCZ=q|g?U>r4nEo_ z=0ZvQ%Hp6q4+kBIp$tzQ)uG~YZ-_P$b~2a`CA>}s#)aAAPfwF;VICHY$U{0pJS}ch0HhR@JSlTle;RA^rV6 ze>3Fut@ZrRsZ*!UIk)a@3tu&`-@N_sf871wUMd!#ZxUT=)Yt(oqU@y1wZDz3L@ z?wVP1`^>E~L*1p#%C1(U(;SOuy8A(mv1)B{ycySLw#{@8#Om$ZWNU=CU)+kv+OvXz{+m#(yG*ews9jqQueL{79b#*sh ze_bnXw$|@#)#J+c^iLM`q0;oIR+-w1@M_;yoXM1(O?!sDqJl?H9$xyBy1GH6-1rU#i|33l#|0MYTHAp8w z)vOV9L)`__m0EMAyKbs6-kFTgih?FE(;a5@*M(KDF1oTkQ|VMsuC7yndTmjlCgMuF z(~L*AH!JnAs)p5iiIx1tv6|kq2>}L*>pP;xL?D5H?mR$uX?H1zR%J)CGF?>=?jF0j zQEyjj^;R^|sgsn$uSPSHvlwCWyDFq+D#@Dxo%5I&U0FREh1JPL1oNpNZTmWig5Ln< z2-6}$4LC{D1$0ph7ze7Ndr31M>oi-no8!^(+E{zEGY!HQ53PxYYW0YTV;FPS%yiER zlG_pMh%;7cX8eNXxB!&rm?A4e=j{g?5=ur}HP9I-#!8*;>DG~k#y3Ss>Ttwp9p!(o ziPoJ%1tercFz5l)HR^6uM?zm$7j{n!BUDIhX!TTN7XgDO-6A{GT?PcNn+ElaGwUwL ziISeBzhg}?E!{mexv4c>!R=)UGyyewb3B8Rp1>#*T)#fF@2U-#z~E8_E-fW4nJhZY z%6q{PN2$($+kFgJf(&5jFTn|9fv?_Dy%kY@UW#({xukz!(g)L|Q43DR?YKEvgS|%) zu)`fPDn*k?y=@Ou)?R~ z`Z#F9(cNHvC?N99eig5+L-Sd+XZKzLc3nI%-k5?7ZKk{b^d2w~;6Z!OG_1pgv{+}T zO1skB5w~afP_Q-b*~IkjO!tH!J%h`7&nDL6mB@=n0hLc?wz&sfJd2%sh7jSqp~Jg? zxv!BZ9;oY1E^8^uOGLR~b^1UD^H&})?KA!vOys?CA|7G-A5YgG$$){Pgk4)i>1S$3 zc2W9_n2=9$l0)EFp!O9eJk_tJl2iS9j?7fQZIOm#1q>W05P(6jK;&0^1)$2em{j?( zeYF|GeqC=Vt4>{;VSt|VcmcY}2B>lz;43FN6DMdwpuo1Rf(HpWErGtA=?>tg(%6p2 zni+i)UsO;fRKH$b)Lk;snVck@Uwr}Uh4JcYWWr_hU`7>`L(9w)O24y6@50F6Y~p$&-#gYjrrtzDINmNegI-;q=zNsSOr zb_7cTB7rvkT(o$Qb;&p<6}Y#wJ1|j;C&xz(145X`;1Zy6Ws#*tys2pv3|u9w67DWo z)m0x!(-H|M!TxDv1$a{Zi@@2A*p;ngVV(%^xCXUj>1v5QQx6--*p>L$=iZa=`KUR z$8M(nxfqd9|>D|gUP)#d-vuC^^(^zLhq)k$?M=Bp@#SloAUKoVQWbCwi}$STmvz7 zCT~@G>81t=`NUQ!4zs=hS&0Q{GjmwXU@p+zRx_67Lc%{DAm z2LiSoMr_NFBPZyp0BkXP%V*0!(CiAZ#oJ}_DkNtxd1XMaFK1OzFZiqvMDjVT>Tar< z+yejTaxs+Lt~~25zM5MZoXPTU2_f-#V1FHYKL}inEyhMtjU}&8#?8p+0Zc~OPAP0+ z{h^#uSAPx|4i=dnY;J?e5zr!I@G15QLdj7_G76#YXZy_n157|{Qq|RL)%Y82r$)>u zVUWVvUT-qQ&QM^}FxQ}IAn}t{av_k@T?|GPowSlI_$QsvmA@C)8_d0X2jEa0rA3FX zWb0CG73*Z-5+??Nh;V65``-o4mzA@GMI1R zlytTyV^B?Cz?8Ilz&Yvs3Ph?lMa-G9>Bg}J*qtm8F)|)cR63Jw+>meN<{?1G8>GIc z^bx>tj{#v-o@%>cV}S9ym|LKV>6yG0`(?~K+%d;=Mzl=dVa!BdrVy|q2N+ke(|gu2 zZ<59n+%oRRZU&P#!#}>=rMrk+Ut{4OEX7xrydQc`Js#3mhL&=?dwQ}qR%_4PK^1mY zn)R7Gn8EcbXhjAWNrC1iabkqB@+cey=Y|3zSw@jEw?@+!3#Z%UQK-j``pK*DCp+z* zD`dZW+{N+aG=znjj>jllt1>k`8IRWLqhr-heP>Ia)tVZR@xDS&!eeY3qx%Y*znuqvBp#kMR9aYo_2yVngV*-o=Ill&XBLGApn*p|T; zq9VS9)sMbxJ~UATx>P(FY~ORnCgVyI1IIxoudrkzh<{ZZ<6r@wTBzL!4X4||k_@4A zsvc8#Be(2WM=)=Q{$AOr$0Jd6bv)I$IgTomlM(uqV4cFsj4ogbai}VdDBPNWW?>-n zzjS^cJfA6FF(sX!Lsg#@b)an9eaF6UA`6a?q4`R=(d<98h5_WtoDoJVgbI?B;v_=i zv9ILGip|zNCWJ?+oyBZCSj4&QbhfRR(Az9;b^9XK#1EhDNKLX1I@G*-Xs;;VJ!!i_ z@GdzSD*Nm!ag<`w1uJTbwY?O2>!r0#Qze7DyIfmDlvIGWH{%`IE6X^LR@>VdctmZ+ zd;*E+Kz8f$3@l=rME46MmjcYmR+vO`8UDHfe_bwrT>-yT9{|%JvvmWUJ=U1sGYd_) zv7jb|(Pp6tPn0}lvj#m_iCR_AevMrbQiAzi7Uj19%Y^P@f9Pwd!&zTO_1z@fcHcf1 zR3AYx8_kyzoV);O&uYFyom{b~J9}lFKd+P+_ejUR96AivaeoPw3+Ol-K8lW;gx>n3 z;|@^Qhg5NlNu=WH9LLfsPILe&PVzpbjRlA)fyATYJ`R&$D(-*bFH&*zt3N9467CKe zov4hp8_hjMtv;D742Iv?#nhcKvQzVQFD;&-Dy&lB?GfZbUN9z`dCbYfg_LBbhklyW zWCVvR`H|9|nI9+fTwkkS=Q37CmwrXI?LIsQbZG`4gg!N!lP>}}eOl^HCZeMV4Vxb$ zl$1b`e2JrKU-joo`*-6OzCzH)!f9jY|7Z;MSV*4Oz9$+T<$i+E(V;cc@lvL#6r1F? zIKjc>fAe|TB}cVnkw|nM{ZmThze^%h2AG-eimfIvkx030wWV_X+sw6r1wxlC!(XJ! z=$Av6@fqU^Eqi)B507{|!E-YUv+eX^dQ6PyR$%X%1FJQqB2PmeBQ&IFGDKdmv++PT z9Ia=kMD=vNL{t<;X8J%%Ir&UZ04Z_Dp!{d-V`ba!9E3YPW-r&kB*cc4e9eKhn3tuw znhU8+fXx5W5q^q9$!aQE6E%}Fp%E;}{kkhE@lPg@ro=a&D8;pa~$DrrpkC9^B+ID3Ci0e+W(v_@z^_ z%S%b}XHcw7ALq#tY|+?mwV$15K27N2Nf%slD$WkoM%pqNq$y!eWN$))inHP%Qvpe1 zo=t>|`J-`86fCjC3YA>Qi#Ipny(w@KLJH)rH2-lA%Xq|{gn11qeQf(ARIHB+w|^^c zV?2PwM{f4L>rje7@&+UZ@~t>c;U>UpY{BfDdn6!kSx`&>fghLv7WRgnW!?`%va`$w z@E7g>^vkvXv+2%e|9=YP0?uOV-%xDp$9#Y7eJ90p-MxPf?D|AN-iCjySZ|0etcYP@ z{<^pP`P4Bx5z%ic%e2vdfy<&@ko_C|W3ufWLpa^z54C~FxASz5m=Cqs?v`%x>9bW` z`mN*oBZ*Cc?fv`ENIjUD=K^(u_%_v5HZn*$r#+NJfs>F^pxmo-ZI2`U<5i(EZO6_xIM_7OEw&J!iW(dn{nPgu z93#-Qm^|gvga${t@RM($z!(O{rwGx$7#zzK1t@I|HV3jb9>wVd*czKz5^I_{KyO9E zGLLE#m~If&T9|5xi3OORL@#21wv8uS@PMr|X=e1KFS!hpKSzEKCV%E-yK3HosX$JK zzb94@4A=6;KISVHhCmH03=2QQEQ~q~$t;Wp{vr#5ez`0RHr?4+80SzZc@{QC!T2~0 z=d?1Ip7%L4&lkcg=FQ?laeLilZD$;@x0LYJ{F`g|1|=B6H`l-tZq%a-P6BbnxH;GB zsq=GT`WQ|t{4Xg?w8g*FD@pz>{)MvboQRimFvyHbH~B*G@|5D_)kr+{rN_(HL)54+ z&ny9@4T1gq;I?}N_jSg;O)|%7V<@@lff4n$K!?H6ru(3>Prn!ubsMhfZj(F@dh3%5 zT1M2FbfCIK$1~$Dsmt3rkaowjE6YMrprQlWt#$$rQ=tC@lVA$;OZbZvDE)FMP_A#v zx@XUZU2Zn6*@6*u9Bme=^IV}i`K$|RPBu0ifmB!M0{Im5Ci_EQT|eVOVK-C#YV*gk z?VO0UGbm=GHB*9<|3cccT5}{&+rdtkaz-Y1%cP@I0=prlNge52U9yN7h<2{3W>uih zTm&5k>&yjExq!~Jp{nT29{|#Q(wQgkuU_q#?A z+nrm7$G1`1=*`1XlckLEH+dnb3!+FaUv|p@oz2D?O}Kq$xy)6b`ga1R*% z)-}S@Ky=E6x-OG#=NLy)<9Nx?&f#b)z|M~rsn=`XPT?$qUpi*nCEa!+|GAlx=v&7g9)3ruAJ1J zLePk=kyIj*ZP+@y5uP<$*|r=dX4R+8+Pi`g4cs7K0UZW!kbec03v7@!v{ODM7ea4+ z+90JP3Kfdj9~sAKf4rE(Xx|^t6$-I?$tBX?1TTz&7phYq2d_T*pO~Hl#Ro2_9q`IZ zeK=}>L#nw8-b9H&ZC==HLjDU@tiTg_?^F+al#-Er2+0{t{+d&jZ#^L-nE7%MwqRke z_e)6JD^EF72?U`Nxsp=eh8YN-has7P@CE!u1_J$Z7zlj2vvEqD3j%=$%~==n2tHJIu0d?Bz8lCopUS0D$j#+{?3Y$g*j z;Z~~K>zs_| zl$rJ}no4j^#vR@pl!aS4i{>-$=^qpT|yij zFL$6z@mcPLlBI#C=1iuBv{`!6msHZpSCNLn(TyLO9u%fxl`rG@AM zmM4yhTkF9^(5zsx_=OZZ*upe}8Xj0AX26^U;!n8%$TB-@iSNkfx6D?`w%s|$kkl$0 z7}|Q_w&4g7XAYO-CODKzKjwTWH5~Wdc^3+k7k=q@4ogg|rkIktqV9)7&?>+dOSs?u ziBw%N$L7QA#gyo`KB;p{O^S`;)@yo_R9udr^nJ&(eSx&Q*^=Bo!g?bqYL4m z0b6gA@GU6xX65!b9NnyUdGo*}^(d}k)B#?tZNW>0?J7(a{%->A@oVg&S8X??li30@ zN1AX zzWO$fqIdx@2*5GOq7vS2uwf1YfhGTU+5XU(b%|0Ub3jitFr!`>ptejIB@) zPDSj(h4born8`C#-OIOHuLeH5BZ~f8t&fy#yYJqI{RJ6*@e71*lSj~%mMZK_Zz<8$ z^RUFgrk?#ZWc6l=gUlwpM*24AGNpzvvbASAdFOk{tJ(t} z=RhL}GKYK@EV;@*fc4X02_GQ)bucPX#aa14*nC)UjN)u=IF;#?PxvRM_!+|XUHAqs zjIVCI_OF9&C-4jt-iNcU;?=!D_zy5}v5E0S=0r29j!b3XxZog zA~vTWIl0?EfL%`b02VpHlHSP4dyJk8&h<@B-bvsYqxo-Qu644}@I(&%dQ<-2&3a$)TX3dU@a%-9iRyB zyE&O!M(O9TMMr-#9`B3+pm-0)Sfka(6pU)+X8!e!F@9ecUh2<~A0F7=flBpBy5X9> z!?6oL+W}qG<9IwCAAx{EtzD~3Mw=Vsaa0?RD-^8VTOa9|-rHoQ8mGJW#|9aGry;}1 zkKulHd1UVMcR09C>+>jb-ICY*VS`}9Qc)Id`n8V_KpPCI@UML!W~NV2J(2O%p1cEx zVqg16*HE%c`L+Vg2tEJ#A5~O82g^}YAL%51KA1!#iho-1F>JJ&yC^OL`Yc~pOkQo7 z`|C2#l<4KK;)uX+g);XUWom)jgMFe0ZobEF>F_s{hV*ZSYF-OYx%Nya{U^bst6vU% zHMGinIrN9{5L6yqnqvFlE0$_U%T?Xge&Xar^D4rsG<#1sTl7C?Wohr5VM8Re`3EHZn{XVEg6p_{}Ei@aTmkG*~~fbsmZqqxL#^p^P8>!VCYdiAl_ zOAYw_AaIRz5jM)vNQ$aC5zo$=kb==sL+bGA#q`F! z%y?w#d2h#>-UvKYRjt0({jsLk$+r9SYm){)GLfbgnF=h^I(3=)OsDNrUfLWXrbnPrXo%@c{sHWM5I%q< zbbuwQ6ssX7SaFPEixUaUbjp8X^rWu`)s_nlG2s~bPNW|ac*bb<&;f(Nt?|_m(?_XW zC295mRrh4XWS+eC9e(M+EIUAlIB2Sip;4$v9O)mxE)skIi%4LJLnM|;tcM#rn&U^l5&G@cE#DgCUE_% zF-@KU1~9G1cBP3oWOvy(`G{U?Lsa1+UrWNZYNI~IEqOJpwtl!)AHr44U8`)rAXndO z;4zALu50!DtK)X3S%;)y-0INZ2bYjk*fk`0Ln)e8QH&Rmw4$MQTyHg+6Zmnv_MYh) zeuHOE`pKPMbS0Nmax1bPa%_Vo08v2K?7nA>|4H+9E7HJ!dsqOab9>hOQKMGebz)JwNmUcOoG)&;i`K%%G zcSiSy)>m{CdLkad+Jni*Xu9sIs?EZ_WpDXtJgj;!1HP{6)8tdou@fx#MEqbPk(#$A z4=9I|E(7SQ?ol2&ky^xCi_c7DRI0FD?zy+-z^M3s?xU)H_uR%f8j>ali9fsSX)12D zDm!BKej8WAO{Rx!tH5KN{Wr`)CDAPbP9`RA!Hd}jliv|R;7H9%JQk^=m^szSC!m6i zMktmI_be(;B=hJfb#3&={8HgOR zZmD-{zEDWix&f6rFI9%+Oa6Zl_x<>D$260CZJ z8VrQU-4^DR+!M3zGA37EcNt0^bC+#LxgvKN{py3e?Cfdyq!t8Z8})LIvh^7M5sGL; z{AkHvqn&nb68;pUly#9^AbX%R?M)FngF_OuAOGC!=Xh0>-(R*%w(Y)kAI{B|%*lAl zmMTTeN2WZH%869^os!n#-mw&?O`r z;!R#69B#0Cp;4&M<3axbcAp0yz~b}35>?G9ZZMWcNE@+fr^1ElmPE!+8GX6;1a+hJ zcsfE886P41jN$A~4u*t#3sOB{uc2-g$>?pe^^g5<+2{W+Y))x5;k->k9O0KPi@)^` zU>6lWfJIcW#33q_Yw3^_ORnd#1NEK^&M60#KtT!2^;`_&X6!#7&PC)Tzb-n%Y>G;E zh8-nyrs)ME%l?&JjY{^jE&`|Z8fj&ud{@~igm+k;^+o=f+J%)5kOjo1p04wcP+aOl z)l&urZ_;bkKh2^*STcZb_Ky$%M0xLNF)Z%z&$J*GmIUCt{R0F*p?f{LfeFAF7(5BU z5BTTk10h!@2`{xxEv1cqdi70I$HrdLFm5e+(X3w38ql3$Zv^6LohHU1@4^~X!rry0n2`2<{Wt|T=}7Zj$Wv+L1qYPnEi^J{|T z#koL4_+*Bp$QnMuqHq$TrfF|dzsw(J0BK}_J*a;0O zXo*Wk#51rsMBGwuP$Y%hghJxg^;QFcH+#+(_*diriJPJ(@ZK&(nB->x%ZP_b&?X8D zlYBLxR~{x2reLA0VqxD)6U`DPp?%03CczpkO!6oEMPU;9)rT<2<&{pmF*?Q!$=1|$T`~H162IJywCM0u&yC#d!xGP8nNgK*Z5}4uvn-tXKMC`^0 z*i>+VY=RH5^i3eS9Htr3bWe|WNZzDCH0W$ELXK$Alc7;)H0Uz_0CwLHAHd?`#}dun zNNFAP@PdFbQ#-(*@wU-rsbY+*FVGT6)ZVf4UDw-)3C1k!p#lb{d%IRcN>8G0m5>rC zO`lrL2;IS1Ma=MD)wLDrFu%|bvz@@(*rbDEPOtP2U>8U}fJGp%KWwQC%%LGUcr z?>mg14Awe)4xZp7jgc=%Zzb@I(Y!c2U;t;^Web#Ksd;A$w!<%-%b)hr>iw99pA|3% z?K2;X*w!y5BL388^Hu+BN_^^rO|s;QdxFnQv9C7Ws1elCYBP#-%KzOWCg6heuUZ9pi1FkHfC*87-uD4?jY-9nL8fTdv?w`4^F>Rm3ADd zCt!973?71`@pw9BpWtr51@&OM!$;5PW$c!WvCXOv$?fDN$mzl4MZpXg0k%1MbR$MR zpHmBr%DxBE>&r!6TLfAWaJw5Dt>#C$o(0^Vh@un?@so%2MUZp1BIJy1*##qP9}Ff^ z^-LrY2G zl37X_SR6~qQtwpPQt}CpWPP_(b68O3O!61hB{{%n7L>P35lwtYz%u30L^SvUqlq(A zHUD+x#q5>ymN0wd-x6S2Tkk3)sQjv_cVMF&`&7AV>Xc?Y)|i@tGYx#;szI0TjHr9> zNUb#**YUH05!K%Yhz@5mqSj+3FXQ(Lus4QTyh(c| z@gQb@qX>E8F!EJw6wd6z-iBWVPpYi`>#{ldHQ>*PJ8tC*I)E7dll*!KXE-8Ph~a*< z!gB<~@wHHnfN)MoMp|+Nz6+YA>&+3s8Z1ZPxI^F<1S^s#LvEOgEo%{`r{J{>O-PYbPH8rCz8D#+CK{z zt6D+&g7Am-&ya2R?VFpktfqLm`stf&6{cKQX1HrOjxUuM6p!Mk_$8NMH%1iyq(C|1 zf|JJL53@Gp)zX+WrOA?6zGYC)op^FEo16*GCE8cwpf3HUiHW%^r&J!%!d;bDx)1Zzv{r4q7Nixv>h~g|)n6 z^?v_MN`zzB1l=31nr3i4VXvea;B|kR>dvgC1z1BYBld^Bf3kTH^iRQEYv2>PeGH^I0R(wJv{o(4;_MWw9lTZHzQ zcZ*?STxYb>g{o>_+5Snu^s*4z6!8xK*a3^T{L8M4gj^vKFJao`C~cf<1a;7l=9fH8%JgLJQ7p+F82|3d;7F?i(+=G%X zGIB7vGnk+3{JW2TlO=1mv#bAJ!pYn#A>TI^!Bluz?!`u{x!vEhknf4o@=rbb;*|}& z`45XBxqz83deB#~{kfxFc_QVA+)5t~CRlaByck+#!oPnF4;|rOEYg&vp|SMvZ)(rqQ}tp%l-48qsh6es{W}$LEe9Yj-Akue_rB}@y};qaroyg^$xL#f@E#i zS`0eF>?u{MuE6j6bAUsP`P(`VQB{B7_lam+rveRsVJJ%6X6cdXT&sM^VY-aDdF^DE zh%_yLt{jq#MLm<`)kbITDJznE6iv=uRh8uAhrp81pzSfxu@f4SWQj{gk~6S4B-v7L zl|u$nVRqF3c{cmYm*;so@MYxL+ogyXy(eImaL+RC7J;7Sd)R`?{WQr@>{ZT)JGkQU z)bT1T(W7{@!B#~gO*_I^A)(|^r5mx)>f|*rVfYLb(5HP;3DgnW-N6i!W)Yj&x#G&p zq=j8DPo1^8oF%I{m~@Iv6t9*L(_0LJa}zZ7r9Pk-aE2jmK@8IdK;EIE04Q?#cVrWT zKtA>zd9|~K#D%!`iXxy01LiNWk(_;od+C0ha_c^9!nj4naux}d3?^?WG7*(KOMp9X zgvNo~!MPXX4i1oV$G^OJ+(y`-h2l2i*dR?qOWcO^vo~&oHCWu{AAnL8x1nEsh})dU z?~aK{f0T>a(A6OMFLY`nm5tZ5v|fg$D!Ws~r$%Rn$yg2zOyD)cCg~v za=(CcxPJh*#QGs z5TUQTUFxOP>$CQ=0_IT6XMKZzCMA5MBneA;v!L!VdNM@3Zwu;G1fDUPeL?wQD6pXZ+Dofi4}AIabiONeIHWq+j_5u&*FKfMo??NpDur!o&5R44E#xf?l;?KX_{m z{>NVT&VN~N9!wx}zOpYRKOO~^(s5p*y-O)~4#k$zY5tj%SW0YyMV3;2U5uyN%uqd^ zdUVifC2J@xq;^Jh@)|ENC8Df+lzf4F8VRJjthWlYcHUNFmJ|M2+LtvSAPd9-Jm?uC zwEZI#UY}hyNH7c*<%9Frl#gOVxWmnVVYD(7jTb7%B!a`uulJ7~0Al%Yb4HxJ*I7Q~ zpQ#t6tU&4RFgl5T+&@476z1K^c&FWL#YsQexrOK}{@HusnXM50*gtjvay=9x&&|}o z_s`RZQSMG4k|J!ILE1R^Cip4(kreS;=oh@<)p77+GG7QKMSPokSHJ@BzcRn+B6cBl z3?EHY-yFf0<|!Beuc5(b5*uUqR{cb$K8By*!S_5HGD~7MT}U@ba?}x^LI;y0@E>r@ zJ3JwZNFmjDBlTSJnh|df<0Jxa`u~>vx*~Xrh{IZJB;^TgQ7v8sN)!Bh$*Z$hG5CYa zS80B+Xz02+h|*TjmF&|I+vs)qD=NG3sww_XF~7qwZbg+=tG1&K5h{>J%&$P%WS%!Y zxx#R>@gRutR7xG`|BHhmQsb|OLaR)Y#Rc%t5t_y#Rj|#pFg?j)A%P=|EdG~1?QKSf zhV`JY6p?80Oq!s(s_JAblxQ&u9XsKn@HE3lCljnk&Y_GQd2<=^IR3`AuaB8JD6RP` zFDWzb3k$%SG@){6)c+2sTO3xeJ@v*i1cm^cn`{11nUUWEjWUN}MYvUo^+TJnHIj!* zq3ba;K2wH5jx88t=I2GRMAI3LybVje;X;a3YL;%XcCcZaW2ZKcD`)Av9F8hE9_LV1 z|F*JsGV%V?V1-+SI+v@+U-}IZWqnf~i!_GMMw2Z&Qt!+?Wkj53;w^zjy;*Mhp(t4n z9Xp|+4MO6QSqB+d9P7YR&zfqNio3NKq}uE$U#fpaT=iqjGx0*Cx__B?n}fx|$u1$u zPbFcoN-`GpOp>oRI`gBb1%jT93bU{e{1Dgu)?hivZGyJuAA$!;`G?@~S0A!q&uZKpHzzC8(G;X5q(`LBEod**BR&HHekrkpwD zMBXU!_hH?^LKv#X;z9Q^f#dECEE)Hf=)C%#;b`|p?aw`W=^nN8asF1yEg)fTJ?hW8 z-7VYBA#UC#nYUQ7nW;DVx2|aaLQ+{g$2LVMxf8oFa%?x17aQ7Fhm`ccC zfAH6Aetgn@WIx`Kn*t61>L!;33b&P)i zJKy;L7U9DZP54qhQf_@c$>`7kK;ePvQ1S^!Sa!$;hM|Q-EYU~|T3?qNtqeNsIQu6N zy1t&}AG!pDVe5;{-dHp~i8ZP!6Z5Yx%}C0wuRZDh1wZxu>vlgj_SxPFjY8MgU-<{H z^PLZ15k4%@gm1R%>upAdhFmH<=s{gVh?U+4ITE&*ZK`eL&; z7L8A0jjGDTvg<3qE~dEKPJw!gd*NG&ck~*~&~G4(!N5L;9mhx{blONyK}(uoW%nbY z^JQqg^Mp=z@TR1}4nLzn>>-=bsoV%Y!hP!3Hal@to0y2U!r^-N#%&Sz7__2YwRSby z3MR{*joV}nXVGTTh)KH0PPpzWn5#$}UiZ*Oiuff`ys?iv7*gU+OMwM+B3%Mfc!8t8p@~`( zE|f;HHbwZ~;iv^S)7KfL>=Ahjv5arvI|Yti%HYX&%8Em3Xmu&06mf2?yShXiOzBz(Z?hz#l4FuqRD5m8^gPJe1JT0F-qMW2bqmBmf}EK zLkN@lNGI=mUh*7%nr}g)P|NX`{sHV34IjW_R$+-|R;8BX0=ewWtYfgxSfNh)g4KFo zhOwm>7J)`18zkQ)wjT_f*#+z-4?{xN`>Os`O`fkYwxqJMGNYa{!m>=MBBVuorbBj; zA2K@)#}m2gi*;^C^ppGp*u{kpU=bHA>6N%#X7sh!#N{Hw<`JbrEsNuZtG4O_LcG za?#b-e!SqEw!x_^cEdupk)DEaKTYxWhFbnTf$ zf<*nWqje#4i-MDzB9(n5bmb6rEb5`CuQj@JPg)W6lW2PGs;a0bzXo1~zF;;C9Xr7x zQJ2VML_GtHL)0zxoN_D~>=kvh$9z#gFbBYlsC&B<>Fgg4SU@}v8n>399KgZkezw+f z6QAXW2l+~oe@hT)l}r~BIG)Bng^hA{LdEU4l5Jk8LB(=d;CN{%k<+skf+D-U$b`X{ zIG8*)fV-RzNLV30_yvI{UkcNvQ1Yd)SS8MuD@bWAd;OSLgZVMv1*9=QCjGMcF}aJc ztPk_4+iUo>gwfW{cvm^U<%Tf7r7})gU*-8qA4B64qpcXdt(zkL_42VsGag~jMy{bE za!|s%=hJ&eCMFw|_UWf_pTJ)BRDQ}U{(ev8BeHGx{(aa}sjw#Fom{3BGLNM8OsWsk zZeNxZ7xzM@XeD35ZVWHv6GNnixrS2DQh1{wHTO>rC0tEQ(!8fH3q(zZM!=esqR!fXQF znhZ$yrlYzwzfW9slP2n-pUNidx}R!!R`*%l#YQb1_0xNex-nWl(i?3^E5}E}g=Iq} z#Xk860Nf83)>n{m+=az74>?Fa#+OR23+tTCmC3QrB;Lt`m!U9?89{8ZHdSdin$ZOO zKkm^GZj@i|*ipMVuG3Z9(vdaWZY1-Qt;qPno-j5iHb+wJMrruFON`pB-@&f0W5UaO2Wnmg9xU+b^o{67Ag$`o9YPBt3y zpBphty9?TJQyY3s@X%sYD$pX8ja^JOIz?n7X<_Zv$qxMI=*#AVY&GB~!9I|pr2xqh zmv4V{PoD)`$&dHnZ$H7yA~(Sk{9621lFk{v^bEGDXgk-C{C=<1kuIHXiBJ~%QP^lTKMpz~K#JdM1vkBf zu_dHB^E_ourU*DNQe>*cfs>&{=0u^`xe5o6q#koXT$+KOJrX2q&m_6D-(6mWJfU_k z!A9Yn7^qKcZW~hG@9Cb}k$z8GFgqn7+_09Gt9BcY4w@U0;1vQe52W znWB|^1iP6NPR}oS33fO=zW|Lwou1$G4`6qC@&PPPPb^WzS#kAx9EoJl%);sUpT?;A zB2tqh)orX_PS4*E{Kg#Y$$1P&_x>RqnRkP&^q8$%#qtq#(dlWE^`1LDk2zN7wL!5m zwLsJhJ3R+s20n|yaC+KMNwH7f3IO-R>G^SF9Cvy$%|kA=`{6Mzm7X{~QCBuv;6rOn zkY}`{)6>_D)WpdJ$oRqJ{9yhg^>f7O$u=VPdd^chfxw{}*j>Ue#ylTMU3t`PCm!B8IzA zu;NdB9sd;wLzv1JXa6x60~GLI$cA$bhv^ zua&sqPkpXG@y^u?%nwaq7BM9vpb>xS1OBIXKnFN%s3PFx*F|@1s(jLQk+w`;1as|& zqVHc^WSW=8)J>h8<`kDgn2Qq znQ}dS1oR(uysov=V`TS8f9J{D_fNNoN7J`b@F`nsyh%1IiTW zE@T7QOi9=f>oa#GAD9PL&MIg{$MXbPmwXy~U15MegB*PnGDzo;tw3UjLXcykqLVn; z4E6Z^NQdK3a*->kCnpQeQ?_rVUT?H3ZA>6*sa71~-jWHwh1y6(l3b4C4c9Tm%Vv-6>mzmDn@fTh2 zM89mNGoLEh=%p`sx)_py@xr5tiP6TyDEo+I$=jVag;~Yn$UY!cq1OFw4v%=w)39j6>5Lt z!7kah``&%{#A4%Y=C!Ls?X}o0V=t5nf_9ucB^Y*t*=MAtKqhx!H%3mv_}&mhE`F(% zx1sQ;yo=O!T}WNfW3UeRUpj1W^1|jY(C&psp_vU2`UkLQHt+!~nGIN?o;(#xeJ#7d zK4i^vq_VjV`iELbus&ss=-zfz)5DY1Kx5>;O7sW=*@6L{>y#?Vj{3P@YLiRajeY2?g#}0rm^AY4O8z&S!-3Iq=PexT` za;kIXHB8GI+ioEP(!TA=OTlT|HSY!g3qO+fG_{vNBVA#+uj{+VKY(3K_yCqI2TQaq zCp9wqwC%pv7}3zU3Ojqd?Y@hFY{39aGz@~a-M=?l8Fbhg;h#kKw)-{z;Ke}<-ga{- z2m29clxYj>@aS+pi_7;Ta z`AO&*gtl$>8vob<@Ri?onE)Dlsc(BSsw$JqZoBz)(QR)#o$FcD^ieHGGJ@rUTer*_ zPyLhJT^b`_5_iM6K1VhONPGdnMt6!>(ge$;AK{8FT0}ft!Mq{lH*WJ29Be-6R~*l_ zd2NK(?po6)CmuY$9=A7nx$pP5-7DKFj-vE68oQs0hf3^)x}tng_FvqIWu03ZX(h)f z_)-NEq^DFo;AU)U39sM|D5FAZ`31O_KIJ9IVZT2DjY93*FZlt#NG#m2)D&BjZq zU1H#n^?b~`);Mnd#OQ6-#siFyuV#M8;ImMNB^q@>M%bT>Rt6Pzi2akWTCldQZ{>;l zjE%9C-NkhZD8KbF5>kyz;UfFi#{|l#s!UGZ`aa6oW2`ecaT@ZKN*+H!ay?=_PoCz- z$v*2-pi$^LJKsNmT?qI97D>bsO%hXTORTf&joyk&iLs#vt+Q(xd=~1kM58Wfoi&VB z1{HRQ{gVh@XSe&uRz$h?>x_|LEFPc48da6aW!G7LT{JOmd*`f7%m-$Try-GnCg%Mx zZUGb1Mz@aGQ1VPniP#GN(PP}B`1p0WHGI9gD5>CI520rBS&o)(N2xdCpST4g*!12U zMzP_}srndPE*7_U#c*>N-j|OCNt#U%T3wo0$rq3-gURQDnZpwa=3;o2jP}oRNKw=Ui>9G6}*l-Ql0r(r=6kI3Nt11QZ5ciKV^~gnB3Q0@Whu3Iu&sH~YB& zEK)}?!yKxXid07Qi(*4Jz9b04YOI z-*l5pp>APZyZaAELU!<{E;u)qAut43?wJ>d1X~dPrZQvKp^?v`P=&S-xUJrUdq)`p zL%>y?_8ejLkzU!?92O6_y{Ro%Mj2=wp=P(Qje=VHpp!5Bxs{hkF*P%tZv8+YO zzS~p4r1a-jYzStrb8i=)$E2*68Fy#DaGfrLtKX!2aTx+bfDJGy?=Ca;OuxXrr}yB# zw+w+H;Hvgxu1WbwnOS_SUoih&?_vI083IFKPA$kBlk%r!X7I25g7{~>hj`u^eZz8Z z8j95u0&%WMd2pGLS3slQoIA57<)P4b@y*R=Qm!pSA_v!EQeuf_TsTZhOT8zcN$Iqx zQk&9W59~g(?|h?jZO&@Q7?s{G#YgV`2YjGDLBL-59XRMN&3U&mc@DE`e@az*b_Y&e zi2wW!obA{s$GfZe?dcSdI_t$9gA^1I4kvG&l=`DTjmBij_dPEt@xEtf=(2BqwsI(#+yz2=->(ZHd>+@(o?}b*&t0om2#b!Pu zp(>t4m%^MpirpA*f^IA>j9k>xbe|(!eejxTCQLy1>^ojs9r<vcxQdrNWM&9JnPiX|GUL5k~P zqm@C29dG|6f)&@N{9`Ku-ebj;JO3c)zUiNS@1V0Nu3z}a4uGz_;$r9-+Q_%^jjGDz zvWhFeE+&53>^(j4b9Kl;!m_{87ddqsW!1_0!ZMbKLQbfd(jfW!>%lOvt~a+z1H{by zS>vCiT^RWQSr{yq+8O=x9iE4&;1V;9FT)KcS& zcF#XZ;qCHIzjx4C6y6>Fu>+thukf<#5I)k&Gw{qLg?s(;EQwJNdmik|&_T-K5&zHu z+|g6`*ikW5Ipppc;?+#swvjeY9s<+3AFpOUh9)^ruxIWG%JP1gpEPrCk_^q5=Q0^u zUG8$pkC1(X$-e}15vjpX(#&a}7BS&_oMzDBX{!BXelC0_)gF#l=rxPLr%UcmnQ$NB zZXb;`>TS5&5^q`r_a0`Qxn0+9R~Td=hJ6v@4i zmcM9N-}{YSTv0d}XX1gI`PgVR_Yn3hE&mK+r%0j#ZVVIu`;~crY%t|&sPwzQr%dMk zYUm2&-j;cfMVf78Yy(>UP&Xh=>U5(+Kg0N^N=~H-x~r=8cA?DsGofQAJd`HIu+hl$ zrb#`m41JsdUTn!s=9=ANmXDSh_l5$vCYM3w(9HV^)GdswKTT>^83IFqWwtX%*5+4z zX_=8<1dV(FRaImQL3?KzXubKgZz@9{M;1;JWxOwn=+QX@;KcDtY+zMnqtz|24CU~G24q4v9@~6yx-hkY#DV>W_ zq|APn$g}PRSfnx5tFHp~f*%+ix~Gl!^S$7^G(mUO(hKW{(6JL9+6x#q;d{aF%h1Oe z;Kep)FBn*-Gs+E?g6m>v)E9+y0CZd!SN~pcTp0pGfX&?tPAxO?DgA=>NoAn*?gf{X zp^qbL*$c2lQyGrEz*5hj;FfL%{(5klHT%xr4gNky#bkB^ZZaILsq zG7Ij!5?OHixMfq|rhT;VbRly7K=NALHuK*yC29U!rs#3afBS}aG5Pb~{#mx|{`FkR ze=~){_zu^ghwCCN;H@Lo7^S`aR3cP7?JY$&`3ZL8NPEkOle|POQ$hp`DIf9@X>YEY zX+A|j+S{MJv^vt>{u>(UQBZgG$np{0?l3H1d-R15U^Vi@pnqFR7e zjl`ql{S#IEm+HC3llR63$&Z*E0|S%KZ=QL@0hVaQ1_hlq8Lfg4_fG<*mj!V?Xix*g z%l$(a$B@RDErhzL-Xb(YCS!2SKYP2VmH^K7vUtZob^vnagQ<)J!z8k2kFbSlR8=OY zW{>=iX^Cvwn`@n>OF1Cz?KOVD?9-otM!Gb(71#a#0qoMi2e2qEEYa3-O6@Ea*GG+> zjrFc@r^kxxLkvv|u~?!J8>G0tY_u{6u_NxEM5yBWk$>po7zQe?+}Q^K_Xq#%dj_0M zaUHl`XSKn!0OZOmE{2|=jeINLsH#jZtGM#(V%nR{-m|5>Wpti?e#q{wHWTHHSz~SF zbcC8Hr^3Lx-gKwEUFx5tT^RWQVK7|pA3@=2j};!DrA6UkNpXeOFj^UF#|xEX5}^w3 zcK^`DF$`3Aeh76Lb6aY!@z1_zz}Xbu1OBlCkSnk7IC{#a;7)t{n17xnF;a$hv*(L_ z89J*REW!8h`-cwTj-euHjQkS_<4o?JA=2J#+eX?r`6n=)`;qqcGc?J0+8c9EP{!4l z`JwvpPkUQ*3h2?nWC8vYbeAPkgK2Mb*Of&an8yhQ1(@c%y(~BVY(UL{8R8aKz$ zcxQSNZWC?CEb~p=F}t->uiey%qnj&}9Vlu{&^1vTh6h^JN;4kk&xa#xwT)>~+$-{D zWhTY-duGyommJ3A=a8cElN^jKSk_$1i@lIFcT$m=imbUOVx!gE!Puv)IW$ zl{I&MFy(5U78WzAucs!2>gmX<;gk~Q~dMu&#Yrfe`6pW>Mk*U|*t zRaHB+P}ba^L&r{dC{u!Aqmk*&nwu^|A7_BELu-R_pQ}jjvN&LGD>L$~1&~c9p>k;6 z-1DJsVPyTe60a#kUl`s_FZLw^=3+Zq6~c;S2#wQ zS#wyTsSHP^gryz@!DpW}XZD<0hOVr+vvRnFx`=1Zok>-TWX)N&f*xnh{nCKkttp*L zQe@5j86*OJ9+kklgo@e)GuV$S&)6z?fb#~SMWb+jkqB8Zwi~sP#S`9&Zcl}nQ@=qFNB|A zK{yv!@1`(WhCYs~WmCWsO?Nmp1xr1DTAVz)bp7?B5gOzeXr|o|4+#~m)BIHo|+y|kBZ=b;} ziE|0bF2p6jnDF#DagHvOJ||pJk_(pfIWptD>2p|vrO*8UNMq@9^s5i)b6d3JBglM< zOJ>cTSt4tWhAW#aSF_BV=g48d?b=j4B7T^ua^ksJL1xUc>*07ap2M`4Z;AVF@0#&v z$^A~Y?Y?KOWXW-1Fp}dA&T?5~z}Sl9enhEo0~_^iPv1(0s@>|#w2zsIFzWMQyGkKU zmSQ(XD%`oV6}3!a+%Y*l@&;+*ML>RBc1DYboArynpzGbCDJ zoJ*>VsA#Em`VfQLf(DjoXecakhnfGuXk}1kXNi9j!Rz$f{;>lPEx%3~3C7~{Nw`r} znOt_A=GVovC)?hxr#;D}M!Id7t`DL&YHfPZ5)4>$sxA=*Zxs>(B{nqGX@3})Vo8~7 zY%D1*q^pfq1|fDK^-sboq?TNW_5PuYV;GnVkvsdK)xE_(`#X5CXB!+-E&)9f=z=rAL1;>o>0iC34Wm*iGt z;b8KdU``@6m`O6{j(Y_BZcZoYhBSfX`utQ4ErA5TPfS3HFB6-ekgmbkqtPoM4v;tG z50J?P2_Gb7W|uMZ&Z5jr?!Xo-t;2@U^%3~+&yU9{omLz*>XUnb{5`E`tWt-sWkY^U z0~2E^@NMUKN2OhZ+!~%d1E2GaoAt`%eP1BTkw5g#*uiU z(wS@zumMJ*Ypd}6X_4nsNxM@gAg9=_R@wuVv9U%6zC=xvn{Kq@db7n!L@MS3STTFo6iJxfJ;DtU6Eq3j8f zEwDa)Li^ER1k^a|E@&lVRU!=iNq9(RWcCx}S&LeRjqpJP{4RW5swMMxMq{oRGhn=R&u3Ivk%oQtSC3NLjAz1V{tdO<`h;jXH#kmT3E+Ry~FVd&TiBCQaKU}lA60CcPnOFe%STB?-%XtmjQ{u((j2g=ME z@pdVq)gKO6c{~n^n^|BS^nSKTZvp#p&FwR{&J0x-f|jK#!){lebr)Y9w>!;xOK5BP zw?vYZ^K>E6F{63rHTYQKQ|8cS0a9;-mL4;j^Wkw-#B`Zo1c2}AKKl~M?k zbFdpDkK{xYk9zsZ90?*%hemMrQQ{!(!1I`Y z0DByS4`2zkVu>ou)s)(0e4+V+by&&RtM?dv>IMpb2UYDD=8 z#vWtM=^Ea?=F&@+Q4%&9^7d&zRQ8E~f=xz|1NWNyvVQ=(9Pj}w!iXiBF!o^0{nY5w z5LJaEE^#qZIzrdnj~I>?GOQ^DH3=Jq>XZ)Ff-$J#%M;5B!!f9wDd%da^`g0YZ% zqH9!DCYN1v`E@ai!?v^PSsVj=OGs@mi!!t92xrY2*pkwD1`JGI#Z3AJmK2xHtBqDc z(&?XsRXQyv#c}`83jYIFIE|6Nsj}JUN{~oEunAGxI5`QFLO&7^&O>Es863j)UW^N@QAjxn}AmCrf=>+Lc6A&K3V1Ha0 zt42HHJ?M0#->5H!2Uxs1QW6lN+60EToAF5yac{seaAE@fsE@_NQ3IdvszD5$H5;PAZW>{CgLA~#u`0bh zPE6BhVXU{RVJvce_zz`=oS_Sro4rmBiO}#0=*l6!Sky!D9WuIePg)V*6KHzws;c-V zzXFbghJ4pT$4+oad?hj&@y!6^5MN8Z6)3){0LUfY%@lzEn?2+U@Bul1WdzvUr3mbP zC}3IexC3qjfpLeovK7>;z;3;efbqcYPHdF3YbjRN@fS!-Nn{9uZ9`XlNqbA|JVA9+ z{s&bDnRs3iGAU|wOMpyp?jamK=AIVx<=dO~OhQ1r-0O>wCv1<`Vxw>_DqF3wC8NVo z-&bf-4+l@GtU}_$`c=|{#2vRbgvCt^e^-7z5hg_B3NhTTFL;%Rtj#6DMFF(_drSI+Z6wBlQ?8b;Ho?cGg*wIh9S?by(aIplj=p~qz<7&EVTnOb`^Q#J^QuYFn;0Y` z!Pv>|@en3!Mpb2UYCL3+u_ui|@)c>@EnF*79(?(VG~@vXzum~oWXo8vQpq{MAzcKnZL|EaJON@-@Pq7vGeuk`ta4gXXSI~E_$S)YJ407z~ z`zH~+BERP!I{?b^5lTjavCMqJY*bYymtB$hbumI|+okmg<>BeR0Cru*y36W4RhIOP zb?K9J=`i@Lkkc2jT?oUI*DDjc#FFA-8yT$(a_nO3pM+IxEuqVe{-KK_85p|Eoqf=H zzr;WLo&jge0@~^yI{>-z>z$#OyD&xI*S0p(#>sEtu+opf?+VoJJn+jbcZxs$j-QQk z1HWsw)av6D=1b#;@V0MzR~*CJwGcBDCl(p}E6_qJl;k#K-a1XtmadpR~*&Ch#1iw3Ue z$F^t)?=fNjnV4);+H2Mr!9iA$S($oxP#*QTFH-)kQ~h8t)vC|#+0ZHzB76WI(r%Lt z5n_?H-58sw5hA49TllL@N(8zb?sw%XFuss|)E{rYSY%icS@3>!AhCIu{NY-OV zoPXvZXO$lWUnDcT!{IfxK&8@=(!G--0o(}VB0qPNbMR|kpAs3J0I^+M0t?@ ztyI+?q(6nt6TDf5Ox-`m;9Zj0`n`h zvv|7{*)#VA>{mSh0*_6B;rN%atu6PgC$B-^wuAgz?#pz_TX&Yu8n@=g?UiTGti?t- zr#vNl=7?v25={pgTR60_ z9j#wtG;^0sILKOEFp@1^&uhZIxW!z6X{x`yK3#~ zDEfa#F;lYKH3}D%NRG0NUN%u`TRvSlT>h)^lq7{(b1T-@KTN-uv!j0P)d2qNs9(so z-H*?pfD7@1PX<}zCNc>-$c8{>XY(f1u)8~MNQk>Z{F386PKs2=Bg8CH2Ib7V;! z42@vBQlf2e3y8`2d#G1T4`kfHWtg^t}w5j6QYlmdK0>eMkIshNFc{EYZkR zuy$u)Jl$wz5MsyLKMAW{g0Y#~GccHB8C8|ZsTmjtGWMi7 zQFIr|?C)iGu^%e?#GlV5qsW1K&CU1+u*(4-z#@!Tq6uRU*4zU|pN6O^9C3+@k^2<7 z=I&=WTFAr_jZ6h=_nP~J(aIpijlf za=Y3;g2KoiFV!pz?AAy044C)vo#LOQeHrorEV=+oitB>&dp`-QF0iDMUF#pZIFkZX z$ryyW>s2H}*_LeDIQa<}$o)u$+8-AbPljSfIHltJ8$Sx=CPRf@Yr(yMq1ELfBiV!O z8%%Zua}lY*TQKJO5svuK=46Ag|Nl!desJ6C_w`FLUdp8P#YLqxc@ef?mtv$m-wSDQ zuPriD;d{Ru8?EMt_MWA|_2*KI4+aycx^!F6DwFZ{K6nTVaaA{)@rFg(u4ot#TG*by z70Xqk?akcBjP4B6McK2^$ICO`9;NBItEx6gp^UfBLB~#TC^tbOlgYWs0ON>_TI!is zU&uYdb}5G0KHWN9`8E&cz=g>2e4BSsRe!!spDx9ie~vC#ZuUAkBvNbsL{wPC7mIo* zzDER4S`pvFpph?Rsfus%U6^oaUg1&Du@f8;Ux`dcd^5l}#Me?UbMr+iznLO1aLgX^ z1^5rdPq#p11lZf921PW-2Y`o$P>25o!BUxi!A6(b1}AL zM@0P1!ILVhkSvjY&D?_O#2 zgCBdUY>Lp;25&lQuRUG>C0p?2nc=8YueCSPdyr>GCtYz8#dgzl_q~31{x5;Gs%fGx z34cKM-(=hF1N(45*I-lT;`|kv3T)TOJeNBRrB(fpq`vr-`6+VAAFvxEG<#YZN#Y4t zY0&8SfL?f`G_JA$8wsB;`$H%Dkf-_t#u2w&0gZIOvO9)!tbYKzLzNF;aj0U6D&WfP z7OTBWl|vJ@t({?vqA#N|k=#I!{izID3*lIz5grs(y3%N65MoE)KMAWR+5MLHjs6)Z zhjZ0JP~*8q@IxIcKLnCXOAw5^{6zE&#-(y+F=8io_$N>tMP;N=5Df#z9;0I`*QlyY zPmR$n1EN5hQWdwt*iEzQ3@b==Mt|t)?A?Bx>~nqxn};F^Zguuy{{VJL-~(7zHI`_r zI#t~iIB}TbmcY$F8a){+U134sItvWke2%~~M)TtAfB}Lhmn}#?@7JAowqP{;(z*N# zFRjU+K{pjuN#i;0Qg{f5L_aHF4mYTCm=7kMm<9dT=kX{1JgVkAx`(tn)6U7e1&ur zjO;tOb1fsHg*NI_+>#%G&DM`-;h&&i;B9pr4sOgYq$t&oxuuyKEj;d`xE--mRD`D} z{4hDb0aL5vch1qWlXoVBRF$%uY(~ZnCg%n752?T?;oLeG5ZdQ(A_49GUz6~RB8Unf z%{ACaN(jhx@`}uT4#}%CkB0mn_DfMdqM_^PbC+m+4oCIQ)bySay327mny$dLj;#@C zaBQQ?6Uc;yj|i{}A3@%*7q$)SHz?#DEN%*hLiIME4XrYfq$zmlh$LZ=wtpI`OOGV+ zPkM4+oAm>qFE%=K>onBbJeKqVnxMO?y5km#CA}0ncEUrRFNTdqX0rPT0ENFKZhjv0 zjb-TL4De#BxDM?v&%C$H$nP$IZ1Os&92(|$AJi?3Y!|;u%8|`}p!Cr)1cpGnOj)>M zc z{epZx%%-qxCyyyw!_101vJ8D3aWMBYuXPy=gy6!$=m)pmWq$G(d(gD|s_tR-9ZIsp zRRPQ$v$xa&bOpVW91bBfdC+?YRrPPl8}Psy4Z)>(wfYX)ZdK!s6`nsFT{awD0iWP$ zMi;RQMTU%>myW$$3oW2OB=xlZw*)iGDI_8Yem->N*mq-2nPkgJ< zWzZ_Ro~G!oT3T^!gN~g5(cUZ3$q0A`9EX5g>S+eQRVE~8-Tb;B_U0J*V*k_}NHb#Z z?NWrw#{(7<54NI392k4Mimkg|h05*mVjWM%tgye&FA!uzh_%n4Car2=dNqKrbNq5(<$UXPak*1ItL(b8Yb zw%vE^!_iWWVVPLza-*0X8jYt?)sS_u;Cy}G*LPn3E37GI$$ad_h?AZ@D|zA~ltvSd z&FzjiNqz2%SQDXx#h*F?M|lx&giKdKBe0}`Vhlt60qijbK7hr!jwPCNDTe`67Y`u`5~8kI0(#ACpQ?UW;Oe0qxDZ($xOxv&^#`s_ z#lr&yu1JdE4nIf`+0mJb>+NU)0#%rlgvv)%IX2bT!<{@6p{se&l|!(x zC|t0~X5}(%v5}85I&)815$D5ca_*|CI49o+4uz&QJOMg(LPO##amk2t1{Q}nTk4$< zCK9QX2Q~oVH%H4C{y!EKes7l|eDy#;uRJ7zJ4#?k)` z+a$2%I$THN9{iw;Mv%GC5^OfS~KGcfpuqqG*k zR!*x0&!83sT<~5dbc+n*6L_zU-c^Ht(c2|lC42c2(ieF(s6PsGyKLM2rup1++b7?A^vlU_P%S&TCD>HrbDrt;knNo!c zA(o*%(}8%v3xvZDdOtJ*VJGyBQ6K1RfN3g4|Re0wI4J) z6~ACJ3lf+=`3JBI3?INEFj(RcnE9|LFp{(KLS;JThh3=mWbjWp$*K0NM_g!({3zE- z7&qfR^Wj`pT2jrych!uvD2haW_DOrDBX*`AF*^;X5xHT?Ws83RyR7g5EV6nzgiqDwpdCKVvu_)Mdp*(HzX;%7}}qN2I*y4|Rcgo*y(j70)4p!vyAK{sHU) z!w0Yk43;e06>Tuhh|G8e{ z9J(w&LqMxi>W*}N*FQ-Ixe-n9TEyCr{-0z#YCc5RHrw^mtJwUv*Y}*FX#>p*U z$M+-Z`)WLz@Tf04&Qs*^x%}9W8}&WsD(1k8D$(X@ExLxe@FH~KQLsR9;c4H2-_dMz zrdu*nIooceVoUBqUJWL%@Uu)2EuLFfwYnUq3uvV9^L7d3|SGH8{F+kOllI>K96q-~kTzNN=)m2;fkDfG`qcZSiS zuNx7s{W49@T~&1m6pGh=4LWv$Ljf*{OeVmU0mc#FveY}ZjKE0dcS|(~on_7>RsXKY z?}u}MS0cZELsk8e-_w;dEvz4~=4km`*_qlNH*t}$@)krBqMWs&9&_bl(H}~{Xtk`k zNS9-`G&u!A1cR4BSB}+!Md7O@J;bi+T0CM;G&*xnSqTOoOOta~Ro6=LGhkY1F!)61 z*a;1-6^Tn`tz=+vtQAYWC|5cppS$^WVHKET5lv#!)l#lKtRQnP`77wU9Ow(Kpfi+x1eTC@AJK@%1DNpw zyt-$|^`bwNkkLl+&S2Sd%7j=jZzEW&3kHkA7fjAZ@^Pax_Zm=^%SUK(?y9Ai%OlXS z6B=4B5|_+!$-v@RE|z-7S~n6+JS3yL0hM7Pn4{z`gg57anpp_mE=4xc2LjAAo=t@3 zqQGpTH!+K@S1-daxLB8Hw`3s*{AKug*eK^1r{pdlb9LP6Or{4e$oh$R)(^Q1#HlK` zUMdN>RY498D?%E*5`QqX$OIjY!w=^eLeOK56}&6{)FR{w&Ygmd!a1jG`Njd$kzH_c z@TAHrDxTEfS5+4fcf7Jp3_mZwp11=6kt@V-zmDJuf5K%`DB(}I=_Dg934e5k@Fx6W z4VLit93YJ){L!yIB>X*jtlFvXESJr9a#%JWjZijKZ-mWnvIY0NvwQULF2*#Y?vi%g zth5`=t?dqEHIuF=BoLjIU# zzwy81UO?vGTO@tOQ`=H(k~d>FMrzxkHmP8aLM7{HsjS6|(iE-vP$afE`mIm>Z@p7@ zB%^&08igjKJ?bC89>?GVSi($LqKct%JG*i}pk=$jg=HLbzisrTi*$(>^wDRk(cVYhs$wDaNJcCcV3Cju_J=MQ`(2^~9W>iNuo);pK=(b@2l@xF z3kDy+A{bcW5RCLBl$8sci_JeV#UfL!h}kEdMKEs0{csmWQTZD*S zr!9lamJ+F7llu_S!Q_p8U={Y`95G%z7px~j@Lo>ZUI_+&pa_oQEc!ldw3^#oJqrd8 zg0&S5p{+qttjpmCzKffhkcOu*$2$9BFlFkA^mWiG6VCkyc<2aFVUf0V8tTgk=aMDG z(^i)@6@vXt4p@rE@Y7V)AA)69|4WzoHT**Wab>LPmfTzea`mOURJnQU zWRLKP9|>JKWEYFVWjD11t-;leMrZCRBf|W}@%1!0cU4t#lm7yCga%hngN~ihkmO2S zGLoBt#UZ(tdIwwhpNg-o6lB=!CtrqF<-nGaVQ-hh>-~2DD}(z`aRUf+sXfRRQLnt- zy9+<~JB8l{VgnGTs@3*XPL$rQ{=Hd4o%}P@7aF3N-^+xuXdA znTc(H{+-WLfp4 z4DDB9A0m#yT<4izlE4z5ZihAtiGJf)^(CWS?{%{nH+)?st zvVpMz8lh~g;Du~{?Z)&dzma(pD))&Rysp2!Q=1%*n0IUj8Me3z6u?esr1GBHNnGWoZHKkrozXqJ<~C}$cvdH2C^9%g~mXx z^ABM6pz#4Lu5K(*7lIN4c|z{8wY+2GZ=_?j(->P{ge77o{=xG-nLCIN#x(3+bB3sU zw^L&&Po-{^SjxuYdNd=K%e6j)WExL(y#LaVx1G>C+2n)5F!%Zgu*)VNz#^Mi@_5PS z!^YT#P$-Tk)u{CZZe}Z+4-y}YX?R)YKos1lp?6t-(F=n25?DW1VGhMEf&IRJCM7O` zWfLs2fb;8O*vq!@>0vLwBseZW@i)@f`F@w{>&6h8y)V0eu*t464dVh?8-ywN$&t`o zKLR+X;w*UphuJI?ei-DUmm9!2HI8uZ>RKQ&)uh{WM8;RaLl?TcL7jAm~F-*9j2`x5OtS+!=Tr!fmN{ zpdl5KyIr#c#M^A2FW#@sfh!~4-Y!J|XiGq^+)s*|N1&f{BUR16OMLOwal6y3x1{bA ze@pCWW&8oUQ)SjIGYA3?0R0y>%Gv9b0MHYdWrJV;1LKCT?5MFlfw$1*{QQ;Vq`Url z!2ab|6rhM4+5^xclkKM1mq0~T{*H}2|XpBqr~|q=hqXQM+ggX-mfEgC_~t_g+dwPNFh0D31!?0g4*?lGOz{< zWwd}a7RsPseF$Z2A!A;6{zoxwr`$UbXNJ84ksYpVkmJ^DSCmsV+L#dJwEk~*S07_X zRmJDZ{E(l&YOA6%VVjoAQYaQD*752dmcAWwM$KEp(-S8m~#Wq2XZhRul>pyV@ z->=AyYUXRiQ+a7P+>sZRoC+Td*)TZv5wWoK02PzMJ`R%hoD}intH#*I@+DP@7Ntbj zJSNkn1TIK6BFVI;q)aOSKb}CQvf#(}|IcJ|hUer534~ zP?l}QhuTMGlVX$_TN&F@K1Tk2J{RCr(iltPSkvQtxFhIuLyp5AzBdp#{FjupJLGMsfco&J4Wdf@(-P{FXYx-o>T|!8 zS^otz{oXvOjp;}V^~qyl#QfG>nAlDQ>hndKFa_$vy)}kc+${`JU({#k`xxp&?t*wK zkj_uhC&qABL&b4;Yu?m?J(KWC&w#l?wP-yy;hn}@lBp@ zAy)=zdIf<6NE1aR%y!B|CpY7{J1jbo=YTIilq@b~O=I&C?G_4*>EEn*#Yy94ejto# zC0bL+9JUP~awfA4pJ7bFHhfOHYMCxT3T+A#qu}>M+t4vW6*2$d`KTx|*#ECb11SZ^1Gim= z|Jc^Xb9bZT2oW1jyK@0P|dM$zr611R8H&PI_!Y|ozND^dF( zG{q)Y4jNt>=JkJY27`v>hBN~to?kW}2N%mGPtLUmLlzDWI7aMmT|>pB07r(oSCLU6 zh!L2uMJDYcb%Y~s%1<3Q7e&!Yz9>?@6kv+CB2!tkp)Ic;V(_?N0KA8_EDD7KApaO!4OYz(hHyLf)gNYgM+8%R&^ zGbt^P$~l(bg@<{wN?mdKn!JL1X%Q9VNDIXjNXrlGjqWPcGeQxR1Z17Hrh!aDKbIB^5wF-oO+;V%)UEI@t7mh%$x3 ziK(ge+2zZY1)H0&6Yq{7uo@Q(OBkVFC`D)nvP@SdP zg5l{k+5<2k$v6l=FZLZ%&8{YHgQif}qE(QvkVVmvDugQ_yr>S9BW>2()dI@5F+~v6kNz0 z1~hTbBs$qzd=ps0m;ISfPW`@0{{;J`oE_%!7p{cF&m?#MS*7;B55V2l2_!BHXU%a26|(3sZg}#U!SU0vI+Y-T5Ww)ll^PvN>Sa)AdE}RMDA)Z}d?Q5;Sop;j1jE z+{oO-cQgu(iimF74)c^?a%y!`bzS=OqAh$R)v9TWfFCJRxKMoOBzc!S*ewxrRq!+9 z8?z!t>2WWVx8SgX#-u&>k}X9g#6ddO^;O1?q>3vw4SbL_uQ+LCW&9`#E@Td~BAhej zt;l^<`X|^g0U63vy`d)C{7)Sfb&EA6qo1WzgWp_lv7HGb%Y{a1YGCF;@+eZM~;ZhbpDyPjdXJuPtlqnH|x zQS}RO2k^opJ*b*Ks&Cd;a(kpt>*vg@km;sB?Al!ir|$G=%Ddd3sCONl!}AmoKI^Xy zLQDf#)U3b8)jV?Q-JZX`Vb@s;c40%*@-(Z_^M`L@J4(?pzIC(y$h>Cp$Ni9h1RGeI z>#6MyevI*IaBbf@il3w6XV)?DYuvNz%A8t1O0lSJ2<>u~dj3??wmr-C@Gamla%Q#@WEuRPW3xrnV6>;yG$v zqjvW`;ZGP=r|T&=_GmYds^^b%z2?r#ce)1t-;#_}G{?d5B^{e~IMxI{Q&a0+&tHcJ zd6K0Ju~K^e)>KTYh}MrGm;MAVH)=zWdrLARmD!)9KDc0%4i=f{Q_mkaRcpSh&THU! z1HV^jR?pwy;HyhcLuqIo$Oo!1G#ZFtod=E>4SeoEYZ{9<5amy(UC&mcAb*7cp&D;= z+Z`noJTR68;3kviSSoa5)?dd$z+KCw;g5nkuGVeX%3_;DYEoOoX1%7wb22HZd&)7x zHSqo<@_?%Tb4VPRocXUWrTYnScJ?`~+vb|a;`yXSAD9IPqGp?F#w1La|0)*yW6TQ9l< zoSkr*^;9(!5>>M$sK&!bCfr?y<~3P0y4N;Q#fYcQL5mum-kVwDZ-q>@l~6syL%oXI zAqlz1pLCZjPhC`WV_rA$2l-uP+9djG-L?uvyS)p&cEP9(>^J|Zn08&o)iq-6*1E1j zg)s13-!PPng~)xh+d&l*n3VXLVm=St1L?8rhSh`&1QWv)O%-l;E}3ppYtLy7=;{*c z(lyOPX&dW+f{rR$TQy8YZ8RK>b~(_#m6~;|2gBg6;Zp>365?f84FF0ICQro|7cu3a z#p_WK#Kpr*2~lWhO&4!&`csKeOKqc61f#TO_+yyVqQSyfQy~Ap^)T6!hd^9^go3@L z4$I6UW?g+7p7dn#`dWQIj#v-##za%{5C`nQUIns^$PbA; zOXSWWkdG62iO2~e?->S}A@XY?za#Rl)gadp8CwIgp2#Ca9wTzr2*{g>+&2dDAQ5LA zWP!-KNszOMyln%>Wki0p5#+Z-oU=g|iF{=X$Tx|6`y7z(6ZujN_yfd(idADNh zIw%k(jrJVAaFa-SRw^(|J(5T^64c7dpGuSuv+a1~Cu~fYC1RHOqp(Em!#ZSg$Lh9e zLb=fgcq6OdZFkB3K&?KEedX&hmv&SKvokc=g%P9*cR>3l+$9%NZxEc-!gmIcpnv57 z=(}Z51?<{E4Hna7OF>xjnp&HKfjx>COS_`hwP4E77@*f(xEQdk(X)JSxSZq?Sx|{p`WntH~aapE)xWx~8r9b5RZ+W|1R@r`K&u@bpUj6g;IE&Qr~w3jL`- je3=@Jg~80~jTu(m>^9)W*z;uYMjPbv3Gawc$h-anPPi_F literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.text_column_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.text_column_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dc5bdda274092098f04be8d76c8507bc5819aa71 GIT binary patch literal 106277 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 aYQ0qJl))l2mQZ)BE2H(~hK5P>-2Vfl5SEw# literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.unstructured_labeler_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.unstructured_labeler_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..98d254f8fc94daec655ad8822d9accc6c5144761 GIT binary patch literal 30575 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.unstructured_text_profile.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.unstructured_text_profile.doctree new file mode 100644 index 0000000000000000000000000000000000000000..1d2573230892656c59c18c556bb1ef1340cd91b6 GIT binary patch literal 28381 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 OU&qUm=Vyy-GW;6bUR}xn literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.reports.graphs.doctree b/docs/0.10.3/doctrees/dataprofiler.reports.graphs.doctree new file mode 100644 index 0000000000000000000000000000000000000000..84fe028bddf646eb507e5cf66ef99c387f18913f GIT binary patch literal 3236 zcmd5;TWcFf6n1P&vV4*4q{&O{)M*HHXe_mmhmrHMdVCT%4Ip=)yoy)JSKmOcYDt~_46kNz@ zpQfo)DKo*Zr7CeblQz5#_kIh{!=dkLdS;Z<2@8G+8VMI!s+kPWg6~CjD>Bos&vy(< ztWdH!&Re|AJI}%)@A{S%He(mIeETa+3vNQxfWqqcY#J>$@)x1>0he6!?SjIp4Sd&k zN#iD8@$K5Xpx-s ztyW`^F+G68W>7ggNU;I+a-$!0wKe@oi9}x;M0o3X*^T&;ZwZ;Q=>@%2S|F6%LPeP z9*eBOl{YI1%UCHPXTowaD^jpnAE>L=&~H}MBpEwpSvX$y>zrnGwru%bHWk3iBFD^J z+Dh5TO<=BfMzsW1(9n$LkaVr435$M*m%b-t;VfY?Q7N>7?>aj^`t-;MeD5u85~j7% zgj1QK!U5;#YGQ-mR?aTo(kgEWe*eO`Lx5P=oE}xJXumCvE)=3 zVM~5)lT;Ww%3>h3mz`NQ@cVuf!5Hu#MGTD>l&RH7Y%pb`yAi)&1T8D-;CbV1Dc*Yn z&AnNIpSv-oKpQy$3p0@m8@^up`=6HY6|6vC8#AP0QbM*FB_j&&V{Z5ZZf#*64hCmu zXZ_;bawYppPX;MF9YE6zg1;V5l&;_eu`I_!Sv<@dP!x+dPAbuB9WSP-=NNUi14PWKNpgY}_ZNhzxn9|OwIx40B((uh*UELZB$-NR4efry(QOhue3fiKxr7j>Ph0^LaYQQTp1KIU0((>< z7RfVguP8c^@)Z1bCh^0u>bJ*gHS=@F#$rL>yET}Jz=Ofm=Shi2z0TS+dzdh&N|1srbp<>?aG094X($+rk(Idbk;;>tpnqa!Bi4n z#y;@ZJKGYS-@3@K5}vI@pa4gF0a+!9g=D5zy~9OGrH9u6BlD5U8q$`k?_Cl$+TDd4 zyECihp{on`qakP;JJ9vZchx&fejQ~lQ7#s-;5QPLWnd0sK%eV8uH~=sx-Y^LBr1k1 sq(0_ng9=+2Y^vRYc%u=QoZJvH$y|yeqb8A#>uD^=b?u5nf*bY!1s$UNG5`Po literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.reports.utils.doctree b/docs/0.10.3/doctrees/dataprofiler.reports.utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..dddef67079e17332332f7d1ad45d60ccb9f66630 GIT binary patch literal 13944 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.rng_utils.doctree b/docs/0.10.3/doctrees/dataprofiler.rng_utils.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c00dcf619d7457cffc72df404f2adb03c2e09b64 GIT binary patch literal 5342 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 MFRPv(FS5z-D+7#U^8f$< literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.version.doctree b/docs/0.10.3/doctrees/dataprofiler.version.doctree new file mode 100644 index 0000000000000000000000000000000000000000..f62a48dd25d9e5df2266a048198da4e2c0bea26d GIT binary patch literal 3171 zcmd5;TW=dh6i%Dij&pI6miDDdafK>U(b!bt0hLM!74bkMgGyWRQjKPJXFWr9cb2&% zj!-3dsMJdH*5U8)U-%Kc^Ubbz9Y^g0ynrQ3J7>@2Tz>8R{^Qn4^>aJANcn`N<`Kmt`NtnNObVI7iUy!2=U!1XkLGs$dS?T1kcSZaSn3!6tw4O6Kqaf!F3Q#PtOck|zzT#)iHu=%QH#Dw1tynF8p1t`A+asFEfo42$P zYdt;Wk6dq#mS+vK79!e^EQGLu8&>Ox`Td%%?~l37OnyI{z2XM3RUwB-o3UGsq|RKo zu9-0)0*cXITU}Cxhh;_LUH3W7ELh%@C%!Xr{V6M$qDCr@1=!5Ap?QhLW^IPx?h`CG z=1Z$GthSAeNyzlD3v->2LFe9GOQkf0G$3ued3?ofhtdWvkr|kjdq@U>vL%US9xA5B zmA7gM%UC5LXTosO)EiiwAD9=QiQ5WwLK%{=Qz|{_-YaN=ZdH zEfN$f;2d0yjdwfJn&n$M)h*r~T-v#G1^>kj>Pr_6G)MQBH!huYyCDD#lsNFo5RiA< z87-z3c?-A`tgoU0x$BC>QY9o|CCC9Yq5e%=7iAztjDSNVD9bDrGtawjK&_EvA#zs* z7`2_)yd*8_fNCWWAe<^_7B1YWB!ITi;q4cqQZt)KGRp&>cG(O?pOK3vD~iO1oC+;! ze(sP&Xc}c9khzz=CL8#Dw}oId_)n`Y3d+pYNaz(+&$=1DUzU zf}eXKr9hiv3KnJ}7sh|P^5eyTGrcTXhI1R^&GZ1V+Oa~h%-q~2+OI+2xc(Fs=4H~TV=&*7-HOdT_2E; zpcf_r0m2(%sG2g=8+83W7y?}khA>be2_wr(RInv!J=Q>s+tPN?4QYXi2=ZPK*5CXY zf1+JK2+Vm2uwHupY@+#{Fm^n_@bd^AxLZ50sKN6YuWcy&5pB9i(>gHFXp9^Fb?5_s z{Eyn8b=wy?RROXc3zXb|C_t(up>#BQHS!lFwI1FB9Lyt`wKT0%Ke!}pwfjpq_8Y6! zp=(R`qXj4vdd`i@cg=TJ+y)9;ENv)T-fhM*%fJ=HfX>!?JeR-4d%p5dkeV2xkn9+K oHEL>Yu&r-P;>}iEv2arqab^>g6*&zA+(<$Ro>!|d7T9R?H#-~Q#Q*>R literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/environment.pickle b/docs/0.10.3/doctrees/environment.pickle new file mode 100644 index 0000000000000000000000000000000000000000..5171298285f3bcf74078d1096ce95d7dd1cab40c GIT binary patch literal 644754 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�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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/graphs.doctree b/docs/0.10.3/doctrees/graphs.doctree new file mode 100644 index 0000000000000000000000000000000000000000..5ffd40f3d0cfc647693b8b373694a73a05b217a5 GIT binary patch literal 25599 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 RkvvCN{y>Ct2k=q(e*t*gn{EIA literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/install.doctree b/docs/0.10.3/doctrees/install.doctree new file mode 100644 index 0000000000000000000000000000000000000000..22b2ec73b464f7d75ac2708952f22756fe1c0074 GIT binary patch literal 11886 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 YJEDb|re7x#JW?gTqewJ~NwAmvf8@S1jQ{`u literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/merge_profile_list.doctree b/docs/0.10.3/doctrees/merge_profile_list.doctree new file mode 100644 index 0000000000000000000000000000000000000000..bc0fa0762813d775f0b1e26aecfbde138252d82d GIT binary patch literal 11827 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 E23UsB{{R30 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/modules.doctree b/docs/0.10.3/doctrees/modules.doctree new file mode 100644 index 0000000000000000000000000000000000000000..2b4cfb10d242f2f81ba09c3fa6d55a8e9d43af80 GIT binary patch literal 2683 zcmZWrTW=gS6i%CL_LAMrrIeQ@K!qw=(PRPffOtXz35iGnajDdY%JPoAYZH$>*q&tb zPyr7`t>m|wAIOj3ozF9~lig*d(TKFE1A*5cMQO2}k+{Msi zCM$EUeS90A{25=y$DwcOwKJv7cnn+6$b?kPavfj9Fiz@TDtFeL?>e4&X>@yBbi}Uc zzKD-SKXknGimz;iA)}ra*36{hHYPo&?flFa$^XXgt60SYgZIL2K@owE;xP0{8?x9A zyG^7QVMj^L<3%~8VL-jNa$0(1m@?Xy%%$kNnWD}?i1&`BdHvR7WpTTh((KamS<)#( z*VB30ieg_p5JPb+w#7;KcJhnk)=e&*=5#vAJ|)QLSK#0#-~U7`FN~XfgFJs|@|+-G zH>m@i2zKUbB_db#n4}sx_cpl;T z2+tEd4??%`gQS6*l~t-28wmduX&6eKsgm(jk(9LfiiTcJ7mOEP#Pc11MvJP#fOxLV zG`#X+zARN zRuc;QP2Q*1mKFu*LRWK4=TC2olI)=Nyfv|rDqUjqKY4>$vNwRe?YhWSTqw?ZOsfI3 z)DutB**jsJl{S%-w3Hk!B{ele&vEaio}=#$+eVsMqdiCI!|pSxN)%z)iDLgE^ygf2 zOTDoX3v>^6p5_G>d$k(^+m~1lnq_GfRwH0X5|z^~+;tN0H!&Q|jPcrdzOs3KCyY`T zqjF?1Gd7Qqj2%c*5b!b$2M3c6Y6(}ol8|fZ1z9!}JT?cK4g=LvBUn!qzv3#M-wgvn zRlDqjL%xu}%2QvurBWw!7@wANxEo(ntAQ0XET=gneQ#;TQ&RDD7)xE0o^YKR2CW$S zrJtRCaq1-AkJmQ|x7Ju9sAg&Epm4}7^D*q3(yv?TR90d*+1S}IA$||z+URWn%cIBZ z8yhFXK}x^@B>{XC5{hA@sGgT}&H*>W`Yu{4+_OA0mJ#$J$N@L0g)hQxX7mg>0uISA zchI+sD0ah`mfnzCQMfC?s1Ymkg0!pys+B;3a8^^54DMGFK&xG<{jI2Qykv$f^2DbD zzQ9!DWc6f4k<61T>155%eZr)pQ7cyH8biJJFg)5N_<5LG3bfI4uu#cd`uN?}KmT^ZxZnk5@C-9ZXBA|_B$-k~pL!#F zAiOW!my^l$_4QeC@#?B{zP#%TpL4Nw^lh1+d*v_&I zH%W5q=6LDG8-wdoazCrw2%jss=zBUv3$Zj~d*K9x%t_muZTQ3$i6L*ofxFS3E{KqG zq40pbJIW;94_!{tWxthZY6qb1RqJ|5l*wp4*276ADEbG5ubT}hR}kX#Wm&*Qy4tIG z-3$Q?cSxk3fdk8_aFphRE2ryv2OJ}xp;2$(OK|RC?S7^Vy(B!RQW1P^SYBPcufsOi zSLv1xy?Q>NAwe&xnFQfI@zl;a<_&J>LpTCmJia$T1>8{SG7m><()!+p7}jR(VmGw~ zu6)S5Nm##&=i-?Q{Uq==1;Bb4#q$d%9^(I*7`iZ8EkJd8lu68|@U4mhmO|lV_sUH2K4<+Tg?t`T}*)t9}_5b411YT z3cw- 1\n", + " ):\n", + " errors.append(\n", + " param + \" must be a valid integer or float \" \"from 0 to 1.\"\n", + " )\n", + " elif (\n", + " param == \"size_fc\" or param == \"size_lstm\"\n", + " ): # additional check for size_lstm\n", + " if (\n", + " not isinstance(parameters[param], list)\n", + " or len(parameters[param]) == 0\n", + " ):\n", + " errors.append(param + \" must be a non-empty list of \" \"integers.\")\n", + " else:\n", + " for item in parameters[param]:\n", + " if not isinstance(item, int):\n", + " errors.append(\n", + " param + \" must be a non-empty \" \"list of integers.\"\n", + " )\n", + " break\n", + " elif param in [\n", + " \"default_label\",\n", + " \"activation\",\n", + " \"recurrent_activation\",\n", + " ]: # additional check for activation and recurrent_activation\n", + " if not isinstance(parameters[param], str):\n", + " error = str(param) + \" must be a string.\"\n", + " errors.append(error)\n", + "\n", + " # Error if there are extra parameters thrown in\n", + " for param in parameters:\n", + " if param not in list_of_necessary_params:\n", + " errors.append(param + \" is not an accepted parameter.\")\n", + " if errors:\n", + " raise ValueError(\"\\n\".join(errors))\n", + "\n", + " def _construct_model(self):\n", + " \"\"\"\n", + " Model constructor for the data labeler. This also serves as a weight\n", + " reset.\n", + "\n", + " :return: None\n", + " \"\"\"\n", + " num_labels = self.num_labels\n", + " default_ind = self.label_mapping[self._parameters[\"default_label\"]]\n", + "\n", + " # Reset model\n", + " tf.keras.backend.clear_session()\n", + "\n", + " # generate glove embedding\n", + " create_glove_char(self._parameters[\"dim_embed\"])\n", + "\n", + " # generate model\n", + " self._model = tf.keras.models.Sequential()\n", + "\n", + " # default parameters\n", + " max_length = self._parameters[\"max_length\"]\n", + " max_char_encoding_id = self._parameters[\"max_char_encoding_id\"]\n", + "\n", + " # Encoding layer\n", + " def encoding_function(input_str):\n", + " char_in_vector = CharacterLevelLstmModel._char_encoding_layer(\n", + " input_str, max_char_encoding_id, max_length\n", + " )\n", + " return char_in_vector\n", + "\n", + " self._model.add(tf.keras.layers.Input(shape=(None,), dtype=tf.string))\n", + "\n", + " self._model.add(\n", + " tf.keras.layers.Lambda(encoding_function, output_shape=tuple([max_length]))\n", + " )\n", + "\n", + " # Create a pre-trained weight matrix\n", + " # character encoding indices range from 0 to max_char_encoding_id,\n", + " # we add one extra index for out-of-vocabulary character\n", + " embed_file = os.path.join(\n", + " \"../dataprofiler/labelers\",\n", + " \"embeddings/glove-reduced-{}D.txt\".format(self._parameters[\"dim_embed\"]),\n", + " )\n", + " embedding_matrix = np.zeros(\n", + " (max_char_encoding_id + 2, self._parameters[\"dim_embed\"])\n", + " )\n", + " embedding_dict = build_embd_dictionary(embed_file)\n", + "\n", + " input_shape = tuple([max_length])\n", + " # Fill in the weight matrix: let pad and space be 0s\n", + " for ascii_num in range(max_char_encoding_id):\n", + " if chr(ascii_num) in embedding_dict:\n", + " embedding_matrix[ascii_num + 1] = embedding_dict[chr(ascii_num)]\n", + "\n", + " self._model.add(\n", + " tf.keras.layers.Embedding(\n", + " max_char_encoding_id + 2,\n", + " self._parameters[\"dim_embed\"],\n", + " weights=[embedding_matrix],\n", + " input_length=input_shape[0],\n", + " trainable=True,\n", + " )\n", + " )\n", + "\n", + " # Add the lstm layers\n", + " #########################################################\n", + " #########################################################\n", + " for size in self._parameters[\"size_lstm\"]:\n", + " self._model.add(\n", + " tf.keras.layers.LSTM(\n", + " units=size,\n", + " recurrent_dropout=self._parameters[\"rec_dropout\"],\n", + " activation=self._parameters[\"activation\"],\n", + " recurrent_activation=self._parameters[\"recurrent_activation\"],\n", + " return_sequences=True,\n", + " )\n", + " )\n", + " if self._parameters[\"dropout\"]:\n", + " self._model.add(tf.keras.layers.Dropout(self._parameters[\"dropout\"]))\n", + " #########################################################\n", + " #########################################################\n", + "\n", + " # Add the fully connected layers\n", + " for size in self._parameters[\"size_fc\"]:\n", + " self._model.add(tf.keras.layers.Dense(units=size, activation=\"relu\"))\n", + " if self._parameters[\"dropout\"]:\n", + " self._model.add(tf.keras.layers.Dropout(self._parameters[\"dropout\"]))\n", + "\n", + " # Add the final Softmax layer\n", + " self._model.add(tf.keras.layers.Dense(num_labels, activation=\"softmax\"))\n", + "\n", + " # Output the model into a .pb file for TensorFlow\n", + " argmax_layer = tf.keras.backend.argmax(self._model.output)\n", + "\n", + " # Create confidence layers\n", + " final_predicted_layer = CharacterLevelLstmModel._argmax_threshold_layer(\n", + " num_labels, threshold=0.0, default_ind=default_ind\n", + " )\n", + "\n", + " argmax_outputs = self._model.outputs + [\n", + " argmax_layer,\n", + " final_predicted_layer(argmax_layer, self._model.output),\n", + " ]\n", + " self._model = tf.keras.Model(self._model.inputs, argmax_outputs)\n", + "\n", + " # Compile the model\n", + " softmax_output_layer_name = self._model.outputs[0].name.split(\"/\")[0]\n", + " losses = {softmax_output_layer_name: \"categorical_crossentropy\"}\n", + "\n", + " # use f1 score metric\n", + " f1_score_training = F1Score(num_classes=num_labels, average=\"micro\")\n", + " metrics = {softmax_output_layer_name: [\"acc\", f1_score_training]}\n", + "\n", + " self._model.compile(loss=losses, optimizer=\"adam\", metrics=metrics)\n", + "\n", + " self._epoch_id = 0\n", + " self._model_num_labels = num_labels\n", + " self._model_default_ind = default_ind" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d66bd25c", + "metadata": {}, + "source": [ + "## Integrate the new LSTM model to the DataLabeler" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "479f407a", + "metadata": {}, + "source": [ + "Once the LSTM model is built, it replaces the existing model in the DataLabeler pipeline, which is then trained on the given dataset. Note that, as the DataLabeler is trained on the above tabular dataset, its label mapping is updated by the list of column names in that dataset while training." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb482ffe", + "metadata": {}, + "outputs": [], + "source": [ + "# get labels from the given dataset\n", + "value_label_df = data_train.reset_index(drop=True).melt()\n", + "value_label_df.columns = [1, 0] # labels=1, values=0 in that order\n", + "value_label_df = value_label_df.astype(str)\n", + "labels = value_label_df[1].unique().tolist()\n", + "\n", + "# create a new LSTM model\n", + "# set default label (one of the column names) to the model\n", + "model = CharacterLevelLstmModel(label_mapping=labels, parameters={'default_label': 'comment'})\n", + "\n", + "# add the new LSTM model to the data labeler\n", + "data_labeler = dp.DataLabeler(labeler_type='structured', trainable=True)\n", + "data_labeler.set_model(model)\n", + "\n", + "# set default label (one of the column names) to the preprocessor and postprocessor\n", + "processor_params = {'default_label': 'comment'}\n", + "data_labeler._preprocessor.set_params(**processor_params)\n", + "data_labeler._postprocessor.set_params(**processor_params)\n", + "\n", + "# train the data labeler\n", + "save_dirpath=\"data_labeler_saved\"\n", + "if not os.path.exists(save_dirpath):\n", + " os.makedirs(save_dirpath)\n", + "\n", + "epochs=2\n", + "data_labeler.fit(\n", + " x=value_label_df[0], y=value_label_df[1], labels=labels, epochs=epochs)\n", + "if save_dirpath:\n", + " data_labeler.save_to_disk(save_dirpath)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "14b78c69", + "metadata": {}, + "source": [ + "The trained Data Labeler is then used by the Data Profiler to provide the prediction on the new dataset. In this example, all options except data labeler are disabled for the sake of presenting data labeler functionality. The results are given in the columnar format where true column types are given in the first column, and the predicted column labels are given in the second column." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdfcf1d2", + "metadata": {}, + "outputs": [], + "source": [ + "# predict with the data labeler object\n", + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({\"structured_options.text.is_enabled\": False, \n", + " \"int.is_enabled\": False, \n", + " \"float.is_enabled\": False, \n", + " \"order.is_enabled\": False, \n", + " \"category.is_enabled\": False, \n", + " \"datetime.is_enabled\": False,})\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_object': data_labeler})\n", + "profile = dp.Profiler(data_test, options=profile_options)\n", + "\n", + "# get the prediction from the data profiler\n", + "def get_structured_results(results):\n", + " columns = []\n", + " predictions = []\n", + " for col_report in results['data_stats']:\n", + " columns.append(col_report['column_name'])\n", + " predictions.append(col_report['data_label'])\n", + "\n", + " df_results = pd.DataFrame({'Column': columns, 'Prediction': predictions})\n", + " return df_results\n", + "\n", + "results = profile.report()\n", + "print(get_structured_results(results))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "cc60ff8a", + "metadata": {}, + "source": [ + "In summary, users can define their own model, plug it in the DataLabeler pipeline, and train the labeler with the new dataset. Above, we show one example of adding the LSTM model to the pipeline. Interested users can implement other neural network models as desired with the same process." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/column_name_labeler_example.ipynb b/docs/0.10.3/doctrees/nbsphinx/column_name_labeler_example.ipynb new file mode 100644 index 000000000..6d3369698 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/column_name_labeler_example.ipynb @@ -0,0 +1,364 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e04c382a-7c49-452b-b9bf-e448951c64fe", + "metadata": {}, + "source": [ + "# ColumnName Labeler Tutorial" + ] + }, + { + "cell_type": "markdown", + "id": "6fb3ecb9-bc51-4c18-93d5-7991bbee5165", + "metadata": {}, + "source": [ + "This notebook teaches how to use the existing `ColumnNameModel`:\n", + "\n", + "1. Loading and utilizing the pre-existing `ColumnNameModel`\n", + "2. Run the labeler\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a67c197b-d3ee-4896-a96f-cc3d043601d3", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "from pprint import pprint\n", + "\n", + "import pandas as pd\n", + "\n", + "try:\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " sys.path.insert(0, '../..')\n", + " import dataprofiler as dp" + ] + }, + { + "cell_type": "markdown", + "id": "35841215", + "metadata": {}, + "source": [ + "## Loading and predicting using a pre-existing model using `load_from_library`\n", + "\n", + "The easiest option for users is to `load_from_library` by specifying the name for the labeler in the `resources/` folder. Quickly import and start predicting with any model from the Data Profiler's library of models available." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46e36dd6", + "metadata": {}, + "outputs": [], + "source": [ + "labeler_from_library = dp.DataLabeler.load_from_library('column_name_labeler')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dfa94868", + "metadata": {}, + "outputs": [], + "source": [ + "labeler_from_library.predict(data=[\"ssn\"])" + ] + }, + { + "cell_type": "markdown", + "id": "c71356f4-9020-4862-a1e1-816effbb5443", + "metadata": {}, + "source": [ + "## Loading and using the pre-existing column name labeler using `load_with_components`\n", + "\n", + "For example purposes here, we will import the exsting `ColumnName` labeler via the `load_with_components` command from the `dp.DataLabeler`. This shows a bit more of the details of the data labeler's flow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "818c5b88", + "metadata": {}, + "outputs": [], + "source": [ + "parameters = {\n", + " \"true_positive_dict\": [\n", + " {\"attribute\": \"ssn\", \"label\": \"ssn\"},\n", + " {\"attribute\": \"suffix\", \"label\": \"name\"},\n", + " {\"attribute\": \"my_home_address\", \"label\": \"address\"},\n", + " ],\n", + " \"false_positive_dict\": [\n", + " {\n", + " \"attribute\": \"contract_number\",\n", + " \"label\": \"ssn\",\n", + " },\n", + " {\n", + " \"attribute\": \"role\",\n", + " \"label\": \"name\",\n", + " },\n", + " {\n", + " \"attribute\": \"send_address\",\n", + " \"label\": \"address\",\n", + " },\n", + " ],\n", + " \"negative_threshold_config\": 50,\n", + " \"positive_threshold_config\": 85,\n", + " \"include_label\": True,\n", + " }\n", + "\n", + "label_mapping = {\"ssn\": 1, \"name\": 2, \"address\": 3}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9098329e", + "metadata": {}, + "outputs": [], + "source": [ + "# pre processor \n", + "preprocessor = dp.labelers.data_processing.DirectPassPreprocessor()\n", + "\n", + "# model\n", + "from dataprofiler.labelers.column_name_model import ColumnNameModel\n", + "model = ColumnNameModel(\n", + " parameters=parameters,\n", + " label_mapping=label_mapping,\n", + ")\n", + "\n", + "\n", + "# post processor\n", + "postprocessor = dp.labelers.data_processing.ColumnNameModelPostprocessor()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113d6655-4bca-4d8e-9e6f-b972e29d5684", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler = dp.DataLabeler.load_with_components(\n", + " preprocessor=preprocessor,\n", + " model=model,\n", + " postprocessor=postprocessor,\n", + ")\n", + "data_labeler.model.help()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b405887-2b92-44ca-b8d7-29c384f6dd9c", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.label_mapping)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11916a48-098c-4056-ac6c-b9542d85fa86", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.model._parameters)" + ] + }, + { + "cell_type": "markdown", + "id": "da0e97ee-8d6d-4631-9b55-78ed904d5f41", + "metadata": {}, + "source": [ + "### Predicting with the ColumnName labeler\n", + "\n", + "In the prediction below, the data will be passed into to stages in the background\n", + "- 1) `compare_negative`: The idea behind the `compare_negative` is to first filter out any possibility of flagging a false positive in the model prediction. In this step, the confidence value is checked and if the similarity is too close to being a false positive, that particular string in the `data` is removed and not returned to the `compare_positive`.\n", + "- 2) `compare_positive`: Finally the `data` is passed to the `compare_positive` step and checked for similarity with the the `true_positive_dict` values. Again, during this stage the `positive_threshold_config` is used to filter the results to only those `data` values that are greater than or equal to the `positive_threshold_config` provided by the user." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe519e65-36a7-4f42-8314-5369de8635c7", + "metadata": {}, + "outputs": [], + "source": [ + "# evaluate a prediction using the default parameters\n", + "data_labeler.predict(data=[\"ssn\", \"name\", \"address\"])" + ] + }, + { + "cell_type": "markdown", + "id": "b41d834d-e47b-45a6-8970-d2d2033e2ade", + "metadata": {}, + "source": [ + "## Replacing the parameters in the existing labeler\n", + "\n", + "We can achieve this by:\n", + "1. Setting the label mapping to the new labels\n", + "2. Setting the model parameters which include: `true_positive_dict`, `false_positive_dict`, `negative_threshold_config`, `positive_threshold_config`, and `include_label`\n", + "\n", + "where `true_positive_dict` and `false_positive_dict` are `lists` of `dicts`, `negative_threshold_config` and `positive_threshold_config` are integer values between `0` and `100`, and `include_label` is a `boolean` value that determines if the output should include the prediction labels or only the confidence values." + ] + }, + { + "cell_type": "markdown", + "id": "c6bb010a-406f-4fd8-abd0-3355a5ad0ded", + "metadata": {}, + "source": [ + "Below, we created 4 labels where `other` is the `default_label`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f86584cf-a7af-4bae-bf44-d87caa68833a", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.set_labels({'other': 0, \"funky_one\": 1, \"funky_two\": 2, \"funky_three\": 3})\n", + "data_labeler.model.set_params(\n", + " true_positive_dict= [\n", + " {\"attribute\": \"ssn\", \"label\": \"funky_one\"},\n", + " {\"attribute\": \"suffix\", \"label\": \"funky_two\"},\n", + " {\"attribute\": \"my_home_address\", \"label\": \"funky_three\"},\n", + " ],\n", + " false_positive_dict=[\n", + " {\n", + " \"attribute\": \"contract_number\",\n", + " \"label\": \"ssn\",\n", + " },\n", + " {\n", + " \"attribute\": \"role\",\n", + " \"label\": \"name\",\n", + " },\n", + " {\n", + " \"attribute\": \"not_my_address\",\n", + " \"label\": \"address\",\n", + " },\n", + " ],\n", + " negative_threshold_config=50,\n", + " positive_threshold_config=85,\n", + " include_label=True,\n", + ")\n", + "data_labeler.label_mapping" + ] + }, + { + "cell_type": "markdown", + "id": "1ece1c8c-18a5-46fc-b563-6458e6e71e53", + "metadata": {}, + "source": [ + "### Predicting with the new labels\n", + "\n", + "Here we are testing the `predict()` method with brand new labels for label_mapping. As we can see the new labels flow throught to the output of the data labeler." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92842e14-2ea6-4879-b58c-c52b607dc94c", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(data=[\"ssn\", \"suffix\"], predict_options=dict(show_confidences=True))" + ] + }, + { + "cell_type": "markdown", + "id": "261b903f-8f4c-403f-839b-ab8813f850e9", + "metadata": {}, + "source": [ + "## Saving the Data Labeler for future use" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6ffbaf2-9400-486a-ba83-5fc9ba9334d7", + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.isdir('new_column_name_labeler'):\n", + " os.mkdir('new_column_name_labeler')\n", + "data_labeler.save_to_disk('new_column_name_labeler')" + ] + }, + { + "cell_type": "markdown", + "id": "09e40cb6-9d89-41c4-ae28-3dca498f8c68", + "metadata": {}, + "source": [ + "## Loading the saved Data Labeler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52615b25-70a6-4ebb-8a32-14aaf1e747d9", + "metadata": {}, + "outputs": [], + "source": [ + "saved_labeler = dp.DataLabeler.load_from_disk('new_column_name_labeler')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1ccc0b3-1dc2-4847-95c2-d6b8769b1590", + "metadata": {}, + "outputs": [], + "source": [ + "# ensuring the parametesr are what we saved.\n", + "print(\"label_mapping:\")\n", + "pprint(saved_labeler.label_mapping)\n", + "print(\"\\nmodel parameters:\")\n", + "pprint(saved_labeler.model._parameters)\n", + "print()\n", + "print(\"postprocessor: \" + saved_labeler.postprocessor.__class__.__name__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c827f2ae-4af6-4f3f-9651-9ee9ebea9fa0", + "metadata": {}, + "outputs": [], + "source": [ + "# predicting with the loaded labeler.\n", + "saved_labeler.predict([\"ssn\", \"name\", \"address\"])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/data_reader.ipynb b/docs/0.10.3/doctrees/nbsphinx/data_reader.ipynb new file mode 100644 index 000000000..d2ce887e6 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/data_reader.ipynb @@ -0,0 +1,689 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d4d79832-59ab-410a-ad6d-fbba01a3f0d3", + "metadata": {}, + "source": [ + "# Intro to Data Readers\n", + "Within the Data Profiler, there are 5 data reader classes:\n", + "\n", + " * CSVData (delimited data: CSV, TSV, etc.)\n", + " * JSONData\n", + " * ParquetData\n", + " * AVROData\n", + " * GraphData\n", + " * TextData\n", + " \n", + "Each of these classes can be used to read data individually, however the Data Profiler provides the unique capability of auto detecting what data you have and reading it automatically by using the `Data` class.\n", + "```python\n", + "import dataprofiler as dp\n", + "data = dp.Data('/path/to/mydata.abc') # auto detects and reads your data\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "f2315666-20be-4937-9f9a-26d42dc135e2", + "metadata": { + "tags": [] + }, + "source": [ + "## Automatically reading and detecting data\n", + "\n", + "Below is a demonstration of utilizing the `Data` class which automatically detects the type of data for a given file and reads it automatically." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99e61c6c-43b8-4700-b627-759b5ef8bdda", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8821ad8d-b2c0-489c-ae6a-54c11b7f0a08", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read input data with different file types\n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "csv_files = [\n", + " \"csv/aws_honeypot_marx_geo.csv\",\n", + " \"csv/all-strings-skip-header-author.csv\", # csv files with the author/description on the first line\n", + " \"csv/sparse-first-and-last-column-empty-first-row.txt\", # csv file with the .txt extension\n", + "]\n", + "json_files = [\n", + " \"json/complex_nested.json\",\n", + " \"json/honeypot_intentially_mislabeled_file.csv\", # json file with the .csv extension\n", + "]\n", + "parquet_files = [\n", + " \"parquet/nation.dict.parquet\",\n", + " \"parquet/nation.plain.intentionally_mislabled_file.csv\", # parquet file with the .csv extension\n", + "]\n", + "avro_files = [\n", + " \"avro/userdata1.avro\",\n", + " \"avro/userdata1_intentionally_mislabled_file.json\", # avro file with the .json extension\n", + "]\n", + "graph_files = [\n", + " \"csv/graph_data_csv_identify.csv\", # csv file with graph column names\n", + "]\n", + "text_files = [\n", + " \"txt/discussion_reddit.txt\",\n", + "]\n", + "all_files = csv_files + json_files + parquet_files + avro_files + graph_files + text_files\n", + "print('filepath' + ' ' * 58 + 'data type')\n", + "print('='*80)\n", + "for file in all_files:\n", + " filepath = os.path.join(data_folder, file)\n", + " data = dp.Data(filepath)\n", + " print(\"{:<65} {:<15}\".format(file, data.data_type))\n", + "print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49dfc981-59fd-48a5-ad7b-e01f0a52d0b2", + "metadata": {}, + "outputs": [], + "source": [ + "# importing from a url\n", + "data = dp.Data('https://raw.githubusercontent.com/capitalone/DataProfiler/main/dataprofiler/tests/data/csv/diamonds.csv')\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "77f8ef2d-5aaf-44d6-b6d1-bf14f7eb7aa6", + "metadata": {}, + "source": [ + "## Specifying detection options of `Data` and loading `pandas.DataFrame`\n", + "\n", + "The `Data` class also gives the ability to set options or if the user wants to load their data with specific requirements.\n", + "Options for each data reader are specified in the docs: https://capitalone.github.io/DataProfiler/docs/0.4.4/html/dataprofiler.data_readers.html\n", + "\n", + "```python\n", + "import dataprofiler as dp\n", + "\n", + "options = {...} # allowed options are specified for each data reader.\n", + "data = dp.Data(data, options=options)\n", + "```\n", + "Later in this tutorial, the options for the CSVData class will be discussed.\n", + "\n", + "Additionally, a user can directly load a `pandas.DataFrame` as any data reader they choose." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b925d4e-ca94-4913-9acf-26a883585e85", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from dataprofiler.data_readers.csv_data import CSVData\n", + "\n", + "\n", + "df = pd.DataFrame(['my', 'random', 'data'])\n", + "\n", + "# specify via the `Data` class\n", + "data = dp.Data(data=df, data_type='csv')\n", + "print('Data Type: ', data.data_type)\n", + "\n", + "# specifically use the CSVData class\n", + "data = CSVData(data=df)\n", + "print('Data Type: ', data.data_type)" + ] + }, + { + "cell_type": "markdown", + "id": "52c3c3ac-c241-4d91-8ac7-b3d28ffd19c3", + "metadata": {}, + "source": [ + "## Accessing data and attributes\n", + "\n", + "Once loaded, the data can be accessed via the `data` property of the object. Additional information about the data loaded may differ between data readers.\n", + "\n", + "For this example we will focus on `CSVData`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09fa5929-e710-4107-9313-1370ab639c9c", + "metadata": {}, + "outputs": [], + "source": [ + "filepath = \"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\"\n", + "data = dp.Data(filepath)\n", + "print('Data Type: ', data.data_type)\n", + "print('Data Filepath: ', data.input_file_path)\n", + "print('File Encoding: ', data.file_encoding)\n", + "print('Data Length (two techniques): ', len(data), data.length)\n", + "print(\"Data Access:\")\n", + "data.data" + ] + }, + { + "cell_type": "markdown", + "id": "b98be971-4768-479d-9e54-00f05a6fb790", + "metadata": {}, + "source": [ + "## Checking data file types with `is_match`\n", + "\n", + "Each data reader has a class method `is_match` which determines whether or not a dataset is of a given data type.\n", + "```python\n", + "CSVData.is_match\n", + "JSONData.is_match\n", + "ParquetData.is_match\n", + "AVROData.is_match\n", + "GraphData.is_match\n", + "TextData.is_match\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "104a32c1-1d50-4aa5-94ce-b2e72de38476", + "metadata": {}, + "outputs": [], + "source": [ + "# supplemental function\n", + "def add_true_false_color(value):\n", + " \"\"\"Converts True to green and False to red in printed text.\"\"\"\n", + " if value:\n", + " return \"\\x1b[92m \" + str(is_match) + \"\\x1b[0m\"\n", + " return \"\\x1b[31m \" + str(is_match) + \"\\x1b[0m\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06868d90-2726-4096-a6da-3866174e6671", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from dataprofiler.data_readers.csv_data import CSVData\n", + "\n", + "\n", + "non_csv_files = [\n", + " 'json/iris-utf-8.json',\n", + " 'json/honeypot_intentially_mislabeled_file.csv',\n", + " 'parquet/titanic.parq',\n", + " 'parquet/nation.plain.intentionally_mislabled_file.csv',\n", + " 'txt/code.txt',\n", + " 'txt/sentence.txt',\n", + " 'avro/users.avro',\n", + " 'avro/snappy_compressed_intentionally_mislabeled_file.csv',\n", + "]\n", + "\n", + "print(\"Is the file a CSV?\")\n", + "print('=' * 80)\n", + "for file in csv_files:\n", + " filepath = os.path.join(data_folder, file)\n", + " is_match = CSVData.is_match(filepath)\n", + " print(add_true_false_color(is_match), ':', file)\n", + " print('=' * 80)\n", + " \n", + "for file in non_csv_files:\n", + " filepath = os.path.join(data_folder, file)\n", + " is_match = CSVData.is_match(filepath)\n", + " print(add_true_false_color(is_match), ':', file)\n", + " print('=' * 80)" + ] + }, + { + "cell_type": "markdown", + "id": "38889990-8e19-4114-a4f3-dc2af938e29d", + "metadata": {}, + "source": [ + "## Reloading data after altering options with `reload`\n", + "\n", + "There are two cases for using the reload function, both of which require the data type to have been interpreted correctly:\n", + "\n", + " 1. The options were not correctly determined\n", + " 2. The options were loaded correctly but a change is desired.\n", + " \n", + "In the example below, the `data_format` for reading the data is changed and the data is then reloaded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01870e8d-45ee-4f33-a088-4453c7ffc7c2", + "metadata": {}, + "outputs": [], + "source": [ + "filepath = \"../dataprofiler/tests/data/csv/diamonds.csv\"\n", + "\n", + "data = dp.Data(filepath)\n", + "print('original data:')\n", + "print('=' * 80)\n", + "print(data.data[:5])\n", + "\n", + "print()\n", + "data.reload(options={'data_format': 'records', 'record_samples_per_line': 1})\n", + "print('reloaded data:')\n", + "print('=' * 80)\n", + "data.data[:5]" + ] + }, + { + "cell_type": "markdown", + "id": "e2285f19-9b34-4484-beaa-79df890b2825", + "metadata": {}, + "source": [ + "## A deeper dive into `CSVData`\n", + "\n", + "This next section will focus on how to use the data reader class: `CSVData`. The `CSVData` class is used for reading delimited data. Delimited data are datasets which have their columns specified by a specific character, commonly the `,`. E.g. from the `diamonds.csv` dataset:\n", + "```\n", + "carat,cut,color,clarity,depth,table,price,x,y,z\n", + "0.23,Ideal,E,SI2,61.5,55,326,3.95,3.98,2.43\n", + "0.21,Premium,E,SI1,59.8,61,326,3.89,3.84,2.31\n", + "0.23,Good,E,VS1,56.9,65,327,4.05,4.07,2.31\n", + "0.29,Premium,I,VS2,62.4,58,334,4.2,4.23,2.63\n", + "0.31,Good,J,SI2,63.3,58,335,4.34,4.35,2.75\n", + "```\n", + "\n", + "However, the delimiter can be any character. Additionally, a `quotechar`, commonly `\"`, can be specified which allows a delimiter to be contained within a column value.\n", + "E.g. from the `blogposts.csv` dataset:\n", + "```\n", + "Blog Post,Date,Subject,Field\n", + "\"Monty Hall, meet Game Theory\",4/13/2014,Statistics,Mathematics\n", + "Gaussian Quadrature,4/13/2014,Algorithms,Mathematics\n", + "```\n", + "Notice how `\"Monty Hall, meet Game Theory\"` is contained by the quotechar because it contains the delimiter value `,`.\n", + "\n", + "These delimiter dataset parameters (and more) can be automatically determined by the `CSVData` data reader, however they can also be set via the options as demonstrated later in this tutorial." + ] + }, + { + "cell_type": "markdown", + "id": "cccb6bf9-7fb8-46b8-992e-9caacb7ab3a8", + "metadata": {}, + "source": [ + "## Intro to the `CSVData` data reader\n", + "\n", + "Previously, it was shown that `CSVData` may automatically be detected using `Data` or can be manually specified by the user:\n", + "\n", + "```python\n", + "import dataprofiler as dp\n", + "from dataprofiler.data_readers.csv_data import CSVData\n", + "\n", + "data = dp.Data(filepath)\n", + "data = CSVData(filepath)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e25f5130-4f19-40c5-9d13-549a04f1aef5", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read delimited data \n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "csv_files = [\n", + " \"csv/diamonds.csv\",\n", + " \"csv/all-strings-skip-header-author.csv\", # csv files with the author/description on the first line\n", + " \"csv/sparse-first-and-last-column-empty-first-row.txt\", # csv file with the .txt extension\n", + "]\n", + "\n", + "for file in csv_files:\n", + " data = CSVData(os.path.join(data_folder, file))\n", + " print(data.data.head())\n", + " print('=' * 80)" + ] + }, + { + "cell_type": "markdown", + "id": "8940de56-1417-4bf6-af87-9d4d00b9a631", + "metadata": {}, + "source": [ + "## CSVData Options\n", + "\n", + "As mentioned preivously, `CSVData` has options that can be set to finetune its detection or to ensure the data is being read in a specific manner.\n", + "The options for `CSVData` are detailed below:\n", + "\n", + " * delimiter - delimiter used to decipher the csv input file\n", + " * quotechar - quote character used in the delimited file\n", + " * header - location of the header in the file.\n", + " * data_format - user selected format in which to return data can only be of specified types\n", + " * selected_columns - columns being selected from the entire dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d74f2e8-0ec3-4e93-8778-0a5f013e0cdb", + "metadata": {}, + "outputs": [], + "source": [ + "# options are set via a dictionary object in which the parameters are specified.\n", + "# these are the default values for each option\n", + "options = {\n", + " \"delimiter\": \",\",\n", + " \"quotechar\": '\"',\n", + " \"header\": 'auto',\n", + " \"data_format\": \"dataframe\", # type: str, choices: \"dataframe\", \"records\"\n", + " \"selected_columns\": list(),\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "9af108a1-ffe6-4c3a-82cc-833b1a3b57a1", + "metadata": {}, + "source": [ + "## Options: delimiter and quotechar\n", + "\n", + "Below, both the auto detection and use of options will be illustrated for `delimiter` and `quotechar`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "570e20c3-198e-4356-98d3-92eb9655ef4e", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/daily-activity-sheet-@-singlequote.csv\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98385148-861e-4eb1-ba8d-e93120515401", + "metadata": {}, + "outputs": [], + "source": [ + "data = dp.Data(filepath) # or use CSVData\n", + "print('Auto detected')\n", + "print('=' * 80)\n", + "print('delimiter: ', data.delimiter)\n", + "print('quotechar: ', data.quotechar)\n", + "data.data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f5d9306-d90a-4fc6-85a7-a0d535fe2d80", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'delimiter': '@', 'quotechar': \"'\"}\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "print('manually set')\n", + "print('=' * 80)\n", + "print('delimiter: ', data.delimiter)\n", + "print('quotechar: ', data.quotechar)\n", + "data.data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7bfa60f-b5b9-48a5-adc5-3937aed145da", + "metadata": {}, + "outputs": [], + "source": [ + "# intentional failure with incorrect options\n", + "options = {'delimiter': ',', 'quotechar': '\"'}\n", + "\n", + "# will be interepted as TextData because the delimtier and quotechar were incorrect\n", + "data = dp.Data(filepath, options=options)\n", + "print('intentional faliure set')\n", + "print('=' * 80)\n", + "try:\n", + " print('delimiter: ', data.delimiter) # attribute error raised here, bc TextData, not CSVData\n", + " print('quotechar: ', data.quotechar)\n", + " \n", + " # should not reach this or something went wrong\n", + " raise Exception('Should have failed because this is detected as TextData.')\n", + "except AttributeError:\n", + " print('When data_type is not set or the CSVData is not set, it will fail over to the\\n'\n", + " 'next best reader. In this case it is \"TextData\"\\n')\n", + "data.data" + ] + }, + { + "cell_type": "markdown", + "id": "eeb41c7c-8319-40a3-9d87-88edbb3c5290", + "metadata": {}, + "source": [ + "## Options: header\n", + "\n", + "Below, both the auto detection and use of options will be illustrated for `header`.\n", + "\n", + "Notice how in the manually set mechanism, we are intentionally setting the header incorrectly to illustrate what happens." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16a927ef-1ba8-4bf2-ae40-2a9909030609", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/sparse-first-and-last-column-header-and-author-description.txt\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0701d7bf-2de0-4dce-8f09-7f0cddd1132c", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'header': 'auto'} # auto detected (default value)\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "print('Data Header:', data.header)\n", + "print('=' * 80)\n", + "data.data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8642a0a-367a-44c6-b611-b89d97b29f85", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'header': 2} # intentionally set incorrectly at value 2\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "print('Data Header:', data.header)\n", + "print('=' * 80)\n", + "data.data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "d6e3f640-c809-4eb6-9571-30065821615e", + "metadata": {}, + "source": [ + "## Options: data_format\n", + "\n", + "For CSVData, the `data_format` option can have the following values:\n", + "\n", + " * dataframe - (default) loads the dataset as a pandas.DataFrame\n", + " * records - loads the data as rows of text values, the extra parameter `record_samples_per_line` how many rows are combined into a single line\n", + " \n", + "`dataframe` is used for conducting **structured profiling** of the dataset while `records` is for **unstructured profiling**.\n", + "\n", + "Below, both the auto detection and use of options will be illustrated for `data_format`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "146109ea-a554-4766-bb19-78c116d2a8dd", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/diamonds.csv\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dceac967-d326-4064-ba1c-87a1146c9d72", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'data_format': 'dataframe'} # default\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "data.data[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c25524f-ef23-4e06-9023-842c64c2640e", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'data_format': 'records', 'record_samples_per_line': 1}\n", + "data = dp.Data(filepath, options=options)\n", + "data.data[:5]" + ] + }, + { + "cell_type": "markdown", + "id": "d45f3ed6-ddcd-4bf3-95bc-09f23eb94c97", + "metadata": {}, + "source": [ + "## Options: selected columns\n", + "\n", + "By default, all columns of a dataset will be read and loaded into the data reader. However, `selected_columns` can be set to only load columns which the user requests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9b45e18-93c6-42e6-b978-af51574307eb", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "018f3f4d-32ac-411a-9918-bae78aff0b0e", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'selected_columns': ['datetime', 'host', 'src', 'proto']}\n", + "data = dp.Data(filepath, options=options)\n", + "data.data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "b50679ea", + "metadata": {}, + "source": [ + "## Intro to `GraphData` data reader\n", + "\n", + "This tutorial will focus on how to use the data reader class: `GraphData`. The `GraphData` class is used for reading the delimited data from a CSV file into a `NetworkX` Graph object. This is all in an effort to prepare the data automaticaly for `GraphProfiler` class to then profile graph data. \n", + "\n", + "The DataProiler keys off of common graph naming conventions in the column header row. E.G. from `dataprofiler/tests/csv/graph_data_csv_identify.csv`\n", + "```\n", + "node_id_dst, node_id_src, continuous_weight, categorical_status\n", + "108,289,7.4448069,9\n", + "81,180,3.65064207,0\n", + "458,83,5.9959787,10\n", + "55,116,4.63359209,79\n", + "454,177,5.76715529,11\n", + "429,225,4.79556889,3\n", + "```\n", + "\n", + "Options for the `GraphData` are exactly the same as `CSVData`.\n", + "\n", + "\n", + "Example implementation of `GraphData`:\n", + "```python\n", + "import dataprofiler as dp\n", + "from dataprofiler.data_readers.graph_data import GraphData\n", + "\n", + "data = dp.Data(graph_file)\n", + "data = GraphData(graph_file)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "838db976", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprofiler.data_readers.graph_data import GraphData\n", + "\n", + "# use data reader to read delimited data \n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "graph_file = \"csv/graph_data_csv_identify.csv\"\n", + "\n", + "data = GraphData(os.path.join(data_folder, graph_file))\n", + "print(data.data.edges)\n", + "print('=' * 80)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/graph_data_demo.ipynb b/docs/0.10.3/doctrees/nbsphinx/graph_data_demo.ipynb new file mode 100644 index 000000000..088612872 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/graph_data_demo.ipynb @@ -0,0 +1,271 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Graph Pipeline Demo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "DataProfiler can also load and profile graph datasets. Similarly to the rest of DataProfiler profilers, this is split into two components:\n", + "- GraphData\n", + "- GraphProfiler\n", + "\n", + "We will demo the use of this graph pipeline.\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import pprint\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now input our dataset into the generic DataProfiler pipeline:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/graph_data_csv_identify.csv\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "report = profile.report()\n", + "\n", + "pp = pprint.PrettyPrinter(sort_dicts=False, compact=True)\n", + "pp.pprint(report)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We notice that the `Data` class automatically detected the input file as graph data. The `GraphData` class is able to differentiate between tabular and graph csv data. After `Data` matches the input file as graph data, `GraphData` does the necessary work to load the csv data into a NetworkX Graph. \n", + "\n", + "`Profiler` runs `GraphProfiler` when graph data is input (or when `data_type=\"graph\"` is specified). The `report()` function outputs the profile for the user." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Profile" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The profile skeleton looks like this:\n", + "```\n", + "profile = {\n", + " \"num_nodes\": ...,\n", + " \"num_edges\": ...,\n", + " \"categorical_attributes\": ...,\n", + " \"continuous_attributes\": ...,\n", + " \"avg_node_degree\": ...,\n", + " \"global_max_component_size\": ...,\n", + " \"continuous_distribution\": ...,\n", + " \"categorical_distribution\": ...,\n", + " \"times\": ...,\n", + "}\n", + "```\n", + "\n", + "Description of properties in profile:\n", + "- `num_nodes`: number of nodes in the graph\n", + "- `num_edges`: number of edges in the graph\n", + "- `categorical_attributes`: list of categorical edge attributes\n", + "- `continuous_attributes`: list of continuous edge attributes\n", + "- `avg_node_degree`: average degree of nodes in the graph\n", + "- `global_max_component_size`: size of largest global max component in the graph\n", + "- `continuous_distribution`: dictionary of statistical properties for each continuous attribute\n", + "- `categorical_distribution`: dictionary of statistical properties for each categorical attribute\n", + "\n", + "The `continuous_distribution` and `categorical_distribution` dictionaries list statistical properties for each edge attribute in the graph:\n", + "```\n", + "continuous_distribution = {\n", + " \"name\": ...,\n", + " \"scale\": ...,\n", + " \"properties\": ...,\n", + "}\n", + "```\n", + "```\n", + "categorical_distribution = {\n", + " \"bin_counts\": ...,\n", + " \"bin_edges\": ...,\n", + "}\n", + "```\n", + "Description of each attribute:\n", + "- Continuous distribution:\n", + " - `name`: name of the distribution\n", + " - `scale`: negative log likelihood used to scale distributions and compare them in `GraphProfiler`\n", + " - `properties`: list of distribution props\n", + "- Categorical distribution:\n", + " - `bin_counts`: histogram bin counts\n", + " - `bin_edges`: histogram bin edges\n", + "\n", + "`properties` lists the following distribution properties: [optional: shape, loc, scale, mean, variance, skew, kurtosis]. The list can be either 6 length or 7 length depending on the distribution (extra shape parameter):\n", + "- 6 length: norm, uniform, expon, logistic\n", + "- 7 length: gamma, lognorm\n", + " - gamma: shape=`a` (float)\n", + " - lognorm: shape=`s` (float)\n", + " \n", + "For more information on shape parameters `a` and `s`: https://docs.scipy.org/doc/scipy/tutorial/stats.html#shape-parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Saving and Loading a Profile\n", + "Below you will see an example of how a Graph Profile can be saved and loaded again." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The default save filepath is profile-.pkl\n", + "profile.save(filepath=\"profile.pkl\")\n", + "\n", + "new_profile = dp.GraphProfiler.load(\"profile.pkl\")\n", + "new_report = new_profile.report()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pp.pprint(report)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Difference in Data\n", + "If we wanted to ensure that this new profile was the same as the previous profile that we loaded, we could compare them using the diff functionality." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "diff = profile.diff(new_profile)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pp.pprint(diff)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another use for diff might be to provide differences between training and testing profiles as shown in the cell below.\n", + "We will use the profile above as the training profile and create a new profile to represent the testing profile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "training_profile = profile\n", + "\n", + "testing_data = dp.Data(os.path.join(data_path, \"csv/graph-differentiator-input-positive.csv\"))\n", + "testing_profile = dp.Profiler(testing_data)\n", + "\n", + "test_train_diff = training_profile.diff(testing_profile)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below you can observe the difference between the two profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pp.pprint(test_train_diff)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have shown the graph pipeline in the DataProfiler. It works similarly to the current DataProfiler implementation." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/labeler.ipynb b/docs/0.10.3/doctrees/nbsphinx/labeler.ipynb new file mode 100644 index 000000000..af31b68c5 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/labeler.ipynb @@ -0,0 +1,650 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "spoken-reunion", + "metadata": {}, + "source": [ + "# Sensitive Data Detection with the Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "interesting-bidder", + "metadata": {}, + "source": [ + "In this example, we utilize the Labeler component of the Data Profiler to detect the sensitive information for both structured and unstructured data. In addition, we show how to train the Labeler on some specific dataset with different list of entities.\n", + "\n", + "First, let's dive into what the Labeler is." + ] + }, + { + "cell_type": "markdown", + "id": "1965b83b", + "metadata": {}, + "source": [ + "## What is the Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "388c643f", + "metadata": {}, + "source": [ + "The Labeler is a pipeline designed to make building, training, and predictions with ML models quick and easy. There are 3 major components to the Labeler: the preprocessor, the model, and the postprocessor." + ] + }, + { + "cell_type": "markdown", + "id": "e5d0aeb4", + "metadata": {}, + "source": [ + "![alt text](DL-Flowchart.png \"Title\")" + ] + }, + { + "cell_type": "markdown", + "id": "550323c7", + "metadata": {}, + "source": [ + "Each component can be switched out individually to suit your needs. As you might expect, the preprocessor takes in raw data and prepares it for the model, the model performs the prediction or training, and the postprocessor takes prediction results and turns them into human-readable results. \n", + "\n", + "Now let's run some examples. Start by importing all the requirements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "scientific-stevens", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "import pandas as pd\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "# remove extra tf loggin\n", + "import tensorflow as tf\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "id": "5125b215", + "metadata": {}, + "source": [ + "## Structured Data Prediction" + ] + }, + { + "cell_type": "markdown", + "id": "wicked-devon", + "metadata": {}, + "source": [ + "We'll use the aws honeypot dataset in the test folder for this example. First, look at the data using the Data Reader class of the Data Profiler. This dataset is from the US department of educations, [found here!](https://data.ed.gov/dataset/college-scorecard-all-data-files-through-6-2020/resources?resource=823ac095-bdfc-41b0-b508-4e8fc3110082)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "adjusted-native", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "data = dp.Data(\"../dataprofiler/tests/data/csv/SchoolDataSmall.csv\")\n", + "df_data = data.data\n", + "df_data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "ab6ccf8a", + "metadata": {}, + "source": [ + "We can directly predict the labels of a structured dataset on the cell level." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19529af4", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "labeler = dp.DataLabeler(labeler_type='structured')\n", + "\n", + "# print out the labels and label mapping\n", + "print(\"Labels: {}\".format(labeler.labels)) \n", + "print(\"\\n\")\n", + "print(\"Label Mapping: {}\".format(labeler.label_mapping))\n", + "print(\"\\n\")\n", + "\n", + "# make predictions and get labels for each cell going row by row\n", + "# predict options are model dependent and the default model can show prediction confidences\n", + "predictions = labeler.predict(data, predict_options={\"show_confidences\": True})\n", + "\n", + "# display prediction results\n", + "print(\"Predictions: {}\".format(predictions['pred']))\n", + "print(\"\\n\")\n", + "\n", + "# display confidence results\n", + "print(\"Confidences: {}\".format(predictions['conf']))" + ] + }, + { + "cell_type": "markdown", + "id": "2af72e2c", + "metadata": {}, + "source": [ + "The profiler uses the Labeler to perform column by column predictions. The data contains 11 columns, each of which has data label. Next, we will use the Labeler of the Data Profiler to predict the label for each column in this tabular dataset. Since we are only going to demo the labeling functionality, other options of the Data Profiler are disabled to keep this quick." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6cb9d7e-149a-4cfe-86f8-76c47c57aeea", + "metadata": {}, + "outputs": [], + "source": [ + "# helper functions for printing results\n", + "\n", + "def get_structured_results(results):\n", + " \"\"\"Helper function to get data labels for each column.\"\"\"\n", + " columns = []\n", + " predictions = []\n", + " samples = []\n", + " for col in results['data_stats']:\n", + " columns.append(col['column_name'])\n", + " predictions.append(col['data_label'])\n", + " samples.append(col['samples'])\n", + "\n", + " df_results = pd.DataFrame({'Column': columns, 'Prediction': predictions, 'Sample': samples})\n", + " return df_results\n", + "\n", + "def get_unstructured_results(data, results):\n", + " \"\"\"Helper function to get data labels for each labeled piece of text.\"\"\"\n", + " labeled_data = []\n", + " for pred in results['pred'][0]:\n", + " labeled_data.append([data[0][pred[0]:pred[1]], pred[2]])\n", + " label_df = pd.DataFrame(labeled_data, columns=['Text', 'Labels'])\n", + " return label_df\n", + " \n", + "\n", + "pd.set_option('display.width', 100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "secret-million", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# set options to only run the labeler\n", + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({\"structured_options.text.is_enabled\": False, \n", + " \"int.is_enabled\": False, \n", + " \"float.is_enabled\": False, \n", + " \"order.is_enabled\": False, \n", + " \"category.is_enabled\": False, \n", + " \"chi2_homogeneity.is_enabled\": False,\n", + " \"datetime.is_enabled\": False,})\n", + "\n", + "profile = dp.Profiler(data, options=profile_options)\n", + "\n", + "results = profile.report() \n", + "print(get_structured_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "fatty-louisville", + "metadata": {}, + "source": [ + "In this example, the results show that the Data Profiler is able to detect integers, URLs, address, and floats appropriately. Unknown is typically strings of text, which is appropriate for those columns." + ] + }, + { + "cell_type": "markdown", + "id": "unavailable-diploma", + "metadata": {}, + "source": [ + "## Unstructured Data Prediction" + ] + }, + { + "cell_type": "markdown", + "id": "metallic-coaching", + "metadata": {}, + "source": [ + "Besides structured data, the Labeler detects the sensitive information on the unstructured text. We use a sample of spam email in Enron email dataset for this demo. As above, we start investigating the content of the given email sample." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "unauthorized-lounge", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# load data\n", + "data = \"Message-ID: <11111111.1111111111111.JavaMail.evans@thyme>\\n\" + \\\n", + " \"Date: Fri, 10 Aug 2005 11:31:37 -0700 (PDT)\\n\" + \\\n", + " \"From: w..smith@company.com\\n\" + \\\n", + " \"To: john.smith@company.com\\n\" + \\\n", + " \"Subject: RE: ABC\\n\" + \\\n", + " \"Mime-Version: 1.0\\n\" + \\\n", + " \"Content-Type: text/plain; charset=us-ascii\\n\" + \\\n", + " \"Content-Transfer-Encoding: 7bit\\n\" + \\\n", + " \"X-From: Smith, Mary W. \\n\" + \\\n", + " \"X-To: Smith, John \\n\" + \\\n", + " \"X-cc: \\n\" + \\\n", + " \"X-bcc: \\n\" + \\\n", + " \"X-Folder: \\SSMITH (Non-Privileged)\\Sent Items\\n\" + \\\n", + " \"X-Origin: Smith-S\\n\" + \\\n", + " \"X-FileName: SSMITH (Non-Privileged).pst\\n\\n\" + \\\n", + " \"All I ever saw was the e-mail from the office.\\n\\n\" + \\\n", + " \"Mary\\n\\n\" + \\\n", + " \"-----Original Message-----\\n\" + \\\n", + " \"From: Smith, John \\n\" + \\\n", + " \"Sent: Friday, August 10, 2005 13:07 PM\\n\" + \\\n", + " \"To: Smith, Mary W.\\n\" + \\\n", + " \"Subject: ABC\\n\\n\" + \\\n", + " \"Have you heard any more regarding the ABC sale? I guess that means that \" + \\\n", + " \"it's no big deal here, but you think they would have send something.\\n\\n\\n\" + \\\n", + " \"John Smith\\n\" + \\\n", + " \"123-456-7890\\n\"\n", + "\n", + "# convert string data to list to feed into the labeler\n", + "data = [data]" + ] + }, + { + "cell_type": "markdown", + "id": "concerned-segment", + "metadata": {}, + "source": [ + "By default, the Labeler predicts the results at the character level for unstructured text." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "junior-acrobat", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "labeler = dp.DataLabeler(labeler_type='unstructured')\n", + "\n", + "# make predictions and get labels per character\n", + "predictions = labeler.predict(data)\n", + "\n", + "# display results\n", + "print(predictions['pred'])" + ] + }, + { + "cell_type": "markdown", + "id": "individual-diabetes", + "metadata": {}, + "source": [ + "In addition to the character-level result, the Labeler provides the results at the word level following the standard NER (Named Entity Recognition), e.g., utilized by spaCy. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "optical-universe", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# convert prediction to word format and ner format\n", + "# Set the output to the NER format (start position, end position, label)\n", + "labeler.set_params(\n", + " { 'postprocessor': { 'output_format':'ner', 'use_word_level_argmax':True } } \n", + ")\n", + "\n", + "# make predictions and get labels per character\n", + "predictions = labeler.predict(data)\n", + "\n", + "# display results\n", + "print('\\n')\n", + "print('=======================Prediction======================\\n')\n", + "for pred in predictions['pred'][0]:\n", + " print('{}: {}'.format(data[0][pred[0]: pred[1]], pred[2]))\n", + " print('--------------------------------------------------------')" + ] + }, + { + "cell_type": "markdown", + "id": "behavioral-tourism", + "metadata": {}, + "source": [ + "Here, the Labeler is able to identify sensitive information such as datetime, email address, person names, and phone number in an email sample. " + ] + }, + { + "cell_type": "markdown", + "id": "nasty-disney", + "metadata": {}, + "source": [ + "## Train the Labeler from Scratch" + ] + }, + { + "cell_type": "markdown", + "id": "destroyed-twist", + "metadata": {}, + "source": [ + "The Labeler can be trained from scratch with a new list of labels. Below, we show an example of training the Labeler on a dataset with labels given as the columns of that dataset. For brevity's sake, let's only train a few epochs with a subset of a dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "utility-evaluation", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "data = dp.Data(\"../dataprofiler/tests/data/csv/SchoolDataSmall.csv\")\n", + "df = data.data[[\"OPEID6\", \"INSTURL\", \"SEARCH_STRING\"]]\n", + "df.head()\n", + "\n", + "# split data to training and test set\n", + "split_ratio = 0.2\n", + "df = df.sample(frac=1).reset_index(drop=True)\n", + "data_train = df[:int((1 - split_ratio) * len(df))]\n", + "data_test = df[int((1 - split_ratio) * len(df)):]\n", + "\n", + "# train a new labeler with column names as labels\n", + "if not os.path.exists('data_labeler_saved'):\n", + " os.makedirs('data_labeler_saved')\n", + "\n", + "labeler = dp.train_structured_labeler(\n", + " data=data_train,\n", + " save_dirpath=\"data_labeler_saved\",\n", + " epochs=10,\n", + " default_label=\"OPEID6\"\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "utility-torture", + "metadata": {}, + "source": [ + "The trained Labeler is then used by the Data Profiler to provide the prediction on the new dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "answering-panel", + "metadata": {}, + "outputs": [], + "source": [ + "# predict with the labeler object\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_object': labeler})\n", + "profile = dp.Profiler(data_test, options=profile_options)\n", + "\n", + "# get the prediction from the data profiler\n", + "results = profile.report()\n", + "print(get_structured_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "polish-stand", + "metadata": {}, + "source": [ + "Another way to use the trained Labeler is through the directory path of the saved labeler." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "industrial-characterization", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# predict with the labeler loaded from path\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_dirpath': 'data_labeler_saved'})\n", + "profile = dp.Profiler(data_test, options=profile_options)\n", + "\n", + "# get the prediction from the data profiler\n", + "results = profile.report()\n", + "print(get_structured_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "2acedba0", + "metadata": {}, + "source": [ + "## Transfer Learning a Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "2f15fb1f", + "metadata": {}, + "source": [ + "Instead of training a model from scratch, we can also transfer learn to improve the model and/or extend the labels. Again for brevity's sake, let's only train a few epochs with a small dataset at the cost of accuracy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0104c374", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "data = dp.Data(\"../dataprofiler/tests/data/csv/SchoolDataSmall.csv\")\n", + "df_data = data.data[[\"OPEID6\", \"INSTURL\", \"SEARCH_STRING\"]]\n", + "\n", + "\n", + "# prep data\n", + "df_data = df_data.reset_index(drop=True).melt()\n", + "df_data.columns = [1, 0] # labels=1, values=0 in that order\n", + "df_data = df_data.astype(str)\n", + "new_labels = df_data[1].unique().tolist()\n", + "\n", + "# load structured Labeler w/ trainable set to True\n", + "labeler = dp.DataLabeler(labeler_type='structured', trainable=True)\n", + "\n", + "# Reconstruct the model to add each new label\n", + "for label in new_labels:\n", + " labeler.add_label(label)\n", + "\n", + "# this will use transfer learning to retrain the labeler on your new\n", + "# dataset and labels.\n", + "# Setting labels with a list of labels or label mapping will overwrite the existing labels with new ones\n", + "# Setting the reset_weights parameter to false allows transfer learning to occur\n", + "model_results = labeler.fit(x=df_data[0], y=df_data[1], validation_split=0.2, \n", + " epochs=10, labels=None, reset_weights=False)" + ] + }, + { + "cell_type": "markdown", + "id": "ae78745f", + "metadata": {}, + "source": [ + "Let's display the training results of the last epoch:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b764aa8c", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "print(\"{:16s} Precision Recall F1-score Support\".format(\"\"))\n", + "for item in model_results[-1][2]:\n", + " print(\"{:16s} {:4.3f} {:4.3f} {:4.3f} {:7.0f}\".format(item,\n", + " model_results[-1][2][item][\"precision\"],\n", + " model_results[-1][2][item][\"recall\"],\n", + " model_results[-1][2][item][\"f1-score\"],\n", + " model_results[-1][2][item][\"support\"]))" + ] + }, + { + "cell_type": "markdown", + "id": "44009522", + "metadata": {}, + "source": [ + "It is now trained to detect additional labels! The model results here show all the labels training accuracy. Since only new labels existed in the dataset, only the new labels are given accuracy scores. Keep in mind this is a small dataset for brevity's sake and that real training would involve more samples and better results." + ] + }, + { + "cell_type": "markdown", + "id": "e110ee1c", + "metadata": {}, + "source": [ + "## Saving and Loading a Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "c484d193", + "metadata": {}, + "source": [ + "The Labeler can easily be saved or loaded with one simple line." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d8684fa", + "metadata": {}, + "outputs": [], + "source": [ + "# Ensure save directory exists\n", + "if not os.path.exists('my_labeler'):\n", + " os.makedirs('my_labeler')\n", + "\n", + "# Saving the labeler\n", + "labeler.save_to_disk(\"my_labeler\")\n", + "\n", + "# Loading the labeler\n", + "labeler = dp.DataLabeler(labeler_type='structured', dirpath=\"my_labeler\")" + ] + }, + { + "cell_type": "markdown", + "id": "8d36dec8", + "metadata": {}, + "source": [ + "## Building a Labeler from the Ground Up" + ] + }, + { + "cell_type": "markdown", + "id": "59346d2b", + "metadata": {}, + "source": [ + "As mentioned earlier, the labeler is comprised of three components, and each of the compenents can be created and interchanged in the the labeler pipeline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6506ef97", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from dataprofiler.labelers.character_level_cnn_model import \\\n", + " CharacterLevelCnnModel\n", + "from dataprofiler.labelers.data_processing import \\\n", + " StructCharPreprocessor, StructCharPostprocessor\n", + "\n", + "model = CharacterLevelCnnModel({\"PAD\":0, \"UNKNOWN\":1, \"Test_Label\":2})\n", + "preprocessor = StructCharPreprocessor()\n", + "postprocessor = StructCharPostprocessor()\n", + "\n", + "labeler = dp.DataLabeler(labeler_type='structured')\n", + "labeler.set_preprocessor(preprocessor)\n", + "labeler.set_model(model)\n", + "labeler.set_postprocessor(postprocessor)\n", + "\n", + "# check for basic compatibility between the processors and the model\n", + "labeler.check_pipeline()\n", + "\n", + "# Optionally set the parameters\n", + "parameters={\n", + " 'preprocessor':{\n", + " 'max_length': 100,\n", + " },\n", + " 'model':{\n", + " 'max_length': 100,\n", + " },\n", + " 'postprocessor':{\n", + " 'random_state': random.Random(1)\n", + " }\n", + "} \n", + "labeler.set_params(parameters)\n", + "\n", + "labeler.help()" + ] + }, + { + "cell_type": "markdown", + "id": "5f020d7f", + "metadata": {}, + "source": [ + "The components can each be created if you inherit the BaseModel and BaseProcessor for the model and processors, respectively. More info can be found about coding your own components in the Labeler section of the [documentation]( https://capitalone.github.io/dataprofiler). In summary, the Data Profiler open source library can be used to scan sensitive information in both structured and unstructured data with different file types. It supports multiple input formats and output formats at word and character levels. Users can also train the labeler on their own datasets." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/merge_profile_list.ipynb b/docs/0.10.3/doctrees/nbsphinx/merge_profile_list.ipynb new file mode 100644 index 000000000..4654caf8f --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/merge_profile_list.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "60af5256", + "metadata": {}, + "source": [ + "# Merge List of Profiles\n", + "\n", + "This is an example of a new utils in the dataprofiler for distributed merging of profile objects. This assumes the user is providing a list of profile objects to the utils function for merging all the profiles together." + ] + }, + { + "cell_type": "markdown", + "id": "7eee37ff", + "metadata": {}, + "source": [ + "## Imports\n", + "\n", + "Let's start by importing the necessary packages..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0d27009", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "\n", + "import pandas as pd\n", + "import tensorflow as tf\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + " from dataprofiler.profilers.utils import merge_profile_list\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + " from dataprofiler.profilers.utils import merge_profile_list\n", + "\n", + "# remove extra tf loggin\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "id": "b4369e64", + "metadata": {}, + "source": [ + "## Setup the Data and Profiler" + ] + }, + { + "cell_type": "markdown", + "id": "410c3c4d", + "metadata": {}, + "source": [ + "This section shows the basic example of the Data Profiler. \n", + "\n", + "1. Instantiate a Pandas dataframe with dummy data\n", + "2. Pass the dataframe to the `Profiler` and instantiate two separate profilers in a list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3567c82", + "metadata": {}, + "outputs": [], + "source": [ + "d = {'col1': [1, 2], 'col2': [3, 4]}\n", + "df = pd.DataFrame(data=d)\n", + "\n", + "list_of_profiles = [dp.Profiler(df), dp.Profiler(df)]" + ] + }, + { + "cell_type": "markdown", + "id": "350502eb", + "metadata": {}, + "source": [ + "Take a look at the list of profiles... " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b649db32", + "metadata": {}, + "outputs": [], + "source": [ + "list_of_profiles" + ] + }, + { + "cell_type": "markdown", + "id": "4ed4fc12", + "metadata": {}, + "source": [ + "## Run Merge on List of Profiles\n", + "\n", + "Now let's merge the list of profiles into a `single_profile`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a636047", + "metadata": {}, + "outputs": [], + "source": [ + "single_profile = merge_profile_list(list_of_profiles=list_of_profiles)" + ] + }, + { + "cell_type": "markdown", + "id": "0aa88720", + "metadata": {}, + "source": [ + "And check out the `.report` on the single profile:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34059c21", + "metadata": {}, + "outputs": [], + "source": [ + "single_profile.report()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "dataprofiler", + "language": "python", + "name": "dataprofiler" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/overview.ipynb b/docs/0.10.3/doctrees/nbsphinx/overview.ipynb new file mode 100644 index 000000000..d5e77abe4 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/overview.ipynb @@ -0,0 +1,470 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fc2826d9", + "metadata": {}, + "source": [ + "# Data Profiler - What's in your data?" + ] + }, + { + "cell_type": "markdown", + "id": "b997522b", + "metadata": {}, + "source": [ + "This introductory jupyter notebook demonstrates the basic usages of the Data Profiler. The library is designed to easily detect sensitive data and gather statistics on your datasets with just several lines of code. The Data Profiler can handle several different data types including: CSV (or any delimited file), JSON, Parquet, AVRO, and text. Additionally, there are a plethora of options to customize your profile. This library also has the ability to update profiles from multiple batches of large datasets, or merge multiple profiles. In particular, this example covers the followings:\n", + "\n", + "- Basic usage of the Data Profiler\n", + "- The data reader class\n", + "- Profiler options\n", + "- Updating profiles and merging profiles\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef404c84", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "sys.path.insert(0, '..')\n", + "import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"" + ] + }, + { + "cell_type": "markdown", + "id": "f51971e3", + "metadata": {}, + "source": [ + "## Basic Usage of the Data Profiler" + ] + }, + { + "cell_type": "markdown", + "id": "639e66d3", + "metadata": {}, + "source": [ + "This section shows the basic example of the Data Profiler. A CSV dataset is read using the data reader, then the Data object is given to the Data Profiler to detect sensitive data and obtain the statistics." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5379c45c", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# use data reader to read input data\n", + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "print(data.data.head())\n", + "\n", + "# run data profiler and get the report\n", + "profile = dp.Profiler(data)\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "57fe2827", + "metadata": {}, + "source": [ + "The report includes `global_stats` and `data_stats` for the given dataset. The former contains overall properties of the data such as number of rows/columns, null ratio, duplicate ratio, while the latter contains specific properties and statistics for each column such as detected data label, min, max, mean, variance, etc. In this example, the `compact` format of the report is used to shorten the full list of the results. To get more results related to detailed predictions at the entity level from the Data Labeler component or histogram results, the format `pretty` should be used." + ] + }, + { + "cell_type": "markdown", + "id": "74027cfd", + "metadata": {}, + "source": [ + "## Data reader class" + ] + }, + { + "cell_type": "markdown", + "id": "41364888", + "metadata": {}, + "source": [ + "DataProfiler can detect multiple file types including CSV (or any delimited file), JSON, Parquet, AVRO, and text. The example below shows that it successfully detects data types from multiple categories regardless of the file extensions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "823829f4", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read input data with different file types\n", + "csv_files = [\n", + " \"csv/aws_honeypot_marx_geo.csv\",\n", + " \"csv/all-strings-skip-header-author.csv\", # csv files with the author/description on the first line\n", + " \"csv/sparse-first-and-last-column-empty-first-row.txt\", # csv file with the .txt extension\n", + "]\n", + "json_files = [\n", + " \"json/complex_nested.json\",\n", + " \"json/honeypot_intentially_mislabeled_file.csv\", # json file with the .csv extension\n", + "]\n", + "parquet_files = [\n", + " \"parquet/nation.dict.parquet\",\n", + " \"parquet/nation.plain.intentionally_mislabled_file.csv\", # parquet file with the .csv extension\n", + "]\n", + "avro_files = [\n", + " \"avro/userdata1.avro\",\n", + " \"avro/userdata1_intentionally_mislabled_file.json\", # avro file with the .json extension\n", + "]\n", + "text_files = [\n", + " \"txt/discussion_reddit.txt\",\n", + "]\n", + "\n", + "all_files = {\n", + " \"csv\": csv_files,\n", + " \"json\": json_files,\n", + " \"parquet\": parquet_files,\n", + " \"avro\": avro_files,\n", + " \"text\": text_files\n", + "}\n", + "\n", + "for file_type in all_files:\n", + " print(file_type)\n", + " for file in all_files[file_type]:\n", + " data = dp.Data(os.path.join(data_path, file))\n", + " print(\"{:<85} {:<15}\".format(file, data.data_type))\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "3f9d7e02", + "metadata": {}, + "source": [ + "The `Data` class detects the file type and uses one of the following classes: `CSVData`, `JSONData`, `ParquetData`, `AVROData`, `TextData`. Users can call these specific classes directly if desired. For example, below we provide a collection of data with different types, each of them is processed by the corresponding data class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "831e68a3", + "metadata": {}, + "outputs": [], + "source": [ + "# use individual data reader classes\n", + "from dataprofiler.data_readers.csv_data import CSVData\n", + "from dataprofiler.data_readers.json_data import JSONData\n", + "from dataprofiler.data_readers.parquet_data import ParquetData\n", + "from dataprofiler.data_readers.avro_data import AVROData\n", + "from dataprofiler.data_readers.text_data import TextData\n", + "\n", + "csv_files = \"csv/aws_honeypot_marx_geo.csv\"\n", + "json_files = \"json/complex_nested.json\"\n", + "parquet_files = \"parquet/nation.dict.parquet\"\n", + "avro_files = \"avro/userdata1.avro\"\n", + "text_files = \"txt/discussion_reddit.txt\"\n", + "\n", + "all_files = {\n", + " \"csv\": [csv_files, CSVData],\n", + " \"json\": [json_files, JSONData],\n", + " \"parquet\": [parquet_files, ParquetData],\n", + " \"avro\": [avro_files, AVROData],\n", + " \"text\": [text_files, TextData],\n", + "}\n", + "\n", + "for file_type in all_files:\n", + " file, data_reader = all_files[file_type]\n", + " data = data_reader(os.path.join(data_path, file))\n", + " print(\"File name {}\\n\".format(file))\n", + " if file_type == \"text\":\n", + " print(data.data[0][:1000]) # print the first 1000 characters\n", + " else:\n", + " print(data.data)\n", + " print('===============================================================================')" + ] + }, + { + "cell_type": "markdown", + "id": "572df0a8", + "metadata": {}, + "source": [ + "In addition to reading the input data from multiple file types, the Data Profiler allows the input data as a dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df87ab83", + "metadata": {}, + "outputs": [], + "source": [ + "# run data profiler and get the report\n", + "my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]], columns=[\"col_int\", \"col_float\"])\n", + "profile = dp.Profiler(my_dataframe)\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "84a06312", + "metadata": {}, + "source": [ + "## Structured Profiler vs. Unstructured Profiler" + ] + }, + { + "cell_type": "markdown", + "id": "4c0ea925", + "metadata": {}, + "source": [ + "The profiler will infer what type of statistics to generate (structured or unstructured) based on the input. However, you can explicitly specify profile type as well. Here is an example of the the profiler explicitly calling the structured profile and the unstructured profile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f4565d8", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# Using the structured profiler\n", + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "profile = dp.Profiler(data, profiler_type='structured')\n", + "\n", + "report = profile.report(report_options={\"output_format\": \"pretty\"})\n", + "print(json.dumps(report, indent=4))\n", + "\n", + "# Using the unstructured profiler\n", + "my_dataframe = pd.DataFrame([[\"Sample1\"],[\"Sample2\"],[\"Sample3\"]], columns=[\"Text_Samples\"])\n", + "profile = dp.Profiler(my_dataframe, profiler_type='unstructured')\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "b16648ba", + "metadata": {}, + "source": [ + "## Profiler options" + ] + }, + { + "cell_type": "markdown", + "id": "8b0cc8ad", + "metadata": {}, + "source": [ + "The Data Profiler can enable/disable statistics and modify features through profiler options. For example, if the users only want the statistics information, they may turn off the Data Labeler functionality. Below, let's remove the histogram and data labeler component while running Data Profiler." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbac3a2c", + "metadata": {}, + "outputs": [], + "source": [ + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({\"histogram_and_quantiles.is_enabled\": False,\n", + " \"median_abs_deviation.is_enabled\": False,\n", + " \"median.is_enabled\": False,\n", + " \"mode.is_enabled\": False,\n", + " \"data_labeler.is_enabled\": False,})\n", + "\n", + "profile = dp.Profiler(my_dataframe, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "590ca50b", + "metadata": {}, + "source": [ + "Besides toggling on and off features, other options like the data labeler sample size or histogram bin method can be directly set and validated as shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ed21bc1", + "metadata": {}, + "outputs": [], + "source": [ + "profile_options = dp.ProfilerOptions()\n", + "profile_options.structured_options.data_labeler.sample_size = 1\n", + "profile_options.structured_options.int.histogram_and_quantiles.bin_count_or_method = \"rice\"\n", + "# An error will raise if the options are set incorrectly.\n", + "profile_options.validate()\n", + "\n", + "profile = dp.Profiler(my_dataframe, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "9f690616", + "metadata": {}, + "source": [ + "## Update profiles" + ] + }, + { + "cell_type": "markdown", + "id": "965f8c85", + "metadata": {}, + "source": [ + "One of the interesting features of the Data Profiler is the ability to update profiles from batches of data, which allows for data streaming usage. In this section, the original dataset is separated into two batches with equal size. Each batch is then updated with Data Profiler sequentially. \n", + "\n", + "After the update, we expect the resulted profiles give the same statistics as the profiles updated from the full dataset. We will verify that through some properties in `global_stats` of the profiles including `column_count`, `row_count`, `row_is_null_ratio`, `duplicate_row_count`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34ac4346", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# read the input data and devide it into two equal halves\n", + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "df = data.data\n", + "df1 = df.iloc[:int(len(df)/2)]\n", + "df2 = df.iloc[int(len(df)/2):]\n", + "\n", + "# Update the profile with the first half\n", + "profile = dp.Profiler(df1)\n", + "\n", + "# Update the profile with the second half\n", + "profile.update_profile(df2)\n", + "\n", + "# Update profile with the full dataset\n", + "profile_full = dp.Profiler(df)\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "report_full = profile_full.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# print the report\n", + "print(json.dumps(report, indent=4))\n", + "print(json.dumps(report_full, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "b41ee2bf", + "metadata": {}, + "source": [ + "You can see that the profiles are exactly the same whether they are broken into several updates or not." + ] + }, + { + "cell_type": "markdown", + "id": "c547f051", + "metadata": {}, + "source": [ + "## Merge profiles" + ] + }, + { + "cell_type": "markdown", + "id": "a5292962", + "metadata": {}, + "source": [ + "In addition to the profile update, Data Profiler provides the merging functionality which allows users to combine the profiles updated from multiple locations. This enables Data Profiler to be used in a distributed computing environment. Below, we assume that the two aforementioned halves of the original dataset come from two different machines. Each of them is then updated with the Data Profiler on the same machine, then the resulted profiles are merged.\n", + "\n", + "As with the profile update, we expect the merged profiles give the same statistics as the profiles updated from the full dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a565b8d1", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Update the profile with the first half\n", + "profile1 = dp.Profiler(df1)\n", + "\n", + "# Update the profile with the second half\n", + "profile2 = dp.Profiler(df2)\n", + "\n", + "# merge profiles\n", + "profile_merge = profile1 + profile2\n", + "\n", + "# check results of the merged profile\n", + "report_merge = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# print the report\n", + "print(json.dumps(report_merge, indent=4))\n", + "print(json.dumps(report_full, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "b77fac3f", + "metadata": {}, + "source": [ + "You can see that the profiles are exactly the same!" + ] + }, + { + "cell_type": "markdown", + "id": "c644ee42", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "We have walked through some basic examples of Data Profiler usage, with different input data types and profiling options. We also work with update and merging functionality of the Data Profiler, which make it applicable for data streaming and distributed environment. Interested users can try with different datasets and functionalities as desired." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/popmon_dp_loader_example.ipynb b/docs/0.10.3/doctrees/nbsphinx/popmon_dp_loader_example.ipynb new file mode 100644 index 000000000..3ddb267da --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/popmon_dp_loader_example.ipynb @@ -0,0 +1,416 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7f0cceea", + "metadata": {}, + "source": [ + "# Dataloader with Popmon Reports" + ] + }, + { + "cell_type": "markdown", + "id": "9e79d9c5", + "metadata": {}, + "source": [ + "This demo is to cover the usage of popmon with the dataloader from the dataprofiler\n", + "\n", + "This demo covers the followings:\n", + "\n", + " - How to install popmon\n", + " - Comparison of the dynamic dataloader from dataprofiler to the \n", + " standard dataloader used in pandas\n", + " - Popmon's usage example using both dataloaders\n", + " - Dataprofiler's examples using both dataloaders\n", + " - Usage of the pm_stability_report function (popmon reports)\n" + ] + }, + { + "cell_type": "markdown", + "id": "aec2198a", + "metadata": {}, + "source": [ + "## How to Install Popmon\n", + "To install popmon you can use the command below:" + ] + }, + { + "cell_type": "markdown", + "id": "4383ed2a", + "metadata": {}, + "source": [ + "`pip3 install popmon`\n" + ] + }, + { + "cell_type": "markdown", + "id": "91dedc34", + "metadata": {}, + "source": [ + "From here, we can import the libararies needed for this demo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2adec556", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "import pandas as pd\n", + "import popmon # noqa" + ] + }, + { + "cell_type": "markdown", + "id": "2ed532ec", + "metadata": {}, + "source": [ + "## Comparison of Dataloaders" + ] + }, + { + "cell_type": "markdown", + "id": "cccbf4cd", + "metadata": {}, + "source": [ + "First, we have the original pandas dataloading which works for specific file types. \n", + "This is good for if the data format is known ahead of time but is less useful for more dynamic cases." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96e9ff89", + "metadata": {}, + "outputs": [], + "source": [ + "def popmon_dataloader(path, time_index):\n", + " # Load pm dataframe (Can only read csvs unless reader option is changed)\n", + " if not time_index is None:\n", + " pm_data = pd.read_csv(path, parse_dates=[time_index])\n", + " else:\n", + " time_index = True\n", + " pm_data = pd.read_csv(path)\n", + " return pm_data" + ] + }, + { + "cell_type": "markdown", + "id": "16dfbe10", + "metadata": {}, + "source": [ + "Next, we have the dataprofiler's dataloader. This allows for the dynamic loading of different data formats which is super useful when the data format is not know ahead of time.\n", + "This is intended to be an improvement on the dataloader standardly used in pandas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07481259", + "metadata": {}, + "outputs": [], + "source": [ + "def dp_dataloader(path):\n", + " # Datalaoder from dataprofiler used\n", + " dp_data = dp.Data(path)\n", + " \n", + " # Profiler used to ensure proper label for datetime even \n", + " # when null values exist\n", + " profiler_options = dp.ProfilerOptions()\n", + " profiler_options.set({'*.is_enabled': False, # Runs first disabling all options in profiler\n", + " '*.datetime.is_enabled': True})\n", + " profile = dp.Profiler(dp_data, options=profiler_options)\n", + "\n", + " # convert any time/datetime types from strings to actual datatime type\n", + " for ind, col in enumerate(dp_data.data.columns):\n", + " if profile.profile[ind].profile.get('data_type') == 'datetime':\n", + " dp_data.data[col] = pd.to_datetime(dp_data.data[col])\n", + "\n", + " return dp_data.data" + ] + }, + { + "cell_type": "markdown", + "id": "69a8ea9b", + "metadata": {}, + "source": [ + "## Popmon's usage example using both dataloaders" + ] + }, + { + "cell_type": "markdown", + "id": "ff914ca7", + "metadata": {}, + "source": [ + "Next, we'll download a dataset from the resources component" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bff33da8", + "metadata": {}, + "outputs": [], + "source": [ + "import gzip\n", + "import shutil\n", + "popmon_tutorial_data = popmon.resources.data(\"flight_delays.csv.gz\")\n", + "with gzip.open(popmon_tutorial_data, 'rb') as f_in:\n", + " with open('./flight_delays.csv', 'wb') as f_out:\n", + " shutil.copyfileobj(f_in, f_out)" + ] + }, + { + "cell_type": "markdown", + "id": "19222c4a", + "metadata": {}, + "source": [ + "Finally we read in the data with popmon and print the report to a file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0090a2f3", + "metadata": {}, + "outputs": [], + "source": [ + "# Default csv from popmon example\n", + "path = \"./flight_delays.csv\"\n", + "time_index = \"DATE\"\n", + "report_output_dir = \"./popmon_output/flight_delays_full\"\n", + "if not os.path.exists(report_output_dir):\n", + " os.makedirs(report_output_dir)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0abcd9b", + "metadata": {}, + "outputs": [], + "source": [ + "pm_data = popmon_dataloader(path, time_index)\n", + "\n", + "report_pm_loader = pm_data.pm_stability_report(\n", + " time_axis=time_index,\n", + " time_width=\"1w\",\n", + " time_offset=\"2015-07-02\",\n", + " extended_report=False,\n", + " pull_rules={\"*_pull\": [10, 7, -7, -10]},\n", + ")\n", + "\n", + "# Save popmon reports\n", + "report_pm_loader.to_file(os.path.join(report_output_dir, \"popmon_loader_report.html\"))\n", + "print(\"Report printed at:\", os.path.join(report_output_dir, \"popmon_loader_report.html\"))" + ] + }, + { + "cell_type": "markdown", + "id": "2303b5cf", + "metadata": {}, + "source": [ + "We then do the same for the dataprofiler loader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2854383", + "metadata": {}, + "outputs": [], + "source": [ + "dp_dataframe = dp_dataloader(path)\n", + "# Generate pm report using dp dataloader\n", + "report_dp_loader = dp_dataframe.pm_stability_report(\n", + " time_axis=time_index,\n", + " time_width=\"1w\",\n", + " time_offset=\"2015-07-02\",\n", + " extended_report=False,\n", + " pull_rules={\"*_pull\": [10, 7, -7, -10]},\n", + ")\n", + "\n", + "# Save popmon reports\n", + "report_dp_loader.to_file(os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))\n", + "print(\"Report printed at:\", os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))" + ] + }, + { + "cell_type": "markdown", + "id": "8cc4e5f3", + "metadata": {}, + "source": [ + "## Examples of data\n", + "Next, We'll use some data from the test files of the data profiler to compare the dynamic loading of the dataprofiler's data loader to that of the standard pandas approach. \n" + ] + }, + { + "cell_type": "markdown", + "id": "352eaeea", + "metadata": {}, + "source": [ + "## Dataprofiler's examples using both dataloaders" + ] + }, + { + "cell_type": "markdown", + "id": "e99af913", + "metadata": {}, + "source": [ + "To execute this properly, simply choose one of the 3 examples below and then run the report generation below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80eb601d", + "metadata": {}, + "outputs": [], + "source": [ + "# Default csv from popmon example (mini version)\n", + "path = \"../dataprofiler/tests/data/csv/flight_delays.csv\"\n", + "time_index = \"DATE\"\n", + "report_output_dir = \"./popmon_output/flight_delays_mini\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c127288", + "metadata": {}, + "outputs": [], + "source": [ + "# Random csv from dataprofiler tests\n", + "path = \"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\"\n", + "time_index = \"datetime\"\n", + "report_output_dir = \"./popmon_output/aws_honeypot_marx_geo\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6cd5c385", + "metadata": {}, + "outputs": [], + "source": [ + "# Random json file from dataprofiler tests\n", + "path = \"../dataprofiler/tests/data/json/math.json\"\n", + "\n", + "time_index = \"data.9\"\n", + "report_output_dir = \"./popmon_output/math\"" + ] + }, + { + "cell_type": "markdown", + "id": "ec860cb7", + "metadata": {}, + "source": [ + "Run the block below to create an output directory for your popmon reports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf21835c", + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.exists(report_output_dir):\n", + " os.makedirs(report_output_dir)\n", + "dp_dataframe = dp_dataloader(path)" + ] + }, + { + "cell_type": "markdown", + "id": "479975a5", + "metadata": {}, + "source": [ + "## Report comparison" + ] + }, + { + "cell_type": "markdown", + "id": "02a355e7", + "metadata": {}, + "source": [ + "We generate reports using different sets of data from the dataprofiler and pandas below using dataprofiler's dataloader and popmons report generator\n" + ] + }, + { + "cell_type": "markdown", + "id": "6ce69145", + "metadata": {}, + "source": [ + "The dataprofiler's dataloader can seemlessly switch between data formats and generate reports with the exact same code in place." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0dcb405", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Generate pm report using dp dataloader\n", + "report_dp_loader = dp_dataframe.pm_stability_report(\n", + " time_axis=time_index,\n", + " time_width=\"1w\",\n", + " time_offset=\"2015-07-02\",\n", + " extended_report=False,\n", + " pull_rules={\"*_pull\": [10, 7, -7, -10]},\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9eb0035c", + "metadata": {}, + "source": [ + "If the dataloaders are valid, you can see the reports and compare them at the output directory specified in the printout below each report generation block (the two code blocks below)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efe7d8d6", + "metadata": {}, + "outputs": [], + "source": [ + "# Save dp reports\n", + "report_dp_loader.to_file(os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))\n", + "print(\"Report printed at:\", os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/profiler_example.ipynb b/docs/0.10.3/doctrees/nbsphinx/profiler_example.ipynb new file mode 100644 index 000000000..b6a4409c9 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/profiler_example.ipynb @@ -0,0 +1,577 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f37ca393", + "metadata": {}, + "source": [ + "# Structured Profilers" + ] + }, + { + "cell_type": "markdown", + "id": "ff9bd095", + "metadata": {}, + "source": [ + "**Data profiling** - *is the process of examining a dataset and collecting statistical or informational summaries about said dataset.*\n", + "\n", + "The Profiler class inside the DataProfiler is designed to generate *data profiles* via the Profiler class, which ingests either a Data class or a Pandas DataFrame. \n", + "\n", + "Currently, the Data class supports loading the following file formats:\n", + "\n", + "* Any delimited (CSV, TSV, etc.)\n", + "* JSON object\n", + "* Avro\n", + "* Parquet\n", + "* Text files\n", + "* Pandas Series/Dataframe\n", + "\n", + "Once the data is loaded, the Profiler can calculate statistics and predict the entities (via the Labeler) of every column (csv) or key-value (JSON) store as well as dataset wide information, such as the number of nulls, duplicates, etc.\n", + "\n", + "This example will look at specifically the structured data types for structured profiling. " + ] + }, + { + "cell_type": "markdown", + "id": "de58b9c4", + "metadata": {}, + "source": [ + "## Reporting" + ] + }, + { + "cell_type": "markdown", + "id": "8001185a", + "metadata": {}, + "source": [ + "One of the primary purposes of the Profiler are to quickly identify what is in the dataset. This can be useful for analyzing a dataset prior to use or determining which columns could be useful for a given purpose.\n", + "\n", + "In terms of reporting, there are multiple reporting options:\n", + "\n", + "* **Pretty**: Floats are rounded to four decimal places, and lists are shortened.\n", + "* **Compact**: Similar to pretty, but removes detailed statistics such as runtimes, label probabilities, index locations of null types, etc.\n", + "* **Serializable**: Output is json serializable and not prettified\n", + "* **Flat**: Nested Output is returned as a flattened dictionary\n", + "\n", + "The **Pretty** and **Compact** reports are the two most commonly used reports and includes `global_stats` and `data_stats` for the given dataset. `global_stats` contains overall properties of the data such as number of rows/columns, null ratio, duplicate ratio. `data_stats` contains specific properties and statistics for each column file such as min, max, mean, variance, etc.\n", + "\n", + "For structured profiles, the report looks like this:\n", + "\n", + "```\n", + "\"global_stats\": {\n", + " \"samples_used\": int,\n", + " \"column_count\": int,\n", + " \"row_count\": int,\n", + " \"row_has_null_ratio\": float,\n", + " \"row_is_null_ratio\": float, \n", + " \"unique_row_ratio\": float,\n", + " \"duplicate_row_count\": int,\n", + " \"file_type\": string,\n", + " \"encoding\": string,\n", + "},\n", + "\"data_stats\": [\n", + " {\n", + " \"column_name\": string,\n", + " \"data_type\": string,\n", + " \"data_label\": string,\n", + " \"categorical\": bool,\n", + " \"order\": string,\n", + " \"samples\": list(str),\n", + " \"statistics\": {\n", + " \"sample_size\": int,\n", + " \"null_count\": int,\n", + " \"null_types\": list(string),\n", + " \"null_types_index\": {\n", + " string: list(int)\n", + " },\n", + " \"data_type_representation\": [string, list(string)],\n", + " \"min\": [null, float],\n", + " \"max\": [null, float],\n", + " \"mean\": float,\n", + " \"variance\": float,\n", + " \"stddev\": float,\n", + " \"histogram\": { \n", + " \"bin_counts\": list(int),\n", + " \"bin_edges\": list(float),\n", + " },\n", + " \"quantiles\": {\n", + " int: float\n", + " }\n", + " \"vocab\": list(char),\n", + " \"avg_predictions\": dict(float), \n", + " \"data_label_representation\": dict(float),\n", + " \"categories\": list(str),\n", + " \"unique_count\": int,\n", + " \"unique_ratio\": float,\n", + " \"precision\": {\n", + " 'min': int,\n", + " 'max': int,\n", + " 'mean': float,\n", + " 'var': float,\n", + " 'std': float,\n", + " 'sample_size': int,\n", + " 'margin_of_error': float,\n", + " 'confidence_level': float\t\t\n", + " },\n", + " \"times\": dict(float),\n", + " \"format\": string\n", + " }\n", + " }\n", + "]\n", + "```\n", + "\n", + "In the example, the `compact` format of the report is used to shorten the full list of the results. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fcb5447", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"\n", + "\n", + "# remove extra tf loggin\n", + "import tensorflow as tf\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7fc2df6", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Compact - A high level view, good for quick reviews\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "d7ec39d2", + "metadata": {}, + "source": [ + "It should be noted, in addition to reading the input data from multiple file types, DataProfiler allows the input data as a dataframe. To get more results related to detailed predictions at the entity level from the DataLabeler component or histogram results, the format `pretty` should be used. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29737f25", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# run data profiler and get the report\n", + "import pandas as pd\n", + "my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]], columns=[\"col_int\", \"col_float\"])\n", + "profile = dp.Profiler(my_dataframe)\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "241f6e3e", + "metadata": {}, + "source": [ + "## Profiler Type" + ] + }, + { + "cell_type": "markdown", + "id": "5b20879b", + "metadata": {}, + "source": [ + "The profiler will infer what type of statistics to generate (structured or unstructured) based on the input. However, you can explicitly specify profile type as well. Here is an example of the the profiler explicitly calling the structured profile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc44eb47", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "profile = dp.Profiler(data, profiler_type='structured')\n", + "\n", + "# print the report using json to prettify.\n", + "report = profile.report(report_options={\"output_format\": \"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "fe02ad64", + "metadata": {}, + "source": [ + "## Profiler options" + ] + }, + { + "cell_type": "markdown", + "id": "40804cc9", + "metadata": {}, + "source": [ + "The DataProfiler has the ability to turn on and off components as needed. This is accomplished via the `ProfilerOptions` class.\n", + "\n", + "For example, if a user doesn't require histogram information they may desire to turn off the histogram functionality. Simialrly, if a user is looking for a more accurate labeling, they can increase the samples used to label.\n", + "\n", + "Below, let's remove the histogram and increase the number of samples to the labeler component (1,000 samples). \n", + "\n", + "Full list of options in the Profiler section of the [DataProfiler documentation](https://capitalone.github.io/DataProfiler/profile_options.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d25d899", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/diamonds.csv\"))\n", + "\n", + "profile_options = dp.ProfilerOptions()\n", + "\n", + "# Setting multiple options via set\n", + "profile_options.set({ \"histogram.is_enabled\": False, \"int.is_enabled\": False})\n", + "\n", + "# Set options via directly setting them\n", + "profile_options.structured_options.data_labeler.max_sample_size = 1000\n", + "\n", + "profile = dp.Profiler(data, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "2052415a", + "metadata": {}, + "source": [ + "## Updating Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "7e02f746", + "metadata": {}, + "source": [ + "Beyond just profiling, one of the unique aspects of the DataProfiler is the ability to update the profiles. To update appropriately, the schema (columns / keys) must match appropriately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ab8022f", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# Load and profile a CSV file\n", + "data = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-header-and-author.txt\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Update the profile with new data:\n", + "new_data = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-skip-header.txt\"))\n", + "# new_data = dp.Data(os.path.join(data_path, \"iris-utf-16.csv\")) # will error due to schema mismatch\n", + "profile.update_profile(new_data)\n", + "\n", + "# Take a peek at the data\n", + "print(data.data)\n", + "print(new_data.data)\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "66ec6dc5", + "metadata": {}, + "source": [ + "## Merging Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "e2265fe9", + "metadata": {}, + "source": [ + "Merging profiles are an alternative method for updating profiles. Particularly, multiple profiles can be generated seperately, then added together with a simple `+` command: `profile3 = profile1 + profile2`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc68ca07", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# Load a CSV file with a schema\n", + "data1 = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-header-and-author.txt\"))\n", + "profile1 = dp.Profiler(data1)\n", + "\n", + "# Load another CSV file with the same schema\n", + "data2 = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-skip-header.txt\"))\n", + "profile2 = dp.Profiler(data2)\n", + "\n", + "# Merge the profiles\n", + "profile3 = profile1 + profile2\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile3.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "7ea07dc6", + "metadata": {}, + "source": [ + "As you can see, the `update_profile` function and the `+` operator function similarly. The reason the `+` operator is important is that it's possible to *save and load profiles*, which we cover next." + ] + }, + { + "cell_type": "markdown", + "id": "375ff25c-b189-436a-b07d-5e7f13cc6e03", + "metadata": {}, + "source": [ + "## Differences in Data\n", + "Can be applied to both structured and unstructured datasets. \n", + "\n", + "Such reports can provide details on the differences between training and validation data like in this pseudo example:\n", + "```python\n", + "profiler_training = dp.Profiler(training_data)\n", + "profiler_testing = dp.Profiler(testing_data)\n", + "\n", + "validation_report = profiler_training.diff(profiler_testing)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65360a03-e3ff-4f3c-9963-412298fdb284", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "\n", + "# structured differences example\n", + "data_split_differences = profile1.diff(profile2)\n", + "pprint(data_split_differences)" + ] + }, + { + "cell_type": "markdown", + "id": "2ae471ff-852f-400a-9bee-5c9fef96f10a", + "metadata": {}, + "source": [ + "## Graphing a Profile\n", + "\n", + "We've also added the ability to generating visual reports from a profile.\n", + "\n", + "The following plots are currently available to work directly with your profilers:\n", + "\n", + " * missing values matrix\n", + " * histogram (numeric columns only)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "734b588d-ac9a-409c-8eb5-b1a0aede8c63", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "# get the data\n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "data = dp.Data(os.path.join(data_folder, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "\n", + "# profile the data\n", + "profile = dp.Profiler(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4e70204-fa30-43c2-9556-e84c19f82d32", + "metadata": {}, + "outputs": [], + "source": [ + "# generate a missing values matrix\n", + "fig = plt.figure(figsize=(8, 6), dpi=100)\n", + "fig = dp.graphs.plot_missing_values_matrix(profile, ax=fig.gca(), title=\"Missing Values Matrix\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d734d355-e542-4245-a1e9-66521e333c2d", + "metadata": {}, + "outputs": [], + "source": [ + "# generate histogram of all int/float columns\n", + "fig = dp.graphs.plot_histograms(profile)\n", + "fig.set_size_inches(8, 6)\n", + "fig.set_dpi(100)" + ] + }, + { + "cell_type": "markdown", + "id": "30868000", + "metadata": {}, + "source": [ + "## Saving and Loading a Profile" + ] + }, + { + "cell_type": "markdown", + "id": "f2858072", + "metadata": {}, + "source": [ + "Not only can the Profiler create and update profiles, it's also possible to save, load then manipulate profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ad9ca57", + "metadata": {}, + "outputs": [], + "source": [ + "# Load data\n", + "data = dp.Data(os.path.join(data_path, \"csv/names-col.txt\"))\n", + "\n", + "# Generate a profile\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Save a profile to disk for later (saves as pickle file)\n", + "profile.save(filepath=\"my_profile.pkl\")\n", + "\n", + "# Load a profile from disk\n", + "loaded_profile = dp.Profiler.load(\"my_profile.pkl\")\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "8f9859c2", + "metadata": {}, + "source": [ + "With the ability to save and load profiles, profiles can be generated via multiple machines then merged. Further, profiles can be stored and later used in applications such as change point detection, synthetic data generation, and more. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3571f2d0", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a multiple files via the Data class\n", + "filenames = [\"csv/sparse-first-and-last-column-header-and-author.txt\",\n", + " \"csv/sparse-first-and-last-column-skip-header.txt\"]\n", + "data_objects = []\n", + "for filename in filenames:\n", + " data_objects.append(dp.Data(os.path.join(data_path, filename)))\n", + "\n", + "\n", + "# Generate and save profiles\n", + "for i in range(len(data_objects)):\n", + " profile = dp.Profiler(data_objects[i])\n", + " profile.save(filepath=\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Load profiles and add them together\n", + "profile = None\n", + "for i in range(len(data_objects)):\n", + " if profile is None:\n", + " profile = dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + " else:\n", + " profile += dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4690068a-8fc3-4bd5-8649-63d0f34fa91d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/regex_labeler_from_scratch.ipynb b/docs/0.10.3/doctrees/nbsphinx/regex_labeler_from_scratch.ipynb new file mode 100644 index 000000000..96aee213a --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/regex_labeler_from_scratch.ipynb @@ -0,0 +1,444 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e04c382a-7c49-452b-b9bf-e448951c64fe", + "metadata": {}, + "source": [ + "# Building a Regex Data Labeler w/ your own Regex" + ] + }, + { + "cell_type": "markdown", + "id": "6fb3ecb9-bc51-4c18-93d5-7991bbee5165", + "metadata": {}, + "source": [ + "This notebook teaches how to use the existing / create your own regex labeler as well as utilize it for structured data profiling.\n", + "\n", + "1. Loading and utilizing the pre-existing regex data labeler\n", + "1. Replacing the existing regex rules with your own.\n", + "1. Utilizng a regex data labeler inside of the structured profiler\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a67c197b-d3ee-4896-a96f-cc3d043601d3", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "from pprint import pprint\n", + "\n", + "import pandas as pd\n", + "\n", + "try:\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " sys.path.insert(0, '../..')\n", + " import dataprofiler as dp" + ] + }, + { + "cell_type": "markdown", + "id": "c71356f4-9020-4862-a1e1-816effbb5443", + "metadata": {}, + "source": [ + "## Loading and using the pre-existing regex data labeler\n", + "We can easily import the exsting regex labeler via the `load_from_library` command from the `dp.DataLabeler`. This allows us to import models other than the default structured / unstructured labelers which exist in the library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113d6655-4bca-4d8e-9e6f-b972e29d5684", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler = dp.DataLabeler.load_from_library('regex_model')\n", + "data_labeler.model.help()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b405887-2b92-44ca-b8d7-29c384f6dd9c", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.label_mapping)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11916a48-098c-4056-ac6c-b9542d85fa86", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.model._parameters['regex_patterns'])" + ] + }, + { + "cell_type": "markdown", + "id": "da0e97ee-8d6d-4631-9b55-78ed904d5f41", + "metadata": {}, + "source": [ + "### Predicting with the regex labeler\n", + "In the prediction below, the default settings will `split` the predictions by default as it's aggregation function. In other words, if a string '123 Fake St.' The first character would receive a vote for integer and for address giving both a 50% probability. This is because these regex functions are defined individually and a post prediction aggregation function must be used to get the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe519e65-36a7-4f42-8314-5369de8635c7", + "metadata": {}, + "outputs": [], + "source": [ + "# evaluate a prediction using the default parameters\n", + "data_labeler.predict(['123 Fake St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "b41d834d-e47b-45a6-8970-d2d2033e2ade", + "metadata": {}, + "source": [ + "## Replacing the regex rules in the existing labeler\n", + "\n", + "We can achieve this by:\n", + "1. Setting the label mapping to the new labels\n", + "2. Setting the model parameters which include: `regex_patterns`, `default_label`, `ignore_case`, and `encapsulators`\n", + "\n", + "where `regex_patterns` is a `dict` of lists or regex for each label, `default_label` is the expected default label for the regex, `ignore_case` tells the model to ignore case during its detection, and `encapsulators` are generic regex statements placed before (start) and after (end) each regex. Currently, this is used by the default model to capture labels that are within a cell rather than matching the entire cell. (e.g. ' 123 ' will still capture 123 as digits)." + ] + }, + { + "cell_type": "markdown", + "id": "c6bb010a-406f-4fd8-abd0-3355a5ad0ded", + "metadata": {}, + "source": [ + "Below, we created 4 labels where `other` is the `default_label`. Additionally, we set enabled case sensitivity such that upper and lower case letters would be detected separately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f86584cf-a7af-4bae-bf44-d87caa68833a", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.set_labels({'other': 0, 'digits':1, 'lowercase_char': 2, 'uppercase_chars': 3})\n", + "data_labeler.model.set_params(\n", + " regex_patterns={\n", + " 'digits': [r'[+-]?[0-9]+'],\n", + " 'lowercase_char': [r'[a-z]+'],\n", + " 'uppercase_chars': [r'[A-Z]+'],\n", + " },\n", + " default_label='other',\n", + " ignore_case=False,\n", + ")\n", + "data_labeler.label_mapping" + ] + }, + { + "cell_type": "markdown", + "id": "1ece1c8c-18a5-46fc-b563-6458e6e71e53", + "metadata": {}, + "source": [ + "### Predicting with the new regex labels\n", + "\n", + "Here we notice the otuput of the predictions gives us a prediction per character for each regex. Note how by default it is matching subtext due to the encapsulators. Where `123` were found to be digits, `FAKE` was foudn to be upper case, and the whitespaces and `St.` were other due no single regex being correct." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92842e14-2ea6-4879-b58c-c52b607dc94c", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(['123 FAKE St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "2ce14e54-094f-41ff-9ce0-69acace6abc2", + "metadata": {}, + "source": [ + "Below we turn off case-sensitivity and we see how the aggregation funciton splits the votes for characters between the `lowercase` and `uppercase` chars." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7b8ed9d-c912-4dc7-82c5-ba78a3affc1e", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.model.set_params(ignore_case=True)\n", + "data_labeler.predict(['123 FAKE St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "dc66515f-24e4-40f0-8592-b1ee4fba7077", + "metadata": {}, + "source": [ + "For the rest of this notebook, we will just use a single regex serach which will capture both upper and lower case chars." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e0c1b11-d111-4080-873f-40aff7cf7930", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.set_labels({'other': 0, 'digits':1, 'chars': 2})\n", + "data_labeler.model.set_params(\n", + " regex_patterns={\n", + " 'digits': [r'[=-]?[0-9]+'],\n", + " 'chars': [r'[a-zA-Z]+'],\n", + " },\n", + " default_label='other',\n", + " ignore_case=False,\n", + ")\n", + "data_labeler.label_mapping" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28e7b2ee-c661-4b31-b727-078f1393b5c4", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(['123 FAKE St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "f60c8fd1-76e1-469f-9e5a-62d7529301b3", + "metadata": {}, + "source": [ + "### Adjusting postprocessor properties\n", + "\n", + "Below we can look at the possible postprocessor parameters to adjust the aggregation function to the desired output. The previous outputs by default used the `split` aggregation function, however, below we will show the `random` aggregation function which will randomly choose a label if multiple labels have a vote for a given character." + ] + }, + { + "cell_type": "markdown", + "id": "36afa82b-1ca5-49ad-9aa9-84c6de621f59", + "metadata": {}, + "source": [ + "data_labeler.postprocessor.help()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66840940-47bf-433a-8ee8-977f26926e0b", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.postprocessor.set_params(aggregation_func='random')\n", + "data_labeler.predict(['123 FAKE St.'], predict_options=dict(show_confidences=True))" + ] + }, + { + "cell_type": "markdown", + "id": "c32b74fc-5051-4d53-b02a-4d1e4a35958f", + "metadata": {}, + "source": [ + "## Integrating the new Regex labeler into Structured Profiling\n", + "\n", + "While the labeler can be used alone, it is also possible to integrate the labeler into the StructuredProfiler with a slight change to its postprocessor. The StructuredProfiler requires a labeler which outputs othe confidence of each label for a given cell being processed. To convert the output of the `RegexPostProcessor` into said format, we will use the `StructRegexPostProcessor`. We can create the postprocessor and set the `data_labeler`'s postprocessor to this value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2663f2d-29a2-41ed-88dd-8a213d303365", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprofiler.labelers.data_processing import StructRegexPostProcessor\n", + "\n", + "postprocesor = StructRegexPostProcessor()\n", + "data_labeler.set_postprocessor(postprocesor)" + ] + }, + { + "cell_type": "markdown", + "id": "f7352769-d636-42c6-9706-7d9cff520a72", + "metadata": {}, + "source": [ + "Below we will see the output is now one vote per sample." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18814634-0fd0-4ce8-b0c3-9b9454701a43", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(['123 FAKE St.', '123', 'FAKE'], predict_options=dict(show_confidences=True))" + ] + }, + { + "cell_type": "markdown", + "id": "b4aa4e36-7362-4966-b827-3f5a6f2dfa7c", + "metadata": {}, + "source": [ + "### Setting the Structuredprofiler's DataLabeler\n", + "\n", + "We can create a `ProfilerOption` and set the structured options to have the new data_labeler as its value. We then run the StructuredProfiler with the specified options." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f18cf7f-283e-4e54-b3f9-1312828c3029", + "metadata": {}, + "outputs": [], + "source": [ + "# create and set the option for the regex data labeler to be used at profile time\n", + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_object': data_labeler})\n", + "\n", + "# profile the dataset using the suggested regex data labeler\n", + "data = pd.DataFrame(\n", + " [['123 FAKE St.', 123, 'this'], \n", + " [123 , -9, 'IS'], \n", + " ['...' , +80, 'A'], \n", + " ['123' , 202, 'raNDom'], \n", + " ['test' , -1, 'TEST']], \n", + " dtype=object)\n", + "profiler = dp.Profiler(data, options=profile_options)" + ] + }, + { + "cell_type": "markdown", + "id": "663e49f7-358b-4b0f-99a4-1823908ef990", + "metadata": {}, + "source": [ + "Below we see the first column is given 3 labels as it received multiple votes for said column. However, it was confident on the second and third column which is why it only specified `digits` and `chars` respectively." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f796d7f5-7e8a-447b-9cbb-d5b8180660a3", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(profiler.report(\n", + " dict(output_format='compact', \n", + " omit_keys=['data_stats.*.statistics', \n", + " 'data_stats.*.categorical', \n", + " 'data_stats.*.order', \n", + " 'global_stats'])))" + ] + }, + { + "cell_type": "markdown", + "id": "261b903f-8f4c-403f-839b-ab8813f850e9", + "metadata": {}, + "source": [ + "## Saving the Data Labeler for future use" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6ffbaf2-9400-486a-ba83-5fc9ba9334d7", + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.isdir('my_new_regex_labeler'):\n", + " os.mkdir('my_new_regex_labeler')\n", + "data_labeler.save_to_disk('my_new_regex_labeler')" + ] + }, + { + "cell_type": "markdown", + "id": "09e40cb6-9d89-41c4-ae28-3dca498f8c68", + "metadata": {}, + "source": [ + "## Loading the saved Data Labeler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52615b25-70a6-4ebb-8a32-14aaf1e747d9", + "metadata": {}, + "outputs": [], + "source": [ + "saved_labeler = dp.DataLabeler.load_from_disk('my_new_regex_labeler')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1ccc0b3-1dc2-4847-95c2-d6b8769b1590", + "metadata": {}, + "outputs": [], + "source": [ + "# ensuring the parametesr are what we saved.\n", + "print(\"label_mapping:\")\n", + "pprint(saved_labeler.label_mapping)\n", + "print(\"\\nmodel parameters:\")\n", + "pprint(saved_labeler.model._parameters)\n", + "print()\n", + "print(\"postprocessor: \" + saved_labeler.postprocessor.__class__.__name__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c827f2ae-4af6-4f3f-9651-9ee9ebea9fa0", + "metadata": {}, + "outputs": [], + "source": [ + "# predicting with the loaded labeler.\n", + "saved_labeler.predict(['test', '123'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "606f9bbf-5955-4b7b-b0d1-390de5600f73", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/nbsphinx/unstructured_profiler_example.ipynb b/docs/0.10.3/doctrees/nbsphinx/unstructured_profiler_example.ipynb new file mode 100644 index 000000000..9ab754cc7 --- /dev/null +++ b/docs/0.10.3/doctrees/nbsphinx/unstructured_profiler_example.ipynb @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f37ca393", + "metadata": {}, + "source": [ + "# Unstructured Profilers" + ] + }, + { + "cell_type": "markdown", + "id": "ff9bd095", + "metadata": {}, + "source": [ + "**Data profiling** - *is the process of examining a dataset and collecting statistical or informational summaries about said dataset.*\n", + "\n", + "The Profiler class inside the DataProfiler is designed to generate *data profiles* via the Profiler class, which ingests either a Data class or a Pandas DataFrame. \n", + "\n", + "Currently, the Data class supports loading the following file formats:\n", + "\n", + "* Any delimited (CSV, TSV, etc.)\n", + "* JSON object\n", + "* Avro\n", + "* Parquet\n", + "* Text files\n", + "* Pandas Series/Dataframe\n", + "\n", + "Once the data is loaded, the Profiler can calculate statistics and predict the entities (via the Labeler) of every column (csv) or key-value (JSON) store as well as dataset wide information, such as the number of nulls, duplicates, etc.\n", + "\n", + "This example will look at specifically the unstructured data types for unstructured profiling. This means that only text files, lists of strings, single column pandas dataframes/series, or DataProfile Data objects in string format will work with the unstructured profiler. " + ] + }, + { + "cell_type": "markdown", + "id": "de58b9c4", + "metadata": {}, + "source": [ + "## Reporting" + ] + }, + { + "cell_type": "markdown", + "id": "8001185a", + "metadata": {}, + "source": [ + "One of the primary purposes of the Profiler are to quickly identify what is in the dataset. This can be useful for analyzing a dataset prior to use or determining which columns could be useful for a given purpose.\n", + "\n", + "In terms of reporting, there are multiple reporting options:\n", + "\n", + "* **Pretty**: Floats are rounded to four decimal places, and lists are shortened.\n", + "* **Compact**: Similar to pretty, but removes detailed statistics\n", + "* **Serializable**: Output is json serializable and not prettified\n", + "* **Flat**: Nested Output is returned as a flattened dictionary\n", + "\n", + "The **Pretty** and **Compact** reports are the two most commonly used reports and includes `global_stats` and `data_stats` for the given dataset. `global_stats` contains overall properties of the data such as samples used and file encoding. `data_stats` contains specific properties and statistics for each text sample.\n", + "\n", + "For unstructured profiles, the report looks like this:\n", + "\n", + "```\n", + "\"global_stats\": {\n", + " \"samples_used\": int,\n", + " \"empty_line_count\": int,\n", + " \"file_type\": string,\n", + " \"encoding\": string\n", + "},\n", + "\"data_stats\": {\n", + " \"data_label\": {\n", + " \"entity_counts\": {\n", + " \"word_level\": dict(int),\n", + " \"true_char_level\": dict(int),\n", + " \"postprocess_char_level\": dict(int)\n", + " },\n", + " \"times\": dict(float)\n", + " },\n", + " \"statistics\": {\n", + " \"vocab\": list(char),\n", + " \"words\": list(string),\n", + " \"word_count\": dict(int),\n", + " \"times\": dict(float)\n", + " }\n", + "}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fcb5447", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"\n", + "\n", + "# remove extra tf loggin\n", + "import tensorflow as tf\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7fc2df6", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"txt/discussion_reddit.txt\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "report = profile.report(report_options={\"output_format\": \"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "4d183992", + "metadata": {}, + "source": [ + "## Profiler Type" + ] + }, + { + "cell_type": "markdown", + "id": "d7ec39d2", + "metadata": {}, + "source": [ + "It should be noted, in addition to reading the input data from text files, DataProfiler allows the input data as a pandas dataframe, a pandas series, a list, and Data objects (when an unstructured format is selected) if the Profiler is explicitly chosen as unstructured." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29737f25", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# run data profiler and get the report\n", + "import pandas as pd\n", + "data = dp.Data(os.path.join(data_path, \"csv/SchoolDataSmall.csv\"), options={\"data_format\": \"records\"})\n", + "profile = dp.Profiler(data, profiler_type='unstructured')\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "fe02ad64", + "metadata": {}, + "source": [ + "## Profiler options" + ] + }, + { + "cell_type": "markdown", + "id": "40804cc9", + "metadata": {}, + "source": [ + "The DataProfiler has the ability to turn on and off components as needed. This is accomplished via the `ProfilerOptions` class.\n", + "\n", + "For example, if a user doesn't require vocab count information they may desire to turn off the word count functionality.\n", + "\n", + "Below, let's remove the vocab count and set the stop words. \n", + "\n", + "Full list of options in the Profiler section of the [DataProfiler documentation](https://capitalone.github.io/DataProfiler/profile_options.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d25d899", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"txt/discussion_reddit.txt\"))\n", + "\n", + "profile_options = dp.ProfilerOptions()\n", + "\n", + "# Setting multiple options via set\n", + "profile_options.set({ \"*.vocab.is_enabled\": False, \"*.is_case_sensitive\": True })\n", + "\n", + "# Set options via directly setting them\n", + "profile_options.unstructured_options.text.stop_words = [\"These\", \"are\", \"stop\", \"words\"]\n", + "\n", + "profile = dp.Profiler(data, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\": \"compact\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "2052415a", + "metadata": {}, + "source": [ + "## Updating Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "7e02f746", + "metadata": {}, + "source": [ + "Beyond just profiling, one of the unique aspects of the DataProfiler is the ability to update the profiles. To update appropriately, the schema (columns / keys) must match appropriately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ab8022f", + "metadata": {}, + "outputs": [], + "source": [ + "# Load and profile a CSV file\n", + "data = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Update the profile with new data:\n", + "new_data = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile.update_profile(new_data)\n", + "\n", + "# Take a peek at the data\n", + "print(data.data)\n", + "print(new_data.data)\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\": \"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "66ec6dc5", + "metadata": {}, + "source": [ + "## Merging Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "e2265fe9", + "metadata": {}, + "source": [ + "Merging profiles are an alternative method for updating profiles. Particularly, multiple profiles can be generated seperately, then added together with a simple `+` command: `profile3 = profile1 + profile2`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc68ca07", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a CSV file with a schema\n", + "data1 = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile1 = dp.Profiler(data1)\n", + "\n", + "# Load another CSV file with the same schema\n", + "data2 = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile2 = dp.Profiler(data2)\n", + "\n", + "# Merge the profiles\n", + "profile3 = profile1 + profile2\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile3.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "7ea07dc6", + "metadata": {}, + "source": [ + "As you can see, the `update_profile` function and the `+` operator function similarly. The reason the `+` operator is important is that it's possible to *save and load profiles*, which we cover next." + ] + }, + { + "cell_type": "markdown", + "id": "4704961a", + "metadata": {}, + "source": [ + "## Differences in Data\n", + "Can be applied to both structured and unstructured datasets. \n", + "\n", + "Such reports can provide details on the differences between training and validation data like in this pseudo example:\n", + "```python\n", + "profiler_training = dp.Profiler(training_data)\n", + "profiler_testing = dp.Profiler(testing_data)\n", + "\n", + "validation_report = profiler_training.diff(profiler_testing)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58f92c1b", + "metadata": {}, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "\n", + "# unstructured differences example\n", + "data_split_differences = profile1.diff(profile2)\n", + "pprint(data_split_differences)" + ] + }, + { + "cell_type": "markdown", + "id": "30868000", + "metadata": {}, + "source": [ + "## Saving and Loading a Profile" + ] + }, + { + "cell_type": "markdown", + "id": "f2858072", + "metadata": {}, + "source": [ + "Not only can the Profiler create and update profiles, it's also possible to save, load then manipulate profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ad9ca57", + "metadata": {}, + "outputs": [], + "source": [ + "# Load data\n", + "data = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "\n", + "# Generate a profile\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Save a profile to disk for later (saves as pickle file)\n", + "profile.save(filepath=\"my_profile.pkl\")\n", + "\n", + "# Load a profile from disk\n", + "loaded_profile = dp.Profiler.load(\"my_profile.pkl\")\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "8f9859c2", + "metadata": {}, + "source": [ + "With the ability to save and load profiles, profiles can be generated via multiple machines then merged. Further, profiles can be stored and later used in applications such as change point detection, synthetic data generation, and more. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3571f2d0", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a multiple files via the Data class\n", + "filenames = [\"txt/sentence-3x.txt\",\n", + " \"txt/sentence.txt\"]\n", + "data_objects = []\n", + "for filename in filenames:\n", + " data_objects.append(dp.Data(os.path.join(data_path, filename)))\n", + "\n", + "print(data_objects)\n", + "# Generate and save profiles\n", + "for i in range(len(data_objects)):\n", + " profile = dp.Profiler(data_objects[i])\n", + " report = profile.report(report_options={\"output_format\":\"compact\"})\n", + " print(json.dumps(report, indent=4))\n", + " profile.save(filepath=\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Load profiles and add them together\n", + "profile = None\n", + "for i in range(len(data_objects)):\n", + " if profile is None:\n", + " profile = dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + " else:\n", + " profile += dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/doctrees/overview.doctree b/docs/0.10.3/doctrees/overview.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c0d0c5707d8592c1bd95cba6c8e98de066b2637b GIT binary patch literal 39429 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

    v6k(Bw@vTBmZ3D-5_8zkBo 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/profiler_example.doctree b/docs/0.10.3/doctrees/profiler_example.doctree new file mode 100644 index 0000000000000000000000000000000000000000..0acc27a8a0aeb78cf7444161109edfaf68240f73 GIT binary patch literal 47461 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/unstructured_profiler_example.doctree b/docs/0.10.3/doctrees/unstructured_profiler_example.doctree new file mode 100644 index 0000000000000000000000000000000000000000..c1e2349266537d65216483bfd704eccdf95b11e4 GIT binary patch literal 36890 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/.buildinfo b/docs/0.10.3/html/.buildinfo new file mode 100644 index 000000000..4732a5974 --- /dev/null +++ b/docs/0.10.3/html/.buildinfo @@ -0,0 +1,4 @@ +# Sphinx build info version 1 +# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. +config: c4c49cedf157569aeaa0ea19b0244ce1 +tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/0.10.3/html/API.html b/docs/0.10.3/html/API.html new file mode 100644 index 000000000..be885790e --- /dev/null +++ b/docs/0.10.3/html/API.html @@ -0,0 +1,293 @@ + + + + + + + + + API - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +

    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    + + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/_images/DL-Flowchart.png b/docs/0.10.3/html/_images/DL-Flowchart.png new file mode 100644 index 0000000000000000000000000000000000000000..696eeb5dc8e5b8d10dcb1afd7d6f165301904cb6 GIT binary patch literal 7609 zcmeHMcQl+`w;!U5P6$SuMDHz37|}`e9wJ)w&d4CcXhB4ch|Xa27Cnd>GJ;@6PohR* zwCKHE-uL~!d+(q3&%5qD&pFTDXYb$M`|Puxv(~frd8MbLPC>>@1^@skG&NKV006w+ zD;`EdboKVBx6rvF1dfW@iU2@O0{NK@;nkeOPQySO00`s;074=FfRigx2o3=769oWP ztpNaV8UVoPmDQpzccqB1H`8>`)&}rj@gx93JX*kwD-Q4K0pKwMuDxAxfQNW2|K<(w zc>lrR0{~IZ0D^xo=2!H(SznE7o4@G|B;J2|MB@Jojn|93@h=_#yFvqS>e7x^gw#vp zu`d8X*>gScQUoYjuDm^VHZp^nX={P)Jl%zDo_X5Z3;Vl!U0VU<{J~eOyFJu~!{6P_ z!x!u?&-E7qe8pdjMYuTrf^Y=_C51(~AY>dI9CAL-9KZ%DYX6vD z&E&b9pinQchzJY@6NX6$d-^zvh{?*ziinDfh>HtdA%uJbJfJrILLR=Lzn%QckBYso zosY8@)Y;R6x4Qx{AVN&-+$7&N>JolBO)d&D)MjNSEh2; zQn0R%v;9@%YyS{2xxbMAP4-V5Ig#t&|79_MXZn})Dpd%XoXEeo4ML{X&GQ%lU;%5Y zC>r_WZDf(AF^s22Qr$0!9tl~$U#r$dLE}9a{Yc43(vBNk0HH&_(z&TaoAO~vliTi1 zx_2~Fff$A`IEFl?P-@N~SgyQrzC2)4Y5 zvQ`l6RvXY?Vm`Jp*AoQ&yd^7s_-B#xeR%#mko)T|4*FBGLgo>Y>_SB+Z=XFDXjDz| zl1)*db>~weNn*#+eWQB)e)~DYZG|3}rKqp4?7d^E!#Y>9I_e`w0X6*Z5-*>2{ia8` zi#>ika4TMduQJfy1*Ku6mfjpPY88RApO<=-R4&}Spq2*?{okMpSujg_+P&w_ui=@(GQkL1#j067$(aWt1 zCAHVRGTs@Y-Bh2H`-0P``Pw(AV`AASp5ZG9@kYj@AhX$hX@N%D+k7ds?CmlUvYE=! z>am3e?vtYgTAc(t+I_?!~%zPEP#4 z@_)1m#*ZFcjH133z(YvKL_&W*^Hiv?`g}LJHS3E5{xL0X@YRhGvU(DCMQJ)-Nxb8E z>ph5h$a>U+_rKIT6~z=hAOgxrk<4-o4^C5(MOFsC%R~?VM)Nn7dV2Xd2QFfDjwu)2 zPQ{voLHOrC1c6(Aa^Ty1qTp+s7e291uNcm3kJZPEAguC$fR)~Lc+l|~4|3jL%*ShR z2>pUw`9asV+|s-m(`?)ye#)4*D$T>dm#nOZfpi}L)Kjfp-uLew)jzyn(lpc54?(zl z5v&UFnylYc4A!59);K%`ncUX2yZGT0{&T{e(+K%n2KxGz;ERgIQ46!*`ua3V zeA1ZBGhFQdLK@C=E;#9ugKqHoHPd&%C@fPpe9Ck#0jBg*`qo6V{hmG&>59SQwJPw8 zo6QRDJSc-pYzIt}j9KV?bTlS03<#UaEpOyHDWzyyV7k$~I1W^n$#9OCxJY@{DD7Nv z%B<}LU$3F|IDSkL#m?LfY;p{!z;)^Yr3mcH9fMtRqa*L)%yP2SYW~6((1z&4RN$kaWDg)nM+0k zE1z|vD!+}mtsc6Ws8X5PnP0oD@nFHuMmQs+J{NKimyww`5x(Xh$F+~_`DEUCPkAS# z5XzRHf8NsAzV<Lt_hc=RX|fhlUsi6np~XOc&dQ*FI_>4>2yrAppa0UW>w&w z$%^pGt%=O+&wH4C$%j_VO8ZZ0Q~X9Bt!OxXoLyg|xtI72L7w7%W9l~ zIJ3su@%mM~#L+P)+sx^XVEGNz@P?TLp{ws)64)BQ>-WTUXfC(-t8JRFagZnm7sDIW zW=8B&sZyslsmH{(9>yyFK2~M*kbbO34b;ywVuf))A))+W0zM7?t*^?jlZNiI0pn(s zstfKqF}F~kQ|_yg#lKF38wA8DkttDe#u?DhLuWRTO_SqKoxn85DpeqB6lLCU z7s6rqx9QLDt-Ekj!(v^9I8R{LUKu!ZN_w7MWT;zLrZKB{=YaJ^|ChZNP!`mn%Uz51G`*|4Y#uI|Q zngYGp#~VrmR=-LH8Z2MF^0--*4>+P#v<5KDvA;*)55;N|h+?T+HNQ8JFN8L5p24Mn zH|C_ev$~fVy^G54J4S+=cC#T|Sr3$-bLSG1Iy~$sb>&9R3>@!JS#F-4JHtFau?r6W zh(j-G{DS9dgjJ3o+Hj~UKcl)kN4VaRvDu_QlmyRJT0WB5S4a}~L*?)vx=o#tH$V*il1qPC zs>xA^0D5#dV#`w@uX060jhe)Zh4> z-LgL=0&u&2$y?-SE_)@^vsvi*dHtQGEJfm==h=}*nu;{ZR7!=47LD^V;k3(}QLE8x zYSo~VP+pF*UQAA&P@5Id{ZS zwabP2`�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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_images/histogram_example_1.png b/docs/0.10.3/html/_images/histogram_example_1.png new file mode 100644 index 0000000000000000000000000000000000000000..062dfdbb9829f3032b4c1afd55fefc61a08b5d56 GIT binary patch literal 11387 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 G+kXRhHtTNy literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_images/missing_value_matrix_example_0.png b/docs/0.10.3/html/_images/missing_value_matrix_example_0.png new file mode 100644 index 0000000000000000000000000000000000000000..21799cddfe73821d7ed15fe29b805df8f2e1879a GIT binary patch literal 37730 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_sources/API.rst.txt b/docs/0.10.3/html/_sources/API.rst.txt new file mode 100644 index 000000000..fdbf2242b --- /dev/null +++ b/docs/0.10.3/html/_sources/API.rst.txt @@ -0,0 +1,16 @@ +.. _API: + +API +*** + +The API is split into 4 main components: Profilers, Labelers, Data Readers, and +Validators. + +.. toctree:: + :maxdepth: 1 + :caption: Contents: + + dataprofiler.data_readers + dataprofiler.profilers + dataprofiler.labelers + dataprofiler.validators \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/add_new_model_to_data_labeler.nblink.txt b/docs/0.10.3/html/_sources/add_new_model_to_data_labeler.nblink.txt new file mode 100644 index 000000000..130e413fc --- /dev/null +++ b/docs/0.10.3/html/_sources/add_new_model_to_data_labeler.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/add_new_model_to_data_labeler.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/column_name_labeler_example.nblink.txt b/docs/0.10.3/html/_sources/column_name_labeler_example.nblink.txt new file mode 100644 index 000000000..6f95cf7cb --- /dev/null +++ b/docs/0.10.3/html/_sources/column_name_labeler_example.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/column_name_labeler.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/data_labeling.rst.txt b/docs/0.10.3/html/_sources/data_labeling.rst.txt new file mode 100644 index 000000000..db76fe791 --- /dev/null +++ b/docs/0.10.3/html/_sources/data_labeling.rst.txt @@ -0,0 +1,365 @@ +.. _data_labeling: + +Labeler (Sensitive Data) +************************ + +In this library, the term *data labeling* refers to entity recognition. + +Builtin to the data profiler is a classifier which evaluates the complex data types of the dataset. +For structured data, it determines the complex data type of each column. When +running the data profile, it uses the default data labeling model builtin to the +library. However, the data labeler allows users to train their own data labeler +as well. + +*Data Labels* are determined per cell for structured data (column/row when +the *profiler* is used) or at the character level for unstructured data. This +is a list of the default labels. + +* UNKNOWN +* ADDRESS +* BAN (bank account number, 10-18 digits) +* CREDIT_CARD +* EMAIL_ADDRESS +* UUID +* HASH_OR_KEY (md5, sha1, sha256, random hash, etc.) +* IPV4 +* IPV6 +* MAC_ADDRESS +* PERSON +* PHONE_NUMBER +* SSN +* URL +* US_STATE +* DRIVERS_LICENSE +* DATE +* TIME +* DATETIME +* INTEGER +* FLOAT +* QUANTITY +* ORDINAL + + +Identify Entities in Structured Data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Makes predictions and identifying labels: + +.. code-block:: python + + import dataprofiler as dp + + # load data and data labeler + data = dp.Data("your_data.csv") + data_labeler = dp.DataLabeler(labeler_type='structured') + + # make predictions and get labels per cell + predictions = data_labeler.predict(data) + +Identify Entities in Unstructured Data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Predict which class characters belong to in unstructured text: + +.. code-block:: python + + import dataprofiler as dp + + data_labeler = dp.DataLabeler(labeler_type='unstructured') + + # Example sample string, must be in an array (multiple arrays can be passed) + sample = ["Help\tJohn Macklemore\tneeds\tfood.\tPlease\tCall\t555-301-1234." + "\tHis\tssn\tis\tnot\t334-97-1234. I'm a BAN: 000043219499392912.\n"] + + # Prediction what class each character belongs to + model_predictions = data_labeler.predict( + sample, predict_options=dict(show_confidences=True)) + + # Predictions / confidences are at the character level + final_results = model_predictions["pred"] + final_confidences = model_predictions["conf"] + +It's also possible to change output formats, output similar to a **SpaCy** format: + +.. code-block:: python + + import dataprofiler as dp + + data_labeler = dp.DataLabeler(labeler_type='unstructured', trainable=True) + + # Example sample string, must be in an array (multiple arrays can be passed) + sample = ["Help\tJohn Macklemore\tneeds\tfood.\tPlease\tCall\t555-301-1234." + "\tHis\tssn\tis\tnot\t334-97-1234. I'm a BAN: 000043219499392912.\n"] + + # Set the output to the NER format (start position, end position, label) + data_labeler.set_params( + { 'postprocessor': { 'output_format':'ner', 'use_word_level_argmax':True } } + ) + + results = data_labeler.predict(sample) + + print(results) + +Train a New Data Labeler +~~~~~~~~~~~~~~~~~~~~~~~~ + +Mechanism for training your own data labeler on their own set of structured data +(tabular): + +.. code-block:: python + + import dataprofiler as dp + + # Will need one column with a default label of UNKNOWN + data = dp.Data("your_file.csv") + + data_labeler = dp.train_structured_labeler( + data=data, + save_dirpath="/path/to/save/labeler", + epochs=2 + ) + + data_labeler.save_to_disk("my/save/path") # Saves the data labeler for reuse + +Load an Existing Data Labeler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mechanism for loading an existing data_labeler: + +.. code-block:: python + + import dataprofiler as dp + + data_labeler = dp.DataLabeler( + labeler_type='structured', dirpath="/path/to/my/labeler") + + # get information about the parameters/inputs/output formats for the DataLabeler + data_labeler.help() + +Extending a Data Labeler with Transfer Learning +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Extending or changing labels of a data labeler w/ transfer learning: +Note: By default, **a labeler loaded will not be trainable**. In order to load a +trainable DataLabeler, the user must set `trainable=True` or load a labeler +using the `TrainableDataLabeler` class. + +The following illustrates how to change the labels: + +.. code-block:: python + + import dataprofiler as dp + + labels = ['label1', 'label2', ...] # new label set can also be an encoding dict + data = dp.Data("your_file.csv") # contains data with new labels + + # load default structured Data Labeler w/ trainable set to True + data_labeler = dp.DataLabeler(labeler_type='structured', trainable=True) + + # this will use transfer learning to retrain the data labeler on your new + # dataset and labels. + # NOTE: data must be in an acceptable format for the preprocessor to interpret. + # please refer to the preprocessor/model for the expected data format. + # Currently, the DataLabeler cannot take in Tabular data, but requires + # data to be ingested with two columns [X, y] where X is the samples and + # y is the labels. + model_results = data_labeler.fit(x=data['samples'], y=data['labels'], + validation_split=0.2, epochs=2, labels=labels) + + # final_results, final_confidences are a list of results for each epoch + epoch_id = 0 + final_results = model_results[epoch_id]["pred"] + final_confidences = model_results[epoch_id]["conf"] + +The following illustrates how to extend the labels: + +.. code-block:: python + + import dataprofiler as dp + + new_labels = ['label1', 'label2', ...] + data = dp.Data("your_file.csv") # contains data with new labels + + # load default structured Data Labeler w/ trainable set to True + data_labeler = dp.DataLabeler(labeler_type='structured', trainable=True) + + # this will maintain current labels and model weights, but extend the model's + # labels + for label in new_labels: + data_labeler.add_label(label) + + # NOTE: a user can also add a label which maps to the same index as an existing + # label + # data_labeler.add_label(label, same_as='') + + # For a trainable model, the user must then train the model to be able to + # continue using the labeler since the model's graph has likely changed + # NOTE: data must be in an acceptable format for the preprocessor to interpret. + # please refer to the preprocessor/model for the expected data format. + # Currently, the DataLabeler cannot take in Tabular data, but requires + # data to be ingested with two columns [X, y] where X is the samples and + # y is the labels. + model_results = data_labeler.fit(x=data['samples'], y=data['labels'], + validation_split=0.2, epochs=2) + + # final_results, final_confidences are a list of results for each epoch + epoch_id = 0 + final_results = model_results[epoch_id]["pred"] + final_confidences = model_results[epoch_id]["conf"] + + +Changing pipeline parameters: + +.. code-block:: python + + import dataprofiler as dp + + # load default Data Labeler + data_labeler = dp.DataLabeler(labeler_type='structured') + + # change parameters of specific component + data_labeler.preprocessor.set_params({'param1': 'value1'}) + + # change multiple simultaneously. + data_labeler.set_params({ + 'preprocessor': {'param1': 'value1'}, + 'model': {'param2': 'value2'}, + 'postprocessor': {'param3': 'value3'} + }) + + +Build Your Own Data Labeler +=========================== + +The DataLabeler has 3 main components: preprocessor, model, and postprocessor. +To create your own DataLabeler, each one would have to be created or an +existing component can be reused. + +Given a set of the 3 components, you can construct your own DataLabeler: + +.. code-block:: python + from dataprofiler.labelers.base_data_labeler import BaseDataLabeler, \ + TrainableDataLabeler + from dataprofiler.labelers.character_level_cnn_model import CharacterLevelCnnModel + from dataprofiler.labelers.data_processing import \ + StructCharPreprocessor, StructCharPostprocessor + + # load a non-trainable data labeler + model = CharacterLevelCnnModel(...) + preprocessor = StructCharPreprocessor(...) + postprocessor = StructCharPostprocessor(...) + + data_labeler = BaseDataLabeler.load_with_components( + preprocessor=preprocessor, model=model, postprocessor=postprocessor) + + # check for basic compatibility between the processors and the model + data_labeler.check_pipeline() + + + # load trainable data labeler + data_labeler = TrainableDataLabeler.load_with_components( + preprocessor=preprocessor, model=model, postprocessor=postprocessor) + + # check for basic compatibility between the processors and the model + data_labeler.check_pipeline() + +Option for swapping out specific components of an existing labeler. + +.. code-block:: python + + import dataprofiler as dp + from dataprofiler.labelers.character_level_cnn_model import \ + CharacterLevelCnnModel + from dataprofiler.labelers.data_processing import \ + StructCharPreprocessor, StructCharPostprocessor + + model = CharacterLevelCnnModel(...) + preprocessor = StructCharPreprocessor(...) + postprocessor = StructCharPostprocessor(...) + + data_labeler = dp.DataLabeler(labeler_type='structured') + data_labeler.set_preprocessor(preprocessor) + data_labeler.set_model(model) + data_labeler.set_postprocessor(postprocessor) + + # check for basic compatibility between the processors and the model + data_labeler.check_pipeline() + + +Model Component +~~~~~~~~~~~~~~~ + +In order to create your own model component for data labeling, you can utilize +the `BaseModel` class from `dataprofiler.labelers.base_model` and +overriding the abstract class methods. + +Reviewing `CharacterLevelCnnModel` from +`dataprofiler.labelers.character_level_cnn_model` illustrates the functions +which need an override. + +#. `__init__`: specifying default parameters and calling base `__init__` +#. `_validate_parameters`: validating parameters given by user during setting +#. `_need_to_reconstruct_model`: flag for when to reconstruct a model (i.e. + parameters change or labels change require a model reconstruction) +#. `_construct_model`: initial construction of the model given the parameters +#. `_reconstruct_model`: updates model architecture for new label set while + maintaining current model weights +#. `fit`: mechanism for the model to learn given training data +#. `predict`: mechanism for model to make predictions on data +#. `details`: prints a summary of the model construction +#. `save_to_disk`: saves model and model parameters to disk +#. `load_from_disk`: loads model given a path on disk + + +Preprocessor Component +~~~~~~~~~~~~~~~~~~~~~~ + +In order to create your own preprocessor component for data labeling, you can +utilize the `BaseDataPreprocessor` class +from `dataprofiler.labelers.data_processing` and override the abstract class +methods. + +Reviewing `StructCharPreprocessor` from +`dataprofiler.labelers.data_processing` illustrates the functions which +need an override. + +#. `__init__`: passing parameters to the base class and executing any + extraneous calculations to be saved as parameters +#. `_validate_parameters`: validating parameters given by user during + setting +#. `process`: takes in the user data and converts it into an digestible, + iterable format for the model +#. `set_params` (optional): if a parameter requires processing before setting, + a user can override this function to assist with setting the parameter +#. `_save_processor` (optional): if a parameter is not JSON serializable, a + user can override this function to assist in saving the processor and its + parameters +#. `load_from_disk` (optional): if a parameter(s) is not JSON serializable, a + user can override this function to assist in loading the processor + +Postprocessor Component +~~~~~~~~~~~~~~~~~~~~~~~ + +The postprocessor is nearly identical to the preprocessor except it handles +the output of the model for processing. In order to create your own +postprocessor component for data labeling, you can utilize the +`BaseDataPostprocessor` class from `dataprofiler.labelers.data_processing` +and override the abstract class methods. + +Reviewing `StructCharPostprocessor` from +`dataprofiler.labelers.data_processing` illustrates the functions which +need an override. + +#. `__init__`: passing parameters to the base class and executing any + extraneous calculations to be saved as parameters +#. `_validate_parameters`: validating parameters given by user during + setting +#. `process`: takes in the output of the model and processes for output to + the user +#. `set_params` (optional): if a parameter requires processing before setting, + a user can override this function to assist with setting the parameter +#. `_save_processor` (optional): if a parameter is not JSON serializable, a + user can override this function to assist in saving the processor and its + parameters +#. `load_from_disk` (optional): if a parameter(s) is not JSON serializable, a + user can override this function to assist in loading the processor diff --git a/docs/0.10.3/html/_sources/data_reader.nblink.txt b/docs/0.10.3/html/_sources/data_reader.nblink.txt new file mode 100644 index 000000000..4722970da --- /dev/null +++ b/docs/0.10.3/html/_sources/data_reader.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/data_readers.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/data_readers.rst.txt b/docs/0.10.3/html/_sources/data_readers.rst.txt new file mode 100644 index 000000000..4679d33a6 --- /dev/null +++ b/docs/0.10.3/html/_sources/data_readers.rst.txt @@ -0,0 +1,164 @@ +.. _data_readers: + +Data Readers +************ + +The `Data` class itself will identify then output one of the following `Data` class types. +Using the data reader is easy, just pass it through the Data object. + +.. code-block:: python + + import dataprofiler as dp + data = dp.Data("your_file.csv") + +The supported file types are: + +* CSV file (or any delimited file) +* JSON object +* Avro file +* Parquet file +* Graph data file +* Text file +* Pandas DataFrame +* A URL that points to one of the supported file types above + +It's also possible to specifically call one of the data classes such as the following command: + +.. code-block:: python + + from dataprofiler.data_readers.csv_data import CSVData + data = CSVData("your_file.csv", options={"delimiter": ","}) + +Additionally any of the data classes can be loaded using a URL: + +.. code-block:: python + + import dataprofiler as dp + data = dp.Data("https://you_website.com/your_file.file", options={"verify_ssl": "True"}) + +Below are descriptions of the various `Data` classes and the available options. + +CSVData +======= + +Data class for loading datasets of type CSV. Can be specified by passing +in memory data or via a file path. Options pertaining the CSV may also +be specified using the options dict parameter. + +`CSVData(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* delimiter - Must be a string, for example `"delimiter": ","` +* data_format - Must be a string, possible choices: "dataframe", "records" +* selected_columns - Columns being selected from the entire dataset, must be a + list `["column 1", "ssn"]` +* sample_nrows - Reservoir sampling to sample `"n"` rows out of a total of `"M"` rows. + Specified for how many rows to sample, default None. +* header - Define the header, for example + + * `"header": 'auto'` for auto detection + * `"header": None` for no header + * `"header": ` to specify the header row (0 based index) + +JSONData +======== + +Data class for loading datasets of type JSON. Can be specified by +passing in memory data or via a file path. Options pertaining the JSON +may also be specified using the options dict parameter. JSON data can be +accessed via the "data" property, the "metadata" property, and the +"data_and_metadata" property. + +`JSONData(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* data_format - must be a string, choices: "dataframe", "records", "json", "flattened_dataframe" + + * "flattened_dataframe" is best used for JSON structure typically found in data streams that contain + nested lists of dictionaries and a payload. For example: `{"data": [ columns ], "response": 200}` +* selected_keys - columns being selected from the entire dataset, must be a list `["column 1", "ssn"]` +* payload_keys - The dictionary keys for the payload of the JSON, typically called "data" + or "payload". Defaults to ["data", "payload", "response"]. + + +AVROData +======== + +Data class for loading datasets of type AVRO. Can be specified by +passing in memory data or via a file path. Options pertaining the AVRO +may also be specified using the options dict parameter. + +`AVROData(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* data_format - must be a string, choices: "dataframe", "records", "avro", "json", "flattened_dataframe" + + * "flattened_dataframe" is best used for AVROs with a JSON structure typically found in data streams that contain + nested lists of dictionaries and a payload. For example: `{"data": [ columns ], "response": 200}` +* selected_keys - columns being selected from the entire dataset, must be a list `["column 1", "ssn"]` + +ParquetData +=========== + +Data class for loading datasets of type PARQUET. Can be specified by +passing in memory data or via a file path. Options pertaining the +PARQUET may also be specified using the options dict parameter. + +`ParquetData(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* data_format - must be a string, choices: "dataframe", "records", "json" +* selected_keys - columns being selected from the entire dataset, must be a list `["column 1", "ssn"]` + +GraphData +========= + +Data Class for loading datasets of graph data. Currently takes CSV format, +further type formats will be supported. Can be specified by passing +in memory data (NetworkX Graph) or via a file path. Options pertaining the CSV file may also +be specified using the options dict parameter. Loads data from CSV into memory +as a NetworkX Graph. + +`GraphData(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* delimiter - must be a string, for example `"delimiter": ","` +* data_format - must be a string, possible choices: "graph", "dataframe", "records" +* header - Define the header, for example + + * `"header": 'auto'` for auto detection + * `"header": None` for no header + * `"header": ` to specify the header row (0 based index) + +TextData +======== + +Data class for loading datasets of type TEXT. Can be specified by +passing in memory data or via a file path. Options pertaining the TEXT +may also be specified using the options dict parameter. + +`TextData(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* data_format: user selected format in which to return data. Currently only supports "text". +* samples_per_line - chunks by which to read in the specified dataset + + +Data Using a URL +================ + +Data class for loading datasets of any type using a URL. Specified by passing in +any valid URL that points to one of the valid data types. Options pertaining the +URL may also be specified using the options dict parameter. + +`Data(input_file_path=None, data=None, options=None)` + +Possible `options`: + +* verify_ssl: must be a boolean string, choices: "True", "False". Set to "True" by default. \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.avro_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.avro_data.rst.txt new file mode 100644 index 000000000..d3227df29 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.avro_data.rst.txt @@ -0,0 +1,7 @@ +Avro Data +========= + +.. automodule:: dataprofiler.data_readers.avro_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.base_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.base_data.rst.txt new file mode 100644 index 000000000..b82883cb9 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.base_data.rst.txt @@ -0,0 +1,7 @@ +Base Data +========= + +.. automodule:: dataprofiler.data_readers.base_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.csv_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.csv_data.rst.txt new file mode 100644 index 000000000..85a625d69 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.csv_data.rst.txt @@ -0,0 +1,7 @@ +CSV Data +======== + +.. automodule:: dataprofiler.data_readers.csv_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.data.rst.txt new file mode 100644 index 000000000..813e81805 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.data.rst.txt @@ -0,0 +1,7 @@ +Data +==== + +.. automodule:: dataprofiler.data_readers.data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.data_utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.data_utils.rst.txt new file mode 100644 index 000000000..309208b73 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.data_utils.rst.txt @@ -0,0 +1,7 @@ +Data Utils +========== + +.. automodule:: dataprofiler.data_readers.data_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.filepath_or_buffer.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.filepath_or_buffer.rst.txt new file mode 100644 index 000000000..89e78cc2d --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.filepath_or_buffer.rst.txt @@ -0,0 +1,7 @@ +Filepath Or Buffer +================== + +.. automodule:: dataprofiler.data_readers.filepath_or_buffer + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.graph_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.graph_data.rst.txt new file mode 100644 index 000000000..b8b982f79 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.graph_data.rst.txt @@ -0,0 +1,7 @@ +Graph Data +========== + +.. automodule:: dataprofiler.data_readers.graph_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.json_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.json_data.rst.txt new file mode 100644 index 000000000..ae0a51d13 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.json_data.rst.txt @@ -0,0 +1,7 @@ +JSON Data +========= + +.. automodule:: dataprofiler.data_readers.json_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.parquet_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.parquet_data.rst.txt new file mode 100644 index 000000000..dfdcbe4bb --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.parquet_data.rst.txt @@ -0,0 +1,7 @@ +Parquet Data +============ + +.. automodule:: dataprofiler.data_readers.parquet_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.rst.txt new file mode 100644 index 000000000..56d68fe83 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.rst.txt @@ -0,0 +1,30 @@ +Data Readers +============ + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + +.. toctree:: + :maxdepth: 4 + + dataprofiler.data_readers.avro_data + dataprofiler.data_readers.base_data + dataprofiler.data_readers.csv_data + dataprofiler.data_readers.data + dataprofiler.data_readers.data_utils + dataprofiler.data_readers.filepath_or_buffer + dataprofiler.data_readers.graph_data + dataprofiler.data_readers.json_data + dataprofiler.data_readers.parquet_data + dataprofiler.data_readers.structured_mixins + dataprofiler.data_readers.text_data + +.. automodule:: dataprofiler.data_readers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.structured_mixins.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.structured_mixins.rst.txt new file mode 100644 index 000000000..157e03d2c --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.structured_mixins.rst.txt @@ -0,0 +1,7 @@ +Structured Mixins +================= + +.. automodule:: dataprofiler.data_readers.structured_mixins + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.data_readers.text_data.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.data_readers.text_data.rst.txt new file mode 100644 index 000000000..6ac6b9648 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.data_readers.text_data.rst.txt @@ -0,0 +1,7 @@ +Text Data +========= + +.. automodule:: dataprofiler.data_readers.text_data + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.dp_logging.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.dp_logging.rst.txt new file mode 100644 index 000000000..d1c6c910d --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.dp_logging.rst.txt @@ -0,0 +1,7 @@ +Dp Logging +========== + +.. automodule:: dataprofiler.dp_logging + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.base_data_labeler.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.base_data_labeler.rst.txt new file mode 100644 index 000000000..839a74157 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.base_data_labeler.rst.txt @@ -0,0 +1,7 @@ +Base Data Labeler +================= + +.. automodule:: dataprofiler.labelers.base_data_labeler + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.base_model.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.base_model.rst.txt new file mode 100644 index 000000000..c4bc9b08b --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.base_model.rst.txt @@ -0,0 +1,7 @@ +Base Model +========== + +.. automodule:: dataprofiler.labelers.base_model + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.char_load_tf_model.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.char_load_tf_model.rst.txt new file mode 100644 index 000000000..7dad3aa71 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.char_load_tf_model.rst.txt @@ -0,0 +1,7 @@ +Char Load Tf Model +================== + +.. automodule:: dataprofiler.labelers.char_load_tf_model + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.character_level_cnn_model.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.character_level_cnn_model.rst.txt new file mode 100644 index 000000000..80113a935 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.character_level_cnn_model.rst.txt @@ -0,0 +1,7 @@ +Character Level Cnn Model +========================= + +.. automodule:: dataprofiler.labelers.character_level_cnn_model + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.classification_report_utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.classification_report_utils.rst.txt new file mode 100644 index 000000000..4c3624869 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.classification_report_utils.rst.txt @@ -0,0 +1,7 @@ +Classification Report Utils +=========================== + +.. automodule:: dataprofiler.labelers.classification_report_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.column_name_model.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.column_name_model.rst.txt new file mode 100644 index 000000000..e4a5bc988 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.column_name_model.rst.txt @@ -0,0 +1,7 @@ +Column Name Model +================= + +.. automodule:: dataprofiler.labelers.column_name_model + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.data_labelers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.data_labelers.rst.txt new file mode 100644 index 000000000..6ac45d9e6 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.data_labelers.rst.txt @@ -0,0 +1,7 @@ +Data Labelers +============= + +.. automodule:: dataprofiler.labelers.data_labelers + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.data_processing.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.data_processing.rst.txt new file mode 100644 index 000000000..58d572a29 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.data_processing.rst.txt @@ -0,0 +1,7 @@ +Data Processing +=============== + +.. automodule:: dataprofiler.labelers.data_processing + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.labeler_utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.labeler_utils.rst.txt new file mode 100644 index 000000000..f14cabd5c --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.labeler_utils.rst.txt @@ -0,0 +1,7 @@ +Labeler Utils +============= + +.. automodule:: dataprofiler.labelers.labeler_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.regex_model.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.regex_model.rst.txt new file mode 100644 index 000000000..e85772ad2 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.regex_model.rst.txt @@ -0,0 +1,7 @@ +Regex Model +=========== + +.. automodule:: dataprofiler.labelers.regex_model + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.rst.txt new file mode 100644 index 000000000..7d660273e --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.rst.txt @@ -0,0 +1,30 @@ +Labelers +======== + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + +.. toctree:: + :maxdepth: 4 + + dataprofiler.labelers.base_data_labeler + dataprofiler.labelers.base_model + dataprofiler.labelers.char_load_tf_model + dataprofiler.labelers.character_level_cnn_model + dataprofiler.labelers.classification_report_utils + dataprofiler.labelers.column_name_model + dataprofiler.labelers.data_labelers + dataprofiler.labelers.data_processing + dataprofiler.labelers.labeler_utils + dataprofiler.labelers.regex_model + dataprofiler.labelers.utils + +.. automodule:: dataprofiler.labelers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.labelers.utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.labelers.utils.rst.txt new file mode 100644 index 000000000..a0486f9be --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.labelers.utils.rst.txt @@ -0,0 +1,7 @@ +Utils +===== + +.. automodule:: dataprofiler.labelers.utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.base_column_profilers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.base_column_profilers.rst.txt new file mode 100644 index 000000000..13cab9ff4 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.base_column_profilers.rst.txt @@ -0,0 +1,7 @@ +Base Column Profilers +===================== + +.. automodule:: dataprofiler.profilers.base_column_profilers + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.categorical_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.categorical_column_profile.rst.txt new file mode 100644 index 000000000..a525d86c8 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.categorical_column_profile.rst.txt @@ -0,0 +1,7 @@ +Categorical Column Profile +========================== + +.. automodule:: dataprofiler.profilers.categorical_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.column_profile_compilers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.column_profile_compilers.rst.txt new file mode 100644 index 000000000..9599deb9a --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.column_profile_compilers.rst.txt @@ -0,0 +1,7 @@ +Column Profile Compilers +======================== + +.. automodule:: dataprofiler.profilers.column_profile_compilers + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.data_labeler_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.data_labeler_column_profile.rst.txt new file mode 100644 index 000000000..282408931 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.data_labeler_column_profile.rst.txt @@ -0,0 +1,7 @@ +Data Labeler Column Profile +=========================== + +.. automodule:: dataprofiler.profilers.data_labeler_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.datetime_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.datetime_column_profile.rst.txt new file mode 100644 index 000000000..d4467634f --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.datetime_column_profile.rst.txt @@ -0,0 +1,7 @@ +Datetime Column Profile +======================= + +.. automodule:: dataprofiler.profilers.datetime_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.float_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.float_column_profile.rst.txt new file mode 100644 index 000000000..d23bb4336 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.float_column_profile.rst.txt @@ -0,0 +1,7 @@ +Float Column Profile +==================== + +.. automodule:: dataprofiler.profilers.float_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.graph_profiler.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.graph_profiler.rst.txt new file mode 100644 index 000000000..196194771 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.graph_profiler.rst.txt @@ -0,0 +1,7 @@ +Graph Profiler +============== + +.. automodule:: dataprofiler.profilers.graph_profiler + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.report_helpers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.report_helpers.rst.txt new file mode 100644 index 000000000..c20d1f391 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.report_helpers.rst.txt @@ -0,0 +1,7 @@ +Report Helpers +============== + +.. automodule:: dataprofiler.profilers.helpers.report_helpers + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.rst.txt new file mode 100644 index 000000000..b82f660b5 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.helpers.rst.txt @@ -0,0 +1,20 @@ +Helpers +======= + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + +.. toctree:: + :maxdepth: 4 + + dataprofiler.profilers.helpers.report_helpers + +.. automodule:: dataprofiler.profilers.helpers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.histogram_utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.histogram_utils.rst.txt new file mode 100644 index 000000000..039bb08d8 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.histogram_utils.rst.txt @@ -0,0 +1,7 @@ +Histogram Utils +=============== + +.. automodule:: dataprofiler.profilers.histogram_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.int_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.int_column_profile.rst.txt new file mode 100644 index 000000000..b6d8d7921 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.int_column_profile.rst.txt @@ -0,0 +1,7 @@ +Int Column Profile +================== + +.. automodule:: dataprofiler.profilers.int_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.json_decoder.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.json_decoder.rst.txt new file mode 100644 index 000000000..761551996 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.json_decoder.rst.txt @@ -0,0 +1,7 @@ +JSON Decoder +============ + +.. automodule:: dataprofiler.profilers.json_decoder + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.json_encoder.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.json_encoder.rst.txt new file mode 100644 index 000000000..bef659ecd --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.json_encoder.rst.txt @@ -0,0 +1,7 @@ +JSON Encoder +============ + +.. automodule:: dataprofiler.profilers.json_encoder + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.numerical_column_stats.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.numerical_column_stats.rst.txt new file mode 100644 index 000000000..a8b6ac226 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.numerical_column_stats.rst.txt @@ -0,0 +1,7 @@ +Numerical Column Stats +====================== + +.. automodule:: dataprofiler.profilers.numerical_column_stats + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.order_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.order_column_profile.rst.txt new file mode 100644 index 000000000..7b1605659 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.order_column_profile.rst.txt @@ -0,0 +1,7 @@ +Order Column Profile +==================== + +.. automodule:: dataprofiler.profilers.order_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.profile_builder.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.profile_builder.rst.txt new file mode 100644 index 000000000..d73e6d9a2 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.profile_builder.rst.txt @@ -0,0 +1,7 @@ +Profile Builder +=============== + +.. automodule:: dataprofiler.profilers.profile_builder + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_options.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_options.rst.txt new file mode 100644 index 000000000..127e8e1ad --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_options.rst.txt @@ -0,0 +1,7 @@ +Profiler Options +================ + +.. automodule:: dataprofiler.profilers.profiler_options + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_utils.rst.txt new file mode 100644 index 000000000..5e9c6533c --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.profiler_utils.rst.txt @@ -0,0 +1,7 @@ +Profiler Utils +============== + +.. automodule:: dataprofiler.profilers.profiler_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.rst.txt new file mode 100644 index 000000000..7a5b45394 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.rst.txt @@ -0,0 +1,39 @@ +Profilers +========= + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + dataprofiler.profilers.helpers + +.. toctree:: + :maxdepth: 4 + + dataprofiler.profilers.base_column_profilers + dataprofiler.profilers.categorical_column_profile + dataprofiler.profilers.column_profile_compilers + dataprofiler.profilers.data_labeler_column_profile + dataprofiler.profilers.datetime_column_profile + dataprofiler.profilers.float_column_profile + dataprofiler.profilers.graph_profiler + dataprofiler.profilers.histogram_utils + dataprofiler.profilers.int_column_profile + dataprofiler.profilers.json_decoder + dataprofiler.profilers.json_encoder + dataprofiler.profilers.numerical_column_stats + dataprofiler.profilers.order_column_profile + dataprofiler.profilers.profile_builder + dataprofiler.profilers.profiler_options + dataprofiler.profilers.profiler_utils + dataprofiler.profilers.text_column_profile + dataprofiler.profilers.unstructured_labeler_profile + dataprofiler.profilers.unstructured_text_profile + +.. automodule:: dataprofiler.profilers + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.text_column_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.text_column_profile.rst.txt new file mode 100644 index 000000000..097e6e02c --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.text_column_profile.rst.txt @@ -0,0 +1,7 @@ +Text Column Profile +=================== + +.. automodule:: dataprofiler.profilers.text_column_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_labeler_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_labeler_profile.rst.txt new file mode 100644 index 000000000..c49f68004 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_labeler_profile.rst.txt @@ -0,0 +1,7 @@ +Unstructured Labeler Profile +============================ + +.. automodule:: dataprofiler.profilers.unstructured_labeler_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_text_profile.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_text_profile.rst.txt new file mode 100644 index 000000000..27b56ea93 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.unstructured_text_profile.rst.txt @@ -0,0 +1,7 @@ +Unstructured Text Profile +========================= + +.. automodule:: dataprofiler.profilers.unstructured_text_profile + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.profilers.utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.profilers.utils.rst.txt new file mode 100644 index 000000000..ddae85e63 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.profilers.utils.rst.txt @@ -0,0 +1,7 @@ +Utils +===== + +.. automodule:: dataprofiler.profilers.utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.reports.graphs.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.reports.graphs.rst.txt new file mode 100644 index 000000000..3a7adf900 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.reports.graphs.rst.txt @@ -0,0 +1,7 @@ +Graphs +====== + +.. automodule:: dataprofiler.reports.graphs + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.reports.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.reports.rst.txt new file mode 100644 index 000000000..59525629c --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.reports.rst.txt @@ -0,0 +1,21 @@ +Reports +======= + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + +.. toctree:: + :maxdepth: 4 + + dataprofiler.reports.graphs + dataprofiler.reports.utils + +.. automodule:: dataprofiler.reports + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.reports.utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.reports.utils.rst.txt new file mode 100644 index 000000000..97e26cde0 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.reports.utils.rst.txt @@ -0,0 +1,7 @@ +Utils +===== + +.. automodule:: dataprofiler.reports.utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.rng_utils.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.rng_utils.rst.txt new file mode 100644 index 000000000..e4b84b46a --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.rng_utils.rst.txt @@ -0,0 +1,7 @@ +Rng Utils +========= + +.. automodule:: dataprofiler.rng_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.rst.txt new file mode 100644 index 000000000..d5ed33a58 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.rst.txt @@ -0,0 +1,28 @@ +Dataprofiler +============ + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + dataprofiler.data_readers + dataprofiler.labelers + dataprofiler.profilers + dataprofiler.reports + dataprofiler.validators + +.. toctree:: + :maxdepth: 4 + + dataprofiler.dp_logging + dataprofiler.rng_utils + dataprofiler.settings + dataprofiler.version + +.. automodule:: dataprofiler + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.settings.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.settings.rst.txt new file mode 100644 index 000000000..81c664c07 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.settings.rst.txt @@ -0,0 +1,7 @@ +Settings +======== + +.. automodule:: dataprofiler.settings + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.validators.base_validators.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.validators.base_validators.rst.txt new file mode 100644 index 000000000..b8f328736 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.validators.base_validators.rst.txt @@ -0,0 +1,7 @@ +Base Validators +=============== + +.. automodule:: dataprofiler.validators.base_validators + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/dataprofiler.validators.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.validators.rst.txt new file mode 100644 index 000000000..704dfee21 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.validators.rst.txt @@ -0,0 +1,20 @@ +Validators +========== + + +Modules +------- + +.. toctree:: + :maxdepth: 4 + + +.. toctree:: + :maxdepth: 4 + + dataprofiler.validators.base_validators + +.. automodule:: dataprofiler.validators + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/0.10.3/html/_sources/dataprofiler.version.rst.txt b/docs/0.10.3/html/_sources/dataprofiler.version.rst.txt new file mode 100644 index 000000000..3977b6379 --- /dev/null +++ b/docs/0.10.3/html/_sources/dataprofiler.version.rst.txt @@ -0,0 +1,7 @@ +Version +======= + +.. automodule:: dataprofiler.version + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/examples.rst.txt b/docs/0.10.3/html/_sources/examples.rst.txt new file mode 100644 index 000000000..3637da6ac --- /dev/null +++ b/docs/0.10.3/html/_sources/examples.rst.txt @@ -0,0 +1,24 @@ +.. _examples: + +Examples +******** + +These examples provide a more in-depth look into the details of the ``Data Profiler`` library. + +Basics +------ + +.. toctree:: + :maxdepth: 0 + + Overview of Data Profiler + Data Reader + Structured Profiler + Unstructured Profiler + Graph Profiler + Labeler + Adding Models to a Labeler Pipeline + Creating a Regex Labeler + Creating a ColumnName Labeler + Merge Profile List + Dataloader with Popmon Reports diff --git a/docs/0.10.3/html/_sources/graph_data_demo.nblink.txt b/docs/0.10.3/html/_sources/graph_data_demo.nblink.txt new file mode 100644 index 000000000..e627c61f8 --- /dev/null +++ b/docs/0.10.3/html/_sources/graph_data_demo.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/graph_data_demo.ipynb" +} diff --git a/docs/0.10.3/html/_sources/graphs.rst.txt b/docs/0.10.3/html/_sources/graphs.rst.txt new file mode 100644 index 000000000..23c2d316b --- /dev/null +++ b/docs/0.10.3/html/_sources/graphs.rst.txt @@ -0,0 +1,196 @@ +.. _reports: + +Graphs +****** + +Graph Your Data +=============== + +We can plot some of our data as seaborn histogram plots. Below will demonstrate how to do so and provide examples. + +The following plots are currently available to work directly with your profilers: + + * histogram (numeric columns only) + * missing values matrix + +Below shows how to do so with examples. + +What we need to import +~~~~~~~~~~~~~~~~~~~~~~ +.. code-block:: python + + from dataprofiler.reports import graphs + +The main functions that is used to plot histograms are in graphs. **You will also need the `dataprofiler[reports]` requirement to be installed**: + +.. code-block:: console + + pip install 'dataprofiler[reports]' + +Plotting from a StructuredProfiler class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With a StructuredProfiler class variable, we can specify what columns we want to be plotted, and plot them into histograms. + +.. code-block:: python + + graphs.plot_histograms(profiler, column_names, column_inds) + +These are what the variables mean: + + * **profiler** - StructuredProfiler class variable that contains the data we want + * **columns** - (Optional) The list of IntColumn or FloatColumn *names* we want to specifically plot. If specified, `column_inds` cannot be specified. + * **column_inds** - (Optional) The list of IntColumn or FloatColumn *indexes* we want to specifically plot. If specified, `column_names` cannot be specified. + + +Additionally, we can also plot the missing values matrix for a StructuredProfiler: + +.. code-block:: python + + graphs.plot_missing_values_matrix(profiler, ax, title) + +These are what the variables mean: + + * **profiler** - StructuredProfiler class variable that contains the data we want + * **ax** - (Optional) MatPlotLib Axes to plot the matrix within. + * **title** - (Optional) The title of the axes we want to define. + + +Plotting an individual IntColumn or FloatColumn +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With a column's Int or Float profile, we can plot their respective histograms. + +.. code-block:: python + + graphs.plot_col_histogram(column, axes, title) + +These are what the variables mean: + + * **column** - The IntColumn or FloatColumn we want to plot + * **axes** - (Optional) The MatPlotLib Axes to plot the histogram within. + * **title** - (Optional) The title of the axes we want to define. + + +Additionally, we can also plot the missing values bargraph for any column profile: + +.. code-block:: python + + graphs.plot_col_missing_values(profiler, ax, title) + +These are what the variables mean: + + * **profiler** - The StructuredColProfiler we want to plot + * **ax** - (Optional) MatPlotLib Axes to plot the matrix within. + * **title** - (Optional) The title of the axes we want to define. + +Examples +~~~~~~~~ + +Histograms +---------- + +1. This example demonstrates how we can take a StructuredProfiler class and plot histograms of the specified columns. + +.. code-block:: python + + import dataprofiler as dp + from dataprofiler.reports import graphs + + + data = [[1, 'a', 1.0], + [2, 'b', 2.2], + [3, 'c', 3.5], + [None, 'd', 10.0]] + profiler = dp.StructuredProfiler(data) + + # This will plot all IntColumn and FloatColumn as histograms (The first and last column). + fig = graphs.plot_histograms(profiler) + fig.show() + + # This will only plot the specified column, 0. + columns_names = [0] + fig = graphs.plot_histograms(profiler, columns_names) + fig.show() + +.. image:: _static/images/histogram_example_0.png + :alt: First Histogram Example Image + +.. image:: _static/images/histogram_example_1.png + :alt: Second Histogram Example Image + +2. This example demonstrates how we can plot a low level profiler. + +.. code-block:: python + + import pandas as pd + + from dataprofiler.profilers import IntColumn + from dataprofiler.reports import graphs + + + data = pd.Series([1, 2, 3], dtype=str) + profiler = IntColumn('example') + profiler.update(data) + + # Plot the axes + ax = graphs.plot_col_histogram(profiler) + + # get and show the figure of the plotted histogram + fig = ax.get_figure() + fig.show() + +.. image:: _static/images/histogram_example_2.png + :alt: Histogram Column Only Example Image + + +Missing Values Matrix +--------------------- + +1. This example demonstrates how we can take a StructuredProfiler class and plot a missing values matrix. + +.. code-block:: python + + import dataprofiler as dp + from dataprofiler.reports import graphs + + + data = pd.DataFrame( + [[None, '', 1.0, '1/2/2021'], + [3, None, 3.5, ''], + [1, None, 1.0, '2/5/2020'], + [None, 1, 10.0, '3/5/2020']], + columns=['integer', 'str', 'float', 'datetime'], + dtype=object + ) + profiler = dp.StructuredProfiler(data) + + # This will plot the missing values matrix for all columns. + fig = graphs.plot_missing_values_matrix(profiler) + fig.show() + +.. image:: _static/images/missing_value_matrix_example_0.png + :alt: Missing Values Matrix Example Image + +2. This example demonstrates how we can plot barchart of a column's missing values. + +.. code-block:: python + + import pandas as pd + + from dataprofiler.profilers.profile_builder import StructuredColProfiler + from dataprofiler.reports import graphs + + + data = pd.Series([1, 2, 3, None, None, 4], name='example', dtype=str) + profiler = StructuredColProfiler(data) + + # Plot the axes, can be a list of multiple columns + ax = graphs.plot_col_missing_values([profiler]) + + # get and show the figure of the plotted histogram + fig = ax.get_figure() + fig.show() + +.. image:: _static/images/missing_value_barchart_example_0.png + :alt: Missing Values Column Only Example Image \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/index.rst.txt b/docs/0.10.3/html/_sources/index.rst.txt new file mode 100644 index 000000000..9f3bb4369 --- /dev/null +++ b/docs/0.10.3/html/_sources/index.rst.txt @@ -0,0 +1,580 @@ +.. _Data Profiler: + +==================================== +Data Profiler | What's in your data? +==================================== + +Purpose +======= + +The DataProfiler is a Python library designed to make data analysis, monitoring and **sensitive data detection** easy. + +Loading **Data** with a single command, the library automatically formats & loads files into a DataFrame. **Profiling** the Data, the library identifies the schema, statistics, entities and more. Data Profiles can then be used in downstream applications or reports. + +The Data Profiler comes with a cutting edge pre-trained deep learning model, used to efficiently identify **sensitive data** (or **PII**). If customization is needed, it's easy to add new entities to the existing pre-trained model or insert a new pipeline for entity recognition. + +The best part? Getting started only takes a few lines of code (`Example CSV`_): + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + data = Data("your_file.csv") # Auto-Detect & Load: CSV, AVRO, Parquet, JSON, Text + print(data.data.head(5)) # Access data directly via a compatible Pandas DataFrame + + profile = Profiler(data) # Calculate Statistics, Entity Recognition, etc + readable_report = profile.report(report_options={"output_format":"pretty"}) + print(json.dumps(readable_report, indent=4)) + + +To install the full package from pypi: + +.. code-block:: console + + pip install DataProfiler[ml] + +If the ML requirements are too strict (say, you don't want to install tensorflow), you can install a slimmer package. The slimmer package disables the default sensitive data detection / entity recognition (labler) + +Install from pypi: + +.. code-block:: console + + pip install DataProfiler + +If you have suggestions or find a bug, please open an `issue`_. + +Visit the :ref:`API` to explore Data Profiler's terminology. + + +What is a Data Profile? +======================= + +In the case of this library, a data profile is a dictionary containing statistics and predictions about the underlying dataset. There are "global statistics" or `global_stats`, which contain dataset level data and there are "column/row level statistics" or `data_stats` (each column is a new key-value entry). + +The format for a structured profile is below: + +.. code-block:: python + + "global_stats": { + "samples_used": int, + "column_count": int, + "row_count": int, + "row_has_null_ratio": float, + "row_is_null_ratio": float, + "unique_row_ratio": float, + "duplicate_row_count": int, + "file_type": string, + "encoding": string, + "correlation_matrix": list[list[int]], (*) + "chi2_matrix": list[list[float]], + "profile_schema": dict[string, list[int]] + }, + "data_stats": [ + { + "column_name": string, + "data_type": string, + "data_label": string, + "categorical": bool, + "order": string, + "samples": list[str], + "statistics": { + "sample_size": int, + "null_count": int, + "null_types": list[string], + "null_types_index": dict[string, list[int]], + "data_type_representation": dict[string, list[string]], + "min": [null, float], + "max": [null, float], + "sum": float, + "mode": list[float], + "median": float, + "median_absolute_deviation": float, + "mean": float, + "variance": float, + "stddev": float, + "skewness": float, + "kurtosis": float, + "num_zeros": int, + "num_negatives": int, + "histogram": { + "bin_counts": list[int], + "bin_edges": list[float], + }, + "quantiles": { + int: float + }, + "vocab": list[char], + "avg_predictions": dict[string, float], + "data_label_representation": dict[string, float], + "categories": list[str], + "unique_count": int, + "unique_ratio": float, + "categorical_count": dict[string, int], + "gini_impurity": float, + "unalikeability": float, + "precision": { + 'min': int, + 'max': int, + 'mean': float, + 'var': float, + 'std': float, + 'sample_size': int, + 'margin_of_error': float, + 'confidence_level': float + }, + "times": dict[string, float], + "format": string + }, + "null_replication_metrics": { + "class_prior": list[int], + "class_sum": list[list[int]], + "class_mean": list[list[int]] + } + } + ] + +(*) Currently the correlation matrix update is toggled off. It will be reset in a later update. Users can still use it as desired with the is_enable option set to True. + +The format for an unstructured profile is below: + +.. code-block:: python + + "global_stats": { + "samples_used": int, + "empty_line_count": int, + "file_type": string, + "encoding": string, + "memory_size": float, # in MB + }, + "data_stats": { + "data_label": { + "entity_counts": { + "word_level": dict[string, int], + "true_char_level": dict[string, int], + "postprocess_char_level": dict[string, int] + }, + "entity_percentages": { + "word_level": dict[string, float], + "true_char_level": dict[string, float], + "postprocess_char_level": dict[string, float] + }, + "times": dict[string, float] + }, + "statistics": { + "vocab": list[char], + "vocab_count": dict[string, int], + "words": list[string], + "word_count": dict[string, int], + "times": dict[string, float] + } + } + +The format for a graph profile is below: + +.. code-block:: python + + "num_nodes": int, + "num_edges": int, + "categorical_attributes": list[string], + "continuous_attributes": list[string], + "avg_node_degree": float, + "global_max_component_size": int, + "continuous_distribution": { + "": { + "name": string, + "scale": float, + "properties": list[float, np.array] + }, + "": None, + }, + "categorical_distribution": { + "": None, + "": { + "bin_counts": list[int], + "bin_edges": list[float] + }, + }, + "times": dict[string, float] + +Supported Data Formats +~~~~~~~~~~~~~~~~~~~~~~ + +* Any delimited file (CSV, TSV, etc.) +* JSON object +* Avro file +* Parquet file +* Text file +* Pandas DataFrame +* A URL that points to one of the supported file types above + + +Data Labels +~~~~~~~~~~~ + +*Data Labels* are determined per cell for structured data (column/row when the *profiler* is used) or at the character level for unstructured data. + +* UNKNOWN +* ADDRESS +* BAN (bank account number, 10-18 digits) +* CREDIT_CARD +* EMAIL_ADDRESS +* UUID +* HASH_OR_KEY (md5, sha1, sha256, random hash, etc.) +* IPV4 +* IPV6 +* MAC_ADDRESS +* PERSON +* PHONE_NUMBER +* SSN +* URL +* US_STATE +* DRIVERS_LICENSE +* DATE +* TIME +* DATETIME +* INTEGER +* FLOAT +* QUANTITY +* ORDINAL + + +Get Started +=========== + +Load a File +~~~~~~~~~~~ + +The profiler should automatically identify the file type and load the data into a `Data Class`. + +Along with other attributtes the `Data class` enables structured data to be accessed via a valid Pandas DataFrame. + +.. code-block:: python + + # Load a csv file, return a CSVData object + csv_data = Data('your_file.csv') + + # Print the first 10 rows of the csv file + print(csv_data.data.head(10)) + + # Load a parquet file, return a ParquetData object + parquet_data = Data('your_file.parquet') + + # Sort the data by the name column + parquet_data.data.sort_values(by='name', inplace=True) + + # Print the sorted first 10 rows of the parquet data + print(parquet_data.data.head(10)) + + +If the file type is not automatically identified (rare), you can specify them +specifically, see section Data Readers. + +Profile a File +~~~~~~~~~~~~~~ + +Example uses a CSV file for example, but CSV, JSON, Avro, Parquet or Text should also work. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load file (CSV should be automatically identified) + data = Data("your_file.csv") + + # Profile the dataset + profile = Profiler(data) + + # Generate a report and use json to prettify. + report = profile.report(report_options={"output_format":"pretty"}) + + # Print the report + print(json.dumps(report, indent=4)) + +Updating Profiles +~~~~~~~~~~~~~~~~~ + +Currently, the data profiler is equipped to update its profile in batches. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load and profile a CSV file + data = Data("your_file.csv") + profile = Profiler(data) + + # Update the profile with new data: + new_data = Data("new_data.csv") + profile.update_profile(new_data) + + # Print the report using json to prettify. + report = profile.report(report_options={"output_format":"pretty"}) + print(json.dumps(report, indent=4)) + + +Merging Profiles +~~~~~~~~~~~~~~~~ + +If you have two files with the same schema (but different data), it is possible to merge the two profiles together via an addition operator. + +This also enables profiles to be determined in a distributed manner. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load a CSV file with a schema + data1 = Data("file_a.csv") + profile1 = Profiler(data) + + # Load another CSV file with the same schema + data2 = Data("file_b.csv") + profile2 = Profiler(data) + + profile3 = profile1 + profile2 + + # Print the report using json to prettify. + report = profile3.report(report_options={"output_format":"pretty"}) + print(json.dumps(report, indent=4)) + +Profile a Pandas DataFrame +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + import pandas as pd + import dataprofiler as dp + import json + + my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]]) + profile = dp.Profiler(my_dataframe) + + # print the report using json to prettify. + report = profile.report(report_options={"output_format":"pretty"}) + print(json.dumps(report, indent=4)) + + # read a specified column, in this case it is labeled 0: + print(json.dumps(report["data stats"][0], indent=4)) + + +Unstructured Profiler +~~~~~~~~~~~~~~~~~~~~~ + +In addition to the structured profiler, the Data Profiler provides unstructured +profiling for the TextData object or string. Unstructured profiling also works +with list(string), pd.Series(string) or pd.DataFrame(string) given profiler_type +option specified as `unstructured`. Below is an example of unstructured profile +with a text file. + +.. code-block:: python + + import dataprofiler as dp + import json + my_text = dp.Data('text_file.txt') + profile = dp.Profiler(my_text) + + # print the report using json to prettify. + report = profile.report(report_options={"output_format":"pretty"}) + print(json.dumps(report, indent=4)) + +Another example of unstructured profile with pd.Series of string is given as below + +.. code-block:: python + + import dataprofiler as dp + import pandas as pd + import json + + text_data = pd.Series(['first string', 'second string']) + profile = dp.Profiler(text_data, profiler_type="unstructured") + + # print the report using json to prettify. + report = profile.report(report_options={"output_format":"pretty"}) + print(json.dumps(report, indent=4)) + + +Graph Profiler +~~~~~~~~~~~~~~ + +DataProfiler also provides the ability to profile graph data from a csv file. Below is an example of the graph profiler with a graph data csv file: + +.. code-block:: python + + import dataprofiler as dp + import pprint + + my_graph = dp.Data('graph_file.csv') + profile = dp.Profiler(my_graph) + + # print the report using pretty print (json dump does not work on numpy array values inside dict) + report = profile.report() + printer = pprint.PrettyPrinter(sort_dicts=False, compact=True) + printer.pprint(report) + + +Specifying a Filetype or Delimiter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Example of specifying a CSV data type, with a `,` delimiter. +In addition, it utilizes only the first 10,000 rows. + +.. code-block:: python + + import json + import os + from dataprofiler import Data, Profiler + from dataprofiler.data_readers.csv_data import CSVData + + # Load a CSV file, with "," as the delimiter + data = CSVData("your_file.csv", options={"delimiter": ","}) + + # Split the data, such that only the first 10,000 rows are used + data = data.data[0:10000] + + # Read in profile and print results + profile = Profiler(data) + print(json.dumps(profile.report(report_options={"output_format":"pretty"}), indent=4)) + + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Getting Started: + + Intro + install.rst + data_readers.rst + profiler.rst + data_labeling.rst + graphs.rst + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: User Guide: + + examples.rst + API.rst + +.. toctree:: + :maxdepth: 2 + :hidden: + :caption: Community: + + Changelog + Feedback + GitHub + Contributing + +.. _Example CSV: https://raw.githubusercontent.com/capitalone/DataProfiler/main/dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv +.. _issue: https://github.com/capitalone/DataProfiler/issues/new/choose + +Versions +======== +* `0.10.3`_ +* `0.10.2`_ +* `0.10.1`_ +* `0.10.0`_ +* `0.9.0`_ +* `0.8.9`_ +* `0.8.8`_ +* `0.8.7`_ +* `0.8.6`_ +* `0.8.5`_ +* `0.8.4`_ +* `0.8.3`_ +* `0.8.2`_ +* `0.8.1`_ +* `0.8.0`_ +* `0.7.11`_ +* `0.7.10`_ +* `0.7.9`_ +* `0.7.8`_ +* `0.7.7`_ +* `0.7.6`_ +* `0.7.2`_ +* `0.7.1`_ +* `0.7.0`_ +* `0.6.0`_ +* `0.5.3`_ +* `0.5.2`_ +* `0.5.1`_ +* `0.5.0`_ +* `0.4.7`_ +* `0.4.6`_ +* `0.4.5`_ +* `0.4.4`_ +* `0.4.3`_ +* `0.3.0`_ + +.. _0.3.0: ../../v0.3/html/index.html +.. _0.4.3: ../../0.4.3/html/index.html + +.. _0.4.4: ../../0.4.4/html/index.html + +.. _0.4.5: ../../0.4.5/html/index.html + +.. _0.4.6: ../../0.4.6/html/index.html + +.. _0.4.7: ../../0.4.7/html/index.html + +.. _0.5.0: ../../0.5.0/html/index.html + +.. _0.5.1: ../../0.5.1/html/index.html + +.. _0.5.2: ../../0.5.2/html/index.html + +.. _0.5.3: ../../0.5.3/html/index.html +.. _0.6.0: ../../0.6.0/html/index.html + +.. _0.7.0: ../../0.7.0/html/index.html + +.. _0.7.1: ../../0.7.1/html/index.html +.. _0.7.2: ../../0.7.2/html/index.html + +.. _0.7.6: ../../0.7.6/html/index.html + +.. _0.7.7: ../../0.7.7/html/index.html + +.. _0.7.8: ../../0.7.8/html/index.html + +.. _0.7.9: ../../0.7.9/html/index.html + +.. _0.7.10: ../../0.7.10/html/index.html + +.. _0.7.11: ../../0.7.11/html/index.html + +.. _0.8.0: ../../0.8.0/html/index.html + +.. _0.8.1: ../../0.8.1/html/index.html + +.. _0.8.2: ../../0.8.2/html/index.html + +.. _0.8.3: ../../0.8.3/html/index.html + +.. _0.8.4: ../../0.8.4/html/index.html + +.. _0.8.5: ../../0.8.5/html/index.html + +.. _0.8.6: ../../0.8.6/html/index.html + +.. _0.8.7: ../../0.8.7/html/index.html + +.. _0.8.8: ../../0.8.8/html/index.html + +.. _0.8.9: ../../0.8.9/html/index.html + +.. _0.9.0: ../../0.9.0/html/index.html + +.. _0.10.0: ../../0.10.0/html/index.html + +.. _0.10.1: ../../0.10.1/html/index.html + +.. _0.10.2: ../../0.10.2/html/index.html + +.. _0.10.3: ../../0.10.3/html/index.html + diff --git a/docs/0.10.3/html/_sources/install.rst.txt b/docs/0.10.3/html/_sources/install.rst.txt new file mode 100644 index 000000000..9db049e92 --- /dev/null +++ b/docs/0.10.3/html/_sources/install.rst.txt @@ -0,0 +1,138 @@ +.. _install: + +Install +******* + +To install the full package from pypi: + +.. code-block:: console + + pip install DataProfiler[ml] + +If the ML requirements are too strict (say, you don't want to install +tensorflow), you can install a slimmer package. The slimmer package disables +the default sensitive data detection / entity recognition (labler) + +Install from pypi: + +.. code-block:: console + + pip install DataProfiler + +Snappy Installation +=================== + +This is required to profile parquet/avro datasets + +MacOS with homebrew: + +.. code-block:: console + + brew install snappy && CPPFLAGS="-I/usr/local/include -L/usr/local/lib" pip install python-snappy + + +Linux install: + +.. code-block:: console + + sudo apt-get -y install libsnappy-dev + + +Build From Scratch +================== + +NOTE: Installation for python3 + +virtualenv install: + +.. code-block:: console + + python3 -m pip install virtualenv + + +Setup virtual env: + +.. code-block:: console + + python3 -m virtualenv --python=python3 venv3 + source venv3/bin/activate + + +Install requirements: + +.. code-block:: console + + pip3 install -r requirements.txt + +Install labeler dependencies: + +.. code-block:: console + + pip3 install -r requirements-ml.txt + + +Install via the repo -- Build setup.py and install locally: + +.. code-block:: console + + python3 setup.py sdist bdist bdist_wheel + pip3 install dist/DataProfiler*-py3-none-any.whl + + +If you see: + +.. code-block:: console + + ERROR: Double requirement given:dataprofiler==X.Y.Z from dataprofiler/dist/DataProfiler-X.Y.Z-py3-none-any.whl (already in dataprofiler==X2.Y2.Z2 from dataprofiler/dist/DataProfiler-X2.Y2.Z2-py3-none-any.whl, name='dataprofiler') + +This means that you have multiple versions of the DataProfiler distribution +in the dist folder. +To resolve, either remove the older one or delete the folder and rerun the steps +above. + +Install via github: + +.. code-block:: console + + pip3 install git+https://github.com/capitalone/dataprofiler.git#egg=dataprofiler + + + +Testing +======= + +For testing, install test requirements: + +.. code-block:: console + + pip3 install -r requirements-test.txt + + +To run all unit tests, use: + +.. code-block:: console + + DATAPROFILER_SEED=0 python3 -m unittest discover -p "test*.py" + + +To run file of unit tests, use form: + +.. code-block:: console + + DATAPROFILER_SEED=0 python3 -m unittest discover -p test_profile_builder.py + + +To run a file with Pytest use: + +.. code-block:: console + + DATAPROFILER_SEED=0 pytest dataprofiler/tests/data_readers/test_csv_data.py -v + + +To run individual of unit test, use form: + +.. code-block:: console + + DATAPROFILER_SEED=0 python3 -m unittest dataprofiler.tests.profilers.test_profile_builder.TestProfiler + + diff --git a/docs/0.10.3/html/_sources/labeler.nblink.txt b/docs/0.10.3/html/_sources/labeler.nblink.txt new file mode 100644 index 000000000..bed6517bf --- /dev/null +++ b/docs/0.10.3/html/_sources/labeler.nblink.txt @@ -0,0 +1,6 @@ +{ + "path": "../../feature_branch/examples/labeler.ipynb", + "extra-media": [ + "../../feature_branch/examples/DL-Flowchart.png" + ] +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/merge_profile_list.nblink.txt b/docs/0.10.3/html/_sources/merge_profile_list.nblink.txt new file mode 100644 index 000000000..50698d637 --- /dev/null +++ b/docs/0.10.3/html/_sources/merge_profile_list.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/merge_profile_list.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/modules.rst.txt b/docs/0.10.3/html/_sources/modules.rst.txt new file mode 100644 index 000000000..0593459df --- /dev/null +++ b/docs/0.10.3/html/_sources/modules.rst.txt @@ -0,0 +1,7 @@ +dataprofiler +============ + +.. toctree:: + :maxdepth: 4 + + dataprofiler diff --git a/docs/0.10.3/html/_sources/overview.nblink.txt b/docs/0.10.3/html/_sources/overview.nblink.txt new file mode 100644 index 000000000..3d9f89d3d --- /dev/null +++ b/docs/0.10.3/html/_sources/overview.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/intro_data_profiler.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/popmon_dp_loader_example.nblink.txt b/docs/0.10.3/html/_sources/popmon_dp_loader_example.nblink.txt new file mode 100644 index 000000000..3beced0ab --- /dev/null +++ b/docs/0.10.3/html/_sources/popmon_dp_loader_example.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/popmon_dp_loader_example.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/profiler.rst.txt b/docs/0.10.3/html/_sources/profiler.rst.txt new file mode 100644 index 000000000..b51a72313 --- /dev/null +++ b/docs/0.10.3/html/_sources/profiler.rst.txt @@ -0,0 +1,962 @@ +.. _profiler: + +Profiler +******** + +Profile Your Data +================= + +Profiling your data is easy. Just use the data reader, send the data to the +profiler, and print out the report. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + data = Data("your_file.csv") # Auto-Detect & Load: CSV, AVRO, Parquet, JSON, Text + + profile = Profiler(data) # Calculate Statistics, Entity Recognition, etc + + readable_report = profile.report(report_options={"output_format": "pretty"}) + print(json.dumps(readable_report, indent=4)) + +If the data is structured, the profile will return global statistics as well as +column by column statistics. The vast amount of statistics are listed on the +intro page. + +Load a File +~~~~~~~~~~~ + +The profiler should automatically identify the file type and load the data into a `Data Class`. + +Along with other attributtes the `Data class` enables structured data to be accessed via a valid Pandas DataFrame. + +.. code-block:: python + + # Load a csv file, return a CSVData object + csv_data = Data('your_file.csv') + + # Print the first 10 rows of the csv file + print(csv_data.data.head(10)) + + # Load a parquet file, return a ParquetData object + parquet_data = Data('your_file.parquet') + + # Sort the data by the name column + parquet_data.data.sort_values(by='name', inplace=True) + + # Print the sorted first 10 rows of the parquet data + print(parquet_data.data.head(10)) + + +If the file type is not automatically identified (rare), you can specify them +specifically, see section Data Readers. + +Profile a File +~~~~~~~~~~~~~~ + +Example uses a CSV file for example, but CSV, JSON, Avro or Parquet should also work. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load file (CSV should be automatically identified) + data = Data("your_file.csv") + + # Profile the dataset + profile = Profiler(data) + + # Generate a report and use json to prettify. + report = profile.report(report_options={"output_format": "pretty"}) + + # Print the report + print(json.dumps(report, indent=4)) + +Updating Profiles +~~~~~~~~~~~~~~~~~ + +Currently, the data profiler is equipped to update its profile in batches. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load and profile a CSV file + data = Data("your_file.csv") + profile = Profiler(data) + + # Update the profile with new data: + new_data = Data("new_data.csv") + profile.update_profile(new_data) + + # Print the report using json to prettify. + report = profile.report(report_options={"output_format": "pretty"}) + print(json.dumps(report, indent=4)) + + +Merging Profiles +~~~~~~~~~~~~~~~~ + +If you have two files with the same schema (but different data), it is possible to merge the two profiles together via an addition operator. + +This also enables profiles to be determined in a distributed manner. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load a CSV file with a schema + data1 = Data("file_a.csv") + profile1 = Profiler(data) + + # Load another CSV file with the same schema + data2 = Data("file_b.csv") + profile2 = Profiler(data) + + profile3 = profile1 + profile2 + + # Print the report using json to prettify. + report = profile3.report(report_options={"output_format": "pretty"}) + print(json.dumps(report, indent=4)) + + +Profile Differences +~~~~~~~~~~~~~~~~~~~ + +Profile differences take two profiles and find the differences +between them. Create the difference report like this: + +.. code-block:: python + + from dataprofiler import Data, Profiler + + # Load a CSV file + data1 = Data("file_a.csv") + profile1 = Profiler(data) + + # Load another CSV file + data2 = Data("file_b.csv") + profile2 = Profiler(data) + + diff_report = profile1.diff(profile2) + print(diff_report) + +The `.diff()` operation is available between two profiles, although there are different +outputs depending on the type of profile being differenced. For example, for numerical +column profiles (e.g. integers and floats), two valuable calculations that +`.diff()` returns are `t-test`, `chi2-test`, and `psi` (Popoulation Stability Index) +for understanding distributional changes. + +The difference report contains a dictionary that mirrors the profile report. +Each data type has its own difference: + +* **Int/Float** - One profile subtracts the value from the other. + +* **String** - The strings will be shown in a list: + + - [profile1 str, profile2 str] +* **List** - A list of 3 will be returned showing the unique values of + each profile and the shared values: + + - [profile 1 unique values, shared values, profile 2 unique values] +* **Dict** - Some dictionaries with varied keys will also return a list + of three in the format: + + - [profile 1 unique key-values, shared key differences, profile 2 unique key-values] + +Otherwise, when no differences occur: + +* **Any Type No Differences** - A string will report: "unchanged". + +Below is the structured difference report: + +.. code-block:: python + + { + 'global_stats': { + 'file_type': [str, str], + 'encoding': [str, str], + 'samples_used': int, + 'column_count': int, + 'row_count': int, + 'row_has_null_ratio': float, + 'row_is_null_ratio': float, + 'unique_row_ratio': float, + 'duplicate_row_count': int, + 'correlation_matrix': list[list[float]], + 'chi2_matrix': list[list[float]], + 'profile_schema': list[dict[str, int]] + }, + 'data_stats': [{ + 'column_name': str, + 'data_type': [str, str], + 'data_label': [list[str], list[str], list[str]], + 'categorical': [str, str], + 'order': [str, str], + 'statistics': { + 'min': float, + 'max': float, + 'sum': float, + 'mean': float, + 'median': float, + 'mode': [list[float], list[float], list[float]], + 'median_absolute_deviation': float, + 'variance': float, + 'stddev': float, + 't-test': { + 't-statistic': float, + 'conservative': {'df': int, + 'p-value': float}, + 'welch': {'df': float, + 'p-value': float}}, + 'psi': float, + "chi2-test": { + "chi2-statistic": float, + "df": int, + "p-value": float + }, + 'unique_count': int, + 'unique_ratio': float, + 'categories': [list[str], list[str], list[str]], + 'gini_impurity': float, + 'unalikeability': float, + 'categorical_count': [dict[str, int], dict[str, int], dict[str, int]], + 'avg_predictions': [dict[str, float]], + 'label_representation': [dict[str, float]], + 'sample_size': int, + 'null_count': int, + 'null_types': [list[str], list[str], list[str]], + 'null_types_index': [dict[str, int], dict[str, int], dict[str, int]], + 'data_type_representation': [dict[str, float]] + }, + "null_replication_metrics": { + "class_prior": list[int], + "class_sum": list[list[int]], + "class_mean": list[list[int]] + } + } + +Below is the unstructured difference report: + +.. code-block:: python + + { + 'global_stats': { + 'file_type': [str, str], + 'encoding': [str, str], + 'samples_used': int, + 'empty_line_count': int, + 'memory_size': float + }, + 'data_stats': { + 'data_label': { + 'entity_counts': { + 'word_level': dict[str, int], + 'true_char_level': dict[str, int], + 'postprocess_char_level': dict[str, int] + }, + 'entity_percentages': { + 'word_level': dict[str, float], + 'true_char_level': dict[str, float], + 'postprocess_char_level': dict[str, float] + } + }, + 'statistics': { + 'vocab': [list[str], list[str], list[str]], + 'vocab_count': [dict[str, int], dict[str, int], dict[str, int]], + 'words': [list[str], list[str], list[str]], + 'word_count': [dict[str, int], dict[str, int], dict[str, int]] + } + } + } + + +Saving and Loading a Profile +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The profiles can easily be saved and loaded as shown below: + +**NOTE: Json saving and loading only supports Structured Profiles currently.** + +There are two save/load methods: + +* **Pickle save/load** + + * Save a profile as a `.pkl` file. + * Load a `.pkl` file as a profile object. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load a CSV file, with "," as the delimiter + data = Data("your_file.csv") + + # Read data into profile + profile = Profiler(data) + + # save structured profile to pkl file + profile.save(filepath="my_profile.pkl") + + # load pkl file to structured profile + loaded_pkl_profile = dp.Profiler.load(filepath="my_profile.pkl") + + print(json.dumps(loaded_pkl_profile.report(report_options={"output_format": "compact"}), + indent=4)) + +* **Json save/load** + + * Save a profile as a human-readable `.json` file. + * Load a `.json` file as a profile object. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Load a CSV file, with "," as the delimiter + data = Data("your_file.csv") + + # Read data into profile + profile = Profiler(data) + + # save structured profile to json file + profile.save(filepath="my_profile.json", save_method="json") + + # load json file to structured profile + loaded_json_profile = dp.Profiler.load(filepath="my_profile.json", load_method="json") + + print(json.dumps(loaded_json_profile.report(report_options={"output_format": "compact"}), + indent=4)) + + +Structured vs Unstructured Profiles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using the profiler, the data profiler will automatically infer whether to +create the structured profile or the unstructured profile. However, you can be +explicit as shown below: + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + + # Creating a structured profile + data1 = Data("normal_csv_file.csv") + structured_profile = Profiler(data1, profiler_type="structured") + + structured_report = structured_profile.report(report_options={"output_format": "pretty"}) + print(json.dumps(structured_report, indent=4)) + + # Creating an unstructured profile + data2 = Data("normal_text_file.txt") + unstructured_profile = Profiler(data2, profiler_type="unstructured") + + unstructured_report = unstructured_profile.report(report_options={"output_format": "pretty"}) + print(json.dumps(unstructured_report, indent=4)) + + +Setting the Sample Size +~~~~~~~~~~~~~~~~~~~~~~~ + +There are two ways to set sample size in a profile: samples_per_update and +min_true_samples. Samples_per_update takes an integer as the exact amount that +will be sampled. Min_true_samples will set the minimum amount of samples that +are not null. For example: + +.. code-block:: python + + from dataprofiler import Profiler + + sample_array = [1.0, NULL, 2.0] + profile = dp.Profiler(sample_array, samples_per_update=2) + +The first two samples (1.0 and NULL) are used for the statistical analysis. + +In contrast, if we also set min_true_samples to 2 then the Data Reader will +continue to read until the minimum true samples were found for the given column. +For example: + +.. code-block:: python + + from dataprofiler import Profiler + + sample_array = [1.0, NULL, 2.0] + profile = dp.Profiler(sample_array, samples_per_update=2, min_true_samples=2) + +This will use all samples in the statistical analysis until the number of "true" +(non-NULL) values are reached. Both min_true_samples and +samples_per_update conditions must be met. In this case, the profile will grab +the first two samples (1.0 and NULL) to satisfy the samples_per_update, and then +it will grab the first two VALID samples (1.0 and 2.0) to satisfy the +min_true_samples. + +Profile a Pandas DataFrame +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. code-block:: python + + import pandas as pd + import dataprofiler as dp + import json + + my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]]) + profile = dp.Profiler(my_dataframe) + + # print the report using json to prettify. + report = profile.report(report_options={"output_format": "pretty"}) + print(json.dumps(report, indent=4)) + + # read a specified column, in this case it is labeled 0: + print(json.dumps(report["data stats"][0], indent=4)) + + +Specifying a Filetype or Delimiter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Example of specifying a CSV data type, with a `,` delimiter. +In addition, it utilizes only the first 10,000 rows. + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler + from dataprofiler.data_readers.csv_data import CSVData + + # Load a CSV file, with "," as the delimiter + data = CSVData("your_file.csv", options={"delimiter": ","}) + + # Split the data, such that only the first 10,000 rows are used + data = data.data[0:10000] + + # Read in profile and print results + profile = Profiler(data) + print(json.dumps(profile.report(report_options={"output_format": "pretty"}), indent=4)) + +Setting Profiler Seed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Example of specifying a seed for reproducibility. + +.. code-block:: python + + import dataprofiler as dp + + # Set seed to non-negative integer value or None + dp.set_seed(0) + + +Profile Statistic Descriptions +============================== + +Structured Profile +~~~~~~~~~~~~~~~~~~ + +**global_stats**: + +* samples_used - number of input data samples used to generate this profile +* column_count - the number of columns contained in the input dataset +* row_count - the number of rows contained in the input dataset +* row_has_null_ratio - the proportion of rows that contain at least one null value to the total number of rows +* row_is_null_ratio - the proportion of rows that are fully comprised of null values (null rows) to the total number of rows +* unique_row_ratio - the proportion of distinct rows in the input dataset to the total number of rows +* duplicate_row_count - the number of rows that occur more than once in the input dataset +* file_type - the format of the file containing the input dataset (ex: .csv) +* encoding - the encoding of the file containing the input dataset (ex: UTF-8) +* correlation_matrix - matrix of shape `column_count` x `column_count` containing the correlation coefficients between each column in the dataset +* chi2_matrix - matrix of shape `column_count` x `column_count` containing the chi-square statistics between each column in the dataset +* profile_schema - a description of the format of the input dataset labeling each column and its index in the dataset + * string - the label of the column in question and its index in the profile schema +* times - the duration of time it took to generate the global statistics for this dataset in milliseconds + +**data_stats**: + +* column_name - the label/title of this column in the input dataset +* data_type - the primitive python data type that is contained within this column +* data_label - the label/entity of the data in this column as determined by the Labeler component +* categorical - 'true' if this column contains categorical data +* order - the way in which the data in this column is ordered, if any, otherwise “random” +* samples - a small subset of data entries from this column +* statistics - statistical information on the column + * sample_size - number of input data samples used to generate this profile + * null_count - the number of null entries in the sample + * null_types - a list of the different null types present within this sample + * null_types_index - a dict containing each null type and a respective list of the indicies that it is present within this sample + * data_type_representation - the percentage of samples used identifying as each data_type + * min - minimum value in the sample + * max - maximum value in the sample + * mode - mode of the entries in the sample + * median - median of the entries in the sample + * median_absolute_deviation - the median absolute deviation of the entries in the sample + * sum - the total of all sampled values from the column + * mean - the average of all entries in the sample + * variance - the variance of all entries in the sample + * stddev - the standard deviation of all entries in the sample + * skewness - the statistical skewness of all entries in the sample + * kurtosis - the statistical kurtosis of all entries in the sample + * num_zeros - the number of entries in this sample that have the value 0 + * num_negatives - the number of entries in this sample that have a value less than 0 + * histogram - contains histogram relevant information + * bin_counts - the number of entries within each bin + * bin_edges - the thresholds of each bin + * quantiles - the value at each percentile in the order they are listed based on the entries in the sample + * vocab - a list of the characters used within the entries in this sample + * avg_predictions - average of the data label prediction confidences across all data points sampled + * categories - a list of each distinct category within the sample if `categorial` = 'true' + * unique_count - the number of distinct entries in the sample + * unique_ratio - the proportion of the number of distinct entries in the sample to the total number of entries in the sample + * categorical_count - number of entries sampled for each category if `categorical` = 'true' + * gini_impurity - measure of how often a randomly chosen element from the set would be incorrectly labeled if it was randomly labeled according to the distribution of labels in the subset + * unalikeability - a value denoting how frequently entries differ from one another within the sample + * precision - a dict of statistics with respect to the number of digits in a number for each sample + * times - the duration of time it took to generate this sample's statistics in milliseconds + * format - list of possible datetime formats +* null_replication_metrics - statistics of data partitioned based on whether column value is null (index 1 of lists referenced by dict keys) or not (index 0) + * class_prior - a list containing probability of a column value being null and not null + * class_sum - a list containing sum of all other rows based on whether column value is null or not + * class_mean - a list containing mean of all other rows based on whether column value is null or not + +Unstructured Profile +~~~~~~~~~~~~~~~~~~~~ + +**global_stats**: + +* samples_used - number of input data samples used to generate this profile +* empty_line_count - the number of empty lines in the input data +* file_type - the file type of the input data (ex: .txt) +* encoding - file encoding of the input data file (ex: UTF-8) +* memory_size - size of the input data in MB +* times - duration of time it took to generate this profile in milliseconds + +**data_stats**: + +* data_label - labels and statistics on the labels of the input data + * entity_counts - the number of times a specific label or entity appears inside the input data + * word_level - the number of words counted within each label or entity + * true_char_level - the number of characters counted within each label or entity as determined by the model + * postprocess_char_level - the number of characters counted within each label or entity as determined by the postprocessor + * entity_percentages - the percentages of each label or entity within the input data + * word_level - the percentage of words in the input data that are contained within each label or entity + * true_char_level - the percentage of characters in the input data that are contained within each label or entity as determined by the model + * postprocess_char_level - the percentage of characters in the input data that are contained within each label or entity as determined by the postprocessor + * times - the duration of time it took for the data labeler to predict on the data +* statistics - statistics of the input data + * vocab - a list of each character in the input data + * vocab_count - the number of occurrences of each distinct character in the input data + * words - a list of each word in the input data + * word_count - the number of occurrences of each distinct word in the input data + * times - the duration of time it took to generate the vocab and words statistics in milliseconds + +Graph Profile +~~~~~~~~~~~~~~~~~~ + +* num_nodes - number of nodes in the graph +* num_edges - number of edges in the graph +* categorical_attributes - list of categorical edge attributes +* continuous_attributes - list of continuous edge attributes +* avg_node_degree - average degree of nodes in the graph +* global_max_component_size: size of the global max component + +**continuous_distribution**: + +* : name of N-th edge attribute in list of attributes + * name - name of distribution for attribute + * scale - negative log likelihood used to scale and compare distributions + * properties - list of statistical properties describing the distribution + * [shape (optional), loc, scale, mean, variance, skew, kurtosis] + +**categorical_distribution**: + +* : name of N-th edge attribute in list of attributes + * bin_counts: counts in each bin of the distribution histogram + * bin_edges: edges of each bin of the distribution histogram + +* times - duration of time it took to generate this profile in milliseconds + +Profile Options +=============== + +The data profiler accepts several options to toggle on and off +features. The 8 columns (int options, float options, datetime options, +text options, order options, category options, data labeler options) can be +enabled or disabled. By default, all options are toggled on. Below is an example +of how to alter these options. Options shared by structured and unstructured options +must be specified as structured or unstructured when setting (ie. datalabeler options). + + +.. code-block:: python + + import json + from dataprofiler import Data, Profiler, ProfilerOptions + + # Load and profile a CSV file + data = Data("your_file.csv") + profile_options = ProfilerOptions() + + #All of these are different examples of adjusting the profile options + + # Options can be toggled directly like this: + profile_options.structured_options.text.is_enabled = False + profile_options.structured_options.text.vocab.is_enabled = True + profile_options.structured_options.int.variance.is_enabled = True + profile_options.structured_options.data_labeler.data_labeler_dirpath = \ + "Wheres/My/Datalabeler" + profile_options.structured_options.data_labeler.is_enabled = False + + # A dictionary can be sent in to set the properties for all the options + profile_options.set({"structured_options.data_labeler.is_enabled": False, "min.is_enabled": False}) + + # Specific columns can be set/disabled/enabled in the same way + profile_options.structured_options.text.set({"max.is_enabled":True, + "variance.is_enabled": True}) + + # numeric stats can be turned off/on entirely + profile_options.set({"is_numeric_stats_enabled": False}) + profile_options.set({"int.is_numeric_stats_enabled": False}) + + profile = Profiler(data, options=profile_options) + + # Print the report using json to prettify. + report = profile.report(report_options={"output_format": "pretty"}) + print(json.dumps(report, indent=4)) + + +Below is an breakdown of all the options. + +* **ProfilerOptions** - The top-level options class that contains options for the Profiler class + + * **presets** - A pre-configured mapping of a string name to group of options: + + * **default is None** + + * **"complete"** + + .. code-block:: python + + options = ProfilerOptions(presets="complete") + + * **"data_types"** + + .. code-block:: python + + options = ProfilerOptions(presets="data_types") + + * **"numeric_stats_disabled"** + + .. code-block:: python + + options = ProfilerOptions(presets="numeric_stats_disabled") + + * **"lower_memory_sketching"** + + .. code-block:: python + + options = ProfilerOptions(presets="lower_memory_sketching") + + * **structured_options** - Options responsible for all structured data + + * **multiprocess** - Option to enable multiprocessing. If on, multiprocessing is toggled on if the dataset contains more than 750,000 rows or more than 20 columns. + Automatically selects the optimal number of pooling processes to utilize based on system constraints when toggled on. + + * is_enabled - (Boolean) Enables or disables multiprocessing + + * **sampling_ratio** - A percentage, as a decimal, ranging from greater than 0 to less than or equal to 1 indicating how much input data to sample. Default value set to 0.2. + + * **int** - Options for the integer columns + + * is_enabled - (Boolean) Enables or disables the integer operations + * min - Finds minimum value in a column + + * is_enabled - (Boolean) Enables or disables min + * max - Finds maximum value in a column + + * is_enabled - (Boolean) Enables or disables max + * mode - Finds mode(s) in a column + + * is_enabled - (Boolean) Enables or disables mode + * top_k_modes - (Int) Sets the number of modes to return if multiple exist. Default returns max 5 modes. + * median - Finds median value in a column + + * is_enabled - (Boolean) Enables or disables median + * sum - Finds sum of all values in a column + + * is_enabled - (Boolean) Enables or disables sum + + * variance - Finds variance of all values in a column + + * is_enabled - (Boolean) Enables or disables variance + * skewness - Finds skewness of all values in a column + + * is_enabled - (Boolean) Enables or disables skewness + * kurtosis - Finds kurtosis of all values in a column + + * is_enabled - (Boolean) Enables or disables kurtosis + * median_abs_deviation - Finds median absolute deviation of all values in a column + + * is_enabled - (Boolean) Enables or disables median absolute deviation + * num_zeros - Finds the count of zeros in a column + + * is_enabled - (Boolean) Enables or disables num_zeros + * num_negatives - Finds the count of negative numbers in a column + + * is_enabled - (Boolean) Enables or disables num_negatives + * bias_correction - Applies bias correction to variance, skewness, and kurtosis calculations + + * is_enabled - (Boolean) Enables or disables bias correction + * histogram_and_quantiles - Generates a histogram and quantiles + from the column values + + * bin_count_or_method - (String/List[String]) Designates preferred method for calculating histogram bins or the number of bins to use. + If left unspecified (None) the optimal method will be chosen by attempting all methods. + If multiple specified (list) the optimal method will be chosen by attempting the provided ones. + methods: 'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt' + Note: 'auto' is used to choose optimally between 'fd' and 'sturges' + * num_quantiles - (Int) Number of quantiles to bin the data. + Default value is set to 1,000 quantiles. + * is_enabled - (Boolean) Enables or disables histogram and quantiles + * **float** - Options for the float columns + + * is_enabled - (Boolean) Enables or disables the float operations + * precision - Finds the precision (significant figures) within the column + + * is_enabled - (Boolean) Enables or disables precision + * sample_ratio - (Float) The ratio of 0 to 1 how much data (identified as floats) to utilize as samples in determining precision + + * min - Finds minimum value in a column + + * is_enabled - (Boolean) Enables or disables min + * max - Finds maximum value in a column + + * is_enabled - (Boolean) Enables or disables max + * mode - Finds mode(s) in a column + + * is_enabled - (Boolean) Enables or disables mode + * top_k_modes - (Int) Sets the number of modes to return if multiple exist. Default returns max 5 modes. + * median - Finds median value in a column + + * is_enabled - (Boolean) Enables or disables median + * sum - Finds sum of all values in a column + + * is_enabled - (Boolean) Enables or disables sum + * variance - Finds variance of all values in a column + + * is_enabled - (Boolean) Enables or disables variance + * skewness - Finds skewness of all values in a column + + * is_enabled - (Boolean) Enables or disables skewness + * kurtosis - Finds kurtosis of all values in a column + + * is_enabled - (Boolean) Enables or disables kurtosis + * median_abs_deviation - Finds median absolute deviation of all values in a column + + * is_enabled - (Boolean) Enables or disables median absolute deviation + * is_numeric_stats_enabled - (Boolean) enable or disable all numeric stats + * num_zeros - Finds the count of zeros in a column + + * is_enabled - (Boolean) Enables or disables num_zeros + * num_negatives - Finds the count of negative numbers in a column + + * is_enabled - (Boolean) Enables or disables num_negatives + * bias_correction - Applies bias correction to variance, skewness, and kurtosis calculations + + * is_enabled - (Boolean) Enables or disables bias correction + * histogram_and_quantiles - Generates a histogram and quantiles + from the column values + + * bin_count_or_method - (String/List[String]) Designates preferred method for calculating histogram bins or the number of bins to use. + If left unspecified (None) the optimal method will be chosen by attempting all methods. + If multiple specified (list) the optimal method will be chosen by attempting the provided ones. + methods: 'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt' + Note: 'auto' is used to choose optimally between 'fd' and 'sturges' + * num_quantiles - (Int) Number of quantiles to bin the data. + Default value is set to 1,000 quantiles. + * is_enabled - (Boolean) Enables or disables histogram and quantiles + * **text** - Options for the text columns + + * is_enabled - (Boolean) Enables or disables the text operations + * vocab - Finds all the unique characters used in a column + + * is_enabled - (Boolean) Enables or disables vocab + * min - Finds minimum value in a column + + * is_enabled - (Boolean) Enables or disables min + * max - Finds maximum value in a column + + * is_enabled - (Boolean) Enables or disables max + * mode - Finds mode(s) in a column + + * is_enabled - (Boolean) Enables or disables mode + * top_k_modes - (Int) Sets the number of modes to return if multiple exist. Default returns max 5 modes. + * median - Finds median value in a column + + * is_enabled - (Boolean) Enables or disables median + * sum - Finds sum of all values in a column + + * is_enabled - (Boolean) Enables or disables sum + * variance - Finds variance of all values in a column + + * is_enabled - (Boolean) Enables or disables variance + * skewness - Finds skewness of all values in a column + + * is_enabled - (Boolean) Enables or disables skewness + * kurtosis - Finds kurtosis of all values in a column + + * is_enabled - (Boolean) Enables or disables kurtosis + * median_abs_deviation - Finds median absolute deviation of all values in a column + + * is_enabled - (Boolean) Enables or disables median absolute deviation + * bias_correction - Applies bias correction to variance, skewness, and kurtosis calculations + + * is_enabled - (Boolean) Enables or disables bias correction + * is_numeric_stats_enabled - (Boolean) enable or disable all numeric stats + * num_zeros - Finds the count of zeros in a column + + * is_enabled - (Boolean) Enables or disables num_zeros + * num_negatives - Finds the count of negative numbers in a column + + * is_enabled - (Boolean) Enables or disables num_negatives + * histogram_and_quantiles - Generates a histogram and quantiles + from the column values + + * bin_count_or_method - (String/List[String]) Designates preferred method for calculating histogram bins or the number of bins to use. + If left unspecified (None) the optimal method will be chosen by attempting all methods. + If multiple specified (list) the optimal method will be chosen by attempting the provided ones. + methods: 'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt' + Note: 'auto' is used to choose optimally between 'fd' and 'sturges' + * num_quantiles - (Int) Number of quantiles to bin the data. + Default value is set to 1,000 quantiles. + * is_enabled - (Boolean) Enables or disables histogram and quantiles + * **datetime** - Options for the datetime columns + + * is_enabled - (Boolean) Enables or disables the datetime operations + * **order** - Options for the order columns + + * is_enabled - (Boolean) Enables or disables the order operations + * **category** - Options for the category columns + + * is_enabled - (Boolean) Enables or disables the category operations + * top_k_categories - (int) Number of categories to be displayed when reporting + * max_sample_size_to_check_stop_condition - (int) The maximum sample size before categorical stop conditions are checked + * stop_condition_unique_value_ratio - (float) The highest ratio of unique values to dataset size that is to be considered a categorical type + * cms - (Boolean) Enables or Disables the use of count min sketch / heavy hitters for approximate frequency counts + * cms_confidence - (float) Defines the number of hashes used in CMS, default 0.95 + * cms_relative_error - (float) Defines the number of buckets used in CMS, default 0.01 + * cms_max_num_heavy_hitters - (int) The value used to define the threshold for minimum frequency required by a category to be counted + * **data_labeler** - Options for the data labeler columns + + * is_enabled - (Boolean) Enables or disables the data labeler operations + * data_labeler_dirpath - (String) Directory path to data labeler + * data_labeler_object - (BaseDataLabeler) Datalabeler to replace + the default labeler + * max_sample_size - (Int) The max number of samples for the data + labeler + * **correlation** - Option set for correlation profiling + * is_enabled - (Boolean) Enables or disables performing correlation profiling + * columns - Columns considered to calculate correlation + * **row_statistics** - (Boolean) Option to enable/disable row statistics calculations + + * unique_count - (UniqueCountOptions) Option to enable/disable unique row count calculations + + * is_enabled - (Bool) Enables or disables options for unique row count + * hashing_method - (String) Property to specify row hashing method ("full" | "hll") + * hll - (HyperLogLogOptions) Options for alternative method of estimating unique row count (activated when `hll` is the selected hashing_method) + + * seed - (Int) Used to set HLL hashing function seed + * register_count - (Int) Number of registers is equal to 2^register_count + + * null_count - (Boolean) Option to enable/disable functionalities for row_has_null_ratio and row_is_null_ratio + * **chi2_homogeneity** - Options for the chi-squared test matrix + + * is_enabled - (Boolean) Enables or disables performing chi-squared tests for homogeneity between the categorical columns of the dataset. + * **null_replication_metrics** - Options for calculating null replication metrics + + * is_enabled - (Boolean) Enables or disables calculation of null replication metrics + * **unstructured_options** - Options responsible for all unstructured data + + * **text** - Options for the text profile + + * is_case_sensitive - (Boolean) Specify whether the profile is case sensitive + * stop_words - (List of Strings) List of stop words to be removed when profiling + * top_k_chars - (Int) Number of top characters to be retrieved when profiling + * top_k_words - (Int) Number of top words to be retrieved when profiling + * vocab - Options for vocab count + + * is_enabled - (Boolean) Enables or disables the vocab stats + * words - Options for word count + + * is_enabled - (Boolean) Enables or disables the word stats + * **data_labeler** - Options for the data labeler + + * is_enabled - (Boolean) Enables or disables the data labeler operations + * data_labeler_dirpath - (String) Directory path to data labeler + * data_labeler_object - (BaseDataLabeler) Datalabeler to replace + the default labeler + * max_sample_size - (Int) The max number of samples for the data + labeler + + + +Statistical Dependency on Order of Updates +========================================== + +Some profile features/statistics are dependent on the order in which the profiler +is updated with new data. + +Order Profile +~~~~~~~~~~~~~ + +The order profiler utilizes the last value in the previous data batch to ensure +the subsequent dataset is above/below/equal to that value when predicting +non-random order. + +For instance, a dataset to be predicted as ascending would require the following +batch data update to be ascending and its first value `>=` than that of the +previous batch of data. + +Ex. of ascending: + +.. code-block:: python + + batch_1 = [0, 1, 2] + batch_2 = [3, 4, 5] + +Ex. of random: + +.. code-block:: python + + batch_1 = [0, 1, 2] + batch_2 = [1, 2, 3] # notice how the first value is less than the last value in the previous batch + + +Reporting Structure +=================== + +For every profile, we can provide a report and customize it with a couple optional parameters: + +* output_format (string) + + * This will allow the user to decide the output format for report. + + * Options are one of [pretty, compact, serializable, flat]: + + * Pretty: floats are rounded to four decimal places, and lists are shortened. + * Compact: Similar to pretty, but removes detailed statistics such as runtimes, label probabilities, index locations of null types, etc. + * Serializable: Output is json serializable and not prettified + * Flat: Nested output is returned as a flattened dictionary +* num_quantile_groups (int) + + * You can sample your data as you like! With a minimum of one and a maximum of 1000, you can decide the number of quantile groups! + +.. code-block:: python + + report = profile.report(report_options={"output_format": "pretty"}) + report = profile.report(report_options={"output_format": "compact"}) + report = profile.report(report_options={"output_format": "serializable"}) + report = profile.report(report_options={"output_format": "flat"}) diff --git a/docs/0.10.3/html/_sources/profiler_example.nblink.txt b/docs/0.10.3/html/_sources/profiler_example.nblink.txt new file mode 100644 index 000000000..8b1612784 --- /dev/null +++ b/docs/0.10.3/html/_sources/profiler_example.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/structured_profilers.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/regex_labeler_from_scratch.nblink.txt b/docs/0.10.3/html/_sources/regex_labeler_from_scratch.nblink.txt new file mode 100644 index 000000000..a0d3fe033 --- /dev/null +++ b/docs/0.10.3/html/_sources/regex_labeler_from_scratch.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/regex_labeler_from_scratch/DataLabeler_from_scratch.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_sources/unstructured_profiler_example.nblink.txt b/docs/0.10.3/html/_sources/unstructured_profiler_example.nblink.txt new file mode 100644 index 000000000..1589c41d4 --- /dev/null +++ b/docs/0.10.3/html/_sources/unstructured_profiler_example.nblink.txt @@ -0,0 +1,3 @@ +{ + "path": "../../feature_branch/examples/unstructured_profilers.ipynb" +} \ No newline at end of file diff --git a/docs/0.10.3/html/_static/DataProfilerLogoLightTheme.png b/docs/0.10.3/html/_static/DataProfilerLogoLightTheme.png new file mode 100644 index 0000000000000000000000000000000000000000..35e59c3497b6cd5ef9248b9e075b3af25a7779e8 GIT binary patch literal 118089 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 I($M#R0n&7#*8l(j literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/basic.css b/docs/0.10.3/html/_static/basic.css new file mode 100644 index 000000000..912859b55 --- /dev/null +++ b/docs/0.10.3/html/_static/basic.css @@ -0,0 +1,904 @@ +/* + * basic.css + * ~~~~~~~~~ + * + * Sphinx stylesheet -- basic theme. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.clearer { + clear: both; +} + +div.section::after { + display: block; + content: ''; + clear: left; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 10px; + list-style: none; +} + +div.related li { + display: inline; +} + +div.related li.right { + float: right; + margin-right: 5px; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; + word-wrap: break-word; + overflow-wrap : break-word; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +div.sphinxsidebar input { + border: 1px solid #98dbcc; + font-family: sans-serif; + font-size: 1em; +} + +div.sphinxsidebar #searchbox form.search { + overflow: hidden; +} + +div.sphinxsidebar #searchbox input[type="text"] { + float: left; + width: 80%; + padding: 0.25em; + box-sizing: border-box; +} + +div.sphinxsidebar #searchbox input[type="submit"] { + float: left; + width: 20%; + border-left: none; + padding: 0.25em; + box-sizing: border-box; +} + + +img { + border: 0; + max-width: 100%; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li p.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + width: 90%; + margin-left: auto; + margin-right: auto; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + font-style: italic; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable { + width: 100%; +} + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable ul { + margin-top: 0; + margin-bottom: 0; + list-style-type: none; +} + +table.indextable > tbody > tr > td > ul { + padding-left: 0em; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +div.modindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +div.genindex-jumpbox { + border-top: 1px solid #ddd; + border-bottom: 1px solid #ddd; + margin: 1em 0 1em 0; + padding: 0.4em; +} + +/* -- domain module index --------------------------------------------------- */ + +table.modindextable td { + padding: 2px; + border-collapse: collapse; +} + +/* -- general body styles --------------------------------------------------- */ + +div.body { + min-width: 450px; + max-width: 800px; +} + +div.body p, div.body dd, div.body li, div.body blockquote { + -moz-hyphens: auto; + -ms-hyphens: auto; + -webkit-hyphens: auto; + hyphens: auto; +} + +a.headerlink { + visibility: hidden; +} + +a.brackets:before, +span.brackets > a:before{ + content: "["; +} + +a.brackets:after, +span.brackets > a:after { + content: "]"; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink, +caption:hover > a.headerlink, +p.caption:hover > a.headerlink, +div.code-block-caption:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +img.align-left, figure.align-left, .figure.align-left, object.align-left { + clear: left; + float: left; + margin-right: 1em; +} + +img.align-right, figure.align-right, .figure.align-right, object.align-right { + clear: right; + float: right; + margin-left: 1em; +} + +img.align-center, figure.align-center, .figure.align-center, object.align-center { + display: block; + margin-left: auto; + margin-right: auto; +} + +img.align-default, figure.align-default, .figure.align-default { + display: block; + margin-left: auto; + margin-right: auto; +} + +.align-left { + text-align: left; +} + +.align-center { + text-align: center; +} + +.align-default { + text-align: center; +} + +.align-right { + text-align: right; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar, +aside.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px; + background-color: #ffe; + width: 40%; + float: right; + clear: right; + overflow-x: auto; +} + +p.sidebar-title { + font-weight: bold; +} + +div.admonition, div.topic, blockquote { + clear: left; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- content of sidebars/topics/admonitions -------------------------------- */ + +div.sidebar > :last-child, +aside.sidebar > :last-child, +div.topic > :last-child, +div.admonition > :last-child { + margin-bottom: 0; +} + +div.sidebar::after, +aside.sidebar::after, +div.topic::after, +div.admonition::after, +blockquote::after { + display: block; + content: ''; + clear: both; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + margin-top: 10px; + margin-bottom: 10px; + border: 0; + border-collapse: collapse; +} + +table.align-center { + margin-left: auto; + margin-right: auto; +} + +table.align-default { + margin-left: auto; + margin-right: auto; +} + +table caption span.caption-number { + font-style: italic; +} + +table caption span.caption-text { +} + +table.docutils td, table.docutils th { + padding: 1px 8px 1px 5px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +table.citation { + border-left: solid 1px gray; + margin-left: 1px; +} + +table.citation td { + border-bottom: none; +} + +th > :first-child, +td > :first-child { + margin-top: 0px; +} + +th > :last-child, +td > :last-child { + margin-bottom: 0px; +} + +/* -- figures --------------------------------------------------------------- */ + +div.figure, figure { + margin: 0.5em; + padding: 0.5em; +} + +div.figure p.caption, figcaption { + padding: 0.3em; +} + +div.figure p.caption span.caption-number, +figcaption span.caption-number { + font-style: italic; +} + +div.figure p.caption span.caption-text, +figcaption span.caption-text { +} + +/* -- field list styles ----------------------------------------------------- */ + +table.field-list td, table.field-list th { + border: 0 !important; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.field-name { + -moz-hyphens: manual; + -ms-hyphens: manual; + -webkit-hyphens: manual; + hyphens: manual; +} + +/* -- hlist styles ---------------------------------------------------------- */ + +table.hlist { + margin: 1em 0; +} + +table.hlist td { + vertical-align: top; +} + +/* -- object description styles --------------------------------------------- */ + +.sig { + font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace; +} + +.sig-name, code.descname { + background-color: transparent; + font-weight: bold; +} + +.sig-name { + font-size: 1.1em; +} + +code.descname { + font-size: 1.2em; +} + +.sig-prename, code.descclassname { + background-color: transparent; +} + +.optional { + font-size: 1.3em; +} + +.sig-paren { + font-size: larger; +} + +.sig-param.n { + font-style: italic; +} + +/* C++ specific styling */ + +.sig-inline.c-texpr, +.sig-inline.cpp-texpr { + font-family: unset; +} + +.sig.c .k, .sig.c .kt, +.sig.cpp .k, .sig.cpp .kt { + color: #0033B3; +} + +.sig.c .m, +.sig.cpp .m { + color: #1750EB; +} + +.sig.c .s, .sig.c .sc, +.sig.cpp .s, .sig.cpp .sc { + color: #067D17; +} + + +/* -- other body styles ----------------------------------------------------- */ + +ol.arabic { + list-style: decimal; +} + +ol.loweralpha { + list-style: lower-alpha; +} + +ol.upperalpha { + list-style: upper-alpha; +} + +ol.lowerroman { + list-style: lower-roman; +} + +ol.upperroman { + list-style: upper-roman; +} + +:not(li) > ol > li:first-child > :first-child, +:not(li) > ul > li:first-child > :first-child { + margin-top: 0px; +} + +:not(li) > ol > li:last-child > :last-child, +:not(li) > ul > li:last-child > :last-child { + margin-bottom: 0px; +} + +ol.simple ol p, +ol.simple ul p, +ul.simple ol p, +ul.simple ul p { + margin-top: 0; +} + +ol.simple > li:not(:first-child) > p, +ul.simple > li:not(:first-child) > p { + margin-top: 0; +} + +ol.simple p, +ul.simple p { + margin-bottom: 0; +} + +dl.footnote > dt, +dl.citation > dt { + float: left; + margin-right: 0.5em; +} + +dl.footnote > dd, +dl.citation > dd { + margin-bottom: 0em; +} + +dl.footnote > dd:after, +dl.citation > dd:after { + content: ""; + clear: both; +} + +dl.field-list { + display: grid; + grid-template-columns: fit-content(30%) auto; +} + +dl.field-list > dt { + font-weight: bold; + word-break: break-word; + padding-left: 0.5em; + padding-right: 5px; +} + +dl.field-list > dt:after { + content: ":"; +} + +dl.field-list > dd { + padding-left: 0.5em; + margin-top: 0em; + margin-left: 0em; + margin-bottom: 0em; +} + +dl { + margin-bottom: 15px; +} + +dd > :first-child { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dl > dd:last-child, +dl > dd:last-child > :last-child { + margin-bottom: 0; +} + +dt:target, span.highlighted { + background-color: #fbe54e; +} + +rect.highlighted { + fill: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa; +} + +.line-block { + display: block; + margin-top: 1em; + margin-bottom: 1em; +} + +.line-block .line-block { + margin-top: 0; + margin-bottom: 0; + margin-left: 1.5em; +} + +.guilabel, .menuselection { + font-family: sans-serif; +} + +.accelerator { + text-decoration: underline; +} + +.classifier { + font-style: oblique; +} + +.classifier:before { + font-style: normal; + margin: 0.5em; + content: ":"; +} + +abbr, acronym { + border-bottom: dotted 1px; + cursor: help; +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; + overflow-y: hidden; /* fixes display issues on Chrome browsers */ +} + +pre, div[class*="highlight-"] { + clear: both; +} + +span.pre { + -moz-hyphens: none; + -ms-hyphens: none; + -webkit-hyphens: none; + hyphens: none; +} + +div[class*="highlight-"] { + margin: 1em 0; +} + +td.linenos pre { + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + display: block; +} + +table.highlighttable tbody { + display: block; +} + +table.highlighttable tr { + display: flex; +} + +table.highlighttable td { + margin: 0; + padding: 0; +} + +table.highlighttable td.linenos { + padding-right: 0.5em; +} + +table.highlighttable td.code { + flex: 1; + overflow: hidden; +} + +.highlight .hll { + display: block; +} + +div.highlight pre, +table.highlighttable pre { + margin: 0; +} + +div.code-block-caption + div { + margin-top: 0; +} + +div.code-block-caption { + margin-top: 1em; + padding: 2px 5px; + font-size: small; +} + +div.code-block-caption code { + background-color: transparent; +} + +table.highlighttable td.linenos, +span.linenos, +div.highlight span.gp { /* gp: Generic.Prompt */ + user-select: none; + -webkit-user-select: text; /* Safari fallback only */ + -webkit-user-select: none; /* Chrome/Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+ */ +} + +div.code-block-caption span.caption-number { + padding: 0.1em 0.3em; + font-style: italic; +} + +div.code-block-caption span.caption-text { +} + +div.literal-block-wrapper { + margin: 1em 0; +} + +code.xref, a code { + background-color: transparent; + font-weight: bold; +} + +h1 code, h2 code, h3 code, h4 code, h5 code, h6 code { + background-color: transparent; +} + +.viewcode-link { + float: right; +} + +.viewcode-back { + float: right; + font-family: sans-serif; +} + +div.viewcode-block:target { + margin: -1px -10px; + padding: 0 10px; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.body div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +span.eqno a.headerlink { + position: absolute; + z-index: 1; +} + +div.math:hover a.headerlink { + visibility: visible; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0 !important; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} \ No newline at end of file diff --git a/docs/0.10.3/html/_static/custom.css b/docs/0.10.3/html/_static/custom.css new file mode 100644 index 000000000..8a7c7cb54 --- /dev/null +++ b/docs/0.10.3/html/_static/custom.css @@ -0,0 +1,50 @@ +/* + the ipython3 code blocks coming from the notebooks + were not getting the dark theme styles applied, so + manually overriding them +*/ +@media (prefers-color-scheme: dark) { + .highlight-ipython3 { + border: none !important; + border-radius: 2px !important; + background: #202020 !important; + color: #d0d0d0 !important; + } +} + +@media (prefers-color-scheme: dark) { + tr:nth-child(odd) { + background-color: #202020 !important; + } +} + +@media (prefers-color-scheme: dark) { + .dataframe { + color: white !important; + } +} + +.hidden { + display: none; +} + +.version { + text-align: right; + font-size: 24px; + margin-top: -47px; + margin-right: 3px; +} + +.sidebar-brand { + margin-bottom: -10px; + margin-top: 10px; +} + +/* unknown warning was showing, manually hiding */ +#Visualizing-Logged-Dataframes .admonition.warning { + display: none; +} + +div.output_area.stderr { + display: none; +} diff --git a/docs/0.10.3/html/_static/doctools.js b/docs/0.10.3/html/_static/doctools.js new file mode 100644 index 000000000..8cbf1b161 --- /dev/null +++ b/docs/0.10.3/html/_static/doctools.js @@ -0,0 +1,323 @@ +/* + * doctools.js + * ~~~~~~~~~~~ + * + * Sphinx JavaScript utilities for all documentation. + * + * :copyright: Copyright 2007-2021 by the Sphinx team, see AUTHORS. + * :license: BSD, see LICENSE for details. + * + */ + +/** + * select a different prefix for underscore + */ +$u = _.noConflict(); + +/** + * make the code below compatible with browsers without + * an installed firebug like debugger +if (!window.console || !console.firebug) { + var names = ["log", "debug", "info", "warn", "error", "assert", "dir", + "dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace", + "profile", "profileEnd"]; + window.console = {}; + for (var i = 0; i < names.length; ++i) + window.console[names[i]] = function() {}; +} + */ + +/** + * small helper function to urldecode strings + * + * See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL + */ +jQuery.urldecode = function(x) { + if (!x) { + return x + } + return decodeURIComponent(x.replace(/\+/g, ' ')); +}; + +/** + * small helper function to urlencode strings + */ +jQuery.urlencode = encodeURIComponent; + +/** + * This function returns the parsed url parameters of the + * current request. Multiple values per key are supported, + * it will always return arrays of strings for the value parts. + */ +jQuery.getQueryParameters = function(s) { + if (typeof s === 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = jQuery.urldecode(tmp[0]); + var value = jQuery.urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +}; + +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node, addItems) { + if (node.nodeType === 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && + !jQuery(node.parentNode).hasClass(className) && + !jQuery(node.parentNode).hasClass("nohighlight")) { + var span; + var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg"); + if (isInSVG) { + span = document.createElementNS("http://www.w3.org/2000/svg", "tspan"); + } else { + span = document.createElement("span"); + span.className = className; + } + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + if (isInSVG) { + var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); + var bbox = node.parentElement.getBBox(); + rect.x.baseVal.value = bbox.x; + rect.y.baseVal.value = bbox.y; + rect.width.baseVal.value = bbox.width; + rect.height.baseVal.value = bbox.height; + rect.setAttribute('class', className); + addItems.push({ + "parent": node.parentNode, + "target": rect}); + } + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this, addItems); + }); + } + } + var addItems = []; + var result = this.each(function() { + highlight(this, addItems); + }); + for (var i = 0; i < addItems.length; ++i) { + jQuery(addItems[i].parent).before(addItems[i].target); + } + return result; +}; + +/* + * backward compatibility for jQuery.browser + * This will be supported until firefox bug is fixed. + */ +if (!jQuery.browser) { + jQuery.uaMatch = function(ua) { + ua = ua.toLowerCase(); + + var match = /(chrome)[ \/]([\w.]+)/.exec(ua) || + /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || + []; + + return { + browser: match[ 1 ] || "", + version: match[ 2 ] || "0" + }; + }; + jQuery.browser = {}; + jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true; +} + +/** + * Small JavaScript module for the documentation. + */ +var Documentation = { + + init : function() { + this.fixFirefoxAnchorBug(); + this.highlightSearchWords(); + this.initIndexTable(); + if (DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS) { + this.initOnKeyListeners(); + } + }, + + /** + * i18n support + */ + TRANSLATIONS : {}, + PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; }, + LOCALE : 'unknown', + + // gettext and ngettext don't access this so that the functions + // can safely bound to a different name (_ = Documentation.gettext) + gettext : function(string) { + var translated = Documentation.TRANSLATIONS[string]; + if (typeof translated === 'undefined') + return string; + return (typeof translated === 'string') ? translated : translated[0]; + }, + + ngettext : function(singular, plural, n) { + var translated = Documentation.TRANSLATIONS[singular]; + if (typeof translated === 'undefined') + return (n == 1) ? singular : plural; + return translated[Documentation.PLURALEXPR(n)]; + }, + + addTranslations : function(catalog) { + for (var key in catalog.messages) + this.TRANSLATIONS[key] = catalog.messages[key]; + this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')'); + this.LOCALE = catalog.locale; + }, + + /** + * add context elements like header anchor links + */ + addContextElements : function() { + $('div[id] > :header:first').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this headline')). + appendTo(this); + }); + $('dt[id]').each(function() { + $('\u00B6'). + attr('href', '#' + this.id). + attr('title', _('Permalink to this definition')). + appendTo(this); + }); + }, + + /** + * workaround a firefox stupidity + * see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075 + */ + fixFirefoxAnchorBug : function() { + if (document.location.hash && $.browser.mozilla) + window.setTimeout(function() { + document.location.href += ''; + }, 10); + }, + + /** + * highlight the search words provided in the url in the text + */ + highlightSearchWords : function() { + var params = $.getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + $('

    ') + .appendTo($('#searchbox')); + } + }, + + /** + * init the domain index toggle buttons + */ + initIndexTable : function() { + var togglers = $('img.toggler').click(function() { + var src = $(this).attr('src'); + var idnum = $(this).attr('id').substr(7); + $('tr.cg-' + idnum).toggle(); + if (src.substr(-9) === 'minus.png') + $(this).attr('src', src.substr(0, src.length-9) + 'plus.png'); + else + $(this).attr('src', src.substr(0, src.length-8) + 'minus.png'); + }).css('display', ''); + if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) { + togglers.click(); + } + }, + + /** + * helper function to hide the search marks again + */ + hideSearchWords : function() { + $('#searchbox .highlight-link').fadeOut(300); + $('span.highlighted').removeClass('highlighted'); + }, + + /** + * make the url absolute + */ + makeURL : function(relativeURL) { + return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL; + }, + + /** + * get the current relative url + */ + getCurrentURL : function() { + var path = document.location.pathname; + var parts = path.split(/\//); + $.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() { + if (this === '..') + parts.pop(); + }); + var url = parts.join('/'); + return path.substring(url.lastIndexOf('/') + 1, path.length - 1); + }, + + initOnKeyListeners: function() { + $(document).keydown(function(event) { + var activeElementType = document.activeElement.tagName; + // don't navigate when in search box, textarea, dropdown or button + if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT' + && activeElementType !== 'BUTTON' && !event.altKey && !event.ctrlKey && !event.metaKey + && !event.shiftKey) { + switch (event.keyCode) { + case 37: // left + var prevHref = $('link[rel="prev"]').prop('href'); + if (prevHref) { + window.location.href = prevHref; + return false; + } + break; + case 39: // right + var nextHref = $('link[rel="next"]').prop('href'); + if (nextHref) { + window.location.href = nextHref; + return false; + } + break; + } + } + }); + } +}; + +// quick alias for translations +_ = Documentation.gettext; + +$(document).ready(function() { + Documentation.init(); +}); diff --git a/docs/0.10.3/html/_static/documentation_options.js b/docs/0.10.3/html/_static/documentation_options.js new file mode 100644 index 000000000..2fa8c97fe --- /dev/null +++ b/docs/0.10.3/html/_static/documentation_options.js @@ -0,0 +1,12 @@ +var DOCUMENTATION_OPTIONS = { + URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), + VERSION: '', + LANGUAGE: 'None', + COLLAPSE_INDEX: false, + BUILDER: 'html', + FILE_SUFFIX: '.html', + LINK_SUFFIX: '.html', + HAS_SOURCE: true, + SOURCELINK_SUFFIX: '.txt', + NAVIGATION_WITH_KEYS: false +}; \ No newline at end of file diff --git a/docs/0.10.3/html/_static/file.png b/docs/0.10.3/html/_static/file.png new file mode 100644 index 0000000000000000000000000000000000000000..a858a410e4faa62ce324d814e4b816fff83a6fb3 GIT binary patch literal 286 zcmV+(0pb3MP)s`hMrGg#P~ix$^RISR_I47Y|r1 z_CyJOe}D1){SET-^Amu_i71Lt6eYfZjRyw@I6OQAIXXHDfiX^GbOlHe=Ae4>0m)d(f|Me07*qoM6N<$f}vM^LjV8( literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/images/DataProfilerDarkLogoLong.png b/docs/0.10.3/html/_static/images/DataProfilerDarkLogoLong.png new file mode 100644 index 0000000000000000000000000000000000000000..a339e0f6acee7c29d438847b4cfc48957c6a3296 GIT binary patch literal 20019 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 I($M#R0n&7#*8l(j literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/images/DataProfilerLogoLightThemeLong.png b/docs/0.10.3/html/_static/images/DataProfilerLogoLightThemeLong.png new file mode 100644 index 0000000000000000000000000000000000000000..ca86fe167d7197e3bb8ccadce91aaae376f27de8 GIT binary patch literal 177437 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%0A=ay5NB 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 r6akxWxj%7T)KQ8?CD{ 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�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 z zl0uYc^9ZKzMG~>%r_K7uq1dwA*On+$N%;&!OBqvGKr7S`o^7A|D%yTF{oBpf)VJ}m zanGDw%q-^;wiFy*EX|%9#^$8;*8N$zQo6|d70Yv}UX#MPrg-E!Q-}j|$*%hyA^P^b zBH(p|feq)A_fCQwYqkT*$_J`?oOcz@=HBWVy_u3Q-g^GaNWRYM%UKGmk7DzTha+Qu zF2az+g{01A!dFxK%apr3)xDVF0LM`F)6)p-2eKmSL1ISN+as=9yl5-;Fi;(JO6aqV ziGmZt2cxo7N7=-*pL`ZNn2~8_$e+wrQXLJ}=suZOj*W0yzEN)TQq^Pof+76|4>)ds zyVhI{R?{FSH1n2w+cz5lhP`oDj=*wt)0;O|PdwDlM@Gn>UEN$QbP816t89x!INa%u zT|)Wl{@6%vWkPTDy7VS9QlV+$Id)E57YjZ;w(S08S!jFmx=Mdn^vr<_!j*WTI(nI3 z^opayz}qO-WYXltb*&HGFAOG{HAu%xN-t)QW!AMte|F1hNft=(J$vqXD_>8>2RCjcM0Ere?55Z#U)+D5qS@waHn@aCL8zZPe|)4 z`ekx0Pf6)Xu-o17XZAW*YVYsc5MgA6>RZJ!&K35tjXxEBDPlzbiRke5?CUNq)laP!* zmvsqyt1*~N`}QU2VTyn9n9xO$x5TL}spi z>N*t3)%y3RqKU1}502F8rA~D=ZP&-o4o>DOC{MO9Rm6KZ>&HP_Ji2ceAligs>*8+V z+uQs@Zv_m5Uq9X!epB<$t_1$6AEw~&n@*mUl&O!pC3&K&?oLx}2fjYS+GKed_kKTD zGdOten!HXjrZ1YXqyC?>JiG7)8CVTB%wNH@|9Ln6x>cBy7CK3hq6N(imA?F+*TMWf z=1%%x?xc_4XDHXdzoMANz<<_Pga#;-5y?o#uzz0U-+cq{rvz#2G*qH=`Udj9FY?ci zwr=JC8*8(MVv@o?Mbv*@OB1`75z}(W*6~sN=SBYMMX(DmVpj7-4%WWhe>Ermen~r$ zaLz!xkwWRbe_rI@CrHfu-^0BBJ@S+_-T&vZMWVrFi)>CX>izx0{`JZU{+RcF4DUz( tXJz{9vNKe`WoP(2B;oyk-@gpj6`?WRXP(C7*iR7fOH1vpYB|8_{2$1jOnm?V literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/images/histogram_example_0.png b/docs/0.10.3/html/_static/images/histogram_example_0.png new file mode 100644 index 0000000000000000000000000000000000000000..9b8301363678d43fb36f795ec59f86c18897b992 GIT binary patch literal 14056 zcmeHu1yohr+V%ntq9Sq(z#vpGkTU326hx%EEpk)RY|<734oG-tq+4>+pr{B)m&7K8 zO-Oft@ATYr?>+ZkZ;bo>WBmUZ{~6*)p>4S z?sJ?+OzrJ$?1XuEEdP80x3#Sa56ArhEf{2n%@u7s45Ph){wGV6NHD`Nes$SP7u1}? zCWx-~YD3YRGbh_+mG(v-WjJzx^Ai*KrGW=JQPRh36NU6uVl`AQb>jW$uW;<8Q~BCr z%Eh3odhA#{m#w7sJ!VPMT|fDr=q68++;i!!(lzpRub+);35Br4))YipvHc( zol`LrEtcLzK`R1i!dDp=JkJ-zptF{b_D)g}Zm})@3S+uUw+o zwyObs#86GJ>sclpksfmClwACR`O3=5XoAE>k{#!%Q&&{uuPG}l`}wd)On$J(8bo*O z*ug!d=#O9gmgKRqItsUCaP?u{J@O|SxcUgO!i~i)y1jb`&WT%mIU}ngE9=dmLMB<0 z$tg!iN4Jxjdd_iwj_rQQ933Mgqo+@wCZG2(`ZiZDv1HGNnJQ!#{hMC|fwcr;CaMkj4~+4%*Fgu%gs2Zdc`WAXDN(GpuL^}_i1L<9E)b?ZtB zFXNTg439Xc9v7Lxk1v{kJ#R9mx4cp*v6&g{AI;SlEZLB(UuZ9zZBpMhJ5=Ma_)VLJ zQBY}axK>p~#h(yECYk-5QAkCXU}ZV&xVa*2r-Z>)*;Qfk{g)KkPZ)M)7v;~ed(P~a zge_9>+wtEHTuUkW+1}DJO?+$JF4wx(KwMnB$A_YC+b!*&x=4wPx^R)2c7nr38F!@s zrrF$mOD~1XE7EgQNMeDqFB#TNdb)lQUgRTR|MIq|r1Yf&?dH_i*A^#^yXOubJ$lqY zfuc`ZRb4#}riqmK8lBZ=9^(2OmrFTa-E|DkU_3&`o5)xCuzH3@QdNKIY`TN{83bmv z(*OLvfA~OuIFKKQm2PdWp?50mG|9=r!jh(6w3ytrfB$~dPrn?^>aZAVjCl;(lemWx z>o%Vm_;5(jChFqFi~INPJyt|acj|Q~G+Oq!&B-rJ5_Kmgp#U$U~ZLwUD8`LP}naZHtdaVXB;f3JL`xW2FWY9ha7=T{#=tdC#6$g$O~ zUMyi?;O0bUu3Yb0&yxMt#u9F8b7P^7hm*4fRxh7X_5O*DY?-R6s;deLZKdvOqG62K zp<#F(Lv14SGmRm9xPY**?!GXDP~+_xPC`e-m;3I+(}nR{b$^MiOiE5xF*Qv*&A|a% zwW<3H*7+((RNDUA7iFH}>3i|lepMmm!5&O3EYulqOSAJKx{$)3zIdUoprG(_GIH>+ zSBlx>op&6OWSpl@tK7W#x<(5Y8SLibJycjoY<#>lhi1B(gG25&N7oWN!BR3)n)Q;I zsG*^ur%#^P9DMfViITc{Ah$trVqagMaF-zCZXw3qB)qzME1!gwnOTxTq`3RU-J_!^ zq;lhI7ZK@{kC8X#9z1-Q1k0D%v%AD~soIJ#4*RfhWjHj~xc1NjY|fqn8m8XrnwrDK zo<7zB+pJ4UG3)88WW~(d+S(z2$qv?rIy%WcC2J!CA9%W7Ri6zd!2c6SLkuU z{BZHjWv|LDzsc5=;Hy`!s%dK{0XTCUKYkhQnKwTfaQyYC&!0b6yL|a!jTZcXl`tl@ zc2XAh?o~xar*utqb#`Il!YW^v)p;}h;^l_}ELCb()IK{5@oRVV9Gh@8@xJLf|3KJb zYGOh#ZLjB}T2*yNwXWdW*3sq!u}xb0>(`?I0FKHY61Gotoa|0wFmzMqDO}3BFE!`4VpgxdVb*(tFI}541Vy1K#s=--swFVMyUGq zso~YxTPI6B~(jP=FX#4dFpQF&*Rga-t zUqAVEW}EnmFf(I1pHnhQJ4YrcDJdO3e)MI@m>H}jC>_I0#XYDG{9^?D1K|8MwEq7C ze^+h(G9{*$G&F)H^9OgMqSN2skI?SzeX7I669NL7P=vVUl$3sXyqBW9RT(3T+5;O^ z-P}AGh*5lTv8emXQ1Br!d`@yo%3&fm8`~uy9CbrqGH)?o-GynArY11VhP5mIPD~Bn z$}0U`MTNSaUh0&`QW1?6X>c&+)2B~CK2%uy!}DI44GkdWaakr2M+^I&htv%A<7tG` z!ooUBy`E)@Q@vB(&R7E*lugsuot-)e(kmX*Y64;(4r@=*^g$+zRTj=7+@%CfJ&jJq!cwtEHa#PZ)s^Ug^g7> zRk}7-LNv~`odQbs)cNW=*lOV@+|- zva+(+Wa~xeo=+CfDJ+aMN+Ci;%~Kq8tI}t*QHEuq(*r9ni^0exS?PHUIAsqB*~Zo^ z<1$L(BiFy4^p9<7QdwE`*zgVk7Gplvl60DfNAvM+CSLmyC19?}z_cQs(qJ!u)=RQ- z))bC~-MdE~yZ|r6y#L)pu7K@Wh%e7w;03=^ega+jw{I37-oHNuGSW{!bN zC)S_@&n_sa)!5h=a`x6EZvDcq>4I>fsTaUbvU*BDL`3@M&(|h;N_6jUqXF#kSBMbR zo?3?qFl|fKuKxVFsy|9rZ(|dFMZoEQxGC)uY+;MeP zm2#2eM2k<3v)qxkxVmkXyDin`tOTopwhS}78z{JryeEC>l^okAZx_=%2zL4>;3B+@;e<}g36v!5DVldqV~LtzJXrnRNz)Ujjl zj6{zeyU60Xey5~seMCm02`b7$_>`MWkkP2&)@m?QARP@`V&)ph@G1@CR zdday@oodLg7f+Gc7**^naV7NN$GOrB%SwA#WXq0maL7eRN7o$}7Vf<74YaY-$2gK~ z7d7?E$jC^zJ-v?{r%&%ccu;$aAJNYWT8VG#+OcF5+Yo<111_|vDi-J|Z#{kfd{Dud;a{qJ@EfiAZIEb(KNrl{7g+>KMf{bE_qFA6j9`Rl+?V=)7OzG zn(nU%5p&J^_~I~$^B#;~dJt&Yz7y9Pl2j9TP3jmyyK(UIYaAA^viCUqHB=&CbG})z zrm|8-QDP$p2@-{HVYBZ1JF64cp5wsNV1x&{JEPd*;^Nr3xYByMN>`*tH#aw7VW=4! z#}`47z%cpu)?^faS&aXy`tyHL%Ko1kN|F`ez`l~nDG@MjCoQd}t!>tBW>M$XiGM(q z?;@&<5cGXpnrc}@vxsfnegE}R1gHE=@*QQ;@FY^t!V1l|Hy20cn@Q|bfA`^ zykU*Q&SG`V9TCjZDNsA*%-fLkv@oc z?prP{E?Hd@3w4AJi=8`m+|kCOj?Wx~dAn$YW^3*_0!!-ofm(%ZLh{bOZc zo=B1l=B}=;_Ggn1<(Frbe%`RYGRNomO$%;b1;DJy|F~Rn9t$=-B}lOyd!beAoCyVz z57-juYoTEE6b&I#Ku{3e>F0uoUw(-~uvz7Q9El)}41+W%Qv9nQ_F&U&b@0@`Bl$hy zTgc^rGNpTD55~*#ZzXO96&_+;AU41AEKE1D#uLz3}ch}+L4v+YGv&Un2GCb z8E(}1d3hQ@$aJ!9dq3LElnh#NBq-w_>({S`TUzjkTJY=I4I&FK zCp@qX3!#`Y3@W*%fy-r2sC*86^{`ASF&huMlrTy^dgJ`V-+h_vgZsA*Y{b@eF*56;7-ZtZR4|WJUj0FsT z{xxQH*7n24kLFNg>UbW(IRasdXT7ZVX7)E&pc0oZw0e-pvamlZUMR9$0VJe5k&T;hU+fZ%zhd#18^5u~j zU-J)7>3TlHg1~5PN-5n&n~rm7XI+{qS&G=Un=#SL3k&w9rste?Mg=-QG8^-lZVEj0bG+`nSB&%v^ZB%%+E4*kHgLi) zouF*YU}e3R4pkvg!#M!o$Z`~BKnI^>W88ZAZ+do=t<+lE_rIg`rGz_^1X^l>d9Dw# z%!!o4X_lYVsjq{3dhgynQ9pPg7;~Q+^)i*j^4%JmAfu$z)N2S&zjb7bG4Fz-Tou}w zl$4ad)%3!GdWJ#C{O9xart>3>%(TBxWJbwi2+Vmo&FIEbZ#yE_U=;zuH>(Zd1ASy= z;{jS5+$D9BVi?@d&yVZXek`PJE0p5HhY!LweO_!yhGiayM4jJMN|BYncnuT{C~gz0 zuc!(s=G+S*05dQ&!p32DbL{~O`dKy>A?l(+E501HbLUR`8ZN>Wf3)_LW2DW7ssjPa zUJ}lcd$m6Y|Mb?!=LN$PfQ8|eDp-D_U>W85GsE?Zr25EqKqUv*W8p$}(x4u|?F;l+ zsWHT#XT@@aGcz**aht@Jx?{lWZs@uL@_%kuAF#CrDA`G%e(DaxMJd4LOMfEAmz)p;A4_4|yz3ke%76I--e7(e0 zx67dSzLUJSKJFsAFA)uPP+^vD-`uFM2Ts4uy8hEACEyQsLLTe+RLx{({NNencuHcY zJh#?Rp|Q8mVH<_=Hr88K23l}3*9&Xt3=9Z31qA{;}yLA+23)79$$!|)5(gFBC(5$8;Cf5Gi`DN|2Dwa z*Vq5$OClXYt?$D2PvqygpQ5dgA6N)}B>FM3GKh{{mXl9l3cXI4I+7Iwi+cL( zS>UTz%M0PFtEbPNRfdW|W3>cOcuG`M58^1Zra|zG)z#Gtev^Z>++GQaks46izVmR_ zKk;yW7PslUC_X8ft>%#T2un@neE8^*aPY{;i185M>6yUFGD^42br-Sq=?eT%pyqyh z`nInV=gyr2_jgnef{UJe>~LG1+*`vv7qqlqt*@`EDJ%D%Gf-BJ27gF+PGVzTl}QY* z22{Y#r?sukgYILmAr&oi3!!XdLbwaO*ba-l;g2wbXAH9Iv2EM7nU6F?SJ&4&p|ejz z!9?cmdQXWf4vd%6?Cf{Ad$%^1_`vl9V3=;>hJr$kTRbQ!3(m6U)vHej1_pQ`S3}Gb zQibm%@~_MnNGxIjXp1a75lpLuBhr~436=(gPWEFh?6tq1mq8}{ix;f`uHlBeK)eQK z@JI;5O0;1G?;;>JCx;hAZL2HFF=D!gVRv$%q$T}cvn~AkF**6K6IG0N02Q?SJA*9+ zb|x#!%chWjXcFV2q9mmr?eeQNR`q2T0}HroK!~hQ2Q1X6J^x;=((+E0ENXPUgbBl} zZbOA?1Zz4(R02o`;xr&^j?22Q&NouAxJ7}J1n(dz?k0ITA3TuPVTdf*&z@~G;$&x+ z1*6>B=I~#noq3Y8y|Hi_U7njgpP%IMo zIwq#%)%JXTSmkYS_Nh(3YY#7da28QWQTt1Dz>ez4C28s8*RS6hrM`ZB5ghJ?h>e$Q zp|vMMYlpqzc6WL|Rj#xuDQ2ROFDH0G`3D9HY*7CrsNvg$t`e}&#=g62z-*!*o`OXP zhWR-j@YMnE1Ls@22;kw{) z0~bbC1&=S>M$4QkWH)@pAGBqdk&=I*(^NW?8x9cqh=ahpKqfvn8AactcStkuff^TJ zq)pRf(3|0g;!D@XZ)R^%kqG$+`^x^*@VB1V`WE8&!@Rfru10@hK0k2+t8F53~ z-}j$8n&6@(@Xov6rOzJ}>ngA?U|t~L6@WsgIBkw+l%;R2 zW^AcIQjTAmOoN_-WRQj+116t<_vIzcTZ9>ux@iMfyL#=~`l^DvI{t8 zS!;~5(u3;;`PO!UFpUDeJ2p${!(lk`rfUMqQc>@Q0wiF~fT-Zmws%7U1VI28qye!% zv?%>g$cMy&>wF5FRsZ?*xq4h(n2=89&4)K{-VBSRD~4FpVXju7h;=UvcBl`Ms2lHo z3Kw>`YB&5@8SJK;w{GR$8I&e5NL`ha8ya6*sQUQf8N)aP|MP@bEZJXQ>J_zL6g&^<%VuKAm3f@}& zVPU<;u6@m;zCaa+;G-+feywm@%l06DOpBnLYLOZ3k=dQ25qx zsCBZ_R1Zk=CNDAyWZyYmh6sKDI&IP*(AWDBXCDtY)Y3`>-DX}Lz>b1#p!$JfVX5HN ze^1b9pq0nc4{8TWQ5?q9&hrX-i6GNycfo=42=Ka;+!J9Ah-nJ)K`^fsAR&;xfd9v^%n1wH&w}?od zRgpE^(6_4YUE{EWXmGOf>$0&AM@9yiBc#ZaA(KEu{GDm|A6NR`(KwIloBwU_vI?I| zY%UMBfrK9;o;Y%(96@l67JwfeGjmVh;B8}L9e*wOFWn48y=ksdT4fgdS$ zoRzg=Xe$})G30ExkL&jO`_{MC$AjSt{U17D(Q970az#$MgyGOdU6lK56H|?okBrv;6iw0 z`9tOTLu-w`1%anLTnzlqa*WcBFMcB9c8_>=84WcJjb+=d+`Pfilew+!Olz(9oDc5) zqE63oi@}oQKZx0&3(csM4azH@APZJ}7n*zWs=2Jm68=4$0guz{{gXW*5}u`~+b)np z6C|EK@`XhPFt08fH;M-Of;dd!)tL(k3gJy*LUs_5qywN@cIPYa*|X>O(APcd?2r2~ zoZcq|g8(o#HV!9fcb;xu)I4V$*aFqr(cycQ7;k;!~1FcmeO zo%3PigqMkRyh0s)z~%u3f7!O{KokTA&POcg^y@c4M76ni+y?_NAb$mN?^KA6g?a9o z6S@{Ai>CMs<#FyFx-sJ$B40v8m%8ns$TmXlDq)K2K*=M^)^g=)8=*7~8XRd3oRI`h zJ?ofij9Ll7HEb<$b)uxA8t>}e%p0x^ZBOl8TYQwVv1X|qgq-Tc#8YsT10-~$+pKq& zU5+=o7Nn#X?r&ok5h;?L^JNrz4OPLsB~clK5Bk^zWV1HM%X5XbxTiZrW(a~Gi0ZhU zv$Hexar=xkT>=>6>c}`UFo-B!pOr%)HYhO~E7czXip!amg@TBUz|z8d>tzyUl|D>! zN&~~=ow+Fyz}A2?;b6(E_AHeqtWA{}t}RVvIC}8Jab`$kps{ zF;@-LULh&z)#JXTzcI+Nh0>{3a8;~ja6zOARQRwqS6y8^JZ60H3EgLqxadL)QVuAw)IF@y zTJR3$9Ak}L2E0$EPPvgpdVKmFVccA1m#=$*Gg;RAsM@4x#lFT}s$Ht}ECUcqgRl^F z|JwKfywm~1Xxmz^-^yRe?0SE&90zgz)|V z$^xtJs0)RKUoe47tX{suP__`z*Q#VehW$_f5f)Oq16So ziWP@_cK3m`2%ii7c*#V*_ikf z6NDv|oRy_gwzV-82r(t_$P`$L%-7sD7AJ`u(Ao*s;V4wtHfWP+Az1g~NqK=J0-yO9 zE{jhKHLOkbq`_q4MV|hap+OD`>EOcGmx|`l`La61xBj>S{IR!Ew!S-(fbDD&|c=4V%7)(H?lsq@a4NG2q z>x_$!HwX5$+IOF}nCSy+NMRYk_mG7)oQf=BV5ZujMR239tQuhmknfPhsibITXn=Q= zXGQG1zT<&YPGH%6C{FD;X3YV?!R^VVXB_xos=#w=h7J%8S(FXHEGC47g=y$xz0QL) zC7Y|`s5F9~Oj_UN3D2gx;NkMj&zel;k9LFQ>^DQHM>L1yVTZax!>_EITyvqrcn;8o zl!#XI5f`85&n>E+SUGU5t;s{e2_I#Xg7<+Akk%L(T10|@yrP)cz-{IO%=SYx+jY2E zX;tWn0bOAZ{kXGBOTl0O!_y>7toPHxUp2w_Bd{6-CnhEeZ#B0hD6&A0AfDaNRTPRl zyt*J}x9JNAJ0V?oWBmD5G#G)_GIpUHl{|`!UC%k8gYwT|IgLkKVj5tfvYJ`|;TEsA zkv1r-W*8*LWzN`Ps%Im)D`%Lrf?r$;{f(aYXv{ITCxGVN{WzwlOJ{Db>rlZUpG!=^ z+GJ5Kuy=R|g2Avv#pWBNU|c_FnL+moiDi4irTS>8$H+5AHw#b9FuUN8#)VSSw6q14 zV@u=U;X}WtzKn{C3>Xm-EoB4!V3SAabfH*zAAIq657zZIE-g zj>ESBG@t{9?&qJcPY{dR4;R_Ur<0DF9aHG z(7JgOtxpXojH&2*3?e$&v9YmQ5DH{MFNq10knMZWiiFfRZ_ePLCieI^%BL?*ErHHA zA==h(wRKsSS-L||h@_-7ykTOY^UP~qR4Sc^_MYt31JLKJSslB4{^t89!d(EGI`H+0 zHcJB0xC9`bxt_?_URV#=Q1JpZ2Xz4v&k_a;{RN{?6Utni-Wfh#T~zn4nd86temiN? zaOUG-Yb_Kw&>c8nib{)4nMaAqeZz$Dj$UvQb)o+w8>m{^lPBB9OV=i|0b?dsrrSsT zWSBD%5ObV4(||%Z2Z%RBY9ftt)6gEN#$|DtQd2f$agL+dJ`G%8U0{l1#3DlO?W(=j zGUj=Jow&{%GY#-4Q=_7ejOTS(Wk=x0*lYT2oJBhM3OdVr0R`HCRG`nUG0xUTjqMK8 zeHRF%>C99O#~qeHt9YOJMSl0*P*dPP{IURuEXmL_&GkcZkgE z@WC?5UFF+RL6;XGew{dg*+`)<=prz~VkR=o>HxGsM%6C2mu<#@4-H;Dh|O!Lr7RFf z^qk|m4k0yy`K^`6tt9A=Ndk3>CxttO5h8&U(2C9fg48+iq=j!CswgK-aN2?C{Dkgj zh9t424T}^y03QRkT;|exBMIPcX|oAI-$Dh;rV@+$ydTgpakNi`?S`MTnJs?nScUIb zM8h;_Qtf7JfCLG}-%0vpUi2RztM7acUsyok44tURTY$}zf_f3*?JU%7RVjMB26=VW zKf--cd!wJ$vjOU=J;Ykc;QB&$riPwgSZqe!5pqf0w;+=(KZZN?u)_nA3W-+ju&7^$ zgoNNpw2XocE4>0l`P+RuKKm2JA^D;5tG_%!sZf%~d<5>jp$XmaO~c3aJnPX<^)OtMl+#vhs;jUU2`wV2e_%yYl3LctBn5bs!qT zs|fJ-e+?T62O;8j9)AP`-1Ze~Y5CN%cTga2ay5Fxkrrm(nj@zxO}pm|Nrk literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/images/histogram_example_1.png b/docs/0.10.3/html/_static/images/histogram_example_1.png new file mode 100644 index 0000000000000000000000000000000000000000..062dfdbb9829f3032b4c1afd55fefc61a08b5d56 GIT binary patch literal 11387 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 G+kXRhHtTNy literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/images/missing_value_matrix_example_0.png b/docs/0.10.3/html/_static/images/missing_value_matrix_example_0.png new file mode 100644 index 0000000000000000000000000000000000000000..21799cddfe73821d7ed15fe29b805df8f2e1879a GIT binary patch literal 37730 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 literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/_static/jquery-3.5.1.js b/docs/0.10.3/html/_static/jquery-3.5.1.js new file mode 100644 index 000000000..50937333b --- /dev/null +++ b/docs/0.10.3/html/_static/jquery-3.5.1.js @@ -0,0 +1,10872 @@ +/*! + * jQuery JavaScript Library v3.5.1 + * https://jquery.com/ + * + * Includes Sizzle.js + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://jquery.org/license + * + * Date: 2020-05-04T22:49Z + */ +( function( global, factory ) { + + "use strict"; + + if ( typeof module === "object" && typeof module.exports === "object" ) { + + // For CommonJS and CommonJS-like environments where a proper `window` + // is present, execute the factory and get jQuery. + // For environments that do not have a `window` with a `document` + // (such as Node.js), expose a factory as module.exports. + // This accentuates the need for the creation of a real `window`. + // e.g. var jQuery = require("jquery")(window); + // See ticket #14549 for more info. + module.exports = global.document ? + factory( global, true ) : + function( w ) { + if ( !w.document ) { + throw new Error( "jQuery requires a window with a document" ); + } + return factory( w ); + }; + } else { + factory( global ); + } + +// Pass this if window is not defined yet +} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) { + +// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1 +// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode +// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common +// enough that all such attempts are guarded in a try block. +"use strict"; + +var arr = []; + +var getProto = Object.getPrototypeOf; + +var slice = arr.slice; + +var flat = arr.flat ? function( array ) { + return arr.flat.call( array ); +} : function( array ) { + return arr.concat.apply( [], array ); +}; + + +var push = arr.push; + +var indexOf = arr.indexOf; + +var class2type = {}; + +var toString = class2type.toString; + +var hasOwn = class2type.hasOwnProperty; + +var fnToString = hasOwn.toString; + +var ObjectFunctionString = fnToString.call( Object ); + +var support = {}; + +var isFunction = function isFunction( obj ) { + + // Support: Chrome <=57, Firefox <=52 + // In some browsers, typeof returns "function" for HTML elements + // (i.e., `typeof document.createElement( "object" ) === "function"`). + // We don't want to classify *any* DOM node as a function. + return typeof obj === "function" && typeof obj.nodeType !== "number"; + }; + + +var isWindow = function isWindow( obj ) { + return obj != null && obj === obj.window; + }; + + +var document = window.document; + + + + var preservedScriptAttributes = { + type: true, + src: true, + nonce: true, + noModule: true + }; + + function DOMEval( code, node, doc ) { + doc = doc || document; + + var i, val, + script = doc.createElement( "script" ); + + script.text = code; + if ( node ) { + for ( i in preservedScriptAttributes ) { + + // Support: Firefox 64+, Edge 18+ + // Some browsers don't support the "nonce" property on scripts. + // On the other hand, just using `getAttribute` is not enough as + // the `nonce` attribute is reset to an empty string whenever it + // becomes browsing-context connected. + // See https://github.com/whatwg/html/issues/2369 + // See https://html.spec.whatwg.org/#nonce-attributes + // The `node.getAttribute` check was added for the sake of + // `jQuery.globalEval` so that it can fake a nonce-containing node + // via an object. + val = node[ i ] || node.getAttribute && node.getAttribute( i ); + if ( val ) { + script.setAttribute( i, val ); + } + } + } + doc.head.appendChild( script ).parentNode.removeChild( script ); + } + + +function toType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + // Support: Android <=2.3 only (functionish RegExp) + return typeof obj === "object" || typeof obj === "function" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} +/* global Symbol */ +// Defining this global in .eslintrc.json would create a danger of using the global +// unguarded in another place, it seems safer to define global only for this module + + + +var + version = "3.5.1", + + // Define a local copy of jQuery + jQuery = function( selector, context ) { + + // The jQuery object is actually just the init constructor 'enhanced' + // Need init if jQuery is called (just allow error to be thrown if not included) + return new jQuery.fn.init( selector, context ); + }; + +jQuery.fn = jQuery.prototype = { + + // The current version of jQuery being used + jquery: version, + + constructor: jQuery, + + // The default length of a jQuery object is 0 + length: 0, + + toArray: function() { + return slice.call( this ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + + // Return all the elements in a clean array + if ( num == null ) { + return slice.call( this ); + } + + // Return just the one element from the set + return num < 0 ? this[ num + this.length ] : this[ num ]; + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems ) { + + // Build a new jQuery matched element set + var ret = jQuery.merge( this.constructor(), elems ); + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + each: function( callback ) { + return jQuery.each( this, callback ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map( this, function( elem, i ) { + return callback.call( elem, i, elem ); + } ) ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ) ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + even: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return ( i + 1 ) % 2; + } ) ); + }, + + odd: function() { + return this.pushStack( jQuery.grep( this, function( _elem, i ) { + return i % 2; + } ) ); + }, + + eq: function( i ) { + var len = this.length, + j = +i + ( i < 0 ? len : 0 ); + return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); + }, + + end: function() { + return this.prevObject || this.constructor(); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: arr.sort, + splice: arr.splice +}; + +jQuery.extend = jQuery.fn.extend = function() { + var options, name, src, copy, copyIsArray, clone, + target = arguments[ 0 ] || {}, + i = 1, + length = arguments.length, + deep = false; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + + // Skip the boolean and the target + target = arguments[ i ] || {}; + i++; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !isFunction( target ) ) { + target = {}; + } + + // Extend jQuery itself if only one argument is passed + if ( i === length ) { + target = this; + i--; + } + + for ( ; i < length; i++ ) { + + // Only deal with non-null/undefined values + if ( ( options = arguments[ i ] ) != null ) { + + // Extend the base object + for ( name in options ) { + copy = options[ name ]; + + // Prevent Object.prototype pollution + // Prevent never-ending loop + if ( name === "__proto__" || target === copy ) { + continue; + } + + // Recurse if we're merging plain objects or arrays + if ( deep && copy && ( jQuery.isPlainObject( copy ) || + ( copyIsArray = Array.isArray( copy ) ) ) ) { + src = target[ name ]; + + // Ensure proper type for the source value + if ( copyIsArray && !Array.isArray( src ) ) { + clone = []; + } else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) { + clone = {}; + } else { + clone = src; + } + copyIsArray = false; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend( { + + // Unique for each copy of jQuery on the page + expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), + + // Assume jQuery is ready without the ready module + isReady: true, + + error: function( msg ) { + throw new Error( msg ); + }, + + noop: function() {}, + + isPlainObject: function( obj ) { + var proto, Ctor; + + // Detect obvious negatives + // Use toString instead of jQuery.type to catch host objects + if ( !obj || toString.call( obj ) !== "[object Object]" ) { + return false; + } + + proto = getProto( obj ); + + // Objects with no prototype (e.g., `Object.create( null )`) are plain + if ( !proto ) { + return true; + } + + // Objects with prototype are plain iff they were constructed by a global Object function + Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor; + return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString; + }, + + isEmptyObject: function( obj ) { + var name; + + for ( name in obj ) { + return false; + } + return true; + }, + + // Evaluates a script in a provided context; falls back to the global one + // if not specified. + globalEval: function( code, options, doc ) { + DOMEval( code, { nonce: options && options.nonce }, doc ); + }, + + each: function( obj, callback ) { + var length, i = 0; + + if ( isArrayLike( obj ) ) { + length = obj.length; + for ( ; i < length; i++ ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } else { + for ( i in obj ) { + if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { + break; + } + } + } + + return obj; + }, + + // results is for internal usage only + makeArray: function( arr, results ) { + var ret = results || []; + + if ( arr != null ) { + if ( isArrayLike( Object( arr ) ) ) { + jQuery.merge( ret, + typeof arr === "string" ? + [ arr ] : arr + ); + } else { + push.call( ret, arr ); + } + } + + return ret; + }, + + inArray: function( elem, arr, i ) { + return arr == null ? -1 : indexOf.call( arr, elem, i ); + }, + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + merge: function( first, second ) { + var len = +second.length, + j = 0, + i = first.length; + + for ( ; j < len; j++ ) { + first[ i++ ] = second[ j ]; + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, invert ) { + var callbackInverse, + matches = [], + i = 0, + length = elems.length, + callbackExpect = !invert; + + // Go through the array, only saving the items + // that pass the validator function + for ( ; i < length; i++ ) { + callbackInverse = !callback( elems[ i ], i ); + if ( callbackInverse !== callbackExpect ) { + matches.push( elems[ i ] ); + } + } + + return matches; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var length, value, + i = 0, + ret = []; + + // Go through the array, translating each of the items to their new values + if ( isArrayLike( elems ) ) { + length = elems.length; + for ( ; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + + // Go through every key on the object, + } else { + for ( i in elems ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret.push( value ); + } + } + } + + // Flatten any nested arrays + return flat( ret ); + }, + + // A global GUID counter for objects + guid: 1, + + // jQuery.support is not used in Core but other projects attach their + // properties to it so it needs to exist. + support: support +} ); + +if ( typeof Symbol === "function" ) { + jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ]; +} + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), +function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); +} ); + +function isArrayLike( obj ) { + + // Support: real iOS 8.2 only (not reproducible in simulator) + // `in` check used to prevent JIT error (gh-2145) + // hasOwn isn't used here due to false negatives + // regarding Nodelist length in IE + var length = !!obj && "length" in obj && obj.length, + type = toType( obj ); + + if ( isFunction( obj ) || isWindow( obj ) ) { + return false; + } + + return type === "array" || length === 0 || + typeof length === "number" && length > 0 && ( length - 1 ) in obj; +} +var Sizzle = +/*! + * Sizzle CSS Selector Engine v2.3.5 + * https://sizzlejs.com/ + * + * Copyright JS Foundation and other contributors + * Released under the MIT license + * https://js.foundation/ + * + * Date: 2020-03-14 + */ +( function( window ) { +var i, + support, + Expr, + getText, + isXML, + tokenize, + compile, + select, + outermostContext, + sortInput, + hasDuplicate, + + // Local document vars + setDocument, + document, + docElem, + documentIsHTML, + rbuggyQSA, + rbuggyMatches, + matches, + contains, + + // Instance-specific data + expando = "sizzle" + 1 * new Date(), + preferredDoc = window.document, + dirruns = 0, + done = 0, + classCache = createCache(), + tokenCache = createCache(), + compilerCache = createCache(), + nonnativeSelectorCache = createCache(), + sortOrder = function( a, b ) { + if ( a === b ) { + hasDuplicate = true; + } + return 0; + }, + + // Instance methods + hasOwn = ( {} ).hasOwnProperty, + arr = [], + pop = arr.pop, + pushNative = arr.push, + push = arr.push, + slice = arr.slice, + + // Use a stripped-down indexOf as it's faster than native + // https://jsperf.com/thor-indexof-vs-for/5 + indexOf = function( list, elem ) { + var i = 0, + len = list.length; + for ( ; i < len; i++ ) { + if ( list[ i ] === elem ) { + return i; + } + } + return -1; + }, + + booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|" + + "ismap|loop|multiple|open|readonly|required|scoped", + + // Regular expressions + + // http://www.w3.org/TR/css3-selectors/#whitespace + whitespace = "[\\x20\\t\\r\\n\\f]", + + // https://www.w3.org/TR/css-syntax-3/#ident-token-diagram + identifier = "(?:\\\\[\\da-fA-F]{1,6}" + whitespace + + "?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+", + + // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors + attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + + + // Operator (capture 2) + "*([*^$|!~]?=)" + whitespace + + + // "Attribute values must be CSS identifiers [capture 5] + // or strings [capture 3 or capture 4]" + "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + + whitespace + "*\\]", + + pseudos = ":(" + identifier + ")(?:\\((" + + + // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: + // 1. quoted (capture 3; capture 4 or capture 5) + "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + + + // 2. simple (capture 6) + "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + + + // 3. anything else (capture 2) + ".*" + + ")\\)|)", + + // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter + rwhitespace = new RegExp( whitespace + "+", "g" ), + rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + + whitespace + "+$", "g" ), + + rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), + rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + + "*" ), + rdescend = new RegExp( whitespace + "|>" ), + + rpseudo = new RegExp( pseudos ), + ridentifier = new RegExp( "^" + identifier + "$" ), + + matchExpr = { + "ID": new RegExp( "^#(" + identifier + ")" ), + "CLASS": new RegExp( "^\\.(" + identifier + ")" ), + "TAG": new RegExp( "^(" + identifier + "|[*])" ), + "ATTR": new RegExp( "^" + attributes ), + "PSEUDO": new RegExp( "^" + pseudos ), + "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + + whitespace + "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + + whitespace + "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), + "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), + + // For use in libraries implementing .is() + // We use this for POS matching in `select` + "needsContext": new RegExp( "^" + whitespace + + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + whitespace + + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) + }, + + rhtml = /HTML$/i, + rinputs = /^(?:input|select|textarea|button)$/i, + rheader = /^h\d$/i, + + rnative = /^[^{]+\{\s*\[native \w/, + + // Easily-parseable/retrievable ID or TAG or CLASS selectors + rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + + rsibling = /[+~]/, + + // CSS escapes + // http://www.w3.org/TR/CSS21/syndata.html#escaped-characters + runescape = new RegExp( "\\\\[\\da-fA-F]{1,6}" + whitespace + "?|\\\\([^\\r\\n\\f])", "g" ), + funescape = function( escape, nonHex ) { + var high = "0x" + escape.slice( 1 ) - 0x10000; + + return nonHex ? + + // Strip the backslash prefix from a non-hex escape sequence + nonHex : + + // Replace a hexadecimal escape sequence with the encoded Unicode code point + // Support: IE <=11+ + // For values outside the Basic Multilingual Plane (BMP), manually construct a + // surrogate pair + high < 0 ? + String.fromCharCode( high + 0x10000 ) : + String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); + }, + + // CSS string/identifier serialization + // https://drafts.csswg.org/cssom/#common-serializing-idioms + rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g, + fcssescape = function( ch, asCodePoint ) { + if ( asCodePoint ) { + + // U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER + if ( ch === "\0" ) { + return "\uFFFD"; + } + + // Control characters and (dependent upon position) numbers get escaped as code points + return ch.slice( 0, -1 ) + "\\" + + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " "; + } + + // Other potentially-special ASCII characters get backslash-escaped + return "\\" + ch; + }, + + // Used for iframes + // See setDocument() + // Removing the function wrapper causes a "Permission Denied" + // error in IE + unloadHandler = function() { + setDocument(); + }, + + inDisabledFieldset = addCombinator( + function( elem ) { + return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset"; + }, + { dir: "parentNode", next: "legend" } + ); + +// Optimize for push.apply( _, NodeList ) +try { + push.apply( + ( arr = slice.call( preferredDoc.childNodes ) ), + preferredDoc.childNodes + ); + + // Support: Android<4.0 + // Detect silently failing push.apply + // eslint-disable-next-line no-unused-expressions + arr[ preferredDoc.childNodes.length ].nodeType; +} catch ( e ) { + push = { apply: arr.length ? + + // Leverage slice if possible + function( target, els ) { + pushNative.apply( target, slice.call( els ) ); + } : + + // Support: IE<9 + // Otherwise append directly + function( target, els ) { + var j = target.length, + i = 0; + + // Can't trust NodeList.length + while ( ( target[ j++ ] = els[ i++ ] ) ) {} + target.length = j - 1; + } + }; +} + +function Sizzle( selector, context, results, seed ) { + var m, i, elem, nid, match, groups, newSelector, + newContext = context && context.ownerDocument, + + // nodeType defaults to 9, since context defaults to document + nodeType = context ? context.nodeType : 9; + + results = results || []; + + // Return early from calls with invalid selector or context + if ( typeof selector !== "string" || !selector || + nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { + + return results; + } + + // Try to shortcut find operations (as opposed to filters) in HTML documents + if ( !seed ) { + setDocument( context ); + context = context || document; + + if ( documentIsHTML ) { + + // If the selector is sufficiently simple, try using a "get*By*" DOM method + // (excepting DocumentFragment context, where the methods don't exist) + if ( nodeType !== 11 && ( match = rquickExpr.exec( selector ) ) ) { + + // ID selector + if ( ( m = match[ 1 ] ) ) { + + // Document context + if ( nodeType === 9 ) { + if ( ( elem = context.getElementById( m ) ) ) { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( elem.id === m ) { + results.push( elem ); + return results; + } + } else { + return results; + } + + // Element context + } else { + + // Support: IE, Opera, Webkit + // TODO: identify versions + // getElementById can match elements by name instead of ID + if ( newContext && ( elem = newContext.getElementById( m ) ) && + contains( context, elem ) && + elem.id === m ) { + + results.push( elem ); + return results; + } + } + + // Type selector + } else if ( match[ 2 ] ) { + push.apply( results, context.getElementsByTagName( selector ) ); + return results; + + // Class selector + } else if ( ( m = match[ 3 ] ) && support.getElementsByClassName && + context.getElementsByClassName ) { + + push.apply( results, context.getElementsByClassName( m ) ); + return results; + } + } + + // Take advantage of querySelectorAll + if ( support.qsa && + !nonnativeSelectorCache[ selector + " " ] && + ( !rbuggyQSA || !rbuggyQSA.test( selector ) ) && + + // Support: IE 8 only + // Exclude object elements + ( nodeType !== 1 || context.nodeName.toLowerCase() !== "object" ) ) { + + newSelector = selector; + newContext = context; + + // qSA considers elements outside a scoping root when evaluating child or + // descendant combinators, which is not what we want. + // In such cases, we work around the behavior by prefixing every selector in the + // list with an ID selector referencing the scope context. + // The technique has to be used as well when a leading combinator is used + // as such selectors are not recognized by querySelectorAll. + // Thanks to Andrew Dupont for this technique. + if ( nodeType === 1 && + ( rdescend.test( selector ) || rcombinators.test( selector ) ) ) { + + // Expand context for sibling selectors + newContext = rsibling.test( selector ) && testContext( context.parentNode ) || + context; + + // We can use :scope instead of the ID hack if the browser + // supports it & if we're not changing the context. + if ( newContext !== context || !support.scope ) { + + // Capture the context ID, setting it first if necessary + if ( ( nid = context.getAttribute( "id" ) ) ) { + nid = nid.replace( rcssescape, fcssescape ); + } else { + context.setAttribute( "id", ( nid = expando ) ); + } + } + + // Prefix every selector in the list + groups = tokenize( selector ); + i = groups.length; + while ( i-- ) { + groups[ i ] = ( nid ? "#" + nid : ":scope" ) + " " + + toSelector( groups[ i ] ); + } + newSelector = groups.join( "," ); + } + + try { + push.apply( results, + newContext.querySelectorAll( newSelector ) + ); + return results; + } catch ( qsaError ) { + nonnativeSelectorCache( selector, true ); + } finally { + if ( nid === expando ) { + context.removeAttribute( "id" ); + } + } + } + } + } + + // All others + return select( selector.replace( rtrim, "$1" ), context, results, seed ); +} + +/** + * Create key-value caches of limited size + * @returns {function(string, object)} Returns the Object data after storing it on itself with + * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) + * deleting the oldest entry + */ +function createCache() { + var keys = []; + + function cache( key, value ) { + + // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) + if ( keys.push( key + " " ) > Expr.cacheLength ) { + + // Only keep the most recent entries + delete cache[ keys.shift() ]; + } + return ( cache[ key + " " ] = value ); + } + return cache; +} + +/** + * Mark a function for special use by Sizzle + * @param {Function} fn The function to mark + */ +function markFunction( fn ) { + fn[ expando ] = true; + return fn; +} + +/** + * Support testing using an element + * @param {Function} fn Passed the created element and returns a boolean result + */ +function assert( fn ) { + var el = document.createElement( "fieldset" ); + + try { + return !!fn( el ); + } catch ( e ) { + return false; + } finally { + + // Remove from its parent by default + if ( el.parentNode ) { + el.parentNode.removeChild( el ); + } + + // release memory in IE + el = null; + } +} + +/** + * Adds the same handler for all of the specified attrs + * @param {String} attrs Pipe-separated list of attributes + * @param {Function} handler The method that will be applied + */ +function addHandle( attrs, handler ) { + var arr = attrs.split( "|" ), + i = arr.length; + + while ( i-- ) { + Expr.attrHandle[ arr[ i ] ] = handler; + } +} + +/** + * Checks document order of two siblings + * @param {Element} a + * @param {Element} b + * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b + */ +function siblingCheck( a, b ) { + var cur = b && a, + diff = cur && a.nodeType === 1 && b.nodeType === 1 && + a.sourceIndex - b.sourceIndex; + + // Use IE sourceIndex if available on both nodes + if ( diff ) { + return diff; + } + + // Check if b follows a + if ( cur ) { + while ( ( cur = cur.nextSibling ) ) { + if ( cur === b ) { + return -1; + } + } + } + + return a ? 1 : -1; +} + +/** + * Returns a function to use in pseudos for input types + * @param {String} type + */ +function createInputPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for buttons + * @param {String} type + */ +function createButtonPseudo( type ) { + return function( elem ) { + var name = elem.nodeName.toLowerCase(); + return ( name === "input" || name === "button" ) && elem.type === type; + }; +} + +/** + * Returns a function to use in pseudos for :enabled/:disabled + * @param {Boolean} disabled true for :disabled; false for :enabled + */ +function createDisabledPseudo( disabled ) { + + // Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable + return function( elem ) { + + // Only certain elements can match :enabled or :disabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled + // https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled + if ( "form" in elem ) { + + // Check for inherited disabledness on relevant non-disabled elements: + // * listed form-associated elements in a disabled fieldset + // https://html.spec.whatwg.org/multipage/forms.html#category-listed + // https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled + // * option elements in a disabled optgroup + // https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled + // All such elements have a "form" property. + if ( elem.parentNode && elem.disabled === false ) { + + // Option elements defer to a parent optgroup if present + if ( "label" in elem ) { + if ( "label" in elem.parentNode ) { + return elem.parentNode.disabled === disabled; + } else { + return elem.disabled === disabled; + } + } + + // Support: IE 6 - 11 + // Use the isDisabled shortcut property to check for disabled fieldset ancestors + return elem.isDisabled === disabled || + + // Where there is no isDisabled, check manually + /* jshint -W018 */ + elem.isDisabled !== !disabled && + inDisabledFieldset( elem ) === disabled; + } + + return elem.disabled === disabled; + + // Try to winnow out elements that can't be disabled before trusting the disabled property. + // Some victims get caught in our net (label, legend, menu, track), but it shouldn't + // even exist on them, let alone have a boolean value. + } else if ( "label" in elem ) { + return elem.disabled === disabled; + } + + // Remaining elements are neither :enabled nor :disabled + return false; + }; +} + +/** + * Returns a function to use in pseudos for positionals + * @param {Function} fn + */ +function createPositionalPseudo( fn ) { + return markFunction( function( argument ) { + argument = +argument; + return markFunction( function( seed, matches ) { + var j, + matchIndexes = fn( [], seed.length, argument ), + i = matchIndexes.length; + + // Match elements found at the specified indexes + while ( i-- ) { + if ( seed[ ( j = matchIndexes[ i ] ) ] ) { + seed[ j ] = !( matches[ j ] = seed[ j ] ); + } + } + } ); + } ); +} + +/** + * Checks a node for validity as a Sizzle context + * @param {Element|Object=} context + * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value + */ +function testContext( context ) { + return context && typeof context.getElementsByTagName !== "undefined" && context; +} + +// Expose support vars for convenience +support = Sizzle.support = {}; + +/** + * Detects XML nodes + * @param {Element|Object} elem An element or a document + * @returns {Boolean} True iff elem is a non-HTML XML node + */ +isXML = Sizzle.isXML = function( elem ) { + var namespace = elem.namespaceURI, + docElem = ( elem.ownerDocument || elem ).documentElement; + + // Support: IE <=8 + // Assume HTML when documentElement doesn't yet exist, such as inside loading iframes + // https://bugs.jquery.com/ticket/4833 + return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" ); +}; + +/** + * Sets document-related variables once based on the current document + * @param {Element|Object} [doc] An element or document object to use to set the document + * @returns {Object} Returns the current document + */ +setDocument = Sizzle.setDocument = function( node ) { + var hasCompare, subWindow, + doc = node ? node.ownerDocument || node : preferredDoc; + + // Return early if doc is invalid or already selected + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( doc == document || doc.nodeType !== 9 || !doc.documentElement ) { + return document; + } + + // Update global variables + document = doc; + docElem = document.documentElement; + documentIsHTML = !isXML( document ); + + // Support: IE 9 - 11+, Edge 12 - 18+ + // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( preferredDoc != document && + ( subWindow = document.defaultView ) && subWindow.top !== subWindow ) { + + // Support: IE 11, Edge + if ( subWindow.addEventListener ) { + subWindow.addEventListener( "unload", unloadHandler, false ); + + // Support: IE 9 - 10 only + } else if ( subWindow.attachEvent ) { + subWindow.attachEvent( "onunload", unloadHandler ); + } + } + + // Support: IE 8 - 11+, Edge 12 - 18+, Chrome <=16 - 25 only, Firefox <=3.6 - 31 only, + // Safari 4 - 5 only, Opera <=11.6 - 12.x only + // IE/Edge & older browsers don't support the :scope pseudo-class. + // Support: Safari 6.0 only + // Safari 6.0 supports :scope but it's an alias of :root there. + support.scope = assert( function( el ) { + docElem.appendChild( el ).appendChild( document.createElement( "div" ) ); + return typeof el.querySelectorAll !== "undefined" && + !el.querySelectorAll( ":scope fieldset div" ).length; + } ); + + /* Attributes + ---------------------------------------------------------------------- */ + + // Support: IE<8 + // Verify that getAttribute really returns attributes and not properties + // (excepting IE8 booleans) + support.attributes = assert( function( el ) { + el.className = "i"; + return !el.getAttribute( "className" ); + } ); + + /* getElement(s)By* + ---------------------------------------------------------------------- */ + + // Check if getElementsByTagName("*") returns only elements + support.getElementsByTagName = assert( function( el ) { + el.appendChild( document.createComment( "" ) ); + return !el.getElementsByTagName( "*" ).length; + } ); + + // Support: IE<9 + support.getElementsByClassName = rnative.test( document.getElementsByClassName ); + + // Support: IE<10 + // Check if getElementById returns elements by name + // The broken getElementById methods don't pick up programmatically-set names, + // so use a roundabout getElementsByName test + support.getById = assert( function( el ) { + docElem.appendChild( el ).id = expando; + return !document.getElementsByName || !document.getElementsByName( expando ).length; + } ); + + // ID filter and find + if ( support.getById ) { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + return elem.getAttribute( "id" ) === attrId; + }; + }; + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var elem = context.getElementById( id ); + return elem ? [ elem ] : []; + } + }; + } else { + Expr.filter[ "ID" ] = function( id ) { + var attrId = id.replace( runescape, funescape ); + return function( elem ) { + var node = typeof elem.getAttributeNode !== "undefined" && + elem.getAttributeNode( "id" ); + return node && node.value === attrId; + }; + }; + + // Support: IE 6 - 7 only + // getElementById is not reliable as a find shortcut + Expr.find[ "ID" ] = function( id, context ) { + if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { + var node, i, elems, + elem = context.getElementById( id ); + + if ( elem ) { + + // Verify the id attribute + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + + // Fall back on getElementsByName + elems = context.getElementsByName( id ); + i = 0; + while ( ( elem = elems[ i++ ] ) ) { + node = elem.getAttributeNode( "id" ); + if ( node && node.value === id ) { + return [ elem ]; + } + } + } + + return []; + } + }; + } + + // Tag + Expr.find[ "TAG" ] = support.getElementsByTagName ? + function( tag, context ) { + if ( typeof context.getElementsByTagName !== "undefined" ) { + return context.getElementsByTagName( tag ); + + // DocumentFragment nodes don't have gEBTN + } else if ( support.qsa ) { + return context.querySelectorAll( tag ); + } + } : + + function( tag, context ) { + var elem, + tmp = [], + i = 0, + + // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too + results = context.getElementsByTagName( tag ); + + // Filter out possible comments + if ( tag === "*" ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem.nodeType === 1 ) { + tmp.push( elem ); + } + } + + return tmp; + } + return results; + }; + + // Class + Expr.find[ "CLASS" ] = support.getElementsByClassName && function( className, context ) { + if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { + return context.getElementsByClassName( className ); + } + }; + + /* QSA/matchesSelector + ---------------------------------------------------------------------- */ + + // QSA and matchesSelector support + + // matchesSelector(:active) reports false when true (IE9/Opera 11.5) + rbuggyMatches = []; + + // qSa(:focus) reports false when true (Chrome 21) + // We allow this because of a bug in IE8/9 that throws an error + // whenever `document.activeElement` is accessed on an iframe + // So, we allow :focus to pass through QSA all the time to avoid the IE error + // See https://bugs.jquery.com/ticket/13378 + rbuggyQSA = []; + + if ( ( support.qsa = rnative.test( document.querySelectorAll ) ) ) { + + // Build QSA regex + // Regex strategy adopted from Diego Perini + assert( function( el ) { + + var input; + + // Select is set to empty string on purpose + // This is to test IE's treatment of not explicitly + // setting a boolean content attribute, + // since its presence should be enough + // https://bugs.jquery.com/ticket/12359 + docElem.appendChild( el ).innerHTML = "" + + ""; + + // Support: IE8, Opera 11-12.16 + // Nothing should be selected when empty strings follow ^= or $= or *= + // The test attribute must be unknown in Opera but "safe" for WinRT + // https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section + if ( el.querySelectorAll( "[msallowcapture^='']" ).length ) { + rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); + } + + // Support: IE8 + // Boolean attributes and "value" are not treated correctly + if ( !el.querySelectorAll( "[selected]" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); + } + + // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ + if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) { + rbuggyQSA.push( "~=" ); + } + + // Support: IE 11+, Edge 15 - 18+ + // IE 11/Edge don't find elements on a `[name='']` query in some cases. + // Adding a temporary attribute to the document before the selection works + // around the issue. + // Interestingly, IE 10 & older don't seem to have the issue. + input = document.createElement( "input" ); + input.setAttribute( "name", "" ); + el.appendChild( input ); + if ( !el.querySelectorAll( "[name='']" ).length ) { + rbuggyQSA.push( "\\[" + whitespace + "*name" + whitespace + "*=" + + whitespace + "*(?:''|\"\")" ); + } + + // Webkit/Opera - :checked should return selected option elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + // IE8 throws error here and will not see later tests + if ( !el.querySelectorAll( ":checked" ).length ) { + rbuggyQSA.push( ":checked" ); + } + + // Support: Safari 8+, iOS 8+ + // https://bugs.webkit.org/show_bug.cgi?id=136851 + // In-page `selector#id sibling-combinator selector` fails + if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) { + rbuggyQSA.push( ".#.+[+~]" ); + } + + // Support: Firefox <=3.6 - 5 only + // Old Firefox doesn't throw on a badly-escaped identifier. + el.querySelectorAll( "\\\f" ); + rbuggyQSA.push( "[\\r\\n\\f]" ); + } ); + + assert( function( el ) { + el.innerHTML = "" + + ""; + + // Support: Windows 8 Native Apps + // The type and name attributes are restricted during .innerHTML assignment + var input = document.createElement( "input" ); + input.setAttribute( "type", "hidden" ); + el.appendChild( input ).setAttribute( "name", "D" ); + + // Support: IE8 + // Enforce case-sensitivity of name attribute + if ( el.querySelectorAll( "[name=d]" ).length ) { + rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); + } + + // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) + // IE8 throws error here and will not see later tests + if ( el.querySelectorAll( ":enabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: IE9-11+ + // IE's :disabled selector does not pick up the children of disabled fieldsets + docElem.appendChild( el ).disabled = true; + if ( el.querySelectorAll( ":disabled" ).length !== 2 ) { + rbuggyQSA.push( ":enabled", ":disabled" ); + } + + // Support: Opera 10 - 11 only + // Opera 10-11 does not throw on post-comma invalid pseudos + el.querySelectorAll( "*,:x" ); + rbuggyQSA.push( ",.*:" ); + } ); + } + + if ( ( support.matchesSelector = rnative.test( ( matches = docElem.matches || + docElem.webkitMatchesSelector || + docElem.mozMatchesSelector || + docElem.oMatchesSelector || + docElem.msMatchesSelector ) ) ) ) { + + assert( function( el ) { + + // Check to see if it's possible to do matchesSelector + // on a disconnected node (IE 9) + support.disconnectedMatch = matches.call( el, "*" ); + + // This should fail with an exception + // Gecko does not error, returns false instead + matches.call( el, "[s!='']:x" ); + rbuggyMatches.push( "!=", pseudos ); + } ); + } + + rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join( "|" ) ); + rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join( "|" ) ); + + /* Contains + ---------------------------------------------------------------------- */ + hasCompare = rnative.test( docElem.compareDocumentPosition ); + + // Element contains another + // Purposefully self-exclusive + // As in, an element does not contain itself + contains = hasCompare || rnative.test( docElem.contains ) ? + function( a, b ) { + var adown = a.nodeType === 9 ? a.documentElement : a, + bup = b && b.parentNode; + return a === bup || !!( bup && bup.nodeType === 1 && ( + adown.contains ? + adown.contains( bup ) : + a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 + ) ); + } : + function( a, b ) { + if ( b ) { + while ( ( b = b.parentNode ) ) { + if ( b === a ) { + return true; + } + } + } + return false; + }; + + /* Sorting + ---------------------------------------------------------------------- */ + + // Document order sorting + sortOrder = hasCompare ? + function( a, b ) { + + // Flag for duplicate removal + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + // Sort on method existence if only one input has compareDocumentPosition + var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; + if ( compare ) { + return compare; + } + + // Calculate position if both inputs belong to the same document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + compare = ( a.ownerDocument || a ) == ( b.ownerDocument || b ) ? + a.compareDocumentPosition( b ) : + + // Otherwise we know they are disconnected + 1; + + // Disconnected nodes + if ( compare & 1 || + ( !support.sortDetached && b.compareDocumentPosition( a ) === compare ) ) { + + // Choose the first element that is related to our preferred document + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( a == document || a.ownerDocument == preferredDoc && + contains( preferredDoc, a ) ) { + return -1; + } + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( b == document || b.ownerDocument == preferredDoc && + contains( preferredDoc, b ) ) { + return 1; + } + + // Maintain original order + return sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + } + + return compare & 4 ? -1 : 1; + } : + function( a, b ) { + + // Exit early if the nodes are identical + if ( a === b ) { + hasDuplicate = true; + return 0; + } + + var cur, + i = 0, + aup = a.parentNode, + bup = b.parentNode, + ap = [ a ], + bp = [ b ]; + + // Parentless nodes are either documents or disconnected + if ( !aup || !bup ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + return a == document ? -1 : + b == document ? 1 : + /* eslint-enable eqeqeq */ + aup ? -1 : + bup ? 1 : + sortInput ? + ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : + 0; + + // If the nodes are siblings, we can do a quick check + } else if ( aup === bup ) { + return siblingCheck( a, b ); + } + + // Otherwise we need full lists of their ancestors for comparison + cur = a; + while ( ( cur = cur.parentNode ) ) { + ap.unshift( cur ); + } + cur = b; + while ( ( cur = cur.parentNode ) ) { + bp.unshift( cur ); + } + + // Walk down the tree looking for a discrepancy + while ( ap[ i ] === bp[ i ] ) { + i++; + } + + return i ? + + // Do a sibling check if the nodes have a common ancestor + siblingCheck( ap[ i ], bp[ i ] ) : + + // Otherwise nodes in our document sort first + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + /* eslint-disable eqeqeq */ + ap[ i ] == preferredDoc ? -1 : + bp[ i ] == preferredDoc ? 1 : + /* eslint-enable eqeqeq */ + 0; + }; + + return document; +}; + +Sizzle.matches = function( expr, elements ) { + return Sizzle( expr, null, null, elements ); +}; + +Sizzle.matchesSelector = function( elem, expr ) { + setDocument( elem ); + + if ( support.matchesSelector && documentIsHTML && + !nonnativeSelectorCache[ expr + " " ] && + ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && + ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { + + try { + var ret = matches.call( elem, expr ); + + // IE 9's matchesSelector returns false on disconnected nodes + if ( ret || support.disconnectedMatch || + + // As well, disconnected nodes are said to be in a document + // fragment in IE 9 + elem.document && elem.document.nodeType !== 11 ) { + return ret; + } + } catch ( e ) { + nonnativeSelectorCache( expr, true ); + } + } + + return Sizzle( expr, document, null, [ elem ] ).length > 0; +}; + +Sizzle.contains = function( context, elem ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( context.ownerDocument || context ) != document ) { + setDocument( context ); + } + return contains( context, elem ); +}; + +Sizzle.attr = function( elem, name ) { + + // Set document vars if needed + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( ( elem.ownerDocument || elem ) != document ) { + setDocument( elem ); + } + + var fn = Expr.attrHandle[ name.toLowerCase() ], + + // Don't get fooled by Object.prototype properties (jQuery #13807) + val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? + fn( elem, name, !documentIsHTML ) : + undefined; + + return val !== undefined ? + val : + support.attributes || !documentIsHTML ? + elem.getAttribute( name ) : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; +}; + +Sizzle.escape = function( sel ) { + return ( sel + "" ).replace( rcssescape, fcssescape ); +}; + +Sizzle.error = function( msg ) { + throw new Error( "Syntax error, unrecognized expression: " + msg ); +}; + +/** + * Document sorting and removing duplicates + * @param {ArrayLike} results + */ +Sizzle.uniqueSort = function( results ) { + var elem, + duplicates = [], + j = 0, + i = 0; + + // Unless we *know* we can detect duplicates, assume their presence + hasDuplicate = !support.detectDuplicates; + sortInput = !support.sortStable && results.slice( 0 ); + results.sort( sortOrder ); + + if ( hasDuplicate ) { + while ( ( elem = results[ i++ ] ) ) { + if ( elem === results[ i ] ) { + j = duplicates.push( i ); + } + } + while ( j-- ) { + results.splice( duplicates[ j ], 1 ); + } + } + + // Clear input after sorting to release objects + // See https://github.com/jquery/sizzle/pull/225 + sortInput = null; + + return results; +}; + +/** + * Utility function for retrieving the text value of an array of DOM nodes + * @param {Array|Element} elem + */ +getText = Sizzle.getText = function( elem ) { + var node, + ret = "", + i = 0, + nodeType = elem.nodeType; + + if ( !nodeType ) { + + // If no nodeType, this is expected to be an array + while ( ( node = elem[ i++ ] ) ) { + + // Do not traverse comment nodes + ret += getText( node ); + } + } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { + + // Use textContent for elements + // innerText usage removed for consistency of new lines (jQuery #11153) + if ( typeof elem.textContent === "string" ) { + return elem.textContent; + } else { + + // Traverse its children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + ret += getText( elem ); + } + } + } else if ( nodeType === 3 || nodeType === 4 ) { + return elem.nodeValue; + } + + // Do not include comment or processing instruction nodes + + return ret; +}; + +Expr = Sizzle.selectors = { + + // Can be adjusted by the user + cacheLength: 50, + + createPseudo: markFunction, + + match: matchExpr, + + attrHandle: {}, + + find: {}, + + relative: { + ">": { dir: "parentNode", first: true }, + " ": { dir: "parentNode" }, + "+": { dir: "previousSibling", first: true }, + "~": { dir: "previousSibling" } + }, + + preFilter: { + "ATTR": function( match ) { + match[ 1 ] = match[ 1 ].replace( runescape, funescape ); + + // Move the given value to match[3] whether quoted or unquoted + match[ 3 ] = ( match[ 3 ] || match[ 4 ] || + match[ 5 ] || "" ).replace( runescape, funescape ); + + if ( match[ 2 ] === "~=" ) { + match[ 3 ] = " " + match[ 3 ] + " "; + } + + return match.slice( 0, 4 ); + }, + + "CHILD": function( match ) { + + /* matches from matchExpr["CHILD"] + 1 type (only|nth|...) + 2 what (child|of-type) + 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) + 4 xn-component of xn+y argument ([+-]?\d*n|) + 5 sign of xn-component + 6 x of xn-component + 7 sign of y-component + 8 y of y-component + */ + match[ 1 ] = match[ 1 ].toLowerCase(); + + if ( match[ 1 ].slice( 0, 3 ) === "nth" ) { + + // nth-* requires argument + if ( !match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + // numeric x and y parameters for Expr.filter.CHILD + // remember that false/true cast respectively to 0/1 + match[ 4 ] = +( match[ 4 ] ? + match[ 5 ] + ( match[ 6 ] || 1 ) : + 2 * ( match[ 3 ] === "even" || match[ 3 ] === "odd" ) ); + match[ 5 ] = +( ( match[ 7 ] + match[ 8 ] ) || match[ 3 ] === "odd" ); + + // other types prohibit arguments + } else if ( match[ 3 ] ) { + Sizzle.error( match[ 0 ] ); + } + + return match; + }, + + "PSEUDO": function( match ) { + var excess, + unquoted = !match[ 6 ] && match[ 2 ]; + + if ( matchExpr[ "CHILD" ].test( match[ 0 ] ) ) { + return null; + } + + // Accept quoted arguments as-is + if ( match[ 3 ] ) { + match[ 2 ] = match[ 4 ] || match[ 5 ] || ""; + + // Strip excess characters from unquoted arguments + } else if ( unquoted && rpseudo.test( unquoted ) && + + // Get excess from tokenize (recursively) + ( excess = tokenize( unquoted, true ) ) && + + // advance to the next closing parenthesis + ( excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length ) ) { + + // excess is a negative index + match[ 0 ] = match[ 0 ].slice( 0, excess ); + match[ 2 ] = unquoted.slice( 0, excess ); + } + + // Return only captures needed by the pseudo filter method (type and argument) + return match.slice( 0, 3 ); + } + }, + + filter: { + + "TAG": function( nodeNameSelector ) { + var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); + return nodeNameSelector === "*" ? + function() { + return true; + } : + function( elem ) { + return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; + }; + }, + + "CLASS": function( className ) { + var pattern = classCache[ className + " " ]; + + return pattern || + ( pattern = new RegExp( "(^|" + whitespace + + ")" + className + "(" + whitespace + "|$)" ) ) && classCache( + className, function( elem ) { + return pattern.test( + typeof elem.className === "string" && elem.className || + typeof elem.getAttribute !== "undefined" && + elem.getAttribute( "class" ) || + "" + ); + } ); + }, + + "ATTR": function( name, operator, check ) { + return function( elem ) { + var result = Sizzle.attr( elem, name ); + + if ( result == null ) { + return operator === "!="; + } + if ( !operator ) { + return true; + } + + result += ""; + + /* eslint-disable max-len */ + + return operator === "=" ? result === check : + operator === "!=" ? result !== check : + operator === "^=" ? check && result.indexOf( check ) === 0 : + operator === "*=" ? check && result.indexOf( check ) > -1 : + operator === "$=" ? check && result.slice( -check.length ) === check : + operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : + operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : + false; + /* eslint-enable max-len */ + + }; + }, + + "CHILD": function( type, what, _argument, first, last ) { + var simple = type.slice( 0, 3 ) !== "nth", + forward = type.slice( -4 ) !== "last", + ofType = what === "of-type"; + + return first === 1 && last === 0 ? + + // Shortcut for :nth-*(n) + function( elem ) { + return !!elem.parentNode; + } : + + function( elem, _context, xml ) { + var cache, uniqueCache, outerCache, node, nodeIndex, start, + dir = simple !== forward ? "nextSibling" : "previousSibling", + parent = elem.parentNode, + name = ofType && elem.nodeName.toLowerCase(), + useCache = !xml && !ofType, + diff = false; + + if ( parent ) { + + // :(first|last|only)-(child|of-type) + if ( simple ) { + while ( dir ) { + node = elem; + while ( ( node = node[ dir ] ) ) { + if ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) { + + return false; + } + } + + // Reverse direction for :only-* (if we haven't yet done so) + start = dir = type === "only" && !start && "nextSibling"; + } + return true; + } + + start = [ forward ? parent.firstChild : parent.lastChild ]; + + // non-xml :nth-child(...) stores cache data on `parent` + if ( forward && useCache ) { + + // Seek `elem` from a previously-cached index + + // ...in a gzip-friendly way + node = parent; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex && cache[ 2 ]; + node = nodeIndex && parent.childNodes[ nodeIndex ]; + + while ( ( node = ++nodeIndex && node && node[ dir ] || + + // Fallback to seeking `elem` from the start + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + // When found, cache indexes on `parent` and break + if ( node.nodeType === 1 && ++diff && node === elem ) { + uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; + break; + } + } + + } else { + + // Use previously-cached element index if available + if ( useCache ) { + + // ...in a gzip-friendly way + node = elem; + outerCache = node[ expando ] || ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + cache = uniqueCache[ type ] || []; + nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; + diff = nodeIndex; + } + + // xml :nth-child(...) + // or :nth-last-child(...) or :nth(-last)?-of-type(...) + if ( diff === false ) { + + // Use the same loop as above to seek `elem` from the start + while ( ( node = ++nodeIndex && node && node[ dir ] || + ( diff = nodeIndex = 0 ) || start.pop() ) ) { + + if ( ( ofType ? + node.nodeName.toLowerCase() === name : + node.nodeType === 1 ) && + ++diff ) { + + // Cache the index of each encountered element + if ( useCache ) { + outerCache = node[ expando ] || + ( node[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ node.uniqueID ] || + ( outerCache[ node.uniqueID ] = {} ); + + uniqueCache[ type ] = [ dirruns, diff ]; + } + + if ( node === elem ) { + break; + } + } + } + } + } + + // Incorporate the offset, then check against cycle size + diff -= last; + return diff === first || ( diff % first === 0 && diff / first >= 0 ); + } + }; + }, + + "PSEUDO": function( pseudo, argument ) { + + // pseudo-class names are case-insensitive + // http://www.w3.org/TR/selectors/#pseudo-classes + // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters + // Remember that setFilters inherits from pseudos + var args, + fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || + Sizzle.error( "unsupported pseudo: " + pseudo ); + + // The user may use createPseudo to indicate that + // arguments are needed to create the filter function + // just as Sizzle does + if ( fn[ expando ] ) { + return fn( argument ); + } + + // But maintain support for old signatures + if ( fn.length > 1 ) { + args = [ pseudo, pseudo, "", argument ]; + return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? + markFunction( function( seed, matches ) { + var idx, + matched = fn( seed, argument ), + i = matched.length; + while ( i-- ) { + idx = indexOf( seed, matched[ i ] ); + seed[ idx ] = !( matches[ idx ] = matched[ i ] ); + } + } ) : + function( elem ) { + return fn( elem, 0, args ); + }; + } + + return fn; + } + }, + + pseudos: { + + // Potentially complex pseudos + "not": markFunction( function( selector ) { + + // Trim the selector passed to compile + // to avoid treating leading and trailing + // spaces as combinators + var input = [], + results = [], + matcher = compile( selector.replace( rtrim, "$1" ) ); + + return matcher[ expando ] ? + markFunction( function( seed, matches, _context, xml ) { + var elem, + unmatched = matcher( seed, null, xml, [] ), + i = seed.length; + + // Match elements unmatched by `matcher` + while ( i-- ) { + if ( ( elem = unmatched[ i ] ) ) { + seed[ i ] = !( matches[ i ] = elem ); + } + } + } ) : + function( elem, _context, xml ) { + input[ 0 ] = elem; + matcher( input, null, xml, results ); + + // Don't keep the element (issue #299) + input[ 0 ] = null; + return !results.pop(); + }; + } ), + + "has": markFunction( function( selector ) { + return function( elem ) { + return Sizzle( selector, elem ).length > 0; + }; + } ), + + "contains": markFunction( function( text ) { + text = text.replace( runescape, funescape ); + return function( elem ) { + return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1; + }; + } ), + + // "Whether an element is represented by a :lang() selector + // is based solely on the element's language value + // being equal to the identifier C, + // or beginning with the identifier C immediately followed by "-". + // The matching of C against the element's language value is performed case-insensitively. + // The identifier C does not have to be a valid language name." + // http://www.w3.org/TR/selectors/#lang-pseudo + "lang": markFunction( function( lang ) { + + // lang value must be a valid identifier + if ( !ridentifier.test( lang || "" ) ) { + Sizzle.error( "unsupported lang: " + lang ); + } + lang = lang.replace( runescape, funescape ).toLowerCase(); + return function( elem ) { + var elemLang; + do { + if ( ( elemLang = documentIsHTML ? + elem.lang : + elem.getAttribute( "xml:lang" ) || elem.getAttribute( "lang" ) ) ) { + + elemLang = elemLang.toLowerCase(); + return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; + } + } while ( ( elem = elem.parentNode ) && elem.nodeType === 1 ); + return false; + }; + } ), + + // Miscellaneous + "target": function( elem ) { + var hash = window.location && window.location.hash; + return hash && hash.slice( 1 ) === elem.id; + }, + + "root": function( elem ) { + return elem === docElem; + }, + + "focus": function( elem ) { + return elem === document.activeElement && + ( !document.hasFocus || document.hasFocus() ) && + !!( elem.type || elem.href || ~elem.tabIndex ); + }, + + // Boolean properties + "enabled": createDisabledPseudo( false ), + "disabled": createDisabledPseudo( true ), + + "checked": function( elem ) { + + // In CSS3, :checked should return both checked and selected elements + // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked + var nodeName = elem.nodeName.toLowerCase(); + return ( nodeName === "input" && !!elem.checked ) || + ( nodeName === "option" && !!elem.selected ); + }, + + "selected": function( elem ) { + + // Accessing this property makes selected-by-default + // options in Safari work properly + if ( elem.parentNode ) { + // eslint-disable-next-line no-unused-expressions + elem.parentNode.selectedIndex; + } + + return elem.selected === true; + }, + + // Contents + "empty": function( elem ) { + + // http://www.w3.org/TR/selectors/#empty-pseudo + // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), + // but not by others (comment: 8; processing instruction: 7; etc.) + // nodeType < 6 works because attributes (2) do not appear as children + for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { + if ( elem.nodeType < 6 ) { + return false; + } + } + return true; + }, + + "parent": function( elem ) { + return !Expr.pseudos[ "empty" ]( elem ); + }, + + // Element/input types + "header": function( elem ) { + return rheader.test( elem.nodeName ); + }, + + "input": function( elem ) { + return rinputs.test( elem.nodeName ); + }, + + "button": function( elem ) { + var name = elem.nodeName.toLowerCase(); + return name === "input" && elem.type === "button" || name === "button"; + }, + + "text": function( elem ) { + var attr; + return elem.nodeName.toLowerCase() === "input" && + elem.type === "text" && + + // Support: IE<8 + // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" + ( ( attr = elem.getAttribute( "type" ) ) == null || + attr.toLowerCase() === "text" ); + }, + + // Position-in-collection + "first": createPositionalPseudo( function() { + return [ 0 ]; + } ), + + "last": createPositionalPseudo( function( _matchIndexes, length ) { + return [ length - 1 ]; + } ), + + "eq": createPositionalPseudo( function( _matchIndexes, length, argument ) { + return [ argument < 0 ? argument + length : argument ]; + } ), + + "even": createPositionalPseudo( function( matchIndexes, length ) { + var i = 0; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "odd": createPositionalPseudo( function( matchIndexes, length ) { + var i = 1; + for ( ; i < length; i += 2 ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "lt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? + argument + length : + argument > length ? + length : + argument; + for ( ; --i >= 0; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ), + + "gt": createPositionalPseudo( function( matchIndexes, length, argument ) { + var i = argument < 0 ? argument + length : argument; + for ( ; ++i < length; ) { + matchIndexes.push( i ); + } + return matchIndexes; + } ) + } +}; + +Expr.pseudos[ "nth" ] = Expr.pseudos[ "eq" ]; + +// Add button/input type pseudos +for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { + Expr.pseudos[ i ] = createInputPseudo( i ); +} +for ( i in { submit: true, reset: true } ) { + Expr.pseudos[ i ] = createButtonPseudo( i ); +} + +// Easy API for creating new setFilters +function setFilters() {} +setFilters.prototype = Expr.filters = Expr.pseudos; +Expr.setFilters = new setFilters(); + +tokenize = Sizzle.tokenize = function( selector, parseOnly ) { + var matched, match, tokens, type, + soFar, groups, preFilters, + cached = tokenCache[ selector + " " ]; + + if ( cached ) { + return parseOnly ? 0 : cached.slice( 0 ); + } + + soFar = selector; + groups = []; + preFilters = Expr.preFilter; + + while ( soFar ) { + + // Comma and first run + if ( !matched || ( match = rcomma.exec( soFar ) ) ) { + if ( match ) { + + // Don't consume trailing commas as valid + soFar = soFar.slice( match[ 0 ].length ) || soFar; + } + groups.push( ( tokens = [] ) ); + } + + matched = false; + + // Combinators + if ( ( match = rcombinators.exec( soFar ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + + // Cast descendant combinators to space + type: match[ 0 ].replace( rtrim, " " ) + } ); + soFar = soFar.slice( matched.length ); + } + + // Filters + for ( type in Expr.filter ) { + if ( ( match = matchExpr[ type ].exec( soFar ) ) && ( !preFilters[ type ] || + ( match = preFilters[ type ]( match ) ) ) ) { + matched = match.shift(); + tokens.push( { + value: matched, + type: type, + matches: match + } ); + soFar = soFar.slice( matched.length ); + } + } + + if ( !matched ) { + break; + } + } + + // Return the length of the invalid excess + // if we're just parsing + // Otherwise, throw an error or return tokens + return parseOnly ? + soFar.length : + soFar ? + Sizzle.error( selector ) : + + // Cache the tokens + tokenCache( selector, groups ).slice( 0 ); +}; + +function toSelector( tokens ) { + var i = 0, + len = tokens.length, + selector = ""; + for ( ; i < len; i++ ) { + selector += tokens[ i ].value; + } + return selector; +} + +function addCombinator( matcher, combinator, base ) { + var dir = combinator.dir, + skip = combinator.next, + key = skip || dir, + checkNonElements = base && key === "parentNode", + doneName = done++; + + return combinator.first ? + + // Check against closest ancestor/preceding element + function( elem, context, xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + return matcher( elem, context, xml ); + } + } + return false; + } : + + // Check against all ancestor/preceding elements + function( elem, context, xml ) { + var oldCache, uniqueCache, outerCache, + newCache = [ dirruns, doneName ]; + + // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching + if ( xml ) { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + if ( matcher( elem, context, xml ) ) { + return true; + } + } + } + } else { + while ( ( elem = elem[ dir ] ) ) { + if ( elem.nodeType === 1 || checkNonElements ) { + outerCache = elem[ expando ] || ( elem[ expando ] = {} ); + + // Support: IE <9 only + // Defend against cloned attroperties (jQuery gh-1709) + uniqueCache = outerCache[ elem.uniqueID ] || + ( outerCache[ elem.uniqueID ] = {} ); + + if ( skip && skip === elem.nodeName.toLowerCase() ) { + elem = elem[ dir ] || elem; + } else if ( ( oldCache = uniqueCache[ key ] ) && + oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { + + // Assign to newCache so results back-propagate to previous elements + return ( newCache[ 2 ] = oldCache[ 2 ] ); + } else { + + // Reuse newcache so results back-propagate to previous elements + uniqueCache[ key ] = newCache; + + // A match means we're done; a fail means we have to keep checking + if ( ( newCache[ 2 ] = matcher( elem, context, xml ) ) ) { + return true; + } + } + } + } + } + return false; + }; +} + +function elementMatcher( matchers ) { + return matchers.length > 1 ? + function( elem, context, xml ) { + var i = matchers.length; + while ( i-- ) { + if ( !matchers[ i ]( elem, context, xml ) ) { + return false; + } + } + return true; + } : + matchers[ 0 ]; +} + +function multipleContexts( selector, contexts, results ) { + var i = 0, + len = contexts.length; + for ( ; i < len; i++ ) { + Sizzle( selector, contexts[ i ], results ); + } + return results; +} + +function condense( unmatched, map, filter, context, xml ) { + var elem, + newUnmatched = [], + i = 0, + len = unmatched.length, + mapped = map != null; + + for ( ; i < len; i++ ) { + if ( ( elem = unmatched[ i ] ) ) { + if ( !filter || filter( elem, context, xml ) ) { + newUnmatched.push( elem ); + if ( mapped ) { + map.push( i ); + } + } + } + } + + return newUnmatched; +} + +function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { + if ( postFilter && !postFilter[ expando ] ) { + postFilter = setMatcher( postFilter ); + } + if ( postFinder && !postFinder[ expando ] ) { + postFinder = setMatcher( postFinder, postSelector ); + } + return markFunction( function( seed, results, context, xml ) { + var temp, i, elem, + preMap = [], + postMap = [], + preexisting = results.length, + + // Get initial elements from seed or context + elems = seed || multipleContexts( + selector || "*", + context.nodeType ? [ context ] : context, + [] + ), + + // Prefilter to get matcher input, preserving a map for seed-results synchronization + matcherIn = preFilter && ( seed || !selector ) ? + condense( elems, preMap, preFilter, context, xml ) : + elems, + + matcherOut = matcher ? + + // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, + postFinder || ( seed ? preFilter : preexisting || postFilter ) ? + + // ...intermediate processing is necessary + [] : + + // ...otherwise use results directly + results : + matcherIn; + + // Find primary matches + if ( matcher ) { + matcher( matcherIn, matcherOut, context, xml ); + } + + // Apply postFilter + if ( postFilter ) { + temp = condense( matcherOut, postMap ); + postFilter( temp, [], context, xml ); + + // Un-match failing elements by moving them back to matcherIn + i = temp.length; + while ( i-- ) { + if ( ( elem = temp[ i ] ) ) { + matcherOut[ postMap[ i ] ] = !( matcherIn[ postMap[ i ] ] = elem ); + } + } + } + + if ( seed ) { + if ( postFinder || preFilter ) { + if ( postFinder ) { + + // Get the final matcherOut by condensing this intermediate into postFinder contexts + temp = []; + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) ) { + + // Restore matcherIn since elem is not yet a final match + temp.push( ( matcherIn[ i ] = elem ) ); + } + } + postFinder( null, ( matcherOut = [] ), temp, xml ); + } + + // Move matched elements from seed to results to keep them synchronized + i = matcherOut.length; + while ( i-- ) { + if ( ( elem = matcherOut[ i ] ) && + ( temp = postFinder ? indexOf( seed, elem ) : preMap[ i ] ) > -1 ) { + + seed[ temp ] = !( results[ temp ] = elem ); + } + } + } + + // Add elements to results, through postFinder if defined + } else { + matcherOut = condense( + matcherOut === results ? + matcherOut.splice( preexisting, matcherOut.length ) : + matcherOut + ); + if ( postFinder ) { + postFinder( null, results, matcherOut, xml ); + } else { + push.apply( results, matcherOut ); + } + } + } ); +} + +function matcherFromTokens( tokens ) { + var checkContext, matcher, j, + len = tokens.length, + leadingRelative = Expr.relative[ tokens[ 0 ].type ], + implicitRelative = leadingRelative || Expr.relative[ " " ], + i = leadingRelative ? 1 : 0, + + // The foundational matcher ensures that elements are reachable from top-level context(s) + matchContext = addCombinator( function( elem ) { + return elem === checkContext; + }, implicitRelative, true ), + matchAnyContext = addCombinator( function( elem ) { + return indexOf( checkContext, elem ) > -1; + }, implicitRelative, true ), + matchers = [ function( elem, context, xml ) { + var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( + ( checkContext = context ).nodeType ? + matchContext( elem, context, xml ) : + matchAnyContext( elem, context, xml ) ); + + // Avoid hanging onto element (issue #299) + checkContext = null; + return ret; + } ]; + + for ( ; i < len; i++ ) { + if ( ( matcher = Expr.relative[ tokens[ i ].type ] ) ) { + matchers = [ addCombinator( elementMatcher( matchers ), matcher ) ]; + } else { + matcher = Expr.filter[ tokens[ i ].type ].apply( null, tokens[ i ].matches ); + + // Return special upon seeing a positional matcher + if ( matcher[ expando ] ) { + + // Find the next relative operator (if any) for proper handling + j = ++i; + for ( ; j < len; j++ ) { + if ( Expr.relative[ tokens[ j ].type ] ) { + break; + } + } + return setMatcher( + i > 1 && elementMatcher( matchers ), + i > 1 && toSelector( + + // If the preceding token was a descendant combinator, insert an implicit any-element `*` + tokens + .slice( 0, i - 1 ) + .concat( { value: tokens[ i - 2 ].type === " " ? "*" : "" } ) + ).replace( rtrim, "$1" ), + matcher, + i < j && matcherFromTokens( tokens.slice( i, j ) ), + j < len && matcherFromTokens( ( tokens = tokens.slice( j ) ) ), + j < len && toSelector( tokens ) + ); + } + matchers.push( matcher ); + } + } + + return elementMatcher( matchers ); +} + +function matcherFromGroupMatchers( elementMatchers, setMatchers ) { + var bySet = setMatchers.length > 0, + byElement = elementMatchers.length > 0, + superMatcher = function( seed, context, xml, results, outermost ) { + var elem, j, matcher, + matchedCount = 0, + i = "0", + unmatched = seed && [], + setMatched = [], + contextBackup = outermostContext, + + // We must always have either seed elements or outermost context + elems = seed || byElement && Expr.find[ "TAG" ]( "*", outermost ), + + // Use integer dirruns iff this is the outermost matcher + dirrunsUnique = ( dirruns += contextBackup == null ? 1 : Math.random() || 0.1 ), + len = elems.length; + + if ( outermost ) { + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + outermostContext = context == document || context || outermost; + } + + // Add elements passing elementMatchers directly to results + // Support: IE<9, Safari + // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id + for ( ; i !== len && ( elem = elems[ i ] ) != null; i++ ) { + if ( byElement && elem ) { + j = 0; + + // Support: IE 11+, Edge 17 - 18+ + // IE/Edge sometimes throw a "Permission denied" error when strict-comparing + // two documents; shallow comparisons work. + // eslint-disable-next-line eqeqeq + if ( !context && elem.ownerDocument != document ) { + setDocument( elem ); + xml = !documentIsHTML; + } + while ( ( matcher = elementMatchers[ j++ ] ) ) { + if ( matcher( elem, context || document, xml ) ) { + results.push( elem ); + break; + } + } + if ( outermost ) { + dirruns = dirrunsUnique; + } + } + + // Track unmatched elements for set filters + if ( bySet ) { + + // They will have gone through all possible matchers + if ( ( elem = !matcher && elem ) ) { + matchedCount--; + } + + // Lengthen the array for every element, matched or not + if ( seed ) { + unmatched.push( elem ); + } + } + } + + // `i` is now the count of elements visited above, and adding it to `matchedCount` + // makes the latter nonnegative. + matchedCount += i; + + // Apply set filters to unmatched elements + // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` + // equals `i`), unless we didn't visit _any_ elements in the above loop because we have + // no element matchers and no seed. + // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that + // case, which will result in a "00" `matchedCount` that differs from `i` but is also + // numerically zero. + if ( bySet && i !== matchedCount ) { + j = 0; + while ( ( matcher = setMatchers[ j++ ] ) ) { + matcher( unmatched, setMatched, context, xml ); + } + + if ( seed ) { + + // Reintegrate element matches to eliminate the need for sorting + if ( matchedCount > 0 ) { + while ( i-- ) { + if ( !( unmatched[ i ] || setMatched[ i ] ) ) { + setMatched[ i ] = pop.call( results ); + } + } + } + + // Discard index placeholder values to get only actual matches + setMatched = condense( setMatched ); + } + + // Add matches to results + push.apply( results, setMatched ); + + // Seedless set matches succeeding multiple successful matchers stipulate sorting + if ( outermost && !seed && setMatched.length > 0 && + ( matchedCount + setMatchers.length ) > 1 ) { + + Sizzle.uniqueSort( results ); + } + } + + // Override manipulation of globals by nested matchers + if ( outermost ) { + dirruns = dirrunsUnique; + outermostContext = contextBackup; + } + + return unmatched; + }; + + return bySet ? + markFunction( superMatcher ) : + superMatcher; +} + +compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { + var i, + setMatchers = [], + elementMatchers = [], + cached = compilerCache[ selector + " " ]; + + if ( !cached ) { + + // Generate a function of recursive functions that can be used to check each element + if ( !match ) { + match = tokenize( selector ); + } + i = match.length; + while ( i-- ) { + cached = matcherFromTokens( match[ i ] ); + if ( cached[ expando ] ) { + setMatchers.push( cached ); + } else { + elementMatchers.push( cached ); + } + } + + // Cache the compiled function + cached = compilerCache( + selector, + matcherFromGroupMatchers( elementMatchers, setMatchers ) + ); + + // Save selector and tokenization + cached.selector = selector; + } + return cached; +}; + +/** + * A low-level selection function that works with Sizzle's compiled + * selector functions + * @param {String|Function} selector A selector or a pre-compiled + * selector function built with Sizzle.compile + * @param {Element} context + * @param {Array} [results] + * @param {Array} [seed] A set of elements to match against + */ +select = Sizzle.select = function( selector, context, results, seed ) { + var i, tokens, token, type, find, + compiled = typeof selector === "function" && selector, + match = !seed && tokenize( ( selector = compiled.selector || selector ) ); + + results = results || []; + + // Try to minimize operations if there is only one selector in the list and no seed + // (the latter of which guarantees us context) + if ( match.length === 1 ) { + + // Reduce context if the leading compound selector is an ID + tokens = match[ 0 ] = match[ 0 ].slice( 0 ); + if ( tokens.length > 2 && ( token = tokens[ 0 ] ).type === "ID" && + context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[ 1 ].type ] ) { + + context = ( Expr.find[ "ID" ]( token.matches[ 0 ] + .replace( runescape, funescape ), context ) || [] )[ 0 ]; + if ( !context ) { + return results; + + // Precompiled matchers will still verify ancestry, so step up a level + } else if ( compiled ) { + context = context.parentNode; + } + + selector = selector.slice( tokens.shift().value.length ); + } + + // Fetch a seed set for right-to-left matching + i = matchExpr[ "needsContext" ].test( selector ) ? 0 : tokens.length; + while ( i-- ) { + token = tokens[ i ]; + + // Abort if we hit a combinator + if ( Expr.relative[ ( type = token.type ) ] ) { + break; + } + if ( ( find = Expr.find[ type ] ) ) { + + // Search, expanding context for leading sibling combinators + if ( ( seed = find( + token.matches[ 0 ].replace( runescape, funescape ), + rsibling.test( tokens[ 0 ].type ) && testContext( context.parentNode ) || + context + ) ) ) { + + // If seed is empty or no tokens remain, we can return early + tokens.splice( i, 1 ); + selector = seed.length && toSelector( tokens ); + if ( !selector ) { + push.apply( results, seed ); + return results; + } + + break; + } + } + } + } + + // Compile and execute a filtering function if one is not provided + // Provide `match` to avoid retokenization if we modified the selector above + ( compiled || compile( selector, match ) )( + seed, + context, + !documentIsHTML, + results, + !context || rsibling.test( selector ) && testContext( context.parentNode ) || context + ); + return results; +}; + +// One-time assignments + +// Sort stability +support.sortStable = expando.split( "" ).sort( sortOrder ).join( "" ) === expando; + +// Support: Chrome 14-35+ +// Always assume duplicates if they aren't passed to the comparison function +support.detectDuplicates = !!hasDuplicate; + +// Initialize against the default document +setDocument(); + +// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) +// Detached nodes confoundingly follow *each other* +support.sortDetached = assert( function( el ) { + + // Should return 1, but returns 4 (following) + return el.compareDocumentPosition( document.createElement( "fieldset" ) ) & 1; +} ); + +// Support: IE<8 +// Prevent attribute/property "interpolation" +// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx +if ( !assert( function( el ) { + el.innerHTML = ""; + return el.firstChild.getAttribute( "href" ) === "#"; +} ) ) { + addHandle( "type|href|height|width", function( elem, name, isXML ) { + if ( !isXML ) { + return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); + } + } ); +} + +// Support: IE<9 +// Use defaultValue in place of getAttribute("value") +if ( !support.attributes || !assert( function( el ) { + el.innerHTML = ""; + el.firstChild.setAttribute( "value", "" ); + return el.firstChild.getAttribute( "value" ) === ""; +} ) ) { + addHandle( "value", function( elem, _name, isXML ) { + if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { + return elem.defaultValue; + } + } ); +} + +// Support: IE<9 +// Use getAttributeNode to fetch booleans when getAttribute lies +if ( !assert( function( el ) { + return el.getAttribute( "disabled" ) == null; +} ) ) { + addHandle( booleans, function( elem, name, isXML ) { + var val; + if ( !isXML ) { + return elem[ name ] === true ? name.toLowerCase() : + ( val = elem.getAttributeNode( name ) ) && val.specified ? + val.value : + null; + } + } ); +} + +return Sizzle; + +} )( window ); + + + +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; + +// Deprecated +jQuery.expr[ ":" ] = jQuery.expr.pseudos; +jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; +jQuery.text = Sizzle.getText; +jQuery.isXMLDoc = Sizzle.isXML; +jQuery.contains = Sizzle.contains; +jQuery.escapeSelector = Sizzle.escape; + + + + +var dir = function( elem, dir, until ) { + var matched = [], + truncate = until !== undefined; + + while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { + if ( elem.nodeType === 1 ) { + if ( truncate && jQuery( elem ).is( until ) ) { + break; + } + matched.push( elem ); + } + } + return matched; +}; + + +var siblings = function( n, elem ) { + var matched = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + matched.push( n ); + } + } + + return matched; +}; + + +var rneedsContext = jQuery.expr.match.needsContext; + + + +function nodeName( elem, name ) { + + return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); + +}; +var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i ); + + + +// Implement the identical functionality for filter and not +function winnow( elements, qualifier, not ) { + if ( isFunction( qualifier ) ) { + return jQuery.grep( elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) !== not; + } ); + } + + // Single element + if ( qualifier.nodeType ) { + return jQuery.grep( elements, function( elem ) { + return ( elem === qualifier ) !== not; + } ); + } + + // Arraylike of elements (jQuery, arguments, Array) + if ( typeof qualifier !== "string" ) { + return jQuery.grep( elements, function( elem ) { + return ( indexOf.call( qualifier, elem ) > -1 ) !== not; + } ); + } + + // Filtered directly for both simple and complex selectors + return jQuery.filter( qualifier, elements, not ); +} + +jQuery.filter = function( expr, elems, not ) { + var elem = elems[ 0 ]; + + if ( not ) { + expr = ":not(" + expr + ")"; + } + + if ( elems.length === 1 && elem.nodeType === 1 ) { + return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : []; + } + + return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { + return elem.nodeType === 1; + } ) ); +}; + +jQuery.fn.extend( { + find: function( selector ) { + var i, ret, + len = this.length, + self = this; + + if ( typeof selector !== "string" ) { + return this.pushStack( jQuery( selector ).filter( function() { + for ( i = 0; i < len; i++ ) { + if ( jQuery.contains( self[ i ], this ) ) { + return true; + } + } + } ) ); + } + + ret = this.pushStack( [] ); + + for ( i = 0; i < len; i++ ) { + jQuery.find( selector, self[ i ], ret ); + } + + return len > 1 ? jQuery.uniqueSort( ret ) : ret; + }, + filter: function( selector ) { + return this.pushStack( winnow( this, selector || [], false ) ); + }, + not: function( selector ) { + return this.pushStack( winnow( this, selector || [], true ) ); + }, + is: function( selector ) { + return !!winnow( + this, + + // If this is a positional/relative selector, check membership in the returned set + // so $("p:first").is("p:last") won't return true for a doc with two "p". + typeof selector === "string" && rneedsContext.test( selector ) ? + jQuery( selector ) : + selector || [], + false + ).length; + } +} ); + + +// Initialize a jQuery object + + +// A central reference to the root jQuery(document) +var rootjQuery, + + // A simple way to check for HTML strings + // Prioritize #id over to avoid XSS via location.hash (#9521) + // Strict HTML recognition (#11290: must start with <) + // Shortcut simple #id case for speed + rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/, + + init = jQuery.fn.init = function( selector, context, root ) { + var match, elem; + + // HANDLE: $(""), $(null), $(undefined), $(false) + if ( !selector ) { + return this; + } + + // Method init() accepts an alternate rootjQuery + // so migrate can support jQuery.sub (gh-2101) + root = root || rootjQuery; + + // Handle HTML strings + if ( typeof selector === "string" ) { + if ( selector[ 0 ] === "<" && + selector[ selector.length - 1 ] === ">" && + selector.length >= 3 ) { + + // Assume that strings that start and end with <> are HTML and skip the regex check + match = [ null, selector, null ]; + + } else { + match = rquickExpr.exec( selector ); + } + + // Match html or make sure no context is specified for #id + if ( match && ( match[ 1 ] || !context ) ) { + + // HANDLE: $(html) -> $(array) + if ( match[ 1 ] ) { + context = context instanceof jQuery ? context[ 0 ] : context; + + // Option to run scripts is true for back-compat + // Intentionally let the error be thrown if parseHTML is not present + jQuery.merge( this, jQuery.parseHTML( + match[ 1 ], + context && context.nodeType ? context.ownerDocument || context : document, + true + ) ); + + // HANDLE: $(html, props) + if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { + for ( match in context ) { + + // Properties of context are called as methods if possible + if ( isFunction( this[ match ] ) ) { + this[ match ]( context[ match ] ); + + // ...and otherwise set as attributes + } else { + this.attr( match, context[ match ] ); + } + } + } + + return this; + + // HANDLE: $(#id) + } else { + elem = document.getElementById( match[ 2 ] ); + + if ( elem ) { + + // Inject the element directly into the jQuery object + this[ 0 ] = elem; + this.length = 1; + } + return this; + } + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return ( context || root ).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return this.constructor( context ).find( selector ); + } + + // HANDLE: $(DOMElement) + } else if ( selector.nodeType ) { + this[ 0 ] = selector; + this.length = 1; + return this; + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( isFunction( selector ) ) { + return root.ready !== undefined ? + root.ready( selector ) : + + // Execute immediately if ready is not present + selector( jQuery ); + } + + return jQuery.makeArray( selector, this ); + }; + +// Give the init function the jQuery prototype for later instantiation +init.prototype = jQuery.fn; + +// Initialize central reference +rootjQuery = jQuery( document ); + + +var rparentsprev = /^(?:parents|prev(?:Until|All))/, + + // Methods guaranteed to produce a unique set when starting from a unique set + guaranteedUnique = { + children: true, + contents: true, + next: true, + prev: true + }; + +jQuery.fn.extend( { + has: function( target ) { + var targets = jQuery( target, this ), + l = targets.length; + + return this.filter( function() { + var i = 0; + for ( ; i < l; i++ ) { + if ( jQuery.contains( this, targets[ i ] ) ) { + return true; + } + } + } ); + }, + + closest: function( selectors, context ) { + var cur, + i = 0, + l = this.length, + matched = [], + targets = typeof selectors !== "string" && jQuery( selectors ); + + // Positional selectors never match, since there's no _selection_ context + if ( !rneedsContext.test( selectors ) ) { + for ( ; i < l; i++ ) { + for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { + + // Always skip document fragments + if ( cur.nodeType < 11 && ( targets ? + targets.index( cur ) > -1 : + + // Don't pass non-elements to Sizzle + cur.nodeType === 1 && + jQuery.find.matchesSelector( cur, selectors ) ) ) { + + matched.push( cur ); + break; + } + } + } + } + + return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); + }, + + // Determine the position of an element within the set + index: function( elem ) { + + // No argument, return index in parent + if ( !elem ) { + return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; + } + + // Index in selector + if ( typeof elem === "string" ) { + return indexOf.call( jQuery( elem ), this[ 0 ] ); + } + + // Locate the position of the desired element + return indexOf.call( this, + + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[ 0 ] : elem + ); + }, + + add: function( selector, context ) { + return this.pushStack( + jQuery.uniqueSort( + jQuery.merge( this.get(), jQuery( selector, context ) ) + ) + ); + }, + + addBack: function( selector ) { + return this.add( selector == null ? + this.prevObject : this.prevObject.filter( selector ) + ); + } +} ); + +function sibling( cur, dir ) { + while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {} + return cur; +} + +jQuery.each( { + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, _i, until ) { + return dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return sibling( elem, "nextSibling" ); + }, + prev: function( elem ) { + return sibling( elem, "previousSibling" ); + }, + nextAll: function( elem ) { + return dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, _i, until ) { + return dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, _i, until ) { + return dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return siblings( ( elem.parentNode || {} ).firstChild, elem ); + }, + children: function( elem ) { + return siblings( elem.firstChild ); + }, + contents: function( elem ) { + if ( elem.contentDocument != null && + + // Support: IE 11+ + // elements with no `data` attribute has an object + // `contentDocument` with a `null` prototype. + getProto( elem.contentDocument ) ) { + + return elem.contentDocument; + } + + // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only + // Treat the template element as a regular one in browsers that + // don't support it. + if ( nodeName( elem, "template" ) ) { + elem = elem.content || elem; + } + + return jQuery.merge( [], elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var matched = jQuery.map( this, fn, until ); + + if ( name.slice( -5 ) !== "Until" ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + matched = jQuery.filter( selector, matched ); + } + + if ( this.length > 1 ) { + + // Remove duplicates + if ( !guaranteedUnique[ name ] ) { + jQuery.uniqueSort( matched ); + } + + // Reverse order for parents* and prev-derivatives + if ( rparentsprev.test( name ) ) { + matched.reverse(); + } + } + + return this.pushStack( matched ); + }; +} ); +var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g ); + + + +// Convert String-formatted options into Object-formatted ones +function createOptions( options ) { + var object = {}; + jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) { + object[ flag ] = true; + } ); + return object; +} + +/* + * Create a callback list using the following parameters: + * + * options: an optional list of space-separated options that will change how + * the callback list behaves or a more traditional option object + * + * By default a callback list will act like an event callback list and can be + * "fired" multiple times. + * + * Possible options: + * + * once: will ensure the callback list can only be fired once (like a Deferred) + * + * memory: will keep track of previous values and will call any callback added + * after the list has been fired right away with the latest "memorized" + * values (like a Deferred) + * + * unique: will ensure a callback can only be added once (no duplicate in the list) + * + * stopOnFalse: interrupt callings when a callback returns false + * + */ +jQuery.Callbacks = function( options ) { + + // Convert options from String-formatted to Object-formatted if needed + // (we check in cache first) + options = typeof options === "string" ? + createOptions( options ) : + jQuery.extend( {}, options ); + + var // Flag to know if list is currently firing + firing, + + // Last fire value for non-forgettable lists + memory, + + // Flag to know if list was already fired + fired, + + // Flag to prevent firing + locked, + + // Actual callback list + list = [], + + // Queue of execution data for repeatable lists + queue = [], + + // Index of currently firing callback (modified by add/remove as needed) + firingIndex = -1, + + // Fire callbacks + fire = function() { + + // Enforce single-firing + locked = locked || options.once; + + // Execute callbacks for all pending executions, + // respecting firingIndex overrides and runtime changes + fired = firing = true; + for ( ; queue.length; firingIndex = -1 ) { + memory = queue.shift(); + while ( ++firingIndex < list.length ) { + + // Run callback and check for early termination + if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && + options.stopOnFalse ) { + + // Jump to end and forget the data so .add doesn't re-fire + firingIndex = list.length; + memory = false; + } + } + } + + // Forget the data if we're done with it + if ( !options.memory ) { + memory = false; + } + + firing = false; + + // Clean up if we're done firing for good + if ( locked ) { + + // Keep an empty list if we have data for future add calls + if ( memory ) { + list = []; + + // Otherwise, this object is spent + } else { + list = ""; + } + } + }, + + // Actual Callbacks object + self = { + + // Add a callback or a collection of callbacks to the list + add: function() { + if ( list ) { + + // If we have memory from a past run, we should fire after adding + if ( memory && !firing ) { + firingIndex = list.length - 1; + queue.push( memory ); + } + + ( function add( args ) { + jQuery.each( args, function( _, arg ) { + if ( isFunction( arg ) ) { + if ( !options.unique || !self.has( arg ) ) { + list.push( arg ); + } + } else if ( arg && arg.length && toType( arg ) !== "string" ) { + + // Inspect recursively + add( arg ); + } + } ); + } )( arguments ); + + if ( memory && !firing ) { + fire(); + } + } + return this; + }, + + // Remove a callback from the list + remove: function() { + jQuery.each( arguments, function( _, arg ) { + var index; + while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { + list.splice( index, 1 ); + + // Handle firing indexes + if ( index <= firingIndex ) { + firingIndex--; + } + } + } ); + return this; + }, + + // Check if a given callback is in the list. + // If no argument is given, return whether or not list has callbacks attached. + has: function( fn ) { + return fn ? + jQuery.inArray( fn, list ) > -1 : + list.length > 0; + }, + + // Remove all callbacks from the list + empty: function() { + if ( list ) { + list = []; + } + return this; + }, + + // Disable .fire and .add + // Abort any current/pending executions + // Clear all callbacks and values + disable: function() { + locked = queue = []; + list = memory = ""; + return this; + }, + disabled: function() { + return !list; + }, + + // Disable .fire + // Also disable .add unless we have memory (since it would have no effect) + // Abort any pending executions + lock: function() { + locked = queue = []; + if ( !memory && !firing ) { + list = memory = ""; + } + return this; + }, + locked: function() { + return !!locked; + }, + + // Call all callbacks with the given context and arguments + fireWith: function( context, args ) { + if ( !locked ) { + args = args || []; + args = [ context, args.slice ? args.slice() : args ]; + queue.push( args ); + if ( !firing ) { + fire(); + } + } + return this; + }, + + // Call all the callbacks with the given arguments + fire: function() { + self.fireWith( this, arguments ); + return this; + }, + + // To know if the callbacks have already been called at least once + fired: function() { + return !!fired; + } + }; + + return self; +}; + + +function Identity( v ) { + return v; +} +function Thrower( ex ) { + throw ex; +} + +function adoptValue( value, resolve, reject, noValue ) { + var method; + + try { + + // Check for promise aspect first to privilege synchronous behavior + if ( value && isFunction( ( method = value.promise ) ) ) { + method.call( value ).done( resolve ).fail( reject ); + + // Other thenables + } else if ( value && isFunction( ( method = value.then ) ) ) { + method.call( value, resolve, reject ); + + // Other non-thenables + } else { + + // Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer: + // * false: [ value ].slice( 0 ) => resolve( value ) + // * true: [ value ].slice( 1 ) => resolve() + resolve.apply( undefined, [ value ].slice( noValue ) ); + } + + // For Promises/A+, convert exceptions into rejections + // Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in + // Deferred#then to conditionally suppress rejection. + } catch ( value ) { + + // Support: Android 4.0 only + // Strict mode functions invoked without .call/.apply get global-object context + reject.apply( undefined, [ value ] ); + } +} + +jQuery.extend( { + + Deferred: function( func ) { + var tuples = [ + + // action, add listener, callbacks, + // ... .then handlers, argument index, [final state] + [ "notify", "progress", jQuery.Callbacks( "memory" ), + jQuery.Callbacks( "memory" ), 2 ], + [ "resolve", "done", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 0, "resolved" ], + [ "reject", "fail", jQuery.Callbacks( "once memory" ), + jQuery.Callbacks( "once memory" ), 1, "rejected" ] + ], + state = "pending", + promise = { + state: function() { + return state; + }, + always: function() { + deferred.done( arguments ).fail( arguments ); + return this; + }, + "catch": function( fn ) { + return promise.then( null, fn ); + }, + + // Keep pipe for back-compat + pipe: function( /* fnDone, fnFail, fnProgress */ ) { + var fns = arguments; + + return jQuery.Deferred( function( newDefer ) { + jQuery.each( tuples, function( _i, tuple ) { + + // Map tuples (progress, done, fail) to arguments (done, fail, progress) + var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ]; + + // deferred.progress(function() { bind to newDefer or newDefer.notify }) + // deferred.done(function() { bind to newDefer or newDefer.resolve }) + // deferred.fail(function() { bind to newDefer or newDefer.reject }) + deferred[ tuple[ 1 ] ]( function() { + var returned = fn && fn.apply( this, arguments ); + if ( returned && isFunction( returned.promise ) ) { + returned.promise() + .progress( newDefer.notify ) + .done( newDefer.resolve ) + .fail( newDefer.reject ); + } else { + newDefer[ tuple[ 0 ] + "With" ]( + this, + fn ? [ returned ] : arguments + ); + } + } ); + } ); + fns = null; + } ).promise(); + }, + then: function( onFulfilled, onRejected, onProgress ) { + var maxDepth = 0; + function resolve( depth, deferred, handler, special ) { + return function() { + var that = this, + args = arguments, + mightThrow = function() { + var returned, then; + + // Support: Promises/A+ section 2.3.3.3.3 + // https://promisesaplus.com/#point-59 + // Ignore double-resolution attempts + if ( depth < maxDepth ) { + return; + } + + returned = handler.apply( that, args ); + + // Support: Promises/A+ section 2.3.1 + // https://promisesaplus.com/#point-48 + if ( returned === deferred.promise() ) { + throw new TypeError( "Thenable self-resolution" ); + } + + // Support: Promises/A+ sections 2.3.3.1, 3.5 + // https://promisesaplus.com/#point-54 + // https://promisesaplus.com/#point-75 + // Retrieve `then` only once + then = returned && + + // Support: Promises/A+ section 2.3.4 + // https://promisesaplus.com/#point-64 + // Only check objects and functions for thenability + ( typeof returned === "object" || + typeof returned === "function" ) && + returned.then; + + // Handle a returned thenable + if ( isFunction( then ) ) { + + // Special processors (notify) just wait for resolution + if ( special ) { + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ) + ); + + // Normal processors (resolve) also hook into progress + } else { + + // ...and disregard older resolution values + maxDepth++; + + then.call( + returned, + resolve( maxDepth, deferred, Identity, special ), + resolve( maxDepth, deferred, Thrower, special ), + resolve( maxDepth, deferred, Identity, + deferred.notifyWith ) + ); + } + + // Handle all other returned values + } else { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Identity ) { + that = undefined; + args = [ returned ]; + } + + // Process the value(s) + // Default process is resolve + ( special || deferred.resolveWith )( that, args ); + } + }, + + // Only normal processors (resolve) catch and reject exceptions + process = special ? + mightThrow : + function() { + try { + mightThrow(); + } catch ( e ) { + + if ( jQuery.Deferred.exceptionHook ) { + jQuery.Deferred.exceptionHook( e, + process.stackTrace ); + } + + // Support: Promises/A+ section 2.3.3.3.4.1 + // https://promisesaplus.com/#point-61 + // Ignore post-resolution exceptions + if ( depth + 1 >= maxDepth ) { + + // Only substitute handlers pass on context + // and multiple values (non-spec behavior) + if ( handler !== Thrower ) { + that = undefined; + args = [ e ]; + } + + deferred.rejectWith( that, args ); + } + } + }; + + // Support: Promises/A+ section 2.3.3.3.1 + // https://promisesaplus.com/#point-57 + // Re-resolve promises immediately to dodge false rejection from + // subsequent errors + if ( depth ) { + process(); + } else { + + // Call an optional hook to record the stack, in case of exception + // since it's otherwise lost when execution goes async + if ( jQuery.Deferred.getStackHook ) { + process.stackTrace = jQuery.Deferred.getStackHook(); + } + window.setTimeout( process ); + } + }; + } + + return jQuery.Deferred( function( newDefer ) { + + // progress_handlers.add( ... ) + tuples[ 0 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onProgress ) ? + onProgress : + Identity, + newDefer.notifyWith + ) + ); + + // fulfilled_handlers.add( ... ) + tuples[ 1 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onFulfilled ) ? + onFulfilled : + Identity + ) + ); + + // rejected_handlers.add( ... ) + tuples[ 2 ][ 3 ].add( + resolve( + 0, + newDefer, + isFunction( onRejected ) ? + onRejected : + Thrower + ) + ); + } ).promise(); + }, + + // Get a promise for this deferred + // If obj is provided, the promise aspect is added to the object + promise: function( obj ) { + return obj != null ? jQuery.extend( obj, promise ) : promise; + } + }, + deferred = {}; + + // Add list-specific methods + jQuery.each( tuples, function( i, tuple ) { + var list = tuple[ 2 ], + stateString = tuple[ 5 ]; + + // promise.progress = list.add + // promise.done = list.add + // promise.fail = list.add + promise[ tuple[ 1 ] ] = list.add; + + // Handle state + if ( stateString ) { + list.add( + function() { + + // state = "resolved" (i.e., fulfilled) + // state = "rejected" + state = stateString; + }, + + // rejected_callbacks.disable + // fulfilled_callbacks.disable + tuples[ 3 - i ][ 2 ].disable, + + // rejected_handlers.disable + // fulfilled_handlers.disable + tuples[ 3 - i ][ 3 ].disable, + + // progress_callbacks.lock + tuples[ 0 ][ 2 ].lock, + + // progress_handlers.lock + tuples[ 0 ][ 3 ].lock + ); + } + + // progress_handlers.fire + // fulfilled_handlers.fire + // rejected_handlers.fire + list.add( tuple[ 3 ].fire ); + + // deferred.notify = function() { deferred.notifyWith(...) } + // deferred.resolve = function() { deferred.resolveWith(...) } + // deferred.reject = function() { deferred.rejectWith(...) } + deferred[ tuple[ 0 ] ] = function() { + deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments ); + return this; + }; + + // deferred.notifyWith = list.fireWith + // deferred.resolveWith = list.fireWith + // deferred.rejectWith = list.fireWith + deferred[ tuple[ 0 ] + "With" ] = list.fireWith; + } ); + + // Make the deferred a promise + promise.promise( deferred ); + + // Call given func if any + if ( func ) { + func.call( deferred, deferred ); + } + + // All done! + return deferred; + }, + + // Deferred helper + when: function( singleValue ) { + var + + // count of uncompleted subordinates + remaining = arguments.length, + + // count of unprocessed arguments + i = remaining, + + // subordinate fulfillment data + resolveContexts = Array( i ), + resolveValues = slice.call( arguments ), + + // the master Deferred + master = jQuery.Deferred(), + + // subordinate callback factory + updateFunc = function( i ) { + return function( value ) { + resolveContexts[ i ] = this; + resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; + if ( !( --remaining ) ) { + master.resolveWith( resolveContexts, resolveValues ); + } + }; + }; + + // Single- and empty arguments are adopted like Promise.resolve + if ( remaining <= 1 ) { + adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject, + !remaining ); + + // Use .then() to unwrap secondary thenables (cf. gh-3000) + if ( master.state() === "pending" || + isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) { + + return master.then(); + } + } + + // Multiple arguments are aggregated like Promise.all array elements + while ( i-- ) { + adoptValue( resolveValues[ i ], updateFunc( i ), master.reject ); + } + + return master.promise(); + } +} ); + + +// These usually indicate a programmer mistake during development, +// warn about them ASAP rather than swallowing them by default. +var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/; + +jQuery.Deferred.exceptionHook = function( error, stack ) { + + // Support: IE 8 - 9 only + // Console exists when dev tools are open, which can happen at any time + if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) { + window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack ); + } +}; + + + + +jQuery.readyException = function( error ) { + window.setTimeout( function() { + throw error; + } ); +}; + + + + +// The deferred used on DOM ready +var readyList = jQuery.Deferred(); + +jQuery.fn.ready = function( fn ) { + + readyList + .then( fn ) + + // Wrap jQuery.readyException in a function so that the lookup + // happens at the time of error handling instead of callback + // registration. + .catch( function( error ) { + jQuery.readyException( error ); + } ); + + return this; +}; + +jQuery.extend( { + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // A counter to track how many items to wait for before + // the ready event fires. See #6781 + readyWait: 1, + + // Handle when the DOM is ready + ready: function( wait ) { + + // Abort if there are pending holds or we're already ready + if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { + return; + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If a normal DOM Ready event fired, decrement, and wait if need be + if ( wait !== true && --jQuery.readyWait > 0 ) { + return; + } + + // If there are functions bound, to execute + readyList.resolveWith( document, [ jQuery ] ); + } +} ); + +jQuery.ready.then = readyList.then; + +// The ready event handler and self cleanup method +function completed() { + document.removeEventListener( "DOMContentLoaded", completed ); + window.removeEventListener( "load", completed ); + jQuery.ready(); +} + +// Catch cases where $(document).ready() is called +// after the browser event has already occurred. +// Support: IE <=9 - 10 only +// Older IE sometimes signals "interactive" too soon +if ( document.readyState === "complete" || + ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { + + // Handle it asynchronously to allow scripts the opportunity to delay ready + window.setTimeout( jQuery.ready ); + +} else { + + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", completed ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", completed ); +} + + + + +// Multifunctional method to get and set values of a collection +// The value/s can optionally be executed if it's a function +var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { + var i = 0, + len = elems.length, + bulk = key == null; + + // Sets many values + if ( toType( key ) === "object" ) { + chainable = true; + for ( i in key ) { + access( elems, fn, i, key[ i ], true, emptyGet, raw ); + } + + // Sets one value + } else if ( value !== undefined ) { + chainable = true; + + if ( !isFunction( value ) ) { + raw = true; + } + + if ( bulk ) { + + // Bulk operations run against the entire set + if ( raw ) { + fn.call( elems, value ); + fn = null; + + // ...except when executing function values + } else { + bulk = fn; + fn = function( elem, _key, value ) { + return bulk.call( jQuery( elem ), value ); + }; + } + } + + if ( fn ) { + for ( ; i < len; i++ ) { + fn( + elems[ i ], key, raw ? + value : + value.call( elems[ i ], i, fn( elems[ i ], key ) ) + ); + } + } + } + + if ( chainable ) { + return elems; + } + + // Gets + if ( bulk ) { + return fn.call( elems ); + } + + return len ? fn( elems[ 0 ], key ) : emptyGet; +}; + + +// Matches dashed string for camelizing +var rmsPrefix = /^-ms-/, + rdashAlpha = /-([a-z])/g; + +// Used by camelCase as callback to replace() +function fcamelCase( _all, letter ) { + return letter.toUpperCase(); +} + +// Convert dashed to camelCase; used by the css and data modules +// Support: IE <=9 - 11, Edge 12 - 15 +// Microsoft forgot to hump their vendor prefix (#9572) +function camelCase( string ) { + return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); +} +var acceptData = function( owner ) { + + // Accepts only: + // - Node + // - Node.ELEMENT_NODE + // - Node.DOCUMENT_NODE + // - Object + // - Any + return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType ); +}; + + + + +function Data() { + this.expando = jQuery.expando + Data.uid++; +} + +Data.uid = 1; + +Data.prototype = { + + cache: function( owner ) { + + // Check if the owner object already has a cache + var value = owner[ this.expando ]; + + // If not, create one + if ( !value ) { + value = {}; + + // We can accept data for non-element nodes in modern browsers, + // but we should not, see #8335. + // Always return an empty object. + if ( acceptData( owner ) ) { + + // If it is a node unlikely to be stringify-ed or looped over + // use plain assignment + if ( owner.nodeType ) { + owner[ this.expando ] = value; + + // Otherwise secure it in a non-enumerable property + // configurable must be true to allow the property to be + // deleted when data is removed + } else { + Object.defineProperty( owner, this.expando, { + value: value, + configurable: true + } ); + } + } + } + + return value; + }, + set: function( owner, data, value ) { + var prop, + cache = this.cache( owner ); + + // Handle: [ owner, key, value ] args + // Always use camelCase key (gh-2257) + if ( typeof data === "string" ) { + cache[ camelCase( data ) ] = value; + + // Handle: [ owner, { properties } ] args + } else { + + // Copy the properties one-by-one to the cache object + for ( prop in data ) { + cache[ camelCase( prop ) ] = data[ prop ]; + } + } + return cache; + }, + get: function( owner, key ) { + return key === undefined ? + this.cache( owner ) : + + // Always use camelCase key (gh-2257) + owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ]; + }, + access: function( owner, key, value ) { + + // In cases where either: + // + // 1. No key was specified + // 2. A string key was specified, but no value provided + // + // Take the "read" path and allow the get method to determine + // which value to return, respectively either: + // + // 1. The entire cache object + // 2. The data stored at the key + // + if ( key === undefined || + ( ( key && typeof key === "string" ) && value === undefined ) ) { + + return this.get( owner, key ); + } + + // When the key is not a string, or both a key and value + // are specified, set or extend (existing objects) with either: + // + // 1. An object of properties + // 2. A key and value + // + this.set( owner, key, value ); + + // Since the "set" path can have two possible entry points + // return the expected data based on which path was taken[*] + return value !== undefined ? value : key; + }, + remove: function( owner, key ) { + var i, + cache = owner[ this.expando ]; + + if ( cache === undefined ) { + return; + } + + if ( key !== undefined ) { + + // Support array or space separated string of keys + if ( Array.isArray( key ) ) { + + // If key is an array of keys... + // We always set camelCase keys, so remove that. + key = key.map( camelCase ); + } else { + key = camelCase( key ); + + // If a key with the spaces exists, use it. + // Otherwise, create an array by matching non-whitespace + key = key in cache ? + [ key ] : + ( key.match( rnothtmlwhite ) || [] ); + } + + i = key.length; + + while ( i-- ) { + delete cache[ key[ i ] ]; + } + } + + // Remove the expando if there's no more data + if ( key === undefined || jQuery.isEmptyObject( cache ) ) { + + // Support: Chrome <=35 - 45 + // Webkit & Blink performance suffers when deleting properties + // from DOM nodes, so set to undefined instead + // https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted) + if ( owner.nodeType ) { + owner[ this.expando ] = undefined; + } else { + delete owner[ this.expando ]; + } + } + }, + hasData: function( owner ) { + var cache = owner[ this.expando ]; + return cache !== undefined && !jQuery.isEmptyObject( cache ); + } +}; +var dataPriv = new Data(); + +var dataUser = new Data(); + + + +// Implementation Summary +// +// 1. Enforce API surface and semantic compatibility with 1.9.x branch +// 2. Improve the module's maintainability by reducing the storage +// paths to a single mechanism. +// 3. Use the same single mechanism to support "private" and "user" data. +// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData) +// 5. Avoid exposing implementation details on user objects (eg. expando properties) +// 6. Provide a clear path for implementation upgrade to WeakMap in 2014 + +var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, + rmultiDash = /[A-Z]/g; + +function getData( data ) { + if ( data === "true" ) { + return true; + } + + if ( data === "false" ) { + return false; + } + + if ( data === "null" ) { + return null; + } + + // Only convert to a number if it doesn't change the string + if ( data === +data + "" ) { + return +data; + } + + if ( rbrace.test( data ) ) { + return JSON.parse( data ); + } + + return data; +} + +function dataAttr( elem, key, data ) { + var name; + + // If nothing was found internally, try to fetch any + // data from the HTML5 data-* attribute + if ( data === undefined && elem.nodeType === 1 ) { + name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase(); + data = elem.getAttribute( name ); + + if ( typeof data === "string" ) { + try { + data = getData( data ); + } catch ( e ) {} + + // Make sure we set the data so it isn't changed later + dataUser.set( elem, key, data ); + } else { + data = undefined; + } + } + return data; +} + +jQuery.extend( { + hasData: function( elem ) { + return dataUser.hasData( elem ) || dataPriv.hasData( elem ); + }, + + data: function( elem, name, data ) { + return dataUser.access( elem, name, data ); + }, + + removeData: function( elem, name ) { + dataUser.remove( elem, name ); + }, + + // TODO: Now that all calls to _data and _removeData have been replaced + // with direct calls to dataPriv methods, these can be deprecated. + _data: function( elem, name, data ) { + return dataPriv.access( elem, name, data ); + }, + + _removeData: function( elem, name ) { + dataPriv.remove( elem, name ); + } +} ); + +jQuery.fn.extend( { + data: function( key, value ) { + var i, name, data, + elem = this[ 0 ], + attrs = elem && elem.attributes; + + // Gets all values + if ( key === undefined ) { + if ( this.length ) { + data = dataUser.get( elem ); + + if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) { + i = attrs.length; + while ( i-- ) { + + // Support: IE 11 only + // The attrs elements can be null (#14894) + if ( attrs[ i ] ) { + name = attrs[ i ].name; + if ( name.indexOf( "data-" ) === 0 ) { + name = camelCase( name.slice( 5 ) ); + dataAttr( elem, name, data[ name ] ); + } + } + } + dataPriv.set( elem, "hasDataAttrs", true ); + } + } + + return data; + } + + // Sets multiple values + if ( typeof key === "object" ) { + return this.each( function() { + dataUser.set( this, key ); + } ); + } + + return access( this, function( value ) { + var data; + + // The calling jQuery object (element matches) is not empty + // (and therefore has an element appears at this[ 0 ]) and the + // `value` parameter was not undefined. An empty jQuery object + // will result in `undefined` for elem = this[ 0 ] which will + // throw an exception if an attempt to read a data cache is made. + if ( elem && value === undefined ) { + + // Attempt to get data from the cache + // The key will always be camelCased in Data + data = dataUser.get( elem, key ); + if ( data !== undefined ) { + return data; + } + + // Attempt to "discover" the data in + // HTML5 custom data-* attrs + data = dataAttr( elem, key ); + if ( data !== undefined ) { + return data; + } + + // We tried really hard, but the data doesn't exist. + return; + } + + // Set the data... + this.each( function() { + + // We always store the camelCased key + dataUser.set( this, key, value ); + } ); + }, null, value, arguments.length > 1, null, true ); + }, + + removeData: function( key ) { + return this.each( function() { + dataUser.remove( this, key ); + } ); + } +} ); + + +jQuery.extend( { + queue: function( elem, type, data ) { + var queue; + + if ( elem ) { + type = ( type || "fx" ) + "queue"; + queue = dataPriv.get( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( data ) { + if ( !queue || Array.isArray( data ) ) { + queue = dataPriv.access( elem, type, jQuery.makeArray( data ) ); + } else { + queue.push( data ); + } + } + return queue || []; + } + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), + startLength = queue.length, + fn = queue.shift(), + hooks = jQuery._queueHooks( elem, type ), + next = function() { + jQuery.dequeue( elem, type ); + }; + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + startLength--; + } + + if ( fn ) { + + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift( "inprogress" ); + } + + // Clear up the last queue stop function + delete hooks.stop; + fn.call( elem, next, hooks ); + } + + if ( !startLength && hooks ) { + hooks.empty.fire(); + } + }, + + // Not public - generate a queueHooks object, or return the current one + _queueHooks: function( elem, type ) { + var key = type + "queueHooks"; + return dataPriv.get( elem, key ) || dataPriv.access( elem, key, { + empty: jQuery.Callbacks( "once memory" ).add( function() { + dataPriv.remove( elem, [ type + "queue", key ] ); + } ) + } ); + } +} ); + +jQuery.fn.extend( { + queue: function( type, data ) { + var setter = 2; + + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + setter--; + } + + if ( arguments.length < setter ) { + return jQuery.queue( this[ 0 ], type ); + } + + return data === undefined ? + this : + this.each( function() { + var queue = jQuery.queue( this, type, data ); + + // Ensure a hooks for this queue + jQuery._queueHooks( this, type ); + + if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + } ); + }, + dequeue: function( type ) { + return this.each( function() { + jQuery.dequeue( this, type ); + } ); + }, + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + }, + + // Get a promise resolved when queues of a certain type + // are emptied (fx is the type by default) + promise: function( type, obj ) { + var tmp, + count = 1, + defer = jQuery.Deferred(), + elements = this, + i = this.length, + resolve = function() { + if ( !( --count ) ) { + defer.resolveWith( elements, [ elements ] ); + } + }; + + if ( typeof type !== "string" ) { + obj = type; + type = undefined; + } + type = type || "fx"; + + while ( i-- ) { + tmp = dataPriv.get( elements[ i ], type + "queueHooks" ); + if ( tmp && tmp.empty ) { + count++; + tmp.empty.add( resolve ); + } + } + resolve(); + return defer.promise( obj ); + } +} ); +var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; + +var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); + + +var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; + +var documentElement = document.documentElement; + + + + var isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ); + }, + composed = { composed: true }; + + // Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only + // Check attachment across shadow DOM boundaries when possible (gh-3504) + // Support: iOS 10.0-10.2 only + // Early iOS 10 versions support `attachShadow` but not `getRootNode`, + // leading to errors. We need to check for `getRootNode`. + if ( documentElement.getRootNode ) { + isAttached = function( elem ) { + return jQuery.contains( elem.ownerDocument, elem ) || + elem.getRootNode( composed ) === elem.ownerDocument; + }; + } +var isHiddenWithinTree = function( elem, el ) { + + // isHiddenWithinTree might be called from jQuery#filter function; + // in that case, element will be second argument + elem = el || elem; + + // Inline style trumps all + return elem.style.display === "none" || + elem.style.display === "" && + + // Otherwise, check computed style + // Support: Firefox <=43 - 45 + // Disconnected elements can have computed display: none, so first confirm that elem is + // in the document. + isAttached( elem ) && + + jQuery.css( elem, "display" ) === "none"; + }; + + + +function adjustCSS( elem, prop, valueParts, tween ) { + var adjusted, scale, + maxIterations = 20, + currentValue = tween ? + function() { + return tween.cur(); + } : + function() { + return jQuery.css( elem, prop, "" ); + }, + initial = currentValue(), + unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), + + // Starting value computation is required for potential unit mismatches + initialInUnit = elem.nodeType && + ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && + rcssNum.exec( jQuery.css( elem, prop ) ); + + if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { + + // Support: Firefox <=54 + // Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144) + initial = initial / 2; + + // Trust units reported by jQuery.css + unit = unit || initialInUnit[ 3 ]; + + // Iteratively approximate from a nonzero starting point + initialInUnit = +initial || 1; + + while ( maxIterations-- ) { + + // Evaluate and update our best guess (doubling guesses that zero out). + // Finish if the scale equals or crosses 1 (making the old*new product non-positive). + jQuery.style( elem, prop, initialInUnit + unit ); + if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) { + maxIterations = 0; + } + initialInUnit = initialInUnit / scale; + + } + + initialInUnit = initialInUnit * 2; + jQuery.style( elem, prop, initialInUnit + unit ); + + // Make sure we update the tween properties later on + valueParts = valueParts || []; + } + + if ( valueParts ) { + initialInUnit = +initialInUnit || +initial || 0; + + // Apply relative offset (+=/-=) if specified + adjusted = valueParts[ 1 ] ? + initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : + +valueParts[ 2 ]; + if ( tween ) { + tween.unit = unit; + tween.start = initialInUnit; + tween.end = adjusted; + } + } + return adjusted; +} + + +var defaultDisplayMap = {}; + +function getDefaultDisplay( elem ) { + var temp, + doc = elem.ownerDocument, + nodeName = elem.nodeName, + display = defaultDisplayMap[ nodeName ]; + + if ( display ) { + return display; + } + + temp = doc.body.appendChild( doc.createElement( nodeName ) ); + display = jQuery.css( temp, "display" ); + + temp.parentNode.removeChild( temp ); + + if ( display === "none" ) { + display = "block"; + } + defaultDisplayMap[ nodeName ] = display; + + return display; +} + +function showHide( elements, show ) { + var display, elem, + values = [], + index = 0, + length = elements.length; + + // Determine new display value for elements that need to change + for ( ; index < length; index++ ) { + elem = elements[ index ]; + if ( !elem.style ) { + continue; + } + + display = elem.style.display; + if ( show ) { + + // Since we force visibility upon cascade-hidden elements, an immediate (and slow) + // check is required in this first loop unless we have a nonempty display value (either + // inline or about-to-be-restored) + if ( display === "none" ) { + values[ index ] = dataPriv.get( elem, "display" ) || null; + if ( !values[ index ] ) { + elem.style.display = ""; + } + } + if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) { + values[ index ] = getDefaultDisplay( elem ); + } + } else { + if ( display !== "none" ) { + values[ index ] = "none"; + + // Remember what we're overwriting + dataPriv.set( elem, "display", display ); + } + } + } + + // Set the display of the elements in a second loop to avoid constant reflow + for ( index = 0; index < length; index++ ) { + if ( values[ index ] != null ) { + elements[ index ].style.display = values[ index ]; + } + } + + return elements; +} + +jQuery.fn.extend( { + show: function() { + return showHide( this, true ); + }, + hide: function() { + return showHide( this ); + }, + toggle: function( state ) { + if ( typeof state === "boolean" ) { + return state ? this.show() : this.hide(); + } + + return this.each( function() { + if ( isHiddenWithinTree( this ) ) { + jQuery( this ).show(); + } else { + jQuery( this ).hide(); + } + } ); + } +} ); +var rcheckableType = ( /^(?:checkbox|radio)$/i ); + +var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i ); + +var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i ); + + + +( function() { + var fragment = document.createDocumentFragment(), + div = fragment.appendChild( document.createElement( "div" ) ), + input = document.createElement( "input" ); + + // Support: Android 4.0 - 4.3 only + // Check state lost if the name is set (#11217) + // Support: Windows Web Apps (WWA) + // `name` and `type` must use .setAttribute for WWA (#14901) + input.setAttribute( "type", "radio" ); + input.setAttribute( "checked", "checked" ); + input.setAttribute( "name", "t" ); + + div.appendChild( input ); + + // Support: Android <=4.1 only + // Older WebKit doesn't clone checked state correctly in fragments + support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; + + // Support: IE <=11 only + // Make sure textarea (and checkbox) defaultValue is properly cloned + div.innerHTML = ""; + support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; + + // Support: IE <=9 only + // IE <=9 replaces "; + support.option = !!div.lastChild; +} )(); + + +// We have to close these tags to support XHTML (#13200) +var wrapMap = { + + // XHTML parsers do not magically insert elements in the + // same way that tag soup parsers do. So we cannot shorten + // this by omitting or other required elements. + thead: [ 1, "", "
    " ], + col: [ 2, "", "
    " ], + tr: [ 2, "", "
    " ], + td: [ 3, "", "
    " ], + + _default: [ 0, "", "" ] +}; + +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// Support: IE <=9 only +if ( !support.option ) { + wrapMap.optgroup = wrapMap.option = [ 1, "" ]; +} + + +function getAll( context, tag ) { + + // Support: IE <=9 - 11 only + // Use typeof to avoid zero-argument method invocation on host objects (#15151) + var ret; + + if ( typeof context.getElementsByTagName !== "undefined" ) { + ret = context.getElementsByTagName( tag || "*" ); + + } else if ( typeof context.querySelectorAll !== "undefined" ) { + ret = context.querySelectorAll( tag || "*" ); + + } else { + ret = []; + } + + if ( tag === undefined || tag && nodeName( context, tag ) ) { + return jQuery.merge( [ context ], ret ); + } + + return ret; +} + + +// Mark scripts as having already been evaluated +function setGlobalEval( elems, refElements ) { + var i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + dataPriv.set( + elems[ i ], + "globalEval", + !refElements || dataPriv.get( refElements[ i ], "globalEval" ) + ); + } +} + + +var rhtml = /<|&#?\w+;/; + +function buildFragment( elems, context, scripts, selection, ignored ) { + var elem, tmp, tag, wrap, attached, j, + fragment = context.createDocumentFragment(), + nodes = [], + i = 0, + l = elems.length; + + for ( ; i < l; i++ ) { + elem = elems[ i ]; + + if ( elem || elem === 0 ) { + + // Add nodes directly + if ( toType( elem ) === "object" ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem ); + + // Convert non-html into a text node + } else if ( !rhtml.test( elem ) ) { + nodes.push( context.createTextNode( elem ) ); + + // Convert html into DOM nodes + } else { + tmp = tmp || fragment.appendChild( context.createElement( "div" ) ); + + // Deserialize a standard representation + tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase(); + wrap = wrapMap[ tag ] || wrapMap._default; + tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ]; + + // Descend through wrappers to the right content + j = wrap[ 0 ]; + while ( j-- ) { + tmp = tmp.lastChild; + } + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( nodes, tmp.childNodes ); + + // Remember the top-level container + tmp = fragment.firstChild; + + // Ensure the created nodes are orphaned (#12392) + tmp.textContent = ""; + } + } + } + + // Remove wrapper from fragment + fragment.textContent = ""; + + i = 0; + while ( ( elem = nodes[ i++ ] ) ) { + + // Skip elements already in the context collection (trac-4087) + if ( selection && jQuery.inArray( elem, selection ) > -1 ) { + if ( ignored ) { + ignored.push( elem ); + } + continue; + } + + attached = isAttached( elem ); + + // Append to fragment + tmp = getAll( fragment.appendChild( elem ), "script" ); + + // Preserve script evaluation history + if ( attached ) { + setGlobalEval( tmp ); + } + + // Capture executables + if ( scripts ) { + j = 0; + while ( ( elem = tmp[ j++ ] ) ) { + if ( rscriptType.test( elem.type || "" ) ) { + scripts.push( elem ); + } + } + } + } + + return fragment; +} + + +var + rkeyEvent = /^key/, + rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, + rtypenamespace = /^([^.]*)(?:\.(.+)|)/; + +function returnTrue() { + return true; +} + +function returnFalse() { + return false; +} + +// Support: IE <=9 - 11+ +// focus() and blur() are asynchronous, except when they are no-op. +// So expect focus to be synchronous when the element is already active, +// and blur to be synchronous when the element is not already active. +// (focus and blur are always synchronous in other supported browsers, +// this just defines when we can count on it). +function expectSync( elem, type ) { + return ( elem === safeActiveElement() ) === ( type === "focus" ); +} + +// Support: IE <=9 only +// Accessing document.activeElement can throw unexpectedly +// https://bugs.jquery.com/ticket/13393 +function safeActiveElement() { + try { + return document.activeElement; + } catch ( err ) { } +} + +function on( elem, types, selector, data, fn, one ) { + var origFn, type; + + // Types can be a map of types/handlers + if ( typeof types === "object" ) { + + // ( types-Object, selector, data ) + if ( typeof selector !== "string" ) { + + // ( types-Object, data ) + data = data || selector; + selector = undefined; + } + for ( type in types ) { + on( elem, type, selector, data, types[ type ], one ); + } + return elem; + } + + if ( data == null && fn == null ) { + + // ( types, fn ) + fn = selector; + data = selector = undefined; + } else if ( fn == null ) { + if ( typeof selector === "string" ) { + + // ( types, selector, fn ) + fn = data; + data = undefined; + } else { + + // ( types, data, fn ) + fn = data; + data = selector; + selector = undefined; + } + } + if ( fn === false ) { + fn = returnFalse; + } else if ( !fn ) { + return elem; + } + + if ( one === 1 ) { + origFn = fn; + fn = function( event ) { + + // Can use an empty set, since event contains the info + jQuery().off( event ); + return origFn.apply( this, arguments ); + }; + + // Use same guid so caller can remove using origFn + fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); + } + return elem.each( function() { + jQuery.event.add( this, types, fn, data, selector ); + } ); +} + +/* + * Helper functions for managing events -- not part of the public interface. + * Props to Dean Edwards' addEvent library for many of the ideas. + */ +jQuery.event = { + + global: {}, + + add: function( elem, types, handler, data, selector ) { + + var handleObjIn, eventHandle, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.get( elem ); + + // Only attach events to objects that accept data + if ( !acceptData( elem ) ) { + return; + } + + // Caller can pass in an object of custom data in lieu of the handler + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + selector = handleObjIn.selector; + } + + // Ensure that invalid selectors throw exceptions at attach time + // Evaluate against documentElement in case elem is a non-element node (e.g., document) + if ( selector ) { + jQuery.find.matchesSelector( documentElement, selector ); + } + + // Make sure that the handler has a unique ID, used to find/remove it later + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure and main handler, if this is the first + if ( !( events = elemData.events ) ) { + events = elemData.events = Object.create( null ); + } + if ( !( eventHandle = elemData.handle ) ) { + eventHandle = elemData.handle = function( e ) { + + // Discard the second event of a jQuery.event.trigger() and + // when an event is called after a page has unloaded + return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ? + jQuery.event.dispatch.apply( elem, arguments ) : undefined; + }; + } + + // Handle multiple events separated by a space + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // There *must* be a type, no attaching namespace-only handlers + if ( !type ) { + continue; + } + + // If event changes its type, use the special event handlers for the changed type + special = jQuery.event.special[ type ] || {}; + + // If selector defined, determine special event api type, otherwise given type + type = ( selector ? special.delegateType : special.bindType ) || type; + + // Update special based on newly reset type + special = jQuery.event.special[ type ] || {}; + + // handleObj is passed to all event handlers + handleObj = jQuery.extend( { + type: type, + origType: origType, + data: data, + handler: handler, + guid: handler.guid, + selector: selector, + needsContext: selector && jQuery.expr.match.needsContext.test( selector ), + namespace: namespaces.join( "." ) + }, handleObjIn ); + + // Init the event handler queue if we're the first + if ( !( handlers = events[ type ] ) ) { + handlers = events[ type ] = []; + handlers.delegateCount = 0; + + // Only use addEventListener if the special events handler returns false + if ( !special.setup || + special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add to the element's handler list, delegates in front + if ( selector ) { + handlers.splice( handlers.delegateCount++, 0, handleObj ); + } else { + handlers.push( handleObj ); + } + + // Keep track of which events have ever been used, for event optimization + jQuery.event.global[ type ] = true; + } + + }, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, selector, mappedTypes ) { + + var j, origCount, tmp, + events, t, handleObj, + special, handlers, type, namespaces, origType, + elemData = dataPriv.hasData( elem ) && dataPriv.get( elem ); + + if ( !elemData || !( events = elemData.events ) ) { + return; + } + + // Once for each type.namespace in types; type may be omitted + types = ( types || "" ).match( rnothtmlwhite ) || [ "" ]; + t = types.length; + while ( t-- ) { + tmp = rtypenamespace.exec( types[ t ] ) || []; + type = origType = tmp[ 1 ]; + namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); + + // Unbind all events (on this namespace, if provided) for the element + if ( !type ) { + for ( type in events ) { + jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); + } + continue; + } + + special = jQuery.event.special[ type ] || {}; + type = ( selector ? special.delegateType : special.bindType ) || type; + handlers = events[ type ] || []; + tmp = tmp[ 2 ] && + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); + + // Remove matching events + origCount = j = handlers.length; + while ( j-- ) { + handleObj = handlers[ j ]; + + if ( ( mappedTypes || origType === handleObj.origType ) && + ( !handler || handler.guid === handleObj.guid ) && + ( !tmp || tmp.test( handleObj.namespace ) ) && + ( !selector || selector === handleObj.selector || + selector === "**" && handleObj.selector ) ) { + handlers.splice( j, 1 ); + + if ( handleObj.selector ) { + handlers.delegateCount--; + } + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + } + + // Remove generic event handler if we removed something and no more handlers exist + // (avoids potential for endless recursion during removal of special event handlers) + if ( origCount && !handlers.length ) { + if ( !special.teardown || + special.teardown.call( elem, namespaces, elemData.handle ) === false ) { + + jQuery.removeEvent( elem, type, elemData.handle ); + } + + delete events[ type ]; + } + } + + // Remove data and the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + dataPriv.remove( elem, "handle events" ); + } + }, + + dispatch: function( nativeEvent ) { + + var i, j, ret, matched, handleObj, handlerQueue, + args = new Array( arguments.length ), + + // Make a writable jQuery.Event from the native event object + event = jQuery.event.fix( nativeEvent ), + + handlers = ( + dataPriv.get( this, "events" ) || Object.create( null ) + )[ event.type ] || [], + special = jQuery.event.special[ event.type ] || {}; + + // Use the fix-ed jQuery.Event rather than the (read-only) native event + args[ 0 ] = event; + + for ( i = 1; i < arguments.length; i++ ) { + args[ i ] = arguments[ i ]; + } + + event.delegateTarget = this; + + // Call the preDispatch hook for the mapped type, and let it bail if desired + if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { + return; + } + + // Determine handlers + handlerQueue = jQuery.event.handlers.call( this, event, handlers ); + + // Run delegates first; they may want to stop propagation beneath us + i = 0; + while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { + event.currentTarget = matched.elem; + + j = 0; + while ( ( handleObj = matched.handlers[ j++ ] ) && + !event.isImmediatePropagationStopped() ) { + + // If the event is namespaced, then each handler is only invoked if it is + // specially universal or its namespaces are a superset of the event's. + if ( !event.rnamespace || handleObj.namespace === false || + event.rnamespace.test( handleObj.namespace ) ) { + + event.handleObj = handleObj; + event.data = handleObj.data; + + ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || + handleObj.handler ).apply( matched.elem, args ); + + if ( ret !== undefined ) { + if ( ( event.result = ret ) === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + } + } + } + + // Call the postDispatch hook for the mapped type + if ( special.postDispatch ) { + special.postDispatch.call( this, event ); + } + + return event.result; + }, + + handlers: function( event, handlers ) { + var i, handleObj, sel, matchedHandlers, matchedSelectors, + handlerQueue = [], + delegateCount = handlers.delegateCount, + cur = event.target; + + // Find delegate handlers + if ( delegateCount && + + // Support: IE <=9 + // Black-hole SVG instance trees (trac-13180) + cur.nodeType && + + // Support: Firefox <=42 + // Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861) + // https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click + // Support: IE 11 only + // ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343) + !( event.type === "click" && event.button >= 1 ) ) { + + for ( ; cur !== this; cur = cur.parentNode || this ) { + + // Don't check non-elements (#13208) + // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) + if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) { + matchedHandlers = []; + matchedSelectors = {}; + for ( i = 0; i < delegateCount; i++ ) { + handleObj = handlers[ i ]; + + // Don't conflict with Object.prototype properties (#13203) + sel = handleObj.selector + " "; + + if ( matchedSelectors[ sel ] === undefined ) { + matchedSelectors[ sel ] = handleObj.needsContext ? + jQuery( sel, this ).index( cur ) > -1 : + jQuery.find( sel, this, null, [ cur ] ).length; + } + if ( matchedSelectors[ sel ] ) { + matchedHandlers.push( handleObj ); + } + } + if ( matchedHandlers.length ) { + handlerQueue.push( { elem: cur, handlers: matchedHandlers } ); + } + } + } + } + + // Add the remaining (directly-bound) handlers + cur = this; + if ( delegateCount < handlers.length ) { + handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } ); + } + + return handlerQueue; + }, + + addProp: function( name, hook ) { + Object.defineProperty( jQuery.Event.prototype, name, { + enumerable: true, + configurable: true, + + get: isFunction( hook ) ? + function() { + if ( this.originalEvent ) { + return hook( this.originalEvent ); + } + } : + function() { + if ( this.originalEvent ) { + return this.originalEvent[ name ]; + } + }, + + set: function( value ) { + Object.defineProperty( this, name, { + enumerable: true, + configurable: true, + writable: true, + value: value + } ); + } + } ); + }, + + fix: function( originalEvent ) { + return originalEvent[ jQuery.expando ] ? + originalEvent : + new jQuery.Event( originalEvent ); + }, + + special: { + load: { + + // Prevent triggered image.load events from bubbling to window.load + noBubble: true + }, + click: { + + // Utilize native event to ensure correct state for checkable inputs + setup: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Claim the first handler + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + // dataPriv.set( el, "click", ... ) + leverageNative( el, "click", returnTrue ); + } + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function( data ) { + + // For mutual compressibility with _default, replace `this` access with a local var. + // `|| data` is dead code meant only to preserve the variable through minification. + var el = this || data; + + // Force setup before triggering a click + if ( rcheckableType.test( el.type ) && + el.click && nodeName( el, "input" ) ) { + + leverageNative( el, "click" ); + } + + // Return non-false to allow normal event-path propagation + return true; + }, + + // For cross-browser consistency, suppress native .click() on links + // Also prevent it if we're currently inside a leveraged native-event stack + _default: function( event ) { + var target = event.target; + return rcheckableType.test( target.type ) && + target.click && nodeName( target, "input" ) && + dataPriv.get( target, "click" ) || + nodeName( target, "a" ); + } + }, + + beforeunload: { + postDispatch: function( event ) { + + // Support: Firefox 20+ + // Firefox doesn't alert if the returnValue field is not set. + if ( event.result !== undefined && event.originalEvent ) { + event.originalEvent.returnValue = event.result; + } + } + } + } +}; + +// Ensure the presence of an event listener that handles manually-triggered +// synthetic events by interrupting progress until reinvoked in response to +// *native* events that it fires directly, ensuring that state changes have +// already occurred before other listeners are invoked. +function leverageNative( el, type, expectSync ) { + + // Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add + if ( !expectSync ) { + if ( dataPriv.get( el, type ) === undefined ) { + jQuery.event.add( el, type, returnTrue ); + } + return; + } + + // Register the controller as a special universal handler for all event namespaces + dataPriv.set( el, type, false ); + jQuery.event.add( el, type, { + namespace: false, + handler: function( event ) { + var notAsync, result, + saved = dataPriv.get( this, type ); + + if ( ( event.isTrigger & 1 ) && this[ type ] ) { + + // Interrupt processing of the outer synthetic .trigger()ed event + // Saved data should be false in such cases, but might be a leftover capture object + // from an async native handler (gh-4350) + if ( !saved.length ) { + + // Store arguments for use when handling the inner native event + // There will always be at least one argument (an event object), so this array + // will not be confused with a leftover capture object. + saved = slice.call( arguments ); + dataPriv.set( this, type, saved ); + + // Trigger the native event and capture its result + // Support: IE <=9 - 11+ + // focus() and blur() are asynchronous + notAsync = expectSync( this, type ); + this[ type ](); + result = dataPriv.get( this, type ); + if ( saved !== result || notAsync ) { + dataPriv.set( this, type, false ); + } else { + result = {}; + } + if ( saved !== result ) { + + // Cancel the outer synthetic event + event.stopImmediatePropagation(); + event.preventDefault(); + return result.value; + } + + // If this is an inner synthetic event for an event with a bubbling surrogate + // (focus or blur), assume that the surrogate already propagated from triggering the + // native event and prevent that from happening again here. + // This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the + // bubbling surrogate propagates *after* the non-bubbling base), but that seems + // less bad than duplication. + } else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) { + event.stopPropagation(); + } + + // If this is a native event triggered above, everything is now in order + // Fire an inner synthetic event with the original arguments + } else if ( saved.length ) { + + // ...and capture the result + dataPriv.set( this, type, { + value: jQuery.event.trigger( + + // Support: IE <=9 - 11+ + // Extend with the prototype to reset the above stopImmediatePropagation() + jQuery.extend( saved[ 0 ], jQuery.Event.prototype ), + saved.slice( 1 ), + this + ) + } ); + + // Abort handling of the native event + event.stopImmediatePropagation(); + } + } + } ); +} + +jQuery.removeEvent = function( elem, type, handle ) { + + // This "if" is needed for plain objects + if ( elem.removeEventListener ) { + elem.removeEventListener( type, handle ); + } +}; + +jQuery.Event = function( src, props ) { + + // Allow instantiation without the 'new' keyword + if ( !( this instanceof jQuery.Event ) ) { + return new jQuery.Event( src, props ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + + // Events bubbling up the document may have been marked as prevented + // by a handler lower down the tree; reflect the correct value. + this.isDefaultPrevented = src.defaultPrevented || + src.defaultPrevented === undefined && + + // Support: Android <=2.3 only + src.returnValue === false ? + returnTrue : + returnFalse; + + // Create target properties + // Support: Safari <=6 - 7 only + // Target should not be a text node (#504, #13143) + this.target = ( src.target && src.target.nodeType === 3 ) ? + src.target.parentNode : + src.target; + + this.currentTarget = src.currentTarget; + this.relatedTarget = src.relatedTarget; + + // Event type + } else { + this.type = src; + } + + // Put explicitly provided properties onto the event object + if ( props ) { + jQuery.extend( this, props ); + } + + // Create a timestamp if incoming event doesn't have one + this.timeStamp = src && src.timeStamp || Date.now(); + + // Mark it as fixed + this[ jQuery.expando ] = true; +}; + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + constructor: jQuery.Event, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse, + isSimulated: false, + + preventDefault: function() { + var e = this.originalEvent; + + this.isDefaultPrevented = returnTrue; + + if ( e && !this.isSimulated ) { + e.preventDefault(); + } + }, + stopPropagation: function() { + var e = this.originalEvent; + + this.isPropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopPropagation(); + } + }, + stopImmediatePropagation: function() { + var e = this.originalEvent; + + this.isImmediatePropagationStopped = returnTrue; + + if ( e && !this.isSimulated ) { + e.stopImmediatePropagation(); + } + + this.stopPropagation(); + } +}; + +// Includes all common event props including KeyEvent and MouseEvent specific props +jQuery.each( { + altKey: true, + bubbles: true, + cancelable: true, + changedTouches: true, + ctrlKey: true, + detail: true, + eventPhase: true, + metaKey: true, + pageX: true, + pageY: true, + shiftKey: true, + view: true, + "char": true, + code: true, + charCode: true, + key: true, + keyCode: true, + button: true, + buttons: true, + clientX: true, + clientY: true, + offsetX: true, + offsetY: true, + pointerId: true, + pointerType: true, + screenX: true, + screenY: true, + targetTouches: true, + toElement: true, + touches: true, + + which: function( event ) { + var button = event.button; + + // Add which for key events + if ( event.which == null && rkeyEvent.test( event.type ) ) { + return event.charCode != null ? event.charCode : event.keyCode; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) { + if ( button & 1 ) { + return 1; + } + + if ( button & 2 ) { + return 3; + } + + if ( button & 4 ) { + return 2; + } + + return 0; + } + + return event.which; + } +}, jQuery.event.addProp ); + +jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) { + jQuery.event.special[ type ] = { + + // Utilize native event if possible so blur/focus sequence is correct + setup: function() { + + // Claim the first handler + // dataPriv.set( this, "focus", ... ) + // dataPriv.set( this, "blur", ... ) + leverageNative( this, type, expectSync ); + + // Return false to allow normal processing in the caller + return false; + }, + trigger: function() { + + // Force setup before trigger + leverageNative( this, type ); + + // Return non-false to allow normal event-path propagation + return true; + }, + + delegateType: delegateType + }; +} ); + +// Create mouseenter/leave events using mouseover/out and event-time checks +// so that event delegation works in jQuery. +// Do the same for pointerenter/pointerleave and pointerover/pointerout +// +// Support: Safari 7 only +// Safari sends mouseenter too often; see: +// https://bugs.chromium.org/p/chromium/issues/detail?id=470258 +// for the description of the bug (it existed in older Chrome versions as well). +jQuery.each( { + mouseenter: "mouseover", + mouseleave: "mouseout", + pointerenter: "pointerover", + pointerleave: "pointerout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + delegateType: fix, + bindType: fix, + + handle: function( event ) { + var ret, + target = this, + related = event.relatedTarget, + handleObj = event.handleObj; + + // For mouseenter/leave call the handler if related is outside the target. + // NB: No relatedTarget if the mouse left/entered the browser window + if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { + event.type = handleObj.origType; + ret = handleObj.handler.apply( this, arguments ); + event.type = fix; + } + return ret; + } + }; +} ); + +jQuery.fn.extend( { + + on: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn ); + }, + one: function( types, selector, data, fn ) { + return on( this, types, selector, data, fn, 1 ); + }, + off: function( types, selector, fn ) { + var handleObj, type; + if ( types && types.preventDefault && types.handleObj ) { + + // ( event ) dispatched jQuery.Event + handleObj = types.handleObj; + jQuery( types.delegateTarget ).off( + handleObj.namespace ? + handleObj.origType + "." + handleObj.namespace : + handleObj.origType, + handleObj.selector, + handleObj.handler + ); + return this; + } + if ( typeof types === "object" ) { + + // ( types-object [, selector] ) + for ( type in types ) { + this.off( type, selector, types[ type ] ); + } + return this; + } + if ( selector === false || typeof selector === "function" ) { + + // ( types [, fn] ) + fn = selector; + selector = undefined; + } + if ( fn === false ) { + fn = returnFalse; + } + return this.each( function() { + jQuery.event.remove( this, types, fn, selector ); + } ); + } +} ); + + +var + + // Support: IE <=10 - 11, Edge 12 - 13 only + // In IE/Edge using regex groups here causes severe slowdowns. + // See https://connect.microsoft.com/IE/feedback/details/1736512/ + rnoInnerhtml = /\s*$/g; + +// Prefer a tbody over its parent table for containing new rows +function manipulationTarget( elem, content ) { + if ( nodeName( elem, "table" ) && + nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) { + + return jQuery( elem ).children( "tbody" )[ 0 ] || elem; + } + + return elem; +} + +// Replace/restore the type attribute of script elements for safe DOM manipulation +function disableScript( elem ) { + elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type; + return elem; +} +function restoreScript( elem ) { + if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) { + elem.type = elem.type.slice( 5 ); + } else { + elem.removeAttribute( "type" ); + } + + return elem; +} + +function cloneCopyEvent( src, dest ) { + var i, l, type, pdataOld, udataOld, udataCur, events; + + if ( dest.nodeType !== 1 ) { + return; + } + + // 1. Copy private data: events, handlers, etc. + if ( dataPriv.hasData( src ) ) { + pdataOld = dataPriv.get( src ); + events = pdataOld.events; + + if ( events ) { + dataPriv.remove( dest, "handle events" ); + + for ( type in events ) { + for ( i = 0, l = events[ type ].length; i < l; i++ ) { + jQuery.event.add( dest, type, events[ type ][ i ] ); + } + } + } + } + + // 2. Copy user data + if ( dataUser.hasData( src ) ) { + udataOld = dataUser.access( src ); + udataCur = jQuery.extend( {}, udataOld ); + + dataUser.set( dest, udataCur ); + } +} + +// Fix IE bugs, see support tests +function fixInput( src, dest ) { + var nodeName = dest.nodeName.toLowerCase(); + + // Fails to persist the checked state of a cloned checkbox or radio button. + if ( nodeName === "input" && rcheckableType.test( src.type ) ) { + dest.checked = src.checked; + + // Fails to return the selected option to the default selected state when cloning options + } else if ( nodeName === "input" || nodeName === "textarea" ) { + dest.defaultValue = src.defaultValue; + } +} + +function domManip( collection, args, callback, ignored ) { + + // Flatten any nested arrays + args = flat( args ); + + var fragment, first, scripts, hasScripts, node, doc, + i = 0, + l = collection.length, + iNoClone = l - 1, + value = args[ 0 ], + valueIsFunction = isFunction( value ); + + // We can't cloneNode fragments that contain checked, in WebKit + if ( valueIsFunction || + ( l > 1 && typeof value === "string" && + !support.checkClone && rchecked.test( value ) ) ) { + return collection.each( function( index ) { + var self = collection.eq( index ); + if ( valueIsFunction ) { + args[ 0 ] = value.call( this, index, self.html() ); + } + domManip( self, args, callback, ignored ); + } ); + } + + if ( l ) { + fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); + first = fragment.firstChild; + + if ( fragment.childNodes.length === 1 ) { + fragment = first; + } + + // Require either new content or an interest in ignored elements to invoke the callback + if ( first || ignored ) { + scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); + hasScripts = scripts.length; + + // Use the original fragment for the last item + // instead of the first because it can end up + // being emptied incorrectly in certain situations (#8070). + for ( ; i < l; i++ ) { + node = fragment; + + if ( i !== iNoClone ) { + node = jQuery.clone( node, true, true ); + + // Keep references to cloned scripts for later restoration + if ( hasScripts ) { + + // Support: Android <=4.0 only, PhantomJS 1 only + // push.apply(_, arraylike) throws on ancient WebKit + jQuery.merge( scripts, getAll( node, "script" ) ); + } + } + + callback.call( collection[ i ], node, i ); + } + + if ( hasScripts ) { + doc = scripts[ scripts.length - 1 ].ownerDocument; + + // Reenable scripts + jQuery.map( scripts, restoreScript ); + + // Evaluate executable scripts on first document insertion + for ( i = 0; i < hasScripts; i++ ) { + node = scripts[ i ]; + if ( rscriptType.test( node.type || "" ) && + !dataPriv.access( node, "globalEval" ) && + jQuery.contains( doc, node ) ) { + + if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) { + + // Optional AJAX dependency, but won't run scripts if not present + if ( jQuery._evalUrl && !node.noModule ) { + jQuery._evalUrl( node.src, { + nonce: node.nonce || node.getAttribute( "nonce" ) + }, doc ); + } + } else { + DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc ); + } + } + } + } + } + } + + return collection; +} + +function remove( elem, selector, keepData ) { + var node, + nodes = selector ? jQuery.filter( selector, elem ) : elem, + i = 0; + + for ( ; ( node = nodes[ i ] ) != null; i++ ) { + if ( !keepData && node.nodeType === 1 ) { + jQuery.cleanData( getAll( node ) ); + } + + if ( node.parentNode ) { + if ( keepData && isAttached( node ) ) { + setGlobalEval( getAll( node, "script" ) ); + } + node.parentNode.removeChild( node ); + } + } + + return elem; +} + +jQuery.extend( { + htmlPrefilter: function( html ) { + return html; + }, + + clone: function( elem, dataAndEvents, deepDataAndEvents ) { + var i, l, srcElements, destElements, + clone = elem.cloneNode( true ), + inPage = isAttached( elem ); + + // Fix IE cloning issues + if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) && + !jQuery.isXMLDoc( elem ) ) { + + // We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2 + destElements = getAll( clone ); + srcElements = getAll( elem ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + fixInput( srcElements[ i ], destElements[ i ] ); + } + } + + // Copy the events from the original to the clone + if ( dataAndEvents ) { + if ( deepDataAndEvents ) { + srcElements = srcElements || getAll( elem ); + destElements = destElements || getAll( clone ); + + for ( i = 0, l = srcElements.length; i < l; i++ ) { + cloneCopyEvent( srcElements[ i ], destElements[ i ] ); + } + } else { + cloneCopyEvent( elem, clone ); + } + } + + // Preserve script evaluation history + destElements = getAll( clone, "script" ); + if ( destElements.length > 0 ) { + setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); + } + + // Return the cloned set + return clone; + }, + + cleanData: function( elems ) { + var data, elem, type, + special = jQuery.event.special, + i = 0; + + for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) { + if ( acceptData( elem ) ) { + if ( ( data = elem[ dataPriv.expando ] ) ) { + if ( data.events ) { + for ( type in data.events ) { + if ( special[ type ] ) { + jQuery.event.remove( elem, type ); + + // This is a shortcut to avoid jQuery.event.remove's overhead + } else { + jQuery.removeEvent( elem, type, data.handle ); + } + } + } + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataPriv.expando ] = undefined; + } + if ( elem[ dataUser.expando ] ) { + + // Support: Chrome <=35 - 45+ + // Assign undefined instead of using delete, see Data#remove + elem[ dataUser.expando ] = undefined; + } + } + } + } +} ); + +jQuery.fn.extend( { + detach: function( selector ) { + return remove( this, selector, true ); + }, + + remove: function( selector ) { + return remove( this, selector ); + }, + + text: function( value ) { + return access( this, function( value ) { + return value === undefined ? + jQuery.text( this ) : + this.empty().each( function() { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + this.textContent = value; + } + } ); + }, null, value, arguments.length ); + }, + + append: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.appendChild( elem ); + } + } ); + }, + + prepend: function() { + return domManip( this, arguments, function( elem ) { + if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { + var target = manipulationTarget( this, elem ); + target.insertBefore( elem, target.firstChild ); + } + } ); + }, + + before: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this ); + } + } ); + }, + + after: function() { + return domManip( this, arguments, function( elem ) { + if ( this.parentNode ) { + this.parentNode.insertBefore( elem, this.nextSibling ); + } + } ); + }, + + empty: function() { + var elem, + i = 0; + + for ( ; ( elem = this[ i ] ) != null; i++ ) { + if ( elem.nodeType === 1 ) { + + // Prevent memory leaks + jQuery.cleanData( getAll( elem, false ) ); + + // Remove any remaining nodes + elem.textContent = ""; + } + } + + return this; + }, + + clone: function( dataAndEvents, deepDataAndEvents ) { + dataAndEvents = dataAndEvents == null ? false : dataAndEvents; + deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; + + return this.map( function() { + return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); + } ); + }, + + html: function( value ) { + return access( this, function( value ) { + var elem = this[ 0 ] || {}, + i = 0, + l = this.length; + + if ( value === undefined && elem.nodeType === 1 ) { + return elem.innerHTML; + } + + // See if we can take a shortcut and just use innerHTML + if ( typeof value === "string" && !rnoInnerhtml.test( value ) && + !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { + + value = jQuery.htmlPrefilter( value ); + + try { + for ( ; i < l; i++ ) { + elem = this[ i ] || {}; + + // Remove element nodes and prevent memory leaks + if ( elem.nodeType === 1 ) { + jQuery.cleanData( getAll( elem, false ) ); + elem.innerHTML = value; + } + } + + elem = 0; + + // If using innerHTML throws an exception, use the fallback method + } catch ( e ) {} + } + + if ( elem ) { + this.empty().append( value ); + } + }, null, value, arguments.length ); + }, + + replaceWith: function() { + var ignored = []; + + // Make the changes, replacing each non-ignored context element with the new content + return domManip( this, arguments, function( elem ) { + var parent = this.parentNode; + + if ( jQuery.inArray( this, ignored ) < 0 ) { + jQuery.cleanData( getAll( this ) ); + if ( parent ) { + parent.replaceChild( elem, this ); + } + } + + // Force callback invocation + }, ignored ); + } +} ); + +jQuery.each( { + appendTo: "append", + prependTo: "prepend", + insertBefore: "before", + insertAfter: "after", + replaceAll: "replaceWith" +}, function( name, original ) { + jQuery.fn[ name ] = function( selector ) { + var elems, + ret = [], + insert = jQuery( selector ), + last = insert.length - 1, + i = 0; + + for ( ; i <= last; i++ ) { + elems = i === last ? this : this.clone( true ); + jQuery( insert[ i ] )[ original ]( elems ); + + // Support: Android <=4.0 only, PhantomJS 1 only + // .get() because push.apply(_, arraylike) throws on ancient WebKit + push.apply( ret, elems.get() ); + } + + return this.pushStack( ret ); + }; +} ); +var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" ); + +var getStyles = function( elem ) { + + // Support: IE <=11 only, Firefox <=30 (#15098, #14150) + // IE throws on elements created in popups + // FF meanwhile throws on frame elements through "defaultView.getComputedStyle" + var view = elem.ownerDocument.defaultView; + + if ( !view || !view.opener ) { + view = window; + } + + return view.getComputedStyle( elem ); + }; + +var swap = function( elem, options, callback ) { + var ret, name, + old = {}; + + // Remember the old values, and insert the new ones + for ( name in options ) { + old[ name ] = elem.style[ name ]; + elem.style[ name ] = options[ name ]; + } + + ret = callback.call( elem ); + + // Revert the old values + for ( name in options ) { + elem.style[ name ] = old[ name ]; + } + + return ret; +}; + + +var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" ); + + + +( function() { + + // Executing both pixelPosition & boxSizingReliable tests require only one layout + // so they're executed at the same time to save the second computation. + function computeStyleTests() { + + // This is a singleton, we need to execute it only once + if ( !div ) { + return; + } + + container.style.cssText = "position:absolute;left:-11111px;width:60px;" + + "margin-top:1px;padding:0;border:0"; + div.style.cssText = + "position:relative;display:block;box-sizing:border-box;overflow:scroll;" + + "margin:auto;border:1px;padding:1px;" + + "width:60%;top:1%"; + documentElement.appendChild( container ).appendChild( div ); + + var divStyle = window.getComputedStyle( div ); + pixelPositionVal = divStyle.top !== "1%"; + + // Support: Android 4.0 - 4.3 only, Firefox <=3 - 44 + reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12; + + // Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3 + // Some styles come back with percentage values, even though they shouldn't + div.style.right = "60%"; + pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36; + + // Support: IE 9 - 11 only + // Detect misreporting of content dimensions for box-sizing:border-box elements + boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36; + + // Support: IE 9 only + // Detect overflow:scroll screwiness (gh-3699) + // Support: Chrome <=64 + // Don't get tricked when zoom affects offsetWidth (gh-4029) + div.style.position = "absolute"; + scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12; + + documentElement.removeChild( container ); + + // Nullify the div so it wouldn't be stored in the memory and + // it will also be a sign that checks already performed + div = null; + } + + function roundPixelMeasures( measure ) { + return Math.round( parseFloat( measure ) ); + } + + var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal, + reliableTrDimensionsVal, reliableMarginLeftVal, + container = document.createElement( "div" ), + div = document.createElement( "div" ); + + // Finish early in limited (non-browser) environments + if ( !div.style ) { + return; + } + + // Support: IE <=9 - 11 only + // Style of cloned element affects source element cloned (#8908) + div.style.backgroundClip = "content-box"; + div.cloneNode( true ).style.backgroundClip = ""; + support.clearCloneStyle = div.style.backgroundClip === "content-box"; + + jQuery.extend( support, { + boxSizingReliable: function() { + computeStyleTests(); + return boxSizingReliableVal; + }, + pixelBoxStyles: function() { + computeStyleTests(); + return pixelBoxStylesVal; + }, + pixelPosition: function() { + computeStyleTests(); + return pixelPositionVal; + }, + reliableMarginLeft: function() { + computeStyleTests(); + return reliableMarginLeftVal; + }, + scrollboxSize: function() { + computeStyleTests(); + return scrollboxSizeVal; + }, + + // Support: IE 9 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Behavior in IE 9 is more subtle than in newer versions & it passes + // some versions of this test; make sure not to make it pass there! + reliableTrDimensions: function() { + var table, tr, trChild, trStyle; + if ( reliableTrDimensionsVal == null ) { + table = document.createElement( "table" ); + tr = document.createElement( "tr" ); + trChild = document.createElement( "div" ); + + table.style.cssText = "position:absolute;left:-11111px"; + tr.style.height = "1px"; + trChild.style.height = "9px"; + + documentElement + .appendChild( table ) + .appendChild( tr ) + .appendChild( trChild ); + + trStyle = window.getComputedStyle( tr ); + reliableTrDimensionsVal = parseInt( trStyle.height ) > 3; + + documentElement.removeChild( table ); + } + return reliableTrDimensionsVal; + } + } ); +} )(); + + +function curCSS( elem, name, computed ) { + var width, minWidth, maxWidth, ret, + + // Support: Firefox 51+ + // Retrieving style before computed somehow + // fixes an issue with getting wrong values + // on detached elements + style = elem.style; + + computed = computed || getStyles( elem ); + + // getPropertyValue is needed for: + // .css('filter') (IE 9 only, #12537) + // .css('--customProperty) (#3144) + if ( computed ) { + ret = computed.getPropertyValue( name ) || computed[ name ]; + + if ( ret === "" && !isAttached( elem ) ) { + ret = jQuery.style( elem, name ); + } + + // A tribute to the "awesome hack by Dean Edwards" + // Android Browser returns percentage for some values, + // but width seems to be reliably pixels. + // This is against the CSSOM draft spec: + // https://drafts.csswg.org/cssom/#resolved-values + if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) { + + // Remember the original values + width = style.width; + minWidth = style.minWidth; + maxWidth = style.maxWidth; + + // Put in the new values to get a computed value out + style.minWidth = style.maxWidth = style.width = ret; + ret = computed.width; + + // Revert the changed values + style.width = width; + style.minWidth = minWidth; + style.maxWidth = maxWidth; + } + } + + return ret !== undefined ? + + // Support: IE <=9 - 11 only + // IE returns zIndex value as an integer. + ret + "" : + ret; +} + + +function addGetHookIf( conditionFn, hookFn ) { + + // Define the hook, we'll check on the first run if it's really needed. + return { + get: function() { + if ( conditionFn() ) { + + // Hook not needed (or it's not possible to use it due + // to missing dependency), remove it. + delete this.get; + return; + } + + // Hook needed; redefine it so that the support test is not executed again. + return ( this.get = hookFn ).apply( this, arguments ); + } + }; +} + + +var cssPrefixes = [ "Webkit", "Moz", "ms" ], + emptyStyle = document.createElement( "div" ).style, + vendorProps = {}; + +// Return a vendor-prefixed property or undefined +function vendorPropName( name ) { + + // Check for vendor prefixed names + var capName = name[ 0 ].toUpperCase() + name.slice( 1 ), + i = cssPrefixes.length; + + while ( i-- ) { + name = cssPrefixes[ i ] + capName; + if ( name in emptyStyle ) { + return name; + } + } +} + +// Return a potentially-mapped jQuery.cssProps or vendor prefixed property +function finalPropName( name ) { + var final = jQuery.cssProps[ name ] || vendorProps[ name ]; + + if ( final ) { + return final; + } + if ( name in emptyStyle ) { + return name; + } + return vendorProps[ name ] = vendorPropName( name ) || name; +} + + +var + + // Swappable if display is none or starts with table + // except "table", "table-cell", or "table-caption" + // See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display + rdisplayswap = /^(none|table(?!-c[ea]).+)/, + rcustomProp = /^--/, + cssShow = { position: "absolute", visibility: "hidden", display: "block" }, + cssNormalTransform = { + letterSpacing: "0", + fontWeight: "400" + }; + +function setPositiveNumber( _elem, value, subtract ) { + + // Any relative (+/-) values have already been + // normalized at this point + var matches = rcssNum.exec( value ); + return matches ? + + // Guard against undefined "subtract", e.g., when used as in cssHooks + Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) : + value; +} + +function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) { + var i = dimension === "width" ? 1 : 0, + extra = 0, + delta = 0; + + // Adjustment may not be necessary + if ( box === ( isBorderBox ? "border" : "content" ) ) { + return 0; + } + + for ( ; i < 4; i += 2 ) { + + // Both box models exclude margin + if ( box === "margin" ) { + delta += jQuery.css( elem, box + cssExpand[ i ], true, styles ); + } + + // If we get here with a content-box, we're seeking "padding" or "border" or "margin" + if ( !isBorderBox ) { + + // Add padding + delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + + // For "border" or "margin", add border + if ( box !== "padding" ) { + delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + + // But still keep track of it otherwise + } else { + extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + + // If we get here with a border-box (content + padding + border), we're seeking "content" or + // "padding" or "margin" + } else { + + // For "content", subtract padding + if ( box === "content" ) { + delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles ); + } + + // For "content" or "padding", subtract border + if ( box !== "margin" ) { + delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles ); + } + } + } + + // Account for positive content-box scroll gutter when requested by providing computedVal + if ( !isBorderBox && computedVal >= 0 ) { + + // offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border + // Assuming integer scroll gutter, subtract the rest and round down + delta += Math.max( 0, Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + computedVal - + delta - + extra - + 0.5 + + // If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter + // Use an explicit zero to avoid NaN (gh-3964) + ) ) || 0; + } + + return delta; +} + +function getWidthOrHeight( elem, dimension, extra ) { + + // Start with computed style + var styles = getStyles( elem ), + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322). + // Fake content-box until we know it's needed to know the true value. + boxSizingNeeded = !support.boxSizingReliable() || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + valueIsBorderBox = isBorderBox, + + val = curCSS( elem, dimension, styles ), + offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ); + + // Support: Firefox <=54 + // Return a confounding non-pixel value or feign ignorance, as appropriate. + if ( rnumnonpx.test( val ) ) { + if ( !extra ) { + return val; + } + val = "auto"; + } + + + // Support: IE 9 - 11 only + // Use offsetWidth/offsetHeight for when box sizing is unreliable. + // In those cases, the computed value can be trusted to be border-box. + if ( ( !support.boxSizingReliable() && isBorderBox || + + // Support: IE 10 - 11+, Edge 15 - 18+ + // IE/Edge misreport `getComputedStyle` of table rows with width/height + // set in CSS while `offset*` properties report correct values. + // Interestingly, in some cases IE 9 doesn't suffer from this issue. + !support.reliableTrDimensions() && nodeName( elem, "tr" ) || + + // Fall back to offsetWidth/offsetHeight when value is "auto" + // This happens for inline elements with no explicit setting (gh-3571) + val === "auto" || + + // Support: Android <=4.1 - 4.3 only + // Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602) + !parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) && + + // Make sure the element is visible & connected + elem.getClientRects().length ) { + + isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box"; + + // Where available, offsetWidth/offsetHeight approximate border box dimensions. + // Where not available (e.g., SVG), assume unreliable box-sizing and interpret the + // retrieved value as a content box dimension. + valueIsBorderBox = offsetProp in elem; + if ( valueIsBorderBox ) { + val = elem[ offsetProp ]; + } + } + + // Normalize "" and auto + val = parseFloat( val ) || 0; + + // Adjust for the element's box model + return ( val + + boxModelAdjustment( + elem, + dimension, + extra || ( isBorderBox ? "border" : "content" ), + valueIsBorderBox, + styles, + + // Provide the current computed size to request scroll gutter calculation (gh-3589) + val + ) + ) + "px"; +} + +jQuery.extend( { + + // Add in style property hooks for overriding the default + // behavior of getting and setting a style property + cssHooks: { + opacity: { + get: function( elem, computed ) { + if ( computed ) { + + // We should always get a number back from opacity + var ret = curCSS( elem, "opacity" ); + return ret === "" ? "1" : ret; + } + } + } + }, + + // Don't automatically add "px" to these possibly-unitless properties + cssNumber: { + "animationIterationCount": true, + "columnCount": true, + "fillOpacity": true, + "flexGrow": true, + "flexShrink": true, + "fontWeight": true, + "gridArea": true, + "gridColumn": true, + "gridColumnEnd": true, + "gridColumnStart": true, + "gridRow": true, + "gridRowEnd": true, + "gridRowStart": true, + "lineHeight": true, + "opacity": true, + "order": true, + "orphans": true, + "widows": true, + "zIndex": true, + "zoom": true + }, + + // Add in properties whose names you wish to fix before + // setting or getting the value + cssProps: {}, + + // Get and set the style property on a DOM Node + style: function( elem, name, value, extra ) { + + // Don't set styles on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) { + return; + } + + // Make sure that we're working with the right name + var ret, type, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ), + style = elem.style; + + // Make sure that we're working with the right name. We don't + // want to query the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Gets hook for the prefixed version, then unprefixed version + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // Check if we're setting a value + if ( value !== undefined ) { + type = typeof value; + + // Convert "+=" or "-=" to relative numbers (#7345) + if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) { + value = adjustCSS( elem, name, ret ); + + // Fixes bug #9237 + type = "number"; + } + + // Make sure that null and NaN values aren't set (#7116) + if ( value == null || value !== value ) { + return; + } + + // If a number was passed in, add the unit (except for certain CSS properties) + // The isCustomProp check can be removed in jQuery 4.0 when we only auto-append + // "px" to a few hardcoded values. + if ( type === "number" && !isCustomProp ) { + value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" ); + } + + // background-* props affect original clone's values + if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) { + style[ name ] = "inherit"; + } + + // If a hook was provided, use that value, otherwise just set the specified value + if ( !hooks || !( "set" in hooks ) || + ( value = hooks.set( elem, value, extra ) ) !== undefined ) { + + if ( isCustomProp ) { + style.setProperty( name, value ); + } else { + style[ name ] = value; + } + } + + } else { + + // If a hook was provided get the non-computed value from there + if ( hooks && "get" in hooks && + ( ret = hooks.get( elem, false, extra ) ) !== undefined ) { + + return ret; + } + + // Otherwise just get the value from the style object + return style[ name ]; + } + }, + + css: function( elem, name, extra, styles ) { + var val, num, hooks, + origName = camelCase( name ), + isCustomProp = rcustomProp.test( name ); + + // Make sure that we're working with the right name. We don't + // want to modify the value if it is a CSS custom property + // since they are user-defined. + if ( !isCustomProp ) { + name = finalPropName( origName ); + } + + // Try prefixed name followed by the unprefixed name + hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ]; + + // If a hook was provided get the computed value from there + if ( hooks && "get" in hooks ) { + val = hooks.get( elem, true, extra ); + } + + // Otherwise, if a way to get the computed value exists, use that + if ( val === undefined ) { + val = curCSS( elem, name, styles ); + } + + // Convert "normal" to computed value + if ( val === "normal" && name in cssNormalTransform ) { + val = cssNormalTransform[ name ]; + } + + // Make numeric if forced or a qualifier was provided and val looks numeric + if ( extra === "" || extra ) { + num = parseFloat( val ); + return extra === true || isFinite( num ) ? num || 0 : val; + } + + return val; + } +} ); + +jQuery.each( [ "height", "width" ], function( _i, dimension ) { + jQuery.cssHooks[ dimension ] = { + get: function( elem, computed, extra ) { + if ( computed ) { + + // Certain elements can have dimension info if we invisibly show them + // but it must have a current display style that would benefit + return rdisplayswap.test( jQuery.css( elem, "display" ) ) && + + // Support: Safari 8+ + // Table columns in Safari have non-zero offsetWidth & zero + // getBoundingClientRect().width unless display is changed. + // Support: IE <=11 only + // Running getBoundingClientRect on a disconnected node + // in IE throws an error. + ( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ? + swap( elem, cssShow, function() { + return getWidthOrHeight( elem, dimension, extra ); + } ) : + getWidthOrHeight( elem, dimension, extra ); + } + }, + + set: function( elem, value, extra ) { + var matches, + styles = getStyles( elem ), + + // Only read styles.position if the test has a chance to fail + // to avoid forcing a reflow. + scrollboxSizeBuggy = !support.scrollboxSize() && + styles.position === "absolute", + + // To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991) + boxSizingNeeded = scrollboxSizeBuggy || extra, + isBorderBox = boxSizingNeeded && + jQuery.css( elem, "boxSizing", false, styles ) === "border-box", + subtract = extra ? + boxModelAdjustment( + elem, + dimension, + extra, + isBorderBox, + styles + ) : + 0; + + // Account for unreliable border-box dimensions by comparing offset* to computed and + // faking a content-box to get border and padding (gh-3699) + if ( isBorderBox && scrollboxSizeBuggy ) { + subtract -= Math.ceil( + elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] - + parseFloat( styles[ dimension ] ) - + boxModelAdjustment( elem, dimension, "border", false, styles ) - + 0.5 + ); + } + + // Convert to pixels if value adjustment is needed + if ( subtract && ( matches = rcssNum.exec( value ) ) && + ( matches[ 3 ] || "px" ) !== "px" ) { + + elem.style[ dimension ] = value; + value = jQuery.css( elem, dimension ); + } + + return setPositiveNumber( elem, value, subtract ); + } + }; +} ); + +jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft, + function( elem, computed ) { + if ( computed ) { + return ( parseFloat( curCSS( elem, "marginLeft" ) ) || + elem.getBoundingClientRect().left - + swap( elem, { marginLeft: 0 }, function() { + return elem.getBoundingClientRect().left; + } ) + ) + "px"; + } + } +); + +// These hooks are used by animate to expand properties +jQuery.each( { + margin: "", + padding: "", + border: "Width" +}, function( prefix, suffix ) { + jQuery.cssHooks[ prefix + suffix ] = { + expand: function( value ) { + var i = 0, + expanded = {}, + + // Assumes a single number if not a string + parts = typeof value === "string" ? value.split( " " ) : [ value ]; + + for ( ; i < 4; i++ ) { + expanded[ prefix + cssExpand[ i ] + suffix ] = + parts[ i ] || parts[ i - 2 ] || parts[ 0 ]; + } + + return expanded; + } + }; + + if ( prefix !== "margin" ) { + jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber; + } +} ); + +jQuery.fn.extend( { + css: function( name, value ) { + return access( this, function( elem, name, value ) { + var styles, len, + map = {}, + i = 0; + + if ( Array.isArray( name ) ) { + styles = getStyles( elem ); + len = name.length; + + for ( ; i < len; i++ ) { + map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles ); + } + + return map; + } + + return value !== undefined ? + jQuery.style( elem, name, value ) : + jQuery.css( elem, name ); + }, name, value, arguments.length > 1 ); + } +} ); + + +function Tween( elem, options, prop, end, easing ) { + return new Tween.prototype.init( elem, options, prop, end, easing ); +} +jQuery.Tween = Tween; + +Tween.prototype = { + constructor: Tween, + init: function( elem, options, prop, end, easing, unit ) { + this.elem = elem; + this.prop = prop; + this.easing = easing || jQuery.easing._default; + this.options = options; + this.start = this.now = this.cur(); + this.end = end; + this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" ); + }, + cur: function() { + var hooks = Tween.propHooks[ this.prop ]; + + return hooks && hooks.get ? + hooks.get( this ) : + Tween.propHooks._default.get( this ); + }, + run: function( percent ) { + var eased, + hooks = Tween.propHooks[ this.prop ]; + + if ( this.options.duration ) { + this.pos = eased = jQuery.easing[ this.easing ]( + percent, this.options.duration * percent, 0, 1, this.options.duration + ); + } else { + this.pos = eased = percent; + } + this.now = ( this.end - this.start ) * eased + this.start; + + if ( this.options.step ) { + this.options.step.call( this.elem, this.now, this ); + } + + if ( hooks && hooks.set ) { + hooks.set( this ); + } else { + Tween.propHooks._default.set( this ); + } + return this; + } +}; + +Tween.prototype.init.prototype = Tween.prototype; + +Tween.propHooks = { + _default: { + get: function( tween ) { + var result; + + // Use a property on the element directly when it is not a DOM element, + // or when there is no matching style property that exists. + if ( tween.elem.nodeType !== 1 || + tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) { + return tween.elem[ tween.prop ]; + } + + // Passing an empty string as a 3rd parameter to .css will automatically + // attempt a parseFloat and fallback to a string if the parse fails. + // Simple values such as "10px" are parsed to Float; + // complex values such as "rotate(1rad)" are returned as-is. + result = jQuery.css( tween.elem, tween.prop, "" ); + + // Empty strings, null, undefined and "auto" are converted to 0. + return !result || result === "auto" ? 0 : result; + }, + set: function( tween ) { + + // Use step hook for back compat. + // Use cssHook if its there. + // Use .style if available and use plain properties where available. + if ( jQuery.fx.step[ tween.prop ] ) { + jQuery.fx.step[ tween.prop ]( tween ); + } else if ( tween.elem.nodeType === 1 && ( + jQuery.cssHooks[ tween.prop ] || + tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) { + jQuery.style( tween.elem, tween.prop, tween.now + tween.unit ); + } else { + tween.elem[ tween.prop ] = tween.now; + } + } + } +}; + +// Support: IE <=9 only +// Panic based approach to setting things on disconnected nodes +Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = { + set: function( tween ) { + if ( tween.elem.nodeType && tween.elem.parentNode ) { + tween.elem[ tween.prop ] = tween.now; + } + } +}; + +jQuery.easing = { + linear: function( p ) { + return p; + }, + swing: function( p ) { + return 0.5 - Math.cos( p * Math.PI ) / 2; + }, + _default: "swing" +}; + +jQuery.fx = Tween.prototype.init; + +// Back compat <1.8 extension point +jQuery.fx.step = {}; + + + + +var + fxNow, inProgress, + rfxtypes = /^(?:toggle|show|hide)$/, + rrun = /queueHooks$/; + +function schedule() { + if ( inProgress ) { + if ( document.hidden === false && window.requestAnimationFrame ) { + window.requestAnimationFrame( schedule ); + } else { + window.setTimeout( schedule, jQuery.fx.interval ); + } + + jQuery.fx.tick(); + } +} + +// Animations created synchronously will run synchronously +function createFxNow() { + window.setTimeout( function() { + fxNow = undefined; + } ); + return ( fxNow = Date.now() ); +} + +// Generate parameters to create a standard animation +function genFx( type, includeWidth ) { + var which, + i = 0, + attrs = { height: type }; + + // If we include width, step value is 1 to do all cssExpand values, + // otherwise step value is 2 to skip over Left and Right + includeWidth = includeWidth ? 1 : 0; + for ( ; i < 4; i += 2 - includeWidth ) { + which = cssExpand[ i ]; + attrs[ "margin" + which ] = attrs[ "padding" + which ] = type; + } + + if ( includeWidth ) { + attrs.opacity = attrs.width = type; + } + + return attrs; +} + +function createTween( value, prop, animation ) { + var tween, + collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ), + index = 0, + length = collection.length; + for ( ; index < length; index++ ) { + if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) { + + // We're done with this property + return tween; + } + } +} + +function defaultPrefilter( elem, props, opts ) { + var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display, + isBox = "width" in props || "height" in props, + anim = this, + orig = {}, + style = elem.style, + hidden = elem.nodeType && isHiddenWithinTree( elem ), + dataShow = dataPriv.get( elem, "fxshow" ); + + // Queue-skipping animations hijack the fx hooks + if ( !opts.queue ) { + hooks = jQuery._queueHooks( elem, "fx" ); + if ( hooks.unqueued == null ) { + hooks.unqueued = 0; + oldfire = hooks.empty.fire; + hooks.empty.fire = function() { + if ( !hooks.unqueued ) { + oldfire(); + } + }; + } + hooks.unqueued++; + + anim.always( function() { + + // Ensure the complete handler is called before this completes + anim.always( function() { + hooks.unqueued--; + if ( !jQuery.queue( elem, "fx" ).length ) { + hooks.empty.fire(); + } + } ); + } ); + } + + // Detect show/hide animations + for ( prop in props ) { + value = props[ prop ]; + if ( rfxtypes.test( value ) ) { + delete props[ prop ]; + toggle = toggle || value === "toggle"; + if ( value === ( hidden ? "hide" : "show" ) ) { + + // Pretend to be hidden if this is a "show" and + // there is still data from a stopped show/hide + if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) { + hidden = true; + + // Ignore all other no-op show/hide data + } else { + continue; + } + } + orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop ); + } + } + + // Bail out if this is a no-op like .hide().hide() + propTween = !jQuery.isEmptyObject( props ); + if ( !propTween && jQuery.isEmptyObject( orig ) ) { + return; + } + + // Restrict "overflow" and "display" styles during box animations + if ( isBox && elem.nodeType === 1 ) { + + // Support: IE <=9 - 11, Edge 12 - 15 + // Record all 3 overflow attributes because IE does not infer the shorthand + // from identically-valued overflowX and overflowY and Edge just mirrors + // the overflowX value there. + opts.overflow = [ style.overflow, style.overflowX, style.overflowY ]; + + // Identify a display type, preferring old show/hide data over the CSS cascade + restoreDisplay = dataShow && dataShow.display; + if ( restoreDisplay == null ) { + restoreDisplay = dataPriv.get( elem, "display" ); + } + display = jQuery.css( elem, "display" ); + if ( display === "none" ) { + if ( restoreDisplay ) { + display = restoreDisplay; + } else { + + // Get nonempty value(s) by temporarily forcing visibility + showHide( [ elem ], true ); + restoreDisplay = elem.style.display || restoreDisplay; + display = jQuery.css( elem, "display" ); + showHide( [ elem ] ); + } + } + + // Animate inline elements as inline-block + if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) { + if ( jQuery.css( elem, "float" ) === "none" ) { + + // Restore the original display value at the end of pure show/hide animations + if ( !propTween ) { + anim.done( function() { + style.display = restoreDisplay; + } ); + if ( restoreDisplay == null ) { + display = style.display; + restoreDisplay = display === "none" ? "" : display; + } + } + style.display = "inline-block"; + } + } + } + + if ( opts.overflow ) { + style.overflow = "hidden"; + anim.always( function() { + style.overflow = opts.overflow[ 0 ]; + style.overflowX = opts.overflow[ 1 ]; + style.overflowY = opts.overflow[ 2 ]; + } ); + } + + // Implement show/hide animations + propTween = false; + for ( prop in orig ) { + + // General show/hide setup for this element animation + if ( !propTween ) { + if ( dataShow ) { + if ( "hidden" in dataShow ) { + hidden = dataShow.hidden; + } + } else { + dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } ); + } + + // Store hidden/visible for toggle so `.stop().toggle()` "reverses" + if ( toggle ) { + dataShow.hidden = !hidden; + } + + // Show elements before animating them + if ( hidden ) { + showHide( [ elem ], true ); + } + + /* eslint-disable no-loop-func */ + + anim.done( function() { + + /* eslint-enable no-loop-func */ + + // The final step of a "hide" animation is actually hiding the element + if ( !hidden ) { + showHide( [ elem ] ); + } + dataPriv.remove( elem, "fxshow" ); + for ( prop in orig ) { + jQuery.style( elem, prop, orig[ prop ] ); + } + } ); + } + + // Per-property setup + propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim ); + if ( !( prop in dataShow ) ) { + dataShow[ prop ] = propTween.start; + if ( hidden ) { + propTween.end = propTween.start; + propTween.start = 0; + } + } + } +} + +function propFilter( props, specialEasing ) { + var index, name, easing, value, hooks; + + // camelCase, specialEasing and expand cssHook pass + for ( index in props ) { + name = camelCase( index ); + easing = specialEasing[ name ]; + value = props[ index ]; + if ( Array.isArray( value ) ) { + easing = value[ 1 ]; + value = props[ index ] = value[ 0 ]; + } + + if ( index !== name ) { + props[ name ] = value; + delete props[ index ]; + } + + hooks = jQuery.cssHooks[ name ]; + if ( hooks && "expand" in hooks ) { + value = hooks.expand( value ); + delete props[ name ]; + + // Not quite $.extend, this won't overwrite existing keys. + // Reusing 'index' because we have the correct "name" + for ( index in value ) { + if ( !( index in props ) ) { + props[ index ] = value[ index ]; + specialEasing[ index ] = easing; + } + } + } else { + specialEasing[ name ] = easing; + } + } +} + +function Animation( elem, properties, options ) { + var result, + stopped, + index = 0, + length = Animation.prefilters.length, + deferred = jQuery.Deferred().always( function() { + + // Don't match elem in the :animated selector + delete tick.elem; + } ), + tick = function() { + if ( stopped ) { + return false; + } + var currentTime = fxNow || createFxNow(), + remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ), + + // Support: Android 2.3 only + // Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497) + temp = remaining / animation.duration || 0, + percent = 1 - temp, + index = 0, + length = animation.tweens.length; + + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( percent ); + } + + deferred.notifyWith( elem, [ animation, percent, remaining ] ); + + // If there's more to do, yield + if ( percent < 1 && length ) { + return remaining; + } + + // If this was an empty animation, synthesize a final progress notification + if ( !length ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + } + + // Resolve the animation and report its conclusion + deferred.resolveWith( elem, [ animation ] ); + return false; + }, + animation = deferred.promise( { + elem: elem, + props: jQuery.extend( {}, properties ), + opts: jQuery.extend( true, { + specialEasing: {}, + easing: jQuery.easing._default + }, options ), + originalProperties: properties, + originalOptions: options, + startTime: fxNow || createFxNow(), + duration: options.duration, + tweens: [], + createTween: function( prop, end ) { + var tween = jQuery.Tween( elem, animation.opts, prop, end, + animation.opts.specialEasing[ prop ] || animation.opts.easing ); + animation.tweens.push( tween ); + return tween; + }, + stop: function( gotoEnd ) { + var index = 0, + + // If we are going to the end, we want to run all the tweens + // otherwise we skip this part + length = gotoEnd ? animation.tweens.length : 0; + if ( stopped ) { + return this; + } + stopped = true; + for ( ; index < length; index++ ) { + animation.tweens[ index ].run( 1 ); + } + + // Resolve when we played the last frame; otherwise, reject + if ( gotoEnd ) { + deferred.notifyWith( elem, [ animation, 1, 0 ] ); + deferred.resolveWith( elem, [ animation, gotoEnd ] ); + } else { + deferred.rejectWith( elem, [ animation, gotoEnd ] ); + } + return this; + } + } ), + props = animation.props; + + propFilter( props, animation.opts.specialEasing ); + + for ( ; index < length; index++ ) { + result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts ); + if ( result ) { + if ( isFunction( result.stop ) ) { + jQuery._queueHooks( animation.elem, animation.opts.queue ).stop = + result.stop.bind( result ); + } + return result; + } + } + + jQuery.map( props, createTween, animation ); + + if ( isFunction( animation.opts.start ) ) { + animation.opts.start.call( elem, animation ); + } + + // Attach callbacks from options + animation + .progress( animation.opts.progress ) + .done( animation.opts.done, animation.opts.complete ) + .fail( animation.opts.fail ) + .always( animation.opts.always ); + + jQuery.fx.timer( + jQuery.extend( tick, { + elem: elem, + anim: animation, + queue: animation.opts.queue + } ) + ); + + return animation; +} + +jQuery.Animation = jQuery.extend( Animation, { + + tweeners: { + "*": [ function( prop, value ) { + var tween = this.createTween( prop, value ); + adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween ); + return tween; + } ] + }, + + tweener: function( props, callback ) { + if ( isFunction( props ) ) { + callback = props; + props = [ "*" ]; + } else { + props = props.match( rnothtmlwhite ); + } + + var prop, + index = 0, + length = props.length; + + for ( ; index < length; index++ ) { + prop = props[ index ]; + Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || []; + Animation.tweeners[ prop ].unshift( callback ); + } + }, + + prefilters: [ defaultPrefilter ], + + prefilter: function( callback, prepend ) { + if ( prepend ) { + Animation.prefilters.unshift( callback ); + } else { + Animation.prefilters.push( callback ); + } + } +} ); + +jQuery.speed = function( speed, easing, fn ) { + var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : { + complete: fn || !fn && easing || + isFunction( speed ) && speed, + duration: speed, + easing: fn && easing || easing && !isFunction( easing ) && easing + }; + + // Go to the end state if fx are off + if ( jQuery.fx.off ) { + opt.duration = 0; + + } else { + if ( typeof opt.duration !== "number" ) { + if ( opt.duration in jQuery.fx.speeds ) { + opt.duration = jQuery.fx.speeds[ opt.duration ]; + + } else { + opt.duration = jQuery.fx.speeds._default; + } + } + } + + // Normalize opt.queue - true/undefined/null -> "fx" + if ( opt.queue == null || opt.queue === true ) { + opt.queue = "fx"; + } + + // Queueing + opt.old = opt.complete; + + opt.complete = function() { + if ( isFunction( opt.old ) ) { + opt.old.call( this ); + } + + if ( opt.queue ) { + jQuery.dequeue( this, opt.queue ); + } + }; + + return opt; +}; + +jQuery.fn.extend( { + fadeTo: function( speed, to, easing, callback ) { + + // Show any hidden elements after setting opacity to 0 + return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show() + + // Animate to the value specified + .end().animate( { opacity: to }, speed, easing, callback ); + }, + animate: function( prop, speed, easing, callback ) { + var empty = jQuery.isEmptyObject( prop ), + optall = jQuery.speed( speed, easing, callback ), + doAnimation = function() { + + // Operate on a copy of prop so per-property easing won't be lost + var anim = Animation( this, jQuery.extend( {}, prop ), optall ); + + // Empty animations, or finishing resolves immediately + if ( empty || dataPriv.get( this, "finish" ) ) { + anim.stop( true ); + } + }; + doAnimation.finish = doAnimation; + + return empty || optall.queue === false ? + this.each( doAnimation ) : + this.queue( optall.queue, doAnimation ); + }, + stop: function( type, clearQueue, gotoEnd ) { + var stopQueue = function( hooks ) { + var stop = hooks.stop; + delete hooks.stop; + stop( gotoEnd ); + }; + + if ( typeof type !== "string" ) { + gotoEnd = clearQueue; + clearQueue = type; + type = undefined; + } + if ( clearQueue ) { + this.queue( type || "fx", [] ); + } + + return this.each( function() { + var dequeue = true, + index = type != null && type + "queueHooks", + timers = jQuery.timers, + data = dataPriv.get( this ); + + if ( index ) { + if ( data[ index ] && data[ index ].stop ) { + stopQueue( data[ index ] ); + } + } else { + for ( index in data ) { + if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) { + stopQueue( data[ index ] ); + } + } + } + + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && + ( type == null || timers[ index ].queue === type ) ) { + + timers[ index ].anim.stop( gotoEnd ); + dequeue = false; + timers.splice( index, 1 ); + } + } + + // Start the next in the queue if the last step wasn't forced. + // Timers currently will call their complete callbacks, which + // will dequeue but only if they were gotoEnd. + if ( dequeue || !gotoEnd ) { + jQuery.dequeue( this, type ); + } + } ); + }, + finish: function( type ) { + if ( type !== false ) { + type = type || "fx"; + } + return this.each( function() { + var index, + data = dataPriv.get( this ), + queue = data[ type + "queue" ], + hooks = data[ type + "queueHooks" ], + timers = jQuery.timers, + length = queue ? queue.length : 0; + + // Enable finishing flag on private data + data.finish = true; + + // Empty the queue first + jQuery.queue( this, type, [] ); + + if ( hooks && hooks.stop ) { + hooks.stop.call( this, true ); + } + + // Look for any active animations, and finish them + for ( index = timers.length; index--; ) { + if ( timers[ index ].elem === this && timers[ index ].queue === type ) { + timers[ index ].anim.stop( true ); + timers.splice( index, 1 ); + } + } + + // Look for any animations in the old queue and finish them + for ( index = 0; index < length; index++ ) { + if ( queue[ index ] && queue[ index ].finish ) { + queue[ index ].finish.call( this ); + } + } + + // Turn off finishing flag + delete data.finish; + } ); + } +} ); + +jQuery.each( [ "toggle", "show", "hide" ], function( _i, name ) { + var cssFn = jQuery.fn[ name ]; + jQuery.fn[ name ] = function( speed, easing, callback ) { + return speed == null || typeof speed === "boolean" ? + cssFn.apply( this, arguments ) : + this.animate( genFx( name, true ), speed, easing, callback ); + }; +} ); + +// Generate shortcuts for custom animations +jQuery.each( { + slideDown: genFx( "show" ), + slideUp: genFx( "hide" ), + slideToggle: genFx( "toggle" ), + fadeIn: { opacity: "show" }, + fadeOut: { opacity: "hide" }, + fadeToggle: { opacity: "toggle" } +}, function( name, props ) { + jQuery.fn[ name ] = function( speed, easing, callback ) { + return this.animate( props, speed, easing, callback ); + }; +} ); + +jQuery.timers = []; +jQuery.fx.tick = function() { + var timer, + i = 0, + timers = jQuery.timers; + + fxNow = Date.now(); + + for ( ; i < timers.length; i++ ) { + timer = timers[ i ]; + + // Run the timer and safely remove it when done (allowing for external removal) + if ( !timer() && timers[ i ] === timer ) { + timers.splice( i--, 1 ); + } + } + + if ( !timers.length ) { + jQuery.fx.stop(); + } + fxNow = undefined; +}; + +jQuery.fx.timer = function( timer ) { + jQuery.timers.push( timer ); + jQuery.fx.start(); +}; + +jQuery.fx.interval = 13; +jQuery.fx.start = function() { + if ( inProgress ) { + return; + } + + inProgress = true; + schedule(); +}; + +jQuery.fx.stop = function() { + inProgress = null; +}; + +jQuery.fx.speeds = { + slow: 600, + fast: 200, + + // Default speed + _default: 400 +}; + + +// Based off of the plugin by Clint Helfers, with permission. +// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/ +jQuery.fn.delay = function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time; + type = type || "fx"; + + return this.queue( type, function( next, hooks ) { + var timeout = window.setTimeout( next, time ); + hooks.stop = function() { + window.clearTimeout( timeout ); + }; + } ); +}; + + +( function() { + var input = document.createElement( "input" ), + select = document.createElement( "select" ), + opt = select.appendChild( document.createElement( "option" ) ); + + input.type = "checkbox"; + + // Support: Android <=4.3 only + // Default value for a checkbox should be "on" + support.checkOn = input.value !== ""; + + // Support: IE <=11 only + // Must access selectedIndex to make default options select + support.optSelected = opt.selected; + + // Support: IE <=11 only + // An input loses its value after becoming a radio + input = document.createElement( "input" ); + input.value = "t"; + input.type = "radio"; + support.radioValue = input.value === "t"; +} )(); + + +var boolHook, + attrHandle = jQuery.expr.attrHandle; + +jQuery.fn.extend( { + attr: function( name, value ) { + return access( this, jQuery.attr, name, value, arguments.length > 1 ); + }, + + removeAttr: function( name ) { + return this.each( function() { + jQuery.removeAttr( this, name ); + } ); + } +} ); + +jQuery.extend( { + attr: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set attributes on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + // Fallback to prop when attributes are not supported + if ( typeof elem.getAttribute === "undefined" ) { + return jQuery.prop( elem, name, value ); + } + + // Attribute hooks are determined by the lowercase version + // Grab necessary hook if one is defined + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + hooks = jQuery.attrHooks[ name.toLowerCase() ] || + ( jQuery.expr.match.bool.test( name ) ? boolHook : undefined ); + } + + if ( value !== undefined ) { + if ( value === null ) { + jQuery.removeAttr( elem, name ); + return; + } + + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + elem.setAttribute( name, value + "" ); + return value; + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + ret = jQuery.find.attr( elem, name ); + + // Non-existent attributes return null, we normalize to undefined + return ret == null ? undefined : ret; + }, + + attrHooks: { + type: { + set: function( elem, value ) { + if ( !support.radioValue && value === "radio" && + nodeName( elem, "input" ) ) { + var val = elem.value; + elem.setAttribute( "type", value ); + if ( val ) { + elem.value = val; + } + return value; + } + } + } + }, + + removeAttr: function( elem, value ) { + var name, + i = 0, + + // Attribute names can contain non-HTML whitespace characters + // https://html.spec.whatwg.org/multipage/syntax.html#attributes-2 + attrNames = value && value.match( rnothtmlwhite ); + + if ( attrNames && elem.nodeType === 1 ) { + while ( ( name = attrNames[ i++ ] ) ) { + elem.removeAttribute( name ); + } + } + } +} ); + +// Hooks for boolean attributes +boolHook = { + set: function( elem, value, name ) { + if ( value === false ) { + + // Remove boolean attributes when set to false + jQuery.removeAttr( elem, name ); + } else { + elem.setAttribute( name, name ); + } + return name; + } +}; + +jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( _i, name ) { + var getter = attrHandle[ name ] || jQuery.find.attr; + + attrHandle[ name ] = function( elem, name, isXML ) { + var ret, handle, + lowercaseName = name.toLowerCase(); + + if ( !isXML ) { + + // Avoid an infinite loop by temporarily removing this function from the getter + handle = attrHandle[ lowercaseName ]; + attrHandle[ lowercaseName ] = ret; + ret = getter( elem, name, isXML ) != null ? + lowercaseName : + null; + attrHandle[ lowercaseName ] = handle; + } + return ret; + }; +} ); + + + + +var rfocusable = /^(?:input|select|textarea|button)$/i, + rclickable = /^(?:a|area)$/i; + +jQuery.fn.extend( { + prop: function( name, value ) { + return access( this, jQuery.prop, name, value, arguments.length > 1 ); + }, + + removeProp: function( name ) { + return this.each( function() { + delete this[ jQuery.propFix[ name ] || name ]; + } ); + } +} ); + +jQuery.extend( { + prop: function( elem, name, value ) { + var ret, hooks, + nType = elem.nodeType; + + // Don't get/set properties on text, comment and attribute nodes + if ( nType === 3 || nType === 8 || nType === 2 ) { + return; + } + + if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) { + + // Fix name and attach hooks + name = jQuery.propFix[ name ] || name; + hooks = jQuery.propHooks[ name ]; + } + + if ( value !== undefined ) { + if ( hooks && "set" in hooks && + ( ret = hooks.set( elem, value, name ) ) !== undefined ) { + return ret; + } + + return ( elem[ name ] = value ); + } + + if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) { + return ret; + } + + return elem[ name ]; + }, + + propHooks: { + tabIndex: { + get: function( elem ) { + + // Support: IE <=9 - 11 only + // elem.tabIndex doesn't always return the + // correct value when it hasn't been explicitly set + // https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + // Use proper attribute retrieval(#12072) + var tabindex = jQuery.find.attr( elem, "tabindex" ); + + if ( tabindex ) { + return parseInt( tabindex, 10 ); + } + + if ( + rfocusable.test( elem.nodeName ) || + rclickable.test( elem.nodeName ) && + elem.href + ) { + return 0; + } + + return -1; + } + } + }, + + propFix: { + "for": "htmlFor", + "class": "className" + } +} ); + +// Support: IE <=11 only +// Accessing the selectedIndex property +// forces the browser to respect setting selected +// on the option +// The getter ensures a default option is selected +// when in an optgroup +// eslint rule "no-unused-expressions" is disabled for this code +// since it considers such accessions noop +if ( !support.optSelected ) { + jQuery.propHooks.selected = { + get: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent && parent.parentNode ) { + parent.parentNode.selectedIndex; + } + return null; + }, + set: function( elem ) { + + /* eslint no-unused-expressions: "off" */ + + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + }; +} + +jQuery.each( [ + "tabIndex", + "readOnly", + "maxLength", + "cellSpacing", + "cellPadding", + "rowSpan", + "colSpan", + "useMap", + "frameBorder", + "contentEditable" +], function() { + jQuery.propFix[ this.toLowerCase() ] = this; +} ); + + + + + // Strip and collapse whitespace according to HTML spec + // https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace + function stripAndCollapse( value ) { + var tokens = value.match( rnothtmlwhite ) || []; + return tokens.join( " " ); + } + + +function getClass( elem ) { + return elem.getAttribute && elem.getAttribute( "class" ) || ""; +} + +function classesToArray( value ) { + if ( Array.isArray( value ) ) { + return value; + } + if ( typeof value === "string" ) { + return value.match( rnothtmlwhite ) || []; + } + return []; +} + +jQuery.fn.extend( { + addClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).addClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + if ( cur.indexOf( " " + clazz + " " ) < 0 ) { + cur += clazz + " "; + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + var classes, elem, cur, curValue, clazz, j, finalValue, + i = 0; + + if ( isFunction( value ) ) { + return this.each( function( j ) { + jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) ); + } ); + } + + if ( !arguments.length ) { + return this.attr( "class", "" ); + } + + classes = classesToArray( value ); + + if ( classes.length ) { + while ( ( elem = this[ i++ ] ) ) { + curValue = getClass( elem ); + + // This expression is here for better compressibility (see addClass) + cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " ); + + if ( cur ) { + j = 0; + while ( ( clazz = classes[ j++ ] ) ) { + + // Remove *all* instances + while ( cur.indexOf( " " + clazz + " " ) > -1 ) { + cur = cur.replace( " " + clazz + " ", " " ); + } + } + + // Only assign if different to avoid unneeded rendering. + finalValue = stripAndCollapse( cur ); + if ( curValue !== finalValue ) { + elem.setAttribute( "class", finalValue ); + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, + isValidValue = type === "string" || Array.isArray( value ); + + if ( typeof stateVal === "boolean" && isValidValue ) { + return stateVal ? this.addClass( value ) : this.removeClass( value ); + } + + if ( isFunction( value ) ) { + return this.each( function( i ) { + jQuery( this ).toggleClass( + value.call( this, i, getClass( this ), stateVal ), + stateVal + ); + } ); + } + + return this.each( function() { + var className, i, self, classNames; + + if ( isValidValue ) { + + // Toggle individual class names + i = 0; + self = jQuery( this ); + classNames = classesToArray( value ); + + while ( ( className = classNames[ i++ ] ) ) { + + // Check each className given, space separated list + if ( self.hasClass( className ) ) { + self.removeClass( className ); + } else { + self.addClass( className ); + } + } + + // Toggle whole class name + } else if ( value === undefined || type === "boolean" ) { + className = getClass( this ); + if ( className ) { + + // Store className if set + dataPriv.set( this, "__className__", className ); + } + + // If the element has a class name or if we're passed `false`, + // then remove the whole classname (if there was one, the above saved it). + // Otherwise bring back whatever was previously saved (if anything), + // falling back to the empty string if nothing was stored. + if ( this.setAttribute ) { + this.setAttribute( "class", + className || value === false ? + "" : + dataPriv.get( this, "__className__" ) || "" + ); + } + } + } ); + }, + + hasClass: function( selector ) { + var className, elem, + i = 0; + + className = " " + selector + " "; + while ( ( elem = this[ i++ ] ) ) { + if ( elem.nodeType === 1 && + ( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) { + return true; + } + } + + return false; + } +} ); + + + + +var rreturn = /\r/g; + +jQuery.fn.extend( { + val: function( value ) { + var hooks, ret, valueIsFunction, + elem = this[ 0 ]; + + if ( !arguments.length ) { + if ( elem ) { + hooks = jQuery.valHooks[ elem.type ] || + jQuery.valHooks[ elem.nodeName.toLowerCase() ]; + + if ( hooks && + "get" in hooks && + ( ret = hooks.get( elem, "value" ) ) !== undefined + ) { + return ret; + } + + ret = elem.value; + + // Handle most common string cases + if ( typeof ret === "string" ) { + return ret.replace( rreturn, "" ); + } + + // Handle cases where value is null/undef or number + return ret == null ? "" : ret; + } + + return; + } + + valueIsFunction = isFunction( value ); + + return this.each( function( i ) { + var val; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( valueIsFunction ) { + val = value.call( this, i, jQuery( this ).val() ); + } else { + val = value; + } + + // Treat null/undefined as ""; convert numbers to string + if ( val == null ) { + val = ""; + + } else if ( typeof val === "number" ) { + val += ""; + + } else if ( Array.isArray( val ) ) { + val = jQuery.map( val, function( value ) { + return value == null ? "" : value + ""; + } ); + } + + hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ]; + + // If set returns undefined, fall back to normal setting + if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) { + this.value = val; + } + } ); + } +} ); + +jQuery.extend( { + valHooks: { + option: { + get: function( elem ) { + + var val = jQuery.find.attr( elem, "value" ); + return val != null ? + val : + + // Support: IE <=10 - 11 only + // option.text throws exceptions (#14686, #14858) + // Strip and collapse whitespace + // https://html.spec.whatwg.org/#strip-and-collapse-whitespace + stripAndCollapse( jQuery.text( elem ) ); + } + }, + select: { + get: function( elem ) { + var value, option, i, + options = elem.options, + index = elem.selectedIndex, + one = elem.type === "select-one", + values = one ? null : [], + max = one ? index + 1 : options.length; + + if ( index < 0 ) { + i = max; + + } else { + i = one ? index : 0; + } + + // Loop through all the selected options + for ( ; i < max; i++ ) { + option = options[ i ]; + + // Support: IE <=9 only + // IE8-9 doesn't update selected after form reset (#2551) + if ( ( option.selected || i === index ) && + + // Don't return options that are disabled or in a disabled optgroup + !option.disabled && + ( !option.parentNode.disabled || + !nodeName( option.parentNode, "optgroup" ) ) ) { + + // Get the specific value for the option + value = jQuery( option ).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + }, + + set: function( elem, value ) { + var optionSet, option, + options = elem.options, + values = jQuery.makeArray( value ), + i = options.length; + + while ( i-- ) { + option = options[ i ]; + + /* eslint-disable no-cond-assign */ + + if ( option.selected = + jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1 + ) { + optionSet = true; + } + + /* eslint-enable no-cond-assign */ + } + + // Force browsers to behave consistently when non-matching value is set + if ( !optionSet ) { + elem.selectedIndex = -1; + } + return values; + } + } + } +} ); + +// Radios and checkboxes getter/setter +jQuery.each( [ "radio", "checkbox" ], function() { + jQuery.valHooks[ this ] = { + set: function( elem, value ) { + if ( Array.isArray( value ) ) { + return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 ); + } + } + }; + if ( !support.checkOn ) { + jQuery.valHooks[ this ].get = function( elem ) { + return elem.getAttribute( "value" ) === null ? "on" : elem.value; + }; + } +} ); + + + + +// Return jQuery for attributes-only inclusion + + +support.focusin = "onfocusin" in window; + + +var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, + stopPropagationCallback = function( e ) { + e.stopPropagation(); + }; + +jQuery.extend( jQuery.event, { + + trigger: function( event, data, elem, onlyHandlers ) { + + var i, cur, tmp, bubbleType, ontype, handle, special, lastElement, + eventPath = [ elem || document ], + type = hasOwn.call( event, "type" ) ? event.type : event, + namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; + + cur = lastElement = tmp = elem = elem || document; + + // Don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // focus/blur morphs to focusin/out; ensure we're not firing them right now + if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { + return; + } + + if ( type.indexOf( "." ) > -1 ) { + + // Namespaced trigger; create a regexp to match event type in handle() + namespaces = type.split( "." ); + type = namespaces.shift(); + namespaces.sort(); + } + ontype = type.indexOf( ":" ) < 0 && "on" + type; + + // Caller can pass in a jQuery.Event object, Object, or just an event type string + event = event[ jQuery.expando ] ? + event : + new jQuery.Event( type, typeof event === "object" && event ); + + // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) + event.isTrigger = onlyHandlers ? 2 : 3; + event.namespace = namespaces.join( "." ); + event.rnamespace = event.namespace ? + new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : + null; + + // Clean up the event in case it is being reused + event.result = undefined; + if ( !event.target ) { + event.target = elem; + } + + // Clone any incoming data and prepend the event, creating the handler arg list + data = data == null ? + [ event ] : + jQuery.makeArray( data, [ event ] ); + + // Allow special events to draw outside the lines + special = jQuery.event.special[ type ] || {}; + if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { + return; + } + + // Determine event propagation path in advance, per W3C events spec (#9951) + // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) + if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) { + + bubbleType = special.delegateType || type; + if ( !rfocusMorph.test( bubbleType + type ) ) { + cur = cur.parentNode; + } + for ( ; cur; cur = cur.parentNode ) { + eventPath.push( cur ); + tmp = cur; + } + + // Only add window if we got to document (e.g., not plain obj or detached DOM) + if ( tmp === ( elem.ownerDocument || document ) ) { + eventPath.push( tmp.defaultView || tmp.parentWindow || window ); + } + } + + // Fire handlers on the event path + i = 0; + while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { + lastElement = cur; + event.type = i > 1 ? + bubbleType : + special.bindType || type; + + // jQuery handler + handle = ( + dataPriv.get( cur, "events" ) || Object.create( null ) + )[ event.type ] && + dataPriv.get( cur, "handle" ); + if ( handle ) { + handle.apply( cur, data ); + } + + // Native handler + handle = ontype && cur[ ontype ]; + if ( handle && handle.apply && acceptData( cur ) ) { + event.result = handle.apply( cur, data ); + if ( event.result === false ) { + event.preventDefault(); + } + } + } + event.type = type; + + // If nobody prevented the default action, do it now + if ( !onlyHandlers && !event.isDefaultPrevented() ) { + + if ( ( !special._default || + special._default.apply( eventPath.pop(), data ) === false ) && + acceptData( elem ) ) { + + // Call a native DOM method on the target with the same name as the event. + // Don't do default actions on window, that's where global variables be (#6170) + if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) { + + // Don't re-trigger an onFOO event when we call its FOO() method + tmp = elem[ ontype ]; + + if ( tmp ) { + elem[ ontype ] = null; + } + + // Prevent re-triggering of the same event, since we already bubbled it above + jQuery.event.triggered = type; + + if ( event.isPropagationStopped() ) { + lastElement.addEventListener( type, stopPropagationCallback ); + } + + elem[ type ](); + + if ( event.isPropagationStopped() ) { + lastElement.removeEventListener( type, stopPropagationCallback ); + } + + jQuery.event.triggered = undefined; + + if ( tmp ) { + elem[ ontype ] = tmp; + } + } + } + } + + return event.result; + }, + + // Piggyback on a donor event to simulate a different one + // Used only for `focus(in | out)` events + simulate: function( type, elem, event ) { + var e = jQuery.extend( + new jQuery.Event(), + event, + { + type: type, + isSimulated: true + } + ); + + jQuery.event.trigger( e, null, elem ); + } + +} ); + +jQuery.fn.extend( { + + trigger: function( type, data ) { + return this.each( function() { + jQuery.event.trigger( type, data, this ); + } ); + }, + triggerHandler: function( type, data ) { + var elem = this[ 0 ]; + if ( elem ) { + return jQuery.event.trigger( type, data, elem, true ); + } + } +} ); + + +// Support: Firefox <=44 +// Firefox doesn't have focus(in | out) events +// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 +// +// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1 +// focus(in | out) events fire after focus & blur events, +// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order +// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857 +if ( !support.focusin ) { + jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { + + // Attach a single capturing handler on the document while someone wants focusin/focusout + var handler = function( event ) { + jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); + }; + + jQuery.event.special[ fix ] = { + setup: function() { + + // Handle: regular nodes (via `this.ownerDocument`), window + // (via `this.document`) & document (via `this`). + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ); + + if ( !attaches ) { + doc.addEventListener( orig, handler, true ); + } + dataPriv.access( doc, fix, ( attaches || 0 ) + 1 ); + }, + teardown: function() { + var doc = this.ownerDocument || this.document || this, + attaches = dataPriv.access( doc, fix ) - 1; + + if ( !attaches ) { + doc.removeEventListener( orig, handler, true ); + dataPriv.remove( doc, fix ); + + } else { + dataPriv.access( doc, fix, attaches ); + } + } + }; + } ); +} +var location = window.location; + +var nonce = { guid: Date.now() }; + +var rquery = ( /\?/ ); + + + +// Cross-browser xml parsing +jQuery.parseXML = function( data ) { + var xml; + if ( !data || typeof data !== "string" ) { + return null; + } + + // Support: IE 9 - 11 only + // IE throws on parseFromString with invalid input. + try { + xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" ); + } catch ( e ) { + xml = undefined; + } + + if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) { + jQuery.error( "Invalid XML: " + data ); + } + return xml; +}; + + +var + rbracket = /\[\]$/, + rCRLF = /\r?\n/g, + rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i, + rsubmittable = /^(?:input|select|textarea|keygen)/i; + +function buildParams( prefix, obj, traditional, add ) { + var name; + + if ( Array.isArray( obj ) ) { + + // Serialize array item. + jQuery.each( obj, function( i, v ) { + if ( traditional || rbracket.test( prefix ) ) { + + // Treat each array item as a scalar. + add( prefix, v ); + + } else { + + // Item is non-scalar (array or object), encode its numeric index. + buildParams( + prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]", + v, + traditional, + add + ); + } + } ); + + } else if ( !traditional && toType( obj ) === "object" ) { + + // Serialize object item. + for ( name in obj ) { + buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add ); + } + + } else { + + // Serialize scalar item. + add( prefix, obj ); + } +} + +// Serialize an array of form elements or a set of +// key/values into a query string +jQuery.param = function( a, traditional ) { + var prefix, + s = [], + add = function( key, valueOrFunction ) { + + // If value is a function, invoke it and use its return value + var value = isFunction( valueOrFunction ) ? + valueOrFunction() : + valueOrFunction; + + s[ s.length ] = encodeURIComponent( key ) + "=" + + encodeURIComponent( value == null ? "" : value ); + }; + + if ( a == null ) { + return ""; + } + + // If an array was passed in, assume that it is an array of form elements. + if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) { + + // Serialize the form elements + jQuery.each( a, function() { + add( this.name, this.value ); + } ); + + } else { + + // If traditional, encode the "old" way (the way 1.3.2 or older + // did it), otherwise encode params recursively. + for ( prefix in a ) { + buildParams( prefix, a[ prefix ], traditional, add ); + } + } + + // Return the resulting serialization + return s.join( "&" ); +}; + +jQuery.fn.extend( { + serialize: function() { + return jQuery.param( this.serializeArray() ); + }, + serializeArray: function() { + return this.map( function() { + + // Can add propHook for "elements" to filter or add form elements + var elements = jQuery.prop( this, "elements" ); + return elements ? jQuery.makeArray( elements ) : this; + } ) + .filter( function() { + var type = this.type; + + // Use .is( ":disabled" ) so that fieldset[disabled] works + return this.name && !jQuery( this ).is( ":disabled" ) && + rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) && + ( this.checked || !rcheckableType.test( type ) ); + } ) + .map( function( _i, elem ) { + var val = jQuery( this ).val(); + + if ( val == null ) { + return null; + } + + if ( Array.isArray( val ) ) { + return jQuery.map( val, function( val ) { + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ); + } + + return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) }; + } ).get(); + } +} ); + + +var + r20 = /%20/g, + rhash = /#.*$/, + rantiCache = /([?&])_=[^&]*/, + rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg, + + // #7653, #8125, #8152: local protocol detection + rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/, + rnoContent = /^(?:GET|HEAD)$/, + rprotocol = /^\/\//, + + /* Prefilters + * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example) + * 2) These are called: + * - BEFORE asking for a transport + * - AFTER param serialization (s.data is a string if s.processData is true) + * 3) key is the dataType + * 4) the catchall symbol "*" can be used + * 5) execution will start with transport dataType and THEN continue down to "*" if needed + */ + prefilters = {}, + + /* Transports bindings + * 1) key is the dataType + * 2) the catchall symbol "*" can be used + * 3) selection will start with transport dataType and THEN go to "*" if needed + */ + transports = {}, + + // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression + allTypes = "*/".concat( "*" ), + + // Anchor tag for parsing the document origin + originAnchor = document.createElement( "a" ); + originAnchor.href = location.href; + +// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport +function addToPrefiltersOrTransports( structure ) { + + // dataTypeExpression is optional and defaults to "*" + return function( dataTypeExpression, func ) { + + if ( typeof dataTypeExpression !== "string" ) { + func = dataTypeExpression; + dataTypeExpression = "*"; + } + + var dataType, + i = 0, + dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || []; + + if ( isFunction( func ) ) { + + // For each dataType in the dataTypeExpression + while ( ( dataType = dataTypes[ i++ ] ) ) { + + // Prepend if requested + if ( dataType[ 0 ] === "+" ) { + dataType = dataType.slice( 1 ) || "*"; + ( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func ); + + // Otherwise append + } else { + ( structure[ dataType ] = structure[ dataType ] || [] ).push( func ); + } + } + } + }; +} + +// Base inspection function for prefilters and transports +function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) { + + var inspected = {}, + seekingTransport = ( structure === transports ); + + function inspect( dataType ) { + var selected; + inspected[ dataType ] = true; + jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) { + var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR ); + if ( typeof dataTypeOrTransport === "string" && + !seekingTransport && !inspected[ dataTypeOrTransport ] ) { + + options.dataTypes.unshift( dataTypeOrTransport ); + inspect( dataTypeOrTransport ); + return false; + } else if ( seekingTransport ) { + return !( selected = dataTypeOrTransport ); + } + } ); + return selected; + } + + return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" ); +} + +// A special extend for ajax options +// that takes "flat" options (not to be deep extended) +// Fixes #9887 +function ajaxExtend( target, src ) { + var key, deep, + flatOptions = jQuery.ajaxSettings.flatOptions || {}; + + for ( key in src ) { + if ( src[ key ] !== undefined ) { + ( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ]; + } + } + if ( deep ) { + jQuery.extend( true, target, deep ); + } + + return target; +} + +/* Handles responses to an ajax request: + * - finds the right dataType (mediates between content-type and expected dataType) + * - returns the corresponding response + */ +function ajaxHandleResponses( s, jqXHR, responses ) { + + var ct, type, finalDataType, firstDataType, + contents = s.contents, + dataTypes = s.dataTypes; + + // Remove auto dataType and get content-type in the process + while ( dataTypes[ 0 ] === "*" ) { + dataTypes.shift(); + if ( ct === undefined ) { + ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" ); + } + } + + // Check if we're dealing with a known content-type + if ( ct ) { + for ( type in contents ) { + if ( contents[ type ] && contents[ type ].test( ct ) ) { + dataTypes.unshift( type ); + break; + } + } + } + + // Check to see if we have a response for the expected dataType + if ( dataTypes[ 0 ] in responses ) { + finalDataType = dataTypes[ 0 ]; + } else { + + // Try convertible dataTypes + for ( type in responses ) { + if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) { + finalDataType = type; + break; + } + if ( !firstDataType ) { + firstDataType = type; + } + } + + // Or just use first one + finalDataType = finalDataType || firstDataType; + } + + // If we found a dataType + // We add the dataType to the list if needed + // and return the corresponding response + if ( finalDataType ) { + if ( finalDataType !== dataTypes[ 0 ] ) { + dataTypes.unshift( finalDataType ); + } + return responses[ finalDataType ]; + } +} + +/* Chain conversions given the request and the original response + * Also sets the responseXXX fields on the jqXHR instance + */ +function ajaxConvert( s, response, jqXHR, isSuccess ) { + var conv2, current, conv, tmp, prev, + converters = {}, + + // Work with a copy of dataTypes in case we need to modify it for conversion + dataTypes = s.dataTypes.slice(); + + // Create converters map with lowercased keys + if ( dataTypes[ 1 ] ) { + for ( conv in s.converters ) { + converters[ conv.toLowerCase() ] = s.converters[ conv ]; + } + } + + current = dataTypes.shift(); + + // Convert to each sequential dataType + while ( current ) { + + if ( s.responseFields[ current ] ) { + jqXHR[ s.responseFields[ current ] ] = response; + } + + // Apply the dataFilter if provided + if ( !prev && isSuccess && s.dataFilter ) { + response = s.dataFilter( response, s.dataType ); + } + + prev = current; + current = dataTypes.shift(); + + if ( current ) { + + // There's only work to do if current dataType is non-auto + if ( current === "*" ) { + + current = prev; + + // Convert response if prev dataType is non-auto and differs from current + } else if ( prev !== "*" && prev !== current ) { + + // Seek a direct converter + conv = converters[ prev + " " + current ] || converters[ "* " + current ]; + + // If none found, seek a pair + if ( !conv ) { + for ( conv2 in converters ) { + + // If conv2 outputs current + tmp = conv2.split( " " ); + if ( tmp[ 1 ] === current ) { + + // If prev can be converted to accepted input + conv = converters[ prev + " " + tmp[ 0 ] ] || + converters[ "* " + tmp[ 0 ] ]; + if ( conv ) { + + // Condense equivalence converters + if ( conv === true ) { + conv = converters[ conv2 ]; + + // Otherwise, insert the intermediate dataType + } else if ( converters[ conv2 ] !== true ) { + current = tmp[ 0 ]; + dataTypes.unshift( tmp[ 1 ] ); + } + break; + } + } + } + } + + // Apply converter (if not an equivalence) + if ( conv !== true ) { + + // Unless errors are allowed to bubble, catch and return them + if ( conv && s.throws ) { + response = conv( response ); + } else { + try { + response = conv( response ); + } catch ( e ) { + return { + state: "parsererror", + error: conv ? e : "No conversion from " + prev + " to " + current + }; + } + } + } + } + } + } + + return { state: "success", data: response }; +} + +jQuery.extend( { + + // Counter for holding the number of active queries + active: 0, + + // Last-Modified header cache for next request + lastModified: {}, + etag: {}, + + ajaxSettings: { + url: location.href, + type: "GET", + isLocal: rlocalProtocol.test( location.protocol ), + global: true, + processData: true, + async: true, + contentType: "application/x-www-form-urlencoded; charset=UTF-8", + + /* + timeout: 0, + data: null, + dataType: null, + username: null, + password: null, + cache: null, + throws: false, + traditional: false, + headers: {}, + */ + + accepts: { + "*": allTypes, + text: "text/plain", + html: "text/html", + xml: "application/xml, text/xml", + json: "application/json, text/javascript" + }, + + contents: { + xml: /\bxml\b/, + html: /\bhtml/, + json: /\bjson\b/ + }, + + responseFields: { + xml: "responseXML", + text: "responseText", + json: "responseJSON" + }, + + // Data converters + // Keys separate source (or catchall "*") and destination types with a single space + converters: { + + // Convert anything to text + "* text": String, + + // Text to html (true = no transformation) + "text html": true, + + // Evaluate text as a json expression + "text json": JSON.parse, + + // Parse text as xml + "text xml": jQuery.parseXML + }, + + // For options that shouldn't be deep extended: + // you can add your own custom options here if + // and when you create one that shouldn't be + // deep extended (see ajaxExtend) + flatOptions: { + url: true, + context: true + } + }, + + // Creates a full fledged settings object into target + // with both ajaxSettings and settings fields. + // If target is omitted, writes into ajaxSettings. + ajaxSetup: function( target, settings ) { + return settings ? + + // Building a settings object + ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) : + + // Extending ajaxSettings + ajaxExtend( jQuery.ajaxSettings, target ); + }, + + ajaxPrefilter: addToPrefiltersOrTransports( prefilters ), + ajaxTransport: addToPrefiltersOrTransports( transports ), + + // Main method + ajax: function( url, options ) { + + // If url is an object, simulate pre-1.5 signature + if ( typeof url === "object" ) { + options = url; + url = undefined; + } + + // Force options to be an object + options = options || {}; + + var transport, + + // URL without anti-cache param + cacheURL, + + // Response headers + responseHeadersString, + responseHeaders, + + // timeout handle + timeoutTimer, + + // Url cleanup var + urlAnchor, + + // Request state (becomes false upon send and true upon completion) + completed, + + // To know if global events are to be dispatched + fireGlobals, + + // Loop variable + i, + + // uncached part of the url + uncached, + + // Create the final options object + s = jQuery.ajaxSetup( {}, options ), + + // Callbacks context + callbackContext = s.context || s, + + // Context for global events is callbackContext if it is a DOM node or jQuery collection + globalEventContext = s.context && + ( callbackContext.nodeType || callbackContext.jquery ) ? + jQuery( callbackContext ) : + jQuery.event, + + // Deferreds + deferred = jQuery.Deferred(), + completeDeferred = jQuery.Callbacks( "once memory" ), + + // Status-dependent callbacks + statusCode = s.statusCode || {}, + + // Headers (they are sent all at once) + requestHeaders = {}, + requestHeadersNames = {}, + + // Default abort message + strAbort = "canceled", + + // Fake xhr + jqXHR = { + readyState: 0, + + // Builds headers hashtable if needed + getResponseHeader: function( key ) { + var match; + if ( completed ) { + if ( !responseHeaders ) { + responseHeaders = {}; + while ( ( match = rheaders.exec( responseHeadersString ) ) ) { + responseHeaders[ match[ 1 ].toLowerCase() + " " ] = + ( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] ) + .concat( match[ 2 ] ); + } + } + match = responseHeaders[ key.toLowerCase() + " " ]; + } + return match == null ? null : match.join( ", " ); + }, + + // Raw string + getAllResponseHeaders: function() { + return completed ? responseHeadersString : null; + }, + + // Caches the header + setRequestHeader: function( name, value ) { + if ( completed == null ) { + name = requestHeadersNames[ name.toLowerCase() ] = + requestHeadersNames[ name.toLowerCase() ] || name; + requestHeaders[ name ] = value; + } + return this; + }, + + // Overrides response content-type header + overrideMimeType: function( type ) { + if ( completed == null ) { + s.mimeType = type; + } + return this; + }, + + // Status-dependent callbacks + statusCode: function( map ) { + var code; + if ( map ) { + if ( completed ) { + + // Execute the appropriate callbacks + jqXHR.always( map[ jqXHR.status ] ); + } else { + + // Lazy-add the new callbacks in a way that preserves old ones + for ( code in map ) { + statusCode[ code ] = [ statusCode[ code ], map[ code ] ]; + } + } + } + return this; + }, + + // Cancel the request + abort: function( statusText ) { + var finalText = statusText || strAbort; + if ( transport ) { + transport.abort( finalText ); + } + done( 0, finalText ); + return this; + } + }; + + // Attach deferreds + deferred.promise( jqXHR ); + + // Add protocol if not provided (prefilters might expect it) + // Handle falsy url in the settings object (#10093: consistency with old signature) + // We also use the url parameter if available + s.url = ( ( url || s.url || location.href ) + "" ) + .replace( rprotocol, location.protocol + "//" ); + + // Alias method option to type as per ticket #12004 + s.type = options.method || options.type || s.method || s.type; + + // Extract dataTypes list + s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ]; + + // A cross-domain request is in order when the origin doesn't match the current origin. + if ( s.crossDomain == null ) { + urlAnchor = document.createElement( "a" ); + + // Support: IE <=8 - 11, Edge 12 - 15 + // IE throws exception on accessing the href property if url is malformed, + // e.g. http://example.com:80x/ + try { + urlAnchor.href = s.url; + + // Support: IE <=8 - 11 only + // Anchor's host property isn't correctly set when s.url is relative + urlAnchor.href = urlAnchor.href; + s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !== + urlAnchor.protocol + "//" + urlAnchor.host; + } catch ( e ) { + + // If there is an error parsing the URL, assume it is crossDomain, + // it can be rejected by the transport if it is invalid + s.crossDomain = true; + } + } + + // Convert data if not already a string + if ( s.data && s.processData && typeof s.data !== "string" ) { + s.data = jQuery.param( s.data, s.traditional ); + } + + // Apply prefilters + inspectPrefiltersOrTransports( prefilters, s, options, jqXHR ); + + // If request was aborted inside a prefilter, stop there + if ( completed ) { + return jqXHR; + } + + // We can fire global events as of now if asked to + // Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118) + fireGlobals = jQuery.event && s.global; + + // Watch for a new set of requests + if ( fireGlobals && jQuery.active++ === 0 ) { + jQuery.event.trigger( "ajaxStart" ); + } + + // Uppercase the type + s.type = s.type.toUpperCase(); + + // Determine if request has content + s.hasContent = !rnoContent.test( s.type ); + + // Save the URL in case we're toying with the If-Modified-Since + // and/or If-None-Match header later on + // Remove hash to simplify url manipulation + cacheURL = s.url.replace( rhash, "" ); + + // More options handling for requests with no content + if ( !s.hasContent ) { + + // Remember the hash so we can put it back + uncached = s.url.slice( cacheURL.length ); + + // If data is available and should be processed, append data to url + if ( s.data && ( s.processData || typeof s.data === "string" ) ) { + cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data; + + // #9682: remove data so that it's not used in an eventual retry + delete s.data; + } + + // Add or update anti-cache param if needed + if ( s.cache === false ) { + cacheURL = cacheURL.replace( rantiCache, "$1" ); + uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce.guid++ ) + + uncached; + } + + // Put hash and anti-cache on the URL that will be requested (gh-1732) + s.url = cacheURL + uncached; + + // Change '%20' to '+' if this is encoded form body content (gh-2658) + } else if ( s.data && s.processData && + ( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) { + s.data = s.data.replace( r20, "+" ); + } + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + if ( jQuery.lastModified[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] ); + } + if ( jQuery.etag[ cacheURL ] ) { + jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] ); + } + } + + // Set the correct header, if data is being sent + if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) { + jqXHR.setRequestHeader( "Content-Type", s.contentType ); + } + + // Set the Accepts header for the server, depending on the dataType + jqXHR.setRequestHeader( + "Accept", + s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ? + s.accepts[ s.dataTypes[ 0 ] ] + + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) : + s.accepts[ "*" ] + ); + + // Check for headers option + for ( i in s.headers ) { + jqXHR.setRequestHeader( i, s.headers[ i ] ); + } + + // Allow custom headers/mimetypes and early abort + if ( s.beforeSend && + ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) { + + // Abort if not done already and return + return jqXHR.abort(); + } + + // Aborting is no longer a cancellation + strAbort = "abort"; + + // Install callbacks on deferreds + completeDeferred.add( s.complete ); + jqXHR.done( s.success ); + jqXHR.fail( s.error ); + + // Get transport + transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR ); + + // If no transport, we auto-abort + if ( !transport ) { + done( -1, "No Transport" ); + } else { + jqXHR.readyState = 1; + + // Send global event + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] ); + } + + // If request was aborted inside ajaxSend, stop there + if ( completed ) { + return jqXHR; + } + + // Timeout + if ( s.async && s.timeout > 0 ) { + timeoutTimer = window.setTimeout( function() { + jqXHR.abort( "timeout" ); + }, s.timeout ); + } + + try { + completed = false; + transport.send( requestHeaders, done ); + } catch ( e ) { + + // Rethrow post-completion exceptions + if ( completed ) { + throw e; + } + + // Propagate others as results + done( -1, e ); + } + } + + // Callback for when everything is done + function done( status, nativeStatusText, responses, headers ) { + var isSuccess, success, error, response, modified, + statusText = nativeStatusText; + + // Ignore repeat invocations + if ( completed ) { + return; + } + + completed = true; + + // Clear timeout if it exists + if ( timeoutTimer ) { + window.clearTimeout( timeoutTimer ); + } + + // Dereference transport for early garbage collection + // (no matter how long the jqXHR object will be used) + transport = undefined; + + // Cache response headers + responseHeadersString = headers || ""; + + // Set readyState + jqXHR.readyState = status > 0 ? 4 : 0; + + // Determine if successful + isSuccess = status >= 200 && status < 300 || status === 304; + + // Get response data + if ( responses ) { + response = ajaxHandleResponses( s, jqXHR, responses ); + } + + // Use a noop converter for missing script + if ( !isSuccess && jQuery.inArray( "script", s.dataTypes ) > -1 ) { + s.converters[ "text script" ] = function() {}; + } + + // Convert no matter what (that way responseXXX fields are always set) + response = ajaxConvert( s, response, jqXHR, isSuccess ); + + // If successful, handle type chaining + if ( isSuccess ) { + + // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode. + if ( s.ifModified ) { + modified = jqXHR.getResponseHeader( "Last-Modified" ); + if ( modified ) { + jQuery.lastModified[ cacheURL ] = modified; + } + modified = jqXHR.getResponseHeader( "etag" ); + if ( modified ) { + jQuery.etag[ cacheURL ] = modified; + } + } + + // if no content + if ( status === 204 || s.type === "HEAD" ) { + statusText = "nocontent"; + + // if not modified + } else if ( status === 304 ) { + statusText = "notmodified"; + + // If we have data, let's convert it + } else { + statusText = response.state; + success = response.data; + error = response.error; + isSuccess = !error; + } + } else { + + // Extract error from statusText and normalize for non-aborts + error = statusText; + if ( status || !statusText ) { + statusText = "error"; + if ( status < 0 ) { + status = 0; + } + } + } + + // Set data for the fake xhr object + jqXHR.status = status; + jqXHR.statusText = ( nativeStatusText || statusText ) + ""; + + // Success/Error + if ( isSuccess ) { + deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] ); + } else { + deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] ); + } + + // Status-dependent callbacks + jqXHR.statusCode( statusCode ); + statusCode = undefined; + + if ( fireGlobals ) { + globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError", + [ jqXHR, s, isSuccess ? success : error ] ); + } + + // Complete + completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] ); + + if ( fireGlobals ) { + globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] ); + + // Handle the global AJAX counter + if ( !( --jQuery.active ) ) { + jQuery.event.trigger( "ajaxStop" ); + } + } + } + + return jqXHR; + }, + + getJSON: function( url, data, callback ) { + return jQuery.get( url, data, callback, "json" ); + }, + + getScript: function( url, callback ) { + return jQuery.get( url, undefined, callback, "script" ); + } +} ); + +jQuery.each( [ "get", "post" ], function( _i, method ) { + jQuery[ method ] = function( url, data, callback, type ) { + + // Shift arguments if data argument was omitted + if ( isFunction( data ) ) { + type = type || callback; + callback = data; + data = undefined; + } + + // The url can be an options object (which then must have .url) + return jQuery.ajax( jQuery.extend( { + url: url, + type: method, + dataType: type, + data: data, + success: callback + }, jQuery.isPlainObject( url ) && url ) ); + }; +} ); + +jQuery.ajaxPrefilter( function( s ) { + var i; + for ( i in s.headers ) { + if ( i.toLowerCase() === "content-type" ) { + s.contentType = s.headers[ i ] || ""; + } + } +} ); + + +jQuery._evalUrl = function( url, options, doc ) { + return jQuery.ajax( { + url: url, + + // Make this explicit, since user can override this through ajaxSetup (#11264) + type: "GET", + dataType: "script", + cache: true, + async: false, + global: false, + + // Only evaluate the response if it is successful (gh-4126) + // dataFilter is not invoked for failure responses, so using it instead + // of the default converter is kludgy but it works. + converters: { + "text script": function() {} + }, + dataFilter: function( response ) { + jQuery.globalEval( response, options, doc ); + } + } ); +}; + + +jQuery.fn.extend( { + wrapAll: function( html ) { + var wrap; + + if ( this[ 0 ] ) { + if ( isFunction( html ) ) { + html = html.call( this[ 0 ] ); + } + + // The elements to wrap the target around + wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true ); + + if ( this[ 0 ].parentNode ) { + wrap.insertBefore( this[ 0 ] ); + } + + wrap.map( function() { + var elem = this; + + while ( elem.firstElementChild ) { + elem = elem.firstElementChild; + } + + return elem; + } ).append( this ); + } + + return this; + }, + + wrapInner: function( html ) { + if ( isFunction( html ) ) { + return this.each( function( i ) { + jQuery( this ).wrapInner( html.call( this, i ) ); + } ); + } + + return this.each( function() { + var self = jQuery( this ), + contents = self.contents(); + + if ( contents.length ) { + contents.wrapAll( html ); + + } else { + self.append( html ); + } + } ); + }, + + wrap: function( html ) { + var htmlIsFunction = isFunction( html ); + + return this.each( function( i ) { + jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html ); + } ); + }, + + unwrap: function( selector ) { + this.parent( selector ).not( "body" ).each( function() { + jQuery( this ).replaceWith( this.childNodes ); + } ); + return this; + } +} ); + + +jQuery.expr.pseudos.hidden = function( elem ) { + return !jQuery.expr.pseudos.visible( elem ); +}; +jQuery.expr.pseudos.visible = function( elem ) { + return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length ); +}; + + + + +jQuery.ajaxSettings.xhr = function() { + try { + return new window.XMLHttpRequest(); + } catch ( e ) {} +}; + +var xhrSuccessStatus = { + + // File protocol always yields status code 0, assume 200 + 0: 200, + + // Support: IE <=9 only + // #1450: sometimes IE returns 1223 when it should be 204 + 1223: 204 + }, + xhrSupported = jQuery.ajaxSettings.xhr(); + +support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported ); +support.ajax = xhrSupported = !!xhrSupported; + +jQuery.ajaxTransport( function( options ) { + var callback, errorCallback; + + // Cross domain only allowed if supported through XMLHttpRequest + if ( support.cors || xhrSupported && !options.crossDomain ) { + return { + send: function( headers, complete ) { + var i, + xhr = options.xhr(); + + xhr.open( + options.type, + options.url, + options.async, + options.username, + options.password + ); + + // Apply custom fields if provided + if ( options.xhrFields ) { + for ( i in options.xhrFields ) { + xhr[ i ] = options.xhrFields[ i ]; + } + } + + // Override mime type if needed + if ( options.mimeType && xhr.overrideMimeType ) { + xhr.overrideMimeType( options.mimeType ); + } + + // X-Requested-With header + // For cross-domain requests, seeing as conditions for a preflight are + // akin to a jigsaw puzzle, we simply never set it to be sure. + // (it can always be set on a per-request basis or even using ajaxSetup) + // For same-domain requests, won't change header if already provided. + if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) { + headers[ "X-Requested-With" ] = "XMLHttpRequest"; + } + + // Set headers + for ( i in headers ) { + xhr.setRequestHeader( i, headers[ i ] ); + } + + // Callback + callback = function( type ) { + return function() { + if ( callback ) { + callback = errorCallback = xhr.onload = + xhr.onerror = xhr.onabort = xhr.ontimeout = + xhr.onreadystatechange = null; + + if ( type === "abort" ) { + xhr.abort(); + } else if ( type === "error" ) { + + // Support: IE <=9 only + // On a manual native abort, IE9 throws + // errors on any property access that is not readyState + if ( typeof xhr.status !== "number" ) { + complete( 0, "error" ); + } else { + complete( + + // File: protocol always yields status 0; see #8605, #14207 + xhr.status, + xhr.statusText + ); + } + } else { + complete( + xhrSuccessStatus[ xhr.status ] || xhr.status, + xhr.statusText, + + // Support: IE <=9 only + // IE9 has no XHR2 but throws on binary (trac-11426) + // For XHR2 non-text, let the caller handle it (gh-2498) + ( xhr.responseType || "text" ) !== "text" || + typeof xhr.responseText !== "string" ? + { binary: xhr.response } : + { text: xhr.responseText }, + xhr.getAllResponseHeaders() + ); + } + } + }; + }; + + // Listen to events + xhr.onload = callback(); + errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" ); + + // Support: IE 9 only + // Use onreadystatechange to replace onabort + // to handle uncaught aborts + if ( xhr.onabort !== undefined ) { + xhr.onabort = errorCallback; + } else { + xhr.onreadystatechange = function() { + + // Check readyState before timeout as it changes + if ( xhr.readyState === 4 ) { + + // Allow onerror to be called first, + // but that will not handle a native abort + // Also, save errorCallback to a variable + // as xhr.onerror cannot be accessed + window.setTimeout( function() { + if ( callback ) { + errorCallback(); + } + } ); + } + }; + } + + // Create the abort callback + callback = callback( "abort" ); + + try { + + // Do send the request (this may raise an exception) + xhr.send( options.hasContent && options.data || null ); + } catch ( e ) { + + // #14683: Only rethrow if this hasn't been notified as an error yet + if ( callback ) { + throw e; + } + } + }, + + abort: function() { + if ( callback ) { + callback(); + } + } + }; + } +} ); + + + + +// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432) +jQuery.ajaxPrefilter( function( s ) { + if ( s.crossDomain ) { + s.contents.script = false; + } +} ); + +// Install script dataType +jQuery.ajaxSetup( { + accepts: { + script: "text/javascript, application/javascript, " + + "application/ecmascript, application/x-ecmascript" + }, + contents: { + script: /\b(?:java|ecma)script\b/ + }, + converters: { + "text script": function( text ) { + jQuery.globalEval( text ); + return text; + } + } +} ); + +// Handle cache's special case and crossDomain +jQuery.ajaxPrefilter( "script", function( s ) { + if ( s.cache === undefined ) { + s.cache = false; + } + if ( s.crossDomain ) { + s.type = "GET"; + } +} ); + +// Bind script tag hack transport +jQuery.ajaxTransport( "script", function( s ) { + + // This transport only deals with cross domain or forced-by-attrs requests + if ( s.crossDomain || s.scriptAttrs ) { + var script, callback; + return { + send: function( _, complete ) { + script = jQuery( " + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/add_new_model_to_data_labeler.ipynb b/docs/0.10.3/html/add_new_model_to_data_labeler.ipynb new file mode 100644 index 000000000..1495e6a85 --- /dev/null +++ b/docs/0.10.3/html/add_new_model_to_data_labeler.ipynb @@ -0,0 +1,488 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "id": "228bb2a6", + "metadata": {}, + "source": [ + "# Adding new model to the existing DataLabeler pipeline" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "cab7a569", + "metadata": {}, + "source": [ + "Consider the case when we would like to explore different character-level neural network models and evaluate their performance on different datasets. The existing DataLabeler in the DataProfiler library already contains a preprocessor, a postprocessor, and a character-level CNN (Convolutional Neural Network) model that are combined to work on such data. All we need is to build additional model classes that inherit the main functionalities from the CNN model and also adapt the model construction to the desired architectures. In this example, we define such a new model to be used with the Data Labeler component of the Data Profiler. In particular, a character-level LSTM (Long Short-Term Memory) model is implemented, then integrated into the DataLabeler pipeline to be trained with a tabular dataset. The process includes the following steps:\n", + "\n", + " - Build a new character-level LSTM model that inherits the CNN model\n", + " - Load the DataLabeler from the DataProfiler\n", + " - Swap the existing CNN model with the new LSTM model\n", + " - Train the data labeler pipeline on a given dataset\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16624c48", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "import pandas as pd\n", + "sys.path.insert(0, '..')\n", + "import dataprofiler as dp" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "e90728ab", + "metadata": {}, + "source": [ + "## Dataset" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "3d61981c", + "metadata": {}, + "source": [ + "In this example, we use a structured dataset, the aws honeypot dataset, given in the test folder of the library. This dataset is first read by the Data Reader class of the Data Profiler, then split into training and test data to be used in the next sections." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f031fe06", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read input data\n", + "data = dp.Data(\"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\")\n", + "df_data = data.data\n", + "\n", + "# split data to training and test set\n", + "split_ratio = 0.2\n", + "df_data = df_data.sample(frac=1).reset_index(drop=True)\n", + "data_train = df_data[:int((1 - split_ratio) * len(df_data))]\n", + "data_test = df_data[int((1 - split_ratio) * len(df_data)):]\n", + "\n", + "df_data.head()" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "745ed0d4", + "metadata": {}, + "source": [ + "## Implement a new character-level LSTM model" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "7375b0c0", + "metadata": {}, + "source": [ + "This new model is inherited from `CharacterLevelCnnModel` class, with some modifications on the following functions\n", + "\n", + "`__init__`: to add new parameters for the LSTM model. The new parameters, `size_lstm`, `rec_dropout`, `activation`, `recurrent_activation`, specify number of LSTM layers, activation function, and recurrent dropout ratio.\n", + "\n", + "`_validate_parameters`: to add additional checks on the new parameters for the LSTM model\n", + "\n", + "`_construct_model`: to construct the new LSTM model with the desired architecture" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8568fb49", + "metadata": {}, + "outputs": [], + "source": [ + "import tensorflow as tf\n", + "import numpy as np\n", + "from dataprofiler.labelers.character_level_cnn_model import (\n", + " CharacterLevelCnnModel,\n", + " create_glove_char,\n", + " build_embd_dictionary,\n", + ")\n", + "from dataprofiler.labelers.base_model import BaseModel\n", + "from dataprofiler.labelers.labeler_utils import F1Score\n", + "\n", + "\n", + "# CharacterLevelLstmModel derives from CharacterLevelCnnModel\n", + "#########################################################\n", + "#########################################################\n", + "class CharacterLevelLstmModel(CharacterLevelCnnModel):\n", + " # boolean if the label mapping requires the mapping for index 0 reserved\n", + " requires_zero_mapping = True\n", + "\n", + " def __init__(self, label_mapping=None, parameters=None):\n", + " \"\"\"\n", + " LSTM Model Initializer\n", + " \"\"\"\n", + "\n", + " # parameter initialization\n", + " if not parameters:\n", + " parameters = {}\n", + " parameters.setdefault(\"max_length\", 3400)\n", + " parameters.setdefault(\"max_char_encoding_id\", 127)\n", + " parameters.setdefault(\"dim_embed\", 64)\n", + " parameters.setdefault(\"size_fc\", [32, 32])\n", + " parameters.setdefault(\"dropout\", 0.1)\n", + " # new parameters for LSTM model\n", + " #########################################################\n", + " #########################################################\n", + " parameters.setdefault(\"size_lstm\", [64])\n", + " parameters.setdefault(\"rec_dropout\", 0.1)\n", + " parameters.setdefault(\"activation\", \"tanh\")\n", + " parameters.setdefault(\"recurrent_activation\", \"sigmoid\")\n", + " #########################################################\n", + " #########################################################\n", + " parameters.setdefault(\"default_label\", \"UNKNOWN\")\n", + " parameters[\"pad_label\"] = \"PAD\"\n", + " self._epoch_id = 0\n", + "\n", + " # reconstruct flags for model\n", + " self._model_num_labels = 0\n", + " self._model_default_ind = -1\n", + "\n", + " BaseModel.__init__(self, label_mapping, parameters)\n", + "\n", + " def _validate_parameters(self, parameters):\n", + " \"\"\"\n", + " Validate the parameters sent in. Raise error if invalid parameters are\n", + " present.\n", + " \"\"\"\n", + " errors = []\n", + " list_of_necessary_params = [\n", + " \"max_length\",\n", + " \"max_char_encoding_id\",\n", + " \"dim_embed\",\n", + " \"size_fc\",\n", + " \"dropout\",\n", + " \"size_lstm\",\n", + " \"rec_dropout\",\n", + " \"activation\",\n", + " \"recurrent_activation\",\n", + " \"default_label\",\n", + " \"pad_label\",\n", + " ]\n", + " # Make sure the necessary parameters are present and valid.\n", + " for param in parameters:\n", + " if param in [\n", + " \"max_length\",\n", + " \"max_char_encoding_id\",\n", + " \"dim_embed\",\n", + " \"size_conv\",\n", + " ]:\n", + " if (\n", + " not isinstance(parameters[param], (int, float))\n", + " or parameters[param] < 0\n", + " ):\n", + " errors.append(\n", + " param + \" must be a valid integer or float \" \"greater than 0.\"\n", + " )\n", + " elif param in [\n", + " \"dropout\",\n", + " \"rec_dropout\",\n", + " ]: # additional check for rec_dropout\n", + " if (\n", + " not isinstance(parameters[param], (int, float))\n", + " or parameters[param] < 0\n", + " or parameters[param] > 1\n", + " ):\n", + " errors.append(\n", + " param + \" must be a valid integer or float \" \"from 0 to 1.\"\n", + " )\n", + " elif (\n", + " param == \"size_fc\" or param == \"size_lstm\"\n", + " ): # additional check for size_lstm\n", + " if (\n", + " not isinstance(parameters[param], list)\n", + " or len(parameters[param]) == 0\n", + " ):\n", + " errors.append(param + \" must be a non-empty list of \" \"integers.\")\n", + " else:\n", + " for item in parameters[param]:\n", + " if not isinstance(item, int):\n", + " errors.append(\n", + " param + \" must be a non-empty \" \"list of integers.\"\n", + " )\n", + " break\n", + " elif param in [\n", + " \"default_label\",\n", + " \"activation\",\n", + " \"recurrent_activation\",\n", + " ]: # additional check for activation and recurrent_activation\n", + " if not isinstance(parameters[param], str):\n", + " error = str(param) + \" must be a string.\"\n", + " errors.append(error)\n", + "\n", + " # Error if there are extra parameters thrown in\n", + " for param in parameters:\n", + " if param not in list_of_necessary_params:\n", + " errors.append(param + \" is not an accepted parameter.\")\n", + " if errors:\n", + " raise ValueError(\"\\n\".join(errors))\n", + "\n", + " def _construct_model(self):\n", + " \"\"\"\n", + " Model constructor for the data labeler. This also serves as a weight\n", + " reset.\n", + "\n", + " :return: None\n", + " \"\"\"\n", + " num_labels = self.num_labels\n", + " default_ind = self.label_mapping[self._parameters[\"default_label\"]]\n", + "\n", + " # Reset model\n", + " tf.keras.backend.clear_session()\n", + "\n", + " # generate glove embedding\n", + " create_glove_char(self._parameters[\"dim_embed\"])\n", + "\n", + " # generate model\n", + " self._model = tf.keras.models.Sequential()\n", + "\n", + " # default parameters\n", + " max_length = self._parameters[\"max_length\"]\n", + " max_char_encoding_id = self._parameters[\"max_char_encoding_id\"]\n", + "\n", + " # Encoding layer\n", + " def encoding_function(input_str):\n", + " char_in_vector = CharacterLevelLstmModel._char_encoding_layer(\n", + " input_str, max_char_encoding_id, max_length\n", + " )\n", + " return char_in_vector\n", + "\n", + " self._model.add(tf.keras.layers.Input(shape=(None,), dtype=tf.string))\n", + "\n", + " self._model.add(\n", + " tf.keras.layers.Lambda(encoding_function, output_shape=tuple([max_length]))\n", + " )\n", + "\n", + " # Create a pre-trained weight matrix\n", + " # character encoding indices range from 0 to max_char_encoding_id,\n", + " # we add one extra index for out-of-vocabulary character\n", + " embed_file = os.path.join(\n", + " \"../dataprofiler/labelers\",\n", + " \"embeddings/glove-reduced-{}D.txt\".format(self._parameters[\"dim_embed\"]),\n", + " )\n", + " embedding_matrix = np.zeros(\n", + " (max_char_encoding_id + 2, self._parameters[\"dim_embed\"])\n", + " )\n", + " embedding_dict = build_embd_dictionary(embed_file)\n", + "\n", + " input_shape = tuple([max_length])\n", + " # Fill in the weight matrix: let pad and space be 0s\n", + " for ascii_num in range(max_char_encoding_id):\n", + " if chr(ascii_num) in embedding_dict:\n", + " embedding_matrix[ascii_num + 1] = embedding_dict[chr(ascii_num)]\n", + "\n", + " self._model.add(\n", + " tf.keras.layers.Embedding(\n", + " max_char_encoding_id + 2,\n", + " self._parameters[\"dim_embed\"],\n", + " weights=[embedding_matrix],\n", + " input_length=input_shape[0],\n", + " trainable=True,\n", + " )\n", + " )\n", + "\n", + " # Add the lstm layers\n", + " #########################################################\n", + " #########################################################\n", + " for size in self._parameters[\"size_lstm\"]:\n", + " self._model.add(\n", + " tf.keras.layers.LSTM(\n", + " units=size,\n", + " recurrent_dropout=self._parameters[\"rec_dropout\"],\n", + " activation=self._parameters[\"activation\"],\n", + " recurrent_activation=self._parameters[\"recurrent_activation\"],\n", + " return_sequences=True,\n", + " )\n", + " )\n", + " if self._parameters[\"dropout\"]:\n", + " self._model.add(tf.keras.layers.Dropout(self._parameters[\"dropout\"]))\n", + " #########################################################\n", + " #########################################################\n", + "\n", + " # Add the fully connected layers\n", + " for size in self._parameters[\"size_fc\"]:\n", + " self._model.add(tf.keras.layers.Dense(units=size, activation=\"relu\"))\n", + " if self._parameters[\"dropout\"]:\n", + " self._model.add(tf.keras.layers.Dropout(self._parameters[\"dropout\"]))\n", + "\n", + " # Add the final Softmax layer\n", + " self._model.add(tf.keras.layers.Dense(num_labels, activation=\"softmax\"))\n", + "\n", + " # Output the model into a .pb file for TensorFlow\n", + " argmax_layer = tf.keras.backend.argmax(self._model.output)\n", + "\n", + " # Create confidence layers\n", + " final_predicted_layer = CharacterLevelLstmModel._argmax_threshold_layer(\n", + " num_labels, threshold=0.0, default_ind=default_ind\n", + " )\n", + "\n", + " argmax_outputs = self._model.outputs + [\n", + " argmax_layer,\n", + " final_predicted_layer(argmax_layer, self._model.output),\n", + " ]\n", + " self._model = tf.keras.Model(self._model.inputs, argmax_outputs)\n", + "\n", + " # Compile the model\n", + " softmax_output_layer_name = self._model.outputs[0].name.split(\"/\")[0]\n", + " losses = {softmax_output_layer_name: \"categorical_crossentropy\"}\n", + "\n", + " # use f1 score metric\n", + " f1_score_training = F1Score(num_classes=num_labels, average=\"micro\")\n", + " metrics = {softmax_output_layer_name: [\"acc\", f1_score_training]}\n", + "\n", + " self._model.compile(loss=losses, optimizer=\"adam\", metrics=metrics)\n", + "\n", + " self._epoch_id = 0\n", + " self._model_num_labels = num_labels\n", + " self._model_default_ind = default_ind" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d66bd25c", + "metadata": {}, + "source": [ + "## Integrate the new LSTM model to the DataLabeler" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "479f407a", + "metadata": {}, + "source": [ + "Once the LSTM model is built, it replaces the existing model in the DataLabeler pipeline, which is then trained on the given dataset. Note that, as the DataLabeler is trained on the above tabular dataset, its label mapping is updated by the list of column names in that dataset while training." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fb482ffe", + "metadata": {}, + "outputs": [], + "source": [ + "# get labels from the given dataset\n", + "value_label_df = data_train.reset_index(drop=True).melt()\n", + "value_label_df.columns = [1, 0] # labels=1, values=0 in that order\n", + "value_label_df = value_label_df.astype(str)\n", + "labels = value_label_df[1].unique().tolist()\n", + "\n", + "# create a new LSTM model\n", + "# set default label (one of the column names) to the model\n", + "model = CharacterLevelLstmModel(label_mapping=labels, parameters={'default_label': 'comment'})\n", + "\n", + "# add the new LSTM model to the data labeler\n", + "data_labeler = dp.DataLabeler(labeler_type='structured', trainable=True)\n", + "data_labeler.set_model(model)\n", + "\n", + "# set default label (one of the column names) to the preprocessor and postprocessor\n", + "processor_params = {'default_label': 'comment'}\n", + "data_labeler._preprocessor.set_params(**processor_params)\n", + "data_labeler._postprocessor.set_params(**processor_params)\n", + "\n", + "# train the data labeler\n", + "save_dirpath=\"data_labeler_saved\"\n", + "if not os.path.exists(save_dirpath):\n", + " os.makedirs(save_dirpath)\n", + "\n", + "epochs=2\n", + "data_labeler.fit(\n", + " x=value_label_df[0], y=value_label_df[1], labels=labels, epochs=epochs)\n", + "if save_dirpath:\n", + " data_labeler.save_to_disk(save_dirpath)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "14b78c69", + "metadata": {}, + "source": [ + "The trained Data Labeler is then used by the Data Profiler to provide the prediction on the new dataset. In this example, all options except data labeler are disabled for the sake of presenting data labeler functionality. The results are given in the columnar format where true column types are given in the first column, and the predicted column labels are given in the second column." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bdfcf1d2", + "metadata": {}, + "outputs": [], + "source": [ + "# predict with the data labeler object\n", + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({\"structured_options.text.is_enabled\": False, \n", + " \"int.is_enabled\": False, \n", + " \"float.is_enabled\": False, \n", + " \"order.is_enabled\": False, \n", + " \"category.is_enabled\": False, \n", + " \"datetime.is_enabled\": False,})\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_object': data_labeler})\n", + "profile = dp.Profiler(data_test, options=profile_options)\n", + "\n", + "# get the prediction from the data profiler\n", + "def get_structured_results(results):\n", + " columns = []\n", + " predictions = []\n", + " for col_report in results['data_stats']:\n", + " columns.append(col_report['column_name'])\n", + " predictions.append(col_report['data_label'])\n", + "\n", + " df_results = pd.DataFrame({'Column': columns, 'Prediction': predictions})\n", + " return df_results\n", + "\n", + "results = profile.report()\n", + "print(get_structured_results(results))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "cc60ff8a", + "metadata": {}, + "source": [ + "In summary, users can define their own model, plug it in the DataLabeler pipeline, and train the labeler with the new dataset. Above, we show one example of adding the LSTM model to the pipeline. Interested users can implement other neural network models as desired with the same process." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/column_name_labeler_example.html b/docs/0.10.3/html/column_name_labeler_example.html new file mode 100644 index 000000000..376aa73db --- /dev/null +++ b/docs/0.10.3/html/column_name_labeler_example.html @@ -0,0 +1,820 @@ + + + + + + + + + ColumnName Labeler Tutorial - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    ColumnName Labeler Tutorial

    +

    This notebook teaches how to use the existing ColumnNameModel:

    +
      +
    1. Loading and utilizing the pre-existing ColumnNameModel

    2. +
    3. Run the labeler

    4. +
    +

    First, let’s import the libraries needed for this example.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +from pprint import pprint
    +
    +import pandas as pd
    +
    +try:
    +    import dataprofiler as dp
    +except ImportError:
    +    sys.path.insert(0, '../..')
    +    import dataprofiler as dp
    +
    +
    +
    +
    +

    Loading and predicting using a pre-existing model using load_from_library

    +

    The easiest option for users is to load_from_library by specifying the name for the labeler in the resources/ folder. Quickly import and start predicting with any model from the Data Profiler’s library of models available.

    +
    +
    [ ]:
    +
    +
    +
    +labeler_from_library = dp.DataLabeler.load_from_library('column_name_labeler')
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +labeler_from_library.predict(data=["ssn"])
    +
    +
    +
    +
    +
    +

    Loading and using the pre-existing column name labeler using load_with_components

    +

    For example purposes here, we will import the exsting ColumnName labeler via the load_with_components command from the dp.DataLabeler. This shows a bit more of the details of the data labeler’s flow.

    +
    +
    [ ]:
    +
    +
    +
    +parameters = {
    +            "true_positive_dict": [
    +                {"attribute": "ssn", "label": "ssn"},
    +                {"attribute": "suffix", "label": "name"},
    +                {"attribute": "my_home_address", "label": "address"},
    +            ],
    +            "false_positive_dict": [
    +                {
    +                    "attribute": "contract_number",
    +                    "label": "ssn",
    +                },
    +                {
    +                    "attribute": "role",
    +                    "label": "name",
    +                },
    +                {
    +                    "attribute": "send_address",
    +                    "label": "address",
    +                },
    +            ],
    +            "negative_threshold_config": 50,
    +            "positive_threshold_config": 85,
    +            "include_label": True,
    +        }
    +
    +label_mapping = {"ssn": 1, "name": 2, "address": 3}
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# pre processor
    +preprocessor = dp.labelers.data_processing.DirectPassPreprocessor()
    +
    +# model
    +from dataprofiler.labelers.column_name_model import ColumnNameModel
    +model = ColumnNameModel(
    +    parameters=parameters,
    +    label_mapping=label_mapping,
    +)
    +
    +
    +# post processor
    +postprocessor = dp.labelers.data_processing.ColumnNameModelPostprocessor()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +data_labeler = dp.DataLabeler.load_with_components(
    +    preprocessor=preprocessor,
    +    model=model,
    +    postprocessor=postprocessor,
    +)
    +data_labeler.model.help()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pprint(data_labeler.label_mapping)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pprint(data_labeler.model._parameters)
    +
    +
    +
    +
    +

    Predicting with the ColumnName labeler

    +

    In the prediction below, the data will be passed into to stages in the background - 1) compare_negative: The idea behind the compare_negative is to first filter out any possibility of flagging a false positive in the model prediction. In this step, the confidence value is checked and if the similarity is too close to being a false positive, that particular string in the data is removed and not returned to the compare_positive. - 2) compare_positive: Finally the data is +passed to the compare_positive step and checked for similarity with the the true_positive_dict values. Again, during this stage the positive_threshold_config is used to filter the results to only those data values that are greater than or equal to the positive_threshold_config provided by the user.

    +
    +
    [ ]:
    +
    +
    +
    +# evaluate a prediction using the default parameters
    +data_labeler.predict(data=["ssn", "name", "address"])
    +
    +
    +
    +
    +
    +
    +

    Replacing the parameters in the existing labeler

    +

    We can achieve this by: 1. Setting the label mapping to the new labels 2. Setting the model parameters which include: true_positive_dict, false_positive_dict, negative_threshold_config, positive_threshold_config, and include_label

    +

    where true_positive_dict and false_positive_dict are lists of dicts, negative_threshold_config and positive_threshold_config are integer values between 0 and 100, and include_label is a boolean value that determines if the output should include the prediction labels or only the confidence values.

    +

    Below, we created 4 labels where other is the default_label.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.set_labels({'other': 0, "funky_one": 1, "funky_two": 2, "funky_three": 3})
    +data_labeler.model.set_params(
    +    true_positive_dict= [
    +                {"attribute": "ssn", "label": "funky_one"},
    +                {"attribute": "suffix", "label": "funky_two"},
    +                {"attribute": "my_home_address", "label": "funky_three"},
    +            ],
    +    false_positive_dict=[
    +                {
    +                    "attribute": "contract_number",
    +                    "label": "ssn",
    +                },
    +                {
    +                    "attribute": "role",
    +                    "label": "name",
    +                },
    +                {
    +                    "attribute": "not_my_address",
    +                    "label": "address",
    +                },
    +            ],
    +    negative_threshold_config=50,
    +    positive_threshold_config=85,
    +    include_label=True,
    +)
    +data_labeler.label_mapping
    +
    +
    +
    +
    +

    Predicting with the new labels

    +

    Here we are testing the predict() method with brand new labels for label_mapping. As we can see the new labels flow throught to the output of the data labeler.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.predict(data=["ssn", "suffix"], predict_options=dict(show_confidences=True))
    +
    +
    +
    +
    +
    +
    +

    Saving the Data Labeler for future use

    +
    +
    [ ]:
    +
    +
    +
    +if not os.path.isdir('new_column_name_labeler'):
    +    os.mkdir('new_column_name_labeler')
    +data_labeler.save_to_disk('new_column_name_labeler')
    +
    +
    +
    +
    +
    +

    Loading the saved Data Labeler

    +
    +
    [ ]:
    +
    +
    +
    +saved_labeler = dp.DataLabeler.load_from_disk('new_column_name_labeler')
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# ensuring the parametesr are what we saved.
    +print("label_mapping:")
    +pprint(saved_labeler.label_mapping)
    +print("\nmodel parameters:")
    +pprint(saved_labeler.model._parameters)
    +print()
    +print("postprocessor: " + saved_labeler.postprocessor.__class__.__name__)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# predicting with the loaded labeler.
    +saved_labeler.predict(["ssn", "name", "address"])
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/column_name_labeler_example.ipynb b/docs/0.10.3/html/column_name_labeler_example.ipynb new file mode 100644 index 000000000..6d3369698 --- /dev/null +++ b/docs/0.10.3/html/column_name_labeler_example.ipynb @@ -0,0 +1,364 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e04c382a-7c49-452b-b9bf-e448951c64fe", + "metadata": {}, + "source": [ + "# ColumnName Labeler Tutorial" + ] + }, + { + "cell_type": "markdown", + "id": "6fb3ecb9-bc51-4c18-93d5-7991bbee5165", + "metadata": {}, + "source": [ + "This notebook teaches how to use the existing `ColumnNameModel`:\n", + "\n", + "1. Loading and utilizing the pre-existing `ColumnNameModel`\n", + "2. Run the labeler\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a67c197b-d3ee-4896-a96f-cc3d043601d3", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "from pprint import pprint\n", + "\n", + "import pandas as pd\n", + "\n", + "try:\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " sys.path.insert(0, '../..')\n", + " import dataprofiler as dp" + ] + }, + { + "cell_type": "markdown", + "id": "35841215", + "metadata": {}, + "source": [ + "## Loading and predicting using a pre-existing model using `load_from_library`\n", + "\n", + "The easiest option for users is to `load_from_library` by specifying the name for the labeler in the `resources/` folder. Quickly import and start predicting with any model from the Data Profiler's library of models available." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "46e36dd6", + "metadata": {}, + "outputs": [], + "source": [ + "labeler_from_library = dp.DataLabeler.load_from_library('column_name_labeler')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dfa94868", + "metadata": {}, + "outputs": [], + "source": [ + "labeler_from_library.predict(data=[\"ssn\"])" + ] + }, + { + "cell_type": "markdown", + "id": "c71356f4-9020-4862-a1e1-816effbb5443", + "metadata": {}, + "source": [ + "## Loading and using the pre-existing column name labeler using `load_with_components`\n", + "\n", + "For example purposes here, we will import the exsting `ColumnName` labeler via the `load_with_components` command from the `dp.DataLabeler`. This shows a bit more of the details of the data labeler's flow." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "818c5b88", + "metadata": {}, + "outputs": [], + "source": [ + "parameters = {\n", + " \"true_positive_dict\": [\n", + " {\"attribute\": \"ssn\", \"label\": \"ssn\"},\n", + " {\"attribute\": \"suffix\", \"label\": \"name\"},\n", + " {\"attribute\": \"my_home_address\", \"label\": \"address\"},\n", + " ],\n", + " \"false_positive_dict\": [\n", + " {\n", + " \"attribute\": \"contract_number\",\n", + " \"label\": \"ssn\",\n", + " },\n", + " {\n", + " \"attribute\": \"role\",\n", + " \"label\": \"name\",\n", + " },\n", + " {\n", + " \"attribute\": \"send_address\",\n", + " \"label\": \"address\",\n", + " },\n", + " ],\n", + " \"negative_threshold_config\": 50,\n", + " \"positive_threshold_config\": 85,\n", + " \"include_label\": True,\n", + " }\n", + "\n", + "label_mapping = {\"ssn\": 1, \"name\": 2, \"address\": 3}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9098329e", + "metadata": {}, + "outputs": [], + "source": [ + "# pre processor \n", + "preprocessor = dp.labelers.data_processing.DirectPassPreprocessor()\n", + "\n", + "# model\n", + "from dataprofiler.labelers.column_name_model import ColumnNameModel\n", + "model = ColumnNameModel(\n", + " parameters=parameters,\n", + " label_mapping=label_mapping,\n", + ")\n", + "\n", + "\n", + "# post processor\n", + "postprocessor = dp.labelers.data_processing.ColumnNameModelPostprocessor()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113d6655-4bca-4d8e-9e6f-b972e29d5684", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler = dp.DataLabeler.load_with_components(\n", + " preprocessor=preprocessor,\n", + " model=model,\n", + " postprocessor=postprocessor,\n", + ")\n", + "data_labeler.model.help()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b405887-2b92-44ca-b8d7-29c384f6dd9c", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.label_mapping)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11916a48-098c-4056-ac6c-b9542d85fa86", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.model._parameters)" + ] + }, + { + "cell_type": "markdown", + "id": "da0e97ee-8d6d-4631-9b55-78ed904d5f41", + "metadata": {}, + "source": [ + "### Predicting with the ColumnName labeler\n", + "\n", + "In the prediction below, the data will be passed into to stages in the background\n", + "- 1) `compare_negative`: The idea behind the `compare_negative` is to first filter out any possibility of flagging a false positive in the model prediction. In this step, the confidence value is checked and if the similarity is too close to being a false positive, that particular string in the `data` is removed and not returned to the `compare_positive`.\n", + "- 2) `compare_positive`: Finally the `data` is passed to the `compare_positive` step and checked for similarity with the the `true_positive_dict` values. Again, during this stage the `positive_threshold_config` is used to filter the results to only those `data` values that are greater than or equal to the `positive_threshold_config` provided by the user." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe519e65-36a7-4f42-8314-5369de8635c7", + "metadata": {}, + "outputs": [], + "source": [ + "# evaluate a prediction using the default parameters\n", + "data_labeler.predict(data=[\"ssn\", \"name\", \"address\"])" + ] + }, + { + "cell_type": "markdown", + "id": "b41d834d-e47b-45a6-8970-d2d2033e2ade", + "metadata": {}, + "source": [ + "## Replacing the parameters in the existing labeler\n", + "\n", + "We can achieve this by:\n", + "1. Setting the label mapping to the new labels\n", + "2. Setting the model parameters which include: `true_positive_dict`, `false_positive_dict`, `negative_threshold_config`, `positive_threshold_config`, and `include_label`\n", + "\n", + "where `true_positive_dict` and `false_positive_dict` are `lists` of `dicts`, `negative_threshold_config` and `positive_threshold_config` are integer values between `0` and `100`, and `include_label` is a `boolean` value that determines if the output should include the prediction labels or only the confidence values." + ] + }, + { + "cell_type": "markdown", + "id": "c6bb010a-406f-4fd8-abd0-3355a5ad0ded", + "metadata": {}, + "source": [ + "Below, we created 4 labels where `other` is the `default_label`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f86584cf-a7af-4bae-bf44-d87caa68833a", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.set_labels({'other': 0, \"funky_one\": 1, \"funky_two\": 2, \"funky_three\": 3})\n", + "data_labeler.model.set_params(\n", + " true_positive_dict= [\n", + " {\"attribute\": \"ssn\", \"label\": \"funky_one\"},\n", + " {\"attribute\": \"suffix\", \"label\": \"funky_two\"},\n", + " {\"attribute\": \"my_home_address\", \"label\": \"funky_three\"},\n", + " ],\n", + " false_positive_dict=[\n", + " {\n", + " \"attribute\": \"contract_number\",\n", + " \"label\": \"ssn\",\n", + " },\n", + " {\n", + " \"attribute\": \"role\",\n", + " \"label\": \"name\",\n", + " },\n", + " {\n", + " \"attribute\": \"not_my_address\",\n", + " \"label\": \"address\",\n", + " },\n", + " ],\n", + " negative_threshold_config=50,\n", + " positive_threshold_config=85,\n", + " include_label=True,\n", + ")\n", + "data_labeler.label_mapping" + ] + }, + { + "cell_type": "markdown", + "id": "1ece1c8c-18a5-46fc-b563-6458e6e71e53", + "metadata": {}, + "source": [ + "### Predicting with the new labels\n", + "\n", + "Here we are testing the `predict()` method with brand new labels for label_mapping. As we can see the new labels flow throught to the output of the data labeler." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92842e14-2ea6-4879-b58c-c52b607dc94c", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(data=[\"ssn\", \"suffix\"], predict_options=dict(show_confidences=True))" + ] + }, + { + "cell_type": "markdown", + "id": "261b903f-8f4c-403f-839b-ab8813f850e9", + "metadata": {}, + "source": [ + "## Saving the Data Labeler for future use" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6ffbaf2-9400-486a-ba83-5fc9ba9334d7", + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.isdir('new_column_name_labeler'):\n", + " os.mkdir('new_column_name_labeler')\n", + "data_labeler.save_to_disk('new_column_name_labeler')" + ] + }, + { + "cell_type": "markdown", + "id": "09e40cb6-9d89-41c4-ae28-3dca498f8c68", + "metadata": {}, + "source": [ + "## Loading the saved Data Labeler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52615b25-70a6-4ebb-8a32-14aaf1e747d9", + "metadata": {}, + "outputs": [], + "source": [ + "saved_labeler = dp.DataLabeler.load_from_disk('new_column_name_labeler')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1ccc0b3-1dc2-4847-95c2-d6b8769b1590", + "metadata": {}, + "outputs": [], + "source": [ + "# ensuring the parametesr are what we saved.\n", + "print(\"label_mapping:\")\n", + "pprint(saved_labeler.label_mapping)\n", + "print(\"\\nmodel parameters:\")\n", + "pprint(saved_labeler.model._parameters)\n", + "print()\n", + "print(\"postprocessor: \" + saved_labeler.postprocessor.__class__.__name__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c827f2ae-4af6-4f3f-9651-9ee9ebea9fa0", + "metadata": {}, + "outputs": [], + "source": [ + "# predicting with the loaded labeler.\n", + "saved_labeler.predict([\"ssn\", \"name\", \"address\"])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/data_labeling.html b/docs/0.10.3/html/data_labeling.html new file mode 100644 index 000000000..ba738281b --- /dev/null +++ b/docs/0.10.3/html/data_labeling.html @@ -0,0 +1,615 @@ + + + + + + + + + Labeler (Sensitive Data) - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Labeler (Sensitive Data)

    +

    In this library, the term data labeling refers to entity recognition.

    +

    Builtin to the data profiler is a classifier which evaluates the complex data types of the dataset. +For structured data, it determines the complex data type of each column. When +running the data profile, it uses the default data labeling model builtin to the +library. However, the data labeler allows users to train their own data labeler +as well.

    +

    Data Labels are determined per cell for structured data (column/row when +the profiler is used) or at the character level for unstructured data. This +is a list of the default labels.

    +
      +
    • UNKNOWN

    • +
    • ADDRESS

    • +
    • BAN (bank account number, 10-18 digits)

    • +
    • CREDIT_CARD

    • +
    • EMAIL_ADDRESS

    • +
    • UUID

    • +
    • HASH_OR_KEY (md5, sha1, sha256, random hash, etc.)

    • +
    • IPV4

    • +
    • IPV6

    • +
    • MAC_ADDRESS

    • +
    • PERSON

    • +
    • PHONE_NUMBER

    • +
    • SSN

    • +
    • URL

    • +
    • US_STATE

    • +
    • DRIVERS_LICENSE

    • +
    • DATE

    • +
    • TIME

    • +
    • DATETIME

    • +
    • INTEGER

    • +
    • FLOAT

    • +
    • QUANTITY

    • +
    • ORDINAL

    • +
    +
    +

    Identify Entities in Structured Data

    +

    Makes predictions and identifying labels:

    +
    import dataprofiler as dp
    +
    +# load data and data labeler
    +data = dp.Data("your_data.csv")
    +data_labeler = dp.DataLabeler(labeler_type='structured')
    +
    +# make predictions and get labels per cell
    +predictions = data_labeler.predict(data)
    +
    +
    +
    +
    +

    Identify Entities in Unstructured Data

    +

    Predict which class characters belong to in unstructured text:

    +
    import dataprofiler as dp
    +
    +data_labeler = dp.DataLabeler(labeler_type='unstructured')
    +
    +# Example sample string, must be in an array (multiple arrays can be passed)
    +sample = ["Help\tJohn Macklemore\tneeds\tfood.\tPlease\tCall\t555-301-1234."
    +          "\tHis\tssn\tis\tnot\t334-97-1234. I'm a BAN: 000043219499392912.\n"]
    +
    +# Prediction what class each character belongs to
    +model_predictions = data_labeler.predict(
    +    sample, predict_options=dict(show_confidences=True))
    +
    +# Predictions / confidences are at the character level
    +final_results = model_predictions["pred"]
    +final_confidences = model_predictions["conf"]
    +
    +
    +

    It’s also possible to change output formats, output similar to a SpaCy format:

    +
    import dataprofiler as dp
    +
    +data_labeler = dp.DataLabeler(labeler_type='unstructured', trainable=True)
    +
    +# Example sample string, must be in an array (multiple arrays can be passed)
    +sample = ["Help\tJohn Macklemore\tneeds\tfood.\tPlease\tCall\t555-301-1234."
    +          "\tHis\tssn\tis\tnot\t334-97-1234. I'm a BAN: 000043219499392912.\n"]
    +
    +# Set the output to the NER format (start position, end position, label)
    +data_labeler.set_params(
    +    { 'postprocessor': { 'output_format':'ner', 'use_word_level_argmax':True } }
    +)
    +
    +results = data_labeler.predict(sample)
    +
    +print(results)
    +
    +
    +
    +
    +

    Train a New Data Labeler

    +

    Mechanism for training your own data labeler on their own set of structured data +(tabular):

    +
    import dataprofiler as dp
    +
    +# Will need one column with a default label of UNKNOWN
    +data = dp.Data("your_file.csv")
    +
    +data_labeler = dp.train_structured_labeler(
    +    data=data,
    +    save_dirpath="/path/to/save/labeler",
    +    epochs=2
    +)
    +
    +data_labeler.save_to_disk("my/save/path") # Saves the data labeler for reuse
    +
    +
    +
    +
    +

    Load an Existing Data Labeler

    +

    Mechanism for loading an existing data_labeler:

    +
    import dataprofiler as dp
    +
    +data_labeler = dp.DataLabeler(
    +    labeler_type='structured', dirpath="/path/to/my/labeler")
    +
    +# get information about the parameters/inputs/output formats for the DataLabeler
    +data_labeler.help()
    +
    +
    +
    +
    +

    Extending a Data Labeler with Transfer Learning

    +

    Extending or changing labels of a data labeler w/ transfer learning: +Note: By default, a labeler loaded will not be trainable. In order to load a +trainable DataLabeler, the user must set trainable=True or load a labeler +using the TrainableDataLabeler class.

    +

    The following illustrates how to change the labels:

    +
    import dataprofiler as dp
    +
    +labels = ['label1', 'label2', ...]  # new label set can also be an encoding dict
    +data = dp.Data("your_file.csv")  # contains data with new labels
    +
    +# load default structured Data Labeler w/ trainable set to True
    +data_labeler = dp.DataLabeler(labeler_type='structured', trainable=True)
    +
    +# this will use transfer learning to retrain the data labeler on your new
    +# dataset and labels.
    +# NOTE: data must be in an acceptable format for the preprocessor to interpret.
    +#       please refer to the preprocessor/model for the expected data format.
    +#       Currently, the DataLabeler cannot take in Tabular data, but requires
    +#       data to be ingested with two columns [X, y] where X is the samples and
    +#       y is the labels.
    +model_results = data_labeler.fit(x=data['samples'], y=data['labels'],
    +                                 validation_split=0.2, epochs=2, labels=labels)
    +
    +# final_results, final_confidences are a list of results for each epoch
    +epoch_id = 0
    +final_results = model_results[epoch_id]["pred"]
    +final_confidences = model_results[epoch_id]["conf"]
    +
    +
    +

    The following illustrates how to extend the labels:

    +
    import dataprofiler as dp
    +
    +new_labels = ['label1', 'label2', ...]
    +data = dp.Data("your_file.csv")  # contains data with new labels
    +
    +# load default structured Data Labeler w/ trainable set to True
    +data_labeler = dp.DataLabeler(labeler_type='structured', trainable=True)
    +
    +# this will maintain current labels and model weights, but extend the model's
    +# labels
    +for label in new_labels:
    +    data_labeler.add_label(label)
    +
    +# NOTE: a user can also add a label which maps to the same index as an existing
    +# label
    +# data_labeler.add_label(label, same_as='<label_name>')
    +
    +# For a trainable model, the user must then train the model to be able to
    +# continue using the labeler since the model's graph has likely changed
    +# NOTE: data must be in an acceptable format for the preprocessor to interpret.
    +#       please refer to the preprocessor/model for the expected data format.
    +#       Currently, the DataLabeler cannot take in Tabular data, but requires
    +#       data to be ingested with two columns [X, y] where X is the samples and
    +#       y is the labels.
    +model_results = data_labeler.fit(x=data['samples'], y=data['labels'],
    +                                 validation_split=0.2, epochs=2)
    +
    +# final_results, final_confidences are a list of results for each epoch
    +epoch_id = 0
    +final_results = model_results[epoch_id]["pred"]
    +final_confidences = model_results[epoch_id]["conf"]
    +
    +
    +

    Changing pipeline parameters:

    +
    import dataprofiler as dp
    +
    +# load default Data Labeler
    +data_labeler = dp.DataLabeler(labeler_type='structured')
    +
    +# change parameters of specific component
    +data_labeler.preprocessor.set_params({'param1': 'value1'})
    +
    +# change multiple simultaneously.
    +data_labeler.set_params({
    +    'preprocessor':  {'param1': 'value1'},
    +    'model':         {'param2': 'value2'},
    +    'postprocessor': {'param3': 'value3'}
    +})
    +
    +
    +
    +

    Build Your Own Data Labeler

    +

    The DataLabeler has 3 main components: preprocessor, model, and postprocessor. +To create your own DataLabeler, each one would have to be created or an +existing component can be reused.

    +

    Given a set of the 3 components, you can construct your own DataLabeler:

    +

    Option for swapping out specific components of an existing labeler.

    +
    import dataprofiler as dp
    +from dataprofiler.labelers.character_level_cnn_model import \
    +    CharacterLevelCnnModel
    +from dataprofiler.labelers.data_processing import \
    +    StructCharPreprocessor, StructCharPostprocessor
    +
    +model = CharacterLevelCnnModel(...)
    +preprocessor = StructCharPreprocessor(...)
    +postprocessor = StructCharPostprocessor(...)
    +
    +data_labeler = dp.DataLabeler(labeler_type='structured')
    +data_labeler.set_preprocessor(preprocessor)
    +data_labeler.set_model(model)
    +data_labeler.set_postprocessor(postprocessor)
    +
    +# check for basic compatibility between the processors and the model
    +data_labeler.check_pipeline()
    +
    +
    +
    +
    +
    +

    Model Component

    +

    In order to create your own model component for data labeling, you can utilize +the BaseModel class from dataprofiler.labelers.base_model and +overriding the abstract class methods.

    +

    Reviewing CharacterLevelCnnModel from +dataprofiler.labelers.character_level_cnn_model illustrates the functions +which need an override.

    +
      +
    1. __init__: specifying default parameters and calling base __init__

    2. +
    3. _validate_parameters: validating parameters given by user during setting

    4. +
    5. _need_to_reconstruct_model: flag for when to reconstruct a model (i.e. +parameters change or labels change require a model reconstruction)

    6. +
    7. _construct_model: initial construction of the model given the parameters

    8. +
    9. _reconstruct_model: updates model architecture for new label set while +maintaining current model weights

    10. +
    11. fit: mechanism for the model to learn given training data

    12. +
    13. predict: mechanism for model to make predictions on data

    14. +
    15. details: prints a summary of the model construction

    16. +
    17. save_to_disk: saves model and model parameters to disk

    18. +
    19. load_from_disk: loads model given a path on disk

    20. +
    +
    +
    +

    Preprocessor Component

    +

    In order to create your own preprocessor component for data labeling, you can +utilize the BaseDataPreprocessor class +from dataprofiler.labelers.data_processing and override the abstract class +methods.

    +

    Reviewing StructCharPreprocessor from +dataprofiler.labelers.data_processing illustrates the functions which +need an override.

    +
      +
    1. __init__: passing parameters to the base class and executing any +extraneous calculations to be saved as parameters

    2. +
    3. _validate_parameters: validating parameters given by user during +setting

    4. +
    5. process: takes in the user data and converts it into an digestible, +iterable format for the model

    6. +
    7. set_params (optional): if a parameter requires processing before setting, +a user can override this function to assist with setting the parameter

    8. +
    9. _save_processor (optional): if a parameter is not JSON serializable, a +user can override this function to assist in saving the processor and its +parameters

    10. +
    11. load_from_disk (optional): if a parameter(s) is not JSON serializable, a +user can override this function to assist in loading the processor

    12. +
    +
    +
    +

    Postprocessor Component

    +

    The postprocessor is nearly identical to the preprocessor except it handles +the output of the model for processing. In order to create your own +postprocessor component for data labeling, you can utilize the +BaseDataPostprocessor class from dataprofiler.labelers.data_processing +and override the abstract class methods.

    +

    Reviewing StructCharPostprocessor from +dataprofiler.labelers.data_processing illustrates the functions which +need an override.

    +
      +
    1. __init__: passing parameters to the base class and executing any +extraneous calculations to be saved as parameters

    2. +
    3. _validate_parameters: validating parameters given by user during +setting

    4. +
    5. process: takes in the output of the model and processes for output to +the user

    6. +
    7. set_params (optional): if a parameter requires processing before setting, +a user can override this function to assist with setting the parameter

    8. +
    9. _save_processor (optional): if a parameter is not JSON serializable, a +user can override this function to assist in saving the processor and its +parameters

    10. +
    11. load_from_disk (optional): if a parameter(s) is not JSON serializable, a +user can override this function to assist in loading the processor

    12. +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/data_reader.html b/docs/0.10.3/html/data_reader.html new file mode 100644 index 000000000..c82048c5c --- /dev/null +++ b/docs/0.10.3/html/data_reader.html @@ -0,0 +1,1101 @@ + + + + + + + + + Intro to Data Readers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Intro to Data Readers

    +

    Within the Data Profiler, there are 5 data reader classes:

    +
      +
    • CSVData (delimited data: CSV, TSV, etc.)

    • +
    • JSONData

    • +
    • ParquetData

    • +
    • AVROData

    • +
    • GraphData

    • +
    • TextData

    • +
    +

    Each of these classes can be used to read data individually, however the Data Profiler provides the unique capability of auto detecting what data you have and reading it automatically by using the Data class.

    +
    import dataprofiler as dp
    +data = dp.Data('/path/to/mydata.abc')  # auto detects and reads your data
    +
    +
    +
    +

    Automatically reading and detecting data

    +

    Below is a demonstration of utilizing the Data class which automatically detects the type of data for a given file and reads it automatically.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +except ImportError:
    +    import dataprofiler as dp
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# use data reader to read input data with different file types
    +data_folder = "../dataprofiler/tests/data"
    +csv_files = [
    +    "csv/aws_honeypot_marx_geo.csv",
    +    "csv/all-strings-skip-header-author.csv", # csv files with the author/description on the first line
    +    "csv/sparse-first-and-last-column-empty-first-row.txt", # csv file with the .txt extension
    +]
    +json_files = [
    +    "json/complex_nested.json",
    +    "json/honeypot_intentially_mislabeled_file.csv", # json file with the .csv extension
    +]
    +parquet_files = [
    +    "parquet/nation.dict.parquet",
    +    "parquet/nation.plain.intentionally_mislabled_file.csv", # parquet file with the .csv extension
    +]
    +avro_files = [
    +    "avro/userdata1.avro",
    +    "avro/userdata1_intentionally_mislabled_file.json", # avro file with the .json extension
    +]
    +graph_files = [
    +    "csv/graph_data_csv_identify.csv", # csv file with graph column names
    +]
    +text_files = [
    +    "txt/discussion_reddit.txt",
    +]
    +all_files = csv_files + json_files + parquet_files + avro_files + graph_files + text_files
    +print('filepath' + ' ' * 58 + 'data type')
    +print('='*80)
    +for file in all_files:
    +    filepath = os.path.join(data_folder, file)
    +    data = dp.Data(filepath)
    +    print("{:<65} {:<15}".format(file, data.data_type))
    +print("\n")
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# importing from a url
    +data = dp.Data('https://raw.githubusercontent.com/capitalone/DataProfiler/main/dataprofiler/tests/data/csv/diamonds.csv')
    +data.head()
    +
    +
    +
    +
    +
    +

    Specifying detection options of Data and loading pandas.DataFrame

    +

    The Data class also gives the ability to set options or if the user wants to load their data with specific requirements. Options for each data reader are specified in the docs: https://capitalone.github.io/DataProfiler/docs/0.4.4/html/dataprofiler.data_readers.html

    +
    import dataprofiler as dp
    +
    +options = {...}  # allowed options are specified for each data reader.
    +data = dp.Data(data, options=options)
    +
    +
    +

    Later in this tutorial, the options for the CSVData class will be discussed.

    +

    Additionally, a user can directly load a pandas.DataFrame as any data reader they choose.

    +
    +
    [ ]:
    +
    +
    +
    +import pandas as pd
    +from dataprofiler.data_readers.csv_data import CSVData
    +
    +
    +df = pd.DataFrame(['my', 'random', 'data'])
    +
    +# specify via the `Data` class
    +data = dp.Data(data=df, data_type='csv')
    +print('Data Type: ', data.data_type)
    +
    +# specifically use the CSVData class
    +data = CSVData(data=df)
    +print('Data Type: ', data.data_type)
    +
    +
    +
    +
    +
    +

    Accessing data and attributes

    +

    Once loaded, the data can be accessed via the data property of the object. Additional information about the data loaded may differ between data readers.

    +

    For this example we will focus on CSVData.

    +
    +
    [ ]:
    +
    +
    +
    +filepath = "../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv"
    +data = dp.Data(filepath)
    +print('Data Type: ', data.data_type)
    +print('Data Filepath: ', data.input_file_path)
    +print('File Encoding: ', data.file_encoding)
    +print('Data Length (two techniques): ', len(data), data.length)
    +print("Data Access:")
    +data.data
    +
    +
    +
    +
    +
    +

    Checking data file types with is_match

    +

    Each data reader has a class method is_match which determines whether or not a dataset is of a given data type.

    +
    CSVData.is_match
    +JSONData.is_match
    +ParquetData.is_match
    +AVROData.is_match
    +GraphData.is_match
    +TextData.is_match
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# supplemental function
    +def add_true_false_color(value):
    +    """Converts True to green and False to red in printed text."""
    +    if value:
    +        return "\x1b[92m  " + str(is_match) + "\x1b[0m"
    +    return "\x1b[31m " + str(is_match) + "\x1b[0m"
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +from dataprofiler.data_readers.csv_data import CSVData
    +
    +
    +non_csv_files = [
    +    'json/iris-utf-8.json',
    +    'json/honeypot_intentially_mislabeled_file.csv',
    +    'parquet/titanic.parq',
    +    'parquet/nation.plain.intentionally_mislabled_file.csv',
    +    'txt/code.txt',
    +    'txt/sentence.txt',
    +    'avro/users.avro',
    +    'avro/snappy_compressed_intentionally_mislabeled_file.csv',
    +]
    +
    +print("Is the file a CSV?")
    +print('=' * 80)
    +for file in csv_files:
    +    filepath = os.path.join(data_folder, file)
    +    is_match = CSVData.is_match(filepath)
    +    print(add_true_false_color(is_match), ':', file)
    +    print('=' * 80)
    +
    +for file in non_csv_files:
    +    filepath = os.path.join(data_folder, file)
    +    is_match = CSVData.is_match(filepath)
    +    print(add_true_false_color(is_match), ':', file)
    +    print('=' * 80)
    +
    +
    +
    +
    +
    +

    Reloading data after altering options with reload

    +

    There are two cases for using the reload function, both of which require the data type to have been interpreted correctly:

    +
    1. The options were not correctly determined
    +2. The options were loaded correctly but a change is desired.
    +
    +
    +

    In the example below, the data_format for reading the data is changed and the data is then reloaded.

    +
    +
    [ ]:
    +
    +
    +
    +filepath = "../dataprofiler/tests/data/csv/diamonds.csv"
    +
    +data = dp.Data(filepath)
    +print('original data:')
    +print('=' * 80)
    +print(data.data[:5])
    +
    +print()
    +data.reload(options={'data_format': 'records', 'record_samples_per_line': 1})
    +print('reloaded data:')
    +print('=' * 80)
    +data.data[:5]
    +
    +
    +
    +
    +
    +

    A deeper dive into CSVData

    +

    This next section will focus on how to use the data reader class: CSVData. The CSVData class is used for reading delimited data. Delimited data are datasets which have their columns specified by a specific character, commonly the ,. E.g. from the diamonds.csv dataset:

    +
    carat,cut,color,clarity,depth,table,price,x,y,z
    +0.23,Ideal,E,SI2,61.5,55,326,3.95,3.98,2.43
    +0.21,Premium,E,SI1,59.8,61,326,3.89,3.84,2.31
    +0.23,Good,E,VS1,56.9,65,327,4.05,4.07,2.31
    +0.29,Premium,I,VS2,62.4,58,334,4.2,4.23,2.63
    +0.31,Good,J,SI2,63.3,58,335,4.34,4.35,2.75
    +
    +
    +

    However, the delimiter can be any character. Additionally, a quotechar, commonly ", can be specified which allows a delimiter to be contained within a column value. E.g. from the blogposts.csv dataset:

    +
    Blog Post,Date,Subject,Field
    +"Monty Hall, meet Game Theory",4/13/2014,Statistics,Mathematics
    +Gaussian Quadrature,4/13/2014,Algorithms,Mathematics
    +
    +
    +

    Notice how "Monty Hall, meet Game Theory" is contained by the quotechar because it contains the delimiter value ,.

    +

    These delimiter dataset parameters (and more) can be automatically determined by the CSVData data reader, however they can also be set via the options as demonstrated later in this tutorial.

    +
    +
    +

    Intro to the CSVData data reader

    +

    Previously, it was shown that CSVData may automatically be detected using Data or can be manually specified by the user:

    +
    import dataprofiler as dp
    +from dataprofiler.data_readers.csv_data import CSVData
    +
    +data = dp.Data(filepath)
    +data = CSVData(filepath)
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# use data reader to read delimited data
    +data_folder = "../dataprofiler/tests/data"
    +csv_files = [
    +    "csv/diamonds.csv",
    +    "csv/all-strings-skip-header-author.csv", # csv files with the author/description on the first line
    +    "csv/sparse-first-and-last-column-empty-first-row.txt", # csv file with the .txt extension
    +]
    +
    +for file in csv_files:
    +    data = CSVData(os.path.join(data_folder, file))
    +    print(data.data.head())
    +    print('=' * 80)
    +
    +
    +
    +
    +
    +

    CSVData Options

    +

    As mentioned preivously, CSVData has options that can be set to finetune its detection or to ensure the data is being read in a specific manner. The options for CSVData are detailed below:

    +
      +
    • delimiter - delimiter used to decipher the csv input file

    • +
    • quotechar - quote character used in the delimited file

    • +
    • header - location of the header in the file.

    • +
    • data_format - user selected format in which to return data can only be of specified types

    • +
    • selected_columns - columns being selected from the entire dataset

    • +
    +
    +
    [ ]:
    +
    +
    +
    +# options are set via a dictionary object in which the parameters are specified.
    +# these are the default values for each option
    +options = {
    +    "delimiter": ",",
    +    "quotechar": '"',
    +    "header": 'auto',
    +    "data_format": "dataframe",  # type: str, choices: "dataframe", "records"
    +    "selected_columns": list(),
    +}
    +
    +
    +
    +
    +
    +

    Options: delimiter and quotechar

    +

    Below, both the auto detection and use of options will be illustrated for delimiter and quotechar.

    +
    +
    [ ]:
    +
    +
    +
    +# display the data we are reading
    +filepath = "../dataprofiler/tests/data/csv/daily-activity-sheet-@-singlequote.csv"
    +num_lines = 10
    +with open(filepath) as fp:
    +    print(''.join(fp.readlines()[:num_lines]))
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(filepath)  # or use CSVData
    +print('Auto detected')
    +print('=' * 80)
    +print('delimiter: ', data.delimiter)
    +print('quotechar: ', data.quotechar)
    +data.data.head()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +options = {'delimiter': '@', 'quotechar': "'"}
    +data = dp.Data(filepath, options=options)  # or use CSVData
    +print('manually set')
    +print('=' * 80)
    +print('delimiter: ', data.delimiter)
    +print('quotechar: ', data.quotechar)
    +data.data.head()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# intentional failure with incorrect options
    +options = {'delimiter': ',', 'quotechar': '"'}
    +
    +# will be interepted as TextData because the delimtier and quotechar were incorrect
    +data = dp.Data(filepath, options=options)
    +print('intentional faliure set')
    +print('=' * 80)
    +try:
    +    print('delimiter: ', data.delimiter)  # attribute error raised here, bc TextData, not CSVData
    +    print('quotechar: ', data.quotechar)
    +
    +    # should not reach this or something went wrong
    +    raise Exception('Should have failed because this is detected as TextData.')
    +except AttributeError:
    +    print('When data_type is not set or the CSVData is not set, it will fail over to the\n'
    +          'next best reader. In this case it is "TextData"\n')
    +data.data
    +
    +
    +
    +
    +
    +

    Options: header

    +

    Below, both the auto detection and use of options will be illustrated for header.

    +

    Notice how in the manually set mechanism, we are intentionally setting the header incorrectly to illustrate what happens.

    +
    +
    [ ]:
    +
    +
    +
    +# display the data we are reading
    +filepath = "../dataprofiler/tests/data/csv/sparse-first-and-last-column-header-and-author-description.txt"
    +num_lines = 10
    +with open(filepath) as fp:
    +    print(''.join(fp.readlines()[:num_lines]))
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +options = {'header': 'auto'}  # auto detected (default value)
    +data = dp.Data(filepath, options=options)  # or use CSVData
    +print('Data Header:', data.header)
    +print('=' * 80)
    +data.data.head()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +options = {'header': 2}  # intentionally set incorrectly at value 2
    +data = dp.Data(filepath, options=options)  # or use CSVData
    +print('Data Header:', data.header)
    +print('=' * 80)
    +data.data.head()
    +
    +
    +
    +
    +
    +

    Options: data_format

    +

    For CSVData, the data_format option can have the following values:

    +
      +
    • dataframe - (default) loads the dataset as a pandas.DataFrame

    • +
    • records - loads the data as rows of text values, the extra parameter record_samples_per_line how many rows are combined into a single line

    • +
    +

    dataframe is used for conducting structured profiling of the dataset while records is for unstructured profiling.

    +

    Below, both the auto detection and use of options will be illustrated for data_format.

    +
    +
    [ ]:
    +
    +
    +
    +# display the data we are reading
    +filepath = "../dataprofiler/tests/data/csv/diamonds.csv"
    +num_lines = 10
    +with open(filepath) as fp:
    +    print(''.join(fp.readlines()[:num_lines]))
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +options = {'data_format': 'dataframe'}  # default
    +data = dp.Data(filepath, options=options)  # or use CSVData
    +data.data[:5]
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +options = {'data_format': 'records', 'record_samples_per_line': 1}
    +data = dp.Data(filepath, options=options)
    +data.data[:5]
    +
    +
    +
    +
    +
    +

    Options: selected columns

    +

    By default, all columns of a dataset will be read and loaded into the data reader. However, selected_columns can be set to only load columns which the user requests.

    +
    +
    [ ]:
    +
    +
    +
    +# display the data we are reading
    +filepath = "../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv"
    +num_lines = 10
    +with open(filepath) as fp:
    +    print(''.join(fp.readlines()[:num_lines]))
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +options = {'selected_columns': ['datetime', 'host', 'src', 'proto']}
    +data = dp.Data(filepath, options=options)
    +data.data.head()
    +
    +
    +
    +
    +
    +

    Intro to GraphData data reader

    +

    This tutorial will focus on how to use the data reader class: GraphData. The GraphData class is used for reading the delimited data from a CSV file into a NetworkX Graph object. This is all in an effort to prepare the data automaticaly for GraphProfiler class to then profile graph data.

    +

    The DataProiler keys off of common graph naming conventions in the column header row. E.G. from dataprofiler/tests/csv/graph_data_csv_identify.csv

    +
    node_id_dst, node_id_src, continuous_weight, categorical_status
    +108,289,7.4448069,9
    +81,180,3.65064207,0
    +458,83,5.9959787,10
    +55,116,4.63359209,79
    +454,177,5.76715529,11
    +429,225,4.79556889,3
    +
    +
    +

    Options for the GraphData are exactly the same as CSVData.

    +

    Example implementation of GraphData:

    +
    import dataprofiler as dp
    +from dataprofiler.data_readers.graph_data import GraphData
    +
    +data = dp.Data(graph_file)
    +data = GraphData(graph_file)
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +from dataprofiler.data_readers.graph_data import GraphData
    +
    +# use data reader to read delimited data
    +data_folder = "../dataprofiler/tests/data"
    +graph_file = "csv/graph_data_csv_identify.csv"
    +
    +data = GraphData(os.path.join(data_folder, graph_file))
    +print(data.data.edges)
    +print('=' * 80)
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/data_reader.ipynb b/docs/0.10.3/html/data_reader.ipynb new file mode 100644 index 000000000..d2ce887e6 --- /dev/null +++ b/docs/0.10.3/html/data_reader.ipynb @@ -0,0 +1,689 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d4d79832-59ab-410a-ad6d-fbba01a3f0d3", + "metadata": {}, + "source": [ + "# Intro to Data Readers\n", + "Within the Data Profiler, there are 5 data reader classes:\n", + "\n", + " * CSVData (delimited data: CSV, TSV, etc.)\n", + " * JSONData\n", + " * ParquetData\n", + " * AVROData\n", + " * GraphData\n", + " * TextData\n", + " \n", + "Each of these classes can be used to read data individually, however the Data Profiler provides the unique capability of auto detecting what data you have and reading it automatically by using the `Data` class.\n", + "```python\n", + "import dataprofiler as dp\n", + "data = dp.Data('/path/to/mydata.abc') # auto detects and reads your data\n", + "```" + ] + }, + { + "cell_type": "markdown", + "id": "f2315666-20be-4937-9f9a-26d42dc135e2", + "metadata": { + "tags": [] + }, + "source": [ + "## Automatically reading and detecting data\n", + "\n", + "Below is a demonstration of utilizing the `Data` class which automatically detects the type of data for a given file and reads it automatically." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99e61c6c-43b8-4700-b627-759b5ef8bdda", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8821ad8d-b2c0-489c-ae6a-54c11b7f0a08", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read input data with different file types\n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "csv_files = [\n", + " \"csv/aws_honeypot_marx_geo.csv\",\n", + " \"csv/all-strings-skip-header-author.csv\", # csv files with the author/description on the first line\n", + " \"csv/sparse-first-and-last-column-empty-first-row.txt\", # csv file with the .txt extension\n", + "]\n", + "json_files = [\n", + " \"json/complex_nested.json\",\n", + " \"json/honeypot_intentially_mislabeled_file.csv\", # json file with the .csv extension\n", + "]\n", + "parquet_files = [\n", + " \"parquet/nation.dict.parquet\",\n", + " \"parquet/nation.plain.intentionally_mislabled_file.csv\", # parquet file with the .csv extension\n", + "]\n", + "avro_files = [\n", + " \"avro/userdata1.avro\",\n", + " \"avro/userdata1_intentionally_mislabled_file.json\", # avro file with the .json extension\n", + "]\n", + "graph_files = [\n", + " \"csv/graph_data_csv_identify.csv\", # csv file with graph column names\n", + "]\n", + "text_files = [\n", + " \"txt/discussion_reddit.txt\",\n", + "]\n", + "all_files = csv_files + json_files + parquet_files + avro_files + graph_files + text_files\n", + "print('filepath' + ' ' * 58 + 'data type')\n", + "print('='*80)\n", + "for file in all_files:\n", + " filepath = os.path.join(data_folder, file)\n", + " data = dp.Data(filepath)\n", + " print(\"{:<65} {:<15}\".format(file, data.data_type))\n", + "print(\"\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "49dfc981-59fd-48a5-ad7b-e01f0a52d0b2", + "metadata": {}, + "outputs": [], + "source": [ + "# importing from a url\n", + "data = dp.Data('https://raw.githubusercontent.com/capitalone/DataProfiler/main/dataprofiler/tests/data/csv/diamonds.csv')\n", + "data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "77f8ef2d-5aaf-44d6-b6d1-bf14f7eb7aa6", + "metadata": {}, + "source": [ + "## Specifying detection options of `Data` and loading `pandas.DataFrame`\n", + "\n", + "The `Data` class also gives the ability to set options or if the user wants to load their data with specific requirements.\n", + "Options for each data reader are specified in the docs: https://capitalone.github.io/DataProfiler/docs/0.4.4/html/dataprofiler.data_readers.html\n", + "\n", + "```python\n", + "import dataprofiler as dp\n", + "\n", + "options = {...} # allowed options are specified for each data reader.\n", + "data = dp.Data(data, options=options)\n", + "```\n", + "Later in this tutorial, the options for the CSVData class will be discussed.\n", + "\n", + "Additionally, a user can directly load a `pandas.DataFrame` as any data reader they choose." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4b925d4e-ca94-4913-9acf-26a883585e85", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from dataprofiler.data_readers.csv_data import CSVData\n", + "\n", + "\n", + "df = pd.DataFrame(['my', 'random', 'data'])\n", + "\n", + "# specify via the `Data` class\n", + "data = dp.Data(data=df, data_type='csv')\n", + "print('Data Type: ', data.data_type)\n", + "\n", + "# specifically use the CSVData class\n", + "data = CSVData(data=df)\n", + "print('Data Type: ', data.data_type)" + ] + }, + { + "cell_type": "markdown", + "id": "52c3c3ac-c241-4d91-8ac7-b3d28ffd19c3", + "metadata": {}, + "source": [ + "## Accessing data and attributes\n", + "\n", + "Once loaded, the data can be accessed via the `data` property of the object. Additional information about the data loaded may differ between data readers.\n", + "\n", + "For this example we will focus on `CSVData`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "09fa5929-e710-4107-9313-1370ab639c9c", + "metadata": {}, + "outputs": [], + "source": [ + "filepath = \"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\"\n", + "data = dp.Data(filepath)\n", + "print('Data Type: ', data.data_type)\n", + "print('Data Filepath: ', data.input_file_path)\n", + "print('File Encoding: ', data.file_encoding)\n", + "print('Data Length (two techniques): ', len(data), data.length)\n", + "print(\"Data Access:\")\n", + "data.data" + ] + }, + { + "cell_type": "markdown", + "id": "b98be971-4768-479d-9e54-00f05a6fb790", + "metadata": {}, + "source": [ + "## Checking data file types with `is_match`\n", + "\n", + "Each data reader has a class method `is_match` which determines whether or not a dataset is of a given data type.\n", + "```python\n", + "CSVData.is_match\n", + "JSONData.is_match\n", + "ParquetData.is_match\n", + "AVROData.is_match\n", + "GraphData.is_match\n", + "TextData.is_match\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "104a32c1-1d50-4aa5-94ce-b2e72de38476", + "metadata": {}, + "outputs": [], + "source": [ + "# supplemental function\n", + "def add_true_false_color(value):\n", + " \"\"\"Converts True to green and False to red in printed text.\"\"\"\n", + " if value:\n", + " return \"\\x1b[92m \" + str(is_match) + \"\\x1b[0m\"\n", + " return \"\\x1b[31m \" + str(is_match) + \"\\x1b[0m\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "06868d90-2726-4096-a6da-3866174e6671", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from dataprofiler.data_readers.csv_data import CSVData\n", + "\n", + "\n", + "non_csv_files = [\n", + " 'json/iris-utf-8.json',\n", + " 'json/honeypot_intentially_mislabeled_file.csv',\n", + " 'parquet/titanic.parq',\n", + " 'parquet/nation.plain.intentionally_mislabled_file.csv',\n", + " 'txt/code.txt',\n", + " 'txt/sentence.txt',\n", + " 'avro/users.avro',\n", + " 'avro/snappy_compressed_intentionally_mislabeled_file.csv',\n", + "]\n", + "\n", + "print(\"Is the file a CSV?\")\n", + "print('=' * 80)\n", + "for file in csv_files:\n", + " filepath = os.path.join(data_folder, file)\n", + " is_match = CSVData.is_match(filepath)\n", + " print(add_true_false_color(is_match), ':', file)\n", + " print('=' * 80)\n", + " \n", + "for file in non_csv_files:\n", + " filepath = os.path.join(data_folder, file)\n", + " is_match = CSVData.is_match(filepath)\n", + " print(add_true_false_color(is_match), ':', file)\n", + " print('=' * 80)" + ] + }, + { + "cell_type": "markdown", + "id": "38889990-8e19-4114-a4f3-dc2af938e29d", + "metadata": {}, + "source": [ + "## Reloading data after altering options with `reload`\n", + "\n", + "There are two cases for using the reload function, both of which require the data type to have been interpreted correctly:\n", + "\n", + " 1. The options were not correctly determined\n", + " 2. The options were loaded correctly but a change is desired.\n", + " \n", + "In the example below, the `data_format` for reading the data is changed and the data is then reloaded." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "01870e8d-45ee-4f33-a088-4453c7ffc7c2", + "metadata": {}, + "outputs": [], + "source": [ + "filepath = \"../dataprofiler/tests/data/csv/diamonds.csv\"\n", + "\n", + "data = dp.Data(filepath)\n", + "print('original data:')\n", + "print('=' * 80)\n", + "print(data.data[:5])\n", + "\n", + "print()\n", + "data.reload(options={'data_format': 'records', 'record_samples_per_line': 1})\n", + "print('reloaded data:')\n", + "print('=' * 80)\n", + "data.data[:5]" + ] + }, + { + "cell_type": "markdown", + "id": "e2285f19-9b34-4484-beaa-79df890b2825", + "metadata": {}, + "source": [ + "## A deeper dive into `CSVData`\n", + "\n", + "This next section will focus on how to use the data reader class: `CSVData`. The `CSVData` class is used for reading delimited data. Delimited data are datasets which have their columns specified by a specific character, commonly the `,`. E.g. from the `diamonds.csv` dataset:\n", + "```\n", + "carat,cut,color,clarity,depth,table,price,x,y,z\n", + "0.23,Ideal,E,SI2,61.5,55,326,3.95,3.98,2.43\n", + "0.21,Premium,E,SI1,59.8,61,326,3.89,3.84,2.31\n", + "0.23,Good,E,VS1,56.9,65,327,4.05,4.07,2.31\n", + "0.29,Premium,I,VS2,62.4,58,334,4.2,4.23,2.63\n", + "0.31,Good,J,SI2,63.3,58,335,4.34,4.35,2.75\n", + "```\n", + "\n", + "However, the delimiter can be any character. Additionally, a `quotechar`, commonly `\"`, can be specified which allows a delimiter to be contained within a column value.\n", + "E.g. from the `blogposts.csv` dataset:\n", + "```\n", + "Blog Post,Date,Subject,Field\n", + "\"Monty Hall, meet Game Theory\",4/13/2014,Statistics,Mathematics\n", + "Gaussian Quadrature,4/13/2014,Algorithms,Mathematics\n", + "```\n", + "Notice how `\"Monty Hall, meet Game Theory\"` is contained by the quotechar because it contains the delimiter value `,`.\n", + "\n", + "These delimiter dataset parameters (and more) can be automatically determined by the `CSVData` data reader, however they can also be set via the options as demonstrated later in this tutorial." + ] + }, + { + "cell_type": "markdown", + "id": "cccb6bf9-7fb8-46b8-992e-9caacb7ab3a8", + "metadata": {}, + "source": [ + "## Intro to the `CSVData` data reader\n", + "\n", + "Previously, it was shown that `CSVData` may automatically be detected using `Data` or can be manually specified by the user:\n", + "\n", + "```python\n", + "import dataprofiler as dp\n", + "from dataprofiler.data_readers.csv_data import CSVData\n", + "\n", + "data = dp.Data(filepath)\n", + "data = CSVData(filepath)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e25f5130-4f19-40c5-9d13-549a04f1aef5", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read delimited data \n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "csv_files = [\n", + " \"csv/diamonds.csv\",\n", + " \"csv/all-strings-skip-header-author.csv\", # csv files with the author/description on the first line\n", + " \"csv/sparse-first-and-last-column-empty-first-row.txt\", # csv file with the .txt extension\n", + "]\n", + "\n", + "for file in csv_files:\n", + " data = CSVData(os.path.join(data_folder, file))\n", + " print(data.data.head())\n", + " print('=' * 80)" + ] + }, + { + "cell_type": "markdown", + "id": "8940de56-1417-4bf6-af87-9d4d00b9a631", + "metadata": {}, + "source": [ + "## CSVData Options\n", + "\n", + "As mentioned preivously, `CSVData` has options that can be set to finetune its detection or to ensure the data is being read in a specific manner.\n", + "The options for `CSVData` are detailed below:\n", + "\n", + " * delimiter - delimiter used to decipher the csv input file\n", + " * quotechar - quote character used in the delimited file\n", + " * header - location of the header in the file.\n", + " * data_format - user selected format in which to return data can only be of specified types\n", + " * selected_columns - columns being selected from the entire dataset" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d74f2e8-0ec3-4e93-8778-0a5f013e0cdb", + "metadata": {}, + "outputs": [], + "source": [ + "# options are set via a dictionary object in which the parameters are specified.\n", + "# these are the default values for each option\n", + "options = {\n", + " \"delimiter\": \",\",\n", + " \"quotechar\": '\"',\n", + " \"header\": 'auto',\n", + " \"data_format\": \"dataframe\", # type: str, choices: \"dataframe\", \"records\"\n", + " \"selected_columns\": list(),\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "9af108a1-ffe6-4c3a-82cc-833b1a3b57a1", + "metadata": {}, + "source": [ + "## Options: delimiter and quotechar\n", + "\n", + "Below, both the auto detection and use of options will be illustrated for `delimiter` and `quotechar`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "570e20c3-198e-4356-98d3-92eb9655ef4e", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/daily-activity-sheet-@-singlequote.csv\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98385148-861e-4eb1-ba8d-e93120515401", + "metadata": {}, + "outputs": [], + "source": [ + "data = dp.Data(filepath) # or use CSVData\n", + "print('Auto detected')\n", + "print('=' * 80)\n", + "print('delimiter: ', data.delimiter)\n", + "print('quotechar: ', data.quotechar)\n", + "data.data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7f5d9306-d90a-4fc6-85a7-a0d535fe2d80", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'delimiter': '@', 'quotechar': \"'\"}\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "print('manually set')\n", + "print('=' * 80)\n", + "print('delimiter: ', data.delimiter)\n", + "print('quotechar: ', data.quotechar)\n", + "data.data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b7bfa60f-b5b9-48a5-adc5-3937aed145da", + "metadata": {}, + "outputs": [], + "source": [ + "# intentional failure with incorrect options\n", + "options = {'delimiter': ',', 'quotechar': '\"'}\n", + "\n", + "# will be interepted as TextData because the delimtier and quotechar were incorrect\n", + "data = dp.Data(filepath, options=options)\n", + "print('intentional faliure set')\n", + "print('=' * 80)\n", + "try:\n", + " print('delimiter: ', data.delimiter) # attribute error raised here, bc TextData, not CSVData\n", + " print('quotechar: ', data.quotechar)\n", + " \n", + " # should not reach this or something went wrong\n", + " raise Exception('Should have failed because this is detected as TextData.')\n", + "except AttributeError:\n", + " print('When data_type is not set or the CSVData is not set, it will fail over to the\\n'\n", + " 'next best reader. In this case it is \"TextData\"\\n')\n", + "data.data" + ] + }, + { + "cell_type": "markdown", + "id": "eeb41c7c-8319-40a3-9d87-88edbb3c5290", + "metadata": {}, + "source": [ + "## Options: header\n", + "\n", + "Below, both the auto detection and use of options will be illustrated for `header`.\n", + "\n", + "Notice how in the manually set mechanism, we are intentionally setting the header incorrectly to illustrate what happens." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16a927ef-1ba8-4bf2-ae40-2a9909030609", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/sparse-first-and-last-column-header-and-author-description.txt\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0701d7bf-2de0-4dce-8f09-7f0cddd1132c", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'header': 'auto'} # auto detected (default value)\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "print('Data Header:', data.header)\n", + "print('=' * 80)\n", + "data.data.head()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8642a0a-367a-44c6-b611-b89d97b29f85", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'header': 2} # intentionally set incorrectly at value 2\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "print('Data Header:', data.header)\n", + "print('=' * 80)\n", + "data.data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "d6e3f640-c809-4eb6-9571-30065821615e", + "metadata": {}, + "source": [ + "## Options: data_format\n", + "\n", + "For CSVData, the `data_format` option can have the following values:\n", + "\n", + " * dataframe - (default) loads the dataset as a pandas.DataFrame\n", + " * records - loads the data as rows of text values, the extra parameter `record_samples_per_line` how many rows are combined into a single line\n", + " \n", + "`dataframe` is used for conducting **structured profiling** of the dataset while `records` is for **unstructured profiling**.\n", + "\n", + "Below, both the auto detection and use of options will be illustrated for `data_format`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "146109ea-a554-4766-bb19-78c116d2a8dd", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/diamonds.csv\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dceac967-d326-4064-ba1c-87a1146c9d72", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'data_format': 'dataframe'} # default\n", + "data = dp.Data(filepath, options=options) # or use CSVData\n", + "data.data[:5]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c25524f-ef23-4e06-9023-842c64c2640e", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'data_format': 'records', 'record_samples_per_line': 1}\n", + "data = dp.Data(filepath, options=options)\n", + "data.data[:5]" + ] + }, + { + "cell_type": "markdown", + "id": "d45f3ed6-ddcd-4bf3-95bc-09f23eb94c97", + "metadata": {}, + "source": [ + "## Options: selected columns\n", + "\n", + "By default, all columns of a dataset will be read and loaded into the data reader. However, `selected_columns` can be set to only load columns which the user requests." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c9b45e18-93c6-42e6-b978-af51574307eb", + "metadata": {}, + "outputs": [], + "source": [ + "# display the data we are reading\n", + "filepath = \"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\"\n", + "num_lines = 10\n", + "with open(filepath) as fp:\n", + " print(''.join(fp.readlines()[:num_lines]))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "018f3f4d-32ac-411a-9918-bae78aff0b0e", + "metadata": {}, + "outputs": [], + "source": [ + "options = {'selected_columns': ['datetime', 'host', 'src', 'proto']}\n", + "data = dp.Data(filepath, options=options)\n", + "data.data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "b50679ea", + "metadata": {}, + "source": [ + "## Intro to `GraphData` data reader\n", + "\n", + "This tutorial will focus on how to use the data reader class: `GraphData`. The `GraphData` class is used for reading the delimited data from a CSV file into a `NetworkX` Graph object. This is all in an effort to prepare the data automaticaly for `GraphProfiler` class to then profile graph data. \n", + "\n", + "The DataProiler keys off of common graph naming conventions in the column header row. E.G. from `dataprofiler/tests/csv/graph_data_csv_identify.csv`\n", + "```\n", + "node_id_dst, node_id_src, continuous_weight, categorical_status\n", + "108,289,7.4448069,9\n", + "81,180,3.65064207,0\n", + "458,83,5.9959787,10\n", + "55,116,4.63359209,79\n", + "454,177,5.76715529,11\n", + "429,225,4.79556889,3\n", + "```\n", + "\n", + "Options for the `GraphData` are exactly the same as `CSVData`.\n", + "\n", + "\n", + "Example implementation of `GraphData`:\n", + "```python\n", + "import dataprofiler as dp\n", + "from dataprofiler.data_readers.graph_data import GraphData\n", + "\n", + "data = dp.Data(graph_file)\n", + "data = GraphData(graph_file)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "838db976", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprofiler.data_readers.graph_data import GraphData\n", + "\n", + "# use data reader to read delimited data \n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "graph_file = \"csv/graph_data_csv_identify.csv\"\n", + "\n", + "data = GraphData(os.path.join(data_folder, graph_file))\n", + "print(data.data.edges)\n", + "print('=' * 80)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/data_readers.html b/docs/0.10.3/html/data_readers.html new file mode 100644 index 000000000..ecfe251a7 --- /dev/null +++ b/docs/0.10.3/html/data_readers.html @@ -0,0 +1,452 @@ + + + + + + + + + Data Readers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data Readers

    +

    The Data class itself will identify then output one of the following Data class types. +Using the data reader is easy, just pass it through the Data object.

    +
    import dataprofiler as dp
    +data = dp.Data("your_file.csv")
    +
    +
    +

    The supported file types are:

    +
      +
    • CSV file (or any delimited file)

    • +
    • JSON object

    • +
    • Avro file

    • +
    • Parquet file

    • +
    • Graph data file

    • +
    • Text file

    • +
    • Pandas DataFrame

    • +
    • A URL that points to one of the supported file types above

    • +
    +

    It’s also possible to specifically call one of the data classes such as the following command:

    +
    from dataprofiler.data_readers.csv_data import CSVData
    +data = CSVData("your_file.csv", options={"delimiter": ","})
    +
    +
    +

    Additionally any of the data classes can be loaded using a URL:

    +
    import dataprofiler as dp
    +data = dp.Data("https://you_website.com/your_file.file", options={"verify_ssl": "True"})
    +
    +
    +

    Below are descriptions of the various Data classes and the available options.

    +
    +

    CSVData

    +

    Data class for loading datasets of type CSV. Can be specified by passing +in memory data or via a file path. Options pertaining the CSV may also +be specified using the options dict parameter.

    +

    CSVData(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • delimiter - Must be a string, for example “delimiter”: “,”

    • +
    • data_format - Must be a string, possible choices: “dataframe”, “records”

    • +
    • selected_columns - Columns being selected from the entire dataset, must be a +list [“column 1”, “ssn”]

    • +
    • sample_nrows - Reservoir sampling to sample “n” rows out of a total of “M” rows. +Specified for how many rows to sample, default None.

    • +
    • header - Define the header, for example

      +
        +
      • “header”: ‘auto’ for auto detection

      • +
      • “header”: None for no header

      • +
      • “header”: <INT> to specify the header row (0 based index)

      • +
      +
    • +
    +
    +
    +

    JSONData

    +

    Data class for loading datasets of type JSON. Can be specified by +passing in memory data or via a file path. Options pertaining the JSON +may also be specified using the options dict parameter. JSON data can be +accessed via the “data” property, the “metadata” property, and the +“data_and_metadata” property.

    +

    JSONData(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • data_format - must be a string, choices: “dataframe”, “records”, “json”, “flattened_dataframe”

      +
        +
      • “flattened_dataframe” is best used for JSON structure typically found in data streams that contain +nested lists of dictionaries and a payload. For example: {“data”: [ columns ], “response”: 200}

      • +
      +
    • +
    • selected_keys - columns being selected from the entire dataset, must be a list [“column 1”, “ssn”]

    • +
    • payload_keys - The dictionary keys for the payload of the JSON, typically called “data” +or “payload”. Defaults to [“data”, “payload”, “response”].

    • +
    +
    +
    +

    AVROData

    +

    Data class for loading datasets of type AVRO. Can be specified by +passing in memory data or via a file path. Options pertaining the AVRO +may also be specified using the options dict parameter.

    +

    AVROData(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • data_format - must be a string, choices: “dataframe”, “records”, “avro”, “json”, “flattened_dataframe”

      +
        +
      • “flattened_dataframe” is best used for AVROs with a JSON structure typically found in data streams that contain +nested lists of dictionaries and a payload. For example: {“data”: [ columns ], “response”: 200}

      • +
      +
    • +
    • selected_keys - columns being selected from the entire dataset, must be a list [“column 1”, “ssn”]

    • +
    +
    +
    +

    ParquetData

    +

    Data class for loading datasets of type PARQUET. Can be specified by +passing in memory data or via a file path. Options pertaining the +PARQUET may also be specified using the options dict parameter.

    +

    ParquetData(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • data_format - must be a string, choices: “dataframe”, “records”, “json”

    • +
    • selected_keys - columns being selected from the entire dataset, must be a list [“column 1”, “ssn”]

    • +
    +
    +
    +

    GraphData

    +

    Data Class for loading datasets of graph data. Currently takes CSV format, +further type formats will be supported. Can be specified by passing +in memory data (NetworkX Graph) or via a file path. Options pertaining the CSV file may also +be specified using the options dict parameter. Loads data from CSV into memory +as a NetworkX Graph.

    +

    GraphData(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • delimiter - must be a string, for example “delimiter”: “,”

    • +
    • data_format - must be a string, possible choices: “graph”, “dataframe”, “records”

    • +
    • header - Define the header, for example

      +
        +
      • “header”: ‘auto’ for auto detection

      • +
      • “header”: None for no header

      • +
      • “header”: <INT> to specify the header row (0 based index)

      • +
      +
    • +
    +
    +
    +

    TextData

    +

    Data class for loading datasets of type TEXT. Can be specified by +passing in memory data or via a file path. Options pertaining the TEXT +may also be specified using the options dict parameter.

    +

    TextData(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • data_format: user selected format in which to return data. Currently only supports “text”.

    • +
    • samples_per_line - chunks by which to read in the specified dataset

    • +
    +
    +
    +

    Data Using a URL

    +

    Data class for loading datasets of any type using a URL. Specified by passing in +any valid URL that points to one of the valid data types. Options pertaining the +URL may also be specified using the options dict parameter.

    +

    Data(input_file_path=None, data=None, options=None)

    +

    Possible options:

    +
      +
    • verify_ssl: must be a boolean string, choices: “True”, “False”. Set to “True” by default.

    • +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.avro_data.html b/docs/0.10.3/html/dataprofiler.data_readers.avro_data.html new file mode 100644 index 000000000..ecfa60a16 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.avro_data.html @@ -0,0 +1,409 @@ + + + + + + + + + Avro Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Avro Data

    +

    Contains class for saving and loading spreadsheet data.

    +
    +
    +class dataprofiler.data_readers.avro_data.AVROData(input_file_path: Optional[str] = None, data: Optional[Any] = None, options: Optional[Dict] = None)
    +

    Bases: dataprofiler.data_readers.json_data.JSONData, dataprofiler.data_readers.base_data.BaseData

    +

    AVROData class to save and load spreadsheet data.

    +

    Initialize Data class for loading datasets of type AVRO.

    +

    Can be specified by passing in memory data or via a file path. +Options pertaining to AVRO may also be specified using options dict param. +Possible Options:

    +
    options = dict(
    +    data_format= type: str, choices: "dataframe", "records", "avro"
    +    selected_keys= type: list(str)
    +)
    +
    +
    +

    data_format: user selected format can only be of specified types +selected_keys: keys being selected from the entire dataset

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str = 'avro'
    +
    +
    +
    +property file_encoding: Optional[str]
    +

    Set file encoding to None since not detected for avro.

    +
    +
    +
    +classmethod is_match(file_path: Union[str, _io.StringIO, _io.BytesIO], options: Optional[Dict] = None) bool
    +

    Test the given file to check if the file has valid AVRO format or not.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the file to be examined

    • +
    • options (dict) – avro read options

    • +
    +
    +
    Returns
    +

    is file a avro file or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_and_metadata: Optional[pandas.core.frame.DataFrame]
    +

    Return a data frame that joins the data and the metadata.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +property is_structured
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    +property metadata: Optional[pandas.core.frame.DataFrame]
    +

    Return a data frame that contains the metadata.

    +
    +
    +
    +reload(input_file_path: Optional[str] = None, data: Optional[Union[pandas.core.frame.DataFrame, str]] = None, options: Optional[Dict] = None) None
    +

    Reload the data class with a new dataset.

    +

    This erases all existing data/options and replaces it +with the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property selected_keys: Optional[List[str]]
    +

    Return selected keys.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.base_data.html b/docs/0.10.3/html/dataprofiler.data_readers.base_data.html new file mode 100644 index 000000000..fad8cb431 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.base_data.html @@ -0,0 +1,371 @@ + + + + + + + + + Base Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Base Data

    +

    Contains abstract class for data loading and saving.

    +
    +
    +class dataprofiler.data_readers.base_data.BaseData(input_file_path: Optional[str], data: Any, options: Dict)
    +

    Bases: object

    +

    Abstract class for data loading and saving.

    +

    Initialize Base class for loading a dataset.

    +

    Options can be specified and maybe +more specific to the subclasses.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str
    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +property is_structured: bool
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +property file_encoding: Optional[str]
    +

    Return file encoding.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +classmethod is_match(input_file_path: str, options: Optional[Dict]) bool
    +

    Return true if match, false otherwise.

    +
    +
    +
    +reload(input_file_path: Optional[str], data: Any, options: Optional[Dict]) None
    +

    Reload the data class with a new dataset.

    +

    This erases all existing +data/options and replaces it with the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.csv_data.html b/docs/0.10.3/html/dataprofiler.data_readers.csv_data.html new file mode 100644 index 000000000..6fbcad106 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.csv_data.html @@ -0,0 +1,438 @@ + + + + + + + + + CSV Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    CSV Data

    +

    Contains class that saves and loads spreadsheet data.

    +
    +
    +class dataprofiler.data_readers.csv_data.CSVData(input_file_path: Optional[str] = None, data: Optional[pandas.core.frame.DataFrame] = None, options: Optional[Dict] = None)
    +

    Bases: dataprofiler.data_readers.structured_mixins.SpreadSheetDataMixin, dataprofiler.data_readers.base_data.BaseData

    +

    SpreadsheetData class to save and load spreadsheet data.

    +

    Initialize Data class for loading datasets of type CSV.

    +

    Can be specified by passing in memory data or via a file path. +Options pertaining to CSV may also be specified using options dict param. +Possible Options:

    +
    options = dict(
    +    delimiter= type: str
    +    data_format= type: str, choices: "dataframe", "records"
    +    record_samples_per_line= type: int (only for "records")
    +    selected_columns= type: list(str)
    +    header= type: any
    +)
    +
    +
    +

    delimiter: delimiter used to decipher the csv input file +data_format: user selected format in which to return data +can only be of specified types: +``` +dataframe - (default) loads the dataset as a pandas.DataFrame +records - loads the data as rows of text values, the extra parameter

    +
    +

    “record_samples_per_line” determines how many rows are combined into +a single line

    +
    +

    ``` +selected_columns: columns being selected from the entire dataset +header: location of the header in the file +quotechar: quote character used in the delimited file

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str = 'csv'
    +
    +
    +
    +property selected_columns: List[str]
    +

    Return selected columns.

    +
    +
    +
    +property delimiter: Optional[str]
    +

    Return delimiter.

    +
    +
    +
    +property quotechar: Optional[str]
    +

    Return quotechar.

    +
    +
    +
    +property header: Optional[Union[str, int]]
    +

    Return header.

    +
    +
    +
    +property sample_nrows: Optional[int]
    +

    Return sample_nrows.

    +
    +
    +
    +property is_structured: bool
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +property file_encoding: Optional[str]
    +

    Return file encoding.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +classmethod is_match(file_path: str, options: Optional[Dict] = None) bool
    +

    Check if first 1000 lines of given file has valid delimited format.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the file to be examined

    • +
    • options (dict) – delimiter read options dict(delimiter=”,”)

    • +
    +
    +
    Returns
    +

    is file a csv file or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    +options: Optional[Dict]
    +
    +
    +
    +reload(input_file_path: Optional[str] = None, data: Optional[pandas.core.frame.DataFrame] = None, options: Optional[Dict] = None)
    +

    Reload the data class with a new dataset.

    +

    This erases all existing data/options and replaces it with +the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.data.html b/docs/0.10.3/html/dataprofiler.data_readers.data.html new file mode 100644 index 000000000..81688bb2a --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.data.html @@ -0,0 +1,310 @@ + + + + + + + + + Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data

    +

    Contains factory class reading various kinds of data.

    +
    +
    +class dataprofiler.data_readers.data.Data(input_file_path: Optional[Union[str, _io.BytesIO]] = None, data: Optional[Any] = None, data_type: Optional[str] = None, options: Optional[Dict] = None)
    +

    Bases: object

    +

    Factory class for reading various kinds of data.

    +

    Create Factory Data object.

    +

    Auto-detection of data type if not specified for input files. +Returns the proper data class or specified data class for +the given data or input file.

    +
    +
    Parameters
    +
      +
    • input_file_path

    • +
    • data

    • +
    • data_type

    • +
    • options

    • +
    +
    +
    Returns
    +

    +
    +
    +
    +
    +data_classes: List[Dict] = [{'data_class': <class 'dataprofiler.data_readers.json_data.JSONData'>, 'kwargs': {}}, {'data_class': <class 'dataprofiler.data_readers.graph_data.GraphData'>, 'kwargs': {}}, {'data_class': <class 'dataprofiler.data_readers.csv_data.CSVData'>, 'kwargs': {}}, {'data_class': <class 'dataprofiler.data_readers.parquet_data.ParquetData'>, 'kwargs': {}}, {'data_class': <class 'dataprofiler.data_readers.avro_data.AVROData'>, 'kwargs': {}}, {'data_class': <class 'dataprofiler.data_readers.text_data.TextData'>, 'kwargs': {}}]
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.data_utils.html b/docs/0.10.3/html/dataprofiler.data_readers.data_utils.html new file mode 100644 index 000000000..5d674f48c --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.data_utils.html @@ -0,0 +1,656 @@ + + + + + + + + + Data Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data Utils

    +

    Contains functions for data readers.

    +
    +
    +dataprofiler.data_readers.data_utils.data_generator(data_list: List[str]) Generator[str, None, None]
    +

    Take a list and return a generator on the list.

    +
    +
    Parameters
    +

    data_list (list) – list of strings

    +
    +
    Returns
    +

    item from the list

    +
    +
    Return type
    +

    generator

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.generator_on_file(file_object: Union[_io.StringIO, _io.BytesIO]) Generator[Union[str, bytes], None, None]
    +

    Take a file and return a generator that returns lines.

    +
    +
    Parameters
    +

    file_path (path) – path to the file

    +
    +
    Returns
    +

    Line from file

    +
    +
    Return type
    +

    generator

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.convert_int_to_string(x: int) str
    +

    Convert the given input to string.

    +

    In particular, it is int, it converts it ensuring there is no . or 00. +In addition, if the input is np.nan, the output will be ‘nan’ which is +what we need to handle data properly.

    +
    +
    Parameters
    +

    x (Union[int, float, str, numpy.nan]) –

    +
    +
    Returns
    +

    +
    +
    Return type
    +

    str

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.unicode_to_str(data: Union[str, int, float, bool, None, List, Dict], ignore_dicts: bool = False) Union[str, int, float, bool, None, List, Dict]
    +

    Convert data to string representation if it is a unicode string.

    +
    +
    Parameters
    +
      +
    • data (JSONType) – input data

    • +
    • ignore_dicts (boolean) – if set, ignore the dictionary type processing

    • +
    +
    +
    Returns
    +

    string representation of data

    +
    +
    Return type
    +

    str

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.json_to_dataframe(json_lines: List[Union[str, int, float, bool, None, List, Dict]], selected_columns: Optional[List[str]] = None, read_in_string: bool = False) Tuple[pandas.core.frame.DataFrame, pandas.core.series.Series]
    +

    Take list of json objects and return dataframe representing json list.

    +
    +
    Parameters
    +
      +
    • json_lines (list(JSONType)) – list of json objects

    • +
    • selected_columns (list(str)) – a list of keys to be processed

    • +
    • read_in_string (bool) – if True, all the values in dataframe will be +converted to string

    • +
    +
    +
    Returns
    +

    dataframe converted from json list and list of dtypes for each +column

    +
    +
    Return type
    +

    tuple(pd.DataFrame, pd.Series(dtypes))

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.read_json_df(data_generator: Generator, selected_columns: Optional[List[str]] = None, read_in_string: bool = False) Tuple[pandas.core.frame.DataFrame, pandas.core.series.Series]
    +

    Return an iterator that returns a chunk of data as dataframe in each call.

    +

    The source of input to this function is either a +file or a list of JSON structured strings. If the file path is given as +input, the file is expected to have one JSON structures in each line. The +lines that are not valid json will be ignored. Therefore, a file with +pretty printed JSON objects will not be considered valid JSON. If the +input is a data list, it is expected to be a list of strings where each +string is a valid JSON object. if the individual object is not valid +JSON, it will be ignored.

    +

    NOTE: both data_list and file_path cannot be passed at the same time.

    +
    +
    Parameters
    +
      +
    • data_generator (generator) – The generator you want to read.

    • +
    • selected_columns (list(str)) – a list of keys to be processed

    • +
    • read_in_string (bool) – if True, all the values in dataframe will be +converted to string

    • +
    +
    +
    Returns
    +

    returns an iterator that returns a chunk of file as dataframe in +each call as well as original dtypes of the dataframe columns.

    +
    +
    Return type
    +

    tuple(pd.DataFrame, pd.Series(dtypes))

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.read_json(data_generator: Iterator, selected_columns: Optional[List[str]] = None, read_in_string: bool = False) List[Union[str, int, float, bool, None, List, Dict]]
    +

    Return the lines of a json.

    +

    The source of input to this function is either a file or +a list of JSON structured strings. +If the file path is given as input, the file is expected to have one JSON +structures in each line. The lines that are not valid json will be ignored. +Therefore, a file with pretty printed JSON objects will not be considered +valid JSON. If the input is a data list, it is expected to be a list of +strings where each string is a valid JSON object. if the individual object +is not valid JSON, it will be ignored.

    +

    NOTE: both data_list and file_path cannot be passed at the same time.

    +
    +
    Parameters
    +
      +
    • data_generator (generator) – The generator you want to read.

    • +
    • selected_columns (list(str)) – a list of keys to be processed

    • +
    • read_in_string (bool) – if True, all the values in dataframe will be +converted to string

    • +
    +
    +
    Returns
    +

    returns the lines of a json file

    +
    +
    Return type
    +

    list(dict)

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.reservoir(file: _io.TextIOWrapper, sample_nrows: int) list
    +

    Implement the mathematical logic of Reservoir sampling.

    +
    +
    Parameters
    +
      +
    • file (TextIOWrapper) – wrapper of the opened csv file

    • +
    • sample_nrows (int) – number of rows to sample

    • +
    +
    +
    Raises
    +

    ValueError()

    +
    +
    Returns
    +

    sampled values

    +
    +
    Return type
    +

    list

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.rsample(file_path: _io.TextIOWrapper, sample_nrows: int, args: dict) _io.StringIO
    +

    Implement Reservoir Sampling to sample n rows out of a total of M rows.

    +
    +
    Parameters
    +
      +
    • file_path (TextIOWrapper) – path of the csv file to be read in

    • +
    • sample_nrows (int) – number of rows being sampled

    • +
    • args (dict) – options to read the csv file

    • +
    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.read_csv_df(file_path: Union[str, _io.BytesIO, _io.TextIOWrapper], delimiter: Optional[str], header: Optional[int], sample_nrows: Optional[int] = None, selected_columns: List[str] = [], read_in_string: bool = False, encoding: Optional[str] = 'utf-8') pandas.core.frame.DataFrame
    +

    Read a CSV file in chunks and return dataframe in form of iterator.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the CSV file.

    • +
    • delimiter (str) – character used to separate csv values.

    • +
    • header (int) – the header row in the csv file.

    • +
    • selected_columns (list(str)) – a list of columns to be processed

    • +
    • read_in_string (bool) – if True, all the values in dataframe will be +converted to string

    • +
    +
    +
    Returns
    +

    Iterator

    +
    +
    Return type
    +

    pd.DataFrame

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.read_parquet_df(file_path: str, selected_columns: Optional[List[str]] = None, read_in_string: bool = False) Tuple[pandas.core.frame.DataFrame, pandas.core.series.Series]
    +

    Return an iterator that returns one row group each time.

    +
    +
    Parameters
    +

    file_path (str) – path to the Parquet file.

    +
    +
    Returns
    +

    +
    +
    Return type
    +

    Iterator(pd.DataFrame)

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.read_text_as_list_of_strs(file_path: str, encoding: Optional[str] = None) List[str]
    +

    Return list of strings relative to the chunk size.

    +

    Each line is 1 chunk.

    +
    +
    Parameters
    +

    file_path (str) – path to the file

    +
    +
    Returns
    +

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.detect_file_encoding(file_path: str, buffer_size: int = 1024, max_lines: int = 20) str
    +

    Determine encoding of files within initial max_lines of length buffer_size.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the file

    • +
    • buffer_size (int) – buffer length for each line being read

    • +
    • max_lines (int) – number of lines to read from file of length buffer_size

    • +
    +
    +
    Returns
    +

    encoding type

    +
    +
    Return type
    +

    str

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.detect_cell_type(cell: str) str
    +

    Detect the cell type (int, float, etc).

    +
    +
    Parameters
    +

    cell (str) – String designated for data type detection

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.get_delimiter_regex(delimiter: str = ',', quotechar: str = ',') Pattern[str]
    +

    Build regex for delimiter checks.

    +
    +
    Parameters
    +
      +
    • delimiter (str) – Delimiter to be added to regex

    • +
    • quotechar – Quotechar to be added to regex

    • +
    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.find_nth_loc(string: Optional[str] = None, search_query: Optional[str] = None, n: int = 0, ignore_consecutive: bool = True) Tuple[int, int]
    +

    Search string via search_query and return nth index in which query occurs.

    +

    If there are less than ‘n’ the last loc is returned

    +
    +
    Parameters
    +
      +
    • string (str) – Input string, to be searched

    • +
    • search_query (str) – char(s) to find nth occurrence of

    • +
    • n (int) – The number of occurrences to iterate through

    • +
    • ignore_consecutive (bool) – Ignore consecutive matches in the search query.

    • +
    +
    +
    Return idx
    +

    Index of the nth or last occurrence of the search_query

    +
    +
    Rtype idx
    +

    int

    +
    +
    Return id_count
    +

    Number of identifications prior to idx

    +
    +
    Rtype id_count
    +

    int

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.load_as_str_from_file(file_path: str, file_encoding: Optional[str] = None, max_lines: int = 10, max_bytes: int = 65536, chunk_size_bytes: int = 1024) str
    +

    Load data from a csv file up to a specific line OR byte_size.

    +
    +
    Parameters
    +
      +
    • file_path (str) – Path to file to load data from

    • +
    • file_encoding (str) – File encoding

    • +
    • max_lines (int) – Maximum number of lines to load from file

    • +
    • max_bytes (int) – Maximum number of bytes to load from file

    • +
    • chunk_size_bytes (int) – Chunk size to load every data load

    • +
    +
    +
    Returns
    +

    Data as string

    +
    +
    Return type
    +

    str

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.is_valid_url(url_as_string: Any) typing_extensions.TypeGuard[Url]
    +

    Determine whether a given string is a valid URL.

    +
    +
    Parameters
    +

    url_as_string (str) – string to be tested if URL

    +
    +
    Returns
    +

    true if string is a valid URL

    +
    +
    Return type
    +

    boolean

    +
    +
    +
    +
    +
    +dataprofiler.data_readers.data_utils.url_to_bytes(url_as_string: Url, options: Dict) _io.BytesIO
    +

    Read in URL and converts it to a byte stream.

    +
    +
    Parameters
    +
      +
    • url_as_string (str) – string to read as URL

    • +
    • options (dict) – options for the url

    • +
    +
    +
    Returns
    +

    BytesIO stream of data downloaded from URL

    +
    +
    Return type
    +

    BytesIO stream

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.filepath_or_buffer.html b/docs/0.10.3/html/dataprofiler.data_readers.filepath_or_buffer.html new file mode 100644 index 000000000..2195b7942 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.filepath_or_buffer.html @@ -0,0 +1,321 @@ + + + + + + + + + Filepath Or Buffer - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Filepath Or Buffer

    +

    Contains functions and classes for handling filepaths and buffers.

    +
    +
    +dataprofiler.data_readers.filepath_or_buffer.is_stream_buffer(filepath_or_buffer: Any) typing_extensions.TypeGuard[Union[_io.StringIO, _io.BytesIO]]
    +

    Determine whether a given argument is a filepath or buffer.

    +
    +
    Parameters
    +

    filepath_or_buffer (str) – path to the file or buffer

    +
    +
    Returns
    +

    true if string is a buffer or false if string is a filepath

    +
    +
    Return type
    +

    boolean

    +
    +
    +
    +
    +
    +class dataprofiler.data_readers.filepath_or_buffer.FileOrBufferHandler(filepath_or_buffer: Union[str, _io.StringIO, _io.BytesIO], open_method: str = 'r', encoding: Optional[str] = None, seek_offset: Optional[int] = None, seek_whence: int = 0)
    +

    Bases: object

    +

    FileOrBufferHandler class to read a filepath or buffer in.

    +

    Always returns a readable buffer.

    +

    Initialize Context manager class.

    +

    Used for inputting a file or buffer and returning +a structure that is always a buffer.

    +
    +
    Parameters
    +
      +
    • filepath_or_buffer (Union[str, StringIO, BytesIO]) – path to the file being loaded or buffer

    • +
    • open_method (string) – value describes the mode the file is opened in

    • +
    • seek_offset (int) – offset from start of the stream

    • +
    +
    +
    Returns
    +

    TextIOBase or BufferedIOBase class/subclass

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.graph_data.html b/docs/0.10.3/html/dataprofiler.data_readers.graph_data.html new file mode 100644 index 000000000..0b18ab7b0 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.graph_data.html @@ -0,0 +1,415 @@ + + + + + + + + + Graph Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Graph Data

    +

    Contains class for identifying, reading, and loading graph data.

    +
    +
    +class dataprofiler.data_readers.graph_data.GraphData(input_file_path: Optional[str] = None, data: Optional[networkx.classes.graph.Graph] = None, options: Optional[Dict] = None)
    +

    Bases: dataprofiler.data_readers.base_data.BaseData

    +

    GraphData class to identify, read, and load graph data.

    +

    Initialize Data class for identifying, reading, and loading graph data.

    +

    Current implementation only accepts file path as input. +An options parameter is also passed in to specify properties of the +input file.

    +

    Possible Options:

    +
    options = dict(
    +    delimiter= type: str
    +    column_names= type: list(str)
    +    source_node= type: int
    +    destination_node= type: int
    +    target_keywords= type: list(str)
    +    source_keywords= type: list(str)
    +    header= type: any
    +    quotechar= type: str
    +)
    +
    +
    +

    delimiter: delimiter used to decipher the csv input file +column_names: list of column names of the csv +source_node: index of the source node column, range of (0,n-1) +target_node: index of the target node column, range of (0,n-1) +target_keywords: list of keywords to identify target/destination node col +source_keywords: list of keywords to identify source node col +graph_keywords: list of keywords to identify if data has graph data +header: location o the header in the file +quotechar: quote character used in the delimited file

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str = 'graph'
    +
    +
    +
    +classmethod csv_column_names(file_path: str, header: Optional[int], delimiter: Optional[str], encoding: str = 'utf-8') List[str]
    +

    Fetch a list of column names from the csv file.

    +
    +
    +
    +classmethod is_match(file_path: str, options: Optional[Dict] = None) bool
    +

    Determine whether the file is a graph.

    +
    +
    Current formats checked:
      +
    • attributed edge list

    • +
    +
    +
    +

    This works by finding whether the file contains a target and a source node

    +
    +
    +
    +check_integer(string: str) Union[int, str]
    +

    Check whether string is integer and output integer.

    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +property file_encoding: Optional[str]
    +

    Return file encoding.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +property is_structured: bool
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    +reload(input_file_path: Optional[str], data: Any, options: Optional[Dict]) None
    +

    Reload the data class with a new dataset.

    +

    This erases all existing +data/options and replaces it with the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +options: Optional[Dict]
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.html b/docs/0.10.3/html/dataprofiler.data_readers.html new file mode 100644 index 000000000..bed464656 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.html @@ -0,0 +1,324 @@ + + + + + + + + + Data Readers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    + + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.json_data.html b/docs/0.10.3/html/dataprofiler.data_readers.json_data.html new file mode 100644 index 000000000..a56ba4d80 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.json_data.html @@ -0,0 +1,420 @@ + + + + + + + + + JSON Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    JSON Data

    +

    Contains class to save and load json data.

    +
    +
    +class dataprofiler.data_readers.json_data.JSONData(input_file_path: Optional[str] = None, data: Optional[Union[pandas.core.frame.DataFrame, str]] = None, options: Optional[Dict] = None)
    +

    Bases: dataprofiler.data_readers.structured_mixins.SpreadSheetDataMixin, dataprofiler.data_readers.base_data.BaseData

    +

    SpreadsheetData class to save and load spreadsheet data.

    +

    Initialize Data class for loading datasets of type JSON.

    +

    Can be specified by passing in memory data or via a file path. +Options pertaining the JSON may also be specified using the +options dict parameter. +Possible Options:

    +
    options = dict(
    +    data_format= type: str, choices: "dataframe", "records", "json",
    +     "flattened_dataframe"
    +    selected_keys= type: list(str)
    +    payload_keys= type: Union[str, list(str)]
    +)
    +
    +
    +

    data_format: user selected format in which to return data +can only be of specified types +selected_keys: keys being selected from the entire dataset +payload_keys: list of dictionary keys that determine the payload

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str = 'json'
    +
    +
    +
    +property selected_keys: Optional[List[str]]
    +

    Return selected keys.

    +
    +
    +
    +property metadata: Optional[pandas.core.frame.DataFrame]
    +

    Return a data frame that contains the metadata.

    +
    +
    +
    +property data_and_metadata: Optional[pandas.core.frame.DataFrame]
    +

    Return a data frame that joins the data and the metadata.

    +
    +
    +
    +property is_structured
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +classmethod is_match(file_path: Union[str, _io.StringIO], options: Optional[Dict] = None) bool
    +

    Test whether first 1000 lines of file has valid JSON format or not.

    +

    At least 60 percent of the lines in the first 1000 +lines have to be valid json.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the file to be examined

    • +
    • options (dict) – json read options

    • +
    +
    +
    Returns
    +

    is file a json file or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +property file_encoding: Optional[str]
    +

    Return file encoding.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    +reload(input_file_path: Optional[str] = None, data: Optional[Union[pandas.core.frame.DataFrame, str]] = None, options: Optional[Dict] = None) None
    +

    Reload the data class with a new dataset.

    +

    This erases all existing data/options and replaces it +with the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +options: Optional[Dict]
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.parquet_data.html b/docs/0.10.3/html/dataprofiler.data_readers.parquet_data.html new file mode 100644 index 000000000..26ab67a91 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.parquet_data.html @@ -0,0 +1,405 @@ + + + + + + + + + Parquet Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Parquet Data

    +

    Contains class to save and load parquet data.

    +
    +
    +class dataprofiler.data_readers.parquet_data.ParquetData(input_file_path: Optional[str] = None, data: Optional[Union[pandas.core.frame.DataFrame, str]] = None, options: Optional[Dict] = None)
    +

    Bases: dataprofiler.data_readers.structured_mixins.SpreadSheetDataMixin, dataprofiler.data_readers.base_data.BaseData

    +

    SpreadsheetData class to save and load parquet data.

    +

    Initialize Data class for loading datasets of type PARQUET.

    +

    Can be specified by passing in memory data or via a file path. +Options pertaining to PARQUET may also be specified using options dict param. +Possible Options:

    +
    options = dict(
    +    data_format= type: str, choices: "dataframe", "records", "json"
    +    selected_columns= type: list(str)
    +    header= type: any
    +)
    +
    +
    +

    data_format: user selected format in which to return data +can only be of specified types +selected_columns: columns being selected from the entire dataset

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str = 'parquet'
    +
    +
    +
    +property file_encoding: None
    +

    Set file encoding to None since not detected for avro.

    +
    +
    +
    +property selected_columns: List[str]
    +

    Return selected columns.

    +
    +
    +
    +property is_structured: bool
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +classmethod is_match(file_path: Union[str, _io.StringIO, _io.BytesIO], options: Optional[Dict] = None) bool
    +

    Test the given file to check if the file has valid Parquet format.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the file to be examined

    • +
    • options (dict) – parquet read options

    • +
    +
    +
    Returns
    +

    is file a parquet file or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    +reload(input_file_path: Optional[str] = None, data: Optional[Any] = None, options: Optional[Dict] = None) None
    +

    Reload the data class with a new dataset.

    +

    This erases all existing data/options and replaces it +with the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +options: Optional[Dict]
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.structured_mixins.html b/docs/0.10.3/html/dataprofiler.data_readers.structured_mixins.html new file mode 100644 index 000000000..402ce1369 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.structured_mixins.html @@ -0,0 +1,304 @@ + + + + + + + + + Structured Mixins - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Structured Mixins

    +

    Contains mixin data class for loading datasets of tye SpreadSheet.

    +
    +
    +class dataprofiler.data_readers.structured_mixins.SpreadSheetDataMixin(input_file_path: Optional[str], data: Any, options: Dict)
    +

    Bases: object

    +

    Mixin data class for loading datasets of type SpreadSheet.

    +

    Can be specified. +Adds specialized functions for loading data from a string or file.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +

    Initialize spreadsheet mixin object.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.data_readers.text_data.html b/docs/0.10.3/html/dataprofiler.data_readers.text_data.html new file mode 100644 index 000000000..0e38f96a9 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.data_readers.text_data.html @@ -0,0 +1,410 @@ + + + + + + + + + Text Data - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Text Data

    +

    Contains class for saving and loading text files.

    +
    +
    +class dataprofiler.data_readers.text_data.TextData(input_file_path: Optional[str] = None, data: Optional[List[str]] = None, options: Optional[Dict] = None)
    +

    Bases: dataprofiler.data_readers.base_data.BaseData

    +

    TextData class to save and load text files.

    +

    Initialize Data class for loading datasets of type TEXT.

    +

    Can be specified by +passing in memory data or via a file path. Options pertaining the TEXT +may also be specified using the options dict parameter. +Possible Options:

    +
    options = dict(
    +    data_format= type: str, choices: "text"
    +    samples_per_line= type: int
    +)
    +
    +
    +

    data_format: user selected format in which to return data +can only be of specified types +samples_per_line: chunks by which to read in the specified dataset

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +data_type: str = 'text'
    +
    +
    +
    +property samples_per_line: int
    +

    Return samples per line.

    +
    +
    +
    +property is_structured: bool
    +

    Determine compatibility with StructuredProfiler.

    +
    +
    +
    +tokenize() None
    +

    Tokenize data.

    +
    +
    +
    +classmethod is_match(file_path: str, options: Optional[Dict] = None) bool
    +

    Return True if all are text files.

    +
    +
    Parameters
    +
      +
    • file_path (str) – path to the file to be examined

    • +
    • options (dict) – text file read options

    • +
    +
    +
    Returns
    +

    is file a text file or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +reload(input_file_path: Optional[str] = None, data: Optional[List[str]] = None, options: Optional[Dict] = None) None
    +

    Reload the data class with a new dataset.

    +

    This erases all existing +data/options and replaces it with the input data/options.

    +
    +
    Parameters
    +
      +
    • input_file_path (str) – path to the file being loaded or None

    • +
    • data (multiple types) – data being loaded into the class instead of an input file

    • +
    • options (dict) – options pertaining to the data type

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property data
    +

    Return data.

    +
    +
    +
    +property data_format: Optional[str]
    +

    Return data format.

    +
    +
    +
    +property file_encoding: Optional[str]
    +

    Return file encoding.

    +
    +
    +
    +get_batch_generator(batch_size: int) Generator[Union[pandas.core.frame.DataFrame, List], None, None]
    +

    Get batch generator.

    +
    +
    +
    +info: Optional[str] = None
    +
    +
    +
    +property length: int
    +

    Return the length of the dataset which is loaded.

    +
    +
    Returns
    +

    length of the dataset

    +
    +
    +
    +
    +
    +options: Optional[Dict]
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.dp_logging.html b/docs/0.10.3/html/dataprofiler.dp_logging.html new file mode 100644 index 000000000..bbdbd2aef --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.dp_logging.html @@ -0,0 +1,298 @@ + + + + + + + + + Dp Logging - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Dp Logging

    +

    Utility funcs allowing alteration of logging level/verbosity within dp lib.

    +
    +
    +dataprofiler.dp_logging.get_logger()
    +

    Access DataProfiler-specific logger.

    +
    +
    +
    +dataprofiler.dp_logging.set_verbosity(level)
    +

    Set verbosity level for DataProfiler logger.

    +

    Must set it to one of the following values: +[logging.NOTSET, logging.DEBUG, logging.INFO,

    +
    +

    logging.WARNING, logging.ERROR, logging.CRITICAL]

    +
    +
    +
    Parameters
    +

    level (int) – Verbosity level from logging module

    +
    +
    +
    +
    +
    +dataprofiler.dp_logging.get_child_logger(name)
    +

    Return logger for the given filepath.

    +
    +
    Parameters
    +

    name (str) – name of file in need of accessing child logger

    +
    +
    Returns
    +

    Logger instance for given file

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.html b/docs/0.10.3/html/dataprofiler.html new file mode 100644 index 000000000..6d985928c --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.html @@ -0,0 +1,383 @@ + + + + + + + + + Dataprofiler - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    + + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.base_data_labeler.html b/docs/0.10.3/html/dataprofiler.labelers.base_data_labeler.html new file mode 100644 index 000000000..6a7d454f2 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.base_data_labeler.html @@ -0,0 +1,909 @@ + + + + + + + + + Base Data Labeler - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Base Data Labeler

    +

    Contains abstract classes from which labeler classes will inherit.

    +
    +
    +class dataprofiler.labelers.base_data_labeler.BaseDataLabeler(dirpath: Optional[str] = None, load_options: Optional[dict] = None)
    +

    Bases: object

    +

    Parent class for data labeler objects.

    +

    Initialize DataLabeler class.

    +
    +
    Parameters
    +
      +
    • dirpath – path to data labeler

    • +
    • load_options – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    +
    +
    +help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict
    +

    Retrieve the label encodings.

    +
    +
    Returns
    +

    dictionary for associating labels to indexes

    +
    +
    +
    +
    +
    +property reverse_label_mapping: dict
    +

    Retrieve the index to label encoding.

    +
    +
    Returns
    +

    dictionary for associating indexes to labels

    +
    +
    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +property preprocessor: data_processing.BaseDataPreprocessor | None
    +

    Retrieve the data preprocessor.

    +
    +
    Returns
    +

    returns the preprocessor instance

    +
    +
    +
    +
    +
    +property model: dataprofiler.labelers.base_model.BaseModel
    +

    Retrieve the data labeler model.

    +
    +
    Returns
    +

    returns the model instance

    +
    +
    +
    +
    +
    +property postprocessor: data_processing.BaseDataPostprocessor | None
    +

    Retrieve the data postprocessor.

    +
    +
    Returns
    +

    returns the postprocessor instance

    +
    +
    +
    +
    +
    +set_params(params: dict) None
    +

    Allow user to set parameters of pipeline components.

    +
    +
    Done in the following format:
    +
    params = dict(

    preprocessor=dict(…), +model=dict(…), +postprocessor=dict(…)

    +
    +
    +

    )

    +
    +
    +

    where the key,values pairs for each pipeline component must match +parameters that exist in their components.

    +
    +
    Parameters
    +

    params (dict) –

    dictionary containing a key for a given pipeline +component and its associated value of parameters as such:

    +
    +

    dict(preprocessor=dict(…), model=dict(…), +postprocessor=dict(…))

    +
    +

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +add_label(label: str, same_as: Optional[str] = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_labels(labels: list | dict) None
    +

    Set the labels for the data labeler.

    +
    +
    Parameters
    +

    labels (list or dict) – new labels in either encoding list or dict

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +predict(data: DataArray, batch_size: int = 32, predict_options: dict[str, bool] = None, error_on_mismatch: bool = False, verbose: bool = True) dict
    +

    Predict labels of input data based with the data labeler model.

    +
    +
    Parameters
    +
      +
    • data (Union[pd.DataFrame, pd.Series, np.ndarray]) – data to be predicted upon

    • +
    • batch_size (int) – batch size of prediction

    • +
    • predict_options (Dict[str, bool]) – optional parameters to allow for predict as a +dict, i.e. dict(show_confidences=True)

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    predictions

    +
    +
    Return type
    +

    Dict

    +
    +
    +
    +
    +
    +set_preprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPreprocessor) None
    +

    Set the data preprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPreprocessor) – processor to set as the preprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_model(model: dataprofiler.labelers.base_model.BaseModel) None
    +

    Set the model for the data labeler.

    +
    +
    Parameters
    +

    model (base_model.BaseModel) – model to use within the data labeler

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_postprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) None
    +

    Set the data postprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPostprocessor) – processor to set as the postprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +check_pipeline(skip_postprocessor: bool = False, error_on_mismatch: bool = False) None
    +

    Check whether the processors and models connect together without error.

    +
    +
    Parameters
    +
      +
    • skip_postprocessor (bool) – skip checking postprocessor is valid in +pipeline

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from the data labeler zoo in the library.

    +
    +
    Parameters
    +

    name (str) – name of the data labeler.

    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str, load_options: Optional[dict] = None) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a saved location on disk.

    +
    +
    Parameters
    +
      +
    • dirpath (str) – path to data labeler files.

    • +
    • load_options (dict) – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_with_components(preprocessor: dataprofiler.labelers.data_processing.BaseDataPreprocessor, model: dataprofiler.labelers.base_model.BaseModel, postprocessor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a its set of components.

    +
    +
    Parameters
    +
    +
    +
    Returns
    +

    loaded BaseDataLabeler

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save the data labeler to the specified location.

    +
    +
    Parameters
    +

    dirpath (str) – location to save the data labeler.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +
    +class dataprofiler.labelers.base_data_labeler.TrainableDataLabeler(dirpath: Optional[str] = None, load_options: Optional[dict] = None)
    +

    Bases: dataprofiler.labelers.base_data_labeler.BaseDataLabeler

    +

    Subclass of BaseDataLabeler that can be trained.

    +

    Initialize DataLabeler class.

    +
    +
    Parameters
    +
      +
    • dirpath – path to data labeler

    • +
    • load_options – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    +
    +
    +fit(x: DataArray, y: DataArray, validation_split: float = 0.2, labels: list | dict | None = None, reset_weights: bool = False, batch_size: int = 32, epochs: int = 1, error_on_mismatch: bool = False) list
    +

    Fit the data labeler model for the dataset.

    +
    +
    Parameters
    +
      +
    • x (Union[pd.DataFrame, pd.Series, np.ndarray]) – samples to fit model

    • +
    • y (Union[pd.DataFrame, pd.Series, np.ndarray]) – labels associated with the samples to fit model

    • +
    • validation_split (float) – split of the data to have as cross-validation +data

    • +
    • labels (Union[list, dict]) – Encoding or number of labels if refit is needed to new +labels

    • +
    • reset_weights (bool) – Flag to determine whether or not to reset the +weights

    • +
    • batch_size (int) – Size of each batch sent to data labeler model

    • +
    • epochs (int) – number of epochs to iterate over the dataset and send to +the model

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    +
    +
    Returns
    +

    model output

    +
    +
    +
    +
    +
    +set_model(model: dataprofiler.labelers.base_model.BaseModel) None
    +

    Set the model for a trainable data labeler.

    +

    Model must have a train function to be able to be set.

    +
    +
    Parameters
    +

    model (base_model.BaseModel) – model to use within the data labeler

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_with_components(preprocessor: dataprofiler.labelers.data_processing.BaseDataPreprocessor, model: dataprofiler.labelers.base_model.BaseModel, postprocessor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) dataprofiler.labelers.base_data_labeler.TrainableDataLabeler
    +

    Load the data labeler from a its set of components.

    +
    +
    Parameters
    +
    +
    +
    Returns
    +

    loaded TrainableDataLabeler

    +
    +
    Return type
    +

    TrainableDataLabeler

    +
    +
    +
    +
    +
    +add_label(label: str, same_as: Optional[str] = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +check_pipeline(skip_postprocessor: bool = False, error_on_mismatch: bool = False) None
    +

    Check whether the processors and models connect together without error.

    +
    +
    Parameters
    +
      +
    • skip_postprocessor (bool) – skip checking postprocessor is valid in +pipeline

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict
    +

    Retrieve the label encodings.

    +
    +
    Returns
    +

    dictionary for associating labels to indexes

    +
    +
    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str, load_options: Optional[dict] = None) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a saved location on disk.

    +
    +
    Parameters
    +
      +
    • dirpath (str) – path to data labeler files.

    • +
    • load_options (dict) – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from the data labeler zoo in the library.

    +
    +
    Parameters
    +

    name (str) – name of the data labeler.

    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +property model: dataprofiler.labelers.base_model.BaseModel
    +

    Retrieve the data labeler model.

    +
    +
    Returns
    +

    returns the model instance

    +
    +
    +
    +
    +
    +property postprocessor: data_processing.BaseDataPostprocessor | None
    +

    Retrieve the data postprocessor.

    +
    +
    Returns
    +

    returns the postprocessor instance

    +
    +
    +
    +
    +
    +predict(data: DataArray, batch_size: int = 32, predict_options: dict[str, bool] = None, error_on_mismatch: bool = False, verbose: bool = True) dict
    +

    Predict labels of input data based with the data labeler model.

    +
    +
    Parameters
    +
      +
    • data (Union[pd.DataFrame, pd.Series, np.ndarray]) – data to be predicted upon

    • +
    • batch_size (int) – batch size of prediction

    • +
    • predict_options (Dict[str, bool]) – optional parameters to allow for predict as a +dict, i.e. dict(show_confidences=True)

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    predictions

    +
    +
    Return type
    +

    Dict

    +
    +
    +
    +
    +
    +property preprocessor: data_processing.BaseDataPreprocessor | None
    +

    Retrieve the data preprocessor.

    +
    +
    Returns
    +

    returns the preprocessor instance

    +
    +
    +
    +
    +
    +property reverse_label_mapping: dict
    +

    Retrieve the index to label encoding.

    +
    +
    Returns
    +

    dictionary for associating indexes to labels

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save the data labeler to the specified location.

    +
    +
    Parameters
    +

    dirpath (str) – location to save the data labeler.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_labels(labels: list | dict) None
    +

    Set the labels for the data labeler.

    +
    +
    Parameters
    +

    labels (list or dict) – new labels in either encoding list or dict

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_params(params: dict) None
    +

    Allow user to set parameters of pipeline components.

    +
    +
    Done in the following format:
    +
    params = dict(

    preprocessor=dict(…), +model=dict(…), +postprocessor=dict(…)

    +
    +
    +

    )

    +
    +
    +

    where the key,values pairs for each pipeline component must match +parameters that exist in their components.

    +
    +
    Parameters
    +

    params (dict) –

    dictionary containing a key for a given pipeline +component and its associated value of parameters as such:

    +
    +

    dict(preprocessor=dict(…), model=dict(…), +postprocessor=dict(…))

    +
    +

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_postprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) None
    +

    Set the data postprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPostprocessor) – processor to set as the postprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_preprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPreprocessor) None
    +

    Set the data preprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPreprocessor) – processor to set as the preprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.base_model.html b/docs/0.10.3/html/dataprofiler.labelers.base_model.html new file mode 100644 index 000000000..29bd2fa7f --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.base_model.html @@ -0,0 +1,675 @@ + + + + + + + + + Base Model - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Base Model

    +

    Contains abstract classes for labeling data.

    +
    +
    +class dataprofiler.labelers.base_model.AutoSubRegistrationMeta(clsname: str, bases: tuple[type, ...], attrs: dict[str, object])
    +

    Bases: abc.ABCMeta

    +

    For registering subclasses.

    +

    Create auto registration object and return new class.

    +
    +
    +mro()
    +

    Return a type’s method resolution order.

    +
    +
    +
    +register(subclass)
    +

    Register a virtual subclass of an ABC.

    +

    Returns the subclass, to allow usage as a class decorator.

    +
    +
    +
    +
    +class dataprofiler.labelers.base_model.BaseModel(label_mapping: list | dict, parameters: dict)
    +

    Bases: object

    +

    For labeling data.

    +

    Initialize Base Model.

    +

    Only model and model parameters are stored here. +:param label_mapping: label mapping of the model or list of labels to be

    +
    +

    converted into the label mapping

    +
    +
    +
    Parameters
    +

    parameters (dict) – Contains all the appropriate parameters for the model. +Must contain num_labels.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +requires_zero_mapping: bool = False
    +
    +
    +
    +property label_mapping: dict[str, int]
    +

    Return mapping of labels to their encoded values.

    +
    +
    +
    +property reverse_label_mapping: dict[int, str]
    +

    Return reversed order of current labels.

    +

    Useful for when needed to extract Labels via indices.

    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +property num_labels: int
    +

    Return max label mapping.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseModel] | None
    +

    Get subclasses.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (List[str]) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +add_label(label: str, same_as: str | None = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_label_mapping(label_mapping: list[str] | dict[str, int]) None
    +

    Set the labels for the model.

    +
    +
    Parameters
    +

    label_mapping (Union[list, dict]) – label mapping of the model or list of labels to be +converted into the label mapping

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Help describe alterable parameters.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +abstract reset_weights() None
    +

    Reset the weights of the model.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +abstract predict(data: Union[pandas.core.frame.DataFrame, pandas.core.series.Series, numpy.ndarray], batch_size: int, show_confidences: bool, verbose: bool) dict
    +

    Predict the data with the current model.

    +
    +
    Parameters
    +
      +
    • data (iterator of data to process) – model input data to predict on

    • +
    • batch_size (int) – number of samples in the batch of data

    • +
    • show_confidences (bool) – whether user wants prediction confidences

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    char level predictions and confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +abstract classmethod load_from_disk(dirpath: str) dataprofiler.labelers.base_model.BaseModel
    +

    Load whole model from disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to load the model from

    +
    +
    Returns
    +

    loaded model

    +
    +
    Return type
    +

    BaseModel

    +
    +
    +
    +
    +
    +abstract save_to_disk(dirpath: str) None
    +

    Save whole model to disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to save the model to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +
    +class dataprofiler.labelers.base_model.BaseTrainableModel(label_mapping: list | dict, parameters: dict)
    +

    Bases: dataprofiler.labelers.base_model.BaseModel

    +

    Contains abstract method for training models.

    +

    Initialize Base Model.

    +

    Only model and model parameters are stored here. +:param label_mapping: label mapping of the model or list of labels to be

    +
    +

    converted into the label mapping

    +
    +
    +
    Parameters
    +

    parameters (dict) – Contains all the appropriate parameters for the model. +Must contain num_labels.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +abstract fit(train_data: DataArray, val_data: DataArray, batch_size: int | None = None, epochs: int | None = None, label_mapping: dict[str, int] | None = None, reset_weights: bool = False, verbose: bool = True) tuple[dict, float | None, dict]
    +

    Train the current model with the training data and validation data.

    +
    +
    Parameters
    +
      +
    • train_data (Union[pd.DataFrame, pd.Series, np.ndarray]) – Training data used to train model

    • +
    • val_data (Union[pd.DataFrame, pd.Series, np.ndarray]) – Validation data used to validate the training

    • +
    • batch_size (int) – Used to determine number of samples in each batch

    • +
    • epochs (int) – Used to determine how many epochs to run

    • +
    • label_mapping (dict) – Mapping of the labels

    • +
    • reset_weights (bool) – Flag to determine whether or not to reset the +model’s weights

    • +
    +
    +
    Returns
    +

    history, f1, f1_report

    +
    +
    Return type
    +

    Tuple[dict, float, dict]

    +
    +
    +
    +
    +
    +add_label(label: str, same_as: str | None = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseModel] | None
    +

    Get subclasses.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (List[str]) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Help describe alterable parameters.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict[str, int]
    +

    Return mapping of labels to their encoded values.

    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +abstract classmethod load_from_disk(dirpath: str) dataprofiler.labelers.base_model.BaseModel
    +

    Load whole model from disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to load the model from

    +
    +
    Returns
    +

    loaded model

    +
    +
    Return type
    +

    BaseModel

    +
    +
    +
    +
    +
    +property num_labels: int
    +

    Return max label mapping.

    +
    +
    +
    +abstract predict(data: Union[pandas.core.frame.DataFrame, pandas.core.series.Series, numpy.ndarray], batch_size: int, show_confidences: bool, verbose: bool) dict
    +

    Predict the data with the current model.

    +
    +
    Parameters
    +
      +
    • data (iterator of data to process) – model input data to predict on

    • +
    • batch_size (int) – number of samples in the batch of data

    • +
    • show_confidences (bool) – whether user wants prediction confidences

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    char level predictions and confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +requires_zero_mapping: bool = False
    +
    +
    +
    +abstract reset_weights() None
    +

    Reset the weights of the model.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property reverse_label_mapping: dict[int, str]
    +

    Return reversed order of current labels.

    +

    Useful for when needed to extract Labels via indices.

    +
    +
    +
    +abstract save_to_disk(dirpath: str) None
    +

    Save whole model to disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to save the model to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_label_mapping(label_mapping: list[str] | dict[str, int]) None
    +

    Set the labels for the model.

    +
    +
    Parameters
    +

    label_mapping (Union[list, dict]) – label mapping of the model or list of labels to be +converted into the label mapping

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.char_load_tf_model.html b/docs/0.10.3/html/dataprofiler.labelers.char_load_tf_model.html new file mode 100644 index 000000000..680716c22 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.char_load_tf_model.html @@ -0,0 +1,491 @@ + + + + + + + + + Char Load Tf Model - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Char Load Tf Model

    +

    Contains class for training data labeler model.

    +
    +
    +class dataprofiler.labelers.char_load_tf_model.CharLoadTFModel(model_path: str, label_mapping: dict[str, int], parameters: dict = None)
    +

    Bases: dataprofiler.labelers.base_model.BaseTrainableModel

    +

    For training data labeler model.

    +

    Initialize Loadable TF Model.

    +
    +
    Parameters
    +
      +
    • model_path (str) – path to model to load

    • +
    • label_mapping (dict) – maps labels to their encoded integers

    • +
    • parameters (dict) –

      Contains all the appropriate parameters for the +model. Must contain num_labels. Other possible parameters are:

      +
      +

      max_length, max_char_encoding_id, dim_embed, size_fc +dropout, size_conv, num_fil, optimizer, default_label

      +
      +

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +requires_zero_mapping: bool = False
    +
    +
    +
    +set_label_mapping(label_mapping: list[str] | dict[str, int]) None
    +

    Set the labels for the model.

    +
    +
    Parameters
    +

    label_mapping (dict) – label mapping of the model

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save whole model to disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to save the model to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) dataprofiler.labelers.char_load_tf_model.CharLoadTFModel
    +

    Load whole model from disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to load the model from

    +
    +
    Returns
    +

    loaded CharLoadTFModel

    +
    +
    Return type
    +

    CharLoadTFModel

    +
    +
    +
    +
    +
    +reset_weights() None
    +

    Reset the weights of the model.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +fit(train_data: DataArray, val_data: DataArray = None, batch_size: int = None, epochs: int = None, label_mapping: dict[str, int] = None, reset_weights: bool = False, verbose: bool = True) tuple[dict, float | None, dict]
    +

    Train the current model with the training data and validation data.

    +
    +
    Parameters
    +
      +
    • train_data (Union[list, np.ndarray]) – Training data used to train model

    • +
    • val_data (Union[list, np.ndarray]) – Validation data used to validate the training

    • +
    • batch_size (int) – Used to determine number of samples in each batch

    • +
    • label_mapping (Union[dict, None]) – maps labels to their encoded integers

    • +
    • reset_weights (bool) – Flag to determine whether to reset the weights or +not

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    history, f1, f1_report

    +
    +
    Return type
    +

    Tuple[dict, float, dict]

    +
    +
    +
    +
    +
    +predict(data: Union[pandas.core.frame.DataFrame, pandas.core.series.Series, numpy.ndarray], batch_size: int = 32, show_confidences: bool = False, verbose: bool = True) dict
    +

    Run model and get predictions.

    +
    +
    Parameters
    +
      +
    • data (Union[list, numpy.ndarray]) – text input

    • +
    • batch_size (int) – number of samples in the batch of data

    • +
    • show_confidences – whether user wants prediction confidences

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    char level predictions and confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +details() None
    +

    Print the relevant details of the model.

    +

    Details include summary, parameters, label mapping.

    +
    +
    +
    +add_label(label: str, same_as: str | None = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseModel] | None
    +

    Get subclasses.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (List[str]) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Help describe alterable parameters.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict[str, int]
    +

    Return mapping of labels to their encoded values.

    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +property num_labels: int
    +

    Return max label mapping.

    +
    +
    +
    +property reverse_label_mapping: dict[int, str]
    +

    Return reversed order of current labels.

    +

    Useful for when needed to extract Labels via indices.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.character_level_cnn_model.html b/docs/0.10.3/html/dataprofiler.labelers.character_level_cnn_model.html new file mode 100644 index 000000000..aad878b33 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.character_level_cnn_model.html @@ -0,0 +1,512 @@ + + + + + + + + + Character Level Cnn Model - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Character Level Cnn Model

    +

    Contains classes for char data labeling.

    +
    +
    +dataprofiler.labelers.character_level_cnn_model.build_embd_dictionary(filename: str) dict[str, np.ndarray]
    +

    Return a numpy embedding dictionary from embed file with GloVe-like format.

    +
    +
    Parameters
    +

    filename (str) – Path to the embed file for loading

    +
    +
    +
    +
    +
    +dataprofiler.labelers.character_level_cnn_model.create_glove_char(n_dims: int, source_file: Optional[str] = None) None
    +

    Embed GloVe chars embeddings from source file to n_dims principal components.

    +

    Embed in a new file.

    +
    +
    Parameters
    +
      +
    • n_dims (int) – Final number of principal component dims of the embeddings

    • +
    • source_file (str) – Location of original embeddings to factor down

    • +
    +
    +
    +
    +
    +
    +class dataprofiler.labelers.character_level_cnn_model.CharacterLevelCnnModel(label_mapping: dict[str, int], parameters: dict = None)
    +

    Bases: dataprofiler.labelers.base_model.BaseTrainableModel

    +

    Class for training char data labeler.

    +

    Initialize CNN Model.

    +

    Initialize epoch_id.

    +
    +
    Parameters
    +
      +
    • label_mapping (dict) – maps labels to their encoded integers

    • +
    • parameters (dict) –

      Contains all the appropriate parameters for the +model. Must contain num_labels. Other possible parameters are:

      +
      +

      max_length, max_char_encoding_id, dim_embed, size_fc +dropout, size_conv, num_fil, optimizer, default_label

      +
      +

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +requires_zero_mapping: bool = True
    +
    +
    +
    +set_label_mapping(label_mapping: list[str] | dict[str, int]) None
    +

    Set the labels for the model.

    +
    +
    Parameters
    +

    label_mapping (dict) – label mapping of the model

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save whole model to disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to save the model to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) dataprofiler.labelers.character_level_cnn_model.CharacterLevelCnnModel
    +

    Load whole model from disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to load the model from

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +reset_weights() None
    +

    Reset the weights of the model.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +fit(train_data: DataArray, val_data: DataArray | None = None, batch_size: int = None, epochs: int = None, label_mapping: dict[str, int] = None, reset_weights: bool = False, verbose: bool = True) tuple[dict, float | None, dict]
    +

    Train the current model with the training data and validation data.

    +
    +
    Parameters
    +
      +
    • train_data (Union[list, np.ndarray]) – Training data used to train model

    • +
    • val_data (Union[list, np.ndarray]) – Validation data used to validate the training

    • +
    • batch_size (int) – Used to determine number of samples in each batch

    • +
    • label_mapping (Union[dict, None]) – maps labels to their encoded integers

    • +
    • reset_weights (bool) – Flag to determine whether to reset the weights or +not

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    history, f1, f1_report

    +
    +
    Return type
    +

    Tuple[dict, float, dict]

    +
    +
    +
    +
    +
    +predict(data: Union[pandas.core.frame.DataFrame, pandas.core.series.Series, numpy.ndarray], batch_size: int = 32, show_confidences: bool = False, verbose: bool = True) dict
    +

    Run model and get predictions.

    +
    +
    Parameters
    +
      +
    • data (Union[list, numpy.ndarray]) – text input

    • +
    • batch_size (int) – number of samples in the batch of data

    • +
    • show_confidences – whether user wants prediction confidences

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    char level predictions and confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +details() None
    +

    Print the relevant details of the model.

    +

    Details include summary, parameters, and label mapping.

    +
    +
    +
    +add_label(label: str, same_as: str | None = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseModel] | None
    +

    Get subclasses.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (List[str]) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Help describe alterable parameters.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict[str, int]
    +

    Return mapping of labels to their encoded values.

    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +property num_labels: int
    +

    Return max label mapping.

    +
    +
    +
    +property reverse_label_mapping: dict[int, str]
    +

    Return reversed order of current labels.

    +

    Useful for when needed to extract Labels via indices.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.classification_report_utils.html b/docs/0.10.3/html/dataprofiler.labelers.classification_report_utils.html new file mode 100644 index 000000000..745cd0064 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.classification_report_utils.html @@ -0,0 +1,451 @@ + + + + + + + + + Classification Report Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Classification Report Utils

    +

    Contains functions for classification.

    +
    +
    +dataprofiler.labelers.classification_report_utils.convert_confusion_matrix_to_MCM(conf_matrix: list | np.ndarray) np.ndarray
    +

    Convert a confusion matrix into the MCM format.

    +

    Format for precision/recall/fscore/ +support computation by sklearn.

    +

    The format is as specified by sklearn below: +In multilabel confusion matrix \(MCM\), the count of true negatives +is \(MCM_{:,0,0}\), false negatives is \(MCM_{:,1,0}\), +true positives is \(MCM_{:,1,1}\) and false positives is +\(MCM_{:,0,1}\). +Note: this utilizes code/ideology from sklearn.

    +
    +
    Parameters
    +

    conf_matrix (Union[list, np.ndarray]) – confusion matrix, which is a square matrix describing +false positives and false negatives, true positives and true negatives +for classification

    +
    +
    Returns
    +

    MCM format for readability by sklearn confusion reports.

    +
    +
    Return type
    +

    np.ndarray

    +
    +
    +
    +
    +
    +dataprofiler.labelers.classification_report_utils.precision_recall_fscore_support(MCM: np.ndarray, beta: float = 1.0, labels: np.ndarray | None = None, pos_label: str | int = 1, average: str | None = None, warn_for: tuple[str, ...] | set[str] = ('precision', 'recall', 'f-score'), sample_weight: np.ndarray | None = None) tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray | None]
    +

    Perform same functionality as recision_recall_fscore_support function.

    +

    Copy of the precision_recall_fscore_support function from sklearn.metrics +with the update to receiving the MCM instead of calculating each time it is +called.

    +
    +
    Parameters
    +
      +
    • MCM (array, shape (n_outputs, 2, 2)) – Multi-classification confusion matrix as referenced by the sklearn +metrics module. A 2x2 confusion matrix corresponding to each output in +the input. In multilabel confusion matrix \(MCM\), the count of +true negatives is \(MCM_{:,0,0}\), false negatives is +\(MCM_{:,1,0}\), true positives is \(MCM_{:,1,1}\) and false +positives is \(MCM_{:,0,1}\).

    • +
    • beta (float, 1.0 by default) – The strength of recall versus precision in the F-score.

    • +
    • labels (list, optional) – The set of labels to include when average != 'binary', and their +order if average is None. Labels present in the data can be +excluded, for example to calculate a multiclass average ignoring a +majority negative class, while labels not present in the data will +result in 0 components in a macro average. For multilabel targets, +labels are column indices. By default, all labels in y_true and +y_pred are used in sorted order.

    • +
    • pos_label (str or int, 1 by default) – The class to report if average='binary' and the data is binary. +If the data are multiclass or multilabel, this will be ignored; +setting labels=[pos_label] and average != 'binary' will report +scores for that label only.

    • +
    • average (string, [None (default), 'binary', 'micro', 'macro', 'weighted']) –

      If None, the scores for each class are returned. Otherwise, this +determines the type of averaging performed on the data:

      +
      +
      'binary':

      Only report results for the class specified by pos_label. +This is applicable only if targets (y_{true,pred}) are binary.

      +
      +
      'micro':

      Calculate metrics globally by counting the total true positives, +false negatives and false positives.

      +
      +
      'macro':

      Calculate metrics for each label, and find their unweighted +mean. This does not take label imbalance into account.

      +
      +
      'weighted':

      Calculate metrics for each label, and find their average weighted +by support (the number of true instances for each label). This +alters ‘macro’ to account for label imbalance; it can result in an +F-score that is not between precision and recall.

      +
      +
      +

    • +
    • warn_for (tuple or set, for internal use) – This determines which warnings will be made in the case that this +function is being used to return only one of its metrics.

    • +
    • sample_weight (array-like of shape = [n_samples], optional) – Sample weights.

    • +
    +
    +
    Returns
    +

      +
    • precision (float (if average is not None) or array of float, shape = [n_unique_labels])

    • +
    • recall (float (if average is not None) or array of float, , shape = [n_unique_labels])

    • +
    • fbeta_score (float (if average is not None) or array of float, shape = [n_unique_labels])

    • +
    • support (int (if average is not None) or array of int, shape = [n_unique_labels]) – The number of occurrences of each label in y_true.

    • +
    +

    +
    +
    +

    References

    +
    +
    1
    +

    Wikipedia entry for the Precision and recall

    +
    +
    2
    +

    Wikipedia entry for the F1-score

    +
    +
    3
    +

    Discriminative Methods for Multi-labeled Classification Advances +in Knowledge Discovery and Data Mining (2004), pp. 22-30 by Shantanu +Godbole, Sunita Sarawagi

    +
    +
    +

    Notes

    +

    When true positive + false positive == 0, precision is undefined; +When true positive + false negative == 0, recall is undefined. +In such cases, the metric will be set to 0, as will f-score, and +UndefinedMetricWarning will be raised.

    +
    +
    +
    +dataprofiler.labelers.classification_report_utils.classification_report(conf_matrix: np.ndarray, labels: list | np.ndarray | None = None, target_names: list[str] | None = None, sample_weight: np.ndarray | None = None, digits: int = 2, output_dict: bool = False) str | dict
    +

    Build a text report showing the main classification metrics.

    +

    Copy of the classification_report function from sklearn.metrics +with the update to receiving the conf_matrix instead of calculating each +time it is called.

    +

    Read more in the User Guide.

    +
    +
    Parameters
    +
      +
    • conf_matrix (array, shape = [n_labels, n_labels]) – confusion matrix, which is a square matrix describing +false positives and false negatives, true positives and true negatives +for classification.

    • +
    • labels (array, shape = [n_labels]) – Optional list of label indices to include in the report.

    • +
    • target_names (list of strings) – Optional display names matching the labels (same order).

    • +
    • sample_weight (array-like of shape = [n_samples], optional) – Sample weights.

    • +
    • digits (int) – Number of digits for formatting output floating point values. +When output_dict is True, this will be ignored and the +returned values will not be rounded.

    • +
    • output_dict (bool (default = False)) – If True, return output as dict

    • +
    +
    +
    Returns
    +

    report – Text summary of the precision, recall, F1 score for each class. +Dictionary returned if output_dict is True. Dictionary has the +following structure:

    +
    {'label 1': {'precision':0.5,
    +             'recall':1.0,
    +             'f1-score':0.67,
    +             'support':1},
    + 'label 2': { ... },
    +  ...
    +}
    +
    +
    +

    The reported averages include macro average (averaging the unweighted +mean per label), weighted average (averaging the support-weighted mean +per label), sample average (only for multilabel classification) and +micro average (averaging the total true positives, false negatives and +false positives) it is only shown for multi-label or multi-class +with a subset of classes because it is accuracy otherwise. +See also:func:precision_recall_fscore_support for more details +on averages.

    +

    Note that in binary classification, recall of the positive class +is also known as “sensitivity”; recall of the negative class is +“specificity”.

    +

    +
    +
    Return type
    +

    string / dict

    +
    +
    +
    +

    See also

    +

    precision_recall_fscore_support, confusion_matrix, multilabel_confusion_matrix

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.column_name_model.html b/docs/0.10.3/html/dataprofiler.labelers.column_name_model.html new file mode 100644 index 000000000..d2893caba --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.column_name_model.html @@ -0,0 +1,451 @@ + + + + + + + + + Column Name Model - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Column Name Model

    +

    Contains class for column name data labeling model.

    +
    +
    +class dataprofiler.labelers.column_name_model.ColumnNameModel(label_mapping: dict[str, int], parameters: dict = None)
    +

    Bases: dataprofiler.labelers.base_model.BaseModel

    +

    Class for column name data labeling model.

    +

    Initialize function for ColumnNameModel.

    +
    +
    Parameters
    +

    parameters (dict) –

    Contains all the appropriate parameters for the model. +Possible parameters are:

    +
    +

    max_length, max_num_chars, dim_embed

    +
    +

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +reset_weights() None
    +

    Reset weights function.

    +
    +
    +
    +predict(data: Union[pandas.core.frame.DataFrame, pandas.core.series.Series, numpy.ndarray], batch_size: Optional[int] = None, show_confidences: bool = False, verbose: bool = True) dict
    +

    Apply the process.cdist for similarity score on input list of strings.

    +
    +
    Parameters
    +
      +
    • data (iterator) – list of strings to predict upon

    • +
    • batch_size (N/A) – does not impact this model and should be fixed to not +be required.

    • +
    • show_confidences – Parameter disabled. Confidence values returned +by default.

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    char level predictions and confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) dataprofiler.labelers.column_name_model.ColumnNameModel
    +

    Load whole model from disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to load the model from

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save whole model to disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to save the model to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +add_label(label: str, same_as: str | None = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseModel] | None
    +

    Get subclasses.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (List[str]) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Help describe alterable parameters.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict[str, int]
    +

    Return mapping of labels to their encoded values.

    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +property num_labels: int
    +

    Return max label mapping.

    +
    +
    +
    +requires_zero_mapping: bool = False
    +
    +
    +
    +property reverse_label_mapping: dict[int, str]
    +

    Return reversed order of current labels.

    +

    Useful for when needed to extract Labels via indices.

    +
    +
    +
    +set_label_mapping(label_mapping: list[str] | dict[str, int]) None
    +

    Set the labels for the model.

    +
    +
    Parameters
    +

    label_mapping (Union[list, dict]) – label mapping of the model or list of labels to be +converted into the label mapping

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.data_labelers.html b/docs/0.10.3/html/dataprofiler.labelers.data_labelers.html new file mode 100644 index 000000000..1ffd0899a --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.data_labelers.html @@ -0,0 +1,980 @@ + + + + + + + + + Data Labelers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data Labelers

    +

    Module to train and choose between structured and unstructured data labelers.

    +
    +
    +dataprofiler.labelers.data_labelers.train_structured_labeler(data: None | pd.DataFrame, default_label: int = None, save_dirpath: str = None, epochs: int = 2) TrainableDataLabeler
    +

    Use provided data to create and save a structured data labeler.

    +
    +
    Parameters
    +
      +
    • data (Union[None, pd.DataFrame]) – data to be trained upon

    • +
    • save_dirpath (Union[None, str]) – path to save data labeler

    • +
    • epochs (int) – number of epochs to loop training the data

    • +
    +
    +
    Returns
    +

    structured data labeler

    +
    +
    Return type
    +

    TrainableDataLabeler

    +
    +
    +
    +
    +
    +class dataprofiler.labelers.data_labelers.UnstructuredDataLabeler(dirpath: Optional[str] = None, load_options: Optional[dict] = None)
    +

    Bases: dataprofiler.labelers.base_data_labeler.BaseDataLabeler

    +

    BaseDataLabeler subclass specified as unstructured with internal variable.

    +

    Initialize DataLabeler class.

    +
    +
    Parameters
    +
      +
    • dirpath – path to data labeler

    • +
    • load_options – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    +
    +
    +add_label(label: str, same_as: Optional[str] = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +check_pipeline(skip_postprocessor: bool = False, error_on_mismatch: bool = False) None
    +

    Check whether the processors and models connect together without error.

    +
    +
    Parameters
    +
      +
    • skip_postprocessor (bool) – skip checking postprocessor is valid in +pipeline

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict
    +

    Retrieve the label encodings.

    +
    +
    Returns
    +

    dictionary for associating labels to indexes

    +
    +
    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str, load_options: Optional[dict] = None) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a saved location on disk.

    +
    +
    Parameters
    +
      +
    • dirpath (str) – path to data labeler files.

    • +
    • load_options (dict) – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from the data labeler zoo in the library.

    +
    +
    Parameters
    +

    name (str) – name of the data labeler.

    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_with_components(preprocessor: dataprofiler.labelers.data_processing.BaseDataPreprocessor, model: dataprofiler.labelers.base_model.BaseModel, postprocessor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a its set of components.

    +
    +
    Parameters
    +
    +
    +
    Returns
    +

    loaded BaseDataLabeler

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +property model: dataprofiler.labelers.base_model.BaseModel
    +

    Retrieve the data labeler model.

    +
    +
    Returns
    +

    returns the model instance

    +
    +
    +
    +
    +
    +property postprocessor: data_processing.BaseDataPostprocessor | None
    +

    Retrieve the data postprocessor.

    +
    +
    Returns
    +

    returns the postprocessor instance

    +
    +
    +
    +
    +
    +predict(data: DataArray, batch_size: int = 32, predict_options: dict[str, bool] = None, error_on_mismatch: bool = False, verbose: bool = True) dict
    +

    Predict labels of input data based with the data labeler model.

    +
    +
    Parameters
    +
      +
    • data (Union[pd.DataFrame, pd.Series, np.ndarray]) – data to be predicted upon

    • +
    • batch_size (int) – batch size of prediction

    • +
    • predict_options (Dict[str, bool]) – optional parameters to allow for predict as a +dict, i.e. dict(show_confidences=True)

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    predictions

    +
    +
    Return type
    +

    Dict

    +
    +
    +
    +
    +
    +property preprocessor: data_processing.BaseDataPreprocessor | None
    +

    Retrieve the data preprocessor.

    +
    +
    Returns
    +

    returns the preprocessor instance

    +
    +
    +
    +
    +
    +property reverse_label_mapping: dict
    +

    Retrieve the index to label encoding.

    +
    +
    Returns
    +

    dictionary for associating indexes to labels

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save the data labeler to the specified location.

    +
    +
    Parameters
    +

    dirpath (str) – location to save the data labeler.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_labels(labels: list | dict) None
    +

    Set the labels for the data labeler.

    +
    +
    Parameters
    +

    labels (list or dict) – new labels in either encoding list or dict

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_model(model: dataprofiler.labelers.base_model.BaseModel) None
    +

    Set the model for the data labeler.

    +
    +
    Parameters
    +

    model (base_model.BaseModel) – model to use within the data labeler

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_params(params: dict) None
    +

    Allow user to set parameters of pipeline components.

    +
    +
    Done in the following format:
    +
    params = dict(

    preprocessor=dict(…), +model=dict(…), +postprocessor=dict(…)

    +
    +
    +

    )

    +
    +
    +

    where the key,values pairs for each pipeline component must match +parameters that exist in their components.

    +
    +
    Parameters
    +

    params (dict) –

    dictionary containing a key for a given pipeline +component and its associated value of parameters as such:

    +
    +

    dict(preprocessor=dict(…), model=dict(…), +postprocessor=dict(…))

    +
    +

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_postprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) None
    +

    Set the data postprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPostprocessor) – processor to set as the postprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_preprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPreprocessor) None
    +

    Set the data preprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPreprocessor) – processor to set as the preprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +
    +class dataprofiler.labelers.data_labelers.StructuredDataLabeler(dirpath: Optional[str] = None, load_options: Optional[dict] = None)
    +

    Bases: dataprofiler.labelers.base_data_labeler.BaseDataLabeler

    +

    BaseDataLabeler subclass specified as structured with internal variable.

    +

    Initialize DataLabeler class.

    +
    +
    Parameters
    +
      +
    • dirpath – path to data labeler

    • +
    • load_options – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    +
    +
    +add_label(label: str, same_as: Optional[str] = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +check_pipeline(skip_postprocessor: bool = False, error_on_mismatch: bool = False) None
    +

    Check whether the processors and models connect together without error.

    +
    +
    Parameters
    +
      +
    • skip_postprocessor (bool) – skip checking postprocessor is valid in +pipeline

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict
    +

    Retrieve the label encodings.

    +
    +
    Returns
    +

    dictionary for associating labels to indexes

    +
    +
    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str, load_options: Optional[dict] = None) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a saved location on disk.

    +
    +
    Parameters
    +
      +
    • dirpath (str) – path to data labeler files.

    • +
    • load_options (dict) – optional arguments to include for load i.e. class +for model or processors

    • +
    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from the data labeler zoo in the library.

    +
    +
    Parameters
    +

    name (str) – name of the data labeler.

    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +classmethod load_with_components(preprocessor: dataprofiler.labelers.data_processing.BaseDataPreprocessor, model: dataprofiler.labelers.base_model.BaseModel, postprocessor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a its set of components.

    +
    +
    Parameters
    +
    +
    +
    Returns
    +

    loaded BaseDataLabeler

    +
    +
    Return type
    +

    BaseDataLabeler

    +
    +
    +
    +
    +
    +property model: dataprofiler.labelers.base_model.BaseModel
    +

    Retrieve the data labeler model.

    +
    +
    Returns
    +

    returns the model instance

    +
    +
    +
    +
    +
    +property postprocessor: data_processing.BaseDataPostprocessor | None
    +

    Retrieve the data postprocessor.

    +
    +
    Returns
    +

    returns the postprocessor instance

    +
    +
    +
    +
    +
    +predict(data: DataArray, batch_size: int = 32, predict_options: dict[str, bool] = None, error_on_mismatch: bool = False, verbose: bool = True) dict
    +

    Predict labels of input data based with the data labeler model.

    +
    +
    Parameters
    +
      +
    • data (Union[pd.DataFrame, pd.Series, np.ndarray]) – data to be predicted upon

    • +
    • batch_size (int) – batch size of prediction

    • +
    • predict_options (Dict[str, bool]) – optional parameters to allow for predict as a +dict, i.e. dict(show_confidences=True)

    • +
    • error_on_mismatch (bool) – if true, errors instead of warns on parameter +mismatches in pipeline

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    predictions

    +
    +
    Return type
    +

    Dict

    +
    +
    +
    +
    +
    +property preprocessor: data_processing.BaseDataPreprocessor | None
    +

    Retrieve the data preprocessor.

    +
    +
    Returns
    +

    returns the preprocessor instance

    +
    +
    +
    +
    +
    +property reverse_label_mapping: dict
    +

    Retrieve the index to label encoding.

    +
    +
    Returns
    +

    dictionary for associating indexes to labels

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save the data labeler to the specified location.

    +
    +
    Parameters
    +

    dirpath (str) – location to save the data labeler.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_labels(labels: list | dict) None
    +

    Set the labels for the data labeler.

    +
    +
    Parameters
    +

    labels (list or dict) – new labels in either encoding list or dict

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_model(model: dataprofiler.labelers.base_model.BaseModel) None
    +

    Set the model for the data labeler.

    +
    +
    Parameters
    +

    model (base_model.BaseModel) – model to use within the data labeler

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_params(params: dict) None
    +

    Allow user to set parameters of pipeline components.

    +
    +
    Done in the following format:
    +
    params = dict(

    preprocessor=dict(…), +model=dict(…), +postprocessor=dict(…)

    +
    +
    +

    )

    +
    +
    +

    where the key,values pairs for each pipeline component must match +parameters that exist in their components.

    +
    +
    Parameters
    +

    params (dict) –

    dictionary containing a key for a given pipeline +component and its associated value of parameters as such:

    +
    +

    dict(preprocessor=dict(…), model=dict(…), +postprocessor=dict(…))

    +
    +

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_postprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPostprocessor) None
    +

    Set the data postprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPostprocessor) – processor to set as the postprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_preprocessor(data_processor: dataprofiler.labelers.data_processing.BaseDataPreprocessor) None
    +

    Set the data preprocessor for the data labeler.

    +
    +
    Parameters
    +

    data_processor (data_processing.BaseDataPreprocessor) – processor to set as the preprocessor

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +
    +class dataprofiler.labelers.data_labelers.DataLabeler(labeler_type: str, dirpath: Optional[str] = None, load_options: Optional[dict] = None, trainable: bool = False)
    +

    Bases: object

    +

    Wrapper class for choosing between structured and unstructured labeler.

    +

    Create structured and unstructured data labeler objects.

    +
    +
    Parameters
    +
      +
    • dirpath (str) – Path to load data labeler

    • +
    • load_options (Dict) – Optional arguments to include for load.

    • +
    • trainable (bool) – variable to dictate whether you want a trainable data +labeler

    • +
    +
    +
    Returns
    +

    +
    +
    +
    +
    +labeler_classes = {'structured': <class 'dataprofiler.labelers.data_labelers.StructuredDataLabeler'>, 'unstructured': <class 'dataprofiler.labelers.data_labelers.UnstructuredDataLabeler'>}
    +
    +
    +
    +classmethod load_from_library(name: str, trainable: bool = False) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from the data labeler zoo in the library.

    +
    +
    Parameters
    +
      +
    • name (str) – name of the data labeler.

    • +
    • trainable (bool) – variable to dictate whether you want a trainable data +labeler

    • +
    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str, load_options: Optional[dict] = None, trainable: bool = False) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a saved location on disk.

    +
    +
    Parameters
    +
      +
    • dirpath (str) – path to data labeler files.

    • +
    • load_options (dict) – optional arguments to include for load i.e. class +for model or processors

    • +
    • trainable (bool) – variable to dictate whether you want a trainable data +labeler

    • +
    +
    +
    Returns
    +

    DataLabeler class

    +
    +
    +
    +
    +
    +classmethod load_with_components(preprocessor: dataprofiler.labelers.data_processing.BaseDataPreprocessor, model: dataprofiler.labelers.base_model.BaseModel, postprocessor: dataprofiler.labelers.data_processing.BaseDataPostprocessor, trainable: bool = False) dataprofiler.labelers.base_data_labeler.BaseDataLabeler
    +

    Load the data labeler from a its set of components.

    +
    +
    Parameters
    +
    +
    +
    Returns
    +

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.data_processing.html b/docs/0.10.3/html/dataprofiler.labelers.data_processing.html new file mode 100644 index 000000000..c3d09b498 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.data_processing.html @@ -0,0 +1,1412 @@ + + + + + + + + + Data Processing - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data Processing

    +

    Contains pre-built processors for data labeling/processing.

    +
    +
    +class dataprofiler.labelers.data_processing.AutoSubRegistrationMeta(clsname: str, bases: tuple[type, ...], attrs: dict[str, object])
    +

    Bases: abc.ABCMeta

    +

    For registering subclasses.

    +

    Create AutoSubRegistration object.

    +
    +
    +mro()
    +

    Return a type’s method resolution order.

    +
    +
    +
    +register(subclass)
    +

    Register a virtual subclass of an ABC.

    +

    Returns the subclass, to allow usage as a class decorator.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.BaseDataProcessor(**parameters: Any)
    +

    Bases: object

    +

    Abstract Data processing class.

    +

    Initialize BaseDataProcessor object.

    +
    +
    +processor_type: str
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +abstract classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +abstract process(*args: Any, **kwargs: Any) Any
    +

    Process data.

    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.BaseDataPreprocessor(**parameters: Any)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataProcessor

    +

    Abstract Data preprocessing class.

    +

    Initialize BaseDataPreprocessor object.

    +
    +
    +processor_type: str = 'preprocessor'
    +
    +
    +
    +abstract process(data: np.ndarray, labels: np.ndarray | None = None, label_mapping: dict[str, int] | None = None, batch_size: int = 32) Generator[tuple[np.ndarray, np.ndarray] | np.ndarray, None, None] | tuple[np.ndarray, np.ndarray] | np.ndarray
    +

    Preprocess data.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +abstract classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.BaseDataPostprocessor(**parameters: Any)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataProcessor

    +

    Abstract Data postprocessing class.

    +

    Initialize BaseDataPostprocessor object.

    +
    +
    +processor_type: str = 'postprocessor'
    +
    +
    +
    +abstract process(data: np.ndarray, results: dict, label_mapping: dict[str, int]) dict
    +

    Postprocess data.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +abstract classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.DirectPassPreprocessor
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPreprocessor

    +

    Subclass of BaseDataPreprocessor for preprocessing data.

    +

    Initialize the DirectPassPreprocessor class.

    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +process(data: np.ndarray, labels: np.ndarray | None = None, label_mapping: dict[str, int] | None = None, batch_size: int = 32) tuple[np.ndarray, np.ndarray] | np.ndarray
    +

    Preprocess data.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'preprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.CharPreprocessor(max_length: int = 3400, default_label: str = 'UNKNOWN', pad_label: str = 'PAD', flatten_split: float = 0, flatten_separator: str = ' ', is_separate_at_max_len: bool = False, **kwargs: Any)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPreprocessor

    +

    Subclass of BaseDataPreprocessor for preprocessing char data.

    +

    Initialize the CharPreprocessor class.

    +
    +
    Parameters
    +
      +
    • max_length (int) – Maximum char length in a sample.

    • +
    • default_label (string (could be int, char, etc.)) – Key for label_mapping that is the default label

    • +
    • pad_label (string (could be int, char, etc.)) – Key for label_mapping that is the pad label

    • +
    • flatten_split (float) – approximate output of split between flattened and +non-flattened characters, value between [0, 1]. When the current +flattened split becomes more than the flatten_split value, any +leftover sample or subsequent samples will be non-flattened until +the current flattened split is below the flatten_split value

    • +
    • flatten_separator (str) – separator used to put between flattened +samples.

    • +
    • is_separate_at_max_len (bool) – if true, separates at max_length, +otherwise at nearest separator

    • +
    +
    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +process(data: np.ndarray, labels: np.ndarray | None = None, label_mapping: dict[str, int] | None = None, batch_size: int = 32) Generator[tuple[np.ndarray, np.ndarray] | np.ndarray, None, None]
    +

    Flatten batches of data.

    +
    +
    Parameters
    +
      +
    • data (numpy.ndarray) – List of strings to create embeddings for

    • +
    • labels (numpy.ndarray) – labels for each input character

    • +
    • label_mapping (Union[None, dict]) – maps labels to their encoded integers

    • +
    • batch_size (int) – Number of samples in the batch of data

    • +
    +
    +
    Return batch_data
    +

    A dict containing samples of size batch_size

    +
    +
    Rtype batch_data
    +

    dicts

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'preprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.CharEncodedPreprocessor(encoding_map: dict[str, int] | None = None, max_length: int = 5000, default_label: str = 'UNKNOWN', pad_label: str = 'PAD', flatten_split: float = 0, flatten_separator: str = ' ', is_separate_at_max_len: bool = False)
    +

    Bases: dataprofiler.labelers.data_processing.CharPreprocessor

    +

    Subclass of CharPreprocessor for preprocessing char encoded data.

    +

    Initialize the CharEncodedPreprocessor class.

    +
    +
    Parameters
    +
      +
    • encoding_map (dict) – char to int encoding map

    • +
    • max_length (int) – Maximum char length in a sample.

    • +
    • default_label (string (could be int, char, etc.)) – Key for label_mapping that is the default label

    • +
    • pad_label (string (could be int, char, etc.)) – Key for label_mapping that is the pad label

    • +
    • flatten_split (float) – approximate output of split between flattened and +non-flattened characters, value between [0, 1]. When the current +flattened split becomes more than the flatten_split value, any +leftover sample or subsequent samples will be non-flattened until +the current flattened split is below the flatten_split value

    • +
    • flatten_separator (str) – separator used to put between flattened +samples.

    • +
    • is_separate_at_max_len (bool) – if true, separates at max_length, +otherwise at nearest separator

    • +
    +
    +
    +
    +
    +process(data: np.ndarray, labels: np.ndarray | None = None, label_mapping: dict[str, int] | None = None, batch_size: int = 32) Generator[tuple[np.ndarray, np.ndarray] | np.ndarray, None, None]
    +

    Process structured data for being processed by CharacterLevelCnnModel.

    +
    +
    Parameters
    +
      +
    • data (numpy.ndarray) – List of strings to create embeddings for

    • +
    • labels (numpy.ndarray) – labels for each input character

    • +
    • label_mapping (Union[dict, None]) – maps labels to their encoded integers

    • +
    • batch_size (int) – Number of samples in the batch of data

    • +
    +
    +
    Return batch_data
    +

    A dict containing samples of size batch_size

    +
    +
    Rtype batch_data
    +

    dict

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'preprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.CharPostprocessor(default_label: str = 'UNKNOWN', pad_label: str = 'PAD', flatten_separator: str = ' ', use_word_level_argmax: bool = False, output_format: str = 'character_argmax', separators: tuple[str, ...] = (' ', ',', ';', "'", '"', ':', '\n', '\t', '.'), word_level_min_percent: float = 0.75)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPostprocessor

    +

    Subclass of BaseDataPostprocessor for postprocessing char data.

    +

    Initialize the CharPostprocessor class.

    +
    +
    Parameters
    +
      +
    • default_label (string (could be int, char, etc.)) – Key for label_mapping that is the default label

    • +
    • pad_label (string (could be int, char, etc.)) – Key for label_mapping that is the pad label

    • +
    • flatten_separator (str) – separator used to put between flattened +samples.

    • +
    • use_word_level_argmax (bool) – whether to require the argmax value of +each character in a word to determine the word’s entity

    • +
    • output_format (str) – (character_argmax vs NER) where character_argmax +is a list of encodings for each character in the input text and NER +is in the dict format which specifies start,end,label for each +entity in a sentence

    • +
    • separators (tuple(str)) – list of characters to use for separating words within +the character predictions

    • +
    • word_level_min_percent (float) – threshold on generating dominant +word_level labeling

    • +
    +
    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +static convert_to_NER_format(predictions: list[list], label_mapping: dict[str, int], default_label: str, pad_label: str) list[list]
    +

    Convert word level predictions to specified format.

    +
    +
    Parameters
    +
      +
    • predictions (list) – predictions

    • +
    • label_mapping (dict) – labels and corresponding integers

    • +
    • default_label (str) – default label in label_mapping

    • +
    • pad_label (str) – pad label in label_mapping

    • +
    +
    +
    Returns
    +

    formatted predictions

    +
    +
    Return type
    +

    list

    +
    +
    +
    +
    +
    +static match_sentence_lengths(data: numpy.ndarray, results: dict, flatten_separator: str, inplace: bool = True) dict
    +

    Convert results from model into same ragged data shapes as original data.

    +
    +
    Parameters
    +
      +
    • data (numpy.ndarray) – original input data to the data labeler

    • +
    • results (dict) – dict of model character level predictions and confs

    • +
    • flatten_separator (str) – string which joins to samples together when +flattening

    • +
    • inplace (bool) – flag to modify results in place

    • +
    +
    +
    Returns
    +

    dict(pred=…) or dict(pred=…, conf=…)

    +
    +
    +
    +
    +
    +process(data: np.ndarray, results: dict, label_mapping: dict[str, int]) dict
    +

    Conduct processing on data given predictions, label_mapping, and default_label.

    +
    +
    Parameters
    +
      +
    • data (Union[np.ndarray, pd.DataFrame]) – original input data to the data labeler

    • +
    • results (dict) – dict of model character level predictions and confs

    • +
    • label_mapping (dict) – labels and corresponding integers

    • +
    +
    +
    Returns
    +

    dict of predictions and if they exist, confidences

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'postprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.StructCharPreprocessor(max_length: int = 3400, default_label: str = 'UNKNOWN', pad_label: str = 'PAD', flatten_separator: str = '\x01\x01\x01\x01\x01', is_separate_at_max_len: bool = False)
    +

    Bases: dataprofiler.labelers.data_processing.CharPreprocessor

    +

    Subclass of CharPreprocessor for preprocessing struct char data.

    +

    Initialize the StructCharPreprocessor class.

    +
    +
    Parameters
    +
      +
    • max_length (int) – Maximum char length in a sample.

    • +
    • default_label (string (could be int, char, etc.)) – Key for label_mapping that is the default label

    • +
    • pad_label (string (could be int, char, etc.)) – Key for label_mapping that is the pad label

    • +
    • flatten_separator (str) – separator used to put between flattened +samples.

    • +
    • is_separate_at_max_len (bool) – if true, separates at max_length, +otherwise at nearest separator

    • +
    +
    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for preprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +convert_to_unstructured_format(data: np.ndarray, labels: list[str] | npt.NDArray[np.str_] | None) tuple[str, list[tuple[int, int, str]] | None]
    +

    Convert data samples list to StructCharPreprocessor required input data format.

    +
    +
    Parameters
    +
      +
    • data (numpy.ndarray) – list of strings

    • +
    • labels (Optional[Union[List[str], npt.NDArray[np.str_]]]) – labels for each input character

    • +
    +
    +
    Returns
    +

    data in the following format +text=”<SAMPLE><SEPARATOR><SAMPLE>…”, +entities=[(start=<INT>, end=<INT>, label=”<LABEL>”),

    +
    +

    …(num_samples in data)])

    +
    +

    +
    +
    Return type
    +

    Tuple[str, Optional[List[Tuple[int, int, str]]]]

    +
    +
    +
    +
    +
    +process(data: np.ndarray, labels: np.ndarray | None = None, label_mapping: dict[str, int] | None = None, batch_size: int = 32) Generator[tuple[np.ndarray, np.ndarray] | np.ndarray, None, None]
    +

    Process structured data for being processed by CharacterLevelCnnModel.

    +
    +
    Parameters
    +
      +
    • data (numpy.ndarray) – List of strings to create embeddings for

    • +
    • labels (numpy.ndarray) – labels for each input character

    • +
    • label_mapping (Union[dict, None]) – maps labels to their encoded integers

    • +
    • batch_size (int) – Number of samples in the batch of data

    • +
    +
    +
    Return batch_data
    +

    A dict containing samples of size batch_size

    +
    +
    Rtype batch_data
    +

    dict

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'preprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.StructCharPostprocessor(default_label: str = 'UNKNOWN', pad_label: str = 'PAD', flatten_separator: str = '\x01\x01\x01\x01\x01', is_pred_labels: bool = True, random_state: random.Random | int | list | tuple | None = None)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPostprocessor

    +

    Subclass of BaseDataPostprocessor for postprocessing struct char data.

    +

    Initialize the StructCharPostprocessor class.

    +
    +
    Parameters
    +
      +
    • default_label (str) – Key for label_mapping that is the default label

    • +
    • pad_label (str) – Key for label_mapping that is the pad label

    • +
    • flatten_separator (str) – separator used to put between flattened +samples.

    • +
    • is_pred_labels (bool) – (default: true) if true, will convert the model +indexes to the label strings given the label_mapping

    • +
    • random_state (random.Random) – random state setting to be used for randomly +selecting a prediction when two labels have equal opportunity for +a given sample.

    • +
    +
    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +static match_sentence_lengths(data: numpy.ndarray, results: dict, flatten_separator: str, inplace: bool = True) dict
    +

    Convert results from model into same ragged data shapes as original data.

    +
    +
    Parameters
    +
      +
    • data (np.ndarray) – original input data to the data labeler

    • +
    • results (dict) – dict of model character level predictions and confs

    • +
    • flatten_separator (str) – string which joins to samples together when +flattening

    • +
    • inplace (bool) – flag to modify results in place

    • +
    +
    +
    Returns
    +

    dict(pred=…) or dict(pred=…, conf=…)

    +
    +
    +
    +
    +
    +convert_to_structured_analysis(sentences: np.ndarray, results: dict, label_mapping: dict[str, int], default_label: str, pad_label: str) dict
    +

    Convert unstructured results to a structured column analysis.

    +

    This assumes the column was flattened into a single sample, and takes mode of +all character predictions except for the separator labels. In cases of +tie, chose anything but background, otherwise randomly choose between +the remaining labels.

    +
    +
    Parameters
    +
      +
    • sentences (numpy.ndarray) – samples which were predicted upon

    • +
    • results (dict) – character predictions for each sample return from model

    • +
    • label_mapping (dict) – maps labels to their encoded integers

    • +
    • default_label (str) – Key for label_mapping that is the default label

    • +
    • pad_label (str) – Key for label_mapping that is the pad label

    • +
    +
    +
    Returns
    +

    prediction value for a single column

    +
    +
    +
    +
    +
    +process(data: np.ndarray, results: dict, label_mapping: dict[str, int]) dict
    +

    Postprocess CharacterLevelCnnModel results when given structured data.

    +

    Said structured data is processed by StructCharPreprocessor.

    +
    +
    Parameters
    +
      +
    • data (Union[numpy.ndarray, pandas.DataFrame]) – original input data to the data labeler

    • +
    • results – dict of model character level predictions and confs

    • +
    • results – dict

    • +
    • label_mapping (dict) – maps labels to their encoded integers

    • +
    +
    +
    Returns
    +

    dict of predictions and if they exist, confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'postprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.RegexPostProcessor(aggregation_func: str = 'split', priority_order: list | np.ndarray | None = None, random_state: random.Random | int | list | tuple | None = None)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPostprocessor

    +

    Subclass of BaseDataPostprocessor for postprocessing regex data.

    +

    Initialize the RegexPostProcessor class.

    +
    +
    Parameters
    +
      +
    • aggregation_func (str) – aggregation function to apply to regex model +output (split, random, priority)

    • +
    • priority_order (Union[list, numpy.ndarray]) – if priority is set as the aggregation function, +the order in which entities are given priority must be set

    • +
    • random_state (random.Random) – random state setting to be used for randomly +selecting a prediction when two labels have equal opportunity for +a given sample.

    • +
    +
    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +static priority_prediction(results: dict, entity_priority_order: numpy.ndarray) None
    +

    Use priority of regex to give entity determination.

    +
    +
    Parameters
    +
      +
    • results (dict) – regex from model in format: dict(pred=…, conf=…)

    • +
    • entity_priority_order (np.ndarray) – list of entity priorities (lowest has +higher priority)

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +static split_prediction(results: dict) None
    +

    Split the prediction across votes.

    +
    +
    Parameters
    +

    results (dict) – regex from model in format: dict(pred=…, conf=…)

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +process(data: np.ndarray, results: dict, label_mapping: dict[str, int]) dict
    +

    Preprocess data.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'postprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.StructRegexPostProcessor(random_state: random.Random | int | list | tuple | None = None)
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPostprocessor

    +

    Subclass of BaseDataPostprocessor for postprocessing struct regex data.

    +

    Initialize the RegexPostProcessor class.

    +
    +
    Parameters
    +

    random_state (random.Random) – random state setting to be used for randomly +selecting a prediction when two labels have equal opportunity for +a given sample.

    +
    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Given kwargs, set the parameters if they exist.

    +
    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +process(data: np.ndarray, results: dict, label_mapping: dict[str, int]) dict
    +

    Preprocess data.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'postprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +
    +class dataprofiler.labelers.data_processing.ColumnNameModelPostprocessor
    +

    Bases: dataprofiler.labelers.data_processing.BaseDataPostprocessor

    +

    Subclass of BaseDataPostprocessor for postprocessing regex data.

    +

    Initialize the ColumnNameModelPostProcessor class.

    +
    +
    +classmethod help() None
    +

    Describe alterable parameters.

    +

    Input data formats for preprocessors. +Output data formats for postprocessors.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +process(data: np.ndarray, results: dict, label_mapping: dict[str, int] | None = None) dict
    +

    Preprocess data.

    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseDataProcessor] | None
    +

    Get class of BaseDataProcessor object.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (list) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) Processor
    +

    Load data processor from a given path on disk.

    +
    +
    +
    +classmethod load_from_library(name: str) dataprofiler.labelers.data_processing.BaseDataProcessor
    +

    Load data processor from within the library.

    +
    +
    +
    +processor_type: str = 'postprocessor'
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save data processor to a path on disk.

    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.html b/docs/0.10.3/html/dataprofiler.labelers.html new file mode 100644 index 000000000..52792838d --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.html @@ -0,0 +1,360 @@ + + + + + + + + + Labelers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Labelers

    +
    +

    Modules

    +
    +
    + +

    The following will list the built-in models, processors, and data labelers.

    +
    +
    Models:
      +
    1. CharacterLevelCnnModel - character classification of text.

    2. +
    3. RegexModel - character classification of text.

    4. +
    +
    +
    Processors:
    +
    Preprocessors
      +
    1. CharPreprocessor

    2. +
    3. StructCharPreprocessor

    4. +
    5. DirectPassPreprocessor

    6. +
    +
    +
    PostProcessors
      +
    1. CharPreprocessor

    2. +
    3. StructCharPostprocessor

    4. +
    5. RegexPostProcessor

    6. +
    +
    +
    +
    +
    Data Labelers:
    +
    Classes
      +
    1. UnstructuredDataLabeler

    2. +
    3. StructuredDataLabeler

    4. +
    +
    +
    Files to load from disk using BaseDataLabeler.load_from_library(<NAME>)
      +
    1. unstructured_model

    2. +
    3. structured_model

    4. +
    5. regex_model

    6. +
    +
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.labeler_utils.html b/docs/0.10.3/html/dataprofiler.labelers.labeler_utils.html new file mode 100644 index 000000000..c0fe3c9c6 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.labeler_utils.html @@ -0,0 +1,2641 @@ + + + + + + + + + Labeler Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Labeler Utils

    +

    Contains functions for the data labeler.

    +
    +
    +dataprofiler.labelers.labeler_utils.f1_report_dict_to_str(f1_report: dict, label_names: list[str]) str
    +

    Return the report string from the f1_report dict.

    +
    +
    Example Output:
    +
    +

    precision recall f1-score support

    +
    +

    class 0 0.00 0.00 0.00 1 +class 1 1.00 0.67 0.80 3

    +
    +

    micro avg 0.67 0.50 0.57 4 +macro avg 0.50 0.33 0.40 4

    +
    +
    +

    weighted avg 0.75 0.50 0.60 4

    +

    Note: this is generally taken from the classification_report function +inside sklearn. +:param f1_report: f1 report dictionary from sklearn +:type f1_report: dict +:param label_names: names of labels included in the report +:type label_names: list(str) +:return: string representing f1_report printout +:rtype: str

    +
    +
    +
    +dataprofiler.labelers.labeler_utils.evaluate_accuracy(predicted_entities_in_index: list[list[int]], true_entities_in_index: list[list[int]], num_labels: int, entity_rev_dict: dict[int, str], verbose: bool = True, omitted_labels: tuple[str, ...] = ('PAD', 'UNKNOWN'), confusion_matrix_file: str | None = None) tuple[float, dict]
    +

    Evaluate accuracy from comparing predicted labels with true labels.

    +
    +
    Parameters
    +
      +
    • predicted_entities_in_index (list(array(int))) – predicted encoded labels for input +sentences

    • +
    • true_entities_in_index (list(array(int))) – true encoded labels for input sentences

    • +
    • entity_rev_dict (dict([index, entity])) – dictionary to convert indices to entities

    • +
    • verbose (boolean) – print additional information for debugging

    • +
    • omitted_labels (list() of text labels) – labels to omit from the accuracy evaluation

    • +
    • confusion_matrix_file (str) – File name (and dir) for confusion matrix

    • +
    +
    +
    +

    :return : f1-score +:rtype: float

    +
    +
    +
    +dataprofiler.labelers.labeler_utils.get_tf_layer_index_from_name(model: tf.keras.Model, layer_name: str) int | None
    +

    Return the index of the layer given the layer name within a tf model.

    +
    +
    Parameters
    +
      +
    • model – tf keras model to search

    • +
    • layer_name – name of the layer to find

    • +
    +
    +
    Returns
    +

    layer index if it exists or None

    +
    +
    +
    +
    +
    +dataprofiler.labelers.labeler_utils.hide_tf_logger_warnings() None
    +

    Filter out a set of warnings from the tf logger.

    +
    +
    +
    +dataprofiler.labelers.labeler_utils.protected_register_keras_serializable(package: str = 'Custom', name: str | None = None) Callable
    +

    Protect against already registered keras serializable layers.

    +

    Ensures that if it was already registered, it will not try to +register it again.

    +
    +
    +
    +class dataprofiler.labelers.labeler_utils.FBetaScore(*args, **kwargs)
    +

    Bases: keras.src.metrics.base_metric.Metric

    +

    Computes F-Beta score.

    +

    Adapted and slightly modified from https://github.com/tensorflow/addons/blob/v0.12.0/tensorflow_addons/metrics/f_scores.py#L211-L283

    +

    # Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the “License”); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# https://github.com/tensorflow/addons/blob/v0.12.0/LICENSE +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an “AS IS” BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ==============================================================================

    +

    It is the weighted harmonic mean of precision +and recall. Output range is [0, 1]. Works for +both multi-class and multi-label classification. +$$ +F_{beta} = (1 + beta^2) * frac{textrm{precision} * +textrm{precision}}{(beta^2 cdot textrm{precision}) + textrm{recall}} +$$ +:param num_classes: Number of unique classes in the dataset. +:param average: Type of averaging to be performed on data.

    +
    +

    Acceptable values are None, micro, macro and +weighted. Default value is None.

    +
    +
    +
    Parameters
    +
      +
    • beta – Determines the weight of precision and recall +in harmonic mean. Determines the weight given to the +precision and recall. Default value is 1.

    • +
    • threshold – Elements of y_pred greater than threshold are +converted to be 1, and the rest 0. If threshold is +None, the argmax is converted to 1, and the rest 0.

    • +
    • name – (Optional) String name of the metric instance.

    • +
    • dtype – (Optional) Data type of the metric result.

    • +
    +
    +
    Returns
    +

    float.

    +
    +
    Return type
    +

    F-Beta Score

    +
    +
    +

    Initialize FBetaScore class.

    +
    +
    +update_state(y_true: tf.Tensor, y_pred: tf.Tensor, sample_weight: tf.Tensor | None = None) None
    +

    Update state.

    +
    +
    +
    +result() tensorflow.python.framework.ops.Tensor
    +

    Return f1 score.

    +
    +
    +
    +get_config() dict
    +

    Return the serializable config of the metric.

    +
    +
    +
    +reset_state() None
    +

    Reset state.

    +
    +
    +
    +property activity_regularizer
    +

    Optional regularizer function for the output of this layer.

    +
    +
    +
    +add_loss(losses, **kwargs)
    +

    Add loss tensor(s), potentially dependent on layer inputs.

    +

    Some losses (for instance, activity regularization losses) may be +dependent on the inputs passed when calling a layer. Hence, when reusing +the same layer on different inputs a and b, some entries in +layer.losses may be dependent on a and some on b. This method +automatically keeps track of dependencies.

    +

    This method can be used inside a subclassed layer or model’s call +function, in which case losses should be a Tensor or list of Tensors.

    +

    Example:

    +

    ```python +class MyLayer(tf.keras.layers.Layer):

    +
    +
    +
    def call(self, inputs):

    self.add_loss(tf.abs(tf.reduce_mean(inputs))) +return inputs

    +
    +
    +
    +

    ```

    +

    The same code works in distributed training: the input to add_loss() +is treated like a regularization loss and averaged across replicas +by the training loop (both built-in Model.fit() and compliant custom +training loops).

    +

    The add_loss method can also be called directly on a Functional Model +during construction. In this case, any loss Tensors passed to this Model +must be symbolic and be able to be traced back to the model’s Input`s. +These losses become part of the model’s topology and are tracked in +`get_config.

    +

    Example:

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +x = tf.keras.layers.Dense(10)(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +# Activity regularization. +model.add_loss(tf.abs(tf.reduce_mean(x))) +`

    +

    If this is not the case for your loss (if, for example, your loss +references a Variable of one of the model’s layers), you can wrap your +loss in a zero-argument lambda. These losses are not tracked as part of +the model’s topology since they can’t be serialized.

    +

    Example:

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +d = tf.keras.layers.Dense(10) +x = d(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +# Weight regularization. +model.add_loss(lambda: tf.reduce_mean(d.kernel)) +`

    +
    +
    Parameters
    +
      +
    • losses – Loss tensor, or list/tuple of tensors. Rather than tensors, +losses may also be zero-argument callables which create a loss +tensor.

    • +
    • **kwargs – Used for backwards compatibility only.

    • +
    +
    +
    +
    +
    +
    +add_metric(value, name=None, **kwargs)
    +

    Adds metric tensor to the layer.

    +

    This method can be used inside the call() method of a subclassed layer +or model.

    +

    ```python +class MyMetricLayer(tf.keras.layers.Layer):

    +
    +
    +
    def __init__(self):

    super(MyMetricLayer, self).__init__(name=’my_metric_layer’) +self.mean = tf.keras.metrics.Mean(name=’metric_1’)

    +
    +
    def call(self, inputs):

    self.add_metric(self.mean(inputs)) +self.add_metric(tf.reduce_sum(inputs), name=’metric_2’) +return inputs

    +
    +
    +
    +

    ```

    +

    This method can also be called directly on a Functional Model during +construction. In this case, any tensor passed to this Model must +be symbolic and be able to be traced back to the model’s Input`s. These +metrics become part of the model’s topology and are tracked when you +save the model via `save().

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +x = tf.keras.layers.Dense(10)(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +model.add_metric(math_ops.reduce_sum(x), name='metric_1') +`

    +

    Note: Calling add_metric() with the result of a metric object on a +Functional Model, as shown in the example below, is not supported. This +is because we cannot trace the metric result tensor back to the model’s +inputs.

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +x = tf.keras.layers.Dense(10)(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +model.add_metric(tf.keras.metrics.Mean()(x), name='metric_1') +`

    +
    +
    Parameters
    +
      +
    • value – Metric tensor.

    • +
    • name – String metric name.

    • +
    • **kwargs – Additional keyword arguments for backward compatibility. +Accepted values: +aggregation - When the value tensor provided is not the result +of calling a keras.Metric instance, it will be aggregated by +default using a keras.Metric.Mean.

    • +
    +
    +
    +
    +
    +
    +add_update(updates)
    +

    Add update op(s), potentially dependent on layer inputs.

    +

    Weight updates (for instance, the updates of the moving mean and +variance in a BatchNormalization layer) may be dependent on the inputs +passed when calling a layer. Hence, when reusing the same layer on +different inputs a and b, some entries in layer.updates may be +dependent on a and some on b. This method automatically keeps track +of dependencies.

    +

    This call is ignored when eager execution is enabled (in that case, +variable updates are run on the fly and thus do not need to be tracked +for later execution).

    +
    +
    Parameters
    +

    updates – Update op, or list/tuple of update ops, or zero-arg callable +that returns an update op. A zero-arg callable should be passed in +order to disable running the updates by setting trainable=False +on this Layer, when executing in Eager mode.

    +
    +
    +
    +
    +
    +add_variable(*args, **kwargs)
    +

    Deprecated, do NOT use! Alias for add_weight.

    +
    +
    +
    +add_weight(name, shape=(), aggregation=VariableAggregationV2.SUM, synchronization=VariableSynchronization.ON_READ, initializer=None, dtype=None)
    +

    Adds state variable. Only for use by subclasses.

    +
    +
    +
    +build(input_shape)
    +

    Creates the variables of the layer (for subclass implementers).

    +

    This is a method that implementers of subclasses of Layer or Model +can override if they need a state-creation step in-between +layer instantiation and layer call. It is invoked automatically before +the first execution of call().

    +

    This is typically used to create the weights of Layer subclasses +(at the discretion of the subclass implementer).

    +
    +
    Parameters
    +

    input_shape – Instance of TensorShape, or list of instances of +TensorShape if the layer expects a list of inputs +(one instance per input).

    +
    +
    +
    +
    +
    +build_from_config(config)
    +

    Builds the layer’s states with the supplied config dict.

    +

    By default, this method calls the build(config[“input_shape”]) method, +which creates weights based on the layer’s input shape in the supplied +config. If your config contains other information needed to load the +layer’s state, you should override this method.

    +
    +
    Parameters
    +

    config – Dict containing the input shape associated with this layer.

    +
    +
    +
    +
    +
    +call(inputs, *args, **kwargs)
    +

    This is where the layer’s logic lives.

    +

    The call() method may not create state (except in its first +invocation, wrapping the creation of variables or other resources in +tf.init_scope()). It is recommended to create state, including +tf.Variable instances and nested Layer instances,

    +
    +

    in __init__(), or in the build() method that is

    +
    +

    called automatically before call() executes for the first time.

    +
    +
    Parameters
    +
      +
    • inputs

      Input tensor, or dict/list/tuple of input tensors. +The first positional inputs argument is subject to special rules: +- inputs must be explicitly passed. A layer cannot have zero

      +
      +

      arguments, and inputs cannot be provided via the default value +of a keyword argument.

      +
      +
        +
      • NumPy array or Python scalar values in inputs get cast as +tensors.

      • +
      • Keras mask metadata is only collected from inputs.

      • +
      • Layers are built (build(input_shape) method) +using shape info from inputs only.

      • +
      • input_spec compatibility is only checked against inputs.

      • +
      • Mixed precision input casting is only applied to inputs. +If a layer has tensor arguments in *args or **kwargs, their +casting behavior in mixed precision should be handled manually.

      • +
      • The SavedModel input specification is generated using inputs +only.

      • +
      • Integration with various ecosystem packages like TFMOT, TFLite, +TF.js, etc is only supported for inputs and not for tensors in +positional and keyword arguments.

      • +
      +

    • +
    • *args – Additional positional arguments. May contain tensors, although +this is not recommended, for the reasons above.

    • +
    • **kwargs

      Additional keyword arguments. May contain tensors, although +this is not recommended, for the reasons above. +The following optional keyword arguments are reserved: +- training: Boolean scalar tensor of Python boolean indicating

      +
      +

      whether the call is meant for training or inference.

      +
      +
        +
      • mask: Boolean input mask. If the layer’s call() method takes a +mask argument, its default value will be set to the mask +generated for inputs by the previous layer (if input did come +from a layer that generated a corresponding mask, i.e. if it came +from a Keras layer with masking support).

      • +
      +

    • +
    +
    +
    Returns
    +

    A tensor or list/tuple of tensors.

    +
    +
    +
    +
    +
    +property compute_dtype
    +

    The dtype of the layer’s computations.

    +

    This is equivalent to Layer.dtype_policy.compute_dtype. Unless +mixed precision is used, this is the same as Layer.dtype, the dtype of +the weights.

    +

    Layers automatically cast their inputs to the compute dtype, which +causes computations and the output to be in the compute dtype as well. +This is done by the base Layer class in Layer.__call__, so you do not +have to insert these casts if implementing your own layer.

    +

    Layers often perform certain internal computations in higher precision +when compute_dtype is float16 or bfloat16 for numeric stability. The +output will still typically be float16 or bfloat16 in such cases.

    +
    +
    Returns
    +

    The layer’s compute dtype.

    +
    +
    +
    +
    +
    +compute_mask(inputs, mask=None)
    +

    Computes an output mask tensor.

    +
    +
    Parameters
    +
      +
    • inputs – Tensor or list of tensors.

    • +
    • mask – Tensor or list of tensors.

    • +
    +
    +
    Returns
    +

    +
    None or a tensor (or list of tensors,

    one per output tensor of the layer).

    +
    +
    +

    +
    +
    +
    +
    +
    +compute_output_shape(input_shape)
    +

    Computes the output shape of the layer.

    +

    This method will cause the layer’s state to be built, if that has not +happened before. This requires that the layer will later be used with +inputs that match the input shape provided here.

    +
    +
    Parameters
    +

    input_shape – Shape tuple (tuple of integers) or tf.TensorShape, +or structure of shape tuples / tf.TensorShape instances +(one per output tensor of the layer). +Shape tuples can include None for free dimensions, +instead of an integer.

    +
    +
    Returns
    +

    A tf.TensorShape instance +or structure of tf.TensorShape instances.

    +
    +
    +
    +
    +
    +compute_output_signature(input_signature)
    +

    Compute the output tensor signature of the layer based on the inputs.

    +

    Unlike a TensorShape object, a TensorSpec object contains both shape +and dtype information for a tensor. This method allows layers to provide +output dtype information if it is different from the input dtype. +For any layer that doesn’t implement this function, +the framework will fall back to use compute_output_shape, and will +assume that the output dtype matches the input dtype.

    +
    +
    Parameters
    +

    input_signature – Single TensorSpec or nested structure of TensorSpec +objects, describing a candidate input for the layer.

    +
    +
    Returns
    +

    +
    Single TensorSpec or nested structure of TensorSpec objects,

    describing how the layer would transform the provided input.

    +
    +
    +

    +
    +
    Raises
    +

    TypeError – If input_signature contains a non-TensorSpec object.

    +
    +
    +
    +
    +
    +count_params()
    +

    Count the total number of scalars composing the weights.

    +
    +
    Returns
    +

    An integer count.

    +
    +
    Raises
    +

    ValueError – if the layer isn’t yet built + (in which case its weights aren’t yet defined).

    +
    +
    +
    +
    +
    +property dtype
    +

    The dtype of the layer weights.

    +

    This is equivalent to Layer.dtype_policy.variable_dtype. Unless +mixed precision is used, this is the same as Layer.compute_dtype, the +dtype of the layer’s computations.

    +
    +
    +
    +property dtype_policy
    +

    The dtype policy associated with this layer.

    +

    This is an instance of a tf.keras.mixed_precision.Policy.

    +
    +
    +
    +property dynamic
    +

    Whether the layer is dynamic (eager-only); set in the constructor.

    +
    +
    +
    +finalize_state()
    +

    Finalizes the layers state after updating layer weights.

    +

    This function can be subclassed in a layer and will be called after +updating a layer weights. It can be overridden to finalize any +additional layer state after a weight update.

    +

    This function will be called after weights of a layer have been restored +from a loaded model.

    +
    +
    +
    +classmethod from_config(config)
    +

    Creates a layer from its config.

    +

    This method is the reverse of get_config, +capable of instantiating the same layer from the config +dictionary. It does not handle layer connectivity +(handled by Network), nor weights (handled by set_weights).

    +
    +
    Parameters
    +

    config – A Python dictionary, typically the +output of get_config.

    +
    +
    Returns
    +

    A layer instance.

    +
    +
    +
    +
    +
    +get_build_config()
    +

    Returns a dictionary with the layer’s input shape.

    +

    This method returns a config dict that can be used by +build_from_config(config) to create all states (e.g. Variables and +Lookup tables) needed by the layer.

    +

    By default, the config only contains the input shape that the layer +was built with. If you’re writing a custom layer that creates state in +an unusual way, you should override this method to make sure this state +is already created when Keras attempts to load its value upon model +loading.

    +
    +
    Returns
    +

    A dict containing the input shape associated with the layer.

    +
    +
    +
    +
    +
    +get_input_at(node_index)
    +

    Retrieves the input tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first input node of the layer.

    +
    +
    Returns
    +

    A tensor (or list of tensors if the layer has multiple inputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_input_mask_at(node_index)
    +

    Retrieves the input mask tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A mask tensor +(or list of tensors if the layer has multiple inputs).

    +
    +
    +
    +
    +
    +get_input_shape_at(node_index)
    +

    Retrieves the input shape(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A shape tuple +(or list of shape tuples if the layer has multiple inputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_output_at(node_index)
    +

    Retrieves the output tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first output node of the layer.

    +
    +
    Returns
    +

    A tensor (or list of tensors if the layer has multiple outputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_output_mask_at(node_index)
    +

    Retrieves the output mask tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A mask tensor +(or list of tensors if the layer has multiple outputs).

    +
    +
    +
    +
    +
    +get_output_shape_at(node_index)
    +

    Retrieves the output shape(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A shape tuple +(or list of shape tuples if the layer has multiple outputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_weights()
    +

    Returns the current weights of the layer, as NumPy arrays.

    +

    The weights of a layer represent the state of the layer. This function +returns both trainable and non-trainable weight values associated with +this layer as a list of NumPy arrays, which can in turn be used to load +state into similarly parameterized layers.

    +

    For example, a Dense layer returns a list of two values: the kernel +matrix and the bias vector. These can be used to set the weights of +another Dense layer:

    +
    >>> layer_a = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(1.))
    +>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
    +>>> layer_a.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(2.))
    +>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
    +>>> layer_b.get_weights()
    +[array([[2.],
    +       [2.],
    +       [2.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b.set_weights(layer_a.get_weights())
    +>>> layer_b.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +
    +
    +
    +
    Returns
    +

    Weights values as a list of NumPy arrays.

    +
    +
    +
    +
    +
    +property inbound_nodes
    +

    Return Functional API nodes upstream of this layer.

    +
    +
    +
    +property input
    +

    Retrieves the input tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one input, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Input tensor or list of input tensors.

    +
    +
    Raises
    +
      +
    • RuntimeError – If called in Eager mode.

    • +
    • AttributeError – If no inbound nodes are found.

    • +
    +
    +
    +
    +
    +
    +property input_mask
    +

    Retrieves the input mask tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one inbound node, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Input mask tensor (potentially None) or list of input +mask tensors.

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer is connected to

    • +
    • more than one incoming layers.

    • +
    +
    +
    +
    +
    +
    +property input_shape
    +

    Retrieves the input shape(s) of a layer.

    +

    Only applicable if the layer has exactly one input, +i.e. if it is connected to one incoming layer, or if all inputs +have the same shape.

    +
    +
    Returns
    +

    Input shape, as an integer shape tuple +(or list of shape tuples, one tuple per input tensor).

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer has no defined input_shape.

    • +
    • RuntimeError – if called in Eager mode.

    • +
    +
    +
    +
    +
    +
    +property input_spec
    +

    InputSpec instance(s) describing the input format for this layer.

    +

    When you create a layer subclass, you can set self.input_spec to +enable the layer to run input compatibility checks when it is called. +Consider a Conv2D layer: it can only be called on a single input +tensor of rank 4. As such, you can set, in __init__():

    +

    `python +self.input_spec = tf.keras.layers.InputSpec(ndim=4) +`

    +

    Now, if you try to call the layer on an input that isn’t rank 4 +(for instance, an input of shape (2,), it will raise a +nicely-formatted error:

    +

    ` +ValueError: Input 0 of layer conv2d is incompatible with the layer: +expected ndim=4, found ndim=1. Full shape received: [2] +`

    +

    Input checks that can be specified via input_spec include: +- Structure (e.g. a single input, a list of 2 inputs, etc) +- Shape +- Rank (ndim) +- Dtype

    +

    For more information, see tf.keras.layers.InputSpec.

    +
    +
    Returns
    +

    A tf.keras.layers.InputSpec instance, or nested structure thereof.

    +
    +
    +
    +
    +
    +load_own_variables(store)
    +

    Loads the state of the layer.

    +

    You can override this method to take full control of how the state of +the layer is loaded upon calling keras.models.load_model().

    +
    +
    Parameters
    +

    store – Dict from which the state of the model will be loaded.

    +
    +
    +
    +
    +
    +property losses
    +

    List of losses added using the add_loss() API.

    +

    Variable regularization tensors are created when this property is +accessed, so it is eager safe: accessing losses under a +tf.GradientTape will propagate gradients back to the corresponding +variables.

    +

    Examples:

    +
    >>> class MyLayer(tf.keras.layers.Layer):
    +...   def call(self, inputs):
    +...     self.add_loss(tf.abs(tf.reduce_mean(inputs)))
    +...     return inputs
    +>>> l = MyLayer()
    +>>> l(np.ones((10, 1)))
    +>>> l.losses
    +[1.0]
    +
    +
    +
    >>> inputs = tf.keras.Input(shape=(10,))
    +>>> x = tf.keras.layers.Dense(10)(inputs)
    +>>> outputs = tf.keras.layers.Dense(1)(x)
    +>>> model = tf.keras.Model(inputs, outputs)
    +>>> # Activity regularization.
    +>>> len(model.losses)
    +0
    +>>> model.add_loss(tf.abs(tf.reduce_mean(x)))
    +>>> len(model.losses)
    +1
    +
    +
    +
    >>> inputs = tf.keras.Input(shape=(10,))
    +>>> d = tf.keras.layers.Dense(10, kernel_initializer='ones')
    +>>> x = d(inputs)
    +>>> outputs = tf.keras.layers.Dense(1)(x)
    +>>> model = tf.keras.Model(inputs, outputs)
    +>>> # Weight regularization.
    +>>> model.add_loss(lambda: tf.reduce_mean(d.kernel))
    +>>> model.losses
    +[<tf.Tensor: shape=(), dtype=float32, numpy=1.0>]
    +
    +
    +
    +
    Returns
    +

    A list of tensors.

    +
    +
    +
    +
    +
    +merge_state(metrics)
    +

    Merges the state from one or more metrics.

    +

    This method can be used by distributed systems to merge the state +computed by different metric instances. Typically the state will be +stored in the form of the metric’s weights. For example, a +tf.keras.metrics.Mean metric contains a list of two weight values: a +total and a count. If there were two instances of a +tf.keras.metrics.Accuracy that each independently aggregated partial +state for an overall accuracy calculation, these two metric’s states +could be combined as follows:

    +
    >>> m1 = tf.keras.metrics.Accuracy()
    +>>> _ = m1.update_state([[1], [2]], [[0], [2]])
    +
    +
    +
    >>> m2 = tf.keras.metrics.Accuracy()
    +>>> _ = m2.update_state([[3], [4]], [[3], [4]])
    +
    +
    +
    >>> m2.merge_state([m1])
    +>>> m2.result().numpy()
    +0.75
    +
    +
    +
    +
    Parameters
    +

    metrics – an iterable of metrics. The metrics must have compatible +state.

    +
    +
    Raises
    +

    ValueError – If the provided iterable does not contain metrics matching + the metric’s required specifications.

    +
    +
    +
    +
    +
    +property metrics
    +

    List of metrics added using the add_metric() API.

    +

    Example:

    +
    >>> input = tf.keras.layers.Input(shape=(3,))
    +>>> d = tf.keras.layers.Dense(2)
    +>>> output = d(input)
    +>>> d.add_metric(tf.reduce_max(output), name='max')
    +>>> d.add_metric(tf.reduce_min(output), name='min')
    +>>> [m.name for m in d.metrics]
    +['max', 'min']
    +
    +
    +
    +
    Returns
    +

    A list of Metric objects.

    +
    +
    +
    +
    +
    +property name
    +

    Name of the layer (string), set in the constructor.

    +
    +
    +
    +property name_scope
    +

    Returns a tf.name_scope instance for this class.

    +
    +
    +
    +property non_trainable_variables
    +

    Sequence of non-trainable variables owned by this module and its submodules.

    +

    Note: this method uses reflection to find variables on the current instance +and submodules. For performance reasons you may wish to cache the result +of calling this method if you don’t expect the return value to change.

    +
    +
    Returns
    +

    A sequence of variables for the current module (sorted by attribute +name) followed by variables from all submodules recursively (breadth +first).

    +
    +
    +
    +
    +
    +property non_trainable_weights
    +

    List of all non-trainable weights tracked by this layer.

    +

    Non-trainable weights are not updated during training. They are +expected to be updated manually in call().

    +
    +
    Returns
    +

    A list of non-trainable variables.

    +
    +
    +
    +
    +
    +property outbound_nodes
    +

    Return Functional API nodes downstream of this layer.

    +
    +
    +
    +property output
    +

    Retrieves the output tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one output, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Output tensor or list of output tensors.

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer is connected to more than one incoming + layers.

    • +
    • RuntimeError – if called in Eager mode.

    • +
    +
    +
    +
    +
    +
    +property output_mask
    +

    Retrieves the output mask tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one inbound node, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Output mask tensor (potentially None) or list of output +mask tensors.

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer is connected to

    • +
    • more than one incoming layers.

    • +
    +
    +
    +
    +
    +
    +property output_shape
    +

    Retrieves the output shape(s) of a layer.

    +

    Only applicable if the layer has one output, +or if all outputs have the same shape.

    +
    +
    Returns
    +

    Output shape, as an integer shape tuple +(or list of shape tuples, one tuple per output tensor).

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer has no defined output shape.

    • +
    • RuntimeError – if called in Eager mode.

    • +
    +
    +
    +
    +
    +
    +reset_states()
    +
    +
    +
    +save_own_variables(store)
    +

    Saves the state of the layer.

    +

    You can override this method to take full control of how the state of +the layer is saved upon calling model.save().

    +
    +
    Parameters
    +

    store – Dict where the state of the model will be saved.

    +
    +
    +
    +
    +
    +set_weights(weights)
    +

    Sets the weights of the layer, from NumPy arrays.

    +

    The weights of a layer represent the state of the layer. This function +sets the weight values from numpy arrays. The weight values should be +passed in the order they are created by the layer. Note that the layer’s +weights must be instantiated before calling this function, by calling +the layer.

    +

    For example, a Dense layer returns a list of two values: the kernel +matrix and the bias vector. These can be used to set the weights of +another Dense layer:

    +
    >>> layer_a = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(1.))
    +>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
    +>>> layer_a.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(2.))
    +>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
    +>>> layer_b.get_weights()
    +[array([[2.],
    +       [2.],
    +       [2.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b.set_weights(layer_a.get_weights())
    +>>> layer_b.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +
    +
    +
    +
    Parameters
    +

    weights – a list of NumPy arrays. The number +of arrays and their shape must match +number of the dimensions of the weights +of the layer (i.e. it should match the +output of get_weights).

    +
    +
    Raises
    +

    ValueError – If the provided weights list does not match the + layer’s specifications.

    +
    +
    +
    +
    +
    +property stateful
    +
    +
    +
    +property submodules
    +

    Sequence of all sub-modules.

    +

    Submodules are modules which are properties of this module, or found as +properties of modules which are properties of this module (and so on).

    +
    >>> a = tf.Module()
    +>>> b = tf.Module()
    +>>> c = tf.Module()
    +>>> a.b = b
    +>>> b.c = c
    +>>> list(a.submodules) == [b, c]
    +True
    +>>> list(b.submodules) == [c]
    +True
    +>>> list(c.submodules) == []
    +True
    +
    +
    +
    +
    Returns
    +

    A sequence of all submodules.

    +
    +
    +
    +
    +
    +property supports_masking
    +

    Whether this layer supports computing a mask using compute_mask.

    +
    +
    +
    +property trainable
    +
    +
    +
    +property trainable_variables
    +

    Sequence of trainable variables owned by this module and its submodules.

    +

    Note: this method uses reflection to find variables on the current instance +and submodules. For performance reasons you may wish to cache the result +of calling this method if you don’t expect the return value to change.

    +
    +
    Returns
    +

    A sequence of variables for the current module (sorted by attribute +name) followed by variables from all submodules recursively (breadth +first).

    +
    +
    +
    +
    +
    +property trainable_weights
    +

    List of all trainable weights tracked by this layer.

    +

    Trainable weights are updated via gradient descent during training.

    +
    +
    Returns
    +

    A list of trainable variables.

    +
    +
    +
    +
    +
    +property updates
    +
    +
    +
    +property variable_dtype
    +

    Alias of Layer.dtype, the dtype of the weights.

    +
    +
    +
    +property variables
    +

    Returns the list of all layer variables/weights.

    +

    Alias of self.weights.

    +

    Note: This will not track the weights of nested tf.Modules that are +not themselves Keras layers.

    +
    +
    Returns
    +

    A list of variables.

    +
    +
    +
    +
    +
    +property weights
    +

    Returns the list of all layer variables/weights.

    +
    +
    Returns
    +

    A list of variables.

    +
    +
    +
    +
    +
    +classmethod with_name_scope(method)
    +

    Decorator to automatically enter the module name scope.

    +
    >>> class MyModule(tf.Module):
    +...   @tf.Module.with_name_scope
    +...   def __call__(self, x):
    +...     if not hasattr(self, 'w'):
    +...       self.w = tf.Variable(tf.random.normal([x.shape[1], 3]))
    +...     return tf.matmul(x, self.w)
    +
    +
    +

    Using the above module would produce `tf.Variable`s and `tf.Tensor`s whose +names included the module name:

    +
    >>> mod = MyModule()
    +>>> mod(tf.ones([1, 2]))
    +<tf.Tensor: shape=(1, 3), dtype=float32, numpy=..., dtype=float32)>
    +>>> mod.w
    +<tf.Variable 'my_module/Variable:0' shape=(2, 3) dtype=float32,
    +numpy=..., dtype=float32)>
    +
    +
    +
    +
    Parameters
    +

    method – The method to wrap.

    +
    +
    Returns
    +

    The original method wrapped such that it enters the module’s name scope.

    +
    +
    +
    +
    +
    +
    +class dataprofiler.labelers.labeler_utils.F1Score(*args, **kwargs)
    +

    Bases: dataprofiler.labelers.labeler_utils.FBetaScore

    +

    Computes F-1 Score.

    +

    # Copyright 2019 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the “License”); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# https://github.com/tensorflow/addons/blob/v0.12.0/LICENSE +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an “AS IS” BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ==============================================================================

    +

    It is the harmonic mean of precision and recall. +Output range is [0, 1]. Works for both multi-class +and multi-label classification. +$$ +F_1 = 2 cdot frac{textrm{precision} +cdot textrm{recall}}{textrm{precision} + textrm{recall}} +$$ +:param num_classes: Number of unique classes in the dataset. +:param average: Type of averaging to be performed on data.

    +
    +

    Acceptable values are None, micro, macro +and weighted. Default value is None.

    +
    +
    +
    Parameters
    +
      +
    • threshold – Elements of y_pred above threshold are +considered to be 1, and the rest 0. If threshold is +None, the argmax is converted to 1, and the rest 0.

    • +
    • name – (Optional) String name of the metric instance.

    • +
    • dtype – (Optional) Data type of the metric result.

    • +
    +
    +
    Returns
    +

    float.

    +
    +
    Return type
    +

    F-1 Score

    +
    +
    +

    Initialize F1Score object.

    +
    +
    +property activity_regularizer
    +

    Optional regularizer function for the output of this layer.

    +
    +
    +
    +add_loss(losses, **kwargs)
    +

    Add loss tensor(s), potentially dependent on layer inputs.

    +

    Some losses (for instance, activity regularization losses) may be +dependent on the inputs passed when calling a layer. Hence, when reusing +the same layer on different inputs a and b, some entries in +layer.losses may be dependent on a and some on b. This method +automatically keeps track of dependencies.

    +

    This method can be used inside a subclassed layer or model’s call +function, in which case losses should be a Tensor or list of Tensors.

    +

    Example:

    +

    ```python +class MyLayer(tf.keras.layers.Layer):

    +
    +
    +
    def call(self, inputs):

    self.add_loss(tf.abs(tf.reduce_mean(inputs))) +return inputs

    +
    +
    +
    +

    ```

    +

    The same code works in distributed training: the input to add_loss() +is treated like a regularization loss and averaged across replicas +by the training loop (both built-in Model.fit() and compliant custom +training loops).

    +

    The add_loss method can also be called directly on a Functional Model +during construction. In this case, any loss Tensors passed to this Model +must be symbolic and be able to be traced back to the model’s Input`s. +These losses become part of the model’s topology and are tracked in +`get_config.

    +

    Example:

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +x = tf.keras.layers.Dense(10)(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +# Activity regularization. +model.add_loss(tf.abs(tf.reduce_mean(x))) +`

    +

    If this is not the case for your loss (if, for example, your loss +references a Variable of one of the model’s layers), you can wrap your +loss in a zero-argument lambda. These losses are not tracked as part of +the model’s topology since they can’t be serialized.

    +

    Example:

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +d = tf.keras.layers.Dense(10) +x = d(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +# Weight regularization. +model.add_loss(lambda: tf.reduce_mean(d.kernel)) +`

    +
    +
    Parameters
    +
      +
    • losses – Loss tensor, or list/tuple of tensors. Rather than tensors, +losses may also be zero-argument callables which create a loss +tensor.

    • +
    • **kwargs – Used for backwards compatibility only.

    • +
    +
    +
    +
    +
    +
    +add_metric(value, name=None, **kwargs)
    +

    Adds metric tensor to the layer.

    +

    This method can be used inside the call() method of a subclassed layer +or model.

    +

    ```python +class MyMetricLayer(tf.keras.layers.Layer):

    +
    +
    +
    def __init__(self):

    super(MyMetricLayer, self).__init__(name=’my_metric_layer’) +self.mean = tf.keras.metrics.Mean(name=’metric_1’)

    +
    +
    def call(self, inputs):

    self.add_metric(self.mean(inputs)) +self.add_metric(tf.reduce_sum(inputs), name=’metric_2’) +return inputs

    +
    +
    +
    +

    ```

    +

    This method can also be called directly on a Functional Model during +construction. In this case, any tensor passed to this Model must +be symbolic and be able to be traced back to the model’s Input`s. These +metrics become part of the model’s topology and are tracked when you +save the model via `save().

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +x = tf.keras.layers.Dense(10)(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +model.add_metric(math_ops.reduce_sum(x), name='metric_1') +`

    +

    Note: Calling add_metric() with the result of a metric object on a +Functional Model, as shown in the example below, is not supported. This +is because we cannot trace the metric result tensor back to the model’s +inputs.

    +

    `python +inputs = tf.keras.Input(shape=(10,)) +x = tf.keras.layers.Dense(10)(inputs) +outputs = tf.keras.layers.Dense(1)(x) +model = tf.keras.Model(inputs, outputs) +model.add_metric(tf.keras.metrics.Mean()(x), name='metric_1') +`

    +
    +
    Parameters
    +
      +
    • value – Metric tensor.

    • +
    • name – String metric name.

    • +
    • **kwargs – Additional keyword arguments for backward compatibility. +Accepted values: +aggregation - When the value tensor provided is not the result +of calling a keras.Metric instance, it will be aggregated by +default using a keras.Metric.Mean.

    • +
    +
    +
    +
    +
    +
    +add_update(updates)
    +

    Add update op(s), potentially dependent on layer inputs.

    +

    Weight updates (for instance, the updates of the moving mean and +variance in a BatchNormalization layer) may be dependent on the inputs +passed when calling a layer. Hence, when reusing the same layer on +different inputs a and b, some entries in layer.updates may be +dependent on a and some on b. This method automatically keeps track +of dependencies.

    +

    This call is ignored when eager execution is enabled (in that case, +variable updates are run on the fly and thus do not need to be tracked +for later execution).

    +
    +
    Parameters
    +

    updates – Update op, or list/tuple of update ops, or zero-arg callable +that returns an update op. A zero-arg callable should be passed in +order to disable running the updates by setting trainable=False +on this Layer, when executing in Eager mode.

    +
    +
    +
    +
    +
    +add_variable(*args, **kwargs)
    +

    Deprecated, do NOT use! Alias for add_weight.

    +
    +
    +
    +add_weight(name, shape=(), aggregation=VariableAggregationV2.SUM, synchronization=VariableSynchronization.ON_READ, initializer=None, dtype=None)
    +

    Adds state variable. Only for use by subclasses.

    +
    +
    +
    +build(input_shape)
    +

    Creates the variables of the layer (for subclass implementers).

    +

    This is a method that implementers of subclasses of Layer or Model +can override if they need a state-creation step in-between +layer instantiation and layer call. It is invoked automatically before +the first execution of call().

    +

    This is typically used to create the weights of Layer subclasses +(at the discretion of the subclass implementer).

    +
    +
    Parameters
    +

    input_shape – Instance of TensorShape, or list of instances of +TensorShape if the layer expects a list of inputs +(one instance per input).

    +
    +
    +
    +
    +
    +build_from_config(config)
    +

    Builds the layer’s states with the supplied config dict.

    +

    By default, this method calls the build(config[“input_shape”]) method, +which creates weights based on the layer’s input shape in the supplied +config. If your config contains other information needed to load the +layer’s state, you should override this method.

    +
    +
    Parameters
    +

    config – Dict containing the input shape associated with this layer.

    +
    +
    +
    +
    +
    +call(inputs, *args, **kwargs)
    +

    This is where the layer’s logic lives.

    +

    The call() method may not create state (except in its first +invocation, wrapping the creation of variables or other resources in +tf.init_scope()). It is recommended to create state, including +tf.Variable instances and nested Layer instances,

    +
    +

    in __init__(), or in the build() method that is

    +
    +

    called automatically before call() executes for the first time.

    +
    +
    Parameters
    +
      +
    • inputs

      Input tensor, or dict/list/tuple of input tensors. +The first positional inputs argument is subject to special rules: +- inputs must be explicitly passed. A layer cannot have zero

      +
      +

      arguments, and inputs cannot be provided via the default value +of a keyword argument.

      +
      +
        +
      • NumPy array or Python scalar values in inputs get cast as +tensors.

      • +
      • Keras mask metadata is only collected from inputs.

      • +
      • Layers are built (build(input_shape) method) +using shape info from inputs only.

      • +
      • input_spec compatibility is only checked against inputs.

      • +
      • Mixed precision input casting is only applied to inputs. +If a layer has tensor arguments in *args or **kwargs, their +casting behavior in mixed precision should be handled manually.

      • +
      • The SavedModel input specification is generated using inputs +only.

      • +
      • Integration with various ecosystem packages like TFMOT, TFLite, +TF.js, etc is only supported for inputs and not for tensors in +positional and keyword arguments.

      • +
      +

    • +
    • *args – Additional positional arguments. May contain tensors, although +this is not recommended, for the reasons above.

    • +
    • **kwargs

      Additional keyword arguments. May contain tensors, although +this is not recommended, for the reasons above. +The following optional keyword arguments are reserved: +- training: Boolean scalar tensor of Python boolean indicating

      +
      +

      whether the call is meant for training or inference.

      +
      +
        +
      • mask: Boolean input mask. If the layer’s call() method takes a +mask argument, its default value will be set to the mask +generated for inputs by the previous layer (if input did come +from a layer that generated a corresponding mask, i.e. if it came +from a Keras layer with masking support).

      • +
      +

    • +
    +
    +
    Returns
    +

    A tensor or list/tuple of tensors.

    +
    +
    +
    +
    +
    +property compute_dtype
    +

    The dtype of the layer’s computations.

    +

    This is equivalent to Layer.dtype_policy.compute_dtype. Unless +mixed precision is used, this is the same as Layer.dtype, the dtype of +the weights.

    +

    Layers automatically cast their inputs to the compute dtype, which +causes computations and the output to be in the compute dtype as well. +This is done by the base Layer class in Layer.__call__, so you do not +have to insert these casts if implementing your own layer.

    +

    Layers often perform certain internal computations in higher precision +when compute_dtype is float16 or bfloat16 for numeric stability. The +output will still typically be float16 or bfloat16 in such cases.

    +
    +
    Returns
    +

    The layer’s compute dtype.

    +
    +
    +
    +
    +
    +compute_mask(inputs, mask=None)
    +

    Computes an output mask tensor.

    +
    +
    Parameters
    +
      +
    • inputs – Tensor or list of tensors.

    • +
    • mask – Tensor or list of tensors.

    • +
    +
    +
    Returns
    +

    +
    None or a tensor (or list of tensors,

    one per output tensor of the layer).

    +
    +
    +

    +
    +
    +
    +
    +
    +compute_output_shape(input_shape)
    +

    Computes the output shape of the layer.

    +

    This method will cause the layer’s state to be built, if that has not +happened before. This requires that the layer will later be used with +inputs that match the input shape provided here.

    +
    +
    Parameters
    +

    input_shape – Shape tuple (tuple of integers) or tf.TensorShape, +or structure of shape tuples / tf.TensorShape instances +(one per output tensor of the layer). +Shape tuples can include None for free dimensions, +instead of an integer.

    +
    +
    Returns
    +

    A tf.TensorShape instance +or structure of tf.TensorShape instances.

    +
    +
    +
    +
    +
    +compute_output_signature(input_signature)
    +

    Compute the output tensor signature of the layer based on the inputs.

    +

    Unlike a TensorShape object, a TensorSpec object contains both shape +and dtype information for a tensor. This method allows layers to provide +output dtype information if it is different from the input dtype. +For any layer that doesn’t implement this function, +the framework will fall back to use compute_output_shape, and will +assume that the output dtype matches the input dtype.

    +
    +
    Parameters
    +

    input_signature – Single TensorSpec or nested structure of TensorSpec +objects, describing a candidate input for the layer.

    +
    +
    Returns
    +

    +
    Single TensorSpec or nested structure of TensorSpec objects,

    describing how the layer would transform the provided input.

    +
    +
    +

    +
    +
    Raises
    +

    TypeError – If input_signature contains a non-TensorSpec object.

    +
    +
    +
    +
    +
    +count_params()
    +

    Count the total number of scalars composing the weights.

    +
    +
    Returns
    +

    An integer count.

    +
    +
    Raises
    +

    ValueError – if the layer isn’t yet built + (in which case its weights aren’t yet defined).

    +
    +
    +
    +
    +
    +property dtype
    +

    The dtype of the layer weights.

    +

    This is equivalent to Layer.dtype_policy.variable_dtype. Unless +mixed precision is used, this is the same as Layer.compute_dtype, the +dtype of the layer’s computations.

    +
    +
    +
    +property dtype_policy
    +

    The dtype policy associated with this layer.

    +

    This is an instance of a tf.keras.mixed_precision.Policy.

    +
    +
    +
    +property dynamic
    +

    Whether the layer is dynamic (eager-only); set in the constructor.

    +
    +
    +
    +finalize_state()
    +

    Finalizes the layers state after updating layer weights.

    +

    This function can be subclassed in a layer and will be called after +updating a layer weights. It can be overridden to finalize any +additional layer state after a weight update.

    +

    This function will be called after weights of a layer have been restored +from a loaded model.

    +
    +
    +
    +classmethod from_config(config)
    +

    Creates a layer from its config.

    +

    This method is the reverse of get_config, +capable of instantiating the same layer from the config +dictionary. It does not handle layer connectivity +(handled by Network), nor weights (handled by set_weights).

    +
    +
    Parameters
    +

    config – A Python dictionary, typically the +output of get_config.

    +
    +
    Returns
    +

    A layer instance.

    +
    +
    +
    +
    +
    +get_build_config()
    +

    Returns a dictionary with the layer’s input shape.

    +

    This method returns a config dict that can be used by +build_from_config(config) to create all states (e.g. Variables and +Lookup tables) needed by the layer.

    +

    By default, the config only contains the input shape that the layer +was built with. If you’re writing a custom layer that creates state in +an unusual way, you should override this method to make sure this state +is already created when Keras attempts to load its value upon model +loading.

    +
    +
    Returns
    +

    A dict containing the input shape associated with the layer.

    +
    +
    +
    +
    +
    +get_input_at(node_index)
    +

    Retrieves the input tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first input node of the layer.

    +
    +
    Returns
    +

    A tensor (or list of tensors if the layer has multiple inputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_input_mask_at(node_index)
    +

    Retrieves the input mask tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A mask tensor +(or list of tensors if the layer has multiple inputs).

    +
    +
    +
    +
    +
    +get_input_shape_at(node_index)
    +

    Retrieves the input shape(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A shape tuple +(or list of shape tuples if the layer has multiple inputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_output_at(node_index)
    +

    Retrieves the output tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first output node of the layer.

    +
    +
    Returns
    +

    A tensor (or list of tensors if the layer has multiple outputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_output_mask_at(node_index)
    +

    Retrieves the output mask tensor(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A mask tensor +(or list of tensors if the layer has multiple outputs).

    +
    +
    +
    +
    +
    +get_output_shape_at(node_index)
    +

    Retrieves the output shape(s) of a layer at a given node.

    +
    +
    Parameters
    +

    node_index – Integer, index of the node +from which to retrieve the attribute. +E.g. node_index=0 will correspond to the +first time the layer was called.

    +
    +
    Returns
    +

    A shape tuple +(or list of shape tuples if the layer has multiple outputs).

    +
    +
    Raises
    +

    RuntimeError – If called in Eager mode.

    +
    +
    +
    +
    +
    +get_weights()
    +

    Returns the current weights of the layer, as NumPy arrays.

    +

    The weights of a layer represent the state of the layer. This function +returns both trainable and non-trainable weight values associated with +this layer as a list of NumPy arrays, which can in turn be used to load +state into similarly parameterized layers.

    +

    For example, a Dense layer returns a list of two values: the kernel +matrix and the bias vector. These can be used to set the weights of +another Dense layer:

    +
    >>> layer_a = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(1.))
    +>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
    +>>> layer_a.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(2.))
    +>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
    +>>> layer_b.get_weights()
    +[array([[2.],
    +       [2.],
    +       [2.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b.set_weights(layer_a.get_weights())
    +>>> layer_b.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +
    +
    +
    +
    Returns
    +

    Weights values as a list of NumPy arrays.

    +
    +
    +
    +
    +
    +property inbound_nodes
    +

    Return Functional API nodes upstream of this layer.

    +
    +
    +
    +property input
    +

    Retrieves the input tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one input, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Input tensor or list of input tensors.

    +
    +
    Raises
    +
      +
    • RuntimeError – If called in Eager mode.

    • +
    • AttributeError – If no inbound nodes are found.

    • +
    +
    +
    +
    +
    +
    +property input_mask
    +

    Retrieves the input mask tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one inbound node, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Input mask tensor (potentially None) or list of input +mask tensors.

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer is connected to

    • +
    • more than one incoming layers.

    • +
    +
    +
    +
    +
    +
    +property input_shape
    +

    Retrieves the input shape(s) of a layer.

    +

    Only applicable if the layer has exactly one input, +i.e. if it is connected to one incoming layer, or if all inputs +have the same shape.

    +
    +
    Returns
    +

    Input shape, as an integer shape tuple +(or list of shape tuples, one tuple per input tensor).

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer has no defined input_shape.

    • +
    • RuntimeError – if called in Eager mode.

    • +
    +
    +
    +
    +
    +
    +property input_spec
    +

    InputSpec instance(s) describing the input format for this layer.

    +

    When you create a layer subclass, you can set self.input_spec to +enable the layer to run input compatibility checks when it is called. +Consider a Conv2D layer: it can only be called on a single input +tensor of rank 4. As such, you can set, in __init__():

    +

    `python +self.input_spec = tf.keras.layers.InputSpec(ndim=4) +`

    +

    Now, if you try to call the layer on an input that isn’t rank 4 +(for instance, an input of shape (2,), it will raise a +nicely-formatted error:

    +

    ` +ValueError: Input 0 of layer conv2d is incompatible with the layer: +expected ndim=4, found ndim=1. Full shape received: [2] +`

    +

    Input checks that can be specified via input_spec include: +- Structure (e.g. a single input, a list of 2 inputs, etc) +- Shape +- Rank (ndim) +- Dtype

    +

    For more information, see tf.keras.layers.InputSpec.

    +
    +
    Returns
    +

    A tf.keras.layers.InputSpec instance, or nested structure thereof.

    +
    +
    +
    +
    +
    +load_own_variables(store)
    +

    Loads the state of the layer.

    +

    You can override this method to take full control of how the state of +the layer is loaded upon calling keras.models.load_model().

    +
    +
    Parameters
    +

    store – Dict from which the state of the model will be loaded.

    +
    +
    +
    +
    +
    +property losses
    +

    List of losses added using the add_loss() API.

    +

    Variable regularization tensors are created when this property is +accessed, so it is eager safe: accessing losses under a +tf.GradientTape will propagate gradients back to the corresponding +variables.

    +

    Examples:

    +
    >>> class MyLayer(tf.keras.layers.Layer):
    +...   def call(self, inputs):
    +...     self.add_loss(tf.abs(tf.reduce_mean(inputs)))
    +...     return inputs
    +>>> l = MyLayer()
    +>>> l(np.ones((10, 1)))
    +>>> l.losses
    +[1.0]
    +
    +
    +
    >>> inputs = tf.keras.Input(shape=(10,))
    +>>> x = tf.keras.layers.Dense(10)(inputs)
    +>>> outputs = tf.keras.layers.Dense(1)(x)
    +>>> model = tf.keras.Model(inputs, outputs)
    +>>> # Activity regularization.
    +>>> len(model.losses)
    +0
    +>>> model.add_loss(tf.abs(tf.reduce_mean(x)))
    +>>> len(model.losses)
    +1
    +
    +
    +
    >>> inputs = tf.keras.Input(shape=(10,))
    +>>> d = tf.keras.layers.Dense(10, kernel_initializer='ones')
    +>>> x = d(inputs)
    +>>> outputs = tf.keras.layers.Dense(1)(x)
    +>>> model = tf.keras.Model(inputs, outputs)
    +>>> # Weight regularization.
    +>>> model.add_loss(lambda: tf.reduce_mean(d.kernel))
    +>>> model.losses
    +[<tf.Tensor: shape=(), dtype=float32, numpy=1.0>]
    +
    +
    +
    +
    Returns
    +

    A list of tensors.

    +
    +
    +
    +
    +
    +merge_state(metrics)
    +

    Merges the state from one or more metrics.

    +

    This method can be used by distributed systems to merge the state +computed by different metric instances. Typically the state will be +stored in the form of the metric’s weights. For example, a +tf.keras.metrics.Mean metric contains a list of two weight values: a +total and a count. If there were two instances of a +tf.keras.metrics.Accuracy that each independently aggregated partial +state for an overall accuracy calculation, these two metric’s states +could be combined as follows:

    +
    >>> m1 = tf.keras.metrics.Accuracy()
    +>>> _ = m1.update_state([[1], [2]], [[0], [2]])
    +
    +
    +
    >>> m2 = tf.keras.metrics.Accuracy()
    +>>> _ = m2.update_state([[3], [4]], [[3], [4]])
    +
    +
    +
    >>> m2.merge_state([m1])
    +>>> m2.result().numpy()
    +0.75
    +
    +
    +
    +
    Parameters
    +

    metrics – an iterable of metrics. The metrics must have compatible +state.

    +
    +
    Raises
    +

    ValueError – If the provided iterable does not contain metrics matching + the metric’s required specifications.

    +
    +
    +
    +
    +
    +property metrics
    +

    List of metrics added using the add_metric() API.

    +

    Example:

    +
    >>> input = tf.keras.layers.Input(shape=(3,))
    +>>> d = tf.keras.layers.Dense(2)
    +>>> output = d(input)
    +>>> d.add_metric(tf.reduce_max(output), name='max')
    +>>> d.add_metric(tf.reduce_min(output), name='min')
    +>>> [m.name for m in d.metrics]
    +['max', 'min']
    +
    +
    +
    +
    Returns
    +

    A list of Metric objects.

    +
    +
    +
    +
    +
    +property name
    +

    Name of the layer (string), set in the constructor.

    +
    +
    +
    +property name_scope
    +

    Returns a tf.name_scope instance for this class.

    +
    +
    +
    +property non_trainable_variables
    +

    Sequence of non-trainable variables owned by this module and its submodules.

    +

    Note: this method uses reflection to find variables on the current instance +and submodules. For performance reasons you may wish to cache the result +of calling this method if you don’t expect the return value to change.

    +
    +
    Returns
    +

    A sequence of variables for the current module (sorted by attribute +name) followed by variables from all submodules recursively (breadth +first).

    +
    +
    +
    +
    +
    +property non_trainable_weights
    +

    List of all non-trainable weights tracked by this layer.

    +

    Non-trainable weights are not updated during training. They are +expected to be updated manually in call().

    +
    +
    Returns
    +

    A list of non-trainable variables.

    +
    +
    +
    +
    +
    +property outbound_nodes
    +

    Return Functional API nodes downstream of this layer.

    +
    +
    +
    +property output
    +

    Retrieves the output tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one output, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Output tensor or list of output tensors.

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer is connected to more than one incoming + layers.

    • +
    • RuntimeError – if called in Eager mode.

    • +
    +
    +
    +
    +
    +
    +property output_mask
    +

    Retrieves the output mask tensor(s) of a layer.

    +

    Only applicable if the layer has exactly one inbound node, +i.e. if it is connected to one incoming layer.

    +
    +
    Returns
    +

    Output mask tensor (potentially None) or list of output +mask tensors.

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer is connected to

    • +
    • more than one incoming layers.

    • +
    +
    +
    +
    +
    +
    +property output_shape
    +

    Retrieves the output shape(s) of a layer.

    +

    Only applicable if the layer has one output, +or if all outputs have the same shape.

    +
    +
    Returns
    +

    Output shape, as an integer shape tuple +(or list of shape tuples, one tuple per output tensor).

    +
    +
    Raises
    +
      +
    • AttributeError – if the layer has no defined output shape.

    • +
    • RuntimeError – if called in Eager mode.

    • +
    +
    +
    +
    +
    +
    +reset_state() None
    +

    Reset state.

    +
    +
    +
    +reset_states()
    +
    +
    +
    +result() tensorflow.python.framework.ops.Tensor
    +

    Return f1 score.

    +
    +
    +
    +save_own_variables(store)
    +

    Saves the state of the layer.

    +

    You can override this method to take full control of how the state of +the layer is saved upon calling model.save().

    +
    +
    Parameters
    +

    store – Dict where the state of the model will be saved.

    +
    +
    +
    +
    +
    +set_weights(weights)
    +

    Sets the weights of the layer, from NumPy arrays.

    +

    The weights of a layer represent the state of the layer. This function +sets the weight values from numpy arrays. The weight values should be +passed in the order they are created by the layer. Note that the layer’s +weights must be instantiated before calling this function, by calling +the layer.

    +

    For example, a Dense layer returns a list of two values: the kernel +matrix and the bias vector. These can be used to set the weights of +another Dense layer:

    +
    >>> layer_a = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(1.))
    +>>> a_out = layer_a(tf.convert_to_tensor([[1., 2., 3.]]))
    +>>> layer_a.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b = tf.keras.layers.Dense(1,
    +...   kernel_initializer=tf.constant_initializer(2.))
    +>>> b_out = layer_b(tf.convert_to_tensor([[10., 20., 30.]]))
    +>>> layer_b.get_weights()
    +[array([[2.],
    +       [2.],
    +       [2.]], dtype=float32), array([0.], dtype=float32)]
    +>>> layer_b.set_weights(layer_a.get_weights())
    +>>> layer_b.get_weights()
    +[array([[1.],
    +       [1.],
    +       [1.]], dtype=float32), array([0.], dtype=float32)]
    +
    +
    +
    +
    Parameters
    +

    weights – a list of NumPy arrays. The number +of arrays and their shape must match +number of the dimensions of the weights +of the layer (i.e. it should match the +output of get_weights).

    +
    +
    Raises
    +

    ValueError – If the provided weights list does not match the + layer’s specifications.

    +
    +
    +
    +
    +
    +property stateful
    +
    +
    +
    +property submodules
    +

    Sequence of all sub-modules.

    +

    Submodules are modules which are properties of this module, or found as +properties of modules which are properties of this module (and so on).

    +
    >>> a = tf.Module()
    +>>> b = tf.Module()
    +>>> c = tf.Module()
    +>>> a.b = b
    +>>> b.c = c
    +>>> list(a.submodules) == [b, c]
    +True
    +>>> list(b.submodules) == [c]
    +True
    +>>> list(c.submodules) == []
    +True
    +
    +
    +
    +
    Returns
    +

    A sequence of all submodules.

    +
    +
    +
    +
    +
    +property supports_masking
    +

    Whether this layer supports computing a mask using compute_mask.

    +
    +
    +
    +property trainable
    +
    +
    +
    +property trainable_variables
    +

    Sequence of trainable variables owned by this module and its submodules.

    +

    Note: this method uses reflection to find variables on the current instance +and submodules. For performance reasons you may wish to cache the result +of calling this method if you don’t expect the return value to change.

    +
    +
    Returns
    +

    A sequence of variables for the current module (sorted by attribute +name) followed by variables from all submodules recursively (breadth +first).

    +
    +
    +
    +
    +
    +property trainable_weights
    +

    List of all trainable weights tracked by this layer.

    +

    Trainable weights are updated via gradient descent during training.

    +
    +
    Returns
    +

    A list of trainable variables.

    +
    +
    +
    +
    +
    +update_state(y_true: tf.Tensor, y_pred: tf.Tensor, sample_weight: tf.Tensor | None = None) None
    +

    Update state.

    +
    +
    +
    +property updates
    +
    +
    +
    +property variable_dtype
    +

    Alias of Layer.dtype, the dtype of the weights.

    +
    +
    +
    +property variables
    +

    Returns the list of all layer variables/weights.

    +

    Alias of self.weights.

    +

    Note: This will not track the weights of nested tf.Modules that are +not themselves Keras layers.

    +
    +
    Returns
    +

    A list of variables.

    +
    +
    +
    +
    +
    +property weights
    +

    Returns the list of all layer variables/weights.

    +
    +
    Returns
    +

    A list of variables.

    +
    +
    +
    +
    +
    +classmethod with_name_scope(method)
    +

    Decorator to automatically enter the module name scope.

    +
    >>> class MyModule(tf.Module):
    +...   @tf.Module.with_name_scope
    +...   def __call__(self, x):
    +...     if not hasattr(self, 'w'):
    +...       self.w = tf.Variable(tf.random.normal([x.shape[1], 3]))
    +...     return tf.matmul(x, self.w)
    +
    +
    +

    Using the above module would produce `tf.Variable`s and `tf.Tensor`s whose +names included the module name:

    +
    >>> mod = MyModule()
    +>>> mod(tf.ones([1, 2]))
    +<tf.Tensor: shape=(1, 3), dtype=float32, numpy=..., dtype=float32)>
    +>>> mod.w
    +<tf.Variable 'my_module/Variable:0' shape=(2, 3) dtype=float32,
    +numpy=..., dtype=float32)>
    +
    +
    +
    +
    Parameters
    +

    method – The method to wrap.

    +
    +
    Returns
    +

    The original method wrapped such that it enters the module’s name scope.

    +
    +
    +
    +
    +
    +get_config() dict
    +

    Get configuration.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.regex_model.html b/docs/0.10.3/html/dataprofiler.labelers.regex_model.html new file mode 100644 index 000000000..1ccd5fd8b --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.regex_model.html @@ -0,0 +1,486 @@ + + + + + + + + + Regex Model - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Regex Model

    +

    Contains class for regex data labeling model.

    +
    +
    +class dataprofiler.labelers.regex_model.RegexModel(label_mapping: dict[str, int], parameters: dict = None)
    +

    Bases: dataprofiler.labelers.base_model.BaseModel

    +

    Class for regex data labeling model.

    +

    Initialize Regex Model.

    +
    +
    Example regex_patterns:
    +
    regex_patterns = {
    +
    “LABEL_1”: [

    “LABEL_1_pattern_1”, +“LABEL_1_pattern_2”, +…

    +
    +
    +

    ], +“LABEL_2”: [

    +
    +

    “LABEL_2_pattern_1”, +“LABEL_2_pattern_2”, +…

    +
    +
    +
    +

    }

    +
    +
    Example encapsulators:
    +
    encapsulators = {

    ‘start’: r’(?<![w.$%-])’, +‘end’: r’(?:(?=(b|[ ]))|(?=[^w%$]([^w]|$))|$)’,

    +
    +
    +

    }

    +
    +
    +
    +
    Parameters
    +
      +
    • label_mapping (dict) – maps labels to their encoded integers

    • +
    • parameters (dict) –

      Contains all the appropriate parameters for the model. +Possible parameters are:

      +
      +

      max_length, max_num_chars, dim_embed

      +
      +

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +reset_weights() None
    +

    Reset weights.

    +
    +
    +
    +predict(data: Union[pandas.core.frame.DataFrame, pandas.core.series.Series, numpy.ndarray], batch_size: Optional[int] = None, show_confidences: bool = False, verbose: bool = True) dict
    +

    Apply the regex patterns (within regex_model) to the input_string.

    +

    Create predictions for all matching patterns. Each pattern has an +associated entity and the predictions of each character within the +string are given a True or False identification for each entity. All +characters not identified by ANY of the regex patterns in the +pattern_dict are considered background characters, and are replaced with +the default_label value.

    +
    +
    Parameters
    +
      +
    • data (iterator) – list of strings to predict upon

    • +
    • batch_size (N/A) – does not impact this model and should be fixed to not +be required.

    • +
    • show_confidences – whether user wants prediction confidences

    • +
    • verbose (bool) – Flag to determine whether to print status or not

    • +
    +
    +
    Returns
    +

    char level predictions and confidences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_disk(dirpath: str) dataprofiler.labelers.regex_model.RegexModel
    +

    Load whole model from disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to load the model from

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +save_to_disk(dirpath: str) None
    +

    Save whole model to disk with weights.

    +
    +
    Parameters
    +

    dirpath (str) – directory path where you want to save the model to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +add_label(label: str, same_as: str | None = None) None
    +

    Add a label to the data labeler.

    +
    +
    Parameters
    +
      +
    • label (str) – new label being added to the data labeler

    • +
    • same_as (str) – label to have the same encoding index as for multi-label +to single encoding index.

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod get_class(class_name: str) type[BaseModel] | None
    +

    Get subclasses.

    +
    +
    +
    +get_parameters(param_list: list[str] | None = None) dict
    +

    Return a dict of parameters from the model given a list.

    +
    +
    Parameters
    +

    param_list (List[str]) – list of parameters to retrieve from the model.

    +
    +
    Returns
    +

    dict of parameters

    +
    +
    +
    +
    +
    +classmethod help() None
    +

    Help describe alterable parameters.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property label_mapping: dict[str, int]
    +

    Return mapping of labels to their encoded values.

    +
    +
    +
    +property labels: list[str]
    +

    Retrieve the label.

    +
    +
    Returns
    +

    list of labels

    +
    +
    +
    +
    +
    +property num_labels: int
    +

    Return max label mapping.

    +
    +
    +
    +requires_zero_mapping: bool = False
    +
    +
    +
    +property reverse_label_mapping: dict[int, str]
    +

    Return reversed order of current labels.

    +

    Useful for when needed to extract Labels via indices.

    +
    +
    +
    +set_label_mapping(label_mapping: list[str] | dict[str, int]) None
    +

    Set the labels for the model.

    +
    +
    Parameters
    +

    label_mapping (Union[list, dict]) – label mapping of the model or list of labels to be +converted into the label mapping

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +set_params(**kwargs: Any) None
    +

    Set the parameters if they exist given kwargs.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.labelers.utils.html b/docs/0.10.3/html/dataprofiler.labelers.utils.html new file mode 100644 index 000000000..5e80492f9 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.labelers.utils.html @@ -0,0 +1,308 @@ + + + + + + + + + Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Utils

    +

    Contains functions for checking for installations/dependencies.

    +
    +
    +dataprofiler.labelers.utils.warn_missing_module(labeler_function: str, module_name: str) None
    +

    Return a warning if a given graph module doesn’t exist.

    +
    +
    Parameters
    +
      +
    • labeler_function (str) – Name of the graphing function

    • +
    • module_name (str) – module name that was missing

    • +
    +
    +
    +
    +
    +
    +dataprofiler.labelers.utils.require_module(names: List[str]) Callable
    +

    Check if a set of modules exists in sys.modules prior to running function.

    +

    If they do not, give a user a warning and do not run the +function.

    +
    +
    Parameters
    +

    names (list[str]) – list of module names to check for in sys.modules

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.base_column_profilers.html b/docs/0.10.3/html/dataprofiler.profilers.base_column_profilers.html new file mode 100644 index 000000000..d71229564 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.base_column_profilers.html @@ -0,0 +1,457 @@ + + + + + + + + + Base Column Profilers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Base Column Profilers

    +

    Contains parent column profiler class.

    +
    +
    +class dataprofiler.profilers.base_column_profilers.BaseColumnProfiler(name: str | None, options: BaseOption | None = None)
    +

    Bases: Generic[dataprofiler.profilers.base_column_profilers.BaseColumnProfilerT]

    +

    Abstract class for profiling a column of data.

    +

    Initialize base class properties for the subclass.

    +
    +
    Parameters
    +

    name (String) – Name of the dataset

    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.base_column_profilers.BaseColumnProfilerT, options: Optional[dict] = None) dict
    +

    Find the differences for columns.

    +
    +
    Parameters
    +

    other_profile (BaseColumnProfiler) – profile to find the difference with

    +
    +
    Returns
    +

    the stat differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +abstract update(df_series: pandas.core.frame.DataFrame) dataprofiler.profilers.base_column_profilers.BaseColumnProfiler
    +

    Update the profile.

    +
    +
    Parameters
    +

    df_series (Pandas Dataframe) – Data to profile.

    +
    +
    +
    +
    +
    +abstract property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +abstract report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data: dict[str, Any], config: dict | None = None) BaseColumnProfilerT
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    BaseColumnProfiler

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfiler(name: str | None)
    +

    Bases: dataprofiler.profilers.base_column_profilers.BaseColumnProfiler[dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfilerT]

    +

    Abstract class for profiling primative data type for col of data.

    +

    Initialize base class properties for the subclass.

    +
    +
    Parameters
    +

    name (String) – Name of the data

    +
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +col_type = None
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.base_column_profilers.BaseColumnProfilerT, options: Optional[dict] = None) dict
    +

    Find the differences for columns.

    +
    +
    Parameters
    +

    other_profile (BaseColumnProfiler) – profile to find the difference with

    +
    +
    Returns
    +

    the stat differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data: dict[str, Any], config: dict | None = None) BaseColumnProfilerT
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    BaseColumnProfiler

    +
    +
    +
    +
    +
    +abstract property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +abstract report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +abstract update(df_series: pandas.core.frame.DataFrame) dataprofiler.profilers.base_column_profilers.BaseColumnProfiler
    +

    Update the profile.

    +
    +
    Parameters
    +

    df_series (Pandas Dataframe) – Data to profile.

    +
    +
    +
    +
    +
    +name: str | None
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.categorical_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.categorical_column_profile.html new file mode 100644 index 000000000..0d49993ab --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.categorical_column_profile.html @@ -0,0 +1,449 @@ + + + + + + + + + Categorical Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Categorical Column Profile

    +

    Contains class for categorical column profiler.

    +
    +
    +class dataprofiler.profilers.categorical_column_profile.CategoricalColumn(name: str | None, options: CategoricalOptions = None)
    +

    Bases: dataprofiler.profilers.base_column_profilers.BaseColumnProfiler[CategoricalColumn]

    +

    Categorical column profile subclass of BaseColumnProfiler.

    +

    Represents a column int the dataset which is a categorical column.

    +

    Initialize column base properties and itself.

    +
    +
    Parameters
    +

    name (String) – Name of data

    +
    +
    +
    +
    +type = 'category'
    +
    +
    +
    +property gini_impurity: float | None
    +

    Return Gini Impurity.

    +

    Gini Impurity is a way to calculate +likelihood of an incorrect classification of a new instance of +a random variable.

    +

    G = Σ(i=1; J): P(i) * (1 - P(i)), where i is the category classes. +We are traversing through categories and calculating with the column

    +
    +
    Returns
    +

    None or Gini Impurity probability

    +
    +
    +
    +
    +
    +property unalikeability: float | None
    +

    Return Unlikeability.

    +

    Unikeability checks for “how often observations differ from one another” +Reference: Perry, M. and Kader, G. Variation as Unalikeability. +Teaching Statistics, Vol. 27, No. 2 (2005), pp. 58-60.

    +

    U = Σ(i=1,n)Σ(j=1,n): (Cij)/(n**2-n) +Cij = 1 if i!=j, 0 if i=j

    +
    +
    Returns
    +

    None or unlikeability probability

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.categorical_column_profile.CategoricalColumn, options: Optional[dict] = None) dict
    +

    Find the differences for CategoricalColumns.

    +
    +
    Parameters
    +

    other_profile (CategoricalColumn) – profile to find the difference with

    +
    +
    Returns
    +

    the CategoricalColumn differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +

    This is a private abstract method.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data: dict, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    CategoricalColumn

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +

    For categorical_count, it will display the top k categories most +frequently occurred in descending order.

    +
    +
    +
    +property categories: list[str]
    +

    Return categories.

    +
    +
    +
    +property categorical_counts: dict[str, int]
    +

    Return counts of each category.

    +
    +
    +
    +property unique_ratio: float
    +

    Return ratio of unique categories to sample_size.

    +
    +
    +
    +property unique_count: int
    +

    Return ratio of unique categories to sample_size.

    +
    +
    +
    +property is_match: bool
    +

    Return true if column is categorical.

    +
    +
    +
    +col_type = None
    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.categorical_column_profile.CategoricalColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – Data to profile.

    +
    +
    Returns
    +

    updated CategoricalColumn

    +
    +
    Return type
    +

    CategoricalColumn

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.column_profile_compilers.html b/docs/0.10.3/html/dataprofiler.profilers.column_profile_compilers.html new file mode 100644 index 000000000..b1ba51149 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.column_profile_compilers.html @@ -0,0 +1,677 @@ + + + + + + + + + Column Profile Compilers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Column Profile Compilers

    +

    For generating a report.

    +
    +
    +class dataprofiler.profilers.column_profile_compilers.BaseCompiler(df_series: Optional[pandas.core.series.Series] = None, options: Optional[dataprofiler.profilers.profiler_options.StructuredOptions] = None, pool: Optional[multiprocessing.pool.Pool] = None)
    +

    Bases: Generic[dataprofiler.profilers.column_profile_compilers.BaseCompilerT]

    +

    Abstract class for generating a report.

    +

    Initialize BaseCompiler object.

    +
    +
    +abstract report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled options should be excluded in report.

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +diff(other: dataprofiler.profilers.column_profile_compilers.BaseCompilerT, options: Optional[dict] = None) dict
    +

    Find the difference between 2 compilers and returns the report.

    +
    +
    Parameters
    +

    other (BaseCompiler) – profile compiler finding the difference with this one.

    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +update_profile(df_series: Series, pool: Pool = None) BaseCompiler | None
    +

    Update the profiles from the data frames.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – a given column, assume df_series in str

    • +
    • pool (multiprocessing.Pool) – pool to utilized for multiprocessing

    • +
    +
    +
    Returns
    +

    Self

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseCompiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Compiler with attributes populated.

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.column_profile_compilers.ColumnPrimitiveTypeProfileCompiler(df_series: Optional[pandas.core.series.Series] = None, options: Optional[dataprofiler.profilers.profiler_options.StructuredOptions] = None, pool: Optional[multiprocessing.pool.Pool] = None)
    +

    Bases: dataprofiler.profilers.column_profile_compilers.BaseCompiler[ColumnPrimitiveTypeProfileCompiler]

    +

    For generating ordered column profile reports.

    +

    Initialize BaseCompiler object.

    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled options should be excluded in report.

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +property selected_data_type: str | None
    +

    Find the selected data_type in a primitive compiler.

    +
    +
    Returns
    +

    name of the selected data type

    +
    +
    Return type
    +

    str

    +
    +
    +
    +
    +
    +diff(other: dataprofiler.profilers.column_profile_compilers.ColumnPrimitiveTypeProfileCompiler, options: Optional[dict] = None) dict
    +

    Find the difference between 2 compilers and returns the report.

    +
    +
    Parameters
    +

    other (ColumnPrimitiveTypeProfileCompiler) – profile compiler finding the difference with this one.

    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseCompiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Compiler with attributes populated.

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +update_profile(df_series: Series, pool: Pool = None) BaseCompiler | None
    +

    Update the profiles from the data frames.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – a given column, assume df_series in str

    • +
    • pool (multiprocessing.Pool) – pool to utilized for multiprocessing

    • +
    +
    +
    Returns
    +

    Self

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.column_profile_compilers.ColumnStatsProfileCompiler(df_series: Optional[pandas.core.series.Series] = None, options: Optional[dataprofiler.profilers.profiler_options.StructuredOptions] = None, pool: Optional[multiprocessing.pool.Pool] = None)
    +

    Bases: dataprofiler.profilers.column_profile_compilers.BaseCompiler[ColumnStatsProfileCompiler]

    +

    For generating OrderColumn and CategoricalColumn reports.

    +

    Initialize BaseCompiler object.

    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled options should be excluded in report.

    +
    +
    +
    +
    +
    +diff(other: dataprofiler.profilers.column_profile_compilers.ColumnStatsProfileCompiler, options: Optional[dict] = None) dict
    +

    Find the difference between 2 compilers and returns the report.

    +
    +
    Parameters
    +

    other (ColumnStatsProfileCompiler) – profile compiler finding the difference with this one.

    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseCompiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Compiler with attributes populated.

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +update_profile(df_series: Series, pool: Pool = None) BaseCompiler | None
    +

    Update the profiles from the data frames.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – a given column, assume df_series in str

    • +
    • pool (multiprocessing.Pool) – pool to utilized for multiprocessing

    • +
    +
    +
    Returns
    +

    Self

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.column_profile_compilers.ColumnDataLabelerCompiler(df_series: Optional[pandas.core.series.Series] = None, options: Optional[dataprofiler.profilers.profiler_options.StructuredOptions] = None, pool: Optional[multiprocessing.pool.Pool] = None)
    +

    Bases: dataprofiler.profilers.column_profile_compilers.BaseCompiler[ColumnDataLabelerCompiler]

    +

    For generating DataLabelerColumn report.

    +

    Initialize BaseCompiler object.

    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled options should be excluded in report.

    +
    +
    +
    +
    +
    +diff(other: dataprofiler.profilers.column_profile_compilers.ColumnDataLabelerCompiler, options: Optional[dict] = None) dict
    +

    Find the difference between 2 compilers and return the report.

    +
    +
    Parameters
    +
      +
    • other (ColumnDataLabelerCompiler) – profile compiler finding the difference with this one.

    • +
    • options (dict) – options to change results of the difference

    • +
    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseCompiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Compiler with attributes populated.

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +update_profile(df_series: Series, pool: Pool = None) BaseCompiler | None
    +

    Update the profiles from the data frames.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – a given column, assume df_series in str

    • +
    • pool (multiprocessing.Pool) – pool to utilized for multiprocessing

    • +
    +
    +
    Returns
    +

    Self

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.column_profile_compilers.UnstructuredCompiler(df_series: Optional[pandas.core.series.Series] = None, options: Optional[dataprofiler.profilers.profiler_options.StructuredOptions] = None, pool: Optional[multiprocessing.pool.Pool] = None)
    +

    Bases: dataprofiler.profilers.column_profile_compilers.BaseCompiler[UnstructuredCompiler]

    +

    For generating TextProfiler and UnstructuredLabelerProfile reports.

    +

    Initialize BaseCompiler object.

    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Report profile attrs of class and potentially pop val from self.profile.

    +
    +
    +
    +diff(other: dataprofiler.profilers.column_profile_compilers.UnstructuredCompiler, options: Optional[dict] = None) dict
    +

    Find the difference between 2 compilers and return the report.

    +
    +
    Parameters
    +
      +
    • other (UnstructuredCompiler) – profile compiler finding the difference with this one.

    • +
    • options (dict) – options to impact the results of the diff

    • +
    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseCompiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Compiler with attributes populated.

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +update_profile(df_series: Series, pool: Pool = None) BaseCompiler | None
    +

    Update the profiles from the data frames.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – a given column, assume df_series in str

    • +
    • pool (multiprocessing.Pool) – pool to utilized for multiprocessing

    • +
    +
    +
    Returns
    +

    Self

    +
    +
    Return type
    +

    BaseCompiler

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.data_labeler_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.data_labeler_column_profile.html new file mode 100644 index 000000000..958e32589 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.data_labeler_column_profile.html @@ -0,0 +1,446 @@ + + + + + + + + + Data Labeler Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data Labeler Column Profile

    +

    Contains class for for profiling data labeler col.

    +
    +
    +class dataprofiler.profilers.data_labeler_column_profile.DataLabelerColumn(name: str | None, options: DataLabelerOptions = None)
    +

    Bases: dataprofiler.profilers.base_column_profilers.BaseColumnProfiler[DataLabelerColumn]

    +

    Sublass of BaseColumnProfiler for profiling data labeler col.

    +

    Initialize Data Label profiling for structured datasets.

    +
    +
    Parameters
    +
      +
    • name (String) – name of column being profiled

    • +
    • options (DataLabelerOptions) – Options for the data labeler column

    • +
    +
    +
    +
    +
    +type = 'data_labeler'
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    +static assert_equal_conditions(data_labeler: dataprofiler.profilers.data_labeler_column_profile.DataLabelerColumn, data_labeler2: dataprofiler.profilers.data_labeler_column_profile.DataLabelerColumn) None
    +

    Ensure data labelers have the same values. Raise error otherwise.

    +
    +
    Parameters
    +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +property reverse_label_mapping: dict
    +

    Return reverse label mapping.

    +
    +
    +
    +property possible_data_labels: list[str]
    +

    Return possible data labels.

    +
    +
    +
    +property rank_distribution: dict[str, int]
    +

    Return rank distribution.

    +
    +
    +
    +property sum_predictions: numpy.ndarray
    +

    Sum predictions.

    +
    +
    +
    +property data_label: str | None
    +

    Return data labels which best fit data it has seen based on DataLabeler used.

    +

    Data labels must be within the minimum probability +differential of the top predicted value. If nothing is more than +minimum top label value, it says it could not determine the data label.

    +
    +
    +
    +property avg_predictions: dict[str, float] | None
    +

    Average all sample predictions for each data label.

    +
    +
    +
    +property label_representation: dict[str, float] | None
    +

    Represent label found within the dataset based on ranked voting.

    +

    When top_k=1, this is simply the distribution of data labels found +within the dataset.

    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) DataLabelerColumn
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    DataLabelerColumn

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +

    Private abstract method.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.data_labeler_column_profile.DataLabelerColumn, options: Optional[dict] = None) dict
    +

    Generate differences between the orders of two DataLabeler columns.

    +
    +
    Returns
    +

    Dict containing the differences between orders in their

    +
    +
    +

    appropriate output formats +:rtype: dict

    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.data_labeler_column_profile.DataLabelerColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    updated DataLabelerColumn

    +
    +
    Return type
    +

    DataLabelerColumn

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.datetime_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.datetime_column_profile.html new file mode 100644 index 000000000..18dd0783f --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.datetime_column_profile.html @@ -0,0 +1,405 @@ + + + + + + + + + Datetime Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Datetime Column Profile

    +

    Contains class for profiling datetime column.

    +
    +
    +class dataprofiler.profilers.datetime_column_profile.DateTimeColumn(name: str | None, options: DateTimeOptions = None)
    +

    Bases: dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfiler[DateTimeColumn]

    +

    Datetime column profile subclass of BaseColumnProfiler.

    +

    Represents a column int the dataset which is a datetime column.

    +

    Initialize it and the column base properties.

    +
    +
    Parameters
    +
      +
    • name (String) – Name of the data

    • +
    • options (DateTimeOptions) – Options for the datetime column

    • +
    +
    +
    +
    +
    +type = 'datetime'
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return report.

    +

    Private abstract method.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    DateTimeColumn

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    +
    +property data_type_ratio: float | None
    +

    Calculate the ratio of samples which match this data type.

    +
    +
    Returns
    +

    ratio of data type

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.datetime_column_profile.DateTimeColumn, options: Optional[dict] = None) dict
    +

    Generate differences between max, min, and formats of two DateTime cols.

    +
    +
    Returns
    +

    Dict containing the differences between max, min, and format in their

    +
    +
    +

    appropriate output formats +:rtype: dict

    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.datetime_column_profile.DateTimeColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    +match_count: int
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.float_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.float_column_profile.html new file mode 100644 index 000000000..4ea362806 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.float_column_profile.html @@ -0,0 +1,546 @@ + + + + + + + + + Float Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Float Column Profile

    +

    Float profile analysis for individual col within structured profiling.

    +
    +
    +class dataprofiler.profilers.float_column_profile.FloatColumn(name: str | None, options: FloatOptions = None)
    +

    Bases: dataprofiler.profilers.numerical_column_stats.NumericStatsMixin[FloatColumn], dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfiler[FloatColumn]

    +

    Float column profile mixin with numerical stats.

    +

    Represents a column in the dataset which is a float column.

    +

    Initialize column base properties and itself.

    +
    +
    Parameters
    +
      +
    • name (String) – Name of the data

    • +
    • options (FloatOptions) – Options for the float column

    • +
    +
    +
    +
    +
    +type: str | None = 'float'
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.float_column_profile.FloatColumn, options: Optional[dict] = None) dict
    +

    Find the differences for FloatColumns.

    +
    +
    Parameters
    +

    other_profile (FloatColumn) – profile to find the difference with

    +
    +
    Returns
    +

    the FloatColumn differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Report profile attribute of class; potentially pop val from self.profile.

    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    FloatColumn

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    Returns
    +

    +
    +
    +
    +
    +
    +property precision: dict[str, float | None]
    +

    Report statistics on the significant figures of each element in the data.

    +
    +
    Returns
    +

    Precision statistics

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property data_type_ratio: float | None
    +

    Calculate the ratio of samples which match this data type.

    +
    +
    Returns
    +

    ratio of data type

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +static is_float(x: str) bool
    +

    Return True if x is float.

    +

    For “0.80” this function returns True +For “1.00” this function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is float or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +static is_int(x: str) bool
    +

    Return True if x is integer.

    +

    For “0.80” This function returns False +For “1.00” This function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is integer or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property kurtosis: float | np.float64
    +

    Return kurtosis value.

    +
    +
    +
    +property mean: float | np.float64
    +

    Return mean value.

    +
    +
    +
    +property median: float
    +

    Estimate the median of the data.

    +
    +
    Returns
    +

    the median

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +property median_abs_deviation: float | np.float64
    +

    Get median absolute deviation estimated from the histogram of the data.

    +
    +

    Subtract bin edges from the median value +Fold the histogram to positive and negative parts around zero +Impose the two bin edges from the two histogram +Calculate the counts for the two histograms with the imposed bin edges +Superimpose the counts from the two histograms +Interpolate the median absolute deviation from the superimposed counts

    +
    +
    +
    Returns
    +

    median absolute deviation

    +
    +
    +
    +
    +
    +property mode: list[float]
    +

    Find an estimate for the mode[s] of the data.

    +
    +
    Returns
    +

    the mode(s) of the data

    +
    +
    Return type
    +

    list(float)

    +
    +
    +
    +
    +
    +static np_type_to_type(val: Any) Any
    +

    Convert numpy variables to base python type variables.

    +
    +
    Parameters
    +

    val (numpy type or base type) – value to check & change

    +
    +
    Return val
    +

    base python type

    +
    +
    Rtype val
    +

    int or float

    +
    +
    +
    +
    +
    +property skewness: float | np.float64
    +

    Return skewness value.

    +
    +
    +
    +property stddev: float | np.float64
    +

    Return stddev value.

    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.float_column_profile.FloatColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    updated FloatColumn

    +
    +
    Return type
    +

    FloatColumn

    +
    +
    +
    +
    +
    +property variance: float | np.float64
    +

    Return variance.

    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    +match_count: int
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.graph_profiler.html b/docs/0.10.3/html/dataprofiler.profilers.graph_profiler.html new file mode 100644 index 000000000..4938eb759 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.graph_profiler.html @@ -0,0 +1,382 @@ + + + + + + + + + Graph Profiler - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Graph Profiler

    +

    Class and functions to calculate and profile properties of graph data.

    +
    +
    +class dataprofiler.profilers.graph_profiler.GraphProfiler(data: nx.Graph | GraphData, options: ProfilerOptions = None)
    +

    Bases: object

    +

    GraphProfiler class.

    +

    Creates a profile describing a graph dataset +Statistical properties of graph

    +

    Initialize Graph Profiler.

    +
    +
    Parameters
    +
    +
    +
    +
    +
    +times: dict[str, float]
    +

    Properties

    +
    +
    +
    +property profile: dict
    +

    Return the profile of the graph.

    +
    +
    Returns
    +

    the profile of the graph in data

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.graph_profiler.GraphProfiler, options: Optional[dict] = None) dict
    +

    Find the differences for two graph profiles.

    +
    +
    Parameters
    +
      +
    • other_profile (GraphProfiler) – profile to find the difference with

    • +
    • options (dict) – options for diff output

    • +
    +
    +
    Returns
    +

    the difference between profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Report on profile attribute of the class.

    +

    Pop value from self.profile if key not in self.__calculations

    +
    +
    +
    +update(graph: networkx.classes.graph.Graph) dataprofiler.profilers.graph_profiler.GraphProfiler
    +

    Update the graph profile.

    +
    +
    Parameters
    +

    data (NetworkX Graph) – networkx graph

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +save(filepath: Optional[str] = None) None
    +

    Save profiler to disk.

    +
    +
    Parameters
    +

    filepath (String) – Path of file to save to

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load(filepath: str) dataprofiler.profilers.graph_profiler.GraphProfiler
    +

    Load profiler from disk.

    +
    +
    Parameters
    +

    filepath (String) – Path of file to load from

    +
    +
    Returns
    +

    GraphProfiler being loaded

    +
    +
    Return type
    +

    GraphProfiler

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.helpers.html b/docs/0.10.3/html/dataprofiler.profilers.helpers.html new file mode 100644 index 000000000..6485d4978 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.helpers.html @@ -0,0 +1,333 @@ + + + + + + + + + Helpers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Helpers

    +
    +

    Modules

    +
    +
    + +

    This package provides helper functions for generating reports.

    +
    +
    +dataprofiler.profilers.helpers.calculate_quantiles(num_quantile_groups: int, quantiles: dict[int, int]) dict[int, int]
    +

    Calculate and return quantiles.

    +
    +
    Parameters
    +
      +
    • num_quantile_groups (int) – number of quantile groups

    • +
    • quantiles (dict[int, int]) – original quantiles

    • +
    +
    +
    Returns
    +

    calculated quantiles

    +
    +
    Return type
    +

    dict[int, int]

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.helpers.report_helpers.html b/docs/0.10.3/html/dataprofiler.profilers.helpers.report_helpers.html new file mode 100644 index 000000000..f28e5fab9 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.helpers.report_helpers.html @@ -0,0 +1,324 @@ + + + + + + + + + Report Helpers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Report Helpers

    +

    Contains helper functions for generating report.

    +
    +
    +dataprofiler.profilers.helpers.report_helpers.calculate_quantiles(num_quantile_groups: int, quantiles: dict[int, int]) dict[int, int]
    +

    Calculate and return quantiles.

    +
    +
    Parameters
    +
      +
    • num_quantile_groups (int) – number of quantile groups

    • +
    • quantiles (dict[int, int]) – original quantiles

    • +
    +
    +
    Returns
    +

    calculated quantiles

    +
    +
    Return type
    +

    dict[int, int]

    +
    +
    +
    +
    +
    +dataprofiler.profilers.helpers.report_helpers.flat_dict(od: dict, separator: str = '_', key: str = '') dict
    +

    Flatten nested dictionary.

    +

    Each level is collapsed and +joined with the specified seperator.

    +
    +
    Parameters
    +
      +
    • od (dict) – dictionary or dictionary-like object

    • +
    • seperator (str) – character(s) joining successive levels

    • +
    • key (str) – concatenated keys

    • +
    +
    +
    Returns
    +

    unnested dictionary

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.histogram_utils.html b/docs/0.10.3/html/dataprofiler.profilers.histogram_utils.html new file mode 100644 index 000000000..605fb527f --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.histogram_utils.html @@ -0,0 +1,287 @@ + + + + + + + + + Histogram Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    + + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.html b/docs/0.10.3/html/dataprofiler.profilers.html new file mode 100644 index 000000000..6b609fc77 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.html @@ -0,0 +1,341 @@ + + + + + + + + + Profilers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    + + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.int_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.int_column_profile.html new file mode 100644 index 000000000..5d85175fd --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.int_column_profile.html @@ -0,0 +1,539 @@ + + + + + + + + + Int Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Int Column Profile

    +

    Int profile analysis for individual col within structured profiling.

    +
    +
    +class dataprofiler.profilers.int_column_profile.IntColumn(name: str | None, options: IntOptions = None)
    +

    Bases: dataprofiler.profilers.numerical_column_stats.NumericStatsMixin[IntColumn], dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfiler[IntColumn]

    +

    Integer column profile mixin with of numerical stats.

    +

    Represents a column in the dataset which is an integer column.

    +

    Initialize column base properties and itself.

    +
    +
    Parameters
    +
      +
    • name (String) – Name of the data

    • +
    • options (IntOptions) – Options for the integer column

    • +
    +
    +
    +
    +
    +type: str | None = 'int'
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return the report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    IntColumn

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    Returns
    +

    +
    +
    +
    +
    +
    +property data_type_ratio: float | None
    +

    Calculate the ratio of samples which match this data type.

    +
    +
    Returns
    +

    ratio of data type

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.int_column_profile.IntColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    updated IntColumn

    +
    +
    Return type
    +

    IntColumn

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.numerical_column_stats.NumericStatsMixinT, options: Optional[dict] = None) dict
    +

    Find the differences for several numerical stats.

    +
    +
    Parameters
    +

    other_profile (NumericStatsMixin Profile) – profile to find the difference with

    +
    +
    Returns
    +

    the numerical stats differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +static is_float(x: str) bool
    +

    Return True if x is float.

    +

    For “0.80” this function returns True +For “1.00” this function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is float or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +static is_int(x: str) bool
    +

    Return True if x is integer.

    +

    For “0.80” This function returns False +For “1.00” This function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is integer or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property kurtosis: float | np.float64
    +

    Return kurtosis value.

    +
    +
    +
    +property mean: float | np.float64
    +

    Return mean value.

    +
    +
    +
    +property median: float
    +

    Estimate the median of the data.

    +
    +
    Returns
    +

    the median

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +property median_abs_deviation: float | np.float64
    +

    Get median absolute deviation estimated from the histogram of the data.

    +
    +

    Subtract bin edges from the median value +Fold the histogram to positive and negative parts around zero +Impose the two bin edges from the two histogram +Calculate the counts for the two histograms with the imposed bin edges +Superimpose the counts from the two histograms +Interpolate the median absolute deviation from the superimposed counts

    +
    +
    +
    Returns
    +

    median absolute deviation

    +
    +
    +
    +
    +
    +property mode: list[float]
    +

    Find an estimate for the mode[s] of the data.

    +
    +
    Returns
    +

    the mode(s) of the data

    +
    +
    Return type
    +

    list(float)

    +
    +
    +
    +
    +
    +static np_type_to_type(val: Any) Any
    +

    Convert numpy variables to base python type variables.

    +
    +
    Parameters
    +

    val (numpy type or base type) – value to check & change

    +
    +
    Return val
    +

    base python type

    +
    +
    Rtype val
    +

    int or float

    +
    +
    +
    +
    +
    +property skewness: float | np.float64
    +

    Return skewness value.

    +
    +
    +
    +property stddev: float | np.float64
    +

    Return stddev value.

    +
    +
    +
    +property variance: float | np.float64
    +

    Return variance.

    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    +match_count: int
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.json_decoder.html b/docs/0.10.3/html/dataprofiler.profilers.json_decoder.html new file mode 100644 index 000000000..3a0d7234c --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.json_decoder.html @@ -0,0 +1,546 @@ + + + + + + + + + JSON Decoder - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    JSON Decoder

    +

    Contains methods to decode components of a Profiler.

    +
    +
    +dataprofiler.profilers.json_decoder.get_column_profiler_class(class_name: str) type[BaseColumnProfiler]
    +

    Use name of class to return default-constructed version of that class.

    +
    +
    Raises ValueError if class_name is not name of a subclass of

    BaseColumnProfiler.

    +
    +
    +
    +
    Parameters
    +

    class_name (str representing name of class) – name of BaseColumnProfiler subclass retrieved by +calling type(instance).__name__

    +
    +
    Returns
    +

    subclass of BaseColumnProfiler object

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.get_compiler_class(class_name: str) type[col_pro_compiler.BaseCompiler]
    +

    Use name of class to return default-constructed version of that class.

    +
    +
    Raises ValueError if class_name is not name of a subclass of

    BaseCompiler.

    +
    +
    +
    +
    Parameters
    +

    class_name (str representing name of class) – name of BaseCompiler subclass retrieved by +calling type(instance).__name__

    +
    +
    Returns
    +

    subclass of BaseCompiler object

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.get_option_class(class_name: str) type[BaseOption]
    +

    Use name of class to return default-constructed version of that class.

    +
    +
    Raises ValueError if class_name is not name of a subclass of

    BaseOptions.

    +
    +
    +
    +
    Parameters
    +

    class_name (str representing name of class) – name of BaseOptions subclass retrieved by +calling type(instance).__name__

    +
    +
    Returns
    +

    subclass of BaseOptions object

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.get_profiler_class(class_name: str) type[BaseProfiler]
    +

    Use name of class to return default-constructed version of that class.

    +
    +
    Raises ValueError if class_name is not name of a subclass of

    BaseProfiler.

    +
    +
    +
    +
    Parameters
    +

    class_name (str representing name of class) – name of BaseProfiler subclass retrieved by +calling type(instance).__name__

    +
    +
    Raises
    +

    ValueError if the profiler class does not exist

    +
    +
    Returns
    +

    subclass of BaseProfiler object

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.get_structured_col_profiler_class(class_name: str) type[StructuredColProfiler]
    +

    Use name of class to return default-constructed version of that class.

    +
    +
    Raises ValueError if class_name is not name of a subclass of

    StructuredColProfiler.

    +
    +
    +
    +
    Parameters
    +

    class_name (str representing name of class) – name of StructuredColProfiler subclass retrieved by +calling type(instance).__name__

    +
    +
    Returns
    +

    subclass of StructuredColProfiler object

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.load_column_profile(serialized_json: dict, config: dict | None = None) BaseColumnProfiler
    +

    Construct subclass of BaseColumnProfiler given a serialized JSON.

    +
    +
    Expected format of serialized_json (see json_encoder):
    +
    {

    “class”: <str name of class that was serialized> +“data”: {

    +
    +

    <attr1>: <value1> +<attr2>: <value2> +…

    +
    +

    }

    +
    +
    +

    }

    +
    +
    +
    +
    Parameters
    +
      +
    • serialized_json (a dict that was created by calling json.loads on +a JSON representation using the custom encoder) – JSON representation of column profiler that was +serialized using the custom encoder in profilers.json_encoder

    • +
    • config (Dict | None) – config for overriding data params when loading from dict

    • +
    +
    +
    Returns
    +

    subclass of BaseColumnProfiler that has been deserialized from +JSON

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.load_compiler(serialized_json: dict, config: dict | None = None) col_pro_compiler.BaseCompiler
    +

    Construct subclass of BaseCompiler given a serialized JSON.

    +
    +
    Expected format of serialized_json (see json_encoder):
    +
    {

    “class”: <str name of class that was serialized> +“data”: {

    +
    +

    <attr1>: <value1> +<attr2>: <value2> +…

    +
    +

    }

    +
    +
    +

    }

    +
    +
    +
    +
    Parameters
    +
      +
    • serialized_json (a dict that was created by calling json.loads on +a JSON representation using the custom encoder) – JSON representation of profile compiler that was +serialized using the custom encoder in profilers.json_encoder

    • +
    • config (Dict | None) – config for overriding data params when loading from dict

    • +
    +
    +
    Returns
    +

    subclass of BaseCompiler that has been deserialized from +JSON

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.load_option(serialized_json: dict, config: dict | None = None) BaseOption
    +

    Construct subclass of BaseOption given a serialized JSON.

    +
    +
    Expected format of serialized_json (see json_encoder):
    +
    {

    “class”: <str name of class that was serialized> +“data”: {

    +
    +

    <attr1>: <value1> +<attr2>: <value2> +…

    +
    +

    }

    +
    +
    +

    }

    +
    +
    +
    +
    Parameters
    +
      +
    • serialized_json (a dict that was created by calling json.loads on +a JSON representation using the custom encoder) – JSON representation of option that was +serialized using the custom encoder in profilers.json_encoder

    • +
    • config (Dict | None) – config for overriding data params when loading from dict

    • +
    +
    +
    Returns
    +

    subclass of BaseOption that has been deserialized from +JSON

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.load_profiler(serialized_json: dict, config=None) BaseProfiler
    +

    Construct subclass of BaseProfiler given a serialized JSON.

    +
    +
    Expected format of serialized_json (see json_encoder):
    +
    {

    “class”: <str name of class that was serialized> +“data”: {

    +
    +

    <attr1>: <value1> +<attr2>: <value2> +…

    +
    +

    }

    +
    +
    +

    }

    +
    +
    +
    +
    Parameters
    +
      +
    • serialized_json (a dict that was created by calling json.loads on +a JSON representation using the custom encoder) – JSON representation of column profiler that was +serialized using the custom encoder in profilers.json_encoder

    • +
    • config (Dict | None) – config for overriding data params when loading from dict

    • +
    +
    +
    Returns
    +

    subclass of BaseProfiler that has been deserialized from +JSON

    +
    +
    +
    +
    +
    +dataprofiler.profilers.json_decoder.load_structured_col_profiler(serialized_json: dict, config: dict | None = None) StructuredColProfiler
    +

    Construct subclass of BaseProfiler given a serialized JSON.

    +
    +
    Expected format of serialized_json (see json_encoder):
    +
    {

    “class”: <str name of class that was serialized> +“data”: {

    +
    +

    <attr1>: <value1> +<attr2>: <value2> +…

    +
    +

    }

    +
    +
    +

    }

    +
    +
    +
    +
    Parameters
    +
      +
    • serialized_json (a dict that was created by calling json.loads on +a JSON representation using the custom encoder) – JSON representation of column profiler that was +serialized using the custom encoder in profilers.json_encoder

    • +
    • config (Dict | None) – config for overriding data params when loading from dict

    • +
    +
    +
    Returns
    +

    subclass of BaseCompiler that has been deserialized from +JSON

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.json_encoder.html b/docs/0.10.3/html/dataprofiler.profilers.json_encoder.html new file mode 100644 index 000000000..220a79372 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.json_encoder.html @@ -0,0 +1,363 @@ + + + + + + + + + JSON Encoder - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    JSON Encoder

    +

    Contains ProfilerEncoder class.

    +
    +
    +class dataprofiler.profilers.json_encoder.ProfileEncoder(*, skipkeys=False, ensure_ascii=True, check_circular=True, allow_nan=True, sort_keys=False, indent=None, separators=None, default=None)
    +

    Bases: json.encoder.JSONEncoder

    +

    JSONify profiler objects and it subclasses and contents.

    +

    Constructor for JSONEncoder, with sensible defaults.

    +

    If skipkeys is false, then it is a TypeError to attempt +encoding of keys that are not str, int, float or None. If +skipkeys is True, such items are simply skipped.

    +

    If ensure_ascii is true, the output is guaranteed to be str +objects with all incoming non-ASCII characters escaped. If +ensure_ascii is false, the output can contain non-ASCII characters.

    +

    If check_circular is true, then lists, dicts, and custom encoded +objects will be checked for circular references during encoding to +prevent an infinite recursion (which would cause an OverflowError). +Otherwise, no such check takes place.

    +

    If allow_nan is true, then NaN, Infinity, and -Infinity will be +encoded as such. This behavior is not JSON specification compliant, +but is consistent with most JavaScript based encoders and decoders. +Otherwise, it will be a ValueError to encode such floats.

    +

    If sort_keys is true, then the output of dictionaries will be +sorted by key; this is useful for regression tests to ensure +that JSON serializations can be compared on a day-to-day basis.

    +

    If indent is a non-negative integer, then JSON array +elements and object members will be pretty-printed with that +indent level. An indent level of 0 will only insert newlines. +None is the most compact representation.

    +

    If specified, separators should be an (item_separator, key_separator) +tuple. The default is (’, ‘, ‘: ‘) if indent is None and +(‘,’, ‘: ‘) otherwise. To get the most compact JSON representation, +you should specify (‘,’, ‘:’) to eliminate whitespace.

    +

    If specified, default is a function that gets called for objects +that can’t otherwise be serialized. It should return a JSON encodable +version of the object or raise a TypeError.

    +
    +
    +default(to_serialize)
    +

    Specify how an object should be serialized.

    +
    +
    Parameters
    +

    to_serialize (a BaseColumnProfile object) – an object to be serialized

    +
    +
    Raises
    +

    NotImplementedError

    +
    +
    Returns
    +

    a datatype serializble by json.JSONEncoder

    +
    +
    +
    +
    +
    +encode(o)
    +

    Return a JSON string representation of a Python data structure.

    +
    >>> from json.encoder import JSONEncoder
    +>>> JSONEncoder().encode({"foo": ["bar", "baz"]})
    +'{"foo": ["bar", "baz"]}'
    +
    +
    +
    +
    +
    +item_separator = ', '
    +
    +
    +
    +iterencode(o, _one_shot=False)
    +

    Encode the given object and yield each string +representation as available.

    +

    For example:

    +
    for chunk in JSONEncoder().iterencode(bigobject):
    +    mysocket.write(chunk)
    +
    +
    +
    +
    +
    +key_separator = ': '
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.numerical_column_stats.html b/docs/0.10.3/html/dataprofiler.profilers.numerical_column_stats.html new file mode 100644 index 000000000..516b3f6f4 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.numerical_column_stats.html @@ -0,0 +1,535 @@ + + + + + + + + + Numerical Column Stats - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Numerical Column Stats

    +

    Build model for dataset by identifying col type along with its respective params.

    +
    +
    +class dataprofiler.profilers.numerical_column_stats.abstractstaticmethod(function: Callable)
    +

    Bases: staticmethod

    +

    For making function an abstract method.

    +

    Initialize abstract static method.

    +
    +
    +
    +class dataprofiler.profilers.numerical_column_stats.NumericStatsMixin(options: Optional[dataprofiler.profilers.profiler_options.NumericalOptions] = None)
    +

    Bases: dataprofiler.profilers.base_column_profilers.BaseColumnProfiler[dataprofiler.profilers.numerical_column_stats.NumericStatsMixinT]

    +

    Abstract numerical column profile subclass of BaseColumnProfiler.

    +

    Represents column in the dataset which is a text column. +Has Subclasses itself.

    +

    Initialize column base properties and itself.

    +
    +
    Parameters
    +

    options (NumericalOptions) – Options for the numerical stats.

    +
    +
    +
    +
    +type: str | None = None
    +
    +
    +
    +profile() dict
    +

    Return profile of the column.

    +
    +
    Returns
    +

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Call the profile and remove the disabled columns from profile’s report.

    +
    +

    “Disabled column” is defined as a column +that is not present in self.__calculations but is present +in the self.profile.

    +
    +
    +
    Variables
    +

    remove_disabled_flag – true/false value to tell the code to remove +values missing in __calculations

    +
    +
    Returns
    +

    Profile object pop’d based on values missing from __calculations

    +
    +
    Return type
    +

    Profile

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.numerical_column_stats.NumericStatsMixinT, options: Optional[dict] = None) dict
    +

    Find the differences for several numerical stats.

    +
    +
    Parameters
    +

    other_profile (NumericStatsMixin Profile) – profile to find the difference with

    +
    +
    Returns
    +

    the numerical stats differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property mean: float | np.float64
    +

    Return mean value.

    +
    +
    +
    +property mode: list[float]
    +

    Find an estimate for the mode[s] of the data.

    +
    +
    Returns
    +

    the mode(s) of the data

    +
    +
    Return type
    +

    list(float)

    +
    +
    +
    +
    +
    +property median: float
    +

    Estimate the median of the data.

    +
    +
    Returns
    +

    the median

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +property variance: float | np.float64
    +

    Return variance.

    +
    +
    +
    +property stddev: float | np.float64
    +

    Return stddev value.

    +
    +
    +
    +property skewness: float | np.float64
    +

    Return skewness value.

    +
    +
    +
    +property kurtosis: float | np.float64
    +

    Return kurtosis value.

    +
    +
    +
    +property median_abs_deviation: float | np.float64
    +

    Get median absolute deviation estimated from the histogram of the data.

    +
    +

    Subtract bin edges from the median value +Fold the histogram to positive and negative parts around zero +Impose the two bin edges from the two histogram +Calculate the counts for the two histograms with the imposed bin edges +Superimpose the counts from the two histograms +Interpolate the median absolute deviation from the superimposed counts

    +
    +
    +
    Returns
    +

    median absolute deviation

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +classmethod load_from_dict(data: dict[str, Any], config: dict | None = None) BaseColumnProfilerT
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    BaseColumnProfiler

    +
    +
    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    +abstract update(df_series: pandas.core.series.Series) dataprofiler.profilers.numerical_column_stats.NumericStatsMixin
    +

    Update the numerical profile properties with an uncleaned dataset.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series with nulls removed

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +static is_float(x: str) bool
    +

    Return True if x is float.

    +

    For “0.80” this function returns True +For “1.00” this function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is float or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +static is_int(x: str) bool
    +

    Return True if x is integer.

    +

    For “0.80” This function returns False +For “1.00” This function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is integer or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +static np_type_to_type(val: Any) Any
    +

    Convert numpy variables to base python type variables.

    +
    +
    Parameters
    +

    val (numpy type or base type) – value to check & change

    +
    +
    Return val
    +

    base python type

    +
    +
    Rtype val
    +

    int or float

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.order_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.order_column_profile.html new file mode 100644 index 000000000..2b7d2e106 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.order_column_profile.html @@ -0,0 +1,401 @@ + + + + + + + + + Order Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Order Column Profile

    +

    Index profile analysis for individual col within structured profiling.

    +
    +
    +class dataprofiler.profilers.order_column_profile.Comparable(*args, **kwargs)
    +

    Bases: Protocol

    +

    Protocol for ensuring comparable types, in this case both floats or strings.

    +
    +
    +
    +class dataprofiler.profilers.order_column_profile.OrderColumn(name: str | None, options: OrderOptions = None)
    +

    Bases: dataprofiler.profilers.base_column_profilers.BaseColumnProfiler[OrderColumn]

    +

    Index column profile subclass of BaseColumnProfiler.

    +

    Represents a column in the dataset which is an index column.

    +

    Initialize column base properties and self.

    +
    +
    Parameters
    +
      +
    • name (String) – Name of the data

    • +
    • options (OrderOptions) – Options for the Order column

    • +
    +
    +
    +
    +
    +type = 'order'
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Private abstract method for returning report.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled +options should be excluded in the report.

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – options for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    CategoricalColumn

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Property for profile. Returns the profile of the column.

    +
    +
    Returns
    +

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.order_column_profile.OrderColumn, options: Optional[dict] = None) dict
    +

    Generate the differences between the orders of two OrderColumns.

    +
    +
    Returns
    +

    Dict containing the differences between orders in their

    +
    +
    +

    appropriate output formats +:rtype: dict

    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.order_column_profile.OrderColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    updated OrderColumn

    +
    +
    Return type
    +

    OrderColumn

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.profile_builder.html b/docs/0.10.3/html/dataprofiler.profilers.profile_builder.html new file mode 100644 index 000000000..5f1672b6f --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.profile_builder.html @@ -0,0 +1,891 @@ + + + + + + + + + Profile Builder - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Profile Builder

    +

    Build model for dataset by identifying col type along with its respective params.

    +
    +
    +class dataprofiler.profilers.profile_builder.StructuredColProfiler(df_series: Optional[pandas.core.series.Series] = None, sample_size: Optional[int] = None, min_sample_size: int = 5000, sampling_ratio: float = 0.2, min_true_samples: int = 0, sample_ids: Optional[numpy.ndarray] = None, pool: Optional[multiprocessing.pool.Pool] = None, column_index: Optional[int] = None, options: Optional[dataprofiler.profilers.profiler_options.StructuredOptions] = None)
    +

    Bases: object

    +

    For profiling structured data columns.

    +

    Instantiate the StructuredColProfiler class for a given column.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – Data to be profiled

    • +
    • sample_size (int) – Number of samples to use in generating profile

    • +
    • min_true_samples (int) – Minimum number of samples required for the +profiler

    • +
    • sample_ids (list(list)) – Randomized list of sample indices

    • +
    • pool (multiprocessing.Pool) – pool utilized for multiprocessing

    • +
    • column_index (int) – index of the given column

    • +
    • options (StructuredOptions Object) – Options for the structured profiler.

    • +
    +
    +
    +
    +
    +update_column_profilers(clean_sampled_df: pandas.core.series.Series, pool: Optional[multiprocessing.pool.Pool] = None) None
    +

    Calculate type statistics and label dataset.

    +
    +
    Parameters
    +
      +
    • clean_sampled_df (Pandas.Series) – sampled series with none types dropped

    • +
    • pool (multiprocessing.pool) – pool utilized for multiprocessing

    • +
    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.profile_builder.StructuredColProfiler, options: Optional[dict] = None) dict
    +

    Find the difference between 2 StructuredCols and return the report.

    +
    +
    Parameters
    +
      +
    • other_profile (StructuredColProfiler) – Structured col finding the difference with this +one.

    • +
    • options (dict) – options to change results of the difference

    • +
    +
    +
    Returns
    +

    difference of the structured column

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) collections.OrderedDict
    +

    Return profile.

    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) StructuredColProfiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading structured column profiler

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    StructuredColProfiler

    +
    +
    +
    +
    +
    +property profile: dict
    +

    Return a report.

    +
    +
    +
    +update_profile(df_series: pandas.core.series.Series, sample_size: Optional[int] = None, min_true_samples: Optional[int] = None, sample_ids: Optional[numpy.ndarray] = None, pool: Optional[multiprocessing.pool.Pool] = None) None
    +

    Update the column profiler.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – Data to be profiled

    • +
    • sample_size (int) – Number of samples to use in generating profile

    • +
    • min_true_samples (int) – Minimum number of samples required for the +profiler

    • +
    • sample_ids (list(list)) – Randomized list of sample indices

    • +
    • pool (multiprocessing.Pool) – pool utilized for multiprocessing

    • +
    +
    +
    +
    +
    +
    +static clean_data_and_get_base_stats(df_series: pd.Series, sample_size: int, null_values: dict[str, re.RegexFlag | int] = None, min_true_samples: int = None, sample_ids: np.ndarray | list[list[int]] | None = None) tuple[pd.Series, dict]
    +

    Identify null characters and return them in a dictionary.

    +

    Remove any nulls in column.

    +
    +
    Parameters
    +
      +
    • df_series (pandas.core.series.Series) – a given column

    • +
    • sample_size (int) – Number of samples to use in generating the profile

    • +
    • null_values (Dict[str, Union[re.RegexFlag, int]]) – Dictionary mapping null values to regex flag where +the key represents the null value to remove from the data and the +flag represents the regex flag to apply

    • +
    • min_true_samples (int) – Minimum number of samples required for the +profiler

    • +
    • sample_ids (list(list)) – Randomized list of sample indices

    • +
    +
    +
    Returns
    +

    updated column with null removed and dictionary of null +parameters

    +
    +
    Return type
    +

    pd.Series, dict

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profile_builder.BaseProfiler(data: Data | None, samples_per_update: int = None, min_true_samples: int = 0, options: BaseOption = None)
    +

    Bases: object

    +

    Abstract class for profiling data.

    +

    Instantiate the BaseProfiler class.

    +
    +
    Parameters
    +
      +
    • data (Data class object) – Data to be profiled

    • +
    • samples_per_update (int) – Number of samples to use in generating +profile

    • +
    • min_true_samples (int) – Minimum number of samples required for the +profiler

    • +
    • options (ProfilerOptions Object) – Options for the profiler.

    • +
    +
    +
    Returns
    +

    Profiler

    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.profile_builder.BaseProfiler, options: Optional[dict] = None) dict
    +

    Find the difference of two profiles.

    +
    +
    Parameters
    +

    other_profile (BaseProfiler) – profile being added to this one.

    +
    +
    Returns
    +

    diff of the two profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property profile: BaseCompiler | list[StructuredColProfiler]
    +

    Return the stored profiles for the given profiler.

    +
    +
    Returns
    +

    BaseCompiler | list[StructuredColProfiler]

    +
    +
    +
    +
    +
    +report(report_options: Optional[dict] = None) dict
    +

    Return profile report based on all profiled data fed into the profiler.

    +
    +
    User can specify the output_formats: (pretty, compact, serializable, flat).
    +
    Pretty: floats are rounded to four decimal places, and lists are

    shortened.

    +
    +
    Compact: Similar to pretty, but removes detailed statistics such as

    runtimes, label probabilities, index locations of null types, +etc.

    +
    +
    +

    Serializable: Output is json serializable and not prettified +Flat: Nested output is returned as a flattened dictionary

    +
    +
    +
    +
    Variables
    +

    report_options – optional format changes to the report +dict(output_format=<FORMAT>)

    +
    +
    Returns
    +

    dictionary report

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseProfilerT
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for overriding data params when loading from dict

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    BaseProfiler

    +
    +
    +
    +
    +
    +update_profile(data: data_readers.base_data.BaseData | pd.DataFrame | pd.Series, sample_size: int = None, min_true_samples: int = None) None
    +

    Update the profile for data provided.

    +

    User can specify the sample size to profile the data with. +Additionally, the user can specify the +minimum number of non-null samples to profile.

    +
    +
    Parameters
    +
      +
    • data (Union[data_readers.base_data.BaseData, pandas.DataFrame, +pandas.Series]) – data to be profiled

    • +
    • sample_size (int) – number of samples to profile from the data

    • +
    • min_true_samples (int) – minimum number of non-null samples to profile

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +save(filepath: Optional[str] = None, save_method: str = 'pickle') None
    +

    Save profiler to disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to save to

    • +
    • save_method (String) – The desired saving method (must be “pickle” or “json”)

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load(filepath: str, load_method: str | None = None) BaseProfiler
    +

    Load profiler from disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to load from

    • +
    • load_method (Optional[String]) – The desired loading method, default = None

    • +
    +
    +
    Returns
    +

    Profiler being loaded, StructuredProfiler or +UnstructuredProfiler

    +
    +
    Return type
    +

    BaseProfiler

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profile_builder.UnstructuredProfiler(data: dataprofiler.data_readers.data.Data, samples_per_update: Optional[int] = None, min_true_samples: int = 0, options: Optional[dataprofiler.profilers.profiler_options.BaseOption] = None)
    +

    Bases: dataprofiler.profilers.profile_builder.BaseProfiler

    +

    For profiling unstructured data.

    +

    Instantiate the UnstructuredProfiler class.

    +
    +
    Parameters
    +
      +
    • data (Data class object) – Data to be profiled

    • +
    • samples_per_update (int) – Number of samples to use in generating +profile

    • +
    • min_true_samples (int) – Minimum number of samples required for the +profiler

    • +
    • options (ProfilerOptions Object) – Options for the profiler.

    • +
    +
    +
    Returns
    +

    UnstructuredProfiler

    +
    +
    +
    +
    +diff(other_profile: UnstructuredProfiler, options: dict | None = None) dict
    +

    Find difference between 2 unstuctured profiles and return the report.

    +
    +
    Parameters
    +
      +
    • other_profile (UnstructuredProfiler) – profile finding the difference with this one.

    • +
    • options (dict) – options to impact the results of the diff

    • +
    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property profile: dataprofiler.profilers.column_profile_compilers.BaseCompiler
    +

    Return the stored profiles for the given profiler.

    +
    +
    Returns
    +

    BaseCompiler

    +
    +
    +
    +
    +
    +report(report_options: Optional[dict] = None) dict
    +

    Return unstructured report based on all profiled data fed into profiler.

    +
    +
    User can specify the output_formats: (pretty, compact, serializable, flat).
    +
    Pretty: floats are rounded to four decimal places, and lists are

    shortened.

    +
    +
    Compact: Similar to pretty, but removes detailed statistics such as

    runtimes, label probabilities, index locations of null types, +etc.

    +
    +
    +

    Serializable: Output is json serializable and not prettified +Flat: Nested output is returned as a flattened dictionary

    +
    +
    +
    +
    Variables
    +

    report_options – optional format changes to the report +dict(output_format=<FORMAT>)

    +
    +
    Returns
    +

    dictionary report

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading profiler params from dictionary

    • +
    +
    +
    Raises
    +

    NotImplementedError

    +
    +
    +
    +
    +
    +save(filepath: Optional[str] = None, save_method: str = 'pickle') None
    +

    Save profiler to disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to save to

    • +
    • save_method (String) – The desired saving method (“pickle” | “json”)

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load(filepath: str, load_method: str | None = None) BaseProfiler
    +

    Load profiler from disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to load from

    • +
    • load_method (Optional[String]) – The desired loading method, default = None

    • +
    +
    +
    Returns
    +

    Profiler being loaded, StructuredProfiler or +UnstructuredProfiler

    +
    +
    Return type
    +

    BaseProfiler

    +
    +
    +
    +
    +
    +update_profile(data: data_readers.base_data.BaseData | pd.DataFrame | pd.Series, sample_size: int = None, min_true_samples: int = None) None
    +

    Update the profile for data provided.

    +

    User can specify the sample size to profile the data with. +Additionally, the user can specify the +minimum number of non-null samples to profile.

    +
    +
    Parameters
    +
      +
    • data (Union[data_readers.base_data.BaseData, pandas.DataFrame, +pandas.Series]) – data to be profiled

    • +
    • sample_size (int) – number of samples to profile from the data

    • +
    • min_true_samples (int) – minimum number of non-null samples to profile

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profile_builder.StructuredProfiler(data: dataprofiler.data_readers.data.Data, samples_per_update: Optional[int] = None, min_true_samples: int = 0, options: Optional[dataprofiler.profilers.profiler_options.BaseOption] = None)
    +

    Bases: dataprofiler.profilers.profile_builder.BaseProfiler

    +

    For profiling structured data.

    +

    Instantiate the StructuredProfiler class.

    +
    +
    Parameters
    +
      +
    • data (Data class object) – Data to be profiled

    • +
    • samples_per_update (int) – Number of samples to use in generating +profile

    • +
    • min_true_samples (int) – Minimum number of samples required for the +profiler

    • +
    • options (ProfilerOptions Object) – Options for the profiler.

    • +
    +
    +
    Returns
    +

    StructuredProfiler

    +
    +
    +
    +
    +diff(other_profile: StructuredProfiler, options: dict | None = None) dict
    +

    Find the difference between 2 Profiles and return the report.

    +
    +
    Parameters
    +
      +
    • other_profile (StructuredProfiler) – profile finding the difference with this one

    • +
    • options (dict) – options to change results of the difference

    • +
    +
    +
    Returns
    +

    difference of the profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property profile: list[StructuredColProfiler]
    +

    Return the stored profiles for the given profiler.

    +
    +
    Returns
    +

    list[StructuredColProfiler]

    +
    +
    +
    +
    +
    +report(report_options: Optional[dict] = None) dict
    +

    Return a report.

    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) StructuredProfiler
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    StructuredProfiler

    +
    +
    +
    +
    +
    +save(filepath: Optional[str] = None, save_method: str = 'pickle') None
    +

    Save profiler to disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to save to

    • +
    • save_method (String) – The desired saving method (must be “pickle” or “json”)

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +classmethod load(filepath: str, load_method: str | None = None) BaseProfiler
    +

    Load profiler from disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to load from

    • +
    • load_method (Optional[String]) – The desired loading method, default = None

    • +
    +
    +
    Returns
    +

    Profiler being loaded, StructuredProfiler or +UnstructuredProfiler

    +
    +
    Return type
    +

    BaseProfiler

    +
    +
    +
    +
    +
    +update_profile(data: data_readers.base_data.BaseData | pd.DataFrame | pd.Series, sample_size: int = None, min_true_samples: int = None) None
    +

    Update the profile for data provided.

    +

    User can specify the sample size to profile the data with. +Additionally, the user can specify the +minimum number of non-null samples to profile.

    +
    +
    Parameters
    +
      +
    • data (Union[data_readers.base_data.BaseData, pandas.DataFrame, +pandas.Series]) – data to be profiled

    • +
    • sample_size (int) – number of samples to profile from the data

    • +
    • min_true_samples (int) – minimum number of non-null samples to profile

    • +
    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profile_builder.Profiler(data: Data, samples_per_update: int = None, min_true_samples: int = 0, options: ProfilerOptions = None, profiler_type: str = None)
    +

    Bases: object

    +

    For profiling data.

    +

    Instantiate Structured and Unstructured Profilers.

    +

    This is a factory class.

    +
    +
    Parameters
    +
      +
    • data (Data class object) – Data to be profiled, type allowed depends on the +profiler_type

    • +
    • samples_per_update (int) – Number of samples to use to generate profile

    • +
    • min_true_samples (int) – Min number of samples required for the profiler

    • +
    • options (ProfilerOptions Object) – Options for the profiler.

    • +
    • profiler_type (str) – Type of Profiler (“graph”/”structured”/”unstructured”)

    • +
    +
    +
    Returns
    +

    Union[GraphProfiler, StructuredProfiler, UnstructuredProfiler]

    +
    +
    +
    +
    +classmethod load(filepath: str, load_method: str | None = None) BaseProfiler
    +

    Load profiler from disk.

    +
    +
    Parameters
    +
      +
    • filepath (String) – Path of file to load from

    • +
    • load_method (Optional[String]) – The desired loading method, default = “None”

    • +
    +
    +
    Returns
    +

    Profiler being loaded, StructuredProfiler or +UnstructuredProfiler

    +
    +
    Return type
    +

    BaseProfiler

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.profiler_options.html b/docs/0.10.3/html/dataprofiler.profilers.profiler_options.html new file mode 100644 index 000000000..e0c93d723 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.profiler_options.html @@ -0,0 +1,2395 @@ + + + + + + + + + Profiler Options - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Profiler Options

    +

    Specify the options when running the data profiler.

    +
    +
    +class dataprofiler.profilers.profiler_options.BaseOption(*args, **kwds)
    +

    Bases: Generic[dataprofiler.profilers.profiler_options.BaseOptionT]

    +

    For configuring options.

    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.BooleanOption(is_enabled: bool = True)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseOption[dataprofiler.profilers.profiler_options.BooleanOptionT]

    +

    For setting Boolean options.

    +

    Initialize Boolean option.

    +
    +
    Variables
    +

    is_enabled (bool) – boolean option to enable/disable the option.

    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.HistogramAndQuantilesOption(is_enabled: bool = True, bin_count_or_method: str | int | list[str] = 'auto', num_quantiles: int = 1000)
    +

    Bases: dataprofiler.profilers.profiler_options.BooleanOption[HistogramAndQuantilesOption]

    +

    For setting histogram options.

    +

    Initialize Options for histograms.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the option.

    • +
    • bin_count_or_method (Union[str, int, list(str)]) – bin count or the method with which to +calculate histograms

    • +
    • num_quantiles (int) – number of quantiles

    • +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.ModeOption(is_enabled: bool = True, max_k_modes: int = 5)
    +

    Bases: dataprofiler.profilers.profiler_options.BooleanOption[ModeOption]

    +

    For setting mode estimation options.

    +

    Initialize Options for mode estimation.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the option.

    • +
    • max_k_modes (int) – the max number of modes to return, if applicable

    • +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.BaseInspectorOptions(is_enabled: bool = True)
    +

    Bases: dataprofiler.profilers.profiler_options.BooleanOption[dataprofiler.profilers.profiler_options.BaseInspectorOptionsT]

    +

    For setting Base options.

    +

    Initialize Base options for all the columns.

    +
    +
    Variables
    +

    is_enabled (bool) – boolean option to enable/disable the column.

    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.NumericalOptions
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[dataprofiler.profilers.profiler_options.NumericalOptionsT]

    +

    For configuring options for Numerican Stats Mixin.

    +

    Initialize Options for the Numerical Stats Mixin.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • min (BooleanOption) – boolean option to enable/disable min

    • +
    • max (BooleanOption) – boolean option to enable/disable max

    • +
    • mode (ModeOption) – option to enable/disable mode and set return count

    • +
    • median (BooleanOption) – option to enable/disable median

    • +
    • sum (BooleanOption) – boolean option to enable/disable sum

    • +
    • variance (BooleanOption) – boolean option to enable/disable variance

    • +
    • skewness (BooleanOption) – boolean option to enable/disable skewness

    • +
    • kurtosis (BooleanOption) – boolean option to enable/disable kurtosis

    • +
    • histogram_and_quantiles (BooleanOption) – boolean option to enable/disable +histogram_and_quantiles

    • +
    +
    +
    +

    :ivar bias_correction : boolean option to enable/disable existence of bias +:vartype bias_correction: BooleanOption +:ivar num_zeros: boolean option to enable/disable num_zeros +:vartype num_zeros: BooleanOption +:ivar num_negatives: boolean option to enable/disable num_negatives +:vartype num_negatives: BooleanOption +:ivar is_numeric_stats_enabled: boolean to enable/disable all numeric

    +
    +

    stats

    +
    +
    +
    +
    +
    +property is_numeric_stats_enabled: bool
    +

    Return the state of numeric stats being enabled / disabled.

    +

    If any numeric stats property is enabled it will return True, +otherwise it will return False.

    +
    +
    Returns
    +

    true if any numeric stats property is enabled, otherwise false

    +
    +
    Rtype bool
    +

    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Include is_enabled.

    +

    is_enabled: Turns on or off the column.

    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.IntOptions
    +

    Bases: dataprofiler.profilers.profiler_options.NumericalOptions[IntOptions]

    +

    For configuring options for Int Column.

    +

    Initialize Options for the Int Column.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • min (BooleanOption) – boolean option to enable/disable min

    • +
    • max (BooleanOption) – boolean option to enable/disable max

    • +
    • mode (ModeOption) – option to enable/disable mode and set return count

    • +
    • median (BooleanOption) – option to enable/disable median

    • +
    • sum (BooleanOption) – boolean option to enable/disable sum

    • +
    • variance (BooleanOption) – boolean option to enable/disable variance

    • +
    • skewness (BooleanOption) – boolean option to enable/disable skewness

    • +
    • kurtosis (BooleanOption) – boolean option to enable/disable kurtosis

    • +
    • histogram_and_quantiles (BooleanOption) – boolean option to enable/disable +histogram_and_quantiles

    • +
    +
    +
    +

    :ivar bias_correction : boolean option to enable/disable existence of bias +:vartype bias_correction: BooleanOption +:ivar num_zeros: boolean option to enable/disable num_zeros +:vartype num_zeros: BooleanOption +:ivar num_negatives: boolean option to enable/disable num_negatives +:vartype num_negatives: BooleanOption +:ivar is_numeric_stats_enabled: boolean to enable/disable all numeric

    +
    +

    stats

    +
    +
    +
    +
    +
    +property is_numeric_stats_enabled: bool
    +

    Return the state of numeric stats being enabled / disabled.

    +

    If any numeric stats property is enabled it will return True, +otherwise it will return False.

    +
    +
    Returns
    +

    true if any numeric stats property is enabled, otherwise false

    +
    +
    Rtype bool
    +

    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Include is_enabled.

    +

    is_enabled: Turns on or off the column.

    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.PrecisionOptions(is_enabled: bool = True, sample_ratio: Optional[float] = None)
    +

    Bases: dataprofiler.profilers.profiler_options.BooleanOption[PrecisionOptions]

    +

    For configuring options for precision.

    +

    Initialize Options for precision.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • sample_ratio (float) – float option to determine ratio of valid +float samples in determining percision. +This ratio will override any defaults.

    • +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.FloatOptions
    +

    Bases: dataprofiler.profilers.profiler_options.NumericalOptions[FloatOptions]

    +

    For configuring options for Float Column.

    +

    Initialize Options for the Float Column.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • min (BooleanOption) – boolean option to enable/disable min

    • +
    • max (BooleanOption) – boolean option to enable/disable max

    • +
    • mode (ModeOption) – option to enable/disable mode and set return count

    • +
    • median (BooleanOption) – option to enable/disable median

    • +
    • sum (BooleanOption) – boolean option to enable/disable sum

    • +
    • variance (BooleanOption) – boolean option to enable/disable variance

    • +
    • skewness (BooleanOption) – boolean option to enable/disable skewness

    • +
    • kurtosis (BooleanOption) – boolean option to enable/disable kurtosis

    • +
    • histogram_and_quantiles (BooleanOption) – boolean option to enable/disable +histogram_and_quantiles

    • +
    +
    +
    +

    :ivar bias_correction : boolean option to enable/disable existence of bias +:vartype bias_correction: BooleanOption +:ivar num_zeros: boolean option to enable/disable num_zeros +:vartype num_zeros: BooleanOption +:ivar num_negatives: boolean option to enable/disable num_negatives +:vartype num_negatives: BooleanOption +:ivar is_numeric_stats_enabled: boolean to enable/disable all numeric

    +
    +

    stats

    +
    +
    +
    +
    +
    +property is_numeric_stats_enabled: bool
    +

    Return the state of numeric stats being enabled / disabled.

    +

    If any numeric stats property is enabled it will return True, +otherwise it will return False.

    +
    +
    Returns
    +

    true if any numeric stats property is enabled, otherwise false

    +
    +
    Rtype bool
    +

    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Include is_enabled.

    +

    is_enabled: Turns on or off the column.

    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.TextOptions
    +

    Bases: dataprofiler.profilers.profiler_options.NumericalOptions[TextOptions]

    +

    For configuring options for Text Column.

    +

    Initialize Options for the Text Column.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • vocab (BooleanOption) – boolean option to enable/disable vocab

    • +
    • min (BooleanOption) – boolean option to enable/disable min

    • +
    • max (BooleanOption) – boolean option to enable/disable max

    • +
    • mode (ModeOption) – option to enable/disable mode and set return count

    • +
    • median (BooleanOption) – option to enable/disable median

    • +
    • sum (BooleanOption) – boolean option to enable/disable sum

    • +
    • variance (BooleanOption) – boolean option to enable/disable variance

    • +
    • skewness (BooleanOption) – boolean option to enable/disable skewness

    • +
    • kurtosis (BooleanOption) – boolean option to enable/disable kurtosis

    • +
    +
    +
    +

    :ivar bias_correction : boolean option to enable/disable existence of bias +:vartype bias_correction: BooleanOption +:ivar histogram_and_quantiles: boolean option to enable/disable

    +
    +

    histogram_and_quantiles

    +
    +
    +
    Variables
    +
      +
    • num_zeros (BooleanOption) – boolean option to enable/disable num_zeros

    • +
    • num_negatives (BooleanOption) – boolean option to enable/disable num_negatives

    • +
    • is_numeric_stats_enabled (bool) – boolean to enable/disable all numeric +stats

    • +
    +
    +
    +
    +
    +property is_numeric_stats_enabled: bool
    +

    Return the state of numeric stats being enabled / disabled.

    +

    If any numeric stats property is enabled it will return True, otherwise +it will return False. Although it seems redundant, this method is needed +in order for the function below, the setter function +also called is_numeric_stats_enabled, to properly work.

    +
    +
    Returns
    +

    true if any numeric stats property is enabled, otherwise false

    +
    +
    Rtype bool
    +

    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Include is_enabled.

    +

    is_enabled: Turns on or off the column.

    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.DateTimeOptions
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[DateTimeOptions]

    +

    For configuring options for Datetime Column.

    +

    Initialize Options for the Datetime Column.

    +
    +
    Variables
    +

    is_enabled (bool) – boolean option to enable/disable the column.

    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.OrderOptions
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[OrderOptions]

    +

    For configuring options for Order Column.

    +

    Initialize options for the Order Column.

    +
    +
    Variables
    +

    is_enabled (bool) – boolean option to enable/disable the column.

    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.CategoricalOptions(is_enabled: bool = True, top_k_categories: int | None = None, max_sample_size_to_check_stop_condition: int | None = None, stop_condition_unique_value_ratio: float | None = None, cms: bool = False, cms_confidence: float | None = 0.95, cms_relative_error: float | None = 0.01, cms_max_num_heavy_hitters: int | None = 5000)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[CategoricalOptions]

    +

    For configuring options Categorical Column.

    +

    Initialize options for the Categorical Column.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • top_k_categories ([None, int]) – number of categories to be displayed when called

    • +
    • max_sample_size_to_check_stop_condition ([None, int]) – The maximum sample size +before categorical stop conditions are checked

    • +
    • stop_condition_unique_value_ratio ([None, float]) – The highest ratio of unique +values to dataset size that is to be considered a categorical type

    • +
    • cms (bool) – boolean option for using count min sketch

    • +
    • cms_confidence ([None, float]) – defines the number of hashes used in CMS. +eg. confidence = 1 - failure probability, default 0.95

    • +
    • cms_relative_error ([None, float]) – defines the number of buckets used in CMS, +default 0.01

    • +
    • cms_max_num_heavy_hitters – value used to define

    • +
    +
    +
    +

    the threshold for minimum frequency required by a category to be counted +:vartype cms_max_num_heavy_hitters: [None, int]

    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.CorrelationOptions(is_enabled: bool = False, columns: list[str] = None)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[CorrelationOptions]

    +

    For configuring options for Correlation between Columns.

    +

    Initialize options for the Correlation between Columns.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable.

    • +
    • columns (list()) – Columns considered to calculate correlation

    • +
    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.HyperLogLogOptions(seed: int = 0, register_count: int = 15)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseOption[HyperLogLogOptions]

    +

    Options for alternative method of gathering unique row count.

    +

    Initialize options for the hyperloglog method of gathering unique row count.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable.

    • +
    • seed (int) – seed used to set HLL hashing function

    • +
    • register_count (int) – number of registers is equal to 2^register_count

    • +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.UniqueCountOptions(is_enabled: bool = True, hashing_method: str = 'full')
    +

    Bases: dataprofiler.profilers.profiler_options.BooleanOption[UniqueCountOptions]

    +

    For configuring options for unique row count.

    +

    Initialize options for unique row counts.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable.

    • +
    • hashing_method (str) – property to specify row hashing method (“full” | “hll”)

    • +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.RowStatisticsOptions(is_enabled: bool = True, unique_count: bool = True, null_count: bool = True)
    +

    Bases: dataprofiler.profilers.profiler_options.BooleanOption[RowStatisticsOptions]

    +

    For configuring options for row statistics.

    +

    Initialize options for row statistics.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable.

    • +
    • unique_count (bool) – boolean option to enable/disable unique_count

    • +
    +
    +
    +

    ivar null_count: boolean option to enable/disable null_count +:vartype null_count: bool

    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.DataLabelerOptions
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[DataLabelerOptions]

    +

    For configuring options for Data Labeler Column.

    +

    Initialize options for the Data Labeler Column.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the column.

    • +
    • data_labeler_dirpath (str) – String to load data labeler

    • +
    • max_sample_size (BaseDataLabeler) – Int to decide sample size

    • +
    • data_labeler_object – DataLabeler object used in profiler

    • +
    +
    +
    +
    +
    +property properties: dict
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) DataLabelerOptions
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    DataLabelerOptions

    +
    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.TextProfilerOptions(is_enabled: bool = True, is_case_sensitive: bool = True, stop_words: set[str] = None, top_k_chars: int = None, top_k_words: int = None)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseInspectorOptions[TextProfilerOptions]

    +

    For configuring options for text profiler.

    +

    Construct the TextProfilerOption object with default values.

    +
    +
    Variables
    +
      +
    • is_enabled (bool) – boolean option to enable/disable the option.

    • +
    • is_case_sensitive (bool) – option set for case sensitivity.

    • +
    • stop_words (Union[None, list(str)]) – option set for stop words.

    • +
    • top_k_chars (Union[None, int]) – option set for number of top common characters.

    • +
    • top_k_words (Union[None, int]) – option set for number of top common words.

    • +
    • words (BooleanOption) – option set for word update.

    • +
    • vocab (BooleanOption) – option set for vocab update.

    • +
    +
    +
    +
    +
    +is_prop_enabled(prop: str) bool
    +

    Check to see if a property is enabled or not and returns boolean.

    +
    +
    Parameters
    +

    prop (String) – The option to check if it is enabled

    +
    +
    Returns
    +

    Whether or not the property is enabled

    +
    +
    Return type
    +

    Boolean

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.StructuredOptions(null_values: dict[str, re.RegexFlag | int] = None, column_null_values: dict[int, dict[str, re.RegexFlag | int]] = None, sampling_ratio: float = 0.2)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseOption[StructuredOptions]

    +

    For configuring options for structured profiler.

    +

    Construct the StructuredOptions object with default values.

    +
    +
    Parameters
    +
      +
    • null_values – null values we input.

    • +
    • column_null_values – column level null values we input.

    • +
    +
    +
    Variables
    +
      +
    • int (IntOptions) – option set for int profiling.

    • +
    • float (FloatOptions) – option set for float profiling.

    • +
    • datetime (DateTimeOptions) – option set for datetime profiling.

    • +
    • text (TextOptions) – option set for text profiling.

    • +
    • order (OrderOptions) – option set for order profiling.

    • +
    • category (CategoricalOptions) – option set for category profiling.

    • +
    • data_labeler (DataLabelerOptions) – option set for data_labeler profiling.

    • +
    • correlation (CorrelationOptions) – option set for correlation profiling.

    • +
    • chi2_homogeneity (BooleanOption()) – option set for chi2_homogeneity matrix

    • +
    • row_statistics (BooleanOption()) – option set for row statistics calculations

    • +
    • null_replication_metrics (BooleanOptions) – option set for metrics +calculation for replicating nan vals

    • +
    • null_values (Union[None, dict]) – option set for defined null values

    • +
    • sampling_ratio (Union[None, float]) – What ratio of the input data to sample. +Float value > 0 and <= 1

    • +
    +
    +
    +
    +
    +property enabled_profiles: list[str]
    +

    Return a list of the enabled profilers for columns.

    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.UnstructuredOptions
    +

    Bases: dataprofiler.profilers.profiler_options.BaseOption[UnstructuredOptions]

    +

    For configuring options for unstructured profiler.

    +

    Construct the UnstructuredOptions object with default values.

    +
    +
    Variables
    +
    +
    +
    +
    +
    +property enabled_profiles: list[str]
    +

    Return a list of the enabled profilers.

    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +set(options: dict[str, bool]) None
    +

    Set all the options.

    +

    Send in a dict that contains all of or a subset of +the appropriate options. Set the values of the options. Will raise error +if the formatting is improper.

    +
    +
    Parameters
    +

    options (dict) – dict containing the options you want to set.

    +
    +
    Returns
    +

    None

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_options.ProfilerOptions(presets: Optional[str] = None)
    +

    Bases: dataprofiler.profilers.profiler_options.BaseOption[ProfilerOptions]

    +

    For configuring options for profiler.

    +

    Initialize the ProfilerOptions object.

    +
    +
    Variables
    +
      +
    • structured_options (StructuredOptions) – option set for structured dataset profiling.

    • +
    • unstructured_options (UnstructuredOptions) – option set for unstructured dataset profiling.

    • +
    • presets (Optional[str]) – A pre-configured mapping of a string name to group of options: +“complete”, “data_types”, “numeric_stats_disabled”, +and “lower_memory_sketching”. Default: None

    • +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None) BaseOption
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config to override loading options params from dictionary

    • +
    +
    +
    Returns
    +

    Options with attributes populated.

    +
    +
    Return type
    +

    BaseOption

    +
    +
    +
    +
    +
    +property properties: dict[str, BooleanOption]
    +

    Return a copy of the option properties.

    +
    +
    Returns
    +

    dictionary of the option’s properties attr: value

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +validate(raise_error: bool = True) list[str] | None
    +

    Validate the options do not conflict and cause errors.

    +

    Raises error/warning if so.

    +
    +
    Parameters
    +

    raise_error (bool) – Flag that raises errors if true. Returns errors if +false.

    +
    +
    Returns
    +

    list of errors (if raise_error is false)

    +
    +
    Return type
    +

    list(str)

    +
    +
    +
    +
    +
    +set(options: dict[str, Any]) None
    +

    Overwrite BaseOption.set.

    +

    We do this because the type (unstructured/structured) may +need to be specified if the same options exist within both +self.structured_options and self.unstructured_options

    +
    +
    Parameters
    +

    options (dict) – Dictionary of options to set

    +
    +
    Return
    +

    None

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.profiler_utils.html b/docs/0.10.3/html/dataprofiler.profilers.profiler_utils.html new file mode 100644 index 000000000..393770d56 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.profiler_utils.html @@ -0,0 +1,824 @@ + + + + + + + + + Profiler Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Profiler Utils

    +

    Contains functions for profilers.

    +
    +
    +dataprofiler.profilers.profiler_utils.recursive_dict_update(d: dict, update_d: dict) dict
    +

    Recursive updates nested dictionaries. Updating d with update_d.

    +
    +
    Parameters
    +
      +
    • d – dict which gets updated with update_d

    • +
    • update_d – dict to update d with

    • +
    +
    +
    Returns
    +

    updated dict

    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_utils.KeyDict
    +

    Bases: collections.defaultdict

    +

    Helper class for sample_in_chunks.

    +

    Allows keys that are missing to become the values for that key. +From: +https://www.drmaciver.com/2018/01/lazy-fisher-yates-shuffling-for-precise-rejection-sampling/

    +
    +
    +clear() None.  Remove all items from D.
    +
    +
    +
    +copy() a shallow copy of D.
    +
    +
    +
    +default_factory
    +

    Factory for default value called by __missing__().

    +
    +
    +
    +fromkeys(value=None, /)
    +

    Create a new dictionary with keys from iterable and values set to value.

    +
    +
    +
    +get(key, default=None, /)
    +

    Return the value for key if key is in the dictionary, else default.

    +
    +
    +
    +items() a set-like object providing a view on D’s items
    +
    +
    +
    +keys() a set-like object providing a view on D’s keys
    +
    +
    +
    +pop(k[, d]) v, remove specified key and return the corresponding value.
    +

    If key is not found, d is returned if given, otherwise KeyError is raised

    +
    +
    +
    +popitem()
    +

    Remove and return a (key, value) pair as a 2-tuple.

    +

    Pairs are returned in LIFO (last-in, first-out) order. +Raises KeyError if the dict is empty.

    +
    +
    +
    +setdefault(key, default=None, /)
    +

    Insert key with a value of default if key is not in the dictionary.

    +

    Return the value for key if key is in the dictionary, else default.

    +
    +
    +
    +update([E, ]**F) None.  Update D from dict/iterable E and F.
    +

    If E is present and has a .keys() method, then does: for k in E: D[k] = E[k] +If E is present and lacks a .keys() method, then does: for k, v in E: D[k] = v +In either case, this is followed by: for k in F: D[k] = F[k]

    +
    +
    +
    +values() an object providing a view on D’s values
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.shuffle_in_chunks(data_length: int, chunk_size: int) Generator[list[int], None, Any]
    +

    Create shuffled indexes in chunks.

    +

    This reduces the cost of having to create all indexes, +but only of that what is needed. +Initial Code idea from: +https://www.drmaciver.com/2018/01/lazy-fisher-yates-shuffling-for-precise-rejection-sampling/

    +
    +
    Parameters
    +
      +
    • data_length – length of data to be shuffled

    • +
    • chunk_size – size of shuffled chunks

    • +
    +
    +
    Returns
    +

    list of shuffled indices of chunk size

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.warn_on_profile(col_profile: str, e: Exception) None
    +

    Return a warning if a given profile errors (tensorflow typically).

    +
    +
    Parameters
    +
      +
    • col_profile (str) – Name of the column profile

    • +
    • e (Exception) – Error message from profiler error

    • +
    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.partition(data: list, chunk_size: int) Generator[list, None, Any]
    +

    Create a generator which returns data in specified chunk size.

    +
    +
    Parameters
    +
      +
    • data (list, dataframe, etc) – list, dataframe, etc

    • +
    • chunk_size (int) – size of partition to return

    • +
    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.auto_multiprocess_toggle(data: pandas.core.frame.DataFrame, num_rows_threshold: int = 750000, num_cols_threshold: int = 20) bool
    +

    Automate multiprocessing toggle depending on dataset sizes.

    +
    +
    Parameters
    +
      +
    • data (pandas.DataFrame) – a dataset

    • +
    • num_rows_threshold (int) – threshold for number of rows to +use multiprocess

    • +
    • num_cols_threshold (int) – threshold for number of columns +to use multiprocess

    • +
    +
    +
    Returns
    +

    recommended option.multiprocess.is_enabled value

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.suggest_pool_size(data_size: int = None, cols: int = None) int | None
    +

    Suggest the pool size based on resources.

    +
    +
    Parameters
    +
      +
    • data_size (int) – size of the dataset

    • +
    • cols (int) – columns of the dataset

    • +
    +
    +
    Return suggested_pool_size
    +

    suggested pool size

    +
    +
    Rtype suggested_pool_size
    +

    int

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.generate_pool(max_pool_size: int = None, data_size: int = None, cols: int = None) tuple[Pool | None, int | None]
    +

    Generate a multiprocessing pool to allocate functions too.

    +
    +
    Parameters
    +
      +
    • max_pool_size (Union[int, None]) – Max number of processes assigned to the pool

    • +
    • data_size (int) – size of the dataset

    • +
    • cols (int) – columns of the dataset

    • +
    +
    +
    Return pool
    +

    Multiprocessing pool to allocate processes to

    +
    +
    Rtype pool
    +

    Multiproessing.Pool

    +
    +
    Return cpu_count
    +

    Number of processes (cpu bound) to utilize

    +
    +
    Rtype cpu_count
    +

    int

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.overlap(x1: int | Any, x2: int | Any, y1: int | Any, y2: int | Any) bool
    +

    Return True iff [x1:x2] overlaps with [y1:y2].

    +
    +
    +
    +dataprofiler.profilers.profiler_utils.add_nested_dictionaries(first_dict: dict, second_dict: dict) dict
    +

    Merge two dictionaries together and add values together.

    +
    +
    Parameters
    +
      +
    • first_dict (dict) – dictionary to be merged

    • +
    • second_dict (dict) – dictionary to be merged

    • +
    +
    +
    Returns
    +

    merged dictionary

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.biased_skew(df_series: pandas.core.series.Series) numpy.float64
    +

    Calculate the biased estimator for skewness of the given data.

    +
    +
    The definition is formalized as g_1 here:

    https://en.wikipedia.org/wiki/Skewness#Sample_skewness

    +
    +
    +
    +
    Parameters
    +

    df_series (pandas Series) – data to get skewness of, assuming floats

    +
    +
    Returns
    +

    biased skewness

    +
    +
    Return type
    +

    np.float64

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.biased_kurt(df_series: pandas.core.series.Series) numpy.float64
    +

    Calculate the biased estimator for kurtosis of the given data.

    +
    +
    The definition is formalized as g_2 here:

    https://en.wikipedia.org/wiki/Kurtosis#A_natural_but_biased_estimator

    +
    +
    +
    +
    Parameters
    +

    df_series (pandas Series) – data to get kurtosis of, assuming floats

    +
    +
    Returns
    +

    biased kurtosis

    +
    +
    Return type
    +

    np.float64

    +
    +
    +
    +
    +
    +class dataprofiler.profilers.profiler_utils.Subtractable(*args, **kwargs)
    +

    Bases: Protocol

    +

    Protocol for annotating subtractable types.

    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_numbers(stat1: int | float | np.float64 | np.int64 | None, stat2: int | float | np.float64 | np.int64 | None) Any
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_numbers(stat1: T | None, stat2: T | None) Any
    +

    Find the difference between two stats.

    +

    If there is no difference, return “unchanged”. +For ints/floats, returns stat1 - stat2.

    +
    +
    Parameters
    +
      +
    • stat1 (Union[int, float, np.float64, np.int64, None]) – the first statistical input

    • +
    • stat2 (Union[int, float, np.float64, np.int64, None]) – the second statistical input

    • +
    +
    +
    Returns
    +

    the difference of the stats

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_strings_and_bools(stat1: str | bool | None, stat2: str | bool | None) list[str | bool | None] | str
    +

    Find the difference between two stats.

    +

    If there is no difference, return “unchanged”. +For strings and bools, return list containing [stat1, stat2].

    +
    +
    Parameters
    +
      +
    • stat1 (Union[str, bool]) – the first statistical input

    • +
    • stat2 (Union[str, bool]) – the second statistical input

    • +
    +
    +
    Returns
    +

    the difference of the stats

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_lists_and_sets(stat1: list | set | None, stat2: list | set | None) list[list | set | None] | str
    +

    Find the difference between two stats.

    +

    If there is no difference, return +“unchanged”. Remove duplicates and returns [unique values of stat1, +shared values, unique values of stat2].

    +
    +
    Parameters
    +
      +
    • stat1 (Union[list, set]) – the first statistical input

    • +
    • stat2 (Union[list, set]) – the second statistical input

    • +
    +
    +
    Returns
    +

    the difference of the stats

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_dates(stat1: datetime.datetime | None, stat2: datetime.datetime | None) list | str | None
    +

    Find the difference between two dates.

    +

    If there is no difference, return +“unchanged”. For dates, return the difference in time.

    +

    Because only days can be stored as negative values internally +for timedelta objects, the output for these negative values is +less readable due to the combination of signs in the default +output. This returns a readable output for timedelta that +accounts for potential negative differences.

    +
    +
    Parameters
    +
      +
    • stat1 (datetime.datetime object) – the first statistical input

    • +
    • stat2 (datetime.datetime object) – the second statistical input

    • +
    +
    +
    Returns
    +

    difference in stats

    +
    +
    Return type
    +

    Union[List, str]

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_dicts(dict1: dict | None, dict2: dict | None) dict | str
    +

    Find the difference between two dicts.

    +

    For each key in each dict, +return “unchanged” if there’s no difference, otherwise return +the difference. Assume that if the two dictionaries share the +same key, their values are the same type.

    +
    +
    Parameters
    +
      +
    • dict1 (dict) – the first dict

    • +
    • dict2 (dict) – the second dict

    • +
    +
    +
    Returns
    +

    Difference in the keys of each dict

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_matrices(matrix1: np.ndarray | None, matrix2: np.ndarray | None) np.ndarray | str | None
    +

    Find the difference between two matrices.

    +
    +
    Parameters
    +
      +
    • matrix1 (list(list(float))) – the first matrix

    • +
    • matrix2 (list(list(float))) – the second matrix

    • +
    +
    +
    Returns
    +

    Difference in the matrix

    +
    +
    Return type
    +

    list(list(float))

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.find_diff_of_dicts_with_diff_keys(dict1: dict | None, dict2: dict | None) list[dict] | str
    +

    Find the difference between two dicts.

    +

    For each key in each dict, +return “unchanged” if there’s no difference, otherwise return +the difference. Assume that if the two dictionaries share the +same key, their values are the same type.

    +
    +
    Parameters
    +
      +
    • dict1 (dict) – the first dict

    • +
    • dict2 (dict) – the second dict

    • +
    +
    +
    Returns
    +

    Difference in the keys of each dict

    +
    +
    Return type
    +

    list

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.get_memory_size(data: list | np.ndarray | DataFrame, unit: str = 'M') float
    +

    Get memory size of the input data.

    +
    +
    Parameters
    +
      +
    • data (Union[list, numpy.array, pandas.DataFrame]) – list or array of data

    • +
    • unit (string) – memory size unit (B, K, M, or G)

    • +
    +
    +
    Returns
    +

    memory size of the input data

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.method_timeit(method: Optional[Callable] = None, name: Optional[str] = None) Callable
    +

    Measure execution time of provided method.

    +

    Record time into times dictionary.

    +
    +
    Parameters
    +
      +
    • method (Callable) – method to time

    • +
    • name (str) – key argument for the times dictionary

    • +
    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.perform_chi_squared_test_for_homogeneity(categories1: dict, sample_size1: int, categories2: dict, sample_size2: int) dict[str, int | float | None]
    +

    Perform a Chi Squared test for homogeneity between two groups.

    +
    +
    Parameters
    +
      +
    • categories1 (dict) – Categories and respective counts of the first group

    • +
    • sample_size1 (int) – Number of samples in first group

    • +
    • categories2 (dict) – Categories and respective counts of the second group

    • +
    • sample_size2 (int) – Number of samples in second group

    • +
    +
    +
    Returns
    +

    Results of the chi squared test

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.chunk(lst: list, size: int) Iterator[tuple]
    +

    Chunk things out.

    +
    +
    Parameters
    +
      +
    • lst (list) – List to chunk

    • +
    • size (int) – Size of each chunk

    • +
    +
    +
    Returns
    +

    Iterator that produces tuples of each chunk

    +
    +
    Return type
    +

    Iterator[Tuple]

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.merge(top_profile: profile_builder.BaseProfiler, other_profile: profile_builder.BaseProfiler = None) profile_builder.BaseProfiler
    +

    Merge two Profiles.

    +
    +
    Parameters
    +
      +
    • top_profile (Profile) – First profile

    • +
    • other_profile (Profile) – Second profile

    • +
    +
    +
    Returns
    +

    Merge of two profile objects

    +
    +
    Return type
    +

    Profile

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.merge_profile_list(list_of_profiles: list[profile_builder.BaseProfiler], pool_count: int = 5) profile_builder.BaseProfiler
    +

    Merge list of profiles into a single profile.

    +
    +
    Parameters
    +
      +
    • list_of_profiles (list) – Categories and respective counts of the second group

    • +
    • pool_count (int) – Number of samples in second group

    • +
    +
    +
    Returns
    +

    Single profile that is the merge of all profiles in the +list_of_profiles list.

    +
    +
    Return type
    +

    Profile

    +
    +
    +
    +
    +
    +dataprofiler.profilers.profiler_utils.reload_labeler_from_options_or_get_new(data_labeler_load_attr: dict, config: dict | None = None) BaseDataLabeler | None
    +

    If required by the load_attr load a data labeler, but reuse from config if possible.

    +
    +
    Parameters
    +
      +
    • data_labeler_load_attr (dict[string, dict]) – dictionary with attributes and values.

    • +
    • config (dict[string, dict]) – config for loading classes to reuse an existing labeler

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    DataLabelerOptions

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.text_column_profile.html b/docs/0.10.3/html/dataprofiler.profilers.text_column_profile.html new file mode 100644 index 000000000..c9dc6cb69 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.text_column_profile.html @@ -0,0 +1,587 @@ + + + + + + + + + Text Column Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Text Column Profile

    +

    Text profile analysis for individual col within structured profiling..

    +
    +
    +class dataprofiler.profilers.text_column_profile.TextColumn(name: str | None, options: TextOptions = None)
    +

    Bases: dataprofiler.profilers.numerical_column_stats.NumericStatsMixin[TextColumn], dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfiler[TextColumn]

    +

    Text column profile subclass of BaseColumnProfiler.

    +

    Represents a column in the dataset which is a text column.

    +

    Initialize column base properties and itself.

    +
    +
    Parameters
    +
      +
    • name (String) – Name of the data

    • +
    • options (TextOptions) – Options for the Text column

    • +
    +
    +
    +
    +
    +type: str | None = 'text'
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Report profile attribute of class; potentially pop val from self.profile.

    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    Returns
    +

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.text_column_profile.TextColumn, options: Optional[dict] = None) dict
    +

    Find the differences for text columns.

    +
    +
    Parameters
    +

    other_profile (TextColumn Profile) – profile to find the difference with

    +
    +
    Returns
    +

    the text columns differences

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property data_type_ratio: float | None
    +

    Calculate the ratio of samples which match this data type.

    +

    NOTE: all values can be considered string so always returns 1 in this +case.

    +
    +
    Returns
    +

    ratio of data type

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +update(df_series: pandas.core.series.Series) dataprofiler.profilers.text_column_profile.TextColumn
    +

    Update the column profile.

    +
    +
    Parameters
    +

    df_series (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    updated TextColumn

    +
    +
    Return type
    +

    TextColumn

    +
    +
    +
    +
    +
    +classmethod load_from_dict(data, config: dict | None = None)
    +

    Parse attribute from json dictionary into self.

    +
    +
    Parameters
    +
      +
    • data (dict[string, Any]) – dictionary with attributes and values.

    • +
    • config (Dict | None) – config for loading column profiler params from dictionary

    • +
    +
    +
    Returns
    +

    Profiler with attributes populated.

    +
    +
    Return type
    +

    TextColumn

    +
    +
    +
    +
    +
    +col_type = None
    +
    +
    +
    +static is_float(x: str) bool
    +

    Return True if x is float.

    +

    For “0.80” this function returns True +For “1.00” this function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is float or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +static is_int(x: str) bool
    +

    Return True if x is integer.

    +

    For “0.80” This function returns False +For “1.00” This function returns True +For “1” this function returns True

    +
    +
    Parameters
    +

    x (str) – string to test

    +
    +
    Returns
    +

    if is integer or not

    +
    +
    Return type
    +

    bool

    +
    +
    +
    +
    +
    +property kurtosis: float | np.float64
    +

    Return kurtosis value.

    +
    +
    +
    +property mean: float | np.float64
    +

    Return mean value.

    +
    +
    +
    +property median: float
    +

    Estimate the median of the data.

    +
    +
    Returns
    +

    the median

    +
    +
    Return type
    +

    float

    +
    +
    +
    +
    +
    +property median_abs_deviation: float | np.float64
    +

    Get median absolute deviation estimated from the histogram of the data.

    +
    +

    Subtract bin edges from the median value +Fold the histogram to positive and negative parts around zero +Impose the two bin edges from the two histogram +Calculate the counts for the two histograms with the imposed bin edges +Superimpose the counts from the two histograms +Interpolate the median absolute deviation from the superimposed counts

    +
    +
    +
    Returns
    +

    median absolute deviation

    +
    +
    +
    +
    +
    +property mode: list[float]
    +

    Find an estimate for the mode[s] of the data.

    +
    +
    Returns
    +

    the mode(s) of the data

    +
    +
    Return type
    +

    list(float)

    +
    +
    +
    +
    +
    +static np_type_to_type(val: Any) Any
    +

    Convert numpy variables to base python type variables.

    +
    +
    Parameters
    +

    val (numpy type or base type) – value to check & change

    +
    +
    Return val
    +

    base python type

    +
    +
    Rtype val
    +

    int or float

    +
    +
    +
    +
    +
    +property skewness: float | np.float64
    +

    Return skewness value.

    +
    +
    +
    +property stddev: float | np.float64
    +

    Return stddev value.

    +
    +
    +
    +property variance: float | np.float64
    +

    Return variance.

    +
    +
    +
    +min: int | float | np.float64 | np.int64 | None
    +
    +
    +
    +max: int | float | np.float64 | np.int64 | None
    +
    +
    +
    +sum: int | float | np.float64 | np.int64
    +
    +
    +
    +max_histogram_bin: int
    +
    +
    +
    +min_histogram_bin: int
    +
    +
    +
    +histogram_bin_method_names: list[str]
    +
    +
    +
    +histogram_selection: str | None
    +
    +
    +
    +user_set_histogram_bin: int | None
    +
    +
    +
    +bias_correction: bool
    +
    +
    +
    +num_zeros: int | np.int64
    +
    +
    +
    +num_negatives: int | np.int64
    +
    +
    +
    +histogram_methods: dict
    +
    +
    +
    +quantiles: list[float] | None
    +
    +
    +
    +match_count: int
    +
    +
    +
    +name: str | None
    +
    +
    +
    +sample_size: int
    +
    +
    +
    +metadata: dict
    +
    +
    +
    +times: dict
    +
    +
    +
    +thread_safe: bool
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.unstructured_labeler_profile.html b/docs/0.10.3/html/dataprofiler.profilers.unstructured_labeler_profile.html new file mode 100644 index 000000000..c2cb73e4f --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.unstructured_labeler_profile.html @@ -0,0 +1,347 @@ + + + + + + + + + Unstructured Labeler Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Unstructured Labeler Profile

    +

    Profile analysis for applying labels within unstructured profiling.

    +
    +
    +class dataprofiler.profilers.unstructured_labeler_profile.UnstructuredLabelerProfile(data_labeler_dirpath: Optional[str] = None, options: Optional[dataprofiler.profilers.profiler_options.DataLabelerOptions] = None)
    +

    Bases: object

    +

    Profiles and labels unstructured data.

    +

    Initialize of Data Label profiling for unstructured datasets.

    +
    +
    Parameters
    +
      +
    • data_labeler_dirpath (String) – Directory path to the data labeler

    • +
    • options (DataLabelerOptions) – Options for the data labeler column

    • +
    +
    +
    +
    +
    +type = 'data_labeler'
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Return profile object.

    +
    +
    Parameters
    +

    remove_disabled_flag (boolean) – flag to determine if disabled options +should be excluded in report.

    +
    +
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.unstructured_labeler_profile.UnstructuredLabelerProfile, options: Optional[dict] = None) dict
    +

    Find the differences for two unstructured labeler profiles.

    +
    +
    Parameters
    +
      +
    • other_profile (UnstructuredLabelerProfile) – profile to find the difference with

    • +
    • options (dict) – options for diff output

    • +
    +
    +
    Returns
    +

    the difference between entity counts/percentages

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +property label_encoding: list[str]
    +

    Return list of labels.

    +
    +
    +
    +update(df_series: pandas.core.series.Series) None
    +

    Update profile.

    +
    +
    +
    +property profile: dict
    +

    Return a profile.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.unstructured_text_profile.html b/docs/0.10.3/html/dataprofiler.profilers.unstructured_text_profile.html new file mode 100644 index 000000000..760291ab3 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.unstructured_text_profile.html @@ -0,0 +1,355 @@ + + + + + + + + + Unstructured Text Profile - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Unstructured Text Profile

    +

    For profiling unstructured text data.

    +
    +
    +class dataprofiler.profilers.unstructured_text_profile.TextProfiler(name: str | None, options: TextProfilerOptions = None)
    +

    Bases: object

    +

    Profiles text data.

    +

    Initialize TextProfiler object.

    +
    +
    Parameters
    +
      +
    • name (String) – Name of the data

    • +
    • options (TextProfilerOptions) – Options for the Text Profiler

    • +
    +
    +
    +
    +
    +type = 'text'
    +
    +
    +
    +diff(other_profile: dataprofiler.profilers.unstructured_text_profile.TextProfiler, options: Optional[dict] = None) dict
    +

    Find the differences for two unstructured text profiles.

    +
    +
    Parameters
    +
      +
    • other_profile (TextProfiler) – profile to find the difference with

    • +
    • options (dict) – options for diff output

    • +
    +
    +
    Returns
    +

    the difference between profiles

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +report(remove_disabled_flag: bool = False) dict
    +

    Report profile attribute of class; potentially pop val from self.profile.

    +
    +
    +
    +property profile: dict
    +

    Return the profile of the column.

    +
    +
    Returns
    +

    profile of the column

    +
    +
    Return type
    +

    dict

    +
    +
    +
    +
    +
    +update(data: pandas.core.series.Series) dataprofiler.profilers.unstructured_text_profile.TextProfiler
    +

    Update the column profile.

    +
    +
    Parameters
    +

    data (pandas.core.series.Series) – df series

    +
    +
    Returns
    +

    updated TextProfiler

    +
    +
    Return type
    +

    TextProfiler

    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.profilers.utils.html b/docs/0.10.3/html/dataprofiler.profilers.utils.html new file mode 100644 index 000000000..c19bcf316 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.profilers.utils.html @@ -0,0 +1,264 @@ + + + + + + + + + Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Utils

    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.reports.graphs.html b/docs/0.10.3/html/dataprofiler.reports.graphs.html new file mode 100644 index 000000000..6c903afbb --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.reports.graphs.html @@ -0,0 +1,265 @@ + + + + + + + + + Graphs - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Graphs

    +

    Contains functions for generating graph data report.

    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.reports.html b/docs/0.10.3/html/dataprofiler.reports.html new file mode 100644 index 000000000..f8a0db514 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.reports.html @@ -0,0 +1,297 @@ + + + + + + + + + Reports - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Reports

    +
    +

    Modules

    +
    +
    +
    + +
    +

    Package for generating reports.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.reports.utils.html b/docs/0.10.3/html/dataprofiler.reports.utils.html new file mode 100644 index 000000000..65ba7f201 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.reports.utils.html @@ -0,0 +1,290 @@ + + + + + + + + + Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Utils

    +

    Contains functions for checking for installations/dependencies.

    +
    +
    +dataprofiler.reports.utils.warn_missing_module(graph_func: str, module_name: str) None
    +

    Return a warning if a given graph module doesn’t exist.

    +
    +
    Parameters
    +
      +
    • graph_func (str) – Name of the graphing function

    • +
    • module_name (str) – module name that was missing

    • +
    +
    +
    +
    +
    +
    +dataprofiler.reports.utils.require_module(names: List[str]) Callable[[dataprofiler.reports.utils.F], dataprofiler.reports.utils.F]
    +

    Check if a set of modules exists in sys.modules prior to running function.

    +

    If they do not, give a user a warning and do not run the +function.

    +
    +
    Parameters
    +

    names (list[str]) – list of module names to check for in sys.modules

    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.rng_utils.html b/docs/0.10.3/html/dataprofiler.rng_utils.html new file mode 100644 index 000000000..6b00c4b1d --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.rng_utils.html @@ -0,0 +1,270 @@ + + + + + + + + + Rng Utils - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Rng Utils

    +

    Create a random number generator using a manual seed DATAPROFILER_SEED.

    +
    +
    +dataprofiler.rng_utils.get_random_number_generator() numpy.random._generator.Generator
    +

    Create a random number generator using a manual seed DATAPROFILER_SEED.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.settings.html b/docs/0.10.3/html/dataprofiler.settings.html new file mode 100644 index 000000000..d01a5f1dc --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.settings.html @@ -0,0 +1,265 @@ + + + + + + + + + Settings - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Settings

    +

    Configure settings for dataprofiler.

    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.validators.base_validators.html b/docs/0.10.3/html/dataprofiler.validators.base_validators.html new file mode 100644 index 000000000..624cba946 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.validators.base_validators.html @@ -0,0 +1,353 @@ + + + + + + + + + Base Validators - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Base Validators

    +

    Build model for dataset by identifying col type along with its respective params.

    +
    +
    +dataprofiler.validators.base_validators.is_in_range(x: str | int | float, config: dict) bool
    +

    Check to see x is in the range of the config.

    +
    +
    Parameters
    +
      +
    • x (int/float) – number

    • +
    • config (dict) – configuration

    • +
    +
    +
    Returns
    +

    bool

    +
    +
    +
    +
    +
    +dataprofiler.validators.base_validators.is_in_list(x: str | int | float, config: dict) bool
    +

    Check to see x is in the config list.

    +
    +
    Parameters
    +
      +
    • x (string) – item

    • +
    • config (dict) – configuration

    • +
    +
    +
    Returns
    +

    bool

    +
    +
    +
    +
    +
    +class dataprofiler.validators.base_validators.Validator
    +

    Bases: object

    +

    For validating a data set.

    +

    Initialize Validator object.

    +
    +
    +validate(data: pd.DataFrame | dd.DataFrame, config: dict) None
    +

    Validate a data set.

    +

    No option for validating a partial data set.

    +

    Set configuration on run not on instantiation of the class such that +you have the option to run multiple times with different configurations +without having to also reinstantiate the class.

    +
    +
    Parameters
    +
      +
    • data (DataFrame Dask/Pandas) – The data to be processed by the validator. Processing +occurs in a column-wise fashion.

    • +
    • config (dict) – configuration for how the validator should +run across the given data. Validator will only run over columns +specified in the configuration.

    • +
    +
    +
    Example
    +

    This is an example of the config:

    +
    config = {
    +        <column_name>: {
    +                range: {
    +                    'start': 1,
    +                    'end':2
    +                },
    +                list: [1,2,3]
    +            }
    +        }
    +
    +
    +
    +
    +
    +
    +
    +get() dict
    +

    Get the results of the validation run.

    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.validators.html b/docs/0.10.3/html/dataprofiler.validators.html new file mode 100644 index 000000000..c62ae8e18 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.validators.html @@ -0,0 +1,314 @@ + + + + + + + + + Validators - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Validators

    +
    +

    Modules

    +
    +
    + +

    Package for identifying cols.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/dataprofiler.version.html b/docs/0.10.3/html/dataprofiler.version.html new file mode 100644 index 000000000..b0b234cc0 --- /dev/null +++ b/docs/0.10.3/html/dataprofiler.version.html @@ -0,0 +1,265 @@ + + + + + + + + + Version - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Version

    +

    File contains the version number for the package.

    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/examples.html b/docs/0.10.3/html/examples.html new file mode 100644 index 000000000..338e039a7 --- /dev/null +++ b/docs/0.10.3/html/examples.html @@ -0,0 +1,426 @@ + + + + + + + + + Examples - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Examples

    +

    These examples provide a more in-depth look into the details of the Data Profiler library.

    +
    +

    Basics

    +
    + +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/genindex.html b/docs/0.10.3/html/genindex.html new file mode 100644 index 000000000..32154f139 --- /dev/null +++ b/docs/0.10.3/html/genindex.html @@ -0,0 +1,3430 @@ + + + + + + + Index - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + +
    +

    Index

    +
    A | B | C | D | E | F | G | H | I | J | K | L | M | N | O | P | Q | R | S | T | U | V | W
    +
    +
    +

    A

    + + + +
    +
    + +
    +

    B

    + + + +
    +
    + +
    +

    C

    + + + +
    +
    + +
    +

    D

    + + + +
    +
    + +
    +

    E

    + + + +
    +
    + +
    +

    F

    + + + +
    +
    + +
    +

    G

    + + + +
    +
    + +
    +

    H

    + + + +
    +
    + +
    +

    I

    + + + +
    +
    + +
    +

    J

    + + + +
    +
    + +
    +

    K

    + + + +
    +
    + +
    +

    L

    + + + +
    +
    + +
    +

    M

    + + + +
    +
    + +
    +

    N

    + + + +
    +
    + +
    +

    O

    + + + +
    +
    + +
    +

    P

    + + + +
    +
    + +
    +

    Q

    + + + +
    +
    + +
    +

    R

    + + + +
    +
    + +
    +

    S

    + + + +
    +
    + +
    +

    T

    + + + +
    +
    + +
    +

    U

    + + + +
    +
    + +
    +

    V

    + + + +
    +
    + +
    +

    W

    + + + +
    +
    + + +
    +
    + + + + + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/graph_data_demo.html b/docs/0.10.3/html/graph_data_demo.html new file mode 100644 index 000000000..469a59647 --- /dev/null +++ b/docs/0.10.3/html/graph_data_demo.html @@ -0,0 +1,708 @@ + + + + + + + + + Graph Pipeline Demo - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Graph Pipeline Demo

    +

    DataProfiler can also load and profile graph datasets. Similarly to the rest of DataProfiler profilers, this is split into two components: - GraphData - GraphProfiler

    +

    We will demo the use of this graph pipeline.

    +

    First, let’s import the libraries needed for this example.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import pprint
    +
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +except ImportError:
    +    import dataprofiler as dp
    +
    +data_path = "../dataprofiler/tests/data"
    +
    +
    +
    +

    We now input our dataset into the generic DataProfiler pipeline:

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(os.path.join(data_path, "csv/graph_data_csv_identify.csv"))
    +profile = dp.Profiler(data)
    +
    +report = profile.report()
    +
    +pp = pprint.PrettyPrinter(sort_dicts=False, compact=True)
    +pp.pprint(report)
    +
    +
    +
    +

    We notice that the Data class automatically detected the input file as graph data. The GraphData class is able to differentiate between tabular and graph csv data. After Data matches the input file as graph data, GraphData does the necessary work to load the csv data into a NetworkX Graph.

    +

    Profiler runs GraphProfiler when graph data is input (or when data_type="graph" is specified). The report() function outputs the profile for the user.

    +
    +

    Profile

    +

    The profile skeleton looks like this:

    +
    profile = {
    +    "num_nodes": ...,
    +    "num_edges": ...,
    +    "categorical_attributes": ...,
    +    "continuous_attributes": ...,
    +    "avg_node_degree": ...,
    +    "global_max_component_size": ...,
    +    "continuous_distribution": ...,
    +    "categorical_distribution": ...,
    +    "times": ...,
    +}
    +
    +
    +

    Description of properties in profile: - num_nodes: number of nodes in the graph - num_edges: number of edges in the graph - categorical_attributes: list of categorical edge attributes - continuous_attributes: list of continuous edge attributes - avg_node_degree: average degree of nodes in the graph - global_max_component_size: size of largest global max component in the graph - continuous_distribution: dictionary of statistical properties for each continuous attribute +- categorical_distribution: dictionary of statistical properties for each categorical attribute

    +

    The continuous_distribution and categorical_distribution dictionaries list statistical properties for each edge attribute in the graph:

    +
    continuous_distribution = {
    +    "name": ...,
    +    "scale": ...,
    +    "properties": ...,
    +}
    +
    +
    +
    categorical_distribution = {
    +    "bin_counts": ...,
    +    "bin_edges": ...,
    +}
    +
    +
    +

    Description of each attribute: - Continuous distribution: - name: name of the distribution - scale: negative log likelihood used to scale distributions and compare them in GraphProfiler - properties: list of distribution props - Categorical distribution: - bin_counts: histogram bin counts - bin_edges: histogram bin edges

    +

    properties lists the following distribution properties: [optional: shape, loc, scale, mean, variance, skew, kurtosis]. The list can be either 6 length or 7 length depending on the distribution (extra shape parameter): - 6 length: norm, uniform, expon, logistic - 7 length: gamma, lognorm - gamma: shape=a (float) - lognorm: shape=s (float)

    +

    For more information on shape parameters a and s: https://docs.scipy.org/doc/scipy/tutorial/stats.html#shape-parameters

    +
    +
    +

    Saving and Loading a Profile

    +

    Below you will see an example of how a Graph Profile can be saved and loaded again.

    +
    +
    [ ]:
    +
    +
    +
    +# The default save filepath is profile-<datetime>.pkl
    +profile.save(filepath="profile.pkl")
    +
    +new_profile = dp.GraphProfiler.load("profile.pkl")
    +new_report = new_profile.report()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pp.pprint(report)
    +
    +
    +
    +
    +
    +

    Difference in Data

    +

    If we wanted to ensure that this new profile was the same as the previous profile that we loaded, we could compare them using the diff functionality.

    +
    +
    [ ]:
    +
    +
    +
    +diff = profile.diff(new_profile)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pp.pprint(diff)
    +
    +
    +
    +

    Another use for diff might be to provide differences between training and testing profiles as shown in the cell below. We will use the profile above as the training profile and create a new profile to represent the testing profile

    +
    +
    [ ]:
    +
    +
    +
    +training_profile = profile
    +
    +testing_data = dp.Data(os.path.join(data_path, "csv/graph-differentiator-input-positive.csv"))
    +testing_profile = dp.Profiler(testing_data)
    +
    +test_train_diff = training_profile.diff(testing_profile)
    +
    +
    +
    +

    Below you can observe the difference between the two profiles.

    +
    +
    [ ]:
    +
    +
    +
    +pp.pprint(test_train_diff)
    +
    +
    +
    +
    +
    +

    Conclusion

    +

    We have shown the graph pipeline in the DataProfiler. It works similarly to the current DataProfiler implementation.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/graph_data_demo.ipynb b/docs/0.10.3/html/graph_data_demo.ipynb new file mode 100644 index 000000000..088612872 --- /dev/null +++ b/docs/0.10.3/html/graph_data_demo.ipynb @@ -0,0 +1,271 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Graph Pipeline Demo" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "DataProfiler can also load and profile graph datasets. Similarly to the rest of DataProfiler profilers, this is split into two components:\n", + "- GraphData\n", + "- GraphProfiler\n", + "\n", + "We will demo the use of this graph pipeline.\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import pprint\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now input our dataset into the generic DataProfiler pipeline:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/graph_data_csv_identify.csv\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "report = profile.report()\n", + "\n", + "pp = pprint.PrettyPrinter(sort_dicts=False, compact=True)\n", + "pp.pprint(report)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We notice that the `Data` class automatically detected the input file as graph data. The `GraphData` class is able to differentiate between tabular and graph csv data. After `Data` matches the input file as graph data, `GraphData` does the necessary work to load the csv data into a NetworkX Graph. \n", + "\n", + "`Profiler` runs `GraphProfiler` when graph data is input (or when `data_type=\"graph\"` is specified). The `report()` function outputs the profile for the user." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Profile" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The profile skeleton looks like this:\n", + "```\n", + "profile = {\n", + " \"num_nodes\": ...,\n", + " \"num_edges\": ...,\n", + " \"categorical_attributes\": ...,\n", + " \"continuous_attributes\": ...,\n", + " \"avg_node_degree\": ...,\n", + " \"global_max_component_size\": ...,\n", + " \"continuous_distribution\": ...,\n", + " \"categorical_distribution\": ...,\n", + " \"times\": ...,\n", + "}\n", + "```\n", + "\n", + "Description of properties in profile:\n", + "- `num_nodes`: number of nodes in the graph\n", + "- `num_edges`: number of edges in the graph\n", + "- `categorical_attributes`: list of categorical edge attributes\n", + "- `continuous_attributes`: list of continuous edge attributes\n", + "- `avg_node_degree`: average degree of nodes in the graph\n", + "- `global_max_component_size`: size of largest global max component in the graph\n", + "- `continuous_distribution`: dictionary of statistical properties for each continuous attribute\n", + "- `categorical_distribution`: dictionary of statistical properties for each categorical attribute\n", + "\n", + "The `continuous_distribution` and `categorical_distribution` dictionaries list statistical properties for each edge attribute in the graph:\n", + "```\n", + "continuous_distribution = {\n", + " \"name\": ...,\n", + " \"scale\": ...,\n", + " \"properties\": ...,\n", + "}\n", + "```\n", + "```\n", + "categorical_distribution = {\n", + " \"bin_counts\": ...,\n", + " \"bin_edges\": ...,\n", + "}\n", + "```\n", + "Description of each attribute:\n", + "- Continuous distribution:\n", + " - `name`: name of the distribution\n", + " - `scale`: negative log likelihood used to scale distributions and compare them in `GraphProfiler`\n", + " - `properties`: list of distribution props\n", + "- Categorical distribution:\n", + " - `bin_counts`: histogram bin counts\n", + " - `bin_edges`: histogram bin edges\n", + "\n", + "`properties` lists the following distribution properties: [optional: shape, loc, scale, mean, variance, skew, kurtosis]. The list can be either 6 length or 7 length depending on the distribution (extra shape parameter):\n", + "- 6 length: norm, uniform, expon, logistic\n", + "- 7 length: gamma, lognorm\n", + " - gamma: shape=`a` (float)\n", + " - lognorm: shape=`s` (float)\n", + " \n", + "For more information on shape parameters `a` and `s`: https://docs.scipy.org/doc/scipy/tutorial/stats.html#shape-parameters" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Saving and Loading a Profile\n", + "Below you will see an example of how a Graph Profile can be saved and loaded again." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The default save filepath is profile-.pkl\n", + "profile.save(filepath=\"profile.pkl\")\n", + "\n", + "new_profile = dp.GraphProfiler.load(\"profile.pkl\")\n", + "new_report = new_profile.report()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pp.pprint(report)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Difference in Data\n", + "If we wanted to ensure that this new profile was the same as the previous profile that we loaded, we could compare them using the diff functionality." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "diff = profile.diff(new_profile)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pp.pprint(diff)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Another use for diff might be to provide differences between training and testing profiles as shown in the cell below.\n", + "We will use the profile above as the training profile and create a new profile to represent the testing profile" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "training_profile = profile\n", + "\n", + "testing_data = dp.Data(os.path.join(data_path, \"csv/graph-differentiator-input-positive.csv\"))\n", + "testing_profile = dp.Profiler(testing_data)\n", + "\n", + "test_train_diff = training_profile.diff(testing_profile)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Below you can observe the difference between the two profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pp.pprint(test_train_diff)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Conclusion" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have shown the graph pipeline in the DataProfiler. It works similarly to the current DataProfiler implementation." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/0.10.3/html/graphs.html b/docs/0.10.3/html/graphs.html new file mode 100644 index 000000000..8d4d0c80d --- /dev/null +++ b/docs/0.10.3/html/graphs.html @@ -0,0 +1,487 @@ + + + + + + + + + Graphs - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Graphs

    +
    +

    Graph Your Data

    +

    We can plot some of our data as seaborn histogram plots. Below will demonstrate how to do so and provide examples.

    +

    The following plots are currently available to work directly with your profilers:

    +
    +
      +
    • histogram (numeric columns only)

    • +
    • missing values matrix

    • +
    +
    +

    Below shows how to do so with examples.

    +
    +

    What we need to import

    +
    from dataprofiler.reports import graphs
    +
    +
    +

    The main functions that is used to plot histograms are in graphs. You will also need the `dataprofiler[reports]` requirement to be installed:

    +
    pip install 'dataprofiler[reports]'
    +
    +
    +
    +
    +

    Plotting from a StructuredProfiler class

    +

    With a StructuredProfiler class variable, we can specify what columns we want to be plotted, and plot them into histograms.

    +
    graphs.plot_histograms(profiler, column_names, column_inds)
    +
    +
    +

    These are what the variables mean:

    +
    +
      +
    • profiler - StructuredProfiler class variable that contains the data we want

    • +
    • columns - (Optional) The list of IntColumn or FloatColumn names we want to specifically plot. If specified, column_inds cannot be specified.

    • +
    • column_inds - (Optional) The list of IntColumn or FloatColumn indexes we want to specifically plot. If specified, column_names cannot be specified.

    • +
    +
    +

    Additionally, we can also plot the missing values matrix for a StructuredProfiler:

    +
    graphs.plot_missing_values_matrix(profiler, ax, title)
    +
    +
    +

    These are what the variables mean:

    +
    +
      +
    • profiler - StructuredProfiler class variable that contains the data we want

    • +
    • ax - (Optional) MatPlotLib Axes to plot the matrix within.

    • +
    • title - (Optional) The title of the axes we want to define.

    • +
    +
    +
    +
    +

    Plotting an individual IntColumn or FloatColumn

    +

    With a column’s Int or Float profile, we can plot their respective histograms.

    +
    graphs.plot_col_histogram(column, axes, title)
    +
    +
    +

    These are what the variables mean:

    +
    +
      +
    • column - The IntColumn or FloatColumn we want to plot

    • +
    • axes - (Optional) The MatPlotLib Axes to plot the histogram within.

    • +
    • title - (Optional) The title of the axes we want to define.

    • +
    +
    +

    Additionally, we can also plot the missing values bargraph for any column profile:

    +
    graphs.plot_col_missing_values(profiler, ax, title)
    +
    +
    +

    These are what the variables mean:

    +
    +
      +
    • profiler - The StructuredColProfiler we want to plot

    • +
    • ax - (Optional) MatPlotLib Axes to plot the matrix within.

    • +
    • title - (Optional) The title of the axes we want to define.

    • +
    +
    +
    +
    +

    Examples

    +
    +

    Histograms

    +
      +
    1. This example demonstrates how we can take a StructuredProfiler class and plot histograms of the specified columns.

    2. +
    +
    import dataprofiler as dp
    +from dataprofiler.reports import graphs
    +
    +
    +data = [[1, 'a', 1.0],
    +        [2, 'b', 2.2],
    +        [3, 'c', 3.5],
    +        [None, 'd', 10.0]]
    +profiler = dp.StructuredProfiler(data)
    +
    +# This will plot all IntColumn and FloatColumn as histograms (The first and last column).
    +fig = graphs.plot_histograms(profiler)
    +fig.show()
    +
    +# This will only plot the specified column, 0.
    +columns_names = [0]
    +fig = graphs.plot_histograms(profiler, columns_names)
    +fig.show()
    +
    +
    +First Histogram Example Image +Second Histogram Example Image +
      +
    1. This example demonstrates how we can plot a low level profiler.

    2. +
    +
    import pandas as pd
    +
    +from dataprofiler.profilers import IntColumn
    +from dataprofiler.reports import graphs
    +
    +
    +data = pd.Series([1, 2, 3], dtype=str)
    +profiler = IntColumn('example')
    +profiler.update(data)
    +
    +# Plot the axes
    +ax = graphs.plot_col_histogram(profiler)
    +
    +# get and show the figure of the plotted histogram
    +fig = ax.get_figure()
    +fig.show()
    +
    +
    +Histogram Column Only Example Image +
    +
    +

    Missing Values Matrix

    +
      +
    1. This example demonstrates how we can take a StructuredProfiler class and plot a missing values matrix.

    2. +
    +
    import dataprofiler as dp
    +from dataprofiler.reports import graphs
    +
    +
    +data = pd.DataFrame(
    +    [[None, '', 1.0, '1/2/2021'],
    +     [3, None, 3.5, ''],
    +     [1, None, 1.0, '2/5/2020'],
    +     [None, 1, 10.0, '3/5/2020']],
    +    columns=['integer', 'str', 'float', 'datetime'],
    +    dtype=object
    +)
    +profiler = dp.StructuredProfiler(data)
    +
    +# This will plot the missing values matrix for all columns.
    +fig = graphs.plot_missing_values_matrix(profiler)
    +fig.show()
    +
    +
    +Missing Values Matrix Example Image +
      +
    1. This example demonstrates how we can plot barchart of a column’s missing values.

    2. +
    +
    import pandas as pd
    +
    +from dataprofiler.profilers.profile_builder import StructuredColProfiler
    +from dataprofiler.reports import graphs
    +
    +
    +data = pd.Series([1, 2, 3, None, None, 4], name='example', dtype=str)
    +profiler = StructuredColProfiler(data)
    +
    +# Plot the axes, can be a list of multiple columns
    +ax = graphs.plot_col_missing_values([profiler])
    +
    +# get and show the figure of the plotted histogram
    +fig = ax.get_figure()
    +fig.show()
    +
    +
    +Missing Values Column Only Example Image +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/index.html b/docs/0.10.3/html/index.html new file mode 100644 index 000000000..3edb560ec --- /dev/null +++ b/docs/0.10.3/html/index.html @@ -0,0 +1,743 @@ + + + + + + + + + Home - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Data Profiler | What’s in your data?

    +
    +

    Purpose

    +

    The DataProfiler is a Python library designed to make data analysis, monitoring and sensitive data detection easy.

    +

    Loading Data with a single command, the library automatically formats & loads files into a DataFrame. Profiling the Data, the library identifies the schema, statistics, entities and more. Data Profiles can then be used in downstream applications or reports.

    +

    The Data Profiler comes with a cutting edge pre-trained deep learning model, used to efficiently identify sensitive data (or PII). If customization is needed, it’s easy to add new entities to the existing pre-trained model or insert a new pipeline for entity recognition.

    +

    The best part? Getting started only takes a few lines of code (Example CSV):

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +data = Data("your_file.csv") # Auto-Detect & Load: CSV, AVRO, Parquet, JSON, Text
    +print(data.data.head(5)) # Access data directly via a compatible Pandas DataFrame
    +
    +profile = Profiler(data) # Calculate Statistics, Entity Recognition, etc
    +readable_report = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(readable_report, indent=4))
    +
    +
    +

    To install the full package from pypi:

    +
    pip install DataProfiler[ml]
    +
    +
    +

    If the ML requirements are too strict (say, you don’t want to install tensorflow), you can install a slimmer package. The slimmer package disables the default sensitive data detection / entity recognition (labler)

    +

    Install from pypi:

    +
    pip install DataProfiler
    +
    +
    +

    If you have suggestions or find a bug, please open an issue.

    +

    Visit the API to explore Data Profiler’s terminology.

    +
    +
    +

    What is a Data Profile?

    +

    In the case of this library, a data profile is a dictionary containing statistics and predictions about the underlying dataset. There are “global statistics” or global_stats, which contain dataset level data and there are “column/row level statistics” or data_stats (each column is a new key-value entry).

    +

    The format for a structured profile is below:

    +
    "global_stats": {
    +    "samples_used": int,
    +    "column_count": int,
    +    "row_count": int,
    +    "row_has_null_ratio": float,
    +    "row_is_null_ratio": float,
    +    "unique_row_ratio": float,
    +    "duplicate_row_count": int,
    +    "file_type": string,
    +    "encoding": string,
    +    "correlation_matrix": list[list[int]], (*)
    +    "chi2_matrix": list[list[float]],
    +    "profile_schema": dict[string, list[int]]
    +},
    +"data_stats": [
    +    {
    +        "column_name": string,
    +        "data_type": string,
    +        "data_label": string,
    +        "categorical": bool,
    +        "order": string,
    +        "samples": list[str],
    +        "statistics": {
    +            "sample_size": int,
    +            "null_count": int,
    +            "null_types": list[string],
    +            "null_types_index": dict[string, list[int]],
    +            "data_type_representation": dict[string, list[string]],
    +            "min": [null, float],
    +            "max": [null, float],
    +            "sum": float,
    +            "mode": list[float],
    +            "median": float,
    +            "median_absolute_deviation": float,
    +            "mean": float,
    +            "variance": float,
    +            "stddev": float,
    +            "skewness": float,
    +            "kurtosis": float,
    +            "num_zeros": int,
    +            "num_negatives": int,
    +            "histogram": {
    +                "bin_counts": list[int],
    +                "bin_edges": list[float],
    +            },
    +            "quantiles": {
    +                int: float
    +            },
    +            "vocab": list[char],
    +            "avg_predictions": dict[string, float],
    +            "data_label_representation": dict[string, float],
    +            "categories": list[str],
    +            "unique_count": int,
    +            "unique_ratio": float,
    +            "categorical_count": dict[string, int],
    +            "gini_impurity": float,
    +            "unalikeability": float,
    +            "precision": {
    +                'min': int,
    +                'max': int,
    +                'mean': float,
    +                'var': float,
    +                'std': float,
    +                'sample_size': int,
    +                'margin_of_error': float,
    +                'confidence_level': float
    +            },
    +            "times": dict[string, float],
    +            "format": string
    +        },
    +        "null_replication_metrics": {
    +            "class_prior": list[int],
    +            "class_sum": list[list[int]],
    +            "class_mean": list[list[int]]
    +        }
    +    }
    +]
    +
    +
    +

    (*) Currently the correlation matrix update is toggled off. It will be reset in a later update. Users can still use it as desired with the is_enable option set to True.

    +

    The format for an unstructured profile is below:

    +
    "global_stats": {
    +    "samples_used": int,
    +    "empty_line_count": int,
    +    "file_type": string,
    +    "encoding": string,
    +    "memory_size": float, # in MB
    +},
    +"data_stats": {
    +    "data_label": {
    +        "entity_counts": {
    +            "word_level": dict[string, int],
    +            "true_char_level": dict[string, int],
    +            "postprocess_char_level": dict[string, int]
    +        },
    +        "entity_percentages": {
    +            "word_level": dict[string, float],
    +            "true_char_level": dict[string, float],
    +            "postprocess_char_level": dict[string, float]
    +        },
    +        "times": dict[string, float]
    +    },
    +    "statistics": {
    +        "vocab": list[char],
    +        "vocab_count": dict[string, int],
    +        "words": list[string],
    +        "word_count": dict[string, int],
    +        "times": dict[string, float]
    +    }
    +}
    +
    +
    +

    The format for a graph profile is below:

    +
    "num_nodes": int,
    +"num_edges": int,
    +"categorical_attributes": list[string],
    +"continuous_attributes": list[string],
    +"avg_node_degree": float,
    +"global_max_component_size": int,
    +"continuous_distribution": {
    +    "<attribute_1>": {
    +        "name": string,
    +        "scale": float,
    +        "properties": list[float, np.array]
    +    },
    +    "<attribute_2>": None,
    +},
    +"categorical_distribution": {
    +    "<attribute_1>": None,
    +    "<attribute_2>": {
    +        "bin_counts": list[int],
    +        "bin_edges": list[float]
    +    },
    +},
    +"times": dict[string, float]
    +
    +
    +
    +

    Supported Data Formats

    +
      +
    • Any delimited file (CSV, TSV, etc.)

    • +
    • JSON object

    • +
    • Avro file

    • +
    • Parquet file

    • +
    • Text file

    • +
    • Pandas DataFrame

    • +
    • A URL that points to one of the supported file types above

    • +
    +
    +
    +

    Data Labels

    +

    Data Labels are determined per cell for structured data (column/row when the profiler is used) or at the character level for unstructured data.

    +
      +
    • UNKNOWN

    • +
    • ADDRESS

    • +
    • BAN (bank account number, 10-18 digits)

    • +
    • CREDIT_CARD

    • +
    • EMAIL_ADDRESS

    • +
    • UUID

    • +
    • HASH_OR_KEY (md5, sha1, sha256, random hash, etc.)

    • +
    • IPV4

    • +
    • IPV6

    • +
    • MAC_ADDRESS

    • +
    • PERSON

    • +
    • PHONE_NUMBER

    • +
    • SSN

    • +
    • URL

    • +
    • US_STATE

    • +
    • DRIVERS_LICENSE

    • +
    • DATE

    • +
    • TIME

    • +
    • DATETIME

    • +
    • INTEGER

    • +
    • FLOAT

    • +
    • QUANTITY

    • +
    • ORDINAL

    • +
    +
    +
    +
    +

    Get Started

    +
    +

    Load a File

    +

    The profiler should automatically identify the file type and load the data into a Data Class.

    +

    Along with other attributtes the Data class enables structured data to be accessed via a valid Pandas DataFrame.

    +
    # Load a csv file, return a CSVData object
    +csv_data = Data('your_file.csv')
    +
    +# Print the first 10 rows of the csv file
    +print(csv_data.data.head(10))
    +
    +# Load a parquet file, return a ParquetData object
    +parquet_data = Data('your_file.parquet')
    +
    +# Sort the data by the name column
    +parquet_data.data.sort_values(by='name', inplace=True)
    +
    +# Print the sorted first 10 rows of the parquet data
    +print(parquet_data.data.head(10))
    +
    +
    +

    If the file type is not automatically identified (rare), you can specify them +specifically, see section Data Readers.

    +
    +
    +

    Profile a File

    +

    Example uses a CSV file for example, but CSV, JSON, Avro, Parquet or Text should also work.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load file (CSV should be automatically identified)
    +data = Data("your_file.csv")
    +
    +# Profile the dataset
    +profile = Profiler(data)
    +
    +# Generate a report and use json to prettify.
    +report  = profile.report(report_options={"output_format":"pretty"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Updating Profiles

    +

    Currently, the data profiler is equipped to update its profile in batches.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load and profile a CSV file
    +data = Data("your_file.csv")
    +profile = Profiler(data)
    +
    +# Update the profile with new data:
    +new_data = Data("new_data.csv")
    +profile.update_profile(new_data)
    +
    +# Print the report using json to prettify.
    +report  = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Merging Profiles

    +

    If you have two files with the same schema (but different data), it is possible to merge the two profiles together via an addition operator.

    +

    This also enables profiles to be determined in a distributed manner.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load a CSV file with a schema
    +data1 = Data("file_a.csv")
    +profile1 = Profiler(data)
    +
    +# Load another CSV file with the same schema
    +data2 = Data("file_b.csv")
    +profile2 = Profiler(data)
    +
    +profile3 = profile1 + profile2
    +
    +# Print the report using json to prettify.
    +report  = profile3.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Profile a Pandas DataFrame

    +
    import pandas as pd
    +import dataprofiler as dp
    +import json
    +
    +my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]])
    +profile = dp.Profiler(my_dataframe)
    +
    +# print the report using json to prettify.
    +report = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +# read a specified column, in this case it is labeled 0:
    +print(json.dumps(report["data stats"][0], indent=4))
    +
    +
    +
    +
    +

    Unstructured Profiler

    +

    In addition to the structured profiler, the Data Profiler provides unstructured +profiling for the TextData object or string. Unstructured profiling also works +with list(string), pd.Series(string) or pd.DataFrame(string) given profiler_type +option specified as unstructured. Below is an example of unstructured profile +with a text file.

    +
    import dataprofiler as dp
    +import json
    +my_text = dp.Data('text_file.txt')
    +profile = dp.Profiler(my_text)
    +
    +# print the report using json to prettify.
    +report = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +

    Another example of unstructured profile with pd.Series of string is given as below

    +
    import dataprofiler as dp
    +import pandas as pd
    +import json
    +
    +text_data = pd.Series(['first string', 'second string'])
    +profile = dp.Profiler(text_data, profiler_type="unstructured")
    +
    +# print the report using json to prettify.
    +report = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Graph Profiler

    +

    DataProfiler also provides the ability to profile graph data from a csv file. Below is an example of the graph profiler with a graph data csv file:

    +
    import dataprofiler as dp
    +import pprint
    +
    +my_graph = dp.Data('graph_file.csv')
    +profile = dp.Profiler(my_graph)
    +
    +# print the report using pretty print (json dump does not work on numpy array values inside dict)
    +report = profile.report()
    +printer = pprint.PrettyPrinter(sort_dicts=False, compact=True)
    +printer.pprint(report)
    +
    +
    +
    +
    +

    Specifying a Filetype or Delimiter

    +

    Example of specifying a CSV data type, with a , delimiter. +In addition, it utilizes only the first 10,000 rows.

    +
    import json
    +import os
    +from dataprofiler import Data, Profiler
    +from dataprofiler.data_readers.csv_data import CSVData
    +
    +# Load a CSV file, with "," as the delimiter
    +data = CSVData("your_file.csv", options={"delimiter": ","})
    +
    +# Split the data, such that only the first 10,000 rows are used
    +data = data.data[0:10000]
    +
    +# Read in profile and print results
    +profile = Profiler(data)
    +print(json.dumps(profile.report(report_options={"output_format":"pretty"}), indent=4))
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +
    +

    Versions

    + +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/install.html b/docs/0.10.3/html/install.html new file mode 100644 index 000000000..74b3e7177 --- /dev/null +++ b/docs/0.10.3/html/install.html @@ -0,0 +1,387 @@ + + + + + + + + + Install - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Install

    +

    To install the full package from pypi:

    +
    pip install DataProfiler[ml]
    +
    +
    +

    If the ML requirements are too strict (say, you don’t want to install +tensorflow), you can install a slimmer package. The slimmer package disables +the default sensitive data detection / entity recognition (labler)

    +

    Install from pypi:

    +
    pip install DataProfiler
    +
    +
    +
    +

    Snappy Installation

    +

    This is required to profile parquet/avro datasets

    +

    MacOS with homebrew:

    +
    brew install snappy && CPPFLAGS="-I/usr/local/include -L/usr/local/lib" pip install python-snappy
    +
    +
    +

    Linux install:

    +
    sudo apt-get -y install libsnappy-dev
    +
    +
    +
    +
    +

    Build From Scratch

    +

    NOTE: Installation for python3

    +

    virtualenv install:

    +
    python3 -m pip install virtualenv
    +
    +
    +

    Setup virtual env:

    +
    python3 -m virtualenv --python=python3 venv3
    +source venv3/bin/activate
    +
    +
    +

    Install requirements:

    +
    pip3 install -r requirements.txt
    +
    +
    +

    Install labeler dependencies:

    +
    pip3 install -r requirements-ml.txt
    +
    +
    +

    Install via the repo – Build setup.py and install locally:

    +
    python3 setup.py sdist bdist bdist_wheel
    +pip3 install dist/DataProfiler*-py3-none-any.whl
    +
    +
    +

    If you see:

    +
    ERROR: Double requirement given:dataprofiler==X.Y.Z from dataprofiler/dist/DataProfiler-X.Y.Z-py3-none-any.whl (already in dataprofiler==X2.Y2.Z2 from dataprofiler/dist/DataProfiler-X2.Y2.Z2-py3-none-any.whl, name='dataprofiler')
    +
    +
    +

    This means that you have multiple versions of the DataProfiler distribution +in the dist folder. +To resolve, either remove the older one or delete the folder and rerun the steps +above.

    +

    Install via github:

    +
    pip3 install git+https://github.com/capitalone/dataprofiler.git#egg=dataprofiler
    +
    +
    +
    +
    +

    Testing

    +

    For testing, install test requirements:

    +
    pip3 install -r requirements-test.txt
    +
    +
    +

    To run all unit tests, use:

    +
    DATAPROFILER_SEED=0 python3 -m unittest discover -p "test*.py"
    +
    +
    +

    To run file of unit tests, use form:

    +
    DATAPROFILER_SEED=0 python3 -m unittest discover -p test_profile_builder.py
    +
    +
    +

    To run a file with Pytest use:

    +
    DATAPROFILER_SEED=0 pytest dataprofiler/tests/data_readers/test_csv_data.py -v
    +
    +
    +

    To run individual of unit test, use form:

    +
    DATAPROFILER_SEED=0 python3 -m unittest dataprofiler.tests.profilers.test_profile_builder.TestProfiler
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/labeler.html b/docs/0.10.3/html/labeler.html new file mode 100644 index 000000000..333d132c6 --- /dev/null +++ b/docs/0.10.3/html/labeler.html @@ -0,0 +1,956 @@ + + + + + + + + + Sensitive Data Detection with the Labeler - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Sensitive Data Detection with the Labeler

    +

    In this example, we utilize the Labeler component of the Data Profiler to detect the sensitive information for both structured and unstructured data. In addition, we show how to train the Labeler on some specific dataset with different list of entities.

    +

    First, let’s dive into what the Labeler is.

    +
    +

    What is the Labeler

    +

    The Labeler is a pipeline designed to make building, training, and predictions with ML models quick and easy. There are 3 major components to the Labeler: the preprocessor, the model, and the postprocessor.

    +

    alt text

    +

    Each component can be switched out individually to suit your needs. As you might expect, the preprocessor takes in raw data and prepares it for the model, the model performs the prediction or training, and the postprocessor takes prediction results and turns them into human-readable results.

    +

    Now let’s run some examples. Start by importing all the requirements.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +import pandas as pd
    +
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +except ImportError:
    +    import dataprofiler as dp
    +
    +# remove extra tf loggin
    +import tensorflow as tf
    +tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
    +
    +
    +
    +
    +
    +

    Structured Data Prediction

    +

    We’ll use the aws honeypot dataset in the test folder for this example. First, look at the data using the Data Reader class of the Data Profiler. This dataset is from the US department of educations, found here!

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data("../dataprofiler/tests/data/csv/SchoolDataSmall.csv")
    +df_data = data.data
    +df_data.head()
    +
    +
    +
    +

    We can directly predict the labels of a structured dataset on the cell level.

    +
    +
    [ ]:
    +
    +
    +
    +labeler = dp.DataLabeler(labeler_type='structured')
    +
    +# print out the labels and label mapping
    +print("Labels: {}".format(labeler.labels))
    +print("\n")
    +print("Label Mapping: {}".format(labeler.label_mapping))
    +print("\n")
    +
    +# make predictions and get labels for each cell going row by row
    +# predict options are model dependent and the default model can show prediction confidences
    +predictions = labeler.predict(data, predict_options={"show_confidences": True})
    +
    +# display prediction results
    +print("Predictions: {}".format(predictions['pred']))
    +print("\n")
    +
    +# display confidence results
    +print("Confidences: {}".format(predictions['conf']))
    +
    +
    +
    +

    The profiler uses the Labeler to perform column by column predictions. The data contains 11 columns, each of which has data label. Next, we will use the Labeler of the Data Profiler to predict the label for each column in this tabular dataset. Since we are only going to demo the labeling functionality, other options of the Data Profiler are disabled to keep this quick.

    +
    +
    [ ]:
    +
    +
    +
    +# helper functions for printing results
    +
    +def get_structured_results(results):
    +    """Helper function to get data labels for each column."""
    +    columns = []
    +    predictions = []
    +    samples = []
    +    for col in results['data_stats']:
    +        columns.append(col['column_name'])
    +        predictions.append(col['data_label'])
    +        samples.append(col['samples'])
    +
    +    df_results = pd.DataFrame({'Column': columns, 'Prediction': predictions, 'Sample': samples})
    +    return df_results
    +
    +def get_unstructured_results(data, results):
    +    """Helper function to get data labels for each labeled piece of text."""
    +    labeled_data = []
    +    for pred in results['pred'][0]:
    +        labeled_data.append([data[0][pred[0]:pred[1]], pred[2]])
    +    label_df = pd.DataFrame(labeled_data, columns=['Text', 'Labels'])
    +    return label_df
    +
    +
    +pd.set_option('display.width', 100)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# set options to only run the labeler
    +profile_options = dp.ProfilerOptions()
    +profile_options.set({"structured_options.text.is_enabled": False,
    +                     "int.is_enabled": False,
    +                     "float.is_enabled": False,
    +                     "order.is_enabled": False,
    +                     "category.is_enabled": False,
    +                     "chi2_homogeneity.is_enabled": False,
    +                     "datetime.is_enabled": False,})
    +
    +profile = dp.Profiler(data, options=profile_options)
    +
    +results = profile.report()
    +print(get_structured_results(results))
    +
    +
    +
    +

    In this example, the results show that the Data Profiler is able to detect integers, URLs, address, and floats appropriately. Unknown is typically strings of text, which is appropriate for those columns.

    +
    +
    +

    Unstructured Data Prediction

    +

    Besides structured data, the Labeler detects the sensitive information on the unstructured text. We use a sample of spam email in Enron email dataset for this demo. As above, we start investigating the content of the given email sample.

    +
    +
    [ ]:
    +
    +
    +
    +# load data
    +data = "Message-ID: <11111111.1111111111111.JavaMail.evans@thyme>\n" + \
    +        "Date: Fri, 10 Aug 2005 11:31:37 -0700 (PDT)\n" + \
    +        "From: w..smith@company.com\n" + \
    +        "To: john.smith@company.com\n" + \
    +        "Subject: RE: ABC\n" + \
    +        "Mime-Version: 1.0\n" + \
    +        "Content-Type: text/plain; charset=us-ascii\n" + \
    +        "Content-Transfer-Encoding: 7bit\n" + \
    +        "X-From: Smith, Mary W. </O=ENRON/OU=NA/CN=RECIPIENTS/CN=SSMITH>\n" + \
    +        "X-To: Smith, John </O=ENRON/OU=NA/CN=RECIPIENTS/CN=JSMITH>\n" + \
    +        "X-cc: \n" + \
    +        "X-bcc: \n" + \
    +        "X-Folder: \SSMITH (Non-Privileged)\Sent Items\n" + \
    +        "X-Origin: Smith-S\n" + \
    +        "X-FileName: SSMITH (Non-Privileged).pst\n\n" + \
    +        "All I ever saw was the e-mail from the office.\n\n" + \
    +        "Mary\n\n" + \
    +        "-----Original Message-----\n" + \
    +        "From:   Smith, John  \n" + \
    +        "Sent:   Friday, August 10, 2005 13:07 PM\n" + \
    +        "To:     Smith, Mary W.\n" + \
    +        "Subject:        ABC\n\n" + \
    +        "Have you heard any more regarding the ABC sale? I guess that means that " + \
    +        "it's no big deal here, but you think they would have send something.\n\n\n" + \
    +        "John Smith\n" + \
    +        "123-456-7890\n"
    +
    +# convert string data to list to feed into the labeler
    +data = [data]
    +
    +
    +
    +

    By default, the Labeler predicts the results at the character level for unstructured text.

    +
    +
    [ ]:
    +
    +
    +
    +labeler = dp.DataLabeler(labeler_type='unstructured')
    +
    +# make predictions and get labels per character
    +predictions = labeler.predict(data)
    +
    +# display results
    +print(predictions['pred'])
    +
    +
    +
    +

    In addition to the character-level result, the Labeler provides the results at the word level following the standard NER (Named Entity Recognition), e.g., utilized by spaCy.

    +
    +
    [ ]:
    +
    +
    +
    +# convert prediction to word format and ner format
    +# Set the output to the NER format (start position, end position, label)
    +labeler.set_params(
    +    { 'postprocessor': { 'output_format':'ner', 'use_word_level_argmax':True } }
    +)
    +
    +# make predictions and get labels per character
    +predictions = labeler.predict(data)
    +
    +# display results
    +print('\n')
    +print('=======================Prediction======================\n')
    +for pred in predictions['pred'][0]:
    +    print('{}: {}'.format(data[0][pred[0]: pred[1]], pred[2]))
    +    print('--------------------------------------------------------')
    +
    +
    +
    +

    Here, the Labeler is able to identify sensitive information such as datetime, email address, person names, and phone number in an email sample.

    +
    +
    +

    Train the Labeler from Scratch

    +

    The Labeler can be trained from scratch with a new list of labels. Below, we show an example of training the Labeler on a dataset with labels given as the columns of that dataset. For brevity’s sake, let’s only train a few epochs with a subset of a dataset.

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data("../dataprofiler/tests/data/csv/SchoolDataSmall.csv")
    +df = data.data[["OPEID6", "INSTURL", "SEARCH_STRING"]]
    +df.head()
    +
    +# split data to training and test set
    +split_ratio = 0.2
    +df = df.sample(frac=1).reset_index(drop=True)
    +data_train = df[:int((1 - split_ratio) * len(df))]
    +data_test = df[int((1 - split_ratio) * len(df)):]
    +
    +# train a new labeler with column names as labels
    +if not os.path.exists('data_labeler_saved'):
    +    os.makedirs('data_labeler_saved')
    +
    +labeler = dp.train_structured_labeler(
    +    data=data_train,
    +    save_dirpath="data_labeler_saved",
    +    epochs=10,
    +    default_label="OPEID6"
    +)
    +
    +
    +
    +
    +

    The trained Labeler is then used by the Data Profiler to provide the prediction on the new dataset.

    +
    +
    [ ]:
    +
    +
    +
    +# predict with the labeler object
    +profile_options.set({'structured_options.data_labeler.data_labeler_object': labeler})
    +profile = dp.Profiler(data_test, options=profile_options)
    +
    +# get the prediction from the data profiler
    +results = profile.report()
    +print(get_structured_results(results))
    +
    +
    +
    +

    Another way to use the trained Labeler is through the directory path of the saved labeler.

    +
    +
    [ ]:
    +
    +
    +
    +# predict with the labeler loaded from path
    +profile_options.set({'structured_options.data_labeler.data_labeler_dirpath': 'data_labeler_saved'})
    +profile = dp.Profiler(data_test, options=profile_options)
    +
    +# get the prediction from the data profiler
    +results = profile.report()
    +print(get_structured_results(results))
    +
    +
    +
    +
    +
    +

    Transfer Learning a Labeler

    +

    Instead of training a model from scratch, we can also transfer learn to improve the model and/or extend the labels. Again for brevity’s sake, let’s only train a few epochs with a small dataset at the cost of accuracy.

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data("../dataprofiler/tests/data/csv/SchoolDataSmall.csv")
    +df_data = data.data[["OPEID6", "INSTURL", "SEARCH_STRING"]]
    +
    +
    +# prep data
    +df_data = df_data.reset_index(drop=True).melt()
    +df_data.columns = [1, 0]  # labels=1, values=0 in that order
    +df_data = df_data.astype(str)
    +new_labels = df_data[1].unique().tolist()
    +
    +# load structured Labeler w/ trainable set to True
    +labeler = dp.DataLabeler(labeler_type='structured', trainable=True)
    +
    +# Reconstruct the model to add each new label
    +for label in new_labels:
    +    labeler.add_label(label)
    +
    +# this will use transfer learning to retrain the labeler on your new
    +# dataset and labels.
    +# Setting labels with a list of labels or label mapping will overwrite the existing labels with new ones
    +# Setting the reset_weights parameter to false allows transfer learning to occur
    +model_results = labeler.fit(x=df_data[0], y=df_data[1], validation_split=0.2,
    +                                 epochs=10, labels=None, reset_weights=False)
    +
    +
    +
    +

    Let’s display the training results of the last epoch:

    +
    +
    [ ]:
    +
    +
    +
    +print("{:16s}  Precision  Recall  F1-score  Support".format(""))
    +for item in model_results[-1][2]:
    +    print("{:16s}  {:4.3f}      {:4.3f}   {:4.3f}     {:7.0f}".format(item,
    +                                                                      model_results[-1][2][item]["precision"],
    +                                                                      model_results[-1][2][item]["recall"],
    +                                                                      model_results[-1][2][item]["f1-score"],
    +                                                                      model_results[-1][2][item]["support"]))
    +
    +
    +
    +

    It is now trained to detect additional labels! The model results here show all the labels training accuracy. Since only new labels existed in the dataset, only the new labels are given accuracy scores. Keep in mind this is a small dataset for brevity’s sake and that real training would involve more samples and better results.

    +
    +
    +

    Saving and Loading a Labeler

    +

    The Labeler can easily be saved or loaded with one simple line.

    +
    +
    [ ]:
    +
    +
    +
    +# Ensure save directory exists
    +if not os.path.exists('my_labeler'):
    +    os.makedirs('my_labeler')
    +
    +# Saving the labeler
    +labeler.save_to_disk("my_labeler")
    +
    +# Loading the labeler
    +labeler = dp.DataLabeler(labeler_type='structured', dirpath="my_labeler")
    +
    +
    +
    +
    +
    +

    Building a Labeler from the Ground Up

    +

    As mentioned earlier, the labeler is comprised of three components, and each of the compenents can be created and interchanged in the the labeler pipeline.

    +
    +
    [ ]:
    +
    +
    +
    +import random
    +from dataprofiler.labelers.character_level_cnn_model import \
    +    CharacterLevelCnnModel
    +from dataprofiler.labelers.data_processing import \
    +    StructCharPreprocessor, StructCharPostprocessor
    +
    +model = CharacterLevelCnnModel({"PAD":0, "UNKNOWN":1, "Test_Label":2})
    +preprocessor = StructCharPreprocessor()
    +postprocessor = StructCharPostprocessor()
    +
    +labeler = dp.DataLabeler(labeler_type='structured')
    +labeler.set_preprocessor(preprocessor)
    +labeler.set_model(model)
    +labeler.set_postprocessor(postprocessor)
    +
    +# check for basic compatibility between the processors and the model
    +labeler.check_pipeline()
    +
    +# Optionally set the parameters
    +parameters={
    +    'preprocessor':{
    +        'max_length': 100,
    +    },
    +    'model':{
    +        'max_length': 100,
    +    },
    +    'postprocessor':{
    +        'random_state': random.Random(1)
    +    }
    +}
    +labeler.set_params(parameters)
    +
    +labeler.help()
    +
    +
    +
    +

    The components can each be created if you inherit the BaseModel and BaseProcessor for the model and processors, respectively. More info can be found about coding your own components in the Labeler section of the documentation. In summary, the Data Profiler open source library can be used to scan sensitive information in both structured and unstructured data with different file types. It supports multiple input formats and output formats at word and +character levels. Users can also train the labeler on their own datasets.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/labeler.ipynb b/docs/0.10.3/html/labeler.ipynb new file mode 100644 index 000000000..af31b68c5 --- /dev/null +++ b/docs/0.10.3/html/labeler.ipynb @@ -0,0 +1,650 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "spoken-reunion", + "metadata": {}, + "source": [ + "# Sensitive Data Detection with the Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "interesting-bidder", + "metadata": {}, + "source": [ + "In this example, we utilize the Labeler component of the Data Profiler to detect the sensitive information for both structured and unstructured data. In addition, we show how to train the Labeler on some specific dataset with different list of entities.\n", + "\n", + "First, let's dive into what the Labeler is." + ] + }, + { + "cell_type": "markdown", + "id": "1965b83b", + "metadata": {}, + "source": [ + "## What is the Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "388c643f", + "metadata": {}, + "source": [ + "The Labeler is a pipeline designed to make building, training, and predictions with ML models quick and easy. There are 3 major components to the Labeler: the preprocessor, the model, and the postprocessor." + ] + }, + { + "cell_type": "markdown", + "id": "e5d0aeb4", + "metadata": {}, + "source": [ + "![alt text](DL-Flowchart.png \"Title\")" + ] + }, + { + "cell_type": "markdown", + "id": "550323c7", + "metadata": {}, + "source": [ + "Each component can be switched out individually to suit your needs. As you might expect, the preprocessor takes in raw data and prepares it for the model, the model performs the prediction or training, and the postprocessor takes prediction results and turns them into human-readable results. \n", + "\n", + "Now let's run some examples. Start by importing all the requirements." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "scientific-stevens", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "import pandas as pd\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "# remove extra tf loggin\n", + "import tensorflow as tf\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "id": "5125b215", + "metadata": {}, + "source": [ + "## Structured Data Prediction" + ] + }, + { + "cell_type": "markdown", + "id": "wicked-devon", + "metadata": {}, + "source": [ + "We'll use the aws honeypot dataset in the test folder for this example. First, look at the data using the Data Reader class of the Data Profiler. This dataset is from the US department of educations, [found here!](https://data.ed.gov/dataset/college-scorecard-all-data-files-through-6-2020/resources?resource=823ac095-bdfc-41b0-b508-4e8fc3110082)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "adjusted-native", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "data = dp.Data(\"../dataprofiler/tests/data/csv/SchoolDataSmall.csv\")\n", + "df_data = data.data\n", + "df_data.head()" + ] + }, + { + "cell_type": "markdown", + "id": "ab6ccf8a", + "metadata": {}, + "source": [ + "We can directly predict the labels of a structured dataset on the cell level." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19529af4", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "labeler = dp.DataLabeler(labeler_type='structured')\n", + "\n", + "# print out the labels and label mapping\n", + "print(\"Labels: {}\".format(labeler.labels)) \n", + "print(\"\\n\")\n", + "print(\"Label Mapping: {}\".format(labeler.label_mapping))\n", + "print(\"\\n\")\n", + "\n", + "# make predictions and get labels for each cell going row by row\n", + "# predict options are model dependent and the default model can show prediction confidences\n", + "predictions = labeler.predict(data, predict_options={\"show_confidences\": True})\n", + "\n", + "# display prediction results\n", + "print(\"Predictions: {}\".format(predictions['pred']))\n", + "print(\"\\n\")\n", + "\n", + "# display confidence results\n", + "print(\"Confidences: {}\".format(predictions['conf']))" + ] + }, + { + "cell_type": "markdown", + "id": "2af72e2c", + "metadata": {}, + "source": [ + "The profiler uses the Labeler to perform column by column predictions. The data contains 11 columns, each of which has data label. Next, we will use the Labeler of the Data Profiler to predict the label for each column in this tabular dataset. Since we are only going to demo the labeling functionality, other options of the Data Profiler are disabled to keep this quick." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d6cb9d7e-149a-4cfe-86f8-76c47c57aeea", + "metadata": {}, + "outputs": [], + "source": [ + "# helper functions for printing results\n", + "\n", + "def get_structured_results(results):\n", + " \"\"\"Helper function to get data labels for each column.\"\"\"\n", + " columns = []\n", + " predictions = []\n", + " samples = []\n", + " for col in results['data_stats']:\n", + " columns.append(col['column_name'])\n", + " predictions.append(col['data_label'])\n", + " samples.append(col['samples'])\n", + "\n", + " df_results = pd.DataFrame({'Column': columns, 'Prediction': predictions, 'Sample': samples})\n", + " return df_results\n", + "\n", + "def get_unstructured_results(data, results):\n", + " \"\"\"Helper function to get data labels for each labeled piece of text.\"\"\"\n", + " labeled_data = []\n", + " for pred in results['pred'][0]:\n", + " labeled_data.append([data[0][pred[0]:pred[1]], pred[2]])\n", + " label_df = pd.DataFrame(labeled_data, columns=['Text', 'Labels'])\n", + " return label_df\n", + " \n", + "\n", + "pd.set_option('display.width', 100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "secret-million", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# set options to only run the labeler\n", + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({\"structured_options.text.is_enabled\": False, \n", + " \"int.is_enabled\": False, \n", + " \"float.is_enabled\": False, \n", + " \"order.is_enabled\": False, \n", + " \"category.is_enabled\": False, \n", + " \"chi2_homogeneity.is_enabled\": False,\n", + " \"datetime.is_enabled\": False,})\n", + "\n", + "profile = dp.Profiler(data, options=profile_options)\n", + "\n", + "results = profile.report() \n", + "print(get_structured_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "fatty-louisville", + "metadata": {}, + "source": [ + "In this example, the results show that the Data Profiler is able to detect integers, URLs, address, and floats appropriately. Unknown is typically strings of text, which is appropriate for those columns." + ] + }, + { + "cell_type": "markdown", + "id": "unavailable-diploma", + "metadata": {}, + "source": [ + "## Unstructured Data Prediction" + ] + }, + { + "cell_type": "markdown", + "id": "metallic-coaching", + "metadata": {}, + "source": [ + "Besides structured data, the Labeler detects the sensitive information on the unstructured text. We use a sample of spam email in Enron email dataset for this demo. As above, we start investigating the content of the given email sample." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "unauthorized-lounge", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# load data\n", + "data = \"Message-ID: <11111111.1111111111111.JavaMail.evans@thyme>\\n\" + \\\n", + " \"Date: Fri, 10 Aug 2005 11:31:37 -0700 (PDT)\\n\" + \\\n", + " \"From: w..smith@company.com\\n\" + \\\n", + " \"To: john.smith@company.com\\n\" + \\\n", + " \"Subject: RE: ABC\\n\" + \\\n", + " \"Mime-Version: 1.0\\n\" + \\\n", + " \"Content-Type: text/plain; charset=us-ascii\\n\" + \\\n", + " \"Content-Transfer-Encoding: 7bit\\n\" + \\\n", + " \"X-From: Smith, Mary W. \\n\" + \\\n", + " \"X-To: Smith, John \\n\" + \\\n", + " \"X-cc: \\n\" + \\\n", + " \"X-bcc: \\n\" + \\\n", + " \"X-Folder: \\SSMITH (Non-Privileged)\\Sent Items\\n\" + \\\n", + " \"X-Origin: Smith-S\\n\" + \\\n", + " \"X-FileName: SSMITH (Non-Privileged).pst\\n\\n\" + \\\n", + " \"All I ever saw was the e-mail from the office.\\n\\n\" + \\\n", + " \"Mary\\n\\n\" + \\\n", + " \"-----Original Message-----\\n\" + \\\n", + " \"From: Smith, John \\n\" + \\\n", + " \"Sent: Friday, August 10, 2005 13:07 PM\\n\" + \\\n", + " \"To: Smith, Mary W.\\n\" + \\\n", + " \"Subject: ABC\\n\\n\" + \\\n", + " \"Have you heard any more regarding the ABC sale? I guess that means that \" + \\\n", + " \"it's no big deal here, but you think they would have send something.\\n\\n\\n\" + \\\n", + " \"John Smith\\n\" + \\\n", + " \"123-456-7890\\n\"\n", + "\n", + "# convert string data to list to feed into the labeler\n", + "data = [data]" + ] + }, + { + "cell_type": "markdown", + "id": "concerned-segment", + "metadata": {}, + "source": [ + "By default, the Labeler predicts the results at the character level for unstructured text." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "junior-acrobat", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "labeler = dp.DataLabeler(labeler_type='unstructured')\n", + "\n", + "# make predictions and get labels per character\n", + "predictions = labeler.predict(data)\n", + "\n", + "# display results\n", + "print(predictions['pred'])" + ] + }, + { + "cell_type": "markdown", + "id": "individual-diabetes", + "metadata": {}, + "source": [ + "In addition to the character-level result, the Labeler provides the results at the word level following the standard NER (Named Entity Recognition), e.g., utilized by spaCy. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "optical-universe", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# convert prediction to word format and ner format\n", + "# Set the output to the NER format (start position, end position, label)\n", + "labeler.set_params(\n", + " { 'postprocessor': { 'output_format':'ner', 'use_word_level_argmax':True } } \n", + ")\n", + "\n", + "# make predictions and get labels per character\n", + "predictions = labeler.predict(data)\n", + "\n", + "# display results\n", + "print('\\n')\n", + "print('=======================Prediction======================\\n')\n", + "for pred in predictions['pred'][0]:\n", + " print('{}: {}'.format(data[0][pred[0]: pred[1]], pred[2]))\n", + " print('--------------------------------------------------------')" + ] + }, + { + "cell_type": "markdown", + "id": "behavioral-tourism", + "metadata": {}, + "source": [ + "Here, the Labeler is able to identify sensitive information such as datetime, email address, person names, and phone number in an email sample. " + ] + }, + { + "cell_type": "markdown", + "id": "nasty-disney", + "metadata": {}, + "source": [ + "## Train the Labeler from Scratch" + ] + }, + { + "cell_type": "markdown", + "id": "destroyed-twist", + "metadata": {}, + "source": [ + "The Labeler can be trained from scratch with a new list of labels. Below, we show an example of training the Labeler on a dataset with labels given as the columns of that dataset. For brevity's sake, let's only train a few epochs with a subset of a dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "utility-evaluation", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "data = dp.Data(\"../dataprofiler/tests/data/csv/SchoolDataSmall.csv\")\n", + "df = data.data[[\"OPEID6\", \"INSTURL\", \"SEARCH_STRING\"]]\n", + "df.head()\n", + "\n", + "# split data to training and test set\n", + "split_ratio = 0.2\n", + "df = df.sample(frac=1).reset_index(drop=True)\n", + "data_train = df[:int((1 - split_ratio) * len(df))]\n", + "data_test = df[int((1 - split_ratio) * len(df)):]\n", + "\n", + "# train a new labeler with column names as labels\n", + "if not os.path.exists('data_labeler_saved'):\n", + " os.makedirs('data_labeler_saved')\n", + "\n", + "labeler = dp.train_structured_labeler(\n", + " data=data_train,\n", + " save_dirpath=\"data_labeler_saved\",\n", + " epochs=10,\n", + " default_label=\"OPEID6\"\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "utility-torture", + "metadata": {}, + "source": [ + "The trained Labeler is then used by the Data Profiler to provide the prediction on the new dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "answering-panel", + "metadata": {}, + "outputs": [], + "source": [ + "# predict with the labeler object\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_object': labeler})\n", + "profile = dp.Profiler(data_test, options=profile_options)\n", + "\n", + "# get the prediction from the data profiler\n", + "results = profile.report()\n", + "print(get_structured_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "polish-stand", + "metadata": {}, + "source": [ + "Another way to use the trained Labeler is through the directory path of the saved labeler." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "industrial-characterization", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# predict with the labeler loaded from path\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_dirpath': 'data_labeler_saved'})\n", + "profile = dp.Profiler(data_test, options=profile_options)\n", + "\n", + "# get the prediction from the data profiler\n", + "results = profile.report()\n", + "print(get_structured_results(results))" + ] + }, + { + "cell_type": "markdown", + "id": "2acedba0", + "metadata": {}, + "source": [ + "## Transfer Learning a Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "2f15fb1f", + "metadata": {}, + "source": [ + "Instead of training a model from scratch, we can also transfer learn to improve the model and/or extend the labels. Again for brevity's sake, let's only train a few epochs with a small dataset at the cost of accuracy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0104c374", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "data = dp.Data(\"../dataprofiler/tests/data/csv/SchoolDataSmall.csv\")\n", + "df_data = data.data[[\"OPEID6\", \"INSTURL\", \"SEARCH_STRING\"]]\n", + "\n", + "\n", + "# prep data\n", + "df_data = df_data.reset_index(drop=True).melt()\n", + "df_data.columns = [1, 0] # labels=1, values=0 in that order\n", + "df_data = df_data.astype(str)\n", + "new_labels = df_data[1].unique().tolist()\n", + "\n", + "# load structured Labeler w/ trainable set to True\n", + "labeler = dp.DataLabeler(labeler_type='structured', trainable=True)\n", + "\n", + "# Reconstruct the model to add each new label\n", + "for label in new_labels:\n", + " labeler.add_label(label)\n", + "\n", + "# this will use transfer learning to retrain the labeler on your new\n", + "# dataset and labels.\n", + "# Setting labels with a list of labels or label mapping will overwrite the existing labels with new ones\n", + "# Setting the reset_weights parameter to false allows transfer learning to occur\n", + "model_results = labeler.fit(x=df_data[0], y=df_data[1], validation_split=0.2, \n", + " epochs=10, labels=None, reset_weights=False)" + ] + }, + { + "cell_type": "markdown", + "id": "ae78745f", + "metadata": {}, + "source": [ + "Let's display the training results of the last epoch:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b764aa8c", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "print(\"{:16s} Precision Recall F1-score Support\".format(\"\"))\n", + "for item in model_results[-1][2]:\n", + " print(\"{:16s} {:4.3f} {:4.3f} {:4.3f} {:7.0f}\".format(item,\n", + " model_results[-1][2][item][\"precision\"],\n", + " model_results[-1][2][item][\"recall\"],\n", + " model_results[-1][2][item][\"f1-score\"],\n", + " model_results[-1][2][item][\"support\"]))" + ] + }, + { + "cell_type": "markdown", + "id": "44009522", + "metadata": {}, + "source": [ + "It is now trained to detect additional labels! The model results here show all the labels training accuracy. Since only new labels existed in the dataset, only the new labels are given accuracy scores. Keep in mind this is a small dataset for brevity's sake and that real training would involve more samples and better results." + ] + }, + { + "cell_type": "markdown", + "id": "e110ee1c", + "metadata": {}, + "source": [ + "## Saving and Loading a Labeler" + ] + }, + { + "cell_type": "markdown", + "id": "c484d193", + "metadata": {}, + "source": [ + "The Labeler can easily be saved or loaded with one simple line." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4d8684fa", + "metadata": {}, + "outputs": [], + "source": [ + "# Ensure save directory exists\n", + "if not os.path.exists('my_labeler'):\n", + " os.makedirs('my_labeler')\n", + "\n", + "# Saving the labeler\n", + "labeler.save_to_disk(\"my_labeler\")\n", + "\n", + "# Loading the labeler\n", + "labeler = dp.DataLabeler(labeler_type='structured', dirpath=\"my_labeler\")" + ] + }, + { + "cell_type": "markdown", + "id": "8d36dec8", + "metadata": {}, + "source": [ + "## Building a Labeler from the Ground Up" + ] + }, + { + "cell_type": "markdown", + "id": "59346d2b", + "metadata": {}, + "source": [ + "As mentioned earlier, the labeler is comprised of three components, and each of the compenents can be created and interchanged in the the labeler pipeline." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6506ef97", + "metadata": {}, + "outputs": [], + "source": [ + "import random\n", + "from dataprofiler.labelers.character_level_cnn_model import \\\n", + " CharacterLevelCnnModel\n", + "from dataprofiler.labelers.data_processing import \\\n", + " StructCharPreprocessor, StructCharPostprocessor\n", + "\n", + "model = CharacterLevelCnnModel({\"PAD\":0, \"UNKNOWN\":1, \"Test_Label\":2})\n", + "preprocessor = StructCharPreprocessor()\n", + "postprocessor = StructCharPostprocessor()\n", + "\n", + "labeler = dp.DataLabeler(labeler_type='structured')\n", + "labeler.set_preprocessor(preprocessor)\n", + "labeler.set_model(model)\n", + "labeler.set_postprocessor(postprocessor)\n", + "\n", + "# check for basic compatibility between the processors and the model\n", + "labeler.check_pipeline()\n", + "\n", + "# Optionally set the parameters\n", + "parameters={\n", + " 'preprocessor':{\n", + " 'max_length': 100,\n", + " },\n", + " 'model':{\n", + " 'max_length': 100,\n", + " },\n", + " 'postprocessor':{\n", + " 'random_state': random.Random(1)\n", + " }\n", + "} \n", + "labeler.set_params(parameters)\n", + "\n", + "labeler.help()" + ] + }, + { + "cell_type": "markdown", + "id": "5f020d7f", + "metadata": {}, + "source": [ + "The components can each be created if you inherit the BaseModel and BaseProcessor for the model and processors, respectively. More info can be found about coding your own components in the Labeler section of the [documentation]( https://capitalone.github.io/dataprofiler). In summary, the Data Profiler open source library can be used to scan sensitive information in both structured and unstructured data with different file types. It supports multiple input formats and output formats at word and character levels. Users can also train the labeler on their own datasets." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/merge_profile_list.html b/docs/0.10.3/html/merge_profile_list.html new file mode 100644 index 000000000..1e00b4cb4 --- /dev/null +++ b/docs/0.10.3/html/merge_profile_list.html @@ -0,0 +1,637 @@ + + + + + + + + + Merge List of Profiles - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Merge List of Profiles

    +

    This is an example of a new utils in the dataprofiler for distributed merging of profile objects. This assumes the user is providing a list of profile objects to the utils function for merging all the profiles together.

    +
    +

    Imports

    +

    Let’s start by importing the necessary packages…

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +
    +import pandas as pd
    +import tensorflow as tf
    +
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +    from dataprofiler.profilers.utils import merge_profile_list
    +except ImportError:
    +    import dataprofiler as dp
    +    from dataprofiler.profilers.utils import merge_profile_list
    +
    +# remove extra tf loggin
    +tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
    +
    +
    +
    +
    +
    +

    Setup the Data and Profiler

    +

    This section shows the basic example of the Data Profiler.

    +
      +
    1. Instantiate a Pandas dataframe with dummy data

    2. +
    3. Pass the dataframe to the Profiler and instantiate two separate profilers in a list

    4. +
    +
    +
    [ ]:
    +
    +
    +
    +d = {'col1': [1, 2], 'col2': [3, 4]}
    +df = pd.DataFrame(data=d)
    +
    +list_of_profiles = [dp.Profiler(df), dp.Profiler(df)]
    +
    +
    +
    +

    Take a look at the list of profiles…

    +
    +
    [ ]:
    +
    +
    +
    +list_of_profiles
    +
    +
    +
    +
    +
    +

    Run Merge on List of Profiles

    +

    Now let’s merge the list of profiles into a single_profile

    +
    +
    [ ]:
    +
    +
    +
    +single_profile = merge_profile_list(list_of_profiles=list_of_profiles)
    +
    +
    +
    +

    And check out the .report on the single profile:

    +
    +
    [ ]:
    +
    +
    +
    +single_profile.report()
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/merge_profile_list.ipynb b/docs/0.10.3/html/merge_profile_list.ipynb new file mode 100644 index 000000000..4654caf8f --- /dev/null +++ b/docs/0.10.3/html/merge_profile_list.ipynb @@ -0,0 +1,159 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "60af5256", + "metadata": {}, + "source": [ + "# Merge List of Profiles\n", + "\n", + "This is an example of a new utils in the dataprofiler for distributed merging of profile objects. This assumes the user is providing a list of profile objects to the utils function for merging all the profiles together." + ] + }, + { + "cell_type": "markdown", + "id": "7eee37ff", + "metadata": {}, + "source": [ + "## Imports\n", + "\n", + "Let's start by importing the necessary packages..." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f0d27009", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "\n", + "import pandas as pd\n", + "import tensorflow as tf\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + " from dataprofiler.profilers.utils import merge_profile_list\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + " from dataprofiler.profilers.utils import merge_profile_list\n", + "\n", + "# remove extra tf loggin\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "markdown", + "id": "b4369e64", + "metadata": {}, + "source": [ + "## Setup the Data and Profiler" + ] + }, + { + "cell_type": "markdown", + "id": "410c3c4d", + "metadata": {}, + "source": [ + "This section shows the basic example of the Data Profiler. \n", + "\n", + "1. Instantiate a Pandas dataframe with dummy data\n", + "2. Pass the dataframe to the `Profiler` and instantiate two separate profilers in a list" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3567c82", + "metadata": {}, + "outputs": [], + "source": [ + "d = {'col1': [1, 2], 'col2': [3, 4]}\n", + "df = pd.DataFrame(data=d)\n", + "\n", + "list_of_profiles = [dp.Profiler(df), dp.Profiler(df)]" + ] + }, + { + "cell_type": "markdown", + "id": "350502eb", + "metadata": {}, + "source": [ + "Take a look at the list of profiles... " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b649db32", + "metadata": {}, + "outputs": [], + "source": [ + "list_of_profiles" + ] + }, + { + "cell_type": "markdown", + "id": "4ed4fc12", + "metadata": {}, + "source": [ + "## Run Merge on List of Profiles\n", + "\n", + "Now let's merge the list of profiles into a `single_profile`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4a636047", + "metadata": {}, + "outputs": [], + "source": [ + "single_profile = merge_profile_list(list_of_profiles=list_of_profiles)" + ] + }, + { + "cell_type": "markdown", + "id": "0aa88720", + "metadata": {}, + "source": [ + "And check out the `.report` on the single profile:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34059c21", + "metadata": {}, + "outputs": [], + "source": [ + "single_profile.report()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "dataprofiler", + "language": "python", + "name": "dataprofiler" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/modules.html b/docs/0.10.3/html/modules.html new file mode 100644 index 000000000..a9a66b9c5 --- /dev/null +++ b/docs/0.10.3/html/modules.html @@ -0,0 +1,298 @@ + + + + + + + + + dataprofiler - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    + + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/objects.inv b/docs/0.10.3/html/objects.inv new file mode 100644 index 0000000000000000000000000000000000000000..53f79437e014c996dd800c00e58244e07498cc82 GIT binary patch literal 28981 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 bk+1KXAHyFOMtB9C``{|;FB~s|5bys1uvX_i literal 0 HcmV?d00001 diff --git a/docs/0.10.3/html/overview.html b/docs/0.10.3/html/overview.html new file mode 100644 index 000000000..908079612 --- /dev/null +++ b/docs/0.10.3/html/overview.html @@ -0,0 +1,848 @@ + + + + + + + + + Data Profiler - What’s in your data? - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Data Profiler - What’s in your data?

    +

    This introductory jupyter notebook demonstrates the basic usages of the Data Profiler. The library is designed to easily detect sensitive data and gather statistics on your datasets with just several lines of code. The Data Profiler can handle several different data types including: CSV (or any delimited file), JSON, Parquet, AVRO, and text. Additionally, there are a plethora of options to customize your profile. This library also has the ability to update profiles from multiple batches of large +datasets, or merge multiple profiles. In particular, this example covers the followings:

    +
      +
    • Basic usage of the Data Profiler

    • +
    • The data reader class

    • +
    • Profiler options

    • +
    • Updating profiles and merging profiles

    • +
    +

    First, let’s import the libraries needed for this example.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +import pandas as pd
    +import matplotlib.pyplot as plt
    +sys.path.insert(0, '..')
    +import dataprofiler as dp
    +
    +data_path = "../dataprofiler/tests/data"
    +
    +
    +
    +
    +

    Basic Usage of the Data Profiler

    +

    This section shows the basic example of the Data Profiler. A CSV dataset is read using the data reader, then the Data object is given to the Data Profiler to detect sensitive data and obtain the statistics.

    +
    +
    [ ]:
    +
    +
    +
    +# use data reader to read input data
    +data = dp.Data(os.path.join(data_path, "csv/aws_honeypot_marx_geo.csv"))
    +print(data.data.head())
    +
    +# run data profiler and get the report
    +profile = dp.Profiler(data)
    +report  = profile.report(report_options={"output_format":"compact"})
    +
    +# print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    The report includes global_stats and data_stats for the given dataset. The former contains overall properties of the data such as number of rows/columns, null ratio, duplicate ratio, while the latter contains specific properties and statistics for each column such as detected data label, min, max, mean, variance, etc. In this example, the compact format of the report is used to shorten the full list of the results. To get more results related to detailed predictions at the entity +level from the Data Labeler component or histogram results, the format pretty should be used.

    +
    +
    +

    Data reader class

    +

    DataProfiler can detect multiple file types including CSV (or any delimited file), JSON, Parquet, AVRO, and text. The example below shows that it successfully detects data types from multiple categories regardless of the file extensions.

    +
    +
    [ ]:
    +
    +
    +
    +# use data reader to read input data with different file types
    +csv_files = [
    +    "csv/aws_honeypot_marx_geo.csv",
    +    "csv/all-strings-skip-header-author.csv", # csv files with the author/description on the first line
    +    "csv/sparse-first-and-last-column-empty-first-row.txt", # csv file with the .txt extension
    +]
    +json_files = [
    +    "json/complex_nested.json",
    +    "json/honeypot_intentially_mislabeled_file.csv", # json file with the .csv extension
    +]
    +parquet_files = [
    +    "parquet/nation.dict.parquet",
    +    "parquet/nation.plain.intentionally_mislabled_file.csv", # parquet file with the .csv extension
    +]
    +avro_files = [
    +    "avro/userdata1.avro",
    +    "avro/userdata1_intentionally_mislabled_file.json", # avro file with the .json extension
    +]
    +text_files = [
    +    "txt/discussion_reddit.txt",
    +]
    +
    +all_files = {
    +    "csv": csv_files,
    +    "json": json_files,
    +    "parquet": parquet_files,
    +    "avro": avro_files,
    +    "text": text_files
    +}
    +
    +for file_type in all_files:
    +    print(file_type)
    +    for file in all_files[file_type]:
    +        data = dp.Data(os.path.join(data_path, file))
    +        print("{:<85} {:<15}".format(file, data.data_type))
    +    print("\n")
    +
    +
    +
    +

    The Data class detects the file type and uses one of the following classes: CSVData, JSONData, ParquetData, AVROData, TextData. Users can call these specific classes directly if desired. For example, below we provide a collection of data with different types, each of them is processed by the corresponding data class.

    +
    +
    [ ]:
    +
    +
    +
    +# use individual data reader classes
    +from dataprofiler.data_readers.csv_data import CSVData
    +from dataprofiler.data_readers.json_data import JSONData
    +from dataprofiler.data_readers.parquet_data import ParquetData
    +from dataprofiler.data_readers.avro_data import AVROData
    +from dataprofiler.data_readers.text_data import TextData
    +
    +csv_files = "csv/aws_honeypot_marx_geo.csv"
    +json_files = "json/complex_nested.json"
    +parquet_files = "parquet/nation.dict.parquet"
    +avro_files = "avro/userdata1.avro"
    +text_files = "txt/discussion_reddit.txt"
    +
    +all_files = {
    +    "csv": [csv_files, CSVData],
    +    "json": [json_files, JSONData],
    +    "parquet": [parquet_files, ParquetData],
    +    "avro": [avro_files, AVROData],
    +    "text": [text_files, TextData],
    +}
    +
    +for file_type in all_files:
    +    file, data_reader = all_files[file_type]
    +    data = data_reader(os.path.join(data_path, file))
    +    print("File name {}\n".format(file))
    +    if file_type == "text":
    +        print(data.data[0][:1000]) # print the first 1000 characters
    +    else:
    +        print(data.data)
    +    print('===============================================================================')
    +
    +
    +
    +

    In addition to reading the input data from multiple file types, the Data Profiler allows the input data as a dataframe.

    +
    +
    [ ]:
    +
    +
    +
    +# run data profiler and get the report
    +my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]], columns=["col_int", "col_float"])
    +profile = dp.Profiler(my_dataframe)
    +report  = profile.report(report_options={"output_format":"compact"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Structured Profiler vs. Unstructured Profiler

    +

    The profiler will infer what type of statistics to generate (structured or unstructured) based on the input. However, you can explicitly specify profile type as well. Here is an example of the the profiler explicitly calling the structured profile and the unstructured profile.

    +
    +
    [ ]:
    +
    +
    +
    +# Using the structured profiler
    +data = dp.Data(os.path.join(data_path, "csv/aws_honeypot_marx_geo.csv"))
    +profile = dp.Profiler(data, profiler_type='structured')
    +
    +report = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +# Using the unstructured profiler
    +my_dataframe = pd.DataFrame([["Sample1"],["Sample2"],["Sample3"]], columns=["Text_Samples"])
    +profile = dp.Profiler(my_dataframe, profiler_type='unstructured')
    +
    +report  = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Profiler options

    +

    The Data Profiler can enable/disable statistics and modify features through profiler options. For example, if the users only want the statistics information, they may turn off the Data Labeler functionality. Below, let’s remove the histogram and data labeler component while running Data Profiler.

    +
    +
    [ ]:
    +
    +
    +
    +profile_options = dp.ProfilerOptions()
    +profile_options.set({"histogram_and_quantiles.is_enabled": False,
    +                     "median_abs_deviation.is_enabled": False,
    +                     "median.is_enabled": False,
    +                     "mode.is_enabled": False,
    +                     "data_labeler.is_enabled": False,})
    +
    +profile = dp.Profiler(my_dataframe, options=profile_options)
    +report  = profile.report(report_options={"output_format":"pretty"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    Besides toggling on and off features, other options like the data labeler sample size or histogram bin method can be directly set and validated as shown here:

    +
    +
    [ ]:
    +
    +
    +
    +profile_options = dp.ProfilerOptions()
    +profile_options.structured_options.data_labeler.sample_size = 1
    +profile_options.structured_options.int.histogram_and_quantiles.bin_count_or_method = "rice"
    +# An error will raise if the options are set incorrectly.
    +profile_options.validate()
    +
    +profile = dp.Profiler(my_dataframe, options=profile_options)
    +report  = profile.report(report_options={"output_format":"pretty"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Update profiles

    +

    One of the interesting features of the Data Profiler is the ability to update profiles from batches of data, which allows for data streaming usage. In this section, the original dataset is separated into two batches with equal size. Each batch is then updated with Data Profiler sequentially.

    +

    After the update, we expect the resulted profiles give the same statistics as the profiles updated from the full dataset. We will verify that through some properties in global_stats of the profiles including column_count, row_count, row_is_null_ratio, duplicate_row_count.

    +
    +
    [ ]:
    +
    +
    +
    +# read the input data and devide it into two equal halves
    +data = dp.Data(os.path.join(data_path, "csv/aws_honeypot_marx_geo.csv"))
    +df = data.data
    +df1 = df.iloc[:int(len(df)/2)]
    +df2 = df.iloc[int(len(df)/2):]
    +
    +# Update the profile with the first half
    +profile = dp.Profiler(df1)
    +
    +# Update the profile with the second half
    +profile.update_profile(df2)
    +
    +# Update profile with the full dataset
    +profile_full = dp.Profiler(df)
    +
    +report  = profile.report(report_options={"output_format":"compact"})
    +report_full  = profile_full.report(report_options={"output_format":"compact"})
    +
    +# print the report
    +print(json.dumps(report, indent=4))
    +print(json.dumps(report_full, indent=4))
    +
    +
    +
    +

    You can see that the profiles are exactly the same whether they are broken into several updates or not.

    +
    +
    +

    Merge profiles

    +

    In addition to the profile update, Data Profiler provides the merging functionality which allows users to combine the profiles updated from multiple locations. This enables Data Profiler to be used in a distributed computing environment. Below, we assume that the two aforementioned halves of the original dataset come from two different machines. Each of them is then updated with the Data Profiler on the same machine, then the resulted profiles are merged.

    +

    As with the profile update, we expect the merged profiles give the same statistics as the profiles updated from the full dataset.

    +
    +
    [ ]:
    +
    +
    +
    +# Update the profile with the first half
    +profile1 = dp.Profiler(df1)
    +
    +# Update the profile with the second half
    +profile2 = dp.Profiler(df2)
    +
    +# merge profiles
    +profile_merge = profile1 + profile2
    +
    +# check results of the merged profile
    +report_merge  = profile.report(report_options={"output_format":"compact"})
    +
    +# print the report
    +print(json.dumps(report_merge, indent=4))
    +print(json.dumps(report_full, indent=4))
    +
    +
    +
    +

    You can see that the profiles are exactly the same!

    +
    +
    +

    Conclusion

    +

    We have walked through some basic examples of Data Profiler usage, with different input data types and profiling options. We also work with update and merging functionality of the Data Profiler, which make it applicable for data streaming and distributed environment. Interested users can try with different datasets and functionalities as desired.

    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/overview.ipynb b/docs/0.10.3/html/overview.ipynb new file mode 100644 index 000000000..d5e77abe4 --- /dev/null +++ b/docs/0.10.3/html/overview.ipynb @@ -0,0 +1,470 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "fc2826d9", + "metadata": {}, + "source": [ + "# Data Profiler - What's in your data?" + ] + }, + { + "cell_type": "markdown", + "id": "b997522b", + "metadata": {}, + "source": [ + "This introductory jupyter notebook demonstrates the basic usages of the Data Profiler. The library is designed to easily detect sensitive data and gather statistics on your datasets with just several lines of code. The Data Profiler can handle several different data types including: CSV (or any delimited file), JSON, Parquet, AVRO, and text. Additionally, there are a plethora of options to customize your profile. This library also has the ability to update profiles from multiple batches of large datasets, or merge multiple profiles. In particular, this example covers the followings:\n", + "\n", + "- Basic usage of the Data Profiler\n", + "- The data reader class\n", + "- Profiler options\n", + "- Updating profiles and merging profiles\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ef404c84", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "import pandas as pd\n", + "import matplotlib.pyplot as plt\n", + "sys.path.insert(0, '..')\n", + "import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"" + ] + }, + { + "cell_type": "markdown", + "id": "f51971e3", + "metadata": {}, + "source": [ + "## Basic Usage of the Data Profiler" + ] + }, + { + "cell_type": "markdown", + "id": "639e66d3", + "metadata": {}, + "source": [ + "This section shows the basic example of the Data Profiler. A CSV dataset is read using the data reader, then the Data object is given to the Data Profiler to detect sensitive data and obtain the statistics." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5379c45c", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# use data reader to read input data\n", + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "print(data.data.head())\n", + "\n", + "# run data profiler and get the report\n", + "profile = dp.Profiler(data)\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "57fe2827", + "metadata": {}, + "source": [ + "The report includes `global_stats` and `data_stats` for the given dataset. The former contains overall properties of the data such as number of rows/columns, null ratio, duplicate ratio, while the latter contains specific properties and statistics for each column such as detected data label, min, max, mean, variance, etc. In this example, the `compact` format of the report is used to shorten the full list of the results. To get more results related to detailed predictions at the entity level from the Data Labeler component or histogram results, the format `pretty` should be used." + ] + }, + { + "cell_type": "markdown", + "id": "74027cfd", + "metadata": {}, + "source": [ + "## Data reader class" + ] + }, + { + "cell_type": "markdown", + "id": "41364888", + "metadata": {}, + "source": [ + "DataProfiler can detect multiple file types including CSV (or any delimited file), JSON, Parquet, AVRO, and text. The example below shows that it successfully detects data types from multiple categories regardless of the file extensions." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "823829f4", + "metadata": {}, + "outputs": [], + "source": [ + "# use data reader to read input data with different file types\n", + "csv_files = [\n", + " \"csv/aws_honeypot_marx_geo.csv\",\n", + " \"csv/all-strings-skip-header-author.csv\", # csv files with the author/description on the first line\n", + " \"csv/sparse-first-and-last-column-empty-first-row.txt\", # csv file with the .txt extension\n", + "]\n", + "json_files = [\n", + " \"json/complex_nested.json\",\n", + " \"json/honeypot_intentially_mislabeled_file.csv\", # json file with the .csv extension\n", + "]\n", + "parquet_files = [\n", + " \"parquet/nation.dict.parquet\",\n", + " \"parquet/nation.plain.intentionally_mislabled_file.csv\", # parquet file with the .csv extension\n", + "]\n", + "avro_files = [\n", + " \"avro/userdata1.avro\",\n", + " \"avro/userdata1_intentionally_mislabled_file.json\", # avro file with the .json extension\n", + "]\n", + "text_files = [\n", + " \"txt/discussion_reddit.txt\",\n", + "]\n", + "\n", + "all_files = {\n", + " \"csv\": csv_files,\n", + " \"json\": json_files,\n", + " \"parquet\": parquet_files,\n", + " \"avro\": avro_files,\n", + " \"text\": text_files\n", + "}\n", + "\n", + "for file_type in all_files:\n", + " print(file_type)\n", + " for file in all_files[file_type]:\n", + " data = dp.Data(os.path.join(data_path, file))\n", + " print(\"{:<85} {:<15}\".format(file, data.data_type))\n", + " print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "3f9d7e02", + "metadata": {}, + "source": [ + "The `Data` class detects the file type and uses one of the following classes: `CSVData`, `JSONData`, `ParquetData`, `AVROData`, `TextData`. Users can call these specific classes directly if desired. For example, below we provide a collection of data with different types, each of them is processed by the corresponding data class." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "831e68a3", + "metadata": {}, + "outputs": [], + "source": [ + "# use individual data reader classes\n", + "from dataprofiler.data_readers.csv_data import CSVData\n", + "from dataprofiler.data_readers.json_data import JSONData\n", + "from dataprofiler.data_readers.parquet_data import ParquetData\n", + "from dataprofiler.data_readers.avro_data import AVROData\n", + "from dataprofiler.data_readers.text_data import TextData\n", + "\n", + "csv_files = \"csv/aws_honeypot_marx_geo.csv\"\n", + "json_files = \"json/complex_nested.json\"\n", + "parquet_files = \"parquet/nation.dict.parquet\"\n", + "avro_files = \"avro/userdata1.avro\"\n", + "text_files = \"txt/discussion_reddit.txt\"\n", + "\n", + "all_files = {\n", + " \"csv\": [csv_files, CSVData],\n", + " \"json\": [json_files, JSONData],\n", + " \"parquet\": [parquet_files, ParquetData],\n", + " \"avro\": [avro_files, AVROData],\n", + " \"text\": [text_files, TextData],\n", + "}\n", + "\n", + "for file_type in all_files:\n", + " file, data_reader = all_files[file_type]\n", + " data = data_reader(os.path.join(data_path, file))\n", + " print(\"File name {}\\n\".format(file))\n", + " if file_type == \"text\":\n", + " print(data.data[0][:1000]) # print the first 1000 characters\n", + " else:\n", + " print(data.data)\n", + " print('===============================================================================')" + ] + }, + { + "cell_type": "markdown", + "id": "572df0a8", + "metadata": {}, + "source": [ + "In addition to reading the input data from multiple file types, the Data Profiler allows the input data as a dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df87ab83", + "metadata": {}, + "outputs": [], + "source": [ + "# run data profiler and get the report\n", + "my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]], columns=[\"col_int\", \"col_float\"])\n", + "profile = dp.Profiler(my_dataframe)\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "84a06312", + "metadata": {}, + "source": [ + "## Structured Profiler vs. Unstructured Profiler" + ] + }, + { + "cell_type": "markdown", + "id": "4c0ea925", + "metadata": {}, + "source": [ + "The profiler will infer what type of statistics to generate (structured or unstructured) based on the input. However, you can explicitly specify profile type as well. Here is an example of the the profiler explicitly calling the structured profile and the unstructured profile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5f4565d8", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# Using the structured profiler\n", + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "profile = dp.Profiler(data, profiler_type='structured')\n", + "\n", + "report = profile.report(report_options={\"output_format\": \"pretty\"})\n", + "print(json.dumps(report, indent=4))\n", + "\n", + "# Using the unstructured profiler\n", + "my_dataframe = pd.DataFrame([[\"Sample1\"],[\"Sample2\"],[\"Sample3\"]], columns=[\"Text_Samples\"])\n", + "profile = dp.Profiler(my_dataframe, profiler_type='unstructured')\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "b16648ba", + "metadata": {}, + "source": [ + "## Profiler options" + ] + }, + { + "cell_type": "markdown", + "id": "8b0cc8ad", + "metadata": {}, + "source": [ + "The Data Profiler can enable/disable statistics and modify features through profiler options. For example, if the users only want the statistics information, they may turn off the Data Labeler functionality. Below, let's remove the histogram and data labeler component while running Data Profiler." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bbac3a2c", + "metadata": {}, + "outputs": [], + "source": [ + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({\"histogram_and_quantiles.is_enabled\": False,\n", + " \"median_abs_deviation.is_enabled\": False,\n", + " \"median.is_enabled\": False,\n", + " \"mode.is_enabled\": False,\n", + " \"data_labeler.is_enabled\": False,})\n", + "\n", + "profile = dp.Profiler(my_dataframe, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "590ca50b", + "metadata": {}, + "source": [ + "Besides toggling on and off features, other options like the data labeler sample size or histogram bin method can be directly set and validated as shown here:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4ed21bc1", + "metadata": {}, + "outputs": [], + "source": [ + "profile_options = dp.ProfilerOptions()\n", + "profile_options.structured_options.data_labeler.sample_size = 1\n", + "profile_options.structured_options.int.histogram_and_quantiles.bin_count_or_method = \"rice\"\n", + "# An error will raise if the options are set incorrectly.\n", + "profile_options.validate()\n", + "\n", + "profile = dp.Profiler(my_dataframe, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "9f690616", + "metadata": {}, + "source": [ + "## Update profiles" + ] + }, + { + "cell_type": "markdown", + "id": "965f8c85", + "metadata": {}, + "source": [ + "One of the interesting features of the Data Profiler is the ability to update profiles from batches of data, which allows for data streaming usage. In this section, the original dataset is separated into two batches with equal size. Each batch is then updated with Data Profiler sequentially. \n", + "\n", + "After the update, we expect the resulted profiles give the same statistics as the profiles updated from the full dataset. We will verify that through some properties in `global_stats` of the profiles including `column_count`, `row_count`, `row_is_null_ratio`, `duplicate_row_count`. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34ac4346", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# read the input data and devide it into two equal halves\n", + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "df = data.data\n", + "df1 = df.iloc[:int(len(df)/2)]\n", + "df2 = df.iloc[int(len(df)/2):]\n", + "\n", + "# Update the profile with the first half\n", + "profile = dp.Profiler(df1)\n", + "\n", + "# Update the profile with the second half\n", + "profile.update_profile(df2)\n", + "\n", + "# Update profile with the full dataset\n", + "profile_full = dp.Profiler(df)\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "report_full = profile_full.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# print the report\n", + "print(json.dumps(report, indent=4))\n", + "print(json.dumps(report_full, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "b41ee2bf", + "metadata": {}, + "source": [ + "You can see that the profiles are exactly the same whether they are broken into several updates or not." + ] + }, + { + "cell_type": "markdown", + "id": "c547f051", + "metadata": {}, + "source": [ + "## Merge profiles" + ] + }, + { + "cell_type": "markdown", + "id": "a5292962", + "metadata": {}, + "source": [ + "In addition to the profile update, Data Profiler provides the merging functionality which allows users to combine the profiles updated from multiple locations. This enables Data Profiler to be used in a distributed computing environment. Below, we assume that the two aforementioned halves of the original dataset come from two different machines. Each of them is then updated with the Data Profiler on the same machine, then the resulted profiles are merged.\n", + "\n", + "As with the profile update, we expect the merged profiles give the same statistics as the profiles updated from the full dataset." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a565b8d1", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Update the profile with the first half\n", + "profile1 = dp.Profiler(df1)\n", + "\n", + "# Update the profile with the second half\n", + "profile2 = dp.Profiler(df2)\n", + "\n", + "# merge profiles\n", + "profile_merge = profile1 + profile2\n", + "\n", + "# check results of the merged profile\n", + "report_merge = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# print the report\n", + "print(json.dumps(report_merge, indent=4))\n", + "print(json.dumps(report_full, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "b77fac3f", + "metadata": {}, + "source": [ + "You can see that the profiles are exactly the same!" + ] + }, + { + "cell_type": "markdown", + "id": "c644ee42", + "metadata": {}, + "source": [ + "## Conclusion\n", + "\n", + "We have walked through some basic examples of Data Profiler usage, with different input data types and profiling options. We also work with update and merging functionality of the Data Profiler, which make it applicable for data streaming and distributed environment. Interested users can try with different datasets and functionalities as desired." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/popmon_dp_loader_example.html b/docs/0.10.3/html/popmon_dp_loader_example.html new file mode 100644 index 000000000..348ac53c3 --- /dev/null +++ b/docs/0.10.3/html/popmon_dp_loader_example.html @@ -0,0 +1,803 @@ + + + + + + + + + Dataloader with Popmon Reports - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Dataloader with Popmon Reports

    +

    This demo is to cover the usage of popmon with the dataloader from the dataprofiler

    +

    This demo covers the followings:

    +
    - How to install popmon
    +- Comparison of the dynamic dataloader from dataprofiler to the
    +    standard dataloader used in pandas
    +- Popmon's usage example using both dataloaders
    +- Dataprofiler's examples using both dataloaders
    +- Usage of the pm_stability_report function (popmon reports)
    +
    +
    +
    +

    How to Install Popmon

    +

    To install popmon you can use the command below:

    +

    pip3 install popmon

    +

    From here, we can import the libararies needed for this demo.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +except ImportError:
    +    import dataprofiler as dp
    +import pandas as pd
    +import popmon  # noqa
    +
    +
    +
    +
    +
    +

    Comparison of Dataloaders

    +

    First, we have the original pandas dataloading which works for specific file types. This is good for if the data format is known ahead of time but is less useful for more dynamic cases.

    +
    +
    [ ]:
    +
    +
    +
    +def popmon_dataloader(path, time_index):
    +    # Load pm dataframe (Can only read csvs unless reader option is changed)
    +    if not time_index is None:
    +        pm_data = pd.read_csv(path, parse_dates=[time_index])
    +    else:
    +        time_index = True
    +        pm_data = pd.read_csv(path)
    +    return pm_data
    +
    +
    +
    +

    Next, we have the dataprofiler’s dataloader. This allows for the dynamic loading of different data formats which is super useful when the data format is not know ahead of time. This is intended to be an improvement on the dataloader standardly used in pandas.

    +
    +
    [ ]:
    +
    +
    +
    +def dp_dataloader(path):
    +    # Datalaoder from dataprofiler used
    +    dp_data = dp.Data(path)
    +
    +    # Profiler used to ensure proper label for datetime even
    +    # when null values exist
    +    profiler_options = dp.ProfilerOptions()
    +    profiler_options.set({'*.is_enabled': False,  # Runs first disabling all options in profiler
    +                          '*.datetime.is_enabled': True})
    +    profile = dp.Profiler(dp_data, options=profiler_options)
    +
    +    # convert any time/datetime types from strings to actual datatime type
    +    for ind, col in enumerate(dp_data.data.columns):
    +        if profile.profile[ind].profile.get('data_type') == 'datetime':
    +            dp_data.data[col] = pd.to_datetime(dp_data.data[col])
    +
    +    return dp_data.data
    +
    +
    +
    +
    +
    +

    Popmon’s usage example using both dataloaders

    +

    Next, we’ll download a dataset from the resources component

    +
    +
    [ ]:
    +
    +
    +
    +import gzip
    +import shutil
    +popmon_tutorial_data = popmon.resources.data("flight_delays.csv.gz")
    +with gzip.open(popmon_tutorial_data, 'rb') as f_in:
    +    with open('./flight_delays.csv', 'wb') as f_out:
    +        shutil.copyfileobj(f_in, f_out)
    +
    +
    +
    +

    Finally we read in the data with popmon and print the report to a file

    +
    +
    [ ]:
    +
    +
    +
    +# Default csv from popmon example
    +path = "./flight_delays.csv"
    +time_index = "DATE"
    +report_output_dir = "./popmon_output/flight_delays_full"
    +if not os.path.exists(report_output_dir):
    +    os.makedirs(report_output_dir)
    +
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pm_data = popmon_dataloader(path, time_index)
    +
    +report_pm_loader = pm_data.pm_stability_report(
    +    time_axis=time_index,
    +    time_width="1w",
    +    time_offset="2015-07-02",
    +    extended_report=False,
    +    pull_rules={"*_pull": [10, 7, -7, -10]},
    +)
    +
    +# Save popmon reports
    +report_pm_loader.to_file(os.path.join(report_output_dir, "popmon_loader_report.html"))
    +print("Report printed at:", os.path.join(report_output_dir, "popmon_loader_report.html"))
    +
    +
    +
    +

    We then do the same for the dataprofiler loader

    +
    +
    [ ]:
    +
    +
    +
    +dp_dataframe = dp_dataloader(path)
    +# Generate pm report using dp dataloader
    +report_dp_loader = dp_dataframe.pm_stability_report(
    +    time_axis=time_index,
    +    time_width="1w",
    +    time_offset="2015-07-02",
    +    extended_report=False,
    +    pull_rules={"*_pull": [10, 7, -7, -10]},
    +)
    +
    +# Save popmon reports
    +report_dp_loader.to_file(os.path.join(report_output_dir, "dataprofiler_loader_report.html"))
    +print("Report printed at:", os.path.join(report_output_dir, "dataprofiler_loader_report.html"))
    +
    +
    +
    +
    +
    +

    Examples of data

    +

    Next, We’ll use some data from the test files of the data profiler to compare the dynamic loading of the dataprofiler’s data loader to that of the standard pandas approach.

    +
    +
    +

    Dataprofiler’s examples using both dataloaders

    +

    To execute this properly, simply choose one of the 3 examples below and then run the report generation below.

    +
    +
    [ ]:
    +
    +
    +
    +# Default csv from popmon example (mini version)
    +path = "../dataprofiler/tests/data/csv/flight_delays.csv"
    +time_index = "DATE"
    +report_output_dir = "./popmon_output/flight_delays_mini"
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# Random csv from dataprofiler tests
    +path = "../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv"
    +time_index = "datetime"
    +report_output_dir = "./popmon_output/aws_honeypot_marx_geo"
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# Random json file from dataprofiler tests
    +path = "../dataprofiler/tests/data/json/math.json"
    +
    +time_index = "data.9"
    +report_output_dir = "./popmon_output/math"
    +
    +
    +
    +

    Run the block below to create an output directory for your popmon reports.

    +
    +
    [ ]:
    +
    +
    +
    +if not os.path.exists(report_output_dir):
    +    os.makedirs(report_output_dir)
    +dp_dataframe = dp_dataloader(path)
    +
    +
    +
    +
    +
    +

    Report comparison

    +

    We generate reports using different sets of data from the dataprofiler and pandas below using dataprofiler’s dataloader and popmons report generator

    +

    The dataprofiler’s dataloader can seemlessly switch between data formats and generate reports with the exact same code in place.

    +
    +
    [ ]:
    +
    +
    +
    +# Generate pm report using dp dataloader
    +report_dp_loader = dp_dataframe.pm_stability_report(
    +    time_axis=time_index,
    +    time_width="1w",
    +    time_offset="2015-07-02",
    +    extended_report=False,
    +    pull_rules={"*_pull": [10, 7, -7, -10]},
    +)
    +
    +
    +
    +

    If the dataloaders are valid, you can see the reports and compare them at the output directory specified in the printout below each report generation block (the two code blocks below).

    +
    +
    [ ]:
    +
    +
    +
    +# Save dp reports
    +report_dp_loader.to_file(os.path.join(report_output_dir, "dataprofiler_loader_report.html"))
    +print("Report printed at:", os.path.join(report_output_dir, "dataprofiler_loader_report.html"))
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/popmon_dp_loader_example.ipynb b/docs/0.10.3/html/popmon_dp_loader_example.ipynb new file mode 100644 index 000000000..3ddb267da --- /dev/null +++ b/docs/0.10.3/html/popmon_dp_loader_example.ipynb @@ -0,0 +1,416 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7f0cceea", + "metadata": {}, + "source": [ + "# Dataloader with Popmon Reports" + ] + }, + { + "cell_type": "markdown", + "id": "9e79d9c5", + "metadata": {}, + "source": [ + "This demo is to cover the usage of popmon with the dataloader from the dataprofiler\n", + "\n", + "This demo covers the followings:\n", + "\n", + " - How to install popmon\n", + " - Comparison of the dynamic dataloader from dataprofiler to the \n", + " standard dataloader used in pandas\n", + " - Popmon's usage example using both dataloaders\n", + " - Dataprofiler's examples using both dataloaders\n", + " - Usage of the pm_stability_report function (popmon reports)\n" + ] + }, + { + "cell_type": "markdown", + "id": "aec2198a", + "metadata": {}, + "source": [ + "## How to Install Popmon\n", + "To install popmon you can use the command below:" + ] + }, + { + "cell_type": "markdown", + "id": "4383ed2a", + "metadata": {}, + "source": [ + "`pip3 install popmon`\n" + ] + }, + { + "cell_type": "markdown", + "id": "91dedc34", + "metadata": {}, + "source": [ + "From here, we can import the libararies needed for this demo." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2adec556", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "import pandas as pd\n", + "import popmon # noqa" + ] + }, + { + "cell_type": "markdown", + "id": "2ed532ec", + "metadata": {}, + "source": [ + "## Comparison of Dataloaders" + ] + }, + { + "cell_type": "markdown", + "id": "cccbf4cd", + "metadata": {}, + "source": [ + "First, we have the original pandas dataloading which works for specific file types. \n", + "This is good for if the data format is known ahead of time but is less useful for more dynamic cases." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "96e9ff89", + "metadata": {}, + "outputs": [], + "source": [ + "def popmon_dataloader(path, time_index):\n", + " # Load pm dataframe (Can only read csvs unless reader option is changed)\n", + " if not time_index is None:\n", + " pm_data = pd.read_csv(path, parse_dates=[time_index])\n", + " else:\n", + " time_index = True\n", + " pm_data = pd.read_csv(path)\n", + " return pm_data" + ] + }, + { + "cell_type": "markdown", + "id": "16dfbe10", + "metadata": {}, + "source": [ + "Next, we have the dataprofiler's dataloader. This allows for the dynamic loading of different data formats which is super useful when the data format is not know ahead of time.\n", + "This is intended to be an improvement on the dataloader standardly used in pandas." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "07481259", + "metadata": {}, + "outputs": [], + "source": [ + "def dp_dataloader(path):\n", + " # Datalaoder from dataprofiler used\n", + " dp_data = dp.Data(path)\n", + " \n", + " # Profiler used to ensure proper label for datetime even \n", + " # when null values exist\n", + " profiler_options = dp.ProfilerOptions()\n", + " profiler_options.set({'*.is_enabled': False, # Runs first disabling all options in profiler\n", + " '*.datetime.is_enabled': True})\n", + " profile = dp.Profiler(dp_data, options=profiler_options)\n", + "\n", + " # convert any time/datetime types from strings to actual datatime type\n", + " for ind, col in enumerate(dp_data.data.columns):\n", + " if profile.profile[ind].profile.get('data_type') == 'datetime':\n", + " dp_data.data[col] = pd.to_datetime(dp_data.data[col])\n", + "\n", + " return dp_data.data" + ] + }, + { + "cell_type": "markdown", + "id": "69a8ea9b", + "metadata": {}, + "source": [ + "## Popmon's usage example using both dataloaders" + ] + }, + { + "cell_type": "markdown", + "id": "ff914ca7", + "metadata": {}, + "source": [ + "Next, we'll download a dataset from the resources component" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bff33da8", + "metadata": {}, + "outputs": [], + "source": [ + "import gzip\n", + "import shutil\n", + "popmon_tutorial_data = popmon.resources.data(\"flight_delays.csv.gz\")\n", + "with gzip.open(popmon_tutorial_data, 'rb') as f_in:\n", + " with open('./flight_delays.csv', 'wb') as f_out:\n", + " shutil.copyfileobj(f_in, f_out)" + ] + }, + { + "cell_type": "markdown", + "id": "19222c4a", + "metadata": {}, + "source": [ + "Finally we read in the data with popmon and print the report to a file" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0090a2f3", + "metadata": {}, + "outputs": [], + "source": [ + "# Default csv from popmon example\n", + "path = \"./flight_delays.csv\"\n", + "time_index = \"DATE\"\n", + "report_output_dir = \"./popmon_output/flight_delays_full\"\n", + "if not os.path.exists(report_output_dir):\n", + " os.makedirs(report_output_dir)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d0abcd9b", + "metadata": {}, + "outputs": [], + "source": [ + "pm_data = popmon_dataloader(path, time_index)\n", + "\n", + "report_pm_loader = pm_data.pm_stability_report(\n", + " time_axis=time_index,\n", + " time_width=\"1w\",\n", + " time_offset=\"2015-07-02\",\n", + " extended_report=False,\n", + " pull_rules={\"*_pull\": [10, 7, -7, -10]},\n", + ")\n", + "\n", + "# Save popmon reports\n", + "report_pm_loader.to_file(os.path.join(report_output_dir, \"popmon_loader_report.html\"))\n", + "print(\"Report printed at:\", os.path.join(report_output_dir, \"popmon_loader_report.html\"))" + ] + }, + { + "cell_type": "markdown", + "id": "2303b5cf", + "metadata": {}, + "source": [ + "We then do the same for the dataprofiler loader" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f2854383", + "metadata": {}, + "outputs": [], + "source": [ + "dp_dataframe = dp_dataloader(path)\n", + "# Generate pm report using dp dataloader\n", + "report_dp_loader = dp_dataframe.pm_stability_report(\n", + " time_axis=time_index,\n", + " time_width=\"1w\",\n", + " time_offset=\"2015-07-02\",\n", + " extended_report=False,\n", + " pull_rules={\"*_pull\": [10, 7, -7, -10]},\n", + ")\n", + "\n", + "# Save popmon reports\n", + "report_dp_loader.to_file(os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))\n", + "print(\"Report printed at:\", os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))" + ] + }, + { + "cell_type": "markdown", + "id": "8cc4e5f3", + "metadata": {}, + "source": [ + "## Examples of data\n", + "Next, We'll use some data from the test files of the data profiler to compare the dynamic loading of the dataprofiler's data loader to that of the standard pandas approach. \n" + ] + }, + { + "cell_type": "markdown", + "id": "352eaeea", + "metadata": {}, + "source": [ + "## Dataprofiler's examples using both dataloaders" + ] + }, + { + "cell_type": "markdown", + "id": "e99af913", + "metadata": {}, + "source": [ + "To execute this properly, simply choose one of the 3 examples below and then run the report generation below." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "80eb601d", + "metadata": {}, + "outputs": [], + "source": [ + "# Default csv from popmon example (mini version)\n", + "path = \"../dataprofiler/tests/data/csv/flight_delays.csv\"\n", + "time_index = \"DATE\"\n", + "report_output_dir = \"./popmon_output/flight_delays_mini\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0c127288", + "metadata": {}, + "outputs": [], + "source": [ + "# Random csv from dataprofiler tests\n", + "path = \"../dataprofiler/tests/data/csv/aws_honeypot_marx_geo.csv\"\n", + "time_index = \"datetime\"\n", + "report_output_dir = \"./popmon_output/aws_honeypot_marx_geo\"" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6cd5c385", + "metadata": {}, + "outputs": [], + "source": [ + "# Random json file from dataprofiler tests\n", + "path = \"../dataprofiler/tests/data/json/math.json\"\n", + "\n", + "time_index = \"data.9\"\n", + "report_output_dir = \"./popmon_output/math\"" + ] + }, + { + "cell_type": "markdown", + "id": "ec860cb7", + "metadata": {}, + "source": [ + "Run the block below to create an output directory for your popmon reports." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cf21835c", + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.exists(report_output_dir):\n", + " os.makedirs(report_output_dir)\n", + "dp_dataframe = dp_dataloader(path)" + ] + }, + { + "cell_type": "markdown", + "id": "479975a5", + "metadata": {}, + "source": [ + "## Report comparison" + ] + }, + { + "cell_type": "markdown", + "id": "02a355e7", + "metadata": {}, + "source": [ + "We generate reports using different sets of data from the dataprofiler and pandas below using dataprofiler's dataloader and popmons report generator\n" + ] + }, + { + "cell_type": "markdown", + "id": "6ce69145", + "metadata": {}, + "source": [ + "The dataprofiler's dataloader can seemlessly switch between data formats and generate reports with the exact same code in place." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a0dcb405", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "# Generate pm report using dp dataloader\n", + "report_dp_loader = dp_dataframe.pm_stability_report(\n", + " time_axis=time_index,\n", + " time_width=\"1w\",\n", + " time_offset=\"2015-07-02\",\n", + " extended_report=False,\n", + " pull_rules={\"*_pull\": [10, 7, -7, -10]},\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "9eb0035c", + "metadata": {}, + "source": [ + "If the dataloaders are valid, you can see the reports and compare them at the output directory specified in the printout below each report generation block (the two code blocks below)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "efe7d8d6", + "metadata": {}, + "outputs": [], + "source": [ + "# Save dp reports\n", + "report_dp_loader.to_file(os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))\n", + "print(\"Report printed at:\", os.path.join(report_output_dir, \"dataprofiler_loader_report.html\"))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/profiler.html b/docs/0.10.3/html/profiler.html new file mode 100644 index 000000000..0ed23a4ab --- /dev/null +++ b/docs/0.10.3/html/profiler.html @@ -0,0 +1,1409 @@ + + + + + + + + + Profiler - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +

    Profiler

    +
    +

    Profile Your Data

    +

    Profiling your data is easy. Just use the data reader, send the data to the +profiler, and print out the report.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +data = Data("your_file.csv") # Auto-Detect & Load: CSV, AVRO, Parquet, JSON, Text
    +
    +profile = Profiler(data) # Calculate Statistics, Entity Recognition, etc
    +
    +readable_report = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(readable_report, indent=4))
    +
    +
    +

    If the data is structured, the profile will return global statistics as well as +column by column statistics. The vast amount of statistics are listed on the +intro page.

    +
    +

    Load a File

    +

    The profiler should automatically identify the file type and load the data into a Data Class.

    +

    Along with other attributtes the Data class enables structured data to be accessed via a valid Pandas DataFrame.

    +
    # Load a csv file, return a CSVData object
    +csv_data = Data('your_file.csv')
    +
    +# Print the first 10 rows of the csv file
    +print(csv_data.data.head(10))
    +
    +# Load a parquet file, return a ParquetData object
    +parquet_data = Data('your_file.parquet')
    +
    +# Sort the data by the name column
    +parquet_data.data.sort_values(by='name', inplace=True)
    +
    +# Print the sorted first 10 rows of the parquet data
    +print(parquet_data.data.head(10))
    +
    +
    +

    If the file type is not automatically identified (rare), you can specify them +specifically, see section Data Readers.

    +
    +
    +

    Profile a File

    +

    Example uses a CSV file for example, but CSV, JSON, Avro or Parquet should also work.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load file (CSV should be automatically identified)
    +data = Data("your_file.csv")
    +
    +# Profile the dataset
    +profile = Profiler(data)
    +
    +# Generate a report and use json to prettify.
    +report  = profile.report(report_options={"output_format": "pretty"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Updating Profiles

    +

    Currently, the data profiler is equipped to update its profile in batches.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load and profile a CSV file
    +data = Data("your_file.csv")
    +profile = Profiler(data)
    +
    +# Update the profile with new data:
    +new_data = Data("new_data.csv")
    +profile.update_profile(new_data)
    +
    +# Print the report using json to prettify.
    +report  = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Merging Profiles

    +

    If you have two files with the same schema (but different data), it is possible to merge the two profiles together via an addition operator.

    +

    This also enables profiles to be determined in a distributed manner.

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load a CSV file with a schema
    +data1 = Data("file_a.csv")
    +profile1 = Profiler(data)
    +
    +# Load another CSV file with the same schema
    +data2 = Data("file_b.csv")
    +profile2 = Profiler(data)
    +
    +profile3 = profile1 + profile2
    +
    +# Print the report using json to prettify.
    +report  = profile3.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +

    Profile Differences

    +

    Profile differences take two profiles and find the differences +between them. Create the difference report like this:

    +
    from dataprofiler import Data, Profiler
    +
    +# Load a CSV file
    +data1 = Data("file_a.csv")
    +profile1 = Profiler(data)
    +
    +# Load another CSV file
    +data2 = Data("file_b.csv")
    +profile2 = Profiler(data)
    +
    +diff_report = profile1.diff(profile2)
    +print(diff_report)
    +
    +
    +

    The .diff() operation is available between two profiles, although there are different +outputs depending on the type of profile being differenced. For example, for numerical +column profiles (e.g. integers and floats), two valuable calculations that +.diff() returns are t-test, chi2-test, and psi (Popoulation Stability Index) +for understanding distributional changes.

    +

    The difference report contains a dictionary that mirrors the profile report. +Each data type has its own difference:

    +
      +
    • Int/Float - One profile subtracts the value from the other.

    • +
    • String - The strings will be shown in a list:

      +
        +
      • [profile1 str, profile2 str]

      • +
      +
    • +
    • List - A list of 3 will be returned showing the unique values of +each profile and the shared values:

      +
        +
      • [profile 1 unique values, shared values, profile 2 unique values]

      • +
      +
    • +
    • Dict - Some dictionaries with varied keys will also return a list +of three in the format:

      +
        +
      • [profile 1 unique key-values, shared key differences, profile 2 unique key-values]

      • +
      +
    • +
    +

    Otherwise, when no differences occur:

    +
      +
    • Any Type No Differences - A string will report: “unchanged”.

    • +
    +

    Below is the structured difference report:

    +
    {
    +    'global_stats': {
    +        'file_type': [str, str],
    +        'encoding': [str, str],
    +        'samples_used': int,
    +        'column_count': int,
    +        'row_count': int,
    +        'row_has_null_ratio': float,
    +        'row_is_null_ratio': float,
    +        'unique_row_ratio': float,
    +        'duplicate_row_count': int,
    +        'correlation_matrix': list[list[float]],
    +        'chi2_matrix': list[list[float]],
    +        'profile_schema': list[dict[str, int]]
    +    },
    +    'data_stats': [{
    +        'column_name': str,
    +        'data_type': [str, str],
    +        'data_label': [list[str], list[str], list[str]],
    +        'categorical': [str, str],
    +        'order': [str, str],
    +        'statistics': {
    +            'min': float,
    +            'max': float,
    +            'sum': float,
    +            'mean': float,
    +            'median': float,
    +            'mode': [list[float], list[float], list[float]],
    +            'median_absolute_deviation': float,
    +            'variance': float,
    +            'stddev': float,
    +            't-test': {
    +                't-statistic': float,
    +                'conservative': {'df': int,
    +                                 'p-value': float},
    +                'welch': {'df': float,
    +                          'p-value': float}},
    +            'psi': float,
    +            "chi2-test": {
    +                "chi2-statistic": float,
    +                "df": int,
    +                "p-value": float
    +            },
    +            'unique_count': int,
    +            'unique_ratio': float,
    +            'categories': [list[str], list[str], list[str]],
    +            'gini_impurity': float,
    +            'unalikeability': float,
    +            'categorical_count': [dict[str, int], dict[str, int], dict[str, int]],
    +            'avg_predictions': [dict[str, float]],
    +            'label_representation': [dict[str, float]],
    +            'sample_size': int,
    +            'null_count': int,
    +            'null_types': [list[str], list[str], list[str]],
    +            'null_types_index': [dict[str, int], dict[str, int], dict[str, int]],
    +            'data_type_representation': [dict[str, float]]
    +        },
    +        "null_replication_metrics": {
    +            "class_prior": list[int],
    +            "class_sum": list[list[int]],
    +            "class_mean": list[list[int]]
    +        }
    +    }
    +
    +
    +

    Below is the unstructured difference report:

    +
    {
    +    'global_stats': {
    +        'file_type': [str, str],
    +        'encoding': [str, str],
    +        'samples_used': int,
    +        'empty_line_count': int,
    +        'memory_size': float
    +    },
    +    'data_stats': {
    +        'data_label': {
    +            'entity_counts': {
    +                'word_level': dict[str, int],
    +                'true_char_level': dict[str, int],
    +                'postprocess_char_level': dict[str, int]
    +            },
    +            'entity_percentages': {
    +                'word_level': dict[str, float],
    +                'true_char_level': dict[str, float],
    +                'postprocess_char_level': dict[str, float]
    +            }
    +        },
    +        'statistics': {
    +            'vocab': [list[str], list[str], list[str]],
    +            'vocab_count': [dict[str, int], dict[str, int], dict[str, int]],
    +            'words': [list[str], list[str], list[str]],
    +            'word_count': [dict[str, int], dict[str, int], dict[str, int]]
    +        }
    +    }
    +}
    +
    +
    +
    +
    +

    Saving and Loading a Profile

    +

    The profiles can easily be saved and loaded as shown below:

    +

    NOTE: Json saving and loading only supports Structured Profiles currently.

    +

    There are two save/load methods:

    +
      +
    • Pickle save/load

      +
        +
      • Save a profile as a .pkl file.

      • +
      • Load a .pkl file as a profile object.

      • +
      +
    • +
    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load a CSV file, with "," as the delimiter
    +data = Data("your_file.csv")
    +
    +# Read data into profile
    +profile = Profiler(data)
    +
    +# save structured profile to pkl file
    +profile.save(filepath="my_profile.pkl")
    +
    +# load pkl file to structured profile
    +loaded_pkl_profile = dp.Profiler.load(filepath="my_profile.pkl")
    +
    +print(json.dumps(loaded_pkl_profile.report(report_options={"output_format": "compact"}),
    +                                       indent=4))
    +
    +
    +
      +
    • Json save/load

      +
        +
      • Save a profile as a human-readable .json file.

      • +
      • Load a .json file as a profile object.

      • +
      +
    • +
    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Load a CSV file, with "," as the delimiter
    +data = Data("your_file.csv")
    +
    +# Read data into profile
    +profile = Profiler(data)
    +
    +# save structured profile to json file
    +profile.save(filepath="my_profile.json", save_method="json")
    +
    +# load json file to structured profile
    +loaded_json_profile = dp.Profiler.load(filepath="my_profile.json", load_method="json")
    +
    +print(json.dumps(loaded_json_profile.report(report_options={"output_format": "compact"}),
    +                                       indent=4))
    +
    +
    +
    +
    +

    Structured vs Unstructured Profiles

    +

    When using the profiler, the data profiler will automatically infer whether to +create the structured profile or the unstructured profile. However, you can be +explicit as shown below:

    +
    import json
    +from dataprofiler import Data, Profiler
    +
    +# Creating a structured profile
    +data1 = Data("normal_csv_file.csv")
    +structured_profile = Profiler(data1, profiler_type="structured")
    +
    +structured_report = structured_profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(structured_report, indent=4))
    +
    +# Creating an unstructured profile
    +data2 = Data("normal_text_file.txt")
    +unstructured_profile = Profiler(data2, profiler_type="unstructured")
    +
    +unstructured_report = unstructured_profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(unstructured_report, indent=4))
    +
    +
    +
    +
    +

    Setting the Sample Size

    +

    There are two ways to set sample size in a profile: samples_per_update and +min_true_samples. Samples_per_update takes an integer as the exact amount that +will be sampled. Min_true_samples will set the minimum amount of samples that +are not null. For example:

    +
    from dataprofiler import Profiler
    +
    +sample_array = [1.0, NULL, 2.0]
    +profile = dp.Profiler(sample_array, samples_per_update=2)
    +
    +
    +

    The first two samples (1.0 and NULL) are used for the statistical analysis.

    +

    In contrast, if we also set min_true_samples to 2 then the Data Reader will +continue to read until the minimum true samples were found for the given column. +For example:

    +
    from dataprofiler import Profiler
    +
    +sample_array = [1.0, NULL, 2.0]
    +profile = dp.Profiler(sample_array, samples_per_update=2, min_true_samples=2)
    +
    +
    +

    This will use all samples in the statistical analysis until the number of “true” +(non-NULL) values are reached. Both min_true_samples and +samples_per_update conditions must be met. In this case, the profile will grab +the first two samples (1.0 and NULL) to satisfy the samples_per_update, and then +it will grab the first two VALID samples (1.0 and 2.0) to satisfy the +min_true_samples.

    +
    +
    +

    Profile a Pandas DataFrame

    +
    import pandas as pd
    +import dataprofiler as dp
    +import json
    +
    +my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]])
    +profile = dp.Profiler(my_dataframe)
    +
    +# print the report using json to prettify.
    +report = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +# read a specified column, in this case it is labeled 0:
    +print(json.dumps(report["data stats"][0], indent=4))
    +
    +
    +
    +
    +

    Specifying a Filetype or Delimiter

    +

    Example of specifying a CSV data type, with a , delimiter. +In addition, it utilizes only the first 10,000 rows.

    +
    import json
    +from dataprofiler import Data, Profiler
    +from dataprofiler.data_readers.csv_data import CSVData
    +
    +# Load a CSV file, with "," as the delimiter
    +data = CSVData("your_file.csv", options={"delimiter": ","})
    +
    +# Split the data, such that only the first 10,000 rows are used
    +data = data.data[0:10000]
    +
    +# Read in profile and print results
    +profile = Profiler(data)
    +print(json.dumps(profile.report(report_options={"output_format": "pretty"}), indent=4))
    +
    +
    +
    +
    +

    Setting Profiler Seed

    +

    Example of specifying a seed for reproducibility.

    +
    import dataprofiler as dp
    +
    +# Set seed to non-negative integer value or None
    +dp.set_seed(0)
    +
    +
    +
    +
    +
    +

    Profile Statistic Descriptions

    +
    +

    Structured Profile

    +

    global_stats:

    +
      +
    • samples_used - number of input data samples used to generate this profile

    • +
    • column_count - the number of columns contained in the input dataset

    • +
    • row_count - the number of rows contained in the input dataset

    • +
    • row_has_null_ratio - the proportion of rows that contain at least one null value to the total number of rows

    • +
    • row_is_null_ratio - the proportion of rows that are fully comprised of null values (null rows) to the total number of rows

    • +
    • unique_row_ratio - the proportion of distinct rows in the input dataset to the total number of rows

    • +
    • duplicate_row_count - the number of rows that occur more than once in the input dataset

    • +
    • file_type - the format of the file containing the input dataset (ex: .csv)

    • +
    • encoding - the encoding of the file containing the input dataset (ex: UTF-8)

    • +
    • correlation_matrix - matrix of shape column_count x column_count containing the correlation coefficients between each column in the dataset

    • +
    • chi2_matrix - matrix of shape column_count x column_count containing the chi-square statistics between each column in the dataset

    • +
    • +
      profile_schema - a description of the format of the input dataset labeling each column and its index in the dataset
        +
      • string - the label of the column in question and its index in the profile schema

      • +
      +
      +
      +
    • +
    • times - the duration of time it took to generate the global statistics for this dataset in milliseconds

    • +
    +

    data_stats:

    +
      +
    • column_name - the label/title of this column in the input dataset

    • +
    • data_type - the primitive python data type that is contained within this column

    • +
    • data_label - the label/entity of the data in this column as determined by the Labeler component

    • +
    • categorical - ‘true’ if this column contains categorical data

    • +
    • order - the way in which the data in this column is ordered, if any, otherwise “random”

    • +
    • samples - a small subset of data entries from this column

    • +
    • +
      statistics - statistical information on the column
        +
      • sample_size - number of input data samples used to generate this profile

      • +
      • null_count - the number of null entries in the sample

      • +
      • null_types - a list of the different null types present within this sample

      • +
      • null_types_index - a dict containing each null type and a respective list of the indicies that it is present within this sample

      • +
      • data_type_representation - the percentage of samples used identifying as each data_type

      • +
      • min - minimum value in the sample

      • +
      • max - maximum value in the sample

      • +
      • mode - mode of the entries in the sample

      • +
      • median - median of the entries in the sample

      • +
      • median_absolute_deviation - the median absolute deviation of the entries in the sample

      • +
      • sum - the total of all sampled values from the column

      • +
      • mean - the average of all entries in the sample

      • +
      • variance - the variance of all entries in the sample

      • +
      • stddev - the standard deviation of all entries in the sample

      • +
      • skewness - the statistical skewness of all entries in the sample

      • +
      • kurtosis - the statistical kurtosis of all entries in the sample

      • +
      • num_zeros - the number of entries in this sample that have the value 0

      • +
      • num_negatives - the number of entries in this sample that have a value less than 0

      • +
      • +
        histogram - contains histogram relevant information
          +
        • bin_counts - the number of entries within each bin

        • +
        • bin_edges - the thresholds of each bin

        • +
        +
        +
        +
      • +
      • quantiles - the value at each percentile in the order they are listed based on the entries in the sample

      • +
      • vocab - a list of the characters used within the entries in this sample

      • +
      • avg_predictions - average of the data label prediction confidences across all data points sampled

      • +
      • categories - a list of each distinct category within the sample if categorial = ‘true’

      • +
      • unique_count - the number of distinct entries in the sample

      • +
      • unique_ratio - the proportion of the number of distinct entries in the sample to the total number of entries in the sample

      • +
      • categorical_count - number of entries sampled for each category if categorical = ‘true’

      • +
      • gini_impurity - measure of how often a randomly chosen element from the set would be incorrectly labeled if it was randomly labeled according to the distribution of labels in the subset

      • +
      • unalikeability - a value denoting how frequently entries differ from one another within the sample

      • +
      • precision - a dict of statistics with respect to the number of digits in a number for each sample

      • +
      • times - the duration of time it took to generate this sample’s statistics in milliseconds

      • +
      • format - list of possible datetime formats

      • +
      +
      +
      +
    • +
    • +
      null_replication_metrics - statistics of data partitioned based on whether column value is null (index 1 of lists referenced by dict keys) or not (index 0)
        +
      • class_prior - a list containing probability of a column value being null and not null

      • +
      • class_sum - a list containing sum of all other rows based on whether column value is null or not

      • +
      • class_mean - a list containing mean of all other rows based on whether column value is null or not

      • +
      +
      +
      +
    • +
    +
    +
    +

    Unstructured Profile

    +

    global_stats:

    +
      +
    • samples_used - number of input data samples used to generate this profile

    • +
    • empty_line_count - the number of empty lines in the input data

    • +
    • file_type - the file type of the input data (ex: .txt)

    • +
    • encoding - file encoding of the input data file (ex: UTF-8)

    • +
    • memory_size - size of the input data in MB

    • +
    • times - duration of time it took to generate this profile in milliseconds

    • +
    +

    data_stats:

    +
      +
    • +
      data_label - labels and statistics on the labels of the input data
        +
      • +
        entity_counts - the number of times a specific label or entity appears inside the input data
          +
        • word_level - the number of words counted within each label or entity

        • +
        • true_char_level - the number of characters counted within each label or entity as determined by the model

        • +
        • postprocess_char_level - the number of characters counted within each label or entity as determined by the postprocessor

        • +
        +
        +
        +
      • +
      • +
        entity_percentages - the percentages of each label or entity within the input data
          +
        • word_level - the percentage of words in the input data that are contained within each label or entity

        • +
        • true_char_level - the percentage of characters in the input data that are contained within each label or entity as determined by the model

        • +
        • postprocess_char_level - the percentage of characters in the input data that are contained within each label or entity as determined by the postprocessor

        • +
        +
        +
        +
      • +
      • times - the duration of time it took for the data labeler to predict on the data

      • +
      +
      +
      +
    • +
    • +
      statistics - statistics of the input data
        +
      • vocab - a list of each character in the input data

      • +
      • vocab_count - the number of occurrences of each distinct character in the input data

      • +
      • words - a list of each word in the input data

      • +
      • word_count - the number of occurrences of each distinct word in the input data

      • +
      • times - the duration of time it took to generate the vocab and words statistics in milliseconds

      • +
      +
      +
      +
    • +
    +
    +
    +

    Graph Profile

    +
      +
    • num_nodes - number of nodes in the graph

    • +
    • num_edges - number of edges in the graph

    • +
    • categorical_attributes - list of categorical edge attributes

    • +
    • continuous_attributes - list of continuous edge attributes

    • +
    • avg_node_degree - average degree of nodes in the graph

    • +
    • global_max_component_size: size of the global max component

    • +
    +

    continuous_distribution:

    +
      +
    • +
      <attribute_N>: name of N-th edge attribute in list of attributes
        +
      • name - name of distribution for attribute

      • +
      • scale - negative log likelihood used to scale and compare distributions

      • +
      • +
        properties - list of statistical properties describing the distribution
          +
        • [shape (optional), loc, scale, mean, variance, skew, kurtosis]

        • +
        +
        +
        +
      • +
      +
      +
      +
    • +
    +

    categorical_distribution:

    +
      +
    • +
      <attribute_N>: name of N-th edge attribute in list of attributes
        +
      • bin_counts: counts in each bin of the distribution histogram

      • +
      • bin_edges: edges of each bin of the distribution histogram

      • +
      +
      +
      +
    • +
    • times - duration of time it took to generate this profile in milliseconds

    • +
    +
    +
    +
    +

    Profile Options

    +

    The data profiler accepts several options to toggle on and off +features. The 8 columns (int options, float options, datetime options, +text options, order options, category options, data labeler options) can be +enabled or disabled. By default, all options are toggled on. Below is an example +of how to alter these options. Options shared by structured and unstructured options +must be specified as structured or unstructured when setting (ie. datalabeler options).

    +
    import json
    +from dataprofiler import Data, Profiler, ProfilerOptions
    +
    +# Load and profile a CSV file
    +data = Data("your_file.csv")
    +profile_options = ProfilerOptions()
    +
    +#All of these are different examples of adjusting the profile options
    +
    +# Options can be toggled directly like this:
    +profile_options.structured_options.text.is_enabled = False
    +profile_options.structured_options.text.vocab.is_enabled = True
    +profile_options.structured_options.int.variance.is_enabled = True
    +profile_options.structured_options.data_labeler.data_labeler_dirpath = \
    +    "Wheres/My/Datalabeler"
    +profile_options.structured_options.data_labeler.is_enabled = False
    +
    +# A dictionary can be sent in to set the properties for all the options
    +profile_options.set({"structured_options.data_labeler.is_enabled": False, "min.is_enabled": False})
    +
    +# Specific columns can be set/disabled/enabled in the same way
    +profile_options.structured_options.text.set({"max.is_enabled":True,
    +                                         "variance.is_enabled": True})
    +
    +# numeric stats can be turned off/on entirely
    +profile_options.set({"is_numeric_stats_enabled": False})
    +profile_options.set({"int.is_numeric_stats_enabled": False})
    +
    +profile = Profiler(data, options=profile_options)
    +
    +# Print the report using json to prettify.
    +report  = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +

    Below is an breakdown of all the options.

    +
      +
    • ProfilerOptions - The top-level options class that contains options for the Profiler class

      +
        +
      • presets - A pre-configured mapping of a string name to group of options:

        +
          +
        • default is None

        • +
        • “complete”

        • +
        +
        options = ProfilerOptions(presets="complete")
        +
        +
        +
          +
        • “data_types”

        • +
        +
        options = ProfilerOptions(presets="data_types")
        +
        +
        +
          +
        • “numeric_stats_disabled”

        • +
        +
        options = ProfilerOptions(presets="numeric_stats_disabled")
        +
        +
        +
          +
        • “lower_memory_sketching”

        • +
        +
        options = ProfilerOptions(presets="lower_memory_sketching")
        +
        +
        +
      • +
      • structured_options - Options responsible for all structured data

        +
          +
        • multiprocess - Option to enable multiprocessing. If on, multiprocessing is toggled on if the dataset contains more than 750,000 rows or more than 20 columns. +Automatically selects the optimal number of pooling processes to utilize based on system constraints when toggled on.

          +
            +
          • is_enabled - (Boolean) Enables or disables multiprocessing

          • +
          +
        • +
        • sampling_ratio - A percentage, as a decimal, ranging from greater than 0 to less than or equal to 1 indicating how much input data to sample. Default value set to 0.2.

        • +
        • int - Options for the integer columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the integer operations

          • +
          • min - Finds minimum value in a column

          • +
          • is_enabled - (Boolean) Enables or disables min

          • +
          • max - Finds maximum value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables max

            • +
            +
          • +
          • mode - Finds mode(s) in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables mode

            • +
            • top_k_modes - (Int) Sets the number of modes to return if multiple exist. Default returns max 5 modes.

            • +
            +
          • +
          • median - Finds median value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables median

            • +
            +
          • +
          • sum - Finds sum of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables sum

            • +
            +
          • +
          • variance - Finds variance of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables variance

            • +
            +
          • +
          • skewness - Finds skewness of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables skewness

            • +
            +
          • +
          • kurtosis - Finds kurtosis of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables kurtosis

            • +
            +
          • +
          • median_abs_deviation - Finds median absolute deviation of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables median absolute deviation

            • +
            +
          • +
          • num_zeros - Finds the count of zeros in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables num_zeros

            • +
            +
          • +
          • num_negatives - Finds the count of negative numbers in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables num_negatives

            • +
            +
          • +
          • bias_correction - Applies bias correction to variance, skewness, and kurtosis calculations

            +
              +
            • is_enabled - (Boolean) Enables or disables bias correction

            • +
            +
          • +
          • histogram_and_quantiles - Generates a histogram and quantiles +from the column values

            +
              +
            • bin_count_or_method - (String/List[String]) Designates preferred method for calculating histogram bins or the number of bins to use. +If left unspecified (None) the optimal method will be chosen by attempting all methods. +If multiple specified (list) the optimal method will be chosen by attempting the provided ones. +methods: ‘auto’, ‘fd’, ‘doane’, ‘scott’, ‘rice’, ‘sturges’, ‘sqrt’ +Note: ‘auto’ is used to choose optimally between ‘fd’ and ‘sturges’

            • +
            • num_quantiles - (Int) Number of quantiles to bin the data. +Default value is set to 1,000 quantiles.

            • +
            • is_enabled - (Boolean) Enables or disables histogram and quantiles

            • +
            +
          • +
          +
        • +
        • float - Options for the float columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the float operations

          • +
          • precision - Finds the precision (significant figures) within the column

            +
              +
            • is_enabled - (Boolean) Enables or disables precision

            • +
            +
          • +
          • sample_ratio - (Float) The ratio of 0 to 1 how much data (identified as floats) to utilize as samples in determining precision

          • +
          • min - Finds minimum value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables min

            • +
            +
          • +
          • max - Finds maximum value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables max

            • +
            +
          • +
          • mode - Finds mode(s) in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables mode

            • +
            • top_k_modes - (Int) Sets the number of modes to return if multiple exist. Default returns max 5 modes.

            • +
            +
          • +
          • median - Finds median value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables median

            • +
            +
          • +
          • sum - Finds sum of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables sum

            • +
            +
          • +
          • variance - Finds variance of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables variance

            • +
            +
          • +
          • skewness - Finds skewness of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables skewness

            • +
            +
          • +
          • kurtosis - Finds kurtosis of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables kurtosis

            • +
            +
          • +
          • median_abs_deviation - Finds median absolute deviation of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables median absolute deviation

            • +
            +
          • +
          • is_numeric_stats_enabled - (Boolean) enable or disable all numeric stats

          • +
          • num_zeros - Finds the count of zeros in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables num_zeros

            • +
            +
          • +
          • num_negatives - Finds the count of negative numbers in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables num_negatives

            • +
            +
          • +
          • bias_correction - Applies bias correction to variance, skewness, and kurtosis calculations

            +
              +
            • is_enabled - (Boolean) Enables or disables bias correction

            • +
            +
          • +
          • histogram_and_quantiles - Generates a histogram and quantiles +from the column values

            +
              +
            • bin_count_or_method - (String/List[String]) Designates preferred method for calculating histogram bins or the number of bins to use. +If left unspecified (None) the optimal method will be chosen by attempting all methods. +If multiple specified (list) the optimal method will be chosen by attempting the provided ones. +methods: ‘auto’, ‘fd’, ‘doane’, ‘scott’, ‘rice’, ‘sturges’, ‘sqrt’ +Note: ‘auto’ is used to choose optimally between ‘fd’ and ‘sturges’

            • +
            • num_quantiles - (Int) Number of quantiles to bin the data. +Default value is set to 1,000 quantiles.

            • +
            • is_enabled - (Boolean) Enables or disables histogram and quantiles

            • +
            +
          • +
          +
        • +
        • text - Options for the text columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the text operations

          • +
          • vocab - Finds all the unique characters used in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables vocab

            • +
            +
          • +
          • min - Finds minimum value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables min

            • +
            +
          • +
          • max - Finds maximum value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables max

            • +
            +
          • +
          • mode - Finds mode(s) in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables mode

            • +
            • top_k_modes - (Int) Sets the number of modes to return if multiple exist. Default returns max 5 modes.

            • +
            +
          • +
          • median - Finds median value in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables median

            • +
            +
          • +
          • sum - Finds sum of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables sum

            • +
            +
          • +
          • variance - Finds variance of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables variance

            • +
            +
          • +
          • skewness - Finds skewness of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables skewness

            • +
            +
          • +
          • kurtosis - Finds kurtosis of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables kurtosis

            • +
            +
          • +
          • median_abs_deviation - Finds median absolute deviation of all values in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables median absolute deviation

            • +
            +
          • +
          • bias_correction - Applies bias correction to variance, skewness, and kurtosis calculations

            +
              +
            • is_enabled - (Boolean) Enables or disables bias correction

            • +
            +
          • +
          • is_numeric_stats_enabled - (Boolean) enable or disable all numeric stats

          • +
          • num_zeros - Finds the count of zeros in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables num_zeros

            • +
            +
          • +
          • num_negatives - Finds the count of negative numbers in a column

            +
              +
            • is_enabled - (Boolean) Enables or disables num_negatives

            • +
            +
          • +
          • histogram_and_quantiles - Generates a histogram and quantiles +from the column values

            +
              +
            • bin_count_or_method - (String/List[String]) Designates preferred method for calculating histogram bins or the number of bins to use. +If left unspecified (None) the optimal method will be chosen by attempting all methods. +If multiple specified (list) the optimal method will be chosen by attempting the provided ones. +methods: ‘auto’, ‘fd’, ‘doane’, ‘scott’, ‘rice’, ‘sturges’, ‘sqrt’ +Note: ‘auto’ is used to choose optimally between ‘fd’ and ‘sturges’

            • +
            • num_quantiles - (Int) Number of quantiles to bin the data. +Default value is set to 1,000 quantiles.

            • +
            • is_enabled - (Boolean) Enables or disables histogram and quantiles

            • +
            +
          • +
          +
        • +
        • datetime - Options for the datetime columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the datetime operations

          • +
          +
        • +
        • order - Options for the order columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the order operations

          • +
          +
        • +
        • category - Options for the category columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the category operations

          • +
          • top_k_categories - (int) Number of categories to be displayed when reporting

          • +
          • max_sample_size_to_check_stop_condition - (int) The maximum sample size before categorical stop conditions are checked

          • +
          • stop_condition_unique_value_ratio - (float) The highest ratio of unique values to dataset size that is to be considered a categorical type

          • +
          • cms - (Boolean) Enables or Disables the use of count min sketch / heavy hitters for approximate frequency counts

          • +
          • cms_confidence - (float) Defines the number of hashes used in CMS, default 0.95

          • +
          • cms_relative_error - (float) Defines the number of buckets used in CMS, default 0.01

          • +
          • cms_max_num_heavy_hitters - (int) The value used to define the threshold for minimum frequency required by a category to be counted

          • +
          +
        • +
        • data_labeler - Options for the data labeler columns

          +
            +
          • is_enabled - (Boolean) Enables or disables the data labeler operations

          • +
          • data_labeler_dirpath - (String) Directory path to data labeler

          • +
          • data_labeler_object - (BaseDataLabeler) Datalabeler to replace +the default labeler

          • +
          • max_sample_size - (Int) The max number of samples for the data +labeler

          • +
          +
        • +
        • correlation - Option set for correlation profiling +* is_enabled - (Boolean) Enables or disables performing correlation profiling +* columns - Columns considered to calculate correlation

        • +
        • row_statistics - (Boolean) Option to enable/disable row statistics calculations

          +
            +
          • unique_count - (UniqueCountOptions) Option to enable/disable unique row count calculations

            +
              +
            • is_enabled - (Bool) Enables or disables options for unique row count

            • +
            • hashing_method - (String) Property to specify row hashing method (“full” | “hll”)

            • +
            • hll - (HyperLogLogOptions) Options for alternative method of estimating unique row count (activated when hll is the selected hashing_method)

              +
                +
              • seed - (Int) Used to set HLL hashing function seed

              • +
              • register_count - (Int) Number of registers is equal to 2^register_count

              • +
              +
            • +
            +
          • +
          • null_count - (Boolean) Option to enable/disable functionalities for row_has_null_ratio and row_is_null_ratio

          • +
          +
        • +
        • chi2_homogeneity - Options for the chi-squared test matrix

          +
            +
          • is_enabled - (Boolean) Enables or disables performing chi-squared tests for homogeneity between the categorical columns of the dataset.

          • +
          +
        • +
        • null_replication_metrics - Options for calculating null replication metrics

          +
            +
          • is_enabled - (Boolean) Enables or disables calculation of null replication metrics

          • +
          +
        • +
        +
      • +
      • unstructured_options - Options responsible for all unstructured data

        +
          +
        • text - Options for the text profile

          +
            +
          • is_case_sensitive - (Boolean) Specify whether the profile is case sensitive

          • +
          • stop_words - (List of Strings) List of stop words to be removed when profiling

          • +
          • top_k_chars - (Int) Number of top characters to be retrieved when profiling

          • +
          • top_k_words - (Int) Number of top words to be retrieved when profiling

          • +
          • vocab - Options for vocab count

            +
              +
            • is_enabled - (Boolean) Enables or disables the vocab stats

            • +
            +
          • +
          • words - Options for word count

            +
              +
            • is_enabled - (Boolean) Enables or disables the word stats

            • +
            +
          • +
          +
        • +
        • data_labeler - Options for the data labeler

          +
            +
          • is_enabled - (Boolean) Enables or disables the data labeler operations

          • +
          • data_labeler_dirpath - (String) Directory path to data labeler

          • +
          • data_labeler_object - (BaseDataLabeler) Datalabeler to replace +the default labeler

          • +
          • max_sample_size - (Int) The max number of samples for the data +labeler

          • +
          +
        • +
        +
      • +
      +
    • +
    +
    +
    +

    Statistical Dependency on Order of Updates

    +

    Some profile features/statistics are dependent on the order in which the profiler +is updated with new data.

    +
    +

    Order Profile

    +

    The order profiler utilizes the last value in the previous data batch to ensure +the subsequent dataset is above/below/equal to that value when predicting +non-random order.

    +

    For instance, a dataset to be predicted as ascending would require the following +batch data update to be ascending and its first value >= than that of the +previous batch of data.

    +

    Ex. of ascending:

    +
    batch_1 = [0, 1, 2]
    +batch_2 = [3, 4, 5]
    +
    +
    +

    Ex. of random:

    +
    batch_1 = [0, 1, 2]
    +batch_2 = [1, 2, 3] # notice how the first value is less than the last value in the previous batch
    +
    +
    +
    +
    +
    +

    Reporting Structure

    +

    For every profile, we can provide a report and customize it with a couple optional parameters:

    +
      +
    • output_format (string)

      +
        +
      • This will allow the user to decide the output format for report.

        +
          +
        • Options are one of [pretty, compact, serializable, flat]:

          +
            +
          • Pretty: floats are rounded to four decimal places, and lists are shortened.

          • +
          • Compact: Similar to pretty, but removes detailed statistics such as runtimes, label probabilities, index locations of null types, etc.

          • +
          • Serializable: Output is json serializable and not prettified

          • +
          • Flat: Nested output is returned as a flattened dictionary

          • +
          +
        • +
        +
      • +
      +
    • +
    • num_quantile_groups (int)

      +
        +
      • You can sample your data as you like! With a minimum of one and a maximum of 1000, you can decide the number of quantile groups!

      • +
      +
    • +
    +
    report  = profile.report(report_options={"output_format": "pretty"})
    +report  = profile.report(report_options={"output_format": "compact"})
    +report  = profile.report(report_options={"output_format": "serializable"})
    +report  = profile.report(report_options={"output_format": "flat"})
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/profiler_example.html b/docs/0.10.3/html/profiler_example.html new file mode 100644 index 000000000..269f2365b --- /dev/null +++ b/docs/0.10.3/html/profiler_example.html @@ -0,0 +1,948 @@ + + + + + + + + + Structured Profilers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Structured Profilers

    +

    Data profiling - is the process of examining a dataset and collecting statistical or informational summaries about said dataset.

    +

    The Profiler class inside the DataProfiler is designed to generate data profiles via the Profiler class, which ingests either a Data class or a Pandas DataFrame.

    +

    Currently, the Data class supports loading the following file formats:

    +
      +
    • Any delimited (CSV, TSV, etc.)

    • +
    • JSON object

    • +
    • Avro

    • +
    • Parquet

    • +
    • Text files

    • +
    • Pandas Series/Dataframe

    • +
    +

    Once the data is loaded, the Profiler can calculate statistics and predict the entities (via the Labeler) of every column (csv) or key-value (JSON) store as well as dataset wide information, such as the number of nulls, duplicates, etc.

    +

    This example will look at specifically the structured data types for structured profiling.

    +
    +

    Reporting

    +

    One of the primary purposes of the Profiler are to quickly identify what is in the dataset. This can be useful for analyzing a dataset prior to use or determining which columns could be useful for a given purpose.

    +

    In terms of reporting, there are multiple reporting options:

    +
      +
    • Pretty: Floats are rounded to four decimal places, and lists are shortened.

    • +
    • Compact: Similar to pretty, but removes detailed statistics such as runtimes, label probabilities, index locations of null types, etc.

    • +
    • Serializable: Output is json serializable and not prettified

    • +
    • Flat: Nested Output is returned as a flattened dictionary

    • +
    +

    The Pretty and Compact reports are the two most commonly used reports and includes global_stats and data_stats for the given dataset. global_stats contains overall properties of the data such as number of rows/columns, null ratio, duplicate ratio. data_stats contains specific properties and statistics for each column file such as min, max, mean, variance, etc.

    +

    For structured profiles, the report looks like this:

    +
    "global_stats": {
    +    "samples_used": int,
    +    "column_count": int,
    +    "row_count": int,
    +    "row_has_null_ratio": float,
    +    "row_is_null_ratio": float,
    +    "unique_row_ratio": float,
    +    "duplicate_row_count": int,
    +    "file_type": string,
    +    "encoding": string,
    +},
    +"data_stats": [
    +    {
    +        "column_name": string,
    +        "data_type": string,
    +        "data_label": string,
    +        "categorical": bool,
    +        "order": string,
    +        "samples": list(str),
    +        "statistics": {
    +            "sample_size": int,
    +            "null_count": int,
    +            "null_types": list(string),
    +            "null_types_index": {
    +                string: list(int)
    +            },
    +            "data_type_representation": [string, list(string)],
    +            "min": [null, float],
    +            "max": [null, float],
    +            "mean": float,
    +            "variance": float,
    +            "stddev": float,
    +            "histogram": {
    +                "bin_counts": list(int),
    +                "bin_edges": list(float),
    +            },
    +            "quantiles": {
    +                int: float
    +            }
    +            "vocab": list(char),
    +            "avg_predictions": dict(float),
    +            "data_label_representation": dict(float),
    +            "categories": list(str),
    +            "unique_count": int,
    +            "unique_ratio": float,
    +            "precision": {
    +                'min': int,
    +                'max': int,
    +                'mean': float,
    +                'var': float,
    +                'std': float,
    +                'sample_size': int,
    +                'margin_of_error': float,
    +                'confidence_level': float
    +            },
    +            "times": dict(float),
    +            "format": string
    +        }
    +    }
    +]
    +
    +
    +

    In the example, the compact format of the report is used to shorten the full list of the results.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +except ImportError:
    +    import dataprofiler as dp
    +
    +data_path = "../dataprofiler/tests/data"
    +
    +# remove extra tf loggin
    +import tensorflow as tf
    +tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(os.path.join(data_path, "csv/aws_honeypot_marx_geo.csv"))
    +profile = dp.Profiler(data)
    +
    +# Compact - A high level view, good for quick reviews
    +report  = profile.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    It should be noted, in addition to reading the input data from multiple file types, DataProfiler allows the input data as a dataframe. To get more results related to detailed predictions at the entity level from the DataLabeler component or histogram results, the format pretty should be used.

    +
    +
    [ ]:
    +
    +
    +
    +# run data profiler and get the report
    +import pandas as pd
    +my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]], columns=["col_int", "col_float"])
    +profile = dp.Profiler(my_dataframe)
    +
    +report  = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Profiler Type

    +

    The profiler will infer what type of statistics to generate (structured or unstructured) based on the input. However, you can explicitly specify profile type as well. Here is an example of the the profiler explicitly calling the structured profile.

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(os.path.join(data_path, "csv/aws_honeypot_marx_geo.csv"))
    +profile = dp.Profiler(data, profiler_type='structured')
    +
    +# print the report using json to prettify.
    +report = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Profiler options

    +

    The DataProfiler has the ability to turn on and off components as needed. This is accomplished via the ProfilerOptions class.

    +

    For example, if a user doesn’t require histogram information they may desire to turn off the histogram functionality. Simialrly, if a user is looking for a more accurate labeling, they can increase the samples used to label.

    +

    Below, let’s remove the histogram and increase the number of samples to the labeler component (1,000 samples).

    +

    Full list of options in the Profiler section of the DataProfiler documentation.

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(os.path.join(data_path, "csv/diamonds.csv"))
    +
    +profile_options = dp.ProfilerOptions()
    +
    +# Setting multiple options via set
    +profile_options.set({ "histogram.is_enabled": False, "int.is_enabled": False})
    +
    +# Set options via directly setting them
    +profile_options.structured_options.data_labeler.max_sample_size = 1000
    +
    +profile = dp.Profiler(data, options=profile_options)
    +report  = profile.report(report_options={"output_format":"compact"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Updating Profiles

    +

    Beyond just profiling, one of the unique aspects of the DataProfiler is the ability to update the profiles. To update appropriately, the schema (columns / keys) must match appropriately.

    +
    +
    [ ]:
    +
    +
    +
    +# Load and profile a CSV file
    +data = dp.Data(os.path.join(data_path, "csv/sparse-first-and-last-column-header-and-author.txt"))
    +profile = dp.Profiler(data)
    +
    +# Update the profile with new data:
    +new_data = dp.Data(os.path.join(data_path, "csv/sparse-first-and-last-column-skip-header.txt"))
    +# new_data = dp.Data(os.path.join(data_path, "iris-utf-16.csv")) # will error due to schema mismatch
    +profile.update_profile(new_data)
    +
    +# Take a peek at the data
    +print(data.data)
    +print(new_data.data)
    +
    +# Report the compact version of the profile
    +report  = profile.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Merging Profiles

    +

    Merging profiles are an alternative method for updating profiles. Particularly, multiple profiles can be generated seperately, then added together with a simple + command: profile3 = profile1 + profile2

    +
    +
    [ ]:
    +
    +
    +
    +# Load a CSV file with a schema
    +data1 = dp.Data(os.path.join(data_path, "csv/sparse-first-and-last-column-header-and-author.txt"))
    +profile1 = dp.Profiler(data1)
    +
    +# Load another CSV file with the same schema
    +data2 = dp.Data(os.path.join(data_path, "csv/sparse-first-and-last-column-skip-header.txt"))
    +profile2 = dp.Profiler(data2)
    +
    +# Merge the profiles
    +profile3 = profile1 + profile2
    +
    +# Report the compact version of the profile
    +report  = profile3.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    As you can see, the update_profile function and the + operator function similarly. The reason the + operator is important is that it’s possible to save and load profiles, which we cover next.

    +
    +
    +

    Differences in Data

    +

    Can be applied to both structured and unstructured datasets.

    +

    Such reports can provide details on the differences between training and validation data like in this pseudo example:

    +
    profiler_training = dp.Profiler(training_data)
    +profiler_testing = dp.Profiler(testing_data)
    +
    +validation_report = profiler_training.diff(profiler_testing)
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +from pprint import pprint
    +
    +# structured differences example
    +data_split_differences = profile1.diff(profile2)
    +pprint(data_split_differences)
    +
    +
    +
    +
    +
    +

    Graphing a Profile

    +

    We’ve also added the ability to generating visual reports from a profile.

    +

    The following plots are currently available to work directly with your profilers:

    +
      +
    • missing values matrix

    • +
    • histogram (numeric columns only)

    • +
    +
    +
    [ ]:
    +
    +
    +
    +import matplotlib.pyplot as plt
    +
    +
    +# get the data
    +data_folder = "../dataprofiler/tests/data"
    +data = dp.Data(os.path.join(data_folder, "csv/aws_honeypot_marx_geo.csv"))
    +
    +# profile the data
    +profile = dp.Profiler(data)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# generate a missing values matrix
    +fig = plt.figure(figsize=(8, 6), dpi=100)
    +fig = dp.graphs.plot_missing_values_matrix(profile, ax=fig.gca(), title="Missing Values Matrix")
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# generate histogram of all int/float columns
    +fig = dp.graphs.plot_histograms(profile)
    +fig.set_size_inches(8, 6)
    +fig.set_dpi(100)
    +
    +
    +
    +
    +
    +

    Saving and Loading a Profile

    +

    Not only can the Profiler create and update profiles, it’s also possible to save, load then manipulate profiles.

    +
    +
    [ ]:
    +
    +
    +
    +# Load data
    +data = dp.Data(os.path.join(data_path, "csv/names-col.txt"))
    +
    +# Generate a profile
    +profile = dp.Profiler(data)
    +
    +# Save a profile to disk for later (saves as pickle file)
    +profile.save(filepath="my_profile.pkl")
    +
    +# Load a profile from disk
    +loaded_profile = dp.Profiler.load("my_profile.pkl")
    +
    +# Report the compact version of the profile
    +report = profile.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    With the ability to save and load profiles, profiles can be generated via multiple machines then merged. Further, profiles can be stored and later used in applications such as change point detection, synthetic data generation, and more.

    +
    +
    [ ]:
    +
    +
    +
    +# Load a multiple files via the Data class
    +filenames = ["csv/sparse-first-and-last-column-header-and-author.txt",
    +             "csv/sparse-first-and-last-column-skip-header.txt"]
    +data_objects = []
    +for filename in filenames:
    +    data_objects.append(dp.Data(os.path.join(data_path, filename)))
    +
    +
    +# Generate and save profiles
    +for i in range(len(data_objects)):
    +    profile = dp.Profiler(data_objects[i])
    +    profile.save(filepath="data-"+str(i)+".pkl")
    +
    +
    +# Load profiles and add them together
    +profile = None
    +for i in range(len(data_objects)):
    +    if profile is None:
    +        profile = dp.Profiler.load("data-"+str(i)+".pkl")
    +    else:
    +        profile += dp.Profiler.load("data-"+str(i)+".pkl")
    +
    +
    +# Report the compact version of the profile
    +report = profile.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/profiler_example.ipynb b/docs/0.10.3/html/profiler_example.ipynb new file mode 100644 index 000000000..b6a4409c9 --- /dev/null +++ b/docs/0.10.3/html/profiler_example.ipynb @@ -0,0 +1,577 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f37ca393", + "metadata": {}, + "source": [ + "# Structured Profilers" + ] + }, + { + "cell_type": "markdown", + "id": "ff9bd095", + "metadata": {}, + "source": [ + "**Data profiling** - *is the process of examining a dataset and collecting statistical or informational summaries about said dataset.*\n", + "\n", + "The Profiler class inside the DataProfiler is designed to generate *data profiles* via the Profiler class, which ingests either a Data class or a Pandas DataFrame. \n", + "\n", + "Currently, the Data class supports loading the following file formats:\n", + "\n", + "* Any delimited (CSV, TSV, etc.)\n", + "* JSON object\n", + "* Avro\n", + "* Parquet\n", + "* Text files\n", + "* Pandas Series/Dataframe\n", + "\n", + "Once the data is loaded, the Profiler can calculate statistics and predict the entities (via the Labeler) of every column (csv) or key-value (JSON) store as well as dataset wide information, such as the number of nulls, duplicates, etc.\n", + "\n", + "This example will look at specifically the structured data types for structured profiling. " + ] + }, + { + "cell_type": "markdown", + "id": "de58b9c4", + "metadata": {}, + "source": [ + "## Reporting" + ] + }, + { + "cell_type": "markdown", + "id": "8001185a", + "metadata": {}, + "source": [ + "One of the primary purposes of the Profiler are to quickly identify what is in the dataset. This can be useful for analyzing a dataset prior to use or determining which columns could be useful for a given purpose.\n", + "\n", + "In terms of reporting, there are multiple reporting options:\n", + "\n", + "* **Pretty**: Floats are rounded to four decimal places, and lists are shortened.\n", + "* **Compact**: Similar to pretty, but removes detailed statistics such as runtimes, label probabilities, index locations of null types, etc.\n", + "* **Serializable**: Output is json serializable and not prettified\n", + "* **Flat**: Nested Output is returned as a flattened dictionary\n", + "\n", + "The **Pretty** and **Compact** reports are the two most commonly used reports and includes `global_stats` and `data_stats` for the given dataset. `global_stats` contains overall properties of the data such as number of rows/columns, null ratio, duplicate ratio. `data_stats` contains specific properties and statistics for each column file such as min, max, mean, variance, etc.\n", + "\n", + "For structured profiles, the report looks like this:\n", + "\n", + "```\n", + "\"global_stats\": {\n", + " \"samples_used\": int,\n", + " \"column_count\": int,\n", + " \"row_count\": int,\n", + " \"row_has_null_ratio\": float,\n", + " \"row_is_null_ratio\": float, \n", + " \"unique_row_ratio\": float,\n", + " \"duplicate_row_count\": int,\n", + " \"file_type\": string,\n", + " \"encoding\": string,\n", + "},\n", + "\"data_stats\": [\n", + " {\n", + " \"column_name\": string,\n", + " \"data_type\": string,\n", + " \"data_label\": string,\n", + " \"categorical\": bool,\n", + " \"order\": string,\n", + " \"samples\": list(str),\n", + " \"statistics\": {\n", + " \"sample_size\": int,\n", + " \"null_count\": int,\n", + " \"null_types\": list(string),\n", + " \"null_types_index\": {\n", + " string: list(int)\n", + " },\n", + " \"data_type_representation\": [string, list(string)],\n", + " \"min\": [null, float],\n", + " \"max\": [null, float],\n", + " \"mean\": float,\n", + " \"variance\": float,\n", + " \"stddev\": float,\n", + " \"histogram\": { \n", + " \"bin_counts\": list(int),\n", + " \"bin_edges\": list(float),\n", + " },\n", + " \"quantiles\": {\n", + " int: float\n", + " }\n", + " \"vocab\": list(char),\n", + " \"avg_predictions\": dict(float), \n", + " \"data_label_representation\": dict(float),\n", + " \"categories\": list(str),\n", + " \"unique_count\": int,\n", + " \"unique_ratio\": float,\n", + " \"precision\": {\n", + " 'min': int,\n", + " 'max': int,\n", + " 'mean': float,\n", + " 'var': float,\n", + " 'std': float,\n", + " 'sample_size': int,\n", + " 'margin_of_error': float,\n", + " 'confidence_level': float\t\t\n", + " },\n", + " \"times\": dict(float),\n", + " \"format\": string\n", + " }\n", + " }\n", + "]\n", + "```\n", + "\n", + "In the example, the `compact` format of the report is used to shorten the full list of the results. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fcb5447", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"\n", + "\n", + "# remove extra tf loggin\n", + "import tensorflow as tf\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7fc2df6", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Compact - A high level view, good for quick reviews\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "d7ec39d2", + "metadata": {}, + "source": [ + "It should be noted, in addition to reading the input data from multiple file types, DataProfiler allows the input data as a dataframe. To get more results related to detailed predictions at the entity level from the DataLabeler component or histogram results, the format `pretty` should be used. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29737f25", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# run data profiler and get the report\n", + "import pandas as pd\n", + "my_dataframe = pd.DataFrame([[1, 2.0],[1, 2.2],[-1, 3]], columns=[\"col_int\", \"col_float\"])\n", + "profile = dp.Profiler(my_dataframe)\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "241f6e3e", + "metadata": {}, + "source": [ + "## Profiler Type" + ] + }, + { + "cell_type": "markdown", + "id": "5b20879b", + "metadata": {}, + "source": [ + "The profiler will infer what type of statistics to generate (structured or unstructured) based on the input. However, you can explicitly specify profile type as well. Here is an example of the the profiler explicitly calling the structured profile." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc44eb47", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "profile = dp.Profiler(data, profiler_type='structured')\n", + "\n", + "# print the report using json to prettify.\n", + "report = profile.report(report_options={\"output_format\": \"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "fe02ad64", + "metadata": {}, + "source": [ + "## Profiler options" + ] + }, + { + "cell_type": "markdown", + "id": "40804cc9", + "metadata": {}, + "source": [ + "The DataProfiler has the ability to turn on and off components as needed. This is accomplished via the `ProfilerOptions` class.\n", + "\n", + "For example, if a user doesn't require histogram information they may desire to turn off the histogram functionality. Simialrly, if a user is looking for a more accurate labeling, they can increase the samples used to label.\n", + "\n", + "Below, let's remove the histogram and increase the number of samples to the labeler component (1,000 samples). \n", + "\n", + "Full list of options in the Profiler section of the [DataProfiler documentation](https://capitalone.github.io/DataProfiler/profile_options.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d25d899", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"csv/diamonds.csv\"))\n", + "\n", + "profile_options = dp.ProfilerOptions()\n", + "\n", + "# Setting multiple options via set\n", + "profile_options.set({ \"histogram.is_enabled\": False, \"int.is_enabled\": False})\n", + "\n", + "# Set options via directly setting them\n", + "profile_options.structured_options.data_labeler.max_sample_size = 1000\n", + "\n", + "profile = dp.Profiler(data, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "2052415a", + "metadata": {}, + "source": [ + "## Updating Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "7e02f746", + "metadata": {}, + "source": [ + "Beyond just profiling, one of the unique aspects of the DataProfiler is the ability to update the profiles. To update appropriately, the schema (columns / keys) must match appropriately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ab8022f", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# Load and profile a CSV file\n", + "data = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-header-and-author.txt\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Update the profile with new data:\n", + "new_data = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-skip-header.txt\"))\n", + "# new_data = dp.Data(os.path.join(data_path, \"iris-utf-16.csv\")) # will error due to schema mismatch\n", + "profile.update_profile(new_data)\n", + "\n", + "# Take a peek at the data\n", + "print(data.data)\n", + "print(new_data.data)\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "66ec6dc5", + "metadata": {}, + "source": [ + "## Merging Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "e2265fe9", + "metadata": {}, + "source": [ + "Merging profiles are an alternative method for updating profiles. Particularly, multiple profiles can be generated seperately, then added together with a simple `+` command: `profile3 = profile1 + profile2`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc68ca07", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# Load a CSV file with a schema\n", + "data1 = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-header-and-author.txt\"))\n", + "profile1 = dp.Profiler(data1)\n", + "\n", + "# Load another CSV file with the same schema\n", + "data2 = dp.Data(os.path.join(data_path, \"csv/sparse-first-and-last-column-skip-header.txt\"))\n", + "profile2 = dp.Profiler(data2)\n", + "\n", + "# Merge the profiles\n", + "profile3 = profile1 + profile2\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile3.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "7ea07dc6", + "metadata": {}, + "source": [ + "As you can see, the `update_profile` function and the `+` operator function similarly. The reason the `+` operator is important is that it's possible to *save and load profiles*, which we cover next." + ] + }, + { + "cell_type": "markdown", + "id": "375ff25c-b189-436a-b07d-5e7f13cc6e03", + "metadata": {}, + "source": [ + "## Differences in Data\n", + "Can be applied to both structured and unstructured datasets. \n", + "\n", + "Such reports can provide details on the differences between training and validation data like in this pseudo example:\n", + "```python\n", + "profiler_training = dp.Profiler(training_data)\n", + "profiler_testing = dp.Profiler(testing_data)\n", + "\n", + "validation_report = profiler_training.diff(profiler_testing)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65360a03-e3ff-4f3c-9963-412298fdb284", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "\n", + "# structured differences example\n", + "data_split_differences = profile1.diff(profile2)\n", + "pprint(data_split_differences)" + ] + }, + { + "cell_type": "markdown", + "id": "2ae471ff-852f-400a-9bee-5c9fef96f10a", + "metadata": {}, + "source": [ + "## Graphing a Profile\n", + "\n", + "We've also added the ability to generating visual reports from a profile.\n", + "\n", + "The following plots are currently available to work directly with your profilers:\n", + "\n", + " * missing values matrix\n", + " * histogram (numeric columns only)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "734b588d-ac9a-409c-8eb5-b1a0aede8c63", + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "\n", + "# get the data\n", + "data_folder = \"../dataprofiler/tests/data\"\n", + "data = dp.Data(os.path.join(data_folder, \"csv/aws_honeypot_marx_geo.csv\"))\n", + "\n", + "# profile the data\n", + "profile = dp.Profiler(data)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e4e70204-fa30-43c2-9556-e84c19f82d32", + "metadata": {}, + "outputs": [], + "source": [ + "# generate a missing values matrix\n", + "fig = plt.figure(figsize=(8, 6), dpi=100)\n", + "fig = dp.graphs.plot_missing_values_matrix(profile, ax=fig.gca(), title=\"Missing Values Matrix\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d734d355-e542-4245-a1e9-66521e333c2d", + "metadata": {}, + "outputs": [], + "source": [ + "# generate histogram of all int/float columns\n", + "fig = dp.graphs.plot_histograms(profile)\n", + "fig.set_size_inches(8, 6)\n", + "fig.set_dpi(100)" + ] + }, + { + "cell_type": "markdown", + "id": "30868000", + "metadata": {}, + "source": [ + "## Saving and Loading a Profile" + ] + }, + { + "cell_type": "markdown", + "id": "f2858072", + "metadata": {}, + "source": [ + "Not only can the Profiler create and update profiles, it's also possible to save, load then manipulate profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ad9ca57", + "metadata": {}, + "outputs": [], + "source": [ + "# Load data\n", + "data = dp.Data(os.path.join(data_path, \"csv/names-col.txt\"))\n", + "\n", + "# Generate a profile\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Save a profile to disk for later (saves as pickle file)\n", + "profile.save(filepath=\"my_profile.pkl\")\n", + "\n", + "# Load a profile from disk\n", + "loaded_profile = dp.Profiler.load(\"my_profile.pkl\")\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "8f9859c2", + "metadata": {}, + "source": [ + "With the ability to save and load profiles, profiles can be generated via multiple machines then merged. Further, profiles can be stored and later used in applications such as change point detection, synthetic data generation, and more. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3571f2d0", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a multiple files via the Data class\n", + "filenames = [\"csv/sparse-first-and-last-column-header-and-author.txt\",\n", + " \"csv/sparse-first-and-last-column-skip-header.txt\"]\n", + "data_objects = []\n", + "for filename in filenames:\n", + " data_objects.append(dp.Data(os.path.join(data_path, filename)))\n", + "\n", + "\n", + "# Generate and save profiles\n", + "for i in range(len(data_objects)):\n", + " profile = dp.Profiler(data_objects[i])\n", + " profile.save(filepath=\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Load profiles and add them together\n", + "profile = None\n", + "for i in range(len(data_objects)):\n", + " if profile is None:\n", + " profile = dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + " else:\n", + " profile += dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4690068a-8fc3-4bd5-8649-63d0f34fa91d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/py-modindex.html b/docs/0.10.3/html/py-modindex.html new file mode 100644 index 000000000..b08ac9e5d --- /dev/null +++ b/docs/0.10.3/html/py-modindex.html @@ -0,0 +1,604 @@ + + + + + + + Python Module Index - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + +
    +

    Python Module Index

    + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
     
    d
    + dataprofiler +
        + dataprofiler.data_readers +
        + dataprofiler.data_readers.avro_data +
        + dataprofiler.data_readers.base_data +
        + dataprofiler.data_readers.csv_data +
        + dataprofiler.data_readers.data +
        + dataprofiler.data_readers.data_utils +
        + dataprofiler.data_readers.filepath_or_buffer +
        + dataprofiler.data_readers.graph_data +
        + dataprofiler.data_readers.json_data +
        + dataprofiler.data_readers.parquet_data +
        + dataprofiler.data_readers.structured_mixins +
        + dataprofiler.data_readers.text_data +
        + dataprofiler.dp_logging +
        + dataprofiler.labelers +
        + dataprofiler.labelers.base_data_labeler +
        + dataprofiler.labelers.base_model +
        + dataprofiler.labelers.char_load_tf_model +
        + dataprofiler.labelers.character_level_cnn_model +
        + dataprofiler.labelers.classification_report_utils +
        + dataprofiler.labelers.column_name_model +
        + dataprofiler.labelers.data_labelers +
        + dataprofiler.labelers.data_processing +
        + dataprofiler.labelers.labeler_utils +
        + dataprofiler.labelers.regex_model +
        + dataprofiler.labelers.utils +
        + dataprofiler.profilers +
        + dataprofiler.profilers.base_column_profilers +
        + dataprofiler.profilers.categorical_column_profile +
        + dataprofiler.profilers.column_profile_compilers +
        + dataprofiler.profilers.data_labeler_column_profile +
        + dataprofiler.profilers.datetime_column_profile +
        + dataprofiler.profilers.float_column_profile +
        + dataprofiler.profilers.graph_profiler +
        + dataprofiler.profilers.helpers +
        + dataprofiler.profilers.helpers.report_helpers +
        + dataprofiler.profilers.histogram_utils +
        + dataprofiler.profilers.int_column_profile +
        + dataprofiler.profilers.json_decoder +
        + dataprofiler.profilers.json_encoder +
        + dataprofiler.profilers.numerical_column_stats +
        + dataprofiler.profilers.order_column_profile +
        + dataprofiler.profilers.profile_builder +
        + dataprofiler.profilers.profiler_options +
        + dataprofiler.profilers.profiler_utils +
        + dataprofiler.profilers.text_column_profile +
        + dataprofiler.profilers.unstructured_labeler_profile +
        + dataprofiler.profilers.unstructured_text_profile +
        + dataprofiler.reports +
        + dataprofiler.reports.graphs +
        + dataprofiler.reports.utils +
        + dataprofiler.rng_utils +
        + dataprofiler.settings +
        + dataprofiler.validators +
        + dataprofiler.validators.base_validators +
        + dataprofiler.version +
    + +
    +
    + + + + + +
    +
    + +
    +
    + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/regex_labeler_from_scratch.html b/docs/0.10.3/html/regex_labeler_from_scratch.html new file mode 100644 index 000000000..6eb9a2e94 --- /dev/null +++ b/docs/0.10.3/html/regex_labeler_from_scratch.html @@ -0,0 +1,857 @@ + + + + + + + + + Building a Regex Data Labeler w/ your own Regex - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Building a Regex Data Labeler w/ your own Regex

    +

    This notebook teaches how to use the existing / create your own regex labeler as well as utilize it for structured data profiling.

    +
      +
    1. Loading and utilizing the pre-existing regex data labeler

    2. +
    3. Replacing the existing regex rules with your own.

    4. +
    5. Utilizng a regex data labeler inside of the structured profiler

    6. +
    +

    First, let’s import the libraries needed for this example.

    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +from pprint import pprint
    +
    +import pandas as pd
    +
    +try:
    +    import dataprofiler as dp
    +except ImportError:
    +    sys.path.insert(0, '../..')
    +    import dataprofiler as dp
    +
    +
    +
    +
    +

    Loading and using the pre-existing regex data labeler

    +

    We can easily import the exsting regex labeler via the load_from_library command from the dp.DataLabeler. This allows us to import models other than the default structured / unstructured labelers which exist in the library.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler = dp.DataLabeler.load_from_library('regex_model')
    +data_labeler.model.help()
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pprint(data_labeler.label_mapping)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +pprint(data_labeler.model._parameters['regex_patterns'])
    +
    +
    +
    +
    +

    Predicting with the regex labeler

    +

    In the prediction below, the default settings will split the predictions by default as it’s aggregation function. In other words, if a string ‘123 Fake St.’ The first character would receive a vote for integer and for address giving both a 50% probability. This is because these regex functions are defined individually and a post prediction aggregation function must be used to get the results.

    +
    +
    [ ]:
    +
    +
    +
    +# evaluate a prediction using the default parameters
    +data_labeler.predict(['123 Fake St.'])
    +
    +
    +
    +
    +
    +
    +

    Replacing the regex rules in the existing labeler

    +

    We can achieve this by: 1. Setting the label mapping to the new labels 2. Setting the model parameters which include: regex_patterns, default_label, ignore_case, and encapsulators

    +

    where regex_patterns is a dict of lists or regex for each label, default_label is the expected default label for the regex, ignore_case tells the model to ignore case during its detection, and encapsulators are generic regex statements placed before (start) and after (end) each regex. Currently, this is used by the default model to capture labels that are within a cell rather than matching the entire cell. (e.g. ’ 123 ’ will still capture 123 as digits).

    +

    Below, we created 4 labels where other is the default_label. Additionally, we set enabled case sensitivity such that upper and lower case letters would be detected separately.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.set_labels({'other': 0, 'digits':1, 'lowercase_char': 2, 'uppercase_chars': 3})
    +data_labeler.model.set_params(
    +    regex_patterns={
    +        'digits': [r'[+-]?[0-9]+'],
    +        'lowercase_char': [r'[a-z]+'],
    +        'uppercase_chars': [r'[A-Z]+'],
    +    },
    +    default_label='other',
    +    ignore_case=False,
    +)
    +data_labeler.label_mapping
    +
    +
    +
    +
    +

    Predicting with the new regex labels

    +

    Here we notice the otuput of the predictions gives us a prediction per character for each regex. Note how by default it is matching subtext due to the encapsulators. Where 123 were found to be digits, FAKE was foudn to be upper case, and the whitespaces and St. were other due no single regex being correct.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.predict(['123 FAKE St.'])
    +
    +
    +
    +

    Below we turn off case-sensitivity and we see how the aggregation funciton splits the votes for characters between the lowercase and uppercase chars.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.model.set_params(ignore_case=True)
    +data_labeler.predict(['123 FAKE St.'])
    +
    +
    +
    +

    For the rest of this notebook, we will just use a single regex serach which will capture both upper and lower case chars.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.set_labels({'other': 0, 'digits':1, 'chars': 2})
    +data_labeler.model.set_params(
    +    regex_patterns={
    +        'digits': [r'[=-]?[0-9]+'],
    +        'chars': [r'[a-zA-Z]+'],
    +    },
    +    default_label='other',
    +    ignore_case=False,
    +)
    +data_labeler.label_mapping
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.predict(['123 FAKE St.'])
    +
    +
    +
    +
    +
    +

    Adjusting postprocessor properties

    +

    Below we can look at the possible postprocessor parameters to adjust the aggregation function to the desired output. The previous outputs by default used the split aggregation function, however, below we will show the random aggregation function which will randomly choose a label if multiple labels have a vote for a given character.

    +

    data_labeler.postprocessor.help()

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.postprocessor.set_params(aggregation_func='random')
    +data_labeler.predict(['123 FAKE St.'], predict_options=dict(show_confidences=True))
    +
    +
    +
    +
    +
    +
    +

    Integrating the new Regex labeler into Structured Profiling

    +

    While the labeler can be used alone, it is also possible to integrate the labeler into the StructuredProfiler with a slight change to its postprocessor. The StructuredProfiler requires a labeler which outputs othe confidence of each label for a given cell being processed. To convert the output of the RegexPostProcessor into said format, we will use the StructRegexPostProcessor. We can create the postprocessor and set the data_labeler’s postprocessor to this value.

    +
    +
    [ ]:
    +
    +
    +
    +from dataprofiler.labelers.data_processing import StructRegexPostProcessor
    +
    +postprocesor = StructRegexPostProcessor()
    +data_labeler.set_postprocessor(postprocesor)
    +
    +
    +
    +

    Below we will see the output is now one vote per sample.

    +
    +
    [ ]:
    +
    +
    +
    +data_labeler.predict(['123 FAKE St.', '123', 'FAKE'], predict_options=dict(show_confidences=True))
    +
    +
    +
    +
    +

    Setting the Structuredprofiler’s DataLabeler

    +

    We can create a ProfilerOption and set the structured options to have the new data_labeler as its value. We then run the StructuredProfiler with the specified options.

    +
    +
    [ ]:
    +
    +
    +
    +# create and set the option for the regex data labeler to be used at profile time
    +profile_options = dp.ProfilerOptions()
    +profile_options.set({'structured_options.data_labeler.data_labeler_object': data_labeler})
    +
    +# profile the dataset using the suggested regex data labeler
    +data = pd.DataFrame(
    +    [['123 FAKE St.', 123, 'this'],
    +     [123           ,  -9, 'IS'],
    +     ['...'         , +80, 'A'],
    +     ['123'         , 202, 'raNDom'],
    +     ['test'        ,  -1, 'TEST']],
    +    dtype=object)
    +profiler = dp.Profiler(data, options=profile_options)
    +
    +
    +
    +

    Below we see the first column is given 3 labels as it received multiple votes for said column. However, it was confident on the second and third column which is why it only specified digits and chars respectively.

    +
    +
    [ ]:
    +
    +
    +
    +pprint(profiler.report(
    +    dict(output_format='compact',
    +         omit_keys=['data_stats.*.statistics',
    +                    'data_stats.*.categorical',
    +                    'data_stats.*.order',
    +                    'global_stats'])))
    +
    +
    +
    +
    +
    +
    +

    Saving the Data Labeler for future use

    +
    +
    [ ]:
    +
    +
    +
    +if not os.path.isdir('my_new_regex_labeler'):
    +    os.mkdir('my_new_regex_labeler')
    +data_labeler.save_to_disk('my_new_regex_labeler')
    +
    +
    +
    +
    +
    +

    Loading the saved Data Labeler

    +
    +
    [ ]:
    +
    +
    +
    +saved_labeler = dp.DataLabeler.load_from_disk('my_new_regex_labeler')
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# ensuring the parametesr are what we saved.
    +print("label_mapping:")
    +pprint(saved_labeler.label_mapping)
    +print("\nmodel parameters:")
    +pprint(saved_labeler.model._parameters)
    +print()
    +print("postprocessor: " + saved_labeler.postprocessor.__class__.__name__)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +# predicting with the loaded labeler.
    +saved_labeler.predict(['test', '123'])
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/regex_labeler_from_scratch.ipynb b/docs/0.10.3/html/regex_labeler_from_scratch.ipynb new file mode 100644 index 000000000..96aee213a --- /dev/null +++ b/docs/0.10.3/html/regex_labeler_from_scratch.ipynb @@ -0,0 +1,444 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "e04c382a-7c49-452b-b9bf-e448951c64fe", + "metadata": {}, + "source": [ + "# Building a Regex Data Labeler w/ your own Regex" + ] + }, + { + "cell_type": "markdown", + "id": "6fb3ecb9-bc51-4c18-93d5-7991bbee5165", + "metadata": {}, + "source": [ + "This notebook teaches how to use the existing / create your own regex labeler as well as utilize it for structured data profiling.\n", + "\n", + "1. Loading and utilizing the pre-existing regex data labeler\n", + "1. Replacing the existing regex rules with your own.\n", + "1. Utilizng a regex data labeler inside of the structured profiler\n", + "\n", + "First, let's import the libraries needed for this example." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a67c197b-d3ee-4896-a96f-cc3d043601d3", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "from pprint import pprint\n", + "\n", + "import pandas as pd\n", + "\n", + "try:\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " sys.path.insert(0, '../..')\n", + " import dataprofiler as dp" + ] + }, + { + "cell_type": "markdown", + "id": "c71356f4-9020-4862-a1e1-816effbb5443", + "metadata": {}, + "source": [ + "## Loading and using the pre-existing regex data labeler\n", + "We can easily import the exsting regex labeler via the `load_from_library` command from the `dp.DataLabeler`. This allows us to import models other than the default structured / unstructured labelers which exist in the library." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "113d6655-4bca-4d8e-9e6f-b972e29d5684", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler = dp.DataLabeler.load_from_library('regex_model')\n", + "data_labeler.model.help()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0b405887-2b92-44ca-b8d7-29c384f6dd9c", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.label_mapping)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "11916a48-098c-4056-ac6c-b9542d85fa86", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(data_labeler.model._parameters['regex_patterns'])" + ] + }, + { + "cell_type": "markdown", + "id": "da0e97ee-8d6d-4631-9b55-78ed904d5f41", + "metadata": {}, + "source": [ + "### Predicting with the regex labeler\n", + "In the prediction below, the default settings will `split` the predictions by default as it's aggregation function. In other words, if a string '123 Fake St.' The first character would receive a vote for integer and for address giving both a 50% probability. This is because these regex functions are defined individually and a post prediction aggregation function must be used to get the results." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "fe519e65-36a7-4f42-8314-5369de8635c7", + "metadata": {}, + "outputs": [], + "source": [ + "# evaluate a prediction using the default parameters\n", + "data_labeler.predict(['123 Fake St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "b41d834d-e47b-45a6-8970-d2d2033e2ade", + "metadata": {}, + "source": [ + "## Replacing the regex rules in the existing labeler\n", + "\n", + "We can achieve this by:\n", + "1. Setting the label mapping to the new labels\n", + "2. Setting the model parameters which include: `regex_patterns`, `default_label`, `ignore_case`, and `encapsulators`\n", + "\n", + "where `regex_patterns` is a `dict` of lists or regex for each label, `default_label` is the expected default label for the regex, `ignore_case` tells the model to ignore case during its detection, and `encapsulators` are generic regex statements placed before (start) and after (end) each regex. Currently, this is used by the default model to capture labels that are within a cell rather than matching the entire cell. (e.g. ' 123 ' will still capture 123 as digits)." + ] + }, + { + "cell_type": "markdown", + "id": "c6bb010a-406f-4fd8-abd0-3355a5ad0ded", + "metadata": {}, + "source": [ + "Below, we created 4 labels where `other` is the `default_label`. Additionally, we set enabled case sensitivity such that upper and lower case letters would be detected separately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f86584cf-a7af-4bae-bf44-d87caa68833a", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.set_labels({'other': 0, 'digits':1, 'lowercase_char': 2, 'uppercase_chars': 3})\n", + "data_labeler.model.set_params(\n", + " regex_patterns={\n", + " 'digits': [r'[+-]?[0-9]+'],\n", + " 'lowercase_char': [r'[a-z]+'],\n", + " 'uppercase_chars': [r'[A-Z]+'],\n", + " },\n", + " default_label='other',\n", + " ignore_case=False,\n", + ")\n", + "data_labeler.label_mapping" + ] + }, + { + "cell_type": "markdown", + "id": "1ece1c8c-18a5-46fc-b563-6458e6e71e53", + "metadata": {}, + "source": [ + "### Predicting with the new regex labels\n", + "\n", + "Here we notice the otuput of the predictions gives us a prediction per character for each regex. Note how by default it is matching subtext due to the encapsulators. Where `123` were found to be digits, `FAKE` was foudn to be upper case, and the whitespaces and `St.` were other due no single regex being correct." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "92842e14-2ea6-4879-b58c-c52b607dc94c", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(['123 FAKE St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "2ce14e54-094f-41ff-9ce0-69acace6abc2", + "metadata": {}, + "source": [ + "Below we turn off case-sensitivity and we see how the aggregation funciton splits the votes for characters between the `lowercase` and `uppercase` chars." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f7b8ed9d-c912-4dc7-82c5-ba78a3affc1e", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.model.set_params(ignore_case=True)\n", + "data_labeler.predict(['123 FAKE St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "dc66515f-24e4-40f0-8592-b1ee4fba7077", + "metadata": {}, + "source": [ + "For the rest of this notebook, we will just use a single regex serach which will capture both upper and lower case chars." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3e0c1b11-d111-4080-873f-40aff7cf7930", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.set_labels({'other': 0, 'digits':1, 'chars': 2})\n", + "data_labeler.model.set_params(\n", + " regex_patterns={\n", + " 'digits': [r'[=-]?[0-9]+'],\n", + " 'chars': [r'[a-zA-Z]+'],\n", + " },\n", + " default_label='other',\n", + " ignore_case=False,\n", + ")\n", + "data_labeler.label_mapping" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28e7b2ee-c661-4b31-b727-078f1393b5c4", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(['123 FAKE St.'])" + ] + }, + { + "cell_type": "markdown", + "id": "f60c8fd1-76e1-469f-9e5a-62d7529301b3", + "metadata": {}, + "source": [ + "### Adjusting postprocessor properties\n", + "\n", + "Below we can look at the possible postprocessor parameters to adjust the aggregation function to the desired output. The previous outputs by default used the `split` aggregation function, however, below we will show the `random` aggregation function which will randomly choose a label if multiple labels have a vote for a given character." + ] + }, + { + "cell_type": "markdown", + "id": "36afa82b-1ca5-49ad-9aa9-84c6de621f59", + "metadata": {}, + "source": [ + "data_labeler.postprocessor.help()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "66840940-47bf-433a-8ee8-977f26926e0b", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.postprocessor.set_params(aggregation_func='random')\n", + "data_labeler.predict(['123 FAKE St.'], predict_options=dict(show_confidences=True))" + ] + }, + { + "cell_type": "markdown", + "id": "c32b74fc-5051-4d53-b02a-4d1e4a35958f", + "metadata": {}, + "source": [ + "## Integrating the new Regex labeler into Structured Profiling\n", + "\n", + "While the labeler can be used alone, it is also possible to integrate the labeler into the StructuredProfiler with a slight change to its postprocessor. The StructuredProfiler requires a labeler which outputs othe confidence of each label for a given cell being processed. To convert the output of the `RegexPostProcessor` into said format, we will use the `StructRegexPostProcessor`. We can create the postprocessor and set the `data_labeler`'s postprocessor to this value." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a2663f2d-29a2-41ed-88dd-8a213d303365", + "metadata": {}, + "outputs": [], + "source": [ + "from dataprofiler.labelers.data_processing import StructRegexPostProcessor\n", + "\n", + "postprocesor = StructRegexPostProcessor()\n", + "data_labeler.set_postprocessor(postprocesor)" + ] + }, + { + "cell_type": "markdown", + "id": "f7352769-d636-42c6-9706-7d9cff520a72", + "metadata": {}, + "source": [ + "Below we will see the output is now one vote per sample." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18814634-0fd0-4ce8-b0c3-9b9454701a43", + "metadata": {}, + "outputs": [], + "source": [ + "data_labeler.predict(['123 FAKE St.', '123', 'FAKE'], predict_options=dict(show_confidences=True))" + ] + }, + { + "cell_type": "markdown", + "id": "b4aa4e36-7362-4966-b827-3f5a6f2dfa7c", + "metadata": {}, + "source": [ + "### Setting the Structuredprofiler's DataLabeler\n", + "\n", + "We can create a `ProfilerOption` and set the structured options to have the new data_labeler as its value. We then run the StructuredProfiler with the specified options." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f18cf7f-283e-4e54-b3f9-1312828c3029", + "metadata": {}, + "outputs": [], + "source": [ + "# create and set the option for the regex data labeler to be used at profile time\n", + "profile_options = dp.ProfilerOptions()\n", + "profile_options.set({'structured_options.data_labeler.data_labeler_object': data_labeler})\n", + "\n", + "# profile the dataset using the suggested regex data labeler\n", + "data = pd.DataFrame(\n", + " [['123 FAKE St.', 123, 'this'], \n", + " [123 , -9, 'IS'], \n", + " ['...' , +80, 'A'], \n", + " ['123' , 202, 'raNDom'], \n", + " ['test' , -1, 'TEST']], \n", + " dtype=object)\n", + "profiler = dp.Profiler(data, options=profile_options)" + ] + }, + { + "cell_type": "markdown", + "id": "663e49f7-358b-4b0f-99a4-1823908ef990", + "metadata": {}, + "source": [ + "Below we see the first column is given 3 labels as it received multiple votes for said column. However, it was confident on the second and third column which is why it only specified `digits` and `chars` respectively." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f796d7f5-7e8a-447b-9cbb-d5b8180660a3", + "metadata": {}, + "outputs": [], + "source": [ + "pprint(profiler.report(\n", + " dict(output_format='compact', \n", + " omit_keys=['data_stats.*.statistics', \n", + " 'data_stats.*.categorical', \n", + " 'data_stats.*.order', \n", + " 'global_stats'])))" + ] + }, + { + "cell_type": "markdown", + "id": "261b903f-8f4c-403f-839b-ab8813f850e9", + "metadata": {}, + "source": [ + "## Saving the Data Labeler for future use" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b6ffbaf2-9400-486a-ba83-5fc9ba9334d7", + "metadata": {}, + "outputs": [], + "source": [ + "if not os.path.isdir('my_new_regex_labeler'):\n", + " os.mkdir('my_new_regex_labeler')\n", + "data_labeler.save_to_disk('my_new_regex_labeler')" + ] + }, + { + "cell_type": "markdown", + "id": "09e40cb6-9d89-41c4-ae28-3dca498f8c68", + "metadata": {}, + "source": [ + "## Loading the saved Data Labeler" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52615b25-70a6-4ebb-8a32-14aaf1e747d9", + "metadata": {}, + "outputs": [], + "source": [ + "saved_labeler = dp.DataLabeler.load_from_disk('my_new_regex_labeler')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d1ccc0b3-1dc2-4847-95c2-d6b8769b1590", + "metadata": {}, + "outputs": [], + "source": [ + "# ensuring the parametesr are what we saved.\n", + "print(\"label_mapping:\")\n", + "pprint(saved_labeler.label_mapping)\n", + "print(\"\\nmodel parameters:\")\n", + "pprint(saved_labeler.model._parameters)\n", + "print()\n", + "print(\"postprocessor: \" + saved_labeler.postprocessor.__class__.__name__)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c827f2ae-4af6-4f3f-9651-9ee9ebea9fa0", + "metadata": {}, + "outputs": [], + "source": [ + "# predicting with the loaded labeler.\n", + "saved_labeler.predict(['test', '123'])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "606f9bbf-5955-4b7b-b0d1-390de5600f73", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/0.10.3/html/search.html b/docs/0.10.3/html/search.html new file mode 100644 index 000000000..7de5d8d62 --- /dev/null +++ b/docs/0.10.3/html/search.html @@ -0,0 +1,266 @@ + + + + + + + Search - <div class='hidden'>Data Profiler</div> <div class='version'> v0.10.3</div> + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + +
    +

    Error

    +

    + Please activate JavaScript to enable the search functionality. +

    +
    + + +
    + +
    +
    + + + + + +
    +
    + +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/searchindex.js b/docs/0.10.3/html/searchindex.js new file mode 100644 index 000000000..e1fd48547 --- /dev/null +++ b/docs/0.10.3/html/searchindex.js @@ -0,0 +1 @@ +Search.setIndex({docnames:["API","add_new_model_to_data_labeler","column_name_labeler_example","data_labeling","data_reader","data_readers","dataprofiler","dataprofiler.data_readers","dataprofiler.data_readers.avro_data","dataprofiler.data_readers.base_data","dataprofiler.data_readers.csv_data","dataprofiler.data_readers.data","dataprofiler.data_readers.data_utils","dataprofiler.data_readers.filepath_or_buffer","dataprofiler.data_readers.graph_data","dataprofiler.data_readers.json_data","dataprofiler.data_readers.parquet_data","dataprofiler.data_readers.structured_mixins","dataprofiler.data_readers.text_data","dataprofiler.dp_logging","dataprofiler.labelers","dataprofiler.labelers.base_data_labeler","dataprofiler.labelers.base_model","dataprofiler.labelers.char_load_tf_model","dataprofiler.labelers.character_level_cnn_model","dataprofiler.labelers.classification_report_utils","dataprofiler.labelers.column_name_model","dataprofiler.labelers.data_labelers","dataprofiler.labelers.data_processing","dataprofiler.labelers.labeler_utils","dataprofiler.labelers.regex_model","dataprofiler.labelers.utils","dataprofiler.profilers","dataprofiler.profilers.base_column_profilers","dataprofiler.profilers.categorical_column_profile","dataprofiler.profilers.column_profile_compilers","dataprofiler.profilers.data_labeler_column_profile","dataprofiler.profilers.datetime_column_profile","dataprofiler.profilers.float_column_profile","dataprofiler.profilers.graph_profiler","dataprofiler.profilers.helpers","dataprofiler.profilers.helpers.report_helpers","dataprofiler.profilers.histogram_utils","dataprofiler.profilers.int_column_profile","dataprofiler.profilers.json_decoder","dataprofiler.profilers.json_encoder","dataprofiler.profilers.numerical_column_stats","dataprofiler.profilers.order_column_profile","dataprofiler.profilers.profile_builder","dataprofiler.profilers.profiler_options","dataprofiler.profilers.profiler_utils","dataprofiler.profilers.text_column_profile","dataprofiler.profilers.unstructured_labeler_profile","dataprofiler.profilers.unstructured_text_profile","dataprofiler.profilers.utils","dataprofiler.reports","dataprofiler.reports.graphs","dataprofiler.reports.utils","dataprofiler.rng_utils","dataprofiler.settings","dataprofiler.validators","dataprofiler.validators.base_validators","dataprofiler.version","examples","graph_data_demo","graphs","index","install","labeler","merge_profile_list","modules","overview","popmon_dp_loader_example","profiler","profiler_example","regex_labeler_from_scratch","unstructured_profiler_example"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":4,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,"sphinx.ext.intersphinx":1,nbsphinx:3,sphinx:56},filenames:["API.rst","add_new_model_to_data_labeler.nblink","column_name_labeler_example.nblink","data_labeling.rst","data_reader.nblink","data_readers.rst","dataprofiler.rst","dataprofiler.data_readers.rst","dataprofiler.data_readers.avro_data.rst","dataprofiler.data_readers.base_data.rst","dataprofiler.data_readers.csv_data.rst","dataprofiler.data_readers.data.rst","dataprofiler.data_readers.data_utils.rst","dataprofiler.data_readers.filepath_or_buffer.rst","dataprofiler.data_readers.graph_data.rst","dataprofiler.data_readers.json_data.rst","dataprofiler.data_readers.parquet_data.rst","dataprofiler.data_readers.structured_mixins.rst","dataprofiler.data_readers.text_data.rst","dataprofiler.dp_logging.rst","dataprofiler.labelers.rst","dataprofiler.labelers.base_data_labeler.rst","dataprofiler.labelers.base_model.rst","dataprofiler.labelers.char_load_tf_model.rst","dataprofiler.labelers.character_level_cnn_model.rst","dataprofiler.labelers.classification_report_utils.rst","dataprofiler.labelers.column_name_model.rst","dataprofiler.labelers.data_labelers.rst","dataprofiler.labelers.data_processing.rst","dataprofiler.labelers.labeler_utils.rst","dataprofiler.labelers.regex_model.rst","dataprofiler.labelers.utils.rst","dataprofiler.profilers.rst","dataprofiler.profilers.base_column_profilers.rst","dataprofiler.profilers.categorical_column_profile.rst","dataprofiler.profilers.column_profile_compilers.rst","dataprofiler.profilers.data_labeler_column_profile.rst","dataprofiler.profilers.datetime_column_profile.rst","dataprofiler.profilers.float_column_profile.rst","dataprofiler.profilers.graph_profiler.rst","dataprofiler.profilers.helpers.rst","dataprofiler.profilers.helpers.report_helpers.rst","dataprofiler.profilers.histogram_utils.rst","dataprofiler.profilers.int_column_profile.rst","dataprofiler.profilers.json_decoder.rst","dataprofiler.profilers.json_encoder.rst","dataprofiler.profilers.numerical_column_stats.rst","dataprofiler.profilers.order_column_profile.rst","dataprofiler.profilers.profile_builder.rst","dataprofiler.profilers.profiler_options.rst","dataprofiler.profilers.profiler_utils.rst","dataprofiler.profilers.text_column_profile.rst","dataprofiler.profilers.unstructured_labeler_profile.rst","dataprofiler.profilers.unstructured_text_profile.rst","dataprofiler.profilers.utils.rst","dataprofiler.reports.rst","dataprofiler.reports.graphs.rst","dataprofiler.reports.utils.rst","dataprofiler.rng_utils.rst","dataprofiler.settings.rst","dataprofiler.validators.rst","dataprofiler.validators.base_validators.rst","dataprofiler.version.rst","examples.rst","graph_data_demo.nblink","graphs.rst","index.rst","install.rst","labeler.nblink","merge_profile_list.nblink","modules.rst","overview.nblink","popmon_dp_loader_example.nblink","profiler.rst","profiler_example.nblink","regex_labeler_from_scratch.nblink","unstructured_profiler_example.nblink"],objects:{"":{dataprofiler:[6,0,0,"-"]},"dataprofiler.data_readers":{avro_data:[8,0,0,"-"],base_data:[9,0,0,"-"],csv_data:[10,0,0,"-"],data:[11,0,0,"-"],data_utils:[12,0,0,"-"],filepath_or_buffer:[13,0,0,"-"],graph_data:[14,0,0,"-"],json_data:[15,0,0,"-"],parquet_data:[16,0,0,"-"],structured_mixins:[17,0,0,"-"],text_data:[18,0,0,"-"]},"dataprofiler.data_readers.avro_data":{AVROData:[8,1,1,""]},"dataprofiler.data_readers.avro_data.AVROData":{data:[8,2,1,""],data_and_metadata:[8,2,1,""],data_format:[8,2,1,""],data_type:[8,3,1,""],file_encoding:[8,2,1,""],get_batch_generator:[8,4,1,""],info:[8,3,1,""],is_match:[8,4,1,""],is_structured:[8,2,1,""],length:[8,2,1,""],metadata:[8,2,1,""],reload:[8,4,1,""],selected_keys:[8,2,1,""]},"dataprofiler.data_readers.base_data":{BaseData:[9,1,1,""]},"dataprofiler.data_readers.base_data.BaseData":{data:[9,2,1,""],data_format:[9,2,1,""],data_type:[9,3,1,""],file_encoding:[9,2,1,""],get_batch_generator:[9,4,1,""],info:[9,3,1,""],is_match:[9,4,1,""],is_structured:[9,2,1,""],length:[9,2,1,""],reload:[9,4,1,""]},"dataprofiler.data_readers.csv_data":{CSVData:[10,1,1,""]},"dataprofiler.data_readers.csv_data.CSVData":{data:[10,2,1,""],data_format:[10,2,1,""],data_type:[10,3,1,""],delimiter:[10,2,1,""],file_encoding:[10,2,1,""],get_batch_generator:[10,4,1,""],header:[10,2,1,""],info:[10,3,1,""],is_match:[10,4,1,""],is_structured:[10,2,1,""],length:[10,2,1,""],options:[10,3,1,""],quotechar:[10,2,1,""],reload:[10,4,1,""],sample_nrows:[10,2,1,""],selected_columns:[10,2,1,""]},"dataprofiler.data_readers.data":{Data:[11,1,1,""]},"dataprofiler.data_readers.data.Data":{data_classes:[11,3,1,""]},"dataprofiler.data_readers.data_utils":{convert_int_to_string:[12,5,1,""],data_generator:[12,5,1,""],detect_cell_type:[12,5,1,""],detect_file_encoding:[12,5,1,""],find_nth_loc:[12,5,1,""],generator_on_file:[12,5,1,""],get_delimiter_regex:[12,5,1,""],is_valid_url:[12,5,1,""],json_to_dataframe:[12,5,1,""],load_as_str_from_file:[12,5,1,""],read_csv_df:[12,5,1,""],read_json:[12,5,1,""],read_json_df:[12,5,1,""],read_parquet_df:[12,5,1,""],read_text_as_list_of_strs:[12,5,1,""],reservoir:[12,5,1,""],rsample:[12,5,1,""],unicode_to_str:[12,5,1,""],url_to_bytes:[12,5,1,""]},"dataprofiler.data_readers.filepath_or_buffer":{FileOrBufferHandler:[13,1,1,""],is_stream_buffer:[13,5,1,""]},"dataprofiler.data_readers.graph_data":{GraphData:[14,1,1,""]},"dataprofiler.data_readers.graph_data.GraphData":{check_integer:[14,4,1,""],csv_column_names:[14,4,1,""],data:[14,2,1,""],data_format:[14,2,1,""],data_type:[14,3,1,""],file_encoding:[14,2,1,""],get_batch_generator:[14,4,1,""],info:[14,3,1,""],is_match:[14,4,1,""],is_structured:[14,2,1,""],length:[14,2,1,""],options:[14,3,1,""],reload:[14,4,1,""]},"dataprofiler.data_readers.json_data":{JSONData:[15,1,1,""]},"dataprofiler.data_readers.json_data.JSONData":{data:[15,2,1,""],data_and_metadata:[15,2,1,""],data_format:[15,2,1,""],data_type:[15,3,1,""],file_encoding:[15,2,1,""],get_batch_generator:[15,4,1,""],info:[15,3,1,""],is_match:[15,4,1,""],is_structured:[15,2,1,""],length:[15,2,1,""],metadata:[15,2,1,""],options:[15,3,1,""],reload:[15,4,1,""],selected_keys:[15,2,1,""]},"dataprofiler.data_readers.parquet_data":{ParquetData:[16,1,1,""]},"dataprofiler.data_readers.parquet_data.ParquetData":{data:[16,2,1,""],data_format:[16,2,1,""],data_type:[16,3,1,""],file_encoding:[16,2,1,""],get_batch_generator:[16,4,1,""],info:[16,3,1,""],is_match:[16,4,1,""],is_structured:[16,2,1,""],length:[16,2,1,""],options:[16,3,1,""],reload:[16,4,1,""],selected_columns:[16,2,1,""]},"dataprofiler.data_readers.structured_mixins":{SpreadSheetDataMixin:[17,1,1,""]},"dataprofiler.data_readers.text_data":{TextData:[18,1,1,""]},"dataprofiler.data_readers.text_data.TextData":{data:[18,2,1,""],data_format:[18,2,1,""],data_type:[18,3,1,""],file_encoding:[18,2,1,""],get_batch_generator:[18,4,1,""],info:[18,3,1,""],is_match:[18,4,1,""],is_structured:[18,2,1,""],length:[18,2,1,""],options:[18,3,1,""],reload:[18,4,1,""],samples_per_line:[18,2,1,""],tokenize:[18,4,1,""]},"dataprofiler.dp_logging":{get_child_logger:[19,5,1,""],get_logger:[19,5,1,""],set_verbosity:[19,5,1,""]},"dataprofiler.labelers":{base_data_labeler:[21,0,0,"-"],base_model:[22,0,0,"-"],char_load_tf_model:[23,0,0,"-"],character_level_cnn_model:[24,0,0,"-"],classification_report_utils:[25,0,0,"-"],column_name_model:[26,0,0,"-"],data_labelers:[27,0,0,"-"],data_processing:[28,0,0,"-"],labeler_utils:[29,0,0,"-"],regex_model:[30,0,0,"-"],utils:[31,0,0,"-"]},"dataprofiler.labelers.base_data_labeler":{BaseDataLabeler:[21,1,1,""],TrainableDataLabeler:[21,1,1,""]},"dataprofiler.labelers.base_data_labeler.BaseDataLabeler":{add_label:[21,4,1,""],check_pipeline:[21,4,1,""],help:[21,4,1,""],label_mapping:[21,2,1,""],labels:[21,2,1,""],load_from_disk:[21,4,1,""],load_from_library:[21,4,1,""],load_with_components:[21,4,1,""],model:[21,2,1,""],postprocessor:[21,2,1,""],predict:[21,4,1,""],preprocessor:[21,2,1,""],reverse_label_mapping:[21,2,1,""],save_to_disk:[21,4,1,""],set_labels:[21,4,1,""],set_model:[21,4,1,""],set_params:[21,4,1,""],set_postprocessor:[21,4,1,""],set_preprocessor:[21,4,1,""]},"dataprofiler.labelers.base_data_labeler.TrainableDataLabeler":{add_label:[21,4,1,""],check_pipeline:[21,4,1,""],fit:[21,4,1,""],help:[21,4,1,""],label_mapping:[21,2,1,""],labels:[21,2,1,""],load_from_disk:[21,4,1,""],load_from_library:[21,4,1,""],load_with_components:[21,4,1,""],model:[21,2,1,""],postprocessor:[21,2,1,""],predict:[21,4,1,""],preprocessor:[21,2,1,""],reverse_label_mapping:[21,2,1,""],save_to_disk:[21,4,1,""],set_labels:[21,4,1,""],set_model:[21,4,1,""],set_params:[21,4,1,""],set_postprocessor:[21,4,1,""],set_preprocessor:[21,4,1,""]},"dataprofiler.labelers.base_model":{AutoSubRegistrationMeta:[22,1,1,""],BaseModel:[22,1,1,""],BaseTrainableModel:[22,1,1,""]},"dataprofiler.labelers.base_model.AutoSubRegistrationMeta":{mro:[22,4,1,""],register:[22,4,1,""]},"dataprofiler.labelers.base_model.BaseModel":{add_label:[22,4,1,""],get_class:[22,4,1,""],get_parameters:[22,4,1,""],help:[22,4,1,""],label_mapping:[22,2,1,""],labels:[22,2,1,""],load_from_disk:[22,4,1,""],num_labels:[22,2,1,""],predict:[22,4,1,""],requires_zero_mapping:[22,3,1,""],reset_weights:[22,4,1,""],reverse_label_mapping:[22,2,1,""],save_to_disk:[22,4,1,""],set_label_mapping:[22,4,1,""],set_params:[22,4,1,""]},"dataprofiler.labelers.base_model.BaseTrainableModel":{add_label:[22,4,1,""],fit:[22,4,1,""],get_class:[22,4,1,""],get_parameters:[22,4,1,""],help:[22,4,1,""],label_mapping:[22,2,1,""],labels:[22,2,1,""],load_from_disk:[22,4,1,""],num_labels:[22,2,1,""],predict:[22,4,1,""],requires_zero_mapping:[22,3,1,""],reset_weights:[22,4,1,""],reverse_label_mapping:[22,2,1,""],save_to_disk:[22,4,1,""],set_label_mapping:[22,4,1,""],set_params:[22,4,1,""]},"dataprofiler.labelers.char_load_tf_model":{CharLoadTFModel:[23,1,1,""]},"dataprofiler.labelers.char_load_tf_model.CharLoadTFModel":{add_label:[23,4,1,""],details:[23,4,1,""],fit:[23,4,1,""],get_class:[23,4,1,""],get_parameters:[23,4,1,""],help:[23,4,1,""],label_mapping:[23,2,1,""],labels:[23,2,1,""],load_from_disk:[23,4,1,""],num_labels:[23,2,1,""],predict:[23,4,1,""],requires_zero_mapping:[23,3,1,""],reset_weights:[23,4,1,""],reverse_label_mapping:[23,2,1,""],save_to_disk:[23,4,1,""],set_label_mapping:[23,4,1,""],set_params:[23,4,1,""]},"dataprofiler.labelers.character_level_cnn_model":{CharacterLevelCnnModel:[24,1,1,""],build_embd_dictionary:[24,5,1,""],create_glove_char:[24,5,1,""]},"dataprofiler.labelers.character_level_cnn_model.CharacterLevelCnnModel":{add_label:[24,4,1,""],details:[24,4,1,""],fit:[24,4,1,""],get_class:[24,4,1,""],get_parameters:[24,4,1,""],help:[24,4,1,""],label_mapping:[24,2,1,""],labels:[24,2,1,""],load_from_disk:[24,4,1,""],num_labels:[24,2,1,""],predict:[24,4,1,""],requires_zero_mapping:[24,3,1,""],reset_weights:[24,4,1,""],reverse_label_mapping:[24,2,1,""],save_to_disk:[24,4,1,""],set_label_mapping:[24,4,1,""],set_params:[24,4,1,""]},"dataprofiler.labelers.classification_report_utils":{classification_report:[25,5,1,""],convert_confusion_matrix_to_MCM:[25,5,1,""],precision_recall_fscore_support:[25,5,1,""]},"dataprofiler.labelers.column_name_model":{ColumnNameModel:[26,1,1,""]},"dataprofiler.labelers.column_name_model.ColumnNameModel":{add_label:[26,4,1,""],get_class:[26,4,1,""],get_parameters:[26,4,1,""],help:[26,4,1,""],label_mapping:[26,2,1,""],labels:[26,2,1,""],load_from_disk:[26,4,1,""],num_labels:[26,2,1,""],predict:[26,4,1,""],requires_zero_mapping:[26,3,1,""],reset_weights:[26,4,1,""],reverse_label_mapping:[26,2,1,""],save_to_disk:[26,4,1,""],set_label_mapping:[26,4,1,""],set_params:[26,4,1,""]},"dataprofiler.labelers.data_labelers":{DataLabeler:[27,1,1,""],StructuredDataLabeler:[27,1,1,""],UnstructuredDataLabeler:[27,1,1,""],train_structured_labeler:[27,5,1,""]},"dataprofiler.labelers.data_labelers.DataLabeler":{labeler_classes:[27,3,1,""],load_from_disk:[27,4,1,""],load_from_library:[27,4,1,""],load_with_components:[27,4,1,""]},"dataprofiler.labelers.data_labelers.StructuredDataLabeler":{add_label:[27,4,1,""],check_pipeline:[27,4,1,""],help:[27,4,1,""],label_mapping:[27,2,1,""],labels:[27,2,1,""],load_from_disk:[27,4,1,""],load_from_library:[27,4,1,""],load_with_components:[27,4,1,""],model:[27,2,1,""],postprocessor:[27,2,1,""],predict:[27,4,1,""],preprocessor:[27,2,1,""],reverse_label_mapping:[27,2,1,""],save_to_disk:[27,4,1,""],set_labels:[27,4,1,""],set_model:[27,4,1,""],set_params:[27,4,1,""],set_postprocessor:[27,4,1,""],set_preprocessor:[27,4,1,""]},"dataprofiler.labelers.data_labelers.UnstructuredDataLabeler":{add_label:[27,4,1,""],check_pipeline:[27,4,1,""],help:[27,4,1,""],label_mapping:[27,2,1,""],labels:[27,2,1,""],load_from_disk:[27,4,1,""],load_from_library:[27,4,1,""],load_with_components:[27,4,1,""],model:[27,2,1,""],postprocessor:[27,2,1,""],predict:[27,4,1,""],preprocessor:[27,2,1,""],reverse_label_mapping:[27,2,1,""],save_to_disk:[27,4,1,""],set_labels:[27,4,1,""],set_model:[27,4,1,""],set_params:[27,4,1,""],set_postprocessor:[27,4,1,""],set_preprocessor:[27,4,1,""]},"dataprofiler.labelers.data_processing":{AutoSubRegistrationMeta:[28,1,1,""],BaseDataPostprocessor:[28,1,1,""],BaseDataPreprocessor:[28,1,1,""],BaseDataProcessor:[28,1,1,""],CharEncodedPreprocessor:[28,1,1,""],CharPostprocessor:[28,1,1,""],CharPreprocessor:[28,1,1,""],ColumnNameModelPostprocessor:[28,1,1,""],DirectPassPreprocessor:[28,1,1,""],RegexPostProcessor:[28,1,1,""],StructCharPostprocessor:[28,1,1,""],StructCharPreprocessor:[28,1,1,""],StructRegexPostProcessor:[28,1,1,""]},"dataprofiler.labelers.data_processing.AutoSubRegistrationMeta":{mro:[28,4,1,""],register:[28,4,1,""]},"dataprofiler.labelers.data_processing.BaseDataPostprocessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.BaseDataPreprocessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.BaseDataProcessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.CharEncodedPreprocessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.CharPostprocessor":{convert_to_NER_format:[28,4,1,""],get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],match_sentence_lengths:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.CharPreprocessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.ColumnNameModelPostprocessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.DirectPassPreprocessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.RegexPostProcessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],priority_prediction:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""],split_prediction:[28,4,1,""]},"dataprofiler.labelers.data_processing.StructCharPostprocessor":{convert_to_structured_analysis:[28,4,1,""],get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],match_sentence_lengths:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.StructCharPreprocessor":{convert_to_unstructured_format:[28,4,1,""],get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.data_processing.StructRegexPostProcessor":{get_class:[28,4,1,""],get_parameters:[28,4,1,""],help:[28,4,1,""],load_from_disk:[28,4,1,""],load_from_library:[28,4,1,""],process:[28,4,1,""],processor_type:[28,3,1,""],save_to_disk:[28,4,1,""],set_params:[28,4,1,""]},"dataprofiler.labelers.labeler_utils":{F1Score:[29,1,1,""],FBetaScore:[29,1,1,""],evaluate_accuracy:[29,5,1,""],f1_report_dict_to_str:[29,5,1,""],get_tf_layer_index_from_name:[29,5,1,""],hide_tf_logger_warnings:[29,5,1,""],protected_register_keras_serializable:[29,5,1,""]},"dataprofiler.labelers.labeler_utils.F1Score":{activity_regularizer:[29,2,1,""],add_loss:[29,4,1,""],add_metric:[29,4,1,""],add_update:[29,4,1,""],add_variable:[29,4,1,""],add_weight:[29,4,1,""],build:[29,4,1,""],build_from_config:[29,4,1,""],call:[29,4,1,""],compute_dtype:[29,2,1,""],compute_mask:[29,4,1,""],compute_output_shape:[29,4,1,""],compute_output_signature:[29,4,1,""],count_params:[29,4,1,""],dtype:[29,2,1,""],dtype_policy:[29,2,1,""],dynamic:[29,2,1,""],finalize_state:[29,4,1,""],from_config:[29,4,1,""],get_build_config:[29,4,1,""],get_config:[29,4,1,""],get_input_at:[29,4,1,""],get_input_mask_at:[29,4,1,""],get_input_shape_at:[29,4,1,""],get_output_at:[29,4,1,""],get_output_mask_at:[29,4,1,""],get_output_shape_at:[29,4,1,""],get_weights:[29,4,1,""],inbound_nodes:[29,2,1,""],input:[29,2,1,""],input_mask:[29,2,1,""],input_shape:[29,2,1,""],input_spec:[29,2,1,""],load_own_variables:[29,4,1,""],losses:[29,2,1,""],merge_state:[29,4,1,""],metrics:[29,2,1,""],name:[29,2,1,""],name_scope:[29,2,1,""],non_trainable_variables:[29,2,1,""],non_trainable_weights:[29,2,1,""],outbound_nodes:[29,2,1,""],output:[29,2,1,""],output_mask:[29,2,1,""],output_shape:[29,2,1,""],reset_state:[29,4,1,""],reset_states:[29,4,1,""],result:[29,4,1,""],save_own_variables:[29,4,1,""],set_weights:[29,4,1,""],stateful:[29,2,1,""],submodules:[29,2,1,""],supports_masking:[29,2,1,""],trainable:[29,2,1,""],trainable_variables:[29,2,1,""],trainable_weights:[29,2,1,""],update_state:[29,4,1,""],updates:[29,2,1,""],variable_dtype:[29,2,1,""],variables:[29,2,1,""],weights:[29,2,1,""],with_name_scope:[29,4,1,""]},"dataprofiler.labelers.labeler_utils.FBetaScore":{activity_regularizer:[29,2,1,""],add_loss:[29,4,1,""],add_metric:[29,4,1,""],add_update:[29,4,1,""],add_variable:[29,4,1,""],add_weight:[29,4,1,""],build:[29,4,1,""],build_from_config:[29,4,1,""],call:[29,4,1,""],compute_dtype:[29,2,1,""],compute_mask:[29,4,1,""],compute_output_shape:[29,4,1,""],compute_output_signature:[29,4,1,""],count_params:[29,4,1,""],dtype:[29,2,1,""],dtype_policy:[29,2,1,""],dynamic:[29,2,1,""],finalize_state:[29,4,1,""],from_config:[29,4,1,""],get_build_config:[29,4,1,""],get_config:[29,4,1,""],get_input_at:[29,4,1,""],get_input_mask_at:[29,4,1,""],get_input_shape_at:[29,4,1,""],get_output_at:[29,4,1,""],get_output_mask_at:[29,4,1,""],get_output_shape_at:[29,4,1,""],get_weights:[29,4,1,""],inbound_nodes:[29,2,1,""],input:[29,2,1,""],input_mask:[29,2,1,""],input_shape:[29,2,1,""],input_spec:[29,2,1,""],load_own_variables:[29,4,1,""],losses:[29,2,1,""],merge_state:[29,4,1,""],metrics:[29,2,1,""],name:[29,2,1,""],name_scope:[29,2,1,""],non_trainable_variables:[29,2,1,""],non_trainable_weights:[29,2,1,""],outbound_nodes:[29,2,1,""],output:[29,2,1,""],output_mask:[29,2,1,""],output_shape:[29,2,1,""],reset_state:[29,4,1,""],reset_states:[29,4,1,""],result:[29,4,1,""],save_own_variables:[29,4,1,""],set_weights:[29,4,1,""],stateful:[29,2,1,""],submodules:[29,2,1,""],supports_masking:[29,2,1,""],trainable:[29,2,1,""],trainable_variables:[29,2,1,""],trainable_weights:[29,2,1,""],update_state:[29,4,1,""],updates:[29,2,1,""],variable_dtype:[29,2,1,""],variables:[29,2,1,""],weights:[29,2,1,""],with_name_scope:[29,4,1,""]},"dataprofiler.labelers.regex_model":{RegexModel:[30,1,1,""]},"dataprofiler.labelers.regex_model.RegexModel":{add_label:[30,4,1,""],get_class:[30,4,1,""],get_parameters:[30,4,1,""],help:[30,4,1,""],label_mapping:[30,2,1,""],labels:[30,2,1,""],load_from_disk:[30,4,1,""],num_labels:[30,2,1,""],predict:[30,4,1,""],requires_zero_mapping:[30,3,1,""],reset_weights:[30,4,1,""],reverse_label_mapping:[30,2,1,""],save_to_disk:[30,4,1,""],set_label_mapping:[30,4,1,""],set_params:[30,4,1,""]},"dataprofiler.labelers.utils":{require_module:[31,5,1,""],warn_missing_module:[31,5,1,""]},"dataprofiler.profilers":{base_column_profilers:[33,0,0,"-"],categorical_column_profile:[34,0,0,"-"],column_profile_compilers:[35,0,0,"-"],data_labeler_column_profile:[36,0,0,"-"],datetime_column_profile:[37,0,0,"-"],float_column_profile:[38,0,0,"-"],graph_profiler:[39,0,0,"-"],helpers:[40,0,0,"-"],histogram_utils:[42,0,0,"-"],int_column_profile:[43,0,0,"-"],json_decoder:[44,0,0,"-"],json_encoder:[45,0,0,"-"],numerical_column_stats:[46,0,0,"-"],order_column_profile:[47,0,0,"-"],profile_builder:[48,0,0,"-"],profiler_options:[49,0,0,"-"],profiler_utils:[50,0,0,"-"],text_column_profile:[51,0,0,"-"],unstructured_labeler_profile:[52,0,0,"-"],unstructured_text_profile:[53,0,0,"-"]},"dataprofiler.profilers.base_column_profilers":{BaseColumnPrimitiveTypeProfiler:[33,1,1,""],BaseColumnProfiler:[33,1,1,""]},"dataprofiler.profilers.base_column_profilers.BaseColumnPrimitiveTypeProfiler":{col_type:[33,3,1,""],diff:[33,4,1,""],load_from_dict:[33,4,1,""],metadata:[33,3,1,""],name:[33,3,1,""],profile:[33,2,1,""],report:[33,4,1,""],sample_size:[33,3,1,""],thread_safe:[33,3,1,""],times:[33,3,1,""],update:[33,4,1,""]},"dataprofiler.profilers.base_column_profilers.BaseColumnProfiler":{col_type:[33,3,1,""],diff:[33,4,1,""],load_from_dict:[33,4,1,""],profile:[33,2,1,""],report:[33,4,1,""],update:[33,4,1,""]},"dataprofiler.profilers.categorical_column_profile":{CategoricalColumn:[34,1,1,""]},"dataprofiler.profilers.categorical_column_profile.CategoricalColumn":{categorical_counts:[34,2,1,""],categories:[34,2,1,""],col_type:[34,3,1,""],diff:[34,4,1,""],gini_impurity:[34,2,1,""],is_match:[34,2,1,""],load_from_dict:[34,4,1,""],metadata:[34,3,1,""],name:[34,3,1,""],profile:[34,2,1,""],report:[34,4,1,""],sample_size:[34,3,1,""],thread_safe:[34,3,1,""],times:[34,3,1,""],type:[34,3,1,""],unalikeability:[34,2,1,""],unique_count:[34,2,1,""],unique_ratio:[34,2,1,""],update:[34,4,1,""]},"dataprofiler.profilers.column_profile_compilers":{BaseCompiler:[35,1,1,""],ColumnDataLabelerCompiler:[35,1,1,""],ColumnPrimitiveTypeProfileCompiler:[35,1,1,""],ColumnStatsProfileCompiler:[35,1,1,""],UnstructuredCompiler:[35,1,1,""]},"dataprofiler.profilers.column_profile_compilers.BaseCompiler":{diff:[35,4,1,""],load_from_dict:[35,4,1,""],profile:[35,2,1,""],report:[35,4,1,""],update_profile:[35,4,1,""]},"dataprofiler.profilers.column_profile_compilers.ColumnDataLabelerCompiler":{diff:[35,4,1,""],load_from_dict:[35,4,1,""],profile:[35,2,1,""],report:[35,4,1,""],update_profile:[35,4,1,""]},"dataprofiler.profilers.column_profile_compilers.ColumnPrimitiveTypeProfileCompiler":{diff:[35,4,1,""],load_from_dict:[35,4,1,""],profile:[35,2,1,""],report:[35,4,1,""],selected_data_type:[35,2,1,""],update_profile:[35,4,1,""]},"dataprofiler.profilers.column_profile_compilers.ColumnStatsProfileCompiler":{diff:[35,4,1,""],load_from_dict:[35,4,1,""],profile:[35,2,1,""],report:[35,4,1,""],update_profile:[35,4,1,""]},"dataprofiler.profilers.column_profile_compilers.UnstructuredCompiler":{diff:[35,4,1,""],load_from_dict:[35,4,1,""],profile:[35,2,1,""],report:[35,4,1,""],update_profile:[35,4,1,""]},"dataprofiler.profilers.data_labeler_column_profile":{DataLabelerColumn:[36,1,1,""]},"dataprofiler.profilers.data_labeler_column_profile.DataLabelerColumn":{assert_equal_conditions:[36,4,1,""],avg_predictions:[36,2,1,""],col_type:[36,3,1,""],data_label:[36,2,1,""],diff:[36,4,1,""],label_representation:[36,2,1,""],load_from_dict:[36,4,1,""],metadata:[36,3,1,""],name:[36,3,1,""],possible_data_labels:[36,2,1,""],profile:[36,2,1,""],rank_distribution:[36,2,1,""],report:[36,4,1,""],reverse_label_mapping:[36,2,1,""],sample_size:[36,3,1,""],sum_predictions:[36,2,1,""],thread_safe:[36,3,1,""],times:[36,3,1,""],type:[36,3,1,""],update:[36,4,1,""]},"dataprofiler.profilers.datetime_column_profile":{DateTimeColumn:[37,1,1,""]},"dataprofiler.profilers.datetime_column_profile.DateTimeColumn":{col_type:[37,3,1,""],data_type_ratio:[37,2,1,""],diff:[37,4,1,""],load_from_dict:[37,4,1,""],match_count:[37,3,1,""],metadata:[37,3,1,""],name:[37,3,1,""],profile:[37,2,1,""],report:[37,4,1,""],sample_size:[37,3,1,""],thread_safe:[37,3,1,""],times:[37,3,1,""],type:[37,3,1,""],update:[37,4,1,""]},"dataprofiler.profilers.float_column_profile":{FloatColumn:[38,1,1,""]},"dataprofiler.profilers.float_column_profile.FloatColumn":{col_type:[38,3,1,""],data_type_ratio:[38,2,1,""],diff:[38,4,1,""],is_float:[38,4,1,""],is_int:[38,4,1,""],kurtosis:[38,2,1,""],load_from_dict:[38,4,1,""],match_count:[38,3,1,""],mean:[38,2,1,""],median:[38,2,1,""],median_abs_deviation:[38,2,1,""],metadata:[38,3,1,""],mode:[38,2,1,""],name:[38,3,1,""],np_type_to_type:[38,4,1,""],precision:[38,2,1,""],profile:[38,2,1,""],report:[38,4,1,""],sample_size:[38,3,1,""],skewness:[38,2,1,""],stddev:[38,2,1,""],thread_safe:[38,3,1,""],times:[38,3,1,""],type:[38,3,1,""],update:[38,4,1,""],variance:[38,2,1,""]},"dataprofiler.profilers.graph_profiler":{GraphProfiler:[39,1,1,""]},"dataprofiler.profilers.graph_profiler.GraphProfiler":{diff:[39,4,1,""],load:[39,4,1,""],profile:[39,2,1,""],report:[39,4,1,""],save:[39,4,1,""],times:[39,3,1,""],update:[39,4,1,""]},"dataprofiler.profilers.helpers":{calculate_quantiles:[40,5,1,""],report_helpers:[41,0,0,"-"]},"dataprofiler.profilers.helpers.report_helpers":{calculate_quantiles:[41,5,1,""],flat_dict:[41,5,1,""]},"dataprofiler.profilers.int_column_profile":{IntColumn:[43,1,1,""]},"dataprofiler.profilers.int_column_profile.IntColumn":{col_type:[43,3,1,""],data_type_ratio:[43,2,1,""],diff:[43,4,1,""],is_float:[43,4,1,""],is_int:[43,4,1,""],kurtosis:[43,2,1,""],load_from_dict:[43,4,1,""],match_count:[43,3,1,""],mean:[43,2,1,""],median:[43,2,1,""],median_abs_deviation:[43,2,1,""],metadata:[43,3,1,""],mode:[43,2,1,""],name:[43,3,1,""],np_type_to_type:[43,4,1,""],profile:[43,2,1,""],report:[43,4,1,""],sample_size:[43,3,1,""],skewness:[43,2,1,""],stddev:[43,2,1,""],thread_safe:[43,3,1,""],times:[43,3,1,""],type:[43,3,1,""],update:[43,4,1,""],variance:[43,2,1,""]},"dataprofiler.profilers.json_decoder":{get_column_profiler_class:[44,5,1,""],get_compiler_class:[44,5,1,""],get_option_class:[44,5,1,""],get_profiler_class:[44,5,1,""],get_structured_col_profiler_class:[44,5,1,""],load_column_profile:[44,5,1,""],load_compiler:[44,5,1,""],load_option:[44,5,1,""],load_profiler:[44,5,1,""],load_structured_col_profiler:[44,5,1,""]},"dataprofiler.profilers.json_encoder":{ProfileEncoder:[45,1,1,""]},"dataprofiler.profilers.json_encoder.ProfileEncoder":{"default":[45,4,1,""],encode:[45,4,1,""],item_separator:[45,3,1,""],iterencode:[45,4,1,""],key_separator:[45,3,1,""]},"dataprofiler.profilers.numerical_column_stats":{NumericStatsMixin:[46,1,1,""],abstractstaticmethod:[46,1,1,""]},"dataprofiler.profilers.numerical_column_stats.NumericStatsMixin":{col_type:[46,3,1,""],diff:[46,4,1,""],is_float:[46,4,1,""],is_int:[46,4,1,""],kurtosis:[46,2,1,""],load_from_dict:[46,4,1,""],mean:[46,2,1,""],median:[46,2,1,""],median_abs_deviation:[46,2,1,""],metadata:[46,3,1,""],mode:[46,2,1,""],name:[46,3,1,""],np_type_to_type:[46,4,1,""],profile:[46,4,1,""],report:[46,4,1,""],sample_size:[46,3,1,""],skewness:[46,2,1,""],stddev:[46,2,1,""],thread_safe:[46,3,1,""],times:[46,3,1,""],type:[46,3,1,""],update:[46,4,1,""],variance:[46,2,1,""]},"dataprofiler.profilers.order_column_profile":{Comparable:[47,1,1,""],OrderColumn:[47,1,1,""]},"dataprofiler.profilers.order_column_profile.OrderColumn":{col_type:[47,3,1,""],diff:[47,4,1,""],load_from_dict:[47,4,1,""],metadata:[47,3,1,""],name:[47,3,1,""],profile:[47,2,1,""],report:[47,4,1,""],sample_size:[47,3,1,""],thread_safe:[47,3,1,""],times:[47,3,1,""],type:[47,3,1,""],update:[47,4,1,""]},"dataprofiler.profilers.profile_builder":{BaseProfiler:[48,1,1,""],Profiler:[48,1,1,""],StructuredColProfiler:[48,1,1,""],StructuredProfiler:[48,1,1,""],UnstructuredProfiler:[48,1,1,""]},"dataprofiler.profilers.profile_builder.BaseProfiler":{diff:[48,4,1,""],load:[48,4,1,""],load_from_dict:[48,4,1,""],profile:[48,2,1,""],report:[48,4,1,""],save:[48,4,1,""],update_profile:[48,4,1,""]},"dataprofiler.profilers.profile_builder.Profiler":{load:[48,4,1,""]},"dataprofiler.profilers.profile_builder.StructuredColProfiler":{clean_data_and_get_base_stats:[48,4,1,""],diff:[48,4,1,""],load_from_dict:[48,4,1,""],profile:[48,2,1,""],report:[48,4,1,""],update_column_profilers:[48,4,1,""],update_profile:[48,4,1,""]},"dataprofiler.profilers.profile_builder.StructuredProfiler":{diff:[48,4,1,""],load:[48,4,1,""],load_from_dict:[48,4,1,""],profile:[48,2,1,""],report:[48,4,1,""],save:[48,4,1,""],update_profile:[48,4,1,""]},"dataprofiler.profilers.profile_builder.UnstructuredProfiler":{diff:[48,4,1,""],load:[48,4,1,""],load_from_dict:[48,4,1,""],profile:[48,2,1,""],report:[48,4,1,""],save:[48,4,1,""],update_profile:[48,4,1,""]},"dataprofiler.profilers.profiler_options":{BaseInspectorOptions:[49,1,1,""],BaseOption:[49,1,1,""],BooleanOption:[49,1,1,""],CategoricalOptions:[49,1,1,""],CorrelationOptions:[49,1,1,""],DataLabelerOptions:[49,1,1,""],DateTimeOptions:[49,1,1,""],FloatOptions:[49,1,1,""],HistogramAndQuantilesOption:[49,1,1,""],HyperLogLogOptions:[49,1,1,""],IntOptions:[49,1,1,""],ModeOption:[49,1,1,""],NumericalOptions:[49,1,1,""],OrderOptions:[49,1,1,""],PrecisionOptions:[49,1,1,""],ProfilerOptions:[49,1,1,""],RowStatisticsOptions:[49,1,1,""],StructuredOptions:[49,1,1,""],TextOptions:[49,1,1,""],TextProfilerOptions:[49,1,1,""],UniqueCountOptions:[49,1,1,""],UnstructuredOptions:[49,1,1,""]},"dataprofiler.profilers.profiler_options.BaseInspectorOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.BaseOption":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.BooleanOption":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.CategoricalOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.CorrelationOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.DataLabelerOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.DateTimeOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.FloatOptions":{is_numeric_stats_enabled:[49,2,1,""],is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.HistogramAndQuantilesOption":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.HyperLogLogOptions":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.IntOptions":{is_numeric_stats_enabled:[49,2,1,""],is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.ModeOption":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.NumericalOptions":{is_numeric_stats_enabled:[49,2,1,""],is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.OrderOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.PrecisionOptions":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.ProfilerOptions":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.RowStatisticsOptions":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.StructuredOptions":{enabled_profiles:[49,2,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.TextOptions":{is_numeric_stats_enabled:[49,2,1,""],is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.TextProfilerOptions":{is_prop_enabled:[49,4,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.UniqueCountOptions":{load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_options.UnstructuredOptions":{enabled_profiles:[49,2,1,""],load_from_dict:[49,4,1,""],properties:[49,2,1,""],set:[49,4,1,""],validate:[49,4,1,""]},"dataprofiler.profilers.profiler_utils":{KeyDict:[50,1,1,""],Subtractable:[50,1,1,""],add_nested_dictionaries:[50,5,1,""],auto_multiprocess_toggle:[50,5,1,""],biased_kurt:[50,5,1,""],biased_skew:[50,5,1,""],chunk:[50,5,1,""],find_diff_of_dates:[50,5,1,""],find_diff_of_dicts:[50,5,1,""],find_diff_of_dicts_with_diff_keys:[50,5,1,""],find_diff_of_lists_and_sets:[50,5,1,""],find_diff_of_matrices:[50,5,1,""],find_diff_of_numbers:[50,5,1,""],find_diff_of_strings_and_bools:[50,5,1,""],generate_pool:[50,5,1,""],get_memory_size:[50,5,1,""],merge:[50,5,1,""],merge_profile_list:[50,5,1,""],method_timeit:[50,5,1,""],overlap:[50,5,1,""],partition:[50,5,1,""],perform_chi_squared_test_for_homogeneity:[50,5,1,""],recursive_dict_update:[50,5,1,""],reload_labeler_from_options_or_get_new:[50,5,1,""],shuffle_in_chunks:[50,5,1,""],suggest_pool_size:[50,5,1,""],warn_on_profile:[50,5,1,""]},"dataprofiler.profilers.profiler_utils.KeyDict":{clear:[50,4,1,""],copy:[50,4,1,""],default_factory:[50,3,1,""],fromkeys:[50,4,1,""],get:[50,4,1,""],items:[50,4,1,""],keys:[50,4,1,""],pop:[50,4,1,""],popitem:[50,4,1,""],setdefault:[50,4,1,""],update:[50,4,1,""],values:[50,4,1,""]},"dataprofiler.profilers.text_column_profile":{TextColumn:[51,1,1,""]},"dataprofiler.profilers.text_column_profile.TextColumn":{bias_correction:[51,3,1,""],col_type:[51,3,1,""],data_type_ratio:[51,2,1,""],diff:[51,4,1,""],histogram_bin_method_names:[51,3,1,""],histogram_methods:[51,3,1,""],histogram_selection:[51,3,1,""],is_float:[51,4,1,""],is_int:[51,4,1,""],kurtosis:[51,2,1,""],load_from_dict:[51,4,1,""],match_count:[51,3,1,""],max:[51,3,1,""],max_histogram_bin:[51,3,1,""],mean:[51,2,1,""],median:[51,2,1,""],median_abs_deviation:[51,2,1,""],metadata:[51,3,1,""],min:[51,3,1,""],min_histogram_bin:[51,3,1,""],mode:[51,2,1,""],name:[51,3,1,""],np_type_to_type:[51,4,1,""],num_negatives:[51,3,1,""],num_zeros:[51,3,1,""],profile:[51,2,1,""],quantiles:[51,3,1,""],report:[51,4,1,""],sample_size:[51,3,1,""],skewness:[51,2,1,""],stddev:[51,2,1,""],sum:[51,3,1,""],thread_safe:[51,3,1,""],times:[51,3,1,""],type:[51,3,1,""],update:[51,4,1,""],user_set_histogram_bin:[51,3,1,""],variance:[51,2,1,""]},"dataprofiler.profilers.unstructured_labeler_profile":{UnstructuredLabelerProfile:[52,1,1,""]},"dataprofiler.profilers.unstructured_labeler_profile.UnstructuredLabelerProfile":{diff:[52,4,1,""],label_encoding:[52,2,1,""],profile:[52,2,1,""],report:[52,4,1,""],type:[52,3,1,""],update:[52,4,1,""]},"dataprofiler.profilers.unstructured_text_profile":{TextProfiler:[53,1,1,""]},"dataprofiler.profilers.unstructured_text_profile.TextProfiler":{diff:[53,4,1,""],profile:[53,2,1,""],report:[53,4,1,""],type:[53,3,1,""],update:[53,4,1,""]},"dataprofiler.reports":{graphs:[56,0,0,"-"],utils:[57,0,0,"-"]},"dataprofiler.reports.utils":{require_module:[57,5,1,""],warn_missing_module:[57,5,1,""]},"dataprofiler.rng_utils":{get_random_number_generator:[58,5,1,""]},"dataprofiler.validators":{base_validators:[61,0,0,"-"]},"dataprofiler.validators.base_validators":{Validator:[61,1,1,""],is_in_list:[61,5,1,""],is_in_range:[61,5,1,""]},"dataprofiler.validators.base_validators.Validator":{get:[61,4,1,""],validate:[61,4,1,""]},dataprofiler:{data_readers:[7,0,0,"-"],dp_logging:[19,0,0,"-"],labelers:[20,0,0,"-"],profilers:[32,0,0,"-"],reports:[55,0,0,"-"],rng_utils:[58,0,0,"-"],set_seed:[6,5,1,""],settings:[59,0,0,"-"],validators:[60,0,0,"-"],version:[62,0,0,"-"]}},objnames:{"0":["py","module","Python module"],"1":["py","class","Python class"],"2":["py","property","Python property"],"3":["py","attribute","Python attribute"],"4":["py","method","Python method"],"5":["py","function","Python function"]},objtypes:{"0":"py:module","1":"py:class","2":"py:property","3":"py:attribute","4":"py:method","5":"py:function"},terms:{"0":[1,2,3,4,5,12,13,14,21,25,28,29,34,38,43,45,46,48,49,51,64,65,66,67,68,69,71,72,73,74,75,76],"00":[12,29,38,43,46,51],"000":[66,73,74],"000043219499392912":3,"01":[49,50,73],"02":72,"05":4,"07":[4,68,72],"0700":68,"0f":68,"0m":4,"0s":1,"1":[1,2,4,5,12,14,21,25,28,29,34,36,38,43,46,49,51,61,65,66,68,69,71,73,74,75],"10":[3,4,12,29,65,66,68,72,73],"100":[2,68,74],"1000":[10,15,49,71,73,74],"10000":[66,73],"1024":12,"108":4,"11":[4,66,68],"11111111":68,"1111111111111":68,"116":4,"12":29,"123":[68,75],"1234":3,"127":1,"13":[4,68],"15":[4,49,71],"16":[68,74],"177":4,"18":[3,66],"180":4,"1w":72,"2":[1,2,3,4,21,25,27,29,34,35,48,49,50,61,65,66,68,69,71,73,74,75],"20":[12,29,50,73],"200":5,"2004":25,"2005":[34,68],"2014":4,"2015":72,"2018":50,"2019":29,"202":75,"2020":65,"2021":65,"21":4,"22":25,"225":4,"23":4,"27":34,"289":4,"29":4,"2x2":25,"3":[2,3,4,25,29,61,65,66,68,69,71,72,73,74,75],"30":[25,29],"301":3,"31":[4,68],"31m":4,"32":[1,21,23,24,27,28],"326":4,"327":4,"33":29,"334":4,"335":4,"34":4,"3400":[1,28],"35":4,"37":68,"3f":68,"3x":76,"4":[0,2,4,29,65,66,68,69,71,73,74,75,76],"40":29,"429":4,"43":4,"4448069":4,"454":4,"456":68,"458":4,"5":[4,25,49,50,65,66,73],"50":[2,29,75],"5000":[28,48,49],"55":4,"56":4,"57":29,"58":[4,34],"59":4,"6":[64,66,74],"60":[15,29,34],"61":4,"62":4,"63":4,"63359209":4,"64":1,"65":4,"65064207":4,"65536":12,"67":[25,29],"7":[4,64,66,68,72],"75":[4,28,29],"750":73,"750000":50,"76715529":4,"7890":68,"79":4,"79556889":4,"7bit":68,"8":[4,12,14,66,73,74],"80":[4,29,38,43,46,51,75],"81":4,"83":4,"84":4,"85":[2,71],"89":4,"9":[4,66,72,75],"92m":4,"95":[4,49,73],"97":3,"98":4,"9959787":4,"\u03c3":34,"abstract":[3,9,21,22,28,33,34,35,36,37,46,47,48],"boolean":[1,2,5,12,13,29,33,34,35,36,37,43,47,49,52,73],"break":1,"byte":12,"case":[1,4,25,28,29,47,49,50,51,66,72,73,75],"char":[6,12,20,22,24,26,28,30,66,74,75,76],"class":[1,3,4,5,8,9,10,11,13,14,15,16,17,18,20,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,43,44,45,46,47,48,49,50,51,52,53,61,63,64,66,68,73,74,76],"default":[1,2,3,4,5,10,25,26,28,29,44,45,48,49,50,64,66,67,68,72,73,75],"do":[29,31,49,57,65,72],"final":[1,2,24,29,72],"float":[1,3,6,12,21,22,23,24,25,28,29,32,34,36,37,39,43,45,46,47,48,49,50,51,61,64,65,66,68,73,74,76],"function":[1,3,4,12,13,17,21,25,26,28,29,31,38,39,40,41,42,43,45,46,49,50,51,56,57,64,65,68,69,71,72,73,74,75,76],"import":[1,2,3,4,5,45,63,64,66,68,71,72,73,74,75,76],"int":[1,5,6,8,9,10,12,13,14,15,16,18,19,21,22,23,24,25,26,27,28,29,30,32,33,34,36,37,38,40,41,45,46,47,48,49,50,51,61,65,66,68,71,73,74,76],"long":1,"new":[8,9,10,14,15,16,18,21,22,23,24,26,27,30,34,50,63,64,66,68,69,73,74,76],"null":[46,48,49,66,71,72,73,74,76],"return":[1,2,4,5,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,57,61,66,68,72,73,74,76],"short":1,"static":[28,36,38,43,46,48,51],"super":[29,72],"switch":[68,72],"true":[1,2,3,4,5,9,12,13,18,21,22,23,24,25,26,27,28,29,30,34,38,43,45,46,49,50,51,64,66,68,72,73,75,76],"try":[2,4,29,64,68,69,71,72,74,75,76],"var":[66,74],"while":[1,3,4,25,71,75],A:[5,25,26,28,29,30,42,49,63,66,71,73,74,75],AS:29,And:69,As:[2,4,29,42,68,71,74,76],At:15,By:[3,4,25,29,68,73],For:[2,3,4,5,22,23,25,28,29,34,35,38,43,45,46,48,49,50,51,53,61,64,67,68,71,73,74,75,76],IS:[29,75],If:[12,25,29,31,36,45,49,50,57,64,65,66,67,72,73],In:[1,2,3,4,12,25,28,29,50,66,68,71,73,74,75,76],Is:4,It:[3,5,29,45,64,66,68,74,76],NOT:29,No:[34,61,73],Not:[74,76],OF:29,OR:[12,29],One:[71,73,74,76],Or:[6,7],Such:[74,76],The:[0,1,2,3,4,5,12,20,25,29,45,48,49,50,61,64,65,66,67,68,71,72,73,74,75,76],There:[4,66,68,73],These:[4,29,63,65,76],To:[3,45,66,67,68,71,72,74,75,76],Will:[3,49],With:[65,73,74,76],_:[29,41],__calcul:[39,46],__call__:29,__class__:[2,75],__init__:[1,3,29],__missing__:50,__name__:[2,44,75],_argmax_threshold_lay:1,_char_encoding_lay:1,_construct_model:[1,3],_epoch_id:1,_gener:58,_io:[8,11,12,13,15,16],_model:1,_model_default_ind:1,_model_num_label:1,_need_to_reconstruct_model:3,_one_shot:45,_paramet:[1,2,75],_postprocessor:1,_preprocessor:1,_pull:72,_reconstruct_model:3,_save_processor:3,_validate_paramet:[1,3],a_natural_but_biased_estim:50,a_out:29,ab:29,abc:[4,22,28,68],abcmeta:[22,28],abil:[4,66,71,74,76],abl:[3,21,29,64,68],about:[3,4,66,68,74,76],abov:[1,5,29,64,66,67,68,73],absolut:[38,43,46,51,73],abstractstaticmethod:46,acc:1,accept:[1,3,14,29,73],access:[5,19,29,63,66,73],accomplish:[74,76],accord:73,account:[3,25,50,66],accur:74,accuraci:[25,29,68],achiev:[2,75],across:[28,29,61,73],activ:[1,4,29,67,73],activity_regular:29,actual:72,ad:[12,21,22,23,24,26,27,29,30,48,63,74,76],adam:1,adapt:[1,29],add:[1,3,17,21,22,23,24,26,27,29,30,50,66,68,74,76],add_label:[3,21,22,23,24,26,27,30,68],add_loss:29,add_metr:29,add_nested_dictionari:50,add_true_false_color:4,add_upd:29,add_vari:29,add_weight:29,addit:[1,4,12,29,66,68,71,73,74,76],addition:[4,5,48,65,71,75],addon:29,address:[2,3,66,68,75],adjust:[63,73],advanc:25,aforement:71,after:[29,63,64,71,75],again:[2,29,64,68],against:29,aggreg:[28,29,75],aggregation_func:[28,75],agre:29,ahead:72,algorithm:4,alia:29,all:[1,4,8,9,10,12,14,15,16,18,22,23,24,25,26,28,29,30,36,45,48,49,50,51,65,67,68,69,71,72,73,74],all_fil:[4,71],alloc:50,allow:[3,4,19,21,22,27,28,29,48,50,68,71,72,73,74,75,76],allow_nan:45,alon:75,along:[46,48,61,66,73],alreadi:[1,29,67],also:[1,3,4,5,8,10,14,15,16,18,25,29,49,61,64,65,66,68,71,73,74,75,76],alter:[19,21,22,23,24,25,26,27,28,30,63,73],altern:[49,73,74,76],although:[29,49,73],alwai:[13,51],amount:73,an:[1,4,8,9,10,12,14,15,16,17,18,22,25,28,29,30,34,38,43,45,46,47,50,51,61,64,66,68,69,71,72,73,74,76],analysi:[28,38,43,47,51,52,66,73],analyz:[74,76],ani:[2,3,4,5,8,9,10,11,12,13,14,16,17,22,23,24,26,28,29,30,33,34,35,36,37,38,43,46,47,48,49,50,51,65,66,67,68,71,72,73,74,76],annot:50,anoth:[29,34,64,66,68,73,74,76],anyth:28,apach:29,api:[29,66],appear:73,append:[1,68,74,76],appli:[26,28,29,30,48,52,73,74,76],applic:[25,29,49,66,71,74,76],approach:72,appropri:[22,23,24,26,30,36,37,47,49,68,74,76],approxim:[28,73],apt:67,ar:[1,2,3,4,5,10,12,18,22,23,24,25,26,28,29,30,34,45,48,49,50,65,66,67,68,71,72,73,74,75,76],architectur:[1,3],aren:29,arg:[12,28,29,47,49,50],argmax:[1,28,29],argmax_lay:1,argmax_output:1,argument:[13,21,27,29,50],around:[38,43,46,51],arrai:[3,25,29,45,50,66],ascend:73,ascii:[45,68],ascii_num:1,aspect:[74,76],assert_equal_condit:36,assign:50,assist:3,associ:[21,27,29,30],assum:[28,29,35,50,69,71],astyp:[1,68],attempt:[29,45,73],attr1:44,attr2:44,attr:[22,28,35,49],attribut:[2,14,29,33,34,35,36,37,38,39,43,46,47,48,49,50,51,53,63,64,73],attribute_1:66,attribute_2:66,attribute_n:73,attributeerror:[4,29],attributt:[66,73],aug:68,august:68,author:[4,29,71,74],auto:[4,5,11,22,49,66,73],auto_multiprocess_toggl:50,autom:50,automat:[29,63,64,66,73],automaticali:4,autosubregistr:28,autosubregistrationmeta:[22,28],avail:[2,5,42,45,65,73,74],averag:[1,25,29,36,64,73],avg:29,avg_node_degre:[64,66,73],avg_predict:[36,66,73,74],avro:[4,5,6,7,16,66,67,71,73,74,76],avro_data:[8,11,71],avro_fil:[4,71],avrodata:[4,8,11,71],aw:[1,68],aws_honeypot_marx_geo:[1,4,71,72,74],ax:[65,74],b:[29,30,50,65],b_out:29,back:29,backend:1,background:[2,28,30],backward:29,ban:[3,66],bank:[3,66],bar:45,barchart:65,bargraph:65,base:[3,5,6,7,8,10,11,13,14,15,16,17,18,20,23,24,26,27,28,29,30,32,34,35,36,37,38,39,43,45,46,47,48,49,50,51,52,53,60,71,73,74],base_column_profil:[33,34,36,37,38,43,46,47,51],base_data:[8,9,10,14,15,16,18,48],base_data_label:[21,27],base_metr:29,base_model:[1,3,21,22,23,24,26,27,30],base_valid:61,basecolumnprimitivetypeprofil:[33,37,38,43,51],basecolumnprimitivetypeprofilert:33,basecolumnprofil:[33,34,36,37,44,45,46,47,51],basecolumnprofilert:[33,46],basecompil:[35,44,48],basecompilert:35,basedata:[8,9,10,14,15,16,18,48],basedatalabel:[20,21,27,49,50,73],basedatapostprocessor:[3,21,27,28],basedatapreprocessor:[3,21,27,28],basedataprocessor:28,baseinspectoropt:49,baseinspectoroptionst:49,basemodel:[1,3,21,22,23,24,26,27,30,68],baseopt:[33,44,48,49],baseoptiont:49,baseprocessor:68,baseprofil:[44,48,50],baseprofilert:48,basetrainablemodel:[22,23,24],basi:[29,45],basic:[3,68,69],batch:[8,9,10,14,15,16,18,21,22,23,24,27,28,66,71,73],batch_1:73,batch_2:73,batch_data:28,batch_siz:[8,9,10,14,15,16,18,21,22,23,24,26,27,28,30],batchnorm:29,baz:45,bc:4,bcc:68,bdist:67,bdist_wheel:67,becaus:[4,25,29,49,50,75],becom:[28,29,50],been:[4,29,44],befor:[3,29,49,73,75],behavior:[29,45],behind:2,being:[2,4,5,8,9,10,12,13,14,15,16,17,18,21,22,23,24,25,26,27,28,30,36,39,48,49,73,75],belong:3,below:[2,4,5,25,28,29,42,49,64,65,66,68,71,72,73,74,75,76],besid:[68,71],best:[4,5,36,66],beta:[25,29],better:68,between:[2,3,4,25,27,28,29,35,36,37,39,47,48,49,50,52,53,64,68,72,73,74,75,76],beyond:[74,76],bfloat16:29,bia:[29,49,73],bias:50,bias_correct:[49,51,73],biased_kurt:50,biased_skew:50,big:68,bigobject:45,bin:[38,43,46,49,51,64,67,71,73],bin_count:[64,66,73,74],bin_count_or_method:[49,71,73],bin_edg:[64,66,73,74],binari:25,bit:2,blob:[29,42],block:72,blog:4,blogpost:4,bool:[8,9,10,12,14,15,16,18,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,43,46,47,48,49,50,51,52,53,61,66,73,74],booleanopt:49,booleanoptiont:49,both:[4,12,29,47,49,63,68,73,74,75,76],bound:50,brand:2,breadth:29,breakdown:73,breviti:68,brew:67,broken:71,bucket:[49,73],buffer:[6,7,12],buffer_s:12,bufferediobas:13,bug:66,build:[1,12,25,29,46,48,61,63],build_embd_dictionari:[1,24],build_from_config:29,builder:[6,32],built:[1,20,28,29],builtin:3,byte_s:12,bytesio:[8,11,12,13,16],c:[29,65],cach:29,calcul:[3,25,29,34,37,38,39,40,41,43,46,48,49,50,51,66,73,74,76],calculate_quantil:[40,41],call:[3,5,12,25,29,44,45,46,49,50,71,74],callabl:[29,31,46,50,57],came:29,can:[1,2,3,4,5,8,9,10,15,16,17,18,21,25,29,45,48,50,51,64,65,66,67,68,71,72,73,74,75,76],candid:29,cannot:[3,12,29,65],capabl:[4,29],capitalon:[4,67],captur:75,carat:4,cast:29,categor:[6,32,49,64,66,73,74,75],categori:[1,34,49,50,66,68,71,73,74],categorical_attribut:[64,66,73],categorical_column_profil:34,categorical_count:[34,66,73],categorical_crossentropi:1,categorical_distribut:[64,66,73],categorical_statu:4,categoricalcolumn:[34,35,47],categoricalopt:[34,49],categories1:50,categories2:50,caus:[29,45,49],cc:68,cdist:26,cdot:29,cell:[3,12,64,66,68,75],certain:29,chang:[3,4,29,35,38,43,46,48,51,72,73,74,75,76],char_in_vector:1,char_load_tf_model:23,charact:[3,4,6,10,12,14,20,28,30,41,45,48,49,63,66,68,71,73,75],character_argmax:28,character_level_cnn_model:[1,3,24,68],characterlevelcnnmodel:[1,3,20,24,28,68],characterlevellstmmodel:1,charencodedpreprocessor:28,charloadtfmodel:23,charpostprocessor:28,charpreprocessor:[20,28],charset:68,check:[1,2,3,8,10,12,14,16,21,27,29,31,34,38,43,45,46,49,51,57,61,63,68,69,71,73],check_circular:45,check_integ:14,check_pipelin:[3,21,27,68],chi2:73,chi2_homogen:[49,68,73],chi2_matrix:[66,73],chi:[50,73],child:19,choic:[4,5,8,10,15,16,18],choos:[4,27,28,72,73,75],chose:28,chosen:[73,76],chr:1,chunk:[5,12,18,45,50],chunk_siz:50,chunk_size_byt:12,cij:34,circular:45,clariti:4,class_mean:[66,73],class_nam:[22,23,24,26,28,30,44],class_prior:[66,73],class_sum:[66,73],classif:[6,20,29,34],classifi:3,classification_report:[25,29],classification_report_util:25,classmethod:[8,9,10,14,15,16,18,21,22,23,24,26,27,28,29,30,33,34,35,36,37,38,39,43,46,47,48,49,51],clean_data_and_get_base_stat:48,clean_sampled_df:48,clear:50,clear_sess:1,close:2,clsname:[22,28],cm:[49,73],cms_confid:[49,73],cms_max_num_heavy_hitt:[49,73],cms_relative_error:[49,73],cn:68,cnn:[1,6,20],code:[4,25,29,42,46,50,66,68,71,72],coeffici:73,col1:69,col2:69,col:[14,33,36,37,38,43,46,47,48,50,51,60,61,68,72,74],col_float:[71,74],col_int:[71,74],col_pro_compil:44,col_profil:50,col_report:1,col_typ:[33,34,36,37,38,43,46,47,51],collaps:41,collect:[29,48,50,71,74,76],color:4,column:[1,3,5,6,10,12,14,16,20,25,28,32,44,48,49,50,52,53,61,63,65,66,68,71,72,73,74,75,76],column_count:[66,71,73,74],column_ind:65,column_index:48,column_nam:[1,14,61,65,66,68,73,74],column_name_label:2,column_name_model:[2,26],column_null_valu:49,column_profile_compil:[35,48],columnar:1,columndatalabelercompil:35,columnnam:63,columnnamemodel:[2,26],columnnamemodelpostprocessor:[2,28],columnprimitivetypeprofilecompil:35,columns_nam:65,columnstatsprofilecompil:35,com:[4,5,29,42,50,67,68],combin:[1,4,10,29,50,71],come:[29,66,71],command:[2,5,66,72,74,75,76],comment:1,common:[4,49],commonli:[4,74,76],compact:[45,48,64,66,71,73,74,75,76],compani:68,compar:[29,45,47,64,72,73],compare_neg:2,compare_posit:2,comparison:63,compat:[3,8,9,10,14,15,16,18,29,66,68,69,74,76],compen:68,compil:[1,6,32,44],complet:[49,73],complex:3,complex_nest:[4,71],complianc:29,compliant:[29,45],compon:[0,1,21,24,25,27,44,64,68,71,72,73,74,76],compos:29,compris:[68,73],comput:[25,29,71],compute_dtyp:29,compute_mask:29,compute_output_shap:29,compute_output_signatur:29,concaten:41,conclus:63,condit:[29,49,73],conduct:[4,28],conf:[3,28,68],conf_matrix:25,confid:[1,2,3,22,23,24,26,28,30,49,68,73,75],confidence_level:[66,74],config:[29,33,34,35,36,37,38,43,44,46,47,48,49,50,51,61],configur:[29,49,59,61,73],conflict:49,confus:[25,29],confusion_matrix:25,confusion_matrix_fil:29,connect:[1,21,27,29],consecut:12,conserv:73,consid:[1,12,29,30,49,51,73],consist:45,constant_initi:29,constraint:73,construct:[1,3,29,44,49],constructor:[1,29,45],contain:[1,3,4,5,8,9,10,11,12,13,14,15,16,17,18,21,22,23,24,25,26,27,28,29,30,31,33,34,36,37,41,42,44,45,47,49,50,56,57,62,65,66,68,71,73,74,76],content:[45,68],context:13,continu:[3,64,73],continuous_attribut:[64,66,73],continuous_distribut:[64,66,73],continuous_weight:4,contract_numb:2,contrast:73,control:29,conv2d:29,convent:4,convert:[3,4,12,22,25,26,28,29,30,38,43,46,51,68,72,75],convert_confusion_matrix_to_mcm:25,convert_int_to_str:12,convert_to_ner_format:28,convert_to_structured_analysi:28,convert_to_tensor:29,convert_to_unstructured_format:28,convolut:1,copi:[25,29,42,49,50],copyfileobj:72,copyright:29,core:[8,9,10,12,14,15,16,18,22,23,24,26,30,33,34,35,36,37,38,43,46,47,48,50,51,52,53],correct:[73,75],correctli:4,correl:[49,66,73],correlation_matrix:[66,73],correlationopt:49,correspond:[25,28,29,50,71],cost:[50,68],could:[28,29,36,64,74,76],count:[25,29,34,38,43,46,49,50,51,52,64,73,76],count_param:29,coupl:73,cover:[71,72,74,76],cppflag:67,cpu:50,cpu_count:50,creat:[1,2,3,11,22,27,28,29,30,39,44,50,58,63,64,68,72,73,74,75,76],create_glove_char:[1,24],creation:29,credit_card:[3,66],critic:19,cross:21,csv:[1,3,4,5,6,7,12,14,64,66,68,71,72,73,74,76],csv_column_nam:14,csv_data:[4,5,10,11,66,71,73],csv_file:[4,71],csvdata:[10,11,63,66,71,73],current:[3,5,14,22,23,24,26,28,29,30,64,65,66,73,74,75,76],custom:[29,44,45,66,71,73],cut:[4,66],d:[1,29,46,50,65,69],dai:[45,50],daili:4,dask:61,data1:[66,73,74,76],data2:[66,73,74,76],data:[0,1,6,17,20,22,23,24,25,26,29,30,32,33,34,35,37,38,39,43,44,45,46,47,48,49,50,51,52,53,56,61,63,67,70],data_and_metadata:[5,8,15],data_class:11,data_fold:[4,74],data_format:[5,8,9,10,14,15,16,18,63,76],data_gener:12,data_label:[1,2,3,27,36,49,52,66,68,71,73,74,75,76],data_label_represent:[66,74],data_labeler2:36,data_labeler_column_profil:36,data_labeler_dirpath:[49,52,68,73],data_labeler_load_attr:50,data_labeler_object:[1,49,68,73,75],data_labeler_sav:[1,68],data_length:50,data_list:12,data_object:[74,76],data_path:[64,71,74,76],data_process:[2,3,21,27,28,68,75],data_processor:[21,27],data_read:[4,5,8,9,10,11,12,13,14,15,16,17,18,39,48,66,67,71,73],data_s:50,data_split_differ:[74,76],data_stat:[1,66,68,71,73,74,75,76],data_test:[1,68],data_train:[1,68],data_typ:[4,8,9,10,11,14,15,16,18,35,49,64,66,71,72,73,74],data_type_ratio:[37,38,43,51],data_type_represent:[66,73,74],data_util:12,dataarrai:[21,22,23,24,27],datafram:[1,5,8,9,10,12,14,15,16,18,21,22,23,24,26,27,28,30,33,48,50,61,63,65,68,69,71,72,74,75,76],datalabel:[2,3,21,27,36,49,63,68,73,74],datalabelercolumn:[35,36],datalabeleropt:[36,49,50,52],datalaod:72,dataload:63,dataprofil:[1,2,3,4,5,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,57,58,59,61,63,64,65,66,67,68,69,71,73,74,75,76],dataprofiler_loader_report:72,dataprofiler_se:[58,67],dataproil:4,dataset:[3,4,5,8,9,10,14,15,16,17,18,21,29,32,33,34,36,37,38,39,43,46,47,48,49,50,51,52,61,63,64,66,67,68,71,72,73,74,75,76],datatim:72,datatyp:45,date:[3,4,50,66,68,72],datetim:[1,3,4,6,32,49,50,64,65,66,68,72,73],datetime_column_profil:37,datetimecolumn:37,datetimeopt:[37,49],dd:61,deal:68,debug:[19,29],decid:[49,73],decim:[48,73,74,76],deciph:[4,10,14],decod:[6,32,45],decor:[22,28,29],deep:66,deeper:63,def:[1,4,29,68,72],default_factori:50,default_ind:1,default_label:[1,2,23,24,27,28,30,68,75],defaultdict:50,defin:[1,5,29,46,49,65,73,75],definit:50,degre:[64,73],delet:67,delimit:[5,10,12,14,63,71,74,76],delimti:4,demo:[68,72],demonstr:[4,65,71],denot:73,dens:[1,29],depart:68,depend:[29,31,48,50,57,64,67,68],deprec:29,depth:[4,63],deriv:1,descend:34,descent:29,describ:[13,21,22,23,24,25,26,27,28,29,30,39,73],descript:[4,5,64,71],deseri:44,design:[7,12,66,68,71,73,74,76],desir:[1,4,48,66,71,74,75,76],destin:14,destination_nod:14,detail:[2,3,4,23,24,25,48,63,71,73,74,76],detect:[5,8,11,12,16,63,64,66,67,71,73,74,75,76],detect_cell_typ:12,detect_file_encod:12,determin:[2,3,4,8,9,10,12,13,14,15,16,18,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,43,47,49,52,66,73,74,76],dev:67,deviat:[38,43,46,51,73],devid:71,df1:71,df2:71,df:[4,36,37,38,43,46,47,51,53,68,69,71,73],df_data:[1,68],df_result:[1,68],df_seri:[33,34,35,36,37,38,43,46,47,48,50,51,52],diamond:[4,74],dict1:50,dict2:50,dict:[2,3,4,5,8,9,10,11,12,14,15,16,17,18,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,61,66,71,73,74,75,76],dictat:27,dictionari:[4,5,12,15,21,24,25,27,29,33,34,35,36,37,38,41,43,45,46,47,48,49,50,51,64,66,73,74,76],did:29,diff:[33,34,35,36,37,38,39,43,46,47,48,51,52,53,64,73,74,76],diff_report:73,differ:[1,4,29,33,34,35,36,37,38,39,43,46,47,48,50,51,52,53,61,63,66,68,71,72],differenc:73,differenti:[36,64],digest:3,digit:[3,25,66,73,75],dim:24,dim_emb:[1,23,24,26,30],dimens:29,dir:29,directli:[4,29,65,66,68,71,73,74,76],directori:[22,23,24,26,30,52,68,72,73],directpasspreprocessor:[2,20,28],dirpath:[3,21,22,23,24,26,27,28,30,68],disabl:[1,26,29,33,34,35,36,37,43,46,47,49,52,66,67,68,71,72,73],discov:67,discoveri:25,discret:29,discrimin:25,discuss:4,discussion_reddit:[4,71,76],disk:[3,20,21,22,23,24,26,27,28,30,39,48,74,76],displai:[4,25,34,49,68,73],dist:67,distinct:73,distribut:[29,36,64,66,67,69,71,73],dive:[63,68],doan:73,doc:[4,64],document:[68,74,76],doe:[25,26,29,30,44,50,64,66],doesn:[29,31,57,74,76],domin:28,don:[29,66,67],done:[21,27,29],doubl:67,down:24,download:[12,72],downstream:[29,66],dp:[1,2,3,4,5,6,64,65,66,68,69,70,71,72,73,74,75,76],dp_data:72,dp_datafram:72,dp_dataload:72,dp_log:19,dpi:74,drivers_licens:[3,66],drmaciv:50,drop:[1,48,68],dropout:[1,23,24],dtype:[1,12,29,65,75],dtype_polici:29,due:[50,74,75],dummi:69,dump:[66,71,73,74,76],duplic:[50,71,74,76],duplicate_row_count:[66,71,73,74],durat:73,dure:[2,3,29,45,75],dynam:[29,72],e:[3,4,21,27,29,50,68,73,75],each:[3,4,12,21,22,23,24,25,27,28,29,30,34,36,38,41,45,50,64,66,68,71,72,73,74,75,76],eager:29,earlier:68,easi:[5,66,68,73],easiest:2,easili:[68,71,73,75],ecosystem:29,edg:[4,14,38,43,46,51,64,66,73],educ:68,effici:66,effort:4,eg:49,egg:67,either:[12,21,27,29,50,64,67,74,76],element:[29,38,45,73],elif:1,elimin:45,els:[1,50,71,72,74,76],email:68,email_address:[3,66],emb:24,embed:[1,24,28],embed_fil:1,embedding_dict:1,embedding_matrix:1,empti:[1,4,50,71,73],empty_line_count:[66,73,76],en:50,enabl:[29,49,66,71,73,75],enabled_profil:49,encapsul:[30,75],encod:[1,3,4,6,8,9,10,12,13,14,15,16,18,21,22,23,24,26,27,28,29,30,32,44,66,68,73,74,76],encoding_funct:1,encoding_map:28,end:[3,28,30,61,68,75],enron:68,ensur:[2,4,12,29,36,45,47,64,68,72,73,75],ensure_ascii:45,enter:29,entir:[4,5,8,10,15,16,73,75],entiti:[28,29,30,52,66,67,68,71,73,74,76],entity_count:[66,73,76],entity_percentag:[66,73],entity_priority_ord:28,entity_rev_dict:29,entri:[25,29,66,73],enumer:72,env:67,environ:71,epoch:[1,3,21,22,23,24,27,68],epoch_id:[3,24],equal:[2,28,49,71,73],equip:[66,73],equival:29,eras:[8,9,10,14,15,16,18],error:[1,4,19,21,27,29,36,49,50,67,68,69,71,74,76],error_on_mismatch:[21,27],escap:45,estim:[38,43,46,49,50,51,73],etc:[3,4,12,28,29,48,50,66,71,73,74,76],evalu:[1,2,3,29,75],evaluate_accuraci:29,evan:68,even:72,ever:68,everi:[12,73,74,76],ex:73,exact:[72,73],exactli:[4,29,71],examin:[8,10,15,16,18,74,76],exampl:[1,2,3,4,5,25,29,30,45,61,64,66,68,69,71,73,74,75,76],except:[1,2,3,4,28,29,50,64,68,69,72,74,75,76],exclud:[25,33,34,35,36,37,43,47,52],execut:[3,29,50,72],exist:[8,9,10,14,15,16,18,21,22,23,24,26,27,28,29,30,31,44,49,50,57,63,66,68,72,73],expect:[3,12,29,44,68,71,75],explicit:73,explicitli:[29,71,74,76],explor:[1,66],expon:64,express:29,exst:[2,75],extend:68,extended_report:72,extens:[4,71],extra:[1,4,10,64,68,69,74,76],extract:[22,23,24,26,30],extran:3,f1:[1,22,23,24,25,29,68],f1_report:[22,23,24,29],f1_report_dict_to_str:29,f1_score_train:1,f1score:[1,29],f:[25,29,50,57],f_1:29,f_:29,f_in:72,f_out:72,f_score:29,factor:24,factori:[11,48,50],fail:4,failur:[4,49],fake:75,faliur:4,fall:29,fals:[1,2,4,5,9,12,13,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,43,45,46,47,48,49,51,52,53,64,66,68,71,72,73,74,75,76],false_positive_dict:2,fashion:61,fbeta_scor:25,fbetascor:29,fd:73,featur:[71,73],fed:48,feed:68,fetch:14,few:[66,68],field:4,fig:[65,74],figsiz:74,figur:[38,65,73,74],file:[1,5,8,9,10,11,12,13,14,15,16,17,18,19,20,21,24,27,29,39,42,48,62,63,64,67,68,71,72,74,76],file_a:[66,73],file_b:[66,73],file_encod:[4,8,9,10,12,14,15,16,18],file_object:12,file_path:[8,10,12,14,15,16,18],file_typ:[66,71,73,74,76],filenam:[24,68,74,76],fileorbufferhandl:13,filepath:[4,6,7,19,39,48,64,73,74,76],filepath_or_buff:13,fill:1,filter:[2,29],final_confid:3,final_predicted_lay:1,final_result:3,finalize_st:29,find:[12,14,25,29,33,34,35,38,39,43,46,48,50,51,52,53,66,73],find_diff_of_d:50,find_diff_of_dict:50,find_diff_of_dicts_with_diff_kei:50,find_diff_of_lists_and_set:50,find_diff_of_matric:50,find_diff_of_numb:50,find_diff_of_strings_and_bool:50,find_nth_loc:12,finetun:4,first:[1,2,4,10,15,29,36,50,64,65,66,68,71,72,73,74,75],first_dict:50,fisher:50,fit:[1,3,21,22,23,24,29,36,68],fix:[26,30],flag:[1,2,3,21,22,23,24,26,27,28,30,33,34,35,36,37,43,47,48,49,52],flat:[48,73,74,76],flat_dict:41,flatten:[28,41,48,73,74,76],flatten_separ:28,flatten_split:28,flattened_datafram:[5,15],flight_delai:72,flight_delays_ful:72,flight_delays_mini:72,float16:29,float32:29,float64:[38,43,46,50,51],float_column_profil:38,floatcolumn:38,floatopt:[38,49],flow:2,fly:29,focu:4,fold:[38,43,46,51],folder:[1,2,67,68],follow:[1,3,4,5,19,20,21,25,27,28,29,50,64,65,68,71,72,73,74,76],foo:45,form:[12,29,67],formal:50,format:[1,3,4,5,8,9,10,14,15,16,18,21,24,25,27,28,29,36,37,44,47,48,49,68,71,72,73,74,75,76],former:71,foudn:75,found:[5,29,36,50,68,73,75],four:[48,73,74,76],fp:4,frac:[1,29,68],frame:[8,9,10,12,14,15,16,18,22,23,24,26,30,33,35,50],framework:29,free:29,frequenc:[49,73],frequent:[34,73],fri:68,fridai:68,from:[1,2,3,4,5,8,10,12,13,14,15,16,17,19,20,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,42,43,44,45,46,47,48,49,50,51,53,63,66,69,71,72,73,74,75,76],from_config:29,fromkei:50,fscore:25,full:[29,49,66,67,71,73,74,76],fulli:[1,73],func:[19,25],funciton:75,funky_on:2,funky_thre:2,funky_two:2,further:[5,74,76],futur:63,g:[4,29,34,50,68,73,75],g_1:50,g_2:50,game:4,gamma:64,gather:[49,71],gaussian:4,gca:74,gener:[1,8,9,10,12,14,15,16,18,28,29,33,35,36,37,40,41,47,48,49,50,55,56,58,64,66,71,72,73,74,75,76],generate_pool:50,generator_on_fil:12,get:[1,3,8,9,10,14,15,16,18,22,23,24,26,28,29,30,38,43,45,46,50,51,61,65,67,68,71,72,74,75,76],get_batch_gener:[8,9,10,14,15,16,18],get_build_config:29,get_child_logg:19,get_class:[22,23,24,26,28,30],get_column_profiler_class:44,get_compiler_class:44,get_config:29,get_delimiter_regex:12,get_figur:65,get_input_at:29,get_input_mask_at:29,get_input_shape_at:29,get_logg:19,get_memory_s:50,get_option_class:44,get_output_at:29,get_output_mask_at:29,get_output_shape_at:29,get_paramet:[22,23,24,26,28,30],get_profiler_class:44,get_random_number_gener:58,get_structured_col_profiler_class:44,get_structured_result:[1,68],get_tf_layer_index_from_nam:29,get_unstructured_result:68,get_weight:29,gini:34,gini_impur:[34,66,73],git:67,github:[1,2,4,29,42,64,67,68,69,71,72,74,75,76],githubusercont:4,give:[4,28,31,57,71,75],given:[1,3,4,8,10,11,12,13,16,19,21,22,23,24,26,27,28,29,30,31,32,35,44,45,48,50,57,61,66,67,68,71,73,74,75,76],global:[25,64,66,73],global_max_component_s:[64,66,73],global_stat:[66,71,73,74,75,76],glove:[1,24],go:68,godbol:25,good:[4,72,74],govern:29,grab:73,gradient:29,gradienttap:29,graph:[3,4,5,6,7,31,32,48,55,57,63],graph_data:[4,11,14,39],graph_data_csv_identifi:[4,64],graph_fil:[4,66],graph_func:57,graph_keyword:14,graph_profil:39,graphdata:[11,14,39,63,64],graphopt:39,graphprofil:[4,39,48,64],greater:[1,2,29,73],green:4,ground:63,group:[12,40,41,49,50,73],guarante:45,guess:68,guid:25,gz:72,gzip:72,ha:[3,4,8,10,14,15,16,25,28,29,30,36,44,46,50,68,71,73,74,76],half:71,hall:4,halv:71,handl:[3,12,13,29,71],happen:[4,29],harmon:29,hasattr:29,hash:[3,49,66,73],hash_or_kei:[3,66],hashing_method:[49,73],have:[3,4,12,15,21,22,23,24,26,27,28,29,30,36,50,61,64,66,67,68,71,72,73,75],head:[1,4,66,68,71,73],header:[5,10,12,14,16,63,71,74],heard:68,heavi:73,help:[2,3,21,22,23,24,26,27,28,30,68,75],helper:[6,32,50,68],henc:29,here:[2,4,22,29,42,50,68,71,72,74,75],hide_tf_logger_warn:29,high:74,higher:[28,29],highest:[49,73],histogram:[6,32,38,43,46,49,51,64,66,71,73,74],histogram_and_quantil:[49,71,73],histogram_bin_method_nam:51,histogram_method:51,histogram_select:51,histogramandquantilesopt:49,histori:[22,23,24],hitter:73,hll:[49,73],homebrew:67,homogen:[50,73],honeypot:[1,68],honeypot_intentially_mislabeled_fil:[4,71],host:4,how:[2,3,4,5,10,22,29,34,45,61,63,64,65,68,73,75],howev:[3,4,71,73,74,75],html:[4,64,72],http:[4,5,29,42,50,64,67],human:[68,73],hyperloglog:49,hyperloglogopt:[49,73],i:[3,4,21,27,29,34,67,68,74,76],id:68,id_count:12,idea:[2,50],ideal:4,ident:3,identif:[12,30],identifi:[5,14,30,46,48,60,61,66,68,73,74,76],ideolog:25,idx:12,ie:73,iff:50,ignor:[12,25,29,75],ignore_cas:75,ignore_consecut:12,ignore_dict:12,illustr:[3,4],iloc:71,imbal:25,impact:[26,30,35,48],implement:[4,12,14,29,63,64],impli:29,importerror:[2,4,64,68,69,72,74,75,76],impos:[38,43,46,51],improp:49,improv:[68,72],impur:34,inbound:29,inbound_nod:29,includ:[1,2,21,23,24,25,27,29,49,67,71,74,75,76],include_label:2,incom:[29,45],incompat:29,incorrect:[4,34],incorrectli:[4,71,73],increas:74,ind:72,indent:[45,66,71,73,74,76],independ:29,index:[1,3,5,12,14,21,22,23,24,26,27,28,29,30,47,48,50,65,73,74],indic:[1,22,23,24,25,26,29,30,48,50,73],indici:73,individu:[4,12,38,43,47,51,67,68,71,75],infer:[29,71,73,74],infin:45,infinit:45,info:[8,9,10,14,15,16,18,19,29,68],inform:[3,4,29,64,68,71,73,74,76],ingest:[3,74,76],inherit:[1,21,68],init_scop:29,initi:[1,3,8,9,10,12,13,14,15,16,17,18,21,22,23,24,26,27,28,29,30,33,34,35,36,37,38,39,43,46,47,49,50,51,52,53,61],inplac:[28,66,73],input:[1,3,4,8,9,10,11,12,13,14,15,16,17,18,21,22,23,24,25,26,27,28,29,49,50,64,68,71,73,74,76],input_file_path:[4,5,8,9,10,11,14,15,16,17,18],input_length:1,input_mask:29,input_shap:[1,29],input_signatur:29,input_spec:29,input_str:[1,30],inputspec:29,insert:[1,2,4,29,45,50,64,66,68,69,71,72,74,75,76],insid:[29,66,73,74,75,76],instal:[31,57,63,65,66],instanc:[19,21,25,27,29,34,44,73],instanti:[29,48,61,69],instead:[8,9,10,14,15,16,17,18,21,25,27,29,68],insturl:68,int64:[50,51],int_column_profil:43,intcolumn:43,integ:[1,2,3,14,23,24,28,29,30,38,43,45,46,51,65,66,68,73,75],integr:[29,63],intend:72,intent:4,intention:4,intentionally_mislabled_fil:[4,71],interchang:68,interept:4,interest:[1,71],intern:[25,27,29,50],interpol:[38,43,46,51],interpret:[3,4],intopt:[43,49],intro:[63,73],introductori:71,invalid:1,investig:68,invoc:29,invok:29,involv:68,io:4,ipv4:[3,66],ipv6:[3,66],iri:[4,74],is_case_sensit:[49,73,76],is_en:[1,49,50,66,68,71,72,73,74,76],is_float:[38,43,46,51],is_in_list:61,is_in_rang:61,is_int:[38,43,46,51],is_match:[8,9,10,14,15,16,18,34,63],is_numeric_stats_en:[49,73],is_pred_label:28,is_prop_en:49,is_separate_at_max_len:28,is_stream_buff:13,is_structur:[8,9,10,14,15,16,18],is_valid_url:12,isdir:[2,75],isinst:1,isn:29,issu:66,item:[1,12,45,50,61,68],item_separ:45,iter:[3,12,21,22,26,29,30,50],iterencod:45,its:[1,3,4,21,25,27,29,46,48,61,66,73,75],itself:[5,34,38,43,46,51],ivar:49,j:[4,34],javamail:68,javascript:45,john:68,join:[1,4,8,15,28,41,64,71,72,74,76],js:29,jsmith:68,json:[1,2,3,4,5,6,7,12,16,32,33,34,35,36,37,38,43,46,47,48,49,51,66,68,69,71,72,73,74,75,76],json_data:[8,11,15,71],json_decod:44,json_encod:[44,45],json_fil:[4,71],json_lin:12,json_to_datafram:12,jsondata:[4,8,11,15,71],jsonencod:45,jsonifi:45,jsontyp:12,jupyt:71,just:[5,71,73,74,75,76],k:[34,50],kader:34,keep:[29,68],kei:[4,5,8,12,15,21,27,28,39,41,45,48,50,66,73,74,76],kera:[1,29],kernel:29,kernel_initi:29,key_separ:45,keydict:50,keyerror:50,keyword:[14,29],kind:[11,29],know:72,knowledg:25,known:[25,72],kurtosi:[38,43,46,49,50,51,64,66,73],kwarg:[11,22,23,24,26,28,29,30,47,50],kwd:49,l211:29,l283:29,l:[29,67],label1:3,label2:3,label:[0,1,6,22,23,24,25,26,28,30,31,32,48,49,50,63,67,70,71,72,73,74,76],label_1:30,label_1_pattern_1:30,label_1_pattern_2:30,label_2:30,label_2_pattern_1:30,label_2_pattern_2:30,label_df:68,label_encod:52,label_map:[1,2,21,22,23,24,26,27,28,30,68,75],label_nam:[3,29],label_represent:[36,73],labeled_data:68,labeler_class:27,labeler_from_librari:2,labeler_funct:31,labeler_typ:[1,3,27,68],labeler_util:[1,29],labler:[66,67],lack:50,lambda:[1,29],languag:29,larg:71,largest:64,last:[4,12,50,65,68,71,73,74],later:[4,29,66,74,76],latter:71,law:29,layer:[1,29],layer_a:29,layer_b:29,layer_nam:29,lazi:50,learn:[63,66],least:[15,73],left:73,leftov:28,len:[1,4,29,68,71,74,76],length:[4,8,9,10,12,14,15,16,18,28,50,64],less:[12,50,72,73],let:[1,2,64,68,69,71,74,75,76],letter:75,level:[3,6,19,20,22,23,26,28,30,41,45,49,63,65,66,68,71,73,74],lib:[19,67],libarari:72,librari:[1,2,3,21,27,28,63,64,66,68,71,75],libsnappi:67,licens:[29,42],lifo:50,like:[1,3,24,25,29,41,50,64,71,73,74,76],likelihood:[34,64,73],limit:29,line:[4,10,12,15,18,66,68,71,73],linux:67,list:[1,2,3,4,5,8,9,10,11,12,14,15,16,18,20,21,22,23,24,25,26,27,28,29,30,31,34,36,38,43,45,46,48,49,50,51,52,57,61,63,64,65,66,68,71,73,74,75,76],list_of_necessary_param:1,list_of_profil:[50,69],live:29,ll:[68,72],load:[1,5,6,8,9,10,12,13,14,15,16,17,18,20,21,22,24,26,27,28,29,30,33,34,35,36,37,38,39,43,44,46,47,48,49,50,51,63,72],load_as_str_from_fil:12,load_attr:50,load_column_profil:44,load_compil:44,load_from_dict:[33,34,35,36,37,38,43,46,47,48,49,51],load_from_disk:[2,3,21,22,23,24,26,27,28,30,75],load_from_librari:[20,21,27,28,63,75],load_method:[48,73],load_model:29,load_opt:[21,27,44],load_own_vari:29,load_profil:44,load_structured_col_profil:44,load_with_compon:[21,27,63],loadabl:23,loaded_json_profil:73,loaded_pkl_profil:73,loaded_profil:[74,76],loader:72,loc:[12,64,73],local:67,locat:[4,10,14,21,24,27,48,71,73,74],log:[6,64,68,69,70,73,74,76],logger:[19,29],loggin:[68,69,74,76],logic:[12,29],logist:64,lognorm:64,look:[63,64,68,69,74,75,76],lookup:29,loop:[27,29],loss:[1,29],low:65,lower:75,lower_memory_sketch:[49,73],lowercas:75,lowercase_char:75,lowest:28,lst:50,lstm:63,m1:29,m2:29,m:[3,5,12,29,34,50,67],mac_address:[3,66],machin:[71,74,76],macklemor:3,maco:67,macro:[25,29],made:25,mai:[4,5,8,10,15,16,18,29,49,71,74,76],mail:68,main:[0,1,3,4,25,42,65],maintain:3,major:[25,68],make:[1,3,29,46,66,68,71],makedir:[1,68,72],manag:13,mani:[4,5,10,22],manipul:[74,76],manner:[4,66,73],manual:[4,29,58],map:[1,2,3,22,23,24,26,28,30,36,48,49,68,73,75],margin_of_error:[66,74],mari:68,mask:29,match:[9,12,21,25,27,29,30,37,38,43,51,64,74,75,76],match_count:[37,38,43,51],match_sentence_length:28,math:72,math_op:29,mathemat:[4,12],matmul:29,matplotlib:[65,71,74],matric:50,matrix1:50,matrix2:50,matrix:[1,25,29,49,50,66,73,74],max:[22,23,24,26,29,30,37,49,50,51,64,66,71,73,74],max_byt:12,max_char_encoding_id:[1,23,24],max_histogram_bin:51,max_k_mod:49,max_length:[1,23,24,26,28,30,68],max_lin:12,max_num_char:[26,30],max_pool_s:50,max_sample_s:[49,73,74],max_sample_size_to_check_stop_condit:[49,73],maximum:[12,28,49,73],mayb:9,mb:[66,73],mcm:25,mcm_:25,md5:[3,66],mean:[25,29,38,43,46,51,64,65,66,67,68,71,73,74,76],meant:29,measur:[50,73],mechan:[3,4],median:[38,43,46,49,51,66,71,73],median_abs_devi:[38,43,46,51,71,73],median_absolute_devi:[66,73],meet:4,melt:[1,68],member:45,memori:[1,5,8,10,15,16,18,50],memory_s:[66,73],mention:[4,68],merg:[29,50,63],merge_profile_list:[50,69],merge_st:29,messag:[50,68],met:73,metadata:[5,8,15,29,33,34,36,37,38,43,46,47,51],method:[2,3,4,22,25,28,29,34,36,37,44,46,47,48,49,50,71,73,74,76],method_timeit:50,metric:[1,25,29,49,73],metric_1:29,metric_2:29,micro:[1,25,29],might:[64,68],millisecond:73,mime:68,min:[29,37,48,49,51,66,71,73,74],min_histogram_bin:51,min_sample_s:48,min_true_sampl:[48,73],mind:68,mine:25,mini:72,minimum:[36,48,49,73],mirror:73,mismatch:[21,27,74],miss:[31,46,50,57,74],mix:29,mixed_precis:29,mixin:[6,7,38,43,49],mkdir:[2,75],ml:[66,67,68],mod:29,mode:[13,28,29,38,43,46,49,51,66,71,73],model:[6,20,21,27,28,29,46,48,61,63,66,68,73,75],model_path:23,model_predict:3,model_result:[3,68],modeopt:49,modif:1,modifi:[28,29,42,71],modul:[19,25,27,29,31,57,70],module_nam:[31,57],monitor:66,monti:4,more:[2,4,9,25,28,29,36,63,64,66,68,71,72,73,74,76],most:[34,45,74,76],move:29,mro:[22,28],much:73,multi:[21,22,23,24,25,26,27,29,30],multiclass:25,multilabel:25,multilabel_confusion_matrix:25,multipl:[3,8,9,10,14,15,16,17,18,29,61,65,67,68,71,73,74,75,76],multiprocess:[35,48,50,73],multiproess:50,must:[1,3,5,19,21,22,23,24,27,28,29,36,48,73,74,75,76],my:[3,4,73],my_datafram:[66,71,73,74],my_graph:66,my_home_address:2,my_label:68,my_metric_lay:29,my_modul:29,my_new_regex_label:75,my_profil:[73,74,76],my_text:66,mydata:4,mylay:29,mymetriclay:29,mymodul:29,mysocket:45,n:[1,3,4,5,12,14,26,28,30,34,68,71,73],n_dim:24,n_label:25,n_output:25,n_sampl:25,n_unique_label:25,na:68,name:[1,4,6,14,19,20,21,25,27,28,29,31,33,34,35,36,37,38,43,44,46,47,49,50,51,53,57,63,64,65,66,67,68,71,73,74],name_scop:29,nan:[12,45,49],nation:[4,71],ndarrai:[21,22,23,24,25,26,27,28,30,36,48,50],ndim:29,nearest:28,nearli:3,necessari:[1,64,69],need:[1,2,3,12,19,21,22,23,24,26,29,30,49,50,64,66,68,71,72,74,75,76],neg:[25,38,43,45,46,50,51,64,73],negative_threshold_config:2,ner:[3,28,68],nest:[5,29,41,48,50,73,74,76],network:[1,29],networkx:[4,5,14,39,64],neural:1,new_column_name_label:2,new_data:[66,73,74,76],new_label:[3,68],new_profil:64,new_report:64,newlin:45,next:[1,4,68,72,74,76],nice:29,nmodel:[2,75],node:[14,29,64,73],node_id_dst:4,node_id_src:4,node_index:29,non:[1,28,29,45,48,68,73],non_csv_fil:4,non_trainable_vari:29,non_trainable_weight:29,none:[1,5,6,8,9,10,11,12,13,14,15,16,17,18,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,43,44,45,46,47,48,49,50,51,52,53,57,61,65,66,67,68,72,73,74,76],noqa:72,nor:29,norm:64,normal:29,normal_csv_fil:73,normal_text_fil:73,not_my_address:2,note:[1,3,12,25,29,42,51,67,73,74,75,76],notebook:[1,2,4,64,68,69,71,72,74,75,76],noth:36,notic:[4,64,73,75],notimplementederror:[45,48],notset:19,now:[29,64,68,69,75],np:[1,12,21,22,23,24,25,27,28,29,38,43,46,48,50,51,66],np_type_to_typ:[38,43,46,51],npt:28,nth:12,null_count:[49,66,73,74],null_replication_metr:[49,66,73],null_typ:[66,73,74],null_types_index:[66,73,74],null_valu:[48,49],num_class:[1,29],num_cols_threshold:50,num_edg:[64,66,73],num_fil:[23,24],num_label:[1,22,23,24,26,29,30],num_lin:4,num_neg:[49,51,66,73],num_nod:[64,66,73],num_quantil:[49,73],num_quantile_group:[40,41,73],num_rows_threshold:50,num_sampl:28,num_zero:[49,51,66,73],number:[1,3,12,21,22,23,24,25,27,28,29,40,41,48,49,50,58,61,62,64,66,68,71,73,74,76],numer:[6,29,32,38,43,49,65,73,74],numeric_stats_dis:[49,73],numerical_column_stat:[38,43,46,51],numericalopt:[46,49],numericaloptionst:49,numerican:49,numericstatsmixin:[38,43,46,51],numericstatsmixint:[43,46],numpi:[1,12,22,23,24,26,28,29,30,36,38,42,43,46,48,50,51,58,66],nx:39,o:[14,45,68],object:[1,4,5,9,11,12,13,17,21,22,27,28,29,35,39,41,44,45,46,48,49,50,52,53,61,65,66,68,69,71,73,74,75,76],observ:[34,64],obtain:[29,71],occur:[12,34,61,68,73],occurr:[12,25,73],od:41,off:[4,49,66,71,73,74,75,76],offic:68,offset:13,often:[29,34,73],older:67,omit:29,omit_kei:75,omitted_label:29,on_read:29,onc:[1,4,73,74,76],one:[1,3,5,12,19,25,29,34,35,48,66,67,68,71,72,73,74,75,76],ones:[29,68,73],onli:[2,4,5,8,10,14,15,16,18,22,25,29,45,50,61,65,66,68,71,72,73,74,75,76],op:29,opeid6:68,open:[4,12,13,66,68,72],open_method:13,oper:[66,73,74,76],opportun:28,optim:[1,23,24,73],option:[1,2,3,5,6,8,9,10,11,12,13,14,15,16,17,18,21,24,25,26,27,28,29,30,32,33,34,35,36,37,38,39,43,44,46,47,48,50,51,52,53,61,63,64,65,66,68,72,75],order:[1,3,6,22,23,24,25,26,28,29,30,32,34,35,36,49,50,66,68,74,75],order_column_profil:47,ordercolumn:[35,47],ordereddict:48,orderopt:[47,49],ordin:[3,66],org:[29,50,64],origin:[4,12,24,28,29,40,41,68,71,72],os:[1,2,4,64,66,68,69,71,72,74,75,76],oth:75,other:[1,2,23,24,29,35,66,68,71,73,75],other_profil:[33,34,36,37,38,39,43,46,47,48,50,51,52,53],otherwis:[9,25,28,36,45,49,50,73],otuput:75,ou:68,our:[64,65],out:[1,2,3,5,12,29,50,68,69,73],outbound_nod:29,output:[1,2,3,5,12,14,21,25,27,28,29,36,37,39,45,47,48,50,52,53,64,68,72,73,74,75,76],output_dict:25,output_format:[3,28,48,66,68,71,73,74,75,76],output_mask:29,output_shap:[1,29],over:[4,21,61],overal:[29,71,74,76],overflowerror:45,overlap:50,overrid:[3,29,44,48,49],overridden:29,overview:63,overwrit:[49,68],own:[1,29,68,73],p:[34,67,73],packag:[6,7,29,32,40,55,60,62,66,67,69],pad:[1,28,29,68],pad_label:[1,28],page:73,pair:[21,27,50],panda:[1,2,5,8,9,10,12,14,15,16,18,22,23,24,26,28,30,33,34,35,36,37,38,43,46,47,48,50,51,52,53,61,63,65,68,69,71,72,74,75,76],param1:3,param2:3,param3:3,param:[1,8,10,16,21,22,27,29,33,34,35,36,37,38,43,44,46,47,48,49,51,61],param_list:[22,23,24,26,28,30],paramet:[1,3,4,5,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,40,41,43,44,45,46,47,48,49,50,51,52,53,57,61,63,64,68,73,75],parameter:29,parametesr:[2,75],parent:[21,33],parq:4,parquet:[4,5,6,7,12,66,67,71,73,74,76],parquet_data:[11,16,66,71,73],parquet_fil:[4,71],parquetdata:[4,11,16,66,71,73],pars:[33,34,35,36,37,38,43,46,47,48,49,51],parse_d:72,part:[29,38,43,46,51,66],partial:[29,61],particular:[1,2,12,71],particularli:[74,76],partit:[50,73],pass:[2,3,5,8,10,12,14,15,16,18,29,69],path:[1,2,3,4,5,8,9,10,12,13,14,15,16,17,18,21,22,23,24,26,27,28,30,39,48,52,64,68,69,71,72,73,74,75,76],pattern:[12,30],pattern_dict:30,payload:[5,15],payload_kei:[5,15],pb:1,pd:[1,2,4,12,21,22,27,28,48,61,65,66,68,69,71,72,73,74,75,76],pdt:68,peek:[74,76],per:[3,18,25,29,66,68,75],percent:15,percentag:[52,73],percentil:73,percis:49,perform:[1,25,29,50,68,73],perform_chi_squared_test_for_homogen:50,permiss:29,perri:34,person:[3,66,68],pertain:[5,8,9,10,14,15,16,17,18],phone:68,phone_numb:[3,66],pickl:[48,73,74,76],piec:68,pii:66,pip3:[67,72],pip:[65,66,67],pipelin:[3,21,27,63,66,68],pkl:[64,73,74,76],place:[28,45,48,72,73,74,75,76],plain:[4,68,71],pleas:[3,66],plethora:71,plot:74,plot_col_histogram:65,plot_col_missing_valu:65,plot_histogram:[65,74],plot_missing_values_matrix:[65,74],plt:[71,74],plug:1,pm:[68,72],pm_data:72,pm_stability_report:72,point:[5,25,66,73,74,76],polici:29,pool:[35,48,50,73],pool_count:50,pop:[35,38,39,46,50,51,53],popitem:50,popmon:63,popmon_dataload:72,popmon_loader_report:72,popmon_output:72,popmon_tutorial_data:72,popoul:73,popul:[33,34,35,36,37,38,43,46,47,48,49,50,51],pos_label:25,posit:[2,3,25,29,38,43,46,51,64,68],positive_threshold_config:2,possibl:[2,3,5,8,10,14,15,16,18,23,24,26,30,36,50,66,73,74,75,76],possible_data_label:36,post:[2,4,75],postprocesor:75,postprocess:28,postprocess_char_level:[66,73,76],postprocessor:[1,2,20,21,27,28,63,68,73],potenti:[29,35,38,50,51,53],pp:[25,34,64],pprint:[2,64,66,74,75,76],pre:[1,28,49,63,66,73],precis:[25,29,38,49,50,66,68,73,74],precision_recall_fscore_support:25,precisionopt:49,pred:[3,25,28,68],predict:[1,3,21,22,23,24,26,27,28,29,30,32,36,63,66,71,73,74,76],predict_opt:[2,3,21,27,68,75],predicted_entities_in_index:29,prefer:73,preivous:4,premium:4,prep:68,prepar:[4,68],preprocess:28,preprocessor:[1,2,20,21,27,28,68],present:[1,25,46,50,73],preset:[49,73],pretti:[12,45,48,66,71,73,74,76],prettifi:[48,66,73,74,76],prettyprint:[64,66],prevent:45,previou:[29,64,73,75],previous:4,price:4,prim:33,primari:[74,76],primit:[35,73],princip:24,print:[1,2,3,4,12,21,22,23,24,26,27,29,30,45,66,68,71,72,73,74,75,76],printer:66,printout:[29,72],prior:[12,31,57,74,76],prioriti:28,priority_ord:28,priority_predict:28,privat:[34,36,37,47],privileg:68,probabl:[34,36,48,49,73,74,75],process:[1,3,6,12,20,22,26,50,61,71,73,74,75,76],processor:[2,3,20,21,27,28,68],processor_param:1,processor_typ:28,produc:[29,50],profil:[0,1,2,3,4,6,7,40,41,44,45,46,63,65,67,68,70,72],profile1:[66,71,73,74,76],profile2:[66,71,73,74,76],profile3:[66,73,74,76],profile_build:[48,50,65],profile_ful:71,profile_merg:71,profile_opt:[1,68,71,73,74,75,76],profile_schema:[66,73],profileencod:45,profiler_opt:[35,46,48,49,52,72],profiler_test:[74,76],profiler_train:[74,76],profiler_typ:[48,66,71,73,74,76],profiler_util:50,profilerencod:45,profileropt:[1,39,48,49,68,71,72,73,74,75,76],prop:[49,64],propag:29,proper:[11,72],properli:[12,49,72],properti:[4,5,8,9,10,14,15,16,18,21,22,23,24,26,27,29,30,33,34,35,36,37,38,39,43,46,47,48,49,51,52,53,63,64,66,71,73,74,76],proport:73,protect:29,protected_register_keras_serializ:29,proto:4,protocol:[47,50],provid:[1,2,4,27,29,32,40,48,50,63,64,65,66,68,69,71,73,74,76],pseudo:[74,76],psi:73,pst:68,pull_rul:72,purpos:[2,74,76],put:28,py3:67,py:[29,67],pypi:[66,67],pyplot:[71,74],pytest:67,python3:67,python:[29,38,43,45,46,51,66,67,73],quadratur:4,quantil:[40,41,49,51,66,73,74],quantiti:[3,66],queri:12,question:73,quick:[68,74],quickli:[2,74,76],quot:[4,10,14],quotechar:[10,12,14,63],r:[13,30,67,75],rag:28,rais:[1,4,12,25,29,36,44,45,48,49,50,71],raise_error:49,random:[3,4,28,29,34,48,58,66,68,72,73,75],random_st:[28,68],randomli:[28,73,75],rang:[1,14,29,61,73,74,76],rank:[29,36],rank_distribut:36,rare:[66,73],rather:[29,75],ratio:[1,34,37,38,43,49,51,71,73,74],raw:[4,68],rb:72,re:[29,48,49,68],reach:[4,73],read:[1,5,8,10,11,12,13,14,15,16,18,25,63,66,71,72,73,74,76],read_csv:72,read_csv_df:12,read_in_str:12,read_json:12,read_json_df:12,read_parquet_df:12,read_text_as_list_of_str:12,readabl:[13,25,50,68,73],readable_report:[66,73],reader:[0,1,6,12,63,66,68,70,72,73],readlin:4,real:68,reason:[29,74,76],rec_dropout:1,recal:[25,29,68],receiv:[25,29,75],recipi:68,recision_recall_fscore_support:25,recognit:[3,66,67,68,73],recommend:[29,50],reconstruct:[1,3,68],record:[4,5,8,10,15,16,50,76],record_samples_per_lin:[4,10],recurr:1,recurrent_activ:1,recurrent_dropout:1,recurs:[29,45,50],recursive_dict_upd:50,red:4,reduc:[1,50],reduce_max:29,reduce_mean:29,reduce_min:29,reduce_sum:29,redund:49,refer:[3,25,29,34,45],referenc:[25,73],refit:21,reflect:29,regard:68,regardless:71,regex:[6,12,20,28,48,63],regex_model:[20,30,75],regex_pattern:[30,75],regexflag:[48,49],regexmodel:[20,30],regexpostprocessor:[20,28,75],regist:[22,28,29,49,73],register_count:[49,73],registr:22,regress:45,regular:29,reinstanti:61,reject:50,rel:12,relat:[42,71,74],relev:[23,24,73],reload:[8,9,10,14,15,16,18,63],reload_labeler_from_options_or_get_new:50,relu:1,remain:28,remov:[2,46,48,50,67,68,69,71,73,74,76],remove_disabled_flag:[33,34,35,36,37,38,39,43,46,47,48,51,52,53],replac:[1,8,9,10,14,15,16,18,30,63,73],replic:[49,73],replica:29,repo:67,report:[1,6,20,29,32,33,34,35,36,37,38,39,40,43,46,47,48,51,52,53,56,57,63,64,65,66,68,69,70,71,75],report_dp_load:72,report_ful:71,report_help:41,report_merg:71,report_opt:[48,66,71,73,74,76],report_output_dir:72,report_pm_load:72,repres:[12,29,34,36,37,38,43,44,46,47,48,51,64],represent:[12,44,45],reproduc:73,request:4,requir:[1,3,4,26,28,29,30,48,49,50,65,66,67,68,73,74,75,76],require_modul:[31,57],requires_zero_map:[1,22,23,24,26,30],rerun:67,reserv:[1,29],reservoir:[5,12],reset:[1,21,22,23,24,26,29,30,66],reset_index:[1,68],reset_st:29,reset_weight:[21,22,23,24,26,30,68],resolut:[22,28],resolv:67,resourc:[2,29,50,72],respect:[46,48,50,61,65,68,73,75],respons:[5,73],rest:[29,64,75],restor:29,result:[1,2,3,25,28,29,35,48,50,61,66,68,71,73,74,75],retrain:[3,68],retriev:[21,22,23,24,26,27,28,29,30,44,73],return_sequ:1,reus:[3,29,50],revers:[22,23,24,26,29,30,36],reverse_label_map:[21,22,23,24,26,27,30,36],review:[3,74],rice:[71,73],right:29,rng:[6,70],rng_util:58,role:2,round:[25,48,73,74,76],row:[3,4,5,10,12,49,50,66,68,71,73,74],row_count:[66,71,73,74],row_has_null_ratio:[66,73,74],row_is_null_ratio:[66,71,73,74],row_statist:[49,73],rowstatisticsopt:49,rsampl:12,rtype:[12,28,29,36,37,38,43,46,47,49,50,51],rule:[29,63],run:[2,3,22,23,24,29,31,49,57,61,63,64,67,68,71,72,74,75,76],runtim:[48,73,74],runtimeerror:29,s:[1,2,3,5,12,22,28,29,38,41,43,46,49,50,51,63,64,65,68,69,73,74,76],safe:29,sai:[36,66,67],said:[28,74,75,76],sake:[1,68],sale:68,same:[1,3,4,12,21,22,23,24,25,26,27,28,29,30,36,49,50,64,66,71,72,73,74,76],same_a:[3,21,22,23,24,26,27,30],sampl:[1,3,5,12,18,21,22,23,24,25,28,36,37,38,43,48,49,50,51,66,68,71,74,75,76],sample1:71,sample2:71,sample3:71,sample_arrai:73,sample_id:48,sample_in_chunk:50,sample_nrow:[5,10,12],sample_ratio:[49,73],sample_s:[33,34,36,37,38,43,46,47,48,51,66,71,73,74],sample_size1:50,sample_size2:50,sample_skew:50,sample_weight:[25,29],samples_per_lin:[5,18],samples_per_upd:[48,73],samples_us:[66,73,74,76],sampling_ratio:[48,49,73],sarawagi:25,satisfi:73,save:[3,8,9,10,15,16,18,21,22,23,24,26,27,28,29,30,39,48,63,72],save_dirpath:[1,3,27,68],save_method:[48,73],save_own_vari:29,save_to_disk:[1,2,3,21,22,23,24,26,27,28,30,68,75],saved_label:[2,75],savedmodel:29,saw:68,scalar:29,scale:[64,66,73],scan:68,schema:[66,73,74,76],schooldatasmal:[68,76],scipi:64,scope:29,score:[1,25,26,29,68],scott:73,scratch:63,sdist:67,seaborn:65,search:[12,29],search_queri:12,search_str:68,second:[1,36,50,66,71,75],second_dict:50,section:[1,4,66,68,69,71,73,74,76],see:[2,25,29,44,49,61,64,66,67,71,72,73,74,75,76],seed:[6,49,58],seek_offset:13,seek_whenc:13,seem:49,seemlessli:72,seen:36,select:[5,8,10,15,16,18,28,35,63,73,76],selected_column:[4,5,10,12,16],selected_data_typ:35,selected_kei:[5,8,15],self:[1,29,33,34,35,36,37,38,39,43,46,47,48,49,51,53],send:[21,49,68,73],send_address:2,sensibl:45,sensit:[25,49,66,67,71,73,75],sent:[1,21,68,73],sentenc:[4,28,29,76],separ:[12,28,41,45,69,71,75],seper:[41,74,76],sequenc:29,sequenti:[1,71],serach:75,seri:[12,21,22,23,24,26,27,30,34,35,36,37,38,43,46,47,48,50,51,52,53,65,66,74,76],serial:[29,44,45],serializ:[3,29,48,73,74,76],serializbl:45,serialized_json:44,serv:1,set:[1,2,3,4,5,6,8,12,16,19,21,22,23,24,25,26,27,28,29,30,31,49,50,57,61,63,66,68,70,71,72,74,76],set_dpi:74,set_label:[2,21,27,75],set_label_map:[22,23,24,26,30],set_model:[1,3,21,27,68],set_opt:68,set_param:[1,2,3,21,22,23,24,26,27,28,30,68,75],set_postprocessor:[3,21,27,68,75],set_preprocessor:[3,21,27,68],set_se:[6,73],set_size_inch:74,set_verbos:[19,68,69,74,76],set_weight:29,setdefault:[1,50],setter:49,setup:[63,67],sever:[43,46,71,73],sha1:[3,66],sha256:[3,66],shallow:50,shantanu:25,shape:[1,25,28,29,64,73],share:[50,73],sheet:4,shorten:[48,71,73,74,76],should:[2,4,26,29,30,33,34,35,36,37,43,45,47,52,61,66,71,73,74,76],show:[1,2,25,65,68,69,71,73,75],show_confid:[2,3,21,22,23,24,26,27,30,68,75],shown:[4,25,29,64,71,73],shuffl:50,shuffle_in_chunk:50,shutil:72,si1:4,si2:4,sigmoid:1,sign:50,signatur:29,signific:[38,73],simialrli:74,similar:[2,3,26,48,73,74,76],similarli:[29,64,74,76],simpl:[68,74,76],simpli:[36,45,72],simultan:3,sinc:[3,8,16,29,68],singl:[4,10,21,22,23,24,26,27,28,29,30,50,66,69,75,76],single_profil:69,singlequot:4,size:[1,12,21,27,28,48,49,50,64,71],size_conv:[1,23,24],size_fc:[1,23,24],size_lstm:1,skeleton:64,sketch:[49,73],skew:[38,43,46,49,50,51,64,66,73],skip:[4,21,27,45,71,74],skip_postprocessor:[21,27],skipkei:45,sklearn:[25,29],slight:75,slightli:29,slimmer:[66,67],small:[68,73],smith:68,snappy_compressed_intentionally_mislabeled_fil:4,so:[29,49,51,65],softmax:1,softmax_output_layer_nam:1,softwar:29,some:[1,29,65,68,71,72,73],someth:[4,68],sort:[25,29,45,66,73],sort_dict:[64,66],sort_kei:45,sort_valu:[66,73],sourc:[12,14,24,67,68],source_fil:24,source_keyword:14,source_nod:14,space:1,spaci:[3,68],spam:68,spars:[4,71,74],special:[17,29],specif:[3,4,5,9,12,19,25,29,45,65,66,68,71,72,73,74,76],specifi:[1,2,3,5,8,9,10,11,14,15,16,17,18,21,25,27,28,29,41,45,48,49,50,61,63,64,65,71,72,74,75],split:[0,1,21,28,64,66,68,73,75],split_predict:28,split_ratio:[1,68],spreadsheet:[8,10,15,17],spreadsheetdata:[10,15,16],spreadsheetdatamixin:[10,15,16,17],sqrt:73,squar:[25,50,73],src:[4,29],ssmith:68,ssn:[2,3,5,66],st:75,stabil:[29,73],stage:2,standard:[68,72,73],standardli:72,start:[2,3,13,28,30,61,68,69,75],stat1:50,stat2:50,stat:[6,32,33,38,43,49,50,64,66,73],state:[28,29,49],statement:75,staticmethod:46,statist:[4,32,34,38,39,48,49,50,64,66,71,74,75,76],statu:[21,22,23,24,26,27,30],std:[66,74],stddev:[38,43,46,51,66,73,74],step:[1,2,29,67],still:[29,66,75],stop:[49,73,76],stop_condition_unique_value_ratio:[49,73],stop_word:[49,73,76],store:[22,29,48,50,74,76],str:[1,4,8,9,10,11,12,13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30,31,33,34,35,36,37,38,39,41,43,44,45,46,47,48,49,50,51,52,53,57,61,65,66,68,73,74,76],str_:28,stream:[5,12,13,71],strength:25,strict:[66,67],string:[1,2,3,4,5,12,13,14,17,25,26,28,29,30,33,34,35,36,37,38,39,43,45,46,47,48,49,50,51,52,53,61,66,68,71,72,73,74,75,76],stringio:[8,12,13,15,16],struct:28,structcharpostprocessor:[3,20,28,68],structcharpreprocessor:[3,20,28,68],structregexpostprocessor:[28,75],structur:[1,4,5,6,7,12,13,25,27,28,29,36,38,43,45,47,48,49,51,63,66,76],structured_mixin:[10,15,16,17],structured_model:20,structured_opt:[1,49,68,71,73,74,75],structured_profil:73,structured_report:73,structuredcol:48,structuredcolprofil:[44,48,65],structureddatalabel:[20,27],structuredopt:[35,48,49],structuredprofil:[8,9,10,14,15,16,18,48,63],sturg:73,sub:29,subclass:[9,13,21,22,23,24,26,27,28,29,30,33,34,37,44,45,46,47,51],subject:[4,29,68],sublass:36,submodul:29,subsequ:[28,73],subset:[25,49,68,73],subtext:75,subtract:[38,43,46,50,51,73],success:41,successfulli:71,sudo:67,suffix:2,suggest:[50,66,75],suggest_pool_s:50,suggested_pool_s:50,suit:68,sum:[29,36,49,51,66,73],sum_predict:36,summari:[1,3,23,24,25,68,74,76],sunita:25,superimpos:[38,43,46,51],supplement:4,suppli:29,support:[5,25,29,68,73,74,76],supports_mask:29,sure:[1,29],swap:[1,3],sy:[1,2,4,31,57,64,68,69,71,72,74,75,76],symbol:29,synchron:29,synthet:[74,76],system:[29,73],t334:3,t555:3,t:[28,29,31,45,50,57,66,67,73,74,76],tabl:[4,29],tabular:[1,3,64,68],take:[3,5,12,25,28,29,45,65,66,68,69,73,74,76],taken:29,tanh:1,target:[14,25],target_keyword:14,target_nam:25,target_nod:14,tcall:3,teach:[2,34,75],techniqu:4,tell:[46,75],tensor:29,tensorflow:[1,29,50,66,67,68,69,74,76],tensorflow_addon:29,tensorshap:29,tensorspec:29,term:[1,3,74,76],terminolog:66,test:[1,2,4,8,12,15,16,38,43,45,46,50,51,64,68,71,72,73,74,75,76],test_csv_data:67,test_label:68,test_profile_build:67,test_train_diff:64,testing_data:[64,74,76],testing_profil:64,testprofil:67,text:[1,3,4,5,6,7,10,20,23,24,25,28,29,32,46,49,66,68,71,73,74,76],text_column_profil:51,text_data:[11,18,66,71],text_fil:[4,66,71],text_sampl:71,textcolumn:51,textdata:[4,11,18,66,71],textiobas:13,textiowrapp:12,textopt:[49,51],textprofil:[35,53],textprofileropt:[49,53],textrm:29,tf:[1,6,20,29,68,69,74,76],tflite:29,tfmot:29,tfood:3,th:73,than:[1,2,12,28,29,36,73,75],thei:[4,22,23,24,26,28,29,30,31,57,68,71,73,74,76],them:[48,64,65,66,68,71,72,73,74,76],themselv:29,theori:4,therefor:12,thereof:29,thi:[1,2,3,4,7,8,9,10,12,14,15,16,18,25,26,28,29,30,34,35,36,37,38,40,42,43,45,46,47,48,49,50,51,61,64,65,66,67,68,69,71,72,73,74,75,76],thing:50,think:68,third:75,those:[2,68],thread_saf:[33,34,36,37,38,43,46,47,51],three:[68,73],threshold:[1,28,29,49,50,73],through:[5,12,34,68,71],throught:2,thrown:1,thu:29,thyme:68,ti:3,tie:28,time:[3,12,25,29,33,34,36,37,38,39,43,46,47,50,51,61,64,66,72,73,74,75,76],time_axi:72,time_index:72,time_offset:72,time_width:72,timedelta:50,titan:4,titl:[65,73,74],tjohn:3,tneed:3,tnot:3,to_datetim:72,to_fil:72,to_seri:45,togeth:[21,27,28,50,66,69,73,74,76],toggl:[50,66,71,73],token:18,tolist:[1,68],too:[2,50,66,67],took:73,top:[34,36,49,73],top_k:36,top_k_categori:[49,73],top_k_char:[49,73],top_k_mod:73,top_k_word:[49,73],top_profil:50,topolog:29,total:[5,12,25,29,73],tpleas:3,trace:29,track:29,train:[1,21,22,23,24,27,29,63,64,66,74,76],train_data:[22,23,24],train_structured_label:[3,27,68],trainabl:[1,3,21,27,29,68],trainable_vari:29,trainable_weight:29,trainabledatalabel:[3,21,27],training_data:[74,76],training_profil:64,transfer:63,transform:29,travers:34,treat:29,tree:42,true_char_level:[66,73,76],true_entities_in_index:29,true_positive_dict:2,tssn:3,tsv:[4,66,74,76],tupl:[1,12,22,23,24,25,28,29,45,48,50],turn:[29,49,68,71,73,74,75,76],tutori:[4,64],two:[3,4,28,29,36,37,38,39,43,46,47,48,50,51,52,53,64,66,69,71,72,73,74,76],txt:[1,4,42,66,67,71,73,74,76],tye:17,type:[1,3,5,8,9,10,11,12,13,14,15,16,17,18,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,40,41,43,44,46,47,48,49,50,51,52,53,61,63,66,68,71,72,73],typeerror:[29,45],typeguard:[12,13],typic:[5,29,50,68],typing_extens:[12,13],u:34,unalik:[34,66,73],unchang:[50,73],unclean:46,undefin:25,undefinedmetricwarn:25,under:29,underli:66,understand:73,unicod:12,unicode_to_str:12,uniform:64,unik:34,union:[8,9,10,11,12,13,14,15,16,18,21,22,23,24,25,26,27,28,30,39,48,49,50],uniqu:[1,4,29,34,49,50,68,73,74,76],unique_count:[34,49,66,73,74],unique_ratio:[34,66,73,74],unique_row_ratio:[66,73,74],uniquecountopt:[49,73],unit:[1,50,67],unittest:67,unknown:[1,3,28,29,66,68],unless:[29,72],unlik:[29,34],unnest:41,unspecifi:73,unstructur:[4,6,27,28,32,48,49,63,74,75],unstructured_labeler_profil:52,unstructured_model:20,unstructured_opt:[49,73,76],unstructured_profil:73,unstructured_report:73,unstructured_text_profil:53,unstructuredcompil:35,unstructureddatalabel:[20,27],unstructuredlabelerprofil:[35,52],unstructuredopt:49,unstructuredprofil:48,unstuctur:48,until:[28,73],unusu:29,unweight:25,up:[12,63],updat:[1,3,25,29,33,34,35,36,37,38,39,43,46,47,48,49,50,51,52,53,63,65],update_column_profil:48,update_d:50,update_profil:[35,48,66,71,73,74,76],update_st:29,upon:[21,26,27,28,29,30],upper:75,uppercas:75,uppercase_char:75,upstream:29,url:[3,4,12,66,68],url_as_str:12,url_to_byt:12,us:[1,3,4,8,10,12,13,14,15,16,18,20,21,22,23,24,25,26,27,28,29,30,36,44,45,48,49,50,58,63,64,65,66,67,68,71,73,74,76],us_stat:[3,66],usag:[22,28,63],use_word_level_argmax:[3,28,68],user:[1,2,3,4,5,8,10,15,16,18,21,22,23,24,25,27,30,31,48,57,64,66,68,69,71,73,74,76],user_set_histogram_bin:51,userdata1:[4,71],userdata1_intentionally_mislabled_fil:[4,71],usr:67,utf:[4,12,14,73,74],util:[2,3,4,6,7,19,20,32,35,48,55,66,68,69,70,73,75],utilizng:75,uuid:[3,66],v0:29,v1:[68,69,74,76],v:[50,67],val:[35,38,43,46,49,51,53],val_data:[22,23,24],valid:[0,1,3,5,6,8,10,12,15,16,21,22,23,24,27,49,66,70,71,72,73,74,76],validation_report:[74,76],validation_split:[3,21,68],valu:[1,2,4,10,12,13,19,21,22,23,24,25,26,27,28,29,30,33,34,35,36,37,38,39,43,46,47,48,49,50,51,66,68,72,73,74,75,76],valuabl:73,value1:[3,44],value2:[3,44],value3:3,value_label_df:1,valueerror:[1,12,29,44,45],vari:73,variabl:[27,29,34,38,43,46,48,49,51,65],variable_dtyp:29,variableaggregationv2:29,variablesynchron:29,varianc:[29,38,43,46,49,51,64,66,71,73,74],variat:34,variou:[5,11,29],vartyp:49,vast:73,ve:74,vector:29,venv3:67,verbos:[19,21,22,23,24,26,27,29,30],verifi:71,verify_ssl:5,version:[6,29,42,44,45,67,68,70,72,74,76],versu:25,via:[2,4,5,8,10,12,15,16,18,22,23,24,26,29,30,66,67,73,74,75,76],view:[1,2,4,50,64,68,69,71,72,74,75,76],virtual:[22,28,67],virtualenv:67,visit:66,visual:74,vocab:[49,66,73,74,76],vocab_count:[66,73],vocabulari:1,vol:34,vote:[28,36,75],vs1:4,vs2:4,vs:[28,63],w:[3,29,30,68],wa:[4,28,29,31,44,57,64,68,73,75],wai:[29,34,68,73],walk:71,want:[4,12,22,23,24,26,27,30,49,64,65,66,67,71],warn:[19,21,25,27,29,31,49,50,57],warn_for:25,warn_missing_modul:[31,57],warn_on_profil:50,warranti:29,wb:72,we:[1,2,4,12,29,34,49,64,68,71,72,73,74,75,76],weight:[1,3,21,22,23,24,25,26,29,30],welch:73,well:[3,12,29,71,73,74,75,76],went:4,were:[4,28,29,73,75],what:[2,3,4,12,49,50,63,74,75,76],when:[1,3,4,22,23,24,25,26,28,29,30,36,44,48,49,64,66,72,73,76],where:[1,2,3,12,21,22,23,24,26,27,28,29,30,34,48,73,75],whether:[4,12,13,14,15,21,22,23,24,26,27,28,29,30,49,71,73],which:[1,2,3,4,5,8,9,10,12,14,15,16,18,21,25,28,29,34,36,37,38,43,45,46,47,49,50,51,66,68,71,72,73,74,75,76],whitespac:[45,75],whl:67,whole:[22,23,24,26,30],whose:29,why:75,wide:[74,76],width:68,wiki:50,wikipedia:[25,50],wise:61,wish:29,with_name_scop:29,within:[4,12,19,21,27,28,29,30,36,38,43,47,49,51,52,65,73,75],without:[21,27,29,61],word:[28,49,66,68,73,75,76],word_count:[66,73,76],word_level:[28,66,73,76],word_level_min_perc:28,work:[1,14,29,49,64,65,66,71,72,73,74,76],would:[1,3,29,45,68,73,75],wrap:[7,29],wrapper:[12,27],write:[29,45],wrong:4,www:[29,50],x01:28,x1:50,x1b:4,x2:[50,67],x:[1,3,4,12,21,29,38,43,46,51,61,67,68,73],y1:50,y2:[50,67],y:[1,3,4,21,67,68],y_:25,y_pred:[25,29],y_true:[25,29],yate:50,yet:29,yield:45,you:[3,4,12,22,23,24,26,27,29,30,45,49,61,64,65,66,67,68,71,72,73,74,76],you_websit:5,your:[4,29,68,72,74],your_data:3,your_fil:[3,5,66,73],z2:67,z:[4,67,75],za:75,zero:[1,29,38,43,46,51,73],zoo:[21,27]},titles:["API","Adding new model to the existing DataLabeler pipeline","ColumnName Labeler Tutorial","Labeler (Sensitive Data)","Intro to Data Readers","Data Readers","Dataprofiler","Data Readers","Avro Data","Base Data","CSV Data","Data","Data Utils","Filepath Or Buffer","Graph Data","JSON Data","Parquet Data","Structured Mixins","Text Data","Dp Logging","Labelers","Base Data Labeler","Base Model","Char Load Tf Model","Character Level Cnn Model","Classification Report Utils","Column Name Model","Data Labelers","Data Processing","Labeler Utils","Regex Model","Utils","Profilers","Base Column Profilers","Categorical Column Profile","Column Profile Compilers","Data Labeler Column Profile","Datetime Column Profile","Float Column Profile","Graph Profiler","Helpers","Report Helpers","Histogram Utils","Int Column Profile","JSON Decoder","JSON Encoder","Numerical Column Stats","Order Column Profile","Profile Builder","Profiler Options","Profiler Utils","Text Column Profile","Unstructured Labeler Profile","Unstructured Text Profile","Utils","Reports","Graphs","Utils","Rng Utils","Settings","Validators","Base Validators","Version","Examples","Graph Pipeline Demo","Graphs","Data Profiler | What\u2019s in your data?","Install","Sensitive Data Detection with the Labeler","Merge List of Profiles","dataprofiler","Data Profiler - What\u2019s in your data?","Dataloader with Popmon Reports","Profiler","Structured Profilers","Building a Regex Data Labeler w/ your own Regex","Unstructured Profilers"],titleterms:{"char":23,"class":[65,71],"float":38,"import":[65,69],"int":43,"new":[1,2,3,75],A:4,Or:13,access:4,ad:1,adjust:75,after:4,alter:4,an:[3,65],api:0,attribut:4,automat:4,avro:8,avrodata:5,base:[9,21,22,33,61],basic:[63,71],both:72,buffer:13,build:[3,67,68,75],builder:48,categor:34,charact:[1,24],check:4,classif:25,cnn:24,column:[2,4,26,33,34,35,36,37,38,43,46,47,51],columnnam:2,comparison:72,compil:35,compon:3,conclus:[64,71],content:0,csv:10,csvdata:[4,5],data:[2,3,4,5,7,8,9,10,11,12,14,15,16,18,21,27,28,36,64,65,66,68,69,71,72,73,74,75,76],data_format:4,datafram:[4,66,73],datalabel:[1,75],dataload:72,dataprofil:[6,70,72],dataset:1,datetim:37,decod:44,deeper:4,delimit:[4,66,73],demo:64,depend:73,descript:73,detect:[4,68],differ:[64,73,74,76],dive:4,dp:19,encod:45,entiti:3,exampl:[63,65,72],exist:[1,2,3,75],extend:3,file:[4,66,73],filepath:13,filetyp:[66,73],floatcolumn:65,format:66,from:[65,67,68],futur:[2,75],get:66,graph:[14,39,56,64,65,66,73,74],graphdata:[4,5],ground:68,header:4,helper:[40,41],histogram:[42,65],how:72,identifi:3,implement:1,individu:65,instal:[67,72],intcolumn:65,integr:[1,75],intro:4,is_match:4,json:[15,44,45],jsondata:5,label:[2,3,20,21,27,29,36,52,66,68,75],learn:[3,68],level:[1,24],list:69,load:[2,3,4,23,64,66,68,73,74,75,76],load_from_librari:2,load_with_compon:2,log:19,lstm:1,matrix:65,merg:[66,69,71,73,74,76],miss:65,mixin:17,model:[1,2,3,22,23,24,26,30],modul:[6,7,20,32,40,55,60],name:[2,26],need:65,numer:46,option:[4,49,71,73,74,76],order:[47,73],own:[3,75],panda:[4,66,73],paramet:2,parquet:16,parquetdata:5,pipelin:[1,64],plot:65,popmon:72,postprocessor:[3,75],pre:[2,75],predict:[2,68,75],preprocessor:3,process:28,profil:[32,33,34,35,36,37,38,39,43,47,48,49,50,51,52,53,64,66,69,71,73,74,75,76],properti:75,purpos:66,quotechar:4,read:4,reader:[4,5,7,71],regex:[30,75],reload:4,replac:[2,75],report:[25,41,55,72,73,74,76],rng:58,rule:75,run:69,s:[66,71,72,75],sampl:73,save:[2,64,68,73,74,75,76],scratch:[67,68],seed:73,select:4,sensit:[3,68],set:[59,73,75],setup:69,size:73,snappi:67,specifi:[4,66,73],start:66,stat:46,statist:73,structur:[3,17,68,71,73,74,75],structuredprofil:[65,75],support:66,test:67,text:[18,51,53],textdata:5,tf:23,train:[3,68],transfer:[3,68],tutori:2,type:[4,74,76],unstructur:[3,52,53,66,68,71,73,76],up:68,updat:[66,71,73,74,76],url:5,us:[2,5,72,75],usag:[71,72],util:[12,25,29,31,42,50,54,57,58],valid:[60,61],valu:65,version:[62,66],vs:[71,73],w:75,we:65,what:[65,66,68,71],your:[3,65,66,71,73,75]}}) \ No newline at end of file diff --git a/docs/0.10.3/html/unstructured_profiler_example.html b/docs/0.10.3/html/unstructured_profiler_example.html new file mode 100644 index 000000000..b98d18353 --- /dev/null +++ b/docs/0.10.3/html/unstructured_profiler_example.html @@ -0,0 +1,835 @@ + + + + + + + + + Unstructured Profilers - Data Profiler v0.10.3 + + + + + + + + + + + + + Contents + + + + + + + + + Menu + + + + + + + + Expand + + + + + + + + + + + + + +
    +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + + + +

    View this notebook on GitHub

    +
    +

    Unstructured Profilers

    +

    Data profiling - is the process of examining a dataset and collecting statistical or informational summaries about said dataset.

    +

    The Profiler class inside the DataProfiler is designed to generate data profiles via the Profiler class, which ingests either a Data class or a Pandas DataFrame.

    +

    Currently, the Data class supports loading the following file formats:

    +
      +
    • Any delimited (CSV, TSV, etc.)

    • +
    • JSON object

    • +
    • Avro

    • +
    • Parquet

    • +
    • Text files

    • +
    • Pandas Series/Dataframe

    • +
    +

    Once the data is loaded, the Profiler can calculate statistics and predict the entities (via the Labeler) of every column (csv) or key-value (JSON) store as well as dataset wide information, such as the number of nulls, duplicates, etc.

    +

    This example will look at specifically the unstructured data types for unstructured profiling. This means that only text files, lists of strings, single column pandas dataframes/series, or DataProfile Data objects in string format will work with the unstructured profiler.

    +
    +

    Reporting

    +

    One of the primary purposes of the Profiler are to quickly identify what is in the dataset. This can be useful for analyzing a dataset prior to use or determining which columns could be useful for a given purpose.

    +

    In terms of reporting, there are multiple reporting options:

    +
      +
    • Pretty: Floats are rounded to four decimal places, and lists are shortened.

    • +
    • Compact: Similar to pretty, but removes detailed statistics

    • +
    • Serializable: Output is json serializable and not prettified

    • +
    • Flat: Nested Output is returned as a flattened dictionary

    • +
    +

    The Pretty and Compact reports are the two most commonly used reports and includes global_stats and data_stats for the given dataset. global_stats contains overall properties of the data such as samples used and file encoding. data_stats contains specific properties and statistics for each text sample.

    +

    For unstructured profiles, the report looks like this:

    +
    "global_stats": {
    +    "samples_used": int,
    +    "empty_line_count": int,
    +    "file_type": string,
    +    "encoding": string
    +},
    +"data_stats": {
    +    "data_label": {
    +        "entity_counts": {
    +            "word_level": dict(int),
    +            "true_char_level": dict(int),
    +            "postprocess_char_level": dict(int)
    +        },
    +        "times": dict(float)
    +    },
    +    "statistics": {
    +        "vocab": list(char),
    +        "words": list(string),
    +        "word_count": dict(int),
    +        "times": dict(float)
    +    }
    +}
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +import os
    +import sys
    +import json
    +
    +try:
    +    sys.path.insert(0, '..')
    +    import dataprofiler as dp
    +except ImportError:
    +    import dataprofiler as dp
    +
    +data_path = "../dataprofiler/tests/data"
    +
    +# remove extra tf loggin
    +import tensorflow as tf
    +tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)
    +
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(os.path.join(data_path, "txt/discussion_reddit.txt"))
    +profile = dp.Profiler(data)
    +
    +report  = profile.report(report_options={"output_format": "pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Profiler Type

    +

    It should be noted, in addition to reading the input data from text files, DataProfiler allows the input data as a pandas dataframe, a pandas series, a list, and Data objects (when an unstructured format is selected) if the Profiler is explicitly chosen as unstructured.

    +
    +
    [ ]:
    +
    +
    +
    +# run data profiler and get the report
    +import pandas as pd
    +data = dp.Data(os.path.join(data_path, "csv/SchoolDataSmall.csv"), options={"data_format": "records"})
    +profile = dp.Profiler(data, profiler_type='unstructured')
    +
    +report  = profile.report(report_options={"output_format":"pretty"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Profiler options

    +

    The DataProfiler has the ability to turn on and off components as needed. This is accomplished via the ProfilerOptions class.

    +

    For example, if a user doesn’t require vocab count information they may desire to turn off the word count functionality.

    +

    Below, let’s remove the vocab count and set the stop words.

    +

    Full list of options in the Profiler section of the DataProfiler documentation.

    +
    +
    [ ]:
    +
    +
    +
    +data = dp.Data(os.path.join(data_path, "txt/discussion_reddit.txt"))
    +
    +profile_options = dp.ProfilerOptions()
    +
    +# Setting multiple options via set
    +profile_options.set({ "*.vocab.is_enabled": False, "*.is_case_sensitive": True })
    +
    +# Set options via directly setting them
    +profile_options.unstructured_options.text.stop_words = ["These", "are", "stop", "words"]
    +
    +profile = dp.Profiler(data, options=profile_options)
    +report  = profile.report(report_options={"output_format": "compact"})
    +
    +# Print the report
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Updating Profiles

    +

    Beyond just profiling, one of the unique aspects of the DataProfiler is the ability to update the profiles. To update appropriately, the schema (columns / keys) must match appropriately.

    +
    +
    [ ]:
    +
    +
    +
    +# Load and profile a CSV file
    +data = dp.Data(os.path.join(data_path, "txt/sentence-3x.txt"))
    +profile = dp.Profiler(data)
    +
    +# Update the profile with new data:
    +new_data = dp.Data(os.path.join(data_path, "txt/sentence-3x.txt"))
    +profile.update_profile(new_data)
    +
    +# Take a peek at the data
    +print(data.data)
    +print(new_data.data)
    +
    +# Report the compact version of the profile
    +report  = profile.report(report_options={"output_format": "compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    +

    Merging Profiles

    +

    Merging profiles are an alternative method for updating profiles. Particularly, multiple profiles can be generated seperately, then added together with a simple + command: profile3 = profile1 + profile2

    +
    +
    [ ]:
    +
    +
    +
    +# Load a CSV file with a schema
    +data1 = dp.Data(os.path.join(data_path, "txt/sentence-3x.txt"))
    +profile1 = dp.Profiler(data1)
    +
    +# Load another CSV file with the same schema
    +data2 = dp.Data(os.path.join(data_path, "txt/sentence-3x.txt"))
    +profile2 = dp.Profiler(data2)
    +
    +# Merge the profiles
    +profile3 = profile1 + profile2
    +
    +# Report the compact version of the profile
    +report  = profile3.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    As you can see, the update_profile function and the + operator function similarly. The reason the + operator is important is that it’s possible to save and load profiles, which we cover next.

    +
    +
    +

    Differences in Data

    +

    Can be applied to both structured and unstructured datasets.

    +

    Such reports can provide details on the differences between training and validation data like in this pseudo example:

    +
    profiler_training = dp.Profiler(training_data)
    +profiler_testing = dp.Profiler(testing_data)
    +
    +validation_report = profiler_training.diff(profiler_testing)
    +
    +
    +
    +
    [ ]:
    +
    +
    +
    +from pprint import pprint
    +
    +# unstructured differences example
    +data_split_differences = profile1.diff(profile2)
    +pprint(data_split_differences)
    +
    +
    +
    +
    +
    +

    Saving and Loading a Profile

    +

    Not only can the Profiler create and update profiles, it’s also possible to save, load then manipulate profiles.

    +
    +
    [ ]:
    +
    +
    +
    +# Load data
    +data = dp.Data(os.path.join(data_path, "txt/sentence-3x.txt"))
    +
    +# Generate a profile
    +profile = dp.Profiler(data)
    +
    +# Save a profile to disk for later (saves as pickle file)
    +profile.save(filepath="my_profile.pkl")
    +
    +# Load a profile from disk
    +loaded_profile = dp.Profiler.load("my_profile.pkl")
    +
    +# Report the compact version of the profile
    +report = profile.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +

    With the ability to save and load profiles, profiles can be generated via multiple machines then merged. Further, profiles can be stored and later used in applications such as change point detection, synthetic data generation, and more.

    +
    +
    [ ]:
    +
    +
    +
    +# Load a multiple files via the Data class
    +filenames = ["txt/sentence-3x.txt",
    +             "txt/sentence.txt"]
    +data_objects = []
    +for filename in filenames:
    +    data_objects.append(dp.Data(os.path.join(data_path, filename)))
    +
    +print(data_objects)
    +# Generate and save profiles
    +for i in range(len(data_objects)):
    +    profile = dp.Profiler(data_objects[i])
    +    report = profile.report(report_options={"output_format":"compact"})
    +    print(json.dumps(report, indent=4))
    +    profile.save(filepath="data-"+str(i)+".pkl")
    +
    +
    +# Load profiles and add them together
    +profile = None
    +for i in range(len(data_objects)):
    +    if profile is None:
    +        profile = dp.Profiler.load("data-"+str(i)+".pkl")
    +    else:
    +        profile += dp.Profiler.load("data-"+str(i)+".pkl")
    +
    +
    +# Report the compact version of the profile
    +report = profile.report(report_options={"output_format":"compact"})
    +print(json.dumps(report, indent=4))
    +
    +
    +
    +
    +
    + +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/docs/0.10.3/html/unstructured_profiler_example.ipynb b/docs/0.10.3/html/unstructured_profiler_example.ipynb new file mode 100644 index 000000000..9ab754cc7 --- /dev/null +++ b/docs/0.10.3/html/unstructured_profiler_example.ipynb @@ -0,0 +1,436 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "f37ca393", + "metadata": {}, + "source": [ + "# Unstructured Profilers" + ] + }, + { + "cell_type": "markdown", + "id": "ff9bd095", + "metadata": {}, + "source": [ + "**Data profiling** - *is the process of examining a dataset and collecting statistical or informational summaries about said dataset.*\n", + "\n", + "The Profiler class inside the DataProfiler is designed to generate *data profiles* via the Profiler class, which ingests either a Data class or a Pandas DataFrame. \n", + "\n", + "Currently, the Data class supports loading the following file formats:\n", + "\n", + "* Any delimited (CSV, TSV, etc.)\n", + "* JSON object\n", + "* Avro\n", + "* Parquet\n", + "* Text files\n", + "* Pandas Series/Dataframe\n", + "\n", + "Once the data is loaded, the Profiler can calculate statistics and predict the entities (via the Labeler) of every column (csv) or key-value (JSON) store as well as dataset wide information, such as the number of nulls, duplicates, etc.\n", + "\n", + "This example will look at specifically the unstructured data types for unstructured profiling. This means that only text files, lists of strings, single column pandas dataframes/series, or DataProfile Data objects in string format will work with the unstructured profiler. " + ] + }, + { + "cell_type": "markdown", + "id": "de58b9c4", + "metadata": {}, + "source": [ + "## Reporting" + ] + }, + { + "cell_type": "markdown", + "id": "8001185a", + "metadata": {}, + "source": [ + "One of the primary purposes of the Profiler are to quickly identify what is in the dataset. This can be useful for analyzing a dataset prior to use or determining which columns could be useful for a given purpose.\n", + "\n", + "In terms of reporting, there are multiple reporting options:\n", + "\n", + "* **Pretty**: Floats are rounded to four decimal places, and lists are shortened.\n", + "* **Compact**: Similar to pretty, but removes detailed statistics\n", + "* **Serializable**: Output is json serializable and not prettified\n", + "* **Flat**: Nested Output is returned as a flattened dictionary\n", + "\n", + "The **Pretty** and **Compact** reports are the two most commonly used reports and includes `global_stats` and `data_stats` for the given dataset. `global_stats` contains overall properties of the data such as samples used and file encoding. `data_stats` contains specific properties and statistics for each text sample.\n", + "\n", + "For unstructured profiles, the report looks like this:\n", + "\n", + "```\n", + "\"global_stats\": {\n", + " \"samples_used\": int,\n", + " \"empty_line_count\": int,\n", + " \"file_type\": string,\n", + " \"encoding\": string\n", + "},\n", + "\"data_stats\": {\n", + " \"data_label\": {\n", + " \"entity_counts\": {\n", + " \"word_level\": dict(int),\n", + " \"true_char_level\": dict(int),\n", + " \"postprocess_char_level\": dict(int)\n", + " },\n", + " \"times\": dict(float)\n", + " },\n", + " \"statistics\": {\n", + " \"vocab\": list(char),\n", + " \"words\": list(string),\n", + " \"word_count\": dict(int),\n", + " \"times\": dict(float)\n", + " }\n", + "}\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5fcb5447", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import sys\n", + "import json\n", + "\n", + "try:\n", + " sys.path.insert(0, '..')\n", + " import dataprofiler as dp\n", + "except ImportError:\n", + " import dataprofiler as dp\n", + "\n", + "data_path = \"../dataprofiler/tests/data\"\n", + "\n", + "# remove extra tf loggin\n", + "import tensorflow as tf\n", + "tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a7fc2df6", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"txt/discussion_reddit.txt\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "report = profile.report(report_options={\"output_format\": \"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "4d183992", + "metadata": {}, + "source": [ + "## Profiler Type" + ] + }, + { + "cell_type": "markdown", + "id": "d7ec39d2", + "metadata": {}, + "source": [ + "It should be noted, in addition to reading the input data from text files, DataProfiler allows the input data as a pandas dataframe, a pandas series, a list, and Data objects (when an unstructured format is selected) if the Profiler is explicitly chosen as unstructured." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29737f25", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "# run data profiler and get the report\n", + "import pandas as pd\n", + "data = dp.Data(os.path.join(data_path, \"csv/SchoolDataSmall.csv\"), options={\"data_format\": \"records\"})\n", + "profile = dp.Profiler(data, profiler_type='unstructured')\n", + "\n", + "report = profile.report(report_options={\"output_format\":\"pretty\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "fe02ad64", + "metadata": {}, + "source": [ + "## Profiler options" + ] + }, + { + "cell_type": "markdown", + "id": "40804cc9", + "metadata": {}, + "source": [ + "The DataProfiler has the ability to turn on and off components as needed. This is accomplished via the `ProfilerOptions` class.\n", + "\n", + "For example, if a user doesn't require vocab count information they may desire to turn off the word count functionality.\n", + "\n", + "Below, let's remove the vocab count and set the stop words. \n", + "\n", + "Full list of options in the Profiler section of the [DataProfiler documentation](https://capitalone.github.io/DataProfiler/profile_options.html)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9d25d899", + "metadata": { + "scrolled": true, + "tags": [] + }, + "outputs": [], + "source": [ + "data = dp.Data(os.path.join(data_path, \"txt/discussion_reddit.txt\"))\n", + "\n", + "profile_options = dp.ProfilerOptions()\n", + "\n", + "# Setting multiple options via set\n", + "profile_options.set({ \"*.vocab.is_enabled\": False, \"*.is_case_sensitive\": True })\n", + "\n", + "# Set options via directly setting them\n", + "profile_options.unstructured_options.text.stop_words = [\"These\", \"are\", \"stop\", \"words\"]\n", + "\n", + "profile = dp.Profiler(data, options=profile_options)\n", + "report = profile.report(report_options={\"output_format\": \"compact\"})\n", + "\n", + "# Print the report\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "2052415a", + "metadata": {}, + "source": [ + "## Updating Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "7e02f746", + "metadata": {}, + "source": [ + "Beyond just profiling, one of the unique aspects of the DataProfiler is the ability to update the profiles. To update appropriately, the schema (columns / keys) must match appropriately." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7ab8022f", + "metadata": {}, + "outputs": [], + "source": [ + "# Load and profile a CSV file\n", + "data = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Update the profile with new data:\n", + "new_data = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile.update_profile(new_data)\n", + "\n", + "# Take a peek at the data\n", + "print(data.data)\n", + "print(new_data.data)\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\": \"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "66ec6dc5", + "metadata": {}, + "source": [ + "## Merging Profiles" + ] + }, + { + "cell_type": "markdown", + "id": "e2265fe9", + "metadata": {}, + "source": [ + "Merging profiles are an alternative method for updating profiles. Particularly, multiple profiles can be generated seperately, then added together with a simple `+` command: `profile3 = profile1 + profile2`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cc68ca07", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a CSV file with a schema\n", + "data1 = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile1 = dp.Profiler(data1)\n", + "\n", + "# Load another CSV file with the same schema\n", + "data2 = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "profile2 = dp.Profiler(data2)\n", + "\n", + "# Merge the profiles\n", + "profile3 = profile1 + profile2\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile3.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "7ea07dc6", + "metadata": {}, + "source": [ + "As you can see, the `update_profile` function and the `+` operator function similarly. The reason the `+` operator is important is that it's possible to *save and load profiles*, which we cover next." + ] + }, + { + "cell_type": "markdown", + "id": "4704961a", + "metadata": {}, + "source": [ + "## Differences in Data\n", + "Can be applied to both structured and unstructured datasets. \n", + "\n", + "Such reports can provide details on the differences between training and validation data like in this pseudo example:\n", + "```python\n", + "profiler_training = dp.Profiler(training_data)\n", + "profiler_testing = dp.Profiler(testing_data)\n", + "\n", + "validation_report = profiler_training.diff(profiler_testing)\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "58f92c1b", + "metadata": {}, + "outputs": [], + "source": [ + "from pprint import pprint\n", + "\n", + "# unstructured differences example\n", + "data_split_differences = profile1.diff(profile2)\n", + "pprint(data_split_differences)" + ] + }, + { + "cell_type": "markdown", + "id": "30868000", + "metadata": {}, + "source": [ + "## Saving and Loading a Profile" + ] + }, + { + "cell_type": "markdown", + "id": "f2858072", + "metadata": {}, + "source": [ + "Not only can the Profiler create and update profiles, it's also possible to save, load then manipulate profiles." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ad9ca57", + "metadata": {}, + "outputs": [], + "source": [ + "# Load data\n", + "data = dp.Data(os.path.join(data_path, \"txt/sentence-3x.txt\"))\n", + "\n", + "# Generate a profile\n", + "profile = dp.Profiler(data)\n", + "\n", + "# Save a profile to disk for later (saves as pickle file)\n", + "profile.save(filepath=\"my_profile.pkl\")\n", + "\n", + "# Load a profile from disk\n", + "loaded_profile = dp.Profiler.load(\"my_profile.pkl\")\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "8f9859c2", + "metadata": {}, + "source": [ + "With the ability to save and load profiles, profiles can be generated via multiple machines then merged. Further, profiles can be stored and later used in applications such as change point detection, synthetic data generation, and more. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3571f2d0", + "metadata": {}, + "outputs": [], + "source": [ + "# Load a multiple files via the Data class\n", + "filenames = [\"txt/sentence-3x.txt\",\n", + " \"txt/sentence.txt\"]\n", + "data_objects = []\n", + "for filename in filenames:\n", + " data_objects.append(dp.Data(os.path.join(data_path, filename)))\n", + "\n", + "print(data_objects)\n", + "# Generate and save profiles\n", + "for i in range(len(data_objects)):\n", + " profile = dp.Profiler(data_objects[i])\n", + " report = profile.report(report_options={\"output_format\":\"compact\"})\n", + " print(json.dumps(report, indent=4))\n", + " profile.save(filepath=\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Load profiles and add them together\n", + "profile = None\n", + "for i in range(len(data_objects)):\n", + " if profile is None:\n", + " profile = dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + " else:\n", + " profile += dp.Profiler.load(\"data-\"+str(i)+\".pkl\")\n", + "\n", + "\n", + "# Report the compact version of the profile\n", + "report = profile.report(report_options={\"output_format\":\"compact\"})\n", + "print(json.dumps(report, indent=4))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/source/dataprofiler.profilers.profiler_utils.rst b/docs/source/dataprofiler.profilers.profiler_utils.rst new file mode 100644 index 000000000..5e9c6533c --- /dev/null +++ b/docs/source/dataprofiler.profilers.profiler_utils.rst @@ -0,0 +1,7 @@ +Profiler Utils +============== + +.. automodule:: dataprofiler.profilers.profiler_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/dataprofiler.profilers.rst b/docs/source/dataprofiler.profilers.rst index b08153106..7a5b45394 100644 --- a/docs/source/dataprofiler.profilers.rst +++ b/docs/source/dataprofiler.profilers.rst @@ -28,10 +28,10 @@ Modules dataprofiler.profilers.order_column_profile dataprofiler.profilers.profile_builder dataprofiler.profilers.profiler_options + dataprofiler.profilers.profiler_utils dataprofiler.profilers.text_column_profile dataprofiler.profilers.unstructured_labeler_profile dataprofiler.profilers.unstructured_text_profile - dataprofiler.profilers.utils .. automodule:: dataprofiler.profilers :members: diff --git a/docs/source/dataprofiler.rng_utils.rst b/docs/source/dataprofiler.rng_utils.rst new file mode 100644 index 000000000..e4b84b46a --- /dev/null +++ b/docs/source/dataprofiler.rng_utils.rst @@ -0,0 +1,7 @@ +Rng Utils +========= + +.. automodule:: dataprofiler.rng_utils + :members: + :undoc-members: + :show-inheritance: \ No newline at end of file diff --git a/docs/source/dataprofiler.rst b/docs/source/dataprofiler.rst index 7a57e0427..d5ed33a58 100644 --- a/docs/source/dataprofiler.rst +++ b/docs/source/dataprofiler.rst @@ -18,6 +18,7 @@ Modules :maxdepth: 4 dataprofiler.dp_logging + dataprofiler.rng_utils dataprofiler.settings dataprofiler.version diff --git a/docs/source/index.rst b/docs/source/index.rst index 9f604377e..9f3bb4369 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -475,6 +475,7 @@ In addition, it utilizes only the first 10,000 rows. Versions ======== +* `0.10.3`_ * `0.10.2`_ * `0.10.1`_ * `0.10.0`_ @@ -575,3 +576,5 @@ Versions .. _0.10.2: ../../0.10.2/html/index.html +.. _0.10.3: ../../0.10.3/html/index.html + diff --git a/docs/source/profiler.rst b/docs/source/profiler.rst index 145bdeb47..b51a72313 100644 --- a/docs/source/profiler.rst +++ b/docs/source/profiler.rst @@ -662,7 +662,8 @@ Below is an breakdown of all the options. * **structured_options** - Options responsible for all structured data - * **multiprocess** - Option to enable multiprocessing. Automatically selects the optimal number of processes to utilize based on system constraints. + * **multiprocess** - Option to enable multiprocessing. If on, multiprocessing is toggled on if the dataset contains more than 750,000 rows or more than 20 columns. + Automatically selects the optimal number of pooling processes to utilize based on system constraints when toggled on. * is_enabled - (Boolean) Enables or disables multiprocessing @@ -717,6 +718,8 @@ Below is an breakdown of all the options. If multiple specified (list) the optimal method will be chosen by attempting the provided ones. methods: 'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt' Note: 'auto' is used to choose optimally between 'fd' and 'sturges' + * num_quantiles - (Int) Number of quantiles to bin the data. + Default value is set to 1,000 quantiles. * is_enabled - (Boolean) Enables or disables histogram and quantiles * **float** - Options for the float columns @@ -772,6 +775,8 @@ Below is an breakdown of all the options. If multiple specified (list) the optimal method will be chosen by attempting the provided ones. methods: 'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt' Note: 'auto' is used to choose optimally between 'fd' and 'sturges' + * num_quantiles - (Int) Number of quantiles to bin the data. + Default value is set to 1,000 quantiles. * is_enabled - (Boolean) Enables or disables histogram and quantiles * **text** - Options for the text columns @@ -825,6 +830,8 @@ Below is an breakdown of all the options. If multiple specified (list) the optimal method will be chosen by attempting the provided ones. methods: 'auto', 'fd', 'doane', 'scott', 'rice', 'sturges', 'sqrt' Note: 'auto' is used to choose optimally between 'fd' and 'sturges' + * num_quantiles - (Int) Number of quantiles to bin the data. + Default value is set to 1,000 quantiles. * is_enabled - (Boolean) Enables or disables histogram and quantiles * **datetime** - Options for the datetime columns diff --git a/docs/update_documentation.py b/docs/update_documentation.py index e780243bc..93d5d8b19 100644 --- a/docs/update_documentation.py +++ b/docs/update_documentation.py @@ -74,3 +74,13 @@ ) index_file.write(redirect_link) index_file.close() + +# update the profiler_options.html file to redirect to detailed options docs +index_file = open("../profiler_options.html", "w") +redirect_link = ( + '' +) +index_file.write(redirect_link) +index_file.close() diff --git a/index.html b/index.html index 779e2aa6d..20c5ba7c2 100644 --- a/index.html +++ b/index.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/profiler_options.html b/profiler_options.html new file mode 100644 index 000000000..59fa9a354 --- /dev/null +++ b/profiler_options.html @@ -0,0 +1 @@ + \ No newline at end of file

    wxM$1?$~;$9o?3FsK)AtWbso2^6Q{uPXL z3C=|$t3bR@UBKM4-Tiof;6C;dj%jzs-OTZD54!t~Zz{?~iYLOL+o@sO_8981~}b^`O>`yhb>OtDjqu)2jF4iQl#xU8KQ2 z*%POCcP_+J%lrgr&_VktEF7FLLO>rsw(?=B==&6YPK%%2P6NNTM?tN+XxC2BTMRc2 zxH{*0@p(%@5VeBH(Ow?k7;g`qTGZ+`t7qw?Tn{BX=*IeXwH7p+Xd0r+8D8Qv99B}L zk0ewXI{`9A6b%}77_x$G{QH#EhI86!^p0Cn}OLJ!Y-&6icD z(+N6N7ss?3P6u=*P;nP^yptaf)Os0bz4YSQ)SFZn{?{O*@ebZ^0)uS5*L;y`9Pc6= zLJ$fbO}hb{dhzy#-CFM2%MK`B$L~!}s~4Z&ad4)rUadQA$Ond@9O;Ev-uw-Ucy(Mf z~0iPlcIQ&2cg5^wswM;vgk=Q?lRKRjzW$C5cd`;tw-plmlcIL$ zbn8L&Y?DN4mvgoqgicj&$)uzfRZn}N7cmjtDL*t1MCi+TXgDbq!aW#o12Q30z@|^T z;N5mnt-9njfE?8HLVCg=NC~Gp;0^n1Jy^cAW1mq!A)>oUs~|b8We8%!YkE=dwhjOO z{CK>h?X;^Pi#RKdVYX4pq7CRtJz~p^qIP(Ae*VmvGjr{8ksGw;g3j`M-8nsvn&Ese zzJOXVP|%_pIoLyk?)9*f?z9iRW*Huj zH#@Dc7iJh1ZXXB^VN3a85V;F8Xe@tYZh-S_U(tU|H8{%o$=33At%iD{$!cl2J z+<^n;=gFg@{7DGoTY7iEy5P$Yuvd`n5Yqw;2yxsIo(o}%WNE)x-k|RNIDE6`;JeWc zFN`eA9wEEM9J88bTZ@=%PT@_#v!(EA!!e#IEOZakj6`^X&&#};lOvqoiM?361N`-2Vg1%whBZ literal 0 HcmV?d00001 diff --git a/docs/0.10.3/doctrees/dataprofiler.profilers.profile_builder.doctree b/docs/0.10.3/doctrees/dataprofiler.profilers.profile_builder.doctree new file mode 100644 index 0000000000000000000000000000000000000000..995127d7726beb970bcc1c56cbd6ddcaa429a8db GIT binary patch literal 268990 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⪻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