In [1]:
from __future__ import division

from sys import stdout

import numpy as np
import networkx as nx

from sklearn.metrics import normalized_mutual_info_score
from sklearn.metrics.pairwise import euclidean_distances
from sklearn.metrics import pairwise_distances_argmin_min

import matplotlib.pyplot as plt

from itertools import repeat

from Queue import Queue
from threading import Thread
from threading import current_thread

MIN_EXPANSION_SIZE = 50
MAX_DELETED_NEURONS = 3

#########################################################################################################################

##function to visualise graph
def visualise_graph(G, colours, layer):
        
    ## create new figure for graph plot
    fig, ax = plt.subplots()
    
    # graph layout
    pos = nx.spring_layout(G)
    
    #attributes in this graph
    attributes = np.unique([v for k, v in nx.get_node_attributes(G, "assigned_community_layer_{}".format(layer)).items()])

    # draw nodes -- colouring by cluster
    for i in range(min(len(colours), len(attributes))):
       
        node_list = [n for n in G.nodes() if G.node[n]["assigned_community_layer_{}".format(layer)] == attributes[i]]
        colour = [colours[i] for n in range(len(node_list))]
        
        nx.draw_networkx_nodes(G, pos, nodelist=node_list, node_color=colour)
        
    #draw edges
    nx.draw_networkx_edges(G, pos)

    # draw labels
    nx.draw_networkx_labels(G, pos)
    
    #title of plot
    plt.title('Nodes coloured by cluster, layer: {}'.format(layer))

    #show plot
    plt.show()

## visualise graph based on network clusters
def visualise_network(network, colours, layer):
    
    #num neurons in lattice
    num_neurons = len(network)

    ##create new figure for lattice plot
    fig, ax = plt.subplots()
    
    # graph layout
    pos = nx.spring_layout(network)

    # draw nodes -- colouring by cluster
    for i in range(len(colours)):
        nx.draw_networkx_nodes(network, pos, nodelist = [network.nodes()[i]], node_color = colours[i])

    #draw edges
    nx.draw_networkx_edges(network, pos)

    # draw labels
    nx.draw_networkx_labels(network, pos)
    
    #label axes
    plt.title('Neurons in lattice, layer: '+str(layer))
    
    #show lattice plot
    plt.show()

##########################################################################################################################

#function to generate real valued som for graph input
#three initial nodes
def initialise_network(ID, X, starting_nodes=4):
    
    #network will be a one dimensional list
    network = nx.Graph(ID = ID)
    
    #initialise a network with just one neuron
    network.add_nodes_from(range(1, starting_nodes + 1))
    
    #id of nodes
    for n in network.nodes():
        network.node[n]["ID"] = "{}-{}".format(ID, str(n).zfill(2))
        
    #connect nodes     
    for i in range(1, starting_nodes + 1):
        for j in range(i + 1, starting_nodes + 1):
            network.add_edge(i, j)
    
    #assign a random vector in X to be the weight
    V = X[np.random.randint(len(X), size=starting_nodes)]

    return network, V

#########################################################################################################################

def precompute_sigmas(sigma, num_epochs):
    
    return np.array([sigma * np.exp(-2 * sigma * e / num_epochs)
                     for e in range(num_epochs)])

##########################################################################################################################
##TODO
# function to train SOM on given graph
def train_network(X, network, V, num_epochs, eta_0, precomputed_sigmas):
    
    #initial learning rate
    eta = eta_0
    
    #list if all patterns to visit
    training_patterns = range(len(X))
    
    #shortest path matrix
    shortest_path = np.array(nx.floyd_warshall_numpy(network))
    
#     net_change = np.zeros((V.shape))
    
    for e in range(num_epochs):
        
        #shuffle nodes
        np.random.shuffle(training_patterns)
        
        sigma = precomputed_sigmas[e]
        
        # iterate through N nodes of graph
        for i in training_patterns:
            
            #data point to consider
            x = X[i]
            
            #determine winning neuron
            closest_neuron = winning_neuron(x, V)
            
            # update weights
            deltaV = update_weights(x, V, closest_neuron, shortest_path[closest_neuron], eta, sigma)
            
            #weight update (vectorised)
            V += deltaV

