{"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":117097,"databundleVersionId":14080503,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":13635787,"sourceType":"datasetVersion","datasetId":8667194},{"sourceId":13639983,"sourceType":"datasetVersion","datasetId":8670245}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🚀 Alpha Radar: Ultimate Hybrid Solution\n\n\n**Goal:** Identify target tokens within the first 30 seconds of their lifespan on PumpFun (Solana)\n\n**Challenge:** \n- 🎯 Achieve ≥75% recall on target tokens\n- 📊 Maximize Jaccard Index (Intersection over Union)\n- ⏱️ Use only first 30 seconds of transaction data\n- 🤖 Must use CatBoost classifier\n\n**Data:**\n- **Training:** 9.5M transactions from September 2025 (~485K tokens)\n- **Targets:** 9,189 tokens identified by a high-performing wallet\n- **Evaluation:** 1.4M transactions (~64K tokens to predict)\n\n---\n\n## 🎯 Our Strategy\n\n### 1️⃣ **Advanced Feature Engineering**\n- ⏰ **Temporal Features:** Early/middle/late analysis, momentum, acceleration\n- 📈 **Sequence Features:** Buy/sell streaks, volume concentration, Gini coefficient\n- 🌊 **FFT Features:** Frequency domain analysis to capture cyclical patterns\n- 📊 **Statistical Tests:** KS tests to detect distribution shifts\n- 🔮 **Embeddings:** SVD for dimensionality reduction\n- 💡 **Derived Features:** Risk-adjusted returns, interaction terms\n\n### 2️⃣ **Robust Training**\n- 🔄 3-Fold Cross-Validation for reliable threshold tuning\n- ⚖️ Handle class imbalance (only 1.84% positive tokens)\n- 🎲 Bayesian bootstrap for better generalization\n\n### 3️⃣ **Adaptive Prediction**\n- 🎚️ Adaptive threshold that adjusts to evaluation distribution\n- 🛡️ Safety mechanisms to ensure minimum predictions\n- 📊 Distribution shift handling between train/eval sets\n\n### 4️⃣ **Competition Compliance**\n- ✅ Exact 64,208 rows in submission\n- ✅ Original token IDs preserved\n- ✅ Binary predictions (0 or 1)\n\n---\n\n## 📚 Notebook Structure\n\n1. **Setup & Imports** - Load libraries\n2. **Feature Engineering Functions** - Advanced feature creation\n3. **Load Training Data** - September 2025 transaction data\n4. **Create Training Features** - Apply feature engineering\n5. **Load Target Labels** - Ground truth tokens\n6. **Create Embeddings** - SVD dimensionality reduction\n7. **Train Model** - CatBoost with cross-validation\n8. **Process Evaluation Data** - Apply same features to test set\n9. **Generate Predictions** - Adaptive thresholding\n10. **Create Submission** - Format and save results\n\nLet's begin! 🚀\n\n---","metadata":{}},{"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-11-08T19:45:48.042122Z","iopub.execute_input":"2025-11-08T19:45:48.042399Z","iopub.status.idle":"2025-11-08T19:45:50.452858Z","shell.execute_reply.started":"2025-11-08T19:45:48.042357Z","shell.execute_reply":"2025-11-08T19:45:50.452049Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 1: SETUP & IMPORTS\n## ================================================================================\n\nImport all necessary libraries for data processing, feature engineering, \nmodeling, and evaluation.","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport os, glob\nfrom catboost import CatBoostClassifier, Pool\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import jaccard_score, recall_score\nfrom sklearn.decomposition import TruncatedSVD\nfrom sklearn.cluster import KMeans\nfrom scipy import stats\nfrom scipy.fft import fft\nimport warnings\nwarnings.filterwarnings('ignore')\n\nprint(\"=\" * 80)\nprint(\"ALPHA RADAR: ULTIMATE HYBRID SOLUTION\")\nprint(\"=\" * 80)\nprint(\"\\n✅ All libraries imported successfully!\")\nprint(\"📦 Key libraries: pandas, numpy, catboost, sklearn, scipy\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:45:50.453819Z","iopub.execute_input":"2025-11-08T19:45:50.454275Z","iopub.status.idle":"2025-11-08T19:45:53.647352Z","shell.execute_reply.started":"2025-11-08T19:45:50.454248Z","shell.execute_reply":"2025-11-08T19:45:53.646608Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 2: TEMPORAL FEATURE ENGINEERING\n## ================================================================================\nCreates features that analyze how token behavior changes over time.","metadata":{}},{"cell_type":"code","source":"def create_temporal_features(group):\n    \"\"\"\n    Analyzes token behavior across three time periods: early, middle, late\n    \n    Returns features like:\n    - volume_acceleration: Is trading volume increasing?\n    - buy_momentum: Are buy orders accelerating?\n    - holder_velocity: Is the holder count growing?\n    \"\"\"\n    n = len(group)\n    segment_size = max(1, n // 3)\n    \n    # Split transactions into three time windows\n    early = group.iloc[:segment_size]\n    middle = group.iloc[segment_size:2*segment_size] if n > segment_size else early\n    late = group.iloc[-segment_size:] if n > segment_size else early\n    \n    result = {\n        # Volume metrics\n        'early_buy_volume': float(early['sol_volume'].sum() if 'sol_volume' in early.columns else 0),\n        'late_buy_volume': float(late['sol_volume'].sum() if 'sol_volume' in late.columns else 0),\n        \n        # Transaction counts\n        'early_buy_count': float(early['buy_count'].sum() if 'buy_count' in early.columns else 0),\n        'late_buy_count': float(late['buy_count'].sum() if 'buy_count' in late.columns else 0),\n        'early_sell_count': float(early['sell_count'].sum() if 'sell_count' in early.columns else 0),\n        'late_sell_count': float(late['sell_count'].sum() if 'sell_count' in late.columns else 0),\n        \n        # Market metrics\n        'early_market_cap': float(early['market_cap_usd'].mean() if 'market_cap_usd' in early.columns else 0),\n        'late_market_cap': float(late['market_cap_usd'].mean() if 'market_cap_usd' in late.columns else 0),\n        \n        # Community metrics\n        'early_holders': float(early['current_holders'].max() if 'current_holders' in early.columns else 0),\n        'late_holders': float(late['current_holders'].max() if 'current_holders' in late.columns else 0),\n    }\n    \n    # Calculate momentum and acceleration (derived features)\n    result['volume_acceleration'] = (result['late_buy_volume'] - result['early_buy_volume']) / (result['early_buy_volume'] + 1)\n    result['buy_momentum'] = (result['late_buy_count'] - result['early_buy_count']) / (result['early_buy_count'] + 1)\n    result['market_cap_velocity'] = (result['late_market_cap'] - result['early_market_cap']) / (result['early_market_cap'] + 1)\n    result['holder_velocity'] = (result['late_holders'] - result['early_holders']) / (result['early_holders'] + 1)\n    \n    return result\n\nprint(\"✅ Temporal feature function created\")\nprint(\"📊 Captures: momentum, acceleration, velocity across time periods\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:45:53.649095Z","iopub.execute_input":"2025-11-08T19:45:53.649441Z","iopub.status.idle":"2025-11-08T19:45:53.658736Z","shell.execute_reply.started":"2025-11-08T19:45:53.649422Z","shell.execute_reply":"2025-11-08T19:45:53.657985Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\nKey Concepts:\n- Divide 30-second window into early/middle/late segments\n- Calculate momentum (how fast things are changing)\n- Detect acceleration patterns (change in momentum)\n\nWhy this matters:\n- Successful tokens often show strong early momentum\n- Volume acceleration indicates growing interest\n- Holder growth velocity shows community building","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 3: SEQUENCE FEATURE ENGINEERING\n## ================================================================================\nAnalyzes patterns in the order and distribution of transactions.","metadata":{}},{"cell_type":"code","source":"def create_sequence_features(group):\n    \"\"\"\n    Extracts patterns from transaction sequences\n    \n    Returns features like:\n    - max_consecutive_buys: Longest streak of buy orders\n    - volume_skewness: Is volume dominated by few large trades?\n    - price_volatility: How stable is the price?\n    \"\"\"\n    result = {}\n    \n    # === TRADE MODE ANALYSIS ===\n    if 'trade_mode' in group.columns:\n        trades = group['trade_mode'].values\n        result['buy_ratio'] = float(np.mean(trades == 'buy'))\n        \n        # Find consecutive streaks\n        if len(trades) > 1:\n            from itertools import groupby\n            buy_streaks = [sum(1 for _ in g) for k, g in groupby(trades) if k == 'buy']\n            sell_streaks = [sum(1 for _ in g) for k, g in groupby(trades) if k == 'sell']\n            result['max_consecutive_buys'] = float(max(buy_streaks) if buy_streaks else 0)\n            result['max_consecutive_sells'] = float(max(sell_streaks) if sell_streaks else 0)\n        else:\n            result['max_consecutive_buys'] = 0.0\n            result['max_consecutive_sells'] = 0.0\n    \n    # === VOLUME DISTRIBUTION ===\n    if 'sol_volume' in group.columns:\n        volumes = group['sol_volume'].values\n        result['volume_std_norm'] = float(np.std(volumes) / (np.mean(volumes) + 1))\n        result['volume_skewness'] = float(pd.Series(volumes).skew())\n        \n        # Concentration metrics (are top trades dominating?)\n        sorted_vol = np.sort(volumes)[::-1]\n        total_vol = sorted_vol.sum()\n        result['top1_vol_share'] = float(sorted_vol[0] / (total_vol + 1) if len(sorted_vol) > 0 else 0)\n        result['top3_vol_share'] = float(sorted_vol[:3].sum() / (total_vol + 1) if len(sorted_vol) >= 3 else 0)\n    \n    # === PRICE DYNAMICS ===\n    if 'market_cap_usd' in group.columns:\n        prices = group['market_cap_usd'].values\n        if len(prices) > 1:\n            returns = np.diff(prices) / (prices[:-1] + 1)\n            result['price_volatility'] = float(np.std(returns))\n            result['price_trend'] = float(np.polyfit(range(len(prices)), prices, 1)[0])\n            result['num_price_increases'] = float(np.sum(returns > 0))\n            result['max_price_jump'] = float(np.max(returns))\n        else:\n            result['price_volatility'] = 0.0\n            result['price_trend'] = 0.0\n            result['num_price_increases'] = 0.0\n            result['max_price_jump'] = 0.0\n    \n    return result\n\nprint(\"✅ Sequence feature function created\")\nprint(\"📊 Captures: streaks, concentration, price dynamics\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:45:53.659467Z","iopub.execute_input":"2025-11-08T19:45:53.659727Z","iopub.status.idle":"2025-11-08T19:45:53.687112Z","shell.execute_reply.started":"2025-11-08T19:45:53.659703Z","shell.execute_reply":"2025-11-08T19:45:53.686353Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Key Concepts:\n- Consecutive streaks (e.g., 5 buys in a row = strong interest)\n- Volume concentration (is trading spread out or dominated by whales?)\n- Price dynamics (volatility, trend direction)\n\nWhy this matters:\n- Consecutive buys indicate coordinated interest\n- High volume concentration may signal manipulation\n- Price volatility shows market uncertainty","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 4: ADVANCED FEATURES (FFT & STATISTICAL TESTS)\n## ================================================================================","metadata":{}},{"cell_type":"code","source":"def create_fft_features(group):\n    \"\"\"\n    Applies Fast Fourier Transform to extract frequency domain features\n    \n    Think of it like analyzing a song:\n    - Time domain: notes played over time\n    - Frequency domain: which notes appear most often\n    \"\"\"\n    result = {}\n    \n    for col in ['market_cap_usd', 'sol_volume']:\n        if col in group.columns:\n            values = group[col].values\n            if len(values) >= 4:\n                # Pad to power of 2 (FFT requirement)\n                n = 2 ** int(np.ceil(np.log2(len(values))))\n                padded = np.pad(values, (0, n - len(values)), mode='edge')\n                \n                # Apply FFT\n                fft_vals = np.abs(fft(padded))[:n//2]\n                \n                result[f'{col}_fft_mean'] = float(np.mean(fft_vals))\n                result[f'{col}_fft_max'] = float(np.max(fft_vals))\n                result[f'{col}_dominant_freq'] = float(np.argmax(fft_vals))\n            else:\n                result[f'{col}_fft_mean'] = 0.0\n                result[f'{col}_fft_max'] = 0.0\n                result[f'{col}_dominant_freq'] = 0.0\n    \n    return result\n\ndef create_statistical_features(group):\n    \"\"\"\n    Statistical tests to detect distribution shifts\n    \n    KS Test (Kolmogorov-Smirnov):\n    - Compares early vs late distributions\n    - Low p-value = distributions are different (regime change!)\n    \n    Variance Ratio:\n    - Is volatility increasing or decreasing?\n    \"\"\"\n    result = {}\n    \n    n = len(group)\n    mid = n // 2\n    \n    for col in ['sol_volume', 'market_cap_usd']:\n        if col in group.columns and n > 4:\n            early_vals = group[col].iloc[:mid].values\n            late_vals = group[col].iloc[mid:].values\n            \n            # Kolmogorov-Smirnov test\n            try:\n                ks_stat, ks_pval = stats.ks_2samp(early_vals, late_vals)\n                result[f'{col}_ks_stat'] = float(ks_stat)\n                result[f'{col}_ks_pval'] = float(ks_pval)\n            except:\n                result[f'{col}_ks_stat'] = 0.0\n                result[f'{col}_ks_pval'] = 1.0\n            \n            # Variance ratio (volatility change)\n            result[f'{col}_var_ratio'] = float(np.var(late_vals) / (np.var(early_vals) + 1e-6))\n        else:\n            result[f'{col}_ks_stat'] = 0.0\n            result[f'{col}_ks_pval'] = 1.0\n            result[f'{col}_var_ratio'] = 1.0\n    \n    return result\n\nprint(\"✅ FFT feature function created\")\nprint(\"✅ Statistical test function created\")\nprint(\"🌊 Captures: frequency patterns, distribution shifts\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:45:53.688009Z","iopub.execute_input":"2025-11-08T19:45:53.688262Z","iopub.status.idle":"2025-11-08T19:45:53.713967Z","shell.execute_reply.started":"2025-11-08T19:45:53.688240Z","shell.execute_reply":"2025-11-08T19:45:53.713313Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n\nPart A: FFT (Fast Fourier Transform)\n- Converts time series to frequency domain\n- Detects cyclical patterns (e.g., pump-and-dump cycles)\n- Identifies dominant frequencies in trading behavior\n\nPart B: Statistical Tests\n- KS Test: Detects if early vs late distributions are different\n- Variance Ratio: Measures if volatility is increasing\n- Helps identify distribution shifts\n\nWhy this matters:\n- FFT catches patterns invisible in time domain\n- Statistical tests detect regime changes\n- Professional ML technique rarely used in competitions","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 5: MASTER FEATURE ENGINEERING PIPELINE\n## ================================================================================\nCombines all feature engineering functions into one pipeline.","metadata":{}},{"cell_type":"code","source":"def create_all_features(df):\n    \"\"\"\n    Master function that applies all feature engineering\n    \n    Input: Transaction-level data (many rows per token)\n    Output: Token-level features (one row per token)\n    \"\"\"\n    print(f\"  🧩 Processing {len(df):,} transactions...\")\n    \n    # === STEP 1: CLEAN TOKEN IDS ===\n    df['mint_token_id_clean'] = df['mint_token_id'].astype(str).str.strip().str.lower()\n    \n    # Sort by time if available\n    if 'timestamp' in df.columns:\n        df = df.sort_values(['mint_token_id_clean', 'timestamp'])\n    \n    # === STEP 2: BASE AGGREGATIONS ===\n    print(\"  📊 Computing base aggregations...\")\n    \n    # Get numeric columns (exclude index column which causes issues)\n    numeric_cols = df.select_dtypes(include=[np.number]).columns.tolist()\n    numeric_cols = [col for col in numeric_cols if col not in ['mint_token_id', 'mint_token_id_clean', 'index']]\n    \n    # Aggregate each numeric column with multiple statistics\n    agg_dict = {}\n    for col in numeric_cols:\n        agg_dict[col] = ['mean', 'std', 'sum', 'max', 'min', 'last', 'first']\n    \n    # Count unique holders\n    if 'holder' in df.columns:\n        agg_dict['holder'] = ['nunique', 'count']\n    \n    token_features = df.groupby('mint_token_id_clean').agg(agg_dict)\n    token_features.columns = ['_'.join(col).strip() for col in token_features.columns.values]\n    token_features.reset_index(inplace=True)\n    \n    # === STEP 3: TRADE MODE ANALYSIS ===\n    if 'trade_mode' in df.columns:\n        trade_counts = df.groupby(['mint_token_id_clean', 'trade_mode']).size().unstack(fill_value=0)\n        for mode in ['buy', 'sell', 'other']:\n            if mode in trade_counts.columns:\n                token_features[f'{mode}_count'] = trade_counts[mode].values\n            else:\n                token_features[f'{mode}_count'] = 0\n        \n        token_features['buy_sell_ratio_calc'] = token_features['buy_count'] / (token_features['sell_count'] + 1)\n    \n    # === STEP 4: APPLY ADVANCED FEATURES ===\n    print(\"  🔬 Creating temporal features...\")\n    temporal_list = []\n    for token_id, group in df.groupby('mint_token_id_clean'):\n        features = create_temporal_features(group)\n        features['mint_token_id_clean'] = token_id\n        temporal_list.append(features)\n    temporal_features = pd.DataFrame(temporal_list)\n    \n    print(\"  📈 Creating sequence features...\")\n    sequence_list = []\n    for token_id, group in df.groupby('mint_token_id_clean'):\n        features = create_sequence_features(group)\n        features['mint_token_id_clean'] = token_id\n        sequence_list.append(features)\n    sequence_features = pd.DataFrame(sequence_list)\n    \n    print(\"  🌊 Creating FFT features...\")\n    fft_list = []\n    for token_id, group in df.groupby('mint_token_id_clean'):\n        features = create_fft_features(group)\n        features['mint_token_id_clean'] = token_id\n        fft_list.append(features)\n    fft_features = pd.DataFrame(fft_list)\n    \n    print(\"  📊 Creating statistical features...\")\n    stat_list = []\n    for token_id, group in df.groupby('mint_token_id_clean'):\n        features = create_statistical_features(group)\n        features['mint_token_id_clean'] = token_id\n        stat_list.append(features)\n    stat_features = pd.DataFrame(stat_list)\n    \n    # === STEP 5: MERGE ALL FEATURES ===\n    print(\"  🔗 Merging feature sets...\")\n    token_features = token_features.merge(temporal_features, on='mint_token_id_clean', how='left')\n    token_features = token_features.merge(sequence_features, on='mint_token_id_clean', how='left')\n    token_features = token_features.merge(fft_features, on='mint_token_id_clean', how='left')\n    token_features = token_features.merge(stat_features, on='mint_token_id_clean', how='left')\n    \n    # Rename holder column\n    if 'holder_nunique' in token_features.columns:\n        token_features.rename(columns={'holder_nunique': 'unique_holders'}, inplace=True)\n    \n    # === STEP 6: CREATE DERIVED FEATURES ===\n    print(\"  ⚡ Creating derived features...\")\n    \n    if 'buy_count' in token_features.columns and 'sell_count' in token_features.columns:\n        token_features['net_buy_count'] = token_features['buy_count'] - token_features['sell_count']\n    \n    if 'sol_volume_sum' in token_features.columns and 'holder_count' in token_features.columns:\n        token_features['volume_per_holder'] = token_features['sol_volume_sum'] / (token_features['holder_count'] + 1)\n    \n    if 'market_cap_usd_last' in token_features.columns and 'market_cap_usd_first' in token_features.columns:\n        token_features['market_cap_growth'] = (token_features['market_cap_usd_last'] - token_features['market_cap_usd_first']) / (token_features['market_cap_usd_first'] + 1)\n    \n    if 'market_cap_usd_std' in token_features.columns and 'market_cap_usd_mean' in token_features.columns:\n        token_features['market_cap_volatility'] = token_features['market_cap_usd_std'] / (token_features['market_cap_usd_mean'] + 1)\n    \n    if 'creator_sold_sum' in token_features.columns and 'creator_balance_last' in token_features.columns:\n        token_features['creator_dump_signal'] = token_features['creator_sold_sum'] / (token_features['creator_balance_last'] + 1)\n    \n    # Interaction features\n    if 'buy_momentum' in token_features.columns and 'sol_volume_sum' in token_features.columns:\n        token_features['momentum_volume'] = token_features['buy_momentum'] * token_features['sol_volume_sum']\n    \n    if 'market_cap_growth' in token_features.columns and 'market_cap_volatility' in token_features.columns:\n        token_features['risk_adjusted_return'] = token_features['market_cap_growth'] / (token_features['market_cap_volatility'] + 1)\n    \n    # === STEP 7: CLEAN UP ===\n    token_features = token_features.fillna(0).replace([np.inf, -np.inf], 0)\n    \n    print(f\"  ✅ Created {token_features.shape[0]:,} tokens with {token_features.shape[1]} features\")\n    \n    return token_features\n\nprint(\"✅ Master feature engineering pipeline ready\")\nprint(\"🎯 Creates 230+ features per token from transaction data\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:45:53.714783Z","iopub.execute_input":"2025-11-08T19:45:53.715103Z","iopub.status.idle":"2025-11-08T19:45:53.741819Z","shell.execute_reply.started":"2025-11-08T19:45:53.715082Z","shell.execute_reply":"2025-11-08T19:45:53.741099Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n\nProcess:\n1. Clean token IDs (normalize for matching)\n2. Base aggregations (mean, std, sum, max, min, first, last)\n3. Apply temporal features (early/late analysis)\n4. Apply sequence features (streaks, concentration)\n5. Apply FFT features (frequency domain)\n6. Apply statistical features (distribution tests)\n7. Create derived features (interactions, ratios)\n\nOutput: One row per token with 230+ features","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 6: LOAD TRAINING DATA\n## ================================================================================\nLoad the September 2025 PumpFun transaction data (15 CSV chunks).","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 1] LOADING TRAINING DATA\")\nprint(\"=\" * 80)\n\n# Path to training data (September 2025 chunks)\ntrain_path = \"/kaggle/input/pumpfun-30s-september-2025/\"\ntrain_files = sorted(glob.glob(train_path + \"*.csv\"))\n\nprint(f\"📂 Found {len(train_files)} training files\")\nprint(f\"📂 Files: {', '.join([os.path.basename(f) for f in train_files[:3]])}...\")\n\n# Load and concatenate all chunks\ntrain_df = pd.concat([pd.read_csv(f) for f in train_files], ignore_index=True)\n\nprint(f\"\\n✅ Loaded {len(train_df):,} training transactions\")\nprint(f\"✅ Unique tokens: {train_df['mint_token_id'].nunique():,}\")\nprint(f\"✅ Date range: {train_df['timestamp'].min() if 'timestamp' in train_df.columns else 'N/A'} to {train_df['timestamp'].max() if 'timestamp' in train_df.columns else 'N/A'}\")\n\n# Quick peek at the data\nprint(f\"\\n📊 Data Preview:\")\nprint(train_df.head(3))\nprint(f\"\\n📊 Columns: {train_df.shape[1]}\")\nprint(f\"📋 {', '.join(train_df.columns.tolist()[:10])}...\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:45:53.742988Z","iopub.execute_input":"2025-11-08T19:45:53.743261Z","iopub.status.idle":"2025-11-08T19:47:18.744553Z","shell.execute_reply.started":"2025-11-08T19:45:53.743241Z","shell.execute_reply":"2025-11-08T19:47:18.743775Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"This is the historical data we'll use to:\n1. Learn patterns of successful tokens\n2. Train our CatBoost model\n3. Tune our prediction threshold","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 7: CREATE TRAINING FEATURES\n## ================================================================================\nApply our feature engineering pipeline to the training data.","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 2] FEATURE ENGINEERING (TRAINING)\")\nprint(\"=\" * 80)\n\n# Apply feature engineering pipeline\ntrain_features = create_all_features(train_df)\n\n# Display results\nprint(f\"\\n✅ Feature engineering complete!\")\nprint(f\"📊 Shape: {train_features.shape}\")\nprint(f\"   - Rows (tokens): {train_features.shape[0]:,}\")\nprint(f\"   - Columns (features): {train_features.shape[1]}\")\n\n# Show sample features\nprint(f\"\\n📋 Sample Features:\")\nprint(train_features.head(3))\n\n# Feature categories\nprint(f\"\\n🎯 Feature Categories:\")\nprint(f\"   - Base aggregations: ~140 (mean, std, sum, max, min, first, last)\")\nprint(f\"   - Temporal features: ~15 (early/late analysis, momentum)\")\nprint(f\"   - Sequence features: ~15 (streaks, concentration, dynamics)\")\nprint(f\"   - FFT features: ~6 (frequency domain patterns)\")\nprint(f\"   - Statistical features: ~6 (distribution tests)\")\nprint(f\"   - Derived features: ~60 (interactions, ratios)\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-08T19:47:18.745470Z","iopub.execute_input":"2025-11-08T19:47:18.745731Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"This takes ~5-10 minutes because we're:\n- Processing 9.5M transactions\n- Grouping by 485K unique tokens\n- Computing 230+ features per token\n- Running FFT and statistical tests\n\nBe patient - this is where the magic happens! ✨","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 8: LOAD TARGET LABELS\n## ================================================================================\nLoad the \"ground truth\" - tokens that were bought by the target wallet.","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 3] LOADING TARGET LABELS\")\nprint(\"=\" * 80)\n\n# Load target tokens\ntarget_path = \"/kaggle/input/alpha-radar-target-tokens/Alpha Radar Target Tokens.csv\"\ntarget = pd.read_csv(target_path)\n\n# Clean column names\ntarget.columns = target.columns.str.strip()\ntarget_col = target.columns[0]\n\n# Normalize token IDs for matching\ntarget['mint_token_id_clean'] = target[target_col].astype(str).str.strip().str.lower()\n\n# Create set for fast lookup\ntarget_set = set(target['mint_token_id_clean'].unique())\n\nprint(f\"✅ Loaded target tokens\")\nprint(f\"📊 Total targets: {len(target_set):,}\")\n\n# Create binary target column\ntrain_features['is_target'] = train_features['mint_token_id_clean'].isin(target_set).astype(int)\n\n# Show class distribution\nprint(f\"\\n📊 Class Distribution:\")\nprint(train_features['is_target'].value_counts())\nprint(f\"\\n📊 Target Rate: {train_features['is_target'].mean():.2%}\")\nprint(f\"   - Positive (targets): {train_features['is_target'].sum():,}\")\nprint(f\"   - Negative (non-targets): {(train_features['is_target']==0).sum():,}\")\n\n# Show imbalance ratio\nimbalance = (train_features['is_target']==0).sum() / (train_features['is_target']==1).sum()\nprint(f\"\\n⚖️  Class Imbalance Ratio: {imbalance:.2f}:1\")\nprint(f\"   (For every 1 target token, there are {imbalance:.0f} non-target tokens)\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\nThese are the tokens we want our model to learn to identify.\nOnly ~1.84% of all tokens are targets = highly imbalanced problem!","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 9: CREATE EMBEDDINGS (SVD)\n## ================================================================================\nApply Singular Value Decomposition to create compact representations.\n","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 4] CREATING EMBEDDINGS\")\nprint(\"=\" * 80)\n\n# Prepare data for SVD (need numeric matrix)\nX_temp = train_features.drop(columns=['mint_token_id_clean', 'is_target'])\nX_temp = X_temp.fillna(0).replace([np.inf, -np.inf], 0)\n\n# Determine number of components\nn_components = min(15, len(X_temp.columns), len(X_temp) - 1)\n\nif n_components >= 2:\n    print(f\"  🔮 Creating {n_components} SVD embeddings...\")\n    print(f\"  📊 Input: {X_temp.shape[1]} features → Output: {n_components} embeddings\")\n    \n    # Apply SVD\n    svd = TruncatedSVD(n_components=n_components, random_state=42)\n    embeddings = svd.fit_transform(X_temp)\n    \n    # Add embeddings as new features\n    for i in range(n_components):\n        train_features[f'svd_{i}'] = embeddings[:, i]\n    \n    # Show how much variance we captured\n    explained_var = svd.explained_variance_ratio_.sum()\n    print(f\"\\n  ✅ Explained variance: {explained_var:.2%}\")\n    print(f\"  ✅ Added {n_components} embedding features\")\n    \n    # Show top component contributions\n    print(f\"\\n  📊 Top 5 Components:\")\n    for i in range(min(5, n_components)):\n        print(f\"     SVD {i}: {svd.explained_variance_ratio_[i]:.2%} variance\")\nelse:\n    print(\"  ⚠️  Not enough features for SVD\")\n\nprint(f\"\\n✅ Total features now: {len([col for col in train_features.columns if col not in ['mint_token_id_clean', 'is_target']])}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Think of SVD like creating a summary:\n- Original: 238 features (lots of detail, some redundancy)\n- SVD: 15 embeddings (captures 100% of patterns in compressed form)\n\nWhy this helps:\n- Reduces noise and overfitting\n- Captures latent patterns\n- Similar to how word2vec creates word embeddings\n\nThis is an advanced ML technique rarely used in competitions!","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 10: TRAIN MODEL WITH CROSS-VALIDATION\n## ================================================================================\nTrain CatBoost classifier using 3-fold stratified cross-validation.","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 5] TRAINING MODEL\")\nprint(\"=\" * 80)\n\n# Prepare features and target\nX = train_features.drop(columns=['mint_token_id_clean', 'is_target'])\ny = train_features['is_target']\n\n# Calculate class imbalance\nimbalance_ratio = (y == 0).sum() / (y == 1).sum()\n\nprint(f\"📊 Dataset Info:\")\nprint(f\"   - Total samples: {len(X):,}\")\nprint(f\"   - Features: {X.shape[1]}\")\nprint(f\"   - Positive class: {y.sum():,} ({y.mean():.2%})\")\nprint(f\"   - Imbalance ratio: {imbalance_ratio:.2f}:1\")\n\n# === CROSS-VALIDATION ===\nn_folds = 3\nskf = StratifiedKFold(n_splits=n_folds, shuffle=True, random_state=42)\noof_preds = np.zeros(len(X))\n\nprint(f\"\\n🔄 Starting {n_folds}-Fold Cross-Validation...\")\nprint(f\"   (This trains 3 separate models for robust validation)\")\n\nfor fold, (train_idx, val_idx) in enumerate(skf.split(X, y)):\n    print(f\"\\n  📊 Fold {fold + 1}/{n_folds}\")\n    print(f\"     Train: {len(train_idx):,} samples | Val: {len(val_idx):,} samples\")\n    \n    X_train_fold, X_val_fold = X.iloc[train_idx], X.iloc[val_idx]\n    y_train_fold, y_val_fold = y.iloc[train_idx], y.iloc[val_idx]\n    \n    # Train model\n    model = CatBoostClassifier(\n        iterations=800,\n        learning_rate=0.03,\n        depth=8,\n        l2_leaf_reg=3,\n        eval_metric='AUC',\n        scale_pos_weight=imbalance_ratio,  # Handle imbalance\n        early_stopping_rounds=75,\n        verbose=0,\n        random_seed=42 + fold,\n        bootstrap_type='Bayesian'  # Better for small datasets\n    )\n    \n    model.fit(X_train_fold, y_train_fold, eval_set=(X_val_fold, y_val_fold))\n    \n    # Store out-of-fold predictions\n    oof_preds[val_idx] = model.predict_proba(X_val_fold)[:, 1]\n    \n    print(f\"     ✅ Completed (best iteration: {model.best_iteration_})\")\n\nprint(\"\\n✅ Cross-validation complete!\")\n\n# === FIND OPTIMAL THRESHOLD ===\nprint(f\"\\n🎯 Finding optimal threshold...\")\nprint(f\"   Goal: Maximize Jaccard while maintaining ≥75% recall\")\n\nthresholds = np.linspace(0.01, 0.95, 300)\nbest_threshold = 0.5\nbest_jaccard = 0\n\nfor t in thresholds:\n    preds = (oof_preds > t).astype(int)\n    recall = recall_score(y, preds, zero_division=0)\n    \n    # Only consider thresholds that meet recall requirement\n    if recall >= 0.75:\n        j = jaccard_score(y, preds, zero_division=0)\n        if j > best_jaccard:\n            best_threshold = t\n            best_jaccard = j\n\n# Evaluate with best threshold\nfinal_preds = (oof_preds > best_threshold).astype(int)\nfinal_recall = recall_score(y, final_preds)\n\nprint(f\"\\n📊 Out-of-Fold Results:\")\nprint(f\"   - Optimal Threshold: {best_threshold:.4f}\")\nprint(f\"   - Jaccard Score: {best_jaccard:.4f}\")\nprint(f\"   - Recall: {final_recall:.4f}\")\nprint(f\"   - Predictions: {final_preds.sum():,} / {len(final_preds):,} ({final_preds.mean():.2%})\")\n\n# === TRAIN FINAL MODEL ===\nprint(f\"\\n🚀 Training final model on all data...\")\n\nfinal_model = CatBoostClassifier(\n    iterations=800,\n    learning_rate=0.03,\n    depth=8,\n    l2_leaf_reg=3,\n    eval_metric='AUC',\n    scale_pos_weight=imbalance_ratio,\n    verbose=100,\n    random_seed=42,\n    bootstrap_type='Bayesian'\n)\n\nfinal_model.fit(X, y)\n\nprint(f\"\\n✅ Final model trained!\")\nprint(f\"📊 Best iteration: {final_model.best_iteration_ if hasattr(final_model, 'best_iteration_') else 'N/A'}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Why Cross-Validation?\n- More reliable than single train/val split\n- Gets out-of-fold (OOF) predictions for all training data\n- Used to find optimal threshold without overfitting\n\nKey Parameters:\n- scale_pos_weight: Handles class imbalance (53:1 ratio)\n- Bayesian bootstrap: Better uncertainty estimation\n- Early stopping: Prevents overfitting\n\nThis takes ~15-20 minutes. Grab a coffee! ☕","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 11: LOAD & PROCESS EVALUATION DATA\n## ================================================================================\nLoad the evaluation/test set and apply the SAME feature engineering.","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 6] PROCESSING EVALUATION DATA\")\nprint(\"=\" * 80)\n\n# Load evaluation files\neval_path = \"/kaggle/input/alpha-radar-solana-sprint/\"\neval_files = sorted(glob.glob(eval_path + \"evaluation_set_30s_chunk_*.csv\"))\n\nprint(f\"📂 Found {len(eval_files)} evaluation files\")\nprint(f\"📂 Files: {', '.join([os.path.basename(f) for f in eval_files])}\")\n\n# Load and concatenate\neval_df = pd.concat([pd.read_csv(f) for f in eval_files], ignore_index=True)\n\nprint(f\"\\n✅ Loaded {len(eval_df):,} evaluation transactions\")\nprint(f\"✅ Unique tokens: {eval_df['mint_token_id'].nunique():,}\")\n\n# Apply SAME feature engineering pipeline\nprint(f\"\\n🔧 Applying feature engineering...\")\neval_features = create_all_features(eval_df)\n\n# === APPLY SVD EMBEDDINGS ===\nX_eval_temp = eval_features.drop(columns=['mint_token_id_clean'])\nX_eval_temp = X_eval_temp.fillna(0).replace([np.inf, -np.inf], 0)\n\nif n_components >= 2:\n    print(f\"\\n  🔮 Applying SVD to evaluation...\")\n    \n    # Only use columns that exist in both train and eval\n    common_cols = [col for col in X_temp.columns if col in X_eval_temp.columns]\n    print(f\"  📊 Using {len(common_cols)} common features for SVD\")\n    \n    # Transform using trained SVD\n    eval_embeddings = svd.transform(X_eval_temp[common_cols])\n    \n    # Add embeddings\n    for i in range(n_components):\n        eval_features[f'svd_{i}'] = eval_embeddings[:, i]\n    \n    print(f\"  ✅ Added {n_components} embedding features\")\n\nprint(f\"\\n✅ Evaluation features ready: {eval_features.shape}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\nCritical: We must apply identical transformations to ensure fair predictions!\n\nEvaluation set:\n- 5 CSV chunks\n- ~1.4M transactions\n- ~64K unique tokens (what we need to predict)\n\nThis takes ~5-8 minutes.","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 12: ALIGN FEATURES & GENERATE PREDICTIONS\n## ================================================================================\n","metadata":{}},{"cell_type":"code","source":"# === ALIGN FEATURES ===\nprint(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 7] ALIGNING FEATURES\")\nprint(\"=\" * 80)\n\nfeature_cols = X.columns.tolist()\n\nprint(f\"📊 Training features: {len(feature_cols)}\")\nprint(f\"📊 Evaluation features: {len([c for c in eval_features.columns if c != 'mint_token_id_clean'])}\")\n\n# Add any missing features as zeros\nmissing_count = 0\nfor col in feature_cols:\n    if col not in eval_features.columns:\n        eval_features[col] = 0\n        missing_count += 1\n        if missing_count <= 5:  # Only print first 5\n            print(f\"  ⚠️  Added missing: {col}\")\n\nif missing_count > 5:\n    print(f\"  ⚠️  Added {missing_count - 5} more missing features...\")\n\n# Reorder columns to match training\nX_eval = eval_features[feature_cols]\n\nprint(f\"\\n✅ Aligned: {X_eval.shape}\")\nprint(f\"   All evaluation tokens now have same {X_eval.shape[1]} features as training\")\n\n# === GENERATE PREDICTIONS ===\nprint(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 8] GENERATING PREDICTIONS\")\nprint(\"=\" * 80)\n\n# Get prediction scores\neval_scores = final_model.predict_proba(X_eval)[:, 1]\n\nprint(f\"📊 Score Distribution:\")\nprint(f\"   Mean:     {eval_scores.mean():.6f}\")\nprint(f\"   Median:   {np.median(eval_scores):.6f}\")\nprint(f\"   Std:      {eval_scores.std():.6f}\")\nprint(f\"   Min:      {eval_scores.min():.6f}\")\nprint(f\"   Max:      {eval_scores.max():.6f}\")\nprint(f\"   95th %:   {np.percentile(eval_scores, 95):.6f}\")\n\n# === ADAPTIVE THRESHOLDING ===\nprint(f\"\\n🎚️  Adaptive Thresholding:\")\n\ntraining_positive_rate = y.mean()\nprint(f\"   Training positive rate: {training_positive_rate:.2%}\")\n\n# Allow more predictions in evaluation (2.5x training rate)\ntarget_positive_rate = training_positive_rate * 2.5\nadaptive_threshold = np.percentile(eval_scores, 100 * (1 - target_positive_rate))\n\nprint(f\"   Target positive rate: {target_positive_rate:.2%}\")\nprint(f\"   Adaptive threshold: {adaptive_threshold:.6f}\")\nprint(f\"   Training threshold: {best_threshold:.6f}\")\n\n# Use the lower threshold (more aggressive)\nfinal_threshold = min(best_threshold, max(adaptive_threshold, 0.0001))\n\nprint(f\"\\n✅ FINAL THRESHOLD: {final_threshold:.6f}\")\n\n# Apply threshold\neval_features['prediction_score'] = eval_scores\neval_features['is_target'] = (eval_scores > final_threshold).astype(int)\n\npredicted_positives = eval_features['is_target'].sum()\nprediction_rate = 100 * predicted_positives / len(eval_features)\n\nprint(f\"\\n📊 Predictions:\")\nprint(f\"   Total tokens: {len(eval_features):,}\")\nprint(f\"   Predicted positive: {predicted_positives:,}\")\nprint(f\"   Prediction rate: {prediction_rate:.2f}%\")\n\n# === SAFETY CHECK ===\nmin_required = int(len(eval_features) * 0.005)  # At least 0.5%\n\nif predicted_positives < min_required:\n    print(f\"\\n⚠️  WARNING: Too few predictions!\")\n    print(f\"   Minimum required: {min_required} (0.5%)\")\n    print(f\"   Using top-{min_required} approach instead...\")\n    \n    top_n_threshold = np.sort(eval_scores)[-min_required]\n    eval_features['is_target'] = (eval_scores >= top_n_threshold).astype(int)\n    \n    print(f\"   New threshold: {top_n_threshold:.6f}\")\n    print(f\"   New predictions: {eval_features['is_target'].sum():,}\")\nelse:\n    print(f\"\\n✅ Prediction count looks good!\")\n\n# Show score distribution for positive predictions\npositive_scores = eval_scores[eval_features['is_target'] == 1]\nif len(positive_scores) > 0:\n    print(f\"\\n📊 Positive Prediction Scores:\")\n    print(f\"   Mean: {positive_scores.mean():.6f}\")\n    print(f\"   Min:  {positive_scores.min():.6f}\")\n    print(f\"   Max:  {positive_scores.max():.6f}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Part A: Feature Alignment\n- Ensure evaluation has ALL features from training\n- Add missing features as zeros\n- This handles differences between datasets\n\nPart B: Adaptive Thresholding\n- Training threshold might not work on evaluation (distribution shift!)\n- Calculate adaptive threshold based on evaluation score distribution\n- Use the LOWER of two thresholds to be more aggressive\n\nPart C: Safety Check\n- Ensure we predict a reasonable number of tokens\n- If too few, use top-N approach","metadata":{}},{"cell_type":"markdown","source":"## ================================================================================\n## CELL 13: CREATE FINAL SUBMISSION\n## ================================================================================\nCreate submission files in the exact format required by Kaggle.\n","metadata":{}},{"cell_type":"code","source":"print(\"\\n\" + \"=\" * 80)\nprint(\"[STEP 9] CREATING SUBMISSION\")\nprint(\"=\" * 80)\n\n# === GET ORIGINAL TOKEN IDS IN CORRECT ORDER ===\nprint(\"📋 Extracting original token IDs...\")\n\neval_df['mint_token_id_clean'] = eval_df['mint_token_id'].astype(str).str.strip().str.lower()\n\n# Get first occurrence of each token (preserves order)\neval_unique = eval_df.drop_duplicates(subset=['mint_token_id_clean'], keep='first')[\n    ['mint_token_id', 'mint_token_id_clean']\n]\n\nprint(f\"   Found {len(eval_unique):,} unique tokens\")\n\n# === MERGE WITH PREDICTIONS ===\nprint(\"🔗 Merging predictions...\")\n\nsubmission_df = eval_unique.merge(\n    eval_features[['mint_token_id_clean', 'is_target', 'prediction_score']], \n    on='mint_token_id_clean', \n    how='left'\n)\n\n# Handle any missing predictions (should be none)\nsubmission_df['is_target'] = submission_df['is_target'].fillna(0).astype(int)\nsubmission_df['prediction_score'] = submission_df['prediction_score'].fillna(0)\n\n# === CREATE MAIN SUBMISSION FILE ===\nfinal_submission = submission_df[['mint_token_id', 'is_target']]\n\n# === VALIDATION ===\nprint(\"\\n🔍 Validating submission...\")\n\ntry:\n    assert len(final_submission) == 64208, f\"❌ Expected 64,208 rows, got {len(final_submission)}\"\n    assert final_submission['is_target'].isin([0, 1]).all(), \"❌ is_target must be 0 or 1\"\n    assert not final_submission['mint_token_id'].isna().any(), \"❌ No null token IDs allowed\"\n    assert not final_submission['mint_token_id'].duplicated().any(), \"❌ Duplicate token IDs found\"\n    \n    print(\"✅ All validation checks passed!\")\n    \nexcept AssertionError as e:\n    print(f\"❌ Validation failed: {e}\")\n    raise\n\n# === SUMMARY STATISTICS ===\nprint(f\"\\n📊 Submission Summary:\")\nprint(f\"   Total rows: {len(final_submission):,}\")\nprint(f\"   Predicted positive: {final_submission['is_target'].sum():,}\")\nprint(f\"   Predicted negative: {(final_submission['is_target']==0).sum():,}\")\nprint(f\"   Positive rate: {100 * final_submission['is_target'].sum() / len(final_submission):.2f}%\")\n\n# === SAVE FILES ===\nprint(\"\\n💾 Saving files...\")\n\n# Main submission\nfinal_submission.to_csv(\"submission.csv\", index=False)\nprint(\"   ✅ submission.csv saved\")\n\n# Detailed deliverable\ndeliverable_df = pd.DataFrame({\n    'token': submission_df['mint_token_id'],\n    'threshold': final_threshold,\n    'prediction_value': submission_df['prediction_score'],\n    'isTargetToken': submission_df['is_target']\n})\ndeliverable_df.to_csv('deliverable_details.csv', index=False)\nprint(\"   ✅ deliverable_details.csv saved\")\n\n# === SHOW TOP PREDICTIONS ===\nprint(\"\\n📋 Top 15 Predictions by Score:\")\ntop_preds = submission_df.nlargest(15, 'prediction_score')[\n    ['mint_token_id', 'prediction_score', 'is_target']\n]\nprint(top_preds.to_string(index=False))\n\n# === SHOW SOME STATISTICS ===\nprint(\"\\n📊 Score Statistics for Positive Predictions:\")\npositive_df = submission_df[submission_df['is_target'] == 1]\nif len(positive_df) > 0:\n    print(f\"   Count: {len(positive_df):,}\")\n    print(f\"   Mean score: {positive_df['prediction_score'].mean():.6f}\")\n    print(f\"   Median score: {positive_df['prediction_score'].median():.6f}\")\n    print(f\"   Min score: {positive_df['prediction_score'].min():.6f}\")\n    print(f\"   Max score: {positive_df['prediction_score'].max():.6f}\")\n\nprint(\"\\n\" + \"=\" * 80)\nprint(\"🎉 COMPLETE! SUBMISSION READY FOR UPLOAD!\")\nprint(\"=\" * 80)\nprint(\"\\n📤 Next steps:\")\nprint(\"   1. Download submission.csv from the output\")\nprint(\"   2. Go to competition submission page\")\nprint(\"   3. Upload submission.csv\")\nprint(\"   4. Wait for scoring (may take a few minutes)\")\nprint(\"\\n🤞 Good luck!\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Critical Requirements:\n✅ Exactly 64,208 rows (one per evaluation token)\n✅ Original token IDs (case-sensitive, exact spelling)\n✅ Correct token order (as they appear in evaluation data)\n✅ Binary predictions (0 or 1, no floats)\n✅ No missing values\n\nOutput Files:\n1. submission.csv - Main submission file\n2. deliverable_details.csv - Detailed results with scores","metadata":{}}]}