{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.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":67356,"databundleVersionId":8006601,"sourceType":"competition"},{"sourceId":8906673,"sourceType":"datasetVersion","datasetId":5355153}],"dockerImageVersionId":30732,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"pip install pandas numpy scikit-learn rdkit duckdb","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport duckdb\nimport pandas as pd\nfrom rdkit import Chem\nfrom rdkit.Chem import AllChem\nfrom sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier, VotingClassifier\nfrom sklearn.model_selection import train_test_split, GridSearchCV, cross_val_score\nfrom sklearn.metrics import average_precision_score\nfrom sklearn.preprocessing import OneHotEncoder, StandardScaler\nfrom sklearn.pipeline import Pipeline\nimport numpy as np\n\n# Paths to training and testing data\ntrain_path = '/kaggle/input/leash-BELKA/train.parquet'\ntest_path = '/kaggle/input/leash-BELKA/test.parquet'\n\n# Connect to DuckDB and sample the training data\ncon = duckdb.connect()\ndf = con.query(f\"\"\"\n    (SELECT *\n     FROM parquet_scan('{train_path}')\n     WHERE binds = 0\n     ORDER BY random()\n     LIMIT 30000)\n    UNION ALL\n    (SELECT *\n     FROM parquet_scan('{train_path}')\n     WHERE binds = 1\n     ORDER BY random()\n     LIMIT 30000)\n\"\"\").df()\ncon.close()\n\n# Convert SMILES to RDKit molecules\ndf['molecule'] = df['molecule_smiles'].apply(Chem.MolFromSmiles)\n\n# Generate ECFPs\ndef generate_ecfp(molecule, radius=2, bits=1024):\n    if molecule is None:\n        return None\n    return list(AllChem.GetMorganFingerprintAsBitVect(molecule, radius, nBits=bits))\n\ndf['ecfp'] = df['molecule'].apply(generate_ecfp)\n\n# Filter out rows where ECFP generation failed\ndf = df[df['ecfp'].notna()]\n\n# One-hot encode the protein_name\nonehot_encoder = OneHotEncoder(sparse_output=False)\nprotein_onehot = onehot_encoder.fit_transform(df['protein_name'].values.reshape(-1, 1))\n\n# Combine ECFPs and one-hot encoded protein_name\nX = [ecfp + protein.tolist() for ecfp, protein in zip(df['ecfp'], protein_onehot)]\ny = df['binds'].tolist()\n\n# Split the data into train and test sets\nX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)\n\n# Define the pipeline for RandomForest with StandardScaler\nrf_pipeline = Pipeline([\n    ('scaler', StandardScaler()),\n    ('classifier', RandomForestClassifier(random_state=42))\n])\n\n# Define the pipeline for GradientBoosting with StandardScaler\ngb_pipeline = Pipeline([\n    ('scaler', StandardScaler()),\n    ('classifier', GradientBoostingClassifier(random_state=42))\n])\n\n# Hyperparameter tuning for RandomForest\nparam_grid_rf = {\n    'classifier__n_estimators': [100, 200, 300],\n    'classifier__max_depth': [None, 10, 20, 30],\n    'classifier__min_samples_split': [2, 5, 10],\n    'classifier__min_samples_leaf': [1, 2, 4]\n}\n\n# Hyperparameter tuning for GradientBoosting\nparam_grid_gb = {\n    'classifier__n_estimators': [100, 200],\n    'classifier__learning_rate': [0.01, 0.1],\n    'classifier__max_depth': [3, 5, 7]\n}\n\n# GridSearchCV for RandomForest\ngrid_search_rf = GridSearchCV(rf_pipeline, param_grid_rf, cv=3, n_jobs=-1, scoring='average_precision')\ngrid_search_rf.fit(X_train, y_train)\nbest_rf_model = grid_search_rf.best_estimator_\n\n# GridSearchCV for GradientBoosting\ngrid_search_gb = GridSearchCV(gb_pipeline, param_grid_gb, cv=3, n_jobs=-1, scoring='average_precision')\ngrid_search_gb.fit(X_train, y_train)\nbest_gb_model = grid_search_gb.best_estimator_\n\n# Ensemble of best models\nensemble_model = VotingClassifier(estimators=[\n    ('rf', best_rf_model),\n    ('gb', best_gb_model)\n], voting='soft')\n\nensemble_model.fit(X_train, y_train)\n\n# Cross-validation to evaluate the model\ncv_scores = cross_val_score(ensemble_model, X_train, y_train, cv=5, scoring='average_precision')\nprint(f\"Cross-Validation Mean Average Precision (mAP): {np.mean(cv_scores):.2f}\")\n\n# Make predictions on the test set\ny_pred_proba = ensemble_model.predict_proba(X_test)[:, 1]  # Probability of the positive class\n\n# Calculate the mean average precision\nmap_score = average_precision_score(y_test, y_pred_proba)\nprint(f\"Mean Average Precision (mAP): {map_score:.2f}\")\n\n# Process the test.parquet file chunk by chunk\noutput_file = 'submission.csv'  # Specify the path and filename for the output file\n\n# Function to process each chunk\ndef process_chunk(df_chunk):\n    # Generate ECFPs for the molecule_smiles\n    df_chunk['molecule'] = df_chunk['molecule_smiles'].apply(Chem.MolFromSmiles)\n    df_chunk['ecfp'] = df_chunk['molecule'].apply(generate_ecfp)\n\n    # Filter out rows where ECFP generation failed\n    df_chunk = df_chunk[df_chunk['ecfp'].notna()]\n\n    # One-hot encode the protein_name\n    protein_onehot = onehot_encoder.transform(df_chunk['protein_name'].values.reshape(-1, 1))\n\n    # Combine ECFPs and one-hot encoded protein_name\n    X_test_chunk = [ecfp + protein.tolist() for ecfp, protein in zip(df_chunk['ecfp'], protein_onehot)]\n\n    # Predict the probabilities\n    probabilities = ensemble_model.predict_proba(X_test_chunk)[:, 1]\n\n    # Create a DataFrame with 'id' and 'binds' columns\n    output_df = pd.DataFrame({'id': df_chunk['id'], 'binds': probabilities})\n\n    # Save the output DataFrame to a CSV file\n    output_df.to_csv(output_file, index=False, mode='a', header=not os.path.exists(output_file))\n\n# Read the test.parquet file and process it in chunks\ndf_test = pd.read_parquet(test_path)\nchunk_size = 100000\nfor start in range(0, len(df_test), chunk_size):\n    end = start + chunk_size\n    process_chunk(df_test.iloc[start:end])\n\nprint(\"Predictions saved to submission.csv\")\n","metadata":{},"execution_count":null,"outputs":[]}]}