Esempio n. 1
0
    def test_instantaneous_rate_regression_245(self):
        # This test makes sure that the correct kernel width is chosen when
        # selecting 'auto' as kernel
        spiketrain = neo.SpikeTrain(
            range(1, 30) * pq.ms, t_start=0*pq.ms, t_stop=30*pq.ms)

        # This is the correct procedure to attain the kernel: first, the result
        # of sskernel retrieves the kernel bandwidth of an optimal Gaussian
        # kernel in terms of its standard deviation sigma, then uses this value
        # directly in the function for creating the Gaussian kernel
        kernel_width_sigma = es.sskernel(
            spiketrain.magnitude, tin=None, bootstrap=False)['optw']
        kernel = kernels.GaussianKernel(kernel_width_sigma * spiketrain.units)
        result_target = es.instantaneous_rate(
            spiketrain, 10*pq.ms, kernel=kernel)

        # Here, we check if the 'auto' argument leads to the same operation. In
        # the regression, it was incorrectly assumed that the sskernel()
        # function returns the actual bandwidth of the kernel, which is defined
        # as approximately bandwidth = sigma * 5.5 = sigma * (2 * 2.75).
        # factor 2.0 connects kernel width with its half width,
        # factor 2.7 connects half width of Gaussian distribution with
        #            99% probability mass with its standard deviation.
        result_automatic = es.instantaneous_rate(
            spiketrain, 10*pq.ms, kernel='auto')

        assert_array_almost_equal(result_target, result_automatic)
Esempio n. 2
0
 def optimal_kernel(st):
     width_sigma = None
     if len(st) > 0:
         width_sigma = optimal_kernel_bandwidth(st.magnitude,
                                                times=None,
                                                bootstrap=False)['optw']
     if width_sigma is None:
         raise ValueError("Unable to calculate optimal kernel width for "
                          "instantaneous rate from input data.")
     return kernels.GaussianKernel(width_sigma * st.units)
Esempio n. 3
0
    def test_gaussian(self):
        def evaluate_old(t):
            t_units = t.units
            t = t.magnitude
            sigma = kernel.sigma.rescale(t_units).magnitude
            kernel_pdf = (1.0 / (math.sqrt(2.0 * math.pi) * sigma)) * np.exp(
                -0.5 * (t / sigma) ** 2)
            kernel_pdf = pq.Quantity(kernel_pdf, units=1 / t_units)
            return kernel_pdf

        for invert in (False, True):
            kernel = kernels.GaussianKernel(self.sigma, invert=invert)
            assert_array_almost_equal(kernel(self.time_input),
                                      evaluate_old(self.time_input))
Esempio n. 4
0
 def test_instantaneous_rate_grows_with_sampling_period(self):
     np.random.seed(0)
     rate_expected = 10 * pq.Hz
     spiketrain = homogeneous_poisson_process(rate=rate_expected,
                                              t_stop=10 * pq.s)
     kernel = kernels.GaussianKernel(sigma=100 * pq.ms)
     rates_mean = []
     for sampling_period in np.linspace(1, 1000, num=10) * pq.ms:
         with self.subTest(sampling_period=sampling_period):
             rate = statistics.instantaneous_rate(
                 spiketrain, sampling_period=sampling_period, kernel=kernel)
             rates_mean.append(rate.mean())
     # rate means are greater or equal the expected rate
     assert_array_less(rate_expected, rates_mean)
     # check sorted
     self.assertTrue(np.all(rates_mean[:-1] < rates_mean[1:]))
Esempio n. 5
0
    def convert_one_population_to_rates(self, recordings_index, trial_index,
                                        brain_area):
        path = self.all_data_path + '/' + self.selected_recordings[
            recordings_index]
        trials = np.load(path + '/' + 'trials.intervals.npy')
        spike_times_lst = self.get_spikes_of_one_population(
            recordings_index, brain_area)

        rates_lst = []
        spk_tr_lst = []
        for spk_tms_one_neuron in spike_times_lst:
            spks_range = np.bitwise_and(
                spk_tms_one_neuron >= trials[trial_index][0],
                spk_tms_one_neuron <= trials[trial_index][1])
            subset = spk_tms_one_neuron[spks_range]

            #Create elephant SpikeTrain object
            spk_tr = neo.SpikeTrain(subset * pq.s,
                                    t_start=trials[trial_index][0] * pq.s,
                                    t_stop=trials[trial_index][1] * pq.s)
            #plt.eventplot(spk_tr)
            #plt.show()
            kernel = kernels.GaussianKernel(sigma=0.1 * pq.s, invert=True)
            #sampling_rate the same as behavior
            r = instantaneous_rate(spk_tr,
                                   t_start=trials[trial_index][0] * pq.s,
                                   t_stop=trials[trial_index][1] * pq.s,
                                   sampling_period=0.02524578 * pq.s,
                                   kernel=kernel)  #cutoff=5.0)
            binned_spk_tr = conv.BinnedSpikeTrain(
                spk_tr,
                binsize=0.02524578 * pq.s,
                t_start=trials[trial_index][0] * pq.s)
            binned_spk_tr = binned_spk_tr.to_array()
            spk_tr_lst.append(binned_spk_tr)
            rates_lst.append(r.flatten())

        rates_lst = np.array(rates_lst)
        spk_tr_lst = np.array(spk_tr_lst)
        print(spk_tr_lst)
        #print(rates_lst.shape)
        return rates_lst, spk_tr_lst
