scikit-learn-intelex 2024.0.1__py311-none-manylinux1_x86_64.whl → 2024.4.0__py311-none-manylinux1_x86_64.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.

Potentially problematic release.


This version of scikit-learn-intelex might be problematic. Click here for more details.

Files changed (89) hide show
  1. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/METADATA +2 -2
  2. scikit_learn_intelex-2024.4.0.dist-info/RECORD +101 -0
  3. sklearnex/__init__.py +11 -7
  4. sklearnex/__main__.py +0 -1
  5. sklearnex/_device_offload.py +31 -4
  6. sklearnex/_utils.py +15 -1
  7. sklearnex/basic_statistics/__init__.py +2 -2
  8. sklearnex/basic_statistics/incremental_basic_statistics.py +288 -0
  9. sklearnex/basic_statistics/tests/test_incremental_basic_statistics.py +386 -0
  10. sklearnex/cluster/__init__.py +0 -1
  11. sklearnex/cluster/dbscan.py +5 -2
  12. sklearnex/cluster/k_means.py +0 -1
  13. sklearnex/cluster/tests/test_dbscan.py +0 -1
  14. sklearnex/cluster/tests/test_kmeans.py +0 -1
  15. sklearnex/conftest.py +63 -0
  16. sklearnex/covariance/__init__.py +19 -0
  17. sklearnex/covariance/incremental_covariance.py +130 -0
  18. sklearnex/covariance/tests/test_incremental_covariance.py +143 -0
  19. sklearnex/decomposition/__init__.py +0 -1
  20. sklearnex/decomposition/pca.py +319 -2
  21. sklearnex/decomposition/tests/test_pca.py +34 -6
  22. sklearnex/dispatcher.py +93 -28
  23. sklearnex/ensemble/__init__.py +0 -1
  24. sklearnex/ensemble/_forest.py +93 -89
  25. sklearnex/ensemble/tests/test_forest.py +15 -20
  26. sklearnex/glob/__main__.py +0 -1
  27. sklearnex/glob/dispatcher.py +0 -1
  28. sklearnex/linear_model/__init__.py +1 -3
  29. sklearnex/linear_model/coordinate_descent.py +0 -1
  30. sklearnex/linear_model/linear.py +275 -332
  31. sklearnex/linear_model/logistic_path.py +0 -1
  32. sklearnex/linear_model/logistic_regression.py +385 -0
  33. sklearnex/linear_model/ridge.py +0 -1
  34. sklearnex/linear_model/tests/test_linear.py +47 -7
  35. sklearnex/linear_model/tests/test_logreg.py +70 -8
  36. sklearnex/manifold/__init__.py +0 -1
  37. sklearnex/manifold/t_sne.py +0 -1
  38. sklearnex/manifold/tests/test_tsne.py +0 -1
  39. sklearnex/metrics/__init__.py +0 -1
  40. sklearnex/metrics/pairwise.py +0 -1
  41. sklearnex/metrics/ranking.py +0 -1
  42. sklearnex/metrics/tests/test_metrics.py +0 -1
  43. sklearnex/model_selection/__init__.py +0 -1
  44. sklearnex/model_selection/split.py +0 -1
  45. sklearnex/model_selection/tests/test_model_selection.py +0 -1
  46. sklearnex/neighbors/__init__.py +1 -2
  47. sklearnex/neighbors/_lof.py +221 -0
  48. sklearnex/neighbors/common.py +5 -3
  49. sklearnex/neighbors/knn_classification.py +47 -133
  50. sklearnex/neighbors/knn_regression.py +20 -129
  51. sklearnex/neighbors/knn_unsupervised.py +15 -89
  52. sklearnex/neighbors/tests/test_neighbors.py +12 -17
  53. sklearnex/preview/__init__.py +1 -2
  54. sklearnex/preview/cluster/__init__.py +0 -1
  55. sklearnex/preview/cluster/k_means.py +7 -74
  56. sklearnex/preview/{decomposition → covariance}/__init__.py +19 -20
  57. sklearnex/preview/covariance/covariance.py +133 -0
  58. sklearnex/preview/covariance/tests/test_covariance.py +66 -0
  59. sklearnex/spmd/__init__.py +1 -0
  60. sklearnex/spmd/covariance/__init__.py +19 -0
  61. sklearnex/spmd/covariance/covariance.py +21 -0
  62. sklearnex/spmd/ensemble/forest.py +4 -12
  63. sklearnex/spmd/linear_model/__init__.py +2 -1
  64. sklearnex/spmd/linear_model/logistic_regression.py +21 -0
  65. sklearnex/svm/__init__.py +0 -1
  66. sklearnex/svm/_common.py +4 -7
  67. sklearnex/svm/nusvc.py +73 -49
  68. sklearnex/svm/nusvr.py +8 -52
  69. sklearnex/svm/svc.py +74 -51
  70. sklearnex/svm/svr.py +5 -49
  71. sklearnex/svm/tests/test_svm.py +0 -1
  72. sklearnex/tests/_utils.py +164 -0
  73. sklearnex/tests/test_memory_usage.py +9 -7
  74. sklearnex/tests/test_monkeypatch.py +192 -134
  75. sklearnex/tests/test_n_jobs_support.py +99 -0
  76. sklearnex/tests/test_parallel.py +6 -8
  77. sklearnex/tests/test_patching.py +338 -89
  78. sklearnex/utils/__init__.py +2 -1
  79. sklearnex/utils/_namespace.py +97 -0
  80. sklearnex/utils/validation.py +0 -1
  81. scikit_learn_intelex-2024.0.1.dist-info/RECORD +0 -90
  82. sklearnex/neighbors/lof.py +0 -437
  83. sklearnex/preview/decomposition/pca.py +0 -376
  84. sklearnex/preview/decomposition/tests/test_preview_pca.py +0 -38
  85. sklearnex/tests/_models_info.py +0 -170
  86. sklearnex/tests/utils/_launch_algorithms.py +0 -118
  87. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/LICENSE.txt +0 -0
  88. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/WHEEL +0 -0
  89. {scikit_learn_intelex-2024.0.1.dist-info → scikit_learn_intelex-2024.4.0.dist-info}/top_level.txt +0 -0
