def test_corrcoef_binned(self):
        '''
        Test the correlation coefficient between two binned spike trains.
        '''

        # Calculate clipped and unclipped
        res_clipped = sc.correlation_coefficient(self.binned_st, binary=True)
        res_unclipped = sc.correlation_coefficient(self.binned_st,
                                                   binary=False)

        # Check dimensions
        self.assertEqual(len(res_clipped), 2)
        self.assertEqual(len(res_unclipped), 2)

        # Check result unclipped against result calculated from scratch for
        # the off-diagonal element
        mat = self.binned_st.to_array()
        mean_0 = np.mean(mat[0])
        mean_1 = np.mean(mat[1])
        target_from_scratch = \
            np.dot(mat[0] - mean_0, mat[1] - mean_1) / \
            np.sqrt(
                np.dot(mat[0] - mean_0, mat[0] - mean_0) *
                np.dot(mat[1] - mean_1, mat[1] - mean_1))

        # Check result unclipped against result calculated by numpy.corrcoef
        target_numpy = np.corrcoef(mat)

        self.assertAlmostEqual(target_from_scratch, target_numpy[0][1])
        self.assertAlmostEqual(res_unclipped[0][1], target_from_scratch)
        self.assertAlmostEqual(res_unclipped[1][0], target_from_scratch)

        # Check result clipped against result calculated from scratch for
        # the off-diagonal elemant
        mat = self.binned_st.to_bool_array()
        mean_0 = np.mean(mat[0])
        mean_1 = np.mean(mat[1])
        target_from_scratch = \
            np.dot(mat[0] - mean_0, mat[1] - mean_1) / \
            np.sqrt(
                np.dot(mat[0] - mean_0, mat[0] - mean_0) *
                np.dot(mat[1] - mean_1, mat[1] - mean_1))

        # Check result unclipped against result calculated by numpy.corrcoef
        target_numpy = np.corrcoef(mat)

        self.assertAlmostEqual(target_from_scratch, target_numpy[0][1])
        self.assertAlmostEqual(res_clipped[0][1], target_from_scratch)
        self.assertAlmostEqual(res_clipped[1][0], target_from_scratch)
 def compute_spikes_correlation_coefficient(self,
                                            binned_spikes_trains,
                                            binsize=None,
                                            num_bins=None,
                                            **kwargs):
     """A method to compute the correlation coefficients
        among the spikes' trains of a set of elephant.conversion.BinnedSpikeTrain,
        using the elephant.spike_train_correlation.correlation_coefficient method.
        - binned_spikes_trains: an elephant.conversion.BinnedSpikeTrain instance, or a
                                sequence (array, list, tuple) of Spikes Trains or of spikes' times arrays
        - binsize: the size (float, in ms) of the bin to be used. Default=None.
         - num_bins: the number (integer > 0) of bins to be used. Default=None.
         If none of binsize or num_bins if given, a bin size equal to the sampling period is used.
        Returns:
         - a dictionary of the following key-value pair(s):
          "correlation_coefficient": correlation_coefficient array
          "binned_spikes_trains": the elephant.conversion.BinnedSpikeTrain instance used for the computation
     """
     binned_spikes_trains = self._assert_binned_spikes_trains(
         binned_spikes_trains, binsize, num_bins)
     from elephant.spike_train_correlation import correlation_coefficient
     return {
         self._get_comput_res_type():
         correlation_coefficient(binned_spikes_trains, **kwargs),
         self.binned_spikes_trains_name:
         binned_spikes_trains
     }
Exemplo n.º 3
0
    def test_corrcoef_binned_short_input(self):
        """
        Test if input list of one binned spike train yields 1.0.
        """
        # Calculate correlation
        binned_st = conv.BinnedSpikeTrain(
            self.st_0, t_start=0 * pq.ms, t_stop=50. * pq.ms,
            bin_size=1 * pq.ms)
        result = sc.correlation_coefficient(binned_st, fast=False)
        target = np.array(1.)

        # Check result and dimensionality of result
        self.assertEqual(result.ndim, 0)
        assert_array_almost_equal(result, target)
        assert_array_almost_equal(
            result, sc.correlation_coefficient(
                binned_st, fast=True))
