whitepanda
whitepanda

Reputation: 488

how can I shuffle node labels and get a new weight vector using NumPy in Python?

I am saving the edge weights of an undirected graph in a row vector. For instance, if I have a graph as pictured below

enter image description here

The vector that I create is [5, 3, 4, 1, 2, 7] as ordered based on node number in ascending order. Now, if I swap the node labels of nodes 1 and 4, I can obtain the following graph;

enter image description here

In this scenerio, the vector that I should have is [2, 7, 4, 1, 5, 3]. My question is if I have an n by m NumPy array, where n is the number of graphs and m is the number of edges, how can I shuffle the node labels for each row and get the updated array efficiently?

Suppose I have a set of graphs consisting of four nodes as shown below. My intention is to randomly shuffle node labels in each network and then get an updated weights accordingly in a same size array.

np.random.seed(2)
arr = np.random.randint(10, size=(5, 6))
arr
array([[8, 8, 6, 2, 8, 7],
       [2, 1, 5, 4, 4, 5],
       [7, 3, 6, 4, 3, 7],
       [6, 1, 3, 5, 8, 4],
       [6, 3, 9, 2, 0, 4]])

Upvotes: 3

Views: 350

Answers (1)

MangoNrFive
MangoNrFive

Reputation: 1599

You can do it like this:

import numpy as np


def get_arr_from_edges(a):
    n = int(np.sqrt(len(a) * 2)) + 1
    mask = np.tri(n, dtype=bool, k=-1).T
    out = np.zeros((n, n))
    out[mask] = a
    out += out.T
    return out


def get_edges_from_arr(a):
    mask = np.tri(a.shape[0], dtype=bool, k=-1).T
    out = a[mask]
    return out


def swap_nodes(a, nodes):
    a[:, [nodes[0] - 1, nodes[1] - 1], :] = a[:, [nodes[1] - 1, nodes[0] - 1], :]
    a[:, :, [nodes[0] - 1, nodes[1] - 1]] = a[:, :, [nodes[1] - 1, nodes[0] - 1]]
    return a


arr = np.array([
        [8, 8, 6, 2, 8, 7],
        [2, 1, 5, 4, 4, 5],
        [7, 3, 6, 4, 3, 7],
        [6, 1, 3, 5, 8, 4],
        [6, 3, 9, 2, 0, 4],
])
nodes_to_swap = (1, 4)

# initialize node-arr
node_arrs = np.apply_along_axis(get_arr_from_edges, axis=1, arr=arr)

# swap nodes
node_arrs = swap_nodes(node_arrs, nodes_to_swap)

# return rempapped edges
edges = np.array([get_edges_from_arr(node_arr) for node_arr in node_arrs])
print(edges)

Gives the following result:

[[8 7 6 2 8 8]
 [4 5 5 4 2 1]
 [3 7 6 4 7 3]
 [8 4 3 5 6 1]
 [0 4 9 2 6 3]]
  • The idea is to build a connection-matrix from the edges, where the edge-number is saved at the indices of the two nodes.
  • Then you just swap the columns and rows according to the nodes you want to swap. If you want this process to be random you could create random node pairs and call the function multiple times with these node pairs. This process is non-commutative, so if you want to swap multiple node-pairs then order matters!
  • After that you read out the remapped edges of the array with the swapped columns and rows (this is basically the inverse of the first step).

I am sure that there are some more optimizations left using numpys vast functionality.

Upvotes: 0

Related Questions