sklearnex/dispatcher.py CHANGED
@@ -1,6 +1,6 @@
1
- #!/usr/bin/env python
2
1
  # ==============================================================================
3
2
  # Copyright 2021 Intel Corporation
3
+ # Copyright 2024 Fujitsu Limited
4
4
  #
5
5
  # Licensed under the Apache License, Version 2.0 (the "License");
6
6
  # you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@ from daal4py.sklearn._utils import daal_check_version, sklearn_check_version
23
23
 
24
24
 
25
25
  def _is_new_patching_available():
26
- return os.environ.get("OFF_ONEDAL_IFACE") is None and daal_check_version(
26
+ return os.environ.get("OFF_ONEDAL_IFACE", "0") == "0" and daal_check_version(
27
27
  (2021, "P", 300)
28
28
  )
29
29
 
@@ -33,11 +33,62 @@ def _is_preview_enabled():
33
33
 
34
34
 
35
35
  @lru_cache(maxsize=None)
36
- def get_patch_map():
36
+ def get_patch_map_core(preview=False):
37
+ if preview:
38
+ # use recursion to guarantee that state of preview
39
+ # and non-preview maps are done at the same time.
40
+ # The two lru_cache dicts are actually one underneath.
41
+ # Preview is always secondary. Both sklearnex patch
42
+ # maps are referring to the daal4py dict unless the
43
+ # key has been replaced. Use with caution.
44
+ mapping = get_patch_map_core().copy()
45
+
46
+ if _is_new_patching_available():
47
+ import sklearn.covariance as covariance_module
48
+
49
+ # Preview classes for patching
50
+ from .preview.cluster import KMeans as KMeans_sklearnex
51
+ from .preview.covariance import (
52
+ EmpiricalCovariance as EmpiricalCovariance_sklearnex,
53
+ )
54
+
55
+ # Since the state of the lru_cache without preview cannot be
56
+ # guaranteed to not have already enabled sklearnex algorithms
57
+ # when preview is used, setting the mapping element[1] to None
58
+ # should NOT be done. This may lose track of the unpatched
59
+ # sklearn estimator or function.
60
+ # KMeans
61
+ cluster_module, _, _ = mapping["kmeans"][0][0]
62
+ sklearn_obj = mapping["kmeans"][0][1]
63
+ mapping.pop("kmeans")
64
+ mapping["kmeans"] = [
65
+ [(cluster_module, "kmeans", KMeans_sklearnex), sklearn_obj]
66
+ ]
67
+
68
+ # Covariance
69
+ mapping["empiricalcovariance"] = [
70
+ [
71
+ (
72
+ covariance_module,
73
+ "EmpiricalCovariance",
74
+ EmpiricalCovariance_sklearnex,
75
+ ),
76
+ None,
77
+ ]
78
+ ]
79
+ return mapping
80
+
37
81
  from daal4py.sklearn.monkeypatch.dispatcher import _get_map_of_algorithms
38
82
 
83
+ # NOTE: this is a shallow copy of a dict, modification is dangerous
39
84
  mapping = _get_map_of_algorithms().copy()
40
85
 
86
+ # NOTE: Use of daal4py _get_map_of_algorithms and
87
+ # get_patch_map/get_patch_map_core should not be used concurrently.
88
+ # The setting of elements to None below may cause loss of state
89
+ # when interacting with sklearn. A dictionary key must not be
90
+ # modified but totally replaced, otherwise it will cause chaos.
91
+ # Hence why pop is being used.
41
92
  if _is_new_patching_available():
42
93
  # Scikit-learn* modules
43
94
  import sklearn as base_module
@@ -64,47 +115,30 @@ def get_patch_map():
64
115
  from .utils.parallel import _FuncWrapperOld as _FuncWrapper_sklearnex
65
116
 
66
117
  from .cluster import DBSCAN as DBSCAN_sklearnex
118
+ from .decomposition import PCA as PCA_sklearnex
67
119
  from .ensemble import ExtraTreesClassifier as ExtraTreesClassifier_sklearnex
68
120
  from .ensemble import ExtraTreesRegressor as ExtraTreesRegressor_sklearnex
69
121
  from .ensemble import RandomForestClassifier as RandomForestClassifier_sklearnex
70
122
  from .ensemble import RandomForestRegressor as RandomForestRegressor_sklearnex
71
123
  from .linear_model import LinearRegression as LinearRegression_sklearnex
124
+ from .linear_model import LogisticRegression as LogisticRegression_sklearnex
72
125
  from .neighbors import KNeighborsClassifier as KNeighborsClassifier_sklearnex
73
126
  from .neighbors import KNeighborsRegressor as KNeighborsRegressor_sklearnex
74
127
  from .neighbors import LocalOutlierFactor as LocalOutlierFactor_sklearnex
75
128
  from .neighbors import NearestNeighbors as NearestNeighbors_sklearnex
76
-
77
- # Preview classes for patching
78
- from .preview.cluster import KMeans as KMeans_sklearnex
79
- from .preview.decomposition import PCA as PCA_sklearnex
80
129
  from .svm import SVC as SVC_sklearnex
81
130
  from .svm import SVR as SVR_sklearnex
82
131
  from .svm import NuSVC as NuSVC_sklearnex
83
132
  from .svm import NuSVR as NuSVR_sklearnex
84
133
 
85
- # Patch for mapping
86
- if _is_preview_enabled():
87
- # PCA
88
- mapping.pop("pca")
89
- mapping["pca"] = [[(decomposition_module, "PCA", PCA_sklearnex), None]]
90
-
91
- # KMeans
92
- mapping.pop("kmeans")
93
- mapping["kmeans"] = [
94
- [
95
- (
96
- cluster_module,
97
- "KMeans",
98
- KMeans_sklearnex,
99
- ),
100
- None,
101
- ]
102
- ]
103
-
104
134
  # DBSCAN
105
135
  mapping.pop("dbscan")
106
136
  mapping["dbscan"] = [[(cluster_module, "DBSCAN", DBSCAN_sklearnex), None]]
107
137
 
138
+ # PCA
139
+ mapping.pop("pca")
140
+ mapping["pca"] = [[(decomposition_module, "PCA", PCA_sklearnex), None]]
141
+
108
142
  # SVM
109
143
  mapping.pop("svm")
110
144
  mapping.pop("svc")
@@ -128,6 +162,24 @@ def get_patch_map():
128
162
  ]
