<jupyter_start><jupyter_text>Limpieza de Datos<jupyter_code># Leo la fuente de datos local en CSV 
df = pd.read_csv('data/vacunation_data.csv')
df.head()
# Obtengo el conteo del número de valores en cada columnas
total_count = len(df)
print(f'TOTAL COUNT: {total_count}')
print(df.count())
# Verificamos que las columnas DEPARTAMENTO, GRUPO_RIESGO y SEXO tengan los valores indicados
print(df['DEPARTAMENTO'].unique())
print(df['GRUPO_RIESGO'].unique())
print(df['SEXO'].unique())
# Nos quedamos con los datos que correspondan solo a la primera dosis
df = df[df['DOSIS'] == 1]
# Filtramos las filas que no tienen valor en las columnas EDAD o SEXO
df = df[df['EDAD'].notnull() & df['SEXO'].notnull()]<jupyter_output><empty_output><jupyter_text>Transformación de Datos<jupyter_code># Abreviando los grupos de riesgo
df['GRUPO_RIESGO'].replace('PERSONAL DE SALUD','P. SALUD', inplace=True)
df['GRUPO_RIESGO'].replace('TRABAJADOR Ó PERSONAL DE LIMPIEZA','T. LIMP.', inplace=True)
df['GRUPO_RIESGO'].replace('PERSONAL DE SEGURIDAD','P. SEG.', inplace=True)
df['GRUPO_RIESGO'].replace('PERSONAL MILITAR Ó FF AA','FF.AA.', inplace=True)
df['GRUPO_RIESGO'].replace('POLICIA NACIONAL DEL PERU','P.N.P.', inplace=True)
df['GRUPO_RIESGO'].replace('ESTUDIANTES DE CIENCIAS DE LA SALUD','E. SALUD', inplace=True)
df['GRUPO_RIESGO'].replace('BRIGADISTAS','BRIG.', inplace=True)

# Genero Serie de grupos de riesgo
grupos_riesgo = df['GRUPO_RIESGO'].unique()
grupos_riesgo_series = pd.Series(np.zeros_like(grupos_riesgo),grupos_riesgo)

# Agrupo el conjunto de datos por DEPARTAMENTO, SEXO y EDAD para el DataFrame
gb_age = df[["DEPARTAMENTO","SEXO",'EDAD']].groupby(['DEPARTAMENTO', 'SEXO', pd.cut(df['EDAD'], BINS, False)])

# Agrupo el conjunto de datos por DEPARTAMENTO, SEXO y GRUPO_RIESGO para el DataFrame
gb_gr = df[["DEPARTAMENTO","SEXO",'GRUPO_RIESGO']].groupby(['DEPARTAMENTO', 'SEXO', 'GRUPO_RIESGO'])
def get_data_to_plot(department=None):
    if(department is None):
        return df[['SEXO','EDAD','GRUPO_RIESGO','FECHA_VACUNACION']]
    else:
        return df[df['DEPARTAMENTO'] == department][['SEXO','EDAD','GRUPO_RIESGO','FECHA_VACUNACION']]<jupyter_output><empty_output><jupyter_text>Visualización de Datos<jupyter_code># Visualizo los datos agrupados por EDAD via DataFrame
gb_age.size().unstack()
# Visualizo los datos agrupados por GRUPO_RIESGO via DataFrame
gb_gr.size().unstack()
yticks = [5,15,25,35,45,55,65,75,85]

