<jupyter_start><jupyter_text>Cartões de Pagamento do Governo FederalCampos do Arquivo:- "CÓDIGO ÓRGÃO SUPERIOR";- "NOME ÓRGÃO SUPERIOR";- "CÓDIGO ÓRGÃO";- "NOME ÓRGÃO";- "CÓDIGO UNIDADE GESTORA";- "NOME UNIDADE GESTORA";- "ANO EXTRATO";- "MÊS EXTRATO";- "CPF PORTADOR";- "NOME PORTADOR";- "CNPJ OU CPF FAVORECIDO";- "NOME FAVORECIDO";- "TRANSAÇÃO";- "DATA TRANSAÇÃO";- "VALOR TRANSAÇÃO"Podemos ter várias modelagens para descrever os relacionamentos no CPGF, em especial as transações. Vamos considerar que teremos as entidades abaixo já definidas:- Órgão Superior- Órgão- Unidade Gestora- Portador- FavorecidoAgora podemos explorar alguns cenários com ênfase nas transações. Caso 1: Transação como vérticeNesse caso, as transações podem ser colocadas como vértices, com atributos identificadores de saque ou compra. Compras sempre ligam portadores com favorecidos e saques são relações apenas entre portador e a transação. A data da transação e o valor também são adicionadas como atributos.Observer que, nessa situação, uma instância de transação terá no máximo duas arestas. Se o grafo pode ter atributos em arestas também, isso poderia ser substituído por uma aresta entre favorecido e portador, mas seria necessário um vértice de saque para identificar que esse foi o tipo de transação.Para esse cenário, as entidades seriam:- Órgão Superior- Órgão- Unidade Gestora- Portador- Favorecido- Transação Caso 2: Transação descrita pelos valores de domínioComo temos dois tipos de transação para CPGF, pode-se criar dois tipos distintos de vértices descrevendo as transações: saque e compra.Dessa forma, um saque se ligaria a um vértice do tipo saque, com informações sobre esse. E as compras seriam parecidas com as transações anteriores, mas da forma portador -> compra -> favorecido. Uma possibilidade adicional nesse cenário é que, se o grafo suporta atributos nas arestas, pode-se colocar apenas uma entidade de saque e as informações do saque específico ficarem nas arestas. Isso permite localizar rapidamente todos os saques realizados além de aumentar a normalização.Para esse cenário, as entidades seriam:- Órgão Superior- Órgão- Unidade Gestora- Portador- Favorecido- Saque- Compra Caso 3: Transações com saque como uma instância e compras como vérticesConsiderando o CPGF, não temos outras entidades que se liguem a transação a não ser favorecido e portador. Dessa forma, o vérice intermediário poderia ser substituído por um vínculo de compra com os dados da compra. Assim, teríamos portador -> comprou -> favorecido com os dados da operação na aresta. A operação de saque precisa de uma entidade para ser representada, e como comentado no caso anterior, os dados da operação podem ser colocados na aresta também. Assim, pode-se ter apenas um vértice de Saque consolidando todas as arestas de eventos de saque. Caso 4: Enfatizando datasNos cenários anteriores as datas estavam sempre inseridas como atributos de algum vértice ou aresta. Entretanto, identificar compras ou saques na mesma data (assim como lugares) pode ser interessante para auditoria ou detecção de fraudes. Em um grafo, podemos enfatizar relacionamentos utilizando os vértices. Criando uma entidade de Data, podemos interligar as transações por meio dessa entidade e identificar quais operações estão conectadas pelas mesmas instâncias.Nesse caso, entretanto, os vértices de compra já não poderiam ser mantidos como arestas (a menos que fosse um hipergrafo), pois o relacionamento possui mais de duas entidades e o vértice de compra permite fazer a ligação entre portador, favorecido e data. As operações de saque poderiam ser colocadas novamente como um vértice de saque que liga com as datas, mas nesse caso deve-se ter uma instância de saque para cada operação para identificar as diferentes datas e operações. Se tivermos a hora da operação, podemos criar o saque como uma aresta entre portador e data, colocando as informações da operação na aresta, isso também pode ser obtido somando os valores de saque do mesmo dia e o número de operação como atributos, mas não saberíamos o valor individual de cada operação. Por fim, para esse cenário vamos considerar que transação será uma entidade, e ligaremos ela a cada favorecido, portador e data. Isso simplifica algumas consultas pois permite agrupar, por datas, todas as transações realizadas.Para esse cenário, as entidades seriam:- Órgão Superior- Órgão- Unidade Gestora- Portador- Favorecido- Transações- DataEsse último cenário será a base para a construção do banco para exploração do CPGF.<jupyter_code>import pandas as pd
import hashlib
import networkx as nx

#Fonte: Portal da Transparência: http://www.portaldatransparencia.gov.br/
cartoes = pd.read_csv("201801_CPGF_utf8.csv", sep=";")
cartoes.head()
#Extrair entidades
G = nx.Graph()

entidades = {"orgao_superior": set(), "orgao": set(), "unidade_gestora": set(), 
            "portador": set(), "favorecido": set(), "data": set()}
relacionamentos = {"superior_de-orgao_superior-orgao": set(), "possui_ug-orgao-unidade_gestora": set(), 
                   "tem_portador-unidade_gestora-portador": set(), 
                   "realizou_tx-portador-tx": set(), "transacao_em-tx-data": set(), "favoreceu-tx-favorecido": set()}
