NumPy
Complete Beginner-to-Intermediate Study Notes
Built from a Full Video Tutorial — A Professional Textbook-Style Reference
How to use these notes: Read them in order, just as the video was taught. Every concept, tip, warning, and
example from the tutorial is preserved here — explained more clearly and expanded for beginners. No need to
re-watch the video.
Table of Contents
• 1. Introduction to NumPy
• 2. Installing and Importing NumPy
• 3. What is a NumPy Array?
• 4. Array Restrictions — The Rules NumPy Enforces
• 5. Array Fundamentals — Indexing and Slicing
• 6. Views vs Copies — A Critical Difference
• 7. Multi-Dimensional Arrays (Matrices)
• 8. Important Array Attributes
• 9. Special Methods for Creating Arrays
• 10. Sorting, Concatenating, and Reshaping Arrays
• 11. Adding New Axes — expand_dims and [Link]
• 12. Advanced Indexing — Conditions and Boolean Masking
• 13. Stacking Arrays — hstack and vstack
• 14. Array Operations and Broadcasting
• 15. Useful Statistical Operations
• 16. Matrix Indexing, Slicing, and Operations
• 17. Random Number Generation
• 18. Unique Elements and Counts
• 19. Transposing and the .T Attribute
• 20. Reversing Arrays — [Link]
• 21. Flattening Arrays — flatten vs ravel
• 22. Saving and Loading NumPy Data
• 23. Master Comparison Tables
• 24. Full Quick-Revision Summary
• 25. Practice Questions and Answers
1. Introduction to NumPy
What is NumPy?
NumPy stands for Numerical Python. It is one of Python's most popular and powerful libraries, forming the
backbone of nearly every data science, machine learning, and scientific computing workflow in Python.
Purpose / Why it is used
Without NumPy With NumPy
Python's built-in list is flexible but slow NumPy arrays are fast, memory-efficient, and built for math
Can't do element-wise math on lists easily Element-wise operations are built-in
No shape, dimension, or type enforcement Arrays have enforced shapes and types — enabling optimization
Slow iteration needed for operations Vectorized operations run at near-C speed
NumPy is primarily used for: fast numerical computing, multi-dimensional arrays and matrices, scientific
computing (linear algebra, statistics, Fourier transforms), and as a foundation for other libraries — Pandas,
Matplotlib, scikit-learn, TensorFlow, and PyTorch all use NumPy under the hood.
Note: NumPy arrays store data in contiguous blocks of memory (like C/C++ arrays), and operations are
implemented in optimized C code. Python lists store references to objects scattered in memory, which is much
slower.
2. Installing and Importing NumPy
Installing NumPy
pip install numpy
Importing NumPy
import numpy as np
Part Meaning
import Python keyword to bring in an external library
numpy The full name of the library
as np An alias — shortens numpy to np for convenience
Tip: Always use np as the alias. This is the universal convention. Never use a different alias like import numpy
as num.
3. What is a NumPy Array?
A NumPy array is a grid of values, all of the same data type, arranged in one or more dimensions.
Dimensions of Arrays
1D Array (Vector)
vector = [Link]([1, 2, 3, 4, 5, 6])
print(vector)
# [1 2 3 4 5 6]
Note: No commas in the output! This is how you distinguish a NumPy array from a Python list when printed.
2D Array (Matrix)
matrix = [Link]([[1, 2, 3], [4, 5, 6]])
print(matrix)
# [[1 2 3]
# [4 5 6]]
Mathematical Terminology vs NumPy Terminology
Dimensions Math Term NumPy Term
0D Scalar 0-dimensional array
1D Vector 1-dimensional array
2D Matrix 2-dimensional array
nD (n > 2) Tensor n-dimensional array
Note: The NumPy docs explicitly say: avoid using mathematical terms like "vector", "matrix", or "tensor" when
working with NumPy arrays, because the mathematical operations on these structures differ from NumPy's
operations.
4. Array Restrictions — The Rules NumPy Enforces
NumPy enforces three important restrictions on arrays. These restrictions are not bugs — they are the reason
NumPy is so fast and efficient.
Restriction 1: All Elements Must Be the Same Data Type
# Correct — all integers
vector = [Link]([1, 2, 3, 4, 5, 6])
# Insert a string — NumPy converts EVERYTHING to strings
bad_vector = [Link]([1, 2, 3, 4, 5, 'x'])
print(bad_vector) # ['1' '2' '3' '4' '5' 'x']
# Insert a float — NumPy converts ALL integers to floats
float_vector = [Link]([1, 2, 3, 4, 5, 6.6])
print(float_vector) # [1. 2. 3. 4. 5. 6.6]
Restriction 2: The Size of an Array Cannot Change After Creation
Once you create a NumPy array, you cannot append to it or remove from it directly. To change size, you must
create a new array.
vector = [Link]([1, 2, 3, 4, 5, 6])
new_vector = [Link](vector, [10, 20])
print(new_vector) # [1 2 3 4 5 6 10 20]
print(vector) # [1 2 3 4 5 6] — original unchanged
Note: [Link] does NOT modify the original array. It returns a new array. This is different from Python's
[Link](), which modifies the list in place.
Restriction 3: The Data Must Be Rectangular (No Jagged Arrays)
# Correct — both rows have 3 elements
matrix = [Link]([[1, 2, 3], [4, 5, 6]])
# Wrong — rows have different lengths — NumPy raises ValueError
bad_matrix = [Link]([[1, 2, 3], [4, 5]])
5. Array Fundamentals — Indexing and Slicing
Integer Indexing
array = [Link]([1, 2, 3, 4, 5, 6])
print(array[0]) # 1 — first element
print(array[2]) # 3 — third element
print(array[-1]) # 6 — last element (negative indexing)
Slice Notation: array[start:stop:step]
Component Default Meaning
start 0 Index to begin the slice
stop end of array Index to stop at (NOT included)
step 1 How many indices to skip between each element
array = [Link]([1, 2, 3, 4, 5, 6])
array[3:] # [4, 5, 6] — from index 3 onwards
array[:3] # [1, 2, 3] — first 3 elements
array[1:4] # [2, 3, 4] — index 1 to 3
array[::2] # [1, 3, 5] — step 2
array[::-1] # [6, 5, 4, 3, 2, 1] — reversed
Modifying Elements
array = [Link]([1, 2, 3, 4, 5, 6])
array[2] = 999
print(array) # [1 2 999 4 5 6]
6. Views vs Copies — A Critical Difference
This is one of the most important and commonly misunderstood concepts in NumPy.
Python List Slice — Returns a COPY
py_list = [1, 2, 3, 4, 5, 6]
py_slice = py_list[:3] # Creates an INDEPENDENT COPY
py_slice[0] = 999
print(py_slice) # [999, 2, 3]
print(py_list) # [1, 2, 3, 4, 5, 6] — ORIGINAL UNCHANGED
NumPy Slice — Returns a VIEW
array = [Link]([1, 2, 3, 4, 5, 6])
array_slice = array[0:3] # Creates a VIEW (NOT a copy)
array_slice[0] = 999
print(array_slice) # [999, 2, 3]
print(array) # [999, 2, 3, 4, 5, 6] — ORIGINAL ALSO CHANGED!
Note: NumPy creates a view (a window into the original data) to save memory and be faster. The slice points to
the same memory as the original.
How to Create an Independent Copy
array = [Link]([1, 2, 3, 4, 5, 6])
array_slice = array[0:3].copy() # Deep copy
array_slice[0] = 999
print(array) # [1, 2, 3, 4, 5, 6] — UNCHANGED
View vs Copy Comparison
Python List Slice NumPy Slice (view) NumPy .copy()
Type of result Independent copy View of original Independent copy
Modifying result affects original?
No Yes No
Memory efficiency Less efficient More efficient Less efficient
7. Multi-Dimensional Arrays (Matrices)
matrix = [Link]([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(matrix)
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
Understanding Axes
In NumPy, the term axis is used instead of "dimension." Axes are numbered starting at 0.
axis 0 — direction of rows (vertical)
axis 1 — direction of columns (horizontal)
Indexing a 2D Array — Syntax: matrix[row_index, col_index]
print(matrix[1, 2]) # 6 — row 1, column 2
print(matrix[2, 1]) # 8 — row 2, column 1
print(matrix[0, 0]) # 1 — row 0, column 0
8. Important Array Attributes
These are properties of a NumPy array, not methods — no parentheses needed.
array = [Link]([[1, 2, 3], [4, 5, 6]])
print([Link]) # 2
print([Link]) # (2, 3)
print([Link]) # 6
print([Link]) # int64
Attribute Description Example Result
.ndim Number of dimensions (axes) 2
.shape Tuple of dimension sizes (2, 3)
.size Total number of elements 6
.dtype Data type of elements int64
Common NumPy Data Types
dtype Description
int8, int16, int32, int64 Signed integers of 8, 16, 32, 64 bits
uint8, uint16, ... Unsigned integers
float16, float32, float64 Floating point numbers
bool True/False
complex64, complex128 Complex numbers
# Specify smaller integer type to save memory
arr = [Link]([[1, 2, 3], [4, 5, 6]], dtype=np.int16)
print([Link]) # int16
9. Special Methods for Creating Arrays
[Link]() — Array Filled with Zeros
[Link](5) # [0. 0. 0. 0. 0.] (float64 default)
[Link]((3, 5), dtype=int) # 3x5 matrix of integer zeros
[Link]() — Array Filled with Ones
[Link](4) # [1. 1. 1. 1.]
[Link]((2, 3, 4)) # 3D array of ones
[Link]() — Uninitialized Array (FAST)
e = [Link](5)
print(e) # Values are UNPREDICTABLE — whatever is in memory
Note: Critical Warning: Never use [Link] if you need zeros or specific values. The content is garbage from
previous memory operations. Only use it when you will overwrite every value manually.
[Link]() — Create a Range
[Link](10) # [0 1 2 3 4 5 6 7 8 9]
[Link](5, 10) # [5 6 7 8 9]
[Link](0, 20, 2) # [0 2 4 6 8 10 12 14 16 18]
Note: stop is always exclusive (not included). [Link](10) gives 0 through 9.
[Link]() — Linearly Spaced Values
[Link](0, 10, 3) # [ 0. 5. 10.] — 3 values between 0 and 10
[Link](0, 10, 5) # [ 0. 2.5 5. 7.5 10.]
[Link] vs [Link] Comparison
[Link] [Link]
You control Step size Number of elements
stop value Exclusive Inclusive
Output type Usually integers Usually floats
Use case When you know the step When you know how many points
Function Initial Values Speed Use Case
[Link] All 0 Moderate Default initialization, counters, masks
[Link] All 1 Moderate Multiplicative initialization, identity
[Link] Random/garbage Fastest When you'll immediately overwrite all values
10. Sorting, Concatenating, and Reshaping Arrays
Sorting
array = [Link]([3, 2, 10, 1, 0])
# [Link]() — returns sorted copy
sorted_arr = [Link](array)
print(sorted_arr) # [0 1 2 3 10]
print(array) # [3 2 10 1 0] — UNCHANGED
# .sort() — in-place
[Link]()
print(array) # [0 1 2 3 10]
[Link](arr) [Link]()
Modifies original No — returns new array Yes — in-place
Return value Sorted copy None
When to use Need original + sorted Only need sorted version
Concatenating Arrays — [Link]()
a = [Link]([1, 2, 3])
b = [Link]([4, 5, 6])
c = [Link]([7, 8, 9])
[Link]((a, b)) # [1 2 3 4 5 6]
[Link]((a, b, c)) # [1 2 3 4 5 6 7 8 9]
Note: The arrays must be passed inside a tuple or list — not as separate arguments.
Reshaping Arrays — .reshape()
The Golden Rule of Reshaping: The total number of elements must be the same before and after reshaping.
original = [Link](10) # [0 1 2 3 4 5 6 7 8 9]
[Link](2, 5) # 2x5 = 10 ✓
# [[0 1 2 3 4]
# [5 6 7 8 9]]
[Link](5, 2) # 5x2 = 10 ✓
# [[0 1]
# [2 3]
# [4 5]
# [6 7]
# [8 9]]
arr = [Link](27)
[Link](3, 3, 3) # 3D reshape — 3x3x3 = 27 ✓
The -1 Shortcut
arr = [Link](27)
[Link](-1) # Flatten to 1D — same as (27,)
[Link](3, -1) # 3 rows, NumPy calculates 9 columns
[Link](-1, 3) # NumPy calculates 9 rows, 3 columns
Note: You can only use -1 for ONE dimension at a time. NumPy can only infer one unknown dimension.
11. Adding New Axes — expand_dims and [Link]
Sometimes you need to add an extra dimension to an array without changing the data — this is common when
preparing data for machine learning models.
Method 1: [Link]
array = [Link](3)
print([Link]) # (3,)
row = array[[Link], :] # Shape: (1, 3) — row vector
col = array[:, [Link]] # Shape: (3, 1) — column vector
Method 2: np.expand_dims() — More Readable
np.expand_dims(array, axis=0) # (1, 3)
np.expand_dims(array, axis=1) # (3, 1)
[Link] np.expand_dims
Readability Less readable More readable
Syntax Inline with slice notation Function call
Result Identical Identical
12. Advanced Indexing — Conditions and Boolean Masking
Boolean Masking / Conditional Indexing
matrix = [Link]([[1, 2, 3, 4], [5, 30, 40, 6]])
# Get all even numbers
print(matrix[matrix % 2 == 0]) # [ 2 4 30 40 6]
# Get all values less than 3
print(matrix[matrix < 3]) # [1 2]
# Get all values greater than 10
print(matrix[matrix > 10]) # [30 40]
Combining Multiple Conditions
array = [Link](20)
# Elements > 10 AND even
result = array[(array > 10) & (array % 2 == 0)]
print(result) # [12 14 16 18]
# Even numbers OR equals 15
result2 = array[(array % 2 == 0) | (array == 15)]
Note: Use & for AND, | for OR — not Python's and/or. NumPy needs element-wise comparison operators.
[Link]() — Getting Indices of Matching Elements
matrix = [Link]([[2, 3, 3], [4, 4, 6]])
# Get indices of even numbers
rows, cols = [Link](matrix % 2 == 0)
print(rows) # [0 1 1 1]
print(cols) # [0 0 1 2]
13. Stacking Arrays — hstack and vstack
[Link]() — Horizontal Stack (side by side)
A = [Link]([[1, 2], [3, 4]])
B = [Link]([[10, 20], [30, 40]])
[Link]((A, B))
# [[ 1 2 10 20]
# [ 3 4 30 40]]
[Link]() — Vertical Stack (on top of each other)
[Link]((A, B))
# [[ 1 2]
# [ 3 4]
# [10 20]
# [30 40]]
hstack vstack
Direction Horizontal (side by side) Vertical (on top)
Requirement Arrays must have same number of rows Arrays must have same number of columns
Similar to concatenate(axis=1) concatenate(axis=0)
14. Array Operations and Broadcasting
Element-wise Arithmetic Operations
first = [Link]([1, 2, 3])
second = [Link]([4, 5, 6])
print(first + second) # [5 7 9]
print(first - second) # [-3 -3 -3]
print(first * second) # [ 4 10 18]
print(first / second) # [0.25 0.4 0.5 ]
print(first ** second) # [ 1 32 729]
Broadcasting
Broadcasting is NumPy's mechanism for performing operations on arrays of different shapes by automatically
stretching the smaller array to match the larger one — without copying data.
# Scalar broadcasting
data = [Link]([1, 2, 3])
print(data * 3) # [3 6 9]
# 2D with scalar
data = [Link]([[1, 2], [3, 4]])
print(data * 4)
# [[ 4 8]
# [12 16]]
# 2D with compatible 1D array
data = [Link]([[1, 2], [3, 4]])
multiplier = [Link]([2, 3]) # Shape (2,)
print(data * multiplier)
# [[ 2 6]
# [ 6 12]]
Note: Two shapes are compatible when, from the rightmost dimension leftward, each dimension is either equal or
one of them is 1.
15. Useful Statistical Operations
Single-Value Operations on 1D Arrays
ages = [Link]([23, 25, 30, 21, 35, 28, 26, 28])
[Link]() # 35
[Link]() # 21
[Link]() # 216
[Link]() # 27.0
[Link]() # standard deviation
Operations on 2D Arrays with Axis
data = [Link](1, 17).reshape(4, 4)
[Link]() # 16 — overall max
[Link](axis=0) # [13 14 15 16] — max of each COLUMN
[Link](axis=1) # [ 4 8 12 16] — max of each ROW
Method Description
.max() Maximum value
.min() Minimum value
.sum() Sum of all elements
Method Description
.mean() Average (arithmetic mean)
.prod() Product of all elements
.std() Standard deviation
.var() Variance
.cumsum() Cumulative sum
All of these accept an optional axis argument.
16. Matrix Indexing, Slicing, and Operations
data = [Link]([[1, 2, 3], [3, 4, 5], [5, 6, 7]])
data[0] # [1 2 3] — first row
data[1, 1] # 4 — row 1, col 1
data[0:2] # First two rows
data[1:3, 0] # [3 5] — rows 1:3, column 0 only
# Matrix arithmetic
D1 = [Link]([[5, 6], [7, 8]])
D2 = [Link]([[1, 2], [3, 4]])
print(D1 + D2)
# [[ 6 8]
# [10 12]]
17. Random Number Generation
The modern way (recommended) is to use a Generator object with default_rng().
rng = [Link].default_rng()
# 4x3 matrix of random floats between 0 and 1
matrix = [Link]((4, 3))
# 2x5 matrix of random integers 0 to 10 (inclusive)
integers = [Link](0, 10, size=(2, 5), endpoint=True)
# Reproducible — use a seed
rng = [Link].default_rng(seed=42)
print([Link](3)) # Always produces the same output
Tip: Setting a seed guarantees the same random values every run, so others can reproduce your results.
18. Unique Elements and Counts
array = [Link]([1, 2, 2, 1, 6, 2, 1])
[Link](array) # [1 2 6]
# With first occurrence indices
unique, indices = [Link](array, return_index=True)
# indices: [0 1 4] — first occurrence of each value
# With occurrence counts
unique, counts = [Link](array, return_counts=True)
# counts: [3 3 1] — 1 appears 3x, 2 appears 3x, 6 appears 1x
# Unique rows in 2D array
matrix = [Link]([[1, 1, 2], [1, 1, 2], [6, 6, 7]])
[Link](matrix, axis=0) # Unique ROWS
19. Transposing and the .T Attribute
Transposing swaps the axes of an array. For a 2D matrix, it swaps rows and columns.
data = [Link](10).reshape(2, 5)
print([Link]) # (2, 5)
# Method 1: .transpose()
data = [Link]()
print([Link]) # (5, 2)
# Method 2: .T (shorthand — identical result)
print([Link]) # (2, 5)
20. Reversing Arrays — [Link]()
array = [Link](10)
[Link](array) # [9 8 7 6 5 4 3 2 1 0]
arr = [Link](12).reshape(3, 4)
[Link](arr) # Reverse all axes
[Link](arr, axis=0) # Flip rows (vertical flip)
[Link](arr, axis=1) # Flip columns (horizontal flip)
# Reverse only a specific row
arr[2] = [Link](arr[2])
# Reverse only a specific column
arr[:, 1] = [Link](arr[:, 1])
21. Flattening Arrays — flatten vs ravel
Both methods convert a multi-dimensional array into a 1D array, but they differ in whether they return a copy or a
view.
ones = [Link]((3, 4), dtype=int)
# flatten() — returns deep copy
new_ones = [Link]()
new_ones[0] = 999
print(ones) # UNCHANGED — it's a copy
# ravel() — returns view
new_ones = [Link]()
new_ones[0] = 999
print(ones) # CHANGED — it's a view
flatten() ravel()
Returns Deep copy View (usually)
Modifying result affects original? No Yes
Memory usage Higher Lower
Speed Slightly slower Slightly faster
When to use When you need independence When you just need 1D access
22. Saving and Loading NumPy Data
Saving and Loading a Single Array
# Save
[Link]('np_data', data) # Creates 'np_data.npy'
# Load
loaded = [Link]('np_data.npy')
Saving and Loading Multiple Arrays
# Save
[Link]('multiple_np', arr1=array1, arr2=array2)
# Load
np_loaded = [Link]('multiple_np.npz')
print(np_loaded.files) # ['arr1', 'arr2']
print(np_loaded['arr1']) # [1 2 3]
Saving as Text / CSV
[Link]('[Link]', data) # Text file
[Link]('[Link]', data, delimiter=',') # CSV file
loaded = [Link]('[Link]')
loaded = [Link]('[Link]', delimiter=',')
Format Function Preserves dtype? Human-readable? Speed
.npy [Link] Yes No (binary) Fast
.npz [Link] Yes No (binary) Fast
.txt [Link] No Yes Slower
.csv [Link] No Yes Slower
Tip: Use .npy or .npz for storing NumPy arrays. Only use .txt or .csv when you need to share data with someone
who doesn't use NumPy.
23. Master Comparison Tables
Python List vs NumPy Array
Feature Python List NumPy Array
Element types Mixed (any type) Same type only
Size after creation Can grow/shrink Fixed
Data structure Linked references Contiguous memory block
Arithmetic Not element-wise Element-wise (built-in)
Speed Slower Much faster
Slicing returns Copy View
Dimensions 1D only (nesting=workaround) True multi-dimensional
reshape Operations Overview
Original New Shape Valid? Product Check
10 elements (2, 5) Yes 2x5=10
10 elements (5, 2) Yes 5x2=10
10 elements (2, 6) No 2x6=12 ≠ 10
27 elements (3, 3, 3) Yes 3x3x3=27
Array Creation Methods Summary
Method Use When
[Link]([...]) You have the data already
[Link](shape) You need a blank array of zeros
Method Use When
[Link](shape) You need a blank array of ones
[Link](shape) Speed matters, you'll fill it yourself
[Link](n) You need a sequence with a specific step
[Link](a,b,n) You need N evenly spaced points between a and b
[Link](shape) You need random floats [0, 1)
[Link](lo, hi, size) You need random integers
24. Full Quick-Revision Summary
• NumPy Basics: NumPy = Numerical Python; fast, efficient numerical computing. Install: pip install numpy;
Import: import numpy as np (always use np).
• Array Restrictions: Arrays must have same element types, fixed size, rectangular shape.
• Array Types: 1D=vector, 2D=matrix, nD=tensor (they're all NumPy arrays). No commas in printed output.
• Indexing: Zero-indexed. 2D: array[row, col]. Slicing: array[start:stop:step].
• Views vs Copies: NumPy slices return views, not copies. Changes to a view affect the original. Use .copy()
for independence.
• Attributes: .ndim, .shape, .size, .dtype.
• Operations: Arithmetic is element-wise for same-shape arrays. Broadcasting extends smaller arrays. Use &
for AND, | for OR.
• Sort: [Link]() (copy) vs .sort() (in-place).
• Join: [Link](), [Link](), [Link]().
• Reshape: .reshape() — product must stay the same; -1 auto-infers dimension.
• Flip: [Link]() with optional axis argument.
• Flatten: .flatten() (copy) vs .ravel() (view).
• Transpose: .transpose() or .T.
• Unique: [Link]() with optional return_index, return_counts.
• Save/Load: .npy best format; .txt/.csv lose dtype info.
25. Practice Questions and Answers
Section 1: NumPy Basics and Restrictions
Q1. What are the three main restrictions of a NumPy array? Briefly explain why each exists.
1. Same data type — enables contiguous memory storage and vectorized operations.
2. Fixed size — memory is pre-allocated; no reallocation needed mid-operation.
3. Rectangular shape — allows formula-based element location: pos = row * cols + col.
Q2. What is the key difference between [Link]() and [Link]()?
[Link]() modifies the list in place and returns None. [Link]() does NOT modify the original; it ret
Q3. Create a 1D array [10, 20, 30, 40, 50] and change the value at index 3 to 999.
arr = [Link]([10, 20, 30, 40, 50])
arr[3] = 999
print(arr) # [10 20 30 999 50]
Q4. What will happen? arr = [Link]([1, 2, 'three', 4])
NumPy converts all elements to strings to maintain type uniformity. [Link] will be something like <U5 (U
Q5. What does [Link]((3, 3)) guarantee about the values it returns?
Nothing. [Link]() makes no guarantees — the content is whatever existed in that memory location. Only use
Section 2: Array Creation Methods
Q6. Create a 4x5 matrix of zeros with dtype int. What is the default dtype of [Link]()?
arr = [Link]((4, 5), dtype=int)
# Default dtype of [Link]() is float64
Q7. What is the difference between [Link](0, 10, 2) and [Link](0, 10, 5)?
[Link](0, 10, 2) → [0 2 4 6 8] — step is 2, stop exclusive
[Link](0, 10, 5) → [ 0. 2.5 5. 7.5 10.] — 5 points, stop inclusive
arange controls step size; linspace controls number of points.
Q8. Create an array of exactly 7 evenly spaced values between 1 and 4.
arr = [Link](1, 4, 7)
# [1. 1.5 2. 2.5 3. 3.5 4.]
Q9. Why would a data scientist use [Link]() over [Link]()?
[Link]() is faster because it skips the zeroing step. Use case: creating a large output buffer that you'l
Q10. Create a 3D array of ones with shape (2, 3, 4) and print ndim, shape, and size.
arr = [Link]((2, 3, 4))
print([Link]) # 3
print([Link]) # (2, 3, 4)
print([Link]) # 24
Section 3: Indexing, Slicing, Views, and Copies
Q11. Given arr = [Link](10), get [2,3,4], then [0,2,4,6,8], then reversed.
print(arr[2:5]) # [2 3 4]
print(arr[::2]) # [0 2 4 6 8]
print(arr[::-1]) # [9 8 7 6 5 4 3 2 1 0]
Q12. Explain what a 'view' is in NumPy.
A view is a window into the original array's memory — no data is copied. Changes to the view also change th
Q13. What is the output? arr = [Link]([1,2,3,4,5]); view = arr[1:4]; view[0] = 100; print(arr)
[1 100 3 4 5]
The view modifies index 0 of the view, which is index 1 of arr. Since they share memory, arr[1] becomes 100
Q14. Rewrite Q13 so modifying view does NOT affect arr.
arr = [Link]([1, 2, 3, 4, 5])
view = arr[1:4].copy() # Deep copy
view[0] = 100
print(arr) # [1 2 3 4 5] — unchanged
Q15. Access element 7 from matrix = [Link]([[1,2,3],[4,5,6],[7,8,9]]).
print(matrix[2, 0]) # 7 — row 2, column 0
Section 4: Reshaping, Broadcasting, and Operations
Q16. Reshape [Link](24) into shape (2,3,4), then into (6,4).
arr = [Link](24)
r1 = [Link](2, 3, 4) # 2x3x4 = 24 ✓
r2 = [Link](6, 4) # 6x4 = 24 ✓
Q17. What does the -1 do in [Link](-1)?
-1 tells NumPy to automatically calculate that dimension. [Link](-1) flattens to 1D. Use it when you d
Q18. Given a = [Link]([1,2,3]) and b = [Link]([10,20,30]), what is a * b?
a * b → [10 40 90]
Element-wise: 1x10=10, 2x20=40, 3x30=90.
Q19. Why does this raise a ValueError? a = [Link]([[1,2],[3,4]]); b = [Link]([10,20,30]); a + b
Shape (2,2) and shape (3,) are incompatible. Broadcasting requires dimensions to either be equal or one of
Q20. What is the difference between axis=0 and axis=1 when using .sum() on a 2D array?
arr = [Link]([[1,2,3],[4,5,6]])
[Link](axis=0) # [5 7 9] — sum each COLUMN (across rows)
[Link](axis=1) # [6 15] — sum each ROW (across columns)
Section 5: Advanced Operations
Q21. Extract all values divisible by 3 AND greater than 5 from [Link](20).
arr = [Link](20)
print(arr[(arr % 3 == 0) & (arr > 5)]) # [ 6 9 12 15 18]
Q22. What does [Link]() return? How is it different from boolean indexing?
[Link]() returns INDICES of matching elements as a tuple of arrays (one per dimension). Boolean indexin
Q23. Compare flatten() and ravel(). When would you prefer each?
Both flatten to 1D. flatten() returns a deep copy (safe to modify independently). ravel() returns a view (f
Q24. What is the difference between [Link]() (.npy) and [Link]() (.txt)?
.npy preserves dtype, shape, and all array metadata in a compact binary format. .txt is human-readable but
Q25. Stack two (3,2) matrices vertically (6,2) and horizontally (3,4).
A = [Link]((3, 2), dtype=int)
B = [Link]((3, 2), dtype=int) * 2
vertical = [Link]((A, B)) # Shape: (6, 2)
horizontal = [Link]((A, B)) # Shape: (3, 4)
Recommended next steps: Official NumPy docs at [Link]/doc — then move on to Pandas, and apply
NumPy in a data project (load CSV data, clean it, compute statistics). Explore [Link], [Link], and [Link] in
depth.