<jupyter_start><jupyter_text>Diplomatura AACSyA 2018 - FaMAF - UNCAnálisis y visualización de datos Tarea integradora - Parte 1En esta notebook presentamos una serie de ejercicios para trabajar con variables aleatorias discretas, tanto númericas como cátegoricas, ejemplificando los conceptos de probabilidad explicados en clase. Lo primero es determinar si todas las librerías están correctamente instaladas.<jupyter_code># %matplotlib notebook
%matplotlib inline
import matplotlib.pyplot as plt
import pandas
import numpy
import seaborn
seaborn.set_style('whitegrid')
seaborn.set_context('talk')<jupyter_output><empty_output><jupyter_text>Cargar el dataset en un dataframe de pandasLos dataframes son tablas con un montón de operaciones ya programadas. Prácticamente todas las funciones de SQL se pueden realizar en pandas con pocas líneas. Además de eso, tiene funciones para leer y escribir archivos en numerosos formatos.Ahora leemos directamente el archivo .csv<jupyter_code>dataset = pandas.read_csv('violencia-institucional-2018-01.csv',
                          encoding='utf8')
dataset[:3]<jupyter_output><empty_output><jupyter_text>Los valores para los años no tienen un formato consistente en todas las filas, por lo que los procesaremos antes de comenzar. Los valores de año faltantes son reemplazados por NaN, y como la representación de enteros de numpy no soporta este tipo de valores, convertiremos cada año a tipo numpy.float. Otras decisiones pueden ser tomadas en este punto, como reemplazar los valores faltantes por 0 o elminarlos del dataset, dependiendo del tipo de datos que se requiera.También cambiaremos el nombre de la columna año, ya que el caracter ñ no permite utilizar el syntax sugar de pandas donde se obtienen los valores de la columna con la sintáxis de llamar a un método.<jupyter_code>import six
def convert_to_int(row):
    try:
        return float(row)
    except ValueError:
        if isinstance(row, six.string_types):
            return float(row.split(',')[0])
        return row

dataset.loc[:,'year'] = dataset[u'año'].apply(convert_to_int)
# Se podrían también decodicar los nombres de provincias
# dataset.loc[:,'provincia'] = dataset.provincia.apply(lambda x: x.decode("utf-8"))
dataset.shape, dataset.year.dropna().shape<jupyter_output><empty_output><jupyter_text>--- Ejercicios  Ejercicio 1* Crear una imagen mostrando la distribución de los eventos por año* Construir una tabla de frecuencia de probabilidades dado el evento Y = ’año en el que ocurrió’$$fdp(Y)$$* Crear una imagen de dichas probabilidades con el gráfico que considere adecuado. ¿Son ambos gráficos iguales? ¿Cuál considera que es más útil?* ¿A qué se debe la forma de la distribución? ¿Qué tendencia muestra? ¿Ha aumentado la violencia institucional en los últimos años?* Calcular la función de distribución acumulada de la variable Y y graficarla. ¿Cuál es la probabilidad de que haya dado un acto de violencia antes del último cambio de gobierno?IMPORTANTE: ¿Qué hacemos con los datos faltantes?  Sol Ejercicio 1a<jupyter_code># Tenemos que contar para cada año la cantidad de eventos. Aprovechamos el ejemplo
s_yc=dataset.year.value_counts(); #dropna=True por default
# Probemos un grafico simple usando matplotlib
plt.figure(figsize=(10,10))
plt.bar(s_yc.index,s_yc.values)
plt.xlabel('year');plt.ylabel('eventos')
plt.show()
# Veamos que tipo de dato es yc y lo ploteamos usando seaborn 
print(type(s_yc))
# Es un tipo Series de pandas, seaborn entiende dataframes y series pero seguimos el ejemplo.
ax = seaborn.barplot(data=s_yc.to_frame().reset_index(),
    x='index', y='year', color='#2ecc71')
