Unit III · Basics of Python Programming for Pharmaceutical Sciences (BP101T) · As per PCI B.Pharmacy Syllabus, NEP 2020
Once pharmaceutical data grows beyond a handful of values, plain Python lists start to feel slow and clumsy for numerical work. NumPy, short for Numerical Python, solves this by giving you a fast, purpose-built array structure and a full set of mathematical operations that run on entire datasets at once. This post introduces the NumPy array, explains why it outperforms a list, and walks through pharmacy-relevant calculations such as scaling drug concentrations and converting patient temperatures.

What Is NumPy and Why Pharmacy Needs It
NumPy is a foundational Python library built for scientific computing and numerical analysis. It provides a rich toolkit for working with arrays, mathematical functions, linear algebra, and statistics. Because of this, NumPy is heavily relied upon in data science, machine learning, and pharmaceutical research — anywhere large sets of numerical data, such as drug concentrations, dosages, or lab readings, need to be processed efficiently.
The NumPy Array (ndarray)
The central object in NumPy is the ndarray (n-dimensional array). It can hold data in one or more dimensions, but every element inside it must share the same data type. This homogeneity, combined with how the data is laid out in memory, is what makes NumPy arrays far faster to process and more memory-efficient than an ordinary Python list. NumPy arrays also support vectorized operations: a single operation can be applied to every element at once, with no explicit loop required.
Key Features of NumPy Arrays
- Homogeneous data — every element must be the same type (all integers, or all floats), which is part of what makes storage and computation so efficient.
- Multidimensional structure — a 1D array is a simple vector of values, a 2D array is a matrix arranged in rows and columns, and a 3D array is a tensor, useful for more complex data.
- Fixed size — once created, an array’s size is locked in and cannot grow or shrink dynamically the way a list can with
append(). - Efficient memory layout — arrays are stored in contiguous blocks of memory, letting the computer access and compute on the data much faster than the scattered memory layout typical of Python lists.
- Vectorized operations — writing
a + 5adds 5 to every element of arrayain a single step, instead of looping through each element one at a time.
Important NumPy Terminology
A handful of terms recur throughout NumPy documentation and exam questions, so it’s worth defining them precisely.
| Term | Meaning |
|---|---|
| ndarray | The core NumPy array object that stores the data and enables array-based operations. |
| Axis | The direction along which an operation runs. Axis 0 runs down the rows; Axis 1 runs across the columns. |
| Shape | The array’s structure as (rows, columns), e.g. (2, 3) means 2 rows and 3 columns. |
| Size | The total number of elements in the array, regardless of dimensional arrangement. |
| dtype | The data type of every element, such as int32 or float64. |
Creating NumPy Arrays
NumPy offers several ways to build an array, either from existing Python data or generated automatically.
import numpy as np
# From an existing Python list
a = np.array([1, 2, 3])
# An array filled with zeros
b = np.zeros(3)
# An array filled with ones
c = np.ones(3)
# A range of values, similar to Python's range()
d = np.arange(1, 5)
print(a) # [1 2 3]
print(b) # [0. 0. 0.]
print(c) # [1. 1. 1.]
print(d) # [1 2 3 4]
zeros() and ones() build arrays pre-filled with a single value — useful as a starting point before filling in real readings. arange() generates a sequence of values across a given range, and a related function, linspace(), creates an array of evenly spaced values between a starting and ending point — handy for generating, say, ten evenly spaced time points for a concentration-time study.
Indexing, Slicing, and Broadcasting
Indexing and slicing in NumPy work much like they do with Python lists, but extend naturally to multiple dimensions: a[0, 1] retrieves the element at row 0, column 1 of a two-dimensional array. Broadcasting is the NumPy concept that lets arithmetic run between arrays of different shapes without you manually resizing anything — writing a + 5 automatically “broadcasts” the single value 5 across every element of array a.
Arithmetic Operations in NumPy
NumPy supports the full range of arithmetic operations — addition, subtraction, multiplication, and division — along with statistical functions like mean() and sum(). All of these run element by element across the array automatically, a technique known as vectorization, and this is precisely what makes NumPy dramatically faster than writing the equivalent loop in plain Python.
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
print(a + b) # [11 22 33]
print(a - b) # [ 9 18 27]
print(a * b) # [10 40 90]
print(a / b) # [10. 10. 10.]
Worked Example: Increasing Drug Concentration by a Percentage
Suppose a set of drug concentration readings all need to be increased by 10 percent, perhaps to reflect a revised assay standard. Instead of looping through each value, a single vectorized multiplication does the job:
import numpy as np
conc = np.array([100, 200, 300]) # drug concentration data
new_conc = conc * 1.1 # increase every value by 10%
print(new_conc)
# [110. 220. 330.]
Worked Example: Converting Patient Temperature, Celsius to Fahrenheit
An array of patient temperatures recorded in Celsius can be converted to Fahrenheit for the entire batch in one line, using the standard conversion formula F = (C × 9/5) + 32:
import numpy as np
temp_c = np.array([36.5, 37, 38])
temp_f = (temp_c * 9 / 5) + 32
print(temp_f)
# [97.7 98.6 100.4]
More Worked Pharmaceutical Problems
The same vectorized pattern applies to almost any batch numerical task in a pharmacy setting.
import numpy as np
# Increase all drug doses in the array by 50 mg
dose = np.array([100, 200, 300])
print(dose + 50) # [150 250 350]
# Find the ratio between two sets of drug concentration values
c1 = np.array([100, 200, 300])
c2 = np.array([10, 20, 30])
print(c1 / c2) # [10. 10. 10.]
# Double the tablet production quantity for each batch
tablets = np.array([1000, 2000, 3000])
print(tablets * 2) # [2000 4000 6000]
# Average concentration across several readings
conc = np.array([10, 20, 30, 40])
print(conc.mean()) # 25.0
Advantages and Disadvantages of NumPy Arrays
NumPy arrays offer high performance on large numerical datasets, make arithmetic operations trivially easy to apply across a whole array, support broadcasting between differently shaped arrays, and let complex, multi-step calculations often be written as a single expression instead of nested loops and conditions.
That performance comes with trade-offs. An array’s fixed size makes it less flexible than a list when the amount of data keeps changing. NumPy has its own syntax and conventions that take time to learn. And because every element must share one data type, a NumPy array cannot mix strings, numbers, and other types together the way a Python list freely can.
Frequently Asked Questions
Why is a NumPy array faster than a Python list for numerical work?
A NumPy array stores its elements as a contiguous block of memory of a single fixed data type, so the computer’s processor can operate on the whole block efficiently. A Python list, by contrast, stores references to separate Python objects that may be scattered in memory, and every arithmetic operation on a list requires a Python-level loop, which is much slower.
Do I need to install NumPy separately?
Yes. NumPy is a third-party library, not part of the Python standard library, so it must be installed once using pip install numpy before it can be imported with import numpy as np.
What does “broadcasting” actually mean in practice?
Broadcasting lets NumPy apply an operation between arrays (or an array and a single number) even when their shapes don’t match exactly, by conceptually “stretching” the smaller one to fit. The simplest case is an expression like conc * 1.1, where the single number 1.1 is broadcast across every element of the conc array.
Summary
NumPy provides the ndarray, a fast, homogeneous, fixed-size array structure that dramatically outperforms Python lists for numerical work through vectorized operations and contiguous memory storage. Arrays can be created from Python lists or generated with functions like zeros(), ones(), arange(), and linspace(), and support the same indexing and slicing patterns as lists, extended to multiple dimensions. Arithmetic operations — addition, subtraction, multiplication, division, and statistical functions like mean() — apply automatically across an entire array, making tasks like scaling drug concentrations or converting temperature units a one-line operation rather than a manual loop.
References
- Pharmacy Council of India (PCI), B.Pharm Regulations, NEP 2020 — BP101T Syllabus, Basics of Python Programming for Pharmaceutical Sciences
- NumPy Developers, “NumPy Documentation” — official NumPy documentation, numpy.org/doc
- NumPy Developers, “NumPy: the absolute basics for beginners” — official NumPy documentation, numpy.org/doc
- Python Software Foundation, official Python documentation, docs.python.org
