user3139545
user3139545

Reputation: 7394

Adding dimension to numpy matrix

Why is the following code not adding a third dimension to the matrix and how should I change the code to get what I need?

imm = np.zeros(shape=(10,10))
dims = imm.shape
if len(dims) < 3:
    imm.reshape((dims[0], dims[1], 1))
imm.shape # I want this to pring (10,10,1)

Upvotes: 2

Views: 4398

Answers (5)

Mad Physicist
Mad Physicist

Reputation: 114538

There are a number of ways to change the dimensions of an array, as long as the product of the sizes in the new dimensions remains the same as it was for the old.

In all cases but one, the reshaping operation returns a new array object, but uses the same underlying data in memory. This means that reshaping is very cheap, even for enormous arrays. You just have to assign the returned reference back to the original array.

The only way to reshape the array object in place is to assign to its shape property:

arr.shape += (1,)

All the other methods to add a dimension return a new array object. In most cases, they will not copy the data, unless you do something weird with the indexing scheme:

  1. Use np.reshape:

    arr = np.reshape(arr, arr.shape + (1,))
    
  2. Use arr.reshape. This works exactly like np.reshape:

    arr = arr.reshape(arr.shape + (1,))
    
  3. Index the array with np.newaxis (a.k.a. None):

    arr = arr[..., np.newaxis]
    

    OR

    arr = arr[..., None]
    

    This creates a new array object, inserting a new axis of size 1 into your indexing scheme wherever you put the newaxis object, but leaves the underlying data untouched.

  4. Use np.expand_dims. This will insert a new dimension of size 1 wherever you tell it to through the second argument:

    arr = np.expand_dims(arr, -1)
    
  5. For your particular case, you can use np.atleast_3d:

    arr = np.atleast_3d(arr)
    

    This function behaves strangely when given a 1D input: it places the dimensions of size one in the beginning and the end of the tuple, instead of all on one side. The 2D case behaves exactly as you want though.

  6. Use np.array to explicitly create a new array object with the expected number of dimensions:

    arr = np.array(arr, copy=False, ndmin=3)
    

    copy=False must be stated explicitly to avoid copying the data. The third axis will be prepended to the shape, not appended, so you may need to do something like

    arr = np.moveaxis(arr, 0, -1)
    

    This is by far the least desirable option for your particular needs.

Update

If we equate your original problem to a thumbtack, here is the nuclear sledgehammer of a solution:

arr = np.lib.stride_tricks.as_strided(arr, arr.shape + (1,))

Just remember that as_strided really is a nuclear sledgehammer!

Upvotes: 2

Mehul Jain
Mehul Jain

Reputation: 491

You can do:

new_imm = np.expand_dims(imm,axis=-1)

and reshape doesn't work in place. Your code isn't working because you aren't assigning the value returned by reshape to any variable.

Upvotes: 1

FHTMitchell
FHTMitchell

Reputation: 12156

The best way to add a dimension to a numpy array is

imm = imm[..., np.newaxis]

Don't worry, this isn't doing any expensive copying or anything, the underlying memory remains in place*. All that happens is the ndim increases by 1.

I think this solution is cleaner as you don't have to worry about grabbing the shape and putting it into reshape. It also has the advantage of you can quickly put the newaxis in any dimension. Say you wanted dimension 0 or 1 to be the new dimension

imm = imm[np.newaxis, ...]  # new dimension is axis 0
imm = imm[:, np.newaxis, :] # new dimension is axis 1
imm = imm[:, :, np.newaxis] # new dimension is axis 2 (same as above)

* you can prove this to yourself by doing

x = np.array([1,2,3])
y = x[..., np.newaxis]
x *= 10
print(y)
# 
# [[10]
#  [20]
#  [30]]

Upvotes: 2

Austin
Austin

Reputation: 26047

The easiest way if you want to modify imm in place:

import numpy as np
imm = np.zeros(shape=(10,10))
dims = imm.shape
if len(dims) < 3:
    imm.shape = imm.shape + (1,)
print(imm.shape) 
# (10,10,1)

You could use

imm.shape = imm.shape + (1,)

Or simply,

imm.shape += 1,

Upvotes: 1

penguin2048
penguin2048

Reputation: 1343

imm.reshape does not performs inplace modification. Instead it returns the modified array.

Hence, do imm = imm.reshape((dims[0], dims[1], 1)) and you will get the desired output. Consider reading the documentation for more details

Upvotes: 1

Related Questions