# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# <img src=".\img\mioti.png">   
# <br />
# <center style="color:#888">Proyecto Activaciones Madrid SAMUR-PC<br/></center>
#
# # Proyecto Activaciones Madrid SAMUR-PC: Clasificación

# <img src="./img/samur690.jpg" style="width: 800px">

# # 1. Visión general del problema.
#
# Nuestro objetivo es lograr clasificar las emergencias en función de su porcentaje de hospitalización, para conocer cuáles son más propensas a terminar en ingresos y realizar comparaciones entre ellas. Esto lo vamos a conseguir a través de las diferentes medidas de las que disponemos sobre activaciones de emergencias, realizando el tratamiento adecuado de estos datos

# +
# instalar requisitos
# import sys
# # !{sys.executable} -m pip install pandas numpy nltk wordcloud

# +
# %matplotlib inline

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import scipy.cluster.hierarchy as sch
from sklearn.preprocessing import Normalizer
from sklearn.cluster import AgglomerativeClustering
from wordcloud import WordCloud
import nltk
from nltk.tokenize import sent_tokenize, word_tokenize
from nltk.corpus import stopwords
# -

# ## 2.Obtención de los datos
#
# Una vez importadas las librerías necesarias para el análisis, procedemos a la importación del fichero preprocesado. Para llevar a cabo nuestro objetivo, será necesario realizar otro preprocesamiento adicional

# +
#Se importa el archivo y se realiza una visualización del contenido de sus datos

emergencias_df=pd.read_csv('datos/emergencias_pp_def.csv',sep=';', encoding='iso8859')
emergencias_df.head()
# -

# ## 3. Analizar y preparar los datos para nuestro algoritmo
#
# Para realizar nuestra clasificación vamos a necesitar las fechas de activación de cada emergencia para conocer el número total de llamadas a Samur, el código para saber el tipo y si tuvo o no hospitalización
#
# En primer lugar vamos a quedarnos con las variables que necesitamos de nuestro dataframe, después pasaremos a realizar las transformaciones necesarias hasta adaptar nuestro dataset al formato que nos proporcionará la clasificación que estamos buscando

# +
#Se transforman las variables de fecha y hora a datetime y se revisa la información del dataframe

emergencias=emergencias_df[['Fecha Activacion','Código','Hospital']].copy()
emergencias['Fecha Activacion']=pd.to_datetime(emergencias['Fecha Activacion'])
emergencias.info()

# +
#Se visualiza el número de tipos de emergencias y sus etiquetas

print('cuenta tipo emergencia: ',len(emergencias['Código'].unique()))
print()
print('tipo de emergencia: ',emergencias['Código'].unique())
# -

# ## 4. Preparar los datos para el algoritmo de Machine Learning que vamos a utilizar
#
# Disponemos de un total de 95 tipos de emergencias diferentes, el objetivo ahora es unirlas en función de la proporción de hospitalizaciones que acumule cada una sobre su total de activaciones

# ###  Variables Codificadas
#
# La variable 'Hospital' que nos facilita la información sobre si la emergencia acabó en ingreso o no esta definida como tipo objeto. Para poder calcular el número total de hospitalizaciones vamos a pasar a codificar la variable mediante una función

# +
#Creamos un nuevo dataframe con los campos que vamos a utilizar

emergencias_agrup=emergencias[['Código','Fecha Activacion','Hospital']]

#Se codifica la variable hospital

def cod_hosp(x):
    if x['Hospital']=='Sin hospitalizacion':
        x['Hospital']=0
    else:
        x['Hospital']=1
    return x

#Se aplica la función
emergencias_agrup=emergencias_agrup.apply(cod_hosp,axis=1)
emergencias_agrup.sample(15)
# -

# ### Agrupación de variables
#
# A continuación vamos a generar un nuevo dataframe donde agruparemos las emergencias, realizando una cuenta de las fechas de activación obtendremos el número total de activaciones de cada emergencia, sumando los valores del campo 'Hospital' codificado el número de veces que cada emergencia acabó en hospitalización

# +
#Se agrupan las variables

emergencias_agrup=emergencias_agrup.groupby('Código').agg({'Fecha Activacion':'count','Hospital':'sum'}).reset_index()

#Se cambia el nombre de Fecha Activación para facilitar la comprensión del dataframe

emergencias_agrup=emergencias_agrup.rename(columns={'Fecha Activacion':'Nº Activaciones'})
emergencias_agrup
# -

# ### Estandarización de variables
#
# Para hacer el entrenamiento de nuestros modelos más sencillos, estandarizaremos las variables normalizándolas

# +
#Se normalizan los datos

data=emergencias_agrup[['Nº Activaciones','Hospital']]
emergencias_norm=Normalizer().fit_transform(data)
# -

# ## 5. Seleccionar un modelo y entrenarlo.
#
# Una vez procesados los datos vamos a determinar el modelo que vamos a utilizar. En este caso hemos optado por un clustering jerárquico
#

