Aplicación de algoritmos no supervisados de agrupamiento para agrupar los 212 países ante la Pandemia del COVID-19

by Juan I. Barrios - Agosto 2020 Health -BIG DATA and Data Science . Barcelona.

www.juanbarrios.com

1.) Proceso: Inclusión de las Librerías necesarias de Python

In [107]:
import pandas as pd
import seaborn as sb
from pandas.plotting import table
import numpy as np
import six
import seaborn as sns
from matplotlib import pyplot as plt
from matplotlib.dates import date2num, num2date
from matplotlib import dates as mdates
from matplotlib import ticker
from matplotlib.colors import ListedColormap
from matplotlib.patches import Patch
from matplotlib import animation
plt.style.use("ggplot")# for pretty graphs
from IPython.display import clear_output
import ftplib
import os
import math
from sklearn.cluster import KMeans
import scipy.cluster.hierarchy as sch
from sklearn.cluster import AgglomerativeClustering
%matplotlib inline

%config InlineBackend.figure_format = 'retina'

2.) Proceso : Carga de datos, y verificación inicial del data set

Ahora vamos a "cargar" los datos de los países al 16-8-2020

In [108]:
data2=pd.read_csv('https://covid.ourworldindata.org/data/owid-covid-data.csv')
data2['date']=pd.to_datetime(data2['date'],format='%Y-%m-%d')
today_data=data2[data2.date==data2.date.max()]
In [109]:
## Verificando la cantidad de datos en la serie , en caso de blancos se asignará ceros
sum(today_data.duplicated(subset = 'location')) == 0
Out[109]:
True
In [110]:
fig, axs = plt.subplots(2,2,figsize = (15,15))

# densidad poblacional  -top 10 de paises

top10_population = today_data[['location','population_density']].sort_values('population_density', ascending = False).head(10)
plt1 = sns.barplot(x='location', y='population_density', data= top10_population, ax = axs[0,0])
plt1.set(xlabel = '', ylabel= 'Population density')

# Pobrza extrema -top 10 de paises
top10_total_fer = today_data[['location','extreme_poverty']].sort_values('extreme_poverty', ascending = False).head(10)
plt1 = sns.barplot(x='location', y='extreme_poverty', data= top10_total_fer, ax = axs[0,1])
plt1.set(xlabel = '', ylabel= 'Extreme Poverty')

# Esperanza de vida: paises con la esperanza mas baja
bottom10_life_expec = today_data[['location','life_expectancy']].sort_values('life_expectancy', ascending = True).head(10)
plt1 = sns.barplot(x='location', y='life_expectancy', data= bottom10_life_expec, ax = axs[1,0])
plt1.set(xlabel = '', ylabel= 'Life Expectancy')

# Producto Interno Bruto PIB -últimos 10 paises

bottom10_gdpp = today_data[['location','gdp_per_capita']].sort_values('gdp_per_capita', ascending = True).head(10)
plt1 = sns.barplot(x='location', y='gdp_per_capita', data= bottom10_gdpp, ax = axs[1,1])
plt1.set(xlabel = '', ylabel= 'GDP per capita')

for ax in fig.axes:
    plt.sca(ax)
    plt.xticks(rotation = 90)
    
plt.tight_layout()
plt.savefig('eda')
plt.show()
In [111]:
colormap = plt.cm.viridis
plt.figure(figsize=(12,12))
plt.title('Correlación de Pearson para los atributos', y=1.05, size=15)
sb.heatmap(data2.corr(), linewidths=0.1,vmax=1.0, square=True, cmap=colormap, linecolor='white', annot=True)
Out[111]:
<matplotlib.axes._subplots.AxesSubplot at 0x15a8ab68948>

3.) Proceso: Transformación de datos - Análisis preliminar

In [112]:
## países excluidos del análisis
excluded_cntry=['World', 'China', 'India']
In [113]:
## variables disponibles
print(data2.columns)
Index(['iso_code', 'continent', 'location', 'date', 'total_cases', 'new_cases',
       'total_deaths', 'new_deaths', 'total_cases_per_million',
       'new_cases_per_million', 'total_deaths_per_million',
       'new_deaths_per_million', 'new_tests', 'total_tests',
       'total_tests_per_thousand', 'new_tests_per_thousand',
       'new_tests_smoothed', 'new_tests_smoothed_per_thousand',
       'tests_per_case', 'positive_rate', 'tests_units', 'stringency_index',
       'population', 'population_density', 'median_age', 'aged_65_older',
       'aged_70_older', 'gdp_per_capita', 'extreme_poverty',
       'cardiovasc_death_rate', 'diabetes_prevalence', 'female_smokers',
       'male_smokers', 'handwashing_facilities', 'hospital_beds_per_thousand',
       'life_expectancy'],
      dtype='object')