Esempio n. 6
0
def correlate_to_stim(sp_neo, var, kernel_sigmas, mode='g', plot_tgl=False):
    '''
    Calculate the correlation between a spike train and an analog signal.
    Smooths the observed spike train with a user defined kernel in order to get a continuous rate estimate

    :param sp_neo:          a neo spiketrain
    :param var:             a 1D numpy array, neo analog signal, or quantity to correlate the spike rate with
    :param kernel_sigmas:   list or numpy array of sigma values defining the kernel to smooth the spike train
    :param mode:            type of kernel to smooth the spike train with ['g': gaussian,'b'/'r': box or rectangular]

    :return corr_:          A numpy array of correlation values between the spiketrain and desired variable.
                                Each entry corresponds to a different smoothing parameter as indicated in 'kernel_sigmas'
    :return kernel_sigmas:  The numpy array of kernel sigma values used
    '''

    # map var to a numpy array if needed
    if type(var) == neo.core.AnalogSignal or type(
            var) == quantities.quantity.Quantity:
        var = var.magnitude

    # init correlation output
    corr_ = np.empty(kernel_sigmas.shape[0])

    # loop over all sigma values
    for ii, sigma in enumerate(kernel_sigmas):
        # get the appropriate kernel with corresponding sigma
        if mode == 'b' or mode == 'r':
            kernel = kernels.RectangularKernel(sigma=sigma * pq.ms)
        elif mode == 'g':
            kernel = kernels.GaussianKernel(sigma=sigma * pq.ms)
        else:
            raise ValueError('Kernel mode not defined')

        r = instantaneous_rate(sp_neo, sampling_period=pq.ms, kernel=kernel)
        corr_[ii] = np.corrcoef(r.squeeze(), var)[0, 1]

    if plot_tgl:
        plt.plot(kernel_sigmas, corr_, 'k')

    return (corr_, kernel_sigmas)
Esempio n. 7
0
    def plot_one_trial_one_neuron(self, recordings_index, trial_index,
                                  neuron_index):
        '''
        Plots spikes, rates and behavior over a specified trial and neuron.

        '''
        path = self.all_data_path + '/' + self.selected_recordings[
            recordings_index]
        #Neural data
        neuron_inds = np.load(path + '/' + 'spikes.clusters.npy')
        spk_tms = np.load(path + '/' + 'spikes.times.npy')
        trials = np.load(path + '/' + 'trials.intervals.npy')
        #Behavioral data
        mot_timestamps = np.load(path + '/' + 'face.timestamps.npy')
        mot_energy = np.load(path + '/' + 'face.motionEnergy.npy')

        spk_ids = np.where(neuron_inds == neuron_index)
        spk_tms_one_neuron = spk_tms[spk_ids]

        #Select spikes in the trial for the neuron that we care about
        spks_range = np.bitwise_and(
            spk_tms_one_neuron >= trials[trial_index][0],
            spk_tms_one_neuron <= trials[trial_index][1])
        subset = spk_tms_one_neuron[spks_range]

        #Create elephant SpikeTrain object
        spk_tr = neo.SpikeTrain(subset * pq.s,
                                t_start=trials[trial_index][0] * pq.s,
                                t_stop=trials[trial_index][1] * pq.s)
        #print(spk_tr)
        print((trials[trial_index][1] - trials[trial_index][0]))

        #Plot spike train
        plt.eventplot(spk_tr)
        plt.title('Spike train for one trial. trial ' + str(trial_index) +
                  ' ' + ', neuron: ' + str(neuron_index))
        plt.show()

        #Plot instantaneous firing rate
        kernel = kernels.GaussianKernel(sigma=0.1 * pq.s, invert=True)
        #sampling_rate the same as behavior
        r = instantaneous_rate(spk_tr,
                               t_start=trials[trial_index][0] * pq.s,
                               t_stop=trials[trial_index][1] * pq.s,
                               sampling_period=0.02524578 * pq.s,
                               kernel=kernel)  #cutoff=5.0)
        plt.plot(r)
        plt.title('Instantaneous rate for one trial')
        plt.show()
        print('r shape', r.shape)

        #Plot behavior motion energy
        beh_range = np.bitwise_and(
            mot_timestamps[:, 1] >= trials[trial_index][0],
            mot_timestamps[:, 1] <= trials[trial_index][1])
        #print(np.where(beh_range==True))
        #print(mot_timestamps[beh_range])
        beh_subset = mot_energy[beh_range]
        plt.plot(mot_timestamps[beh_range][:, 1].flatten(), beh_subset)
        plt.title('Motion energy in trial')
        plt.show()
        print('beh shp', beh_subset.shape)

        rate = np.array(r).flatten()
        beh_subset_aligned = self.align_rate_and_behavior(beh_subset,
                                                          rate).flatten()
        print('Correlation coefficient between rate and behavior: ' +
              str(np.corrcoef(beh_subset_aligned, rate)[0, 1]))
