├── .gitignore ├── DICOM_Conversion ├── DICOM_2_NIFTI │ └── dcmstack_Method.ipynb └── DSO_2_NIFTI │ └── dcmqi_Method.ipynb ├── LICENSE ├── README.md ├── _config.yml ├── index.md ├── tutorial_1 ├── .ipynb_checkpoints │ └── getting_started-checkpoint.ipynb ├── getting_started.ipynb ├── opened.png └── retina.tif ├── tutorial_2 ├── .ipynb_checkpoints │ └── intro_to_ML-checkpoint.ipynb ├── diabetes.csv ├── intro_to_ML.ipynb └── pima.png ├── tutorial_3 ├── .gitignore ├── .ipynb_checkpoints │ ├── ML_for_images-checkpoint.ipynb │ └── images_as_tensors-checkpoint.ipynb ├── ML_for_images.ipynb ├── mnist_glossary.png ├── mnist_sample.png └── mnist_sample_2.png ├── tutorial_4 ├── .gitignore └── images_tensors_convolutions.ipynb ├── tutorial_5 ├── .gitignore ├── BRATS.png ├── build_your_own_unet.ipynb ├── colab.ipynb └── u-net-architecture.png ├── tutorial_6 └── segmentation_network.ipynb └── tutorial_7 ├── .gitignore ├── .ipynb_checkpoints ├── Unsupervised machine learning-checkpoint.ipynb └── Untitled-checkpoint.ipynb ├── Unsupervised machine learning.ipynb ├── __pycache__ └── models.cpython-36.pyc └── models.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.h5 2 | -------------------------------------------------------------------------------- /DICOM_Conversion/DICOM_2_NIFTI/dcmstack_Method.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Converting DICOM Files to NIfTI Format Using dcmstack \n", 8 | "\n", 9 | "\n", 10 | "This tutorial will teach you how to convert DICOM files to Nifti format using the \"dcmstack\" Python package. DICOM is an effecient and flexible format for storing pixel data and metadata tags for medical images. Nifti is a another popular imaging format that is more limited than DICOM when it comes to metadata and segmentation features, but is well-supported in packages in Python ([nibabel](http://nipy.org/nibabel/)), Matlab ([dicm2nii](https://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter--nifti-tool-and-viewer)), and R ([oro.nifti](https://cran.r-project.org/web/packages/oro.nifti/oro.nifti.pdf)). [dcmstack](https://github.com/QIICR/dcmqi) is a Python library used to convert between the two.\n", 11 | "\n", 12 | "Much of this tutorial is lifted directly from the dcmstack documentation pages, which you can find here:\n", 13 | "\n", 14 | "http://dcmstack.readthedocs.io/en/v0.6.1/" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Installing dcmstack\n", 22 | "\n", 23 | "To install dcmstack, you should follow the instructions at https://github.com/moloney/dcmstack. First, you will need to download the package from the Github page. You can do this by clicking on the green \"Clone or download\" button at the top right of the page. If you are already familiar with Git, you can simply clone the repository using the following line on the command prompt:" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": null, 29 | "metadata": { 30 | "collapsed": true 31 | }, 32 | "outputs": [], 33 | "source": [ 34 | "git clone https://github.com/moloney/dcmstack " 35 | ] 36 | }, 37 | { 38 | "cell_type": "markdown", 39 | "metadata": {}, 40 | "source": [ 41 | "After downloading and if necessary unzipping the package, you can install the package by running:" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": null, 47 | "metadata": { 48 | "collapsed": true 49 | }, 50 | "outputs": [], 51 | "source": [ 52 | "python setup.py install " 53 | ] 54 | }, 55 | { 56 | "cell_type": "markdown", 57 | "metadata": {}, 58 | "source": [ 59 | "Make sure to run this command in the same directory that you downloaded your package into." 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "## Converting DICOMs to NIfTI using Python\n", 67 | "\n", 68 | "Once you have dcmstack installed, you can use it like any Python library. Below is a Python function one can use to output a nifti file and a JSON file with imaging data and DICOM header data, respectively." 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": null, 74 | "metadata": { 75 | "collapsed": true 76 | }, 77 | "outputs": [], 78 | "source": [ 79 | "import dcmstack\n", 80 | "import glob\n", 81 | "import os\n", 82 | "\n", 83 | "def dcmstack_process(input_directory, nii_output_file, metadata_output_file):\n", 84 | "\n", 85 | " # Load all of the .dcm files found in the provided directory.\n", 86 | " src_dcms = glob.glob(os.path.join(input_directory, '*.dcm'))\n", 87 | "\n", 88 | " # Use DICOM stack to retrieve the first imaging series found in that folder.\n", 89 | " # Note that if your folder contains multiple imaging series, this function\n", 90 | " # will only return one of them.\n", 91 | " stacks = dcmstack.parse_and_stack(src_dcms)\n", 92 | " stack = stacks.values()[0]\n", 93 | "\n", 94 | " # Write your imaging series to a NIfTI file using to_filename, and write\n", 95 | " # your metadata to a json file using .meta_ext.to_json()\n", 96 | " nii = stack.to_nifti_wrapper()\n", 97 | " with open(metadata_output_file, 'wb') as metadata_file:\n", 98 | " metadata_file.write(nii.meta_ext.to_json())\n", 99 | " nii.to_filename(nii_output_file)" 100 | ] 101 | }, 102 | { 103 | "cell_type": "markdown", 104 | "metadata": {}, 105 | "source": [ 106 | "dcmstack_process take an input_directory of DICOM files, presumed to have the \".dcm\" extension, and outputs two files. The first is nii_output_file, which is in NIfTI format. The second is metadata_output_file, which should be a \".json\" file containing all of the DICOM tags in the given imaging series." 107 | ] 108 | }, 109 | { 110 | "cell_type": "markdown", 111 | "metadata": {}, 112 | "source": [ 113 | "## Converting DICOMs to NIfTI from the Command Prompt\n", 114 | "\n", 115 | "Installing dcmstack will also give you access to a new command prompt tool, \"dcmstack\". You can replicate the behavior of the Python function above with the following command from the command prompt:" 116 | ] 117 | }, 118 | { 119 | "cell_type": "code", 120 | "execution_count": null, 121 | "metadata": { 122 | "collapsed": true 123 | }, 124 | "outputs": [], 125 | "source": [ 126 | "dcmstack ./INPUT_DICOM_DATA -o ./OUTPUT_NIFTI_FOLDER/test_nifti -d" 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "This will find DICOM files from the ./INPUT_DICOM_DATA directory, and output two files: test_nifti.nii.gz, and test_nifti.json. The former will contain imaging data, while the later will contain DICOM tags in JSON format. dcmstack has many other features, which can be explored in d" 134 | ] 135 | }, 136 | { 137 | "cell_type": "markdown", 138 | "metadata": {}, 139 | "source": [ 140 | "## Converting NIfTI Files to Numpy Arrays using Nibabel\n", 141 | "\n", 142 | "Often, you will want to operate directly on the image data stored in NIfTI files. Below, I will show you how to do this Python using the nibabel package. [nibabel](http://nipy.org/nibabel/) can be installed using the pip package manager in Python by entering the following command on the command prompt:" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": null, 148 | "metadata": { 149 | "collapsed": true 150 | }, 151 | "outputs": [], 152 | "source": [ 153 | "pip install nibabel" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "We can then use the nibabel package to write a short function that will convert incoming nifti files into numpy arrays. See the code below:" 161 | ] 162 | }, 163 | { 164 | "cell_type": "code", 165 | "execution_count": null, 166 | "metadata": { 167 | "collapsed": true 168 | }, 169 | "outputs": [], 170 | "source": [ 171 | "import nibabel as nib\n", 172 | "\n", 173 | "def nifti_2_numpy(input_filepath):\n", 174 | " nifti = nib.load(input_filepath)\n", 175 | " return nifti.get_data()" 176 | ] 177 | }, 178 | { 179 | "cell_type": "markdown", 180 | "metadata": {}, 181 | "source": [ 182 | "nifti_2_numpy return a numpy array of the imaging data from a NIfTI file located at input_filepath. Note that the numpy array returned by this function may not be oriented in the way you expect. To correctly determine the orientation of your array, you must use extract the affine matrix from your NIfTI file. You can do that with a function like this: " 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": { 189 | "collapsed": true 190 | }, 191 | "outputs": [], 192 | "source": [ 193 | "import nibabel as nib\n", 194 | "\n", 195 | "def nifti_2_numpy_with_affine(input_filepath):\n", 196 | " nifti = nib.load(input_filepath)\n", 197 | " return nifti.get_data(), nifti.affine" 198 | ] 199 | }, 200 | { 201 | "cell_type": "markdown", 202 | "metadata": {}, 203 | "source": [ 204 | "nifti_2_numpy_with_affine return a tuple of (data, affine) generated from a NIfTI file located at input_filepath.\n", 205 | "\n", 206 | "And that's all you need to know for this tutorial! If you run into any problems with this tutorial, or the code presented here, please submit an issue on our Github page here: https://github.com/QTIM-Lab/qtim_Tutorials/issues" 207 | ] 208 | } 209 | ], 210 | "metadata": { 211 | "anaconda-cloud": {}, 212 | "kernelspec": { 213 | "display_name": "Python [default]", 214 | "language": "python", 215 | "name": "python2" 216 | }, 217 | "language_info": { 218 | "codemirror_mode": { 219 | "name": "ipython", 220 | "version": 2 221 | }, 222 | "file_extension": ".py", 223 | "mimetype": "text/x-python", 224 | "name": "python", 225 | "nbconvert_exporter": "python", 226 | "pygments_lexer": "ipython2", 227 | "version": "2.7.12" 228 | } 229 | }, 230 | "nbformat": 4, 231 | "nbformat_minor": 1 232 | } 233 | -------------------------------------------------------------------------------- /DICOM_Conversion/DSO_2_NIFTI/dcmqi_Method.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Converting DICOM Segmentation Objects (DSOs) to NIfTI Format Using dcmqi \n", 8 | "\n", 9 | "\n", 10 | "This tutorial will teach you how to convert DICOM Segmentation Objects (DSOs) to Nifti format using the \"dcmqi\" package. DSO is an effecient and flexible format for storing segmented regions and associated metadata in medical imaging data. Nifti is a another popular imaging format that is more limited than DSOs when it comes to metadata and segmentation features, but is well-supported in packages in Python ([nibabel](http://nipy.org/nibabel/)), Matlab ([dicm2nii](https://www.mathworks.com/matlabcentral/fileexchange/42997-dicom-to-nifti-converter--nifti-tool-and-viewer)), and R ([oro.nifti](https://cran.r-project.org/web/packages/oro.nifti/oro.nifti.pdf)). [dcmqi](https://github.com/QIICR/dcmqi) is a library used for quantiative image research, and has many utilities for converting to and from DICOM image formats to other image formats.\n", 11 | "\n", 12 | "Much of this tutorial is lifted directly from the dcmqi documentation pages, which you can find here:\n", 13 | "\n", 14 | "https://qiicr.gitbooks.io/dcmqi-guide/" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "## Installing dcmqi\n", 22 | "\n", 23 | "To install dcmqi, you should download and unpack the appropriate binary files for your operating system at this link:\n", 24 | "\n", 25 | "https://qiicr.gitbooks.io/dcmqi-guide/quick-start.html\n", 26 | "\n", 27 | "Also, if you are familiar with Docker, you can also download a dcmqi Docker container from that link." 28 | ] 29 | }, 30 | { 31 | "cell_type": "markdown", 32 | "metadata": {}, 33 | "source": [ 34 | "## Converting DSOs\n", 35 | "\n", 36 | "The following instructions are following the documentation located at this link:\n", 37 | "\n", 38 | "https://qiicr.gitbooks.io/dcmqi-guide/user_guide/segimage2itkimage.html\n", 39 | "\n", 40 | "The command we're going to use the segimage2itkimage command. Note that you will need to add you binary folder (\"bin\") to your system PATH in order for the vanilla command \"segimage2itkimage\" to work. See these links for more information about how to add folders to your path: [Mac and Linux](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path), [Windows](https://www.howtogeek.com/118594/how-to-edit-your-system-path-for-easy-command-line-access/). If you don't want to modify your path, you can still run your command by replacing \"segimage2itkimage\" with the full path to your bin folder, e.g. C:/users/example_user/Software/dcmqi/bin/segimage2itkimage with \".exe\" on windows.\n", 41 | "\n", 42 | "Once you have your path figured out, an example command, entered on the command prompt, might look like:" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": null, 48 | "metadata": { 49 | "collapsed": true 50 | }, 51 | "outputs": [], 52 | "source": [ 53 | "segimage2itkimage --outputType nii --prefix my_NII_file --outputDirectory ./Test_Data --inputDICOM ./Test_Data/my_DSO_file.dcm" 54 | ] 55 | }, 56 | { 57 | "cell_type": "markdown", 58 | "metadata": {}, 59 | "source": [ 60 | "This will take the file located at ./Test_Data/my_DSO_file.dcm and convert it to nifti (\\*.nii) format. It will be outputed in the ./Test_Data directory with the filename (a.k.a. prefix), \"converted\". It will output one Nifti file for each segmentation at each label value of the segmentation. For example, if you have three segmentations with values 1, 2, and 3, then output files will be titled my_NII_file-1.nii, my_NII_file-2.nii, my_NII_file-3.nii. A metadata file with information taken from the original DICOM will also be generated in JSON format, with the filename my_NII_file.json." 61 | ] 62 | }, 63 | { 64 | "cell_type": "markdown", 65 | "metadata": {}, 66 | "source": [ 67 | "## Python Wrapper\n", 68 | "\n", 69 | "I often like to wrap command-line utilities in Python functions, so that I can easily integrate them with existing Python workflows. Below is an example of how you might do so with this dcmqi command, using the subprocess module in Python." 70 | ] 71 | }, 72 | { 73 | "cell_type": "code", 74 | "execution_count": null, 75 | "metadata": { 76 | "collapsed": true 77 | }, 78 | "outputs": [], 79 | "source": [ 80 | "import subprocess\n", 81 | "\n", 82 | "def segimage2itkimage(outputType, inputDICOM, outputDirectory, prefix, command_line='C:/Users/abeers/Documents/Software/dcmqi-1.0.5-win64-20171213-e5c3934/bin/segimage2itkimage.exe'):\n", 83 | "\n", 84 | " full_command = ' '.join([command_line, '--outputType', outputType, '--outputDirectory', outputDirectory, '--prefix', prefix, '--inputDICOM', inputDICOM])\n", 85 | " subprocess.call(full_command, shell=True)" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "## Converting NIfTI Files to Numpy Arrays using Nibabel\n", 93 | "\n", 94 | "Often, you will want to operate directly on the image data stored in NIfTI files. Below, I will show you how to do this Python using the nibabel package. [nibabel](http://nipy.org/nibabel/) can be installed using the pip package manager in Python by entering the following command on the command prompt:" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": null, 100 | "metadata": { 101 | "collapsed": true 102 | }, 103 | "outputs": [], 104 | "source": [ 105 | "pip install nibabel" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "We can then use the nibabel package to write a short function that will convert incoming nifti files into numpy arrays. See the code below:" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": null, 118 | "metadata": { 119 | "collapsed": true 120 | }, 121 | "outputs": [], 122 | "source": [ 123 | "import nibabel as nib\n", 124 | "\n", 125 | "def nifti_2_numpy(input_filepath):\n", 126 | " nifti = nib.load(input_filepath)\n", 127 | " return nifti.get_data()" 128 | ] 129 | }, 130 | { 131 | "cell_type": "markdown", 132 | "metadata": {}, 133 | "source": [ 134 | "nifti_2_numpy return a numpy array of the imaging data from a NIfTI file located at input_filepath. Note that the numpy array returned by this function may not be oriented in the way you expect. To correctly determine the orientation of your array, you must use extract the affine matrix from your NIfTI file. You can do that with a function like this: " 135 | ] 136 | }, 137 | { 138 | "cell_type": "code", 139 | "execution_count": null, 140 | "metadata": { 141 | "collapsed": true 142 | }, 143 | "outputs": [], 144 | "source": [ 145 | "import nibabel as nib\n", 146 | "\n", 147 | "def nifti_2_numpy_with_affine(input_filepath):\n", 148 | " nifti = nib.load(input_filepath)\n", 149 | " return nifti.get_data(), nifti.affine" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "nifti_2_numpy_with_affine return a tuple of (data, affine) generated from a NIfTI file located at input_filepath.\n", 157 | "\n", 158 | "And that's all you need to know for this tutorial! If you run into any problems with this tutorial, or the code presented here, please submit an issue on our Github page here: https://github.com/QTIM-Lab/qtim_Tutorials/issues" 159 | ] 160 | } 161 | ], 162 | "metadata": { 163 | "anaconda-cloud": {}, 164 | "kernelspec": { 165 | "display_name": "Python [default]", 166 | "language": "python", 167 | "name": "python2" 168 | }, 169 | "language_info": { 170 | "codemirror_mode": { 171 | "name": "ipython", 172 | "version": 2 173 | }, 174 | "file_extension": ".py", 175 | "mimetype": "text/x-python", 176 | "name": "python", 177 | "nbconvert_exporter": "python", 178 | "pygments_lexer": "ipython2", 179 | "version": "2.7.12" 180 | } 181 | }, 182 | "nbformat": 4, 183 | "nbformat_minor": 1 184 | } 185 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 QTIM Lab 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # QTIM Tutorials 2 | Jupyter notebooks and other tutorials for medical imaging and deep learning, courtesy of the QTIM lab. 3 | 4 | ## Prerequisites 5 | 6 | - Git - to download this repository 7 | - Python 3 distribution. We recommend Anaconda: https://www.anaconda.com/download/ 8 | - Spyder 3 (Python IDE) - this comes with Anaconda, useful for larger projects 9 | - Jupyter - also comes with Anaconda 10 | 11 | ## Dependencies 12 | - scikit-image - ```pip install scikit-image``` 13 | - scikit-learn - ```pip install scikit-learn``` 14 | - TensorFlow 1.5+ - ```pip install tensorflow``` 15 | - Keras 2+ - ```pip install keras``` 16 | 17 | If you have an NVIDIA GPU and would like to use it, then you'll need to also install: 18 | - Up-to-date NVIDIA drivers 19 | - NVIDIA CUDA toolkit 20 | - CuDNN 21 | - tensorflow-gpu -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /index.md: -------------------------------------------------------------------------------- 1 | # Welcome to QTIM Tutorials! 2 | 3 | The purpose of these tutorials is to provide a broad overview of techniques for applying machine learning to medical images. 4 | 5 | We focus on building a set of skills to make you an effective machine learning practitioner with a good understanding of the underlying theory: 6 | 7 | - Python programming: variables, data types, data structures, control flow, I/O 8 | - Project management: data organization, modular code design, version control 9 | - Data science: tabular data, feature selection, normalization, plotting 10 | - Image processing: multi-dimensional arrays, thresholding, histograms, morphological operations 11 | - Machine learning models: decision trees, random forests, support vector machines, logistic regression, multi-layer perceptrons 12 | - Deep learning: convolutional neural networks, image classification, image segmentation, feature visualization 13 | 14 | ## Requirements 15 | 16 | The tutorials are designed such that anyone with an interest in applying ML to medical images can follow along, regardless of programming experience. However, the following prior experience would be useful: 17 | 18 | - Rudimentary programming skills in a high-level language, such as Python or MATLAB 19 | - Using the terminal to navigate your computer's file system and run simple commands 20 | - A basic understanding of linear algebra, particularly operations between scalars, vectors and matrices 21 | - Familiarity with basic image processing techniques 22 | 23 | ## Getting started 24 | All of our tutorials are written in Python 3 as Jupyter Notebooks. To get started, follow the installation steps below: 25 | 26 | 1. Download and install Python 3.6 (or greater). We highly recommend [Anaconda](https://www.anaconda.com/download/), which includes many of the dependencies you'll need (including Jupyter). The process will vary depending on platform, but is usually straightfoward. 27 | 2. Download the tutorial notebooks from [here](https://github.com/QTIM-Lab/qtim_Tutorials). We highly recommend using Git, as the tutorials will be updated as time goes on. If you're unfamilar with git, just download and unpack the code as a [zip file](https://github.com/QTIM-Lab/qtim_Tutorials/archive/master.zip). 28 | 3. In a terminal, install the following additional dependencies using `pip` (comes with Anaconda): 29 | * `pip install tensorflow` 30 | * `pip install keras` 31 | 32 | ## Running a tutorial 33 | 1. In a terminal, navigate to the *qtim_Tutorials* folder you cloned/unzipped in step 2 above. 34 | 2. Run the command `jupyter notebook`. A new browser window/tab should appear. 35 | 3. Click on the tutorial folder you want to run, and then click the *.ipynb* file in that folder. 36 | 4. To run a chunk of code, click in a box and hit Ctrl + Enter (or the 'Run' button in the top panel). 37 | 38 | ## Troubleshooting 39 | If you happen to hit some errors, then consider the following: 40 | * Code blocks often rely on each other, and must be run in order (top to bottom). Be sure to go back and check all preceding blocks have been run. 41 | * The `[*]` beside a code block indicates that the code is still running. You'll need to wait until it finishes before moving on. 42 | * Be sure to read the descriptions as you go; some steps involve downloading external data. 43 | * File paths can be confusing for first-time coders. The easiest solution is to put any downloaded data in the same folder as the tutorial you're running, that way you can reference the data by folder name, rather than */lots/of/nested/directories/...* 44 | * If all else fails, [Stack Overflow](https://stackoverflow.com/search?q=) is your friend :) 45 | 46 | ## Contact (@mgh.harvard.edu) 47 | James Brown: jbrown97, Andrew Beers: abeers 48 | 49 | -------------------------------------------------------------------------------- /tutorial_1/opened.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_1/opened.png -------------------------------------------------------------------------------- /tutorial_1/retina.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_1/retina.tif -------------------------------------------------------------------------------- /tutorial_2/diabetes.csv: -------------------------------------------------------------------------------- 1 | Pregnancies,Glucose,BloodPressure,SkinThickness,Insulin,BMI,DiabetesPedigreeFunction,Age,Outcome 2 | 6,148,72,35,0,33.6,0.627,50,1 3 | 1,85,66,29,0,26.6,0.351,31,0 4 | 8,183,64,0,0,23.3,0.672,32,1 5 | 1,89,66,23,94,28.1,0.167,21,0 6 | 0,137,40,35,168,43.1,2.288,33,1 7 | 5,116,74,0,0,25.6,0.201,30,0 8 | 3,78,50,32,88,31,0.248,26,1 9 | 10,115,0,0,0,35.3,0.134,29,0 10 | 2,197,70,45,543,30.5,0.158,53,1 11 | 8,125,96,0,0,0,0.232,54,1 12 | 4,110,92,0,0,37.6,0.191,30,0 13 | 10,168,74,0,0,38,0.537,34,1 14 | 10,139,80,0,0,27.1,1.441,57,0 15 | 1,189,60,23,846,30.1,0.398,59,1 16 | 5,166,72,19,175,25.8,0.587,51,1 17 | 7,100,0,0,0,30,0.484,32,1 18 | 0,118,84,47,230,45.8,0.551,31,1 19 | 7,107,74,0,0,29.6,0.254,31,1 20 | 1,103,30,38,83,43.3,0.183,33,0 21 | 1,115,70,30,96,34.6,0.529,32,1 22 | 3,126,88,41,235,39.3,0.704,27,0 23 | 8,99,84,0,0,35.4,0.388,50,0 24 | 7,196,90,0,0,39.8,0.451,41,1 25 | 9,119,80,35,0,29,0.263,29,1 26 | 11,143,94,33,146,36.6,0.254,51,1 27 | 10,125,70,26,115,31.1,0.205,41,1 28 | 7,147,76,0,0,39.4,0.257,43,1 29 | 1,97,66,15,140,23.2,0.487,22,0 30 | 13,145,82,19,110,22.2,0.245,57,0 31 | 5,117,92,0,0,34.1,0.337,38,0 32 | 5,109,75,26,0,36,0.546,60,0 33 | 3,158,76,36,245,31.6,0.851,28,1 34 | 3,88,58,11,54,24.8,0.267,22,0 35 | 6,92,92,0,0,19.9,0.188,28,0 36 | 10,122,78,31,0,27.6,0.512,45,0 37 | 4,103,60,33,192,24,0.966,33,0 38 | 11,138,76,0,0,33.2,0.42,35,0 39 | 9,102,76,37,0,32.9,0.665,46,1 40 | 2,90,68,42,0,38.2,0.503,27,1 41 | 4,111,72,47,207,37.1,1.39,56,1 42 | 3,180,64,25,70,34,0.271,26,0 43 | 7,133,84,0,0,40.2,0.696,37,0 44 | 7,106,92,18,0,22.7,0.235,48,0 45 | 9,171,110,24,240,45.4,0.721,54,1 46 | 7,159,64,0,0,27.4,0.294,40,0 47 | 0,180,66,39,0,42,1.893,25,1 48 | 1,146,56,0,0,29.7,0.564,29,0 49 | 2,71,70,27,0,28,0.586,22,0 50 | 7,103,66,32,0,39.1,0.344,31,1 51 | 7,105,0,0,0,0,0.305,24,0 52 | 1,103,80,11,82,19.4,0.491,22,0 53 | 1,101,50,15,36,24.2,0.526,26,0 54 | 5,88,66,21,23,24.4,0.342,30,0 55 | 8,176,90,34,300,33.7,0.467,58,1 56 | 7,150,66,42,342,34.7,0.718,42,0 57 | 1,73,50,10,0,23,0.248,21,0 58 | 7,187,68,39,304,37.7,0.254,41,1 59 | 0,100,88,60,110,46.8,0.962,31,0 60 | 0,146,82,0,0,40.5,1.781,44,0 61 | 0,105,64,41,142,41.5,0.173,22,0 62 | 2,84,0,0,0,0,0.304,21,0 63 | 8,133,72,0,0,32.9,0.27,39,1 64 | 5,44,62,0,0,25,0.587,36,0 65 | 2,141,58,34,128,25.4,0.699,24,0 66 | 7,114,66,0,0,32.8,0.258,42,1 67 | 5,99,74,27,0,29,0.203,32,0 68 | 0,109,88,30,0,32.5,0.855,38,1 69 | 2,109,92,0,0,42.7,0.845,54,0 70 | 1,95,66,13,38,19.6,0.334,25,0 71 | 4,146,85,27,100,28.9,0.189,27,0 72 | 2,100,66,20,90,32.9,0.867,28,1 73 | 5,139,64,35,140,28.6,0.411,26,0 74 | 13,126,90,0,0,43.4,0.583,42,1 75 | 4,129,86,20,270,35.1,0.231,23,0 76 | 1,79,75,30,0,32,0.396,22,0 77 | 1,0,48,20,0,24.7,0.14,22,0 78 | 7,62,78,0,0,32.6,0.391,41,0 79 | 5,95,72,33,0,37.7,0.37,27,0 80 | 0,131,0,0,0,43.2,0.27,26,1 81 | 2,112,66,22,0,25,0.307,24,0 82 | 3,113,44,13,0,22.4,0.14,22,0 83 | 2,74,0,0,0,0,0.102,22,0 84 | 7,83,78,26,71,29.3,0.767,36,0 85 | 0,101,65,28,0,24.6,0.237,22,0 86 | 5,137,108,0,0,48.8,0.227,37,1 87 | 2,110,74,29,125,32.4,0.698,27,0 88 | 13,106,72,54,0,36.6,0.178,45,0 89 | 2,100,68,25,71,38.5,0.324,26,0 90 | 15,136,70,32,110,37.1,0.153,43,1 91 | 1,107,68,19,0,26.5,0.165,24,0 92 | 1,80,55,0,0,19.1,0.258,21,0 93 | 4,123,80,15,176,32,0.443,34,0 94 | 7,81,78,40,48,46.7,0.261,42,0 95 | 4,134,72,0,0,23.8,0.277,60,1 96 | 2,142,82,18,64,24.7,0.761,21,0 97 | 6,144,72,27,228,33.9,0.255,40,0 98 | 2,92,62,28,0,31.6,0.13,24,0 99 | 1,71,48,18,76,20.4,0.323,22,0 100 | 6,93,50,30,64,28.7,0.356,23,0 101 | 1,122,90,51,220,49.7,0.325,31,1 102 | 1,163,72,0,0,39,1.222,33,1 103 | 1,151,60,0,0,26.1,0.179,22,0 104 | 0,125,96,0,0,22.5,0.262,21,0 105 | 1,81,72,18,40,26.6,0.283,24,0 106 | 2,85,65,0,0,39.6,0.93,27,0 107 | 1,126,56,29,152,28.7,0.801,21,0 108 | 1,96,122,0,0,22.4,0.207,27,0 109 | 4,144,58,28,140,29.5,0.287,37,0 110 | 3,83,58,31,18,34.3,0.336,25,0 111 | 0,95,85,25,36,37.4,0.247,24,1 112 | 3,171,72,33,135,33.3,0.199,24,1 113 | 8,155,62,26,495,34,0.543,46,1 114 | 1,89,76,34,37,31.2,0.192,23,0 115 | 4,76,62,0,0,34,0.391,25,0 116 | 7,160,54,32,175,30.5,0.588,39,1 117 | 4,146,92,0,0,31.2,0.539,61,1 118 | 5,124,74,0,0,34,0.22,38,1 119 | 5,78,48,0,0,33.7,0.654,25,0 120 | 4,97,60,23,0,28.2,0.443,22,0 121 | 4,99,76,15,51,23.2,0.223,21,0 122 | 0,162,76,56,100,53.2,0.759,25,1 123 | 6,111,64,39,0,34.2,0.26,24,0 124 | 2,107,74,30,100,33.6,0.404,23,0 125 | 5,132,80,0,0,26.8,0.186,69,0 126 | 0,113,76,0,0,33.3,0.278,23,1 127 | 1,88,30,42,99,55,0.496,26,1 128 | 3,120,70,30,135,42.9,0.452,30,0 129 | 1,118,58,36,94,33.3,0.261,23,0 130 | 1,117,88,24,145,34.5,0.403,40,1 131 | 0,105,84,0,0,27.9,0.741,62,1 132 | 4,173,70,14,168,29.7,0.361,33,1 133 | 9,122,56,0,0,33.3,1.114,33,1 134 | 3,170,64,37,225,34.5,0.356,30,1 135 | 8,84,74,31,0,38.3,0.457,39,0 136 | 2,96,68,13,49,21.1,0.647,26,0 137 | 2,125,60,20,140,33.8,0.088,31,0 138 | 0,100,70,26,50,30.8,0.597,21,0 139 | 0,93,60,25,92,28.7,0.532,22,0 140 | 0,129,80,0,0,31.2,0.703,29,0 141 | 5,105,72,29,325,36.9,0.159,28,0 142 | 3,128,78,0,0,21.1,0.268,55,0 143 | 5,106,82,30,0,39.5,0.286,38,0 144 | 2,108,52,26,63,32.5,0.318,22,0 145 | 10,108,66,0,0,32.4,0.272,42,1 146 | 4,154,62,31,284,32.8,0.237,23,0 147 | 0,102,75,23,0,0,0.572,21,0 148 | 9,57,80,37,0,32.8,0.096,41,0 149 | 2,106,64,35,119,30.5,1.4,34,0 150 | 5,147,78,0,0,33.7,0.218,65,0 151 | 2,90,70,17,0,27.3,0.085,22,0 152 | 1,136,74,50,204,37.4,0.399,24,0 153 | 4,114,65,0,0,21.9,0.432,37,0 154 | 9,156,86,28,155,34.3,1.189,42,1 155 | 1,153,82,42,485,40.6,0.687,23,0 156 | 8,188,78,0,0,47.9,0.137,43,1 157 | 7,152,88,44,0,50,0.337,36,1 158 | 2,99,52,15,94,24.6,0.637,21,0 159 | 1,109,56,21,135,25.2,0.833,23,0 160 | 2,88,74,19,53,29,0.229,22,0 161 | 17,163,72,41,114,40.9,0.817,47,1 162 | 4,151,90,38,0,29.7,0.294,36,0 163 | 7,102,74,40,105,37.2,0.204,45,0 164 | 0,114,80,34,285,44.2,0.167,27,0 165 | 2,100,64,23,0,29.7,0.368,21,0 166 | 0,131,88,0,0,31.6,0.743,32,1 167 | 6,104,74,18,156,29.9,0.722,41,1 168 | 3,148,66,25,0,32.5,0.256,22,0 169 | 4,120,68,0,0,29.6,0.709,34,0 170 | 4,110,66,0,0,31.9,0.471,29,0 171 | 3,111,90,12,78,28.4,0.495,29,0 172 | 6,102,82,0,0,30.8,0.18,36,1 173 | 6,134,70,23,130,35.4,0.542,29,1 174 | 2,87,0,23,0,28.9,0.773,25,0 175 | 1,79,60,42,48,43.5,0.678,23,0 176 | 2,75,64,24,55,29.7,0.37,33,0 177 | 8,179,72,42,130,32.7,0.719,36,1 178 | 6,85,78,0,0,31.2,0.382,42,0 179 | 0,129,110,46,130,67.1,0.319,26,1 180 | 5,143,78,0,0,45,0.19,47,0 181 | 5,130,82,0,0,39.1,0.956,37,1 182 | 6,87,80,0,0,23.2,0.084,32,0 183 | 0,119,64,18,92,34.9,0.725,23,0 184 | 1,0,74,20,23,27.7,0.299,21,0 185 | 5,73,60,0,0,26.8,0.268,27,0 186 | 4,141,74,0,0,27.6,0.244,40,0 187 | 7,194,68,28,0,35.9,0.745,41,1 188 | 8,181,68,36,495,30.1,0.615,60,1 189 | 1,128,98,41,58,32,1.321,33,1 190 | 8,109,76,39,114,27.9,0.64,31,1 191 | 5,139,80,35,160,31.6,0.361,25,1 192 | 3,111,62,0,0,22.6,0.142,21,0 193 | 9,123,70,44,94,33.1,0.374,40,0 194 | 7,159,66,0,0,30.4,0.383,36,1 195 | 11,135,0,0,0,52.3,0.578,40,1 196 | 8,85,55,20,0,24.4,0.136,42,0 197 | 5,158,84,41,210,39.4,0.395,29,1 198 | 1,105,58,0,0,24.3,0.187,21,0 199 | 3,107,62,13,48,22.9,0.678,23,1 200 | 4,109,64,44,99,34.8,0.905,26,1 201 | 4,148,60,27,318,30.9,0.15,29,1 202 | 0,113,80,16,0,31,0.874,21,0 203 | 1,138,82,0,0,40.1,0.236,28,0 204 | 0,108,68,20,0,27.3,0.787,32,0 205 | 2,99,70,16,44,20.4,0.235,27,0 206 | 6,103,72,32,190,37.7,0.324,55,0 207 | 5,111,72,28,0,23.9,0.407,27,0 208 | 8,196,76,29,280,37.5,0.605,57,1 209 | 5,162,104,0,0,37.7,0.151,52,1 210 | 1,96,64,27,87,33.2,0.289,21,0 211 | 7,184,84,33,0,35.5,0.355,41,1 212 | 2,81,60,22,0,27.7,0.29,25,0 213 | 0,147,85,54,0,42.8,0.375,24,0 214 | 7,179,95,31,0,34.2,0.164,60,0 215 | 0,140,65,26,130,42.6,0.431,24,1 216 | 9,112,82,32,175,34.2,0.26,36,1 217 | 12,151,70,40,271,41.8,0.742,38,1 218 | 5,109,62,41,129,35.8,0.514,25,1 219 | 6,125,68,30,120,30,0.464,32,0 220 | 5,85,74,22,0,29,1.224,32,1 221 | 5,112,66,0,0,37.8,0.261,41,1 222 | 0,177,60,29,478,34.6,1.072,21,1 223 | 2,158,90,0,0,31.6,0.805,66,1 224 | 7,119,0,0,0,25.2,0.209,37,0 225 | 7,142,60,33,190,28.8,0.687,61,0 226 | 1,100,66,15,56,23.6,0.666,26,0 227 | 1,87,78,27,32,34.6,0.101,22,0 228 | 0,101,76,0,0,35.7,0.198,26,0 229 | 3,162,52,38,0,37.2,0.652,24,1 230 | 4,197,70,39,744,36.7,2.329,31,0 231 | 0,117,80,31,53,45.2,0.089,24,0 232 | 4,142,86,0,0,44,0.645,22,1 233 | 6,134,80,37,370,46.2,0.238,46,1 234 | 1,79,80,25,37,25.4,0.583,22,0 235 | 4,122,68,0,0,35,0.394,29,0 236 | 3,74,68,28,45,29.7,0.293,23,0 237 | 4,171,72,0,0,43.6,0.479,26,1 238 | 7,181,84,21,192,35.9,0.586,51,1 239 | 0,179,90,27,0,44.1,0.686,23,1 240 | 9,164,84,21,0,30.8,0.831,32,1 241 | 0,104,76,0,0,18.4,0.582,27,0 242 | 1,91,64,24,0,29.2,0.192,21,0 243 | 4,91,70,32,88,33.1,0.446,22,0 244 | 3,139,54,0,0,25.6,0.402,22,1 245 | 6,119,50,22,176,27.1,1.318,33,1 246 | 2,146,76,35,194,38.2,0.329,29,0 247 | 9,184,85,15,0,30,1.213,49,1 248 | 10,122,68,0,0,31.2,0.258,41,0 249 | 0,165,90,33,680,52.3,0.427,23,0 250 | 9,124,70,33,402,35.4,0.282,34,0 251 | 1,111,86,19,0,30.1,0.143,23,0 252 | 9,106,52,0,0,31.2,0.38,42,0 253 | 2,129,84,0,0,28,0.284,27,0 254 | 2,90,80,14,55,24.4,0.249,24,0 255 | 0,86,68,32,0,35.8,0.238,25,0 256 | 12,92,62,7,258,27.6,0.926,44,1 257 | 1,113,64,35,0,33.6,0.543,21,1 258 | 3,111,56,39,0,30.1,0.557,30,0 259 | 2,114,68,22,0,28.7,0.092,25,0 260 | 1,193,50,16,375,25.9,0.655,24,0 261 | 11,155,76,28,150,33.3,1.353,51,1 262 | 3,191,68,15,130,30.9,0.299,34,0 263 | 3,141,0,0,0,30,0.761,27,1 264 | 4,95,70,32,0,32.1,0.612,24,0 265 | 3,142,80,15,0,32.4,0.2,63,0 266 | 4,123,62,0,0,32,0.226,35,1 267 | 5,96,74,18,67,33.6,0.997,43,0 268 | 0,138,0,0,0,36.3,0.933,25,1 269 | 2,128,64,42,0,40,1.101,24,0 270 | 0,102,52,0,0,25.1,0.078,21,0 271 | 2,146,0,0,0,27.5,0.24,28,1 272 | 10,101,86,37,0,45.6,1.136,38,1 273 | 2,108,62,32,56,25.2,0.128,21,0 274 | 3,122,78,0,0,23,0.254,40,0 275 | 1,71,78,50,45,33.2,0.422,21,0 276 | 13,106,70,0,0,34.2,0.251,52,0 277 | 2,100,70,52,57,40.5,0.677,25,0 278 | 7,106,60,24,0,26.5,0.296,29,1 279 | 0,104,64,23,116,27.8,0.454,23,0 280 | 5,114,74,0,0,24.9,0.744,57,0 281 | 2,108,62,10,278,25.3,0.881,22,0 282 | 0,146,70,0,0,37.9,0.334,28,1 283 | 10,129,76,28,122,35.9,0.28,39,0 284 | 7,133,88,15,155,32.4,0.262,37,0 285 | 7,161,86,0,0,30.4,0.165,47,1 286 | 2,108,80,0,0,27,0.259,52,1 287 | 7,136,74,26,135,26,0.647,51,0 288 | 5,155,84,44,545,38.7,0.619,34,0 289 | 1,119,86,39,220,45.6,0.808,29,1 290 | 4,96,56,17,49,20.8,0.34,26,0 291 | 5,108,72,43,75,36.1,0.263,33,0 292 | 0,78,88,29,40,36.9,0.434,21,0 293 | 0,107,62,30,74,36.6,0.757,25,1 294 | 2,128,78,37,182,43.3,1.224,31,1 295 | 1,128,48,45,194,40.5,0.613,24,1 296 | 0,161,50,0,0,21.9,0.254,65,0 297 | 6,151,62,31,120,35.5,0.692,28,0 298 | 2,146,70,38,360,28,0.337,29,1 299 | 0,126,84,29,215,30.7,0.52,24,0 300 | 14,100,78,25,184,36.6,0.412,46,1 301 | 8,112,72,0,0,23.6,0.84,58,0 302 | 0,167,0,0,0,32.3,0.839,30,1 303 | 2,144,58,33,135,31.6,0.422,25,1 304 | 5,77,82,41,42,35.8,0.156,35,0 305 | 5,115,98,0,0,52.9,0.209,28,1 306 | 3,150,76,0,0,21,0.207,37,0 307 | 2,120,76,37,105,39.7,0.215,29,0 308 | 10,161,68,23,132,25.5,0.326,47,1 309 | 0,137,68,14,148,24.8,0.143,21,0 310 | 0,128,68,19,180,30.5,1.391,25,1 311 | 2,124,68,28,205,32.9,0.875,30,1 312 | 6,80,66,30,0,26.2,0.313,41,0 313 | 0,106,70,37,148,39.4,0.605,22,0 314 | 2,155,74,17,96,26.6,0.433,27,1 315 | 3,113,50,10,85,29.5,0.626,25,0 316 | 7,109,80,31,0,35.9,1.127,43,1 317 | 2,112,68,22,94,34.1,0.315,26,0 318 | 3,99,80,11,64,19.3,0.284,30,0 319 | 3,182,74,0,0,30.5,0.345,29,1 320 | 3,115,66,39,140,38.1,0.15,28,0 321 | 6,194,78,0,0,23.5,0.129,59,1 322 | 4,129,60,12,231,27.5,0.527,31,0 323 | 3,112,74,30,0,31.6,0.197,25,1 324 | 0,124,70,20,0,27.4,0.254,36,1 325 | 13,152,90,33,29,26.8,0.731,43,1 326 | 2,112,75,32,0,35.7,0.148,21,0 327 | 1,157,72,21,168,25.6,0.123,24,0 328 | 1,122,64,32,156,35.1,0.692,30,1 329 | 10,179,70,0,0,35.1,0.2,37,0 330 | 2,102,86,36,120,45.5,0.127,23,1 331 | 6,105,70,32,68,30.8,0.122,37,0 332 | 8,118,72,19,0,23.1,1.476,46,0 333 | 2,87,58,16,52,32.7,0.166,25,0 334 | 1,180,0,0,0,43.3,0.282,41,1 335 | 12,106,80,0,0,23.6,0.137,44,0 336 | 1,95,60,18,58,23.9,0.26,22,0 337 | 0,165,76,43,255,47.9,0.259,26,0 338 | 0,117,0,0,0,33.8,0.932,44,0 339 | 5,115,76,0,0,31.2,0.343,44,1 340 | 9,152,78,34,171,34.2,0.893,33,1 341 | 7,178,84,0,0,39.9,0.331,41,1 342 | 1,130,70,13,105,25.9,0.472,22,0 343 | 1,95,74,21,73,25.9,0.673,36,0 344 | 1,0,68,35,0,32,0.389,22,0 345 | 5,122,86,0,0,34.7,0.29,33,0 346 | 8,95,72,0,0,36.8,0.485,57,0 347 | 8,126,88,36,108,38.5,0.349,49,0 348 | 1,139,46,19,83,28.7,0.654,22,0 349 | 3,116,0,0,0,23.5,0.187,23,0 350 | 3,99,62,19,74,21.8,0.279,26,0 351 | 5,0,80,32,0,41,0.346,37,1 352 | 4,92,80,0,0,42.2,0.237,29,0 353 | 4,137,84,0,0,31.2,0.252,30,0 354 | 3,61,82,28,0,34.4,0.243,46,0 355 | 1,90,62,12,43,27.2,0.58,24,0 356 | 3,90,78,0,0,42.7,0.559,21,0 357 | 9,165,88,0,0,30.4,0.302,49,1 358 | 1,125,50,40,167,33.3,0.962,28,1 359 | 13,129,0,30,0,39.9,0.569,44,1 360 | 12,88,74,40,54,35.3,0.378,48,0 361 | 1,196,76,36,249,36.5,0.875,29,1 362 | 5,189,64,33,325,31.2,0.583,29,1 363 | 5,158,70,0,0,29.8,0.207,63,0 364 | 5,103,108,37,0,39.2,0.305,65,0 365 | 4,146,78,0,0,38.5,0.52,67,1 366 | 4,147,74,25,293,34.9,0.385,30,0 367 | 5,99,54,28,83,34,0.499,30,0 368 | 6,124,72,0,0,27.6,0.368,29,1 369 | 0,101,64,17,0,21,0.252,21,0 370 | 3,81,86,16,66,27.5,0.306,22,0 371 | 1,133,102,28,140,32.8,0.234,45,1 372 | 3,173,82,48,465,38.4,2.137,25,1 373 | 0,118,64,23,89,0,1.731,21,0 374 | 0,84,64,22,66,35.8,0.545,21,0 375 | 2,105,58,40,94,34.9,0.225,25,0 376 | 2,122,52,43,158,36.2,0.816,28,0 377 | 12,140,82,43,325,39.2,0.528,58,1 378 | 0,98,82,15,84,25.2,0.299,22,0 379 | 1,87,60,37,75,37.2,0.509,22,0 380 | 4,156,75,0,0,48.3,0.238,32,1 381 | 0,93,100,39,72,43.4,1.021,35,0 382 | 1,107,72,30,82,30.8,0.821,24,0 383 | 0,105,68,22,0,20,0.236,22,0 384 | 1,109,60,8,182,25.4,0.947,21,0 385 | 1,90,62,18,59,25.1,1.268,25,0 386 | 1,125,70,24,110,24.3,0.221,25,0 387 | 1,119,54,13,50,22.3,0.205,24,0 388 | 5,116,74,29,0,32.3,0.66,35,1 389 | 8,105,100,36,0,43.3,0.239,45,1 390 | 5,144,82,26,285,32,0.452,58,1 391 | 3,100,68,23,81,31.6,0.949,28,0 392 | 1,100,66,29,196,32,0.444,42,0 393 | 5,166,76,0,0,45.7,0.34,27,1 394 | 1,131,64,14,415,23.7,0.389,21,0 395 | 4,116,72,12,87,22.1,0.463,37,0 396 | 4,158,78,0,0,32.9,0.803,31,1 397 | 2,127,58,24,275,27.7,1.6,25,0 398 | 3,96,56,34,115,24.7,0.944,39,0 399 | 0,131,66,40,0,34.3,0.196,22,1 400 | 3,82,70,0,0,21.1,0.389,25,0 401 | 3,193,70,31,0,34.9,0.241,25,1 402 | 4,95,64,0,0,32,0.161,31,1 403 | 6,137,61,0,0,24.2,0.151,55,0 404 | 5,136,84,41,88,35,0.286,35,1 405 | 9,72,78,25,0,31.6,0.28,38,0 406 | 5,168,64,0,0,32.9,0.135,41,1 407 | 2,123,48,32,165,42.1,0.52,26,0 408 | 4,115,72,0,0,28.9,0.376,46,1 409 | 0,101,62,0,0,21.9,0.336,25,0 410 | 8,197,74,0,0,25.9,1.191,39,1 411 | 1,172,68,49,579,42.4,0.702,28,1 412 | 6,102,90,39,0,35.7,0.674,28,0 413 | 1,112,72,30,176,34.4,0.528,25,0 414 | 1,143,84,23,310,42.4,1.076,22,0 415 | 1,143,74,22,61,26.2,0.256,21,0 416 | 0,138,60,35,167,34.6,0.534,21,1 417 | 3,173,84,33,474,35.7,0.258,22,1 418 | 1,97,68,21,0,27.2,1.095,22,0 419 | 4,144,82,32,0,38.5,0.554,37,1 420 | 1,83,68,0,0,18.2,0.624,27,0 421 | 3,129,64,29,115,26.4,0.219,28,1 422 | 1,119,88,41,170,45.3,0.507,26,0 423 | 2,94,68,18,76,26,0.561,21,0 424 | 0,102,64,46,78,40.6,0.496,21,0 425 | 2,115,64,22,0,30.8,0.421,21,0 426 | 8,151,78,32,210,42.9,0.516,36,1 427 | 4,184,78,39,277,37,0.264,31,1 428 | 0,94,0,0,0,0,0.256,25,0 429 | 1,181,64,30,180,34.1,0.328,38,1 430 | 0,135,94,46,145,40.6,0.284,26,0 431 | 1,95,82,25,180,35,0.233,43,1 432 | 2,99,0,0,0,22.2,0.108,23,0 433 | 3,89,74,16,85,30.4,0.551,38,0 434 | 1,80,74,11,60,30,0.527,22,0 435 | 2,139,75,0,0,25.6,0.167,29,0 436 | 1,90,68,8,0,24.5,1.138,36,0 437 | 0,141,0,0,0,42.4,0.205,29,1 438 | 12,140,85,33,0,37.4,0.244,41,0 439 | 5,147,75,0,0,29.9,0.434,28,0 440 | 1,97,70,15,0,18.2,0.147,21,0 441 | 6,107,88,0,0,36.8,0.727,31,0 442 | 0,189,104,25,0,34.3,0.435,41,1 443 | 2,83,66,23,50,32.2,0.497,22,0 444 | 4,117,64,27,120,33.2,0.23,24,0 445 | 8,108,70,0,0,30.5,0.955,33,1 446 | 4,117,62,12,0,29.7,0.38,30,1 447 | 0,180,78,63,14,59.4,2.42,25,1 448 | 1,100,72,12,70,25.3,0.658,28,0 449 | 0,95,80,45,92,36.5,0.33,26,0 450 | 0,104,64,37,64,33.6,0.51,22,1 451 | 0,120,74,18,63,30.5,0.285,26,0 452 | 1,82,64,13,95,21.2,0.415,23,0 453 | 2,134,70,0,0,28.9,0.542,23,1 454 | 0,91,68,32,210,39.9,0.381,25,0 455 | 2,119,0,0,0,19.6,0.832,72,0 456 | 2,100,54,28,105,37.8,0.498,24,0 457 | 14,175,62,30,0,33.6,0.212,38,1 458 | 1,135,54,0,0,26.7,0.687,62,0 459 | 5,86,68,28,71,30.2,0.364,24,0 460 | 10,148,84,48,237,37.6,1.001,51,1 461 | 9,134,74,33,60,25.9,0.46,81,0 462 | 9,120,72,22,56,20.8,0.733,48,0 463 | 1,71,62,0,0,21.8,0.416,26,0 464 | 8,74,70,40,49,35.3,0.705,39,0 465 | 5,88,78,30,0,27.6,0.258,37,0 466 | 10,115,98,0,0,24,1.022,34,0 467 | 0,124,56,13,105,21.8,0.452,21,0 468 | 0,74,52,10,36,27.8,0.269,22,0 469 | 0,97,64,36,100,36.8,0.6,25,0 470 | 8,120,0,0,0,30,0.183,38,1 471 | 6,154,78,41,140,46.1,0.571,27,0 472 | 1,144,82,40,0,41.3,0.607,28,0 473 | 0,137,70,38,0,33.2,0.17,22,0 474 | 0,119,66,27,0,38.8,0.259,22,0 475 | 7,136,90,0,0,29.9,0.21,50,0 476 | 4,114,64,0,0,28.9,0.126,24,0 477 | 0,137,84,27,0,27.3,0.231,59,0 478 | 2,105,80,45,191,33.7,0.711,29,1 479 | 7,114,76,17,110,23.8,0.466,31,0 480 | 8,126,74,38,75,25.9,0.162,39,0 481 | 4,132,86,31,0,28,0.419,63,0 482 | 3,158,70,30,328,35.5,0.344,35,1 483 | 0,123,88,37,0,35.2,0.197,29,0 484 | 4,85,58,22,49,27.8,0.306,28,0 485 | 0,84,82,31,125,38.2,0.233,23,0 486 | 0,145,0,0,0,44.2,0.63,31,1 487 | 0,135,68,42,250,42.3,0.365,24,1 488 | 1,139,62,41,480,40.7,0.536,21,0 489 | 0,173,78,32,265,46.5,1.159,58,0 490 | 4,99,72,17,0,25.6,0.294,28,0 491 | 8,194,80,0,0,26.1,0.551,67,0 492 | 2,83,65,28,66,36.8,0.629,24,0 493 | 2,89,90,30,0,33.5,0.292,42,0 494 | 4,99,68,38,0,32.8,0.145,33,0 495 | 4,125,70,18,122,28.9,1.144,45,1 496 | 3,80,0,0,0,0,0.174,22,0 497 | 6,166,74,0,0,26.6,0.304,66,0 498 | 5,110,68,0,0,26,0.292,30,0 499 | 2,81,72,15,76,30.1,0.547,25,0 500 | 7,195,70,33,145,25.1,0.163,55,1 501 | 6,154,74,32,193,29.3,0.839,39,0 502 | 2,117,90,19,71,25.2,0.313,21,0 503 | 3,84,72,32,0,37.2,0.267,28,0 504 | 6,0,68,41,0,39,0.727,41,1 505 | 7,94,64,25,79,33.3,0.738,41,0 506 | 3,96,78,39,0,37.3,0.238,40,0 507 | 10,75,82,0,0,33.3,0.263,38,0 508 | 0,180,90,26,90,36.5,0.314,35,1 509 | 1,130,60,23,170,28.6,0.692,21,0 510 | 2,84,50,23,76,30.4,0.968,21,0 511 | 8,120,78,0,0,25,0.409,64,0 512 | 12,84,72,31,0,29.7,0.297,46,1 513 | 0,139,62,17,210,22.1,0.207,21,0 514 | 9,91,68,0,0,24.2,0.2,58,0 515 | 2,91,62,0,0,27.3,0.525,22,0 516 | 3,99,54,19,86,25.6,0.154,24,0 517 | 3,163,70,18,105,31.6,0.268,28,1 518 | 9,145,88,34,165,30.3,0.771,53,1 519 | 7,125,86,0,0,37.6,0.304,51,0 520 | 13,76,60,0,0,32.8,0.18,41,0 521 | 6,129,90,7,326,19.6,0.582,60,0 522 | 2,68,70,32,66,25,0.187,25,0 523 | 3,124,80,33,130,33.2,0.305,26,0 524 | 6,114,0,0,0,0,0.189,26,0 525 | 9,130,70,0,0,34.2,0.652,45,1 526 | 3,125,58,0,0,31.6,0.151,24,0 527 | 3,87,60,18,0,21.8,0.444,21,0 528 | 1,97,64,19,82,18.2,0.299,21,0 529 | 3,116,74,15,105,26.3,0.107,24,0 530 | 0,117,66,31,188,30.8,0.493,22,0 531 | 0,111,65,0,0,24.6,0.66,31,0 532 | 2,122,60,18,106,29.8,0.717,22,0 533 | 0,107,76,0,0,45.3,0.686,24,0 534 | 1,86,66,52,65,41.3,0.917,29,0 535 | 6,91,0,0,0,29.8,0.501,31,0 536 | 1,77,56,30,56,33.3,1.251,24,0 537 | 4,132,0,0,0,32.9,0.302,23,1 538 | 0,105,90,0,0,29.6,0.197,46,0 539 | 0,57,60,0,0,21.7,0.735,67,0 540 | 0,127,80,37,210,36.3,0.804,23,0 541 | 3,129,92,49,155,36.4,0.968,32,1 542 | 8,100,74,40,215,39.4,0.661,43,1 543 | 3,128,72,25,190,32.4,0.549,27,1 544 | 10,90,85,32,0,34.9,0.825,56,1 545 | 4,84,90,23,56,39.5,0.159,25,0 546 | 1,88,78,29,76,32,0.365,29,0 547 | 8,186,90,35,225,34.5,0.423,37,1 548 | 5,187,76,27,207,43.6,1.034,53,1 549 | 4,131,68,21,166,33.1,0.16,28,0 550 | 1,164,82,43,67,32.8,0.341,50,0 551 | 4,189,110,31,0,28.5,0.68,37,0 552 | 1,116,70,28,0,27.4,0.204,21,0 553 | 3,84,68,30,106,31.9,0.591,25,0 554 | 6,114,88,0,0,27.8,0.247,66,0 555 | 1,88,62,24,44,29.9,0.422,23,0 556 | 1,84,64,23,115,36.9,0.471,28,0 557 | 7,124,70,33,215,25.5,0.161,37,0 558 | 1,97,70,40,0,38.1,0.218,30,0 559 | 8,110,76,0,0,27.8,0.237,58,0 560 | 11,103,68,40,0,46.2,0.126,42,0 561 | 11,85,74,0,0,30.1,0.3,35,0 562 | 6,125,76,0,0,33.8,0.121,54,1 563 | 0,198,66,32,274,41.3,0.502,28,1 564 | 1,87,68,34,77,37.6,0.401,24,0 565 | 6,99,60,19,54,26.9,0.497,32,0 566 | 0,91,80,0,0,32.4,0.601,27,0 567 | 2,95,54,14,88,26.1,0.748,22,0 568 | 1,99,72,30,18,38.6,0.412,21,0 569 | 6,92,62,32,126,32,0.085,46,0 570 | 4,154,72,29,126,31.3,0.338,37,0 571 | 0,121,66,30,165,34.3,0.203,33,1 572 | 3,78,70,0,0,32.5,0.27,39,0 573 | 2,130,96,0,0,22.6,0.268,21,0 574 | 3,111,58,31,44,29.5,0.43,22,0 575 | 2,98,60,17,120,34.7,0.198,22,0 576 | 1,143,86,30,330,30.1,0.892,23,0 577 | 1,119,44,47,63,35.5,0.28,25,0 578 | 6,108,44,20,130,24,0.813,35,0 579 | 2,118,80,0,0,42.9,0.693,21,1 580 | 10,133,68,0,0,27,0.245,36,0 581 | 2,197,70,99,0,34.7,0.575,62,1 582 | 0,151,90,46,0,42.1,0.371,21,1 583 | 6,109,60,27,0,25,0.206,27,0 584 | 12,121,78,17,0,26.5,0.259,62,0 585 | 8,100,76,0,0,38.7,0.19,42,0 586 | 8,124,76,24,600,28.7,0.687,52,1 587 | 1,93,56,11,0,22.5,0.417,22,0 588 | 8,143,66,0,0,34.9,0.129,41,1 589 | 6,103,66,0,0,24.3,0.249,29,0 590 | 3,176,86,27,156,33.3,1.154,52,1 591 | 0,73,0,0,0,21.1,0.342,25,0 592 | 11,111,84,40,0,46.8,0.925,45,1 593 | 2,112,78,50,140,39.4,0.175,24,0 594 | 3,132,80,0,0,34.4,0.402,44,1 595 | 2,82,52,22,115,28.5,1.699,25,0 596 | 6,123,72,45,230,33.6,0.733,34,0 597 | 0,188,82,14,185,32,0.682,22,1 598 | 0,67,76,0,0,45.3,0.194,46,0 599 | 1,89,24,19,25,27.8,0.559,21,0 600 | 1,173,74,0,0,36.8,0.088,38,1 601 | 1,109,38,18,120,23.1,0.407,26,0 602 | 1,108,88,19,0,27.1,0.4,24,0 603 | 6,96,0,0,0,23.7,0.19,28,0 604 | 1,124,74,36,0,27.8,0.1,30,0 605 | 7,150,78,29,126,35.2,0.692,54,1 606 | 4,183,0,0,0,28.4,0.212,36,1 607 | 1,124,60,32,0,35.8,0.514,21,0 608 | 1,181,78,42,293,40,1.258,22,1 609 | 1,92,62,25,41,19.5,0.482,25,0 610 | 0,152,82,39,272,41.5,0.27,27,0 611 | 1,111,62,13,182,24,0.138,23,0 612 | 3,106,54,21,158,30.9,0.292,24,0 613 | 3,174,58,22,194,32.9,0.593,36,1 614 | 7,168,88,42,321,38.2,0.787,40,1 615 | 6,105,80,28,0,32.5,0.878,26,0 616 | 11,138,74,26,144,36.1,0.557,50,1 617 | 3,106,72,0,0,25.8,0.207,27,0 618 | 6,117,96,0,0,28.7,0.157,30,0 619 | 2,68,62,13,15,20.1,0.257,23,0 620 | 9,112,82,24,0,28.2,1.282,50,1 621 | 0,119,0,0,0,32.4,0.141,24,1 622 | 2,112,86,42,160,38.4,0.246,28,0 623 | 2,92,76,20,0,24.2,1.698,28,0 624 | 6,183,94,0,0,40.8,1.461,45,0 625 | 0,94,70,27,115,43.5,0.347,21,0 626 | 2,108,64,0,0,30.8,0.158,21,0 627 | 4,90,88,47,54,37.7,0.362,29,0 628 | 0,125,68,0,0,24.7,0.206,21,0 629 | 0,132,78,0,0,32.4,0.393,21,0 630 | 5,128,80,0,0,34.6,0.144,45,0 631 | 4,94,65,22,0,24.7,0.148,21,0 632 | 7,114,64,0,0,27.4,0.732,34,1 633 | 0,102,78,40,90,34.5,0.238,24,0 634 | 2,111,60,0,0,26.2,0.343,23,0 635 | 1,128,82,17,183,27.5,0.115,22,0 636 | 10,92,62,0,0,25.9,0.167,31,0 637 | 13,104,72,0,0,31.2,0.465,38,1 638 | 5,104,74,0,0,28.8,0.153,48,0 639 | 2,94,76,18,66,31.6,0.649,23,0 640 | 7,97,76,32,91,40.9,0.871,32,1 641 | 1,100,74,12,46,19.5,0.149,28,0 642 | 0,102,86,17,105,29.3,0.695,27,0 643 | 4,128,70,0,0,34.3,0.303,24,0 644 | 6,147,80,0,0,29.5,0.178,50,1 645 | 4,90,0,0,0,28,0.61,31,0 646 | 3,103,72,30,152,27.6,0.73,27,0 647 | 2,157,74,35,440,39.4,0.134,30,0 648 | 1,167,74,17,144,23.4,0.447,33,1 649 | 0,179,50,36,159,37.8,0.455,22,1 650 | 11,136,84,35,130,28.3,0.26,42,1 651 | 0,107,60,25,0,26.4,0.133,23,0 652 | 1,91,54,25,100,25.2,0.234,23,0 653 | 1,117,60,23,106,33.8,0.466,27,0 654 | 5,123,74,40,77,34.1,0.269,28,0 655 | 2,120,54,0,0,26.8,0.455,27,0 656 | 1,106,70,28,135,34.2,0.142,22,0 657 | 2,155,52,27,540,38.7,0.24,25,1 658 | 2,101,58,35,90,21.8,0.155,22,0 659 | 1,120,80,48,200,38.9,1.162,41,0 660 | 11,127,106,0,0,39,0.19,51,0 661 | 3,80,82,31,70,34.2,1.292,27,1 662 | 10,162,84,0,0,27.7,0.182,54,0 663 | 1,199,76,43,0,42.9,1.394,22,1 664 | 8,167,106,46,231,37.6,0.165,43,1 665 | 9,145,80,46,130,37.9,0.637,40,1 666 | 6,115,60,39,0,33.7,0.245,40,1 667 | 1,112,80,45,132,34.8,0.217,24,0 668 | 4,145,82,18,0,32.5,0.235,70,1 669 | 10,111,70,27,0,27.5,0.141,40,1 670 | 6,98,58,33,190,34,0.43,43,0 671 | 9,154,78,30,100,30.9,0.164,45,0 672 | 6,165,68,26,168,33.6,0.631,49,0 673 | 1,99,58,10,0,25.4,0.551,21,0 674 | 10,68,106,23,49,35.5,0.285,47,0 675 | 3,123,100,35,240,57.3,0.88,22,0 676 | 8,91,82,0,0,35.6,0.587,68,0 677 | 6,195,70,0,0,30.9,0.328,31,1 678 | 9,156,86,0,0,24.8,0.23,53,1 679 | 0,93,60,0,0,35.3,0.263,25,0 680 | 3,121,52,0,0,36,0.127,25,1 681 | 2,101,58,17,265,24.2,0.614,23,0 682 | 2,56,56,28,45,24.2,0.332,22,0 683 | 0,162,76,36,0,49.6,0.364,26,1 684 | 0,95,64,39,105,44.6,0.366,22,0 685 | 4,125,80,0,0,32.3,0.536,27,1 686 | 5,136,82,0,0,0,0.64,69,0 687 | 2,129,74,26,205,33.2,0.591,25,0 688 | 3,130,64,0,0,23.1,0.314,22,0 689 | 1,107,50,19,0,28.3,0.181,29,0 690 | 1,140,74,26,180,24.1,0.828,23,0 691 | 1,144,82,46,180,46.1,0.335,46,1 692 | 8,107,80,0,0,24.6,0.856,34,0 693 | 13,158,114,0,0,42.3,0.257,44,1 694 | 2,121,70,32,95,39.1,0.886,23,0 695 | 7,129,68,49,125,38.5,0.439,43,1 696 | 2,90,60,0,0,23.5,0.191,25,0 697 | 7,142,90,24,480,30.4,0.128,43,1 698 | 3,169,74,19,125,29.9,0.268,31,1 699 | 0,99,0,0,0,25,0.253,22,0 700 | 4,127,88,11,155,34.5,0.598,28,0 701 | 4,118,70,0,0,44.5,0.904,26,0 702 | 2,122,76,27,200,35.9,0.483,26,0 703 | 6,125,78,31,0,27.6,0.565,49,1 704 | 1,168,88,29,0,35,0.905,52,1 705 | 2,129,0,0,0,38.5,0.304,41,0 706 | 4,110,76,20,100,28.4,0.118,27,0 707 | 6,80,80,36,0,39.8,0.177,28,0 708 | 10,115,0,0,0,0,0.261,30,1 709 | 2,127,46,21,335,34.4,0.176,22,0 710 | 9,164,78,0,0,32.8,0.148,45,1 711 | 2,93,64,32,160,38,0.674,23,1 712 | 3,158,64,13,387,31.2,0.295,24,0 713 | 5,126,78,27,22,29.6,0.439,40,0 714 | 10,129,62,36,0,41.2,0.441,38,1 715 | 0,134,58,20,291,26.4,0.352,21,0 716 | 3,102,74,0,0,29.5,0.121,32,0 717 | 7,187,50,33,392,33.9,0.826,34,1 718 | 3,173,78,39,185,33.8,0.97,31,1 719 | 10,94,72,18,0,23.1,0.595,56,0 720 | 1,108,60,46,178,35.5,0.415,24,0 721 | 5,97,76,27,0,35.6,0.378,52,1 722 | 4,83,86,19,0,29.3,0.317,34,0 723 | 1,114,66,36,200,38.1,0.289,21,0 724 | 1,149,68,29,127,29.3,0.349,42,1 725 | 5,117,86,30,105,39.1,0.251,42,0 726 | 1,111,94,0,0,32.8,0.265,45,0 727 | 4,112,78,40,0,39.4,0.236,38,0 728 | 1,116,78,29,180,36.1,0.496,25,0 729 | 0,141,84,26,0,32.4,0.433,22,0 730 | 2,175,88,0,0,22.9,0.326,22,0 731 | 2,92,52,0,0,30.1,0.141,22,0 732 | 3,130,78,23,79,28.4,0.323,34,1 733 | 8,120,86,0,0,28.4,0.259,22,1 734 | 2,174,88,37,120,44.5,0.646,24,1 735 | 2,106,56,27,165,29,0.426,22,0 736 | 2,105,75,0,0,23.3,0.56,53,0 737 | 4,95,60,32,0,35.4,0.284,28,0 738 | 0,126,86,27,120,27.4,0.515,21,0 739 | 8,65,72,23,0,32,0.6,42,0 740 | 2,99,60,17,160,36.6,0.453,21,0 741 | 1,102,74,0,0,39.5,0.293,42,1 742 | 11,120,80,37,150,42.3,0.785,48,1 743 | 3,102,44,20,94,30.8,0.4,26,0 744 | 1,109,58,18,116,28.5,0.219,22,0 745 | 9,140,94,0,0,32.7,0.734,45,1 746 | 13,153,88,37,140,40.6,1.174,39,0 747 | 12,100,84,33,105,30,0.488,46,0 748 | 1,147,94,41,0,49.3,0.358,27,1 749 | 1,81,74,41,57,46.3,1.096,32,0 750 | 3,187,70,22,200,36.4,0.408,36,1 751 | 6,162,62,0,0,24.3,0.178,50,1 752 | 4,136,70,0,0,31.2,1.182,22,1 753 | 1,121,78,39,74,39,0.261,28,0 754 | 3,108,62,24,0,26,0.223,25,0 755 | 0,181,88,44,510,43.3,0.222,26,1 756 | 8,154,78,32,0,32.4,0.443,45,1 757 | 1,128,88,39,110,36.5,1.057,37,1 758 | 7,137,90,41,0,32,0.391,39,0 759 | 0,123,72,0,0,36.3,0.258,52,1 760 | 1,106,76,0,0,37.5,0.197,26,0 761 | 6,190,92,0,0,35.5,0.278,66,1 762 | 2,88,58,26,16,28.4,0.766,22,0 763 | 9,170,74,31,0,44,0.403,43,1 764 | 9,89,62,0,0,22.5,0.142,33,0 765 | 10,101,76,48,180,32.9,0.171,63,0 766 | 2,122,70,27,0,36.8,0.34,27,0 767 | 5,121,72,23,112,26.2,0.245,30,0 768 | 1,126,60,0,0,30.1,0.349,47,1 769 | 1,93,70,31,0,30.4,0.315,23,0 -------------------------------------------------------------------------------- /tutorial_2/pima.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_2/pima.png -------------------------------------------------------------------------------- /tutorial_3/.gitignore: -------------------------------------------------------------------------------- 1 | *.zip 2 | *.csv -------------------------------------------------------------------------------- /tutorial_3/.ipynb_checkpoints/images_as_tensors-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Tutorial 3: Machine Learning and Image Data" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Previously, we applie" 15 | ] 16 | } 17 | ], 18 | "metadata": { 19 | "kernelspec": { 20 | "display_name": "Python 2", 21 | "language": "python", 22 | "name": "python2" 23 | }, 24 | "language_info": { 25 | "codemirror_mode": { 26 | "name": "ipython", 27 | "version": 2 28 | }, 29 | "file_extension": ".py", 30 | "mimetype": "text/x-python", 31 | "name": "python", 32 | "nbconvert_exporter": "python", 33 | "pygments_lexer": "ipython2", 34 | "version": "2.7.12" 35 | } 36 | }, 37 | "nbformat": 4, 38 | "nbformat_minor": 2 39 | } 40 | -------------------------------------------------------------------------------- /tutorial_3/ML_for_images.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Tutorial 3: Machine Learning and Image Data" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "Previously, we applied machine learning to stroke risk data using random forests. We got some pretty good results! \n", 15 | "\n", 16 | "You may be wondering, however -- how do we apply these machine learning methods to the medical imaging data we know and love? At first glance, images seem more complex then the list of stroke predictors we looked at before. Pixels (and voxels) have scalar values, like the list of stroke predictors, but they also have spatial relationships that affect their interpretation. For example, a data point in a image may be significant because it is valued very highly (bright), or it may be significant because of its differences from neighboring voxels (contrast). How can we process this new relationship with the methods we've already encountered?\n", 17 | "\n", 18 | "The answer, in short, is to reformat our image data so that it is more similar to the vectorized stroke data we dealt with previously. In this tutorial, we will show you how you can do that quite simply with small images by \"flattening\" an image into a vectorized state. We will also show that this basicmethod quickly becomes impractical with large images, and start to discuss how neural networks overcome this problem with the help of _convolutional filters_ over images." 19 | ] 20 | }, 21 | { 22 | "cell_type": "markdown", 23 | "metadata": {}, 24 | "source": [ 25 | "To get started, we're first going to load a very small image of the number \"4\"." 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 1, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "name": "stderr", 35 | "output_type": "stream", 36 | "text": [ 37 | "'wget' is not recognized as an internal or external command,\n", 38 | "operable program or batch file.\n", 39 | "'wget' is not recognized as an internal or external command,\n", 40 | "operable program or batch file.\n", 41 | "'wget' is not recognized as an internal or external command,\n", 42 | "operable program or batch file.\n" 43 | ] 44 | } 45 | ], 46 | "source": [ 47 | "!wget -O mnist_sample.png https://github.com/QTIM-Lab/qtim_Tutorials/blob/master/tutorial_3/mnist_sample.png?raw=true\n", 48 | "!wget -O mnist_sample_2.png https://github.com/QTIM-Lab/qtim_Tutorials/blob/master/tutorial_3/mnist_sample_2.png?raw=true\n", 49 | "!wget -O mnist_glossary.png https://github.com/QTIM-Lab/qtim_Tutorials/blob/master/tutorial_3/mnist_glossary.png?raw=true" 50 | ] 51 | }, 52 | { 53 | "cell_type": "code", 54 | "execution_count": 3, 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/plain": [ 60 | "(-0.5, 27.5, 27.5, -0.5)" 61 | ] 62 | }, 63 | "execution_count": 3, 64 | "metadata": {}, 65 | "output_type": "execute_result" 66 | }, 67 | { 68 | "data": { 69 | "image/png": "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\n", 70 | "text/plain": [ 71 | "
" 72 | ] 73 | }, 74 | "metadata": {}, 75 | "output_type": "display_data" 76 | } 77 | ], 78 | "source": [ 79 | "from PIL import Image\n", 80 | "import matplotlib.pyplot as plt # another common abbreviation\n", 81 | "%matplotlib inline\n", 82 | "import numpy as np # common abbreviation\n", 83 | "\n", 84 | "img = Image.open('mnist_sample.png')\n", 85 | "img_arr = np.asarray(img)\n", 86 | "plt.imshow(img_arr, cmap='gray')\n", 87 | "plt.axis('off')" 88 | ] 89 | }, 90 | { 91 | "cell_type": "markdown", 92 | "metadata": {}, 93 | "source": [ 94 | "Pretty small! Let's check the size of that image." 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 4, 100 | "metadata": {}, 101 | "outputs": [ 102 | { 103 | "name": "stdout", 104 | "output_type": "stream", 105 | "text": [ 106 | "(28, 28)\n" 107 | ] 108 | } 109 | ], 110 | "source": [ 111 | "print(img_arr.shape)" 112 | ] 113 | }, 114 | { 115 | "cell_type": "markdown", 116 | "metadata": {}, 117 | "source": [ 118 | "Only 28x28, or 784 pixels. Far smaller than most images we deal with in the real world, but a good starting point for today's tutorial. Let's bring up a second image, and use matplotlib's subplot feature to compare the two." 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 5, 124 | "metadata": {}, 125 | "outputs": [ 126 | { 127 | "data": { 128 | "text/plain": [ 129 | "(-0.5, 27.5, 27.5, -0.5)" 130 | ] 131 | }, 132 | "execution_count": 5, 133 | "metadata": {}, 134 | "output_type": "execute_result" 135 | }, 136 | { 137 | "data": { 138 | "image/png": "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\n", 139 | "text/plain": [ 140 | "
" 141 | ] 142 | }, 143 | "metadata": {}, 144 | "output_type": "display_data" 145 | } 146 | ], 147 | "source": [ 148 | "img_2 = Image.open('mnist_sample_2.png')\n", 149 | "img_arr_2 = np.asarray(img_2)\n", 150 | "\n", 151 | "plt.subplot(1, 2, 1) # total rows, total columns, position (row*column)\n", 152 | "plt.imshow(img_arr, cmap='gray')\n", 153 | "plt.axis('off')\n", 154 | "plt.subplot(1, 2, 2)\n", 155 | "plt.imshow(img_arr_2, cmap='gray')\n", 156 | "plt.axis('off')" 157 | ] 158 | }, 159 | { 160 | "cell_type": "markdown", 161 | "metadata": {}, 162 | "source": [ 163 | "A 4 and a 5 -- quite interesting! Here is today's challenge: how can you use an algorithm to tell whether a picture is a picture of a \"4\" or a picture of a \"5\"? Or, maybe, for that matter, a picture of a \"3\"? This problem of differentiating between different pictures of handwritten digits is a common benchmarking problem in computer vision, and its trained on a datset known as the MNIST dataset." 164 | ] 165 | }, 166 | { 167 | "cell_type": "markdown", 168 | "metadata": {}, 169 | "source": [ 170 | "![ML](mnist_glossary.png)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "markdown", 175 | "metadata": {}, 176 | "source": [ 177 | "Telling the difference between the rows of handwritten digits above is easy for a human being, but creating an algorithm to do so in the context of a program is not necessarily obvious. We'll start with the simplest possible method, which is to _flatten_ an image into a vectorized state, and then run a machine learning algorithm we're familiar with on it. Let's get started." 178 | ] 179 | }, 180 | { 181 | "cell_type": "code", 182 | "execution_count": 7, 183 | "metadata": {}, 184 | "outputs": [ 185 | { 186 | "name": "stdout", 187 | "output_type": "stream", 188 | "text": [ 189 | "(28, 28)\n", 190 | "(1, 784)\n" 191 | ] 192 | } 193 | ], 194 | "source": [ 195 | "# We flatten our image by using numpy's \"reshape\" function to make it a 1 x (height * width) array.\n", 196 | "print(img_arr.shape)\n", 197 | "img_flattened = np.reshape(img_arr, (1, 784)) # 28x28 = 784\n", 198 | "print(img_flattened.shape)" 199 | ] 200 | }, 201 | { 202 | "cell_type": "markdown", 203 | "metadata": {}, 204 | "source": [ 205 | "So what does that look like.." 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 9, 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "data": { 215 | "text/plain": [ 216 | "(-0.5, 783.5, 0.5, -0.5)" 217 | ] 218 | }, 219 | "execution_count": 9, 220 | "metadata": {}, 221 | "output_type": "execute_result" 222 | }, 223 | { 224 | "data": { 225 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAAkCAYAAAAElMoBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA9lJREFUeJzt2l1o1mUYBvDLzVwURGmFyoxSpwWWW6Q5K7KygiAsLA/6kNI+zKQIJDsJigIzComsIKqD9WkKiWKGURhB5RRNTJdhSqmleSBJITi2t4OXwPFU9K7FdvD7nf4fbi4e+N8HF8+gSqUSAAAAADhRXX8HAAAAAGDgURoBAAAAUFAaAQAAAFBQGgEAAABQUBoBAAAAUFAaAQAAAFBQGgEAAABQUBoBAAAAUFAaAQAAAFAY3N8B/s61dbdW+jsDUPX7LZdmybOvJEmemjU7lc3f1Dzj2IzJOTasPkky9I0v+zTf3mdaM3ryj8mjZyRJr/J9//yUnDLm1yTJiJs6+iZYXX32vHVhkuS+iz7PJ3dPrebbtL3mUbN37cuSjuv6LluS+qbRWbNhZZKkuf2OjLx5Z6/mzP1ub5Lk6Z039Gm+hs+G54OxHyZJxr87P2MWflXzjO7Lm9P2zrIkyfVb7u3TfOM3n5SlIzZm+tz7kyRDPtpU84y9z7Sm486XkiQtm27vk3yDzz0niz5dnSS5rKE7N149K0nStWt3zbP2rZyQ7a1tueDNB5Mk5z323//dn1ddkK2T3k6SvH60MaumTajmO/RLzdmSZHtrW658+IEkyakrN9Y0o/7MYUmSQzPHZeis/UmS98ctz2l1JydJLlm8IGcv+6KmmX+Vb/KT1fs789We99d9RUsq9YOq56c35PjIztQN6UqSrL/ixZxU/ZSDXQ15fM/NSZKXx76XxsENmXHTnCS92ydJsvutliTJt1e9lo7Ozqw+2lycWTRsR+pSDXGscjw/dXVl2eFpSZI12ybm9K1DkiQj1h9K9w/780RH9a4mDOnMzMYpvcp1or2LW5MkoyYd+Nszh9c1ZtiOziT//A8eWDQ12x6q7oL3fjsrbeNH/ed8fenI2qZ82bw8STJ2zbyMm9fez4l6+jPfNfdU913Dutr33f/lyNqmJBnw+dpbVmTikvlJkuEv9G6v/B9OvL+Ln1uQ4UsHTrak579x/mdzMvq2r/s5UU9H1jalvWVFkqRpw10DLt/BR6Zmy8Lq7huI90f/+bh7xaB/e9ZLIwAAAAAKgyoVD3oAAAAA6MlLIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACkojAAAAAApKIwAAAAAKSiMAAAAACn8AWILfQ8Xa6xEAAAAASUVORK5CYII=\n", 226 | "text/plain": [ 227 | "
" 228 | ] 229 | }, 230 | "metadata": {}, 231 | "output_type": "display_data" 232 | } 233 | ], 234 | "source": [ 235 | "plt.figure(figsize = (20,1))\n", 236 | "plt.imshow(img_flattened)\n", 237 | "plt.axis('off')" 238 | ] 239 | }, 240 | { 241 | "cell_type": "markdown", 242 | "metadata": {}, 243 | "source": [ 244 | "Not very helpful -- let's try looking at just one segment." 245 | ] 246 | }, 247 | { 248 | "cell_type": "code", 249 | "execution_count": 10, 250 | "metadata": {}, 251 | "outputs": [ 252 | { 253 | "data": { 254 | "text/plain": [ 255 | "(-0.5, 99.5, 0.5, -0.5)" 256 | ] 257 | }, 258 | "execution_count": 10, 259 | "metadata": {}, 260 | "output_type": "execute_result" 261 | }, 262 | { 263 | "data": { 264 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAAuCAYAAAClD+lnAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAhhJREFUeJzt2jFKXFEYhmFHbYIL0LQzsRBUTK2tIKSxTSlIcAGuwMZKAgGXME4XrALaiY0YpgooWiguIRvw2onwEfhvBhmF56k/Dqe4nOLldpqmmQAAAACAlybHfQEAAAAA3h7RCAAAAIAgGgEAAAAQRCMAAAAAgmgEAAAAQBCNAAAAAAiiEQAAAABBNAIAAAAgiEYAAAAABNEIAAAAgDA97gv8S/f7QVPdzvT+ls+d27z+r/vAs8mpVvP7/mJ5u7N0Xt6ebq2Wt83vP+Utr2/r5qHVfv96o7z1xjGqqfluefvr7Gd5u3z5tbz96Dt+177d3pW3e1dfylvvG6P6cDZb3h7Pn7Q6+9PRTnnb271odTav63FtpbztDw5bnb0+3C5vvXGMamFYzzs/Pg861a0/jQAAAAAIohEAAAAAQTQCAAAAIIhGAAAAAATRCAAAAIAgGgEAAAAQRCMAAAAAgmgEAAAAQBCNAAAAAAiiEQAAAACh0zTNuO8AAAAAwBvjTyMAAAAAgmgEAAAAQBCNAAAAAAiiEQAAAABBNAIAAAAgiEYAAAAABNEIAAAAgCAaAQAAABBEIwAAAACCaAQAAABAEI0AAAAACKIRAAAAAEE0AgAAACCIRgAAAAAE0QgAAACAIBoBAAAAEEQjAAAAAIJoBAAAAEAQjQAAAAAIohEAAAAAQTQCAAAAIIhGAAAAAATRCAAAAIDwBN5OLlf2CIO5AAAAAElFTkSuQmCC\n", 265 | "text/plain": [ 266 | "
" 267 | ] 268 | }, 269 | "metadata": {}, 270 | "output_type": "display_data" 271 | } 272 | ], 273 | "source": [ 274 | "shortened_img_flattened = img_flattened[:, 200:300]\n", 275 | "plt.figure(figsize = (20,1))\n", 276 | "plt.imshow(shortened_img_flattened)\n", 277 | "plt.axis('off')" 278 | ] 279 | }, 280 | { 281 | "cell_type": "markdown", 282 | "metadata": {}, 283 | "source": [ 284 | "Weird! Let's see how that compares to our old friend \"5\"." 285 | ] 286 | }, 287 | { 288 | "cell_type": "code", 289 | "execution_count": 11, 290 | "metadata": {}, 291 | "outputs": [ 292 | { 293 | "data": { 294 | "text/plain": [ 295 | "(-0.5, 99.5, 0.5, -0.5)" 296 | ] 297 | }, 298 | "execution_count": 11, 299 | "metadata": {}, 300 | "output_type": "execute_result" 301 | }, 302 | { 303 | "data": { 304 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAABMCAYAAADgM0c2AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA8lJREFUeJzt2s9r1wUcx3G/+4HE2Clregl0GQqZGV1GIl6EokuXwA4eBiZDCA/5F0QoBBH0w7vB2iGQnYTq0ghGpV4sNhzk8iBedDUaeMjvPt1CeLF4fzbGd67H4/ziw/vw5bPx5NNpmmYHAAAAADyur9cHAAAAALD1iEYAAAAABNEIAAAAgCAaAQAAABBEIwAAAACCaAQAAABAEI0AAAAACKIRAAAAAEE0AgAAACCIRgAAAACEgV4fsJZ9n3zcVLdDo8vl5+5+a35d98C/+vpbzRcnXyxvJw79UN5+O/5aedtc+6W8ZfON37rTan9x/vXy1juOjerfv6+8vTpzpbx96ed3yts9fsdPtDMLt8vbD+beLG+939iop2ZGytvp/d+0evbzX02Ut6Pnf2z1bDbX6tGXy9vJqS9aPfvEjdPlrXccG3XwRj3vfHpkqlPd+tIIAAAAgCAaAQAAABBEIwAAAACCaAQAAABAEI0AAAAACKIRAAAAAEE0AgAAACCIRgAAAAAE0QgAAACAIBoBAAAAEDpN0/T6BgAAAAC2GF8aAQAAABBEIwAAAACCaAQAAABAEI0AAAAACKIRAAAAAEE0AgAAACCIRgAAAAAE0QgAAACAIBoBAAAAEEQjAAAAAIJoBAAAAEAQjQAAAAAIohEAAAAAQTQCAAAAIIhGAAAAAATRCAAAAIAgGgEAAAAQRCMAAAAAwkCvD1jLib63m17f0D3+Sqv9pcuflbcvDA61PYeW/m665e2rH71X3g6ubN5Pc/juo/J25/2H5W1z/df1nMM2N7Bnd3l76vufytuTw3+s55wnxvv36n8bflt5pry9PDrd6o7l1fo77t3njrZ6NvzfLI2Plbd/vbFS3vbdHC5v585eKm/b+PD+gVb72WMj5W33z+Xythk7XN7+fq7+v9bekzfLW+C/9e96urztPlhq9ezFqUPl7cKxL8vbIxfOlrfPfj5b3m53361+3alufWkEAAAAQBCNAAAAAAiiEQAAAABBNAIAAAAgiEYAAAAABNEIAAAAgCAaAQAAABBEIwAAAACCaAQAAABAEI0AAAAACJ2maXp9AwAAAABbjC+NAAAAAAiiEQAAAABBNAIAAAAgiEYAAAAABNEIAAAAgCAaAQAAABBEIwAAAACCaAQAAABAEI0AAAAACKIRAAAAAEE0AgAAACCIRgAAAAAE0QgAAACAIBoBAAAAEEQjAAAAAIJoBAAAAEAQjQAAAAAIohEAAAAAQTQCAAAAIIhGAAAAAATRCAAAAIAgGgEAAAAQRCMAAAAAwj8FUmuR67I1hgAAAABJRU5ErkJggg==\n", 305 | "text/plain": [ 306 | "
" 307 | ] 308 | }, 309 | "metadata": {}, 310 | "output_type": "display_data" 311 | } 312 | ], 313 | "source": [ 314 | "img_flattened_2 = np.reshape(img_arr_2, (1, 784)) # 28x28 = 784\n", 315 | "shortened_img_flattened_2 = img_flattened_2[:, 200:300]\n", 316 | "\n", 317 | "plt.figure(figsize = (20,1))\n", 318 | "plt.imshow(shortened_img_flattened, interpolation='none')\n", 319 | "plt.axis('off')\n", 320 | "plt.subplot(2, 1, 1) # total rows, total columns, position (row*column)\n", 321 | "plt.imshow(shortened_img_flattened)\n", 322 | "plt.axis('off')\n", 323 | "plt.subplot(2, 1, 2)\n", 324 | "plt.imshow(shortened_img_flattened_2)\n", 325 | "plt.axis('off')" 326 | ] 327 | }, 328 | { 329 | "cell_type": "markdown", 330 | "metadata": {}, 331 | "source": [ 332 | "Interesting -- it seems like there might be something there. There are high values on the \"5\" where there are low values on the \"4\", and vice-versa. Much like how the random forest identified risk factors in the stroke dataset, a random forest can also identify these informative pixels that may lead to a classification of an image as a \"4\" or a \"5\".\n", 333 | "\n", 334 | "To train an algorithm to separate these 4s and 5s, we will need a lot of images. We _could_ write some code to download a massive dataset of images of 4s and 5s from the internet, flatten those images individually, and concatenate each flattened image into a new row of a pandas array. Lord knows that if you continue in data science, you will have to write code like that, but today, thankfully, someone else has done the hard work for you. In this case, you'll simply need to load a dataset we've attached to this lesson called \"mnist.csv\"." 335 | ] 336 | }, 337 | { 338 | "cell_type": "code", 339 | "execution_count": 13, 340 | "metadata": { 341 | "scrolled": true 342 | }, 343 | "outputs": [ 344 | { 345 | "name": "stderr", 346 | "output_type": "stream", 347 | "text": [ 348 | "'wget' is not recognized as an internal or external command,\n", 349 | "operable program or batch file.\n" 350 | ] 351 | }, 352 | { 353 | "data": { 354 | "text/html": [ 355 | "
\n", 356 | "\n", 369 | "\n", 370 | " \n", 371 | " \n", 372 | " \n", 373 | " \n", 374 | " \n", 375 | " \n", 376 | " \n", 377 | " \n", 378 | " \n", 379 | " \n", 380 | " \n", 381 | " \n", 382 | " \n", 383 | " \n", 384 | " \n", 385 | " \n", 386 | " \n", 387 | " \n", 388 | " \n", 389 | " \n", 390 | " \n", 391 | " \n", 392 | " \n", 393 | " \n", 394 | " \n", 395 | " \n", 396 | " \n", 397 | " \n", 398 | " \n", 399 | " \n", 400 | " \n", 401 | " \n", 402 | " \n", 403 | " \n", 404 | " \n", 405 | " \n", 406 | " \n", 407 | " \n", 408 | " \n", 409 | " \n", 410 | " \n", 411 | " \n", 412 | " \n", 413 | " \n", 414 | " \n", 415 | " \n", 416 | " \n", 417 | " \n", 418 | " \n", 419 | " \n", 420 | " \n", 421 | " \n", 422 | " \n", 423 | " \n", 424 | " \n", 425 | " \n", 426 | " \n", 427 | " \n", 428 | " \n", 429 | " \n", 430 | " \n", 431 | " \n", 432 | " \n", 433 | " \n", 434 | " \n", 435 | " \n", 436 | " \n", 437 | " \n", 438 | " \n", 439 | " \n", 440 | " \n", 441 | " \n", 442 | " \n", 443 | " \n", 444 | " \n", 445 | " \n", 446 | " \n", 447 | " \n", 448 | " \n", 449 | " \n", 450 | " \n", 451 | " \n", 452 | " \n", 453 | " \n", 454 | " \n", 455 | " \n", 456 | " \n", 457 | " \n", 458 | " \n", 459 | " \n", 460 | " \n", 461 | " \n", 462 | " \n", 463 | " \n", 464 | " \n", 465 | " \n", 466 | " \n", 467 | " \n", 468 | " \n", 469 | " \n", 470 | " \n", 471 | " \n", 472 | " \n", 473 | " \n", 474 | " \n", 475 | " \n", 476 | " \n", 477 | " \n", 478 | " \n", 479 | " \n", 480 | " \n", 481 | " \n", 482 | " \n", 483 | " \n", 484 | " \n", 485 | " \n", 486 | " \n", 487 | " \n", 488 | " \n", 489 | " \n", 490 | " \n", 491 | " \n", 492 | " \n", 493 | " \n", 494 | " \n", 495 | " \n", 496 | " \n", 497 | " \n", 498 | " \n", 499 | " \n", 500 | " \n", 501 | " \n", 502 | " \n", 503 | " \n", 504 | " \n", 505 | " \n", 506 | " \n", 507 | " \n", 508 | " \n", 509 | " \n", 510 | " \n", 511 | " \n", 512 | " \n", 513 | " \n", 514 | " \n", 515 | " \n", 516 | " \n", 517 | " \n", 518 | " \n", 519 | " \n", 520 | " \n", 521 | " \n", 522 | " \n", 523 | " \n", 524 | " \n", 525 | " \n", 526 | " \n", 527 | " \n", 528 | " \n", 529 | " \n", 530 | " \n", 531 | " \n", 532 | " \n", 533 | " \n", 534 | " \n", 535 | " \n", 536 | " \n", 537 | " \n", 538 | " \n", 539 | " \n", 540 | " \n", 541 | " \n", 542 | " \n", 543 | " \n", 544 | " \n", 545 | " \n", 546 | " \n", 547 | " \n", 548 | " \n", 549 | " \n", 550 | " \n", 551 | " \n", 552 | " \n", 553 | " \n", 554 | " \n", 555 | " \n", 556 | " \n", 557 | " \n", 558 | " \n", 559 | " \n", 560 | " \n", 561 | " \n", 562 | " \n", 563 | " \n", 564 | " \n", 565 | " \n", 566 | " \n", 567 | " \n", 568 | " \n", 569 | " \n", 570 | " \n", 571 | " \n", 572 | " \n", 573 | " \n", 574 | " \n", 575 | " \n", 576 | " \n", 577 | " \n", 578 | " \n", 579 | " \n", 580 | " \n", 581 | " \n", 582 | " \n", 583 | " \n", 584 | " \n", 585 | " \n", 586 | " \n", 587 | " \n", 588 | " \n", 589 | " \n", 590 | " \n", 591 | " \n", 592 | " \n", 593 | " \n", 594 | " \n", 595 | " \n", 596 | " \n", 597 | " \n", 598 | " \n", 599 | " \n", 600 | " \n", 601 | " \n", 602 | " \n", 603 | " \n", 604 | " \n", 605 | " \n", 606 | " \n", 607 | " \n", 608 | " \n", 609 | " \n", 610 | " \n", 611 | " \n", 612 | " \n", 613 | " \n", 614 | " \n", 615 | " \n", 616 | " \n", 617 | " \n", 618 | " \n", 619 | " \n", 620 | " \n", 621 | " \n", 622 | " \n", 623 | " \n", 624 | " \n", 625 | " \n", 626 | " \n", 627 | " \n", 628 | " \n", 629 | " \n", 630 | " \n", 631 | " \n", 632 | " \n", 633 | " \n", 634 | " \n", 635 | " \n", 636 | " \n", 637 | " \n", 638 | "
labelpixel0pixel1pixel2pixel3pixel4pixel5pixel6pixel7pixel8...pixel774pixel775pixel776pixel777pixel778pixel779pixel780pixel781pixel782pixel783
04000000000...0000000000
15000000000...0000000000
25000000000...0000000000
34000000000...0000000000
44000000000...0000000000
54000000000...0000000000
64000000000...0000000000
74000000000...0000000000
85000000000...0000000000
95000000000...0000000000
\n", 639 | "

