Source code for thema.expansion.realtor
import numpy as np
from scipy.spatial.distance import cdist
[docs]
class Realtor:
"""
Find a the best location for an incoming target node in the cosmic neighborhood.
"""
def __init__(self, target_vector, graph, node_features, group_features):
self.target = target_vector
self.node_features = node_features
self.group_features = group_features
self.graph = graph
[docs]
def random_walk(self, n_samples=1000, m_steps=1000, metric="euclidean"):
"""
A MCMC inspired method for obtaining a collection of node locations from a
distribution considering both graph structure and feature differences.
"""
G = self.graph
node_distances = cdist([self.target], self.node_features, metric=metric)
group_distances = cdist([self.target], self.group_features, metric=metric)
samples = []
for _ in range(n_samples):
# select a random starting point
current_node = np.random.choice(list(G.nodes))
for __ in range(m_steps):
# choose a neighbor (including self loops) based on feature distances
neighbors = list(G.neighbors(current_node)) + [current_node]
neighbor_distances = node_distances[0, [int(nb) for nb in neighbors]]
t_probabilities = neighbor_distances / sum(neighbor_distances)
current_node = np.random.choice(neighbors, p=t_probabilities)
# if no good local choices, jump somewhere else with prob 1/4
if (
max(neighbor_distances)
> np.average(group_distances) # could take Nth quantile here.
and np.random.rand() < 1 / 4
):
current_node = np.random.choice(list(G.nodes))
# After 1000 steps, add to sample
samples.append(current_node)
return samples
[docs]
def node_docking(self, metric="euclidean"):
distances = cdist([self.target], self.node_features, metric=metric)
best_node_index = np.argmin(distances)
return best_node_index