Manipulando Dados com Grafos


Bernardo Fontes


São Paulo/SP

13 de Dezembro de 2018

Só para dizer um oi!

Berin =]

berinfontes.com

twitter.com/bbfontes

github.com/berinhard

bernardoxhc@gmail.com

## WARNING! - ### O Teoria de Grafos é uma **área inteira** em Ciência da Computação - ### Veremos algumas partes dela nessa palestra para avaliarmos a **utilidade** do tema - ### Encorajo muito a buscarem mais informações e trocarmos ideia depois da palestra
## Roteiro - O que são grafos? - Possíveis análises - Persistindo no banco - Exemplos no mundo real
## O que são grafos? - Estrutura composta por **nós e arestas** - **Nós** possuem dados - **Arestas** definem relações entre os nós - As relações são entidades, ou seja, podem **possuir dados** também

Exemplo clássico

## Quando usar grafos? - Quando o *domínio do problema* e/ou *entendimento dos dados* é muito mais atrelado a **como as entidades se relacionam** do que com suas mudanças de estado

Exemplo mais real

## Quais tecnologias usar? - Análise: Python + **networkx** - Persistência: Neo4j
## Possíveis análises - Centralidades - Clusterização - Percursos no grafo - Padrões estruturais da rede - E por aí vai...
## Centralidades - Degree - Closeness - Betweenness - Eigenvector - Existem outras

Nosso grafo

## Input de texto ``` sq ml mj mq lk lj ... ```
## Criando o grafo ```python import networkx as nx def get_graph(): graph = nx.Graph() with open('links.txt', 'r') as fd: lines = fd.readlines() for line in lines: node_1, node_2 = line.strip() graph.add_edge(node_1, node_2) return graph ```
## Degree centrality - Centralidade baseada diretamente no número de arestas de um nó
## Degree centrality ```python g = get_graph() centralities = nx.degree_centrality(g) centralities = sorted(centralities.items(), key=lambda x: x[1], reverse=True) for node, value in centralities: print('{} - {}'.format(node, value)) ```
## Degree centrality - Resultado ``` j - 0.3684210526315789 d - 0.3157894736842105 h - 0.2631578947368421 g - 0.2631578947368421 p - 0.21052631578947367 i - 0.21052631578947367 f - 0.21052631578947367 b - 0.21052631578947367 m - 0.15789473684210525 l - 0.15789473684210525 k - 0.15789473684210525 n - 0.15789473684210525 a - 0.15789473684210525 e - 0.15789473684210525 q - 0.10526315789473684 o - 0.10526315789473684 c - 0.10526315789473684 s - 0.05263157894736842 t - 0.05263157894736842 r - 0.05263157894736842 ```

Degree centrality - Resultado

Útil para análises quantitativas totais

## Closeness centrality - Centralidade baseada na distância entre os nós
## Closeness centrality ```python g = get_graph() centralities = nx.closeness_centrality(g) centralities = sorted(centralities.items(), key=lambda x: x[1], reverse=True) for node, value in centralities: print('{} - {}'.format(node, value)) ```
## Closeness centrality - Resultado ``` i - 0.4634146341463415 h - 0.4418604651162791 j - 0.4318181818181818 p - 0.3877551020408163 n - 0.37254901960784315 g - 0.3584905660377358 f - 0.35185185185185186 c - 0.3392857142857143 m - 0.3333333333333333 l - 0.3275862068965517 k - 0.3220338983050847 o - 0.3114754098360656 r - 0.3114754098360656 d - 0.296875 b - 0.2878787878787879 t - 0.2835820895522388 a - 0.2835820895522388 e - 0.2835820895522388 q - 0.2602739726027397 s - 0.2087912087912088 ```

Closeness centrality - Resultado

Útil para análises com o objetivo de otimizar propagações

## Betweenness centrality - Centralidade baseada em caminhos ao qual o nó pertence como intermediário
## Betweenness centrality ```python g = get_graph() centralities = nx.betweenness_centrality(g) centralities = sorted(centralities.items(), key=lambda x: x[1], reverse=True) for node, value in centralities: print('{} - {}'.format(node, value)) ```
## Betweenness centrality - Resultado ``` h - 0.5614035087719298 i - 0.5321637426900585 j - 0.41812865497076024 m - 0.19883040935672514 g - 0.18226120857699804 p - 0.13450292397660818 q - 0.10526315789473684 f - 0.1033138401559454 d - 0.03313840155945419 n - 0.029239766081871343 c - 0.025341130604288498 l - 0.008771929824561403 k - 0.005847953216374269 b - 0.004873294346978557 a - 0.001949317738791423 s - 0.0 t - 0.0 o - 0.0 r - 0.0 e - 0.0 ```

Betweenness centrality - Resultado

Útil para identificações pontos de entradas de clusters

## Eigenvector centrality - Centralidade baseada na influência de um nó na rede (topologia)
## Eigenvector centrality ```python g = get_graph() centralities = nx.eigenvector_centrality(g, max_iters=1000) centralities = sorted(centralities.items(), key=lambda x: x[1], reverse=True) for node, value in centralities: print('{} - {}'.format(node, value)) ```
## Eigenvector centrality - Resultado ``` d - 0.4624402711011163 g - 0.426845473522682 b - 0.3581392113941398 f - 0.3534627131011391 e - 0.30255496341693877 a - 0.2847564509725969 h - 0.28327303565327666 c - 0.18086819094144457 i - 0.1380402866193515 j - 0.12545874636983892 p - 0.08464539539539807 n - 0.07574895588735901 r - 0.06870626212854221 k - 0.06495072621439604 l - 0.05767676369108016 o - 0.04880319165681279 m - 0.0473817168614392 t - 0.020530832833996485 q - 0.012210983147939322 s - 0.0029618234810396492 ```

Eigenvector centrality - Resultado

Versões iniciais do PageRank do Google

## Persistência - Neo4j - BD Orientado a Grafos escrito em **Java** - **Cypher** query language == SQL do Neo4j - **Bolt** é o protocolo de comunicação utilizado - Módulo **py2neo** para comunicação com o banco

Interface web

Voltando ao nosso exemplo

Recuperando o grafo de pessoas via Cypher

            
              MATCH
                p=(:Person)-[]->(:Person)
              RETURN p;
            
          

Grafo de pessoas que trabalham juntas

            
              MATCH
                p=(:Person)-[:TRABALHA_COM]-(:Person)
              RETURN p;
            
          

Grafo das pessoas que moram em SP

            
              MATCH
                p=(:Person)-[]->(state:Estado)
              WHERE
                state.Name='SP'
              RETURN p;
            
          

Grafo das pessoas amigas de pessoas que moram no RJ

            
              MATCH
                p=(:Person)-[:AMIGO]-(:Person)-[:VIVE_EM]-(state:Estado)
              WHERE
                state.Name='RJ'
              RETURN p;
            
          

Exemplo real: Brasil.io

Exemplo real: Jazz anos 60

Exemplo real: Jazz anos 60

Grafos e uma Análise Matemática do Jazz nos anos 60

## Conclusões - O módulo do **networkx** já tem 99% do que você precisa - NoSQL **não** é uma estratégia para todos os problemas - Saiba quais **perguntas** fazer e quais **métricas** as respondem - Não confie em apenas uma métrica

Obrigado!


Bernardo Fontes (Berin)


berinfontes.com

twitter.com/bbfontes

github.com/berinhard

bernardoxhc@gmail.com