10 rows × 785 columns

\n", 640 | "
" 641 | ], 642 | "text/plain": [ 643 | " label pixel0 pixel1 pixel2 pixel3 pixel4 pixel5 pixel6 pixel7 \\\n", 644 | "0 4 0 0 0 0 0 0 0 0 \n", 645 | "1 5 0 0 0 0 0 0 0 0 \n", 646 | "2 5 0 0 0 0 0 0 0 0 \n", 647 | "3 4 0 0 0 0 0 0 0 0 \n", 648 | "4 4 0 0 0 0 0 0 0 0 \n", 649 | "5 4 0 0 0 0 0 0 0 0 \n", 650 | "6 4 0 0 0 0 0 0 0 0 \n", 651 | "7 4 0 0 0 0 0 0 0 0 \n", 652 | "8 5 0 0 0 0 0 0 0 0 \n", 653 | "9 5 0 0 0 0 0 0 0 0 \n", 654 | "\n", 655 | " pixel8 ... pixel774 pixel775 pixel776 pixel777 pixel778 \\\n", 656 | "0 0 ... 0 0 0 0 0 \n", 657 | "1 0 ... 0 0 0 0 0 \n", 658 | "2 0 ... 0 0 0 0 0 \n", 659 | "3 0 ... 0 0 0 0 0 \n", 660 | "4 0 ... 0 0 0 0 0 \n", 661 | "5 0 ... 0 0 0 0 0 \n", 662 | "6 0 ... 0 0 0 0 0 \n", 663 | "7 0 ... 0 0 0 0 0 \n", 664 | "8 0 ... 0 0 0 0 0 \n", 665 | "9 0 ... 0 0 0 0 0 \n", 666 | "\n", 667 | " pixel779 pixel780 pixel781 pixel782 pixel783 \n", 668 | "0 0 0 0 0 0 \n", 669 | "1 0 0 0 0 0 \n", 670 | "2 0 0 0 0 0 \n", 671 | "3 0 0 0 0 0 \n", 672 | "4 0 0 0 0 0 \n", 673 | "5 0 0 0 0 0 \n", 674 | "6 0 0 0 0 0 \n", 675 | "7 0 0 0 0 0 \n", 676 | "8 0 0 0 0 0 \n", 677 | "9 0 0 0 0 0 \n", 678 | "\n", 679 | "[10 rows x 785 columns]" 680 | ] 681 | }, 682 | "execution_count": 13, 683 | "metadata": {}, 684 | "output_type": "execute_result" 685 | } 686 | ], 687 | "source": [ 688 | "!wget -O mnist.csv https://www.dropbox.com/s/zzltdvylq6sj25j/mnist.csv?dl=1\n", 689 | "import pandas as pd # common abbreviation\n", 690 | "data = pd.read_csv('mnist.csv') # load the comma separated value (CSV) file\n", 691 | "data.head(10) # show the first n rows of this file" 692 | ] 693 | }, 694 | { 695 | "cell_type": "markdown", 696 | "metadata": {}, 697 | "source": [ 698 | "It's kind of looking like the diabetes dataset now! For fun and knowledge, let's visualize some of the data like we did above." 699 | ] 700 | }, 701 | { 702 | "cell_type": "code", 703 | "execution_count": 14, 704 | "metadata": {}, 705 | "outputs": [ 706 | { 707 | "name": "stderr", 708 | "output_type": "stream", 709 | "text": [ 710 | "C:\\Users\\jxb29\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\ipykernel_launcher.py:4: FutureWarning: reshape is deprecated and will raise in a subsequent release. Please use .values.reshape(...) instead\n", 711 | " after removing the cwd from sys.path.\n" 712 | ] 713 | }, 714 | { 715 | "data": { 716 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAxNJREFUeJzt3b+rzXEcx/H3270DkjIzCHdh8aP8GMjAxCoyWBSRxY+/gMVmEiUTk+FmshmE5MdkZvFjshikO8jHIFHv1Oece9zvvXo8tnN6dXpP3+HZt0621gIAAAAA/rRs6AMAAAAAWHxEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAJinzJzJzLnMvDv0LQAAkyIaAQDM3/WIeDn0EQAAkyQaAQDMQ2Yei4jPEfFw6FsAACZJNAIAGFNmro6IyxFxcehbAAAmTTQCABjflYi43Vp7P/QhAACTNj30AQAAS1Fmbo2IAxGxbehbAAD+BdEIAGA8+yNifUS8y8yIiFURMZWZm1tr2we8CwBgIrK1NvQNAABLTmaujIjVf3x1KX5GpDOttU+DHAUAMEHeNAIAGENr7WtEfP31OTO/RMScYAQA/C+8aQQAAABA4d/TAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAACimhz7gbw4uO7Lk/tbt1rsn3duDz852b9cffT3OOYxgamZD9/bBo9mRfnvf2VPd2xX3X4z027BQPs5u6d4e3/Sqe/t455qR7vg+NzfSnp/+1TNu77nT3duVs8+7t7DQ3lzb3b19e/Rm9/bQrsPd22/vP3Rv+W163dru7bWn97q3J89fGOkOzzgWq88n9nRvn1+90b0d5fkW4Rm3EDa+XN69vbnjTvZuvWkEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFBka23oGwAAAABYZLxpBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFD8APHxZvey+YJgAAAAASUVORK5CYII=\n", 717 | "text/plain": [ 718 | "
" 719 | ] 720 | }, 721 | "metadata": {}, 722 | "output_type": "display_data" 723 | }, 724 | { 725 | "data": { 726 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA01JREFUeJzt3b1r1WcYx+H7TuILoYMZugiCDmp1kICIm3aRDlpwESp2LgoW/CMEcVXnjl2chAotVhDBgopjRW2r4GKthS5SQu3J45JBuBGe5Bz45eW64GxfDvcQTsIn5yTZWgsAAAAA+NDU0AcAAAAAsPqIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEADCGzLyTmQuZ+Xbp8XTomwAAJkE0AgAY3/nW2idLj71DHwMAMAmiEQAAAACFaAQAML5Lmfl3Zt7LzM+HPgYAYBKytTb0DQAAa1ZmHo6IxxHxX0R8FRHXImK+tfbHoIcBAIxJNAIAmKDM/DEibrbWrg59CwDAOHw8DQBgslpE5NBHAACMSzQCAFihzNyWmV9k5tbMnMnMMxFxJCJ+Gvo2AIBxzQx9AADAGrYpIi5GxGcRMYqIJxFxsrX2dNCrAAAmwN80AgAAAKDw8TQAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAAipmhD/iYY1On/Fu3FZjev6d7e/bGD93b47NvV3JOly+fneje/vtuc/c2s/9LqLXs3q4WF3b93L09uvWv7u3B2992b/ee/bV7u7iw0L1l45ianV3Wfvfdd93bK9sfdm9HbbF7e+jR6e7tpyd/797G4qh/u85Nz811b19+s29Zz73n+G/d24VT/d8bRq/7X2fZOJ5/P9+9fXL0u+7tdPb/3vfAg/7XrIiIHef+6d7+/+rPZT03sH5cfnF/Wfv5LVu6t/t/+bp7u/Pc6+7t6M2b7u16d2vxevcPOd5pBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQZGtt6BsAAAAAWGW80wgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAACjeAxaYboDIUWFGAAAAAElFTkSuQmCC\n", 727 | "text/plain": [ 728 | "
" 729 | ] 730 | }, 731 | "metadata": {}, 732 | "output_type": "display_data" 733 | }, 734 | { 735 | "data": { 736 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAy5JREFUeJzt3c+LzXscx/H3e4whyeha+BMohUiykcWVrNiQyD8gf4QuZcWGbFi4XTbYTvmxURJlZyET/gClULPAvXc+NhbqTX3GOdN3Ro9Hnd1r8V6cTqfnnDMnW2sBAAAAAN+bGPoAAAAAAJYe0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAABGkJkPM/NTZs59e8wOfRMAwDiIRgAAozvdWlv77bFp6GMAAMZBNAIAAACgEI0AAEZ3PjPfZebjzNw39DEAAOOQrbWhbwAAWLYyc3dEvIiILxFxLCIuR8T21tqbQQ8DABiRaAQAMEaZeTciZlprl4a+BQBgFL6eBgAwXi0icugjAABGJRoBAPyizFyfmQcyc3VmTmbmiYjYGxH3hr4NAGBUk0MfAACwjK2MiHMRsTki/o+IlxFxuLU2O+hVAABj4H8aAQAAAFD4ehoAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAxeTQB/zM/okjy+5n3T6c3NO9vX/+Yvd2TU51b+djvnu7mDbPnOreTr3tfxpOv+6/4Y+bz7q3c4d2dm+nPv7Xf0REvN+0qnv7Yeu/3duNj1Z0b6dvPO3ewo+8+ntH93b2z6vd25XZ/zyOiLg1N929vXD2ePd2/T9PFnQHsLTlzi0L2v9153r3dlv/27KYWMDfZ/c+P9q9XXfwTf8RwG/n88Fd3dt7164syg0LeX2LiNhz5nT3dsNV78sW24P529m79UkjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIAiW2tD3wAAAADAEuOTRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQPEVgJZfgGulr5IAAAAASUVORK5CYII=\n", 737 | "text/plain": [ 738 | "
" 739 | ] 740 | }, 741 | "metadata": {}, 742 | "output_type": "display_data" 743 | }, 744 | { 745 | "data": { 746 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA0xJREFUeJzt3b+r1XUcx/H323sTFLtuCoKigw1CkBINOqigm+AkODgoSKAWkT9oUyjwDxBtiaDhOjmIDi4qbhEqItoagoIQLgqhNtTH4SJKb4XPOffEV+Xx2M7hxeE9nOnJF77ZWgsAAAAAeN2CoQ8AAAAA4N0jGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAMA8ZebazHyembND3wIAMCmiEQDA/J2JiBtDHwEAMEmiEQDAPGTm7oh4HBFXh74FAGCSRCMAgDFl5kxEfB8RR4a+BQBg0kQjAIDx/RARP7fWHgx9CADApE0PfQAAwPsoMz+LiG0RsX7oWwAA/g+iEQDAeLZExOqIuJ+ZERFLImIqM9e11jYMeBcAwERka23oGwAA3juZuTgiZl776mjMRaQDrbVHgxwFADBBnjQCABhDa+1pRDx9+Tkz/4qI54IRAPCh8KQRAAAAAIW3pwEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQTA99wNtsX7DLa93G8PD8uu7t7S9mu7efn/xqpDuWnfl1pD1z/tm6oXv70y+nurerphd3bzd9d7B7u3T2t+4tvEl+tHCk/ZOLK7u3lz89273d88fO7u2zzX92b3llamame3v89rXu7YrpZyPdsefrw93bRReuj/Tb8F9Ty5d1bzdfude93fHxne7tN/sOdW8jIqau3Rppz5yHxzZ2b+9++2P3ds2l/d3bT/bf7N7CfN0/0f+fj4j4/cvT3dsbf/engBO79/Yfcf1u//YDd/nfc9m79aQRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAECRrbWhbwAAAADgHeNJIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoHgBf7xevUBDeNkAAAAASUVORK5CYII=\n", 747 | "text/plain": [ 748 | "
" 749 | ] 750 | }, 751 | "metadata": {}, 752 | "output_type": "display_data" 753 | }, 754 | { 755 | "data": { 756 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA01JREFUeJzt3U2LlmUYx+Hz9GWTNi2ERDA0yEUuxAmEIBShEfwCYRCYK6Fop7gWo5Vkq9lIQajg9AVa9LIRMcEP0BBNRq40qIjQodLLhQjCiXDdM89wzwzHsXuGPzcns3r4ccOTrbUAAAAAgGdtGPsAAAAAAFYf0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAACWKTP3ZOZiZl4Z+xYAgEkRjQAAlm82Im6NfQQAwCSJRgAAy5CZ70bEXxHx/di3AABMkmgEALBEmTkVEeci4tTYtwAATJpoBACwdB9HxBettTtjHwIAMGmbxj4AAGAtysz9ETETEdNj3wIAsBJEIwCApTkcEbsj4rfMjIjYGhEbM3Nva+2NEe8CAJiIbK2NfQMAwJqTmS9ExNQzfzodTyLSB62130c5CgBggrxpBACwBK21+xFx/+nnzPwnIhYFIwBgvfCmEQAAAACFX08DAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoNg09gHPc2TDO37WbYVt3P5y93b+/M5Bz3797B/d2/9/+XXQs8f26OD0oP3Xc593b/98tNi9PfH28e7tw58WurewXrx0fVv39uqr33Zvpy981L3d8emN7u1qsf2Hqe7tpV3Xurd7Zz/s3r7yydr7v8Fy/Xzhze7t/LHZ7u03D7YMumP2rUPd24d37w169koY8n32zI3vurevbf570B0nZ97v3vpexnrw79EDg/aXL37Wvf1vQAl478zp7u2LX93sf/AqcXtuX/f2x4Nfdm8371jI3q03jQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAAimytjX0DAAAAAKuMN40AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIDiMfz1ZL2YUtVQAAAAAElFTkSuQmCC\n", 757 | "text/plain": [ 758 | "
" 759 | ] 760 | }, 761 | "metadata": {}, 762 | "output_type": "display_data" 763 | }, 764 | { 765 | "data": { 766 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAzZJREFUeJzt3b+r1XUcx/H323shEjGcGiJQSIhL0NVJa7mDgjdaJf+DqDuUFC4Ogi5OXQjsxyA4FLg6eRcnwYJwipYmqaHAhgt1LxeE+2kI8eJb8fM999y+V3k8tnN58eU9XM7w5AsnW2sBAAAAAFvtGfsAAAAAAHYf0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAC2KTMPZ+ZGZn439i0AANMiGgEAbN+ViPhp7CMAAKZJNAIA2IbMPBMRqxFxa+xbAACmSTQCAJhQZu6PiIsR8dnYtwAATJtoBAAwuUsRcbW19vvYhwAATNvs2AcAADyPMnM+Ik5ExJGxbwEA2AmiEQDAZBYi4mBE/JaZERH7ImImM+daa0dHvAsAYCqytTb2DQAAz53M3BsR+7f86fP4LyJ91Fq7P8pRAABT5E0jAIAJtNbWI2L94efM/CciNgQjAOBF4U0jAAAAAAq/ngYAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAMTv2AU9zcs/pF/pn3TZvvd69XXnzRvd27tpS9/bg+R+6t0zurw+Pd2/vXvi6ezt/+ePu7atf3unewpPMvHGoe7u0crN7e+rl9WePtnj3XP///Svf/zjo2Qy3+Mtq9/bTA/e6t77f+L/9/cGx7u3tL77akRvee+3ojjyXR9rxt7u3316/MujZ9zdf6t5eeGuhe7u5tjboDnjckO+3O8vfdG/f/3Vx0B0PFv4YtGe4Pz95p3v78/LZ7N160wgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoMjW2tg3AAAAALDLeNMIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAo/gXHtV29TgDtfwAAAABJRU5ErkJggg==\n", 767 | "text/plain": [ 768 | "
" 769 | ] 770 | }, 771 | "metadata": {}, 772 | "output_type": "display_data" 773 | }, 774 | { 775 | "data": { 776 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA4NJREFUeJzt3b9r3XUUx+FzkghS2kL/ALGiVenkjy51EtHBwUGw6thBDJZOVnByURR0cdEiiIs4imBdFFHqJKhFEQcrOvijCHXRUuPF2nwcVCgciic3V76JPM+W8CYcQgg3r3zh5hgjAAAAAOBSS1MfAAAAAMDWIxoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQDAJmXmvsycZeZrU98CALAoohEAwOa9GBEfT30EAMAiiUYAAJuQmQ9GxM8R8d7UtwAALJJoBAAwp8zcHRFPRsSxqW8BAFg00QgAYH5PRcQrY4zvpz4EAGDRVqY+AABgO8rMmyLizoi4eepbAAD+C6IRAMB8bo+IvRHxXWZGROyMiOXM3D/GuGXCuwAAFiLHGFPfAACw7WTmjojYfcmnHou/ItIjY4yfJjkKAGCBPGkEADCHMcZaRKz983Fmno+ImWAEAPxfeNIIAAAAgMK7pwEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQrEx9wOXctXTI27ptY8vXX9verrz8a3t7Yt/b7e3Fsd7enr249u+jv73/29XtbUTEE+/e195e9U7/x/7Ktz7a0B3A5Z15/Lb29s0jz7W3e1d2tLcnZ1e0txERR19dbW9/39P/ffjVoePt7XL2//f0zYXz7e3Rex5qb9c//7K9ha3sjztubW9XX3q9vb1/5y/znNNyzYmH29sbj59rb/PM2fb28Ien2tuNfC+uO3m4vY2IePbAG+3tB+duaG9PH7iwoTtgM5Z27WpvTz+9f0Nf+9S9z7e3e5b7r59WfzjY3n57pP83an7xdXu7Ppu1tz8+2n/NGRHx6bEX2tuDnz3Q3n5y9zPZ3XrSCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgyDHG1DcAAAAAsMV40ggAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAACj+BAEqc71E82C/AAAAAElFTkSuQmCC\n", 777 | "text/plain": [ 778 | "
" 779 | ] 780 | }, 781 | "metadata": {}, 782 | "output_type": "display_data" 783 | }, 784 | { 785 | "data": { 786 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA0tJREFUeJzt3b9rVXcYx/HnSWIHKXYVXExpMhQL1SJkdFAhuBUKrqUO1VXxD6iLs+AkKQ4qOohbIWChdJBCLV06mdJC6yIOOvgjHeK3gwqRB+Gc5B5P1Ndru+Hh8lly4L65cLO1FgAAAACw3tTYAwAAAADYekQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIA2KTMnMvM1cy8NPYWAIBJEY0AADbvfET8OvYIAIBJEo0AADYhM49GxMOI+HHsLQAAkyQaAQBsUGbuiIjvIuLk2FsAACZNNAIA2LgzEbHUWvt37CEAAJM2M/YAAIC3UWZ+HhEHI2Lv2FsAAIYgGgEAbMyBiNgdEf9kZkTEhxExnZmfttb2jbgLAGAisrU29gYAgLdOZm6PiB3r/nQqnkek4621+6OMAgCYIN80AgDYgNbak4h48vJ1Zj6KiFXBCAB4V/imEQAAAACFX08DAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoJgZe8DrHJr6ys+6vfB0ebbz7c+f3Rhkw+zyN73u57/+bZAdQ8mZ7v8K965/0uu9f99/te+ciVs4/W3n248u/TLgEnjVf4v7e93/tHRhkB17zp3ofLvr7K1BNgxp7cC+zrc3r3w/yIYv/zzU+fbxqZ2db6dX7vbasfbgQa972Iw7F7o/4/4+MszzbfHjhV73z1ZXB9kxlJWLX3S+/evw0mA7Zn841vl2/tjtwXbAm9LnM2rEcJ9T+zzjtsLzLbd90Ov+7rW5zrd/LFzufDu1cyU733Z+VwAAAADeG6IRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAEW21sbeAAAAAMAW45tGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABA8T+6g2O9Xjn1iQAAAABJRU5ErkJggg==\n", 787 | "text/plain": [ 788 | "
" 789 | ] 790 | }, 791 | "metadata": {}, 792 | "output_type": "display_data" 793 | }, 794 | { 795 | "data": { 796 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAyJJREFUeJzt3c+rzXkcx/H3W2fqioVZKSkshNREiZ3UEAuL2Uwpf4DIwmzveoo1ln6UjQU7o0jKhlvKYu7CoMRKTc2OuEPjMxsL9U59nB99763Ho87u3e11N7dzn+ece7O1FgAAAADwtVVDDwAAAABg+RGNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAYAKZ+SAzlzLz3ZfH86E3AQBMg2gEADC50621tV8e24YeAwAwDaIRAAAAAIVoBAAwubOZ+U9mPszMA0OPAQCYhmytDb0BAGDFysx9EfE0Ij5GxLGIuBgRu1prLwcdBgAwIdEIAGCKMvNORNxurV0YegsAwCR8PA0AYLpaROTQIwAAJiUaAQCMKTPXZebhzJzLzFFmHo+I/RFxd+htAACTGg09AABgBfshIn6PiO0R8V9EPIuIX1przwddBQAwBf6mEQAAAACFj6cBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIyGHvAth1b9uuL+rdtoy6bu20N//Nl9e+bH1923/7ZP3bc77p/ovl3911z37Sy939z//V09eHmGS/ptGL3tvj26cLL7dsuxxXHmwFheXNnTffvqyKWZ7Zj/+6fu2ye7vS4ya7l7Z/fth41rum/nbj0eZw6MbTn8jNt17lT37frzj2ayAVgZctT/a/ybm1u7bxf3Xu++ffd5qfs2IuLn+d+6b9ddW/iur833u/f5RvbeekYNAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFBka23oDQAAAAAsM95pBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFP8DrUNhgB5fCksAAAAASUVORK5CYII=\n", 797 | "text/plain": [ 798 | "
" 799 | ] 800 | }, 801 | "metadata": {}, 802 | "output_type": "display_data" 803 | }, 804 | { 805 | "data": { 806 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA4NJREFUeJzt3buLnHUUx+FzdldzIZCLoMEiiI1Js6yVnaQRkTQREYSACHaiTfwDDCgI0U4rQQISCKQQLMQVGwlEsQhWXiYgeFmsVDCucc0m+dmsKByE3+vM8G70eWC6L8Pplv3wzky21gIAAAAA/m5h7AMAAAAA2H5EIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAJhCZn6YmRuZub71mox9EwDALIhGAADTe7a1tmfrdd/YxwAAzIJoBAAAAEAhGgEATO/lzPwhMy9m5tGxjwEAmIVsrY19AwDALSszH4iIzyPiWkQ8ERGvR8RKa+2rUQ8DAJiSaAQAMEOZuRoR77bWXhv7FgCAafh4GgDAbLWIyLGPAACYlmgEAPAvZea+zHw4M3dm5lJmnoiIByPi/bFvAwCY1tLYBwAA3MJui4iXIuJwRNyIiC8j4nhrbTLqVQAAM+A7jQAAAAAofDwNAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgGJp7AP+yUMLj/tZty2Ldxzo3q49dbh7++vKb93bHZd3dW8jIo49+nH39pWDn3ZvL2z033D620f6x9vE7y8c7N7ePvm+e9s2N7u3N378qXvL/8fC7t3d229OrnRvX3zy7KA7HttzZdCe/77z63sH7U+9dWIudxx67+fubbv02Vxu4C+L+/cP2m8u39O9/eDcmYHXzN7q1R3d2ys3dw567zsXf+neHt11s3u7dn29e/vJxt3dW38X5u/IG88M2h869dGcLuFP66v3dm8vLr89lxu+uHZ10P7YOye7t0deXeveXv+uf7uw3P+/8uTpfd3bvZP+Z3HuevNS9zYi4vLp+wfte3393PPZu/WkEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAka21sW8AAAAAYJvxpBEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFD8AWGAfIAMcTQ6AAAAAElFTkSuQmCC\n", 807 | "text/plain": [ 808 | "
" 809 | ] 810 | }, 811 | "metadata": {}, 812 | "output_type": "display_data" 813 | }, 814 | { 815 | "data": { 816 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA1RJREFUeJzt3b2LlGcUxuFzdKMiYau0iggrKAbURBCbhBAj2BgLP5okRZq1SrEBq0RI/gAr8wERLGJlYZFWLazEIIiCNtqshYgpwiIiJPqkkBDlEHh2dobXda+rm+FmOMU08+OFydZaAAAAAMDLVg19AAAAAACvH9EIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAligzZzLzaWb+OvQtAADjIhoBACzd6Yj4fegjAADGSTQCAFiCzDwWEX9GxKWhbwEAGCfRCABgRJk5HRHfRcTc0LcAAIybaAQAMLrvI+JMa+3+0IcAAIzb1NAHAAAsR5m5IyI+joidQ98CADAJohEAwGg+jIhNETGfmRERb0fE6szc1lrbNeBdAABjka21oW8AAFh2MnN9REy/9NbX8SIiHW+tPRrkKACAMfKkEQDACFprTyLiyb+vM/NxRDwVjACAN4UnjQAAAAAo/HsaAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAMXU0Af8n32rDi+7v3V7MLe3e3tz7oeJ3LD5/Gz3duarqxO5gVf98duW7u2P2891b08e+qJ7+/zG7e4tK0fufrd7e+r8z93brWvWj3JOl/2fftY/vnZrYne8yaY2bezefnP5Qvd2z7rV3duPPv+ye/vWxevdW1aOvz55f1H7y2d/mcgd710/0r195+C9/g9+/myEa7h7ak/39t7Rnxb12Sce7uje3vpgunv7bGFhUXewMsx/2/+7887sZH53zv/9eFH72e0Hure+9//JtWu7txuu9OedM7vPZu/Wk0YAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAEW21oa+AQAAAIDXjCeNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACA4h/b62K9oBkuOQAAAABJRU5ErkJggg==\n", 817 | "text/plain": [ 818 | "
" 819 | ] 820 | }, 821 | "metadata": {}, 822 | "output_type": "display_data" 823 | }, 824 | { 825 | "data": { 826 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAv5JREFUeJzt3bGrzXEYx/Hn4SLCZKAMBtcgiZsUE8WfIDYyKGVjsSiEMpiIxaYMStkIqwGbMpCSuzEw6GTyNUipJ/qee49+XK/Xdk6fTs/87lsnW2sBAAAAAD9bNPQBAAAAAPx9RCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgCYp8yczswvmXlr6FsAACZFNAIAmL9rEfFs6CMAACZJNAIAmIfMPBQRnyLi8dC3AABMkmgEADBHmbk6Is5FxMmhbwEAmDTRCABg7s5HxM3W2uzQhwAATNrU0AcAAPyLMnNbROyLiO1D3wIA8CeIRgAAc7MnIjZExLvMjIhYGRGLM3Nza21mwLsAACYiW2tD3wAA8M/JzBURsfqnr07F94h0vLX2YZCjAAAmyEsjAIA5aK2NImL043Nmfo6IL4IRALBQeGkEAAAAQOHf0wAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAopoY+4Ff2Lzrgb93gN95e2NW9fXnkWvf2ysfp7u2jLau6t8D/bWrd2u7tjvuz3dsza16MdcfGB8e6t5uOPh/rt2E+Xl3f2b09u/du9/b2zKax7vg6Go21X6hyydKx9q8vz3Rv3xy80b29P1rWvb148nD3dvm9p91bmIT3J3Z3b5+fvtq93Xr1RPd2/aUn3duF7uHXO9m79dIIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKDI1trQNwAAAADwl/HSCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKL4BgyxRvVDd8S0AAAAASUVORK5CYII=\n", 827 | "text/plain": [ 828 | "
" 829 | ] 830 | }, 831 | "metadata": {}, 832 | "output_type": "display_data" 833 | }, 834 | { 835 | "data": { 836 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAuZJREFUeJzt3SGLVFEYx+H3XTctslWxaLGYVosaFINiNogmq4hRP4F+ANOCBovYzQaLBhGLXQ0qCGIRkWXbMaiw8CLMnb13z+zwPG2Xw/CHZc6wPy5MttYCAAAAAHZa6T0AAAAAgMUjGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAMAuZebxzNzOzKe9twAAjEU0AgDYvc2IeNt7BADAmEQjAIBdyMzrEfEjIl703gIAMCbRCABgTpm5HhH3IuJO7y0AAGMTjQAA5nc/Ih631r70HgIAMLbV3gMAAPajzNyIiIsRcbL3FgCAKYhGAADzuRARxyLic2ZGRByMiAOZeaK1dqrjLgCAUWRrrfcGAIB9JzPXImJ9x6/uxp+IdKu19r3LKACAEXnSCABgDq21rYjY+vdzZv6KiG3BCABYFp40AgAAAKDw7WkAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKu9B/zPpZWrvtbtr60rp2c++2rz0SQbbnw6P+j8t7M/J9mxCD48ODPo/MdrD2c+e+72zZnPrj17M2gH7JUh75Eh74+hhtxby3xnDbUIf7/LRzYmeV0Yw/Ov7yZ5XXfW9Bbhfotwx7G3Dr1en/nsk6MvJ9vh/5zpDfl8Wjn8Pmc+O9caAAAAAJaaaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAka213hsAAAAAWDCeNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAIrfTuhYvdzPghYAAAAASUVORK5CYII=\n", 837 | "text/plain": [ 838 | "
" 839 | ] 840 | }, 841 | "metadata": {}, 842 | "output_type": "display_data" 843 | }, 844 | { 845 | "data": { 846 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAuxJREFUeJzt3S9r1WEYx+H7nhuIDp1YRJioIBoFhTWxiDAMloEg+Aa0+wYEk0mbr0PQpAgLM1gEccEgVuOE4dgey4JwI/zOfmc+G14XnHaHbzknfM6/bK0FAAAAAPxppvcAAAAAAA4e0QgAAACAQjQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAABGyMx3mbmZmRu7j/XemwAApkE0AgAY71FrbX73cbn3GACAaRCNAAAAAChEIwCA8Z5m5o/MXM3Mm73HAABMQ7bWem8AADi0MnMpIj5HxK+IuBcRLyLiamvta9dhAAAjiUYAAFOUma8j4lVr7XnvLQAAY/h6GgDAdLWIyN4jAADGEo0AAPYoMxcy83ZmHs3M2cy8HxE3IuJN720AAGPN9h4AAHCIzUXEk4i4EhHbEfElIu621ta7rgIAmAK/aQQAAABA4etpAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSzvQf8za2ZFX/rBgD/2OzF84Nvt86cHHz7bfnYHtYM2HBqZ6L7O0sf92XHJNavb/WewH9kY2Vpovtrj4c/R07P/Zx0ziBHcvjzersNfw/8wcKHwbcX5uYH3x4U7zeH337aXBx8++zt8kQ7Lj1cm+gexji3dnzw7cvF1X1c0t/GzvAXgRNnv+fQW580AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAosrXWewMAAAAAB4xPGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAMVvE9xUgKJQ7MwAAAAASUVORK5CYII=\n", 847 | "text/plain": [ 848 | "
" 849 | ] 850 | }, 851 | "metadata": {}, 852 | "output_type": "display_data" 853 | }, 854 | { 855 | "data": { 856 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAzNJREFUeJzt3bFrlXcUx+FzTFwkhC4d4tRqO7RgqaIUhIKDWgpdLAhS6ODQQbpVFxcH/QccdBBxURFRd0GwgwhabOjmULUUHdriIhJCKMLPQQThIPzuzQ1vEp5nu5cvL2e8fHjhZmstAAAAAOBdG4Y+AAAAAIDVRzQCAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoBCNAAAAAChEIwCAZcrMTzNzKTMvD30LAMCkiEYAAMt3NiIeDH0EAMAkiUYAAMuQmYci4kVE3B76FgCASRKNAADGlJmzEXEyIo4OfQsAwKSJRgAA4zsVERdaa8+GPgQAYNKmhz4AAGAtyswvI2JvRGwf+hYAgJUgGgEAjGdPRHwUEU8zMyJiJiKmMvPz1tqOAe8CAJiIbK0NfQMAwJqTmZsiYvadr47Fm4h0pLX2fJCjAAAmyJtGAABjaK0tRsTi28+ZuRARS4IRALBeeNMIAAAAgMK/pwEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQTA99wPvs23DQ37qxKv15btdI+8ffneveXl34sHt75duvu7ev/vq7ewvrxaMzX3Vv5+5k93bm2v1xzlkzPpvv/2lweu737u22337o3m4+8LB7C+vF1Ccfd29P3LrRvd2ycWmkOw7v+r57++rf/0Z69kr4/5ud3dtL5093b+emNo10x+7jP3dvP7h4b6Rnw3rwzy+7u7d/HD2zIjfs//Gn7u30r/MrcsOoXt7c2r29+8X17u3GuSfdP369aQQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUGRrbegbAAAAAFhlvGkEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUrwEf31e9CCt6AQAAAABJRU5ErkJggg==\n", 857 | "text/plain": [ 858 | "
" 859 | ] 860 | }, 861 | "metadata": {}, 862 | "output_type": "display_data" 863 | }, 864 | { 865 | "data": { 866 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAzpJREFUeJzt3T2IVGcUx+Fzdi1Ek60sLVTYxkI0sGgjSNBGLAwiaK1GtkgTLSzSJBYpk0YIRBuxC7GwEYsUEoL4RcAPIkYQTJc0KaJooa9FEISD8N7ZCXc3Pk+3w5/hMNXsjwuTrbUAAAAAgLfNjH0AAAAAAMuPaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAABLlJnzmfk8My+MfQsAwLSIRgAAS3cmIm6OfQQAwDSJRgAAS5CZhyLi74j4aexbAACmSTQCAJhQZs5FxFcRcWLsWwAApk00AgCY3OmIONda+2PsQwAApm3V2AcAAKxEmbk1InZHxLaxbwEA+C+IRgAAk9kVERsi4klmRkR8EBGzmbm5tfbRiHcBAExFttbGvgEAYMXJzDURMffWSyfj34i02Fr7a5SjAACmyJNGAAATaK09i4hnb/7OzH8i4rlgBAD8X3jSCAAAAIDCr6cBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUKwa+4B32TNz0M+6TeDRtzu6t/t33uje3lvIYYe8ejlsP7IPf17Xvf1+w6VB7334k0+7t+3WvUHvDSvdzOrVg/Zf/3a1e3vmz4+7t0+2Px10x0pz5OHj7u2Xd/d1b9cfuD/JOfDemFm7tnt7+fdfurebfjzevZ3/7Hr3drmYnZvr3p74tf9zW/yh/zvZxlPXurfwPnqxd2HQ/sJ333Rvj+072r19defBoDtGt2PLoPmVi+e7twtfLHZvb5/9vPsffE8aAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAU2Vob+wYAAAAAlhlPGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAMVrN5tbvcnNY0YAAAAASUVORK5CYII=\n", 867 | "text/plain": [ 868 | "
" 869 | ] 870 | }, 871 | "metadata": {}, 872 | "output_type": "display_data" 873 | }, 874 | { 875 | "data": { 876 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAyJJREFUeJzt3T2ozXEYwPHnua4yGMRiUV4GL6UsIgMWWQwMSqxsdzcrZTK5UiQLFouUIgOLbEzkJspmMLg3g9S9P8sd1EP9rnNu/3v1+dTZnn49nTrn/Puet2ytBQAAAAD8bmLoBQAAAABYeUQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAGEFmvsjMH5n5ffE2M/ROAADjIBoBAIxuqrW2fvG2c+hlAADGQTQCAAAAoBCNAABGdyUzv2bmy8w8OvQyAADjkK21oXcAAFi1MvNARLyLiJ8RcSYipiNiX2vt46CLAQCMSDQCABijzHwSEY9ba9eG3gUAYBS+ngYAMF4tInLoJQAARiUaAQD8o8zckJnHM3NdZk5m5rmIOBwRT4feDQBgVJNDLwAAsIqtjYjLEbErIuYj4n1EnGytzQy6FQDAGPhNIwAAAAAKX08DAAAAoBCNAAAAAChEIwAAAAAK0QgAAACAQjQCAAAAoJgceoG/OTZx2t+6LfrycHf37Ov997pnF6L/Lp6I7J5dzrNXwrlvfi50z0ZEnH11oXt288a57tnnex90z+65O9U9u/3iq+5Z+JPPlw51z749P72ks9dk/3sd863/sbqUc69/29I9e+fqie7ZTbc99mA1+HR/X/fsuyO3u2eX67rl5uzW7tmIiMcHt3XPzs/1X7cAK9+H6QP9s6duLOns5bqGuzXbf1326OCO/h3+8+e3ZwsPul90fNIIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKDI1trQOwAAAACwwvikEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUPwCGRtwgNb3J/EAAAAASUVORK5CYII=\n", 877 | "text/plain": [ 878 | "
" 879 | ] 880 | }, 881 | "metadata": {}, 882 | "output_type": "display_data" 883 | }, 884 | { 885 | "data": { 886 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAspJREFUeJzt3S+LlGEUxuFzlhEMBvEj+AcFiwYRDGIREYtFEPwAGta2yWAS/ACKZYNJixgXViwWUZNNXEHsslFBhPWxbBAOwrO+A88MXhdMO+FOb/jxzky21gIAAAAA/rQyegAAAAAAi0c0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAgAky81Vm/sjMb7ufrdGbAADmQTQCAJhutbV2YPdzfPQYAIB5EI0AAAAAKEQjAIDp7mfmdma+zswLo8cAAMxDttZGbwAAWFqZeTYiPkTEz4i4HhEPI+JUa+3z0GEAABOJRgAAc5SZmxGx0Vp7MHoLAMAUvp4GADBfLSJy9AgAgKlEIwCAf5SZBzPzUmbuz8xZZt6IiPMR8WL0NgCAqWajBwAALLF9EXEvIk5ExE5EfIyIq621raGrAADmwG8aAQAAAFD4ehoAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAxWz0gL+5uHJt6f7WLU+f7L7d3HjSfbu987379vLdte7bQ4/fdN8C/7evq+e6b9/fedR9e/j5zT3tOHb73Z7uAXp8Wj/Tffvlynr37dGnt7pvj6y97b4F6LUIz7cIz7hF8/LXs+y99aYRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAECRrbXRGwAAAABYMN40AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAACtEIAAAAgEI0AgAAAKAQjQAAAAAoRCMAAAAAit9PKVOA2V/CMQAAAABJRU5ErkJggg==\n", 887 | "text/plain": [ 888 | "
" 889 | ] 890 | }, 891 | "metadata": {}, 892 | "output_type": "display_data" 893 | }, 894 | { 895 | "data": { 896 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAA1NJREFUeJzt3b9rlWcYx+H7NmkFG9xjEXUwhRShdhNBOii4CAUVAkIzFcxsoXaTFvofOBZEhELBgoiL4I9FrDgqCoUq2DEtFRFx0aeDFMTbwnOSc3iTcF3bOXwJ9/QOn7xwsrUWAAAAAPC2TUMfAAAAAMDaIxoBAAAAUIhGAAAAABSiEQAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQDAKmXm7sx8mZkXhr4FAGBcRCMAgNU7GxF3hz4CAGCcRCMAgFXIzIWIeBoR14a+BQBgnEQjAIAVysytEfF9RJwa+hYAgHETjQAAVu6HiPiptfbn0IcAAIzb9NAHAACsR5n5WUQcjIi9Q98CADAJohEAwMp8ERE7I+JJZkZEzETEVGbOt9Y+H/AuAICxyNba0DcAAKw7mbklIra+9dU38SYiLbXWlgc5CgBgjLxpBACwAq21FxHx4r/Pmfk8Il4KRgDARuFNIwAAAAAKv54GAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQDE99AH/59Cm44P/rNvU/NxI+4Vfr3dvd374V/f2u9Mnu7czv/zWvd3opj79pHt7+erPE7tj790T3dvZLx9O7A54199f7+ve3jlztns7lf3/j5g7v9S9jYjYdfr2SPuNbC084w7cO9a9nTn8aCI3wPs8/rH/+RYR8XCx/xk3iiOHFrq3rx78PpEb1qPpHdu7t9/euNy93b/5dfd2z+2vurcREduP3R9pD++a/nhb93bxxq3u7dGP/unennvWf8PFA3u6txERr5aXR9rzxgc3Z7u3l3Zf6f+7s39k79abRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAARbbWhr4BAAAAgDXGm0YAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEDxLwsZXb17T4E0AAAAAElFTkSuQmCC\n", 897 | "text/plain": [ 898 | "
" 899 | ] 900 | }, 901 | "metadata": {}, 902 | "output_type": "display_data" 903 | }, 904 | { 905 | "data": { 906 | "image/png": "iVBORw0KGgoAAAANSUhEUgAABI0AAAA6CAYAAAA9SKnqAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAAyJJREFUeJzt3TFrlWcYx+H7TiKIRLFYROsmlDi6tXYoHSxdXSpChnTSDkJB/AiCg6NF/AiiYxGqhSIFSwYLpYMYMFO1aujSmkIoiY+Lg3AjPK/nwKvkuuDd/hzu+cd7zsnWWgAAAADA62bGPgAAAACAd49oBAAAAEAhGgEAAABQiEYAAAAAFKIRAAAAAIVoBAAAAEAhGgEAAABQiEYAABPIzDuZuZGZ66+elbFvAgCYBtEIAGByZ1tr86+ehbGPAQCYBtEIAAAAgEI0AgCY3MXM/Dsz72bmF2MfAwAwDdlaG/sGAID3VmZ+EhH3I+L/iDgVEd9HxNHW2uqohwEATEg0AgCYosz8MSJuttYuj30LAMAkfD0NAGC6WkTk2EcAAExKNAIAeEuZuTczv8rMnZk5l5mLEfF5RNwa+zYAgEnNjX0AAMB7bEdEXIiIIxGxFREPIuJEa21l1KsAAKbAbxoBAAAAUPh6GgAAAACFaAQAAABAIRoBAAAAUIhGAAAAABSiEQAAAADF3NgHvMmXM1/7W7e3cO3PX7u3H8zu6t7+sjHsjqXbp7u3ew48797++3T3sEM67bs3273d/8PqoM/eerY29BzYNmY/3Ddof/33m93b+Zmd3dvDN77t3n783XL3Ftje/ln8tHu7fOlq93Zt67/u7TfHl7q3ERFbKw8H7YHt6cm5zwbt/zh/pXv7aHO9e3vm2Mnu7ebjv7q3Q8wd+qh7u7FwcNhn//zb0HO6/PTiRvZuvWkEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFCIRgAAAAAUohEAAAAAhWgEAAAAQCEaAQAAAFBka23sGwAAAAB4x3jTCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKEQjAAAAAArRCAAAAIBCNAIAAACgEI0AAAAAKF4CTmtjgJRyW4YAAAAASUVORK5CYII=\n", 907 | "text/plain": [ 908 | "
" 909 | ] 910 | }, 911 | "metadata": {}, 912 | "output_type": "display_data" 913 | } 914 | ], 915 | "source": [ 916 | "for i in range(20): \n", 917 | " plt.figure(figsize = (20,20)) \n", 918 | " plt.subplot(20, 1, i+1) # total rows, total columns, position (row*column)\n", 919 | " plt.imshow(data.iloc[i, 200:300].reshape(1,100))\n", 920 | " plt.axis('off')\n", 921 | " plt.title(str(data.label[i]))" 922 | ] 923 | }, 924 | { 925 | "cell_type": "markdown", 926 | "metadata": {}, 927 | "source": [ 928 | "Hmmm... Looks like there might be a pattern there. I wonder if we can use the visualization method we used for the stroke data? Let's give it a shot. " 929 | ] 930 | }, 931 | { 932 | "cell_type": "code", 933 | "execution_count": 11, 934 | "metadata": {}, 935 | "outputs": [ 936 | { 937 | "data": { 938 | "image/png": "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\n", 939 | "text/plain": [ 940 | "" 941 | ] 942 | }, 943 | "metadata": {}, 944 | "output_type": "display_data" 945 | } 946 | ], 947 | "source": [ 948 | "plt.rcParams['figure.figsize'] = [20, 10]\n", 949 | "\n", 950 | "import seaborn as sns\n", 951 | "sns.set_style('white')\n", 952 | "\n", 953 | "for i, column in enumerate(data.columns[100:108]): \n", 954 | " \n", 955 | " plt.subplot(2, 4, i+1) # total rows, total columns, position (row*column)\n", 956 | " box = sns.boxplot(x='label', y=column, data=data)" 957 | ] 958 | }, 959 | { 960 | "cell_type": "markdown", 961 | "metadata": {}, 962 | "source": [ 963 | "Weird! And not very helpful. Most of the time, pixel values are zero, so a boxplot median and upper and lower quartiles will all be zero. I wonder.. could a random forest still learn? Let's recycle our code from last time." 964 | ] 965 | }, 966 | { 967 | "cell_type": "code", 968 | "execution_count": 16, 969 | "metadata": {}, 970 | "outputs": [ 971 | { 972 | "name": "stdout", 973 | "output_type": "stream", 974 | "text": [ 975 | "(6293, 784) (6293,)\n", 976 | "(1574, 784) (1574,)\n" 977 | ] 978 | }, 979 | { 980 | "name": "stderr", 981 | "output_type": "stream", 982 | "text": [ 983 | "C:\\Users\\jxb29\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\sklearn\\cross_validation.py:41: DeprecationWarning: This module was deprecated in version 0.18 in favor of the model_selection module into which all the refactored classes and functions are moved. Also note that the interface of the new CV iterators are different from that of this module. This module will be removed in 0.20.\n", 984 | " \"This module will be removed in 0.20.\", DeprecationWarning)\n" 985 | ] 986 | } 987 | ], 988 | "source": [ 989 | "pixel_variables = data.columns[1:] # Instead of clinical_variables, we have pixel_variables. They are all columns except the first row.\n", 990 | "\n", 991 | "from sklearn.cross_validation import train_test_split\n", 992 | "\n", 993 | "# Note: these are not great variable names, but very common in mathematical notation\n", 994 | "# Capital letter: matrix, lower-case letter: vector\n", 995 | "X_train, X_test, y_train, y_test = train_test_split(data[pixel_variables], data['label'], train_size=0.8, test_size=0.2)\n", 996 | "\n", 997 | "# How many cases do we have?\n", 998 | "print(X_train.shape, y_train.shape)\n", 999 | "print(X_test.shape, y_test.shape)" 1000 | ] 1001 | }, 1002 | { 1003 | "cell_type": "code", 1004 | "execution_count": 17, 1005 | "metadata": {}, 1006 | "outputs": [], 1007 | "source": [ 1008 | "# Let's train our random forest!\n", 1009 | "from sklearn import tree\n", 1010 | "\n", 1011 | "clf = tree.DecisionTreeClassifier()\n", 1012 | "clf = clf.fit(X_train, y_train)" 1013 | ] 1014 | }, 1015 | { 1016 | "cell_type": "code", 1017 | "execution_count": 18, 1018 | "metadata": {}, 1019 | "outputs": [ 1020 | { 1021 | "name": "stdout", 1022 | "output_type": "stream", 1023 | "text": [ 1024 | "Accuracy on training data: 1.0\n", 1025 | "Accuracy on testing data: 0.9714104193138501\n" 1026 | ] 1027 | } 1028 | ], 1029 | "source": [ 1030 | "# How does it do?\n", 1031 | "from sklearn.metrics import accuracy_score, classification_report\n", 1032 | "\n", 1033 | "# Training data\n", 1034 | "print('Accuracy on training data:', accuracy_score(y_train, clf.predict(X_train)))\n", 1035 | "\n", 1036 | "# Testing...\n", 1037 | "print('Accuracy on testing data:', accuracy_score(y_test, clf.predict(X_test)))" 1038 | ] 1039 | }, 1040 | { 1041 | "cell_type": "markdown", 1042 | "metadata": {}, 1043 | "source": [ 1044 | "Looks like it does pretty well -- 98%! It turns out computer vision isn't that hard after all. However, we're only able to get this result because we are dealing with 28x28 images. Particularly, because these images have only 784 variables, we are able to relatively easily create a dataset where we have more samples than variables. Real images, however, can be much larger. A 1000x1000 pixel image will have 1,000,000 separate variables to regress over, which is often much larger than the number of samples we can acquire. An MRI image is often on the order of 150x150x225 if in isotropic resolution, which gives about 5 million variable!" 1045 | ] 1046 | }, 1047 | { 1048 | "cell_type": "markdown", 1049 | "metadata": {}, 1050 | "source": [ 1051 | "# Bonus: neural network!" 1052 | ] 1053 | }, 1054 | { 1055 | "cell_type": "code", 1056 | "execution_count": 19, 1057 | "metadata": {}, 1058 | "outputs": [ 1059 | { 1060 | "data": { 1061 | "text/plain": [ 1062 | "MLPClassifier(activation='relu', alpha=1e-05, batch_size='auto', beta_1=0.9,\n", 1063 | " beta_2=0.999, early_stopping=False, epsilon=1e-08,\n", 1064 | " hidden_layer_sizes=(32, 32), learning_rate='constant',\n", 1065 | " learning_rate_init=0.001, max_iter=200, momentum=0.9,\n", 1066 | " nesterovs_momentum=True, power_t=0.5, random_state=None,\n", 1067 | " shuffle=True, solver='sgd', tol=0.0001, validation_fraction=0.1,\n", 1068 | " verbose=False, warm_start=False)" 1069 | ] 1070 | }, 1071 | "execution_count": 19, 1072 | "metadata": {}, 1073 | "output_type": "execute_result" 1074 | } 1075 | ], 1076 | "source": [ 1077 | "from sklearn.neural_network import MLPClassifier\n", 1078 | "clf = MLPClassifier(solver='sgd', alpha=1e-5, hidden_layer_sizes=(32, 32))\n", 1079 | "clf.fit(X_train, y_train)" 1080 | ] 1081 | }, 1082 | { 1083 | "cell_type": "code", 1084 | "execution_count": 20, 1085 | "metadata": {}, 1086 | "outputs": [ 1087 | { 1088 | "name": "stdout", 1089 | "output_type": "stream", 1090 | "text": [ 1091 | "Accuracy on training data: 0.9984109327824567\n", 1092 | "Accuracy on testing data: 0.9911054637865311\n" 1093 | ] 1094 | } 1095 | ], 1096 | "source": [ 1097 | "print('Accuracy on training data:', accuracy_score(y_train, clf.predict(X_train)))\n", 1098 | "print('Accuracy on testing data:', accuracy_score(y_test, clf.predict(X_test)))" 1099 | ] 1100 | } 1101 | ], 1102 | "metadata": { 1103 | "kernelspec": { 1104 | "display_name": "Python 3", 1105 | "language": "python", 1106 | "name": "python3" 1107 | }, 1108 | "language_info": { 1109 | "codemirror_mode": { 1110 | "name": "ipython", 1111 | "version": 3 1112 | }, 1113 | "file_extension": ".py", 1114 | "mimetype": "text/x-python", 1115 | "name": "python", 1116 | "nbconvert_exporter": "python", 1117 | "pygments_lexer": "ipython3", 1118 | "version": "3.6.5" 1119 | } 1120 | }, 1121 | "nbformat": 4, 1122 | "nbformat_minor": 2 1123 | } 1124 | -------------------------------------------------------------------------------- /tutorial_3/mnist_glossary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_3/mnist_glossary.png -------------------------------------------------------------------------------- /tutorial_3/mnist_sample.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_3/mnist_sample.png -------------------------------------------------------------------------------- /tutorial_3/mnist_sample_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_3/mnist_sample_2.png -------------------------------------------------------------------------------- /tutorial_4/.gitignore: -------------------------------------------------------------------------------- 1 | train/ 2 | test/ 3 | tb_log/ 4 | *.csv 5 | *.zip 6 | train_5000/ 7 | -------------------------------------------------------------------------------- /tutorial_5/.gitignore: -------------------------------------------------------------------------------- 1 | *.h5 2 | *.zip 3 | BRATS_*/ -------------------------------------------------------------------------------- /tutorial_5/BRATS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_5/BRATS.png -------------------------------------------------------------------------------- /tutorial_5/colab.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": { 6 | "colab_type": "text", 7 | "id": "vcB9ZIyVOVkE" 8 | }, 9 | "source": [ 10 | "# Mounting your Google Drive\n", 11 | "\n", 12 | "Running these two blocks of code will give the Colab environment access to your data on Google Drive. If you aren't comfortable with this idea, I'd suggest making a new Drive account dedicated to this project!" 13 | ] 14 | }, 15 | { 16 | "cell_type": "code", 17 | "execution_count": null, 18 | "metadata": { 19 | "colab": { 20 | "autoexec": { 21 | "startup": false, 22 | "wait_interval": 0 23 | }, 24 | "base_uri": "https://localhost:8080/", 25 | "height": 87 26 | }, 27 | "colab_type": "code", 28 | "collapsed": true, 29 | "executionInfo": { 30 | "elapsed": 17747, 31 | "status": "ok", 32 | "timestamp": 1528405995359, 33 | "user": { 34 | "displayName": "James Brown", 35 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 36 | "userId": "108976389057231134781" 37 | }, 38 | "user_tz": 240 39 | }, 40 | "id": "AZSYwExZQ7cq", 41 | "outputId": "cc799dce-1480-497f-ea58-8d259461ac2e" 42 | }, 43 | "outputs": [], 44 | "source": [ 45 | "!apt-get install -y -qq software-properties-common python-software-properties module-init-tools\n", 46 | "!add-apt-repository -y ppa:alessandro-strada/ppa 2>&1 > /dev/null\n", 47 | "!apt-get update -qq 2>&1 > /dev/null\n", 48 | "!apt-get -y install -qq google-drive-ocamlfuse fuse\n", 49 | "from google.colab import auth\n", 50 | "auth.authenticate_user()\n", 51 | "from oauth2client.client import GoogleCredentials\n", 52 | "creds = GoogleCredentials.get_application_default()\n", 53 | "import getpass\n", 54 | "!google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret} < /dev/null 2>&1 | grep URL\n", 55 | "vcode = getpass.getpass()\n", 56 | "!echo {vcode} | google-drive-ocamlfuse -headless -id={creds.client_id} -secret={creds.client_secret}" 57 | ] 58 | }, 59 | { 60 | "cell_type": "code", 61 | "execution_count": null, 62 | "metadata": { 63 | "colab": { 64 | "autoexec": { 65 | "startup": false, 66 | "wait_interval": 0 67 | } 68 | }, 69 | "colab_type": "code", 70 | "collapsed": true, 71 | "id": "KL9us_5abXTb" 72 | }, 73 | "outputs": [], 74 | "source": [ 75 | "!mkdir -p drive\n", 76 | "!google-drive-ocamlfuse drive" 77 | ] 78 | }, 79 | { 80 | "cell_type": "markdown", 81 | "metadata": { 82 | "colab_type": "text", 83 | "id": "6-hXiBgiPTd3" 84 | }, 85 | "source": [ 86 | "Let's navigate to the folder where our data is stored and check everything is there:" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": null, 92 | "metadata": { 93 | "colab": { 94 | "autoexec": { 95 | "startup": false, 96 | "wait_interval": 0 97 | }, 98 | "base_uri": "https://localhost:8080/", 99 | "height": 87 100 | }, 101 | "colab_type": "code", 102 | "collapsed": true, 103 | "executionInfo": { 104 | "elapsed": 3014, 105 | "status": "ok", 106 | "timestamp": 1528406043676, 107 | "user": { 108 | "displayName": "James Brown", 109 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 110 | "userId": "108976389057231134781" 111 | }, 112 | "user_tz": 240 113 | }, 114 | "id": "1gGLdcfPbdEz", 115 | "outputId": "e354f8c5-d298-4f9a-a357-b27467d26d8e" 116 | }, 117 | "outputs": [], 118 | "source": [ 119 | "import os\n", 120 | "os.chdir('drive/MGH/Teaching/qtim_Tutorials/tutorial_5/')\n", 121 | "!ls" 122 | ] 123 | }, 124 | { 125 | "cell_type": "markdown", 126 | "metadata": { 127 | "colab_type": "text", 128 | "id": "3MSzs_RIPGAd" 129 | }, 130 | "source": [ 131 | "# Implementing our network" 132 | ] 133 | }, 134 | { 135 | "cell_type": "code", 136 | "execution_count": null, 137 | "metadata": { 138 | "colab": { 139 | "autoexec": { 140 | "startup": false, 141 | "wait_interval": 0 142 | }, 143 | "base_uri": "https://localhost:8080/", 144 | "height": 1002 145 | }, 146 | "colab_type": "code", 147 | "collapsed": true, 148 | "executionInfo": { 149 | "elapsed": 1138, 150 | "status": "ok", 151 | "timestamp": 1528410893113, 152 | "user": { 153 | "displayName": "James Brown", 154 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 155 | "userId": "108976389057231134781" 156 | }, 157 | "user_tz": 240 158 | }, 159 | "id": "uRPnbnUtRbrE", 160 | "outputId": "917c9189-0a5f-442a-b6d9-557da8c2f706" 161 | }, 162 | "outputs": [], 163 | "source": [ 164 | "from keras.layers import Input, Conv2D, MaxPool2D, Dense, Dropout, BatchNormalization\n", 165 | "from keras.layers.pooling import GlobalAveragePooling2D\n", 166 | "from keras.models import Model\n", 167 | "\n", 168 | "max_channels = 1024\n", 169 | "\n", 170 | "# First block\n", 171 | "input_layer = Input(shape=(240, 240, 4))\n", 172 | "conv1 = Conv2D(max_channels // 16, (3, 3), padding='same', activation='relu')(input_layer)\n", 173 | "conv2 = Conv2D(max_channels // 16, (3, 3), padding='same', activation='relu')(conv1)\n", 174 | "conv2 = BatchNormalization()(conv2)\n", 175 | "pool1 = MaxPool2D((2, 2))(conv2)\n", 176 | "\n", 177 | "# Second block\n", 178 | "conv3 = Conv2D(max_channels // 8, (3, 3), padding='same', activation='relu')(pool1)\n", 179 | "conv4 = Conv2D(max_channels // 8, (3, 3), padding='same', activation='relu')(conv3)\n", 180 | "conv4 = BatchNormalization()(conv4)\n", 181 | "pool2 = MaxPool2D((2, 2))(conv4)\n", 182 | "\n", 183 | "# Third block\n", 184 | "conv5 = Conv2D(max_channels // 4, (3, 3), padding='same', activation='relu')(pool2)\n", 185 | "conv6 = Conv2D(max_channels // 4, (3, 3), padding='same', activation='relu')(conv5)\n", 186 | "conv6 = BatchNormalization()(conv6)\n", 187 | "pool3 = MaxPool2D((2, 2))(conv6)\n", 188 | "\n", 189 | "# Fourth block\n", 190 | "conv7 = Conv2D(max_channels // 2, (3, 3), padding='same', activation='relu')(pool3)\n", 191 | "conv8 = Conv2D(max_channels // 2, (3, 3), padding='same', activation='relu')(conv7)\n", 192 | "conv8 = BatchNormalization()(conv8)\n", 193 | "pool4 = MaxPool2D((2, 2))(conv8)\n", 194 | "\n", 195 | "# Fifth block\n", 196 | "conv9 = Conv2D(max_channels, (3, 3), padding='same', activation='relu')(pool4)\n", 197 | "conv10 = Conv2D(max_channels, (3, 3), padding='same', activation='relu')(conv9)\n", 198 | "conv10 = BatchNormalization()(conv10)\n", 199 | "pool5 = GlobalAveragePooling2D()(conv10)\n", 200 | "\n", 201 | "# Fully-connected\n", 202 | "dense1 = Dense(128, activation='relu')(pool5)\n", 203 | "drop1 = Dropout(0.5)(dense1)\n", 204 | "output = Dense(1, activation='sigmoid')(drop1)\n", 205 | "\n", 206 | "# Create model object\n", 207 | "model = Model(inputs=input_layer, outputs=output)\n", 208 | "print(model.summary())" 209 | ] 210 | }, 211 | { 212 | "cell_type": "markdown", 213 | "metadata": { 214 | "colab_type": "text", 215 | "id": "dhA8Gk6OPizN" 216 | }, 217 | "source": [ 218 | "# Data generators\n", 219 | "\n", 220 | "Keras provides powerful tools for iterating over datasets and augmenting them in real-time. In just a few lines of code, we can define a generator that yields random batches of the data (without ever loading all of it into memory) with randomly applied transformations. This serves to diversify the dataset and hopefully make the resulting model more generalizable." 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": null, 226 | "metadata": { 227 | "colab": { 228 | "autoexec": { 229 | "startup": false, 230 | "wait_interval": 0 231 | } 232 | }, 233 | "colab_type": "code", 234 | "collapsed": true, 235 | "id": "kB_OaNV1xmIr" 236 | }, 237 | "outputs": [], 238 | "source": [ 239 | "from keras.preprocessing.image import ImageDataGenerator\n", 240 | "from keras.utils.io_utils import HDF5Matrix\n", 241 | "seed = 0\n", 242 | "\n", 243 | "data_gen_args = dict( \n", 244 | " width_shift_range=0.05,\n", 245 | " height_shift_range=0.05,\n", 246 | " zoom_range=0.2,\n", 247 | " channel_shift_range=0.005,\n", 248 | " horizontal_flip=True,\n", 249 | " vertical_flip=True\n", 250 | ")\n", 251 | "\n", 252 | "# Generator for the training data\n", 253 | "train_datagen = ImageDataGenerator(**data_gen_args)\n", 254 | "X_train = HDF5Matrix('training.h5', 'train')\n", 255 | "y_train = HDF5Matrix('training.h5', 'labels')\n", 256 | "train_generator = train_datagen.flow(X_train, y_train, seed=0, batch_size=16)\n", 257 | "\n", 258 | "# Generator for the validation data\n", 259 | "val_datagen = ImageDataGenerator() # no augmentation! why?\n", 260 | "X_val = HDF5Matrix('validation.h5', 'train')\n", 261 | "y_val = HDF5Matrix('validation.h5', 'labels')\n", 262 | "val_generator = val_datagen.flow(X_val, y_val, seed=0, batch_size=1)" 263 | ] 264 | }, 265 | { 266 | "cell_type": "markdown", 267 | "metadata": { 268 | "colab_type": "text", 269 | "id": "Bem-YhYnY8kX" 270 | }, 271 | "source": [ 272 | "# Training the model\n", 273 | "\n", 274 | "At long last, we can train our model! The process goes something like this:\n", 275 | "\n", 276 | "* Initialize the network randomly, with a certain optimizer, loss function and metric\n", 277 | "* Grab a random batch of data from the HDF5 file and randomly augment it\n", 278 | "* Push it through the network, and get the predictions\n", 279 | "* Calculate the error (loss)\n", 280 | "* Calculate the partial derivative of the loss function w.r.t. each of the weights + biases, using back-propagation\n", 281 | "* Update the network's weights in the negative direction of the gradient, multiplied by the learning rate\n", 282 | "* Repeat until dataset is exhausted\n", 283 | "* Run the network on the validation data, but *do not* update the network\n", 284 | "* Repeat until convergence/fixed number of iterations (epochs) reached\n", 285 | "\n", 286 | "We specify two 'callbacks' which are run at the end of each epoch:\n", 287 | "\n", 288 | "* Model checkpoint: if the validation loss improves, save the model\n", 289 | "* Early stopping: if we fail to make progress after a certain number of epochs, stop early\n" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "execution_count": null, 295 | "metadata": { 296 | "colab": { 297 | "autoexec": { 298 | "startup": false, 299 | "wait_interval": 0 300 | }, 301 | "base_uri": "https://localhost:8080/", 302 | "height": 228 303 | }, 304 | "colab_type": "code", 305 | "collapsed": true, 306 | "executionInfo": { 307 | "elapsed": 444978, 308 | "status": "ok", 309 | "timestamp": 1528411649588, 310 | "user": { 311 | "displayName": "James Brown", 312 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 313 | "userId": "108976389057231134781" 314 | }, 315 | "user_tz": 240 316 | }, 317 | "id": "NvevjJNHfVkT", 318 | "outputId": "06f9d3e2-4672-4693-a704-7a1ca1de1e4b" 319 | }, 320 | "outputs": [], 321 | "source": [ 322 | "from keras.callbacks import ModelCheckpoint, EarlyStopping\n", 323 | "\n", 324 | "mc_cb = ModelCheckpoint('best_model.h5')\n", 325 | "el_cb = EarlyStopping(patience=5)\n", 326 | "\n", 327 | "model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])\n", 328 | "history = model.fit_generator(train_generator, epochs=50, shuffle='batch',\n", 329 | " validation_data=val_generator, callbacks=[mc_cb, el_cb])\n", 330 | "model.save('final_model.h5')" 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": null, 336 | "metadata": { 337 | "colab": { 338 | "autoexec": { 339 | "startup": false, 340 | "wait_interval": 0 341 | } 342 | }, 343 | "colab_type": "code", 344 | "collapsed": true, 345 | "id": "Am8yOi33peru" 346 | }, 347 | "outputs": [], 348 | "source": [ 349 | "from keras.models import load_model\n", 350 | "import numpy as np\n", 351 | "import h5py\n", 352 | "\n", 353 | "model = load_model('best_model.h5')\n", 354 | "\n", 355 | "# We will use testing data in future... this is somewhat biased!\n", 356 | "val_data = h5py.File('validation.h5', 'r')\n", 357 | "X_val, y_val = val_data['train'], val_data['labels']\n", 358 | "\n", 359 | "y_pred = model.predict(X_val) # get network predictions over entire dataset\n", 360 | "y_true = np.asarray(y_val) # using np.asarray explicitly loads the HDF5 data" 361 | ] 362 | }, 363 | { 364 | "cell_type": "code", 365 | "execution_count": null, 366 | "metadata": { 367 | "colab": { 368 | "autoexec": { 369 | "startup": false, 370 | "wait_interval": 0 371 | }, 372 | "base_uri": "https://localhost:8080/", 373 | "height": 1882 374 | }, 375 | "colab_type": "code", 376 | "collapsed": true, 377 | "executionInfo": { 378 | "elapsed": 263, 379 | "status": "ok", 380 | "timestamp": 1528411690123, 381 | "user": { 382 | "displayName": "James Brown", 383 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 384 | "userId": "108976389057231134781" 385 | }, 386 | "user_tz": 240 387 | }, 388 | "id": "zQrybzGoJQpG", 389 | "outputId": "a0585e3c-d50e-4ad3-ca05-e35b1b84039f" 390 | }, 391 | "outputs": [], 392 | "source": [ 393 | "import pandas as pd\n", 394 | "pd.DataFrame([y_pred.squeeze(), y_true]).T" 395 | ] 396 | }, 397 | { 398 | "cell_type": "code", 399 | "execution_count": null, 400 | "metadata": { 401 | "colab": { 402 | "autoexec": { 403 | "startup": false, 404 | "wait_interval": 0 405 | }, 406 | "base_uri": "https://localhost:8080/", 407 | "height": 365 408 | }, 409 | "colab_type": "code", 410 | "collapsed": true, 411 | "executionInfo": { 412 | "elapsed": 1189, 413 | "status": "ok", 414 | "timestamp": 1528411697359, 415 | "user": { 416 | "displayName": "James Brown", 417 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 418 | "userId": "108976389057231134781" 419 | }, 420 | "user_tz": 240 421 | }, 422 | "id": "I2Q5PGAsH9Dl", 423 | "outputId": "c40b3164-0a1a-413e-8559-1bc377f17cf2" 424 | }, 425 | "outputs": [], 426 | "source": [ 427 | "from sklearn.metrics import roc_curve, auc, confusion_matrix\n", 428 | "import matplotlib.pyplot as plt\n", 429 | "import seaborn as sns\n", 430 | "sns.set_style('white')\n", 431 | "\n", 432 | "# Confusion matrix, optionally normalized\n", 433 | "normalize = False\n", 434 | "cm = confusion_matrix(y_true, np.round(y_pred).astype('bool'))\n", 435 | "fmt = 'd' # for displaying the values\n", 436 | "\n", 437 | "if normalize:\n", 438 | " cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] # optional!\n", 439 | " fmt = '.2%'\n", 440 | "\n", 441 | "# Use some fancy plotting\n", 442 | "labels = ['No tumor', 'Tumor']\n", 443 | "ax = sns.heatmap(cm, annot=True, fmt=fmt, xticklabels=labels, yticklabels=labels, cmap='Blues')\n", 444 | "plt.xlabel('Predicted label')\n", 445 | "plt.ylabel('True label')\n", 446 | "ax.xaxis.set_label_position('top')\n", 447 | "ax.xaxis.tick_top()\n", 448 | "plt.savefig('confusion.png', dpi=300)" 449 | ] 450 | }, 451 | { 452 | "cell_type": "code", 453 | "execution_count": null, 454 | "metadata": { 455 | "colab": { 456 | "autoexec": { 457 | "startup": false, 458 | "wait_interval": 0 459 | }, 460 | "base_uri": "https://localhost:8080/", 461 | "height": 376 462 | }, 463 | "colab_type": "code", 464 | "collapsed": true, 465 | "executionInfo": { 466 | "elapsed": 1069, 467 | "status": "ok", 468 | "timestamp": 1528411704928, 469 | "user": { 470 | "displayName": "James Brown", 471 | "photoUrl": "//lh4.googleusercontent.com/-uoFM3PRUlTo/AAAAAAAAAAI/AAAAAAAANoU/bCtDaLz51oY/s50-c-k-no/photo.jpg", 472 | "userId": "108976389057231134781" 473 | }, 474 | "user_tz": 240 475 | }, 476 | "id": "DHiHApTXLgwW", 477 | "outputId": "8c699473-6edb-4ee4-8780-ea5ebf883266" 478 | }, 479 | "outputs": [], 480 | "source": [ 481 | "fpr, tpr, _ = roc_curve(y_true, y_pred)\n", 482 | "plt.plot(fpr, tpr, label='AUC: {:.2f}'.format(auc(fpr, tpr)))\n", 483 | "plt.title('ROC analysis of my first tumor detector')\n", 484 | "plt.xlabel('1 - Specificity')\n", 485 | "plt.ylabel('Sensitivity')\n", 486 | "plt.legend()\n", 487 | "plt.savefig('roc.png', dpi=300)" 488 | ] 489 | } 490 | ], 491 | "metadata": { 492 | "accelerator": "GPU", 493 | "colab": { 494 | "collapsed_sections": [], 495 | "default_view": {}, 496 | "name": "Tutorial 5C", 497 | "provenance": [], 498 | "version": "0.3.2", 499 | "views": {} 500 | }, 501 | "kernelspec": { 502 | "display_name": "Python 2", 503 | "language": "python", 504 | "name": "python2" 505 | }, 506 | "language_info": { 507 | "codemirror_mode": { 508 | "name": "ipython", 509 | "version": 2 510 | }, 511 | "file_extension": ".py", 512 | "mimetype": "text/x-python", 513 | "name": "python", 514 | "nbconvert_exporter": "python", 515 | "pygments_lexer": "ipython2", 516 | "version": "2.7.12" 517 | } 518 | }, 519 | "nbformat": 4, 520 | "nbformat_minor": 1 521 | } 522 | -------------------------------------------------------------------------------- /tutorial_5/u-net-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_5/u-net-architecture.png -------------------------------------------------------------------------------- /tutorial_7/.gitignore: -------------------------------------------------------------------------------- 1 | *.h5 2 | *.pyc -------------------------------------------------------------------------------- /tutorial_7/.ipynb_checkpoints/Unsupervised machine learning-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Unsupervised machine learning\n", 8 | "\n", 9 | "Previously, we have taken MR images and attempt assign to them values of normal/diseased, at a whole image level (classification) or a pixel level (segmentation). But what if we don't have labels?\n", 10 | "\n", 11 | "We are going to spent this tutorial exploring how to find patterns in data using unsupervised machine learning. We'll introduce three new tools that require no labels (though we'll keep track of them to evaluate our performance):\n", 12 | "\n", 13 | "- Autoencoders: deep neural network designed minimize the \"reconstruction error\" between the input and output (which are the same)\n", 14 | "- K-means clustering: a way of automatically find groups of unlabelled data points in space based on distances between them\n", 15 | "- K-nearest neighbours: assigning a new data point a label based on its proximity to other labelled data points" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 10, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "%load_ext autoreload\n", 25 | "train_path = 'C:/Users/jxb29/Dropbox (Partners HealthCare)/Teaching/BRATS_10_Updated/*/*.nii.gz'\n", 26 | "sequences = ['t1', 't2']" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": 3, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "from skimage.measure import label, regionprops\n", 36 | "\n", 37 | "def normalize_images(channel_copy):\n", 38 | " \n", 39 | " label_image = label(channel_copy == 0)\n", 40 | "\n", 41 | " largest_label, largest_area = None, 0\n", 42 | " for region in regionprops(label_image):\n", 43 | " if region.area > largest_area:\n", 44 | " largest_area = region.area\n", 45 | " largest_label = region.label\n", 46 | "\n", 47 | " mask = label_image == largest_label \n", 48 | " masked_channel = np.ma.masked_where(mask, channel_copy)\n", 49 | "\n", 50 | " masked_channel = masked_channel - np.mean(masked_channel)\n", 51 | " masked_channel = masked_channel / np.std(masked_channel)\n", 52 | " masked_channel = np.ma.getdata(masked_channel)\n", 53 | " return masked_channel" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 6, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "from glob import glob\n", 63 | "import nibabel as nib\n", 64 | "from os.path import basename\n", 65 | "import numpy as np \n", 66 | "\n", 67 | "all_images = glob(train_path)\n", 68 | "slices = []\n", 69 | "labels = []\n", 70 | "\n", 71 | "for nifti_file in all_images:\n", 72 | " \n", 73 | " seq = basename(nifti_file).split('.')[0].split('_')[-1]\n", 74 | " \n", 75 | " if seq not in sequences:\n", 76 | " continue\n", 77 | " \n", 78 | " # Load Nifti file, normalize it\n", 79 | " vol = nib.load(nifti_file).get_data()\n", 80 | " vol = normalize_images(vol)\n", 81 | " \n", 82 | " # Take a middle-ish section of the volume\n", 83 | " halfway_point = vol.shape[2] // 2\n", 84 | " sample = [vol[:,:,i] for i in range(halfway_point-20, halfway_point+20)]\n", 85 | " slices.extend(sample)\n", 86 | " \n", 87 | " # Keep track of the labels (sequence ID: 0 == t1, 1 == t2)\n", 88 | " index = sequences.index(seq)\n", 89 | " index_list = [index] * 40\n", 90 | " labels.extend(index_list)\n", 91 | " break" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 7, 97 | "metadata": {}, 98 | "outputs": [ 99 | { 100 | "name": "stdout", 101 | "output_type": "stream", 102 | "text": [ 103 | "(40, 240, 240, 1)\n" 104 | ] 105 | } 106 | ], 107 | "source": [ 108 | "# (samples: 40 * N, rows: 240, columns: 240, channels: 1)\n", 109 | "X = np.expand_dims(np.asarray(slices), axis=-1)\n", 110 | "print(X.shape)" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 24, 116 | "metadata": {}, 117 | "outputs": [ 118 | { 119 | "name": "stdout", 120 | "output_type": "stream", 121 | "text": [ 122 | "_________________________________________________________________\n", 123 | "Layer (type) Output Shape Param # \n", 124 | "=================================================================\n", 125 | "conv2d_23 (Conv2D) (None, 240, 240, 8) 80 \n", 126 | "_________________________________________________________________\n", 127 | "batch_normalization_22 (Batc (None, 240, 240, 8) 32 \n", 128 | "_________________________________________________________________\n", 129 | "max_pooling2d_18 (MaxPooling (None, 120, 120, 8) 0 \n", 130 | "_________________________________________________________________\n", 131 | "conv2d_24 (Conv2D) (None, 120, 120, 16) 1168 \n", 132 | "_________________________________________________________________\n", 133 | "batch_normalization_23 (Batc (None, 120, 120, 16) 64 \n", 134 | "_________________________________________________________________\n", 135 | "max_pooling2d_19 (MaxPooling (None, 60, 60, 16) 0 \n", 136 | "_________________________________________________________________\n", 137 | "conv2d_25 (Conv2D) (None, 60, 60, 32) 4640 \n", 138 | "_________________________________________________________________\n", 139 | "batch_normalization_24 (Batc (None, 60, 60, 32) 128 \n", 140 | "_________________________________________________________________\n", 141 | "max_pooling2d_20 (MaxPooling (None, 30, 30, 32) 0 \n", 142 | "_________________________________________________________________\n", 143 | "conv2d_26 (Conv2D) (None, 30, 30, 64) 18496 \n", 144 | "_________________________________________________________________\n", 145 | "batch_normalization_25 (Batc (None, 30, 30, 64) 256 \n", 146 | "_________________________________________________________________\n", 147 | "max_pooling2d_21 (MaxPooling (None, 15, 15, 64) 0 \n", 148 | "_________________________________________________________________\n", 149 | "up_sampling2d_3 (UpSampling2 (None, 30, 30, 64) 0 \n", 150 | "_________________________________________________________________\n", 151 | "conv2d_27 (Conv2D) (None, 30, 30, 32) 18464 \n", 152 | "_________________________________________________________________\n", 153 | "batch_normalization_26 (Batc (None, 30, 30, 32) 128 \n", 154 | "=================================================================\n", 155 | "Total params: 43,456\n", 156 | "Trainable params: 43,152\n", 157 | "Non-trainable params: 304\n", 158 | "_________________________________________________________________\n", 159 | "None\n", 160 | "1\n" 161 | ] 162 | } 163 | ], 164 | "source": [ 165 | "# from models import autoencoder\n", 166 | "%autoreload 2\n", 167 | "import models\n", 168 | "ae = models.autoencoder(image_shape=X.shape[1:])\n", 169 | "print(ae.summary())" 170 | ] 171 | } 172 | ], 173 | "metadata": { 174 | "kernelspec": { 175 | "display_name": "Python 3", 176 | "language": "python", 177 | "name": "python3" 178 | }, 179 | "language_info": { 180 | "codemirror_mode": { 181 | "name": "ipython", 182 | "version": 3 183 | }, 184 | "file_extension": ".py", 185 | "mimetype": "text/x-python", 186 | "name": "python", 187 | "nbconvert_exporter": "python", 188 | "pygments_lexer": "ipython3", 189 | "version": "3.6.5" 190 | } 191 | }, 192 | "nbformat": 4, 193 | "nbformat_minor": 2 194 | } 195 | -------------------------------------------------------------------------------- /tutorial_7/.ipynb_checkpoints/Untitled-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Unsupervised machine learning\n", 8 | "\n", 9 | "Previously, we have taken MR images and attempt assign to them values of normal/diseased, at a whole image level (classification) or a pixel level (segmentation). But what if we don't have labels?\n", 10 | "\n", 11 | "We are going to spent this tutorial exploring how to find patterns in data using unsupervised machine learning. We'll introduce three new tools that require no labels (though we'll keep track of them to evaluate our performance):\n", 12 | "\n", 13 | "- Autoencoders: deep neural network designed minimize the \"reconstruction error\" between the input and output (which are the same)\n", 14 | "- K-means clustering: a way of automatically find groups of unlabelled data points in space based on distances between them\n", 15 | "- K-nearest neighbours: assigning a new data point a label based on its proximity to other labelled data points" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 3, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "train_path = 'C:/Users/jxb29/Dropbox (Partners HealthCare)/Teaching/BRATS_10_Updated/*/*.nii.gz'\n", 25 | "sequences = ['t1', 't2']" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 5, 31 | "metadata": {}, 32 | "outputs": [ 33 | { 34 | "ename": "KeyboardInterrupt", 35 | "evalue": "", 36 | "output_type": "error", 37 | "traceback": [ 38 | "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", 39 | "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", 40 | "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[0mglob\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mglob\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mnibabel\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mnib\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mimage_list\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mglob\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtrain_path\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", 41 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\nibabel\\__init__.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 36\u001b[0m \"\"\"\n\u001b[0;32m 37\u001b[0m \u001b[1;31m# module imports\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 38\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0manalyze\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mana\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 39\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mspm99analyze\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mspm99\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 40\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mspm2analyze\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mspm2\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 42 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\nibabel\\analyze.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 83\u001b[0m '''\n\u001b[0;32m 84\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 85\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mnumpy\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 86\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 87\u001b[0m from .volumeutils import (native_code, swapped_code, make_dt_codes,\n", 43 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\numpy\\__init__.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 170\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 171\u001b[0m \u001b[1;31m# Allow distributors to run custom init code\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 172\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0m_distributor_init\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 173\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 174\u001b[0m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mcore\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 44 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\site-packages\\numpy\\_distributor_init.py\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[0;32m 32\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 33\u001b[0m \u001b[1;32mwith\u001b[0m \u001b[0mRTLD_for_MKL\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 34\u001b[1;33m \u001b[1;32mfrom\u001b[0m \u001b[1;33m.\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0m_mklinit\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 35\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 36\u001b[0m \u001b[1;32mdel\u001b[0m \u001b[0mRTLD_for_MKL\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", 45 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\importlib\\_bootstrap.py\u001b[0m in \u001b[0;36m_find_and_load\u001b[1;34m(name, import_)\u001b[0m\n", 46 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\importlib\\_bootstrap.py\u001b[0m in \u001b[0;36m_find_and_load_unlocked\u001b[1;34m(name, import_)\u001b[0m\n", 47 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\importlib\\_bootstrap.py\u001b[0m in \u001b[0;36m_load_unlocked\u001b[1;34m(spec)\u001b[0m\n", 48 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\importlib\\_bootstrap.py\u001b[0m in \u001b[0;36mmodule_from_spec\u001b[1;34m(spec)\u001b[0m\n", 49 | "\u001b[1;32m~\\AppData\\Local\\Continuum\\anaconda3\\lib\\importlib\\_bootstrap_external.py\u001b[0m in \u001b[0;36mcreate_module\u001b[1;34m(self, spec)\u001b[0m\n", 50 | "\u001b[1;31mKeyboardInterrupt\u001b[0m: " 51 | ] 52 | } 53 | ], 54 | "source": [ 55 | "from glob import glob\n", 56 | "import nibabel as nib\n", 57 | "\n", 58 | "image_list = glob(train_path)\n", 59 | "\n", 60 | "for nifti_file in image_list:\n", 61 | " \n", 62 | " if 'seg' in nifti_file:\n", 63 | " continue\n", 64 | " \n", 65 | " # Load our file\n", 66 | " vol = nib.load(nifti_file)\n", 67 | " break" 68 | ] 69 | } 70 | ], 71 | "metadata": { 72 | "kernelspec": { 73 | "display_name": "Python 3", 74 | "language": "python", 75 | "name": "python3" 76 | }, 77 | "language_info": { 78 | "codemirror_mode": { 79 | "name": "ipython", 80 | "version": 3 81 | }, 82 | "file_extension": ".py", 83 | "mimetype": "text/x-python", 84 | "name": "python", 85 | "nbconvert_exporter": "python", 86 | "pygments_lexer": "ipython3", 87 | "version": "3.6.5" 88 | } 89 | }, 90 | "nbformat": 4, 91 | "nbformat_minor": 2 92 | } 93 | -------------------------------------------------------------------------------- /tutorial_7/Unsupervised machine learning.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Unsupervised machine learning\n", 8 | "\n", 9 | "Previously, we have taken MR images and attempt assign to them values of normal/diseased, at a whole image level (classification) or a pixel level (segmentation). But what if we don't have labels?\n", 10 | "\n", 11 | "We are going to spent this tutorial exploring how to find patterns in data using unsupervised machine learning. We'll introduce three new tools that require no labels (though we'll keep track of them to evaluate our performance):\n", 12 | "\n", 13 | "- Autoencoders: deep neural network designed minimize the \"reconstruction error\" between the input and output (which are the same)\n", 14 | "- K-means clustering: a way of automatically find groups of unlabelled data points in space based on distances between them\n", 15 | "- K-nearest neighbours: assigning a new data point a label based on its proximity to other labelled data points" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": null, 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "%load_ext autoreload\n", 25 | "train_path = 'C:/Users/jxb29/Dropbox (Partners HealthCare)/Teaching/BRATS_10_Updated/*/*.nii.gz'\n", 26 | "sequences = ['t1', 't2', 't1ce', 'flair']" 27 | ] 28 | }, 29 | { 30 | "cell_type": "code", 31 | "execution_count": null, 32 | "metadata": {}, 33 | "outputs": [], 34 | "source": [ 35 | "from skimage.measure import label, regionprops\n", 36 | "\n", 37 | "def normalize_images(channel_copy):\n", 38 | " \n", 39 | " label_image = label(channel_copy == 0)\n", 40 | "\n", 41 | " largest_label, largest_area = None, 0\n", 42 | " for region in regionprops(label_image):\n", 43 | " if region.area > largest_area:\n", 44 | " largest_area = region.area\n", 45 | " largest_label = region.label\n", 46 | "\n", 47 | " mask = label_image == largest_label \n", 48 | " masked_channel = np.ma.masked_where(mask, channel_copy)\n", 49 | "\n", 50 | " masked_channel = masked_channel - np.mean(masked_channel)\n", 51 | " masked_channel = masked_channel / np.std(masked_channel)\n", 52 | " masked_channel = np.ma.getdata(masked_channel)\n", 53 | " return masked_channel" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": null, 59 | "metadata": {}, 60 | "outputs": [], 61 | "source": [ 62 | "from glob import glob\n", 63 | "import nibabel as nib\n", 64 | "from os.path import basename, join\n", 65 | "import numpy as np \n", 66 | "import pandas as pd\n", 67 | "from PIL import Image\n", 68 | "\n", 69 | "all_images = glob(train_path)\n", 70 | "\n", 71 | "slices = []\n", 72 | "labels = []\n", 73 | "\n", 74 | "thumb_data = []\n", 75 | "\n", 76 | "no_slices = 40\n", 77 | "\n", 78 | "for nifti_file in all_images:\n", 79 | " \n", 80 | " seq = basename(nifti_file).split('.')[0].split('_')[-1]\n", 81 | " \n", 82 | " if seq not in sequences:\n", 83 | " continue\n", 84 | " \n", 85 | " # Load Nifti file, normalize it\n", 86 | " vol = nib.load(nifti_file).get_data()\n", 87 | " vol = normalize_images(vol)\n", 88 | " \n", 89 | " # Take a middle-ish section of the volume\n", 90 | " halfway_point = vol.shape[2] // 2\n", 91 | " sample = [vol[:,:,i] for i in range(halfway_point-(no_slices//2), halfway_point+(no_slices//2))]\n", 92 | " slices.extend(sample)\n", 93 | " \n", 94 | " # Generate thumbnails\n", 95 | " for i, np_arr in enumerate(sample):\n", 96 | " \n", 97 | " pil_img = Image.fromarray(np_arr).resize((100, 100))\n", 98 | " #file_name = basename(nifti_file).split('.')[0] + '_' + str(i) + '.tif'\n", 99 | " file_name = join('thumbnails', basename(nifti_file).split('.')[0] + f'_{i}.tif')\n", 100 | " pil_img.save(file_name)\n", 101 | " \n", 102 | " thumb_dict = dict(file_name=file_name, subject_name=basename(nifti_file).split('.')[0], sequence=seq)\n", 103 | " thumb_data.append(thumb_dict)\n", 104 | " \n", 105 | " # Keep track of the labels (sequence ID: 0 == t1, 1 == t2)\n", 106 | " index = sequences.index(seq)\n", 107 | " index_list = [index] * no_slices\n", 108 | " labels.extend(index_list)\n", 109 | " \n", 110 | " \n", 111 | "df = pd.DataFrame(data=thumb_data)\n", 112 | "print(df)\n", 113 | "df.to_csv('thumbs.csv')" 114 | ] 115 | }, 116 | { 117 | "cell_type": "code", 118 | "execution_count": null, 119 | "metadata": {}, 120 | "outputs": [], 121 | "source": [ 122 | "# (samples: 40 * N, rows: 240, columns: 240, channels: 1)\n", 123 | "X = np.expand_dims(np.asarray(slices), axis=-1)\n", 124 | "y = np.asarray(labels)\n", 125 | "print(X.shape, y.shape)" 126 | ] 127 | }, 128 | { 129 | "cell_type": "code", 130 | "execution_count": null, 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "import h5py\n", 135 | "from keras.utils.io_utils import HDF5Matrix\n", 136 | "from keras.preprocessing.image import ImageDataGenerator\n", 137 | "\n", 138 | "\n", 139 | "def save_hdf5_file(train_data, output_filename):\n", 140 | " \n", 141 | " with h5py.File(output_filename, 'w') as file_handle:\n", 142 | " file_handle.create_dataset('train', data=train_data, dtype=train_data.dtype)\n", 143 | "\n", 144 | "class ReconGenerator:\n", 145 | " \n", 146 | " def __init__(self, save_file, training_data=None, batch_size=20, augmentation=None):\n", 147 | " \n", 148 | " self.training_data = training_data\n", 149 | " self.save_file = save_file\n", 150 | " self.batch_size = batch_size\n", 151 | " self.augmentation = augmentation\n", 152 | " self.seed = 1989\n", 153 | " \n", 154 | " if training_data is not None:\n", 155 | " save_hdf5_file(training_data, self.save_file)\n", 156 | " \n", 157 | " self.X_train = HDF5Matrix(self.save_file, 'train')\n", 158 | " self.image_shape = self.X_train.shape[1:]\n", 159 | " self.steps = self.X_train.shape[0] // self.batch_size\n", 160 | "\n", 161 | " def generate(self):\n", 162 | "\n", 163 | " aug_dict = dict()\n", 164 | " if self.augmentation is not None:\n", 165 | " aug_dict = self.augmentation\n", 166 | "\n", 167 | " X_datagen = ImageDataGenerator(**aug_dict)\n", 168 | " X_generator = X_datagen.flow(self.X_train, seed=self.seed, batch_size=self.batch_size, shuffle=True)\n", 169 | "\n", 170 | " return zip(X_generator, X_generator)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": null, 176 | "metadata": { 177 | "scrolled": false 178 | }, 179 | "outputs": [], 180 | "source": [ 181 | "batch_size = 20\n", 182 | "recon_gen = ReconGenerator('ae_data.h5')" 183 | ] 184 | }, 185 | { 186 | "cell_type": "code", 187 | "execution_count": null, 188 | "metadata": { 189 | "scrolled": true 190 | }, 191 | "outputs": [], 192 | "source": [ 193 | "%autoreload 2\n", 194 | "import models\n", 195 | "ae = models.autoencoder(image_shape=recon_gen.image_shape)\n", 196 | "ae.compile(loss='mse', optimizer='sgd', metrics=['mae'])\n", 197 | "ae.fit_generator(recon_gen.generate(), epochs=10, steps_per_epoch=recon_gen.steps)\n", 198 | "ae.save_weights('ae_weights.h5')" 199 | ] 200 | }, 201 | { 202 | "cell_type": "code", 203 | "execution_count": null, 204 | "metadata": {}, 205 | "outputs": [], 206 | "source": [ 207 | "import models\n", 208 | "encoder = models.autoencoder(image_shape=recon_gen.image_shape, encoder_only=True)\n", 209 | "encoder.load_weights('ae_weights.h5', by_name=True)" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": null, 215 | "metadata": {}, 216 | "outputs": [], 217 | "source": [ 218 | "import numpy as np" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": null, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "features = encoder.predict(recon_gen.X_train)\n", 228 | "np.savez('features.npz', features)" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": null, 234 | "metadata": {}, 235 | "outputs": [], 236 | "source": [ 237 | "features = np.load('features.npz')['arr_0'] # bit weird, but necessary\n", 238 | "print(features.shape)" 239 | ] 240 | }, 241 | { 242 | "cell_type": "code", 243 | "execution_count": null, 244 | "metadata": {}, 245 | "outputs": [], 246 | "source": [ 247 | "from sklearn.manifold import TSNE\n", 248 | "\n", 249 | "tsne = TSNE(n_components=2, verbose=1)\n", 250 | "T = tsne.fit_transform(features)" 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": null, 256 | "metadata": {}, 257 | "outputs": [], 258 | "source": [ 259 | "print(T.shape)" 260 | ] 261 | }, 262 | { 263 | "cell_type": "code", 264 | "execution_count": null, 265 | "metadata": {}, 266 | "outputs": [], 267 | "source": [ 268 | "import seaborn as sns\n", 269 | "sns.set_style('white')\n", 270 | "import matplotlib.pyplot as plt\n", 271 | "%matplotlib inline\n", 272 | "\n", 273 | "def plot_embedding(T, y):\n", 274 | " plt.figure(figsize=(10,10))\n", 275 | "\n", 276 | " for c, i in {'r': 0, 'b': 1, 'c': 2, 'm': 3}.items():\n", 277 | "\n", 278 | " idx = y == i\n", 279 | " plt.scatter(T[idx, 0], T[idx, 1], c=c, marker='.', s=10, alpha=.5, label=sequences[i].upper())\n", 280 | " plt.legend()\n", 281 | " plt.show()" 282 | ] 283 | }, 284 | { 285 | "cell_type": "code", 286 | "execution_count": null, 287 | "metadata": {}, 288 | "outputs": [], 289 | "source": [ 290 | "!conda install -c conda-forge umap-learn\n", 291 | "import umap\n", 292 | "embedding = umap.UMAP().fit_transform(features)" 293 | ] 294 | }, 295 | { 296 | "cell_type": "code", 297 | "execution_count": null, 298 | "metadata": {}, 299 | "outputs": [], 300 | "source": [ 301 | "import pandas as pd\n", 302 | "\n", 303 | "df = pd.read_csv('thumbs.csv', index_col=0)\n", 304 | "df['x'] = embedding[:, 0]\n", 305 | "df['y'] = embedding[:, 1]\n", 306 | "df['color'] = df['sequence'].replace({'t1': '#c866d1', 't2': '#6674d1', 't1ce': '#66d171', 'flair': '#f4b942'})" 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": null, 312 | "metadata": {}, 313 | "outputs": [], 314 | "source": [ 315 | "df.to_csv('thumbs.csv')" 316 | ] 317 | }, 318 | { 319 | "cell_type": "markdown", 320 | "metadata": {}, 321 | "source": [ 322 | "# Plan for today\n", 323 | "\n", 324 | "* Review last week\n", 325 | "* Demonstrate Bokeh plots\n", 326 | "* Create some thumbnail versions of our data\n", 327 | "* Create an interactive visualization in Bokeh" 328 | ] 329 | }, 330 | { 331 | "cell_type": "code", 332 | "execution_count": null, 333 | "metadata": {}, 334 | "outputs": [], 335 | "source": [ 336 | "import pandas as pd\n", 337 | "df = pd.read_csv('thumbs.csv', index_col=0)\n", 338 | "df.head()" 339 | ] 340 | }, 341 | { 342 | "cell_type": "code", 343 | "execution_count": null, 344 | "metadata": {}, 345 | "outputs": [], 346 | "source": [ 347 | "from bokeh.plotting import figure, output_file, show, ColumnDataSource\n", 348 | "\n", 349 | "output_file(\"bokeh.html\")\n", 350 | "\n", 351 | "source = ColumnDataSource(data=dict(\n", 352 | " x=df['x'],\n", 353 | " y=df['y'],\n", 354 | " desc=df['subject_name'],\n", 355 | " imgs=df['file_name'],\n", 356 | " color=df['color']\n", 357 | "))\n", 358 | "\n", 359 | "TOOLTIPS = \"\"\"\n", 360 | "
\n", 361 | "
\n", 362 | " \n", 367 | "
\n", 368 | "
\n", 369 | " @desc\n", 370 | " [$index]\n", 371 | "
\n", 372 | "
\n", 373 | " Location\n", 374 | " ($x, $y)\n", 375 | "
\n", 376 | "
\n", 377 | "\"\"\"\n", 378 | "\n", 379 | "p = figure(plot_width=800, plot_height=800, tooltips=TOOLTIPS,\n", 380 | " title=\"UMAP applied to autoencoded MR features\")\n", 381 | "\n", 382 | "p.circle('x', 'y', fill_color='color', fill_alpha=0.5, line_alpha=0., size=8, source=source)\n", 383 | "\n", 384 | "show(p)\n" 385 | ] 386 | } 387 | ], 388 | "metadata": { 389 | "kernelspec": { 390 | "display_name": "Python 3", 391 | "language": "python", 392 | "name": "python3" 393 | }, 394 | "language_info": { 395 | "codemirror_mode": { 396 | "name": "ipython", 397 | "version": 3 398 | }, 399 | "file_extension": ".py", 400 | "mimetype": "text/x-python", 401 | "name": "python", 402 | "nbconvert_exporter": "python", 403 | "pygments_lexer": "ipython3", 404 | "version": "3.6.5" 405 | } 406 | }, 407 | "nbformat": 4, 408 | "nbformat_minor": 2 409 | } 410 | -------------------------------------------------------------------------------- /tutorial_7/__pycache__/models.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QTIM-Lab/qtim_Tutorials/9291f42d0737d9c30e981dc72fbaf92c053232a5/tutorial_7/__pycache__/models.cpython-36.pyc -------------------------------------------------------------------------------- /tutorial_7/models.py: -------------------------------------------------------------------------------- 1 | from keras.layers import * 2 | from keras.models import Sequential 3 | 4 | def autoencoder(image_shape=(240, 240, 1), encoder_only=False, activation='relu'): 5 | 6 | # Encoder 7 | model = Sequential() 8 | model.add(Conv2D(8, (3,3), padding='same', activation=activation, input_shape=image_shape)) 9 | model.add(BatchNormalization()) 10 | model.add(MaxPool2D((2,2))) 11 | 12 | model.add(Conv2D(16, (3,3), padding='same', activation=activation)) 13 | model.add(BatchNormalization()) 14 | model.add(MaxPool2D((2,2))) 15 | 16 | model.add(Conv2D(32, (3,3), padding='same', activation=activation)) 17 | model.add(BatchNormalization()) 18 | model.add(MaxPool2D((2,2))) 19 | 20 | model.add(Conv2D(64, (3,3), padding='same', activation=activation)) 21 | model.add(BatchNormalization()) 22 | # model.add(MaxPool2D((2,2))) 23 | 24 | if encoder_only: 25 | model.add(Flatten()) 26 | return model 27 | 28 | # Decoder 29 | model.add(UpSampling2D((2,2))) 30 | model.add(Conv2D(32, (3,3), padding='same', activation=activation)) 31 | model.add(BatchNormalization()) 32 | 33 | model.add(UpSampling2D((2,2))) 34 | model.add(Conv2D(16, (3,3), padding='same', activation=activation)) 35 | model.add(BatchNormalization()) 36 | 37 | model.add(UpSampling2D((2,2))) 38 | model.add(Conv2D(8, (3,3), padding='same', activation=activation)) 39 | model.add(BatchNormalization()) 40 | 41 | model.add(Conv2D(1, (3,3), padding='same')) 42 | return model --------------------------------------------------------------------------------