{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Dimensionality reduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "###### COMP4670/8600 - Introduction to Statistical Machine Learning - Tutorial 6" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Setting up the environment" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import scipy.optimize as opt\n", "import pickle\n", "\n", "%matplotlib inline" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Toy dataset for debugging\n", "\n", "Write a function that generates data from two Gaussians with unit variance, centered at $\\mathbf{1}$ and $-\\mathbf{1}$ respectively. $\\mathbf{1}$ is the vector of all ones.\n", "\n", "Use the function to generate 100 samples from each Gaussian, with a 5 dimensional feature space." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Principal component analysis (PCA)\n", "\n", "The **Singular Values** of a square matrix $A$ is defined as the square root of the eigenvalues of $A^T A$. Given a matrix $X$, the singular value decomposition (SVD) is given by\n", "$$\n", "X = U S V^T\n", "$$\n", "where $U$ and $V$ are orthogonal matrices containing the left and right singular vectors respectively. And $S$ is a matrix with the singular values along the diagonal.\n", "\n", "Recall that PCA considers the covariance matrix of a data matrix $X$. Using the definition of SVD above, derive expressions for:\n", "1. the eigenvectors\n", "2. the projection of $X$ onto the $k$ largest eigenvalues\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Solution description" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Implement PCA\n", "\n", "Implement the principal component analysis method, using numpy.linalg.svd. Your function should take the data matrix and return two matrices:\n", "1. The projection of the data onto the principal components\n", "2. The actual components (eigenvectors) themselves.\n", "\n", "*Hint: do not forget to center the data by removing the mean*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Obtain the projection of the toy data above to its first two principal components. Plot the results. You should be able to see that the first principal component already gives you the axis of discrimination." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": { "collapsed": false }, "source": [ "## The classification data set\n", "\n", "*You have seen this dataset in earlier tutorials*\n", "\n", "We will predict the incidence of diabetes based on various measurements (see [description](https://archive.ics.uci.edu/ml/datasets/Pima+Indians+Diabetes)). Instead of directly using the raw data, we use a normalised version, where the label to be predicted (the incidence of diabetes) is in the first column. Download the data from [mldata.org](http://mldata.org/repository/data/download/csv/diabetes_scale/).\n", "\n", "Read in the data using pandas." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "names = ['diabetes', 'num preg', 'plasma', 'bp', 'skin fold', 'insulin', 'bmi', 'pedigree', 'age']\n", "data = pd.read_csv('diabetes_scale.csv', header=None, names=names)\n", "data.diabetes.replace(-1, 0, inplace=True) # replace -1 with 0 because we need labels to be in {0, 1}\n", "data.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find the first two principal components of the features in the classification data set. Plot the scatter plot showing the examples projected onto the first two principal components. Use the labels to produce different symbols for each class. Discuss whether the first two principal components discriminate well." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## (optional) Effect of normalisation on principal components\n", "\n", "Plot the scatter plot of the first two principal components of the classification dataset respectively before and after the normalisations in Tutorial 2 and 5." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using principal components as features for classification" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Write a file containing the features projected onto the first 4 principal components, using the to_csv command of pandas." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Data should look something like the below\n", "data = pd.read_csv('prin_feat4.csv')\n", "data.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use the first four principal components with your logistic regression code from Tutorial 3, and compare the results. For simplicity, compare the training error." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## (optional) Explore noisy features\n", "\n", "Use numpy.random.randn to generate 20 random features and add them to the diabetes dataset. How does logistic regression perform on all features? Can PCA be used to identify the signal?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Eigenfaces\n", "\n", "The aim of this section of the tutorial is to see that in some cases, the principal components can be human interpretable.\n", "\n", "The images below are of Colin Powell, resized to a smaller image, from [LFW](http://vis-www.cs.umass.edu/lfw/). Download the images from [the course website](https://machlearn.gitlab.io/isml2017/tutorial/lfw_colin.pkl)." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Visualising images\n", "def plot_gallery(images, titles, h, w, n_row=2, n_col=6):\n", " \"\"\"Helper function to plot a gallery of portraits\"\"\"\n", " plt.figure(figsize=(1.8 * n_col, 2.4 * n_row))\n", " plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)\n", " for i in range(n_row * n_col):\n", " plt.subplot(n_row, n_col, i + 1)\n", " plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)\n", " plt.title(titles[i], size=12)\n", " plt.xticks(())\n", " plt.yticks(())\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "lfw_colin = pickle.load(open('lfw_colin.pkl', 'rb'))\n", "\n", "# introspect the images array to find the shapes (for plotting)\n", "n_samples, h, w = lfw_colin['images'].shape\n", "plot_gallery(lfw_colin['images'], range(n_samples), h, w)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Use the pca function you wrote above to find the first 15 principal components. Visualise them. Discuss what the components potentially capture, for example lighting from the right.\n", "\n", "*Hint: Images need to be converted into a vector for PCA, and the results need to be converted back*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Solution goes here" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.4" } }, "nbformat": 4, "nbformat_minor": 0 }