#             net_change += deltaV
            
#     print "TRAINING COMPLETED"
#     print net_change
#     print np.linalg.norm(net_change, axis=1)
            
    return V
        
##########################################################################################################################

# winning neuron
def winning_neuron(x, V):
    
    distances = np.linalg.norm(x - V, axis=1)
    
    return distances.argmin()

##########################################################################################################################

# function to update weights
def update_weights(x, V, winning_neuron, shortest_path_length, eta, sigma):
    
    #weight update (vectorised)
    return np.dot(np.diag(eta * np.exp(- shortest_path_length ** 2 / (2 * sigma ** 2))), 
                      (x - V))

########################################################################################################################   

# assign nodes into clusters
def assign_nodes(names, X, network, V):
    
    #distance from each datapoint (row) to each weight vector (column)
#     distances = euclidean_distances(X, V)
    
    #
    arg_min_distances, min_distances = pairwise_distances_argmin_min(X, V)

    #nodes corresponding to minimum index (of length len(X))
    minimum_nodes = np.array([network.nodes()[n] for n in arg_min_distances])

    #list of neurons with no assignments
    empty_neurons = np.array([n for n in network.nodes() if n not in minimum_nodes])
    
    if empty_neurons.size > 0:
    
        ################################################DELETION####################################################

        #neighbours of deleted neurons
        neighbour_lists = np.array([network.neighbors(n) for n in empty_neurons])
        
        print "DELETING NODES: {}".format(empty_neurons)
        
        #remove the nodes
        network.remove_nodes_from(empty_neurons)
        
        ##remove from V
        V = np.array([V[i] for i in range(len(V)) if i in arg_min_distances])
        
        #compute distances between all neurons in input space
        computed_neuron_distances = compute_euclidean_distances(network, V)
        
        ##connect separated components
        for neighbour_list in neighbour_lists:
            connect_components(network, neighbour_list, computed_neuron_distances)

        ############################################################################################################

    #array of errors
    errors = np.array([np.mean(min_distances[minimum_nodes == n]) for n in network.nodes()])
    
    #compute MQE
    MQE = np.mean(errors)
    
    print "MQE={}, size of map={}".format(MQE, len(network))
    
    ##array of assignments
    assignments_array = np.array([np.array([names[i] for i in np.where(minimum_nodes == n)[0]]) for n in network.nodes()])
    
    #zip zith nodes
    errors = {n: e for n, e in zip(network.nodes(), errors)}
    assignments = {n: a for n, a in zip(network.nodes(), assignments_array)}
    
#     print "ERRORS"
#     print errors
#     print "number of nodes assigned to neurons"
#     print {n: len(a) for n, a in zip(network.nodes(), assignments_array)}
    
    nx.set_node_attributes(network, "e", errors)
    nx.set_node_attributes(network, "ls", assignments)
    
    return MQE, empty_neurons.size, V

##########################################################################################################################

def compute_euclidean_distances(network, V):
    
    distances = euclidean_distances(V)
    
    return {network.nodes()[i] : {network.nodes()[j] : distances[i, j] for j in range(len(distances[i]))}
           for i in range(len(distances))}
    
######################################################################################################################### 


def connect_components(network, neighbour_list, computed_neuron_distances):
    
    sub_network = network.subgraph(neighbour_list)
    
    connected_components = [sub_network.subgraph(c) for c in nx.connected_components(sub_network)]
    number_of_connected_components = len(connected_components)
    
    for i in range(number_of_connected_components):
        
        connected_component_1 = connected_components[i].nodes()
        
        for j in range(i + 1, number_of_connected_components):
            
            connected_component_2 = connected_components[j].nodes()
            
            distances = np.array([[computed_neuron_distances[n1][n2] for n2 in connected_component_2]
                                 for n1 in connected_component_1])
            
            min_n1, min_n2 = np.unravel_index(distances.argmin(), distances.shape)
            
            network.add_edge(connected_component_1[min_n1], 
                            connected_component_2[min_n2])

