{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.11.13"},"colab":{"name":"ML LEAGUE 04  FINAL","provenance":[]},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":113366,"databundleVersionId":13605326,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## 1. Text Cleaning 🧹\n- ✨ Function: `clean_text(text: str)`\n- 📉 Remove links, images, and special chars\n- 🔡 Convert text to lowercase","metadata":{}},{"cell_type":"code","source":"import re\nimport string\n\ndef clean_text(text: str):\n    text = text.lower()\n    text = re.sub(r'http\\S+|www\\S+|https\\S+', '', text, flags=re.MULTILINE)\n    text = re.sub(r'\\S+\\.(jpg|jpeg|png|gif|bmp|svg)', '', text, flags=re.IGNORECASE)\n    text=re.sub(r\"[^a-zA-Z0-9\\s.,!?;:'\\\"-]\", \"\", text)\n    text = re.sub(r'\\s+', ' ', text).strip()\n\n    return text","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.status.busy":"2025-09-17T18:11:46.487546Z","iopub.execute_input":"2025-09-17T18:11:46.488169Z","iopub.status.idle":"2025-09-17T18:11:46.496188Z","shell.execute_reply.started":"2025-09-17T18:11:46.488125Z","shell.execute_reply":"2025-09-17T18:11:46.495438Z"},"id":"cG0ygjQm0sSo","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. Data Loading & Preprocessing 📊\n- 📥 Load dataset with `pandas`\n- 🧼 Clean comments using `tqdm.progress_apply`\n- 📊 Visualize label distribution with `seaborn.countplot`","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nfrom tqdm import tqdm\nimport seaborn as sns\ntqdm.pandas()\n\ndf=pd.read_csv(\"/kaggle/input/comments-classification/Dataset/train.csv\")\ndf[\"clean_text\"]=df['comment_text'].progress_apply(clean_text)\n\nplot = sns.countplot(x=df['psychotic_depression'], data=df)\nprint(df['psychotic_depression'].value_counts())","metadata":{"execution":{"iopub.status.busy":"2025-09-17T18:11:47.914841Z","iopub.execute_input":"2025-09-17T18:11:47.915665Z","iopub.status.idle":"2025-09-17T18:12:01.525251Z","shell.execute_reply.started":"2025-09-17T18:11:47.915637Z","shell.execute_reply":"2025-09-17T18:12:01.524338Z"},"id":"AZHpXwPN0sSp","outputId":"265203f4-d896-4f4b-a413-e52e41d37e1d","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.head()","metadata":{"execution":{"iopub.status.busy":"2025-09-17T18:12:01.526503Z","iopub.execute_input":"2025-09-17T18:12:01.526737Z","iopub.status.idle":"2025-09-17T18:12:01.548206Z","shell.execute_reply.started":"2025-09-17T18:12:01.526719Z","shell.execute_reply":"2025-09-17T18:12:01.547500Z"},"id":"hGDAYJ1X0sSq","outputId":"62389f24-579a-4d8f-b0e5-09dcb8be52ed","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"markdown","source":"\n## 3. Train-Test Split ✂️\n- 🔀 `train_test_split` for training and validation sets","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nX=df['clean_text']\ny=df['psychotic_depression']\nX_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.2, random_state=42\n)","metadata":{"execution":{"iopub.status.busy":"2025-09-17T18:12:03.343488Z","iopub.execute_input":"2025-09-17T18:12:03.343811Z","iopub.status.idle":"2025-09-17T18:12:03.620419Z","shell.execute_reply.started":"2025-09-17T18:12:03.343787Z","shell.execute_reply":"2025-09-17T18:12:03.619701Z"},"id":"hWcicURP0sSr","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. Tokenization & Padding 🔢\n- 🧾 `Tokenizer` to convert words → sequences\n- 📏 `pad_sequences` to ensure uniform length","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.preprocessing.text import Tokenizer\nfrom tensorflow.keras.preprocessing.sequence import pad_sequences\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Embedding, Bidirectional, LSTM, Dense, Dropout, GlobalAveragePooling1D, Attention\n\n\nvocab_size = 12000\nmax_len = 200\nembedding_dim = 200\n\ntokenizer = Tokenizer(num_words=vocab_size, oov_token=\"<OOV>\")\ntokenizer.fit_on_texts(X_train)\n\nX_train_seq = tokenizer.texts_to_sequences(X_train)\nX_test_seq = tokenizer.texts_to_sequences(X_test)\n\nX_train_pad = pad_sequences(X_train_seq, maxlen=max_len, padding='post')\nX_test_pad = pad_sequences(X_test_seq, maxlen=max_len, padding='post')","metadata":{"execution":{"iopub.status.busy":"2025-09-17T18:12:04.112272Z","iopub.execute_input":"2025-09-17T18:12:04.112560Z","iopub.status.idle":"2025-09-17T18:12:31.334866Z","shell.execute_reply.started":"2025-09-17T18:12:04.112540Z","shell.execute_reply":"2025-09-17T18:12:31.333911Z"},"id":"ToV3lig-0sSr","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5. Model Architecture 🧠\n- 🟢 Input Layer\n- 🔤 Embedding Layer\n- 🔄 BiLSTM Layers (stacked)\n- 🎯 Attention Mechanism\n- 📉 GlobalAveragePooling\n- 🔷 Dense + Dropout\n- 🏁 Output Layer (sigmoid)","metadata":{}},{"cell_type":"code","source":"\ninputs = Input(shape=(max_len,))\n\n# Embedding Layer\nx = Embedding(input_dim=vocab_size, output_dim=embedding_dim, input_length=max_len)(inputs)\n\n# BiLSTM stack\nx = Bidirectional(LSTM(128, return_sequences=True, dropout=0.3, recurrent_dropout=0.3))(x)\nx = Bidirectional(LSTM(64, return_sequences=True, dropout=0.3, recurrent_dropout=0.3))(x)\n\n# Attention\nattention_out = Attention()([x, x])\n\n# Pooling\nx = GlobalAveragePooling1D()(attention_out)\n\n# Dense + Dropout\nx = Dense(128, activation=\"relu\")(x)\nx = Dropout(0.5)(x)\n\n# Output layer\noutputs = Dense(1, activation=\"sigmoid\")(x)\n\n# Build model\nmodel = Model(inputs, outputs)\n","metadata":{"execution":{"iopub.status.busy":"2025-09-17T18:12:31.336235Z","iopub.execute_input":"2025-09-17T18:12:31.336850Z","iopub.status.idle":"2025-09-17T18:12:34.172817Z","shell.execute_reply.started":"2025-09-17T18:12:31.336826Z","shell.execute_reply":"2025-09-17T18:12:34.172080Z"},"id":"A0-yF0YD0sSs","outputId":"1ebea4e3-3a6a-47c7-fe54-0a1407edbf8b","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 6. Model Compilation ⚙️\n- 🚀 Optimizer: Adam (lr=1e-3)\n- ❌ Loss: Binary Crossentropy\n- ✅ Metric: Accuracy\n","metadata":{}},{"cell_type":"code","source":"\n# Compile\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),\n    loss=\"binary_crossentropy\",\n    metrics=[\"accuracy\"]\n)\n\nmodel.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-09-17T18:12:34.173610Z","iopub.execute_input":"2025-09-17T18:12:34.173831Z","iopub.status.idle":"2025-09-17T18:12:34.207875Z","shell.execute_reply.started":"2025-09-17T18:12:34.173815Z","shell.execute_reply":"2025-09-17T18:12:34.207289Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 7. Training the Model 💪\n- ⏸️ EarlyStopping for best results\n- 📈 `model.fit()` with validation\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tensorflow.keras.callbacks import EarlyStopping\n\n# Define early stopping\nearly_stop = EarlyStopping(\n    monitor='val_loss',\n    patience=3,\n    restore_best_weights=True )\n\n# Training\nhistory = model.fit(\n    X_train_pad, np.array(y_train),\n    validation_data=(X_test_pad, np.array(y_test)),\n    epochs=15,\n    batch_size=256,\n    verbose=1,\n    callbacks=[early_stop]\n)\n","metadata":{"execution":{"iopub.status.busy":"2025-09-17T18:12:34.209725Z","iopub.execute_input":"2025-09-17T18:12:34.209959Z","execution_failed":"2025-09-18T05:03:18.924Z"},"id":"XzzVjjsv0sSs","outputId":"d91164a4-3312-4c09-c680-10c9471bf02b","trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 8. Predictions & Evaluation 📐\n- 📊 Classification Report\n- 🎯 F1 Score\n- 🔍 Threshold Optimization (`evaluate_best_threshold`)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.metrics import classification_report, f1_score\n\ndef evaluate_best_threshold(model, X_test_pad, y_test, thresholds=[0.3, 0.35, 0.4, 0.45, 0.5, 0.55, 0.65]):\n    # Predict probabilities once\n    y_pred_probs = model.predict(X_test_pad, verbose=0)\n\n    best_threshold = None\n    best_f1 = -1\n    best_report = None\n    best_preds = None\n\n    for t in thresholds:\n        y_pred = (y_pred_probs > t).astype(\"int32\")\n        f1 = f1_score(y_test, y_pred, pos_label=1)  # F1 only for class 1\n\n        if f1 > best_f1:\n            best_f1 = f1\n            best_threshold = t\n            best_report = classification_report(y_test, y_pred, digits=4)\n            best_preds = y_pred\n\n    print(f\"\\nBest Threshold: {best_threshold}\")\n    print(f\"Best F1 Score (class 1): {best_f1:.4f}\")\n    print(\"Classification Report:\\n\", best_report)\n\n    return best_threshold, best_preds\n","metadata":{"id":"squiui-L0sSt","trusted":true,"execution":{"execution_failed":"2025-09-18T05:03:18.925Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Predictions\ny_pred_probs = model.predict(X_test_pad)\nbest_t, best_preds = evaluate_best_threshold(model, X_test_pad, y_test)","metadata":{"id":"z80Joqm00sSt","trusted":true,"execution":{"execution_failed":"2025-09-18T05:03:18.925Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 9 Model Saving 💾\n- 🧩 Save model: `lstm_sentiment_model.h5`\n- 🗂️ Save tokenizer: `tokenizer.joblib`\n","metadata":{}},{"cell_type":"code","source":"!pip install joblib\n\nimport joblib\n\n# Save model\nmodel.save(\"lstm_sentiment_model.h5\")\nprint(\"✅ Model saved as lstm_sentiment_model.h5\")\n\n# Save tokenizer\njoblib.dump(tokenizer, \"tokenizer.joblib\")\nprint(\"✅ Tokenizer saved as tokenizer.joblib\")\n\n\n","metadata":{"id":"2wvp3KgG0sSt","trusted":true,"execution":{"execution_failed":"2025-09-18T05:03:18.925Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 10. Inference on Test Data 🔮\n- 📂 Load saved model & tokenizer\n- 🤖 Predict labels on test set\n- 🎚️ Apply best threshold\n- 📝 Save submission as `submission.csv`","metadata":{}},{"cell_type":"code","source":"test_df=pd.read_csv(\"/kaggle/input/comments-classification/Dataset/test.csv\")\n\n\nimport joblib\nfrom tensorflow.keras.preprocessing.sequence import pad_sequences\nfrom tensorflow.keras.models import load_model\nimport numpy as np\n\n# Load tokenizer and model\ntokenizer = joblib.load(\"/kaggle/working/tokenizer.joblib\")\nmodel = load_model(\"/kaggle/working/lstm_sentiment_model.h5\")\n\n# New text to predict\nnew_texts = test_df['comment_text']\n\n# Tokenize and pad\nsequences = tokenizer.texts_to_sequences(new_texts)\npadded = pad_sequences(sequences, maxlen=max_len, padding='post')\n\n# Predict\npredictions = model.predict(padded)\n\n# labeling\npred_labels = (predictions > best_t).astype(int)\n\npred_labels=pred_labels.flatten()\n\ndf=pd.DataFrame(\n    {\n        \"ID\":[i for i in range(1,len(new_texts)+1)],\n        \"psychotic_depression\":pred_labels\n    }\n)\n\ndf.to_csv(\"submission.csv\",index=False)","metadata":{"id":"E4iSR7dx0sSt","trusted":true,"execution":{"execution_failed":"2025-09-18T05:03:18.925Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.head()","metadata":{"id":"MkTH5Pgz0sSu","trusted":true,"execution":{"execution_failed":"2025-09-18T05:03:18.926Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}