{ "metadata": { "name": "", "signature": "sha256:55bcd14f2534e3c4d1305defd8f3463f9885b410bf6c5bdecd57030c8ae5b85d" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to pattern_classification](https://github.com/rasbt/pattern_classification)]" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load_ext watermark" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "%watermark -d -u -v -p scikit-learn,pandas,scipy,matplotlib" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Last updated: 15/08/2014 \n", "\n", "CPython 3.4.1\n", "IPython 2.0.0\n", "\n", "scikit-learn 0.15.1\n", "pandas 0.14.0\n", "scipy 0.14.0\n", "matplotlib 1.3.1\n" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "[More information](https://github.com/rasbt/watermark) about the `watermark` magic command extension.\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "I would be happy to hear your comments and suggestions. \n", "Please feel free to drop me a note via\n", "[twitter](https://twitter.com/rasbt), [email](mailto:bluewoodtree@gmail.com), or [google+](https://plus.google.com/+SebastianRaschka).\n", "
" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Streamline your cross-validation and classification workflow \n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "- scikit-learn's Pipeline in action" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Sections" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- [An example for using Pipelines in Cross-validation and classification](#An-example-for-using-Pipelines-in-Cross-validation-and-classification)\n", " - [Key concepts and links for further reading](#Key-concepts-and-links-for-further-reading)\n", " - [Reading in the Iris dataset](#Reading-in-the-Iris-dataset)\n", " - [Exploratory visualization](#Exploratory-visualization)\n", " - [Preparing a Test and Training dataset](#Preparing-a-Test-and-Training-dataset)\n", " - [Cross-Validation and Pipelines](#Cross-Validation-and-Pipelines)\n", " - [Custom Pipeline objects](#Custom-Pipeline-objects)\n", " - [Running the cross-validation](#Running-the-cross-validation)\n", " - [Training the Naive Bayes classifier](#Training-the-Naive-Bayes-classifier)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Introduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `Pipeline` class in scikit-learn's [`pipeline`](http://scikit-learn.org/stable/modules/generated/sklearn.pipeline.Pipeline.html) module offers a convenient way to execute a chain of normalization and pre-processing steps, as well as predictors and classifiers on a dataset. \n", "\n", "Such a pipeline is especially useful in the context of cross-validation, where we are interested in testing and comparing different feature selection techniques, dimensionality reduction approaches, and classifiers. All in all, `Pipeline`s are not only a great time-saver, but they also allow us to write clutter-free code and stay organized in the attempt to find the ideal combination of techniques for solving a pattern classification task.\n", "\n", "In the current implementation of `Pipeline` the different steps in the chain have to be classes that have `fit` and `transform` methods (or, alternatively, a `fit_transform` method instead of `transform`).\n", "\n", "But before we get bogged down into details, let us prepare the Iris dataset in order to have a look at a `Pipeline` in action." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An example of a simple pipeline that consists of three steps: standardizing the dataset, dimensionality reduction via PCA, and training a naive Bayes classifier:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "clf = Pipeline(steps=[\n", " ('scaler', StandardScaler()), \n", " ('reduce_dim', PCA(n_components=2)),\n", " ('classifier', GaussianNB()) \n", " ])\n", "\n", "clf.fit(X_train, y_train) # fitting on the training dataset\n", "pred = clf_lda.predict(X_test) # classifying the test dataset" ], "language": "python", "metadata": {}, "outputs": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "An example for using Pipelines in Cross-validation and classification" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since I don't want to distract from the main topic of this article, the `Pipeline`s, I want to keep the descriptions about the other steps and concepts as concise as possible. Below is a list of the particular topics with links to other articles for further reading." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Key concepts and links for further reading" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "####The Iris dataset\n", "A dataset of 150 flowers from three iris classes with 4 different features. \n", "\n", "- [About the Iris dataset](http://sebastianraschka.com/Articles/2014_python_lda.html#about-the-iris-dataset)\n", "\n", "\n", "####Cross-validation\n", "Cross-validation is a statistical technique to estimate the prediction error rate by splitting the data into training, cross-validation, and test datasets. A prediction model is obtained using the training set, and model parameters are optimized by the cross-validation set, while the test set is held primarily for empirical error estimation. \n", "\n", "- Separate article in preparation\n", "\n", "####Feature Scaling and Standardization\n", "A data pre-processing step for re-scaling features from different measurements to match proportions of a standard normal distribution (unit variance centered at mean=0).\n", "\n", "- [About Feature Scaling and Normalization](http://sebastianraschka.com/Articles/2014_about_feature_scaling.html)\n", "\n", "####Principal Component Analysis (PCA)\n", "A linear transformation technique that is commonly used to project a dataset (without utilizing class labels) onto a new feature space or feature subspace (for dimensionality reduction) where the new component axes are the directions that maximize the variance/spread of the data.\n", "\n", "- [Implementing a Principal Component Analysis (PCA) in Python step by step](http://sebastianraschka.com/Articles/2014_pca_step_by_step.html)\n", "\n", "####Linear Discriminant Analysis (LDA)\n", "A linear transformation technique (related to Principal Component Analysis) that is commonly used to project a dataset onto a new feature space or feature subspace, where the new component axes maximize the spread between multiple classes, or for classification of data.\n", "\n", "- [Linear Discriminant Analysis bit by bit](http://sebastianraschka.com/Articles/2014_python_lda.html)\n", "\n", "####Naive Bayes classifier\n", "A classifier based on a statistical model (i.e., Bayes theorem: calculating posterior probabilities based on the prior probability and the so-called likelihood) in the field of pattern classification. Naive Bayes assumes that all attributes are conditionally independent, thereby, computing the likelihood is simplified to the product of the conditional probabilities of observing individual attributes given a particular class label.\n", "\n", "- Separate article in preparation\n", "\n", "\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Reading in the Iris dataset" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import pandas as pd\n", "\n", "df = pd.io.parsers.read_csv(\n", " filepath_or_buffer='https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', \n", " header=None, \n", " sep=',', \n", " )\n", "df.dropna(how=\"all\", inplace=True) # to drop the empty line at file-end\n", "\n", "feature_dict = {i:label for i,label in zip(\n", " range(4),\n", " ('sepal length in cm', \n", " 'sepal width in cm', \n", " 'petal length in cm', \n", " 'petal width in cm', ))}" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stderr", "text": [ "/Users/sebastian/miniconda3/envs/py34/lib/python3.4/site-packages/pandas/io/excel.py:626: UserWarning: Installed openpyxl is not supported at this time. Use >=1.6.1 and <2.0.0.\n", " .format(openpyxl_compat.start_ver, openpyxl_compat.stop_ver))\n" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since it is more convenient to work with numerical values, we will use the `LabelEncoder` from the scikit-learn library to convert the class labels into numbers: 1, 2, and 3." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sklearn.preprocessing import LabelEncoder\n", "\n", "X = df[[0,1,2,3]].values \n", "y = df[4].values\n", "\n", "enc = LabelEncoder()\n", "label_encoder = enc.fit(y)\n", "y = label_encoder.transform(y) + 1\n", "\n", "label_dict = {1: 'Setosa', 2: 'Versicolor', 3:'Virginica'}" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Exploratory visualization" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%matplotlib inline" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "from matplotlib import pyplot as plt\n", "import numpy as np\n", "import math\n", "\n", "fig, axes = plt.subplots(nrows=2, ncols=2, figsize=(12,6))\n", "\n", "for ax,cnt in zip(axes.ravel(), range(4)):\n", "\n", " # set bin sizes\n", " min_b = math.floor(np.min(X[:,cnt]))\n", " max_b = math.ceil(np.max(X[:,cnt]))\n", " bins = np.linspace(min_b, max_b, 25)\n", "\n", " # plottling the histograms\n", " for lab,col in zip(range(1,4), ('blue', 'red', 'green')):\n", " ax.hist(X[y==lab, cnt],\n", " color=col, \n", " label='class %s' %label_dict[lab], \n", " bins=bins,\n", " alpha=0.5,)\n", " ylims = ax.get_ylim()\n", "\n", " # plot annotation\n", " leg = ax.legend(loc='upper right', fancybox=True, fontsize=8)\n", " leg.get_frame().set_alpha(0.5)\n", " ax.set_ylim([0, max(ylims)+2])\n", " ax.set_xlabel(feature_dict[cnt])\n", " ax.set_title('Iris histogram #%s' %str(cnt+1))\n", "\n", " # hide axis ticks\n", " ax.tick_params(axis=\"both\", which=\"both\", bottom=\"off\", top=\"off\", \n", " labelbottom=\"on\", left=\"off\", right=\"off\", labelleft=\"on\")\n", "\n", " # remove axis spines\n", " ax.spines[\"top\"].set_visible(False) \n", " ax.spines[\"right\"].set_visible(False) \n", " ax.spines[\"bottom\"].set_visible(False) \n", " ax.spines[\"left\"].set_visible(False)\n", "\n", "axes[0][0].set_ylabel('count')\n", "axes[1][0].set_ylabel('count')\n", "\n", "fig.tight_layout()\n", "\n", "plt.show()" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Above, we used simple 1D-histograms as a quick exploratory tool to get a rough idea how the classes are separated for each particular feature. \n", "We can see that the petal dimensions (petal width and petal width) are much more useful features than the sepal dimensions, which have a large overlap between the 3 different Iris species. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Preparing a Test and Training dataset" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this step, we split our dataset into two subsets: A training dataset (60% of the samples) and a test dataset (40% of the samples from the original dataset). " ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sklearn.cross_validation import train_test_split\n", "\n", "X_train, X_test, y_train, y_test = train_test_split(X, y,\n", " test_size=0.40, random_state=12345)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 10 }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Cross-Validation and Pipelines" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is important to note that the test set should only be used once for evaluating the prediction error of a classifier after training it on the training dataset; repetitive evaluations of different models using the same test dataset would be prone to overfitting. \n", "A common approach to compare and evaluate different pre-processing techniques and models is cross-validation. Here, we will use a variant called \"k-fold cross-validation\" in order to compare different preprocessing steps and demonstrate the usefulness of a `Pipeline`.\n", "\n", "In k-fold cross-validation, the original training dataset is split into *k* different subsets (the so-called \"folds\") where 1 fold is retained for testing the classifier and the other k-1 folds are used for training.\n", "\n", "E.g., if we'd choose k=4 (4 folds) the classifier will be trained on the remaining using 3 different training set subsets and evaluated on the 4th fold (the test fold). This procedure is then repeated 4 times until every fold has been used as the test set once so that we can eventually calculate the average error rate of our model from the error rate of every iteration, which gives us an idea of how well our model generalizes (a more detailed article about different cross validation methods is in preparation).\n", "\n", "![](../../Images/cross-validation-001_small.png)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Custom Pipeline objects" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, after we successfully prepared our example dataset, let us come back to the pipelines. Pipelines, as we have heard before, are extremely useful in a cross-validation task in order to compare different models. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we can also write our own classes that can be used in such a pipeline. If we think [back to the histograms](#Exploratory-visualization) of our Iris dataset, one interesting exploration could be to select the features \"petal length\" and \"petal width\" and compare a classifier trained on this subset against classifiers that were trained on the whole dataset, or classifiers that were trained on datasets after dimensionality reduction (e.g., Linear Discriminant Analysis or Principal Component Analysis).\n", "\n", "Below, we will write a simple `ColumnSelector` that will return a subset of certain features (columns) from a NumPy array that represents our dataset.\n", "\n", "The requirement for a valid `Pipeline` object is that it responds to the `transform` method with exception of the last object (the final estimator), which has to respond to the `fit` function.\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "class ColumnSelector(object):\n", " \"\"\" A feature selector for scikit-learn's Pipeline class that returns\n", " specified columns from a numpy array.\n", " \n", " \"\"\"\n", " \n", " def __init__(self, cols):\n", " self.cols = cols\n", " \n", " def transform(self, X, y=None):\n", " return X[:, self.cols]\n", "\n", " def fit(self, X, y=None):\n", " return self" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 11 }, { "cell_type": "markdown", "metadata": {}, "source": [ "I thought that it was worthwhile to create a central module for such helper functions and classes ([https://github.com/rasbt/mlxtend](https://github.com/rasbt/mlxtend)) from which they could not only be easily imported but also collected, documented, and optimized. I am happy about any suggestions, ideas, and contributions!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Running the cross-validation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For a simple example, let us do cross-validation to compare different preprocessing steps for training a naive Bayes classifier.\n", "\n", "- on the whole feature set\n", "- on a 2D feature subset consisting of the features \"petal width\" and \"petal length\"\n", "- on a 2D subset after dimensionality reduction via Principal Component Analysis\n", "- on a 2D subset after dimensionality reduction via Linear Discriminant Analysis" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sklearn.cross_validation import cross_val_score, KFold\n", "from sklearn.pipeline import Pipeline\n", "from sklearn.naive_bayes import GaussianNB\n", "from sklearn.preprocessing import StandardScaler\n", "from sklearn.lda import LDA\n", "from sklearn.decomposition import PCA\n", "\n", "clf_all = Pipeline(steps=[\n", " ('scaler', StandardScaler()), \n", " ('classifier', GaussianNB()) \n", " ])\n", "\n", "clf_petal = Pipeline(steps=[\n", " ('scaler', StandardScaler()),\n", " ('reduce_dim', ColumnSelector(cols=(2,3))), \n", " ('classifier', GaussianNB()) \n", " ]) \n", "\n", "clf_pca = Pipeline(steps=[\n", " ('scaler', StandardScaler()), \n", " ('reduce_dim', PCA(n_components=2)),\n", " ('classifier', GaussianNB()) \n", " ])\n", "\n", "clf_lda = Pipeline(steps=[\n", " ('scaler', StandardScaler()), \n", " ('reduce_dim', LDA(n_components=2)),\n", " ('classifier', GaussianNB()) \n", " ])\n", "\n", "# Constructing the k-fold cross validation iterator (k=5) \n", "\n", "cv = KFold(n=X_train.shape[0], # total number of samples\n", " n_folds=5, # number of folds the dataset is divided into\n", " random_state=12345)\n", "\n", "scores = [\n", " cross_val_score(clf, X_train, y_train, cv=cv, scoring='accuracy')\n", " for clf in [clf_all, clf_petal, clf_pca, clf_lda]\n", " ]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "for score,label in zip(scores, \n", " ['all attributes', \n", " 'Petal dimensions (column 3 & 4)',\n", " 'PCA dim. red. (n=2)', \n", " 'LDA dim. red. (n=2)', \n", " ]\n", " ):\n", " print(\"Accuracy: {:.2%} (+/- {:.2%}), {:}\".format(score.mean(), score.std(), label))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Accuracy: 94.44% (+/- 3.51%), all attributes\n", "Accuracy: 94.44% (+/- 6.09%), Petal dimensions (column 3 & 4)\n", "Accuracy: 85.56% (+/- 9.69%), PCA dim. red. (n=2)\n", "Accuracy: 96.67% (+/- 4.44%), LDA dim. red. (n=2)\n" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In general, the prediction accuracy is calculated as the number of correct classification divided by the number of total classification. In this case, the accuracies displayed above represent the averages from all 5 iterations in a cross-validation procedure.\n", "\n", "Here, the accuracies differ only slightly. Interestingly, the prediction accuracies are the same for the whole dataset and our feature subset that consists of only the petal widths and lengths. This indicates that we might lose minimum information by removing the sepal measurements (but note that the standard error increased). LDA tends to outperform PCA in this case, which is not unexpected: In contrast to PCA, LDA tries to maximize class separability for a supervised dataset." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "
" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Training the Naive Bayes classifier" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "[[back to overview](#Sections)]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Conviniently, we can reuse the pipeline objects from our cross-validation above to train the classifier on the whole training dataset and evaluate its performance on the separate test dataset. \n", "Since the LDA-approach for preprocessing seemed to have performed best in cross validation, let us have a look how it performs on the \"real\" test dataset." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sklearn import metrics\n", "\n", "clf_lda.fit(X_train, y_train)\n", "pred_test = clf_lda.predict(X_test)\n", "\n", "print('Prediction accuracy for the test dataset')\n", "print('{:.2%}'.format(metrics.accuracy_score(y_test, pred_test)))\n", "\n", "print('\\nConfusion Matrix of the Naive Bayes classifier')\n", "print(metrics.confusion_matrix(y_test, clf_lda.predict(X_test)))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "Prediction accuracy for the test dataset\n", "100.00%\n", "\n", "Confusion Matrix of the Naive Bayes classifier\n", "[[21 0 0]\n", " [ 0 22 0]\n", " [ 0 0 17]]\n" ] } ], "prompt_number": 14 } ], "metadata": {} } ] }