# Revising NumPy: A Cheatsheet

## Introduction to NumPy

**NumPy** is a powerful Python library for numerical computing. It simplifies numerical computations by performing efficient operations on large multidimensional arrays and matrices.

Say goodbye to slow loops and hello to blazing speed!

```python
import numpy as np
```

---

## NumPy Array Creation

Create arrays using `array()` or functions such as `zeros()` and `ones()`. Think of it as building blocks for your data.

```python
arr = np.array([1, 2, 3])
zeros = np.zeros((2, 2))
ones = np.ones((3, 3))
```

---

## NumPy N-d Array Creation

Supports the creation of multi-dimensional arrays. Because 2D is cool, but N-D is cooler.

```python
nd_array = np.array([[1, 2], [3, 4]])
higher_dim = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
```

---

## NumPy Data Types

Specify or inspect array data types. Useful when you want to avoid unexpected data-type surprises.

```python
arr = np.array([1.0, 2.0], dtype=np.float32)
print(arr.dtype)  # float32
int_arr = np.array([1, 2, 3], dtype=np.int32)
print(int_arr.dtype)  # int32
```

---

## NumPy Array Attributes

Inspect the shape, size, and dimensions of arrays. It’s like peeking under the hood of your array.

```python
arr = np.array([[1, 2, 3], [4, 5, 6]])
print(arr.shape, arr.size, arr.ndim)  # (2, 3), 6, 2
```

---

## NumPy Input Output

Save and load arrays easily. Think of it as bookmarking your progress.

```python
np.save('array.npy', arr)
loaded = np.load('array.npy')
np.savetxt('array.txt', arr, delimiter=',')
loaded_txt = np.loadtxt('array.txt', delimiter=',')
```

---

## NumPy Array Indexing

Access elements by indices. Remember, NumPy arrays are 0-indexed!

```python
arr = np.array([10, 20, 30])
print(arr[0])  # 10
print(arr[-1])  # 30
```

---

## NumPy Array Slicing

Extract sub-arrays using slicing. It’s like cutting a slice of your data pizza.

```python
arr = np.array([1, 2, 3, 4, 5])
sub_arr = arr[1:4]  # [2, 3, 4]
every_other = arr[::2]  # [1, 3, 5]
```

---

## NumPy Array Reshaping

Change the shape without altering data. Rearrange your data like a Rubik’s cube.

```python
arr = np.array([1, 2, 3, 4, 5, 6])
reshaped = arr.reshape((2, 3))  # [[1, 2, 3], [4, 5, 6]]
flattened = reshaped.flatten()  # [1, 2, 3, 4, 5, 6]
```

---

## NumPy Arithmetic Array Operations

Perform element-wise operations. Because who wants to loop through elements manually?

```python
arr = np.array([1, 2, 3])
result_add = arr + 10  # [11, 12, 13]
result_mul = arr * 2  # [2, 4, 6]
```

---

## NumPy Array Functions

Built-in functions like `sum` and `mean` make life easier. They’re like your data’s best friends.

```python
arr = np.array([1, 2, 3, 4])
print(np.sum(arr))  # 10
print(np.mean(arr))  # 2.5
```

---

## NumPy Comparison/Logical Operations

Compare arrays element-wise. Great for filtering data with conditions.

```python
arr = np.array([1, 2, 3, 4])
print(arr > 2)  # [False, False, True, True]
print(np.logical_and(arr > 1, arr < 4))  # [False, True, True, False]
```

---

## NumPy Math Functions

Apply math functions directly. No need for calculators anymore.

```python
arr = np.array([1, 4, 9])
print(np.sqrt(arr))  # [1. 2. 3.]
print(np.power(arr, 2))  # [1 16 81]
```

---

## NumPy Constants

Use predefined constants like `pi`. For when you don’t want to remember 3.14159.

```python
print(np.pi)  # 3.141592653589793
print(np.e)  # 2.718281828459045
```

---

## NumPy Statistical Functions

Compute stats like median, and variance. Perfect for understanding your data’s personality.

```python
arr = np.array([1, 2, 3, 4])
print(np.median(arr))  # 2.5
print(np.var(arr))  # 1.25
```

---

## NumPy String Functions

Operate on strings in arrays. Because even text data needs some love.

```python
names = np.array(['Alice', 'Bob'])
print(np.char.upper(names))  # ['ALICE' 'BOB']
print(np.char.replace(names, 'o', '0'))  # ['Alice' 'B0b']
```

---

