In [89]:
from SPARQLWrapper import SPARQLWrapper, JSON
import time, numpy as n, networkx as x
Definição de prefixos úteis para as consultas SparQL:
In [90]:
PREFIX="""PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX ops: <http://purl.org/socialparticipation/ops#>
PREFIX opa: <http://purl.org/socialparticipation/opa#>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>
PREFIX dc: <http://purl.org/dc/terms/>
PREFIX tsioc: <http://rdfs.org/sioc/types#>
PREFIX sioc: <http://rdfs.org/sioc/ns#>
PREFIX schema: <http://schema.org/>"""
Buscando amizades do Participa.br:
In [91]:
NOW=time.time()
q="""SELECT DISTINCT ?aname ?bname
WHERE {
?a foaf:knows ?b .
?a foaf:name ?aname .
?b foaf:name ?bname .
}"""
sparql3 = SPARQLWrapper("http://localhost:82/participabr/query")
sparql3.setQuery(PREFIX+q)
sparql3.setReturnFormat(JSON)
results4 = sparql3.query().convert()
print("%.2f segundos para puxar todas as amizades do Participa.br"%
(time.time()-NOW,))
Erigindo rede de amizades como um grafo não direcionado:
In [92]:
g=x.Graph()
for amizade in results4["results"]["bindings"]:
nome1=amizade["aname"]["value"]
nome2=amizade["bname"]["value"]
g.add_edge(nome1,nome2)
In [93]:
print(u"são %i amizades entre %i pessoas no Participa.br"%
(g.number_of_edges(), g.number_of_nodes()))
In [146]:
x.write_graphml(g,"amizadesParticipa.graphml")
x.write_gml(g,"amizadesParticipa.gml")
Para visualizar e analisar, a estrutura de amizades está pronta neste link: https://github.com/ttm/pnud3/blob/master/amizadesParticipa.graphml.
Usos são imediatos, p.ex:
In [94]:
x.draw(g,pos=x.layout.fruchterman_reingold_layout(g))
Puxando as interações de comentários do Participa.br:
In [95]:
NOW=time.time()
q2="""SELECT DISTINCT ?aname ?bname
WHERE {
?comentario dc:type tsioc:Comment.
?participante1 ops:performsParticipation ?comentario.
?participante1 foaf:name ?aname.
?artigo sioc:has_reply ?comentario.
?participante2 ops:performsParticipation ?artigo.
?participante2 foaf:name ?bname.
}"""
sparql3.setQuery(PREFIX+q2)
sparql3.setReturnFormat(JSON)
results = sparql3.query().convert()
print("%.2f segundos para puxar as interações do Participa.br"%
(time.time()-NOW,))
Sintetizando rede direcionada de interação:
In [96]:
d=x.DiGraph()
for interacao in results["results"]["bindings"]:
nome_chegada=interacao["aname"]["value"]
nome_partida=interacao["bname"]["value"]
if (nome_partida,nome_chegada) in d.edges():
d[nome_partida][nome_chegada]["weight"]+=1
else:
d.add_edge(nome_partida,nome_chegada,weight=1.)
In [147]:
x.write_graphml(d,"interacoesParticipa.graphml")
x.write_gml(d,"interacoesParticipa.gml")
Estrutura de interação pronta para análises e visualizações neste link: https://github.com/ttm/pnud3/blob/master/interacoesParticipa.graphml.
In [97]:
x.draw(d,pos=x.layout.fruchterman_reingold_layout(d))
In [143]:
import operator
sorted_d = sorted(d.degree().iteritems(), key=operator.itemgetter(1))
sorted_d[::-1][:15]
Out[143]:
Elencando as 15 pessoas mais conectadas via amizades:
In [100]:
sorted_g = sorted(g.degree().iteritems(), key=operator.itemgetter(1))
sorted_g[::-1][:15]
Out[100]:
Para medida de centralidade, as listagens acima usam quantidade de conexão, ou grau.
Medidas de interesse imediato são: de atravessador (presente em mais geodésicas do grafo, betweenness), de mais "perto de todos os outros" (closeness) e de auto-vetor:
In [105]:
bc=x.betweenness_centrality(g)
cc=x.closeness_centrality(g)
In [106]:
sorted_bc = sorted(bc.iteritems(), key=operator.itemgetter(1))
sorted_bc[::-1][:15]
Out[106]:
In [107]:
sorted_cc = sorted(cc.iteritems(), key=operator.itemgetter(1))
sorted_cc[::-1][:15]
Out[107]:
Para as redes de interação:
In [108]:
bcd=x.betweenness_centrality(d)
ccd=x.closeness_centrality(d)
In [109]:
sorted_bcd = sorted(bcd.iteritems(), key=operator.itemgetter(1))
sorted_bcd[::-1][:15]
Out[109]:
In [110]:
sorted_ccd = sorted(ccd.iteritems(), key=operator.itemgetter(1))
sorted_ccd[::-1][:15]
Out[110]:
Na caracterização qualitativa das redes livres de escala, há uma distinção que salta aos olhos: uma multidão de vértices pouco conectados (periféricos), pouquíssimos vértices muito conectados (hubs), e alguns intermediários (intermediários mesmo).
Esta divisão é usualmente concebida na proporção 5% hubs, 15% intermediários e 80% periféricos.
In [144]:
hi=int(len(sorted_g)*0.05)
ii=int(len(sorted_g)*0.15)
pi=int(len(sorted_g)*0.80)
sorted_g_=sorted_g[::-1]
hubs=sorted_g_[:hi]
intermediarios=sorted_g_[hi:ii]
perifericos=sorted_g_[ii:]
In [117]:
hubs
Out[117]:
Descomentar para acessar participantes nos setores:
In [ ]:
# intermediarios
# perifericos
E para a rede de interação:
In [123]:
hi=int(len(sorted_d)*0.05)
ii=int(len(sorted_d)*0.15)
pi=int(len(sorted_d)*0.80)
sorted_d_=sorted_d[::-1]
hubs_d=sorted_d_[:hi]
intermediarios_d=sorted_d_[hi:ii]
perifericos_d=sorted_d_[ii:]
In [125]:
hubs_d
# intermediarios_d
# perifericos_d
Out[125]:
Há correlação com a atividade de cada participante, principalmente na rede de interação.
Além disso, é recomendada a comparação com a rede de Erdös-Renyi com o mesmo número de vértices e arestas, como feito neste trabalho: http://sourceforge.net/p/labmacambira/fimDoMundo/ci/master/tree/textos/evolutionSN/paper.pdf?format=raw.
In [145]:
[aa for aa in x.community.k_clique_communities(g,5)]
Out[145]:
As comunidades acima foram definidas pelo número de amizades mínimo em comum no grupo. Há bons métodos espectrais (Newman) e iterativos.