Published
Edited
May 31, 2019
1 fork
1 star
Insert cell
Insert cell
Insert cell
Insert cell
edges = southern_women.map(d => ({node_a: d.event, node_b: d.individual}))
Insert cell
Insert cell
Insert cell
Insert cell
Ka = 3
Insert cell
Kb = 3
Insert cell
Insert cell
node_groups = assign_random_groups(nodes);
Insert cell
Insert cell
Insert cell
prob_model = function(edges, nodes, nodes_w_groups) {
//================================================================================
// Step 1: Attach degrees and degree correction to the assignemnts
//================================================================================
// Start by appending number of edges/degrees onto each node's group assignment
nodes_w_groups.forEach(node => {
node.degree = nodes.find(n => n.id == node.id).degree;
});
// Calculate the total edges for each group
const group_degrees = d3_arr.rollup(
nodes_w_groups,
group => d3_arr.sum(group, d => d.degree),
d => d.type, d => d.group);
// Use the total edge counts to calculate each node's degree correction
nodes_w_groups.forEach(n => {
n.dc = n.degree/group_degrees.get(n.type).get(n.group);
});
//================================================================================
// Step 2: Find total number of edges between the groups
//================================================================================
// Helper function to take a node id and return that node's group.
const get_node_group = node_id => nodes_w_groups.find(n => n.id == node_id).group;

// Given a pair of groups, get the number of edges shared between them
const num_edges_between_groups = (a_group, b_group) => edges
.filter(e => get_node_group(e.node_a) === a_group && get_node_group(e.node_b) === b_group).length;
// Get edges between every pair of groups
const group_edges = d3_arr.cross(
init_array(Ka),
init_array(Kb),
(a_group, b_group) => ({
a_group, b_group,
edges: num_edges_between_groups(a_group, b_group),
})
);
//================================================================================
// Step 3: Calculate probability of graph
//================================================================================
// Calculate the probability for a given pair of nodes sharing an edge
const get_edge_prob = (a_node, b_node) => {
const nodes_connected = edges.find(e => e.node_a == a_node.id && e.node_b == b_node.id)? 1 : 0;
// How many edges due the two nodes groups' share?
const num_edges_between_groups = group_edges
.find(e => e.a_group == a_node.group && e.b_group == b_node.group)
.edges || 0;
const edge_lambda = (a_node.dc * b_node.dc) * num_edges_between_groups;
const edge_prob = Math.pow(edge_lambda, nodes_connected) * Math.exp(-edge_lambda);
if(edge_prob == 0) debugger;
return edge_prob;
};

// Get every pair of node's probability under current partitioning
const pair_probs = d3_arr.cross(
nodes_w_groups.filter(n => n.type == 'a'),
nodes_w_groups.filter(n => n.type == 'b'),
get_edge_prob
);
const total_prob = product(pair_probs);
// Return the product of all those probabilities
return total_prob
}
Insert cell
Insert cell
prob_model(edges, nodes, node_groups)
Insert cell
Insert cell
// Make a function that fixes the variables that we aren't going to change for simplicity
test_prob = group_assignment => prob_model(edges, nodes, group_assignment);
Insert cell
swap_node_groups = (node_groups, test_prob) => {

const swap_results = [];
for(let swap_ind = 0; swap_ind < node_groups.length; swap_ind++){
const curr_node = node_groups[swap_ind];
const starting_group = curr_node.group;

// Remove the node's current group from posibilities
const available_groups = init_array(curr_node.type === 'a' ? Ka : Kb)
.filter(g => g !== starting_group);

// Sample a new group from remaining group options
const new_group = sample(available_groups);

// Swap the group
curr_node.group = new_group;

// Record new probability
// Return results
swap_results.push({
node: swap_ind,
new_group: new_group,
probability: test_prob(node_groups),
});

// Reset the node to its original group
curr_node.group = starting_group;
}
return swap_results;
}
Insert cell
model_state = {
const model_probs = [];
const num_itts = 100;
const num_chains = 6;
for(let chain = 0; chain < num_chains; chain++){
const node_groupings = assign_random_groups(nodes);

for(let i = 0; i < num_itts; i++){

const swap_results = swap_node_groups(node_groupings, test_prob);

// Find the best swap
const best_swap = d3_arr.least(swap_results, swap => -swap.probability);

// Perform the best swap found
node_groupings[best_swap.node].group = best_swap.new_group;

// Record the new model prob
model_probs.push({
step: i,
prob: best_swap.probability,
chain,
current_chain: true,
});

yield {
current_chain: chain,
groupings: node_groupings,
training_history: model_probs,
};
await Promises.delay(5);
}
model_probs.forEach(d => {
d.current_chain = false;
});
}
}
Insert cell
Insert cell
Insert cell
Insert cell
height = 400
Insert cell
Insert cell
sample = arr => arr[gen_discrete_unif(0,arr.length-1)]
Insert cell
// Do a psuedo deep copy on an array of objects.
import {copy_array} from "@nstrayer/javascript-statistics-snippets"
Insert cell
import {product} from "@nstrayer/javascript-statistics-snippets"
Insert cell
import {gen_discrete_unif} from "@nstrayer/javascript-statistics-snippets@84"
Insert cell
import {init_array} from "@nstrayer/javascript-statistics-snippets@84"
Insert cell
import {weighted_sample} from "@nstrayer/javascript-statistics-snippets"
Insert cell
import {unique} from "@nstrayer/javascript-statistics-snippets"
Insert cell
southern_women = [
{"event":"event_0","individual":"ind_0"},{"event":"event_1","individual":"ind_0"},{"event":"event_2","individual":"ind_0"},{"event":"event_3","individual":"ind_0"},{"event":"event_4","individual":"ind_0"},{"event":"event_5","individual":"ind_0"},{"event":"event_7","individual":"ind_0"},{"event":"event_8","individual":"ind_0"},{"event":"event_0","individual":"ind_1"},{"event":"event_1","individual":"ind_1"},{"event":"event_2","individual":"ind_1"},{"event":"event_4","individual":"ind_1"},{"event":"event_5","individual":"ind_1"},{"event":"event_6","individual":"ind_1"},{"event":"event_7","individual":"ind_1"},{"event":"event_1","individual":"ind_2"},{"event":"event_2","individual":"ind_2"},{"event":"event_3","individual":"ind_2"},{"event":"event_4","individual":"ind_2"},{"event":"event_5","individual":"ind_2"},{"event":"event_6","individual":"ind_2"},{"event":"event_7","individual":"ind_2"},{"event":"event_8","individual":"ind_2"},{"event":"event_0","individual":"ind_3"},{"event":"event_2","individual":"ind_3"},{"event":"event_3","individual":"ind_3"},{"event":"event_4","individual":"ind_3"},{"event":"event_5","individual":"ind_3"},{"event":"event_6","individual":"ind_3"},{"event":"event_7","individual":"ind_3"},{"event":"event_2","individual":"ind_4"},{"event":"event_3","individual":"ind_4"},{"event":"event_4","individual":"ind_4"},{"event":"event_6","individual":"ind_4"},{"event":"event_2","individual":"ind_5"},{"event":"event_4","individual":"ind_5"},{"event":"event_5","individual":"ind_5"},{"event":"event_7","individual":"ind_5"},{"event":"event_4","individual":"ind_6"},{"event":"event_5","individual":"ind_6"},{"event":"event_6","individual":"ind_6"},{"event":"event_7","individual":"ind_6"},{"event":"event_5","individual":"ind_7"},{"event":"event_7","individual":"ind_7"},{"event":"event_8","individual":"ind_7"},{"event":"event_4","individual":"ind_8"},{"event":"event_6","individual":"ind_8"},{"event":"event_7","individual":"ind_8"},{"event":"event_8","individual":"ind_8"},{"event":"event_6","individual":"ind_9"},{"event":"event_7","individual":"ind_9"},{"event":"event_8","individual":"ind_9"},{"event":"event_11","individual":"ind_9"},{"event":"event_7","individual":"ind_10"},{"event":"event_8","individual":"ind_10"},{"event":"event_9","individual":"ind_10"},{"event":"event_11","individual":"ind_10"},{"event":"event_7","individual":"ind_11"},{"event":"event_8","individual":"ind_11"},{"event":"event_9","individual":"ind_11"},{"event":"event_11","individual":"ind_11"},{"event":"event_12","individual":"ind_11"},{"event":"event_13","individual":"ind_11"},{"event":"event_6","individual":"ind_12"},{"event":"event_7","individual":"ind_12"},{"event":"event_8","individual":"ind_12"},{"event":"event_9","individual":"ind_12"},{"event":"event_11","individual":"ind_12"},{"event":"event_12","individual":"ind_12"},{"event":"event_13","individual":"ind_12"},{"event":"event_5","individual":"ind_13"},{"event":"event_6","individual":"ind_13"},{"event":"event_8","individual":"ind_13"},{"event":"event_9","individual":"ind_13"},{"event":"event_10","individual":"ind_13"},{"event":"event_11","individual":"ind_13"},{"event":"event_12","individual":"ind_13"},{"event":"event_13","individual":"ind_13"},{"event":"event_6","individual":"ind_14"},{"event":"event_7","individual":"ind_14"},{"event":"event_9","individual":"ind_14"},{"event":"event_10","individual":"ind_14"},{"event":"event_11","individual":"ind_14"},{"event":"event_7","individual":"ind_15"},{"event":"event_8","individual":"ind_15"},{"event":"event_8","individual":"ind_16"},{"event":"event_10","individual":"ind_16"},{"event":"event_8","individual":"ind_17"},{"event":"event_10","individual":"ind_17"}]
Insert cell
Insert cell
d3 = require("d3@5")
Insert cell
d3_arr = require("d3-array@^2.2")
Insert cell
vegalite = require("@observablehq/vega-lite@0.1")
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more