Multi scale entropy =================== Demonstration code for performing a multi scale entropy analysis using MultiScaleEntropy(). Link to script: `feature_extraction/multi_scale_entropy.py `_ .. code-block:: python import os import matplotlib.pyplot as plt import numpy as np from nnsa import MultiScaleEntropy, print_object_summary, EdfReader, SUPPORTED_RESULT_FILE_TYPES, read_result_from_file, \ assert_equal plt.close('all') Parameters. .. code-block:: python # Print the default parameters of MultiScaleAnalysis(): print(MultiScaleEntropy().default_parameters()) # Descriptions of the parameters are documented in the default_parameters() code. # Create an instance of the MultiScaleEntropy class with custom parameters, overruling some defaults: mse = MultiScaleEntropy(artefact_criteria={'max_diff': 200}, segmentation={'segment_length': 5, 'overlap': 0}, mse={'max_scale': 20}) # See if the custom parameters were accepted: print('\nCustom parameters:') print(mse.parameters) Main method: power_analysis. .. code-block:: python # Now that we have initialized a MultiScaleEntropy object with certain parameters, we can run the multi_scale_entropy # method, which performs the actual multi-scale entropy analysis: # Create 2 random signals (5 segments) to simulate 2 channel EEG data (amplitude 50). fs = 128 data_matrix = np.random.rand(2, 5 * mse.parameters['segmentation']['segment_length'] * fs)*100 - 50 result = mse.multi_scale_entropy(data_matrix, fs, channel_labels=None, verbose=1) # Note: the kwargs are optional. # The returned object is a MultiScaleEntropyResult object, which is a high-level interface for # manipulating/visualizing/saving the result: print('\nSummary of result object:') print_object_summary(result) MultiScaleEntropyResult attributes. .. code-block:: python # The main attribute is 'mse', which contains the entropy values per scale, channel and segment. Therefore, # 'mse' is a 3D array with dimensions corresponding to (scales, channels, segments), where mse[i, :, :] corresponds to # scale i+1. print('result.mse: {}'.format(result.mse)) print('result.mse.shape (scales, channels, segments): {}'.format(result.mse.shape)) # The labels of the channels are found in result.channels, such that mse[:, i, :] corresponds to result.channels[i]. print('result.channels: {}'.format(result.channel_labels)) # The time (in seconds) corresponding to the segments in the data in mse: print('result.segment_times: {}'.format(result.segment_times)) # The average mse over all segments are computed (and subsequently stored) by the 'average_mse' property: print('result.average_mse (scales, channels): {}'.format(result.average_mse)) MultiScaleEntropyResult methods. .. code-block:: python # Compute the average slope of the mse curve in the small and large scales per channel, respectively: slope_small, slope_large = result.compute_average_slopes() print('Average slope of mse curve for small scales (channels, segments):\n{}'.format(slope_small)) print('Average slope of mse curve for large scales (channels, segments):\n{}'.format(slope_large)) # Compute the complexity index, i.e. the area under the mse curve, for each segment and each channel: print('Complexity index (channels, segments):\n{}'.format(result.compute_complexity_index())) # Get the maximum value of the multiscale entropy curve: print('Maximum sample entropy (channels, segments):\n{}'.format(result.maximum_mse())) # Plot average mse curves for all channels: result.plot() Save the result. .. code-block:: python # We can save the result to any supported file. To list the supported file types/extensions: print('Supported result file types: {}'.format(SUPPORTED_RESULT_FILE_TYPES)) # E.g. save as hdf5 (the file type to save is automatically detected from the extension of the filename). filename = 'temp_result.hdf5' result.save_to_file(filename) # We can reload the result back to a PowerAnalysisResult object: result_loaded = read_result_from_file(filename) # Remove temporary file. os.remove(filename) # Verify that the loaded object is equal to the original object: result._average_mse = None # Properties won't be saved, so reset average mse to None before the assert_equal test. assert_equal(actual=result_loaded, desired=result) # Will raise an AssertionError if not equal. print('Loaded result object is equal to original object.') MultiScaleEntropy of EegDataset. .. code-block:: python # Specify a file and open a reader to read the data (e.g. EdfReader to read an EDF(+) file). filepath = 'C:/data_temp/test.edf' # Read EEG channels in an EegDataset object. with EdfReader(filepath) as r: ds = r.read_eeg_dataset(dtype=np.float32) # We can specify the dtype, lower precision, means less memory usage. ds_preprocessed = ds.reference('Cz').resample(fs_new=128).filter_saved_filter(filter_name='bandpassfir_a') # We can do the mse analysis for multichannel EEG via the wrapper method 'multi_scale_entropy' of the EegDataset class. # Specify the parameters to the MultiScaleEntropy class as kwargs. if False: # Disable this line, since the multi_scale_entropy will take a long time to compute. result_ds = ds_preprocessed.multi_scale_entropy(segmentation={'segment_length': 5}) Perform on only some segments (the below code is basically what's inside the EegDataset.multi_scale_entropy method). .. code-block:: python # Initialize MultiScaleEntropy object with default arguments. mse = MultiScaleEntropy() # Prepare input matrix for multi_scale_entropy. data_matrix, channel_labels = ds_preprocessed.asarray(return_channel_labels=True) # Sample frequency of all EEG signals is the same if self.asarray() did not raise an error. fs = next((ts.fs for ts in ds_preprocessed.time_series.values())) # Select only some segments. n_segments = 8 data_matrix = data_matrix[:, :n_segments * mse.parameters['segmentation']['segment_length'] * fs] # Run multi_scale_entropy. result_ds_ = mse.multi_scale_entropy(data_matrix, fs=fs, channel_labels=channel_labels) print(result_ds_.mse) result_ds_.plot(segments=[1], plot_fit=True)