<jupyter_start><jupyter_text>Table of Contents1&nbsp;&nbsp;Analisando como os recursos físicos estão distribuidos nos estados2&nbsp;&nbsp;Analise do panorama geral dos estados2.0.1&nbsp;&nbsp;Vamos plotar a situação dos recursos físicos em um estado específico2.1&nbsp;&nbsp;Escolhendo um novo local de diagnostico2.1.1&nbsp;&nbsp;Agora iremos fazer a redistribuição dos recursos físicos  Analisando como os recursos físicos estão distribuidos nos estados<jupyter_code>import numpy as np
import pandas as pd
from tqdm.auto import tqdm

import matplotlib.pyplot as plt
import mplleaflet

from geopy.distance import geodesic

import os

import math

from k_medoids_rf import KMedoidsWeighted

tqdm.pandas()

%matplotlib inline
data_dir = '../data/'
rf_dataset_name = 'RF- Mamógrafos.csv' #podemos fazer a analise tambem para tomografos
use_cols = ['COD_MUN','2018/Dez'] # obtendo os dados mais recentes
municipios_dataset_name = 'dados_mun_clean.csv'
distancia_max = 65 #padrão internacional que queremos atingir (para tomografos 70)
populacao_max = 240000 #padrão internacional que queremos atingir (para tomografos 100000)
UF_analisado = 'CE'
def dist_to_near_rf(row):
    '''
    Retorna a menor distancia a um recurso físico, dada a latitude e longitude de uma cidade
    '''
    distancias = cities_rf[cities_rf.UF == row.UF].apply(lambda x: geodesic((x['LATITUDE'], x['LONGITUDE']), (row.LATITUDE, row.LONGITUDE)).km , axis=1)
    index_min = distancias.idxmin()
    near_city = cities_rf.iloc[index_min]
    distancia = geodesic((near_city.LATITUDE, near_city.LONGITUDE), (row.LATITUDE, row.LONGITUDE)).km
    return near_city.COD_MUN, distancia

def population_around_rf(codigo_mun):
    '''
    Retorna a soma das populacoes das cidades ao redor de um rf
    '''
    cidades_proximas = municipios[municipios.COD_PROX == codigo_mun]
    return cidades_proximas.POPULACAO.astype(int).sum()

def generate_panorama_rfs(cities_rf, municipios):
    '''
    Cria um dataframe com um panorama geral dos estados
    '''
    total_cidades, total_populacao, total_rfs, ideal_rfs,suficiente,cidades_proximas, cidades_distantes, centros_suficiente, centros_insuficiente = [],[],[],[],[],[],[],[],[]
    for estado in estados:
        UF_analisado = estado
        cidades_no_estado = municipios[municipios.UF == estado]
        rf_no_estado = cities_rf[cities_rf.UF == estado]
        rf_no_estado = rf_no_estado.assign(POP_ATENDIDA = rf_no_estado.COD_MUN.apply(lambda cod: population_around_rf(cod)))

        distantes, proximas = cidades_no_estado[cidades_no_estado.DISTANCIAS > distancia_max], cidades_no_estado[cidades_no_estado.DISTANCIAS < distancia_max]
        suficientes, insuficientes = rf_no_estado[rf_no_estado.POP_ATENDIDA < populacao_max], rf_no_estado[rf_no_estado.POP_ATENDIDA > populacao_max]
        total_populacao_estado = cidades_no_estado.POPULACAO.astype(int).sum()
        total_rf_estado = rf_no_estado['2018/Dez'].astype(int).sum()
        ideal_rf_estado = math.ceil(total_populacao_estado/populacao_max)

        total_cidades.append(cidades_no_estado.COD_MUN.count())
        total_populacao.append(total_populacao_estado)
        total_rfs.append(total_rf_estado)
        ideal_rfs.append(ideal_rf_estado)
        suficiente.append(total_rf_estado > ideal_rf_estado)
        cidades_proximas.append(proximas.COD_MUN.count())
        cidades_distantes.append(distantes.COD_MUN.count())
        centros_suficiente.append(suficientes.COD_MUN.count())
        centros_insuficiente.append(insuficientes.COD_MUN.count())

    panorama_distribuicao_rfs_uf = pd.DataFrame({
        'UF': estados,
        'TOTAL_CIDADES': total_cidades,
        'TOTAL_POPULACAO': total_populacao,
        'TOTAL_MAMOGRAGOS': total_rfs,
        'IDEAL_RFS': ideal_rfs,
        'SUFICIENTE': suficiente,
        'CIDADES_PROXIMAS': cidades_proximas,
        'CIDADES_DISTANTES': cidades_distantes,
        'CENTROS_SUFICIENTES': centros_suficiente,
        'CENTROS_INSUFICIENTES': centros_insuficiente
    },columns= ['UF', 'TOTAL_MAMOGRAGOS', 'TOTAL_POPULACAO', 'IDEAL_RFS','SUFICIENTE','TOTAL_CIDADES', 'CIDADES_DISTANTES' , 'CIDADES_PROXIMAS', 'CENTROS_SUFICIENTES', 'CENTROS_INSUFICIENTES'])
    return panorama_distribuicao_rfs_uf

