NumPy
A Complete Classroom Tutorial — Unit 4
Python Programming | 23CS203ES | KMIT | I Year II Semester
Topics Covered in This Tutorial
Topic 1 Basics of NumPy Arrays
Topic 2 Computation on NumPy Arrays: Universal
Functions
Topic 3 Aggregations: Min, Max, and Other Functions
Topic 4 Comparisons, Masks, and Boolean Logic
Topic 5 Fancy Indexing
Topic 6 Sorting Arrays
Topic 7 Structured Data: NumPy Structured Arrays
Topic: 1 — Basics of NumPy Arrays
1. Basics of NumPy Arrays
NumPy (Numerical Python) is Python's core library for numerical computation. Its central object is the
ndarray — an N-dimensional array that stores homogeneous data (all elements of the same type) in a
contiguous block of memory, making it far faster and more memory-efficient than Python lists.
1.1 Import Convention
import numpy as np # Always use this alias
Note: The alias np is universally adopted in all Python code, textbooks, and documentation. Always
use it.
1.2 Creating Arrays
From Python Lists
# 1-D array
a = [Link]([10, 20, 30, 40, 50])
print(a) # [10 20 30 40 50]
# 2-D array (matrix)
m = [Link]([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(m)
# [[1 2 3]
# [4 5 6]
# [7 8 9]]
# 3-D array
t = [Link]([[[1,2],[3,4]],[[5,6],[7,8]]])
print([Link]) # (2, 2, 2)
Built-in Creators
[Link]((3, 4)) # 3x4 all zeros
[Link]((2, 3)) # 2x3 all ones
[Link]((3, 3), 7) # 3x3 filled with 7
[Link](4) # 4x4 identity matrix
[Link](0, 20, 2) # [0 2 4 6 8 10 12 14 16 18]
[Link](0, 1, 6) # [0. 0.2 0.4 0.6 0.8 1. ]
[Link](3, 3) # 3x3 random floats [0,1)
[Link](1,101,size=(3,3)) # 3x3 random ints 1-100
1.3 Array Attributes
Every ndarray carries metadata about its structure:
a = [Link]([[1,2,3],[4,5,6]])
print([Link]) # 2 — number of dimensions
print([Link]) # (2, 3) — (rows, columns)
print([Link]) # 6 — total elements
print([Link]) # int64 — element data type
print([Link]) # 8 — bytes per element
print([Link]) # 48 — total bytes used
1.4 Data Types (dtype)
dtype Description Example
np.int32 / int64 Integer (32 or 64 bit) [Link]([1,2,3], dtype=np.int32)
np.float32 / Float (default float64) [Link]([1.5, 2.5])
float64
np.bool_ Boolean True/False [Link]([True, False])
np.complex128 Complex number [Link]([1+2j, 3+4j])
np.str_ / U10 String (fixed width) [Link](['Ravi','Priya'])
# Explicit dtype
a = [Link]([1, 2, 3], dtype=np.float64)
print([Link]) # float64
# Type conversion
b = [Link](np.int32)
print([Link]) # int32
1.5 Array Indexing and Slicing
1-D Indexing
a = [Link]([10, 20, 30, 40, 50])
print(a[0]) # 10 — first element
print(a[-1]) # 50 — last element
print(a[1:4]) # [20 30 40]
print(a[::2]) # [10 30 50] — every 2nd
print(a[::-1]) # [50 40 30 20 10] — reversed
2-D Indexing
m = [Link]([[1,2,3],[4,5,6],[7,8,9]])
print(m[0, 0]) # 1 — row 0, col 0
print(m[1, 2]) # 6 — row 1, col 2
print(m[0]) # [1 2 3] — entire row 0
print(m[:, 1]) # [2 5 8] — entire col 1
print(m[0:2, 1:3]) # [[2 3] — submatrix
# [5 6]]
1.6 Reshaping Arrays
a = [Link](12)
# reshape — total elements must stay the same
m = [Link](3, 4) # 3 rows, 4 cols
m = [Link](2, -1) # -1 means 'figure it out' -> (2,6)
# Flatten back to 1-D
flat = [Link]() # returns a copy
flat = [Link]() # returns a view (faster)
# Transpose
print(m.T) # swaps rows and columns
print([Link]) # (4, 3) if m was (3, 4)
Topic: 2 — Computation on NumPy Arrays: Universal Functions
2. Computation on NumPy Arrays: Universal Functions
Universal Functions (ufuncs) are NumPy's secret weapon. They are pre-compiled functions that
operate element-by-element on arrays at C speed — no Python loops needed. A single ufunc call on an
array of 1 million elements is hundreds of times faster than an equivalent Python for loop.
Why ufuncs? Python loops are slow because each iteration goes through the Python interpreter.
NumPy ufuncs bypass this by working directly on the raw memory buffer in compiled C code.
2.1 Arithmetic ufuncs
a = [Link]([10, 20, 30, 40])
b = [Link]([ 1, 2, 3, 4])
[Link](a, b) # [11 22 33 44] same as a + b
[Link](a, b) # [ 9 18 27 36] same as a - b
[Link](a, b) # [10 40 90 160] same as a * b
[Link](a, b) # [10. 10. 10. 10.]
np.floor_divide(a, b) # [10 10 10 10] integer division
[Link](a, b) # [0 0 0 0] remainder
[Link](a, 2) # [100 400 900 1600]
[Link](a) # [-10 -20 -30 -40]
[Link]([-3,-1,2]) # [3 1 2]
2.2 Mathematical ufuncs
Exponential and Logarithm
a = [Link]([1, 2, 4, 8])
[Link](a) # [2.718 7.389 54.598 2981.0] — e^x
np.exp2(a) # [2. 4. 16. 256.] — 2^x
[Link](a) # [0. 0.693 1.386 2.079] — natural log
np.log2(a) # [0. 1. 2. 3.] — log base 2
np.log10(a) # [0. 0.301 0.602 0.903] — log base 10
Trigonometric
theta = [Link](0, [Link], 5)
# [0. 0.785 1.571 2.356 3.141]
[Link](theta) # [0. 0.707 1. 0.707 0.]
[Link](theta) # [1. 0.707 0. -0.707 -1.]
[Link](theta)
# Inverse trig
[Link]([0, 0.5, 1]) # [0. 0.524 1.571]
[Link]([1, 0.5, 0]) # [0. 1.047 1.571]
[Link]([0, 1, [Link]]) # [0. 0.785 1.571]
# Convert degrees <-> radians
[Link]([0, [Link]/2, [Link]]) # [0. 90. 180.]
[Link]([0, 90, 180]) # [0. 1.571 3.141]
Rounding
a = [Link]([1.234, 2.567, 3.891, -1.5])
[Link](a, 2) # [ 1.23 2.57 3.89 -1.5 ]
[Link](a) # [ 1. 2. 3. -2.] — round DOWN
[Link](a) # [ 2. 3. 4. -1.] — round UP
[Link](a) # [ 1. 2. 3. -1.] — towards zero
[Link](a) # [ 1. 3. 4. -2.] — round to nearest int
2.3 Specialised ufuncs
# Hyperbolic
[Link]([0, 1]) # [0. 1.175]
[Link]([0, 1]) # [1. 1.543]
# Sign and comparison
[Link]([-3, 0, 5]) # [-1 0 1]
[Link]([2,5,1],[3,4,7])# [3 5 7] — element-wise max
[Link]([2,5,1],[3,4,7])# [2 4 1] — element-wise min
# Square root and power
[Link]([4, 9, 16]) # [2. 3. 4.]
[Link]([8, 27, 64]) # [2. 3. 4.] — cube root
[Link]([2, 3, 4]) # [4 9 16]
[Link]([3],[4]) # [5.] — sqrt(a^2 + b^2)
2.4 ufunc Output Parameter
# Instead of creating a temporary array, write result directly
a = [Link](5, dtype=float)
out = [Link](5)
[Link](a, 10, out=out) # writes to out in-place
print(out) # [ 0. 10. 20. 30. 40.]
Performance tip: The out= parameter avoids allocating a new array for the result. For very large
arrays this can significantly reduce memory usage.
Topic: 3 — Aggregations: Min, Max, and Other Functions
3. Aggregations: Min, Max, and Other Functions
Aggregation functions reduce an array to a single summary value — or to a smaller array when applied
along a specific axis. They are the statistical backbone of NumPy.
3.1 Basic Aggregations
marks = [Link]([85, 92, 78, 88, 74, 96, 61])
[Link](marks) # 574
[Link](marks) # 61
[Link](marks) # 96
[Link](marks) # 82.0
[Link](marks) # 85.0
[Link](marks) # 11.37 — standard deviation
[Link](marks) # 129.3 — variance
# Equivalent method syntax
[Link]() # 574
[Link]() # 61
[Link]() # 96
[Link]() # 82.0
3.2 Index of Min / Max
marks = [Link]([85, 92, 78, 88, 74, 96, 61])
[Link](marks) # 6 — index of minimum value (61)
[Link](marks) # 5 — index of maximum value (96)
# Practical use: find which student scored highest
names = [Link](['Ravi','Priya','Arjun','Meena','Kiran','Sita','Ram'])
print('Top scorer:', names[[Link](marks)]) # Sita
print('Lowest scorer:', names[[Link](marks)]) # Ram
3.3 Aggregation Along an Axis
For 2-D arrays, you can aggregate along a specific axis:
• axis=0 — collapse rows, operate DOWN each column (result has one value per column)
• axis=1 — collapse columns, operate ACROSS each row (result has one value per row)
# Marks: rows = students, columns = subjects
marks = [Link]([[85, 78, 90], # Ravi
[92, 88, 80], # Priya
[74, 85, 91]]) # Arjun
# Global
print([Link](marks)) # 763
print([Link](marks)) # 92
# axis=0 : result per COLUMN (subject averages)
print([Link](marks, axis=0)) # [83.67 83.67 87. ]
print([Link](marks, axis=0)) # [92 88 91]
# axis=1 : result per ROW (student averages)
print([Link](marks, axis=1)) # [84.33 86.67 83.33]
print([Link](marks, axis=1)) # [90 92 91]
Common mistake: Many students confuse axis=0 and axis=1. Remember: axis=0 removes rows
(collapses vertically), axis=1 removes columns (collapses horizontally).
3.4 Other Useful Aggregations
a = [Link]([1, 2, 3, 4, 5])
[Link](a) # [ 1 3 6 10 15] — running total
[Link](a) # [ 1 2 6 24 120] — running product
[Link](a) # 120
[Link](a) # 4 — peak-to-peak (max - min)
[Link](a, 75) # 4.0 — 75th percentile
[Link](a, 0.25) # 2.0 — 25th percentile (Q1)
# NaN-safe versions (ignore NaN values)
b = [Link]([1.0, 2.0, [Link], 4.0])
[Link](b) # 7.0
[Link](b) # 2.33
[Link](b) # 4.0
Topic: 4 — Comparisons, Masks, and Boolean Logic
4. Comparisons, Masks, and Boolean Logic
NumPy can apply comparison operators across entire arrays at once, producing Boolean arrays. These
Boolean arrays — called masks — can then be used to filter, count, and select data without writing a
single loop.
4.1 Comparison Operators
a = [Link]([10, 25, 13, 42, 8, 31])
a > 20 # [False True False True False True]
a < 20 # [ True False True False True False]
a == 25 # [False True False False False False]
a != 25 # [ True False True True True True]
a >= 13 # [False True True True False True]
a <= 13 # [ True False True False True False]
Note: Comparison of arrays returns a Boolean ndarray, NOT a single True/False value. Each element
is compared independently.
4.2 Using Masks to Filter Data
marks = [Link]([85, 92, 78, 88, 74, 96, 61])
# Step 1: Create a mask
mask = marks > 80
print(mask) # [ True True False True False True False]
# Step 2: Apply mask — returns only True elements
print(marks[mask]) # [85 92 88 96]
# One-liner (most common usage)
print(marks[marks > 80]) # [85 92 88 96]
# Also works with string arrays
names = [Link](['Ravi','Priya','Arjun','Meena','Kiran'])
scores = [Link]([85, 92, 78, 88, 74])
print(names[scores >= 85]) # ['Ravi' 'Priya' 'Meena']
4.3 Counting and Checking with Boolean Arrays
marks = [Link]([85, 92, 78, 88, 74, 96, 61])
# Count how many satisfy a condition (True = 1, False = 0)
[Link](marks > 80) # 4 — four students scored above 80
np.count_nonzero(marks > 80) # 4 — same result
# What fraction/percentage passed?
[Link](marks > 80) # 0.571 — 57.1% scored above 80
# Does ANY element satisfy condition?
[Link](marks > 90) # True
[Link](marks > 100) # False
# Do ALL elements satisfy condition?
[Link](marks > 60) # True
[Link](marks > 70) # False (61 fails)
4.4 Boolean Logic: AND, OR, NOT
Combine multiple conditions using bitwise operators (NOT Python's and/or keywords):
Python keyword NumPy operator Example
and & marks[( marks>70 ) & ( marks<90 )]
or | marks[( marks<65 ) | ( marks>90 )]
not ~ marks[~( marks == 85 )]
xor ^ (a>5) ^ (b>5)
marks = [Link]([85, 92, 78, 88, 74, 96, 61])
# Between 80 and 90 (exclusive)
print(marks[(marks > 80) & (marks < 90)]) # [85 88]
# Below 70 OR above 90
print(marks[(marks < 70) | (marks > 90)]) # [92 96 61]
# NOT equal to 88
print(marks[~(marks == 88)]) # [85 92 78 74 96 61]
# IMPORTANT: Always wrap each condition in parentheses!
# marks[marks > 80 & marks < 90] -- WRONG, causes error
# marks[(marks > 80) & (marks < 90)] -- CORRECT
Critical: Never use Python's and / or keywords with NumPy arrays — they raise an error on arrays
with more than one element. Always use & | ~ with parentheses around each condition.
4.5 [Link] — Conditional Selection
[Link](condition, value_if_true, value_if_false) is NumPy's vectorised if-else:
marks = [Link]([85, 92, 78, 55, 74, 96, 38])
# Assign grade: PASS if >= 40, else FAIL
result = [Link](marks >= 40, 'PASS', 'FAIL')
print(result) # ['PASS' 'PASS' 'PASS' 'PASS' 'PASS' 'PASS' 'FAIL']
# Replace values: cap marks at 90
capped = [Link](marks > 90, 90, marks)
print(capped) # [85 90 78 55 74 90 38]
# Get INDICES where condition is True
idx = [Link](marks > 80)
print(idx) # (array([0, 1, 5]),) — tuple of index arrays
print(idx[0]) # [0 1 5]
Topic: 5 — Fancy Indexing
5. Fancy Indexing
Fancy indexing means passing an array of indices (instead of a single integer or slice) to select multiple
elements in one operation. It gives you surgical control over which elements to extract — in any order,
with repetition if needed.
5.1 Integer Array Indexing — 1-D
a = [Link]([10, 20, 30, 40, 50, 60, 70, 80])
# Pass a list of indices
idx = [Link]([0, 3, 6])
print(a[idx]) # [10 40 70]
# Indices can be in any order
print(a[[5, 1, 3]]) # [60 20 40]
# Indices can repeat
print(a[[0, 0, 2, 2]]) # [10 10 30 30]
5.2 Integer Array Indexing — 2-D
m = [Link]([[10, 20, 30],
[40, 50, 60],
[70, 80, 90]])
# Select specific (row, col) pairs
rows = [Link]([0, 1, 2])
cols = [Link]([2, 0, 1])
print(m[rows, cols]) # [30 40 80] — m[0,2], m[1,0], m[2,1]
# Select entire rows
print(m[[0, 2]]) # [[10 20 30] rows 0 and 2
# [70 80 90]]
# Select entire columns
print(m[:, [0, 2]]) # [[10 30] columns 0 and 2
# [40 60]
# [70 90]]
5.3 Combined Fancy + Slice Indexing
m = [Link](12).reshape(4, 3)
# [[ 0 1 2]
# [ 3 4 5]
# [ 6 7 8]
# [ 9 10 11]]
# Select rows 0 and 2, all columns
print(m[[0, 2], :]) # [[0 1 2] [6 7 8]]
# Select rows 1 and 3, columns 0 and 2
print(m[np.ix_([1, 3], [0, 2])])
# [[ 3 5]
# [ 9 11]]
np.ix_(): np.ix_(row_list, col_list) creates an open mesh from two arrays — useful when you want all
combinations of selected rows and columns (a submatrix), rather than specific row-col pairs.
5.4 Modifying Values with Fancy Indexing
a = [Link](8, dtype=int)
idx = [Link]([1, 3, 5, 7])
a[idx] = 99
print(a) # [ 0 99 0 99 0 99 0 99]
# Increment specific positions
a[idx] += 1
print(a) # [ 0 100 0 100 0 100 0 100]
# Caution with repeated indices — only last assignment wins
a = [Link](4, dtype=int)
a[[0, 0, 1]] = [5, 10, 3]
print(a) # [10 3 0 0] — index 0 was overwritten
5.5 Fancy Indexing vs Slicing
Feature Slicing Fancy Indexing
Syntax a[1:4] a[[1,2,3]]
Returns a VIEW (no copy) a COPY (new array)
Order Must be sequential Any order, repeats allowed
Modifiable Yes, modifies original Yes, modifies original
Topic: 6 — Sorting Arrays
6. Sorting Arrays
NumPy provides fast sorting routines that work on arrays of any shape and dimension. There are two
flavours: functions that return a sorted copy, and methods that sort in-place.
6.1 [Link]() — Returns a Sorted Copy
a = [Link]([42, 15, 8, 73, 27, 61])
# Ascending (default)
print([Link](a)) # [ 8 15 27 42 61 73]
# Descending
print([Link](a)[::-1])# [73 61 42 27 15 8]
# Original is UNCHANGED
print(a) # [42 15 8 73 27 61]
6.2 [Link]() — Sorts In-Place
a = [Link]([42, 15, 8, 73, 27, 61])
[Link]() # modifies a directly
print(a) # [ 8 15 27 42 61 73]
6.3 Sorting 2-D Arrays Along an Axis
m = [Link]([[3, 1, 2],
[9, 4, 7],
[6, 8, 5]])
# Sort each ROW (axis=1 — sort along columns within each row)
print([Link](m, axis=1))
# [[1 2 3]
# [4 7 9]
# [5 6 8]]
# Sort each COLUMN (axis=0 — sort along rows within each col)
print([Link](m, axis=0))
# [[3 1 2]
# [6 4 5]
# [9 8 7]]
6.4 [Link]() — Returns Sorted Indices
argsort() doesn't return the sorted values — it returns the indices that would sort the array. This is
extremely useful when you want to know which element came first, second, etc.
marks = [Link]([85, 92, 78, 88, 74])
names = [Link](['Ravi','Priya','Arjun','Meena','Kiran'])
# Get indices that would sort marks (ascending)
idx = [Link](marks)
print(idx) # [4 2 0 3 1] — Kiran, Arjun, Ravi, Meena, Priya
# Use indices to sort both arrays together
print(marks[idx]) # [74 78 85 88 92]
print(names[idx]) # ['Kiran' 'Arjun' 'Ravi' 'Meena' 'Priya']
# Rank (descending — highest first)
idx_desc = [Link](marks)[::-1]
print(names[idx_desc]) # ['Priya' 'Meena' 'Ravi' 'Arjun' 'Kiran']
6.5 [Link]() — Sort by Multiple Keys
lexsort() sorts by multiple criteria — like sorting a table by primary key first, then secondary key.
# Sort students: primary = marks (descending), secondary = name (ascending)
names = [Link](['Meena','Ravi','Priya','Arjun','Kiran'])
marks = [Link]([88, 85, 88, 78, 88 ])
# lexsort sorts by LAST key first
# To sort by marks DESC then name ASC:
idx = [Link]((names, -marks))
print(names[idx]) # ['Kiran' 'Meena' 'Priya' 'Ravi' 'Arjun']
print(marks[idx]) # [88 88 88 85 78]
6.6 [Link]() — Partial Sort
When you only need the k smallest or largest elements (not a full sort), [Link]() is much faster:
a = [Link]([42, 15, 8, 73, 27, 61, 34])
# Rearrange so the 3 smallest are on the left (not necessarily sorted)
print([Link](a, 3)) # [ 8 15 27 | 42 73 61 34]
# first 3 guaranteed to be smallest
# Get the 3 smallest values
print([Link](a, 3)[:3]) # [ 8 15 27]
# Get the 3 largest
print([Link](a, -3)[-3:]) # [42 61 73]
Topic: 7 — Structured Data: NumPy Structured Arrays
7. Structured Data: NumPy Structured Arrays
A standard NumPy array holds one type of data (all integers, or all floats). A structured array can hold
multiple fields of different types in each element — like a row in a database table or a C struct. Each
row has named fields that can be accessed by name.
7.1 Creating a Structured Array
Method 1 — Define dtype with a list of (name, type) tuples
import numpy as np
# Define the structure: name (string 20), age (int), marks (float)
dt = [Link]([('name', 'U20'), ('age', 'i4'), ('marks', 'f4')])
# Create the array
students = [Link]([
('Ravi', 20, 85.5),
('Priya', 19, 92.0),
('Arjun', 21, 78.3),
('Meena', 20, 88.7),
('Kiran', 22, 74.1)
], dtype=dt)
print(students)
# [('Ravi', 20, 85.5) ('Priya', 19, 92. ) ('Arjun', 21, 78.3)
# ('Meena', 20, 88.7) ('Kiran', 22, 74.1)]
Method 2 — [Link] with structured dtype
dt = [Link]([('name','U20'), ('roll','i4'), ('cgpa','f4')])
# Create empty array, then fill fields
data = [Link](3, dtype=dt)
data['name'] = ['Ravi', 'Priya', 'Arjun']
data['roll'] = [101, 102, 103]
data['cgpa'] = [8.5, 9.1, 7.8]
print(data)
7.2 dtype Type Codes
Code Meaning Example
'i4' 32-bit integer age, roll number
'i8' 64-bit integer large IDs
'f4' 32-bit float marks, GPA
'f8' 64-bit float (default) precise measurements
'U10' Unicode string, 10 chars short names
'U50' Unicode string, 50 chars long names / addresses
'b' Boolean pass/fail flag
7.3 Accessing Fields
# Access entire field (column) by name
print(students['name']) # ['Ravi' 'Priya' 'Arjun' 'Meena' 'Kiran']
print(students['marks']) # [85.5 92. 78.3 88.7 74.1]
print(students['age']) # [20 19 21 20 22]
# Access a specific row
print(students[0]) # ('Ravi', 20, 85.5)
# Access a specific field of a specific row
print(students[1]['name']) # Priya
print(students[1]['marks']) # 92.0
7.4 Operations on Structured Arrays
# Statistical operations on a single field
print([Link](students['marks'])) # 92.0
print([Link](students['marks'])) # 83.72
print([Link](students['age'])) # 19
# Boolean masking on a field
toppers = students[students['marks'] > 85]
print(toppers['name']) # ['Ravi' 'Priya' 'Meena']
# Sort structured array by a field
sorted_by_marks = [Link](students, order='marks')
print(sorted_by_marks['name']) # ['Kiran' 'Arjun' 'Ravi' 'Meena' 'Priya']
# Sort descending
sorted_desc = sorted_by_marks[::-1]
print(sorted_desc['name']) # ['Priya' 'Meena' 'Ravi' 'Arjun' 'Kiran']
7.5 Nested dtypes
# A student with a nested 'scores' struct (mid, end, lab)
dt = [Link]([
('name', 'U20'),
('roll', 'i4'),
('scores', [('mid','f4'), ('end','f4'), ('lab','f4')])
])
data = [Link]([
('Ravi', 101, (28.0, 52.0, 18.0)),
('Priya', 102, (30.0, 55.0, 20.0)),
], dtype=dt)
# Access nested field
print(data['scores']['mid']) # [28. 30.]
print(data['scores']['end']) # [52. 55.]
# Total marks = mid + end + lab
total = data['scores']['mid'] + data['scores']['end'] + data['scores']
['lab']
print(total) # [98. 105.]
7.6 Converting Structured Array to Regular Array
# Extract just the marks column as a plain float array
marks_only = students['marks'].astype(np.float64)
print(type(marks_only)) # <class '[Link]'>
print(marks_only.dtype) # float64
# Convert structured array to a 2-D array (all fields as strings)
import [Link] as rfn
plain = rfn.structured_to_unstructured(students[['age','marks']])
print(plain)
# [[20. 85.5]
# [19. 92. ]
# [21. 78.3]
# [20. 88.7]
# [22. 74.1]]
Complete Worked Example — Student Performance Analyser
This program combines all 7 topics into one realistic application:
import numpy as np
# ── Structured array of students ──
dt = [Link]([('name','U20'), ('roll','i4'), ('marks','f4'),
('age','i4')])
students = [Link]([
('Ravi', 101, 85.5, 20),
('Priya', 102, 92.0, 19),
('Arjun', 103, 78.3, 21),
('Meena', 104, 88.7, 20),
('Kiran', 105, 74.1, 22),
('Sita', 106, 95.2, 19),
('Ram', 107, 61.0, 23),
], dtype=dt)
marks = students['marks']
names = students['name']
# ── Topic 3: Aggregations ──
print('=== Class Summary ===')
print(f'Highest : {[Link](marks):.1f} ({names[[Link](marks)]})')
print(f'Lowest : {[Link](marks):.1f} ({names[[Link](marks)]})')
print(f'Average : {[Link](marks):.2f}')
print(f'Std Dev : {[Link](marks):.2f}')
print(f'Median : {[Link](marks):.1f}')
# ── Topic 2: Universal Functions ──
# Normalise marks to 0-100 scale
normalised = (marks - [Link](marks)) / ([Link](marks) - [Link](marks)) *
100
print('Normalised scores:', [Link](normalised, 1))
# ── Topic 4: Comparisons and Masks ──
print('', 'Distinctions (>=85):', names[marks >= 85])
passed = [Link](marks >= 40)
print(f'Pass rate: {[Link](marks>=40)*100:.1f}% ({passed}/{len(marks)})')
# Grade using [Link] chain
grades = [Link](marks >= 85, 'A',
[Link](marks >= 70, 'B',
[Link](marks >= 55, 'C', 'F')))
for n, m, g in zip(names, marks, grades):
print(f' {n:<8}: {m:.1f} Grade {g}')
# ── Topic 5: Fancy Indexing ──
# Pick top 3 and bottom 3
top_idx = [Link](marks)[-3:][::-1]
bottom_idx = [Link](marks)[:3]
print('Top 3 :', names[top_idx])
print('Bottom 3:', names[bottom_idx])
# ── Topic 6: Sorting ──
sorted_students = [Link](students, order='marks')[::-1]
print('', '=== Rank List ===')
for i, s in enumerate(sorted_students):
print(f' Rank {i+1}: {s["name"]:<8} {s["marks"]:.1f}')
Quick Reference — All 7 Topics
Function / Syntax Topic Description
[Link]([...]) 1 — Basics Create ndarray from list
[Link], [Link], [Link] 1 — Basics Array metadata attributes
[Link](r,c) 1 — Basics Change shape
[Link](), [Link]() 2 — ufuncs Element-wise math functions
[Link](), [Link]() 2 — ufuncs Trig and log ufuncs
[Link](), [Link]() 3 — Aggregation Sum and mean (global or by
axis)
[Link](), [Link]() 3 — Aggregation Min and max values
[Link](), [Link]() 3 — Aggregation Index of min / max
[Link](), [Link]() 3 — Aggregation Standard deviation / variance
[Link](), [Link]() 3 — Aggregation Running total / product
a > 5, a == 3 4 — Masks Element-wise comparisons
a[(a>5) & (a<10)] 4 — Masks Boolean mask filtering
[Link](), [Link]() 4 — Masks Check if any/all satisfy
condition
[Link](cond, t, f) 4 — Masks Vectorised if-else
a[[0,3,5]] 5 — Fancy Indexing Index with integer array
m[np.ix_([0,2],[1,3])] 5 — Fancy Indexing Select submatrix
[Link](a) 6 — Sorting Returns sorted copy
[Link]() 6 — Sorting Sort in-place
[Link](a) 6 — Sorting Indices that would sort array
[Link](a, order='field') 6 — Sorting Sort structured array by field
[Link]([('f','type')]) 7 — Structured Define structured dtype
a['fieldname'] 7 — Structured Access field from structured
array
[Link](a, order='f') 7 — Structured Sort structured array by a field
KMIT | Python Programming | 23CS203ES | Unit 4 — NumPy | I Year II Semester