---
title: '`numpy` Exercises'
jupyter: python3
---
These exercises test your understanding of the NumPy concepts covered in the introduction notebook.
## Exercise 1: Import and Basic Array Creation
**Task:** Import NumPy with the standard `import` command and create a NumPy array from the list `[2, 4, 6, 8, 10, 12]`. Print the array, its data type, and its shape.
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
import numpy as np
arr = np.array([2, 4, 6, 8, 10, 12])
print("Array:", arr)
print("Data type:", arr.dtype)
print("Shape:", arr.shape)
```
## Exercise 2: Array Indexing and Slicing
**Task:** Using the array you created in Exercise 1:
- Print the first element
- Print the last element
- Print elements from index 2 to 4 (inclusive of 2, exclusive of 5)
- Print every second element
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
print("First element:", arr[0])
print("Last element:", arr[-1])
print("Elements from index 2 to 4:", arr[2:5])
print("Every second element:", arr[::2])
```
## Exercise 3: Element-wise Operations
**Task:** Create a NumPy array `arr = np.array([1, 4, 9, 16, 25])`. Perform the following operations and print the results:
- Multiply each element by 3
- Add 10 to each element
- Calculate the square root of each element
- Apply the sine function to each element
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
arr = np.array([1, 4, 9, 16, 25])
print("Original array:", arr)
print("Multiply by 3:", arr * 3)
print("Add 10:", arr + 10)
print("Square root:", np.sqrt(arr))
print("Sine function:", np.sin(arr))
```
## Exercise 4: Array Operations with Two Arrays
**Task:** Create two NumPy arrays:
- `arr1 = np.array([1, 2, 3, 4, 5])`
- `arr2 = np.array([10, 20, 30, 40, 50])`
Perform element-wise operations and print the results:
- Add the two arrays
- Subtract arr1 from arr2
- Multiply the two arrays
- Divide arr2 by arr1
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
arr1 = np.array([1, 2, 3, 4, 5])
arr2 = np.array([10, 20, 30, 40, 50])
print("arr1:", arr1)
print("arr2:", arr2)
print("Addition:", arr1 + arr2)
print("Subtraction (arr2 - arr1):", arr2 - arr1)
print("Multiplication:", arr1 * arr2)
print("Division (arr2 / arr1):", arr2 / arr1)
```
## Exercise 5: Shape Mismatch Error
**Task:** Create two arrays with different lengths:
- `arr_a = np.array([1, 2, 3, 4])`
- `arr_b = np.array([10, 20])`
Try to add these arrays together. What happens? Write the code and explain the error in a comment.
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
arr_a = np.array([1, 2, 3, 4])
arr_b = np.array([10, 20])
print("arr_a:", arr_a)
print("arr_b:", arr_b)
try:
result = arr_a + arr_b
print("Result:", result)
except ValueError as e:
print("Error occurred:", e)
# This happens because the arrays have different shapes: (4,) and (2,)
# NumPy cannot broadcast these shapes together for element-wise operations
# The arrays must have compatible shapes for element-wise operations
```
## Exercise 6: Reductive Operations
**Task:** Create a NumPy array `data = np.array([12, 8, 15, 3, 7, 20, 11, 9])`. Calculate and print:
- The sum of all elements
- The mean (average) of all elements
- The maximum value
- The minimum value
- The standard deviation
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
data = np.array([12, 8, 15, 3, 7, 20, 11, 9])
print("Data:", data)
print("Sum:", np.sum(data))
print("Mean:", np.mean(data))
print("Maximum:", np.max(data))
print("Minimum:", np.min(data))
print("Standard deviation:", np.std(data))
```
## Exercise 7: Array Manipulation
**Task:** Create a NumPy array `numbers = np.array([5, 2, 8, 1, 9, 3])`. Perform the following operations:
- Sort the array and print the result
- Calculate the cumulative sum and print the result
- Create a new array with duplicates: `with_duplicates = np.array([5, 2, 8, 1, 9, 3, 5, 2, 1])` and find the unique elements
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
numbers = np.array([5, 2, 8, 1, 9, 3])
print("Original numbers:", numbers)
print("Sorted array:", np.sort(numbers))
print("Cumulative sum:", np.cumsum(numbers))
with_duplicates = np.array([5, 2, 8, 1, 9, 3, 5, 2, 1])
print("Array with duplicates:", with_duplicates)
print("Unique elements:", np.unique(with_duplicates))
```
## Exercise 8: List vs NumPy Comparison
**Task:** Compare the flexibility of lists vs NumPy arrays:
1. Create a Python list containing mixed data types: `mixed_list = [1, 'hello', 3.14, True]`
2. Try to create a NumPy array from this list. What happens to the data types?
3. Create a list of numbers: `num_list = [1, 2, 3, 4, 5]`
4. Try to multiply the entire list by 2 using `num_list * 2`. What happens?
5. Create a NumPy array from the same numbers and multiply by 2. Compare the results.
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
# Mixed data types
mixed_list = [1, 'hello', 3.14, True]
print("Mixed list:", mixed_list)
mixed_array = np.array(mixed_list)
print("NumPy array from mixed list:", mixed_array)
print("Array dtype:", mixed_array.dtype)
print("# NumPy converted everything to strings (the most general type)")
# List multiplication vs NumPy
num_list = [1, 2, 3, 4, 5]
print("\nNumeric list:", num_list)
print("List * 2:", num_list * 2)
print("# List multiplication repeats the entire list")
num_array = np.array([1, 2, 3, 4, 5])
print("NumPy array:", num_array)
print("Array * 2:", num_array * 2)
print("# NumPy multiplication is element-wise")
```
## Exercise 9: Performance Comparison
**Task:** Compare the performance of list comprehension vs NumPy operations:
1. Import the `time` module
2. Create a range of 50,000 numbers using numpy `np.arange()`
3. Time how long it takes to square each number using a **list comprehension**, i.e. the syntax `[x**2 for x in myarray]`
4. Time how long it takes to square each number using NumPy operations
5. Calculate and print how many times faster the NumPy operation is
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
import time
num_range = 50000
test_array = np.arange(num_range)
# List comprehension timing
time1 = time.time()
list_squared = [x**2 for x in test_array]
time2 = time.time()
list_time = time2 - time1
# NumPy operation timing
time1 = time.time()
arr_squared = test_array**2
time2 = time.time()
arr_time = time2 - time1
print(f"List comprehension time: {list_time:.6f} seconds")
print(f"NumPy operation time: {arr_time:.6f} seconds")
if arr_time > 0:
print(f"NumPy is {list_time/arr_time:.1f} times faster")
else:
print("NumPy operation was too fast to measure accurately")
```
## Exercise 10: Complex Operations
**Task:** Create a NumPy array representing angles in degrees: `angles_deg = np.array([0, 30, 45, 60, 90, 120, 180])`
1. Convert these angles to radians (hint: multiply by π/180, use `np.pi`)
2. Calculate the sine and cosine of each angle
3. Verify that sin²(x) + cos²(x) = 1 for each angle (use `np.sin()` and `np.cos()`)
4. Print all results
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
angles_deg = np.array([0, 30, 45, 60, 90, 120, 180])
print("Angles in degrees:", angles_deg)
# Convert to radians
angles_rad = angles_deg * np.pi / 180
print("Angles in radians:", angles_rad)
# Calculate sine and cosine
sin_values = np.sin(angles_rad)
cos_values = np.cos(angles_rad)
print("Sine values:", sin_values)
print("Cosine values:", cos_values)
# Verify sin²(x) + cos²(x) = 1
verification = sin_values**2 + cos_values**2
print("sin²(x) + cos²(x):", verification)
print("All close to 1?", np.allclose(verification, 1))
```
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
# Additional verification - showing the identity holds for each angle
for i, angle in enumerate(angles_deg):
identity_value = sin_values[i]**2 + cos_values[i]**2
print(f"{angle}°: sin²({angle}) + cos²({angle}) = {identity_value:.10f}")
```
## Challenge Exercise: Temperature Conversion
**Task:** You have temperature readings in Celsius: `celsius_temps = np.array([0, 10, 20, 25, 30, 35, 40])`
1. Convert all temperatures to Fahrenheit using the formula: F = (C × 9/5) + 32
2. Convert all temperatures to Kelvin using the formula: K = C + 273.15
3. Calculate the temperature range (max - min) for each scale
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
celsius_temps = np.array([0, 10, 20, 25, 30, 35, 40])
print("Celsius temperatures:", celsius_temps)
# Convert to Fahrenheit
fahrenheit_temps = (celsius_temps * 9/5) + 32
print("Fahrenheit temperatures:", fahrenheit_temps)
# Convert to Kelvin
kelvin_temps = celsius_temps + 273.15
print("Kelvin temperatures:", kelvin_temps)
# Calculate temperature ranges
celsius_range = np.max(celsius_temps) - np.min(celsius_temps)
fahrenheit_range = np.max(fahrenheit_temps) - np.min(fahrenheit_temps)
kelvin_range = np.max(kelvin_temps) - np.min(kelvin_temps)
print(f"\nTemperature ranges:")
print(f"Celsius: {celsius_range}°C")
print(f"Fahrenheit: {fahrenheit_range}°F")
print(f"Kelvin: {kelvin_range}K")
# Note: The range in Celsius and Kelvin is the same because it's just a shift
# The range in Fahrenheit is larger due to the scaling factor (9/5)
```
## Challenge 2: Kinetic energy
**Task** Given arrays of mass (kg) and velocity (m/s) for several objects:
```python
# copy and paste this code below
masses = np.array([2.0, 1.5, 3.0, 0.5]) # in kilograms
velocities = np.array([10.0, 20.0, 15.0, 5.0]) # in meters per second
```
1. Calculate the kinetic energy $K$ for each object using the formula:
$$K = \dfrac{1}{2}m v^2$$
2. Calculate the total kinetic energy of the system (sum of all objects)
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
import numpy as np
masses = np.array([2.0, 1.5, 3.0, 0.5]) # kg
velocities = np.array([10.0, 20.0, 15.0, 5.0]) # m/s
# 1. Kinetic energy for each object
kinetic_energy = 0.5 * masses * velocities**2
print("Kinetic energy of each object:", kinetic_energy)
# 2. Total kinetic energy of the system
total_ke = np.sum(kinetic_energy)
print("Total kinetic energy:", total_ke)
```
## Challenge 3: Temperature Analysis
**Task:**
Given a NumPy array of daily temperatures for 30 days:
```python
temperatures = np.array([23.5, 24.0, 21.2, 25.6, 22.8, 23.9, 26.1, 27.3, 21.7, 22.5,
24.6, 25.8, 20.9, 22.3, 24.7, 26.0, 27.5, 21.0, 22.9, 24.8,
25.9, 27.6, 20.8, 22.7, 24.5, 26.2, 27.7, 20.5, 22.6, 24.9])
```
Perform the following tasks:
1. Find the top 3 hottest days and their temperatures.
2. Calculate the day-to-day percentage change in temperature.
```{pyodide}
#| caption: "▶ Ctrl/Cmd+Enter | ⇥ Ctrl/Cmd+] | ⇤ Ctrl/Cmd+["
import numpy as np
temperatures = np.array([23.5, 24.0, 21.2, 25.6, 22.8, 23.9, 26.1, 27.3, 21.7, 22.5,
24.6, 25.8, 20.9, 22.3, 24.7, 26.0, 27.5, 21.0, 22.9, 24.8,
25.9, 27.6, 20.8, 22.7, 24.5, 26.2, 27.7, 20.5, 22.6, 24.9])
# 1. Top 3 hottest days
top3_indices = np.argsort(temperatures)[-3:][::-1]
top3_temps = temperatures[top3_indices]
print("Top 3 hottest days (indices and temperatures):", list(zip(top3_indices, top3_temps)))
# 2. Day-to-day percentage change
pct_change = (temperatures[1:] - temperatures[:-1]) / temperatures[:-1] * 100
print("Day-to-day percentage change:", pct_change)
```