Esempio n. 8
0
def instantaneous_rate(spiketrain,
                       sampling_period,
                       kernel='auto',
                       cutoff=5.0,
                       t_start=None,
                       t_stop=None,
                       trim=False):
    """
    Estimates instantaneous firing rate by kernel convolution.

    Parameters
    -----------
    spiketrain : 'neo.SpikeTrain'
        Neo object that contains spike times, the unit of the time stamps
        and t_start and t_stop of the spike train.
    sampling_period : Time Quantity
        Time stamp resolution of the spike times. The same resolution will
        be assumed for the kernel
    kernel : string 'auto' or callable object of :class:`Kernel` from module
        'kernels.py'. Currently implemented kernel forms are rectangular,
        triangular, epanechnikovlike, gaussian, laplacian, exponential,
        and alpha function.
        Example: kernel = kernels.RectangularKernel(sigma=10*ms, invert=False)
        The kernel is used for convolution with the spike train and its
        standard deviation determines the time resolution of the instantaneous
        rate estimation.
        Default: 'auto'. In this case, the optimized kernel width for the 
        rate estimation is calculated according to [1] and with this width
        a gaussian kernel is constructed. Automatized calculation of the 
        kernel width is not available for other than gaussian kernel shapes.
    cutoff : float
        This factor determines the cutoff of the probability distribution of
        the kernel, i.e., the considered width of the kernel in terms of 
        multiples of the standard deviation sigma.
        Default: 5.0
    t_start : Time Quantity (optional)
        Start time of the interval used to compute the firing rate. If None
        assumed equal to spiketrain.t_start
        Default: None
    t_stop : Time Quantity (optional)
        End time of the interval used to compute the firing rate (included).
        If None assumed equal to spiketrain.t_stop
        Default: None
    trim : bool
        if False, the output of the Fast Fourier Transformation being a longer
        vector than the input vector by the size of the kernel is reduced back
        to the original size of the considered time interval of the spiketrain
        using the median of the kernel.
        if True, only the region of the convolved signal is returned, where
        there is complete overlap between kernel and spike train. This is
        achieved by reducing the length of the output of the Fast Fourier
        Transformation by a total of two times the size of the kernel, and
        t_start and t_stop are adjusted.
        Default: False

    Returns
    -------
    rate : neo.AnalogSignal
        Contains the rate estimation in unit hertz (Hz).
        Has a property 'rate.times' which contains the time axis of the rate
        estimate. The unit of this property is the same as the resolution that
        is given via the argument 'sampling_period' to the function.

    Raises
    ------
    TypeError:
        If `spiketrain` is not an instance of :class:`SpikeTrain` of Neo.
        If `sampling_period` is not a time quantity.
        If `kernel` is neither instance of :class:`Kernel` or string 'auto'.
        If `cutoff` is neither float nor int.
        If `t_start` and `t_stop` are neither None nor a time quantity.
        If `trim` is not bool.

    ValueError:
        If `sampling_period` is smaller than zero.

    Example
    --------
    kernel = kernels.AlphaKernel(sigma = 0.05*s, invert = True)
    rate = instantaneous_rate(spiketrain, sampling_period = 2*ms, kernel)

    References
    ----------
    ..[1] H. Shimazaki, S. Shinomoto, J Comput Neurosci (2010) 29:171–182.

    """
    # Checks of input variables:
    if not isinstance(spiketrain, SpikeTrain):
        raise TypeError(
            "spiketrain must be instance of :class:`SpikeTrain` of Neo!\n"
            "    Found: %s, value %s" % (type(spiketrain), str(spiketrain)))

    if not (isinstance(sampling_period, pq.Quantity)
            and sampling_period.dimensionality.simplified == pq.Quantity(
                1, "s").dimensionality):
        raise TypeError("The sampling period must be a time quantity!\n"
                        "    Found: %s, value %s" %
                        (type(sampling_period), str(sampling_period)))

    if sampling_period.magnitude < 0:
        raise ValueError("The sampling period must be larger than zero.")

    if kernel == 'auto':
        kernel_width = sskernel(spiketrain.magnitude, tin=None,
                                bootstrap=True)['optw']
        unit = spiketrain.units
        sigma = 1 / (2.0 * 2.7) * kernel_width * unit
        # factor 2.0 connects kernel width with its half width,
        # factor 2.7 connects half width of Gaussian distribution with
        #             99% probability mass with its standard deviation.
        kernel = kernels.GaussianKernel(sigma)
    elif not isinstance(kernel, kernels.Kernel):
        raise TypeError("kernel must be either instance of :class:`Kernel` "
                        "or the string 'auto'!\n"
                        "    Found: %s, value %s" %
                        (type(kernel), str(kernel)))

    if not (isinstance(cutoff, float) or isinstance(cutoff, int)):
        raise TypeError("cutoff must be float or integer!")

    if not (t_start is None or (isinstance(t_start, pq.Quantity)
                                and t_start.dimensionality.simplified
                                == pq.Quantity(1, "s").dimensionality)):
        raise TypeError("t_start must be a time quantity!")

    if not (t_stop is None or (isinstance(t_stop, pq.Quantity)
                               and t_stop.dimensionality.simplified
                               == pq.Quantity(1, "s").dimensionality)):
        raise TypeError("t_stop must be a time quantity!")

    if not (isinstance(trim, bool)):
        raise TypeError("trim must be bool!")

    # main function:
    units = pq.CompoundUnit("%s*s" %
                            str(sampling_period.rescale('s').magnitude))
    spiketrain = spiketrain.rescale(units)
    if t_start is None:
        t_start = spiketrain.t_start
    else:
        t_start = t_start.rescale(spiketrain.units)

    if t_stop is None:
        t_stop = spiketrain.t_stop
    else:
        t_stop = t_stop.rescale(spiketrain.units)

    time_vector = np.zeros(int((t_stop - t_start)) + 1)

    spikes_slice = spiketrain.time_slice(t_start, t_stop) \
        if len(spiketrain) else np.array([])

    for spike in spikes_slice:
        index = int((spike - t_start))
        time_vector[index] += 1

    if cutoff < kernel.min_cutoff:
        cutoff = kernel.min_cutoff
        warnings.warn("The width of the kernel was adjusted to a minimally "
                      "allowed width.")

    t_arr = np.arange(
        -cutoff * kernel.sigma.rescale(units).magnitude,
        cutoff * kernel.sigma.rescale(units).magnitude +
        sampling_period.rescale(units).magnitude,
        sampling_period.rescale(units).magnitude) * units

    r = scipy.signal.fftconvolve(time_vector,
                                 kernel(t_arr).rescale(pq.Hz).magnitude,
                                 'full')
    if np.any(r < 0):
        warnings.warn("Instantaneous firing rate approximation contains "
                      "negative values, possibly caused due to machine "
                      "precision errors.")

    if not trim:
        r = r[kernel.median_index(t_arr):-(kernel(t_arr).size -
                                           kernel.median_index(t_arr))]
    elif trim:
        r = r[2 * kernel.median_index(t_arr):-2 *
              (kernel(t_arr).size - kernel.median_index(t_arr))]
        t_start += kernel.median_index(t_arr) * spiketrain.units
        t_stop -= (kernel(t_arr).size -
                   kernel.median_index(t_arr)) * spiketrain.units

    rate = neo.AnalogSignal(signal=r.reshape(r.size, 1),
                            sampling_period=sampling_period,
                            units=pq.Hz,
                            t_start=t_start,
                            t_stop=t_stop)

    return rate
]
same_len_labels = [
    str(label[0]) + '0' + str(label[1]) if len(label) < 3 else label
    for label in labels
]
ordered_indices_for_ids = np.array(np.argsort(same_len_labels))

