DEV Community

Cover image for How to Analyze Complex Networks in Python: From Social Media to Infrastructure Systems
Nithin Bharadwaj
Nithin Bharadwaj

Posted on

How to Analyze Complex Networks in Python: From Social Media to Infrastructure Systems

As a best-selling author, I invite you to explore my books on Amazon. Don't forget to follow me on Medium and show your support. Thank you! Your support means the world!

Working with networks in Python feels like having a map to invisible cities. I can take raw connection data—who emails whom, which proteins interact, how websites link to each other—and start to see the shape of the entire system. The patterns that emerge tell stories about influence, resilience, and community. Let me share how I do this, piece by piece, using some straightforward techniques.

First, you need to build the map, which is your graph. Think of a graph as a collection of points, called nodes, connected by lines, called edges. In Python, NetworkX makes this simple. You start by creating an empty graph object.

import networkx as nx

# I'll create a graph to model a simple social network
social_graph = nx.Graph()

# I add people as nodes. I can even store details about them.
social_graph.add_node("Alice", age=34, role="Developer")
social_graph.add_node("Bob", age=28, role="Designer")
social_graph.add_nodes_from(["Charlie", "Diana"])

# Now, I define relationships as edges. Maybe Alice and Bob are friends.
social_graph.add_edge("Alice", "Bob", relation="friends", strength=8)
# Charlie and Diana are coworkers who collaborated on 5 projects.
social_graph.add_edge("Charlie", "Diana", relation="coworkers", projects=5)

print(f"My network has {social_graph.number_of_nodes()} people.")
print(f"They have {social_graph.number_of_edges()} connections between them.")
print(f"Details on Alice: {social_graph.nodes['Alice']}")
Enter fullscreen mode Exit fullscreen mode

This is the foundation. Every analysis starts with building this structure correctly. You can model anything: friendships, computer networks, flight routes. The key is to decide what your nodes and edges represent. Is an edge just a yes/no connection, or does it have a weight or strength, like the number of messages exchanged? Defining this early shapes everything that follows.

Once you have a network, the immediate question is: who or what is important? Not all points on the map are equal. This is where centrality measures come in. They give you numbers that describe a node's importance from different angles. I use these all the time to find key influencers in social media data or critical hubs in an infrastructure network.

Let's calculate a few. Degree centrality is the simplest. It just counts how many direct connections a node has. The person with the most friends has the highest degree.

# I'll add a few more connections to make it interesting
social_graph.add_edges_from([("Alice", "Charlie"), ("Bob", "Diana"), ("Alice", "Diana")])

# Calculating degree centrality
degree_centrality = nx.degree_centrality(social_graph)
print("Who has the most direct connections?")
for person, score in sorted(degree_centrality.items(), key=lambda x: x[1], reverse=True):
    print(f"  {person}: {score:.3f}")
Enter fullscreen mode Exit fullscreen mode

But sometimes, the most important person isn't the one with the most friends. It's the bridge. Imagine someone who connects two separate friend groups. They control the flow of information. Betweenness centrality finds these bridges. It calculates how many shortest paths between all other pairs of nodes go through a given node.

betweenness_centrality = nx.betweenness_centrality(social_graph)
print("\nWho is the crucial bridge or connector?")
for person, score in sorted(betweenness_centrality.items(), key=lambda x: x[1], reverse=True):
    print(f"  {person}: {score:.3f}")
Enter fullscreen mode Exit fullscreen mode

I often combine these scores to get a fuller picture. The most connected person and the best bridge might be different, and understanding both is powerful.

Networks aren't just random connections; they form groups. Finding these hidden communities is my next step. It's like looking at a bustling city and identifying distinct neighborhoods where people interact more with each other than with outsiders. The Louvain method is a great way to do this automatically by optimizing a metric called modularity.

# Note: You may need to 'pip install python-louvain'
import community as community_louvain

# Detect communities
partition = community_louvain.best_partition(social_graph)

print("Community assignments:")
for node, comm_id in partition.items():
    print(f"  {node} -> Neighborhood {comm_id}")

# Let's see how good this grouping is
modularity_score = community_louvain.modularity(partition, social_graph)
print(f"\nModularity score: {modularity_score:.3f}")
# A score closer to 1 means strong, separate communities.
Enter fullscreen mode Exit fullscreen mode

