Best way to concatenate subarrays along an axis? - python

I have an array of arrays:
a = [ [[1,2], [3,4]], [[5,6], [7,8]] ]
How can I, for each subarray in the above array, perform the following:
reshape(-1,1)
concatenate along axis=1
a is not a numpy array but it can of course be converted to a numpy array. I do not care whether it stays a Python list or is converted to a numpy array - whatever yields the most concise/clean solution.
I am aware that this can be accomplished using a for loop but it seems clumsy and I am interesting in cleaner solutions :)
The result I expect is:
[[1, 5], [2, 6], [3, 7], [4, 8]]

The library einops contains a function rearrange that should do the trick in a tidy manner. It uses the same type of indexing as np.einsum to operate flexible reshaping operations.
import numpy as np
a = [ [[1,2], [3,4]], [[5,6], [7,8]] ]
an = np.array(a)
from einops import rearrange
ar = rearrange(an, "a b c -> (b c) a")
ar
output:
array([[1, 5],
[2, 6],
[3, 7],
[4, 8]])

You are looking to reshape each sub-array to (-1, 1), which means the overall shape of the initial array is (len(a), -1, 1). From there we can np.concatenate on axis=1:
>>> a
array([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
>>> a.reshape((len(a), -1, 1))
array([[[1],
[2],
[3],
[4]],
[[5],
[6],
[7],
[8]]])
>>> np.concatenate(x.reshape((len(x), -1, 1)), 1)
array([[1, 5],
[2, 6],
[3, 7],
[4, 8]])
Note: len(a) is essentially a.shape[0]
Alternatively you can discard the last axis and work with np.stack instead:
>>> np.stack(x.reshape((len(x), -1)), 1)
array([[1, 5],
[2, 6],
[3, 7],
[4, 8]])

A python list solution:
In [182]: alist = []
...: for xy in zip(*a):
...: alist.extend(list(zip(*xy)))
...:
In [183]: alist
Out[183]: [(1, 5), (2, 6), (3, 7), (4, 8)]

Related

Combinig two numpy arrays of different dimensions

I want to add one numpy array two another so it will look like this:
a = [3, 4]
b = [[6, 5], [2, 1]]
output:
[[3, 4], [[6, 5], [2, 1]]]
It should look like the output above and not like [[3,4],[6,5],[2,1]].
How do I do that with numpy arrays?
Work with pure python lists, and not numpy arrays.
It doesn't make sense to have a numpy array holding two list objects. There's literally no gain in doing that.
If you directly instantiate an array like so:
np.array([[3, 4], [[6, 5], [2, 1]]])
You get
array([[3, 4],
[list([6, 5]), list([2, 1])]], dtype=object)
which is an array with dtype=object. Most of numpy's power is lost in this case. For more information on examples and why, take a look at this thread.
If you work with pure python lists, then you can easily achieve what you want:
>>> a + b
[[3, 4], [[6, 5], [2, 1]]]
Numpy as built-in stack commands that are (in my opinion) slightly easier to use:
>>> a = np.array([3, 4])
>>> b = np.array([[6, 5], [2, 1]])
>>> np.row_stack([b, a])
array([[3, 4],
[6, 5],
[2, 1]])
There's also a column stack.
Ref: https://numpy.org/doc/stable/reference/generated/numpy.ma.row_stack.html
You can't stack arrays of different shapes in one array the way you want (or you have to fill in gaps with NaNs or zeroes), so if you want to iterate over them, consider using list.
a = np.array([3, 4])
b = np.array([[6, 5], [2, 1]])
c = [a, b]
for arr in c:
...
If you still want a numpy array, you can try this:
>>> a = np.array([3, 4])
>>> b = np.array([[6, 5], [2, 1]])
>>> a.resize(b.shape,refcheck=False)
>>> c = np.array([a, b])
array([[[3, 4],
[0, 0]],
[[6, 5],
[2, 1]]])

Append elements to Ragged tensors?

Can I append elements or extend in some way Ragged Tensors as I can do nested lists ?
In [158]: l=[[1,2],[3],[4,5,6]]
In [159]: l
Out[159]: [[1, 2], [3], [4, 5, 6]]
In [160]: l[1]
Out[160]: [3]
In [161]: l[1].append(9)
In [162]: l
Out[162]: [[1, 2], [3, 9], [4, 5, 6]]
Or for that matter can any Tensor be dynamically resized (not reshaped)
RaggedTensors are not dynamic. However, you can use tf.concat with another RaggedTensor containing your update to create a new RaggedTensor:
>>> rt = tf.ragged.constant([[1,2],[3],[4,5,6]])
>>> update = tf.ragged.constant([[],[9],[]])
>>> tf.concat([rt,update],axis=1)
<tf.RaggedTensor [[1, 2], [3, 9], [4, 5, 6]]>

Numpy - combine two feature arrays but keep original index

I have two feature arrays, e.g.
a = [1, 2, 3]
b = [4, 5, 6]
Now I want to combine these arrays in the following way:
[[1, 4], [2, 5], [3, 6]]
The location in the array corresponds to a timestep. I tried appending and then reshaping, but then I get:
[[1, 2], [3, 4], [5, 6]]
you can use np.dstack to stack your lists depth-wise:
>>> np.dstack([a, b])
array([[[1, 4],
[2, 5],
[3, 6]]])
As noted by #BramVanroy, this does add an unwanted dimension. Two ways around that are to squeeze the result, or to use column_stack instead:
np.dstack([a, b]).squeeze()
# or
np.column_stack([a, b])
Both of which return:
array([[1, 4],
[2, 5],
[3, 6]])
As an alternative to sacuL's reply, you can also simply do
>>> np.array(list(zip(a, b)))
array([[1, 4],
[2, 5],
[3, 6]])
In fact, this is closer to the expected result in terms of the number of dimensions (two, rather than three in sacuL's answer which you still need to .squeeze() to achieve the correct result).

Convert two arrays to an array of arrays compatible with the result of `findContours`

I need to convert two arrays to an array of arrays compatible with the result of findContours as the following example shows:
a = [1,3,5,7]
b = [2,4,6,8]
c = convert(a, b)
print(c)
# c = [ [[1,2]], [[3,4]], [[5,6]], [[7,8]] ]
How can I do it using NumPy?
With zip an list comprehension it's quite easy to achieve what you want.
a = [1,3,5,7]
b = [2,4,6,8]
c = list([[x,y]] for x,y in zip(a,b))
print(c)
Output
[[[1, 2]], [[3, 4]], [[5, 6]], [[7, 8]]]
In case you need a numpy array:
import numpy as np
a = np.array([1,3,5,7])
b = np.array([2,4,6,8])
c = np.array(list([[x,y]] for x,y in zip(a,b)))
print(c.shape)
Output:
(4, 1, 2)
I don't really know what findContours is though.
You can make use of np.dstack(..) [numpy-doc] here, and then .reshape(..) [numpy-doc] the result:
>>> np.dstack((a,b)).reshape(-1, 1, 2)
array([[[1, 2]],
[[3, 4]],
[[5, 6]],
[[7, 8]]])

How to add a 2D matrix to another 3D matrix in python?

I have an 3D matrix a,like this:
a=np.array([[[1,2],[2,3]],[[3,4],[4,5]]])
[
[[1 2],[2 3]]
[[3 4],[4 5]]
]
a.shape
(2, 2, 2)
Now, I want to add another element, like [[5,6],[6,7]] to this array.
So, new array will be:
[
[[1, 2],[2, 3]]
[[3, 4],[4, 5]]
[[5, 6],[6, 7]]
]
a.shape
(3, 2, 2)
What is the best way to do this?
( I'm working with big datasets so I need the best way)
Use np.vstack to vertically stack after extending the second array to 3D by adding a new axis as its first axis with None/np.newaxis, like so -
np.vstack((a,b[None]))
Sample run -
In [403]: a
Out[403]:
array([[[1, 2],
[2, 3]],
[[3, 4],
[4, 5]]])
In [404]: b
Out[404]:
array([[5, 6],
[6, 7]])
In [405]: np.vstack((a,b[None]))
Out[405]:
array([[[1, 2],
[2, 3]],
[[3, 4],
[4, 5]],
[[5, 6],
[6, 7]]])
You can use np.append to append to matrixes:
a = np.array([[[1,2],[2,3]],[[3,4],[4,5]]])
a = np.append(a, [[[5,6],[6,7]]], axis=0)
Note that I had to add an extra set of brackets around the second part, in order for the dimensions to be correct. Also, you must use an axis or it will all be flattened to a linear array.
Try numpy.append
import numpy as np
a=np.array([[[1,2],[2,3]],[[3,4],[4,5]]])
b=np.array([[3,4],[4,5]])
np.append(a,[b[:,:]],axis=0)

Categories

Resources