129
163
  mapping["linearregression"] = mapping["linear"]
130
164
 
165
+ # Logistic Regression
166
+
167
+ mapping.pop("logisticregression")
168
+ mapping.pop("log_reg")
169
+ mapping.pop("logistic")
170
+ mapping.pop("_logistic_regression_path")
171
+ mapping["log_reg"] = [
172
+ [
173
+ (
174
+ linear_model_module,
175
+ "LogisticRegression",
176
+ LogisticRegression_sklearnex,
177
+ ),
178
+ None,
179
+ ]
180
+ ]
181
+ mapping["logisticregression"] = mapping["log_reg"]
182
+
131
183
  # kNN
132
184
  mapping.pop("knn_classifier")
133
185
  mapping.pop("kneighborsclassifier")
@@ -242,6 +294,19 @@ def get_patch_map():
242
294
  return mapping
243
295
 
244
296
 
297
+ # This is necessary to properly cache the patch_map when
298
+ # using preview.
299
+ def get_patch_map():
300
+ preview = _is_preview_enabled()
301
+ return get_patch_map_core(preview=preview)
302
+
303
+
304
+ get_patch_map.cache_clear = get_patch_map_core.cache_clear
305
+
306
+
307
+ get_patch_map.cache_info = get_patch_map_core.cache_info
308
+
309
+
245
310
  def get_patch_names():