transacoes = []
count = -1
for index, row in cartoes.iterrows():
    count += 1

    id_orgao_sup = hashlib.sha256(str.encode(str(row['CÓDIGO ÓRGÃO SUPERIOR']) + row['NOME ÓRGÃO SUPERIOR'])).hexdigest()
    orgao_sup = str(id_orgao_sup) + ":" + str(row['CÓDIGO ÓRGÃO SUPERIOR']) + ":" + row['NOME ÓRGÃO SUPERIOR']
    entidades["orgao_superior"] = entidades["orgao_superior"] | set([orgao_sup])

    id_orgao = hashlib.sha256(str.encode(str(row['CÓDIGO ÓRGÃO']) + row['NOME ÓRGÃO'])).hexdigest()
    orgao = str(id_orgao) + ":" + str(row['CÓDIGO ÓRGÃO']) + ":" + row['NOME ÓRGÃO']
    entidades["orgao"] = entidades["orgao"] | set([orgao])

    id_un_gestora = hashlib.sha256(str.encode(str(row['CÓDIGO UNIDADE GESTORA']) + row['NOME UNIDADE GESTORA'])).hexdigest()    
    un_gestora = str(id_un_gestora) + ":" + str(row['CÓDIGO UNIDADE GESTORA']) + ":" + row['NOME UNIDADE GESTORA']
    entidades["unidade_gestora"] = entidades["unidade_gestora"] | set([un_gestora])

    id_portador = hashlib.sha256(str.encode(str(row['CPF PORTADOR']) + row['NOME PORTADOR'])).hexdigest()    
    portador = str(id_portador) + ":" + str(row['CPF PORTADOR']) + ":" + row['NOME PORTADOR']
    entidades["portador"] = entidades["portador"] | set([portador])

    data_tx = str(row['DATA TRANSAÇÃO']).replace("/", "")
    data =  data_tx[4:] + data_tx[2:4] + data_tx[0:2] + ":" + data_tx + ":" + str(row['DATA TRANSAÇÃO'])
    entidades["data"] = entidades["data"] | set([data])

    id_transacao = "tx" + str(count)
    transacao = {"id_transacao": id_transacao, "tipo": row["TRANSAÇÃO"], "valor": row["VALOR TRANSAÇÃO"]}
    transacoes.append(transacao)
    
    relacionamentos["superior_de-orgao_superior-orgao"] = relacionamentos["superior_de-orgao_superior-orgao"] | set([(orgao_sup.split(":")[0], orgao.split(":")[0])])
    relacionamentos["possui_ug-orgao-unidade_gestora"] = relacionamentos["possui_ug-orgao-unidade_gestora"] | set([(orgao.split(":")[0], un_gestora.split(":")[0])])
    relacionamentos["tem_portador-unidade_gestora-portador"] = relacionamentos["tem_portador-unidade_gestora-portador"] | set([(un_gestora.split(":")[0], portador.split(":")[0])])
    relacionamentos["transacao_em-tx-data"] = relacionamentos["transacao_em-tx-data"] | set([(id_transacao, data.split(":")[0])])
    relacionamentos["realizou_tx-portador-tx"] = relacionamentos["realizou_tx-portador-tx"] | set([(portador.split(":")[0], id_transacao)])
    
    if row['CNPJ OU CPF FAVORECIDO'] > 0 and "COMPRA" in row["TRANSAÇÃO"]:
        favorecido = str(row['CNPJ OU CPF FAVORECIDO']) + ":" + str(row['CNPJ OU CPF FAVORECIDO']).zfill(14) + ":" + row['NOME FAVORECIDO']
        entidades["favorecido"] = entidades["favorecido"] | set([favorecido])
        relacionamentos["favoreceu-tx-favorecido"] = relacionamentos["favoreceu-tx-favorecido"] | set([(id_transacao, favorecido.split(":")[0])])

        
for key, entidade in entidades.items():
    with open("ent_" + key + ".csv", "w") as file:
        print(key)
        file.write(key + "Id:ID(" + key.capitalize() + "),id_origem,desc,:LABEL\n")
        for row in entidade:
            fields = row.split(":")
            file.write(fields[0].replace(",","").replace(";","") + "," + 
                       fields[1].replace(",","").replace(";","") + "," +
                       fields[2].replace(",","").replace(";","") + "," + 
                       key.capitalize() + "\n")
            G.add_node(fields[0].replace(",","").replace(";",""),
                       id_origem=fields[1].replace(",","").replace(";",""),
                       desc=fields[2].replace(",","").replace(";",""),
                       grupo=key.capitalize())

with open("ent_transacoes.csv", "w") as file:
    file.write("transacaoId:ID(Tx),tipo,valor,:LABEL\n")
    for tx in transacoes:
        file.write(tx["id_transacao"] + "," + tx["tipo"] + "," + str(tx["valor"]).replace(",",".") + "," + "Tx\n")
        G.add_node(tx["id_transacao"], tipo=tx["tipo"], valor=float(str(tx["valor"]).replace(",",".")), grupo="Tx")

for key, rel in relacionamentos.items():
    key_fields = key.split("-")
    with open("rel_" + key_fields[0] + ".csv", "w") as file:
        file.write(":START_ID(" + key_fields[1].capitalize() + "),:END_ID(" + key_fields[2].capitalize() + ")\n")
        #file.write(":START_ID(" + key_fields[1].capitalize() + "-ID),:END_ID(" + key_fields[2].capitalize() + "-ID),:TYPE\n")
        for row in rel:
            #file.write(row[0] + "," + row[1] + "," + key_fields[0].upper() + "\n")
            file.write(row[0] + "," + row[1] + "\n")
            G.add_edge(row[0], row[1])

print(G.order())
print(G.size())
print(G.nodes["<KEY>"])

#clc = nx.closeness_centrality(G)<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup