NumPy is an open-sourced scientific numerical library in Python. It is fundamentally used to perform mathematical calculations involving matrices and arrays. It contains numerous mathematical functions which are essentially high level and these functions operate on arrays to provide outputs.

NumPy was originally developed as ** Numeric**, by Jim Hugunin along with several other developers as contributors to the project. In the year 2005, Numarray, a similar kind of library that competed with Numeric, was brought together by Travis Oliphant. He incorporated the features of Numarray into Numeric, thereby creating NumPy.

*Also read: Difference Between Pandas Dataframe and Numpy Arrays*

## Key Features

Below are the most significant features of NumPy which make it really popular across the whole technological community.

**N-Dimensional Arrays**– NumPy is very fast, powerful, and versatile too. It uses the Vectorization technique to carry out mathematical operations. Also incorporates broadcasting and indexing as standard concepts for array computations.**Provides Number-based Computing Tools**– A lot of mathematical and complicated functions can be handled by NumPy. Some of them include linear algebra, random number generators, Fourier transforms, and so on which are widely utilized in scientific computing.**Ability to work with Multiple Connected Devices and Hardware**– Specifically termed interoperability, NumPy’s support for multiple types of hardware, computing platforms, Graphics Processing Units, distributed computing capabilities, and sparse array libraries integration makes it one of the most capable Python libraries utilized by the large community around it.**Optimized and Performant Code Execution**– NumPy incorporates the very performant C Code compilation at its core providing efficient and high-speed code executions.**User Friendly**– NumPy provides very readable and simple Python Syntax which makes it user-friendly. The code requirement for using it is minimal and easy to debug. Hence, making it usable and programmable by all levels of coders and across multiple industries.**Open-Source**– NumPy has a huge and diverse community around it with numerous open-source contributors. It carries a BSD license, developed, and maintained publically on GitHub.

## Examples of NumPy in real-world data analysis

NumPy is heavily used by the scientific community which makes it stand out at every important level. Below are a few examples providing a glimpse of them. The complete case studies can be read on the NumPy Official Website.

- First Image of a Black Hole – NumPy along with other scientific libraries like Matplotlib and SciPy, which use NumPy as dependencies, produced the first ever Black Hole Image leveraging the Event Horizon Telescope.
- Detection of Gravitational Waves – NumPy was used to confirm the existence of Gravitational Waves by LIGO scientists 100 years later after being initially predicted by Albert Einstein in the year 1916.
- Sports Analytics – Predictive Analytics and Data Modelling are heavily used by the sports industry to provide statistical analytics of teams as well as players to improve their performance. NumPy is used for this very purpose in most cases.
- Pose Estimation Using Deep Learning – Animal behaviour observations for better insights into motor controls, species, and timescales are being performed using NumPy by DeepLabCuts to conduct fast pace scientific studies.

## Theoretical NumPy Interview Questions

### 1. What is NumPy and what are its basic features?

NumPy is a scientific computing package/library in Python. It provides an array object that is of multi- dimensionality as well as multiple derived objects like masked arrays and matrices. The NumPy package is the ** ndarray** at its core. This is responsible for encapsulating n-dimensional arrays of homogeneous data types providing an optimized code compilation making it very performant. It is fundamentally used to perform mathematical and logical operations, implement basic linear algebra, manipulate array shapes, sort and select, I/O, perform discrete Fourier transforms, and so on.

### 2. In what language has NumPy been written?

NumPy is essentially a Python library. It is mainly written in C/C++ for the purpose of fast and optimized code execution. However, some portion of NumPy has also been written using Python.

### 3. What is the primary reason to use NumPy?

NumPy is a very popular Python library across various industries. Data Science is one of the main areas utilizing this library. Most scientific computations use arrays. While performing advanced and complex computations, efficient and fast code execution is inevitable to get results as fast as possible.

Although, Python lists are arrays as well, the processing time of these lists is up to 50 times slower than NumPy arrays, making it the most popular library to perform numerical and scientific calculations. In NumPy, the array object is referred to as ** ndarray **which provides many additional functional capabilities making it faster and easier to use.

### 4. What are some important differences between the standard Python sequences and NumPy arrays?

Below are some of the most significant differences between the two.

