1
2
3
4
5
6
7
8
9 """Implementation of the Searchlight algorithm"""
10
11 __docformat__ = 'restructuredtext'
12
13 if __debug__:
14 from mvpa.base import debug
15
16 from mvpa.datasets.mapped import MappedDataset
17 from mvpa.measures.base import DatasetMeasure
18 from mvpa.misc.state import StateVariable
19 from mvpa.base.dochelpers import enhancedDocString
20
21
23 """Runs a scalar `DatasetMeasure` on all possible spheres of a certain size
24 within a dataset.
25
26 The idea for a searchlight algorithm stems from a paper by
27 :ref:`Kriegeskorte et al. (2006) <KGB06>`.
28 """
29
30 spheresizes = StateVariable(enabled=False,
31 doc="Number of features in each sphere.")
32
33 - def __init__(self, datameasure, radius=1.0, center_ids=None, **kwargs):
34 """
35 :Parameters:
36 datameasure: callable
37 Any object that takes a :class:`~mvpa.datasets.base.Dataset`
38 and returns some measure when called.
39 radius: float
40 All features within the radius around the center will be part
41 of a sphere.
42 center_ids: list(int)
43 List of feature ids (not coordinates) the shall serve as sphere
44 centers. By default all features will be used.
45 **kwargs
46 In additions this class supports all keyword arguments of its
47 base-class :class:`~mvpa.measures.base.DatasetMeasure`.
48
49 .. note::
50
51 If `Searchlight` is used as `SensitivityAnalyzer` one has to make
52 sure that the specified scalar `DatasetMeasure` returns large
53 (absolute) values for high sensitivities and small (absolute) values
54 for low sensitivities. Especially when using error functions usually
55 low values imply high performance and therefore high sensitivity.
56 This would in turn result in sensitivity maps that have low
57 (absolute) values indicating high sensitivites and this conflicts
58 with the intended behavior of a `SensitivityAnalyzer`.
59 """
60 DatasetMeasure.__init__(self, **(kwargs))
61
62 self.__datameasure = datameasure
63 self.__radius = radius
64 self.__center_ids = center_ids
65
66
67 __doc__ = enhancedDocString('Searchlight', locals(), DatasetMeasure)
68
69
70 - def _call(self, dataset):
71 """Perform the spheresearch.
72 """
73 if not isinstance(dataset, MappedDataset) \
74 or dataset.mapper.metric is None:
75 raise ValueError, "Searchlight only works with MappedDatasets " \
76 "that has metric assigned."
77
78 if self.states.isEnabled('spheresizes'):
79 self.spheresizes = []
80
81 if __debug__:
82 nspheres = dataset.nfeatures
83 sphere_count = 0
84
85
86 results = []
87
88
89
90 if not self.__center_ids == None:
91 generator = self.__center_ids
92 else:
93 generator = xrange(dataset.nfeatures)
94
95
96
97 for f in generator:
98 sphere = dataset.selectFeatures(
99 dataset.mapper.getNeighbors(f, self.__radius),
100 plain=True)
101
102
103 measure = self.__datameasure(sphere)
104 results.append(measure)
105
106
107 if self.states.isEnabled('spheresizes'):
108 self.spheresizes.append(sphere.nfeatures)
109
110 if __debug__:
111 sphere_count += 1
112 debug('SLC', "Doing %i spheres: %i (%i features) [%i%%]" \
113 % (nspheres,
114 sphere_count,
115 sphere.nfeatures,
116 float(sphere_count)/nspheres*100,), cr=True)
117
118 if __debug__:
119 debug('SLC', '')
120
121
122 self.raw_results = results
123
124
125 return results
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208