import networkx as nx
import networkx.convert_matrix as nxm
import pandas as pd
dati = pd.read_csv (r'from_to.csv')
print (dati)
info = pd.read_csv (r'info.csv')
print (info)
df = dati.pivot_table(index=['From','To'], values=['To'], aggfunc=['count'])
print (df)
G = nx.DiGraph()
#aggiungere nodi
for i in range(len(info['Node'])):
G.add_node(info['Node'][i])
#aggiungere edge
for i in range(len(df.index)):
G.add_edge(df.index[i][0], df.index[i][1],weight=df.ix[df.index[i]][0])
# aggiungere attributi
nx.set_node_attributes(G, info['Age'], 'Age')
nx.set_node_attributes(G, info['Department'], 'Department')
nx.set_node_attributes(G, info['Job'], 'Job')
print(G)
density = nx.density(G)
print("Network density:", density)
A_B_path = nx.shortest_path(G, source="A", target="B")
print("Shortest path between A and B:", A_B_path)
print("Length of that path:", len(A_B_path)-1)
triadic_closure = nx.transitivity(G)
print("Triadic closure:", triadic_closure)
La misura più semplice di centralità in un social network è il grado. Esso è il modo più semplice e più comune di trovare nodi importanti. Il grado di un nodo è la somma dei bordi. Se, ad esempio, un nodo ha tre linee che si estendono da esso ad altri nodi, il suo grado è tre.
Esistono due tipi di centralità dei gradi: indegree e outdegree.
degree_centrality(G) Compute the degree centrality for nodes.
in_degree_centrality(G) Compute the in-degree centrality for nodes.
out_degree_centrality(G) Compute the out-degree centrality for nodes.
degree_dict = dict(G.degree(G.nodes()))
print(degree_dict)
nx.set_node_attributes(G, degree_dict, 'degree')
La seconda misura che tratteremo si chiama Closeness. Ci sono anche altri nomi per questo; a volte si chiama centralità dell'accesso. In poche parole, Closeness centrality cattura la distanza media dal nodo focale a tutti gli altri nodi del social network. La rappresentazione matematica della vicinanza è la seguente:
$$ l_i = \frac{1}{n-1} \sum_j d_{i,j} $$Stiamo provando a calcolare la vicinanza del nodo a tutti gli altri nodi della rete; quindi la Prossimità. Il numeratore è la somma di tutte le distanze a coppie tra il nodo i e tutti gli altri nodi j (escluso i). La somma delle distanze viene quindi divisa per il numero totale di nodi nella rete $n$ sottratto per 1 (per regolare il conteggio per escludere il nodo i). Ora abbiamo lontananza, che è la distanza media del nodo i da tutti gli altri nodi della rete. Prendere il reciproco ci rende vicini.
$$ C_i = \frac{1}{l_i} = \frac{n-1}{\sum_j d_{i,j}} $$closeness_dict = nx.closeness_centrality(G)
print(closeness_dict)
nx.set_node_attributes(G, closeness_dict, 'closeness')
E' forse una delle più potenti misure di centralità ed è strettamente correlata all'idea di buchi strutturali. La distanza intermedia può essere calcolata come:
$$b_i = \sum_{s, t} w_{s,t}^{i} = \sum_{s, t} \frac{n_{s,t}^{i}}{n_{s,t}} $$Betweenness è la misura con cui si capisce se un nodo funge da ponte tra altri nodi della rete. Viene calcolato osservando tutte le coppie di nodi nella rete ed esaminando la frequenza con cui i, il nodo focale, esiste sui percorsi più brevi tra i nodi j e k.
In termini piu semplici, è la misura in cui un nodo si trova su percorsi tra altri nodi. I nodi con un alto livello di intermittenza possono avere una notevole influenza all'interno di una rete in virtù del loro controllo sulle informazioni che passano tra gli altri. Sono anche quelli la cui rimozione dalla rete interromperà maggiormente le comunicazioni tra altri nodi perché si trovano sul maggior numero di percorsi seguiti dai messaggi.
betweenness_dict = nx.betweenness_centrality(G)
print(betweenness_dict)
nx.set_node_attributes(G, betweenness_dict, 'betweenness')
Una naturale estensione della centralità dei gradi è la centralità degli autovettori. La centralità in gradi conferisce un punto di centralità per ogni collegamento ricevuto da un nodo. Ma non tutti i vertici sono equivalenti: alcuni sono più rilevanti di altri e, ragionevolmente, le approvazioni da nodi importanti contano di più. La tesi di centralità dell'autovettore recita: Un nodo è importante se è collegato da altri nodi importanti. La centralità degli autovettori differisce dalla centralità in gradi: un nodo che riceve molti collegamenti non ha necessariamente una elevata centralità degli autovettori (è possibile che tutti i linker abbiano una centralità degli autovettori bassa o nulla). Inoltre, un nodo con elevata centralità di autovettore non è necessariamente fortemente collegato (il nodo potrebbe avere pochi ma importanti linker).
Sia $ A = (a_ {i, j}) $ la matrice di adiacenza di un grafico. La centralità dell'autovettore $ x_ {i} $ del nodo $ i $ è data da: $$ x_i = \frac {1} {\lambda} \sum_k a_ {k, i} \, x_k $$ dove $ \lambda \neq 0 $ è una costante. In forma di matrice abbiamo: $$ \lambda x = x A $$
Quindi il vettore di centralità $ x $ è l'autovettore sinistro della matrice di adiacenza $ A $ associato all'autovalore $ \lambda $. È saggio scegliere $ \lambda $ come autovalore più grande in valore assoluto della matrice $ A $. In virtù del teorema di Perron-Frobenius, questa scelta garantisce la seguente proprietà desiderabile: se la matrice $ A $ è irriducibile, o equivalentemente se il grafico è (fortemente) connesso, allora la soluzione di autovettore $ x $ è sia unica che positiva. Lascia che $ m (v) $ denoti la componente firmata della grandezza massima del vettore $ v $. Se esiste più di un componente massimo, lascia che $ m (v) $ sia il primo. Ad esempio, $ m (-3,3,2) = -3 $. Sia $ x ^ {(0)} $ un vettore arbitrario. Per $ k \geq 1 $: calcola ripetutamente $ x ^ {(k)} = x ^ {(k-1)} A $; normalizzare $ x ^ {(k)} = x ^ {(k)} / m (x ^ {(k)}) $; fino a raggiungere la precisione desiderata. Ne segue che $ x ^ {(k)} $ converge all'autovettore dominante di $ A $ e $ m (x ^ {(k)}) $ converge all'autovalore dominante di $ A $. Se la matrice $ A $ è scarsa, ogni prodotto a matrice vettoriale può essere eseguito in tempo lineare nella dimensione del grafico.
Il metodo converge quando gli autovalori dominanti (il più grande) e quelli sub-dominanti (il secondo più grande) di $ A $, rispettivamente indicati con $ \lambda_1 $ e $ \lambda_2 $, sono separati, ovvero sono diversi in valore assoluto, quindi quando $ | \lambda_1 | > | \lambda_2 | $. Il tasso di convergenza è il tasso al quale $ (\lambda_2 / \lambda_1) ^ k $ va a $ 0 $. Quindi, se l'autovalore secondario sub-dominante è piccolo rispetto a quello dominante, il metodo converge rapidamente.
eigenvector_dict = nx.eigenvector_centrality(G)
print(eigenvector_dict)
nx.set_node_attributes(G, eigenvector_dict, 'eigenvector')
edges = G.edges()
weights = [G[u][v]['weight'] for u,v in edges]
options = {
'node_size': 600,
'width': 1,
'arrowstyle': '-|>',
'arrowsize': 12,
}
nx.draw(G, widht=weights, arrows=True, node_shape='D',
with_labels=True,
edge_color='green',
node_color=range(len(G)), **options)