- Python list can grow dynamically whereas the size of NumPy arrays when created, has a fixed size. Thus, while we change the size of a
, it deletes the original array and creates a new one.*ndarray* - NumPy is much more performant while computing advanced mathematics and various other types of operations containing large numbers of data. Making computations using Python requires much more code and is also not as efficient as NumPy.
- The data type is the same for all the elements of a NumPy array so it takes up a fixed memory size, unlike a Python array. However, there is an exception that one can have arrays of objects (Python as well as Numpy) allowing different-sized elements for arrays.
- Much of the scientific community using Python-based packages for advanced calculations incorporate NumPy arrays. Python-based sequences are typically converted to NumPy arrays while pre-processing the data and also output the result as a NumPy array. Thus, the knowledge of NumPy arrays is required to write efficient Python-based scientific calculations.

### 5. What makes NumPy arrays faster than Python lists?

Lists, when created and saved, are stored at random memory locations, which if operated upon, take a longer time to get accessed and processed. This is where the NumPy array shines. They are stored as ndarrays at one continuous memory location making the manipulation and computation very efficient and optimized. This type of code execution is coherent with modern CPU architectures, hence, making NumPy a very fast and optimized Python library.

### 6. Briefly explain an array in the context of NumPy.

In the NumPy library, the array is a core data structure. Arrays contain the raw data information and provide methods to interpret an item and locate an element. The element in an array can be indexed in several ways and comprises a grid of elements.

The element type in an array is referred to as **dtype** and they have to be of the same data type as well. The number of dimensions pertains to the rank of the array. A tuple of integers is the shape of an array providing the array size along each of the dimensions.

### 7. List some of the important attributes of the NumPy *ndarray* object.

Below are some of the main attributes of a ** ndarray** object

**ndarray.shape**– It outputs the array dimensions. For a matrix containing**n rows**and**m columns**, the shape would be**(n, m)**. To get the number of axes for the given array**, ndarray.ndim**is used.**ndarray.dtype**– It describes the data type of the elements contained in an array. We can also specify the data type using standard Python. NumPy also provides additional dtypes of its own. Some of the examples are**numpy.int16, numpy.int32,**and**numpy.float64**.**ndarray.itemsize**– It outputs the size of each element of the given array inIt is the same as using*bytes.***ndarray.dtype.itemsize**. Letâ€™s say for example we have an array with elements of type**float64**. Its itemsize will be**8**which is the result of**64/8**. Another one is when the data type contained is**complex32**. Its itemsize will be**4**which is**32/8**.**ndarray.data**– It returns the memory location or the buffer where the array has been saved. It is not used often since we use indexing as references to that memory location to get the elements contained in the array.

### 8. What are Universal functions in NumPy?

Mathematical functions like **exp, sin, cos, add, sqrt,** and so on are called **universal functions** or **ufunc** in Numpy. They operate on an array going elementwise within NumPy and provide output as an array. They use **Vectorization** to implement the operations and also support broadcasting along with other methods like **accumulate** and **reduce**.

### 9. Explain the term Broadcasting in NumPy.

Whenever we have arrays of different dimensions, NumPy treats them in a uniform way while performing arithmetic, functional, bitwise as well as logical operations. This is termed **Broadcasting**. It is used to explain the operational behaviour which is done implicitly element-by-element.

### 10. How can we convert 1D arrays into 2D arrays?

To increase the dimension of a given array, we can use **np.newaxis** and **np.expand_dims** functions provided by NumPy. Thus, we can convert 1D to 2D, 2D to 3D and so on.

### 11. Explain the main difference between **copy **and **view **in NumPy.

When we use the **copy() function in NumPy**, it creates an entirely new array. The changes that we make in the original array is not reflected in the copied version of it. On the other hand, view() function is just the reflection of the original array. Whatever changes we make in the original array, will also be implemented in the array that has been invoked with the view function.

### 12. How are NumPy and Pandas different from each other?

Below are some of the differences between NumPy and Pandas.

- NumPy is much faster and memory efficient than Pandas.
- NumPy is used mainly for numerical calculations, whereas Pandas is used for broader purposes like data analysis and visualization.
- NumPy supports the usage of matrices and arrays data format, where Pandas can be used with Table Data, Excel files, CSV files, etc.
- NumPy uses arrays as its primary object and also are not indexed by default. Pandas use series and data frames as their primary object and additionally provide indexing as default.

### 13. State the differences between NumPy and SciPy.

NumPy implements basic functions namely indexing, sorting, and so on, which makes it lightweight and compact. SciPy, on the other hand, is used for complex computations involving algorithmic and algebraic functions. which makes it carry a lot more functionality.