ax.set_xticklabels(ax.get_xticklabels(), rotation=90, ha="right")
ax.set_xlabel('year');ax.set_ylabel('eventos')
ax.figure.set_size_inches(10,10)
seaborn.despine()
# Comentario: el correspondiente a matplotlib, parece mas claro en el sentido que preserva los nan (no los incluye,
# pero deja el espacio correspondiente en el grafico, mientras que el correspondiente a seaborn, con la configuracion
# default, parece quitarlos...)<jupyter_output><empty_output><jupyter_text>Solucion Ejercicio 1b/1c<jupyter_code>#La tabla es similar a lo anterior pero tenemos que normalizar
s_y_norm=dataset.year.value_counts(normalize=True) # por default dropnan=True!
pd_y_norm=s_y_norm.to_frame().reset_index().sort_values(['index'])
pd_y_norm.reset_index(inplace=True,drop=True)
pd_y_norm.columns=['year','pFreq']
#
pd_y_norm.reset_index(drop=True,inplace=True)
pd_y_norm
# Graficamos usando matplotlib
plt.figure(figsize=(10,10))
plt.bar(pd_y_norm.year,pd_y_norm.pFreq)
plt.xlabel('year');plt.ylabel('pFreq')
plt.show()<jupyter_output><empty_output><jupyter_text>* ¿Son ambos gráficos iguales? ¿Cuál considera que es más útil?*Ambos graficos son similares pero NO iguales. Los dos tienen su utilidad dependiendo del dato que quiera entregar. Si deseo tener un rapido pantallazo de la cantidad absoluta de eventos de un dado año recurriria al primero de los graficos el cual muestra cantidad de cuentas. En el caso de que quiera obtener la contribucion frecuencial recurriria al segundo.* * ¿A qué se debe la forma de la distribución? ¿Qué tendencia muestra? ¿Ha aumentado la violencia institucional en los últimos años?*Si suponemos que la recoleccion de la informacion se efectuó de la misma manera y por los mismos organismos en todos los años mencionados, podriamos elaborar alguna clase de analisis. Caso contrario estariamos sacando conclusiones de intervalos temporales que no tuvieron el mismo tratamiento. Esto en realidad lo podriamos analizar usando el mismo dataset y contabilizando la cantidad de entidades en una dada fecha.Pero dado el supuesto anterior la distribucion al menos en el intervalo (asimetrico) mostrado parece bimodal.La cantidad de casos de violencia parecen haberse incrementado en los ultimos años, esto puede verse en cualquiera de los graficos elaborados, pero es mas notorio en el caso de magnitudes absolutas/cuentas.Esto lo podemos observar tambien en el grafico siguiente:*<jupyter_code># yc contenia los valores de cuentas y años 
pd_y_ordered=s_yc.to_frame().reset_index().sort_values(['index'])
pd_y_ordered.columns=['year','eventos']
pd_y_ordered.reset_index(inplace=True,drop=True)
plt.figure
plt.plot(pd_y_ordered.year.values[:],pd_y_ordered.eventos.values[:]-pd_y_ordered.eventos.values[0],'-o')
plt.xlabel('years'); plt.ylabel('eventos(year) - eventos(1988)',fontsize=12)
plt.show()
# En la grafica utilizamos como linea base el primer año 1988, respecto a esto podemos ver que la cantidad de eventos
# se ha incrementado respecto al comienzo de la medicion. 
#Sinos concentramos respecto al 2010 por ejemplo
plt.figure
plt.plot(pd_y_ordered.year.values[20:],pd_y_ordered.eventos.values[20:]-pd_y_ordered.eventos.values[20],'-o')
plt.xlabel('years',fontsize=12); plt.ylabel('eventos(year) - eventos(2010)',fontsize=12)
plt.show()<jupyter_output><empty_output><jupyter_text>*En la grafica anterior ya se observa una tendencia (al margen del descenso en 2015). Esto queda mas claro en la imagen siguiente*<jupyter_code># Una forma alternativa de observar el incremento es utilizar un moving average
plt.figure
xrng=range(2,4)
for x in xrng:
    plt.plot(pd_y_ordered.rolling(x).mean().year,pd_y_ordered.rolling(x).mean().eventos,'-o')
