{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 💤 CMI Sleep State Detection - Chunked Dataset","metadata":{}},{"cell_type":"markdown","source":"<div class=\"alert alert-success\" role=\"alert\">\n  <h3>This notebook aims to group/partition the dataset by series ID for fast access</h3>\n</div>\n\nThe data used is that from [the 2nd update](https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states/discussion/440697#2448756).\n\nOutput of this notebook is linked to this dataset: [CMI Sleep State Detection - Grouped by Series ID](https://www.kaggle.com/datasets/rimbax/cmi-sleep-state-detection-chunked-by-series-id).\n\nPlease refer to that dataset for detailed description about the output.\n\nCredits:\n1. [Sleep State: Fast Data Access with Parquet](https://www.kaggle.com/code/tolgadincer/sleep-state-fast-data-access-with-parquet/) by [Tolga @tolgadincer](https://www.kaggle.com/tolgadincer) for the parquet fast access tips","metadata":{"execution":{"iopub.status.busy":"2023-09-21T15:46:21.517510Z","iopub.execute_input":"2023-09-21T15:46:21.518002Z","iopub.status.idle":"2023-09-21T15:46:21.526656Z","shell.execute_reply.started":"2023-09-21T15:46:21.517963Z","shell.execute_reply":"2023-09-21T15:46:21.525108Z"}}},{"cell_type":"code","source":"import gc\nimport os\nimport json\nimport warnings\nimport pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport pyarrow as pa\nimport pyarrow.parquet as pq\n\nfrom time import time\nfrom tqdm.notebook import tqdm\nfrom functools import lru_cache\nfrom IPython.display import Markdown\n\n# Suppress the SettingWithCopyWarning\nwarnings.filterwarnings('ignore', category=pd.errors.SettingWithCopyWarning)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:06:41.342236Z","iopub.execute_input":"2023-09-28T16:06:41.342666Z","iopub.status.idle":"2023-09-28T16:06:42.771208Z","shell.execute_reply.started":"2023-09-28T16:06:41.342618Z","shell.execute_reply":"2023-09-28T16:06:42.769930Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Events Summary","metadata":{}},{"cell_type":"code","source":"tz_localize = lambda x: x.tz_localize(None)\n\ndef to_datetime(pd_series: pd.Series):\n    return (pd.to_datetime(pd_series, utc=True) - pd.Timedelta(hours=4)).apply(tz_localize)\n\nevents = pd.read_csv('/kaggle/input/child-mind-institute-detect-sleep-states/train_events.csv')\nevents.timestamp = to_datetime(events.timestamp)\nevents.step = events.step.astype('Int32')\nevents.to_csv('train_events.csv', index=False)\n\npivot = pd.pivot_table(events, index='series_id', columns='event', values='timestamp', aggfunc=['min', 'max'])\npivot.columns = [f'{level}_{col}_ts' for level, col in pivot.columns]\n\nevents_summary = events \\\n    .groupby('series_id').agg({'series_id': 'count', 'step': 'count'}) \\\n    .rename({'series_id': 'count_events', 'step': 'count_non_null_events'}, axis=1) \\\n    .join(pivot, how='left')\n\nevents_summary.insert(\n    2, 'pct_non_null_events', events_summary.count_non_null_events / events_summary.count_events\n)\n\nevents_summary = events_summary.sort_values(['pct_non_null_events', 'count_non_null_events'], ascending=[False, True])\n\ncomplete_series = events_summary.query('pct_non_null_events == 1.0')\nempty_series    = events_summary.query('pct_non_null_events == 0.0')\nincomplete_series = events_summary.query('(pct_non_null_events > 0.0) & (pct_non_null_events < 1.0)')\n\nseries_ids = sorted(events_summary.index)\nsid2idx = dict(zip(series_ids, range(len(series_ids))))\n\ncomplete_series_ids = sorted(complete_series.index.tolist())\nempty_series_ids = sorted(empty_series.index.tolist())\nincomplete_series_ids = sorted(incomplete_series.index.tolist())\n\nevents_summary.to_csv('train_events_summary.csv')\n\nevents_summary","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:06:42.773758Z","iopub.execute_input":"2023-09-28T16:06:42.774386Z","iopub.status.idle":"2023-09-28T16:06:43.110733Z","shell.execute_reply.started":"2023-09-28T16:06:42.774340Z","shell.execute_reply":"2023-09-28T16:06:43.109362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Grouped Events","metadata":{}},{"cell_type":"code","source":"row_idx = ['series_id', 'night']\ngrouped_events = []\n\nfor ev in ['onset', 'wakeup']:\n    e = events.query(f\"event == '{ev}'\") \\\n        .groupby(row_idx) \\\n        .agg({'step': 'max', 'timestamp': 'max'})\n    grouped_events.append(e)\n    \n\ngrouped_events =  pd.merge(grouped_events[0].reset_index(), grouped_events[1].reset_index(),\n                           suffixes=['_onset', '_wakeup'], left_on=row_idx, right_on=row_idx)\n\ngrouped_events[['step_onset', 'step_wakeup']] = grouped_events[['step_onset', 'step_wakeup']].astype('Int32')\n\ngrouped_events.to_csv('train_events_grouped.csv', index=False)\ngrouped_events.head(10)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:06:43.114201Z","iopub.execute_input":"2023-09-28T16:06:43.114520Z","iopub.status.idle":"2023-09-28T16:06:43.224875Z","shell.execute_reply.started":"2023-09-28T16:06:43.114493Z","shell.execute_reply":"2023-09-28T16:06:43.224062Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Grouping Series to Parquet File","metadata":{}},{"cell_type":"code","source":"series_file = (\n    \"/kaggle/input/child-mind-institute-detect-sleep-states/train_series.parquet\"\n)\n\n# This schema can be optimized.\nparquet_schema = pa.schema(\n    [\n        (\"series_id\", pa.string()),\n        (\"step\", pa.int32()),\n        (\"timestamp\", pa.string()),\n        (\"anglez\", pa.float32()),\n        (\"enmo\", pa.float32()),\n    ]\n)\n\nprint('Start loading train data...')\n\nst = time()\nparquet_file = pq.ParquetFile(series_file)\ndata = parquet_file.read().to_pandas()\nen = time()\neta = int(en - st)\n\nprint(f'Done loading train data in {eta}s')","metadata":{"_kg_hide-output":false,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:06:43.226172Z","iopub.execute_input":"2023-09-28T16:06:43.227153Z","iopub.status.idle":"2023-09-28T16:07:45.253618Z","shell.execute_reply.started":"2023-09-28T16:06:43.227121Z","shell.execute_reply":"2023-09-28T16:07:45.252965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Start grouping data...')\nst = time()\n\noutput_path = f'train_series_grouped.parquet'\nwriter = pq.ParquetWriter(output_path, parquet_schema)\n\ngrouped_data = data.groupby(\"series_id\")\nfor series_id, group in tqdm(grouped_data):\n    table = pa.Table.from_pandas(group, schema=parquet_schema)\n    writer.write_table(table)\nwriter.close()\n\nen = time()\neta = int(en - st)\nprint(f'Done grouping in {eta}s -- saved to {output_path}')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:07:45.255476Z","iopub.execute_input":"2023-09-28T16:07:45.255779Z","iopub.status.idle":"2023-09-28T16:09:14.700882Z","shell.execute_reply.started":"2023-09-28T16:07:45.255753Z","shell.execute_reply":"2023-09-28T16:09:14.699770Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"del data, grouped_data\ngc.collect()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:09:14.702095Z","iopub.execute_input":"2023-09-28T16:09:14.702406Z","iopub.status.idle":"2023-09-28T16:09:16.361687Z","shell.execute_reply.started":"2023-09-28T16:09:14.702378Z","shell.execute_reply":"2023-09-28T16:09:16.360870Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Batch Data","metadata":{}},{"cell_type":"code","source":"_root = ''\n\ntz_localize = lambda x: x.tz_localize(None)\n\ndef to_datetime(pd_series: pd.Series):\n    if pd_series.str.contains('T').any():\n        return (pd.to_datetime(pd_series, utc=True) - pd.Timedelta(hours=4)).apply(tz_localize)\n    else:\n        return pd.to_datetime(pd_series).apply(tz_localize)\n\n\n# load files\nevents = pd.read_csv(f'train_events.csv')\nevents.step = events.step.astype('Int32')\n\ngrouped_events = pd.read_csv(f'train_events_grouped.csv').set_index('series_id')\ngrouped_events.step_onset = grouped_events.step_onset.astype('Int32')\ngrouped_events.step_wakeup = grouped_events.step_wakeup.astype('Int32')\n\nevents_summary = pd.read_csv(f'train_events_summary.csv').set_index('series_id')\nevents_summary = events_summary.sort_values(['pct_non_null_events', 'count_non_null_events'], ascending=[False, True])\n\n# to timestamp\nevents.timestamp = to_datetime(events.timestamp)\ngrouped_events.timestamp_onset = to_datetime(grouped_events.timestamp_onset)\ngrouped_events.timestamp_wakeup = to_datetime(grouped_events.timestamp_wakeup)\nevents_summary.min_onset_ts = to_datetime(events_summary.min_onset_ts)\nevents_summary.max_onset_ts = to_datetime(events_summary.max_onset_ts)\nevents_summary.min_wakeup_ts = to_datetime(events_summary.min_wakeup_ts)\nevents_summary.max_wakeup_ts = to_datetime(events_summary.max_wakeup_ts)\n\n# load series IDs\ncomplete_series = events_summary.query('pct_non_null_events == 1.0')\nempty_series    = events_summary.query('pct_non_null_events == 0.0')\nincomplete_series = events_summary.query('(pct_non_null_events > 0.0) & (pct_non_null_events < 1.0)')\n\ncomplete_series_ids = sorted(complete_series.index.tolist())\nempty_series_ids = sorted(empty_series.index.tolist())\nincomplete_series_ids = sorted(incomplete_series.index.tolist())\n\nseries_ids = sorted(events_summary.index)\nmapping = dict(zip(series_ids, list(range(len(series_ids)))))\n\ndata = pq.ParquetFile(f\"train_series_grouped.parquet\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:09:16.363349Z","iopub.execute_input":"2023-09-28T16:09:16.364046Z","iopub.status.idle":"2023-09-28T16:09:16.654574Z","shell.execute_reply.started":"2023-09-28T16:09:16.364005Z","shell.execute_reply":"2023-09-28T16:09:16.653329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"@lru_cache(maxsize=384)\ndef get_train_series(series_id: str | tuple, localize_ts=True, **kwargs):\n    if 'columns' in kwargs:\n        kwargs['columns'] = list(kwargs['columns'])\n    \n    if isinstance(series_id, str):\n        table = data.read_row_group(mapping[series_id], **kwargs)\n    elif isinstance(series_id, tuple):\n        table = data.read_row_groups([mapping[s] for s in series_id], **kwargs)\n    else:\n        raise ValueError('series_id have to be an int or a tuple')\n        \n    df = table.to_pandas()\n    if 'timestamp' in df.columns and localize_ts:\n        df.timestamp = to_datetime(df.timestamp)\n    \n    return df\n\n\ndef process(series_id):\n    series = get_train_series(series_id)\n    event = events[events.series_id == series_id]\n\n    samples = []\n    subseries_id = 0\n    for idx in event.index:\n        if pd.isnull(event.loc[idx, 'timestamp']):\n            subseries_id += 1\n            continue\n\n        if idx == event.index[0]:\n            x = event.loc[idx, 'timestamp']\n            seq = series[series.timestamp.lt(x)]\n            seq.loc[:, 'subseries_id'] = subseries_id\n            samples.append(seq)\n\n        # current event is not null, onset, but previous event is null: extend current min ts to previous closest 15:00:00\n        elif pd.isnull(event.loc[idx - 1, 'timestamp']) & (event.loc[idx, 'event'] == 'onset'):\n            x = event.loc[idx, 'timestamp']\n            closest_1500 = pd.to_datetime(x.strftime('%Y-%m-%d 15:00:00'))\n            if x.time() < pd.Timestamp('15:00:00').time():\n                closest_1500 = closest_1500 - pd.Timedelta(days=1)\n\n            seq = series[series.timestamp.ge(closest_1500) & series.timestamp.lt(x)]\n            seq.loc[:, 'subseries_id'] = subseries_id\n            samples.append(seq)\n\n        # current event is not null, wakeup, but previous event is null: can't do anything\n        elif pd.isnull(event.loc[idx - 1, 'timestamp']) & (event.loc[idx, 'event'] == 'wakeup'):\n            subseries_id += 1\n            continue\n\n        # current event is not null, wakeup, but next event is null: extend current max ts to next closest 15:00:00\n        elif idx != event.index[-1]:\n            if pd.isnull(event.loc[idx + 1, 'timestamp']) & (event.loc[idx, 'event'] == 'wakeup'):\n                x = event.loc[idx, 'timestamp']\n                closest_1500 = pd.to_datetime(x.strftime('%Y-%m-%d 15:00:00'))\n                if x.time() >= pd.Timestamp('15:00:00').time():\n                    closest_1500 = closest_1500 + pd.Timedelta(days=1)\n\n                seq = series[series.timestamp.ge(x) & series.timestamp.lt(closest_1500)]\n                seq.loc[:, 'subseries_id'] = subseries_id\n                samples.append(seq)\n            elif pd.isnull(event.loc[idx + 1, 'timestamp']) & (event.loc[idx, 'event'] == 'onset'):\n                subseries_id += 1\n                continue # skip \"onset but not wakeup\"-event\n            else:\n                seq = series[series.step.ge(event.loc[idx - 1, 'step']) & series.step.lt(event.loc[idx, 'step'])]\n                seq.loc[:, 'subseries_id'] = subseries_id\n                samples.append(seq)\n        else:\n            # current event is the last event and not null\n            x = event.loc[idx, 'timestamp']\n            seq = series[series.timestamp.ge(x)]\n            seq.loc[:, 'subseries_id'] = subseries_id\n            samples.append(seq)\n\n    # post-process subseries_id\n    samples = pd.concat(samples)\n    subseries_ids = samples.subseries_id.unique().tolist()\n    subseries_ids = dict(zip(subseries_ids, range(len(subseries_ids))))\n    samples.subseries_id = samples.subseries_id.map(subseries_ids)\n\n    assert (samples.timestamp.shift(-1).iloc[:-1] >= samples.timestamp.iloc[:-1]).all()\n\n    return samples","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T16:15:28.548402Z","iopub.execute_input":"2023-09-28T16:15:28.549050Z","iopub.status.idle":"2023-09-28T16:15:28.627103Z","shell.execute_reply.started":"2023-09-28T16:15:28.549015Z","shell.execute_reply":"2023-09-28T16:15:28.625958Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"parquet_schema = pa.schema(\n    [\n        (\"series_id\", pa.string()),\n        (\"step\", pa.int32()),\n        (\"timestamp\", pa.string()),\n        (\"anglez\", pa.float32()),\n        (\"enmo\", pa.float32()),\n        (\"subseries_id\", pa.int32())\n    ]\n)\n\nprint(f'Start grouping data...')\nst = time()\n\n# grouped series summary\ngss = []\n\noutput_path = f'train_series_grouped_by_subseries.parquet'\nwriter = pq.ParquetWriter(output_path, parquet_schema)\n\nN = len(series_ids[:])\nfor j, series_id in enumerate(tqdm(series_ids[:])):\n    if events_summary.loc[series_id, 'pct_non_null_events'] == 0.0:\n        continue\n    \n    df_ = process(series_id)\n    df_.assign(series_id=series_id)\n    \n    grouped_data = df_.groupby([\"series_id\", \"subseries_id\"])\n    gss.append(grouped_data.agg({\n        'step': ['min', 'max'],\n        'timestamp': ['min', 'max']\n    }))\n    \n    for _, group in grouped_data:\n        group.timestamp = group.timestamp.astype(str)\n        table = pa.Table.from_pandas(group, schema=parquet_schema)\n        writer.write_table(table)\n    \nwriter.close()\n\ngss = pd.concat(gss)\ngss.columns = ['min_step', 'max_step', 'min_ts', 'max_ts']\ngss.to_csv('train_series_grouped_summary.csv')\n\nen = time()\neta = int(en - st)\nprint(f'Done in {eta}s')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-09-28T13:01:36.096175Z","iopub.execute_input":"2023-09-28T13:01:36.096672Z","iopub.status.idle":"2023-09-28T13:20:15.534758Z","shell.execute_reply.started":"2023-09-28T13:01:36.096636Z","shell.execute_reply":"2023-09-28T13:20:15.533279Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# How to Read The Data","metadata":{}},{"cell_type":"code","source":"_root = ''\n\ntz_localize = lambda x: x.tz_localize(None)\n\ndef to_datetime(pd_series: pd.Series):\n    if pd_series.str.contains('T').any():\n        return (pd.to_datetime(pd_series, utc=True) - pd.Timedelta(hours=4)).apply(tz_localize)\n    else:\n        return pd.to_datetime(pd_series).apply(tz_localize)\n\n\n# load files\nevents = pd.read_csv(f'train_events.csv')\nevents.step = events.step.astype('Int32')\n\ngrouped_events = pd.read_csv(f'train_events_grouped.csv').set_index('series_id')\ngrouped_events.step_onset = grouped_events.step_onset.astype('Int32')\ngrouped_events.step_wakeup = grouped_events.step_wakeup.astype('Int32')\n\nevents_summary = pd.read_csv(f'train_events_summary.csv').set_index('series_id')\nevents_summary = events_summary.sort_values(['pct_non_null_events', 'count_non_null_events'], ascending=[False, True])\n\n# grouped series summary\ngss = pd.read_csv('train_series_grouped_summary.csv').set_index(['series_id', 'subseries_id'])\ngss.min_step = gss.min_step.astype('Int32')\ngss.max_step = gss.max_step.astype('Int32')\n\nmapping = pd.DataFrame(gss.index.tolist(), columns=['series_id', 'subseries_id'])\nmapping.index.name = 'row_num'\n\n# to timestamp\nevents.timestamp = to_datetime(events.timestamp)\ngrouped_events.timestamp_onset = to_datetime(grouped_events.timestamp_onset)\ngrouped_events.timestamp_wakeup = to_datetime(grouped_events.timestamp_wakeup)\nevents_summary.min_onset_ts = to_datetime(events_summary.min_onset_ts)\nevents_summary.max_onset_ts = to_datetime(events_summary.max_onset_ts)\nevents_summary.min_wakeup_ts = to_datetime(events_summary.min_wakeup_ts)\nevents_summary.max_wakeup_ts = to_datetime(events_summary.max_wakeup_ts)\ngss.min_ts = to_datetime(gss.min_ts)\ngss.max_ts = to_datetime(gss.max_ts)","metadata":{"execution":{"iopub.status.busy":"2023-09-28T13:33:48.061567Z","iopub.execute_input":"2023-09-28T13:33:48.063419Z","iopub.status.idle":"2023-09-28T13:33:48.486078Z","shell.execute_reply.started":"2023-09-28T13:33:48.063362Z","shell.execute_reply":"2023-09-28T13:33:48.485007Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = pq.ParquetFile(f\"train_series_grouped_by_subseries.parquet\")\n\n@lru_cache(maxsize=768)\ndef get_train_series(\n    row_num: int | tuple | None = None,\n    series_id: str | tuple | None = None,\n    subseries_id: int | tuple | None = None,\n    localize_ts=True, **kwargs\n):\n    assert row_num is not None or series_id is not None, 'row_num or series_id should be specified!'\n    assert subseries_id is None or (subseries_id is not None and series_id is not None), \\\n        'series_id should also be specified if subseries_id is specified!'\n    \n    if not(\n        isinstance(row_num, (int, tuple))\n        or isinstance(series_id, (str, tuple))\n        or isinstance(subseries_id, (int, tuple))\n    ):\n        raise ValueError('args invalid type!')\n    \n    if 'columns' in kwargs:\n        kwargs['columns'] = list(kwargs['columns'])\n    \n    if row_num is not None:\n        row_num = (row_num,) if isinstance(row_num, int) else tuple(row_num)\n    elif series_id is not None:\n        series_id = (series_id,) if isinstance(series_id, str) else tuple(series_id)\n        row_num = mapping[mapping.series_id.isin(series_id)].index.tolist()\n    elif subseries_id is not None:\n        series_id = (series_id,) if isinstance(series_id, str) else tuple(series_id)\n        subseries_id = (subseries_id,) if isinstance(subseries_id, int) else tuple(subseries_id)\n        row_num = mapping[\n            mapping.series_id.isin(series_id) & (mapping.subseries_id == subseries_id)\n        ].index.tolist()\n    \n    table = data.read_row_groups(row_num, **kwargs)\n    df = table.to_pandas()\n    if 'timestamp' in df.columns and localize_ts:\n        df.timestamp = to_datetime(df.timestamp)\n    \n    return df","metadata":{"execution":{"iopub.status.busy":"2023-09-28T13:33:56.625221Z","iopub.execute_input":"2023-09-28T13:33:56.625712Z","iopub.status.idle":"2023-09-28T13:33:56.654752Z","shell.execute_reply.started":"2023-09-28T13:33:56.625675Z","shell.execute_reply":"2023-09-28T13:33:56.653451Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_train_series(row_num=0)","metadata":{"execution":{"iopub.status.busy":"2023-09-28T13:33:58.842815Z","iopub.execute_input":"2023-09-28T13:33:58.843311Z","iopub.status.idle":"2023-09-28T13:33:59.196876Z","shell.execute_reply.started":"2023-09-28T13:33:58.843252Z","shell.execute_reply":"2023-09-28T13:33:59.195558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_train_series(row_num=(0, 1), localize_ts=False)","metadata":{"execution":{"iopub.status.busy":"2023-09-28T13:34:08.255053Z","iopub.execute_input":"2023-09-28T13:34:08.256606Z","iopub.status.idle":"2023-09-28T13:34:08.334800Z","shell.execute_reply.started":"2023-09-28T13:34:08.256546Z","shell.execute_reply":"2023-09-28T13:34:08.333800Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_train_series(series_id=('fe90110788d2',), columns=('step', 'timestamp'))","metadata":{"execution":{"iopub.status.busy":"2023-09-28T13:34:12.169986Z","iopub.execute_input":"2023-09-28T13:34:12.170453Z","iopub.status.idle":"2023-09-28T13:34:16.661553Z","shell.execute_reply.started":"2023-09-28T13:34:12.170418Z","shell.execute_reply":"2023-09-28T13:34:16.660317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"get_train_series(series_id='03d92c9f6f8a', subseries_id=(0, 3))","metadata":{"execution":{"iopub.status.busy":"2023-09-28T13:34:21.741392Z","iopub.execute_input":"2023-09-28T13:34:21.741858Z","iopub.status.idle":"2023-09-28T13:34:22.417591Z","shell.execute_reply.started":"2023-09-28T13:34:21.741824Z","shell.execute_reply":"2023-09-28T13:34:22.416080Z"},"trusted":true},"execution_count":null,"outputs":[]}]}