def generate_plot(area, data, date_range, show_plot=False, save_plot=True):

    # Creamos la figura, los ejes y agregamos la atribución
    fig, axs = plt.subplots(2,2, figsize=(20,20))
    plt.figtext(0.1,0.95, area + ': DISTRIBUCIÓN DE VACUNADOS CONTRA COVID-19 (N=' + str(len(data)) + ')', ha='left', fontsize=24)
    plt.figtext(0.1,0.925, 'Rango de fechas de vacunación: del {} al {}'.format(f'{date_range[0]:%Y-%m-%d}',f'{date_range[1]:%Y-%m-%d}'), ha='left', fontsize=20, color='#999')
    plt.figtext(0.9,0.02, """Fuente: https://www.datosabiertos.gob.pe/dataset/vacunaci%C3%B3n-contra-covid-19-ministerio-de-salud-minsa
    Autor: https://malexandersalazar.github.io/, <NAME>, """ + f'{DateTime.now():%Y-%m-%d}', ha='right')

    # 1. Graficamos distribución por GRUPO ETAREO
    xlim_max = 0

    ## 1.1. Graficamos el primer histograma
    N, bins, patches = axs[0][0].hist(data["EDAD"], BINS, orientation = 'horizontal')

    ### Colorearemos las barras en base el conteo relativo de cada agrupación
    xlim_max = N.max() * 1.1
    fracs = N / N.max()
    norm = colors.Normalize(fracs.min(), fracs.max())

    ### Recorremos las barras y actualizamos cada color respectivamente
    for thisfrac, thispatch in zip(fracs, patches):
        color = plt.cm.viridis(norm(thisfrac))
        thispatch.set_facecolor(color)

    ### Personalizamos las ejes de nuestro gráfico
    axs[0][0].set_yticklabels([])
    axs[0][0].yaxis.set_tick_params(width=0)
    axs[0][0].set_yticks(yticks, minor=True)
    axs[0][0].set_yticklabels(['0-9','10-19', '20-29', '30-39', '40-49', '50-59', '60-69', '70-79', '80+'], minor=True)
    axs[0][0].set_ylim(0,90)
    axs[0][0].set_xlim(0,xlim_max)
    axs[0][0].set_ylabel('GRUPO ETÁREO (AÑOS)')

    ### Calculamos y anotamos los porcentajes correspondientes a cada barra
    for i in range(len(BINS)-1):
        axs[0][0].text(N[i], yticks[i]-1, str(round(N[i]*100/len(data),2)) + '%')

    ## 1.2. Graficamos el segundo histograma
    males = data[data['SEXO'] == 'MASCULINO']["EDAD"]
    females = data[data['SEXO'] == 'FEMENINO']["EDAD"]

    N, bins, patches = axs[0][1].hist([males, females], bins=9, range=[0,90], orientation = 'horizontal')
    
    ### Personalizamos las ejes de nuestro gráfico
    axs[0][1].set_yticklabels([])
    axs[0][1].yaxis.set_tick_params(width=0)
    axs[0][1].set_yticks(yticks, minor=True)
    axs[0][1].set_ylim(0,90)
    axs[0][1].set_xlim(0,xlim_max)

    ### Calculamos y anotamos los porcentajes correspondientes a cada barra
    for i in range(len(BINS)-1):
        axs[0][1].text(N[0][i], yticks[i]-3, str(round(N[0][i]*100/len(data),2)) + '%')
        axs[0][1].text(N[1][i], yticks[i]+1, str(round(N[1][i]*100/len(data),2)) + '%')

    axs[0][1].legend(['Hombres (n=' + str(len(males)) + ')', 'Mujeres (n=' + str(len(females)) + ')'])

    # 2. Graficamos distribución por GRUPO RIESGO
    xlim_max = 0

    ## 2.1. Graficamos el primer gráfico de barras 
    group_counts = data['GRUPO_RIESGO'].value_counts().add(grupos_riesgo_series,fill_value=0)
    group_counts.sort_index(inplace=True,ascending=False)
    pos = np.array(range(len(group_counts)))
    patches = axs[1][0].barh(pos, group_counts.values, align='center')
    
    ### Colorearemos las barras en base el conteo relativo de cada agrupación
    xlim_max = group_counts.values.max() * 1.1
    fracs = group_counts.values / group_counts.values.max()
    norm = colors.Normalize(fracs.min(), fracs.max())

    ### Recorremos las barras y actualizamos cada color respectivamente
    for thisfrac, thispatch in zip(fracs, patches):
        color = plt.cm.viridis(norm(thisfrac))
        thispatch.set_facecolor(color)

    ### Personalizamos las ejes de nuestro gráfico
    axs[1][0].set_yticks(pos)
    axs[1][0].set_yticklabels(list(group_counts.index.values))
    axs[1][0].set_xlim(0,xlim_max)

    ### Calculamos y anotamos los porcentajes correspondientes a cada barra
    for i in range(len(pos)):
        axs[1][0].text(group_counts.values[i], pos[i]-0.1, str(round(group_counts[i]*100/len(data),2)) + '%')

    ## 2.2. Graficamos el segundo gráfico de barras 
    males = data[data['SEXO'] == 'MASCULINO']
    males_group_counts = males["GRUPO_RIESGO"].value_counts().add(grupos_riesgo_series,fill_value=0)
    males_group_counts.sort_index(inplace=True,ascending=False)

    females = data[data['SEXO'] == 'FEMENINO']
    females_group_counts = females["GRUPO_RIESGO"].value_counts().add(grupos_riesgo_series,fill_value=0)
    females_group_counts.sort_index(inplace=True,ascending=False)

    pos = np.array(range(len(males_group_counts)))

    axs[1][1].barh(pos, males_group_counts.values, 0.35, align='center')
    axs[1][1].barh(pos+0.35, females_group_counts.values, 0.35, align='center')
    
    ### Personalizamos las ejes de nuestro gráfico
    axs[1][1].set_yticks(pos)
    axs[1][1].set_yticklabels([])
    axs[1][1].set_xlim(0,xlim_max)
    
    ### Calculamos y anotamos los porcentajes correspondientes a cada barra
    for i in range(len(pos)):
        axs[1][1].text(males_group_counts.values[i], pos[i]-0.1, str(round(males_group_counts[i]*100/len(data),2)) + '%')
        axs[1][1].text(females_group_counts.values[i], pos[i]+0.3, str(round(females_group_counts[i]*100/len(data),2)) + '%')

    ## 3. Mostramos, guardamos y generamos el Markdown para las imágenes

    sns.despine(left=False, bottom=False)

    if save_plot:
        filename = 'dist/{}_{}.png'.format(f'{DateTime.now():%Y%m%d}', area.replace(' ', '_'))
        plt.savefig("../" + filename, bbox_inches='tight')
        with open("../dist/images.txt", "a", encoding='utf-8') as f:
            f.write('![alt text]({} "{}")\n\n'.format(filename, area))

    if show_plot:
        plt.show()

    plt.close(fig)
# Eliminando archivo generado para el Markdown de las imágenes
if os.path.exists("../dist/images.txt"):
    os.remove("../dist/images.txt")
# Perú
data = get_data_to_plot()
dates = pd.to_datetime(data['FECHA_VACUNACION'], infer_datetime_format=False, format='%Y%m%d')
generate_plot('PERÚ', data, (dates.min(), dates.max()), False, True)
# Departamentos
departments_ordered = np.sort(df['DEPARTAMENTO'].unique())
for d in departments_ordered:
    data = get_data_to_plot(d)
    dates = pd.to_datetime(data['FECHA_VACUNACION'], infer_datetime_format=False, format='%Y%m%d')
    generate_plot(d, data, (dates.min(), dates.max()), False, True)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.17360875945366294, 'fraction_numerical': 0.026188057342815218, 'mean_word_length': 4.9106070713809205, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, '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': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '317572', 'license': 'MIT', 'n_tokens_mistral': 3661, 'n_tokens_neox': 3568, 'n_words': 625, 'path': 'src/main.ipynb', 'repo_name': 'MAlexanderSalazar/covid-19-peru-distribucion-vacunacion', 'size': '8882'}