## NumPy Broadcasting

Perform operations on arrays with different shapes. It’s like magic, but with math.

```python
arr = np.array([1, 2, 3])
broadcasted = arr + np.array([10])  # [11, 12, 13]
expanded = arr + np.array([[10], [20]])  # [[11, 12, 13], [21, 22, 23]]
```

---

## NumPy Matrix Operations

Matrix multiplication, inversion, etc. Linear algebra geeks, rejoice!

```python
matrix = np.array([[1, 2], [3, 4]])
print(np.dot(matrix, matrix))  # Matrix multiplication
print(np.linalg.inv(matrix))  # Matrix inversion
```

---

## NumPy Set Operations

Find unique elements and intersections. Useful for deduplication and comparisons.

```python
set1 = np.array([1, 2, 3])
set2 = np.array([2, 3, 4])
print(np.union1d(set1, set2))  # [1 2 3 4]
print(np.setdiff1d(set1, set2))  # [1]
```

---

## NumPy Vectorization

Efficient operations on entire arrays. Skip the loops and embrace speed.

```python
arr = np.array([1, 2, 3])
vectorized = np.vectorize(lambda x: x ** 2)(arr)  # [1, 4, 9]
vectorized_add = np.vectorize(lambda x: x + 10)(arr)  # [11, 12, 13]
```

---

## NumPy Boolean Indexing

Filter elements based on conditions. Let your data speak for itself.

```python
arr = np.array([1, 2, 3, 4])
filtered = arr[arr > 2]  # [3, 4]
even = arr[arr % 2 == 0]  # [2, 4]
```

---

## NumPy Fancy Indexing

Access specific elements with lists/arrays. Fancy indeed!

```python
arr = np.array([10, 20, 30, 40])
print(arr[[0, 2]])  # [10, 30]
print(arr[[1, 3]])  # [20, 40]
```

---

## NumPy Random

Generate random numbers. Perfect for simulations and shuffling data.

```python
rand_arr = np.random.rand(3, 3)  # Uniform distribution
rand_ints = np.random.randint(0, 10, (2, 2))  # Random integers
```

---

## NumPy Linear Algebra

Handle linear algebra operations. Your math professor would approve.

```python
matrix = np.array([[1, 2], [3, 4]])
print(np.linalg.det(matrix))  # Determinant
print(np.linalg.eig(matrix))  # Eigenvalues and eigenvectors
```

---

## NumPy Histogram

Create histograms. Visualize data distribution like a pro.

```python
arr = np.array([1, 1, 2, 3, 3, 3, 4])
hist, bins = np.histogram(arr, bins=3)
print(hist)  # [2 1 4]
print(bins)  # [1. 2. 3. 4.]
```

---

## NumPy Interpolation

Interpolate data. Filling gaps has never been easier.

```python
x = [0, 1, 2]
y = [0, 1, 4]
print(np.interp(1.5, x, y))  # 2.5
print(np.interp([0.5, 1.5], x, y))  # [0.5, 2.5]
```

---

## NumPy Files

Read/write text/binary files. Share or save your work effortlessly.

```python
arr = np.array([[1, 2], [3, 4]])
np.savetxt('data.txt', arr)
loaded = np.loadtxt('data.txt')
np.save('data.npy', arr)
loaded_bin = np.load('data.npy')
```

---

## NumPy Error Handling

Handle errors gracefully. Because no one likes crashing code.

```python
try:
    result = np.sqrt(-1)
except FloatingPointError as e:
    print(e)  # Domain error
try:
    bad_index = arr[100]
except IndexError as e:
    print(e)  # Index out of bounds
```

---

## NumPy Date and Time

Work with date/time data. Time travel, but for data.

```python
dates = np.arange('2023-01-01', '2023-01-10', dtype='datetime64[D]')
duration = np.timedelta64(1, 'D')
print(dates + duration)  # Increment dates by one day
```

---

## NumPy Data Visualization

Combine with libraries like Matplotlib. Because pictures speak louder than numbers.

```python
import matplotlib.pyplot as plt
arr = np.array([1, 2, 3, 4])
plt.plot(arr)  # Line plot
plt.hist(arr)  # Histogram
plt.show()
```

---

## NumPy Universal Function

Operate element-wise using ufuncs. Fast and functional, just like NumPy.

```python
arr = np.array([1, 2, 3])
print(np.add(arr, 2))  # [3, 4, 5]
print(np.multiply(arr, 2))  # [2, 4, 6]
```

---
