Efficient way to add a singleton dimension to a NumPy vector so that slice assignments work
Asked Answered
B

5

26

In NumPy, how can you efficiently make a 1-D object into a 2-D object where the singleton dimension is inferred from the current object (i.e. a list should go to either a 1xlength or lengthx1 vector)?

 # This comes from some other, unchangeable code that reads data files.
 my_list = [1,2,3,4]

 # What I want to do:
 my_numpy_array[some_index,:] = numpy.asarray(my_list)

 # The above doesn't work because of a broadcast error, so:
 my_numpy_array[some_index,:] = numpy.reshape(numpy.asarray(my_list),(1,len(my_list)))

 # How to do the above without the call to reshape?
 # Is there a way to directly convert a list, or vector, that doesn't have a
 # second dimension, into a 1 by length "array" (but really it's still a vector)?
Bedside answered 1/3, 2012 at 3:32 Comment(0)
D
49

In the most general case, the easiest way to add extra dimensions to an array is by using the keyword None when indexing at the position to add the extra dimension. For example

my_array = numpy.array([1,2,3,4])

my_array[None, :] # shape 1x4

my_array[:, None] # shape 4x1
Divide answered 1/3, 2012 at 5:35 Comment(5)
This is what np.atleast_2d([1,2,3,4]) does.Cordillera
@Cordillera yes, but the approach by @Divide is clean, saves the hassle of looking up np.atleast_2d in the docs, and generalizes to n-dim arrays (where n>3 b/c I know there's an np.atleast_3d).Krause
There is now a np.expand_dims to handle all sizes.Cordillera
@hpaulj, it looks to me that expand_dims has strictly inferior capabilities compared to using None as suggested. It does not seem possible to add multiple axes with expand_dims.Regarding
@Alexey, look at its code. It's a convenience function using reshape.Cordillera
D
5

Why not simply add square brackets?

>> my_list
[1, 2, 3, 4]
>>> numpy.asarray([my_list])
array([[1, 2, 3, 4]])
>>> numpy.asarray([my_list]).shape
(1, 4)

.. wait, on second thought, why is your slice assignment failing? It shouldn't:

>>> my_list = [1,2,3,4]
>>> d = numpy.ones((3,4))
>>> d
array([[ 1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.],
       [ 1.,  1.,  1.,  1.]])
>>> d[0,:] = my_list
>>> d[1,:] = numpy.asarray(my_list)
>>> d[2,:] = numpy.asarray([my_list])
>>> d
array([[ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.],
       [ 1.,  2.,  3.,  4.]])

even:

>>> d[1,:] = (3*numpy.asarray(my_list)).T
>>> d
array([[  1.,   2.,   3.,   4.],
       [  3.,   6.,   9.,  12.],
       [  1.,   2.,   3.,   4.]])
Dexedrine answered 1/3, 2012 at 3:41 Comment(2)
Not sure. I'm looking into the broadcasting error right now, but it looks to be because of my NumPy version (1.5.1). The square bracket idea you mentioned works for my current problem. I'm not sure how viable that is for large lists... is Python smart about not adding a ton of overhead to go from a list of, say, 100,000 items to a list containing a list of 100,000 elements?Bedside
Probably not as smart as you'd like it to be -- Python lists and numpy arrays don't share data. But if you already have the list from elsewhere, there's no overhead to adding the square brackets if for some reason you need them: try a = [1,2]; b = [a]; print b[0] is a, and you see that Python isn't making a new copy of a, it's reusing the original.Dexedrine
H
3
import numpy as np
a = np.random.random(10)
sel = np.at_least2d(a)[idx]
Haas answered 6/5, 2014 at 22:30 Comment(0)
P
3

What about expand_dims?

np.expand_dims(np.array([1,2,3,4]), 0)

has shape (1,4) while

np.expand_dims(np.array([1,2,3,4]), 1)

has shape (4,1).

Pall answered 17/4, 2015 at 13:1 Comment(2)
[None, :]: 495 ns ± 9.04 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each). expand_dims: 8.98 µs ± 261 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)Grandstand
@Grandstand Interesting. expand_dims, even though it seems to be the dedicated function for it, must have some additional overhead. Would need to look into the implementations to see where the difference is.Pall
H
1

You can always use dstack() to replicate your array:

import numpy

my_list = array([1,2,3,4])
my_list_2D = numpy.dstack((my_list,my_list));
Hedwig answered 7/1, 2014 at 13:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.