Package mvpa :: Package tests :: Module test_metadataset

[hide private]
[frames] | no frames]

# Source Code for Module mvpa.tests.test_metadataset

      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  """Unit tests for PyMVPA meta dataset handling"""
     10
     11  import unittest
     12  import numpy as N
     13  import os.path
     14  from mvpa import pymvpa_dataroot
     15  from mvpa.support.copy import deepcopy
     16  from mvpa.base import externals
     17  from mvpa.datasets import Dataset
     18  from mvpa.datasets.meta import MetaDataset
     19  from mvpa.datasets.eep import EEPDataset
     20  from mvpa.mappers.base import CombinedMapper, ChainMapper
     21  from mvpa.mappers.array import DenseArrayMapper
     22  from mvpa.mappers.mask import MaskMapper
     23  from mvpa.mappers.boxcar import BoxcarMapper
     24  from mvpa.datasets.event import EventDataset
     25  from mvpa.misc.support import Event
     26  from mvpa.misc.exceptions import DatasetError
     27
     28
     29 -class MetaDatasetTests(unittest.TestCase):
     30
     31 -    def testSimple(self):
     32          # bunch of datasets
     33
     34          datasets = [
     35                       Dataset(samples=N.arange(12).reshape((4,3)), labels=1),
     36                       Dataset(samples=N.zeros((4,4)), labels=1),
     37                       Dataset(samples=N.ones((4,2), dtype='float'), labels=1),
     38                     ]
     39
     40          mds = MetaDataset(datasets)
     41
     42          # all together
     43          self.failUnless(mds.samples.shape == (4, 9))
     44          # should do upcasting
     45          self.failUnless(mds.samples.dtype == 'float')
     46          # simple samples attrs
     47          self.failUnless((mds.labels == [1] * 4).all())
     48          self.failUnless((mds.chunks == range(4)).all())
     49
     50          # do sample selection across all datasets
     51          mds1 = mds.selectSamples([0,3])
     52          self.failUnless(mds1.samples.shape == (2, 9))
     53          self.failUnless(\
     54              (mds1.samples[0] == [0, 1, 2, 0, 0, 0, 0, 1, 1]).all())
     55          self.failUnless(\
     56              (mds1.samples[1] == [9, 10, 11, 0, 0, 0, 0, 1, 1]).all())
     57
     58          # more tricky feature selection on all datasets
     59          mds2 = mds.selectFeatures([1,4,8])
     60
     61          self.failUnless(\
     62              (mds2.samples == [[ 1, 0, 1],
     63                                [ 4, 0, 1],
     64                                [ 7, 0, 1],
     65                                [10, 0, 1]] ).all())
     66
     67
     68 -    def testMapping(self):
     69          if not externals.exists('nifti'):
     70              return
     71          from mvpa.datasets.nifti import NiftiDataset
     72          eeds = EEPDataset(os.path.join(pymvpa_dataroot, 'eep.bin'), labels=[1,2])
     73          nids = NiftiDataset(os.path.join(pymvpa_dataroot, 'example4d.nii.gz'),
     74                              labels=[1,2])
     75          plainds = Dataset(samples=N.arange(8).reshape((2,4)), labels=[1,2])
     76
     77          datasets = (eeds, plainds, nids)
     78
     79          mds = MetaDataset(datasets)
     80
     81          self.failUnless(mds.nfeatures == N.sum([d.nfeatures for d in datasets]))
     82          self.failUnless(mds.nsamples == 2)
     83
     84          # try reverse mapping
     85          mr = mds.mapReverse(N.arange(mds.nfeatures))
     86
     87          self.failUnless(len(mr) == 3)
     88          self.failUnless(mr[1].shape == (plainds.nfeatures,))
     89
     90
     91 -    def testCombinedMapper(self):
     92          # simple case: two array of different shape combined
     93          m = CombinedMapper([DenseArrayMapper(mask=N.ones((2,3,4))),
     94                              MaskMapper(mask=N.array((1,1)))])
     95
     96          self.failUnless(m.getInSize() == 26)
     97          self.failUnless(m.getOutSize() == 26)
     98
     99          d1 = N.ones((5,2,3,4))
    100          d2_broken = N.ones((6,2)) + 1
    101          d2 = N.ones((5,2)) + 1
    102
    103          # should not work for sample mismatch
    104          self.failUnlessRaises(ValueError, m.forward, (d1, d2_broken))
    105
    106          # check forward mapping (size and identity)
    107          mf = m.forward((d1, d2))
    108          self.failUnless(mf.shape == (5, 26))
    109          self.failUnless((mf[:,:24] == 1).all())
    110          self.failUnless((mf[:,-2:] == 2).all())
    111
    112          # check reverse mapping
    113          self.failUnlessRaises(ValueError, m.reverse, N.arange(12))
    114          mr = m.reverse(N.arange(26) + 1)
    115          self.failUnless(len(mr) == 2)
    116          self.failUnless((mr[0] == N.arange(24).reshape((2,3,4)) + 1).all())
    117          self.failUnless((mr[1] == N.array((25,26))).all())
    118
    119          # check reverse mapping of multiple samples
    120          mr = m.reverse(N.array([N.arange(26) + 1 for i in range(4)]))
    121          self.failUnless(len(mr) == 2)
    122          self.failUnless(
    123              (mr[0] == N.array([N.arange(24).reshape((2,3,4)) + 1
    124                                      for i in range(4)])).all())
    125          self.failUnless(
    126              (mr[1] == N.array([N.array((25,26)) for i in range(4)])).all())
    127
    128
    129          # check dummy train
    130          m.train(Dataset(samples=N.random.rand(10,26), labels=range(10)))
    131          self.failUnlessRaises(ValueError, m.train,
    132              Dataset(samples=N.random.rand(10,25), labels=range(10)))
    133
    134          # check neighbor information
    135          # fail if invalid id
    136          self.failUnlessRaises(ValueError, m.getNeighbor, 26)
    137          # neighbors for last feature of first mapper, ie.
    138          # close in out space but infinite/undefined distance in in-space
    139          self.failUnless([n for n in m.getNeighbor(23, radius=2)]
    140                          == [6, 7, 10, 11, 15, 18, 19, 21, 22, 23])
    141
    142          # check feature selection
    143          m.selectOut((23,25))
    144          self.failUnless(m.getInSize() == 26)
    145          self.failUnless(m.getOutSize() == 2)
    146
    147          # check reverse mapping of truncated mapper
    148          mr = m.reverse(N.array((99,88)))
    149          target1 = N.zeros((2,3,4))
    150          target1[1,2,3] = 99
    151          target2 = N.array((0, 88))
    152          self.failUnless(len(mr) == 2)
    153          self.failUnless((mr[0] == target1).all())
    154          self.failUnless((mr[1] == target2).all())
    155
    156          # check forward mapping
    157          self.failUnless((m.forward((d1, d2))[0] == (1, 2)).all())
    158
    159          # check copying
    160          mc = deepcopy(m)
    161          mc.selectOut([1])
    162          self.failUnless(m.getOutSize() == 2)
    163          self.failUnless(mc.getOutSize() == 1)
    164
    165
    166 -    def testChainMapper(self):
    167          data = N.array([N.arange(24).reshape(3,4,2) + (i * 100)
    168                              for i in range(10)])
    169
    170          startpoints = [ 2, 4, 3, 5 ]
    171          m = ChainMapper([BoxcarMapper(startpoints, 2),
    172                           DenseArrayMapper(mask=N.ones((2, 3, 4, 2)))])
    173          mp = m.forward(data)
    174          # 4 startpoint, with each two samples of shape (3,4,2)
    175          self.failUnless(mp.shape == (4, 48))
    176
    177          self.failUnless(m.reverse(N.arange(48)).shape == (2, 3, 4, 2))
    178
    179          # should behave a DenseArrayMapper alone
    180          self.failUnless((N.array([n for n in m.getNeighbor(24, radius=1.1)])
    181                           == N.array((0, 24, 25, 26, 32))).all())
    182
    183
    184 -    def testEventDataset(self):
    185          # baisc checks
    186          self.failUnlessRaises(DatasetError, EventDataset)
    187
    188          # simple data
    189          samples = N.arange(240).reshape(10, 2, 3, 4)
    190
    191          # copy constructor does not work on non-2D data
    192          self.failUnlessRaises(DatasetError, EventDataset, samples=samples)
    193
    194          # try case without extra features
    195          evs = [Event(onset=2, duration=2, label=1, chunk=2),
    196                 Event(onset=5, duration=1, label=2, chunk=2),
    197                 Event(onset=7, duration=2, label=3, chunk=4)]
    198
    199          ds = EventDataset(samples=samples, events=evs)
    200          self.failUnless(ds.nfeatures == 48)
    201          self.failUnless(ds.nsamples == 3)
    202          self.failUnless((ds.labels == [1,2,3]).all())
    203          self.failUnless((ds.chunks == [2,2,4]).all())
    204          mr = ds.mapReverse(N.arange(48))
    205          self.failUnless((mr == N.arange(48).reshape(2,2,3,4)).all())
    206
    207          # try case with extra features
    208          evs = [Event(onset=2, duration=2, label=1, features=[2,3]),
    209                 Event(onset=5, duration=2, label=1, features=[4,5]),
    210                 Event(onset=7, duration=2, label=1, features=[6,7]),]
    211          ds = EventDataset(samples=samples, events=evs)
    212          # we have 2 additional features
    213          self.failUnless(ds.nfeatures == 50)
    214          self.failUnless(ds.nsamples == 3)
    215          self.failUnless((ds.labels == [1,1,1]).all())
    216          self.failUnless((ds.chunks == [0,1,2]).all())
    217          # now for the long awaited -- map back into two distinct
    218          # feature spaces
    219          mr = ds.mapReverse(N.arange(50))
    220          # we get two sets of feature spaces (samples and extra features)
    221          self.failUnless(len(mr) == 2)
    222          msamples, mxfeat = mr
    223          # the sample side should be identical to the case without extra features
    224          self.failUnless((msamples == N.arange(48).reshape(2,2,3,4)).all())
    225          # the extra features should be flat
    226          self.failUnless((mxfeat == (48,49)).all())
    227
    228          # now take a look at
    229          orig = ds.O
    230          self.failUnless(len(mr) == 2)
    231          osamples, oextra = orig
    232          self.failUnless((oextra == [[2,3],[4,5],[6,7]]).all())
    233          self.failUnless(osamples.shape == samples.shape)
    234          # check that all samples not covered by an event are zero
    235          filt = N.array([True,True,False,False,True,False,False,False,False,True])
    236          self.failUnless(N.sum(osamples[filt]) == 0)
    237          self.failUnless((osamples[N.negative(filt)] > 0).all())
    238
    239 -    def testEventDatasetExtended(self):
    240          if not externals.exists('nifti'):
    241              return
    242          from mvpa.datasets.nifti import ERNiftiDataset
    243          try:
    244              ds = ERNiftiDataset(
    245                  samples=os.path.join(pymvpa_dataroot, 'bold.nii.gz'),
    246                  mask=os.path.join(pymvpa_dataroot, 'mask.nii.gz'),
    247                  events=[Event(onset=1,duration=5,label=1,chunk=1)],
    248                  evconv=True, tr=2.0)
    249          except ValueError, e:
    250              self.fail("Failed to create a simple ERNiftiDataset from a volume"
    251                        " with only 1 slice. Exception was:\n %s" % e)
    252
    253 -def suite():
    254      return unittest.makeSuite(MetaDatasetTests)
    255
    256
    257  if __name__ == '__main__':
    258      import runner
    259