Source code for hypertools.tools.align
#!/usr/bin/env python
"""
Implements the "hyperalignment" algorithm described by the
following paper:
Haxby JV, Guntupalli JS, Connolly AC, Halchenko YO, Conroy BR, Gobbini
MI, Hanke M, and Ramadge PJ (2011) A common, high-dimensional model of
the representational space in human ventral temporal cortex. Neuron 72,
404 -- 416.
INPUTS:
-numpy array(s)
-list of numpy arrays
OUTPUTS:
-numpy array
-list of aligned numpy arrays
"""
##PACKAGES##
from __future__ import division
from builtins import range
from .._externals.srm import SRM
from .procrustes import procrustes
import numpy as np
from .._shared.helpers import format_data
from warnings import warn
##MAIN FUNCTION##
[docs]def align(data, method='hyper'):
"""
Aligns a list of arrays
This function takes a list of high dimensional arrays and 'hyperaligns' them
to a 'common' space, or coordinate system following the approach outlined by
Haxby et al, 2011. Hyperalignment uses linear transformations (rotation,
reflection, translation, scaling) to register a group of arrays to a common
space. This can be useful when two or more datasets describe an identical
or similar system, but may not be in same coordinate system. For example,
consider the example of fMRI recordings (voxels by time) from the visual
cortex of a group of subjects watching the same movie: The brain responses
should be highly similar, but the coordinates may not be aligned.
Haxby JV, Guntupalli JS, Connolly AC, Halchenko YO, Conroy BR, Gobbini
MI, Hanke M, and Ramadge PJ (2011) A common, high-dimensional model of
the representational space in human ventral temporal cortex. Neuron 72,
404 -- 416.
Parameters
----------
data : list
A list of Numpy arrays or Pandas Dataframes
method : str
Either 'hyper' or 'SRM'. If 'hyper' (default),
Returns
----------
aligned : list
An aligned list of numpy arrays
"""
data = format_data(data)
if data[0].shape[1]>=data[0].shape[0]:
warn('The number of features exceeds number of samples. This can lead \
to overfitting. We recommend reducing the dimensionality to be \
less than the number of samples prior to hyperalignment.')
if method=='hyper':
##STEP 0: STANDARDIZE SIZE AND SHAPE##
sizes_0 = [x.shape[0] for x in data]
sizes_1 = [x.shape[1] for x in data]
#find the smallest number of rows
R = min(sizes_0)
C = max([3, max(sizes_1)])
m = [np.empty((R,C), dtype=np.ndarray)] * len(data)
for idx,x in enumerate(data):
y = x[0:R,:]
missing = C - y.shape[1]
add = np.zeros((y.shape[0], missing))
y = np.append(y, add, axis=1)
m[idx]=y
##STEP 1: TEMPLATE##
for x in range(0, len(m)):
if x==0:
template = np.copy(m[x])
else:
next = procrustes(m[x], template / (x + 1))
template += next
template /= len(m)
##STEP 2: NEW COMMON TEMPLATE##
#align each subj to the template from STEP 1
template2 = np.zeros(template.shape)
for x in range(0, len(m)):
next = procrustes(m[x], template)
template2 += next
template2 /= len(m)
#STEP 3 (below): ALIGN TO NEW TEMPLATE
aligned = [np.zeros(template2.shape)] * len(m)
for x in range(0, len(m)):
next = procrustes(m[x], template2)
aligned[x] = next
return aligned
elif method=='SRM':
data = [i.T for i in data]
srm = SRM(features=np.min([i.shape[0] for i in data]))
fit = srm.fit(data)
return [i.T for i in srm.transform(data)]