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. Provided dataset should have a metric assigned
42 (for NiftiDataset, voxel size is used to provide such a metric,
43 hence radius should be specified in mm).
44 center_ids: list(int)
45 List of feature ids (not coordinates) the shall serve as sphere
46 centers. By default all features will be used.
47 **kwargs
48 In additions this class supports all keyword arguments of its
49 base-class :class:`~mvpa.measures.base.DatasetMeasure`.
50
51 .. note::
52
53 If `Searchlight` is used as `SensitivityAnalyzer` one has to make
54 sure that the specified scalar `DatasetMeasure` returns large
55 (absolute) values for high sensitivities and small (absolute) values
56 for low sensitivities. Especially when using error functions usually
57 low values imply high performance and therefore high sensitivity.
58 This would in turn result in sensitivity maps that have low
59 (absolute) values indicating high sensitivites and this conflicts
60 with the intended behavior of a `SensitivityAnalyzer`.
61 """
62 DatasetMeasure.__init__(self, **(kwargs))
63
64 self.__datameasure = datameasure
65 self.__radius = radius
66 self.__center_ids = center_ids
67
68
69 __doc__ = enhancedDocString('Searchlight', locals(), DatasetMeasure)
70
71
72 - def _call(self, dataset):
73 """Perform the spheresearch.
74 """
75 if not isinstance(dataset, MappedDataset) \
76 or dataset.mapper.metric is None:
77 raise ValueError, "Searchlight only works with MappedDatasets " \
78 "that has metric assigned."
79
80 if self.states.isEnabled('spheresizes'):
81 self.spheresizes = []
82
83 if __debug__:
84 if not self.__center_ids == None:
85 nspheres = len(self.__center_ids)
86 else:
87 nspheres = dataset.nfeatures
88 sphere_count = 0
89
90
91 results = []
92
93
94
95 if not self.__center_ids == None:
96 generator = self.__center_ids
97 else:
98 generator = xrange(dataset.nfeatures)
99
100
101
102 for f in generator:
103 sphere = dataset.selectFeatures(
104 dataset.mapper.getNeighbors(f, self.__radius),
105 plain=True)
106
107
108 measure = self.__datameasure(sphere)
109 results.append(measure)
110
111
112 if self.states.isEnabled('spheresizes'):
113 self.spheresizes.append(sphere.nfeatures)
114
115 if __debug__:
116 sphere_count += 1
117 debug('SLC', "Doing %i spheres: %i (%i features) [%i%%]" \
118 % (nspheres,
119 sphere_count,
120 sphere.nfeatures,
121 float(sphere_count)/nspheres*100,), cr=True)
122
123 if __debug__:
124 debug('SLC', '')
125
126
127 self.raw_results = results
128
129
130 return results
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
209
210
211
212
213