246
311
  return list(get_patch_map().keys())
247
312
 
@@ -249,10 +314,10 @@ def get_patch_names():
249
314
  def patch_sklearn(name=None, verbose=True, global_patch=False, preview=False):
250
315
  if preview:
251
316
  os.environ["SKLEARNEX_PREVIEW"] = "enabled_via_patch_sklearn"
252
- if not sklearn_check_version("0.22"):
317
+ if not sklearn_check_version("0.24"):
253
318
  raise NotImplementedError(
254
319
  "Intel(R) Extension for Scikit-learn* patches apply "
255
- "for scikit-learn >= 0.22 only ..."
320
+ "for scikit-learn >= 0.24 only ..."
256
321
  )
257
322
 
258
323
  if global_patch:
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2023 Intel Corporation
4
3
  #
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ==============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #
@@ -26,8 +25,11 @@ from sklearn.ensemble import ExtraTreesClassifier as sklearn_ExtraTreesClassifie
26
25
  from sklearn.ensemble import ExtraTreesRegressor as sklearn_ExtraTreesRegressor
27
26
  from sklearn.ensemble import RandomForestClassifier as sklearn_RandomForestClassifier
28
27
  from sklearn.ensemble import RandomForestRegressor as sklearn_RandomForestRegressor
28
+ from sklearn.ensemble._forest import ForestClassifier as sklearn_ForestClassifier
29
+ from sklearn.ensemble._forest import ForestRegressor as sklearn_ForestRegressor
29
30
  from sklearn.ensemble._forest import _get_n_samples_bootstrap
30
31
  from sklearn.exceptions import DataConversionWarning
