Graph Embeddings
Graph embeddings compress relational networks into geometric vector coordinates where connected or structurally similar nodes sit close together.
Why Does This Exist?
Standard machine learning models like linear classifiers, gradient-boosted trees, and multi-layer perceptrons expect inputs formatted as rigid, fixed-dimensional feature vectors in Euclidean space . Real-world relational datasets—such as financial transaction trails, citation graphs, protein interactomes, and social networks—are fundamentally non-Euclidean: each entity has an arbitrary number of connections, unordered neighbors, and complex multihop dependencies.
Representing a graph of nodes naively via its adjacency matrix leads to catastrophic failure at scale. An adjacency row for a node is extremely high-dimensional, sparse (often over 99.9% zeros), and brittle: reordering node indices completely shuffles the vector, and the dot product between two disconnected nodes sharing a mutual neighbor evaluates to zero. Graph embeddings solve this disconnect by projecting discrete nodes, edges, or entire subgraphs into a compact, low-dimensional coordinate space (, often 64 to 256) where geometric operations like the dot product directly reflect topological proximity and structural equivalence.
Think of It Like This
Drawing a subway map on a flat sheet of paper
Imagine a massive underground transit network with thousands of stations connected by winding railway tunnels. In the real world, the tracks twist, double back, and span three dimensions across irregular terrain. An engineer wants to plan bus routes between stations without carrying around physical track blueprints.
A graph embedding is like laying out a simplified 2D subway map. You assign every station a set of coordinates on the page. Stations that share direct rail lines or belong to the same commercial district are placed close together. Remote transfer stations that serve identical commuter hubs end up in matching geometric zones. Once every station has a coordinate, you can measure transit relationships with a standard plastic ruler rather than traversing miles of subterranean track.
How It Actually Works
The Encoder-Decoder Framework
The universal formulation of node-level graph embeddings operates through an encoder-decoder framework. Given a graph , the encoder function maps each node to a low-dimensional vector .
In shallow (transductive) embedding algorithms, the encoder is simply an embedding lookup table parameterized by a matrix , such that:
where is an indicator one-hot vector for node .
The decoder function reconstructs pairwise relational similarity between nodes from their coordinate representations. The most common decoder is the inner product:
The training objective minimizes empirical discrepancy between the decoded vector proximity and a pre-defined graph similarity metric over all node pairs:
Depending on the definition of :
- First-order proximity sets , penalizing coordinates if immediate neighbors do not share a large dot product.
- Second-order proximity enforces that nodes sharing similar neighborhood probability distributions have nearby coordinates, even if no direct edge exists between and .
- High-order random walk proximity samples random walks to maximize the log-probability of co-occurrence within a temporal context window.
Worked Example
Consider a small 4-node undirected graph with edges , , and . We train a 2-dimensional embedding () using a dot-product decoder and a sigmoid cross-entropy loss with negative sampling.
Let the current embeddings be:
We compute the loss for a true positive edge and a sampled negative edge (nodes 1 and 4 have no direct connection):
-
Positive Pair : The inner product is: The predicted edge probability is: The positive loss contribution is:
-
Negative Pair : The inner product is: The negative probability is: The negative loss contribution is:
-
Total Pairwise Loss:
-
Gradient Update for : The gradient with respect to evaluates to: Using learning rate , the updated coordinate is: Node 1 moved closer to its true neighbor node 2 along dimension 0.
Code
import numpy as np
class ShallowGraphEmbedding: """Matrix-factorization style shallow node embedding table."""
def __init__(self, num_nodes: int, embedding_dim: int, lr: float = 0.05) -> None: self.num_nodes = num_nodes self.embedding_dim = embedding_dim self.lr = lr # Initialize embedding table with small Gaussian noise rng = np.random.default_rng(seed=42) self.embeddings: np.ndarray = rng.standard_normal((num_nodes, embedding_dim)) * 0.1
def _sigmoid(self, x: float) -> float: return float(1.0 / (1.0 + np.exp(-np.clip(x, -15.0, 15.0))))
def train_step(self, u: int, v_pos: int, v_neg: int) -> float: """Single SGD step optimizing positive edge (u, v_pos) against negative pair (u, v_neg).""" z_u = self.embeddings[u] z_pos = self.embeddings[v_pos] z_neg = self.embeddings[v_neg]
# Forward passes dot_pos = float(np.dot(z_u, z_pos)) dot_neg = float(np.dot(z_u, z_neg))
p_pos = self._sigmoid(dot_pos) p_neg = self._sigmoid(dot_neg)
loss = -np.log(max(p_pos, 1e-7)) - np.log(max(1.0 - p_neg, 1e-7))
# Gradient derivations grad_u = (p_pos - 1.0) * z_pos + p_neg * z_neg grad_pos = (p_pos - 1.0) * z_u grad_neg = p_neg * z_u
# In-place parameter updates self.embeddings[u] -= self.lr * grad_u self.embeddings[v_pos] -= self.lr * grad_pos self.embeddings[v_neg] -= self.lr * grad_neg
return float(loss)
# Verify executionmodel = ShallowGraphEmbedding(num_nodes=4, embedding_dim=2, lr=0.1)initial_loss = model.train_step(u=0, v_pos=1, v_neg=3)# -> initial_loss around 1.3863updated_sim = float(np.dot(model.embeddings[0], model.embeddings[1]))# -> similarity increases between connected nodesprint(f"Initial loss: {initial_loss:.4f}, Connected dot product: {updated_sim:.4f}")Watch Out For
The transductive out-of-vocabulary barrier
Shallow graph embeddings optimize a direct parameter lookup table with no shared weight functions. If a new user registers on your platform or a new molecule is synthesized, the model has no mechanism to produce an embedding without retraining the entire table from scratch.
When your graph exhibits constant dynamic node arrivals, do not rely on transductive lookup embeddings. Upgrade to inductive architectures (such as GraphSAGE or Message Passing Neural Networks) that parameterize node updates through shared neural aggregation functions over node feature attributes.
The Quick Version
- Graph embeddings map discrete, non-Euclidean graph topologies into compact, continuous vectors where Euclidean distances or dot products reflect network proximity.
- The encoder-decoder paradigm abstracts graph embeddings into an encoder that extracts coordinates and a decoder that reconstructs pairwise edge affinities.
- Shallow lookups optimize an explicit parameter vector per node, which is computationally fast for static networks but cannot generalize inductively to unseen nodes.