El estudio de datos de paises es de gran importancia para la humanidad debido a que permite caracterizar los principales problemas de la misma, mostrar las principales tendencias que experimentan los distintos paises y además otorga parametros de referencia que permiten determinar la situación de un país en un momento dado de la historia o a lo largo de esta misma. Uno de los principales organismos internacionales que se encarga de la recopilación y estudio de los paises es el banco mundial, el cual tiene como objetivo declarado la reducción de la pobreza. Mediante el estudio de los datos del banco mundial se pretende encontrar clusters de paises de acuerdo a su desarrollo, relacionarlos con su ubicación geografica y estudiar su comportamiento a travez del tiempo, para así poder caracterizar el posicionamiento de Chile con respecto al resto del mundo y países de la OCDE. Adicionalmente se busca determinar las variables que más afecta en el desarrollo de los paises.
Para la realización de clustering de datos del Banco Mundial se utilizó la base de datos de "Development" de la misma institución, la cual incluye todas las subcategorias que pueden descargarse por separado a desde la misma página web. La base de datos se encuentra disponibe en:
http://databank.worldbank.org/data/reports.aspx?source=world-development-indicators#
La pagina entregada anteriormente contiene mas de 1500 caracteristicas de mas de 200 paises entre los años 1960 y 2017, es decir que contiene millones de datos, es por esto que la página no permite descargar todos los datos al mismo tiempo y se optó por descargar los datos entre 1980 y 2015 en intervalos de, por lo general, 5 años en formato xlsx usandp la nomenclatura "dev_añoinicial-añofinal.xlsx". Al observar los datos de cada Excel es posible notar que tienen un formato amigable con las librerias de data mining de python (gran redundancia en donde cada pais tiene un numero de filas igual al numero de caracteristicas estudiadas), que tienen una firma al final del documento que no permite leer el documento y los datos faltantes son representados por el string "..". A continuación se presenta un codigo que permite ver el formato de un excel descargado una vez que se ha eliminado "a mano" la firma al final del mismo.
import numpy as np
import pandas as pd
name = 'dev_2006-2010.xlsx' #formato dev_añoinicial-añofinal.xlsx
anho = '2010' #año para el cual se pretende extraer información
d_input = pd.read_excel(name, keep_default_na=False, na_values='..')
d_input.head()
Para poder realizar la exploración inicial es necesario adaptar la base de datos a un formato adecuado que permita utilizar las librerias de data mining de python, es decir un formato en donde las filas sean los paises y las columnas sean las caracteristicas. A continuación se entregan dos codigos, uno encargado de eliminar columnas innecesarias para el estudio con el fin de reducir los tiempos de procesamiento y el otro encargado de cambiar el formato de la base de datos al formato adecuado.
todel_columns = ['Series Code']
for column in todel_columns:
d_input.__delitem__(column)
#d_input.head()
#El metodo np.unique ordena las listas
#es necesario devolver la lista a su orden original
#====================================================
paises_d = np.array(d_input['Country Name'])
indexes_d = np.unique(paises_d, return_index=True)[1]
paises_d = [paises_d[index] for index in sorted(indexes_d)]
features_d = np.array(d_input['Series Name'])
indexes_d = np.unique(features_d, return_index=True)[1]
features_d = [features_d[index] for index in sorted(indexes_d)]
codes_d = np.array(d_input['Country Code'])
indexes_d = np.unique(codes_d, return_index=True)[1]
codes_d = [codes_d[index] for index in sorted(indexes_d)]
#====================================================
columns_d = [('Country Name',paises_d),('Country Code',codes_d)]
empty = 0
notempty = 0
for c_feature in features_d:
vals = d_input[d_input['Series Name'] == c_feature][anho+' ['+'YR'+anho+']'] #Valores de una caracteristica para todos los paises
xvals = vals.tolist()
if (~np.isnan(np.array(xvals))).any(): #No considerar columnas con puros NaN
columns_d.append((c_feature,xvals))
notempty+=1
else:
empty+=1
new_input = pd.DataFrame.from_items(columns_d)
new_input.head()
Haciendo un analisis visual de los datos es posible notar que existe una cantidad significativa de caracteristicas con valores faltantes para un gran numero de paises y paises con un gran numero de caracteristicas sin datos. Se determinó que la inclusión de estas filas y columnas con medidas como rellenar datos faltantes con el promedio de la fila perjudica considerablemente la obtención de resultados, es por esto que se optó por eliminar caracteristicas y paises que tuvieran una cantidad considerable de datos faltantes. A continuación se encuentra el script que realiza esta operación.
coef = 0.2 # nans/total debe dar superior a este numero
deleted = 0
output = new_input
todel = []
itodel = []
for k in range(2,len(new_input.keys())):
llave = new_input.keys()[k]
valores = new_input[llave]
total = valores.shape[0]
nans = np.count_nonzero(np.isnan(valores))
xnans = 0
if coef < float(nans)/float(total):
todel.append(llave)
itodel.append(k)
deleted += 1
for column in todel:
output.__delitem__(column)
print("Se eliminaron "+str(deleted)+" columnas")
deleted = 0
new_output = output.T
todel = []
itodel = []
for k in range(len(new_output.keys())):
llave = new_output.keys()[k]
valores = new_output[llave] #
xvalores = np.array(valores)[2:-1]
xvalores = xvalores.astype(float)
total = xvalores.shape[0]
#pdb.set_trace()
nans = np.count_nonzero(np.isnan(xvalores))
if coef < float(nans)/float(total):
todel.append(llave)
itodel.append(k)
deleted += 1
for column in todel:
new_output.__delitem__(column)
print("Se eliminaron "+str(deleted)+" filas")
out = new_output.T
out.head()
Una vez que se preprocesaron los datos se exporta la tabla del año a estudiar en otro documento con la nomenclatura "dev_año_proc.xlsx"
writer = pd.ExcelWriter('dev_'+anho+'_proc.xlsx')
out.to_excel(writer,'Data')
writer.save()
import numpy as np
import pandas as pd
import pdb
d_2016 = pd.read_excel('dev_'+anho+'_proc.xlsx', keep_default_na=False,
na_values='')
#el nombre de esta variable NO significa que se esté estudiando el año 2016, lo que determina el año será el
#archivo que lea la variable
d_2016.head()
Tras realizar el calculo de medidas de tendencia central y distribución se descubrió que en la base de datos aparecen como paises agrupaciones como "OCDE Members", "South America" entre otros, por lo que para realizar un correcto estudio de la base de datos es necesario eliminar estos datos redundantes. También se determinó que la diferencia de magnitud entre las caracteristicas estudiadas alterará los resultados obtenidos (Numero de hijos en el orden de las unidades vs poblacion total en el orden de las decenas-centenas de millones, en general), por lo que se optó por efectuar una normalización min-max de los datos.
redun1 = [u'High income', u'High income: OECD', u'OECD members', u'World']
redun2 = [u'East Asia & Pacific',u'East Asia & Pacific (excluding high income)',
u'Euro area',u'Europe & Central Asia',u'European Union',u'Low & middle income',
u'Middle income',u'North America',u'Upper middle income']
redun3 = [u'Arab World', u'Sub-Saharan Africa',
u'Sub-Saharan Africa (excluding high income)', u'Middle East & North Africa',
u'Middle East & North Africa (excluding high income)',
u'Latin America & Caribbean',u'Latin America & Caribbean (excluding high income)',
u'Least developed countries: UN classification',
u'Heavily indebted poor countries (HIPC)',u'High income',u'High income: nonOECD',
u'High income: OECD', u'Euro area',u'Europe & Central Asia',
u'Europe & Central Asia (excluding high income)',u'European Union',
u'East Asia & Pacific',u'East Asia & Pacific (excluding high income)',
u'Lower middle income',u'South Asia']
redun4 = [u'IDA & IBRD total', u'IDA blend', u'IDA only', u'IDA total',
u'East Asia & Pacific (IDA & IBRD countries)',u'Europe & Central Asia (IDA & IBRD countries)',
u'Fragile and conflict affected situations',u'IBRD only',u'Late-demographic dividend',
u'Latin America & the Caribbean (IDA & IBRD countries)',
u'Middle East & North Africa (IDA & IBRD countries)',u'Not classified',
u'Other small states',u'Post-demographic dividend',u'Pre-demographic dividend']
redun5 = [u'Early-demographic dividend',u'Early-demographic dividend',u'Central Europe and the Baltics',
u'South Asia (IDA & IBRD)',u'Sub-Saharan Africa (IDA & IBRD countries)',
u'Sub-Saharan Africa (IDA & IBRD countries)', u'South Asia (IDA & IBRD)',u'Low income']
for out in redun1:
d_2016 = d_2016[d_2016['Country Name'] != out]
for out in redun2:
d_2016 = d_2016[d_2016['Country Name'] != out]
for out in redun3:
d_2016 = d_2016[d_2016['Country Name'] != out]
for out in redun4:
d_2016 = d_2016[d_2016['Country Name'] != out]
for out in redun5:
d_2016 = d_2016[d_2016['Country Name'] != out]
paises = d_2016['Country Name'].values.tolist()
d_2016_n = d_2016
for k in range(2,len(d_2016.keys())):
llave = d_2016.keys()[k]
valores = d_2016[llave]
xvals = valores.tolist()
#Normalización
xmax = np.nanmax(valores)
xmin = np.nanmin(valores)
norm = xmax - xmin
#pdb.set_trace()
if (not np.isnan(xmax)) and norm!=0:
d_2016_n[llave] = (d_2016[llave]-xmin)/norm
d_2016_n.head()
Una vez que se tiene la base de datos en un formato adecuado se realiza un análisis estadistico de los datos.
varianzas = []
promedios = []
maximos = []
minimos = []
desv = []
for k in range(2,len(d_2016_n.keys())):
llave = d_2016_n.keys()[k]
valores = d_2016_n[llave]
count = 0
xmax = np.nanmax(valores)
xmean = np.nanmean(valores)
xmin = np.nanmin(valores)
xstd = np.nanstd(valores)
xvar = np.nanvar(valores)
promedios.append(xmean)
minimos.append(xmin)
maximos.append(xmax)
desv.append(xstd)
varianzas.append(xvar)
sort = np.sort(varianzas)
most = -1
print "Estadisticas con mayor varianza:"
#Se entrega como output las estadisticas con mayor varianza ya que son las que entregan mayor información
#Sin embargo es posible estudiar las otras medidas mediantes las variables promedios, minimos, maximos, etc.
#Recordar que se está rabajando con datos normalizados, por lo que sería necesario revertir la normalización para
#obtener los valores reales en caso de max, min y mean
for i in range(10): #numero de variables deseadas como output
value = sort[most]
j = np.argwhere(varianzas == sort[most])+2
features = d_2016_n.keys()
print str(i+1)+' '+str(features[j])+' ('+str(sort[most]) +')'
most-=1
Otra parte importante de la exploración de los datos consiste el la geración de gráficos, es por esto que se programó un codigo capaz de generar histogramas para una caracteristica determinada
%matplotlib inline
import matplotlib.pyplot as plt
for k in range(2,len(d_2016.keys())):
fig = plt.figure()
ax1 = fig.add_subplot(1, 1, 1)
llave = d_2016.keys()[k]
x = []
for nonan in d_2016[llave]:
if not np.isnan(nonan):
x.append(nonan)
ax1.hist(x, 5, facecolor='blue', alpha=0.75)
ax1.set_xlabel(llave)
ax1.set_ylabel('Total')
plt.show()
plt.close
Tal como se indicó anteriormente, el objetivo del proyecto es realizar un clustering de la base de datos trabajada para estudiar el posicionamiento de Chile en base a su desarrollo y compararlo con los paises de la OCDE, además de la validación de la agrupación de paises según su desarrollo realizando un estudio geográfico y temporal. Las principales problematicas encontradas para esto son la alta dimensionalidad de los datos, lo cual dificulta la visualización de los mismos y el desconocimiento de la posible existencia de una "métrica" que permita comparar datos de años distintos.
Para la realización del estudio mencionado se realizará un clustering con el algoritmo k-means. Inicialmente se desconoce el número de clusters en la base de datos, sin embargo se espera que los clusters serán del tipo desarrollo-ubicación geográfica (Sudamerica desarrollados, Sudamerica subdesarrollados, etc). En base a los resultados entregados por el clustering de los datos se verá a que cluster pertenecen Chile y los paises de la OCDE, asi como los valores de las caracteristicas de mayor varianza a lo largo de los años.
Para el desarrollo del estudio temporal de los clusters será necesario validar o descartar la existencia de una "métrica" que permita agrupar los paises para cualquier año. Para esto se verá la evolución de las caracteristicas de mayor varianza de los clusters a traves del tiempo para determinar si existen patrones en común para la evolución de los paises y de esta forma determinar si corresponde hacer la agrupación según un estandar de desarrollo para cualquier año o si corresponde realizarla aisladamente para cada año.
Finalmente, para el estudio geográfico se hará una visualizacion de los paises clusterizados en forma de mapa, lo cual permitirá comprobar/refutar el supuesto de que el desarrollo de un país está fuertemente relacionado con la ubicación geografica del mismo.
Debido a que se utilizará K-Means para el clustering de los datos de cada año, se debe ejecutar el algoritmo del método del codo para determinar la cantidad óptima de clusters correspondiente a cada año. De la ejecución de este algoritmo para los años entre 1980 y 2016 se determina que un número adecuado de clusters es K = 3.
np_df = d_2016_n.as_matrix()
test = np_df[:,2:]
for row in range(test.shape[0]):
for column in range(test.shape[1]):
val = test[row][column]
#print val
if np.isnan(val):
test[row][column]= promedios[column]
else:
#test[row][column]= val/maximos[column]
pass
xdf = pd.DataFrame(test)
vectors = []
tot = test#.T
for i in range(len(tot[:,0])):
vectors.append(tot[i])
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn import metrics
from scipy.spatial.distance import cdist
X = tot
# k means determine k
distortions = []
K = range(1,10)
for k in K:
kmeanModel = KMeans(n_clusters=k).fit(X)
kmeanModel.fit(X)
distortions.append(sum(np.min(cdist(X, kmeanModel.cluster_centers_, 'euclidean'), axis=1)) / X.shape[0])
# Plot the elbow
plt.plot(K, distortions, 'bx-')
plt.xlabel('k')
plt.ylabel('Distortion')
plt.title('The Elbow Method showing the optimal k')
plt.show()
Una vez que se determina el número de clusters que se usarán en el método de K-Means se utilizan tSNE y PCA para la reducción de la dimensionalidad del dataset y su visualización mediante Scatter Plots.
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
X = vectors
X_embedded = TSNE(n_components=2,n_iter=100000000).fit_transform(X)
X_embedded.shape
plt.scatter(X_embedded[:, 0], X_embedded[:, 1], c="r", cmap=plt.cm.Spectral)
plt.show()
from mpl_toolkits.mplot3d import Axes3D
from sklearn import decomposition
from sklearn import datasets
np.random.seed(5)
centers = [[1, 1], [-1, -1], [1, -1]]
X = tot
pca = decomposition.PCA(n_components=2)
pca.fit(X)
X = pca.transform(X)
plt.scatter(X[:, 0], X[:, 1], c="r", cmap=plt.cm.spectral,
edgecolor='k')
plt.show()
Habiendo visualizado los datos solo resta la ejecución del método K-Means, y su posterior visualización mediante tSNE y PCA.
from sklearn.cluster import KMeans
from sklearn import datasets
X = tot
kmeans = KMeans(n_clusters=3)
kmeans.fit(X)
labels = kmeans.labels_
centroids = kmeans.cluster_centers_
%matplotlib inline
r = []
r_l = []
g = []
g_l = []
b = []
b_l = []
y = []
y_l = []
c=[]
c_l=[]
m=[]
m_l=[]
plt.gcf().clear()
r_embedded = TSNE(n_components=2,n_iter=100000000).fit_transform(X)
r_embedded.shape
for k in range(len(labels)):
if labels[k]==0:
r.append(X_embedded[k])
r_l.append(paises[k])
elif labels[k]==1:
g.append(X_embedded[k])
g_l.append(paises[k])
elif labels[k]==2:
b.append(X_embedded[k])
b_l.append(paises[k])
elif labels[k]==3:
y.append(X_embedded[k])
y_l.append(paises[k])
elif labels[k]==4:
c.append(X_embedded[k])
c_l.append(paises[k])
elif labels[k]==5:
m.append(X_embedded[k])
m_l.append(paises[k])
plt.scatter([item[0] for item in r], [item[1] for item in r], c="r", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in g], [item[1] for item in g], c="g", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in b], [item[1] for item in b], c="b", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in y], [item[1] for item in y], c="y", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in c], [item[1] for item in c], c="c", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in m], [item[1] for item in m], c="m", cmap=plt.cm.Spectral)
plt.show()
# LAS LINEAS A CONTINUACION SE UTILIZAN PARA GUARDAR LOS RESULTADOS EN UNA IMAGEN #
#tsnename='k3_dev_'+str(yr)+'_tsne'
#plt.savefig(tsnename)
#plt.gcf().clear()
from mpl_toolkits.mplot3d import Axes3D
from sklearn import decomposition
from sklearn import datasets
X = tot
pca = decomposition.PCA(n_components=2)
pca.fit(X)
X = pca.transform(X)
r = []
r_l = []
g = []
g_l = []
b = []
b_l = []
y = []
y_l = []
c = []
c_l = []
for k in range(len(labels)):
if labels[k]==0:
r.append(X[k])
r_l.append(paises[k])
elif labels[k]==1:
g.append(X[k])
g_l.append(paises[k])
elif labels[k]==2:
b.append(X[k])
b_l.append(paises[k])
elif labels[k]==3:
y.append(X[k])
y_l.append(paises[k])
elif labels[k]==4:
c.append(X[k])
c_l.append(paises[k])
plt.scatter([item[0] for item in r], [item[1] for item in r], c="r", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in g], [item[1] for item in g], c="g", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in b], [item[1] for item in b], c="b", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in y], [item[1] for item in y], c="y", cmap=plt.cm.Spectral)
plt.scatter([item[0] for item in c], [item[1] for item in c], c="c", cmap=plt.cm.Spectral)
plt.show()
# LAS LINEAS A CONTINUACION SE UTILIZAN PARA GUARDAR LOS RESULTADOS EN UNA IMAGEN #
#pcaname='k3_dev_'+str(yr)+'_pca'
#plt.savefig(pcaname)
#plt.gcf().clear()
A continuación se muestran los países correspondientes a cada una de las etiquetas:
rojo = ''
for i in r_l:
rojo += i
if i != r_l[-1]:
rojo+= ', '
print rojo
azul = ''
for i in b_l:
azul += i
if i != b_l[-1]:
azul+= ', '
print azul
verde = ''
for i in g_l:
verde += i
if i != g_l[-1]:
verde+= ', '
print verde
De esta clusterización se identifican tres clusters que identificamos que corresponden a la medida subjetiva de desarrollo: el cluster Rojo es identificado como "Países desarrollados", el Azul como "Países en vías de desarrollo" y el cluster Verde como "Países sub-desarrollados".
Sin embargo, no basta solamente con la visualización de estos clusters ni interpretar su significado. Es necesario aplicar algoritmos que nos permitan visualizar la evolución de estos clusters en el tiempo, así como poder representarlos en un mapa que entregue información más clara y nos permita observar patrones que vinculen estos clusters con su ubicación geográfica.
Para ello se guardan las etiquetas obtenidas de cada cluster, las que serán usadas posteriormente para poder representar a cada uno de los países en el cluster que le corresponda en un mapa. Los algoritmos que fueron presentados se ejecutan para cada uno de los años entre 1980 y 2016 y se guardan sus resultados, con los que se trabajará en la sección siguiente para mostrar la evolución temporal de los clusters.
clusters = [r,g,b,y,c,m]
clusters_l = [r_l,g_l,b_l,y_l,c_l,m_l]
ncluster = 1
pre_out = []#('Country','Label')]
for cluster_l in clusters_l:
for country in cluster_l:
pre_out.append((country,ncluster))
ncluster +=1
out = pd.DataFrame(pre_out,columns=['Country', 'Label'])
out.head()
labelname='Labels'+str(anho)+'.xlsx'
writer = pd.ExcelWriter(labelname)
out.to_excel(writer,'Data')
writer.save()
Habiendo ejecutado los algoritmos y guardado sus resultados, es necesario poder representar los clusters y su evolución temporal en el tiempo. Lamentablemente utilizar la visualización por medio de PCA o tSNE no es de mucha utilidad debido a la reducción de dimensionalidad que no nos entrega una representación que entregue mayor información. Sin embargo, es posible seleccionar ciertas variables de cada país y evaluar su comportamiento a medida que transcurren los años. Esto es lo que definimos como una "métrica" para mostrar la evolución de los clusters en el tiempo.
En particular, se eligen de manera arbitraria las variables de Tasa de Natalidad y la Esperanza de Vida, bajo la hipótesis de que países más desarrollados tienden a tener una esperanza de vida mayor, acompañado de una menor tasa de natalidad, inspirados en el vídeo de Hans Rosling (https://www.ted.com/talks/hans_rosling_shows_the_best_stats_you_ve_ever_seen).
El código presentado a continuación es ejecutado para obtener el Scatter Plot Esperanza de Vida vs Tasa de Natalidad, se ejecuta para cada año sin "limpiar" la figura del gráfico, de manera que se van sobreponiendo los gráficos generados permitiendo visualizar una evolución y la direccionalidad del movimiento de los clusters. En este caso particular se hace para el año 2010:
hijos = d_2016['Fertility rate, total (births per woman)']
expectativa = d_2016['Life expectancy at birth, total (years)']
import matplotlib.pyplot as plt
plt.gcf().clear()
sizes = np.linspace(1,100,100)
#pdb.set_trace()
size = 1
for pais in g_l:
hijos = d_2016[d_2016['Country Name']==pais]['Fertility rate, total (births per woman)']
expectativa = d_2016[d_2016['Country Name']==pais]['Life expectancy at birth, total (years)']
plt.scatter(hijos, expectativa, c="r", cmap=plt.cm.Spectral,s=size)
size = size*1.12
size = 1
for pais in b_l:
hijos = d_2016[d_2016['Country Name']==pais]['Fertility rate, total (births per woman)']
expectativa = d_2016[d_2016['Country Name']==pais]['Life expectancy at birth, total (years)']
plt.scatter(hijos, expectativa, c="g", cmap=plt.cm.Spectral,s=size)
size = size*1.09
size = 1
for pais in r_l:
hijos = d_2016[d_2016['Country Name']==pais]['Fertility rate, total (births per woman)']
expectativa = d_2016[d_2016['Country Name']==pais]['Life expectancy at birth, total (years)']
plt.scatter(hijos, expectativa, c="b", cmap=plt.cm.Spectral,s=size)
size = size*1.1
'''
c_hijos = d_2016[d_2016['Country Name']=='Chile']['Fertility rate, total (births per woman)']
c_expectativa = d_2016[d_2016['Country Name']=='Chile']['Life expectancy at birth, total (years)']
plt.scatter(c_hijos, c_expectativa, c="r", cmap=plt.cm.Spectral,s=300,label='Chile[2015]')
'''
'''
f_hijos = d_2016[d_2016['Country Name']=='Finland']['Fertility rate, total (births per woman)']
f_expectativa = d_2016[d_2016['Country Name']=='Finland']['Life expectancy at birth, total (years)']
plt.scatter(f_hijos, f_expectativa, c="b", cmap=plt.cm.Spectral,s=500,label='Finland[2005]')
'''
plt.ylabel('Life expectancy at birth, total (years)')
plt.xlabel('Fertility rate, total (births per woman)')
plt.title(str(anho))
#plt.title('Chile[2015] vs Finland[2005]')
plt.xlim([0,10])
plt.ylim([20, 90])
#plt.legend(loc='best')#, borderaxespad=0.)
plt.show()
#plt.savefig(str(year)+'.png')
A continuación se muestra el estado inicial en 1980, y el estado final de estos gráficos en 2015.
Se observa una tendencia de todos los países a la esquina superior izquierda, es decir, a un aumento de la expectativa de vida correlacionado con una menor tasa de natalidad.
Se puede verificar además que en general, a medida que transcurren los años la distancia entre los clusters es cada vez menor.
Resulta interesante también, aislar a Chile y otro de los países que se identifican como países desarrollados. De manera arbitraria se decide realizar esta comparación con Finlandia, para determinar en qué año Chile logra alcanzar el nivel de "desarrollo" dado por esta métrica.
Otras métricas podrían mostrar de manera más fidedigna la evolución temporal del nivel de desarrollo de los distintos países y clusters obtenidos, sin embargo, esto implicaba un trabajo de exploración de datos muy acabado, y dada la arbitrariedad con que se realiza esta tarea parecía agregar poco valor al proyecto.
Sin embargo, se proponen en iteraciones futuras implementar métricas de desarrollo establecidas, y un análisis estadístico más profundo para lograr determinar la correlación entre el nivel de desarrollo y las distintas variables que componen nuestra base de datos.
Por último, se busca representar geográficamente en un mapa estos clusters, y poder mostrar su evolución temporal a lo largo de los años. Para ello se ejecuta el código siguiente que los coloca en sus respectivas posiciones en el mapa, y guarda la imagen resultante. Luego se pueden observar las diferencias en el mapa para cada año.
# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import numpy as np
import pandas as pd
import pdb
import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import cartopy.io.shapereader as shpreader
import copy
plt.gcf().clear()
for yr in range(2010,2011): # El rango que se debe ejecutar es 1980 a 2015, pero en este caso se muestra solo el año 2010
labelname = 'Labels'+str(yr)+'.xlsx'
labels = pd.read_excel(labelname, keep_default_na=False, na_values='')
#labels.head()
Cluster1 = labels[labels['Label'] == 1]['Country']
Cluster2 = labels[labels['Label'] == 2]['Country']
Cluster3 = labels[labels['Label'] == 3]['Country']
shapename = 'admin_0_countries'
countries_shp = shpreader.natural_earth(resolution='110m', category='cultural', name=shapename)
plt.figure(figsize=(20,15))
ax = plt.axes(projection=ccrs.PlateCarree())
#color = "r"
for country in shpreader.Reader(countries_shp).records():
if any(country.attributes['NAME_LONG'] in x for x in Cluster1):
if any(Cluster1.str.contains("United States")):
color = 'b'
elif any(Cluster1.str.contains("Brazil")):
color = 'g'
else:
color = 'r'
elif any(country.attributes['NAME_LONG'] in x for x in Cluster2):
if any(Cluster2.str.contains("United States")):
color = 'b'
elif any(Cluster2.str.contains("Brazil")):
color = 'g'
else:
color = 'r'
elif any(country.attributes['NAME_LONG'] in x for x in Cluster3):
if any(Cluster3.str.contains("United States")):
color = 'b'
elif any(Cluster3.str.contains("Brazil")):
color = 'g'
else:
color = 'r'
'''
elif any(country.attributes['NAME_LONG'] in x for x in y_l):
color = 'y'
'''
ax.add_geometries(country.geometry, ccrs.PlateCarree(),facecolor=color,label=country.attributes['NAME_LONG'])
fig_size = plt.rcParams["figure.figsize"]
# Set figure width to 12 and height to 9
fig_size[0] = 240
fig_size[1] = 180
plt.rcParams["figure.figsize"] = fig_size
plt.show()
#mapname='k3_dev_'+str(yr)+'_map'
#plt.savefig(mapname)
#plt.gcf().clear()
A continuación se muestra el estado inicial de los clusters geográficamente, en 1980:
En estos mapas se observa que en un comienzo existía un mayor número de países pertenecientes al cluster de países subdesarrollados, concentrados principalmente en África, Asia y algunos países de Sudamérica. Al año 2015, sin embargo, Sudamérica se encuentra en un estado de vías de desarrollo tendiendo al desarrollo, con Chile formando parte del cluster de países con más alto desarrollo. Así mismo, se observa un aumento del número de países africanos que se integran al cluster verde de países en vías de desarrollo y una disminución de los países sub-desarrollados, situación muy similar en Asia. Así mismo, cabe destacar fenómenos como la inclusión de China en el cluster azul, debido a su predominancia económica luego del comienzo del siglo XXI.
El trabajo realizado y presentado en este reporte puede ser una importante herramienta de visualización y comunicación de la importancia de ciertas variables en el nivel de desarrollo de un país. Sin embargo, no hay que caer en el vicio de vincular correlación con causalidad, la información que entregan los gráficos presentados puede resultar engañosa.
De lo que no hay duda alguna es que los resultados muestran una tendencia a una mayor igualdad entre los países del mundo y de los clusters que se obtuvieron, potenciados por el fortalecimiento de las economías y de una mayor estabilidad política.
Se considera el trabajo realizado insuficiente, sin embargo, lamentablemente por los tiempos de los que se dispone no fue posible realizar un análisis más acabado que ayudara a identificar las variables que tienen incidencia en estas clasificaciones. Parte del problema nace debido a que la concepción de este proyecto se dio sin un objetivo claro, ajustándose sus objetivos con cada entrega para cumplir con los requerimientos del curso. Sin lugar a dudas resulta un aprendizaje valioso la importancia de tener una hipótesis clara en mente antes de comenzar a desarrollar un proyecto de Data Mining.