32
+ from sklearn.metrics import accuracy_score
31
33
  from sklearn.tree import (
32
34
  DecisionTreeClassifier,
33
35
  DecisionTreeRegressor,
@@ -36,13 +38,9 @@ from sklearn.tree import (
36
38
  )
37
39
  from sklearn.tree._tree import Tree
38
40
  from sklearn.utils import check_random_state, deprecated
39
- from sklearn.utils.validation import (
40
- check_array,
41
- check_consistent_length,
42
- check_is_fitted,
43
- check_X_y,
44
- )
41
+ from sklearn.utils.validation import check_array, check_is_fitted
45
42
 
43
+ from daal4py.sklearn._n_jobs_support import control_n_jobs
46
44
  from daal4py.sklearn._utils import (
47
45
  check_tree_nodes,
48
46
  daal_check_version,
@@ -52,19 +50,10 @@ from onedal.ensemble import ExtraTreesClassifier as onedal_ExtraTreesClassifier
52
50
  from onedal.ensemble import ExtraTreesRegressor as onedal_ExtraTreesRegressor
53
51
  from onedal.ensemble import RandomForestClassifier as onedal_RandomForestClassifier
54
52
  from onedal.ensemble import RandomForestRegressor as onedal_RandomForestRegressor
55
-
56
- # try catch needed for changes in structures observed in Scikit-learn around v0.22
57
- try:
58
- from sklearn.ensemble._forest import ForestClassifier as sklearn_ForestClassifier
59
- from sklearn.ensemble._forest import ForestRegressor as sklearn_ForestRegressor
60
- except ModuleNotFoundError:
61
- from sklearn.ensemble.forest import ForestClassifier as sklearn_ForestClassifier
62
- from sklearn.ensemble.forest import ForestRegressor as sklearn_ForestRegressor
63
-
64
53
  from onedal.primitives import get_tree_state_cls, get_tree_state_reg
65
54
  from onedal.utils import _num_features, _num_samples
55
+ from sklearnex.utils import get_namespace
66
56
 
67
- from .._config import get_config
68
57
  from .._device_offload import dispatch, wrap_output_data
69
58
  from .._utils import PatchingConditionsChain
70
59
 
@@ -78,24 +67,14 @@ class BaseForest(ABC):
78
67
  _onedal_factory = None
79
68
 
80
69
  def _onedal_fit(self, X, y, sample_weight=None, queue=None):
81
- if sklearn_check_version("0.24"):
82
- X, y = self._validate_data(
83
- X,
84
- y,
85
- multi_output=False,
86
- accept_sparse=False,
87
- dtype=[np.float64, np.float32],
88
- force_all_finite=False,
89
- )
90
- else:
91
- X, y = check_X_y(
92
- X,
93
- y,
94
- accept_sparse=False,
95
- dtype=[np.float64, np.float32],
96
- multi_output=False,
97
- force_all_finite=False,
98
- )
70
+ X, y = self._validate_data(
71
+ X,
72
+ y,
73
+ multi_output=False,
74
+ accept_sparse=False,
75
+ dtype=[np.float64, np.float32],
76
+ force_all_finite=False,
77
+ )
99
78
 
100
79
  if sample_weight is not None:
101
80
  sample_weight = self.check_sample_weight(sample_weight, X)
@@ -114,6 +93,8 @@ class BaseForest(ABC):
114
93
  # [:, np.newaxis] that does not.
115
94
  y = np.reshape(y, (-1, 1))
116
95
 
96
+ self._n_samples, self.n_outputs_ = y.shape
97
+
117
98
  y, expanded_class_weight = self._validate_y_class_weight(y)
118
99
 
119
100
  self.n_features_in_ = X.shape[1]
@@ -171,15 +152,6 @@ class BaseForest(ABC):
171
152
 
172
153
  return self
173
154
 
174
- def _fit_proba(self, X, y, sample_weight=None, queue=None):
175
- params = self.get_params()
176
- self.__class__(**params)
177
-
178
- # We use stock metaestimators below, so the only way
179
- # to pass a queue is using config_context.
180
- cfg = get_config()
181
- cfg["target_offload"] = queue
182
-
183
155
  def _save_attributes(self):
184
156
  if self.oob_score:
185
157
  self.oob_score_ = self._onedal_estimator.oob_score_
@@ -189,12 +161,19 @@ class BaseForest(ABC):
189
161
  self.oob_decision_function_ = (
190
162
  self._onedal_estimator.oob_decision_function_
191
163
  )
192
-
164
+ if self.bootstrap:
165
+ self._n_samples_bootstrap = max(
166
+ round(
167
+ self._onedal_estimator.observations_per_tree_fraction
168
+ * self._n_samples
169
+ ),
170
+ 1,
171
+ )
172
+ else:
173
+ self._n_samples_bootstrap = None
193
174
  self._validate_estimator()
194
175
  return self
195
176
 
196
- # TODO:
197
- # move to onedal modul.
198
177
  def _check_parameters(self):
199
178
  if isinstance(self.min_samples_leaf, numbers.Integral):
200
179
  if not 1 <= self.min_samples_leaf:
@@ -442,14 +421,12 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
442
421
 
443
422
  # The estimator is checked against the class attribute for conformance.
444
423
  # This should only trigger if the user uses this class directly.
445
- if (
446
- self.estimator.__class__ == DecisionTreeClassifier
447
- and self._onedal_factory != onedal_RandomForestClassifier
424
+ if self.estimator.__class__ == DecisionTreeClassifier and not issubclass(
425
+ self._onedal_factory, onedal_RandomForestClassifier
448
426
  ):
449
427
  self._onedal_factory = onedal_RandomForestClassifier
450
- elif (
451
- self.estimator.__class__ == ExtraTreeClassifier
452
- and self._onedal_factory != onedal_ExtraTreesClassifier
428
+ elif self.estimator.__class__ == ExtraTreeClassifier and not issubclass(
429
+ self._onedal_factory, onedal_ExtraTreesClassifier
453
430
  ):
454
431
  self._onedal_factory = onedal_ExtraTreesClassifier
455
432
 
@@ -541,18 +518,14 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
541
518
  )
542
519
 
543
520
  if patching_status.get_status():
544
- if sklearn_check_version("0.24"):
545
- X, y = self._validate_data(
546
- X,
547
- y,
548
- multi_output=True,
549
- accept_sparse=True,
550
- dtype=[np.float64, np.float32],
551
- force_all_finite=False,
552
- )
553
- else:
554
- X = check_array(X, dtype=[np.float64, np.float32], force_all_finite=False)
555
- y = check_array(y, ensure_2d=False, dtype=X.dtype, force_all_finite=False)
521
+ X, y = self._validate_data(
522
+ X,
523
+ y,
524
+ multi_output=True,
525
+ accept_sparse=True,
526
+ dtype=[np.float64, np.float32],
527
+ force_all_finite=False,
528
+ )
556
529
 
557
530
  if y.ndim == 2 and y.shape[1] == 1:
558
531
  warnings.warn(
@@ -646,9 +619,38 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
646
619
  X,
647
620
  )
648
621
 
622
+ def predict_log_proba(self, X):
623
+ xp, _ = get_namespace(X)
624
+ proba = self.predict_proba(X)
625
+
626
+ if self.n_outputs_ == 1:
627
+ return xp.log(proba)
628
+
629
+ else:
630
+ for k in range(self.n_outputs_):
631
+ proba[k] = xp.log(proba[k])
632
+
633
+ return proba
634
+
635
+ @wrap_output_data
636
+ def score(self, X, y, sample_weight=None):
637
+ return dispatch(
638
+ self,
639
+ "score",
640
+ {
641
+ "onedal": self.__class__._onedal_score,
642
+ "sklearn": sklearn_ForestClassifier.score,
643
+ },
644
+ X,
645
+ y,
646
+ sample_weight=sample_weight,
647
+ )
648
+
649
649
  fit.__doc__ = sklearn_ForestClassifier.fit.__doc__
650
650
  predict.__doc__ = sklearn_ForestClassifier.predict.__doc__
651
651
  predict_proba.__doc__ = sklearn_ForestClassifier.predict_proba.__doc__
652
+ predict_log_proba.__doc__ = sklearn_ForestClassifier.predict_log_proba.__doc__
653
+ score.__doc__ = sklearn_ForestClassifier.score.__doc__
652
654
 
653
655
  def _onedal_cpu_supported(self, method_name, *data):
654
656
  class_name = self.__class__.__name__
@@ -675,7 +677,7 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
675
677
  ]
676
678
  )
677
679
 
678
- elif method_name in ["predict", "predict_proba"]:
680
+ elif method_name in ["predict", "predict_proba", "score"]:
679
681
  X = data[0]
680
682
 
681
683
  patching_status.and_conditions(
@@ -736,11 +738,11 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
736
738
  or self.estimator.__class__ == DecisionTreeClassifier,
737
739
  "ExtraTrees only supported starting from oneDAL version 2023.1",
738
740
  ),
739
- (sample_weight is not None, "sample_weight is not supported."),
741
+ (sample_weight is None, "sample_weight is not supported."),
740
742
  ]
