├── Data_Clasif_comentarios.xlsx ├── result_models_sentiment.pbix ├── local_robertuito ├── descargar_robertiu.py └── test_roberti.py ├── local_tabuilaris_sentiment ├── descarga_modelo.py └── sentiment_context.py ├── local_nlp_bert ├── descargar_nlp_bert.py └── bert_sentiment.py ├── test_comentarios.csv ├── readme.md ├── .gitignore └── analisis_sentimiento.py /Data_Clasif_comentarios.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluesfer2007/Python_TutorialData/main/Data_Clasif_comentarios.xlsx -------------------------------------------------------------------------------- /result_models_sentiment.pbix: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bluesfer2007/Python_TutorialData/main/result_models_sentiment.pbix -------------------------------------------------------------------------------- /local_robertuito/descargar_robertiu.py: -------------------------------------------------------------------------------- 1 | # descargar_robertuito.py 2 | from transformers import AutoTokenizer, AutoModelForSequenceClassification 3 | 4 | MODEL_ID = "pysentimiento/robertuito-sentiment-analysis" 5 | SAVE_PATH = "./local_robertuito/modelo_robertuito_descargado" 6 | 7 | print(f"📥 Descargando el modelo '{MODEL_ID}'...") 8 | 9 | # Descargar y guardar el tokenizador y el modelo 10 | tokenizer = AutoTokenizer.from_pretrained(MODEL_ID) 11 | model = AutoModelForSequenceClassification.from_pretrained(MODEL_ID) 12 | 13 | tokenizer.save_pretrained(SAVE_PATH) 14 | model.save_pretrained(SAVE_PATH) 15 | 16 | print(f"✅ ¡Modelo Robertuito guardado exitosamente en '{SAVE_PATH}'!") -------------------------------------------------------------------------------- /local_tabuilaris_sentiment/descarga_modelo.py: -------------------------------------------------------------------------------- 1 | from transformers import AutoTokenizer, AutoModelForSequenceClassification 2 | 3 | # Nombre del modelo en Hugging Face 4 | nombre_modelo = "tabularisai/multilingual-sentiment-analysis" 5 | 6 | # Ruta a la carpeta local donde se guardará el modelo 7 | ruta_local = "./modelo_descargado" 8 | 9 | print(f"Descargando el modelo y el tokenizador a '{ruta_local}'...") 10 | 11 | # Descargar y guardar el tokenizador 12 | tokenizer = AutoTokenizer.from_pretrained(nombre_modelo) 13 | tokenizer.save_pretrained(ruta_local) 14 | 15 | # Descargar y guardar el modelo 16 | model = AutoModelForSequenceClassification.from_pretrained(nombre_modelo) 17 | model.save_pretrained(ruta_local) 18 | 19 | print("¡Descarga completada! El modelo está listo para usarse offline.") -------------------------------------------------------------------------------- /local_nlp_bert/descargar_nlp_bert.py: -------------------------------------------------------------------------------- 1 | from transformers import AutoTokenizer, AutoModelForSequenceClassification 2 | import os 3 | 4 | # Identificador oficial del modelo en Hugging Face 5 | nombre_modelo = "nlptown/bert-base-multilingual-uncased-sentiment" 6 | 7 | # Ruta a la carpeta local donde se guardará el nuevo modelo 8 | ruta_local = "./modelo_bert_descargado" 9 | 10 | # Crear la carpeta si no existe 11 | if not os.path.exists(ruta_local): 12 | os.makedirs(ruta_local) 13 | 14 | print(f"Descargando el modelo '{nombre_modelo}' a la carpeta '{ruta_local}'...") 15 | 16 | # Descargar y guardar el tokenizador 17 | tokenizer = AutoTokenizer.from_pretrained(nombre_modelo) 18 | tokenizer.save_pretrained(ruta_local) 19 | 20 | # Descargar y guardar el modelo 21 | model = AutoModelForSequenceClassification.from_pretrained(nombre_modelo) 22 | model.save_pretrained(ruta_local) 23 | 24 | print("¡Descarga completada! El modelo de calificación por estrellas está listo para usarse offline.") -------------------------------------------------------------------------------- /test_comentarios.csv: -------------------------------------------------------------------------------- 1 | Texto 2 | Wow, otra vez esta delicia. Mi paladar aun no se se recupera de tanta emoción. 3 | Interesante combinación de texturas, sobre todo la crujiente ceniza y el sobervio color carbon 🤢. 4 | Mi más sincera enhorabuena al chef, ha conseguido que eche de menos la comida de hospital y quiera romperme una pierna de nuevo. 5 | Este plato es tan increíblemente bueno que me hace dudar de todas las buenas comidas que he tenido antes. 6 | No sé qué le pusieron, pero deberían declararlo ilegal de tan bueno que está. 7 | Está tan delicioso que casi me ofende que no me hayas traído mas veces a este lugar. 8 | La presentación era prometedora, pero el sabor no le hizo justicia. 9 | "Creo que al salero se le fue la mano, el mar muerto debe tener menos sal que esto 🤢" 10 | La textura de la carne me recuerda a la suela de un zapato que ha corrido un maratón. 11 | Cada bocado es una explosión de sabor. ¡Absolutamente espectacular! 12 | La combinación de ingredientes es perfecta, se nota la frescura y la calidad. 13 | Simple, pero ejecutado a la perfección. Un plato reconfortante y delicioso. 14 | -------------------------------------------------------------------------------- /local_robertuito/test_roberti.py: -------------------------------------------------------------------------------- 1 | from transformers import AutoModelForSequenceClassification, AutoTokenizer 2 | import torch 3 | import pandas as pd 4 | 5 | #configuración del modelo offline 6 | ruta_modelo = "./modelo_robertuito_descargado" # Ruta donde se guardó el modelo 7 | print(f"Cargando el modelo y el tokenizador desde '{ruta_modelo}'...") 8 | 9 | # Cargar el tokenizador y el modelo desde la ruta local 10 | tokenizer = AutoTokenizer.from_pretrained(ruta_modelo) 11 | 12 | #cargar el modelo desde la ruta local 13 | model = AutoModelForSequenceClassification.from_pretrained(ruta_modelo) 14 | print("Modelo y tokenizador cargados correctamente.") 15 | 16 | # Función para predecir el sentimiento de un texto 17 | def predecir_sentimiento(texto): 18 | # Tokenizar el texto 19 | inputs = tokenizer(texto, return_tensors="pt", truncation=True, padding=True, max_length=512) 20 | 21 | # Realizar la predicción 22 | with torch.no_grad(): 23 | outputs = model(**inputs) 24 | 25 | # Obtener las probabilidades de cada clase 26 | probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1) 27 | predicciones=torch.argmax(probabilities, dim=-1).tolist() 28 | 29 | #mapear los sentimientos 30 | mapa_sentimientos = { 31 | 0: "Negativo", 32 | 1: "Neutro", 33 | 2: "Positivo" 34 | } 35 | 36 | return [mapa_sentimientos[pred] for pred in predicciones] 37 | 38 | #leer los datos del csv 39 | df= pd.read_csv("../test_comentarios.csv",sep=";") 40 | df['sentimiento'] = df['Texto'].apply(predecir_sentimiento) 41 | 42 | print(df.head(10)) -------------------------------------------------------------------------------- /local_tabuilaris_sentiment/sentiment_context.py: -------------------------------------------------------------------------------- 1 | from transformers import AutoModelForSequenceClassification, AutoTokenizer 2 | import torch 3 | import pandas as pd 4 | 5 | #configuración del modelo offline 6 | ruta_modelo = "./modelo_descargado" # Ruta donde se guardó el modelo 7 | print(f"Cargando el modelo y el tokenizador desde '{ruta_modelo}'...") 8 | 9 | # Cargar el tokenizador y el modelo desde la ruta local 10 | tokenizer = AutoTokenizer.from_pretrained(ruta_modelo) 11 | 12 | #cargar el modelo desde la ruta local 13 | model = AutoModelForSequenceClassification.from_pretrained(ruta_modelo) 14 | print("Modelo y tokenizador cargados correctamente.") 15 | 16 | # Función para predecir el sentimiento de un texto 17 | def predecir_sentimiento(texto): 18 | # Tokenizar el texto 19 | inputs = tokenizer(texto, return_tensors="pt", truncation=True, padding=True, max_length=512) 20 | 21 | # Realizar la predicción 22 | with torch.no_grad(): 23 | outputs = model(**inputs) 24 | 25 | # Obtener las probabilidades de cada clase 26 | probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1) 27 | predicciones=torch.argmax(probabilities, dim=-1).tolist() 28 | 29 | #mapear los sentimientos 30 | mapa_sentimientos = { 31 | 0: "Muy Negativo", 32 | 1: "Negativo", 33 | 2: "Neutro", 34 | 3: "Positivo", 35 | 4: "Muy Positivo" 36 | } 37 | 38 | return [mapa_sentimientos[pred] for pred in predicciones] 39 | 40 | #leer los datos del csv 41 | df= pd.read_csv("../test_comentarios.csv",sep=";") 42 | df['sentimiento'] = df['Texto'].apply(predecir_sentimiento) 43 | 44 | print(df.head()) -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 🤖 Análisis de Sentimiento Dual con Modelos Locales 📊 2 | 3 | ![Python](https://img.shields.io/badge/Python-3.9%2B-blue.svg) 4 | ![Libraries](https://img.shields.io/badge/Librerías-Transformers%20%7C%20PyTorch%20%7C%20Pandas-orange.svg) 5 | ![License](https://img.shields.io/badge/Licencia-MIT-green.svg) 6 | 7 | ¡Bienvenido a este proyecto de análisis de sentimiento! 🚀 Este pipeline está diseñado para leer un archivo de comentarios, procesarlos y enriquecerlos usando dos potentes modelos de lenguaje de Hugging Face. Todo el proceso se ejecuta de manera **100% local y offline**, garantizando la máxima velocidad y la total privacidad de tus datos. 8 | 9 | ## ✨ Características Principales 10 | 11 | * **🌐 Ejecución Offline:** Tras una descarga inicial, no se necesita conexión a internet. ¡Analiza tus datos en cualquier lugar! 12 | * **🧠 Análisis Dual:** Cada comentario es evaluado por dos modelos diferentes para obtener una visión más completa: 13 | * **Clasificación Categórica:** `Muy Positivo`, `Positivo`, `Neutral`, `Negativo`, `Muy Negativo`. 14 | * **Calificación por Estrellas:** De ★☆☆☆☆ (1 estrella) a ★★★★★ (5 estrellas). 15 | * **⚙️ Procesamiento Eficiente:** Utiliza un sistema de lotes para procesar miles de comentarios sin agotar la memoria de tu equipo. 16 | * **⚡ Aceleración por GPU:** ¡Saca el máximo provecho a tu hardware! Detecta y usa automáticamente tu tarjeta gráfica NVIDIA (CUDA) para un análisis mucho más rápido. 17 | * **📁 Manejo Sencillo de Datos:** Lee archivos `.xlsx` de forma nativa y exporta los resultados a un archivo `.csv` limpio y listo para usar. 18 | 19 | ## 🤖 Modelos Utilizados 20 | 21 | Este proyecto se apoya en dos modelos de lenguaje de código abierto, descargados y ejecutados localmente: 22 | 23 | 1. **Tabularis Sentiment Model** 24 | * **Descripción:** Un modelo multilingüe basado en `DistilBERT` que clasifica el texto en 5 categorías de sentimiento. 25 | * **Identificador en Hugging Face:** `tabularisai/multilingual-sentiment-analysis` 26 | 27 | 2. **NLP Town - Star Rating Model** 28 | * **Descripción:** Un modelo multilingüe basado en `BERT` entrenado para calificar reseñas en una escala de 1 a 5 estrellas. 29 | * **Identificador en Hugging Face:** `nlptown/bert-base-multilingual-uncased-sentiment` 30 | 31 | ## 📂 Estructura del Proyecto 32 | 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | modelo_bert_descargado/ 132 | modelo_descargado/ 133 | 134 | # Ignorar modelos descargados para evitar subirlos al repositorio 135 | local_nlp_bert/modelo_bert_descargado/ 136 | local_tabularis_sentiment/modelo_descargado/ 137 | local_robertuito/modelo_robertuito_descargado/ 138 | 139 | kjewkjndffkjndf.pbix 140 | # Ignorar archivos de Power BI 141 | medir_resultado_accur_v3.csv 142 | # Ignorar resultados de accuracy 143 | medir_resultado_accur.csv 144 | 145 | train.csv 146 | # Ignorar archivo de entrenamiento -------------------------------------------------------------------------------- /local_nlp_bert/bert_sentiment.py: -------------------------------------------------------------------------------- 1 | from transformers import AutoTokenizer, AutoModelForSequenceClassification 2 | import torch 3 | import pandas as pd 4 | 5 | # --- CONFIGURACIÓN OFFLINE --- 6 | # Ruta a la carpeta local donde guardaste el modelo de NLP Town. 7 | ruta_modelo_local = "./modelo_bert_descargado" 8 | 9 | print("Cargando el modelo de calificación por estrellas desde archivos locales...") 10 | 11 | # Cargar el tokenizador y el modelo desde la carpeta local 12 | try: 13 | tokenizer = AutoTokenizer.from_pretrained(ruta_modelo_local) 14 | model = AutoModelForSequenceClassification.from_pretrained(ruta_modelo_local) 15 | print("¡Modelo cargado exitosamente en modo offline!") 16 | except OSError: 17 | print(f"Error: No se encontraron los archivos del modelo en la ruta '{ruta_modelo_local}'.") 18 | print("Por favor, asegúrate de haber ejecutado primero el script 'descargar_modelo_bert.py'.") 19 | exit() 20 | 21 | 22 | # --- FUNCIÓN DE PREDICCIÓN ADAPTADA --- 23 | def predict_star_rating(textos): 24 | """ 25 | Analiza una lista de textos y devuelve su calificación en estrellas (1 a 5). 26 | """ 27 | inputs = tokenizer(textos, return_tensors="pt", truncation=True, padding=True, max_length=512) 28 | 29 | with torch.no_grad(): 30 | outputs = model(**inputs) 31 | 32 | # La salida del modelo (logits) se convierte a predicciones. 33 | # El modelo produce una clase de 0 a 4. 34 | predicciones = torch.argmax(outputs.logits, dim=-1).tolist() 35 | 36 | # IMPORTANTE: Mapear la salida del modelo a estrellas. 37 | # El modelo fue entrenado para que 'label 0' sea 1 estrella, 'label 1' sea 2 estrellas, etc. 38 | mapa_estrellas = { 39 | 0: "★☆☆☆☆ (1 estrella)", 40 | 1: "★★☆☆☆ (2 estrellas)", 41 | 2: "★★★☆☆ (3 estrellas)", 42 | 3: "★★★★☆ (4 estrellas)", 43 | 4: "★★★★★ (5 estrellas)" 44 | } 45 | 46 | return [mapa_estrellas[p] for p in predicciones] 47 | 48 | # --- EJEMPLO DE USO --- 49 | # ¡Ahora puedes desconectar tu internet para probar! 50 | 51 | # Lista de reseñas de productos para analizar 52 | textos_de_prueba = [ 53 | # Español 54 | "El producto es una maravilla, superó todas mis expectativas.", 55 | "No está mal, pero podría ser mejor. Cumple su función.", 56 | "Una completa decepción, el material es de pésima calidad y no funciona.", 57 | 58 | # Inglés 59 | "This is the best purchase I have ever made!", 60 | "It's an okay product, nothing special.", 61 | 62 | # Francés 63 | "Je suis très déçu par cet article, il s'est cassé après deux jours.", 64 | 65 | # Alemán 66 | "Absolut fantastisch! Sehr zu empfehlen." 67 | ] 68 | 69 | df= pd.read_csv("../test_comentarios.csv",sep=";") 70 | textos_de_prueba = df['Texto'].tolist() # Cargar los textos desde 71 | 72 | # Obtener las predicciones 73 | calificaciones = predict_star_rating(textos_de_prueba) 74 | 75 | # Imprimir los resultados 76 | print("\n--- Resultados del Análisis de Calificación por Estrellas (Offline) ---") 77 | for texto, calificacion in zip(textos_de_prueba, calificaciones): 78 | print(f"Reseña: {texto}\nCalificación: {calificacion}\n") -------------------------------------------------------------------------------- /analisis_sentimiento.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import torch 3 | from transformers import AutoTokenizer, AutoModelForSequenceClassification 4 | import os 5 | 6 | # --- MAPAS DE RESULTADOS PARA CADA MODELO --- 7 | # Mapa para el modelo Tabularis (5 etiquetas) 8 | MAPA_TABULARIS = {0: "Muy Negativo", 1: "Negativo", 2: "Neutral", 3: "Positivo", 4: "Muy Positivo"} 9 | 10 | # Mapa para el modelo NLP Town Bert (5 estrellas) --- CORREGIDO --- 11 | # Este modelo devuelve una calificación por estrellas, no etiquetas de texto. 12 | MAPA_NLP_BERT = { 13 | 0: "Muy Negativo", 14 | 1: "Negativo", 15 | 2: "Neutral", 16 | 3: "Positivo", 17 | 4: "Muy Positivo" 18 | } 19 | 20 | # --- NUEVO --- 21 | # Mapa para el modelo Robertuito (3 etiquetas). 22 | # La correspondencia de índices (0, 1, 2) se obtiene del archivo config.json del modelo. 23 | MAPA_ROBERTUITO = {0: "Negativo", 1: "Neutral", 2: "Positivo"} 24 | 25 | 26 | def cargar_modelo_local(ruta_modelo, device): 27 | """ 28 | Carga un tokenizador y un modelo desde una ruta local y lo mueve al dispositivo especificado (CPU o GPU). 29 | """ 30 | if not os.path.exists(ruta_modelo): 31 | print(f"¡ERROR! La ruta del modelo '{ruta_modelo}' no existe.") 32 | print("Asegúrate de que la estructura de carpetas sea correcta y que los modelos estén descargados.") 33 | return None, None 34 | 35 | try: 36 | print(f"Cargando modelo desde: {ruta_modelo}") 37 | tokenizer = AutoTokenizer.from_pretrained(ruta_modelo) 38 | model = AutoModelForSequenceClassification.from_pretrained(ruta_modelo) 39 | model.to(device) # Mover el modelo a la GPU si está disponible 40 | model.eval() # Poner el modelo en modo de evaluación 41 | print("...Carga exitosa.") 42 | return tokenizer, model 43 | except Exception as e: 44 | print(f"Ocurrió un error al cargar el modelo desde '{ruta_modelo}': {e}") 45 | return None, None 46 | 47 | def analizar_lote(textos, tokenizer, model, mapa_resultados, device): 48 | """ 49 | Función genérica para analizar un lote de textos con un modelo dado. 50 | """ 51 | if not textos: 52 | return [] 53 | 54 | # Tokenizar el lote de textos 55 | inputs = tokenizer(textos, return_tensors="pt", truncation=True, padding=True, max_length=512) 56 | 57 | # Mover los tensores de entrada al mismo dispositivo que el modelo 58 | inputs = {k: v.to(device) for k, v in inputs.items()} 59 | 60 | # Realizar la predicción sin calcular gradientes (más rápido) 61 | with torch.no_grad(): 62 | outputs = model(**inputs) 63 | 64 | # Obtener la predicción (el índice con la probabilidad más alta) 65 | predicciones = torch.argmax(outputs.logits, dim=-1).tolist() 66 | 67 | # Mapear los índices a las etiquetas de texto correspondientes 68 | return [mapa_resultados[p] for p in predicciones] 69 | 70 | 71 | def procesar_archivo_completo(config): 72 | """ 73 | Función principal que orquesta todo el proceso de análisis. 74 | """ 75 | # 1. Verificar si la GPU está disponible 76 | device = "cuda" if torch.cuda.is_available() else "cpu" 77 | print(f"--- Usando dispositivo: {device} ---") 78 | if device == "cuda": 79 | print(f"Nombre de la GPU: {torch.cuda.get_device_name(0)}") 80 | 81 | # 2. Cargar los tres modelos desde las rutas locales --- MODIFICADO --- 82 | print("\n--- Cargando Modelos Locales ---") 83 | tokenizer_tabularis, model_tabularis = cargar_modelo_local(config["ruta_tabularis"], device) 84 | tokenizer_nlp_bert, model_nlp_bert = cargar_modelo_local(config["ruta_nlp_bert"], device) 85 | tokenizer_robertuito, model_robertuito = cargar_modelo_local(config["ruta_robertuito"], device) # --- NUEVO --- 86 | 87 | # Salir si alguno de los modelos no pudo cargarse --- MODIFICADO --- 88 | if not model_tabularis or not model_nlp_bert or not model_robertuito: 89 | print("\nProceso detenido debido a un error en la carga de modelos.") 90 | return 91 | 92 | # 3. Cargar el archivo de entrada 93 | try: 94 | print(f"\n--- Cargando datos de '{config['archivo_entrada']}' ---") 95 | df = pd.read_excel(config['archivo_entrada']) # Cambiado a read_csv para tu caso de uso 96 | print(f"Archivo cargado. {len(df)} filas encontradas.") 97 | except FileNotFoundError: 98 | print(f"¡ERROR! No se encontró el archivo '{config['archivo_entrada']}'. Verifica el nombre y la ubicación.") 99 | return 100 | except Exception as e: 101 | print(f"Ocurrió un error al leer el archivo de entrada: {e}") 102 | return 103 | 104 | # Extraer los comentarios y asegurarse de que no haya valores nulos 105 | comentarios = df[config['columna_texto']].fillna('').tolist() 106 | 107 | # Limitar filas si se especificó un límite para pruebas 108 | if config['limite_filas']: 109 | print(f"\n¡ATENCIÓN! Se procesarán únicamente las primeras {config['limite_filas']} filas para la prueba.") 110 | comentarios = comentarios[:config['limite_filas']] 111 | df = df.head(config['limite_filas']).copy() 112 | 113 | # 4. Procesar en lotes --- MODIFICADO --- 114 | print(f"\n--- Iniciando análisis de {len(comentarios)} comentarios en lotes de {config['tamano_lote']} ---") 115 | resultados_tabularis = [] 116 | resultados_nlp_bert = [] 117 | resultados_robertuito = [] # --- NUEVO --- 118 | 119 | for i in range(0, len(comentarios), config['tamano_lote']): 120 | lote_textos = comentarios[i:i + config['tamano_lote']] 121 | 122 | # Analizar con cada modelo 123 | res_tab = analizar_lote(lote_textos, tokenizer_tabularis, model_tabularis, MAPA_TABULARIS, device) 124 | resultados_tabularis.extend(res_tab) 125 | 126 | res_bert = analizar_lote(lote_textos, tokenizer_nlp_bert, model_nlp_bert, MAPA_NLP_BERT, device) 127 | resultados_nlp_bert.extend(res_bert) 128 | 129 | res_robertuito = analizar_lote(lote_textos, tokenizer_robertuito, model_robertuito, MAPA_ROBERTUITO, device) # --- NUEVO --- 130 | resultados_robertuito.extend(res_robertuito) 131 | 132 | print(f"Procesados {len(resultados_tabularis)} de {len(comentarios)} comentarios...") 133 | 134 | # 5. Añadir resultados al DataFrame --- MODIFICADO --- 135 | df['sentimiento_tabularis'] = resultados_tabularis 136 | df['calificacion_nlp_bert'] = resultados_nlp_bert 137 | df['sentimiento_robertuito'] = resultados_robertuito # --- NUEVO --- 138 | print("\n--- Análisis completado. Añadiendo resultados al archivo. ---") 139 | 140 | # 6. Guardar el archivo final 141 | try: 142 | df.to_csv(config['archivo_salida'], index=False, encoding='utf-8-sig') 143 | print(f"\n¡ÉXITO! Resultados guardados en '{config['archivo_salida']}'") 144 | except Exception as e: 145 | print(f"Ocurrió un error al guardar el archivo de salida: {e}") 146 | 147 | 148 | # --- CONFIGURACIÓN Y EJECUCIÓN --- 149 | if __name__ == "__main__": 150 | 151 | configuracion = { 152 | # 1. Archivos y columnas 153 | "archivo_entrada": "Data_Clasif_comentarios.xlsx", 154 | "columna_texto": "Comentario", # Cambiado a "Comentario" para tu caso de uso 155 | "archivo_salida": "resultados_analisis_combinado.csv", 156 | 157 | # 2. Rutas a tus modelos locales 158 | "ruta_tabularis": "local_tabuilaris_sentiment/modelo_descargado", # --- CORREGIDO --- 159 | "ruta_nlp_bert": "local_nlp_bert/modelo_bert_descargado", 160 | "ruta_robertuito": "local_robertuito/modelo_robertuito_descargado", # --- NUEVO --- 161 | 162 | # 3. Parámetros de ejecución 163 | "tamano_lote": 100, 164 | "limite_filas": None # Cambia a un número para limitar las filas procesadas, o None para procesar todo 165 | } 166 | 167 | procesar_archivo_completo(configuracion) 168 | --------------------------------------------------------------------------------