scikit-rec 0.4__tar.gz → 0.4.2__tar.gz

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 (323) hide show
  1. {scikit_rec-0.4 → scikit_rec-0.4.2}/.github/workflows/ci.yml +1 -1
  2. {scikit_rec-0.4 → scikit_rec-0.4.2}/PKG-INFO +2 -2
  3. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/advanced/orchestration.md +3 -1
  4. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/examples/index.md +18 -0
  5. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/getting-started/datasets.md +18 -0
  6. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/capability-matrix.md +17 -2
  7. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/estimators.md +23 -2
  8. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/scorers.md +97 -4
  9. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/training.md +4 -0
  10. scikit_rec-0.4.2/examples/generic/multioutput_per_label_vs_joint_xgb.ipynb +688 -0
  11. {scikit_rec-0.4 → scikit_rec-0.4.2}/pyproject.toml +2 -1
  12. {scikit_rec-0.4 → scikit_rec-0.4.2}/scikit_rec.egg-info/PKG-INFO +2 -2
  13. {scikit_rec-0.4 → scikit_rec-0.4.2}/scikit_rec.egg-info/SOURCES.txt +12 -0
  14. {scikit_rec-0.4 → scikit_rec-0.4.2}/scikit_rec.egg-info/requires.txt +1 -1
  15. scikit_rec-0.4.2/scikit_rec.egg-info/scm_file_list.json +312 -0
  16. scikit_rec-0.4.2/scikit_rec.egg-info/scm_version.json +8 -0
  17. scikit_rec-0.4.2/skrec/dataset/batch_training_dataset.py +198 -0
  18. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/dataset.py +74 -3
  19. scikit_rec-0.4.2/skrec/dataset/local_data_reader.py +81 -0
  20. scikit_rec-0.4.2/skrec/dataset/partitioning.py +42 -0
  21. scikit_rec-0.4.2/skrec/dataset/s3_data_reader.py +157 -0
  22. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/schema.py +25 -3
  23. scikit_rec-0.4.2/skrec/estimator/_fit_params_mixin.py +178 -0
  24. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/__init__.py +4 -0
  25. scikit_rec-0.4.2/skrec/estimator/classification/joint_xgb_multioutput.py +134 -0
  26. scikit_rec-0.4.2/skrec/estimator/classification/lightgbm_classifier.py +65 -0
  27. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/multioutput_classifier.py +21 -3
  28. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/sklearn_universal_classifier.py +22 -4
  29. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/xgb_classifier.py +53 -10
  30. scikit_rec-0.4.2/skrec/estimator/regression/__init__.py +7 -0
  31. scikit_rec-0.4.2/skrec/estimator/regression/joint_xgb_multioutput.py +81 -0
  32. scikit_rec-0.4.2/skrec/estimator/regression/lightgbm_regressor.py +65 -0
  33. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/regression/multioutput_regressor.py +21 -3
  34. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/regression/sklearn_universal_regressor.py +22 -4
  35. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/regression/xgb_regressor.py +28 -6
  36. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/tuned_estimator.py +20 -4
  37. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/orchestrator/factory.py +103 -11
  38. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/base_recommender.py +31 -8
  39. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/gcsl_recommender.py +6 -3
  40. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/ranking/ranking_recommender.py +2 -2
  41. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/training_coordinator.py +2 -1
  42. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/base_scorer.py +37 -8
  43. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/independent.py +266 -17
  44. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_dataset.py +154 -0
  45. scikit_rec-0.4.2/tests/test_fit_params_passthrough.py +267 -0
  46. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_gcsl_recommender.py +60 -0
  47. scikit_rec-0.4.2/tests/test_hive_partitioning.py +460 -0
  48. scikit_rec-0.4.2/tests/test_independent_batch_training.py +407 -0
  49. scikit_rec-0.4.2/tests/test_joint_xgb_multioutput.py +247 -0
  50. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_multiclass_scorer.py +39 -0
  51. scikit_rec-0.4.2/tests/test_null_ids.py +135 -0
  52. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_orchestrator_factory.py +98 -0
  53. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_ranking_recommender.py +73 -0
  54. scikit_rec-0.4/skrec/dataset/batch_training_dataset.py +0 -116
  55. scikit_rec-0.4/skrec/dataset/local_data_reader.py +0 -41
  56. scikit_rec-0.4/skrec/dataset/s3_data_reader.py +0 -101
  57. scikit_rec-0.4/skrec/estimator/classification/lightgbm_classifier.py +0 -34
  58. scikit_rec-0.4/skrec/estimator/regression/lightgbm_regressor.py +0 -34
  59. scikit_rec-0.4/tests/__init__.py +0 -0
  60. {scikit_rec-0.4 → scikit_rec-0.4.2}/.github/workflows/docs.yml +0 -0
  61. {scikit_rec-0.4 → scikit_rec-0.4.2}/.github/workflows/publish.yml +0 -0
  62. {scikit_rec-0.4 → scikit_rec-0.4.2}/.gitignore +0 -0
  63. {scikit_rec-0.4 → scikit_rec-0.4.2}/CODE_OF_CONDUCT.md +0 -0
  64. {scikit_rec-0.4 → scikit_rec-0.4.2}/CONTRIBUTING.md +0 -0
  65. {scikit_rec-0.4 → scikit_rec-0.4.2}/LICENSE +0 -0
  66. {scikit_rec-0.4 → scikit_rec-0.4.2}/README.md +0 -0
  67. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/advanced/hpo.md +0 -0
  68. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/advanced/hybrid.md +0 -0
  69. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/advanced/production.md +0 -0
  70. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/getting-started/installation.md +0 -0
  71. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/getting-started/quick-start.md +0 -0
  72. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/images/3layers.png +0 -0
  73. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/images/RecommenderFlowcharts.pptx +0 -0
  74. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/images/recommender_dataset.png +0 -0
  75. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/images/scorer.png +0 -0
  76. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/index.md +0 -0
  77. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/bandits.md +0 -0
  78. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/comparison.md +0 -0
  79. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/gcsl.md +0 -0
  80. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/hierarchical.md +0 -0
  81. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/ranking.md +0 -0
  82. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/sequential.md +0 -0
  83. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/recommender-types/uplift.md +0 -0
  84. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/stylesheets/extra.css +0 -0
  85. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/architecture.md +0 -0
  86. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/collaborative-filtering.md +0 -0
  87. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/decision-rule.md +0 -0
  88. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/evaluation.md +0 -0
  89. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/hrnn.md +0 -0
  90. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/inference.md +0 -0
  91. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/ncf.md +0 -0
  92. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/retrieval.md +0 -0
  93. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/sasrec.md +0 -0
  94. {scikit_rec-0.4 → scikit_rec-0.4.2}/docs/user-guide/two-tower.md +0 -0
  95. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/amazon-books/deepfm_amazon_books.ipynb +0 -0
  96. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/amazon-books/lightgbm_amazon_books.ipynb +0 -0
  97. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/amazon-books/ncf_amazon_books.ipynb +0 -0
  98. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/amazon-books/sasrec_amazon_books_positives.ipynb +0 -0
  99. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/generic/factory_pipeline_demo.ipynb +0 -0
  100. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/generic/retrieval_two_stage.ipynb +0 -0
  101. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/generic/uplift_modeling.ipynb +0 -0
  102. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/mixed_type_multi_target/conditional.ipynb +0 -0
  103. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/mixed_type_multi_target/independent.ipynb +0 -0
  104. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/mixed_type_multi_target/joint_families.ipynb +0 -0
  105. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/composability_demo.ipynb +0 -0
  106. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/contextualized_two_tower_context_modes.ipynb +0 -0
  107. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/gcsl_multi_objective_movielens1m.ipynb +0 -0
  108. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/hpo_xgboost_movielens1m.ipynb +0 -0
  109. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/hrnn_movielens1m.ipynb +0 -0
  110. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/ranking_xgboost_movielens1m.ipynb +0 -0
  111. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/sasrec_movielens1m_positives.ipynb +0 -0
  112. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/sasrec_movielens1m_ratings.ipynb +0 -0
  113. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/movielens-1m/sasrec_movielens1m_ratings_mse.ipynb +0 -0
  114. {scikit_rec-0.4 → scikit_rec-0.4.2}/examples/ope_validation/obd_ope_validation.ipynb +0 -0
  115. {scikit_rec-0.4 → scikit_rec-0.4.2}/mixed_type_multi_target_plan_v2.md +0 -0
  116. {scikit_rec-0.4 → scikit_rec-0.4.2}/mixed_type_multi_target_plan_v3.md +0 -0
  117. {scikit_rec-0.4 → scikit_rec-0.4.2}/mkdocs.yml +0 -0
  118. {scikit_rec-0.4 → scikit_rec-0.4.2}/scikit_rec.egg-info/dependency_links.txt +0 -0
  119. {scikit_rec-0.4 → scikit_rec-0.4.2}/scikit_rec.egg-info/top_level.txt +0 -0
  120. {scikit_rec-0.4 → scikit_rec-0.4.2}/setup.cfg +0 -0
  121. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/__init__.py +0 -0
  122. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/__version.py +0 -0
  123. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/constants.py +0 -0
  124. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/datatypes.py +0 -0
  125. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/interactions_dataset.py +0 -0
  126. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/items_dataset.py +0 -0
  127. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/interaction_multiclass_schema_training.yaml +0 -0
  128. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/interaction_multioutput_schema_training.yaml +0 -0
  129. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/interactions_schema_inference.yaml +0 -0
  130. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/interactions_schema_training.yaml +0 -0
  131. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/interactions_schema_with_timestamp_training.yaml +0 -0
  132. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/items_schema.yaml +0 -0
  133. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/mixed_type_multi_target_schema_training.yaml +0 -0
  134. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/required_schemas/users_schema.yaml +0 -0
  135. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/dataset/users_dataset.py +0 -0
  136. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/__init__.py +0 -0
  137. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/base_estimator.py +0 -0
  138. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/_conditional_joint_multi_target_base.py +0 -0
  139. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/_conditional_label_encoding.py +0 -0
  140. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/_joint_multi_target_base.py +0 -0
  141. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/_joint_multi_target_encoders.py +0 -0
  142. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/_multi_target_protocol.py +0 -0
  143. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/base_classifier.py +0 -0
  144. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/conditional_joint_multi_target_mlp.py +0 -0
  145. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/conditional_joint_multi_target_transformer.py +0 -0
  146. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/deep_fm_classifier.py +0 -0
  147. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/independent_multi_target.py +0 -0
  148. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/joint_multi_target_mlp.py +0 -0
  149. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/joint_multi_target_transformer.py +0 -0
  150. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/classification/logreg_classifier.py +0 -0
  151. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/datatypes.py +0 -0
  152. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/base_embedding_estimator.py +0 -0
  153. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/base_pytorch_estimator.py +0 -0
  154. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/contextualized_two_tower_estimator.py +0 -0
  155. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/deep_cross_network_estimator.py +0 -0
  156. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/matrix_factorization_estimator.py +0 -0
  157. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/ncf_estimator.py +0 -0
  158. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/embedding/neural_factorization_estimator.py +0 -0
  159. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/numpy_predictor.py +0 -0
  160. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/regression/base_regressor.py +0 -0
  161. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/sequential/__init__.py +0 -0
  162. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/sequential/base_sequential_estimator.py +0 -0
  163. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/sequential/hrnn_estimator.py +0 -0
  164. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/estimator/sequential/sasrec_estimator.py +0 -0
  165. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/README.md +0 -0
  166. {scikit_rec-0.4/skrec/estimator/regression → scikit_rec-0.4.2/skrec/evaluator}/__init__.py +0 -0
  167. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/base_evaluator.py +0 -0
  168. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/categories.py +0 -0
  169. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/datatypes.py +0 -0
  170. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/direct_method.py +0 -0
  171. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/doubly_robust.py +0 -0
  172. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/evaluation_session.py +0 -0
  173. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/factory.py +0 -0
  174. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/inverse_propensity_score.py +0 -0
  175. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/policy_weighted.py +0 -0
  176. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/replay_match.py +0 -0
  177. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/simple.py +0 -0
  178. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/snips.py +0 -0
  179. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/evaluator/utils.py +0 -0
  180. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/README.md +0 -0
  181. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/__init__.py +0 -0
  182. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_binary_reward/interactions.csv +0 -0
  183. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_binary_reward/interactions_schema.yaml +0 -0
  184. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_binary_reward/items.csv +0 -0
  185. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_binary_reward/items_schema.yaml +0 -0
  186. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_binary_reward/users.csv +0 -0
  187. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_binary_reward/users_schema.yaml +0 -0
  188. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_continuous_reward/interactions.csv +0 -0
  189. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_continuous_reward/interactions_schema.yaml +0 -0
  190. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_continuous_reward/items.csv +0 -0
  191. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_continuous_reward/items_schema.yaml +0 -0
  192. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_continuous_reward/users.csv +0 -0
  193. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_continuous_reward/users_schema.yaml +0 -0
  194. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_class/interactions_multi_class.csv +0 -0
  195. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_class/interactions_schema.yaml +0 -0
  196. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_outcome/interactions_multi_outcome.csv +0 -0
  197. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_outcome/items.csv +0 -0
  198. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_outcome/users.csv +0 -0
  199. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_output/interactions.csv +0 -0
  200. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_multi_output/interactions_schema.yaml +0 -0
  201. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_uplift/interactions.csv +0 -0
  202. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_uplift/interactions_schema.yaml +0 -0
  203. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_uplift/interactions_schema_with_feats.yaml +0 -0
  204. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_uplift/interactions_with_feats.csv +0 -0
  205. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_uplift/users.csv +0 -0
  206. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/datasets/sample_uplift/users_schema.yaml +0 -0
  207. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/estimators/estimator_hyperparameters.yaml +0 -0
  208. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/estimators/generated_personalized_data.csv +0 -0
  209. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/estimators/multi_class_data.csv +0 -0
  210. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/estimators/reward_model_data_classification.csv +0 -0
  211. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/estimators/reward_model_data_regression.csv +0 -0
  212. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/examples/scripts/example_script.py +0 -0
  213. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/MAE.py +0 -0
  214. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/MAP.py +0 -0
  215. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/MRR.py +0 -0
  216. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/NDCG.py +0 -0
  217. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/PRAUC.py +0 -0
  218. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/README.md +0 -0
  219. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/RMSE.py +0 -0
  220. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/ROCAUC.py +0 -0
  221. {scikit_rec-0.4/skrec/evaluator → scikit_rec-0.4.2/skrec/metrics}/__init__.py +0 -0
  222. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/base_metric.py +0 -0
  223. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/datatypes.py +0 -0
  224. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/expected_reward.py +0 -0
  225. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/factory.py +0 -0
  226. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/multiclass_accuracy.py +0 -0
  227. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/recall.py +0 -0
  228. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/recommender_precision.py +0 -0
  229. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/metrics/utils.py +0 -0
  230. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/orchestrator/__init__.py +0 -0
  231. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/orchestrator/hpo.py +0 -0
  232. {scikit_rec-0.4/skrec/metrics → scikit_rec-0.4.2/skrec/recommender}/__init__.py +0 -0
  233. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/bandits/contextual_bandits.py +0 -0
  234. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/bandits/datatypes.py +0 -0
  235. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/bandits/factory.py +0 -0
  236. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/bandits/strategy/base_strategy.py +0 -0
  237. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/bandits/strategy/epsilon_greedy.py +0 -0
  238. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/bandits/strategy/static_action.py +0 -0
  239. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/__init__.py +0 -0
  240. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/inference/__init__.py +0 -0
  241. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/inference/base_inference.py +0 -0
  242. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/inference/mean_scalarization.py +0 -0
  243. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/inference/percentile_value.py +0 -0
  244. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/gcsl/inference/predefined_value.py +0 -0
  245. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/inference_input.py +0 -0
  246. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/ranking/__init__.py +0 -0
  247. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/sequential/__init__.py +0 -0
  248. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/sequential/hierarchical_recommender.py +0 -0
  249. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/sequential/sequential_recommender.py +0 -0
  250. {scikit_rec-0.4/skrec/recommender → scikit_rec-0.4.2/skrec/recommender/uplift_model}/__init__.py +0 -0
  251. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/uplift_model/uplift_recommender.py +0 -0
  252. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/recommender/uplift_model/uplift_scorer_adapter.py +0 -0
  253. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/retriever/__init__.py +0 -0
  254. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/retriever/base_retriever.py +0 -0
  255. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/retriever/content_based_retriever.py +0 -0
  256. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/retriever/embedding_retriever.py +0 -0
  257. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/retriever/popularity_retriever.py +0 -0
  258. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/__init__.py +0 -0
  259. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/hierarchical.py +0 -0
  260. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/mixed_type_multi_target.py +0 -0
  261. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/multiclass.py +0 -0
  262. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/multioutput.py +0 -0
  263. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/sequential.py +0 -0
  264. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/scorer/universal.py +0 -0
  265. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/split.py +0 -0
  266. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/util/config_loader.py +0 -0
  267. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/util/logger.py +0 -0
  268. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/util/numpy_util.py +0 -0
  269. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/util/s3.py +0 -0
  270. {scikit_rec-0.4 → scikit_rec-0.4.2}/skrec/util/torch_device.py +0 -0
  271. {scikit_rec-0.4/skrec/recommender/uplift_model → scikit_rec-0.4.2/tests}/__init__.py +0 -0
  272. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/conftest.py +0 -0
  273. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_bandits_recommender.py +0 -0
  274. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_base_estimator.py +0 -0
  275. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_base_retriever.py +0 -0
  276. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_base_scorer.py +0 -0
  277. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_classifier_estimators.py +0 -0
  278. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_conditional_joint_multi_target.py +0 -0
  279. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_content_based_retriever.py +0 -0
  280. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_dataset_iterator.py +0 -0
  281. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_deep_fm_network.py +0 -0
  282. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_embedding_estimators.py +0 -0
  283. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_embedding_retriever.py +0 -0
  284. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_estimator_smoke.py +0 -0
  285. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_evaluator_utils.py +0 -0
  286. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_example_datasets.py +0 -0
  287. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_factory_multi_target.py +0 -0
  288. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_hrnn_estimator.py +0 -0
  289. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_import.py +0 -0
  290. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_independent_multi_target.py +0 -0
  291. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_independent_scorer.py +0 -0
  292. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_joint_multi_target_mlp.py +0 -0
  293. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_joint_multi_target_transformer.py +0 -0
  294. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_matrix_factorization_estimator.py +0 -0
  295. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_matrix_factorization_integration.py +0 -0
  296. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_metrics_utils.py +0 -0
  297. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_mixed_type_multi_target_evaluation.py +0 -0
  298. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_mixed_type_multi_target_gates.py +0 -0
  299. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_mixed_type_multi_target_scorer.py +0 -0
  300. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_multioutput_evaluation.py +0 -0
  301. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_multioutput_scorer.py +0 -0
  302. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_ncf_estimator.py +0 -0
  303. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_ncf_integration.py +0 -0
  304. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_numpy.py +0 -0
  305. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_orchestrator_hpo.py +0 -0
  306. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_popularity_retriever.py +0 -0
  307. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_rec_datasets.py +0 -0
  308. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_recommender_evaluation_session.py +0 -0
  309. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_recommender_evaluator.py +0 -0
  310. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_recommender_metrics.py +0 -0
  311. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_regression_estimators.py +0 -0
  312. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_retrieval_integration.py +0 -0
  313. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_s3.py +0 -0
  314. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_sasrec_estimator.py +0 -0
  315. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_schema.py +0 -0
  316. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_sequential_recommender.py +0 -0
  317. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_split.py +0 -0
  318. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_strategy.py +0 -0
  319. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_universal_scorer.py +0 -0
  320. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_uplift_s_learner.py +0 -0
  321. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_uplift_t_learner.py +0 -0
  322. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/test_uplift_x_learner.py +0 -0
  323. {scikit_rec-0.4 → scikit_rec-0.4.2}/tests/utils.py +0 -0
