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

Source Code for Module mvpa.clfs.enet

  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  """Elastic-Net (ENET) regression classifier.""" 
 10   
 11  __docformat__ = 'restructuredtext' 
 12   
 13  # system imports 
 14  import numpy as N 
 15   
 16  import mvpa.base.externals as externals 
 17   
 18  # do conditional to be able to build module reference 
 19  if externals.exists('rpy', raiseException=True) and \ 
 20     externals.exists('elasticnet', raiseException=True): 
 21      import rpy 
 22      rpy.r.library('elasticnet') 
 23   
 24   
 25  # local imports 
 26  from mvpa.clfs.base import Classifier 
 27  from mvpa.measures.base import Sensitivity 
 28   
 29  if __debug__: 
 30      from mvpa.base import debug 
 31   
32 -class ENET(Classifier):
33 """Elastic-Net regression (ENET) `Classifier`. 34 35 Elastic-Net is the model selection algorithm from: 36 37 :ref:`Zou and Hastie (2005) <ZH05>` 'Regularization and Variable 38 Selection via the Elastic Net' Journal of the Royal Statistical 39 Society, Series B, 67, 301-320. 40 41 Similar to SMLR, it performs a feature selection while performing 42 classification, but instead of starting with all features, it 43 starts with none and adds them in, which is similar to boosting. 44 45 Unlike LARS it has both L1 and L2 regularization (instead of just 46 L1). This means that while it tries to sparsify the features it 47 also tries to keep redundant features, which may be very very good 48 for fMRI classification. 49 50 In the true nature of the PyMVPA framework, this algorithm was 51 actually implemented in R by Zou and Hastie and wrapped via RPy. 52 To make use of ENET, you must have R and RPy installed as well as 53 both the lars and elasticnet contributed package. You can install 54 the R and RPy with the following command on Debian-based machines: 55 56 sudo aptitude install python-rpy python-rpy-doc r-base-dev 57 58 You can then install the lars and elasticnet package by running R 59 as root and calling: 60 61 install.packages() 62 63 """ 64 65 _clf_internals = [ 'enet', 'regression', 'linear', 'has_sensitivity', 66 'does_feature_selection' 67 ]
68 - def __init__(self, lm=1.0, trace=False, normalize=True, 69 intercept=True, max_steps=None, **kwargs):
70 """ 71 Initialize ENET. 72 73 See the help in R for further details on the following parameters: 74 75 :Parameters: 76 lm : float 77 Penalty parameter. 0 will perform LARS with no ridge regression. 78 Default is 1.0. 79 trace : boolean 80 Whether to print progress in R as it works. 81 normalize : boolean 82 Whether to normalize the L2 Norm. 83 intercept : boolean 84 Whether to add a non-penalized intercept to the model. 85 max_steps : None or int 86 If not None, specify the total number of iterations to run. Each 87 iteration adds a feature, but leaving it none will add until 88 convergence. 89 """ 90 # init base class first 91 Classifier.__init__(self, **kwargs) 92 93 # set up the params 94 self.__lm = lm 95 self.__normalize = normalize 96 self.__intercept = intercept 97 self.__trace = trace 98 self.__max_steps = max_steps 99 100 # pylint friendly initializations 101 self.__weights = None 102 """The beta weights for each feature.""" 103 self.__trained_model = None 104 """The model object after training that will be used for 105 predictions.""" 106 107 # It does not make sense to calculate a confusion matrix for a 108 # regression 109 self.states.enable('training_confusion', False)
110
111 - def __repr__(self):
112 """String summary of the object 113 """ 114 return """ENET(lm=%s, normalize=%s, intercept=%s, trace=%s, max_steps=%s, enable_states=%s)""" % \ 115 (self.__lm, 116 self.__normalize, 117 self.__intercept, 118 self.__trace, 119 self.__max_steps, 120 str(self.states.enabled))
121 122
123 - def _train(self, data):
124 """Train the classifier using `data` (`Dataset`). 125 """ 126 if self.__max_steps is None: 127 # train without specifying max_steps 128 self.__trained_model = rpy.r.enet(data.samples, 129 data.labels[:,N.newaxis], 130 self.__lm, 131 normalize=self.__normalize, 132 intercept=self.__intercept, 133 trace=self.__trace) 134 else: 135 # train with specifying max_steps 136 self.__trained_model = rpy.r.enet(data.samples, 137 data.labels[:,N.newaxis], 138 self.__lm, 139 normalize=self.__normalize, 140 intercept=self.__intercept, 141 trace=self.__trace, 142 max_steps=self.__max_steps) 143 144 # find the step with the lowest Cp (risk) 145 # it is often the last step if you set a max_steps 146 # must first convert dictionary to array 147 # Cp_vals = N.asarray([self.__trained_model['Cp'][str(x)] 148 # for x in range(len(self.__trained_model['Cp']))]) 149 # self.__lowest_Cp_step = Cp_vals.argmin() 150 151 # set the weights to the last step 152 self.__weights = N.zeros(data.nfeatures,dtype=self.__trained_model['beta.pure'].dtype) 153 ind = N.asarray(self.__trained_model['allset'])-1 154 self.__weights[ind] = self.__trained_model['beta.pure'][-1,:]
155 156 # # set the weights to the final state 157 # self.__weights = self.__trained_model['beta'][-1,:] 158 159
160 - def _predict(self, data):
161 """Predict the output for the provided data. 162 """ 163 # predict with the final state (i.e., the last step) 164 res = rpy.r.predict_enet(self.__trained_model, 165 data, 166 mode='step', 167 type='fit', 168 s=self.__trained_model['beta.pure'].shape[0]) 169 #s=self.__lowest_Cp_step) 170 171 fit = N.asarray(res['fit']) 172 if len(fit.shape) == 0: 173 # if we just got 1 sample with a scalar 174 fit = fit.reshape( (1,) ) 175 return fit
176 177
178 - def _getFeatureIds(self):
179 """Return ids of the used features 180 """ 181 return N.where(N.abs(self.__weights)>0)[0]
182 183 184
185 - def getSensitivityAnalyzer(self, **kwargs):
186 """Returns a sensitivity analyzer for ENET.""" 187 return ENETWeights(self, **kwargs)
188 189 weights = property(lambda self: self.__weights)
190 191 192
193 -class ENETWeights(Sensitivity):
194 """`SensitivityAnalyzer` that reports the weights ENET trained 195 on a given `Dataset`. 196 """ 197 198 _LEGAL_CLFS = [ ENET ] 199
200 - def _call(self, dataset=None):
201 """Extract weights from ENET classifier. 202 203 ENET always has weights available, so nothing has to be computed here. 204 """ 205 clf = self.clf 206 weights = clf.weights 207 208 if __debug__: 209 debug('ENET', 210 "Extracting weights for ENET - "+ 211 "Result: min=%f max=%f" %\ 212 (N.min(weights), N.max(weights))) 213 214 return weights
215