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,66 @@
1
+ """[STATISTIC] Median Absolute Deviation."""
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 MADStatistic(Statistic):
13
+ """[STATISTIC] Median Absolute Deviation."""
14
+
15
+ name: str = "Median Absolute Deviation"
16
+ _description: str = textwrap.dedent("""\
17
+ Median absolute deviation measures the typical absolute deviation from the median.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Median absolute deviation measures the typical absolute deviation from the median,
21
+ optionally per class for classification.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'mad'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute median absolute deviation for each numerical column."""
30
+ if dataset.type_of_target == 'survival':
31
+ return pd.DataFrame()
32
+
33
+ data = []
34
+ columns = []
35
+
36
+ def mad(series: pd.Series) -> float:
37
+ median = series.median()
38
+ return (series - median).abs().median()
39
+
40
+ if dataset.type_of_target == 'continuous':
41
+ for col in dataset.X.columns:
42
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
43
+ columns.append(col)
44
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
45
+ data.append(mad(dataset.X[col]))
46
+ else:
47
+ data.append(None)
48
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
49
+
50
+ class_labels = list(pd.unique(dataset.y))
51
+ for col in dataset.X.columns:
52
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
53
+ for label in ['all'] + class_labels:
54
+ columns.append(f"{col}_{label}")
55
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
56
+ if label == 'all':
57
+ data.append(mad(dataset.X[col]))
58
+ else:
59
+ data.append(mad(dataset.X.loc[dataset.y == label][col]))
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,61 @@
1
+ """[STATISTIC] 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 MeanStatistic(Statistic):
13
+ """[STATISTIC] Mean."""
14
+
15
+ name: str = "Mean"
16
+ _description: str = textwrap.dedent("""\
17
+ Mean measures the average of numerical columns.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Mean measures the average of numerical columns, optionally per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ def __str__(self) -> str:
25
+ return 'mean'
26
+
27
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
28
+ """Compute mean 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
+ data.append(dataset.X[col].mean())
41
+ else:
42
+ data.append(None)
43
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
44
+
45
+ class_labels = list(pd.unique(dataset.y))
46
+ for col in dataset.X.columns:
47
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
48
+ for label in ['all'] + class_labels:
49
+ columns.append(f"{col}_{label}")
50
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
51
+ if label == 'all':
52
+ data.append(dataset.X[col].mean())
53
+ else:
54
+ data.append(dataset.X.loc[dataset.y == label][col].mean())
55
+ else:
56
+ data.append(None)
57
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
58
+
59
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
60
+ """Does this statistic apply to the dataset?"""
61
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,61 @@
1
+ """[STATISTIC] Median."""
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 MedianStatistic(Statistic):
13
+ """[STATISTIC] Median."""
14
+
15
+ name: str = "Median"
16
+ _description: str = textwrap.dedent("""\
17
+ Median measures the central value of numerical columns.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Median measures the central value of numerical columns, per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ def __str__(self) -> str:
25
+ return 'median'
26
+
27
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
28
+ """Compute median 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
+ data.append(dataset.X[col].median())
41
+ else:
42
+ data.append(None)
43
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
44
+
45
+ class_labels = list(pd.unique(dataset.y))
46
+ for col in dataset.X.columns:
47
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
48
+ for label in ['all'] + class_labels:
49
+ columns.append(f"{col}_{label}")
50
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
51
+ if label == 'all':
52
+ data.append(dataset.X[col].median())
53
+ else:
54
+ data.append(dataset.X.loc[dataset.y == label][col].median())
55
+ else:
56
+ data.append(None)
57
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
58
+
59
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
60
+ """Does this statistic apply to the dataset?"""
61
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,60 @@
1
+ """[STATISTIC] Min / Max."""
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 BoundStatistic(Statistic):
13
+ """[STATISTIC] Bound."""
14
+
15
+ name: str = "Bound"
16
+ _description: str = textwrap.dedent("""\
17
+ Bound measures extreme values (min/max) of numerical columns.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Bound measures extreme values (min/max) of numerical columns, per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ bound_to_compute = ['min', 'max']
25
+
26
+ def __init__(self, bound: str = 'min') -> None:
27
+ self.bound = bound
28
+
29
+ def __str__(self) -> str:
30
+ return self.bound
31
+
32
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
33
+ """Compute min/max for numerical columns."""
34
+ if dataset.type_of_target in ['survival', 'continuous']:
35
+ return pd.DataFrame()
36
+
37
+ class_labels = list(pd.unique(dataset.y))
38
+ df = pd.DataFrame()
39
+ for bound in BoundStatistic.bound_to_compute:
40
+ self.bound = bound
41
+ data = []
42
+ columns = []
43
+ for col in dataset.X.columns:
44
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
45
+ for label in ['all'] + class_labels:
46
+ columns.append(f"{col}_{label}")
47
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
48
+ if label == 'all':
49
+ value = getattr(dataset.X[col], bound)()
50
+ else:
51
+ value = getattr(dataset.X.loc[dataset.y == label][col], bound)()
52
+ data.append(value)
53
+ else:
54
+ data.append(None)
55
+ df = pd.concat([df, pd.DataFrame([data], index=[str(self)], columns=columns)])
56
+ return df
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,62 @@
1
+ """[STATISTIC] Missing Rate."""
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 MissingRateStatistic(Statistic):
13
+ """[STATISTIC] Missing Rate."""
14
+
15
+ name: str = "Missing Rate"
16
+ _description: str = textwrap.dedent("""\
17
+ Missing rate measures the percentage of missing values per column.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Missing rate measures the percentage of missing values per column,
21
+ optionally per class for classification.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'missing_rate'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute missing rate for each column."""
30
+ if dataset.type_of_target == 'survival':
31
+ return pd.DataFrame()
32
+
33
+ data = []
34
+ columns = []
35
+
36
+ if dataset.type_of_target == 'continuous':
37
+ for col in dataset.X.columns:
38
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
39
+ columns.append(col)
40
+ values = dataset.X[col]
41
+ n_rows = int(values.shape[0])
42
+ rate = values.isna().mean() if n_rows else 0.0
43
+ data.append(rate)
44
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
45
+
46
+ class_labels = list(pd.unique(dataset.y))
47
+ for col in dataset.X.columns:
48
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
49
+ for label in ['all'] + class_labels:
50
+ columns.append(f"{col}_{label}")
51
+ if label == 'all':
52
+ values = dataset.X[col]
53
+ else:
54
+ values = dataset.X.loc[dataset.y == label][col]
55
+ n_rows = int(values.shape[0])
56
+ rate = values.isna().mean() if n_rows else 0.0
57
+ data.append(rate)
58
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
59
+
60
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
61
+ """Does this statistic apply to the dataset?"""
62
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,47 @@
1
+ """[STATISTIC] Mode."""
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 ModeStatistic(Statistic):
13
+ """[STATISTIC] Mode."""
14
+
15
+ name: str = "Mode"
16
+ _description: str = textwrap.dedent("""\
17
+ Mode measures the most common values of each column.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Mode measures the most common values of each column, per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ def __str__(self) -> str:
25
+ return 'mode'
26
+
27
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
28
+ """Compute mode for each column."""
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 label == 'all':
40
+ data.append(dataset.X[col].mode().to_list())
41
+ else:
42
+ data.append(dataset.X.loc[dataset.y == label][col].mode().to_list())
43
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
44
+
45
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
46
+ """Does this statistic apply to the dataset?"""
47
+ return dataset.type_of_target not in ['survival', 'continuous']
@@ -0,0 +1,81 @@
1
+ """[STATISTIC] Most Frequent Ratio."""
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 MostFrequentRatioStatistic(Statistic):
13
+ """[STATISTIC] Most Frequent Ratio."""
14
+
15
+ name: str = "Most Frequent Ratio"
16
+ _description: str = textwrap.dedent("""\
17
+ Most frequent ratio measures the share of the dominant category in
18
+ categorical columns.
19
+ """)
20
+ _description_long: str = textwrap.dedent("""\
21
+ Most frequent ratio measures the ratio of the most common category in
22
+ categorical columns, optionally per class.
23
+ """)
24
+ refs: list[dict] = []
25
+
26
+ def __str__(self) -> str:
27
+ return 'most_frequent_ratio'
28
+
29
+ def _select_columns(self, dataset: Dataset) -> list[str]:
30
+ columns = dataset.get_columns_names_by_type(DataType.CATEGORICAL)
31
+ category_columns = list(dataset.X.select_dtypes(include=['category']).columns)
32
+ seen = set()
33
+ ordered = []
34
+ for column in columns + category_columns:
35
+ if column in dataset.X.columns and column not in seen:
36
+ ordered.append(column)
37
+ seen.add(column)
38
+ return ordered
39
+
40
+ def _most_frequent_ratio(self, series: pd.Series) -> float:
41
+ counts = series.value_counts(dropna=True)
42
+ if counts.empty:
43
+ return 0.0
44
+ total = int(counts.sum())
45
+ if total <= 0:
46
+ return 0.0
47
+ top = int(counts.max())
48
+ return top / total
49
+
50
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
51
+ """Compute most frequent ratio for categorical columns."""
52
+ if dataset.type_of_target == 'survival':
53
+ return pd.DataFrame()
54
+
55
+ columns = self._select_columns(dataset)
56
+ if not columns:
57
+ return pd.DataFrame()
58
+
59
+ data = []
60
+ df_columns = []
61
+
62
+ if dataset.type_of_target == 'continuous':
63
+ for col in columns:
64
+ df_columns.append(col)
65
+ data.append(self._most_frequent_ratio(dataset.X[col]))
66
+ return pd.DataFrame([data], index=[str(self)], columns=df_columns)
67
+
68
+ class_labels = list(pd.unique(dataset.y))
69
+ for col in columns:
70
+ for label in ['all'] + class_labels:
71
+ df_columns.append(f"{col}_{label}")
72
+ if label == 'all':
73
+ values = dataset.X[col]
74
+ else:
75
+ values = dataset.X.loc[dataset.y == label][col]
76
+ data.append(self._most_frequent_ratio(values))
77
+ return pd.DataFrame([data], index=[str(self)], columns=df_columns)
78
+
79
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
80
+ """Does this statistic apply to the dataset?"""
81
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,76 @@
1
+ """[STATISTIC] Outlier Count (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 OutlierCountIQRStatistic(Statistic):
13
+ """[STATISTIC] Outlier Count (IQR)."""
14
+
15
+ name: str = "Outlier Count (IQR)"
16
+ _description: str = textwrap.dedent("""\
17
+ Outlier count measures how many values fall outside 1.5*IQR.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Outlier count measures how many values fall outside 1.5*IQR,
21
+ optionally per class for classification.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'outlier_count_iqr'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute outlier counts (1.5*IQR rule) for each numerical column."""
30
+ if dataset.type_of_target == 'survival':
31
+ return pd.DataFrame()
32
+
33
+ def count_outliers(values: pd.Series) -> int:
34
+ values = values.dropna()
35
+ if values.empty:
36
+ return 0
37
+ q1 = values.quantile(0.25)
38
+ q3 = values.quantile(0.75)
39
+ iqr = q3 - q1
40
+ if pd.isna(iqr):
41
+ return 0
42
+ lower = q1 - 1.5 * iqr
43
+ upper = q3 + 1.5 * iqr
44
+ return int(((values < lower) | (values > upper)).sum())
45
+
46
+ data = []
47
+ columns = []
48
+
49
+ if dataset.type_of_target == 'continuous':
50
+ for col in dataset.X.columns:
51
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
52
+ columns.append(col)
53
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
54
+ data.append(count_outliers(dataset.X[col]))
55
+ else:
56
+ data.append(None)
57
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
58
+
59
+ class_labels = list(pd.unique(dataset.y))
60
+ for col in dataset.X.columns:
61
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
62
+ for label in ['all'] + class_labels:
63
+ columns.append(f"{col}_{label}")
64
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
65
+ if label == 'all':
66
+ values = dataset.X[col]
67
+ else:
68
+ values = dataset.X.loc[dataset.y == label][col]
69
+ data.append(count_outliers(values))
70
+ else:
71
+ data.append(None)
72
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
73
+
74
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
75
+ """Does this statistic apply to the dataset?"""
76
+ return dataset.type_of_target != 'survival'
@@ -0,0 +1,59 @@
1
+ """[STATISTIC] Quantile."""
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 QuantileStatistic(Statistic):
13
+ """[STATISTIC] Quantile."""
14
+
15
+ name: str = "Quantile"
16
+ _description: str = textwrap.dedent("""\
17
+ Quantile measures percentile values of numerical columns.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Quantile measures percentile values of numerical columns, per class for classification.
21
+ """)
22
+ refs: list[dict] = []
23
+
24
+ quantile_to_compute = [0.1, 0.25, 0.50, 0.75, 0.90]
25
+
26
+ def __init__(self, percentile: float = 0.5) -> None:
27
+ self.percentile = percentile
28
+
29
+ def __str__(self) -> str:
30
+ return f'quantile_{self.percentile}'
31
+
32
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
33
+ """Compute quantiles for numerical columns."""
34
+ if dataset.type_of_target in ['survival', 'continuous']:
35
+ return pd.DataFrame()
36
+
37
+ class_labels = list(pd.unique(dataset.y))
38
+ df = pd.DataFrame()
39
+ for quantile in QuantileStatistic.quantile_to_compute:
40
+ self.percentile = quantile
41
+ data = []
42
+ columns = []
43
+ for col in dataset.X.columns:
44
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
45
+ for label in ['all'] + class_labels:
46
+ columns.append(f"{col}_{label}")
47
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
48
+ if label == 'all':
49
+ data.append(dataset.X[col].quantile(self.percentile))
50
+ else:
51
+ data.append(dataset.X.loc[dataset.y == label][col].quantile(self.percentile))
52
+ else:
53
+ data.append(None)
54
+ df = pd.concat([df, pd.DataFrame([data], index=[str(self)], columns=columns)])
55
+ return df
56
+
57
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
58
+ """Does this statistic apply to the dataset?"""
59
+ return dataset.type_of_target not in ['survival', 'continuous']
@@ -0,0 +1,53 @@
1
+ """[STATISTIC] Range."""
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 RangeStatistic(Statistic):
13
+ """[STATISTIC] Range."""
14
+
15
+ name: str = "Range"
16
+ _description: str = textwrap.dedent("""\
17
+ Range measures the dispersion between min and max for numerical columns.
18
+ """)
19
+ _description_long: str = textwrap.dedent("""\
20
+ Range measures the dispersion between min and max for numerical columns,
21
+ per class for classification.
22
+ """)
23
+ refs: list[dict] = []
24
+
25
+ def __str__(self) -> str:
26
+ return 'range'
27
+
28
+ def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
29
+ """Compute range for numerical columns."""
30
+ if dataset.type_of_target in ['survival', 'continuous']:
31
+ return pd.DataFrame()
32
+
33
+ class_labels = list(pd.unique(dataset.y))
34
+ data = []
35
+ columns = []
36
+ for col in dataset.X.columns:
37
+ if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
38
+ for label in ['all'] + class_labels:
39
+ columns.append(f"{col}_{label}")
40
+ if dataset.columns_types[col][1] == DataType.NUMERIC:
41
+ if label == 'all':
42
+ value = dataset.X[col].max() - dataset.X[col].min()
43
+ else:
44
+ values = dataset.X.loc[dataset.y == label][col]
45
+ value = values.max() - values.min()
46
+ data.append(value)
47
+ else:
48
+ data.append(None)
49
+ return pd.DataFrame([data], index=[str(self)], columns=columns)
50
+
51
+ def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
52
+ """Does this statistic apply to the dataset?"""
53
+ return dataset.type_of_target not in ['survival', 'continuous']