I have a numpy array that is built with coded sections. The sections come in 2x2 blocks. I have a large dictionary of what those 2x2 blocks should be replaced with. How do I replace those 2x2 codes with values in the dictionary.
info_dict = {
5: np.array([[1, 0], [1, 0]], "int"),
6: np.array([[1, 0], [0, 1]], "int"),
7: np.array([[0, 1], [1, 0]], "int"),
8: np.array([[1, 1], [0, 0]], "int"),
}
print(np.array([[5, 5, 8, 8], [5, 5, 8, 8], [6, 6, 7, 7], [6, 6, 7, 7]]))
print(np.array([[1, 0, 1, 1], [1, 0, 0, 0], [1, 0, 0, 1], [0, 1, 1, 0]]))
# before (coded)
[[5 5 8 8]
[5 5 8 8]
[6 6 7 7]
[6 6 7 7]]
# after (final matrix)
[[1 0 1 1]
[1 0 0 0]
[1 0 0 1]
[0 1 1 0]]
For reference
#5
[[1 0]
[1 0]]
#6
[[1 0]
[0 1]]
#7
[[0 1]
[1 0]]
#8
[[1 1]
[0 0]]
One way to do it:
import numpy as np
info_dict = {
5: np.array([[1, 0], [1, 0]], "int"),
6: np.array([[1, 0], [0, 1]], "int"),
7: np.array([[0, 1], [1, 0]], "int"),
8: np.array([[1, 1], [0, 0]], "int"),
}
a = np.array([[5, 5, 8, 8], [5, 5, 8, 8], [6, 6, 7, 7], [6, 6, 7, 7]])
np.block([[info_dict[b] for b in r] for r in a[::2, ::2]])
It gives:
[[1 0 1 1]
[1 0 0 0]
[1 0 0 1]
[0 1 1 0]]
Assuming your dictionary has a small number of integers in it, and your squares are N to a side, you info_dict as follows:
mapping = np.zeros((max(info_dict) + 1, N, N), dtype=int)
for channel, value in info_dict.items():
mapping[channel] = value
If you can store the dictionary in this format to begin with, that's even better. Now you can use simple index with some rearrangement to get the result:
after = mapping[before[::N, ::N]].transpose(0, 2, 1, 3).reshape(before.shape)
Related
I'm trying to creating a matrix like this:
[[A 0 0],
[0 B 0],
[0 0 C]]
in which A,B,C could be either a submatrix or a constant
suppose I got one of the submatrix first:
[[1 2],
[3 4]]
then got the next:
[[5 0 0],
[0 6 0],
[0 0 7]]
How can I concat them into the format like below?
[[1 2 0 0 0],
[3 4 0 0 0],
[0 0 5 0 0],
[0 0 0 6 0],
[0 0 0 0 7]]
You can simply use scipy.linalg.block_diag
As follow:
from scipy.linalg import block_diag
A = [[1, 2], [3, 4]]
B = [[5, 0, 0],
[0, 6, 0],
[0, 0, 7]]
block_diag(A, B)
Output:
array([[1, 2, 0, 0, 0],
[3, 4, 0, 0, 0],
[0, 0, 5, 0, 0],
[0, 0, 0, 6, 0],
[0, 0, 0, 0, 7]])
I've been looking all over but I'm not really sure how to even describe what it is I want. Essentially I need to turn
np.array(
[[0,0, 1,1, 2,2],
[0,0, 1,1, 2,2],
[3,3, 4,4, 5,5],
[3,3, 4,4, 5,5]]
)
into
np.array(
[[[0,1,2,3,4,5], [0,1,2,3,4,5]],
[[0,1,2,3,4,5], [0,1,2,3,4,5]]
)
I think I can accomplish that using np.reshape and maybe some other stuff but if I try reshape with arguments (2,2,6) I get back
[[[0 0 1 1 2 2]
[0 0 1 1 2 2]]
[[3 3 4 4 5 5]
[3 3 4 4 5 5]]]
which is not quite what I want.
Make your array with a couple of repeats:
In [208]: arr = np.arange(0,6).reshape(2,3)
In [209]: arr
Out[209]:
array([[0, 1, 2],
[3, 4, 5]])
In [210]: arr = arr.repeat(2,0).repeat(2,1)
In [211]: arr
Out[211]:
array([[0, 0, 1, 1, 2, 2],
[0, 0, 1, 1, 2, 2],
[3, 3, 4, 4, 5, 5],
[3, 3, 4, 4, 5, 5]])
Now break it into blocks which we can transpose:
In [215]: arr1 = arr.reshape(2,2,3,2)
In [216]: arr1
Out[216]:
array([[[[0, 0],
[1, 1],
[2, 2]],
[[0, 0],
[1, 1],
[2, 2]]],
[[[3, 3],
[4, 4],
[5, 5]],
[[3, 3],
[4, 4],
[5, 5]]]])
In [217]: arr1.shape
Out[217]: (2, 2, 3, 2)
In [218]: arr1.transpose(1,0,2,3)
Out[218]:
array([[[[0, 0],
[1, 1],
[2, 2]],
[[3, 3],
[4, 4],
[5, 5]]],
[[[0, 0],
[1, 1],
[2, 2]],
[[3, 3],
[4, 4],
[5, 5]]]])
Let's consolidate the middle 2 axes:
In [220]: arr1.transpose(1,0,2,3).reshape(2,6,2)
Out[220]:
array([[[0, 0],
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]],
[[0, 0],
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5]]])
Almost there; just need another transpose:
In [221]: arr1.transpose(1,0,2,3).reshape(2,6,2).transpose(0,2,1)
Out[221]:
array([[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]],
[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]]])
The basic idea is to reshape the array into blocks, do a transpose, and reshape again. Here I needed another transpose, but if I choose the right one to start with I might not have needed that.
I don't know of a systematic way of doing this; there may be one, but so far I've just used a bit of trial and error when answering this kind of question. Everyone wants a different final arrangement.
This should work:
>>> import numpy as np
>>> A = np.array(
... [[0,0, 1,1, 2,2],
... [0,0, 1,1, 2,2],
... [3,3, 4,4, 5,5],
... [3,3, 4,4, 5,5]]
... )
>>> B = a[::2,::2].flatten()
>>> B
array([0, 1, 2, 3, 4, 5])
>>> C = np.tile(b, (2,2,1))
>>> C
array([[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]],
[[0, 1, 2, 3, 4, 5],
[0, 1, 2, 3, 4, 5]]])
We can generalize this for a given n * m matrix, that contain blocks sized n/y * m/x of identical values (so there are y rows and x columns of blocks)
def transform(A, y, x):
dy = A.shape[0]/y
dx = A.shape[1]/x
B = A[::dy, ::dx].flatten()
return np.tile(B, (y,x,1))
I think this is what you are looking for:
import numpy
b=numpy.array([[0,0,1,1,2,2],[0,0,1,1,2,2],[3,3,4,4,5,5],[3,3,4,4,5,5]])
c1=(b[::2,::2].flatten(),b[::2,1::2].flatten())
c2=(b[1::2,::2].flatten(),b[1::2,1::2].flatten())
c=numpy.vstack((c1,c2)).reshape((2,2,6))
print(c)
which outputs:
[[[0 1 2 3 4 5]
[0 1 2 3 4 5]]
[[0 1 2 3 4 5]
[0 1 2 3 4 5]]]
and for general size target array and general size input array this is the algorithm with an example of 3*3 input array:
import numpy
b=numpy.array([[0,0,1,1,2,2],[0,0,1,1,2,2],[0,0,1,1,2,2],[3,3,4,4,5,5],[3,3,4,4,5,5],[3,3,4,4,5,5]])
(m,n)=b.shape
C=b[::int(m/2),::2].flatten(),b[::int(m/2),1::2].flatten()
for i in range(1,int(m/2)):
C=numpy.vstack((C,(b[i::int(m/2),::2].flatten(),b[i::int(m/2),1::2].flatten())))
print(C)
which outputs:
[[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]
[0 1 2 3 4 5]]
I have a numpy Ndarray of dimensions (N * N * M) and want to mirror it over the main diagonal efficiently.
For N=1 I did the following:
A = np.array([[1, 0, 6, 5], [0, 2, 0, 0], [1, 0, 2, 0], [0, 1, 0, 3]])
A = np.tril(A) + np.triu(A.T, 1)
'''
From:
array([[1, 0, 6, 5],
[0, 2, 0, 0],
[1, 0, 2, 0],
[0, 1, 0, 3]])
To:
array([[1, 0, 1, 0],
[0, 2, 0, 1],
[1, 0, 2, 0],
[0, 1, 0, 3]])
'''
However this (np.tril and np.triu) doesn’t work for higher dimensions e.g.
A = np.array([[[1], [0], [6], [5]], [[0], [2],[0], [0]], [[1], [0], [2], [0]], [[0], [1], [0], [3]]]) # (4,4,1)
A = np.array([[[1,2], [0,3], [6,5], [5,6]], [[0,3], [2,2],[0,1], [0,3]], [[1,5], [0,2], [2,1], [0,9]], [[0,1], [1,2], [0,2], [3,4]]]) # (4,4,2)
Any ideas to do this efficiently (without for loops)? I don’t mind if you mirror the bottom or the top triangle of the matrix
This is a simple way to do that:
import numpy as np
# Example data, shape (4, 4, 2)
a = np.array([[[1, 2], [0, 3], [6, 5], [5, 6]],
[[0, 3], [2, 2], [0, 1], [0, 3]],
[[1, 5], [0, 2], [2, 1], [0, 9]],
[[0, 1], [1, 2], [0, 2], [3, 4]]])
# Lower triangle of ones, shape (4, 4, 1)
tril = np.tril(np.ones(a.shape[:-1], a.dtype))[..., np.newaxis]
# Eye matrix with extra dimension, shape (4, 4, 1)
eye = np.eye(a.shape[0], dtype=a.dtype)[..., np.newaxis]
# Lower triangle
atril = a * tril
# Add upper triangle and remove diagonal that was added twice
result = atril + atril.swapaxes(0, 1) - a * eye
# Check result
print(result[..., 0])
# [[1 0 1 0]
# [0 2 0 1]
# [1 0 2 0]
# [0 1 0 3]]
print(result[..., 1])
# [[2 3 5 1]
# [3 2 2 2]
# [5 2 1 2]
# [1 2 2 4]]
I have a matrix like this:
tf_ent = tf.Variable([ [9.96, 8.65, 0.8, 0.1 ],
[0.7, 8.33, 0 , 0 ],
[0.9, 0, 6, 7.33],
[6.60, 0, 3, 5.5 ],
[9.49, 0., 0, 0 ],
[0.4, 8.45, 0, 0.2 ],
[0.3, 0, 5.82, 8.28]])
I want to get an output in which the weight in the same range get the same number.
To put it another way, This number is a good representative of the weight range in the matrix.
So my ideal output could be something like this:
[[5, 5, 1, 1],
[1, 5, 0, 0],
[1, 0, 6, 5],
[4, 0, 2, 3],
[5, 0., 0, 0],
[1, 5, 0, 1],
[1, 0, 3, 5]]
In this case I mapped with this condition(consider that i have my mapping):
range(0.1, 1) -> 1
range( 1, 3) -> 2
range( 3, 5) -> 3
range(5, 7) -> 4
range (7, 10) -> 5
firstly I tried with tf.histogram_fixed_width_bins but it did not give me the expected result:
this is my code:
value_ranges = [0, 10.0]
nbins = 5
new_f_w_t = tf.histogram_fixed_width_bins(tf_ent, value_ranges, nbins)
print(new_f_w_t)
and this is the output of this code:
output= [[4 4 0 0]
[0 4 0 0]
[0 0 3 3]
[3 0 1 2]
[4 0 0 0]
[0 4 0 0]
[0 0 2 4]]
output more like getting an equivalent integer of those float numbers rather than considering any range.
How can I get a dynamic mapping of the matrix in an efficient way?
Thanks in advance:)
This is equivalent to a np.digitize operation. You can use math_ops._bucketize:
from tensorflow.python.ops import math_ops
bins = [0.1, 1, 3, 5, 7, 10]
new_f_w_t = math_ops._bucketize(tf_ent, boundaries=bins)
new_f_w_t.numpy()
array([[5, 5, 1, 1],
[1, 5, 0, 0],
[1, 0, 4, 5],
[4, 0, 3, 4],
[5, 0, 0, 0],
[1, 5, 0, 1],
[1, 0, 4, 5]], dtype=int32)
The tf.searchsorted() call can also be used for this purpose, which avoids calling the hidden _bucketize function. You have to tile the bins to match the dimensions of the input values, though.
For example:
bins = tf.tile([[0.1, 1, 3, 5, 7, 10]], (tf_ent.shape[0], 1))
new_f_w_t = tf.searchsorted(bins, tf_ent, side="right")
I want to do this in a proper way:
data = np.array(data)
data =[
[1, 1, 2, 1],
[0, 1, 3, 2],
[0, 2, 3, 2],
[2, 4, 3, 1],
[0, 2, 1, 4],
[3, 1, 4, 1]]
this should become (delete the lines that start with 0):
[1, 1, 2, 1]
[2, 4, 3, 1]
[3, 1, 4, 1]
So far I did it like this:
lines = []
for i in range(0, len(data[0])):
if data[0,i] != 0:
lines.append(data[:,i])
lines = np.array(lines)
Then I found this fine method:
mask = 1 <= data[0,:]
and now I want to apply that mask to that array. This Mask reads: [True, False, False, True, False, True]. How do I do that?
Why not just:
[ar for ar in data if ar[0] != 0]
This assumes that arrays are not empty.
I presume you have a numpy array based on the data[0,:] and data[0,i] you have in your question and you mean data[:, 0] :
import numpy as np
data = np.array([
[1, 1, 2, 1],
[0, 1, 3, 2],
[0, 2, 3, 2],
[2, 4, 3, 1],
[0, 2, 1, 4],
[3, 1, 4, 1]])
data = data[data[:,0] != 0]
print(data)
Output:
[[1 1 2 1]
[2 4 3 1]
[3 1 4 1]]
data[0,:] is the first row [1 1 2 1] not the first column
Using List comprehension
In [56]: [elem for elem in data if elem[0] !=0]
Out[56]: [[1, 1, 2, 1], [2, 4, 3, 1], [3, 1, 4, 1]]