# ### Cálculo del número óptimo de clusters
#
# Ahora toca determinar cuál es el número óptimo de clusters en los que vamos a agrupar las emergencias, para ello vamos a utilizar un dendrograma. Una ver visualizado, un corte sobre la línea más larga generada entre las uniones de clusters nos indicará el mejor número de grupos a generar

# +
#Se realiza el dendrograma para determinar el número óptimo de clusters

dendrograma=sch.dendrogram(sch.linkage(emergencias_norm,method='ward'))
plt.suptitle('Dendrograma')
plt.axhline(y=1.25,xmin=0,xmax=100, color='k', linestyle='--');
# -

# Visualizando el dendrograma vemos que lo más óptimo es dividir el número de emergencias en dos grupos. A continuación pasaremos a realizar la clusterización, después veremos qué códigos forman parte de cada grupo

# ### Aplicamos el algoritmo
#
# Una vez determinado el número óptimo del clusters vamos a pasar a definir y entrenar el modelo, después realizaremos una visualización de los resultados obtenidos

algoritmo = AgglomerativeClustering(n_clusters = 2, affinity='euclidean', linkage='ward')
#Se entrena el algoritmo
algoritmo.fit(emergencias_norm)
pred1 = algoritmo.fit_predict(emergencias_norm)
pred1=pd.Series(pred1)
emergencias_agrup1=pd.concat([emergencias_agrup,pred1],axis=1).rename(columns={0:'cluster'})
emergencias_agrup1=emergencias_agrup1.set_index('Código')
emergencias_agrup1

# +
#Se imprimen las listas de los códigos de cada grupo

cluster_0=emergencias_agrup1[emergencias_agrup1['cluster']==0].index
print('Emergencias cluster 1')
print()
print(cluster_0)
print()
cluster_1=emergencias_agrup1[emergencias_agrup1['cluster']==1].index
print('Emergencias cluster 2')
print()
print(cluster_1)
print()


# -

# ## 6. Análisis de resultados
#
# Nuestro modelo a agrupado las emergencias en dos grupos, ahora nos interesa conocer qué tipos se encuentran en cada uno de ellos, si alguno destaca más que el resto y cuáles son sus porcentajes de hospitalización
#

# ### Procesamiento de texto
#
# Anteriormente imprimimos las listas con las emergencias que forman cada cluster, ahora queremos determinar cuáles son las más frecuentes en cada grupo, para ello vamos a trabajar con estas listas. Los pasos a seguir serán los siguientes
#
# #### Limpieza de texto
#
# En primer lugar vamos a filtrar los textos eliminando símbolos de puntuación, números y palabras como artículos o determinantes que no aportan información

def tokenizar(cluster):
    cluster_token = ''
    cluster_token=word_tokenize(cluster)
    return cluster_token


cluster_1_token = []
for t in cluster_0:
    cluster_1_token.extend(tokenizar(t))
print(cluster_1_token)

cluster_2_token = []
for t in cluster_1:
    cluster_2_token.extend(tokenizar(t))
print(cluster_2_token)

stopwords=stopwords.words('spanish')
def filtrar_cluster(palabras):
    out = []
    #Se crea una lista de palabras y signos no deseados
    eliminar=['.',',','¡','!','¿','?','""','(',')','=','/','+','#','$','&','*','-',';',':','_','{','}','[',']',"n't",
             "'s","'ve'",'...','-we','..','``','3','....','2',"'","'re",'iii',"'m",'<',"'d",'b','2.5','1','y','y/o']
    for word in palabras:
        if word in stopwords or word in eliminar:
            pass
        else:
            out.append(word)
    return out


cluster_1_filtrado = filtrar_cluster(cluster_1_token)
print(cluster_1_filtrado)

cluster_2_filtrado = filtrar_cluster(cluster_2_token)
print(cluster_2_filtrado)

# ### Resultados
#
# Una vez filtradas las emergencias vamos a pasar a ver qué emergencias componen cada uno de los grupos
#
# #### Visualización
#
# Vamos a realizar una visualización mediante una nube de palabras

cluster_1_filtrado_join = ' '.join(cluster_1_filtrado)
wordcloud = WordCloud(width = 1000, height = 500, relative_scaling = 0.5).generate(cluster_1_filtrado_join)
plt.figure(figsize=(15,8))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()

cluster_2_filtrado_join = ' '.join(cluster_2_filtrado)
wordcloud = WordCloud(width = 1000, height = 500, relative_scaling = 0.5).generate(cluster_2_filtrado_join)
plt.figure(figsize=(15,8))
plt.imshow(wordcloud)
plt.axis("off")
plt.show()

# #### Agrupaciones
#
# En las visualizaciones podemos ver lo siguiente:
#
#    * Cluster 1. Agrupa emergencias patológicas y accidentes
#    
#    * Cluster 2. La atención psicológica es la emergencia más notoria en este grupo
#    
# #### Tablas de resultados
#
# Vamos a generar dataframes con cada uno de los cluster y visualizar su contenido

cluster_1_df=emergencias_agrup1[emergencias_agrup1['cluster']==0].sort_values('Nº Activaciones',ascending=False)
cluster_1_df['% hospital']=cluster_1_df['Hospital']/cluster_1_df['Nº Activaciones']
cluster_1_df