ordered_labels = np.array(labels)[ordered_indices_for_ids]
print(1 / sampling_frequency * pq.s)
sts = retrieve_spiketimes(file)

label_spiketimes_map = make_label_spiketimes_map(ordered_labels, sts,
                                                 dead_channels)
spiketimes = label_spiketimes_map['L2'] / sampling_frequency
spiketimes = spiketimes[spiketimes <= 900]
kernel = kernels.GaussianKernel(sigma=1 * pq.s)
# plt.plot(kernel)
# plt.savefig('/home/lisa_ruth/lab_seminar/kernel.png')
# spike_object = neo.SpikeTrain(spiketimes, units='sec', t_stop=900.0)
# sr = elephant.statistics.instantaneous_rate(spike_object, 1/sampling_frequency * pq.s, kernel=kernel)
# figure, ax = plt.subplots(1, 1, figsize=(12, 9))
# ax.plot(np.linspace(0, 900.0, len(sr)), sr)
# print(np.linspace(0, 900.0, len(sr))[:5])
# # ax.set_xlim([0, 60])
# ax.set_xlabel('time [s]')
# ax.set_ylabel('firing rate [Hz]')
# ax.set_yticks(range(0, len(ordered_labels), 16))
# # ax.set_yticklabels(np.flip(ordered_labels)[::16])
# ax.spines['right'].set_visible(False)
# ax.spines['top'].set_visible(False)
# ax.get_xaxis().tick_bottom()
Esempio n. 10
0
def instantaneous_rate(spiketrain, sampling_period, kernel='auto',
                       cutoff=5.0, t_start=None, t_stop=None, trim=False,
                       center_kernel=True):
    """
    Estimates instantaneous firing rate by kernel convolution.

    Parameters
    ----------
    spiketrain : neo.SpikeTrain or list of neo.SpikeTrain
        Neo object(s) that contains spike times, the unit of the time stamps,
        and `t_start` and `t_stop` of the spike train.
    sampling_period : pq.Quantity
        Time stamp resolution of the spike times. The same resolution will
        be assumed for the kernel.
    kernel : 'auto' or Kernel, optional
        The string 'auto' or callable object of class `kernels.Kernel`.
        The kernel is used for convolution with the spike train and its
        standard deviation determines the time resolution of the instantaneous
        rate estimation. Currently implemented kernel forms are rectangular,
        triangular, epanechnikovlike, gaussian, laplacian, exponential, and
        alpha function.
        If 'auto', the optimized kernel width for the rate estimation is
        calculated according to [1]_ and with this width a gaussian kernel is
        constructed. Automatized calculation of the kernel width is not
        available for other than gaussian kernel shapes.
        Default: 'auto'.
    cutoff : float, optional
        This factor determines the cutoff of the probability distribution of
        the kernel, i.e., the considered width of the kernel in terms of
        multiples of the standard deviation sigma.
        Default: 5.0.
    t_start : pq.Quantity, optional
        Start time of the interval used to compute the firing rate.
        If None, `t_start` is assumed equal to `t_start` attribute of
        `spiketrain`.
        Default: None.
    t_stop : pq.Quantity, optional
        End time of the interval used to compute the firing rate (included).
        If None, `t_stop` is assumed equal to `t_stop` attribute of
        `spiketrain`.
        Default: None.
    trim : bool, optional
        Accounts for the asymmetry of a kernel.
        If False, the output of the Fast Fourier Transformation being a longer
        vector than the input vector by the size of the kernel is reduced back
        to the original size of the considered time interval of the
        `spiketrain` using the median of the kernel. False (no trimming) is
        equivalent to 'same' convolution mode for symmetrical kernels.
        If True, only the region of the convolved signal is returned, where
        there is complete overlap between kernel and spike train. This is
        achieved by reducing the length of the output of the Fast Fourier
        Transformation by a total of two times the size of the kernel, and
        `t_start` and `t_stop` are adjusted. True (trimming) is equivalent to
        'valid' convolution mode for symmetrical kernels.
        Default: False.
    center_kernel : bool, optional
        If set to True, the kernel will be translated such that its median is
        centered on the spike, thus putting equal weight before and after the
        spike. If False, no adjustment is performed such that the spike sits at
        the origin of the kernel.
        Default: True

    Returns
    -------
    rate : neo.AnalogSignal
        Contains the rate estimation in unit hertz (Hz). In case a list of
        spike trains was given, this is the combined rate of all spike trains
        (not the average rate). `rate.times` contains the time axis of the rate
        estimate. The unit of this property is the same as the resolution that
        is given via the argument `sampling_period` to the function.

    Raises
    ------
    TypeError
        If `spiketrain` is not an instance of `neo.SpikeTrain`.

        If `sampling_period` is not a `pq.Quantity`.

        If `sampling_period` is not larger than zero.

        If `kernel` is neither instance of `kernels.Kernel` nor string 'auto'.

        If `cutoff` is neither `float` nor `int`.

        If `t_start` and `t_stop` are neither None nor a `pq.Quantity`.

        If `trim` is not `bool`.
    ValueError
        If `sampling_period` is smaller than zero.

        If `kernel` is 'auto' and the function was unable to calculate optimal
        kernel width for instantaneous rate from input data.

    Warns
    -----
    UserWarning
        If `cutoff` is less than `min_cutoff` attribute of `kernel`, the width
        of the kernel is adjusted to a minimally allowed width.

        If the instantaneous firing rate approximation contains negative values
        with respect to a tolerance (less than -1e-5), possibly due to machine
        precision errors.

    References
    ----------
    .. [1] H. Shimazaki, & S. Shinomoto, "Kernel bandwidth optimization in
           spike rate estimation," J Comput Neurosci, vol. 29, pp. 171–182,
           2010.

    Examples
    --------
    >>> import quantities as pq
    >>> from elephant import kernels
    >>> kernel = kernels.AlphaKernel(sigma=0.05*pq.s, invert=True)
    >>> rate = instantaneous_rate(spiketrain, sampling_period=2*pq.ms,
    ...     kernel=kernel)

    """
    # Merge spike trains if list of spike trains given:
    if isinstance(spiketrain, list):
        _check_consistency_of_spiketrains(
            spiketrain, t_start=t_start, t_stop=t_stop)
        if t_start is None:
            t_start = spiketrain[0].t_start
        if t_stop is None:
            t_stop = spiketrain[0].t_stop
        spikes = np.concatenate([st.magnitude for st in spiketrain])
        merged_spiketrain = SpikeTrain(np.sort(spikes),
                                       units=spiketrain[0].units,
                                       t_start=t_start, t_stop=t_stop)
        return instantaneous_rate(merged_spiketrain,
                                  sampling_period=sampling_period,
                                  kernel=kernel, cutoff=cutoff,
                                  t_start=t_start,
                                  t_stop=t_stop, trim=trim)

    # Checks of input variables:
    if not isinstance(spiketrain, SpikeTrain):
        raise TypeError(
            "'spiketrain' must be an instance of neo.SpikeTrain. \n"
            "Found: '{}'".format(type(spiketrain)))

    if not is_time_quantity(sampling_period):
        raise TypeError(
            "The 'sampling_period' must be a time Quantity. \n"
            "Found: {}".format(type(sampling_period)))

    if sampling_period.magnitude < 0:
        raise ValueError("The 'sampling_period' ({}) must be non-negative.".
                         format(sampling_period))

    if kernel == 'auto':
        kernel_width_sigma = None
        if len(spiketrain) > 0:
            kernel_width_sigma = optimal_kernel_bandwidth(
                spiketrain.magnitude, times=None, bootstrap=False)['optw']
        if kernel_width_sigma is None:
            raise ValueError(
                "Unable to calculate optimal kernel width for "
                "instantaneous rate from input data.")
        kernel = kernels.GaussianKernel(kernel_width_sigma * spiketrain.units)
    elif not isinstance(kernel, kernels.Kernel):
        raise TypeError(
            "'kernel' must be either instance of class elephant.kernels.Kernel"
            " or the string 'auto'. Found: %s, value %s" % (type(kernel),
                                                            str(kernel)))

    if not isinstance(cutoff, (float, int)):
        raise TypeError("'cutoff' must be float or integer")

    if not is_time_quantity(t_start, allow_none=True):
        raise TypeError("'t_start' must be a time Quantity")

    if not is_time_quantity(t_stop, allow_none=True):
        raise TypeError("'t_stop' must be a time Quantity")

    if not isinstance(trim, bool):
        raise TypeError("'trim' must be bool")

    # main function:
    units = pq.CompoundUnit(
        "{}*s".format(sampling_period.rescale('s').item()))
    spiketrain = spiketrain.rescale(units)
    if t_start is None:
        t_start = spiketrain.t_start
    else:
        t_start = t_start.rescale(spiketrain.units)

    if t_stop is None:
        t_stop = spiketrain.t_stop
    else:
        t_stop = t_stop.rescale(spiketrain.units)

    # float32 makes fftconvolve less precise which may result in nan
    time_vector = np.zeros(int(t_stop - t_start) + 1, dtype=np.float64)
    spikes_slice = spiketrain.time_slice(t_start, t_stop)
    bins_active = (spikes_slice.times - t_start).magnitude.astype(np.int32)
    bins_unique, bin_counts = np.unique(bins_active, return_counts=True)
    time_vector[bins_unique] = bin_counts

    if cutoff < kernel.min_cutoff:
        cutoff = kernel.min_cutoff
        warnings.warn("The width of the kernel was adjusted to a minimally "
                      "allowed width.")

    t_arr = np.arange(-cutoff * kernel.sigma.rescale(units).magnitude,
                      cutoff * kernel.sigma.rescale(units).magnitude +
                      sampling_period.rescale(units).magnitude,
                      sampling_period.rescale(units).magnitude) * units

    if center_kernel:
        # keep the full convolve range and do the trimming afterwards;
        # trimming is performed according to the kernel median index
        fft_mode = 'full'
    elif trim:
        # no median index trimming is involved
        fft_mode = 'valid'
    else:
        # no median index trimming is involved
        fft_mode = 'same'
    rate = scipy.signal.fftconvolve(time_vector,
                                    kernel(t_arr).rescale(pq.Hz).magnitude,
                                    mode=fft_mode)

    if np.any(rate < -1e-8):  # abs tolerance in np.isclose
        warnings.warn("Instantaneous firing rate approximation contains "
                      "negative values, possibly caused due to machine "
                      "precision errors.")

    median_id = kernel.median_index(t_arr)
    # the size of kernel() output matches the input size
    kernel_array_size = len(t_arr)
    if center_kernel:
        # account for the kernel asymmetry
        if not trim:
            rate = rate[median_id: -kernel_array_size + median_id]
        else:
            rate = rate[2 * median_id: -2 * (kernel_array_size - median_id)]
            t_start = t_start + median_id * spiketrain.units
            t_stop = t_stop - (kernel_array_size - median_id
                               ) * spiketrain.units
    else:
        # (to be consistent with center_kernel=True)
        # n points have n-1 intervals;
        # instantaneous rate is a list of intervals;
        # hence, the last element is excluded
        rate = rate[:-1]

    rate = neo.AnalogSignal(signal=np.expand_dims(rate, axis=1),
                            sampling_period=sampling_period,
                            units=pq.Hz, t_start=t_start, t_stop=t_stop)

    return rate