Exemplo n.º 4
0
    def test_corrcoef_binned_same_spiketrains(self):
        """
        Test if the correlation coefficient between two identical binned spike
        trains evaluates to a 2x2 matrix of ones.
        """
        # Calculate correlation
        binned_st = conv.BinnedSpikeTrain(
            [self.st_0, self.st_0], t_start=0 * pq.ms, t_stop=50. * pq.ms,
            bin_size=1 * pq.ms)
        result = sc.correlation_coefficient(binned_st, fast=False)
        target = np.ones((2, 2))

        # Check dimensions
        self.assertEqual(len(result), 2)
        # Check result
        assert_array_almost_equal(result, target)
        assert_array_almost_equal(
            result, sc.correlation_coefficient(
                binned_st, fast=True))
Exemplo n.º 5
0
    def test_empty_spike_train(self):
        """
        Test whether a warning is yielded in case of empty spike train.
        Also check correctness of the output array.
        """
        # st_2 is empty
        binned_12 = conv.BinnedSpikeTrain([self.st_1, self.st_2],
                                          bin_size=1 * pq.ms)

        with self.assertWarns(UserWarning):
            result = sc.correlation_coefficient(binned_12, fast=False)

        # test for NaNs in the output array
        target = np.zeros((2, 2)) * np.NaN
        target[0, 0] = 1.0
        assert_array_almost_equal(result, target)
