CSC to learn LFP spiking atoms#

Here, we show how CSC can be used to learn spiking atoms from Local Field Potential (LFP) data [1].

[1] Hitziger, Sebastian, et al.

Adaptive Waveform Learning: A Framework for Modeling Variability in Neurophysiological Signals. IEEE Transactions on Signal Processing (2017).

First, let us fetch the data (~14 MB)

import os
from mne.datasets import fetch_dataset
from mne.utils import get_config

url = ('https://github.com/hitziger/AWL/raw/master/Experiments/data/'
       'LFP_data_contiguous_1250_Hz.mat')

folder_name = "LFP"
archive_name = "LFP_data_contiguous_1250_Hz.mat"

fname = fetch_dataset(
    {"dataset_name": "LFP_data",
     "url": url,
     "archive_name": archive_name,
     "folder_name": folder_name,
     "hash": None
     },
    path=None,
    force_update=False
)

fname = os.path.join(fname, archive_name)
Using default location ~/mne_data for LFP_data...
Creating /github/home/mne_data
Downloading file 'LFP_data_contiguous_1250_Hz.mat' from 'https://github.com/hitziger/AWL/raw/master/Experiments/data/LFP_data_contiguous_1250_Hz.mat' to '/github/home/mne_data/LFP'.

  0%|                                              | 0.00/14.4M [00:00<?, ?B/s]
 51%|██████████████████▉                  | 7.36M/14.4M [00:00<00:00, 73.6MB/s]
  0%|                                              | 0.00/14.4M [00:00<?, ?B/s]
100%|█████████████████████████████████████| 14.4M/14.4M [00:00<00:00, 65.7GB/s]
Download complete in 00s (13.8 MB)

It is a mat file, so we use scipy to load it

from scipy import io

data = io.loadmat(fname)
X, sfreq = data['X'].T, float(data['sfreq'])
/github/workspace/examples/csc/plot_lfp_data.py:44: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
  X, sfreq = data['X'].T, float(data['sfreq'])

And now let us look at the data

import numpy as np
import matplotlib.pyplot as plt

start, stop = 11000, 15000
times = np.arange(start, stop) / sfreq
plt.plot(times, X[0, start:stop], color='b')
plt.xlabel('Time (s)')
plt.ylabel(r'$\mu$ V')
plt.xlim([9., 12.])
plot lfp data
(9.0, 12.0)

and filter it using a convenient function from MNE. This will remove low frequency drifts, but we keep the high frequencies

from mne.filter import filter_data
X = filter_data(
    X.astype(np.float64), sfreq, l_freq=1, h_freq=None, fir_design='firwin')
Setting up high-pass filter at 1 Hz

FIR filter parameters
---------------------
Designing a one-pass, zero-phase, non-causal highpass filter:
- Windowed time-domain design (firwin) method
- Hamming window with 0.0194 passband ripple and 53 dB stopband attenuation
- Lower passband edge: 1.00
- Lower transition bandwidth: 1.00 Hz (-6 dB cutoff frequency: 0.50 Hz)
- Filter length: 4125 samples (3.300 s)

Now, we define the parameters of our model.

reg = 6.0
n_times = 2500
n_times_atom = 350
n_trials = 100
n_atoms = 3
n_iter = 60

Let’s stick to one random state for now, but if you want to learn how to select the random state, consult this example.

Now, we epoch the trials

overlap = 0
starts = np.arange(0, X.shape[1] - n_times, n_times - overlap)
stops = np.arange(n_times, X.shape[1], n_times - overlap)

X_new = []
for idx, (start, stop) in enumerate(zip(starts, stops)):
    if idx >= n_trials:
        break
    X_new.append(X[0, start:stop])
X_new = np.vstack(X_new)
del X

We remove the mean and scale to unit variance.

The convolutions can result in edge artifacts at the edges of the trials. Therefore, we discount the contributions from the edges by windowing the trials.

from numpy import hamming
X_new *= hamming(n_times)[None, :]