In [114]:
##variables a incluir, si se deja en blanco se utilizarán todas.
cols_needed=['total_cases_per_million','total_cases',
       'total_deaths_per_million',
       'new_deaths_per_million','total_tests_per_thousand','hospital_beds_per_thousand','population', 'population_density','new_tests_per_thousand','positive_rate'  ]
In [115]:
data2=data2[~data2.location.isin(excluded_cntry)]
if len(cols_needed)==0:
    data2_sub=data2.select_dtypes(include='float')
else:
    data2_sub=data2[cols_needed]
data2_sub=pd.concat([data2_sub,data2[['location']]],axis=1)
data2_sub=data2_sub.groupby('location').mean().reset_index()
data2_sub.fillna(0,inplace=True)
In [116]:
# Análisis del método del hombro para determinar el número ideal de grupos utilizando Inertia
In [117]:
inertias = [] 
K = range(1,10) 
  
for k in K: 
    #Building and fitting the model 
    kmeanModel = KMeans(n_clusters=k).fit(data2_sub.drop(['location'],axis=1)) 
    kmeanModel.fit(data2_sub.drop(['location'],axis=1))     
    inertias.append(kmeanModel.inertia_) 
    
plt.plot(K, inertias, 'bx-') 
plt.xlabel('Numero de grupos') 
plt.ylabel('Inertia') 
plt.title('Método del Hombro con la herramienta Inertia') 
plt.show()

4.) Proceso - Aplicación del algoritmo

In [118]:
# ajustado el algoritmo Kmeans ak conjunto de datos
from sklearn.cluster import KMeans

## Numero de clústers a utilizar. En este caso 4 clústers
kmeans = KMeans(n_clusters = 4, init = 'k-means++', random_state = 42)
y_kmeans = kmeans.fit_predict(data2_sub.drop(['location'],axis=1))
y_kmeans1=y_kmeans+1
cluster = pd.DataFrame(y_kmeans1)
today_sub=data2_sub.drop(['location'],axis=1)
# Adding cluster to the Dataset
today_sub['cluster'] = cluster
#Mean of clusters
kmeans_mean_cluster = pd.DataFrame(round(today_sub.groupby('cluster').mean(),1))

## Identificación de los valores promedio ( centroides) 
kmeans_mean_cluster
Out[118]:
total_cases_per_million total_cases total_deaths_per_million new_deaths_per_million total_tests_per_thousand hospital_beds_per_thousand population population_density new_tests_per_thousand positive_rate
cluster
1 778.5 35313.0 48.0 0.6 13.3 2.3 41187186.7 88.3 0.2 0.0
2 1374.3 5384.3 40.0 0.5 16.2 2.3 5410841.0 416.1 0.3 0.0
3 1529.4 425466.3 63.1 0.9 14.5 1.3 248823519.0 134.3 0.3 0.1
4 680.6 74714.9 26.6 0.4 15.6 3.4 110994006.4 248.2 0.2 0.1

Ejemplo de datos de 10 primeros países

In [119]:
today_Sub_2=pd.concat([data2_sub[['location']],today_sub],axis=1)
today_Sub_2.head(10)
Out[119]:
location total_cases_per_million total_cases total_deaths_per_million new_deaths_per_million total_tests_per_thousand hospital_beds_per_thousand population population_density new_tests_per_thousand positive_rate cluster
0 Afghanistan 308.222318 11998.581818 8.654718 0.159968 0.000000 0.50 38928341.0 54.422 0.000000 0.000000 1
1 Albania 672.643323 1935.732919 19.893106 0.485491 0.000000 2.89 2877800.0 104.871 0.000000 0.000000 2
2 Algeria 184.148862 8075.120000 10.346022 0.137822 0.000000 1.90 43851043.0 17.348 0.000000 0.000000 1
3 Andorra 9329.779058 720.865385 532.051538 4.397051 0.000000 0.00 77265.0 163.755 0.000000 0.000000 2
4 Angola 10.043966 330.108108 0.464878 0.017622 0.000000 0.00 32866268.0 23.890 0.000000 0.000000 1
5 Anguilla 196.710070 2.951049 0.000000 0.000000 0.000000 0.00 15002.0 0.000 0.000000 0.000000 2
6 Antigua and Barbuda 424.733873 41.593333 25.597220 0.204233 0.000000 3.80 97928.0 231.845 0.000000 0.000000 2
7 Argentina 1164.594945 52634.773006 23.982252 0.755442 4.391129 5.00 45195777.0 16.177 0.103265 0.211801 1
8 Armenia 3634.612783 10770.208145 64.933018 1.247511 0.000000 4.20 2963234.0 102.931 0.000000 0.000000 2
9 Aruba 1269.735939 135.564626 22.173395 0.254857 0.000000 0.00 106766.0 584.800 0.000000 0.000000 2

