1
2
3
4
5
6
7
8
9 """Elastic-Net (ENET) regression classifier."""
10
11 __docformat__ = 'restructuredtext'
12
13
14 import numpy as N
15
16 import mvpa.base.externals as externals
17
18
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
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
91 Classifier.__init__(self, **kwargs)
92
93
94 self.__lm = lm
95 self.__normalize = normalize
96 self.__intercept = intercept
97 self.__trace = trace
98 self.__max_steps = max_steps
99
100
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
108
109 self.states.enable('training_confusion', False)
110
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
124 """Train the classifier using `data` (`Dataset`).
125 """
126 if self.__max_steps is None:
127
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
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
145
146
147
148
149
150
151
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
157
158
159
161 """
162 Predict the output for the provided data.
163 """
164
165 res = rpy.r.predict_enet(self.__trained_model,
166 data,
167 mode='step',
168 type='fit',
169 s=self.__trained_model['beta.pure'].shape[0])
170
171
172 fit = N.asarray(res['fit'])
173 if len(fit.shape) == 0:
174
175 fit = fit.reshape( (1,) )
176 return fit
177
178
180 """Return ids of the used features
181 """
182 return N.where(N.abs(self.__weights)>0)[0]
183
184
185
187 """Returns a sensitivity analyzer for ENET."""
188 return ENETWeights(self, **kwargs)
189
190 weights = property(lambda self: self.__weights)
191
192
193
195 """`SensitivityAnalyzer` that reports the weights ENET trained
196 on a given `Dataset`.
197 """
198
199 _LEGAL_CLFS = [ ENET ]
200
201 - def _call(self, dataset=None):
202 """Extract weights from ENET classifier.
203
204 ENET always has weights available, so nothing has to be computed here.
205 """
206 clf = self.clf
207 weights = clf.weights
208
209 if __debug__:
210 debug('ENET',
211 "Extracting weights for ENET - "+
212 "Result: min=%f max=%f" %\
213 (N.min(weights), N.max(weights)))
214
215 return weights
216