#!/usr/bin/env python # coding: utf-8 # In[1]: import numpy as np # In[2]: L = [1,2,3] L # In[3]: for i in L: print(L) # In[4]: B = np.array([1,2,3]) for e in B: print(B) # In[5]: B = B + B B # In[6]: B = B*2 B # In[7]: L = L*2 L # In[8]: L**2 # In[ ]: L2 = [] for i in L: L2.append(i*i) print(L2) # In[ ]: L.append(4) L # In[9]: np.sqrt(B) # In[10]: np.log(B) # In[11]: np.exp(B) # ## A bit about dot product # # 1. First method: $a.b = a^{T} = \sum_{d = 1}^ba_{d}b_{d}$ # 2. Second method: $a.b = |a||b|cos\theta_{ab}$ - not really convenient # In[12]: a = np.array([1,2]) b = np.array([2,1]) # In[13]: dot = 0 # In[14]: for i,j in zip(a,b): dot += i*j dot # In[15]: a*b # ## A matrix is essentially a list of lists # # # In[16]: M = np.array([[1,2], [3,4]]) # In[17]: L = [[1,2], [3,4]] # In[18]: L[0] # In[19]: L[0][0] # In[20]: M[0][0] # In[21]: M[0,0] # In[22]: M2 = np.matrix([[1,2], [3,4]]) #works somewhat similarly to np.array but not exactly same. # In[23]: M2 # In[24]: A = np.array(M2) # converting it into a matrix # In[25]: A # you get the same matrix but as an array # In[26]: A.T # Transposing values with T # ## Summarizing: # A matrix is just a 2-dimensional numpy array and a vector is a 1-dimensional numpy array. Or you can see it this way: A matrix is actually like a 2-dimensional vector (a 2-dimensional math object that contains numbers) and a vector is a 1-dim mathematical object containing numbers).
# A col vector is 3x1 and a row vector is 1x3. All you need to remember is 1-D array, which is a vector and 2 or multiple dimensional arrays that are matrices. # ## Different ways in generating data # In[27]: np.array([1,2,3,4]) #tedious way # In[28]: Z = np.zeros(10) #gives us a vector of 10s using function zeros # In[29]: Z # will give you a vector with length 10 of all zeros # In[30]: Z = np.zeros((10, 10)) # for a matrix of 10x10 # In[31]: Z # In[32]: O = np.ones((10, 10)) # for ones use ones function # In[33]: O # gives you a 10x10 matrix with all numbers # In[34]: RandomNumbers = np.random.random((10,10)) # In[35]: RandomNumbers # in a matrix of size 10x10 # In[36]: GaussianNumbers = np.random.randn((10,10)) # In[37]: # It failed becuase Randn function takes each of the dimensions as individual objects, while all others took tuples. GaussianNumbers = np.random.randn(10,10) # In[38]: GaussianNumbers # will give a gauissian distribution with mean 0 and variance 1 # In[39]: GaussianNumbers.mean() # In[40]: GaussianNumbers.var() # ## Matrix Products or multiplication # 1. Matrix multiplication : Inner dimensions must match! if we have A of size (2,3) and B of size (3,3), we can multiply AB (inner dimension is 3) but we cannot multiply BA where inner dimension is 3 and 2! # 2. The definition of matrix multiplication is as follows: $$C(i,j) = \sum_{k=1}^K A(i,k)B(k,j)$$ # 3. This means $(i,j)^{th}$ entry of C is the sum of the multiplication of all the corresponding element from $i^{th}$ row of A and $j^{th}$ col of B. In other words, $C(ij)$ is the dot product of $i^{th}$ row of A and $j^{th}$ col of B. That is, $C(ij)$ is the dot product of Because of this we use the dot function in numpy and that does what you see as matrix multiplication. # 4. Instinctively (in maths that is) you'd want to do an element by element multiplication, for vectors we can do with a * operation, as you may imagine for a 2D array , the * also does an element-wise multiplication ,meaningwhwn you use an * for multidimensional arrya, both must be exactly the same size. This may mean a bit weird, because in other (programming) languages * means real matrix multiplication. So, to summarize -- asterisk(*) means element by element multiplication while dot function does a matrix multiplication. # 5. One more funny thing in maths equations, there isn't a well defined real symbol to use a element by element multiplication. Sometimes folks use circle with a . insidde or an x. # # ### More matrix operations # In[41]: # matrix inverse A = np.array([[1,2], [3,4]]) # In[42]: A_inverse = np.linalg.inv(A) # In[43]: A_inverse # In[44]: A*A_inverse # In[45]: A.dot(A_inverse) #gives us an identity matrix # In[46]: A_inverse.dot(A) # note this gives us an identity matrix as well # In[47]: # matrix determinant np.linalg.det(A) # In[48]: np.diag(A) # gives us diagonal elements in a vector # In[49]: # Note this: if you pass a 2D array to diag, you get a 1D array (as above), if you pass a 1D array # 2 get a 2D array where off diagonals are zero as below np.diag([1,2]) # ### Outer product / inner product # 1. Outer product: $C(i,j) = A(i)B(j)$ # 1.1 Example: $$\sum = E{(x - μ)(x - μ)^T} ≈ \frac{1}{N-1}\sum_{n=1}^N(x_n - \overline{x})(x_n - \overline{x})T$$ # 2. Inner product: C = sum over i {A(i)B(i)} # In[50]: #Doing an outer product a = np.array([1,2]) b = np.array([3,4]) np.outer(a,b) # In[51]: # dot product ,as you may recall is also known as inner product np.inner(a,b) # In[52]: a.dot(b) # same as above # In[53]: # Matrix trace is the sum of the diagonals of a matrix np.diag(A).sum() # See In [92] # In[54]: np.trace(A) # In[55]: # Eigenvalues and Eigenvectors X = np.random.randn(100,3) # In[56]: covariance = np.cov(X) # In[57]: covariance.shape # In[58]: covariance = np.cov(X.T) # transpose X # In[59]: covariance # ### Eigenvalues and Eigenvectors # # 1. eigenvalues, eigenvectors = np.eig(C) # Symmetric matrix is equal of a Transpose of itself # or # 2. eigenvalues, eigenvectors = np.eigh(C) # While a Hermitian matrix ia a conjugate of transpose of itself # # So, Symmetricc $A = A^T$, while Hermitian matrix of $A = A^H$ or simply $A^H$ is conjugate transpose of A # # 3. Convariance is a symmetric matrix, so we should be able to use eigh... # In[60]: np.linalg.eigh(covariance) #gives a tuple # In[61]: type(np.linalg.eigh(covariance)) # In[62]: np.linalg.eig(covariance) # will give us a tuple, first tuple contains 3 eigenvalues and sector tuple contains eigenvectors stored in columns # In[63]: type(np.linalg.eig(covariance)) # In[64]: # You may have notice they can be in different order, try running it again to check it out for yourself! # ## Solving a Linear System # # 1. $Ax = b$ # A is matrix, x is col vector of values we are trying to solve for and B is vector of numbers # 2. Solution = $A^{-1} = x = A^{-1}b$ # 3. Notes: Will be adding soon... # In[65]: A # In[66]: b # In[67]: b = np.array([1,2]) b # In[68]: x = np.linalg.inv(A).dot(b) x # In[69]: x = np.linalg.solve(A, b) # much intuitive and efficient way to do it. also more accurate. # In[70]: x # ## A simple example... # 1. Problem description: In a party, singles pay a entry ticket of 2.50 dollars and couples paid for a single 4.00 dollars . At this big rock concert event, some 20,000 tickets were sold and 75,500 dollars was made by the organizers. How many singles and how many couples partied that night? # # 1.1 X1 = number of singles, X2 = number of couples => # 1.2 X1 + X2 = 20,000 => # 1.3 2.5X1 + 4.00X2 = 75,000 # # 2. As a matrix this is how it looks like: $$ # \begin{bmatrix} # 1 & 1 \\ # 2.5 & 4 \\ # \end{bmatrix} # \begin{bmatrix} # x1 \\ # x2 \\ # \end{bmatrix} = # \begin{bmatrix} # 20000 \\ # 75000 \\ # \end{bmatrix}$$ # In[71]: party_goers = np.array([[1,1], [2.5,4]]) # This is our 2D matrix A collections = np.array([20000, 75000]) #This is our 1D matrix / vector b # In[72]: np.linalg.solve(party_goers, collections) print("There were ", np.linalg.solve(party_goers, collections)[0],\ " singles and ", np.linalg.solve(party_goers, collections)[1] ,\ " couples; and apparently some one cheated on their partner that night ;)") # ## More stuff coming here! # Don't go away as I explain and we learn together the following, we first do a recap so you refresh your thoughts again on: # 1. Numpy Specific # 1.1 Arrays # 1.2. Array Indexing # 1.3. Datatypes # 1.4. Array Math # 1.5. Broadcasting # 2. A super fast refresh on Python lists, dictionaries, classes and functions # 3. Pandas w.r.t Numpy # 4. Scipy w.r.t Numpy # 5. Matplotlib w.r.t Numpy # In[ ]: