Numpy Array Attributes
- We'll use Numpy's random number generator, which we will seed with a set value in order to ensure that the same random arrays are generated each time this code is run:
# In[1]
import numpy as np
rng=np.random.default_rng(seed=1701) # seed for reproducibility
x1 = rng.integers(10,size=6)
x2 = rng.integers(10,size=(3,4))
x3 = rng.integers(10,size=(3,4,5))
print("x3 ndim: ",x3.ndim)
print("x3 shape: ",x3.shape)
print("x3 size: ",x3.size)
print("x3 dtype: ",x3.dtype)
# Out[1]
x3 ndim: 3
x3 shape: (3, 4, 5)
x3 size: 60
x3 dtype: int64
Array Indexing : Accessing Single Elements
# In[2]
print(x2)
print(x2[2,-1])
# Out[2]
[[3 1 3 7]
[4 0 2 3]
[0 0 6 9]]
9
# In[3]
x2[0,0]=12
print(x2)
# Out[3]
[[12 1 3 7]
[ 4 0 2 3]
[ 0 0 6 9]]
- Unlike Python lists, Numpy array have a fixed type. For example, that if you attempt to insert a floating-point value to an integer array, the value will be truncated.
# In[4]
x1[0]=3.14
print(x1)
# Out[4]
[3 0 3 3 7 9]
Array Slicing : Accessing Subarrays
- Numpy slicing syntax follows that of the standard Python lists; to access a slice of an array 'x', use this:
x[start:stop:step]
One dimensional subarray
# In[5]
x=np.arange(10)
x
# Out[5]
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
# In[6]
print("first five elements:",x[:5])
print("elements after index 5:",x[5:])
print("middle subarray:",x[4:7])
print("every other element that step is 2:",x[::2])
print("every other element, starting at index 1 and step 2:",x[1::2])
print("all reversed elements:",x[::-1])
print("reversed every other element from index 5:",x[5::-2])
# Out[6]
first five elements: [0 1 2 3 4]
elements after index 5: [5 6 7 8 9]
middle subarray: [4 5 6]
every other element that step is 2: [0 2 4 6 8]
every other element, starting at index 1 and step 2: [1 3 5 7 9]
all reversed elements: [9 8 7 6 5 4 3 2 1 0]
reversed every other element from index 5: [5 3 1]
Multidimensional subarray
# In[7]
x2
# Out[7]
array([[12, 1, 3, 7],
[ 4, 0, 2, 3],
[ 0, 0, 6, 9]])
# In[8]
print("two rows, three columns:",x2[:2,:3])
print("all rows, every other column:",x2[:3,::2])
print("reversed array:",x2[::-1,::-1])
# Out[8]
two rows, three columns: [[12 1 3]
[ 4 0 2]]
all rows, every other column: [[12 3]
[ 4 2]
[ 0 6]]
reversed array: [[ 9 6 0 0]
[ 3 2 0 4]
[ 7 3 1 12]]
Accessing array rows and columns
- You can access single rows or columns of an array by combining indexing and slicing, using an empty slice marked by a single colon(:)
- However, In the case of row access, you can omit colon(:) for a more compact syntax
# In[9]
print("first column of x2:",x2[:,0])
print("first row of x2:",x2[0,:])
print("equivalent to x2[0,:]:",x2[0])
# Out[9]
first column of x2: [12 4 0]
first row of x2: [12 1 3 7]
equivalent to x2[0,:]: [12 1 3 7]
Subarrays as no-copy views
- Unlike Python list slices, Numpy array slices are returned as views rather than copies of the array data.
# In[10]
x2_sub=x2[:2,:2]
print(x2_sub)
x2_sub[0,0]=99
print(x2_sub)
print(x2)
# Out[10]
[[12 1]
[ 4 0]]
[[99 1]
[ 4 0]]
[[99 1 3 7]
[ 4 0 2 3]
[ 0 0 6 9]]
- If we modify this subarray, orginal array will be changed.
Creating copies of Arrays
# In[11]
x2_sub_copy=x2[:2,:2].copy()
print(x2_sub_copy)
# Out[11]
[[99 1]
[ 4 0]]
# In[12]
x2_sub_copy[0,0]=42
print(x2_sub_copy)
print(x2)
# Out[12]
[[42 1]
[ 4 0]]
[[99 1 3 7]
[ 4 0 2 3]
[ 0 0 6 9]]
- If we modify this subarray, the original array is not touched.
Reshaping of Arrays
# In[13]
grid=np.arange(1,10).reshape((3,3))
print(grid)
# Out[13]
[[1 2 3]
[4 5 6]
[7 8 9]]
# In[14]
x=np.array([1,2,3])
print(x.reshape((1,3))) # row vector via reshape
print(x.reshape((3,1))) # column vector via reshape
# Out[14]
array([[1, 2, 3]])
array([[1],
[2],
[3]])
- A convenient shorthad for this is to use
np.newaxis
in the slicing syntax
# In[15]
print(x[np.newaxis,:]) # row vector via reshape
print(x[:,np.newaxis]) # column vector via reshape
# Out[15]
array([[1, 2, 3]])
array([[1],
[2],
[3]])
Array Concatenation and Splitting
Concatenation of Arrays
- Using
np.concatenate
, np.vstack(vertical stack)
, np.hstack(horizontal stack)
np.concatenate
# In[16]
x=np.array([1,2,3])
y=np.array([3,2,1])
np.concatenate([x,y])
# Out[16]
array([1, 2, 3, 3, 2, 1])
# In[17]
grid=np.array([[1,2,3],[4,5,6]])
np.concatenate([grid,grid])
# Out[17]
array([[1, 2, 3],
[4, 5, 6],
[1, 2, 3],
[4, 5, 6]])
# In[18]
np.concatenate([grid,grid],axis=1)
# Out[18]
array([[1, 2, 3, 1, 2, 3],
[4, 5, 6, 4, 5, 6]])
- For More Information about the
axis
, reference this blog: About the axis
np.vstack
# In[19]
x=np.array([1,2,3])
grid=np.array([[9,8,7],[6,5,4]])
np.vstack([x,grid])
# Out[19]
array([[1, 2, 3],
[9, 8, 7],
[6, 5, 4]])
np.hstack
# In[20]
y=np.array([[99],[99]])
np.hstack([grid,y])
# Out[20]
array([[ 9, 8, 7, 99],
[ 6, 5, 4, 99]])
Splitting of Arrays
- Using
np.split
, np.hsplit(horizontal split)
, np.vsplit(vertical split)
np.split
np.split(array,indices_or_sections,axis=0)
indices or sections
are int or 1-dimensional array
- For example,
indices or sections
= [2,3]
- array[:2]
- array[2:3]
- array[3:]
# In[21]
x=[1,2,3,99,99,3,2,1]
x1,x2,x3=np.split(x,[3,5])
print(x1,x2,x3)
# Out[21]
[1 2 3] [99 99] [3 2 1]
np.hsplit
- Split an array into multiple sub-arrays horizontally(column-wise)
hsplit
is equivalent to split with axis=1
- The array is always split along the second axis except for 1-dimensional arrays, where it is split at axis=0
# In[22]
grid=np.arange(16).reshape((4,4))
grid
# Out[22]
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
# In[23]
left,right=np.hsplit(grid,2)
a=np.hsplit(grid,(2,3))
print(left)
print(right)
print(a)
# Out[23]
[[ 0 1]
[ 4 5]
[ 8 9]
[12 13]]
[[ 2 3]
[ 6 7]
[10 11]
[14 15]]
[array([[ 0, 1],
[ 4, 5],
[ 8, 9],
[12, 13]]),
array([[ 2],
[ 6],
[10],
[14]]),
array([[ 3],
[ 7],
[11],
[15]])]
- With a higher dimensional array, the split is still along the second axis
# In[24]
x=np.arange(8).reshape(2,2,2)
a=np.hsplit(x,2)
print(x)
print(a)
# Out[24]
[[[0 1]
[2 3]]
[[4 5]
[6 7]]]
[array([[[0, 1]],
[[4, 5]]]),
array([[[2, 3]],
[[6, 7]]])]
- With a 1-D array, the split is along the axis=0
# In[25]
x=np.array([0,1,2,3,4,5])
np.hsplit(x,3)
# Out[25]
[array([0, 1]), array([2, 3]), array([4, 5])]
np.vsplit
- Split an array into multiple sub-arrays vertically(row-wise)
vsplit
is equivalent to split with axis=0 (default)
- The array is always split along the first axis regardless of the array dimension.
# In[26]
upper,lower=np.vsplit(grid,2)
a=np.vsplit(grid,(2,3))
print(upper)
print(lower)
print(a)
# Out[26]
[[0 1 2 3]
[4 5 6 7]]
[[ 8 9 10 11]
[12 13 14 15]]
[array([[0, 1, 2, 3],
[4, 5, 6, 7]]),
array([[ 8, 9, 10, 11]]),
array([[12, 13, 14, 15]])]
- With a higher dimensional array, the split is still along the first axis
# In[27]
x=np.arange(8).reshape(2,2,2)
a=np.vsplit(x,2)
print(x)
print(a)
# Out[27]
[[[0, 1],
[2, 3]],
[[4, 5],
[6, 7]]]
[array([[[0, 1],
[2, 3]]]),
array([[[4, 5],
[6, 7]]])]
np.dsplit
- Split array into multiple sub-arrays along the third axis(depth) in higher-dimensional arrays.
dsplit
is equivalent to split with axis=2
- The array is always split along the third axis provided the array dimension is greater than or equal to 3
# In[28]
x=np.arange(16).reshape(2,2,4)
a=np.dsplit(x,2)
b=np.dsplit(x,(2,3))
print(x)
print(a)
print(b)
# Out[28]
[[[ 0, 1, 2, 3],
[ 4, 5, 6, 7]],
[[ 8, 9, 10, 11],
[12, 13, 14, 15]]]
[array([[[ 0, 1],
[ 4, 5]],
[[ 8, 9],
[12, 13]]]),
array([[[ 2, 3],
[ 6, 7]],
[[10, 11],
[14, 15]]])
[array([[[ 0, 1],
[ 4, 5]],
[[ 8, 9],
[12, 13]]]),
array([[[ 2],
[ 6]],
[[10],
[14]]]),
array([[[ 3],
[ 7]],
[[11],
[15]]])]