5.) Proceso - Presentación de los Resultados-

In [120]:
for i in range(1,5):
    print('****Países incluídos en el grupo {}*****'.format(str(i)))
    print(list(today_Sub_2[today_Sub_2.cluster==i]['location'].values))
****Países incluídos en el grupo 1*****
['Afghanistan', 'Algeria', 'Angola', 'Argentina', 'Australia', 'Cameroon', 'Canada', 'Colombia', "Cote d'Ivoire", 'France', 'Ghana', 'Iraq', 'Italy', 'Kenya', 'Madagascar', 'Malaysia', 'Morocco', 'Mozambique', 'Myanmar', 'Nepal', 'Niger', 'Peru', 'Poland', 'Saudi Arabia', 'South Africa', 'South Korea', 'Spain', 'Sudan', 'Taiwan', 'Tanzania', 'Thailand', 'Uganda', 'Ukraine', 'United Kingdom', 'Uzbekistan', 'Venezuela', 'Yemen']
****Países incluídos en el grupo 2*****
['Albania', 'Andorra', 'Anguilla', 'Antigua and Barbuda', 'Armenia', 'Aruba', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivia', 'Bonaire Sint Eustatius and Saba', 'Bosnia and Herzegovina', 'Botswana', 'British Virgin Islands', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cape Verde', 'Cayman Islands', 'Central African Republic', 'Chad', 'Chile', 'Comoros', 'Congo', 'Costa Rica', 'Croatia', 'Cuba', 'Curacao', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'Ecuador', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Faeroe Islands', 'Falkland Islands', 'Fiji', 'Finland', 'French Polynesia', 'Gabon', 'Gambia', 'Georgia', 'Gibraltar', 'Greece', 'Greenland', 'Grenada', 'Guam', 'Guatemala', 'Guernsey', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', 'Hong Kong', 'Hungary', 'Iceland', 'International', 'Ireland', 'Isle of Man', 'Israel', 'Jamaica', 'Jersey', 'Jordan', 'Kazakhstan', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Macedonia', 'Malawi', 'Maldives', 'Mali', 'Malta', 'Mauritania', 'Mauritius', 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Montserrat', 'Namibia', 'Netherlands', 'New Caledonia', 'New Zealand', 'Nicaragua', 'Northern Mariana Islands', 'Norway', 'Oman', 'Palestine', 'Panama', 'Papua New Guinea', 'Paraguay', 'Portugal', 'Puerto Rico', 'Qatar', 'Romania', 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'San Marino', 'Sao Tome and Principe', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Sint Maarten (Dutch part)', 'Slovakia', 'Slovenia', 'Somalia', 'South Sudan', 'Sri Lanka', 'Suriname', 'Swaziland', 'Sweden', 'Switzerland', 'Syria', 'Tajikistan', 'Timor', 'Togo', 'Trinidad and Tobago', 'Tunisia', 'Turks and Caicos Islands', 'United Arab Emirates', 'United States Virgin Islands', 'Uruguay', 'Vatican', 'Western Sahara', 'Zambia', 'Zimbabwe']
****Países incluídos en el grupo 3*****
['Brazil', 'Indonesia', 'Nigeria', 'Pakistan', 'United States']
****Países incluídos en el grupo 4*****
['Bangladesh', 'Democratic Republic of Congo', 'Egypt', 'Ethiopia', 'Germany', 'Iran', 'Japan', 'Mexico', 'Philippines', 'Russia', 'Turkey', 'Vietnam']
In [121]:
import plotly.express as px
fig = px.treemap(today_Sub_2, path=['cluster','location'], values='total_cases')
fig.update_layout(autosize=False,width=800,height=700)

fig.show()

6.) Proceso -aplicando de un segundo algoritmo

Algoritmo de clustering jerárquico o agrupamiento jerárquico

La agrupación jerárquica por acumulación difiere del algoritmo k-means en el hecho de que elige una cantidad de grupos y comienza con centroides (púntos medios) aleatorios. Luego, va buscando los puntos más cercanos y los va agregando en el mismo grupo. Luego continua encontrando mas puntos cercanos y al final eso termina siendo un grupo. El dendograma final se dividirá en el número de grupos que el algoritmo haya identificado, aunque ese número se puede variar de forma manual.

