{"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-28T12:58:05.307004Z","iopub.execute_input":"2023-09-28T12:58:05.307408Z","iopub.status.idle":"2023-09-28T12:58:06.760306Z","shell.execute_reply.started":"2023-09-28T12:58:05.307373Z","shell.execute_reply":"2023-09-28T12:58:06.759076Z"},"jupyter":{"source_hidden":true},"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-28T12:58:06.762278Z","iopub.execute_input":"2023-09-28T12:58:06.762749Z","iopub.status.idle":"2023-09-28T12:58:07.033428Z","shell.execute_reply.started":"2023-09-28T12:58:06.762715Z","shell.execute_reply":"2023-09-28T12:58:07.032346Z"},"jupyter":{"source_hidden":true},"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-28T12:58:07.035230Z","iopub.execute_input":"2023-09-28T12:58:07.035558Z","iopub.status.idle":"2023-09-28T12:58:07.128300Z","shell.execute_reply.started":"2023-09-28T12:58:07.035531Z","shell.execute_reply":"2023-09-28T12:58:07.127178Z"},"jupyter":{"source_hidden":true},"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-28T12:58:07.131361Z","iopub.execute_input":"2023-09-28T12:58:07.131730Z","iopub.status.idle":"2023-09-28T12:59:26.160725Z","shell.execute_reply.started":"2023-09-28T12:58:07.131699Z","shell.execute_reply":"2023-09-28T12:59:26.159724Z"},"jupyter":{"source_hidden":true},"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-28T12:59:26.161728Z","iopub.execute_input":"2023-09-28T12:59:26.162055Z","iopub.status.idle":"2023-09-28T13:01:13.247685Z","shell.execute_reply.started":"2023-09-28T12:59:26.162028Z","shell.execute_reply":"2023-09-28T13:01:13.244805Z"},"jupyter":{"source_hidden":true},"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-28T13:01:13.252526Z","iopub.execute_input":"2023-09-28T13:01:13.253063Z","iopub.status.idle":"2023-09-28T13:01:15.627752Z","shell.execute_reply.started":"2023-09-28T13:01:13.253022Z","shell.execute_reply":"2023-09-28T13:01:15.626170Z"},"jupyter":{"source_hidden":true},"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-28T13:01:15.630061Z","iopub.execute_input":"2023-09-28T13:01:15.630481Z","iopub.status.idle":"2023-09-28T13:01:15.878141Z","shell.execute_reply.started":"2023-09-28T13:01:15.630448Z","shell.execute_reply":"2023-09-28T13:01:15.876707Z"},"jupyter":{"source_hidden":true},"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[1:]:\n        if pd.isnull(event.loc[idx, 'timestamp']):\n            subseries_id += 1\n            continue\n\n        # current event is not null, onset, but previous event is null: extend current min ts to previous closest 15:00:00\n        if 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            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\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-28T13:01:15.880015Z","iopub.execute_input":"2023-09-28T13:01:15.880409Z","iopub.status.idle":"2023-09-28T13:01:15.902116Z","shell.execute_reply.started":"2023-09-28T13:01:15.880375Z","shell.execute_reply":"2023-09-28T13:01:15.901094Z"},"jupyter":{"source_hidden":true},"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([\"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"},"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"},"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":[]}]}