Unit 4: Array Operations using NumPy - Subjective Questions
ECE181 — Introduction To Python • Practice Questions with Detailed Answers
20 questions
Distinguish between NumPy arrays and Python lists. Explain at least four key differences with examples.
NumPy arrays and Python lists are both used to store collections of data, but they differ significantly in performance and functionality.
Key Differences:
-
Homogeneity: NumPy arrays store elements of the same data type, whereas Python lists can hold mixed data types.
- Array:
np.array([1, 2, 3])— all integers - List:
[1, 'a', 3.5]— mixed types
- Array:
-
Memory Efficiency: Arrays use contiguous memory blocks and store data more compactly, while lists store pointers to objects, consuming more memory.
-
Performance: Arrays support vectorized operations executed in optimized C code, making them much faster for numerical computations. Lists require explicit loops.
-
Functionality: Arrays support element-wise operations directly (e.g.,
arr * 2), while lists would repeat/concatenate (list * 2).
Example:
python
import numpy as np
arr = np.array([1, 2, 3])
print(arr 2) # [2 4 6]
lst = [1, 2, 3]
print(lst 2) # [1, 2, 3, 1, 2, 3]
Thus, NumPy arrays are preferred for scientific and numerical computing.
Define a NumPy array. Explain the different ways to create arrays in NumPy with examples.
A NumPy array (ndarray) is a multidimensional, homogeneous data structure that stores elements of the same data type in a contiguous block of memory.
Ways to Create Arrays:
-
From a list/tuple using
np.array():
python
np.array([1, 2, 3]) -
Array of zeros using
np.zeros():
python
np.zeros((2, 3)) # 2x3 array of zeros -
Array of ones using
np.ones():
python
np.ones((3,)) -
Range of values using
np.arange():
python
np.arange(0, 10, 2) # [0 2 4 6 8] -
Evenly spaced values using
np.linspace():
python
np.linspace(0, 1, 5) # 5 values between 0 and 1 -
Identity matrix using
np.eye():
python
np.eye(3) -
Random values using
np.random.rand():
python
np.random.rand(2, 2)
These methods provide flexibility in initializing arrays for different computational needs.
Explain the concept of data types (dtype) in NumPy. Why is specifying a data type important?
In NumPy, every array has an associated data type (dtype) that describes the type of elements it contains. Since arrays are homogeneous, all elements share the same dtype.
Common NumPy Data Types:
int8,int16,int32,int64— integers of various sizesfloat16,float32,float64— floating-point numberscomplex64,complex128— complex numbersbool— boolean valuesstr_/unicode_— string types
Specifying dtype:
python
import numpy as np
arr = np.array([1, 2, 3], dtype='float64')
print(arr.dtype) # float64
Importance of Specifying dtype:
- Memory Control: Choosing a smaller dtype (e.g.,
int8vsint64) reduces memory usage. - Precision: Ensures numerical precision for scientific calculations.
- Performance: Optimized operations depend on consistent types.
- Compatibility: Prevents unexpected type errors in computations.
You can convert types using astype():
python
arr.astype('int32')
Describe the various arithmetic operations that can be performed on NumPy arrays with examples.
NumPy supports element-wise arithmetic operations on arrays, which are applied to each element without explicit loops.
Common Arithmetic Operations:
- Addition:
arr1 + arr2ornp.add() - Subtraction:
arr1 - arr2ornp.subtract() - Multiplication:
arr1 * arr2ornp.multiply() - Division:
arr1 / arr2ornp.divide() - Exponentiation:
arr ** 2ornp.power() - Modulus:
arr1 % arr2ornp.mod()
Example:
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.]
print(a ** 2) # [100 400 900]
These operations are vectorized, meaning they execute efficiently in compiled C code rather than Python loops.
What is broadcasting in NumPy? Explain the broadcasting rules with examples.
Broadcasting is a mechanism in NumPy that allows arithmetic operations between arrays of different shapes by automatically expanding the smaller array to match the larger one, without copying data.
Broadcasting Rules:
- Compare the shapes of the arrays from the trailing (rightmost) dimensions.
- Two dimensions are compatible when they are equal or one of them is 1.
- If dimensions are incompatible and neither is 1, a ValueError is raised.
Example 1 — Scalar Broadcasting:
python
import numpy as np
arr = np.array([1, 2, 3])
print(arr + 10) # [11 12 13]
Example 2 — Array Broadcasting:
python
a = np.array([[1, 2, 3],
[4, 5, 6]]) # shape (2,3)
b = np.array([10, 20, 30]) # shape (3,)
print(a + b)
[[11 22 33]
[14 25 36]]
Here b is broadcast across each row of a.
Benefits: Broadcasting avoids explicit loops, saves memory, and makes code concise and efficient.
Explain the commonly used statistical functions in NumPy with examples.
NumPy provides a rich set of statistical functions to analyze numerical data efficiently.
Common Statistical Functions:
- Mean:
np.mean(arr)— average of elements - Median:
np.median(arr)— middle value - Standard Deviation:
np.std(arr)— measure of spread - Variance:
np.var(arr)— square of standard deviation - Minimum:
np.min(arr) - Maximum:
np.max(arr) - Sum:
np.sum(arr) - Percentile:
np.percentile(arr, 50)
Example:
python
import numpy as np
arr = np.array([10, 20, 30, 40, 50])
print(np.mean(arr)) # 30.0
print(np.median(arr)) # 30.0
print(np.std(arr)) # 14.142...
print(np.var(arr)) # 200.0
print(np.max(arr)) # 50
print(np.min(arr)) # 10
The standard deviation formula is:
These functions can also operate along a specific axis in multidimensional arrays.
Explain array indexing and slicing in NumPy with suitable examples.
Indexing and slicing allow accessing and modifying specific elements or subsets of a NumPy array.
Indexing:
- Access single elements using their position (0-based).
python
import numpy as np
arr = np.array([10, 20, 30, 40])
print(arr[0]) # 10
print(arr[-1]) # 40
Slicing: Uses the syntax arr[start:stop:step].
python
print(arr[1:3]) # [20 30]
print(arr[::2]) # [10 30]
2D Array Indexing:
python
mat = np.array([[1, 2, 3],
[4, 5, 6]])
print(mat[0, 1]) # 2
print(mat[:, 0]) # [1 4] (first column)
print(mat[1, :]) # [4 5 6] (second row)
Boolean Indexing:
python
arr = np.array([1, 2, 3, 4, 5])
print(arr[arr > 3]) # [4 5]
Slicing returns a view (not a copy), so modifying the slice affects the original array.
Compare vectorized operations with traditional loop-based operations in Python. Why are vectorized operations faster?
Vectorized operations apply computations to entire arrays at once, while loop-based operations process one element at a time.
Comparison:
-
Loop-based approach:
python
result = []
for i in range(len(a)):
result.append(a[i] + b[i]) -
Vectorized approach:
python
result = a + b
Why Vectorized Operations Are Faster:
- Compiled C Backend: NumPy operations run in optimized, pre-compiled C code rather than interpreted Python.
- No Python Loop Overhead: Avoids the overhead of Python's interpreter for each iteration.
- Contiguous Memory: Data is stored contiguously, enabling efficient CPU cache usage.
- SIMD Instructions: Modern CPUs process multiple data points in parallel.
Performance Example:
For large arrays (e.g., 1 million elements), vectorized operations can be 10–100x faster than Python loops.
Vectorization also makes code shorter, cleaner, and more readable.
Describe the important attributes of a NumPy array such as shape, ndim, size, and dtype with examples.
NumPy arrays have several useful attributes that describe their structure and properties.
Key Attributes:
ndim: Number of dimensions (axes) of the array.shape: A tuple indicating the size along each dimension.size: Total number of elements in the array.dtype: Data type of the array's elements.itemsize: Size (in bytes) of each element.nbytes: Total bytes consumed by the array.
Example:
python
import numpy as np
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(arr.ndim) # 2
print(arr.shape) # (2, 3)
print(arr.size) # 6
print(arr.dtype) # int64
print(arr.itemsize) # 8
print(arr.nbytes) # 48
These attributes help understand memory usage and structure, which is essential for reshaping and operating on arrays correctly.
Explain reshaping of arrays in NumPy. Discuss the reshape(), flatten(), and ravel() methods.
Reshaping changes the shape (dimensions) of an array without altering its data.
1. reshape() — Changes the array to a new shape (total elements must match).
python
import numpy as np
arr = np.arange(6) # [0 1 2 3 4 5]
reshaped = arr.reshape(2, 3)
[[0 1 2]
[3 4 5]]
Using -1 lets NumPy infer the dimension automatically:
python
arr.reshape(3, -1) # 3x2 array
2. flatten() — Returns a copy of the array collapsed into 1D.
python
reshaped.flatten() # [0 1 2 3 4 5]
3. ravel() — Returns a flattened view (when possible), which is more memory-efficient.
python
reshaped.ravel() # [0 1 2 3 4 5]
Key Difference: flatten() always returns a copy, whereas ravel() returns a view if possible, so modifying it may affect the original array.
What are aggregate functions in NumPy? Explain how the axis parameter affects their behavior in multidimensional arrays.
Aggregate functions compute a single summary value (or values along an axis) from array elements, such as sum, mean, min, and max.
Common Aggregate Functions:
np.sum(),np.mean(),np.min(),np.max(),np.prod()
The axis Parameter:
axis=None(default): Aggregates over the entire array.axis=0: Aggregates along columns (down the rows).axis=1: Aggregates along rows (across columns).
Example:
python
import numpy as np
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(np.sum(arr)) # 21 (entire array)
print(np.sum(arr, axis=0)) # [5 7 9] (column-wise)
print(np.sum(arr, axis=1)) # [6 15] (row-wise)
Visualization:
axis=0→ collapses rows, result has shape(3,)axis=1→ collapses columns, result has shape(2,)
Understanding the axis is crucial for correct data analysis on matrices.
Explain the difference between a copy and a view of a NumPy array. Why is this distinction important?
In NumPy, understanding the difference between a copy and a view is crucial to avoid unintended data modifications.
View:
- A view is a new array object that shares the same data as the original.
- Modifying a view affects the original array.
- Slicing typically produces a view.
python
import numpy as np
arr = np.array([1, 2, 3, 4])
view = arr[1:3]
view[0] = 99
print(arr) # [ 1 99 3 4] — original changed
Copy:
- A copy is a completely independent array with its own data.
- Modifying a copy does not affect the original.
python
copy = arr.copy()
copy[0] = 100
print(arr) # unchanged
Importance:
- Prevents accidental data corruption.
- Helps optimize memory usage (views save memory).
- You can check with
arr.base(a view returns the original array; a copy returnsNone).
Use .copy() explicitly when you need independent data.
Describe how to perform matrix operations like matrix multiplication, transpose, and dot product using NumPy.
NumPy provides efficient functions for linear algebra and matrix operations.
1. Matrix Multiplication:
Use np.dot(), np.matmul(), or the @ operator.
python
import numpy as np
A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])
print(A @ B)
[[19 22]
[43 50]]
2. Transpose:
Use .T or np.transpose() to swap rows and columns.
python
print(A.T)
[[1 3]
[2 4]]
3. Dot Product (vectors):
python
v1 = np.array([1, 2, 3])
v2 = np.array([4, 5, 6])
print(np.dot(v1, v2)) # 32
Note: Element-wise multiplication (A * B) differs from matrix multiplication (A @ B).
Other Useful Functions:
np.linalg.inv()— matrix inversenp.linalg.det()— determinantnp.linalg.eig()— eigenvalues and eigenvectors
Explain boolean masking and fancy indexing in NumPy with examples.
Boolean masking and fancy indexing are powerful techniques to select and manipulate array elements based on conditions or index arrays.
1. Boolean Masking:
Selects elements that satisfy a condition using a boolean array.
python
import numpy as np
arr = np.array([10, 15, 20, 25, 30])
mask = arr > 18
print(mask) # [False False True True True]
print(arr[mask]) # [20 25 30]
You can also modify elements:
python
arr[arr > 18] = 0
print(arr) # [10 15 0 0 0]
2. Fancy Indexing:
Uses arrays of indices to access multiple elements at once.
python
arr = np.array([100, 200, 300, 400, 500])
indices = [0, 2, 4]
print(arr[indices]) # [100 300 500]
2D Fancy Indexing:
python
mat = np.array([[1, 2], [3, 4], [5, 6]])
print(mat[[0, 2]]) # rows 0 and 2
These techniques enable concise, efficient data filtering without explicit loops.
Derive and demonstrate how broadcasting works when adding a 1D array to a 2D array of different shapes. Include shape analysis.
Consider adding a 2D array of shape (3, 3) to a 1D array of shape (3,).
Given Arrays:
python
import numpy as np
A = np.array([[0, 0, 0],
[10, 10, 10],
[20, 20, 20]]) # shape (3, 3)
b = np.array([1, 2, 3]) # shape (3,)
Step 1 — Align Shapes (from right):
A: (3, 3)
b: ( 3) → treated as (1, 3)
Step 2 — Apply Broadcasting Rules:
- Trailing dimension:
3 == 3✓ compatible - Next dimension:
3vs1→ the1is stretched to3✓
Step 3 — Broadcast b to shape (3, 3):
[[1 2 3]
[1 2 3]
[1 2 3]]
Step 4 — Element-wise Addition:
python
print(A + b)
[[ 1 2 3]
[11 12 13]
[21 22 23]]
Conclusion: Broadcasting virtually replicates b across each row of A without physically copying data, saving memory while enabling clean vectorized computation.
Explain in detail the advantages of using NumPy over standard Python data structures for scientific computing. Support your answer with performance and functionality aspects.
NumPy (Numerical Python) is the foundational library for scientific computing in Python, offering major advantages over built-in data structures like lists.
1. Performance Advantages:
- Speed: Operations run in optimized C code, up to 50–100x faster than pure Python loops.
- Memory Efficiency: Contiguous, typed storage uses far less memory than lists of objects.
- Vectorization: Eliminates slow Python-level loops.
2. Functional Advantages:
- Multidimensional Arrays: Native support for n-dimensional data (
ndarray). - Broadcasting: Enables operations between arrays of different shapes.
- Rich Function Library: Includes mathematical, statistical, and linear algebra functions.
- Integration: Serves as the base for libraries like Pandas, SciPy, Scikit-learn, and TensorFlow.
3. Convenience:
- Concise syntax for complex operations.
- Easy reshaping, slicing, and aggregation.
Example — Speed Comparison:
python
import numpy as np
a = np.arange(1000000)
b = a * 2 # instant, vectorized
vs. a Python loop over a million elements, which is drastically slower.
Conclusion: NumPy's speed, memory efficiency, and mathematical capabilities make it indispensable for data science, machine learning, and numerical computing.
Explain the functions used to join and split arrays in NumPy, such as concatenate(), vstack(), hstack(), and split().
NumPy provides functions to combine multiple arrays or divide an array into parts.
Joining Arrays:
-
np.concatenate()— Joins arrays along an existing axis.
python
import numpy as np
a = np.array([1, 2])
b = np.array([3, 4])
print(np.concatenate([a, b])) # [1 2 3 4] -
np.vstack()— Stacks arrays vertically (row-wise).
python
print(np.vstack([a, b]))[[1 2]
[3 4]]
-
np.hstack()— Stacks arrays horizontally (column-wise).
python
print(np.hstack([a, b])) # [1 2 3 4]
Splitting Arrays:
-
np.split()— Divides an array into multiple sub-arrays.
python
arr = np.arange(6)
print(np.split(arr, 3)) # [array([0,1]), array([2,3]), array([4,5])] -
np.hsplit()andnp.vsplit()split along horizontal and vertical axes respectively.
These functions are useful for restructuring datasets before analysis.
Explain universal functions (ufuncs) in NumPy. Give examples of mathematical and trigonometric ufuncs.
Universal functions (ufuncs) are functions in NumPy that operate element-wise on arrays, supporting fast, vectorized computation.
Characteristics of ufuncs:
- Operate element-by-element.
- Support broadcasting.
- Return an array as output.
- Implemented in optimized C code.
1. Mathematical ufuncs:
python
import numpy as np
arr = np.array([1, 4, 9, 16])
print(np.sqrt(arr)) # [1. 2. 3. 4.]
print(np.exp(arr)) # exponential
print(np.log(arr)) # natural log
print(np.abs(-arr)) # absolute value
2. Trigonometric ufuncs:
python
angles = np.array([0, np.pi/2, np.pi])
print(np.sin(angles)) # [0. 1. 0. (approx)]
print(np.cos(angles)) # [1. 0. -1.]
print(np.tan(angles))
3. Rounding ufuncs:
np.round(),np.floor(),np.ceil()
Benefits: ufuncs replace slow Python loops with efficient, readable vectorized code, forming the backbone of NumPy's computational power.
Given an array of exam scores, explain how you would compute descriptive statistics (mean, median, standard deviation, min, max) and interpret the results. Provide code and formulas.
Descriptive statistics summarize the central tendency and spread of a dataset. Consider an array of exam scores.
Sample Data:
python
import numpy as np
scores = np.array([55, 62, 70, 85, 90, 78, 88])
1. Mean (Average):
python
print(np.mean(scores)) # 75.43
Interpretation: The average score is about 75.4.
2. Median (Middle Value):
python
print(np.median(scores)) # 78.0
Interpretation: Half the students scored below 78.
3. Standard Deviation (Spread):
python
print(np.std(scores)) # ~12.4
Interpretation: Scores deviate from the mean by about 12.4 on average.
4. Min and Max:
python
print(np.min(scores)) # 55
print(np.max(scores)) # 90
Interpretation: Lowest score 55, highest 90; range = 35.
Conclusion: These statistics together reveal that scores are moderately spread around a mean of ~75, useful for evaluating class performance.
Explain type casting and type promotion in NumPy operations. What happens when arrays of different data types are combined?
Type casting is converting an array from one data type to another, while type promotion determines the resulting type when arrays of different types interact.
1. Explicit Type Casting using astype():
python
import numpy as np
arr = np.array([1.7, 2.5, 3.9])
int_arr = arr.astype('int32')
print(int_arr) # [1 2 3] (truncated, not rounded)
2. Type Promotion (Implicit Upcasting):
When combining arrays of different types, NumPy promotes to the more general (wider) type to avoid data loss.
python
a = np.array([1, 2, 3]) # int
b = np.array([1.5, 2.5, 3.5]) # float
result = a + b
print(result.dtype) # float64
Here integers are promoted to floats.
Type Promotion Hierarchy (simplified):
Key Points:
- Mixing
intandfloat→ result isfloat. - Mixing
floatandcomplex→ result iscomplex. - Casting
floattointtruncates the decimal part.
Importance: Understanding type promotion prevents precision loss and unexpected results in numerical computations.
Distinguish between NumPy arrays and Python lists. Explain at least four key differences with examples.
NumPy arrays and Python lists are both used to store collections of data, but they differ significantly in performance and functionality.
Key Differences:
-
Homogeneity: NumPy arrays store elements of the same data type, whereas Python lists can hold mixed data types.
- Array:
np.array([1, 2, 3])— all integers - List:
[1, 'a', 3.5]— mixed types
- Array:
-
Memory Efficiency: Arrays use contiguous memory blocks and store data more compactly, while lists store pointers to objects, consuming more memory.
-
Performance: Arrays support vectorized operations executed in optimized C code, making them much faster for numerical computations. Lists require explicit loops.
-
Functionality: Arrays support element-wise operations directly (e.g.,
arr * 2), while lists would repeat/concatenate (list * 2).
Example:
python
import numpy as np
arr = np.array([1, 2, 3])
print(arr 2) # [2 4 6]
lst = [1, 2, 3]
print(lst 2) # [1, 2, 3, 1, 2, 3]
Thus, NumPy arrays are preferred for scientific and numerical computing.
Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →