Lesson · 40 min · Free
NumPy Basics: Arrays & Operations
NumPy Basics: Arrays & Operations body { font-family: sans-serif; line-height: 1.6; margin: 20px; } pre { background-color: #eee; padding: 10px; border-radius: 5px; overflow-x: auto; } code { font-family: "Courier New",
NumPy Basics: Arrays & Operations
Welcome to this module on NumPy, a fundamental library in Python for numerical computing. For students in pharmacy and biotechnology, understanding NumPy is crucial as it underpins many advanced data analysis, statistical modeling, and scientific computing tasks you'll encounter. Whether you're processing high-throughput screening data, analyzing pharmacokinetic profiles, or simulating molecular interactions, NumPy provides the efficient tools to handle large datasets effectively. At its core, NumPy introduces the ndarray (N-dimensional array) object, which is a powerful and efficient container for large datasets. Unlike Python's built-in lists, NumPy arrays are optimized for numerical operations, allowing for significant speed improvements and memory efficiency. This is particularly important when dealing with the large matrices and vectors often found in scientific research.
Creating NumPy Arrays
NumPy arrays can be created in several ways. The most common method is converting a Python list or tuple into an array using the np.array() function. You can create one-dimensional arrays (vectors), two-dimensional arrays (matrices), or even higher-dimensional arrays (tensors). Let's look at some basic array creation examples: import numpy as np # Creating a 1D array (vector) drug_concentrations = np.array([0.1, 0.5, 1.0, 2.5, 5.0]) print("Drug Concentrations (1D array):") print(drug_concentrations) print(f"Shape: {drug_concentrations.shape}") print(f"Data type: {drug_concentrations.dtype}\n") # Creating a 2D array (matrix) - e.g., patient data (dosage, response) patient_data = np.array([[10, 75], [20, 82], [15, 78]]) print("Patient Data (2D array):") print(patient_data) print(f"Shape: {patient_data.shape}") print(f"Number of dimensions: {patient_data.ndim}\n") # Creating arrays with pre-filled values # An array of zeros, useful for initializing data zeros_array = np.zeros((2, 3)) # 2 rows, 3 columns print("Array of Zeros:") print(zeros_array) print(f"Shape: {zeros_array.shape}\n") # An array of ones ones_array = np.ones(4) print("Array of Ones:") print(ones_array) print(f"Shape: {ones_array.shape}\n") # An array with a range of values (similar to Python's range but returns an array) time_points = np.arange(0, 10, 2) # start, stop (exclusive), step print("Time Points (arange):") print(time_points) print(f"Shape: {time_points.shape}\n") # An array with a specified number of evenly spaced values over an interval linear_space = np.linspace(0, 1, 5) # start, stop (inclusive), number of points print("Linear Space (linspace):") print(linear_space) print(f"Shape: {linear_space.shape}\n") Notice the .shape attribute, which returns a tuple indicating the size of the array in each dimension. The .dtype attribute tells you the data type of the elements in the array (e.g., float64 , int32 ). NumPy automatically infers the data type, but you can also explicitly specify it during array creation. One of the most powerful features of NumPy is its ability to perform operations on entire arrays without explicit loops. This concept is called "vectorization" and is crucial for high-performance computing. Instead of iterating through each element, NumPy applies operations to all elements simultaneously, leveraging optimized C/Fortran code underneath.
Basic Array Operations
Let's explore some common operations: # Assuming drug_concentrations and patient_data from previous example import numpy as np drug_concentrations = np.array([0.1, 0.5, 1.0, 2.5, 5.0]) patient_data = np.array([[10, 75], [20, 82], [15, 78]]) # Scalar operations (applying a single value to all elements) # Doubling drug concentrations doubled_concentrations = drug_concentrations * 2 print("Doubled Concentrations:") print(doubled_concentrations) # Adding a baseline response to patient data baseline_response_added = patient_data[:, 1] + 5 # Adding 5 to the response column print("\nPatient Responses with Baseline Added:") print(baseline_response_added) # Element-wise operations (operations between arrays of the same shape) # Let's say we have two sets of experimental readings exp_A = np.array([10, 12, 15]) exp_B = np.array([11, 13, 14]) # Sum of corresponding elements sum_experiments = exp_A + exp_B print("\nSum of Experiments (element-wise):") print(sum_experiments) # Difference diff_experiments = exp_A - exp_B print("\nDifference of Experiments (element-wise):") print(diff_experiments) # Multiplication (element-wise) # If exp_A represents cell counts and exp_B represents viability factors product_experiments = exp_A * exp_B print("\nProduct of Experiments (element-wise):") print(product_experiments) # Mathematical functions (apply to each element) # Square root of concentrations sqrt_concentrations = np.sqrt(drug_concentrations) print("\nSquare Root of Concentrations:") print(sqrt_concentrations) # Logarithm base 10 of concentrations (common in dose-response curves) log10_concentrations = np.log10(drug_concentrations) print("\nLog10 of Concentrations:") print(log10_concentrations) # Aggregation functions (summarize data) print("\nAggregation Functions:") print(f"Mean drug concentration: {np.mean(drug_concentrations)}") print(f"Max patient response: {np.max(patient_data[:, 1])}") print(f"Sum of all patient data values: {np.sum(patient_data)}") # Aggregation along an axis (e.g., mean of each column/row in a matrix) # Mean of each column in patient_data (axis=0 means across rows, so for each column) # patient_data represents [[dosage, response], ...] mean_per_column = np.mean(patient_data, axis=0) print(f"Mean dosage and mean response: {mean_per_column}") # Sum of each row in patient_data (axis=1 means across columns, so for each row) sum_per_row = np.sum(patient_data, axis=1) print(f"Sum per patient (dosage + response): {sum_per_row}") The concept of "axis" is critical in NumPy. For a 2D array, axis=0 refers to operations performed column-wise (i.e., collapsing rows), while axis=1 refers to operations performed row-wise (i.e., collapsing columns). This becomes intuitive with practice and is essential for tasks like calculating means for different experimental groups or summing values across time points.
Key Takeaways
NumPy's ndarray is the core object for efficient numerical data storage and manipulation. NumPy arrays are faster and more memory-efficient than Python lists for numerical operations. Arrays can be created from lists, or using functions like np.zeros() , np.ones() , np.arange() , and np.linspace() . NumPy supports vectorized operations (scalar, element-wise) and universal functions (ufuncs) for applying mathematical functions to entire arrays without explicit loops. Aggregation functions (e.g., np.mean() , np.sum() , np.max() ) can be applied to entire arrays or along specific axes.
Practice Exercise
Imagine you are analyzing data from an experiment measuring the efficacy of three different drug formulations (A, B, C) on reducing a particular biomarker level over a 24-hour period. You have recorded the biomarker levels at 0, 6, 12, and 24 hours for each formulation. Create a 2D NumPy array representing this data, where rows are drug formulations and columns are time points. Then, calculate the average biomarker level for each drug formulation and the overall average biomarker level across all formulations and time points. Finally, determine which drug formulation had the lowest average biomarker level.
Watch the full lesson — free
This topic is part of Python for Data Science, a complete AI-narrated video course. Press play once and watch the entire lecture like a movie.
Start the course free →