Permute rows and columns of a matrix - python-2.7

Assuming that I have the following matrix/array:
array([[0, 0, 1, 1, 1],
[0, 0, 1, 0, 1],
[1, 1, 0, 1, 1],
[1, 0, 1, 0, 0],
[1, 1, 1, 0, 0]])
and I want to apply the following permutation:
1 -> 5
2 -> 4
the result should be in the end:
array([[1, 1, 1, 0, 0],
[1, 0, 1, 0, 0],
[1, 1, 0, 1, 1],
[0, 0, 1, 0, 1],
[0, 0, 1, 1, 1]])
Now, an incredibly naive (and memory costly) way of doing so might be:
a2 = deepcopy(a1)
a2[0,:] = a1[4,:]
a2[4,:] = a1[0,:]
a = deepcopy(a2)
a2[:,0] = a[:,4]
a2[:,4] = a[:,0]
a3 = deepcopy(a2)
a2[1,:] = a3[3,:]
a2[3,:] = a3[1,:]
a = deepcopy(a2)
a2[:,1] = a[:,3]
a2[:,3] = a[:,1]
But, I would like to know if there is something more efficient that does this. numpy.shuffle and numpy.permutation seem to permute only the rows of the matrix (not the columns at the same time). That doesn't work for me because the matrices are adjacency matrices (representing graphs), and I need to do the permutations which will give me a graph which is isomorphic with the original graph. Furthermore, I need to do an arbitrary number of permutations (more than one).
Thanks!

You can perform the swap in a one-liner using integer array indexing:
a = np.array([[0, 0, 1, 1, 1],
[0, 0, 1, 0, 1],
[1, 1, 0, 1, 1],
[1, 0, 1, 0, 0],
[1, 1, 1, 0, 0]])
b = a.copy()
# map 0 -> 4 and 1 -> 3 (N.B. Python indexing starts at 0 rather than 1)
a[[4, 3, 0, 1]] = a[[0, 1, 4, 3]]
print(repr(a))
# array([[1, 1, 1, 0, 0],
# [1, 0, 1, 0, 0],
# [1, 1, 0, 1, 1],
# [0, 0, 1, 0, 1],
# [0, 0, 1, 1, 1]])
Note that array indexing always returns a copy rather than a view - there's no way to swap arbitrary rows/columns of an array without generating a copy.
In this particular case you could avoid the copy by using slice indexing, which returns a view rather than a copy:
b = b[::-1] # invert the row order
print(repr(b))
# array([[1, 1, 1, 0, 0],
# [1, 0, 1, 0, 0],
# [1, 1, 0, 1, 1],
# [0, 0, 1, 0, 1],
# [0, 0, 1, 1, 1]])
Update:
You can use the same indexing approach to swap columns.
c = np.arange(25).reshape(5, 5)
print(repr(c))
# array([[ 0, 1, 2, 3, 4],
# [ 5, 6, 7, 8, 9],
# [10, 11, 12, 13, 14],
# [15, 16, 17, 18, 19],
# [20, 21, 22, 23, 24]])
c[[0, 4], :] = c[[4, 0], :] # swap row 0 with row 4...
c[:, [0, 4]] = c[:, [4, 0]] # ...and column 0 with column 4
print(repr(c))
# array([[24, 21, 22, 23, 20],
# [ 9, 6, 7, 8, 5],
# [14, 11, 12, 13, 10],
# [19, 16, 17, 18, 15],
# [ 4, 1, 2, 3, 0]])
I've used a different example array in this case - your version will yield an identical output after performing the row/column swaps which makes it difficult to understand what's going on.

I found a solution to do what I want (though it is expensive):
a2 = deepcopy(a1)
first = randint(0, 5, 10)
second = randint(0, 5, 10)
for i in range(len(first)):
a = deepcopy(a2)
a2[first[i],:] = a[second[i],:]
a2[second[i],:] = a[first[i],:]
for i in range(len(first)):
a = deepcopy(a2)
a2[:,first[i]] = a[:,second[i]]
a2[:,second[i]] = a[:,first[i]]
Basically, I am doing 10 random switches. However, I need to copy the matrix many times. Anyway, a2 now represents a graph which is isomorphic with a1.

Related

Python: How to make values of a list in a list of lists zeros

I would like to make all the values in the first list inside the list of lists named "child_Before" below zero. The piece of code I wrote to accomplish this task is also shown below after the list:
child_Before = [[9, 12, 7, 3, 13, 14, 10, 5, 4, 11, 8, 6, 2],
[1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1],
[[1, 0], [1, 1]]]
for elem in range(len(child_Before[0])):
child_Before[0][elem] = 0
Below is the expected result:
child_After = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1],
[[1, 0], [1, 1]]]
However, I think there should be a more nibble way to accomplish this exercise. Hence, I welcome your help. Thank you in advance.
just to add a creative answer
import numpy as np
child_Before[0] = (np.array(child_Before[0])&0).tolist()
this is bad practice though since i'm using bitwise operasions in a senario where it is not intuitive, and i think there is a slight chance i'm making 2 loops xD on the bright site the & which is making all the zeros is O(1) time complexity
Just create a list of [0] with the same length as the original list.
# Answer to this question - make first list in the list to be all 0
child_Before[0] = [0] * len(child_Before[0])
As for you answer, I can correct it to make all the elements in the lists of this list to be zero.
# Make all elements 0
for child in range(len(child_Before)):
child_Before[child] = [0] * len(child_Before[child])
Use list comprehension:
child_after = [[i if n != 0 else 0 for i in j] for n, j in enumerate(child_Before)]

Writting in sub-ndarray of a ndarray in the most pythonian way. Python 2

I have a ndarray like this one:
number_of_rows = 3
number_of_columns = 3
a = np.arange(number_of_rows*number_of_columns).reshape(number_of_rows,number_of_columns)
a
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
But I want something like this:
array([[0, 100, 101],
[3, 102, 103],
[6, 7, 8]])
To do that I want to avoid to do it one by one, I rather prefer to do it in arrays or matrices, because later I want to extend the code.
Nothe I have change a submatrix of the initial matrix (in mathematical terms, in terms of this example ndarray). In the example the columns considered are [1,2] and the rows [0,1].
columns_to_keep = [1,2]
rows_to_keep = [0,1]
My first try was to do:
a[rows_to_keep,:][:,columns_to_keep] = np.asarray([[100,101],[102,103]])
However this doesn't modify the initial a, I am not having any error, so a=
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
So I have implemented a piece of code that goes do the job:
b = [[100, 101],[102, 103]]
for i in range(len(rows_to_keep)):
a[i,columns_to_keep] = b[i]
Al thought the previous lines do the job I am wondering how to do it slicing and in a faster fashion. Also in a way that with:
columns_to_keep = [0,2]
rows_to_keep = [0,2]
the desired output is
array([[100, 1, 101],
[3, 4, 5],
[102, 7, 103]]).
Many thanks!
Indexing with lists like [1,2] is called advanced indexing. By itself it produces a copy, not a view. You have to use one indexing expression, not two to assign or change values. That is a[[1,2],:] is a copy, a[[1,2],:][:,[1,2]] += 100 modifies that copy, not the original a.
In [68]: arr = np.arange(12).reshape(3,4)
Indexing with slices; this is basic indexing:
In [69]: arr[1:,2:]
Out[69]:
array([[ 6, 7],
[10, 11]])
In [70]: arr[1:,2:] += 100
In [71]: arr
Out[71]:
array([[ 0, 1, 2, 3],
[ 4, 5, 106, 107],
[ 8, 9, 110, 111]])
Doing the same indexing with lists requires arrays that 'broadcast' against each other. ix_ is a handy way of generating these:
In [73]: arr[np.ix_([1,2],[2,3])]
Out[73]:
array([[106, 107],
[110, 111]])
In [74]: arr[np.ix_([1,2],[2,3])] -= 100
In [75]: arr
Out[75]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
Here's what ix_ produces - a tuple of arrays, one is (2,1) in shape, the other (1,2). Together they index a (2,2) block:
In [76]: np.ix_([1,2],[2,3])
Out[76]:
(array([[1],
[2]]), array([[2, 3]]))
For the continuous rows and columns case, you can use basic slicing like this:
In [634]: a
Out[634]:
array([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]])
In [635]: b = np.asarray([[100, 101],[102, 103]])
In [636]: a[:rows_to_keep[1]+1, columns_to_keep[0]:] = b
In [637]: a
Out[637]:
array([[ 0, 100, 101],
[ 3, 102, 103],
[ 6, 7, 8]])

