scikit-learn/sklearn/svm/sparse/base.py

305 lines
11 KiB
Python

import numpy as np
import scipy.sparse
from ..base import BaseLibSVM, BaseLibLinear, LIBSVM_IMPL, _get_class_weight
from . import libsvm
from .. import liblinear
class SparseBaseLibSVM(BaseLibSVM):
_kernel_types = ['linear', 'poly', 'rbf', 'sigmoid', 'precomputed']
def __init__(self, impl, kernel, degree, gamma, coef0,
tol, C, nu, epsilon, shrinking, probability, cache_size,
scale_C):
assert kernel in self._kernel_types, \
"kernel should be one of %s, "\
"%s was given." % (self._kernel_types, kernel)
super(SparseBaseLibSVM, self).__init__(impl, kernel, degree, gamma,
coef0, tol, C, nu, epsilon, shrinking, probability, cache_size,
scale_C)
def fit(self, X, y, class_weight=None, sample_weight=None):
"""
Fit the SVM model according to the given training data and parameters.
Parameters
----------
X : sparse matrix, shape = [n_samples, n_features]
Training vectors, where n_samples is the number of samples and
n_features is the number of features.
y : array-like, shape = [n_samples]
Target values (integers in classification, real numbers in
regression)
class_weight : {dict, 'auto'}, optional
Weights associated with classes in the form
{class_label : weight}. If not given, all classes are
supposed to have weight one.
The 'auto' mode uses the values of y to automatically adjust
weights inversely proportional to class frequencies.
sample_weight : array-like, shape = [n_samples], optional
Weights applied to individual samples (1. for unweighted).
Returns
-------
self : object
Returns an instance of self.
Notes
-----
For maximum effiency, use a sparse matrix in csr format
(scipy.sparse.csr_matrix)
"""
X = scipy.sparse.csr_matrix(X)
X.data = np.asarray(X.data, dtype=np.float64, order='C')
y = np.asarray(y, dtype=np.float64, order='C')
sample_weight = np.asarray([] if sample_weight is None
else sample_weight, dtype=np.float64)
if X.shape[0] != y.shape[0]:
raise ValueError("X and y have incompatible shapes: %r vs %r\n"
"Note: Sparse matrices cannot be indexed w/"
"boolean masks (use `indices=True` in CV)."
% (X.shape, y.shape))
if sample_weight.shape[0] > 0 and sample_weight.shape[0] != X.shape[0]:
raise ValueError("sample_weight and X have incompatible shapes:"
"%r vs %r\n"
"Note: Sparse matrices cannot be indexed w/"
"boolean masks (use `indices=True` in CV)."
% (sample_weight.shape, X.shape))
solver_type = LIBSVM_IMPL.index(self.impl)
kernel_type = self._kernel_types.index(self.kernel)
self.class_weight, self.class_weight_label = \
_get_class_weight(class_weight, y)
if (kernel_type in [1, 2]) and (self.gamma == 0):
# if custom gamma is not provided ...
self.gamma = 1.0 / X.shape[1]
C = self.C
if self.scale_C:
C = C / float(X.shape[0])
self.support_vectors_, dual_coef_data, self.intercept_, self.label_, \
self.n_support_, self.probA_, self.probB_ = \
libsvm.libsvm_sparse_train(
X.shape[1], X.data, X.indices, X.indptr, y, solver_type,\
kernel_type, self.degree, self.gamma, self.coef0, self.tol,\
C, self.class_weight_label, self.class_weight,\
sample_weight, self.nu, self.cache_size, self.epsilon,\
int(self.shrinking), int(self.probability))
n_class = len(self.label_) - 1
n_SV = self.support_vectors_.shape[0]
dual_coef_indices = np.tile(np.arange(n_SV), n_class)
dual_coef_indptr = np.arange(0, dual_coef_indices.size + 1,
dual_coef_indices.size / n_class)
self.dual_coef_ = scipy.sparse.csr_matrix(
(dual_coef_data, dual_coef_indices, dual_coef_indptr),
(n_class, n_SV))
return self
def predict(self, T):
"""
This function does classification or regression on an array of
test vectors T.
For a classification model, the predicted class for each
sample in T is returned. For a regression model, the function
value of T calculated is returned.
For an one-class model, +1 or -1 is returned.
Parameters
----------
T : scipy.sparse.csr, shape = [n_samples, n_features]
Returns
-------
C : array, shape = [n_samples]
"""
T = scipy.sparse.csr_matrix(T)
T.data = np.asarray(T.data, dtype=np.float64, order='C')
kernel_type = self._kernel_types.index(self.kernel)
return libsvm.libsvm_sparse_predict(T.data, T.indices, T.indptr,
self.support_vectors_.data,
self.support_vectors_.indices,
self.support_vectors_.indptr,
self.dual_coef_.data, self.intercept_,
LIBSVM_IMPL.index(self.impl), kernel_type,
self.degree, self.gamma, self.coef0, self.tol,
self.C, self.class_weight_label, self.class_weight,
self.nu, self.epsilon, self.shrinking,
self.probability, self.n_support_, self.label_,
self.probA_, self.probB_)
def predict_proba(self, X):
"""
This function does classification or regression on a test vector X
given a model with probability information.
Parameters
----------
X : scipy.sparse.csr, shape = [n_samples, n_features]
Returns
-------
X : array-like, shape = [n_samples, n_classes]
Returns the probability of the sample for each class in
the model, where classes are ordered by arithmetical
order.
Notes
-----
The probability model is created using cross validation, so
the results can be slightly different than those obtained by
predict. Also, it will meaningless results on very small
datasets.
"""
if not self.probability:
raise ValueError(
"probability estimates must be enabled to use this method")
if self.impl not in ('c_svc', 'nu_svc'):
raise NotImplementedError("predict_proba only implemented for " +
"SVC and NuSVC")
X = scipy.sparse.csr_matrix(X)
X.data = np.asarray(X.data, dtype=np.float64, order='C')
kernel_type = self._kernel_types.index(self.kernel)
return libsvm.libsvm_sparse_predict_proba(
X.data, X.indices, X.indptr,
self.support_vectors_.data,
self.support_vectors_.indices,
self.support_vectors_.indptr,
self.dual_coef_.data, self.intercept_,
LIBSVM_IMPL.index(self.impl), kernel_type,
self.degree, self.gamma, self.coef0, self.tol,
self.C, self.class_weight_label, self.class_weight,
self.nu, self.epsilon, self.shrinking,
self.probability, self.n_support_, self.label_,
self.probA_, self.probB_)
class SparseBaseLibLinear(BaseLibLinear):
def fit(self, X, y, class_weight=None):
"""
Fit the model using X, y as training data.
Parameters
----------
X : sparse matrix, shape = [n_samples, n_features]
Training vector, where n_samples in the number of samples and
n_features is the number of features.
y : array, shape = [n_samples]
Target vector relative to X
Returns
-------
self : object
Returns an instance of self.
"""
import scipy.sparse
X = scipy.sparse.csr_matrix(X)
y = np.asarray(y, dtype=np.int32, order='C')
if X.shape[0] != y.shape[0]:
raise ValueError("X and y have incompatible shapes.\n" +
"Note: Sparse matrices cannot be indexed w/" +
"boolean masks (use `indices=True` in CV).")
X.data = np.asarray(X.data, dtype=np.float64, order='C')
self.class_weight, self.class_weight_label = \
_get_class_weight(class_weight, y)
C = self.C
if self.scale_C:
C = C / float(X.shape[0])
self.raw_coef_, self.label_ = \
liblinear.csr_train_wrap(X.shape[1], X.data, X.indices,
X.indptr, y,
self._get_solver_type(),
self.tol, self._get_bias(), C,
self.class_weight_label, self.class_weight)
return self
def predict(self, X):
"""
Predict target values of X according to the fitted model.
Parameters
----------
X : sparse matrix, shape = [n_samples, n_features]
Returns
-------
C : array, shape = [n_samples]
"""
import scipy.sparse
X = scipy.sparse.csr_matrix(X)
self._check_n_features(X)
X.data = np.asarray(X.data, dtype=np.float64, order='C')
return liblinear.csr_predict_wrap(X.shape[1], X.data,
X.indices, X.indptr,
self.raw_coef_,
self._get_solver_type(),
self.tol, self.C,
self.class_weight_label,
self.class_weight, self.label_,
self._get_bias())
def decision_function(self, X):
"""
Return the decision function of X according to the trained
model.
Parameters
----------
X : sparse matrix, shape = [n_samples, n_features]
Returns
-------
T : array-like, shape = [n_samples, n_class]
Returns the decision function of the sample for each class
in the model.
"""
import scipy.sparse
X = scipy.sparse.csr_matrix(X)
self._check_n_features(X)
X.data = np.asarray(X.data, dtype=np.float64, order='C')
dec_func = liblinear.csr_decision_function_wrap(
X.shape[1], X.data, X.indices, X.indptr, self.raw_coef_,
self._get_solver_type(), self.tol, self.C,
self.class_weight_label, self.class_weight, self.label_,
self._get_bias())
if len(self.label_) <= 2:
# in the two-class case, the decision sign needs be flipped
# due to liblinear's design
return -dec_func
else:
return dec_func
libsvm.set_verbosity_wrap(0)