741
743
  )
742
744
 
743
- elif method_name in ["predict", "predict_proba"]:
745
+ elif method_name in ["predict", "predict_proba", "score"]:
744
746
  X = data[0]
745
747
 
746
748
  patching_status.and_conditions(
@@ -792,12 +794,16 @@ class ForestClassifier(sklearn_ForestClassifier, BaseForest):
792
794
  X = check_array(X, dtype=[np.float64, np.float32], force_all_finite=False)
793
795
  check_is_fitted(self, "_onedal_estimator")
794
796
 
795
- if sklearn_check_version("0.23"):
796
- self._check_n_features(X, reset=False)
797
+ self._check_n_features(X, reset=False)
797
798
  if sklearn_check_version("1.0"):
798
799
  self._check_feature_names(X, reset=False)
799
800
  return self._onedal_estimator.predict_proba(X, queue=queue)
800
801
 
802
+ def _onedal_score(self, X, y, sample_weight=None, queue=None):
803
+ return accuracy_score(
804
+ y, self._onedal_predict(X, queue=queue), sample_weight=sample_weight
805
+ )
806
+
801
807
 
802
808
  class ForestRegressor(sklearn_ForestRegressor, BaseForest):
803
809
  _err = "out_of_bag_error_r2|out_of_bag_error_prediction"
@@ -832,14 +838,12 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
832
838
 
833
839
  # The splitter is checked against the class attribute for conformance
834
840
  # This should only trigger if the user uses this class directly.
835
- if (
836
- self.estimator.__class__ == DecisionTreeRegressor
837
- and self._onedal_factory != onedal_RandomForestRegressor
841
+ if self.estimator.__class__ == DecisionTreeRegressor and not issubclass(
842
+ self._onedal_factory, onedal_RandomForestRegressor
838
843
  ):
839
844
  self._onedal_factory = onedal_RandomForestRegressor
840
- elif (
841
- self.estimator.__class__ == ExtraTreeRegressor
842
- and self._onedal_factory != onedal_ExtraTreesRegressor
845
+ elif self.estimator.__class__ == ExtraTreeRegressor and not issubclass(
846
+ self._onedal_factory, onedal_ExtraTreesRegressor
843
847
  ):
844
848
  self._onedal_factory = onedal_ExtraTreesRegressor
845
849
 
@@ -909,18 +913,14 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
909
913
  )
910
914
 
911
915
  if patching_status.get_status():
912
- if sklearn_check_version("0.24"):
913
- X, y = self._validate_data(
914
- X,
915
- y,
916
- multi_output=True,
917
- accept_sparse=True,
918
- dtype=[np.float64, np.float32],
919
- force_all_finite=False,
920
- )
921
- else:
922
- X = check_array(X, dtype=[np.float64, np.float32], force_all_finite=False)
923
- y = check_array(y, ensure_2d=False, dtype=X.dtype, force_all_finite=False)
916
+ X, y = self._validate_data(
917
+ X,
918
+ y,
919
+ multi_output=True,
920
+ accept_sparse=True,
921
+ dtype=[np.float64, np.float32],
922
+ force_all_finite=False,
923
+ )
924
924
 
925
925
  if y.ndim == 2 and y.shape[1] == 1:
926
926
  warnings.warn(
@@ -1045,7 +1045,7 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
1045
1045
  or self.estimator.__class__ == DecisionTreeClassifier,
1046
1046
  "ExtraTrees only supported starting from oneDAL version 2023.1",
1047
1047
  ),
1048
- (sample_weight is not None, "sample_weight is not supported."),
1048
+ (sample_weight is None, "sample_weight is not supported."),
1049
1049
  ]
1050
1050
  )