Exemplo n.º 6
0
    def test_cross_correlation_histogram(self):
        """
        Test generic result of a cross-correlation histogram between two binned
        spike trains.
        """
        # Calculate CCH using Elephant (normal and binary version) with
        # mode equal to 'full' (whole spike trains are correlated)
        cch_clipped, bin_ids_clipped = sc.cross_correlation_histogram(
            self.binned_st1, self.binned_st2, window='full',
            binary=True)
        cch_unclipped, bin_ids_unclipped = sc.cross_correlation_histogram(
            self.binned_st1, self.binned_st2, window='full', binary=False)

        cch_clipped_mem, bin_ids_clipped_mem = sc.cross_correlation_histogram(
            self.binned_st1, self.binned_st2, window='full',
            binary=True, method='memory')
        cch_unclipped_mem, bin_ids_unclipped_mem = \
            sc.cross_correlation_histogram(
                self.binned_st1, self.binned_st2, window='full',
                binary=False, method='memory')
        # Check consistency two methods
        assert_array_equal(
            np.squeeze(cch_clipped.magnitude), np.squeeze(
                cch_clipped_mem.magnitude))
        assert_array_equal(
            np.squeeze(cch_clipped.times), np.squeeze(
                cch_clipped_mem.times))
        assert_array_equal(
            np.squeeze(cch_unclipped.magnitude), np.squeeze(
                cch_unclipped_mem.magnitude))
        assert_array_equal(
            np.squeeze(cch_unclipped.times), np.squeeze(
                cch_unclipped_mem.times))
        assert_array_almost_equal(bin_ids_clipped, bin_ids_clipped_mem)
        assert_array_almost_equal(bin_ids_unclipped, bin_ids_unclipped_mem)

        # Check normal correlation Note: Use numpy correlate to verify result.
        # Note: numpy conventions for input array 1 and input array 2 are
        # swapped compared to Elephant!
        mat1 = self.binned_st1.to_array()[0]
        mat2 = self.binned_st2.to_array()[0]
        target_numpy = np.correlate(mat2, mat1, mode='full')
        assert_array_equal(
            target_numpy, np.squeeze(cch_unclipped.magnitude))

        # Check cross correlation function for several displacements tau
        # Note: Use Elephant corrcoeff to verify result
        tau = [-25.0, 0.0, 13.0]  # in ms
        for t in tau:
            # adjust t_start, t_stop to shift by tau
            t0 = np.min([self.st_1.t_start + t * pq.ms, self.st_2.t_start])
            t1 = np.max([self.st_1.t_stop + t * pq.ms, self.st_2.t_stop])
            st1 = neo.SpikeTrain(self.st_1.magnitude + t, units='ms',
                                 t_start=t0 * pq.ms, t_stop=t1 * pq.ms)
            st2 = neo.SpikeTrain(self.st_2.magnitude, units='ms',
                                 t_start=t0 * pq.ms, t_stop=t1 * pq.ms)
            binned_sts = conv.BinnedSpikeTrain([st1, st2],
                                               bin_size=1 * pq.ms,
                                               t_start=t0 * pq.ms,
                                               t_stop=t1 * pq.ms)
            # caluclate corrcoef
            corrcoef = sc.correlation_coefficient(binned_sts)[1, 0]

            # expand t_stop to have two spike trains with same length as st1,
            # st2
            st1 = neo.SpikeTrain(self.st_1.magnitude, units='ms',
                                 t_start=self.st_1.t_start,
                                 t_stop=self.st_1.t_stop + np.abs(t) * pq.ms)
            st2 = neo.SpikeTrain(self.st_2.magnitude, units='ms',
                                 t_start=self.st_2.t_start,
                                 t_stop=self.st_2.t_stop + np.abs(t) * pq.ms)
            binned_st1 = conv.BinnedSpikeTrain(
                st1, t_start=0 * pq.ms, t_stop=(50 + np.abs(t)) * pq.ms,
                bin_size=1 * pq.ms)
            binned_st2 = conv.BinnedSpikeTrain(
                st2, t_start=0 * pq.ms, t_stop=(50 + np.abs(t)) * pq.ms,
                bin_size=1 * pq.ms)
            # calculate CCHcoef and take value at t=tau
            CCHcoef, _ = sc.cch(binned_st1, binned_st2,
                                cross_correlation_coefficient=True)
            left_edge = - binned_st1.n_bins + 1
            tau_bin = int(t / float(binned_st1.bin_size.magnitude))
            assert_array_almost_equal(
                corrcoef, CCHcoef[tau_bin - left_edge].magnitude)

        # Check correlation using binary spike trains
        mat1 = np.array(self.binned_st1.to_bool_array()[0], dtype=int)
        mat2 = np.array(self.binned_st2.to_bool_array()[0], dtype=int)
        target_numpy = np.correlate(mat2, mat1, mode='full')
        assert_array_equal(
            target_numpy, np.squeeze(cch_clipped.magnitude))

        # Check the time axis and bin IDs of the resulting AnalogSignal
        assert_array_almost_equal(
            (bin_ids_clipped - 0.5) * self.binned_st1.bin_size,
            cch_unclipped.times)
        assert_array_almost_equal(
            (bin_ids_clipped - 0.5) * self.binned_st1.bin_size,
            cch_clipped.times)

        # Calculate CCH using Elephant (normal and binary version) with
        # mode equal to 'valid' (only completely overlapping intervals of the
        # spike trains are correlated)
        cch_clipped, bin_ids_clipped = sc.cross_correlation_histogram(
            self.binned_st1, self.binned_st2, window='valid',
            binary=True)
        cch_unclipped, bin_ids_unclipped = sc.cross_correlation_histogram(
            self.binned_st1, self.binned_st2, window='valid',
            binary=False)
        cch_clipped_mem, bin_ids_clipped_mem = sc.cross_correlation_histogram(
            self.binned_st1, self.binned_st2, window='valid',
            binary=True, method='memory')
        cch_unclipped_mem, bin_ids_unclipped_mem = \
            sc.cross_correlation_histogram(
                self.binned_st1, self.binned_st2, window='valid',
                binary=False, method='memory')

        # Check consistency two methods
        assert_array_equal(
            np.squeeze(cch_clipped.magnitude), np.squeeze(
                cch_clipped_mem.magnitude))
        assert_array_equal(
            np.squeeze(cch_clipped.times), np.squeeze(
                cch_clipped_mem.times))
        assert_array_equal(
            np.squeeze(cch_unclipped.magnitude), np.squeeze(
                cch_unclipped_mem.magnitude))
        assert_array_equal(
            np.squeeze(cch_unclipped.times), np.squeeze(
                cch_unclipped_mem.times))
        assert_array_equal(bin_ids_clipped, bin_ids_clipped_mem)
        assert_array_equal(bin_ids_unclipped, bin_ids_unclipped_mem)

        # Check normal correlation Note: Use numpy correlate to verify result.
        # Note: numpy conventions for input array 1 and input array 2 are
        # swapped compared to Elephant!
        mat1 = self.binned_st1.to_array()[0]
        mat2 = self.binned_st2.to_array()[0]
        target_numpy = np.correlate(mat2, mat1, mode='valid')
        assert_array_equal(
            target_numpy, np.squeeze(cch_unclipped.magnitude))

        # Check correlation using binary spike trains
        mat1 = np.array(self.binned_st1.to_bool_array()[0], dtype=int)
        mat2 = np.array(self.binned_st2.to_bool_array()[0], dtype=int)
        target_numpy = np.correlate(mat2, mat1, mode='valid')
        assert_array_equal(
            target_numpy, np.squeeze(cch_clipped.magnitude))

        # Check the time axis and bin IDs of the resulting AnalogSignal
        assert_array_equal(
            (bin_ids_clipped - 0.5) * self.binned_st1.bin_size,
            cch_unclipped.times)
        assert_array_equal(
            (bin_ids_clipped - 0.5) * self.binned_st1.bin_size,
            cch_clipped.times)

        # Check for wrong window parameter setting
        self.assertRaises(
            ValueError, sc.cross_correlation_histogram, self.binned_st1,
            self.binned_st2, window='dsaij')
        self.assertRaises(
            ValueError, sc.cross_correlation_histogram, self.binned_st1,
            self.binned_st2, window='dsaij', method='memory')
