コード例 #1
0
ファイル: filtertools.py プロジェクト: dongsoolee2/pyret
def linear_response(filt, stim, nsamples_after=0):
    """
    Compute the response of a linear filter to a stimulus.

    Parameters
    ----------
    filt : array_like
        The linear filter whose response is to be computed. The array should
        have shape ``(t, ...)``, where ``t`` is the number of time points in
        the filter and the ellipsis indicates any remaining spatial dimenions.
        The number of dimensions and the sizes of the spatial dimensions
        must match that of ``stim``.

    stim : array_like
        The stimulus to which the predicted response is computed. The array
        should have shape ``(T,...)``, where ``T`` is the number of time points
        in the stimulus and the ellipsis indicates any remaining spatial
        dimensions. The number of dimensions and the sizes of the spatial
        dimenions must match that of ``filt``.

    nsamples_after : int, optional
        The number of acausal points in the filter. Defaults to 0.

    Returns
    -------
    pred : array_like
        The predicted linear response, of shape ``(t,)``.

    Raises
    ------
    ValueError : If the number of dimensions of ``stim`` and ``filt`` do not
        match, or if the spatial dimensions differ.

    Notes
    -----
    Note that the first parameter is a *linear filter*. The values returned by
    ``filtertools.sta`` and ``filtertools.revcorr`` are proportional to the
    time-reverse of the linear filter, so to use those values in this function,
    they must be flipped along the first dimension.

    Both ``filtertools.sta`` and ``filtertools.revcorr`` can estimate "acausal"
    components, such as points in the stimulus occuring *after* a spike. The
    value passed as parameter ``nsamples_after`` must match that value used
    when calling ``filtertools.sta`` or ``filtertools.revcorr``.

    """
    if (filt.ndim != stim.ndim) or (filt.shape[1:] != stim.shape[1:]):
        raise ValueError("The filter and stimulus must have the same "
                         "number of dimensions and match in size along "
                         "spatial dimensions")
    if (nsamples_after >= filt.shape[0]):
        raise ValueError("Cannot compute the response of a "
                "filter with no causal points.")
    padded = np.concatenate((
            np.zeros((filt.shape[0] - nsamples_after - 1,) + stim.shape[1:]),
            stim, np.zeros((nsamples_after,) + stim.shape[1:])), axis=0)
    slices = np.fliplr(slicestim(padded, 
            filt.shape[0] - nsamples_after, nsamples_after))
    return np.einsum('tx,x->t', flat2d(slices), filt.ravel())
コード例 #2
0
ファイル: filtertools.py プロジェクト: leelabcnbc/pyret
def linear_response(filt, stim, nsamples_after=0):
    """
    Compute the response of a linear filter to a stimulus.

    Parameters
    ----------
    filt : array_like
        The linear filter whose response is to be computed. The array should
        have shape ``(t, ...)``, where ``t`` is the number of time points in the
        filter and the ellipsis indicates any remaining spatial dimenions.
        The number of dimensions and the sizes of the spatial dimensions
        must match that of ``stim``.

    stim : array_like
        The stimulus to which the predicted response is computed. The array
        should have shape (T,...), where ``T`` is the number of time points
        in the stimulus and the ellipsis indicates any remaining spatial
        dimensions. The number of dimensions and the sizes of the spatial
        dimenions must match that of ``filt``.

    nsamples_after : int, optional
        The number of acausal points in the filter. Defaults to 0.

    Returns
    -------
    pred : array_like
        The predicted linear response. The shape is ``(T - t + 1,)`` where
        ``T`` is the number of time points in the stimulus, and ``t`` is
        the number of time points in the filter. This is the valid portion
        of the convolution between the stimulus and filter.

    Raises
    ------
    ValueError : If the number of dimensions of ``stim`` and ``filt`` do not
        match, or if the spatial dimensions differ.

    Notes
    -----
    Both ``filtertools.sta`` and ``filtertools.revcorr`` can estimate "acausal"
    components, such as points in the stimulus occuring *after* a spike. The
    value passed as parameter ``nsamples_after`` must match that value used
    when calling ``filtertools.sta`` or ``filtertools.revcorr``.

    """
    if (filt.ndim != stim.ndim) or (filt.shape[1:] != stim.shape[1:]):
        raise ValueError("The filter and stimulus must have the same " +
                         "number of dimensions and match in size along spatial dimensions")

    slices = slicestim(stim, filt.shape[0] - nsamples_after, nsamples_after)
    return np.einsum('tx,x->t', flat2d(slices), filt.ravel())
