<jupyter_start><jupyter_text>Estudando BDGD Notebook referente a primeira versão das análises exploratórias da BDGD.Vamos ler as tabelas referentes a rede de Média Tensão (MT) da Energisa-Paraíba (EPB) a partir da base de dados de 31/12/2020.**Atenção:**Estamos lendo os dados com um primeiro filtro:Tabelas que possuem o campo **SIT_ATIV: Tipo de Situação de Ativação (TSITATI)** já foram filtradas para ler apenas situação **AT Ativada**.<jupyter_code>import pandas as pd
import numpy as np<jupyter_output><empty_output><jupyter_text>Leitura dos DataFrames de Interesse - MT Todos os dataframes lidos serão armazenados no dicionário `base`, para facilitar o acesso.<jupyter_code>base = {}
def ler_dataframe(filename, index_col, filter = ''):
    '''
    Lê o dataframe a partir do arquivo e imprime as 3 primeiras linhas e o shape.
    '''

    df = pd.read_csv(filename, index_col=index_col)
    return df.query(filter) if len(filter)>0 else df<jupyter_output><empty_output><jupyter_text>Leitura: SUB **Subestação*** Designação da Entidade: Subestação* Designação da Modelagem: SUB* Tipo: Polígono<jupyter_code>base['SUB'] = ler_dataframe(filename = '../20201231_Exportação/20201231_sub.csv', index_col = 1)
display(base['SUB'].head(3))<jupyter_output><empty_output><jupyter_text>Leitura: CTMT **Circuito de Média Tensão*** Designação da Entidade: Circuito de Média Tensão* Designação da Modelagem: CTMT* Tipo: Entidades Não Geográficas<jupyter_code>base['CTMT'] = ler_dataframe(filename = '../20201231_Exportação/20201231_ctmt.csv', index_col = 0)
display(base['CTMT'].head(3))<jupyter_output><empty_output><jupyter_text>Leitura: UCMT **Unidade Consumidora de Média Tensão*** Designação da Entidade: Unidade Consumidora de Média Tensão* Designação da Modelagem: UCMT* Tipo: Ponto<jupyter_code>base['UCMT'] = ler_dataframe(
    filename = '../20201231_Exportação/20201231_ucmt.csv', 
    index_col = 0,
    filter = 'SIT_ATIV == "AT"',
)
display(base['UCMT'].head(3))<jupyter_output><empty_output><jupyter_text>Leitura: UGMT **Unidade Geradora de Média Tensão*** Designação da Entidade: Unidade Geradora de Média Tensão* Designação da Modelagem: UGMT* Tipo: Ponto<jupyter_code>base['UGMT'] = ler_dataframe(
    filename = '../20201231_Exportação/20201231_ugmt.csv', 
    index_col = 0,
    filter = 'SIT_ATIV == "AT"',
)
display(base['UGMT'].head(3))<jupyter_output><empty_output><jupyter_text>Leitura: SSDMT **Segmento do Sistema de Distribuição de Média Tensão*** Designação da Entidade: Segmento de Rede Média Tensão* Designação da Modelagem: SSDMT* Tipo: Linha<jupyter_code>base['SSDMT'] = ler_dataframe(filename = '../20201231_Exportação/20201231_ssdmt.csv', index_col = 1)
display(base['SSDMT'].head(3))<jupyter_output>C:\ProgramData\Anaconda3\lib\site-packages\ipykernel_launcher.py:1: DtypeWarning: Columns (4) have mixed types.Specify dtype option on import or set low_memory=False.
  """Entry point for launching an IPython kernel.<jupyter_text>Leitura: UNCRMT **Unidade Compensadora de Reativo de Média Tensão*** Designação da Entidade: Unidade Compensadora de Reativo Média Tensão* Designação da Modelagem: UNCRMT* Tipo: Ponto<jupyter_code>base['UNCRMT'] = ler_dataframe(
    filename = '../20201231_Exportação/20201231_uncrmt.csv', 
    index_col = 1,
    filter = 'SIT_ATIV == "AT"',
)
display(base['UNCRMT'].head(3))<jupyter_output><empty_output><jupyter_text>Leitura: UNREMT **Unidade Reguladora de Média Tensão*** Designação da Entidade: Unidade Reguladora de Média Tensão* Designação da Modelagem: UNREMT* Tipo: Ponto<jupyter_code>base['UNREMT'] = ler_dataframe(
    filename = '../20201231_Exportação/20201231_unremt.csv', 
    index_col = 1,
    filter = 'SIT_ATIV == "AT"',
)
display(base['UNREMT'].head(3))<jupyter_output><empty_output><jupyter_text>Leitura: UNSEMT **Unidade Seccionadora de Média Tensão*** Designação da Entidade: Unidade Seccionadora de Média Tensão* Designação da Modelagem: UNSEMT* Tipo: Ponto<jupyter_code>base['UNSEMT'] = ler_dataframe(
    filename = '../20201231_Exportação/20201231_unsemt.csv', 
    index_col = 1,
    filter = 'SIT_ATIV == "AT"',
)
display(base['UNSEMT'].head(3))<jupyter_output><empty_output><jupyter_text>Resultado<jupyter_code>for key in base.keys():
    print(f'[{key}]: {base[key].shape}')<jupyter_output>[SUB]: (91, 8)
[CTMT]: (360, 58)
[UCMT]: (1891, 51)
[UGMT]: (5, 46)
[SSDMT]: (434463, 24)
[UNCRMT]: (145, 19)
[UNREMT]: (265, 17)
[UNSEMT]: (102984, 21)<jupyter_text>Consistência da base em relação às SUBs Vou guardar em `lista_SUBs` os códigos das subestações declaradas em **SUB**.Todos os dataframes filtrados serão armazenados nos dicionários `base_ok` e `base_not_ok`, para facilitar o acesso.<jupyter_code>base_ok = {}
base_not_ok = {}

lista_SUBs = list(base['SUB']['COD_ID'].unique())
lista_SUBs[:3]
def filtrar_por_SUB(key, base, lista_SUBs):
    '''
    Separa o dataframe base[key] olhando para a coluna 'SUB'.
    Registros com 'SUB' pertencentes a 'lista_SUBs' vão para 'df'.
    Os demais vão para 'df_not'.
    '''
    
    def converte_para_int(valor):
        try:
            return int(valor)
        except:
            return -1
    
    flag = [(converte_para_int(item) in lista_SUBs) for item in base[key]['SUB']]
    flag_not = [not item for item in flag]

    df = base[key][flag].copy()
    display(df.head(3))
    print(f'df.shape = {df.shape}')

    df_not = base[key][flag_not].copy()
    display(df_not.head(3))
    print(f'df_not.shape = {df_not.shape}')
    
    return df, df_not<jupyter_output><empty_output><jupyter_text>Filtro CTMT<jupyter_code>base_ok['CTMT'], base_not_ok['CTMT'] = filtrar_por_SUB('CTMT', base, lista_SUBs)<jupyter_output><empty_output><jupyter_text>Filtro UCMT<jupyter_code>base_ok['UCMT'], base_not_ok['UCMT'] = filtrar_por_SUB('UCMT', base, lista_SUBs)<jupyter_output><empty_output><jupyter_text>No campo SUB aparece 'BVA'.  Filtro UGMT<jupyter_code>base_ok['UGMT'], base_not_ok['UGMT'] = filtrar_por_SUB('UGMT', base, lista_SUBs)<jupyter_output><empty_output><jupyter_text>Filtro SSDMT<jupyter_code>base_ok['SSDMT'], base_not_ok['SSDMT'] = filtrar_por_SUB('SSDMT', base, lista_SUBs)
12873455 in lista_SUBs<jupyter_output><empty_output><jupyter_text>Filtro UNCRMT<jupyter_code>base_ok['UNCRMT'], base_not_ok['UNCRMT'] = filtrar_por_SUB('UNCRMT', base, lista_SUBs)<jupyter_output><empty_output><jupyter_text>Filtro UNREMT<jupyter_code>base_ok['UNREMT'], base_not_ok['UNREMT'] = filtrar_por_SUB('UNREMT', base, lista_SUBs)
12873455 in lista_SUBs<jupyter_output><empty_output><jupyter_text>Filtro UNSEMT<jupyter_code>base_ok['UNSEMT'], base_not_ok['UNSEMT'] = filtrar_por_SUB('UNSEMT', base, lista_SUBs)<jupyter_output><empty_output><jupyter_text>Resultado<jupyter_code>for key in base_ok.keys():
    print(f'[{key}]: {base_ok[key].shape}')
for key in base_not_ok.keys():
    print(f'[{key}]: {base_not_ok[key].shape}')<jupyter_output>[CTMT]: (14, 58)
[UCMT]: (1, 51)
[UGMT]: (0, 46)
[SSDMT]: (497, 24)
[UNCRMT]: (0, 19)
[UNREMT]: (2, 17)
[UNSEMT]: (111, 21)<jupyter_text>Criação de Dataframe único com equipamentos de 2 portas A idéia aqui é deixar a base de dados de entrada genérica:* `base` significa usar os dados completos;* `base_ok` significa usar apenas os registros que tem **SUB** na lista de subestações.A escolha ocorre aqui:<jupyter_code>work = base
df_2portas = pd.DataFrame(columns=['COD_ID','PAC_1','PAC_2','SUB','CTMT','KEY'])
for key in work.keys():
    if key in ['SUB','CTMT','UCMT','UGMT']:
        continue

    if key == 'UNSEMT':
        dff = work[key].query('P_N_OPE == "F"')
        dff = dff[['COD_ID','PAC_1','PAC_2','SUB','CTMT']]
    else:
        dff = work[key][['COD_ID','PAC_1','PAC_2','SUB','CTMT']].copy()

    dff['KEY'] = key
    df_2portas = pd.concat([df_2portas, dff], ignore_index=True)

display(df_2portas.head(3))
display(df_2portas.tail(3))
df_2portas.shape<jupyter_output><empty_output><jupyter_text>Na próxima etapa, uma busca em largura será feita para descobrir os trechos que formam cada um dos circuitos de MT.Essa busca será feita de modo que novas colunas serão geradas em `df_2portas` visando validar os resultados obtidos:* circ_SUB* circ_CTMT* circ_PAC_de* circ_PAC_pr* circ_contador<jupyter_code>df_2portas['circ_SUB'] = -1
df_2portas['circ_CTMT'] = -1
df_2portas['circ_PAC_de'] = -1
df_2portas['circ_PAC_pr'] = -1
df_2portas['circ_cont'] = -1
df_2portas.head(3)<jupyter_output><empty_output><jupyter_text>Criação dos circuitos por Busca em Largura Existe um `PAC` em cada circuito de MT armazenado em `CTMT` que identifica sua conexão na `SUB`. Esse `PAC` será usado como ponto de partida para a busca em largura. De forma didática, faremos primeiro a busca referente ao primeiro circuito:<jupyter_code>row = work['CTMT'].iloc[0]
sub = row['SUB']
pac = row['PAC']

print(f'sub = {sub}, pac = {pac}')
def busca_em_largura(df, sub, pac_circ):
    flag = (df['circ_SUB'] == -1)
    dff = df[flag]
    
    C = [pac_circ,]
    D = set(list(dff['PAC_1']) + list(dff['PAC_2'])) - set(C)
    D = [item for item in D if len(item.strip()) > 0]
    cont = 0

    while(len(C) > 0):

        atual = C[0]
#         print('\n\n')
#         print(f'atual = {atual}\n')
#         print('=====')
#         for item in C:
#             print(f'C.item = {item}')
#         print('=====')

        flag1 = (dff['PAC_1'] == atual)
#         print(f'sum(flag1) = {sum(flag1)}\n')

        filhos = dff[flag1]
#         display(filhos)

        for idx, row in filhos.iterrows():
            if (row['PAC_2'] in D) or (len(row['PAC_2'].strip()) == 0):
#                 print('Achou trecho!')
                df.loc[idx,'circ_SUB'] = sub
                df.loc[idx,'circ_CTMT'] = pac_circ
                df.loc[idx,'circ_PAC_de'] = row['PAC_1']
                df.loc[idx,'circ_PAC_pr'] = row['PAC_2']
                df.loc[idx,'circ_cont'] = cont
                cont += 1

                if len(row['PAC_2'].strip()) > 0:
                    D.remove(row['PAC_2'])
                    C.append(row['PAC_2'])
            else:
#                 print('Achou malha!')
                df.loc[idx,'circ_SUB'] = 'Malha'
                df.loc[idx,'circ_CTMT'] = 'Malha'
                df.loc[idx,'circ_PAC_de'] = 'Malha'
                df.loc[idx,'circ_PAC_pr'] = 'Malha'
#                 breakpoint()

        flag2 = (dff['PAC_2'] == atual)
#         print(f'sum(flag2) = {sum(flag2)}\n')
        
        filhos = dff[flag2]
#         display(filhos)
        
        for idx, row in filhos.iterrows():
            if (row['PAC_1'] in D) or (len(row['PAC_1'].strip()) == 0):
#                 print('Achou trecho!')
                df.loc[idx,'circ_SUB'] = sub
                df.loc[idx,'circ_CTMT'] = pac_circ
                df.loc[idx,'circ_PAC_de'] = row['PAC_2']
                df.loc[idx,'circ_PAC_pr'] = row['PAC_1']
                df.loc[idx,'circ_cont'] = cont
                cont += 1

                if len(row['PAC_2'].strip()) > 0:
                    D.remove(row['PAC_1'])
                    C.append(row['PAC_1'])
            else:
#                 print('Achou malha!')
                df.loc[idx,'circ_SUB'] = 'Malha'
                df.loc[idx,'circ_CTMT'] = 'Malha'
                df.loc[idx,'circ_PAC_de'] = 'Malha'
                df.loc[idx,'circ_PAC_pr'] = 'Malha'
    
        flag = (df['circ_SUB'] == -1)      
        dff = df[flag]
#         print(f'dff.shape = {dff.shape}')
        if (cont % 500) == 0:
            print('+500 iterações.')
#             breakpoint()
        C.remove(atual)
df = df_2portas.copy()
busca_em_largura(df, sub, pac)<jupyter_output>+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.
+500 iterações.<jupyter_text>Quantos trechos foram classificados como sendo da SUB?<jupyter_code>flag = (df['circ_SUB'] == sub)
sum(flag)<jupyter_output><empty_output><jupyter_text>Quantos trechos classificados como sendo da SUB eram esperados?<jupyter_code>flag = (df['SUB'] == sub)
sum(flag)<jupyter_output><empty_output><jupyter_text>Mostre os trechos em que houve diferença.<jupyter_code>flag = (df['circ_SUB'] != -1) & (df['SUB'] != df['circ_SUB'])
df[flag]<jupyter_output><empty_output><jupyter_text>Observe que nos 11 trechos a busca em largura identificou o fechamento de malha e por isso não registrou como parte da subestação `sub`.Há apenas um segmento de rede e o restante é chave.O segmento é mostrado a seguir:<jupyter_code>work['SSDMT'].loc[344743,:]<jupyter_output><empty_output><jupyter_text>Por curiosidade, quantos trechos foram classificados como `malha`?<jupyter_code>flag = (df['circ_SUB'] == 'Malha')
sum(flag)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1464779972010574, 'fraction_numerical': 0.03055512361996579, 'mean_word_length': 4.199272433306386, 'pattern_counts': {'":': 0, '<': 109, '<?xml version=': 0, '>': 114, 'https://': 0, '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': '28', 'dir': 'jupyter-structured-clean-dedup', 'id': '90279', 'license': 'MIT', 'n_tokens_mistral': 5296, 'n_tokens_neox': 5027, 'n_words': 1020, 'path': 'v00_20220430/Busca_em_Largura_2.ipynb', 'repo_name': 'HelonBraz/bdgd', 'size': '12862'}