Gurobi and Python: how to query a dictionary using optimal variable solutions

I'm using Python and Gurobi and I'm having difficulty on how to optimal variable solutions to query a dictionary.
my_dict = {(i, j) : func(Z) for i in I for j in J}
my_dict results to be like this:
{(15687, 'B'): [[7, 0, 0, 0], [0, 7, 0, 0], [0, 0, 7, 0], [0, 0, 0, 7]],
...
(18906, 'C'): [[4, 0, 0, 3], [3, 0, 0, 3], [4, 0, 0, 0], [3, 0, 0, 0]}
Moreover I have a binary variable x[i, j, z] and an assignment constraint:
assignment = m.addConstrs((quicksum(x[i, j, z]
for z in range(len(my_dict[i, j]))) == 1
for i in I for j in J), "assignment")
Supposing I obtain as optimal solution variables
x[15687,'B',0] 1.000000
x[18906,'C',2] 1.000000
Is there a way to retrieve the sublist of my_dict corresponding to the "z" index?
(For instance, if my solution is x[18906,'C',2] 1.000000 then z = 2 and I want to obtain the sublist [4, 0, 0, 0])
Your code is not really a nice minimal example to work with, so it's hard to post valid code.
The general problem does not look that tough.
If your original dict looks like:
{(15687, 'B'): [[7, 0, 0, 0], [0, 7, 0, 0], [0, 0, 7, 0], [0, 0, 0, 7]],
...
(18906, 'C'): [[4, 0, 0, 3], [3, 0, 0, 3], [4, 0, 0, 0], [3, 0, 0, 0]}
and your solution is my_dict_opt, probably something like this should do (python3):
import numpy as np # easy fp-math comparison
sublists = []
for key, val in my_dict.items():
n_vars = len(val) # my assumption
for i in range(n_vars):
if np.isclose(my_dict_opt[key + tuple([i])].X, 1.0): # depends on your dict if .X is needed
sublists.append(my_dict[key][i])
Because of the dicts, the order of elements in sublists is not defined and this should only be a prototype as it's not really clear to me how those dicts are in use for you.

How to average sub arrays in Numpy using broadcasting?

If there is a numpy array that is a list of 2d arrays, is there more efficient way than calling the mean function twice?
z = np.array([[[0, 0, 0],
[10, 10, 10]],
[[0, 0, 0],
[5, 5, 5]],
[[0, 0, 0],
[2, 2, 2]]])
print(z.mean(axis=2).mean(axis=1))
>[ 5. 2.5 1. ]

Transforming a mapping matrix

I have a 2-dimensional array of ones and zeros called M where the g rows represent groups and the a columns represent articles. M maps groups and articles. If a given article "art" belongs to group "gr" then we have M[gr,art]=1; if not we have M[gr,art]=0.
Now, I would like to convert M into a square a x a matrix of ones and zeros (call it N) where if an article "art1" is in the same group as article "art2", we have N(art1,art2)=1 and N(art1,art2)=0 otherwise. N is clearly symmetric with 1's in the diagonal.
How do I construct N based on M?
Many thanks for your suggestions - and sorry if this is trivial (still new to python...)!
So you have a boolean matrix M like the following:
>>> M
array([[1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 0],
[1, 0, 1, 0, 0, 0]])
>>> ngroups, narticles = M.shape
and what you want is a matrix of shape (narticles, narticles) that represents co-occurrence. That's simply the square of the matrix:
>>> np.dot(M, M.T)
array([[1, 0, 0, 1],
[0, 2, 0, 0],
[0, 0, 1, 1],
[1, 0, 1, 2]])
... except that you don't want counts, so set entries > 0 to 1.
>>> N = np.dot(M, M.T)
>>> N[N > 0] = 1
>>> N
array([[1, 0, 0, 1],
[0, 1, 0, 0],
[0, 0, 1, 1],
[1, 0, 1, 1]])