Module 0: Python Bootcamp for EEG Analysis Workbook

Welcome to your Python programming journey in neuroscience! This interactive workbook contains exercises designed to test your understanding of Python concepts in the context of EEG data analysis. Complete the exercises digitally or on paper, then implement your solutions in your Python environment.
How to use this workbook:
• Click the checkboxes to mark your answers
• Fill in the blanks with appropriate Python code
• Write complete solutions in the provided spaces
• Test all your answers in your Python IDE or Jupyter notebook
• Check your work with the answer key at the end

Topic 2: Python with Neuroscience Examples

1

EEG Channel Variables

Complete the following code to organize EEG channels by brain region:

# Define channel counts for each brain region frontal_count = # Fp1, Fp2, F3, F4 parietal_count = 4 temporal_count = # T3, T4, T5, T6 occipital_count = 2 # O1, O2 # Create lists of channel names frontal_channels = ['Fp1', 'Fp2', , ] temporal_channels = [ , 'T4', 'T5', ] # Combine all channels into one list all_channels = frontal_channels + + temporal_channels + # Calculate total number of channels total_channels = (all_channels) print(f"Total EEG channels: { }")

Question: What function would you use to find how many times 'Fp1' appears in all_channels?

2

Sampling Rate Calculations

Complete this function to calculate EEG recording parameters:

def calculate_eeg_params(sampling_rate, duration_seconds, num_channels): # Calculate samples per channel samples_per_channel = * # Calculate total data points total_points = samples_per_channel * # Calculate Nyquist frequency nyquist_freq = / 2 # File size in MB (4 bytes per sample) file_size_mb = (total_points * 4) / ( * 1024) return { 'samples_per_channel': samples_per_channel, 'total_points': total_points, 'nyquist_frequency': nyquist_freq, 'file_size_mb': file_size_mb } # Test with 256 Hz, 10 seconds, 32 channels result = calculate_eeg_params( , , )

True or False:

Statement True False
A 256 Hz sampling rate can accurately capture 150 Hz signals
The Nyquist frequency determines the highest frequency we can measure
Doubling the sampling rate doubles the file size

Topic 3: NumPy for EEG Data

3

Creating EEG Arrays

Fill in the blanks to create and manipulate EEG data arrays:

import numpy as np # Create time array for 5 seconds at 250 Hz sampling_rate = 250 duration = 5 time = np. (0, duration, ) # Create 8-channel EEG data array with random noise num_channels = 8 num_samples = len(time) eeg_data = np.random. ((num_channels, num_samples)) # Add 10 Hz sine wave to channel 0 frequency = 10 amplitude = 50 # microvolts eeg_data[0, :] += amplitude * np. (2 * np. * frequency * time) # Extract data from channels 2 to 5 subset = eeg_data[ : , :] # Calculate mean across all channels (axis=?) channel_means = np.mean(eeg_data, axis= )

Match the NumPy functions with their EEG applications:

1. np.fft.fft()
2. np.std()
3. np.correlate()
4. np.concatenate()
A. Calculate signal variance
B. Frequency analysis
C. Combine multiple recordings
D. Find signal relationships
Match numbers to letters: 1-___, 2-___, 3-___, 4-___
4

Epoch Extraction Logic

Complete the epoch extraction function:

def extract_epoch(eeg_data, event_sample, pre_samples, post_samples): """Extract a single epoch around an event""" # Calculate start and end indices start_idx = event_sample - end_idx = event_sample + # Check boundaries if start_idx < 0 or end_idx > eeg_data.shape[ ]: return None # Extract epoch (all channels, time window) epoch = eeg_data[ , start_idx: ] return epoch # Convert time to samples: 200ms = ? samples at 250 Hz pre_time_ms = 200 pre_samples = int(pre_time_ms * / )
Remember: samples = time_in_seconds × sampling_rate

Select all correct statements about epoching:

Topic 4: Pandas for EEG Data

5

Event Data Management

