File size: 8,992 Bytes
12dfcea
782093a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6a26905
b16ef7f
7782d80
4b90953
6a26905
4b90953
782093a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
import io
import datetime
from tqdm import tqdm

# Pandas
import pandas as pd

# Expresiones regulares
import re

# Matplotlib, Seaborn y Plotly
import matplotlib.pyplot as plt
import seaborn as sns

# NLTK
import nltk
from nltk.corpus import stopwords

# spaCy
import spacy

# PySentimiento y Transformers
from pysentimiento import create_analyzer
from sentence_transformers import SentenceTransformer

# Word cloud
from PIL import Image

import uuid
import streamlit as st

nltk.download('stopwords')
nltk.download('punkt')


### Reformado. Antes hacia reproceso para obtener output y probas. Se puede hacer en un paso.
def get_sentiment(df,column):
    analyzer = create_analyzer(task="sentiment", lang="es")
    analyzer_outputs = []
    with tqdm(total=len(df), desc="Analyzing Comments") as pbar:
        # Iterate through each element in the DataFrame column
        for element in df[column]:
            # Perform sentiment analysis on each element
            result = analyzer.predict(element)
            # Append the result to the list
            analyzer_outputs.append(result)
            # Update the progress bar
            pbar.update(1)

    # Extracting values into columns
    output_list = [output.output for output in analyzer_outputs]
    NEU_list = [output.probas.get('NEU', None) for output in analyzer_outputs]
    NEG_list = [output.probas.get('NEG', None) for output in analyzer_outputs]
    POS_list = [output.probas.get('POS', None) for output in analyzer_outputs]
    
    # Assigning lists to DataFrame columns
    df['Polaridad'] = output_list
    df['sent_NEU'] = NEU_list
    df['sent_NEG'] = NEG_list
    df['sent_POS'] = POS_list
    return df

### Reformado. Antes hacia reproceso para obtener output y probas. Se puede hacer en un paso.
def get_emotions(df,column):
    analyzer = create_analyzer(task="emotion", lang="es")
    analyzer_outputs = []
    with tqdm(total=len(df), desc="Analyzing Comments") as pbar:
        # Iterate through each element in the DataFrame column
        for element in df[column]:
            # Perform sentiment analysis on each element
            result = analyzer.predict(element)
            # Append the result to the list
            analyzer_outputs.append(result)
            # Update the progress bar
            pbar.update(1)

    # Extracting values into columns
    output_list = [output.output for output in analyzer_outputs]
    anger_list = [output.probas.get('anger', None) for output in analyzer_outputs]
    sadness_list = [output.probas.get('sadness', None) for output in analyzer_outputs]
    surprise_list = [output.probas.get('surprise', None) for output in analyzer_outputs]
    disgust_list = [output.probas.get('disgust', None) for output in analyzer_outputs]
    joy_list = [output.probas.get('joy', None) for output in analyzer_outputs]
    fear_list = [output.probas.get('fear', None) for output in analyzer_outputs]
    others_list = [output.probas.get('others', None) for output in analyzer_outputs]
    
    # Assigning lists to DataFrame columns
    df['Emocion'] = output_list
    df['emo_anger'] = anger_list
    df['emo_sadness'] = sadness_list
    df['emo_surprise'] = surprise_list
    df['emo_disgust'] = disgust_list
    df['emo_joy'] = joy_list
    df['emo_fear'] = fear_list
    df['emo_others'] = others_list
    return df

class ProcesamientoLenguaje:
    def __init__(self):
        self.nlp = spacy.load('es_core_news_md', disable=["parser", "ner"])

    def postags_and_stopwords(self, texts, allowed_postags=['NOUN', 'ADJ','PROPN', 'VB', 'X']):

        '''Función que procesa todos los textos en un pipeline de spaCy para tokenizar y etiquetar las POS.
        Luego, filtra todas las palabras de longitud mayor a 2 caracteres que no sean stop words y que se encuentren
        dentro de las etiquetas permitidas: sustantivo, adjetivo, verbo, nombre propio y todo lo que no caiga en una categoría
        preestablecida (palabras OOV, nombres propios no reconocidos, etc).
        Devuelve los textos procesados.
        '''

        texts_out = ' '.join([token.text for token in self.nlp(texts) if token.pos_ in
                    allowed_postags and token.text not in stop_words and len(token.text) > 2])
        return texts_out

    def cleaner(self, word):

        '''Función que toma un texto y remueve distintos símbolos y variaciones de palabras.
        Devuelve el string limpio.
        '''

        word = re.sub(r'https?\S+', '', word) #remueve todas las URLs
        word = re.sub(r'(?::|;|=)(?:-)?(?:\)|\(|D|P)', "", word) #remueve interrogación, paréntesis, dos puntos, etc
        word = re.sub(r'ee.uu', 'eeuu', word, flags=re.IGNORECASE) #convierte todas las variaciones de EEUU sin importar el separador en EEUU
        word = re.sub(r'\#\.', '', word)
        word = re.sub(r'\n', ' ', word) #remueve todos los line-breaks y los reemplaza con espacios
        word = re.sub(r',', '', word) #remueve comas
        word = re.sub(r'\-', ' ', word) #remueve guiones
        word = re.sub(r'\.{3}', ' ', word) #remueve tres puntos
        word = re.sub(r'a{2,}', 'a', word) #remueve múltiples instancias de la letra a (p.ej: aaaaaaah, holaaaaaa)
        word = re.sub(r'é{2,}', 'é', word) #remueve múltiples instancias de la letra é (p.ej: volvééééé)
        word = re.sub(r'i{2,}', 'i', word) #remueve múltiples instancias de la letra i (p.ej: salíiiiiii)
        word = re.sub(r'ja{2,}', 'ja', word) #remueve las "risas" (p.ej: jaaaaaa)
        word = re.sub(r'[^\w\s@ñ]', '', word, flags=re.UNICODE) #remueve todos los símbolos no alfanuméricos excepto @ y ñ
        word = re.sub(r'\b@\w+\b', '', word) #remueve todos los usuarios de Twitter
        word = re.sub(r'\b\w{1,2}\b', '', word) #remueve todas las palabras de una o dos letras

        return word

