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,490 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
# Timestamp: "2025-10-03 01:56:15 (ywatanabe)"
|
|
4
|
+
# File: /ssh:sp:/home/ywatanabe/proj/scitex_repo/src/scitex/ml/metrics/_calc_seizure_prediction_metrics.py
|
|
5
|
+
"""Calculate clinical seizure prediction metrics.
|
|
6
|
+
|
|
7
|
+
This module provides both window-based and event-based seizure prediction metrics
|
|
8
|
+
following FDA/clinical guidelines.
|
|
9
|
+
|
|
10
|
+
Two Approaches:
|
|
11
|
+
1. Window-based: Measures % of seizure time windows detected
|
|
12
|
+
2. Event-based: Measures % of seizure events detected (≥1 alarm per event)
|
|
13
|
+
|
|
14
|
+
Key Metrics:
|
|
15
|
+
- seizure_sensitivity: % detected (interpretation depends on window vs event-based)
|
|
16
|
+
- fp_per_hour: False positives per hour during interictal periods
|
|
17
|
+
- time_in_warning: % of total time in alarm state
|
|
18
|
+
|
|
19
|
+
Clinical Targets (FDA guidelines):
|
|
20
|
+
- Sensitivity ≥ 90%
|
|
21
|
+
- FP/h ≤ 0.2
|
|
22
|
+
- Time in warning ≤ 20%
|
|
23
|
+
"""
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
from typing import Dict
|
|
26
|
+
import numpy as np
|
|
27
|
+
import pandas as pd
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def calc_seizure_window_prediction_metrics(
|
|
31
|
+
y_true: np.ndarray,
|
|
32
|
+
y_pred: np.ndarray,
|
|
33
|
+
metadata: pd.DataFrame,
|
|
34
|
+
window_duration_min: float = 1.0,
|
|
35
|
+
) -> Dict[str, float]:
|
|
36
|
+
"""Calculate clinical seizure prediction metrics (window-based).
|
|
37
|
+
|
|
38
|
+
This function calculates window-based sensitivity, meaning it measures
|
|
39
|
+
the percentage of seizure time windows that were correctly identified.
|
|
40
|
+
This is NOT event-based sensitivity (which would measure % of seizure
|
|
41
|
+
events detected regardless of how many windows within each event).
|
|
42
|
+
|
|
43
|
+
Parameters
|
|
44
|
+
----------
|
|
45
|
+
y_true : np.ndarray
|
|
46
|
+
True labels (string: 'seizure' or 'interictal_control')
|
|
47
|
+
y_pred : np.ndarray
|
|
48
|
+
Predicted labels (string: 'seizure' or 'interictal_control')
|
|
49
|
+
metadata : pd.DataFrame
|
|
50
|
+
Metadata with 'seizure_type' column indicating seizure/interictal periods
|
|
51
|
+
window_duration_min : float, optional
|
|
52
|
+
Duration of each time window in minutes (default: 1.0)
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
Dict[str, float]
|
|
57
|
+
Dictionary containing:
|
|
58
|
+
- seizure_sensitivity: % of seizure *time windows* detected (NOT event-based)
|
|
59
|
+
- fp_per_hour: False positives per hour during interictal periods
|
|
60
|
+
- time_in_warning: % of total time in alarm state
|
|
61
|
+
- n_seizure_windows: Number of seizure windows
|
|
62
|
+
- n_interictal_windows: Number of interictal windows
|
|
63
|
+
- n_true_positives: Correctly predicted seizure windows
|
|
64
|
+
- n_false_positives: Incorrectly predicted as seizure
|
|
65
|
+
- n_false_negatives: Missed seizure windows
|
|
66
|
+
- n_true_negatives: Correctly predicted as interictal
|
|
67
|
+
- meets_sensitivity_target: Whether sensitivity ≥ 90%
|
|
68
|
+
- meets_fp_target: Whether FP/h ≤ 0.2
|
|
69
|
+
- meets_tiw_target: Whether time in warning ≤ 20%
|
|
70
|
+
|
|
71
|
+
Notes
|
|
72
|
+
-----
|
|
73
|
+
- False positives are calculated only during interictal periods
|
|
74
|
+
- True positives/false negatives are calculated only during seizure periods
|
|
75
|
+
- Clinical targets based on FDA guidance for seizure prediction devices
|
|
76
|
+
- For event-based sensitivity, use calc_seizure_event_prediction_metrics instead
|
|
77
|
+
|
|
78
|
+
Example
|
|
79
|
+
-------
|
|
80
|
+
>>> # 1 seizure spanning 20 windows, detect 5 windows
|
|
81
|
+
>>> # Window-based sensitivity: 5/20 = 25%
|
|
82
|
+
>>> # This measures temporal coverage of the seizure
|
|
83
|
+
|
|
84
|
+
References
|
|
85
|
+
----------
|
|
86
|
+
FDA guidance on seizure prediction devices
|
|
87
|
+
"""
|
|
88
|
+
# Create masks for seizure and interictal periods
|
|
89
|
+
seizure_mask = metadata["seizure_type"] == "seizure"
|
|
90
|
+
interictal_mask = metadata["seizure_type"] == "interictal_control"
|
|
91
|
+
|
|
92
|
+
# Convert string labels to binary for calculations
|
|
93
|
+
y_true_bin = (y_true == "seizure").astype(int)
|
|
94
|
+
y_pred_bin = (y_pred == "seizure").astype(int)
|
|
95
|
+
|
|
96
|
+
# True positives (seizure windows correctly identified)
|
|
97
|
+
tp = np.sum((y_true_bin == 1) & (y_pred_bin == 1) & seizure_mask)
|
|
98
|
+
|
|
99
|
+
# False negatives (seizure windows missed)
|
|
100
|
+
fn = np.sum((y_true_bin == 1) & (y_pred_bin == 0) & seizure_mask)
|
|
101
|
+
|
|
102
|
+
# False positives (interictal windows incorrectly alarmed)
|
|
103
|
+
fp = np.sum((y_true_bin == 0) & (y_pred_bin == 1) & interictal_mask)
|
|
104
|
+
|
|
105
|
+
# True negatives (interictal windows correctly identified)
|
|
106
|
+
tn = np.sum((y_true_bin == 0) & (y_pred_bin == 0) & interictal_mask)
|
|
107
|
+
|
|
108
|
+
# Sensitivity (seizure detection rate) - WINDOW-BASED
|
|
109
|
+
n_seizures = seizure_mask.sum()
|
|
110
|
+
seizure_sensitivity = (tp / n_seizures * 100) if n_seizures > 0 else 0.0
|
|
111
|
+
|
|
112
|
+
# False positives per hour
|
|
113
|
+
n_interictal = interictal_mask.sum()
|
|
114
|
+
total_interictal_hours = (n_interictal * window_duration_min) / 60.0
|
|
115
|
+
fp_per_hour = (
|
|
116
|
+
fp / total_interictal_hours if total_interictal_hours > 0 else 0.0
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Time in warning (% of total time in alarm state)
|
|
120
|
+
total_windows = len(y_pred)
|
|
121
|
+
alarm_windows = np.sum(y_pred_bin == 1)
|
|
122
|
+
time_in_warning = (
|
|
123
|
+
(alarm_windows / total_windows * 100) if total_windows > 0 else 0.0
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
metrics = {
|
|
127
|
+
# Primary prediction metrics
|
|
128
|
+
"seizure_sensitivity": round(seizure_sensitivity, 3),
|
|
129
|
+
"fp_per_hour": round(fp_per_hour, 3),
|
|
130
|
+
"time_in_warning": round(time_in_warning, 3),
|
|
131
|
+
# Counts (time windows, not events)
|
|
132
|
+
"n_seizure_windows": int(n_seizures),
|
|
133
|
+
"n_interictal_windows": int(n_interictal),
|
|
134
|
+
"n_true_positives": int(tp),
|
|
135
|
+
"n_false_positives": int(fp),
|
|
136
|
+
"n_false_negatives": int(fn),
|
|
137
|
+
"n_true_negatives": int(tn),
|
|
138
|
+
# Clinical targets (FDA/clinical guidelines)
|
|
139
|
+
"meets_sensitivity_target": bool(seizure_sensitivity >= 90.0),
|
|
140
|
+
"meets_fp_target": bool(fp_per_hour <= 0.2),
|
|
141
|
+
"meets_tiw_target": bool(time_in_warning <= 20.0),
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return metrics
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def calc_seizure_event_prediction_metrics(
|
|
148
|
+
y_true: np.ndarray,
|
|
149
|
+
y_pred: np.ndarray,
|
|
150
|
+
metadata: pd.DataFrame,
|
|
151
|
+
window_duration_min: float = 1.0,
|
|
152
|
+
) -> Dict[str, float]:
|
|
153
|
+
"""Calculate clinical seizure prediction metrics (event-based).
|
|
154
|
+
|
|
155
|
+
This function calculates event-based sensitivity, meaning it measures
|
|
156
|
+
whether each seizure EVENT was detected (at least one alarm raised),
|
|
157
|
+
regardless of how many windows within that event were predicted.
|
|
158
|
+
|
|
159
|
+
This is clinically more relevant as one timely alarm per seizure event
|
|
160
|
+
is sufficient for intervention, matching the clinical requirement:
|
|
161
|
+
"Did the system raise an alarm for this seizure?"
|
|
162
|
+
|
|
163
|
+
Parameters
|
|
164
|
+
----------
|
|
165
|
+
y_true : np.ndarray
|
|
166
|
+
True labels (string: 'seizure' or 'interictal_control')
|
|
167
|
+
y_pred : np.ndarray
|
|
168
|
+
Predicted labels (string: 'seizure' or 'interictal_control')
|
|
169
|
+
metadata : pd.DataFrame
|
|
170
|
+
Metadata with 'seizure_type' and 'seizure_id' columns.
|
|
171
|
+
seizure_id: Unique identifier for each seizure event (e.g., 'sz_001', 'sz_002')
|
|
172
|
+
Should be NaN or empty for interictal periods
|
|
173
|
+
window_duration_min : float, optional
|
|
174
|
+
Duration of each time window in minutes (default: 1.0)
|
|
175
|
+
|
|
176
|
+
Returns
|
|
177
|
+
-------
|
|
178
|
+
Dict[str, float]
|
|
179
|
+
Dictionary containing:
|
|
180
|
+
- seizure_sensitivity: % of seizure *events* detected (event-based)
|
|
181
|
+
- fp_per_hour: False positives per hour during interictal periods
|
|
182
|
+
- time_in_warning: % of total time in alarm state
|
|
183
|
+
- n_seizure_events: Number of unique seizure events
|
|
184
|
+
- n_detected_events: Number of events with at least one alarm
|
|
185
|
+
- n_missed_events: Number of events with zero alarms
|
|
186
|
+
- n_interictal_windows: Number of interictal windows
|
|
187
|
+
- n_false_positives: Incorrectly predicted as seizure
|
|
188
|
+
- n_true_negatives: Correctly predicted as interictal
|
|
189
|
+
- meets_sensitivity_target: Whether sensitivity ≥ 90%
|
|
190
|
+
- meets_fp_target: Whether FP/h ≤ 0.2
|
|
191
|
+
- meets_tiw_target: Whether time in warning ≤ 20%
|
|
192
|
+
|
|
193
|
+
Notes
|
|
194
|
+
-----
|
|
195
|
+
- Requires 'seizure_id' column in metadata to group windows by event
|
|
196
|
+
- False positives are calculated only during interictal periods
|
|
197
|
+
- Event detection requires at least one window predicted as seizure
|
|
198
|
+
- Clinical targets based on FDA guidance for seizure prediction devices
|
|
199
|
+
- For window-based sensitivity, use calc_seizure_window_prediction_metrics instead
|
|
200
|
+
|
|
201
|
+
Example
|
|
202
|
+
-------
|
|
203
|
+
>>> # 1 seizure spanning 20 windows, detect just 1 window
|
|
204
|
+
>>> # Event-based sensitivity: 1/1 = 100% (event was detected!)
|
|
205
|
+
>>> # This measures "did we catch the seizure at all?"
|
|
206
|
+
|
|
207
|
+
References
|
|
208
|
+
----------
|
|
209
|
+
FDA guidance on seizure prediction devices
|
|
210
|
+
"""
|
|
211
|
+
# Validate required column
|
|
212
|
+
if "seizure_id" not in metadata.columns:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
"metadata must contain 'seizure_id' column for event-based metrics. "
|
|
215
|
+
"Use calc_seizure_window_prediction_metrics for window-based metrics."
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
# Create masks
|
|
219
|
+
seizure_mask = metadata["seizure_type"] == "seizure"
|
|
220
|
+
interictal_mask = metadata["seizure_type"] == "interictal_control"
|
|
221
|
+
|
|
222
|
+
# Convert string labels to binary
|
|
223
|
+
y_true_bin = (y_true == "seizure").astype(int)
|
|
224
|
+
y_pred_bin = (y_pred == "seizure").astype(int)
|
|
225
|
+
|
|
226
|
+
# Event-based sensitivity calculation
|
|
227
|
+
# Group by seizure_id and check if any window in that event was predicted
|
|
228
|
+
seizure_events = metadata[seizure_mask]["seizure_id"].unique()
|
|
229
|
+
n_seizure_events = len(seizure_events)
|
|
230
|
+
|
|
231
|
+
detected_events = 0
|
|
232
|
+
for event_id in seizure_events:
|
|
233
|
+
event_mask = (metadata["seizure_id"] == event_id).values
|
|
234
|
+
# Check if at least one window in this event was predicted as seizure
|
|
235
|
+
event_predictions = y_pred_bin[event_mask]
|
|
236
|
+
if np.any(event_predictions == 1):
|
|
237
|
+
detected_events += 1
|
|
238
|
+
|
|
239
|
+
missed_events = n_seizure_events - detected_events
|
|
240
|
+
|
|
241
|
+
# Event-based sensitivity: % of events detected
|
|
242
|
+
seizure_sensitivity = (
|
|
243
|
+
(detected_events / n_seizure_events * 100) if n_seizure_events > 0 else 0.0
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
# False positives (interictal windows incorrectly alarmed)
|
|
247
|
+
fp = np.sum((y_true_bin == 0) & (y_pred_bin == 1) & interictal_mask)
|
|
248
|
+
|
|
249
|
+
# True negatives (interictal windows correctly identified)
|
|
250
|
+
tn = np.sum((y_true_bin == 0) & (y_pred_bin == 0) & interictal_mask)
|
|
251
|
+
|
|
252
|
+
# False positives per hour
|
|
253
|
+
n_interictal = interictal_mask.sum()
|
|
254
|
+
total_interictal_hours = (n_interictal * window_duration_min) / 60.0
|
|
255
|
+
fp_per_hour = (
|
|
256
|
+
fp / total_interictal_hours if total_interictal_hours > 0 else 0.0
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
# Time in warning (% of total time in alarm state)
|
|
260
|
+
total_windows = len(y_pred)
|
|
261
|
+
alarm_windows = np.sum(y_pred_bin == 1)
|
|
262
|
+
time_in_warning = (
|
|
263
|
+
(alarm_windows / total_windows * 100) if total_windows > 0 else 0.0
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
metrics = {
|
|
267
|
+
# Primary prediction metrics
|
|
268
|
+
"seizure_sensitivity": round(seizure_sensitivity, 3),
|
|
269
|
+
"fp_per_hour": round(fp_per_hour, 3),
|
|
270
|
+
"time_in_warning": round(time_in_warning, 3),
|
|
271
|
+
# Counts (events, not windows)
|
|
272
|
+
"n_seizure_events": int(n_seizure_events),
|
|
273
|
+
"n_detected_events": int(detected_events),
|
|
274
|
+
"n_missed_events": int(missed_events),
|
|
275
|
+
"n_interictal_windows": int(n_interictal),
|
|
276
|
+
"n_false_positives": int(fp),
|
|
277
|
+
"n_true_negatives": int(tn),
|
|
278
|
+
# Clinical targets (FDA/clinical guidelines)
|
|
279
|
+
"meets_sensitivity_target": bool(seizure_sensitivity >= 90.0),
|
|
280
|
+
"meets_fp_target": bool(fp_per_hour <= 0.2),
|
|
281
|
+
"meets_tiw_target": bool(time_in_warning <= 20.0),
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return metrics
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
# Backward compatibility aliases
|
|
288
|
+
calc_seizure_prediction_metrics = calc_seizure_window_prediction_metrics
|
|
289
|
+
calculate_seizure_prediction_metrics = calc_seizure_window_prediction_metrics
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
def parse_args():
|
|
293
|
+
"""Parse command line arguments."""
|
|
294
|
+
import argparse
|
|
295
|
+
|
|
296
|
+
parser = argparse.ArgumentParser(
|
|
297
|
+
description="Demonstrate seizure prediction metrics calculation"
|
|
298
|
+
)
|
|
299
|
+
parser.add_argument(
|
|
300
|
+
"--n-windows",
|
|
301
|
+
type=int,
|
|
302
|
+
default=1000,
|
|
303
|
+
help="Number of time windows to simulate (default: %(default)s)",
|
|
304
|
+
)
|
|
305
|
+
parser.add_argument(
|
|
306
|
+
"--window-duration",
|
|
307
|
+
type=float,
|
|
308
|
+
default=1.0,
|
|
309
|
+
help="Duration of each window in minutes (default: %(default)s)",
|
|
310
|
+
)
|
|
311
|
+
parser.add_argument(
|
|
312
|
+
"--sensitivity",
|
|
313
|
+
type=float,
|
|
314
|
+
default=0.9,
|
|
315
|
+
help="Target sensitivity to simulate (default: %(default)s)",
|
|
316
|
+
)
|
|
317
|
+
args = parser.parse_args()
|
|
318
|
+
return args
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
def main(args):
|
|
322
|
+
"""Demonstrate seizure prediction metrics with synthetic data."""
|
|
323
|
+
from scitex import logging
|
|
324
|
+
|
|
325
|
+
logger = logging.getLogger(__name__)
|
|
326
|
+
|
|
327
|
+
logger.info("Creating synthetic seizure prediction data")
|
|
328
|
+
logger.info(f" n_windows: {args.n_windows}")
|
|
329
|
+
logger.info(f" window_duration: {args.window_duration} min")
|
|
330
|
+
logger.info(f" target_sensitivity: {args.sensitivity * 100}%")
|
|
331
|
+
|
|
332
|
+
# Create synthetic test data
|
|
333
|
+
n_windows = args.n_windows
|
|
334
|
+
window_duration_min = args.window_duration
|
|
335
|
+
|
|
336
|
+
# Create labels and metadata with seizure_id for event-based metrics
|
|
337
|
+
y_true = np.array(["interictal_control"] * n_windows)
|
|
338
|
+
y_pred = np.array(["interictal_control"] * n_windows)
|
|
339
|
+
metadata = pd.DataFrame({
|
|
340
|
+
"seizure_type": ["interictal_control"] * n_windows,
|
|
341
|
+
"seizure_id": [None] * n_windows # seizure_id for event-based metrics
|
|
342
|
+
})
|
|
343
|
+
|
|
344
|
+
# Add TWO seizure events (event 1: 100-119, event 2: 500-529)
|
|
345
|
+
event1_indices = list(range(100, 120)) # 20 windows
|
|
346
|
+
event2_indices = list(range(500, 530)) # 30 windows
|
|
347
|
+
seizure_indices = event1_indices + event2_indices
|
|
348
|
+
|
|
349
|
+
y_true[event1_indices] = "seizure"
|
|
350
|
+
y_true[event2_indices] = "seizure"
|
|
351
|
+
metadata.loc[event1_indices, "seizure_type"] = "seizure"
|
|
352
|
+
metadata.loc[event1_indices, "seizure_id"] = "sz_001"
|
|
353
|
+
metadata.loc[event2_indices, "seizure_type"] = "seizure"
|
|
354
|
+
metadata.loc[event2_indices, "seizure_id"] = "sz_002"
|
|
355
|
+
|
|
356
|
+
logger.info(f"Created 2 seizure events spanning {len(seizure_indices)} windows total")
|
|
357
|
+
logger.info(f" Event 1 (sz_001): 20 windows")
|
|
358
|
+
logger.info(f" Event 2 (sz_002): 30 windows")
|
|
359
|
+
|
|
360
|
+
# Predict some seizures correctly based on target sensitivity
|
|
361
|
+
# For event-based demo: detect only 1 window from event 1, most of event 2
|
|
362
|
+
n_detect = int(len(seizure_indices) * args.sensitivity)
|
|
363
|
+
# Detect 1 window from event 1, rest from event 2
|
|
364
|
+
detected_indices = [event1_indices[0]] + event2_indices[:n_detect-1]
|
|
365
|
+
y_pred[detected_indices] = "seizure"
|
|
366
|
+
|
|
367
|
+
logger.info(f"Simulating detection of {n_detect}/{len(seizure_indices)} seizure windows")
|
|
368
|
+
logger.info(f" Event 1: 1/20 windows detected")
|
|
369
|
+
logger.info(f" Event 2: {n_detect-1}/30 windows detected")
|
|
370
|
+
|
|
371
|
+
# Add some false positives
|
|
372
|
+
fp_indices = [200, 300, 400, 600, 700]
|
|
373
|
+
y_pred[fp_indices] = "seizure"
|
|
374
|
+
|
|
375
|
+
logger.info(f"Added {len(fp_indices)} false positive alarms")
|
|
376
|
+
|
|
377
|
+
# Calculate WINDOW-BASED metrics
|
|
378
|
+
logger.info("")
|
|
379
|
+
logger.info("Calculating WINDOW-BASED seizure prediction metrics")
|
|
380
|
+
metrics_window = calc_seizure_window_prediction_metrics(
|
|
381
|
+
y_true, y_pred, metadata, window_duration_min
|
|
382
|
+
)
|
|
383
|
+
|
|
384
|
+
# Print window-based results
|
|
385
|
+
logger.info("=" * 70)
|
|
386
|
+
logger.info("WINDOW-BASED Metrics (How well did we cover seizure duration?)")
|
|
387
|
+
logger.info("=" * 70)
|
|
388
|
+
logger.info(f"Seizure Sensitivity: {metrics_window['seizure_sensitivity']:.1f}%")
|
|
389
|
+
logger.info(f"False Positives/Hour: {metrics_window['fp_per_hour']:.3f}")
|
|
390
|
+
logger.info(f"Time in Warning: {metrics_window['time_in_warning']:.1f}%")
|
|
391
|
+
logger.info("")
|
|
392
|
+
logger.info("Counts:")
|
|
393
|
+
logger.info(f" Seizure windows: {metrics_window['n_seizure_windows']}")
|
|
394
|
+
logger.info(f" Interictal windows: {metrics_window['n_interictal_windows']}")
|
|
395
|
+
logger.info(f" True positives: {metrics_window['n_true_positives']}")
|
|
396
|
+
logger.info(f" False positives: {metrics_window['n_false_positives']}")
|
|
397
|
+
logger.info(f" False negatives: {metrics_window['n_false_negatives']}")
|
|
398
|
+
logger.info(f" True negatives: {metrics_window['n_true_negatives']}")
|
|
399
|
+
logger.info("")
|
|
400
|
+
logger.info("Clinical Targets (FDA Guidelines):")
|
|
401
|
+
logger.info(
|
|
402
|
+
f" Meets sensitivity target (≥90%): {metrics_window['meets_sensitivity_target']}"
|
|
403
|
+
)
|
|
404
|
+
logger.info(f" Meets FP/h target (≤0.2): {metrics_window['meets_fp_target']}")
|
|
405
|
+
logger.info(f" Meets time in warning target (≤20%): {metrics_window['meets_tiw_target']}")
|
|
406
|
+
logger.info("=" * 70)
|
|
407
|
+
|
|
408
|
+
# Calculate EVENT-BASED metrics
|
|
409
|
+
logger.info("")
|
|
410
|
+
logger.info("Calculating EVENT-BASED seizure prediction metrics")
|
|
411
|
+
metrics_event = calc_seizure_event_prediction_metrics(
|
|
412
|
+
y_true, y_pred, metadata, window_duration_min
|
|
413
|
+
)
|
|
414
|
+
|
|
415
|
+
# Print event-based results
|
|
416
|
+
logger.info("=" * 70)
|
|
417
|
+
logger.info("EVENT-BASED Metrics (Did we detect each seizure event?)")
|
|
418
|
+
logger.info("=" * 70)
|
|
419
|
+
logger.info(f"Seizure Sensitivity: {metrics_event['seizure_sensitivity']:.1f}%")
|
|
420
|
+
logger.info(f"False Positives/Hour: {metrics_event['fp_per_hour']:.3f}")
|
|
421
|
+
logger.info(f"Time in Warning: {metrics_event['time_in_warning']:.1f}%")
|
|
422
|
+
logger.info("")
|
|
423
|
+
logger.info("Counts:")
|
|
424
|
+
logger.info(f" Seizure events: {metrics_event['n_seizure_events']}")
|
|
425
|
+
logger.info(f" Detected events: {metrics_event['n_detected_events']}")
|
|
426
|
+
logger.info(f" Missed events: {metrics_event['n_missed_events']}")
|
|
427
|
+
logger.info(f" Interictal windows: {metrics_event['n_interictal_windows']}")
|
|
428
|
+
logger.info(f" False positives: {metrics_event['n_false_positives']}")
|
|
429
|
+
logger.info(f" True negatives: {metrics_event['n_true_negatives']}")
|
|
430
|
+
logger.info("")
|
|
431
|
+
logger.info("Clinical Targets (FDA Guidelines):")
|
|
432
|
+
logger.info(
|
|
433
|
+
f" Meets sensitivity target (≥90%): {metrics_event['meets_sensitivity_target']}"
|
|
434
|
+
)
|
|
435
|
+
logger.info(f" Meets FP/h target (≤0.2): {metrics_event['meets_fp_target']}")
|
|
436
|
+
logger.info(f" Meets time in warning target (≤20%): {metrics_event['meets_tiw_target']}")
|
|
437
|
+
logger.info("=" * 70)
|
|
438
|
+
|
|
439
|
+
# Comparison summary
|
|
440
|
+
logger.info("")
|
|
441
|
+
logger.info("=" * 70)
|
|
442
|
+
logger.info("KEY DIFFERENCE DEMONSTRATION")
|
|
443
|
+
logger.info("=" * 70)
|
|
444
|
+
logger.info(f"Window-based sensitivity: {metrics_window['seizure_sensitivity']:.1f}% (detected {metrics_window['n_true_positives']}/{metrics_window['n_seizure_windows']} windows)")
|
|
445
|
+
logger.info(f"Event-based sensitivity: {metrics_event['seizure_sensitivity']:.1f}% (detected {metrics_event['n_detected_events']}/{metrics_event['n_seizure_events']} events)")
|
|
446
|
+
logger.info("")
|
|
447
|
+
logger.info("Interpretation:")
|
|
448
|
+
logger.info(" - Window-based: Detected only 1 window from Event 1 → Low sensitivity")
|
|
449
|
+
logger.info(" - Event-based: Detected at least 1 window from BOTH events → 100% sensitivity!")
|
|
450
|
+
logger.info(" - Clinical relevance: One timely alarm per seizure is sufficient")
|
|
451
|
+
logger.info("=" * 70)
|
|
452
|
+
|
|
453
|
+
return 0
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
def run_main():
|
|
457
|
+
"""Initialize scitex framework, run main function, and cleanup."""
|
|
458
|
+
global CONFIG, CC, sys, plt, rng
|
|
459
|
+
|
|
460
|
+
import sys
|
|
461
|
+
import matplotlib.pyplot as plt
|
|
462
|
+
import scitex as stx
|
|
463
|
+
|
|
464
|
+
args = parse_args()
|
|
465
|
+
|
|
466
|
+
CONFIG, sys.stdout, sys.stderr, plt, CC, rng = stx.session.start(
|
|
467
|
+
sys,
|
|
468
|
+
plt,
|
|
469
|
+
args=args,
|
|
470
|
+
file=__file__,
|
|
471
|
+
sdir_suffix=None,
|
|
472
|
+
verbose=False,
|
|
473
|
+
agg=True,
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
exit_status = main(args)
|
|
477
|
+
|
|
478
|
+
stx.session.close(
|
|
479
|
+
CONFIG,
|
|
480
|
+
verbose=False,
|
|
481
|
+
notify=False,
|
|
482
|
+
message="",
|
|
483
|
+
exit_status=exit_status,
|
|
484
|
+
)
|
|
485
|
+
|
|
486
|
+
|
|
487
|
+
if __name__ == "__main__":
|
|
488
|
+
run_main()
|
|
489
|
+
|
|
490
|
+
# EOF
|