##########################################################################################################################
            
##function to identify neuron with greatest error
def identify_error_unit(network):
    
    errors = nx.get_node_attributes(network, "e")
    
#     print "ERROR UNIT"
#     print max(errors, key=errors.get)
    
    return max(errors, key=errors.get)

##########################################################################################################################

def expand_network(ID, named_X, network, V, error_unit):
    
    #v goes to random vector in range of error unit
    ls = network.node[error_unit]["ls"]    
    r = np.random.randint(len(ls))
    v = named_X[ls[r]]
    
    #zip nodes and distances
    distances = zip(network.nodes(), np.linalg.norm(V - v, axis=1))
        
    #identify neighbour pointing closet
    error_unit_neighbours = network.neighbors(error_unit)
    
    
    #id of new node
    new_node = max(network) + 1
    
    #add new node to map
    network.add_node(new_node)
    
    ##id
    network.node[new_node]["ID"] = "{}-{}".format(ID, str(new_node).zfill(2))
    
    #add edges to map
    
    #connect error unit and new node
    network.add_edge(error_unit, new_node)
    
    if len(error_unit_neighbours) > 0:
        
        ##find closest neighbour
        distances = {n: v for n, v in distances if n in error_unit_neighbours}
        closest_neighbour = min(distances, key=distances.get)
        
        #connect to error unit and closest neighbour
        network.add_edge(closest_neighbour, new_node)
        
    #add v to V
    V = np.vstack([V, v])   
    
    return V
        
##########################################################################################################################
##########################################################################################################################

##GHSOM algorithm
def ghsom(ID, named_X, num_iter, eta, sigma, e_0, e_sg, e_en, q):
    
    print "MQE_0={}, growth target={}".format(e_0, e_0 * e_sg)
    
    #separate names and matrix of node embedding
    names, X = zip(*named_X.items())
    names = np.array(names)
    X = np.array(X)
    
    #create som for this neuron
    network, V = initialise_network(ID, X)
    
    #precompute sigmas
    precomputed_sigmas = precompute_sigmas(sigma, num_iter)
    
    #train for lamda epochs
    V = train_network(X, network, V, num_iter, eta, precomputed_sigmas)
    
    #classify nodes and compute error
    MQE, num_deleted_neurons, V = assign_nodes(names, X, network, V)
    
    ##som growth phase
    #repeat until error is low enough
    while MQE > e_sg * e_0 and num_deleted_neurons < MAX_DELETED_NEURONS:
        
        #find neuron with greatest error
        error_unit = identify_error_unit(network)
        
        #expand network
        V = expand_network(ID, named_X, network, V, error_unit)
        
        #train for lam epochs
        V = train_network(X, network, V, num_iter, eta, precomputed_sigmas)

        #calculate mean network error
        MQE, deleted_neurons, V = assign_nodes(names, X, network, V)
        num_deleted_neurons += deleted_neurons
        
    print "growth terminated, MQE: {}, target: {}, number of deleted neurons: {}".format(MQE, 
                                            e_0 * e_sg, num_deleted_neurons)
        
    ##neuron expansion phase
    #iterate thorugh all neruons and find neurons with error great enough to expand
    for _, d in network.nodes(data=True):
        
        #unpack
        node_id = d["ID"]
        ls = d["ls"]
        e = d["e"]
        
        #check error
        if (e > e_en * e_0 and len(ls) > MIN_EXPANSION_SIZE and num_deleted_neurons < MAX_DELETED_NEURONS):
#         if (len(ls) > MIN_EXPANSION_SIZE and num_deleted_neurons < MAX_DELETED_NEURONS):
                
            sub_X = {k: named_X[k] for k in ls}
            
            print "submitted job: ID={}, e={}, number of nodes={}".format(node_id, e, len(ls))
            
            #add these parameters to the queue
            q.put((node_id, sub_X, num_iter, eta, sigma, e, e_sg, e_en))
    
    #return network
    return network, MQE

##########################################################################################################################
##########################################################################################################################