Esempio n. 11
0
def myrate(spiketrain,
           sampling_period,
           kernel='auto',
           cutoff=5.0,
           t_start=None,
           t_stop=None,
           trim=False,
           center_kernel=True):
    """
    Estimates instantaneous firing rate by kernel convolution.

    Modified by gryang from elephant.statistics.instantaneous_rate. Much
    faster for many spike trains.

    Parameters
    ----------
    spiketrain : list of lists of spike times
        Neo object(s) that contains spike times, the unit of the time stamps,
        and `t_start` and `t_stop` of the spike train.
    sampling_period : float (s)
        Time stamp resolution of the spike times. The same resolution will
        be assumed for the kernel.

    The rest are the same as elephant.statistics.instantaneous_rate,
    abbreviated here.
    """

    if kernel == 'auto':
        kernel_width_sigma = None
        if len(spiketrain) > 0:
            kernel_width_sigma = optimal_kernel_bandwidth(
                spiketrain.magnitude, times=None, bootstrap=False)['optw']
        if kernel_width_sigma is None:
            raise ValueError("Unable to calculate optimal kernel width for "
                             "instantaneous rate from input data.")
        kernel = kernels.GaussianKernel(kernel_width_sigma * spiketrain.units)
    elif not isinstance(kernel, kernels.Kernel):
        raise TypeError(
            "'kernel' must be either instance of class elephant.kernels.Kernel"
            " or the string 'auto'. Found: %s, value %s" %
            (type(kernel), str(kernel)))

    # TODO: do the single spike train case
    n_spiketrain = len(spiketrain)  # Number of spike trains

    # main function:
    nbins = int((t_stop - t_start) / sampling_period) + 1
    time_vectors = np.zeros((n_spiketrain, nbins))
    ranges = (t_start, t_stop + sampling_period)
    times = np.arange(ranges[0], ranges[1], sampling_period)
    for i, st in enumerate(spiketrain):
        # See https://iscinumpy.gitlab.io/post/histogram-speeds-in-python/
        time_vectors[i], _ = np.histogram(st, bins=nbins, range=ranges)
        # c = ((st[(st >= ranges[0]) & (st < ranges[1])] - ranges[0]) /
        #      sampling_period).astype(np.int_)
        # time_vectors[i] = np.bincount(c)

    # This line is necessary to match elephant's original implementation
    time_vectors[:, -1] = 0
    time_vectors = time_vectors.T  # make it (time, units)
    time_vectors = time_vectors.astype(np.float64)  # from elephant

    if cutoff < kernel.min_cutoff:
        cutoff = kernel.min_cutoff
        warnings.warn("The width of the kernel was adjusted to a minimally "
                      "allowed width.")

    sigma = kernel.sigma.rescale(pq.s).magnitude
    t_arr = np.arange(-cutoff * sigma, cutoff * sigma + sampling_period,
                      sampling_period) * pq.s

    if center_kernel:
        # keep the full convolve range and do the trimming afterwards;
        # trimming is performed according to the kernel median index
        fft_mode = 'full'
    elif trim:
        # no median index trimming is involved
        fft_mode = 'valid'
    else:
        # no median index trimming is involved
        fft_mode = 'same'

    _kernel = kernel(t_arr).rescale(pq.Hz).magnitude[:, np.newaxis]
    rates = scipy.signal.fftconvolve(time_vectors,
                                     _kernel,
                                     mode=fft_mode,
                                     axes=0)

    median_id = kernel.median_index(t_arr)
    # the size of kernel() output matches the input size
    kernel_array_size = len(t_arr)
    if center_kernel:
        # account for the kernel asymmetry
        if not trim:
            rates = rates[median_id:-kernel_array_size + median_id]
        else:
            rates = rates[2 * median_id:-2 * (kernel_array_size - median_id)]
    else:
        # (to be consistent with center_kernel=True)
        # n points have n-1 intervals;
        # instantaneous rate is a list of intervals;
        # hence, the last element is excluded
        rates = rates[:-1]

    return rates, times[:-1]
