{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"collapsed_sections":["X3p5mmodbpvn","BGxhozdtabBx"],"authorship_tag":"ABX9TyOMQQxQmBtuckaWq7Gf9XZl"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["## Implementación de temas de la Semana 3\n","\n","El código a continuación es un ejemplo completo y sencillo de los temas analizados la semana 3: (**dataset + etiquetas + BoW + TF-IDF + “embeddings” + matriz de confusión**)\n","\n","Se recomienda:\n","- Leer los comentarios.\n","- Analizar el código y cotejarlo con el descrito en la parte teórica.\n","- Ejecutar el código\n","- Analizar los resultados\n","- Confrontar el análisis con la explicación de resultados que se encuentra al final del Notebook.\n","\n","Nota: “embeddings” aquí se muestran como embeddings densos de documento vía LSA (TF-IDF + SVD), que es una forma clásica de embeddings semánticos (no-transformer) útil para docencia."],"metadata":{"id":"X3p5mmodbpvn"}},{"cell_type":"code","execution_count":null,"metadata":{"id":"JCh_mhlzZs1I"},"outputs":[],"source":["import numpy as np\n","import pandas as pd\n","\n","from sklearn.model_selection import train_test_split\n","from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer\n","from sklearn.decomposition import TruncatedSVD\n","from sklearn.linear_model import LogisticRegression\n","from sklearn.metrics import confusion_matrix, classification_report\n","\n","# -----------------------------\n","# 1) Dataset pequeño etiquetado\n","# -----------------------------\n","data = [\n"," (\"URGENTE verifique su cuenta ahora [URL] para evitar suspension\", \"phishing\"),\n"," (\"Actividad sospechosa detectada confirme credenciales [URL]\", \"phishing\"),\n"," (\"Su cuenta sera bloqueada hoy verificacion inmediata [URL]\", \"phishing\"),\n"," (\"Actualice su contrasena inmediatamente usando el enlace [URL]\", \"phishing\"),\n","\n"," (\"No puedo acceder al VPN aparece error de autenticacion\", \"legitimo\"),\n"," (\"Ticket: falla de servidor y lentitud general en el sistema\", \"legitimo\"),\n"," (\"El correo corporativo no sincroniza desde ayer, por favor revisar\", \"legitimo\"),\n"," (\"Soporte: incidente tecnico en ERP, error 504 al ingresar\", \"legitimo\"),\n","]\n","df = pd.DataFrame(data, columns=[\"texto\", \"etiqueta\"])\n","\n","X_train, X_test, y_train, y_test = train_test_split(\n"," df[\"texto\"], df[\"etiqueta\"],\n"," test_size=0.25, stratify=df[\"etiqueta\"], random_state=42\n",")\n","\n","def train_and_eval(name, Xtr, Xte, ytr, yte, labels):\n"," clf = LogisticRegression(max_iter=2000, class_weight=\"balanced\")\n"," clf.fit(Xtr, ytr)\n"," pred = clf.predict(Xte)\n","\n"," print(\"\\n\" + \"=\"*70)\n"," print(f\"{name}\")\n"," print(\"=\"*70)\n"," print(\"Classification report:\")\n"," print(classification_report(yte, pred, digits=3))\n"," cm = confusion_matrix(yte, pred, labels=labels)\n"," cm_df = pd.DataFrame(cm, index=[f\"real_{l}\" for l in labels], columns=[f\"pred_{l}\" for l in labels])\n"," print(\"Matriz de confusión (filas=real, columnas=pred):\")\n"," print(cm_df)\n"," return clf, pred, cm_df\n","\n","labels_sorted = [\"legitimo\", \"phishing\"] # orden fijo para matrices comparables\n","\n","# -----------------------------\n","# 2) BoW (Bag of Words)\n","# -----------------------------\n","bow = CountVectorizer(ngram_range=(1, 2)) # uni + bi-gramas (útil en phishing)\n","Xtr_bow = bow.fit_transform(X_train)\n","Xte_bow = bow.transform(X_test)\n","\n","# Mostrar “resultados” de BoW: vocabulario + matriz (pequeña muestra)\n","bow_vocab = bow.get_feature_names_out()\n","bow_df = pd.DataFrame(Xtr_bow.toarray(), columns=bow_vocab, index=X_train.index)\n","print(\"=== BoW: muestra de matriz (train) ===\")\n","print(bow_df.head(3).iloc[:, :12]) # solo primeras 12 columnas para que sea legible\n","\n","train_and_eval(\"Clasificador con BoW\", Xtr_bow, Xte_bow, y_train, y_test, labels_sorted)\n","\n","# -----------------------------\n","# 3) TF-IDF\n","# -----------------------------\n","tfidf = TfidfVectorizer(ngram_range=(1, 2), sublinear_tf=True)\n","Xtr_tfidf = tfidf.fit_transform(X_train)\n","Xte_tfidf = tfidf.transform(X_test)\n","\n","# Mostrar “resultados” TF-IDF: matriz (muestra)\n","tfidf_vocab = tfidf.get_feature_names_out()\n","tfidf_df = pd.DataFrame(Xtr_tfidf.toarray(), columns=tfidf_vocab, index=X_train.index)\n","print(\"\\n=== TF-IDF: muestra de matriz (train) ===\")\n","print(tfidf_df.head(3).iloc[:, :12])\n","\n","train_and_eval(\"Clasificador con TF-IDF\", Xtr_tfidf, Xte_tfidf, y_train, y_test, labels_sorted)\n","\n","# -----------------------------\n","# 4) “Embeddings” densos (LSA: TF-IDF + SVD)\n","# -----------------------------\n","# SVD crea una representación densa de menor dimensión que captura estructura semántica latente.\n","svd = TruncatedSVD(n_components=4, random_state=42) # 4 dimensiones solo para demo\n","Xtr_emb = svd.fit_transform(Xtr_tfidf)\n","Xte_emb = svd.transform(Xte_tfidf)\n","\n","# Mostrar “resultados” de embeddings: vectores densos\n","emb_cols = [f\"emb_{i+1}\" for i in range(Xtr_emb.shape[1])]\n","emb_df = pd.DataFrame(Xtr_emb, columns=emb_cols, index=X_train.index)\n","print(\"\\n=== Embeddings (LSA/SVD): muestra de vectores densos (train) ===\")\n","print(emb_df.head(5))\n","\n","train_and_eval(\"Clasificador con Embeddings densos (LSA/SVD)\", Xtr_emb, Xte_emb, y_train, y_test, labels_sorted)\n","\n","# -----------------------------\n","# 5) Predicción individual (demo rápida)\n","# -----------------------------\n","texto_nuevo = \"URGENTE: confirme su cuenta para evitar suspension [URL]\"\n","x_bow = bow.transform([texto_nuevo])\n","x_tfidf = tfidf.transform([texto_nuevo])\n","x_emb = svd.transform(x_tfidf)\n","\n","print(\"\\n=== Predicción de ejemplo ===\")\n","print(\"Texto:\", texto_nuevo)\n","print(\"Pred (BoW):\", LogisticRegression(max_iter=2000, class_weight=\"balanced\").fit(Xtr_bow, y_train).predict(x_bow)[0])\n","print(\"Pred (TF-IDF):\", LogisticRegression(max_iter=2000, class_weight=\"balanced\").fit(Xtr_tfidf, y_train).predict(x_tfidf)[0])\n","print(\"Pred (Embeddings LSA):\", LogisticRegression(max_iter=2000, class_weight=\"balanced\").fit(Xtr_emb, y_train).predict(x_emb)[0])"]},{"cell_type":"markdown","source":["## Interpretación de Resultados"],"metadata":{"id":"BGxhozdtabBx"}},{"cell_type":"markdown","source":["1. Clasificador con BoW (Bag of Words)\n","\n","Classification Report:\n","\n","1.1. Legítimo\n","\n","- Precisión para 'legitimo': 0.000. Esto significa que ninguna de las predicciones como 'legitimo' fue correcta. El modelo no predijo ninguna instancia como 'legitimo' de manera correcta.\n","- Recall para 'legitimo': 0.000. Esto indica que el modelo no fue capaz de identificar ninguna de las instancias reales de 'legitimo'.\n","- F1-score para 'legitimo': 0.000, lo que confirma el pobre rendimiento para esta clase.\n","\n","1.2. Phishing\n","\n","- Precisión para 'phishing': 0.500. El 50% de las predicciones como 'phishing' fueron correctas.\n","- Recall para 'phishing': 1.000. El modelo identificó correctamente todas las instancias reales de 'phishing'.\n","- F1-score para 'phishing': 0.667.\n","- Accuracy: 0.500. El 50% de las predicciones totales fueron correctas.\n","- UndefinedMetricWarning: Este aviso aparece porque la precisión para 'legitimo' no se pudo calcular (división por cero) ya que el modelo no predijo ninguna instancia como 'legitimo'.\n","\n","1.3. Matriz de Confusión:\n","\n","- real_legitimo: 0 pred_legitimo, 1 pred_phishing: Una instancia real 'legitimo' fue clasificada erróneamente como 'phishing'.\n","- real_phishing: 0 pred_legitimo, 1 pred_phishing: Una instancia real 'phishing' fue clasificada correctamente como 'phishing'.\n","- El modelo BoW tuvo dificultades para clasificar la clase 'legitimo' correctamente, prediciendo todas las instancias como 'phishing'.\n","\n","2. Clasificador con TF-IDF\n","\n","Classification Report:\n","\n","2.1. Precisión, Recall y F1-score: 1.000 para ambas clases ('legitimo' y 'phishing').\n","\n","2.2. Accuracy: 1.000. Esto indica que el modelo TF-IDF clasificó todas las instancias del conjunto de prueba correctamente.\n","\n","2.3. Matriz de Confusión:\n","\n","- real_legitimo: 1 pred_legitimo, 0 pred_phishing: Una instancia real 'legitimo' fue clasificada correctamente.\n","- real_phishing: 0 pred_legitimo, 1 pred_phishing: Una instancia real 'phishing' fue clasificada correctamente.\n","- El modelo TF-IDF mostró un rendimiento perfecto en este pequeño conjunto de datos de prueba.\n","\n","3. Clasificador con Embeddings densos (LSA/SVD)\n","\n","Classification Report:\n","\n","3.1. Precisión, Recall y F1-score: 1.000 para ambas clases ('legitimo' y 'phishing').\n","\n","3.2. Accuracy: 1.000. Al igual que TF-IDF, este modelo también clasificó todas las instancias del conjunto de prueba correctamente.\n","\n","3.3. Matriz de Confusión:\n","\n","- real_legitimo: 1 pred_legitimo, 0 pred_phishing: Una instancia real 'legitimo' fue clasificada correctamente.\n","- real_phishing: 0 pred_legitimo, 1 pred_phishing: Una instancia real 'phishing' fue clasificada correctamente.\n","- El modelo basado en LSA/SVD también logró un rendimiento perfecto en este pequeño conjunto de datos de prueba.\n","\n","4. Predicción de Ejemplo Individual\n","\n","Para el texto nuevo: \"URGENTE: confirme su cuenta para evitar suspension [URL]\"\n","\n","- Pred (BoW): phishing\n","- Pred (TF-IDF): phishing\n","- Pred (Embeddings LSA): phishing\n","- Todos los modelos, incluyendo el que tuvo un rendimiento imperfecto en el conjunto de prueba (BoW), predijeron correctamente este nuevo texto como 'phishing'. Esto sugiere que el texto contiene características muy fuertes de phishing que son detectadas por los tres enfoques."],"metadata":{"id":"1Jnz1l5PafeL"}}]}