Package mvpa :: Package clfs :: Package libsvmc :: Module sens
[hide private]
[frames] | no frames]

Source Code for Module mvpa.clfs.libsvmc.sens

  1  # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- 
  2  # vi: set ft=python sts=4 ts=4 sw=4 et: 
  3  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 
  4  # 
  5  #   See COPYING file distributed along with the PyMVPA package for the 
  6  #   copyright and license terms. 
  7  # 
  8  ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ## 
  9  """Provide sensitivity measures for libsvm's SVM.""" 
 10   
 11  __docformat__ = 'restructuredtext' 
 12   
 13  import numpy as N 
 14   
 15  from mvpa.base import warning 
 16  from mvpa.misc.state import StateVariable 
 17  from mvpa.misc.param import Parameter 
 18  from mvpa.measures.base import Sensitivity 
 19   
 20  if __debug__: 
 21      from mvpa.base import debug 
 22   
23 -class LinearSVMWeights(Sensitivity):
24 """`SensitivityAnalyzer` for the LIBSVM implementation of a linear SVM. 25 """ 26 27 _ATTRIBUTE_COLLECTIONS = ['params'] 28 29 biases = StateVariable(enabled=True, 30 doc="Offsets of separating hyperplanes") 31 32 split_weights = Parameter(False, allowedtype='bool', 33 doc="If binary classification either to sum SVs per each " 34 "class separately") 35
36 - def __init__(self, clf, **kwargs):
37 """Initialize the analyzer with the classifier it shall use. 38 39 :Parameters: 40 clf: LinearSVM 41 classifier to use. Only classifiers sub-classed from 42 `LinearSVM` may be used. 43 """ 44 # init base classes first 45 Sensitivity.__init__(self, clf, **kwargs)
46 47
48 - def _call(self, dataset, callables=[]):
49 # local bindings 50 clf = self.clf 51 model = clf.model 52 if clf.params.regression: 53 nr_class = None 54 else: 55 nr_class = model.nr_class 56 57 if not nr_class in [None, 2]: 58 warning("You are estimating sensitivity for SVM %s trained on %d" % 59 (str(self.clf), self.clf.model.nr_class) + 60 " classes. Make sure that it is what you intended to do" ) 61 62 svcoef = N.matrix(model.getSVCoef()) 63 svs = N.matrix(model.getSV()) 64 rhos = N.asarray(model.getRho()) 65 66 self.biases = rhos 67 if self.split_weights: 68 if nr_class != 2: 69 raise NotImplementedError, \ 70 "Cannot compute per-class weights for" \ 71 " non-binary classification task" 72 # libsvm might have different idea on the ordering 73 # of labels, so we would need to map them back explicitely 74 svm_labels = model.getLabels() # labels as assigned by libsvm 75 ds_labels = list(dataset.uniquelabels) # labels in the dataset 76 senses = [None for i in ds_labels] 77 # first label is given positive value 78 for i, (c, l) in enumerate( [(svcoef > 0, lambda x: x), 79 (svcoef < 0, lambda x: x*-1)] ): 80 # convert to array, and just take the meaningful dimension 81 c_ = c.A[0] 82 senses[ds_labels.index(svm_labels[i])] = \ 83 (l(svcoef[:, c_] * svs[c_, :])).A[0] 84 weights = N.array(senses) 85 else: 86 # XXX yoh: .mean() is effectively 87 # averages across "sensitivities" of all paired classifiers (I 88 # think). See more info on this topic in svm.py on how sv_coefs 89 # are stored 90 # 91 # First multiply SV coefficients with the actual SVs to get 92 # weighted impact of SVs on decision, then for each feature 93 # take mean across SVs to get a single weight value 94 # per feature 95 weights = svcoef * svs 96 97 if __debug__ and 'SVM' in debug.active: 98 if clf.params.regression: 99 nsvs = model.getTotalNSV() 100 else: 101 nsvs = model.getNSV() 102 if clf.regression: 103 svm_type = clf._svm_impl # type of regression 104 else: 105 svm_type = '%d-class SVM(%s)' % (nr_class, clf._svm_impl) 106 debug('SVM', 107 "Extracting weights for %s: #SVs=%s, " % \ 108 (svm_type, nsvs) + \ 109 " SVcoefshape=%s SVs.shape=%s Rhos=%s." % \ 110 (svcoef.shape, svs.shape, rhos) + \ 111 " Result: min=%f max=%f" % (N.min(weights), N.max(weights))) 112 113 return N.asarray(weights.T)
114 115 _customizeDocInherit = True
116