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

Source Code for Module mvpa.measures.searchlight

  1  # emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*- 
  2  # vi: set ft=python 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.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   
22 -class Searchlight(DatasetMeasure):
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 # collect the results in a list -- you never know what you get 91 results = [] 92 93 # decide whether to run on all possible center coords or just a provided 94 # subset 95 if not self.__center_ids == None: 96 generator = self.__center_ids 97 else: 98 generator = xrange(dataset.nfeatures) 99 100 # put spheres around all features in the dataset and compute the 101 # measure within them 102 for f in generator: 103 sphere = dataset.selectFeatures( 104 dataset.mapper.getNeighbors(f, self.__radius), 105 plain=True) 106 107 # compute the datameasure and store in results 108 measure = self.__datameasure(sphere) 109 results.append(measure) 110 111 # store the size of the sphere dataset 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 # charge state 127 self.raw_results = results 128 129 # return raw results, base-class will take care of transformations 130 return results
131 132 133 134 135 #class OptimalSearchlight( object ): 136 # def __init__( self, 137 # searchlight, 138 # test_radii, 139 # verbose=False, 140 # **kwargs ): 141 # """ 142 # """ 143 # # results will end up here 144 # self.__perfmeans = [] 145 # self.__perfvars = [] 146 # self.__chisquares = [] 147 # self.__chanceprobs = [] 148 # self.__spheresizes = [] 149 # 150 # # run searchligh for all radii in the list 151 # for radius in test_radii: 152 # if verbose: 153 # print 'Using searchlight with radius:', radius 154 # # compute the results 155 # searchlight( radius, **(kwargs) ) 156 # 157 # self.__perfmeans.append( searchlight.perfmean ) 158 # self.__perfvars.append( searchlight.perfvar ) 159 # self.__chisquares.append( searchlight.chisquare ) 160 # self.__chanceprobs.append( searchlight.chanceprob ) 161 # self.__spheresizes.append( searchlight.spheresize ) 162 # 163 # 164 # # now determine the best classification accuracy 165 # best = N.array(self.__perfmeans).argmax( axis=0 ) 166 # 167 # # select the corresponding values of the best classification 168 # # in all data tables 169 # self.perfmean = best.choose(*(self.__perfmeans)) 170 # self.perfvar = best.choose(*(self.__perfvars)) 171 # self.chisquare = best.choose(*(self.__chisquares)) 172 # self.chanceprob = best.choose(*(self.__chanceprobs)) 173 # self.spheresize = best.choose(*(self.__spheresizes)) 174 # 175 # # store the best performing radius 176 # self.bestradius = N.zeros( self.perfmean.shape, dtype='uint' ) 177 # self.bestradius[searchlight.mask==True] = \ 178 # best.choose( test_radii )[searchlight.mask==True] 179 # 180 # 181 # 182 #def makeSphericalROIMask( mask, radius, elementsize=None ): 183 # """ 184 # """ 185 # # use default elementsize if none is supplied 186 # if not elementsize: 187 # elementsize = [ 1 for i in range( len(mask.shape) ) ] 188 # else: 189 # if len( elementsize ) != len( mask.shape ): 190 # raise ValueError, 'elementsize does not match mask dimensions.' 191 # 192 # # rois will be drawn into this mask 193 # roi_mask = N.zeros( mask.shape, dtype='int32' ) 194 # 195 # # while increase with every ROI 196 # roi_id_counter = 1 197 # 198 # # build spheres around every non-zero value in the mask 199 # for center, spheremask in \ 200 # algorithms.SpheresInMask( mask, 201 # radius, 202 # elementsize, 203 # forcesphere = True ): 204 # 205 # # set all elements that match the current spheremask to the 206 # # current ROI index value 207 # roi_mask[spheremask] = roi_id_counter 208 # 209 # # increase ROI counter 210 # roi_id_counter += 1 211 # 212 # return roi_mask 213