plt.legend(xrng)
plt.xlabel('years',fontsize=12); plt.ylabel('eventos rolling mean',fontsize=12)
plt.show()
pd_y_ordered.columns=['year','eventos']
# Figura en la cual se ve (con una estructura similar a las anteriores) un notorio incremento.<jupyter_output><empty_output><jupyter_text>* Calcular la función de distribución acumulada de la variable Y y graficarla. ¿Cuál es la probabilidad de que haya dado un acto de violencia antes del último cambio de gobierno?<jupyter_code># La funcion de distribucion acumulada la calculamos en terminos de la pdf que ya habiamos utilizado y la dejamos 
# disponible en el data frame
pd_y_norm['pFreqCumSum']=pd_y_norm.pFreq.cumsum();
print(pd_y_norm)
# Grafiquemos
plt.figure
plt.plot(pd_y_norm.year,pd_y_norm.pFreqCumSum,'.-')
plt.xlabel('year');plt.ylabel('FDA')
plt.show()
# La propabilidad de que se haya dado un acto de violencia antes del ultimo cambio de gobierno es lo mismo que 1-P(year>2015). Suponemos que el cambio
# se dio en 2016 puesto que no tenemos la discretizacion en terminos de meses
pAC=1-pd_y_norm.pFreq[pd_y_norm.year>2015].sum();
pACstr= 'P(acto de violencia antes del cambio de gobierno):  %f' % pAC 
print(pACstr)
fdastr='Esto es lo mismo que la FDA(2015): %f\n' % pd_y_norm.pFreqCumSum[pd_y_norm.year==2015].values
print(fdastr)<jupyter_output>year     pFreq  pFreqCumSum
0   1988.0  0.000760     0.000760
1   1989.0  0.000760     0.001520
2   1990.0  0.003799     0.005319
3   1991.0  0.003799     0.009119
4   1993.0  0.001520     0.010638
5   1994.0  0.002280     0.012918
6   1996.0  0.000760     0.013678
7   1997.0  0.000760     0.014438
8   1998.0  0.001520     0.015957
9   1999.0  0.001520     0.017477
10  2000.0  0.002280     0.019757
11  2001.0  0.002280     0.022036
12  2002.0  0.005319     0.027356
13  2003.0  0.006839     0.034195
14  2004.0  0.001520     0.035714
15  2005.0  0.002280     0.037994
16  2006.0  0.002280     0.040274
17  2007.0  0.003799     0.044073
18  2008.0  0.003799     0.047872
19  2009.0  0.007599     0.055471
20  2010.0  0.015957     0.071429
21  2011.0  0.012158     0.083587
22  2012.0  0.047112     0.130699
23  2013.0  0.216565     0.347264
24  2014.0  0.183131     0.530395
25  2015.0  0.066109     0.596505
26  2016.0  0.225684     0.822188
27  2017.0  0.177812     1.000000<jupyter_text>IMPORTANTE: ¿Qué hacemos con los datos faltantes?En el proceso de cuenta los metodos (de pandas) los ignoran por defecto. Lo cual es razonable si conocemos esta situacion (es decir que debemos ser informados de los datos excluidos por este motivo). Eso significa que no es que estamos ignorando esa situacion, sino que en el caso de considerarla no podriamos asignarle una pertenencia. Por ejemplo aquellos eventos que no tienen un año asignado no significa que no existieron sino que no podemos asignarlo o contabilizarlos en un año en particular.   Ejercicio 2* Construir una tabla de frecuencia de probabilidades dado el evento X = ’provincia donde se desarrollo el hecho’$$fdp(X)$$* ¿Qué información adicional es necesaria para mostrar estos datos de manera más adecuada?* Muestre la distribución de los eventos visualmente. ¿Qué tipo de gráfico es más adecuado para mostrar esta información?<jupyter_code># de https://stackoverflow.com/questions/37926248/how-to-remove-accents-from-values-in-columns
dataset['provincia']=dataset['provincia'].str.normalize('NFKD').str.encode('ascii', errors='ignore').str.decode('utf-8')
# Cuentas Abolutas
s_provincia=dataset.provincia.value_counts() #dropnan=True por default
# Valores Normalizados
s_provincia_norm=dataset.provincia.value_counts(normalize=True)
# Acomodamos el Data Frame
pd_provincia_norm=s_provincia_norm.to_frame().reset_index().sort_values(['index'])
pd_provincia_norm.reset_index(inplace=True,drop=True)
pd_provincia_norm.columns=['provincia','pFreq']
pd_provincia_norm<jupyter_output><empty_output><jupyter_text>* ¿Qué información adicional es necesaria para mostrar estos datos de manera más adecuada?*Seria conveniente normalizar las cuentas en funcion del tamaño de la poblacion de cada provincia. Asimismo se podria incorporar la evolución temporal.* * Muestre la distribución de los eventos visualmente. ¿Qué tipo de gráfico es más adecuado para mostrar esta información?<jupyter_code>ax = seaborn.barplot(data=s_provincia.to_frame().reset_index(),
    x='provincia', y='index', color='#2ecc71')
