Closed apavlo89 closed 4 years ago
Have you labeled this as a bug?Not sure how the github system works. I think it is more like my programming incompetence! :P My understanding is that in order for df_feat to display entropy for each channel, something has to be changed in data = data[0, :] to make it include all channels but I am terrible at programming so everything I've tried doesn't work! Is including all channels in df_feat possible currently or will there need to be major changes in the YASA source code to do this?
Hi @apavlo89! Just removed the "Bug" label :-) So the issue here is not with YASA but rather with Entropy, which is designed to work only with one-dimensional array. In other words, if you want to create a df_feat dataframe with all the channels, you need to create a for loop in which you loop across all the channels
df_all = []
for i, c in enumerate(chan):
data = data[i, :]
# Calculate entropy for this channel
df_chan = {'perm_entropy': apply(...), }
df_chan['Channel'] = f
# Append to a larger dataframe
df_all.append(df_chan)
df_all = pd.DataFrame(df_all, ignore_index=True)
Something like that should work, let me know! Thanks
It is giving me an error: too many indices for array
import yasa import mne import numpy as np import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import entropy as ent sns.set(font_scale=1.2)
f = mne.io.read_raw_eeglab('E:\REEG MU HIGHLOW\EEGLAB\P1_postICA.set', montage=None, eog=(), preload=True, uint16_codec=None, verbose=None)
data = f._data * 1e6
sf = f.info['sfreq'] chan = f.ch_names times = np.arange(data.shape[1]) / sf print(data.shape, chan, times)
data = data[0, :] # 0 indicates first electrode location, change number to change electrode - to see which number is each electrode look at variable 'chan' print(data.shape, np.round(data[0:5], 3))
times, data_win = yasa.sliding_window(data, sf, window=120)
times /= 60
data_win.shape
from numpy import apply_along_axis as apply
df_feat = {
'perm_entropy': apply(ent.perm_entropy, axis=1, arr=data_win, normalize=True),
'svd_entropy': apply(ent.svd_entropy, 1, data_win, normalize=True),
'spec_entropy': apply(ent.spectral_entropy, 1, data_win, sf=sf, nperseg=data_win.shape[1], normalize=True),
'sample_entropy': apply(ent.sample_entropy, 1, data_win),
# Fractal dimension
'dfa': apply(ent.detrended_fluctuation, 1, data_win),
'petrosian': apply(ent.petrosian_fd, 1, data_win),
'katz': apply(ent.katz_fd, 1, data_win),
'higuchi': apply(ent.higuchi_fd, 1, data_win),
}
df_feat = pd.DataFrame(df_feat) df_feat.head()
def lziv(x): """Binarize the EEG signal and calculate the Lempel-Ziv complexity. """ return ent.lziv_complexity(x > x.mean(), normalize=True)
df_feat['lziv'] = apply(lziv, 1, data_win) # Slow
df_all = [] for i, c in enumerate(chan): data = data[i, :]
# Calculate entropy for this channel
df_chan = {'perm_entropy': apply(...), }
df_chan['Channel'] = f
# Append to a larger dataframe
df_all.append(df_chan)
df_all = pd.DataFrame(df_all, ignore_index=True)
I wasn't sure if the three dots in this line df_chan = {'perm_entropy': apply(...), } meant to just copy paste from df_feat all the values so I also tried like this
df_all = [] for i, c in enumerate(chan): data = data[i, :]
# Calculate entropy for this channel
df_chan = {
# Entropy
'perm_entropy': apply(ent.perm_entropy, axis=1, arr=data_win, normalize=True),
'svd_entropy': apply(ent.svd_entropy, 1, data_win, normalize=True),
'spec_entropy': apply(ent.spectral_entropy, 1, data_win, sf=sf, nperseg=data_win.shape[1], normalize=True),
'sample_entropy': apply(ent.sample_entropy, 1, data_win),
# Fractal dimension
'dfa': apply(ent.detrended_fluctuation, 1, data_win),
'petrosian': apply(ent.petrosian_fd, 1, data_win),
'katz': apply(ent.katz_fd, 1, data_win),
'higuchi': apply(ent.higuchi_fd, 1, data_win),
} df_chan['Channel'] = f
# Append to a larger dataframe
df_all.append(df_chan)
df_all = pd.DataFrame(df_all, ignore_index=True)
Again I got same error :( Also how do I get lziv complexity analysis into this loop?
You need to remove this line from your script;
data = data[0, :]
Yes the three dots meant copy-paste everything.
For LZiv just define this function at the beginning of the script:
def lziv(x):
"""Binarize the EEG signal and calculate the Lempel-Ziv complexity.
"""
return ent.lziv_complexity(x > x.mean(), normalize=True)
and then add
df_chan = {...,
'lziv': apply(lziv, 1, data_win),
}
I've done as you have explained but now I get
Error: order*delay should be lower than x.size
This is my code now
import yasa import mne import numpy as np import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import entropy as ent sns.set(font_scale=1.2)
f = mne.io.read_raw_eeglab('E:\REEG MU HIGHLOW\EEGLAB\P1_postICA.set', montage=None, eog=(), preload=True, uint16_codec=None, verbose=None)
data = f._data * 1e6
sf = f.info['sfreq'] chan = f.ch_names times = np.arange(data.shape[1]) / sf
print(data.shape, np.round(data[0:5], 3))
times, data_win = yasa.sliding_window(data, sf, window=120)
times /= 60
data_win.shape
from numpy import apply_along_axis as apply
def lziv(x): """Binarize the EEG signal and calculate the Lempel-Ziv complexity. """ return ent.lziv_complexity(x > x.mean(), normalize=True)
df_all = [] for i, c in enumerate(chan): data = data[i, :]
# Calculate entropy for this channel
df_chan = {
# Entropy
'perm_entropy': apply(ent.perm_entropy, axis=1, arr=data_win, normalize=True),
'svd_entropy': apply(ent.svd_entropy, 1, data_win, normalize=True),
'spec_entropy': apply(ent.spectral_entropy, 1, data_win, sf=sf, nperseg=data_win.shape[1], normalize=True),
'sample_entropy': apply(ent.sample_entropy, 1, data_win),
# Fractal dimension
'dfa': apply(ent.detrended_fluctuation, 1, data_win),
'petrosian': apply(ent.petrosian_fd, 1, data_win),
'katz': apply(ent.katz_fd, 1, data_win),
'higuchi': apply(ent.higuchi_fd, 1, data_win),
'lziv': apply(lziv, 1, data_win),
}
df_chan['Channel'] = f
# Append to a larger dataframe
df_all.append(df_chan)
df_all = pd.DataFrame(df_all, ignore_index=True)
Ok it's hard for me to debug without having the data and code but the issue is that data_win
is now a three-dimension array, so you first need to create something like:
data_win_ep = data_win[i, :, :]
and then use this data_win_ep
in the df_chan = {...}
code, possibily changing the axis
argument of the numpy.apply_along_axis.
df_chan = {
# Entropy
'perm_entropy': apply(ent.perm_entropy, axis=1, arr=data_win_ep, normalize=True),
}
As this is not directly related to YASA or Entropy I will close this issue now. I recommend that you read on Numpy axis and shape.
Thanks
Merci beaucoup, you are a rockstar! It worked perfectly! Thank you for your time. The only thing I had to change from your code was to remove ignore_index=True as it was giving me an error: unexpected keyword argument 'ignore index'. Not sure what it does but removing seemed to have fixed all errors.
For anyone wanting to analyze more than 1 channel in one go for their analysis this is an example of code they could use
import yasa import mne import numpy as np import matplotlib.pyplot as plt import seaborn as sns import pandas as pd import entropy as ent sns.set(font_scale=1.2)
f = mne.io.read_raw_eeglab('E:\study\P1_nonlinear.set', montage=None, eog=(), preload=True, uint16_codec=None, verbose=None)
data = f._data * 1e6
sf = f.info['sfreq'] chan = f.ch_names times = np.arange(data.shape[1]) / sf
print(data.shape, np.round(data[0:5], 3))
times, data_win = yasa.sliding_window(data, sf, window=120)
times /= 60
from numpy import apply_along_axis as apply
def lziv(x): """Binarize the EEG signal and calculate the Lempel-Ziv complexity. """ return ent.lziv_complexity(x > x.mean(), normalize=True)
df_all = []
for i, c in enumerate(chan): data_win_ep = data_win[i, :, :]
df_chan = {
# Entropy
'perm_entropy': apply(ent.perm_entropy, axis=1, arr=data_win_ep, normalize=True),
'svd_entropy': apply(ent.svd_entropy, 1, data_win_ep, normalize=True),
'spec_entropy': apply(ent.spectral_entropy, 1, data_win_ep, sf=sf, nperseg=data_win_ep.shape[1], normalize=True),
'sample_entropy': apply(ent.sample_entropy, 1, data_win_ep),
# Fractal dimension
'dfa': apply(ent.detrended_fluctuation, 1, data_win_ep),
'petrosian': apply(ent.petrosian_fd, 1, data_win_ep),
'katz': apply(ent.katz_fd, 1, data_win_ep),
'higuchi': apply(ent.higuchi_fd, 1, data_win_ep),
'lziv': apply(lziv, 1, data_win_ep),
}
df_chan['Channel'] = f
# Append to a larger dataframe
df_all.append(df_chan)
df_all = pd.DataFrame(df_all) df_all.to_csv(r'E:\study\1_nonlinear.csv')
Hello,
I'm trying to use your entropy analysis algorithm on 2-minute resting-state EEG with 64 channels. Is there a way to create a df_feat that includes in columns or rows all the channels?
This is the code I have thus far.
P1
Load data as a eeglab file
raw = mne.io.read_raw_eeglab('E:/study/EEGLAB/restingstate/1_restingstate.set', montage=None, eog=(), preload=True, uint16_codec=None, verbose=None)
Load data
data = raw._data * 1e6
sf = raw.info['sfreq'] chan = raw.ch_names
ch_names = chan
times = np.arange(data.size) / sf
times = np.arange(data.shape[1]) / sf print(data.shape, chan, times)
data = data[0, :] # 0 indicates first electrode location, change number to change electrode - to see which number is each electrode look at variable 'chan' print(data.shape, np.round(data[0:5], 3))
Convert the EEG data to 120-sec data
times, data_win = yasa.sliding_window(data, sf, window=120)
Convert times to minutes
times /= 60
data_win.shape
from numpy import apply_along_axis as apply
df_feat = {
Entropy
}
df_feat = pd.DataFrame(df_feat) df_feat.head()
def lziv(x): """Binarize the EEG signal and calculate the Lempel-Ziv complexity. """ return ent.lziv_complexity(x > x.mean(), normalize=True)
df_feat['lziv'] = apply(lziv, 1, data_win) # Slow
Any help will be greatly appreciated!