<jupyter_start><jupyter_text>Práctica 2: Aprendizaje automático__Fecha de entrega: 16 de mayo de 2021__El objetivo de esta práctica es aplicar los distintos algoritmos de aprendizaje automático disponibles en la scikit-learn [sklearn](https://scikit-learn.org/stable/) sobre varios conjuntos de datos y aprender a interpretar los resultados obtenidos. La práctica consta de 3 notebooks que se entregarán simultáneamente en la tarea de entrega habilitada en el Campus  Virtual.Lo más importante en esta práctica no es el código Python, sino el análisis de los datos y modelos que construyas y las explicaciones razonadas de cada una de las decisiones que tomes. __No se valorarán trozos de código o gráficas sin ningún tipo de contexto o explicación__.Finalmente, recuerda establecer el parámetro `random_state` en todas las funciones que tomen decisiones aleatorias para que los resultados sean reproducibles (los resultados no varíen entre ejecuciones).  Apartado 1: Clustering __Número de grupo: 2__Nombres de los estudiantes: <NAME>, <NAME>, <NAME>.<jupyter_code>RANDOM_STATE=333<jupyter_output><empty_output><jupyter_text>1) Carga del conjunto de datosCrea un dataframe a partir del fichero `countries_of_the_world.csv` que se proporciona junto con la práctica. Usa como índice el nombre de los países. Vamos a eliminar la columna `Region` por ser categórica y todas las filas en las que faltan valores usando la operación `dropna`.Muestra el dataframe resultante y explica cuántos países y variables contiene.<jupyter_code>import pandas as pd
filename = "countries_of_the_world.csv"
#column_names=["Country","Region","Population","Area(sq.mi.)","Pop.Density(per sq. mi.)","Coastline (coast/area ratio)","Net migration",
 #             "Infant mortality (per 1000 births)","GDP ($ per capita)","Literacy (%)","Phones (per 1000)","Arable (%)","Crops (%)"
  #            ,"Other (%)","Climate","Birthrate","Deathrate","Agriculture","Industry","Service"]

df = pd.read_csv(filename)
df = df.set_index("Country")
df = df.drop(["Region"],axis=1)
df = df.dropna(axis=0) #elimina las filas que contengan algun hueco
df<jupyter_output><empty_output><jupyter_text>El dataframe contiene 179 países y 18 variables porque el dataframe es 179x18   2) Análisis de los datosEn este notebook vamos a trabajar con un subconjunto de las variables. Crea un nuevo dataframe que sólo contenga las variables `GDP ($ per capita)`, `Literacy (%)`, `Phones (per 1000)`, `Agriculture`, `Industry` y `Service`. ¿Qué crees que representan cada una de esas variables?Analiza razonadamente las distribuciones de cada una de las variables (medias, desviaciones típicas, rangos, ...) y las principales relaciones entre pares de variables (diagrama de dispersión, coeficientes de correlación, ...).<jupyter_code>df2=df.loc[:,['GDP ($ per capita)','Literacy (%)', 'Phones (per 1000)', 'Agriculture', 'Industry', 'Service']]
df2.describe() #saca las variables<jupyter_output><empty_output><jupyter_text>VARIABLES1. GDP : producto interior bruto per cápita (medido en dólares).2. Literacy : porcentaje de personas alfabetas.3. Phones : móviles por cada 1000 habitantes.4. Agriculture : porcentaje de sector primario sobre el PIB del país.5. Industry : porcentaje de sector secundario sobre el PIB del país.6. Service : porcentaje de sector servicios sobre el PIB del país.  DISTRIBUCIONES1. GDP : Se observa que la desviacion es equivalente a la media, lo que significa que existen muchos países muy pobres al igual que muchos países muy ricos. Se evidencia una gran brecha económica entre los países no desarrollados o del 3er mundo y las potencias desarrolladas.2. Literacy :  Al contrario de GDP, el indice de alfabetización es muy alto en la mayor parte del mundo. De hecho, a pesar de que el mínimo es un 17% (Níger), el 75% de los países se encuentran por encima del 70% de alfabetización de su población. Se concluye que a excepción de los países más pobres del mundo, en el resto existe un alto porcentaje de alfabetización.3. Phones : Este índice también separa claramente a países desarrollados y subdesarrollados. La media es un poco engañosa, pues en realidad en el 50% de los países se tienen 137 o menos por cada 1000 habitantes, mientras que en las potencias mundiales sobrepasan los 600, llegando a ser el máximo de 900. Se aprecia una correlación entre GDP y los móviles, lo cual tiene gran sentido. Más adelante lo comprobaremos con algunas gráficas.4. Sectores : el sector primario es en el que se aprecian mayores variaciones entre los países, aunque en la mayoría de ellos constituye un pequeñisimo porcentaje del PIB; en cuanto al secundario y terciario, no existe una brecha tan grande. De hecho el terciario es en la mayoría el mayor porcentaje del PIB.<jupyter_code>#coeficientes de correlación
df2.corr(method='pearson')<jupyter_output><empty_output><jupyter_text>OBSERVACIONES1. Como ya hemos indicado anteriormente, Phones y GDP son las más relacionadas (linealmente, pues el coeficiente de pearson mide la correlación lineal) entre sí; es decir, cuando una aumenta la otra también lo hace. De hecho, esa relación es muy estrecha, pues el valor máximo es de 1.2. En contraposición con los móviles por cada 1000 habitantes, la agricultura está inversamente relacionada con GDP. En los paises menos desarrollados, con un menor GDP, es el sector primario el motor principal de la economía (muy notable en países asiáticos como Cambodia o Myanmar). De igual forma, también es inversamente proporcional en una medida muy parecida al índice de los móviles, lo cual tiene sentido pues Phones y GDP tienen un coeficiente muy elevado.3. En cuanto a la alfabetización, no presenta grandes relaciones con ninguna variable. Esto se debe al gran avance de los países más pobres en este aspecto. Quizas nombrar la relación con los móviles, aunque no es muy destacada. Puede tener sentido el hecho de que en países que tienen muchos móviles, la inmensa mayoría de la población es alfabeta.4. El sector secundario es el menos relacionado con el resto de indicadores. Una razón puede ser su elevada extensión por todos los países. De hecho, son muchas las empresas multinacionales que establecen fábricas en partes más desfavorecidas (buscando el máximo beneficio posible), dato que creemos afecta a este índice. Aunque parezca sorprendente, es con el sector servicio con quien presenta una mayor relación inversa. Puede deberse al crecimiento del sector terciario en los países 1er mundistas e inclusive en fases de desarrollo, que pretenden explotar el turismo internacional.5. El sector terciario es el gran artíficice de un GDP elevado, como se observa en los tres coeficientes de los sectores con el GDP. De hecho, se observa que al igual que el GDP, los móviles por cada 1000 habitantes es otro indicador de que el sector terciario es el más importante, por lo general.<jupyter_code>#Diagrama de dispersion

