## Introduction

NumPy is a powerful library for numerical computing in Python. It provides support for arrays, matrices, and many mathematical functions to operate on these data structures. This tutorial covers the basics of using NumPy, including creating arrays, indexing, slicing, reshaping, and performing various operations.

1. NumPy Getting Started
2. NumPy Creating Arrays
3. NumPy Array Indexing
4. NumPy Array Slicing
5. NumPy Data Types
6. NumPy Copy vs View
7. NumPy Array Shape
8. NumPy Array Reshape
9. NumPy Array Iterating
10. NumPy Array Join
11. NumPy Array Split
12. NumPy Array Search
13. NumPy Array Sort
14. NumPy Array Filter

## 1. NumPy Getting Started

To get started with NumPy, you need to install the library. You can install NumPy using `pip`.

``````pip install numpy
``````

### Example

``````import numpy as np

# Checking the version of NumPy
print(np.__version__)
``````

## 2. NumPy Creating Arrays

NumPy arrays can be created using various methods such as `array()`, `zeros()`, `ones()`, `arange()`, and `linspace()`.

### Example

``````# Creating an array from a list
arr = np.array([1, 2, 3, 4, 5])
print(arr)

# Creating an array of zeros
zeros = np.zeros(5)
print(zeros)

# Creating an array of ones
ones = np.ones(5)
print(ones)

# Creating an array with a range of values
range_array = np.arange(1, 10, 2)
print(range_array)

# Creating an array with evenly spaced values
linspace_array = np.linspace(0, 1, 5)
print(linspace_array)
``````

## 3. NumPy Array Indexing

You can access elements of an array using indexing.

### Example

``````arr = np.array([10, 20, 30, 40, 50])

# Accessing individual elements
print(arr[0])  # Output: 10
print(arr[3])  # Output: 40

# Accessing elements in a 2D array
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr_2d[0, 1])  # Output: 2
print(arr_2d[1, 2])  # Output: 6
``````

## 4. NumPy Array Slicing

Slicing allows you to extract a portion of an array.

### Example

``````arr = np.array([10, 20, 30, 40, 50])

# Slicing elements from index 1 to 3
print(arr[1:4])  # Output: [20 30 40]

# Slicing elements with a step
print(arr[::2])  # Output: [10 30 50]

# Slicing a 2D array
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
print(arr_2d[:, 1:3])  # Output: [[2 3] [5 6]]
``````

## 5. NumPy Data Types

NumPy supports various data types, and you can specify the data type of an array during its creation.

### Example

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

# Changing data type of an array
arr_float = arr.astype('float64')
print(arr_float.dtype)  # Output: float64
``````

## 6. NumPy Copy vs View

In NumPy, a copy is a new array, and changes to the copy do not affect the original array, whereas a view is a new array object that looks at the same data.

### Example

``````arr = np.array([1, 2, 3, 4, 5])

# Creating a copy
arr_copy = arr.copy()
arr_copy[0] = 10
print(arr)       # Output: [1 2 3 4 5]
print(arr_copy)  # Output: [10  2  3  4  5]

# Creating a view
arr_view = arr.view()
arr_view[0] = 10
print(arr)       # Output: [10  2  3  4  5]
print(arr_view)  # Output: [10  2  3  4  5]
``````

## 7. NumPy Array Shape

The shape of an array is the number of elements in each dimension.

### Example

``````arr = np.array([[1, 2, 3], [4, 5, 6]])

# Getting the shape of the array
print(arr.shape)  # Output: (2, 3)
``````

## 8. NumPy Array Reshape

You can change the shape of an array using the `reshape()` method.

### Example

``````arr = np.array([1, 2, 3, 4, 5, 6])

# Reshaping the array to 2x3
reshaped_arr = arr.reshape((2, 3))
print(reshaped_arr)
``````

## 9. NumPy Array Iterating

You can iterate over the elements of an array using loops.

### Example

``````arr = np.array([1, 2, 3, 4, 5])

# Iterating over a 1D array
for x in arr:
print(x)

# Iterating over a 2D array
arr_2d = np.array([[1, 2, 3], [4, 5, 6]])
for row in arr_2d:
for element in row:
print(element)
``````

## 10. NumPy Array Join

You can join arrays using functions like `concatenate()`, `stack()`, and `hstack()`.

### Example

``````arr1 = np.array([1, 2, 3])
arr2 = np.array([4, 5, 6])

# Concatenating arrays
concatenated = np.concatenate((arr1, arr2))
print(concatenated)  # Output: [1 2 3 4 5 6]

# Stacking arrays
stacked = np.stack((arr1, arr2))
print(stacked)  # Output: [[1 2 3] [4 5 6]]
``````

## 11. NumPy Array Split

You can split arrays using the `split()` function.

### Example

``````arr = np.array([1, 2, 3, 4, 5, 6])

# Splitting the array into 3 parts
split_arr = np.split(arr, 3)
print(split_arr)  # Output: [array([1, 2]), array([3, 4]), array([5, 6])]
``````

## 12. NumPy Array Search

You can search for elements in an array using the `where()` function.

### Example

``````arr = np.array([1, 2, 3, 4, 5, 6])

# Searching for elements equal to 4
result = np.where(arr == 4)
print(result)  # Output: (array([3]),)
``````

## 13. NumPy Array Sort

You can sort arrays using the `sort()` function.

### Example

``````arr = np.array([3, 1, 4, 1, 5, 9])

# Sorting the array
sorted_arr = np.sort(arr)
print(sorted_arr)  # Output: [1 1 3 4 5 9]
``````

## 14. NumPy Array Filter

You can filter elements in an array using a boolean index list.

### Example

``````arr = np.array([1, 2, 3, 4, 5, 6])

# Creating a boolean index list
filter_arr = arr % 2 == 0

# Filtering the array
filtered_arr = arr[filter_arr]
print(filtered_arr)  # Output: [2 4 6]
``````

## Conclusion

NumPy is a powerful library for numerical computing in Python, providing support for arrays, matrices, and a wide range of mathematical functions. By understanding how to create, manipulate, and perform operations on arrays, you can efficiently handle large datasets and perform complex computations in your Python projects. This tutorial covered the basics of NumPy, including creating arrays, indexing, slicing, reshaping, and performing various operations.