コード例 #3
0
ファイル: filtertools.py プロジェクト: Sandy4321/pyret
def revcorr(response, stimulus, filter_length):
    """
    Compute the reverse-correlation between a stimulus and a response.

    This returns the best-fitting linear filter which predicts the given
    response from the stimulus. It is analogous to the spike-triggered
    average for continuous variables. ``response`` is most often a membrane
    potential.

    Parameters
    ----------
    response : array_like
        A continuous output response correlated with the stimulus. Must
        be one-dimensional.

    stimulus : array_like
        A input stimulus correlated with the ``response``. Must be of shape
        ``(t, ...)``, where ``t`` is the time and ``...`` indicates any spatial dimensions.

    filter_length : int
        The length of the returned filter, in samples of the ``stimulus`` and
        ``response`` arrays.

    Returns
    -------
    filt : array_like
        An array of shape ``(filter_length, ...)`` containing the best-fitting
        linear filter which predicts the response from the stimulus. The ellipses
        indicates spatial dimensions of the filter.

    Raises
    ------
    ValueError : If the ``stimulus`` and ``response`` arrays are of different shapes.

    Notes
    -----
    The ``response`` and ``stimulus`` arrays must share the same sampling
    rate. As the stimulus often has a lower sampling rate, one can use
    ``stimulustools.upsamplestim`` to upsample it.
    """
    if response.ndim > 1:
        raise ValueError("The `response` must be 1-dimensional")
    if response.size != (stimulus.shape[0] - filter_length + 1):
        msg = "`stimulus` must have {:#d} time points (`response.size` + `filter_length`)"
        raise ValueError(msg.format(response.size + filter_length + 1))

    slices = slicestim(stimulus, filter_length)
    recovered = np.einsum('tx,t->x', flat2d(slices), response)
    return recovered.reshape(slices.shape[1:])
コード例 #4
0
ファイル: filtertools.py プロジェクト: Sandy4321/pyret
def linear_prediction(filt, stim):
    """
    Compute the predicted linear response of a receptive field to a stimulus.

    Parameters
    ----------
    filt : array_like
        The linear filter whose response is to be computed. The array should
        have shape ``(t, ...)``, where ``t`` is the number of time points in the
        filter and the ellipsis indicates any remaining spatial dimenions.
        The number of dimensions and the sizes of the spatial dimensions
        must match that of ``stim``.

    stim : array_like
        The stimulus to which the predicted response is computed. The array
        should have shape (T,...), where ``T`` is the number of time points
        in the stimulus and the ellipsis indicates any remaining spatial
        dimensions. The number of dimensions and the sizes of the spatial
        dimenions must match that of ``filt``.

    Returns
    -------
    pred : array_like
        The predicted linear response. The shape is ``(T - t + 1,)`` where
        ``T`` is the number of time points in the stimulus, and ``t`` is 
        the number of time points in the filter. This is the valid portion
        of the convolution between the stimulus and filter

    Raises
    ------
    ValueError : If the number of dimensions of ``stim`` and ``filt`` do not
        match, or if the spatial dimensions differ.
    """
    if (filt.ndim != stim.ndim) or (filt.shape[1:] != stim.shape[1:]):
        raise ValueError(
            "The filter and stimulus must have the same " +
            "number of dimensions and match in size along spatial dimensions")

    slices = slicestim(stim, filt.shape[0])
    return np.einsum('tx,x->t', flat2d(slices), filt.ravel())
コード例 #5
0
def cov(stimulus, history, nsamples=None, verbose=False):
    """
    Computes a stimulus covariance matrix

    .. warning:: This is computationally expensive for large stimuli

    Parameters
    ----------
    stimulus : array_like
        The spatiotemporal or temporal stimulus to slices. Should have shape
        (t, ...), where the ellipses indicate any spatial dimensions.

    history : int
        Integer number of time points to keep in each slice.

    Returns
    ------
    stim_cov : array_like
        Covariance matrix
    """
    stim = slicestim(stimulus, history)
    return np.cov(flat2d(stim).T)
コード例 #6
0
ファイル: test_utils.py プロジェクト: leelabcnbc/pyret
def test_flat2d():
    x = np.random.randn(10, 2, 3, 4)
    x_ = x.reshape(x.shape[0], -1).copy()
    assert np.allclose(x_, flat2d(x))
