5.4 Laplacian spectral embedding

5.4 Laplacian spectral embedding#

mode = "svg"

import matplotlib

font = {'family' : 'Dejavu Sans',
        'weight' : 'normal',
        'size'   : 20}

matplotlib.rc('font', **font)

import matplotlib
from matplotlib import pyplot as plt
import numpy as np
from graphbook_code import dcsbm

np.random.seed(0)

nk = 150
z = np.repeat([1,2], nk)
B = np.array([[0.6, 0.2], [0.2, 0.4]])
theta = np.tile(6**np.linspace(0, -1, nk), 2)
np.random.seed(0)
A, P = dcsbm(z, theta, B, return_prob=True)
from graspologic.embed import AdjacencySpectralEmbed as ase
from scipy.spatial import distance_matrix

d = 2  # the latent dimensionality
# estimate the latent position matrix with ase
Xhat = ase(n_components=d, svd_seed=0).fit_transform(A)
# compute the distance matrix
D = distance_matrix(Xhat, Xhat)
Xhat_rescaled = Xhat / theta[:,None]
D_rescaled = distance_matrix(Xhat_rescaled, Xhat_rescaled)
from graphbook_code import heatmap, plot_latents
import os
fig, axs = plt.subplots(2, 2, gridspec_kw={"width_ratios": [1.5, 2]}, figsize=(12, 12))

ase_lim=(np.min((np.min(Xhat[:, 0]), np.min(Xhat[:, 1]))), np.max((np.max(Xhat[:, 0]), np.max(Xhat[:, 1])))) 
resc_lim=(np.min((np.min(Xhat_rescaled[:, 0]), np.min(Xhat_rescaled[:, 1]))), np.max((np.max(Xhat_rescaled[:, 0]), np.max(Xhat_rescaled[:, 1])))) 

ax = plot_latents(Xhat, labels=z, title="(A) $\\hat X = ase(A)$", palette={1: "#000000", 2: "#999999"}, 
                  size=5, ax=axs[0][0], legend=False, xtitle="Dimension 1", ytitle="Dimension 2")
ax.set_title("(A) $\\hat X = ase(A)$", pad=42, fontsize=18, loc="left")
ax.set_xlim(*ase_lim)
ax.set_ylim(*ase_lim)
ax.set_xticks([-.5, 0, .5])
ax.set_yticks([-.5, 0, .5])
heatmap(D, title="(B) Distance Matrix for $\\hat X$", ax=axs[0][1],
        xticks=[0.5, 149.5, 299.5], xticklabels=[1, 150, 300], xtitle="Node",
        inner_hier_labels=z, legend_title="Eucl. dist.")

ax = plot_latents(Xhat_rescaled, labels=z, title="(C) $\\hat X$, rescaled by $\\vec \\theta$", 
                  palette={1: "#000000", 2: "#999999"}, size=5, ax=axs[1][0], legend=False,
                  xtitle="Dimension 1", ytitle="Dimension 2")
ax.set_xlim(*resc_lim)
ax.set_ylim(*resc_lim)
ax.set_xticks([-.5, 0, .5, 1])
ax.set_yticks([-.5, 0, .5, 1])
ax.set_title("(C) $\\hat X$, rescaled by $\\theta$", pad=42, fontsize=18, loc="left")
heatmap(D_rescaled, title="(D) Distance Matrix for rescaled $\\hat X$", ax=axs[1][1],
        xticks=[0.5, 149.5, 299.5], xticklabels=[1, 150, 300], xtitle="Node",
        inner_hier_labels=z, legend_title="")

fig.tight_layout()

os.makedirs("Figures", exist_ok=True)
fname = "dcsbm_ase"
if mode != "png":
    os.makedirs(f"Figures/{mode:s}", exist_ok=True)
    fig.savefig(f"Figures/{mode:s}/{fname:s}.{mode:s}")

os.makedirs("Figures/png", exist_ok=True)
fig.savefig(f"Figures/png/{fname:s}.png")
../../_images/fd42190235c40a2c7339f57ef4ab058b5ecadb145a76c08004b9bbf55822774f.png
from graspologic.embed import LaplacianSpectralEmbed as lse