cluster_1_df.describe()

cluster_2_df=emergencias_agrup1[emergencias_agrup1['cluster']==1].sort_values('Nº Activaciones',ascending=False)
cluster_2_df['% hospital']=cluster_2_df['Hospital']/cluster_2_df['Nº Activaciones']
cluster_2_df

cluster_2_df.describe()


# #### Definición de cada cluster
#
# Con los resultados obtenidos pasaremos aa definir cada cluster de la siguiente manera:
#
#    * Cluster 1: Emergencias con alto grado de hospitalización compuestas mayormente por patologías y accidentes. Las clasificaremos como alta hospitalización
#    
#    * Cluster 2: Emergencias sin apenas hospitalizaciones con la atención psicológica como principal tipo. Las clasificaremos como baja hospitalizacion
#
# #### Unión en dataframe original
#
# Ahora pasaremos a añadir esta información al dataframe original

def union(x):
    emer=''
    if x['Código'] in cluster_0:
        emer='Ata hospitalizacion'
    elif x['Código'] in cluster_1:
        emer='Baja hospitalizacion'
    return emer


emergencias_cluster=emergencias_df.copy()
emergencias_cluster['cluster']=emergencias_cluster.apply(union,axis=1)
emergencias_cluster.sample(15)

# #### Representación gráfica

emergencias_g=emergencias_cluster.pivot_table(index='Distrito',columns='cluster',values='Código',aggfunc='count',margins=True)
emergencias_g['Alta']=emergencias_g['Ata hospitalizacion']/emergencias_g['All']
emergencias_g['Baja']=emergencias_g['Baja hospitalizacion']/emergencias_g['All']
emergencias_g=emergencias_g.drop('All',axis=0)
emergencias_g

em_g=emergencias_cluster.groupby('cluster').agg({'Código':'count'})
em_g=np.round(em_g['Código']/em_g['Código'].sum(),2)
em_g=em_g.drop('',axis=0)
em_g

distrito=emergencias_g.index
emer=['Ata hospitalizacion','Baja hospitalizacion']
fig,ax=plt.subplots(1,2,figsize=(15,5))
ax[0].pie(em_g,labels=emer,autopct="%0.1f %%",startangle=270)
ax[0].set_title('Proporción cluster')
ax[1].bar(emergencias_g.index,emergencias_g['Alta'],label='Ata hospitalizacion')
ax[1].bar(emergencias_g.index,emergencias_g['Baja'],bottom=emergencias_g['Alta'],label='Baja hospitalizacion')
plt.axhline(y=0.5, color='k', linestyle='--')
ax[1].set_ylabel('Proporción relativa')
ax[1].set_xlabel('Distrito')
ax[1].set_title('Proporción tipo emergencia por distrito')
fig.suptitle('Visualización cluster')
ax[1].spines['top'].set_visible(False)
ax[1].spines['right'].set_visible(False)
ax[1].spines['bottom'].set_visible(False)
ax[1].spines['left'].set_visible(False)
ax[1].set_xticks(distrito)
ax[1].set_xticklabels(distrito,rotation=85)
ax[1].grid(True, axis='y')
ax[1].legend(bbox_to_anchor=(1, 1),frameon=False);

# +
distrito=emergencias_g.index
emer=['Ata hospitalizacion','Baja hospitalizacion']
fig,ax=plt.subplots(figsize=(15,5))

ax.bar(emergencias_g.index,emergencias_g['Alta'],label='Ata hospitalizacion')
ax.bar(emergencias_g.index,emergencias_g['Baja'],bottom=emergencias_g['Alta'],label='Baja hospitalizacion')
plt.axhline(y=0.5, color='k', linestyle='--')
ax.set_ylabel('Proporción relativa')
ax.set_xlabel('Distrito')
ax.set_title('Proporción tipo emergencia por distrito')

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.spines['bottom'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.set_xticks(distrito)
ax.set_xticklabels(distrito,rotation=85)
ax.grid(True, axis='y')
ax.legend(bbox_to_anchor=(1, 1),frameon=False);
# -

# ## 7. Conclusiones
#
# * Realizada la clasificación de emergencias y visualizando los resultados podemos concluir que existen dos tipos de emergencias en función de sus hospitalizaciones. Las emergencias que acumulan hospitalizaciones altas se centran sobre todo en patologías y accidentes mientras que las hospitalizaciones bajas en atención psicológica y servicios básicos
#
#
# * Con esta clasificación en función de la activación de la emergencia el servicio SAMUR podría establecer tiempos de prioridad en sus respuestas o ponerse en contacto con los hospitales para advertir que es probable un nuevo ingreso
#
#
# * Esta clasificación también nos puede servir para hacer comparativas entre diferentes emergencias, por ejemplo podemos ver que los accidentes de patinete y bicicleta tienen un porcentaje similar de hospitalización al de las patologías cardiovasculares y con ello, que autoridades diferentes a SAMUR elaboren planes para reducir este tipo de incidentes como, por ejemplo habilitando más carriles bici



StarcoderdataJupyterScriptsDedupFiltered