import seaborn as sns
sns.pairplot(df2, diag_kind='kde')<jupyter_output><empty_output><jupyter_text>OBSERVACIONESSe confirma lo analizado mediante los coeficientes de correlación y los valores de las distribuciones. De hecho, en la gráfica se observa de forma sencilla las relaciones aclaradas. Por destacar algunas aportaciones: 1. La mayoría de países tiene un GDP muy bajo. Existe una gran brecha económica entres países desarrollados y no desarrollados. 2. En todos los países desarrollados existe un elevadísimo porcentaje de alfabetización, aunque también en países menos desarrollados. 3. Phone y GDP guardan una relación muy estrecha (la gráfica se parece a la recta y=x). 4. Si el sector primario es un notable porcentaje del PIB de cada país, el PIB será muy bajo.   3) Preprocesar los datosTeniendo en cuenta que vamos a utilizar el algoritmo k-Means para encontrar grupos de países similares, explica razonadamente si es necesario o no cambiar la escalas de los datos y si a priori es mejor reescalarlos (MinMaxScaler) o estandarizarlos (StandarScaler).Si decides preprocesarlos, accede al array interno del dataframe y crea un nuevo array con los datos escalados.  PREPROCESADOEs necesario preprocesar los datos, pues al medir distancias entre varias variables podemos obtener resultados sin sentido. Por ejemplo, una distancia de 50 unidades en la variable de Phones no es muy significante, mientras que en otras variables no tiene sentido ya que miden porcentajes (0-1). En este caso distancias muy pequeñas en esta variable van a a marcar la diferencia, lo que es un sin sentido!!!En el diagrama de dispersión se observa que casi ninguna variable sigue una distribución normal (debe ser simétrica respecto a un punto), si bien es cierto que la formas de las distribuciones tampoco distan demasiado. Por ello, a pesar de que los datos no procedan de una distribución normal, creemos conveniente aplicar el escalado estandarizado.<jupyter_code>from sklearn.preprocessing import StandardScaler, MinMaxScaler
scaler = StandardScaler()
scaler.fit(df2.values)
S2_scaled = scaler.transform(df2.values)

