{"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":"none","dataSources":[{"sourceId":116062,"databundleVersionId":14084779,"sourceType":"competition"},{"sourceId":269303029,"sourceType":"kernelVersion"},{"sourceId":269339911,"sourceType":"kernelVersion"},{"sourceId":270571028,"sourceType":"kernelVersion"},{"sourceId":270597770,"sourceType":"kernelVersion"},{"sourceId":271888783,"sourceType":"kernelVersion"}],"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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":"import pandas as pd\nimport numpy as np\nfrom sklearn.ensemble import StackingRegressor, RandomForestRegressor\nfrom sklearn.linear_model import LinearRegression, Ridge\nfrom sklearn.svm import SVR\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import mean_squared_error, r2_score\nfrom sklearn.preprocessing import StandardScaler\n\ndef ensemble_submissions(file_paths, weights, output_path='submission.tsv'):\n    \"\"\"\n    Ensemble multiple submission files using weighted averaging\n    \"\"\"\n    dfs = []\n    for i, path in enumerate(file_paths):\n        try:\n            df = pd.read_csv(path, sep='\\t', header=None, names=['protein', 'go_term', 'score'])\n            df['key'] = df['protein'] + '_' + df['go_term']\n            df = df.rename(columns={'score': f'score_{i}'})\n            dfs.append(df)\n            print(f\"✅ Loaded {len(df):,} predictions from file {i+1}: {path.split('/')[-1]}\")\n        except Exception as e:\n            print(f\"❌ Error loading file {path}: {e}\")\n            return None\n    \n    if not dfs:\n        print(\"❌ No files were successfully loaded\")\n        return None\n    \n    # Start with first dataframe\n    result = dfs[0][['protein', 'go_term', 'key', 'score_0']].copy()\n    \n    # Merge all dataframes\n    for i in range(1, len(dfs)):\n        result = result.merge(\n            dfs[i][['key', f'score_{i}']], \n            on='key', \n            how='outer',\n            validate='one_to_one'  # Add validation\n        )\n    \n    # Fill missing scores with 0\n    for i in range(len(dfs)):\n        result[f'score_{i}'] = result[f'score_{i}'].fillna(0)\n    \n    # Calculate weighted average\n    result['score'] = sum(weights[i] * result[f'score_{i}'] for i in range(len(dfs)))\n    \n    # Handle missing protein/go_term values\n    result['protein'] = result['protein'].fillna(result['key'].str.split('_').str[0])\n    result['go_term'] = result['go_term'].fillna(result['key'].str.split('_').str[-1])\n    \n    # Sort by score and save\n    result = result.sort_values('score', ascending=False)\n    \n    # Save final submission\n    final_submission = result[['protein', 'go_term', 'score']].copy()\n    final_submission.to_csv(\n        output_path,\n        sep='\\t',\n        index=False,\n        header=False,\n        float_format='%.6f'  # Consistent float formatting\n    )\n    \n    print(f\"✅ Saved {len(final_submission):,} predictions to {output_path}\")\n    print(f\"📊 Score range: [{final_submission['score'].min():.4f}, {final_submission['score'].max():.4f}]\")\n    \n    return result\n\ndef stacking_regressor(file_paths, weights, output_path='submission_stacked.tsv'):\n    \"\"\"\n    Use stacking regressor to combine predictions\n    \"\"\"\n    print(\"🚀 Training Stacking Regressor...\")\n    \n    # Load and prepare data\n    result = ensemble_submissions(file_paths, weights, 'temp_ensemble.tsv')\n    if result is None:\n        return None\n    \n    # Prepare features and target\n    feature_columns = [col for col in result.columns if col.startswith('score_')]\n    \n    if len(feature_columns) < 2:\n        print(\"❌ Need at least 2 score columns for stacking\")\n        return result\n    \n    X = result[feature_columns]\n    y = result['score']  # Continuous target - use regression!\n    \n    print(f\"📈 Features: {feature_columns}\")\n    print(f\"🎯 Target shape: {y.shape}\")\n    \n    # Split data (we'll use a holdout set for validation)\n    X_train, X_val, y_train, y_val = train_test_split(\n        X, y, test_size=0.2, random_state=42, shuffle=True\n    )\n    \n    # Scale features for better performance\n    scaler = StandardScaler()\n    X_train_scaled = scaler.fit_transform(X_train)\n    X_val_scaled = scaler.transform(X_val)\n    \n    # Define base models for stacking (REGRESSION models)\n    base_learners = [\n        ('svr', SVR(kernel='rbf', C=1.0)),\n        ('ridge', Ridge(alpha=1.0)),\n        ('rf', RandomForestRegressor(n_estimators=50, random_state=42, n_jobs=-1))\n    ]\n    \n    # Meta model\n    meta_model = LinearRegression()\n    \n    # Create stacking regressor\n    stacking_model = StackingRegressor(\n        estimators=base_learners, \n        final_estimator=meta_model,\n        cv=5,  # Cross-validation for base models\n        n_jobs=-1\n    )\n    \n    # Train the stacking model\n    print(\"🔄 Training stacking model...\")\n    stacking_model.fit(X_train_scaled, y_train)\n    \n    # Predict on validation set\n    y_pred_val = stacking_model.predict(X_val_scaled)\n    \n    # Calculate regression metrics\n    mse = mean_squared_error(y_val, y_pred_val)\n    r2 = r2_score(y_val, y_pred_val)\n    \n    print(f\"📊 Stacking Model Performance:\")\n    print(f\"   MSE: {mse:.6f}\")\n    print(f\"   R² Score: {r2:.4f}\")\n    print(f\"   Predictions range: [{y_pred_val.min():.4f}, {y_pred_val.max():.4f}]\")\n    \n    # Apply model to all data\n    X_scaled = scaler.transform(X)\n    result['stacking_score'] = stacking_model.predict(X_scaled)\n    \n    # Ensure scores are in valid range [0, 1]\n    result['stacking_score'] = np.clip(result['stacking_score'], 0, 1)\n    \n    # Save stacked predictions\n    final_stacked = result[['protein', 'go_term', 'stacking_score']].copy()\n    final_stacked = final_stacked.sort_values('stacking_score', ascending=False)\n    \n    final_stacked.to_csv(\n        output_path,\n        sep='\\t',\n        index=False,\n        header=False,\n        float_format='%.6f'\n    )\n    \n    print(f\"✅ Saved {len(final_stacked):,} stacked predictions to {output_path}\")\n    print(f\"📊 Final score range: [{final_stacked['stacking_score'].min():.4f}, {final_stacked['stacking_score'].max():.4f}]\")\n    \n    return result\n\ndef simple_weighted_ensemble(file_paths, weights, output_path='submission.tsv'):\n    \"\"\"\n    Simple weighted ensemble without machine learning\n    \"\"\"\n    print(\"🔧 Using simple weighted ensemble...\")\n    return ensemble_submissions(file_paths, weights, output_path)\n\nif __name__ == \"__main__\":\n    # Configuration\n    file_paths = [\n        '/kaggle/input/gaf-submission/submission.tsv',\n        '/kaggle/input/cafa-6-predictions/submission.tsv'\n    ]\n    weights = [0.5, 0.5]  # You can adjust these weights\n    \n    print(\"🏁 Starting CAFA 6 Protein Function Prediction Ensemble\")\n    print(\"=\" * 60)\n    \n    # Option 1: Simple weighted average (fast and reliable)\n    print(\"\\n1. Running Simple Weighted Ensemble...\")\n    simple_result = simple_weighted_ensemble(file_paths, weights, 'submission.tsv')\n    \n    # Option 2: Stacking regressor (more sophisticated)\n    print(\"\\n2. Running Stacking Regressor...\")\n    stacked_result = stacking_regressor(file_paths, weights, 'submission.tsv')\n    \n    print(\"\\n🎉 Ensemble completed successfully!\")\n    print(\"📁 Output files:\")\n    print(\"   - submission_simple.tsv : Simple weighted ensemble\")\n    print(\"   - submission_stacked.tsv : Stacking regressor ensemble\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}