ax.set_yticklabels(ax.get_yticklabels(), rotation=0, ha="right",fontsize=14)
ax.set_xlabel('eventos_registrados');ax.set_ylabel('Provincias')
ax.figure.set_size_inches(10,10)
seaborn.despine()<jupyter_output><empty_output><jupyter_text>*Alternativamente se podria utilizar un estilo de heatmap geolocalizado. Es decir en el mapa de Argentina, ubicar cada provincia y utilizar un heatmap para tonalizarlo.*  Ejercicio 3* Construir una tabla de doble entrada donde se observen las función de distribución de probabilidades con las 2 variables aleatorias anteriores.¿Son eventos independientes?* Crear una imagen de dichas probabilidades con el gráfico que considere adecuado.  Sol Ejercicio 3a<jupyter_code># Antes de armar la tabla revisemos la consistencia de los datos.
print('Cantidad de eventos  (Y=provincia) con NaN: '+ str(sum(dataset.provincia.value_counts(dropna=False))))
print('Cantidad de eventos (X=año) con NaN: ' + str(sum(dataset.year.value_counts(dropna=False))))
print('Cantidad de eventos  (Y=provincia) quitando NaN: '+ str(sum(dataset.provincia.value_counts(dropna=True))))
print('Cantidad de eventos (X=año) quitando NaN: ' + str(sum(dataset.year.value_counts(dropna=True))))<jupyter_output>Cantidad de eventos  (Y=provincia) con NaN: 1439
Cantidad de eventos (X=año) con NaN: 1439
Cantidad de eventos  (Y=provincia) quitando NaN: 1408
Cantidad de eventos (X=año) quitando NaN: 1316<jupyter_text>*En esta instancia tenemos un par de opciones. Realizamos el filtrado de años y provincias de tal forma de eliminar aquellas instancias donde existan nan en alguna de las dos condiciones o en ambas. Es decir si tenemos casos (year,provincia), eliminamos aquellos (year,nan),(nan,provincia),(nan,nan). O simplemente utilizamos el conjunto total de datos y llevamos la informacion de los nan a cuestas.Si tuvieramos datos completos esperariamos ver que las distribuciones marginales sean identicas, pero esto en la condicion actual puede no ocurrir puesto que cuando las tratamos en el ejercicio 1 por ejemplo un par (year,nan) hubiera sido aceptado, pero en el ejercicio 2 no hubiera sido considerada (igualmente para el caso inverso (nan, provincia)).*<jupyter_code>lst_provincia=list(set(dataset.provincia.values))
lst_provincia.pop(lst_provincia.index(numpy.nan))
lst_provincia.sort()
auxDict={};
for i in range(0,len(lst_provincia)):
    s_y_pc=dataset.year[dataset.provincia==lst_provincia[i]].value_counts()
    pd_y_pc=s_y_pc.to_frame()
    auxDict[lst_provincia[i]]=pd_y_pc
    pd_y_p=pandas.concat(auxDict.values(),axis=1)
