{"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":102335,"databundleVersionId":12518947,"sourceType":"competition"}],"dockerImageVersionId":31239,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 📦 Step 1: Importing Libraries","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"# ============================================================================\n# BFRB Gesture Detection - Professional EDA & Modeling Pipeline\n# Author: [َArman Karimi]\n# Kaggle Notebook for Resume\n# ============================================================================\n\n# Step 1: Import libraries with clean organization\n\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.preprocessing import LabelEncoder, StandardScaler\nfrom sklearn.model_selection import train_test_split, cross_val_score\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.metrics import f1_score, classification_report, confusion_matrix\nimport warnings\nwarnings.filterwarnings('ignore')\n\n# Set aesthetic style\nplt.style.use('seaborn-v0_8-darkgrid')\nsns.set_palette(\"husl\")\nplt.rcParams['figure.figsize'] = [12, 8]\nplt.rcParams['font.size'] = 12\n\nprint(\"✅ Libraries imported successfully\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T17:13:34.178633Z","iopub.execute_input":"2026-01-03T17:13:34.179812Z","iopub.status.idle":"2026-01-03T17:13:34.188338Z","shell.execute_reply.started":"2026-01-03T17:13:34.179775Z","shell.execute_reply":"2026-01-03T17:13:34.186906Z"},"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 📥 Step 2: Loading and Initial Data Inspection","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 2: Load and Inspect Data\n# ============================================================================\n\n# Load the dataset\ntrain_path = \"/kaggle/input/cmi-detect-behavior-with-sensor-data/train.csv\"\ndf = pd.read_csv(train_path)\n\n# Display basic information\nprint(f\"📊 Dataset Shape: {df.shape[0]} rows × {df.shape[1]} columns\")\nprint(f\"📋 Column Types:\\n{df.dtypes.value_counts()}\")\n\n# Show first few rows\nprint(\"\\n👀 First 5 rows of the dataset:\")\ndisplay(df.head())\n\n# Show column categories\nprint(\"\\n🏷️ Column Categories:\")\nprint(\"-\" * 40)\nprint(\"Identifier Columns:\", [col for col in df.columns if 'id' in col])\nprint(\"Target Columns:\", [col for col in df.columns if 'type' in col or 'gesture' in col])\nprint(\"Sensor Columns - IMU:\", [col for col in df.columns if col.startswith('acc_') or col.startswith('rot_')])\nprint(\"Sensor Columns - Thermopile:\", [col for col in df.columns if col.startswith('thm_')])\nprint(\"Sensor Columns - TOF:\", [col for col in df.columns if col.startswith('tof_')][:5], \"...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T17:14:34.945971Z","iopub.execute_input":"2026-01-03T17:14:34.947224Z","iopub.status.idle":"2026-01-03T17:15:12.763275Z","shell.execute_reply.started":"2026-01-03T17:14:34.947126Z","shell.execute_reply":"2026-01-03T17:15:12.762084Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🎯 Step 3: Target Variables Analysis","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 3: Analyze Target Variables\n# ============================================================================\n\n# Create a figure for target analysis\nfig, axes = plt.subplots(1, 3, figsize=(18, 5))\n\n# 1. Sequence Type Distribution\nsequence_counts = df['sequence_type'].value_counts()\naxes[0].bar(sequence_counts.index, sequence_counts.values, color=['#FF6B6B', '#4ECDC4'])\naxes[0].set_title('Distribution of Sequence Types', fontsize=14, fontweight='bold')\naxes[0].set_xlabel('Sequence Type')\naxes[0].set_ylabel('Count')\nfor i, v in enumerate(sequence_counts.values):\n    axes[0].text(i, v + 1000, f'{v:,}', ha='center', fontweight='bold')\n\n# 2. Gesture Distribution (Top 10)\ngesture_counts = df['gesture'].value_counts().head(10)\nbars = axes[1].bar(range(len(gesture_counts)), gesture_counts.values, color='#45B7D1')\naxes[1].set_title('Top 10 Gestures Distribution', fontsize=14, fontweight='bold')\naxes[1].set_xlabel('Gesture')\naxes[1].set_ylabel('Count')\naxes[1].set_xticks(range(len(gesture_counts)))\naxes[1].set_xticklabels(gesture_counts.index, rotation=45, ha='right')\n\n# Add value labels on bars\nfor bar, count in zip(bars, gesture_counts.values):\n    axes[1].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 500, \n                f'{count:,}', ha='center', fontsize=9)\n\n# 3. Pie Chart for Sequence Type Percentage\ncolors = ['#FF6B6B', '#4ECDC4']\nwedges, texts, autotexts = axes[2].pie(sequence_counts.values, labels=sequence_counts.index, \n                                       colors=colors, autopct='%1.1f%%', startangle=90)\naxes[2].set_title('Sequence Type Percentage', fontsize=14, fontweight='bold')\n\n# Make percentages bold\nfor autotext in autotexts:\n    autotext.set_color('white')\n    autotext.set_fontweight('bold')\n\nplt.tight_layout()\nplt.show()\n\n# Print statistics\nprint(f\"📈 Sequence Type Statistics:\")\nprint(f\"   • Target: {sequence_counts['Target']:,} samples ({sequence_counts['Target']/len(df)*100:.1f}%)\")\nprint(f\"   • Non-Target: {sequence_counts['Non-Target']:,} samples ({sequence_counts['Non-Target']/len(df)*100:.1f}%)\")\nprint(f\"\\n🎭 Total Unique Gestures: {df['gesture'].nunique()}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T17:18:38.221114Z","iopub.execute_input":"2026-01-03T17:18:38.221513Z","iopub.status.idle":"2026-01-03T17:18:38.89825Z","shell.execute_reply.started":"2026-01-03T17:18:38.221489Z","shell.execute_reply":"2026-01-03T17:18:38.896206Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🔍 Step 4: Missing Values Analysis","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 4: Missing Values Analysis with Visualization\n# ============================================================================\n\n# Calculate missing values\nmissing_stats = pd.DataFrame({\n    'Missing_Count': df.isnull().sum(),\n    'Missing_Percentage': df.isnull().sum() / len(df) * 100\n})\n\n# Filter columns with missing values\nmissing_stats = missing_stats[missing_stats['Missing_Count'] > 0].sort_values('Missing_Percentage', ascending=False)\n\n# Create visualization\nfig, axes = plt.subplots(1, 2, figsize=(16, 6))\n\n# 1. Bar plot for top 20 columns with missing values\ntop_missing = missing_stats.head(20)\nbars = axes[0].barh(range(len(top_missing)), top_missing['Missing_Percentage'].values, color='#FF9F43')\naxes[0].set_yticks(range(len(top_missing)))\naxes[0].set_yticklabels(top_missing.index)\naxes[0].set_xlabel('Missing Percentage (%)')\naxes[0].set_title('Top 20 Columns with Missing Values', fontsize=14, fontweight='bold')\naxes[0].invert_yaxis()  # Highest on top\n\n# Add percentage labels\nfor i, (bar, pct) in enumerate(zip(bars, top_missing['Missing_Percentage'].values)):\n    axes[0].text(bar.get_width() + 0.5, bar.get_y() + bar.get_height()/2, \n                f'{pct:.2f}%', va='center', fontsize=9)\n\n# 2. Pie chart for missing values by sensor type\nsensor_types = {\n    'TOF Sensors': len([col for col in df.columns if col.startswith('tof_') and df[col].isnull().sum() > 0]),\n    'Thermopile': len([col for col in df.columns if col.startswith('thm_') and df[col].isnull().sum() > 0]),\n    'IMU': len([col for col in df.columns if col.startswith(('acc_', 'rot_')) and df[col].isnull().sum() > 0]),\n    'Other': len(missing_stats) - len([col for col in df.columns if col.startswith(('tof_', 'thm_', 'acc_', 'rot_')) \n                                      and df[col].isnull().sum() > 0])\n}\n\ncolors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']\naxes[1].pie(sensor_types.values(), labels=sensor_types.keys(), colors=colors, autopct='%1.1f%%', startangle=90)\naxes[1].set_title('Missing Values by Sensor Type', fontsize=14, fontweight='bold')\n\nplt.tight_layout()\nplt.show()\n\n# Print summary\nprint(f\"📊 Missing Values Summary:\")\nprint(f\"   • Total columns with missing values: {len(missing_stats)}\")\nprint(f\"   • Maximum missing percentage: {missing_stats['Missing_Percentage'].max():.2f}%\")\nprint(f\"   • Columns with >5% missing: {len(missing_stats[missing_stats['Missing_Percentage'] > 5])}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T17:19:27.008314Z","iopub.execute_input":"2026-01-03T17:19:27.008769Z","iopub.status.idle":"2026-01-03T17:19:30.859495Z","shell.execute_reply.started":"2026-01-03T17:19:27.008745Z","shell.execute_reply":"2026-01-03T17:19:30.858246Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#  📡 Step 5: Sensor Data Distribution Analysis","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 5: Sensor Data Distribution Analysis\n# ============================================================================\n\n# Select key sensor columns for analysis\nkey_sensors = {\n    'IMU - Acceleration': ['acc_x', 'acc_y', 'acc_z'],\n    'IMU - Rotation': ['rot_w', 'rot_x', 'rot_y', 'rot_z'],\n    'Thermopile': ['thm_1', 'thm_2', 'thm_3', 'thm_4'],\n    'TOF Sample': ['tof_1_v0', 'tof_2_v0', 'tof_3_v0']  # Sample TOF sensors\n}\n\n# Create distribution plots\nfig, axes = plt.subplots(2, 2, figsize=(16, 12))\naxes = axes.flatten()\n\nfor idx, (sensor_group, sensor_cols) in enumerate(key_sensors.items()):\n    # Filter only columns that exist in dataframe\n    existing_cols = [col for col in sensor_cols if col in df.columns]\n    \n    if existing_cols:\n        # Create subplot for each sensor group\n        ax = axes[idx]\n        \n        # Plot distribution for each sensor in the group\n        for col in existing_cols:\n            # Remove outliers for better visualization\n            data = df[col].dropna()\n            Q1 = data.quantile(0.25)\n            Q3 = data.quantile(0.75)\n            IQR = Q3 - Q1\n            filtered_data = data[(data >= Q1 - 1.5*IQR) & (data <= Q3 + 1.5*IQR)]\n            \n            sns.kdeplot(data=filtered_data, label=col, ax=ax, linewidth=2)\n        \n        ax.set_title(f'{sensor_group} Distribution', fontsize=14, fontweight='bold')\n        ax.set_xlabel('Sensor Value')\n        ax.set_ylabel('Density')\n        ax.legend()\n        ax.grid(True, alpha=0.3)\n    else:\n        axes[idx].text(0.5, 0.5, f'No {sensor_group} data available', \n                      ha='center', va='center', transform=axes[idx].transAxes)\n        axes[idx].set_title(f'{sensor_group} (Not Available)', fontsize=14, fontweight='bold')\n\nplt.tight_layout()\nplt.show()\n\n# Print sensor statistics\nprint(\"📊 Key Sensor Statistics:\")\nfor sensor_group, sensor_cols in key_sensors.items():\n    existing_cols = [col for col in sensor_cols if col in df.columns]\n    if existing_cols:\n        print(f\"\\n🔹 {sensor_group}:\")\n        for col in existing_cols[:3]:  # Show first 3 sensors only\n            stats = df[col].describe()\n            print(f\"   {col}: Mean={stats['mean']:.2f}, Std={stats['std']:.2f}, \"\n                  f\"Range=[{stats['min']:.2f}, {stats['max']:.2f}]\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T17:20:44.02304Z","iopub.execute_input":"2026-01-03T17:20:44.023652Z","iopub.status.idle":"2026-01-03T17:21:20.924811Z","shell.execute_reply.started":"2026-01-03T17:20:44.023623Z","shell.execute_reply":"2026-01-03T17:21:20.923881Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🔢 Step 7: Label Encoding for Categorical Variables","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 7: Label Encoding for Categorical Variables\n# ============================================================================\n\n# Create encoding visualization\nfig, axes = plt.subplots(2, 3, figsize=(16, 10))\ncategorical_cols = ['sequence_type', 'behavior', 'phase', 'orientation', 'gesture']\n\n# Select only columns that exist\ncategorical_cols = [col for col in categorical_cols if col in df_processed.columns]\n\nfor idx, col in enumerate(categorical_cols):\n    row, col_idx = divmod(idx, 3)\n    \n    # Get unique values and counts\n    value_counts = df_processed[col].value_counts()\n    \n    # For columns with many unique values, show top 10 only\n    if len(value_counts) > 10 and col == 'gesture':\n        value_counts = value_counts.head(10)\n        title_suffix = ' (Top 10)'\n    else:\n        title_suffix = ''\n    \n    # Create bar plot\n    bars = axes[row, col_idx].bar(range(len(value_counts)), value_counts.values, \n                                  color=plt.cm.Set3(np.arange(len(value_counts))/len(value_counts)))\n    axes[row, col_idx].set_title(f'{col}{title_suffix}', fontweight='bold')\n    axes[row, col_idx].set_xlabel(col)\n    axes[row, col_idx].set_ylabel('Count')\n    \n    # Rotate x-tick labels for better readability\n    axes[row, col_idx].set_xticks(range(len(value_counts)))\n    axes[row, col_idx].set_xticklabels(value_counts.index, rotation=45, ha='right')\n    \n    # Add count labels on bars\n    for bar, count in zip(bars, value_counts.values):\n        height = bar.get_height()\n        axes[row, col_idx].text(bar.get_x() + bar.get_width()/2, height + max(value_counts.values)*0.01,\n                               f'{count:,}', ha='center', va='bottom', fontsize=8)\n\n# Hide empty subplots if any\nfor idx in range(len(categorical_cols), 6):\n    row, col_idx = divmod(idx, 3)\n    axes[row, col_idx].set_visible(False)\n\nplt.tight_layout()\nplt.show()\n\n# Apply Label Encoding\nprint(\"🔄 Applying Label Encoding:\")\nlabel_encoders = {}\n\nfor col in categorical_cols:\n    if col != 'gesture':  # We'll encode gesture separately if needed\n        le = LabelEncoder()\n        df_processed[f'{col}_encoded'] = le.fit_transform(df_processed[col])\n        label_encoders[col] = le\n        print(f\"   ✅ {col} → {col}_encoded ({len(le.classes_)} unique values)\")\n\n# Show encoding mapping for sequence_type\nif 'sequence_type' in categorical_cols:\n    print(f\"\\n📋 Encoding mapping for sequence_type:\")\n    for class_name, encoded_value in zip(label_encoders['sequence_type'].classes_, \n                                         range(len(label_encoders['sequence_type'].classes_))):\n        print(f\"   {class_name} → {encoded_value}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T18:55:15.629749Z","iopub.execute_input":"2026-01-03T18:55:15.630203Z","iopub.status.idle":"2026-01-03T18:55:17.230368Z","shell.execute_reply.started":"2026-01-03T18:55:15.630171Z","shell.execute_reply":"2026-01-03T18:55:17.229415Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# ⚖️ Step 8: Feature Scaling/Normalization","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 8: Feature Scaling/Normalization\n# ============================================================================\n\n# Select numerical features for scaling (excluding encoded categoricals and identifiers)\nnumerical_features = df_processed.select_dtypes(include=[np.number]).columns.tolist()\n\n# Remove columns that shouldn't be scaled\nexclude_from_scaling = ['row_id', 'sequence_id', 'sequence_counter', \n                        'sequence_type_encoded', 'behavior_encoded', \n                        'phase_encoded', 'orientation_encoded']\nnumerical_features = [col for col in numerical_features if col not in exclude_from_scaling]\n\n# Limit to key features for demonstration (first 20)\nnumerical_features = numerical_features[:20]\n\nprint(f\"📊 Scaling {len(numerical_features)} numerical features\")\n\n# Create before/after scaling visualization\nfig, axes = plt.subplots(2, 2, figsize=(16, 12))\n\n# 1. Distribution before scaling (sample features)\nsample_features = numerical_features[:4]\nfor idx, feature in enumerate(sample_features):\n    axes[0, 0].hist(df_processed[feature].dropna(), bins=50, alpha=0.5, label=feature)\naxes[0, 0].set_title('Distribution Before Scaling', fontweight='bold')\naxes[0, 0].set_xlabel('Value')\naxes[0, 0].set_ylabel('Frequency')\naxes[0, 0].legend()\naxes[0, 0].grid(True, alpha=0.3)\n\n# 2. Box plot before scaling\nbox_data = [df_processed[feature].dropna() for feature in sample_features]\nbp = axes[0, 1].boxplot(box_data, labels=sample_features, patch_artist=True)\n# Set colors for box plots\ncolors = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4']\nfor patch, color in zip(bp['boxes'], colors):\n    patch.set_facecolor(color)\naxes[0, 1].set_title('Box Plot Before Scaling', fontweight='bold')\naxes[0, 1].set_ylabel('Value')\naxes[0, 1].tick_params(axis='x', rotation=45)\naxes[0, 1].grid(True, alpha=0.3)\n\n# Apply Standard Scaling\nfrom sklearn.preprocessing import StandardScaler\n\nscaler = StandardScaler()\nscaled_features = scaler.fit_transform(df_processed[numerical_features])\ndf_scaled = pd.DataFrame(scaled_features, columns=numerical_features)\n\n# 3. Distribution after scaling\nfor idx, feature in enumerate(sample_features):\n    axes[1, 0].hist(df_scaled[feature].dropna(), bins=50, alpha=0.5, label=feature)\naxes[1, 0].axvline(0, color='red', linestyle='--', alpha=0.7, label='Mean = 0')\naxes[1, 0].set_title('Distribution After Standard Scaling', fontweight='bold')\naxes[1, 0].set_xlabel('Scaled Value')\naxes[1, 0].set_ylabel('Frequency')\naxes[1, 0].legend()\naxes[1, 0].grid(True, alpha=0.3)\n\n# 4. Box plot after scaling\nscaled_box_data = [df_scaled[feature].dropna() for feature in sample_features]\nbp_scaled = axes[1, 1].boxplot(scaled_box_data, labels=sample_features, patch_artist=True)\nfor patch, color in zip(bp_scaled['boxes'], colors):\n    patch.set_facecolor(color)\naxes[1, 1].axhline(0, color='red', linestyle='--', alpha=0.7)\naxes[1, 1].set_title('Box Plot After Standard Scaling', fontweight='bold')\naxes[1, 1].set_ylabel('Scaled Value')\naxes[1, 1].tick_params(axis='x', rotation=45)\naxes[1, 1].grid(True, alpha=0.3)\n\nplt.tight_layout()\nplt.show()\n\nprint(\"✅ Standard Scaling applied successfully\")\nprint(f\"   Features scaled: Mean ≈ 0, Standard Deviation = 1\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T18:59:37.076277Z","iopub.execute_input":"2026-01-03T18:59:37.076635Z","iopub.status.idle":"2026-01-03T18:59:44.254502Z","shell.execute_reply.started":"2026-01-03T18:59:37.07661Z","shell.execute_reply":"2026-01-03T18:59:44.253608Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🤖 Step 9: Preparing Data for Machine Learning Model","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 9: Prepare Data for Modeling\n# ============================================================================\n\n# Define features and target\nprint(\"🎯 Defining features and target variable...\")\n\n# Use a subset of features for faster training and demonstration\nselected_features = [\n    # IMU features\n    'acc_x', 'acc_y', 'acc_z',\n    'rot_w', 'rot_x', 'rot_y', 'rot_z',\n    \n    # Thermopile features\n    'thm_1', 'thm_2', 'thm_3', 'thm_4',\n    \n    # Encoded categorical features\n    'behavior_encoded', 'phase_encoded', 'orientation_encoded'\n]\n\n# Add TOF features if they exist (first few pixels from first sensor)\ntof_features = [f'tof_1_v{i}' for i in range(5)]  # First 5 pixels\nselected_features.extend([f for f in tof_features if f in df_processed.columns])\n\n# Ensure all selected features exist\nselected_features = [f for f in selected_features if f in df_processed.columns]\n\n# Target variable\ntarget = 'sequence_type_encoded'\n\nprint(f\"📊 Selected {len(selected_features)} features for modeling\")\nprint(f\"🎯 Target variable: {target}\")\n\n# Create feature matrix X and target vector y\nX = df_processed[selected_features].copy()\ny = df_processed[target].copy()\n\n# Split the data\nprint(\"\\n🔀 Splitting data into training and testing sets...\")\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y\n)\n\nprint(f\"   Training set: {X_train.shape[0]:,} samples\")\nprint(f\"   Testing set: {X_test.shape[0]:,} samples\")\nprint(f\"   Feature count: {X_train.shape[1]}\")\n\n# Create split visualization\nfig, axes = plt.subplots(1, 2, figsize=(14, 5))\n\n# Class distribution in train and test sets\ntrain_counts = y_train.value_counts().sort_index()\ntest_counts = y_test.value_counts().sort_index()\n\nx = np.arange(len(train_counts))\nwidth = 0.35\n\naxes[0].bar(x - width/2, train_counts.values, width, label='Train', color='#4ECDC4')\naxes[0].bar(x + width/2, test_counts.values, width, label='Test', color='#FF6B6B')\n\naxes[0].set_xlabel('Class (0=Non-Target, 1=Target)')\naxes[0].set_ylabel('Count')\naxes[0].set_title('Class Distribution in Train/Test Split', fontweight='bold')\naxes[0].set_xticks(x)\naxes[0].set_xticklabels(train_counts.index)\naxes[0].legend()\naxes[0].grid(True, alpha=0.3)\n\n# Add count labels\nfor i, (train_count, test_count) in enumerate(zip(train_counts.values, test_counts.values)):\n    axes[0].text(i - width/2, train_count + max(train_counts.values)*0.01, \n                f'{train_count:,}', ha='center', va='bottom', fontsize=9)\n    axes[0].text(i + width/2, test_count + max(test_counts.values)*0.01, \n                f'{test_count:,}', ha='center', va='bottom', fontsize=9)\n\n# Feature correlation heatmap (sample of features)\nsample_features = selected_features[:10]  # First 10 features for clarity\ncorr_matrix = X_train[sample_features].corr()\n\nim = axes[1].imshow(corr_matrix, cmap='coolwarm', aspect='auto')\naxes[1].set_title('Feature Correlation Heatmap (Sample)', fontweight='bold')\naxes[1].set_xticks(range(len(sample_features)))\naxes[1].set_yticks(range(len(sample_features)))\naxes[1].set_xticklabels(sample_features, rotation=45, ha='right')\naxes[1].set_yticklabels(sample_features)\n\n# Add correlation values\nfor i in range(len(sample_features)):\n    for j in range(len(sample_features)):\n        text = axes[1].text(j, i, f'{corr_matrix.iloc[i, j]:.2f}',\n                           ha=\"center\", va=\"center\", color=\"white\" if abs(corr_matrix.iloc[i, j]) > 0.5 else \"black\")\n\nplt.colorbar(im, ax=axes[1])\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T19:00:39.25012Z","iopub.execute_input":"2026-01-03T19:00:39.250505Z","iopub.status.idle":"2026-01-03T19:00:40.663469Z","shell.execute_reply.started":"2026-01-03T19:00:39.250483Z","shell.execute_reply":"2026-01-03T19:00:40.662375Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🌳 Step 10: Training Random Forest Classifier","metadata":{}},{"cell_type":"code","source":"# ============================================================================\n# Step 10: Train and Evaluate Machine Learning Model\n# ============================================================================\n\nprint(\"🚀 Training Random Forest model...\")\n\n# Initialize and train the model\nmodel = RandomForestClassifier(\n    n_estimators=100,      # Number of trees\n    max_depth=10,          # Maximum depth of each tree\n    min_samples_split=20,  # Minimum samples to split a node\n    min_samples_leaf=10,   # Minimum samples in a leaf\n    random_state=42,       # For reproducibility\n    n_jobs=-1,             # Use all CPU cores\n    class_weight='balanced' # Handle class imbalance\n)\n\n# Train the model\nmodel.fit(X_train, y_train)\nprint(\"✅ Model training completed\")\n\n# Make predictions\nprint(\"\\n📈 Making predictions and evaluating model...\")\ny_pred = model.predict(X_test)\ny_pred_proba = model.predict_proba(X_test)[:, 1]\n\n# Calculate metrics\nf1 = f1_score(y_test, y_pred)\naccuracy = model.score(X_test, y_test)\n\nprint(f\"\\n🎯 Model Performance Metrics:\")\nprint(f\"   • F1-Score: {f1:.4f}\")\nprint(f\"   • Accuracy: {accuracy:.4f} ({accuracy*100:.2f}%)\")\nprint(f\"   • Training samples: {X_train.shape[0]:,}\")\nprint(f\"   • Testing samples: {X_test.shape[0]:,}\")\n\n# Create comprehensive evaluation visualization\nfig, axes = plt.subplots(2, 3, figsize=(18, 12))\n\n# 1. Confusion Matrix\ncm = confusion_matrix(y_test, y_pred)\nim = axes[0, 0].imshow(cm, interpolation='nearest', cmap=plt.cm.Blues)\naxes[0, 0].set_title('Confusion Matrix', fontweight='bold')\naxes[0, 0].set_ylabel('True Label')\naxes[0, 0].set_xlabel('Predicted Label')\naxes[0, 0].set_xticks([0, 1])\naxes[0, 0].set_yticks([0, 1])\naxes[0, 0].set_xticklabels(['Non-Target', 'Target'])\naxes[0, 0].set_yticklabels(['Non-Target', 'Target'])\n\n# Add text annotations\nthresh = cm.max() / 2.\nfor i in range(cm.shape[0]):\n    for j in range(cm.shape[1]):\n        axes[0, 0].text(j, i, f'{cm[i, j]:,}',\n                       ha=\"center\", va=\"center\",\n                       color=\"white\" if cm[i, j] > thresh else \"black\")\n\n# 2. Feature Importance\nfeature_importance = pd.DataFrame({\n    'Feature': selected_features,\n    'Importance': model.feature_importances_\n}).sort_values('Importance', ascending=False).head(10)\n\nbars = axes[0, 1].barh(range(len(feature_importance)), feature_importance['Importance'].values, color='#45B7D1')\naxes[0, 1].set_yticks(range(len(feature_importance)))\naxes[0, 1].set_yticklabels(feature_importance['Feature'].values)\naxes[0, 1].set_xlabel('Importance')\naxes[0, 1].set_title('Top 10 Feature Importances', fontweight='bold')\naxes[0, 1].invert_yaxis()\n\n# Add importance values\nfor bar, importance in zip(bars, feature_importance['Importance'].values):\n    axes[0, 1].text(bar.get_width() + 0.001, bar.get_y() + bar.get_height()/2,\n                   f'{importance:.3f}', va='center', fontsize=9)\n\n# 3. Probability Distribution\naxes[0, 2].hist(y_pred_proba[y_test == 0], bins=30, alpha=0.7, label='Non-Target', color='#FF6B6B')\naxes[0, 2].hist(y_pred_proba[y_test == 1], bins=30, alpha=0.7, label='Target', color='#4ECDC4')\naxes[0, 2].set_xlabel('Predicted Probability')\naxes[0, 2].set_ylabel('Count')\naxes[0, 2].set_title('Prediction Probability Distribution', fontweight='bold')\naxes[0, 2].legend()\naxes[0, 2].grid(True, alpha=0.3)\n\n# 4. Classification Report Heatmap\nreport = classification_report(y_test, y_pred, target_names=['Non-Target', 'Target'], output_dict=True)\nreport_df = pd.DataFrame(report).transpose()\nreport_metrics = report_df.drop(['accuracy', 'macro avg', 'weighted avg'], errors='ignore')\n\nim2 = axes[1, 0].imshow(report_metrics[['precision', 'recall', 'f1-score']].values.T, \n                       cmap='YlOrRd', aspect='auto', vmin=0, vmax=1)\naxes[1, 0].set_title('Classification Report', fontweight='bold')\naxes[1, 0].set_xticks(range(len(report_metrics)))\naxes[1, 0].set_yticks(range(3))\naxes[1, 0].set_xticklabels(report_metrics.index, rotation=45, ha='right')\naxes[1, 0].set_yticklabels(['Precision', 'Recall', 'F1-Score'])\n\n# Add metric values\nfor i in range(3):\n    for j in range(len(report_metrics)):\n        value = report_metrics.iloc[j, i]\n        axes[1, 0].text(j, i, f'{value:.2f}', ha=\"center\", va=\"center\", \n                       color=\"white\" if value < 0.5 else \"black\")\n\nplt.colorbar(im2, ax=axes[1, 0])\n\n# 5. ROC Curve\nfrom sklearn.metrics import roc_curve, auc\nfpr, tpr, _ = roc_curve(y_test, y_pred_proba)\nroc_auc = auc(fpr, tpr)\n\naxes[1, 1].plot(fpr, tpr, color='#FF6B6B', lw=2, label=f'ROC curve (AUC = {roc_auc:.2f})')\naxes[1, 1].plot([0, 1], [0, 1], color='navy', lw=2, linestyle='--', label='Random')\naxes[1, 1].set_xlim([0.0, 1.0])\naxes[1, 1].set_ylim([0.0, 1.05])\naxes[1, 1].set_xlabel('False Positive Rate')\naxes[1, 1].set_ylabel('True Positive Rate')\naxes[1, 1].set_title('Receiver Operating Characteristic', fontweight='bold')\naxes[1, 1].legend(loc=\"lower right\")\naxes[1, 1].grid(True, alpha=0.3)\n\n# 6. Model Performance Summary\nmetrics_summary = {\n    'F1-Score': f1,\n    'Accuracy': accuracy,\n    'Precision': report['Target']['precision'],\n    'Recall': report['Target']['recall'],\n    'AUC-ROC': roc_auc\n}\n\nbars_summary = axes[1, 2].bar(range(len(metrics_summary)), list(metrics_summary.values()), \n                             color=['#FF6B6B', '#4ECDC4', '#45B7D1', '#96CEB4', '#FFEAA7'])\naxes[1, 2].set_xticks(range(len(metrics_summary)))\naxes[1, 2].set_xticklabels(list(metrics_summary.keys()), rotation=45, ha='right')\naxes[1, 2].set_ylabel('Score')\naxes[1, 2].set_title('Model Performance Summary', fontweight='bold')\naxes[1, 2].set_ylim([0, 1])\naxes[1, 2].grid(True, alpha=0.3, axis='y')\n\n# Add score values\nfor bar, (metric, value) in zip(bars_summary, metrics_summary.items()):\n    axes[1, 2].text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.02,\n                   f'{value:.3f}', ha='center', va='bottom', fontweight='bold')\n\nplt.tight_layout()\nplt.show()\n\nprint(\"\\n\" + \"=\"*60)\nprint(\"✅ PROJECT COMPLETED SUCCESSFULLY!\")\nprint(\"=\"*60)\nprint(f\"🎯 Final Model Performance: F1-Score = {f1:.4f}\")\nprint(f\"📊 Total Steps Completed: 10\")\nprint(f\"💾 Processed Samples: {len(df_processed):,}\")\nprint(f\"🔧 Features Used: {len(selected_features)}\")\nprint(\"=\"*60)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-03T19:01:33.710539Z","iopub.execute_input":"2026-01-03T19:01:33.711202Z","iopub.status.idle":"2026-01-03T19:02:42.140249Z","shell.execute_reply.started":"2026-01-03T19:01:33.711124Z","shell.execute_reply":"2026-01-03T19:02:42.139219Z"},"jupyter":{"source_hidden":true,"outputs_hidden":true},"collapsed":true},"outputs":[],"execution_count":null}]}