scitex 2.0.0__py2.py3-none-any.whl → 2.1.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- scitex/__init__.py +53 -15
- scitex/__main__.py +72 -26
- scitex/__version__.py +1 -1
- scitex/_sh.py +145 -23
- scitex/ai/__init__.py +30 -16
- scitex/ai/_gen_ai/_Anthropic.py +5 -7
- scitex/ai/_gen_ai/_BaseGenAI.py +2 -2
- scitex/ai/_gen_ai/_DeepSeek.py +10 -2
- scitex/ai/_gen_ai/_Google.py +2 -2
- scitex/ai/_gen_ai/_Llama.py +2 -2
- scitex/ai/_gen_ai/_OpenAI.py +2 -2
- scitex/ai/_gen_ai/_PARAMS.py +51 -65
- scitex/ai/_gen_ai/_Perplexity.py +2 -2
- scitex/ai/_gen_ai/__init__.py +25 -14
- scitex/ai/_gen_ai/_format_output_func.py +4 -4
- scitex/ai/classification/{classifier_server.py → Classifier.py} +5 -5
- scitex/ai/classification/CrossValidationExperiment.py +374 -0
- scitex/ai/classification/__init__.py +43 -4
- scitex/ai/classification/reporters/_BaseClassificationReporter.py +281 -0
- scitex/ai/classification/reporters/_ClassificationReporter.py +773 -0
- scitex/ai/classification/reporters/_MultiClassificationReporter.py +406 -0
- scitex/ai/classification/reporters/_SingleClassificationReporter.py +1834 -0
- scitex/ai/classification/reporters/__init__.py +11 -0
- scitex/ai/classification/reporters/reporter_utils/_Plotter.py +1028 -0
- scitex/ai/classification/reporters/reporter_utils/__init__.py +80 -0
- scitex/ai/classification/reporters/reporter_utils/aggregation.py +457 -0
- scitex/ai/classification/reporters/reporter_utils/data_models.py +313 -0
- scitex/ai/classification/reporters/reporter_utils/reporting.py +1056 -0
- scitex/ai/classification/reporters/reporter_utils/storage.py +221 -0
- scitex/ai/classification/reporters/reporter_utils/validation.py +395 -0
- scitex/ai/classification/timeseries/_TimeSeriesBlockingSplit.py +568 -0
- scitex/ai/classification/timeseries/_TimeSeriesCalendarSplit.py +688 -0
- scitex/ai/classification/timeseries/_TimeSeriesMetadata.py +139 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +1716 -0
- scitex/ai/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +1685 -0
- scitex/ai/classification/timeseries/_TimeSeriesStrategy.py +84 -0
- scitex/ai/classification/timeseries/_TimeSeriesStratifiedSplit.py +610 -0
- scitex/ai/classification/timeseries/__init__.py +39 -0
- scitex/ai/classification/timeseries/_normalize_timestamp.py +436 -0
- scitex/ai/clustering/_umap.py +2 -2
- scitex/ai/feature_extraction/vit.py +1 -0
- scitex/ai/feature_selection/__init__.py +30 -0
- scitex/ai/feature_selection/feature_selection.py +364 -0
- scitex/ai/loss/multi_task_loss.py +1 -1
- scitex/ai/metrics/__init__.py +51 -4
- scitex/ai/metrics/_calc_bacc.py +61 -0
- scitex/ai/metrics/_calc_bacc_from_conf_mat.py +38 -0
- scitex/ai/metrics/_calc_clf_report.py +78 -0
- scitex/ai/metrics/_calc_conf_mat.py +93 -0
- scitex/ai/metrics/_calc_feature_importance.py +183 -0
- scitex/ai/metrics/_calc_mcc.py +61 -0
- scitex/ai/metrics/_calc_pre_rec_auc.py +116 -0
- scitex/ai/metrics/_calc_roc_auc.py +110 -0
- scitex/ai/metrics/_calc_seizure_prediction_metrics.py +490 -0
- scitex/ai/metrics/{silhoute_score_block.py → _calc_silhouette_score.py} +15 -8
- scitex/ai/metrics/_normalize_labels.py +83 -0
- scitex/ai/plt/__init__.py +47 -8
- scitex/ai/plt/{_conf_mat.py → _plot_conf_mat.py} +158 -87
- scitex/ai/plt/_plot_feature_importance.py +323 -0
- scitex/ai/plt/_plot_learning_curve.py +345 -0
- scitex/ai/plt/_plot_optuna_study.py +225 -0
- scitex/ai/plt/_plot_pre_rec_curve.py +290 -0
- scitex/ai/plt/_plot_roc_curve.py +255 -0
- scitex/ai/training/{learning_curve_logger.py → _LearningCurveLogger.py} +197 -213
- scitex/ai/training/__init__.py +2 -2
- scitex/ai/utils/grid_search.py +3 -3
- scitex/benchmark/__init__.py +52 -0
- scitex/benchmark/benchmark.py +400 -0
- scitex/benchmark/monitor.py +370 -0
- scitex/benchmark/profiler.py +297 -0
- scitex/browser/__init__.py +48 -0
- scitex/browser/automation/CookieHandler.py +216 -0
- scitex/browser/automation/__init__.py +7 -0
- scitex/browser/collaboration/__init__.py +55 -0
- scitex/browser/collaboration/auth_helpers.py +94 -0
- scitex/browser/collaboration/collaborative_agent.py +136 -0
- scitex/browser/collaboration/credential_manager.py +188 -0
- scitex/browser/collaboration/interactive_panel.py +400 -0
- scitex/browser/collaboration/persistent_browser.py +170 -0
- scitex/browser/collaboration/shared_session.py +383 -0
- scitex/browser/collaboration/standard_interactions.py +246 -0
- scitex/browser/collaboration/visual_feedback.py +181 -0
- scitex/browser/core/BrowserMixin.py +326 -0
- scitex/browser/core/ChromeProfileManager.py +446 -0
- scitex/browser/core/__init__.py +9 -0
- scitex/browser/debugging/__init__.py +18 -0
- scitex/browser/debugging/_browser_logger.py +657 -0
- scitex/browser/debugging/_highlight_element.py +143 -0
- scitex/browser/debugging/_show_grid.py +154 -0
- scitex/browser/interaction/__init__.py +24 -0
- scitex/browser/interaction/click_center.py +149 -0
- scitex/browser/interaction/click_with_fallbacks.py +206 -0
- scitex/browser/interaction/close_popups.py +498 -0
- scitex/browser/interaction/fill_with_fallbacks.py +209 -0
- scitex/browser/pdf/__init__.py +14 -0
- scitex/browser/pdf/click_download_for_chrome_pdf_viewer.py +200 -0
- scitex/browser/pdf/detect_chrome_pdf_viewer.py +198 -0
- scitex/browser/remote/CaptchaHandler.py +434 -0
- scitex/browser/remote/ZenRowsAPIClient.py +347 -0
- scitex/browser/remote/ZenRowsBrowserManager.py +570 -0
- scitex/browser/remote/__init__.py +11 -0
- scitex/browser/stealth/HumanBehavior.py +344 -0
- scitex/browser/stealth/StealthManager.py +1008 -0
- scitex/browser/stealth/__init__.py +9 -0
- scitex/browser/template.py +122 -0
- scitex/capture/__init__.py +110 -0
- scitex/capture/__main__.py +25 -0
- scitex/capture/capture.py +848 -0
- scitex/capture/cli.py +233 -0
- scitex/capture/gif.py +344 -0
- scitex/capture/mcp_server.py +961 -0
- scitex/capture/session.py +70 -0
- scitex/capture/utils.py +705 -0
- scitex/cli/__init__.py +17 -0
- scitex/cli/cloud.py +447 -0
- scitex/cli/main.py +42 -0
- scitex/cli/scholar.py +280 -0
- scitex/context/_suppress_output.py +5 -3
- scitex/db/__init__.py +30 -3
- scitex/db/__main__.py +75 -0
- scitex/db/_check_health.py +381 -0
- scitex/db/_delete_duplicates.py +25 -386
- scitex/db/_inspect.py +335 -114
- scitex/db/_inspect_optimized.py +301 -0
- scitex/db/{_PostgreSQL.py → _postgresql/_PostgreSQL.py} +3 -3
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BackupMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BatchMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_BlobMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_ConnectionMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_MaintenanceMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_QueryMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_SchemaMixin.py +1 -1
- scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_TransactionMixin.py +1 -1
- scitex/db/_postgresql/__init__.py +6 -0
- scitex/db/_sqlite3/_SQLite3.py +210 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin.py +581 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ArrayMixin_v01-need-_hash-col.py +517 -0
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_BatchMixin.py +1 -1
- scitex/db/_sqlite3/_SQLite3Mixins/_BlobMixin.py +281 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin.py +548 -0
- scitex/db/_sqlite3/_SQLite3Mixins/_ColumnMixin_v01-indentation-issues.py +583 -0
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_ConnectionMixin.py +29 -13
- scitex/db/_sqlite3/_SQLite3Mixins/_GitMixin.py +583 -0
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_ImportExportMixin.py +1 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_IndexMixin.py +1 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_MaintenanceMixin.py +2 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_QueryMixin.py +37 -10
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_RowMixin.py +46 -6
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_TableMixin.py +56 -10
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/_TransactionMixin.py +1 -1
- scitex/db/{_SQLite3Mixins → _sqlite3/_SQLite3Mixins}/__init__.py +14 -2
- scitex/db/_sqlite3/__init__.py +7 -0
- scitex/db/_sqlite3/_delete_duplicates.py +274 -0
- scitex/decorators/__init__.py +2 -0
- scitex/decorators/_cache_disk.py +13 -5
- scitex/decorators/_cache_disk_async.py +49 -0
- scitex/decorators/_deprecated.py +175 -10
- scitex/decorators/_timeout.py +1 -1
- scitex/dev/_analyze_code_flow.py +2 -2
- scitex/dict/_DotDict.py +73 -15
- scitex/dict/_DotDict_v01-not-handling-recursive-instantiations.py +442 -0
- scitex/dict/_DotDict_v02-not-serializing-Path-object.py +446 -0
- scitex/dict/__init__.py +2 -0
- scitex/dict/_flatten.py +27 -0
- scitex/dsp/_crop.py +2 -2
- scitex/dsp/_demo_sig.py +2 -2
- scitex/dsp/_detect_ripples.py +2 -2
- scitex/dsp/_hilbert.py +2 -2
- scitex/dsp/_listen.py +6 -6
- scitex/dsp/_modulation_index.py +2 -2
- scitex/dsp/_pac.py +1 -1
- scitex/dsp/_psd.py +2 -2
- scitex/dsp/_resample.py +2 -1
- scitex/dsp/_time.py +3 -2
- scitex/dsp/_wavelet.py +3 -2
- scitex/dsp/add_noise.py +2 -2
- scitex/dsp/example.py +1 -0
- scitex/dsp/filt.py +10 -9
- scitex/dsp/template.py +3 -2
- scitex/dsp/utils/_differential_bandpass_filters.py +1 -1
- scitex/dsp/utils/pac.py +2 -2
- scitex/dt/_normalize_timestamp.py +432 -0
- scitex/errors.py +572 -0
- scitex/gen/_DimHandler.py +2 -2
- scitex/gen/__init__.py +37 -7
- scitex/gen/_deprecated_close.py +80 -0
- scitex/gen/_deprecated_start.py +26 -0
- scitex/gen/_detect_environment.py +152 -0
- scitex/gen/_detect_notebook_path.py +169 -0
- scitex/gen/_embed.py +6 -2
- scitex/gen/_get_notebook_path.py +257 -0
- scitex/gen/_less.py +1 -1
- scitex/gen/_list_packages.py +2 -2
- scitex/gen/_norm.py +44 -9
- scitex/gen/_norm_cache.py +269 -0
- scitex/gen/_src.py +3 -5
- scitex/gen/_title_case.py +3 -3
- scitex/io/__init__.py +28 -6
- scitex/io/_glob.py +13 -7
- scitex/io/_load.py +108 -21
- scitex/io/_load_cache.py +303 -0
- scitex/io/_load_configs.py +40 -15
- scitex/io/{_H5Explorer.py → _load_modules/_H5Explorer.py} +80 -17
- scitex/io/_load_modules/_ZarrExplorer.py +114 -0
- scitex/io/_load_modules/_bibtex.py +207 -0
- scitex/io/_load_modules/_hdf5.py +53 -178
- scitex/io/_load_modules/_json.py +5 -3
- scitex/io/_load_modules/_pdf.py +871 -16
- scitex/io/_load_modules/_sqlite3.py +15 -0
- scitex/io/_load_modules/_txt.py +41 -12
- scitex/io/_load_modules/_yaml.py +4 -3
- scitex/io/_load_modules/_zarr.py +126 -0
- scitex/io/_save.py +429 -171
- scitex/io/_save_modules/__init__.py +6 -0
- scitex/io/_save_modules/_bibtex.py +194 -0
- scitex/io/_save_modules/_csv.py +8 -4
- scitex/io/_save_modules/_excel.py +174 -15
- scitex/io/_save_modules/_hdf5.py +251 -226
- scitex/io/_save_modules/_image.py +1 -3
- scitex/io/_save_modules/_json.py +49 -4
- scitex/io/_save_modules/_listed_dfs_as_csv.py +1 -3
- scitex/io/_save_modules/_listed_scalars_as_csv.py +1 -3
- scitex/io/_save_modules/_tex.py +277 -0
- scitex/io/_save_modules/_yaml.py +42 -3
- scitex/io/_save_modules/_zarr.py +160 -0
- scitex/io/utils/__init__.py +20 -0
- scitex/io/utils/h5_to_zarr.py +616 -0
- scitex/linalg/_geometric_median.py +6 -2
- scitex/{gen/_tee.py → logging/_Tee.py} +43 -84
- scitex/logging/__init__.py +122 -0
- scitex/logging/_config.py +158 -0
- scitex/logging/_context.py +103 -0
- scitex/logging/_formatters.py +128 -0
- scitex/logging/_handlers.py +64 -0
- scitex/logging/_levels.py +35 -0
- scitex/logging/_logger.py +163 -0
- scitex/logging/_print_capture.py +95 -0
- scitex/ml/__init__.py +69 -0
- scitex/{ai/genai/anthropic.py → ml/_gen_ai/_Anthropic.py} +13 -19
- scitex/{ai/genai/base_genai.py → ml/_gen_ai/_BaseGenAI.py} +5 -5
- scitex/{ai/genai/deepseek.py → ml/_gen_ai/_DeepSeek.py} +11 -16
- scitex/{ai/genai/google.py → ml/_gen_ai/_Google.py} +7 -15
- scitex/{ai/genai/groq.py → ml/_gen_ai/_Groq.py} +1 -8
- scitex/{ai/genai/llama.py → ml/_gen_ai/_Llama.py} +3 -16
- scitex/{ai/genai/openai.py → ml/_gen_ai/_OpenAI.py} +3 -3
- scitex/{ai/genai/params.py → ml/_gen_ai/_PARAMS.py} +51 -65
- scitex/{ai/genai/perplexity.py → ml/_gen_ai/_Perplexity.py} +3 -14
- scitex/ml/_gen_ai/__init__.py +43 -0
- scitex/{ai/genai/calc_cost.py → ml/_gen_ai/_calc_cost.py} +1 -1
- scitex/{ai/genai/format_output_func.py → ml/_gen_ai/_format_output_func.py} +4 -4
- scitex/{ai/genai/genai_factory.py → ml/_gen_ai/_genai_factory.py} +8 -8
- scitex/ml/activation/__init__.py +8 -0
- scitex/ml/activation/_define.py +11 -0
- scitex/{ai/classifier_server.py → ml/classification/Classifier.py} +5 -5
- scitex/ml/classification/CrossValidationExperiment.py +374 -0
- scitex/ml/classification/__init__.py +46 -0
- scitex/ml/classification/reporters/_BaseClassificationReporter.py +281 -0
- scitex/ml/classification/reporters/_ClassificationReporter.py +773 -0
- scitex/ml/classification/reporters/_MultiClassificationReporter.py +406 -0
- scitex/ml/classification/reporters/_SingleClassificationReporter.py +1834 -0
- scitex/ml/classification/reporters/__init__.py +11 -0
- scitex/ml/classification/reporters/reporter_utils/_Plotter.py +1028 -0
- scitex/ml/classification/reporters/reporter_utils/__init__.py +80 -0
- scitex/ml/classification/reporters/reporter_utils/aggregation.py +457 -0
- scitex/ml/classification/reporters/reporter_utils/data_models.py +313 -0
- scitex/ml/classification/reporters/reporter_utils/reporting.py +1056 -0
- scitex/ml/classification/reporters/reporter_utils/storage.py +221 -0
- scitex/ml/classification/reporters/reporter_utils/validation.py +395 -0
- scitex/ml/classification/timeseries/_TimeSeriesBlockingSplit.py +568 -0
- scitex/ml/classification/timeseries/_TimeSeriesCalendarSplit.py +688 -0
- scitex/ml/classification/timeseries/_TimeSeriesMetadata.py +139 -0
- scitex/ml/classification/timeseries/_TimeSeriesSlidingWindowSplit.py +1716 -0
- scitex/ml/classification/timeseries/_TimeSeriesSlidingWindowSplit_v01-not-using-n_splits.py +1685 -0
- scitex/ml/classification/timeseries/_TimeSeriesStrategy.py +84 -0
- scitex/ml/classification/timeseries/_TimeSeriesStratifiedSplit.py +610 -0
- scitex/ml/classification/timeseries/__init__.py +39 -0
- scitex/ml/classification/timeseries/_normalize_timestamp.py +436 -0
- scitex/ml/clustering/__init__.py +11 -0
- scitex/ml/clustering/_pca.py +115 -0
- scitex/ml/clustering/_umap.py +376 -0
- scitex/ml/feature_extraction/__init__.py +56 -0
- scitex/ml/feature_extraction/vit.py +149 -0
- scitex/ml/feature_selection/__init__.py +30 -0
- scitex/ml/feature_selection/feature_selection.py +364 -0
- scitex/ml/loss/_L1L2Losses.py +34 -0
- scitex/ml/loss/__init__.py +12 -0
- scitex/ml/loss/multi_task_loss.py +47 -0
- scitex/ml/metrics/__init__.py +56 -0
- scitex/ml/metrics/_calc_bacc.py +61 -0
- scitex/ml/metrics/_calc_bacc_from_conf_mat.py +38 -0
- scitex/ml/metrics/_calc_clf_report.py +78 -0
- scitex/ml/metrics/_calc_conf_mat.py +93 -0
- scitex/ml/metrics/_calc_feature_importance.py +183 -0
- scitex/ml/metrics/_calc_mcc.py +61 -0
- scitex/ml/metrics/_calc_pre_rec_auc.py +116 -0
- scitex/ml/metrics/_calc_roc_auc.py +110 -0
- scitex/ml/metrics/_calc_seizure_prediction_metrics.py +490 -0
- scitex/ml/metrics/_calc_silhouette_score.py +503 -0
- scitex/ml/metrics/_normalize_labels.py +83 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/__init__.py +0 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/__init__.py +3 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger.py +207 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger2020.py +238 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/ranger913A.py +215 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/ranger/rangerqh.py +184 -0
- scitex/ml/optim/Ranger_Deep_Learning_Optimizer/setup.py +24 -0
- scitex/ml/optim/__init__.py +13 -0
- scitex/ml/optim/_get_set.py +31 -0
- scitex/ml/optim/_optimizers.py +71 -0
- scitex/ml/plt/__init__.py +60 -0
- scitex/ml/plt/_plot_conf_mat.py +663 -0
- scitex/ml/plt/_plot_feature_importance.py +323 -0
- scitex/ml/plt/_plot_learning_curve.py +345 -0
- scitex/ml/plt/_plot_optuna_study.py +225 -0
- scitex/ml/plt/_plot_pre_rec_curve.py +290 -0
- scitex/ml/plt/_plot_roc_curve.py +255 -0
- scitex/ml/sk/__init__.py +11 -0
- scitex/ml/sk/_clf.py +58 -0
- scitex/ml/sk/_to_sktime.py +100 -0
- scitex/ml/sklearn/__init__.py +26 -0
- scitex/ml/sklearn/clf.py +58 -0
- scitex/ml/sklearn/to_sktime.py +100 -0
- scitex/{ai/training/early_stopping.py → ml/training/_EarlyStopping.py} +1 -2
- scitex/{ai → ml/training}/_LearningCurveLogger.py +198 -242
- scitex/ml/training/__init__.py +7 -0
- scitex/ml/utils/__init__.py +22 -0
- scitex/ml/utils/_check_params.py +50 -0
- scitex/ml/utils/_default_dataset.py +46 -0
- scitex/ml/utils/_format_samples_for_sktime.py +26 -0
- scitex/ml/utils/_label_encoder.py +134 -0
- scitex/ml/utils/_merge_labels.py +22 -0
- scitex/ml/utils/_sliding_window_data_augmentation.py +11 -0
- scitex/ml/utils/_under_sample.py +51 -0
- scitex/ml/utils/_verify_n_gpus.py +16 -0
- scitex/ml/utils/grid_search.py +148 -0
- scitex/nn/_BNet.py +15 -9
- scitex/nn/_Filters.py +2 -2
- scitex/nn/_ModulationIndex.py +2 -2
- scitex/nn/_PAC.py +1 -1
- scitex/nn/_Spectrogram.py +12 -3
- scitex/nn/__init__.py +9 -10
- scitex/path/__init__.py +18 -0
- scitex/path/_clean.py +4 -0
- scitex/path/_find.py +9 -4
- scitex/path/_symlink.py +348 -0
- scitex/path/_version.py +4 -3
- scitex/pd/__init__.py +2 -0
- scitex/pd/_get_unique.py +99 -0
- scitex/plt/__init__.py +114 -5
- scitex/plt/_subplots/_AxesWrapper.py +1 -3
- scitex/plt/_subplots/_AxisWrapper.py +7 -3
- scitex/plt/_subplots/_AxisWrapperMixins/_AdjustmentMixin.py +47 -13
- scitex/plt/_subplots/_AxisWrapperMixins/_MatplotlibPlotMixin.py +160 -2
- scitex/plt/_subplots/_AxisWrapperMixins/_SeabornMixin.py +26 -4
- scitex/plt/_subplots/_AxisWrapperMixins/_UnitAwareMixin.py +322 -0
- scitex/plt/_subplots/_AxisWrapperMixins/__init__.py +1 -0
- scitex/plt/_subplots/_FigWrapper.py +62 -6
- scitex/plt/_subplots/_export_as_csv.py +43 -27
- scitex/plt/_subplots/_export_as_csv_formatters/__init__.py +5 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_annotate.py +81 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_bar.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_barh.py +20 -5
- scitex/plt/_subplots/_export_as_csv_formatters/_format_boxplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_contour.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_errorbar.py +35 -18
- scitex/plt/_subplots/_export_as_csv_formatters/_format_eventplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_fill.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_fill_between.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_hist.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_imshow2d.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot.py +15 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_box.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_conf_mat.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_ecdf.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_fillv.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_heatmap.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_image.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_joyplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_kde.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_line.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_mean_ci.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_mean_std.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_median_iqr.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_raster.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_rectangle.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter.py +35 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_scatter_hist.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_shaded_line.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_plot_violin.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_scatter.py +6 -4
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_barplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_boxplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_heatmap.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_histplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_jointplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_kdeplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_lineplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_pairplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_scatterplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_stripplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_swarmplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_sns_violinplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_text.py +60 -0
- scitex/plt/_subplots/_export_as_csv_formatters/_format_violin.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/_format_violinplot.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters/test_formatters.py +1 -3
- scitex/plt/_subplots/_export_as_csv_formatters.py +56 -59
- scitex/plt/ax/_style/_hide_spines.py +1 -3
- scitex/plt/ax/_style/_rotate_labels.py +180 -76
- scitex/plt/ax/_style/_rotate_labels_v01.py +248 -0
- scitex/plt/ax/_style/_set_meta.py +11 -4
- scitex/plt/ax/_style/_set_supxyt.py +3 -3
- scitex/plt/ax/_style/_set_xyt.py +3 -3
- scitex/plt/ax/_style/_share_axes.py +2 -2
- scitex/plt/color/__init__.py +4 -4
- scitex/plt/color/{_get_colors_from_cmap.py → _get_colors_from_conf_matap.py} +7 -7
- scitex/plt/utils/_configure_mpl.py +99 -86
- scitex/plt/utils/_histogram_utils.py +1 -3
- scitex/plt/utils/_is_valid_axis.py +1 -3
- scitex/plt/utils/_scitex_config.py +1 -0
- scitex/repro/__init__.py +75 -0
- scitex/{reproduce → repro}/_gen_ID.py +1 -1
- scitex/{reproduce → repro}/_gen_timestamp.py +1 -1
- scitex/repro_rng/_RandomStateManager.py +590 -0
- scitex/repro_rng/_RandomStateManager_v01-no-verbose-options.py +414 -0
- scitex/repro_rng/__init__.py +39 -0
- scitex/reproduce/__init__.py +25 -13
- scitex/reproduce/_hash_array.py +22 -0
- scitex/resource/_get_processor_usages.py +4 -4
- scitex/resource/_get_specs.py +2 -2
- scitex/resource/_log_processor_usages.py +2 -2
- scitex/rng/_RandomStateManager.py +590 -0
- scitex/rng/_RandomStateManager_v01-no-verbose-options.py +414 -0
- scitex/rng/__init__.py +39 -0
- scitex/scholar/__init__.py +309 -19
- scitex/scholar/__main__.py +319 -0
- scitex/scholar/auth/ScholarAuthManager.py +308 -0
- scitex/scholar/auth/__init__.py +12 -0
- scitex/scholar/auth/core/AuthenticationGateway.py +473 -0
- scitex/scholar/auth/core/BrowserAuthenticator.py +386 -0
- scitex/scholar/auth/core/StrategyResolver.py +309 -0
- scitex/scholar/auth/core/__init__.py +16 -0
- scitex/scholar/auth/gateway/_OpenURLLinkFinder.py +120 -0
- scitex/scholar/auth/gateway/_OpenURLResolver.py +209 -0
- scitex/scholar/auth/gateway/__init__.py +38 -0
- scitex/scholar/auth/gateway/_resolve_functions.py +101 -0
- scitex/scholar/auth/providers/BaseAuthenticator.py +166 -0
- scitex/scholar/auth/providers/EZProxyAuthenticator.py +484 -0
- scitex/scholar/auth/providers/OpenAthensAuthenticator.py +619 -0
- scitex/scholar/auth/providers/ShibbolethAuthenticator.py +686 -0
- scitex/scholar/auth/providers/__init__.py +18 -0
- scitex/scholar/auth/session/AuthCacheManager.py +189 -0
- scitex/scholar/auth/session/SessionManager.py +159 -0
- scitex/scholar/auth/session/__init__.py +11 -0
- scitex/scholar/auth/sso/BaseSSOAutomator.py +373 -0
- scitex/scholar/auth/sso/OpenAthensSSOAutomator.py +378 -0
- scitex/scholar/auth/sso/SSOAutomator.py +180 -0
- scitex/scholar/auth/sso/UniversityOfMelbourneSSOAutomator.py +380 -0
- scitex/scholar/auth/sso/__init__.py +15 -0
- scitex/scholar/browser/ScholarBrowserManager.py +705 -0
- scitex/scholar/browser/__init__.py +38 -0
- scitex/scholar/browser/utils/__init__.py +13 -0
- scitex/scholar/browser/utils/click_and_wait.py +205 -0
- scitex/scholar/browser/utils/close_unwanted_pages.py +140 -0
- scitex/scholar/browser/utils/wait_redirects.py +732 -0
- scitex/scholar/config/PublisherRules.py +132 -0
- scitex/scholar/config/ScholarConfig.py +126 -0
- scitex/scholar/config/__init__.py +17 -0
- scitex/scholar/core/Paper.py +627 -0
- scitex/scholar/core/Papers.py +722 -0
- scitex/scholar/core/Scholar.py +1975 -0
- scitex/scholar/core/__init__.py +9 -0
- scitex/scholar/impact_factor/ImpactFactorEngine.py +204 -0
- scitex/scholar/impact_factor/__init__.py +20 -0
- scitex/scholar/impact_factor/estimation/ImpactFactorEstimationEngine.py +0 -0
- scitex/scholar/impact_factor/estimation/__init__.py +40 -0
- scitex/scholar/impact_factor/estimation/build_database.py +0 -0
- scitex/scholar/impact_factor/estimation/core/__init__.py +28 -0
- scitex/scholar/impact_factor/estimation/core/cache_manager.py +523 -0
- scitex/scholar/impact_factor/estimation/core/calculator.py +355 -0
- scitex/scholar/impact_factor/estimation/core/journal_matcher.py +428 -0
- scitex/scholar/integration/__init__.py +59 -0
- scitex/scholar/integration/base.py +502 -0
- scitex/scholar/integration/mendeley/__init__.py +22 -0
- scitex/scholar/integration/mendeley/exporter.py +166 -0
- scitex/scholar/integration/mendeley/importer.py +236 -0
- scitex/scholar/integration/mendeley/linker.py +79 -0
- scitex/scholar/integration/mendeley/mapper.py +212 -0
- scitex/scholar/integration/zotero/__init__.py +27 -0
- scitex/scholar/integration/zotero/__main__.py +264 -0
- scitex/scholar/integration/zotero/exporter.py +351 -0
- scitex/scholar/integration/zotero/importer.py +372 -0
- scitex/scholar/integration/zotero/linker.py +415 -0
- scitex/scholar/integration/zotero/mapper.py +286 -0
- scitex/scholar/metadata_engines/ScholarEngine.py +588 -0
- scitex/scholar/metadata_engines/__init__.py +21 -0
- scitex/scholar/metadata_engines/individual/ArXivEngine.py +397 -0
- scitex/scholar/metadata_engines/individual/CrossRefEngine.py +274 -0
- scitex/scholar/metadata_engines/individual/CrossRefLocalEngine.py +263 -0
- scitex/scholar/metadata_engines/individual/OpenAlexEngine.py +350 -0
- scitex/scholar/metadata_engines/individual/PubMedEngine.py +329 -0
- scitex/scholar/metadata_engines/individual/SemanticScholarEngine.py +438 -0
- scitex/scholar/metadata_engines/individual/URLDOIEngine.py +410 -0
- scitex/scholar/metadata_engines/individual/_BaseDOIEngine.py +487 -0
- scitex/scholar/metadata_engines/individual/__init__.py +7 -0
- scitex/scholar/metadata_engines/utils/_PubMedConverter.py +469 -0
- scitex/scholar/metadata_engines/utils/_URLDOIExtractor.py +283 -0
- scitex/scholar/metadata_engines/utils/__init__.py +30 -0
- scitex/scholar/metadata_engines/utils/_metadata2bibtex.py +103 -0
- scitex/scholar/metadata_engines/utils/_standardize_metadata.py +376 -0
- scitex/scholar/pdf_download/ScholarPDFDownloader.py +579 -0
- scitex/scholar/pdf_download/__init__.py +5 -0
- scitex/scholar/pdf_download/strategies/__init__.py +38 -0
- scitex/scholar/pdf_download/strategies/chrome_pdf_viewer.py +376 -0
- scitex/scholar/pdf_download/strategies/direct_download.py +131 -0
- scitex/scholar/pdf_download/strategies/manual_download_fallback.py +167 -0
- scitex/scholar/pdf_download/strategies/manual_download_utils.py +996 -0
- scitex/scholar/pdf_download/strategies/response_body.py +207 -0
- scitex/scholar/pipelines/ScholarPipelineBibTeX.py +364 -0
- scitex/scholar/pipelines/ScholarPipelineParallel.py +478 -0
- scitex/scholar/pipelines/ScholarPipelineSingle.py +767 -0
- scitex/scholar/pipelines/__init__.py +49 -0
- scitex/scholar/storage/BibTeXHandler.py +1018 -0
- scitex/scholar/storage/PaperIO.py +468 -0
- scitex/scholar/storage/ScholarLibrary.py +182 -0
- scitex/scholar/storage/_DeduplicationManager.py +548 -0
- scitex/scholar/storage/_LibraryCacheManager.py +724 -0
- scitex/scholar/storage/_LibraryManager.py +1835 -0
- scitex/scholar/storage/__init__.py +28 -0
- scitex/scholar/url_finder/ScholarURLFinder.py +379 -0
- scitex/scholar/url_finder/__init__.py +7 -0
- scitex/scholar/url_finder/strategies/__init__.py +33 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_direct_links.py +261 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_dropdown.py +67 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_href.py +204 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_navigation.py +256 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_publisher_patterns.py +165 -0
- scitex/scholar/url_finder/strategies/find_pdf_urls_by_zotero_translators.py +163 -0
- scitex/scholar/url_finder/strategies/find_supplementary_urls_by_href.py +70 -0
- scitex/scholar/utils/__init__.py +22 -0
- scitex/scholar/utils/bibtex/__init__.py +9 -0
- scitex/scholar/utils/bibtex/_parse_bibtex.py +71 -0
- scitex/scholar/utils/cleanup/__init__.py +8 -0
- scitex/scholar/utils/cleanup/_cleanup_scholar_processes.py +96 -0
- scitex/scholar/utils/cleanup/cleanup_old_extractions.py +117 -0
- scitex/scholar/utils/text/_TextNormalizer.py +407 -0
- scitex/scholar/utils/text/__init__.py +9 -0
- scitex/scholar/zotero/__init__.py +38 -0
- scitex/session/__init__.py +51 -0
- scitex/session/_lifecycle.py +736 -0
- scitex/session/_manager.py +102 -0
- scitex/session/template.py +122 -0
- scitex/stats/__init__.py +30 -26
- scitex/stats/correct/__init__.py +21 -0
- scitex/stats/correct/_correct_bonferroni.py +551 -0
- scitex/stats/correct/_correct_fdr.py +634 -0
- scitex/stats/correct/_correct_holm.py +548 -0
- scitex/stats/correct/_correct_sidak.py +499 -0
- scitex/stats/descriptive/__init__.py +85 -0
- scitex/stats/descriptive/_circular.py +540 -0
- scitex/stats/descriptive/_describe.py +219 -0
- scitex/stats/descriptive/_nan.py +518 -0
- scitex/stats/descriptive/_real.py +189 -0
- scitex/stats/effect_sizes/__init__.py +41 -0
- scitex/stats/effect_sizes/_cliffs_delta.py +325 -0
- scitex/stats/effect_sizes/_cohens_d.py +342 -0
- scitex/stats/effect_sizes/_epsilon_squared.py +315 -0
- scitex/stats/effect_sizes/_eta_squared.py +302 -0
- scitex/stats/effect_sizes/_prob_superiority.py +296 -0
- scitex/stats/posthoc/__init__.py +19 -0
- scitex/stats/posthoc/_dunnett.py +463 -0
- scitex/stats/posthoc/_games_howell.py +383 -0
- scitex/stats/posthoc/_tukey_hsd.py +367 -0
- scitex/stats/power/__init__.py +19 -0
- scitex/stats/power/_power.py +433 -0
- scitex/stats/template.py +119 -0
- scitex/stats/utils/__init__.py +62 -0
- scitex/stats/utils/_effect_size.py +985 -0
- scitex/stats/utils/_formatters.py +270 -0
- scitex/stats/utils/_normalizers.py +927 -0
- scitex/stats/utils/_power.py +433 -0
- scitex/stats_v01/_EffectSizeCalculator.py +488 -0
- scitex/stats_v01/_StatisticalValidator.py +411 -0
- scitex/stats_v01/__init__.py +60 -0
- scitex/stats_v01/_additional_tests.py +415 -0
- scitex/{stats → stats_v01}/_p2stars.py +19 -5
- scitex/stats_v01/_two_sample_tests.py +141 -0
- scitex/stats_v01/desc/__init__.py +83 -0
- scitex/stats_v01/desc/_circular.py +540 -0
- scitex/stats_v01/desc/_describe.py +219 -0
- scitex/stats_v01/desc/_nan.py +518 -0
- scitex/{stats/desc/_nan.py → stats_v01/desc/_nan_v01-20250920_145731.py} +23 -12
- scitex/stats_v01/desc/_real.py +189 -0
- scitex/stats_v01/tests/__corr_test_optimized.py +221 -0
- scitex/stats_v01/tests/_corr_test_optimized.py +179 -0
- scitex/str/__init__.py +1 -3
- scitex/str/_clean_path.py +6 -2
- scitex/str/_latex_fallback.py +267 -160
- scitex/str/_parse.py +44 -36
- scitex/str/_printc.py +1 -3
- scitex/template/__init__.py +87 -0
- scitex/template/_create_project.py +267 -0
- scitex/template/create_pip_project.py +80 -0
- scitex/template/create_research.py +80 -0
- scitex/template/create_singularity.py +80 -0
- scitex/units.py +291 -0
- scitex/utils/_compress_hdf5.py +14 -3
- scitex/utils/_email.py +21 -2
- scitex/utils/_grid.py +6 -4
- scitex/utils/_notify.py +13 -10
- scitex/utils/_verify_scitex_format.py +589 -0
- scitex/utils/_verify_scitex_format_v01.py +370 -0
- scitex/utils/template.py +122 -0
- scitex/web/_search_pubmed.py +62 -16
- scitex-2.1.0.dist-info/LICENSE +21 -0
- scitex-2.1.0.dist-info/METADATA +677 -0
- scitex-2.1.0.dist-info/RECORD +919 -0
- {scitex-2.0.0.dist-info → scitex-2.1.0.dist-info}/WHEEL +1 -1
- scitex-2.1.0.dist-info/entry_points.txt +3 -0
- scitex/ai/__Classifiers.py +0 -101
- scitex/ai/classification/classification_reporter.py +0 -1137
- scitex/ai/classification/classifiers.py +0 -101
- scitex/ai/classification_reporter.py +0 -1161
- scitex/ai/genai/__init__.py +0 -277
- scitex/ai/genai/anthropic_provider.py +0 -320
- scitex/ai/genai/anthropic_refactored.py +0 -109
- scitex/ai/genai/auth_manager.py +0 -200
- scitex/ai/genai/base_provider.py +0 -291
- scitex/ai/genai/chat_history.py +0 -307
- scitex/ai/genai/cost_tracker.py +0 -276
- scitex/ai/genai/deepseek_provider.py +0 -251
- scitex/ai/genai/google_provider.py +0 -228
- scitex/ai/genai/groq_provider.py +0 -248
- scitex/ai/genai/image_processor.py +0 -250
- scitex/ai/genai/llama_provider.py +0 -214
- scitex/ai/genai/mock_provider.py +0 -127
- scitex/ai/genai/model_registry.py +0 -304
- scitex/ai/genai/openai_provider.py +0 -293
- scitex/ai/genai/perplexity_provider.py +0 -205
- scitex/ai/genai/provider_base.py +0 -302
- scitex/ai/genai/provider_factory.py +0 -370
- scitex/ai/genai/response_handler.py +0 -235
- scitex/ai/layer/_Pass.py +0 -21
- scitex/ai/layer/__init__.py +0 -10
- scitex/ai/layer/_switch.py +0 -8
- scitex/ai/metrics/_bACC.py +0 -51
- scitex/ai/plt/_learning_curve.py +0 -194
- scitex/ai/plt/_optuna_study.py +0 -111
- scitex/ai/plt/aucs/__init__.py +0 -2
- scitex/ai/plt/aucs/example.py +0 -60
- scitex/ai/plt/aucs/pre_rec_auc.py +0 -223
- scitex/ai/plt/aucs/roc_auc.py +0 -246
- scitex/ai/sampling/undersample.py +0 -29
- scitex/db/_SQLite3.py +0 -2136
- scitex/db/_SQLite3Mixins/_BlobMixin.py +0 -229
- scitex/gen/_close.py +0 -222
- scitex/gen/_start.py +0 -451
- scitex/general/__init__.py +0 -5
- scitex/io/_load_modules/_db.py +0 -24
- scitex/life/__init__.py +0 -10
- scitex/life/_monitor_rain.py +0 -49
- scitex/reproduce/_fix_seeds.py +0 -45
- scitex/res/__init__.py +0 -5
- scitex/scholar/_local_search.py +0 -454
- scitex/scholar/_paper.py +0 -244
- scitex/scholar/_pdf_downloader.py +0 -325
- scitex/scholar/_search.py +0 -393
- scitex/scholar/_vector_search.py +0 -370
- scitex/scholar/_web_sources.py +0 -457
- scitex/stats/desc/__init__.py +0 -40
- scitex-2.0.0.dist-info/METADATA +0 -307
- scitex-2.0.0.dist-info/RECORD +0 -572
- scitex-2.0.0.dist-info/licenses/LICENSE +0 -7
- /scitex/ai/{act → activation}/__init__.py +0 -0
- /scitex/ai/{act → activation}/_define.py +0 -0
- /scitex/ai/{early_stopping.py → training/_EarlyStopping.py} +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_ImportExportMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_IndexMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_RowMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/_TableMixin.py +0 -0
- /scitex/db/{_PostgreSQLMixins → _postgresql/_PostgreSQLMixins}/__init__.py +0 -0
- /scitex/{stats → stats_v01}/_calc_partial_corr.py +0 -0
- /scitex/{stats → stats_v01}/_corr_test_multi.py +0 -0
- /scitex/{stats → stats_v01}/_corr_test_wrapper.py +0 -0
- /scitex/{stats → stats_v01}/_describe_wrapper.py +0 -0
- /scitex/{stats → stats_v01}/_multiple_corrections.py +0 -0
- /scitex/{stats → stats_v01}/_nan_stats.py +0 -0
- /scitex/{stats → stats_v01}/_p2stars_wrapper.py +0 -0
- /scitex/{stats → stats_v01}/_statistical_tests.py +0 -0
- /scitex/{stats/desc/_describe.py → stats_v01/desc/_describe_v01-20250920_145731.py} +0 -0
- /scitex/{stats/desc/_real.py → stats_v01/desc/_real_v01-20250920_145731.py} +0 -0
- /scitex/{stats → stats_v01}/multiple/__init__.py +0 -0
- /scitex/{stats → stats_v01}/multiple/_bonferroni_correction.py +0 -0
- /scitex/{stats → stats_v01}/multiple/_fdr_correction.py +0 -0
- /scitex/{stats → stats_v01}/multiple/_multicompair.py +0 -0
- /scitex/{stats → stats_v01}/tests/__corr_test.py +0 -0
- /scitex/{stats → stats_v01}/tests/__corr_test_multi.py +0 -0
- /scitex/{stats → stats_v01}/tests/__corr_test_single.py +0 -0
- /scitex/{stats → stats_v01}/tests/__init__.py +0 -0
- /scitex/{stats → stats_v01}/tests/_brunner_munzel_test.py +0 -0
- /scitex/{stats → stats_v01}/tests/_nocorrelation_test.py +0 -0
- /scitex/{stats → stats_v01}/tests/_smirnov_grubbs.py +0 -0
- {scitex-2.0.0.dist-info → scitex-2.1.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,773 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-10-02 06:38:58 (ywatanabe)"
|
|
4
|
+
# File: /ssh:sp:/home/ywatanabe/proj/scitex_repo/src/scitex/ml/classification/reporters/_ClassificationReporter.py
|
|
5
|
+
# ----------------------------------------
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
import os
|
|
8
|
+
__FILE__ = __file__
|
|
9
|
+
__DIR__ = os.path.dirname(__FILE__)
|
|
10
|
+
# ----------------------------------------
|
|
11
|
+
|
|
12
|
+
"""
|
|
13
|
+
Unified Classification Reporter.
|
|
14
|
+
|
|
15
|
+
A single, unified reporter that handles both single-task and multi-task
|
|
16
|
+
classification scenarios seamlessly.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from typing import Any, Dict, List, Optional, Union
|
|
21
|
+
|
|
22
|
+
import numpy as np
|
|
23
|
+
|
|
24
|
+
# Import base class and single reporter for internal use
|
|
25
|
+
from ._BaseClassificationReporter import (BaseClassificationReporter,
|
|
26
|
+
ReporterConfig)
|
|
27
|
+
from ._SingleClassificationReporter import SingleTaskClassificationReporter
|
|
28
|
+
from .reporter_utils.storage import MetricStorage
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class ClassificationReporter(BaseClassificationReporter):
|
|
32
|
+
"""
|
|
33
|
+
Unified classification reporter for single and multi-task scenarios.
|
|
34
|
+
|
|
35
|
+
This reporter automatically adapts to your use case:
|
|
36
|
+
- Single task: Just use it without specifying tasks
|
|
37
|
+
- Multiple tasks: Specify tasks upfront or create them dynamically
|
|
38
|
+
- Seamless switching between single and multi-task workflows
|
|
39
|
+
|
|
40
|
+
Features:
|
|
41
|
+
- Comprehensive metrics calculation (balanced accuracy, MCC, ROC-AUC, PR-AUC, etc.)
|
|
42
|
+
- Automated visualization generation:
|
|
43
|
+
* Confusion matrices
|
|
44
|
+
* ROC and Precision-Recall curves
|
|
45
|
+
* Feature importance plots (via plotter)
|
|
46
|
+
* CV aggregation plots with faded fold lines
|
|
47
|
+
* Comprehensive metrics dashboard
|
|
48
|
+
- Multi-format report generation (Org, Markdown, LaTeX, HTML, DOCX, PDF)
|
|
49
|
+
- Cross-validation support with automatic fold aggregation
|
|
50
|
+
- Multi-task classification tracking
|
|
51
|
+
|
|
52
|
+
Parameters
|
|
53
|
+
----------
|
|
54
|
+
output_dir : Union[str, Path]
|
|
55
|
+
Base directory for outputs. If None, creates timestamped directory.
|
|
56
|
+
tasks : List[str], optional
|
|
57
|
+
List of task names. If None, tasks are created dynamically as needed.
|
|
58
|
+
precision : int, default 3
|
|
59
|
+
Number of decimal places for numerical outputs
|
|
60
|
+
required_metrics : List[str], optional
|
|
61
|
+
List of metrics to calculate. Defaults to comprehensive set.
|
|
62
|
+
verbose : bool, default True
|
|
63
|
+
Whether to print initialization messages
|
|
64
|
+
**kwargs
|
|
65
|
+
Additional arguments passed to base class
|
|
66
|
+
|
|
67
|
+
Examples
|
|
68
|
+
--------
|
|
69
|
+
>>> # Single task usage (no tasks specified)
|
|
70
|
+
>>> reporter = ClassificationReporter("./results")
|
|
71
|
+
>>> reporter.calculate_metrics(y_true, y_pred, y_proba)
|
|
72
|
+
|
|
73
|
+
>>> # Multi-task with predefined tasks
|
|
74
|
+
>>> reporter = ClassificationReporter("./results", tasks=["binary", "multiclass"])
|
|
75
|
+
>>> reporter.calculate_metrics(y_true, y_pred, task="binary")
|
|
76
|
+
|
|
77
|
+
>>> # Dynamic task creation
|
|
78
|
+
>>> reporter = ClassificationReporter("./results")
|
|
79
|
+
>>> reporter.calculate_metrics(y_true1, y_pred1, task="task1")
|
|
80
|
+
>>> reporter.calculate_metrics(y_true2, y_pred2, task="task2")
|
|
81
|
+
|
|
82
|
+
>>> # Feature importance visualization (via plotter)
|
|
83
|
+
>>> reporter._single_reporter.plotter.create_feature_importance_plot(
|
|
84
|
+
... feature_importance=importances,
|
|
85
|
+
... feature_names=feature_names,
|
|
86
|
+
... save_path="./results/feature_importance.png"
|
|
87
|
+
... )
|
|
88
|
+
|
|
89
|
+
>>> # CV aggregation plots (automatically created on save_summary)
|
|
90
|
+
>>> for fold in range(5):
|
|
91
|
+
... metrics = reporter.calculate_metrics(y_true, y_pred, y_proba, fold=fold)
|
|
92
|
+
>>> reporter.save_summary() # Creates CV aggregation plots with faded fold lines
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
def __init__(
|
|
96
|
+
self,
|
|
97
|
+
output_dir: Union[str, Path],
|
|
98
|
+
tasks: Optional[List[str]] = None,
|
|
99
|
+
precision: int = 3,
|
|
100
|
+
required_metrics: Optional[List[str]] = [
|
|
101
|
+
"balanced_accuracy",
|
|
102
|
+
"mcc",
|
|
103
|
+
"confusion_matrix",
|
|
104
|
+
"classification_report",
|
|
105
|
+
"roc_auc",
|
|
106
|
+
"roc_curve",
|
|
107
|
+
"pre_rec_auc",
|
|
108
|
+
"pre_rec_curve",
|
|
109
|
+
],
|
|
110
|
+
verbose: bool = True,
|
|
111
|
+
**kwargs,
|
|
112
|
+
):
|
|
113
|
+
# Set default metrics if not provided
|
|
114
|
+
if required_metrics is None:
|
|
115
|
+
required_metrics = [
|
|
116
|
+
"balanced_accuracy",
|
|
117
|
+
"mcc",
|
|
118
|
+
"confusion_matrix",
|
|
119
|
+
"classification_report",
|
|
120
|
+
"roc_auc",
|
|
121
|
+
"roc_curve",
|
|
122
|
+
"pre_rec_auc",
|
|
123
|
+
"pre_rec_curve",
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
# Create internal config from parameters
|
|
127
|
+
self.config = ReporterConfig(
|
|
128
|
+
precision=precision, required_metrics=required_metrics
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Initialize base class
|
|
132
|
+
super().__init__(output_dir=output_dir, precision=precision, **kwargs)
|
|
133
|
+
|
|
134
|
+
self.precision = precision
|
|
135
|
+
self.required_metrics = required_metrics
|
|
136
|
+
self.storage = MetricStorage(self.output_dir, precision=self.precision)
|
|
137
|
+
|
|
138
|
+
# Setup tasks
|
|
139
|
+
self.tasks = tasks if tasks is not None else []
|
|
140
|
+
self.verbose = verbose
|
|
141
|
+
|
|
142
|
+
# Create individual reporters for each task
|
|
143
|
+
self.reporters: Dict[str, SingleTaskClassificationReporter] = {}
|
|
144
|
+
|
|
145
|
+
# Single mode: Create a single reporter at the root level
|
|
146
|
+
# Multi mode: Create reporters in subdirectories
|
|
147
|
+
if not self.tasks:
|
|
148
|
+
# Single-task mode - use output_dir directly
|
|
149
|
+
self._single_reporter = SingleTaskClassificationReporter(
|
|
150
|
+
output_dir=self.output_dir, config=self.config, verbose=False
|
|
151
|
+
)
|
|
152
|
+
else:
|
|
153
|
+
# Multi-task mode - create subdirectories
|
|
154
|
+
self._single_reporter = None
|
|
155
|
+
self._setup_task_reporters()
|
|
156
|
+
|
|
157
|
+
# Save configuration
|
|
158
|
+
self._save_config()
|
|
159
|
+
|
|
160
|
+
# Print initialization info if verbose
|
|
161
|
+
if self.verbose and self.tasks:
|
|
162
|
+
print(f"\n{'='*70}")
|
|
163
|
+
print(f"Classification Reporter Initialized")
|
|
164
|
+
print(f"{'='*70}")
|
|
165
|
+
print(f"Output Directory: {self.output_dir.absolute()}")
|
|
166
|
+
print(f"Tasks: {self.tasks}")
|
|
167
|
+
print(f"{'='*70}\n")
|
|
168
|
+
|
|
169
|
+
def _create_single_reporter(self, task: str) -> None:
|
|
170
|
+
"""Create a single task reporter."""
|
|
171
|
+
task_output_dir = self.output_dir / task
|
|
172
|
+
self.reporters[task] = SingleTaskClassificationReporter(
|
|
173
|
+
output_dir=task_output_dir,
|
|
174
|
+
config=self.config,
|
|
175
|
+
verbose=False, # Suppress individual reporter messages
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
def _setup_task_reporters(self) -> None:
|
|
179
|
+
"""Setup individual reporters for each task."""
|
|
180
|
+
for task in self.tasks:
|
|
181
|
+
self._create_single_reporter(task)
|
|
182
|
+
|
|
183
|
+
def calculate_metrics(
|
|
184
|
+
self,
|
|
185
|
+
y_true: np.ndarray,
|
|
186
|
+
y_pred: np.ndarray,
|
|
187
|
+
y_proba: Optional[np.ndarray] = None,
|
|
188
|
+
labels: Optional[List[str]] = None,
|
|
189
|
+
fold: Optional[int] = None,
|
|
190
|
+
task: Optional[str] = None,
|
|
191
|
+
verbose: bool = True,
|
|
192
|
+
model=None,
|
|
193
|
+
feature_names: Optional[List[str]] = None,
|
|
194
|
+
) -> Dict[str, Any]:
|
|
195
|
+
"""
|
|
196
|
+
Calculate metrics for classification.
|
|
197
|
+
|
|
198
|
+
Automatically handles single vs multi-task scenarios:
|
|
199
|
+
- If no task specified and no tasks defined: creates "default" task
|
|
200
|
+
- If no task specified but tasks exist: uses first task
|
|
201
|
+
- If task specified: uses/creates that specific task
|
|
202
|
+
|
|
203
|
+
Parameters
|
|
204
|
+
----------
|
|
205
|
+
y_true : np.ndarray
|
|
206
|
+
True class labels
|
|
207
|
+
y_pred : np.ndarray
|
|
208
|
+
Predicted class labels
|
|
209
|
+
y_proba : np.ndarray, optional
|
|
210
|
+
Prediction probabilities (required for AUC metrics)
|
|
211
|
+
labels : List[str], optional
|
|
212
|
+
Class labels for display
|
|
213
|
+
fold : int, optional
|
|
214
|
+
Fold index for cross-validation
|
|
215
|
+
task : str, optional
|
|
216
|
+
Task identifier. If None and no tasks exist, creates "default" task.
|
|
217
|
+
verbose : bool, default True
|
|
218
|
+
Whether to print progress
|
|
219
|
+
model : object, optional
|
|
220
|
+
Trained model for automatic feature importance extraction
|
|
221
|
+
feature_names : List[str], optional
|
|
222
|
+
Feature names for feature importance (required if model is provided)
|
|
223
|
+
|
|
224
|
+
Returns
|
|
225
|
+
-------
|
|
226
|
+
Dict[str, Any]
|
|
227
|
+
Dictionary of calculated metrics
|
|
228
|
+
"""
|
|
229
|
+
# Single-task mode (tasks=None)
|
|
230
|
+
if not self.tasks and self._single_reporter:
|
|
231
|
+
if task is not None:
|
|
232
|
+
# Convert to multi-task mode on the fly
|
|
233
|
+
self.tasks = [task]
|
|
234
|
+
self._single_reporter = None
|
|
235
|
+
self._create_single_reporter(task)
|
|
236
|
+
return self.reporters[task].calculate_metrics(
|
|
237
|
+
y_true=y_true,
|
|
238
|
+
y_pred=y_pred,
|
|
239
|
+
y_proba=y_proba,
|
|
240
|
+
labels=labels,
|
|
241
|
+
fold=fold,
|
|
242
|
+
verbose=verbose,
|
|
243
|
+
model=model,
|
|
244
|
+
feature_names=feature_names,
|
|
245
|
+
)
|
|
246
|
+
else:
|
|
247
|
+
# Stay in single-task mode
|
|
248
|
+
return self._single_reporter.calculate_metrics(
|
|
249
|
+
y_true=y_true,
|
|
250
|
+
y_pred=y_pred,
|
|
251
|
+
y_proba=y_proba,
|
|
252
|
+
labels=labels,
|
|
253
|
+
fold=fold,
|
|
254
|
+
verbose=verbose,
|
|
255
|
+
model=model,
|
|
256
|
+
feature_names=feature_names,
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Multi-task mode
|
|
260
|
+
if task is None:
|
|
261
|
+
# Use first available task
|
|
262
|
+
task = self.tasks[0]
|
|
263
|
+
else:
|
|
264
|
+
# Task explicitly specified - create if doesn't exist
|
|
265
|
+
if task not in self.reporters:
|
|
266
|
+
if task not in self.tasks:
|
|
267
|
+
self.tasks.append(task)
|
|
268
|
+
self._create_single_reporter(task)
|
|
269
|
+
|
|
270
|
+
# Delegate to task-specific reporter
|
|
271
|
+
return self.reporters[task].calculate_metrics(
|
|
272
|
+
y_true=y_true,
|
|
273
|
+
y_pred=y_pred,
|
|
274
|
+
y_proba=y_proba,
|
|
275
|
+
labels=labels,
|
|
276
|
+
fold=fold,
|
|
277
|
+
verbose=verbose,
|
|
278
|
+
model=model,
|
|
279
|
+
feature_names=feature_names,
|
|
280
|
+
)
|
|
281
|
+
|
|
282
|
+
def save(
|
|
283
|
+
self,
|
|
284
|
+
data: Any,
|
|
285
|
+
relative_path: Union[str, Path],
|
|
286
|
+
task: Optional[str] = None,
|
|
287
|
+
fold: Optional[int] = None,
|
|
288
|
+
) -> Path:
|
|
289
|
+
"""
|
|
290
|
+
Save custom data with automatic task/fold organization.
|
|
291
|
+
|
|
292
|
+
Parameters
|
|
293
|
+
----------
|
|
294
|
+
data : Any
|
|
295
|
+
Data to save (any format supported by stx.io.save)
|
|
296
|
+
relative_path : Union[str, Path]
|
|
297
|
+
Relative path from output directory
|
|
298
|
+
task : Optional[str], default None
|
|
299
|
+
Task name. If provided, saves to task-specific directory
|
|
300
|
+
fold : Optional[int], default None
|
|
301
|
+
If provided, automatically prepends "fold_{fold:02d}/" to path
|
|
302
|
+
|
|
303
|
+
Returns
|
|
304
|
+
-------
|
|
305
|
+
Path
|
|
306
|
+
Absolute path to the saved file
|
|
307
|
+
|
|
308
|
+
Examples
|
|
309
|
+
--------
|
|
310
|
+
>>> # Single task mode (no task specified)
|
|
311
|
+
>>> reporter.save({"accuracy": 0.95}, "metrics.json")
|
|
312
|
+
|
|
313
|
+
>>> # Multi-task mode
|
|
314
|
+
>>> reporter.save(results, "results.csv", task="binary", fold=0)
|
|
315
|
+
"""
|
|
316
|
+
# Single-task mode
|
|
317
|
+
if not self.tasks and self._single_reporter:
|
|
318
|
+
if task is not None:
|
|
319
|
+
# Convert to multi-task mode
|
|
320
|
+
self.tasks = [task]
|
|
321
|
+
self._single_reporter = None
|
|
322
|
+
self._create_single_reporter(task)
|
|
323
|
+
return self.reporters[task].save(
|
|
324
|
+
data, relative_path, fold=fold
|
|
325
|
+
)
|
|
326
|
+
else:
|
|
327
|
+
# Use single reporter's save
|
|
328
|
+
return self._single_reporter.save(
|
|
329
|
+
data, relative_path, fold=fold
|
|
330
|
+
)
|
|
331
|
+
|
|
332
|
+
# Multi-task mode
|
|
333
|
+
if task is not None:
|
|
334
|
+
# Delegate to task-specific reporter
|
|
335
|
+
if task not in self.reporters:
|
|
336
|
+
# Create task if it doesn't exist
|
|
337
|
+
if task not in self.tasks:
|
|
338
|
+
self.tasks.append(task)
|
|
339
|
+
self._create_single_reporter(task)
|
|
340
|
+
return self.reporters[task].save(data, relative_path, fold=fold)
|
|
341
|
+
else:
|
|
342
|
+
# Save to base output directory
|
|
343
|
+
if fold is not None:
|
|
344
|
+
relative_path = f"fold_{fold:02d}/{relative_path}"
|
|
345
|
+
return self.storage.save(data, relative_path)
|
|
346
|
+
|
|
347
|
+
def get_summary(self) -> Dict[str, Any]:
|
|
348
|
+
"""
|
|
349
|
+
Get summary of all calculated metrics.
|
|
350
|
+
|
|
351
|
+
Returns
|
|
352
|
+
-------
|
|
353
|
+
Dict[str, Any]
|
|
354
|
+
Summary of metrics across all tasks and folds
|
|
355
|
+
"""
|
|
356
|
+
# Single-task mode
|
|
357
|
+
if not self.tasks and self._single_reporter:
|
|
358
|
+
return self._single_reporter.get_summary()
|
|
359
|
+
|
|
360
|
+
# Multi-task mode
|
|
361
|
+
if not self.reporters:
|
|
362
|
+
return {"message": "No metrics calculated yet"}
|
|
363
|
+
|
|
364
|
+
if len(self.reporters) == 1:
|
|
365
|
+
# Only one task but in multi-task mode
|
|
366
|
+
task_name = list(self.reporters.keys())[0]
|
|
367
|
+
return self.reporters[task_name].get_summary()
|
|
368
|
+
else:
|
|
369
|
+
# Multiple tasks - aggregate summaries
|
|
370
|
+
summary = {"n_tasks": len(self.reporters), "tasks": {}}
|
|
371
|
+
for task_name, reporter in self.reporters.items():
|
|
372
|
+
summary["tasks"][task_name] = reporter.get_summary()
|
|
373
|
+
return summary
|
|
374
|
+
|
|
375
|
+
def save_summary(
|
|
376
|
+
self, filename: str = "summary.json", verbose: bool = True
|
|
377
|
+
) -> Path:
|
|
378
|
+
"""
|
|
379
|
+
Save summary to file.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
filename : str
|
|
384
|
+
Filename for summary
|
|
385
|
+
verbose : bool
|
|
386
|
+
Whether to print summary
|
|
387
|
+
|
|
388
|
+
Returns
|
|
389
|
+
-------
|
|
390
|
+
Path
|
|
391
|
+
Path to saved summary file
|
|
392
|
+
"""
|
|
393
|
+
# Single-task mode - delegate to single reporter
|
|
394
|
+
if not self.tasks and self._single_reporter:
|
|
395
|
+
return self._single_reporter.save_summary(
|
|
396
|
+
filename, verbose=verbose
|
|
397
|
+
)
|
|
398
|
+
|
|
399
|
+
# Multi-task mode
|
|
400
|
+
summary = self.get_summary()
|
|
401
|
+
|
|
402
|
+
if len(self.reporters) == 1:
|
|
403
|
+
# Only one task but in multi-task mode
|
|
404
|
+
task_name = list(self.reporters.keys())[0]
|
|
405
|
+
return self.reporters[task_name].save_summary(
|
|
406
|
+
filename, verbose=verbose
|
|
407
|
+
)
|
|
408
|
+
else:
|
|
409
|
+
# Multiple tasks - save in root directory
|
|
410
|
+
return self.storage.save(summary, filename)
|
|
411
|
+
|
|
412
|
+
def _save_config(self) -> None:
|
|
413
|
+
"""Save configuration to file."""
|
|
414
|
+
config_data = {
|
|
415
|
+
"output_dir": str(self.output_dir),
|
|
416
|
+
"tasks": self.tasks,
|
|
417
|
+
"precision": self.precision,
|
|
418
|
+
"required_metrics": self.required_metrics,
|
|
419
|
+
}
|
|
420
|
+
self.storage.save(config_data, "config.json")
|
|
421
|
+
|
|
422
|
+
def save_feature_importance(
|
|
423
|
+
self,
|
|
424
|
+
model,
|
|
425
|
+
feature_names: List[str],
|
|
426
|
+
fold: Optional[int] = None,
|
|
427
|
+
task: Optional[str] = None,
|
|
428
|
+
) -> Dict[str, float]:
|
|
429
|
+
"""
|
|
430
|
+
Calculate and save feature importance for tree-based models.
|
|
431
|
+
|
|
432
|
+
Parameters
|
|
433
|
+
----------
|
|
434
|
+
model : object
|
|
435
|
+
Fitted classifier (must have feature_importances_)
|
|
436
|
+
feature_names : List[str]
|
|
437
|
+
Names of features
|
|
438
|
+
fold : int, optional
|
|
439
|
+
Fold number for tracking
|
|
440
|
+
task : str, optional
|
|
441
|
+
Task name for multi-task mode
|
|
442
|
+
|
|
443
|
+
Returns
|
|
444
|
+
-------
|
|
445
|
+
Dict[str, float]
|
|
446
|
+
Dictionary of feature importances {feature_name: importance}
|
|
447
|
+
"""
|
|
448
|
+
# Single-task mode
|
|
449
|
+
if not self.tasks and self._single_reporter:
|
|
450
|
+
return self._single_reporter.save_feature_importance(
|
|
451
|
+
model, feature_names, fold
|
|
452
|
+
)
|
|
453
|
+
|
|
454
|
+
# Multi-task mode
|
|
455
|
+
if task is not None and task in self.reporters:
|
|
456
|
+
return self.reporters[task].save_feature_importance(
|
|
457
|
+
model, feature_names, fold
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
return {}
|
|
461
|
+
|
|
462
|
+
def save_feature_importance_summary(
|
|
463
|
+
self,
|
|
464
|
+
all_importances: List[Dict[str, float]],
|
|
465
|
+
task: Optional[str] = None,
|
|
466
|
+
) -> None:
|
|
467
|
+
"""
|
|
468
|
+
Create summary visualization of feature importances across all folds.
|
|
469
|
+
|
|
470
|
+
Parameters
|
|
471
|
+
----------
|
|
472
|
+
all_importances : List[Dict[str, float]]
|
|
473
|
+
List of feature importance dicts from each fold
|
|
474
|
+
task : str, optional
|
|
475
|
+
Task name for multi-task mode
|
|
476
|
+
"""
|
|
477
|
+
# Single-task mode
|
|
478
|
+
if not self.tasks and self._single_reporter:
|
|
479
|
+
return self._single_reporter.save_feature_importance_summary(
|
|
480
|
+
all_importances
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
# Multi-task mode
|
|
484
|
+
if task is not None and task in self.reporters:
|
|
485
|
+
return self.reporters[task].save_feature_importance_summary(
|
|
486
|
+
all_importances
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
def __repr__(self) -> str:
|
|
490
|
+
if not self.tasks:
|
|
491
|
+
return f"ClassificationReporter(output_dir='{self.output_dir}', tasks=None)"
|
|
492
|
+
elif len(self.tasks) == 1:
|
|
493
|
+
return f"ClassificationReporter(output_dir='{self.output_dir}', task='{self.tasks[0]}')"
|
|
494
|
+
else:
|
|
495
|
+
return f"ClassificationReporter(output_dir='{self.output_dir}', tasks={len(self.tasks)})"
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
# Convenience function for backwards compatibility
|
|
499
|
+
def create_classification_reporter(
|
|
500
|
+
output_dir: Union[str, Path], tasks: Optional[List[str]] = None, **kwargs
|
|
501
|
+
) -> ClassificationReporter:
|
|
502
|
+
"""
|
|
503
|
+
Create a unified classification reporter.
|
|
504
|
+
|
|
505
|
+
Parameters
|
|
506
|
+
----------
|
|
507
|
+
output_dir : Union[str, Path]
|
|
508
|
+
Output directory for results
|
|
509
|
+
tasks : List[str], optional
|
|
510
|
+
List of task names (for multi-task)
|
|
511
|
+
**kwargs
|
|
512
|
+
Additional configuration options
|
|
513
|
+
|
|
514
|
+
Returns
|
|
515
|
+
-------
|
|
516
|
+
ClassificationReporter
|
|
517
|
+
Configured reporter instance
|
|
518
|
+
"""
|
|
519
|
+
return ClassificationReporter(output_dir, tasks=tasks, **kwargs)
|
|
520
|
+
|
|
521
|
+
|
|
522
|
+
def parse_args():
|
|
523
|
+
"""Parse command line arguments."""
|
|
524
|
+
import argparse
|
|
525
|
+
|
|
526
|
+
parser = argparse.ArgumentParser(
|
|
527
|
+
description="Test ClassificationReporter with sample data"
|
|
528
|
+
)
|
|
529
|
+
parser.add_argument(
|
|
530
|
+
"--output-dir",
|
|
531
|
+
type=str,
|
|
532
|
+
default="./.dev/classification_reporter_test_out",
|
|
533
|
+
help="Output directory for test results (default: %(default)s)"
|
|
534
|
+
)
|
|
535
|
+
parser.add_argument(
|
|
536
|
+
"--n-samples",
|
|
537
|
+
type=int,
|
|
538
|
+
default=100,
|
|
539
|
+
help="Number of samples to generate (default: %(default)s)"
|
|
540
|
+
)
|
|
541
|
+
parser.add_argument(
|
|
542
|
+
"--n-folds",
|
|
543
|
+
type=int,
|
|
544
|
+
default=3,
|
|
545
|
+
help="Number of CV folds (default: %(default)s)"
|
|
546
|
+
)
|
|
547
|
+
parser.add_argument(
|
|
548
|
+
"--task-type",
|
|
549
|
+
type=str,
|
|
550
|
+
choices=["binary", "multiclass", "multitask"],
|
|
551
|
+
default="binary",
|
|
552
|
+
help="Type of classification task (default: %(default)s)"
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
return parser.parse_args()
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
def main(args):
|
|
559
|
+
"""Test ClassificationReporter functionality."""
|
|
560
|
+
from sklearn.datasets import make_classification
|
|
561
|
+
from sklearn.model_selection import StratifiedKFold
|
|
562
|
+
from sklearn.linear_model import LogisticRegression
|
|
563
|
+
from sklearn.ensemble import RandomForestClassifier
|
|
564
|
+
|
|
565
|
+
# Create output directory
|
|
566
|
+
output_dir = Path(args.output_dir)
|
|
567
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
568
|
+
|
|
569
|
+
print("=" * 60)
|
|
570
|
+
print("ClassificationReporter Test")
|
|
571
|
+
print("=" * 60)
|
|
572
|
+
print(f"Task type: {args.task_type}")
|
|
573
|
+
print(f"Output dir: {output_dir}")
|
|
574
|
+
print(f"Samples: {args.n_samples}, Folds: {args.n_folds}")
|
|
575
|
+
print()
|
|
576
|
+
|
|
577
|
+
if args.task_type == "binary":
|
|
578
|
+
# Binary classification
|
|
579
|
+
print("Testing Binary Classification...")
|
|
580
|
+
X, y = make_classification(
|
|
581
|
+
n_samples=args.n_samples,
|
|
582
|
+
n_features=20,
|
|
583
|
+
n_classes=2,
|
|
584
|
+
n_informative=15,
|
|
585
|
+
n_redundant=5,
|
|
586
|
+
random_state=42
|
|
587
|
+
)
|
|
588
|
+
labels = ["Negative", "Positive"]
|
|
589
|
+
|
|
590
|
+
reporter = ClassificationReporter(output_dir / "binary", track=True)
|
|
591
|
+
|
|
592
|
+
# Cross-validation
|
|
593
|
+
cv = StratifiedKFold(n_splits=args.n_folds, shuffle=True, random_state=42)
|
|
594
|
+
model = LogisticRegression(random_state=42, max_iter=1000)
|
|
595
|
+
|
|
596
|
+
for fold, (train_idx, test_idx) in enumerate(cv.split(X, y)):
|
|
597
|
+
X_train, X_test = X[train_idx], X[test_idx]
|
|
598
|
+
y_train, y_test = y[train_idx], y[test_idx]
|
|
599
|
+
|
|
600
|
+
model.fit(X_train, y_train)
|
|
601
|
+
y_pred = model.predict(X_test)
|
|
602
|
+
y_proba = model.predict_proba(X_test)
|
|
603
|
+
|
|
604
|
+
reporter.calculate_metrics(
|
|
605
|
+
y_true=y_test,
|
|
606
|
+
y_pred=y_pred,
|
|
607
|
+
y_proba=y_proba,
|
|
608
|
+
labels=labels,
|
|
609
|
+
fold=fold
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
# Generate reports
|
|
613
|
+
reporter.save_summary()
|
|
614
|
+
print(f"✓ Binary classification results saved to: {output_dir / 'binary'}")
|
|
615
|
+
|
|
616
|
+
elif args.task_type == "multiclass":
|
|
617
|
+
# Multiclass classification
|
|
618
|
+
print("Testing Multiclass Classification...")
|
|
619
|
+
X, y = make_classification(
|
|
620
|
+
n_samples=args.n_samples,
|
|
621
|
+
n_features=20,
|
|
622
|
+
n_classes=4,
|
|
623
|
+
n_informative=15,
|
|
624
|
+
n_redundant=5,
|
|
625
|
+
n_clusters_per_class=1,
|
|
626
|
+
random_state=42
|
|
627
|
+
)
|
|
628
|
+
labels = ["Class_A", "Class_B", "Class_C", "Class_D"]
|
|
629
|
+
|
|
630
|
+
reporter = ClassificationReporter(output_dir / "multiclass", track=True)
|
|
631
|
+
|
|
632
|
+
cv = StratifiedKFold(n_splits=args.n_folds, shuffle=True, random_state=42)
|
|
633
|
+
model = RandomForestClassifier(n_estimators=50, random_state=42)
|
|
634
|
+
|
|
635
|
+
for fold, (train_idx, test_idx) in enumerate(cv.split(X, y)):
|
|
636
|
+
X_train, X_test = X[train_idx], X[test_idx]
|
|
637
|
+
y_train, y_test = y[train_idx], y[test_idx]
|
|
638
|
+
|
|
639
|
+
model.fit(X_train, y_train)
|
|
640
|
+
y_pred = model.predict(X_test)
|
|
641
|
+
y_proba = model.predict_proba(X_test)
|
|
642
|
+
|
|
643
|
+
reporter.calculate_metrics(
|
|
644
|
+
y_true=y_test,
|
|
645
|
+
y_pred=y_pred,
|
|
646
|
+
y_proba=y_proba,
|
|
647
|
+
labels=labels,
|
|
648
|
+
fold=fold
|
|
649
|
+
)
|
|
650
|
+
|
|
651
|
+
reporter.save_summary()
|
|
652
|
+
print(f"✓ Multiclass classification results saved to: {output_dir / 'multiclass'}")
|
|
653
|
+
|
|
654
|
+
elif args.task_type == "multitask":
|
|
655
|
+
# Multi-task classification
|
|
656
|
+
print("Testing Multi-task Classification...")
|
|
657
|
+
|
|
658
|
+
# Task 1: Binary
|
|
659
|
+
X1, y1 = make_classification(
|
|
660
|
+
n_samples=args.n_samples, n_features=20, n_classes=2, random_state=42
|
|
661
|
+
)
|
|
662
|
+
|
|
663
|
+
# Task 2: Multiclass
|
|
664
|
+
X2, y2 = make_classification(
|
|
665
|
+
n_samples=args.n_samples, n_features=20, n_classes=3, random_state=43
|
|
666
|
+
)
|
|
667
|
+
|
|
668
|
+
reporter = ClassificationReporter(
|
|
669
|
+
output_dir / "multitask",
|
|
670
|
+
tasks=["binary_task", "multiclass_task"],
|
|
671
|
+
track=True
|
|
672
|
+
)
|
|
673
|
+
|
|
674
|
+
cv = StratifiedKFold(n_splits=args.n_folds, shuffle=True, random_state=42)
|
|
675
|
+
|
|
676
|
+
# Task 1
|
|
677
|
+
model1 = LogisticRegression(random_state=42, max_iter=1000)
|
|
678
|
+
for fold, (train_idx, test_idx) in enumerate(cv.split(X1, y1)):
|
|
679
|
+
X_train, X_test = X1[train_idx], X1[test_idx]
|
|
680
|
+
y_train, y_test = y1[train_idx], y1[test_idx]
|
|
681
|
+
|
|
682
|
+
model1.fit(X_train, y_train)
|
|
683
|
+
y_pred = model1.predict(X_test)
|
|
684
|
+
y_proba = model1.predict_proba(X_test)
|
|
685
|
+
|
|
686
|
+
reporter.calculate_metrics(
|
|
687
|
+
y_true=y_test,
|
|
688
|
+
y_pred=y_pred,
|
|
689
|
+
y_proba=y_proba,
|
|
690
|
+
labels=["Neg", "Pos"],
|
|
691
|
+
fold=fold,
|
|
692
|
+
task="binary_task"
|
|
693
|
+
)
|
|
694
|
+
|
|
695
|
+
# Task 2
|
|
696
|
+
model2 = RandomForestClassifier(n_estimators=50, random_state=42)
|
|
697
|
+
for fold, (train_idx, test_idx) in enumerate(cv.split(X2, y2)):
|
|
698
|
+
X_train, X_test = X2[train_idx], X2[test_idx]
|
|
699
|
+
y_train, y_test = y2[train_idx], y2[test_idx]
|
|
700
|
+
|
|
701
|
+
model2.fit(X_train, y_train)
|
|
702
|
+
y_pred = model2.predict(X_test)
|
|
703
|
+
y_proba = model2.predict_proba(X_test)
|
|
704
|
+
|
|
705
|
+
reporter.calculate_metrics(
|
|
706
|
+
y_true=y_test,
|
|
707
|
+
y_pred=y_pred,
|
|
708
|
+
y_proba=y_proba,
|
|
709
|
+
labels=["A", "B", "C"],
|
|
710
|
+
fold=fold,
|
|
711
|
+
task="multiclass_task"
|
|
712
|
+
)
|
|
713
|
+
|
|
714
|
+
reporter.save_summary()
|
|
715
|
+
print(f"✓ Multi-task classification results saved to: {output_dir / 'multitask'}")
|
|
716
|
+
|
|
717
|
+
print()
|
|
718
|
+
print("=" * 60)
|
|
719
|
+
print("Test Complete!")
|
|
720
|
+
print("=" * 60)
|
|
721
|
+
print(f"\nCreated files in: {output_dir}")
|
|
722
|
+
|
|
723
|
+
# List all created files
|
|
724
|
+
import subprocess
|
|
725
|
+
result = subprocess.run(
|
|
726
|
+
["find", str(output_dir), "-type", "f"],
|
|
727
|
+
capture_output=True,
|
|
728
|
+
text=True
|
|
729
|
+
)
|
|
730
|
+
if result.stdout:
|
|
731
|
+
files = sorted(result.stdout.strip().split('\n'))
|
|
732
|
+
print(f"\nTotal files created: {len(files)}")
|
|
733
|
+
print("\nFile tree:")
|
|
734
|
+
subprocess.run(["tree", str(output_dir)])
|
|
735
|
+
|
|
736
|
+
return 0
|
|
737
|
+
|
|
738
|
+
|
|
739
|
+
def run_main():
|
|
740
|
+
"""Initialize scitex framework, run main function, and cleanup."""
|
|
741
|
+
global CONFIG, CC, sys, plt, rng
|
|
742
|
+
|
|
743
|
+
import sys
|
|
744
|
+
import matplotlib.pyplot as plt
|
|
745
|
+
import scitex as stx
|
|
746
|
+
|
|
747
|
+
args = parse_args()
|
|
748
|
+
|
|
749
|
+
CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
|
|
750
|
+
sys,
|
|
751
|
+
plt,
|
|
752
|
+
args=args,
|
|
753
|
+
file=__FILE__,
|
|
754
|
+
sdir_suffix=None,
|
|
755
|
+
verbose=False,
|
|
756
|
+
agg=True,
|
|
757
|
+
)
|
|
758
|
+
|
|
759
|
+
exit_status = main(args)
|
|
760
|
+
|
|
761
|
+
stx.session.close(
|
|
762
|
+
CONFIG,
|
|
763
|
+
verbose=False,
|
|
764
|
+
notify=False,
|
|
765
|
+
message="",
|
|
766
|
+
exit_status=exit_status,
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
|
|
770
|
+
if __name__ == "__main__":
|
|
771
|
+
run_main()
|
|
772
|
+
|
|
773
|
+
# EOF
|