d = 2  # embed into two dimensions
Xhat_lapl = lse(n_components=d, svd_seed=0).fit_transform(A)
D_lapl = distance_matrix(Xhat_lapl, Xhat_lapl)
fig, axs = plt.subplots(2, 2, gridspec_kw={"width_ratios": [1.5, 2]}, figsize=(12, 12))

lse_lim=(np.min((np.min(Xhat_lapl[:, 0]), np.min(Xhat_lapl[:, 1]))), np.max((np.max(Xhat_lapl[:, 0]), np.max(Xhat_lapl[:, 1])))) 

ax = plot_latents(Xhat, labels=z, title="(A) $\\hat X = ase(A)$", palette={1: "#000000", 2: "#999999"}, size=5, ax=axs[0][0], legend=False,
                 xtitle="Dimension 1", ytitle="Dimension 2")
ax.set_title("(A) $\\hat X = ase(A)$", pad=42, fontsize=18, loc="left")
ax.set_xlim(*ase_lim)
ax.set_ylim(*ase_lim)
ax.set_xticks([-.5, 0, .5])
ax.set_yticks([-.5, 0, .5])
heatmap(D, title="(B) Distance Matrix for $\\hat X$", ax=axs[0][1],
        xticks=[0.5, 149.5, 299.5], xticklabels=[1, 150, 300], xtitle="Node",
        inner_hier_labels=z, legend_title="Eucl. dist.")

ax = plot_latents(Xhat_lapl, labels=z, title="(C) $\\hat Y = lse(A)$", 
             palette={1: "#000000", 2: "#999999"}, size=5, ax=axs[1][0], legend=False,
                 xtitle="Dimension 1", ytitle="Dimension 2")
ax.set_xlim(*lse_lim)
ax.set_ylim(*lse_lim)
ax.set_title("(C) $\\hat Y = lse(A)$", pad=42, fontsize=18, loc="left")
heatmap(D_lapl, title="(D) Distance Matrix for $\\hat Y$", ax=axs[1][1],
        xticks=[0.5, 149.5, 299.5], xticklabels=[1, 150, 300], xtitle="Node",
        inner_hier_labels=z, legend_title="")

fig.tight_layout()

fname = "dcsbm_lse"
if mode != "png":
    fig.savefig(f"Figures/{mode:s}/{fname:s}.{mode:s}")

fig.savefig(f"Figures/png/{fname:s}.png")
../../_images/14447ab405bc178e7fd8f9ee22a322a62ed9a7f277bcdf88fdcb8aa7d080b0a3.png
import seaborn as sns
import pandas as pd

# compute the degrees for each node, using the
# row-sums of the network
degrees = A.sum(axis = 0)

# plot the degree histogram
df = pd.DataFrame({"Node degree" : degrees, "Community": z})
from graspologic.simulations import sbm

Asbm = sbm([nk, nk], B)

# row-sums of the network
degrees_sbm = Asbm.sum(axis = 0)
df_sbm = pd.DataFrame({"Node degree" : degrees_sbm, "Community": z})
fig, axs = plt.subplots(1, 2, figsize=(12, 4))

sns.histplot(data=df, x="Node degree", bins=20, color="black", ax=axs[0])
axs[0].set_title("$DCSBM_n(\\vec z, \\vec \\theta, B)$ sample")
axs[0].annotate("Heavy tail", xy=(35, 15), rotation=-25)
axs[0].annotate("", xy=(55, 10), xytext=(30, 25), arrowprops={"arrowstyle": "->"}, rotation=-25)
sns.histplot(data=df_sbm, x="Node degree", bins=20, color="black", ax=axs[1])
axs[1].set_title("$SBM_n(\\vec z, B)$ sample")
axs[1].annotate("No tail", xy=(140, 10), xytext=(140, 15), arrowprops={"arrowstyle": "->"})
axs[1].set_xlim(60, 160)

fig.tight_layout()

fname = "lse_degree"
if mode != "png":
    fig.savefig(f"Figures/{mode:s}/{fname:s}.{mode:s}")

fig.savefig(f"Figures/png/{fname:s}.png")
../../_images/582cbdf5cf010d74cfa44f0b2be546f85380d1216b7c7e5eb872cabe4c6fda33.png