AnoushkaJain3
commited on
Commit
•
54da53e
1
Parent(s):
227cac9
Upload 2 files
Browse files- model_based_curation_tutorial.ipynb +617 -0
- train_new_model.ipynb +0 -0
model_based_curation_tutorial.ipynb
ADDED
@@ -0,0 +1,617 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"cells": [
|
3 |
+
{
|
4 |
+
"cell_type": "markdown",
|
5 |
+
"metadata": {},
|
6 |
+
"source": [
|
7 |
+
"## Model Based Curation Tutorial\n",
|
8 |
+
"#### This notebook provides a step-by-step guide on how to use machine learning classifier for curating spike sorted output into 'noise', multi-unit-activity' (MUA) and 'single-unit-activity' (SUA) using Spikeinterface. \n",
|
9 |
+
"\n",
|
10 |
+
"\n",
|
11 |
+
"#### To use this, you should have already done spike sorting.\n",
|
12 |
+
"#### In this notebook we will compute quality metrics and load machine model to predict curation labels for previously uncurated electrophysiology data.\n",
|
13 |
+
"#### The classifier is trained on Neuropixels data from 11 mice recorded in V1,SC and ALM\n",
|
14 |
+
"\n"
|
15 |
+
]
|
16 |
+
},
|
17 |
+
{
|
18 |
+
"cell_type": "code",
|
19 |
+
"execution_count": 19,
|
20 |
+
"metadata": {},
|
21 |
+
"outputs": [
|
22 |
+
{
|
23 |
+
"name": "stdout",
|
24 |
+
"output_type": "stream",
|
25 |
+
"text": [
|
26 |
+
"Number of cores set to: 23\n"
|
27 |
+
]
|
28 |
+
}
|
29 |
+
],
|
30 |
+
"source": [
|
31 |
+
"from pathlib import Path\n",
|
32 |
+
"import numpy as np\n",
|
33 |
+
"import pandas as pd\n",
|
34 |
+
"import matplotlib.pyplot as plt\n",
|
35 |
+
"import spikeinterface as si\n",
|
36 |
+
"import spikeinterface.extractors as se\n",
|
37 |
+
"import spikeinterface.postprocessing as spost\n",
|
38 |
+
"import spikeinterface.qualitymetrics as sqm\n",
|
39 |
+
"import os\n",
|
40 |
+
"from os import cpu_count\n",
|
41 |
+
"import json\n",
|
42 |
+
"# Set the number of CPU cores to be used globally - defaults to all cores -1\n",
|
43 |
+
"n_cores = cpu_count() -1\n",
|
44 |
+
"si.set_global_job_kwargs(n_jobs = n_cores)\n",
|
45 |
+
"print(f\"Number of cores set to: {n_cores}\")\n",
|
46 |
+
"\n",
|
47 |
+
"# SET OUTPUT FOLDER\n",
|
48 |
+
"output_folder = Path(r\"E:\\spikeinterface_outputs\")"
|
49 |
+
]
|
50 |
+
},
|
51 |
+
{
|
52 |
+
"cell_type": "code",
|
53 |
+
"execution_count": null,
|
54 |
+
"metadata": {},
|
55 |
+
"outputs": [],
|
56 |
+
"source": [
|
57 |
+
"import spikeinterface\n",
|
58 |
+
"print(spikeinterface.__version__)"
|
59 |
+
]
|
60 |
+
},
|
61 |
+
{
|
62 |
+
"cell_type": "markdown",
|
63 |
+
"metadata": {},
|
64 |
+
"source": [
|
65 |
+
"# Load data "
|
66 |
+
]
|
67 |
+
},
|
68 |
+
{
|
69 |
+
"cell_type": "markdown",
|
70 |
+
"metadata": {},
|
71 |
+
"source": [
|
72 |
+
"## First step: Loading the recording and sorting objects"
|
73 |
+
]
|
74 |
+
},
|
75 |
+
{
|
76 |
+
"cell_type": "markdown",
|
77 |
+
"metadata": {},
|
78 |
+
"source": [
|
79 |
+
"For the tutorial, we are using simulated data to create recording and sorting objects."
|
80 |
+
]
|
81 |
+
},
|
82 |
+
{
|
83 |
+
"cell_type": "code",
|
84 |
+
"execution_count": 22,
|
85 |
+
"metadata": {},
|
86 |
+
"outputs": [],
|
87 |
+
"source": [
|
88 |
+
"# Generate a synthetic recording\n",
|
89 |
+
"recording = si.generate_recording(num_channels=50, sampling_frequency=30000.,\n",
|
90 |
+
" durations=[30], set_probe=True)\n",
|
91 |
+
"# load your recoring depeding on the acquistion software you used, for example:\n",
|
92 |
+
"# recording = se.read_spikeglx(recording_path, stream_name='imec0.ap')\n",
|
93 |
+
"\n",
|
94 |
+
"# Generate a synthetic sorting\n",
|
95 |
+
"sorting = si.generate_sorting(num_units=100, sampling_frequency=30000., durations=[30],\n",
|
96 |
+
" firing_rates=15, refractory_period_ms=1.5)\n",
|
97 |
+
"# load your sorting depeding on the which spike sorter you used, for example:\n",
|
98 |
+
"# sorting = se.read_kilosort(folder_path)"
|
99 |
+
]
|
100 |
+
},
|
101 |
+
{
|
102 |
+
"cell_type": "markdown",
|
103 |
+
"metadata": {},
|
104 |
+
"source": [
|
105 |
+
"## Second step: Create SortingAnalyzer "
|
106 |
+
]
|
107 |
+
},
|
108 |
+
{
|
109 |
+
"cell_type": "markdown",
|
110 |
+
"metadata": {},
|
111 |
+
"source": [
|
112 |
+
"SortingAnalyzer is a postprocessing module which is used to compute quality metrics and template metrics.\n",
|
113 |
+
"To know more about it, please refer to : https://spikeinterface.readthedocs.io/en/latest/modules/postprocessing.html\n",
|
114 |
+
"\n",
|
115 |
+
"If you have already have WaveformExtractor from previous run, you can use it to create a SortingAnalyzer. \n",
|
116 |
+
"Please refer to: https://spikeinterface.readthedocs.io/en/latest/tutorials/waveform_extractor_to_sorting_analyzer.html\n"
|
117 |
+
]
|
118 |
+
},
|
119 |
+
{
|
120 |
+
"cell_type": "code",
|
121 |
+
"execution_count": null,
|
122 |
+
"metadata": {},
|
123 |
+
"outputs": [],
|
124 |
+
"source": [
|
125 |
+
"analyzer = si.create_sorting_analyzer(sorting = sorting, recording = recording, sparse = True)"
|
126 |
+
]
|
127 |
+
},
|
128 |
+
{
|
129 |
+
"cell_type": "markdown",
|
130 |
+
"metadata": {},
|
131 |
+
"source": [
|
132 |
+
"## Third step: Compute metrics"
|
133 |
+
]
|
134 |
+
},
|
135 |
+
{
|
136 |
+
"cell_type": "markdown",
|
137 |
+
"metadata": {},
|
138 |
+
"source": [
|
139 |
+
"Quality metrics serve as features for the machine learning model. We generate these metrics and use the model to predict labels based on them."
|
140 |
+
]
|
141 |
+
},
|
142 |
+
{
|
143 |
+
"cell_type": "code",
|
144 |
+
"execution_count": 13,
|
145 |
+
"metadata": {},
|
146 |
+
"outputs": [],
|
147 |
+
"source": [
|
148 |
+
"# Defines a function to compute all analyzer properties and quality metrics\n",
|
149 |
+
"# Note: this can be a time-consuming step, especially computing PCA-based metrics for long recordings\n",
|
150 |
+
"\n",
|
151 |
+
"def compute_all_metrics(analyzer):\n",
|
152 |
+
"\n",
|
153 |
+
" # Compute required extensions for quality metrics\n",
|
154 |
+
" analyzer.compute({\n",
|
155 |
+
"\t'noise_levels': {},\n",
|
156 |
+
"\t'random_spikes': {'max_spikes_per_unit': 1_000},\n",
|
157 |
+
"\t'templates': {'ms_before': 1.5, 'ms_after': 3.5},\n",
|
158 |
+
"\t'spike_amplitudes': {},\n",
|
159 |
+
"\t'waveforms': {},\n",
|
160 |
+
"\t'principal_components': {},\n",
|
161 |
+
"\t'spike_locations': {},\n",
|
162 |
+
"\t'unit_locations': {},\n",
|
163 |
+
"\t})\n",
|
164 |
+
"\n",
|
165 |
+
" # Compute all available quality metrics\n",
|
166 |
+
" analyzer.compute(\"quality_metrics\", metric_names = sqm.get_quality_metric_list() + sqm.get_quality_pca_metric_list())\n",
|
167 |
+
" analyzer.compute(\"template_metrics\", metric_names = spost.get_template_metric_names())\n",
|
168 |
+
"\n",
|
169 |
+
"\t# Make metric dataframe\n",
|
170 |
+
" quality_metrics = analyzer.extensions['quality_metrics'].data[\"metrics\"]\n",
|
171 |
+
" template_metrics = analyzer.extensions['template_metrics'].data[\"metrics\"]\n",
|
172 |
+
" calculated_metrics = pd.concat([quality_metrics, template_metrics], axis = 1)\n",
|
173 |
+
"\n",
|
174 |
+
" return calculated_metrics"
|
175 |
+
]
|
176 |
+
},
|
177 |
+
{
|
178 |
+
"cell_type": "code",
|
179 |
+
"execution_count": null,
|
180 |
+
"metadata": {},
|
181 |
+
"outputs": [],
|
182 |
+
"source": [
|
183 |
+
"# Compute all metrics\n",
|
184 |
+
"metrics = compute_all_metrics(analyzer)\n",
|
185 |
+
"metrics.index.name = 'cluster_id'"
|
186 |
+
]
|
187 |
+
},
|
188 |
+
{
|
189 |
+
"cell_type": "code",
|
190 |
+
"execution_count": null,
|
191 |
+
"metadata": {},
|
192 |
+
"outputs": [],
|
193 |
+
"source": [
|
194 |
+
"# save the analyzer\n",
|
195 |
+
"analyzer.save_as(folder=output_folder / 'sorting_analyzer', format=\"binary_folder\")"
|
196 |
+
]
|
197 |
+
},
|
198 |
+
{
|
199 |
+
"cell_type": "markdown",
|
200 |
+
"metadata": {},
|
201 |
+
"source": [
|
202 |
+
"## Load a pretrained model from the Hugging Face Hub"
|
203 |
+
]
|
204 |
+
},
|
205 |
+
{
|
206 |
+
"cell_type": "markdown",
|
207 |
+
"metadata": {},
|
208 |
+
"source": [
|
209 |
+
"## First we use noise vs neuron classifier"
|
210 |
+
]
|
211 |
+
},
|
212 |
+
{
|
213 |
+
"cell_type": "code",
|
214 |
+
"execution_count": 20,
|
215 |
+
"metadata": {},
|
216 |
+
"outputs": [],
|
217 |
+
"source": [
|
218 |
+
"analyzer = si.load_sorting_analyzer(folder= output_folder / 'sorting_analyzer', format=\"binary_folder\")"
|
219 |
+
]
|
220 |
+
},
|
221 |
+
{
|
222 |
+
"cell_type": "code",
|
223 |
+
"execution_count": 21,
|
224 |
+
"metadata": {},
|
225 |
+
"outputs": [
|
226 |
+
{
|
227 |
+
"name": "stderr",
|
228 |
+
"output_type": "stream",
|
229 |
+
"text": [
|
230 |
+
"C:\\Users\\jain\\Documents\\Github_extend\\spikeinterface\\src\\spikeinterface\\curation\\model_based_curation.py:353: UserWarning: No 'model_info.json' file found in folder. No metadata can be checked.\n",
|
231 |
+
" warnings.warn(\"No 'model_info.json' file found in folder. No metadata can be checked.\")\n"
|
232 |
+
]
|
233 |
+
}
|
234 |
+
],
|
235 |
+
"source": [
|
236 |
+
"import skops.io as sio\n",
|
237 |
+
"from huggingface_hub import hf_hub_download\n",
|
238 |
+
"\n",
|
239 |
+
"model_path = hf_hub_download(\"AnoushkaJain3/curation_machine_learning_models\", \"noise_neuron_model.skops\")\n",
|
240 |
+
"untrusted_types = sio.get_untrusted_types(file=model_path)\n",
|
241 |
+
"\n",
|
242 |
+
"# Load pretrained noise/neural activity model and predict on unlabelled data\n",
|
243 |
+
"from spikeinterface.curation.model_based_curation import auto_label_units\n",
|
244 |
+
"\n",
|
245 |
+
"label_conversion = {1: 'noise',0: 'neuron'}\n",
|
246 |
+
"\n",
|
247 |
+
"label_dict_noise = auto_label_units(sorting_analyzer = analyzer,\n",
|
248 |
+
" repo_id = \"AnoushkaJain3/curation_machine_learning_models\",\n",
|
249 |
+
" model_name= 'noise_neuron_model.skops',\n",
|
250 |
+
" label_conversion=label_conversion,\n",
|
251 |
+
" trusted= untrusted_types\n",
|
252 |
+
" )"
|
253 |
+
]
|
254 |
+
},
|
255 |
+
{
|
256 |
+
"cell_type": "markdown",
|
257 |
+
"metadata": {},
|
258 |
+
"source": [
|
259 |
+
"## Second we use sua vs mua classifier"
|
260 |
+
]
|
261 |
+
},
|
262 |
+
{
|
263 |
+
"cell_type": "code",
|
264 |
+
"execution_count": 22,
|
265 |
+
"metadata": {},
|
266 |
+
"outputs": [
|
267 |
+
{
|
268 |
+
"name": "stderr",
|
269 |
+
"output_type": "stream",
|
270 |
+
"text": [
|
271 |
+
"C:\\Users\\jain\\Documents\\Github_extend\\spikeinterface\\src\\spikeinterface\\curation\\model_based_curation.py:353: UserWarning: No 'model_info.json' file found in folder. No metadata can be checked.\n",
|
272 |
+
" warnings.warn(\"No 'model_info.json' file found in folder. No metadata can be checked.\")\n"
|
273 |
+
]
|
274 |
+
}
|
275 |
+
],
|
276 |
+
"source": [
|
277 |
+
"model_path = hf_hub_download(\"AnoushkaJain3/curation_machine_learning_models\", \"sua_mua_model.skops\")\n",
|
278 |
+
"untrusted_types = sio.get_untrusted_types(file=model_path)\n",
|
279 |
+
"\n",
|
280 |
+
"label_conversion = {1: 'sua',0: 'mua'}\n",
|
281 |
+
"\n",
|
282 |
+
"label_dict_sua= auto_label_units(sorting_analyzer = analyzer,\n",
|
283 |
+
" repo_id = \"AnoushkaJain3/curation_machine_learning_models\",\n",
|
284 |
+
" model_name= 'sua_mua_model.skops',\n",
|
285 |
+
" label_conversion=label_conversion,\n",
|
286 |
+
" trusted= untrusted_types\n",
|
287 |
+
" )"
|
288 |
+
]
|
289 |
+
},
|
290 |
+
{
|
291 |
+
"cell_type": "markdown",
|
292 |
+
"metadata": {},
|
293 |
+
"source": [
|
294 |
+
"## Combine the predictions and probabilities from the two models"
|
295 |
+
]
|
296 |
+
},
|
297 |
+
{
|
298 |
+
"cell_type": "code",
|
299 |
+
"execution_count": 23,
|
300 |
+
"metadata": {},
|
301 |
+
"outputs": [
|
302 |
+
{
|
303 |
+
"name": "stdout",
|
304 |
+
"output_type": "stream",
|
305 |
+
"text": [
|
306 |
+
"{0: ('noise', 0.6136904761904761), 1: ('noise', 0.5225), 2: ('noise', 0.6099285714285715), 3: ('noise', 0.6553571428571427), 4: ('noise', 0.6146904761904761), 5: ('noise', 0.6320238095238095), 6: ('noise', 0.6036904761904761), 7: ('noise', 0.6036904761904761), 8: ('noise', 0.7125), 9: ('noise', 0.6025), 10: ('noise', 0.5891666666666666), 11: ('noise', 0.6911666666666666), 12: ('noise', 0.7113571428571429), 13: ('noise', 0.6826904761904761), 14: ('noise', 0.6248333333333334), 15: ('noise', 0.6308333333333335), 16: ('noise', 0.5936904761904762), 17: ('noise', 0.6193571428571428), 18: ('noise', 0.5803571428571428), 19: ('noise', 0.5836904761904761), 20: ('noise', 0.6753571428571428), 21: ('noise', 0.5824999999999999), 22: ('noise', 0.6633333333333333), 23: ('noise', 0.6806904761904762), 24: ('noise', 0.6986904761904762), 25: ('noise', 0.7125), 26: ('noise', 0.6036904761904761), 27: ('noise', 0.6633571428571429), 28: ('noise', 0.6958333333333333), 29: ('noise', 0.6136904761904761), 30: ('noise', 0.6093571428571428), 31: ('noise', 0.5338333333333334), 32: ('noise', 0.5577380952380951), 33: ('noise', 0.6425), 34: ('noise', 0.5836904761904761), 35: ('noise', 0.5910714285714286), 36: ('noise', 0.5458333333333333), 37: ('noise', 0.6320238095238095), 38: ('noise', 0.6353571428571428), 39: ('noise', 0.6591666666666667), 40: ('noise', 0.6453571428571427), 41: ('noise', 0.6508333333333334), 42: ('noise', 0.6420238095238094), 43: ('noise', 0.7020238095238095), 44: ('noise', 0.6541666666666666), 45: ('noise', 0.6625), 46: ('noise', 0.6986904761904762), 47: ('noise', 0.6886904761904762), 48: ('noise', 0.6236904761904761), 49: ('noise', 0.6008333333333333), 50: ('noise', 0.6786904761904762), 51: ('noise', 0.6276666666666667), 52: ('noise', 0.5775), 53: ('noise', 0.7025), 54: ('noise', 0.6225), 55: ('noise', 0.5825), 56: ('noise', 0.6708333333333334), 57: ('noise', 0.6203571428571428), 58: ('noise', 0.6753571428571428), 59: ('noise', 0.6653571428571428), 60: ('noise', 0.7226904761904762), 61: ('noise', 0.6225), 62: ('noise', 0.6753571428571428), 63: ('noise', 0.6548333333333334), 64: ('noise', 0.7358333333333333), 65: ('noise', 0.6593571428571429), 66: ('noise', 0.6600238095238095), 67: ('noise', 0.5974999999999999), 68: ('noise', 0.6036904761904761), 69: ('noise', 0.6386904761904761), 70: ('noise', 0.6886904761904762), 71: ('noise', 0.6403571428571427), 72: ('noise', 0.6586904761904762), 73: ('noise', 0.7053571428571429), 74: ('noise', 0.5651666666666667), 75: ('noise', 0.5941666666666666), 76: ('noise', 0.5975), 77: ('noise', 0.6986904761904762), 78: ('noise', 0.7058333333333333), 79: ('noise', 0.6830238095238096), 80: ('noise', 0.6886904761904762), 81: ('noise', 0.6796666666666666), 82: ('noise', 0.6886904761904762), 83: ('noise', 0.6141666666666666), 84: ('noise', 0.5966666666666667), 85: ('noise', 0.7021666666666667), 86: ('noise', 0.6608333333333334), 87: ('noise', 0.6926904761904763), 88: ('noise', 0.6720238095238095), 89: ('noise', 0.5858333333333333), 90: ('noise', 0.6425), 91: ('noise', 0.5908333333333333), 92: ('noise', 0.6175), 93: ('noise', 0.6170238095238095), 94: ('noise', 0.6308333333333332), 95: ('noise', 0.6041666666666666), 96: ('noise', 0.6236904761904761), 97: ('noise', 0.5891666666666666), 98: ('noise', 0.6248333333333334), 99: ('noise', 0.6805000000000001)}\n"
|
307 |
+
]
|
308 |
+
}
|
309 |
+
],
|
310 |
+
"source": [
|
311 |
+
"# Combine data\n",
|
312 |
+
"decoder_output = {}\n",
|
313 |
+
"\n",
|
314 |
+
"for key, value in label_dict_noise.items():\n",
|
315 |
+
" label, prob1 = value\n",
|
316 |
+
" if label == 'noise':\n",
|
317 |
+
" decoder_output[key] = (label, prob1) # Keep 'noise' and its probability\n",
|
318 |
+
" else:\n",
|
319 |
+
" sua_mua_label, prob2 = label_dict_sua[key] # Get 'sua' or 'mua' label and its probability\n",
|
320 |
+
" decoder_output[key] = (sua_mua_label, prob2) # Replace 'neuron' with 'sua'/'mua' and their probabilities\n",
|
321 |
+
"\n",
|
322 |
+
"# Print the resulting combined data\n",
|
323 |
+
"print(decoder_output)\n",
|
324 |
+
"\n",
|
325 |
+
"# Save the decoder output\n",
|
326 |
+
"with open(output_folder / 'decoder_output.json', 'w') as f:\n",
|
327 |
+
" json.dump(decoder_output, f)"
|
328 |
+
]
|
329 |
+
},
|
330 |
+
{
|
331 |
+
"cell_type": "markdown",
|
332 |
+
"metadata": {},
|
333 |
+
"source": [
|
334 |
+
"## Assess model performance by comparing with human labels"
|
335 |
+
]
|
336 |
+
},
|
337 |
+
{
|
338 |
+
"cell_type": "markdown",
|
339 |
+
"metadata": {},
|
340 |
+
"source": [
|
341 |
+
"To assess the performance of the model relative to human labels, we can load (or here generate randomly) some labels, and plot a confusion matrix of predicted vs human labels for all clusters"
|
342 |
+
]
|
343 |
+
},
|
344 |
+
{
|
345 |
+
"cell_type": "code",
|
346 |
+
"execution_count": 24,
|
347 |
+
"metadata": {},
|
348 |
+
"outputs": [
|
349 |
+
{
|
350 |
+
"data": {
|
351 |
+
"image/png": "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BAYG6jMOIiIi08VVG0RERKQtQ9zZ8lXhqg0iIiLSGisSRERE+saKBBEREZE6ViSIiIj0zJTnSGicSDx+/Bhz587Fnj17kJmZCYVCobL/77//1llwREREZNw0TiT+85//4MCBA3jrrbfg6elplDehGmmfaegQiIzSj/A0dAhE/05c/vk/O3fuxPbt29GmTRt9xENERGR6THhoQ+PJlk5OTnB2dtZHLERERPSa0TiRmD17NmbMmIG8vDx9xENERGR6hI42I6Tx0Ma8efNw7do1uLu7o2bNmrCwsFDZf+rUKZ0FR0REZAq4auMZffr00UMYRERE9DrSOJGIjo7WRxxERESmixUJIiIi0hoTif8pLi7GggULsG7dOqSmpqKgoEBl/z///KOz4IiIiMi4abxqIyYmBvPnz8fgwYORk5ODqKgo9OvXD1KpFDNnztRDiERERK83idDNZow0TiQSExOxYsUKvPvuuzA3N8fQoUPx7bffYsaMGTh27Jg+YiQiInq9CYluNiOkcSKRnp4OX19fAICtrS1ycnIAAD169MD27dt1Gx0REZEpMOH7SGicSFSrVg1paWkAgNq1a+OXX34BAJw4cQIymUy30REREZFR0ziR6Nu3L/bs2QMAmDhxIj7++GPUrVsXYWFhGD16tM4DJCIiet2Z8hwJjVdtzJ07V/n14MGDUaNGDRw9ehR169ZFz549dRocERGRSTDSJEAXXvo+EgEBAQgICNBFLERERPSa0SqRuHv3Lg4fPozMzEwoFAqVfZMmTdJJYERERKbCWIcldEHjRCIhIQFjx46FpaUlXFxcIJH8bzmKRCJhIkFERPQ8JhL/8/HHH2PGjBmYPn06pFKN52oSERGRCdE4kcjLy8OQIUOYRBAREVWUCVckNM4GxowZg6SkJH3EQkREZJK4/PMZsbGx6NGjB3bt2gVfX19YWFio7J8/f77OgiMiIiLjplUisXv3btSvXx8A1CZbEhER0b+HxonEvHnzsGrVKowcOVIP4RAREZkgIx2W0AWNEwmZTIY2bdroIxYiIiKTZKzzG3RB48mWkydPxuLFi/URCxEREb1mNK5I/P7779i7dy+2bduGRo0aqU223Lhxo86CIyIiMgkmXJHQOJFwdHREv3799BELERGRaWIi8T/x8fH6iIOIiIheQy/99E8iIiIqnylPttQ4kfD29i73fhF/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",
|
352 |
+
"text/plain": [
|
353 |
+
"<Figure size 640x480 with 2 Axes>"
|
354 |
+
]
|
355 |
+
},
|
356 |
+
"metadata": {},
|
357 |
+
"output_type": "display_data"
|
358 |
+
}
|
359 |
+
],
|
360 |
+
"source": [
|
361 |
+
"from sklearn.metrics import confusion_matrix, balanced_accuracy_score\n",
|
362 |
+
"import seaborn as sns\n",
|
363 |
+
"\n",
|
364 |
+
"# Use 'ground-truth' labels to check prediction accuracy\n",
|
365 |
+
"# These are assigned randomly here but you could load these from phy 'cluster_group.tsv', from the 'quality' property of the sorting, or similar\n",
|
366 |
+
"human_labels = np.random.choice(list(label_conversion.values()), analyzer.get_num_units())\n",
|
367 |
+
"\n",
|
368 |
+
"# Get labels from phy sorting (if loaded) using:\n",
|
369 |
+
"# human_labels = unlabelled_analyzer.sorting.get_property('quality')\n",
|
370 |
+
"\n",
|
371 |
+
"predictions = analyzer.sorting.get_property('label_prediction')\n",
|
372 |
+
"\n",
|
373 |
+
"conf_matrix = confusion_matrix(human_labels, predictions)\n",
|
374 |
+
"\n",
|
375 |
+
"# Calculate balanced accuracy for the confusion matrix\n",
|
376 |
+
"balanced_accuracy = balanced_accuracy_score(human_labels, predictions)\n",
|
377 |
+
"\n",
|
378 |
+
"sns.heatmap(conf_matrix, annot=True, fmt='d', cmap='viridis')\n",
|
379 |
+
"plt.xlabel('Predicted Label')\n",
|
380 |
+
"plt.ylabel('Human Label')\n",
|
381 |
+
"plt.xticks(ticks = [0.5, 1.5], labels = list(label_conversion.values()))\n",
|
382 |
+
"plt.yticks(ticks = [0.5, 1.5], labels = list(label_conversion.values()))\n",
|
383 |
+
"plt.title('Predicted vs Human Label')\n",
|
384 |
+
"plt.suptitle(f\"Balanced Accuracy: {balanced_accuracy}\")\n",
|
385 |
+
"plt.show()"
|
386 |
+
]
|
387 |
+
},
|
388 |
+
{
|
389 |
+
"cell_type": "markdown",
|
390 |
+
"metadata": {},
|
391 |
+
"source": [
|
392 |
+
"We can also see how the model's confidence relates to the probability that the model label matches the human label\n",
|
393 |
+
"\n",
|
394 |
+
"This could be used to set a threshold above which you might accept the model's classification, and only manually curate those which it is less sure of"
|
395 |
+
]
|
396 |
+
},
|
397 |
+
{
|
398 |
+
"cell_type": "code",
|
399 |
+
"execution_count": 25,
|
400 |
+
"metadata": {},
|
401 |
+
"outputs": [
|
402 |
+
{
|
403 |
+
"data": {
|
404 |
+
"image/png": "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y8sL69evt0SMREREVITJHqb5+eefsX79erRs2RKDBw9Gs2bNUKVKFVSsWBEbNmxAv379LBEnERERFVGye0YSExPh6+sLIHt+SGJiIgCgadOmOHTokHmjIyIioiJPdjLi6+uL6OhoAIC/vz82b94MILvHJOfBeURERESmkp2MDB48GOfPnwcATJo0CUuXLoVGo8F7772H999/3+wBEhERUdEme87Ie++9J33ftm1bXL58GadPn0aVKlVQq1YtswZHRERERZ/snpEnVaxYET169ECpUqXw1ltvmSMmIiIiKkaeORnJkZCQgNWrV5vrdERERFRMmC0ZISIiIioIJiNERERkVUxGiIiIyKpMXk3To0ePfN9PSkp61liIiIioGDI5GXFxcXnq+wMGDHjmgIiIiKh4MTkZWbt2rSXjICIiomKKc0aIiIjIqpiMEBERkVUxGSEiIiKrYjJCREREVsVkhIiIiKxK9lN7ASAyMhL79+9HfHw89Hq9wXtTp041S2BERERUPMhORr755hu88847KFOmDMqWLQuFQiG9p1AomIwQERGRLLKTkRkzZmDmzJn44IMPLBEPERERFTOy54zcv38fb7zxhiViISIiomJIdjLyxhtvYO/evZaIhYiIiIoh2cM0VapUwZQpU3DixAkEBARApVIZvD9mzBizBUdERERFn+xkZOXKlXBycsLBgwdx8OBBg/cUCgWTESIiIpJFdjISHR1tiTiIiIiomOKmZ0RERGRVBdr07NatW9i+fTtiYmKQmZlp8N6CBQvMEhgREREVD7KTkYiICLz22mvw9fXF5cuXUbNmTVy/fh1CCNSrV88SMRIREVERJnuYZvLkyZgwYQIuXLgAjUaDbdu24ebNm2jRogX3HyEiIiLZZCcjly5dwoABAwAAtra2ePToEZycnPDpp59izpw5Zg+QiIiIijbZyYijo6M0T8TT0xNRUVHSe/fu3TNfZERERFQsyJ4z8sorr+DIkSOoVq0aOnbsiPHjx+PChQsICwvDK6+8YokYiYiIqAiTnYwsWLAAKSkpAIDp06cjJSUFmzZtQtWqVbmShoiIiGSTnYz4+vpK3zs6OmLFihVmDYiIiIiKlwLtM5IjJSUFer3eoMzZ2fmZAiIiIqLiRfYE1ujoaHTq1AmOjo5wcXFByZIlUbJkSbi6uqJkyZKWiJGIiIiKMNk9I2+++SaEEFizZg08PDygUCgsERcREREVE7KTkfPnz+P06dPw8/OzRDxERERUzMgepnn55Zdx8+ZNS8RCRERExZDsnpFVq1bh7bffxu3bt1GzZk2oVCqD92vVqmW24IiIiKjok52M3L17F1FRURg8eLBUplAoIISAQqGATqcza4BERERUtMlORoYMGYK6devi+++/5wRWIiIiemayk5EbN25g+/btqFKliiXiISIiomJG9gTW1q1b4/z585aIhYiIiIoh2T0jXbp0wXvvvYcLFy4gICDAaALra6+9ZrbgiIiIqOiTnYy8/fbbAIBPP/3U6D1OYCUiIiK5ZCcjTz6LhoiIiOhZyJ4zQkRERGROsntGchueedzUqVMLHAwREREVP7KTkR9++MHgtVarRXR0NGxtbVG5cmUmI0RERCSL7GTk7NmzRmXJyckYNGgQunfvbpagiIiIqPgwy5wRZ2dnTJ8+HVOmTDHH6YiIiKgYMdsE1gcPHuDBgwfmOh0REREVE7KHab788kuD10II3LlzB99++y06dOhgtsCIiIioeJCdjCxcuNDgtY2NDdzc3DBw4EBMnjzZbIERERFR8SA7GYmOjrZEHERERFRMcdMzIiIisiqTe0Z69OhhUr2wsLACB0NERETFj8nJiIuLi8HrjRs3okuXLihRooTZgyIiIqLiw+RkZO3atQavt27dirlz58LX19fsQREREVHxwTkjREREZFVMRoiIiMiqmIwQERGRVZk8Z2T79u0Gr/V6PSIiInDx4kWD8tdee808kREREVGxYHIy0q1bN6OyESNGGLxWKBTQ6XTPHBQREREVHyYP0+j1+qd+FSQRWbp0KXx8fKDRaNCoUSOcPHky3/pJSUkYNWoUPD09oVar8dJLL2HXrl2yr0tERETPB9nbwZvTpk2bEBISghUrVqBRo0ZYtGgRgoKCcOXKFbi7uxvVz8zMRLt27eDu7o6tW7eiXLlyuHHjBlxdXQs/eCIiIjILqyYjCxYswPDhwzF48GAAwIoVK7Bz506sWbMGkyZNMqq/Zs0aJCYm4tixY1CpVAAAHx+fwgyZiIiewc4/7uDvuIfoUa8cKpZ2tHY49JywWjKSmZmJ06dPGzzp18bGBm3btsXx48dzPWb79u0IDAzEqFGj8NNPP8HNzQ19+/bFBx98AKVSmesxGRkZyMjIkF4nJycDALRaLbRa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RZjsYZr58+dDoVBgwIAByMrKAgCoVCq88847+Pzzz80eIBERERVtspMROzs7LF68GLNnz0ZUVBQAoHLlynBwcDB7cERERFT0FWifEQBwcHCAq6ur9D0RERFRQcieM5KVlYUpU6bAxcUFPj4+8PHxgYuLCz7++GNotVpLxEhERERFmOyekXfffRdhYWGYO3cuAgMDAQDHjx/HJ598goSEBCxfvtzsQRIREVHRJTsZ2bhxI0JDQ9GhQweprFatWvD29kafPn2YjBAREZEssodp1Go1fHx8jMorVaoEOzs7c8RERERExYjsZGT06NH47LPPkJGRIZVlZGRg5syZGD16tFmDIyIioqJP9jDN2bNnERERgfLly6N27doAgPPnzyMzMxNt2rRBjx49pLphYWHmi5SIiIiKJNnJiKurK3r27GlQ5u3tbbaAiIiIqHiRnYysXbvWEnEQERFRMVXgTc/u3r2LK1euAAD8/Pzg5uZmtqCIiIio+JA9gTU1NRVDhgyBp6cnmjdvjubNm8PLywtDhw5FWlqaJWIkIiKiIkx2MhISEoKDBw/i559/RlJSEpKSkvDTTz/h4MGDGD9+vCViJCIioiJM9jDNtm3bsHXrVrRs2VIq69ixI+zt7dGrVy9uekZERESyyO4ZSUtLg4eHh1G5u7s7h2mIiIhINtnJSGBgIKZNm4b09HSp7NGjR5g+fbr0rBoiIiIiU8keplm0aBHat29vtOmZRqPBnj17zB4gERERFW2yk5GAgABERkZiw4YNuHz5MgCgT58+6NevH+zt7c0eIBERERVtspIRrVYLf39/7NixA8OHD7dUTERERFSMyJozolKpDOaKEBERET0r2RNYR40ahTlz5iArK8sS8RAREVExI3vOyO+//46IiAjs3bsXAQEBcHR0NHifT+olIiIiOczy1F4iIiKignountq7dOlSzJs3D7GxsahduzaWLFmChg0b5lr3m2++wfr163Hx4kUAQP369TFr1qw86xMREdHzzeQ5I3q9HnPmzEGTJk3w8ssvY9KkSXj06NEzB7Bp0yaEhIRg2rRpOHPmDGrXro2goCDEx8fnWv/AgQPo06cP9u/fj+PHj8Pb2xuvvvoqbt++/cyxEBERUeEzORmZOXMmPvzwQzg5OaFcuXJYvHgxRo0a9cwBLFiwAMOHD8fgwYNRvXp1rFixAg4ODlizZk2u9Tds2ICRI0eiTp068Pf3x6pVq6DX6xEREfHMsRAREVHhM3mYZv369Vi2bBlGjBgBANi3bx86deqEVatWwcZG9qIcAEBmZiZOnz6NyZMnS2U2NjZo27Ytjh8/btI50tLSoNVqUapUqVzfz8jIQEZGhvQ6OTkZQPaeKVqttkBxkzw57cz2Ljxs88LHNi98bPPCZ6m2NjkZiYmJQceOHaXXbdu2hUKhwD///IPy5csX6OL37t2DTqczevCeh4eHtLvr03zwwQfw8vJC27Ztc31/9uzZmD59ulH5/v374eDgID9oKrDw8HBrh1DssM0LH9u88LHNC4+lHohrcjKSlZUFjUZjUKZSqayakX7++ecIDQ3FgQMHjGLLMXnyZISEhEivk5OT4e3tjVatWqF06dKFFWqxptVqER4ejnbt2kGlUlk7nGKBbV742OaFj21e+BISEixyXpOTESEEBg0aBLVaLZWlp6fj7bffNthrRM4+I2XKlIFSqURcXJxBeVxcHMqWLZvvsfPnz8fnn3+Offv2oVatWnnWU6vVBjHnUKlUvHkLGdu88LHNCx/bvPCxzQuPpdrZ5GRk4MCBRmVvvvnmM13czs4O9evXR0REBLp16wYA0mTU0aNH53nc3LlzMXPmTOzZswcNGjR4phiIiIjIukxORiyxvwgAhISEYODAgWjQoAEaNmyIRYsWITU1FYMHDwYADBgwAOXKlcPs2bMBAHPmzMHUqVOxceNG+Pj4IDY2FgDg5OQEJycni8RIREREliN70zNzCw4Oxt27dzF16lTExsaiTp062L17tzSpNSYmxmC1zvLly5GZmYnXX3/d4DzTpk3DJ598UpihExERkRlYPRkBgNGjR+c5LHPgwAGD19evX7d8QERERFRoCrZBCBEREZGZMBkhIiIiq2IyQkRERFbFZISIiIisiskIERERWRWTESIiIrIqJiNERERkVUxGiIiIyKqYjBAREZFVMRkhIiIiq2IyQkRERFbFZISIiIisiskIERERWRWTESIiIrIqJiNERERkVUxGiIiIyKqYjBAREZFVMRkhIiIiq2IyQkRERFbFZISIiIisiskIERERWRWTESIiIrIqJiNERERkVUxGiIiIyKqYjBAREZFVMRkhIiIiq2IyQkRERFbFZISIiIisiskIERERWRWTESIiIrIqJiNERERkVUxGiIiI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",
|
405 |
+
"text/plain": [
|
406 |
+
"<Figure size 600x600 with 1 Axes>"
|
407 |
+
]
|
408 |
+
},
|
409 |
+
"metadata": {},
|
410 |
+
"output_type": "display_data"
|
411 |
+
}
|
412 |
+
],
|
413 |
+
"source": [
|
414 |
+
"confidences = analyzer.sorting.get_property('label_confidence')\n",
|
415 |
+
"\n",
|
416 |
+
"# Make dataframe of human label, model label, and confidence\n",
|
417 |
+
"label_df = pd.DataFrame(data = {\n",
|
418 |
+
" 'phy_label': human_labels,\n",
|
419 |
+
" 'decoder_label': predictions,\n",
|
420 |
+
" 'confidence': confidences},\n",
|
421 |
+
" index = decoder_output.keys())\n",
|
422 |
+
"\n",
|
423 |
+
"# Calculate the proportion of agreed labels by confidence decile\n",
|
424 |
+
"label_df['model_x_human_agreement'] = label_df['phy_label'] == label_df['decoder_label']\n",
|
425 |
+
"\n",
|
426 |
+
"def calculate_moving_avg(label_df, confidence_label, window_size):\n",
|
427 |
+
"\n",
|
428 |
+
" label_df[f'{confidence_label}_decile'] = pd.cut(label_df[confidence_label], 10, labels=False, duplicates='drop')\n",
|
429 |
+
" # Group by decile and calculate the proportion of correct labels (agreement)\n",
|
430 |
+
" p_label_grouped = label_df.groupby(f'{confidence_label}_decile')['model_x_human_agreement'].mean()\n",
|
431 |
+
" # Convert decile to range 0-1\n",
|
432 |
+
" p_label_grouped.index = p_label_grouped.index / 10\n",
|
433 |
+
" # Sort the DataFrame by confidence scores\n",
|
434 |
+
" label_df_sorted = label_df.sort_values(by=confidence_label)\n",
|
435 |
+
"\n",
|
436 |
+
" p_label_moving_avg = label_df_sorted['model_x_human_agreement'].rolling(window=window_size).mean()\n",
|
437 |
+
"\n",
|
438 |
+
" return label_df_sorted[confidence_label], p_label_moving_avg\n",
|
439 |
+
"\n",
|
440 |
+
"p_agreement_sorted, p_agreement_moving_avg = calculate_moving_avg(label_df, 'confidence', 20)\n",
|
441 |
+
"\n",
|
442 |
+
"# Plot the moving average of agreement\n",
|
443 |
+
"plt.figure(figsize=(6, 6))\n",
|
444 |
+
"plt.plot(p_agreement_sorted, p_agreement_moving_avg, label = 'Moving Average')\n",
|
445 |
+
"plt.axhline(y=1/len(np.unique(predictions)), color='black', linestyle='--', label='Chance')\n",
|
446 |
+
"plt.xlabel('Confidence'); plt.xlim(0.5, 1)\n",
|
447 |
+
"plt.ylabel('Proportion Agreement with Human Label'); plt.ylim(0, 1)\n",
|
448 |
+
"plt.title('Agreement vs Confidence (Moving Average)')\n",
|
449 |
+
"plt.legend(); plt.grid(True); plt.show()"
|
450 |
+
]
|
451 |
+
},
|
452 |
+
{
|
453 |
+
"cell_type": "markdown",
|
454 |
+
"metadata": {},
|
455 |
+
"source": [
|
456 |
+
"# If you only have metrics files"
|
457 |
+
]
|
458 |
+
},
|
459 |
+
{
|
460 |
+
"cell_type": "markdown",
|
461 |
+
"metadata": {},
|
462 |
+
"source": [
|
463 |
+
"If you don't have access to to sorting analyzer for a particular recording, you can still use the pretrained model to predict on a new data"
|
464 |
+
]
|
465 |
+
},
|
466 |
+
{
|
467 |
+
"cell_type": "code",
|
468 |
+
"execution_count": 2,
|
469 |
+
"metadata": {},
|
470 |
+
"outputs": [],
|
471 |
+
"source": [
|
472 |
+
"# Load your files\n",
|
473 |
+
"\n",
|
474 |
+
"data_directory = Path(r\"Y:\\invivo_ephys\\Neuropixels\")\n",
|
475 |
+
"recording_folder = '2838_20240620'\n",
|
476 |
+
"metrics_folder = data_directory / recording_folder / 'metrics'\n"
|
477 |
+
]
|
478 |
+
},
|
479 |
+
{
|
480 |
+
"cell_type": "code",
|
481 |
+
"execution_count": 3,
|
482 |
+
"metadata": {},
|
483 |
+
"outputs": [],
|
484 |
+
"source": [
|
485 |
+
"# load quality metrics and template metrics csv files\n",
|
486 |
+
"\n",
|
487 |
+
"quality_metrics = pd.read_csv(metrics_folder / 'quality_metrics.csv')\n",
|
488 |
+
"template_metrics = pd.read_csv(metrics_folder / 'template_metrics.csv')\n",
|
489 |
+
"\n",
|
490 |
+
"# merge them based on the index\n",
|
491 |
+
"metrics = pd.merge(quality_metrics, template_metrics, left_index=True, right_index=True)\n",
|
492 |
+
"\n",
|
493 |
+
"# Replace infinities with NaNs and convert to float32\n",
|
494 |
+
"metrics_dataframe = metrics.applymap(lambda x: np.nan if np.isinf(x) else x).astype(\"float32\")"
|
495 |
+
]
|
496 |
+
},
|
497 |
+
{
|
498 |
+
"cell_type": "markdown",
|
499 |
+
"metadata": {},
|
500 |
+
"source": [
|
501 |
+
"## First we use noise vs neuron classifier"
|
502 |
+
]
|
503 |
+
},
|
504 |
+
{
|
505 |
+
"cell_type": "code",
|
506 |
+
"execution_count": 5,
|
507 |
+
"metadata": {},
|
508 |
+
"outputs": [],
|
509 |
+
"source": [
|
510 |
+
"import skops.io as sio\n",
|
511 |
+
"from huggingface_hub import hf_hub_download\n",
|
512 |
+
"\n",
|
513 |
+
"json_path = hf_hub_download(repo_id=\"AnoushkaJain3/curation_machine_learning_models\", filename=\"features_sequence.json\")\n",
|
514 |
+
"\n",
|
515 |
+
"# Load the JSON file\n",
|
516 |
+
"with open(json_path, 'r') as file:\n",
|
517 |
+
" column_list = json.load(file)"
|
518 |
+
]
|
519 |
+
},
|
520 |
+
{
|
521 |
+
"cell_type": "code",
|
522 |
+
"execution_count": 10,
|
523 |
+
"metadata": {},
|
524 |
+
"outputs": [],
|
525 |
+
"source": [
|
526 |
+
"model_path_noise = hf_hub_download(repo_id=\"AnoushkaJain3/curation_test\", filename=\"noise_neuron_model.skops\")\n",
|
527 |
+
"\n",
|
528 |
+
"# Get the untrusted types from the skops file\n",
|
529 |
+
"untrusted_types = sio.get_untrusted_types(file = model_path_noise)\n",
|
530 |
+
"clf = sio.load(model_path_noise, trusted=untrusted_types)\n",
|
531 |
+
"\n",
|
532 |
+
"# Perform prediction\n",
|
533 |
+
"noise_predictions = clf.predict(metrics_dataframe[column_list])\n",
|
534 |
+
"noise_probabs = clf.predict_proba(metrics_dataframe[column_list])\n",
|
535 |
+
"\n",
|
536 |
+
"metrics_dataframe['noise_label'] = noise_predictions\n",
|
537 |
+
"metrics_dataframe['noise_probs'] = noise_probabs[:,1]\n",
|
538 |
+
"metrics_dataframe['noise_label'] = metrics_dataframe['noise_label'].map({1: 'noise', 0: 'neural'})"
|
539 |
+
]
|
540 |
+
},
|
541 |
+
{
|
542 |
+
"cell_type": "markdown",
|
543 |
+
"metadata": {},
|
544 |
+
"source": [
|
545 |
+
"## First we use sua vs mua classifier"
|
546 |
+
]
|
547 |
+
},
|
548 |
+
{
|
549 |
+
"cell_type": "code",
|
550 |
+
"execution_count": 11,
|
551 |
+
"metadata": {},
|
552 |
+
"outputs": [],
|
553 |
+
"source": [
|
554 |
+
"model_path_sua = hf_hub_download(repo_id=\"AnoushkaJain3/curation_test\", filename=\"sua_mua_model.skops\")\n",
|
555 |
+
"\n",
|
556 |
+
"# Get the untrusted types from the skops file\n",
|
557 |
+
"untrusted_types = sio.get_untrusted_types(file = model_path_sua)\n",
|
558 |
+
"clf = sio.load(model_path_sua, trusted=untrusted_types)\n",
|
559 |
+
"\n",
|
560 |
+
"# Perform prediction\n",
|
561 |
+
"sua_predictions = clf.predict(metrics_dataframe[column_list])\n",
|
562 |
+
"sua_probabs = clf.predict_proba(metrics_dataframe[column_list])\n",
|
563 |
+
"metrics_dataframe['sua_label'] = sua_predictions\n",
|
564 |
+
"metrics_dataframe['sua_probs'] = sua_probabs[:,1]\n",
|
565 |
+
"metrics_dataframe['sua_label'] = metrics_dataframe['sua_label'].map({1 : 'sua', 0 :'mua'})"
|
566 |
+
]
|
567 |
+
},
|
568 |
+
{
|
569 |
+
"cell_type": "code",
|
570 |
+
"execution_count": 12,
|
571 |
+
"metadata": {},
|
572 |
+
"outputs": [],
|
573 |
+
"source": [
|
574 |
+
"# Combine the predictions and probabilities from the two models\n",
|
575 |
+
"\n",
|
576 |
+
"# Create the 'decoder_label' column\n",
|
577 |
+
"metrics_dataframe['decoder_label'] = metrics_dataframe.apply(lambda row: row['noise_label'] if row['noise_label'] == 'noise' else row['sua_label'], axis=1)\n",
|
578 |
+
" \n",
|
579 |
+
"# Create the 'decoder_probs' column\n",
|
580 |
+
"metrics_dataframe['decoder_probs'] = metrics_dataframe.apply(lambda row: row['noise_probs'] if row['decoder_label'] == 'noise' else row['sua_probs'], axis=1)\n",
|
581 |
+
"\n",
|
582 |
+
"# Update 'decoder_probs' for 'mua' values\n",
|
583 |
+
"metrics_dataframe.loc[metrics_dataframe['decoder_label'] == 'mua', 'decoder_probs'] = 1 - metrics_dataframe['decoder_probs']"
|
584 |
+
]
|
585 |
+
},
|
586 |
+
{
|
587 |
+
"cell_type": "code",
|
588 |
+
"execution_count": null,
|
589 |
+
"metadata": {},
|
590 |
+
"outputs": [],
|
591 |
+
"source": [
|
592 |
+
"metrics_dataframe['decoder_label']"
|
593 |
+
]
|
594 |
+
}
|
595 |
+
],
|
596 |
+
"metadata": {
|
597 |
+
"kernelspec": {
|
598 |
+
"display_name": "spike_interface",
|
599 |
+
"language": "python",
|
600 |
+
"name": "python3"
|
601 |
+
},
|
602 |
+
"language_info": {
|
603 |
+
"codemirror_mode": {
|
604 |
+
"name": "ipython",
|
605 |
+
"version": 3
|
606 |
+
},
|
607 |
+
"file_extension": ".py",
|
608 |
+
"mimetype": "text/x-python",
|
609 |
+
"name": "python",
|
610 |
+
"nbconvert_exporter": "python",
|
611 |
+
"pygments_lexer": "ipython3",
|
612 |
+
"version": "3.9.16"
|
613 |
+
}
|
614 |
+
},
|
615 |
+
"nbformat": 4,
|
616 |
+
"nbformat_minor": 2
|
617 |
+
}
|
train_new_model.ipynb
ADDED
The diff for this file is too large to render.
See raw diff
|
|