コード例 #7
0
ファイル: filtertools.py プロジェクト: dongsoolee2/pyret
def revcorr(stimulus, response, nsamples_before, nsamples_after=0):
    """
    Compute the reverse-correlation between a stimulus and a response.

    Parameters
    ----------
    stimulus : array_like
        A input stimulus correlated with the ``response``. Must be of shape
        ``(t, ...)``, where ``t`` is the time and ``...`` indicates any spatial
        dimensions.

    response : array_like
        A continuous output response correlated with ``stimulus``. Must
        be one-dimensional, of size ``t``, the same size as ``stimulus``
        along the first axis. Note that the first ``history`` points of
        the response are ignored, where ``history = nsamples_before +
        nsamples_after``, in order to only return the portion of the
        correlation during which the ``stimulus`` and ``response``
        completely overlap.

    nsamples_before : int
        The maximum negative lag for the correlation between stimulus and
        response, in samples.

    nsamples_after : int, optional
        The maximum positive lag for the correlation between stimulus and
        response, in samples. Defaults to 0.

    Returns
    -------
    rc : array_like
        An array of shape ``(nsamples_before + nsamples_after, ...)``
        containing the best-fitting linear filter which predicts the response
        from the stimulus. The ellipses indicates spatial dimensions of the
        filter.

    lags : array_like
        An array of shape ``(nsamples_before + nsamples_after,)``, which gives
        the lags, in samples, between ``stimulus`` and ``response`` for the
        correlation returned in ``rc``. This can be converted to an axis of time
        (like that returned from ``filtertools.sta``) by multiplying by the 
        sampling period.

    Raises
    ------
    ValueError : If the ``stimulus`` and ``response`` arrays do not match in
    size along the first dimension.

    Notes
    -----
    The ``response`` and ``stimulus`` arrays must share the same sampling
    rate. As the stimulus often has a lower sampling rate, one can use
    ``stimulustools.upsample`` to upsample it.

    Reverse correlation is a method analogous to spike-triggered averaging for
    continuous response variables, such as a membrane voltage recording. It
    estimates the stimulus feature that most strongly correlates with the
    response on average.

    It is the time-reverse of the standard cross-correlation function, and is defined
    as:

    .. math::
        c[-k] = \\sum_{n} s[n] r[n - k]

    The parameter ``k`` is the lag between the two signals in samples. The range
    of lags computed in this method are determined by ``nsamples_before`` and
    ``nsamples_after``.

    Note that, as with ``filtertools.sta``, the values (samples) in the ``lags``
    array increase with increasing array index. This means that time is moving
    forward with increasing array index.

    Also note that this method assumes an uncorrelated stimulus. If the
    stimulus is correlated, those will bias the estimated reverse correlation.

    """
    history = nsamples_before + nsamples_after
    if response.ndim > 1:
        raise ValueError("The `response` must be 1-dimensional")
    if response.size != stimulus.shape[0]:
        raise ValueError('`stimulus` and `response` must match in ' +
                'size along the first axis')
    slices = slicestim(stimulus, nsamples_before, nsamples_after)
    recovered = np.einsum('tx,t->x', flat2d(slices),
            response[history - 1:]).reshape(slices.shape[1:])
    lags = np.arange(-nsamples_before + 1, nsamples_after + 1)
    return recovered, lags
コード例 #8
0
ファイル: filtertools.py プロジェクト: dongsoolee2/pyret
def lowranksta(sta_orig, k=10):
    """
    Constructs a rank-k approximation to the given spatiotemporal STA.
    This is useful for estimating a spatial and temporal kernel for an
    STA or for denoising.

    Parameters
    ----------
    sta_orig : array_like
        3D STA to be separated, shaped as ``(time, space, space)``.

    k : int
        Number of components to keep (rank of the reduced STA).

    Returns
    -------
    sk : array_like
        The rank-k estimate of the original STA.

    u : array_like
        The top ``k`` temporal components (each column is a component).

    s : array_like
        The top ``k`` singular values.

    v : array_like
        The top ``k`` spatial components (each row is a component). These
        components have all spatial dimensions collapsed to one.

    Notes
    -----
    This method requires that the STA be 3D. To decompose a STA into a
    temporal and 1-dimensional spatial component, simply promote the STA
    to 3D before calling this method.

    Despite the name this method accepts both an STA or a linear filter.
    The components estimated for one will be flipped versions of the other.
    """

    # work with a copy of the STA (prevents corrupting the input)
    f = sta_orig.copy() - sta_orig.mean()

    # Compute the SVD of the full STA
    assert f.ndim >= 2, "STA must be at least 2-D"
    u, s, v = np.linalg.svd(flat2d(f), full_matrices=False)

    # Keep the top k components
    k = np.min([k, s.size])
    u = u[:, :k]
    s = s[:k]
    v = v[:k, :]

    # Compute the rank-k STA
    sk = (u.dot(np.diag(s).dot(v))).reshape(f.shape)

    # Ensure that the computed STA components have the correct sign.
    # The full STA should have positive projection onto first temporal
    # component of the low-rank STA.
    sign = np.sign(np.tensordot(u[:, 0], f, axes=1).sum())
    u *= sign
    v *= sign

    # Return the rank-k approximate STA, and the SVD components
    return sk, u, s, v