def label_nodes(G, networks):
    
    for _, network, _ in networks: 
        
        for _, d in network.nodes(data=True):
            
            community = d["ID"]
            layer = community.count("-")
            assignment_string = "assigned_community_layer_{}".format(layer)
            
            for node in d["ls"]:
                
                G.node[node][assignment_string] = community


##########################################################################################################################

def NMI_one_layer(G, label, layer):
    
    #actual community for this layer
    actual_community_labels = np.array([v for k, v in nx.get_node_attributes(G, label).items()])
    
    #predicted communitiy for this layer
    predicted_community_labels = np.array([v for k, v in nx.get_node_attributes(G, 
         "assigned_community_layer_{}".format(layer)).items()])

    print actual_community_labels
    print predicted_community_labels
    
    return normalized_mutual_info_score(actual_community_labels, predicted_community_labels)

def NMI_all_layers(G, labels):
    
    return np.array([NMI_one_layer(G, labels[len(labels) - 1 - i], i + 1) for i in range(len(labels))])

##########################################################################################################################

## get embedding
def get_embedding(G):

    return np.array([v for k, v in nx.get_node_attributes(G, "embedding").items()])
#     return np.array([v for k, v in nx.get_node_attributes(G, "embedding").items()])[:,:3]


##########################################################################################################################

def process_job(q, networks):
    
    #unpack first element of queue
    #contains all the para,eters for GHSOM
    ID, X, num_iter, eta, sigma, e_0, e_sg, e_en = q.get()

    #run GHSOM and return a network and MQE
    n, e = ghsom(ID, X, num_iter, eta, sigma, e_0, e_sg, e_en, q)

    #append result to networks list
    networks.append((ID, n, e))

    #mark task as done
    q.task_done()

def worker(q, networks):
    
    #continually poll queue for jobs 
    while True:
        process_job(q, networks)

def main(params, filename, num_iter=10000, num_threads=1):
    
    #network
    G = nx.read_gpickle(filename)
    
    #embedding matrix
    X = get_embedding(G)
    
    #zip with names
    named_X = {k: v for k, v in zip(G.nodes(), X)}
    
    ##list of returned networks
    networks = []
    
    #initilise worker queue
    q = Queue()
    
    ##initial MQE is variance of dataset
    m = np.mean(X, axis=0)
    MQE_0 = np.mean(np.linalg.norm(X - m, axis=1))
    
    #add initial layer of ghsom to queue
    q.put(("01", named_X, num_iter, params["eta"], params["sigma"], MQE_0, params["e_sg"], params["e_en"]))
    
    if num_threads > 1:
    
        #initialise threads
        for i in range(num_threads):

            t = Thread(target=worker, args=(q, networks))
            t.setDaemon(True)
            t.start()

        #finally wait until queue is empty and all tasks are done
        q.join()
        
    else :
        
        #single thread
        while not q.empty():
            process_job(q, networks)
    
    print "DONE"
    
    return G, networks

In [ ]:
params = {'eta': 0.001,
         'sigma': 0.01,
          'e_sg': 0.85,
         'e_en': 0.1}

In [3]:
G, networks = main(params=params, filename="benchmarks/hierarchical_benchmark.gpickle", num_threads=5, num_iter=1000)


MQE_0=1.37562737716, growth target=1.16928327059
MQE=0.962474605559, size of map=4
growth terminated, MQE: 0.962474605559, target: 1.16928327059, number of deleted neurons: 0
submitted job: ID=01-01, e=1.34034788984, number of nodes=255
submitted job: ID=01-02, e=1.25584409061, number of nodes=128MQE_0=1.34034788984, growth target=1.13929570636

MQE_0=1.25584409061, growth target=1.06746747702MQE_0=1.25296864704, growth target=1.06502334999
submitted job: ID=01-04, e=1.25296864704, number of nodes=128

