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.
Files changed (352) hide show
  1. dslighting/__init__.py +1 -1
  2. dslighting/core/agent.py +78 -62
  3. {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/METADATA +1 -1
  4. {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/RECORD +352 -7
  5. {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/top_level.txt +1 -0
  6. mlebench/README.md +39 -0
  7. mlebench/__init__.py +0 -0
  8. mlebench/cli.py +221 -0
  9. mlebench/competitions/3d-object-detection-for-autonomous-vehicles/grade.py +161 -0
  10. mlebench/competitions/3d-object-detection-for-autonomous-vehicles/mAP_evaluation.py +425 -0
  11. mlebench/competitions/3d-object-detection-for-autonomous-vehicles/prepare.py +483 -0
  12. mlebench/competitions/3d-object-detection-for-autonomous-vehicles/prepare_val.py +719 -0
  13. mlebench/competitions/AI4Code/grade.py +70 -0
  14. mlebench/competitions/AI4Code/prepare.py +84 -0
  15. mlebench/competitions/AI4Code/prepare_val.py +159 -0
  16. mlebench/competitions/__init__.py +0 -0
  17. mlebench/competitions/aerial-cactus-identification/grade.py +11 -0
  18. mlebench/competitions/aerial-cactus-identification/prepare.py +71 -0
  19. mlebench/competitions/aerial-cactus-identification/prepare_val.py +133 -0
  20. mlebench/competitions/alaska2-image-steganalysis/grade.py +136 -0
  21. mlebench/competitions/alaska2-image-steganalysis/prepare.py +88 -0
  22. mlebench/competitions/alaska2-image-steganalysis/prepare_val.py +148 -0
  23. mlebench/competitions/aptos2019-blindness-detection/grade.py +35 -0
  24. mlebench/competitions/aptos2019-blindness-detection/prepare.py +75 -0
  25. mlebench/competitions/aptos2019-blindness-detection/prepare_val.py +123 -0
  26. mlebench/competitions/bike-sharing-demand/__init__.py +0 -0
  27. mlebench/competitions/bike-sharing-demand/grade.py +55 -0
  28. mlebench/competitions/bike-sharing-demand/prepare.py +37 -0
  29. mlebench/competitions/billion-word-imputation/grade.py +37 -0
  30. mlebench/competitions/billion-word-imputation/prepare.py +107 -0
  31. mlebench/competitions/billion-word-imputation/prepare_val.py +179 -0
  32. mlebench/competitions/bms-molecular-translation/grade.py +40 -0
  33. mlebench/competitions/bms-molecular-translation/prepare.py +68 -0
  34. mlebench/competitions/bms-molecular-translation/prepare_val.py +131 -0
  35. mlebench/competitions/cassava-leaf-disease-classification/grade.py +12 -0
  36. mlebench/competitions/cassava-leaf-disease-classification/prepare.py +113 -0
  37. mlebench/competitions/cassava-leaf-disease-classification/prepare_val.py +186 -0
  38. mlebench/competitions/cdiscount-image-classification-challenge/grade.py +11 -0
  39. mlebench/competitions/cdiscount-image-classification-challenge/prepare.py +144 -0
  40. mlebench/competitions/cdiscount-image-classification-challenge/prepare_val.py +205 -0
  41. mlebench/competitions/chaii-hindi-and-tamil-question-answering/grade.py +67 -0
  42. mlebench/competitions/chaii-hindi-and-tamil-question-answering/prepare.py +31 -0
  43. mlebench/competitions/chaii-hindi-and-tamil-question-answering/prepare_val.py +94 -0
  44. mlebench/competitions/champs-scalar-coupling/grade.py +60 -0
  45. mlebench/competitions/champs-scalar-coupling/prepare.py +116 -0
  46. mlebench/competitions/champs-scalar-coupling/prepare_val.py +155 -0
  47. mlebench/competitions/conways-reverse-game-of-life-2020/__init__.py +0 -0
  48. mlebench/competitions/conways-reverse-game-of-life-2020/grade.py +40 -0
  49. mlebench/competitions/conways-reverse-game-of-life-2020/prepare.py +41 -0
  50. mlebench/competitions/demand-forecasting-kernels-only/__init__.py +0 -0
  51. mlebench/competitions/demand-forecasting-kernels-only/grade.py +66 -0
  52. mlebench/competitions/demand-forecasting-kernels-only/prepare.py +27 -0
  53. mlebench/competitions/demand_forecasting_kernels_only/__init__.py +0 -0
  54. mlebench/competitions/demand_forecasting_kernels_only/grade.py +66 -0
  55. mlebench/competitions/demand_forecasting_kernels_only/prepare.py +27 -0
  56. mlebench/competitions/denoising-dirty-documents/grade.py +44 -0
  57. mlebench/competitions/denoising-dirty-documents/prepare.py +134 -0
  58. mlebench/competitions/denoising-dirty-documents/prepare_val.py +178 -0
  59. mlebench/competitions/detecting-insults-in-social-commentary/grade.py +11 -0
  60. mlebench/competitions/detecting-insults-in-social-commentary/prepare.py +72 -0
  61. mlebench/competitions/detecting-insults-in-social-commentary/prepare_val.py +128 -0
  62. mlebench/competitions/dog-breed-identification/dogs.py +124 -0
  63. mlebench/competitions/dog-breed-identification/grade.py +42 -0
  64. mlebench/competitions/dog-breed-identification/prepare.py +55 -0
  65. mlebench/competitions/dog-breed-identification/prepare_val.py +104 -0
  66. mlebench/competitions/dogs-vs-cats-redux-kernels-edition/grade.py +43 -0
  67. mlebench/competitions/dogs-vs-cats-redux-kernels-edition/prepare.py +70 -0
  68. mlebench/competitions/dogs-vs-cats-redux-kernels-edition/prepare_val.py +143 -0
  69. mlebench/competitions/ethanol-concentration/grade.py +23 -0
  70. mlebench/competitions/ethanol-concentration/prepare.py +90 -0
  71. mlebench/competitions/facebook-recruiting-iii-keyword-extraction/grade.py +60 -0
  72. mlebench/competitions/facebook-recruiting-iii-keyword-extraction/prepare.py +41 -0
  73. mlebench/competitions/facebook-recruiting-iii-keyword-extraction/prepare_val.py +92 -0
  74. mlebench/competitions/feedback-prize-english-language-learning/__init__.py +0 -0
  75. mlebench/competitions/feedback-prize-english-language-learning/grade.py +60 -0
  76. mlebench/competitions/feedback-prize-english-language-learning/prepare.py +39 -0
  77. mlebench/competitions/freesound-audio-tagging-2019/grade.py +64 -0
  78. mlebench/competitions/freesound-audio-tagging-2019/prepare.py +94 -0
  79. mlebench/competitions/freesound-audio-tagging-2019/prepare_val.py +175 -0
  80. mlebench/competitions/freesound-audio-tagging-2019/vocabulary.py +83 -0
  81. mlebench/competitions/google-quest-challenge/classes.py +32 -0
  82. mlebench/competitions/google-quest-challenge/grade.py +45 -0
  83. mlebench/competitions/google-quest-challenge/prepare.py +58 -0
  84. mlebench/competitions/google-quest-challenge/prepare_val.py +120 -0
  85. mlebench/competitions/google-research-identify-contrails-reduce-global-warming/grade.py +77 -0
  86. mlebench/competitions/google-research-identify-contrails-reduce-global-warming/prepare.py +155 -0
  87. mlebench/competitions/google-research-identify-contrails-reduce-global-warming/prepare_val.py +211 -0
  88. mlebench/competitions/h-and-m-personalized-fashion-recommendations/grade.py +42 -0
  89. mlebench/competitions/h-and-m-personalized-fashion-recommendations/prepare.py +102 -0
  90. mlebench/competitions/h-and-m-personalized-fashion-recommendations/prepare_val.py +132 -0
  91. mlebench/competitions/handwriting/grade.py +23 -0
  92. mlebench/competitions/handwriting/prepare.py +179 -0
  93. mlebench/competitions/herbarium-2020-fgvc7/grade.py +34 -0
  94. mlebench/competitions/herbarium-2020-fgvc7/prepare.py +251 -0
  95. mlebench/competitions/herbarium-2020-fgvc7/prepare_val.py +242 -0
  96. mlebench/competitions/herbarium-2021-fgvc8/grade.py +34 -0
  97. mlebench/competitions/herbarium-2021-fgvc8/prepare.py +251 -0
  98. mlebench/competitions/herbarium-2021-fgvc8/prepare_val.py +222 -0
  99. mlebench/competitions/herbarium-2022-fgvc9/grade.py +31 -0
  100. mlebench/competitions/herbarium-2022-fgvc9/prepare.py +233 -0
  101. mlebench/competitions/herbarium-2022-fgvc9/prepare_val.py +213 -0
  102. mlebench/competitions/histopathologic-cancer-detection/grade.py +12 -0
  103. mlebench/competitions/histopathologic-cancer-detection/prepare.py +59 -0
  104. mlebench/competitions/histopathologic-cancer-detection/prepare_val.py +131 -0
  105. mlebench/competitions/hms-harmful-brain-activity-classification/constants.py +9 -0
  106. mlebench/competitions/hms-harmful-brain-activity-classification/grade.py +43 -0
  107. mlebench/competitions/hms-harmful-brain-activity-classification/kaggle_metric_utilities.py +96 -0
  108. mlebench/competitions/hms-harmful-brain-activity-classification/kullback_leibler_divergence.py +118 -0
  109. mlebench/competitions/hms-harmful-brain-activity-classification/prepare.py +121 -0
  110. mlebench/competitions/hms-harmful-brain-activity-classification/prepare_val.py +190 -0
  111. mlebench/competitions/hotel-id-2021-fgvc8/grade.py +41 -0
  112. mlebench/competitions/hotel-id-2021-fgvc8/prepare.py +63 -0
  113. mlebench/competitions/hotel-id-2021-fgvc8/prepare_val.py +132 -0
  114. mlebench/competitions/hubmap-kidney-segmentation/grade.py +62 -0
  115. mlebench/competitions/hubmap-kidney-segmentation/prepare.py +108 -0
  116. mlebench/competitions/hubmap-kidney-segmentation/prepare_val.py +153 -0
  117. mlebench/competitions/icecube-neutrinos-in-deep-ice/grade.py +111 -0
  118. mlebench/competitions/icecube-neutrinos-in-deep-ice/prepare.py +127 -0
  119. mlebench/competitions/icecube-neutrinos-in-deep-ice/prepare_val.py +183 -0
  120. mlebench/competitions/ili/grade.py +60 -0
  121. mlebench/competitions/ili/prepare.py +99 -0
  122. mlebench/competitions/imet-2020-fgvc7/grade.py +54 -0
  123. mlebench/competitions/imet-2020-fgvc7/prepare.py +77 -0
  124. mlebench/competitions/imet-2020-fgvc7/prepare_val.py +157 -0
  125. mlebench/competitions/inaturalist-2019-fgvc6/grade.py +35 -0
  126. mlebench/competitions/inaturalist-2019-fgvc6/prepare.py +259 -0
  127. mlebench/competitions/inaturalist-2019-fgvc6/prepare_val.py +304 -0
  128. mlebench/competitions/instant-gratification/__init__.py +0 -0
  129. mlebench/competitions/instant-gratification/grade.py +55 -0
  130. mlebench/competitions/instant-gratification/prepare.py +25 -0
  131. mlebench/competitions/instant_gratification/__init__.py +0 -0
  132. mlebench/competitions/instant_gratification/grade.py +55 -0
  133. mlebench/competitions/instant_gratification/prepare.py +25 -0
  134. mlebench/competitions/invasive-species-monitoring/grade.py +11 -0
  135. mlebench/competitions/invasive-species-monitoring/prepare.py +97 -0
  136. mlebench/competitions/invasive-species-monitoring/prepare_val.py +164 -0
  137. mlebench/competitions/iwildcam-2019-fgvc6/grade.py +44 -0
  138. mlebench/competitions/iwildcam-2019-fgvc6/prepare.py +118 -0
  139. mlebench/competitions/iwildcam-2019-fgvc6/prepare_val.py +194 -0
  140. mlebench/competitions/iwildcam-2020-fgvc7/grade.py +11 -0
  141. mlebench/competitions/iwildcam-2020-fgvc7/prepare.py +164 -0
  142. mlebench/competitions/iwildcam-2020-fgvc7/prepare_val.py +245 -0
  143. mlebench/competitions/jigsaw-toxic-comment-classification-challenge/classes.py +1 -0
  144. mlebench/competitions/jigsaw-toxic-comment-classification-challenge/grade.py +54 -0
  145. mlebench/competitions/jigsaw-toxic-comment-classification-challenge/prepare.py +42 -0
  146. mlebench/competitions/jigsaw-toxic-comment-classification-challenge/prepare_val.py +88 -0
  147. mlebench/competitions/jigsaw-unintended-bias-in-toxicity-classification/grade.py +153 -0
  148. mlebench/competitions/jigsaw-unintended-bias-in-toxicity-classification/prepare.py +36 -0
  149. mlebench/competitions/jigsaw-unintended-bias-in-toxicity-classification/prepare_val.py +117 -0
  150. mlebench/competitions/kuzushiji-recognition/grade.py +58 -0
  151. mlebench/competitions/kuzushiji-recognition/kuzushiji_metric.py +118 -0
  152. mlebench/competitions/kuzushiji-recognition/prepare.py +92 -0
  153. mlebench/competitions/kuzushiji-recognition/prepare_val.py +149 -0
  154. mlebench/competitions/leaf-classification/classes.py +101 -0
  155. mlebench/competitions/leaf-classification/grade.py +44 -0
  156. mlebench/competitions/leaf-classification/prepare.py +60 -0
  157. mlebench/competitions/leaf-classification/prepare_val.py +116 -0
  158. mlebench/competitions/learning-agency-lab-automated-essay-scoring-2/grade.py +44 -0
  159. mlebench/competitions/learning-agency-lab-automated-essay-scoring-2/prepare.py +51 -0
  160. mlebench/competitions/learning-agency-lab-automated-essay-scoring-2/prepare_val.py +96 -0
  161. mlebench/competitions/liverpool-ion-switching/__init__.py +0 -0
  162. mlebench/competitions/liverpool-ion-switching/grade.py +52 -0
  163. mlebench/competitions/liverpool-ion-switching/prepare.py +27 -0
  164. mlebench/competitions/liverpool_ion_switching/__init__.py +0 -0
  165. mlebench/competitions/liverpool_ion_switching/grade.py +52 -0
  166. mlebench/competitions/liverpool_ion_switching/prepare.py +27 -0
  167. mlebench/competitions/lmsys-chatbot-arena/grade.py +63 -0
  168. mlebench/competitions/lmsys-chatbot-arena/prepare.py +52 -0
  169. mlebench/competitions/lmsys-chatbot-arena/prepare_val.py +115 -0
  170. mlebench/competitions/mcm_2024_c_test/grade.py +107 -0
  171. mlebench/competitions/mcm_2024_c_test/prepare.py +2 -0
  172. mlebench/competitions/ml2021spring-hw2/grade.py +11 -0
  173. mlebench/competitions/ml2021spring-hw2/prepare.py +58 -0
  174. mlebench/competitions/ml2021spring-hw2/prepare_val.py +135 -0
  175. mlebench/competitions/mlsp-2013-birds/grade.py +11 -0
  176. mlebench/competitions/mlsp-2013-birds/prepare.py +182 -0
  177. mlebench/competitions/mlsp-2013-birds/prepare_val.py +241 -0
  178. mlebench/competitions/movie-review-sentiment-analysis-kernels-only/grade.py +11 -0
  179. mlebench/competitions/movie-review-sentiment-analysis-kernels-only/prepare.py +58 -0
  180. mlebench/competitions/movie-review-sentiment-analysis-kernels-only/prepare_val.py +120 -0
  181. mlebench/competitions/multi-modal-gesture-recognition/grade.py +58 -0
  182. mlebench/competitions/multi-modal-gesture-recognition/prepare.py +85 -0
  183. mlebench/competitions/multi-modal-gesture-recognition/prepare_val.py +139 -0
  184. mlebench/competitions/my-custom-task-01/prepare.py +2 -0
  185. mlebench/competitions/new-my-task-01/prepare.py +2 -0
  186. mlebench/competitions/new-my-task-03/grade.py +107 -0
  187. mlebench/competitions/new-my-task-03/prepare.py +2 -0
  188. mlebench/competitions/new-york-city-taxi-fare-prediction/grade.py +28 -0
  189. mlebench/competitions/new-york-city-taxi-fare-prediction/prepare.py +44 -0
  190. mlebench/competitions/new-york-city-taxi-fare-prediction/prepare_val.py +89 -0
  191. mlebench/competitions/nfl-player-contact-detection/grade.py +36 -0
  192. mlebench/competitions/nfl-player-contact-detection/prepare.py +101 -0
  193. mlebench/competitions/nfl-player-contact-detection/prepare_val.py +186 -0
  194. mlebench/competitions/nomad2018-predict-transparent-conductors/grade.py +47 -0
  195. mlebench/competitions/nomad2018-predict-transparent-conductors/prepare.py +77 -0
  196. mlebench/competitions/nomad2018-predict-transparent-conductors/prepare_val.py +144 -0
  197. mlebench/competitions/osic-pulmonary-fibrosis-progression/grade.py +74 -0
  198. mlebench/competitions/osic-pulmonary-fibrosis-progression/prepare.py +95 -0
  199. mlebench/competitions/osic-pulmonary-fibrosis-progression/prepare_val.py +167 -0
  200. mlebench/competitions/paddy-disease-classification/grade.py +35 -0
  201. mlebench/competitions/paddy-disease-classification/prepare.py +69 -0
  202. mlebench/competitions/paddy-disease-classification/prepare_val.py +122 -0
  203. mlebench/competitions/petfinder-pawpularity-score/grade.py +41 -0
  204. mlebench/competitions/petfinder-pawpularity-score/prepare.py +76 -0
  205. mlebench/competitions/petfinder-pawpularity-score/prepare_val.py +154 -0
  206. mlebench/competitions/plant-pathology-2020-fgvc7/grade.py +41 -0
  207. mlebench/competitions/plant-pathology-2020-fgvc7/prepare.py +74 -0
  208. mlebench/competitions/plant-pathology-2020-fgvc7/prepare_val.py +160 -0
  209. mlebench/competitions/plant-pathology-2021-fgvc8/grade.py +54 -0
  210. mlebench/competitions/plant-pathology-2021-fgvc8/prepare.py +65 -0
  211. mlebench/competitions/plant-pathology-2021-fgvc8/prepare_val.py +130 -0
  212. mlebench/competitions/plant-seedlings-classification/grade.py +39 -0
  213. mlebench/competitions/plant-seedlings-classification/prepare.py +91 -0
  214. mlebench/competitions/plant-seedlings-classification/prepare_val.py +158 -0
  215. mlebench/competitions/playground-series-s3e1/__init__.py +0 -0
  216. mlebench/competitions/playground-series-s3e1/grade.py +52 -0
  217. mlebench/competitions/playground-series-s3e1/prepare.py +25 -0
  218. mlebench/competitions/playground-series-s3e11/__init__.py +0 -0
  219. mlebench/competitions/playground-series-s3e11/grade.py +55 -0
  220. mlebench/competitions/playground-series-s3e11/prepare.py +25 -0
  221. mlebench/competitions/playground-series-s3e18/grade.py +39 -0
  222. mlebench/competitions/playground-series-s3e18/prepare.py +36 -0
  223. mlebench/competitions/playground-series-s3e18/prepare_val.py +89 -0
  224. mlebench/competitions/playground_series_s3e1/__init__.py +0 -0
  225. mlebench/competitions/playground_series_s3e1/grade.py +52 -0
  226. mlebench/competitions/playground_series_s3e1/prepare.py +25 -0
  227. mlebench/competitions/playground_series_s3e11/__init__.py +0 -0
  228. mlebench/competitions/playground_series_s3e11/grade.py +55 -0
  229. mlebench/competitions/playground_series_s3e11/prepare.py +25 -0
  230. mlebench/competitions/predict-volcanic-eruptions-ingv-oe/grade.py +44 -0
  231. mlebench/competitions/predict-volcanic-eruptions-ingv-oe/prepare.py +68 -0
  232. mlebench/competitions/predict-volcanic-eruptions-ingv-oe/prepare_val.py +146 -0
  233. mlebench/competitions/random-acts-of-pizza/grade.py +14 -0
  234. mlebench/competitions/random-acts-of-pizza/prepare.py +80 -0
  235. mlebench/competitions/random-acts-of-pizza/prepare_val.py +144 -0
  236. mlebench/competitions/ranzcr-clip-catheter-line-classification/classes.py +11 -0
  237. mlebench/competitions/ranzcr-clip-catheter-line-classification/grade.py +31 -0
  238. mlebench/competitions/ranzcr-clip-catheter-line-classification/prepare.py +53 -0
  239. mlebench/competitions/ranzcr-clip-catheter-line-classification/prepare_val.py +113 -0
  240. mlebench/competitions/rsna-2022-cervical-spine-fracture-detection/grade.py +124 -0
  241. mlebench/competitions/rsna-2022-cervical-spine-fracture-detection/prepare.py +219 -0
  242. mlebench/competitions/rsna-2022-cervical-spine-fracture-detection/prepare_val.py +257 -0
  243. mlebench/competitions/rsna-breast-cancer-detection/grade.py +65 -0
  244. mlebench/competitions/rsna-breast-cancer-detection/prepare.py +141 -0
  245. mlebench/competitions/rsna-breast-cancer-detection/prepare_val.py +201 -0
  246. mlebench/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/grade.py +13 -0
  247. mlebench/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/prepare.py +47 -0
  248. mlebench/competitions/rsna-miccai-brain-tumor-radiogenomic-classification/prepare_val.py +97 -0
  249. mlebench/competitions/santander-customer-satisfaction/grade.py +10 -0
  250. mlebench/competitions/santander-customer-satisfaction/prepare.py +41 -0
  251. mlebench/competitions/sciencebench-001-clintox-nn/__init__.py +0 -0
  252. mlebench/competitions/sciencebench-001-clintox-nn/grade.py +56 -0
  253. mlebench/competitions/sciencebench-001-clintox-nn/prepare.py +75 -0
  254. mlebench/competitions/sciencebench-015-aai/grade.py +37 -0
  255. mlebench/competitions/sciencebench-015-aai/prepare.py +102 -0
  256. mlebench/competitions/sciencebench-051-brain-blood-qsar/grade.py +58 -0
  257. mlebench/competitions/sciencebench-051-brain-blood-qsar/prepare.py +69 -0
  258. mlebench/competitions/sciencebench-101-experimental-band-gap-prediction/grade.py +55 -0
  259. mlebench/competitions/sciencebench-101-experimental-band-gap-prediction/prepare.py +88 -0
  260. mlebench/competitions/see-click-predict-fix/__init__.py +0 -0
  261. mlebench/competitions/see-click-predict-fix/grade.py +66 -0
  262. mlebench/competitions/see-click-predict-fix/prepare.py +25 -0
  263. mlebench/competitions/see_click_predict_fix/__init__.py +0 -0
  264. mlebench/competitions/see_click_predict_fix/grade.py +66 -0
  265. mlebench/competitions/see_click_predict_fix/prepare.py +25 -0
  266. mlebench/competitions/seti-breakthrough-listen/grade.py +11 -0
  267. mlebench/competitions/seti-breakthrough-listen/prepare.py +71 -0
  268. mlebench/competitions/seti-breakthrough-listen/prepare_val.py +159 -0
  269. mlebench/competitions/siim-covid19-detection/grade.py +194 -0
  270. mlebench/competitions/siim-covid19-detection/prepare.py +123 -0
  271. mlebench/competitions/siim-covid19-detection/prepare_val.py +164 -0
  272. mlebench/competitions/siim-isic-melanoma-classification/grade.py +11 -0
  273. mlebench/competitions/siim-isic-melanoma-classification/prepare.py +127 -0
  274. mlebench/competitions/siim-isic-melanoma-classification/prepare_val.py +158 -0
  275. mlebench/competitions/smartphone-decimeter-2022/grade.py +55 -0
  276. mlebench/competitions/smartphone-decimeter-2022/notebook.py +86 -0
  277. mlebench/competitions/smartphone-decimeter-2022/prepare.py +143 -0
  278. mlebench/competitions/smartphone-decimeter-2022/prepare_val.py +199 -0
  279. mlebench/competitions/spaceship-titanic/grade.py +11 -0
  280. mlebench/competitions/spaceship-titanic/prepare.py +23 -0
  281. mlebench/competitions/spaceship-titanic/prepare_val.py +61 -0
  282. mlebench/competitions/spooky-author-identification/classes.py +1 -0
  283. mlebench/competitions/spooky-author-identification/grade.py +38 -0
  284. mlebench/competitions/spooky-author-identification/prepare.py +40 -0
  285. mlebench/competitions/spooky-author-identification/prepare_val.py +78 -0
  286. mlebench/competitions/stanford-covid-vaccine/grade.py +65 -0
  287. mlebench/competitions/stanford-covid-vaccine/prepare.py +129 -0
  288. mlebench/competitions/stanford-covid-vaccine/prepare_val.py +199 -0
  289. mlebench/competitions/statoil-iceberg-classifier-challenge/grade.py +41 -0
  290. mlebench/competitions/statoil-iceberg-classifier-challenge/prepare.py +105 -0
  291. mlebench/competitions/statoil-iceberg-classifier-challenge/prepare_val.py +157 -0
  292. mlebench/competitions/tabular-playground-series-dec-2021/grade.py +11 -0
  293. mlebench/competitions/tabular-playground-series-dec-2021/prepare.py +39 -0
  294. mlebench/competitions/tabular-playground-series-dec-2021/prepare_val.py +99 -0
  295. mlebench/competitions/tabular-playground-series-may-2022/grade.py +9 -0
  296. mlebench/competitions/tabular-playground-series-may-2022/prepare.py +56 -0
  297. mlebench/competitions/tabular-playground-series-may-2022/prepare_val.py +116 -0
  298. mlebench/competitions/tensorflow-speech-recognition-challenge/grade.py +11 -0
  299. mlebench/competitions/tensorflow-speech-recognition-challenge/prepare.py +90 -0
  300. mlebench/competitions/tensorflow-speech-recognition-challenge/prepare_val.py +148 -0
  301. mlebench/competitions/tensorflow2-question-answering/grade.py +122 -0
  302. mlebench/competitions/tensorflow2-question-answering/prepare.py +122 -0
  303. mlebench/competitions/tensorflow2-question-answering/prepare_val.py +187 -0
  304. mlebench/competitions/text-normalization-challenge-english-language/grade.py +49 -0
  305. mlebench/competitions/text-normalization-challenge-english-language/prepare.py +115 -0
  306. mlebench/competitions/text-normalization-challenge-english-language/prepare_val.py +213 -0
  307. mlebench/competitions/text-normalization-challenge-russian-language/grade.py +49 -0
  308. mlebench/competitions/text-normalization-challenge-russian-language/prepare.py +113 -0
  309. mlebench/competitions/text-normalization-challenge-russian-language/prepare_val.py +165 -0
  310. mlebench/competitions/tgs-salt-identification-challenge/grade.py +144 -0
  311. mlebench/competitions/tgs-salt-identification-challenge/prepare.py +158 -0
  312. mlebench/competitions/tgs-salt-identification-challenge/prepare_val.py +166 -0
  313. mlebench/competitions/the-icml-2013-whale-challenge-right-whale-redux/grade.py +11 -0
  314. mlebench/competitions/the-icml-2013-whale-challenge-right-whale-redux/prepare.py +95 -0
  315. mlebench/competitions/the-icml-2013-whale-challenge-right-whale-redux/prepare_val.py +141 -0
  316. mlebench/competitions/tmdb-box-office-prediction/__init__.py +0 -0
  317. mlebench/competitions/tmdb-box-office-prediction/grade.py +55 -0
  318. mlebench/competitions/tmdb-box-office-prediction/prepare.py +35 -0
  319. mlebench/competitions/tweet-sentiment-extraction/grade.py +67 -0
  320. mlebench/competitions/tweet-sentiment-extraction/prepare.py +36 -0
  321. mlebench/competitions/tweet-sentiment-extraction/prepare_val.py +106 -0
  322. mlebench/competitions/us-patent-phrase-to-phrase-matching/grade.py +31 -0
  323. mlebench/competitions/us-patent-phrase-to-phrase-matching/prepare.py +33 -0
  324. mlebench/competitions/us-patent-phrase-to-phrase-matching/prepare_val.py +71 -0
  325. mlebench/competitions/utils.py +266 -0
  326. mlebench/competitions/uw-madison-gi-tract-image-segmentation/grade.py +158 -0
  327. mlebench/competitions/uw-madison-gi-tract-image-segmentation/prepare.py +139 -0
  328. mlebench/competitions/uw-madison-gi-tract-image-segmentation/prepare_val.py +193 -0
  329. mlebench/competitions/ventilator-pressure-prediction/__init__.py +0 -0
  330. mlebench/competitions/ventilator-pressure-prediction/grade.py +52 -0
  331. mlebench/competitions/ventilator-pressure-prediction/prepare.py +27 -0
  332. mlebench/competitions/ventilator-pressure-prediction/prepare_val.py +142 -0
  333. mlebench/competitions/ventilator_pressure_prediction/__init__.py +0 -0
  334. mlebench/competitions/ventilator_pressure_prediction/grade.py +52 -0
  335. mlebench/competitions/ventilator_pressure_prediction/prepare.py +27 -0
  336. mlebench/competitions/vesuvius-challenge-ink-detection/grade.py +97 -0
  337. mlebench/competitions/vesuvius-challenge-ink-detection/prepare.py +122 -0
  338. mlebench/competitions/vesuvius-challenge-ink-detection/prepare_val.py +170 -0
  339. mlebench/competitions/vinbigdata-chest-xray-abnormalities-detection/grade.py +220 -0
  340. mlebench/competitions/vinbigdata-chest-xray-abnormalities-detection/prepare.py +129 -0
  341. mlebench/competitions/vinbigdata-chest-xray-abnormalities-detection/prepare_val.py +204 -0
  342. mlebench/competitions/whale-categorization-playground/grade.py +41 -0
  343. mlebench/competitions/whale-categorization-playground/prepare.py +103 -0
  344. mlebench/competitions/whale-categorization-playground/prepare_val.py +196 -0
  345. mlebench/data.py +420 -0
  346. mlebench/grade.py +209 -0
  347. mlebench/grade_helpers.py +235 -0
  348. mlebench/metrics.py +75 -0
  349. mlebench/registry.py +332 -0
  350. mlebench/utils.py +346 -0
  351. {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/WHEEL +0 -0
  352. {dslighting-1.7.1.dist-info → dslighting-1.7.6.dist-info}/entry_points.txt +0 -0
mlebench/data.py ADDED
@@ -0,0 +1,420 @@
1
+ import functools
2
+ import hashlib
3
+ import inspect
4
+ import os
5
+ import shutil
6
+ import webbrowser
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+ from typing import Any, Callable, Optional
10
+
11
+ import diskcache as dc
12
+ import pandas as pd
13
+ import yaml
14
+ from tenacity import retry, retry_if_exception, stop_after_attempt, wait_fixed
15
+ from tqdm.auto import tqdm
16
+
17
+ from mlebench.registry import Competition
18
+ from mlebench.utils import (
19
+ authenticate_kaggle_api,
20
+ extract,
21
+ get_diff,
22
+ get_logger,
23
+ get_path_to_callable,
24
+ is_empty,
25
+ load_yaml,
26
+ )
27
+
28
+ logger = get_logger(__name__)
29
+ #cache = dc.Cache("cache", size_limit=2**26) # 64 MB
30
+ # 修改为
31
+ import tempfile
32
+ cache_dir = os.path.join(tempfile.gettempdir(), f"mlebench_cache_{os.getpid()}")
33
+ cache = dc.Cache(cache_dir, size_limit=2**26) # 64 MB
34
+
35
+ def create_prepared_dir(competition: Competition) -> None:
36
+ competition.public_dir.mkdir(exist_ok=True, parents=True)
37
+ competition.private_dir.mkdir(exist_ok=True, parents=True)
38
+
39
+
40
+ def download_and_prepare_dataset(
41
+ competition: Competition,
42
+ keep_raw: bool = True,
43
+ overwrite_checksums: bool = False,
44
+ overwrite_leaderboard: bool = False,
45
+ skip_verification: bool = False,
46
+ ) -> None:
47
+ """
48
+ Creates a `public` and `private` directory for the competition using the `prepare_fn`,
49
+ downloading the competition's dataset zip file and extracting it into `raw` if needed.
50
+ """
51
+
52
+ assert is_valid_prepare_fn(
53
+ competition.prepare_fn
54
+ ), f"Provided `prepare_fn` doesn't take arguments `raw`, `private` and `public`!"
55
+
56
+ ensure_leaderboard_exists(competition, force=overwrite_leaderboard)
57
+
58
+ competition_dir = competition.raw_dir.parent
59
+
60
+ competition.raw_dir.mkdir(exist_ok=True, parents=True)
61
+ create_prepared_dir(competition)
62
+
63
+ zipfile = download_dataset(
64
+ competition_id=competition.id,
65
+ download_dir=competition_dir,
66
+ force=False,
67
+ )
68
+
69
+ if overwrite_checksums or not skip_verification:
70
+ logger.info(f"Generating checksum for `{zipfile}`...")
71
+ actual_zip_checksum = get_checksum(zipfile)
72
+
73
+ if competition.checksums.is_file() and not overwrite_checksums:
74
+ expected_checksums = load_yaml(competition.checksums)
75
+ expected_zip_checksum = expected_checksums["zip"]
76
+
77
+ if actual_zip_checksum != expected_zip_checksum:
78
+ raise ValueError(
79
+ f"Checksum for `{zipfile}` does not match the expected checksum! "
80
+ f"Expected `{expected_zip_checksum}` but got `{actual_zip_checksum}`."
81
+ )
82
+
83
+ logger.info(f"Checksum for `{zipfile}` matches the expected checksum.")
84
+
85
+ if is_empty(competition.raw_dir):
86
+ logger.info(f"Extracting `{zipfile}` to `{competition.raw_dir}`...")
87
+ extract(zipfile, competition.raw_dir, recursive=False)
88
+ logger.info(f"Extracted `{zipfile}` to `{competition.raw_dir}` successfully.")
89
+
90
+ if not is_dataset_prepared(competition) or overwrite_checksums:
91
+ if competition.public_dir.parent.exists() and overwrite_checksums:
92
+ logger.info(
93
+ f"Removing the existing prepared data directory for `{competition.id}` since "
94
+ "`overwrite_checksums` is set to `True`..."
95
+ )
96
+ shutil.rmtree(competition.public_dir.parent)
97
+ create_prepared_dir(competition)
98
+
99
+ logger.info(
100
+ f"Preparing the dataset using `{competition.prepare_fn.__name__}` from "
101
+ f"`{get_path_to_callable(competition.prepare_fn)}`..."
102
+ )
103
+
104
+ competition.prepare_fn(
105
+ raw=competition.raw_dir,
106
+ public=competition.public_dir,
107
+ private=competition.private_dir,
108
+ )
109
+
110
+ logger.info(f"Data for competition `{competition.id}` prepared successfully.")
111
+
112
+ with open(competition.public_dir / "description.md", "w") as f:
113
+ f.write(competition.description)
114
+
115
+ # Also save to public_val directory
116
+ public_val_dir = competition.public_dir.parent / (competition.public_dir.name + "_val")
117
+ if public_val_dir.exists():
118
+ with open(public_val_dir / "description.md", "w") as f:
119
+ f.write(competition.description)
120
+
121
+ if overwrite_checksums or not skip_verification:
122
+ logger.info(f"Generating checksums for files in `{competition_dir}`...")
123
+
124
+ actual_checksums = {
125
+ "zip": actual_zip_checksum,
126
+ "public": generate_checksums(competition.public_dir),
127
+ "private": generate_checksums(competition.private_dir),
128
+ }
129
+
130
+ if not competition.checksums.is_file() or overwrite_checksums:
131
+ with open(competition.checksums, "w") as file:
132
+ yaml.dump(actual_checksums, file, default_flow_style=False)
133
+
134
+ logger.info(f"Checksums for `{competition.id}` saved to `{competition.checksums}`.")
135
+
136
+ expected_checksums = load_yaml(competition.checksums)
137
+
138
+ if actual_checksums != expected_checksums:
139
+ logger.error(f"Checksums do not match for `{competition.id}`!")
140
+
141
+ diff = get_diff(
142
+ actual_checksums,
143
+ expected_checksums,
144
+ fromfile="actual_checksums",
145
+ tofile="expected_checksums",
146
+ )
147
+
148
+ raise ValueError(f"Checksums do not match for `{competition.id}`!\n{diff}")
149
+
150
+ logger.info(f"Checksums for files in `{competition_dir}` match the expected checksums.")
151
+
152
+ if not keep_raw:
153
+ logger.info(f"Removing the raw data directory for `{competition.id}`...")
154
+ shutil.rmtree(competition.raw_dir)
155
+
156
+ assert competition.public_dir.is_dir(), f"Public data directory doesn't exist."
157
+ assert competition.private_dir.is_dir(), f"Private data directory doesn't exist."
158
+ assert not is_empty(competition.public_dir), f"Public data directory is empty!"
159
+ assert not is_empty(competition.private_dir), f"Private data directory is empty!"
160
+
161
+
162
+ def is_dataset_prepared(competition: Competition, grading_only: bool = False) -> bool:
163
+ """Checks if the competition has non-empty `public` and `private` directories with the expected files."""
164
+
165
+ assert isinstance(
166
+ competition, Competition
167
+ ), f"Expected input to be of type `Competition` but got {type(competition)}."
168
+
169
+ public = competition.public_dir
170
+ private = competition.private_dir
171
+
172
+ if not grading_only:
173
+ if not public.is_dir():
174
+ logger.warning("Public directory does not exist.")
175
+ return False
176
+ if is_empty(public):
177
+ logger.warning("Public directory is empty.")
178
+ return False
179
+
180
+ if not private.is_dir():
181
+ logger.warning("Private directory does not exist.")
182
+ return False
183
+ if is_empty(private):
184
+ logger.warning("Private directory is empty.")
185
+ return False
186
+
187
+ if not competition.answers.is_file():
188
+ logger.warning("Answers file does not exist.")
189
+ return False
190
+
191
+ if not competition.sample_submission.is_file() and not grading_only:
192
+ logger.warning("Sample submission file does not exist.")
193
+ return False
194
+
195
+ return True
196
+
197
+
198
+ def is_api_exception(exception: Exception) -> bool:
199
+ # only import when necessary; otherwise kaggle asks for API key on import
200
+ #from kaggle.rest import ApiException
201
+ try:
202
+ from kaggle.rest import ApiException
203
+ except ImportError:
204
+ class ApiException(Exception): pass
205
+
206
+ return isinstance(exception, ApiException)
207
+
208
+
209
+ @retry(
210
+ retry=retry_if_exception(is_api_exception),
211
+ stop=stop_after_attempt(3), # stop after 3 attempts
212
+ wait=wait_fixed(5), # wait 5 seconds between attempts
213
+ reraise=True,
214
+ )
215
+ def download_dataset(
216
+ competition_id: str,
217
+ download_dir: Path,
218
+ quiet: bool = False,
219
+ force: bool = False,
220
+ ) -> Path:
221
+ """Downloads the competition data as a zip file using the Kaggle API and returns the path to the zip file."""
222
+
223
+ if not download_dir.exists():
224
+ download_dir.mkdir(parents=True)
225
+
226
+ logger.info(f"Downloading the dataset for `{competition_id}` to `{download_dir}`...")
227
+
228
+ api = authenticate_kaggle_api()
229
+
230
+ # only import when necessary; otherwise kaggle asks for API key on import
231
+ from kaggle.rest import ApiException
232
+
233
+ try:
234
+ api.competition_download_files(
235
+ competition=competition_id,
236
+ path=download_dir,
237
+ quiet=quiet,
238
+ force=force,
239
+ )
240
+ except ApiException as e:
241
+ if _need_to_accept_rules(str(e)):
242
+ logger.warning("You must accept the competition rules before downloading the dataset.")
243
+ _prompt_user_to_accept_rules(competition_id)
244
+ download_dataset(competition_id, download_dir, quiet, force)
245
+ else:
246
+ raise e
247
+
248
+ zip_files = list(download_dir.glob("*.zip"))
249
+
250
+ assert (
251
+ len(zip_files) == 1
252
+ ), f"Expected to download a single zip file, but found {len(zip_files)} zip files."
253
+
254
+ zip_file = zip_files[0]
255
+
256
+ return zip_file
257
+
258
+
259
+ def _need_to_accept_rules(error_msg: str) -> bool:
260
+ return "You must accept this competition" in error_msg
261
+
262
+
263
+ def _prompt_user_to_accept_rules(competition_id: str) -> None:
264
+ response = input("Would you like to open the competition page in your browser now? (y/n): ")
265
+
266
+ if response.lower() != "y":
267
+ raise RuntimeError("You must accept the competition rules before downloading the dataset.")
268
+
269
+ webbrowser.open(f"https://www.kaggle.com/c/{competition_id}/rules")
270
+ input("Press Enter to continue after you have accepted the rules...")
271
+
272
+
273
+ def is_valid_prepare_fn(preparer_fn: Any) -> bool:
274
+ """Checks if the `preparer_fn` takes three arguments: `raw`, `public` and `private`, in that order."""
275
+
276
+ try:
277
+ sig = inspect.signature(preparer_fn)
278
+ except (TypeError, ValueError):
279
+ return False
280
+
281
+ actual_params = list(sig.parameters.keys())
282
+ expected_params = ["raw", "public", "private"]
283
+
284
+ return actual_params == expected_params
285
+
286
+
287
+ def generate_checksums(
288
+ target_dir: Path,
289
+ exts: Optional[list[str]] = None,
290
+ exclude: Optional[list[Path]] = None,
291
+ ) -> dict:
292
+ """
293
+ Generate checksums for the files directly under the target directory with the specified extensions.
294
+
295
+ Args:
296
+ target_dir: directory to generate checksums for.
297
+ exts: List of file extensions to generate checksums for.
298
+ exclude: List of file paths to exclude from checksum generation.
299
+
300
+ Returns:
301
+ A dictionary of form file: checksum.
302
+ """
303
+
304
+ if exts is None:
305
+ exts = ["csv", "json", "jsonl", "parquet", "bson"]
306
+
307
+ if exclude is None:
308
+ exclude = []
309
+
310
+ checksums = {}
311
+
312
+ for ext in exts:
313
+ fpaths = target_dir.glob(f"*.{ext}")
314
+
315
+ for fpath in fpaths:
316
+ if not fpath.is_file():
317
+ continue # skip dirs named like `my/dir.csv/`
318
+
319
+ if fpath in exclude:
320
+ continue
321
+
322
+ checksums[fpath.name] = get_checksum(fpath)
323
+
324
+ return checksums
325
+
326
+
327
+ def get_last_modified(fpath: Path) -> datetime:
328
+ """Return the last modified time of a file."""
329
+
330
+ return datetime.fromtimestamp(fpath.stat().st_mtime)
331
+
332
+
333
+ def file_cache(fn: Callable) -> Callable:
334
+ """A decorator that caches results of a function with a Path argument, invalidating the cache when the file is modified."""
335
+
336
+ sig = inspect.signature(fn)
337
+ params = list(sig.parameters.values())
338
+
339
+ if not (len(params) == 1 and params[0].annotation is Path):
340
+ raise NotImplementedError("Only functions with a single `Path` argument are supported.")
341
+
342
+ # Use `functools.wraps` to preserve the function's metadata, like the name and docstring.
343
+ # Query the cache, but with an additional `last_modified` argument in the key, which has the
344
+ # side effect of invalidating the cache when the file is modified.
345
+ @functools.wraps(fn)
346
+ def wrapper(fpath: Path) -> Any:
347
+ last_modified = get_last_modified(fpath)
348
+ key = (fn.__name__, str(fpath), last_modified)
349
+
350
+ if key not in cache:
351
+ cache[key] = fn(fpath)
352
+
353
+ return cache[key]
354
+
355
+ return wrapper
356
+
357
+
358
+ @file_cache
359
+ def get_checksum(fpath: Path) -> str:
360
+ """Compute MD5 checksum of a file."""
361
+
362
+ assert fpath.is_file(), f"Expected a file at `{fpath}`, but it doesn't exist."
363
+
364
+ hash_md5 = hashlib.md5()
365
+ file_size = os.path.getsize(fpath)
366
+
367
+ # only show progress bar for large files (> ~5 GB)
368
+ show_progress = file_size > 5_000_000_000
369
+
370
+ with open(fpath, "rb") as f:
371
+ for chunk in tqdm(
372
+ iter(lambda: f.read(4_096), b""),
373
+ total=file_size // 4096,
374
+ unit="B",
375
+ unit_scale=True,
376
+ disable=not show_progress,
377
+ ):
378
+ hash_md5.update(chunk)
379
+
380
+ return hash_md5.hexdigest()
381
+
382
+
383
+ def ensure_leaderboard_exists(competition: Competition, force: bool = False) -> Path:
384
+ """
385
+ Ensures the leaderboard for a given competition exists in the competition's
386
+ directory, returning the path to it.
387
+ If `force` is True, the leaderboard is downloaded using the Kaggle API.
388
+ If `force` is `false`, if the leaderboard does not exist, an error is raised.
389
+ """
390
+ download_dir = competition.leaderboard.parent
391
+ leaderboard_path = competition.leaderboard
392
+ if not force:
393
+ if leaderboard_path.exists():
394
+ return leaderboard_path
395
+ else:
396
+ raise FileNotFoundError(
397
+ f"Leaderboard not found locally for competition `{competition.id}`. Please flag this to the developers."
398
+ )
399
+ api = authenticate_kaggle_api()
400
+ leaderboard = api.competition_leaderboard_view(competition=competition.id)
401
+ if leaderboard:
402
+ leaderboard = [row.__dict__ for row in leaderboard]
403
+ leaderboard_df = pd.DataFrame(leaderboard)
404
+ leaderboard_df.drop(columns=["teamNameNullable", "teamName"], inplace=True)
405
+ leaderboard_df.to_csv(leaderboard_path, index=False)
406
+ logger.info(
407
+ f"Downloaded leaderboard for competition `{competition.id}` to `{download_dir.relative_to(Path.cwd()) / 'leaderboard.csv'}`."
408
+ )
409
+ return leaderboard_path
410
+ else:
411
+ raise RuntimeError(f"Failed to download leaderboard for competition `{competition.id}`.")
412
+
413
+
414
+ def get_leaderboard(competition: Competition) -> pd.DataFrame:
415
+ leaderboard_path = competition.leaderboard
416
+ assert (
417
+ leaderboard_path.exists()
418
+ ), f"Leaderboard not found locally for competition `{competition.id}`."
419
+ leaderboard_df = pd.read_csv(leaderboard_path)
420
+ return leaderboard_df
mlebench/grade.py ADDED
@@ -0,0 +1,209 @@
1
+ """High-level grading functionality"""
2
+ import json
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+
6
+ import pandas as pd
7
+ from tqdm import tqdm
8
+
9
+ from mlebench.data import get_leaderboard, is_dataset_prepared
10
+ from mlebench.grade_helpers import CompetitionReport
11
+ from mlebench.registry import Competition, Registry
12
+ from mlebench.registry import registry as DEFAULT_REGISTRY
13
+ from mlebench.utils import get_logger, get_timestamp, load_answers, purple, read_csv, read_jsonl
14
+
15
+ logger = get_logger(__name__)
16
+
17
+
18
+ def grade_jsonl(
19
+ path_to_submissions: Path,
20
+ output_dir: Path,
21
+ registry: Registry = DEFAULT_REGISTRY,
22
+ ):
23
+ """
24
+ Grades multiple submissions stored in a JSONL file.
25
+ Saves the aggregated report as a JSON file.
26
+ """
27
+
28
+ submissions = read_jsonl(path_to_submissions, skip_commented_out_lines=True)
29
+ competitions_reports = []
30
+
31
+ for submission in tqdm(submissions, desc="Grading submissions", unit="submission"):
32
+ submission_path = Path(str(submission["submission_path"]))
33
+ competition_id = submission["competition_id"]
34
+ competition = registry.get_competition(competition_id)
35
+ single_report = grade_csv(submission_path, competition)
36
+ competitions_reports.append(single_report)
37
+
38
+ aggregated_report = aggregate_reports(competitions_reports)
39
+ timestamp = get_timestamp()
40
+ save_path = output_dir / f"{timestamp}_grading_report.json"
41
+ logger.info(
42
+ json.dumps(
43
+ {k: v for k, v in aggregated_report.items() if k != "competition_reports"}, indent=4
44
+ )
45
+ )
46
+
47
+ output_dir.mkdir(exist_ok=True)
48
+ with open(save_path, "w") as f:
49
+ json.dump(aggregated_report, f, indent=2)
50
+ logger.info(purple(f"Saved summary report to {save_path}"))
51
+
52
+
53
+ def grade_csv(path_to_submission: Path, competition: Competition) -> CompetitionReport:
54
+ """Grades a submission CSV for the given competition."""
55
+
56
+ if not is_dataset_prepared(competition, grading_only=True):
57
+ raise ValueError(
58
+ f"Dataset for competition `{competition.id}` is not prepared! "
59
+ f"Please run `mlebench prepare -c {competition.id}` to prepare the dataset."
60
+ )
61
+
62
+ score = None
63
+ submission_exists = path_to_submission.is_file() and path_to_submission.suffix.lower() == ".csv"
64
+
65
+ if submission_exists:
66
+ submission_df = read_csv(path_to_submission)
67
+ logger.info(purple(f"Load answers from {competition.answers}"))
68
+ answers = load_answers(competition.answers)
69
+ score = competition.grader(submission_df, answers)
70
+ else:
71
+ logger.warning(
72
+ f"Invalid submission file: {path_to_submission}. Please check that the file exists and it is a CSV."
73
+ )
74
+
75
+ valid_submission = score is not None
76
+ competition_leaderboard = get_leaderboard(competition)
77
+ rank_info = competition.grader.rank_score(score, competition_leaderboard)
78
+ is_lower_better = competition.grader.is_lower_better(competition_leaderboard)
79
+
80
+ return CompetitionReport(
81
+ competition_id=competition.id,
82
+ score=score,
83
+ gold_threshold=rank_info["gold_threshold"],
84
+ silver_threshold=rank_info["silver_threshold"],
85
+ bronze_threshold=rank_info["bronze_threshold"],
86
+ median_threshold=rank_info["median_threshold"],
87
+ any_medal=rank_info["gold_medal"] or rank_info["silver_medal"] or rank_info["bronze_medal"],
88
+ gold_medal=rank_info["gold_medal"],
89
+ silver_medal=rank_info["silver_medal"],
90
+ bronze_medal=rank_info["bronze_medal"],
91
+ above_median=rank_info["above_median"],
92
+ submission_exists=submission_exists,
93
+ valid_submission=valid_submission,
94
+ is_lower_better=is_lower_better,
95
+ created_at=datetime.now(),
96
+ submission_path=str(path_to_submission),
97
+ )
98
+
99
+
100
+ def validate_submission(submission: Path, competition: Competition) -> tuple[bool, str]:
101
+ """
102
+ Validates a submission for the given competition by actually running the competition grader.
103
+ This is designed for end users, not developers (we assume that the competition grader is
104
+ correctly implemented and use that for validating the submission, not the other way around).
105
+ """
106
+ if not submission.is_file():
107
+ return False, f"Submission invalid! Submission file {submission} does not exist."
108
+
109
+ if not submission.suffix.lower() == ".csv":
110
+ return False, "Submission invalid! Submission file must be a CSV file."
111
+
112
+ if not is_dataset_prepared(competition, grading_only=True):
113
+ raise ValueError(
114
+ f"Dataset for competition `{competition.id}` is not prepared! "
115
+ f"Please run `mlebench prepare -c {competition.id}` to prepare the dataset."
116
+ )
117
+
118
+ try:
119
+ competition.grader.grade_fn(read_csv(submission), read_csv(competition.answers))
120
+ except Exception as e:
121
+ return (
122
+ False,
123
+ f"Submission invalid! The attempt to grade the submission has resulted in the following error message:\n{e}",
124
+ )
125
+
126
+ return True, "Submission is valid."
127
+
128
+
129
+ def aggregate_reports(competition_reports: list[CompetitionReport]) -> dict:
130
+ """
131
+ Builds the summary report from a list of competition reports.
132
+ If pass_at_n is True, then aggregate performence of competitions by selecting the best performance per
133
+ competition, otherwise sum metrics
134
+ """
135
+
136
+ total_gold_medals = sum(report.gold_medal for report in competition_reports)
137
+ total_silver_medals = sum(report.silver_medal for report in competition_reports)
138
+ total_bronze_medals = sum(report.bronze_medal for report in competition_reports)
139
+ total_above_median = sum(report.above_median for report in competition_reports)
140
+ total_submissions = sum(report.submission_exists for report in competition_reports)
141
+ total_valid_submissions = sum(report.valid_submission for report in competition_reports)
142
+
143
+ summary_report = {
144
+ "total_runs": int(len(competition_reports)),
145
+ "total_runs_with_submissions": int(total_submissions),
146
+ "total_valid_submissions": int(total_valid_submissions),
147
+ "total_medals": int(total_gold_medals + total_silver_medals + total_bronze_medals),
148
+ "total_gold_medals": int(total_gold_medals),
149
+ "total_silver_medals": int(total_silver_medals),
150
+ "total_bronze_medals": int(total_bronze_medals),
151
+ "total_above_median": int(total_above_median),
152
+ "competition_reports": [cr.to_dict() for cr in competition_reports],
153
+ }
154
+
155
+ return summary_report
156
+
157
+ def simple_accuracy_grader(submission: pd.DataFrame, answers: pd.DataFrame) -> float:
158
+ """
159
+ Computes simple accuracy between submission and answers.
160
+ Assumes matching order or joins on an ID column.
161
+ """
162
+ try:
163
+ # 1. Try to find ID column to merge on
164
+ id_col = None
165
+ common_cols = set(submission.columns).intersection(set(answers.columns))
166
+ for col in common_cols:
167
+ if col.lower() in ['id', 'key', 'index', 'sample_id', 'image_id', 'patient_id']:
168
+ id_col = col
169
+ break
170
+
171
+ if id_col:
172
+ merged = submission.merge(answers, on=id_col, suffixes=('_pred', '_true'))
173
+ # Compare all other columns
174
+ pred_cols = [c for c in submission.columns if c != id_col]
175
+ true_cols = [c for c in answers.columns if c != id_col]
176
+
177
+ # If there's only one other column, compare it
178
+ if len(pred_cols) == 1 and len(true_cols) == 1:
179
+ return float((merged[pred_cols[0]] == merged[true_cols[0]]).mean())
180
+
181
+ # Iterate over shared columns that are NOT id
182
+ shared_content_cols = [c for c in common_cols if c != id_col]
183
+ if shared_content_cols:
184
+ matches = []
185
+ for c in shared_content_cols:
186
+ # In merged df, they are c_pred and c_true
187
+ matches.append((merged[f"{c}_pred"] == merged[f"{c}_true"]).mean())
188
+ if matches:
189
+ return float(sum(matches) / len(matches))
190
+
191
+ # 2. Fallback: Position-based comparison (assuming sorted)
192
+ if len(submission) == len(answers):
193
+ # Compare last column if dimensions match
194
+ if submission.shape[1] == answers.shape[1]:
195
+ return float((submission.iloc[:, -1] == answers.iloc[:, -1]).mean())
196
+
197
+ # Or compare specific common columns
198
+ common_cols = set(submission.columns).intersection(set(answers.columns))
199
+ if common_cols:
200
+ matches = []
201
+ for c in common_cols:
202
+ matches.append((submission[c] == answers[c]).mean())
203
+ if matches:
204
+ return float(sum(matches) / len(matches))
205
+ except Exception as e:
206
+ logger.error(f"simple_accuracy_grader failed: {e}")
207
+ return 0.0
208
+
209
+ return 0.0