@@ -16,7 +16,7 @@ jobs:
16
16
  with:
17
17
  python-version: "3.12"
18
18
  - name: Install ruff
19
- run: pip install ruff
19
+ run: pip install ruff==0.16.0
20
20
  - name: Check formatting
21
21
  run: ruff format --check .
22
22
  - name: Check lint
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: scikit-rec
3
- Version: 0.4
3
+ Version: 0.4.2
4
4
  Summary: A scikit-style recommender systems library
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Homepage, https://github.com/intuit/scikit-rec
@@ -26,7 +26,7 @@ Requires-Dist: boto3<3.0.0,>=1.26.27; extra == "aws"
26
26
  Provides-Extra: dev
27
27
  Requires-Dist: pytest>=7.0; extra == "dev"
28
28
  Requires-Dist: pytest-cov>=4.0; extra == "dev"
29
- Requires-Dist: ruff>=0.4; extra == "dev"
29
+ Requires-Dist: ruff==0.16.0; extra == "dev"
30
30
  Requires-Dist: mypy>=1.0; extra == "dev"
31
31
  Requires-Dist: moto[s3]>=4.0; extra == "dev"
32
32
  Requires-Dist: pre-commit>=3.0; extra == "dev"
@@ -66,8 +66,9 @@ Per-scorer constructor kwargs. Optional; defaults preserve historical scorer beh
66
66
  | Key | Used by | Type | Description |