# Lendo os dataframes:

rf = pd.read_csv(os.path.join(data_dir, rf_dataset_name), encoding='latin', index_col=False, 
                     error_bad_lines=False, low_memory=False, usecols=use_cols)

municipios = pd.read_csv(os.path.join(data_dir, municipios_dataset_name), encoding='latin', index_col=0, 
                     error_bad_lines=False, low_memory=False)

municipios['COD_MUN'] = municipios['COD_MUN'].apply(lambda x: (int) ((x - x%10)/10))
cities_rf = pd.merge(rf[rf['2018/Dez'] > 0], municipios, on='COD_MUN', how='left')
municipios = municipios.assign(DISTANCIAS = municipios.progress_apply(lambda row: dist_to_near_rf(row)[1], axis=1), COD_PROX = municipios.progress_apply(lambda row: dist_to_near_rf(row)[0], axis=1))
estados = municipios.UF.unique()<jupyter_output><empty_output><jupyter_text>Analise do panorama geral dos estados<jupyter_code>panorma_distribuicao_rfs_uf = generate_panorama_rfs(cities_rf, municipios)
panorma_distribuicao_rfs_uf
panorma_distribuicao_rfs_uf['rf_por_pop'] = populacao_max*(panorma_distribuicao_rfs_uf['TOTAL_MAMOGRAGOS']/panorma_distribuicao_rfs_uf['TOTAL_POPULACAO'])
panorma_distribuicao_rfs_uf<jupyter_output><empty_output><jupyter_text>Da tabela acima, aplicando para mamografos, podemos notar que, com exceção de AC, AP e DF, todos os estados são suficientes de mamógrafos.  Vamos plotar a situação dos recursos físicos em um estado específico<jupyter_code>cidades_no_estado = municipios[municipios.UF == UF_analisado]
bool_dist = cidades_no_estado.DISTANCIAS < distancia_max
proximos, distantes = cidades_no_estado[bool_dist], cidades_no_estado[~bool_dist]