MQE=0.891631433157, size of map=4
growth terminated, MQE: 0.891631433157, target: 1.06746747702, number of deleted neurons: 0
submitted job: ID=01-02-04, e=1.12109526668, number of nodes=54
MQE_0=1.12109526668, growth target=0.95293097668
MQE=1.02950025983, size of map=4
growth terminated, MQE: 1.02950025983, target: 1.06502334999, number of deleted neurons: 0
submitted job: ID=01-04-01, e=1.21406463877, number of nodes=64
MQE_0=1.21406463877, growth target=1.03195494295
MQE=0.512503024191, size of map=4
growth terminated, MQE: 0.512503024191, target: 0.95293097668, number of deleted neurons: 0
MQE=0.74113067957, size of map=4
growth terminated, MQE: 0.74113067957, target: 1.03195494295, number of deleted neurons: 0
MQE=1.04103271235, size of map=4
growth terminated, MQE: 1.04103271235, target: 1.13929570636, number of deleted neurons: 0MQE_0=1.25913172338, growth target=1.07026196487

submitted job: ID=01-01-02, e=1.25913172338, number of nodes=121
submitted job: ID=01-01-03, e=1.25466706685, number of nodes=128
MQE_0=1.25466706685, growth target=1.06646700682
MQE=0.915102576699, size of map=4
growth terminated, MQE: 0.915102576699, target: 1.07026196487, number of deleted neurons: 0
submitted job: ID=01-01-02-02, e=1.22610580516, number of nodes=83
MQE_0=1.22610580516, growth target=1.04218993439
MQE=0.866966542253, size of map=4
growth terminated, MQE: 0.866966542253, target: 1.06646700682, number of deleted neurons: 0
submitted job: ID=01-01-03-03, e=1.19146730153, number of nodes=63
MQE_0=1.19146730153, growth target=1.0127472063
MQE=0.769502390415, size of map=4
growth terminated, MQE: 0.769502390415, target: 1.0127472063, number of deleted neurons: 0
MQE=1.07290705926, size of map=4
MQE=0.857419256471, size of map=5
growth terminated, MQE: 0.857419256471, target: 1.04218993439, number of deleted neurons: 0
DONE

In [4]:
label_nodes(G, networks)

In [5]:
NMI_all_layers(G, labels=["firstlevelcommunity", "secondlevelcommunity"])


['3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3'
 '3' '3' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '3' '3' '3' '3' '3' '3'
 '3' '3' '3' '3' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '1' '1' '1' '1'
 '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '4' '4'
 '4' '4' '4' '4' '4' '4' '4' '4' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3'
 '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '2' '2' '2' '2' '2' '2' '2'
 '2' '2' '2' '1' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2'
 '2' '4' '2' '2' '4' '4' '4' '2' '4' '4' '4' '4' '1' '1' '1' '1' '1' '1'
 '1' '1' '1' '1' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '3' '3' '3' '3'
 '3' '3' '3' '3' '3' '3' '4' '4' '1' '4' '4' '4' '4' '4' '1' '1' '4' '4'
 '1' '1' '1' '1' '1' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '4' '4' '4'
 '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '2' '2' '2' '2' '2' '2' '2' '2'
 '2' '2' '2' '2' '2' '1' '2' '2' '2' '2' '2' '2' '1' '1' '1' '1' '1' '1'
 '1' '1' '1' '1' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '2' '2' '2' '2'
 '2' '2' '2' '2' '2' '2' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1'
 '1' '1' '1' '1' '1' '1' '1' '1' '2' '4' '4' '4' '4' '4' '4' '4' '4' '4'
 '4' '4' '2' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '2' '4' '1' '3' '3'
 '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '4' '4' '4' '4' '4'
 '1' '1' '3' '3' '1' '1' '1' '1' '2' '1' '2' '2' '2' '3' '2' '2' '4' '4'
 '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4'
 '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '1' '3' '3' '3' '3' '3' '3' '3'
 '3' '3' '3' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '3' '3' '1' '3' '3'
 '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '3' '1' '1'
 '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '1' '2'
 '1' '1' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '3' '3' '3' '3' '3' '3'
 '3' '3' '3' '3' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '1' '4' '1'
 '2' '2' '2' '2' '2' '2' '2' '2' '2' '2' '1' '1' '1' '1' '1' '1' '1' '1'
 '1' '1' '1' '1' '1' '1' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4' '4'
 '4' '4' '4' '4' '4' '4' '4' '4']
