{
  "id": 663274,
  "title": " 52th Place Solution: Feature Engineering & Post-Processing Improvements",
  "url": "/competitions/MABe-mouse-behavior-detection/discussion/663274",
  "author_name": "Chikuwabu",
  "post_date": "2025-12-17T06:05:40.708000",
  "votes": 14,
  "comment_count": 0,
  "views": 0,
  "content": "<p>The solution introduction image was created by Nano Banana.</p>\n<p>First, I want to thank <a href=\"https://www.kaggle.com/AmbrosM\" target=\"_blank\">@AmbrosM</a> and <a href=\"https://www.kaggle.com/mattiaangeli\" target=\"_blank\">@mattiaangeli</a> for the excellent baseline notebook. My solution builds directly on top of it, keeping the core FPS-adaptive windowing approach and GBDT ensemble (LightGBM, XGBoost, CatBoost) while adding several feature engineering and post-processing improvements.</p>\n<p><strong>Final Rank: 52nd</strong></p>\n<hr>\n<h2>Baseline Overview</h2>\n<p>The baseline already includes:</p>\n<ul>\n<li>FPS-adaptive feature scaling (<code>_scale</code> function)</li>\n<li>Body part distance features</li>\n<li>Rolling statistics (mean, std, range) for position and velocity</li>\n<li>Curvature, multi-scale speed, and state transition features</li>\n<li>GPU-accelerated GBDT ensemble</li>\n</ul>\n<hr>\n<h2>My Improvements</h2>\n<h3>1. Action-Specific Thresholds &amp; Minimum Durations</h3>\n<p>Instead of using a single threshold (0.27) for all behaviors, I defined per-action thresholds based on behavior characteristics:</p>\n<pre><code>DEFAULT_ACTION_THRESHOLDS = {\n    'rear': 0.25,\n    'selfgroom': 0.30,\n    'attack': 0.35,\n    'chase': 0.30,\n    'approach': 0.22,\n    'sniff': 0.25,\n    # ... etc\n}\n\nDEFAULT_MIN_DURATION = {\n    'rear': 5,\n    'attack': 4,\n    'chase': 5,\n    # ... etc (in frames at 30fps, scaled by actual fps)\n}\n</code></pre>\n<p>This helps reduce false positives for aggressive behaviors while being more sensitive to subtle social interactions.</p>\n<hr>\n<h3>2. Advanced Temporal Smoothing &amp; Event Merging</h3>\n<p><strong>Two-stage smoothing:</strong></p>\n<ol>\n<li>Median filter to remove single-frame outliers</li>\n<li>Rolling mean for final smoothing</li>\n</ol>\n<p><strong>Event merging:</strong> If two events of the same action are separated by a small gap (&lt; 5 frames), they are merged into one continuous event. This handles brief detection dropouts.</p>\n<pre><code>def merge_nearby_events(submission, max_gap_frames=5):\n    # Merge events separated by small gaps\n    ...\n</code></pre>\n<hr>\n<h3>3. Orientation &amp; Angle Features</h3>\n<p><strong>Single mouse:</strong></p>\n<ul>\n<li>Body orientation angle (nose-to-tail direction)</li>\n<li>Angular velocity and acceleration</li>\n<li>Rolling angular statistics</li>\n</ul>\n<p><strong>Mouse pairs:</strong></p>\n<ul>\n<li><code>A_facing_B</code> / <code>B_facing_A</code>: Is mouse A's body oriented toward B?</li>\n<li><code>mutual_facing</code>: Both mice facing each other (for sniffing)</li>\n<li><code>A_behind_B</code>: Following/chase pattern detection</li>\n<li><code>orient_parallel</code>: Parallel vs perpendicular orientation</li>\n</ul>\n<pre><code># Direction from A to B\ndir_A_to_B = np.arctan2(B_cy - A_cy, B_cx - A_cx)\n# Is A facing B?\nA_facing_B = np.cos(A_orient - dir_A_to_B)  # 1 = facing, -1 = away\n</code></pre>\n<hr>\n<h3>4. Behavior-Specific Signature Features</h3>\n<p><strong>Rearing (<code>rear</code>):</strong></p>\n<ul>\n<li>Nose-tail distance compression (body appears shorter from top-down view)</li>\n<li><code>rear_ratio</code>: nose-to-center vs center-to-tail distance ratio</li>\n<li>Body length variance (increases during rearing transitions)</li>\n</ul>\n<p><strong>Chase (<code>chase</code>):</strong></p>\n<ul>\n<li>Sustained approach rate (negative distance derivative)</li>\n<li>Velocity correlation between mice (high = following)</li>\n<li>Speed ratio (chaser typically faster)</li>\n</ul>\n<p><strong>Attack (<code>attack</code>):</strong></p>\n<ul>\n<li>Proximity indicator (very close &lt; 3cm)</li>\n<li>Rapid approach detection</li>\n<li>Acceleration bursts</li>\n</ul>\n<hr>\n<h3>5. Metadata Features</h3>\n<p>Added lab and experimental context as features:</p>\n<ul>\n<li><strong>Lab ID encoding</strong>: Different labs may have different annotation styles</li>\n<li><strong>Arena shape/size</strong>: Square, rectangular, or circular; normalized dimensions</li>\n<li><strong>Number of mice</strong></li>\n<li><strong>FPS</strong> (normalized)</li>\n<li><strong>Mouse sex</strong>: Agent/target sex, same-sex interaction flag</li>\n</ul>\n<pre><code>LAB_ID_ENCODING = {\n    'AdaptableSnail': 0,\n    'BoisterousParrot': 1,\n    # ... etc\n}\n</code></pre>\n<hr>\n<h2>Summary of Changes</h2>\n<table>\n<thead>\n<tr>\n<th>Category</th>\n<th>Baseline</th>\n<th>My Solution</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Thresholds</td>\n<td>Fixed 0.27</td>\n<td>Per-action (0.22-0.35)</td>\n</tr>\n<tr>\n<td>Smoothing</td>\n<td>Simple rolling</td>\n<td>Median + rolling mean</td>\n</tr>\n<tr>\n<td>Post-processing</td>\n<td>Min 3 frames</td>\n<td>Per-action min + event merge</td>\n</tr>\n<tr>\n<td>Orientation features</td>\n<td>None</td>\n<td>Angular velocity, facing detection</td>\n</tr>\n<tr>\n<td>Behavior signatures</td>\n<td>None</td>\n<td>Rear/chase/attack specific</td>\n</tr>\n<tr>\n<td>Metadata</td>\n<td>None</td>\n<td>Lab, arena, sex features</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>What Didn't Work (or wasn't used)</h2>\n<ul>\n<li>TCN sequence model: Implemented but disabled due to time constraints</li>\n<li>CV-based threshold optimization: Too slow for the final submission</li>\n</ul>",
  "messages": [
    {
      "id": 3377899,
      "postDate": "2025-12-17T06:05:40.707Z",
      "content": "<p>The solution introduction image was created by Nano Banana.</p>\n<p>First, I want to thank <a href=\"https://www.kaggle.com/AmbrosM\" target=\"_blank\">@AmbrosM</a> and <a href=\"https://www.kaggle.com/mattiaangeli\" target=\"_blank\">@mattiaangeli</a> for the excellent baseline notebook. My solution builds directly on top of it, keeping the core FPS-adaptive windowing approach and GBDT ensemble (LightGBM, XGBoost, CatBoost) while adding several feature engineering and post-processing improvements.</p>\n<p><strong>Final Rank: 52nd</strong></p>\n<hr>\n<h2>Baseline Overview</h2>\n<p>The baseline already includes:</p>\n<ul>\n<li>FPS-adaptive feature scaling (<code>_scale</code> function)</li>\n<li>Body part distance features</li>\n<li>Rolling statistics (mean, std, range) for position and velocity</li>\n<li>Curvature, multi-scale speed, and state transition features</li>\n<li>GPU-accelerated GBDT ensemble</li>\n</ul>\n<hr>\n<h2>My Improvements</h2>\n<h3>1. Action-Specific Thresholds &amp; Minimum Durations</h3>\n<p>Instead of using a single threshold (0.27) for all behaviors, I defined per-action thresholds based on behavior characteristics:</p>\n<pre><code>DEFAULT_ACTION_THRESHOLDS = {\n    'rear': 0.25,\n    'selfgroom': 0.30,\n    'attack': 0.35,\n    'chase': 0.30,\n    'approach': 0.22,\n    'sniff': 0.25,\n    # ... etc\n}\n\nDEFAULT_MIN_DURATION = {\n    'rear': 5,\n    'attack': 4,\n    'chase': 5,\n    # ... etc (in frames at 30fps, scaled by actual fps)\n}\n</code></pre>\n<p>This helps reduce false positives for aggressive behaviors while being more sensitive to subtle social interactions.</p>\n<hr>\n<h3>2. Advanced Temporal Smoothing &amp; Event Merging</h3>\n<p><strong>Two-stage smoothing:</strong></p>\n<ol>\n<li>Median filter to remove single-frame outliers</li>\n<li>Rolling mean for final smoothing</li>\n</ol>\n<p><strong>Event merging:</strong> If two events of the same action are separated by a small gap (&lt; 5 frames), they are merged into one continuous event. This handles brief detection dropouts.</p>\n<pre><code>def merge_nearby_events(submission, max_gap_frames=5):\n    # Merge events separated by small gaps\n    ...\n</code></pre>\n<hr>\n<h3>3. Orientation &amp; Angle Features</h3>\n<p><strong>Single mouse:</strong></p>\n<ul>\n<li>Body orientation angle (nose-to-tail direction)</li>\n<li>Angular velocity and acceleration</li>\n<li>Rolling angular statistics</li>\n</ul>\n<p><strong>Mouse pairs:</strong></p>\n<ul>\n<li><code>A_facing_B</code> / <code>B_facing_A</code>: Is mouse A's body oriented toward B?</li>\n<li><code>mutual_facing</code>: Both mice facing each other (for sniffing)</li>\n<li><code>A_behind_B</code>: Following/chase pattern detection</li>\n<li><code>orient_parallel</code>: Parallel vs perpendicular orientation</li>\n</ul>\n<pre><code># Direction from A to B\ndir_A_to_B = np.arctan2(B_cy - A_cy, B_cx - A_cx)\n# Is A facing B?\nA_facing_B = np.cos(A_orient - dir_A_to_B)  # 1 = facing, -1 = away\n</code></pre>\n<hr>\n<h3>4. Behavior-Specific Signature Features</h3>\n<p><strong>Rearing (<code>rear</code>):</strong></p>\n<ul>\n<li>Nose-tail distance compression (body appears shorter from top-down view)</li>\n<li><code>rear_ratio</code>: nose-to-center vs center-to-tail distance ratio</li>\n<li>Body length variance (increases during rearing transitions)</li>\n</ul>\n<p><strong>Chase (<code>chase</code>):</strong></p>\n<ul>\n<li>Sustained approach rate (negative distance derivative)</li>\n<li>Velocity correlation between mice (high = following)</li>\n<li>Speed ratio (chaser typically faster)</li>\n</ul>\n<p><strong>Attack (<code>attack</code>):</strong></p>\n<ul>\n<li>Proximity indicator (very close &lt; 3cm)</li>\n<li>Rapid approach detection</li>\n<li>Acceleration bursts</li>\n</ul>\n<hr>\n<h3>5. Metadata Features</h3>\n<p>Added lab and experimental context as features:</p>\n<ul>\n<li><strong>Lab ID encoding</strong>: Different labs may have different annotation styles</li>\n<li><strong>Arena shape/size</strong>: Square, rectangular, or circular; normalized dimensions</li>\n<li><strong>Number of mice</strong></li>\n<li><strong>FPS</strong> (normalized)</li>\n<li><strong>Mouse sex</strong>: Agent/target sex, same-sex interaction flag</li>\n</ul>\n<pre><code>LAB_ID_ENCODING = {\n    'AdaptableSnail': 0,\n    'BoisterousParrot': 1,\n    # ... etc\n}\n</code></pre>\n<hr>\n<h2>Summary of Changes</h2>\n<table>\n<thead>\n<tr>\n<th>Category</th>\n<th>Baseline</th>\n<th>My Solution</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Thresholds</td>\n<td>Fixed 0.27</td>\n<td>Per-action (0.22-0.35)</td>\n</tr>\n<tr>\n<td>Smoothing</td>\n<td>Simple rolling</td>\n<td>Median + rolling mean</td>\n</tr>\n<tr>\n<td>Post-processing</td>\n<td>Min 3 frames</td>\n<td>Per-action min + event merge</td>\n</tr>\n<tr>\n<td>Orientation features</td>\n<td>None</td>\n<td>Angular velocity, facing detection</td>\n</tr>\n<tr>\n<td>Behavior signatures</td>\n<td>None</td>\n<td>Rear/chase/attack specific</td>\n</tr>\n<tr>\n<td>Metadata</td>\n<td>None</td>\n<td>Lab, arena, sex features</td>\n</tr>\n</tbody>\n</table>\n<hr>\n<h2>What Didn't Work (or wasn't used)</h2>\n<ul>\n<li>TCN sequence model: Implemented but disabled due to time constraints</li>\n<li>CV-based threshold optimization: Too slow for the final submission</li>\n</ul>",
      "rawMarkdown": "The solution introduction image was created by Nano Banana.\n\nFirst, I want to thank @AmbrosM and @mattiaangeli for the excellent baseline notebook. My solution builds directly on top of it, keeping the core FPS-adaptive windowing approach and GBDT ensemble (LightGBM, XGBoost, CatBoost) while adding several feature engineering and post-processing improvements.\n\n**Final Rank: 52nd**\n\n---\n\n## Baseline Overview\n\nThe baseline already includes:\n- FPS-adaptive feature scaling (`_scale` function)\n- Body part distance features\n- Rolling statistics (mean, std, range) for position and velocity\n- Curvature, multi-scale speed, and state transition features\n- GPU-accelerated GBDT ensemble\n\n---\n\n## My Improvements\n\n### 1. Action-Specific Thresholds & Minimum Durations\n\nInstead of using a single threshold (0.27) for all behaviors, I defined per-action thresholds based on behavior characteristics:\n\n```python\nDEFAULT_ACTION_THRESHOLDS = {\n    'rear': 0.25,\n    'selfgroom': 0.30,\n    'attack': 0.35,\n    'chase': 0.30,\n    'approach': 0.22,\n    'sniff': 0.25,\n    # ... etc\n}\n\nDEFAULT_MIN_DURATION = {\n    'rear': 5,\n    'attack': 4,\n    'chase': 5,\n    # ... etc (in frames at 30fps, scaled by actual fps)\n}\n```\n\nThis helps reduce false positives for aggressive behaviors while being more sensitive to subtle social interactions.\n\n---\n\n### 2. Advanced Temporal Smoothing & Event Merging\n\n**Two-stage smoothing:**\n1. Median filter to remove single-frame outliers\n2. Rolling mean for final smoothing\n\n**Event merging:** If two events of the same action are separated by a small gap (< 5 frames), they are merged into one continuous event. This handles brief detection dropouts.\n\n```python\ndef merge_nearby_events(submission, max_gap_frames=5):\n    # Merge events separated by small gaps\n    ...\n```\n\n---\n\n### 3. Orientation & Angle Features\n\n**Single mouse:**\n- Body orientation angle (nose-to-tail direction)\n- Angular velocity and acceleration\n- Rolling angular statistics\n\n**Mouse pairs:**\n- `A_facing_B` / `B_facing_A`: Is mouse A's body oriented toward B?\n- `mutual_facing`: Both mice facing each other (for sniffing)\n- `A_behind_B`: Following/chase pattern detection\n- `orient_parallel`: Parallel vs perpendicular orientation\n\n```python\n# Direction from A to B\ndir_A_to_B = np.arctan2(B_cy - A_cy, B_cx - A_cx)\n# Is A facing B?\nA_facing_B = np.cos(A_orient - dir_A_to_B)  # 1 = facing, -1 = away\n```\n\n---\n\n### 4. Behavior-Specific Signature Features\n\n**Rearing (`rear`):**\n- Nose-tail distance compression (body appears shorter from top-down view)\n- `rear_ratio`: nose-to-center vs center-to-tail distance ratio\n- Body length variance (increases during rearing transitions)\n\n**Chase (`chase`):**\n- Sustained approach rate (negative distance derivative)\n- Velocity correlation between mice (high = following)\n- Speed ratio (chaser typically faster)\n\n**Attack (`attack`):**\n- Proximity indicator (very close < 3cm)\n- Rapid approach detection\n- Acceleration bursts\n\n---\n\n### 5. Metadata Features\n\nAdded lab and experimental context as features:\n\n- **Lab ID encoding**: Different labs may have different annotation styles\n- **Arena shape/size**: Square, rectangular, or circular; normalized dimensions\n- **Number of mice**\n- **FPS** (normalized)\n- **Mouse sex**: Agent/target sex, same-sex interaction flag\n\n```python\nLAB_ID_ENCODING = {\n    'AdaptableSnail': 0,\n    'BoisterousParrot': 1,\n    # ... etc\n}\n```\n\n---\n\n## Summary of Changes\n\n| Category | Baseline | My Solution |\n|----------|----------|-------------|\n| Thresholds | Fixed 0.27 | Per-action (0.22-0.35) |\n| Smoothing | Simple rolling | Median + rolling mean |\n| Post-processing | Min 3 frames | Per-action min + event merge |\n| Orientation features | None | Angular velocity, facing detection |\n| Behavior signatures | None | Rear/chase/attack specific |\n| Metadata | None | Lab, arena, sex features |\n\n---\n\n## What Didn't Work (or wasn't used)\n\n- TCN sequence model: Implemented but disabled due to time constraints\n- CV-based threshold optimization: Too slow for the final submission\n\n",
      "votes": 14
    }
  ],
  "comments": [],
  "raw_markdown_by_id": {
    "3377899": "The solution introduction image was created by Nano Banana.\n\nFirst, I want to thank @AmbrosM and @mattiaangeli for the excellent baseline notebook. My solution builds directly on top of it, keeping the core FPS-adaptive windowing approach and GBDT ensemble (LightGBM, XGBoost, CatBoost) while adding several feature engineering and post-processing improvements.\n\n**Final Rank: 52nd**\n\n---\n\n## Baseline Overview\n\nThe baseline already includes:\n- FPS-adaptive feature scaling (`_scale` function)\n- Body part distance features\n- Rolling statistics (mean, std, range) for position and velocity\n- Curvature, multi-scale speed, and state transition features\n- GPU-accelerated GBDT ensemble\n\n---\n\n## My Improvements\n\n### 1. Action-Specific Thresholds & Minimum Durations\n\nInstead of using a single threshold (0.27) for all behaviors, I defined per-action thresholds based on behavior characteristics:\n\n```python\nDEFAULT_ACTION_THRESHOLDS = {\n    'rear': 0.25,\n    'selfgroom': 0.30,\n    'attack': 0.35,\n    'chase': 0.30,\n    'approach': 0.22,\n    'sniff': 0.25,\n    # ... etc\n}\n\nDEFAULT_MIN_DURATION = {\n    'rear': 5,\n    'attack': 4,\n    'chase': 5,\n    # ... etc (in frames at 30fps, scaled by actual fps)\n}\n```\n\nThis helps reduce false positives for aggressive behaviors while being more sensitive to subtle social interactions.\n\n---\n\n### 2. Advanced Temporal Smoothing & Event Merging\n\n**Two-stage smoothing:**\n1. Median filter to remove single-frame outliers\n2. Rolling mean for final smoothing\n\n**Event merging:** If two events of the same action are separated by a small gap (< 5 frames), they are merged into one continuous event. This handles brief detection dropouts.\n\n```python\ndef merge_nearby_events(submission, max_gap_frames=5):\n    # Merge events separated by small gaps\n    ...\n```\n\n---\n\n### 3. Orientation & Angle Features\n\n**Single mouse:**\n- Body orientation angle (nose-to-tail direction)\n- Angular velocity and acceleration\n- Rolling angular statistics\n\n**Mouse pairs:**\n- `A_facing_B` / `B_facing_A`: Is mouse A's body oriented toward B?\n- `mutual_facing`: Both mice facing each other (for sniffing)\n- `A_behind_B`: Following/chase pattern detection\n- `orient_parallel`: Parallel vs perpendicular orientation\n\n```python\n# Direction from A to B\ndir_A_to_B = np.arctan2(B_cy - A_cy, B_cx - A_cx)\n# Is A facing B?\nA_facing_B = np.cos(A_orient - dir_A_to_B)  # 1 = facing, -1 = away\n```\n\n---\n\n### 4. Behavior-Specific Signature Features\n\n**Rearing (`rear`):**\n- Nose-tail distance compression (body appears shorter from top-down view)\n- `rear_ratio`: nose-to-center vs center-to-tail distance ratio\n- Body length variance (increases during rearing transitions)\n\n**Chase (`chase`):**\n- Sustained approach rate (negative distance derivative)\n- Velocity correlation between mice (high = following)\n- Speed ratio (chaser typically faster)\n\n**Attack (`attack`):**\n- Proximity indicator (very close < 3cm)\n- Rapid approach detection\n- Acceleration bursts\n\n---\n\n### 5. Metadata Features\n\nAdded lab and experimental context as features:\n\n- **Lab ID encoding**: Different labs may have different annotation styles\n- **Arena shape/size**: Square, rectangular, or circular; normalized dimensions\n- **Number of mice**\n- **FPS** (normalized)\n- **Mouse sex**: Agent/target sex, same-sex interaction flag\n\n```python\nLAB_ID_ENCODING = {\n    'AdaptableSnail': 0,\n    'BoisterousParrot': 1,\n    # ... etc\n}\n```\n\n---\n\n## Summary of Changes\n\n| Category | Baseline | My Solution |\n|----------|----------|-------------|\n| Thresholds | Fixed 0.27 | Per-action (0.22-0.35) |\n| Smoothing | Simple rolling | Median + rolling mean |\n| Post-processing | Min 3 frames | Per-action min + event merge |\n| Orientation features | None | Angular velocity, facing detection |\n| Behavior signatures | None | Rear/chase/attack specific |\n| Metadata | None | Lab, arena, sex features |\n\n---\n\n## What Didn't Work (or wasn't used)\n\n- TCN sequence model: Implemented but disabled due to time constraints\n- CV-based threshold optimization: Too slow for the final submission\n\n"
  }
}