Complete the code to analyze an EEG experiment's behavioral data:

import pandas as pd # Create event log DataFrame events_dict = { 'timestamp': [1.2, 2.5, 3.8, 5.1, 6.4], 'event_type': ['stimulus', 'response', 'stimulus', 'response', 'stimulus'], 'reaction_time': [None, 1.3, None, 1.3, None], 'accuracy': [None, 1, None, 0, None] } df = pd. (events_dict) # Filter only response events responses = df[df['event_type'] == ] # Calculate mean reaction time (exclude None values) mean_rt = responses['reaction_time']. () # Count accurate responses accurate_count = responses['accuracy']. () # Group by event type and count event_counts = df. ('event_type').size()

Which Pandas method would you use for each task?

Task Method
Remove rows with missing reaction times
  • dropna()
  • fillna()
  • isna()
Sort events by timestamp
  • sort_index()
  • sort_values()
  • order_by()
Save DataFrame to CSV
  • save_csv()
  • to_csv()
  • write_csv()
6

Power Band Analysis

Complete this code to organize EEG frequency band data:

# Define frequency bands bands = { 'delta': (0.5, 4), 'theta': ( , ), 'alpha': (8, 13), 'beta': ( , 30), 'gamma': (30, ) } # Create DataFrame for power values power_data = { 'subject': ['S01', 'S01', 'S02', 'S02'], 'channel': ['Fz', 'Cz', 'Fz', 'Cz'], 'alpha_power': [12.5, 15.3, 10.2, 14.8], 'beta_power': [8.3, 7.9, 9.1, 8.5] } df_power = pd.DataFrame(power_data) # Calculate mean power per subject subject_means = df_power.groupby( )[['alpha_power', 'beta_power']]. () # Find subject with highest alpha power max_alpha_subject = df_power.loc[df_power['alpha_power']. (), 'subject']. ()

What's the correct way to create a MultiIndex DataFrame for channels × frequency bands?

Topic 5: Matplotlib for EEG Visualization

7

Basic EEG Plotting

Complete the code to create a multi-channel EEG plot:

import matplotlib.pyplot as plt def plot_eeg(data, channel_names, sampling_rate): n_channels = data.shape[0] n_samples = data.shape[1] time = np.arange(n_samples) / # Create figure and axis fig, = plt.subplots(figsize=(12, 8)) # Plot each channel with offset for i in range(n_channels): offset = i * 100 # microvolts spacing plt. (time, data[i, :] + offset, 'b-', linewidth=0.5) # Add channel label plt. (0, offset, channel_names[i], fontsize=8) # Set labels plt.xlabel( ) plt.ylabel('Channel') plt.title('Multi-channel EEG') # Add grid plt. (True, alpha=0.3) plt.tight_layout() plt.show()

Match the matplotlib functions with their purpose:

Function Purpose Options
plt.specgram()
  • Create a spectrogram
  • Draw spectrum lines
  • Plot spectral density
plt.axvline()
  • Add vertical axis
  • Draw vertical line
  • Create line plot
plt.colorbar()
  • Change plot colors
  • Add color scale
  • Create bar chart
8

Spectrogram Parameters

Choose the correct parameters for EEG spectrogram visualization:

# Create spectrogram plt.figure(figsize=(10, 6)) Pxx, freqs, bins, im = plt.specgram( signal, NFFT= , # Window size (power of 2) Fs= , # Sampling frequency noverlap= , # Overlap between windows cmap=' ' # Colormap ) # Limit frequency range for EEG plt.ylim([0, ]) # Typical EEG range in Hz # Add colorbar cbar = plt.colorbar() cbar.set_label(' ')

For a 256 Hz EEG signal, which NFFT value is most appropriate?

What overlap percentage typically provides good time-frequency resolution?

Final Project: Complete EEG Analysis Pipeline

9

Integrated EEG Analysis

Complete this comprehensive EEG analysis class by filling in the missing parts:

class EEGAnalyzer: def __init__(self, data, channels, fs): self.data = data # numpy array (channels × samples) self.channels = channels # list of channel names self.fs = fs # sampling rate def get_time_array(self): """Return time array in seconds""" n_samples = self.data.shape[ ] return np.arange(n_samples) / self. def filter_data(self, low_freq, high_freq): """Apply bandpass filter""" from scipy import signal # Design Butterworth filter nyquist = self.fs / low = low_freq / nyquist high = high_freq / nyquist b, a = signal. (4, [low, high], btype='band') # Apply filter to each channel filtered = np.zeros_like(self.data) for ch in range(self.data.shape[0]): filtered[ch, :] = signal. (b, a, self.data[ch, :]) return filtered def calculate_band_power(self, band_name): """Calculate power in specific frequency band""" bands = { 'delta': (0.5, 4), 'theta': (4, 8), 'alpha': (8, 13), 'beta': (13, 30), 'gamma': (30, 50) } low, high = bands[ ] # Filter data to band band_data = self.filter_data( , ) # Calculate power (variance of filtered signal) power = np. (band_data, axis=1) return power

Select the correct filter design considerations:

10

Analysis Questions

Answer these questions about the EEG analysis pipeline:

  1. What order should these processing steps typically follow?
    • Filtering → Epoching → Artifact removal → Analysis
    • Epoching → Filtering → Analysis → Artifact removal
    • Artifact removal → Filtering → Epoching → Analysis
    • Analysis → Filtering → Epoching → Artifact removal
  2. For a 30-minute EEG recording at 500 Hz with 64 channels, calculate the uncompressed file size:
  3. Write the NumPy code to calculate the correlation between two EEG channels:
  4. What sampling rate would you need for gamma band activity up to 80 Hz?
    Minimum: Hz
    Recommended: Hz

Answer Key

Use this section to check your answers after completing all exercises.

Exercise 1: frontal_count = 4, temporal_count = 4, 'F3', 'F4', 'T3', 'T6', parietal_channels, occipital_channels, len, total_channels
Multiple choice: all_channels.count('Fp1')
Exercise 2: sampling_rate, duration_seconds, num_channels, sampling_rate, 1024, 256, 10, 32
True/False: F, T, T
Exercise 3: linspace, sampling_rate * duration, randn, sin, pi, 2, 5, 1
Matching: 1-B, 2-A, 3-D, 4-C
Exercise 4: pre_samples, post_samples, 1, :, end_idx, 250, 1000
Checkboxes: 1st, 3rd, and 4th statements are correct
Exercise 5: DataFrame, 'response', mean, sum, groupby
Methods: dropna(), sort_values(), to_csv()
Exercise 6: 4, 8, 13, 50, 'subject', mean, idxmax, iloc[0]
Multiple choice: pd.MultiIndex.from_product([channels, bands])
Exercise 7: sampling_rate, ax, plot, text, 'Time (s)', grid
Functions: specgram - Create a spectrogram, axvline - Draw vertical line, colorbar - Add color scale
Exercise 8: 256, sampling_rate, 128, 'viridis' or 'jet', 50, 'Power (dB/Hz)'
Multiple choice: 256 (NFFT), 50% (overlap)
Exercise 9: 1, fs, 2, butter, filtfilt, band_name, low, high, var
Checkboxes: 1st and 3rd statements are correct
Exercise 10: 1. Artifact removal → Filtering → Epoching → Analysis 2. 30 min × 60 s/min × 500 Hz × 64 channels × 4 bytes = 230.4 MB 3. correlation = np.corrcoef(channel1, channel2)[0, 1] 4. Minimum: 160 Hz, Recommended: 250-500 Hz

Congratulations! 🎉

You've completed the Module 0 workbook. Make sure to implement all these exercises in your Python environment and experiment with different parameters. This hands-on practice is essential for mastering EEG analysis programming!

Next step: Move on to Module 1 - Signal Processing Fundamentals