#scalerMM=MinMaxScaler()
#scalerMM.fit(df2.values)
#S2_scaled=scalerMM.transform(df2.values)<jupyter_output><empty_output><jupyter_text>4) Encontrar el número óptimo de clustersDecide razonadamente el número óptimo de clusters en el rango 2..10. Ten en cuenta que para interpretar los datos no nos interesa tampoco tener un número excesivo de clusters. Para hacerlo calcula y pinta el diagrama del codo, el índice davies_boulding y el coeficiente silhouette en función del número de clusters.<jupyter_code>import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn.metrics import davies_bouldin_score, silhouette_score


K_MAX = 10
score = np.zeros(K_MAX-2)
davies_boulding = np.zeros(K_MAX-2)
silhouette = np.zeros(K_MAX-2)
for k in range(2, K_MAX): 
    km = KMeans(init='random', n_clusters=k, random_state=RANDOM_STATE)
    km.fit(S2_scaled)
    
    score[k-2] = -1 * km.score(S2_scaled)
    davies_boulding[k-2] = davies_bouldin_score(S2_scaled, km.labels_)
    silhouette[k-2] = silhouette_score(S2_scaled, km.labels_)

# diagrama del codo
plt.plot(range(2, K_MAX), score)
plt.xlabel('Number of Clusters')
plt.ylabel('Score')
plt.title('Elbow Curve')
plt.show()

# davies boulding
plt.plot(range(2, K_MAX), davies_boulding)
plt.xlabel('Number of Clusters')
plt.ylabel('Davies Boulding value')
plt.title('Valor de Davies Boulding de 2 a 10')
plt.show()

