1611 lines
59 KiB
Plaintext
1611 lines
59 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"<!-- dom:TITLE: Data Analysis and Machine Learning: Preprocessing and Dimensionality Reduction -->\n",
|
||
"# Data Analysis and Machine Learning: Preprocessing and Dimensionality Reduction\n",
|
||
"<!-- dom:AUTHOR: Morten Hjorth-Jensen at Department of Physics, University of Oslo & Department of Physics and Astronomy and National Superconducting Cyclotron Laboratory, Michigan State University -->\n",
|
||
"<!-- Author: --> \n",
|
||
"**Morten Hjorth-Jensen**, Department of Physics, University of Oslo and Department of Physics and Astronomy and National Superconducting Cyclotron Laboratory, Michigan State University\n",
|
||
"\n",
|
||
"Date: **Oct 25, 2019**\n",
|
||
"\n",
|
||
"Copyright 1999-2019, Morten Hjorth-Jensen. Released under CC Attribution-NonCommercial 4.0 license\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Reducing the number of degrees of freedom, overarching view\n",
|
||
"\n",
|
||
"Many Machine Learning problems involve thousands or even millions of\n",
|
||
"features for each training instance. Not only does this make training\n",
|
||
"extremely slow, it can also make it much harder to find a good\n",
|
||
"solution, as we will see. This problem is often referred to as the\n",
|
||
"curse of dimensionality. Fortunately, in real-world problems, it is\n",
|
||
"often possible to reduce the number of features considerably, turning\n",
|
||
"an intractable problem into a tractable one.\n",
|
||
"\n",
|
||
"Here we will discuss some of the most popular dimensionality reduction\n",
|
||
"techniques: the principal component analysis PCA, Kernel PCA, and\n",
|
||
"Locally Linear Embedding (LLE). Furthermore, we will start by looking\n",
|
||
"at some simple preprocessing of the data which allow us to rescale the\n",
|
||
"data.\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Preprocessing our data\n",
|
||
"\n",
|
||
"Before we proceed however, we will discuss how to preprocess our\n",
|
||
"data. Till now and in connection with our previous examples we have\n",
|
||
"not met so many cases where we are too sensitive to the scaling of our\n",
|
||
"data. Normally the data may need a rescaling and/or may be sensitive\n",
|
||
"to extreme values. Scaling the data renders our inputs much more\n",
|
||
"suitable for the algorithms we want to employ.\n",
|
||
"\n",
|
||
"**Scikit-Learn** has several functions which allow us to rescale the\n",
|
||
"data, normally resulting in much better results in terms of various\n",
|
||
"accuracy scores. The **StandardScaler** function in **Scikit-Learn**\n",
|
||
"ensures that for each feature/predictor we study the mean value is\n",
|
||
"zero and the variance is one (every column in the design/feature\n",
|
||
"matrix). This scaling has the drawback that it does not ensure that\n",
|
||
"we have a particular maximum or minimum in our data set. Another\n",
|
||
"function included in **Scikit-Learn** is the **MinMaxScaler** which\n",
|
||
"ensures that all features are exactly between $0$ and $1$. The\n",
|
||
"\n",
|
||
"## More preprocessing\n",
|
||
"\n",
|
||
"\n",
|
||
"The **Normalizer** scales each data\n",
|
||
"point such that the feature vector has a euclidean length of one. In other words, it\n",
|
||
"projects a data point on the circle (or sphere in the case of higher dimensions) with a\n",
|
||
"radius of 1. This means every data point is scaled by a different number (by the\n",
|
||
"inverse of it’s length).\n",
|
||
"This normalization is often used when only the direction (or angle) of the data matters,\n",
|
||
"not the length of the feature vector.\n",
|
||
"\n",
|
||
"The **RobustScaler** works similarly to the StandardScaler in that it\n",
|
||
"ensures statistical properties for each feature that guarantee that\n",
|
||
"they are on the same scale. However, the RobustScaler uses the median\n",
|
||
"and quartiles, instead of mean and variance. This makes the\n",
|
||
"RobustScaler ignore data points that are very different from the rest\n",
|
||
"(like measurement errors). These odd data points are also called\n",
|
||
"outliers, and might often lead to trouble for other scaling\n",
|
||
"techniques.\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Simple preprocessing examples, Franke function and regression"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 1,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"%matplotlib inline\n",
|
||
"\n",
|
||
"# Common imports\n",
|
||
"import os\n",
|
||
"import numpy as np\n",
|
||
"import pandas as pd\n",
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import sklearn.linear_model as skl\n",
|
||
"from sklearn.metrics import mean_squared_error\n",
|
||
"from sklearn.model_selection import train_test_split\n",
|
||
"from sklearn.preprocessing import MinMaxScaler, StandardScaler, Normalizer\n",
|
||
"from sklearn.svm import SVR\n",
|
||
"\n",
|
||
"# Where to save the figures and data files\n",
|
||
"PROJECT_ROOT_DIR = \"Results\"\n",
|
||
"FIGURE_ID = \"Results/FigureFiles\"\n",
|
||
"DATA_ID = \"DataFiles/\"\n",
|
||
"\n",
|
||
"if not os.path.exists(PROJECT_ROOT_DIR):\n",
|
||
" os.mkdir(PROJECT_ROOT_DIR)\n",
|
||
"\n",
|
||
"if not os.path.exists(FIGURE_ID):\n",
|
||
" os.makedirs(FIGURE_ID)\n",
|
||
"\n",
|
||
"if not os.path.exists(DATA_ID):\n",
|
||
" os.makedirs(DATA_ID)\n",
|
||
"\n",
|
||
"def image_path(fig_id):\n",
|
||
" return os.path.join(FIGURE_ID, fig_id)\n",
|
||
"\n",
|
||
"def data_path(dat_id):\n",
|
||
" return os.path.join(DATA_ID, dat_id)\n",
|
||
"\n",
|
||
"def save_fig(fig_id):\n",
|
||
" plt.savefig(image_path(fig_id) + \".png\", format='png')\n",
|
||
"\n",
|
||
"\n",
|
||
"def FrankeFunction(x,y):\n",
|
||
"\tterm1 = 0.75*np.exp(-(0.25*(9*x-2)**2) - 0.25*((9*y-2)**2))\n",
|
||
"\tterm2 = 0.75*np.exp(-((9*x+1)**2)/49.0 - 0.1*(9*y+1))\n",
|
||
"\tterm3 = 0.5*np.exp(-(9*x-7)**2/4.0 - 0.25*((9*y-3)**2))\n",
|
||
"\tterm4 = -0.2*np.exp(-(9*x-4)**2 - (9*y-7)**2)\n",
|
||
"\treturn term1 + term2 + term3 + term4\n",
|
||
"\n",
|
||
"\n",
|
||
"def create_X(x, y, n ):\n",
|
||
"\tif len(x.shape) > 1:\n",
|
||
"\t\tx = np.ravel(x)\n",
|
||
"\t\ty = np.ravel(y)\n",
|
||
"\n",
|
||
"\tN = len(x)\n",
|
||
"\tl = int((n+1)*(n+2)/2)\t\t# Number of elements in beta\n",
|
||
"\tX = np.ones((N,l))\n",
|
||
"\n",
|
||
"\tfor i in range(1,n+1):\n",
|
||
"\t\tq = int((i)*(i+1)/2)\n",
|
||
"\t\tfor k in range(i+1):\n",
|
||
"\t\t\tX[:,q+k] = (x**(i-k))*(y**k)\n",
|
||
"\n",
|
||
"\treturn X\n",
|
||
"\n",
|
||
"\n",
|
||
"# Making meshgrid of datapoints and compute Franke's function\n",
|
||
"n = 5\n",
|
||
"N = 1000\n",
|
||
"x = np.sort(np.random.uniform(0, 1, N))\n",
|
||
"y = np.sort(np.random.uniform(0, 1, N))\n",
|
||
"z = FrankeFunction(x, y)\n",
|
||
"X = create_X(x, y, n=n) \n",
|
||
"# split in training and test data\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(X,z,test_size=0.2)\n",
|
||
"\n",
|
||
"\n",
|
||
"svm = SVR(gamma='auto',C=10.0)\n",
|
||
"svm.fit(X_train, y_train)\n",
|
||
"\n",
|
||
"# The mean squared error and R2 score\n",
|
||
"print(\"MSE before scaling: {:.2f}\".format(mean_squared_error(svm.predict(X_test), y_test)))\n",
|
||
"print(\"R2 score before scaling {:.2f}\".format(svm.score(X_test,y_test)))\n",
|
||
"\n",
|
||
"scaler = StandardScaler()\n",
|
||
"scaler.fit(X_train)\n",
|
||
"X_train_scaled = scaler.transform(X_train)\n",
|
||
"X_test_scaled = scaler.transform(X_test)\n",
|
||
"\n",
|
||
"print(\"Feature min values before scaling:\\n {}\".format(X_train.min(axis=0)))\n",
|
||
"print(\"Feature max values before scaling:\\n {}\".format(X_train.max(axis=0)))\n",
|
||
"\n",
|
||
"print(\"Feature min values after scaling:\\n {}\".format(X_train_scaled.min(axis=0)))\n",
|
||
"print(\"Feature max values after scaling:\\n {}\".format(X_train_scaled.max(axis=0)))\n",
|
||
"\n",
|
||
"svm = SVR(gamma='auto',C=10.0)\n",
|
||
"svm.fit(X_train_scaled, y_train)\n",
|
||
"\n",
|
||
"print(\"MSE after scaling: {:.2f}\".format(mean_squared_error(svm.predict(X_test_scaled), y_test)))\n",
|
||
"print(\"R2 score for scaled data: {:.2f}\".format(svm.score(X_test_scaled,y_test)))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Simple preprocessing examples, breast cancer data and classification, Support Vector Machines\n",
|
||
"\n",
|
||
"We show here how we can use a simple regression case on the breast\n",
|
||
"cancer data using support vector machines (SVM) as algorithm for\n",
|
||
"classification."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 2,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"from sklearn.model_selection import train_test_split \n",
|
||
"from sklearn.datasets import load_breast_cancer\n",
|
||
"from sklearn.svm import SVC\n",
|
||
"cancer = load_breast_cancer()\n",
|
||
"\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(cancer.data,cancer.target,random_state=0)\n",
|
||
"print(X_train.shape)\n",
|
||
"print(X_test.shape)\n",
|
||
"\n",
|
||
"svm = SVC(C=100)\n",
|
||
"svm.fit(X_train, y_train)\n",
|
||
"print(\"Test set accuracy: {:.2f}\".format(svm.score(X_test,y_test)))\n",
|
||
"\n",
|
||
"from sklearn.preprocessing import MinMaxScaler, StandardScaler\n",
|
||
"scaler = MinMaxScaler()\n",
|
||
"scaler.fit(X_train)\n",
|
||
"X_train_scaled = scaler.transform(X_train)\n",
|
||
"X_test_scaled = scaler.transform(X_test)\n",
|
||
"\n",
|
||
"print(\"Feature min values before scaling:\\n {}\".format(X_train.min(axis=0)))\n",
|
||
"print(\"Feature max values before scaling:\\n {}\".format(X_train.max(axis=0)))\n",
|
||
"\n",
|
||
"print(\"Feature min values before scaling:\\n {}\".format(X_train_scaled.min(axis=0)))\n",
|
||
"print(\"Feature max values before scaling:\\n {}\".format(X_train_scaled.max(axis=0)))\n",
|
||
"\n",
|
||
"\n",
|
||
"svm.fit(X_train_scaled, y_train)\n",
|
||
"print(\"Test set accuracy scaled data with Min-Max scaling: {:.2f}\".format(svm.score(X_test_scaled,y_test)))\n",
|
||
"\n",
|
||
"scaler = StandardScaler()\n",
|
||
"scaler.fit(X_train)\n",
|
||
"X_train_scaled = scaler.transform(X_train)\n",
|
||
"X_test_scaled = scaler.transform(X_test)\n",
|
||
"\n",
|
||
"svm.fit(X_train_scaled, y_train)\n",
|
||
"print(\"Test set accuracy scaled data with Standar Scaler: {:.2f}\".format(svm.score(X_test_scaled,y_test)))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## More on Cancer Data, now with Logistic Regression"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 3,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"from sklearn.model_selection import train_test_split \n",
|
||
"from sklearn.datasets import load_breast_cancer\n",
|
||
"from sklearn.linear_model import LogisticRegression\n",
|
||
"cancer = load_breast_cancer()\n",
|
||
"\n",
|
||
"# Set up training data\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(cancer.data,cancer.target,random_state=0)\n",
|
||
"logreg = LogisticRegression()\n",
|
||
"logreg.fit(X_train, y_train)\n",
|
||
"print(\"Test set accuracy: {:.2f}\".format(logreg.score(X_test,y_test)))\n",
|
||
"\n",
|
||
"# Scale data\n",
|
||
"from sklearn.preprocessing import StandardScaler\n",
|
||
"scaler = StandardScaler()\n",
|
||
"scaler.fit(X_train)\n",
|
||
"X_train_scaled = scaler.transform(X_train)\n",
|
||
"X_test_scaled = scaler.transform(X_test)\n",
|
||
"logreg.fit(X_train_scaled, y_train)\n",
|
||
"print(\"Test set accuracy scaled data: {:.2f}\".format(logreg.score(X_test_scaled,y_test)))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Why should we think of reducing the dimensionality\n",
|
||
"\n",
|
||
"In addition to the plot of the features, we study now also the covariance (or rather the correlation matrix).\n",
|
||
"We use also **Pandas** to compute the correlation matrix."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 4,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"from sklearn.model_selection import train_test_split \n",
|
||
"from sklearn.datasets import load_breast_cancer\n",
|
||
"from sklearn.linear_model import LogisticRegression\n",
|
||
"cancer = load_breast_cancer()\n",
|
||
"import pandas as pd\n",
|
||
"# Making a data frame\n",
|
||
"cancerpd = pd.DataFrame(cancer.data, columns=cancer.feature_names)\n",
|
||
"\n",
|
||
"fig, axes = plt.subplots(15,2,figsize=(10,20))\n",
|
||
"malignant = cancer.data[cancer.target == 0]\n",
|
||
"benign = cancer.data[cancer.target == 1]\n",
|
||
"ax = axes.ravel()\n",
|
||
"\n",
|
||
"for i in range(30):\n",
|
||
" _, bins = np.histogram(cancer.data[:,i], bins =50)\n",
|
||
" ax[i].hist(malignant[:,i], bins = bins, alpha = 0.5)\n",
|
||
" ax[i].hist(benign[:,i], bins = bins, alpha = 0.5)\n",
|
||
" ax[i].set_title(cancer.feature_names[i])\n",
|
||
" ax[i].set_yticks(())\n",
|
||
"ax[0].set_xlabel(\"Feature magnitude\")\n",
|
||
"ax[0].set_ylabel(\"Frequency\")\n",
|
||
"ax[0].legend([\"Malignant\", \"Benign\"], loc =\"best\")\n",
|
||
"fig.tight_layout()\n",
|
||
"plt.show()\n",
|
||
"\n",
|
||
"import seaborn as sns\n",
|
||
"correlation_matrix = cancerpd.corr().round(1)\n",
|
||
"# use the heatmap function from seaborn to plot the correlation matrix\n",
|
||
"# annot = True to print the values inside the square\n",
|
||
"sns.heatmap(data=correlation_matrix, annot=True)\n",
|
||
"plt.show()\n",
|
||
"\n",
|
||
"#print eigvalues of correlation matrix\n",
|
||
"EigValues, EigVectors = np.linalg.eig(correlation_matrix)\n",
|
||
"print(EigValues)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"In the above example we note two things. In the first plot we display\n",
|
||
"the overlap of benign and malignant tumors as functions of the various\n",
|
||
"features in the Wisconsing breast cancer data set. We see that for\n",
|
||
"some of the features we can distinguish clearly the benign and\n",
|
||
"malignant cases while for other features we cannot. This can point to\n",
|
||
"us which features may be of greater interest when we wish to classify\n",
|
||
"a benign or not benign tumour.\n",
|
||
"\n",
|
||
"In the second figure we have computed the so-called correlation\n",
|
||
"matrix, which in our case with thirty features becomes a $30\\times 30$\n",
|
||
"matrix.\n",
|
||
"\n",
|
||
"We constructed this matrix using **pandas** via the statements"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 5,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"cancerpd = pd.DataFrame(cancer.data, columns=cancer.feature_names)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"and then"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 6,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"correlation_matrix = cancerpd.corr().round(1)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Diagonalizing this matrix we can in turn say something about which\n",
|
||
"features are of relevance and which are not. But before we proceed we\n",
|
||
"need to define covariance and correlation matrices. This leads us to\n",
|
||
"the classical Principal Component Analysis (PCA) theorem with\n",
|
||
"applications.\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Basic ideas of the Principal Component Analysis (PCA)\n",
|
||
"\n",
|
||
"We have a data set defined by a design/feature matrix $\\boldsymbol{X}$ (see below for its definition) \n",
|
||
"* Each data point is determined by $p$ extrinsic (measurement) variables\n",
|
||
"\n",
|
||
"* We may want to ask the following question: Are there fewer intrinsic variables (say $d << p$) that still approximately describe the data?\n",
|
||
"\n",
|
||
"* If so, these intrinsic variables may tell us something important and finding these intrinsic variables is what dimension reduction methods do. \n",
|
||
"\n",
|
||
"## Introducing the Covariance and Correlation functions\n",
|
||
"\n",
|
||
"Before we discuss the PCA theorem, we need to remind ourselves about\n",
|
||
"the definition of the covariance and the correlation function.\n",
|
||
"\n",
|
||
"Suppose we have defined two vectors\n",
|
||
"$\\hat{x}$ and $\\hat{y}$ with $n$ elements each. The covariance matrix $\\boldsymbol{C}$ is defined as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x},\\boldsymbol{y}] = \\begin{bmatrix} \\mathrm{cov}[\\boldsymbol{x},\\boldsymbol{x}] & \\mathrm{cov}[\\boldsymbol{x},\\boldsymbol{y}] \\\\\n",
|
||
" \\mathrm{cov}[\\boldsymbol{y},\\boldsymbol{x}] & \\mathrm{cov}[\\boldsymbol{y},\\boldsymbol{y}] \\\\\n",
|
||
" \\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"where for example"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathrm{cov}[\\boldsymbol{x},\\boldsymbol{y}] =\\frac{1}{n} \\sum_{i=0}^{n-1}(x_i- \\overline{x})(y_i- \\overline{y}).\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"With this definition and recalling that the variance is defined as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathrm{var}[\\boldsymbol{x}]=\\frac{1}{n} \\sum_{i=0}^{n-1}(x_i- \\overline{x})^2,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"we can rewrite the covariance matrix as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x},\\boldsymbol{y}] = \\begin{bmatrix} \\mathrm{var}[\\boldsymbol{x}] & \\mathrm{cov}[\\boldsymbol{x},\\boldsymbol{y}] \\\\\n",
|
||
" \\mathrm{cov}[\\boldsymbol{x},\\boldsymbol{y}] & \\mathrm{var}[\\boldsymbol{y}] \\\\\n",
|
||
" \\end{bmatrix}.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"The covariance takes values between zero and infinity and may thus\n",
|
||
"lead to problems with loss of numerical precision for particularly\n",
|
||
"large values. It is common to scale the covariance matrix by\n",
|
||
"introducing instead the correlation matrix defined via the so-called\n",
|
||
"correlation function"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathrm{corr}[\\boldsymbol{x},\\boldsymbol{y}]=\\frac{\\mathrm{cov}[\\boldsymbol{x},\\boldsymbol{y}]}{\\sqrt{\\mathrm{var}[\\boldsymbol{x}] \\mathrm{var}[\\boldsymbol{y}]}}.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"The correlation function is then given by values $\\mathrm{corr}[\\boldsymbol{x},\\boldsymbol{y}]\n",
|
||
"\\in [-1,1]$. This avoids eventual problems with too large values. We\n",
|
||
"can then define the correlation matrix for the two vectors $\\boldsymbol{x}$\n",
|
||
"and $\\boldsymbol{y}$ as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{K}[\\boldsymbol{x},\\boldsymbol{y}] = \\begin{bmatrix} 1 & \\mathrm{corr}[\\boldsymbol{x},\\boldsymbol{y}] \\\\\n",
|
||
" \\mathrm{corr}[\\boldsymbol{y},\\boldsymbol{x}] & 1 \\\\\n",
|
||
" \\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"In the above example this is the function we constructed using **pandas**.\n",
|
||
"\n",
|
||
"## Correlation Function and Design/Feature Matrix\n",
|
||
"\n",
|
||
"In our derivation of the various regression algorithms like Ordinary Least Squares or Ridge regression we defined the design/feature matrix $\\boldsymbol{X}$ as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{X}=\\begin{bmatrix}\n",
|
||
"x_{0,0} & x_{0,1} & x_{0,2}& \\dots & \\dots x_{0,p-1}\\\\\n",
|
||
"x_{1,0} & x_{1,1} & x_{1,2}& \\dots & \\dots x_{1,p-1}\\\\\n",
|
||
"x_{2,0} & x_{2,1} & x_{2,2}& \\dots & \\dots x_{2,p-1}\\\\\n",
|
||
"\\dots & \\dots & \\dots & \\dots \\dots & \\dots \\\\\n",
|
||
"x_{n-2,0} & x_{n-2,1} & x_{n-2,2}& \\dots & \\dots x_{n-2,p-1}\\\\\n",
|
||
"x_{n-1,0} & x_{n-1,1} & x_{n-1,2}& \\dots & \\dots x_{n-1,p-1}\\\\\n",
|
||
"\\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"with $\\boldsymbol{X}\\in {\\mathbb{R}}^{n\\times p}$, with the predictors/features $p$ refering to the column numbers and the\n",
|
||
"entries $n$ being the row elements.\n",
|
||
"We can rewrite the design/feature matrix in terms of its column vectors as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{X}=\\begin{bmatrix} \\boldsymbol{x}_0 & \\boldsymbol{x}_1 & \\boldsymbol{x}_2 & \\dots & \\dots & \\boldsymbol{x}_{p-1}\\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"with a given vector"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{x}_i^T = \\begin{bmatrix}x_{0,i} & x_{1,i} & x_{2,i}& \\dots & \\dots x_{n-1,i}\\end{bmatrix}.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"With these definitions, we can now rewrite our $2\\times 2$ correaltion/covariance matrix in terms of a moe general design/feature matrix $\\boldsymbol{X}\\in {\\mathbb{R}}^{n\\times p}$. This leads to a $p\\times p$ covariance matrix for the vectors $\\boldsymbol{x}_i$ with $i =0,1,\\dots,p-1$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x}] = \\begin{bmatrix}\n",
|
||
"\\mathrm{var}[\\boldsymbol{x}_0] & \\mathrm{cov}[\\boldsymbol{x}_0,\\boldsymbol{x}_1] & \\mathrm{cov}[\\boldsymbol{x}_0,\\boldsymbol{x}_2] & \\dots & \\dots & \\mathrm{cov}[\\boldsymbol{x}_0,\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\mathrm{cov}[\\boldsymbol{x}_1,\\boldsymbol{x}_0] & \\mathrm{var}[\\boldsymbol{x}_1] & \\mathrm{cov}[\\boldsymbol{x}_1,\\boldsymbol{x}_2] & \\dots & \\dots & \\mathrm{cov}[\\boldsymbol{x}_1,\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\mathrm{cov}[\\boldsymbol{x}_2,\\boldsymbol{x}_0] & \\mathrm{cov}[\\boldsymbol{x}_2,\\boldsymbol{x}_1] & \\mathrm{var}[\\boldsymbol{x}_2] & \\dots & \\dots & \\mathrm{cov}[\\boldsymbol{x}_2,\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\dots & \\dots & \\dots & \\dots & \\dots & \\dots \\\\\n",
|
||
"\\dots & \\dots & \\dots & \\dots & \\dots & \\dots \\\\\n",
|
||
"\\mathrm{cov}[\\boldsymbol{x}_{p-1},\\boldsymbol{x}_0] & \\mathrm{cov}[\\boldsymbol{x}_{p-1},\\boldsymbol{x}_1] & \\mathrm{cov}[\\boldsymbol{x}_{p-1},\\boldsymbol{x}_{2}] & \\dots & \\dots & \\mathrm{var}[\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"and the correlation matrix"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{K}[\\boldsymbol{x}] = \\begin{bmatrix}\n",
|
||
"1 & \\mathrm{corr}[\\boldsymbol{x}_0,\\boldsymbol{x}_1] & \\mathrm{corr}[\\boldsymbol{x}_0,\\boldsymbol{x}_2] & \\dots & \\dots & \\mathrm{corr}[\\boldsymbol{x}_0,\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\mathrm{corr}[\\boldsymbol{x}_1,\\boldsymbol{x}_0] & 1 & \\mathrm{corr}[\\boldsymbol{x}_1,\\boldsymbol{x}_2] & \\dots & \\dots & \\mathrm{corr}[\\boldsymbol{x}_1,\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\mathrm{corr}[\\boldsymbol{x}_2,\\boldsymbol{x}_0] & \\mathrm{corr}[\\boldsymbol{x}_2,\\boldsymbol{x}_1] & 1 & \\dots & \\dots & \\mathrm{corr}[\\boldsymbol{x}_2,\\boldsymbol{x}_{p-1}]\\\\\n",
|
||
"\\dots & \\dots & \\dots & \\dots & \\dots & \\dots \\\\\n",
|
||
"\\dots & \\dots & \\dots & \\dots & \\dots & \\dots \\\\\n",
|
||
"\\mathrm{corr}[\\boldsymbol{x}_{p-1},\\boldsymbol{x}_0] & \\mathrm{corr}[\\boldsymbol{x}_{p-1},\\boldsymbol{x}_1] & \\mathrm{corr}[\\boldsymbol{x}_{p-1},\\boldsymbol{x}_{2}] & \\dots & \\dots & 1\\\\\n",
|
||
"\\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Covariance Matrix Examples\n",
|
||
"\n",
|
||
"\n",
|
||
"The Numpy function **np.cov** calculates the covariance elements using\n",
|
||
"the factor $1/(n-1)$ instead of $1/n$ since it assumes we do not have\n",
|
||
"the exact mean values. The following simple function uses the\n",
|
||
"**np.vstack** function which takes each vector of dimension $1\\times n$\n",
|
||
"and produces a $2\\times n$ matrix $\\boldsymbol{W}$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{W} = \\begin{bmatrix} x_0 & y_0 \\\\\n",
|
||
" x_1 & y_1 \\\\\n",
|
||
" x_2 & y_2\\\\\n",
|
||
" \\dots & \\dots \\\\\n",
|
||
" x_{n-2} & y_{n-2}\\\\\n",
|
||
" x_{n-1} & y_{n-1} & \n",
|
||
" \\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"which in turn is converted into into the $2\\times 2$ covariance matrix\n",
|
||
"$\\boldsymbol{C}$ via the Numpy function **np.cov()**. We note that we can also calculate\n",
|
||
"the mean value of each set of samples $\\boldsymbol{x}$ etc using the Numpy\n",
|
||
"function **np.mean(x)**. We can also extract the eigenvalues of the\n",
|
||
"covariance matrix through the **np.linalg.eig()** function."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 7,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Importing various packages\n",
|
||
"import numpy as np\n",
|
||
"n = 100\n",
|
||
"x = np.random.normal(size=n)\n",
|
||
"print(np.mean(x))\n",
|
||
"y = 4+3*x+np.random.normal(size=n)\n",
|
||
"print(np.mean(y))\n",
|
||
"W = np.vstack((x, y))\n",
|
||
"C = np.cov(W)\n",
|
||
"print(C)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Correlation Matrix\n",
|
||
"\n",
|
||
"The previous example can be converted into the correlation matrix by\n",
|
||
"simply scaling the matrix elements with the variances. We should also\n",
|
||
"subtract the mean values for each column. This leads to the following\n",
|
||
"code which sets up the correlations matrix for the previous example in\n",
|
||
"a more brute force way. Here we scale the mean values for each column of the design matrix, calculate the relevant mean values and variances and then finally set up the $2\\times 2$ correlation matrix (since we have only two vectors)."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 8,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"n = 100\n",
|
||
"# define two vectors \n",
|
||
"x = np.random.random(size=n)\n",
|
||
"y = 4+3*x+np.random.normal(size=n)\n",
|
||
"#scaling the x and y vectors \n",
|
||
"x = x - np.mean(x)\n",
|
||
"y = y - np.mean(y)\n",
|
||
"variance_x = np.sum(x@x)/n\n",
|
||
"variance_y = np.sum(y@y)/n\n",
|
||
"print(variance_x)\n",
|
||
"print(variance_y)\n",
|
||
"cov_xy = np.sum(x@y)/n\n",
|
||
"cov_xx = np.sum(x@x)/n\n",
|
||
"cov_yy = np.sum(y@y)/n\n",
|
||
"C = np.zeros((2,2))\n",
|
||
"C[0,0]= cov_xx/variance_x\n",
|
||
"C[1,1]= cov_yy/variance_y\n",
|
||
"C[0,1]= cov_xy/np.sqrt(variance_y*variance_x)\n",
|
||
"C[1,0]= C[0,1]\n",
|
||
"print(C)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"We see that the matrix elements along the diagonal are one as they\n",
|
||
"should be and that the matrix is symmetric. Furthermore, diagonalizing\n",
|
||
"this matrix we easily see that it is a positive definite matrix.\n",
|
||
"\n",
|
||
"The above procedure with **numpy** can be made more compact if we use **pandas**.\n",
|
||
"\n",
|
||
"## Correlation Matrix with Pandas\n",
|
||
"\n",
|
||
"We whow here how we can set up the correlation matrix using **pandas**, as done in this simple code"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 9,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"import pandas as pd\n",
|
||
"n = 10\n",
|
||
"x = np.random.normal(size=n)\n",
|
||
"x = x - np.mean(x)\n",
|
||
"y = 4+3*x+np.random.normal(size=n)\n",
|
||
"y = y - np.mean(y)\n",
|
||
"X = (np.vstack((x, y))).T\n",
|
||
"print(X)\n",
|
||
"Xpd = pd.DataFrame(X)\n",
|
||
"print(Xpd)\n",
|
||
"correlation_matrix = Xpd.corr()\n",
|
||
"print(correlation_matrix)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"We expand this model to the Franke function discussed above.\n",
|
||
"\n",
|
||
"## Correlation Matrix with Pandas and the Franke function"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 10,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"# Common imports\n",
|
||
"import numpy as np\n",
|
||
"import pandas as pd\n",
|
||
"\n",
|
||
"\n",
|
||
"def FrankeFunction(x,y):\n",
|
||
"\tterm1 = 0.75*np.exp(-(0.25*(9*x-2)**2) - 0.25*((9*y-2)**2))\n",
|
||
"\tterm2 = 0.75*np.exp(-((9*x+1)**2)/49.0 - 0.1*(9*y+1))\n",
|
||
"\tterm3 = 0.5*np.exp(-(9*x-7)**2/4.0 - 0.25*((9*y-3)**2))\n",
|
||
"\tterm4 = -0.2*np.exp(-(9*x-4)**2 - (9*y-7)**2)\n",
|
||
"\treturn term1 + term2 + term3 + term4\n",
|
||
"\n",
|
||
"\n",
|
||
"def create_X(x, y, n ):\n",
|
||
"\tif len(x.shape) > 1:\n",
|
||
"\t\tx = np.ravel(x)\n",
|
||
"\t\ty = np.ravel(y)\n",
|
||
"\n",
|
||
"\tN = len(x)\n",
|
||
"\tl = int((n+1)*(n+2)/2)\t\t# Number of elements in beta\n",
|
||
"\tX = np.ones((N,l))\n",
|
||
"\n",
|
||
"\tfor i in range(1,n+1):\n",
|
||
"\t\tq = int((i)*(i+1)/2)\n",
|
||
"\t\tfor k in range(i+1):\n",
|
||
"\t\t\tX[:,q+k] = (x**(i-k))*(y**k)\n",
|
||
"\n",
|
||
"\treturn X\n",
|
||
"\n",
|
||
"\n",
|
||
"# Making meshgrid of datapoints and compute Franke's function\n",
|
||
"n = 4\n",
|
||
"N = 100\n",
|
||
"x = np.sort(np.random.uniform(0, 1, N))\n",
|
||
"y = np.sort(np.random.uniform(0, 1, N))\n",
|
||
"z = FrankeFunction(x, y)\n",
|
||
"X = create_X(x, y, n=n) \n",
|
||
"\n",
|
||
"Xpd = pd.DataFrame(X)\n",
|
||
"# subtract the mean values and set up the covariance matrix\n",
|
||
"Xpd = Xpd - Xpd.mean()\n",
|
||
"covariance_matrix = Xpd.cov()\n",
|
||
"print(covariance_matrix)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"We note here that the covariance is zero for the first rows and\n",
|
||
"columns since all matrix elements in the design matrix were set to one\n",
|
||
"(we are fitting the function in terms of a polynomial of degree $n$).\n",
|
||
"\n",
|
||
"This means that the variance for these elements will be zero and will\n",
|
||
"cause problems when we set up the correlation matrix. We can simply\n",
|
||
"drop these elements as follows and then construct the correlation\n",
|
||
"matrix. \n",
|
||
"\n",
|
||
"\n",
|
||
"## Rewriting the Covariance and/or Correlation Matrix\n",
|
||
"\n",
|
||
"We can rewrite the covariance matrix in a more compact form in terms of the design/feature matrix $\\boldsymbol{X}$ as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x}] = \\frac{1}{n}\\boldsymbol{X}\\boldsymbol{X}^T= \\mathbb{E}[\\boldsymbol{X}\\boldsymbol{X}^T].\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"To see this let us simply look at a design matrix $\\boldsymbol{X}\\in {\\mathbb{R}}^{2\\times 2}$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{X}=\\begin{bmatrix}\n",
|
||
"x_{00} & x_{01}\\\\\n",
|
||
"x_{10} & x_{11}\\\\\n",
|
||
"\\end{bmatrix}=\\begin{bmatrix}\n",
|
||
"\\boldsymbol{x}_{0} & \\boldsymbol{x}_{1}\\\\\n",
|
||
"\\end{bmatrix}.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"If we then compute the expectation value"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathbb{E}[\\boldsymbol{X}\\boldsymbol{X}^T] = \\frac{1}{n}\\boldsymbol{X}\\boldsymbol{X}^T=\\begin{bmatrix}\n",
|
||
"x_{00}^2+x_{01}^2 & x_{00}x_{10}+x_{01}x_{11}\\\\\n",
|
||
"x_{10}x_{00}+x_{11}x_{01} & x_{10}^2+x_{11}^2\\\\\n",
|
||
"\\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"which is just"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x}_0,\\boldsymbol{x}_1] = \\boldsymbol{C}[\\boldsymbol{x}]=\\begin{bmatrix} \\mathrm{var}[\\boldsymbol{x}_0] & \\mathrm{cov}[\\boldsymbol{x}_0,\\boldsymbol{x}_1] \\\\\n",
|
||
" \\mathrm{cov}[\\boldsymbol{x}_1,\\boldsymbol{x}_0] & \\mathrm{var}[\\boldsymbol{x}_1] \\\\\n",
|
||
" \\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"where we wrote $$\\boldsymbol{C}[\\boldsymbol{x}_0,\\boldsymbol{x}_1] = \\boldsymbol{C}[\\boldsymbol{x}]$$ to indicate that this the covariance of the vectors $\\boldsymbol{x}$ of the design/feature matrix $\\boldsymbol{X}$.\n",
|
||
"\n",
|
||
"It is easy to generalize this to a matrix $\\boldsymbol{X}\\in {\\mathbb{R}}^{n\\times p}$.\n",
|
||
"\n",
|
||
"\n",
|
||
"## Towards the PCA theorem\n",
|
||
"\n",
|
||
"We have that the covariance matrix (the correlation matrix involves a simple rescaling) is given as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x}] = \\frac{1}{n}\\boldsymbol{X}\\boldsymbol{X}^T= \\mathbb{E}[\\boldsymbol{X}\\boldsymbol{X}^T].\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Let us now assume that we can perform a series of orthogonal transformations where we employ some orthogonal matrices $\\boldsymbol{S}$.\n",
|
||
"These matrices are defined as $\\boldsymbol{S}\\in {\\mathbb{R}}^{p\\times p}$ and obey the orthogonality requirements $\\boldsymbol{S}\\boldsymbol{S}^T=\\boldsymbol{S}^T\\boldsymbol{S}=\\boldsymbol{I}$. The matrix can be written out in terms of the column vectors $\\boldsymbol{s}_i$ as $\\boldsymbol{S}=[\\boldsymbol{s}_0,\\boldsymbol{s}_1,\\dots,\\boldsymbol{s}_{p-1}]$ and $\\boldsymbol{s}_i \\in {\\mathbb{R}}^{p}$.\n",
|
||
"\n",
|
||
"Assume also that there is a transformation $\\boldsymbol{S}\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{S}^T=\\boldsymbol{C}[\\boldsymbol{y}]$ such that the new matrix $\\boldsymbol{C}[\\boldsymbol{y}]$ is diagonal with elements $[\\lambda_0,\\lambda_1,\\lambda_2,\\dots,\\lambda_{p-1}]$. \n",
|
||
"\n",
|
||
"That is we have"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{y}] = \\mathbb{E}[\\boldsymbol{S}\\boldsymbol{X}\\boldsymbol{X}^T\\boldsymbol{S}^T]=\\boldsymbol{S}\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{S}^T,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"since the matrix $\\boldsymbol{S}$ is not a data dependent matrix. Multiplying with $\\boldsymbol{S}^T$ from the left we have"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{S}^T\\boldsymbol{C}[\\boldsymbol{y}] = \\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{S}^T,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"and since $\\boldsymbol{C}[\\boldsymbol{y}]$ is diagonal we have for a given eigenvalue $i$ of the covariance matrix that"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{S}^T_i\\lambda_i = \\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{S}^T_i.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"In the derivation of the PCA theorem we will assume that the eigenvalues are ordered in descending order, that is\n",
|
||
"$\\lambda_0 > \\lambda_1 > \\dots > \\lambda_{p-1}$. \n",
|
||
"\n",
|
||
"\n",
|
||
"The eigenvalues tell us then how much we need to stretch the\n",
|
||
"corresponding eigenvectors. Dimensions with large eigenvalues have\n",
|
||
"thus large variations (large variance) and define therefore useful\n",
|
||
"dimensions. The data points are more spread out in the direction of\n",
|
||
"these eigenvectors. Smaller eigenvalues mean on the other hand that\n",
|
||
"the corresponding eigenvectors are shrunk accordingly and the data\n",
|
||
"points are tightly bunched together and there is not much variation in\n",
|
||
"these specific directions. Hopefully then we could leave it out\n",
|
||
"dimensions where the eigenvalues are very small. If $p$ is very large,\n",
|
||
"we could then aim at reducing $p$ to $l << p$ and handle only $l$\n",
|
||
"features/predictors.\n",
|
||
"\n",
|
||
"## The Algorithm before theorem\n",
|
||
"\n",
|
||
"Here's how we would proceed in setting up the algorithm for the PCA, see also discussion below here. \n",
|
||
"* Set up the datapoints for the design/feature matrix $\\boldsymbol{X}$ with $\\boldsymbol{X}\\in {\\mathbb{R}}^{n\\times p}$, with the predictors/features $p$ referring to the column numbers and the entries $n$ being the row elements."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{X}=\\begin{bmatrix}\n",
|
||
"x_{0,0} & x_{0,1} & x_{0,2}& \\dots & \\dots x_{0,p-1}\\\\\n",
|
||
"x_{1,0} & x_{1,1} & x_{1,2}& \\dots & \\dots x_{1,p-1}\\\\\n",
|
||
"x_{2,0} & x_{2,1} & x_{2,2}& \\dots & \\dots x_{2,p-1}\\\\\n",
|
||
"\\dots & \\dots & \\dots & \\dots \\dots & \\dots \\\\\n",
|
||
"x_{n-2,0} & x_{n-2,1} & x_{n-2,2}& \\dots & \\dots x_{n-2,p-1}\\\\\n",
|
||
"x_{n-1,0} & x_{n-1,1} & x_{n-1,2}& \\dots & \\dots x_{n-1,p-1}\\\\\n",
|
||
"\\end{bmatrix},\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"* Center the data by subtracting the mean value for each column. This leads to a new matrix $\\boldsymbol{X}\\rightarrow \\overline{\\boldsymbol{X}}$.\n",
|
||
"\n",
|
||
"* Compute then the covariance/correlation matrix $\\mathbb{E}[\\overline{\\boldsymbol{X}}\\overline{\\boldsymbol{X}}^T]$.\n",
|
||
"\n",
|
||
"* Find the eigenpairs of $\\boldsymbol{C}$ with eigenvalues $[\\lambda_0,\\lambda_1,\\dots,\\lambda_{p-1}]$ and eigenvectors $[\\boldsymbol{s}_0,\\boldsymbol{s}_1,\\dots,\\boldsymbol{s}_{p-1}]$.\n",
|
||
"\n",
|
||
"* Order the eigenvalue (and the eigenvectors accordingly) in order of decreasing eigenvalues.\n",
|
||
"\n",
|
||
"* Keep only those $l$ eigenvalues larger than a selected threshold value, discarding thus $p-l$ features since we expect small variations in the data here.\n",
|
||
"\n",
|
||
"After this we ask ourselves how do we prove the link between the maximum variance and the feature reduction.\n",
|
||
"\n",
|
||
"## Classical PCA Theorem\n",
|
||
"\n",
|
||
"We assume now that we have a design matrix $\\boldsymbol{X}$ which has been centered as discussed above. For the sake of simplicity we skip the overline symbol. The matrix is defined in terms of the various column vectors $[\\boldsymbol{x}_0,\\boldsymbol{x}_1,\\dots, \\boldsymbol{x}_{p-1}]$\n",
|
||
"each with dimension $\\boldsymbol{x}\\in {\\mathbb{R}}^{n}$.\n",
|
||
"\n",
|
||
"We assume also that we have an orthogonal transformation $\\boldsymbol{W}\\in {\\mathbb{R}}^{p\\times p}$. We define the reconstruction error (which is similar to the mean squared error we have seen before) as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"J(\\boldsymbol{W},\\boldsymbol{Z}) = \\frac{1}{n}\\sum_i (\\boldsymbol{x}_i - \\overline{\\boldsymbol{x}}_i)^2,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"with $\\overline{\\boldsymbol{x}}_i = \\boldsymbol{W}\\boldsymbol{z}_i$, where $\\boldsymbol{z}_i$ is a row vector with dimension ${\\mathbb{R}}^{n}$ of the matrix\n",
|
||
"$\\boldsymbol{Z}\\in{\\mathbb{R}}^{p\\times n}$. When doing PCA we want to reduce this dimensionality. \n",
|
||
"\n",
|
||
"The PCA theorem states that minimizing the above reconstruction error corresponds to setting $\\boldsymbol{W}=\\boldsymbol{S}$, the orthogonal matrix which diagonalizes the empirical covariance(correlation) matrix. The optimal low-dimensional encoding of the data is then given by a set of vectors $\\boldsymbol{z}_i$ with at most $l$ vectors, with $l << p$, defined by the orthogonal projection of the data onto the columns spanned by the eigenvectors of the covariance(correlations matrix).\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Proof of the PCA Theorem\n",
|
||
"\n",
|
||
"To show the PCA theorem let us start with the assumption that there is one vector $\\boldsymbol{w}_0$ which corresponds to a solution which minimized the reconstruction error $J$. This is an orthogonal vector. It means that we now approximate the reconstruction error in terms of $\\boldsymbol{w}_0$ and $\\boldsymbol{z}_0$ as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"J(\\boldsymbol{w}_0,\\boldsymbol{z}_0)= \\frac{1}{n}\\sum_i (\\boldsymbol{x}_i - z_{i0}\\boldsymbol{w}_0)^2=\\frac{1}{n}\\sum_i (\\boldsymbol{x}_i^T\\boldsymbol{x}_i - 2z_{i0}\\boldsymbol{w}_0^T\\boldsymbol{x}_i+z_{i0}^2\\boldsymbol{w}_0^T\\boldsymbol{w}_0),\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"which we can rewrite due to the orthogonality of $\\boldsymbol{w}_i$ as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"J(\\boldsymbol{w}_0,\\boldsymbol{z}_0)=\\frac{1}{n}\\sum_i (\\boldsymbol{x}_i^T\\boldsymbol{x}_i - 2z_{i0}\\boldsymbol{w}_0^T\\boldsymbol{x}_i+z_{i0}^2).\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Minimizing $J$ with respect to the unknown parameters $z_{0i}$ we obtain that"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"z_{i0}=\\boldsymbol{w}_0^T\\boldsymbol{x}_i,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"where the vectors on the rhs are known. \n",
|
||
"\n",
|
||
"\n",
|
||
"## PCA Proof continued\n",
|
||
"\n",
|
||
"We have now found the unknown parameters $z_{i0}$. These correspond to the projected coordinates and we can write"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"J(\\boldsymbol{w}_0)= \\frac{1}{p}\\sum_i (\\boldsymbol{x}_i^T\\boldsymbol{x}_i - z_{i0}^2)=\\mathrm{const}-\\frac{1}{n}\\sum_i z_{i0}^2.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"We can show that the variance of the projected coordinates defined by $\\boldsymbol{w}_0^T\\boldsymbol{x}_i$ are given by"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathrm{var}[\\boldsymbol{w}_0^T\\boldsymbol{x}_i] = \\frac{1}{n}\\sum_i z_{i0}^2,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"since the expectation value of"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathbb{E}[\\boldsymbol{w}_0^T\\boldsymbol{x}_i] = \\mathbb{E}[z_{i0}]= \\boldsymbol{w}_0^T\\mathbb{E}[\\boldsymbol{x}_i]=0,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"where we have used the fact that our data are centered.\n",
|
||
"\n",
|
||
"Recalling our definition of the covariance as"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x}] = \\frac{1}{n}\\boldsymbol{X}\\boldsymbol{X}^T=\\mathbb{E}[\\boldsymbol{X}\\boldsymbol{X}^T],\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"we have thus that"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\mathrm{var}[\\boldsymbol{w}_0^T\\boldsymbol{x}_i] = \\frac{1}{n}\\sum_i z_{i0}^2=\\boldsymbol{w}_0^T\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{w}_0.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"We are almost there, we have obtained a relation between minimizing the reconstruction error and the variance and the covariance matrix. Minimizing the error is equivalent to maximizing the variance of the projected data. \n",
|
||
"\n",
|
||
"## The final step\n",
|
||
"\n",
|
||
"We could trivially maximize the variance of the projection (and\n",
|
||
"thereby minimize the error in the reconstruction function) by letting\n",
|
||
"the norm-2 of $\\boldsymbol{w}_0$ go to infinity. However, this norm since we\n",
|
||
"want the matrix $\\boldsymbol{W}$ to be an orthogonal matrix, is constrained by\n",
|
||
"$\\vert\\vert \\boldsymbol{w}_0 \\vert\\vert_2^2=1$. Imposing this condition via a\n",
|
||
"Lagrange multiplier we can then in turn maximize"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"J(\\boldsymbol{w}_0)= \\boldsymbol{w}_0^T\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{w}_0+\\lambda_0(1-\\boldsymbol{w}_0^T\\boldsymbol{w}_0).\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Taking the derivative with respect to $\\boldsymbol{w}_0$ we obtain"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\frac{\\partial J(\\boldsymbol{w}_0)}{\\partial \\boldsymbol{w}_0}= 2\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{w}_0-2\\lambda_0\\boldsymbol{w}_0=0,\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"meaning that"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{w}_0=\\lambda_0\\boldsymbol{w}_0.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"**The direction that maximizes the variance (or minimizes the construction error) is an eigenvector of the covariance matrix**! If we left multiply with $\\boldsymbol{w}_0^T$ we have the variance of the projected data is"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"$$\n",
|
||
"\\boldsymbol{w}_0^T\\boldsymbol{C}[\\boldsymbol{x}]\\boldsymbol{w}_0=\\lambda_0.\n",
|
||
"$$"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"If we want to maximize the variance (minimize the construction error)\n",
|
||
"we simply pick the eigenvector of the covariance matrix with the\n",
|
||
"largest eigenvalue. This establishes the link between the minimization\n",
|
||
"of the reconstruction function $J$ in terms of an orthogonal matrix\n",
|
||
"and the maximization of the variance and thereby the covariance of our\n",
|
||
"observations encoded in the design/feature matrix $\\boldsymbol{X}$.\n",
|
||
"\n",
|
||
"The proof\n",
|
||
"for the other eigenvectors $\\boldsymbol{w}_1,\\boldsymbol{w}_2,\\dots$ can be\n",
|
||
"established by applying the above arguments and using the fact that\n",
|
||
"our basis of eigenvectors is orthogonal, see [Murphy chapter\n",
|
||
"12.2](https://mitpress.mit.edu/books/machine-learning-1). The\n",
|
||
"discussion in chapter 12.2 of Murphy's text has also a nice link with\n",
|
||
"the Singular Value Decomposition theorem. For categorical data, see\n",
|
||
"chapter 12.4 and discussion therein.\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Principal Component Analysis\n",
|
||
"Principal Component Analysis (PCA) is by far the most popular dimensionality reduction algorithm.\n",
|
||
"First it identifies the hyperplane that lies closest to the data, and then it projects the data onto it.\n",
|
||
"\n",
|
||
"The following Python code uses NumPy’s **svd()** function to obtain all the principal components of the\n",
|
||
"training set, then extracts the first two principal components. First we center the data using either **pandas** or our own code"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 11,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import numpy as np\n",
|
||
"import pandas as pd\n",
|
||
"from IPython.display import display\n",
|
||
"np.random.seed(100)\n",
|
||
"# setting up a 10 x 5 vanilla matrix \n",
|
||
"rows = 10\n",
|
||
"cols = 5\n",
|
||
"X = np.random.randn(rows,cols)\n",
|
||
"df = pd.DataFrame(X)\n",
|
||
"# Pandas does the centering for us\n",
|
||
"df = df -df.mean()\n",
|
||
"display(df)\n",
|
||
"\n",
|
||
"# we center it ourselves\n",
|
||
"X_centered = X - X.mean(axis=0)\n",
|
||
"# Then check the difference between pandas and our own set up\n",
|
||
"print(X_centered-df)\n",
|
||
"#Now we do an SVD\n",
|
||
"U, s, V = np.linalg.svd(X_centered)\n",
|
||
"c1 = V.T[:, 0]\n",
|
||
"c2 = V.T[:, 1]\n",
|
||
"W2 = V.T[:, :2]\n",
|
||
"X2D = X_centered.dot(W2)\n",
|
||
"print(X2D)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"PCA assumes that the dataset is centered around the origin. Scikit-Learn’s PCA classes take care of centering\n",
|
||
"the data for you. However, if you implement PCA yourself (as in the preceding example), or if you use other libraries, don’t\n",
|
||
"forget to center the data first.\n",
|
||
"\n",
|
||
"Once you have identified all the principal components, you can reduce the dimensionality of the dataset\n",
|
||
"down to $d$ dimensions by projecting it onto the hyperplane defined by the first $d$ principal components.\n",
|
||
"Selecting this hyperplane ensures that the projection will preserve as much variance as possible."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 12,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"W2 = V.T[:, :2]\n",
|
||
"X2D = X_centered.dot(W2)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"<!-- !split -->\n",
|
||
"## PCA and scikit-learn\n",
|
||
"\n",
|
||
"Scikit-Learn’s PCA class implements PCA using SVD decomposition just like we did before. The\n",
|
||
"following code applies PCA to reduce the dimensionality of the dataset down to two dimensions (note\n",
|
||
"that it automatically takes care of centering the data):"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 13,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"#thereafter we do a PCA with Scikit-learn\n",
|
||
"from sklearn.decomposition import PCA\n",
|
||
"pca = PCA(n_components = 2)\n",
|
||
"X2D = pca.fit_transform(X)\n",
|
||
"print(X2D)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"After fitting the PCA transformer to the dataset, you can access the principal components using the\n",
|
||
"components variable (note that it contains the PCs as horizontal vectors, so, for example, the first\n",
|
||
"principal component is equal to"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 14,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"pca.components_.T[:, 0]."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"Another very useful piece of information is the explained variance ratio of each principal component,\n",
|
||
"available via the $explained\\_variance\\_ratio$ variable. It indicates the proportion of the dataset’s\n",
|
||
"variance that lies along the axis of each principal component. \n",
|
||
"\n",
|
||
"## Back to the Cancer Data\n",
|
||
"We can now repeat the above but applied to real data, in this case our breast cancer data.\n",
|
||
"Here we compute performance scores on the training data using logistic regression."
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 15,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"import matplotlib.pyplot as plt\n",
|
||
"import numpy as np\n",
|
||
"from sklearn.model_selection import train_test_split \n",
|
||
"from sklearn.datasets import load_breast_cancer\n",
|
||
"from sklearn.linear_model import LogisticRegression\n",
|
||
"cancer = load_breast_cancer()\n",
|
||
"\n",
|
||
"X_train, X_test, y_train, y_test = train_test_split(cancer.data,cancer.target,random_state=0)\n",
|
||
"\n",
|
||
"logreg = LogisticRegression()\n",
|
||
"logreg.fit(X_train, y_train)\n",
|
||
"print(\"Train set accuracy from Logistic Regression: {:.2f}\".format(logreg.score(X_train,y_train)))\n",
|
||
"# We scale the data\n",
|
||
"from sklearn.preprocessing import StandardScaler\n",
|
||
"scaler = StandardScaler()\n",
|
||
"scaler.fit(X_train)\n",
|
||
"X_train_scaled = scaler.transform(X_train)\n",
|
||
"X_test_scaled = scaler.transform(X_test)\n",
|
||
"# Then perform again a log reg fit\n",
|
||
"logreg.fit(X_train_scaled, y_train)\n",
|
||
"print(\"Train set accuracy scaled data: {:.2f}\".format(logreg.score(X_train_scaled,y_train)))\n",
|
||
"#thereafter we do a PCA with Scikit-learn\n",
|
||
"from sklearn.decomposition import PCA\n",
|
||
"pca = PCA(n_components = 2)\n",
|
||
"X2D_train = pca.fit_transform(X_train_scaled)\n",
|
||
"# and finally compute the log reg fit and the score on the training data\t\n",
|
||
"logreg.fit(X2D_train,y_train)\n",
|
||
"print(\"Train set accuracy scaled and PCA data: {:.2f}\".format(logreg.score(X2D_train,y_train)))"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"We see that our training data after the PCA decomposition has a performance similar to the non-scaled data. \n",
|
||
"\n",
|
||
"## More on the PCA\n",
|
||
"\n",
|
||
"Instead of arbitrarily choosing the number of dimensions to reduce down to, it is generally preferable to\n",
|
||
"choose the number of dimensions that add up to a sufficiently large portion of the variance (e.g., 95%).\n",
|
||
"Unless, of course, you are reducing dimensionality for data visualization — in that case you will\n",
|
||
"generally want to reduce the dimensionality down to 2 or 3.\n",
|
||
"The following code computes PCA without reducing dimensionality, then computes the minimum number\n",
|
||
"of dimensions required to preserve 95% of the training set’s variance:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 16,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"pca = PCA()\n",
|
||
"pca.fit(X)\n",
|
||
"cumsum = np.cumsum(pca.explained_variance_ratio_)\n",
|
||
"d = np.argmax(cumsum >= 0.95) + 1"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"You could then set $n\\_components=d$ and run PCA again. However, there is a much better option: instead\n",
|
||
"of specifying the number of principal components you want to preserve, you can set $n\\_components$ to be\n",
|
||
"a float between 0.0 and 1.0, indicating the ratio of variance you wish to preserve:"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 17,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"pca = PCA(n_components=0.95)\n",
|
||
"X_reduced = pca.fit_transform(X)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## Incremental PCA\n",
|
||
"\n",
|
||
"One problem with the preceding implementation of PCA is that it requires the whole training set to fit in\n",
|
||
"memory in order for the SVD algorithm to run. Fortunately, Incremental PCA (IPCA) algorithms have\n",
|
||
"been developed: you can split the training set into mini-batches and feed an IPCA algorithm one minibatch\n",
|
||
"at a time. This is useful for large training sets, and also to apply PCA online (i.e., on the fly, as new\n",
|
||
"instances arrive).\n",
|
||
"\n",
|
||
"## Randomized PCA\n",
|
||
"\n",
|
||
"Scikit-Learn offers yet another option to perform PCA, called Randomized PCA. This is a stochastic\n",
|
||
"algorithm that quickly finds an approximation of the first d principal components. Its computational\n",
|
||
"complexity is $O(m \\times d^2)+O(d^3)$, instead of $O(m \\times n^2) + O(n^3)$, so it is dramatically faster than the\n",
|
||
"previous algorithms when $d$ is much smaller than $n$.\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Kernel PCA\n",
|
||
"\n",
|
||
"The kernel trick is a mathematical technique that implicitly maps instances into a\n",
|
||
"very high-dimensional space (called the feature space), enabling nonlinear classification and regression\n",
|
||
"with Support Vector Machines. Recall that a linear decision boundary in the high-dimensional feature\n",
|
||
"space corresponds to a complex nonlinear decision boundary in the original space.\n",
|
||
"It turns out that the same trick can be applied to PCA, making it possible to perform complex nonlinear\n",
|
||
"projections for dimensionality reduction. This is called Kernel PCA (kPCA). It is often good at\n",
|
||
"preserving clusters of instances after projection, or sometimes even unrolling datasets that lie close to a\n",
|
||
"twisted manifold.\n",
|
||
"For example, the following code uses Scikit-Learn’s KernelPCA class to perform kPCA with an"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 18,
|
||
"metadata": {
|
||
"collapsed": false
|
||
},
|
||
"outputs": [],
|
||
"source": [
|
||
"from sklearn.decomposition import KernelPCA\n",
|
||
"rbf_pca = KernelPCA(n_components = 2, kernel=\"rbf\", gamma=0.04)\n",
|
||
"X_reduced = rbf_pca.fit_transform(X)"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"metadata": {},
|
||
"source": [
|
||
"## LLE\n",
|
||
"\n",
|
||
"Locally Linear Embedding (LLE) is another very powerful nonlinear dimensionality reduction\n",
|
||
"(NLDR) technique. It is a Manifold Learning technique that does not rely on projections like the previous\n",
|
||
"algorithms. In a nutshell, LLE works by first measuring how each training instance linearly relates to its\n",
|
||
"closest neighbors (c.n.), and then looking for a low-dimensional representation of the training set where\n",
|
||
"these local relationships are best preserved (more details shortly). \n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"## Other techniques\n",
|
||
"\n",
|
||
"\n",
|
||
"There are many other dimensionality reduction techniques, several of which are available in Scikit-Learn.\n",
|
||
"\n",
|
||
"Here are some of the most popular:\n",
|
||
"* **Multidimensional Scaling (MDS)** reduces dimensionality while trying to preserve the distances between the instances.\n",
|
||
"\n",
|
||
"* **Isomap** creates a graph by connecting each instance to its nearest neighbors, then reduces dimensionality while trying to preserve the geodesic distances between the instances.\n",
|
||
"\n",
|
||
"* **t-Distributed Stochastic Neighbor Embedding** (t-SNE) reduces dimensionality while trying to keep similar instances close and dissimilar instances apart. It is mostly used for visualization, in particular to visualize clusters of instances in high-dimensional space (e.g., to visualize the MNIST images in 2D).\n",
|
||
"\n",
|
||
"* Linear Discriminant Analysis (LDA) is actually a classification algorithm, but during training it learns the most discriminative axes between the classes, and these axes can then be used to define a hyperplane onto which to project the data. The benefit is that the projection will keep classes as far apart as possible, so LDA is a good technique to reduce dimensionality before running another classification algorithm such as a Support Vector Machine (SVM) classifier discussed in the SVM lectures."
|
||
]
|
||
}
|
||
],
|
||
"metadata": {},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 2
|
||
}
|