pd_y_p.columns=lst_provincia[:]
ypdSum=sum(pd_y_p.sum())
pd_y_p_norm=pandas.DataFrame(data=pd_y_p.values/ypdSum,columns=lst_provincia[:],index=pd_y_p.index)
# Veamos las distribuciones marginales para provincias, suma sobre años
# Debe ser similar a la calculada en el Ejercicio 2 pero puede diferir en 
# cuanto en el ejercicio 2 contemplabamos casos (year,prov)=(nan,prov), mientras que aqui se filtraron
pd_y_p_norm.sum(axis=0) 
# Veamos las distribuciones marginales para años, suma sobre provincias
# Debe ser similar a la calculada en el Ejercicio 1 pero puede diferir en 
# cuanto en el ejercicio 1 contemplabamos casos (year,prov)=(year,nan), mientras que aqui se filtraron
pd_y_p_norm.sum(axis=1)
# La tabla de doble entrada es:
pd_y_p_norm
#Veamos algun ejemplo para la independencia. Recordemos que P(N|M)=P(N interseccion M)/P(M). En el caso de independencia 
# P(N)=P(N|M)
# Elegimos M=1988 y N= Ciudad de Buenos Aires. De la tabla
p_y_int_p=0.000766; # Probabilidad de la interseccion
p_y=0.000766; # Probabilidad marginal del año 2018
#Entonces
p_y_p=p_y_int_p/p_y  # P(Ciudad de Buenos Aires|2018)=1
p_y_p
#Mientras que la probabilida marginal de la ciudad de Buenos Aires p_p= 0.085824 (ver en celdas anteriores). Lo cual,
# estaria implicando la no independencia.<jupyter_output><empty_output><jupyter_text>*Veamos la visualizacion, quizas un heat map<jupyter_code>fig, ax = plt.subplots(figsize=(15,15))
fig.subplots_adjust(bottom=0.25,left=0.25) # make room for labels
heatmap = ax.pcolormesh(pd_y_p_norm,alpha=0.8,cmap=plt.cm.hot)
cbar = plt.colorbar(heatmap)
headers=pd_y_p_norm.columns.tolist();

# Set ticks in center of cells
ax.set_xticks(numpy.arange(pd_y_p_norm.shape[1])+0.5, minor=False)
ax.set_yticks(numpy.arange(pd_y_p_norm.shape[0])+0.5, minor=False)

# Rotate the xlabels. Set both x and y labels 
ax.set_xticklabels(headers,rotation=90,fontsize=12)
ax.set_yticklabels(pd_y_p_norm.index,fontsize=12)
ax.grid(True)
plt.show()<jupyter_output><empty_output><jupyter_text>Ejercicio 4Dada la variable aleatoria Z = ’contexto1 en el que se produjo el hecho’, calcular la probabilidad que el hecho sea producido en una dependencia de una fuerza de seguridad (penal, comisaría, etc)$$ fdp(z=penal ~~ |~~  z=comisaria ~~ | ...) $$  Sol Ejercicio 4<jupyter_code># Arreglamos el tema de acentos dentro de los strings, puesto que vamos a usarlos para filtrar
dataset['contexto1']=dataset['contexto1'].str.normalize('NFKD').str.encode('ascii', errors='ignore').str.decode('utf-8')
# Veamos que componen contexto1
lst_contexto1 = list(set(dataset.contexto1.tolist()))
lst_contexto1.pop(lst_contexto1.index(numpy.nan))
lst_contexto1.sort()
for i in range(0,len(lst_contexto1)):
    print (i,lst_contexto1[i])
