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.
- iaml/__init__.py +56 -0
- iaml/actionable.py +11 -0
- iaml/actionables/__init__.py +21 -0
- iaml/actionables/boosting/__init__.py +4 -0
- iaml/actionables/boosting/act_adaboost.py +59 -0
- iaml/actionables/cleaning/__init__.py +26 -0
- iaml/actionables/cleaning/act_categorical_imputer.py +124 -0
- iaml/actionables/cleaning/act_count_vectorizer.py +204 -0
- iaml/actionables/cleaning/act_drop_categorical_column.py +51 -0
- iaml/actionables/cleaning/act_drop_date_column.py +48 -0
- iaml/actionables/cleaning/act_drop_high_cardinality_categorical.py +337 -0
- iaml/actionables/cleaning/act_drop_numerical_column.py +75 -0
- iaml/actionables/cleaning/act_drop_textual_column.py +51 -0
- iaml/actionables/cleaning/act_encode_target_column.py +56 -0
- iaml/actionables/cleaning/act_frequency_encoder.py +127 -0
- iaml/actionables/cleaning/act_hashing_vectorizer.py +186 -0
- iaml/actionables/cleaning/act_knn_imputer.py +152 -0
- iaml/actionables/cleaning/act_mean_column.py +79 -0
- iaml/actionables/cleaning/act_mice.py +464 -0
- iaml/actionables/cleaning/act_missing_count_feature.py +109 -0
- iaml/actionables/cleaning/act_missing_indicator.py +124 -0
- iaml/actionables/cleaning/act_onehot.py +65 -0
- iaml/actionables/cleaning/act_ordinal_encoder.py +177 -0
- iaml/actionables/cleaning/act_rare_category_grouper.py +173 -0
- iaml/actionables/cleaning/act_simple_imputer.py +109 -0
- iaml/actionables/cleaning/act_split_date.py +68 -0
- iaml/actionables/cleaning/act_target_encoder.py +274 -0
- iaml/actionables/cleaning/act_text_normalizer.py +241 -0
- iaml/actionables/cleaning/act_tf_idf.py +80 -0
- iaml/actionables/cleaning/act_word2vec.py +150 -0
- iaml/actionables/features_precleaning/__init__.py +12 -0
- iaml/actionables/features_precleaning/act_coerce_numeric_strings.py +194 -0
- iaml/actionables/features_precleaning/act_date_converter.py +99 -0
- iaml/actionables/features_precleaning/act_drop_bad_quality_rows.py +77 -0
- iaml/actionables/features_precleaning/act_drop_duplicate_rows.py +131 -0
- iaml/actionables/features_precleaning/act_drop_high_missing_columns.py +94 -0
- iaml/actionables/features_precleaning/act_drop_id_like_columns.py +294 -0
- iaml/actionables/features_precleaning/act_normalize_column_names.py +157 -0
- iaml/actionables/features_precleaning/act_sentinel_to_na_n.py +270 -0
- iaml/actionables/features_precleaning/act_trim_space.py +79 -0
- iaml/actionables/features_preprocessing/__init__.py +18 -0
- iaml/actionables/features_preprocessing/act_cyclical_date_encoding.py +212 -0
- iaml/actionables/features_preprocessing/act_fast_ica.py +161 -0
- iaml/actionables/features_preprocessing/act_feature_agglomeration.py +90 -0
- iaml/actionables/features_preprocessing/act_k_bins_discretizer.py +207 -0
- iaml/actionables/features_preprocessing/act_k_means_features.py +296 -0
- iaml/actionables/features_preprocessing/act_kernel_pca.py +143 -0
- iaml/actionables/features_preprocessing/act_log_transformer.py +122 -0
- iaml/actionables/features_preprocessing/act_nystroem.py +100 -0
- iaml/actionables/features_preprocessing/act_pca.py +77 -0
- iaml/actionables/features_preprocessing/act_polynomial_features.py +86 -0
- iaml/actionables/features_preprocessing/act_power_transformer.py +106 -0
- iaml/actionables/features_preprocessing/act_quantile_transformer.py +114 -0
- iaml/actionables/features_preprocessing/act_rbf_sampler.py +88 -0
- iaml/actionables/features_preprocessing/act_select_percentile.py +112 -0
- iaml/actionables/features_preprocessing/act_sparse_random_projection.py +157 -0
- iaml/actionables/features_preprocessing/act_truncated_svd.py +137 -0
- iaml/actionables/features_selection/__init__.py +8 -0
- iaml/actionables/features_selection/act_permutation_importance_selector.py +421 -0
- iaml/actionables/features_selection/act_remove_high_correlated_column.py +70 -0
- iaml/actionables/features_selection/act_remove_low_variance_column.py +74 -0
- iaml/actionables/features_selection/act_rfe.py +214 -0
- iaml/actionables/features_selection/act_select_from_model.py +325 -0
- iaml/actionables/features_selection/act_select_k_best.py +181 -0
- iaml/actionables/features_selection/act_vif_selector.py +130 -0
- iaml/actionables/imbalance/__init__.py +10 -0
- iaml/actionables/imbalance/act_adasyn.py +150 -0
- iaml/actionables/imbalance/act_borderline_smote.py +171 -0
- iaml/actionables/imbalance/act_near_miss.py +158 -0
- iaml/actionables/imbalance/act_random_over_sampling.py +60 -0
- iaml/actionables/imbalance/act_random_under_sampler.py +135 -0
- iaml/actionables/imbalance/act_smote.py +162 -0
- iaml/actionables/imbalance/act_smote_tomek.py +182 -0
- iaml/actionables/imbalance/act_smoteenn.py +193 -0
- iaml/actionables/imbalance/act_tomek_links.py +138 -0
- iaml/actionables/normalize/__init__.py +6 -0
- iaml/actionables/normalize/act_max_abs_scaler.py +78 -0
- iaml/actionables/normalize/act_minmax_scaler.py +56 -0
- iaml/actionables/normalize/act_normalizer.py +95 -0
- iaml/actionables/normalize/act_robust_scaler.py +111 -0
- iaml/actionables/normalize/act_standard_scaler.py +55 -0
- iaml/actionables/predictors/__init__.py +6 -0
- iaml/actionables/predictors/_xgboost.py +16 -0
- iaml/actionables/predictors/classifier/__init__.py +26 -0
- iaml/actionables/predictors/classifier/act_bagging_classifier.py +113 -0
- iaml/actionables/predictors/classifier/act_bernoulli_nb.py +89 -0
- iaml/actionables/predictors/classifier/act_catboost_classifier.py +135 -0
- iaml/actionables/predictors/classifier/act_complement_nb.py +106 -0
- iaml/actionables/predictors/classifier/act_decision_tree_classifier.py +117 -0
- iaml/actionables/predictors/classifier/act_extra_trees_classifier.py +115 -0
- iaml/actionables/predictors/classifier/act_gaussian_nb.py +53 -0
- iaml/actionables/predictors/classifier/act_hist_gradient_boosting_classifier.py +144 -0
- iaml/actionables/predictors/classifier/act_knn.py +86 -0
- iaml/actionables/predictors/classifier/act_light_gbm_classifier.py +211 -0
- iaml/actionables/predictors/classifier/act_linear_discriminant_analysis.py +63 -0
- iaml/actionables/predictors/classifier/act_linear_svc.py +134 -0
- iaml/actionables/predictors/classifier/act_logistic_regression.py +92 -0
- iaml/actionables/predictors/classifier/act_mlp_classifier.py +107 -0
- iaml/actionables/predictors/classifier/act_multinomial_nb.py +76 -0
- iaml/actionables/predictors/classifier/act_passive_aggressive_classifier.py +141 -0
- iaml/actionables/predictors/classifier/act_quadratic_discriminant_analysis.py +72 -0
- iaml/actionables/predictors/classifier/act_randomforest.py +113 -0
- iaml/actionables/predictors/classifier/act_ridge_classifier.py +116 -0
- iaml/actionables/predictors/classifier/act_sgd_classifier.py +149 -0
- iaml/actionables/predictors/classifier/act_svm_svc.py +88 -0
- iaml/actionables/predictors/classifier/act_xgboost.py +111 -0
- iaml/actionables/predictors/regressor/__init__.py +27 -0
- iaml/actionables/predictors/regressor/act_ada_boost_regressor.py +75 -0
- iaml/actionables/predictors/regressor/act_ard_regression.py +95 -0
- iaml/actionables/predictors/regressor/act_catboost_regressor.py +134 -0
- iaml/actionables/predictors/regressor/act_decision_tree_regressor.py +111 -0
- iaml/actionables/predictors/regressor/act_elastic_net_regressor.py +109 -0
- iaml/actionables/predictors/regressor/act_extra_trees_regressor.py +113 -0
- iaml/actionables/predictors/regressor/act_gaussian_process_regressor.py +55 -0
- iaml/actionables/predictors/regressor/act_gboost_regressor.py +95 -0
- iaml/actionables/predictors/regressor/act_hist_gradient_boosting_regressor.py +105 -0
- iaml/actionables/predictors/regressor/act_huber_regressor.py +101 -0
- iaml/actionables/predictors/regressor/act_knn_regressor.py +86 -0
- iaml/actionables/predictors/regressor/act_lasso_regressor.py +103 -0
- iaml/actionables/predictors/regressor/act_light_gbm_regressor.py +201 -0
- iaml/actionables/predictors/regressor/act_linear_regression.py +43 -0
- iaml/actionables/predictors/regressor/act_mlp_regressor.py +104 -0
- iaml/actionables/predictors/regressor/act_poisson_regressor.py +111 -0
- iaml/actionables/predictors/regressor/act_quantile_regressor.py +87 -0
- iaml/actionables/predictors/regressor/act_randomforest_regressor.py +116 -0
- iaml/actionables/predictors/regressor/act_ransac_regressor.py +106 -0
- iaml/actionables/predictors/regressor/act_ridge_regressor.py +107 -0
- iaml/actionables/predictors/regressor/act_sgd_regressor.py +106 -0
- iaml/actionables/predictors/regressor/act_svm_svr.py +81 -0
- iaml/actionables/predictors/regressor/act_xgboost_regressor.py +97 -0
- iaml/actionables/predictors/survival/__init__.py +12 -0
- iaml/actionables/predictors/survival/act_aalen_additive_model.py +83 -0
- iaml/actionables/predictors/survival/act_cox.py +110 -0
- iaml/actionables/predictors/survival/act_coxnet_survival_analysis.py +134 -0
- iaml/actionables/predictors/survival/act_extra_survival_trees.py +101 -0
- iaml/actionables/predictors/survival/act_fast_survival_svm.py +102 -0
- iaml/actionables/predictors/survival/act_gradient_boosting_survival_analysis.py +93 -0
- iaml/actionables/predictors/survival/act_random_survival_forest.py +91 -0
- iaml/actionables/predictors/survival/act_survival_component_wise_gboost.py +80 -0
- iaml/actionables/predictors/survival/act_survival_tree.py +120 -0
- iaml/actionables/predictors/survival/act_survival_xgboost.py +9 -0
- iaml/actionables/predictors/survival/act_weibull_aft.py +230 -0
- iaml/cache.py +61 -0
- iaml/cache_keys.py +57 -0
- iaml/candidate.py +736 -0
- iaml/core_dispatcher.py +125 -0
- iaml/data_type.py +11 -0
- iaml/dataset.py +506 -0
- iaml/decorators/__init__.py +3 -0
- iaml/decorators/all.py +4 -0
- iaml/decorators/is_step.py +45 -0
- iaml/decorators/runner.py +100 -0
- iaml/explanation.py +112 -0
- iaml/iaml.py +1072 -0
- iaml/iaml_pipeline.py +600 -0
- iaml/logger.py +138 -0
- iaml/meta_explorer_step.py +62 -0
- iaml/meta_ordered_step.py +28 -0
- iaml/meta_partial_explorer_step.py +34 -0
- iaml/meta_singleton.py +24 -0
- iaml/metastep.py +211 -0
- iaml/metric.py +111 -0
- iaml/metric_plot.py +82 -0
- iaml/metrics/__init__.py +21 -0
- iaml/metrics/_classification.py +28 -0
- iaml/metrics/_survival_times.py +22 -0
- iaml/metrics/accuracy_metric.py +59 -0
- iaml/metrics/balanced_accuracy_metric.py +67 -0
- iaml/metrics/brier_score.py +90 -0
- iaml/metrics/classification_error_metric.py +66 -0
- iaml/metrics/concordance_index_ipcw.py +84 -0
- iaml/metrics/concordance_index_metric.py +67 -0
- iaml/metrics/cumulative_dynamic_auc.py +119 -0
- iaml/metrics/f1_score_metric.py +71 -0
- iaml/metrics/integrated_brier_score.py +98 -0
- iaml/metrics/integrated_brier_score_loss.py +41 -0
- iaml/metrics/mean_absolute_error_metric.py +46 -0
- iaml/metrics/mean_squared_error_metric.py +46 -0
- iaml/metrics/mean_squared_log_error_metric.py +49 -0
- iaml/metrics/median_absolute_error_metric.py +48 -0
- iaml/metrics/precision_metric.py +63 -0
- iaml/metrics/r2_score_metric.py +45 -0
- iaml/metrics/recall_metric.py +65 -0
- iaml/metrics/roc_auc_metric.py +50 -0
- iaml/metrics/specificity_metric.py +44 -0
- iaml/metrics/specificity_multiclass_metric.py +55 -0
- iaml/metrics/specificity_multilabel_metric.py +60 -0
- iaml/optimizers/__init__.py +5 -0
- iaml/optimizers/bayesian_optimizer.py +193 -0
- iaml/optimizers/genetic_optimizer.py +284 -0
- iaml/optimizers/optimizer.py +31 -0
- iaml/optimizers/random_optimizer.py +101 -0
- iaml/plot.py +138 -0
- iaml/plots/__init__.py +32 -0
- iaml/plots/bar_plot.py +141 -0
- iaml/plots/box_plot.py +166 -0
- iaml/plots/class_prediction_error_plot.py +37 -0
- iaml/plots/classification_report_plot.py +35 -0
- iaml/plots/confusion_matrix_plot.py +34 -0
- iaml/plots/correlation_heatmap_plot.py +201 -0
- iaml/plots/cumulative_hazard_plot.py +72 -0
- iaml/plots/density_plot.py +210 -0
- iaml/plots/histogram_plot.py +179 -0
- iaml/plots/kaplan_meier_comparison_plot.py +89 -0
- iaml/plots/line_plot.py +70 -0
- iaml/plots/missingness_heatmap_plot.py +203 -0
- iaml/plots/outlier_plot.py +217 -0
- iaml/plots/pair_plot.py +228 -0
- iaml/plots/precision_recall_curve_plot.py +86 -0
- iaml/plots/prediction_error_plot.py +34 -0
- iaml/plots/qq_plot.py +220 -0
- iaml/plots/residual_plot.py +38 -0
- iaml/plots/roc_dynamique_curve_plot.py +79 -0
- iaml/plots/rocauc_plot.py +96 -0
- iaml/plots/shap_plot.py +187 -0
- iaml/plots/target_distribution_plot.py +241 -0
- iaml/plots/violin_plot.py +206 -0
- iaml/predictor.py +139 -0
- iaml/reference.py +65 -0
- iaml/shared_cache.py +90 -0
- iaml/sklearn_preprocessor.py +74 -0
- iaml/splitters/__init__.py +3 -0
- iaml/splitters/kfold_splitter.py +32 -0
- iaml/splitters/random_splitter.py +26 -0
- iaml/stack.py +39 -0
- iaml/statistic.py +66 -0
- iaml/statistics/__init__.py +77 -0
- iaml/statistics/anova_statistic.py +80 -0
- iaml/statistics/cardinality_ratio_statistic.py +63 -0
- iaml/statistics/category_cooccurrence_statistic.py +79 -0
- iaml/statistics/chi_square_statistic.py +81 -0
- iaml/statistics/coef_variation_statistic.py +72 -0
- iaml/statistics/correlation_with_target.py +105 -0
- iaml/statistics/count.py +72 -0
- iaml/statistics/data_type_summary_statistic.py +74 -0
- iaml/statistics/duplicate_row_statistic.py +56 -0
- iaml/statistics/effect_size_statistic.py +129 -0
- iaml/statistics/entropy_statistic.py +69 -0
- iaml/statistics/event_rate_statistic.py +52 -0
- iaml/statistics/grouped_mean_statistic.py +60 -0
- iaml/statistics/iqr_statistic.py +66 -0
- iaml/statistics/kurtosis.py +50 -0
- iaml/statistics/mad_statistic.py +66 -0
- iaml/statistics/mean.py +61 -0
- iaml/statistics/median_statistic.py +61 -0
- iaml/statistics/minmax.py +60 -0
- iaml/statistics/missing_rate_statistic.py +62 -0
- iaml/statistics/mode.py +47 -0
- iaml/statistics/most_frequent_ratio.py +81 -0
- iaml/statistics/outlier_count_iqr_statistic.py +76 -0
- iaml/statistics/quantile.py +59 -0
- iaml/statistics/range.py +53 -0
- iaml/statistics/rare_category_rate.py +92 -0
- iaml/statistics/skewness.py +53 -0
- iaml/statistics/stdev.py +50 -0
- iaml/statistics/summary_table_statistic.py +60 -0
- iaml/statistics/time_by_group_statistic.py +83 -0
- iaml/statistics/time_summary_statistic.py +56 -0
- iaml/statistics/top_k_value_counts.py +68 -0
- iaml/statistics/unique_count_statistic.py +57 -0
- iaml/statistics/value_counts.py +63 -0
- iaml/statistics/variance.py +51 -0
- iaml/statistics/violin.py +63 -0
- iaml/step.py +600 -0
- iaml/step_cache.py +87 -0
- iaml/step_wrapper.py +79 -0
- iaml/timed_pool_executor.py +492 -0
- iaml/type_of_target.py +68 -0
- iaml/void_step.py +101 -0
- iaml/worker_manager.py +169 -0
- iaml/wrapper/__init__.py +4 -0
- iaml/wrapper/wrap_basic_gridsearch.py +68 -0
- iaml/wrapper/wrap_genetic_gridsearch.py +293 -0
- iaml/wrapper/wrap_iterative_gridsearch.py +399 -0
- pyiaml-1.0.0.dist-info/METADATA +802 -0
- pyiaml-1.0.0.dist-info/RECORD +279 -0
- pyiaml-1.0.0.dist-info/WHEEL +5 -0
- pyiaml-1.0.0.dist-info/licenses/LICENSE +674 -0
- pyiaml-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"""[STATISTIC] Rare Category Rate."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import math
|
|
5
|
+
import textwrap
|
|
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 RareCategoryRateStatistic(Statistic):
|
|
14
|
+
"""[STATISTIC] Rare Category Rate."""
|
|
15
|
+
|
|
16
|
+
name: str = "Rare Category Rate"
|
|
17
|
+
_description: str = textwrap.dedent("""\
|
|
18
|
+
Rare category rate measures the share of rare categories in categorical columns.
|
|
19
|
+
""")
|
|
20
|
+
_description_long: str = textwrap.dedent("""\
|
|
21
|
+
Rare category rate measures the ratio of categories whose frequency is below a
|
|
22
|
+
threshold for categorical columns, optionally per class.
|
|
23
|
+
""")
|
|
24
|
+
refs: list[dict] = []
|
|
25
|
+
|
|
26
|
+
def __str__(self) -> str:
|
|
27
|
+
return 'rare_category_rate'
|
|
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 _rare_ratio(self, series: pd.Series, threshold: float) -> float:
|
|
41
|
+
counts = series.value_counts(dropna=True)
|
|
42
|
+
total = int(counts.sum())
|
|
43
|
+
if total <= 0 or counts.empty:
|
|
44
|
+
return 0.0
|
|
45
|
+
if threshold <= 0:
|
|
46
|
+
return 0.0
|
|
47
|
+
ratios = counts / total
|
|
48
|
+
rare_count = int((ratios < threshold).sum())
|
|
49
|
+
return rare_count / len(counts)
|
|
50
|
+
|
|
51
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
52
|
+
"""Compute the rare category rate for categorical columns."""
|
|
53
|
+
if dataset.type_of_target == 'survival':
|
|
54
|
+
return pd.DataFrame()
|
|
55
|
+
|
|
56
|
+
threshold = kwargs.get('threshold')
|
|
57
|
+
if threshold is None:
|
|
58
|
+
threshold = kwargs.get('min_frequency', 0.01)
|
|
59
|
+
try:
|
|
60
|
+
threshold = float(threshold)
|
|
61
|
+
except (TypeError, ValueError):
|
|
62
|
+
threshold = 0.01
|
|
63
|
+
if not math.isfinite(threshold):
|
|
64
|
+
threshold = 0.01
|
|
65
|
+
|
|
66
|
+
columns = self._select_columns(dataset)
|
|
67
|
+
if not columns:
|
|
68
|
+
return pd.DataFrame()
|
|
69
|
+
|
|
70
|
+
data = []
|
|
71
|
+
df_columns = []
|
|
72
|
+
|
|
73
|
+
if dataset.type_of_target == 'continuous':
|
|
74
|
+
for col in columns:
|
|
75
|
+
df_columns.append(col)
|
|
76
|
+
data.append(self._rare_ratio(dataset.X[col], threshold))
|
|
77
|
+
return pd.DataFrame([data], index=[str(self)], columns=df_columns)
|
|
78
|
+
|
|
79
|
+
class_labels = list(pd.unique(dataset.y))
|
|
80
|
+
for col in columns:
|
|
81
|
+
for label in ['all'] + class_labels:
|
|
82
|
+
df_columns.append(f"{col}_{label}")
|
|
83
|
+
if label == 'all':
|
|
84
|
+
values = dataset.X[col]
|
|
85
|
+
else:
|
|
86
|
+
values = dataset.X.loc[dataset.y == label][col]
|
|
87
|
+
data.append(self._rare_ratio(values, threshold))
|
|
88
|
+
return pd.DataFrame([data], index=[str(self)], columns=df_columns)
|
|
89
|
+
|
|
90
|
+
def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
|
|
91
|
+
"""Does this statistic apply to the dataset?"""
|
|
92
|
+
return dataset.type_of_target != 'survival'
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""[STATISTIC] Skewness."""
|
|
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 SkewnessStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Skewness."""
|
|
14
|
+
|
|
15
|
+
name: str = "Skewness"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Skewness measures the asymmetry of numerical distributions.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Skewness measures the asymmetry of numerical distributions, per class for classification.
|
|
21
|
+
""")
|
|
22
|
+
refs: list[dict] = []
|
|
23
|
+
|
|
24
|
+
def __str__(self) -> str:
|
|
25
|
+
return 'skewness'
|
|
26
|
+
|
|
27
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
28
|
+
"""Compute skewness for numerical columns."""
|
|
29
|
+
if dataset.type_of_target == 'survival':
|
|
30
|
+
return pd.DataFrame()
|
|
31
|
+
|
|
32
|
+
if dataset.type_of_target == 'continuous':
|
|
33
|
+
return pd.DataFrame()
|
|
34
|
+
|
|
35
|
+
class_labels = list(pd.unique(dataset.y))
|
|
36
|
+
data = []
|
|
37
|
+
columns = []
|
|
38
|
+
for col in dataset.X.columns:
|
|
39
|
+
if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
|
|
40
|
+
for label in ['all'] + class_labels:
|
|
41
|
+
columns.append(f"{col}_{label}")
|
|
42
|
+
if dataset.columns_types[col][1] == DataType.NUMERIC:
|
|
43
|
+
if label == 'all':
|
|
44
|
+
data.append(dataset.X[col].skew())
|
|
45
|
+
else:
|
|
46
|
+
data.append(dataset.X.loc[dataset.y == label][col].skew())
|
|
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 != 'survival'
|
iaml/statistics/stdev.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"""[STATISTIC] Standard 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 StdevStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Standard deviation."""
|
|
14
|
+
|
|
15
|
+
name: str = "Stdev"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Stdev measures the standard deviation of numerical columns.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Stdev measures the standard deviation of numerical columns, per class for classification.
|
|
21
|
+
""")
|
|
22
|
+
refs: list[dict] = []
|
|
23
|
+
|
|
24
|
+
def __str__(self) -> str:
|
|
25
|
+
return 'stdev'
|
|
26
|
+
|
|
27
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
28
|
+
"""Compute standard deviation 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].std())
|
|
42
|
+
else:
|
|
43
|
+
data.append(dataset.X.loc[dataset.y == label][col].std())
|
|
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']
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""[STATISTIC] Summary Table."""
|
|
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 SummaryTableStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Summary Table."""
|
|
14
|
+
|
|
15
|
+
name: str = "Summary Table"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Summary table reports global dataset properties.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Summary table reports global dataset properties: number of rows, number of
|
|
21
|
+
usable columns, total missing values, and memory usage.
|
|
22
|
+
""")
|
|
23
|
+
refs: list[dict] = []
|
|
24
|
+
|
|
25
|
+
def __str__(self) -> str:
|
|
26
|
+
return 'summary_table'
|
|
27
|
+
|
|
28
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
29
|
+
"""Compute global summary table for the dataset."""
|
|
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
|
+
if columns:
|
|
39
|
+
data_frame = dataset.X[columns]
|
|
40
|
+
n_missing_total = int(data_frame.isna().sum().sum())
|
|
41
|
+
memory = int(data_frame.memory_usage(deep=True).sum())
|
|
42
|
+
else:
|
|
43
|
+
n_missing_total = 0
|
|
44
|
+
memory = 0
|
|
45
|
+
|
|
46
|
+
data = [[
|
|
47
|
+
dataset.X.shape[0],
|
|
48
|
+
len(columns),
|
|
49
|
+
n_missing_total,
|
|
50
|
+
memory,
|
|
51
|
+
]]
|
|
52
|
+
return pd.DataFrame(
|
|
53
|
+
data,
|
|
54
|
+
index=[str(self)],
|
|
55
|
+
columns=["n_rows", "n_cols", "n_missing_total", "memory"],
|
|
56
|
+
)
|
|
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 != 'survival'
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"""[STATISTIC] Time By Group."""
|
|
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 TimeByGroupStatistic(Statistic):
|
|
14
|
+
"""[STATISTIC] Time By Group."""
|
|
15
|
+
|
|
16
|
+
name: str = "Time By Group"
|
|
17
|
+
_description: str = textwrap.dedent("""\
|
|
18
|
+
Time by group reports event rate and median time by category.
|
|
19
|
+
""")
|
|
20
|
+
_description_long: str = textwrap.dedent("""\
|
|
21
|
+
Time by group reports event rate and median survival time per category
|
|
22
|
+
for categorical features in survival targets.
|
|
23
|
+
""")
|
|
24
|
+
refs: list[dict] = []
|
|
25
|
+
|
|
26
|
+
def __str__(self) -> str:
|
|
27
|
+
return 'time_by_group'
|
|
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 compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
41
|
+
"""Compute event rate and median time by categorical group."""
|
|
42
|
+
if dataset.type_of_target != 'survival':
|
|
43
|
+
return pd.DataFrame()
|
|
44
|
+
|
|
45
|
+
columns = self._select_columns(dataset)
|
|
46
|
+
if not columns:
|
|
47
|
+
return pd.DataFrame()
|
|
48
|
+
|
|
49
|
+
samples = Dataset.normalize_survival_target(dataset.y)
|
|
50
|
+
if not samples or len(samples) != len(dataset.X):
|
|
51
|
+
return pd.DataFrame()
|
|
52
|
+
|
|
53
|
+
events = np.asarray([event for event, _ in samples], dtype=float)
|
|
54
|
+
times = np.asarray([time for _, time in samples], dtype=float)
|
|
55
|
+
|
|
56
|
+
frame = dataset.X[columns].copy()
|
|
57
|
+
frame['_event'] = events
|
|
58
|
+
frame['_time'] = times
|
|
59
|
+
|
|
60
|
+
data = []
|
|
61
|
+
df_columns = []
|
|
62
|
+
for col in columns:
|
|
63
|
+
values = frame[[col, '_event', '_time']].dropna(subset=[col])
|
|
64
|
+
if values.empty:
|
|
65
|
+
continue
|
|
66
|
+
grouped = values.groupby(col, sort=True)
|
|
67
|
+
event_rates = grouped['_event'].mean()
|
|
68
|
+
median_times = grouped['_time'].median()
|
|
69
|
+
for group_value in event_rates.index:
|
|
70
|
+
value_label = str(group_value)
|
|
71
|
+
df_columns.append(f"{col}_{value_label}_event_rate")
|
|
72
|
+
data.append(float(event_rates.loc[group_value]))
|
|
73
|
+
df_columns.append(f"{col}_{value_label}_median_time")
|
|
74
|
+
data.append(float(median_times.loc[group_value]))
|
|
75
|
+
|
|
76
|
+
if not df_columns:
|
|
77
|
+
return pd.DataFrame()
|
|
78
|
+
|
|
79
|
+
return pd.DataFrame([data], index=[str(self)], columns=df_columns)
|
|
80
|
+
|
|
81
|
+
def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
|
|
82
|
+
"""Does this statistic apply to the dataset?"""
|
|
83
|
+
return dataset.type_of_target == 'survival'
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""[STATISTIC] Time Summary."""
|
|
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 ..statistic import Statistic
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TimeSummaryStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Time Summary."""
|
|
14
|
+
|
|
15
|
+
name: str = "Time Summary"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Time summary reports key statistics of survival times.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Time summary reports min/median/max and selected quantiles of survival times.
|
|
21
|
+
""")
|
|
22
|
+
refs: list[dict] = []
|
|
23
|
+
|
|
24
|
+
quantiles = [0.1, 0.25, 0.75, 0.9]
|
|
25
|
+
|
|
26
|
+
def __str__(self) -> str:
|
|
27
|
+
return 'time_summary'
|
|
28
|
+
|
|
29
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
30
|
+
"""Compute survival time summary statistics."""
|
|
31
|
+
if dataset.type_of_target != 'survival':
|
|
32
|
+
return pd.DataFrame()
|
|
33
|
+
|
|
34
|
+
samples = Dataset.normalize_survival_target(dataset.y)
|
|
35
|
+
times = np.asarray([time for _, time in samples], dtype=float)
|
|
36
|
+
|
|
37
|
+
columns = ['time_min', 'time_median', 'time_max']
|
|
38
|
+
columns += [f"time_quantile_{quantile}" for quantile in self.quantiles]
|
|
39
|
+
|
|
40
|
+
if times.size:
|
|
41
|
+
time_min = float(np.min(times))
|
|
42
|
+
time_median = float(np.median(times))
|
|
43
|
+
time_max = float(np.max(times))
|
|
44
|
+
quantile_values = np.quantile(times, self.quantiles).astype(float).tolist()
|
|
45
|
+
else:
|
|
46
|
+
time_min = None
|
|
47
|
+
time_median = None
|
|
48
|
+
time_max = None
|
|
49
|
+
quantile_values = [None] * len(self.quantiles)
|
|
50
|
+
|
|
51
|
+
data = [[time_min, time_median, time_max] + quantile_values]
|
|
52
|
+
return pd.DataFrame(data, index=[str(self)], columns=columns)
|
|
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,68 @@
|
|
|
1
|
+
"""[STATISTIC] Top-K Value Counts."""
|
|
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 TopKValueCountsStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Top-K Value Counts."""
|
|
14
|
+
|
|
15
|
+
name: str = "Top-K Value Counts"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Top-k value counts list the most frequent categories and their shares.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Top-k value counts list the most frequent categories and their shares for
|
|
21
|
+
categorical columns, optionally per class.
|
|
22
|
+
""")
|
|
23
|
+
refs: list[dict] = []
|
|
24
|
+
|
|
25
|
+
def __init__(self, k: int = 5) -> None:
|
|
26
|
+
self.k = k
|
|
27
|
+
|
|
28
|
+
def __str__(self) -> str:
|
|
29
|
+
return f'top_{self.k}_value_counts'
|
|
30
|
+
|
|
31
|
+
def _top_k_counts(self, series: pd.Series) -> list[tuple[object, int, float]]:
|
|
32
|
+
counts = series.value_counts(dropna=True)
|
|
33
|
+
if counts.empty:
|
|
34
|
+
return []
|
|
35
|
+
top_counts = counts.head(self.k)
|
|
36
|
+
total = counts.sum()
|
|
37
|
+
return [(idx, int(val), float(val) / total) for idx, val in top_counts.items()]
|
|
38
|
+
|
|
39
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
40
|
+
"""Compute top-k value counts for categorical columns."""
|
|
41
|
+
if dataset.type_of_target == 'survival':
|
|
42
|
+
return pd.DataFrame()
|
|
43
|
+
|
|
44
|
+
data = []
|
|
45
|
+
columns = []
|
|
46
|
+
|
|
47
|
+
if dataset.type_of_target == 'continuous':
|
|
48
|
+
for col in dataset.X.columns:
|
|
49
|
+
if dataset.columns_types[col][1] == DataType.CATEGORICAL:
|
|
50
|
+
columns.append(col)
|
|
51
|
+
data.append(self._top_k_counts(dataset.X[col]))
|
|
52
|
+
return pd.DataFrame([data], index=[str(self)], columns=columns)
|
|
53
|
+
|
|
54
|
+
class_labels = list(pd.unique(dataset.y))
|
|
55
|
+
for col in dataset.X.columns:
|
|
56
|
+
if dataset.columns_types[col][1] == DataType.CATEGORICAL:
|
|
57
|
+
for label in ['all'] + class_labels:
|
|
58
|
+
columns.append(f"{col}_{label}")
|
|
59
|
+
if label == 'all':
|
|
60
|
+
values = dataset.X[col]
|
|
61
|
+
else:
|
|
62
|
+
values = dataset.X.loc[dataset.y == label][col]
|
|
63
|
+
data.append(self._top_k_counts(values))
|
|
64
|
+
return pd.DataFrame([data], index=[str(self)], columns=columns)
|
|
65
|
+
|
|
66
|
+
def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
|
|
67
|
+
"""Does this statistic apply to the dataset?"""
|
|
68
|
+
return dataset.type_of_target != 'survival'
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""[STATISTIC] Unique 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 UniqueCountStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Unique Count."""
|
|
14
|
+
|
|
15
|
+
name: str = "Unique Count"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Unique count measures the number of distinct non-null values per column.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Unique count measures the number of distinct non-null values per column,
|
|
21
|
+
optionally per class for classification.
|
|
22
|
+
""")
|
|
23
|
+
refs: list[dict] = []
|
|
24
|
+
|
|
25
|
+
def __str__(self) -> str:
|
|
26
|
+
return 'nunique'
|
|
27
|
+
|
|
28
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
29
|
+
"""Compute unique counts 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
|
+
data.append(dataset.X[col].nunique(dropna=True))
|
|
41
|
+
return pd.DataFrame([data], index=[str(self)], columns=columns)
|
|
42
|
+
|
|
43
|
+
class_labels = list(pd.unique(dataset.y))
|
|
44
|
+
for col in dataset.X.columns:
|
|
45
|
+
if dataset.columns_types[col][1] not in (DataType.TEXT, DataType.SHORT_TEXT):
|
|
46
|
+
for label in ['all'] + class_labels:
|
|
47
|
+
columns.append(f"{col}_{label}")
|
|
48
|
+
if label == 'all':
|
|
49
|
+
values = dataset.X[col]
|
|
50
|
+
else:
|
|
51
|
+
values = dataset.X.loc[dataset.y == label][col]
|
|
52
|
+
data.append(values.nunique(dropna=True))
|
|
53
|
+
return pd.DataFrame([data], index=[str(self)], columns=columns)
|
|
54
|
+
|
|
55
|
+
def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
|
|
56
|
+
"""Does this statistic apply to the dataset?"""
|
|
57
|
+
return dataset.type_of_target != 'survival'
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""[STATISTIC] Value counts."""
|
|
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 ValueCountsStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Value counts."""
|
|
14
|
+
|
|
15
|
+
name: str = "Value Counts"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Value counts measures value frequencies for categorical columns.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Value counts measures value frequencies for categorical columns, optionally per class.
|
|
21
|
+
""")
|
|
22
|
+
refs: list[dict] = []
|
|
23
|
+
|
|
24
|
+
def __str__(self) -> str:
|
|
25
|
+
return 'value_counts'
|
|
26
|
+
|
|
27
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
28
|
+
"""Compute value counts for categorical columns."""
|
|
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.CATEGORICAL:
|
|
40
|
+
counts = dataset.X[col].value_counts()
|
|
41
|
+
data.append(list((idx, val) for idx, val in counts.items()))
|
|
42
|
+
else:
|
|
43
|
+
data.append(None)
|
|
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 dataset.columns_types[col][1] == DataType.CATEGORICAL:
|
|
52
|
+
if label == 'all':
|
|
53
|
+
counts = dataset.X[col].value_counts()
|
|
54
|
+
else:
|
|
55
|
+
counts = dataset.X.loc[dataset.y == label][col].value_counts()
|
|
56
|
+
data.append(list((idx, val) for idx, val in counts.items()))
|
|
57
|
+
else:
|
|
58
|
+
data.append(None)
|
|
59
|
+
return pd.DataFrame([data], index=[str(self)], columns=columns)
|
|
60
|
+
|
|
61
|
+
def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
|
|
62
|
+
"""Does this statistic apply to the dataset?"""
|
|
63
|
+
return dataset.type_of_target != 'survival'
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""[STATISTIC] Variance."""
|
|
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 VarianceStatistic(Statistic):
|
|
13
|
+
"""[STATISTIC] Variance."""
|
|
14
|
+
|
|
15
|
+
name: str = "Variance"
|
|
16
|
+
_description: str = textwrap.dedent("""\
|
|
17
|
+
Variance measures unbiased variance for numerical columns.
|
|
18
|
+
""")
|
|
19
|
+
_description_long: str = textwrap.dedent("""\
|
|
20
|
+
Variance measures unbiased variance for numerical columns (normalized by N-1),
|
|
21
|
+
per class for classification.
|
|
22
|
+
""")
|
|
23
|
+
refs: list[dict] = []
|
|
24
|
+
|
|
25
|
+
def __str__(self) -> str:
|
|
26
|
+
return 'variance'
|
|
27
|
+
|
|
28
|
+
def compute(self, dataset: Dataset, **kwargs) -> pd.DataFrame:
|
|
29
|
+
"""Compute variance 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
|
+
data.append(dataset.X[col].var())
|
|
43
|
+
else:
|
|
44
|
+
data.append(dataset.X.loc[dataset.y == label][col].var())
|
|
45
|
+
else:
|
|
46
|
+
data.append(None)
|
|
47
|
+
return pd.DataFrame([data], index=[str(self)], columns=columns)
|
|
48
|
+
|
|
49
|
+
def suitable(self, dataset: Dataset) -> bool: # pylint: disable=unused-argument
|
|
50
|
+
"""Does this statistic apply to the dataset?"""
|
|
51
|
+
return dataset.type_of_target not in ['survival', 'continuous']
|