['01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-01' '01-01' '01-01' '01-01' '01-03' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-04' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-01' '01-01' '01-04'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-04' '01-04' '01-01' '01-01'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-04' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-01' '01-01' '01-04' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-04' '01-04' '01-02' '01-02' '01-04' '01-04' '01-04' '01-04' '01-01'
 '01-04' '01-01' '01-01' '01-01' '01-02' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-04' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-02' '01-02' '01-04' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-01'
 '01-04' '01-04' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-02' '01-02' '01-02' '01-02' '01-02' '01-02'
 '01-02' '01-02' '01-02' '01-02' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-04' '01-01' '01-04'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-04'
 '01-04' '01-04' '01-04' '01-04' '01-04' '01-04' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01'
 '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01' '01-01']
['9' '12' '11' '9' '11' '11' '12' '10' '10' '11' '10' '10' '11' '10' '11'
 '12' '10' '12' '10' '11' '7' '8' '8' '6' '6' '7' '6' '7' '6' '8' '11' '12'
 '10' '12' '11' '9' '10' '10' '11' '9' '14' '16' '14' '13' '14' '16' '15'
 '15' '15' '14' '3' '4' '1' '2' '2' '1' '4' '1' '1' '3' '4' '1' '3' '4' '3'
 '2' '2' '1' '2' '3' '16' '13' '14' '14' '13' '16' '13' '16' '13' '16' '9'
 '12' '9' '11' '11' '10' '11' '12' '9' '12' '1' '2' '4' '3' '2' '4' '1' '2'
 '4' '2' '1' '6' '6' '7' '5' '5' '7' '7' '6' '8' '7' '4' '6' '6' '8' '5'
 '8' '6' '8' '7' '5' '7' '5' '6' '5' '8' '5' '13' '5' '7' '13' '13' '14'
 '7' '15' '13' '15' '13' '3' '3' '4' '2' '2' '3' '4' '3' '2' '3' '16' '16'
 '13' '16' '14' '14' '14' '15' '16' '14' '12' '10' '11' '9' '10' '10' '9'
 '12' '11' '9' '13' '14' '1' '14' '13' '15' '15' '14' '2' '4' '15' '16' '1'
 '4' '1' '3' '4' '8' '7' '5' '7' '6' '7' '7' '8' '5' '8' '16' '15' '14'
 '16' '15' '13' '16' '15' '14' '13' '14' '13' '13' '6' '6' '7' '6' '6' '7'
 '8' '7' '8' '5' '5' '5' '6' '2' '6' '5' '8' '8' '5' '8' '3' '3' '3' '4'
 '4' '1' '4' '4' '1' '4' '11' '12' '12' '12' '9' '9' '11' '9' '9' '11' '6'
 '5' '6' '8' '6' '7' '7' '6' '8' '5' '1' '2' '2' '2' '1' '4' '1' '2' '2'
 '2' '4' '3' '2' '1' '1' '4' '2' '3' '1' '3' '6' '16' '13' '15' '15' '15'
 '16' '13' '14' '13' '13' '15' '7' '10' '11' '10' '12' '12' '12' '12' '11'
 '9' '9' '5' '15' '1' '10' '12' '9' '11' '11' '12' '10' '9' '12' '10' '9'
 '11' '9' '10' '11' '16' '16' '15' '14' '15' '3' '3' '10' '11' '2' '2' '1'
 '4' '8' '3' '6' '6' '5' '10' '7' '6' '16' '16' '16' '14' '15' '15' '14'
 '14' '13' '13' '14' '16' '15' '15' '16' '16' '15' '16' '15' '14' '7' '6'
 '6' '8' '5' '8' '5' '8' '5' '8' '2' '12' '9' '12' '11' '9' '10' '9' '11'
 '9' '11' '8' '7' '7' '5' '5' '8' '6' '8' '7' '5' '10' '12' '1' '10' '12'
 '10' '10' '11' '9' '10' '11' '11' '11' '9' '9' '9' '9' '12' '10' '10' '12'
 '4' '1' '4' '1' '4' '2' '1' '1' '1' '3' '1' '2' '3' '3' '3' '1' '4' '3'
 '3' '6' '2' '4' '16' '16' '13' '16' '16' '13' '13' '14' '14' '15' '12'
 '12' '9' '12' '9' '9' '12' '10' '12' '10' '5' '8' '7' '8' '5' '8' '8' '8'
 '7' '5' '5' '4' '15' '3' '7' '5' '7' '5' '6' '5' '6' '7' '8' '7' '2' '2'
 '1' '4' '3' '4' '4' '2' '2' '3' '3' '4' '3' '1' '16' '14' '15' '14' '13'
 '13' '14' '13' '15' '13' '16' '14' '15' '15' '14' '16' '13' '14' '13' '15']
