chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,414 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 2 - Training Machine Learning Algorithms for Classification
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import ListedColormap
|
||||
|
||||
|
||||
class Perceptron(object):
|
||||
"""Perceptron classifier.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
eta : float
|
||||
Learning rate (between 0.0 and 1.0)
|
||||
n_iter : int
|
||||
Passes over the training dataset.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
w_ : 1d-array
|
||||
Weights after fitting.
|
||||
errors_ : list
|
||||
Number of misclassifications (updates) in each epoch.
|
||||
|
||||
"""
|
||||
def __init__(self, eta=0.01, n_iter=10):
|
||||
self.eta = eta
|
||||
self.n_iter = n_iter
|
||||
|
||||
def fit(self, X, y):
|
||||
"""Fit training data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : {array-like}, shape = [n_samples, n_features]
|
||||
Training vectors, where n_samples is the number of samples and
|
||||
n_features is the number of features.
|
||||
y : array-like, shape = [n_samples]
|
||||
Target values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
self : object
|
||||
|
||||
"""
|
||||
self.w_ = np.zeros(1 + X.shape[1])
|
||||
self.errors_ = []
|
||||
|
||||
for _ in range(self.n_iter):
|
||||
errors = 0
|
||||
for xi, target in zip(X, y):
|
||||
update = self.eta * (target - self.predict(xi))
|
||||
self.w_[1:] += update * xi
|
||||
self.w_[0] += update
|
||||
errors += int(update != 0.0)
|
||||
self.errors_.append(errors)
|
||||
return self
|
||||
|
||||
def net_input(self, X):
|
||||
"""Calculate net input"""
|
||||
return np.dot(X, self.w_[1:]) + self.w_[0]
|
||||
|
||||
def predict(self, X):
|
||||
"""Return class label after unit step"""
|
||||
return np.where(self.net_input(X) >= 0.0, 1, -1)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Training a perceptron model on the Iris dataset')
|
||||
print(50 * '-')
|
||||
|
||||
df = pd.read_csv('https://archive.ics.uci.edu/ml/'
|
||||
'machine-learning-databases/iris/iris.data', header=None)
|
||||
print(df.tail())
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Plotting the Iris data')
|
||||
print(50 * '-')
|
||||
|
||||
# select setosa and versicolor
|
||||
y = df.iloc[0:100, 4].values
|
||||
y = np.where(y == 'Iris-setosa', -1, 1)
|
||||
|
||||
# extract sepal length and petal length
|
||||
X = df.iloc[0:100, [0, 2]].values
|
||||
|
||||
# plot data
|
||||
plt.scatter(X[:50, 0], X[:50, 1],
|
||||
color='red', marker='o', label='setosa')
|
||||
plt.scatter(X[50:100, 0], X[50:100, 1],
|
||||
color='blue', marker='x', label='versicolor')
|
||||
|
||||
plt.xlabel('sepal length [cm]')
|
||||
plt.ylabel('petal length [cm]')
|
||||
plt.legend(loc='upper left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./images/02_06.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Training the perceptron model')
|
||||
print(50 * '-')
|
||||
|
||||
ppn = Perceptron(eta=0.1, n_iter=10)
|
||||
|
||||
ppn.fit(X, y)
|
||||
|
||||
plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, marker='o')
|
||||
plt.xlabel('Epochs')
|
||||
plt.ylabel('Number of misclassifications')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./perceptron_1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('A function for plotting decision regions')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def plot_decision_regions(X, y, classifier, resolution=0.02):
|
||||
|
||||
# setup marker generator and color map
|
||||
markers = ('s', 'x', 'o', '^', 'v')
|
||||
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
|
||||
cmap = ListedColormap(colors[:len(np.unique(y))])
|
||||
|
||||
# plot the decision surface
|
||||
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
|
||||
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
|
||||
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
|
||||
np.arange(x2_min, x2_max, resolution))
|
||||
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
|
||||
Z = Z.reshape(xx1.shape)
|
||||
plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
|
||||
plt.xlim(xx1.min(), xx1.max())
|
||||
plt.ylim(xx2.min(), xx2.max())
|
||||
|
||||
# plot class samples
|
||||
for idx, cl in enumerate(np.unique(y)):
|
||||
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
|
||||
alpha=0.8, c=cmap(idx),
|
||||
marker=markers[idx], label=cl)
|
||||
|
||||
|
||||
plot_decision_regions(X, y, classifier=ppn)
|
||||
plt.xlabel('sepal length [cm]')
|
||||
plt.ylabel('petal length [cm]')
|
||||
plt.legend(loc='upper left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./perceptron_2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Implementing an adaptive linear neuron in Python')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
class AdalineGD(object):
|
||||
"""ADAptive LInear NEuron classifier.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
eta : float
|
||||
Learning rate (between 0.0 and 1.0)
|
||||
n_iter : int
|
||||
Passes over the training dataset.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
w_ : 1d-array
|
||||
Weights after fitting.
|
||||
cost_ : list
|
||||
Sum-of-squares cost function value in each epoch.
|
||||
|
||||
"""
|
||||
def __init__(self, eta=0.01, n_iter=50):
|
||||
self.eta = eta
|
||||
self.n_iter = n_iter
|
||||
|
||||
def fit(self, X, y):
|
||||
""" Fit training data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : {array-like}, shape = [n_samples, n_features]
|
||||
Training vectors, where n_samples is the number of samples and
|
||||
n_features is the number of features.
|
||||
y : array-like, shape = [n_samples]
|
||||
Target values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
self : object
|
||||
|
||||
"""
|
||||
self.w_ = np.zeros(1 + X.shape[1])
|
||||
self.cost_ = []
|
||||
|
||||
for i in range(self.n_iter):
|
||||
output = self.net_input(X)
|
||||
errors = (y - output)
|
||||
self.w_[1:] += self.eta * X.T.dot(errors)
|
||||
self.w_[0] += self.eta * errors.sum()
|
||||
cost = (errors**2).sum() / 2.0
|
||||
self.cost_.append(cost)
|
||||
return self
|
||||
|
||||
def net_input(self, X):
|
||||
"""Calculate net input"""
|
||||
return np.dot(X, self.w_[1:]) + self.w_[0]
|
||||
|
||||
def activation(self, X):
|
||||
"""Compute linear activation"""
|
||||
return self.net_input(X)
|
||||
|
||||
def predict(self, X):
|
||||
"""Return class label after unit step"""
|
||||
return np.where(self.activation(X) >= 0.0, 1, -1)
|
||||
|
||||
|
||||
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(8, 4))
|
||||
|
||||
ada1 = AdalineGD(n_iter=10, eta=0.01).fit(X, y)
|
||||
ax[0].plot(range(1, len(ada1.cost_) + 1), np.log10(ada1.cost_), marker='o')
|
||||
ax[0].set_xlabel('Epochs')
|
||||
ax[0].set_ylabel('log(Sum-squared-error)')
|
||||
ax[0].set_title('Adaline - Learning rate 0.01')
|
||||
|
||||
ada2 = AdalineGD(n_iter=10, eta=0.0001).fit(X, y)
|
||||
ax[1].plot(range(1, len(ada2.cost_) + 1), ada2.cost_, marker='o')
|
||||
ax[1].set_xlabel('Epochs')
|
||||
ax[1].set_ylabel('Sum-squared-error')
|
||||
ax[1].set_title('Adaline - Learning rate 0.0001')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./adaline_1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
print('standardize features')
|
||||
X_std = np.copy(X)
|
||||
X_std[:, 0] = (X[:, 0] - X[:, 0].mean()) / X[:, 0].std()
|
||||
X_std[:, 1] = (X[:, 1] - X[:, 1].mean()) / X[:, 1].std()
|
||||
|
||||
ada = AdalineGD(n_iter=15, eta=0.01)
|
||||
ada.fit(X_std, y)
|
||||
|
||||
plot_decision_regions(X_std, y, classifier=ada)
|
||||
plt.title('Adaline - Gradient Descent')
|
||||
plt.xlabel('sepal length [standardized]')
|
||||
plt.ylabel('petal length [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./adaline_2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
|
||||
plt.xlabel('Epochs')
|
||||
plt.ylabel('Sum-squared-error')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./adaline_3.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Large scale machine learning and stochastic gradient descent')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
class AdalineSGD(object):
|
||||
"""ADAptive LInear NEuron classifier.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
eta : float
|
||||
Learning rate (between 0.0 and 1.0)
|
||||
n_iter : int
|
||||
Passes over the training dataset.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
w_ : 1d-array
|
||||
Weights after fitting.
|
||||
cost_ : list
|
||||
Sum-of-squares cost function value averaged over all
|
||||
training samples in each epoch.
|
||||
shuffle : bool (default: True)
|
||||
Shuffles training data every epoch if True to prevent cycles.
|
||||
random_state : int (default: None)
|
||||
Set random state for shuffling and initializing the weights.
|
||||
|
||||
"""
|
||||
def __init__(self, eta=0.01, n_iter=10, shuffle=True, random_state=None):
|
||||
self.eta = eta
|
||||
self.n_iter = n_iter
|
||||
self.w_initialized = False
|
||||
self.shuffle = shuffle
|
||||
if random_state:
|
||||
np.random.seed(random_state)
|
||||
|
||||
def fit(self, X, y):
|
||||
""" Fit training data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : {array-like}, shape = [n_samples, n_features]
|
||||
Training vectors, where n_samples is the number of samples and
|
||||
n_features is the number of features.
|
||||
y : array-like, shape = [n_samples]
|
||||
Target values.
|
||||
|
||||
Returns
|
||||
-------
|
||||
self : object
|
||||
|
||||
"""
|
||||
self._initialize_weights(X.shape[1])
|
||||
self.cost_ = []
|
||||
for i in range(self.n_iter):
|
||||
if self.shuffle:
|
||||
X, y = self._shuffle(X, y)
|
||||
cost = []
|
||||
for xi, target in zip(X, y):
|
||||
cost.append(self._update_weights(xi, target))
|
||||
avg_cost = sum(cost) / len(y)
|
||||
self.cost_.append(avg_cost)
|
||||
return self
|
||||
|
||||
def partial_fit(self, X, y):
|
||||
"""Fit training data without reinitializing the weights"""
|
||||
if not self.w_initialized:
|
||||
self._initialize_weights(X.shape[1])
|
||||
if y.ravel().shape[0] > 1:
|
||||
for xi, target in zip(X, y):
|
||||
self._update_weights(xi, target)
|
||||
else:
|
||||
self._update_weights(X, y)
|
||||
return self
|
||||
|
||||
def _shuffle(self, X, y):
|
||||
"""Shuffle training data"""
|
||||
r = np.random.permutation(len(y))
|
||||
return X[r], y[r]
|
||||
|
||||
def _initialize_weights(self, m):
|
||||
"""Initialize weights to zeros"""
|
||||
self.w_ = np.zeros(1 + m)
|
||||
self.w_initialized = True
|
||||
|
||||
def _update_weights(self, xi, target):
|
||||
"""Apply Adaline learning rule to update the weights"""
|
||||
output = self.net_input(xi)
|
||||
error = (target - output)
|
||||
self.w_[1:] += self.eta * xi.dot(error)
|
||||
self.w_[0] += self.eta * error
|
||||
cost = 0.5 * error**2
|
||||
return cost
|
||||
|
||||
def net_input(self, X):
|
||||
"""Calculate net input"""
|
||||
return np.dot(X, self.w_[1:]) + self.w_[0]
|
||||
|
||||
def activation(self, X):
|
||||
"""Compute linear activation"""
|
||||
return self.net_input(X)
|
||||
|
||||
def predict(self, X):
|
||||
"""Return class label after unit step"""
|
||||
return np.where(self.activation(X) >= 0.0, 1, -1)
|
||||
|
||||
|
||||
ada = AdalineSGD(n_iter=15, eta=0.01, random_state=1)
|
||||
ada.fit(X_std, y)
|
||||
|
||||
plot_decision_regions(X_std, y, classifier=ada)
|
||||
plt.title('Adaline - Stochastic Gradient Descent')
|
||||
plt.xlabel('sepal length [standardized]')
|
||||
plt.ylabel('petal length [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./adaline_4.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
plt.plot(range(1, len(ada.cost_) + 1), ada.cost_, marker='o')
|
||||
plt.xlabel('Epochs')
|
||||
plt.ylabel('Average Cost')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./adaline_5.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
ada = ada.partial_fit(X_std[0, :], y[0])
|
||||
@@ -0,0 +1,431 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 3 - A Tour of Machine Learning Classifiers Using Scikit-Learn
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
import numpy as np
|
||||
from sklearn import datasets
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.metrics import accuracy_score
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.linear_model import Perceptron
|
||||
from sklearn.svm import SVC
|
||||
from sklearn.tree import DecisionTreeClassifier
|
||||
from sklearn.ensemble import RandomForestClassifier
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
# from sklearn.tree import export_graphviz
|
||||
from matplotlib.colors import ListedColormap
|
||||
import matplotlib.pyplot as plt
|
||||
import warnings
|
||||
|
||||
# for sklearn 0.18's alternative syntax
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.grid_search import train_test_split
|
||||
else:
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: First steps with scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
iris = datasets.load_iris()
|
||||
X = iris.data[:, [2, 3]]
|
||||
y = iris.target
|
||||
print('Class labels:', np.unique(y))
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y, test_size=0.3, random_state=0)
|
||||
|
||||
sc = StandardScaler()
|
||||
sc.fit(X_train)
|
||||
X_train_std = sc.transform(X_train)
|
||||
X_test_std = sc.transform(X_test)
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Training a perceptron via scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
ppn = Perceptron(n_iter=40, eta0=0.1, random_state=0)
|
||||
ppn.fit(X_train_std, y_train)
|
||||
print('Y array shape', y_test.shape)
|
||||
|
||||
y_pred = ppn.predict(X_test_std)
|
||||
print('Misclassified samples: %d' % (y_test != y_pred).sum())
|
||||
print('Accuracy: %.2f' % accuracy_score(y_test, y_pred))
|
||||
|
||||
|
||||
def versiontuple(v):
|
||||
return tuple(map(int, (v.split("."))))
|
||||
|
||||
|
||||
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):
|
||||
|
||||
# setup marker generator and color map
|
||||
markers = ('s', 'x', 'o', '^', 'v')
|
||||
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
|
||||
cmap = ListedColormap(colors[:len(np.unique(y))])
|
||||
|
||||
# plot the decision surface
|
||||
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
|
||||
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
|
||||
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
|
||||
np.arange(x2_min, x2_max, resolution))
|
||||
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
|
||||
Z = Z.reshape(xx1.shape)
|
||||
plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
|
||||
plt.xlim(xx1.min(), xx1.max())
|
||||
plt.ylim(xx2.min(), xx2.max())
|
||||
|
||||
for idx, cl in enumerate(np.unique(y)):
|
||||
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
|
||||
alpha=0.8, c=cmap(idx),
|
||||
marker=markers[idx], label=cl)
|
||||
|
||||
# highlight test samples
|
||||
if test_idx:
|
||||
# plot all samples
|
||||
if not versiontuple(np.__version__) >= versiontuple('1.9.0'):
|
||||
X_test, y_test = X[list(test_idx), :], y[list(test_idx)]
|
||||
warnings.warn('Please update to NumPy 1.9.0 or newer')
|
||||
else:
|
||||
X_test, y_test = X[test_idx, :], y[test_idx]
|
||||
|
||||
plt.scatter(X_test[:, 0],
|
||||
X_test[:, 1],
|
||||
c='',
|
||||
alpha=1.0,
|
||||
linewidths=1,
|
||||
marker='o',
|
||||
s=55, label='test set')
|
||||
|
||||
|
||||
X_combined_std = np.vstack((X_train_std, X_test_std))
|
||||
y_combined = np.hstack((y_train, y_test))
|
||||
|
||||
plot_decision_regions(X=X_combined_std, y=y_combined,
|
||||
classifier=ppn, test_idx=range(105, 150))
|
||||
plt.xlabel('petal length [standardized]')
|
||||
plt.ylabel('petal width [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/iris_perceptron_scikit.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Logistic regression intuition and conditional probabilities')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def sigmoid(z):
|
||||
return 1.0 / (1.0 + np.exp(-z))
|
||||
|
||||
|
||||
z = np.arange(-7, 7, 0.1)
|
||||
phi_z = sigmoid(z)
|
||||
|
||||
plt.plot(z, phi_z)
|
||||
plt.axvline(0.0, color='k')
|
||||
plt.ylim(-0.1, 1.1)
|
||||
plt.xlabel('z')
|
||||
plt.ylabel('$\phi (z)$')
|
||||
|
||||
# y axis ticks and gridline
|
||||
plt.yticks([0.0, 0.5, 1.0])
|
||||
ax = plt.gca()
|
||||
ax.yaxis.grid(True)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/sigmoid.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Learning the weights of the logistic cost function')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def cost_1(z):
|
||||
return - np.log(sigmoid(z))
|
||||
|
||||
|
||||
def cost_0(z):
|
||||
return - np.log(1 - sigmoid(z))
|
||||
|
||||
|
||||
z = np.arange(-10, 10, 0.1)
|
||||
phi_z = sigmoid(z)
|
||||
|
||||
c1 = [cost_1(x) for x in z]
|
||||
plt.plot(phi_z, c1, label='J(w) if y=1')
|
||||
|
||||
c0 = [cost_0(x) for x in z]
|
||||
plt.plot(phi_z, c0, linestyle='--', label='J(w) if y=0')
|
||||
|
||||
plt.ylim(0.0, 5.1)
|
||||
plt.xlim([0, 1])
|
||||
plt.xlabel('$\phi$(z)')
|
||||
plt.ylabel('J(w)')
|
||||
plt.legend(loc='best')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/log_cost.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Training a logistic regression model with scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
lr = LogisticRegression(C=1000.0, random_state=0)
|
||||
lr.fit(X_train_std, y_train)
|
||||
|
||||
plot_decision_regions(X_combined_std, y_combined,
|
||||
classifier=lr, test_idx=range(105, 150))
|
||||
plt.xlabel('petal length [standardized]')
|
||||
plt.ylabel('petal width [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/logistic_regression.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
print('Predicted probabilities', lr.predict_proba(X_test_std[0, :]
|
||||
.reshape(1, -1)))
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Tackling overfitting via regularization')
|
||||
print(50 * '-')
|
||||
|
||||
weights, params = [], []
|
||||
for c in np.arange(-5.0, 5.0):
|
||||
lr = LogisticRegression(C=10**c, random_state=0)
|
||||
lr.fit(X_train_std, y_train)
|
||||
weights.append(lr.coef_[1])
|
||||
params.append(10**c)
|
||||
|
||||
weights = np.array(weights)
|
||||
plt.plot(params, weights[:, 0],
|
||||
label='petal length')
|
||||
plt.plot(params, weights[:, 1], linestyle='--',
|
||||
label='petal width')
|
||||
plt.ylabel('weight coefficient')
|
||||
plt.xlabel('C')
|
||||
plt.legend(loc='upper left')
|
||||
plt.xscale('log')
|
||||
# plt.savefig('./figures/regression_path.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Dealing with the nonlinearly'
|
||||
'separable case using slack variables')
|
||||
print(50 * '-')
|
||||
|
||||
svm = SVC(kernel='linear', C=1.0, random_state=0)
|
||||
svm.fit(X_train_std, y_train)
|
||||
|
||||
plot_decision_regions(X_combined_std, y_combined,
|
||||
classifier=svm, test_idx=range(105, 150))
|
||||
plt.xlabel('petal length [standardized]')
|
||||
plt.ylabel('petal width [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/support_vector_machine_linear.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Solving non-linear problems using a kernel SVM')
|
||||
print(50 * '-')
|
||||
|
||||
np.random.seed(0)
|
||||
X_xor = np.random.randn(200, 2)
|
||||
y_xor = np.logical_xor(X_xor[:, 0] > 0,
|
||||
X_xor[:, 1] > 0)
|
||||
y_xor = np.where(y_xor, 1, -1)
|
||||
|
||||
plt.scatter(X_xor[y_xor == 1, 0],
|
||||
X_xor[y_xor == 1, 1],
|
||||
c='b', marker='x',
|
||||
label='1')
|
||||
plt.scatter(X_xor[y_xor == -1, 0],
|
||||
X_xor[y_xor == -1, 1],
|
||||
c='r',
|
||||
marker='s',
|
||||
label='-1')
|
||||
|
||||
plt.xlim([-3, 3])
|
||||
plt.ylim([-3, 3])
|
||||
plt.legend(loc='best')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/xor.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Using the kernel trick to find separating hyperplanes'
|
||||
'in higher dimensional space')
|
||||
print(50 * '-')
|
||||
|
||||
svm = SVC(kernel='rbf', random_state=0, gamma=0.10, C=10.0)
|
||||
svm.fit(X_xor, y_xor)
|
||||
plot_decision_regions(X_xor, y_xor,
|
||||
classifier=svm)
|
||||
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/support_vector_machine_rbf_xor.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
svm = SVC(kernel='rbf', random_state=0, gamma=0.2, C=1.0)
|
||||
svm.fit(X_train_std, y_train)
|
||||
|
||||
plot_decision_regions(X_combined_std, y_combined,
|
||||
classifier=svm, test_idx=range(105, 150))
|
||||
plt.xlabel('petal length [standardized]')
|
||||
plt.ylabel('petal width [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/support_vector_machine_rbf_iris_1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
svm = SVC(kernel='rbf', random_state=0, gamma=100.0, C=1.0)
|
||||
svm.fit(X_train_std, y_train)
|
||||
|
||||
plot_decision_regions(X_combined_std, y_combined,
|
||||
classifier=svm, test_idx=range(105, 150))
|
||||
plt.xlabel('petal length [standardized]')
|
||||
plt.ylabel('petal width [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/support_vector_machine_rbf_iris_2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Decision tree learning')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def gini(p):
|
||||
return p * (1 - p) + (1 - p) * (1 - (1 - p))
|
||||
|
||||
|
||||
def entropy(p):
|
||||
return - p * np.log2(p) - (1 - p) * np.log2((1 - p))
|
||||
|
||||
|
||||
def error(p):
|
||||
return 1 - np.max([p, 1 - p])
|
||||
|
||||
|
||||
x = np.arange(0.0, 1.0, 0.01)
|
||||
|
||||
ent = [entropy(p) if p != 0 else None for p in x]
|
||||
sc_ent = [e * 0.5 if e else None for e in ent]
|
||||
err = [error(i) for i in x]
|
||||
|
||||
fig = plt.figure()
|
||||
ax = plt.subplot(111)
|
||||
for i, lab, ls, c, in zip([ent, sc_ent, gini(x), err],
|
||||
['Entropy', 'Entropy (scaled)',
|
||||
'Gini Impurity', 'Misclassification Error'],
|
||||
['-', '-', '--', '-.'],
|
||||
['black', 'lightgray', 'red', 'green', 'cyan']):
|
||||
line = ax.plot(x, i, label=lab, linestyle=ls, lw=2, color=c)
|
||||
|
||||
ax.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15),
|
||||
ncol=3, fancybox=True, shadow=False)
|
||||
|
||||
ax.axhline(y=0.5, linewidth=1, color='k', linestyle='--')
|
||||
ax.axhline(y=1.0, linewidth=1, color='k', linestyle='--')
|
||||
plt.ylim([0, 1.1])
|
||||
plt.xlabel('p(i=1)')
|
||||
plt.ylabel('Impurity Index')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/impurity.png', dpi=300, bbox_inches='tight')
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Building a decision tree')
|
||||
print(50 * '-')
|
||||
|
||||
tree = DecisionTreeClassifier(criterion='entropy', max_depth=3, random_state=0)
|
||||
tree.fit(X_train, y_train)
|
||||
|
||||
X_combined = np.vstack((X_train, X_test))
|
||||
y_combined = np.hstack((y_train, y_test))
|
||||
plot_decision_regions(X_combined, y_combined,
|
||||
classifier=tree, test_idx=range(105, 150))
|
||||
|
||||
plt.xlabel('petal length [cm]')
|
||||
plt.ylabel('petal width [cm]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/decision_tree_decision.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
# export_graphviz(tree,
|
||||
# out_file='tree.dot',
|
||||
# feature_names=['petal length', 'petal width'])
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Combining weak to strong learners via random forests')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
forest = RandomForestClassifier(criterion='entropy',
|
||||
n_estimators=10,
|
||||
random_state=1,
|
||||
n_jobs=2)
|
||||
forest.fit(X_train, y_train)
|
||||
|
||||
plot_decision_regions(X_combined, y_combined,
|
||||
classifier=forest, test_idx=range(105, 150))
|
||||
|
||||
plt.xlabel('petal length [cm]')
|
||||
plt.ylabel('petal width [cm]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/random_forest.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: K-nearest neighbors - a lazy learning algorithm')
|
||||
print(50 * '-')
|
||||
|
||||
knn = KNeighborsClassifier(n_neighbors=5, p=2, metric='minkowski')
|
||||
knn.fit(X_train_std, y_train)
|
||||
|
||||
plot_decision_regions(X_combined_std, y_combined,
|
||||
classifier=knn, test_idx=range(105, 150))
|
||||
|
||||
plt.xlabel('petal length [standardized]')
|
||||
plt.ylabel('petal width [standardized]')
|
||||
plt.legend(loc='upper left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/k_nearest_neighbors.png', dpi=300)
|
||||
plt.show()
|
||||
@@ -0,0 +1,398 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 4 - Building Good Training Sets – Data Pre-Processing
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from io import StringIO
|
||||
from sklearn.preprocessing import Imputer
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
from sklearn.preprocessing import OneHotEncoder
|
||||
from sklearn.preprocessing import MinMaxScaler
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
from sklearn.ensemble import RandomForestClassifier
|
||||
from sklearn.base import clone
|
||||
from sklearn.metrics import accuracy_score
|
||||
from itertools import combinations
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
# for sklearn 0.18's alternative syntax
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.grid_search import train_test_split
|
||||
else:
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Dealing with missing data')
|
||||
print(50 * '-')
|
||||
|
||||
csv_data = '''A,B,C,D
|
||||
1.0,2.0,3.0,4.0
|
||||
5.0,6.0,,8.0
|
||||
10.0,11.0,12.0,'''
|
||||
|
||||
# If you are using Python 2.7, you need
|
||||
# to convert the string to unicode:
|
||||
# csv_data = unicode(csv_data)
|
||||
|
||||
df = pd.read_csv(StringIO(csv_data))
|
||||
print(df)
|
||||
print('\n\nExecuting df.isnull().sum():')
|
||||
print(df.isnull().sum())
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Eliminating samples or features with missing values')
|
||||
print(50 * '-')
|
||||
|
||||
print('\n\nExecuting df.dropna()')
|
||||
print(df.dropna())
|
||||
|
||||
print('\n\nExecuting df.dropna(axis=1)')
|
||||
print(df.dropna(axis=1))
|
||||
|
||||
print("\n\nExecuting df.dropna(thresh=4)")
|
||||
print("(drop rows that have not at least 4 non-NaN values)")
|
||||
print(df.dropna(thresh=4))
|
||||
|
||||
print("\n\nExecuting df.dropna(how='all')")
|
||||
print("(only drop rows where all columns are NaN)")
|
||||
print(df.dropna(how='all'))
|
||||
|
||||
print("\n\nExecuting df.dropna(subset=['C'])")
|
||||
print("(only drop rows where NaN appear in specific columns (here: 'C'))")
|
||||
print(df.dropna(subset=['C']))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Imputing missing values')
|
||||
print(50 * '-')
|
||||
|
||||
imr = Imputer(missing_values='NaN', strategy='mean', axis=0)
|
||||
imr = imr.fit(df)
|
||||
imputed_data = imr.transform(df.values)
|
||||
|
||||
print('Input Array:\n', df.values)
|
||||
print('Imputed Data:\n', imputed_data)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Handling categorical data')
|
||||
print(50 * '-')
|
||||
|
||||
df = pd.DataFrame([['green', 'M', 10.1, 'class1'],
|
||||
['red', 'L', 13.5, 'class2'],
|
||||
['blue', 'XL', 15.3, 'class1']])
|
||||
|
||||
df.columns = ['color', 'size', 'price', 'classlabel']
|
||||
print('Input Array:\n', df)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Mapping ordinal features')
|
||||
print(50 * '-')
|
||||
|
||||
size_mapping = {'XL': 3,
|
||||
'L': 2,
|
||||
'M': 1}
|
||||
|
||||
df['size'] = df['size'].map(size_mapping)
|
||||
print('Mapping:\n', df)
|
||||
|
||||
inv_size_mapping = {v: k for k, v in size_mapping.items()}
|
||||
df_inv = df['size'].map(inv_size_mapping)
|
||||
print('\nInverse mapping:\n', df_inv)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Encoding class labels')
|
||||
print(50 * '-')
|
||||
|
||||
class_mapping = {label: idx for idx, label
|
||||
in enumerate(np.unique(df['classlabel']))}
|
||||
print('\nClass mapping:\n', class_mapping)
|
||||
|
||||
df['classlabel'] = df['classlabel'].map(class_mapping)
|
||||
print('Mapping:\n', df)
|
||||
|
||||
inv_class_mapping = {v: k for k, v in class_mapping.items()}
|
||||
df_inv = df['classlabel'] = df['classlabel'].map(inv_class_mapping)
|
||||
print('\nInverse mapping:\n', df_inv)
|
||||
|
||||
class_le = LabelEncoder()
|
||||
y = class_le.fit_transform(df['classlabel'].values)
|
||||
print('Label encoder tansform:\n', y)
|
||||
|
||||
y_inv = class_le.inverse_transform(y)
|
||||
print('Label encoder inverse tansform:\n', y_inv)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Performing one hot encoding on nominal features')
|
||||
print(50 * '-')
|
||||
|
||||
X = df[['color', 'size', 'price']].values
|
||||
|
||||
color_le = LabelEncoder()
|
||||
X[:, 0] = color_le.fit_transform(X[:, 0])
|
||||
print("Input array:\n", X)
|
||||
|
||||
ohe = OneHotEncoder(categorical_features=[0])
|
||||
X_onehot = ohe.fit_transform(X).toarray()
|
||||
print("Encoded array:\n", X_onehot)
|
||||
|
||||
df_dummies = pd.get_dummies(df[['price', 'color', 'size']])
|
||||
print("Pandas get_dummies alternative:\n", df_dummies)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Partitioning a dataset in training and test sets')
|
||||
print(50 * '-')
|
||||
|
||||
df_wine = pd.read_csv('https://archive.ics.uci.edu/'
|
||||
'ml/machine-learning-databases/wine/wine.data',
|
||||
header=None)
|
||||
|
||||
df_wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
|
||||
'Alcalinity of ash', 'Magnesium', 'Total phenols',
|
||||
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
|
||||
'Color intensity', 'Hue', 'OD280/OD315 of diluted wines',
|
||||
'Proline']
|
||||
|
||||
print('Class labels', np.unique(df_wine['Class label']))
|
||||
|
||||
print('\nWine data excerpt:\n\n', df_wine.head())
|
||||
|
||||
|
||||
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
|
||||
|
||||
X_train, X_test, y_train, y_test = \
|
||||
train_test_split(X, y, test_size=0.3, random_state=0)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Bringing features onto the same scale')
|
||||
print(50 * '-')
|
||||
|
||||
mms = MinMaxScaler()
|
||||
X_train_norm = mms.fit_transform(X_train)
|
||||
X_test_norm = mms.transform(X_test)
|
||||
|
||||
stdsc = StandardScaler()
|
||||
X_train_std = stdsc.fit_transform(X_train)
|
||||
X_test_std = stdsc.transform(X_test)
|
||||
|
||||
ex = pd.DataFrame([0, 1, 2, 3, 4, 5])
|
||||
print('Scaling Example:\n')
|
||||
print('\nInput array:\n', ex)
|
||||
ex[1] = (ex[0] - ex[0].mean()) / ex[0].std(ddof=0)
|
||||
|
||||
# Please note that pandas uses ddof=1 (sample standard deviation)
|
||||
# by default, whereas NumPy's std method and the StandardScaler
|
||||
# uses ddof=0 (population standard deviation)
|
||||
|
||||
# normalize
|
||||
ex[2] = (ex[0] - ex[0].min()) / (ex[0].max() - ex[0].min())
|
||||
ex.columns = ['input', 'standardized', 'normalized']
|
||||
print('\nOutput array after scaling:\n', ex)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Sparse solutions with L1-regularization')
|
||||
print(50 * '-')
|
||||
|
||||
lr = LogisticRegression(penalty='l1', C=0.1)
|
||||
lr.fit(X_train_std, y_train)
|
||||
print('Training accuracy:', lr.score(X_train_std, y_train))
|
||||
print('Test accuracy:', lr.score(X_test_std, y_test))
|
||||
print('Intercept:', lr.intercept_)
|
||||
print('Model weights:', lr.coef_)
|
||||
|
||||
fig = plt.figure()
|
||||
ax = plt.subplot(111)
|
||||
|
||||
colors = ['blue', 'green', 'red', 'cyan',
|
||||
'magenta', 'yellow', 'black',
|
||||
'pink', 'lightgreen', 'lightblue',
|
||||
'gray', 'indigo', 'orange']
|
||||
|
||||
weights, params = [], []
|
||||
for c in np.arange(-4.0, 6.0):
|
||||
lr = LogisticRegression(penalty='l1', C=10**c, random_state=0)
|
||||
lr.fit(X_train_std, y_train)
|
||||
weights.append(lr.coef_[1])
|
||||
params.append(10**c)
|
||||
|
||||
weights = np.array(weights)
|
||||
|
||||
for column, color in zip(range(weights.shape[1]), colors):
|
||||
plt.plot(params, weights[:, column],
|
||||
label=df_wine.columns[column + 1],
|
||||
color=color)
|
||||
plt.axhline(0, color='black', linestyle='--', linewidth=3)
|
||||
plt.xlim([10**(-5), 10**5])
|
||||
plt.ylabel('weight coefficient')
|
||||
plt.xlabel('C')
|
||||
plt.xscale('log')
|
||||
plt.legend(loc='upper left')
|
||||
ax.legend(loc='upper center',
|
||||
bbox_to_anchor=(1.38, 1.03),
|
||||
ncol=1, fancybox=True)
|
||||
# plt.savefig('./figures/l1_path.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Sequential feature selection algorithms')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
class SBS():
|
||||
def __init__(self, estimator, k_features, scoring=accuracy_score,
|
||||
test_size=0.25, random_state=1):
|
||||
self.scoring = scoring
|
||||
self.estimator = clone(estimator)
|
||||
self.k_features = k_features
|
||||
self.test_size = test_size
|
||||
self.random_state = random_state
|
||||
|
||||
def fit(self, X, y):
|
||||
|
||||
X_train, X_test, y_train, y_test = \
|
||||
train_test_split(X, y, test_size=self.test_size,
|
||||
random_state=self.random_state)
|
||||
|
||||
dim = X_train.shape[1]
|
||||
self.indices_ = tuple(range(dim))
|
||||
self.subsets_ = [self.indices_]
|
||||
score = self._calc_score(X_train, y_train,
|
||||
X_test, y_test, self.indices_)
|
||||
self.scores_ = [score]
|
||||
|
||||
while dim > self.k_features:
|
||||
scores = []
|
||||
subsets = []
|
||||
|
||||
for p in combinations(self.indices_, r=dim - 1):
|
||||
score = self._calc_score(X_train, y_train,
|
||||
X_test, y_test, p)
|
||||
scores.append(score)
|
||||
subsets.append(p)
|
||||
|
||||
best = np.argmax(scores)
|
||||
self.indices_ = subsets[best]
|
||||
self.subsets_.append(self.indices_)
|
||||
dim -= 1
|
||||
|
||||
self.scores_.append(scores[best])
|
||||
self.k_score_ = self.scores_[-1]
|
||||
|
||||
return self
|
||||
|
||||
def transform(self, X):
|
||||
return X[:, self.indices_]
|
||||
|
||||
def _calc_score(self, X_train, y_train, X_test, y_test, indices):
|
||||
self.estimator.fit(X_train[:, indices], y_train)
|
||||
y_pred = self.estimator.predict(X_test[:, indices])
|
||||
score = self.scoring(y_test, y_pred)
|
||||
return score
|
||||
|
||||
|
||||
knn = KNeighborsClassifier(n_neighbors=2)
|
||||
|
||||
# selecting features
|
||||
sbs = SBS(knn, k_features=1)
|
||||
sbs.fit(X_train_std, y_train)
|
||||
|
||||
# plotting performance of feature subsets
|
||||
k_feat = [len(k) for k in sbs.subsets_]
|
||||
|
||||
plt.plot(k_feat, sbs.scores_, marker='o')
|
||||
plt.ylim([0.7, 1.1])
|
||||
plt.ylabel('Accuracy')
|
||||
plt.xlabel('Number of features')
|
||||
plt.grid()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./sbs.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
k5 = list(sbs.subsets_[8])
|
||||
print('Selected top 5 features:\n', df_wine.columns[1:][k5])
|
||||
|
||||
knn.fit(X_train_std, y_train)
|
||||
print('\nPerformance using all features:\n')
|
||||
print('Training accuracy:', knn.score(X_train_std, y_train))
|
||||
print('Test accuracy:', knn.score(X_test_std, y_test))
|
||||
|
||||
knn.fit(X_train_std[:, k5], y_train)
|
||||
print('\nPerformance using the top 5 features:\n')
|
||||
print('Training accuracy:', knn.score(X_train_std[:, k5], y_train))
|
||||
print('Test accuracy:', knn.score(X_test_std[:, k5], y_test))
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Assessing Feature Importances with Random Forests')
|
||||
print(50 * '-')
|
||||
|
||||
feat_labels = df_wine.columns[1:]
|
||||
|
||||
forest = RandomForestClassifier(n_estimators=10000,
|
||||
random_state=0,
|
||||
n_jobs=-1)
|
||||
|
||||
forest.fit(X_train, y_train)
|
||||
importances = forest.feature_importances_
|
||||
|
||||
indices = np.argsort(importances)[::-1]
|
||||
|
||||
for f in range(X_train.shape[1]):
|
||||
print("%2d) %-*s %f" % (f + 1, 30,
|
||||
feat_labels[indices[f]],
|
||||
importances[indices[f]]))
|
||||
|
||||
plt.title('Feature Importances')
|
||||
plt.bar(range(X_train.shape[1]),
|
||||
importances[indices],
|
||||
color='lightblue',
|
||||
align='center')
|
||||
|
||||
plt.xticks(range(X_train.shape[1]),
|
||||
feat_labels[indices], rotation=90)
|
||||
plt.xlim([-1, X_train.shape[1]])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./random_forest.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
if Version(sklearn_version) < '0.18':
|
||||
X_selected = forest.transform(X_train, threshold=0.15)
|
||||
else:
|
||||
from sklearn.feature_selection import SelectFromModel
|
||||
sfm = SelectFromModel(forest, threshold=0.15, prefit=True)
|
||||
X_selected = sfm.transform(X_train)
|
||||
|
||||
X_selected.shape
|
||||
@@ -0,0 +1,639 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 5 - Compressing Data via Dimensionality Reduction
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.decomposition import PCA
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import ListedColormap
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
|
||||
from sklearn.datasets import make_moons
|
||||
from sklearn.datasets import make_circles
|
||||
from sklearn.decomposition import KernelPCA
|
||||
from scipy.spatial.distance import pdist, squareform
|
||||
from scipy import exp
|
||||
from scipy.linalg import eigh
|
||||
from matplotlib.ticker import FormatStrFormatter
|
||||
|
||||
# for sklearn 0.18's alternative syntax
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.grid_search import train_test_split
|
||||
from sklearn.lda import LDA
|
||||
else:
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Unsupervised dimensionality reduction'
|
||||
' via principal component analysis')
|
||||
print(50 * '-')
|
||||
|
||||
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/'
|
||||
'machine-learning-databases/wine/wine.data',
|
||||
header=None)
|
||||
|
||||
df_wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
|
||||
'Alcalinity of ash', 'Magnesium', 'Total phenols',
|
||||
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
|
||||
'Color intensity', 'Hue',
|
||||
'OD280/OD315 of diluted wines', 'Proline']
|
||||
|
||||
print('Wine data excerpt:\n\n:', df_wine.head())
|
||||
|
||||
|
||||
X, y = df_wine.iloc[:, 1:].values, df_wine.iloc[:, 0].values
|
||||
|
||||
X_train, X_test, y_train, y_test = \
|
||||
train_test_split(X, y, test_size=0.3, random_state=0)
|
||||
|
||||
sc = StandardScaler()
|
||||
X_train_std = sc.fit_transform(X_train)
|
||||
X_test_std = sc.transform(X_test)
|
||||
|
||||
cov_mat = np.cov(X_train_std.T)
|
||||
eigen_vals, eigen_vecs = np.linalg.eig(cov_mat)
|
||||
|
||||
print('\nEigenvalues \n%s' % eigen_vals)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Total and explained variance')
|
||||
print(50 * '-')
|
||||
|
||||
tot = sum(eigen_vals)
|
||||
var_exp = [(i / tot) for i in sorted(eigen_vals, reverse=True)]
|
||||
cum_var_exp = np.cumsum(var_exp)
|
||||
|
||||
plt.bar(range(1, 14), var_exp, alpha=0.5, align='center',
|
||||
label='individual explained variance')
|
||||
plt.step(range(1, 14), cum_var_exp, where='mid',
|
||||
label='cumulative explained variance')
|
||||
plt.ylabel('Explained variance ratio')
|
||||
plt.xlabel('Principal components')
|
||||
plt.legend(loc='best')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/pca1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Feature Transformation')
|
||||
print(50 * '-')
|
||||
|
||||
# Make a list of (eigenvalue, eigenvector) tuples
|
||||
eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i])
|
||||
for i in range(len(eigen_vals))]
|
||||
|
||||
# Sort the (eigenvalue, eigenvector) tuples from high to low
|
||||
eigen_pairs.sort(reverse=True)
|
||||
|
||||
w = np.hstack((eigen_pairs[0][1][:, np.newaxis],
|
||||
eigen_pairs[1][1][:, np.newaxis]))
|
||||
print('Matrix W:\n', w)
|
||||
|
||||
X_train_pca = X_train_std.dot(w)
|
||||
colors = ['r', 'b', 'g']
|
||||
markers = ['s', 'x', 'o']
|
||||
|
||||
for l, c, m in zip(np.unique(y_train), colors, markers):
|
||||
plt.scatter(X_train_pca[y_train == l, 0],
|
||||
X_train_pca[y_train == l, 1],
|
||||
c=c, label=l, marker=m)
|
||||
|
||||
plt.xlabel('PC 1')
|
||||
plt.ylabel('PC 2')
|
||||
plt.legend(loc='lower left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/pca2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
print('Dot product:\n', X_train_std[0].dot(w))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Principal component analysis in scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
pca = PCA()
|
||||
X_train_pca = pca.fit_transform(X_train_std)
|
||||
print('Variance explained ratio:\n', pca.explained_variance_ratio_)
|
||||
|
||||
plt.bar(range(1, 14), pca.explained_variance_ratio_, alpha=0.5, align='center')
|
||||
plt.step(range(1, 14), np.cumsum(pca.explained_variance_ratio_), where='mid')
|
||||
plt.ylabel('Explained variance ratio')
|
||||
plt.xlabel('Principal components')
|
||||
plt.show()
|
||||
|
||||
pca = PCA(n_components=2)
|
||||
X_train_pca = pca.fit_transform(X_train_std)
|
||||
X_test_pca = pca.transform(X_test_std)
|
||||
|
||||
plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1])
|
||||
plt.xlabel('PC 1')
|
||||
plt.ylabel('PC 2')
|
||||
plt.show()
|
||||
|
||||
|
||||
def plot_decision_regions(X, y, classifier, resolution=0.02):
|
||||
|
||||
# setup marker generator and color map
|
||||
markers = ('s', 'x', 'o', '^', 'v')
|
||||
colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
|
||||
cmap = ListedColormap(colors[:len(np.unique(y))])
|
||||
|
||||
# plot the decision surface
|
||||
x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
|
||||
x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
|
||||
xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
|
||||
np.arange(x2_min, x2_max, resolution))
|
||||
Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
|
||||
Z = Z.reshape(xx1.shape)
|
||||
plt.contourf(xx1, xx2, Z, alpha=0.4, cmap=cmap)
|
||||
plt.xlim(xx1.min(), xx1.max())
|
||||
plt.ylim(xx2.min(), xx2.max())
|
||||
|
||||
# plot class samples
|
||||
for idx, cl in enumerate(np.unique(y)):
|
||||
plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],
|
||||
alpha=0.8, c=cmap(idx),
|
||||
marker=markers[idx], label=cl)
|
||||
|
||||
|
||||
lr = LogisticRegression()
|
||||
lr = lr.fit(X_train_pca, y_train)
|
||||
|
||||
plot_decision_regions(X_train_pca, y_train, classifier=lr)
|
||||
plt.xlabel('PC 1')
|
||||
plt.ylabel('PC 2')
|
||||
plt.legend(loc='lower left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/pca3.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
plot_decision_regions(X_test_pca, y_test, classifier=lr)
|
||||
plt.xlabel('PC 1')
|
||||
plt.ylabel('PC 2')
|
||||
plt.legend(loc='lower left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/pca4.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
pca = PCA(n_components=None)
|
||||
X_train_pca = pca.fit_transform(X_train_std)
|
||||
print('Explaind variance ratio:\n', pca.explained_variance_ratio_)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Supervised data compression via linear discriminant analysis'
|
||||
' - Computing the scatter matrices')
|
||||
print(50 * '-')
|
||||
|
||||
np.set_printoptions(precision=4)
|
||||
|
||||
mean_vecs = []
|
||||
for label in range(1, 4):
|
||||
mean_vecs.append(np.mean(X_train_std[y_train == label], axis=0))
|
||||
print('MV %s: %s\n' % (label, mean_vecs[label - 1]))
|
||||
|
||||
|
||||
d = 13 # number of features
|
||||
S_W = np.zeros((d, d))
|
||||
for label, mv in zip(range(1, 4), mean_vecs):
|
||||
class_scatter = np.zeros((d, d)) # scatter matrix for each class
|
||||
for row in X_train_std[y_train == label]:
|
||||
row, mv = row.reshape(d, 1), mv.reshape(d, 1) # make column vectors
|
||||
class_scatter += (row - mv).dot((row - mv).T)
|
||||
S_W += class_scatter # sum class scatter matrices
|
||||
|
||||
print('Within-class scatter matrix: %sx%s' % (S_W.shape[0], S_W.shape[1]))
|
||||
|
||||
print('Class label distribution: %s'
|
||||
% np.bincount(y_train)[1:])
|
||||
|
||||
d = 13 # number of features
|
||||
S_W = np.zeros((d, d))
|
||||
for label, mv in zip(range(1, 4), mean_vecs):
|
||||
class_scatter = np.cov(X_train_std[y_train == label].T)
|
||||
S_W += class_scatter
|
||||
print('Scaled within-class scatter matrix: %sx%s' % (S_W.shape[0],
|
||||
S_W.shape[1]))
|
||||
|
||||
|
||||
mean_overall = np.mean(X_train_std, axis=0)
|
||||
d = 13 # number of features
|
||||
S_B = np.zeros((d, d))
|
||||
for i, mean_vec in enumerate(mean_vecs):
|
||||
n = X_train[y_train == i + 1, :].shape[0]
|
||||
mean_vec = mean_vec.reshape(d, 1) # make column vector
|
||||
mean_overall = mean_overall.reshape(d, 1) # make column vector
|
||||
S_B += n * (mean_vec - mean_overall).dot((mean_vec - mean_overall).T)
|
||||
|
||||
print('Between-class scatter matrix: %sx%s' % (S_B.shape[0], S_B.shape[1]))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Selecting linear discriminants for the new feature subspace')
|
||||
print(50 * '-')
|
||||
|
||||
eigen_vals, eigen_vecs = np.linalg.eig(np.linalg.inv(S_W).dot(S_B))
|
||||
|
||||
# Make a list of (eigenvalue, eigenvector) tuples
|
||||
eigen_pairs = [(np.abs(eigen_vals[i]), eigen_vecs[:, i])
|
||||
for i in range(len(eigen_vals))]
|
||||
|
||||
# Sort the (eigenvalue, eigenvector) tuples from high to low
|
||||
eigen_pairs = sorted(eigen_pairs, key=lambda k: k[0], reverse=True)
|
||||
|
||||
# Visually confirm that the list is correctly sorted by decreasing eigenvalues
|
||||
|
||||
print('Eigenvalues in decreasing order:\n')
|
||||
for eigen_val in eigen_pairs:
|
||||
print(eigen_val[0])
|
||||
|
||||
tot = sum(eigen_vals.real)
|
||||
discr = [(i / tot) for i in sorted(eigen_vals.real, reverse=True)]
|
||||
cum_discr = np.cumsum(discr)
|
||||
|
||||
plt.bar(range(1, 14), discr, alpha=0.5, align='center',
|
||||
label='individual "discriminability"')
|
||||
plt.step(range(1, 14), cum_discr, where='mid',
|
||||
label='cumulative "discriminability"')
|
||||
plt.ylabel('"discriminability" ratio')
|
||||
plt.xlabel('Linear Discriminants')
|
||||
plt.ylim([-0.1, 1.1])
|
||||
plt.legend(loc='best')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/lda1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
w = np.hstack((eigen_pairs[0][1][:, np.newaxis].real,
|
||||
eigen_pairs[1][1][:, np.newaxis].real))
|
||||
print('Matrix W:\n', w)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Projecting samples onto the new feature space')
|
||||
print(50 * '-')
|
||||
|
||||
X_train_lda = X_train_std.dot(w)
|
||||
colors = ['r', 'b', 'g']
|
||||
markers = ['s', 'x', 'o']
|
||||
|
||||
for l, c, m in zip(np.unique(y_train), colors, markers):
|
||||
plt.scatter(X_train_lda[y_train == l, 0] * (-1),
|
||||
X_train_lda[y_train == l, 1] * (-1),
|
||||
c=c, label=l, marker=m)
|
||||
|
||||
plt.xlabel('LD 1')
|
||||
plt.ylabel('LD 2')
|
||||
plt.legend(loc='lower right')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/lda2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: LDA via scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
lda = LDA(n_components=2)
|
||||
X_train_lda = lda.fit_transform(X_train_std, y_train)
|
||||
|
||||
lr = LogisticRegression()
|
||||
lr = lr.fit(X_train_lda, y_train)
|
||||
|
||||
plot_decision_regions(X_train_lda, y_train, classifier=lr)
|
||||
plt.xlabel('LD 1')
|
||||
plt.ylabel('LD 2')
|
||||
plt.legend(loc='lower left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./images/lda3.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
X_test_lda = lda.transform(X_test_std)
|
||||
|
||||
plot_decision_regions(X_test_lda, y_test, classifier=lr)
|
||||
plt.xlabel('LD 1')
|
||||
plt.ylabel('LD 2')
|
||||
plt.legend(loc='lower left')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./images/lda4.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Implementing a kernel principal component analysis in Python')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def rbf_kernel_pca(X, gamma, n_components):
|
||||
"""
|
||||
RBF kernel PCA implementation.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
X: {NumPy ndarray}, shape = [n_samples, n_features]
|
||||
|
||||
gamma: float
|
||||
Tuning parameter of the RBF kernel
|
||||
|
||||
n_components: int
|
||||
Number of principal components to return
|
||||
|
||||
Returns
|
||||
------------
|
||||
X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
|
||||
Projected dataset
|
||||
|
||||
"""
|
||||
# Calculate pairwise squared Euclidean distances
|
||||
# in the MxN dimensional dataset.
|
||||
sq_dists = pdist(X, 'sqeuclidean')
|
||||
|
||||
# Convert pairwise distances into a square matrix.
|
||||
mat_sq_dists = squareform(sq_dists)
|
||||
|
||||
# Compute the symmetric kernel matrix.
|
||||
K = exp(-gamma * mat_sq_dists)
|
||||
|
||||
# Center the kernel matrix.
|
||||
N = K.shape[0]
|
||||
one_n = np.ones((N, N)) / N
|
||||
K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)
|
||||
|
||||
# Obtaining eigenpairs from the centered kernel matrix
|
||||
# numpy.eigh returns them in sorted order
|
||||
eigvals, eigvecs = eigh(K)
|
||||
|
||||
# Collect the top k eigenvectors (projected samples)
|
||||
X_pc = np.column_stack((eigvecs[:, -i]
|
||||
for i in range(1, n_components + 1)))
|
||||
|
||||
return X_pc
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Example 1: Separating half-moon shapes')
|
||||
print(50 * '-')
|
||||
|
||||
X, y = make_moons(n_samples=100, random_state=123)
|
||||
|
||||
plt.scatter(X[y == 0, 0], X[y == 0, 1], color='red', marker='^', alpha=0.5)
|
||||
plt.scatter(X[y == 1, 0], X[y == 1, 1], color='blue', marker='o', alpha=0.5)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/half_moon_1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
scikit_pca = PCA(n_components=2)
|
||||
X_spca = scikit_pca.fit_transform(X)
|
||||
|
||||
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(7, 3))
|
||||
|
||||
ax[0].scatter(X_spca[y == 0, 0], X_spca[y == 0, 1],
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[0].scatter(X_spca[y == 1, 0], X_spca[y == 1, 1],
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[1].scatter(X_spca[y == 0, 0], np.zeros((50, 1)) + 0.02,
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[1].scatter(X_spca[y == 1, 0], np.zeros((50, 1)) - 0.02,
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[0].set_xlabel('PC1')
|
||||
ax[0].set_ylabel('PC2')
|
||||
ax[1].set_ylim([-1, 1])
|
||||
ax[1].set_yticks([])
|
||||
ax[1].set_xlabel('PC1')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/half_moon_2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
X_kpca = rbf_kernel_pca(X, gamma=15, n_components=2)
|
||||
|
||||
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(7, 3))
|
||||
ax[0].scatter(X_kpca[y == 0, 0], X_kpca[y == 0, 1],
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[0].scatter(X_kpca[y == 1, 0], X_kpca[y == 1, 1],
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[1].scatter(X_kpca[y == 0, 0], np.zeros((50, 1)) + 0.02,
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[1].scatter(X_kpca[y == 1, 0], np.zeros((50, 1)) - 0.02,
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[0].set_xlabel('PC1')
|
||||
ax[0].set_ylabel('PC2')
|
||||
ax[1].set_ylim([-1, 1])
|
||||
ax[1].set_yticks([])
|
||||
ax[1].set_xlabel('PC1')
|
||||
ax[0].xaxis.set_major_formatter(FormatStrFormatter('%0.1f'))
|
||||
ax[1].xaxis.set_major_formatter(FormatStrFormatter('%0.1f'))
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/half_moon_3.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Example 2: Separating concentric circles')
|
||||
print(50 * '-')
|
||||
|
||||
X, y = make_circles(n_samples=1000, random_state=123, noise=0.1, factor=0.2)
|
||||
|
||||
plt.scatter(X[y == 0, 0], X[y == 0, 1], color='red', marker='^', alpha=0.5)
|
||||
plt.scatter(X[y == 1, 0], X[y == 1, 1], color='blue', marker='o', alpha=0.5)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/circles_1.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
scikit_pca = PCA(n_components=2)
|
||||
X_spca = scikit_pca.fit_transform(X)
|
||||
|
||||
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(7, 3))
|
||||
|
||||
ax[0].scatter(X_spca[y == 0, 0], X_spca[y == 0, 1],
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[0].scatter(X_spca[y == 1, 0], X_spca[y == 1, 1],
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[1].scatter(X_spca[y == 0, 0], np.zeros((500, 1)) + 0.02,
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[1].scatter(X_spca[y == 1, 0], np.zeros((500, 1)) - 0.02,
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[0].set_xlabel('PC1')
|
||||
ax[0].set_ylabel('PC2')
|
||||
ax[1].set_ylim([-1, 1])
|
||||
ax[1].set_yticks([])
|
||||
ax[1].set_xlabel('PC1')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/circles_2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
X_kpca = rbf_kernel_pca(X, gamma=15, n_components=2)
|
||||
|
||||
fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(7, 3))
|
||||
ax[0].scatter(X_kpca[y == 0, 0], X_kpca[y == 0, 1],
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[0].scatter(X_kpca[y == 1, 0], X_kpca[y == 1, 1],
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[1].scatter(X_kpca[y == 0, 0], np.zeros((500, 1)) + 0.02,
|
||||
color='red', marker='^', alpha=0.5)
|
||||
ax[1].scatter(X_kpca[y == 1, 0], np.zeros((500, 1)) - 0.02,
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
ax[0].set_xlabel('PC1')
|
||||
ax[0].set_ylabel('PC2')
|
||||
ax[1].set_ylim([-1, 1])
|
||||
ax[1].set_yticks([])
|
||||
ax[1].set_xlabel('PC1')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/circles_3.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Projecting new data points')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def rbf_kernel_pca(X, gamma, n_components):
|
||||
"""
|
||||
RBF kernel PCA implementation.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
X: {NumPy ndarray}, shape = [n_samples, n_features]
|
||||
|
||||
gamma: float
|
||||
Tuning parameter of the RBF kernel
|
||||
|
||||
n_components: int
|
||||
Number of principal components to return
|
||||
|
||||
Returns
|
||||
------------
|
||||
X_pc: {NumPy ndarray}, shape = [n_samples, k_features]
|
||||
Projected dataset
|
||||
|
||||
lambdas: list
|
||||
Eigenvalues
|
||||
|
||||
"""
|
||||
# Calculate pairwise squared Euclidean distances
|
||||
# in the MxN dimensional dataset.
|
||||
sq_dists = pdist(X, 'sqeuclidean')
|
||||
|
||||
# Convert pairwise distances into a square matrix.
|
||||
mat_sq_dists = squareform(sq_dists)
|
||||
|
||||
# Compute the symmetric kernel matrix.
|
||||
K = exp(-gamma * mat_sq_dists)
|
||||
|
||||
# Center the kernel matrix.
|
||||
N = K.shape[0]
|
||||
one_n = np.ones((N, N)) / N
|
||||
K = K - one_n.dot(K) - K.dot(one_n) + one_n.dot(K).dot(one_n)
|
||||
|
||||
# Obtaining eigenpairs from the centered kernel matrix
|
||||
# numpy.eigh returns them in sorted order
|
||||
eigvals, eigvecs = eigh(K)
|
||||
|
||||
# Collect the top k eigenvectors (projected samples)
|
||||
alphas = np.column_stack((eigvecs[:, -i]
|
||||
for i in range(1, n_components + 1)))
|
||||
|
||||
# Collect the corresponding eigenvalues
|
||||
lambdas = [eigvals[-i] for i in range(1, n_components + 1)]
|
||||
|
||||
return alphas, lambdas
|
||||
|
||||
|
||||
X, y = make_moons(n_samples=100, random_state=123)
|
||||
alphas, lambdas = rbf_kernel_pca(X, gamma=15, n_components=1)
|
||||
|
||||
|
||||
x_new = X[25]
|
||||
print('New data point x_new:', x_new)
|
||||
|
||||
x_proj = alphas[25] # original projection
|
||||
print('Original projection x_proj:', x_proj)
|
||||
|
||||
|
||||
def project_x(x_new, X, gamma, alphas, lambdas):
|
||||
pair_dist = np.array([np.sum((x_new - row)**2) for row in X])
|
||||
k = np.exp(-gamma * pair_dist)
|
||||
return k.dot(alphas / lambdas)
|
||||
|
||||
|
||||
# projection of the "new" datapoint
|
||||
x_reproj = project_x(x_new, X, gamma=15, alphas=alphas, lambdas=lambdas)
|
||||
print('Reprojection x_reproj:', x_reproj)
|
||||
|
||||
plt.scatter(alphas[y == 0, 0], np.zeros((50)),
|
||||
color='red', marker='^', alpha=0.5)
|
||||
plt.scatter(alphas[y == 1, 0], np.zeros((50)),
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
plt.scatter(x_proj, 0, color='black',
|
||||
label='original projection of point X[25]', marker='^', s=100)
|
||||
plt.scatter(x_reproj, 0, color='green',
|
||||
label='remapped point X[25]', marker='x', s=500)
|
||||
plt.legend(scatterpoints=1)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/reproject.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Kernel principal component analysis in scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
X, y = make_moons(n_samples=100, random_state=123)
|
||||
scikit_kpca = KernelPCA(n_components=2, kernel='rbf', gamma=15)
|
||||
X_skernpca = scikit_kpca.fit_transform(X)
|
||||
|
||||
plt.scatter(X_skernpca[y == 0, 0], X_skernpca[y == 0, 1],
|
||||
color='red', marker='^', alpha=0.5)
|
||||
plt.scatter(X_skernpca[y == 1, 0], X_skernpca[y == 1, 1],
|
||||
color='blue', marker='o', alpha=0.5)
|
||||
|
||||
plt.xlabel('PC1')
|
||||
plt.ylabel('PC2')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/scikit_kpca.png', dpi=300)
|
||||
plt.show()
|
||||
@@ -0,0 +1,443 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 6 - Learning Best Practices for Model Evaluation
|
||||
# and Hyperparameter Tuning
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import matplotlib.pyplot as plt
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.decomposition import PCA
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.pipeline import Pipeline
|
||||
from sklearn.tree import DecisionTreeClassifier
|
||||
from sklearn.svm import SVC
|
||||
from sklearn.metrics import confusion_matrix
|
||||
from sklearn.metrics import f1_score
|
||||
from sklearn.metrics import recall_score
|
||||
from sklearn.metrics import precision_score
|
||||
from sklearn.metrics import make_scorer
|
||||
from sklearn.metrics import roc_curve
|
||||
from sklearn.metrics import auc
|
||||
from sklearn.metrics import roc_auc_score
|
||||
from sklearn.metrics import accuracy_score
|
||||
from scipy import interp
|
||||
|
||||
# for sklearn 0.18's alternative syntax
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.grid_search import train_test_split
|
||||
from sklearn.cross_validation import StratifiedKFold
|
||||
from sklearn.cross_validation import cross_val_score
|
||||
from sklearn.learning_curve import learning_curve
|
||||
from sklearn.learning_curve import validation_curve
|
||||
from sklearn.grid_search import GridSearchCV
|
||||
else:
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.model_selection import StratifiedKFold
|
||||
from sklearn.model_selection import cross_val_score
|
||||
from sklearn.model_selection import learning_curve
|
||||
from sklearn.model_selection import validation_curve
|
||||
from sklearn.model_selection import GridSearchCV
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Loading the Breast Cancer Wisconsin dataset')
|
||||
print(50 * '-')
|
||||
|
||||
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases'
|
||||
'/breast-cancer-wisconsin/wdbc.data', header=None)
|
||||
print('Breast Cancer dataset excerpt:\n\n')
|
||||
print(df.head())
|
||||
|
||||
print('Breast Cancer dataset dimensions:\n\n')
|
||||
print(df.shape)
|
||||
|
||||
X = df.loc[:, 2:].values
|
||||
y = df.loc[:, 1].values
|
||||
le = LabelEncoder()
|
||||
y = le.fit_transform(y)
|
||||
y_enc = le.transform(['M', 'B'])
|
||||
print("Label encoding example, le.transform(['M', 'B'])")
|
||||
print(le.transform(['M', 'B']))
|
||||
|
||||
X_train, X_test, y_train, y_test = \
|
||||
train_test_split(X, y, test_size=0.20, random_state=1)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Combining transformers and estimators in a pipeline')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
pipe_lr = Pipeline([('scl', StandardScaler()),
|
||||
('pca', PCA(n_components=2)),
|
||||
('clf', LogisticRegression(random_state=1))])
|
||||
|
||||
pipe_lr.fit(X_train, y_train)
|
||||
print('Test Accuracy: %.3f' % pipe_lr.score(X_test, y_test))
|
||||
y_pred = pipe_lr.predict(X_test)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: K-fold cross-validation')
|
||||
print(50 * '-')
|
||||
|
||||
if Version(sklearn_version) < '0.18':
|
||||
kfold = StratifiedKFold(y=y_train,
|
||||
n_folds=10,
|
||||
random_state=1)
|
||||
else:
|
||||
kfold = StratifiedKFold(n_splits=10,
|
||||
random_state=1).split(X_train, y_train)
|
||||
|
||||
scores = []
|
||||
for k, (train, test) in enumerate(kfold):
|
||||
pipe_lr.fit(X_train[train], y_train[train])
|
||||
score = pipe_lr.score(X_train[test], y_train[test])
|
||||
scores.append(score)
|
||||
print('Fold: %s, Class dist.: %s, Acc: %.3f' % (k + 1,
|
||||
np.bincount(y_train[train]), score))
|
||||
|
||||
print('\nCV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
|
||||
|
||||
print('Using StratifiedKFold')
|
||||
if Version(sklearn_version) < '0.18':
|
||||
kfold = StratifiedKFold(y=y_train,
|
||||
n_folds=10,
|
||||
random_state=1)
|
||||
else:
|
||||
kfold = StratifiedKFold(n_splits=10,
|
||||
random_state=1).split(X_train, y_train)
|
||||
|
||||
scores = []
|
||||
for k, (train, test) in enumerate(kfold):
|
||||
pipe_lr.fit(X_train[train], y_train[train])
|
||||
score = pipe_lr.score(X_train[test], y_train[test])
|
||||
scores.append(score)
|
||||
print('Fold: %s, Class dist.: %s, Acc: %.3f' % (k + 1,
|
||||
np.bincount(y_train[train]), score))
|
||||
|
||||
print('\nCV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
|
||||
|
||||
|
||||
print('Using cross_val_score')
|
||||
scores = cross_val_score(estimator=pipe_lr,
|
||||
X=X_train,
|
||||
y=y_train,
|
||||
cv=10,
|
||||
n_jobs=1)
|
||||
|
||||
print('CV accuracy scores: %s' % scores)
|
||||
print('CV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Diagnosing bias and variance problems with learning curves')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
pipe_lr = Pipeline([('scl', StandardScaler()),
|
||||
('clf', LogisticRegression(penalty='l2', random_state=0))])
|
||||
|
||||
train_sizes, train_scores, test_scores =\
|
||||
learning_curve(estimator=pipe_lr,
|
||||
X=X_train,
|
||||
y=y_train,
|
||||
train_sizes=np.linspace(0.1, 1.0, 10),
|
||||
cv=10,
|
||||
n_jobs=1)
|
||||
|
||||
train_mean = np.mean(train_scores, axis=1)
|
||||
train_std = np.std(train_scores, axis=1)
|
||||
test_mean = np.mean(test_scores, axis=1)
|
||||
test_std = np.std(test_scores, axis=1)
|
||||
|
||||
plt.plot(train_sizes, train_mean,
|
||||
color='blue', marker='o',
|
||||
markersize=5, label='training accuracy')
|
||||
|
||||
plt.fill_between(train_sizes,
|
||||
train_mean + train_std,
|
||||
train_mean - train_std,
|
||||
alpha=0.15, color='blue')
|
||||
|
||||
plt.plot(train_sizes, test_mean,
|
||||
color='green', linestyle='--',
|
||||
marker='s', markersize=5,
|
||||
label='validation accuracy')
|
||||
|
||||
plt.fill_between(train_sizes,
|
||||
test_mean + test_std,
|
||||
test_mean - test_std,
|
||||
alpha=0.15, color='green')
|
||||
|
||||
plt.grid()
|
||||
plt.xlabel('Number of training samples')
|
||||
plt.ylabel('Accuracy')
|
||||
plt.legend(loc='lower right')
|
||||
plt.ylim([0.8, 1.0])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/learning_curve.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Addressing over- and underfitting with validation curves')
|
||||
print(50 * '-')
|
||||
|
||||
param_range = [0.001, 0.01, 0.1, 1.0, 10.0, 100.0]
|
||||
train_scores, test_scores = validation_curve(
|
||||
estimator=pipe_lr,
|
||||
X=X_train,
|
||||
y=y_train,
|
||||
param_name='clf__C',
|
||||
param_range=param_range,
|
||||
cv=10)
|
||||
|
||||
train_mean = np.mean(train_scores, axis=1)
|
||||
train_std = np.std(train_scores, axis=1)
|
||||
test_mean = np.mean(test_scores, axis=1)
|
||||
test_std = np.std(test_scores, axis=1)
|
||||
|
||||
plt.plot(param_range, train_mean,
|
||||
color='blue', marker='o',
|
||||
markersize=5, label='training accuracy')
|
||||
|
||||
plt.fill_between(param_range, train_mean + train_std,
|
||||
train_mean - train_std, alpha=0.15,
|
||||
color='blue')
|
||||
|
||||
plt.plot(param_range, test_mean,
|
||||
color='green', linestyle='--',
|
||||
marker='s', markersize=5,
|
||||
label='validation accuracy')
|
||||
|
||||
plt.fill_between(param_range,
|
||||
test_mean + test_std,
|
||||
test_mean - test_std,
|
||||
alpha=0.15, color='green')
|
||||
|
||||
plt.grid()
|
||||
plt.xscale('log')
|
||||
plt.legend(loc='lower right')
|
||||
plt.xlabel('Parameter C')
|
||||
plt.ylabel('Accuracy')
|
||||
plt.ylim([0.8, 1.0])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/validation_curve.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Tuning hyperparameters via grid search')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
pipe_svc = Pipeline([('scl', StandardScaler()),
|
||||
('clf', SVC(random_state=1))])
|
||||
|
||||
param_range = [0.0001, 0.001, 0.01, 0.1, 1.0, 10.0, 100.0, 1000.0]
|
||||
|
||||
param_grid = [{'clf__C': param_range,
|
||||
'clf__kernel': ['linear']},
|
||||
{'clf__C': param_range,
|
||||
'clf__gamma': param_range,
|
||||
'clf__kernel': ['rbf']}]
|
||||
|
||||
gs = GridSearchCV(estimator=pipe_svc,
|
||||
param_grid=param_grid,
|
||||
scoring='accuracy',
|
||||
cv=10,
|
||||
n_jobs=-1)
|
||||
gs = gs.fit(X_train, y_train)
|
||||
print('Validation accuracy', gs.best_score_)
|
||||
print('Best parameters', gs.best_params_)
|
||||
|
||||
clf = gs.best_estimator_
|
||||
clf.fit(X_train, y_train)
|
||||
print('Test accuracy: %.3f' % clf.score(X_test, y_test))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Algorithm selection with nested cross-validation')
|
||||
print(50 * '-')
|
||||
|
||||
gs = GridSearchCV(estimator=pipe_svc,
|
||||
param_grid=param_grid,
|
||||
scoring='accuracy',
|
||||
cv=2)
|
||||
|
||||
# Note: Optionally, you could use cv=2
|
||||
# in the GridSearchCV above to produce
|
||||
# the 5 x 2 nested CV that is shown in the figure.
|
||||
|
||||
scores = cross_val_score(gs, X_train, y_train, scoring='accuracy', cv=5)
|
||||
print('CV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
|
||||
|
||||
gs = GridSearchCV(estimator=DecisionTreeClassifier(random_state=0),
|
||||
param_grid=[{'max_depth': [1, 2, 3, 4, 5, 6, 7, None]}],
|
||||
scoring='accuracy',
|
||||
cv=2)
|
||||
scores = cross_val_score(gs, X_train, y_train, scoring='accuracy', cv=5)
|
||||
print('CV accuracy: %.3f +/- %.3f' % (np.mean(scores), np.std(scores)))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Reading a confusion matrix')
|
||||
print(50 * '-')
|
||||
|
||||
pipe_svc.fit(X_train, y_train)
|
||||
y_pred = pipe_svc.predict(X_test)
|
||||
confmat = confusion_matrix(y_true=y_test, y_pred=y_pred)
|
||||
print('Confusion matrix', confmat)
|
||||
|
||||
fig, ax = plt.subplots(figsize=(2.5, 2.5))
|
||||
ax.matshow(confmat, cmap=plt.cm.Blues, alpha=0.3)
|
||||
for i in range(confmat.shape[0]):
|
||||
for j in range(confmat.shape[1]):
|
||||
ax.text(x=j, y=i, s=confmat[i, j], va='center', ha='center')
|
||||
|
||||
plt.xlabel('predicted label')
|
||||
plt.ylabel('true label')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/confusion_matrix.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Optimizing the precision and recall of a classification model')
|
||||
print(50 * '-')
|
||||
|
||||
print('Precision: %.3f' % precision_score(y_true=y_test, y_pred=y_pred))
|
||||
print('Recall: %.3f' % recall_score(y_true=y_test, y_pred=y_pred))
|
||||
print('F1: %.3f' % f1_score(y_true=y_test, y_pred=y_pred))
|
||||
|
||||
scorer = make_scorer(f1_score, pos_label=0)
|
||||
|
||||
c_gamma_range = [0.01, 0.1, 1.0, 10.0]
|
||||
|
||||
param_grid = [{'clf__C': c_gamma_range,
|
||||
'clf__kernel': ['linear']},
|
||||
{'clf__C': c_gamma_range,
|
||||
'clf__gamma': c_gamma_range,
|
||||
'clf__kernel': ['rbf']}]
|
||||
|
||||
gs = GridSearchCV(estimator=pipe_svc,
|
||||
param_grid=param_grid,
|
||||
scoring=scorer,
|
||||
cv=10,
|
||||
n_jobs=-1)
|
||||
gs = gs.fit(X_train, y_train)
|
||||
print(gs.best_score_)
|
||||
print(gs.best_params_)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Plotting a receiver operating characteristic')
|
||||
print(50 * '-')
|
||||
|
||||
pipe_lr = Pipeline([('scl', StandardScaler()),
|
||||
('pca', PCA(n_components=2)),
|
||||
('clf', LogisticRegression(penalty='l2',
|
||||
random_state=0,
|
||||
C=100.0))])
|
||||
|
||||
X_train2 = X_train[:, [4, 14]]
|
||||
|
||||
if Version(sklearn_version) < '0.18':
|
||||
cv = StratifiedKFold(y_train,
|
||||
n_folds=3,
|
||||
random_state=1)
|
||||
|
||||
else:
|
||||
cv = list(StratifiedKFold(n_splits=3,
|
||||
random_state=1).split(X_train, y_train))
|
||||
|
||||
fig = plt.figure(figsize=(7, 5))
|
||||
|
||||
mean_tpr = 0.0
|
||||
mean_fpr = np.linspace(0, 1, 100)
|
||||
all_tpr = []
|
||||
|
||||
for i, (train, test) in enumerate(cv):
|
||||
probas = pipe_lr.fit(X_train2[train],
|
||||
y_train[train]).predict_proba(X_train2[test])
|
||||
|
||||
fpr, tpr, thresholds = roc_curve(y_train[test],
|
||||
probas[:, 1],
|
||||
pos_label=1)
|
||||
mean_tpr += interp(mean_fpr, fpr, tpr)
|
||||
mean_tpr[0] = 0.0
|
||||
roc_auc = auc(fpr, tpr)
|
||||
plt.plot(fpr,
|
||||
tpr,
|
||||
lw=1,
|
||||
label='ROC fold %d (area = %0.2f)'
|
||||
% (i + 1, roc_auc))
|
||||
|
||||
plt.plot([0, 1],
|
||||
[0, 1],
|
||||
linestyle='--',
|
||||
color=(0.6, 0.6, 0.6),
|
||||
label='random guessing')
|
||||
|
||||
mean_tpr /= len(cv)
|
||||
mean_tpr[-1] = 1.0
|
||||
mean_auc = auc(mean_fpr, mean_tpr)
|
||||
plt.plot(mean_fpr, mean_tpr, 'k--',
|
||||
label='mean ROC (area = %0.2f)' % mean_auc, lw=2)
|
||||
plt.plot([0, 0, 1],
|
||||
[0, 1, 1],
|
||||
lw=2,
|
||||
linestyle=':',
|
||||
color='black',
|
||||
label='perfect performance')
|
||||
|
||||
plt.xlim([-0.05, 1.05])
|
||||
plt.ylim([-0.05, 1.05])
|
||||
plt.xlabel('false positive rate')
|
||||
plt.ylabel('true positive rate')
|
||||
plt.title('Receiver Operator Characteristic')
|
||||
plt.legend(loc="lower right")
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/roc.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
pipe_lr = pipe_lr.fit(X_train2, y_train)
|
||||
y_pred2 = pipe_lr.predict(X_test[:, [4, 14]])
|
||||
|
||||
print('ROC AUC: %.3f' % roc_auc_score(y_true=y_test, y_score=y_pred2))
|
||||
print('Accuracy: %.3f' % accuracy_score(y_true=y_test, y_pred=y_pred2))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: The scoring metrics for multiclass classification')
|
||||
print(50 * '-')
|
||||
|
||||
pre_scorer = make_scorer(score_func=precision_score,
|
||||
pos_label=1,
|
||||
greater_is_better=True,
|
||||
average='micro')
|
||||
@@ -0,0 +1,595 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 7 - Combining Different Models for Ensemble Learning
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
import math
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
import operator
|
||||
from scipy.misc import comb
|
||||
import matplotlib.pyplot as plt
|
||||
from sklearn.base import BaseEstimator
|
||||
from sklearn.base import ClassifierMixin
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
from sklearn.externals import six
|
||||
from sklearn.base import clone
|
||||
from sklearn.pipeline import _name_estimators
|
||||
from sklearn import datasets
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.preprocessing import LabelEncoder
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.tree import DecisionTreeClassifier
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
from sklearn.pipeline import Pipeline
|
||||
from sklearn.metrics import roc_curve
|
||||
from sklearn.metrics import auc
|
||||
from sklearn.metrics import accuracy_score
|
||||
from sklearn.ensemble import BaggingClassifier
|
||||
from sklearn.ensemble import AdaBoostClassifier
|
||||
from itertools import product
|
||||
|
||||
# Added version check for recent scikit-learn 0.18 checks
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.cross_validation import train_test_split
|
||||
from sklearn.cross_validation import cross_val_score
|
||||
from sklearn.cross_validation import GridSearchCV
|
||||
else:
|
||||
from sklearn.model_selection import train_test_split
|
||||
from sklearn.model_selection import cross_val_score
|
||||
from sklearn.model_selection import GridSearchCV
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Learning with ensembles')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def ensemble_error(n_classifier, error):
|
||||
k_start = math.ceil(n_classifier / 2.0)
|
||||
probs = [comb(n_classifier, k) * error**k * (1 - error)**(n_classifier - k)
|
||||
for k in range(k_start, n_classifier + 1)]
|
||||
return sum(probs)
|
||||
|
||||
print('Ensemble error', ensemble_error(n_classifier=11, error=0.25))
|
||||
|
||||
error_range = np.arange(0.0, 1.01, 0.01)
|
||||
ens_errors = [ensemble_error(n_classifier=11, error=error)
|
||||
for error in error_range]
|
||||
|
||||
plt.plot(error_range,
|
||||
ens_errors,
|
||||
label='Ensemble error',
|
||||
linewidth=2)
|
||||
|
||||
plt.plot(error_range,
|
||||
error_range,
|
||||
linestyle='--',
|
||||
label='Base error',
|
||||
linewidth=2)
|
||||
|
||||
plt.xlabel('Base error')
|
||||
plt.ylabel('Base/Ensemble error')
|
||||
plt.legend(loc='upper left')
|
||||
plt.grid()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/ensemble_err.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Implementing a simple majority vote classifier')
|
||||
print(50 * '-')
|
||||
|
||||
np.argmax(np.bincount([0, 0, 1],
|
||||
weights=[0.2, 0.2, 0.6]))
|
||||
|
||||
ex = np.array([[0.9, 0.1],
|
||||
[0.8, 0.2],
|
||||
[0.4, 0.6]])
|
||||
|
||||
p = np.average(ex,
|
||||
axis=0,
|
||||
weights=[0.2, 0.2, 0.6])
|
||||
print('Averaged prediction', p)
|
||||
print('np.argmax(p): ', np.argmax(p))
|
||||
|
||||
|
||||
class MajorityVoteClassifier(BaseEstimator,
|
||||
ClassifierMixin):
|
||||
""" A majority vote ensemble classifier
|
||||
|
||||
Parameters
|
||||
----------
|
||||
classifiers : array-like, shape = [n_classifiers]
|
||||
Different classifiers for the ensemble
|
||||
|
||||
vote : str, {'classlabel', 'probability'} (default='label')
|
||||
If 'classlabel' the prediction is based on the argmax of
|
||||
class labels. Else if 'probability', the argmax of
|
||||
the sum of probabilities is used to predict the class label
|
||||
(recommended for calibrated classifiers).
|
||||
|
||||
weights : array-like, shape = [n_classifiers], optional (default=None)
|
||||
If a list of `int` or `float` values are provided, the classifiers
|
||||
are weighted by importance; Uses uniform weights if `weights=None`.
|
||||
|
||||
"""
|
||||
def __init__(self, classifiers, vote='classlabel', weights=None):
|
||||
|
||||
self.classifiers = classifiers
|
||||
self.named_classifiers = {key: value for key, value
|
||||
in _name_estimators(classifiers)}
|
||||
self.vote = vote
|
||||
self.weights = weights
|
||||
|
||||
def fit(self, X, y):
|
||||
""" Fit classifiers.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : {array-like, sparse matrix}, shape = [n_samples, n_features]
|
||||
Matrix of training samples.
|
||||
|
||||
y : array-like, shape = [n_samples]
|
||||
Vector of target class labels.
|
||||
|
||||
Returns
|
||||
-------
|
||||
self : object
|
||||
|
||||
"""
|
||||
if self.vote not in ('probability', 'classlabel'):
|
||||
raise ValueError("vote must be 'probability' or 'classlabel'"
|
||||
"; got (vote=%r)"
|
||||
% self.vote)
|
||||
|
||||
if self.weights and len(self.weights) != len(self.classifiers):
|
||||
raise ValueError('Number of classifiers and weights must be equal'
|
||||
'; got %d weights, %d classifiers'
|
||||
% (len(self.weights), len(self.classifiers)))
|
||||
|
||||
# Use LabelEncoder to ensure class labels start with 0, which
|
||||
# is important for np.argmax call in self.predict
|
||||
self.lablenc_ = LabelEncoder()
|
||||
self.lablenc_.fit(y)
|
||||
self.classes_ = self.lablenc_.classes_
|
||||
self.classifiers_ = []
|
||||
for clf in self.classifiers:
|
||||
fitted_clf = clone(clf).fit(X, self.lablenc_.transform(y))
|
||||
self.classifiers_.append(fitted_clf)
|
||||
return self
|
||||
|
||||
def predict(self, X):
|
||||
""" Predict class labels for X.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : {array-like, sparse matrix}, shape = [n_samples, n_features]
|
||||
Matrix of training samples.
|
||||
|
||||
Returns
|
||||
----------
|
||||
maj_vote : array-like, shape = [n_samples]
|
||||
Predicted class labels.
|
||||
|
||||
"""
|
||||
if self.vote == 'probability':
|
||||
maj_vote = np.argmax(self.predict_proba(X), axis=1)
|
||||
else: # 'classlabel' vote
|
||||
|
||||
# Collect results from clf.predict calls
|
||||
predictions = np.asarray([clf.predict(X)
|
||||
for clf in self.classifiers_]).T
|
||||
|
||||
maj_vote = np.apply_along_axis(
|
||||
lambda x:
|
||||
np.argmax(np.bincount(x,
|
||||
weights=self.weights)),
|
||||
axis=1,
|
||||
arr=predictions)
|
||||
maj_vote = self.lablenc_.inverse_transform(maj_vote)
|
||||
return maj_vote
|
||||
|
||||
def predict_proba(self, X):
|
||||
""" Predict class probabilities for X.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
X : {array-like, sparse matrix}, shape = [n_samples, n_features]
|
||||
Training vectors, where n_samples is the number of samples and
|
||||
n_features is the number of features.
|
||||
|
||||
Returns
|
||||
----------
|
||||
avg_proba : array-like, shape = [n_samples, n_classes]
|
||||
Weighted average probability for each class per sample.
|
||||
|
||||
"""
|
||||
probas = np.asarray([clf.predict_proba(X)
|
||||
for clf in self.classifiers_])
|
||||
avg_proba = np.average(probas, axis=0, weights=self.weights)
|
||||
return avg_proba
|
||||
|
||||
def get_params(self, deep=True):
|
||||
""" Get classifier parameter names for GridSearch"""
|
||||
if not deep:
|
||||
return super(MajorityVoteClassifier, self).get_params(deep=False)
|
||||
else:
|
||||
out = self.named_classifiers.copy()
|
||||
for name, step in six.iteritems(self.named_classifiers):
|
||||
for key, value in six.iteritems(step.get_params(deep=True)):
|
||||
out['%s__%s' % (name, key)] = value
|
||||
return out
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Combining different algorithms for'
|
||||
' classification with majority vote')
|
||||
print(50 * '-')
|
||||
|
||||
iris = datasets.load_iris()
|
||||
X, y = iris.data[50:, [1, 2]], iris.target[50:]
|
||||
le = LabelEncoder()
|
||||
y = le.fit_transform(y)
|
||||
|
||||
X_train, X_test, y_train, y_test =\
|
||||
train_test_split(X, y,
|
||||
test_size=0.5,
|
||||
random_state=1)
|
||||
|
||||
clf1 = LogisticRegression(penalty='l2',
|
||||
C=0.001,
|
||||
random_state=0)
|
||||
|
||||
clf2 = DecisionTreeClassifier(max_depth=1,
|
||||
criterion='entropy',
|
||||
random_state=0)
|
||||
|
||||
clf3 = KNeighborsClassifier(n_neighbors=1,
|
||||
p=2,
|
||||
metric='minkowski')
|
||||
|
||||
pipe1 = Pipeline([['sc', StandardScaler()],
|
||||
['clf', clf1]])
|
||||
pipe3 = Pipeline([['sc', StandardScaler()],
|
||||
['clf', clf3]])
|
||||
|
||||
clf_labels = ['Logistic Regression', 'Decision Tree', 'KNN']
|
||||
|
||||
print('10-fold cross validation:\n')
|
||||
for clf, label in zip([pipe1, clf2, pipe3], clf_labels):
|
||||
scores = cross_val_score(estimator=clf,
|
||||
X=X_train,
|
||||
y=y_train,
|
||||
cv=10,
|
||||
scoring='roc_auc')
|
||||
print("ROC AUC: %0.2f (+/- %0.2f) [%s]"
|
||||
% (scores.mean(), scores.std(), label))
|
||||
|
||||
|
||||
mv_clf = MajorityVoteClassifier(classifiers=[pipe1, clf2, pipe3])
|
||||
|
||||
clf_labels += ['Majority Voting']
|
||||
all_clf = [pipe1, clf2, pipe3, mv_clf]
|
||||
|
||||
for clf, label in zip(all_clf, clf_labels):
|
||||
scores = cross_val_score(estimator=clf,
|
||||
X=X_train,
|
||||
y=y_train,
|
||||
cv=10,
|
||||
scoring='roc_auc')
|
||||
print("ROC AUC: %0.2f (+/- %0.2f) [%s]"
|
||||
% (scores.mean(), scores.std(), label))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Evaluating and tuning the ensemble classifier')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
colors = ['black', 'orange', 'blue', 'green']
|
||||
linestyles = [':', '--', '-.', '-']
|
||||
for clf, label, clr, ls \
|
||||
in zip(all_clf,
|
||||
clf_labels, colors, linestyles):
|
||||
|
||||
# assuming the label of the positive class is 1
|
||||
y_pred = clf.fit(X_train,
|
||||
y_train).predict_proba(X_test)[:, 1]
|
||||
fpr, tpr, thresholds = roc_curve(y_true=y_test,
|
||||
y_score=y_pred)
|
||||
roc_auc = auc(x=fpr, y=tpr)
|
||||
plt.plot(fpr, tpr,
|
||||
color=clr,
|
||||
linestyle=ls,
|
||||
label='%s (auc = %0.2f)' % (label, roc_auc))
|
||||
|
||||
plt.legend(loc='lower right')
|
||||
plt.plot([0, 1], [0, 1],
|
||||
linestyle='--',
|
||||
color='gray',
|
||||
linewidth=2)
|
||||
|
||||
plt.xlim([-0.1, 1.1])
|
||||
plt.ylim([-0.1, 1.1])
|
||||
plt.grid()
|
||||
plt.xlabel('False Positive Rate')
|
||||
plt.ylabel('True Positive Rate')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/roc.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
sc = StandardScaler()
|
||||
X_train_std = sc.fit_transform(X_train)
|
||||
|
||||
|
||||
all_clf = [pipe1, clf2, pipe3, mv_clf]
|
||||
|
||||
x_min = X_train_std[:, 0].min() - 1
|
||||
x_max = X_train_std[:, 0].max() + 1
|
||||
y_min = X_train_std[:, 1].min() - 1
|
||||
y_max = X_train_std[:, 1].max() + 1
|
||||
|
||||
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
|
||||
np.arange(y_min, y_max, 0.1))
|
||||
|
||||
f, axarr = plt.subplots(nrows=2, ncols=2,
|
||||
sharex='col',
|
||||
sharey='row',
|
||||
figsize=(7, 5))
|
||||
|
||||
for idx, clf, tt in zip(product([0, 1], [0, 1]),
|
||||
all_clf, clf_labels):
|
||||
clf.fit(X_train_std, y_train)
|
||||
|
||||
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
|
||||
Z = Z.reshape(xx.shape)
|
||||
|
||||
axarr[idx[0], idx[1]].contourf(xx, yy, Z, alpha=0.3)
|
||||
|
||||
axarr[idx[0], idx[1]].scatter(X_train_std[y_train == 0, 0],
|
||||
X_train_std[y_train == 0, 1],
|
||||
c='blue',
|
||||
marker='^',
|
||||
s=50)
|
||||
|
||||
axarr[idx[0], idx[1]].scatter(X_train_std[y_train == 1, 0],
|
||||
X_train_std[y_train == 1, 1],
|
||||
c='red',
|
||||
marker='o',
|
||||
s=50)
|
||||
|
||||
axarr[idx[0], idx[1]].set_title(tt)
|
||||
|
||||
plt.text(-3.5, -4.5,
|
||||
s='Sepal width [standardized]',
|
||||
ha='center', va='center', fontsize=12)
|
||||
plt.text(-10.5, 4.5,
|
||||
s='Petal length [standardized]',
|
||||
ha='center', va='center',
|
||||
fontsize=12, rotation=90)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/voting_panel', bbox_inches='tight', dpi=300)
|
||||
plt.show()
|
||||
|
||||
print(mv_clf.get_params())
|
||||
|
||||
params = {'decisiontreeclassifier__max_depth': [1, 2],
|
||||
'pipeline-1__clf__C': [0.001, 0.1, 100.0]}
|
||||
|
||||
grid = GridSearchCV(estimator=mv_clf,
|
||||
param_grid=params,
|
||||
cv=10,
|
||||
scoring='roc_auc')
|
||||
grid.fit(X_train, y_train)
|
||||
|
||||
if Version(sklearn_version) < '0.18':
|
||||
for params, mean_score, scores in grid.grid_scores_:
|
||||
print("%0.3f +/- %0.2f %r"
|
||||
% (mean_score, scores.std() / 2.0, params))
|
||||
|
||||
else:
|
||||
cv_keys = ('mean_test_score', 'std_test_score', 'params')
|
||||
|
||||
for r, _ in enumerate(grid.cv_results_['mean_test_score']):
|
||||
print("%0.3f +/- %0.2f %r"
|
||||
% (grid.cv_results_[cv_keys[0]][r],
|
||||
grid.cv_results_[cv_keys[1]][r] / 2.0,
|
||||
grid.cv_results_[cv_keys[2]][r]))
|
||||
|
||||
print('Best parameters: %s' % grid.best_params_)
|
||||
print('Accuracy: %.2f' % grid.best_score_)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Bagging -- Building an ensemble of'
|
||||
'classifiers from bootstrap samples')
|
||||
print(50 * '-')
|
||||
|
||||
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/'
|
||||
'machine-learning-databases/wine/wine.data',
|
||||
header=None)
|
||||
|
||||
df_wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash',
|
||||
'Alcalinity of ash', 'Magnesium', 'Total phenols',
|
||||
'Flavanoids', 'Nonflavanoid phenols', 'Proanthocyanins',
|
||||
'Color intensity', 'Hue', 'OD280/OD315 of diluted wines',
|
||||
'Proline']
|
||||
|
||||
# drop 1 class
|
||||
df_wine = df_wine[df_wine['Class label'] != 1]
|
||||
|
||||
y = df_wine['Class label'].values
|
||||
X = df_wine[['Alcohol', 'Hue']].values
|
||||
|
||||
|
||||
le = LabelEncoder()
|
||||
y = le.fit_transform(y)
|
||||
|
||||
X_train, X_test, y_train, y_test =\
|
||||
train_test_split(X, y,
|
||||
test_size=0.40,
|
||||
random_state=1)
|
||||
|
||||
tree = DecisionTreeClassifier(criterion='entropy',
|
||||
max_depth=None,
|
||||
random_state=1)
|
||||
|
||||
bag = BaggingClassifier(base_estimator=tree,
|
||||
n_estimators=500,
|
||||
max_samples=1.0,
|
||||
max_features=1.0,
|
||||
bootstrap=True,
|
||||
bootstrap_features=False,
|
||||
n_jobs=1,
|
||||
random_state=1)
|
||||
|
||||
tree = tree.fit(X_train, y_train)
|
||||
y_train_pred = tree.predict(X_train)
|
||||
y_test_pred = tree.predict(X_test)
|
||||
|
||||
tree_train = accuracy_score(y_train, y_train_pred)
|
||||
tree_test = accuracy_score(y_test, y_test_pred)
|
||||
print('Decision tree train/test accuracies %.3f/%.3f'
|
||||
% (tree_train, tree_test))
|
||||
|
||||
bag = bag.fit(X_train, y_train)
|
||||
y_train_pred = bag.predict(X_train)
|
||||
y_test_pred = bag.predict(X_test)
|
||||
|
||||
bag_train = accuracy_score(y_train, y_train_pred)
|
||||
bag_test = accuracy_score(y_test, y_test_pred)
|
||||
print('Bagging train/test accuracies %.3f/%.3f'
|
||||
% (bag_train, bag_test))
|
||||
|
||||
|
||||
x_min = X_train[:, 0].min() - 1
|
||||
x_max = X_train[:, 0].max() + 1
|
||||
y_min = X_train[:, 1].min() - 1
|
||||
y_max = X_train[:, 1].max() + 1
|
||||
|
||||
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
|
||||
np.arange(y_min, y_max, 0.1))
|
||||
|
||||
f, axarr = plt.subplots(nrows=1, ncols=2,
|
||||
sharex='col',
|
||||
sharey='row',
|
||||
figsize=(8, 3))
|
||||
|
||||
|
||||
for idx, clf, tt in zip([0, 1],
|
||||
[tree, bag],
|
||||
['Decision Tree', 'Bagging']):
|
||||
clf.fit(X_train, y_train)
|
||||
|
||||
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
|
||||
Z = Z.reshape(xx.shape)
|
||||
|
||||
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
|
||||
axarr[idx].scatter(X_train[y_train == 0, 0],
|
||||
X_train[y_train == 0, 1],
|
||||
c='blue', marker='^')
|
||||
|
||||
axarr[idx].scatter(X_train[y_train == 1, 0],
|
||||
X_train[y_train == 1, 1],
|
||||
c='red', marker='o')
|
||||
|
||||
axarr[idx].set_title(tt)
|
||||
|
||||
axarr[0].set_ylabel('Alcohol', fontsize=12)
|
||||
plt.text(10.2, -1.2,
|
||||
s='Hue',
|
||||
ha='center', va='center', fontsize=12)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/bagging_region.png',
|
||||
# dpi=300,
|
||||
# bbox_inches='tight')
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Leveraging weak learners via adaptive boosting')
|
||||
print(50 * '-')
|
||||
|
||||
tree = DecisionTreeClassifier(criterion='entropy',
|
||||
max_depth=1,
|
||||
random_state=0)
|
||||
|
||||
ada = AdaBoostClassifier(base_estimator=tree,
|
||||
n_estimators=500,
|
||||
learning_rate=0.1,
|
||||
random_state=0)
|
||||
|
||||
tree = tree.fit(X_train, y_train)
|
||||
y_train_pred = tree.predict(X_train)
|
||||
y_test_pred = tree.predict(X_test)
|
||||
|
||||
tree_train = accuracy_score(y_train, y_train_pred)
|
||||
tree_test = accuracy_score(y_test, y_test_pred)
|
||||
print('Decision tree train/test accuracies %.3f/%.3f'
|
||||
% (tree_train, tree_test))
|
||||
|
||||
ada = ada.fit(X_train, y_train)
|
||||
y_train_pred = ada.predict(X_train)
|
||||
y_test_pred = ada.predict(X_test)
|
||||
|
||||
ada_train = accuracy_score(y_train, y_train_pred)
|
||||
ada_test = accuracy_score(y_test, y_test_pred)
|
||||
print('AdaBoost train/test accuracies %.3f/%.3f'
|
||||
% (ada_train, ada_test))
|
||||
|
||||
|
||||
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
|
||||
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
|
||||
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
|
||||
np.arange(y_min, y_max, 0.1))
|
||||
|
||||
f, axarr = plt.subplots(1, 2, sharex='col', sharey='row', figsize=(8, 3))
|
||||
|
||||
|
||||
for idx, clf, tt in zip([0, 1],
|
||||
[tree, ada],
|
||||
['Decision Tree', 'AdaBoost']):
|
||||
clf.fit(X_train, y_train)
|
||||
|
||||
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
|
||||
Z = Z.reshape(xx.shape)
|
||||
|
||||
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
|
||||
axarr[idx].scatter(X_train[y_train == 0, 0],
|
||||
X_train[y_train == 0, 1],
|
||||
c='blue', marker='^')
|
||||
axarr[idx].scatter(X_train[y_train == 1, 0],
|
||||
X_train[y_train == 1, 1],
|
||||
c='red', marker='o')
|
||||
axarr[idx].set_title(tt)
|
||||
|
||||
axarr[0].set_ylabel('Alcohol', fontsize=12)
|
||||
plt.text(10.2, -1.2,
|
||||
s='Hue',
|
||||
ha='center', va='center', fontsize=12)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/adaboost_region.png',
|
||||
# dpi=300,
|
||||
# bbox_inches='tight')
|
||||
plt.show()
|
||||
@@ -0,0 +1,290 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 8 - Applying Machine Learning To Sentiment Analysis
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
import pyprind
|
||||
import pandas as pd
|
||||
import os
|
||||
import numpy as np
|
||||
import re
|
||||
import nltk
|
||||
from sklearn.feature_extraction.text import CountVectorizer
|
||||
from sklearn.feature_extraction.text import TfidfTransformer
|
||||
from sklearn.pipeline import Pipeline
|
||||
from sklearn.linear_model import LogisticRegression
|
||||
from sklearn.feature_extraction.text import TfidfVectorizer
|
||||
from sklearn.feature_extraction.text import HashingVectorizer
|
||||
from sklearn.linear_model import SGDClassifier
|
||||
from nltk.stem.porter import PorterStemmer
|
||||
from nltk.corpus import stopwords
|
||||
|
||||
# Added version check for recent scikit-learn 0.18 checks
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.cross_validation import GridSearchCV
|
||||
else:
|
||||
from sklearn.model_selection import GridSearchCV
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Obtaining the IMDb movie review dataset')
|
||||
print(50 * '-')
|
||||
|
||||
print('!! This script assumes that the movie dataset is located in the'
|
||||
' current directory under ./aclImdb')
|
||||
|
||||
_ = input('Please hit enter to continue.')
|
||||
|
||||
basepath = './aclImdb'
|
||||
|
||||
"""
|
||||
labels = {'pos': 1, 'neg': 0}
|
||||
pbar = pyprind.ProgBar(50000)
|
||||
df = pd.DataFrame()
|
||||
for s in ('test', 'train'):
|
||||
for l in ('pos', 'neg'):
|
||||
path = os.path.join(basepath, s, l)
|
||||
for file in os.listdir(path):
|
||||
with open(os.path.join(path, file), 'r',
|
||||
encoding='utf-8') as infile:
|
||||
txt = infile.read()
|
||||
df = df.append([[txt, labels[l]]], ignore_index=True)
|
||||
pbar.update()
|
||||
df.columns = ['review', 'sentiment']
|
||||
|
||||
|
||||
np.random.seed(0)
|
||||
df = df.reindex(np.random.permutation(df.index))
|
||||
|
||||
df.to_csv('./movie_data.csv', index=False)
|
||||
"""
|
||||
|
||||
df = pd.read_csv('../datasets/movie/movie_data.csv')
|
||||
print('Excerpt of the movie dataset', df.head(3))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Transforming documents into feature vectors')
|
||||
print(50 * '-')
|
||||
|
||||
count = CountVectorizer()
|
||||
docs = np.array(['The sun is shining',
|
||||
'The weather is sweet',
|
||||
'The sun is shining and the weather is sweet'])
|
||||
bag = count.fit_transform(docs)
|
||||
|
||||
print('Vocabulary', count.vocabulary_)
|
||||
print('bag.toarray()', bag.toarray())
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Assessing word relevancy via term frequency-inverse'
|
||||
' document frequency')
|
||||
print(50 * '-')
|
||||
|
||||
np.set_printoptions(precision=2)
|
||||
tfidf = TfidfTransformer(use_idf=True, norm='l2', smooth_idf=True)
|
||||
print(tfidf.fit_transform(count.fit_transform(docs)).toarray())
|
||||
|
||||
tf_is = 2
|
||||
n_docs = 3
|
||||
idf_is = np.log((n_docs + 1) / (3 + 1))
|
||||
tfidf_is = tf_is * (idf_is + 1)
|
||||
print('tf-idf of term "is" = %.2f' % tfidf_is)
|
||||
|
||||
|
||||
tfidf = TfidfTransformer(use_idf=True, norm=None, smooth_idf=True)
|
||||
raw_tfidf = tfidf.fit_transform(count.fit_transform(docs)).toarray()[-1]
|
||||
print('raw tf-idf', raw_tfidf)
|
||||
|
||||
l2_tfidf = raw_tfidf / np.sqrt(np.sum(raw_tfidf**2))
|
||||
l2_tfidf
|
||||
print('l2 tf-idf', l2_tfidf)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Cleaning text data')
|
||||
print(50 * '-')
|
||||
|
||||
print('Excerpt:\n\n', df.loc[0, 'review'][-50:])
|
||||
|
||||
|
||||
def preprocessor(text):
|
||||
text = re.sub('<[^>]*>', '', text)
|
||||
emoticons = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text)
|
||||
text = re.sub('[\W]+', ' ', text.lower()) +\
|
||||
' '.join(emoticons).replace('-', '')
|
||||
return text
|
||||
|
||||
|
||||
print('Preprocessor on Excerpt:\n\n', preprocessor(df.loc[0, 'review'][-50:]))
|
||||
|
||||
res = preprocessor("</a>This :) is :( a test :-)!")
|
||||
print('Preprocessor on "</a>This :) is :( a test :-)!":\n\n', res)
|
||||
|
||||
df['review'] = df['review'].apply(preprocessor)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Processing documents into tokens')
|
||||
print(50 * '-')
|
||||
|
||||
porter = PorterStemmer()
|
||||
|
||||
|
||||
def tokenizer(text):
|
||||
return text.split()
|
||||
|
||||
|
||||
def tokenizer_porter(text):
|
||||
return [porter.stem(word) for word in text.split()]
|
||||
|
||||
|
||||
t1 = tokenizer('runners like running and thus they run')
|
||||
print("Tokenize: 'runners like running and thus they run'")
|
||||
print(t1)
|
||||
|
||||
t2 = tokenizer_porter('runners like running and thus they run')
|
||||
print("\nPorter-Tokenize: 'runners like running and thus they run'")
|
||||
print(t2)
|
||||
|
||||
nltk.download('stopwords')
|
||||
|
||||
|
||||
print('remove stop words')
|
||||
stop = stopwords.words('english')
|
||||
|
||||
r = [w for w in tokenizer_porter('a runner likes running and runs a lot')[-10:]
|
||||
if w not in stop]
|
||||
|
||||
print(r)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Training a logistic regression model'
|
||||
' for document classification')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
X_train = df.loc[:25000, 'review'].values
|
||||
y_train = df.loc[:25000, 'sentiment'].values
|
||||
X_test = df.loc[25000:, 'review'].values
|
||||
y_test = df.loc[25000:, 'sentiment'].values
|
||||
|
||||
|
||||
tfidf = TfidfVectorizer(strip_accents=None,
|
||||
lowercase=False,
|
||||
preprocessor=None)
|
||||
|
||||
param_grid = [{'vect__ngram_range': [(1, 1)],
|
||||
'vect__stop_words': [stop, None],
|
||||
'vect__tokenizer': [tokenizer, tokenizer_porter],
|
||||
'clf__penalty': ['l1', 'l2'],
|
||||
'clf__C': [1.0, 10.0, 100.0]},
|
||||
{'vect__ngram_range': [(1, 1)],
|
||||
'vect__stop_words': [stop, None],
|
||||
'vect__tokenizer': [tokenizer, tokenizer_porter],
|
||||
'vect__use_idf':[False],
|
||||
'vect__norm':[None],
|
||||
'clf__penalty': ['l1', 'l2'],
|
||||
'clf__C': [1.0, 10.0, 100.0]},
|
||||
]
|
||||
|
||||
lr_tfidf = Pipeline([('vect', tfidf),
|
||||
('clf', LogisticRegression(random_state=0))])
|
||||
|
||||
gs_lr_tfidf = GridSearchCV(lr_tfidf, param_grid,
|
||||
scoring='accuracy',
|
||||
cv=5,
|
||||
verbose=1,
|
||||
n_jobs=-1)
|
||||
|
||||
gs_lr_tfidf.fit(X_train, y_train)
|
||||
|
||||
print('Best parameter set: %s ' % gs_lr_tfidf.best_params_)
|
||||
print('CV Accuracy: %.3f' % gs_lr_tfidf.best_score_)
|
||||
|
||||
|
||||
clf = gs_lr_tfidf.best_estimator_
|
||||
print('Test Accuracy: %.3f' % clf.score(X_test, y_test))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Working with bigger data - online'
|
||||
' algorithms and out-of-core learning')
|
||||
print(50 * '-')
|
||||
|
||||
stop = stopwords.words('english')
|
||||
|
||||
|
||||
def tokenizer(text):
|
||||
text = re.sub('<[^>]*>', '', text)
|
||||
emoticons = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text.lower())
|
||||
text = re.sub('[\W]+', ' ', text.lower()) +\
|
||||
' '.join(emoticons).replace('-', '')
|
||||
tokenized = [w for w in text.split() if w not in stop]
|
||||
return tokenized
|
||||
|
||||
|
||||
def stream_docs(path):
|
||||
with open(path, 'r', encoding='utf-8') as csv:
|
||||
next(csv) # skip header
|
||||
for line in csv:
|
||||
text, label = line[:-3], int(line[-2])
|
||||
yield text, label
|
||||
|
||||
|
||||
next(stream_docs(path='./movie_data.csv'))
|
||||
|
||||
|
||||
def get_minibatch(doc_stream, size):
|
||||
docs, y = [], []
|
||||
try:
|
||||
for _ in range(size):
|
||||
text, label = next(doc_stream)
|
||||
docs.append(text)
|
||||
y.append(label)
|
||||
except StopIteration:
|
||||
return None, None
|
||||
return docs, y
|
||||
|
||||
|
||||
vect = HashingVectorizer(decode_error='ignore',
|
||||
n_features=2**21,
|
||||
preprocessor=None,
|
||||
tokenizer=tokenizer)
|
||||
|
||||
clf = SGDClassifier(loss='log', random_state=1, n_iter=1)
|
||||
doc_stream = stream_docs(path='./movie_data.csv')
|
||||
|
||||
pbar = pyprind.ProgBar(45)
|
||||
|
||||
classes = np.array([0, 1])
|
||||
for _ in range(45):
|
||||
X_train, y_train = get_minibatch(doc_stream, size=1000)
|
||||
if not X_train:
|
||||
break
|
||||
X_train = vect.transform(X_train)
|
||||
clf.partial_fit(X_train, y_train, classes=classes)
|
||||
pbar.update()
|
||||
|
||||
|
||||
X_test, y_test = get_minibatch(doc_stream, size=5000)
|
||||
X_test = vect.transform(X_test)
|
||||
print('Accuracy: %.3f' % clf.score(X_test, y_test))
|
||||
|
||||
clf = clf.partial_fit(X_test, y_test)
|
||||
@@ -0,0 +1,23 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 9 - Embedding a Machine Learning Model into a Web Application
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
s = """
|
||||
|
||||
Due to the complexity of this chapter, and the many files involved,
|
||||
please refer to the IPython Notebook at
|
||||
https://github.com/rasbt/python-machine-learning-book/blob/master/code/ch09/ch09.ipynb
|
||||
|
||||
The web application files can be obtained from
|
||||
https://github.com/rasbt/python-machine-learning-book/tree/master/code/ch09
|
||||
|
||||
"""
|
||||
print(s)
|
||||
@@ -0,0 +1,510 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 10 - Predicting Continuous Target Variables with Regression Analysis
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
import seaborn as sns
|
||||
from sklearn.preprocessing import StandardScaler
|
||||
from sklearn.linear_model import LinearRegression
|
||||
from sklearn.linear_model import RANSACRegressor
|
||||
from sklearn.cross_validation import train_test_split
|
||||
from sklearn.metrics import r2_score
|
||||
from sklearn.metrics import mean_squared_error
|
||||
from sklearn.linear_model import Lasso
|
||||
from sklearn.preprocessing import PolynomialFeatures
|
||||
from sklearn.tree import DecisionTreeRegressor
|
||||
from sklearn.ensemble import RandomForestRegressor
|
||||
|
||||
# Added version check for recent scikit-learn 0.18 checks
|
||||
from distutils.version import LooseVersion as Version
|
||||
from sklearn import __version__ as sklearn_version
|
||||
if Version(sklearn_version) < '0.18':
|
||||
from sklearn.cross_validation import train_test_split
|
||||
else:
|
||||
from sklearn.model_selection import train_test_split
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Exploring the Housing dataset')
|
||||
print(50 * '-')
|
||||
|
||||
df = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/'
|
||||
'housing/housing.data',
|
||||
header=None,
|
||||
sep='\s+')
|
||||
|
||||
df.columns = ['CRIM', 'ZN', 'INDUS', 'CHAS',
|
||||
'NOX', 'RM', 'AGE', 'DIS', 'RAD',
|
||||
'TAX', 'PTRATIO', 'B', 'LSTAT', 'MEDV']
|
||||
print('Dataset excerpt:\n\n', df.head())
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Visualizing the important characteristics of a dataset')
|
||||
print(50 * '-')
|
||||
|
||||
sns.set(style='whitegrid', context='notebook')
|
||||
cols = ['LSTAT', 'INDUS', 'NOX', 'RM', 'MEDV']
|
||||
|
||||
sns.pairplot(df[cols], size=2.5)
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/scatter.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
cm = np.corrcoef(df[cols].values.T)
|
||||
sns.set(font_scale=1.5)
|
||||
hm = sns.heatmap(cm,
|
||||
cbar=True,
|
||||
annot=True,
|
||||
square=True,
|
||||
fmt='.2f',
|
||||
annot_kws={'size': 15},
|
||||
yticklabels=cols,
|
||||
xticklabels=cols)
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/corr_mat.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
sns.reset_orig()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Solving regression for regression'
|
||||
' parameters with gradient descent')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
class LinearRegressionGD(object):
|
||||
|
||||
def __init__(self, eta=0.001, n_iter=20):
|
||||
self.eta = eta
|
||||
self.n_iter = n_iter
|
||||
|
||||
def fit(self, X, y):
|
||||
self.w_ = np.zeros(1 + X.shape[1])
|
||||
self.cost_ = []
|
||||
|
||||
for i in range(self.n_iter):
|
||||
output = self.net_input(X)
|
||||
errors = (y - output)
|
||||
self.w_[1:] += self.eta * X.T.dot(errors)
|
||||
self.w_[0] += self.eta * errors.sum()
|
||||
cost = (errors**2).sum() / 2.0
|
||||
self.cost_.append(cost)
|
||||
return self
|
||||
|
||||
def net_input(self, X):
|
||||
return np.dot(X, self.w_[1:]) + self.w_[0]
|
||||
|
||||
def predict(self, X):
|
||||
return self.net_input(X)
|
||||
|
||||
|
||||
X = df[['RM']].values
|
||||
y = df['MEDV'].values
|
||||
|
||||
sc_x = StandardScaler()
|
||||
sc_y = StandardScaler()
|
||||
X_std = sc_x.fit_transform(X)
|
||||
y_std = sc_y.fit_transform(y[:, np.newaxis]).flatten()
|
||||
|
||||
lr = LinearRegressionGD()
|
||||
lr.fit(X_std, y_std)
|
||||
|
||||
|
||||
plt.plot(range(1, lr.n_iter+1), lr.cost_)
|
||||
plt.ylabel('SSE')
|
||||
plt.xlabel('Epoch')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/cost.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
def lin_regplot(X, y, model):
|
||||
plt.scatter(X, y, c='lightblue')
|
||||
plt.plot(X, model.predict(X), color='red', linewidth=2)
|
||||
return
|
||||
|
||||
|
||||
lin_regplot(X_std, y_std, lr)
|
||||
plt.xlabel('Average number of rooms [RM] (standardized)')
|
||||
plt.ylabel('Price in $1000\'s [MEDV] (standardized)')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/gradient_fit.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
print('Slope: %.3f' % lr.w_[1])
|
||||
print('Intercept: %.3f' % lr.w_[0])
|
||||
|
||||
|
||||
num_rooms_std = sc_x.transform(np.array([[5.0]]))
|
||||
price_std = lr.predict(num_rooms_std)
|
||||
print("Price in $1000's: %.3f" % sc_y.inverse_transform(price_std))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Estimating the coefficient of a'
|
||||
' regression model via scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
slr = LinearRegression()
|
||||
slr.fit(X, y)
|
||||
y_pred = slr.predict(X)
|
||||
print('Slope: %.3f' % slr.coef_[0])
|
||||
print('Intercept: %.3f' % slr.intercept_)
|
||||
|
||||
lin_regplot(X, y, slr)
|
||||
plt.xlabel('Average number of rooms [RM]')
|
||||
plt.ylabel('Price in $1000\'s [MEDV]')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/scikit_lr_fit.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
# adding a column vector of "ones"
|
||||
Xb = np.hstack((np.ones((X.shape[0], 1)), X))
|
||||
w = np.zeros(X.shape[1])
|
||||
z = np.linalg.inv(np.dot(Xb.T, Xb))
|
||||
w = np.dot(z, np.dot(Xb.T, y))
|
||||
|
||||
print('Slope: %.3f' % w[1])
|
||||
print('Intercept: %.3f' % w[0])
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Fitting a robust regression model using RANSAC')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
if Version(sklearn_version) < '0.18':
|
||||
ransac = RANSACRegressor(LinearRegression(),
|
||||
max_trials=100,
|
||||
min_samples=50,
|
||||
residual_metric=lambda x: np.sum(
|
||||
np.abs(x), axis=1),
|
||||
residual_threshold=5.0,
|
||||
random_state=0)
|
||||
else:
|
||||
ransac = RANSACRegressor(LinearRegression(),
|
||||
max_trials=100,
|
||||
min_samples=50,
|
||||
loss='absolute_loss',
|
||||
residual_threshold=5.0,
|
||||
random_state=0)
|
||||
ransac.fit(X, y)
|
||||
inlier_mask = ransac.inlier_mask_
|
||||
outlier_mask = np.logical_not(inlier_mask)
|
||||
|
||||
line_X = np.arange(3, 10, 1)
|
||||
line_y_ransac = ransac.predict(line_X[:, np.newaxis])
|
||||
plt.scatter(X[inlier_mask], y[inlier_mask],
|
||||
c='blue', marker='o', label='Inliers')
|
||||
plt.scatter(X[outlier_mask], y[outlier_mask],
|
||||
c='lightgreen', marker='s', label='Outliers')
|
||||
plt.plot(line_X, line_y_ransac, color='red')
|
||||
plt.xlabel('Average number of rooms [RM]')
|
||||
plt.ylabel('Price in $1000\'s [MEDV]')
|
||||
plt.legend(loc='upper left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/ransac_fit.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
print('Slope: %.3f' % ransac.estimator_.coef_[0])
|
||||
print('Intercept: %.3f' % ransac.estimator_.intercept_)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Evaluating the performance of linear regression models')
|
||||
print(50 * '-')
|
||||
|
||||
X = df.iloc[:, :-1].values
|
||||
y = df['MEDV'].values
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y, test_size=0.3, random_state=0)
|
||||
|
||||
slr = LinearRegression()
|
||||
|
||||
slr.fit(X_train, y_train)
|
||||
y_train_pred = slr.predict(X_train)
|
||||
y_test_pred = slr.predict(X_test)
|
||||
|
||||
plt.scatter(y_train_pred, y_train_pred - y_train,
|
||||
c='blue', marker='o', label='Training data')
|
||||
plt.scatter(y_test_pred, y_test_pred - y_test,
|
||||
c='lightgreen', marker='s', label='Test data')
|
||||
plt.xlabel('Predicted values')
|
||||
plt.ylabel('Residuals')
|
||||
plt.legend(loc='upper left')
|
||||
plt.hlines(y=0, xmin=-10, xmax=50, lw=2, color='red')
|
||||
plt.xlim([-10, 50])
|
||||
# plt.tight_layout()
|
||||
|
||||
# plt.savefig('./figures/slr_residuals.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
print('MSE train: %.3f, test: %.3f' % (
|
||||
mean_squared_error(y_train, y_train_pred),
|
||||
mean_squared_error(y_test, y_test_pred)))
|
||||
print('R^2 train: %.3f, test: %.3f' % (
|
||||
r2_score(y_train, y_train_pred),
|
||||
r2_score(y_test, y_test_pred)))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Using regularized methods for regression')
|
||||
print(50 * '-')
|
||||
|
||||
print('LASSO Coefficients')
|
||||
|
||||
lasso = Lasso(alpha=0.1)
|
||||
lasso.fit(X_train, y_train)
|
||||
y_train_pred = lasso.predict(X_train)
|
||||
y_test_pred = lasso.predict(X_test)
|
||||
print(lasso.coef_)
|
||||
|
||||
print('MSE train: %.3f, test: %.3f' % (
|
||||
mean_squared_error(y_train, y_train_pred),
|
||||
mean_squared_error(y_test, y_test_pred)))
|
||||
print('R^2 train: %.3f, test: %.3f' % (
|
||||
r2_score(y_train, y_train_pred),
|
||||
r2_score(y_test, y_test_pred)))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Turning a linear regression model into a curve'
|
||||
' - polynomial regression')
|
||||
print(50 * '-')
|
||||
|
||||
X = np.array([258.0, 270.0, 294.0,
|
||||
320.0, 342.0, 368.0,
|
||||
396.0, 446.0, 480.0, 586.0])[:, np.newaxis]
|
||||
|
||||
y = np.array([236.4, 234.4, 252.8,
|
||||
298.6, 314.2, 342.2,
|
||||
360.8, 368.0, 391.2,
|
||||
390.8])
|
||||
|
||||
lr = LinearRegression()
|
||||
pr = LinearRegression()
|
||||
quadratic = PolynomialFeatures(degree=2)
|
||||
X_quad = quadratic.fit_transform(X)
|
||||
|
||||
|
||||
# fit linear features
|
||||
lr.fit(X, y)
|
||||
X_fit = np.arange(250, 600, 10)[:, np.newaxis]
|
||||
y_lin_fit = lr.predict(X_fit)
|
||||
|
||||
# fit quadratic features
|
||||
pr.fit(X_quad, y)
|
||||
y_quad_fit = pr.predict(quadratic.fit_transform(X_fit))
|
||||
|
||||
# plot results
|
||||
plt.scatter(X, y, label='training points')
|
||||
plt.plot(X_fit, y_lin_fit, label='linear fit', linestyle='--')
|
||||
plt.plot(X_fit, y_quad_fit, label='quadratic fit')
|
||||
plt.legend(loc='upper left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/poly_example.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
y_lin_pred = lr.predict(X)
|
||||
y_quad_pred = pr.predict(X_quad)
|
||||
|
||||
|
||||
print('Training MSE linear: %.3f, quadratic: %.3f' % (
|
||||
mean_squared_error(y, y_lin_pred),
|
||||
mean_squared_error(y, y_quad_pred)))
|
||||
print('Training R^2 linear: %.3f, quadratic: %.3f' % (
|
||||
r2_score(y, y_lin_pred),
|
||||
r2_score(y, y_quad_pred)))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Modeling nonlinear relationships in the Housing Dataset')
|
||||
print(50 * '-')
|
||||
|
||||
X = df[['LSTAT']].values
|
||||
y = df['MEDV'].values
|
||||
|
||||
regr = LinearRegression()
|
||||
|
||||
# create quadratic features
|
||||
quadratic = PolynomialFeatures(degree=2)
|
||||
cubic = PolynomialFeatures(degree=3)
|
||||
X_quad = quadratic.fit_transform(X)
|
||||
X_cubic = cubic.fit_transform(X)
|
||||
|
||||
# fit features
|
||||
X_fit = np.arange(X.min(), X.max(), 1)[:, np.newaxis]
|
||||
|
||||
regr = regr.fit(X, y)
|
||||
y_lin_fit = regr.predict(X_fit)
|
||||
linear_r2 = r2_score(y, regr.predict(X))
|
||||
|
||||
regr = regr.fit(X_quad, y)
|
||||
y_quad_fit = regr.predict(quadratic.fit_transform(X_fit))
|
||||
quadratic_r2 = r2_score(y, regr.predict(X_quad))
|
||||
|
||||
regr = regr.fit(X_cubic, y)
|
||||
y_cubic_fit = regr.predict(cubic.fit_transform(X_fit))
|
||||
cubic_r2 = r2_score(y, regr.predict(X_cubic))
|
||||
|
||||
|
||||
# plot results
|
||||
plt.scatter(X, y, label='training points', color='lightgray')
|
||||
|
||||
plt.plot(X_fit, y_lin_fit,
|
||||
label='linear (d=1), $R^2=%.2f$' % linear_r2,
|
||||
color='blue',
|
||||
lw=2,
|
||||
linestyle=':')
|
||||
|
||||
plt.plot(X_fit, y_quad_fit,
|
||||
label='quadratic (d=2), $R^2=%.2f$' % quadratic_r2,
|
||||
color='red',
|
||||
lw=2,
|
||||
linestyle='-')
|
||||
|
||||
plt.plot(X_fit, y_cubic_fit,
|
||||
label='cubic (d=3), $R^2=%.2f$' % cubic_r2,
|
||||
color='green',
|
||||
lw=2,
|
||||
linestyle='--')
|
||||
|
||||
plt.xlabel('% lower status of the population [LSTAT]')
|
||||
plt.ylabel('Price in $1000\'s [MEDV]')
|
||||
plt.legend(loc='upper right')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/polyhouse_example.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
print('Transforming the dataset')
|
||||
X = df[['LSTAT']].values
|
||||
y = df['MEDV'].values
|
||||
|
||||
# transform features
|
||||
X_log = np.log(X)
|
||||
y_sqrt = np.sqrt(y)
|
||||
|
||||
# fit features
|
||||
X_fit = np.arange(X_log.min()-1, X_log.max()+1, 1)[:, np.newaxis]
|
||||
|
||||
regr = regr.fit(X_log, y_sqrt)
|
||||
y_lin_fit = regr.predict(X_fit)
|
||||
linear_r2 = r2_score(y_sqrt, regr.predict(X_log))
|
||||
|
||||
# plot results
|
||||
plt.scatter(X_log, y_sqrt, label='training points', color='lightgray')
|
||||
|
||||
plt.plot(X_fit, y_lin_fit,
|
||||
label='linear (d=1), $R^2=%.2f$' % linear_r2,
|
||||
color='blue',
|
||||
lw=2)
|
||||
|
||||
plt.xlabel('log(% lower status of the population [LSTAT])')
|
||||
plt.ylabel('$\sqrt{Price \; in \; \$1000\'s [MEDV]}$')
|
||||
plt.legend(loc='lower left')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/transform_example.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Decision tree regression')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
X = df[['LSTAT']].values
|
||||
y = df['MEDV'].values
|
||||
|
||||
tree = DecisionTreeRegressor(max_depth=3)
|
||||
tree.fit(X, y)
|
||||
|
||||
sort_idx = X.flatten().argsort()
|
||||
|
||||
lin_regplot(X[sort_idx], y[sort_idx], tree)
|
||||
plt.xlabel('% lower status of the population [LSTAT]')
|
||||
plt.ylabel('Price in $1000\'s [MEDV]')
|
||||
# plt.savefig('./figures/tree_regression.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Random forest regression')
|
||||
print(50 * '-')
|
||||
|
||||
X = df.iloc[:, :-1].values
|
||||
y = df['MEDV'].values
|
||||
|
||||
X_train, X_test, y_train, y_test = train_test_split(
|
||||
X, y, test_size=0.4, random_state=1)
|
||||
|
||||
forest = RandomForestRegressor(n_estimators=1000,
|
||||
criterion='mse',
|
||||
random_state=1,
|
||||
n_jobs=-1)
|
||||
forest.fit(X_train, y_train)
|
||||
y_train_pred = forest.predict(X_train)
|
||||
y_test_pred = forest.predict(X_test)
|
||||
|
||||
print('MSE train: %.3f, test: %.3f' % (
|
||||
mean_squared_error(y_train, y_train_pred),
|
||||
mean_squared_error(y_test, y_test_pred)))
|
||||
print('R^2 train: %.3f, test: %.3f' % (
|
||||
r2_score(y_train, y_train_pred),
|
||||
r2_score(y_test, y_test_pred)))
|
||||
|
||||
|
||||
plt.scatter(y_train_pred,
|
||||
y_train_pred - y_train,
|
||||
c='black',
|
||||
marker='o',
|
||||
s=35,
|
||||
alpha=0.5,
|
||||
label='Training data')
|
||||
plt.scatter(y_test_pred,
|
||||
y_test_pred - y_test,
|
||||
c='lightgreen',
|
||||
marker='s',
|
||||
s=35,
|
||||
alpha=0.7,
|
||||
label='Test data')
|
||||
|
||||
plt.xlabel('Predicted values')
|
||||
plt.ylabel('Residuals')
|
||||
plt.legend(loc='upper left')
|
||||
plt.hlines(y=0, xmin=-10, xmax=50, lw=2, color='red')
|
||||
plt.xlim([-10, 50])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/slr_residuals.png', dpi=300)
|
||||
plt.show()
|
||||
@@ -0,0 +1,375 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 11 - Working with Unlabeled Data – Clustering Analysis
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
from matplotlib import cm
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from sklearn.datasets import make_blobs
|
||||
from sklearn.cluster import KMeans
|
||||
from sklearn.metrics import silhouette_samples
|
||||
from scipy.spatial.distance import squareform
|
||||
from scipy.spatial.distance import pdist
|
||||
from scipy.cluster.hierarchy import linkage
|
||||
from scipy.cluster.hierarchy import dendrogram
|
||||
from sklearn.cluster import AgglomerativeClustering
|
||||
from sklearn.datasets import make_moons
|
||||
from sklearn.cluster import DBSCAN
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Grouping objects by similarity using k-means')
|
||||
print(50 * '-')
|
||||
|
||||
X, y = make_blobs(n_samples=150,
|
||||
n_features=2,
|
||||
centers=3,
|
||||
cluster_std=0.5,
|
||||
shuffle=True,
|
||||
random_state=0)
|
||||
|
||||
|
||||
plt.scatter(X[:, 0], X[:, 1], c='white', marker='o', s=50)
|
||||
plt.grid()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/spheres.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
km = KMeans(n_clusters=3,
|
||||
init='random',
|
||||
n_init=10,
|
||||
max_iter=300,
|
||||
tol=1e-04,
|
||||
random_state=0)
|
||||
y_km = km.fit_predict(X)
|
||||
|
||||
plt.scatter(X[y_km == 0, 0],
|
||||
X[y_km == 0, 1],
|
||||
s=50,
|
||||
c='lightgreen',
|
||||
marker='s',
|
||||
label='cluster 1')
|
||||
plt.scatter(X[y_km == 1, 0],
|
||||
X[y_km == 1, 1],
|
||||
s=50,
|
||||
c='orange',
|
||||
marker='o',
|
||||
label='cluster 2')
|
||||
plt.scatter(X[y_km == 2, 0],
|
||||
X[y_km == 2, 1],
|
||||
s=50,
|
||||
c='lightblue',
|
||||
marker='v',
|
||||
label='cluster 3')
|
||||
plt.scatter(km.cluster_centers_[:, 0],
|
||||
km.cluster_centers_[:, 1],
|
||||
s=250,
|
||||
marker='*',
|
||||
c='red',
|
||||
label='centroids')
|
||||
plt.legend()
|
||||
plt.grid()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/centroids.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Using the elbow method to find the optimal number of clusters')
|
||||
print(50 * '-')
|
||||
|
||||
print('Distortion: %.2f' % km.inertia_)
|
||||
|
||||
distortions = []
|
||||
for i in range(1, 11):
|
||||
km = KMeans(n_clusters=i,
|
||||
init='k-means++',
|
||||
n_init=10,
|
||||
max_iter=300,
|
||||
random_state=0)
|
||||
km.fit(X)
|
||||
distortions.append(km.inertia_)
|
||||
plt.plot(range(1, 11), distortions, marker='o')
|
||||
plt.xlabel('Number of clusters')
|
||||
plt.ylabel('Distortion')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/elbow.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Quantifying the quality of clustering via silhouette plots')
|
||||
print(50 * '-')
|
||||
|
||||
km = KMeans(n_clusters=3,
|
||||
init='k-means++',
|
||||
n_init=10,
|
||||
max_iter=300,
|
||||
tol=1e-04,
|
||||
random_state=0)
|
||||
y_km = km.fit_predict(X)
|
||||
|
||||
cluster_labels = np.unique(y_km)
|
||||
n_clusters = cluster_labels.shape[0]
|
||||
silhouette_vals = silhouette_samples(X, y_km, metric='euclidean')
|
||||
y_ax_lower, y_ax_upper = 0, 0
|
||||
yticks = []
|
||||
for i, c in enumerate(cluster_labels):
|
||||
c_silhouette_vals = silhouette_vals[y_km == c]
|
||||
c_silhouette_vals.sort()
|
||||
y_ax_upper += len(c_silhouette_vals)
|
||||
color = cm.jet(i / n_clusters)
|
||||
plt.barh(range(y_ax_lower, y_ax_upper), c_silhouette_vals, height=1.0,
|
||||
edgecolor='none', color=color)
|
||||
|
||||
yticks.append((y_ax_lower + y_ax_upper) / 2.)
|
||||
y_ax_lower += len(c_silhouette_vals)
|
||||
|
||||
silhouette_avg = np.mean(silhouette_vals)
|
||||
plt.axvline(silhouette_avg, color="red", linestyle="--")
|
||||
|
||||
plt.yticks(yticks, cluster_labels + 1)
|
||||
plt.ylabel('Cluster')
|
||||
plt.xlabel('Silhouette coefficient')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/silhouette.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
print('A bad clunstering:')
|
||||
|
||||
km = KMeans(n_clusters=2,
|
||||
init='k-means++',
|
||||
n_init=10,
|
||||
max_iter=300,
|
||||
tol=1e-04,
|
||||
random_state=0)
|
||||
y_km = km.fit_predict(X)
|
||||
|
||||
plt.scatter(X[y_km == 0, 0],
|
||||
X[y_km == 0, 1],
|
||||
s=50,
|
||||
c='lightgreen',
|
||||
marker='s',
|
||||
label='cluster 1')
|
||||
plt.scatter(X[y_km == 1, 0],
|
||||
X[y_km == 1, 1],
|
||||
s=50,
|
||||
c='orange',
|
||||
marker='o',
|
||||
label='cluster 2')
|
||||
|
||||
plt.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[:, 1],
|
||||
s=250, marker='*', c='red', label='centroids')
|
||||
plt.legend()
|
||||
plt.grid()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/centroids_bad.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
cluster_labels = np.unique(y_km)
|
||||
n_clusters = cluster_labels.shape[0]
|
||||
silhouette_vals = silhouette_samples(X, y_km, metric='euclidean')
|
||||
y_ax_lower, y_ax_upper = 0, 0
|
||||
yticks = []
|
||||
for i, c in enumerate(cluster_labels):
|
||||
c_silhouette_vals = silhouette_vals[y_km == c]
|
||||
c_silhouette_vals.sort()
|
||||
y_ax_upper += len(c_silhouette_vals)
|
||||
color = cm.jet(i / n_clusters)
|
||||
plt.barh(range(y_ax_lower, y_ax_upper), c_silhouette_vals, height=1.0,
|
||||
edgecolor='none', color=color)
|
||||
|
||||
yticks.append((y_ax_lower + y_ax_upper) / 2.)
|
||||
y_ax_lower += len(c_silhouette_vals)
|
||||
|
||||
silhouette_avg = np.mean(silhouette_vals)
|
||||
plt.axvline(silhouette_avg, color="red", linestyle="--")
|
||||
|
||||
plt.yticks(yticks, cluster_labels + 1)
|
||||
plt.ylabel('Cluster')
|
||||
plt.xlabel('Silhouette coefficient')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/silhouette_bad.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Organizing clusters as a hierarchical tree')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
np.random.seed(123)
|
||||
|
||||
variables = ['X', 'Y', 'Z']
|
||||
labels = ['ID_0', 'ID_1', 'ID_2', 'ID_3', 'ID_4']
|
||||
|
||||
X = np.random.random_sample([5, 3])*10
|
||||
df = pd.DataFrame(X, columns=variables, index=labels)
|
||||
print('DataFrame:\n\n', df)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Performing hierarchical clustering on a distance matrix')
|
||||
print(50 * '-')
|
||||
|
||||
row_dist = pd.DataFrame(squareform(pdist(df, metric='euclidean')),
|
||||
columns=labels,
|
||||
index=labels)
|
||||
print('Row distances:\n\n', row_dist)
|
||||
|
||||
print('1. incorrect approach: Squareform distance matrix')
|
||||
|
||||
row_clusters = linkage(row_dist, method='complete', metric='euclidean')
|
||||
df1 = pd.DataFrame(row_clusters,
|
||||
columns=['row label 1', 'row label 2',
|
||||
'distance', 'no. of items in clust.'],
|
||||
index=['cluster %d' % (i + 1)
|
||||
for i in range(row_clusters.shape[0])])
|
||||
|
||||
|
||||
print('2. correct approach: Condensed distance matrix')
|
||||
|
||||
row_clusters = linkage(pdist(df, metric='euclidean'), method='complete')
|
||||
df2 = pd.DataFrame(row_clusters,
|
||||
columns=['row label 1', 'row label 2',
|
||||
'distance', 'no. of items in clust.'],
|
||||
index=['cluster %d' % (i + 1)
|
||||
for i in range(row_clusters.shape[0])])
|
||||
|
||||
|
||||
print('3. correct approach: Input sample matrix')
|
||||
|
||||
row_clusters = linkage(df.values, method='complete', metric='euclidean')
|
||||
df3 = pd.DataFrame(row_clusters,
|
||||
columns=['row label 1', 'row label 2',
|
||||
'distance', 'no. of items in clust.'],
|
||||
index=['cluster %d' % (i + 1)
|
||||
for i in range(row_clusters.shape[0])])
|
||||
|
||||
|
||||
# make dendrogram black (part 1/2)
|
||||
# from scipy.cluster.hierarchy import set_link_color_palette
|
||||
# set_link_color_palette(['black'])
|
||||
|
||||
row_dendr = dendrogram(row_clusters,
|
||||
labels=labels,
|
||||
# make dendrogram black (part 2/2)
|
||||
# color_threshold=np.inf
|
||||
)
|
||||
# plt.tight_layout()
|
||||
plt.ylabel('Euclidean distance')
|
||||
# plt.savefig('./figures/dendrogram.png', dpi=300,
|
||||
# bbox_inches='tight')
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Attaching dendrograms to a heat map')
|
||||
print(50 * '-')
|
||||
|
||||
# plot row dendrogram
|
||||
fig = plt.figure(figsize=(8, 8), facecolor='white')
|
||||
axd = fig.add_axes([0.09, 0.1, 0.2, 0.6])
|
||||
|
||||
# note: for matplotlib < v1.5.1, please use orientation='right'
|
||||
row_dendr = dendrogram(row_clusters, orientation='left')
|
||||
|
||||
# reorder data with respect to clustering
|
||||
df_rowclust = df.ix[row_dendr['leaves'][::-1]]
|
||||
|
||||
axd.set_xticks([])
|
||||
axd.set_yticks([])
|
||||
|
||||
# remove axes spines from dendrogram
|
||||
for i in axd.spines.values():
|
||||
i.set_visible(False)
|
||||
|
||||
# plot heatmap
|
||||
axm = fig.add_axes([0.23, 0.1, 0.6, 0.6]) # x-pos, y-pos, width, height
|
||||
cax = axm.matshow(df_rowclust, interpolation='nearest', cmap='hot_r')
|
||||
fig.colorbar(cax)
|
||||
axm.set_xticklabels([''] + list(df_rowclust.columns))
|
||||
axm.set_yticklabels([''] + list(df_rowclust.index))
|
||||
|
||||
# plt.savefig('./figures/heatmap.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Applying agglomerative clustering via scikit-learn')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
ac = AgglomerativeClustering(n_clusters=2,
|
||||
affinity='euclidean',
|
||||
linkage='complete')
|
||||
labels = ac.fit_predict(X)
|
||||
print('Cluster labels: %s' % labels)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Section: Attaching dendrograms to a heat map')
|
||||
print(50 * '-')
|
||||
|
||||
X, y = make_moons(n_samples=200, noise=0.05, random_state=0)
|
||||
plt.scatter(X[:, 0], X[:, 1])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/moons.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
f, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 3))
|
||||
|
||||
km = KMeans(n_clusters=2, random_state=0)
|
||||
y_km = km.fit_predict(X)
|
||||
ax1.scatter(X[y_km == 0, 0], X[y_km == 0, 1],
|
||||
c='lightblue', marker='o', s=40, label='cluster 1')
|
||||
ax1.scatter(X[y_km == 1, 0], X[y_km == 1, 1],
|
||||
c='red', marker='s', s=40, label='cluster 2')
|
||||
ax1.set_title('K-means clustering')
|
||||
|
||||
ac = AgglomerativeClustering(n_clusters=2,
|
||||
affinity='euclidean',
|
||||
linkage='complete')
|
||||
y_ac = ac.fit_predict(X)
|
||||
ax2.scatter(X[y_ac == 0, 0], X[y_ac == 0, 1], c='lightblue',
|
||||
marker='o', s=40, label='cluster 1')
|
||||
ax2.scatter(X[y_ac == 1, 0], X[y_ac == 1, 1], c='red',
|
||||
marker='s', s=40, label='cluster 2')
|
||||
ax2.set_title('Agglomerative clustering')
|
||||
|
||||
plt.legend()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/kmeans_and_ac.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
print('DBSCAN')
|
||||
|
||||
db = DBSCAN(eps=0.2, min_samples=5, metric='euclidean')
|
||||
y_db = db.fit_predict(X)
|
||||
plt.scatter(X[y_db == 0, 0], X[y_db == 0, 1],
|
||||
c='lightblue', marker='o', s=40,
|
||||
label='cluster 1')
|
||||
plt.scatter(X[y_db == 1, 0], X[y_db == 1, 1],
|
||||
c='red', marker='s', s=40,
|
||||
label='cluster 2')
|
||||
plt.legend()
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/moons_dbscan.png', dpi=300)
|
||||
plt.show()
|
||||
@@ -0,0 +1,943 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 12 - Training Artificial Neural Networks for Image Recognition
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
import os
|
||||
import struct
|
||||
import numpy as np
|
||||
from scipy.special import expit
|
||||
import sys
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Obtaining the MNIST dataset')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
s = """
|
||||
The MNIST dataset is publicly available at http://yann.lecun.com/exdb/mnist/
|
||||
and consists of the following four parts:
|
||||
|
||||
- Training set images: train-images-idx3-ubyte.gz
|
||||
(9.9 MB, 47 MB unzipped, 60,000 samples)
|
||||
- Training set labels: train-labels-idx1-ubyte.gz
|
||||
(29 KB, 60 KB unzipped, 60,000 labels)
|
||||
- Test set images: t10k-images-idx3-ubyte.gz
|
||||
(1.6 MB, 7.8 MB, 10,000 samples)
|
||||
- Test set labels: t10k-labels-idx1-ubyte.gz
|
||||
(5 KB, 10 KB unzipped, 10,000 labels)
|
||||
|
||||
In this section, we will only be working with a subset of MNIST, thus,
|
||||
we only need to download the training set images and training set labels.
|
||||
After downloading the files, I recommend unzipping the files using
|
||||
the Unix/Linux gzip tool from
|
||||
the terminal for efficiency, e.g., using the command
|
||||
|
||||
gzip *ubyte.gz -d
|
||||
|
||||
in your local MNIST download directory, or, using your
|
||||
favorite unzipping tool if you are working with a machine
|
||||
running on Microsoft Windows. The images are stored in byte form,
|
||||
and using the following function, we will read them into NumPy arrays
|
||||
that we will use to train our MLP.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
print(s)
|
||||
|
||||
_ = input("Please hit enter to continue.")
|
||||
|
||||
|
||||
def load_mnist(path, kind='train'):
|
||||
"""Load MNIST data from `path`"""
|
||||
labels_path = os.path.join(path,
|
||||
'%s-labels-idx1-ubyte' % kind)
|
||||
images_path = os.path.join(path,
|
||||
'%s-images-idx3-ubyte' % kind)
|
||||
|
||||
with open(labels_path, 'rb') as lbpath:
|
||||
magic, n = struct.unpack('>II',
|
||||
lbpath.read(8))
|
||||
labels = np.fromfile(lbpath,
|
||||
dtype=np.uint8)
|
||||
|
||||
with open(images_path, 'rb') as imgpath:
|
||||
magic, num, rows, cols = struct.unpack(">IIII",
|
||||
imgpath.read(16))
|
||||
images = np.fromfile(imgpath,
|
||||
dtype=np.uint8).reshape(len(labels), 784)
|
||||
|
||||
return images, labels
|
||||
|
||||
|
||||
X_train, y_train = load_mnist('mnist', kind='train')
|
||||
print('Training rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1]))
|
||||
|
||||
X_test, y_test = load_mnist('mnist', kind='t10k')
|
||||
print('Test rows: %d, columns: %d' % (X_test.shape[0], X_test.shape[1]))
|
||||
|
||||
fig, ax = plt.subplots(nrows=2, ncols=5, sharex=True, sharey=True,)
|
||||
ax = ax.flatten()
|
||||
for i in range(10):
|
||||
img = X_train[y_train == i][0].reshape(28, 28)
|
||||
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
|
||||
|
||||
ax[0].set_xticks([])
|
||||
ax[0].set_yticks([])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/mnist_all.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
fig, ax = plt.subplots(nrows=5, ncols=5, sharex=True, sharey=True,)
|
||||
ax = ax.flatten()
|
||||
for i in range(25):
|
||||
img = X_train[y_train == 7][i].reshape(28, 28)
|
||||
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
|
||||
|
||||
ax[0].set_xticks([])
|
||||
ax[0].set_yticks([])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/mnist_7.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
"""
|
||||
Uncomment the following lines to optionally save the data in CSV format.
|
||||
However, note that those CSV files will take up a
|
||||
substantial amount of storage space:
|
||||
|
||||
- train_img.csv 1.1 GB (gigabytes)
|
||||
- train_labels.csv 1.4 MB (megabytes)
|
||||
- test_img.csv 187.0 MB
|
||||
- test_labels 144 KB (kilobytes)
|
||||
"""
|
||||
|
||||
# np.savetxt('train_img.csv', X_train, fmt='%i', delimiter=',')
|
||||
# np.savetxt('train_labels.csv', y_train, fmt='%i', delimiter=',')
|
||||
# X_train = np.genfromtxt('train_img.csv', dtype=int, delimiter=',')
|
||||
# y_train = np.genfromtxt('train_labels.csv', dtype=int, delimiter=',')
|
||||
|
||||
# np.savetxt('test_img.csv', X_test, fmt='%i', delimiter=',')
|
||||
# np.savetxt('test_labels.csv', y_test, fmt='%i', delimiter=',')
|
||||
# X_test = np.genfromtxt('test_img.csv', dtype=int, delimiter=',')
|
||||
# y_test = np.genfromtxt('test_labels.csv', dtype=int, delimiter=',')
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Implementing a multi-layer perceptron')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
class NeuralNetMLP(object):
|
||||
""" Feedforward neural network / Multi-layer perceptron classifier.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
n_output : int
|
||||
Number of output units, should be equal to the
|
||||
number of unique class labels.
|
||||
n_features : int
|
||||
Number of features (dimensions) in the target dataset.
|
||||
Should be equal to the number of columns in the X array.
|
||||
n_hidden : int (default: 30)
|
||||
Number of hidden units.
|
||||
l1 : float (default: 0.0)
|
||||
Lambda value for L1-regularization.
|
||||
No regularization if l1=0.0 (default)
|
||||
l2 : float (default: 0.0)
|
||||
Lambda value for L2-regularization.
|
||||
No regularization if l2=0.0 (default)
|
||||
epochs : int (default: 500)
|
||||
Number of passes over the training set.
|
||||
eta : float (default: 0.001)
|
||||
Learning rate.
|
||||
alpha : float (default: 0.0)
|
||||
Momentum constant. Factor multiplied with the
|
||||
gradient of the previous epoch t-1 to improve
|
||||
learning speed
|
||||
w(t) := w(t) - (grad(t) + alpha*grad(t-1))
|
||||
decrease_const : float (default: 0.0)
|
||||
Decrease constant. Shrinks the learning rate
|
||||
after each epoch via eta / (1 + epoch*decrease_const)
|
||||
shuffle : bool (default: True)
|
||||
Shuffles training data every epoch if True to prevent circles.
|
||||
minibatches : int (default: 1)
|
||||
Divides training data into k minibatches for efficiency.
|
||||
Normal gradient descent learning if k=1 (default).
|
||||
random_state : int (default: None)
|
||||
Set random state for shuffling and initializing the weights.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
cost_ : list
|
||||
Sum of squared errors after each epoch.
|
||||
|
||||
"""
|
||||
def __init__(self, n_output, n_features, n_hidden=30,
|
||||
l1=0.0, l2=0.0, epochs=500, eta=0.001,
|
||||
alpha=0.0, decrease_const=0.0, shuffle=True,
|
||||
minibatches=1, random_state=None):
|
||||
|
||||
np.random.seed(random_state)
|
||||
self.n_output = n_output
|
||||
self.n_features = n_features
|
||||
self.n_hidden = n_hidden
|
||||
self.w1, self.w2 = self._initialize_weights()
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
self.epochs = epochs
|
||||
self.eta = eta
|
||||
self.alpha = alpha
|
||||
self.decrease_const = decrease_const
|
||||
self.shuffle = shuffle
|
||||
self.minibatches = minibatches
|
||||
|
||||
def _encode_labels(self, y, k):
|
||||
"""Encode labels into one-hot representation
|
||||
|
||||
Parameters
|
||||
------------
|
||||
y : array, shape = [n_samples]
|
||||
Target values.
|
||||
|
||||
Returns
|
||||
-----------
|
||||
onehot : array, shape = (n_labels, n_samples)
|
||||
|
||||
"""
|
||||
onehot = np.zeros((k, y.shape[0]))
|
||||
for idx, val in enumerate(y):
|
||||
onehot[val, idx] = 1.0
|
||||
return onehot
|
||||
|
||||
def _initialize_weights(self):
|
||||
"""Initialize weights with small random numbers."""
|
||||
w1 = np.random.uniform(-1.0, 1.0,
|
||||
size=self.n_hidden*(self.n_features + 1))
|
||||
w1 = w1.reshape(self.n_hidden, self.n_features + 1)
|
||||
w2 = np.random.uniform(-1.0, 1.0,
|
||||
size=self.n_output*(self.n_hidden + 1))
|
||||
w2 = w2.reshape(self.n_output, self.n_hidden + 1)
|
||||
return w1, w2
|
||||
|
||||
def _sigmoid(self, z):
|
||||
"""Compute logistic function (sigmoid)
|
||||
|
||||
Uses scipy.special.expit to avoid overflow
|
||||
error for very small input values z.
|
||||
|
||||
"""
|
||||
# return 1.0 / (1.0 + np.exp(-z))
|
||||
return expit(z)
|
||||
|
||||
def _sigmoid_gradient(self, z):
|
||||
"""Compute gradient of the logistic function"""
|
||||
sg = self._sigmoid(z)
|
||||
return sg * (1 - sg)
|
||||
|
||||
def _add_bias_unit(self, X, how='column'):
|
||||
"""Add bias unit (column or row of 1s) to array at index 0"""
|
||||
if how == 'column':
|
||||
X_new = np.ones((X.shape[0], X.shape[1]+1))
|
||||
X_new[:, 1:] = X
|
||||
elif how == 'row':
|
||||
X_new = np.ones((X.shape[0]+1, X.shape[1]))
|
||||
X_new[1:, :] = X
|
||||
else:
|
||||
raise AttributeError('`how` must be `column` or `row`')
|
||||
return X_new
|
||||
|
||||
def _feedforward(self, X, w1, w2):
|
||||
"""Compute feedforward step
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
X : array, shape = [n_samples, n_features]
|
||||
Input layer with original features.
|
||||
w1 : array, shape = [n_hidden_units, n_features]
|
||||
Weight matrix for input layer -> hidden layer.
|
||||
w2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Weight matrix for hidden layer -> output layer.
|
||||
|
||||
Returns
|
||||
----------
|
||||
a1 : array, shape = [n_samples, n_features+1]
|
||||
Input values with bias unit.
|
||||
z2 : array, shape = [n_hidden, n_samples]
|
||||
Net input of hidden layer.
|
||||
a2 : array, shape = [n_hidden+1, n_samples]
|
||||
Activation of hidden layer.
|
||||
z3 : array, shape = [n_output_units, n_samples]
|
||||
Net input of output layer.
|
||||
a3 : array, shape = [n_output_units, n_samples]
|
||||
Activation of output layer.
|
||||
|
||||
"""
|
||||
a1 = self._add_bias_unit(X, how='column')
|
||||
z2 = w1.dot(a1.T)
|
||||
a2 = self._sigmoid(z2)
|
||||
a2 = self._add_bias_unit(a2, how='row')
|
||||
z3 = w2.dot(a2)
|
||||
a3 = self._sigmoid(z3)
|
||||
return a1, z2, a2, z3, a3
|
||||
|
||||
def _L2_reg(self, lambda_, w1, w2):
|
||||
"""Compute L2-regularization cost"""
|
||||
return (lambda_/2.0) * (np.sum(w1[:, 1:] ** 2) +
|
||||
np.sum(w2[:, 1:] ** 2))
|
||||
|
||||
def _L1_reg(self, lambda_, w1, w2):
|
||||
"""Compute L1-regularization cost"""
|
||||
return (lambda_/2.0) * (np.abs(w1[:, 1:]).sum() +
|
||||
np.abs(w2[:, 1:]).sum())
|
||||
|
||||
def _get_cost(self, y_enc, output, w1, w2):
|
||||
"""Compute cost function.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
y_enc : array, shape = (n_labels, n_samples)
|
||||
one-hot encoded class labels.
|
||||
output : array, shape = [n_output_units, n_samples]
|
||||
Activation of the output layer (feedforward)
|
||||
w1 : array, shape = [n_hidden_units, n_features]
|
||||
Weight matrix for input layer -> hidden layer.
|
||||
w2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Weight matrix for hidden layer -> output layer.
|
||||
|
||||
Returns
|
||||
---------
|
||||
cost : float
|
||||
Regularized cost.
|
||||
|
||||
"""
|
||||
term1 = -y_enc * (np.log(output))
|
||||
term2 = (1 - y_enc) * np.log(1 - output)
|
||||
cost = np.sum(term1 - term2)
|
||||
L1_term = self._L1_reg(self.l1, w1, w2)
|
||||
L2_term = self._L2_reg(self.l2, w1, w2)
|
||||
cost = cost + L1_term + L2_term
|
||||
return cost
|
||||
|
||||
def _get_gradient(self, a1, a2, a3, z2, y_enc, w1, w2):
|
||||
""" Compute gradient step using backpropagation.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
a1 : array, shape = [n_samples, n_features+1]
|
||||
Input values with bias unit.
|
||||
a2 : array, shape = [n_hidden+1, n_samples]
|
||||
Activation of hidden layer.
|
||||
a3 : array, shape = [n_output_units, n_samples]
|
||||
Activation of output layer.
|
||||
z2 : array, shape = [n_hidden, n_samples]
|
||||
Net input of hidden layer.
|
||||
y_enc : array, shape = (n_labels, n_samples)
|
||||
one-hot encoded class labels.
|
||||
w1 : array, shape = [n_hidden_units, n_features]
|
||||
Weight matrix for input layer -> hidden layer.
|
||||
w2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Weight matrix for hidden layer -> output layer.
|
||||
|
||||
Returns
|
||||
---------
|
||||
grad1 : array, shape = [n_hidden_units, n_features]
|
||||
Gradient of the weight matrix w1.
|
||||
grad2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Gradient of the weight matrix w2.
|
||||
|
||||
"""
|
||||
# backpropagation
|
||||
sigma3 = a3 - y_enc
|
||||
z2 = self._add_bias_unit(z2, how='row')
|
||||
sigma2 = w2.T.dot(sigma3) * self._sigmoid_gradient(z2)
|
||||
sigma2 = sigma2[1:, :]
|
||||
grad1 = sigma2.dot(a1)
|
||||
grad2 = sigma3.dot(a2.T)
|
||||
|
||||
# regularize
|
||||
grad1[:, 1:] += (w1[:, 1:] * (self.l1 + self.l2))
|
||||
grad2[:, 1:] += (w2[:, 1:] * (self.l1 + self.l2))
|
||||
|
||||
return grad1, grad2
|
||||
|
||||
def predict(self, X):
|
||||
"""Predict class labels
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
X : array, shape = [n_samples, n_features]
|
||||
Input layer with original features.
|
||||
|
||||
Returns:
|
||||
----------
|
||||
y_pred : array, shape = [n_samples]
|
||||
Predicted class labels.
|
||||
|
||||
"""
|
||||
if len(X.shape) != 2:
|
||||
raise AttributeError('X must be a [n_samples, n_features] array.\n'
|
||||
'Use X[:,None] for 1-feature classification,'
|
||||
'\nor X[[i]] for 1-sample classification')
|
||||
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X, self.w1, self.w2)
|
||||
y_pred = np.argmax(z3, axis=0)
|
||||
return y_pred
|
||||
|
||||
def fit(self, X, y, print_progress=False):
|
||||
""" Learn weights from training data.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
X : array, shape = [n_samples, n_features]
|
||||
Input layer with original features.
|
||||
y : array, shape = [n_samples]
|
||||
Target class labels.
|
||||
print_progress : bool (default: False)
|
||||
Prints progress as the number of epochs
|
||||
to stderr.
|
||||
|
||||
Returns:
|
||||
----------
|
||||
self
|
||||
|
||||
"""
|
||||
self.cost_ = []
|
||||
X_data, y_data = X.copy(), y.copy()
|
||||
y_enc = self._encode_labels(y, self.n_output)
|
||||
|
||||
delta_w1_prev = np.zeros(self.w1.shape)
|
||||
delta_w2_prev = np.zeros(self.w2.shape)
|
||||
|
||||
for i in range(self.epochs):
|
||||
|
||||
# adaptive learning rate
|
||||
self.eta /= (1 + self.decrease_const*i)
|
||||
|
||||
if print_progress:
|
||||
sys.stderr.write('\rEpoch: %d/%d' % (i+1, self.epochs))
|
||||
sys.stderr.flush()
|
||||
|
||||
if self.shuffle:
|
||||
idx = np.random.permutation(y_data.shape[0])
|
||||
X_data, y_enc = X_data[idx], y_enc[:, idx]
|
||||
|
||||
mini = np.array_split(range(y_data.shape[0]), self.minibatches)
|
||||
for idx in mini:
|
||||
|
||||
# feedforward
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X_data[idx],
|
||||
self.w1,
|
||||
self.w2)
|
||||
cost = self._get_cost(y_enc=y_enc[:, idx],
|
||||
output=a3,
|
||||
w1=self.w1,
|
||||
w2=self.w2)
|
||||
self.cost_.append(cost)
|
||||
|
||||
# compute gradient via backpropagation
|
||||
grad1, grad2 = self._get_gradient(a1=a1, a2=a2,
|
||||
a3=a3, z2=z2,
|
||||
y_enc=y_enc[:, idx],
|
||||
w1=self.w1,
|
||||
w2=self.w2)
|
||||
|
||||
delta_w1, delta_w2 = self.eta * grad1, self.eta * grad2
|
||||
self.w1 -= (delta_w1 + (self.alpha * delta_w1_prev))
|
||||
self.w2 -= (delta_w2 + (self.alpha * delta_w2_prev))
|
||||
delta_w1_prev, delta_w2_prev = delta_w1, delta_w2
|
||||
|
||||
return self
|
||||
|
||||
|
||||
nn = NeuralNetMLP(n_output=10,
|
||||
n_features=X_train.shape[1],
|
||||
n_hidden=50,
|
||||
l2=0.1,
|
||||
l1=0.0,
|
||||
epochs=1000,
|
||||
eta=0.001,
|
||||
alpha=0.001,
|
||||
decrease_const=0.00001,
|
||||
minibatches=50,
|
||||
shuffle=True,
|
||||
random_state=1)
|
||||
|
||||
nn.fit(X_train, y_train, print_progress=True)
|
||||
|
||||
plt.plot(range(len(nn.cost_)), nn.cost_)
|
||||
plt.ylim([0, 2000])
|
||||
plt.ylabel('Cost')
|
||||
plt.xlabel('Epochs * 50')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/cost.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
batches = np.array_split(range(len(nn.cost_)), 1000)
|
||||
cost_ary = np.array(nn.cost_)
|
||||
cost_avgs = [np.mean(cost_ary[i]) for i in batches]
|
||||
|
||||
|
||||
plt.plot(range(len(cost_avgs)), cost_avgs, color='red')
|
||||
plt.ylim([0, 2000])
|
||||
plt.ylabel('Cost')
|
||||
plt.xlabel('Epochs')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/cost2.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
y_train_pred = nn.predict(X_train)
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
acc = ((np.sum(y_train == y_train_pred, axis=0)).astype('float') /
|
||||
X_train.shape[0])
|
||||
else:
|
||||
acc = np.sum(y_train == y_train_pred, axis=0) / X_train.shape[0]
|
||||
|
||||
print('Training accuracy: %.2f%%' % (acc * 100))
|
||||
|
||||
|
||||
y_test_pred = nn.predict(X_test)
|
||||
|
||||
if sys.version_info < (3, 0):
|
||||
acc = ((np.sum(y_test == y_test_pred, axis=0)).astype('float') /
|
||||
X_test.shape[0])
|
||||
else:
|
||||
acc = np.sum(y_test == y_test_pred, axis=0) / X_test.shape[0]
|
||||
|
||||
print('Test accuracy: %.2f%%' % (acc * 100))
|
||||
|
||||
|
||||
miscl_img = X_test[y_test != y_test_pred][:25]
|
||||
correct_lab = y_test[y_test != y_test_pred][:25]
|
||||
miscl_lab = y_test_pred[y_test != y_test_pred][:25]
|
||||
|
||||
fig, ax = plt.subplots(nrows=5, ncols=5, sharex=True, sharey=True,)
|
||||
ax = ax.flatten()
|
||||
for i in range(25):
|
||||
img = miscl_img[i].reshape(28, 28)
|
||||
ax[i].imshow(img, cmap='Greys', interpolation='nearest')
|
||||
ax[i].set_title('%d) t: %d p: %d' % (i+1, correct_lab[i], miscl_lab[i]))
|
||||
|
||||
ax[0].set_xticks([])
|
||||
ax[0].set_yticks([])
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/mnist_miscl.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Debugging neural networks with gradient checking')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
class MLPGradientCheck(object):
|
||||
""" Feedforward neural network / Multi-layer perceptron classifier.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
n_output : int
|
||||
Number of output units, should be equal to the
|
||||
number of unique class labels.
|
||||
n_features : int
|
||||
Number of features (dimensions) in the target dataset.
|
||||
Should be equal to the number of columns in the X array.
|
||||
n_hidden : int (default: 30)
|
||||
Number of hidden units.
|
||||
l1 : float (default: 0.0)
|
||||
Lambda value for L1-regularization.
|
||||
No regularization if l1=0.0 (default)
|
||||
l2 : float (default: 0.0)
|
||||
Lambda value for L2-regularization.
|
||||
No regularization if l2=0.0 (default)
|
||||
epochs : int (default: 500)
|
||||
Number of passes over the training set.
|
||||
eta : float (default: 0.001)
|
||||
Learning rate.
|
||||
alpha : float (default: 0.0)
|
||||
Momentum constant. Factor multiplied with the
|
||||
gradient of the previous epoch t-1 to improve
|
||||
learning speed
|
||||
w(t) := w(t) - (grad(t) + alpha*grad(t-1))
|
||||
decrease_const : float (default: 0.0)
|
||||
Decrease constant. Shrinks the learning rate
|
||||
after each epoch via eta / (1 + epoch*decrease_const)
|
||||
shuffle : bool (default: False)
|
||||
Shuffles training data every epoch if True to prevent circles.
|
||||
minibatches : int (default: 1)
|
||||
Divides training data into k minibatches for efficiency.
|
||||
Normal gradient descent learning if k=1 (default).
|
||||
random_state : int (default: None)
|
||||
Set random state for shuffling and initializing the weights.
|
||||
|
||||
Attributes
|
||||
-----------
|
||||
cost_ : list
|
||||
Sum of squared errors after each epoch.
|
||||
|
||||
"""
|
||||
def __init__(self, n_output, n_features, n_hidden=30,
|
||||
l1=0.0, l2=0.0, epochs=500, eta=0.001,
|
||||
alpha=0.0, decrease_const=0.0, shuffle=True,
|
||||
minibatches=1, random_state=None):
|
||||
|
||||
np.random.seed(random_state)
|
||||
self.n_output = n_output
|
||||
self.n_features = n_features
|
||||
self.n_hidden = n_hidden
|
||||
self.w1, self.w2 = self._initialize_weights()
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
self.epochs = epochs
|
||||
self.eta = eta
|
||||
self.alpha = alpha
|
||||
self.decrease_const = decrease_const
|
||||
self.shuffle = shuffle
|
||||
self.minibatches = minibatches
|
||||
|
||||
def _encode_labels(self, y, k):
|
||||
"""Encode labels into one-hot representation
|
||||
|
||||
Parameters
|
||||
------------
|
||||
y : array, shape = [n_samples]
|
||||
Target values.
|
||||
|
||||
Returns
|
||||
-----------
|
||||
onehot : array, shape = (n_labels, n_samples)
|
||||
|
||||
"""
|
||||
onehot = np.zeros((k, y.shape[0]))
|
||||
for idx, val in enumerate(y):
|
||||
onehot[val, idx] = 1.0
|
||||
return onehot
|
||||
|
||||
def _initialize_weights(self):
|
||||
"""Initialize weights with small random numbers."""
|
||||
w1 = np.random.uniform(-1.0, 1.0,
|
||||
size=self.n_hidden*(self.n_features + 1))
|
||||
w1 = w1.reshape(self.n_hidden, self.n_features + 1)
|
||||
w2 = np.random.uniform(-1.0, 1.0,
|
||||
size=self.n_output*(self.n_hidden + 1))
|
||||
w2 = w2.reshape(self.n_output, self.n_hidden + 1)
|
||||
return w1, w2
|
||||
|
||||
def _sigmoid(self, z):
|
||||
"""Compute logistic function (sigmoid)
|
||||
|
||||
Uses scipy.special.expit to avoid overflow
|
||||
error for very small input values z.
|
||||
|
||||
"""
|
||||
# return 1.0 / (1.0 + np.exp(-z))
|
||||
return expit(z)
|
||||
|
||||
def _sigmoid_gradient(self, z):
|
||||
"""Compute gradient of the logistic function"""
|
||||
sg = self._sigmoid(z)
|
||||
return sg * (1 - sg)
|
||||
|
||||
def _add_bias_unit(self, X, how='column'):
|
||||
"""Add bias unit (column or row of 1s) to array at index 0"""
|
||||
if how == 'column':
|
||||
X_new = np.ones((X.shape[0], X.shape[1]+1))
|
||||
X_new[:, 1:] = X
|
||||
elif how == 'row':
|
||||
X_new = np.ones((X.shape[0]+1, X.shape[1]))
|
||||
X_new[1:, :] = X
|
||||
else:
|
||||
raise AttributeError('`how` must be `column` or `row`')
|
||||
return X_new
|
||||
|
||||
def _feedforward(self, X, w1, w2):
|
||||
"""Compute feedforward step
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
X : array, shape = [n_samples, n_features]
|
||||
Input layer with original features.
|
||||
w1 : array, shape = [n_hidden_units, n_features]
|
||||
Weight matrix for input layer -> hidden layer.
|
||||
w2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Weight matrix for hidden layer -> output layer.
|
||||
|
||||
Returns
|
||||
----------
|
||||
a1 : array, shape = [n_samples, n_features+1]
|
||||
Input values with bias unit.
|
||||
z2 : array, shape = [n_hidden, n_samples]
|
||||
Net input of hidden layer.
|
||||
a2 : array, shape = [n_hidden+1, n_samples]
|
||||
Activation of hidden layer.
|
||||
z3 : array, shape = [n_output_units, n_samples]
|
||||
Net input of output layer.
|
||||
a3 : array, shape = [n_output_units, n_samples]
|
||||
Activation of output layer.
|
||||
|
||||
"""
|
||||
a1 = self._add_bias_unit(X, how='column')
|
||||
z2 = w1.dot(a1.T)
|
||||
a2 = self._sigmoid(z2)
|
||||
a2 = self._add_bias_unit(a2, how='row')
|
||||
z3 = w2.dot(a2)
|
||||
a3 = self._sigmoid(z3)
|
||||
return a1, z2, a2, z3, a3
|
||||
|
||||
def _L2_reg(self, lambda_, w1, w2):
|
||||
"""Compute L2-regularization cost"""
|
||||
return (lambda_/2.0) * (np.sum(w1[:, 1:] ** 2) +
|
||||
np.sum(w2[:, 1:] ** 2))
|
||||
|
||||
def _L1_reg(self, lambda_, w1, w2):
|
||||
"""Compute L1-regularization cost"""
|
||||
return (lambda_/2.0) * (np.abs(w1[:, 1:]).sum() +
|
||||
np.abs(w2[:, 1:]).sum())
|
||||
|
||||
def _get_cost(self, y_enc, output, w1, w2):
|
||||
"""Compute cost function.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
y_enc : array, shape = (n_labels, n_samples)
|
||||
one-hot encoded class labels.
|
||||
output : array, shape = [n_output_units, n_samples]
|
||||
Activation of the output layer (feedforward)
|
||||
w1 : array, shape = [n_hidden_units, n_features]
|
||||
Weight matrix for input layer -> hidden layer.
|
||||
w2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Weight matrix for hidden layer -> output layer.
|
||||
|
||||
Returns
|
||||
---------
|
||||
cost : float
|
||||
Regularized cost.
|
||||
|
||||
"""
|
||||
term1 = -y_enc * (np.log(output))
|
||||
term2 = (1 - y_enc) * np.log(1 - output)
|
||||
cost = np.sum(term1 - term2)
|
||||
L1_term = self._L1_reg(self.l1, w1, w2)
|
||||
L2_term = self._L2_reg(self.l2, w1, w2)
|
||||
cost = cost + L1_term + L2_term
|
||||
return cost
|
||||
|
||||
def _get_gradient(self, a1, a2, a3, z2, y_enc, w1, w2):
|
||||
""" Compute gradient step using backpropagation.
|
||||
|
||||
Parameters
|
||||
------------
|
||||
a1 : array, shape = [n_samples, n_features+1]
|
||||
Input values with bias unit.
|
||||
a2 : array, shape = [n_hidden+1, n_samples]
|
||||
Activation of hidden layer.
|
||||
a3 : array, shape = [n_output_units, n_samples]
|
||||
Activation of output layer.
|
||||
z2 : array, shape = [n_hidden, n_samples]
|
||||
Net input of hidden layer.
|
||||
y_enc : array, shape = (n_labels, n_samples)
|
||||
one-hot encoded class labels.
|
||||
w1 : array, shape = [n_hidden_units, n_features]
|
||||
Weight matrix for input layer -> hidden layer.
|
||||
w2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Weight matrix for hidden layer -> output layer.
|
||||
|
||||
Returns
|
||||
---------
|
||||
grad1 : array, shape = [n_hidden_units, n_features]
|
||||
Gradient of the weight matrix w1.
|
||||
grad2 : array, shape = [n_output_units, n_hidden_units]
|
||||
Gradient of the weight matrix w2.
|
||||
|
||||
"""
|
||||
# backpropagation
|
||||
sigma3 = a3 - y_enc
|
||||
z2 = self._add_bias_unit(z2, how='row')
|
||||
sigma2 = w2.T.dot(sigma3) * self._sigmoid_gradient(z2)
|
||||
sigma2 = sigma2[1:, :]
|
||||
grad1 = sigma2.dot(a1)
|
||||
grad2 = sigma3.dot(a2.T)
|
||||
|
||||
# regularize
|
||||
grad1[:, 1:] += (w1[:, 1:] * (self.l1 + self.l2))
|
||||
grad2[:, 1:] += (w2[:, 1:] * (self.l1 + self.l2))
|
||||
|
||||
return grad1, grad2
|
||||
|
||||
def _gradient_checking(self, X, y_enc, w1, w2, epsilon, grad1, grad2):
|
||||
""" Apply gradient checking (for debugging only)
|
||||
|
||||
Returns
|
||||
---------
|
||||
relative_error : float
|
||||
Relative error between the numerically
|
||||
approximated gradients and the backpropagated gradients.
|
||||
|
||||
"""
|
||||
num_grad1 = np.zeros(np.shape(w1))
|
||||
epsilon_ary1 = np.zeros(np.shape(w1))
|
||||
for i in range(w1.shape[0]):
|
||||
for j in range(w1.shape[1]):
|
||||
epsilon_ary1[i, j] = epsilon
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X,
|
||||
w1 - epsilon_ary1, w2)
|
||||
cost1 = self._get_cost(y_enc, a3, w1-epsilon_ary1, w2)
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X,
|
||||
w1 + epsilon_ary1, w2)
|
||||
cost2 = self._get_cost(y_enc, a3, w1 + epsilon_ary1, w2)
|
||||
num_grad1[i, j] = (cost2 - cost1) / (2 * epsilon)
|
||||
epsilon_ary1[i, j] = 0
|
||||
|
||||
num_grad2 = np.zeros(np.shape(w2))
|
||||
epsilon_ary2 = np.zeros(np.shape(w2))
|
||||
for i in range(w2.shape[0]):
|
||||
for j in range(w2.shape[1]):
|
||||
epsilon_ary2[i, j] = epsilon
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X, w1,
|
||||
w2 - epsilon_ary2)
|
||||
cost1 = self._get_cost(y_enc, a3, w1, w2 - epsilon_ary2)
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X, w1,
|
||||
w2 + epsilon_ary2)
|
||||
cost2 = self._get_cost(y_enc, a3, w1, w2 + epsilon_ary2)
|
||||
num_grad2[i, j] = (cost2 - cost1) / (2 * epsilon)
|
||||
epsilon_ary2[i, j] = 0
|
||||
|
||||
num_grad = np.hstack((num_grad1.flatten(), num_grad2.flatten()))
|
||||
grad = np.hstack((grad1.flatten(), grad2.flatten()))
|
||||
norm1 = np.linalg.norm(num_grad - grad)
|
||||
norm2 = np.linalg.norm(num_grad)
|
||||
norm3 = np.linalg.norm(grad)
|
||||
relative_error = norm1 / (norm2 + norm3)
|
||||
return relative_error
|
||||
|
||||
def predict(self, X):
|
||||
"""Predict class labels
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
X : array, shape = [n_samples, n_features]
|
||||
Input layer with original features.
|
||||
|
||||
Returns:
|
||||
----------
|
||||
y_pred : array, shape = [n_samples]
|
||||
Predicted class labels.
|
||||
|
||||
"""
|
||||
if len(X.shape) != 2:
|
||||
raise AttributeError('X must be a [n_samples, n_features] array.\n'
|
||||
'Use X[:,None] for 1-feature classification,'
|
||||
'\nor X[[i]] for 1-sample classification')
|
||||
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X, self.w1, self.w2)
|
||||
y_pred = np.argmax(z3, axis=0)
|
||||
return y_pred
|
||||
|
||||
def fit(self, X, y, print_progress=False):
|
||||
""" Learn weights from training data.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
X : array, shape = [n_samples, n_features]
|
||||
Input layer with original features.
|
||||
y : array, shape = [n_samples]
|
||||
Target class labels.
|
||||
print_progress : bool (default: False)
|
||||
Prints progress as the number of epochs
|
||||
to stderr.
|
||||
|
||||
Returns:
|
||||
----------
|
||||
self
|
||||
|
||||
"""
|
||||
self.cost_ = []
|
||||
X_data, y_data = X.copy(), y.copy()
|
||||
y_enc = self._encode_labels(y, self.n_output)
|
||||
|
||||
delta_w1_prev = np.zeros(self.w1.shape)
|
||||
delta_w2_prev = np.zeros(self.w2.shape)
|
||||
|
||||
for i in range(self.epochs):
|
||||
|
||||
# adaptive learning rate
|
||||
self.eta /= (1 + self.decrease_const*i)
|
||||
|
||||
if print_progress:
|
||||
sys.stderr.write('\rEpoch: %d/%d' % (i+1, self.epochs))
|
||||
sys.stderr.flush()
|
||||
|
||||
if self.shuffle:
|
||||
idx = np.random.permutation(y_data.shape[0])
|
||||
X_data, y_enc = X_data[idx], y_enc[idx]
|
||||
|
||||
mini = np.array_split(range(y_data.shape[0]), self.minibatches)
|
||||
for idx in mini:
|
||||
|
||||
# feedforward
|
||||
a1, z2, a2, z3, a3 = self._feedforward(X[idx],
|
||||
self.w1,
|
||||
self.w2)
|
||||
cost = self._get_cost(y_enc=y_enc[:, idx],
|
||||
output=a3,
|
||||
w1=self.w1,
|
||||
w2=self.w2)
|
||||
self.cost_.append(cost)
|
||||
|
||||
# compute gradient via backpropagation
|
||||
grad1, grad2 = self._get_gradient(a1=a1, a2=a2,
|
||||
a3=a3, z2=z2,
|
||||
y_enc=y_enc[:, idx],
|
||||
w1=self.w1,
|
||||
w2=self.w2)
|
||||
|
||||
# start gradient checking
|
||||
grad_diff = self._gradient_checking(X=X_data[idx],
|
||||
y_enc=y_enc[:, idx],
|
||||
w1=self.w1,
|
||||
w2=self.w2,
|
||||
epsilon=1e-5,
|
||||
grad1=grad1,
|
||||
grad2=grad2)
|
||||
|
||||
if grad_diff <= 1e-7:
|
||||
print('Ok: %s' % grad_diff)
|
||||
elif grad_diff <= 1e-4:
|
||||
print('Warning: %s' % grad_diff)
|
||||
else:
|
||||
print('PROBLEM: %s' % grad_diff)
|
||||
|
||||
# update weights; [alpha * delta_w_prev] for momentum learning
|
||||
delta_w1, delta_w2 = self.eta * grad1, self.eta * grad2
|
||||
self.w1 -= (delta_w1 + (self.alpha * delta_w1_prev))
|
||||
self.w2 -= (delta_w2 + (self.alpha * delta_w2_prev))
|
||||
delta_w1_prev, delta_w2_prev = delta_w1, delta_w2
|
||||
|
||||
return self
|
||||
|
||||
|
||||
nn_check = MLPGradientCheck(n_output=10,
|
||||
n_features=X_train.shape[1],
|
||||
n_hidden=10,
|
||||
l2=0.0,
|
||||
l1=0.0,
|
||||
epochs=10,
|
||||
eta=0.001,
|
||||
alpha=0.0,
|
||||
decrease_const=0.0,
|
||||
minibatches=1,
|
||||
shuffle=False,
|
||||
random_state=1)
|
||||
|
||||
nn_check.fit(X_train[:5], y_train[:5], print_progress=False)
|
||||
@@ -0,0 +1,424 @@
|
||||
# Sebastian Raschka, 2015 (http://sebastianraschka.com)
|
||||
# Python Machine Learning - Code Examples
|
||||
#
|
||||
# Chapter 13 - Parallelizing Neural Network Training with Theano
|
||||
#
|
||||
# S. Raschka. Python Machine Learning. Packt Publishing Ltd., 2015.
|
||||
# GitHub Repo: https://github.com/rasbt/python-machine-learning-book
|
||||
#
|
||||
# License: MIT
|
||||
# https://github.com/rasbt/python-machine-learning-book/blob/master/LICENSE.txt
|
||||
|
||||
import os
|
||||
import theano
|
||||
from theano import tensor as T
|
||||
import numpy as np
|
||||
import struct
|
||||
import matplotlib.pyplot as plt
|
||||
from keras.utils import np_utils
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense
|
||||
from keras.optimizers import SGD
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('First steps with Theano')
|
||||
print(50 * '-')
|
||||
|
||||
# initialize
|
||||
x1 = T.scalar()
|
||||
w1 = T.scalar()
|
||||
w0 = T.scalar()
|
||||
z1 = w1 * x1 + w0
|
||||
|
||||
# compile
|
||||
net_input = theano.function(inputs=[w1, x1, w0], outputs=z1)
|
||||
|
||||
# execute
|
||||
net_input(2.0, 1.0, 0.5)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Configuring Theano')
|
||||
print(50 * '-')
|
||||
|
||||
print('theano.config.floatX', theano.config.floatX)
|
||||
theano.config.floatX = 'float32'
|
||||
|
||||
print('print(theano.config.device)', print(theano.config.device))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Working with array structures')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
# initialize
|
||||
# if you are running Theano on 64 bit mode,
|
||||
# you need to use dmatrix instead of fmatrix
|
||||
x = T.fmatrix(name='x')
|
||||
x_sum = T.sum(x, axis=0)
|
||||
|
||||
# compile
|
||||
calc_sum = theano.function(inputs=[x], outputs=x_sum)
|
||||
|
||||
# execute (Python list)
|
||||
ary = [[1, 2, 3], [1, 2, 3]]
|
||||
print('Column sum:', calc_sum(ary))
|
||||
|
||||
# execute (NumPy array)
|
||||
ary = np.array([[1, 2, 3], [1, 2, 3]], dtype=theano.config.floatX)
|
||||
print('Column sum:', calc_sum(ary))
|
||||
|
||||
|
||||
# initialize
|
||||
x = T.fmatrix(name='x')
|
||||
w = theano.shared(np.asarray([[0.0, 0.0, 0.0]],
|
||||
dtype=theano.config.floatX))
|
||||
z = x.dot(w.T)
|
||||
update = [[w, w + 1.0]]
|
||||
|
||||
# compile
|
||||
net_input = theano.function(inputs=[x],
|
||||
updates=update,
|
||||
outputs=z)
|
||||
|
||||
# execute
|
||||
data = np.array([[1, 2, 3]], dtype=theano.config.floatX)
|
||||
for i in range(5):
|
||||
print('z%d:' % i, net_input(data))
|
||||
|
||||
|
||||
"""
|
||||
We can use the `givens` variable to insert values into the graph
|
||||
before compiling it. Using this approach we can reduce the number
|
||||
of transfers from RAM (via CPUs) to GPUs to speed up learning with
|
||||
shared variables. If we use `inputs`, a datasets is transferred from
|
||||
the CPU to the GPU multiple times, for example, if we iterate over a
|
||||
dataset multiple times (epochs) during gradient descent. Via `givens`,
|
||||
we can keep the dataset on the GPU if it fits (e.g., a mini-batch).
|
||||
"""
|
||||
|
||||
# initialize
|
||||
data = np.array([[1, 2, 3]],
|
||||
dtype=theano.config.floatX)
|
||||
x = T.fmatrix(name='x')
|
||||
w = theano.shared(np.asarray([[0.0, 0.0, 0.0]],
|
||||
dtype=theano.config.floatX))
|
||||
z = x.dot(w.T)
|
||||
update = [[w, w + 1.0]]
|
||||
|
||||
# compile
|
||||
net_input = theano.function(inputs=[],
|
||||
updates=update,
|
||||
givens={x: data},
|
||||
outputs=z)
|
||||
|
||||
# execute
|
||||
for i in range(5):
|
||||
print('z:', net_input())
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Wrapping things up: A linear regression example')
|
||||
print(50 * '-')
|
||||
|
||||
X_train = np.asarray([[0.0], [1.0], [2.0], [3.0], [4.0],
|
||||
[5.0], [6.0], [7.0], [8.0], [9.0]],
|
||||
dtype=theano.config.floatX)
|
||||
|
||||
y_train = np.asarray([1.0, 1.3, 3.1, 2.0, 5.0,
|
||||
6.3, 6.6, 7.4, 8.0, 9.0],
|
||||
dtype=theano.config.floatX)
|
||||
|
||||
|
||||
def train_linreg(X_train, y_train, eta, epochs):
|
||||
|
||||
costs = []
|
||||
# Initialize arrays
|
||||
eta0 = T.fscalar('eta0')
|
||||
y = T.fvector(name='y')
|
||||
X = T.fmatrix(name='X')
|
||||
w = theano.shared(np.zeros(
|
||||
shape=(X_train.shape[1] + 1),
|
||||
dtype=theano.config.floatX),
|
||||
name='w')
|
||||
|
||||
# calculate cost
|
||||
net_input = T.dot(X, w[1:]) + w[0]
|
||||
errors = y - net_input
|
||||
cost = T.sum(T.pow(errors, 2))
|
||||
|
||||
# perform gradient update
|
||||
gradient = T.grad(cost, wrt=w)
|
||||
update = [(w, w - eta0 * gradient)]
|
||||
|
||||
# compile model
|
||||
train = theano.function(inputs=[eta0],
|
||||
outputs=cost,
|
||||
updates=update,
|
||||
givens={X: X_train,
|
||||
y: y_train})
|
||||
|
||||
for _ in range(epochs):
|
||||
costs.append(train(eta))
|
||||
|
||||
return costs, w
|
||||
|
||||
|
||||
costs, w = train_linreg(X_train, y_train, eta=0.001, epochs=10)
|
||||
|
||||
plt.plot(range(1, len(costs) + 1), costs)
|
||||
|
||||
plt.tight_layout()
|
||||
plt.xlabel('Epoch')
|
||||
plt.ylabel('Cost')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/cost_convergence.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
def predict_linreg(X, w):
|
||||
Xt = T.matrix(name='X')
|
||||
net_input = T.dot(Xt, w[1:]) + w[0]
|
||||
predict = theano.function(inputs=[Xt], givens={w: w}, outputs=net_input)
|
||||
return predict(X)
|
||||
|
||||
|
||||
plt.scatter(X_train, y_train, marker='s', s=50)
|
||||
plt.plot(range(X_train.shape[0]),
|
||||
predict_linreg(X_train, w),
|
||||
color='gray',
|
||||
marker='o',
|
||||
markersize=4,
|
||||
linewidth=3)
|
||||
|
||||
plt.xlabel('x')
|
||||
plt.ylabel('y')
|
||||
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/linreg.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Wrapping things up: A linear regression example')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
# note that first element (X[0] = 1) to denote bias unit
|
||||
|
||||
X = np.array([[1, 1.4, 1.5]])
|
||||
w = np.array([0.0, 0.2, 0.4])
|
||||
|
||||
|
||||
def net_input(X, w):
|
||||
z = X.dot(w)
|
||||
return z
|
||||
|
||||
|
||||
def logistic(z):
|
||||
return 1.0 / (1.0 + np.exp(-z))
|
||||
|
||||
|
||||
def logistic_activation(X, w):
|
||||
z = net_input(X, w)
|
||||
return logistic(z)
|
||||
|
||||
|
||||
print('P(y=1|x) = %.3f' % logistic_activation(X, w)[0])
|
||||
|
||||
|
||||
# W : array, shape = [n_output_units, n_hidden_units+1]
|
||||
# Weight matrix for hidden layer -> output layer.
|
||||
# note that first column (A[:][0] = 1) are the bias units
|
||||
W = np.array([[1.1, 1.2, 1.3, 0.5],
|
||||
[0.1, 0.2, 0.4, 0.1],
|
||||
[0.2, 0.5, 2.1, 1.9]])
|
||||
|
||||
# A : array, shape = [n_hidden+1, n_samples]
|
||||
# Activation of hidden layer.
|
||||
# note that first element (A[0][0] = 1) is for the bias units
|
||||
|
||||
A = np.array([[1.0],
|
||||
[0.1],
|
||||
[0.3],
|
||||
[0.7]])
|
||||
|
||||
# Z : array, shape = [n_output_units, n_samples]
|
||||
# Net input of output layer.
|
||||
|
||||
Z = W.dot(A)
|
||||
y_probas = logistic(Z)
|
||||
print('Probabilities:\n', y_probas)
|
||||
|
||||
y_class = np.argmax(Z, axis=0)
|
||||
print('predicted class label: %d' % y_class[0])
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Estimating probabilities in multi-class'
|
||||
' classification via the softmax function')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def softmax(z):
|
||||
return np.exp(z) / np.sum(np.exp(z))
|
||||
|
||||
|
||||
def softmax_activation(X, w):
|
||||
z = net_input(X, w)
|
||||
return softmax(z)
|
||||
|
||||
|
||||
y_probas = softmax(Z)
|
||||
print('Probabilities:\n', y_probas)
|
||||
|
||||
print('Sum of probabilities', y_probas.sum())
|
||||
|
||||
y_class = np.argmax(Z, axis=0)
|
||||
print('Predicted class', y_class)
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Broadening the output spectrum using a hyperbolic tangent')
|
||||
print(50 * '-')
|
||||
|
||||
|
||||
def tanh(z):
|
||||
e_p = np.exp(z)
|
||||
e_m = np.exp(-z)
|
||||
return (e_p - e_m) / (e_p + e_m)
|
||||
|
||||
|
||||
z = np.arange(-5, 5, 0.005)
|
||||
log_act = logistic(z)
|
||||
tanh_act = tanh(z)
|
||||
|
||||
# alternatives:
|
||||
# from scipy.special import expit
|
||||
# log_act = expit(z)
|
||||
# tanh_act = np.tanh(z)
|
||||
|
||||
plt.ylim([-1.5, 1.5])
|
||||
plt.xlabel('net input $z$')
|
||||
plt.ylabel('activation $\phi(z)$')
|
||||
plt.axhline(1, color='black', linestyle='--')
|
||||
plt.axhline(0.5, color='black', linestyle='--')
|
||||
plt.axhline(0, color='black', linestyle='--')
|
||||
plt.axhline(-1, color='black', linestyle='--')
|
||||
|
||||
plt.plot(z, tanh_act,
|
||||
linewidth=2,
|
||||
color='black',
|
||||
label='tanh')
|
||||
plt.plot(z, log_act,
|
||||
linewidth=2,
|
||||
color='lightgreen',
|
||||
label='logistic')
|
||||
|
||||
plt.legend(loc='lower right')
|
||||
# plt.tight_layout()
|
||||
# plt.savefig('./figures/activation.png', dpi=300)
|
||||
plt.show()
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Broadening the output spectrum using a hyperbolic tangent')
|
||||
print(50 * '-')
|
||||
|
||||
_ = input("Please make sure that you've downloaded and unzipped the"
|
||||
" MNIST dataset as described in the previous chapter. The following"
|
||||
" code assumes that you have created a mnist directory within"
|
||||
" this script's directory. Please hit 'enter' to continue.")
|
||||
|
||||
|
||||
def load_mnist(path, kind='train'):
|
||||
"""Load MNIST data from `path`"""
|
||||
labels_path = os.path.join(path,
|
||||
'%s-labels-idx1-ubyte' % kind)
|
||||
images_path = os.path.join(path,
|
||||
'%s-images-idx3-ubyte'
|
||||
% kind)
|
||||
|
||||
with open(labels_path, 'rb') as lbpath:
|
||||
magic, n = struct.unpack('>II',
|
||||
lbpath.read(8))
|
||||
labels = np.fromfile(lbpath,
|
||||
dtype=np.uint8)
|
||||
|
||||
with open(images_path, 'rb') as imgpath:
|
||||
magic, num, rows, cols = struct.unpack(">IIII",
|
||||
imgpath.read(16))
|
||||
images = np.fromfile(imgpath,
|
||||
dtype=np.uint8).reshape(len(labels), 784)
|
||||
|
||||
return images, labels
|
||||
|
||||
|
||||
X_train, y_train = load_mnist('mnist', kind='train')
|
||||
print('Training rows: %d, columns: %d' % (X_train.shape[0], X_train.shape[1]))
|
||||
|
||||
X_test, y_test = load_mnist('mnist', kind='t10k')
|
||||
print('Test rows: %d, columns: %d' % (X_test.shape[0], X_test.shape[1]))
|
||||
|
||||
|
||||
#############################################################################
|
||||
print(50 * '=')
|
||||
print('Multi-layer Perceptron in Keras')
|
||||
print(50 * '-')
|
||||
|
||||
theano.config.floatX = 'float32'
|
||||
X_train = X_train.astype(theano.config.floatX)
|
||||
X_test = X_test.astype(theano.config.floatX)
|
||||
|
||||
print('First 3 labels: ', y_train[:3])
|
||||
|
||||
y_train_ohe = np_utils.to_categorical(y_train)
|
||||
print('\nFirst 3 labels (one-hot):\n', y_train_ohe[:3])
|
||||
|
||||
np.random.seed(1)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(input_dim=X_train.shape[1],
|
||||
output_dim=50,
|
||||
init='uniform',
|
||||
activation='tanh'))
|
||||
|
||||
model.add(Dense(input_dim=50,
|
||||
output_dim=50,
|
||||
init='uniform',
|
||||
activation='tanh'))
|
||||
|
||||
model.add(Dense(input_dim=50,
|
||||
output_dim=y_train_ohe.shape[1],
|
||||
init='uniform',
|
||||
activation='softmax'))
|
||||
|
||||
sgd = SGD(lr=0.001, decay=1e-7, momentum=.9)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=sgd)
|
||||
|
||||
model.fit(X_train, y_train_ohe,
|
||||
nb_epoch=50,
|
||||
batch_size=300,
|
||||
verbose=1,
|
||||
validation_split=0.1,
|
||||
show_accuracy=True)
|
||||
|
||||
y_train_pred = model.predict_classes(X_train, verbose=0)
|
||||
print('First 3 predictions: ', y_train_pred[:3])
|
||||
|
||||
train_acc = np.sum(y_train == y_train_pred, axis=0) / X_train.shape[0]
|
||||
print('Training accuracy: %.2f%%' % (train_acc * 100))
|
||||
|
||||
y_test_pred = model.predict_classes(X_test, verbose=0)
|
||||
test_acc = np.sum(y_test == y_test_pred, axis=0) / X_test.shape[0]
|
||||
print('Test accuracy: %.2f%%' % (test_acc * 100))
|
||||
Reference in New Issue
Block a user