@@ -366,29 +366,58 @@ def decision_function(self, X):
366
366
# NOTE: _validate_for_predict contains check for is_fitted
367
367
# hence must be placed before any other attributes are used.
368
368
X = self ._validate_for_predict (X )
369
- if self ._sparse :
370
- raise NotImplementedError ("Decision_function not supported for"
371
- " sparse SVM." )
372
369
X = self ._compute_kernel (X )
373
370
371
+ X = self ._validate_for_predict (X )
372
+
373
+ if self ._sparse :
374
+ dec_func = self ._sparse_decision_function (X )
375
+ else :
376
+ dec_func = self ._dense_decision_function (X )
377
+
378
+ # In binary case, we need to flip the sign of coef, intercept and
379
+ # decision function.
380
+ if self .impl != 'one_class' and len (self .classes_ ) == 2 :
381
+ return - dec_func
382
+
383
+ return dec_func
384
+
385
+ def _dense_decision_function (self , X ):
386
+ X = check_array (X , dtype = np .float64 , order = "C" )
387
+
374
388
kernel = self .kernel
375
389
if callable (kernel ):
376
390
kernel = 'precomputed'
377
391
378
- dec_func = libsvm .decision_function (
392
+ return libsvm .decision_function (
379
393
X , self .support_ , self .support_vectors_ , self .n_support_ ,
380
394
self ._dual_coef_ , self ._intercept_ ,
381
395
self .probA_ , self .probB_ ,
382
396
svm_type = LIBSVM_IMPL .index (self ._impl ),
383
397
kernel = kernel , degree = self .degree , cache_size = self .cache_size ,
384
398
coef0 = self .coef0 , gamma = self ._gamma )
385
399
386
- # In binary case, we need to flip the sign of coef, intercept and
387
- # decision function.
388
- if self ._impl in ['c_svc' , 'nu_svc' ] and len (self .classes_ ) == 2 :
389
- return - dec_func .ravel ()
400
+ def _sparse_decision_function (self , X ):
401
+ X .data = np .asarray (X .data , dtype = np .float64 , order = 'C' )
390
402
391
- return dec_func
403
+ kernel = self .kernel
404
+ if hasattr (kernel , '__call__' ):
405
+ kernel = 'precomputed'
406
+
407
+ kernel_type = self ._sparse_kernels .index (kernel )
408
+
409
+ return libsvm_sparse .libsvm_sparse_decision_function (
410
+ X .data , X .indices , X .indptr ,
411
+ self .support_vectors_ .data ,
412
+ self .support_vectors_ .indices ,
413
+ self .support_vectors_ .indptr ,
414
+ self ._dual_coef_ .data , self ._intercept_ ,
415
+ LIBSVM_IMPL .index (self .impl ), kernel_type ,
416
+ self .degree , self .gamma , self .coef0 , self .tol ,
417
+ self .C , self .class_weight_ ,
418
+ self .nu , self .epsilon , self .shrinking ,
419
+ self .probability , self .n_support_ , self ._label ,
420
+ self .probA_ , self .probB_ )
392
421
393
422
def _validate_for_predict (self , X ):
394
423
check_is_fitted (self , 'support_' )
@@ -666,9 +695,8 @@ def _get_liblinear_solver_type(multi_class, penalty, loss, dual):
666
695
% (penalty , loss , dual ))
667
696
else :
668
697
return solver_num
669
-
670
- raise ValueError (('Unsupported set of arguments: %s, '
671
- 'Parameters: penalty=%r, loss=%r, dual=%r' )
698
+ raise ValueError ('Unsupported set of arguments: %s, '
699
+ 'Parameters: penalty=%r, loss=%r, dual=%r'
672
700
% (error_string , penalty , loss , dual ))
673
701
674
702
@@ -811,8 +839,7 @@ def _fit_liblinear(X, y, C, fit_intercept, intercept_scaling, class_weight,
811
839
raw_coef_ , n_iter_ = liblinear .train_wrap (
812
840
X , y_ind , sp .isspmatrix (X ), solver_type , tol , bias , C ,
813
841
class_weight_ , max_iter , rnd .randint (np .iinfo ('i' ).max ),
814
- epsilon
815
- )
842
+ epsilon )
816
843
# Regarding rnd.randint(..) in the above signature:
817
844
# seed for srand in range [0..INT_MAX); due to limitations in Numpy
818
845
# on 32-bit platforms, we can't get to the UINT_MAX limit that
0 commit comments