dslighting 1.7.1__py3-none-any.whl → 1.7.6__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.
- dslighting/__init__.py +1 -1
- dslighting/core/agent.py +78 -62
- {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/METADATA +1 -1
- {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/RECORD +352 -7
- {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/top_level.txt +1 -0
- mlebench/README.md +39 -0
- mlebench/__init__.py +0 -0
- mlebench/cli.py +221 -0
- mlebench/competitions/3d-object-detection-for-autonomous-vehicles/grade.py +161 -0
- mlebench/competitions/3d-object-detection-for-autonomous-vehicles/mAP_evaluation.py +425 -0
- mlebench/competitions/3d-object-detection-for-autonomous-vehicles/prepare.py +483 -0
- mlebench/competitions/3d-object-detection-for-autonomous-vehicles/prepare_val.py +719 -0
- mlebench/competitions/AI4Code/grade.py +70 -0
- mlebench/competitions/AI4Code/prepare.py +84 -0
- mlebench/competitions/AI4Code/prepare_val.py +159 -0
- mlebench/competitions/__init__.py +0 -0
- mlebench/competitions/aerial-cactus-identification/grade.py +11 -0
- mlebench/competitions/aerial-cactus-identification/prepare.py +71 -0
- mlebench/competitions/aerial-cactus-identification/prepare_val.py +133 -0
- mlebench/competitions/alaska2-image-steganalysis/grade.py +136 -0
- mlebench/competitions/alaska2-image-steganalysis/prepare.py +88 -0
- mlebench/competitions/alaska2-image-steganalysis/prepare_val.py +148 -0
- mlebench/competitions/aptos2019-blindness-detection/grade.py +35 -0
- mlebench/competitions/aptos2019-blindness-detection/prepare.py +75 -0
- mlebench/competitions/aptos2019-blindness-detection/prepare_val.py +123 -0
- mlebench/competitions/bike-sharing-demand/__init__.py +0 -0
- mlebench/competitions/bike-sharing-demand/grade.py +55 -0
- mlebench/competitions/bike-sharing-demand/prepare.py +37 -0
- mlebench/competitions/billion-word-imputation/grade.py +37 -0
- mlebench/competitions/billion-word-imputation/prepare.py +107 -0
- mlebench/competitions/billion-word-imputation/prepare_val.py +179 -0
- mlebench/competitions/bms-molecular-translation/grade.py +40 -0
- mlebench/competitions/bms-molecular-translation/prepare.py +68 -0
- mlebench/competitions/bms-molecular-translation/prepare_val.py +131 -0
- mlebench/competitions/cassava-leaf-disease-classification/grade.py +12 -0
- mlebench/competitions/cassava-leaf-disease-classification/prepare.py +113 -0
- mlebench/competitions/cassava-leaf-disease-classification/prepare_val.py +186 -0
- mlebench/competitions/cdiscount-image-classification-challenge/grade.py +11 -0
- mlebench/competitions/cdiscount-image-classification-challenge/prepare.py +144 -0
- mlebench/competitions/cdiscount-image-classification-challenge/prepare_val.py +205 -0
- mlebench/competitions/chaii-hindi-and-tamil-question-answering/grade.py +67 -0
- mlebench/competitions/chaii-hindi-and-tamil-question-answering/prepare.py +31 -0
- mlebench/competitions/chaii-hindi-and-tamil-question-answering/prepare_val.py +94 -0
- mlebench/competitions/champs-scalar-coupling/grade.py +60 -0
- mlebench/competitions/champs-scalar-coupling/prepare.py +116 -0
- mlebench/competitions/champs-scalar-coupling/prepare_val.py +155 -0
- mlebench/competitions/conways-reverse-game-of-life-2020/__init__.py +0 -0
- mlebench/competitions/conways-reverse-game-of-life-2020/grade.py +40 -0
- mlebench/competitions/conways-reverse-game-of-life-2020/prepare.py +41 -0
- mlebench/competitions/demand-forecasting-kernels-only/__init__.py +0 -0
- mlebench/competitions/demand-forecasting-kernels-only/grade.py +66 -0
- mlebench/competitions/demand-forecasting-kernels-only/prepare.py +27 -0
- mlebench/competitions/demand_forecasting_kernels_only/__init__.py +0 -0
- mlebench/competitions/demand_forecasting_kernels_only/grade.py +66 -0
- mlebench/competitions/demand_forecasting_kernels_only/prepare.py +27 -0
- mlebench/competitions/denoising-dirty-documents/grade.py +44 -0
- mlebench/competitions/denoising-dirty-documents/prepare.py +134 -0
- mlebench/competitions/denoising-dirty-documents/prepare_val.py +178 -0
- mlebench/competitions/detecting-insults-in-social-commentary/grade.py +11 -0
- mlebench/competitions/detecting-insults-in-social-commentary/prepare.py +72 -0
- mlebench/competitions/detecting-insults-in-social-commentary/prepare_val.py +128 -0
- mlebench/competitions/dog-breed-identification/dogs.py +124 -0
- mlebench/competitions/dog-breed-identification/grade.py +42 -0
- mlebench/competitions/dog-breed-identification/prepare.py +55 -0
- mlebench/competitions/dog-breed-identification/prepare_val.py +104 -0
- mlebench/competitions/dogs-vs-cats-redux-kernels-edition/grade.py +43 -0
- mlebench/competitions/dogs-vs-cats-redux-kernels-edition/prepare.py +70 -0
- mlebench/competitions/dogs-vs-cats-redux-kernels-edition/prepare_val.py +143 -0
- mlebench/competitions/ethanol-concentration/grade.py +23 -0
- mlebench/competitions/ethanol-concentration/prepare.py +90 -0
- mlebench/competitions/facebook-recruiting-iii-keyword-extraction/grade.py +60 -0
- mlebench/competitions/facebook-recruiting-iii-keyword-extraction/prepare.py +41 -0
- mlebench/competitions/facebook-recruiting-iii-keyword-extraction/prepare_val.py +92 -0
- mlebench/competitions/feedback-prize-english-language-learning/__init__.py +0 -0
- mlebench/competitions/feedback-prize-english-language-learning/grade.py +60 -0
- mlebench/competitions/feedback-prize-english-language-learning/prepare.py +39 -0
- mlebench/competitions/freesound-audio-tagging-2019/grade.py +64 -0
- mlebench/competitions/freesound-audio-tagging-2019/prepare.py +94 -0
- mlebench/competitions/freesound-audio-tagging-2019/prepare_val.py +175 -0
- mlebench/competitions/freesound-audio-tagging-2019/vocabulary.py +83 -0
- mlebench/competitions/google-quest-challenge/classes.py +32 -0
- mlebench/competitions/google-quest-challenge/grade.py +45 -0
- mlebench/competitions/google-quest-challenge/prepare.py +58 -0
- mlebench/competitions/google-quest-challenge/prepare_val.py +120 -0
- mlebench/competitions/google-research-identify-contrails-reduce-global-warming/grade.py +77 -0
- mlebench/competitions/google-research-identify-contrails-reduce-global-warming/prepare.py +155 -0
- mlebench/competitions/google-research-identify-contrails-reduce-global-warming/prepare_val.py +211 -0
- mlebench/competitions/h-and-m-personalized-fashion-recommendations/grade.py +42 -0
- mlebench/competitions/h-and-m-personalized-fashion-recommendations/prepare.py +102 -0
- mlebench/competitions/h-and-m-personalized-fashion-recommendations/prepare_val.py +132 -0
- mlebench/competitions/handwriting/grade.py +23 -0
- mlebench/competitions/handwriting/prepare.py +179 -0
- mlebench/competitions/herbarium-2020-fgvc7/grade.py +34 -0
- mlebench/competitions/herbarium-2020-fgvc7/prepare.py +251 -0
- mlebench/competitions/herbarium-2020-fgvc7/prepare_val.py +242 -0
- mlebench/competitions/herbarium-2021-fgvc8/grade.py +34 -0
- mlebench/competitions/herbarium-2021-fgvc8/prepare.py +251 -0
- mlebench/competitions/herbarium-2021-fgvc8/prepare_val.py +222 -0
- mlebench/competitions/herbarium-2022-fgvc9/grade.py +31 -0
- mlebench/competitions/herbarium-2022-fgvc9/prepare.py +233 -0
- mlebench/competitions/herbarium-2022-fgvc9/prepare_val.py +213 -0
- mlebench/competitions/histopathologic-cancer-detection/grade.py +12 -0
- mlebench/competitions/histopathologic-cancer-detection/prepare.py +59 -0
- mlebench/competitions/histopathologic-cancer-detection/prepare_val.py +131 -0
- mlebench/competitions/hms-harmful-brain-activity-classification/constants.py +9 -0
- mlebench/competitions/hms-harmful-brain-activity-classification/grade.py +43 -0
- mlebench/competitions/hms-harmful-brain-activity-classification/kaggle_metric_utilities.py +96 -0
- mlebench/competitions/hms-harmful-brain-activity-classification/kullback_leibler_divergence.py +118 -0
- mlebench/competitions/hms-harmful-brain-activity-classification/prepare.py +121 -0
- mlebench/competitions/hms-harmful-brain-activity-classification/prepare_val.py +190 -0
- mlebench/competitions/hotel-id-2021-fgvc8/grade.py +41 -0
- mlebench/competitions/hotel-id-2021-fgvc8/prepare.py +63 -0
- mlebench/competitions/hotel-id-2021-fgvc8/prepare_val.py +132 -0
- mlebench/competitions/hubmap-kidney-segmentation/grade.py +62 -0
- mlebench/competitions/hubmap-kidney-segmentation/prepare.py +108 -0
- mlebench/competitions/hubmap-kidney-segmentation/prepare_val.py +153 -0
- mlebench/competitions/icecube-neutrinos-in-deep-ice/grade.py +111 -0
- mlebench/competitions/icecube-neutrinos-in-deep-ice/prepare.py +127 -0
- mlebench/competitions/icecube-neutrinos-in-deep-ice/prepare_val.py +183 -0
- mlebench/competitions/ili/grade.py +60 -0
- mlebench/competitions/ili/prepare.py +99 -0
- mlebench/competitions/imet-2020-fgvc7/grade.py +54 -0
- mlebench/competitions/imet-2020-fgvc7/prepare.py +77 -0
- mlebench/competitions/imet-2020-fgvc7/prepare_val.py +157 -0
- mlebench/competitions/inaturalist-2019-fgvc6/grade.py +35 -0
- mlebench/competitions/inaturalist-2019-fgvc6/prepare.py +259 -0
- mlebench/competitions/inaturalist-2019-fgvc6/prepare_val.py +304 -0
- mlebench/competitions/instant-gratification/__init__.py +0 -0
- mlebench/competitions/instant-gratification/grade.py +55 -0
- mlebench/competitions/instant-gratification/prepare.py +25 -0
- mlebench/competitions/instant_gratification/__init__.py +0 -0
- mlebench/competitions/instant_gratification/grade.py +55 -0
- mlebench/competitions/instant_gratification/prepare.py +25 -0
- mlebench/competitions/invasive-species-monitoring/grade.py +11 -0
- mlebench/competitions/invasive-species-monitoring/prepare.py +97 -0
- mlebench/competitions/invasive-species-monitoring/prepare_val.py +164 -0
- mlebench/competitions/iwildcam-2019-fgvc6/grade.py +44 -0
- mlebench/competitions/iwildcam-2019-fgvc6/prepare.py +118 -0
- mlebench/competitions/iwildcam-2019-fgvc6/prepare_val.py +194 -0
- mlebench/competitions/iwildcam-2020-fgvc7/grade.py +11 -0
- mlebench/competitions/iwildcam-2020-fgvc7/prepare.py +164 -0
- mlebench/competitions/iwildcam-2020-fgvc7/prepare_val.py +245 -0
- mlebench/competitions/jigsaw-toxic-comment-classification-challenge/classes.py +1 -0
- mlebench/competitions/jigsaw-toxic-comment-classification-challenge/grade.py +54 -0
- mlebench/competitions/jigsaw-toxic-comment-classification-challenge/prepare.py +42 -0
- mlebench/competitions/jigsaw-toxic-comment-classification-challenge/prepare_val.py +88 -0
- mlebench/competitions/jigsaw-unintended-bias-in-toxicity-classification/grade.py +153 -0
- mlebench/competitions/jigsaw-unintended-bias-in-toxicity-classification/prepare.py +36 -0
- mlebench/competitions/jigsaw-unintended-bias-in-toxicity-classification/prepare_val.py +117 -0
- mlebench/competitions/kuzushiji-recognition/grade.py +58 -0
- mlebench/competitions/kuzushiji-recognition/kuzushiji_metric.py +118 -0
- mlebench/competitions/kuzushiji-recognition/prepare.py +92 -0
- mlebench/competitions/kuzushiji-recognition/prepare_val.py +149 -0
- mlebench/competitions/leaf-classification/classes.py +101 -0
- mlebench/competitions/leaf-classification/grade.py +44 -0
- mlebench/competitions/leaf-classification/prepare.py +60 -0
- mlebench/competitions/leaf-classification/prepare_val.py +116 -0
- mlebench/competitions/learning-agency-lab-automated-essay-scoring-2/grade.py +44 -0
- mlebench/competitions/learning-agency-lab-automated-essay-scoring-2/prepare.py +51 -0
- mlebench/competitions/learning-agency-lab-automated-essay-scoring-2/prepare_val.py +96 -0
- mlebench/competitions/liverpool-ion-switching/__init__.py +0 -0
- mlebench/competitions/liverpool-ion-switching/grade.py +52 -0
- mlebench/competitions/liverpool-ion-switching/prepare.py +27 -0
- mlebench/competitions/liverpool_ion_switching/__init__.py +0 -0
- mlebench/competitions/liverpool_ion_switching/grade.py +52 -0
- mlebench/competitions/liverpool_ion_switching/prepare.py +27 -0
- mlebench/competitions/lmsys-chatbot-arena/grade.py +63 -0
- mlebench/competitions/lmsys-chatbot-arena/prepare.py +52 -0
- mlebench/competitions/lmsys-chatbot-arena/prepare_val.py +115 -0
- mlebench/competitions/mcm_2024_c_test/grade.py +107 -0
- mlebench/competitions/mcm_2024_c_test/prepare.py +2 -0
- mlebench/competitions/ml2021spring-hw2/grade.py +11 -0
- mlebench/competitions/ml2021spring-hw2/prepare.py +58 -0
- mlebench/competitions/ml2021spring-hw2/prepare_val.py +135 -0
- mlebench/competitions/mlsp-2013-birds/grade.py +11 -0
- mlebench/competitions/mlsp-2013-birds/prepare.py +182 -0
- mlebench/competitions/mlsp-2013-birds/prepare_val.py +241 -0
- mlebench/competitions/movie-review-sentiment-analysis-kernels-only/grade.py +11 -0
- mlebench/competitions/movie-review-sentiment-analysis-kernels-only/prepare.py +58 -0
- mlebench/competitions/movie-review-sentiment-analysis-kernels-only/prepare_val.py +120 -0
- mlebench/competitions/multi-modal-gesture-recognition/grade.py +58 -0
- mlebench/competitions/multi-modal-gesture-recognition/prepare.py +85 -0
- mlebench/competitions/multi-modal-gesture-recognition/prepare_val.py +139 -0
- mlebench/competitions/my-custom-task-01/prepare.py +2 -0
- mlebench/competitions/new-my-task-01/prepare.py +2 -0
- mlebench/competitions/new-my-task-03/grade.py +107 -0
- mlebench/competitions/new-my-task-03/prepare.py +2 -0
- mlebench/competitions/new-york-city-taxi-fare-prediction/grade.py +28 -0
- mlebench/competitions/new-york-city-taxi-fare-prediction/prepare.py +44 -0
- mlebench/competitions/new-york-city-taxi-fare-prediction/prepare_val.py +89 -0
- mlebench/competitions/nfl-player-contact-detection/grade.py +36 -0
- mlebench/competitions/nfl-player-contact-detection/prepare.py +101 -0
- mlebench/competitions/nfl-player-contact-detection/prepare_val.py +186 -0
- mlebench/competitions/nomad2018-predict-transparent-conductors/grade.py +47 -0
- mlebench/competitions/nomad2018-predict-transparent-conductors/prepare.py +77 -0
- mlebench/competitions/nomad2018-predict-transparent-conductors/prepare_val.py +144 -0
- mlebench/competitions/osic-pulmonary-fibrosis-progression/grade.py +74 -0
- mlebench/competitions/osic-pulmonary-fibrosis-progression/prepare.py +95 -0
- mlebench/competitions/osic-pulmonary-fibrosis-progression/prepare_val.py +167 -0
- mlebench/competitions/paddy-disease-classification/grade.py +35 -0
- mlebench/competitions/paddy-disease-classification/prepare.py +69 -0
- mlebench/competitions/paddy-disease-classification/prepare_val.py +122 -0
- mlebench/competitions/petfinder-pawpularity-score/grade.py +41 -0
- mlebench/competitions/petfinder-pawpularity-score/prepare.py +76 -0
- mlebench/competitions/petfinder-pawpularity-score/prepare_val.py +154 -0
- mlebench/competitions/plant-pathology-2020-fgvc7/grade.py +41 -0
- mlebench/competitions/plant-pathology-2020-fgvc7/prepare.py +74 -0
- mlebench/competitions/plant-pathology-2020-fgvc7/prepare_val.py +160 -0
- mlebench/competitions/plant-pathology-2021-fgvc8/grade.py +54 -0
- mlebench/competitions/plant-pathology-2021-fgvc8/prepare.py +65 -0
- mlebench/competitions/plant-pathology-2021-fgvc8/prepare_val.py +130 -0
- mlebench/competitions/plant-seedlings-classification/grade.py +39 -0
- mlebench/competitions/plant-seedlings-classification/prepare.py +91 -0
- mlebench/competitions/plant-seedlings-classification/prepare_val.py +158 -0
- mlebench/competitions/playground-series-s3e1/__init__.py +0 -0
- mlebench/competitions/playground-series-s3e1/grade.py +52 -0
- mlebench/competitions/playground-series-s3e1/prepare.py +25 -0
- mlebench/competitions/playground-series-s3e11/__init__.py +0 -0
- mlebench/competitions/playground-series-s3e11/grade.py +55 -0
- mlebench/competitions/playground-series-s3e11/prepare.py +25 -0
- mlebench/competitions/playground-series-s3e18/grade.py +39 -0
- mlebench/competitions/playground-series-s3e18/prepare.py +36 -0
- mlebench/competitions/playground-series-s3e18/prepare_val.py +89 -0
- mlebench/competitions/playground_series_s3e1/__init__.py +0 -0
- mlebench/competitions/playground_series_s3e1/grade.py +52 -0
- mlebench/competitions/playground_series_s3e1/prepare.py +25 -0
- mlebench/competitions/playground_series_s3e11/__init__.py +0 -0
- mlebench/competitions/playground_series_s3e11/grade.py +55 -0
- mlebench/competitions/playground_series_s3e11/prepare.py +25 -0
- mlebench/competitions/predict-volcanic-eruptions-ingv-oe/grade.py +44 -0
- mlebench/competitions/predict-volcanic-eruptions-ingv-oe/prepare.py +68 -0
- mlebench/competitions/predict-volcanic-eruptions-ingv-oe/prepare_val.py +146 -0
- mlebench/competitions/random-acts-of-pizza/grade.py +14 -0
- mlebench/competitions/random-acts-of-pizza/prepare.py +80 -0
- mlebench/competitions/random-acts-of-pizza/prepare_val.py +144 -0
- mlebench/competitions/ranzcr-clip-catheter-line-classification/classes.py +11 -0
- mlebench/competitions/ranzcr-clip-catheter-line-classification/grade.py +31 -0
- mlebench/competitions/ranzcr-clip-catheter-line-classification/prepare.py +53 -0
- mlebench/competitions/ranzcr-clip-catheter-line-classification/prepare_val.py +113 -0
- mlebench/competitions/rsna-2022-cervical-spine-fracture-detection/grade.py +124 -0
- mlebench/competitions/rsna-2022-cervical-spine-fracture-detection/prepare.py +219 -0
- mlebench/competitions/rsna-2022-cervical-spine-fracture-detection/prepare_val.py +257 -0
- mlebench/competitions/rsna-breast-cancer-detection/grade.py +65 -0
- mlebench/competitions/rsna-breast-cancer-detection/prepare.py +141 -0
- mlebench/competitions/rsna-breast-cancer-detection/prepare_val.py +201 -0
- mlebench/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/grade.py +13 -0
- mlebench/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/prepare.py +47 -0
- mlebench/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/prepare_val.py +97 -0
- mlebench/competitions/santander-customer-satisfaction/grade.py +10 -0
- mlebench/competitions/santander-customer-satisfaction/prepare.py +41 -0
- mlebench/competitions/sciencebench-001-clintox-nn/__init__.py +0 -0
- mlebench/competitions/sciencebench-001-clintox-nn/grade.py +56 -0
- mlebench/competitions/sciencebench-001-clintox-nn/prepare.py +75 -0
- mlebench/competitions/sciencebench-015-aai/grade.py +37 -0
- mlebench/competitions/sciencebench-015-aai/prepare.py +102 -0
- mlebench/competitions/sciencebench-051-brain-blood-qsar/grade.py +58 -0
- mlebench/competitions/sciencebench-051-brain-blood-qsar/prepare.py +69 -0
- mlebench/competitions/sciencebench-101-experimental-band-gap-prediction/grade.py +55 -0
- mlebench/competitions/sciencebench-101-experimental-band-gap-prediction/prepare.py +88 -0
- mlebench/competitions/see-click-predict-fix/__init__.py +0 -0
- mlebench/competitions/see-click-predict-fix/grade.py +66 -0
- mlebench/competitions/see-click-predict-fix/prepare.py +25 -0
- mlebench/competitions/see_click_predict_fix/__init__.py +0 -0
- mlebench/competitions/see_click_predict_fix/grade.py +66 -0
- mlebench/competitions/see_click_predict_fix/prepare.py +25 -0
- mlebench/competitions/seti-breakthrough-listen/grade.py +11 -0
- mlebench/competitions/seti-breakthrough-listen/prepare.py +71 -0
- mlebench/competitions/seti-breakthrough-listen/prepare_val.py +159 -0
- mlebench/competitions/siim-covid19-detection/grade.py +194 -0
- mlebench/competitions/siim-covid19-detection/prepare.py +123 -0
- mlebench/competitions/siim-covid19-detection/prepare_val.py +164 -0
- mlebench/competitions/siim-isic-melanoma-classification/grade.py +11 -0
- mlebench/competitions/siim-isic-melanoma-classification/prepare.py +127 -0
- mlebench/competitions/siim-isic-melanoma-classification/prepare_val.py +158 -0
- mlebench/competitions/smartphone-decimeter-2022/grade.py +55 -0
- mlebench/competitions/smartphone-decimeter-2022/notebook.py +86 -0
- mlebench/competitions/smartphone-decimeter-2022/prepare.py +143 -0
- mlebench/competitions/smartphone-decimeter-2022/prepare_val.py +199 -0
- mlebench/competitions/spaceship-titanic/grade.py +11 -0
- mlebench/competitions/spaceship-titanic/prepare.py +23 -0
- mlebench/competitions/spaceship-titanic/prepare_val.py +61 -0
- mlebench/competitions/spooky-author-identification/classes.py +1 -0
- mlebench/competitions/spooky-author-identification/grade.py +38 -0
- mlebench/competitions/spooky-author-identification/prepare.py +40 -0
- mlebench/competitions/spooky-author-identification/prepare_val.py +78 -0
- mlebench/competitions/stanford-covid-vaccine/grade.py +65 -0
- mlebench/competitions/stanford-covid-vaccine/prepare.py +129 -0
- mlebench/competitions/stanford-covid-vaccine/prepare_val.py +199 -0
- mlebench/competitions/statoil-iceberg-classifier-challenge/grade.py +41 -0
- mlebench/competitions/statoil-iceberg-classifier-challenge/prepare.py +105 -0
- mlebench/competitions/statoil-iceberg-classifier-challenge/prepare_val.py +157 -0
- mlebench/competitions/tabular-playground-series-dec-2021/grade.py +11 -0
- mlebench/competitions/tabular-playground-series-dec-2021/prepare.py +39 -0
- mlebench/competitions/tabular-playground-series-dec-2021/prepare_val.py +99 -0
- mlebench/competitions/tabular-playground-series-may-2022/grade.py +9 -0
- mlebench/competitions/tabular-playground-series-may-2022/prepare.py +56 -0
- mlebench/competitions/tabular-playground-series-may-2022/prepare_val.py +116 -0
- mlebench/competitions/tensorflow-speech-recognition-challenge/grade.py +11 -0
- mlebench/competitions/tensorflow-speech-recognition-challenge/prepare.py +90 -0
- mlebench/competitions/tensorflow-speech-recognition-challenge/prepare_val.py +148 -0
- mlebench/competitions/tensorflow2-question-answering/grade.py +122 -0
- mlebench/competitions/tensorflow2-question-answering/prepare.py +122 -0
- mlebench/competitions/tensorflow2-question-answering/prepare_val.py +187 -0
- mlebench/competitions/text-normalization-challenge-english-language/grade.py +49 -0
- mlebench/competitions/text-normalization-challenge-english-language/prepare.py +115 -0
- mlebench/competitions/text-normalization-challenge-english-language/prepare_val.py +213 -0
- mlebench/competitions/text-normalization-challenge-russian-language/grade.py +49 -0
- mlebench/competitions/text-normalization-challenge-russian-language/prepare.py +113 -0
- mlebench/competitions/text-normalization-challenge-russian-language/prepare_val.py +165 -0
- mlebench/competitions/tgs-salt-identification-challenge/grade.py +144 -0
- mlebench/competitions/tgs-salt-identification-challenge/prepare.py +158 -0
- mlebench/competitions/tgs-salt-identification-challenge/prepare_val.py +166 -0
- mlebench/competitions/the-icml-2013-whale-challenge-right-whale-redux/grade.py +11 -0
- mlebench/competitions/the-icml-2013-whale-challenge-right-whale-redux/prepare.py +95 -0
- mlebench/competitions/the-icml-2013-whale-challenge-right-whale-redux/prepare_val.py +141 -0
- mlebench/competitions/tmdb-box-office-prediction/__init__.py +0 -0
- mlebench/competitions/tmdb-box-office-prediction/grade.py +55 -0
- mlebench/competitions/tmdb-box-office-prediction/prepare.py +35 -0
- mlebench/competitions/tweet-sentiment-extraction/grade.py +67 -0
- mlebench/competitions/tweet-sentiment-extraction/prepare.py +36 -0
- mlebench/competitions/tweet-sentiment-extraction/prepare_val.py +106 -0
- mlebench/competitions/us-patent-phrase-to-phrase-matching/grade.py +31 -0
- mlebench/competitions/us-patent-phrase-to-phrase-matching/prepare.py +33 -0
- mlebench/competitions/us-patent-phrase-to-phrase-matching/prepare_val.py +71 -0
- mlebench/competitions/utils.py +266 -0
- mlebench/competitions/uw-madison-gi-tract-image-segmentation/grade.py +158 -0
- mlebench/competitions/uw-madison-gi-tract-image-segmentation/prepare.py +139 -0
- mlebench/competitions/uw-madison-gi-tract-image-segmentation/prepare_val.py +193 -0
- mlebench/competitions/ventilator-pressure-prediction/__init__.py +0 -0
- mlebench/competitions/ventilator-pressure-prediction/grade.py +52 -0
- mlebench/competitions/ventilator-pressure-prediction/prepare.py +27 -0
- mlebench/competitions/ventilator-pressure-prediction/prepare_val.py +142 -0
- mlebench/competitions/ventilator_pressure_prediction/__init__.py +0 -0
- mlebench/competitions/ventilator_pressure_prediction/grade.py +52 -0
- mlebench/competitions/ventilator_pressure_prediction/prepare.py +27 -0
- mlebench/competitions/vesuvius-challenge-ink-detection/grade.py +97 -0
- mlebench/competitions/vesuvius-challenge-ink-detection/prepare.py +122 -0
- mlebench/competitions/vesuvius-challenge-ink-detection/prepare_val.py +170 -0
- mlebench/competitions/vinbigdata-chest-xray-abnormalities-detection/grade.py +220 -0
- mlebench/competitions/vinbigdata-chest-xray-abnormalities-detection/prepare.py +129 -0
- mlebench/competitions/vinbigdata-chest-xray-abnormalities-detection/prepare_val.py +204 -0
- mlebench/competitions/whale-categorization-playground/grade.py +41 -0
- mlebench/competitions/whale-categorization-playground/prepare.py +103 -0
- mlebench/competitions/whale-categorization-playground/prepare_val.py +196 -0
- mlebench/data.py +420 -0
- mlebench/grade.py +209 -0
- mlebench/grade_helpers.py +235 -0
- mlebench/metrics.py +75 -0
- mlebench/registry.py +332 -0
- mlebench/utils.py +346 -0
- {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/WHEEL +0 -0
- {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from bisect import bisect
|
|
2
|
+
from typing import Any
|
|
3
|
+
|
|
4
|
+
import pandas as pd
|
|
5
|
+
|
|
6
|
+
from mlebench.grade_helpers import InvalidSubmissionError
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def kendall_tau(ground_truth: list[list[Any]], predictions: list[list[Any]]) -> float:
|
|
10
|
+
"""
|
|
11
|
+
Computes the Kendall Tau correlation between
|
|
12
|
+
- `ground_truth`: a list of lists, where each sublist contains the ground truth order of items
|
|
13
|
+
- `predictions`: a list of lists, where each sublist contains the predicted order of items
|
|
14
|
+
|
|
15
|
+
See: https://www.kaggle.com/code/ryanholbrook/competition-metric-kendall-tau-correlation
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
# Actually O(N^2), but fast in practice for our data
|
|
19
|
+
def count_inversions(a):
|
|
20
|
+
inversions = 0
|
|
21
|
+
sorted_so_far = []
|
|
22
|
+
for i, u in enumerate(a): # O(N)
|
|
23
|
+
j = bisect(sorted_so_far, u) # O(log N)
|
|
24
|
+
inversions += i - j
|
|
25
|
+
sorted_so_far.insert(j, u) # O(N)
|
|
26
|
+
return inversions
|
|
27
|
+
|
|
28
|
+
total_inversions = 0 # total inversions in predicted ranks across all instances
|
|
29
|
+
total_2max = 0 # maximum possible inversions across all instances
|
|
30
|
+
for gt, pred in zip(ground_truth, predictions):
|
|
31
|
+
ranks = [gt.index(x) for x in pred] # rank predicted order in terms of ground truth
|
|
32
|
+
total_inversions += count_inversions(ranks)
|
|
33
|
+
n = len(gt)
|
|
34
|
+
total_2max += n * (n - 1)
|
|
35
|
+
return 1 - 4 * total_inversions / total_2max
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def prepare_for_metric(submission: pd.DataFrame, answers: pd.DataFrame) -> dict:
|
|
39
|
+
if len(submission) != len(answers):
|
|
40
|
+
raise InvalidSubmissionError("Submission and answers must have the same length")
|
|
41
|
+
if "id" not in submission.columns or "cell_order" not in submission.columns:
|
|
42
|
+
raise InvalidSubmissionError("Submission must have 'id' and 'cell_order' columns")
|
|
43
|
+
if set(submission["id"]) != set(answers["id"]):
|
|
44
|
+
raise InvalidSubmissionError("Submission and answers must have the same ids")
|
|
45
|
+
# "cell_order" columns must be strings of space-separated cell ids: "54c7cab3 fe66203e 7844d5f8 ..."
|
|
46
|
+
submission["cell_order"] = submission["cell_order"].astype(str)
|
|
47
|
+
answers["cell_order"] = answers["cell_order"].astype(str)
|
|
48
|
+
|
|
49
|
+
# Sort by id to ensure we're comparing the same rows
|
|
50
|
+
submission = submission.sort_values("id")
|
|
51
|
+
answers = answers.sort_values("id")
|
|
52
|
+
|
|
53
|
+
ground_truth, predictions = [], []
|
|
54
|
+
target_column = "cell_order"
|
|
55
|
+
for (_, row_gt), (_, row_pred) in zip(submission.iterrows(), answers.iterrows()):
|
|
56
|
+
ground_truth_items = row_gt[target_column].split()
|
|
57
|
+
prediction_items = row_pred[target_column].split()
|
|
58
|
+
if len(ground_truth_items) != len(prediction_items):
|
|
59
|
+
raise InvalidSubmissionError("Ground truth and predictions must have the same length")
|
|
60
|
+
ground_truth.append(ground_truth_items)
|
|
61
|
+
predictions.append(prediction_items)
|
|
62
|
+
return {
|
|
63
|
+
"ground_truth": ground_truth,
|
|
64
|
+
"predictions": predictions,
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def grade(submission: pd.DataFrame, answers: pd.DataFrame) -> float:
|
|
69
|
+
kendall_tau_inputs = prepare_for_metric(submission, answers)
|
|
70
|
+
return kendall_tau(**kendall_tau_inputs)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import shutil
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from tqdm.auto import tqdm
|
|
7
|
+
|
|
8
|
+
from mlebench.utils import read_csv
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Create train, test from train split
|
|
12
|
+
def create_train_test_split(train_ancestors_df: pd.DataFrame, test_size: int):
|
|
13
|
+
"""
|
|
14
|
+
On Kaggle, a user may "fork" (that is, copy) the notebook of another user to create their own version.
|
|
15
|
+
`train_ancestors_df` contains information about the ancestry of each notebook in the training set.
|
|
16
|
+
|
|
17
|
+
To create the test split, we select rows from the train set that don't share ancestors with any others
|
|
18
|
+
so that there aren't any relatives in the train set. The train split is the remaining rows.
|
|
19
|
+
"""
|
|
20
|
+
group_by_ancestor = {}
|
|
21
|
+
for _, row in tqdm(
|
|
22
|
+
train_ancestors_df.iterrows(), desc="Grouping by Ancestor", total=len(train_ancestors_df)
|
|
23
|
+
):
|
|
24
|
+
ancestor_id = row["ancestor_id"]
|
|
25
|
+
if ancestor_id not in group_by_ancestor:
|
|
26
|
+
group_by_ancestor[ancestor_id] = []
|
|
27
|
+
group_by_ancestor[ancestor_id].append(row)
|
|
28
|
+
|
|
29
|
+
train_ids = []
|
|
30
|
+
test_ids = []
|
|
31
|
+
num_test_ids = 0
|
|
32
|
+
for ancestor_id, rows in tqdm(group_by_ancestor.items(), desc="Splitting on Ancestors"):
|
|
33
|
+
if num_test_ids + len(rows) <= test_size:
|
|
34
|
+
test_ids.extend(([row["id"] for row in rows]))
|
|
35
|
+
num_test_ids += len(rows)
|
|
36
|
+
else:
|
|
37
|
+
train_ids.extend([row["id"] for row in rows])
|
|
38
|
+
|
|
39
|
+
assert len(test_ids) == test_size
|
|
40
|
+
assert len(train_ids) == len(train_ancestors_df) - test_size
|
|
41
|
+
|
|
42
|
+
return train_ids, test_ids
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def prepare(raw: Path, public: Path, private: Path):
|
|
46
|
+
train_ancestors_df = read_csv(raw / "train_ancestors.csv")
|
|
47
|
+
# Shuffle the train_ancestors_df to ensure our split is random
|
|
48
|
+
train_ancestors_df = train_ancestors_df.sample(frac=1, random_state=0).reset_index(drop=True)
|
|
49
|
+
new_train_ids, new_test_ids = create_train_test_split(train_ancestors_df, test_size=20000)
|
|
50
|
+
|
|
51
|
+
# Copy json files to public
|
|
52
|
+
(public / "train").mkdir(parents=True, exist_ok=True)
|
|
53
|
+
for train_id in tqdm(new_train_ids, desc="Copying train json files"):
|
|
54
|
+
shutil.copy(raw / "train" / f"{train_id}.json", public / "train" / f"{train_id}.json")
|
|
55
|
+
(public / "test").mkdir(parents=True, exist_ok=True)
|
|
56
|
+
for test_id in tqdm(new_test_ids, desc="Copying test json files"):
|
|
57
|
+
shutil.copy(raw / "train" / f"{test_id}.json", public / "test" / f"{test_id}.json")
|
|
58
|
+
|
|
59
|
+
# Generate answers for train and test
|
|
60
|
+
train_orders = read_csv(raw / "train_orders.csv")
|
|
61
|
+
# Answers for new train
|
|
62
|
+
train_orders_new = train_orders[train_orders["id"].isin(new_train_ids)]
|
|
63
|
+
train_orders_new.to_csv(public / "train_orders.csv", index=False)
|
|
64
|
+
# Answers for new test
|
|
65
|
+
test_orders_new = train_orders[train_orders["id"].isin(new_test_ids)]
|
|
66
|
+
test_orders_new.to_csv(private / "test_orders.csv", index=False)
|
|
67
|
+
|
|
68
|
+
# Make new train_ancestors.csv, excluding the new_test_ids
|
|
69
|
+
train_ancestors_df = train_ancestors_df[~train_ancestors_df["id"].isin(new_test_ids)]
|
|
70
|
+
train_ancestors_df.to_csv(public / "train_ancestors.csv", index=False)
|
|
71
|
+
|
|
72
|
+
# Create sample submission (use the given order without changing it)
|
|
73
|
+
sample_submission_rows = []
|
|
74
|
+
for sample_id in tqdm(test_orders_new["id"], desc="Creating sample submission"):
|
|
75
|
+
# Get cell order from json file
|
|
76
|
+
with open(public / "test" / f"{sample_id}.json") as f:
|
|
77
|
+
json_data = json.load(f)
|
|
78
|
+
cell_order = list(json_data["cell_type"].keys())
|
|
79
|
+
sample_submission_rows.append({"id": sample_id, "cell_order": " ".join(cell_order)})
|
|
80
|
+
sample_submission = pd.DataFrame(sample_submission_rows)
|
|
81
|
+
sample_submission.to_csv(public / "sample_submission.csv", index=False)
|
|
82
|
+
assert len(sample_submission) == len(
|
|
83
|
+
new_test_ids
|
|
84
|
+
), "Sample submission length does not match test length."
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import shutil
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import pandas as pd
|
|
6
|
+
from tqdm.auto import tqdm
|
|
7
|
+
|
|
8
|
+
from mlebench.utils import read_csv
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Create train, test from train split
|
|
12
|
+
def create_train_test_split(train_ancestors_df: pd.DataFrame, test_size: int):
|
|
13
|
+
"""
|
|
14
|
+
On Kaggle, a user may "fork" (that is, copy) the notebook of another user to create their own version.
|
|
15
|
+
`train_ancestors_df` contains information about the ancestry of each notebook in the training set.
|
|
16
|
+
|
|
17
|
+
To create the test split, we select rows from the train set that don't share ancestors with any others
|
|
18
|
+
so that there aren't any relatives in the train set. The train split is the remaining rows.
|
|
19
|
+
"""
|
|
20
|
+
group_by_ancestor = {}
|
|
21
|
+
for _, row in tqdm(
|
|
22
|
+
train_ancestors_df.iterrows(), desc="Grouping by Ancestor", total=len(train_ancestors_df)
|
|
23
|
+
):
|
|
24
|
+
ancestor_id = row["ancestor_id"]
|
|
25
|
+
if ancestor_id not in group_by_ancestor:
|
|
26
|
+
group_by_ancestor[ancestor_id] = []
|
|
27
|
+
group_by_ancestor[ancestor_id].append(row)
|
|
28
|
+
|
|
29
|
+
train_ids = []
|
|
30
|
+
test_ids = []
|
|
31
|
+
num_test_ids = 0
|
|
32
|
+
# Ensure a deterministic split by sorting the groups
|
|
33
|
+
sorted_ancestors = sorted(group_by_ancestor.items(), key=lambda x: x[0])
|
|
34
|
+
for ancestor_id, rows in tqdm(sorted_ancestors, desc="Splitting on Ancestors"):
|
|
35
|
+
if num_test_ids + len(rows) <= test_size:
|
|
36
|
+
test_ids.extend(([row["id"] for row in rows]))
|
|
37
|
+
num_test_ids += len(rows)
|
|
38
|
+
else:
|
|
39
|
+
train_ids.extend([row["id"] for row in rows])
|
|
40
|
+
|
|
41
|
+
# The exact number of test samples can vary slightly based on group sizes.
|
|
42
|
+
# We adjust the assertion to check it's close to the target, not necessarily equal.
|
|
43
|
+
assert len(train_ids) + len(test_ids) == len(train_ancestors_df)
|
|
44
|
+
|
|
45
|
+
return train_ids, test_ids
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _generate_split_files(
|
|
49
|
+
train_ids: list,
|
|
50
|
+
test_ids: list,
|
|
51
|
+
public_dir: Path,
|
|
52
|
+
private_dir: Path,
|
|
53
|
+
raw_dir: Path,
|
|
54
|
+
full_train_orders_df: pd.DataFrame,
|
|
55
|
+
full_train_ancestors_df: pd.DataFrame,
|
|
56
|
+
):
|
|
57
|
+
"""
|
|
58
|
+
A helper function to generate all required files for a given train/test split.
|
|
59
|
+
This helps avoid code duplication and ensures consistent output structure.
|
|
60
|
+
"""
|
|
61
|
+
# Create output directories
|
|
62
|
+
public_dir.mkdir(parents=True, exist_ok=True)
|
|
63
|
+
private_dir.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
(public_dir / "train").mkdir(exist_ok=True)
|
|
65
|
+
(public_dir / "test").mkdir(exist_ok=True)
|
|
66
|
+
|
|
67
|
+
# Copy json files to public
|
|
68
|
+
for train_id in tqdm(train_ids, desc=f"Copying train json files to {public_dir.name}"):
|
|
69
|
+
shutil.copy(raw_dir / "train" / f"{train_id}.json", public_dir / "train" / f"{train_id}.json")
|
|
70
|
+
for test_id in tqdm(test_ids, desc=f"Copying test json files to {public_dir.name}"):
|
|
71
|
+
shutil.copy(raw_dir / "train" / f"{test_id}.json", public_dir / "test" / f"{test_id}.json")
|
|
72
|
+
|
|
73
|
+
# Generate answers for train and test
|
|
74
|
+
# Answers for new train
|
|
75
|
+
train_orders_new = full_train_orders_df[full_train_orders_df["id"].isin(train_ids)]
|
|
76
|
+
train_orders_new.to_csv(public_dir / "train_orders.csv", index=False)
|
|
77
|
+
# Answers for new test
|
|
78
|
+
test_orders_new = full_train_orders_df[full_train_orders_df["id"].isin(test_ids)]
|
|
79
|
+
test_orders_new.to_csv(private_dir / "test_orders.csv", index=False)
|
|
80
|
+
|
|
81
|
+
# Make new train_ancestors.csv, excluding the new_test_ids
|
|
82
|
+
train_ancestors_new = full_train_ancestors_df[
|
|
83
|
+
full_train_ancestors_df["id"].isin(train_ids)
|
|
84
|
+
]
|
|
85
|
+
train_ancestors_new.to_csv(public_dir / "train_ancestors.csv", index=False)
|
|
86
|
+
|
|
87
|
+
# Create sample submission (use the given order without changing it)
|
|
88
|
+
sample_submission_rows = []
|
|
89
|
+
for sample_id in tqdm(
|
|
90
|
+
test_orders_new["id"], desc=f"Creating sample submission for {public_dir.name}"
|
|
91
|
+
):
|
|
92
|
+
# Get cell order from json file
|
|
93
|
+
with open(public_dir / "test" / f"{sample_id}.json") as f:
|
|
94
|
+
json_data = json.load(f)
|
|
95
|
+
cell_order = list(json_data["cell_type"].keys())
|
|
96
|
+
sample_submission_rows.append({"id": sample_id, "cell_order": " ".join(cell_order)})
|
|
97
|
+
sample_submission = pd.DataFrame(sample_submission_rows)
|
|
98
|
+
sample_submission.to_csv(public_dir / "sample_submission.csv", index=False)
|
|
99
|
+
assert len(sample_submission) == len(test_ids), "Sample submission length does not match test length."
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def prepare(raw: Path, public: Path, private: Path):
|
|
103
|
+
# --- Initial Setup ---
|
|
104
|
+
TEST_SIZE = 20000
|
|
105
|
+
# Load all necessary data once
|
|
106
|
+
full_train_ancestors_df = read_csv(raw / "train_ancestors.csv")
|
|
107
|
+
full_train_orders_df = read_csv(raw / "train_orders.csv")
|
|
108
|
+
|
|
109
|
+
# Shuffle the train_ancestors_df to ensure our split is random but reproducible
|
|
110
|
+
shuffled_ancestors_df = full_train_ancestors_df.sample(
|
|
111
|
+
frac=1, random_state=0
|
|
112
|
+
).reset_index(drop=True)
|
|
113
|
+
|
|
114
|
+
# --- 1. Original Split (train/test) ---
|
|
115
|
+
print("--- Generating original train/test split ---")
|
|
116
|
+
train_ids, test_ids = create_train_test_split(shuffled_ancestors_df, test_size=TEST_SIZE)
|
|
117
|
+
|
|
118
|
+
# Generate files for the original public and private directories
|
|
119
|
+
_generate_split_files(
|
|
120
|
+
train_ids,
|
|
121
|
+
test_ids,
|
|
122
|
+
public,
|
|
123
|
+
private,
|
|
124
|
+
raw,
|
|
125
|
+
full_train_orders_df,
|
|
126
|
+
shuffled_ancestors_df,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
# --- 2. Validation Split (train_val/test_val) ---
|
|
130
|
+
print("\n--- Generating new validation split ---")
|
|
131
|
+
# Define paths for the new validation directories
|
|
132
|
+
public_val = public.parent / "public_val"
|
|
133
|
+
private_val = private.parent / "private_val"
|
|
134
|
+
|
|
135
|
+
# The input for the second split is the training set from the first split.
|
|
136
|
+
# We use the already shuffled dataframe to maintain deterministic behavior.
|
|
137
|
+
train_subset_for_val_split = shuffled_ancestors_df[
|
|
138
|
+
shuffled_ancestors_df["id"].isin(train_ids)
|
|
139
|
+
].reset_index(drop=True)
|
|
140
|
+
|
|
141
|
+
# Create the second split from the first split's training data
|
|
142
|
+
train_val_ids, test_val_ids = create_train_test_split(
|
|
143
|
+
train_subset_for_val_split, test_size=TEST_SIZE
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
# Generate the validation split files in the new directories
|
|
147
|
+
_generate_split_files(
|
|
148
|
+
train_val_ids,
|
|
149
|
+
test_val_ids,
|
|
150
|
+
public_val,
|
|
151
|
+
private_val,
|
|
152
|
+
raw,
|
|
153
|
+
full_train_orders_df,
|
|
154
|
+
shuffled_ancestors_df,
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
print("\nData preparation complete.")
|
|
158
|
+
print(f"Original split created in '{public.name}' and '{private.name}'.")
|
|
159
|
+
print(f"Validation split created in '{public_val.name}' and '{private_val.name}'.")
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
from sklearn.metrics import roc_auc_score
|
|
3
|
+
|
|
4
|
+
from mlebench.competitions.utils import prepare_for_auroc_metric
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def grade(submission: pd.DataFrame, answers: pd.DataFrame) -> float:
|
|
8
|
+
roc_auc_inputs = prepare_for_auroc_metric(
|
|
9
|
+
submission=submission, answers=answers, id_col="id", target_col="has_cactus"
|
|
10
|
+
)
|
|
11
|
+
return roc_auc_score(y_true=roc_auc_inputs["y_true"], y_score=roc_auc_inputs["y_score"])
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from sklearn.model_selection import train_test_split
|
|
5
|
+
from tqdm.auto import tqdm
|
|
6
|
+
|
|
7
|
+
from mlebench.utils import compress, extract, read_csv
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def prepare(raw: Path, public: Path, private: Path):
|
|
11
|
+
|
|
12
|
+
old_train = read_csv(raw / "train.csv")
|
|
13
|
+
|
|
14
|
+
# 4000 / (4000 + 17500) -> test_size is ~0.19
|
|
15
|
+
new_train, new_test = train_test_split(old_train, test_size=0.19, random_state=0)
|
|
16
|
+
|
|
17
|
+
new_train.to_csv(public / "train.csv", index=False)
|
|
18
|
+
new_test.to_csv(private / "test.csv", index=False)
|
|
19
|
+
|
|
20
|
+
sample_submission = new_test.copy()
|
|
21
|
+
sample_submission["has_cactus"] = 0.5
|
|
22
|
+
sample_submission.to_csv(public / "sample_submission.csv", index=False)
|
|
23
|
+
|
|
24
|
+
# need to split the train.zip into train.zip and test.zip; to do so need to extract first
|
|
25
|
+
extract(raw / "train.zip", raw)
|
|
26
|
+
|
|
27
|
+
# copy
|
|
28
|
+
(public / "train").mkdir(parents=True, exist_ok=True)
|
|
29
|
+
for image_id in tqdm(new_train["id"], desc="Copying train images", total=len(new_train)):
|
|
30
|
+
shutil.copy(raw / "train" / image_id, public / "train" / image_id)
|
|
31
|
+
|
|
32
|
+
(public / "test").mkdir(parents=True, exist_ok=True)
|
|
33
|
+
for image_id in tqdm(new_test["id"], desc="Copying test images", total=len(new_test)):
|
|
34
|
+
shutil.copy(raw / "train" / image_id, public / "test" / image_id)
|
|
35
|
+
|
|
36
|
+
# and then recompress
|
|
37
|
+
compress(public / "train", public / "train.zip")
|
|
38
|
+
compress(public / "test", public / "test.zip")
|
|
39
|
+
|
|
40
|
+
# and cleanup
|
|
41
|
+
shutil.rmtree(public / "train")
|
|
42
|
+
shutil.rmtree(public / "test")
|
|
43
|
+
shutil.rmtree(raw / "train")
|
|
44
|
+
|
|
45
|
+
# checks
|
|
46
|
+
assert (public / "train.zip").exists(), "public/train.zip should exist"
|
|
47
|
+
assert (public / "test.zip").exists(), "public/test.zip should exist"
|
|
48
|
+
assert not (raw / "train").exists(), "raw/train/ should not exist"
|
|
49
|
+
|
|
50
|
+
assert len(new_train) + len(new_test) == len(
|
|
51
|
+
old_train
|
|
52
|
+
), "The lengths of the splits should add up to the original"
|
|
53
|
+
assert len(new_train) > len(new_test), "The train set should be larger than the test set"
|
|
54
|
+
assert len(new_test) == len(
|
|
55
|
+
sample_submission
|
|
56
|
+
), "The test set should match the sample submission"
|
|
57
|
+
|
|
58
|
+
assert (
|
|
59
|
+
new_train.columns.tolist()
|
|
60
|
+
== new_test.columns.tolist()
|
|
61
|
+
== old_train.columns.tolist()
|
|
62
|
+
== sample_submission.columns.tolist()
|
|
63
|
+
), "All dataframes should have the same columns, i.e. ['id', 'has_cactus']"
|
|
64
|
+
|
|
65
|
+
assert set(new_train["id"]).isdisjoint(new_test["id"]), "Train and test ids should not overlap"
|
|
66
|
+
assert set(new_test["id"]) == set(
|
|
67
|
+
sample_submission["id"]
|
|
68
|
+
), "Test and sample_submission ids should match"
|
|
69
|
+
|
|
70
|
+
assert new_train["id"].nunique() == len(new_train), "There should be no duplicate ids in train"
|
|
71
|
+
assert new_test["id"].nunique() == len(new_test), "There should be no duplicate ids in test"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import shutil
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
from sklearn.model_selection import train_test_split
|
|
6
|
+
from tqdm.auto import tqdm
|
|
7
|
+
|
|
8
|
+
from mlebench.utils import compress, extract, read_csv
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _process_and_save_split(
|
|
12
|
+
train_df: pd.DataFrame,
|
|
13
|
+
test_df: pd.DataFrame,
|
|
14
|
+
public_dir: Path,
|
|
15
|
+
private_dir: Path,
|
|
16
|
+
raw_image_dir: Path,
|
|
17
|
+
original_df: pd.DataFrame,
|
|
18
|
+
):
|
|
19
|
+
"""
|
|
20
|
+
Helper function to process a single train/test split.
|
|
21
|
+
It saves all required CSVs, copies and compresses images, and runs assertions.
|
|
22
|
+
"""
|
|
23
|
+
public_dir.mkdir(parents=True, exist_ok=True)
|
|
24
|
+
private_dir.mkdir(parents=True, exist_ok=True)
|
|
25
|
+
|
|
26
|
+
# Save the dataframes
|
|
27
|
+
train_df.to_csv(public_dir / "train.csv", index=False)
|
|
28
|
+
test_df.to_csv(private_dir / "test.csv", index=False)
|
|
29
|
+
|
|
30
|
+
sample_submission = test_df.copy()
|
|
31
|
+
sample_submission["has_cactus"] = 0.5
|
|
32
|
+
sample_submission.to_csv(public_dir / "sample_submission.csv", index=False)
|
|
33
|
+
|
|
34
|
+
# Prepare temporary directories for images
|
|
35
|
+
temp_train_img_dir = public_dir / "train"
|
|
36
|
+
temp_test_img_dir = public_dir / "test"
|
|
37
|
+
temp_train_img_dir.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
temp_test_img_dir.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
|
|
40
|
+
# Copy images for the current split
|
|
41
|
+
for image_id in tqdm(train_df["id"], desc=f"Copying train images to {public_dir.name}", total=len(train_df)):
|
|
42
|
+
shutil.copy(raw_image_dir / image_id, temp_train_img_dir / image_id)
|
|
43
|
+
|
|
44
|
+
for image_id in tqdm(test_df["id"], desc=f"Copying test images to {public_dir.name}", total=len(test_df)):
|
|
45
|
+
shutil.copy(raw_image_dir / image_id, temp_test_img_dir / image_id)
|
|
46
|
+
|
|
47
|
+
# and then recompress
|
|
48
|
+
compress(temp_train_img_dir, public_dir / "train.zip")
|
|
49
|
+
compress(temp_test_img_dir, public_dir / "test.zip")
|
|
50
|
+
|
|
51
|
+
# and cleanup temporary image directories
|
|
52
|
+
shutil.rmtree(temp_train_img_dir)
|
|
53
|
+
shutil.rmtree(temp_test_img_dir)
|
|
54
|
+
|
|
55
|
+
# checks for the current split
|
|
56
|
+
assert (public_dir / "train.zip").exists(), f"{public_dir.name}/train.zip should exist"
|
|
57
|
+
assert (public_dir / "test.zip").exists(), f"{public_dir.name}/test.zip should exist"
|
|
58
|
+
|
|
59
|
+
assert len(train_df) + len(test_df) == len(
|
|
60
|
+
original_df
|
|
61
|
+
), "The lengths of the splits should add up to the original"
|
|
62
|
+
assert len(train_df) > len(test_df), "The train set should be larger than the test set"
|
|
63
|
+
assert len(test_df) == len(
|
|
64
|
+
sample_submission
|
|
65
|
+
), "The test set should match the sample submission"
|
|
66
|
+
|
|
67
|
+
assert (
|
|
68
|
+
train_df.columns.tolist()
|
|
69
|
+
== test_df.columns.tolist()
|
|
70
|
+
== original_df.columns.tolist()
|
|
71
|
+
== sample_submission.columns.tolist()
|
|
72
|
+
), "All dataframes should have the same columns, i.e. ['id', 'has_cactus']"
|
|
73
|
+
|
|
74
|
+
assert set(train_df["id"]).isdisjoint(test_df["id"]), "Train and test ids should not overlap"
|
|
75
|
+
assert set(test_df["id"]) == set(
|
|
76
|
+
sample_submission["id"]
|
|
77
|
+
), "Test and sample_submission ids should match"
|
|
78
|
+
|
|
79
|
+
assert train_df["id"].nunique() == len(train_df), "There should be no duplicate ids in train"
|
|
80
|
+
assert test_df["id"].nunique() == len(test_df), "There should be no duplicate ids in test"
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def prepare(raw: Path, public: Path, private: Path):
|
|
84
|
+
|
|
85
|
+
old_train = read_csv(raw / "train.csv")
|
|
86
|
+
|
|
87
|
+
# need to split the train.zip into train.zip and test.zip; to do so need to extract first
|
|
88
|
+
extract(raw / "train.zip", raw)
|
|
89
|
+
raw_image_dir = raw / "train"
|
|
90
|
+
|
|
91
|
+
# --- 1. Original Split: Create main train and test sets ---
|
|
92
|
+
# This block creates the original public/private outputs, which must remain unchanged.
|
|
93
|
+
|
|
94
|
+
# 4000 / (4000 + 17500) -> test_size is ~0.19
|
|
95
|
+
new_train, new_test = train_test_split(old_train, test_size=0.19, random_state=0)
|
|
96
|
+
|
|
97
|
+
_process_and_save_split(
|
|
98
|
+
train_df=new_train,
|
|
99
|
+
test_df=new_test,
|
|
100
|
+
public_dir=public,
|
|
101
|
+
private_dir=private,
|
|
102
|
+
raw_image_dir=raw_image_dir,
|
|
103
|
+
original_df=old_train,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# --- 2. New Validation Split: Create a validation set from the main train set ---
|
|
107
|
+
# This block creates the new public_val/private_val outputs.
|
|
108
|
+
|
|
109
|
+
# Define paths for the new validation split artifacts
|
|
110
|
+
public_val = public.parent / "public_val"
|
|
111
|
+
private_val = private.parent / "private_val"
|
|
112
|
+
|
|
113
|
+
# To make the new validation set (test_val) have the same size as the original
|
|
114
|
+
# test set (new_test), we calculate the required test_size proportion.
|
|
115
|
+
test_size_for_val_split = len(new_test) / len(new_train)
|
|
116
|
+
|
|
117
|
+
# Split the main training set (new_train) into a smaller training set (train_val)
|
|
118
|
+
# and a validation set (test_val), using the same random_state for consistency.
|
|
119
|
+
train_val, test_val = train_test_split(new_train, test_size=test_size_for_val_split, random_state=0)
|
|
120
|
+
|
|
121
|
+
_process_and_save_split(
|
|
122
|
+
train_df=train_val,
|
|
123
|
+
test_df=test_val,
|
|
124
|
+
public_dir=public_val,
|
|
125
|
+
private_dir=private_val,
|
|
126
|
+
raw_image_dir=raw_image_dir,
|
|
127
|
+
original_df=new_train,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# --- Final Cleanup ---
|
|
131
|
+
# and cleanup the extracted raw image directory, which is no longer needed
|
|
132
|
+
shutil.rmtree(raw_image_dir)
|
|
133
|
+
assert not (raw / "train").exists(), "raw/train/ should not exist"
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import pandas as pd
|
|
3
|
+
from sklearn import metrics
|
|
4
|
+
|
|
5
|
+
from mlebench.grade_helpers import InvalidSubmissionError
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def insert_thresholds(fpr: np.ndarray, tpr: np.ndarray, tpr_thresholds: list) -> tuple:
|
|
9
|
+
"""
|
|
10
|
+
Insert tpr_thresholds into the TPR and FPR arrays to ensure that the thresholds are present
|
|
11
|
+
in the TPR array and the corresponding FPR values are interpolated.
|
|
12
|
+
|
|
13
|
+
e.g.
|
|
14
|
+
> tpr = [0.0, 0.25, 0.5, 0.75, 1.0]
|
|
15
|
+
> fpr = [0.0, 0.1, 0.2, 0.3, 0.4]
|
|
16
|
+
|
|
17
|
+
> tpr_thresholds = [0.0, 0.3, 0.4, 1.0]
|
|
18
|
+
> fpr, tpr = insert_thresholds(fpr, tpr, tpr_thresholds)
|
|
19
|
+
|
|
20
|
+
> print(tpr)
|
|
21
|
+
> print(fpr)
|
|
22
|
+
[0.0, 0.25, 0.3, 0.4, 0.5, 0.75, 1.0]
|
|
23
|
+
[0.0, 0.1, 0.12, 0.16, 0.2, 0.3, 0.4]
|
|
24
|
+
"""
|
|
25
|
+
fpr_ = fpr.tolist().copy() # Don't modify the input arrays
|
|
26
|
+
tpr_ = tpr.tolist().copy()
|
|
27
|
+
for threshold in tpr_thresholds:
|
|
28
|
+
if threshold not in tpr_:
|
|
29
|
+
# Find the right position within tpr to insert the threshold
|
|
30
|
+
for i, tpr_val in enumerate(tpr_):
|
|
31
|
+
if tpr_val > threshold:
|
|
32
|
+
# Linear interpolation of fpr
|
|
33
|
+
new_fpr = fpr_[i - 1] + (fpr_[i] - fpr_[i - 1]) * (threshold - tpr_[i - 1]) / (
|
|
34
|
+
tpr_[i] - tpr_[i - 1]
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
tpr_.insert(i, threshold)
|
|
38
|
+
fpr_.insert(i, new_fpr)
|
|
39
|
+
break
|
|
40
|
+
return np.array(fpr_), np.array(tpr_)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def alaska_weighted_auc(y_true: np.ndarray, y_pred: np.ndarray) -> float:
|
|
44
|
+
"""
|
|
45
|
+
Instead of the standard AUC, the competition uses a weighted AUC where different regions of
|
|
46
|
+
the ROC curve are weighted differently.
|
|
47
|
+
|
|
48
|
+
We compute the area under the curve segment by segment (HORIZONTAL segments between TPR pairs
|
|
49
|
+
on the y-axis), and then compute a weighted average of the segments.
|
|
50
|
+
|
|
51
|
+
For more details, see:
|
|
52
|
+
www.kaggle.com/competitions/alaska2-image-steganalysis/overview/evaluation
|
|
53
|
+
|
|
54
|
+
This particular implementation is adapted from:
|
|
55
|
+
https://www.kaggle.com/code/anokas/weighted-auc-metric-updated
|
|
56
|
+
(Key change vs the above implementation: The above implementation uses the `tpr` and `fpr`
|
|
57
|
+
arrays from metrics.roc_curve as is, neglecting to handle the case where the `tpr` values
|
|
58
|
+
don't line up nicely with the thresholds - leading to a situation where some segments either
|
|
59
|
+
belong partially to the wrong threshold, or get skipped entirely. Our implementation fixes
|
|
60
|
+
this by inserting the thresholds into the `tpr` and `fpr` arrays before computing the AUC.)
|
|
61
|
+
"""
|
|
62
|
+
tpr_thresholds = [0.0, 0.4, 1.0]
|
|
63
|
+
weights = [2, 1]
|
|
64
|
+
|
|
65
|
+
fpr, tpr, thresholds = metrics.roc_curve(y_true, y_pred, pos_label=1)
|
|
66
|
+
fpr, tpr = insert_thresholds(fpr, tpr, tpr_thresholds)
|
|
67
|
+
|
|
68
|
+
# size of subsets
|
|
69
|
+
areas = np.array(tpr_thresholds[1:]) - np.array(tpr_thresholds[:-1])
|
|
70
|
+
|
|
71
|
+
competition_metric = 0
|
|
72
|
+
# Compute AUC segment by segment (where each segment is a horizontal slice of the ROC curve
|
|
73
|
+
# between a pair of consecutive TPR thresholds)
|
|
74
|
+
for idx, weight in enumerate(weights):
|
|
75
|
+
y_min = tpr_thresholds[idx]
|
|
76
|
+
y_max = tpr_thresholds[idx + 1]
|
|
77
|
+
|
|
78
|
+
# Here, we're creating new x and y arrays to calculate the AUC for this segment:
|
|
79
|
+
|
|
80
|
+
# The segment arrays consist of the FPR and TPR values in the segment,
|
|
81
|
+
mask = (y_min <= tpr) & (tpr <= y_max)
|
|
82
|
+
if mask.sum() == 0:
|
|
83
|
+
continue
|
|
84
|
+
xs = fpr[mask]
|
|
85
|
+
ys = tpr[mask]
|
|
86
|
+
|
|
87
|
+
# plus a new point [1, y_max] which just closes the shape of this segment (draws a
|
|
88
|
+
# horizontal line from the highest point in this segment to the right of the x-axis)
|
|
89
|
+
xs = np.concatenate([xs, [1]])
|
|
90
|
+
ys = np.concatenate([ys, [y_max]])
|
|
91
|
+
ys = ys - y_min # normalize such that curve starts at y=0
|
|
92
|
+
score = metrics.auc(xs, ys)
|
|
93
|
+
submetric = score * weight
|
|
94
|
+
competition_metric += submetric
|
|
95
|
+
|
|
96
|
+
# The total area is normalized by the sum of weights such that the final weighted AUC is between 0 and 1.
|
|
97
|
+
normalization = np.dot(areas, weights)
|
|
98
|
+
|
|
99
|
+
return competition_metric / normalization
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def prepare_for_metric(submission: pd.DataFrame, answers: pd.DataFrame):
|
|
103
|
+
if len(submission) != len(answers):
|
|
104
|
+
raise InvalidSubmissionError("Submission and answers must have the same length")
|
|
105
|
+
|
|
106
|
+
if "Id" not in submission.columns:
|
|
107
|
+
raise InvalidSubmissionError("Submission must have an 'Id' column")
|
|
108
|
+
|
|
109
|
+
if "Label" not in submission.columns:
|
|
110
|
+
raise InvalidSubmissionError("Submission must have a 'Label' column")
|
|
111
|
+
|
|
112
|
+
submission = submission.sort_values("Id")
|
|
113
|
+
answers = answers.sort_values("Id")
|
|
114
|
+
|
|
115
|
+
if (submission["Id"].values != answers["Id"].values).any():
|
|
116
|
+
raise InvalidSubmissionError("Submission and answers must have the same ids")
|
|
117
|
+
|
|
118
|
+
# Answers and submission must be numbers
|
|
119
|
+
try:
|
|
120
|
+
submission["Label"] = submission["Label"].astype(float)
|
|
121
|
+
except ValueError:
|
|
122
|
+
raise InvalidSubmissionError("Labels in submission must be numbers")
|
|
123
|
+
answers["Label"] = answers["Label"].astype(float)
|
|
124
|
+
|
|
125
|
+
# Cannot contain NaNs
|
|
126
|
+
assert not answers["Label"].isnull().any(), "Answers cannot contain NaNs"
|
|
127
|
+
if submission["Label"].isnull().any():
|
|
128
|
+
raise InvalidSubmissionError("Submission cannot contain NaNs")
|
|
129
|
+
|
|
130
|
+
return answers["Label"], submission["Label"]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def grade(submission: pd.DataFrame, answers: pd.DataFrame) -> float:
|
|
134
|
+
y_true, y_pred = prepare_for_metric(submission, answers)
|
|
135
|
+
|
|
136
|
+
return alaska_weighted_auc(np.array(y_true), np.array(y_pred))
|