Of course, in a data-limited setting we want to use as much of the data as possible. If this is the case, you can set overlap to non-zero (for example half the epoch length).

Now, we run regular CSC since the trials are not too noisy

Coordinate descent loop 0 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 51134.32096508
Using method dual for projection
[seed 10] Objective (d) 45299.80903125
Coordinate descent loop 1 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 26399.47853871
Using method dual for projection
[seed 10] Objective (d) 25948.80915409
Coordinate descent loop 2 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 23777.89064427
Using method dual for projection
[seed 10] Objective (d) 23704.90593344
Coordinate descent loop 3 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 22233.60227587
Using method dual for projection
[seed 10] Objective (d) 22221.01870097
Coordinate descent loop 4 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 21202.43876006
Using method dual for projection
[seed 10] Objective (d) 21169.49202496
Coordinate descent loop 5 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 20579.63611160
Using method dual for projection
[seed 10] Objective (d) 20618.98107838
Coordinate descent loop 6 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 20283.55110757
Using method dual for projection
[seed 10] Objective (d) 20210.75292119
Coordinate descent loop 7 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 19971.53116238
Using method dual for projection
[seed 10] Objective (d) 19970.52325693
Coordinate descent loop 8 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 19708.44554814
Using method dual for projection
[seed 10] Objective (d) 19691.20196937
Coordinate descent loop 9 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 19462.43966049
Using method dual for projection
[seed 10] Objective (d) 19467.01239142
Coordinate descent loop 10 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 19233.45092821
Using method dual for projection
[seed 10] Objective (d) 19214.12766228
Coordinate descent loop 11 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 19085.64469638
Using method dual for projection
[seed 10] Objective (d) 19084.13170902
Coordinate descent loop 12 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18945.61954180
Using method dual for projection
[seed 10] Objective (d) 18980.31578131
Coordinate descent loop 13 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18876.43985522
Using method dual for projection
[seed 10] Objective (d) 18836.38353365
Coordinate descent loop 14 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18720.74584344
Using method dual for projection
[seed 10] Objective (d) 18721.54845149
Coordinate descent loop 15 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18623.64002131
Using method dual for projection
[seed 10] Objective (d) 18621.18904483
Coordinate descent loop 16 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18547.81611676
Using method dual for projection
[seed 10] Objective (d) 18545.24281148
Coordinate descent loop 17 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18471.88752075
Using method dual for projection
[seed 10] Objective (d) 18470.42055101
Coordinate descent loop 18 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18393.84202337
Using method dual for projection
[seed 10] Objective (d) 18391.78226334
Coordinate descent loop 19 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18331.73169084
Using method dual for projection
[seed 10] Objective (d) 18328.84451727
Coordinate descent loop 20 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18274.15271778
Using method dual for projection
[seed 10] Objective (d) 18297.40702014
Coordinate descent loop 21 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18257.44912767
Using method dual for projection
[seed 10] Objective (d) 18276.17808986
Coordinate descent loop 22 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18243.49274443
Using method dual for projection
[seed 10] Objective (d) 18261.00618814
Coordinate descent loop 23 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18234.36110418
Using method dual for projection
[seed 10] Objective (d) 18208.94505659
Coordinate descent loop 24 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18179.04646093
Using method dual for projection
[seed 10] Objective (d) 18179.60670466
Coordinate descent loop 25 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18156.84098659
Using method dual for projection
[seed 10] Objective (d) 18166.58627528
Coordinate descent loop 26 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18145.85002331
Using method dual for projection
[seed 10] Objective (d) 18152.93057101
Coordinate descent loop 27 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18131.29820977
Using method dual for projection
[seed 10] Objective (d) 18131.16931986
Coordinate descent loop 28 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18119.63496022
Using method dual for projection
[seed 10] Objective (d) 18111.53150601
Coordinate descent loop 29 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18095.94337119
Using method dual for projection
[seed 10] Objective (d) 18106.50706309
Coordinate descent loop 30 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18098.05238801
Using method dual for projection
[seed 10] Objective (d) 18097.82989536
Coordinate descent loop 31 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18084.15731509
Using method dual for projection
[seed 10] Objective (d) 18025.10057344
Coordinate descent loop 32 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18015.48731929
Using method dual for projection
[seed 10] Objective (d) 18015.15575173
Coordinate descent loop 33 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18009.09808184
Using method dual for projection
[seed 10] Objective (d) 18010.63889014
Coordinate descent loop 34 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18004.88799026
Using method dual for projection
[seed 10] Objective (d) 18058.43299622
Coordinate descent loop 35 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18049.18824514
Using method dual for projection
[seed 10] Objective (d) 17997.43391151
Coordinate descent loop 36 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17990.54846012
Using method dual for projection
[seed 10] Objective (d) 17990.87720120
Coordinate descent loop 37 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17985.96104119
Using method dual for projection
[seed 10] Objective (d) 17988.72475350
Coordinate descent loop 38 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17984.75059814
Using method dual for projection
[seed 10] Objective (d) 18049.42016194
Coordinate descent loop 39 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 18046.54421717
Using method dual for projection
[seed 10] Objective (d) 17984.35862183
Coordinate descent loop 40 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17980.96890961
Using method dual for projection
[seed 10] Objective (d) 17980.80680588
Coordinate descent loop 41 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17972.69334792
Using method dual for projection
[seed 10] Objective (d) 17972.04042137
Coordinate descent loop 42 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17966.98520329
Using method dual for projection
[seed 10] Objective (d) 17966.83021975
Coordinate descent loop 43 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17962.43883801
Using method dual for projection
[seed 10] Objective (d) 17977.53757640
Coordinate descent loop 44 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17975.03848495
Using method dual for projection
[seed 10] Objective (d) 17966.13321317
Coordinate descent loop 45 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17963.73287315
Using method dual for projection
[seed 10] Objective (d) 17978.89804489
Coordinate descent loop 46 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17976.74368634
Using method dual for projection
[seed 10] Objective (d) 17972.54416171
Coordinate descent loop 47 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17970.51804918
Using method dual for projection
[seed 10] Objective (d) 17972.13711885
Coordinate descent loop 48 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17970.00311159
Using method dual for projection
[seed 10] Objective (d) 17963.24658884
Coordinate descent loop 49 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17961.19262797
Using method dual for projection
[seed 10] Objective (d) 17969.93968333
Coordinate descent loop 50 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17965.80773028
Using method dual for projection
[seed 10] Objective (d) 17965.59699217
Coordinate descent loop 51 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17963.81857389
Using method dual for projection
[seed 10] Objective (d) 17970.06369897
Coordinate descent loop 52 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17968.46972767
Using method dual for projection
[seed 10] Objective (d) 17962.81540665
Coordinate descent loop 53 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17960.61175180
Using method dual for projection
[seed 10] Objective (d) 17951.02970316
Coordinate descent loop 54 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17949.43679149
Using method dual for projection
[seed 10] Objective (d) 17958.78922443
Coordinate descent loop 55 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17957.61467534
Using method dual for projection
[seed 10] Objective (d) 17957.38018059
Coordinate descent loop 56 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17956.17192556
Using method dual for projection
[seed 10] Objective (d) 17955.83032225
Coordinate descent loop 57 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17954.91710469
Using method dual for projection
[seed 10] Objective (d) 17954.02018637
Coordinate descent loop 58 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17952.99486207
Using method dual for projection
[seed 10] Objective (d) 17955.46127494
Coordinate descent loop 59 / 60 [n_jobs=1]
[seed 10] Objective (z_hat) : 17953.82645631
Using method dual for projection
[seed 10] Objective (d) 17943.85910638

Let’s look at the atoms now.

plt.figure()
plt.plot(d_hat.T)
plt.show()
plot lfp data

Total running time of the script: (2 minutes 8.294 seconds)

Gallery generated by Sphinx-Gallery