Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve and benchmark auto-merging functions #2934

Closed
wants to merge 241 commits into from
Closed
Show file tree
Hide file tree
Changes from 188 commits
Commits
Show all changes
241 commits
Select commit Hold shift + click to select a range
0087705
WIP
yger May 29, 2024
57f40d8
Starting to reformat merging methods
yger May 30, 2024
ec92c01
WIP
yger May 30, 2024
8e39954
WIP
yger May 30, 2024
f0d8378
WIP
yger May 30, 2024
f453437
WIP
yger May 30, 2024
d5a541d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 30, 2024
08c5583
WIP
yger May 30, 2024
779b619
WIP
yger May 30, 2024
a811f66
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 30, 2024
51517ab
WIP
yger May 30, 2024
2fa8ace
WIP
yger May 30, 2024
fce51e8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 30, 2024
1693e07
WIP
yger May 30, 2024
9377d2c
WIP
yger May 30, 2024
f67b05b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 30, 2024
0c2b502
WIP
yger May 30, 2024
9cef54e
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 30, 2024
6cdddb7
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 30, 2024
8b05581
Merge branch 'main' of github.com:yger/spikeinterface into meta_mergi…
yger May 31, 2024
3f9f556
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 31, 2024
5130db6
WIP
yger May 31, 2024
50135da
More plots
yger May 31, 2024
75963a4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 31, 2024
8f7e2a0
WIP
yger May 31, 2024
d8e7537
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 31, 2024
7e766b0
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 31, 2024
fa48c56
WIP
yger May 31, 2024
5d950a2
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 31, 2024
bfbea8c
Getting rid of lussac imports
yger May 31, 2024
9ecd241
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 31, 2024
4fe600b
Spaces and tabs
yger May 31, 2024
3ccb5f9
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 31, 2024
96be6c8
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 31, 2024
48329eb
Removing lussac imports
yger May 31, 2024
dd52f77
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 31, 2024
20e6ba9
WIP
yger May 31, 2024
60fc057
WIP
yger May 31, 2024
630273c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 31, 2024
3252e26
Fixing display
yger May 31, 2024
bb2c9a6
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger May 31, 2024
043f2a0
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Jun 2, 2024
c0d0333
Merge branch 'main' into meta_merging_sc2
yger Jun 4, 2024
fea71b4
Fix tests
alejoe91 Jun 4, 2024
4bd5fb0
Fix test imports
alejoe91 Jun 4, 2024
982c065
Fix more test imports
alejoe91 Jun 4, 2024
c51e79d
Renaming the drift suggestion for meta merging
yger Jun 4, 2024
31d8180
WIP
yger Jun 4, 2024
bc0898e
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 4, 2024
719a688
WIP
yger Jun 4, 2024
da862d1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 4, 2024
9a69b14
Harmonize
yger Jun 4, 2024
2eee74e
CircusMerging is now able to do handle drift
yger Jun 4, 2024
e153c15
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 4, 2024
cd08b35
WIP
yger Jun 4, 2024
bea35ee
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 4, 2024
4408a66
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2024
d6a9c8d
WIP
yger Jun 5, 2024
df937cf
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 5, 2024
57749ba
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2024
82d021c
Harmonize lussac and circus meta merging
yger Jun 5, 2024
b956e26
Fixing conflicts
yger Jun 5, 2024
3f9f84c
Exploring params
yger Jun 5, 2024
ba459c6
Params
yger Jun 5, 2024
1a1a54b
WIP
yger Jun 5, 2024
283aae9
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2024
0bde7bb
Docs
yger Jun 5, 2024
a71bd10
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 5, 2024
86e73e1
Docs
yger Jun 5, 2024
88c1bc8
Reuse the templates already available
yger Jun 5, 2024
9195a75
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2024
4ab001d
Merge branch 'main' of github.com:spikeinterface/spikeinterface into …
yger Jun 5, 2024
b7f54d7
Harmonize params
yger Jun 5, 2024
9d8a699
Adding possibility to only split cells given SNR
yger Jun 5, 2024
00f0a9f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 5, 2024
7bc1c29
Merge branch 'main' of github.com:spikeinterface/spikeinterface into …
yger Jun 6, 2024
947a35d
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 6, 2024
30a7d36
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 8, 2024
3c0bb86
Handling precomputed similarities for curation
yger Jun 8, 2024
7468a64
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 8, 2024
5ff19a1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 8, 2024
b0dab64
Prepare for the use of template_similarity instead
yger Jun 9, 2024
7f3d365
WIP to integrate Alessio's widget
yger Jun 10, 2024
76cb82d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 10, 2024
5f4fd0e
WIP
yger Jun 10, 2024
5087781
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 10, 2024
4643334
WIP
yger Jun 10, 2024
5d0277e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 10, 2024
fb6d1ba
WIP
yger Jun 10, 2024
a48ac2e
Lussac merging can use new metrics
yger Jun 12, 2024
f560406
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 12, 2024
8aca009
WIP
yger Jun 12, 2024
2c07c6e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 12, 2024
65b01be
Merging curation functions
yger Jun 13, 2024
f0499e6
WIP
yger Jun 13, 2024
f7bd29b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2024
d777fae
WIP
yger Jun 13, 2024
56c3666
WIP
yger Jun 13, 2024
2d8df38
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2024
852521c
WIP
yger Jun 13, 2024
c806d02
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 13, 2024
c9cbd9e
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2024
476fc31
Useless imports
yger Jun 13, 2024
9b30b5e
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 13, 2024
b2f2e8a
Delete Untitled.ipynb
yger Jun 13, 2024
e7f6655
Docs
yger Jun 13, 2024
cc066f1
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 13, 2024
640446a
Cleaning auto merge
yger Jun 13, 2024
7f6ed93
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2024
f201f71
WIP
yger Jun 13, 2024
c287f25
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 13, 2024
6098de8
Refactoring auto merges
yger Jun 13, 2024
1a29125
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 13, 2024
80f914d
Tests
yger Jun 14, 2024
036a729
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 14, 2024
2d3fbf1
Merge branch 'main' into meta_merging_sc2
yger Jun 14, 2024
b9b0dbb
Merge branch 'main' of github.com:spikeinterface/spikeinterface into …
yger Jun 14, 2024
4658758
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 14, 2024
0056eaf
Adding the extra method from Aurelien as a step in auto_merge for cla…
yger Jun 14, 2024
75a8804
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 14, 2024
8afab01
Factorize params
yger Jun 14, 2024
efc621c
Default params
yger Jun 14, 2024
35b71ec
Default params
yger Jun 14, 2024
2ad54dc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 14, 2024
43fe534
Merge branch 'main' into meta_merging_sc2
yger Jun 17, 2024
4358040
WIP
yger Jun 17, 2024
0a1a400
WIP
yger Jun 17, 2024
4856aeb
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 17, 2024
03d9ac6
Merge branch 'main' into meta_merging_sc2
yger Jun 18, 2024
f8b8e6c
WIP
yger Jun 19, 2024
b5b95de
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 19, 2024
e64542f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 19, 2024
07590ce
Merging
yger Jun 19, 2024
56bbe19
Merge branch 'main' into meta_merging_sc2
alejoe91 Jun 21, 2024
5c6edf8
WIP
yger Jun 24, 2024
e0165b3
WIP
yger Jun 24, 2024
2427c22
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 24, 2024
31ddfec
Typo
yger Jun 24, 2024
0c7458e
WIP
yger Jun 24, 2024
2df7ad3
Refactoring
yger Jun 24, 2024
4c2bbcd
Merge branch 'main' into meta_merging_sc2
yger Jun 24, 2024
30f3617
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 24, 2024
4db85c7
Merge branch 'main' of github.com:spikeinterface/spikeinterface into …
yger Jun 26, 2024
10fce9d
Larger params
yger Jun 27, 2024
816f2fd
WIP
yger Jun 27, 2024
e437670
Bug
yger Jun 27, 2024
835ac4f
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Jun 28, 2024
750eba0
Adding Knn merging
yger Jun 28, 2024
3058a2f
WIP
yger Jun 28, 2024
c73e860
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 28, 2024
e5b02a5
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 28, 2024
55460a9
WIP
yger Jun 28, 2024
599755c
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Jun 29, 2024
63da29e
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jun 29, 2024
c3e2115
knn
yger Jun 29, 2024
f609b23
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jun 29, 2024
37ba955
WIP
yger Jul 1, 2024
a67b4d3
WIP
yger Jul 1, 2024
2ac4898
Merge branch 'main' into meta_merging_sc2
alejoe91 Jul 1, 2024
1f323f9
Sync with main
yger Jul 1, 2024
016d7cc
Fixes
yger Jul 2, 2024
71c4876
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 2, 2024
0607450
Adding a curation step for too small SNR
yger Jul 3, 2024
1a18a05
Fixes
yger Jul 3, 2024
478c173
Fix conflicts
alejoe91 Jul 4, 2024
25f740a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 4, 2024
9e9c3fd
Merge branch 'main' into meta_merging_sc2
alejoe91 Jul 4, 2024
a0bb321
cleanup, tests, automerge recordingless + multi-segment
alejoe91 Jul 4, 2024
37c7fb7
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
alejoe91 Jul 4, 2024
ae51c3a
fix tests
alejoe91 Jul 4, 2024
e1c3c31
fix lussac meta-merging component
alejoe91 Jul 4, 2024
bb127c9
Bring back the default mode for auto_merge
yger Jul 4, 2024
fc36bdc
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 4, 2024
6c85de4
Bring back default old behaviour
yger Jul 4, 2024
722ff6a
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 4, 2024
d6d673a
Docs
yger Jul 5, 2024
d6bd776
Merge branch 'main' into meta_merging_sc2
yger Jul 7, 2024
01e5cc1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 7, 2024
84dea85
rebasing
yger Jul 8, 2024
d697b8c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 8, 2024
4d34a61
Merge branch 'main' into meta_merging_sc2
yger Jul 9, 2024
bd61e1b
polishing
yger Jul 9, 2024
6a6073f
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 9, 2024
a52dc64
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 9, 2024
50f6798
Adapt to new names
yger Jul 9, 2024
8449ee9
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 9, 2024
026bab4
Merge branch 'main' of github.com:spikeinterface/spikeinterface into …
yger Jul 9, 2024
ef9c25c
Cleaning
yger Jul 11, 2024
4150d31
Updating to main
yger Jul 15, 2024
b86f3a1
WIP
yger Jul 16, 2024
f906059
Sync with main
yger Jul 16, 2024
2678d54
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 16, 2024
4dccd51
Sync with main
yger Jul 16, 2024
2700fb0
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 16, 2024
b6310de
Merge branch 'patch_release' into meta_merging_sc2
yger Jul 16, 2024
de21fe8
WIP
yger Jul 16, 2024
53f05e5
Merge branch 'patch_release' into meta_merging_sc2
yger Jul 16, 2024
f3c2d7b
WIP
yger Jul 17, 2024
4df391e
Merge branch 'main' of github.com:spikeinterface/spikeinterface into …
yger Jul 17, 2024
87158b5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
98edbdb
Fixing tests
yger Jul 17, 2024
85623ce
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
164fa58
Adding iterative merges
yger Jul 17, 2024
61cde8c
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 17, 2024
c6e1e00
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
d3bb0a2
Refactoring
yger Jul 17, 2024
c9b57d9
Refactoring
yger Jul 17, 2024
c891245
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
64d2780
WIP
yger Jul 17, 2024
878fe99
Bringing back the components
yger Jul 17, 2024
09eeef3
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
2b0c6bc
WIP
yger Jul 17, 2024
44b3e05
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
67526f5
Propagating job kwargs
yger Jul 17, 2024
09c5903
Merge branch 'fix_sa' of github.com:samuelgarcia/spikeinterface into …
yger Jul 17, 2024
7ebabe1
Debugging and trying old analyzers
yger Jul 17, 2024
0134d0d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 17, 2024
5c327fe
WIP
yger Jul 18, 2024
5d88ec2
Merge branch 'fix_sa' of github.com:samuelgarcia/spikeinterface into …
yger Jul 18, 2024
b88909d
Allowing extra_outputs
yger Jul 18, 2024
15934aa
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 18, 2024
e15c676
Bugs
yger Jul 18, 2024
d4fb25c
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 18, 2024
c3f11aa
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 18, 2024
787d3a1
Docs
yger Jul 18, 2024
711d0ff
Merge branch 'meta_merging_sc2' of github.com:yger/spikeinterface int…
yger Jul 18, 2024
3a72d1d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 18, 2024
ba9d955
Ease the view of final merges
yger Jul 18, 2024
b97f60a
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 18, 2024
b0a6212
Merge branch 'main' of https://github.com/SpikeInterface/spikeinterfa…
yger Jul 18, 2024
faebd26
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Jul 18, 2024
e1ef2a0
Avoid erasing already computed extensions
yger Jul 19, 2024
10a1c78
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 19, 2024
970dd95
Force copy of the analyzer
yger Jul 19, 2024
61fc29b
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 19, 2024
d6a7aee
Merge branch 'main' of https://github.com/SpikeInterface/spikeinterfa…
yger Jul 19, 2024
c9d673d
Fixes
yger Jul 23, 2024
5e99875
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Aug 26, 2024
f18124a
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Aug 27, 2024
fb27a6b
WIP
yger Sep 24, 2024
6ec9940
Merge branch 'SpikeInterface:main' into meta_merging_sc2
yger Oct 8, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
580 changes: 407 additions & 173 deletions src/spikeinterface/curation/auto_merge.py

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions src/spikeinterface/curation/curation_tools.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from __future__ import annotations
from typing import Optional
import numpy as np
from spikeinterface import SortingAnalyzer