['01-02-03' '01-02-01' '01-02-04' '01-02-03' '01-02-04' '01-02-04'
 '01-02-01' '01-02-04' '01-02-04' '01-02-03' '01-02-04' '01-02-04'
 '01-02-04' '01-02-04' '01-02-04' '01-02-01' '01-02-04' '01-02-01'
 '01-02-04' '01-02-04' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-04' '01-01-02' '01-01-04' '01-01-02' '01-01-02' '01-01-02'
 '01-02-03' '01-02-01' '01-02-04' '01-02-01' '01-02-04' '01-02-03'
 '01-02-04' '01-02-04' '01-02-03' '01-02-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-04-02' '01-04-01' '01-04-04' '01-04-01'
 '01-04-01' '01-04-04' '01-04-01' '01-04-04' '01-04-04' '01-04-02'
 '01-04-01' '01-04-04' '01-04-02' '01-04-01' '01-04-02' '01-04-01'
 '01-04-01' '01-04-04' '01-04-01' '01-04-02' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-02-03' '01-02-01' '01-02-03' '01-02-04'
 '01-02-04' '01-02-04' '01-02-03' '01-02-01' '01-02-03' '01-02-01'
 '01-04-04' '01-04-01' '01-04-01' '01-04-02' '01-04-01' '01-04-01'
 '01-04-04' '01-04-01' '01-04-01' '01-04-01' '01-04-04' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-04-01' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-03' '01-01-02' '01-01-02' '01-01-03' '01-01-03' '01-01-03'
 '01-01-02' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-04-02'
 '01-04-02' '01-04-01' '01-04-01' '01-04-01' '01-04-02' '01-04-01'
 '01-04-02' '01-04-01' '01-04-02' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-02-01' '01-02-04' '01-02-04' '01-02-03' '01-02-04'
 '01-02-04' '01-02-03' '01-02-01' '01-02-04' '01-02-03' '01-01-03'
 '01-01-03' '01-04-04' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-04-01' '01-04-01' '01-01-03' '01-01-03' '01-04-04'
 '01-04-01' '01-04-04' '01-04-02' '01-04-01' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-04-01' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-04-02'
 '01-04-03' '01-04-02' '01-04-01' '01-04-01' '01-04-04' '01-04-01'
 '01-04-01' '01-04-04' '01-04-01' '01-02-04' '01-02-01' '01-02-01'
 '01-02-01' '01-02-03' '01-02-03' '01-02-03' '01-02-03' '01-02-03'
 '01-02-04' '01-01-02' '01-01-02' '01-01-01' '01-01-02' '01-01-04'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-04-04'
 '01-04-01' '01-04-01' '01-04-01' '01-04-04' '01-04-01' '01-04-04'
 '01-04-01' '01-04-01' '01-04-01' '01-04-01' '01-04-02' '01-04-01'
 '01-04-04' '01-04-04' '01-04-01' '01-04-01' '01-04-02' '01-04-04'
 '01-04-02' '01-01-02' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-02' '01-02-04' '01-02-04' '01-02-04' '01-02-01'
 '01-02-01' '01-02-01' '01-02-01' '01-02-04' '01-02-03' '01-02-03'
 '01-01-02' '01-01-03' '01-04-04' '01-02-04' '01-02-01' '01-02-03'
 '01-02-04' '01-02-03' '01-02-01' '01-02-04' '01-02-03' '01-02-01'
 '01-02-04' '01-02-03' '01-02-03' '01-02-03' '01-02-04' '01-02-04'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-04-02'
 '01-04-02' '01-02-04' '01-02-04' '01-04-01' '01-04-01' '01-04-04'
 '01-04-01' '01-01-02' '01-04-02' '01-01-01' '01-01-02' '01-01-02'
 '01-02-04' '01-01-02' '01-01-04' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-04-01' '01-02-01' '01-02-03'
 '01-02-01' '01-02-04' '01-02-03' '01-02-04' '01-02-03' '01-02-04'
 '01-02-03' '01-02-04' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-02-04' '01-02-01' '01-04-04' '01-02-04' '01-02-01' '01-02-04'
 '01-02-04' '01-02-03' '01-02-03' '01-02-04' '01-02-04' '01-02-04'
 '01-02-03' '01-02-03' '01-02-03' '01-02-03' '01-02-03' '01-02-01'
 '01-02-04' '01-02-02' '01-02-01' '01-04-01' '01-04-04' '01-04-01'
 '01-04-04' '01-04-01' '01-04-01' '01-04-04' '01-04-04' '01-04-04'
 '01-04-02' '01-04-04' '01-04-01' '01-04-04' '01-04-02' '01-04-02'
 '01-04-04' '01-04-01' '01-04-02' '01-04-02' '01-01-02' '01-04-01'
 '01-04-01' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-02-01'
 '01-02-01' '01-02-03' '01-02-01' '01-02-03' '01-02-03' '01-02-01'
 '01-02-04' '01-02-01' '01-02-04' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-04-01' '01-01-03' '01-04-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02' '01-01-02'
 '01-01-02' '01-01-02' '01-01-02' '01-04-01' '01-04-01' '01-04-04'
 '01-04-01' '01-04-03' '01-04-01' '01-04-01' '01-04-01' '01-04-01'
 '01-04-02' '01-04-02' '01-04-01' '01-04-02' '01-04-04' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03' '01-01-03'
 '01-01-03']
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-5-603f7e57dfe5> in <module>()
----> 1 NMI_all_layers(G, labels=["firstlevelcommunity", "secondlevelcommunity"])