#Armamos la lista para filtrar
lst_contexto1_filt=[lst_contexto1[i] for i in [1, 3, 5,6,11,12,15,16]]
lst_contexto1_filt
#Filtramos
pd_contexto1=dataset.loc[dataset['contexto1'].isin(lst_contexto1_filt)]
# La cantidad de eventos totales en contexto 1 la sacamos 
counts_all=float(dataset.shape[0])
counts_fs=float(pd_contexto1.shape[0])
p_fs=float(counts_fs/counts_all)
sout='La probabilidad es: %f' % p_fs
print(sout)<jupyter_output>La probabilidad es: 0.760250<jupyter_text>Ejercicio 5Dada la variable aleatoria M = ‘existió violencia fisica’:* ¿Que probabilidad existe que también tenga violencia psíquica? N = ‘existió violencia psíquica’$$P(N~~|~~M)$$* ¿Qué conclusión se puede formular de los datos que tenemos y los datos que obtenemos de los métodos probabilísticos?* ¿Podemos concluir en que son eventos independientes dadas las muestras?  Sol Ejercicio 5<jupyter_code># Veamos el espacio muestral de los casos con violencia fisica
lst_vf=list(set(dataset.violencia_fisica.tolist()))
lst_vf.pop(lst_vf.index(numpy.nan)) #Saquemos nan
lst_vf.pop(lst_vf.index('Ninguno')) #Saquemos aquellos casos que explicitamente no tienen violencia fisica
lst_vf.sort()
#lst
#Filtramos aquellos con violencia fisica, es decir reducimos el espacio muestral a los indicados en la lista anterior
pd_vf=dataset.loc[dataset['violencia_fisica'].isin(lst_vf)]
pd_vf[:3]
# Veamos de los casos con violencia fisica, aquellos casos con violencia_psiquica
lst_vps=list(set(pd_vf.violencia_psiquica.tolist()))
lst_vps.pop(lst_vps.index(numpy.nan))
lst_vps.pop(lst_vps.index('Ninguno'))
lst_vps.sort()
#vslst
# Volvamos a filtrar el dataset, de esta manera vamos a tener la cantidad de casos que dado que tienen violencia fisica
# tambien tiene violencia psiquica.
pd_vf_vps=pd_vf.loc[pd_vf['violencia_psiquica'].isin(lst_vps)]
pd_vf_vps[:3]
# Ahora con ambos dataframe, contemos los casos
pd_vf_vps_len = float(pd_vf_vps.shape[0]) # Aquellos que dado que tienen violencia fisica tambien tienen violencia psiquica
pd_vf_len = float(pd_vf.shape[0]) # Todos los casos con violencia fisica
p_n_int_m = float(pd_vf_vps_len/pd_vf_len)
sout='La probabilidad P (N interseccion M) es: %f' % p_n_int_m
print(sout)
# Y por definicion la P buscada es P(N interseccion M)/P(M)=P(N|M)
p_vf=float(pd_vf.shape[0]/dataset.shape[0])
p_n_m=float(p_n_int_m/p_vf);
sout='La probabilidad P (N | M) es: %f' % p_n_m
print(sout)<jupyter_output>La probabilidad P (N interseccion M) es: 0.211966
La probabilidad P (N | M) es: 0.521400<jupyter_text>* ¿Qué conclusión se puede formular de los datos que tenemos y los datos que obtenemos de los métodos probabilísticos?De los datos provisto podemos ver que la existencia de violencia fisica trae aparejada violencia psiquica hasta en un 50%. * ¿Podemos concluir en que son eventos independientes dadas las muestras?<jupyter_code># Para ver si son eventos independientes contemos
# La cantidad de eventos con violencia fisica ya la habiamos contado en el punto anterior
str_vf= 'Cantidad de eventos violencia fisica: ' + str(pd_vf_len)
print(str_vf)
# tenemos que contar los casos con violencia psiquica
# Volvamos a filtrar el dataset
pd_vps=dataset.loc[dataset['violencia_psiquica'].isin(lst_vps)]
pd_vps[:3]
# La cantidad de eventos con violencia psiquica 
pd_vps_len=pd_vps.shape[0]
str_vs= 'Cantidad de eventos violencia psiquica: ' + str(pd_vps_len)
print(str_vs)
# Entonces podemos armar
str_vf_p= 'P(violencia fisica): ' + str(p_vf)
print(str_vf_p)
p_vps=pd_vps_len/dataset.shape[0];
str_vs_p= 'P(violencia psiquica): ' + str(p_vps)
print(str_vs_p)<jupyter_output>P(violencia fisica): 0.4065323141070188
P(violencia psiquica): 0.3085476025017373<jupyter_text>Para el caso de eventos independientes deberia ser cumplirse que $$P(N~~|~~M)=P(N)$$, es decir que tener o no violencia fisica no impacta, en tener violencia psiquica.<jupyter_code># De calculos anteriores sacamos que 
print('P(N|M) = '+ str(p_n_m))
#pero
print('P(N) = '+ str(p_vps))<jupyter_output>P(N|M) = 0.5213996639637665
P(N) = 0.3085476025017373
{'fraction_non_alphanumeric': 0.0918372215066075, 'fraction_numerical': 0.0439864510280998, 'mean_word_length': 5.797016861219196, 'pattern_counts': {'":': 0, '<': 63, '<?xml version=': 0, '>': 65, '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': '17', 'dir': 'jupyter-structured-clean-dedup', 'id': '262295', 'license': 'MIT', 'n_tokens_mistral': 8240, 'n_tokens_neox': 7659, 'n_words': 2229, 'path': 'ayv_2018/Tarea integradora - parte 1.ipynb', 'repo_name': 'felixlapalma/diplodatos_2018', 'size': '20961'}