{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":10384,"databundleVersionId":120379,"sourceType":"competition"}],"dockerImageVersionId":31041,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# 📦 1. Imports\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report, confusion_matrix\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, Dropout, BatchNormalization, GRU, Bidirectional, GlobalMaxPooling1D, GaussianNoise, Concatenate\nfrom tensorflow.keras.optimizers import Adam\nimport numpy as np\nimport pandas as pd\nfrom sklearn.preprocessing import PowerTransformer\n\n# 📂 2. Load Data (Replace with correct Kaggle paths)\ntrain_meta = pd.read_csv(\"/kaggle/input/PLAsTiCC-2018/training_set_metadata.csv\")\ntrain_lc = pd.read_csv(\"/kaggle/input/PLAsTiCC-2018/training_set.csv\")\n# /kaggle/input/PLAsTiCC-2018\n\n# ✨ Add the rest of the code from previous cells (Preprocessing + Models + Training + Confusion Matrix)\n# Due to message limits, let me know if you'd like the remaining 150+ lines again — I'll send them in chunks.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-20T21:06:42.088097Z","iopub.execute_input":"2025-05-20T21:06:42.088394Z","iopub.status.idle":"2025-05-20T21:06:58.044023Z","shell.execute_reply.started":"2025-05-20T21:06:42.088329Z","shell.execute_reply":"2025-05-20T21:06:58.043415Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom sklearn.preprocessing import PowerTransformer\n\n# 3DSubM Preprocessing\ndef preprocess_3dsubm(lc_df, max_seq_len=162):\n    lc_df = lc_df.copy()\n    lc_df['flux'] += np.random.normal(0, lc_df['flux_err'] * 2 / 3)\n    flux_max, flux_min = lc_df['flux'].max(), lc_df['flux'].min()\n    flux_scaler = 1 / np.log2(flux_max - flux_min + 1)\n    lc_df['flux'] *= flux_scaler\n    lc_df['mjd'] = lc_df.groupby('object_id')['mjd'].transform(lambda x: x - x.min())\n\n    grouped_sequences = {}\n    for obj_id, group in lc_df.groupby('object_id'):\n        sequence, night_buffer, current_night = [], {}, -10\n        for _, row in group.sort_values('mjd').iterrows():\n            if row['mjd'] - current_night > 0.33:\n                if night_buffer:\n                    sequence.append([night_buffer.get(pb, np.nan) for pb in range(6)])\n                night_buffer = {}\n                current_night = row['mjd']\n            night_buffer[row['passband']] = row['flux']\n        if night_buffer:\n            sequence.append([night_buffer.get(pb, np.nan) for pb in range(6)])\n\n        df_seq = pd.DataFrame(sequence).interpolate(axis=1).fillna(0)\n        seq_array = df_seq.values.tolist()\n        if len(seq_array) < max_seq_len:\n            seq_array += [[0]*6] * (max_seq_len - len(seq_array))\n        grouped_sequences[obj_id] = np.array(seq_array[:max_seq_len])\n\n    return grouped_sequences\n\n\n# 2DSubM Preprocessing\ndef extract_aggregated_features(lc_df):\n    features = []\n    for obj_id, group in lc_df.groupby(\"object_id\"):\n        obj_feats = {\"object_id\": obj_id}\n        for pb in range(6):\n            pb_data = group[group[\"passband\"] == pb]\n            obj_feats[f\"flux_mean_pb{pb}\"] = pb_data[\"flux\"].mean()\n            obj_feats[f\"flux_std_pb{pb}\"] = pb_data[\"flux\"].std()\n            obj_feats[f\"flux_max_pb{pb}\"] = pb_data[\"flux\"].max()\n            obj_feats[f\"flux_min_pb{pb}\"] = pb_data[\"flux\"].min()\n        features.append(obj_feats)\n    return pd.DataFrame(features)\n\n\ndef preprocess_2dsubm(lc_df, meta_df):\n    agg_feats = extract_aggregated_features(lc_df)\n    combined = pd.merge(agg_feats, meta_df, on=\"object_id\")\n    drop_cols = ['object_id', 'ra', 'decl', 'gal_l', 'gal_b']\n    combined = combined.drop(columns=[col for col in drop_cols if col in combined.columns], errors='ignore')\n    combined = combined.fillna(0)\n    pt = PowerTransformer()\n    combined_scaled = pd.DataFrame(pt.fit_transform(combined), columns=combined.columns)\n    return combined_scaled","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T21:06:58.045302Z","iopub.execute_input":"2025-05-20T21:06:58.045571Z","iopub.status.idle":"2025-05-20T21:06:58.056497Z","shell.execute_reply.started":"2025-05-20T21:06:58.045550Z","shell.execute_reply":"2025-05-20T21:06:58.055796Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 📦 Import model layers\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, Dropout, BatchNormalization, GRU, Bidirectional, GlobalMaxPooling1D, GaussianNoise, Concatenate\nfrom tensorflow.keras.optimizers import Adam\n\n# 🧠 3DSubM: GRU-based model\ndef build_3dsubm_model(input_shape=(162, 6), num_classes=15):\n    inp = Input(shape=input_shape)\n    x = GaussianNoise(0.5)(inp)\n    x = Bidirectional(GRU(256, return_sequences=True, activation='tanh'))(x)\n    x = Dropout(0.1)(x)\n    x = Bidirectional(GRU(64, return_sequences=True, activation='tanh'))(x)\n    x = Dropout(0.1)(x)\n    x = Bidirectional(GRU(32, return_sequences=True, activation='tanh'))(x)\n    x = Dropout(0.1)(x)\n    x = Bidirectional(GRU(32, return_sequences=True, activation='tanh'))(x)\n    x = Dropout(0.1)(x)\n    x = GlobalMaxPooling1D()(x)\n    x = Dense(1024, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    x = Dense(256, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    x = Dense(64, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    x = Dense(32, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    out = Dense(num_classes, activation='softmax')(x)\n    model = Model(inputs=inp, outputs=out)\n    model.compile(optimizer=Adam(learning_rate=0.001), loss='categorical_crossentropy', metrics=['accuracy'])\n    return model\n\n# 🧠 2DSubM: Dense model\ndef build_2dsubm_model(input_shape, num_classes=15):\n    inp = Input(shape=input_shape)\n    x = Dense(512, activation='tanh')(inp)\n    x = Dropout(0.1)(x)\n    x = BatchNormalization()(x)\n    x = Dense(128, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    x = BatchNormalization()(x)\n    x = Dense(128, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    x = BatchNormalization()(x)\n    x = Dense(64, activation='tanh')(x)\n    x = Dropout(0.1)(x)\n    x = BatchNormalization()(x)\n    out = Dense(num_classes, activation='softmax')(x)\n    model = Model(inputs=inp, outputs=out)\n    model.compile(optimizer=Adam(learning_rate=0.01), loss='categorical_crossentropy', metrics=['accuracy'])\n    return model\n\n# 🔀 Stacking Ensemble\ndef build_stacked_ensemble(three_d_model, two_d_model, num_classes=15):\n    for layer in three_d_model.layers:\n        layer.trainable = False\n    for layer in two_d_model.layers:\n        layer.trainable = False\n\n    input_3d = Input(shape=(162, 6))\n    input_2d = Input(shape=(two_d_model.input_shape[1],))\n    output_3d = three_d_model(input_3d)\n    output_2d = two_d_model(input_2d)\n    x = Concatenate()([output_3d, output_2d])\n    x = Dense(10, activation='relu')(x)\n    final_output = Dense(num_classes, activation='softmax')(x)\n\n    model = Model(inputs=[input_3d, input_2d], outputs=final_output)\n    model.compile(optimizer=Adam(), loss='categorical_crossentropy', metrics=['accuracy'])\n    return model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T21:06:58.057152Z","iopub.execute_input":"2025-05-20T21:06:58.057469Z","iopub.status.idle":"2025-05-20T21:06:58.074492Z","shell.execute_reply.started":"2025-05-20T21:06:58.057451Z","shell.execute_reply":"2025-05-20T21:06:58.073941Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 🔄 Preprocess input data\nseqs = preprocess_3dsubm(train_lc)\nX_seq = np.stack([seqs[oid] for oid in train_meta[\"object_id\"] if oid in seqs])\n\nX_dense_df = preprocess_2dsubm(train_lc, train_meta)\nX_dense_df = X_dense_df.loc[train_meta[\"object_id\"].isin(seqs)]\nX_dense = X_dense_df.values\n\n# 🎯 Encode labels dynamically\nfrom tensorflow.keras.utils import to_categorical\n\nlabel_map = {val: idx for idx, val in enumerate(sorted(train_meta['target'].unique()))}\ntrain_meta[\"target_id\"] = train_meta[\"target\"].map(label_map)\ny = to_categorical(train_meta.loc[train_meta[\"object_id\"].isin(seqs), \"target_id\"])\n\n# Automatically match number of classes\nnum_classes = y.shape[1]\n\n# ✂ 85:15 Train-validation split\nfrom sklearn.model_selection import train_test_split\n\nX_seq_train, X_seq_val, X_dense_train, X_dense_val, y_train, y_val = train_test_split(\n    X_seq, X_dense, y, test_size=0.15, random_state=42\n)\n\n# 🧠 Train base models with correct output size\nmodel_3d = build_3dsubm_model(num_classes=num_classes)\nmodel_2d = build_2dsubm_model(input_shape=X_dense.shape[1:], num_classes=num_classes)\n\nmodel_3d.fit(X_seq_train, y_train, epochs=5, batch_size=128, validation_split=0.1, verbose=2)\nmodel_2d.fit(X_dense_train, y_train, epochs=5, batch_size=128, validation_split=0.1, verbose=2)\n\n# 🔀 Train stacking ensemble\nensemble = build_stacked_ensemble(model_3d, model_2d, num_classes=num_classes)\nensemble.fit([X_seq_train, X_dense_train], y_train, epochs=5, batch_size=128, validation_split=0.1, verbose=2)\n\n# 📊 Evaluate on validation set\nfrom sklearn.metrics import classification_report, confusion_matrix\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\ny_pred = ensemble.predict([X_seq_val, X_dense_val])\ny_true = np.argmax(y_val, axis=1)\ny_pred_class = np.argmax(y_pred, axis=1)\n\n# Confusion matrix\ncm = confusion_matrix(y_true, y_pred_class)\nplt.figure(figsize=(12, 8))\nsns.heatmap(cm, annot=False, cmap=\"Blues\")\nplt.title(\"Confusion Matrix on Validation Set\")\nplt.xlabel(\"Predicted\")\nplt.ylabel(\"True\")\nplt.show()\n\n# Detailed report\nprint(classification_report(y_true, y_pred_class))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T21:06:58.075913Z","iopub.execute_input":"2025-05-20T21:06:58.076149Z","iopub.status.idle":"2025-05-20T21:09:59.033440Z","shell.execute_reply.started":"2025-05-20T21:06:58.076132Z","shell.execute_reply":"2025-05-20T21:09:59.032716Z"}},"outputs":[],"execution_count":null}]}