NumPy: Stacking, Splitting, Array attributes
By: Bhanu Soni
Tags: Numpy, Python, Machine Learning, Data Science, Programming

Stacking

Arrays can be stacked horizontally, depth-wise, or vertically. We can use, for that purpose, the vstack , dstack , hstack , column_stack , row_stack , and concatenate functions.

Time for action — stacking arrays

First, let’s set up some arrays:

In: a = arange(9).reshape(3,3)

In: a

Out:

array([[0, 1, 2],

[3, 4, 5],

[6, 7, 8]]) In: b = 2 * a In: b

Out:

array([[ 0, 2, 4],

[ 6, 8, 10],

[12, 14, 16]])

Horizontal stacking: Starting with horizontal stacking, we will form a tuple of ndarrays and give it to the hstack function. It stacks arrays in sequence horizontally (column-wise).This is shown as follows:

In: hstack((a, b))

Out:

array([[ 0, 1, 2, 0, 2, 4],

[ 3, 4, 5, 6, 8, 10],

[ 6, 7, 8, 12, 14, 16]])

We can achieve the same with the concatenate function, concatenation along the second axis, except for 1-D arrays where it concatenates along the first axis, which is shown as follows:

In: concatenate((a, b), axis=1)

Out:

array([[ 0, 1, 2, 0, 2, 4],

[ 3, 4, 5, 6, 8, 10],

[ 6, 7, 8, 12, 14, 16]])

2. Vertical stacking: vstack function is used to stack the sequence of input arrays vertically to make a single array. With vertical stacking, again, a tuple is formed. This time, it is given to the vstack function. This can be seen as follows:

In: vstack((a, b))

Out:

array([[ 0, 1, 2],

[ 3, 4, 5],

[ 6, 7, 8],

[ 0, 2, 4],

[ 6, 8, 10],

[12, 14, 16]])

The concatenate function produces the same result with the axis set to 0. This is the default value for the axis argument.

In: concatenate((a, b), axis=0)

Out:

array([[ 0, 1, 2],

[ 3, 4, 5],

[ 6, 7, 8],

[ 0, 2, 4],

[ 6, 8, 10],

[12, 14, 16]])

3. Depth stacking: Stack arrays in sequence depth wise (along third axis). This is equivalent to concatenation along the third axis after 2-D arrays of shape (M,N) have been reshaped to (M,N,1) and 1-D arrays of shape (N,) have been reshaped to (1,N,1). Additionally, there is the depth-wise stacking using dstack and a tuple, of course. This means stacking of a list of arrays along the third axis (depth). For instance, we could stack 2D arrays of image data on top of each other.

In: dstack((a, b))

Out:

array([[[ 0, 0],

[1, 2],

[2,4]],

[[3,6],

[4,8],

[5,10]],

[[6,12],

[7, 14],

[8,16]]]])



4. Column stacking: The column_stack function stacks 1D arrays column-wise. It’s shown as follows:

In: oned = arange(2)

In: oned

Out: array([0, 1]) In: twiceoned = 2 * oned

In: twiceoned

Out: array([0, 2]) In: column_stack((oned, twiceoned))

Out:

array([[0, 0],

[1, 2]])

2D arrays are stacked the way hstack stacks them:

In: column_stack((a, b))

Out:

array([[ 0, 1, 2, 0, 2, 4],

[ 3, 4, 5, 6, 8, 10],

[ 6, 7, 8, 12, 14, 16]])

In: column_stack((a, b)) == hstack((a, b))

Out:

array([[ True, True, True, True, True,True],

[ True, True, True, True, True,True],

[ True, True, True, True, True,True]],dtype=bool)

Yes, you guessed it right! We compared two arrays with the == operator. Isn’t

it beautiful?

5. Row stacking: NumPy, of course, also has a function that does row-wise stacking. It is called row_stack and, for 1D arrays, it just stacks the arrays in rows into a 2D array.

In: row_stack((oned, twiceoned))

Out:

array([[0, 1],

[0, 2]])

The row_stack function results for 2D arrays are equal to. Yes, exactly the vstack function results.

In: row_stack((a, b))

Out:

array([[ 0, 1, 2],

[ 3, 4, 5],

[ 6, 7, 8],

[ 0, 2, 4],

[ 6, 8, 10],

[12, 14, 16]])

In: row_stack((a,b)) == vstack((a, b))

Out:

array([[ True, True, True],

[ True, True, True],

[ True, True, True],

[ True, True, True],

[ True, True, True],

[ True, True, True]], dtype=bool)

What just happened?

We stacked arrays horizontally, depth-wise, or vertically. We used the vstack , dstack ,hstack , column_stack , row_stack , and concatenate functions.

Splitting

Arrays can be split vertically, horizontally, or depth-wise. The functions involved are hsplit , vsplit , dsplit , and split . We can either split into arrays of the same shape or indicate the position after which the split should occur.

Time for action — splitting arrays

Horizontal splitting:The ensuing code splits an array along its horizontal axis into three pieces of the same size and shape. This is shown as follows:

In: a

Out:

array([[0, 1,

[3, 4,

[6, 7,

In: hsplit(a,

Out:

[array([[0],

[3],

[6]]),

array([[1],

[4],

[7]]),

array([[2],

[5],

[8]])]

Compare it with a call of the split function, with extra parameter axis=1 :

In: split(a, 3, axis=1)

Out:

[array([[0],

[3],

[6]]),

array([[1],

[4],

[7]]),

array([[2],

[5],

[8]])]

2. Vertical splitting: vsplit splits along the vertical axis:

In: vsplit(a, 3)

Out: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]

The split function, with axis=0 , also splits along the vertical axis:

In: split(a, 3, axis=0)

Out: [array([[0, 1, 2]]), array([[3, 4, 5]]), array([[6, 7, 8]])]

3. Depth-wise splitting: The dsplit function, unsurprisingly, splits depth-wise. We will need an array of rank 3 first:

In: c = arange(27).reshape(3, 3, 3)

In: c

Out:

array([[[ 0, 1, 2],

[ 3, 4, 5],

[ 6, 7, 8]],

[[ 9, 10, 11],

[12, 13, 14],

[15, 16, 17]],

[[18, 19, 20],

[21, 22, 23],

[24, 25, 26]]]) In: dsplit(c, 3)

Out:

[array([[[ 0],

[ 3],

[ 6]],

[[ 9],

[12],

[15]],

[[18],

[21],

[24]]]),

array([[[ 1],

[ 4],

[ 7]],

[[10],

[13],

[16]],

[[19],

[22],

[25]]]),

array([[[ 2],

[ 5],

[ 8]],

[[11],

[14],

[17]],

[[20],

[23],

[26]]])]

What just happened?

We split arrays using the hsplit , vsplit , dsplit , and split functions.

Array attributes

Besides the shape and dtype attributes, ndarray has a number of other attributes, as shown in the following list:

ndim gives the number of dimensions:

In: b

Out:

array([[ 0,1,2,3,4,5,6,7,8,9,10,11],

[12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23]]) In: b.ndim

Out: 2

2. size contains the number of elements. This is shown a follows:

In: b.size

Out: 24

3. itemsize gives the number of bytes for each element in the array:

In: b.itemsize

Out: 8

4. If you want the total number of bytes the array requires, you can have a look at nbytes . This is just a product of the itemsize and size attributes:

In: b.resize(6,4)

In: b

Out:

array([[ 0, 1, 2,3],

[ 4, 5, 6,7],

[ 8, 9, 10,11],

[12, 13, 14,15],

[16, 17, 18,19],

[20, 21, 22,23]]) In: b.T

Out:

array([[ 0, 4, 8,12,16,20],

[ 1, 5, 9,13,17,21],

[ 2, 6, 10,14,18,22],

[ 3, 7, 11,15,19,23]])

5. If the array has a rank lower than 2, we will just get a view of the array:

In: b.ndim

Out: 1

In: b.T

Out: array([0, 1, 2, 3, 4])

Complex numbers in NumPy are represented by .j . For example, we can create an array with complex numbers:

In: b = array([1.j + 1, 2.j + 3])

In: b

Out: array([ 1.+1.j, 3.+2.j])

6. The real attribute gives us the real part of the array, or the array itself if it only contains real numbers:

In: b.real

Out: array([ 1.,3.])

7. The imag attribute contains the imaginary part of the array:

In: b.imag

Out: array([ 1.,2.])

8. If the array contains complex numbers, then the data type is automatically

also complex:

In: b.dtype

Out: dtype('complex128')

In: b.dtype.str

Out: '<c16'

9. The flat attribute returns a numpy.flatiter object. This is the only way to

acquire a flatiter — we do not have access to a flatiter constructor. The flat

iterator enables us to loop through an array as if it is a flat array, as shown next:

In: b = arange(4).reshape(2,2)

In: b

Out:

array([[0, 1],

[2, 3]])

In: f = b.flat

In: f

Out: <numpy.flatiter object at 0x103013e00>

In: for item in f: print item

.....:

0

1

2

3

It is possible to directly get an element with the flatiter object:

In: b.flat[2]

Out: 2

or multiple elements:

In: b.flat[[1,3]]

Out: array([1, 3])

The flat attribute is settable. Setting the value of the flat attribute leads to

overwriting the values of the whole array:

In: b.flat = 7

In: b

Out:

array([[7, 7],

[7, 7]])

or selected elements

In: b.flat[[1,3]] = 1

In: b

Out:

array([[7, 1],

[7, 1]])

Time for action — converting arrays

We can convert a NumPy array to a Python list with the tolist function. This is shown as follows:

Convert to a list:

In: b

Out: array([ 1.+1.j, 3.+2.j])

In: b.tolist()

Out: [(1+1j), (3+2j)]

2. astype function: The astype function converts the array to an array of the

specified type:

In: b

Out: array([ 1.+1.j, 3.+2.j]) In: b.astype(int)

/usr/local/bin/ipython:1: ComplexWarning: Casting complex values

to real discards the imaginary part

#!/usr/bin/python

Out: array([1, 3])

We are losing the imaginary part when casting from complex type to int. The astype function also accepts the name of a type as a string.

In: b.astype('complex')

Out: array([ 1.+1.j, 3.+2.j])

It won’t show any warning this time, because we used the proper data type.

What just happened?

We converted NumPy arrays to a list and to arrays of different data types.

Summary

We learned a lot the shape of an array can be manipulated in many ways — stacking, resizing, reshaping, and splitting.