When I run this on real data, like forum interactions, these communities often align perfectly with topics of interest or real-world social circles. It's satisfying to see the algorithm pick up on patterns you might only have guessed at.

Now, how do things flow through this network? If I need to send a message from Alice to Diana, what's the best path? Pathfinding algorithms answer this. The most famous is Dijkstra's algorithm, which finds the shortest path, especially when your connections have different "costs" or weights, like travel time or latency.

Let's assign some hypothetical travel times to our connections.

# Let's model our edges as having a 'travel_time' in minutes
social_graph.add_edge("Alice", "Bob", travel_time=5)
social_graph.add_edge("Bob", "Diana", travel_time=15)
social_graph.add_edge("Alice", "Charlie", travel_time=10)
social_graph.add_edge("Charlie", "Diana", travel_time=10)
social_graph.add_edge("Alice", "Diana", travel_time=25)

# Find the fastest path from Alice to Diana
fastest_path = nx.shortest_path(social_graph, source="Alice", target="Diana", weight='travel_time')
fastest_time = nx.shortest_path_length(social_graph, source="Alice", target="Diana", weight='travel_time')

print(f"The fastest path from Alice to Diana is: {fastest_path}")
print(f"It takes {fastest_time} minutes.")
# This will likely be Alice -> Charlie -> Diana (20 mins), not the direct 25-minute link.
Enter fullscreen mode Exit fullscreen mode

This is the basis for GPS navigation and network routing protocols. Seeing it work on a small scale helps you trust it on a massive one.

All this analysis is great, but a picture is worth a thousand data points. Visualizing a graph makes its structure immediate and intuitive. A good visualization can reveal patterns you'd miss in a table of numbers. I use NetworkX's drawing tools with Matplotlib.

import matplotlib.pyplot as plt

plt.figure(figsize=(8, 6))

# Use a layout algorithm to position nodes nicely. Spring layout is a good default.
pos = nx.spring_layout(social_graph, seed=42)

# Draw the basics
nx.draw_networkx_nodes(social_graph, pos, node_size=700, node_color='lightblue')
nx.draw_networkx_edges(social_graph, pos, width=2, alpha=0.5)
nx.draw_networkx_labels(social_graph, pos, font_size=12)

# Let's color nodes by the community we found earlier
node_colors = [partition[node] for node in social_graph.nodes()]
nx.draw_networkx_nodes(social_graph, pos, node_size=700, node_color=node_colors, cmap=plt.cm.Set2)

plt.title("My Social Network with Communities")
plt.axis('off')  # Turn off the axes
plt.tight_layout()
plt.show()
Enter fullscreen mode Exit fullscreen mode

When you run this, you'll see the nodes cluster visually. Alice, likely a central hub, might sit in the middle. The different colors will show the communities. I've spent hours tweaking these visualizations for reports because they communicate the insight instantly.

To understand the network's overall health and structure, I calculate graph metrics. Is it a tightly-knit web or a loose collection of separate clusters? How easily could it break apart? These metrics give me the answer.

print("Overall Network Metrics:")
print(f"  Density: {nx.density(social_graph):.3f}")
# Density measures how many possible connections actually exist.
# 1 means everyone is connected to everyone; 0 means no connections.

print(f"  Average Clustering: {nx.average_clustering(social_graph):.3f}")
# This tells me how much my friends are also friends with each other.
# High clustering means tight-knit groups.

# Check if the graph is connected (a path exists between every pair)
if nx.is_connected(social_graph):
    print("  The network is fully connected.")
    print(f"  Diameter: {nx.diameter(social_graph)}")
    # Diameter is the longest shortest path. It's a measure of how "wide" the network is.
else:
    print(f"  The network has {nx.number_connected_components(social_graph)} separate parts.")
Enter fullscreen mode Exit fullscreen mode

This is crucial for, say, designing a robust power grid. A high-density, well-connected grid might be more resilient to a single failure.

What's going to happen next? Link prediction tries to forecast new connections. If Alice and Bob both know Charlie, they're likely to meet. This technique powers the "People You May Know" feature on social networks.

