{"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":"none","dataSources":[{"sourceId":59156,"databundleVersionId":13874099,"isSourceIdPinned":false,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:44:01.226370Z","iopub.execute_input":"2025-09-29T18:44:01.226540Z","iopub.status.idle":"2025-09-29T18:44:15.299856Z","shell.execute_reply.started":"2025-09-29T18:44:01.226522Z","shell.execute_reply":"2025-09-29T18:44:15.299099Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 0: Install Required Libraries  \n\nIn this step we install all the Python packages needed for this notebook.\n","metadata":{}},{"cell_type":"code","source":"pip install pandas numpy matplotlib seaborn scikit-learn torch torchvision\n","metadata":{"trusted":true,"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 1: Import Libraries and Load Dataset  \n\nHere we import pandas and read the training metadata CSV file.\n","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\ntrain_meta = pd.read_csv('/kaggle/input/MABe-mouse-behavior-detection/train.csv')\nprint(train_meta.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:28.996657Z","iopub.execute_input":"2025-09-29T18:45:28.996931Z","iopub.status.idle":"2025-09-29T18:45:29.118239Z","shell.execute_reply.started":"2025-09-29T18:45:28.996912Z","shell.execute_reply":"2025-09-29T18:45:29.117450Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 2: Basic Exploration of the Dataset  \n\nHere we check the shape, column names, distribution of labs and look at example behaviors per video.\n","metadata":{}},{"cell_type":"code","source":"print(train_meta.shape)          # rows x columns\nprint(train_meta.columns)        # column names\nprint(train_meta['lab_id'].value_counts())  # kaunse labs kitne videos diye\nprint(train_meta['behaviors_labeled'].head(5))  # example behaviors per video\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.119001Z","iopub.execute_input":"2025-09-29T18:45:29.119764Z","iopub.status.idle":"2025-09-29T18:45:29.129607Z","shell.execute_reply.started":"2025-09-29T18:45:29.119733Z","shell.execute_reply":"2025-09-29T18:45:29.128720Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 3: Parse and Count Behaviors  \n\nIn the dataset the `behaviors_labeled` column contains behaviors stored as string representations of Python lists.\nTo analyze them we:\n\n1. Define a helper function `safe_eval` to safely convert each string into an actual Python list (and turn NaN values into empty lists).\n2. Apply this function to create a new column `behaviors_list`.\n3. Flatten all behaviors from all videos into a single list (we also take the last part after a comma to get the behavior name).\n4. Use `collections.Counter` to count how many times each behavior occurs across the dataset.\n\nFinally, we print the top 10 most common behaviors.\n","metadata":{}},{"cell_type":"code","source":"import ast\nfrom collections import Counter\nimport pandas as pd\n\n# Convert string to list, NaN ko empty list me convert\ndef safe_eval(x):\n    if pd.isna(x):\n        return []\n    else:\n        return ast.literal_eval(x)\n\ntrain_meta['behaviors_list'] = train_meta['behaviors_labeled'].apply(safe_eval)\n\n# Flatten all behaviors\nall_behaviors = [b.split(',')[-1] for blist in train_meta['behaviors_list'] for b in blist]\n\n# Count frequency\nbehavior_counts = Counter(all_behaviors)\nprint(behavior_counts.most_common(10))  # top 10 behaviors\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.130359Z","iopub.execute_input":"2025-09-29T18:45:29.130546Z","iopub.status.idle":"2025-09-29T18:45:29.167362Z","shell.execute_reply.started":"2025-09-29T18:45:29.130531Z","shell.execute_reply":"2025-09-29T18:45:29.166005Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 4: Locate and List Tracking Files  \n\nThe dataset also contains mouse tracking data stored as `.parquet` files inside multiple lab folders.  \nIn this step we:\n\n1. Specify the root path to the tracking data.\n2. Loop through each lab folder and collect the full paths of all `.parquet` files.\n3. Print the total number of tracking files and show the first few paths as a sample.\n","metadata":{}},{"cell_type":"code","source":"import os\n\n# Trackings\ntracking_root = '/kaggle/input/MABe-mouse-behavior-detection/train_tracking'\ntracking_files = []\nfor lab in os.listdir(tracking_root):\n    lab_path = os.path.join(tracking_root, lab)\n    if os.path.isdir(lab_path):\n        for file in os.listdir(lab_path):\n            if file.endswith('.parquet'):\n                tracking_files.append(os.path.join(lab_path, file))\n\nprint(f'Total tracking files: {len(tracking_files)}')\nprint(tracking_files[:5])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.168392Z","iopub.execute_input":"2025-09-29T18:45:29.168632Z","iopub.status.idle":"2025-09-29T18:45:29.213796Z","shell.execute_reply.started":"2025-09-29T18:45:29.168611Z","shell.execute_reply":"2025-09-29T18:45:29.213205Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 5: Locate and List Annotation Files  \n\nApart from the tracking data, the dataset also contains **annotation files** (labels) stored as `.parquet` files inside multiple lab folders.  \n\nIn this step we:\n\n1. Specify the root path to the annotation data.\n2. Loop through each lab folder and collect the full paths of all `.parquet` annotation files.\n3. Print the total number of annotation files and display the first few paths as a sample.\n","metadata":{}},{"cell_type":"code","source":"annotation_root = '/kaggle/input/MABe-mouse-behavior-detection/train_annotation'\nannotation_files = []\nfor lab in os.listdir(annotation_root):\n    lab_path = os.path.join(annotation_root, lab)\n    if os.path.isdir(lab_path):\n        for file in os.listdir(lab_path):\n            if file.endswith('.parquet'):\n                annotation_files.append(os.path.join(lab_path, file))\n\nprint(f'Total annotation files: {len(annotation_files)}')\nprint(annotation_files[:5])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.216058Z","iopub.execute_input":"2025-09-29T18:45:29.216777Z","iopub.status.idle":"2025-09-29T18:45:29.245321Z","shell.execute_reply.started":"2025-09-29T18:45:29.216757Z","shell.execute_reply":"2025-09-29T18:45:29.244581Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 6: Load Tracking and Annotation Data for One Video  \n\nTo inspect the structure of the data, we pick the **first video** from our lists of tracking and annotation files.\n\n- `pose_data` will hold the mouse pose/position data loaded from the first tracking `.parquet` file.\n- `annotations` will hold the labeled behaviors loaded from the corresponding annotation `.parquet` file.\n\nWe then print the first few rows of each to see their format.\n","metadata":{}},{"cell_type":"code","source":"# Pick first video\ntracking_file = tracking_files[0]\nannotation_file = annotation_files[0]\n\npose_data = pd.read_parquet(tracking_file)\nannotations = pd.read_parquet(annotation_file)\n\nprint(pose_data.head())\nprint(annotations.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.245918Z","iopub.execute_input":"2025-09-29T18:45:29.246152Z","iopub.status.idle":"2025-09-29T18:45:29.516926Z","shell.execute_reply.started":"2025-09-29T18:45:29.246107Z","shell.execute_reply":"2025-09-29T18:45:29.516368Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 7: Create Per-Frame Labels from Annotations  \n\nThe annotation file gives us start and stop frames for each behavior.  \nTo work with them easily we:\n\n1. Find the maximum frame index from `pose_data`.\n2. Create a NumPy array `frame_labels` filled with the default label `'none'` for all frames.\n3. Loop through each row of the `annotations` DataFrame and, for the frame range between `start_frame` and `stop_frame`, assign the corresponding `action` label.\n4. Print a small slice of `frame_labels` to check that labels have been filled correctly.\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\n\nmax_frame = pose_data['video_frame'].max()\nframe_labels = np.array(['none'] * (max_frame+1))  # default 'none'\n\n# Fill labels from annotations\nfor _, row in annotations.iterrows():\n    frame_labels[row['start_frame']:row['stop_frame']+1] = row['action']\n\nprint(frame_labels[1750:1770])  # check around first annotated frame\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.517543Z","iopub.execute_input":"2025-09-29T18:45:29.517734Z","iopub.status.idle":"2025-09-29T18:45:29.529402Z","shell.execute_reply.started":"2025-09-29T18:45:29.517718Z","shell.execute_reply":"2025-09-29T18:45:29.528637Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 8: Normalize Pose Coordinates  \n\nTo make the pose data consistent across videos of different sizes, we perform **simple min-max normalization**:\n\n- Divide each `x` coordinate by the maximum `x` value in the video.\n- Divide each `y` coordinate by the maximum `y` value in the video.\n\nThis scales all coordinates to the range `[0, 1]` and makes the data suitable for modeling or visualization.\n","metadata":{}},{"cell_type":"code","source":"# Example: simple min-max normalization per video\npose_data['x_norm'] = pose_data['x'] / pose_data['x'].max()\npose_data['y_norm'] = pose_data['y'] / pose_data['y'].max()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.530179Z","iopub.execute_input":"2025-09-29T18:45:29.530370Z","iopub.status.idle":"2025-09-29T18:45:29.548554Z","shell.execute_reply.started":"2025-09-29T18:45:29.530357Z","shell.execute_reply":"2025-09-29T18:45:29.547664Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 9: Create Sequences and Assign Labels  \n\nTo prepare data for sequence-based modeling:\n\n1. Set a `sequence_length` (here 30 frames per sequence).\n2. Initialize empty lists `sequences` and `labels`.\n3. Check all unique actions in `frame_labels` and create an **action map** to convert action names to integers.\n4. Loop through frames in steps of `sequence_length`:\n    - Select a window of frames from `pose_data`.\n    - Pivot the data to create a matrix with shape `(frames_in_window, bodyparts*2)` containing `x` and `y` coordinates.\n    - Skip empty sequences.\n    - For labels, take the **majority action** in the window and convert it to integer using `action_map`.\n5. Append sequence arrays and their corresponding labels.\n\nFinally, print:\n- Total number of sequences\n- Shape of the first sequence\n- First label\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nsequence_length = 30\nsequences = []\nlabels = []\n\n# frame-level labels already created\n# frame_labels = np.array([...])\n\n# check all unique actions\nunique_actions = np.unique(frame_labels)\nprint(\"Unique actions in this video:\", unique_actions)\n\n# automatically create action map\naction_map = {act:i for i, act in enumerate(unique_actions)}\n\nmax_frame = pose_data['video_frame'].max()\n\nfor start in range(0, max_frame-sequence_length, sequence_length):\n    seq = pose_data[(pose_data['video_frame']>=start) & (pose_data['video_frame']<start+sequence_length)]\n    \n    # Pivot with aggregation to handle duplicates\n    seq_array = seq.pivot_table(\n        index='video_frame',\n        columns='bodypart',\n        values=['x','y'],    # <-- changed from x_norm/y_norm\n        aggfunc='mean'\n    ).values\n    \n    if seq_array.shape[0] == 0:   # skip empty sequences\n        continue\n    \n    sequences.append(seq_array)\n    \n    # Majority action in this window\n    window_labels = frame_labels[start:start+sequence_length]\n    \n    # map actions to integers safely\n    label_ints = [action_map.get(a, action_map.get('none',0)) for a in window_labels]\n    labels.append(np.bincount(label_ints).argmax())\n\nprint(f\"Number of sequences: {len(sequences)}\")\nprint(f\"Shape of first sequence: {sequences[0].shape}\")\nprint(f\"First label: {labels[0]}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:29.549505Z","iopub.execute_input":"2025-09-29T18:45:29.549753Z","iopub.status.idle":"2025-09-29T18:45:31.657509Z","shell.execute_reply.started":"2025-09-29T18:45:29.549735Z","shell.execute_reply":"2025-09-29T18:45:31.656089Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 10: Pad Sequences to Uniform Length  \n\nSince sequences may have different lengths (especially at the end of the video), we need to **pad them** so that all sequences have the same number of frames.\n\nSteps:\n\n1. Find the maximum sequence length among all sequences.\n2. Loop through each sequence and pad it with zeros at the end if its length is shorter than the maximum.\n3. Convert the list of padded sequences to a NumPy array `X`.\n4. Convert labels list to a NumPy array `y`.\n\nAfter this, `X` has shape `(num_sequences, max_seq_len, num_features)` suitable for feeding into sequence-based models (RNN, LSTM, etc.).\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tensorflow.keras.preprocessing.sequence import pad_sequences\n\n# Find max sequence length\nmax_seq_len = max([s.shape[0] for s in sequences])\n\n# Pad sequences to same length\n# seq.shape = (frames, features) -> pad along frames axis\npadded_sequences = []\nfor s in sequences:\n    pad_len = max_seq_len - s.shape[0]\n    if pad_len > 0:\n        # Pad with zeros at the end\n        s_padded = np.pad(s, ((0,pad_len),(0,0)), mode='constant', constant_values=0)\n    else:\n        s_padded = s\n    padded_sequences.append(s_padded)\n\n# Convert to numpy array\nX = np.array(padded_sequences)\ny = np.array(labels)\n\nprint(\"X shape after padding:\", X.shape)\nprint(\"y shape:\", y.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:31.658330Z","iopub.execute_input":"2025-09-29T18:45:31.658511Z","iopub.status.idle":"2025-09-29T18:45:47.609374Z","shell.execute_reply.started":"2025-09-29T18:45:31.658496Z","shell.execute_reply":"2025-09-29T18:45:47.608210Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 11: Split Data into Training and Validation Sets  \n\nBefore training a model, we split the data into **training** and **validation** sets:\n\n- Use `train_test_split` from `sklearn.model_selection`.\n- `test_size=0.2` → 20% of data for validation.\n- `stratify=y` → ensures the label distribution is preserved in both sets.\n- `random_state=42` → for reproducibility.\n\nAfter this, `X_train` and `y_train` will be used for training the model, while `X_val` and `y_val` will be used to evaluate performance during training.\n","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX_train, X_val, y_train, y_val = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y\n)\n\nprint(\"Train shapes:\", X_train.shape, y_train.shape)\nprint(\"Validation shapes:\", X_val.shape, y_val.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:47.610174Z","iopub.execute_input":"2025-09-29T18:45:47.610631Z","iopub.status.idle":"2025-09-29T18:45:47.755668Z","shell.execute_reply.started":"2025-09-29T18:45:47.610613Z","shell.execute_reply":"2025-09-29T18:45:47.754739Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 12: Define LSTM Model  \n\nWe now define a simple **LSTM-based neural network** for sequence classification:\n\n1. **Masking Layer**: `Masking(mask_value=0.)`  \n   - Ignores the zero-padded frames in the sequences.\n\n2. **LSTM Layer**: `LSTM(64)`  \n   - Processes the sequence and outputs a feature vector of size 64.\n   - `return_sequences=False` since we only need the final output for classification.\n\n3. **Dense Layer**: `Dense(64, activation='relu')`  \n   - Fully connected layer to learn additional features.\n\n4. **Output Layer**: `Dense(num_classes, activation='softmax')`  \n   - Outputs probabilities for each behavior class.\n\n5. **Compile Model**:  \n   - Loss: `sparse_categorical_crossentropy` (since labels are integers)  \n   - Optimizer: `adam`  \n   - Metric: `accuracy`\n\nFinally, we print `model.summary()` to see the architecture and number of parameters.\n","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import LSTM, Dense, Masking\n\nnum_classes = len(np.unique(y))  # Number of unique behaviors\n\nmodel = Sequential([\n    Masking(mask_value=0., input_shape=(X_train.shape[1], X_train.shape[2])),  # ignore zero-padding\n    LSTM(64, return_sequences=False),\n    Dense(64, activation='relu'),\n    Dense(num_classes, activation='softmax')\n])\n\nmodel.compile(\n    loss='sparse_categorical_crossentropy',\n    optimizer='adam',\n    metrics=['accuracy']\n)\n\nmodel.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:47.756447Z","iopub.execute_input":"2025-09-29T18:45:47.756756Z","iopub.status.idle":"2025-09-29T18:45:47.887992Z","shell.execute_reply.started":"2025-09-29T18:45:47.756732Z","shell.execute_reply":"2025-09-29T18:45:47.887015Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 13: Train the LSTM Model  \n\nWe train the LSTM model using the training data:\n\n- `X_train`, `y_train`: training sequences and labels.\n- `validation_data=(X_val, y_val)`: to monitor performance on validation set.\n- `epochs=20`: start with a small number of epochs; can increase later depending on GPU/memory resources.\n- `batch_size=32`: number of sequences processed in one iteration.\n\nThe training history is stored in the `history` object, which can later be used to plot loss and accuracy curves.\n","metadata":{}},{"cell_type":"code","source":"history = model.fit(\n    X_train, y_train,\n    validation_data=(X_val, y_val),\n    epochs=20,           # chhota epoch se start karo, GPU resources dekh ke badha sakte ho\n    batch_size=32\n)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:47.888764Z","iopub.execute_input":"2025-09-29T18:45:47.888953Z","iopub.status.idle":"2025-09-29T18:45:57.672322Z","shell.execute_reply.started":"2025-09-29T18:45:47.888928Z","shell.execute_reply":"2025-09-29T18:45:57.671342Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"## Step 14: Plot Training and Validation Accuracy  \n\nAfter training, we can visualize how the model performed over epochs:\n\n- `history.history['accuracy']` → training accuracy per epoch.\n- `history.history['val_accuracy']` → validation accuracy per epoch.\n- Plotting both curves helps to check for **overfitting** or **underfitting**.\n","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.plot(history.history['accuracy'], label='train_acc')\nplt.plot(history.history['val_accuracy'], label='val_acc')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:57.674111Z","iopub.execute_input":"2025-09-29T18:45:57.674544Z","iopub.status.idle":"2025-09-29T18:45:57.889658Z","shell.execute_reply.started":"2025-09-29T18:45:57.674517Z","shell.execute_reply":"2025-09-29T18:45:57.888413Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 15: Evaluate Model on Validation Set  \n\nAfter training, we evaluate the model on the **validation data**:\n\n- `model.evaluate(X_val, y_val)` returns the loss and accuracy on the validation set.\n- This gives a final measure of how well the model generalizes to unseen data.\n","metadata":{}},{"cell_type":"code","source":"val_loss, val_acc = model.evaluate(X_val, y_val)\nprint(\"Validation Accuracy:\", val_acc)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:57.890515Z","iopub.execute_input":"2025-09-29T18:45:57.890781Z","iopub.status.idle":"2025-09-29T18:45:58.548559Z","shell.execute_reply.started":"2025-09-29T18:45:57.890761Z","shell.execute_reply":"2025-09-29T18:45:58.547291Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 16: Generate Predictions and Map to Behavior Names  \n\nAfter training and evaluation, we can predict behaviors for the validation sequences:\n\n1. `model.predict(X_val)` → gives probability distribution over all classes for each sequence.\n2. `np.argmax(..., axis=1)` → get the predicted class index for each sequence.\n3. Map the predicted class indices back to **behavior names** using `inv_action_map`.\n4. Print the first few predicted behaviors as a sample.\n","metadata":{}},{"cell_type":"code","source":"y_pred_probs = model.predict(X_val)\ny_pred_classes = np.argmax(y_pred_probs, axis=1)\n\n# Map back to behavior names\ninv_action_map = {0:'none',1:'sniff',2:'attack',3:'sniffgenital',4:'chase',\n                  5:'approach',6:'mount',7:'rear',8:'escape',9:'avoid',10:'chaseattack'}\n\npred_behaviors = [inv_action_map[i] for i in y_pred_classes]\nprint(pred_behaviors[:10])\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:58.549499Z","iopub.execute_input":"2025-09-29T18:45:58.549748Z","iopub.status.idle":"2025-09-29T18:45:59.070291Z","shell.execute_reply.started":"2025-09-29T18:45:58.549729Z","shell.execute_reply":"2025-09-29T18:45:59.069216Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 17: Classification Report and Confusion Matrix  \n\nTo evaluate the model in detail:\n\n1. **Classification Report**:  \n   - Provides precision, recall, f1-score, and support for each behavior class.\n   - Helps to understand which behaviors are predicted well or poorly.\n\n2. **Confusion Matrix**:  \n   - Shows the number of correct and incorrect predictions for each class.\n   - Helps to visualize misclassifications between behaviors.\n","metadata":{}},{"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix\n\nprint(classification_report(y_val, y_pred_classes))\ncm = confusion_matrix(y_val, y_pred_classes)\nprint(cm)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:59.071372Z","iopub.execute_input":"2025-09-29T18:45:59.071691Z","iopub.status.idle":"2025-09-29T18:45:59.089592Z","shell.execute_reply.started":"2025-09-29T18:45:59.071673Z","shell.execute_reply":"2025-09-29T18:45:59.088969Z"},"_kg_hide-output":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Step 18: Generate Submission File  \n\nTo prepare the submission for Kaggle:\n\n1. Initialize an empty list `submission` and a `row_id` counter.\n2. Loop through all videos in `train_meta`.\n3. For each video:\n    - Load the pose data.\n    - Predict behaviors for sequences (here a placeholder list `['none'] * num_sequences` is used; in practice use model predictions).\n4. For each sequence, create a row with:\n    - `row_id`\n    - `video_id`\n    - `agent_id` and `target_id` (mouse1, mouse2)\n    - `action` (predicted behavior)\n    - `start_frame` and `stop_frame`\n5. Convert the list to a pandas DataFrame and save as `submission.csv`.\n\nThis format matches the expected Kaggle submission structure.\n","metadata":{}},{"cell_type":"code","source":"import pandas as pd\n\nsubmission = []\nrow_id = 0\nsequence_length = 30\nmouse_map = {1: 'mouse1', 2: 'mouse2'}\n\n# Loop through all videos in train_meta\nfor idx, row in train_meta.iterrows():\n    video_id = row['video_id']\n    \n    # Pose data load karo\n    pose_data = pd.read_parquet(f'/kaggle/input/MABe-mouse-behavior-detection/train_tracking/{row[\"lab_id\"]}/{video_id}.parquet')\n    \n    # frame_labels ya model se predictions\n    # sequences aur pred_behaviors calculate karo (jaise pehle kiya)\n    # yahan ek example prediction list le rahe hain\n    max_frame = pose_data['video_frame'].max()\n    num_sequences = max_frame // sequence_length\n    pred_behaviors = ['none'] * num_sequences   # placeholder, model predictions\n    \n    # Submission rows add karo\n    for i in range(num_sequences):\n        start_frame = i * sequence_length\n        stop_frame = start_frame + sequence_length - 1\n        action = pred_behaviors[i]\n        \n        submission.append([\n            row_id,\n            video_id,\n            mouse_map[1],\n            mouse_map[2],\n            action,\n            start_frame,\n            stop_frame\n        ])\n        row_id += 1\n\nsub_df = pd.DataFrame(submission, columns=['row_id','video_id','agent_id','target_id','action','start_frame','stop_frame'])\nsub_df.to_csv('submission.csv', index=False)\nprint(sub_df.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-29T18:45:59.090621Z","iopub.execute_input":"2025-09-29T18:45:59.090790Z","iopub.status.idle":"2025-09-29T18:48:35.045745Z","shell.execute_reply.started":"2025-09-29T18:45:59.090776Z","shell.execute_reply":"2025-09-29T18:48:35.045049Z"}},"outputs":[],"execution_count":null}]}