rf_no_estado = cities_rf[cities_rf.UF == UF_analisado]
rf_no_estado = rf_no_estado.assign(POP_ATENDIDA = rf_no_estado.COD_MUN.progress_apply(lambda cod: population_around_rf(cod)))
bool_pop = rf_no_estado.POP_ATENDIDA < populacao_max
pop_ok, pop_n_ok = rf_no_estado[bool_pop], rf_no_estado[~bool_pop]
fig, ax = plt.subplots(figsize=[10,10])
# plt.scatter(distantes.LONGITUDE, distantes.LATITUDE, color='r' , s = 70) # plotar cidades com mamografos distantes
# plt.scatter(proximos.LONGITUDE, proximos.LATITUDE, color='b',s = 70) # plotar cidades com mamografos proximos
plt.scatter(pop_ok.LONGITUDE, pop_ok.LATITUDE, marker='^', color='#5cd65c', s = 400) # plotar cidades em que o numero de mamografos sao adequados
plt.scatter(pop_n_ok.LONGITUDE, pop_n_ok.LATITUDE, marker='^', color='r', s = 400) #plotar cidades em que o numero de mamografos nao sao adequados
mplleaflet.display(fig=fig)<jupyter_output><empty_output><jupyter_text>Em azul estão as cidades que conseguem ser atendidas pelos recursos físicos e em vermelho as que não conseguem.Os triângulos verde claro são os recursos que estão sendo subutilizados enquanto que os verde escuro são os que estão sendo superutilizados  Escolhendo um novo local de diagnostico<jupyter_code># aplicar o k-medoids para definir novos pontos
n_novos = 1 #numero de novos locais de diagnosticos

cidades_no_estado = municipios[municipios.UF == UF_analisado]
cidades_com_rf = cities_rf[cities_rf.UF == UF_analisado]['COD_MUN'].values.tolist()
X = cidades_no_estado[['LATITUDE', 'LONGITUDE', 'COD_MUN']].values.tolist()
medoids_fix_idxs = []
for i in range(len(X)):
    cod_mun = X[i][2]
    if cod_mun in cidades_com_rf:
        medoids_fix_idxs.append(i)

# quantidade inicial de cidades com rfs
n_centros = len(medoids_fix_idxs)

# quantidade de novas cidades com novo centro
clustering = KMedoidsWeighted(n_clusters=n_centros+n_novos)
medoids_idxs, clusters = clustering.fit(X, medoids_fix_idxs, max_itr=10, verbose=1)
# adicionando cidades sugeridas na lista de cidades com rfs
novos_medoids = np.setdiff1d(medoids_idxs, medoids_fix_idxs)
for i in novos_medoids:
    cod_mun = int(X[i][2])
    nova_cidade = municipios[municipios.COD_MUN == cod_mun].values.tolist()[0]
    cities_rf = cities_rf.append({'COD_MUN' : cod_mun,
                                                '2018/Dez': 0,
                                                'UF': nova_cidade[0],
                                                'NOME': nova_cidade[2],
                                                'POPULACAO': nova_cidade[3],
                                                'LATITUDE': nova_cidade[4],
                                                'LONGITUDE': nova_cidade[5],
                                                'CAPITAL': nova_cidade[6],
                                                'CODIGO_UF': nova_cidade[7]
                                               } , ignore_index=True)


# atualizando distancias no municipio modificado
municipios = municipios.assign(DISTANCIAS = municipios.progress_apply(lambda row: (dist_to_near_rf(row)[1] if (row.UF == UF_analisado) else row.DISTANCIAS), axis=1), COD_PROX = municipios.progress_apply(lambda row: (dist_to_near_rf(row)[0] if (row.UF == UF_analisado) else row.COD_PROX), axis=1))
rf_no_estado = cities_rf[cities_rf.UF == UF_analisado]
rf_no_estado = rf_no_estado.assign(POP_ATENDIDA = rf_no_estado.COD_MUN.apply(lambda cod: population_around_rf(cod)))
rf_no_estado = rf_no_estado.assign(IDEAL_rf = rf_no_estado.POP_ATENDIDA.apply(lambda pop: math.ceil(pop/populacao_max)))<jupyter_output><empty_output><jupyter_text>Agora iremos fazer a redistribuição dos recursos físicos<jupyter_code>rf_no_estado_copy = rf_no_estado.copy()
# preparando para a redistribuição os rfs

rf_no_estado_copy = rf_no_estado_copy.sort_values(by=['POP_ATENDIDA'], ascending=False)
total_rfs = rf_no_estado_copy['2018/Dez'].astype(int).sum()
total_cities = rf_no_estado_copy.COD_MUN.astype(int).count()
total_pop_atendida = rf_no_estado_copy.POP_ATENDIDA.astype(int).sum()
cities_matrix = rf_no_estado_copy[['COD_MUN', 'POP_ATENDIDA', 'IDEAL_rf']].values.tolist()
for i in range(total_cities):
    cities_matrix[i].append(0)
