[pymvpa] Pkg-ExpPsy-PyMVPA Digest, Vol 18, Issue 10

Yaroslav Halchenko debian at onerussian.com
Fri Aug 21 20:27:28 UTC 2009

On Fri, 21 Aug 2009, Johan Carlin wrote:

just a quick hint:
>     roi_ds = ds.copy()
>     roi_ds = roi_ds.selectFeatures(feats)
imho there is no need for .copy() since selectFeatures creates a new
dataset anyways... or am I wrong? ;)

> Which seems similar to what you're suggesting.
seems to be ;)

> The problem with doing
> this on masked data is that you get an error whenever the center
> coordinate is outside the mask (even if the sphere contains other
> in-mask voxels). 
rright -- it seems we did not foresee such usecase, or just we were
wrong in our assumptions of its usefulness ;)

> To get around this, I make the ROI based on unmasked
> data, and then I apply the mask to the ROI dataset.
makes sense... I might suggest alternative solution (not sure if we
should implement a helper for it within pymvpa).

So, if you load a single full (or ROI-surround mask, or just
full-brain) volume (lets load it into dataset ds_full), and then
you load your ROI dataset within ds_roi, then for voxel  which is
outside of ROI but has features within sphere in the ROI you could use
ds_full.mapper to figure out 3D coordinates for the neighbors, and then
just select the ones which are valid for ds_roi. Here is  a snippet
which I've added to unittests (resides under

        ids_out = []
        for id_in in ds_full.mapper.getNeighborIn( (12, 20, 37), radius=20):
            except ValueError:

so, at the end in ids_out you got list of feature ids within ds_roi which
are within 20mm of that voxel... may be there is even better way -- but
don't have it in mind atm ;)

is that smth like what you need? ;)

> >>     lmap = dict(zip(ds.labels_map.values(),ds.labels_map.keys()))
> > whenever creating a new dataset? (may be I got confused...)
> If you just put in the ds.labels_map as it is, you get something like this:
> m_ds = MaskedDataset(samples=ds.samples_original, labels=ds.L,
> chunks=ds.C, labels_map=ds.labels_map)

> ValueError: Provided labels_map {'212': 5, '211': 4, '121': 2, '122':
> 3, '111': 0, '112': 1, '222': 7, '221': 6} is insufficient to map all
> the labels. Mapping for label 5 is missing

> The 3-digit stringed values are my original labels. So it looks like
> the ds.labels_map is stored with key=original label, value=mapped
> label, but the opposite structure is needed when definining a new
> dataset.
I see it now ;) Sorry for too much "magic" behind  labels_map.

Since it had evolved over time, docstring was not reflecting
actual behavior I guess, so I adjusted docstring to be:

            Map original labels into numeric labels.  If True, the
            mapping is computed if labels are literal.  If is False,
            no mapping is computed. If dict instance -- provided
            mapping is verified and applied.

So, what was happening -- since your labels are numeric already and you
provided original labels_map as dict, it tried to remap already numeric labels
using mapping of literal to numeric. Obviously it failed ;)  With your
'reverse' mapping it has done somewhat more evil thing, mapped numerical labels
back into literal (which is not strictly forbidden, but I guess worth a
warning, I've added it -- ie, if now resultant labels are literal).

After such mapping, some classifiers (which remap labels internally anyways,
such as SMLR, or just don't care much about type of labels, such as kNN I
believe) might still perform as fine, but YMMV ;)

back to your issue, to at least document a 'workaround' whenever labels_map
should not be provided to constructor but rather assigned later on, I've
added another piece of documentation to labels_map keyword argument:

 If you want to have labels_map just be present given already
 numeric labels, just assign labels_map dictionary to existing dataset

so, just define m_ds without providing labels_map argument, and then
assign it afterwards:

m_ds.labels_map = ds.labels_map

> > in your code instead of MaskedDataset you could use NiftiDataset where
> > samples... but before getting in details lets first figure out if above snippet
> > was what you were looking for
> That sounds very useful, please tell me more. :)

Well... I guess with the above getIn/getOut magic you could simply work on
NiftiDatasets as is, without reverting to MaskedDataset ;)

in general, if your original space of MaskedDataset is actually the same
as NiftiDataset but used mask was different, you could simply
construct a new NiftiImage using header information only from existing
NiftiDataset... smth like

NiftiImage(maskeddataset.O, header=niftidataset.niftihdr).save('bugi.nii.gz')

=------------------------------   /v\  ----------------------------=
Keep in touch                    // \\     (yoh@|www.)onerussian.com
Yaroslav Halchenko              /(   )\               ICQ#: 60653192
                   Linux User    ^^-^^    [175555]

More information about the Pkg-ExpPsy-PyMVPA mailing list