fg-data-profiling 4.19.0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. data_profiling/__init__.py +34 -0
  2. data_profiling/compare_reports.py +359 -0
  3. data_profiling/config.py +496 -0
  4. data_profiling/config_default.yaml +223 -0
  5. data_profiling/config_minimal.yaml +222 -0
  6. data_profiling/controller/__init__.py +1 -0
  7. data_profiling/controller/console.py +125 -0
  8. data_profiling/controller/pandas_decorator.py +21 -0
  9. data_profiling/expectations_report.py +117 -0
  10. data_profiling/model/__init__.py +4 -0
  11. data_profiling/model/alerts.py +780 -0
  12. data_profiling/model/correlations.py +163 -0
  13. data_profiling/model/dataframe.py +35 -0
  14. data_profiling/model/describe.py +210 -0
  15. data_profiling/model/description.py +108 -0
  16. data_profiling/model/duplicates.py +14 -0
  17. data_profiling/model/expectation_algorithms.py +112 -0
  18. data_profiling/model/handler.py +81 -0
  19. data_profiling/model/missing.py +146 -0
  20. data_profiling/model/pairwise.py +33 -0
  21. data_profiling/model/pandas/__init__.py +55 -0
  22. data_profiling/model/pandas/correlations_pandas.py +207 -0
  23. data_profiling/model/pandas/dataframe_pandas.py +26 -0
  24. data_profiling/model/pandas/describe_boolean_pandas.py +43 -0
  25. data_profiling/model/pandas/describe_categorical_pandas.py +274 -0
  26. data_profiling/model/pandas/describe_counts_pandas.py +63 -0
  27. data_profiling/model/pandas/describe_date_pandas.py +77 -0
  28. data_profiling/model/pandas/describe_file_pandas.py +56 -0
  29. data_profiling/model/pandas/describe_generic_pandas.py +36 -0
  30. data_profiling/model/pandas/describe_image_pandas.py +255 -0
  31. data_profiling/model/pandas/describe_numeric_pandas.py +175 -0
  32. data_profiling/model/pandas/describe_path_pandas.py +63 -0
  33. data_profiling/model/pandas/describe_supported_pandas.py +41 -0
  34. data_profiling/model/pandas/describe_text_pandas.py +62 -0
  35. data_profiling/model/pandas/describe_timeseries_pandas.py +222 -0
  36. data_profiling/model/pandas/describe_url_pandas.py +57 -0
  37. data_profiling/model/pandas/discretize_pandas.py +81 -0
  38. data_profiling/model/pandas/duplicates_pandas.py +56 -0
  39. data_profiling/model/pandas/imbalance_pandas.py +35 -0
  40. data_profiling/model/pandas/missing_pandas.py +42 -0
  41. data_profiling/model/pandas/sample_pandas.py +38 -0
  42. data_profiling/model/pandas/summary_pandas.py +101 -0
  43. data_profiling/model/pandas/table_pandas.py +56 -0
  44. data_profiling/model/pandas/timeseries_index_pandas.py +33 -0
  45. data_profiling/model/pandas/utils_pandas.py +27 -0
  46. data_profiling/model/sample.py +37 -0
  47. data_profiling/model/spark/__init__.py +48 -0
  48. data_profiling/model/spark/correlations_spark.py +152 -0
  49. data_profiling/model/spark/dataframe_spark.py +34 -0
  50. data_profiling/model/spark/describe_boolean_spark.py +27 -0
  51. data_profiling/model/spark/describe_categorical_spark.py +28 -0
  52. data_profiling/model/spark/describe_counts_spark.py +105 -0
  53. data_profiling/model/spark/describe_date_spark.py +51 -0
  54. data_profiling/model/spark/describe_generic_spark.py +30 -0
  55. data_profiling/model/spark/describe_numeric_spark.py +155 -0
  56. data_profiling/model/spark/describe_supported_spark.py +33 -0
  57. data_profiling/model/spark/describe_text_spark.py +25 -0
  58. data_profiling/model/spark/duplicates_spark.py +54 -0
  59. data_profiling/model/spark/missing_spark.py +96 -0
  60. data_profiling/model/spark/sample_spark.py +43 -0
  61. data_profiling/model/spark/summary_spark.py +95 -0
  62. data_profiling/model/spark/table_spark.py +58 -0
  63. data_profiling/model/spark/timeseries_index_spark.py +12 -0
  64. data_profiling/model/summarizer.py +207 -0
  65. data_profiling/model/summary.py +66 -0
  66. data_profiling/model/summary_algorithms.py +276 -0
  67. data_profiling/model/table.py +10 -0
  68. data_profiling/model/timeseries_index.py +16 -0
  69. data_profiling/model/typeset.py +365 -0
  70. data_profiling/model/typeset_relations.py +143 -0
  71. data_profiling/profile_report.py +573 -0
  72. data_profiling/report/__init__.py +4 -0
  73. data_profiling/report/formatters.py +346 -0
  74. data_profiling/report/presentation/__init__.py +1 -0
  75. data_profiling/report/presentation/core/__init__.py +39 -0
  76. data_profiling/report/presentation/core/alerts.py +18 -0
  77. data_profiling/report/presentation/core/collapse.py +24 -0
  78. data_profiling/report/presentation/core/container.py +50 -0
  79. data_profiling/report/presentation/core/correlation_table.py +21 -0
  80. data_profiling/report/presentation/core/dropdown.py +44 -0
  81. data_profiling/report/presentation/core/duplicate.py +16 -0
  82. data_profiling/report/presentation/core/frequency_table.py +14 -0
  83. data_profiling/report/presentation/core/frequency_table_small.py +16 -0
  84. data_profiling/report/presentation/core/html.py +14 -0
  85. data_profiling/report/presentation/core/image.py +34 -0
  86. data_profiling/report/presentation/core/item_renderer.py +17 -0
  87. data_profiling/report/presentation/core/renderable.py +42 -0
  88. data_profiling/report/presentation/core/root.py +35 -0
  89. data_profiling/report/presentation/core/sample.py +20 -0
  90. data_profiling/report/presentation/core/scores.py +32 -0
  91. data_profiling/report/presentation/core/table.py +26 -0
  92. data_profiling/report/presentation/core/toggle_button.py +14 -0
  93. data_profiling/report/presentation/core/variable.py +40 -0
  94. data_profiling/report/presentation/core/variable_info.py +36 -0
  95. data_profiling/report/presentation/flavours/__init__.py +9 -0
  96. data_profiling/report/presentation/flavours/flavour_html.py +64 -0
  97. data_profiling/report/presentation/flavours/flavour_widget.py +61 -0
  98. data_profiling/report/presentation/flavours/flavours.py +43 -0
  99. data_profiling/report/presentation/flavours/html/__init__.py +47 -0
  100. data_profiling/report/presentation/flavours/html/alerts.py +10 -0
  101. data_profiling/report/presentation/flavours/html/collapse.py +7 -0
  102. data_profiling/report/presentation/flavours/html/container.py +58 -0
  103. data_profiling/report/presentation/flavours/html/correlation_table.py +13 -0
  104. data_profiling/report/presentation/flavours/html/dropdown.py +7 -0
  105. data_profiling/report/presentation/flavours/html/duplicate.py +24 -0
  106. data_profiling/report/presentation/flavours/html/frequency_table.py +20 -0
  107. data_profiling/report/presentation/flavours/html/frequency_table_small.py +15 -0
  108. data_profiling/report/presentation/flavours/html/html.py +6 -0
  109. data_profiling/report/presentation/flavours/html/image.py +7 -0
  110. data_profiling/report/presentation/flavours/html/root.py +14 -0
  111. data_profiling/report/presentation/flavours/html/sample.py +12 -0
  112. data_profiling/report/presentation/flavours/html/scores.py +11 -0
  113. data_profiling/report/presentation/flavours/html/table.py +7 -0
  114. data_profiling/report/presentation/flavours/html/templates/alerts/alert_constant.html +1 -0
  115. data_profiling/report/presentation/flavours/html/templates/alerts/alert_constant_length.html +1 -0
  116. data_profiling/report/presentation/flavours/html/templates/alerts/alert_dirty_category.html +1 -0
  117. data_profiling/report/presentation/flavours/html/templates/alerts/alert_duplicates.html +1 -0
  118. data_profiling/report/presentation/flavours/html/templates/alerts/alert_empty.html +1 -0
  119. data_profiling/report/presentation/flavours/html/templates/alerts/alert_high_cardinality.html +1 -0
  120. data_profiling/report/presentation/flavours/html/templates/alerts/alert_high_correlation.html +4 -0
  121. data_profiling/report/presentation/flavours/html/templates/alerts/alert_imbalance.html +1 -0
  122. data_profiling/report/presentation/flavours/html/templates/alerts/alert_infinite.html +1 -0
  123. data_profiling/report/presentation/flavours/html/templates/alerts/alert_missing.html +1 -0
  124. data_profiling/report/presentation/flavours/html/templates/alerts/alert_near_duplicates.html +1 -0
  125. data_profiling/report/presentation/flavours/html/templates/alerts/alert_non_stationary.html +1 -0
  126. data_profiling/report/presentation/flavours/html/templates/alerts/alert_seasonal.html +1 -0
  127. data_profiling/report/presentation/flavours/html/templates/alerts/alert_skewed.html +1 -0
  128. data_profiling/report/presentation/flavours/html/templates/alerts/alert_truncated.html +1 -0
  129. data_profiling/report/presentation/flavours/html/templates/alerts/alert_type_date.html +1 -0
  130. data_profiling/report/presentation/flavours/html/templates/alerts/alert_uniform.html +1 -0
  131. data_profiling/report/presentation/flavours/html/templates/alerts/alert_unique.html +1 -0
  132. data_profiling/report/presentation/flavours/html/templates/alerts/alert_unsupported.html +1 -0
  133. data_profiling/report/presentation/flavours/html/templates/alerts/alert_zeros.html +1 -0
  134. data_profiling/report/presentation/flavours/html/templates/alerts.html +47 -0
  135. data_profiling/report/presentation/flavours/html/templates/collapse.html +11 -0
  136. data_profiling/report/presentation/flavours/html/templates/correlation_table.html +5 -0
  137. data_profiling/report/presentation/flavours/html/templates/diagram.html +11 -0
  138. data_profiling/report/presentation/flavours/html/templates/dropdown.html +16 -0
  139. data_profiling/report/presentation/flavours/html/templates/duplicate.html +5 -0
  140. data_profiling/report/presentation/flavours/html/templates/frequency_table.html +45 -0
  141. data_profiling/report/presentation/flavours/html/templates/frequency_table_small.html +34 -0
  142. data_profiling/report/presentation/flavours/html/templates/report.html +26 -0
  143. data_profiling/report/presentation/flavours/html/templates/sample.html +10 -0
  144. data_profiling/report/presentation/flavours/html/templates/scores.html +78 -0
  145. data_profiling/report/presentation/flavours/html/templates/sequence/batch_grid.html +16 -0
  146. data_profiling/report/presentation/flavours/html/templates/sequence/grid.html +18 -0
  147. data_profiling/report/presentation/flavours/html/templates/sequence/list.html +7 -0
  148. data_profiling/report/presentation/flavours/html/templates/sequence/named_list.html +8 -0
  149. data_profiling/report/presentation/flavours/html/templates/sequence/overview_tabs.html +30 -0
  150. data_profiling/report/presentation/flavours/html/templates/sequence/scores.html +3 -0
  151. data_profiling/report/presentation/flavours/html/templates/sequence/sections.html +13 -0
  152. data_profiling/report/presentation/flavours/html/templates/sequence/select.html +40 -0
  153. data_profiling/report/presentation/flavours/html/templates/sequence/tabs.html +30 -0
  154. data_profiling/report/presentation/flavours/html/templates/table.html +38 -0
  155. data_profiling/report/presentation/flavours/html/templates/toggle_button.html +18 -0
  156. data_profiling/report/presentation/flavours/html/templates/variable.html +7 -0
  157. data_profiling/report/presentation/flavours/html/templates/variable_info.html +49 -0
  158. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/bootstrap.bundle.min.js +7 -0
  159. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/bootstrap.min.css +6 -0
  160. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/cosmo.bootstrap.min.css +12 -0
  161. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/flatly.bootstrap.min.css +12 -0
  162. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/script.js +52 -0
  163. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/simplex.bootstrap.min.css +12 -0
  164. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/style.css +253 -0
  165. data_profiling/report/presentation/flavours/html/templates/wrapper/assets/united.bootstrap.min.css +12 -0
  166. data_profiling/report/presentation/flavours/html/templates/wrapper/footer.html +7 -0
  167. data_profiling/report/presentation/flavours/html/templates/wrapper/javascript.html +18 -0
  168. data_profiling/report/presentation/flavours/html/templates/wrapper/navigation.html +36 -0
  169. data_profiling/report/presentation/flavours/html/templates/wrapper/style.html +53 -0
  170. data_profiling/report/presentation/flavours/html/templates.py +76 -0
  171. data_profiling/report/presentation/flavours/html/toggle_button.py +7 -0
  172. data_profiling/report/presentation/flavours/html/variable.py +7 -0
  173. data_profiling/report/presentation/flavours/html/variable_info.py +7 -0
  174. data_profiling/report/presentation/flavours/widget/__init__.py +49 -0
  175. data_profiling/report/presentation/flavours/widget/alerts.py +45 -0
  176. data_profiling/report/presentation/flavours/widget/collapse.py +43 -0
  177. data_profiling/report/presentation/flavours/widget/container.py +121 -0
  178. data_profiling/report/presentation/flavours/widget/correlation_table.py +14 -0
  179. data_profiling/report/presentation/flavours/widget/dropdown.py +31 -0
  180. data_profiling/report/presentation/flavours/widget/duplicate.py +14 -0
  181. data_profiling/report/presentation/flavours/widget/frequency_table.py +57 -0
  182. data_profiling/report/presentation/flavours/widget/frequency_table_small.py +66 -0
  183. data_profiling/report/presentation/flavours/widget/html.py +11 -0
  184. data_profiling/report/presentation/flavours/widget/image.py +26 -0
  185. data_profiling/report/presentation/flavours/widget/notebook.py +81 -0
  186. data_profiling/report/presentation/flavours/widget/root.py +10 -0
  187. data_profiling/report/presentation/flavours/widget/sample.py +14 -0
  188. data_profiling/report/presentation/flavours/widget/table.py +30 -0
  189. data_profiling/report/presentation/flavours/widget/toggle_button.py +17 -0
  190. data_profiling/report/presentation/flavours/widget/variable.py +12 -0
  191. data_profiling/report/presentation/flavours/widget/variable_info.py +11 -0
  192. data_profiling/report/presentation/frequency_table_utils.py +141 -0
  193. data_profiling/report/structure/__init__.py +1 -0
  194. data_profiling/report/structure/correlations.py +123 -0
  195. data_profiling/report/structure/overview.py +376 -0
  196. data_profiling/report/structure/report.py +457 -0
  197. data_profiling/report/structure/variables/__init__.py +35 -0
  198. data_profiling/report/structure/variables/render_boolean.py +132 -0
  199. data_profiling/report/structure/variables/render_categorical.py +566 -0
  200. data_profiling/report/structure/variables/render_common.py +31 -0
  201. data_profiling/report/structure/variables/render_complex.py +102 -0
  202. data_profiling/report/structure/variables/render_count.py +172 -0
  203. data_profiling/report/structure/variables/render_date.py +143 -0
  204. data_profiling/report/structure/variables/render_file.py +70 -0
  205. data_profiling/report/structure/variables/render_generic.py +45 -0
  206. data_profiling/report/structure/variables/render_image.py +204 -0
  207. data_profiling/report/structure/variables/render_path.py +134 -0
  208. data_profiling/report/structure/variables/render_real.py +314 -0
  209. data_profiling/report/structure/variables/render_text.py +189 -0
  210. data_profiling/report/structure/variables/render_timeseries.py +371 -0
  211. data_profiling/report/structure/variables/render_url.py +132 -0
  212. data_profiling/report/utils.py +34 -0
  213. data_profiling/serialize_report.py +143 -0
  214. data_profiling/utils/__init__.py +1 -0
  215. data_profiling/utils/backend.py +9 -0
  216. data_profiling/utils/cache.py +59 -0
  217. data_profiling/utils/common.py +142 -0
  218. data_profiling/utils/compat.py +31 -0
  219. data_profiling/utils/dataframe.py +238 -0
  220. data_profiling/utils/logger.py +53 -0
  221. data_profiling/utils/notebook.py +8 -0
  222. data_profiling/utils/paths.py +45 -0
  223. data_profiling/utils/progress_bar.py +15 -0
  224. data_profiling/utils/styles.py +22 -0
  225. data_profiling/utils/versions.py +19 -0
  226. data_profiling/version.py +1 -0
  227. data_profiling/visualisation/__init__.py +1 -0
  228. data_profiling/visualisation/context.py +87 -0
  229. data_profiling/visualisation/missing.py +138 -0
  230. data_profiling/visualisation/plot.py +1158 -0
  231. data_profiling/visualisation/utils.py +113 -0
  232. fg_data_profiling-4.19.0.dist-info/METADATA +362 -0
  233. fg_data_profiling-4.19.0.dist-info/RECORD +238 -0
  234. fg_data_profiling-4.19.0.dist-info/WHEEL +6 -0
  235. fg_data_profiling-4.19.0.dist-info/entry_points.txt +3 -0
  236. fg_data_profiling-4.19.0.dist-info/licenses/LICENSE +21 -0
  237. fg_data_profiling-4.19.0.dist-info/top_level.txt +2 -0
  238. ydata_profiling/__init__.py +43 -0