The functions in NumPy are not defined very comprehensively, unlike SciPy. One of the constraints with NumPy is that the arrays being operated upon have to be of the same type or homogeneous. SciPy does not have this limitation of homogeneity making it a lot more flexible and versatile.

Numpy has been partially written in Python and the majority makes use of C language for code compilation and execution. SciPy has been written using Python only making it slow when compared to NumPy, but it also provides a lot more functions than NumPy.

### 14. What functions are provided by NumPy for array iteration?

`nditer()`

and `ndenumerate()`

functions provided by NumPy can be used to perform iteration operations on arrays of varied dimensions.

### 15. How can we join arrays in NumPy?

We can use `concatenate()`

and `stack()`

functions to join NumPy arrays. Both of the functions output similar results with the exception that the stacking operation is performed along a new axis, unlike concatenation.

## NumPy Coding Questions

### 1. How can we install NumPy?

**With Conda**

```
# Using an environment
conda create -n my-env
conda activate my-env
# Install using conda-forge
conda config --env --add channels conda-forge
# Installation command
conda install numpy
```

**With PIP**

```
pip install numpy
```

*Also read: Conda vs Pip: Choosing your Python package manager*

### 2. Import NumPy and create a simple array using it.

```
import numpy as np
array1 = np.array([10, 12, 14, 16])
print(array1)
```

### 3. How can we check the version of installed NumPy?

```
import numpy as np
np.__version__
# Output: '1.21.5'
```

### 4. How can we create arrays of different dimensions using NumPy? Also, check the dimensions.

```
import numpy as np
first_array = np.array(10) # 0D Array
second_array = np.array([21, 22, 23, 24, 25]) # 1D Array
third_array = np.array([[21, 22, 23], [24, 25, 26]]) # 2D Array
fourth_array = np.array([[[10, 20, 30], [40, 50, 60]], [[10, 20, 30], [40, 50, 60]]]) # 3D Array
first_array, first_array.ndim
# Output: (array(10), 0)
second_array, second_array.ndim
# Output: (array([21, 22, 23, 24, 25]), 1)
third_array, third_array.ndim
# Output:
"""
(array([[21, 22, 23],
[24, 25, 26]]),
2)
"""
fourth_array, fourth_array.ndim
# Output:
"""
(array([[[10, 20, 30],
[40, 50, 60]],
[[10, 20, 30],
[40, 50, 60]]]),
3)
"""
```

### 5. How can we create arrays of a higher dimension using NumPy?

```
import numpy as np
higher_dimension_array = np.array([10, 20, 30, 40], ndmin=7)
higher_dimension_array
# Output: array([[[[[[[10, 20, 30, 40]]]]]]])
'Dimensions :', higher_dimension_array.ndim
# Output: ('Dimensions :', 7)
```

### 6. Provide examples for the usage of NumPy *ndarray *attributes.

*ndarray*

**ndarray.shape**

```
import numpy as np
my_array = np.arange(10).reshape(2, 5)
my_array
# Output
"""
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
"""
my_array.shape
# Output
"""
(2, 5)
"""
```

**ndarray.dtype**

```
my_array.dtype
# Output
"""
dtype('int32')
"""
```

**ndarray.itemsize**

```
r_part = [2, 3, 4]
i_part = [6, 7, 8]
my_complex_array = np.array([r_part, i_part], dtype=complex)
my_complex_array
# Output
"""
array([[2.+0.j, 3.+0.j, 4.+0.j],
[6.+0.j, 7.+0.j, 8.+0.j]])
"""
my_complex_array.dtype
# Output
"""
dtype('complex128')
"""
my_complex_array.itemsize
# Output
"""
16
"""
```

**ndarray.data**

```
my_array.data
# Output
"""
<memory at 0x000001E8ABFEDBA0>
"""
```

### 7. How can we create arrays using NumPy with different data types?

We can create arrays using NumPy in several ways. The array type deduction is done from the element types contained in those sequences. Below are some examples.

**int Data Type**

```
first_array = np.array([1, 2, 3])
first_array
# Output: array([1, 2, 3])
first_array.dtype
# Output: dtype('int32')
```

**float Data Type**

```
second_array = np.array([2.3, 4.5, 6.7])
second_array
# Output: array([2.3, 4.5, 6.7])
second_array.dtype
# Output: dtype('float64')
```

**Multiple Data Type**

```
third_array = np.array([(2.3, 8.7, 3.2), (1, 2, 3)])
third_array
# Output
"""
array([[2.3, 8.7, 3.2],
[1. , 2. , 3. ]])
"""
```

