Creating arrays

You can create NumPy arrays using the numpy.array function. It takes a list-like object (or another array) as input and, optionally, a string expressing its data type. You can interactively test array creation using an IPython shell, as follows:

    import numpy as np 
a = np.array([0, 1, 2])

Every NumPy array has an associated data type that can be accessed using the dtype attribute. If we inspect the a array, we find that its  dtype is int64, which stands for 64-bit integer:

    a.dtype 
# Result:
# dtype('int64')

We may decide to convert those integer numbers to float type. To do this, we can either pass the dtype argument at array initialization or cast the array to another data type using the astype method. The two ways to select a data type are shown in the following code:

    a = np.array([1, 2, 3], dtype='float32') 
a.astype('float32')
# Result:
# array([ 0., 1., 2.], dtype=float32)

To create an array with two dimensions (an array of arrays), we can perform the initialization using a nested sequence, as follows:

    a = np.array([[0, 1, 2], [3, 4, 5]]) 
print(a)
# Output:
# [[0 1 2]
# [3 4 5]]

The array created in this way has two dimensions, which are called axes in NumPy's jargon. An array formed in this way is like a table that contains two rows and three columns. We can access the axes using the ndarray.shape attribute:

    a.shape 
# Result:
# (2, 3)

Arrays can also be reshaped as long as the product of the shape dimensions is equal to the total number of elements in the array (that is, the total number of elements is conserved). For example, we can reshape an array containing 16 elements in the following ways: (2, 8), (4, 4), or (2, 2, 4). To reshape an array, we can either use the ndarray.reshape method or assign a new value to the ndarray.shape tuple. The following code illustrates the use of the ndarray.reshape method:

    a = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 
9, 10, 11, 12, 13, 14, 15])
a.shape
# Output:
# (16,)

a.reshape(4, 4) # Equivalent: a.shape = (4, 4)
# Output:
# array([[ 0, 1, 2, 3],
# [ 4, 5, 6, 7],
# [ 8, 9, 10, 11],
# [12, 13, 14, 15]])

Thanks to this property, you can freely add dimensions of size one. You can reshape an array with 16 elements to (16, 1), (1, 16), (16, 1, 1), and so on. In the next section, we will extensively use this feature to implement complex operations through broadcasting

NumPy provides convenience functions, shown in the following code, to create arrays filled with zeros, ones, or with no initial value (in this case, their actual value is meaningless and depends on the memory state). Those functions take the array shape as a tuple and, optionally, its dtype:

    np.zeros((3, 3)) 
np.empty((3, 3))
np.ones((3, 3), dtype='float32')

In our examples, we will use the numpy.random module to generate random floating point numbers in the (0, 1) interval. The numpy.random.rand will take a shape and return an array of random numbers with that shape:

    np.random.rand(3, 3) 

Sometimes it is convenient to initialize arrays that have the same shape as that of some other array. For that purpose, NumPy provides some handy functions, such as zeros_like, empty_like, and ones_like. These functions can be used as follows:

    np.zeros_like(a) 
np.empty_like(a)
np.ones_like(a)