{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":96164,"databundleVersionId":11418275,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#!/usr/bin/env python\n# coding: utf-8\n\n\"\"\"\nComplete VIME Feature Importance Analysis for DRW Crypto Market Prediction\n=========================================================================\nFull implementation with corrected submission file generation\n\"\"\"\n\nimport numpy as np\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, TensorDataset\nfrom sklearn.preprocessing import StandardScaler, RobustScaler\nfrom sklearn.model_selection import train_test_split\nfrom scipy.stats import pearsonr\nimport lightgbm as lgb\nimport xgboost as xgb\nfrom tqdm import tqdm\nimport gc\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n# Set random seed for reproducibility\nRANDOM_SEED = 42\nnp.random.seed(RANDOM_SEED)\ntorch.manual_seed(RANDOM_SEED)\n\n# Device configuration\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Using device: {device}\")\n\n# Memory management\ndef clean_memory():\n    gc.collect()\n    if torch.cuda.is_available():\n        torch.cuda.empty_cache()\n\n# =========================\n# 1. VIME Model Implementation\n# =========================\nclass VIMEModel(nn.Module):\n    \"\"\"VIME: Value Imputation and Mask Estimation\"\"\"\n    def __init__(self, input_dim, hidden_dims=[256, 128], dropout_rate=0.2, corruption_rate=0.3):\n        super().__init__()\n        \n        self.input_dim = input_dim\n        self.corruption_rate = corruption_rate\n        \n        # Encoder network\n        encoder_layers = []\n        prev_dim = input_dim\n        for hidden_dim in hidden_dims:\n            encoder_layers.extend([\n                nn.Linear(prev_dim, hidden_dim),\n                nn.BatchNorm1d(hidden_dim),\n                nn.ReLU(),\n                nn.Dropout(dropout_rate)\n            ])\n            prev_dim = hidden_dim\n        self.encoder = nn.Sequential(*encoder_layers)\n        self.encoder_output_dim = hidden_dims[-1]\n        \n        # Mask estimation network\n        self.mask_estimator = nn.Sequential(\n            nn.Linear(self.encoder_output_dim, self.encoder_output_dim),\n            nn.ReLU(),\n            nn.Dropout(dropout_rate),\n            nn.Linear(self.encoder_output_dim, input_dim),\n            nn.Sigmoid()\n        )\n        \n        # Feature reconstruction network\n        self.feature_reconstructor = nn.Sequential(\n            nn.Linear(self.encoder_output_dim, self.encoder_output_dim * 2),\n            nn.ReLU(),\n            nn.Dropout(dropout_rate),\n            nn.Linear(self.encoder_output_dim * 2, input_dim)\n        )\n        \n        # Prediction network\n        self.predictor = nn.Sequential(\n            nn.Linear(self.encoder_output_dim, 64),\n            nn.ReLU(),\n            nn.Dropout(dropout_rate),\n            nn.Linear(64, 32),\n            nn.ReLU(),\n            nn.Dropout(dropout_rate),\n            nn.Linear(32, 1)\n        )\n        \n        # Feature importance weights\n        self.feature_importance_weights = nn.Parameter(torch.ones(input_dim))\n        \n    def corrupt_data(self, x):\n        \"\"\"Corrupt data for self-supervised pretraining\"\"\"\n        batch_size = x.size(0)\n        \n        # Random corruption mask\n        mask = torch.bernoulli(torch.full((batch_size, self.input_dim), self.corruption_rate)).to(x.device)\n        \n        # Corrupt data by mixing with random samples\n        corrupted_x = x.clone()\n        for i in range(self.input_dim):\n            corrupted_indices = mask[:, i] == 1\n            if corrupted_indices.any():\n                # Swap with random samples from the batch\n                num_corrupted = corrupted_indices.sum()\n                random_indices = torch.randperm(batch_size)[:num_corrupted]\n                corrupted_x[corrupted_indices, i] = x[random_indices, i]\n        \n        return corrupted_x, mask\n    \n    def forward(self, x, pretrain=False):\n        if pretrain:\n            # Self-supervised pretraining\n            corrupted_x, mask = self.corrupt_data(x)\n            encoded = self.encoder(corrupted_x)\n            mask_pred = self.mask_estimator(encoded)\n            feature_pred = self.feature_reconstructor(encoded)\n            return mask_pred, feature_pred, mask, x\n        else:\n            # Supervised prediction with feature importance\n            weighted_x = x * torch.sigmoid(self.feature_importance_weights)\n            encoded = self.encoder(weighted_x)\n            output = self.predictor(encoded)\n            return output\n\n# =========================\n# 2. Data Loading and Preprocessing\n# =========================\nprint(\"=== VIME Feature Importance Analysis ===\\n\")\nprint(\"1. Loading data...\")\n\n# Define features\nX_FEATURES = [f\"X{i}\" for i in range(1, 891)]\nMARKET_FEATURES = [\"bid_qty\", \"ask_qty\", \"buy_qty\", \"sell_qty\", \"volume\"]\n\n# Load data - use subset for memory efficiency\ntrain_df = pd.read_parquet(\n    \"/kaggle/input/drw-crypto-market-prediction/train.parquet\",\n    columns=X_FEATURES[:300] + MARKET_FEATURES + [\"label\"]  # Use first 300 X features\n)\n\ntest_df = pd.read_parquet(\n    \"/kaggle/input/drw-crypto-market-prediction/test.parquet\",\n    columns=X_FEATURES[:300] + MARKET_FEATURES\n)\n\nprint(f\"Train shape: {train_df.shape}\")\nprint(f\"Test shape: {test_df.shape}\")\n\n# =========================\n# 3. Feature Engineering\n# =========================\nprint(\"\\n2. Engineering features...\")\n\ndef add_engineered_features(df):\n    \"\"\"Add engineered features\"\"\"\n    # Order flow features\n    df['net_order_flow'] = df['buy_qty'] - df['sell_qty']\n    df['order_flow_imbalance'] = (df['buy_qty'] - df['sell_qty']) / (df['buy_qty'] + df['sell_qty'] + 1e-10)\n    df['normalized_net_flow'] = df['net_order_flow'] / (df['volume'] + 1e-10)\n    \n    # Liquidity features\n    df['total_depth'] = df['bid_qty'] + df['ask_qty']\n    df['depth_imbalance'] = (df['bid_qty'] - df['ask_qty']) / (df['total_depth'] + 1e-10)\n    df['relative_spread'] = np.abs(df['bid_qty'] - df['ask_qty']) / (df['total_depth'] + 1e-10)\n    \n    # Volume features\n    df['log_volume'] = np.log1p(df['volume'])\n    df['buy_sell_ratio'] = df['buy_qty'] / (df['sell_qty'] + 1e-10)\n    df['volume_depth_ratio'] = df['volume'] / (df['total_depth'] + 1e-10)\n    \n    # Market microstructure\n    df['kyle_lambda'] = np.abs(df['net_order_flow']) / (df['volume'] + 1e-10)\n    df['price_impact_proxy'] = df['net_order_flow'] / (df['total_depth'] + 1e-10)\n    \n    # Simple moving averages\n    for col in ['volume', 'net_order_flow', 'order_flow_imbalance']:\n        df[f'{col}_ma5'] = df[col].rolling(5, min_periods=1).mean()\n        df[f'{col}_ma10'] = df[col].rolling(10, min_periods=1).mean()\n    \n    # Fill NaN and inf values\n    df = df.replace([np.inf, -np.inf], 0).fillna(0)\n    \n    return df\n\n# Apply feature engineering\ntrain_df = add_engineered_features(train_df)\ntest_df = add_engineered_features(test_df)\n\n# Get all feature names\nfeature_cols = [col for col in train_df.columns if col not in ['label']]\nprint(f\"Total features: {len(feature_cols)}\")\n\n# =========================\n# 4. Prepare Training Data\n# =========================\nprint(\"\\n3. Preparing training data...\")\n\n# Use recent 50% of data for training\ntrain_size = int(0.5 * len(train_df))\ntrain_data = train_df.iloc[-train_size:].reset_index(drop=True)\n\n# Clean up memory\ndel train_df\nclean_memory()\n\n# Convert to arrays\nX_full = train_data[feature_cols].values.astype(np.float32)\ny_full = train_data[\"label\"].values.astype(np.float32)\n\n# Train-validation split\nX_train, X_val, y_train, y_val = train_test_split(\n    X_full, y_full, test_size=0.2, random_state=RANDOM_SEED\n)\n\nprint(f\"Training samples: {len(X_train)}\")\nprint(f\"Validation samples: {len(X_val)}\")\n\n# Scale features\nscaler = StandardScaler()\nX_train_scaled = scaler.fit_transform(X_train)\nX_val_scaled = scaler.transform(X_val)\n\n# Create PyTorch datasets\ntrain_dataset = TensorDataset(\n    torch.tensor(X_train_scaled, dtype=torch.float32),\n    torch.tensor(y_train, dtype=torch.float32).unsqueeze(1)\n)\nval_dataset = TensorDataset(\n    torch.tensor(X_val_scaled, dtype=torch.float32),\n    torch.tensor(y_val, dtype=torch.float32).unsqueeze(1)\n)\n\n# Data loaders\ntrain_loader = DataLoader(train_dataset, batch_size=256, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=512, shuffle=False)\n\n# =========================\n# 5. Train VIME Model\n# =========================\nprint(\"\\n4. Training VIME model...\")\n\n# Initialize model\nmodel = VIMEModel(\n    input_dim=len(feature_cols),\n    hidden_dims=[256, 128],\n    dropout_rate=0.2,\n    corruption_rate=0.3\n).to(device)\n\nprint(f\"Model parameters: {sum(p.numel() for p in model.parameters()):,}\")\n\n# Phase 1: Self-supervised pretraining\nprint(\"\\nPhase 1: Self-supervised pretraining...\")\npretrain_optimizer = torch.optim.Adam(model.parameters(), lr=0.001)\nmask_criterion = nn.BCELoss()\nfeature_criterion = nn.MSELoss()\n\nfor epoch in range(8):  # 8 epochs for pretraining\n    model.train()\n    total_loss = 0\n    \n    for batch_idx, (inputs, _) in enumerate(train_loader):\n        inputs = inputs.to(device)\n        \n        pretrain_optimizer.zero_grad()\n        \n        # Forward pass\n        mask_pred, feature_pred, true_mask, original_x = model(inputs, pretrain=True)\n        \n        # Calculate losses\n        mask_loss = mask_criterion(mask_pred, true_mask)\n        feature_loss = feature_criterion(feature_pred, original_x)\n        total_loss_batch = mask_loss + feature_loss\n        \n        # Backward pass\n        total_loss_batch.backward()\n        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n        pretrain_optimizer.step()\n        \n        total_loss += total_loss_batch.item()\n    \n    avg_loss = total_loss / len(train_loader)\n    print(f\"Pretrain Epoch {epoch+1}/8: Loss = {avg_loss:.4f}\")\n\n# Phase 2: Supervised fine-tuning\nprint(\"\\nPhase 2: Supervised fine-tuning...\")\nfinetune_optimizer = torch.optim.Adam(model.parameters(), lr=0.0005)\ncriterion = nn.HuberLoss()\n\nbest_val_corr = -1\npatience = 0\nmax_patience = 5\n\nfor epoch in range(15):  # 15 epochs for fine-tuning\n    # Training\n    model.train()\n    train_loss = 0\n    \n    for inputs, targets in train_loader:\n        inputs, targets = inputs.to(device), targets.to(device)\n        \n        finetune_optimizer.zero_grad()\n        outputs = model(inputs, pretrain=False)\n        loss = criterion(outputs, targets)\n        loss.backward()\n        torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)\n        finetune_optimizer.step()\n        \n        train_loss += loss.item()\n    \n    # Validation\n    model.eval()\n    val_preds = []\n    val_targets = []\n    \n    with torch.no_grad():\n        for inputs, targets in val_loader:\n            inputs = inputs.to(device)\n            outputs = model(inputs, pretrain=False)\n            val_preds.extend(outputs.cpu().numpy().flatten())\n            val_targets.extend(targets.numpy().flatten())\n    \n    # Calculate metrics\n    val_corr = pearsonr(val_targets, val_preds)[0]\n    avg_train_loss = train_loss / len(train_loader)\n    \n    print(f\"Epoch {epoch+1}/15: Train Loss = {avg_train_loss:.4f}, Val Correlation = {val_corr:.4f}\")\n    \n    # Early stopping\n    if val_corr > best_val_corr:\n        best_val_corr = val_corr\n        patience = 0\n        # Save best model\n        torch.save(model.state_dict(), 'best_vime_model.pt')\n    else:\n        patience += 1\n        if patience >= max_patience:\n            print(\"Early stopping triggered\")\n            break\n\n# Load best model\nmodel.load_state_dict(torch.load('best_vime_model.pt'))\n\n# =========================\n# 6. Extract Feature Importance\n# =========================\nprint(\"\\n5. Extracting feature importance...\")\n\n# Get learned feature importance weights\nwith torch.no_grad():\n    vime_weights = torch.sigmoid(model.feature_importance_weights).cpu().numpy()\n\n# Compute corruption sensitivity importance\nprint(\"Computing corruption sensitivity...\")\nmodel.eval()\n\n# Get baseline predictions\nX_val_tensor = torch.tensor(X_val_scaled, dtype=torch.float32, device=device)\nwith torch.no_grad():\n    baseline_preds = model(X_val_tensor, pretrain=False).cpu().numpy().flatten()\nbaseline_score = pearsonr(y_val, baseline_preds)[0]\n\n# Test corruption sensitivity for each feature\ncorruption_importance = np.zeros(len(feature_cols))\n\nfor feat_idx in tqdm(range(len(feature_cols)), desc=\"Testing corruption sensitivity\"):\n    # Create corrupted version\n    X_corrupted = X_val_scaled.copy()\n    # Shuffle the feature values\n    np.random.shuffle(X_corrupted[:, feat_idx])\n    \n    # Get predictions with corrupted feature\n    X_corrupted_tensor = torch.tensor(X_corrupted, dtype=torch.float32, device=device)\n    with torch.no_grad():\n        corrupted_preds = model(X_corrupted_tensor, pretrain=False).cpu().numpy().flatten()\n    \n    # Calculate performance drop\n    corrupted_score = pearsonr(y_val, corrupted_preds)[0]\n    corruption_importance[feat_idx] = baseline_score - corrupted_score\n\n# Combine importance scores\ncombined_importance = 0.7 * (vime_weights / vime_weights.max()) + \\\n                    0.3 * (corruption_importance / (corruption_importance.max() + 1e-8))\n\n# Create importance dataframe\nimportance_df = pd.DataFrame({\n    'feature': feature_cols,\n    'vime_weight': vime_weights,\n    'corruption_sensitivity': corruption_importance,\n    'combined_importance': combined_importance\n}).sort_values('combined_importance', ascending=False)\n\nprint(\"\\nTop 30 most important features:\")\nprint(\"-\" * 60)\nfor idx, row in importance_df.head(30).iterrows():\n    print(f\"{row['feature']:30s} {row['combined_importance']:.4f}\")\n\n# Save importance results\nimportance_df.to_csv('vime_feature_importance.csv', index=False)\n\n# =========================\n# 7. Train Models on Top Features\n# =========================\nprint(\"\\n6. Training models on top features...\")\n\n# Select top features\nn_top_features = 150\ntop_features = importance_df.head(n_top_features)['feature'].tolist()\n\nprint(f\"Using top {n_top_features} features for final models\")\n\n# Prepare data with top features\nX_train_top = train_data[top_features].values\ny_train_top = train_data['label'].values\n\nX_test_top = test_df[top_features].values\n\n# Scale features\nscaler_final = RobustScaler()\nX_train_top_scaled = scaler_final.fit_transform(X_train_top)\nX_test_top_scaled = scaler_final.transform(X_test_top)\n\n# Split for validation\nX_tr, X_vl, y_tr, y_vl = train_test_split(\n    X_train_top_scaled, y_train_top, test_size=0.2, random_state=RANDOM_SEED\n)\n\n# Train LightGBM\nprint(\"\\nTraining LightGBM...\")\nlgb_params = {\n    'objective': 'regression',\n    'metric': 'rmse',\n    'boosting_type': 'gbdt',\n    'num_leaves': 31,\n    'learning_rate': 0.02,\n    'feature_fraction': 0.8,\n    'bagging_fraction': 0.7,\n    'bagging_freq': 5,\n    'verbose': -1,\n    'seed': RANDOM_SEED,\n    'n_jobs': -1\n}\n\nlgb_train = lgb.Dataset(X_tr, y_tr)\nlgb_val = lgb.Dataset(X_vl, y_vl, reference=lgb_train)\n\nlgb_model = lgb.train(\n    lgb_params,\n    lgb_train,\n    valid_sets=[lgb_val],\n    num_boost_round=1500,\n    callbacks=[lgb.early_stopping(100), lgb.log_evaluation(200)]\n)\n\n# Evaluate LightGBM\nlgb_val_pred = lgb_model.predict(X_vl, num_iteration=lgb_model.best_iteration)\nlgb_corr = pearsonr(y_vl, lgb_val_pred)[0]\nprint(f\"LightGBM validation correlation: {lgb_corr:.4f}\")\n\n# Train XGBoost\nprint(\"\\nTraining XGBoost...\")\nxgb_model = xgb.XGBRegressor(\n    n_estimators=1000,\n    learning_rate=0.02,\n    max_depth=5,\n    subsample=0.8,\n    colsample_bytree=0.8,\n    random_state=RANDOM_SEED,\n    tree_method='hist',\n    n_jobs=-1\n)\n\nxgb_model.fit(\n    X_tr, y_tr,\n    eval_set=[(X_vl, y_vl)],\n    early_stopping_rounds=100,\n    verbose=False\n)\n\n# Evaluate XGBoost\nxgb_val_pred = xgb_model.predict(X_vl)\nxgb_corr = pearsonr(y_vl, xgb_val_pred)[0]\nprint(f\"XGBoost validation correlation: {xgb_corr:.4f}\")\n\n# =========================\n# 8. Generate Test Predictions\n# =========================\nprint(\"\\n7. Generating test predictions...\")\n\n# Get predictions from both models\nlgb_test_pred = lgb_model.predict(X_test_top_scaled, num_iteration=lgb_model.best_iteration)\nxgb_test_pred = xgb_model.predict(X_test_top_scaled)\n\n# Ensemble predictions\nensemble_pred = 0.6 * lgb_test_pred + 0.4 * xgb_test_pred\n\n# Get VIME neural network predictions\nX_test_nn_scaled = scaler.transform(test_df[feature_cols].values)\nX_test_nn_tensor = torch.tensor(X_test_nn_scaled, dtype=torch.float32, device=device)\n\nmodel.eval()\nwith torch.no_grad():\n    nn_test_pred = model(X_test_nn_tensor, pretrain=False).cpu().numpy().flatten()\n\n# Final ensemble including neural network\nfinal_ensemble = 0.5 * ensemble_pred + 0.3 * lgb_test_pred + 0.2 * nn_test_pred\n\n# =========================\n# 9. Create Submission Files - CORRECTED VERSION\n# =========================\nprint(\"\\n8. Creating submission files...\")\n\n# Get the number of test samples\nn_test_samples = len(test_df)\n\n# Create submission dataframe with correct format\ndef create_submission(predictions, filename):\n    \"\"\"Create submission file with ID and prediction columns\"\"\"\n    submission_df = pd.DataFrame({\n        'ID': range(1, n_test_samples + 1),  # IDs from 1 to n_test_samples\n        'prediction': predictions\n    })\n    submission_df.to_csv(filename, index=False)\n    return submission_df\n\n# Create multiple submissions\nsubmissions = {\n    'submission_vime_lgb.csv': lgb_test_pred,\n    'submission_vime_xgb.csv': xgb_test_pred,\n    'submission_vime_ensemble.csv': ensemble_pred,\n    'submission_vime_nn.csv': nn_test_pred,\n    'submission_vime_final.csv': final_ensemble\n}\n\n# Generate each submission file\nfor filename, predictions in submissions.items():\n    sub_df = create_submission(predictions, filename)\n    print(f\"Created {filename} - Shape: {sub_df.shape}, Columns: {list(sub_df.columns)}\")\n\n# Display sample of final submission\nprint(\"\\nSample of final submission (submission_vime_final.csv):\")\nfinal_sub = pd.read_csv('submission_vime_final.csv')\nprint(final_sub.head(10))\nprint(f\"\\nTotal rows in submission: {len(final_sub)}\")\n\n# Verify submission format\nprint(\"\\nVerifying submission format:\")\nprint(f\"- First ID: {final_sub['ID'].iloc[0]}\")\nprint(f\"- Last ID: {final_sub['ID'].iloc[-1]}\")\nprint(f\"- Number of rows: {len(final_sub)}\")\nprint(f\"- Columns: {list(final_sub.columns)}\")\nprint(f\"- Prediction range: [{final_sub['prediction'].min():.6f}, {final_sub['prediction'].max():.6f}]\")\n\n# =========================\n# 10. Summary Report\n# =========================\nprint(\"\\n\" + \"=\"*60)\nprint(\"VIME FEATURE IMPORTANCE ANALYSIS COMPLETE\")\nprint(\"=\"*60)\nprint(f\"Total features analyzed: {len(feature_cols)}\")\nprint(f\"Top features selected: {n_top_features}\")\nprint(f\"Training samples: {len(X_train)}\")\nprint(f\"Test samples: {n_test_samples}\")\nprint(f\"\\nModel Performance:\")\nprint(f\"  VIME NN validation correlation: {best_val_corr:.4f}\")\nprint(f\"  LightGBM validation correlation: {lgb_corr:.4f}\")\nprint(f\"  XGBoost validation correlation: {xgb_corr:.4f}\")\n\n# Feature importance summary\nx_features_important = importance_df[importance_df['feature'].str.startswith('X')].head(20)\nmarket_features_important = importance_df[importance_df['feature'].isin(MARKET_FEATURES)]\nengineered_features_important = importance_df[~importance_df['feature'].str.startswith('X') & \n                                           ~importance_df['feature'].isin(MARKET_FEATURES)].head(10)\n\nprint(f\"\\nTop Anonymous Features (X_):\")\nfor _, row in x_features_important.head(10).iterrows():\n    print(f\"  {row['feature']:10s} importance: {row['combined_importance']:.4f}\")\n\nprint(f\"\\nMarket Features Ranking:\")\nfor _, row in market_features_important.iterrows():\n    print(f\"  {row['feature']:10s} importance: {row['combined_importance']:.4f}\")\n\nprint(f\"\\nTop Engineered Features:\")\nfor _, row in engineered_features_important.head(5).iterrows():\n    print(f\"  {row['feature']:25s} importance: {row['combined_importance']:.4f}\")\n\nprint(\"\\n✅ Analysis complete!\")\nprint(\"\\nAll submission files have been created with the correct format:\")\nprint(\"- ID column (starting from 1)\")\nprint(\"- prediction column (model predictions)\")\nprint(\"\\nRecommended submission: submission_vime_final.csv\")\nprint(\"This combines VIME neural network with tree-based models for best performance.\")\n\n# Clean up\nclean_memory()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}