<ipython-input-1-d6e159103ac4> in NMI_all_layers(G, labels)
    441 def NMI_all_layers(G, labels):
    442 
--> 443     return np.array([NMI_one_layer(G, labels[len(labels) - 1 - i], i + 1) for i in range(len(labels))])
    444 
    445 ##########################################################################################################################

<ipython-input-1-d6e159103ac4> in NMI_one_layer(G, label, layer)
    437     print predicted_community_labels
    438 
--> 439     return normalized_mutual_info_score(actual_community_labels, predicted_community_labels)
    440 
    441 def NMI_all_layers(G, labels):

/home/david/miniconda2/lib/python2.7/site-packages/sklearn/metrics/cluster/supervised.pyc in normalized_mutual_info_score(labels_true, labels_pred)
    768 
    769     """
--> 770     labels_true, labels_pred = check_clusterings(labels_true, labels_pred)
    771     classes = np.unique(labels_true)
    772     clusters = np.unique(labels_pred)

/home/david/miniconda2/lib/python2.7/site-packages/sklearn/metrics/cluster/supervised.pyc in check_clusterings(labels_true, labels_pred)
     48         raise ValueError(
     49             "labels_true and labels_pred must have same size, got %d and %d"
---> 50             % (labels_true.shape[0], labels_pred.shape[0]))
     51     return labels_true, labels_pred
     52 

ValueError: labels_true and labels_pred must have same size, got 512 and 511

In [12]:
_, network, _ = networks[0]
colours = np.random.rand(len(network), 3)

In [13]:
visualise_graph(G=G, colours=colours, layer=1)



In [ ]: