In [1]:
import numpy as np
The line above tells the computer to make the functions available and nickname the master object np. To call a function from the master object, we use the syntax np.function(). To find out what functions numpy has for you to use, go to their documentation at https://docs.scipy.org/doc/numpy-dev/user/quickstart.html. Learning to use documentation and proper googling is a very important tool for any programmer. We will cover some effective googling techniques and how to find and use documentation later.
The main thing that numpy gives us are arrays. They are more flexible than lists and have better functionality as we will see. To create a new array we have a couple of methods:
#First make a list and then copy it into a new array
list = [1,2,3,4]
array = np.array(list) # This tells the computer to make a copy of list and turn it into an array
#Use one of NumPy's special array types
arrayofZeros = np.zeros((x-dim, y-dim, etc...)) #creates an x by y by etc. array of all zeros
arrayofOnes = np.ones((x-dim, y-dim, etc...)) #creates an x by y by etc. array of all ones
emptyArray = np.empty((x-dim, y-dim, etc...)) #creates an x by y by etc. array of whatever happened to be in memory at the time of instantiation.
rangeArray = np.arange(start, stop, step) # Works just like range() starting at **start** and ending at **stop** return values in step size of **step**
linearspaceArray = np.linspace(start, stop, # of vals) # Creates a linear spaced array between start and stop with a # of vals in the array.
diagonalArray = np.diagflat(#input list, set, array, etc. goes here) #creates a 2-d matrix with the input list, set, array, etc. as the main diagonal.
NumPy arrays act a little differently than lists and other containers. The first major difference between arrays and other containers is that arrays may only contain one type of thing. That is to say, we may no longer be sloppy about placing an int and a string in the same array. Further, NumPy arrays treat operators differently than other containers. Operations are carried out only between arrays of the same size and are computed elementwise. For example, the sum of two 3 by 1 arrays(could be vectors in $\!R^3$) would be the sum of the 1st, 2nd, and 3rd components added individually. Let's solidify these ideas with some examples.
In [2]:
print("Just an Array: \n",np.array([0,1,2,34,5]))
print("An Array of Zeros: \n",np.zeros((2,3)))
print("An Array of Ones: \n",np.ones((2,)))
print("A Clever Way to Build an Array: \n",np.pi*np.ones((4,3)))
print("A Bunch of Random Junk: \n",np.empty((2,2)))
print("A Range of Values: \n",np.arange(0,100, 3))
print("A Linearly-Spaced Range of Values: \n",np.linspace(0,100, 33))
print("A Diagonal Array: \n",np.diagflat(np.linspace(1,10,10)))
In [3]:
#Let's check out some NumPy operations
a = np.array([[1,2],[3,4]])
print("First Array: \n",a)
b = np.array([[4,3],[2,1]])
print("Second Array: \n",b)
print("Sum:\n",a+b)
print("Product:\n",a*b)
print("Power:\n",a**b)
Now that we have seen how NumPy sees operations, let's practice a bit.
Create at least 2 arrays with each different method.
In the next cell are two arrays of measurements, you happen to know that their sum over their product squared is a quantity of interest, calculate this quantity for every pair of elements in the arrays.
np.random.normal(mean, std, (x-dim, y-dim, etc...)) creates an x by y by etc... array of normally distributed random numbers with mean mean, and standard deviation std. Using this function, create an appropriatly sized array of random "noise" to multiply with the data from 2. Compute the interesting quantity with the "noisy" data.
np.mean(#some array here) computes the mean value of all the elements of the array provided. Compute the average difference between your "noisy" interesting result from 3. and your original interesting result from 2. You have just modeled a system with simulated noise!
In [4]:
p = np.array([1,2,3,5,1,2,3,1,2,2,6,3,1,1,5,1,1,3,2,1])
l = 100*np.array([-0.06878584, -0.13865453, -1.61421586, 1.02892411, 0.31529163, -0.06186747, -0.15273951, 1.67466332, -1.88215846, 0.67427142, 1.2747444, -0.0391945, -0.81211282, -0.38412292, -1.01116052, 0.25611357, 0.3126883, 0.8011353, 0.64691918, 0.34564225])
NumPy slicing is only slightly different than list slicing. With NumPy arrays, to access a single element you perform the typical
array = np.array([1,2,3,4])
array[index]
array[0] #Returns 1
When you want to take a range of elements, you use the following syntax
array[start:stop+1]
array[1:3] #Returns [2,3]
Or if you would like to move in steps.
array[start:stop+1:step]
array[0:4:2] #Returns [1,3]
In [5]:
array = np.array([1,2,3,4])
print(array[0])
print(array[1:4])
print(array[0:4:2])
Masking is a special type of slicing which uses boolean values to decide whether to show or hide the values in another array. A mask must be a boolean array of the same size as the original array. To apply a mask to an array, yous use the folllowing syntax:
mask = np.array([True, False])
array = np.array([25, 30])
array[mask] #Returns [25]
Let's check this masking action out
In [6]:
mask = np.array([[1,1,1,1,0,0,1],[1,0,0,0,0,1,0]], dtype=bool)
#^^^This converts the ones and zeros into trues and falses because I'm lazy^^^
array = np.array([[5,7,3,4,5,7,1],np.random.randn(7)])
print(array)
print(mask)
In [7]:
print(array[mask])
Let's say that we have measured some quantity with a computer and generated a really long numpy array, like, really long. It just so happens that we are interested in how many of these numbers are greater than zero. We could try to make a mask with the methods used above, but the people who made masks gave us a tool to do it without ever making a mask.(That's what it does behind the scenes, but we'll just ignore that) I have the data in the next cell, let's check it out.
In [8]:
data = np.random.normal(0,3,10000) #Wow, I made 10,000 measurements, wouldn't mastoridis be proud.
data[data>0].size #This returns only the elements of data that are greater than 0
Out[8]:
This is a powerful tool that you should keep in the back of your head that can often greatly simplify problems.
In [10]:
import matplotlib.pyplot as plt
%matplotlib inline
x = np.linspace(0,2*np.pi,1000)
y = np.sin(x)
plt.subplot(211)
plt.plot(x)
plt.subplot(212)
plt.plot(x,y)
Out[10]:
A list of all the universal functions is included at the end of this notebook.
Create a couple of arrays of various type and size and play with them until you feel comfortable moving on.
You know that a certain quantity can be calculated using the following formula:
f(x)=x^e^sin(x^2)-sin(x*ln(x))
Given that you measured x in the cell below, calculate f(x)
Using the same x as above, write a function to transform on x. Then create a mask that will keep any value of the reuslting array whose value is greater than 2*$\pi^2$
In [16]:
x = np.random.rand(1000)*np.linspace(0,10,1000)
Function | Description |
---|---|
add(a,b), + | Addition |
subtract(a,b), - | Subtraction |
multiply(a,b), * | Multiplication |
divide(a,b), / | Division |
power(a,b), ** | Power |
mod(a,b), % | Modulo/Remainder |
abs(a) | Absolute Value |
sqrt(a) | Square Root |
conj(a) | Complex Conjugate |
exp(a) | Exponential |
log(a) | Natural Log |
log2(a) | Log base 2 |
log10(a) | Log base 10 |
sin(a) | Sine |
cos(a) | Cosine |
tan(a) | Tangent |
minimum(a,b) | Minimum |
maximum(a,b) | Maximum |
isreal(a) | Tests for zero complex component |
iscomplex(a) | Tests for zero real component |
isfinite(a) | Tests for finiteness |
isinf(a) | Tests for infiniteness |
isnan(a) | Tests for Not a Number |
floor(a) | Rounds down to next integer value |
ceil(a) | Rounds up to next integer value |
trunc(a) | Truncate all noninteger bits |
Function | Description |
---|---|
sum(a) | Sums all elements of a |
prod(a) | Takes the product of all elements of a |
min(a) | Finds the minimum value in a |
max(a) | Finds the maximum value in a |
argmin(a) | Returns the index or location of the minimum value in a |
argmax(a) | Returns the index or location of the maximum value in a |
dot(a,b) | Takes the dot product of a and b |
cross(a,b) | Takes the cross product of a and b |
einsum(subs, arrs) | Takes the Einstein sum over subscripts and a list of arrays |
mean(a) | Computes the average value of all the elements in a |
median(a) | Finds the median value in a |
average(a, weights) | Computes the weighted average of a |
std(a) | Computes the standard deviation of a |
var(a) | Computes the variance of a |
unique(a) | Returns the unique elements of a in a sorted manner |
asarray(a, dtype) | Makes a copy of given array converting every element to type dtype |
atleast_1d(a) | Tests that the array is at least one-dimensional |
atleast_2d(a) | "" |
atleast_3d(a) | "" |
append(a,b) | Appends b to the end of a |
save(file, a) | Saves an array to a file |
load(file) | Loads an array saved as a file |
A prime number seive is an algorithm that will find prime numbers. Your challenge is to recreate the Sieve of Eratosthenes. Use all you learned about NumPy and loops and create a function that takes a max value, as in the sieve, and returns a list of primes. Good Luck!
In [ ]: