The following example gives different results obtained with eigenvector_centrality and eigenvector_centrality_numpy. Is there a way to make such calculation more robust? I'm using networkx 2.4, numpy 1.18.5 and scipy 1.5.0.
import numpy as np
import networkx as nx
AdjacencyMatrix = {
0: {
1: 0.6,
},
1: {
2: 0,
3: 0,
},
2: {
4: 0.5,
5: 0.5,
},
3: {
6: 0.5,
7: 0.5,
8: 0.5,
},
4: {},
5: {},
6: {},
7: {},
8: {},
}
G = nx.DiGraph()
for nodeID in AdjacencyMatrix.keys():
G.add_node(nodeID)
for k1 in AdjacencyMatrix.keys():
for k2 in AdjacencyMatrix[k1]:
weight = AdjacencyMatrix[k1][k2]
split_factor = len(AdjacencyMatrix[k1])
G.add_edge(k1, k2, weight=weight / split_factor, reciprocal=1.0 / (split_factor * weight) if weight != 0 else np.inf)
eigenvector_centrality = {v[0]: v[1] for v in sorted(nx.eigenvector_centrality(G.reverse() if G.is_directed() else G, max_iter=10000, weight="weight").items(), key=lambda x: x[1], reverse=True)}
print(eigenvector_centrality)
eigenvector_centrality_numpy = {v[0]: v[1] for v in sorted(nx.eigenvector_centrality_numpy(G.reverse() if G.is_directed() else G, max_iter=10000, weight="weight").items(), key=lambda x: x[1], reverse=True)}
print(eigenvector_centrality_numpy)
Here's my output:
{0: 0.6468489798823026, 3: 0.5392481399595738, 2: 0.5392481399595732, 1: 0.0012439403459275048, 4: 0.0012439403459275048, 5: 0.0012439403459275048, 6: 0.0012439403459275048, 7: 0.0012439403459275048, 8: 0.0012439403459275048}
{3: 0.9637027924175013, 0: 0.0031436862826891288, 6: 9.593026373266866e-11, 8: 3.5132785569658154e-11, 4: 1.2627565659784068e-11, 1: 9.433263632036004e-14, 7: -2.6958851817582286e-11, 5: -3.185304797703736e-11, 2: -0.26695888283266833}
edit - see the response by dshult. He's one of the main people who maintains/updates networkx.
I think this may be a bug, but not the way you think. This graph is directed and acyclic. So for this graph, I don't think there is a nonzero eigenvalue.
It looks like the algorithm seems to implicitly assume an undirected graph, or at least that if it's directed it has cycles. And I would expect the algorithm to break if there's no cycle.
I'm going to encourage the networkx people to look at this in more detail.
I'm actually surprised that it converges for the non-numpy version.
Joel is right to say that eigenvector_centrality isn't a useful measure for directed acyclic graphs. See this nice description of centrality. This should be useless for both the numpy and non-numpy versions of the code.
Related
Say, a dictionary is provided with certain values.
How to find the highest number ?
Input
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 5
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 5
l1 = list(td.values())
Based on vector value, it should print output.
vector is 5, so sum of the dict-values to form vector is 3,1,1
Corresponding keys are 5,4,1
so, the output should be 541 but slight change here.
Since value '1' is associated with multiple keys, it should pick up highest key,
so, output should be 544 instead of 541 (For above input, to brief about combinations without considering '1+1+1+1+1' to '44444')
Another example
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 7
Possible combinations:
3 # --> Key of 7
21 # --> Key of 6 & 1 (6+1 = 7)
24 # --> Key of 6 & 1 (6+1 = 7)
12 # --> Key of 1 & 6 (1+6 = 7)
42 # --> Key of 1 & 6 (1+6 = 7)
Output : 42 (Highest number)
Another
d1 = {1:9,2:4,3:2,4:2,5:6,6:3,7:2,8:2,9:1}
vector = 5
here, it would be 1+2+2 (988).
But, '1' can also be added 5 times to form vector 5,
which would be '99999'
Since #Patrick Artner requested for minimal reproducible example, posting this though doesn't work as expected.
from itertools import combinations
def find_sum_with_index(l1, vector):
index_vals = [iv for iv in enumerate(l1) if iv[1] < target]
for r in range(1, len(index_vals) + 1):
for perm in combinations(index_vals, r):
if sum([p[1] for p in perm]) == target:
yield perm
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector=5
l1=list(d1.values())
for match in find_sum_with_index(l1, vector):
print(dict(match))
Is there any specific algorithm to be chosen for these kind of stuffs ?
Similar to the other answer but allowing repeatedly using the same keys to get the max number of keys which values sum up to vector:
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 7
#create a dict that contains value -> max-key for that value
d2 = {}
for k,v in d1.items():
d2[v] = max(d2.get(v,-1), k)
def mod_powerset(iterable,l):
# uses combinations_with_replacement to allow multiple usages of one value
from itertools import chain, combinations_with_replacement
s = list(set(iterable))
return chain.from_iterable(combinations_with_replacement(s, r) for r in range(l))
# create all combinations that sum to vector
p = [ s for s in mod_powerset(d1.values(),vector//min(d1.values())+1) if sum(s) == vector]
print(p)
# sort combinations by length then value descending and take the max one
mp = max( (sorted(y, reverse=True) for y in p), key=lambda x: (len(x),x))
# get the correct keys to be used from d2 dict
rv = [d2[num] for num in mp]
# sort by values, biggest first
rv.sort(reverse=True)
# solution
print(''.join(map(str,rv)))
Original powerset - see itertools-recipes.
There are some steps involved, see documentation in comments in code:
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 7
# create a dict that contains value -> sorted key-list, used to get final keys
from collections import defaultdict
d2 = defaultdict(list)
for k,v in d1.items():
d2[v].append(k)
for k,v in d2.items():
d2[k] = sorted(v, reverse=True)
from itertools import chain, combinations
def powerset(iterable):
"see itertools: powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
# create all combinations that sum to vector
p = [ s for s in powerset(d1.values()) if sum(s) == vector]
# sort combinations by length then value descending and take the max one
mp = max( (sorted(y, reverse=True) for y in p), key=lambda x: (len(x),x))
# get the correct keys to be used from d2 dict
rv = []
for num in mp:
rv.append(d2[num][0])
# remove used key from list
d2[num][:] = d2[num][1:]
# sort by values, biggest first
rv.sort(reverse=True)
# solution
print(''.join(map(str,rv)))
For powerset - see itertools-recipes.
first time i post question on stack ! I'd like to go straight into my problem !
Line 114 : error list indices must be integers or slices, not dict
This line got error(I bolded the full code below) :
if dist[c]>=dist[v]+dataAry[v][c]:
I just need give some solutions for this error, the majority of code worked as i wish, so i have to write some more sentences that stack allow me to post
dataJustified="{:>3}"
dataAry = {
0: [{1: 5}, {2: 4}, {5: 5}],
1: [{3: 3}],
2: [{7: 6}],
3: [{8: 8}],
4: [{8: 4}],
5: [{4: 2}, {6: 4}, {9: 3}],
6: [{7: 7}, {10: 5}],
7: [],
8: [{9: 7}],
9: [],
10: [],
}
print("Display Dijkstra's algorithm Shortest Path")
dist=[]
prev=[]
s=0
v=0
vl=[]
for c in range(len(dataAry)):
if c==0:
dist.append(0)
prev.append(-1)
else:
dist.append(999)
prev.append(0)
while len(vl)!=len(dataAry)-1:
vl.append(v)
u=[]
del u[:]
for index in dataAry[v]:
u.append(index)
for c in u:
if dist[c]>=dist[v]+dataAry[v][c]:
dist[c]=dist[v]+dataAry[v][c]
prev[c]=v
new_dist = dist[:]
for x in vl:
new_dist.remove(dist[x])
minV = min(new_dist)
if dist.index(minV) not in vl:
v = dist.index(minV)
else:
new_dist_2 = dist[:]
new_dist_2[dist.index(minV)] = 999
v = new_dist_2.index(minV)
print("dist : ", dist)
print("prev : ", prev)
Basically, I am trying to extract the values from one dictionary and update the value in another dictionary. I have four lists as follows:
a = [1,1,2,3,4,5]
b = [0,3,0,5,6,0]
c = [2,3,4,5,6,5]
d = [20,30,40,50,60,70]
So I use a defaultdict to store key,value pairs for a,b like:
one = defaultdict(list)
for k, v in zip(a, b):
one[k].append(v)
two = defaultdict(list)
for k, v in zip(c, d):
two[k].append(v)
Essentially, b is linked to c so I am trying to extract the values in the two dictionary and then update
the values in the one dictionary
So in the end one would look like {1: 30, 3: 50, 4: 60}
This is my code:
three = defaultdict(list)
for k, v in one.items():
if v in two.keys():
newvalue = two[v].values()
three[k].append(newvalue)
But I am now getting an error at line if v in two.keys(): as unhashable type: 'list'. I'm so lost, all
I want to do is use the values from one dictionary and then use those values to find the keys (which are the values
from the other table) and then get those corressponding values.
You are creating a dictionary of list in the beginning:
one = defaultdict(list)
for k, v in zip(a, b):
one[k].append(v)
[output] : defaultdict(list, {1: [0, 3], 2: [0], 3: [5], 4: [6], 5: [0]})
two = defaultdict(list)
for k, v in zip(c, d):
two[k].append(v)
[output] : defaultdict(list, {2: [20], 3: [30], 4: [40], 5: [50, 70], 6: [60]})
Therefore when calling k,v in one.items(), you are getting a key and a list.
Simply switch to iterate through the list , and you should be good to go
three = defaultdict(list)
for k, v in one.items():
for value in v:
if value in two.keys():
newvalue = two[value]
three[k].append(newvalue)
However I'm getting this output :
defaultdict(list, {1: [[30]], 3: [[50, 70]], 4: [[60]]})
Which sounds reasonable to me, but it is not your expected one, can you please explain ?
Let's try know with dic comprehension
output = { k : two[v_2] for k,v in one.items() for v_2 in v}
[output] : {1: [30], 2: [], 3: [50, 70], 4: [60], 5: []}
Request to sum :
Of course, multiple ways of doing it , the quickest is again with dict_comprehension and sum
output_sum = {k: sum(v) for k,v in output.items()}
I'm here trying to share my depth first-search (DFS) implementation. I'm trying to learn how can it traverse in a graph that is undirected, meaning that not all nodes are making into one graph, but two different ones. I was looking for the small basics of DFS with one graph only. And I came across to a problem in "what would happen if there are more than one graph and are not connected?" So I started to look around how to do it by using my knowledge from the simple DFS implementation. However, it is a little bit more complicated than I thought. Here is the code sample that I came across:
"""DFS implemention."""
adjacency_matrix = {
1: [2, 3],
2: [4, 5],
3: [5],
4: [6],
5: [6],
6: [7],
7: [],
8: [9],
9: [8]
}
def DFS_un(graph):
"""Traversal for undirected graphs."""
vertices = graph[0]
edges = graph[1]
def visit(vertex):
if vertex in visited:
return
visited.add(vertex)
print(vertex)
if vertex in edges:
for e in edges[vertex]:
visit(e)
visited = {}
for v in vertices:
visit(v)
if __name__ == '__main__':
DFS_un(adjacency_matrix)
And the error message says this:
Traceback (most recent call last):
File "dfs.py", line 33, in <module>
DFS_dis(adjacency_matrix)
File "dfs.py", line 17, in DFS_dis
vertices = graph[0]
KeyError: 0
If you see, I'm using one graph, but it has undirected numbers, which is 8 and 9 (8<->9). Why am I not getting my output correctly? Sorry, learning some Python3 too :). Thanks for your help!
You want:
vertices = graph.keys()
edges = graph.values()
'Graph' is a dictionary object. The graph[0] notation says find me the value associated with the key=0. Since you have no key=0 you get an error.
You might be confusing dictionaries with lists. my_list[0] says get me the value at position 0 in my_list.
I found my problem already. #blueenvelope was right with the idea of the dictionary because there are no KeyWords used and thus giving me 0 for some reason... At the end, it finally reads the whole graph list from unconnected vertices.
My variables vertices and edges were incorrectly implemented and quickly understood it's purpose. Keys is used to find particular dictionaries, so I was pulling keys from the graph vertex. Same goes for my edges, but also pulling the values of those edges from a specific key. Here is the full fixed code:
adjacency_matrix = {
1: [2, 3],
2: [4, 5],
3: [5],
4: [6],
5: [6],
6: [7],
7: [],
8: [9],
9: [8]
}
def DFS_un(graph):
"""Traversal for undirected graphs."""
vertices = graph.keys()
edges = graph.values()
visited = []
def visit(vertex):
if vertex in visited:
return
print("Visited vertex: ")
visited.append(vertex)
print(visited)
print("Current vertex: ")
print(vertex)
print("\n")
if vertex in edges:
for e in edges[vertex]:
visit(e)
for v in vertices:
visit(v)
if __name__ == '__main__':
DFS_un(adjacency_matrix)
I'm trying to update a set of nodes with their positions (coordinates) using Python.
n = 5 #number of current nodes
vertices = []
vertices=list(range(n)) # list of vertices=[0,1,2,3,4]
I'm creating a random set of points as follows for each element in vertices:
pos = {i:(random.randint(0,50),random.randint(0,50)) for i in vertices}
Also, I have another list(called "s") with some coordinates and I'm enumerating those elements in "s" to add an index(to continue with indices in "vertices") to each coordinate in "s".
for index, i in enumerate(s , vertices[-1]+1):
print(index, i)
Then, I'm getting my output as
5 (29.5, 34.0)
6 (20.0, 25.75)
7 (23.75, 36.0)
Now I need to update my set "pos" with these points and their corresponding indices. How can I do that?
You can assign like this while iterating itself instead of just printing
for index, i in enumerate(s, vertices[-1] + 1):
pos[index] = i
And finally, the pos will be something like
{0: (0, 10), 1: (16, 33), 2: (17, 36), 3: (40, 13), 4: (26, 39), 5: (29.5, 34.0), 6: (20.0, 25.75), 7: (23.75, 36.0)}