{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":20182,"databundleVersionId":1117628,"sourceType":"competition"}],"dockerImageVersionId":31236,"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,"execution":{"iopub.status.busy":"2026-01-13T11:58:05.119625Z","iopub.execute_input":"2026-01-13T11:58:05.119870Z","iopub.status.idle":"2026-01-13T11:58:05.408545Z","shell.execute_reply.started":"2026-01-13T11:58:05.119845Z","shell.execute_reply":"2026-01-13T11:58:05.407706Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"\n- In the first notebook ([Gene Expression prediction (Baseline + 1D CNN)](http://www.kaggle.com/code/mariamali12/gene-expression-prediction-baseline-1d-cnn)), we built a 1D CNN model to predict the gene expression using histone markers as a feature.\n  \n- In this notebook, we will extend our work and try to improve our model performance using an additional feature (cell type)\n\n- What we are trying to answer in this notebook is could adding cell type info improve the model performance? \n  ","metadata":{}},{"cell_type":"markdown","source":"# Libraries Importing ","metadata":{}},{"cell_type":"code","source":"import random\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.linear_model import Ridge\nfrom sklearn.metrics import mean_squared_error, r2_score\nfrom sklearn.preprocessing import StandardScaler\nimport tensorflow as tf\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Embedding, Concatenate, Conv1D, MaxPooling1D, Flatten, Dense, Dropout, GlobalAveragePooling1D, BatchNormalization\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.regularizers import l2","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:05.409513Z","iopub.execute_input":"2026-01-13T11:58:05.409947Z","iopub.status.idle":"2026-01-13T11:58:08.940084Z","shell.execute_reply.started":"2026-01-13T11:58:05.409918Z","shell.execute_reply":"2026-01-13T11:58:08.939459Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Set Random seeds\nSEED = 42\n\nos.environ[\"PYTHONHASHSEED\"] = str(SEED)\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:08.940975Z","iopub.execute_input":"2026-01-13T11:58:08.941427Z","iopub.status.idle":"2026-01-13T11:58:08.945681Z","shell.execute_reply.started":"2026-01-13T11:58:08.941394Z","shell.execute_reply":"2026-01-13T11:58:08.944992Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Exploring Datasets","metadata":{}},{"cell_type":"code","source":"#Load training dataset\ntrain_data = np.load('/kaggle/input/gene-expression-prediction-cs1850-final/train.npz')\nlen(train_data.files)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:08.946645Z","iopub.execute_input":"2026-01-13T11:58:08.946985Z","iopub.status.idle":"2026-01-13T11:58:08.971379Z","shell.execute_reply.started":"2026-01-13T11:58:08.946962Z","shell.execute_reply":"2026-01-13T11:58:08.970770Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Load testing dataset\neval_data = np.load('/kaggle/input/gene-expression-prediction-cs1850-final/eval.npz')\nlen(eval_data.files)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:08.972150Z","iopub.execute_input":"2026-01-13T11:58:08.972370Z","iopub.status.idle":"2026-01-13T11:58:08.983174Z","shell.execute_reply.started":"2026-01-13T11:58:08.972349Z","shell.execute_reply":"2026-01-13T11:58:08.982489Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(train_data['E065'][:,:,6])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:08.985235Z","iopub.execute_input":"2026-01-13T11:58:08.985671Z","iopub.status.idle":"2026-01-13T11:58:09.141886Z","shell.execute_reply.started":"2026-01-13T11:58:08.985650Z","shell.execute_reply":"2026-01-13T11:58:09.141151Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Training dataset structure:\n- **First column:** gene ID\n- **Second-sixth columns:** histone modification measurements\n- **Seventh column:** gene expression\n\n### Each cell type contains:\n- 16000 genes\n- 100 bins\n- 5 histone markers\n- Each gene–cell pair is treated as an independent training example.","metadata":{}},{"cell_type":"code","source":"# Keys to npzfile of train & eval\ntrain_cells = ['E065', 'E004', 'E066', 'E005', 'E012', 'E027', 'E053', 'E013', 'E028', 'E061', 'E109', 'E120',\n               'E062', 'E037', 'E038', 'E024', 'E105', 'E011', 'E106', 'E082', 'E097', 'E116', 'E098', 'E058', \n'E117', 'E059', 'E070', 'E118', 'E085', 'E104', 'E119', 'E006', 'E127', 'E047', 'E094', 'E007', 'E054', 'E128',\n               'E095', 'E055', 'E114', 'E100', 'E056', 'E016', 'E122', 'E057', 'E123', 'E079', 'E003', 'E050']\nTcell_to_id = {cell: idx for idx, cell in enumerate(train_cells)}\nTnum_cells = len(Tcell_to_id)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:09.142734Z","iopub.execute_input":"2026-01-13T11:58:09.143017Z","iopub.status.idle":"2026-01-13T11:58:09.148239Z","shell.execute_reply.started":"2026-01-13T11:58:09.142981Z","shell.execute_reply":"2026-01-13T11:58:09.147652Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"eval_cells = ['E065', 'E004', 'E066', 'E005', 'E012', 'E027', 'E053', 'E013', 'E028', 'E061', 'E109', 'E120', \n              'E062', 'E037', 'E038', 'E024', 'E071', 'E105', 'E087', 'E011', 'E106', 'E096', 'E082', 'E097', \n'E116', 'E098', 'E058', 'E117', 'E084', 'E059', 'E070', 'E118', 'E085', 'E104', 'E119', 'E006', 'E112', 'E127',\n              'E047', 'E094', 'E007', 'E054', 'E113', 'E128', 'E095', 'E055', 'E114', 'E100', 'E056', 'E016', 'E122',\n              'E057', 'E123', 'E079', 'E003', 'E050']\nEcell_to_id = {cell: idx for idx, cell in enumerate(eval_cells)}\nEnum_cells = len(Ecell_to_id)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:09.149141Z","iopub.execute_input":"2026-01-13T11:58:09.149437Z","iopub.status.idle":"2026-01-13T11:58:09.162696Z","shell.execute_reply.started":"2026-01-13T11:58:09.149389Z","shell.execute_reply":"2026-01-13T11:58:09.162046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Combine Train Data to use information from all cells\ntrain_inputs = [] # histone mark data (X)\ntrain_outputs = [] # expression value (y)\nTcell_id_list = []\nfor cell in train_cells:\n    cell_data = train_data[cell]\n    hm_data = cell_data[:,:,1:6]\n    exp_values = cell_data[:,0,6]\n    cell_ids = np.full(len(exp_values), Tcell_to_id[cell])\n    train_inputs.append(hm_data)\n    train_outputs.append(exp_values)\n    Tcell_id_list.append(cell_ids)\n\ntrain_inputs = np.concatenate(train_inputs, axis=0)\ntrain_outputs = np.concatenate(train_outputs, axis=0)\nTcell_ids = np.concatenate(Tcell_id_list, axis=0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:09.163468Z","iopub.execute_input":"2026-01-13T11:58:09.163642Z","iopub.status.idle":"2026-01-13T11:58:17.624244Z","shell.execute_reply.started":"2026-01-13T11:58:09.163625Z","shell.execute_reply":"2026-01-13T11:58:17.623440Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(train_inputs.shape)\nprint(train_outputs.shape)\nprint(Tcell_ids.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:17.625250Z","iopub.execute_input":"2026-01-13T11:58:17.625960Z","iopub.status.idle":"2026-01-13T11:58:17.629644Z","shell.execute_reply.started":"2026-01-13T11:58:17.625921Z","shell.execute_reply":"2026-01-13T11:58:17.628946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prepare Eval inputs in a similar way\neval_X = []\neval_cell_ids = []\neval_ids = []\n\nfor cell in eval_data.files:\n    cell_array = eval_data[cell]\n    \n    X_cell = cell_array[:, :, 1:6]\n    genes = cell_array[:, 0, 0].astype(int)\n    \n    eval_X.append(X_cell)\n    eval_cell_ids.append(\n        np.full(len(genes), Ecell_to_id[cell])\n    )\n    \n    eval_ids.extend([f\"{cell}_{g}\" for g in genes])\n\neval_X = np.concatenate(eval_X)\neval_cell_ids = np.concatenate(eval_cell_ids)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:17.630416Z","iopub.execute_input":"2026-01-13T11:58:17.630611Z","iopub.status.idle":"2026-01-13T11:58:19.712986Z","shell.execute_reply.started":"2026-01-13T11:58:17.630592Z","shell.execute_reply":"2026-01-13T11:58:19.712357Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(eval_X.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:19.713841Z","iopub.execute_input":"2026-01-13T11:58:19.714060Z","iopub.status.idle":"2026-01-13T11:58:19.718244Z","shell.execute_reply.started":"2026-01-13T11:58:19.714038Z","shell.execute_reply":"2026-01-13T11:58:19.717494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#explore the expression values statistically\n\nprint(\"Mean:\", np.mean(train_outputs))\nprint(\"Std:\", np.std(train_outputs))\nprint(\"Min:\", np.min(train_outputs))\nprint(\"Max:\", np.max(train_outputs))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:19.719115Z","iopub.execute_input":"2026-01-13T11:58:19.719388Z","iopub.status.idle":"2026-01-13T11:58:19.738745Z","shell.execute_reply.started":"2026-01-13T11:58:19.719351Z","shell.execute_reply":"2026-01-13T11:58:19.738069Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model Building","metadata":{}},{"cell_type":"markdown","source":"# Build 1D CNN model","metadata":{}},{"cell_type":"code","source":"X = train_inputs\ny = train_outputs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:19.739837Z","iopub.execute_input":"2026-01-13T11:58:19.740575Z","iopub.status.idle":"2026-01-13T11:58:19.743949Z","shell.execute_reply.started":"2026-01-13T11:58:19.740552Z","shell.execute_reply":"2026-01-13T11:58:19.743230Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#scaling the target\nscaler = StandardScaler()\ny_scaled = scaler.fit_transform(y.reshape(-1, 1)).flatten()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:19.745090Z","iopub.execute_input":"2026-01-13T11:58:19.745306Z","iopub.status.idle":"2026-01-13T11:58:19.767055Z","shell.execute_reply.started":"2026-01-13T11:58:19.745277Z","shell.execute_reply":"2026-01-13T11:58:19.766243Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"type(y_scaled)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:19.767871Z","iopub.execute_input":"2026-01-13T11:58:19.768079Z","iopub.status.idle":"2026-01-13T11:58:19.772741Z","shell.execute_reply.started":"2026-01-13T11:58:19.768059Z","shell.execute_reply":"2026-01-13T11:58:19.772052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#train/validate split\nX_train, X_val, y_train, y_val, cell_train, cell_val= train_test_split(X, y_scaled, Tcell_ids, test_size=0.2, random_state=SEED)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:19.773499Z","iopub.execute_input":"2026-01-13T11:58:19.773697Z","iopub.status.idle":"2026-01-13T11:58:20.356681Z","shell.execute_reply.started":"2026-01-13T11:58:19.773679Z","shell.execute_reply":"2026-01-13T11:58:20.356111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Functional CNN\n\nsignal_input = Input(shape=(100, 5), name=\"histone_input\")\n\nx = Conv1D(32, kernel_size=5, padding=\"same\", activation=\"relu\")(signal_input)\nx = Conv1D(64, kernel_size=5, padding=\"same\", activation=\"relu\")(x)\nx = MaxPooling1D(pool_size=2)(x)\n\nx = Conv1D(128, kernel_size=7, padding=\"same\", activation=\"relu\")(x)\nx = GlobalAveragePooling1D()(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:20.357606Z","iopub.execute_input":"2026-01-13T11:58:20.357902Z","iopub.status.idle":"2026-01-13T11:58:21.470326Z","shell.execute_reply.started":"2026-01-13T11:58:20.357876Z","shell.execute_reply":"2026-01-13T11:58:21.469603Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#encoding cell-type code using embedding\ncell_input = Input(shape=(1,), name=\"cell_id\")\n\ncell_embed = Embedding(\n    input_dim=Enum_cells,\n    output_dim=32,\n    name=\"cell_embedding\"\n)(cell_input)\n\ncell_embed = Flatten()(cell_embed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:21.471338Z","iopub.execute_input":"2026-01-13T11:58:21.471568Z","iopub.status.idle":"2026-01-13T11:58:21.482108Z","shell.execute_reply.started":"2026-01-13T11:58:21.471547Z","shell.execute_reply":"2026-01-13T11:58:21.481564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# combine the 2 models\n\ncombined = Concatenate()([x, cell_embed])\n\ncombined = Dense(256, activation=\"relu\")(combined)\ncombined = Dropout(0.3)(combined)\n\noutput = Dense(1, activation=\"linear\")(combined)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:21.482874Z","iopub.execute_input":"2026-01-13T11:58:21.483167Z","iopub.status.idle":"2026-01-13T11:58:21.506284Z","shell.execute_reply.started":"2026-01-13T11:58:21.483146Z","shell.execute_reply":"2026-01-13T11:58:21.505809Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Final model\n\nmodel = Model(\n    inputs=[signal_input, cell_input],\n    outputs=output\n)\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=5e-4),\n    loss=\"mse\",\n    metrics=[\"mse\"]\n)\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:21.508674Z","iopub.execute_input":"2026-01-13T11:58:21.508990Z","iopub.status.idle":"2026-01-13T11:58:21.540159Z","shell.execute_reply.started":"2026-01-13T11:58:21.508969Z","shell.execute_reply":"2026-01-13T11:58:21.539592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"early_stop = EarlyStopping(\n    monitor='val_loss',\n    patience=3,   \n    restore_best_weights=True\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:21.540898Z","iopub.execute_input":"2026-01-13T11:58:21.541132Z","iopub.status.idle":"2026-01-13T11:58:21.544579Z","shell.execute_reply.started":"2026-01-13T11:58:21.541113Z","shell.execute_reply":"2026-01-13T11:58:21.544004Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#train \n\nhistory = model.fit(\n    [X_train, cell_train],y_train,\n    validation_data=([X_val, cell_val], y_val),\n    epochs=30,\n    batch_size=64,\n    callbacks=[early_stop],\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T11:58:21.545373Z","iopub.execute_input":"2026-01-13T11:58:21.545558Z","iopub.status.idle":"2026-01-13T12:05:56.386591Z","shell.execute_reply.started":"2026-01-13T11:58:21.545540Z","shell.execute_reply":"2026-01-13T12:05:56.385953Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model Evaluation ","metadata":{}},{"cell_type":"code","source":"y_val_pred_scaled = model.predict([X_val, cell_val]).flatten()\n\ny_val_pred = scaler.inverse_transform(\n    y_val_pred_scaled.reshape(-1,1)\n).flatten()\n\ny_val_true = scaler.inverse_transform(\n    y_val.reshape(-1,1)\n).flatten()\n\nmse = mean_squared_error(y_val_true, y_val_pred)\nr2 = r2_score(y_val_true, y_val_pred)\n\nprint(f\"MSE: {mse:.3f}\")\nprint(f\"R²: {r2:.3f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T12:05:56.387598Z","iopub.execute_input":"2026-01-13T12:05:56.387912Z","iopub.status.idle":"2026-01-13T12:06:07.497116Z","shell.execute_reply.started":"2026-01-13T12:05:56.387875Z","shell.execute_reply":"2026-01-13T12:06:07.496387Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Prediction and Submission ","metadata":{}},{"cell_type":"code","source":"eval_preds_scaled = model.predict([eval_X, eval_cell_ids]).flatten()\neval_preds = scaler.inverse_transform(\n    eval_preds_scaled.reshape(-1,1)\n).flatten()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T12:06:07.498088Z","iopub.execute_input":"2026-01-13T12:06:07.498392Z","iopub.status.idle":"2026-01-13T12:06:20.028635Z","shell.execute_reply.started":"2026-01-13T12:06:07.498360Z","shell.execute_reply":"2026-01-13T12:06:20.027873Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"id\": eval_ids,\n    \"expression\": eval_preds\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-13T12:06:20.029614Z","iopub.execute_input":"2026-01-13T12:06:20.029888Z","iopub.status.idle":"2026-01-13T12:06:20.310451Z","shell.execute_reply.started":"2026-01-13T12:06:20.029865Z","shell.execute_reply":"2026-01-13T12:06:20.309838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}