Show code
from matplotlib import pyplot as plt
import networkx as nx
'seaborn-v0_8-whitegrid')
plt.style.use(import numpy as np
from scipy.special import factorial
import pandas as pd
import random
Open the live notebook in Google Colab here.
In a previous chapter, we discussed several properties observed in empirical networks. One of the properties we observed was an (approximate) power law degree distribution. It has been famously claimed (Barabási and Albert 1999) that many empirical networks have power-law degrees, a claim which has also been famously disputed(Broido and Clauset 2019).
We’re not going to take a stance on the question of whether many empirical networks obey power laws in this chapter. Instead, we’ll focus on a modeling question: if we supposed that power laws are present in many real-world systems, how could we explain that? One way to address this question is via mathematical modeling: can we come up with a plausible mathematical model of networks that would reliably generate power-law degree distributions? There have been a number of such models proposed; in these notes we’ll discuss a variation on one of the most famous; the Yule-Simon-Price-Barabási-Albert model of preferential attachment.
To motivate our discussion, let’s take another look at a network which displays an approximate power law degree distribution. We’ll again use the twitch
data set collected from the streaming platform Twitch by Rozemberczki, Allen, and Sarkar (2021). Nodes are users on Twitch. An edge exists between them if they are mutual friends on the platform. The authors collected data sets for users speaking several different languages; we’ll use the network of English-speaking users. Let’s now download the data (as a Pandas data frame) and convert it into a graph using Networkx.
from matplotlib import pyplot as plt
import networkx as nx
'seaborn-v0_8-whitegrid')
plt.style.use(import numpy as np
from scipy.special import factorial
import pandas as pd
import random
= "https://raw.githubusercontent.com/benedekrozemberczki/MUSAE/master/input/edges/ENGB_edges.csv"
url = pd.read_csv(url)
edges = nx.from_pandas_edgelist(edges, "from", "to", create_using=nx.Graph)
G
= G.number_of_nodes()
num_nodes = G.number_of_edges()
num_edges
print(f"This graph has {num_nodes} nodes and {num_edges} edges. The mean degree is {2*num_edges/num_nodes:.1f}.")
This graph has 7126 nodes and 35324 edges. The mean degree is 9.9.
We’ll use the same helper functions for visualizing the degree distribution as a log-binned histogram as we used previously, implemented in the hidden code cell below.
def degree_sequence(G):
= nx.degree(G)
degrees = np.array([deg[1] for deg in degrees])
degree_sequence return degree_sequence
def log_binned_histogram(degree_sequence, interval = 5, num_bins = 20):
= np.histogram(degree_sequence, bins = min(int(len(degree_sequence)/interval), num_bins))
hist, bins = np.logspace(np.log10(bins[0]),np.log10(bins[-1]),len(bins))
bins = np.histogram(degree_sequence, bins = bins)
hist, bins = bins[1:] - bins[:-1]
binwidths = hist / binwidths
hist = hist/hist.sum()
p
return bins[:-1], p
def plot_degree_distribution(G, **kwargs):
= degree_sequence(G)
deg_seq = log_binned_histogram(deg_seq, **kwargs)
x, p ='none', edgecolors = 'cornflowerblue', linewidth = 2, label = "Data")
plt.scatter(x, p, facecolorsset(xlabel = "Degree", xlim = (0.5, x.max()*2))
plt.gca().set(ylabel = "Density")
plt.gca().
plt.gca().loglog()
plt.legend()return plt.gca()
Let’s use this function to inspect the degree distribution of the data:
= plot_degree_distribution(G, interval = 10, num_bins = 30) ax
There are a few things to notice about this degree distribution. First, most nodes have relatively small degrees, fewer than the mean of 9.9. However, there are a small number of nodes that have degrees which are much larger: almost two orders of magnitude larger! You can think of these nodes as “super stars” or “hubs” of the network; they may correspond to especially popular or influential accounts.
Recall that, from our discussion of the Erdős–Rényi model
= degree_sequence(G)
deg_seq = deg_seq.mean()
mean_degree = np.arange(1, 30, 1)
d_ = np.exp(-mean_degree)*(mean_degree**d_)/factorial(d_)
poisson
= plot_degree_distribution(G, interval = 10, num_bins = 30)
ax = 1, label = "Poisson fit", color = "grey", linestyle = "--")
ax.plot(d_, poisson, linewidth ax.legend()
Comparing the Poisson fit predicted by the Erdős–Rényi model to the actual data, we see that the the Poisson places much higher probability mass on degrees that are close to the mean of 9.9. The Poisson would predict that almost no nodes would have degree higher than
We often say that the Poisson has a “light right tail” – the probability mass allocated by the Poisson dramatically drops off as we move to the right of the mean. In contrast, the data itself appears to have a “heavy tail”: there is substantial probability mass even far to the right from the mean.
As we saw previously, power law distributions are linear when plotted on log-log axes. The expectation of a power-law distributed random variable is finite when
Let’s try plotting such a distribution against the data. Since the power law distribution is defined for all
= degree_sequence(G)
deg_seq = 30
cutoff = np.arange(cutoff, deg_seq.max(), 1)
d_ = 2.7
gamma = 18*d_**(-gamma)
power_law
= plot_degree_distribution(G, interval = 10, num_bins = 30)
ax = 1, label = fr"Power law: $\gamma = {gamma}$" , color = "grey", linestyle = "--")
ax.plot(d_, power_law, linewidth ax.legend()
The power law appears to be a much better fit than the Poisson to the tail of the distribution, making apparently reasonable predictions about the numbers of nodes with very high degrees.
The claim that a given network “follows a power law” is a bit murky: like other models, power laws are idealizations that no real data set matches exactly. The idea of a power law is also fundamentally asymptotic in nature: the power law that we fit to the data also predicts that we should see nodes of degree
Why would power-law degree distributions be common in empirical networks? A common way to answer questions like this is to propose a generative model. A generative model is a random network model that is intended to produce some kind of realistic structure. If the mechanism proposed by the generative model is plausible as a real, common mechanism, then we might expect that the large-scale structure generated by that model would be commonly observed.
Barabási and Albert (1999) are responsible for popularizing the claim that many empirical networks are scale-free. Alongside this claim, they offered a generative model called preferential attachment. The preferential attachment model offers a simple mechanism of network growth which leads to power-law degree distributions. Their model is closely related to the regrettably much less famous models of Yule (1925), Simon (1955), and Price (1976).
Here’s how the Yule-Simon-Price-Barabási-Albert model works. First, we start off with some initial graph
We repeat this process as many times as desired. Intuitively, the preferential attachment model expresses the idea that “the rich get richer”: nodes that already have many connections are more likely to receive new connections.
Here’s a quick implementation.
# initial condition
= nx.Graph()
G 0, 1)
G.add_edge(
= 4/5 # proportion of degree-based selection steps
alpha
# main loop
for _ in range(10000):
= nx.degree(G)
degrees
# determine u using one of two mechanisms
if np.random.rand() < alpha:
= np.array([deg[1] for deg in degrees])
deg_seq = deg_seq / deg_seq.sum()
degree_weights = np.random.choice(np.arange(len(degrees)), p = degree_weights)
u else:
= np.random.choice(np.arange(len(degrees)))
u
# integer index of new node v
= len(degrees)
v
# add new edge to graph
G.add_edge(u, v)
Let’s go ahead and plot the result. We’ll add a visualization of the exponent
= degree_sequence(G)
deg_seq = 10
cutoff = np.arange(cutoff, deg_seq.max(), 1)
d_ = (2 + alpha) / alpha
gamma = 10*d_**(-gamma)
power_law
= plot_degree_distribution(G, interval = 2, num_bins = 30)
ax = 1, label = fr"Power law: $\gamma = {gamma:.2f}$" , color = "grey", linestyle = "--")
ax.plot(d_, power_law, linewidth ax.legend()
This fit is somewhat noisy, reflecting the fact that we simulated a relatively small number of preferential attachment steps.
Let’s now see if we can understand mathematically why the preferential attachment model leads to networks with power-law degree distributions. There are many ways to demonstrate this fact, including both “casual” and highly rigorous techniques. Here, we’ll use a “casual” argument from Mitzenmacher (2004).
Let
Well, in the previous timestep there were
So, we can write down our estimate for the expected value of
Let’s compute the probabilities appearing on the righthand side. With probability
Of all the nodes we could pick,
A similar calculation shows that
so our expectation is
Up until now, everything has been exact: no approximations involved. Now we’re going to start making approximations and assumptions. These can all be justified by rigorous probabilistic arguments, but we won’t do this here.
To track these assumptions, we’ll use the symbol
With these assumptions, we can simplify. First, we’ll replace
Next, we’ll assume
Finally, we’ll assume stationarity:
After a long setup, this looks much more manageable! Our next step is to solve for
Now for a trick “out of thin air.” As
Applying this last approximation, we have shown that, for sufficiently large
This recurrence relation, if it were exact, would imply that
This concludes our argument. Although this argument contains many approximations, it is also possible to reach the same conclusion using fully rigorous probabilistic arguments (Bollobás et al. 2001).
We’ve shown that, when
which is a power law with
After the publication of Barabási and Albert (1999), there was a proliferation of papers purporting to find power-law degree distributions in empirical networks. For a time, the standard method for estimating the exponent
As they show, this estimate and related methods are much more reliable estimators of
An important cautionary note: the estimate
What if we are able to observe more than the degree distribution of a network? What if we could also observe the growth of the network, and actually know which edges were added at which times? Under such circumstances, it is possible to estimate more directly the extent to which a graph might grow via the preferential attachment mechanism, possibly alongside additional mechanisms. Overgoor, Benson, and Ugander (2019) supply details on how to estimate the parameters of a general class of models, including preferential attachment, from observed network growth.
Are power laws really that common in empirical data? Broido and Clauset (2019) controversially claimed that scale free networks are rare. In a bit more detail, the authors compare power-law distributions to several competing distributions as models of real-world network degree sequences. The authors find that that the competing models—especially lognormal distributions, which also have heavy tails—are often better fits to observed data than power laws. This paper stirred considerable controversy, which is briefly documented by Holme (2019).
© Heather Zinn Brooks and Phil Chodrow, 2025