def shuffleRows(self,
                    min_cbin, max_cbin, width_cbin,
                    min_ibin, max_ibin, width_ibin,
                    tracks_map,  groups,
                    difference, s_max=100, i=1):

        # make bins with an extra bin at the end to capture spike-ins with
        # initial or changes values over the intended range.
        # these are ignored later
        c_bins = np.arange(min_cbin, max_cbin+width_cbin, width_cbin)
        i_bins = np.arange(min_ibin, max_ibin+width_ibin, width_ibin)

        bin_counts = np.zeros((len(i_bins) + 1, len(c_bins) + 1))

        indices = {(key1, key2): []
                   for key1 in np.digitize(i_bins, i_bins)
                   for key2 in np.digitize(c_bins, c_bins)}

        min_occup = min(bin_counts.flatten())

        for iteration in range(0,  i):
            E.info("performing shuffling iteration number %i.." % (
                iteration + 1))
            if min_occup < s_max:
                group1_rand = copy.copy(self.table.index.tolist())
                group2_rand = copy.copy(self.table.index.tolist())
                random.shuffle(group1_rand)
                random.shuffle(group2_rand)

                # subset the dataframe rows in the first random order
                # and by the column_ids in the first group
                # and return means across columns. Repeat for group2
                group1_mean = self.table.ix[group1_rand,
                                            tracks_map[groups[0]]].apply(
                                                np.mean, axis=1).tolist()
                group2_mean = self.table.ix[group2_rand,
                                            tracks_map[groups[1]]].apply(
                                                np.mean, axis=1).tolist()

                # retrieve the index for the bin in
                # which each index value falls
                change_idx, initial_idx = means2idxarrays(
                    group1_mean, group2_mean, i_bins, c_bins, difference)

                # for each initial and change value coordinate
                for idx, coord in enumerate(zip(initial_idx, change_idx)):
                    # ignore spike-in if change or initial fall into the final bin
                    if coord[0] < len(i_bins) and coord[1] < len(c_bins):
                        if coord in indices.keys():
                            # if max fill of bin not reached
                            if bin_counts[coord] < s_max:
                                # ...append tuple of df indeces for groups
                                bin_counts[coord] += 1
                                indices[coord].append((group1_rand[idx],
                                                       group2_rand[idx]))

                    # find the minimum value in the counts array this should
                    # save time if all bins are filled before final iteration
                    min_occup = min(bin_counts.flatten())

        E.info("The largest bin has %i entries" % max(bin_counts.flatten()))

        return indices, bin_counts
take a dataframe and shuffle the rows to obtain spike in rows.
dataset/ETHPy150Open CGATOxford/cgat/CGAT/Counts.py/Counts.shuffleRows