Concatenating empty array in Numpy
Question:
in Matlab I do this:
>> E = [];
>> A = [1 2 3 4 5; 10 20 30 40 50];
>> E = [E ; A]
E =
1 2 3 4 5
10 20 30 40 50
Now I want the same thing in Numpy but I have problems, look at this:
>>> E = array([],dtype=int)
>>> E
array([], dtype=int64)
>>> A = array([[1,2,3,4,5],[10,20,30,40,50]])
>>> E = vstack((E,A))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/shape_base.py", line 226, in vstack
return _nx.concatenate(map(atleast_2d,tup),0)
ValueError: array dimensions must agree except for d_0
I have a similar situation when I do this with:
>>> E = concatenate((E,A),axis=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: arrays must have same number of dimensions
Or:
>>> E = append([E],[A],axis=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/lib/function_base.py", line 3577, in append
return concatenate((arr, values), axis=axis)
ValueError: arrays must have same number of dimensions
Answers:
if you know the number of columns before hand:
>>> xs = np.array([[1,2,3,4,5],[10,20,30,40,50]])
>>> ys = np.array([], dtype=np.int64).reshape(0,5)
>>> ys
array([], shape=(0, 5), dtype=int64)
>>> np.vstack([ys, xs])
array([[ 1., 2., 3., 4., 5.],
[ 10., 20., 30., 40., 50.]])
if not:
>>> ys = np.array([])
>>> ys = np.vstack([ys, xs]) if ys.size else xs
array([[ 1, 2, 3, 4, 5],
[10, 20, 30, 40, 50]])
np.concatenate
, np.hstack
and np.vstack
will do what you want. Note however that NumPy arrays are not suitable for use as dynamic arrays. Use Python lists for that purpose instead.
Something that I’ve build to deal with this sort of problem. It’s also deals with list
input instead of np.array
:
import numpy as np
def cat(tupleOfArrays, axis=0):
# deals with problems of concating empty arrays
# also gives better error massages
# first check that the input is correct
assert isinstance(tupleOfArrays, tuple), 'first var should be tuple of arrays'
firstFlag = True
res = np.array([])
# run over each element in tuple
for i in range(len(tupleOfArrays)):
x = tupleOfArrays[i]
if len(x) > 0: # if an empty arraylist - skip
if isinstance(x, list): # all should be ndarray
x = np.array(x)
if x.ndim == 1: # easier to concat 2d arrays
x = x.reshape((1, -1))
if firstFlag: # for the first non empty array, just swich the empty res array with it
res = x
firstFlag = False
else: # actual concatination
# first check that concat dims are good
if axis == 0:
assert res.shape[1] == x.shape[1], "Error concating vertically element index " + str(i) +
" with prior elements: given mat shapes are " +
str(res.shape) + " & " + str(x.shape)
else: # axis == 1:
assert res.shape[0] == x.shape[0], "Error concating horizontally element index " + str(i) +
" with prior elements: given mat shapes are " +
str(res.shape) + " & " + str(x.shape)
res = np.concatenate((res, x), axis=axis)
return res
if __name__ == "__main__":
print(cat((np.array([]), [])))
print(cat((np.array([1, 2, 3]), np.array([]), [1, 3, 54+1j]), axis=0))
print(cat((np.array([[1, 2, 3]]).T, np.array([]), np.array([[1, 3, 54+1j]]).T), axis=1))
print(cat((np.array([[1, 2, 3]]).T, np.array([]), np.array([[3, 54]]).T), axis=1)) # a bad one
If you wanna do this just because you cannot concatenate an array with an initialized empty array in a loop, then just use a conditional statement,
e.g.
if (i == 0):
do the first assignment
else:
start your contactenate
In Python, if possible to work with the individual vectors, to append you should use list.append()
>>> E = []
>>> B = np.array([1,2,3,4,5])
>>> C = np.array([10,20,30,40,50])
>>> E = E.append(B)
>>> E = E.append(C)
[array([1, 2, 3, 4, 5]), array([10, 20, 30, 40, 50])]
and then after all append operations are done, return to np.array thusly
>>> E = np.array(E)
array([[ 1, 2, 3, 4, 5],
[10, 20, 30, 40, 50]])
E = np.array([
]).reshape(0, 5)
print("E: n{}nShape {}n".format(E, E.shape))
A = np.vstack([
[1, 2, 3, 4, 5],
[10, 20, 30, 40, 50]]
)
print("A:n{}nShape {}n".format(A, A.shape))
C = np.r_[
E,
A
].astype(np.int32)
print("C:n{}nShape {}n".format(C, C.shape))
E:
[]
Shape (0, 5)
A:
[[ 1 2 3 4 5]
[10 20 30 40 50]]
Shape (2, 5)
C:
[[ 1 2 3 4 5]
[10 20 30 40 50]]
Shape (2, 5)
A solution is to use the None
object and np.concatenate
, np.hstack
or np.vstack
.
>>> arr=None
>>> p=np.array([0,1,2,3])
>>> for i in range(0,2):
>>> arr = (np.vstack((arr, p)) if (arr is not None) else p)
array([[ 0, 1, 2, 3],
[[ 0, 1, 2, 3]])
in Matlab I do this:
>> E = [];
>> A = [1 2 3 4 5; 10 20 30 40 50];
>> E = [E ; A]
E =
1 2 3 4 5
10 20 30 40 50
Now I want the same thing in Numpy but I have problems, look at this:
>>> E = array([],dtype=int)
>>> E
array([], dtype=int64)
>>> A = array([[1,2,3,4,5],[10,20,30,40,50]])
>>> E = vstack((E,A))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/core/shape_base.py", line 226, in vstack
return _nx.concatenate(map(atleast_2d,tup),0)
ValueError: array dimensions must agree except for d_0
I have a similar situation when I do this with:
>>> E = concatenate((E,A),axis=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: arrays must have same number of dimensions
Or:
>>> E = append([E],[A],axis=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/numpy/lib/function_base.py", line 3577, in append
return concatenate((arr, values), axis=axis)
ValueError: arrays must have same number of dimensions
if you know the number of columns before hand:
>>> xs = np.array([[1,2,3,4,5],[10,20,30,40,50]])
>>> ys = np.array([], dtype=np.int64).reshape(0,5)
>>> ys
array([], shape=(0, 5), dtype=int64)
>>> np.vstack([ys, xs])
array([[ 1., 2., 3., 4., 5.],
[ 10., 20., 30., 40., 50.]])
if not:
>>> ys = np.array([])
>>> ys = np.vstack([ys, xs]) if ys.size else xs
array([[ 1, 2, 3, 4, 5],
[10, 20, 30, 40, 50]])
np.concatenate
, np.hstack
and np.vstack
will do what you want. Note however that NumPy arrays are not suitable for use as dynamic arrays. Use Python lists for that purpose instead.
Something that I’ve build to deal with this sort of problem. It’s also deals with list
input instead of np.array
:
import numpy as np
def cat(tupleOfArrays, axis=0):
# deals with problems of concating empty arrays
# also gives better error massages
# first check that the input is correct
assert isinstance(tupleOfArrays, tuple), 'first var should be tuple of arrays'
firstFlag = True
res = np.array([])
# run over each element in tuple
for i in range(len(tupleOfArrays)):
x = tupleOfArrays[i]
if len(x) > 0: # if an empty arraylist - skip
if isinstance(x, list): # all should be ndarray
x = np.array(x)
if x.ndim == 1: # easier to concat 2d arrays
x = x.reshape((1, -1))
if firstFlag: # for the first non empty array, just swich the empty res array with it
res = x
firstFlag = False
else: # actual concatination
# first check that concat dims are good
if axis == 0:
assert res.shape[1] == x.shape[1], "Error concating vertically element index " + str(i) +
" with prior elements: given mat shapes are " +
str(res.shape) + " & " + str(x.shape)
else: # axis == 1:
assert res.shape[0] == x.shape[0], "Error concating horizontally element index " + str(i) +
" with prior elements: given mat shapes are " +
str(res.shape) + " & " + str(x.shape)
res = np.concatenate((res, x), axis=axis)
return res
if __name__ == "__main__":
print(cat((np.array([]), [])))
print(cat((np.array([1, 2, 3]), np.array([]), [1, 3, 54+1j]), axis=0))
print(cat((np.array([[1, 2, 3]]).T, np.array([]), np.array([[1, 3, 54+1j]]).T), axis=1))
print(cat((np.array([[1, 2, 3]]).T, np.array([]), np.array([[3, 54]]).T), axis=1)) # a bad one
If you wanna do this just because you cannot concatenate an array with an initialized empty array in a loop, then just use a conditional statement,
e.g.
if (i == 0):
do the first assignment
else:
start your contactenate
In Python, if possible to work with the individual vectors, to append you should use list.append()
>>> E = []
>>> B = np.array([1,2,3,4,5])
>>> C = np.array([10,20,30,40,50])
>>> E = E.append(B)
>>> E = E.append(C)
[array([1, 2, 3, 4, 5]), array([10, 20, 30, 40, 50])]
and then after all append operations are done, return to np.array thusly
>>> E = np.array(E)
array([[ 1, 2, 3, 4, 5],
[10, 20, 30, 40, 50]])
E = np.array([
]).reshape(0, 5)
print("E: n{}nShape {}n".format(E, E.shape))
A = np.vstack([
[1, 2, 3, 4, 5],
[10, 20, 30, 40, 50]]
)
print("A:n{}nShape {}n".format(A, A.shape))
C = np.r_[
E,
A
].astype(np.int32)
print("C:n{}nShape {}n".format(C, C.shape))
E:
[]
Shape (0, 5)
A:
[[ 1 2 3 4 5]
[10 20 30 40 50]]
Shape (2, 5)
C:
[[ 1 2 3 4 5]
[10 20 30 40 50]]
Shape (2, 5)
A solution is to use the None
object and np.concatenate
, np.hstack
or np.vstack
.
>>> arr=None
>>> p=np.array([0,1,2,3])
>>> for i in range(0,2):
>>> arr = (np.vstack((arr, p)) if (arr is not None) else p)
array([[ 0, 1, 2, 3],
[[ 0, 1, 2, 3]])