{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":87793,"databundleVersionId":12276181,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom IPython.display import display\nimport itertools\nimport matplotlib.pyplot as plt\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras import Sequential, callbacks, regularizers\nfrom tensorflow.keras.losses import MeanSquaredError","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:18.499519Z","iopub.execute_input":"2025-05-19T12:29:18.500079Z","iopub.status.idle":"2025-05-19T12:29:34.987077Z","shell.execute_reply.started":"2025-05-19T12:29:18.500037Z","shell.execute_reply":"2025-05-19T12:29:34.986062Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data wrangling","metadata":{}},{"cell_type":"code","source":"# Load datasets:\ntrain_seq = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/train_sequences.csv\")\ntrain_lab = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/train_labels.csv\")\nval_seq = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/validation_sequences.csv\")\nval_lab = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/validation_labels.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:34.988340Z","iopub.execute_input":"2025-05-19T12:29:34.988959Z","iopub.status.idle":"2025-05-19T12:29:35.448900Z","shell.execute_reply.started":"2025-05-19T12:29:34.988926Z","shell.execute_reply":"2025-05-19T12:29:35.447940Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Quick look at the data:\nfor data in [train_seq, train_lab, val_seq, val_lab]:\n    display(data[:3])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:35.450656Z","iopub.execute_input":"2025-05-19T12:29:35.451046Z","iopub.status.idle":"2025-05-19T12:29:35.518585Z","shell.execute_reply.started":"2025-05-19T12:29:35.451017Z","shell.execute_reply":"2025-05-19T12:29:35.517374Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#removing resid-numbers from the IDs\nfor df in [train_lab, val_lab]:\n    df['ID'] = df['ID'].str.extract('(.*)_[\\d]+$')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:35.520250Z","iopub.execute_input":"2025-05-19T12:29:35.520657Z","iopub.status.idle":"2025-05-19T12:29:35.945171Z","shell.execute_reply.started":"2025-05-19T12:29:35.520626Z","shell.execute_reply":"2025-05-19T12:29:35.944135Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for data in [train_lab, val_lab]:\n    display(data[:3])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:35.946240Z","iopub.execute_input":"2025-05-19T12:29:35.946629Z","iopub.status.idle":"2025-05-19T12:29:35.981725Z","shell.execute_reply.started":"2025-05-19T12:29:35.946594Z","shell.execute_reply":"2025-05-19T12:29:35.980899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#cheching for 0 values in train_ and val_lab datasets:\nfor data in [train_lab, val_lab]:\n    display(data.isnull().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:35.982656Z","iopub.execute_input":"2025-05-19T12:29:35.982943Z","iopub.status.idle":"2025-05-19T12:29:36.032380Z","shell.execute_reply.started":"2025-05-19T12:29:35.982918Z","shell.execute_reply":"2025-05-19T12:29:36.031110Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"The **train_lab** (training labels) dataset has 6145 rows with empty x_1, y_1, z_1 coordinates 😱 <br /> \nLet's select sequences without empty coordinates:","metadata":{}},{"cell_type":"code","source":"#Checking for sequences with complete x_1, y_1, z_1 coordinates: \nnotempty_ids = []\nfor ID in train_lab.ID.unique():\n    x_1 = train_lab[train_lab.ID == ID].x_1\n    if x_1.notnull().all():\n        notempty_ids.append(ID)\n\nprint(f\"There are {len(notempty_ids)} sequences with complete x_1, y_1, z_1 coordinates.\")\n\n#selecting sequences with known x_1, y_1, z_1 coordinates:\ntrain_lab = train_lab[train_lab.ID.isin(notempty_ids)]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:36.033078Z","iopub.execute_input":"2025-05-19T12:29:36.033529Z","iopub.status.idle":"2025-05-19T12:29:46.071707Z","shell.execute_reply.started":"2025-05-19T12:29:36.033485Z","shell.execute_reply":"2025-05-19T12:29:46.070127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#checking if there are still nucleotides other than 'G', 'U', 'C', 'A':\ntrain_lab.resname.unique()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:46.075699Z","iopub.execute_input":"2025-05-19T12:29:46.076185Z","iopub.status.idle":"2025-05-19T12:29:46.090598Z","shell.execute_reply.started":"2025-05-19T12:29:46.076141Z","shell.execute_reply":"2025-05-19T12:29:46.089465Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Length selection","metadata":{}},{"cell_type":"code","source":"train_seq[:3] #just to have in front of the eyes","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:46.092632Z","iopub.execute_input":"2025-05-19T12:29:46.093087Z","iopub.status.idle":"2025-05-19T12:29:46.120831Z","shell.execute_reply.started":"2025-05-19T12:29:46.093042Z","shell.execute_reply":"2025-05-19T12:29:46.119894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#lenght distribution\n\nprint(train_seq.sequence.str.len().describe())\n\nplt.figure()\n_ = plt.hist(train_seq.sequence.str.len(), 300, log=True, range = (0, 300))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:46.121814Z","iopub.execute_input":"2025-05-19T12:29:46.122151Z","iopub.status.idle":"2025-05-19T12:29:47.100675Z","shell.execute_reply.started":"2025-05-19T12:29:46.122113Z","shell.execute_reply":"2025-05-19T12:29:47.099371Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"selected_length = 250 #slightly higer than mean","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:47.101900Z","iopub.execute_input":"2025-05-19T12:29:47.102195Z","iopub.status.idle":"2025-05-19T12:29:47.106982Z","shell.execute_reply.started":"2025-05-19T12:29:47.102169Z","shell.execute_reply":"2025-05-19T12:29:47.105752Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Operations on RNA sequences","metadata":{}},{"cell_type":"markdown","source":"**Train_** and **val_labels** have all information needed: <br />  \n - RNA `ID`'s;\n - coordinates `x_1`, `y_1`, `z_1`;\n - sequences can be built stepwise, nucleotide-by-nucleotide, from `resname`'s (using given ***selected_length***)\n\nTo save currecnt sequence, I'll add a `sequence` column to **train_** and **val_labels** .","metadata":{}},{"cell_type":"code","source":"#nucleotide encoding\ndef encode_sequence(resname):\n    mapping = {'A': 8, 'U': 2, 'G': 6, 'C': 4}\n    return mapping[resname]\n\ntrain_lab.resname = train_lab.resname.apply(encode_sequence)\nval_lab.resname = val_lab.resname.apply(encode_sequence)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:47.107968Z","iopub.execute_input":"2025-05-19T12:29:47.108239Z","iopub.status.idle":"2025-05-19T12:29:47.187038Z","shell.execute_reply.started":"2025-05-19T12:29:47.108216Z","shell.execute_reply":"2025-05-19T12:29:47.186149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#building stepwise (encoded) nucleotide sequence\ndef add_nucleotide_to_sequence(lab):\n\n    sequence = []\n    \n    for ID in lab.ID.unique():\n        \n        #defining how long the sequence should be (lenght defined before: selected_length)\n        #strating sequence has all encoded nucleotides as zeros\n        add_codon = np.zeros(selected_length,)\n        rows = lab[lab.ID == ID]\n        \n        # if sequence is smaller than selected_length:\n        for n in range(min(len(rows), selected_length)):\n            add_codon[n] = rows.resname.iloc[n]\n            sequence.append(add_codon.copy())\n            \n        # if sequence is larger than selected_length:\n        for n in range(selected_length, len(rows)):\n            add_codon[:-1] = add_codon[1:]\n            add_codon[-1] = rows.resname.iloc[n]\n            sequence.append(add_codon.copy())\n            \n    lab['sequence'] = sequence #addidng a sequence colum to save the current sequence\n\nadd_nucleotide_to_sequence(train_lab)\nadd_nucleotide_to_sequence(val_lab)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:47.188011Z","iopub.execute_input":"2025-05-19T12:29:47.188307Z","iopub.status.idle":"2025-05-19T12:29:54.503992Z","shell.execute_reply.started":"2025-05-19T12:29:47.188279Z","shell.execute_reply":"2025-05-19T12:29:54.503123Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_lab.head() #what it should look like","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:54.505104Z","iopub.execute_input":"2025-05-19T12:29:54.505500Z","iopub.status.idle":"2025-05-19T12:29:54.522580Z","shell.execute_reply.started":"2025-05-19T12:29:54.505469Z","shell.execute_reply":"2025-05-19T12:29:54.521477Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### My Normalization","metadata":{}},{"cell_type":"markdown","source":"By normalization, I mean the following:\n1. All RNA sequences should have the same starting point, which is 0;\n2. All RNA sequences should be in the same direction (e.g., the second nucleotide should have positive xyz coordinates);\n3. Scaling using MinMaxScaler","metadata":{}},{"cell_type":"code","source":"def normalizing_coords(lab):\n    \n    for ID in lab.ID.unique():\n        \n        for c in ['x_1', 'y_1', 'z_1']:\n            \n            #normalization_1: shifting xyz coordinates that the 1st coordinate is 0, rest accordinly\n            lab.loc[lab.ID == ID, c] -= lab.loc[lab.ID == ID, c].iloc[0]\n            # normalization_2: mirrowing if any 2nd xyz coordinate(s) is/are negative\n            lab.loc[lab.ID == ID, c] *= np.sign(lab.loc[lab.ID == ID, c].iloc[1])\n    \nnormalizing_coords(train_lab)\nnormalizing_coords(val_lab)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:29:54.523890Z","iopub.execute_input":"2025-05-19T12:29:54.524224Z","iopub.status.idle":"2025-05-19T12:31:01.681868Z","shell.execute_reply.started":"2025-05-19T12:29:54.524195Z","shell.execute_reply":"2025-05-19T12:31:01.680931Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_lab[:3]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:31:01.682876Z","iopub.execute_input":"2025-05-19T12:31:01.683173Z","iopub.status.idle":"2025-05-19T12:31:01.697424Z","shell.execute_reply.started":"2025-05-19T12:31:01.683148Z","shell.execute_reply":"2025-05-19T12:31:01.696315Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_train = np.array(train_lab.sequence.to_list())\ny_train = train_lab[['x_1','y_1','z_1']]\n\nx_val = np.array(val_lab.sequence.to_list())\ny_val = val_lab[['x_1','y_1','z_1']]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-19T12:31:01.698610Z","iopub.execute_input":"2025-05-19T12:31:01.699021Z","iopub.status.idle":"2025-05-19T12:31:01.876119Z","shell.execute_reply.started":"2025-05-19T12:31:01.698992Z","shell.execute_reply":"2025-05-19T12:31:01.874959Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# TensorFlow model","metadata":{}},{"cell_type":"code","source":"model = Sequential(\n    [ \n        Dense(512, activation='softplus'),\n        Dense(512, activation='softplus'),\n        Dense(256, activation='softplus'),\n        Dense(256, activation='softplus'),\n        Dense(128, activation='softplus'),\n        Dense(3, activation = 'softplus')\n    ]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:54:08.817842Z","iopub.execute_input":"2025-05-16T13:54:08.818215Z","iopub.status.idle":"2025-05-16T13:54:08.829753Z","shell.execute_reply.started":"2025-05-16T13:54:08.818184Z","shell.execute_reply":"2025-05-16T13:54:08.828736Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(loss = \"MeanSquaredError\",\n              optimizer=tf.keras.optimizers.AdamW(learning_rate=0.0005),\n              metrics=['accuracy']) \n   \nmodel.fit(\n     x_train, y_train,\n     validation_data = (x_val, y_val),\n     epochs = 100,\n     verbose = 0) \n\nprint(f\"Max validation accuracy: {(max(model.history.history['val_accuracy'])):.2f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-16T13:54:13.802883Z","iopub.execute_input":"2025-05-16T13:54:13.803211Z","iopub.status.idle":"2025-05-16T14:31:56.509527Z","shell.execute_reply.started":"2025-05-16T13:54:13.803185Z","shell.execute_reply":"2025-05-16T14:31:56.508226Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Prediction and sample submission","metadata":{}},{"cell_type":"code","source":"test = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/sample_submission.csv\")\ntest.head()","metadata":{"trusted":true,"execution":{"execution_failed":"2025-05-17T16:39:20.975Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test.ID = test.ID.str.extract('(.*)_[\\d]+$') #removing resid-numbers from the IDs\ntest.resname = test.resname.apply(encode_sequence) #encoding sequence\nadd_nucleotide_to_sequence(test) #building stepwise (encoded) nucleotide sequence","metadata":{"trusted":true,"execution":{"execution_failed":"2025-05-17T16:39:20.975Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x_test = np.array(test.sequence.to_list())\ny_test = model.predict(x_test)\n#y_test = scaler.inverse_transform(y_test)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_sub = pd.read_csv(\"/kaggle/input/stanford-rna-3d-folding/sample_submission.csv\")\n\nfor i in range(1, 6):\n    sample_sub[f\"x_{i}\"] = y_test[:,0]\n    sample_sub[f\"y_{i}\"] = y_test[:,1]\n    sample_sub[f\"z_{i}\"] = y_test[:,2]\n\n    if i == 1:\n        continue\n    sample_sub[f\"x_{i}\"] += np.random.uniform(0, 10)\n    sample_sub[f\"y_{i}\"] += np.random.uniform(0, 10)\n    sample_sub[f\"z_{i}\"] += np.random.uniform(0, 10)\n\nsample_sub","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_sub.to_csv(\"submission.csv\", index=False)\nprint(\"submission.csv file is created\")","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}