How to get the balanced and imbalanced triangles in an incomplete network?

Viewed 45

I am trying to compute the number of balanced and imbalanced triads in an incomplete signed network of organizations. But the problem is that my code only works for complete networks. Organization 5 is in a triad, but because it is not fully connected, the output throws an error. How can I run the analysis considering that some nodes might not be fully connected? My code is the following:

G = nx.Graph()
G.add_edge('Organization 1','Organization 2',color='g', sign='+')
G.add_edge('Organization 2','Organization 3',color='r', sign='-')
G.add_edge('Organization 3','Organization 4',color='r', sign='-')
G.add_edge('Organization 4','Organization 1',color='r', sign='-')
G.add_edge('Organization 2','Organization 4',color='r', sign='-')
G.add_edge('Organization 1','Organization 3',color='g', sign='+')
G.add_edge('Organization 5','Organization 4',color='g', sign='+')
G.add_edge('Organization 2','Organization 4',color='g', sign='+')
G.add_edge('Organization 5','Organization 3',color='r', sign='-')


plt.figure(figsize=(12, 6), dpi=300)
pos = nx.circular_layout(G)

edges = G.edges()
colors = [G[u][v]['color'] for u,v in edges]

nx.draw(G, pos, edge_color=colors, width=5, node_size=1500, with_labels=True)
plt.savefig('simulated_conflicts')

This is the resulting network. Green edges are positive relations and red edges are negative

To do the structural balance analysis I ran this code:


G.nodes()
triangular_relations2009 = [list(each_tri_combination) for each_tri_combination in itertools.combinations(nodes,3)]



#Let's visualize these triangular relationships
#I will create a function to get all the signs of triangles defined in the list

def get_signs_of_triangles_list(triangles_list,graph):
    all_signs = []
    for each_node_in_triangle_list in range(len(triangles_list)):
        temp_storage_list = []
        temp_storage_list.append(G[triangles_list[each_node_in_triangle_list][0]][triangles_list[each_node_in_triangle_list][1]]['sign'])
        temp_storage_list.append(G[triangles_list[each_node_in_triangle_list][0]][triangles_list[each_node_in_triangle_list][2]]['sign'])
        temp_storage_list.append(G[triangles_list[each_node_in_triangle_list][1]][triangles_list[each_node_in_triangle_list][2]]['sign'])
        all_signs.append(temp_storage_list)
    return all_signs


#storing all the signs in the list

all_signs_in_network = get_signs_of_triangles_list(triangular_relations2009,G)
len(all_signs_in_network)
count_unstable_triangles(all_signs_in_network)

The Key error I get is:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Input In [60], in <cell line: 2>()
      1 #storing all the signs in the list
----> 2 all_signs_in_network = get_signs_of_triangles_list(triangular_relations2009,G)
      4 len(all_signs_in_network)
      6 count_unstable_triangles(all_signs_in_network)

Input In [58], in get_signs_of_triangles_list(triangles_list, graph)
      6 temp_storage_list = []
      7 temp_storage_list.append(G[triangles_list[each_node_in_triangle_list][0]][triangles_list[each_node_in_triangle_list][1]]['sign'])
----> 8 temp_storage_list.append(G[triangles_list[each_node_in_triangle_list][0]][triangles_list[each_node_in_triangle_list][2]]['sign'])
      9 temp_storage_list.append(G[triangles_list[each_node_in_triangle_list][1]][triangles_list[each_node_in_triangle_list][2]]['sign'])
     10 all_signs.append(temp_storage_list)

File ~/opt/anaconda3/lib/python3.9/site-packages/networkx/classes/coreviews.py:54, in AtlasView.__getitem__(self, key)
     53 def __getitem__(self, key):
---> 54     return self._atlas[key]

KeyError: 'Organization 5'

I believe the problem is that It cannot include Organization 5 in the analysis because it is not fully connected, how can I do this? What i want is to be able to store all the signs in the list so that I can run this code next:

def count_unstable_triangles(all_signs):
    number_of_stable_triangles = 0
    number_of_unstable_triangles = 0
    for each_sign in range(len(all_signs)):
        if all_signs[each_sign].count('+') == 3 or all_signs[each_sign].count('+') == 1:
            number_of_stable_triangles = number_of_stable_triangles+1
        else:
            number_of_unstable_triangles = number_of_unstable_triangles+1
    print(f"number of stable_triangles out of {number_of_stable_triangles+number_of_unstable_triangles} are {number_of_stable_triangles}")
    print(f"number of unstable_triangles out of {number_of_stable_triangles+number_of_unstable_triangles} are {number_of_unstable_triangles}")  
    return number_of_unstable_triangles,number_of_stable_triangles

count_unstable_triangles(all_signs_in_network)

This code will give me the amount of balanced and unbalanced triangles in the network. I ran this code with multiple complete networks an it runs smoothly.

1 Answers

Here I assume that with balanced triad you mean a set of three nodes that are all connected via an edge with sign + and with an imbalanced triad you mean a set of three nodes of which two are connected via an edge with sign +.

from collections import Counter
from itertools import combinations

edges = set(G.edges)
n_balanced, n_imbalanced = 0, 0
for triad in list(combinations(G.nodes, 3)):
    a, b, c = triad
    edge_set = {(a, b), (a, c), (b, c)}
    if edge_set.issubset(edges):
        count = Counter([G.edges[edge]['sign'] for edge in edge_set])
        if count['+'] == 3:
            n_balanced += 1
        elif count['+'] == 2:
            n_imbalanced += 1
    else:
        edge_subsets = set(combinations(edge_set, 2))
        for edge_subset in edge_subsets:
            if set(edge_subset).issubset(edges):
                if G.edges[edge_subset[0]]['sign'] == G.edges[edge_subset[1]]['sign'] == '+':
                    n_imbalanced += 1
                    break
print(n_balanced, n_imbalanced)

prints

0 3
Related