### 8. How can we create a complex type array with NumPy?

```
import numpy as np
complex_type_array = np.array([[1, 2, 4], [9, 10, 5]], dtype=complex)
complex_type_array
# Output
"""
array([[ 1.+0.j, 2.+0.j, 4.+0.j],
[ 9.+0.j, 10.+0.j, 5.+0.j]])
"""
```

### 9. How do we create NumPy arrays using built-in functions?

**Creating array using “arange” function**

```
import numpy as np
np.arange(1, 20, 3)
# Output: array([ 1, 4, 7, 10, 13, 16, 19])
```

**Creating array with equivalent linear spacing**

```
import numpy as np
np.linspace(0, 1, 4 )
# Output : array([0. , 0.33333333, 0.66666667, 1. ])
```

**Creating an array of zeros of a fixed shape**

```
import numpy as np
np.zeros((4, 5))
# Output:
"""
array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]])
"""
```

**Creating an array of ones of a fixed shape**

```
import numpy as np
np.ones((4, 5))
# Output
"""
array([[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1.]])
"""
```

### 10. Give examples using the universal functions in NumPy.

```
import numpy as np
first_array = np.arange(1, 5)
second_array = np.arange(6, 10)
first_array, second_array
# Output: (array([1, 2, 3, 4]), array([6, 7, 8, 9]))
np.sqrt(first_array)
# Output: array([1. , 1.41421356, 1.73205081, 2. ])
np.add(first_array, second_array)
# Output: array([ 7, 9, 11, 13])
```

### 11. Create a 2D array using the `np.newaxis`

function in NumPy.

```
import numpy as np
# Create 1D array
first_array = np.array([3, 4, 5, 6, 7])
first_array.shape
# Output: (5,)
# Adding a new axis to our 1D array: with np.newaxis
second_array = first_array[np.newaxis, :]
second_array.shape
# Output: (1, 5)
# Adding another axis to our 2D array: with np.newaxis
third_array = second_array[np.newaxis, :]
third_array.shape
# Output: (1, 1, 5)
```

### 12. Create NumPy arrays showing the usage of `np.expand_dims`

function.

```
import numpy as np
# Creating a 1D array
first_array = np.arange(6)
first_array
# Output: array([0, 1, 2, 3, 4, 5])
first_array.shape
# Output: (6,)
# Adding a new axis to our 1D array at position 0: with np.expand_dims
second_array = np.expand_dims(first_array, axis=0)
second_array
# Output: array([[0, 1, 2, 3, 4, 5]])
second_array.shape
# Output: (1, 6)
# Adding a new axis to our 1D array at position 1: with np.expand_dims
third_array = np.expand_dims(first_array, axis=1)
third_array.shape
# Output: (6, 1)
```

### 13. Show some examples of accessing array values with 1D, 2D and 3D arrays.

- Accessing an element from a 1D array

```
import numpy as np
first_array = np.array([25, 30, 35, 40])
first_array[1] # Output: 30
```

- Accessing an element from a 2D array

```
import numpy as np
my_array = np.array([[22, 33, 44, 55], [66, 77, 88, 99]])
# Accessing row 2, element 3
my_array[1, 2] # Output: 88
```

- Accessing an element from a 3D array

```
import numpy as np
my_array = np.array([[[11, 22, 33], [44, 55, 66]], [[77, 88, 99], [100, 111, 122]]])
# Accessing 3rd element of 2nd array of 1st array
my_array[0, 1, 2] # Output: 66
```

### 14. Show an example of negative indexing with a NumPy 2D array.

```
import numpy as np
my_array = np.array([[77, 88, 99], [100, 111, 122]])
# Accessing the last element from the first dimension
my_array[0, -1] # Output: 99
```

### 15. How do we know the shape of an array? Also, reshape a 1D array first to 2D, and then a 1D array to a 3D array

```
import numpy as np
my_array = np.arange(16)
my_array
# Output: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])
# 1D Array
my_array.shape # Output: (16,)
```

- Convert 1D to 2D Array

```
my_array.reshape(4, 4)
"""
Output:
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11],
[12, 13, 14, 15]])
"""
```

- Convert 1D to 3D Array

```
# Convert 1D to 3D Array
my_array.reshape(4, 2, 2)
"""
Output:
array([[[ 0, 1],
[ 2, 3]],
[[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11]],
[[12, 13],
[14, 15]]])
"""
```