try:
Expand Down Expand Up @@ -133,3 +134,44 @@ def find_duplicated_spikes(
return _find_duplicated_spikes_keep_last_iterative(spike_train.astype(np.int64), censored_period)
else:
raise ValueError(f"Method '{method}' isn't a valid method for find_duplicated_spikes. Use one of {_methods}")


def remove_empty_units(sorting_or_sorting_analyzer, minimum_spikes=10):
if isinstance(sorting_or_sorting_analyzer, SortingAnalyzer):
sorting = sorting_or_sorting_analyzer.sorting
counts = sorting.get_total_num_spikes()
ids_to_select = []
for id, num_spikes in counts.items():
if num_spikes >= minimum_spikes:
ids_to_select += [id]
return sorting_or_sorting_analyzer.select_units(ids_to_select)
else:
counts = sorting_or_sorting_analyzer.get_total_num_spikes()
ids_to_select = []
for id, num_spikes in counts.items():
if num_spikes >= minimum_spikes:
ids_to_select += [id]
return sorting_or_sorting_analyzer.select_units(ids_to_select)


def resolve_merging_graph(sorting, potential_merges):
"""
Function to provide, given a list of potential_merges, a resolved merging
graph based on the connected components.
"""
from scipy.sparse.csgraph import connected_components
from scipy.sparse import lil_matrix

n = len(sorting.unit_ids)
graph = lil_matrix((n, n))
for i, j in potential_merges:
graph[sorting.id_to_index(i), sorting.id_to_index(j)] = 1

n_components, labels = connected_components(graph, directed=True, connection="weak", return_labels=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why directed ?

final_merges = []
for i in range(n_components):
merges = labels == i
if merges.sum() > 1:
final_merges += [list(sorting.unit_ids[np.flatnonzero(merges)])]

return final_merges
113 changes: 113 additions & 0 deletions src/spikeinterface/curation/merge_temporal_splits.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
from __future__ import annotations
import numpy as np


def presence_distance(sorting, unit1, unit2, bin_duration_s=2, bins=None, num_samples=None):
"""
Compute the presence distance between two units.

The presence distance is defined as the Wasserstein distance between the two histograms of
the firing activity over time.

Parameters
----------
sorting : Sorting
The sorting object.
unit1 : int or str
The id of the first unit.
unit2 : int or str
The id of the second unit.
bin_duration_s : float
The duration of the bin in seconds.
bins : array-like
The bins used to compute the firing rate.
num_samples : list | int | None, default: None
The number of samples for each segment. Required if the sorting doesn't have a recording
attached.

Returns
-------
d : float
The presence distance between the two units.
"""
import scipy

distances = []
if num_samples is not None:
if isinstance(num_samples, int):
num_samples = [num_samples]

if not sorting.has_recording():
if num_samples is None:
raise ValueError("num_samples must be provided if sorting has no recording")
if len(num_samples) != sorting.get_num_segments():
raise ValueError("num_samples must have the same length as the number of segments")

for segment_index in range(sorting.get_num_segments()):
if bins is None:
bin_size = bin_duration_s * sorting.sampling_frequency
if sorting.has_recording():
ns = sorting.get_num_samples(segment_index)
else:
ns = num_samples[segment_index]
bins = np.arange(0, ns, bin_size)

st1 = sorting.get_unit_spike_train(unit_id=unit1)
st2 = sorting.get_unit_spike_train(unit_id=unit2)

h1, _ = np.histogram(st1, bins)
h1 = h1.astype(float)

h2, _ = np.histogram(st2, bins)
h2 = h2.astype(float)

xaxis = bins[1:] / sorting.sampling_frequency
d = scipy.stats.wasserstein_distance(xaxis, xaxis, h1, h2)
distances.append(d)

return np.mean(d)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could have a weith if segment are unbalance no ?



def compute_presence_distance(sorting, pair_mask, num_samples=None, **presence_distance_kwargs):
"""
Get the potential drift-related merges based on similarity and presence completeness.

Parameters
----------
sorting : Sorting
The sorting object
pair_mask : None or boolean array
A bool matrix of size (num_units, num_units) to select
which pair to compute.
num_samples : list | int | None, default: None
The number of samples for each segment. Required if the sorting doesn't have a recording
attached.
presence_distance_threshold : float
The presence distance threshold used to consider two units as similar
presence_distance_kwargs : A dictionary of kwargs to be passed to compute_presence_distance().

Returns
-------
potential_merges : list
The list of potential merges

"""

unit_ids = sorting.unit_ids
n = len(unit_ids)

if pair_mask is None:
pair_mask = np.ones((n, n), dtype="bool")

presence_distances = np.ones((sorting.get_num_units(), sorting.get_num_units()))

for unit_ind1 in range(n):
for unit_ind2 in range(unit_ind1 + 1, n):
if not pair_mask[unit_ind1, unit_ind2]:
continue
unit1 = unit_ids[unit_ind1]
unit2 = unit_ids[unit_ind2]
d = presence_distance(sorting, unit1, unit2, num_samples=num_samples, **presence_distance_kwargs)
presence_distances[unit_ind1, unit_ind2] = d

return presence_distances
67 changes: 40 additions & 27 deletions src/spikeinterface/curation/tests/test_auto_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@
from spikeinterface.curation.tests.common import make_sorting_analyzer, sorting_analyzer_for_curation


def test_get_auto_merge_list(sorting_analyzer_for_curation):
@pytest.mark.parametrize("preset", ["lussac", "knn", "temporal_splits", None])
def test_get_auto_merge_list(sorting_analyzer_for_curation, preset):

print(sorting_analyzer_for_curation)
sorting = sorting_analyzer_for_curation.sorting
recording = sorting_analyzer_for_curation.recording
num_unit_splited = 1
Expand All @@ -34,32 +36,43 @@ def test_get_auto_merge_list(sorting_analyzer_for_curation):
sorting_analyzer.compute("random_spikes")
sorting_analyzer.compute("waveforms", **job_kwargs)
sorting_analyzer.compute("templates")

potential_merges, outs = get_potential_auto_merge(
sorting_analyzer,
minimum_spikes=1000,
maximum_distance_um=150.0,
peak_sign="neg",
bin_ms=0.25,
window_ms=100.0,
corr_diff_thresh=0.16,
template_diff_thresh=0.25,
censored_period_ms=0.0,
refractory_period_ms=4.0,
sigma_smooth_ms=0.6,
contamination_threshold=0.2,
adaptative_window_threshold=0.5,
num_channels=5,
num_shift=5,
firing_contamination_balance=1.5,
extra_outputs=True,
)

assert len(potential_merges) == num_unit_splited
for true_pair in other_ids.values():
true_pair = tuple(true_pair)
assert true_pair in potential_merges

sorting_analyzer.compute(["spike_amplitudes", "spike_locations"])

if preset is not None:
potential_merges, outs = get_potential_auto_merge(
sorting_analyzer,
preset=preset,
minimum_spikes=1000,
maximum_distance_um=150.0,
peak_sign="neg",
bin_ms=0.25,
window_ms=100.0,
corr_diff_thresh=0.16,
template_diff_thresh=0.25,
censored_period_ms=0.0,
refractory_period_ms=4.0,
sigma_smooth_ms=0.6,
contamination_threshold=0.2,
adaptative_window_threshold=0.5,
num_channels=5,
num_shift=5,
firing_contamination_balance=1.5,
extra_outputs=True,
)
if preset == "lussac":
assert len(potential_merges) == num_unit_splited
for true_pair in other_ids.values():
true_pair = tuple(true_pair)
assert true_pair in potential_merges
else:
# when preset is None you have to specify the steps
with pytest.raises(ValueError):
potential_merges = get_potential_auto_merge(sorting_analyzer, preset=preset)
potential_merges = get_potential_auto_merge(
sorting_analyzer, preset=preset, steps=["min_spikes", "min_snr", "remove_contaminated", "unit_positions"]
)

# DEBUG
# import matplotlib.pyplot as plt
# from spikeinterface.curation.auto_merge import normalize_correlogram
# templates_diff = outs['templates_diff']
Expand Down
101 changes: 101 additions & 0 deletions src/spikeinterface/generation/drift_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,3 +577,104 @@ def get_traces(

def get_num_samples(self) -> int:
return self.num_samples


def split_sorting_by_times(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put this function in anotehr file

sorting_analyzer, splitting_probability=0.5, partial_split_prob=0.95, unit_ids=None, min_snr=None, seed=None
):
sa = sorting_analyzer
sorting = sa.sorting
rng = np.random.RandomState(seed)

sorting_split = sorting.select_units(sorting.unit_ids)
split_units = []
original_units = []
nb_splits = int(splitting_probability * len(sorting.unit_ids))
if unit_ids is None:
select_from = sorting.unit_ids
if min_snr is not None:
if sa.get_extension("noise_levels") is None:
sa.compute("noise_levels")
if sa.get_extension("quality_metrics") is None:
sa.compute("quality_metrics", metric_names=["snr"])

snr = sa.get_extension("quality_metrics").get_data()["snr"].values
select_from = select_from[snr > min_snr]

to_split_ids = rng.choice(select_from, nb_splits, replace=False)
else:
to_split_ids = unit_ids

import spikeinterface.curation as scur
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be sfaer to not use this and use directy numpy like the other function


for unit in to_split_ids:
num_spikes = len(sorting_split.get_unit_spike_train(unit))
indices = np.zeros(num_spikes, dtype=int)
indices[: num_spikes // 2] = (rng.rand(num_spikes // 2) < partial_split_prob).astype(int)
indices[num_spikes // 2 :] = (rng.rand(num_spikes - num_spikes // 2) < 1 - partial_split_prob).astype(int)
sorting_split = scur.split_unit_sorting(
sorting_split, split_unit_id=unit, indices_list=indices, properties_policy="remove"
)
split_units.append(sorting_split.unit_ids[-2:])
original_units.append(unit)
return sorting_split, split_units


def split_sorting_by_amplitudes(sorting_analyzer, splitting_probability=0.5, unit_ids=None, min_snr=None, seed=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would put this function in another file

"""
Fonction used to split a sorting based on the amplitudes of the units. This
might be used for benchmarking meta merging step (see components)
"""

sa = sorting_analyzer
if sa.get_extension("spike_amplitudes") is None:
sa.compute("spike_amplitudes")

rng = np.random.RandomState(seed)

from spikeinterface.core.numpyextractors import NumpySorting
from spikeinterface.core.template_tools import get_template_extremum_channel

extremum_channel_inds = get_template_extremum_channel(sa, outputs="index")
spikes = sa.sorting.to_spike_vector(extremum_channel_inds=extremum_channel_inds)
new_spikes = spikes.copy()
amplitudes = sa.get_extension("spike_amplitudes").get_data()
nb_splits = int(splitting_probability * len(sa.sorting.unit_ids))

if unit_ids is None:
select_from = sa.sorting.unit_ids
if min_snr is not None:
if sa.get_extension("noise_levels") is None:
sa.compute("noise_levels")
if sa.get_extension("quality_metrics") is None:
sa.compute("quality_metrics", metric_names=["snr"])

snr = sa.get_extension("quality_metrics").get_data()["snr"].values
select_from = select_from[snr > min_snr]
to_split_ids = rng.choice(select_from, nb_splits, replace=False)
else:
to_split_ids = unit_ids

max_index = np.max(spikes["unit_index"])
new_unit_ids = list(sa.sorting.unit_ids.copy())
splitted_pairs = []
for unit_id in to_split_ids:
ind_mask = spikes["unit_index"] == sa.sorting.id_to_index(unit_id)

m = amplitudes[ind_mask].mean()
s = amplitudes[ind_mask].std()
thresh = m + 0.2 * s

amplitude_mask = amplitudes > thresh
mask = ind_mask & amplitude_mask
new_spikes["unit_index"][mask] = max_index + 1

amplitude_mask = (amplitudes > m) * (amplitudes < thresh)
mask = ind_mask & amplitude_mask
new_spikes["unit_index"][mask] = (max_index + 1) * rng.rand(np.sum(mask)) > 0.5
max_index += 1
new_unit_ids += [max(new_unit_ids) + 1]
splitted_pairs += [(unit_id, new_unit_ids[-1])]

new_sorting = NumpySorting(new_spikes, sampling_frequency=sa.sampling_frequency, unit_ids=new_unit_ids)
return new_sorting, splitted_pairs
Loading