# silhouette
plt.plot(range(2, K_MAX), silhouette)
plt.xlabel('Number of Clusters')
plt.ylabel('Silhouette value')
plt.title('Valor de Silhouette de 2 a 10')
plt.show()<jupyter_output><empty_output><jupyter_text>OBSERVACIONES1. En el diagrama del codo se utiliza el indicador score. Score mide la suma de las distancias de cada punto a su cluster, por lo que es mejor cuanto menor sea (clusters más compactos). Sin embargo tampoco nos interesan demasiados clusters. Por lo tanto, el nº de clusters idóneos es donde la gráfica deja de decrementar en exceso. En nuestro caso sería k={4,5}.2. El valor de Davies_Boulding es la razón entre las distancias intra-cluster y la inter-cluster. Así pues, cuanto menor sea la medida, mejores cluster obtendremos. Los candidatos a k serían {2,4,5}.3. Silhouette calcula la distancia media al cluster más cercano menos distancia media intra-cluster dividido entre el mayor de ambos. Por lo tanto, cuanto mayor es su valor, más compacta será la agrupación. En este índice los mejores valores son 2 y 3. CONCLUSIONESViendo el índice de Davies y el de Silhouette parece razonable escoger 2 clusters. De hecho, se asemeja a la distribución de países en desarrollados y subdesarrollados. Sin embargo, existen países que se encuentran en vías de desarrollo, difícilmente considerados subdesarrollados o 1er mundistas. Esto está relacionado con la alta distancia de los puntos a sus centroides si tenemos 2 clusters. Si no escogemos k=2, el más apropiado estaría entre k=4 y k=5. Viendo los marcadores, 5 clusters parece una mejor agrupación aunque estamos incluyendo un cluster extra, que a veces puede ser innecesario. Además, si seleccionamos 4 clusters, ambos parámetros son prácticamente iguales y la distancia total aumenta muy poco. Por lo tanto, nuestra decisión es k=4.  5) Descripción de los clustersDescribe los clusters que has obtenido en el apartado anterior y trata identificar el grupo de países que contienen. Si te han salido más de 3 elige 3 de ellos que sean bastante diferentes entre sí. Para hacerlo estudia sus descriptores estadísticos y pinta el diagrama de dispersión en función de cada par de variables usando colores diferentes para cada cluster. ¿Qué clusters se separan mejor y en función de qué variables? ¿y cuáles se confunden más?__Cuidado__: para poder interpretar correctamente los datos necesitas que estén en su escala original. Si decidiste escalar los datos, deberás ejecutar kMeans con los datos escalados pero asignar las etiquetas de clusters al conjunto de datos inicial. En este caso es muy sencillo porque el algoritmo no cambia el orden de los datos así que puedes crear directamente una nueva columna en el dataframe original con esas etiquetas. Puede que aparezca un SettingWithCopyWarning por asignar una nueva columna en un dataframe que es una vista de otro dataframe. Puedes ignorar este aviso o puedes hacer una copia del dataframe con `copy` para que no comparta memoria con el otro.<jupyter_code>from sklearn.cluster import KMeans
km = KMeans(init='random', n_clusters=4, random_state=RANDOM_STATE)
km.fit(S2_scaled)
pd.options.display.max_rows=None #Muestra todas las filas del dataframe
df2 = df2.assign(cluster=pd.Series(data=km.labels_,index=df2.index)) #Añade el cluster al dataframe
df2
df2.groupby(["cluster"]).describe().transpose()<jupyter_output><empty_output><jupyter_text>ELECCIÓNHemos escogido los tres primeros clusters, que parecen asemejarse a las ideas de los tres tipos de países segun su desarrollo económico. El cuarto cluster parece ser un tipo de país en el que predomina la industria, con un nivel bajo en servicios. En este cluster se encuentran países como China, una de las potencias mundiales, o Turkmenistán, cuyo poder económico es mucho más bajo.<jupyter_code>df2.groupby(["cluster"])["GDP ($ per capita)"].plot.density()<jupyter_output><empty_output><jupyter_text>OBSERVACIONESUtilizando el PIB per cápita, es posible diferenciar claramente un cluster del resto. El color azul se corresponde con el cluster 0, el de los países más pobres. También se puede diferenciar el de los países más ricos (cluster 2 - color verde), aunque se entremezcla un poco con el cluster 3 (color rojo), asociado a los países con una fuerte industria.<jupyter_code>df2.groupby(["cluster"])["Literacy (%)"].plot.density()<jupyter_output><empty_output><jupyter_text>OBSERVACIONESUtilizando el porcentaje de población alfabeta, se advierte una enorme separación entre el cluster de los países más desarrollados y el resto. Sin embargo, esta variable no permite separar los clusters 1 y 3. Para ello recurrimos a otras variables.<jupyter_code>df2.groupby(["cluster"])["Phones (per 1000)"].plot.density()<jupyter_output><empty_output><jupyter_text>OBSERVACIONESLa variable Phones da la misma información que la del GDP, aunque en este caso es todavía más evidente la diferencia entre los países menos desarrollados y los más desarrollados. Al igual que en las variables anteriores, los clusters 1 y 3 siguen sin diferenciarse.<jupyter_code>df2.groupby(["cluster"])["Agriculture"].plot.density()<jupyter_output><empty_output><jupyter_text>OBSERVACIONESMismo caso que la alfabetización, solo que en esta variable son las potencias mundiales las que presentan los valores más bajos.<jupyter_code>df2.groupby(["cluster"])["Industry"].plot.density()<jupyter_output><empty_output><jupyter_text>OBSERVACIONESGracias al sector secundario se distinguen con claridad el cluster 1 y el 3. Como hemos mencionado anteriormente, se advierte que el cluster 3 es el asociado a los países con una gran industria (por lo general suele ser países en los que la industria textil es el factor principal de su economía). A diferencia del resto de variables analizadas, el cluster de los países más pobres y los más ricos se diferencian muy poco.<jupyter_code>df2.groupby(["cluster"])["Service"].plot.density()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.05930958501652589, 'fraction_numerical': 0.011568123393316195, 'mean_word_length': 5.447908445146014, 'pattern_counts': {'":': 0, '<': 60, '<?xml version=': 0, '>': 60, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '571775', 'license': 'Apache-2.0', 'n_tokens_mistral': 5299, 'n_tokens_neox': 5100, 'n_words': 2188, 'path': 'Practicas-IA/practica-5-clustering.ipynb', 'repo_name': 'rzAlejandro/Practicas-Universidad', 'size': '16362'}