diff --git a/doc/pub/week36/html/week36-bs.html b/doc/pub/week36/html/week36-bs.html index 9def9c7a3..92eecfe0a 100644 --- a/doc/pub/week36/html/week36-bs.html +++ b/doc/pub/week36/html/week36-bs.html @@ -56,6 +56,10 @@ Automatically generated HTML file from DocOnce source 2, None, 'and-finally-boldsymbol-x-boldsymbol-x-t'), + ('Code for SVD and Inversion of Matrices', + 2, + None, + 'code-for-svd-and-inversion-of-matrices'), ('Ridge and LASSO Regression', 2, None, @@ -269,65 +273,66 @@ MathJax.Hub.Config({
+How do we use the SVD to invert a matrix \( \boldsymbol{X}^\boldsymbol{X} \) which is singular or near singular? +The simple answer is to use the linear algebra function for pseudoinvers, that is +
+ + +
Ainv = np.linlag.pinv(A)
++Let us first look at a matrix which does not causes problems and write our own function where we just use the SVD. + +
+ + +
import numpy as np
+# SVD inversion
+def SVDinv(A):
+ ''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).
+ SVD is numerically more stable than the inversion algorithms provided by
+ numpy and scipy.linalg at the cost of being slower.
+ '''
+ U, s, VT = np.linalg.svd(A)
+ print('test U')
+ print( (np.transpose(U) @ U - U @np.transpose(U)))
+ print('test VT')
+ print( (np.transpose(VT) @ VT - VT @np.transpose(VT)))
+
+
+ D = np.zeros((len(U),len(VT)))
+ D = np.diag(s)
+ UT = np.transpose(U); V = np.transpose(VT); invD = np.linalg.inv(D)
+ return np.matmul(V,np.matmul(invD,UT))
+
+
+#X = np.array([ [1.0, -1.0, 2.0], [1.0, 0.0, 1.0], [1.0, 2.0, -1.0], [1.0, 1.0, 0.0] ])
+X = np.array( [ [1,2],[2,3]])
+print(X)
+A = np.transpose(X) @ X
+# Brute force inversion
+B = np.linalg.inv(A)
+C = SVDinv(A)
+print(np.abs(B-C))
+
+
+How do we use the SVD to invert a matrix \( \boldsymbol{X}^\boldsymbol{X} \) which is singular or near singular? +The simple answer is to use the linear algebra function for pseudoinvers, that is +
+ + +
Ainv = np.linlag.pinv(A)
++Let us first look at a matrix which does not causes problems and write our own function where we just use the SVD. + +
+ + +
import numpy as np
+# SVD inversion
+def SVDinv(A):
+ ''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).
+ SVD is numerically more stable than the inversion algorithms provided by
+ numpy and scipy.linalg at the cost of being slower.
+ '''
+ U, s, VT = np.linalg.svd(A)
+ print('test U')
+ print( (np.transpose(U) @ U - U @np.transpose(U)))
+ print('test VT')
+ print( (np.transpose(VT) @ VT - VT @np.transpose(VT)))
+
+
+ D = np.zeros((len(U),len(VT)))
+ D = np.diag(s)
+ UT = np.transpose(U); V = np.transpose(VT); invD = np.linalg.inv(D)
+ return np.matmul(V,np.matmul(invD,UT))
+
+
+#X = np.array([ [1.0, -1.0, 2.0], [1.0, 0.0, 1.0], [1.0, 2.0, -1.0], [1.0, 1.0, 0.0] ])
+X = np.array( [ [1,2],[2,3]])
+print(X)
+A = np.transpose(X) @ X
+# Brute force inversion
+B = np.linalg.inv(A)
+C = SVDinv(A)
+print(np.abs(B-C))
+
+
+
@@ -995,14 +1047,14 @@ lambdas = np.logspace(-4, for i in range(nlambdas): lmb = lambdas[i] Ridgebeta = np.linalg.inv(X.T @ X+lmb*I) @ X.T @ y -# print(Ridgebeta) + print(Ridgebeta) # and then make the prediction ypredictRidge = X @ Ridgebeta MSERidgePredict[i] = MSE(y,ypredictRidge) -# print(MSEPredict[i]) RegLasso = linear_model.Lasso(lmb) RegLasso.fit(X,y) ypredictLasso = RegLasso.predict(X) + print(RegLasso_coef_) MSELassoPredict[i] = MSE(y,ypredictLasso) # Now plot the results plt.figure() @@ -1057,13 +1109,9 @@ OLSbeta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train print(OLSbeta) # and then make the prediction ytildeOLS = X_train @ OLSbeta -print("Training R2 for OLS") -print(R2(y_train,ytildeOLS)) print("Training MSE for OLS") print(MSE(y_train,ytildeOLS)) ypredictOLS = X_test @ OLSbeta -print("Test R2 for OLS") -print(R2(y_test,ypredictOLS)) print("Test MSE OLS") print(MSE(y_test,ypredictOLS)) diff --git a/doc/pub/week36/html/week36.html b/doc/pub/week36/html/week36.html index ba6797338..69f561b9b 100644 --- a/doc/pub/week36/html/week36.html +++ b/doc/pub/week36/html/week36.html @@ -81,6 +81,10 @@ div { text-align: justify; text-justify: inter-word; } 2, None, 'and-finally-boldsymbol-x-boldsymbol-x-t'), + ('Code for SVD and Inversion of Matrices', + 2, + None, + 'code-for-svd-and-inversion-of-matrices'), ('Ridge and LASSO Regression', 2, None, @@ -443,6 +447,54 @@ values and the column vectors of \( \boldsymbol{V} \).
+
+How do we use the SVD to invert a matrix \( \boldsymbol{X}^\boldsymbol{X} \) which is singular or near singular? +The simple answer is to use the linear algebra function for pseudoinvers, that is +
+ + +
Ainv = np.linlag.pinv(A)
++Let us first look at a matrix which does not causes problems and write our own function where we just use the SVD. + +
+ + +
import numpy as np
+# SVD inversion
+def SVDinv(A):
+ ''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).
+ SVD is numerically more stable than the inversion algorithms provided by
+ numpy and scipy.linalg at the cost of being slower.
+ '''
+ U, s, VT = np.linalg.svd(A)
+ print('test U')
+ print( (np.transpose(U) @ U - U @np.transpose(U)))
+ print('test VT')
+ print( (np.transpose(VT) @ VT - VT @np.transpose(VT)))
+
+
+ D = np.zeros((len(U),len(VT)))
+ D = np.diag(s)
+ UT = np.transpose(U); V = np.transpose(VT); invD = np.linalg.inv(D)
+ return np.matmul(V,np.matmul(invD,UT))
+
+
+#X = np.array([ [1.0, -1.0, 2.0], [1.0, 0.0, 1.0], [1.0, 2.0, -1.0], [1.0, 1.0, 0.0] ])
+X = np.array( [ [1,2],[2,3]])
+print(X)
+A = np.transpose(X) @ X
+# Brute force inversion
+B = np.linalg.inv(A)
+C = SVDinv(A)
+print(np.abs(B-C))
+
+
+
@@ -1000,14 +1052,14 @@ lambdas = np. for i in range(nlambdas): lmb = lambdas[i] Ridgebeta = np.linalg.inv(X.T @ X+lmb*I) @ X.T @ y -# print(Ridgebeta) + print(Ridgebeta) # and then make the prediction ypredictRidge = X @ Ridgebeta MSERidgePredict[i] = MSE(y,ypredictRidge) -# print(MSEPredict[i]) RegLasso = linear_model.Lasso(lmb) RegLasso.fit(X,y) ypredictLasso = RegLasso.predict(X) + print(RegLasso_coef_) MSELassoPredict[i] = MSE(y,ypredictLasso) # Now plot the results plt.figure() @@ -1062,13 +1114,9 @@ OLSbeta = np. print(OLSbeta) # and then make the prediction ytildeOLS = X_train @ OLSbeta -print("Training R2 for OLS") -print(R2(y_train,ytildeOLS)) print("Training MSE for OLS") print(MSE(y_train,ytildeOLS)) ypredictOLS = X_test @ OLSbeta -print("Test R2 for OLS") -print(R2(y_test,ypredictOLS)) print("Test MSE OLS") print(MSE(y_test,ypredictOLS)) diff --git a/doc/pub/week36/ipynb/ipynb-week36-src.tar.gz b/doc/pub/week36/ipynb/ipynb-week36-src.tar.gz index c07b5e271..ce546c0f8 100644 Binary files a/doc/pub/week36/ipynb/ipynb-week36-src.tar.gz and b/doc/pub/week36/ipynb/ipynb-week36-src.tar.gz differ diff --git a/doc/pub/week36/ipynb/week36.ipynb b/doc/pub/week36/ipynb/week36.ipynb index 9395e12c4..a17bc5486 100644 --- a/doc/pub/week36/ipynb/week36.ipynb +++ b/doc/pub/week36/ipynb/week36.ipynb @@ -254,6 +254,75 @@ "values and the column vectors of $\\boldsymbol{V}$.\n", "\n", "\n", + "\n", + "## Code for SVD and Inversion of Matrices\n", + "\n", + "How do we use the SVD to invert a matrix $\\boldsymbol{X}^\\boldsymbol{X}$ which is singular or near singular?\n", + "The simple answer is to use the linear algebra function for pseudoinvers, that is" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "editable": true + }, + "outputs": [], + "source": [ + "Ainv = np.linlag.pinv(A)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us first look at a matrix which does not causes problems and write our own function where we just use the SVD." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false, + "editable": true + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "# SVD inversion\n", + "def SVDinv(A):\n", + " ''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD).\n", + " SVD is numerically more stable than the inversion algorithms provided by\n", + " numpy and scipy.linalg at the cost of being slower.\n", + " '''\n", + " U, s, VT = np.linalg.svd(A)\n", + " print('test U')\n", + " print( (np.transpose(U) @ U - U @np.transpose(U)))\n", + " print('test VT')\n", + " print( (np.transpose(VT) @ VT - VT @np.transpose(VT)))\n", + "\n", + "\n", + " D = np.zeros((len(U),len(VT)))\n", + " D = np.diag(s)\n", + " UT = np.transpose(U); V = np.transpose(VT); invD = np.linalg.inv(D)\n", + " return np.matmul(V,np.matmul(invD,UT))\n", + "\n", + "\n", + "#X = np.array([ [1.0, -1.0, 2.0], [1.0, 0.0, 1.0], [1.0, 2.0, -1.0], [1.0, 1.0, 0.0] ])\n", + "X = np.array( [ [1,2],[2,3]])\n", + "print(X)\n", + "A = np.transpose(X) @ X\n", + "# Brute force inversion\n", + "B = np.linalg.inv(A)\n", + "C = SVDinv(A)\n", + "print(np.abs(B-C))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "## Ridge and LASSO Regression\n", "\n", "Let us remind ourselves about the expression for the standard Mean Squared Error (MSE) which we used to define our cost function and the equations for the ordinary least squares (OLS) method, that is \n", @@ -1222,14 +1291,14 @@ "for i in range(nlambdas):\n", " lmb = lambdas[i]\n", " Ridgebeta = np.linalg.inv(X.T @ X+lmb*I) @ X.T @ y\n", - "# print(Ridgebeta)\n", + " print(Ridgebeta)\n", " # and then make the prediction\n", " ypredictRidge = X @ Ridgebeta\n", " MSERidgePredict[i] = MSE(y,ypredictRidge)\n", - "# print(MSEPredict[i])\n", " RegLasso = linear_model.Lasso(lmb)\n", " RegLasso.fit(X,y)\n", " ypredictLasso = RegLasso.predict(X)\n", + " print(RegLasso_coef_)\n", " MSELassoPredict[i] = MSE(y,ypredictLasso)\n", "# Now plot the results\n", "plt.figure()\n", @@ -1293,13 +1362,9 @@ "print(OLSbeta)\n", "# and then make the prediction\n", "ytildeOLS = X_train @ OLSbeta\n", - "print(\"Training R2 for OLS\")\n", - "print(R2(y_train,ytildeOLS))\n", "print(\"Training MSE for OLS\")\n", "print(MSE(y_train,ytildeOLS))\n", "ypredictOLS = X_test @ OLSbeta\n", - "print(\"Test R2 for OLS\")\n", - "print(R2(y_test,ypredictOLS))\n", "print(\"Test MSE OLS\")\n", "print(MSE(y_test,ypredictOLS))\n", "\n", diff --git a/doc/src/week36/week36.do.txt b/doc/src/week36/week36.do.txt index 201bbac0f..c3d0d4b3f 100644 --- a/doc/src/week36/week36.do.txt +++ b/doc/src/week36/week36.do.txt @@ -144,6 +144,52 @@ of our data (the columns of $\bm{X}$, the quantity of interest for us are the no values and the column vectors of $\bm{V}$. + +!split +===== Code for SVD and Inversion of Matrices ===== + +How do we use the SVD to invert a matrix $\bm{X}^\bm{X}$ which is singular or near singular? +The simple answer is to use the linear algebra function for pseudoinvers, that is +!bc pycod +Ainv = np.linlag.pinv(A) +!ec + +Let us first look at a matrix which does not causes problems and write our own function where we just use the SVD. + +!bc pycod +import numpy as np +# SVD inversion +def SVDinv(A): + ''' Takes as input a numpy matrix A and returns inv(A) based on singular value decomposition (SVD). + SVD is numerically more stable than the inversion algorithms provided by + numpy and scipy.linalg at the cost of being slower. + ''' + U, s, VT = np.linalg.svd(A) + print('test U') + print( (np.transpose(U) @ U - U @np.transpose(U))) + print('test VT') + print( (np.transpose(VT) @ VT - VT @np.transpose(VT))) + + + D = np.zeros((len(U),len(VT))) + D = np.diag(s) + UT = np.transpose(U); V = np.transpose(VT); invD = np.linalg.inv(D) + return np.matmul(V,np.matmul(invD,UT)) + + +#X = np.array([ [1.0, -1.0, 2.0], [1.0, 0.0, 1.0], [1.0, 2.0, -1.0], [1.0, 1.0, 0.0] ]) +X = np.array( [ [1,2],[2,3]]) +print(X) +A = np.transpose(X) @ X +# Brute force inversion +B = np.linalg.inv(A) +C = SVDinv(A) +print(np.abs(B-C)) +!ec + + + + !split ===== Ridge and LASSO Regression ===== @@ -698,14 +744,14 @@ lambdas = np.logspace(-4, 4, nlambdas) for i in range(nlambdas): lmb = lambdas[i] Ridgebeta = np.linalg.inv(X.T @ X+lmb*I) @ X.T @ y -# print(Ridgebeta) + print(Ridgebeta) # and then make the prediction ypredictRidge = X @ Ridgebeta MSERidgePredict[i] = MSE(y,ypredictRidge) -# print(MSEPredict[i]) RegLasso = linear_model.Lasso(lmb) RegLasso.fit(X,y) ypredictLasso = RegLasso.predict(X) + print(RegLasso_coef_) MSELassoPredict[i] = MSE(y,ypredictLasso) # Now plot the results plt.figure() @@ -758,13 +804,9 @@ OLSbeta = np.linalg.inv(X_train.T @ X_train) @ X_train.T @ y_train print(OLSbeta) # and then make the prediction ytildeOLS = X_train @ OLSbeta -print("Training R2 for OLS") -print(R2(y_train,ytildeOLS)) print("Training MSE for OLS") print(MSE(y_train,ytildeOLS)) ypredictOLS = X_test @ OLSbeta -print("Test R2 for OLS") -print(R2(y_test,ypredictOLS)) print("Test MSE OLS") print(MSE(y_test,ypredictOLS))