24

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)?
ely
  • 74,674
  • 34
  • 147
  • 228

5 Answers5

47

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
DaveP
  • 6,952
  • 1
  • 24
  • 37
  • 4
    This is what `np.atleast_2d([1,2,3,4])` does. – hpaulj Jan 07 '14 at 17:59
  • @hpaulj yes, but the approach by @DaveP 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`). – BoltzmannBrain Mar 30 '17 at 17:21
  • There is now a `np.expand_dims` to handle all sizes. – hpaulj Mar 30 '17 at 17:29
  • @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`. – Alexey Dec 04 '17 at 09:11
  • @Alexey, look at its code. It's a convenience function using `reshape`. – hpaulj Dec 04 '17 at 13:13
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.]])
DSM
  • 342,061
  • 65
  • 592
  • 494
  • 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? – ely Mar 01 '12 at 03:57
  • 1
    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. – DSM Mar 01 '12 at 04:02
3
import numpy as np
a = np.random.random(10)
sel = np.at_least2d(a)[idx]
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).

NoDataDumpNoContribution
  • 10,591
  • 9
  • 64
  • 104
  • [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) – Maximus Jun 13 '20 at 23:52
  • @Maximus 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. – NoDataDumpNoContribution Jun 15 '20 at 08:02
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));
phyrox
  • 2,423
  • 15
  • 23