Exemplo n.º 7
0
def get_firing_rate_metrics(neuronset, spikes_fn, num_neurons=8000.,
                            rows=50000000., start_time=100., dt=1.,
                            window=1000., snapshot_dt=200000.,
                            isi_enabled=True, std_enabled=True,
                            cc_enabled=True):
    """Get various metrics from raster spike files.

    :neuronset: name of neuron set being looked at
    :spikes_fn: file name of spikes file
    :num_neurons: number of neurons in neuron set
    :rows: rows to be read in each pandas chunk
    :start_time: time to start the processing at (ms)
    :dt: increment value (ms)
    :window: window to count spikes in (ms)
    :snapshot_dt: interval between snapshots for ISI and STD metrics (ms)
    :isi_enabled: if ISI CVs should be calculated
    :std_enabled: if STD of firing rate should be calculated
    :cc_enabled: if average spike correlation coefficient should be enabled
    :returns: True if everything went OK, else False

    """
    # Initial indices
    left = 0.
    right = 0.

    num_neurons = int(num_neurons)
    current_time = start_time
    old_neuronIDs = numpy.array([])
    old_times = numpy.array([])
    lgr.info("Processing {}.".format(spikes_fn))
    if not os.path.exists(spikes_fn):
        lgr.error("File not found {}".format(spikes_fn))
        return False

    with open("mean-firing-rates-{}.gdf".format(neuronset), 'w') as fh1, \
            open("std-firing-rates-{}.gdf".format(neuronset), 'w') as fh2, \
            open("ISI-cv-{}.gdf".format(neuronset), 'w') as fh3, \
            open("cc-{}.gdf".format(neuronset), 'w') as fh4:

        for chunk in pandas.read_csv(spikes_fn, sep='\s+',  # noqa: W605
                                     names=["neuronID",
                                            "spike_time"],
                                     dtype={'neuronID': numpy.uint16,
                                            'spike_time': float},
                                     lineterminator="\n",
                                     skipinitialspace=True,
                                     header=None, index_col=None,
                                     skip_blank_lines=True,
                                     chunksize=rows):

            # Drop rows with nan
            chunk = chunk.dropna(how='any')
            if not validate_raster_df(chunk):
                lgr.error("Error in {}. Skipping.".format(spikes_fn))
                return False

            neuronIDs = numpy.array(chunk.values[:, 0])
            times = numpy.array(chunk.values[:, 1])

            # 200 neuronIDs per second = 2 neuronIDs per 0.01 second (dt) per
            # neuron this implies 2 * 10000 neuronIDs for 10000 neurons need
            # to be kept to make sure I have a proper sliding window of
            # chunks
            if len(old_neuronIDs) > 0:
                neuronIDs = numpy.append(old_neuronIDs, neuronIDs)
                times = numpy.append(old_times, times)

            lgr.debug(
                "Times from {} to {} being analysed containing {} rows".format(
                    times[0], times[-1], len(times)))

            lgr.debug("Current time is {}".format(current_time))

            # Reset chunks
            left = 0
            right = 0

            while (current_time < math.floor(times[-1])):
                # Initialise these to 0
                mean_firing_rate = 0.
                spikesnum = 0.
                mystd = -1

                left += numpy.searchsorted(times[left:],
                                           (current_time - window),
                                           side='left')
                right = left + numpy.searchsorted(
                    times[left:], current_time,
                    side='right')

                # point is lesser than the first value in the chunk
                if right == 0 and left == 0:
                    lgr.warning("Point too small for chunk")
                    current_time = times[0]
                    lgr.warning("Time to reset to: {}".format(times[0]))
                    continue

                # interval not found, no spikes - not necessarily at max
                # the max check is in the while condition, and that
                # ascertains if a new chunk should be read
                if right == left:
                    lgr.warning("No spikes in interval at {}".format(
                        current_time))
                    # Increment it by snapshot_dt to ensure that the next check
                    # for ISI and STD metrics can be made.
                    # Ideally, I should be able to move it to times[left], but
                    # there is no guarantee that it would remain dividible by
                    # snapshot_dt. That would mean that the next bits are never
                    # run, even if there are spikes.
                    current_time += snapshot_dt
                    lgr.warning("Current time updated to {}".format(
                        current_time))

                    # Print NA values for STD and ISI which will not be
                    # calculated for this time
                    lgr.warning("Printing invalid values for STD and ISI CV")

                    # For gnuplot, lines starting with # are ignored.
                    # To skip these points and have a discontinuous graph in
                    # gnuplot, one must leave a blank line in the text.
                    print(
                        "#{}\tNA\n".format(current_time / 1000.),
                        file=fh2, flush=True)

                    print(
                        "#{}\tNA\n".format(current_time / 1000.),
                        file=fh3, flush=True)
                    continue

                # could even just do right - left if all I'm using is len
                thiswindow_neuronIDs = neuronIDs[left:right]
                thiswindow_times = times[left:right]

                # mean firing rate
                spikesnum = float(len(thiswindow_neuronIDs))
                mean_firing_rate = (spikesnum / num_neurons) / (window / 1000)
                # total neuronIDs by number of neurons
                print(
                    "{}\t{}".format(current_time / 1000.,
                                    mean_firing_rate),
                    file=fh1, flush=True)

                # We only get here if there are some spikes, so there's no need
                # to check for that again.

                # STD of firing rates and ISI cv - it just takes way too much
                # time to do for each dt - my post processing wont finish. So,
                # we calculate it at intervals
                if ((current_time - start_time) % snapshot_dt == 0):
                    if std_enabled:
                        lgr.debug("STD for {}".format(
                            current_time))
                        # STD of firing rates
                        # calculate firing rates of each neuron in the window
                        # then find STD
                        spike_counts = collections.Counter(thiswindow_neuronIDs)
                        firing_rates = []
                        for neuron, count in spike_counts.items():
                            firing_rates.append(count / (window / 1000))
                        neurons_spiking = len(firing_rates)
                        # Add 0s for neurons that did not spike
                        for i in range(0, (num_neurons - neurons_spiking)):
                            firing_rates.append(0)

                        lgr.debug("std being calculated from {} values".format(
                            len(firing_rates)))
                        mystd = numpy.std(firing_rates)
                        print(
                            "{}\t{}".format(current_time / 1000., mystd),
                            file=fh2, flush=True)

                    if cc_enabled:
                        lgr.debug("CC for {}".format(
                            current_time))
                        # CC
                        # I do not sort them.
                        # Get unique neuron list
                        neurons = list(set(thiswindow_neuronIDs))
                        # Shuffle them so that the spike trains are from a shuffled
                        # pack of neurons when the CC is calculated
                        random.shuffle(neurons)
                        # Select at least 800 neurons
                        if len(neurons) > 800:
                            N = max(int(0.1 * len(neurons)), 800)
                        else:
                            N = len(neurons)
                        lgr.debug("CC is using {} neurons".format(N))
                        neurons = neurons[0:N]
                        spike_trains = []
                        # Get spike trains for each neuron
                        for nrn in list(neurons):
                            indices = [i for i, x in
                                       enumerate(thiswindow_neuronIDs) if x == nrn]
                            nrn_spike_times = thiswindow_times[indices]
                            nrn_spiketrain = SpikeTrain(nrn_spike_times * ms,
                                                        t_stop=thiswindow_times[-1])
                            spike_trains.append(nrn_spiketrain)

                        bin_size = (5 * ms)
                        binned_spike_trains = BinnedSpikeTrain(spike_trains,
                                                               bin_size)
                        cc_matrix = correlation_coefficient(binned_spike_trains)
                        # elements in triangle: (N * (N-1)/2)
                        # mean of cc values = (sum of triangle)/(N * (N-1)/2)
                        avg_cc = (
                            numpy.nansum(numpy.tril(cc_matrix, -1)) / (N * (N - 1) / 2)
                        )
                        print(
                            "{}\t{}\t{}".format(current_time / 1000., N, avg_cc), file=fh4,
                            flush=True)

                    if isi_enabled:
                        # ISI stats
                        neurons = set(thiswindow_neuronIDs)
                        lgr.debug("ISI: {} neurons being analysed.".format(
                            len(neurons)))
                        # for all neurons in this window
                        ISI_cvs = []
                        for neuron in list(neurons):
                            indices = [i for i, x
                                       in enumerate(thiswindow_neuronIDs)
                                       if x == neuron]
                            neuron_times = [thiswindow_times[i] for i in
                                            indices]

                            ISIs = []
                            if len(neuron_times) > 1:
                                # otherwise ISI is undefined in this window for
                                # this neuron
                                prev = neuron_times[0]
                                # get a list of ISIs
                                for neuron_time in neuron_times:
                                    ISIs.append(neuron_time - prev)
                                    prev = neuron_time

                                # for this neuron, get stats
                                ISI_mean = numpy.mean(ISIs)
                                ISI_std = numpy.std(ISIs)
                                ISI_cv = ISI_std / ISI_mean

                                if not numpy.isnan(ISI_cv):
                                    ISI_cvs.append(ISI_cv)

                        print(
                            "{}\t{}".format(current_time / 1000.,
                                            numpy.mean(ISI_cvs)),
                            file=fh3, flush=True)

                current_time += dt

            lgr.debug("Printed till {}".format(current_time))
            old_times = numpy.array(times[(left - len(times)):])
            old_neuronIDs = numpy.array(neuronIDs[(left - len(neuronIDs)):])

            del neuronIDs
            del times
            gc.collect()

    lgr.info("Finished processing {}".format(spikes_fn))
    return True