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 """Predict the output for the provided data.
162 """
163
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
170
171 fit = N.asarray(res['fit'])
172 if len(fit.shape) == 0:
173
174 fit = fit.reshape( (1,) )
175 return fit
176
177
179 """Return ids of the used features
180 """
181 return N.where(N.abs(self.__weights)>0)[0]
182
183
184
186 """Returns a sensitivity analyzer for ENET."""
187 return ENETWeights(self, **kwargs)
188
189 weights = property(lambda self: self.__weights)
190
191
192
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