# redistribuir rfs se o estado for suficiente de rfs
if (total_pop_atendida / total_rfs) < populacao_max:
    aux = total_rfs
    i = 0
    saltos_seguidos = 0
    while (aux > 0) and (saltos_seguidos <= total_cities):
        if (cities_matrix[i][3] >= cities_matrix[i][2]):
            saltos_seguidos = saltos_seguidos + 1
            i = (i + 1)%total_cities
            continue
        saltos_seguidos = 0
        cities_matrix[i][3] = cities_matrix[i][3] + 1
        i = (i + 1)%total_cities
        aux = aux - 1
    i = 0
    while aux > 0:
        cities_matrix[i][3] = cities_matrix[i][3] + 1
        i = (i + 1)%total_cities
        aux = aux - 1 
    
cities_matrix = sorted(cities_matrix, key = lambda k: k[0])
redistirbuicao = []
for city in cities_matrix:
    redistirbuicao.append(city[-1])
    
rf_no_estado_copy = rf_no_estado_copy.sort_values(by='COD_MUN')
rf_no_estado_copy['REDISTRIBUICAO'] = redistirbuicao
#calculo as novas distancias aos recursos físicos
cidades_no_estado = cidades_no_estado.assign(NOVA_DISTANCIAS = cidades_no_estado.progress_apply(lambda row: dist_to_near_rf(row)[1], axis=1), COD_PROX = cidades_no_estado.progress_apply(lambda row: dist_to_near_rf(row)[0], axis=1))
proximos, distantes = cidades_no_estado[cidades_no_estado.NOVA_DISTANCIAS < distancia_max], cidades_no_estado[cidades_no_estado.NOVA_DISTANCIAS > distancia_max]
pop_ok, pop_n_ok = rf_no_estado_copy[rf_no_estado_copy.REDISTRIBUICAO >= rf_no_estado_copy.IDEAL_rf], rf_no_estado_copy[rf_no_estado_copy.REDISTRIBUICAO < rf_no_estado_copy.IDEAL_rf]

fig, ax = plt.subplots(figsize=[10,10])

# plt.scatter(distantes.LONGITUDE, distantes.LATITUDE, color='r' , s = 70) # plotar cidades com rfs distantes
# plt.scatter(proximos.LONGITUDE, proximos.LATITUDE, color='b',s = 70) # plotar cidades com rfs proximos
plt.scatter(pop_ok.LONGITUDE, pop_ok.LATITUDE, marker='^', color='#5cd65c', s = 400) # plotar cidades em que o numero de rfs sao adequados
plt.scatter(pop_n_ok.LONGITUDE, pop_n_ok.LATITUDE, marker='^', color='r', s = 400) #plotar cidades em que o numero de rfs nao sao adequados
mplleaflet.display(fig=fig)<jupyter_output><empty_output><jupyter_text>Como podemos ver no mapa acima houve uma redistirbuição dos recursos de forma a utilizar-los de forma mais otimizada.<jupyter_code>#nova distribuição
rf_no_estado_copy
rf_no_estado_copy['DELTA'] = (rf_no_estado_copy['REDISTRIBUICAO'] - rf_no_estado_copy['2018/Dez'])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10282241944511074, 'fraction_numerical': 0.011353641960502118, 'mean_word_length': 4.698405466970387, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 34, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '6', 'dir': 'jupyter-structured-clean-dedup', 'id': '506995', 'license': 'MIT', 'n_tokens_mistral': 5050, 'n_tokens_neox': 4882, 'n_words': 846, 'path': 'code/4-analise-distribuicao-rf.ipynb', 'repo_name': 'bgmello/bcg-gamma-challenge', 'size': '12507'}