{"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":"# Detect Sleep States DataPrepare\n\n### This notebook is inspired by the following [werus23's](https://www.kaggle.com/werus23) amazing notebooks.\n### see also them.\n\nFinding Critical Points using RNNs\n\n - [Data Prep notebook](https://www.kaggle.com/code/werus23/sleep-critical-point-prepare-data)\n - [Training notebook](https://www.kaggle.com/werus23/sleep-critical-point-train)\n - [Inference Notebook](https://www.kaggle.com/code/werus23/sleep-critical-point-infer)\n\nCredits:\n\n - idea: https://www.kaggle.com/competitions/child-mind-institute-detect-sleep-states/discussion/441470\n - dataloader: https://www.kaggle.com/code/henriupton/efficient-loading-memory-usage-visualizations-cmi\n - arch: https://www.kaggle.com/competitions/tlvmc-parkinsons-freezing-gait-prediction/discussion/416410","metadata":{}},{"cell_type":"markdown","source":"My other works\n- [Data preparation Notebook](https://www.kaggle.com/code/itsuki9180/detect-sleep-states-dataprepare)\n- [Training Notebook](https://www.kaggle.com/code/itsuki9180/detect-sleep-states-train) \n- [Inference Notebook](https://www.kaggle.com/code/itsuki9180/detect-sleep-states-dataprepare) <- you are viewing now","metadata":{}},{"cell_type":"markdown","source":"### セル1\nさまざまなライブラリをインポートし、機械学習モデルを実行するためのデバイス（CPUまたはGPU）を設定するPythonスクリプトです。以下はコードの内容を簡単に説明したものです：\n\nライブラリのインポート：\n\n・pandas：データ操作のため。\n\n・numpy：数値演算のため。\n\n・gc：ガベージコレクションのため。\n\n・time：時間関連の操作のため。\n\n・json：JSONデータの処理のため。\n\n・datetime：日付と時刻の操作のため。\n\n・matplotlib.pyplot：データの可視化のため。\n\n・os：オペレーティングシステム関連の機能のため。\n\n・joblib：ジョブ関連のタスクのため。\n\n・random：ランダムな数値の生成のため。\n\n・math：数学的な操作のため。\n\n・tqdm：進捗バーの表示のため。\n\n・scipyライブラリからさまざまな関数やクラス。\n\n・機械学習のためのsklearnライブラリ。\n\n・PyTorchを使用するためのtorch。\n\n・matplotlibのスタイルを設定する行：plt.style.use(\"ggplot\")。\n\n・他のライブラリから特定のクラスや関数をインポートする行：pyarrow.parquet、pyarrow、ctypes。\n\n・GPUが利用可能かどうかを確認し、利用可能であればdevice変数を'cuda'に設定します。利用可能な場合、コードは計算にGPUを使用します。利用できない場合は'cpu'に設定されます。","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport gc\nimport time\nimport json\nfrom datetime import datetime\nimport matplotlib.pyplot as plt\nimport os\nimport joblib\nimport random\nimport math\nfrom tqdm import tqdm \n\nfrom scipy.interpolate import interp1d\nfrom scipy import signal\nfrom scipy.signal import argrelmax\n\nfrom math import pi, sqrt, exp\nimport sklearn,sklearn.model_selection\nfrom sklearn.metrics import mean_squared_error\nimport torch\nfrom torch import nn,Tensor\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset, SubsetRandomSampler\nfrom sklearn.metrics import average_precision_score\nfrom timm.scheduler import CosineLRScheduler\nplt.style.use(\"ggplot\")\n\nfrom pyarrow.parquet import ParquetFile\nimport pyarrow as pa \nimport ctypes\n#torch.set_num_interop_threads(4)\n#torch.set_num_threads(4)\n\ndevice = 'cuda' if torch.cuda.is_available() else 'cpu'","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:30.321339Z","iopub.execute_input":"2023-10-23T20:56:30.32166Z","iopub.status.idle":"2023-10-23T20:56:36.679699Z","shell.execute_reply.started":"2023-10-23T20:56:30.321632Z","shell.execute_reply":"2023-10-23T20:56:36.678865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル2\n\n基本的な設定情報を含んでいます。ここでは、いくつかの重要な設定が行われています：\n\n1. WORKERS: 並列処理のためのワーカー（Worker）の数を設定しています。os.cpu_count() は、利用可能なCPUコアの数を取得し、その値を2で割った値を WORKERS に設定します。これにより、利用可能なCPUリソースを効率的に利用することができます。\n\n2. N_FOLDS: クロスバリデーションのためのフォールド（分割）の数を設定しています。通常、データセットを複数のフォールドに分割し、モデルの訓練と評価を行います。この値は5に設定されており、5つのフォールドを使用することを示しています。\n\n3. TRAIN_FOLD: 現在の訓練フォールドのインデックスを指定します。クロスバリデーションを行う場合、異なるフォールドでモデルを訓練および評価する必要があります。この値は0に設定されており、最初のフォールドでの訓練を示しています。\n\n4. if device=='cpu': の条件文: device が 'cpu' の場合にのみ、次の2つの行が実行されます。\n\n5. torch.set_num_interop_threads(WORKERS) は、CPUの間でのPyTorchの並列処理のスレッド数を設定します。\n\n6. torch.set_num_threads(WORKERS) は、PyTorchのスレッドの数を設定します。\n\nこれにより、CPUを使用している場合、PyTorchの計算が効率的に並列処理され、リソースが最大限に活用されます。GPUを使用している場合は、これらの設定は無視されます。","metadata":{}},{"cell_type":"code","source":"# Fundamental config\nWORKERS = os.cpu_count()//2\nN_FOLDS = 5\nTRAIN_FOLD = 0\n\nif device=='cpu':\n    torch.set_num_interop_threads(WORKERS)\n    torch.set_num_threads(WORKERS)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:36.681038Z","iopub.execute_input":"2023-10-23T20:56:36.682011Z","iopub.status.idle":"2023-10-23T20:56:36.685998Z","shell.execute_reply.started":"2023-10-23T20:56:36.68198Z","shell.execute_reply":"2023-10-23T20:56:36.685261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル3\n\nデータの読み込み、クリーニング、およびメモリ効率の向上を行うためのクラス data_reader を定義しています。以下はこのクラスとそのメソッドについての説明です：\n\n1. PATHS クラス:\n\n    MAIN_DIR: データファイルが格納されているディレクトリのパスを指定します。このクラス内の他の変数はこのパスをベースにデータファイルのパスを構築するために使用されます。\n\n2. CFG クラス:\n\n    DEMO_MODE: デモモードを有効にするためのフラグです。デモモードが有効な場合、データの一部を制限して読み込むことができます。\n\n3. data_reader クラス:\n\n    __init__ メソッド: クラスのコンストラクタで、デモモードを受け取り、データファイルのマッピングと使用可能なデータセット名を定義します。\n    verify メソッド: データセット名が有効かどうかを確認するためのメソッドです。\n    cleaning メソッド: データのクリーニングを行います。欠損値を削除し、クリーニング前後の行数および欠損値の割合を表示します。\n    reduce_memory_usage メソッド: データフレーム内の各列のデータ型を最適化し、メモリ使用量を削減します。\n    load_data メソッド: 指定されたデータセット名に基づいてデータを読み込みます。デモモードが有効な場合、一部のデータのみを読み込みます。\n\nこのクラスは、データの読み込みと前処理を効率的に行うために設計されており、データのクリーニングとメモリ効率の向上に役立つメソッドを提供しています。データセット名に基づいてデータを読み込むために使用できます。","metadata":{}},{"cell_type":"code","source":"class PATHS:\n    MAIN_DIR = \"/kaggle/input/child-mind-institute-detect-sleep-states/\"\n    # CSV FILES : \n    SUBMISSION = MAIN_DIR + \"sample_submission.csv\"\n    TRAIN_EVENTS = MAIN_DIR + \"train_events.csv\"\n    # PARQUET FILES:\n    TRAIN_SERIES = MAIN_DIR + \"train_series.parquet\"\n    TEST_SERIES = MAIN_DIR + \"test_series.parquet\"\nclass CFG:\n    DEMO_MODE = True\nclass data_reader:\n    def __init__(self, demo_mode):\n        super().__init__()\n        # MAPPING FOR DATA LOADING :\n        self.names_mapping = {\n            \"submission\" : {\"path\" : PATHS.SUBMISSION, \"is_parquet\" : False, \"has_timestamp\" : False}, \n            \"train_events\" : {\"path\" : PATHS.TRAIN_EVENTS, \"is_parquet\" : False, \"has_timestamp\" : True},\n            \"train_series\" : {\"path\" : PATHS.TRAIN_SERIES, \"is_parquet\" : True, \"has_timestamp\" : True},\n            \"test_series\" : {\"path\" : PATHS.TEST_SERIES, \"is_parquet\" : True, \"has_timestamp\" : True}\n        }\n        self.valid_names = [\"submission\", \"train_events\", \"train_series\", \"test_series\"]\n        self.demo_mode = demo_mode\n    \n    def verify(self, data_name):\n        \"function for data name verification\"\n        if data_name not in self.valid_names:\n            print(\"PLEASE ENTER A VALID DATASET NAME, VALID NAMES ARE : \", valid_names)\n        return\n    \n    def cleaning(self, data):\n        \"cleaning function : drop na values\"\n        before_cleaning = len(data)\n        print(\"Number of missing timestamps : \", len(data[data[\"timestamp\"].isna()]))\n        data = data.dropna(subset=[\"timestamp\"])\n        after_cleaning = len(data)\n        print(\"Percentage of removed rows : {:.1f}%\".format(100 * (before_cleaning - after_cleaning) / before_cleaning) )\n#         print(data.isna().any())\n#         data = data.bfill()\n        return data\n    \n    @staticmethod\n    def reduce_memory_usage(data):\n        \"iterate through all the columns of a dataframe and modify the data type to reduce memory usage.\"\n        start_mem = data.memory_usage().sum() / 1024**2\n        print('Memory usage of dataframe is {:.2f} MB'.format(start_mem))\n        for col in data.columns:\n            col_type = data[col].dtype    \n            if col_type != object:\n                c_min = data[col].min()\n                c_max = data[col].max()\n                if str(col_type)[:3] == 'int':\n                    if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:\n                        data[col] = data[col].astype(np.int8)\n                    elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:\n                        data[col] = data[col].astype(np.int16)\n                    elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:\n                        data[col] = data[col].astype(np.int32)\n                    elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:\n                        data[col] = data[col].astype(np.int64)  \n                else:\n                    if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:\n                        data[col] = data[col].astype(np.float16)\n                    elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:\n                        data[col] = data[col].astype(np.float32)\n                    else:\n                        data[col] = data[col].astype(np.float64)\n            else:\n                data[col] = data[col].astype('category')\n\n        end_mem = data.memory_usage().sum() / 1024**2\n        print('Memory usage after optimization is: {:.2f} MB'.format(end_mem))\n        print('Decreased by {:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))\n        return data\n    \n    def load_data(self, data_name):\n        \"function for data loading\"\n        self.verify(data_name)\n        data_props = self.names_mapping[data_name]\n        if data_props[\"is_parquet\"]:\n            if self.demo_mode:\n                pf = ParquetFile(data_props[\"path\"]) \n                demo_rows = next(pf.iter_batches(batch_size=20_000)) \n                data = pa.Table.from_batches([demo_rows]).to_pandas()\n            else:\n                data = pd.read_parquet(data_props[\"path\"])\n        else:\n            if self.demo_mode:\n                data = pd.read_csv(data_props[\"path\"], nrows=20_000)\n            else:\n                data = pd.read_csv(data_props[\"path\"])\n                \n        gc.collect()\n        if data_props[\"has_timestamp\"]:\n            print('cleaning')\n            data = self.cleaning(data)\n            gc.collect()\n        #data = self.reduce_memory_usage(data)\n        return data","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:36.687206Z","iopub.execute_input":"2023-10-23T20:56:36.687804Z","iopub.status.idle":"2023-10-23T20:56:36.711116Z","shell.execute_reply.started":"2023-10-23T20:56:36.687771Z","shell.execute_reply":"2023-10-23T20:56:36.71027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル4\n\ndata_reader クラスを使用してデータを読み込む例です。\n\n1. data_reader クラスのインスタンスを reader として作成します。コンストラクタで demo_mode を False に設定しているため、デモモードは無効になり、データセット全体が読み込まれます。\n\n2. load_data メソッドを使用して、data_name=\"test_series\" を指定してテストデータを読み込みます。このメソッドは指定されたデータセット名に基づいてデータを読み込み、クリーニングを行います。test_series データが読み込まれ、データが test_series 変数に格納されます。\n\n3. test_series.series_id.unique() を使用して、test_series データ内の一意の series_id を取得します。これらの一意の series_id は、テストデータ内の異なる系列データを識別するのに使用されます。\n\n4. gc.collect() を呼び出して、不要なメモリリソースを解放します。\n\nこのコードは、テストデータを読み込み、その中の一意の系列データの識別に役立つ series_id を取得します。データの読み込みおよびクリーニングのための data_reader クラスが効果的に使用されています。","metadata":{}},{"cell_type":"code","source":"reader = data_reader(demo_mode=False)\ntest_series = reader.load_data(data_name=\"test_series\")\nids = test_series.series_id.unique()\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:36.713797Z","iopub.execute_input":"2023-10-23T20:56:36.714266Z","iopub.status.idle":"2023-10-23T20:56:37.282334Z","shell.execute_reply.started":"2023-10-23T20:56:36.714228Z","shell.execute_reply":"2023-10-23T20:56:37.281368Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル5\n\nPyTorchを使用してシンプルな畳み込みニューラルネットワーク（Convolutional Neural Network）のモデルを定義するためのクラス SimpleConvNet と、そのモデル内で使用される補助的な関数 seq_block を示しています。以下はこのコードの詳細な説明です：\n\n・seq_block 関数:\n\n    in_features: 入力の特徴量の数。\n    out_features: 出力の特徴量の数。\n    ks: カーネルサイズ（畳み込みのカーネルサイズ）。\n    drop_rate: ドロップアウト率。\n    dilation: 畳み込みのdilation（拡張）。\n\nこの関数は、畳み込み層、バッチ正規化、LeakyReLU活性化関数、およびドロップアウトのシーケンスを作成します。畳み込み操作には dilation パラメータが適用されます。\n\n・SimpleConvNet クラス:\n\n__init__ メソッド: モデルの初期化を行います。以下の要素を定義します：\n\n    in_c: 入力チャンネル数（デフォルトは2）。\n    out_c: 出力チャンネル数（デフォルトは2）。\n    hidden: 隠れ層のユニット数（デフォルトは128）。\n    emb_dim: 埋め込み層の次元数（デフォルトは8）。\n    ks: カーネルサイズ（デフォルトは3）。\n    n_blks: 畳み込みブロックの数（デフォルトは3）。\n    dropout: ドロップアウト率（デフォルトは0.2）。\n\nこのクラスは畳み込みニューラルネットワークのアーキテクチャを定義します。アーキテクチャの概要は次のとおりです：\n\n    入力データに対する時刻埋め込み（hour embedding）を行います。\n    その埋め込みを線形変換し、LeakyReLU活性化関数を適用します。\n    入力データと埋め込みを連結します。\n    追加の線形変換および畳み込みブロックを適用します。\n    出力層を適用して、モデルの出力を生成します。\n\nこのモデルは、畳み込み操作、埋め込み、線形変換、バッチ正規化、LeakyReLU活性化関数、ドロップアウトを使用してデータを処理します。\n\nforward メソッド:\n\n    モデルの順伝播を定義します。入力 x と時刻 h を受け取り、前述のアーキテクチャに従ってデータを処理して出力を生成します。\n\nこのモデルは、入力データに対する畳み込みを使用して時系列データを処理するために設計されており、畳み込みブロックを持つニューラルネットワークです。","metadata":{}},{"cell_type":"code","source":"def seq_block(in_features, out_features, ks=3, drop_rate=0.2, dilation=1):\n    padding = ((ks-1)*dilation)//2\n    return nn.Sequential(\n        nn.Conv1d(in_features, out_features, ks, padding=padding, dilation=dilation),\n        nn.BatchNorm1d(out_features),\n        nn.LeakyReLU(0.2),\n        nn.Dropout(drop_rate)\n    )\n\nclass SimpleConvNet(nn.Module):\n    def __init__(self, in_c=2, out_c=2, hidden=128, emb_dim=8, ks=3, n_blks=3, dropout=0.2):\n        super(SimpleConvNet, self).__init__()\n        \n        self.hr_emb = nn.Embedding(24, emb_dim)\n        self.fc1_hr = nn.Linear(emb_dim, emb_dim)\n        self.fc2_hr = nn.Linear(emb_dim, emb_dim)\n        \n        self.fc_in = nn.Linear(in_c+emb_dim, hidden)\n        self.blks = nn.Sequential(\n            *[seq_block(hidden, hidden, ks, drop_rate=dropout, dilation=2**i) for i in range(n_blks)]\n            )\n        self.fc_out = nn.Linear(hidden, out_c)\n        \n        self.lrelu = nn.LeakyReLU(0.2)\n        \n    def forward(self, x, h):        \n        e = self.hr_emb(h)\n        e = self.fc1_hr(e)\n        e = self.lrelu(e)\n        e = self.fc2_hr(e)\n\n        x = torch.cat([x, e.squeeze(2)], dim=-1)\n        x = self.fc_in(x)\n        \n        x = x.permute(0,2,1)\n        \n        for b in self.blks:\n            x = b(x)\n\n        x = x.permute(0,2,1)\n        \n        x = self.fc_out(x)\n        return x","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:37.28361Z","iopub.execute_input":"2023-10-23T20:56:37.283856Z","iopub.status.idle":"2023-10-23T20:56:37.294748Z","shell.execute_reply.started":"2023-10-23T20:56:37.283834Z","shell.execute_reply":"2023-10-23T20:56:37.293814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル6\nSleepTestDatasetというデータセットクラスを定義しています。このデータセットは、睡眠テストデータに関連する情報を準備および変換するためのメソッドを含んでいます。\n\n1. SIGMA と SAMPLE_FREQ は、クラスのメンバー変数として定義されています。これらは定数で、特定の値が設定されています。\n\n2. SleepTestDataset クラスは、コンストラクタ __init__ を持ちます。このコンストラクタは、テストデータとそれに関連するIDを受け取ります。また、テストデータの前処理を行います。特に、enmo_mean および enmo_std といった統計情報を読み込み、テストデータを変換するためのメソッドを呼び出します。\n\n3. conv_dfs メソッドは、テストデータを変換して新しいデータフレームのリストを返す役割を果たします。これは、各テストシリーズに関連するデータを取得し、必要なカラムを抽出して新しいデータフレームに格納します。\n\n4. norm_feat_eng メソッドは、特徴量の正規化とエンジニアリングを行います。角度 (anglez) と enmo という2つの特徴量を正規化し、移動平均やその他の特徴量を計算します。このメソッドは、特徴量の正規化とエンジニアリングを行うためのもので、初回実行時には特徴量リスト (feat_list) に新しい特徴量の名前を追加します。\n\n5. gauss メソッドは、ガウス分布の関数を定義しています。\n\n6. __len__ メソッドは、データセットの長さを返します。\n\n7. __getitem__ メソッドは、指定されたインデックスのデータを取得します。テストデータの特徴量と時間情報を抽出し、適切なデータ型に変換して返します。\n\n最後に、SleepTestDataset クラスのインスタンスが作成されています。このインスタンスはテストデータとその他の情報を使用して初期化されます。このデータセットを使用することで、テストデータの前処理や特徴量エンジニアリングを行う準備が整い、モデルのトレーニングや評価に使用できるようになります。","metadata":{}},{"cell_type":"code","source":"SIGMA = 720 #average length of day is 24*60*12 = 17280 for comparison\nSAMPLE_FREQ = 12 # 1 obs per minute\nclass SleepTestDataset(Dataset):\n    def __init__(\n        self,\n        test_series,\n        test_ids\n    ):\n        self.enmo_mean = np.load('/kaggle/input/detect-sleep-states-dataprepare/enmo_mean.npy')\n        self.enmo_std = np.load('/kaggle/input/detect-sleep-states-dataprepare/enmo_std.npy')\n\n        self.Xs = self.conv_dfs(test_series, test_ids)\n        \n        self.feat_list = np.load('/kaggle/input/detect-sleep-states-train/feature_list.npy')\n        self.label_list = ['onset', 'wakeup']\n        \n        self.hour_feat= ['hour']\n        \n            \n    def conv_dfs(self, series, ids):\n        res = []\n        for j, viz_id in tqdm(enumerate(ids), total=len(ids)):\n            viz_series = series.loc[(series.series_id==viz_id)].copy().reset_index()\n            viz_series['dt'] = pd.to_datetime(viz_series.timestamp,format = '%Y-%m-%dT%H:%M:%S%z').astype(\"datetime64[ns, UTC-04:00]\")\n            viz_series['hour'] = viz_series['dt'].dt.hour\n            new_df = viz_series[['step', 'anglez', 'enmo', 'hour']]\n            res.append(new_df)\n\n        return res\n\n    def norm_feat_eng(self, X, init=False):\n        X['anglez'] = X['anglez'] / 90.0\n        X['enmo'] = (X['enmo']-self.enmo_mean)/ (self.enmo_std+1e-8)\n        \n        for w in [1, 2, 4, 8, 16]:    \n            X['anglez_shift_pos_' + str(w)] = X['anglez'].shift(w).fillna(0)\n            X['anglez_shift_neg_' + str(w)] = X['anglez'].shift(-w).fillna(0)\n            \n            X['enmo_shift_pos_' + str(w)] = X['enmo'].shift(w).fillna(0)\n            X['enmo_shift_neg_' + str(w)] = X['enmo'].shift(-w).fillna(0)\n            \n            if init:\n                self.feat_list.append('anglez_shift_pos_' + str(w))\n                self.feat_list.append('anglez_shift_neg_' + str(w))\n                \n                self.feat_list.append('enmo_shift_pos_' + str(w))\n                self.feat_list.append('enmo_shift_neg_' + str(w))\n            \n        for r in [17, 33, 65]:\n            tmp_anglez = X['anglez'].rolling(r, center=True)\n            X[f'anglez_mean_{r}'] = tmp_anglez.mean()\n            X[f'anglez_std_{r}'] = tmp_anglez.std()            \n            \n            tmp_enmo = X['enmo'].rolling(r, center=True)\n            X[f'enmo_mean_{r}'] = tmp_enmo.mean()\n            X[f'enmo_std_{r}'] = tmp_enmo.std()\n            \n            if init:\n                self.feat_list.append(f'anglez_mean_{r}')\n                self.feat_list.append(f'anglez_std_{r}')\n\n                self.feat_list.append(f'enmo_mean_{r}')\n                self.feat_list.append(f'enmo_std_{r}')\n                \n        X = X.fillna(0)\n        \n        return X.astype(np.float32)\n\n    def gauss(self,n=SIGMA,sigma=SIGMA*0.15):\n        # guassian distribution function\n        r = range(-int(n/2),int(n/2)+1)\n        return [1 / (sigma * sqrt(2*pi)) * exp(-float(x)**2/(2*sigma**2)) for x in r]\n    \n    def __len__(self):\n        return len(self.Xs)\n\n    def __getitem__(self, index):\n        X = self.Xs[index]\n        X = self.norm_feat_eng(X, init=False)\n        x = X[self.feat_list].values.astype(np.float32)     \n        t = X[self.hour_feat].values.astype(np.int32)\n        return x, t\n\ntest_ds = SleepTestDataset(test_series, ids)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:37.296153Z","iopub.execute_input":"2023-10-23T20:56:37.296432Z","iopub.status.idle":"2023-10-23T20:56:37.361592Z","shell.execute_reply.started":"2023-10-23T20:56:37.296388Z","shell.execute_reply":"2023-10-23T20:56:37.360785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル7\nこのコードは、データセット test_ds の最初のデータポイントの特徴量（[0]）を取得し、その特徴量の形状を取得します。形状は、特徴量の次元数やサイズを表します。","metadata":{}},{"cell_type":"code","source":"test_ds[0][0].shape","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:37.362704Z","iopub.execute_input":"2023-10-23T20:56:37.363064Z","iopub.status.idle":"2023-10-23T20:56:37.400301Z","shell.execute_reply.started":"2023-10-23T20:56:37.36303Z","shell.execute_reply":"2023-10-23T20:56:37.399491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル8\n提供されたコードは、test_ds データセットの Xs メンバー（データポイントのリスト）の長さが3の場合、各データポイントを表示するループを実行します。ここで、display 関数はデータを表示するための方法の一つです","metadata":{}},{"cell_type":"code","source":"if len(test_ds.Xs)==3:\n    for x in test_ds.Xs:\n        display(x)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:37.401377Z","iopub.execute_input":"2023-10-23T20:56:37.401638Z","iopub.status.idle":"2023-10-23T20:56:37.454443Z","shell.execute_reply.started":"2023-10-23T20:56:37.401615Z","shell.execute_reply":"2023-10-23T20:56:37.453616Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル9\n提供されたコードは、3つの異なるデータポイントに対して 'enmo' 特徴量を折れ線グラフでプロットし、それぞれのプロットに対して適切なタイトルを設定するものです。ここで、ids リストはタイトル用のラベルを含んでいる必要があります。\n\n以下は、コードの主なポイントです：\n\n1. if len(test_ds.Xs) == 3: test_ds データセットのデータポイント数が3であるかを確認しています。\n\n2. ループ for i, x in enumerate(test_ds.Xs): Xs リスト内の各データポイントに対して反復処理を行います。enumerate 関数を使用して、データポイントのインデックス i とデータ x を取得しています。\n\n3. plt.plot(x['enmo'], lw=0.5): x データポイント内の 'enmo' 特徴量を抽出し、それを折れ線グラフとしてプロットします。lw=0.5 は線の太さを設定しています。\n\n4. plt.title(ids[i]): 各プロットのタイトルに ids リストから取得したラベルを設定します。ただし、ids リストがどのように定義されているかに注意が必要です。タイトル用のラベルが正しく指定されていることを確認してください。\n\n5. plt.show(): 各プロットを表示します。\n\nこのコードを実行すると、各データポイントに対して 'enmo' 特徴量の折れ線グラフがプロットされ、各プロットのタイトルには ids リストから取得したラベルが表示されるでしょう。データの可視化が行われます。","metadata":{}},{"cell_type":"code","source":"if len(test_ds.Xs)==3:\n    for i, x in enumerate(test_ds.Xs):\n        plt.plot(x['enmo'], lw=0.5)\n        plt.title(ids[i])\n        plt.show()","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:37.455671Z","iopub.execute_input":"2023-10-23T20:56:37.456014Z","iopub.status.idle":"2023-10-23T20:56:38.181043Z","shell.execute_reply.started":"2023-10-23T20:56:37.455988Z","shell.execute_reply":"2023-10-23T20:56:38.180162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル10\n変数 test_series と reader を削除し、ガベージコレクション（Garbage Collection）を実行するものです。これにより、メモリの解放や不要なオブジェクトのクリーンアップが行われます。主にメモリリソースを効率的に管理するために使用されます。\n\n具体的な動作は以下の通りです：\n\n1. del test_series, reader：この行は変数 test_series と reader を削除します。変数を削除することで、それらの変数が占有していたメモリリソースが解放されます。\n\n2. gc.collect()：この行はPythonのガベージコレクションを手動でトリガーします。ガベージコレクションは、不要なオブジェクトをメモリから削除し、メモリを最適化するプロセスです。手動でガベージコレクションを実行することで、メモリリソースをより効果的に解放できる場合があります。\n\nこのコードを実行することで、不要なメモリリソースが解放され、システムのメモリ使用量が削減されることが期待されます。特に大規模なデータ処理の場面では、メモリ管理は重要な要素となります。","metadata":{}},{"cell_type":"code","source":"del test_series, reader\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:38.184377Z","iopub.execute_input":"2023-10-23T20:56:38.18466Z","iopub.status.idle":"2023-10-23T20:56:38.352431Z","shell.execute_reply.started":"2023-10-23T20:56:38.184636Z","shell.execute_reply":"2023-10-23T20:56:38.351497Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル11\nモデルの構成に関する設定を示しています。これらの設定は、モデルのアーキテクチャやハイパーパラメータを指定します。\n\n具体的な設定に関する説明は次の通りです:\n\n1. HIDDEN：モデルの隠れ層（hidden layer）のユニット（ニューロン）の数を示します。この値は、モデルの複雑性や表現能力に影響を与えます。大きな値を指定すると、モデルがより複雑になりますが、過学習のリスクも高まる場合があります。\n\n2. EMB_DIM：埋め込み次元（embedding dimension）を示します。埋め込みはカテゴリカルな特徴量を連続的なベクトルに変換するために使用されるテクニックです。この値は埋め込みベクトルの次元数を指定します。\n\n3. KS：畳み込み層（Convolutional Layer）のカーネルサイズ（Kernel Size）を示します。畳み込み層は画像処理やシーケンスデータの特徴抽出に使用され、カーネルサイズは畳み込み操作の範囲を指定します。\n\n4. N_BLKS：モデル内のブロック（Block）の数を示します。ブロックはネットワーク内の層のグループ化で、モデルのアーキテクチャを構成する要素です。\n\n5. DROPOUT：ドロップアウト率（Dropout Rate）を示します。ドロップアウトは過学習を防ぐ正則化手法の一つで、訓練中にランダムに一部のユニットを無効にすることで、モデルの汎化能力を向上させます。この値は、無効にするユニットの割合を指定します。\n\nこれらの設定は、モデルの設計とトレーニングに重要な影響を与えます。具体的なモデルアーキテクチャについては、これらの設定を使用してモデルを構築およびトレーニングするコードが必要です。モデルのアーキテクチャやハイパーパラメータは、特定のタスクに合わせて調整されることが一般的です。","metadata":{}},{"cell_type":"code","source":"# Model config\nHIDDEN = 256 \nEMB_DIM = 16\nKS = 31 \nN_BLKS = 5 \nDROPOUT = 0.2","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:38.353598Z","iopub.execute_input":"2023-10-23T20:56:38.353904Z","iopub.status.idle":"2023-10-23T20:56:38.362693Z","shell.execute_reply.started":"2023-10-23T20:56:38.353879Z","shell.execute_reply":"2023-10-23T20:56:38.361888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル12\nPyTorchのデータローダー（DataLoader）を構築する部分です。データローダーはデータセットからミニバッチを効率的に取得し、モデルのトレーニングや評価に使用します。\n\n以下は、このコードの主要なポイントです：\n\n1. test_dl はデータローダーの名前です。\n\n2. DataLoader クラスは、PyTorchのデータセットを使用してデータローダーを作成します。データセットとデータローダーは、モデルのトレーニングや評価に必要なデータを提供します。\n\n3. test_ds はデータセットのインスタンスで、test_dl がこのデータセットからデータを取得します。\n\n4. batch_size=1 は、ミニバッチのサイズを指定します。ここではミニバッチのサイズが1に設定されており、1つのデータポイントを1つのミニバッチとして処理します。\n\n5. pin_memory=True は、データをGPUメモリにピン留めするオプションです。これにより、データの転送が高速化される場合があります。ただし、GPUメモリの容量に注意が必要です。\n\n6. num_workers=WORKERS は、データローダーを並列処理するためのワーカー（Worker）の数を指定します。WORKERS はどこかで定義されている変数で、ワーカー数を設定します。多くの場合、データローダーの並列処理を使用してデータの読み込みを高速化できます。\n\n7. shuffle=False は、データをシャッフルしないことを指定します。データをシャッフルしない場合、データはデータセット内の順序通りに提供されます。これはテストデータをシャッフルする必要がない場合に使用されます。\n\n8. drop_last=False は、最後のミニバッチがバッチサイズ未満の場合にデータを削除しないことを指定します。これにより、最後のデータを無駄にしないようになります。\n\nこのデータローダーを使用することで、テストデータをモデルに供給し、モデルの評価を行うことができます。データローダーは、ミニバッチ単位でデータを提供し、モデルの効率的な処理を支援します。","metadata":{}},{"cell_type":"code","source":"test_dl = DataLoader(\n    test_ds,\n    batch_size=1,\n    pin_memory=True,\n    num_workers=WORKERS,\n    shuffle=False,\n    drop_last=False\n)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:38.36373Z","iopub.execute_input":"2023-10-23T20:56:38.364023Z","iopub.status.idle":"2023-10-23T20:56:38.372825Z","shell.execute_reply.started":"2023-10-23T20:56:38.363998Z","shell.execute_reply":"2023-10-23T20:56:38.372061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル13\nPyTorchモデルのインスタンスを作成し、モデルのパラメータを学習済みモデルの状態にロードしています。\n\n1. SimpleConvNet クラスのインスタンス model を作成しています。このモデルは、カスタムの畳み込みニューラルネットワークで、入力の特徴量数 (in_c)、出力クラス数 (out_c)、隠れ層のユニット数 (hidden)、埋め込み次元 (emb_dim)、カーネルサイズ (ks)、ブロック数 (n_blks)、ドロップアウト率 (dropout) などのハイパーパラメータを指定しています。\n\n2. model.load_state_dict(...) は、学習済みモデルの状態をロードしています。ファイルパス f'/kaggle/input/detect-sleep-states-train/model_best_fold-{TRAIN_FOLD}.pth' から学習済みモデルのパラメータを読み込み、model に適用しています。map_location=device は、モデルのパラメータを指定したデバイス (device) 上にロードすることを示します。\n\n3. model.eval().half() は、モデルを評価モードに切り替えています。eval() メソッドはモデルを評価モードに設定し、推論時の動作に適した状態にします。また、half() メソッドは、モデルのデータタイプを半精度浮動小数点数 (float16) に変換しています。これは、モデルのメモリ使用量を削減し、推論速度を向上させるためのものです。\n\nこのコードを実行することで、学習済みモデルが読み込まれ、評価モードで準備が整ったモデル model が得られます。このモデルを使用してテストデータに対する推論を行うことができます。","metadata":{}},{"cell_type":"code","source":"model = SimpleConvNet(in_c=len(test_ds.feat_list), out_c=2, hidden=HIDDEN, emb_dim=EMB_DIM, ks=KS, n_blks=N_BLKS, dropout=DROPOUT).to(device)\nmodel.load_state_dict(torch.load(f'/kaggle/input/detect-sleep-states-train/model_best_fold-{TRAIN_FOLD}.pth',map_location=device))\nmodel.eval().half()","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:38.373901Z","iopub.execute_input":"2023-10-23T20:56:38.374287Z","iopub.status.idle":"2023-10-23T20:56:41.897236Z","shell.execute_reply.started":"2023-10-23T20:56:38.374255Z","shell.execute_reply":"2023-10-23T20:56:41.896342Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル14\nPyTorchの自動混合精度（Automatic Mixed Precision, AMP）を有効化するための設定を行っています。AMPは、深層学習モデルのトレーニングにおいて、浮動小数点数演算の精度を低減してメモリ使用量を削減し、計算速度を向上させるためのテクニックです。\n\n1. autocast は torch.cuda.amp.autocast のインスタンスを作成しています。enabled=True は自動混合精度を有効化することを示し、dtype=torch.half は計算に半精度浮動小数点数（float16）を使用することを指定しています。これにより、モデル内の演算が半精度で実行され、メモリ使用量が削減されます。半精度は通常、精度を保持する必要がない場面で使用されます。\n\n2. scaler は torch.cuda.amp.GradScaler のインスタンスを作成しています。enabled=True は勾配スケーリングを有効化することを示し、init_scale=4096 は初期スケールの値を設定しています。勾配スケーリングは、半精度計算において勾配の値を調整するテクニックで、数値不安定性を軽減するのに役立ちます。\n\nこの設定を使用することで、モデルのトレーニング時にAMPを適用し、メモリ使用量の削減と計算速度の向上を実現できます。特にGPUリソースが制約されている場合や高効率なトレーニングが求められる場合に役立ちます。","metadata":{}},{"cell_type":"code","source":"autocast = torch.cuda.amp.autocast(enabled=True, dtype=torch.half)\nscaler = torch.cuda.amp.GradScaler(enabled=True, init_scale=4096)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:41.898265Z","iopub.execute_input":"2023-10-23T20:56:41.898512Z","iopub.status.idle":"2023-10-23T20:56:41.903425Z","shell.execute_reply.started":"2023-10-23T20:56:41.898489Z","shell.execute_reply":"2023-10-23T20:56:41.902376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル15\nローパスフィルタリング（Low-Pass Filtering）を行う関数 lpf を定義しています。ローパスフィルタは、信号処理の一部として、高周波数成分を除去して信号のスムージングやノイズ低減を行うのに使用されます。この関数は、SciPy ライブラリの signal モジュールを使用しています。\n\n以下は、この関数の主な要点です：\n\n1. lpf 関数は、入力として波形データ (wave) といくつかのパラメータを受け取ります。波形データは時間領域での信号で、フィルタリングを行うためのデータです。\n\n2. fs パラメータはサンプリング周波数（Sampling Frequency）を表します。デフォルト値は1日あたりのサンプリング数を示す 12*60*24 に設定されています。\n\n3. fe パラメータはカットオフ周波数（Cutoff Frequency）を表します。カットオフ周波数以下の成分は通過し、それ以上の高周波成分は除去されます。デフォルト値は60です。\n\n4. n パラメータはフィルタリングの反復回数を指定します。フィルタリング処理を複数回繰り返すことで、信号をさらに平滑化できます。デフォルト値は3です。\n\n5. 関数内で、カットオフ周波数 fe に基づいてバターワースフィルタの係数を計算し、signal.filtfilt 関数を使用して入力波形 wave に対してローパスフィルタを適用しています。これを反復回数 n 回繰り返します。\n\n6. フィルタリングされた波形データは、入力の波形と同じ変数 wave に格納され、最終的に返されます。\n\nこの関数を使用することで、信号のスムージングやノイズ低減を行うことができます。設定したカットオフ周波数と反復回数によって、フィルタリングの効果が調整されます。","metadata":{}},{"cell_type":"code","source":"def lpf(wave, fs=12*60*24, fe=60, n=3):\n    nyq = fs / 2.0\n    b, a = signal.butter(1, fe/nyq, btype='low')\n    for i in range(0, n):\n        wave = signal.filtfilt(b, a, wave)\n    return wave","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:41.904603Z","iopub.execute_input":"2023-10-23T20:56:41.904861Z","iopub.status.idle":"2023-10-23T20:56:41.915629Z","shell.execute_reply.started":"2023-10-23T20:56:41.904839Z","shell.execute_reply":"2023-10-23T20:56:41.914745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル16\n空のデータフレーム（DataFrame）を作成しています。","metadata":{}},{"cell_type":"code","source":"submission = pd.DataFrame()","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:41.91663Z","iopub.execute_input":"2023-10-23T20:56:41.916882Z","iopub.status.idle":"2023-10-23T20:56:41.925811Z","shell.execute_reply.started":"2023-10-23T20:56:41.91686Z","shell.execute_reply":"2023-10-23T20:56:41.924991Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル17\nテストデータに対する推論処理とその結果の処理を行っています。以下は、このコードの主要なポイントです：\n\n1. with torch.no_grad(): は、テンソルの自動微分を無効化し、テストデータに対する推論の計算を高速化します。\n\n2. with tqdm(test_dl, leave=True) as pbar: は、テストデータローダー (test_dl) を使用してテストデータを反復処理します。tqdm は進捗バーを表示し、処理の進行状況をモニタリングします。\n\n3. テストデータバッチ X_batch と hr_batch が取得され、それらはデバイス（GPUまたはCPU）に転送されます。\n\n4. with autocast: ブロック内では、半精度浮動小数点数 (float16) を使用してモデルによる予測を行います。これにより、計算速度が向上し、メモリ使用量が削減されます。\n\n5. モデルを使用して予測 y_pred を取得し、それをCPUに移動して Numpy 配列に変換します。また、RMSE（Root Mean Squared Error）を計算しています。\n\n6. lpf 関数を使用して、y_pred に対して低域通過フィルタを適用しています。このフィルタ処理により、信号が平滑化され、ノイズが低減されます。ただし、条件 if len(test_ds.Xs) != 3: が満たされている場合にのみ適用されます。\n\n7. RMSE の前後で比率 decay_ratio を計算し、それを使用して y_pred の値を調整します。\n\n8. argrelmax 関数を使用して、y_pred 中の極大値（ピーク）の位置を特定します。これにより、睡眠の「onset」（開始）と「wakeup」（目覚め）のイベントが検出されます。\n\n9. series_id はテストデータセット内の各データポイントの識別子です。それぞれの onset と wakeup イベントに対して、データフレームに情報を追加し、それを submission データフレームに連結しています。\n\nこのコードは、テストデータに対してモデルの予測を行い、その結果を整理して submission データフレームに格納しています。最終的に、submission データフレームには予測された睡眠イベントの情報が含まれることになります。","metadata":{}},{"cell_type":"code","source":"with torch.no_grad():\n    with tqdm(test_dl, leave=True) as pbar:\n        for i, (X_batch, hr_batch) in enumerate(pbar):\n            X_batch = X_batch.to(device)\n            hr_batch = hr_batch.to(device)\n            with autocast:\n                y_pred = model(X_batch, hr_batch)\n\n            y_pred = y_pred[0].sigmoid().cpu().numpy().astype(np.float32)\n            \n            before_RMSE = np.sqrt(mean_squared_error(y_pred, np.zeros_like(y_pred)))\n            \n            if len(test_ds.Xs)!=3:\n                y_pred[:,0] = lpf(y_pred[:,0])\n                y_pred[:,1] = lpf(y_pred[:,1])\n            \n            after_RMSE = np.sqrt(mean_squared_error(y_pred, np.zeros_like(y_pred)))\n\n            decay_ratio = before_RMSE/after_RMSE\n            y_pred *= decay_ratio\n            \n            onset_candi = argrelmax(y_pred[:, 0], order=12*60*6) # 12*60*6 = 6hours\n            wakeup_candi = argrelmax(y_pred[:, 1], order=12*60*6) # 12*60*6 = 6hours\n            \n\n            series_id = ids[i]\n            try:                \n                onset_candi = onset_candi[0]\n                onset = pd.DataFrame({'series_id': [series_id]*len(onset_candi),\n                                     'step': onset_candi,\n                                     'score': y_pred[onset_candi, 0].reshape(-1),\n                                     'event': ['onset']*len(onset_candi)})\n            except:\n                 onset = pd.DataFrame()\n            \n            try:\n                wakeup_candi = wakeup_candi[0]\n                wakeup = pd.DataFrame({'series_id': [series_id]*len(wakeup_candi),\n                                     'step': wakeup_candi,\n                                     'score': y_pred[wakeup_candi, 1].reshape(-1),\n                                     'event': ['wakeup']*len(wakeup_candi)})\n            except:\n                wakeup = pd.DataFrame()\n            \n            submission = pd.concat([submission, onset, wakeup], axis=0)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:41.926933Z","iopub.execute_input":"2023-10-23T20:56:41.92723Z","iopub.status.idle":"2023-10-23T20:56:46.996131Z","shell.execute_reply.started":"2023-10-23T20:56:41.9272Z","shell.execute_reply":"2023-10-23T20:56:46.99502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル18\n\nsubmission データフレームを処理して、最終的な予測結果を CSV ファイルに書き出す部分です。以下は、このコードの主要なポイントです：\n\n1. submission データフレームは、事前に生成された予測結果が含まれており、各行は一意の row_id を持っています。\n\n2. submission データフレームは、series_id と step でソートされ、新しいインデックスが設定されます。reset_index(drop=True) は、新しいインデックスを設定した後に以前のインデックスを削除するオプションです。\n\n3. row_id 列を新たに追加し、新しいインデックスを格納します。これにより、各行に一意の識別子が与えられます。\n\n4. score 列の欠損値を平均値で埋める処理を行います。欠損値がある場合、その値は submission['score'].mean() によって平均値で置き換えられます。\n\n5. データフレームの列の順序を調整し、'row_id', 'series_id', 'step', 'event', 'score' の順序に変更します。\n\n6. 最終的に、データフレームを CSV ファイルとしてエクスポートし、submission.csv というファイル名で保存します。index=False オプションは、行のインデックスを CSV ファイルに含めないように設定します。\n\nこのコードを実行することで、予測結果が整理されて CSV ファイルに保存され、提出の準備が整います。CSV ファイルは一般的に、コンペティションプラットフォームに提出するためのフォーマットとして使用されます。","metadata":{}},{"cell_type":"code","source":"submission = submission.sort_values(['series_id','step']).reset_index(drop=True)\nsubmission['row_id'] = submission.index.astype(int)\nsubmission['score'] = submission['score'].fillna(submission['score'].mean())\nsubmission = submission[['row_id','series_id','step','event','score']]\nsubmission.to_csv('submission.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:46.997825Z","iopub.execute_input":"2023-10-23T20:56:46.998255Z","iopub.status.idle":"2023-10-23T20:56:47.016701Z","shell.execute_reply.started":"2023-10-23T20:56:46.99822Z","shell.execute_reply":"2023-10-23T20:56:47.015679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### セル19\nsubmissionの確認をしています。","metadata":{}},{"cell_type":"code","source":"submission","metadata":{"execution":{"iopub.status.busy":"2023-10-23T20:56:47.018141Z","iopub.execute_input":"2023-10-23T20:56:47.018535Z","iopub.status.idle":"2023-10-23T20:56:47.032416Z","shell.execute_reply.started":"2023-10-23T20:56:47.018499Z","shell.execute_reply":"2023-10-23T20:56:47.031486Z"},"trusted":true},"execution_count":null,"outputs":[]}]}