Start off with a few simple worked examples based on JJ's Hypernetworks in the Science of Complex Systems.
#Use pandas and networkx
import pandas as pd
import networkx as nx
import numpy as np
import seaborn as sns
%matplotlib inline
Example from p.33.
# Create graph
B = nx.Graph()
B.add_edges_from([('a1','b1'),('a1','b2'), ('a1','b3'),
('a2','b2'),('a2','b3'), ('a2','b4'), ('a2','b5'), ('a2','b6'),
('a3','b5'),('a3','b6'), ('a3','b7'), ('a3','b8')])
#We can see the nodes in the gaph, and get index of a particular node in that list
B.nodes(), B.nodes().index('a2'), B.nodes(True)
(['b2', 'a2', 'b7', 'a1', 'b8', 'a3', 'b3', 'b5', 'b4', 'b6', 'b1'], 1, [('b2', {}), ('a2', {}), ('b7', {}), ('a1', {}), ('b8', {}), ('a3', {}), ('b3', {}), ('b5', {}), ('b4', {}), ('b6', {}), ('b1', {})])
# Bipartite graph has two non-intersecting sets of nodes
# Edges go from one set to another
X, Y = nx.bipartite.sets(B)
X, Y
({'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8'}, {'a1', 'a2', 'a3'})
# Simple chart of nodes
def bipartite_plot(B, X=None, Y=None):
if X is None and Y is None:
X, Y = nx.bipartite.sets(B)
#http://stackoverflow.com/a/27085151/454773
c = nx.bipartite.color(B)
nx.set_node_attributes(B, 'group', c)
pos = dict()
pos.update( (n, (1, i)) for i, n in enumerate(X) ) # put nodes from X at x=1
pos.update( (n, (2, i)) for i, n in enumerate(Y) ) # put nodes from Y at x=2
colors=[]
for i in B:
if B.node[i]['group']:
colors.append('lightblue')
else:
colors.append('pink')
nx.draw(B, pos=pos,with_labels = True,node_color=colors)
bipartite_plot(B, X, Y)
#Neighbours / hyperedges
B.neighbors('a1'), B.neighbors('b3')
(['b2', 'b3', 'b1'], ['a2', 'a1'])
#Is there a path connecting two nodes?
nx.has_path(B,'a1','a3')
True
nx.shortest_path(B,'a1','a3'), nx.shortest_path_length(B,'a1','a3')
(['a1', 'b2', 'a2', 'b5', 'a3'], 4)
for p in nx.all_simple_paths(B,'a1','a3'):
print(p)
['a1', 'b2', 'a2', 'b5', 'a3'] ['a1', 'b2', 'a2', 'b6', 'a3'] ['a1', 'b3', 'a2', 'b5', 'a3'] ['a1', 'b3', 'a2', 'b6', 'a3']
#Projections onto one set:
P1 = nx.bipartite.projected_graph(B, X)
nx.draw(P1,with_labels = True)
P2 = nx.bipartite.projected_graph(B, Y, multigraph=True)
#Simple plotter doesn't reflect multi-edges though...
nx.draw(P2,with_labels = True)
#We can also project onto a multigraph to see the separate means by which nodes are connected
P1= nx.bipartite.projected_graph(B, X, multigraph=True)
PN = P1 if 'b1' in P1 else P2
PN['b6'], [(k, list(PN['b6'][k].keys())) for k in PN['b6'].keys() ]
({'b2': {'a2': {}}, 'b3': {'a2': {}}, 'b4': {'a2': {}}, 'b5': {'a2': {}, 'a3': {}}, 'b7': {'a3': {}}, 'b8': {'a3': {}}}, [('b2', ['a2']), ('b3', ['a2']), ('b7', ['a3']), ('b8', ['a3']), ('b5', ['a2', 'a3']), ('b4', ['a2'])])
#Find nodes connected to a particular node via one or more in the other set
PN['b6'], list(PN['b6'].keys())
({'b2': {'a2': {}}, 'b3': {'a2': {}}, 'b4': {'a2': {}}, 'b5': {'a2': {}, 'a3': {}}, 'b7': {'a3': {}}, 'b8': {'a3': {}}}, ['b2', 'b3', 'b7', 'b8', 'b5', 'b4'])
#SparseDataFrame map from http://stackoverflow.com/a/17819427/454773
import numpy as np
def pretty_matrix(B, X=None, Y=None):
if X is None and Y is None:
X, Y = nx.bipartite.sets(B)
m=nx.adjacency_matrix(B)
df=pd.SparseDataFrame([ pd.SparseSeries(m[i].toarray().ravel())
for i in np.arange(m.shape[0]) ])
dfa=df[[B.nodes().index(x) for x in X ]]
dfa.columns=X
dfa=dfa.iloc[[B.nodes().index(y) for y in Y ]]
return dfa[sorted(dfa.columns)].rename({B.nodes().index(y):y for y in Y}).sort_index()
pretty_matrix(B)
b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | |
---|---|---|---|---|---|---|---|---|
a1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
a2 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
a3 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
def pretty_bipartite_matrix(B, X=None, Y=None):
if X is None and Y is None:
X, Y = nx.bipartite.sets(B)
#There is a nx.bipartite.biadjacency_matrix(B, Y, X) function, but I don't see how to match index and label?
m=nx.bipartite.biadjacency_matrix(B, Y, X)
m2=pd.SparseDataFrame([ pd.SparseSeries(m[i].toarray().ravel())
for i in np.arange(m.shape[0]) ])
#Is this guaranteed to work correctly with the orderings?
m2.columns=X
return m2[sorted(m2.columns)].rename({[c for c in Y].index(y):y for y in Y}).sort_index()
pretty_bipartite_matrix(B, X, Y)
b1 | b2 | b3 | b4 | b5 | b6 | b7 | b8 | |
---|---|---|---|---|---|---|---|---|
a1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
a2 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
a3 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
For example, p.34-36
Rsets= {'mouse':{'tiny','brown','quadruped','vegetarian'},
'hare':{'small','brown','quadruped','vegetarian'},
'deer':{'large','brown','quadruped','vegetarian','hooves','antlers'},
'camel':{'large','brown','quadruped','vegetarian','hooves','hump'},
'tiger':{'large','quadruped'},
'falcon':{'small'},
'chimpanzee':{'large','vegetarian'}
}
def bipartite_graphBuilder(R,B=None,undirected=True):
if B is None:
if undirected: B=nx.Graph()
else: B=nx.DiGraph()
for key in R:
for descriptor in R[key]:
B.add_edge(key,descriptor)
return B
B2=bipartite_graphBuilder(Rsets)
bipartite_plot(B2)
#If we ask about an item in one set, we get as dict keys the things it's connnected to in the other
B2['deer']
{'antlers': {}, 'brown': {}, 'hooves': {}, 'large': {}, 'quadruped': {}, 'vegetarian': {}}
# This means we can easily find intersecting connected properties of items in one set connected from the other
def R(B, keys):
setlist=[set(B[key].keys()) for key in keys]
return set.intersection(*setlist)
R(B2, ['hare','deer'])
{'brown', 'quadruped', 'vegetarian'}
R(B2, R(B2, ['hare','deer']) )
{'camel', 'deer', 'hare', 'mouse'}
R(B2, R(B2, {'hare','deer'}) )
{'camel', 'deer', 'hare', 'mouse'}
p. 36
#Galoir pairs
def GaloisPair(B,vals):
return (vals, R(B, vals))
GaloisPair(B2,{'brown','quadruped','vegetarian'})
({'brown', 'quadruped', 'vegetarian'}, {'camel', 'deer', 'hare', 'mouse'})
GaloisPair(B2,{'camel', 'deer', 'hare', 'mouse'})
({'camel', 'deer', 'hare', 'mouse'}, {'brown', 'quadruped', 'vegetarian'})
pretty_bipartite_matrix(B2)
camel | chimpanzee | deer | falcon | hare | mouse | tiger | |
---|---|---|---|---|---|---|---|
antlers | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
brown | 1 | 0 | 1 | 0 | 1 | 1 | 0 |
hooves | 1 | 0 | 1 | 0 | 0 | 0 | 0 |
hump | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
large | 1 | 1 | 1 | 0 | 0 | 0 | 1 |
quadruped | 1 | 0 | 1 | 0 | 1 | 1 | 1 |
small | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
tiny | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
vegetarian | 1 | 1 | 1 | 0 | 1 | 1 | 0 |
pp. 51-52
Qsets={
'Pete':{'gaming','pubs','cars','sport'},
'Sam':{'pubs','cars','sport','fashion'},
'Sue':{'fashion','painting','history','literature'},
'Jane':{'history','literature','gardening','cooking'},
'Tim':{'gardening','cooking','nature','science'}
}
QG=bipartite_graphBuilder(Qsets)
bipartite_plot(QG)
QG.neighbors('Pete')
['cars', 'gaming', 'sport', 'pubs']
nx.shortest_path(QG,'Pete','Sam')
['Pete', 'cars', 'Sam']
for p in nx.all_shortest_paths(QG,'Pete','Sam'):
print(p)
['Pete', 'cars', 'Sam'] ['Pete', 'sport', 'Sam'] ['Pete', 'pubs', 'Sam']
#Construct a function based on a literal interpretation of the graph
def Qnear(B,x,y):
#Treat returning -1 as an error code?
return len([e for e in nx.all_shortest_paths(QG,x,y) if len(e)==3])-1
Qnear(QG,'Pete','Sam')
2
Qnear(QG,'Sam','Sue'), Qnear(QG,'Sue','Jane'), Qnear(QG,'Jane','Tim')
(0, 1, 1)
#We can then look for Q-connected items - other than the singletons
import itertools
def componentFinder(setval):
#Make a graph from connected pairs then find components across the graph
T=nx.Graph()
sets=[]
for (x,y) in setval:
T.add_edge(x,y)
return [c for c in nx.connected_components(T)]
#This is not the same as in the example - the singletons (connected to themselves) are ignored
def Qconnected(B,N,X=None,anchor=None):
''' q-connected for q==N '''
def allcombos(B,X,N):
qconnectedN=[]
for (x,y) in itertools.combinations(X,2):
if Qnear(B,x,y)>=N:
qconnectedN.append((x,y))
return qconnectedN
setval=None
if X is None:
X, Y = nx.bipartite.sets(B)
if anchor is not None and anchor in Y:
setval=allcombos(B,Y,N)
else:
setval=allcombos(B,X,N)
return componentFinder(setval)
Qconnected(QG,1,anchor="Sam")
[{'Jane', 'Sue', 'Tim'}, {'Pete', 'Sam'}]
Qconnected(QG,0,anchor="Sam")
[{'Jane', 'Pete', 'Sam', 'Sue', 'Tim'}]
Qconnected(QG,2,anchor="Sam")
[{'Pete', 'Sam'}]
Qconnected(QG,3,anchor="Sam")
[]
We could hack the above to also return as single set items members in the superset that aren't already returned, but that's a fudge. So how can we do it properly?
p. 60-61 suggests a matrix calculation route.
We can get the same (I think?) if we use the bipartite "biadjency" matrix that describes adjacent (connected) nodes in the projected bipartite graph.
def nodematrix(B, anchor=None, X=None, Y=None):
if X is None and Y is None:
X, Y = nx.bipartite.sets(B)
if anchor is not None and anchor in X:
X,Y=Y,X
mxb=nx.bipartite.biadjacency_matrix(B, Y, X)
mx=mxb * mxb.T
m2=pd.SparseDataFrame([ pd.SparseSeries(mx[i].toarray().ravel())
for i in np.arange(mx.shape[0]) ])-1
m2.columns=Y
m2=m2[sorted(m2.columns)].rename({[c for c in Y].index(y):y for y in Y}).sort_index()
return m2.replace(-1, np.nan)
#This could be used to give us the singletons?
NM=nodematrix(QG,anchor="Sam")
NM
Jane | Pete | Sam | Sue | Tim | |
---|---|---|---|---|---|
Jane | 3.0 | NaN | NaN | 1.0 | 1.0 |
Pete | NaN | 3.0 | 2.0 | NaN | NaN |
Sam | NaN | 2.0 | 3.0 | 0.0 | NaN |
Sue | 1.0 | NaN | 0.0 | 3.0 | NaN |
Tim | 1.0 | NaN | NaN | NaN | 3.0 |
nodematrix(QG,anchor="cars")
cars | cooking | fashion | gaming | gardening | history | literature | nature | painting | pubs | science | sport | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
cars | 1.0 | NaN | 0.0 | 0.0 | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 |
cooking | NaN | 1.0 | NaN | NaN | 1.0 | 0.0 | 0.0 | 0.0 | NaN | NaN | 0.0 | NaN |
fashion | 0.0 | NaN | 1.0 | NaN | NaN | 0.0 | 0.0 | NaN | 0.0 | 0.0 | NaN | 0.0 |
gaming | 0.0 | NaN | NaN | 0.0 | NaN | NaN | NaN | NaN | NaN | 0.0 | NaN | 0.0 |
gardening | NaN | 1.0 | NaN | NaN | 1.0 | 0.0 | 0.0 | 0.0 | NaN | NaN | 0.0 | NaN |
history | NaN | 0.0 | 0.0 | NaN | 0.0 | 1.0 | 1.0 | NaN | 0.0 | NaN | NaN | NaN |
literature | NaN | 0.0 | 0.0 | NaN | 0.0 | 1.0 | 1.0 | NaN | 0.0 | NaN | NaN | NaN |
nature | NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | NaN |
painting | NaN | NaN | 0.0 | NaN | NaN | 0.0 | 0.0 | NaN | 0.0 | NaN | NaN | NaN |
pubs | 1.0 | NaN | 0.0 | 0.0 | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 |
science | NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | NaN |
sport | 1.0 | NaN | 0.0 | 0.0 | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 1.0 |
def anotherQnear(NM,x,y):
return NM.ix[x][y]
anotherQnear(NM,'Sam','Pete')
2.0
anotherQnear(NM,'Sam','Sam')
3.0
def anotherQconnected(NM,N,X=None,anchor=None):
''' q-connected for q==N '''
def allcombosDiag(NM,X,N):
qconnectedN=[]
combos=[x for x in itertools.combinations(X,2)]+[(x,x) for x in X]
for (x,y) in combos:
if anotherQnear(NM,x,y)>=N:
qconnectedN.append((x,y))
return qconnectedN
setval=None
if X is None:
X = list(NM.columns)
if anchor is not None and anchor in Y:
setval=allcombosDiag(NM,Y,N)
else:
setval=allcombosDiag(NM,X,N)
return componentFinder(setval)
anotherQconnected(NM,2,anchor='Sam')
[{'Sue'}, {'Pete', 'Sam'}, {'Jane'}, {'Tim'}]
anotherQconnected(NM,3,anchor='Sam')
[{'Sue'}, {'Jane'}, {'Pete'}, {'Sam'}, {'Tim'}]
anotherQconnected(NM,1,anchor='Sam')
[{'Jane', 'Sue', 'Tim'}, {'Pete', 'Sam'}]
anotherQconnected(NM,0,anchor='Sam')
[{'Jane', 'Pete', 'Sam', 'Sue', 'Tim'}]
Trading network - directed graph, p. 52-53
I'm not sure about the sense of these, in that the information flows one way, so can something be connected to another thing going one way, but not the other? e.g. can we say x is qnear
y but y is not qnear
x? I need to go back and read the definitions again...
countries=['Argentina','Barbados','Bolivia','Brazil','Chile','Colombia','Ecuador',
'Trinidad-Tobago','Paraguay', 'Peru','Uruguay','Venezuela']
countrycodes=[x[:3] for x in countries]
print(countrycodes)
['Arg', 'Bar', 'Bol', 'Bra', 'Chi', 'Col', 'Ecu', 'Tri', 'Par', 'Per', 'Uru', 'Ven']
Tlist={
'Argentina': [1,0,1,1,1,0,0,0,1,0,1,0],
'Barbados': [0,1,0,0,0,0,0,1,0,0,0,0],
'Bolivia': [0,0,1,0,0,0,0,0,0,0,0,0],
'Brazil': [1,1,1,1,1,1,1,1,1,1,1,1],
'Chile': [1,0,1,0,1,0,0,0,1,1,1,0],
'Colombia': [0,0,1,0,1,1,1,0,0,1,0,1],
'Ecuador': [0,0,0,0,0,1,1,0,0,1,0,0],
'Trinidad-Tobago': [0,1,0,0,0,0,0,1,0,0,0,0],
'Paraguay': [0,0,0,0,0,0,0,0,1,0,0,0],
'Peru': [0,0,1,0,0,0,0,0,0,1,0,0],
'Uruguay': [0,0,0,0,0,0,0,0,0,0,1,0],
'Venezuela': [0,0,1,0,1,1,1,1,1,1,0,1]
}
Tset={k:[c[1] for c in zip(Tlist[k],countrycodes) if c[0]] for k in Tlist}
Tset
{'Argentina': ['Arg', 'Bol', 'Bra', 'Chi', 'Par', 'Uru'], 'Barbados': ['Bar', 'Tri'], 'Bolivia': ['Bol'], 'Brazil': ['Arg', 'Bar', 'Bol', 'Bra', 'Chi', 'Col', 'Ecu', 'Tri', 'Par', 'Per', 'Uru', 'Ven'], 'Chile': ['Arg', 'Bol', 'Chi', 'Par', 'Per', 'Uru'], 'Colombia': ['Bol', 'Chi', 'Col', 'Ecu', 'Per', 'Ven'], 'Ecuador': ['Col', 'Ecu', 'Per'], 'Paraguay': ['Par'], 'Peru': ['Bol', 'Per'], 'Trinidad-Tobago': ['Bar', 'Tri'], 'Uruguay': ['Uru'], 'Venezuela': ['Bol', 'Chi', 'Col', 'Ecu', 'Tri', 'Par', 'Per', 'Ven']}
BD=bipartite_graphBuilder(Tset,undirected=False)
bipartite_plot(BD)
pretty_matrix(BD, Y=countries, X=countrycodes)
Arg | Bar | Bol | Bra | Chi | Col | Ecu | Par | Per | Tri | Uru | Ven | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Argentina | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
Barbados | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
Bolivia | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Brazil | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
Chile | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 |
Colombia | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |
Ecuador | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 0 |
Paraguay | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
Peru | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
Trinidad-Tobago | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
Uruguay | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 |
Venezuela | 0 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 |
ND=nodematrix(BD,anchor="Peru")
ND
Argentina | Barbados | Bolivia | Brazil | Chile | Colombia | Ecuador | Paraguay | Peru | Trinidad-Tobago | Uruguay | Venezuela | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Argentina | 5.0 | NaN | 0.0 | 5 | 4.0 | 1.0 | NaN | 0.0 | 0.0 | NaN | 0.0 | 2.0 |
Barbados | NaN | 1.0 | NaN | 1 | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 0.0 |
Bolivia | 0.0 | NaN | 0.0 | 0 | 0.0 | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 |
Brazil | 5.0 | 1.0 | 0.0 | 11 | 5.0 | 5.0 | 2.0 | 0.0 | 1.0 | 1.0 | 0.0 | 7.0 |
Chile | 4.0 | NaN | 0.0 | 5 | 5.0 | 2.0 | 0.0 | 0.0 | 1.0 | NaN | 0.0 | 3.0 |
Colombia | 1.0 | NaN | 0.0 | 5 | 2.0 | 5.0 | 2.0 | NaN | 1.0 | NaN | NaN | 5.0 |
Ecuador | NaN | NaN | NaN | 2 | 0.0 | 2.0 | 2.0 | NaN | 0.0 | NaN | NaN | 2.0 |
Paraguay | 0.0 | NaN | NaN | 0 | 0.0 | NaN | NaN | 0.0 | NaN | NaN | NaN | 0.0 |
Peru | 0.0 | NaN | 0.0 | 1 | 1.0 | 1.0 | 0.0 | NaN | 1.0 | NaN | NaN | 1.0 |
Trinidad-Tobago | NaN | 1.0 | NaN | 1 | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 0.0 |
Uruguay | 0.0 | NaN | NaN | 0 | 0.0 | NaN | NaN | NaN | NaN | NaN | 0.0 | NaN |
Venezuela | 2.0 | 0.0 | 0.0 | 7 | 3.0 | 5.0 | 2.0 | 0.0 | 1.0 | 0.0 | NaN | 7.0 |
anotherQconnected(ND,7,anchor='Brazil'), anotherQconnected(ND,6,anchor='Brazil')
([{'Brazil', 'Venezuela'}], [{'Brazil', 'Venezuela'}])
anotherQconnected(ND,5,anchor='Brazil'), anotherQconnected(ND,3,anchor='Brazil')
([{'Argentina', 'Brazil', 'Chile', 'Colombia', 'Venezuela'}], [{'Argentina', 'Brazil', 'Chile', 'Colombia', 'Venezuela'}])
anotherQconnected(ND,2,anchor='Brazil')
[{'Argentina', 'Brazil', 'Chile', 'Colombia', 'Ecuador', 'Venezuela'}]
anotherQconnected(ND,1,anchor='Brazil')
[{'Argentina', 'Barbados', 'Brazil', 'Chile', 'Colombia', 'Ecuador', 'Peru', 'Trinidad-Tobago', 'Venezuela'}]
anotherQconnected(ND,0,anchor='Brazil')
[{'Argentina', 'Barbados', 'Bolivia', 'Brazil', 'Chile', 'Colombia', 'Ecuador', 'Paraguay', 'Peru', 'Trinidad-Tobago', 'Uruguay', 'Venezuela'}]
BD.remove_node('Brazil')
NDx=nodematrix(BD,anchor="Peru")
NDx
Argentina | Barbados | Bolivia | Chile | Colombia | Ecuador | Paraguay | Peru | Trinidad-Tobago | Uruguay | Venezuela | |
---|---|---|---|---|---|---|---|---|---|---|---|
Argentina | 5.0 | NaN | 0.0 | 4.0 | 1.0 | NaN | 0.0 | 0.0 | NaN | 0.0 | 2.0 |
Barbados | NaN | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 0.0 |
Bolivia | 0.0 | NaN | 0.0 | 0.0 | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 |
Chile | 4.0 | NaN | 0.0 | 5.0 | 2.0 | 0.0 | 0.0 | 1.0 | NaN | 0.0 | 3.0 |
Colombia | 1.0 | NaN | 0.0 | 2.0 | 5.0 | 2.0 | NaN | 1.0 | NaN | NaN | 5.0 |
Ecuador | NaN | NaN | NaN | 0.0 | 2.0 | 2.0 | NaN | 0.0 | NaN | NaN | 2.0 |
Paraguay | 0.0 | NaN | NaN | 0.0 | NaN | NaN | 0.0 | NaN | NaN | NaN | 0.0 |
Peru | 0.0 | NaN | 0.0 | 1.0 | 1.0 | 0.0 | NaN | 1.0 | NaN | NaN | 1.0 |
Trinidad-Tobago | NaN | 1.0 | NaN | NaN | NaN | NaN | NaN | NaN | 1.0 | NaN | 0.0 |
Uruguay | 0.0 | NaN | NaN | 0.0 | NaN | NaN | NaN | NaN | NaN | 0.0 | NaN |
Venezuela | 2.0 | 0.0 | 0.0 | 3.0 | 5.0 | 2.0 | 0.0 | 1.0 | 0.0 | NaN | 7.0 |
anotherQconnected(NDx,7,anchor='Chile'), anotherQconnected(NDx,6,anchor='Chile')
([{'Venezuela'}], [{'Venezuela'}])
anotherQconnected(NDx,5,anchor='Chile')
[{'Chile'}, {'Argentina'}, {'Colombia', 'Venezuela'}]
anotherQconnected(NDx,4,anchor='Chile')
[{'Argentina', 'Chile'}, {'Colombia', 'Venezuela'}]
anotherQconnected(NDx,3,anchor='Chile')
[{'Argentina', 'Chile', 'Colombia', 'Venezuela'}]
anotherQconnected(NDx,2,anchor='Chile')
[{'Argentina', 'Chile', 'Colombia', 'Ecuador', 'Venezuela'}]
anotherQconnected(NDx,1,anchor='Chile') #This is different to JJ's?
[{'Barbados', 'Trinidad-Tobago'}, {'Argentina', 'Chile', 'Colombia', 'Ecuador', 'Peru', 'Venezuela'}]
anotherQconnected(NDx,0,anchor='Chile')
[{'Argentina', 'Barbados', 'Bolivia', 'Chile', 'Colombia', 'Ecuador', 'Paraguay', 'Peru', 'Trinidad-Tobago', 'Uruguay', 'Venezuela'}]
What happens if we reverse the edges and rerun the analysis? Is that the sense of this (p54)?
Sense of reading the arrows is now more along lines of "gives money to, for exports"?
Tset2={c:[] for c in countrycodes}
for c in Tset:
for c2 in Tset[c]:
Tset2[c2].append(c)
Tset2
{'Arg': ['Brazil', 'Chile', 'Argentina'], 'Bar': ['Brazil', 'Barbados', 'Trinidad-Tobago'], 'Bol': ['Bolivia', 'Venezuela', 'Brazil', 'Colombia', 'Chile', 'Argentina', 'Peru'], 'Bra': ['Brazil', 'Argentina'], 'Chi': ['Venezuela', 'Brazil', 'Colombia', 'Chile', 'Argentina'], 'Col': ['Ecuador', 'Venezuela', 'Brazil', 'Colombia'], 'Ecu': ['Ecuador', 'Venezuela', 'Brazil', 'Colombia'], 'Par': ['Venezuela', 'Brazil', 'Chile', 'Argentina', 'Paraguay'], 'Per': ['Ecuador', 'Venezuela', 'Brazil', 'Colombia', 'Chile', 'Peru'], 'Tri': ['Venezuela', 'Brazil', 'Barbados', 'Trinidad-Tobago'], 'Uru': ['Brazil', 'Uruguay', 'Chile', 'Argentina'], 'Ven': ['Venezuela', 'Brazil', 'Colombia']}
BD2=bipartite_graphBuilder(Tset2,undirected=False)
bipartite_plot(BD2)
ND2=nodematrix(BD2,anchor="Per")
ND2
Arg | Bar | Bol | Bra | Chi | Col | Ecu | Par | Per | Tri | Uru | Ven | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Arg | 2 | 0 | 2 | 1 | 2 | 0 | 0 | 2 | 1 | 0 | 2 | 0 |
Bar | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 |
Bol | 2 | 0 | 6 | 1 | 4 | 2 | 2 | 3 | 4 | 1 | 2 | 2 |
Bra | 1 | 0 | 1 | 1 | 1 | 0 | 0 | 1 | 0 | 0 | 1 | 0 |
Chi | 2 | 0 | 4 | 1 | 4 | 2 | 2 | 3 | 3 | 1 | 2 | 2 |
Col | 0 | 0 | 2 | 0 | 2 | 3 | 3 | 1 | 3 | 1 | 0 | 2 |
Ecu | 0 | 0 | 2 | 0 | 2 | 3 | 3 | 1 | 3 | 1 | 0 | 2 |
Par | 2 | 0 | 3 | 1 | 3 | 1 | 1 | 4 | 2 | 1 | 2 | 1 |
Per | 1 | 0 | 4 | 0 | 3 | 3 | 3 | 2 | 5 | 1 | 1 | 2 |
Tri | 0 | 2 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 3 | 0 | 1 |
Uru | 2 | 0 | 2 | 1 | 2 | 0 | 0 | 2 | 1 | 0 | 3 | 0 |
Ven | 0 | 0 | 2 | 0 | 2 | 2 | 2 | 1 | 2 | 1 | 0 | 2 |
anotherQconnected(ND2,6,anchor='Bra')
[{'Bol'}]
anotherQconnected(ND2,5,anchor='Bra')
[{'Bol'}, {'Per'}]
anotherQconnected(ND2,4,anchor='Bra')
[{'Par'}, {'Bol', 'Chi', 'Per'}]
anotherQconnected(ND2,3,anchor='Bra') # Differs from JJ's?
[{'Bol', 'Chi', 'Col', 'Ecu', 'Par', 'Per'}, {'Uru'}, {'Tri'}]
anotherQconnected(ND2,2,anchor='Bra')
[{'Arg', 'Bol', 'Chi', 'Col', 'Ecu', 'Par', 'Per', 'Uru', 'Ven'}, {'Bar', 'Tri'}]
anotherQconnected(ND2,1,anchor='Bra')
[{'Arg', 'Bar', 'Bol', 'Bra', 'Chi', 'Col', 'Ecu', 'Par', 'Per', 'Tri', 'Uru', 'Ven'}]
GaloisPair(BD2,{'Bol','Chi','Per'})
({'Bol', 'Chi', 'Per'}, {'Brazil', 'Chile', 'Colombia', 'Venezuela'})
p. 59
glasses={'g1':{'ThinStem','Small','TulipShape','Narrow','Curved'},
'g2':{'ThinStem','Tall','CupShape','Wide','Curved','Logo'},
'g3':{'ThinStem','Tall','TulipShape','Narrow','Curved'},
'g4':{'FatStem','Tall','VeeShape','Narrow','Straight'},
'g5':{'FatStem','Small','VeeShape','Narrow','Straight'},
'g6':{'ThinStem','Small','TubeShape','Narrow','Straight'}
}
GL=bipartite_graphBuilder(glasses)
bipartite_plot(GL)
def _ecc(B,x,y):
return len(set(B[x].keys())-set(B[y].keys())) / len(B[x].keys())
_ecc(GL,'g1','g3'), _ecc(GL,'g2','g3'), _ecc(GL,'g3','g1'), _ecc(GL,'g4','g5'), _ecc(GL,'g5','g4'), _ecc(GL,'g6','g1')
(0.2, 0.5, 0.2, 0.2, 0.2, 0.4)
def _eccg(B,x):
X, Y = nx.bipartite.sets(B)
if x in Y: X,Y=Y,X
return min([_ecc(B,x,z) for z in X if z!=x])
_eccg(GL,'g1'), _eccg(GL,'g2'), _eccg(GL,'g3'), _eccg(GL,'g4'), _eccg(GL,'g5'), _eccg(GL,'g6')
(0.2, 0.5, 0.2, 0.2, 0.2, 0.4)
def ecc(B,x,y=None):
if y is None: return _eccg(B,x)
return _ecc(B,x,y)
ecc(GL,'g1'), ecc(GL,'g2','g3')
(0.2, 0.5)
def qAnalysis(B,anchor):
X, Y = nx.bipartite.sets(B)
if anchor is not None and anchor in X:
X,Y=Y,X
N=nodematrix(B,anchor=anchor, X=X, Y=Y)
S=len(Y)
for i in range(S-1,-1, -1):
print('{}: {}'.format(i, anotherQconnected(N,i,anchor=anchor)))
for y in sorted(list(Y)):
print('Eccentricity of {}: {}'.format(y, ecc(B,y)))
qAnalysis(GL,'g1')
5: [{'g2'}] 4: [{'g2'}, {'g5'}, {'g4'}, {'g6'}, {'g3'}, {'g1'}] 3: [{'g2'}, {'g5', 'g4'}, {'g6'}, {'g3', 'g1'}] 2: [{'g2', 'g5', 'g4', 'g6', 'g3', 'g1'}] 1: [{'g2', 'g5', 'g4', 'g6', 'g3', 'g1'}] 0: [{'g2', 'g5', 'g4', 'g6', 'g3', 'g1'}] Eccentricity of g1: 0.2 Eccentricity of g2: 0.5 Eccentricity of g3: 0.2 Eccentricity of g4: 0.2 Eccentricity of g5: 0.2 Eccentricity of g6: 0.4