<jupyter_start><jupyter_text>Quick Application: Optical Character Recognition To demonstrate the above principles on a more interesting problem, let's consider OCR (Optical Character Recognition) – that is, recognizing hand-written digits.In the wild, this problem involves both locating and identifying characters in an image. Here we'll take a shortcut and use scikit-learn's set of pre-formatted digits, which is built-in to the library.  Loading and visualizing the digits dataWe'll use scikit-learn's data access interface and take a look at this data:<jupyter_code>import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
digits = datasets.load_digits()
digits.images.shape<jupyter_output><empty_output><jupyter_text>Let's plot a few of these:<jupyter_code># DON'T DO THIS
fig, axes = plt.subplots(10, 10, figsize=(8, 8))
fig.subplots_adjust(hspace=0.1, wspace=0.1)

for i, ax in enumerate(axes.flat):
    ax.imshow(digits.images[i], cmap='binary', interpolation='nearest')
    ax.text(0.05, 0.05, str(digits.target[i]),
            transform=ax.transAxes, color='green')
    ax.set_xticks([])
    ax.set_yticks([])<jupyter_output><empty_output><jupyter_text>Here the data is simply each pixel value within an 8x8 grid:<jupyter_code># The images themselves
print(digits.images.shape)
print(digits.images[0])
# The data for use in our algorithms
print(digits.data.shape)
print(digits.data[0])
# The target label
print(digits.target)<jupyter_output>[0 1 2 ... 8 9 8]<jupyter_text>So our data have 1797 samples in 64 dimensions.  Unsupervised Learning: Dimensionality ReductionWe'd like to visualize our points within the 64-dimensional parameter space, but it's difficult to plot points in 64 dimensions!Instead we'll reduce the dimensions to 2, using an unsupervised method.Here, we'll make use of a manifold learning algorithm called *Isomap*, and transform the data to two dimensions.<jupyter_code>from sklearn.manifold import Isomap
iso = Isomap(n_components=2)
data_projected = iso.fit_transform(digits.data)
data_projected.shape
plt.scatter(data_projected[:, 0], data_projected[:, 1], c=digits.target,
            edgecolor='none', alpha=0.5, cmap=plt.cm.get_cmap('nipy_spectral', 10))
plt.colorbar(label='digit label', ticks=range(10))
plt.clim(-0.5, 9.5)<jupyter_output><empty_output><jupyter_text>We see here that the digits are fairly well-separated in the parameter space; this tells us that a supervised classification algorithm should perform fairly well. Let's give it a try.  Classification on DigitsLet's try a classification task on the digits. The first thing we'll want to do is split the digits into a training and testing sample:<jupyter_code>from sklearn.model_selection import train_test_split
Xtrain, Xtest, ytrain, ytest = train_test_split(digits.data, digits.target,
                                                random_state=2)
print(Xtrain.shape, Xtest.shape)<jupyter_output>(1347, 64) (450, 64)<jupyter_text>Let's use a simple logistic regression which (despite its confusing name) is a classification algorithm:<jupyter_code>from sklearn.linear_model import LogisticRegression
clf = LogisticRegression(penalty='l2')
clf.fit(Xtrain, ytrain)
ypred = clf.predict(Xtest)<jupyter_output>/home/markumreed/anaconda3/envs/ds4b/lib/python3.7/site-packages/sklearn/linear_model/logistic.py:432: FutureWarning: Default solver will be changed to 'lbfgs' in 0.22. Specify a solver to silence this warning.
  FutureWarning)
/home/markumreed/anaconda3/envs/ds4b/lib/python3.7/site-packages/sklearn/linear_model/logistic.py:469: FutureWarning: Default multi_class will be changed to 'auto' in 0.22. Specify the multi_class option to silence this warning.
  "this warning.", FutureWarning)<jupyter_text>We can check our classification accuracy by comparing the true values of the test set to the predictions:<jupyter_code>from sklearn.metrics import accuracy_score
accuracy_score(ytest, ypred)<jupyter_output><empty_output><jupyter_text>This single number doesn't tell us **where** we've gone wrong: one nice way to do this is to use the *confusion matrix*<jupyter_code>from sklearn.metrics import confusion_matrix
print(confusion_matrix(ytest, ypred))
plt.imshow(np.log(confusion_matrix(ytest, ypred)),
           cmap='Blues', interpolation='nearest')
plt.grid(False)
plt.ylabel('true')
plt.xlabel('predicted');<jupyter_output>/home/markumreed/anaconda3/envs/ds4b/lib/python3.7/site-packages/ipykernel_launcher.py:1: RuntimeWarning: divide by zero encountered in log
  """Entry point for launching an IPython kernel.<jupyter_text>We might also take a look at some of the outputs along with their predicted labels. We'll make the bad labels red:<jupyter_code>fig, axes = plt.subplots(10, 10, figsize=(8, 8))
fig.subplots_adjust(hspace=0.1, wspace=0.1)

for i, ax in enumerate(axes.flat):
    ax.imshow(Xtest[i].reshape(8, 8), cmap='binary')
    ax.text(0.05, 0.05, str(ypred[i]),
            transform=ax.transAxes,
            color='green' if (ytest[i] == ypred[i]) else 'red')
    ax.set_xticks([])
    ax.set_yticks([])<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10204081632653061, 'fraction_numerical': 0.020800627943485087, 'mean_word_length': 5.509578544061303, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '535534', 'license': 'MIT', 'n_tokens_mistral': 1744, 'n_tokens_neox': 1614, 'n_words': 486, 'path': 'python_ds4b/07_machine_learning/02_classification/08b_classification.ipynb', 'repo_name': 'markumreed/ds4b', 'size': '5096'}