15. Epidemics on temporal networks#

The temporal dynamics of networks affect dynamical processes defined one them

In 2001, Liljeros and collaborators found that the network of human sexual contacts is “scale-free” concluding that STI can be hard to eradicate because of such property.

See: https://www.nature.com/nature/journal/v411/n6840/full/411907a0.html

However, their conclusions were only partially true because the network of human sexual contacts is a dynamical network and temporal fluctuations are very important when considering a dynamical processes that take place on top of it.

In 2011, Rocha and collaborators published a temporal dataset of sexual contacts in Brazil: http://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1001109. We use this dataset to simulate an epidemic process (SI) and compare results between the static aggregated network and the dynamic network.

import networkx as nx
from collections import defaultdict
# %#pylab inline
%pylab is deprecated, use %matplotlib inline and import the required libraries.
Populating the interactive namespace from numpy and matplotlib
import seaborn as sns
filepath = "./../network_data/Dataset_sexual_network.csv"
edgelist = defaultdict(list)
finput = open(filepath, "r")
for line in finput.readlines():
    if line[0] != "#":  # not a comment
        s = line.strip().split(";")

        day = int(s[2])
        edge = (int(s[0]), int(s[1]))

        edgelist[day].append(edge)

finput.close()

We first create the aggregated network

G_agg = nx.Graph()
G_agg.disease_status = {}
daystart = 800  # we skip the transient
dayend = 1800
for d in edgelist:
    if d >= daystart and d <= dayend:
        links = edgelist[d]
        G_agg.add_edges_from(links)  # we add the link to the graph

print("The aggregated network has", len(G_agg.nodes()), "nodes")
print("The aggregated network has", len(G_agg.edges()), "links")
The aggregated network has 11306 nodes
The aggregated network has 23345 links
nx.is_connected(G_agg)
False
nx.number_connected_components(G_agg)
337
for i in nx.connected_components(G_agg):
    print(len(i))
10566
3
2
2
2
2
2
2
2
3
2
4
2
2
3
2
3
2
3
2
3
2
2
2
2
2
2
2
2
3
2
2
2
2
2
2
2
2
2
2
2
2
2
3
4
2
2
6
2
4
2
4
2
3
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
3
2
2
2
2
2
2
2
3
2
2
2
2
3
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
3
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
3
2
2
2
3
2
2
2
2
2
3
2
2
2
3
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2
5
2
2
3
2
2
2
2
2
3
2
2
2
8
2
5
2
3
3
2
2
2
2
4
2
2
2
2
2
3
2
2
2
2
2
2
2
2
2
2
2
3
2
2
3
2
2
2
2
2
2
2
2
2
5
3
2
2
3
2
2
2
2
2
2
2
2
2
3
2
2
2
2
2
2
3
2
2
2
2
2
2
2
2
2
3
2
3
2
2
2
2
2
2
2
2
2
2
3
2
2
2
2
2
2
2
2
2
2
3
2
2
2
2
2
2
2
2
4
2
2
2
2
2
4
2
2
2
2
2
3
2
2
2
2
2
2
3
2
2
2
2
2
2
3
2
2
2
2
2
2
2
2
2
2
2
2
2
2
2

15.1. Simulations on the time-aggregated graph#

# let's choose a random seed
import random

seed_links = edgelist[daystart]
print(len(seed_links))

random.shuffle(seed_links)
seed = seed_links[0][0]

print("The degree of the seed is", G_agg.degree(seed))
24
The degree of the seed is 2
infected_nodes = []
infected_nodes.append(seed)

for n in G_agg.nodes():
    if n in infected_nodes:
        G_agg.disease_status[n] = 1
        # infected
    else:
        G_agg.disease_status[n] = 0
        # susceptible
from tqdm import tqdm
Itime_agg = []

# there are 1000 days of network activity but the network does not change!

for t in tqdm(list(range(0, 1000))):
    for i in infected_nodes:
        for j in G_agg.neighbors(i):
            if G_agg.disease_status[j] == 0:
                G_agg.disease_status[j] = 1  # the probability of infection is 1!!

    # ciclo per aggiornare l'elenco dei nodi infetti
    infected_nodes = []
    for n in G_agg.nodes():
        if G_agg.disease_status[n] == 1:
            infected_nodes.append(n)
    # for-loop aggionrmento nodi guariti

    Itime_agg.append(len(infected_nodes))

