<jupyter_start><jupyter_text>`spudtr` epochs dataframe format`spudtr` epochs are `pandas.DataFrame` objects.There are three key elements: 1. `epoch_id` an index-like integer column, where each value designates a unique epoch 2. `time` an index-like column of integer timestamps, the same in each epoch 3.  the rest of the data columns There must be at least one epoch.There must be at least one timepoint.All the epochs must be timestamped exactly the same way.> NOTE: timestamps are positive and negative integers, the units are unspecified: milliseconds, months, nanoseconds, hours.<jupyter_code>import pandas as pd
from matplotlib import pyplot as plt

from spudtr import get_demo_df, P3_1500_FEATHER
from spudtr import epf
import spudtr.fake_epochs_data as fake_data<jupyter_output><empty_output><jupyter_text>**Example: simulated categorical and continuous data**The `epoch_id` column is "epoch_id", there are four epochs: 0, 1, 2, 3.The `time` column is "days", there are 31 days in each epoch, 0, 1, 2, ..., 31.The rest of the columns are the data recorded in each epoch at each time stamp.<jupyter_code>n_epochs_per_category = 2
sim_epochs_df, channels = fake_data._generate(
    n_epochs=n_epochs_per_category,
    n_samples=32,
    n_categories=2,
    n_channels=4,
    time="days",
    epoch_id="epoch_id",
    seed=10,
)
display(sim_epochs_df)<jupyter_output><empty_output><jupyter_text>**Example: EEG data**The epoch index column is `epoch_id`, there are 600 epochs numbered: 0, 1, 2, ..., 600.  There are 600 not 601 epochs here because `epoch_id` 392 was excluded: the relevant event marked a pause in the recording not a stimulus. The epoch ids must be unique but they can be gappy and out of order.The time column is `time_ms`, there are 375 digital samples in each epoch at 4 ms intervals, -748, -744, ..., 744, 748The rest of the columns are the data recorded in each epoch at each time stamp.<jupyter_code>eeg_epochs_df = get_demo_df(P3_1500_FEATHER)
display(len(eeg_epochs_df["epoch_id"].unique()))
eeg_epochs_df
eeg_epochs_df.query("epoch_id == 392")<jupyter_output><empty_output><jupyter_text>**Always check the epoch x time format**When things go well the check quietly succeeds.When they don't the reason appears at the bottom of the messages. Example: This check of the simulated data **SUCCEEDS**.<jupyter_code>epf.check_epochs(sim_epochs_df, ['channel0', 'channel1'], epoch_id="epoch_id", time="days")<jupyter_output><empty_output><jupyter_text>Example: this checks **FAILS** because the data column named "bogus_channel0"  doesn't exist in the data.<jupyter_code>epf.check_epochs(sim_epochs_df, ['bogus_channel0', 'channel1'], epoch_id="epoch_id", time="days")<jupyter_output><empty_output><jupyter_text>Example: this checks **FAILS** because the `time` column named "hours" doesn't exist.<jupyter_code>epf.check_epochs(sim_epochs_df, ['channel0', 'channel1'], epoch_id="epoch_id", time="hours")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.09681787406905891, 'fraction_numerical': 0.025389302640487475, 'mean_word_length': 6.242647058823529, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '350186', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1032, 'n_tokens_neox': 974, 'n_words': 327, 'path': 'docs/user_guide/epochs_data/epochs_format.ipynb', 'repo_name': 'turbach/spudtr', 'size': '2954'}