Esempio n. 12
0

if __name__ == '__main__':
    import time
    from elephant.statistics import instantaneous_rate
    from neo.core import SpikeTrain

    sampling_period = 0.01
    t_start = -2
    t_stop = 2
    X = [
        np.random.uniform(-3, 3, size=(np.random.randint(9000, 11000), ))
        for i in range(100)
    ]
    kernel_sigma = 0.05
    kernel = kernels.GaussianKernel(50 * pq.ms)

    t0 = time.time()
    Rate = list()
    for i in range(len(X)):
        spiketrain = SpikeTrain(X[i] * pq.s,
                                t_start=-3 * pq.s,
                                t_stop=3 * pq.s)
        rate = instantaneous_rate(spiketrain,
                                  sampling_period=0.01 * pq.s,
                                  t_start=-2 * pq.s,
                                  t_stop=2 * pq.s,
                                  kernel=kernel)
        Rate.append(rate.magnitude[:, 0])
    Rate = np.array(Rate).T
    time_taken0 = (time.time() - t0)
Esempio n. 13
0
def instantaneous_rate(spiketrain, sampling_period, kernel='auto',
                       cutoff=5.0, t_start=None, t_stop=None, trim=False):
    """
    Estimates instantaneous firing rate by kernel convolution.

    Parameters
    -----------
    spiketrain : neo.SpikeTrain or list of neo.SpikeTrain
        Neo object(s) that contains spike times, the unit of the time stamps,
        and `t_start` and `t_stop` of the spike train.
    sampling_period : pq.Quantity
        Time stamp resolution of the spike times. The same resolution will
        be assumed for the kernel.
    kernel : str or `kernels.Kernel`, optional
        The string 'auto' or callable object of class `kernels.Kernel`.
        The kernel is used for convolution with the spike train and its
        standard deviation determines the time resolution of the instantaneous
        rate estimation. Currently implemented kernel forms are rectangular,
        triangular, epanechnikovlike, gaussian, laplacian, exponential, and
        alpha function.
        If 'auto', the optimized kernel width for the rate estimation is
        calculated according to [1]_ and with this width a gaussian kernel is
        constructed. Automatized calculation of the kernel width is not
        available for other than gaussian kernel shapes.
        Default: 'auto'.
    cutoff : float, optional
        This factor determines the cutoff of the probability distribution of
        the kernel, i.e., the considered width of the kernel in terms of
        multiples of the standard deviation sigma.
        Default: 5.0.
    t_start : pq.Quantity, optional
        Start time of the interval used to compute the firing rate.
        If None, `t_start` is assumed equal to `t_start` attribute of
        `spiketrain`.
        Default: None.
    t_stop : pq.Quantity, optional
        End time of the interval used to compute the firing rate (included).
        If None, `t_stop` is assumed equal to `t_stop` attribute of
        `spiketrain`.
        Default: None.
    trim : bool, optional
        If False, the output of the Fast Fourier Transformation being a longer
        vector than the input vector by the size of the kernel is reduced back
        to the original size of the considered time interval of the
        `spiketrain` using the median of the kernel.
        If True, only the region of the convolved signal is returned, where
        there is complete overlap between kernel and spike train. This is
        achieved by reducing the length of the output of the Fast Fourier
        Transformation by a total of two times the size of the kernel, and
        `t_start` and `t_stop` are adjusted.
        Default: False.

    Returns
    -------
    rate : neo.AnalogSignal
        Contains the rate estimation in unit hertz (Hz). In case a list of
        spike trains was given, this is the combined rate of all spike trains
        (not the average rate). `rate.times` contains the time axis of the rate
        estimate. The unit of this property is the same as the resolution that
        is given via the argument `sampling_period` to the function.

    Raises
    ------
    TypeError:
        If `spiketrain` is not an instance of `neo.SpikeTrain`.

        If `sampling_period` is not a `pq.Quantity`.

        If `sampling_period` is not larger than zero.

        If `kernel` is neither instance of `kernels.Kernel` nor string 'auto'.

        If `cutoff` is neither `float` nor `int`.

        If `t_start` and `t_stop` are neither None nor a `pq.Quantity`.

        If `trim` is not `bool`.

    ValueError:
        If `sampling_period` is smaller than zero.

        If `kernel` is 'auto' and the function was unable to calculate optimal
        kernel width for instantaneous rate from input data.

    Warns
    -----
    UserWarning
        If `cutoff` is less than `min_cutoff` attribute of `kernel`, the width
        of the kernel is adjusted to a minimally allowed width.

        If the instantaneous firing rate approximation contains negative values
        with respect to a tolerance (less than -1e-8), possibly due to machine
        precision errors.

    References
    ----------
    .. [1] H. Shimazaki, & S. Shinomoto, "Kernel bandwidth optimization in
           spike rate estimation," J Comput Neurosci, vol. 29, pp. 171–182,
           2010.

    Examples
    --------
    >>> import quantities as pq
    >>> from elephant import kernels
    >>> kernel = kernels.AlphaKernel(sigma=0.05*pq.s, invert=True)
    >>> rate = instantaneous_rate(spiketrain, sampling_period=2*pq.ms,
    ...     kernel=kernel)

    """
    # Merge spike trains if list of spike trains given:
    if isinstance(spiketrain, list):
        _check_consistency_of_spiketrainlist(
            spiketrain, t_start=t_start, t_stop=t_stop)
        if t_start is None:
            t_start = spiketrain[0].t_start
        if t_stop is None:
            t_stop = spiketrain[0].t_stop
        spikes = np.concatenate([st.magnitude for st in spiketrain])
        merged_spiketrain = SpikeTrain(np.sort(spikes),
                                       units=spiketrain[0].units,
                                       t_start=t_start, t_stop=t_stop)
        return instantaneous_rate(merged_spiketrain,
                                  sampling_period=sampling_period,
                                  kernel=kernel, cutoff=cutoff,
                                  t_start=t_start,
                                  t_stop=t_stop, trim=trim)

    # Checks of input variables:
    if not isinstance(spiketrain, SpikeTrain):
        raise TypeError(
            "spiketrain must be instance of :class:`SpikeTrain` of Neo!\n"
            "    Found: %s, value %s" % (type(spiketrain), str(spiketrain)))

    if not (isinstance(sampling_period, pq.Quantity) and
            sampling_period.dimensionality.simplified ==
            pq.Quantity(1, "s").dimensionality):
        raise TypeError(
            "The sampling period must be a time quantity!\n"
            "    Found: %s, value %s" % (
                type(sampling_period), str(sampling_period)))

    if sampling_period.magnitude < 0:
        raise ValueError("The sampling period must be larger than zero.")

    if kernel == 'auto':
        kernel_width_sigma = sskernel(
            spiketrain.magnitude, tin=None, bootstrap=False)['optw']
        if kernel_width_sigma is None:
            raise ValueError(
                "Unable to calculate optimal kernel width for "
                "instantaneous rate from input data.")
        kernel = kernels.GaussianKernel(kernel_width_sigma * spiketrain.units)
    elif not isinstance(kernel, kernels.Kernel):
        raise TypeError(
            "kernel must be either instance of :class:`Kernel` "
            "or the string 'auto'!\n"
            "    Found: %s, value %s" % (type(kernel), str(kernel)))

    if not (isinstance(cutoff, float) or isinstance(cutoff, int)):
        raise TypeError("cutoff must be float or integer!")

    if not (t_start is None or (isinstance(t_start, pq.Quantity) and
                                t_start.dimensionality.simplified ==
                                pq.Quantity(1, "s").dimensionality)):
        raise TypeError("t_start must be a time quantity!")

    if not (t_stop is None or (isinstance(t_stop, pq.Quantity) and
                               t_stop.dimensionality.simplified ==
                               pq.Quantity(1, "s").dimensionality)):
        raise TypeError("t_stop must be a time quantity!")

    if not (isinstance(trim, bool)):
        raise TypeError("trim must be bool!")

    # main function:
    units = pq.CompoundUnit(
        "{}*s".format(sampling_period.rescale('s').item()))
    spiketrain = spiketrain.rescale(units)
    if t_start is None:
        t_start = spiketrain.t_start
    else:
        t_start = t_start.rescale(spiketrain.units)

    if t_stop is None:
        t_stop = spiketrain.t_stop
    else:
        t_stop = t_stop.rescale(spiketrain.units)

    time_vector = np.zeros(int((t_stop - t_start)) + 1)

    spikes_slice = spiketrain.time_slice(t_start, t_stop) \
        if len(spiketrain) else np.array([])

    for spike in spikes_slice:
        index = int((spike - t_start))
        time_vector[index] += 1

    if cutoff < kernel.min_cutoff:
        cutoff = kernel.min_cutoff
        warnings.warn("The width of the kernel was adjusted to a minimally "
                      "allowed width.")

    t_arr = np.arange(-cutoff * kernel.sigma.rescale(units).magnitude,
                      cutoff * kernel.sigma.rescale(units).magnitude +
                      sampling_period.rescale(units).magnitude,
                      sampling_period.rescale(units).magnitude) * units

    r = scipy.signal.fftconvolve(time_vector,
                                 kernel(t_arr).rescale(pq.Hz).magnitude,
                                 'full')
    if np.any(r < -1e-8):  # abs tolerance in np.isclose
        warnings.warn("Instantaneous firing rate approximation contains "
                      "negative values, possibly caused due to machine "
                      "precision errors.")

    if not trim:
        r = r[kernel.median_index(t_arr):-(kernel(t_arr).size -
                                           kernel.median_index(t_arr))]
    elif trim:
        r = r[2 * kernel.median_index(t_arr):-2 * (kernel(t_arr).size -
                                                   kernel.median_index(t_arr))]
        t_start += kernel.median_index(t_arr) * spiketrain.units
        t_stop -= (kernel(t_arr).size -
                   kernel.median_index(t_arr)) * spiketrain.units

    rate = neo.AnalogSignal(signal=r.reshape(r.size, 1),
                            sampling_period=sampling_period,
                            units=pq.Hz, t_start=t_start, t_stop=t_stop)

    return rate