def grafico_pie(df, column_name='Polaridad'):
    file_path = f"{uuid.uuid4()}_sentimiento.jpg"
    plt.figure(figsize=(8, 6))
    polaridad_counts = df[column_name].value_counts()
    plt.pie(polaridad_counts, labels=polaridad_counts.index, autopct='%1.1f%%', startangle=140)
    plt.title("Distribución de Polaridad")
    plt.savefig(file_path, bbox_inches="tight")
    plt.close()
    return file_path

def grafico_barras(df, column_name='Emocion'):
    file_path = f"{uuid.uuid4()}_sentimiento.jpg"
    plt.figure(figsize=(8, 6))
    ax = sns.countplot(x=column_name, data=df)
    for p in ax.patches:
        ax.annotate(format(p.get_height()), (p.get_x() + p.get_width() / 2., p.get_height()), ha = 'center', va = 'center', xytext = (0, 10), textcoords = 'offset points')
    plt.xlabel("Emocion")
    plt.ylabel("Cantidad")
    plt.title("Histograma de Emocion")
    plt.savefig(file_path, bbox_inches="tight")
    plt.close()
    return file_path

pln = ProcesamientoLenguaje()
stop_words = stopwords.words('spanish')

# Función que lee el archivo CSV
def procesar_csv(file):
    if file is None:
        return "No se ha cargado ningún archivo."

    csv_bytes = file.getvalue()#.encode('utf-8')
    csv_read_buffer = io.StringIO(csv_bytes.decode('utf-8'))
    df = pd.read_csv(csv_read_buffer, delimiter=';')
    print(df)
    #df = pd.read_csv(file.name, delimiter=';')
    df['Fecha'] = pd.to_datetime(df['Fecha'], format='%d/%m/%y')
    df = get_sentiment(df, "Comentario")
    df = get_emotions(df, "Comentario")
    
    df['Comentario_clean'] = df['Comentario'].apply(pln.cleaner)
    df['Comentario_clean'] = df['Comentario_clean'].apply(lambda x: ' '.join([word for word in x.split() if word.lower() not in (stop_words)]))
    df['Comentario_clean'] = df['Comentario_clean'].apply(pln.postags_and_stopwords)
    output_file = f"{uuid.uuid4()}_processed_output.csv"
    df.to_csv(output_file, index=False)

    grafico_pie_path = grafico_pie(df)
    grafico_barras_path = grafico_barras(df)
    return df.head(10), output_file # Muestra las primeras filas


# Configuración de la app en Streamlit
st.title("Cargar y visualizar CSV")
st.write("Sube un archivo CSV para ver los primeros registros. El archivo CSV debe tener los campos Fecha y Comentario.")

# Subir archivo
file = st.file_uploader("Archivo CSV", type=["csv"])

if file is not None:
    # Procesar el archivo y obtener el DataFrame y la ruta del archivo procesado
    df, processed_file_path = procesar_csv(file)
    
    # Mostrar vista previa del DataFrame
    st.write("Vista previa del archivo procesado:")
    st.dataframe(df)

    # Generar y mostrar gráficos
    torta_path = grafico_pie(df)
    barras_path = grafico_barras(df)

    # Mostrar gráficos en Streamlit
    st.image(torta_path, caption="Gráfico de torta")
    st.image(barras_path, caption="Gráfico de barras")

    # Opción para descargar el archivo CSV procesado
    with open(processed_file_path, 'rb') as f:
        st.download_button(
            label="Descargar CSV procesado",
            data=f,
            file_name=f"{uuid.uuid4()}_processed_output.csv",
            mime="text/csv"
        )