Package mvpa :: Package measures :: Module searchlight
[hide private]
[frames] | no frames]

Source Code for Module mvpa.measures.searchlight

  1  #emacs: -*- mode: python-mode; py-indent-offset: 4; indent-tabs-mode: nil -*- 
  2  #ex: set 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  """Implementation of the Searchlight algorithm""" 
 10   
 11  __docformat__ = 'restructuredtext' 
 12   
 13  if __debug__: 
 14      from mvpa.misc import debug 
 15   
 16  from mvpa.datasets.mappeddataset import MappedDataset 
 17  from mvpa.mappers.metric import MetricMapper 
 18  from mvpa.measures.base import DatasetMeasure 
 19  from mvpa.misc.state import StateVariable 
 20  from mvpa.base.dochelpers import enhancedDocString 
 21   
 22   
23 -class Searchlight(DatasetMeasure):
24 """Runs a scalar `DatasetMeasure` on all possible spheres of a certain size 25 within a dataset. 26 27 The idea for a searchlight algorithm stems from this paper: 28 29 Kriegeskorte, N., Goebel, R. & Bandettini, P. (2006). 30 'Information-based functional brain mapping.' Proceedings of the 31 National Academy of Sciences of the United States of America 103, 32 3863-3868. 33 """ 34 35 spheresizes = StateVariable(enabled=False, 36 doc="Number of features in each sphere.") 37
38 - def __init__(self, datameasure, radius=1.0, center_ids=None, **kwargs):
39 """Initialize Searchlight to compute `datameasure` for each sphere with 40 a certain `radius` in a given dataset. 41 42 :Parameters: 43 datameasure: callable 44 Any object that takes a `Dataset` and returns some measure when 45 called. 46 radius: float 47 All features within the radius around the center will be part 48 of a sphere. 49 center_ids: list(int) 50 List of feature ids (not coordinates) the shall serve as sphere 51 centers. By default all features will be used. 52 **kwargs: 53 In additions this class supports all keyword arguments of its 54 base-class `DatasetMeasure`. 55 56 ATTENTION: If `Searchlight` is used as `SensitivityAnalyzer` one has to 57 make sure that the specified scalar `DatasetMeasure` returns large 58 (absolute) values for high sensitivities and small (absolute) values 59 for low sensitivities. Especially when using error functions usually 60 low values imply high performance and therefore high sensitivity. This 61 would in turn result in sensitivity maps that have low (absolute) 62 values indicating high sensitivites and this conflicts with the 63 intended behavior of a `SensitivityAnalyzer`. 64 """ 65 DatasetMeasure.__init__(self, **(kwargs)) 66 67 self.__datameasure = datameasure 68 self.__radius = radius 69 self.__center_ids = center_ids
70 71 72 __doc__ = enhancedDocString('Searchlight', locals(), DatasetMeasure) 73 74
75 - def _call(self, dataset):
76 """Perform the spheresearch. 77 """ 78 if not isinstance(dataset, MappedDataset) \ 79 or not isinstance(dataset.mapper, MetricMapper): 80 raise ValueError, "Searchlight only works with MappedDatasets " \ 81 "that make use of a mapper with information " \ 82 "about the dataspace metrics." 83 84 if self.states.isEnabled('spheresizes'): 85 self.spheresizes = [] 86 87 if __debug__: 88 nspheres = dataset.nfeatures 89 sphere_count = 0 90 91 # collect the results in a list -- you never know what you get 92 results = [] 93 94 # decide whether to run on all possible center coords or just a provided 95 # subset 96 if not self.__center_ids == None: 97 generator = self.__center_ids 98 else: 99 generator = xrange(dataset.nfeatures) 100 101 # put spheres around all features in the dataset and compute the 102 # measure within them 103 for f in generator: 104 sphere = dataset.selectFeatures( 105 dataset.mapper.getNeighbors(f, self.__radius), 106 plain=True) 107 108 # compute the datameasure and store in results 109 measure = self.__datameasure(sphere) 110 results.append(measure) 111 112 # store the size of the sphere dataset 113 if self.states.isEnabled('spheresizes'): 114 self.spheresizes.append(sphere.nfeatures) 115 116 if __debug__: 117 sphere_count += 1 118 debug('SLC', "Doing %i spheres: %i (%i features) [%i%%]" \ 119 % (nspheres, 120 sphere_count, 121 sphere.nfeatures, 122 float(sphere_count)/nspheres*100,), cr=True) 123 124 if __debug__: 125 debug('SLC', '') 126 127 # charge state 128 self.raw_results = results 129 130 # return raw results, base-class will take care of transformations 131 return results
132 133 134 135 136 #class OptimalSearchlight( object ): 137 # def __init__( self, 138 # searchlight, 139 # test_radii, 140 # verbose=False, 141 # **kwargs ): 142 # """ 143 # """ 144 # # results will end up here 145 # self.__perfmeans = [] 146 # self.__perfvars = [] 147 # self.__chisquares = [] 148 # self.__chanceprobs = [] 149 # self.__spheresizes = [] 150 # 151 # # run searchligh for all radii in the list 152 # for radius in test_radii: 153 # if verbose: 154 # print 'Using searchlight with radius:', radius 155 # # compute the results 156 # searchlight( radius, **(kwargs) ) 157 # 158 # self.__perfmeans.append( searchlight.perfmean ) 159 # self.__perfvars.append( searchlight.perfvar ) 160 # self.__chisquares.append( searchlight.chisquare ) 161 # self.__chanceprobs.append( searchlight.chanceprob ) 162 # self.__spheresizes.append( searchlight.spheresize ) 163 # 164 # 165 # # now determine the best classification accuracy 166 # best = N.array(self.__perfmeans).argmax( axis=0 ) 167 # 168 # # select the corresponding values of the best classification 169 # # in all data tables 170 # self.perfmean = best.choose(*(self.__perfmeans)) 171 # self.perfvar = best.choose(*(self.__perfvars)) 172 # self.chisquare = best.choose(*(self.__chisquares)) 173 # self.chanceprob = best.choose(*(self.__chanceprobs)) 174 # self.spheresize = best.choose(*(self.__spheresizes)) 175 # 176 # # store the best performing radius 177 # self.bestradius = N.zeros( self.perfmean.shape, dtype='uint' ) 178 # self.bestradius[searchlight.mask==True] = \ 179 # best.choose( test_radii )[searchlight.mask==True] 180 # 181 # 182 # 183 #def makeSphericalROIMask( mask, radius, elementsize=None ): 184 # """ 185 # """ 186 # # use default elementsize if none is supplied 187 # if not elementsize: 188 # elementsize = [ 1 for i in range( len(mask.shape) ) ] 189 # else: 190 # if len( elementsize ) != len( mask.shape ): 191 # raise ValueError, 'elementsize does not match mask dimensions.' 192 # 193 # # rois will be drawn into this mask 194 # roi_mask = N.zeros( mask.shape, dtype='int32' ) 195 # 196 # # while increase with every ROI 197 # roi_id_counter = 1 198 # 199 # # build spheres around every non-zero value in the mask 200 # for center, spheremask in \ 201 # algorithms.SpheresInMask( mask, 202 # radius, 203 # elementsize, 204 # forcesphere = True ): 205 # 206 # # set all elements that match the current spheremask to the 207 # # current ROI index value 208 # roi_mask[spheremask] = roi_id_counter 209 # 210 # # increase ROI counter 211 # roi_id_counter += 1 212 # 213 # return roi_mask 214