NumPy for Data Analysts — Self Study Notes Sachin Tripathi
1. Introduction to NumPy
1.1 What is NumPy?
NumPy (Numerical Python) is Python's core library for fast, efficient numerical and array-based
computing. It provides a powerful data structure called the ndarray (n-dimensional array), along with a
huge collection of mathematical, statistical, and linear algebra functions that operate on it.
NumPy forms the foundation on which most data-analysis libraries — including pandas, scikit-learn, and
matplotlib — are built. A solid grip on NumPy arrays makes every other data-analysis tool easier to
understand.
1.2 Why NumPy is Important for Data Analysis
• Speed — NumPy arrays are implemented in C internally, making numerical operations far faster than
plain Python lists.
• Vectorization — operations apply to an entire array at once, without writing explicit loops.
• Lower memory usage — arrays store data compactly, since every element shares the same data type.
• Built-in statistics — ready-made functions for mean, median, standard deviation, percentiles, and
more — core to almost every analysis task.
• Foundation for other libraries — pandas DataFrames, matplotlib plots, and machine-learning
libraries are all built on top of NumPy arrays.
1.3 Installing and Importing NumPy
Installing NumPy (one-time setup)
NumPy is not part of core Python and must be installed once, using pip, in the terminal / command
prompt.
pip install numpy
Importing NumPy
By convention, NumPy is imported with the short alias np — a convention used throughout the entire
data-analysis ecosystem (pandas, matplotlib, etc.).
import numpy as np
print(np.__version__)
Output:
1.26.4 (the exact version shown depends on what is installed)
Page 2 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
2. NumPy Arrays (ndarray)
2.1 What is an ndarray?
An ndarray (n-dimensional array) is NumPy's core data structure — a grid of values, all of the same data
type, arranged along one or more dimensions and accessed using index positions.
Unlike a Python list, every element in a NumPy array must be of the same data type. This restriction is
exactly what allows NumPy to store data compactly and process it so quickly.
Note: Because every element must share one data type, NumPy automatically converts (upcasts) all
elements to a common type when a mix is provided — e.g. mixing an int and a float in the same array
converts every element to float.
2.2 Types of Arrays (by Dimension)
• 1-D array (vector) — a single row of values.
arr = [Link]([10, 20, 30])
• 2-D array (matrix) — values arranged in rows and columns.
arr = [Link]([[1, 2, 3], [4, 5, 6]])
• 3-D / N-D array — an array of matrices, commonly used for image data, batches, or higher-
dimensional datasets.
arr = [Link]([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
2.3 Creating Arrays — Different Methods
Method 1: Using [Link]() from a list
The most direct way to create an array — pass a Python list (or list of lists) into [Link]().
arr = [Link]([10, 20, 30, 40])
print(arr)
print(type(arr))
Output:
[10 20 30 40]
<class '[Link]'>
Page 3 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
Method 2: Using [Link]()
Creates an array of the given shape filled entirely with 0s — often used as a placeholder before filling in
real data.
zeros = [Link]((2, 3))
print(zeros)
Output:
[[0. 0. 0.]
[0. 0. 0.]]
Method 3: Using [Link]()
Creates an array of the given shape filled entirely with 1s.
ones = [Link]((3,))
print(ones)
Output:
[1. 1. 1.]
Method 4: Using [Link]()
Creates an array of the given shape, filled with a specific constant value.
fives = [Link]((2, 2), 5)
print(fives)
Output:
[[5 5]
[5 5]]
Method 5: Using [Link]()
Works like Python's range(), but returns a NumPy array directly; supports a start, stop, and step value.
arr = [Link](0, 10, 2)
print(arr)
Output:
[0 2 4 6 8]
Page 4 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
Method 6: Using [Link]()
Generates a given number of evenly spaced values between a start and stop value (inclusive) — very
useful for plotting axes.
arr = [Link](0, 1, 5)
print(arr)
Output:
[0. 0.25 0.5 0.75 1. ]
Method 7: Using [Link]()
Creates an identity matrix — 1s along the diagonal and 0s elsewhere — commonly used in linear
algebra.
identity = [Link](3)
print(identity)
Output:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
Method 8: Using [Link] (rand / randint)
Generates arrays of random numbers — useful for simulations, sampling, and testing. [Link]()
fixes the sequence so results are reproducible.
[Link](0)
rand_arr = [Link](1, 100, 5)
print(rand_arr)
Output:
[45 48 65 68 68] (exact values may vary slightly by NumPy version)
2.4 Array Attributes
Once an array is created, it carries useful attributes describing its structure — invaluable for quickly
exploring an unfamiliar dataset before analysis.
ndim, shape, size, dtype, itemsize
Page 5 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
ndim gives the number of dimensions, shape gives the size along each dimension, size gives the total
element count, dtype gives the data type of the elements, and itemsize gives the memory (in bytes)
used by each element.
arr = [Link]([[1, 2, 3], [4, 5, 6]])
print([Link])
print([Link])
print([Link])
print([Link])
print([Link])
Output:
2
(2, 3)
6
int64
8
Note: dtype may show int32 instead of int64 on some systems (commonly on Windows) — this is
normal and simply reflects the platform's default integer size.
3. Array Indexing and Slicing
3.1 1-D Indexing and Slicing
A 1-D NumPy array is indexed and sliced exactly like a Python list — position 0 for the first element, -1
for the last, and the familiar [start:stop:step] slice syntax.
Basic 1-D indexing and slicing
Accessing single elements and ranges of a 1-D array.
arr = [Link]([10, 20, 30, 40, 50])
print(arr[0])
print(arr[-1])
print(arr[1:4])
print(arr[::2])
Output:
10
50
[20 30 40]
[10 30 50]
Page 6 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
3.2 2-D Indexing and Slicing
A 2-D array element is accessed using two comma-separated indices — arr[row, column] — unlike a
nested Python list, which needs arr[row][column].
Accessing rows, columns, and sub-matrices
Combining row and column positions (or full-slice ":") accesses individual elements, whole rows, whole
columns, or a rectangular sub-matrix.
arr = [Link]([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
print(arr[1, 2]) # row 1, column 2
print(arr[0]) # entire first row
print(arr[:, 1]) # entire second column
print(arr[0:2, 1:3]) # sub-matrix
Output:
6
[1 2 3]
[2 5 8]
[[2 3]
[5 6]]
3.3 Boolean Indexing (Masking)
Applying a comparison directly to an array produces a boolean mask (an array of True/False values).
Using that mask inside [ ] returns only the elements where the condition is True — this is the backbone
of data filtering in analysis.
Filtering an array with a condition
A condition applied to an array creates a mask; the mask can then be used to filter — or the condition
can be written directly inside the brackets.
arr = [Link]([10, 15, 20, 25, 30])
mask = arr > 18
print(mask)
print(arr[mask])
print(arr[arr % 2 == 0]) # direct filtering: even numbers only
Output:
[False False True True True]
[20 25 30]
[10 20 30]
Page 7 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
3.4 Fancy Indexing
Passing a list (or array) of index positions directly inside [ ] retrieves exactly those elements, in the order
specified — useful for selecting arbitrary, non-contiguous rows or columns.
Selecting specific positions at once
A list of index positions selects exactly those elements from the array.
arr = [Link]([10, 20, 30, 40, 50])
print(arr[[0, 2, 4]])
Output:
[10 30 50]
4. Important Array Functions
reshape()
Changes the shape (dimensions) of an array without changing its data — the total number of elements
must stay the same.
arr = [Link](1, 7)
print(arr)
reshaped = [Link](2, 3)
print(reshaped)
Output:
[1 2 3 4 5 6]
[[1 2 3]
[4 5 6]]
flatten() and ravel()
Both convert a multi-dimensional array back into a single 1-D array. flatten() always returns an
independent copy; ravel() returns a view where possible, which is faster but can affect the original array
if modified.
arr = [Link]([[1, 2], [3, 4]])
print([Link]())
Output:
[1 2 3 4]
Page 8 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
concatenate(), vstack(), hstack()
concatenate() joins arrays along a given axis; vstack() stacks arrays row-wise (vertically); hstack() stacks
arrays column-wise (horizontally).
a = [Link]([1, 2, 3])
b = [Link]([4, 5, 6])
print([Link]([a, b]))
print([Link]([a, b]))
print([Link]([a, b]))
Output:
[1 2 3 4 5 6]
[[1 2 3]
[4 5 6]]
[1 2 3 4 5 6]
sort()
[Link]() returns a new sorted copy of the array; for a 2-D array, an axis can be specified to sort along
rows or columns.
arr = [Link]([40, 10, 30, 20])
print([Link](arr))
Output:
[10 20 30 40]
unique()
Returns the sorted, unique elements of an array, removing duplicates — handy for finding the distinct
categories in a dataset column.
arr = [Link]([1, 2, 2, 3, 3, 3, 4])
print([Link](arr))
Output:
[1 2 3 4]
where()
Returns the indices where a condition is true; when given two extra arguments, it acts like a vectorized
if/else, replacing values based on the condition.
arr = [Link]([10, 15, 20, 25, 30])
print([Link](arr > 18))
print([Link](arr > 18, 'High', 'Low'))
Page 9 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
Output:
(array([2, 3, 4]),)
['Low' 'Low' 'High' 'High' 'High']
Arithmetic operations and broadcasting
Arithmetic operators (+, -, *, /) work element-wise on arrays. When array shapes differ, NumPy
automatically "broadcasts" the smaller array across the larger one wherever their shapes are
compatible.
a = [Link]([1, 2, 3])
b = [Link]([10, 20, 30])
print(a + b)
print(a * 2) # broadcasting a scalar
matrix = [Link]([[1, 2, 3], [4, 5, 6]])
print(matrix + [Link]([100, 200, 300])) # broadcasting a row
Output:
[11 22 33]
[2 4 6]
[[101 202 303]
[104 205 306]]
copy() vs view()
A slice of a NumPy array is a view by default — it shares the same underlying memory as the original, so
changing the slice also changes the original array. Use .copy() to create a fully independent array
instead.
arr = [Link]([1, 2, 3, 4])
view = arr[0:2]
view[0] = 99
print(arr) # original array is also changed!
copy_arr = [Link]()
copy_arr[0] = -1
print(arr) # original is unaffected this time
Output:
[99 2 3 4]
[99 2 3 4]
Note: This view-sharing behaviour is a common source of bugs for beginners — always use .copy() when
an independent array is needed.
Page 10 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
5. Statistical & Aggregate Functions
These functions are at the heart of exploratory data analysis — summarising an entire dataset (or
specific rows/columns of it) into a handful of meaningful numbers.
sum(), mean(), median()
sum() adds all the values, mean() gives the average, and median() gives the middle value once the data
is sorted.
data = [Link]([2, 4, 4, 4, 5, 5, 7, 9])
print([Link](data))
print([Link](data))
print([Link](data))
Output:
40
5.0
4.5
std() and var()
std() (standard deviation) and var() (variance) measure how spread out the data is around its mean — a
bigger value means the data is more spread out.
data = [Link]([2, 4, 4, 4, 5, 5, 7, 9])
print([Link](data))
print([Link](data))
Output:
2.0
4.0
min(), max(), argmin(), argmax()
min() and max() return the smallest/largest values; argmin() and argmax() return the index position
where that value occurs.
data = [Link]([2, 4, 4, 4, 5, 5, 7, 9])
print([Link](data))
print([Link](data))
print([Link](data))
print([Link](data))
Page 11 of 12
NumPy for Data Analysts — Self Study Notes Sachin Tripathi
Output:
2
9
0
7
The axis parameter — row-wise vs column-wise
For a 2-D array, aggregate functions can be applied along a specific axis: axis=0 aggregates down each
column, axis=1 aggregates across each row. Without an axis, the function aggregates over the entire
array.
marks = [Link]([[80, 90, 70], [60, 85, 95]])
print([Link]()) # total of all elements
print([Link](axis=0)) # column-wise sum
print([Link](axis=1)) # row-wise sum
Output:
480
[140 175 165]
[240 240]
6. Quick Revision — NumPy Array vs Python List
A short comparison to remember why NumPy arrays are preferred over plain Python lists for data
analysis.
Feature Python List NumPy Array
Data type Can hold mixed types All elements must share one type
Speed Slower (general-purpose) Much faster (optimized in C)
Memory usage Higher Lower — compact, fixed-type storage
Arithmetic (+) Concatenates lists together Element-wise, vectorized by default
Broadcasting Not supported Fully supported
Built-in statistics Not built-in Rich built-in functions (mean, std, ...)
Dimensions 1-D; nested lists for more True multi-dimensional support
2-D access syntax list[i][j] array[i, j]
— End of Notes —
Compiled by Sachin Tripathi | Python Trainer
Page 12 of 12