5.7 Estimating latent dimensionality and non positive semidefiniteness

5.7 Estimating latent dimensionality and non positive semidefiniteness#

mode = "svg"

import matplotlib

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

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

import matplotlib
from matplotlib import pyplot as plt
from graspologic.simulations import sbm
import numpy as np

# block matrix
n = 100
B = np.array([[0.6, 0.2], [0.2, 0.4]])
# network sample
np.random.seed(0)
A, z = sbm([n // 2, n // 2], B, return_labels=True)
from scipy.linalg import svdvals

# use scipy to obtain the singular values
s = svdvals(A)
from pandas import DataFrame
import seaborn as sns
import matplotlib.pyplot as plt


def plot_scree(svs, title="", ax=None):
    """
    A utility to plot the scree plot for a list of singular values
    svs.
    """
    if ax is None:
        fig, ax = plt.subplots(1,1, figsize=(10, 4))
    sv_dat = DataFrame({"Singular Value": svs, "Dimension": range(1, len(svs) + 1)})
    sns.scatterplot(data=sv_dat, x="Dimension", y="Singular Value", ax=ax, color="black")
    sns.lineplot(data=sv_dat, x="Dimension", y="Singular Value", ax=ax, color="black")
    ax.set_xlim([0.5, len(svs)])
    ax.set_ylim([0, svs.max() + 1])
    ax.set_title(title)
from matplotlib.patches import Ellipse
import os

fig, axs = plt.subplots(2, 1, figsize=(10, 10))

plot_scree(s, ax=axs[0], title="(A) Scree plot of $A$")
plot_scree(s[0:10], ax=axs[1], title="(B) Scree plot of first ten dimensions of $A$")

x0, y0 = axs[1].transAxes.transform((0, 0)) # lower left in pixels
x1, y1 = axs[1].transAxes.transform((1, 1)) # upper right in pixes

r = 5
# Create a circle annotation
circle = Ellipse((3, s[2]), 1, 9, color='black', fill="gray", alpha=0.2, linewidth=2)
axs[1].add_patch(circle)
axs[1].annotate("Elbow", xy=(3.1, s[2] + 5))

fig.tight_layout()

os.makedirs("Figures", exist_ok=True)
fname = "scree"
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/acd7e6c9776a3f46ae1f4a6eb2abee4ba1688611fbbdb7716ae9dbee0532f902.png
from graspologic.embed import AdjacencySpectralEmbed as ase

# use automatic elbow selection
Xhat_auto = ase(svd_seed=0).fit_transform(A)
from graspologic.embed import AdjacencySpectralEmbed as ase
from scipy.spatial import distance_matrix

nk = 50  # the number of nodes in each community
B_indef = np.array([[.1, .5], [.5, .2]])
np.random.seed(0)
A_dis, z = sbm([nk, nk], B_indef, return_labels=True)
Xhat = ase(n_components=2, svd_seed=0).fit_transform(A_dis)
D = distance_matrix(Xhat, Xhat)
from graphbook_code import heatmap, plot_latents

fig, axs = plt.subplots(1, 3, figsize=(17, 6), gridspec_kw={"width_ratios": [1, .6, 1]})

heatmap(A_dis.astype(int), ax=axs[0], inner_hier_labels=z+1, title="(A) Network sample", xtitle="Node")
plot_latents(Xhat, labels=z + 1, palette={1: "#999999", 2: "#000000"}, title="(B) $\\hat X = ase(A)$", s=30, ax=axs[1])
axs[1].get_legend().remove()
axs[1].set_xlabel("Dimension 1")
axs[1].set_ylabel("Dimension 2")
axs[1].set_title("(B) $\\hat X = ase(A)$", pad=45, loc="left", fontsize=20)
heatmap(D, ax=axs[2], inner_hier_labels=z+1, title="(C) Distance matrix for $\\hat X$", xtitle="Node", legend_title="Distance")

fig.tight_layout()

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

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