@@ -0,0 +1,81 @@
1
+ """
2
+ Auxiliary handler methods for data summary extraction
3
+ """
4
+ from typing import Any, Callable, Dict, List, Sequence
5
+
6
+ import networkx as nx
7
+ from visions import VisionsTypeset
8
+
9
+
10
+ def compose(functions: Sequence[Callable]) -> Callable:
11
+ """
12
+ Compose a sequence of functions.
13
+
14
+ :param functions: sequence of functions
15
+ :return: combined function applying all functions in order.
16
+ """
17
+
18
+ def composed_function(*args) -> List[Any]:
19
+ result = args # Start with the input arguments
20
+ for func in functions:
21
+ result = func(*result) if isinstance(result, tuple) else func(result)
22
+ return result # type: ignore
23
+
24
+ return composed_function # type: ignore
25
+
26
+
27
+ class Handler:
28
+ """A generic handler
29
+
30
+ Allows any custom mapping between data types and functions
31
+ """
32
+
33
+ def __init__(
34
+ self,
35
+ mapping: Dict[str, List[Callable]],
36
+ typeset: VisionsTypeset,
37
+ *args,
38
+ **kwargs
39
+ ):
40
+ self.mapping = mapping
41
+ self.typeset = typeset
42
+ self._complete_dag()
43
+
44
+ def _complete_dag(self) -> None:
45
+ for from_type, to_type in nx.topological_sort(
46
+ nx.line_graph(self.typeset.base_graph)
47
+ ):
48
+ self.mapping[str(to_type)] = (
49
+ self.mapping[str(from_type)] + self.mapping[str(to_type)]
50
+ )
51
+
52
+ def handle(self, dtype: str, *args, **kwargs) -> dict:
53
+ """
54
+ Returns:
55
+ object: a tuple containing the config, the dataset series and the summary extracted
56
+ """
57
+ funcs = self.mapping.get(dtype, [])
58
+ op = compose(funcs)
59
+ summary = op(*args)[-1]
60
+ return summary
61
+
62
+
63
+ def get_render_map() -> Dict[str, Callable]:
64
+ import data_profiling.report.structure.variables as render_algorithms
65
+
66
+ render_map = {
67
+ "Boolean": render_algorithms.render_boolean,
68
+ "Numeric": render_algorithms.render_real,
69
+ "Complex": render_algorithms.render_complex,
70
+ "Text": render_algorithms.render_text,
71
+ "DateTime": render_algorithms.render_date,
72
+ "Categorical": render_algorithms.render_categorical,
73
+ "URL": render_algorithms.render_url,
74
+ "Path": render_algorithms.render_path,
75
+ "File": render_algorithms.render_file,
76
+ "Image": render_algorithms.render_image,
77
+ "Unsupported": render_algorithms.render_generic,
78
+ "TimeSeries": render_algorithms.render_timeseries,
79
+ }
80
+
81
+ return render_map
@@ -0,0 +1,146 @@
1
+ import importlib
2
+ import warnings
3
+ from typing import Any, Callable, Dict, Optional, Sized
4
+
5
+ import pandas as pd
6
+
7
+ from data_profiling.config import Settings
8
+
9
+
10
+ class MissingDataBackend:
11
+ """Helper class to select and cache the appropriate missing-data backend (Pandas or Spark)."""
12
+
13
+ def __init__(self, df: Sized):
14
+ """Determine backend once and store it for all missing-data computations."""
15
+ if isinstance(df, pd.DataFrame):
16
+ self.backend_module = "data_profiling.model.pandas.missing_pandas"
17
+ else:
18
+ self.backend_module = "data_profiling.model.spark.missing_spark"
19
+
20
+ self.module = importlib.import_module(self.backend_module)
21
+
22
+ def get_method(self, method_name: str) -> Callable:
23
+ """Retrieve the appropriate missing-data function from the backend module."""
24
+ try:
25
+ return getattr(self.module, method_name)
26
+ except AttributeError as ex:
27
+ raise AttributeError(
28
+ f"Missing-data function '{method_name}' is not available in {self.backend_module}."
29
+ ) from ex
30
+
31
+
32
+ class MissingData:
33
+ _method_name: str = ""
34
+
35
+ def compute(
36
+ self, config: Settings, df: Sized, backend: MissingDataBackend
37
+ ) -> Optional[Sized]:
38
+ """Computes correlation using the correct backend (Pandas or Spark)."""
39
+ try:
40
+ method = backend.get_method(self._method_name)
41
+ except AttributeError as ex:
42
+ raise NotImplementedError() from ex
43
+ else:
44
+ return method(config, df)
45
+
46
+
47
+ class MissingBar(MissingData):
48
+ _method_name = "missing_bar"
49
+
50
+
51
+ class MissingMatrix(MissingData):
52
+ _method_name = "missing_matrix"
53
+
54
+
55
+ class MissingHeatmap(MissingData):
56
+ _method_name = "missing_heatmap"
57
+
58
+
59
+ def get_missing_active(config: Settings, table_stats: dict) -> Dict[str, Any]:
60
+ """
61
+
62
+ Args:
63
+ config: report Settings object
64
+ table_stats: The overall statistics for the DataFrame.
65
+
66
+ Returns:
67
+
68
+ """
69
+
70
+ missing_map = {
71
+ "bar": {
72
+ "min_missing": 0,
73
+ "name": "Count",
74
+ "caption": "A simple visualization of nullity by column.",
75
+ "function": MissingBar(),
76
+ },
77
+ "matrix": {
78
+ "min_missing": 0,
79
+ "name": "Matrix",
80
+ "caption": "Nullity matrix is a data-dense display which lets you quickly visually pick out patterns in data completion.",
81
+ "function": MissingMatrix(),
82
+ },
83
+ "heatmap": {
84
+ "min_missing": 2,
85
+ "name": "Heatmap",
86
+ "caption": "The correlation heatmap measures nullity correlation: how strongly the presence or absence of one variable affects the presence of another.",
87
+ "function": MissingHeatmap(),
88
+ },
89
+ }
90
+
91
+ missing_map = {
92
+ name: settings
93
+ for name, settings in missing_map.items()
94
+ if (
95
+ config.missing_diagrams[name]
96
+ and table_stats["n_vars_with_missing"] >= settings["min_missing"]
97
+ )
98
+ and (
99
+ name != "heatmap"
100
+ or (
101
+ table_stats["n_vars_with_missing"] - table_stats["n_vars_all_missing"]
102
+ >= settings["min_missing"]
103
+ )
104
+ )
105
+ }
106
+
107
+ return missing_map
108
+
109
+
110
+ def get_missing_diagram(
111
+ config: Settings, df: pd.DataFrame, settings: Dict[str, Any]
112
+ ) -> Optional[Dict[str, Any]]:
113
+ """Gets the rendered diagrams for missing values.
114
+
115
+ Args:
116
+ config: report Settings object
117
+ df: The DataFrame on which to calculate the missing values.
118
+ settings: missing diagram name, caption and function
119
+
120
+ Returns:
121
+ A dictionary containing the base64 encoded plots for each diagram that is active in the config (matrix, bar, heatmap).
122
+ """
123
+ backend = MissingDataBackend(df)
124
+
125
+ missing_func = settings.get("function")
126
+ if missing_func is None:
127
+ return None # No function defined, skip execution
128
+
129
+ try:
130
+ result = missing_func.compute(config, df, backend)
131
+ except ValueError as e:
132
+ warnings.warn(
133
+ f"""There was an attempt to generate the {settings['name']} missing values diagrams, but this failed.
134
+ To hide this warning, disable the calculation
135
+ (using `df.profile_report(missing_diagrams={{"{settings['name']}": False}}`)
136
+ If this is problematic for your use case, please report this as an issue:
137
+ https://github.com/Data-Centric-AI-Community/data-profiling/issues
138
+ (include the error message: '{e}')"""
139
+ )
140
+ return None
141
+ else:
142
+ return {
143
+ "name": settings["name"],
144
+ "caption": settings["caption"],
145
+ "matrix": result,
146
+ }
@@ -0,0 +1,33 @@
1
+ from typing import Any, List, Tuple
2
+
3
+ import pandas as pd
4
+
5
+ from data_profiling.config import Settings
6
+ from data_profiling.visualisation.plot import scatter_pairwise
7
+
8
+
9
+ def get_scatter_tasks(
10
+ config: Settings, continuous_variables: list
11
+ ) -> List[Tuple[Any, Any]]:
12
+ if not config.interactions.continuous:
13
+ return []
14
+
15
+ targets = config.interactions.targets
16
+ if len(targets) == 0:
17
+ targets = continuous_variables
18
+
19
+ tasks = [(x, y) for y in continuous_variables for x in targets]
20
+ return tasks
21
+
22
+
23
+ def get_scatter_plot(
24
+ config: Settings, df: pd.DataFrame, x: Any, y: Any, continuous_variables: list
25
+ ) -> str:
26
+ if x in continuous_variables:
27
+ if y == x:
28
+ df_temp = df[[x]].dropna()
29
+ else:
30
+ df_temp = df[[x, y]].dropna()
31
+ return scatter_pairwise(config, df_temp[x], df_temp[y], x, y)
32
+ else:
33
+ return ""
@@ -0,0 +1,55 @@
1
+ import importlib
2
+
3
+ # List of modules in the 'pandas' model that should be imported explicitly
4
+ PANDAS_MODULES = [
5
+ "correlations_pandas",
6
+ "describe_generic_pandas",
7
+ "describe_boolean_pandas",
8
+ "describe_categorical_pandas",
9
+ "describe_url_pandas",
10
+ "describe_file_pandas",
11
+ "describe_text_pandas",
12
+ "describe_timeseries_pandas",
13
+ "describe_numeric_pandas",
14
+ "describe_path_pandas",
15
+ "describe_image_pandas",
16
+ "describe_date_pandas",
17
+ "describe_counts_pandas",
18
+ "duplicates_pandas",
19
+ "sample_pandas",
20
+ "table_pandas",
21
+ "timeseries_index_pandas",
22
+ "summary_pandas",
23
+ ]
24
+
25
+ # Dynamically import and expose functions from modules
26
+ for module_name in PANDAS_MODULES:
27
+ module = importlib.import_module(f"data_profiling.model.pandas.{module_name}")
28
+ globals().update(
29
+ {
30
+ name: getattr(module, name)
31
+ for name in dir(module)
32
+ if not name.startswith("_")
33
+ }
34
+ )
35
+
36
+ # Explicitly list exposed names for clarity
37
+ __all__ = [
38
+ "pandas_describe_generic",
39
+ "pandas_describe_boolean_1d",
40
+ "pandas_describe_categorical_1d",
41
+ "pandas_describe_url_1d",
42
+ "pandas_describe_file_1d",
43
+ "pandas_describe_text_1d",
44
+ "pandas_describe_timeseries_1d",
45
+ "pandas_describe_numeric_1d",
46
+ "pandas_describe_path_1d",
47
+ "pandas_describe_image_1d",
48
+ "pandas_describe_date_1d",
49
+ "pandas_describe_counts",
50
+ "pandas_get_duplicates",
51
+ "pandas_get_sample",
52
+ "pandas_get_table_stats",
53
+ "pandas_get_time_index_description",
54
+ "pandas_get_series_descriptions",
55
+ ]
@@ -0,0 +1,207 @@
1
+ """Correlations between variables."""
2
+ import itertools
3
+ import warnings
4
+ from typing import Callable, Optional
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ from scipy import stats
9
+
10
+ from data_profiling.config import Settings
11
+ from data_profiling.model.pandas.discretize_pandas import (
12
+ DiscretizationType,
13
+ Discretizer,
14
+ )
15
+
16
+
17
+ def spearman_compute(
18
+ config: Settings, df: pd.DataFrame, summary: dict
19
+ ) -> Optional[pd.DataFrame]:
20
+ df_aux = df.select_dtypes(include="number").copy()
21
+ return df_aux.corr(method="spearman")
22
+
23
+
24
+ def pearson_compute(
25
+ config: Settings, df: pd.DataFrame, summary: dict
26
+ ) -> Optional[pd.DataFrame]:
27
+ df_aux = df.select_dtypes(include="number").copy()
28
+ return df_aux.corr(method="pearson")
29
+
30
+
31
+ def kendall_compute(
32
+ config: Settings, df: pd.DataFrame, summary: dict
33
+ ) -> Optional[pd.DataFrame]:
34
+ df_aux = df.select_dtypes(include="number").copy()
35
+ return df_aux.corr(method="kendall")
36
+
37
+
38
+ def _cramers_corrected_stat(confusion_matrix: pd.DataFrame, correction: bool) -> float:
39
+ """Calculate the Cramer's V corrected stat for two variables.
40
+
41
+ Args:
42
+ confusion_matrix: Crosstab between two variables.
43
+ correction: Should the correction be applied?
44
+
45
+ Returns:
46
+ The Cramer's V corrected stat for the two variables.
47
+ """
48
+ # handles empty crosstab
49
+ if confusion_matrix.empty:
50
+ return 0
51
+
52
+ chi2 = stats.chi2_contingency(confusion_matrix, correction=correction)[0]
53
+ n = confusion_matrix.sum().sum()
54
+ phi2 = chi2 / n
55
+ r = confusion_matrix.shape[0]
56
+ k = confusion_matrix.shape[1] if len(confusion_matrix.shape) > 1 else 1
57
+
58
+ # Deal with NaNs later on
59
+ with np.errstate(divide="ignore", invalid="ignore"):
60
+ phi2corr = max(0.0, phi2 - ((k - 1.0) * (r - 1.0)) / (n - 1.0))
61
+ rcorr = r - ((r - 1.0) ** 2.0) / (n - 1.0)
62
+ kcorr = k - ((k - 1.0) ** 2.0) / (n - 1.0)
63
+ rkcorr = min((kcorr - 1.0), (rcorr - 1.0))
64
+ if rkcorr == 0.0:
65
+ corr = 1.0
66
+ else:
67
+ corr = np.sqrt(phi2corr / rkcorr)
68
+ return corr
69
+
70
+
71
+ def _pairwise_spearman(col_1: pd.Series, col_2: pd.Series) -> float:
72
+ return col_1.corr(col_2, method="spearman")
73
+
74
+
75
+ def _pairwise_cramers(col_1: pd.Series, col_2: pd.Series) -> float:
76
+ return _cramers_corrected_stat(pd.crosstab(col_1, col_2), correction=True)
77
+
78
+
79
+ def cramers_compute(
80
+ config: Settings, df: pd.DataFrame, summary: dict
81
+ ) -> Optional[pd.DataFrame]:
82
+ threshold = config.categorical_maximum_correlation_distinct
83
+
84
+ # `index` and `columns` must not be a set since Pandas 1.5,
85
+ # so convert it to a list. The order of the list is arbitrary.
86
+ categoricals = list(
87
+ {
88
+ key
89
+ for key, value in summary.items()
90
+ if value["type"] in {"Categorical", "Boolean"}
91
+ and 1 < value["n_distinct"] <= threshold
92
+ }
93
+ )
94
+
95
+ if len(categoricals) <= 1:
96
+ return None
97
+
98
+ categoricals = sorted(categoricals)
99
+ matrix = np.zeros((len(categoricals), len(categoricals)))
100
+ np.fill_diagonal(matrix, 1.0)
101
+ correlation_matrix = pd.DataFrame(
102
+ matrix,
103
+ index=categoricals,
104
+ columns=categoricals,
105
+ )
106
+
107
+ for name1, name2 in itertools.combinations(categoricals, 2):
108
+ confusion_matrix = pd.crosstab(df[name1], df[name2])
109
+ if confusion_matrix.empty:
110
+ correlation_matrix.loc[name2, name1] = np.nan
111
+ else:
112
+ correlation_matrix.loc[name2, name1] = _cramers_corrected_stat(
113
+ confusion_matrix, correction=True
114
+ )
115
+ correlation_matrix.loc[name1, name2] = correlation_matrix.loc[name2, name1]
116
+ return correlation_matrix
117
+
118
+
119
+ def phik_compute(
120
+ config: Settings, df: pd.DataFrame, summary: dict
121
+ ) -> Optional[pd.DataFrame]:
122
+ df_cols_dict = {i: list(df.columns).index(i) for i in df.columns}
123
+
124
+ intcols = {
125
+ key
126
+ for key, value in summary.items()
127
+ # DateTime currently excluded
128
+ # In some use cases, it makes sense to convert it to interval
129
+ # See https://github.com/KaveIO/PhiK/issues/7
130
+ if value["type"] == "Numeric" and 1 < value["n_distinct"]
131
+ }
132
+
133
+ selcols = {
134
+ key
135
+ for key, value in summary.items()
136
+ if value["type"] != "Unsupported"
137
+ and 1 < value["n_distinct"] <= config.categorical_maximum_correlation_distinct
138
+ }
139
+ selcols = selcols.union(intcols)
140
+ selected_cols = sorted(selcols, key=lambda i: df_cols_dict[i])
141
+
142
+ if len(selected_cols) <= 1:
143
+ return None
144
+
145
+ with warnings.catch_warnings():
146
+ warnings.simplefilter("ignore")
147
+ from phik import phik_matrix
148
+
149
+ correlation = phik_matrix(df[selected_cols], interval_cols=list(intcols))
150
+
151
+ return correlation
152
+
153
+
154
+ def auto_compute(
155
+ config: Settings, df: pd.DataFrame, summary: dict
156
+ ) -> Optional[pd.DataFrame]:
157
+ threshold = config.categorical_maximum_correlation_distinct
158
+ numerical_columns = [
159
+ key
160
+ for key, value in summary.items()
161
+ if value["type"] in {"Numeric", "TimeSeries"} and value["n_distinct"] > 1
162
+ ]
163
+ categorical_columns = [
164
+ key
165
+ for key, value in summary.items()
166
+ if value["type"] in {"Categorical", "Boolean"}
167
+ and 1 < value["n_distinct"] <= threshold
168
+ ]
169
+
170
+ if len(numerical_columns + categorical_columns) <= 1:
171
+ return None
172
+
173
+ df_discretized = Discretizer(
174
+ DiscretizationType.UNIFORM, n_bins=config.correlations["auto"].n_bins
175
+ ).discretize_dataframe(df)
176
+ columns_tested = sorted(numerical_columns + categorical_columns)
177
+
178
+ correlation_matrix = pd.DataFrame(
179
+ np.ones((len(columns_tested), len(columns_tested))),
180
+ index=columns_tested,
181
+ columns=columns_tested,
182
+ )
183
+ for col_1_name, col_2_name in itertools.combinations(columns_tested, 2):
184
+
185
+ method = (
186
+ _pairwise_spearman
187
+ if any(elem in categorical_columns for elem in [col_1_name, col_2_name])
188
+ is False
189
+ else _pairwise_cramers
190
+ )
191
+
192
+ def f(col_name: str, method: Callable) -> pd.Series:
193
+ return (
194
+ df_discretized
195
+ if col_name in numerical_columns and method is _pairwise_cramers
196
+ else df
197
+ )
198
+
199
+ score = method(
200
+ f(col_1_name, method)[col_1_name], f(col_2_name, method)[col_2_name]
201
+ )
202
+ (
203
+ correlation_matrix.loc[col_1_name, col_2_name],
204
+ correlation_matrix.loc[col_2_name, col_1_name],
205
+ ) = (score, score)
206
+
207
+ return correlation_matrix
@@ -0,0 +1,26 @@
1
+ import pandas as pd
2
+
3
+ from data_profiling.config import Settings
4
+ from data_profiling.utils.dataframe import rename_index
5
+
6
+
7
+ def pandas_preprocess(config: Settings, df: pd.DataFrame) -> pd.DataFrame:
8
+ """Preprocess the dataframe
9
+
10
+ - Appends the index to the dataframe when it contains information
11
+ - Rename the "index" column to "df_index", if exists
12
+ - Convert the DataFrame's columns to str
13
+
14
+ Args:
15
+ config: report Settings object
16
+ df: the pandas DataFrame
17
+
18
+ Returns:
19
+ The preprocessed DataFrame
20
+ """
21
+ # Rename reserved column names
22
+ df = rename_index(df)
23
+
24
+ # Ensure that columns are strings
25
+ df.columns = df.columns.map(str)
26
+ return df
@@ -0,0 +1,43 @@
1
+ from typing import Tuple
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+
6
+ from data_profiling.config import Settings
7
+ from data_profiling.model.pandas.imbalance_pandas import column_imbalance_score
8
+ from data_profiling.model.summary_algorithms import (
9
+ describe_boolean_1d,
10
+ series_hashable,
11
+ )
12
+
13
+
14
+ @describe_boolean_1d.register
15
+ @series_hashable
16
+ def pandas_describe_boolean_1d(
17
+ config: Settings, series: pd.Series, summary: dict
18
+ ) -> Tuple[Settings, pd.Series, dict]:
19
+ """Describe a boolean series.
20
+
21
+ Args:
22
+ config: report Settings object
23
+ series: The Series to describe.
24
+ summary: The dict containing the series description so far.
25
+
26
+ Returns:
27
+ A dict containing calculated series description values.
28
+ """
29
+
30
+ value_counts: pd.Series = summary["value_counts_without_nan"]
31
+ if not value_counts.empty:
32
+ summary.update({"top": value_counts.index[0], "freq": value_counts.iloc[0]})
33
+ summary["imbalance"] = column_imbalance_score(value_counts, len(value_counts))
34
+ else:
35
+ summary.update(
36
+ {
37
+ "top": np.nan,
38
+ "freq": 0,
39
+ "imbalance": 0,
40
+ }
41
+ )
42
+
43
+ return config, series, summary