0

I previously asked a question about multiplying through weights in networkx to find an overall share of nodes in a directed graph. The solution provided works well if there is just one path between 2 nodes but fails if there is more than path. A simple example:

import pandas as pd
data = pd.DataFrame({'shop': ['S1', 'S1', 'S2', 'S2', 'S3'],
                     'owner': ['S2', 'S3', 'O1', 'O2', 'O1'],
                     'share': [0.8,   0.2,  0.5,  0.5, 1.0]})
  owner  shop  share
0    S2   S1    0.8
1    S3   S1    0.2
2    O1   S2    0.5
3    O2   S2    0.5
4    O1   S3    1.0

create the graph:

import networkx as nx    
G = nx.from_pandas_edgelist(data,'shop','owner',edge_attr = ('share'), 
                               create_using=nx.DiGraph())

pos=nx.spring_layout(G, k = 0.5, iterations = 20)
node_labels = {node:node for node in G.nodes()}
nx.draw_networkx(G, pos, labels = node_labels, arrowstyle = '-|>',
                 arrowsize = 20,  font_size = 15, font_weight = 'bold')

enter image description here

To get the share O1 has of S1, the 2 paths need to be multiplied and then added. The previous solution fails to do this. Is there a way of doing this?

1 Answer 1

1

You could modify the previous solution in the following way:

from operator import mul

import pandas as pd
import networkx as nx
from functools import reduce

data = pd.DataFrame({'shop': ['S1', 'S1', 'S2', 'S2', 'S3'],
                     'owner': ['S2', 'S3', 'O1', 'O2', 'O1'],
                     'share': [0.8,   0.2,  0.5,  0.5, 1.0]})

G = nx.from_pandas_edgelist(data,'shop','owner',edge_attr = ('share'),
                               create_using=nx.DiGraph())

owners = set(data['owner'])
shops  = set(data['shop'])


result = []
summary = {}
for shop in shops:
    for owner in owners:
        for path in nx.all_simple_paths(G, shop, owner):
            share = reduce(mul, (G[start][end]['share'] for start, end in zip(path[:-1], path[1:])), 1)
            summary[(owner, shop)] = summary.get((owner, shop), 0) + share


summary = pd.DataFrame.from_dict(summary, orient = 'index', columns = 'share'.split())
print(summary)

Output

          share
(O2, S2)    0.5
(O2, S1)    0.4
(S3, S1)    0.2
(O1, S2)    0.5
(O1, S3)    1.0
(O1, S1)    0.6
(S2, S1)    0.8

The line:

share = reduce(mul, (G[start][end]['share'] for start, end in zip(path[:-1], path[1:])), 1)

computes the share for a particular path. Then this share is aggregated over all paths using the next line:

summary[(owner, shop)] = summary.get((owner, shop), 0) + share
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.