1051
1051
 
@@ -1122,6 +1122,7 @@ class ForestRegressor(sklearn_ForestRegressor, BaseForest):
1122
1122
  predict.__doc__ = sklearn_ForestRegressor.predict.__doc__
1123
1123
 
1124
1124
 
1125
+ @control_n_jobs(decorated_methods=["fit", "predict", "predict_proba", "score"])
1125
1126
  class RandomForestClassifier(ForestClassifier):
1126
1127
  __doc__ = sklearn_RandomForestClassifier.__doc__
1127
1128
  _onedal_factory = onedal_RandomForestClassifier
@@ -1331,6 +1332,7 @@ class RandomForestClassifier(ForestClassifier):
1331
1332
  self.min_bin_size = min_bin_size
1332
1333
 
1333
1334
 
1335
+ @control_n_jobs(decorated_methods=["fit", "predict"])
1334
1336
  class RandomForestRegressor(ForestRegressor):
1335
1337
  __doc__ = sklearn_RandomForestRegressor.__doc__
1336
1338
  _onedal_factory = onedal_RandomForestRegressor
@@ -1531,6 +1533,7 @@ class RandomForestRegressor(ForestRegressor):
1531
1533
  self.min_bin_size = min_bin_size
1532
1534
 
1533
1535
 
1536
+ @control_n_jobs(decorated_methods=["fit", "predict", "predict_proba", "score"])
1534
1537
  class ExtraTreesClassifier(ForestClassifier):
1535
1538
  __doc__ = sklearn_ExtraTreesClassifier.__doc__
1536
1539
  _onedal_factory = onedal_ExtraTreesClassifier
@@ -1740,6 +1743,7 @@ class ExtraTreesClassifier(ForestClassifier):
1740
1743
  self.min_bin_size = min_bin_size
1741
1744
 
1742
1745
 
