So you're starting with an array like this:
In [1]: import numpy as np
In [2]: a = np.arange(20).reshape((10,-1))
In [3]: a
Out[3]:
array([[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7],
[ 8, 9],
[10, 11],
[12, 13],
[14, 15],
[16, 17],
[18, 19]])
What you are looking for is reshape
and argsort
, I think.
Using the reshape
member function you can change the shape without changing the sequence:
In [4]: a.reshape((-1,4))
Out[4]:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15],
[16, 17, 18, 19]])
Reshape takes a tuple. I like to think of that as (number of rows, number or columns). In this case, (-1,4) means: use 4 columns (so each row has four numbers in it), and calculate the amount of rows from the amount of data.
Using argsort
you can get the array that you want.
In [2]: import numpy as np
In [3]: d = np.random.random((10, 2)).reshape((-1,4))
In [4]: d
Out[4]:
array([[ 0.65945195, 0.1907593 , 0.1630845 , 0.76949532],
[ 0.90823488, 0.71518689, 0.38422877, 0.77824007],
[ 0.31453967, 0.76592537, 0.5871099 , 0.09306465],
[ 0.38251335, 0.97461878, 0.97562622, 0.87532202],
[ 0.12358359, 0.20323007, 0.397975 , 0.615806 ]])
In [7]: e = np.array([4-np.argsort(r) for r in d])
In [8]: e
Out[8]:
array([[2, 3, 4, 1],
[2, 3, 1, 4],
[1, 4, 2, 3],
[4, 1, 3, 2],
[4, 3, 2, 1]])
As you can see, each row now has the required indices. Let's go over what line 7 does from the inside out:
for r in d
: iterate over all rows in d.
4 - np.argsort(r)
: argsort would create indices in the rang 0-3. So we substract it from 4 to get to a inverse 4-1 range. In numpy arrays, operations are done to each element, so 4 - np.array([2, 1, 0, 3])
acts like np.array([4,4,4,4]) - np.array([2, 1, 0, 3])
.
[]
: the previous lines wrapped between square brackets make it a list comprehension, which is like a very fast and compact for-loop returning a list.
np.array
: The list of arrays is combined into one big array.
Then using another reshape, you bring the data back into its original shape
In [9]: e.reshape((-1,2))
Out[9]:
array([[2, 3],
[4, 1],
[2, 3],
[1, 4],
[1, 4],
[2, 3],
[4, 1],
[3, 2],
[4, 3],
[2, 1]])
Edit:
Based on your comment, you can do the following. Say you have a 2D matrix:
In [1]: import numpy as np
In [2]: a = np.arange(100).reshape((-1,10))
In [3]: a
Out[3]:
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, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
You can select a 2x2 submatrix like this:
In [4]: a[3:5, 0:2]
Out[4]:
array([[30, 31],
[40, 41]])
The patteren here is a[row:row+2, column:column+2]
. Using the reshape
and argsort
techniques shown above you can create the new values.
In [5]: p = a[3:5, 0:2]
In [6]: e = 4-np.argsort(p.reshape((1,4))).reshape((2,2))
In [7]: e
Out[7]:
array([[4, 3],
[2, 1]])
You can then place this result in the original array or in a copy:
In [12]: a[3:5, 0:2] = e
In [13]: a
Out[13]:
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, 25, 26, 27, 28, 29],
[ 4, 3, 32, 33, 34, 35, 36, 37, 38, 39],
[ 2, 1, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
Note that both the width and height of the image need to be even for a 2x2 submatrix to work as intended...