PyIAML 1.0.0__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 (279) hide show
  1. iaml/__init__.py +56 -0
  2. iaml/actionable.py +11 -0
  3. iaml/actionables/__init__.py +21 -0
  4. iaml/actionables/boosting/__init__.py +4 -0
  5. iaml/actionables/boosting/act_adaboost.py +59 -0
  6. iaml/actionables/cleaning/__init__.py +26 -0
  7. iaml/actionables/cleaning/act_categorical_imputer.py +124 -0
  8. iaml/actionables/cleaning/act_count_vectorizer.py +204 -0
  9. iaml/actionables/cleaning/act_drop_categorical_column.py +51 -0
  10. iaml/actionables/cleaning/act_drop_date_column.py +48 -0
  11. iaml/actionables/cleaning/act_drop_high_cardinality_categorical.py +337 -0
  12. iaml/actionables/cleaning/act_drop_numerical_column.py +75 -0
  13. iaml/actionables/cleaning/act_drop_textual_column.py +51 -0
  14. iaml/actionables/cleaning/act_encode_target_column.py +56 -0
  15. iaml/actionables/cleaning/act_frequency_encoder.py +127 -0
  16. iaml/actionables/cleaning/act_hashing_vectorizer.py +186 -0
  17. iaml/actionables/cleaning/act_knn_imputer.py +152 -0
  18. iaml/actionables/cleaning/act_mean_column.py +79 -0
  19. iaml/actionables/cleaning/act_mice.py +464 -0
  20. iaml/actionables/cleaning/act_missing_count_feature.py +109 -0
  21. iaml/actionables/cleaning/act_missing_indicator.py +124 -0
  22. iaml/actionables/cleaning/act_onehot.py +65 -0
  23. iaml/actionables/cleaning/act_ordinal_encoder.py +177 -0
  24. iaml/actionables/cleaning/act_rare_category_grouper.py +173 -0
  25. iaml/actionables/cleaning/act_simple_imputer.py +109 -0
  26. iaml/actionables/cleaning/act_split_date.py +68 -0
  27. iaml/actionables/cleaning/act_target_encoder.py +274 -0
  28. iaml/actionables/cleaning/act_text_normalizer.py +241 -0
  29. iaml/actionables/cleaning/act_tf_idf.py +80 -0
  30. iaml/actionables/cleaning/act_word2vec.py +150 -0
  31. iaml/actionables/features_precleaning/__init__.py +12 -0
  32. iaml/actionables/features_precleaning/act_coerce_numeric_strings.py +194 -0
  33. iaml/actionables/features_precleaning/act_date_converter.py +99 -0
  34. iaml/actionables/features_precleaning/act_drop_bad_quality_rows.py +77 -0
  35. iaml/actionables/features_precleaning/act_drop_duplicate_rows.py +131 -0
  36. iaml/actionables/features_precleaning/act_drop_high_missing_columns.py +94 -0
  37. iaml/actionables/features_precleaning/act_drop_id_like_columns.py +294 -0
  38. iaml/actionables/features_precleaning/act_normalize_column_names.py +157 -0
  39. iaml/actionables/features_precleaning/act_sentinel_to_na_n.py +270 -0
  40. iaml/actionables/features_precleaning/act_trim_space.py +79 -0
  41. iaml/actionables/features_preprocessing/__init__.py +18 -0
  42. iaml/actionables/features_preprocessing/act_cyclical_date_encoding.py +212 -0
  43. iaml/actionables/features_preprocessing/act_fast_ica.py +161 -0
  44. iaml/actionables/features_preprocessing/act_feature_agglomeration.py +90 -0
  45. iaml/actionables/features_preprocessing/act_k_bins_discretizer.py +207 -0
  46. iaml/actionables/features_preprocessing/act_k_means_features.py +296 -0
  47. iaml/actionables/features_preprocessing/act_kernel_pca.py +143 -0
  48. iaml/actionables/features_preprocessing/act_log_transformer.py +122 -0
  49. iaml/actionables/features_preprocessing/act_nystroem.py +100 -0
  50. iaml/actionables/features_preprocessing/act_pca.py +77 -0
  51. iaml/actionables/features_preprocessing/act_polynomial_features.py +86 -0
  52. iaml/actionables/features_preprocessing/act_power_transformer.py +106 -0
  53. iaml/actionables/features_preprocessing/act_quantile_transformer.py +114 -0
  54. iaml/actionables/features_preprocessing/act_rbf_sampler.py +88 -0
  55. iaml/actionables/features_preprocessing/act_select_percentile.py +112 -0
  56. iaml/actionables/features_preprocessing/act_sparse_random_projection.py +157 -0
  57. iaml/actionables/features_preprocessing/act_truncated_svd.py +137 -0
  58. iaml/actionables/features_selection/__init__.py +8 -0
  59. iaml/actionables/features_selection/act_permutation_importance_selector.py +421 -0
  60. iaml/actionables/features_selection/act_remove_high_correlated_column.py +70 -0
  61. iaml/actionables/features_selection/act_remove_low_variance_column.py +74 -0
  62. iaml/actionables/features_selection/act_rfe.py +214 -0
  63. iaml/actionables/features_selection/act_select_from_model.py +325 -0
  64. iaml/actionables/features_selection/act_select_k_best.py +181 -0
  65. iaml/actionables/features_selection/act_vif_selector.py +130 -0
  66. iaml/actionables/imbalance/__init__.py +10 -0
  67. iaml/actionables/imbalance/act_adasyn.py +150 -0
  68. iaml/actionables/imbalance/act_borderline_smote.py +171 -0
  69. iaml/actionables/imbalance/act_near_miss.py +158 -0
  70. iaml/actionables/imbalance/act_random_over_sampling.py +60 -0
  71. iaml/actionables/imbalance/act_random_under_sampler.py +135 -0
  72. iaml/actionables/imbalance/act_smote.py +162 -0
  73. iaml/actionables/imbalance/act_smote_tomek.py +182 -0
  74. iaml/actionables/imbalance/act_smoteenn.py +193 -0
  75. iaml/actionables/imbalance/act_tomek_links.py +138 -0
  76. iaml/actionables/normalize/__init__.py +6 -0
  77. iaml/actionables/normalize/act_max_abs_scaler.py +78 -0
  78. iaml/actionables/normalize/act_minmax_scaler.py +56 -0
  79. iaml/actionables/normalize/act_normalizer.py +95 -0
  80. iaml/actionables/normalize/act_robust_scaler.py +111 -0
  81. iaml/actionables/normalize/act_standard_scaler.py +55 -0
  82. iaml/actionables/predictors/__init__.py +6 -0
  83. iaml/actionables/predictors/_xgboost.py +16 -0
  84. iaml/actionables/predictors/classifier/__init__.py +26 -0
  85. iaml/actionables/predictors/classifier/act_bagging_classifier.py +113 -0
  86. iaml/actionables/predictors/classifier/act_bernoulli_nb.py +89 -0
  87. iaml/actionables/predictors/classifier/act_catboost_classifier.py +135 -0
  88. iaml/actionables/predictors/classifier/act_complement_nb.py +106 -0
  89. iaml/actionables/predictors/classifier/act_decision_tree_classifier.py +117 -0
  90. iaml/actionables/predictors/classifier/act_extra_trees_classifier.py +115 -0
  91. iaml/actionables/predictors/classifier/act_gaussian_nb.py +53 -0
  92. iaml/actionables/predictors/classifier/act_hist_gradient_boosting_classifier.py +144 -0
  93. iaml/actionables/predictors/classifier/act_knn.py +86 -0
  94. iaml/actionables/predictors/classifier/act_light_gbm_classifier.py +211 -0
  95. iaml/actionables/predictors/classifier/act_linear_discriminant_analysis.py +63 -0
  96. iaml/actionables/predictors/classifier/act_linear_svc.py +134 -0
  97. iaml/actionables/predictors/classifier/act_logistic_regression.py +92 -0
  98. iaml/actionables/predictors/classifier/act_mlp_classifier.py +107 -0
  99. iaml/actionables/predictors/classifier/act_multinomial_nb.py +76 -0
  100. iaml/actionables/predictors/classifier/act_passive_aggressive_classifier.py +141 -0
  101. iaml/actionables/predictors/classifier/act_quadratic_discriminant_analysis.py +72 -0
  102. iaml/actionables/predictors/classifier/act_randomforest.py +113 -0
  103. iaml/actionables/predictors/classifier/act_ridge_classifier.py +116 -0
  104. iaml/actionables/predictors/classifier/act_sgd_classifier.py +149 -0
  105. iaml/actionables/predictors/classifier/act_svm_svc.py +88 -0
  106. iaml/actionables/predictors/classifier/act_xgboost.py +111 -0
  107. iaml/actionables/predictors/regressor/__init__.py +27 -0
  108. iaml/actionables/predictors/regressor/act_ada_boost_regressor.py +75 -0
  109. iaml/actionables/predictors/regressor/act_ard_regression.py +95 -0
  110. iaml/actionables/predictors/regressor/act_catboost_regressor.py +134 -0
  111. iaml/actionables/predictors/regressor/act_decision_tree_regressor.py +111 -0
  112. iaml/actionables/predictors/regressor/act_elastic_net_regressor.py +109 -0
  113. iaml/actionables/predictors/regressor/act_extra_trees_regressor.py +113 -0
  114. iaml/actionables/predictors/regressor/act_gaussian_process_regressor.py +55 -0
  115. iaml/actionables/predictors/regressor/act_gboost_regressor.py +95 -0
  116. iaml/actionables/predictors/regressor/act_hist_gradient_boosting_regressor.py +105 -0
  117. iaml/actionables/predictors/regressor/act_huber_regressor.py +101 -0
  118. iaml/actionables/predictors/regressor/act_knn_regressor.py +86 -0
  119. iaml/actionables/predictors/regressor/act_lasso_regressor.py +103 -0
  120. iaml/actionables/predictors/regressor/act_light_gbm_regressor.py +201 -0
  121. iaml/actionables/predictors/regressor/act_linear_regression.py +43 -0
  122. iaml/actionables/predictors/regressor/act_mlp_regressor.py +104 -0
  123. iaml/actionables/predictors/regressor/act_poisson_regressor.py +111 -0
  124. iaml/actionables/predictors/regressor/act_quantile_regressor.py +87 -0
  125. iaml/actionables/predictors/regressor/act_randomforest_regressor.py +116 -0
  126. iaml/actionables/predictors/regressor/act_ransac_regressor.py +106 -0
  127. iaml/actionables/predictors/regressor/act_ridge_regressor.py +107 -0
  128. iaml/actionables/predictors/regressor/act_sgd_regressor.py +106 -0
  129. iaml/actionables/predictors/regressor/act_svm_svr.py +81 -0
  130. iaml/actionables/predictors/regressor/act_xgboost_regressor.py +97 -0
  131. iaml/actionables/predictors/survival/__init__.py +12 -0
  132. iaml/actionables/predictors/survival/act_aalen_additive_model.py +83 -0
  133. iaml/actionables/predictors/survival/act_cox.py +110 -0
  134. iaml/actionables/predictors/survival/act_coxnet_survival_analysis.py +134 -0
  135. iaml/actionables/predictors/survival/act_extra_survival_trees.py +101 -0
  136. iaml/actionables/predictors/survival/act_fast_survival_svm.py +102 -0
  137. iaml/actionables/predictors/survival/act_gradient_boosting_survival_analysis.py +93 -0
  138. iaml/actionables/predictors/survival/act_random_survival_forest.py +91 -0
  139. iaml/actionables/predictors/survival/act_survival_component_wise_gboost.py +80 -0
  140. iaml/actionables/predictors/survival/act_survival_tree.py +120 -0
  141. iaml/actionables/predictors/survival/act_survival_xgboost.py +9 -0
  142. iaml/actionables/predictors/survival/act_weibull_aft.py +230 -0
  143. iaml/cache.py +61 -0
  144. iaml/cache_keys.py +57 -0
  145. iaml/candidate.py +736 -0
  146. iaml/core_dispatcher.py +125 -0
  147. iaml/data_type.py +11 -0
  148. iaml/dataset.py +506 -0
  149. iaml/decorators/__init__.py +3 -0
  150. iaml/decorators/all.py +4 -0
  151. iaml/decorators/is_step.py +45 -0
  152. iaml/decorators/runner.py +100 -0
  153. iaml/explanation.py +112 -0
  154. iaml/iaml.py +1072 -0
  155. iaml/iaml_pipeline.py +600 -0
  156. iaml/logger.py +138 -0
  157. iaml/meta_explorer_step.py +62 -0
  158. iaml/meta_ordered_step.py +28 -0
  159. iaml/meta_partial_explorer_step.py +34 -0
  160. iaml/meta_singleton.py +24 -0
  161. iaml/metastep.py +211 -0
  162. iaml/metric.py +111 -0
  163. iaml/metric_plot.py +82 -0
  164. iaml/metrics/__init__.py +21 -0
  165. iaml/metrics/_classification.py +28 -0
  166. iaml/metrics/_survival_times.py +22 -0
  167. iaml/metrics/accuracy_metric.py +59 -0
  168. iaml/metrics/balanced_accuracy_metric.py +67 -0
  169. iaml/metrics/brier_score.py +90 -0
  170. iaml/metrics/classification_error_metric.py +66 -0
  171. iaml/metrics/concordance_index_ipcw.py +84 -0
  172. iaml/metrics/concordance_index_metric.py +67 -0
  173. iaml/metrics/cumulative_dynamic_auc.py +119 -0
  174. iaml/metrics/f1_score_metric.py +71 -0
  175. iaml/metrics/integrated_brier_score.py +98 -0
  176. iaml/metrics/integrated_brier_score_loss.py +41 -0
  177. iaml/metrics/mean_absolute_error_metric.py +46 -0
  178. iaml/metrics/mean_squared_error_metric.py +46 -0
  179. iaml/metrics/mean_squared_log_error_metric.py +49 -0
  180. iaml/metrics/median_absolute_error_metric.py +48 -0
  181. iaml/metrics/precision_metric.py +63 -0
  182. iaml/metrics/r2_score_metric.py +45 -0
  183. iaml/metrics/recall_metric.py +65 -0
  184. iaml/metrics/roc_auc_metric.py +50 -0
  185. iaml/metrics/specificity_metric.py +44 -0
  186. iaml/metrics/specificity_multiclass_metric.py +55 -0
  187. iaml/metrics/specificity_multilabel_metric.py +60 -0
  188. iaml/optimizers/__init__.py +5 -0
  189. iaml/optimizers/bayesian_optimizer.py +193 -0
  190. iaml/optimizers/genetic_optimizer.py +284 -0
  191. iaml/optimizers/optimizer.py +31 -0
  192. iaml/optimizers/random_optimizer.py +101 -0
  193. iaml/plot.py +138 -0
  194. iaml/plots/__init__.py +32 -0
  195. iaml/plots/bar_plot.py +141 -0
  196. iaml/plots/box_plot.py +166 -0
  197. iaml/plots/class_prediction_error_plot.py +37 -0
  198. iaml/plots/classification_report_plot.py +35 -0
  199. iaml/plots/confusion_matrix_plot.py +34 -0
  200. iaml/plots/correlation_heatmap_plot.py +201 -0
  201. iaml/plots/cumulative_hazard_plot.py +72 -0
  202. iaml/plots/density_plot.py +210 -0
  203. iaml/plots/histogram_plot.py +179 -0
  204. iaml/plots/kaplan_meier_comparison_plot.py +89 -0
  205. iaml/plots/line_plot.py +70 -0
  206. iaml/plots/missingness_heatmap_plot.py +203 -0
  207. iaml/plots/outlier_plot.py +217 -0
  208. iaml/plots/pair_plot.py +228 -0
  209. iaml/plots/precision_recall_curve_plot.py +86 -0
  210. iaml/plots/prediction_error_plot.py +34 -0
  211. iaml/plots/qq_plot.py +220 -0
  212. iaml/plots/residual_plot.py +38 -0
  213. iaml/plots/roc_dynamique_curve_plot.py +79 -0
  214. iaml/plots/rocauc_plot.py +96 -0
  215. iaml/plots/shap_plot.py +187 -0
  216. iaml/plots/target_distribution_plot.py +241 -0
  217. iaml/plots/violin_plot.py +206 -0
  218. iaml/predictor.py +139 -0
  219. iaml/reference.py +65 -0
  220. iaml/shared_cache.py +90 -0
  221. iaml/sklearn_preprocessor.py +74 -0
  222. iaml/splitters/__init__.py +3 -0
  223. iaml/splitters/kfold_splitter.py +32 -0
  224. iaml/splitters/random_splitter.py +26 -0
  225. iaml/stack.py +39 -0
  226. iaml/statistic.py +66 -0
  227. iaml/statistics/__init__.py +77 -0
  228. iaml/statistics/anova_statistic.py +80 -0
  229. iaml/statistics/cardinality_ratio_statistic.py +63 -0
  230. iaml/statistics/category_cooccurrence_statistic.py +79 -0
  231. iaml/statistics/chi_square_statistic.py +81 -0
  232. iaml/statistics/coef_variation_statistic.py +72 -0
  233. iaml/statistics/correlation_with_target.py +105 -0
  234. iaml/statistics/count.py +72 -0
  235. iaml/statistics/data_type_summary_statistic.py +74 -0
  236. iaml/statistics/duplicate_row_statistic.py +56 -0
  237. iaml/statistics/effect_size_statistic.py +129 -0
  238. iaml/statistics/entropy_statistic.py +69 -0
  239. iaml/statistics/event_rate_statistic.py +52 -0
  240. iaml/statistics/grouped_mean_statistic.py +60 -0
  241. iaml/statistics/iqr_statistic.py +66 -0
  242. iaml/statistics/kurtosis.py +50 -0
  243. iaml/statistics/mad_statistic.py +66 -0
  244. iaml/statistics/mean.py +61 -0
  245. iaml/statistics/median_statistic.py +61 -0
  246. iaml/statistics/minmax.py +60 -0
  247. iaml/statistics/missing_rate_statistic.py +62 -0
  248. iaml/statistics/mode.py +47 -0
  249. iaml/statistics/most_frequent_ratio.py +81 -0
  250. iaml/statistics/outlier_count_iqr_statistic.py +76 -0
  251. iaml/statistics/quantile.py +59 -0
  252. iaml/statistics/range.py +53 -0
  253. iaml/statistics/rare_category_rate.py +92 -0
  254. iaml/statistics/skewness.py +53 -0
  255. iaml/statistics/stdev.py +50 -0
  256. iaml/statistics/summary_table_statistic.py +60 -0
  257. iaml/statistics/time_by_group_statistic.py +83 -0
  258. iaml/statistics/time_summary_statistic.py +56 -0
  259. iaml/statistics/top_k_value_counts.py +68 -0
  260. iaml/statistics/unique_count_statistic.py +57 -0
  261. iaml/statistics/value_counts.py +63 -0
  262. iaml/statistics/variance.py +51 -0
  263. iaml/statistics/violin.py +63 -0
  264. iaml/step.py +600 -0
  265. iaml/step_cache.py +87 -0
  266. iaml/step_wrapper.py +79 -0
  267. iaml/timed_pool_executor.py +492 -0
  268. iaml/type_of_target.py +68 -0
  269. iaml/void_step.py +101 -0
  270. iaml/worker_manager.py +169 -0
  271. iaml/wrapper/__init__.py +4 -0
  272. iaml/wrapper/wrap_basic_gridsearch.py +68 -0
  273. iaml/wrapper/wrap_genetic_gridsearch.py +293 -0
  274. iaml/wrapper/wrap_iterative_gridsearch.py +399 -0
  275. pyiaml-1.0.0.dist-info/METADATA +802 -0
  276. pyiaml-1.0.0.dist-info/RECORD +279 -0
  277. pyiaml-1.0.0.dist-info/WHEEL +5 -0
  278. pyiaml-1.0.0.dist-info/licenses/LICENSE +674 -0
  279. pyiaml-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,72 @@
1
+ """[STATISTIC] Count."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..data_type import DataType
9
+ from ..statistic import Statistic
10
+
11
+
12
+ class CountStatistic(Statistic):
13
+ """[STATISTIC] Count."""
14
+
15
+ name: str = "Count"
16
+ _description: str = textwrap.dedent("""\
17
+ Count measures the number of non-null values for each column.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Count measures the number of non-null values (or null values when requested)
21
+ for each column.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ count_to_compute = [True, False]
26
+
27
+ def __init__(self, null_count: bool = False) -> None:
28
+ self.null_count = null_count
29
+
30
+ def __str__(self) -> str:
31
+ return 'null_count' if self.null_count else 'count'
32
+
33
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
34
+ """Compute counts for each column."""
35
+ if dataset.type_of_target == 'survival':
36
+ return pd.DataFrame()
37
+
38
+ df = pd.DataFrame()
39
+ if dataset.type_of_target == 'continuous':
40
+ for cnt in CountStatistic.count_to_compute:
41
+ self.null_count = cnt
42
+ data = []
43
+ columns = []
44
+ for col in dataset.X.columns:
45
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
46
+ columns.append(col)
47
+ value = dataset.X[col].isna().sum() if self.null_count else dataset.X[col].count()
48
+ data.append(value)
49
+ df = pd.concat([df, pd.DataFrame([data], index=[str(self)], columns=columns)])
50
+ return df
51
+
52
+ class_labels = list(pd.unique(dataset.y))
53
+ for cnt in CountStatistic.count_to_compute:
54
+ self.null_count = cnt
55
+ data = []
56
+ columns = []
57
+ for col in dataset.X.columns:
58
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
59
+ for label in ['all'] + class_labels:
60
+ columns.append(f"{col}_{label}")
61
+ if label == 'all':
62
+ value = dataset.X[col].isna().sum() if self.null_count else dataset.X[col].count()
63
+ else:
64
+ values = dataset.X.loc[dataset.y == label][col]
65
+ value = values.isna().sum() if self.null_count else values.count()
66
+ data.append(value)
67
+ df = pd.concat([df, pd.DataFrame([data], index=[str(self)], columns=columns)])
68
+ return df
69
+
70
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
71
+ """Does this statistic apply to the dataset?"""
72
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,74 @@
1
+ """[STATISTIC] Data Type Summary."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..data_type import DataType
9
+ from ..statistic import Statistic
10
+
11
+
12
+ class DataTypeSummaryStatistic(Statistic):
13
+ """[STATISTIC] Data Type Summary."""
14
+
15
+ name: str = "Data Type Summary"
16
+ _description: str = textwrap.dedent("""\
17
+ Data type summary counts column types and ratios.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Data type summary reports the number of numeric, categorical, text, and date
21
+ columns, along with ratios relative to the total number of columns.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'data_type_summary'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute data type counts and ratios for the dataset."""
30
+ if dataset.type_of_target == 'survival':
31
+ return pd.DataFrame()
32
+
33
+ total_columns = len(dataset.X.columns)
34
+ n_numeric = len(dataset.get_columns_names_by_type(DataType.NUMERIC))
35
+ n_categorical = len(dataset.get_columns_names_by_type(DataType.CATEGORICAL))
36
+ n_text = len(dataset.get_columns_names_by_type([DataType.TEXT, DataType.SHORT_TEXT]))
37
+ n_date = len(dataset.get_columns_names_by_type(DataType.DATE))
38
+
39
+ if total_columns:
40
+ ratio_numeric = n_numeric / total_columns
41
+ ratio_categorical = n_categorical / total_columns
42
+ ratio_text = n_text / total_columns
43
+ ratio_date = n_date / total_columns
44
+ else:
45
+ ratio_numeric = 0.0
46
+ ratio_categorical = 0.0
47
+ ratio_text = 0.0
48
+ ratio_date = 0.0
49
+
50
+ data = [[
51
+ n_numeric,
52
+ n_categorical,
53
+ n_text,
54
+ n_date,
55
+ ratio_numeric,
56
+ ratio_categorical,
57
+ ratio_text,
58
+ ratio_date,
59
+ ]]
60
+ columns = [
61
+ 'n_numeric',
62
+ 'n_categorical',
63
+ 'n_text',
64
+ 'n_date',
65
+ 'ratio_numeric',
66
+ 'ratio_categorical',
67
+ 'ratio_text',
68
+ 'ratio_date',
69
+ ]
70
+ return pd.DataFrame(data, index=[str(self)], columns=columns)
71
+
72
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
73
+ """Does this statistic apply to the dataset?"""
74
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,56 @@
1
+ """[STATISTIC] Duplicate Rows."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..data_type import DataType
9
+ from ..statistic import Statistic
10
+
11
+
12
+ class DuplicateRowStatistic(Statistic):
13
+ """[STATISTIC] Duplicate Rows."""
14
+
15
+ name: str = "Duplicate Rows"
16
+ _description: str = textwrap.dedent("""\
17
+ Duplicate rows reports the number and ratio of duplicated rows.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Duplicate rows counts duplicated rows based on usable columns and
21
+ provides the ratio relative to the total number of rows.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'duplicate_rows'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute number and ratio of duplicated rows."""
30
+ if dataset.type_of_target == 'survival':
31
+ return pd.DataFrame()
32
+
33
+ columns = [
34
+ col for col in dataset.X.columns
35
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT)
36
+ ]
37
+
38
+ n_rows = int(dataset.X.shape[0])
39
+ if columns:
40
+ data_frame = dataset.X[columns]
41
+ n_duplicate = int(data_frame.duplicated().sum())
42
+ else:
43
+ n_duplicate = 0
44
+
45
+ ratio = n_duplicate / n_rows if n_rows else 0.0
46
+
47
+ data = [[n_duplicate, ratio]]
48
+ return pd.DataFrame(
49
+ data,
50
+ index=[str(self)],
51
+ columns=["n_duplicate_rows", "ratio_duplicate_rows"],
52
+ )
53
+
54
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
55
+ """Does this statistic apply to the dataset?"""
56
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,129 @@
1
+ """[STATISTIC] Effect size (Cohen d)."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+ from ..dataset import Dataset
9
+ from ..data_type import DataType
10
+ from ..statistic import Statistic
11
+
12
+
13
+ class EffectSizeStatistic(Statistic):
14
+ """[STATISTIC] Effect size (Cohen d)."""
15
+
16
+ name: str = "Effect Size"
17
+ _description: str = textwrap.dedent("""\
18
+ Effect size measures standardized differences (Cohen d) between classes.
19
+ """)
20
+ _description_long: str = textwrap.dedent("""\
21
+ Effect size computes Cohen's d for each numerical column per class
22
+ compared against the rest of the data. The `_all` suffix reports
23
+ the mean absolute effect size across classes for each feature.
24
+ """)
25
+ refs: list[dict] = []
26
+
27
+ def __str__(self) -> str:
28
+ return 'effect_size'
29
+
30
+ def _safe_variance(self, n: float, total: float, total_sq: float) -> float | None:
31
+ if n is None or n <= 1:
32
+ return None
33
+ denom = n - 1.0
34
+ var = (total_sq - (total * total) / n) / denom
35
+ if pd.isna(var) or var < 0:
36
+ return None
37
+ return float(var)
38
+
39
+ def _cohen_d(self, mean_a: float, mean_b: float, var_a: float | None,
40
+ var_b: float | None, n_a: float, n_b: float) -> float | None:
41
+ if var_a is None or var_b is None:
42
+ return None
43
+ if n_a <= 1 or n_b <= 1:
44
+ return None
45
+ pooled_denom = (n_a + n_b - 2.0)
46
+ if pooled_denom <= 0:
47
+ return None
48
+ pooled_var = ((n_a - 1.0) * var_a + (n_b - 1.0) * var_b) / pooled_denom
49
+ if pooled_var <= 0 or pd.isna(pooled_var):
50
+ return None
51
+ pooled_std = np.sqrt(pooled_var)
52
+ if pooled_std == 0 or pd.isna(pooled_std):
53
+ return None
54
+ return (mean_a - mean_b) / pooled_std
55
+
56
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
57
+ """Compute Cohen's d for numerical columns."""
58
+ if dataset.type_of_target in ['survival', 'continuous']:
59
+ return pd.DataFrame()
60
+
61
+ numeric_columns = dataset.get_columns_names_by_type(DataType.NUMERIC)
62
+ if not numeric_columns:
63
+ return pd.DataFrame()
64
+
65
+ class_labels = list(pd.unique(dataset.y))
66
+
67
+ values = dataset.X[numeric_columns]
68
+ total_n = values.count()
69
+ total_sum = values.sum()
70
+ total_sumsq = (values ** 2).sum()
71
+
72
+ grouped = values.groupby(dataset.y)
73
+ class_n = grouped.count()
74
+ class_sum = grouped.sum()
75
+ class_sumsq = (values ** 2).groupby(dataset.y).sum()
76
+
77
+ data = []
78
+ columns = []
79
+
80
+ for col in numeric_columns:
81
+ col_total_n = float(total_n.get(col, 0))
82
+ col_total_sum = float(total_sum.get(col, 0))
83
+ col_total_sumsq = float(total_sumsq.get(col, 0))
84
+ abs_effects = []
85
+
86
+ for label in ['all'] + class_labels:
87
+ columns.append(f"{col}_{label}")
88
+ if label == 'all':
89
+ data.append(None)
90
+ continue
91
+
92
+ n_a = float(class_n.at[label, col]) if label in class_n.index else 0.0
93
+ if n_a <= 0:
94
+ data.append(None)
95
+ continue
96
+
97
+ sum_a = float(class_sum.at[label, col]) if label in class_sum.index else 0.0
98
+ sumsq_a = float(class_sumsq.at[label, col]) if label in class_sumsq.index else 0.0
99
+
100
+ n_b = col_total_n - n_a
101
+ if n_b <= 0:
102
+ data.append(None)
103
+ continue
104
+
105
+ sum_b = col_total_sum - sum_a
106
+ sumsq_b = col_total_sumsq - sumsq_a
107
+
108
+ mean_a = sum_a / n_a if n_a > 0 else None
109
+ mean_b = sum_b / n_b if n_b > 0 else None
110
+ if mean_a is None or mean_b is None or pd.isna(mean_a) or pd.isna(mean_b):
111
+ data.append(None)
112
+ continue
113
+
114
+ var_a = self._safe_variance(n_a, sum_a, sumsq_a)
115
+ var_b = self._safe_variance(n_b, sum_b, sumsq_b)
116
+ d_value = self._cohen_d(mean_a, mean_b, var_a, var_b, n_a, n_b)
117
+ data.append(d_value)
118
+ if d_value is not None and not pd.isna(d_value):
119
+ abs_effects.append(abs(d_value))
120
+
121
+ if abs_effects:
122
+ data_index = columns.index(f"{col}_all")
123
+ data[data_index] = float(np.mean(abs_effects))
124
+
125
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
126
+
127
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
128
+ """Does this statistic apply to the dataset?"""
129
+ return dataset.type_of_target not in ['survival', 'continuous']
@@ -0,0 +1,69 @@
1
+ """[STATISTIC] Entropy."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import numpy as np
6
+ import pandas as pd
7
+
8
+ from ..dataset import Dataset
9
+ from ..data_type import DataType
10
+ from ..statistic import Statistic
11
+
12
+
13
+ class EntropyStatistic(Statistic):
14
+ """[STATISTIC] Entropy."""
15
+
16
+ name: str = "Entropy"
17
+ _description: str = textwrap.dedent("""\
18
+ Entropy measures the distribution uncertainty for categorical columns.
19
+ """)
20
+ _description_long: str = textwrap.dedent("""\
21
+ Entropy measures the distribution uncertainty for categorical columns,
22
+ optionally per class for classification.
23
+ """)
24
+ refs: list[dict] = []
25
+
26
+ def __str__(self) -> str:
27
+ return 'entropy'
28
+
29
+ def _entropy(self, series: pd.Series) -> float:
30
+ values = series.dropna()
31
+ if values.empty:
32
+ return 0.0
33
+ counts = values.value_counts()
34
+ total = counts.sum()
35
+ if total == 0:
36
+ return 0.0
37
+ probs = counts / total
38
+ return float(-(probs * np.log2(probs)).sum())
39
+
40
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
41
+ """Compute entropy for categorical columns."""
42
+ if dataset.type_of_target == 'survival':
43
+ return pd.DataFrame()
44
+
45
+ data = []
46
+ columns = []
47
+
48
+ if dataset.type_of_target == 'continuous':
49
+ for col in dataset.X.columns:
50
+ if dataset.columns_types[col][1] == DataType.CATEGORICAL:
51
+ columns.append(col)
52
+ data.append(self._entropy(dataset.X[col]))
53
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
54
+
55
+ class_labels = list(pd.unique(dataset.y))
56
+ for col in dataset.X.columns:
57
+ if dataset.columns_types[col][1] == DataType.CATEGORICAL:
58
+ for label in ['all'] + class_labels:
59
+ columns.append(f"{col}_{label}")
60
+ if label == 'all':
61
+ values = dataset.X[col]
62
+ else:
63
+ values = dataset.X.loc[dataset.y == label][col]
64
+ data.append(self._entropy(values))
65
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
66
+
67
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
68
+ """Does this statistic apply to the dataset?"""
69
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,52 @@
1
+ """[STATISTIC] Event Rate."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..statistic import Statistic
9
+
10
+
11
+ class EventRateStatistic(Statistic):
12
+ """[STATISTIC] Event Rate."""
13
+
14
+ name: str = "Event Rate"
15
+ _description: str = textwrap.dedent("""\
16
+ Event rate measures the proportion of events versus censoring in survival data.
17
+ """)
18
+ _description_long: str = textwrap.dedent("""\
19
+ Event rate measures the proportion of events versus censoring in survival targets.
20
+ Rates are reported as fractions in [0, 1].
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ def __str__(self) -> str:
25
+ return 'event_rate'
26
+
27
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
28
+ """Compute event and censoring rates for survival targets."""
29
+ if dataset.type_of_target != 'survival':
30
+ return pd.DataFrame()
31
+
32
+ samples = Dataset.normalize_survival_target(dataset.y)
33
+ n_samples = len(samples)
34
+
35
+ if n_samples:
36
+ event_count = int(sum(event for event, _ in samples))
37
+ censor_count = n_samples - event_count
38
+ event_rate = event_count / n_samples
39
+ censor_rate = censor_count / n_samples
40
+ else:
41
+ event_count = 0
42
+ censor_count = 0
43
+ event_rate = 0.0
44
+ censor_rate = 0.0
45
+
46
+ data = [[event_count, censor_count, event_rate, censor_rate]]
47
+ columns = ['event_count', 'censor_count', 'event_rate', 'censor_rate']
48
+ return pd.DataFrame(data, index=[str(self)], columns=columns)
49
+
50
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
51
+ """Does this statistic apply to the dataset?"""
52
+ return dataset.type_of_target == 'survival'
@@ -0,0 +1,60 @@
1
+ """[STATISTIC] Grouped mean."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..data_type import DataType
9
+ from ..statistic import Statistic
10
+
11
+
12
+ class GroupedMeanStatistic(Statistic):
13
+ """[STATISTIC] Grouped mean."""
14
+
15
+ name: str = "Grouped Mean"
16
+ _description: str = textwrap.dedent("""\
17
+ Grouped mean measures per-class mean offsets from the overall mean.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Grouped mean measures numerical column means per class as offsets from the overall mean.
21
+ The overall mean is reported under the `_all` column suffix for each feature.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'grouped_mean'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute grouped mean offsets for numerical columns."""
30
+ if dataset.type_of_target in ['survival', 'continuous']:
31
+ return pd.DataFrame()
32
+
33
+ numeric_columns = dataset.get_columns_names_by_type(DataType.NUMERIC)
34
+ if not numeric_columns:
35
+ return pd.DataFrame()
36
+
37
+ overall_means = dataset.X[numeric_columns].mean()
38
+ grouped_means = dataset.X[numeric_columns].groupby(dataset.y).mean()
39
+ class_labels = list(pd.unique(dataset.y))
40
+
41
+ data = []
42
+ columns = []
43
+ for col in numeric_columns:
44
+ overall = overall_means.get(col)
45
+ for label in ['all'] + class_labels:
46
+ columns.append(f"{col}_{label}")
47
+ if label == 'all':
48
+ data.append(overall)
49
+ else:
50
+ class_mean = grouped_means.at[label, col] if label in grouped_means.index else pd.NA
51
+ if pd.isna(class_mean) or pd.isna(overall):
52
+ data.append(None)
53
+ else:
54
+ data.append(class_mean - overall)
55
+
56
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
57
+
58
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
59
+ """Does this statistic apply to the dataset?"""
60
+ return dataset.type_of_target not in ['survival', 'continuous']
@@ -0,0 +1,66 @@
1
+ """[STATISTIC] IQR."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..data_type import DataType
9
+ from ..statistic import Statistic
10
+
11
+
12
+ class IQRStatistic(Statistic):
13
+ """[STATISTIC] IQR."""
14
+
15
+ name: str = "IQR"
16
+ _description: str = textwrap.dedent("""\
17
+ IQR measures dispersion as Q3 minus Q1 for numerical columns.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ IQR measures dispersion as Q3 minus Q1 for numerical columns, per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ def __str__(self) -> str:
25
+ return 'iqr'
26
+
27
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
28
+ """Compute IQR for each numerical column."""
29
+ if dataset.type_of_target == 'survival':
30
+ return pd.DataFrame()
31
+
32
+ data = []
33
+ columns = []
34
+
35
+ if dataset.type_of_target == 'continuous':
36
+ for col in dataset.X.columns:
37
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
38
+ columns.append(col)
39
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
40
+ q3 = dataset.X[col].quantile(0.75)
41
+ q1 = dataset.X[col].quantile(0.25)
42
+ data.append(q3 - q1)
43
+ else:
44
+ data.append(None)
45
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
46
+
47
+ class_labels = list(pd.unique(dataset.y))
48
+ for col in dataset.X.columns:
49
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
50
+ for label in ['all'] + class_labels:
51
+ columns.append(f"{col}_{label}")
52
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
53
+ if label == 'all':
54
+ series = dataset.X[col]
55
+ else:
56
+ series = dataset.X.loc[dataset.y == label][col]
57
+ q3 = series.quantile(0.75)
58
+ q1 = series.quantile(0.25)
59
+ data.append(q3 - q1)
60
+ else:
61
+ data.append(None)
62
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
63
+
64
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
65
+ """Does this statistic apply to the dataset?"""
66
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,50 @@
1
+ """[STATISTIC] Kurtosis."""
2
+ from __future__ import annotations
3
+
4
+ import textwrap
5
+ import pandas as pd
6
+
7
+ from ..dataset import Dataset
8
+ from ..data_type import DataType
9
+ from ..statistic import Statistic
10
+
11
+
12
+ class KurtosisStatistic(Statistic):
13
+ """[STATISTIC] Kurtosis."""
14
+
15
+ name: str = "Kurtosis"
16
+ _description: str = textwrap.dedent("""\
17
+ Kurtosis measures the tailedness of numerical distributions.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Kurtosis measures the tailedness of numerical distributions, per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ def __str__(self) -> str:
25
+ return 'kurtosis'
26
+
27
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
28
+ """Compute kurtosis for numerical columns."""
29
+ if dataset.type_of_target in ['survival', 'continuous']:
30
+ return pd.DataFrame()
31
+
32
+ class_labels = list(pd.unique(dataset.y))
33
+ data = []
34
+ columns = []
35
+ for col in dataset.X.columns:
36
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
37
+ for label in ['all'] + class_labels:
38
+ columns.append(f"{col}_{label}")
39
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
40
+ if label == 'all':
41
+ data.append(dataset.X[col].kurtosis())
42
+ else:
43
+ data.append(dataset.X.loc[dataset.y == label][col].kurtosis())
44
+ else:
45
+ data.append(None)
46
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
47
+
48
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
49
+ """Does this statistic apply to the dataset?"""
50
+ return dataset.type_of_target not in ['survival', 'continuous']