In [122]:
# creando el Dendograma 
dendrogram = sch.dendrogram(sch.linkage(data2_sub.drop(['location'],axis=1), method='ward'))
In [123]:
# creando los grupos
hc = AgglomerativeClustering(n_clusters=4, affinity = 'euclidean', linkage = 'ward')# save clusters for chart
y_hc = hc.fit_predict(data2_sub.drop(['location'],axis=1))
In [124]:
heirarchy=data2_sub.copy()
heirarchy['cluster'] = y_hc
In [125]:
# Aca se anota el numero de clústers si se desea poner de forma manual 
for i in range(4):
    print('****Name of countries in cluster {}*****'.format(str(i)))
    print(list(heirarchy[heirarchy.cluster==i]['location'].values))
****Name of countries in cluster 0*****
['Bangladesh', 'Brazil', 'Indonesia', 'Nigeria', 'Pakistan', 'Russia', 'United States']
****Name of countries in cluster 1*****
['Afghanistan', 'Algeria', 'Angola', 'Argentina', 'Australia', 'Cameroon', 'Canada', 'Colombia', "Cote d'Ivoire", 'France', 'Ghana', 'Iraq', 'Italy', 'Kenya', 'Madagascar', 'Malaysia', 'Morocco', 'Mozambique', 'Myanmar', 'Nepal', 'Niger', 'Peru', 'Poland', 'Saudi Arabia', 'South Africa', 'South Korea', 'Spain', 'Sudan', 'Taiwan', 'Tanzania', 'Thailand', 'Uganda', 'Ukraine', 'United Kingdom', 'Uzbekistan', 'Venezuela', 'Yemen']
****Name of countries in cluster 2*****
['Albania', 'Andorra', 'Anguilla', 'Antigua and Barbuda', 'Armenia', 'Aruba', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivia', 'Bonaire Sint Eustatius and Saba', 'Bosnia and Herzegovina', 'Botswana', 'British Virgin Islands', 'Brunei', 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cape Verde', 'Cayman Islands', 'Central African Republic', 'Chad', 'Chile', 'Comoros', 'Congo', 'Costa Rica', 'Croatia', 'Cuba', 'Curacao', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'Ecuador', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Faeroe Islands', 'Falkland Islands', 'Fiji', 'Finland', 'French Polynesia', 'Gabon', 'Gambia', 'Georgia', 'Gibraltar', 'Greece', 'Greenland', 'Grenada', 'Guam', 'Guatemala', 'Guernsey', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Honduras', 'Hong Kong', 'Hungary', 'Iceland', 'International', 'Ireland', 'Isle of Man', 'Israel', 'Jamaica', 'Jersey', 'Jordan', 'Kazakhstan', 'Kosovo', 'Kuwait', 'Kyrgyzstan', 'Laos', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Macedonia', 'Malawi', 'Maldives', 'Mali', 'Malta', 'Mauritania', 'Mauritius', 'Moldova', 'Monaco', 'Mongolia', 'Montenegro', 'Montserrat', 'Namibia', 'Netherlands', 'New Caledonia', 'New Zealand', 'Nicaragua', 'Northern Mariana Islands', 'Norway', 'Oman', 'Palestine', 'Panama', 'Papua New Guinea', 'Paraguay', 'Portugal', 'Puerto Rico', 'Qatar', 'Romania', 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'San Marino', 'Sao Tome and Principe', 'Senegal', 'Serbia', 'Seychelles', 'Sierra Leone', 'Singapore', 'Sint Maarten (Dutch part)', 'Slovakia', 'Slovenia', 'Somalia', 'South Sudan', 'Sri Lanka', 'Suriname', 'Swaziland', 'Sweden', 'Switzerland', 'Syria', 'Tajikistan', 'Timor', 'Togo', 'Trinidad and Tobago', 'Tunisia', 'Turks and Caicos Islands', 'United Arab Emirates', 'United States Virgin Islands', 'Uruguay', 'Vatican', 'Western Sahara', 'Zambia', 'Zimbabwe']
****Name of countries in cluster 3*****
['Democratic Republic of Congo', 'Egypt', 'Ethiopia', 'Germany', 'Iran', 'Japan', 'Mexico', 'Philippines', 'Turkey', 'Vietnam']
In [126]:
# grafico de los grupos de países
fig = px.treemap(heirarchy, path=['cluster','location'], values='total_cases')
fig.update_layout(autosize=False,width=800,height=700)
fig.show()
In [ ]:
 
In [ ]: