In this case study, we will go through and understand a time-varying criminal network that was repeatedly disrupted by police forces, and how the criminal network reoriented in response to the seizures of product by the police forces.
Here is some information on the CAVIAR project and the role of certain individuals arrested following the investigation. The investigation lasted two years and ran from 1994 to 1996. The operation was brought together by investigation units of the Montreal police and the Royal Canadian Mounted Police of Canada. During these two years, 11 wiretap warrants, valid for about two months each, were obtained (11 matrices match these phases).
This case is rather unique because, unlike other investigative strategies, the mandate of the CAVIAR project was to seize the drugs without arresting criminals. During this period, imports of the trafficking network were hit and seized by the police on eleven occasions. The arrests took place only at the end of the investigation. Monetary losses for traffickers were estimated at 32 million dollars. Some phases included no seizures, and others included multiple. Here is what they represent in terms of the amount of money:
As you can see, this case study offers a rare opportunity to study a criminal network in response to upheaval by police forces. This allows us to analyze changes in the network structure and to survey the reaction and adaptation of the participants while they were subjected to an increasing number of distressing constraints.
The network consists of 110 (numbered) players. Players 1-82 are the traffickers. Players 83-110 are the non-traffickers (financial investors, accountants, owners of various importation businesses, etc.). Initially, the investigation targeted Daniel Serero, the alleged mastermind of a drug network in downtown Montreal, attempting to import marijuana to Canada from Morocco, transiting through Spain. After the first seizure, happening in phase 4, traffickers reoriented to cocaine import from Colombia, transiting through the United States.
According to the police, the role of the players of the "Serero organization" under investigation were the following:
%matplotlib inline
import networkx as nx
from decorator import decorator
from networkx.utils import create_random_state, create_py_random_state
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
# To get rid of warning messages
warnings.filterwarnings('ignore')
# Remove scientific notations and display numbers with 2 decimal points instead
pd.options.display.float_format = '{ : , .2f}'.format
# Update default background style of plots
sns.set_style(style = 'darkgrid')
P1 = pd.read_csv("CAVIAR_Phases - Notebook/phase1.csv")
P2 = pd.read_csv("CAVIAR_Phases - Notebook/phase2.csv")
P3 = pd.read_csv("CAVIAR_Phases - Notebook/phase3.csv")
P4 = pd.read_csv("CAVIAR_Phases - Notebook/phase4.csv")
P5 = pd.read_csv("CAVIAR_Phases - Notebook/phase5.csv")
P6 = pd.read_csv("CAVIAR_Phases - Notebook/phase6.csv")
P7 = pd.read_csv("CAVIAR_Phases - Notebook/phase7.csv")
P8 = pd.read_csv("CAVIAR_Phases - Notebook/phase8.csv")
P9 = pd.read_csv("CAVIAR_Phases - Notebook/phase9.csv")
P10 = pd.read_csv("CAVIAR_Phases - Notebook/phase10.csv")
P11 = pd.read_csv("CAVIAR_Phases - Notebook/phase11.csv")
P1.head()
| Unnamed: 0 | 1 | 4 | 89 | 83 | 3 | 5 | 88 | 85 | 90 | 2 | 7 | 54 | 6 | 64 | 8 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 1 | 4 | 0 | 4 | 2 | 2 | 9 | 1 | 2 | 0 | 2 | 0 | 1 | 1 |
| 1 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 89 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 |
| 3 | 83 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 |
| 4 | 3 | 2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
So, we have the data in the form of an adjacency matrix represented through a DataFrame.
Observations:
Let us check the points above.
# Setting first column as the index to achieve the adjacency matrix for each phase
# Defining a list with the phases
phases = [P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11]
# Now, let us set the first column as the index for all the DataFrames
for p in phases:
p.set_index(p.columns[0], inplace = True)
P1
| 1 | 4 | 89 | 83 | 3 | 5 | 88 | 85 | 90 | 2 | 7 | 54 | 6 | 64 | 8 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Unnamed: 0 | |||||||||||||||
| 1 | 0 | 1 | 4 | 0 | 4 | 2 | 2 | 9 | 1 | 2 | 0 | 2 | 0 | 1 | 1 |
| 4 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 89 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 |
| 83 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 |
| 3 | 2 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 88 | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
| 85 | 1 | 0 | 0 | 0 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 5 | 0 | 0 |
| 90 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 7 | 0 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 54 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 6 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 64 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
# Now, that we have set the index, check for the consistency in column names and indices data type
P1.index, P1.columns
(Int64Index([1, 4, 89, 83, 3, 5, 88, 85, 90, 2, 7, 54, 6, 64, 8], dtype='int64', name='Unnamed: 0'),
Index(['1', '4', '89', '83', '3', '5', '88', '85', '90', '2', '7', '54', '6',
'64', '8'],
dtype='object'))
Observation:
# Let's convert the column names to integer types
phases = [P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11]
col = []
for p in phases: # Running the loop for each phase (11)
for i in p.columns: # Running the loop for each column of each phase
col.append(int(i)) # Appending column names to the list 'col'
p.columns = col # Updating the column names for each phase
col = [] # Reinitiating the list 'col' as an empty list
# Let's check if the transformation worked
P1.index, P1.columns
(Int64Index([1, 4, 89, 83, 3, 5, 88, 85, 90, 2, 7, 54, 6, 64, 8], dtype='int64', name='Unnamed: 0'), Int64Index([1, 4, 89, 83, 3, 5, 88, 85, 90, 2, 7, 54, 6, 64, 8], dtype='int64'))
Observation:
Now, that we have created the adjacency matrices, let us now try to create graphs out of these adjacency matrices.
graphs = []
for i, p in enumerate(phases):
g = 'graph' + str(i + 1)
print(g)
g = nx.from_pandas_adjacency(p)
graphs.append(g)
print(g.nodes())
graph1 [5, 83, 3, 90, 88, 85, 89, 4, 8, 64, 6, 54, 7, 2, 1] graph2 [3, 85, 83, 90, 64, 6, 2, 7, 86, 88, 89, 12, 11, 9, 76, 98, 47, 97, 56, 10, 55, 8, 5, 1] graph3 [5, 83, 88, 48, 89, 3, 7, 6, 52, 2, 90, 86, 85, 4, 12, 51, 13, 99, 50, 107, 49, 84, 32, 11, 35, 34, 9, 76, 56, 10, 55, 8, 1] graph4 [5, 83, 88, 90, 85, 3, 76, 47, 6, 106, 8, 7, 86, 89, 4, 15, 52, 14, 12, 31, 109, 63, 51, 13, 107, 49, 84, 53, 11, 35, 9, 2, 1] graph5 [5, 88, 83, 6, 86, 76, 89, 3, 32, 100, 34, 11, 8, 15, 55, 2, 85, 4, 19, 82, 25, 17, 18, 108, 12, 31, 13, 84, 9, 47, 7, 1] graph6 [3, 8, 11, 13, 84, 12, 85, 82, 15, 83, 5, 19, 25, 31, 76, 2, 4, 20, 87, 77, 78, 18, 14, 9, 6, 1] graph7 [3, 18, 83, 81, 2, 34, 9, 14, 88, 8, 55, 17, 5, 11, 69, 12, 77, 19, 85, 4, 15, 28, 75, 16, 68, 61, 79, 74, 22, 20, 87, 78, 76, 6, 62, 1] graph8 [3, 8, 18, 59, 84, 80, 78, 35, 14, 39, 23, 73, 12, 17, 87, 34, 83, 85, 37, 33, 16, 19, 25, 11, 76, 2, 4, 36, 91, 38, 67, 81, 28, 22, 20, 77, 82, 13, 9, 6, 86, 1] graph9 [3, 13, 17, 29, 30, 76, 83, 82, 11, 2, 18, 12, 7, 90, 89, 41, 101, 105, 46, 96, 36, 37, 59, 81, 16, 79, 87, 78, 14, 8, 6, 85, 88, 1] graph10 [3, 65, 40, 87, 37, 16, 84, 85, 105, 73, 70, 58, 44, 81, 22, 82, 18, 9, 4, 45, 71, 42, 93, 95, 27, 104, 103, 21, 41, 46, 96, 24, 38, 19, 17, 14, 12, 76, 8, 86, 83, 1] graph11 [24, 96, 61, 79, 82, 46, 26, 94, 87, 18, 17, 14, 88, 83, 65, 66, 92, 72, 102, 43, 42, 93, 27, 41, 101, 58, 36, 37, 59, 81, 16, 78, 12, 13, 84, 11, 76, 86, 85, 3, 1]
Let us now visualize the graphs that we have created above.
!pip install --upgrade decorator
for i, g in enumerate(graphs):
print("****************************************************************************************") #"*"*50
print("Graph for phase:", i + 1)
nx.draw(g, with_labels = True)
plt.title(str(g))
plt.show()
**************************************************************************************** Graph for phase: 1
**************************************************************************************** Graph for phase: 2
**************************************************************************************** Graph for phase: 3
**************************************************************************************** Graph for phase: 4
**************************************************************************************** Graph for phase: 5
**************************************************************************************** Graph for phase: 6
**************************************************************************************** Graph for phase: 7
**************************************************************************************** Graph for phase: 8
**************************************************************************************** Graph for phase: 9
**************************************************************************************** Graph for phase: 10
**************************************************************************************** Graph for phase: 11
Let us now explore the various centrality measures for the above graphs.
# Let us store the degree centralities for each node of a graph in a dictionary
deg_cen = {}
for g in graphs:
deg_cen[g] = nx.degree_centrality(g)
# Let us look at the deg_cen dictionary
deg_cen
{<networkx.classes.graph.Graph at 0x12393809340>: {5: 0.07142857142857142,
83: 0.14285714285714285,
3: 0.14285714285714285,
90: 0.07142857142857142,
88: 0.2857142857142857,
85: 0.21428571428571427,
89: 0.14285714285714285,
4: 0.07142857142857142,
8: 0.07142857142857142,
64: 0.07142857142857142,
6: 0.21428571428571427,
54: 0.07142857142857142,
7: 0.07142857142857142,
2: 0.07142857142857142,
1: 0.8571428571428571},
<networkx.classes.graph.Graph at 0x123938095b0>: {3: 0.13043478260869565,
85: 0.08695652173913043,
83: 0.08695652173913043,
90: 0.043478260869565216,
64: 0.08695652173913043,
6: 0.043478260869565216,
2: 0.043478260869565216,
7: 0.043478260869565216,
86: 0.043478260869565216,
88: 0.13043478260869565,
89: 0.13043478260869565,
12: 0.043478260869565216,
11: 0.08695652173913043,
9: 0.043478260869565216,
76: 0.08695652173913043,
98: 0.043478260869565216,
47: 0.043478260869565216,
97: 0.043478260869565216,
56: 0.043478260869565216,
10: 0.08695652173913043,
55: 0.043478260869565216,
8: 0.13043478260869565,
5: 0.043478260869565216,
1: 0.8260869565217391},
<networkx.classes.graph.Graph at 0x12393809850>: {5: 0.0625,
83: 0.25,
88: 0.0625,
48: 0.03125,
89: 0.0625,
3: 0.28125,
7: 0.0625,
6: 0.125,
52: 0.09375,
2: 0.09375,
90: 0.0625,
86: 0.125,
85: 0.125,
4: 0.03125,
12: 0.0625,
51: 0.03125,
13: 0.0625,
99: 0.03125,
50: 0.03125,
107: 0.0625,
49: 0.15625,
84: 0.125,
32: 0.0625,
11: 0.09375,
35: 0.03125,
34: 0.0625,
9: 0.15625,
76: 0.0625,
56: 0.03125,
10: 0.03125,
55: 0.03125,
8: 0.0625,
1: 0.84375},
<networkx.classes.graph.Graph at 0x12393809970>: {5: 0.03125,
83: 0.21875,
88: 0.0625,
90: 0.0625,
85: 0.15625,
3: 0.21875,
76: 0.0625,
47: 0.03125,
6: 0.03125,
106: 0.0625,
8: 0.125,
7: 0.03125,
86: 0.09375,
89: 0.1875,
4: 0.03125,
15: 0.03125,
52: 0.0625,
14: 0.03125,
12: 0.03125,
31: 0.09375,
109: 0.03125,
63: 0.03125,
51: 0.03125,
13: 0.0625,
107: 0.09375,
49: 0.0625,
84: 0.0625,
53: 0.03125,
11: 0.03125,
35: 0.03125,
9: 0.125,
2: 0.03125,
1: 0.71875},
<networkx.classes.graph.Graph at 0x123937d6bb0>: {5: 0.06451612903225806,
88: 0.03225806451612903,
83: 0.06451612903225806,
6: 0.06451612903225806,
86: 0.03225806451612903,
76: 0.06451612903225806,
89: 0.0967741935483871,
3: 0.16129032258064516,
32: 0.03225806451612903,
100: 0.03225806451612903,
34: 0.03225806451612903,
11: 0.03225806451612903,
8: 0.06451612903225806,
15: 0.03225806451612903,
55: 0.03225806451612903,
2: 0.03225806451612903,
85: 0.0967741935483871,
4: 0.03225806451612903,
19: 0.03225806451612903,
82: 0.03225806451612903,
25: 0.03225806451612903,
17: 0.03225806451612903,
18: 0.03225806451612903,
108: 0.06451612903225806,
12: 0.25806451612903225,
31: 0.12903225806451613,
13: 0.03225806451612903,
84: 0.03225806451612903,
9: 0.06451612903225806,
47: 0.03225806451612903,
7: 0.03225806451612903,
1: 0.7096774193548387},
<networkx.classes.graph.Graph at 0x1239381a2e0>: {3: 0.56,
8: 0.16,
11: 0.08,
13: 0.04,
84: 0.08,
12: 0.36,
85: 0.2,
82: 0.04,
15: 0.12,
83: 0.08,
5: 0.12,
19: 0.12,
25: 0.04,
31: 0.04,
76: 0.28,
2: 0.08,
4: 0.04,
20: 0.08,
87: 0.08,
77: 0.08,
78: 0.04,
18: 0.04,
14: 0.08,
9: 0.08,
6: 0.04,
1: 0.72},
<networkx.classes.graph.Graph at 0x1239381a6a0>: {3: 0.2857142857142857,
18: 0.02857142857142857,
83: 0.08571428571428572,
81: 0.05714285714285714,
2: 0.05714285714285714,
34: 0.02857142857142857,
9: 0.08571428571428572,
14: 0.02857142857142857,
88: 0.05714285714285714,
8: 0.02857142857142857,
55: 0.02857142857142857,
17: 0.02857142857142857,
5: 0.02857142857142857,
11: 0.05714285714285714,
69: 0.02857142857142857,
12: 0.14285714285714285,
77: 0.08571428571428572,
19: 0.11428571428571428,
85: 0.11428571428571428,
4: 0.02857142857142857,
15: 0.02857142857142857,
28: 0.02857142857142857,
75: 0.02857142857142857,
16: 0.02857142857142857,
68: 0.02857142857142857,
61: 0.02857142857142857,
79: 0.05714285714285714,
74: 0.05714285714285714,
22: 0.02857142857142857,
20: 0.05714285714285714,
87: 0.08571428571428572,
78: 0.05714285714285714,
76: 0.14285714285714285,
6: 0.02857142857142857,
62: 0.02857142857142857,
1: 0.6857142857142857},
<networkx.classes.graph.Graph at 0x1239381a430>: {3: 0.3170731707317073,
8: 0.07317073170731708,
18: 0.024390243902439025,
59: 0.024390243902439025,
84: 0.024390243902439025,
80: 0.024390243902439025,
78: 0.024390243902439025,
35: 0.024390243902439025,
14: 0.07317073170731708,
39: 0.024390243902439025,
23: 0.024390243902439025,
73: 0.04878048780487805,
12: 0.24390243902439024,
17: 0.024390243902439025,
87: 0.21951219512195122,
34: 0.04878048780487805,
83: 0.024390243902439025,
85: 0.07317073170731708,
37: 0.04878048780487805,
33: 0.024390243902439025,
16: 0.024390243902439025,
19: 0.04878048780487805,
25: 0.024390243902439025,
11: 0.07317073170731708,
76: 0.14634146341463417,
2: 0.0975609756097561,
4: 0.024390243902439025,
36: 0.024390243902439025,
91: 0.024390243902439025,
38: 0.024390243902439025,
67: 0.024390243902439025,
81: 0.04878048780487805,
28: 0.024390243902439025,
22: 0.04878048780487805,
20: 0.04878048780487805,
77: 0.024390243902439025,
82: 0.04878048780487805,
13: 0.024390243902439025,
9: 0.04878048780487805,
6: 0.024390243902439025,
86: 0.04878048780487805,
1: 0.4878048780487805},
<networkx.classes.graph.Graph at 0x1239381a1c0>: {3: 0.33333333333333337,
13: 0.030303030303030304,
17: 0.030303030303030304,
29: 0.030303030303030304,
30: 0.06060606060606061,
76: 0.15151515151515152,
83: 0.030303030303030304,
82: 0.18181818181818182,
11: 0.030303030303030304,
2: 0.030303030303030304,
18: 0.030303030303030304,
12: 0.24242424242424243,
7: 0.06060606060606061,
90: 0.030303030303030304,
89: 0.030303030303030304,
41: 0.030303030303030304,
101: 0.030303030303030304,
105: 0.030303030303030304,
46: 0.06060606060606061,
96: 0.12121212121212122,
36: 0.030303030303030304,
37: 0.030303030303030304,
59: 0.030303030303030304,
81: 0.030303030303030304,
16: 0.030303030303030304,
79: 0.09090909090909091,
87: 0.24242424242424243,
78: 0.06060606060606061,
14: 0.030303030303030304,
8: 0.06060606060606061,
6: 0.030303030303030304,
85: 0.09090909090909091,
88: 0.030303030303030304,
1: 0.30303030303030304},
<networkx.classes.graph.Graph at 0x1239381a9d0>: {3: 0.024390243902439025,
65: 0.024390243902439025,
40: 0.024390243902439025,
87: 0.2682926829268293,
37: 0.21951219512195122,
16: 0.024390243902439025,
84: 0.04878048780487805,
85: 0.07317073170731708,
105: 0.04878048780487805,
73: 0.024390243902439025,
70: 0.024390243902439025,
58: 0.04878048780487805,
44: 0.024390243902439025,
81: 0.04878048780487805,
22: 0.024390243902439025,
82: 0.12195121951219512,
18: 0.024390243902439025,
9: 0.024390243902439025,
4: 0.024390243902439025,
45: 0.024390243902439025,
71: 0.04878048780487805,
42: 0.024390243902439025,
93: 0.024390243902439025,
95: 0.024390243902439025,
27: 0.024390243902439025,
104: 0.024390243902439025,
103: 0.024390243902439025,
21: 0.024390243902439025,
41: 0.04878048780487805,
46: 0.04878048780487805,
96: 0.04878048780487805,
24: 0.07317073170731708,
38: 0.024390243902439025,
19: 0.024390243902439025,
17: 0.024390243902439025,
14: 0.07317073170731708,
12: 0.17073170731707318,
76: 0.07317073170731708,
8: 0.04878048780487805,
86: 0.024390243902439025,
83: 0.04878048780487805,
1: 0.3170731707317073},
<networkx.classes.graph.Graph at 0x1239381a760>: {24: 0.025,
96: 0.05,
61: 0.025,
79: 0.125,
82: 0.1,
46: 0.025,
26: 0.025,
94: 0.025,
87: 0.1,
18: 0.025,
17: 0.05,
14: 0.05,
88: 0.025,
83: 0.025,
65: 0.025,
66: 0.025,
92: 0.025,
72: 0.025,
102: 0.07500000000000001,
43: 0.025,
42: 0.025,
93: 0.05,
27: 0.1,
41: 0.225,
101: 0.05,
58: 0.05,
36: 0.025,
37: 0.07500000000000001,
59: 0.05,
81: 0.025,
16: 0.025,
78: 0.025,
12: 0.30000000000000004,
13: 0.05,
84: 0.05,
11: 0.025,
76: 0.17500000000000002,
86: 0.025,
85: 0.07500000000000001,
3: 0.025,
1: 0.17500000000000002}}
# Similarily, we can generate other centrality measures
# Let us try all the measures that we learnt
# Eigenvector Centrality
eig_cen = {}
for g in graphs:
eig_cen[g] = nx.eigenvector_centrality(g)
# Betweenness Centrality
betw_cen = {}
for g in graphs:
betw_cen[g] = nx.betweenness_centrality(g)
# Closeness Centrality
clo_cen = {}
for g in graphs:
clo_cen[g] = nx.closeness_centrality(g)
Observations:
# Let us now sort the degree centrality measure and identify the important nodes
for ix, g in enumerate(graphs):
temp_dict = {}
for w in sorted(deg_cen[g], key = deg_cen[g].get, reverse = True):
temp_dict[w] = deg_cen[g][w]
print("Sorted importance of nodes in terms of deg_cen for Phase {} is {}".format(ix + 1, list(temp_dict.keys())[:5]))
print()
Sorted importance of nodes in terms of deg_cen for Phase 1 is [1, 88, 85, 6, 83] Sorted importance of nodes in terms of deg_cen for Phase 2 is [1, 3, 88, 89, 8] Sorted importance of nodes in terms of deg_cen for Phase 3 is [1, 3, 83, 49, 9] Sorted importance of nodes in terms of deg_cen for Phase 4 is [1, 83, 3, 89, 85] Sorted importance of nodes in terms of deg_cen for Phase 5 is [1, 12, 3, 31, 89] Sorted importance of nodes in terms of deg_cen for Phase 6 is [1, 3, 12, 76, 85] Sorted importance of nodes in terms of deg_cen for Phase 7 is [1, 3, 12, 76, 19] Sorted importance of nodes in terms of deg_cen for Phase 8 is [1, 3, 12, 87, 76] Sorted importance of nodes in terms of deg_cen for Phase 9 is [3, 1, 12, 87, 82] Sorted importance of nodes in terms of deg_cen for Phase 10 is [1, 87, 37, 12, 82] Sorted importance of nodes in terms of deg_cen for Phase 11 is [12, 41, 76, 1, 79]
From the above analysis, we figure out that some nodes appear to be more important than others, and we will focus our attention on analyzing those nodes.
Let us take out Node1, Node3, and Node12 and visualize their importance across phases. We will look at the betweenness and degree centrality only. You are encouraged to try out the same for other measures.
# Let us first start with node 1
# Node 1
node1_deg = []
phases = []
for ix, g in enumerate(graphs):
node1_deg.append(deg_cen[g][1]*100)
phases.append(ix + 1)
node1_bet = []
for ix, g in enumerate(graphs):
node1_bet.append(betw_cen[g][1]*100)
# Now, let us calculate the same for node 3 and 12 as well
# Node 3
node3_deg = []
for ix, g in enumerate(graphs):
node3_deg.append(deg_cen[g][3]*100)
node3_bet = []
for ix, g in enumerate(graphs):
node3_bet.append(betw_cen[g][3]*100)
# Node 12
node12_deg = []
for ix, g in enumerate(graphs):
if (12 in deg_cen[g].keys()):
node12_deg.append(deg_cen[g][12]*100)
else:
node12_deg.append(None)
node12_bet = []
for ix, g in enumerate(graphs):
if (12 in betw_cen[g].keys()):
node12_bet.append(betw_cen[g][12]*100)
else:
node12_bet.append(None)
# Now, let us plot the importance of nodes across phases
# Ploting Degree centrality for nodes 1, 3, and 12
plt.figure(figsize = (10, 7))
plt.plot(phases, node1_deg, label = 'Node 1')
plt.plot(phases, node3_deg, label = 'Node 3')
plt.plot(phases, node12_deg, label = 'Node 12')
plt.ylabel('Degree centrality(*100)')
plt.xlabel('Phases')
plt.legend()
plt.show()
# Plotting the Betweenness Centrality for nodes 1, 3, and 12
plt.figure(figsize = (10, 7))
plt.plot(phases, node1_bet, label = 'Node 1')
plt.plot(phases, node3_bet, label = 'Node 3')
plt.plot(phases, node12_bet, label = 'Node 12')
plt.ylabel('Betweenness centrality(*100)')
plt.xlabel('Phases')
plt.legend()
plt.show()
graph2 = nx.from_pandas_adjacency(P2)
color = []
for node in graph2:
if (node == 1 or node == 12 or node == 3):
color.append('red')
else:
color.append('green')
nx.draw_spring(graph2, node_color = color, with_labels = True)