NumPy stands for Numerical Python . It is a core Python package designed for high-performance data analysis and scientific computing. It introduces a powerful multidimensional array object called ndarray , along with an extensive collection of functions and tools to operate on these arrays efficiently.
Technical Profile: NumPy Library Environment
NumPy can be installed in the system environment using the Python package installer ( pip ) via the command line interface:
pip install NumPy
An array is a data type used to store multiple values of the same type using a single identifier (variable name). It represents an ordered collection of data elements where each element can be referenced by its unique index (position).
For example, consider an array containing 5 numbers:
[ 10, 9, 99, 71, 90 ]
| Element Value | 10 | 9 | 99 | 71 | 90 |
|---|---|---|---|---|---|
| Index (Positive) | [0] | [1] | [2] | [3] | [4] |
Memory Allocation Mechanics:
While Python has a built-in list structure, it is not optimized for vector mathematics or large-scale numerical processing. NumPy's ndarray provides a highly efficient alternative.
| Feature | Python List | NumPy Array (ndarray) |
|---|---|---|
| Data Homogeneity |
Can store elements of different data types. Example:
[1, 3.4, 'hello', 'a@']
|
All elements must be of the same data type. Example:
[1.2, 5.4, 2.7]
(all floats)
|
| Memory Storage | Elements are not stored contiguously in memory; stores pointers to objects. | Elements are stored in contiguous memory locations, enabling fast cache access. |
| Element-wise Operations | Does not support element-wise operations directly (e.g., multiplying a list by 3 replicates the list). |
Supports direct element-wise operations (e.g.,
A1 / 3
divides each element by 3).
|
| Memory Efficiency | Consumes more space because it must store type information and pointers for every individual element. | Highly memory-efficient; stores type information once for the entire array. |
| Library Origin | Part of core Python. | Part of the external NumPy library. |
To create and use NumPy arrays, the NumPy library must first be imported. By convention, it is imported under the alias np :
>>> import numpy as np
The np.array() function converts a Python list into a NumPy array:
>>> array1 = np.array([10, 20, 30])
>>> array1
array([10, 20, 30])
An array with a single row of elements is a 1-D array. If a list contains mixed data types, NumPy automatically promotes (coerces) all elements to a common compatible data type (e.g., integers and floats are promoted to strings if a string is present):
>>> array2 = np.array([5, -7.4, 'a', 7.2])
>>> array2
array(['5', '-7.4', 'a', '7.2'], dtype='<U32')
Note:
<U32
indicates a Unicode-32 data type.
A two-dimensional (2-D) array is created by passing a nested list (a list of lists) to the np.array() function:
>>> array3 = np.array([[2.4, 3], [4.91, 7], [0, -1]])
>>> array3
array([[ 2.4 , 3. ],
[ 4.91, 7. ],
[ 0. , -1. ]])
Note: The integers 3, 7, 0, and -1 have been automatically promoted to floats to maintain homogeneity.
Common Syntax Mistake:
When passing elements to np.array() , you must enclose them in square brackets to pass them as a single list argument. Forgetting the brackets results in a TypeError.
# INCORRECT:
>>> a = np.array(1, 2, 3, 4)
# CORRECT:
>>> a = np.array([1, 2, 3, 4])
NumPy arrays have several built-in attributes that describe their structural properties:
| Attribute | Description | Example Code & Output |
|---|---|---|
| ndim | Returns the number of dimensions (axes/rank) of the array. |
|
| shape | Returns a tuple of integers indicating the size of the array along each dimension (rows, columns). |
|
| size | Returns the total number of elements in the array (equal to the product of the elements of its shape). |
|
| dtype | Returns the data type of the elements stored in the array. |
|
| itemsize | Returns the size in bytes of each individual element in the array. |
|
>>> array4 = np.array([[1, 2], [3, 4]], dtype=float)
>>> array4
array([[1., 2.],
[3., 4.]])
>>> array5 = np.zeros((3, 4))
>>> array5
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
>>> array6 = np.ones((3, 2))
>>> array6
array([[1., 1.],
[1., 1.],
[1., 1.]])
>>> np.arange(6)
array([0, 1, 2, 3, 4, 5])
>>> np.arange(-2, 24, 4)
array([-2, 2, 6, 10, 14, 18, 22])
NumPy arrays support precise indexing and slicing operations to access and extract subsets of data.
For 2-D arrays, elements are referenced using two indices:
[row_index, column_index]
. Both indices start at 0.
Consider a 2-D array representing student marks:
>>> marks[0, 2] # Row 0, Column 2 (Ramesh's Science mark)
56
>>> marks[0, 4] # Out of bounds index
IndexError: index 4 is out of bounds for axis 1 with size 3
Slicing extracts a portion of an array using the syntax
[start:end:step]
. The end index is exclusive.
>>> array8 = np.array([-2, 2, 6, 10, 14, 18, 22])
>>> array8[3:5]
array([10, 14])
>>> array8[::-1] # Reversing the array
array([22, 18, 14, 10, 6, 2, -2])
Using a 3x4 array named
array9
:
>>> array9 = np.array([[-7, 0, 10, 20], [-5, 1, 40, 200], [-1, 1, 4, 30]])
# Access all elements in the 3rd column (index 2) across rows 0 to 2
>>> array9[0:3, 2]
array([10, 40, 4])
# Access elements of the 2nd and 3rd rows, from the 1st and 2nd columns
>>> array9[1:3, 0:2]
array([[-5, 1],
[-1, 1]])
# If row/column indices are omitted, all rows/columns are selected
>>> array9[:, 2]
array([10, 40, 4])
NumPy supports fast element-wise arithmetic, matrix operations, transposing, and sorting.
Arithmetic operations on two arrays are performed element-by-element. The arrays must have the exact same shape.
>>> array1 = np.array([[3, 6], [4, 2]])
>>> array2 = np.array([[10, 20], [15, 12]])
# Element-wise Addition
>>> array1 + array2
array([[13, 26],
[19, 14]])
# Element-wise Subtraction
>>> array1 - array2
array([[ -7, -14],
[-11, -10]])
# Element-wise Multiplication
>>> array1 * array2
array([[30, 120],
[60, 24]])
# Matrix Multiplication (Dot Product)
>>> array1 @ array2
array([[120, 132],
[ 70, 104]])
# Element-wise Exponentiation
>>> array1 ** 3
array([[ 27, 216],
[ 64, 8]], dtype=int32)
# Element-wise Division
>>> array2 / array1
array([[3.33333333, 3.33333333],
[3.75 , 6. ]])
# Element-wise Modulo (Remainder)
>>> array2 % array1
array([[1, 2],
[3, 0]], dtype=int32)
Transposing an array swaps its rows and columns. The original array remains unchanged unless reassigned.
>>> array3 = np.array([[10, -7, 0, 20], [-5, 1, 200, 40], [30, 1, -1, 4]])
>>> array3.transpose()
array([[ 10, -5, 30],
[ -7, 1, 1],
[ 0, 200, -1],
[ 20, 40, 4]])
The sort() method sorts array elements in ascending order. For 2-D arrays, sorting can be performed along specific axes:
>>> array4 = np.array([1, 0, 2, -3, 6, 8, 4, 7])
>>> array4.sort()
>>> array4
array([-3, 0, 1, 2, 4, 6, 7, 8])
>>> array4 = np.array([[10, -7, 0, 20], [-5, 1, 200, 40], [30, 1, -1, 4]])
>>> array4.sort() # axis=1 is default
>>> array4
array([[ -7, 0, 10, 20],
[ -5, 1, 40, 200],
[ -1, 1, 4, 30]])
>>> array5 = np.array([[10, -7, 0, 20], [-5, 1, 200, 40], [30, 1, -1, 4]])
>>> array5.sort(axis=0)
>>> array5
array([[ -5, -7, -1, 4],
[ 10, 1, 0, 20],
[ 30, 1, 200, 40]])
These structural operations allow you to combine, reshape, or divide arrays.
Concatenation joins multiple arrays along a specified axis using np.concatenate() . All dimensions except the concatenation axis must match exactly.
>>> array1 = np.array([[10, 20], [-30, 40]])
>>> array2 = np.zeros((2, 3), dtype=array1.dtype)
# Concatenate along columns (axis=1)
>>> np.concatenate((array1, array2), axis=1)
array([[ 10, 20, 0, 0, 0],
[-30, 40, 0, 0, 0]])
# Attempting to concatenate along rows (axis=0) when column dimensions mismatch:
>>> np.concatenate((array1, array2), axis=0)
ValueError: all the input array dimensions except for the concatenation axis must match exactly
The reshape() function changes the dimensions of an array without changing its data. The total number of elements must remain constant.
>>> array3 = np.arange(10, 22) # 12 elements
>>> array3.reshape(3, 4)
array([[10, 11, 12, 13],
[14, 15, 16, 17],
[18, 19, 20, 21]])
>>> array3.reshape(2, 6)
array([[10, 11, 12, 13, 14, 15],
[16, 17, 18, 19, 20, 21]])
The np.split() function divides an array into multiple sub-arrays along a specified axis. You can split by specifying split indices or an integer for equal divisions.
>>> array4 = np.array([[10, -7, 0, 20], [-5, 1, 200, 40], [30, 1, -1, 4], [1, 2, 0, 4], [0, 1, 0, 2]])
# Split row-wise (axis=0) at row indices 1 and 3
>>> first, second, third = np.split(array4, [1, 3])
>>> first
array([[10, -7, 0, 20]])
>>> second
array([[-5, 1, 200, 40],
[30, 1, -1, 4]])
>>> third
array([[1, 2, 0, 4],
[0, 1, 0, 2]])
# Split column-wise (axis=1) into 2 equal parts
>>> firsthalf, secondhalf = np.split(array4, 2, axis=1)
>>> firsthalf
array([[10, -7],
[-5, 1],
[30, 1],
[ 1, 2],
[ 0, 1]])
NumPy provides built-in statistical functions to compute descriptive metrics across an entire array or along specific axes.
Let's use these two sample arrays:
>>> arrayA = np.array([1, 0, 2, -3, 6, 8, 4, 7])
>>> arrayB = np.array([[3, 6], [4, 2]])
>>> arrayA.max()
8
>>> arrayB.max(axis=1) # Row-wise maximums
array([6, 4])
>>> arrayB.max(axis=0) # Column-wise maximums
array([4, 6])
>>> arrayA.min()
-3
>>> arrayB.min(axis=0)
array([3, 2])
>>> arrayA.sum()
25
>>> arrayB.sum(axis=1)
array([9, 6])
>>> arrayA.mean()
3.125
>>> arrayB.mean(axis=0)
array([3.5, 4. ])
>>> arrayA.std()
3.550968177835448
>>> arrayB.std(axis=0)
array([0.5, 2. ])
NumPy provides robust functions to read data from external \text files (like CSVs) and write arrays back to disk.
The np.loadtxt() function is used to load homogeneous data from \text files. It requires each row to have the same number of values.
Suppose we have a file named
data.txt
:
RollNo, Marks1, Marks2, Marks3
1, 36, 18, 57
2, 22, 23, 45
3, 43, 51, 37
4, 41, 40, 60
5, 13, 18, 37
We can load this file into a NumPy array using:
>>> studentdata = np.loadtxt('C:/NCERT/data.txt', skiprows=1, delimiter=',', dtype=int)
>>> studentdata
array([[ 1, 36, 18, 57],
[ 2, 22, 23, 45],
[ 3, 43, 51, 37],
[ 4, 41, 40, 60],
[ 5, 13, 18, 27]])
>>> rollno, mks1, mks2, mks3 = np.loadtxt('C:/NCERT/data.txt', skiprows=1, delimiter=',', unpack=True, dtype=int)
The np.genfromtxt() function is more robust than loadtxt() because it can handle missing values and non-numeric data, converting them to nan (Not a Number).
Suppose we have a file named
dataMissing.txt
:
RollNo, Marks1, Marks2, Marks3
1, 36, 18, 57
2, ab, 23, 45
3, 43, 51,
4, 41, 40, 60
5, 13, 18, 27
Loading this file with default settings:
>>> dataarray = np.genfromtxt('C:/NCERT/dataMissing.txt', skip_header=1, delimiter=',')
>>> dataarray
array([[ 1., 36., 18., 57.],
[ 2., nan, 23., 45.],
[ 3., 43., 51., nan],
[ 4., 41., 40., 60.],
[ 5., 13., 18., 27.]])
You can replace missing or non-numeric values with a specific placeholder value using the filling_values parameter:
>>> dataarray = np.genfromtxt('C:/NCERT/dataMissing.txt', skip_header=1, delimiter=',', filling_values=-999, dtype=int)
>>> dataarray
array([[ 1, 36, 18, 57],
[ 2, -999, 23, 45],
[ 3, 43, 51, -999],
[ 4, 41, 40, 60],
[ 5, 13, 18, 27]])
The np.savetxt() function writes a NumPy array to a \text file on disk.
>>> np.savetxt('C:/NCERT/testout.txt', studentdata, delimiter=',', fmt='%i')
| Computing Method | Exact Syntactic Execution Signature | Supported Parameters & Arguments | Algorithmic Purpose & Output Representation |
|---|---|---|---|
| loadtxt |
numpy.loadtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, converters=None, skiprows=0, usecols=None, unpack=False, ndmin=0, encoding='bytes', max_rows=None)
|
fname
,
dtype
,
delimiter
,
skiprows
,
unpack
|
Loads homogeneous data from a \text file into a NumPy array. Fast but fails on missing values. |
| genfromtxt |
numpy.genfromtxt(fname, dtype=<class 'float'>, comments='#', delimiter=None, skip_header=0, skip_footer=0, converters=None, missing_values=None, filling_values=None, usecols=None, names=None, unpack=None, usemask=False)
|
fname
,
dtype
,
delimiter
,
skip_header
,
filling_values
,
unpack
|
Loads data from a \text file, automatically handling missing or invalid values by converting them to
nan
or a specified placeholder.
|
| savetxt |
numpy.savetxt(fname, X, fmt='%.18e', delimiter=' ', newline='
', header='', footer='', comments='# ', encoding=None)
|
fname
,
X
,
fmt
,
delimiter
|
Saves a NumPy array to a \text file using a specified delimiter and format. |
The Iris flower dataset is a classic multivariate dataset introduced by the British statistician and biologist Ronald Fisher in 1936. It consists of 50 samples from each of three species of Iris (Iris setosa, Iris virginica, and Iris versicolor). Four features are measured from each sample: the length and the width of the sepals and petals, in centimeters.
Socio-Technical Analysis & Core Systemic Impact: This dataset serves as a foundational benchmark for pattern recognition and classification algorithms. In modern data pipelines, handling such multi-class biological data requires robust preprocessing protocols, including dropping non-numeric categorical columns (like the species name string) to perform matrix operations, splitting arrays cleanly by class indices, and computing descriptive statistics (mean, standard deviation, variance) to establish classification boundaries without algorithmic bias.
>>> import numpy as np
# 1. Load the data from Iris.txt (ignoring the header and string column)
>>> iris = np.genfromtxt('C:/NCERT/Iris.txt', skip_header=1, delimiter=',', dtype=float)
# 2. Drop column index 4 (the species name string column) to keep only numeric data
>>> iris = iris[0:30, [0, 1, 2, 3, 5]]
# 3. Display shape, dimensions, and size
>>> iris.shape
(30, 5)
>>> iris.ndim
2
>>> iris.size
150
# 4. Split the dataset into three arrays (10 rows each for the three species)
>>> iris1, iris2, iris3 = np.split(iris, [10, 20], axis=0)
# 5. Find column-wise statistics for the entire dataset
>>> iris_max = iris.max(axis=0)
>>> iris_min = iris.min(axis=0)
>>> iris_avg = iris.mean(axis=0).round(2)
>>> iris_std = iris.std(axis=0).round(2)
>>> iris_avg
array([5.68, 3.03, 3.61, 1.22, 2. ])
# 6. Compare species statistics (e.g., check if Iris setosa's min sepal length is greater than the dataset's overall min)
>>> iris1_min = iris1.min(axis=0)
>>> iris1_min[0] > iris_min[0]
False
# 7. Save the computed average values to disk
>>> np.savetxt('C:/NCERT/IrisMeanValues.txt', iris_avg, delimiter=',')