# Let's predict which non-existent friendship is most likely
from itertools import combinations

# A simple but effective predictor: Count Common Neighbors
prediction_scores = []
for person_a, person_b in combinations(social_graph.nodes(), 2):
    if not social_graph.has_edge(person_a, person_b):  # If they are NOT already connected
        common_n = list(nx.common_neighbors(social_graph, person_a, person_b))
        score = len(common_n)
        if score > 0:  # Only list pairs with at least one common friend
            prediction_scores.append(((person_a, person_b), score, common_n))

# Sort by score, highest first
prediction_scores.sort(key=lambda x: x[1], reverse=True)

print("Top predicted new connections:")
for (p1, p2), score, common in prediction_scores[:3]:
    print(f"  {p1} and {p2} (Score: {score}). Common friends: {common}")
Enter fullscreen mode Exit fullscreen mode

Finally, networks aren't static. Friendships form, routers fail, trends evolve. Temporal network analysis handles this by looking at networks that change over time. You can think of it as a series of snapshots.

import pandas as pd
from datetime import datetime, timedelta

# Simulate some time-stamped messages
data = []
base_time = datetime(2023, 10, 27, 9, 0)  # Start at 9 AM

# Alice and Bob message frequently in the first hour
data.append({'time': base_time, 'from': 'Alice', 'to': 'Bob'})
data.append({'time': base_time + timedelta(minutes=10), 'from': 'Bob', 'to': 'Alice'})

# Later, a group chat with Charlie starts
data.append({'time': base_time + timedelta(hours=1), 'from': 'Alice', 'to': 'Charlie'})
data.append({'time': base_time + timedelta(hours=1, minutes=15), 'from': 'Charlie', 'to': 'Diana'})

df = pd.DataFrame(data)

print("Message log:")
print(df)

# Analyze the network for the first hour vs. the second hour
first_hour = df[df['time'] < base_time + timedelta(hours=1)]
second_hour = df[df['time'] >= base_time + timedelta(hours=1)]

G_first = nx.from_pandas_edgelist(first_hour, 'from', 'to', create_using=nx.Graph())
G_second = nx.from_pandas_edgelist(second_hour, 'from', 'to', create_using=nx.Graph())

print(f"\nFirst hour network: {G_first.number_of_edges()} connections.")
print(f"Second hour network: {G_second.number_of_edges()} connections.")
Enter fullscreen mode Exit fullscreen mode

By comparing G_first and G_second, I can see how the communication patterns shifted. This is essential for monitoring network health or tracking the spread of information over time.

These eight techniques—building the graph, measuring centrality, detecting communities, finding paths, visualizing, calculating metrics, predicting links, and analyzing over time—form a complete toolkit. I start with construction and basic metrics to understand what I'm working with. I use centrality and community detection to find the key players and groups. Pathfinding and link prediction help me model flow and growth. Visualization communicates it all, and temporal analysis brings it to life. Each project might use a different mix, but together, they let you turn a list of connections into a clear, actionable story about the system you're studying. The code I've shown is the starting point; from here, you can scale it up to thousands or millions of nodes, limited mostly by your computer's memory. It’s a practical, powerful way to make sense of our connected world.

📘 Checkout my latest ebook for free on my channel!

Be sure to like, share, comment, and subscribe to the channel!


101 Books

101 Books is an AI-driven publishing company co-founded by author Aarav Joshi. By leveraging advanced AI technology, we keep our publishing costs incredibly low—some books are priced as low as $4—making quality knowledge accessible to everyone.

Check out our book Golang Clean Code available on Amazon.

Stay tuned for updates and exciting news. When shopping for books, search for Aarav Joshi to find more of our titles. Use the provided link to enjoy special discounts!

Our Creations

Be sure to check out our creations:

Investor Central | Investor Central Spanish | Investor Central German | Smart Living | Epochs & Echoes | Puzzling Mysteries | Hindutva | Elite Dev | Java Elite Dev | Golang Elite Dev | Python Elite Dev | JS Elite Dev | JS Schools


We are on Medium

Tech Koala Insights | Epochs & Echoes World | Investor Central Medium | Puzzling Mysteries Medium | Science & Epochs Medium | Modern Hindutva

Top comments (0)