67
67
  |-----|---------|------|-------------|
68
68
  | `on_degenerate_target` | `multioutput` | `DegenerateTargetPolicy` or `"raise"` / `"constant"` | Policy for single-class targets in the training slice. `"raise"` (default) aborts training with the offending column names; `"constant"` fits a constant predictor for degenerate columns and trains the rest. See [`MultioutputScorer` degenerate-target handling](../user-guide/scorers.md#degenerate-target-handling-on_degenerate_target). |
69
+ | `batch_chunk_dir` | `independent` | `str` | Directory for the temporary per-item chunks written during batch training (default: the system temp directory). Unused when the interactions are already partitioned into `ITEM_ID=<value>/` directories. See [Batch (partitioned) training](../user-guide/capability-matrix.md#batch-partitioned-training). |
69
70
 
70
- Scorers without entries here (`multiclass`, `independent`, `universal`, `sequential`, `hierarchical`) accept no `scorer_config` keys today — passing any key raises.
71
+ Scorers without entries here (`multiclass`, `universal`, `sequential`, `hierarchical`) accept no `scorer_config` keys today — passing any key raises.
71
72
 
72
73
  ### Embedding Config
73
74
 
@@ -182,6 +183,7 @@ capability_matrix()
182
183
  # "scorer_config_keys": {
183
184
  # "multioutput": ("on_degenerate_target",),
184
185
  # "mixed_type_multi_target": ("target_specs",),
186
+ # "independent": ("batch_chunk_dir",),
185
187
  # "multiclass": (),
186
188
  # # ...
187
189
  # },
@@ -67,3 +67,21 @@ Side-by-side comparison of all three `ContextMode` variants on a synthetic datas
67
67
  - `SCORING_LAYER` — most expressive; context, user, and item representations combined in a final linear layer
68
68
 
69
69
  See the [Contextualized Two-Tower Guide](../user-guide/two-tower.md) for architecture details and ANN serving patterns.
70
+
71
+ ---
72
+
73
+ ## Multi-label — Per-label vs Joint XGBoost under `MultioutputScorer`
74
+
75
+ `nb_examples/multioutput_per_label_vs_joint_xgb.ipynb`
76
+
77
+ Three model structures behind the **same** `MultioutputScorer` API, on one wide
78
+ binary-multilabel frame with correlated labels.
79
+
80
+ **What it covers:**
81
+
82
+ - **Per-label** (`MultiOutputClassifierEstimator`) — N independent boosters
83
+ - **Joint `one_output_per_tree`** (`JointXGBMultiOutputClassifierEstimator`, default) — one booster, GPU-capable, **no** cross-label learning (metrics match per-label)
84
+ - **Joint `multi_output_tree`** — one booster, shared vector-leaf splits = **genuine cross-label learning** (CPU-only); shows the small AUC lift on the correlated label
85
+ - The general `sample_weight='balanced'` class-weighting passthrough
86
+
87
+ See [per-label vs joint estimators](../user-guide/scorers.md#per-label-vs-joint-estimators) for the contract.
@@ -225,6 +225,19 @@ interactions_ds = InteractionsDataset(
225
225
  )
226
226
  ```
227
227
 
228
+ ### Partitioned Datasets
229
+
230
+ Point `data_location` at a directory (local or S3) to read every `.parquet` file in it, including subdirectories. Directories starting with `_` or `.` (such as Spark's `_temporary`) are skipped.
231
+
232
+ ```python
233
+ interactions_ds = InteractionsDataset(data_location='s3://my-bucket/data/interactions/')
234
+ ```
235
+
236
+ Hive-style `key=value/` directories are supported, e.g. data written by Spark's `partitionBy`:
237
+
238
+ - `ITEM_ID=<value>/` restores `ITEM_ID` as a column, since it is required. `IndependentScorer` batch training also uses this layout to train each item from its own files.
239
+ - Other keys such as `month=` or `dt=` are ignored, so they never become features by accident. Declare them in the client schema to load them as columns.
240
+
228
241
  ### Using Example Datasets
229
242
 
230
243
  The library includes sample datasets for experimentation:
@@ -288,6 +301,7 @@ Different scorers have different dataset requirements:
288
301
  ### 2. Data Quality
289
302
  - Remove duplicate interactions
290
303
  - Handle missing values consistently
304
+ - Remove rows with missing `USER_ID` or `ITEM_ID`: training and `recommend()` reject them
291
305
  - Ensure ID consistency across datasets
292
306
 
293
307
  ### 3. Train/Test Split
@@ -314,6 +328,10 @@ Different scorers have different dataset requirements:
314
328
 
315
329
  **Solution**: Check your schema matches your actual data types.
316
330
 
331
+ ### ValueError: 'USER_ID' column in interactions contains N null value(s)
332
+
333
+ **Solution**: Drop or fill rows with missing IDs (the message lists the first rows). Null IDs usually come from an unmatched upstream join or a failed type cast. The same check applies to `ITEM_ID`, and to the users and items datasets.
334
+
317
335
  ### ValueError: Items dataset required for Universal scorer
318
336
 
319
337
  **Solution**: Provide an items dataset or switch to Independent scorer.
@@ -38,7 +38,7 @@ Models fall into three **training / scoring planes**. Each plane uses different
38
38
  | **UniversalScorer** | **Yes** (factory yields `TabularUniversalScorer`) | **Yes** (`EmbeddingUniversalScorer`) | **No** (use `SequentialScorer`) |
39
39
  | **IndependentScorer** | **Yes** (single or dict of estimators) | **No** (raises at init) | **No** |
40
40
  | **MulticlassScorer** | **Yes** | **No** (raises at init) | **No** |
41
- | **MultioutputScorer** | **Yes** — accepts both `BaseClassifier` (e.g. `MultiOutputClassifierEstimator`, binary-only — multi-class targets rejected at fit) and `BaseRegressor` (e.g. `MultiOutputRegressorEstimator`, continuous targets) | **No** (raises at init) | **No** |
41
+ | **MultioutputScorer** | **Yes** — `BaseClassifier` (binary-only; multi-class rejected at fit) or `BaseRegressor`. Per-label: `MultiOutputClassifierEstimator` / `MultiOutputRegressorEstimator` (N independent boosters). Joint single-booster: `JointXGBMultiOutputClassifierEstimator` / `JointXGBMultiOutputRegressorEstimator`. sklearn tree ensembles (RandomForest/ExtraTrees) are joint multi-output via the `SklearnUniversal*` wrappers. See [per-label vs joint](scorers.md#per-label-vs-joint-estimators). | **No** (raises at init) | **No** |
42
42
  | **MixedTypeMultiTargetScorer** | **Yes** — accepts any `MultiTargetEstimator` (joint MLP, joint Transformer, or independent). Heterogeneous per-target types: binary + regression + multiclass + multilabel groups in one model. See [decision rule](decision-rule.md) for per-target metric dispatch. | **No** (raises at init via Protocol check) | **No** |
43
43
  | **SequentialScorer** | **No** | **No** | **Yes** |
44
44
  | **HierarchicalScorer** | **No** | **No** | **Yes** (HRNN estimators) |
@@ -46,6 +46,19 @@ Models fall into three **training / scoring planes**. Each plane uses different
46
46
 
47
47
  ---
48
48
 
49
+ ## Estimator config knobs (tabular)
50
+
51
+ These `estimator_config` keys apply to the sklearn-API tabular estimators (XGBoost / LightGBM / sklearn wrappers, single- and multi-target). All are introspectable via `capability_matrix()` so external callers (e.g. the agent) stay in lockstep.
52
+
53
+ | Config path | Values | Applies to | `capability_matrix()` key |
54
+ |---|---|---|---|
55
+ | `weights.sample_weight` | `'balanced'` (class-balanced at fit), a callable `fn(y)->weights`, or an explicit array (default: uniform) | All sklearn-API estimators, all scorers (XGB/LightGBM/sklearn; single- & multi-target). For early stopping, `'balanced'`/callable also weight the eval set; explicit arrays are train-only. | `weights_config_keys` |
56
+ | `weights.fit_params` | dict of static kwargs forwarded to the wrapped `fit` (`feature_weights`, `base_margin`, custom objective, `callbacks`, …) | All sklearn-API estimators | `weights_config_keys` |
57
+ | `weights.action_weight`, `weights.item_sample_weights` | recsys item/action weighting (composes multiplicatively with `sample_weight`) | `WeightedXGBClassifierEstimator` path | `weights_config_keys` |
58
+ | `multioutput_strategy` | `'per_label'` (default; N independent boosters) or `'joint'` (one joint XGBoost booster) | `scorer_type="multioutput"` only. `'joint'` is **XGBoost-only** and **non-tuned-only** (no HPO wrapper); pair with `xgboost.multi_strategy='multi_output_tree'` for cross-label learning (CPU-only) or `'one_output_per_tree'` (GPU; per-label-equivalent). | `multioutput_strategy_types` |
59
+
60
+ ---
61
+
49
62
  ## `recommend()` vs `recommend_online()`
50
63
 
51
64
  | Recommender | `recommend()` | `recommend_online()` | Notes |
@@ -91,9 +104,11 @@ Retriever is **optional** on these classes. `SequentialRecommender`’s public c
91
104
  | Support | Details |
92
105
  |---------|---------|
93
106
  | **Estimator** | In the shipped code, **`BatchXGBClassifierEstimator`** implements `_batch_fit_model` (see `skrec/estimator/classification/xgb_classifier.py`). Other estimators use in-memory `fit` unless extended. |
94
- | **Training** | `coordinate_training` uses the batch path when `estimator.support_batch_training()` is true: **`interactions_ds` required**; **`items_ds` required** for partitioned catalogue setup; validation datasets must satisfy the same rules as tabular validation (e.g. `valid_users_ds` when users + valid interactions). |
107
+ | **Partitioned layout** | Partitioned datasets (local or S3) are read recursively; `_`/`.` directories such as Spark's `_temporary` are skipped. In Hive-style `key=value/` directories, only declared keys become columns: `ITEM_ID` (required) and any key the client schema declares. Other keys such as `month=` or `dt=` are ignored, so they never become features implicitly; declare them in the client schema to use them. |
108
+ | **Training** | `coordinate_training` uses the batch path when `scorer.support_batch_training()` is true (default: delegates to the estimator): **`interactions_ds` required**; **`items_ds` required** for partitioned catalogue setup; validation datasets must satisfy the same rules as tabular validation (e.g. `valid_users_ds` when users + valid interactions). `train()` does not load the whole interactions dataset in batch mode (only one partition, for column names); retrievers and GCSL load it on demand. Each partition gets the recommender's outcome-column handling as it is read. |
95
109
  | **Embedding** | **No** batch-training branch for `BaseEmbeddingEstimator` in the same iterator style. |
96
110
  | **Sequential** | **`support_batch_training()` is False** for `SequentialEstimator`. |
111
+ | **IndependentScorer** | **Yes**, when every per-item estimator supports batch training (mixing batch and in-memory estimators raises `TypeError`). If the interactions are partitioned into `ITEM_ID=<value>/` directories, each item trains straight from its own files with no copy (read once to train, plus once up front when the binary-label check applies); a file whose `ITEM_ID` column disagrees with its directory raises. Otherwise one pass over the partitions writes each item's rows to temporary per-item parquet chunks (buffered, so roughly one file per item), a local-disk copy of the interactions, under `batch_chunk_dir` (`IndependentScorer(..., batch_chunk_dir=...)` or `scorer_config`; default: the system temp directory). Items with no interactions are dropped. `items_ds` is required. |
97
112
 
98
113
  ---
99
114
 
@@ -24,8 +24,29 @@ For continuous outcomes (revenue, time-spent, rating):
24
24
 
25
25
  ### Multi-output Estimators
26
26
 
27
- - **`MultiOutputClassifierEstimator`** - Wrapper for multi-output classification (multiple **binary numeric** targets per user — values strictly in `{0, 1}`). Pairs with `MultioutputScorer` in classifier mode. The scorer-level `MultioutputScorer._validate_targets` (early, before the wrapper sees the data) enforces the strict `{0, 1}` value contract — strings and signed-integer encodings like `{-1, 1}` are rejected there. Bool columns ARE accepted (Python `True == 1` / `False == 0` in set membership, so `{True, False}` collapses to `{0, 1}`). The wrapper's own `_validate_binary_targets` (defense-in-depth pre-flight scan, so the wrapper is safe to use standalone) enforces the per-target cardinality contract — exactly two unique values per column, neither single-class nor 3+-class. See [scorer migration paths](scorers.md#migration-paths-for-multi-class-targets).
28
- - **`MultiOutputRegressorEstimator`** - Wrapper for multi-output regression (multiple continuous targets per user). Pairs with `MultioutputScorer` in regressor mode for predictions like per-user revenue, engagement minutes, click counts, etc.
27
+ - **`MultiOutputClassifierEstimator`** - Wrapper for multi-output classification (multiple **binary numeric** targets per user — values strictly in `{0, 1}`). Pairs with `MultioutputScorer` in classifier mode. Fits **one separate booster per target** (`sklearn.MultiOutputClassifier`). The scorer-level `MultioutputScorer._validate_targets` (early, before the wrapper sees the data) enforces the strict `{0, 1}` value contract — strings and signed-integer encodings like `{-1, 1}` are rejected there. Bool columns ARE accepted (Python `True == 1` / `False == 0` in set membership, so `{True, False}` collapses to `{0, 1}`). The wrapper's own `_validate_binary_targets` (defense-in-depth pre-flight scan, so the wrapper is safe to use standalone) enforces the per-target cardinality contract — exactly two unique values per column, neither single-class nor 3+-class. See [scorer migration paths](scorers.md#migration-paths-for-multi-class-targets).
28
+ - **`MultiOutputRegressorEstimator`** - Wrapper for multi-output regression (multiple continuous targets per user). Fits one separate booster per target. Pairs with `MultioutputScorer` in regressor mode for predictions like per-user revenue, engagement minutes, click counts, etc.
29
+ - **`JointXGBMultiOutputClassifierEstimator`** - A **single joint XGBoost booster** over all N binary labels (vs N independent boosters above). Pairs with `MultioutputScorer` classifier mode; reshapes XGBoost's `(n, N)` `predict_proba` into the per-label list the scorer expects. `multi_strategy='one_output_per_tree'` (default, GPU-capable) does **not** share structure across labels; `multi_strategy='multi_output_tree'` (vector leaf, CPU-only) does — that's the only mode with genuine cross-label learning. See [Per-label vs joint estimators](scorers.md#per-label-vs-joint-estimators).
30
+ - **`JointXGBMultiOutputRegressorEstimator`** - The regressor analogue: a single joint XGBoost booster over N continuous targets, for `MultioutputScorer` regressor mode (no reshape needed — `predict` is already `(n, N)`).
31
+ - **Note on `multi_strategy`:** "joint" means one model artifact; it does **not** automatically mean cross-target learning. Only `multi_output_tree` (or sklearn tree ensembles below) shares tree structure across targets. None of these condition one target on another's *value* — for that, use the conditional estimators under `MixedTypeMultiTargetScorer`.
32
+ - **sklearn tree ensembles (`RandomForestClassifier`, `ExtraTreesClassifier`, regressors)** are joint multi-output **for free**: they natively accept a 2-D target matrix, grow multi-output trees that share structure across all targets **by default**, and their multilabel `predict_proba` already returns the list-of-blocks layout `MultioutputScorer` expects. Use them through the plain `SklearnUniversalClassifierEstimator` / `SklearnUniversalRegressorEstimator` (2-D `y`) — no dedicated estimator needed.
33
+
34
+ ### Class weighting & fit-time parameters
35
+
36
+ Every sklearn-API estimator (XGBoost / LightGBM / sklearn wrappers, single- and multi-target) takes two optional constructor args (and matching `set_sample_weight` / `set_fit_params` setters):
37
+
38
+ - **`sample_weight`** — a row-weight strategy: `'balanced'` (computes `compute_sample_weight('balanced', y)` at fit time — the production class-balancing recipe), a callable `fn(y) -> weights`, or an explicit per-row array. Defaults to uniform.
39
+ - **`fit_params`** — a dict of static kwargs forwarded verbatim to the wrapped model's `fit` (`feature_weights`, `base_margin`, a custom objective, `callbacks`, …).
40
+
41
+ ```python
42
+ # class-balanced multiclass (firmographics-industry recipe)
43
+ estimator = XGBClassifierEstimator(
44
+ {"n_estimators": 426, "objective": "multi:softprob"},
45
+ sample_weight="balanced",
46
+ )
47
+ ```
48
+
49
+ This is the general replacement for ad-hoc weighting; the row weights are resolved against `y` at fit time, so they stay aligned through the scorer pipeline. (`WeightedXGBClassifierEstimator`'s item/action weighting still exists and composes multiplicatively with a `'balanced'` strategy.)
29
50
 
30
51
  ### Embedding Estimators
31
52
 
@@ -72,6 +72,19 @@ scorer = IndependentScorer(estimator)
72
72
 
73
73
  **When to use**: When you don't have item features, or each item needs a specialized model.
74
74
 
75
+ **Batch training** (data larger than memory): pass a batch-capable estimator such as `BatchXGBClassifierEstimator`, either one estimator (copied per item) or a dict with one per item. Don't mix batch and in-memory estimators in one dict. `items_ds` is required, to supply the item list. Each item trains from only its own rows:
76
+
77
+ - If the interactions are partitioned into `ITEM_ID=<value>/` directories (e.g. Spark `partitionBy("ITEM_ID")`), each item reads its own files directly, with no copy.
78
+ - Otherwise one pass over the partitions writes each item's rows to temporary parquet files, a local-disk copy of the interactions. Choose where with `IndependentScorer(estimator, batch_chunk_dir="/big/volume")` or `scorer_config: {batch_chunk_dir: ...}`.
79
+
80
+ ```python
81
+ from skrec.estimator.classification.xgb_classifier import BatchXGBClassifierEstimator
82
+
83
+ scorer = IndependentScorer(BatchXGBClassifierEstimator({"objective": "binary:logistic"}))
84
+ ```
85
+
86
+ See [Batch (partitioned) training](capability-matrix.md#batch-partitioned-training) for details.
87
+
75
88
  ---
76
89
 
77
90
  ## 3. MulticlassScorer
@@ -143,6 +156,86 @@ estimator = MultiOutputRegressorEstimator(
143
156
  scorer = MultioutputScorer(estimator)
144
157
  ```
145
158
 
159
+ ### Per-label vs joint estimators
160
+
161
+ `MultioutputScorer` is agnostic to *how* the N targets are modeled — only to the
162
+ output shape. Two model structures are supported:
163
+
164
+ - **Per-label (N independent models).** `MultiOutputClassifierEstimator` /
165
+ `MultiOutputRegressorEstimator` wrap `sklearn.MultiOutputClassifier` /
166
+ `MultiOutputRegressor`, which fit **one separate booster per target**. Simple
167
+ and robust; no signal is shared across targets.
168
+ - **Joint (one model over all targets).** `JointXGBMultiOutputClassifierEstimator`
169
+ (classifier mode) and `JointXGBMultiOutputRegressorEstimator` (regressor mode)
170
+ train a **single XGBoost booster** on the 2-D target matrix. This matches a
171
+ production `num_target=N` recipe and trains/serves one artifact.
172
+
173
+ ```python
174
+ from skrec.estimator.classification.joint_xgb_multioutput import (
175
+ JointXGBMultiOutputClassifierEstimator,
176
+ )
177
+ # one joint booster over all binary labels
178
+ scorer = MultioutputScorer(JointXGBMultiOutputClassifierEstimator({"n_estimators": 300}))
179
+ ```
180
+
181
+ > **"Joint" ≠ cross-label learning by default.** XGBoost's `multi_strategy`
182
+ > decides whether targets share tree structure:
183
+ > - `'one_output_per_tree'` (**default**): separate trees per target inside one
184
+ > jointly-boosted model. **GPU-capable. No cross-label learning** — modeling-wise
185
+ > close to per-label.
186
+ > - `'multi_output_tree'` (vector leaf): splits chosen on the summed gradient
187
+ > across all targets, so targets share structure. **Genuine cross-label
188
+ > learning, but CPU-only.** Pass `params={'multi_strategy': 'multi_output_tree'}`
189
+ > to opt in; the estimator logs that it's active + CPU-only and warns if a GPU
190
+ > `device`/`tree_method` was also set.
191
+
192
+ - **sklearn tree ensembles are joint for free.** `RandomForestClassifier` /
193
+ `ExtraTreesClassifier` (and their regressors) natively accept a 2-D target
194
+ matrix and grow **multi-output trees that share structure across all targets by
195
+ default** (splits chosen on the averaged criterion across targets — genuine
196
+ shared-representation learning). Their multilabel `predict_proba` already returns
197
+ the list-of-blocks layout the scorer expects, so they work through the plain
198
+ `SklearnUniversalClassifierEstimator` / `SklearnUniversalRegressorEstimator` with
199
+ **no dedicated estimator**:
200
+
201
+ ```python
202
+ from sklearn.ensemble import RandomForestClassifier
203
+ from skrec.estimator.classification.sklearn_universal_classifier import (
204
+ SklearnUniversalClassifierEstimator,
205
+ )
206
+ scorer = MultioutputScorer(
207
+ SklearnUniversalClassifierEstimator(RandomForestClassifier, {"n_estimators": 200})
208
+ )
209
+ ```
210
+
211
+ (Note: shared *structure* across targets is not the same as label *conditioning*
212
+ — none of these read one target's value to predict another. For real-time-label
213
+ conditioning use the `MixedTypeMultiTargetScorer` conditional estimators.)
214
+
215
+ ### Class weighting and fit-time parameters
216
+
217
+ All sklearn-API estimators (XGBoost / LightGBM / sklearn wrappers, single- and
218
+ multi-target) accept a generic fit-time passthrough — no estimator-specific
219
+ plumbing:
220
+
221
+ - `sample_weight`: a row-weight strategy — `'balanced'`
222
+ (`compute_sample_weight('balanced', y)` computed at fit time, the production
223
+ firmographics recipe), a callable `fn(y) -> weights`, or an explicit array.
224
+ Defaults to uniform.
225
+ - `fit_params`: a dict of static kwargs forwarded verbatim to the underlying
226
+ `fit` (`feature_weights`, `base_margin`, a custom objective, `callbacks`, …).
227
+
228
+ ```python
229
+ JointXGBMultiOutputClassifierEstimator({"n_estimators": 300}, sample_weight="balanced")
230
+ ```
231
+
232
+ ### Tree-count pinning vs early stopping
233
+
234
+ To pin the number of trees (e.g. reproduce a production `best_iteration`), set
235
+ `n_estimators` in `params` and **omit** `early_stopping_rounds`. An XGBoost
236
+ `eval_set` is used only when validation data (`X_valid`) is passed to `fit`; with
237
+ no validation set, training runs the full pinned `n_estimators`.
238
+
146
239
  **Dataset Requirements**:
147
240
  - ⚠️ **Interactions**: **One row per user only**
148
241
  - ❌ **Users**: Not allowed (pass user features as plain columns inside interactions)
@@ -222,11 +315,11 @@ Under `CONSTANT`, `recommender.scorer.degenerate_targets` exposes the manifest o
222
315
 
223
316
  ### Migration paths for multi-class targets
224
317
 
225
- Targets with 3+ classes are rejected at fit time. Choose one:
318
+ `MultioutputScorer` rejects multi-class targets (3+ classes per `ITEM_<name>`) at fit time. Pick the path that fits your shape:
226
319
 
227
- 1. **Single multi-class target** → use [`MulticlassScorer`](#3-multiclassscorer) in long format.
228
- 2. **Multiple multi-class targets** → one-hot encode each into binary columns (e.g. `ITEM_X` with classes `{A, B, C}` becomes `ITEM_X_A`, `ITEM_X_B`, `ITEM_X_C`, each binary).
229
- 3. **Heterogeneous target types (mix of binary, regression, multi-class)** → use [`MixedTypeMultiTargetScorer`](#5-mixedtypemultitargetscorer) below.
320
+ 1. **Wide format, any mix of multi-class + binary + regression + multilabel** → use [`MixedTypeMultiTargetScorer`](#5-mixedtypemultitargetscorer) below. Multi-class targets are first-class via `TargetType.MULTICLASS`; class labels are preserved end-to-end (no manual one-hot encoding, no label-encoder round-trips). This is the recommended path for new wide-format multi-target work.
321
+ 2. **Single multi-class target in long format** → use [`MulticlassScorer`](#3-multiclassscorer). Best when you have `(USER_ID, ITEM_ID)` rows and `ITEM_ID` itself is the class label.
322
+ 3. **Legacy compatibility (stay on `MultioutputScorer`)** → one-hot encode each multi-class column into binary columns (e.g. `ITEM_X` with classes `{A, B, C}` becomes `ITEM_X_A`, `ITEM_X_B`, `ITEM_X_C`, each binary). Only choose this if you have an existing `MultioutputScorer` pipeline you don't want to rewrite — option #1 handles the same data without the encoding step.
230
323
 
231
324
  **Pros**:
232
325
  - Multi-label binary classification with cross-target ranking semantics
@@ -236,6 +236,10 @@ estimator = XGBClassifierEstimator({"random_state": 42, ...})
236
236
  - Use fewer estimator iterations
237
237
  - Enable GPU training if available
238
238
 
239
+ ### Issue: Data does not fit in memory
240
+
241
+ **Solution**: Use batch training with a partitioned dataset and a batch-capable estimator such as `BatchXGBClassifierEstimator`, with `UniversalScorer` or `IndependentScorer`. See [Batch (partitioned) training](capability-matrix.md#batch-partitioned-training) and [Partitioned Datasets](../getting-started/datasets.md#partitioned-datasets).
242
+
239
243
  ### Issue: Poor validation performance
240
244
 
241
245
  **Solution**: