This webpage is a static view of an interactive Jupyter Notebook tutorial. To get the full interactive experience where you can run Python code, modify examples and complete exercises, click the "Open in Colab" button. This will access the Google Colab notebook from a GitHub repository github.com/dchappell2/Computational-Physics and open it in Google Colab. You will need a Google account if you want to open it in Colab.
Note: You can download a pdf of the lecture slides for this chapter here: Chapter 7 slides
Goals
Similarities:
x[0], x[1:5], etc.Differences:
Bottom Line: Use NumPy arrays instead of Python Lists when you need to perform mathematical calculations, need multidimensional support or want access to NumPy merthods and functionality.
NumPy arrays can be used to store any sequence of numbers. Here are some examples of the many ways they might be used:
.array() method to create a NumPy array from a listnp. The import command only needs to be run once per Jypyter notebook..array() method and assign it to a variable:import numpy as np # import the NumPy library and assign nickname "np"
my_array = np.array([10, 20, 30, 40, 50]) # create a NumPy array from a Python List
print("my_array has data type = ",type(my_array))
print("first element of my_array (index = 0) is ",my_array[0])
numpy.ndarray, which stands for a N-dimensional array (NumPy arrays can have any number of dimensions)..copy() to copy NumPy arrays.copy() method:##### Create an Alias
A = np.array([1, 1, 1, 1])
B = A # B is an alias of A
B[-1] = 2 # modifying B affects A
print()
print("B is alias of A:")
print("A = ",A) # A will show changes applied to B
print("B = ",B)
##### Deep Copy Example
A = np.array([1, 1, 1, 1])
B = A.copy() # B and A are independent arrays (a deep copy)
B[-1] = 2 # modifying B does not affect A
print()
print("Deep copy:")
print("A = ",A) # A will not show changes applied to B
print("B = ",B)
# display the first n elements of my_array
my_array = np.array([10, 20, 30, 40, 50])
n = 3
print("first",n,"elements of my_array are",my_array[:n])
# reassign the first element of my_array
my_array[0] = 100
print("my_array is now",my_array)
Given the following list, do the following:
xx and name it yy to 0x and y, labeling the arrays accordingly.my_list = [3,6,9,12]
# Enter your code here
A = np.array([3, 6, 9, 12]) # define a NumPy array from a list
A2 = A**2 # square each element
print("square of A = ",A2) # display the result
A2 array contains the square of each element of A.##### The following two code snippets perform the same operation:
# define a NumPy array from a list
A = np.array([1, 2, 3, 4])
##### vectorized method: square each term in A with single command. FASTER
A2 = A**2
print("method 1: A^2 = ",A2)
##### Python loop: each element squared "by hand". SLOWER
for i in range(len(A)):
A[i] = A[i]**2
print("method 2: A^2 = ",A)
---
If x and y are two equal-length NumPy arrays, we can calculate the element-wise product by simply multiplying the arrays:
x = np.array([1,2,4,8]) # NumPy array (length 4)
y = np.array([3,0,1,1]) # NumPy array (length 4)
z = x*y # element-wise product of x and y
print("x*y = ",z) # result is also length 4
z, and so on.x = np.array([1,2,4,8]) # NumPy array (length 4)
a = 10. # variable containing a floating-point number
z = a*x # multiply each element of x by a
print("x*y = ",z) # result is also length 4
Note: Multiplying two arrays that have different lengths will produce an error:
```
x = np.array([1, 2, 0, 2]) # array containing 4 elements
y = np.array([1, 3]) # array containing 2 elements
z = xy # attempting to multiply xy gives an error!!!
```
Without running the following code, try to predict what the print statement will display. Enter your answer in a Text Cell below. If you want, you can copy and paste the code in a Code Cell to see if your calculations are correct:
```
x = np.array([1, 2, 1, 2])
y = np.array([1, 0, 2, 0])
a1 = 2
a2 = 4
z = a1*x**2 + a2xy
print("The array z = ",z)
```
Enter your response here
The following list of mathematical NumPy functions were given in Chapter 3. We repeat the list here because they are vectorized and operation on NumPy arrays in additon to scalar numbers.
x = [.1, .2, .3, .4, .5] # define a NumPy array for x
# constants
np.pi # pi
np.e # e
np.inf # infinity
np.nan # not a number
# logarithmic and exponential functions
np.sqrt(x) # square root(x)
np.exp(x) # e^x
np.log(x) # ln(x)
np.log10(x) # log base 10(x)
np.log2(x) # log base 2(x)
# trigonometric functions
np.sin(x) # sin(x)
np.cos(x) # cos(x)
np.tan(x) # tan(x)
# degree-radian conversions
np.deg2rad(x) # converts degrees to radians
np.rad2deg(x) # converts radians to degrees
# inverse trigonometric functions
np.asin(x) # np.arcsin(x) also works for the arcsin() of a value
np.acos(x) # np.arccos(x) also works
np.atan(x) # np.arctan(x) also works
np.atan2(y,x) # passing the x and y vector components lets the atan2()
# function return an angle in the correct quadrant
# hyperbolic functions
np.sinh(x) # hyperbolic sin
np.cosh(x) # hyperbolic cos
np.tanh(x) # hyperbolic tan
sin() of each angle using a single statement:theta_deg = np.array([0, 10, 20, 30, 40, 50]) # angles in degrees
theta_rad = np.deg2rad(theta_deg) # convert the anges to radians
y_val = np.sin(theta_rad) # take the sine of each angle
for th,y in zip(theta_deg,y_val): # print results
print(f"sin({th:2.0f}) = {y:6.4f}")
Vector components.
vx and vy that store the x and y components of 5 vectors.vx = np.array([ 5.1, 4.0, 2.9, 0.1, 3.2]) # x measurements (meters)
vy = np.array([-4.5, 1.6, -3.7, 4.2, 4.3]) # y measurements (meters)
# Enter your code here
NumPy arrays have both methods and attributes defined:
A = np.array([1,9,2,8,3,7,4,6,5])
##### Attributes do not take parentheses
A.size # number of elements
A.dtype # data type of the array
##### Methods require parentheses
A.sum() # sum of the elements
A.prod() # product of the elements
A.mean() # mean of the elements
A.std() # standard deviation
A.var() # variance
A.min() # minimum value
A.max() # maximum value
A.cumsum() # cumulative sum (result will have same length as A)
A.cumprod() # cumulative product (result will have same length as A)
A = np.array([1,9,2,8,3,7,4,6,5])
N = A.size
print(f"A contains {N} elements")
A_mean = A.mean()
A_std = A.std()
print(f"The mean and standard deviation of A are {A_mean:.2f} ± {A_std:.2f}")
A_min = A.min()
A_max = A.max()
print(f"The min and max values are {A_min:.2f} and {A_max:.2f}")
The following Code Cell contains a NumPy array with multiple temperature readings of a liquid nitrogen cryostat (in K). Calculate and display the following (with labels):
T = np.array([ 77.1, 77.2, 77.0, 77.8, 77.1, 77.0, 77.9, 77.1]) # x measurements (meters)
# Enter your code here
use .linspace() when you know the total number elements
linspace stands for "linearly spaced"np.linspace(start, stop, N) method creates an array with N elements equally spaced from start to stop, inclusive (i.e. the stop value will be the last element of the array).my_array = np.linspace(100,1000,10)
print("my_array is",my_array)
np.arange()arange stands for "array range". It's not a misspelling of "arrange" as in to "arrange flowers".np.arange(start, stop, interval) method creates an array with elements equally spaced from start to stop exclusive (i.e. the stop value will not be in the array) with spacing = interval.my_array = np.arange(0,5.5,0.5)
print("my_array is",my_array)
Notice that we had to set the stop value to 5.5 for the 5.0 value to be included in the list. In general the the stop value must be set to the desired max value + interval value, i.e. $5.0+0.5=5.5$ in this example.
A common application of np.linspace() and np.arange() is to create an array of evenly spaced time or space values.
In this example, we calculate the distance a rock has fallen every 0.5 seconds up to a total of 3 seconds. The distance fallen is given by $d=\frac{1}{2}g t^2$, where $g=9.8$ m/s$^2$.
Solution
np.arange() method to create an array of times equally space by 0.5 seconds. We call this array timesstop value in np.arange(start,stop,step) to 3.5 (instead of 3.0) since np.arange() goes up to but does not include the stop valueg to store the acceleration of gravitytimes array and store these values in a new array called dist.times and dist arrays to display our resultstimes = np.arange(0,3.5,0.5) # create equally spaced times every 0.5 seconds
g = 9.8 # acceleration of gravity
dist = 0.5 * g * times**2 # calculate distance fallen for every time in times array
for t,d in zip(times,dist): # loop over the time and distance arrays to print them
print(f"t = {t:3.1f} s d = {d:5.2f} m")
We see that at time $t=0$, the rock hasn't moved, which gives us some confidence that our code is working at least for this simple case. At time $t=3$ s, the rock has fallen 44.1 meters.
The international space station orbits the Earth approximately 400 km above the Earth's surface. Calculate the acceleration of gravity (g) every 100 km from the sea level up to the space station.
np.arange() to create an array to store the altitude $h$ values from 0, 100... 400 km.# Enter your code here
np.zeros() (see below)np.zeros(N) and np.ones(N) create an array of length N filled with zeros or ones respectively.np.ones(N) by that number.A = np.zeros(5) # create an NumPy array of length 5 filled with 0's
print("A = ",A)
B = np.ones(5) # create an NumPy array of length 5 filled with 1's
print("B = ",B)
C = 9*np.ones(5) # create an NumPy array of length 5 filled with 9's
print("C = ",C)
Let's create a sequence of numbers where each element equals the square of the previous element. This is equivalent to repeatedly pressing the ^2 button on your calculator.
np.zeros() before starting our for loop to do the calculationN = 10 # number of elements in our sequence (i.e. array)
y0 = 2 # initial number
y = np.zeros(N) # preallocate array to hold the sequence
y[0] = y0 # set first number in the sequence
for n in range(1,N): # calculate next element in series based on previous element
y[n] = y[n-1]**2
for n in range(N): # print result
print(f"{y[n]:.10g}")
Back in Chapter 5, you wrote some code to produce the Fibonacci sequence using lists. In this Skill Check, you will rewrite your code using a NumPy array.
append() command, you'll need to preallocate an array to store the sequence.[0,1]# Enter your code here
``rng = np.random.default_rng()``
rng object is created, we can use it to produce a variety of random arraysimport numpy as np
rng = np.random.default_rng() # create random number Generator
N = 5 # size of random array
# Create array of random integers between 0 <= z < 10
z = rng.integers(0, 10, size=N)
print("random integers: ",z)
print()
# Create array of random integers between 0 <= z <= 10 (includes 10 endpoint)
z = rng.integers(0, 10, size=N, endpoint=True)
print("random integers (v2): ",z)
print()
# Create array of random numbers drawn from Gaussian distribution with mean 0 and sdev = 1
z = rng.normal(size=N)
print("Gaussian distribution: ",z)
print()
# Create array of random numbers drawn from a uniform distribution with 1 <= z < 2
z = rng.uniform(1,2, size=N)
print("Uniform distribution: ",z)
print()
# Choose a random sampling from a list or array of items
my_list = ['red', 'green', 'blue']
z = rng.choice(my_list, size=N)
print("Uniform Sampling: ",z)
print()
# Choose 5 random numbers from 0-9, with no duplicates
z = rng.choice(10,size=5,replace=False)
print("No duplicates: ",z)
rng object can be used to produce random number sequences drawn from many more distributions as well. See the documentation or your favorite AI tool for more info.Use the random choice number generator to draw 5 unique random cards from a 52-card card deck and display them.
Run the following code to see how it works. It defines numbers representing the suit and face value of a card, uses the dictionaries to translate them to actual face value and suit, and prints the result.
% and // operators.# Dictionary defining suit
# example: 0 is clubs, 1 is diamonds, etc
suit_lookup = {
0:"♣️",
1:"♦️",
2:"❤️",
3:"♠️"
}
# dictionary defining face value
# example: 0 has face value 2, 1 has face value 3,... 11 is a king, 12 is an Ace
card_lookup = {
0:" 2",
1:" 3",
2:" 4",
3:" 5",
4:" 6",
5:" 7",
6:" 8",
7:" 9",
8:"10",
9:" J",
10:" Q",
11:" K",
12:" A"
}
# suit is a number between 0-3
suit = 2
# face value is a number between 0-12
face_value = 12
my_card = card_lookup[face_value] + suit_lookup[suit]
print("my card is ",my_card)
logical indexing (also called boolean indexing) is one of NumPy’s most powerful features. It lets you select elements from an array using conditions rather than explicit indices.
A[A>50]. This will select only those values > 50# Create an array of squares from 1 to 100
A = np.linspace(1,10,10)**2
print("A = ",A)
# select only the array elements > 50
A_sample = A[A>50]
print()
print("A values > 50", A_sample)
# Create an array of squares from 1 to 10^2
A = np.linspace(1,10,10)**2
print("A = ",A)
# Create an array of cubes from 1 to 10^3
B = np.linspace(1,10,10)**3
print("B = ",B)
mask = A > 50 # list of indices where array A is > 50
print("A values where A > 50", A[mask])
print("B values where A > 50", B[mask])
To combine multiple conditions in the mask, we must use "bit-wise" operators:
& is bit-wise "and"| is bit-wise "or"# select the array elements with values > 10 and < 50
A_sample = A[(A>10) & (A<50)]
print("A values > 10 and < 50: ", A_sample)
A = np.array([1,3,-1,3,9,-2,3,5])
print("A before: ",A)
A[A<0] = 0
print("A after: ",A)
where() to assign elements based on a conditionThe statement np.where(condition, x, y) returns an array choosing elements from x where condition is True and frpm y where condition is False.
A = np.array([1, -2, -3, 4, 5])
result = np.where(A > 0, 1, -1)
print("A = ",A)
print("result = ",result)
The following Code Cell contains an array of x values. Missing data points have been set to 999.
x = np.array([1,2,3,999,5,6,7,999])
# Enter your code here
Flipping a coin
N. Set N to some value, say 10.rng.integers() function described above to produce an array of N random integers. You could use 1 for heads and 2 for tails, or whatever you choose.N, the number of heads and the percent error on a single line.# Enter your code here
Modify your coin flip code as follows:
for loop for the following number of flips: $10$, $10^2$, $10^3$, $10^4$, $10^5$, $10^6$.# Enter your code here
np.array() function converts a list to a NumPy arrayThis tutorial is an adaptation of "Python for Physicists"