{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":102335,"databundleVersionId":12518947,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:19.889941Z","iopub.execute_input":"2025-07-10T13:37:19.890956Z","iopub.status.idle":"2025-07-10T13:37:19.897825Z","shell.execute_reply.started":"2025-07-10T13:37:19.890929Z","shell.execute_reply":"2025-07-10T13:37:19.897274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import random\nimport tensorflow as tf\n\ndef set_seed(seed=42):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    random.seed(seed)\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n\nset_seed(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:19.899107Z","iopub.execute_input":"2025-07-10T13:37:19.899367Z","iopub.status.idle":"2025-07-10T13:37:19.903103Z","shell.execute_reply.started":"2025-07-10T13:37:19.899341Z","shell.execute_reply":"2025-07-10T13:37:19.902577Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Simple LSTM","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM, Dense\n\n# -----------------------------\n# Data Preparation / データ準備\n# -----------------------------\n\n# Input data: 3 samples, each with 5 time steps and 1 feature per time step\n# 入力データ (サンプル数: 3, 時系列ステップ数: 5, 特徴量次元: 1)\nX = np.array([\n    [[0], [1], [2], [3], [4]],\n    [[1], [2], [3], [4], [5]],\n    [[2], [3], [4], [5], [6]]\n])  # shape: (3 samples, 5 time steps, 1 feature) / (3サンプル, 5ステップ, 1特徴)\n\n# Output data: the expected next value after each input sequence\n# 出力データ（各入力に対して予測される次の値）\ny = np.array([\n    [5],\n    [6],\n    [7]\n])  # shape: (3 samples, 1 output) / (3サンプル, 1出力)\n\n# -----------------------------\n# Model Construction / モデル構築\n# -----------------------------\n\n# Create a Sequential model\n# シーケンシャルモデルを作成\nmodel = Sequential()\n\n# Add LSTM layer with 10 units; input shape is (5 time steps, 1 feature)\n# LSTMレイヤーを追加（ユニット数: 10、入力形状: 5ステップ、1特徴）\nmodel.add(LSTM(10, input_shape=(5, 1)))\n\n# Add output Dense layer with 1 unit to predict the next value\n# 出力層としてDenseレイヤー（1ユニット）を追加\nmodel.add(Dense(1))\n\n# Compile the model using Mean Squared Error loss and Adam optimizer\n# モデルをコンパイル（損失関数: 平均二乗誤差 / 最適化: Adam）\nmodel.compile(optimizer='adam', loss='mse')\n\n# Display the model summary\n# モデルの概要を表示\nmodel.summary()\n\n# -----------------------------\n# Model Training / モデルの学習\n# -----------------------------\n\n# Train the model for 200 epochs (verbose=0 to suppress output)\n# モデルを200エポックで学習（verbose=0でログを非表示）\nmodel.fit(X, y, epochs=50, verbose=0)\n\n# -----------------------------\n# Prediction / 予測\n# -----------------------------\n\n# Test input sequence: [3, 4, 5, 6, 7]\n# テスト用の入力データ（[3,4,5,6,7]の系列）\ntest_input = np.array([[[3], [4], [5], [6], [7]]])\n\n# Make prediction using the trained model\n# モデルによる予測を実行\npred = model.predict(test_input)\n\n# Print the predicted next value\n# 予測結果を表示\nprint(\"Prediction result / 予測結果:\", pred)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:19.903705Z","iopub.execute_input":"2025-07-10T13:37:19.903923Z","iopub.status.idle":"2025-07-10T13:37:23.557776Z","shell.execute_reply.started":"2025-07-10T13:37:19.903906Z","shell.execute_reply":"2025-07-10T13:37:23.557159Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Bidirectional","metadata":{}},{"cell_type":"markdown","source":"What is a Bidirectional LSTM? (This is written by ChatGPT!)\n- A standard LSTM processes sequences in one direction only, usually from past to present.\n- A Bidirectional LSTM processes the same sequence in both directions: from past to present and from present to past.\n- This means the model has access to both preceding and following context when making predictions.\n- It helps the model better understand the entire structure of the sequence, not just what comes before a certain point.\n- Bidirectional LSTMs are particularly useful in tasks like:\n    - Natural language processing (NLP) – understanding the meaning of a word based on the full sentence.\n    - Speech recognition – where future sounds help interpret current ones.\n    - Time series forecasting – especially when the entire sequence is available during training.","metadata":{}},{"cell_type":"markdown","source":"Bidirectional LSTMとは？ (ChatGPTに書いてもらいました!)\n- 通常のLSTMは、系列データを一方向（通常は過去から現在）に処理します。\n- Bidirectional LSTM（双方向LSTM）は、同じ系列を2方向（過去→現在 と 現在→過去）で処理します。\n- これにより、モデルはある時点の予測に対して、前後の文脈の両方を活用できるようになります。\n- 単に「前の情報」だけでなく、時系列全体の構造や意味をより深く理解できるようになります。\n- Bidirectional LSTMは、特に以下のようなタスクで効果的です：\n    - 自然言語処理（NLP）：文全体から単語の意味を理解する場合など\n    - 音声認識：前後の音から意味を補完するような場面\n    - 時系列予測：学習時に全体の系列が利用可能なケース","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM, Dense, Bidirectional\n\n# -----------------------------\n# Data Preparation / データ準備\n# -----------------------------\n\n# Input data: 3 samples, each with 5 time steps and 1 feature per step\n# 入力データ：3つのサンプル、それぞれ5ステップ・1特徴\nX = np.array([\n    [[0], [1], [2], [3], [4]],\n    [[1], [2], [3], [4], [5]],\n    [[2], [3], [4], [5], [6]]\n])  # shape: (3 samples, 5 time steps, 1 feature) / (3サンプル, 5ステップ, 1特徴)\n\n# Output data: the next value in the sequence for each input\n# 出力データ：各入力に対して次の値\ny = np.array([\n    [5],\n    [6],\n    [7]\n])  # shape: (3 samples, 1 output) / (3サンプル, 1出力)\n\n# -----------------------------\n# Model Construction / モデル構築\n# -----------------------------\n\n# Create a Sequential model\n# シーケンシャルモデルを作成\nmodel = Sequential()\n\n# Add Bidirectional LSTM layer with 10 units\n# Bidirectional（双方向）LSTMレイヤーを追加（ユニット数10）\n# This allows the model to learn from both past and future context\n# 双方向に時系列を処理することで、過去と未来の両方の文脈を学習できる\nmodel.add(Bidirectional(LSTM(10), input_shape=(5, 1)))  # This is difference from normal LSTM\n\n# Add Dense layer to output the next value\n# 出力層としてDenseレイヤー（1ユニット）を追加\nmodel.add(Dense(1))\n\n# Compile the model using Mean Squared Error loss and Adam optimizer\n# モデルをコンパイル（損失関数: 平均二乗誤差、最適化: Adam）\nmodel.compile(optimizer='adam', loss='mse')\n\n# Display the model summary\n# モデルの概要を表示\nmodel.summary()\n\n# -----------------------------\n# Model Training / モデルの学習\n# -----------------------------\n\n# Train the model for 200 epochs (silent mode)\n# モデルを200エポック学習（出力なし）\nmodel.fit(X, y, epochs=50, verbose=0)\n\n# -----------------------------\n# Prediction / 予測\n# -----------------------------\n\n# Test input sequence: [3, 4, 5, 6, 7]\n# テスト用入力データ：[3, 4, 5, 6, 7] の系列\ntest_input = np.array([[[3], [4], [5], [6], [7]]])\n\n# Make prediction\n# モデルで予測を実行\npred = model.predict(test_input)\n\n# Show the prediction result\n# 予測結果を表示\nprint(\"Prediction result / 予測結果:\", pred)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:23.559109Z","iopub.execute_input":"2025-07-10T13:37:23.559321Z","iopub.status.idle":"2025-07-10T13:37:28.230576Z","shell.execute_reply.started":"2025-07-10T13:37:23.559305Z","shell.execute_reply":"2025-07-10T13:37:28.229908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Submit Practice","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM, Dense, Bidirectional, Masking\nfrom tensorflow.keras.preprocessing.sequence import pad_sequences\nfrom tensorflow.keras.utils import to_categorical\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.layers import Dropout\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.layers import (\n    Conv1D, MaxPooling1D, Flatten, Dense, Dropout, BatchNormalization,\n    LSTM, Bidirectional, GlobalAveragePooling1D\n)\nimport warnings\nwarnings.simplefilter(\"ignore\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:28.231586Z","iopub.execute_input":"2025-07-10T13:37:28.231958Z","iopub.status.idle":"2025-07-10T13:37:28.357185Z","shell.execute_reply.started":"2025-07-10T13:37:28.231933Z","shell.execute_reply":"2025-07-10T13:37:28.356547Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CFG:\n    seed = 42\n    target = \"gesture\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:28.357910Z","iopub.execute_input":"2025-07-10T13:37:28.358148Z","iopub.status.idle":"2025-07-10T13:37:28.361582Z","shell.execute_reply.started":"2025-07-10T13:37:28.358126Z","shell.execute_reply":"2025-07-10T13:37:28.360965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Read Data","metadata":{}},{"cell_type":"code","source":"train_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\")\ntrain_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:28.362218Z","iopub.execute_input":"2025-07-10T13:37:28.362443Z","iopub.status.idle":"2025-07-10T13:37:57.997181Z","shell.execute_reply.started":"2025-07-10T13:37:28.362424Z","shell.execute_reply":"2025-07-10T13:37:57.996556Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_demo_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/train_demographics.csv\")\ntrain_demo_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:57.997820Z","iopub.execute_input":"2025-07-10T13:37:57.998012Z","iopub.status.idle":"2025-07-10T13:37:58.009911Z","shell.execute_reply.started":"2025-07-10T13:37:57.997997Z","shell.execute_reply":"2025-07-10T13:37:58.009340Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv\")\ntest_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.012244Z","iopub.execute_input":"2025-07-10T13:37:58.012433Z","iopub.status.idle":"2025-07-10T13:37:58.040375Z","shell.execute_reply.started":"2025-07-10T13:37:58.012419Z","shell.execute_reply":"2025-07-10T13:37:58.039867Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_demo_df = pd.read_csv(\"/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv\")\ntest_demo_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.041199Z","iopub.execute_input":"2025-07-10T13:37:58.041418Z","iopub.status.idle":"2025-07-10T13:37:58.051545Z","shell.execute_reply.started":"2025-07-10T13:37:58.041402Z","shell.execute_reply":"2025-07-10T13:37:58.050996Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"le = LabelEncoder()\ntrain_df['gesture_encoded'] = le.fit_transform(train_df['gesture'])\n\nlabel_dict = dict(zip(le.classes_, le.transform(le.classes_)))\nCFG.target_label = label_dict\n\nlabel_dict_reverse = dict(zip(le.transform(le.classes_), le.classes_))\nCFG.target_label_reverse = label_dict_reverse","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.052187Z","iopub.execute_input":"2025-07-10T13:37:58.052358Z","iopub.status.idle":"2025-07-10T13:37:58.144285Z","shell.execute_reply.started":"2025-07-10T13:37:58.052345Z","shell.execute_reply":"2025-07-10T13:37:58.143545Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CFG.target_label","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.145115Z","iopub.execute_input":"2025-07-10T13:37:58.145320Z","iopub.status.idle":"2025-07-10T13:37:58.149691Z","shell.execute_reply.started":"2025-07-10T13:37:58.145304Z","shell.execute_reply":"2025-07-10T13:37:58.149149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CFG.target_label_reverse","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.150288Z","iopub.execute_input":"2025-07-10T13:37:58.150965Z","iopub.status.idle":"2025-07-10T13:37:58.154840Z","shell.execute_reply.started":"2025-07-10T13:37:58.150949Z","shell.execute_reply":"2025-07-10T13:37:58.154320Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Bi-LSTM Predict","metadata":{}},{"cell_type":"code","source":"train_df[CFG.target] = train_df[CFG.target].map(CFG.target_label)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.155512Z","iopub.execute_input":"2025-07-10T13:37:58.155773Z","iopub.status.idle":"2025-07-10T13:37:58.194354Z","shell.execute_reply.started":"2025-07-10T13:37:58.155750Z","shell.execute_reply":"2025-07-10T13:37:58.193817Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def preprocess(seq_df, demo_df):\n\n    preprocessed_df = seq_df.copy()\n    \n    preprocessed_df = pd.merge(\n        preprocessed_df,\n        demo_df,\n        on = \"subject\",\n        how = \"left\"\n    )\n    \n    # Calculating base engineered IMU features (magnitude, angle)...\n    preprocessed_df['acc_mag'] = np.sqrt(preprocessed_df['acc_x']**2 + preprocessed_df['acc_y']**2 + preprocessed_df['acc_z']**2)\n    preprocessed_df['rot_angle'] = 2 * np.arccos(preprocessed_df['rot_w'].clip(-1, 1))\n    \n    # Calculating engineered IMU derivatives (jerk, angular velocity) for original acc_mag...\n    preprocessed_df['acc_mag_jerk'] = preprocessed_df.groupby('sequence_id')['acc_mag'].diff().fillna(0)\n    preprocessed_df['rot_angle_vel'] = preprocessed_df.groupby('sequence_id')['rot_angle'].diff().fillna(0)\n\n    preprocessed_df = preprocessed_df.fillna(0)\n\n    return preprocessed_df","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.195192Z","iopub.execute_input":"2025-07-10T13:37:58.195388Z","iopub.status.idle":"2025-07-10T13:37:58.200012Z","shell.execute_reply.started":"2025-07-10T13:37:58.195374Z","shell.execute_reply":"2025-07-10T13:37:58.199379Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def model_preprocess(train_df, train_demo_df):\n\n    pass    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.200584Z","iopub.execute_input":"2025-07-10T13:37:58.200737Z","iopub.status.idle":"2025-07-10T13:37:58.203715Z","shell.execute_reply.started":"2025-07-10T13:37:58.200725Z","shell.execute_reply":"2025-07-10T13:37:58.203046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preprocessed_train_df = preprocess(train_df, train_demo_df)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:37:58.204487Z","iopub.execute_input":"2025-07-10T13:37:58.204732Z","iopub.status.idle":"2025-07-10T13:38:00.774806Z","shell.execute_reply.started":"2025-07-10T13:37:58.204716Z","shell.execute_reply":"2025-07-10T13:38:00.774014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"drop_cols = [\"row_id\", \"sequence_type\", \"sequence_counter\", \"subject\", \"orientation\", \"behavior\", \"phase\", \"gesture_encoded\"]\npreprocessed_train_df = preprocessed_train_df.drop(columns = drop_cols)\npreprocessed_train_df.head(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:38:00.775665Z","iopub.execute_input":"2025-07-10T13:38:00.775889Z","iopub.status.idle":"2025-07-10T13:38:01.252601Z","shell.execute_reply.started":"2025-07-10T13:38:00.775867Z","shell.execute_reply":"2025-07-10T13:38:01.251777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ========== ① データ前処理 ==========\ngrouped = preprocessed_train_df.groupby('sequence_id')\nfeature_cols = list(set(preprocessed_train_df.columns) - {\"gesture\", \"sequence_id\"})\n\n# 各 sequence_id ごとのセンサー値（時系列）をリストにする\nX = [g[feature_cols].values for _, g in grouped]\ny = [g['gesture'].values[0] for _, g in grouped]\n\nX = [StandardScaler().fit_transform(seq) for seq in X]\n\ny_int = np.array(y)\ncw_vals = compute_class_weight(class_weight='balanced', classes=np.unique(y_int), y=y_int)\nclass_weight = dict(zip(np.unique(y_int), cw_vals))\nprint(class_weight)\n\ny_categorical = to_categorical(y)\n\n# パディング長さ決定\nlens = [len(seq) for seq in X]\npad_len = int(np.percentile(lens, 95))\n\nX_padded = pad_sequences(X, maxlen=pad_len, padding='post', dtype='float32')\n\n# 学習データと検証データに分割\nX_train, X_val, y_train, y_val = train_test_split(\n    X_padded, \n    y_categorical, \n    test_size=0.2, \n    random_state=42\n)\n\n# ========== ② BiLSTMモデル構築 ==========\nmodel = Sequential()\nmodel.add(Masking(mask_value=0., input_shape=(pad_len, len(feature_cols))))\nmodel.add(Bidirectional(LSTM(64, return_sequences=False)))\nmodel.add(Dropout(0.3))  # Dropout追加\nmodel.add(Dense(32, activation='relu'))\nmodel.add(Dense(y_categorical.shape[1], activation='softmax'))\n\nmodel.compile(\n    optimizer=Adam(learning_rate=1e-4), \n    loss='categorical_crossentropy', \n    metrics=['accuracy']\n)\nmodel.summary()\n\nearly_stop = EarlyStopping(monitor='val_loss', patience=5, restore_best_weights=True)\n\n# ========== ③ 学習 ==========\nmodel.fit(\n    X_train,\n    y_train,\n    validation_data=(X_val, y_val),\n    epochs=50,               \n    batch_size=32,\n    class_weight=class_weight,\n    callbacks=[early_stop]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:38:01.253440Z","iopub.execute_input":"2025-07-10T13:38:01.253728Z","iopub.status.idle":"2025-07-10T13:40:29.727839Z","shell.execute_reply.started":"2025-07-10T13:38:01.253702Z","shell.execute_reply":"2025-07-10T13:40:29.727068Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_pred = model.predict(X_val)\ny_pred_classes = np.argmax(y_pred, axis=1)\nprint(y_pred_classes)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:40:29.730292Z","iopub.execute_input":"2025-07-10T13:40:29.730488Z","iopub.status.idle":"2025-07-10T13:40:31.478232Z","shell.execute_reply.started":"2025-07-10T13:40:29.730472Z","shell.execute_reply":"2025-07-10T13:40:31.477587Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Submit","metadata":{}},{"cell_type":"code","source":"import os\nimport pandas as pd\nimport polars as pl\nfrom collections import Counter\nimport kaggle_evaluation.cmi_inference_server","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:40:31.479081Z","iopub.execute_input":"2025-07-10T13:40:31.479442Z","iopub.status.idle":"2025-07-10T13:40:32.132759Z","shell.execute_reply.started":"2025-07-10T13:40:31.479406Z","shell.execute_reply":"2025-07-10T13:40:32.132163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def predict(sequence: pl.DataFrame, demographics: pl.DataFrame) -> str:\n\n    sequence_df = sequence.to_pandas()\n    demo_df = demographics.to_pandas()\n\n    preprocessed_sequence_df = preprocess(sequence_df, demo_df)\n    \n    grouped = preprocessed_sequence_df.groupby('sequence_id')\n    \n    X_test = [g[feature_cols].values for _, g in grouped]\n    X_test = [StandardScaler().fit_transform(seq) for seq in X_test]\n\n    pad_len = 127\n    X_test_padded = pad_sequences(X_test, maxlen=pad_len, padding='post', dtype='float32')\n    \n    y_pred = model.predict(X_test_padded)\n    y_pred_classes = np.argmax(y_pred, axis=1)\n    \n    forecast = [CFG.target_label_reverse[int(label)] for label in y_pred_classes]\n    print(forecast)\n    \n    return forecast[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:40:32.133477Z","iopub.execute_input":"2025-07-10T13:40:32.133748Z","iopub.status.idle":"2025-07-10T13:40:32.139218Z","shell.execute_reply.started":"2025-07-10T13:40:32.133724Z","shell.execute_reply":"2025-07-10T13:40:32.138554Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"inference_server = kaggle_evaluation.cmi_inference_server.CMIInferenceServer(predict)\n\nif os.getenv('KAGGLE_IS_COMPETITION_RERUN'):\n    inference_server.serve()\nelse:\n    inference_server.run_local_gateway(\n        data_paths=(\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test.csv',\n            '/kaggle/input/cmi-detect-behavior-with-sensor-data/test_demographics.csv',\n        )\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-10T13:40:32.139929Z","iopub.execute_input":"2025-07-10T13:40:32.140157Z","iopub.status.idle":"2025-07-10T13:40:33.618011Z","shell.execute_reply.started":"2025-07-10T13:40:32.140142Z","shell.execute_reply":"2025-07-10T13:40:33.617394Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}