1746
+ @control_n_jobs(decorated_methods=["fit", "predict"])
1743
1747
  class ExtraTreesRegressor(ForestRegressor):
1744
1748
  __doc__ = sklearn_ExtraTreesRegressor.__doc__
1745
1749
  _onedal_factory = onedal_ExtraTreesRegressor
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2023 Intel Corporation
4
3
  #
@@ -46,11 +45,7 @@ def test_sklearnex_import_rf_classifier(dataframe, queue):
46
45
  assert_allclose([1], _as_numpy(rf.predict([[0, 0, 0, 0]])))
47
46
 
48
47
 
49
- # TODO:
50
- # investigate failure for `dpnp.ndarrays` and `dpctl.tensors` on `GPU`
51
- @pytest.mark.parametrize(
52
- "dataframe,queue", get_dataframes_and_queues(device_filter_="cpu")
53
- )
48
+ @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
54
49
  def test_sklearnex_import_rf_regression(dataframe, queue):
55
50
  from sklearnex.ensemble import RandomForestRegressor
56
51
 
@@ -60,17 +55,17 @@ def test_sklearnex_import_rf_regression(dataframe, queue):
60
55
  rf = RandomForestRegressor(max_depth=2, random_state=0).fit(X, y)
61
56
  assert "sklearnex" in rf.__module__
62
57
  pred = _as_numpy(rf.predict([[0, 0, 0, 0]]))
63
- if daal_check_version((2024, "P", 0)):
64
- assert_allclose([-6.971], pred, atol=1e-2)
58
+
59
+ if queue is not None and queue.sycl_device.is_gpu:
60
+ assert_allclose([-0.011208], pred, atol=1e-2)
65
61
  else:
66
- assert_allclose([-6.839], pred, atol=1e-2)
62
+ if daal_check_version((2024, "P", 0)):
63
+ assert_allclose([-6.971], pred, atol=1e-2)
64
+ else:
65
+ assert_allclose([-6.839], pred, atol=1e-2)
67
66
 
68
67
 
69
- # TODO:
70
- # investigate failure for `dpnp.ndarrays` and `dpctl.tensors` on `GPU`
71
- @pytest.mark.parametrize(
72
- "dataframe,queue", get_dataframes_and_queues(device_filter_="cpu")
73
- )
68
+ @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
74
69
  def test_sklearnex_import_et_classifier(dataframe, queue):
75
70
  from sklearnex.ensemble import ExtraTreesClassifier
76
71
 
@@ -91,11 +86,7 @@ def test_sklearnex_import_et_classifier(dataframe, queue):
91
86
  assert_allclose([1], _as_numpy(rf.predict([[0, 0, 0, 0]])))
92
87
 
93
88
 
94
- # TODO:
95
- # investigate failure for `dpnp.ndarrays` and `dpctl.tensors` on `GPU`
96
- @pytest.mark.parametrize(
97
- "dataframe,queue", get_dataframes_and_queues(device_filter_="cpu")
98
- )
89
+ @pytest.mark.parametrize("dataframe,queue", get_dataframes_and_queues())
99
90
  def test_sklearnex_import_et_regression(dataframe, queue):
100
91
  from sklearnex.ensemble import ExtraTreesRegressor
101
92
 
@@ -115,4 +106,8 @@ def test_sklearnex_import_et_regression(dataframe, queue):
115
106
  ]
116
107
  )
117
108
  )
118
- assert_allclose([0.445], pred, atol=1e-2)
109
+
110
+ if queue is not None and queue.sycl_device.is_gpu:
111
+ assert_allclose([1.909769], pred, atol=1e-2)
112
+ else:
113
+ assert_allclose([0.445], pred, atol=1e-2)
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #
@@ -17,14 +16,13 @@
17
16
 
18
17
  from .coordinate_descent import ElasticNet, Lasso
19
18
  from .linear import LinearRegression
20
- from .logistic_path import LogisticRegression, logistic_regression_path
19
+ from .logistic_regression import LogisticRegression
21
20
  from .ridge import Ridge
22
21
 
23
22
  __all__ = [
24
23
  "Ridge",
25
24
  "LinearRegression",
26
25
  "LogisticRegression",
27
- "logistic_regression_path",
28
26
  "ElasticNet",
29
27
  "Lasso",
30
28
  ]
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env python
2
1
  # ===============================================================================
3
2
  # Copyright 2021 Intel Corporation
4
3
  #