4

I am graphing a tree in networkx, and have added percentage shares as weights. Example: shops and owners of the shops, which can be another shop:

import pandas as pd
data = pd.DataFrame({'shop': ['S1', 'S1', 'S1', 'S2', 'S2', 'S3', 'S3', 'S3'],
                     'owner': ['O1', 'O2', 'S2', 'S3', 'O3', 'O4', 'O5', 'O6'],
                     'share': [0.2, 0.2, 0.6, 0.5, 0.5, 0.1, 0.1, 0.8]})
data

 shop   owner   share
 S1      O1     0.2
 S1      O2     0.2
 S1      S2     0.6
 S2      S3     0.5
 S2      O3     0.5
 S3      O4     0.1
 S3      O5     0.1
 S3      O6     0.8

I can create a directed graph in networkx like this:

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

And graph the result:

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

How would I multiply the weights for each shop in the graph such that I have the owner and the percentage share? Something like the following:

output = pd.DataFrame({'shop': ['S1', 'S1', 'S1', 'S1', 'S1', 'S1', 'S2', 
                                'S2', 'S2','S2', 'S3', 'S3', 'S3'],
                      'owner': ['O1', 'O2', 'O3', 'O4', 'O5', 'O6', 'O3', 
                                'O4', 'O5','O6', 'O4', 'O5', 'O6'],
                      'share': [0.2, 0.2, 0.3, 0.03, 0.03, 0.24, 0.5, 0.05, 
                                0.05, 0.4, 0.1, 0.1, 0.8]})

output

shop    owner   share
 S1     O1      0.2
 S1     O2      0.2
 S1     O3      0.3
 S1     O4      0.03
 S1     O5      0.03
 S1     O6      0.24
 S2     O3      0.5
 S2     O4      0.05
 S2     O5      0.05
 S2     O6      0.4
 S3     O4      0.1
 S3     O5      0.1
 S3     O6      0.8

Update: thanks to this question here I can get the product (multiplied weights) between any 2 chosen nodes (see below) How do I then get the same for all nodes in a data frame as above?

start = 'S1' # start node
end = 'O5'   # end node

all_paths = [path for path in nx.all_simple_paths(G, start, end)]

for p in all_paths:                          # keep track of each path
    for _ in range(len(p)):                 # for each node in this path
        pairs = zip(p, p[1:])                    # get sequence of nodes
        product = 1                              
        for pair in pairs:             # for each pair of nodes in this path
            an_edge = G.get_edge_data(pair[0], pair[1])                
            product *= an_edge['share'] 
prmlmu
  • 643
  • 1
  • 8
  • 16

1 Answers1

1

Edit: misunderstood the question. Here is a possible answer:

owners = set(data['owner'])
shops  = set(data['shop'])
summary = {}
for owner in owners:
    for shop in shops:
        paths = list(nx.all_simple_paths(G, shop, owner))
        if len(paths):
            for path in paths:
                for start, end in zip(path[:-1], path[1:]):
                    summary[(shop, owner)] = summary.get((shop,owner), 1) * G[start][end]['share']

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

Output:

           share
(S2, O4)   0.05
(S3, O4)   0.10
(S1, O4)   0.03
(S2, O6)   0.40
(S3, O6)   0.80
(S1, O6)   0.24
(S2, O5)   0.05
(S3, O5)   0.10
(S1, O5)   0.03
(S1, O2)   0.20
(S2, S3)   0.50
(S1, S3)   0.30
(S1, S2)   0.60
(S2, O3)   0.50
(S1, O3)   0.30
(S1, O1)   0.20
cvanelteren
  • 1,633
  • 9
  • 16
  • I want to multiply the weights I've assigned so I can get an overall share of how much an owner has of a shop. I want to do it for all pairs to produce the second data frame I provided. Your answer doesn't multiply through the weights – prmlmu Dec 10 '18 at 15:00
  • nvm it see your issue now momentito – cvanelteren Dec 10 '18 at 15:05
  • actually I just noticed maybe pd.Series is a better fit than DataFrame. I don't use pandas that often but at least the data should be correct – cvanelteren Dec 10 '18 at 16:01