#  52th Place Solution: Feature Engineering & Post-Processing Improvements

The solution introduction image was created by Nano Banana.
First, I want to thank
[@AmbrosM](https://www.kaggle.com/AmbrosM)
and
[@mattiaangeli](https://www.kaggle.com/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.
Final Rank: 52nd
Baseline Overview
The baseline already includes:
FPS-adaptive feature scaling (
_scale
function)
Body part distance features
Rolling statistics (mean, std, range) for position and velocity
Curvature, multi-scale speed, and state transition features
GPU-accelerated GBDT ensemble
My Improvements
1. Action-Specific Thresholds & Minimum Durations
Instead of using a single threshold (0.27) for all behaviors, I defined per-action thresholds based on behavior characteristics:
DEFAULT_ACTION_THRESHOLDS = {
    'rear': 0.25,
    'selfgroom': 0.30,
    'attack': 0.35,
    'chase': 0.30,
    'approach': 0.22,
    'sniff': 0.25,
    # ... etc
}

DEFAULT_MIN_DURATION = {
    'rear': 5,
    'attack': 4,
    'chase': 5,
    # ... etc (in frames at 30fps, scaled by actual fps)
}
This helps reduce false positives for aggressive behaviors while being more sensitive to subtle social interactions.
2. Advanced Temporal Smoothing & Event Merging
Two-stage smoothing:
Median filter to remove single-frame outliers
Rolling mean for final smoothing
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.
def merge_nearby_events(submission, max_gap_frames=5):
    # Merge events separated by small gaps
    ...
3. Orientation & Angle Features
Single mouse:
Body orientation angle (nose-to-tail direction)
Angular velocity and acceleration
Rolling angular statistics
Mouse pairs:
A_facing_B
/
B_facing_A
: Is mouse A's body oriented toward B?
mutual_facing
: Both mice facing each other (for sniffing)
A_behind_B
: Following/chase pattern detection
orient_parallel
: Parallel vs perpendicular orientation
# Direction from A to B
dir_A_to_B = np.arctan2(B_cy - A_cy, B_cx - A_cx)
# Is A facing B?
A_facing_B = np.cos(A_orient - dir_A_to_B)  # 1 = facing, -1 = away
4. Behavior-Specific Signature Features
Rearing (
rear
):
Nose-tail distance compression (body appears shorter from top-down view)
rear_ratio
: nose-to-center vs center-to-tail distance ratio
Body length variance (increases during rearing transitions)
Chase (
chase
):
Sustained approach rate (negative distance derivative)
Velocity correlation between mice (high = following)
Speed ratio (chaser typically faster)
Attack (
attack
):
Proximity indicator (very close < 3cm)
Rapid approach detection
Acceleration bursts
5. Metadata Features
Added lab and experimental context as features:
Lab ID encoding
: Different labs may have different annotation styles
Arena shape/size
: Square, rectangular, or circular; normalized dimensions
Number of mice
FPS
(normalized)
Mouse sex
: Agent/target sex, same-sex interaction flag
LAB_ID_ENCODING = {
    'AdaptableSnail': 0,
    'BoisterousParrot': 1,
    # ... etc
}
Summary of Changes
Category
Baseline
My Solution
Thresholds
Fixed 0.27
Per-action (0.22-0.35)
Smoothing
Simple rolling
Median + rolling mean
Post-processing
Min 3 frames
Per-action min + event merge
Orientation features
None
Angular velocity, facing detection
Behavior signatures
None
Rear/chase/attack specific
Metadata
None
Lab, arena, sex features
What Didn't Work (or wasn't used)
TCN sequence model: Implemented but disabled due to time constraints
CV-based threshold optimization: Too slow for the final submission