print(
    "The final size of the epidemic is", float(len(infected_nodes)) / len(G_agg.nodes())
)
  0%|                                                                                                                                                                              | 0/1000 [00:00<?, ?it/s]
  2%|██▊                                                                                                                                                                 | 17/1000 [00:00<00:05, 166.44it/s]
  3%|█████▌                                                                                                                                                              | 34/1000 [00:00<00:05, 161.83it/s]
  5%|████████▎                                                                                                                                                           | 51/1000 [00:00<00:05, 162.19it/s]
  7%|███████████▏                                                                                                                                                        | 68/1000 [00:00<00:05, 162.77it/s]
  8%|█████████████▉                                                                                                                                                      | 85/1000 [00:00<00:05, 163.02it/s]
 10%|████████████████▋                                                                                                                                                  | 102/1000 [00:00<00:05, 161.50it/s]
 12%|███████████████████▍                                                                                                                                               | 119/1000 [00:00<00:05, 159.84it/s]
 14%|██████████████████████▏                                                                                                                                            | 136/1000 [00:00<00:05, 160.93it/s]
 15%|████████████████████████▉                                                                                                                                          | 153/1000 [00:00<00:05, 161.34it/s]
 17%|███████████████████████████▋                                                                                                                                       | 170/1000 [00:01<00:05, 156.14it/s]
 19%|██████████████████████████████▎                                                                                                                                    | 186/1000 [00:01<00:05, 151.57it/s]
 20%|████████████████████████████████▉                                                                                                                                  | 202/1000 [00:01<00:05, 145.94it/s]
 22%|███████████████████████████████████▎                                                                                                                               | 217/1000 [00:01<00:05, 143.46it/s]
 23%|█████████████████████████████████████▊                                                                                                                             | 232/1000 [00:01<00:05, 143.50it/s]
 25%|████████████████████████████████████████▍                                                                                                                          | 248/1000 [00:01<00:05, 146.47it/s]
 26%|██████████████████████████████████████████▊                                                                                                                        | 263/1000 [00:01<00:05, 145.26it/s]
 28%|█████████████████████████████████████████████▎                                                                                                                     | 278/1000 [00:01<00:05, 143.07it/s]
 29%|███████████████████████████████████████████████▊                                                                                                                   | 293/1000 [00:01<00:04, 142.96it/s]
 31%|██████████████████████████████████████████████████▎                                                                                                                | 309/1000 [00:02<00:04, 146.72it/s]
 33%|█████████████████████████████████████████████████████▏                                                                                                             | 326/1000 [00:02<00:04, 150.99it/s]
 34%|███████████████████████████████████████████████████████▋                                                                                                           | 342/1000 [00:02<00:04, 153.18it/s]
 36%|██████████████████████████████████████████████████████████▎                                                                                                        | 358/1000 [00:02<00:04, 154.51it/s]
 37%|████████████████████████████████████████████████████████████▉                                                                                                      | 374/1000 [00:02<00:04, 152.73it/s]
 39%|███████████████████████████████████████████████████████████████▌                                                                                                   | 390/1000 [00:02<00:04, 148.76it/s]
 40%|██████████████████████████████████████████████████████████████████                                                                                                 | 405/1000 [00:02<00:04, 146.95it/s]
 42%|████████████████████████████████████████████████████████████████████▍                                                                                              | 420/1000 [00:02<00:03, 145.74it/s]
 44%|██████████████████████████████████████████████████████████████████████▉                                                                                            | 435/1000 [00:02<00:03, 146.14it/s]
 45%|█████████████████████████████████████████████████████████████████████████▌                                                                                         | 451/1000 [00:02<00:03, 148.88it/s]
 47%|████████████████████████████████████████████████████████████████████████████                                                                                       | 467/1000 [00:03<00:03, 149.76it/s]
 48%|██████████████████████████████████████████████████████████████████████████████▌                                                                                    | 482/1000 [00:03<00:03, 147.51it/s]
 50%|█████████████████████████████████████████████████████████████████████████████████                                                                                  | 497/1000 [00:03<00:03, 145.53it/s]
 51%|███████████████████████████████████████████████████████████████████████████████████▍                                                                               | 512/1000 [00:03<00:03, 143.27it/s]
 53%|█████████████████████████████████████████████████████████████████████████████████████▉                                                                             | 527/1000 [00:03<00:03, 142.69it/s]
 54%|████████████████████████████████████████████████████████████████████████████████████████▌                                                                          | 543/1000 [00:03<00:03, 145.52it/s]
 56%|███████████████████████████████████████████████████████████████████████████████████████████                                                                        | 559/1000 [00:03<00:02, 147.80it/s]
 57%|█████████████████████████████████████████████████████████████████████████████████████████████▋                                                                     | 575/1000 [00:03<00:02, 150.05it/s]
 59%|████████████████████████████████████████████████████████████████████████████████████████████████▎                                                                  | 591/1000 [00:03<00:02, 152.72it/s]
 61%|███████████████████████████████████████████████████████████████████████████████████████████████████                                                                | 608/1000 [00:04<00:02, 156.41it/s]
 62%|█████████████████████████████████████████████████████████████████████████████████████████████████████▋                                                             | 624/1000 [00:04<00:02, 156.12it/s]
 64%|████████████████████████████████████████████████████████████████████████████████████████████████████████▎                                                          | 640/1000 [00:04<00:02, 156.81it/s]
 66%|██████████████████████████████████████████████████████████████████████████████████████████████████████████▉                                                        | 656/1000 [00:04<00:02, 157.38it/s]
 67%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████▌                                                     | 672/1000 [00:04<00:02, 157.79it/s]
 69%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏                                                  | 688/1000 [00:04<00:01, 157.83it/s]
 70%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉                                                | 705/1000 [00:04<00:01, 160.67it/s]
 72%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▋                                             | 722/1000 [00:04<00:01, 157.76it/s]
 74%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▎                                          | 738/1000 [00:04<00:01, 152.76it/s]
 75%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉                                        | 754/1000 [00:04<00:01, 149.89it/s]
 77%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▌                                     | 770/1000 [00:05<00:01, 147.87it/s]
 78%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉                                   | 785/1000 [00:05<00:01, 145.95it/s]
 80%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▍                                | 800/1000 [00:05<00:01, 144.67it/s]
 82%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████                              | 816/1000 [00:05<00:01, 146.77it/s]
 83%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▍                           | 831/1000 [00:05<00:01, 147.48it/s]
 85%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏                        | 848/1000 [00:05<00:01, 151.91it/s]
 86%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▊                      | 864/1000 [00:05<00:00, 153.49it/s]
 88%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▌                   | 881/1000 [00:05<00:00, 156.55it/s]
 90%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▎                | 898/1000 [00:05<00:00, 158.70it/s]
 92%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▏             | 915/1000 [00:06<00:00, 159.96it/s]
 93%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▊           | 931/1000 [00:06<00:00, 154.97it/s]
 95%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▎        | 947/1000 [00:06<00:00, 150.69it/s]
 96%|████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▉      | 963/1000 [00:06<00:00, 148.67it/s]
 98%|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████▌   | 979/1000 [00:06<00:00, 149.91it/s]
100%|██████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 1000/1000 [00:06<00:00, 151.69it/s]
The final size of the epidemic is 0.9345480275959668

plt.figure(figsize=(10, 7))
plt.xlabel("Time", fontsize=18)
plt.ylabel("Infected individuals", fontsize=18)
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.plot(range(0, len(Itime_agg)), Itime_agg)
plt.axis([0, 20, -1, 10600])
(0.0, 20.0, -1.0, 10600.0)
../_images/f0692acfefbdfcc8a75d6a30c998d441e5fa74c362e18a7e50e5908539c57cb3.png

15.2. Simulations on the full dynamic network#

G_dyn = nx.Graph()
G_dyn.disease_status = {}
seed_links = edgelist[daystart]
random.shuffle(seed_links)
seed = seed_links[0][0]
seed
98
infected_nodes = []
infected_nodes.append(seed)

G_dyn.add_edges_from(seed_links)  # we consider only the links that are active on day 0

for n in G_dyn.nodes():
    if n in infected_nodes:
        G_dyn.disease_status[n] = 1
        # infected
    else:
        G_dyn.disease_status[n] = 0
        # susceptible
Itime_dyn = []

for t in range(daystart, dayend + 1):
    links = edgelist[t]  # these are the links active on day t

    if t == daystart:
        print("The temporal network has", len(G_dyn.nodes()), "nodes on day", daystart)
        print("The temporal network has", len(G_dyn.edges()), "edges on day", daystart)
        print("The degree of the seed is", G_dyn.degree(seed))
    else:
        G_dyn.add_edges_from(links)
        for e in links:
            if e[0] not in G_dyn.disease_status:
                G_dyn.disease_status[e[0]] = 0
            if e[1] not in G_dyn.disease_status:
                G_dyn.disease_status[e[1]] = 0

    # ciclo sui nodi infetti per la trasmissione
    for i in infected_nodes:
        for j in G_dyn.neighbors(i):
            if G_dyn.disease_status[j] == 0:
                G_dyn.disease_status[j] = 1

    # ciclo per aggiornare l'elenco dei nodi infetti
    infected_nodes = []
    for n in G_dyn.nodes():
        if G_dyn.disease_status[n] == 1:
            infected_nodes.append(n)

    Itime_dyn.append(len(infected_nodes))

    # stampo il numero di nodi infetti a ogni time-step
    G_dyn.remove_edges_from(links)

print(
    "The final size of the epidemic is", float(len(infected_nodes)) / len(G_dyn.nodes())
)
The temporal network has 22 nodes on day 800
The temporal network has 12 edges on day 800
The degree of the seed is 1
The final size of the epidemic is 0.7244825756235627
plt.figure(figsize=(10, 7))
plt.xticks(fontsize=14)
plt.yticks(fontsize=14)
plt.xlabel("time", fontsize=18)
plt.ylabel("infected individuals", fontsize=18)
plt.plot(range(0, len(Itime_agg)), Itime_agg, label="static")
plt.plot(range(0, len(Itime_dyn)), Itime_dyn, label="dynamic")
plt.legend()
# plt.axis([0,365,-1,10600])
<matplotlib.legend.Legend at 0x1779a3a30>
../_images/7088eb748a23ee9235dda74da9945bd2f105c466bedc25314a81ec686664f053.png

15.3. homeworks#

  • does it accelerate if randomized?

  • does it if clustering coefficient (triangles)?

  • does it if temporal clustering?