### 16. Show the usage of the **copy **function in NumPy.

```
import numpy as np
my_array = np.array([14, 15, 16, 17, 18])
my_array_copy = my_array.copy()
my_array[-1] = 100
print(my_array)
print(my_array_copy)
"""
Output:
[ 14 15 16 17 100]
[14 15 16 17 18]
"""
```

### 17. Show the usage of the **view** function in NumPy.

The view function creates an alias-like array of Numpy that copies all changes over to the new array.

```
import numpy as np
my_array = np.array([14, 15, 16, 17, 18])
my_array_view = my_array.view()
my_array[-1] = 100
print(my_array)
print(my_array_view)
"""
Output:
[ 14 15 16 17 100]
[ 14 15 16 17 100]
"""
```

### 18. How is **arange** function used in NumPy?

```
import numpy as np
my_array = np.arange(5)
my_array
# Output: array([0, 1, 2, 3, 4])
```

- arange: with “
**start**” and “**stop**“

```
my_array = np.arange(1, 10)
my_array
# Output: array([1, 2, 3, 4, 5, 6, 7, 8, 9])
```

- arange: with “
**start**” and “**stop**” and “**stepsize**“

```
my_array = np.arange(1, 14, 3)
my_array
# Output: array([ 1, 4, 7, 10, 13])
```

- arange:
**Negative****Count**with “**start**” and “**stop**” and “**stepsize**“

```
my_array = np.arange(25, 0, -4)
my_array
# Output: array([25, 21, 17, 13, 9, 5, 1])
```

### 19. Give examples iterating through 1D and 2D arrays in NumPy.

- 1D Array Iteration

```
import numpy as np
my_array = np.arange(5)
for eachItem in my_array:
print(eachItem)
"""
Output:
0
1
2
3
4
"""
```

- 2D Array Iteration

```
import numpy as np
my_array = np.array([[14, 15, 16], [17, 18, 19]])
for eachItem in my_array:
print(eachItem)
"""
Output:
[14 15 16]
[17 18 19]
"""
```

- Iterating over every scalar item in a 2D Array

```
import numpy as np
my_array = np.array([[14, 15], [17, 19]])
for each in my_array:
for eachItem in each:
print(eachItem)
"""
Output:
14
15
17
19
"""
```

### 20. How do we iterate with nditer() function?

```
import numpy as np
my_array = np.array([[12, 13], [14, 15]])
for each_scalar_item in np.nditer(my_array):
print(each_scalar_item)
"""
Output:
12
13
14
15
"""
```

### 21. Show the usage of nditer() function providing a step size.

```
import numpy as np
my_array = np.array([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]])
for eachItem in np.nditer(my_array[:, ::3]):
print(eachItem)
"""
Output:
0
3
5
8
"""
```

### 22. Give an example using ndenumerate() function.

```
import numpy as np
my_array = np.array([[12, 13], [14, 15]])
for index, eachItem in np.ndenumerate(my_array):
print(index, eachItem)
"""
Output:
(0, 0) 12
(0, 1) 13
(1, 0) 14
(1, 1) 15
"""
```

### 23. How are two arrays joined using concatenate function in NumPy?

```
import numpy as np
first_array = np.array([1, 2, 3])
second_array = np.array([4, 5, 6])
concatenated_array = np.concatenate((first_array, second_array))
concatenated_array
# Output: array([1, 2, 3, 4, 5, 6])
```

### 24. Join two NumPy arrays with the stack function.

```
import numpy as np
first_array = np.array([1, 2, 3])
second_array = np.array([4, 5, 6])
stacked_array = np.stack((first_array, second_array))
stacked_array
"""
Output:
array([[1, 2, 3],
[4, 5, 6]])
"""
```

### 25. How do we use the where() function in NumPy?

- Searching through all the indexes containing the value 10 in an array

```
import numpy as np
my_array = np.array([10, 20, 30, 10, 40, 50, 60, 10])
search_indexes_for_ten = np.where(my_array == 10)
search_indexes_for_ten
# Output: (array([0, 3, 7], dtype=int64),)
```

- Searching through all the indexes where the values are even

```
import numpy as np
my_array = np.array([10, 11, 12, 15, 21, 26])
search_indexes_for_even = np.where(my_array % 2 == 0)
search_indexes_for_even
# Output: (array([0, 2, 5], dtype=int64),)
```

## Summary

These were some of the important concepts and questions from the NumPy library. I hope this article helps to get a good overview of the functions and methods provided by NumPy.