{"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":"gpu","dataSources":[{"sourceId":67356,"databundleVersionId":8006601,"sourceType":"competition"}],"dockerImageVersionId":30732,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install duckdb\n!pip install rdkit","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-01T12:56:36.126449Z","iopub.execute_input":"2024-09-01T12:56:36.127201Z","iopub.status.idle":"2024-09-01T12:56:55.336280Z","shell.execute_reply.started":"2024-09-01T12:56:36.127165Z","shell.execute_reply":"2024-09-01T12:56:55.335143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install torch-geometric","metadata":{"execution":{"iopub.status.busy":"2024-09-01T12:56:55.339178Z","iopub.execute_input":"2024-09-01T12:56:55.340027Z","iopub.status.idle":"2024-09-01T12:56:59.342877Z","shell.execute_reply.started":"2024-09-01T12:56:55.339980Z","shell.execute_reply":"2024-09-01T12:56:59.341699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Import necessary libraries\nfrom sklearn.metrics import average_precision_score\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch_geometric.data import Data, DataLoader\nfrom torch_geometric.nn import GCNConv\nimport pandas as pd\nfrom rdkit import Chem\nfrom rdkit.Chem import Descriptors\nimport duckdb\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T12:56:59.345343Z","iopub.execute_input":"2024-09-01T12:56:59.345826Z","iopub.status.idle":"2024-09-01T12:57:08.856133Z","shell.execute_reply.started":"2024-09-01T12:56:59.345783Z","shell.execute_reply":"2024-09-01T12:57:08.855318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# File paths\ntrain_parquet_path = '/kaggle/input/leash-BELKA/train.parquet'\ntest_parquet_path = '/kaggle/input/leash-BELKA/test.parquet'\ntrain_csv_path = '/kaggle/input/leash-BELKA/train.csv'\ntest_csv_path = '/kaggle/input/leash-BELKA/test.csv'\n\n# Connect to DuckDB\ncon = duckdb.connect()\n\n# Sample 30,000 rows each for binds = 0 and binds = 1 from train.parquet\nquery_train = f\"\"\"\n    (SELECT *\n    FROM parquet_scan('{train_parquet_path}')\n    WHERE binds = 0\n    ORDER BY random()\n    LIMIT 30000)\n    UNION ALL\n    (SELECT *\n    FROM parquet_scan('{train_parquet_path}')\n    WHERE binds = 1\n    ORDER BY random()\n    LIMIT 30000)\n\"\"\"\n\n# Load data into DataFrame\ntrain_df = con.from_query(query_train).df()\n\n# Load test data without sampling\nquery_test = f\"\"\"\n    SELECT *\n    FROM parquet_scan('{test_parquet_path}')\n\"\"\"\n\ntest_df = con.from_query(query_test).df()\n\n# Close DuckDB connection\ncon.close()","metadata":{"execution":{"iopub.status.busy":"2024-09-01T12:57:08.858468Z","iopub.execute_input":"2024-09-01T12:57:08.858983Z","iopub.status.idle":"2024-09-01T12:57:59.688518Z","shell.execute_reply.started":"2024-09-01T12:57:08.858954Z","shell.execute_reply":"2024-09-01T12:57:59.687419Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Perform feature engineering\ndef calculate_descriptors(smiles):\n    mol = Chem.MolFromSmiles(smiles)\n    if mol is None:\n        return None, None\n    num_atoms = mol.GetNumAtoms()\n    mol_weight = Descriptors.MolWt(mol)\n    return num_atoms, mol_weight\n\n# Calculate descriptors for train and test data\ntrain_df['num_atoms'], train_df['mol_weight'] = zip(*train_df['molecule_smiles'].apply(calculate_descriptors))\ntest_df['num_atoms'], test_df['mol_weight'] = zip(*test_df['molecule_smiles'].apply(calculate_descriptors))\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T12:57:59.690091Z","iopub.execute_input":"2024-09-01T12:57:59.690826Z","iopub.status.idle":"2024-09-01T13:06:31.270031Z","shell.execute_reply.started":"2024-09-01T12:57:59.690789Z","shell.execute_reply":"2024-09-01T13:06:31.269156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define features and target\nfeatures = ['num_atoms', 'mol_weight']\ntarget = 'binds'\n\nX_train = train_df[features]\ny_train = train_df[target]\nX_test = test_df[features]\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T13:06:31.271239Z","iopub.execute_input":"2024-09-01T13:06:31.271617Z","iopub.status.idle":"2024-09-01T13:06:31.295978Z","shell.execute_reply.started":"2024-09-01T13:06:31.271568Z","shell.execute_reply":"2024-09-01T13:06:31.295052Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch_geometric.nn import GCNConv\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, roc_auc_score\nfrom sklearn.model_selection import train_test_split\nfrom xgboost import XGBClassifier\nfrom lightgbm import LGBMClassifier\nfrom sklearn.ensemble import RandomForestClassifier\nimport matplotlib.pyplot as plt\nimport time\n\ndef evaluate_model(y_true, y_pred, y_pred_proba):\n    return {\n        'accuracy': accuracy_score(y_true, y_pred),\n        'precision': precision_score(y_true, y_pred),\n        'recall': recall_score(y_true, y_pred),\n        'f1': f1_score(y_true, y_pred),\n        'auc': roc_auc_score(y_true, y_pred_proba)\n    }\n\n# Split data\nX_train_np, X_test_np, y_train_np, y_test_np = train_test_split(X_train.values, y_train.values, test_size=0.95, random_state=42)\n\n# Print data sizes\nprint(f\"Training data size: {len(X_train_np)}\")\nprint(f\"Test data size: {len(X_test_np)}\")\n\n# Convert data to tensors for GNN\nX_train_tensor = torch.tensor(X_train_np, dtype=torch.float32)\ny_train_tensor = torch.tensor(y_train_np.reshape(-1, 1), dtype=torch.float32)\nX_test_tensor = torch.tensor(X_test_np, dtype=torch.float32)\n\n# Improved GNN model\nclass ImprovedGNNModel(nn.Module):\n    def __init__(self, num_features, hidden_dim1, hidden_dim2, num_classes):\n        super(ImprovedGNNModel, self).__init__()\n        self.conv1 = GCNConv(num_features, hidden_dim1)\n        self.conv2 = GCNConv(hidden_dim1, hidden_dim2)\n        self.conv3 = GCNConv(hidden_dim2, num_classes)\n        self.batch_norm1 = nn.BatchNorm1d(hidden_dim1)\n        self.batch_norm2 = nn.BatchNorm1d(hidden_dim2)\n        self.dropout = nn.Dropout(0.3)\n\n    def forward(self, x, edge_index):\n        x = self.conv1(x, edge_index)\n        x = self.batch_norm1(x)\n        x = torch.relu(x)\n        x = self.dropout(x)\n        x = self.conv2(x, edge_index)\n        x = self.batch_norm2(x)\n        x = torch.relu(x)\n        x = self.dropout(x)\n        x = self.conv3(x, edge_index)\n        return torch.sigmoid(x)\n\n# Initialize improved GNN model\nnum_features = X_train_np.shape[1]\nhidden_dim1 = 64\nhidden_dim2 = 32\nnum_classes = 1  # Binary classification\n\nmodel = ImprovedGNNModel(num_features, hidden_dim1, hidden_dim2, num_classes)\n\n# Dummy edge index (assumed fully connected graph for simplicity)\nedge_index = torch.tensor([[i for i in range(len(X_train_np)) for _ in range(len(X_train_np))],\n                           [j for _ in range(len(X_train_np)) for j in range(len(X_train_np))]], dtype=torch.long)\n\n# Define loss function and optimizer\ncriterion = nn.BCELoss()\noptimizer = optim.Adam(model.parameters(), lr=0.001, weight_decay=1e-5)\n\n# Train the GNN model\nmodel.train()\ngnn_train_start = time.time()\nfor epoch in range(100):  # Increased number of epochs\n    optimizer.zero_grad()\n    output = model(X_train_tensor, edge_index)\n    loss = criterion(output, y_train_tensor)\n    loss.backward()\n    optimizer.step()\ngnn_train_time = time.time() - gnn_train_start\n\n# Evaluate GNN model\nmodel.eval()\ngnn_predict_start = time.time()\nwith torch.no_grad():\n    output = model(X_test_tensor, edge_index[:, :len(X_test_np)])\n    y_pred = (output > 0.5).float().numpy()\n    y_pred_proba = output.numpy()\ngnn_predict_time = time.time() - gnn_predict_start\n\ngnn_metrics = evaluate_model(y_test_np, y_pred, y_pred_proba)\n\n# Train and evaluate XGBoost\nxgb_model = XGBClassifier(random_state=42)\nxgb_train_start = time.time()\nxgb_model.fit(X_train_np, y_train_np)\nxgb_train_time = time.time() - xgb_train_start\n\nxgb_predict_start = time.time()\nxgb_pred = xgb_model.predict(X_test_np)\nxgb_pred_proba = xgb_model.predict_proba(X_test_np)[:, 1]\nxgb_predict_time = time.time() - xgb_predict_start\n\nxgb_metrics = evaluate_model(y_test_np, xgb_pred, xgb_pred_proba)\n\n# Train and evaluate LightGBM\nlgbm_model = LGBMClassifier(random_state=42)\nlgbm_train_start = time.time()\nlgbm_model.fit(X_train_np, y_train_np)\nlgbm_train_time = time.time() - lgbm_train_start\n\nlgbm_predict_start = time.time()\nlgbm_pred = lgbm_model.predict(X_test_np)\nlgbm_pred_proba = lgbm_model.predict_proba(X_test_np)[:, 1]\nlgbm_predict_time = time.time() - lgbm_predict_start\n\nlgbm_metrics = evaluate_model(y_test_np, lgbm_pred, lgbm_pred_proba)\n\n# Train and evaluate Random Forest\nrf_model = RandomForestClassifier(random_state=42)\nrf_train_start = time.time()\nrf_model.fit(X_train_np, y_train_np)\nrf_train_time = time.time() - rf_train_start\n\nrf_predict_start = time.time()\nrf_pred = rf_model.predict(X_test_np)\nrf_pred_proba = rf_model.predict_proba(X_test_np)[:, 1]\nrf_predict_time = time.time() - rf_predict_start\n\nrf_metrics = evaluate_model(y_test_np, rf_pred, rf_pred_proba)\n\n# Prepare data for visualization\nmodels = ['GNN', 'XGBoost', 'LightGBM', 'Random Forest']\nmetrics = ['accuracy', 'precision', 'recall', 'f1', 'auc']\nresults = np.array([\n    [gnn_metrics[m] for m in metrics],\n    [xgb_metrics[m] for m in metrics],\n    [lgbm_metrics[m] for m in metrics],\n    [rf_metrics[m] for m in metrics]\n])\n\n# Create bar plot for performance metrics\nfig, ax = plt.subplots(figsize=(12, 6))\nx = np.arange(len(metrics))\nwidth = 0.2\nmultiplier = 0\n\nfor attribute, measurement in zip(models, results):\n    offset = width * multiplier\n    rects = ax.bar(x + offset, measurement, width, label=attribute)\n    ax.bar_label(rects, fmt='%.2f', padding=3)\n    multiplier += 1\n\nax.set_ylabel('Scores')\nax.set_title('Model Performance Comparison')\nax.set_xticks(x + width, metrics)\nax.legend(loc='upper left', ncols=4)\nax.set_ylim(0, 1)\n\nplt.tight_layout()\nplt.show()\n\n# Prepare complexity metrics\ntrain_times = [gnn_train_time, xgb_train_time, lgbm_train_time, rf_train_time]\npredict_times = [gnn_predict_time, xgb_predict_time, lgbm_predict_time, rf_predict_time]\n\n\n# Create table for complexity metrics\ncomplexity_data = {\n    'Model': models,\n    'Training Time (s)': train_times,\n    'Prediction Time (s)': predict_times,\n}\n\n# Print complexity metrics table\nprint(\"\\nModel Complexity Metrics:\")\nprint(\"{:<15} {:<20} {:<20} {:<15}\".format('Model', 'Training Time (s)', 'Prediction Time (s)'))\nprint(\"-\" * 70)\nfor model, train_time, pred_time, size in zip(models, train_times, predict_times):\n    print(\"{:<15} {:<20.4f} {:<20.4f} {:<15}\".format(model, train_time, pred_time ))","metadata":{"execution":{"iopub.status.busy":"2024-09-01T13:06:31.297479Z","iopub.execute_input":"2024-09-01T13:06:31.297977Z","iopub.status.idle":"2024-09-01T13:21:32.256877Z","shell.execute_reply.started":"2024-09-01T13:06:31.297945Z","shell.execute_reply":"2024-09-01T13:21:32.255159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f\"Training data size: {len(X_train_np)}\")\nprint(f\"Test data size: {len(X_test_np)}\")","metadata":{"execution":{"iopub.status.busy":"2024-09-01T13:21:32.258392Z","iopub.status.idle":"2024-09-01T13:21:32.258926Z","shell.execute_reply.started":"2024-09-01T13:21:32.258668Z","shell.execute_reply":"2024-09-01T13:21:32.258689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Convert test data to tensor\nX_test_tensor = torch.tensor(X_test.values, dtype=torch.float32)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T13:21:32.260214Z","iopub.status.idle":"2024-09-01T13:21:32.260724Z","shell.execute_reply.started":"2024-09-01T13:21:32.260480Z","shell.execute_reply":"2024-09-01T13:21:32.260501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Make predictions on the test set\nwith torch.no_grad():\n    y_pred = model(X_test_tensor, edge_index).numpy().flatten()  # Flatten y_pred\n\n","metadata":{"execution":{"iopub.status.busy":"2024-09-01T13:21:32.261975Z","iopub.status.idle":"2024-09-01T13:21:32.262421Z","shell.execute_reply.started":"2024-09-01T13:21:32.262193Z","shell.execute_reply":"2024-09-01T13:21:32.262212Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create submission DataFrame\nsubmission_df = pd.DataFrame({'id': test_df['id'], 'binds': y_pred})\n\n# Save submission file\nsubmission_df.to_csv('submission_gnn.csv', index=False)\nsubmission_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-09-01T13:21:32.263811Z","iopub.status.idle":"2024-09-01T13:21:32.264146Z","shell.execute_reply.started":"2024-09-01T13:21:32.263983Z","shell.execute_reply":"2024-09-01T13:21:32.263997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}