Tuesday, April 12, 2022

Dive into linear regression via gradient descent Python

 Линейная регрессия с использованием градиентного спуска

Градиентный спуск — один из наиболее распространенных методов, используемых для оптимизации различных выпуклых функций в машинном обучении. Поскольку мы знаем, что функция стоимости аналогична функции стоимости (с разницей в 1/2 раза), данной в методе наименьших квадратов, мы будем использовать градиентный спуск для решения проблемы. Мы должны минимизировать функцию стоимости, чтобы найти значение Theta на линии регрессии.

Метод градиентного спуска можно представить следующим образом:

































*******

Code 1

*******

(.env) [boris@fedora35server LINEAREGRS]$ cat gradientDesc1.py

import numpy as np

from matplotlib import pyplot as plt

from PIL import Image

# Function for cost function

def cost(z,theta,y):

    m,n=z.shape;

    htheta = z.dot(theta.transpose())

    cost = ((htheta - y)**2).sum()/(2.0 * m)

    return cost;


def gradient_descent(z,theta,alpha,y,itr):

    cost_arr=[]

    m,n=z.shape;

    count=0;

    htheta = z.dot(theta.transpose())

    while count<itr:

        htheta = z.dot(theta.transpose())

        a=(alpha/m)

        # Using temporary variables for simultaneous updation of variables

        temp0=theta[0,0]-a*(htheta-y).sum();

        temp1=theta[0,1]-a*((htheta-y)*(z[::,1:])).sum();

        theta[0,0]=temp0;

        theta[0,1]=temp1;

        cost_arr.append(float(cost(z,theta,y)));

        count+=1;

    cost_log = np.array(cost_arr);

    plt.plot(np.linspace(0, itr, itr, endpoint=True), cost_log)

    plt.xlabel("No. of iterations")

    plt.ylabel("Error Function value")

    # plt.show()

    fig = plt.gcf()

    fig.savefig('fig1.jpg')

    return theta;


x = np.array([[0], [1],[2], [3], [4], [5], [6], [7], [8], [9]]) 

y = np.array([[11], [13], [12], [15], [17], [18], [18], [19], [20], [22]]) 

m,n=x.shape;

z=np.ones((m,n+1),dtype=int);

z[::,1:]=x;

theta=np.array([[21,2]],dtype=float)

theta_minimised=gradient_descent(z,theta,0.01,y,10000)

print("theta_minimised =",theta_minimised)

new_x=np.array([1,11])

predicted_y=new_x.dot(theta_minimised.transpose())

print(round(predicted_y[0],4))

im = Image.open('fig1.jpg')

im.show()
















Код из https://www.educative.io/edpresso/a-deep-dive-into-linear-regression-3-way-implementation

изменен ( не прнинципиально, мне так удобней )




dive into linear regression (3-way implementation) Python

 Code 1

(.env) [boris@fedora35server LINEAREGRS]$ cat linearRegr1.py

import numpy as np 

import matplotlib.pyplot as plt 

def estimate_coef(x, y): 

    n = np.size(x) 

    m_x, m_y = np.mean(x), np.mean(y) 

    SS_xy = np.sum(y*x) - n*m_y*m_x 

    SS_xx = np.sum(x*x) - n*m_x*m_x 

    theta_1 = SS_xy / SS_xx 

    theta_0 = m_y - theta_1*m_x 

    return(theta_0, theta_1) 

def plot_regression_line(x, y, theta): 

    plt.scatter(x, y, color = "b",marker = "o", s = 30) 

    y_pred = theta[0] + theta[1]*x 

    plt.plot(x, y_pred, color = "r") 

    plt.xlabel('x') 

    plt.ylabel('y') 

    plt.show() 

x = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

y = np.array([11 ,13, 12, 15, 17, 18, 18, 19, 20, 22]) 

theta = estimate_coef(x, y) 

print("Estimated coefficients:\ntheta_0 = {} \ntheta_1 = {}".format(theta[0], theta[1])) 

plot_regression_line(x, y, theta) 

print(round(theta[0]+ theta[1]*11,4))
































References

Monday, April 11, 2022

Cross-validation: evaluating estimator performance

 При оценке различных настроек («гиперпараметров») для оценщиков, таких как параметр C, который должен быть установлен вручную для SVM, все еще существует риск переобучения в тестовом наборе, поскольку параметры можно настраивать до тех пор, пока оценщик не будет работать оптимально. Таким образом, знания о тестовом наборе могут «просочиться» в модель, а метрики оценки больше не сообщают о производительности обобщения. Чтобы решить эту проблему, еще одна часть набора данных может быть представлена ​​в виде так называемого «проверочного набора»: обучение продолжается на обучающем наборе, после чего выполняется оценка на проверочном наборе, и когда эксперимент кажется успешным , окончательную оценку можно выполнить на тестовом наборе.

Однако, разбивая доступные данные на три набора, мы резко сокращаем количество выборок, которые можно использовать для обучения модели, а результаты могут зависеть от конкретного случайного выбора пары наборов (обучение, проверка).

Решением этой проблемы является процедура, называемая перекрестной проверкой (сокращенно CV). Тестовый набор по-прежнему должен храниться для окончательной оценки, но проверочный набор больше не нужен при выполнении CV. В базовом подходе, называемом k-fold CV, обучающая выборка разбивается на k меньших наборов (другие подходы описаны ниже, но в целом следуют тем же принципам). Для каждой из k «складок» выполняется следующая процедура:

Модель обучается с использованием складок в качестве обучающих данных;

полученная модель проверяется на оставшейся части данных (т. Е. Она используется в качестве тестового набора для вычисления показателя производительности, такого как точность).

Мера производительности, о которой сообщает k-кратная перекрестная проверка, представляет собой среднее значение значений, вычисленных в цикле. Этот подход может быть дорогостоящим в вычислительном отношении, но не тратит слишком много данных (как в случае фиксации произвольного набора проверки), что является большим преимуществом в таких задачах, как обратный вывод, когда количество выборок очень мало.






















Самый простой способ использовать перекрестную проверку — вызвать вспомогательную функцию cross_val_score для оценщика и набора данных.
В следующем примере показано, как оценить точность линейной машины опорных векторов ядра в наборе данных радужной оболочки путем разделения данных, подгонки модели и вычисления оценки 5 раз подряд (каждый раз с разными разделениями):

(.env) [boris@fedora35server CROSSVL]$ cat crossVal1.py
from sklearn.model_selection import cross_val_score
from sklearn import svm
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import datasets


X, y = datasets.load_iris(return_X_y=True)
clf = svm.SVC(kernel='linear', C=1, random_state=42)
scores = cross_val_score(clf, X, y, cv=5)
print("%0.2f accuracy with a standard deviation of %0.2f" % (scores.mean(), scores.std()))

(.env) [boris@fedora35server CROSSVL]$ python crossVal1.py
0.98 accuracy with a standard deviation of 0.02






























Другой пример

(.env) [boris@fedora35server CROSSVL]$ cat crossVal2.py
import pandas as pd
import numpy as np
from sklearn.metrics import accuracy_score, confusion_matrix
from sklearn.ensemble import RandomForestClassifier
from sklearn import svm
from sklearn.model_selection import cross_val_score

#read csv file
data  =  pd.read_csv("./Iris.csv")
#Create Dependent and Independent Datasets based on our Dependent #and Independent features
X  = data[['SepalLengthCm','SepalWidthCm','PetalLengthCm']]
y= data['Species']
model = svm.SVC()
accuracy = cross_val_score(model, X, y, scoring='accuracy', cv = 10)
print(accuracy)

#get the mean of each fold 
print("Accuracy of Model with Cross Validation is:",accuracy.mean() * 100)

(.env) [boris@fedora35server CROSSVL]$ python crossVal2.py
[0.93333333 0.93333333 1.         1.         0.93333333 0.8
 0.93333333 0.93333333 1.         1.        ]
Accuracy of Model with Cross Validation is: 94.66666666666667






















Таким образом, перекрестная проверка — это процедура, используемая для предотвращения переобучения и оценки навыков модели на новых данных.
Существуют общие тактики, которые вы можете использовать для выбора значения k для вашего набора данных.
Существуют часто используемые варианты перекрестной проверки, такие как послойная и повторная, которые доступны в scikit-learn.

References





Friday, April 8, 2022

Save and Load Machine Learning Models in Python with scikit-learn

*********** 

Code 1

***********

(.env) [boris@fedora34server SAVEMODEL]$ cat savePikle.py

# Save Model Using Pickle

import pandas

from sklearn import model_selection

from sklearn.linear_model import LogisticRegression

import pickle

url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"

names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']

dataframe = pandas.read_csv(url, names=names)

array = dataframe.values

X = array[:,0:8]

Y = array[:,8]

test_size = 0.33

seed = 7

X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, Y, test_size=test_size, random_state=seed)

# Fit the model on training set

model = LogisticRegression(solver='lbfgs', max_iter=300)

model.fit(X_train, Y_train)

# save the model to disk

filename = 'finalized_model.sav'

pickle.dump(model, open(filename, 'wb'))

# some time later...

# load the model from disk

loaded_model = pickle.load(open(filename, 'rb'))

result = loaded_model.score(X_test, Y_test)

print(result)


(.env) [boris@fedora34server SAVEMODEL]$ python savePikle.py

0.7874015748031497


**********

Code 2

**********
(.env) [boris@fedora34server SAVEMODEL]$ cat saveJoblib.py

# Save Model Using joblib
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
import joblib
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']

dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
test_size = 0.33
seed = 7

X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, Y, test_size=test_size, random_state=seed)

# Fit the model on training set
model = LogisticRegression(solver='lbfgs', max_iter=300)
model.fit(X_train, Y_train)

# save the model to disk
filename = 'finalized_model.sav'
joblib.dump(model, filename)
 
# some time later...
 
# load the model from disk
loaded_model = joblib.load(filename)
result = loaded_model.score(X_test, Y_test)
print(result)

(.env) [boris@fedora34server SAVEMODEL]$ python saveJoblib.py
0.7874015748031497

*********************************
Loading from another python script
*********************************
(.env) [boris@fedora34server SAVEMODEL]$ cat loadPikle.py
import pandas
from sklearn import model_selection
from sklearn.linear_model import LogisticRegression
import pickle
url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/pima-indians-diabetes.data.csv"
names = ['preg', 'plas', 'pres', 'skin', 'test', 'mass', 'pedi', 'age', 'class']
dataframe = pandas.read_csv(url, names=names)
array = dataframe.values
X = array[:,0:8]
Y = array[:,8]
test_size = 0.33
seed = 7
X_train, X_test, Y_train, Y_test = model_selection.train_test_split(X, Y, test_size=test_size, random_state=seed)

######################################
# Skipping model creating and training
# Dumping to file already has been done
######################################

filename = 'finalized_model.sav'
# load the model from disk
loaded_model = pickle.load(open(filename, 'rb'))
result = loaded_model.score(X_test, Y_test)
print(result)

(.env) [boris@fedora34server SAVEMODEL]$ python loadPikle.py
0.7874015748031497




























Thursday, April 7, 2022

PyTorch: Defining new autograd functions

**********

Code 1 

**********

(.env) [boris@fedora34server PYTORCH]$ cat pyTorch3.py

"""

PyTorch: Defining new autograd functions

----------------------------------------

A fully-connected ReLU network with one hidden layer and no biases, trained to

predict y from x by minimizing squared Euclidean distance.

This implementation computes the forward pass using operations on PyTorch

Variables, and uses PyTorch autograd to compute gradients.

In this implementation we implement our own custom autograd function to perform

the ReLU function.

"""

import torch

from torch.autograd import Variable


class MyReLU(torch.autograd.Function):

    """

    We can implement our own custom autograd Functions by subclassing

    torch.autograd.Function and implementing the forward and backward passes

    which operate on Tensors.

    """

    @staticmethod

    def forward(self, input):

        """

        In the forward pass we receive a Tensor containing the input and return a

        Tensor containing the output. You can cache arbitrary Tensors for use in the

        backward pass using the save_for_backward method.

        """

        self.save_for_backward(input)

        return input.clamp(min=0)


    @staticmethod

    def backward(self, grad_output):

        """

        In the backward pass we receive a Tensor containing the gradient of the loss

        with respect to the output, and we need to compute the gradient of the loss

        with respect to the input.

        """

        input, = self.saved_tensors

        grad_input = grad_output.clone()

        grad_input[input < 0] = 0

        return grad_input

dtype = torch.FloatTensor

# dtype = torch.cuda.FloatTensor # Uncomment this to run on GPU

# N is batch size; D_in is input dimension;

# H is hidden dimension; D_out is output dimension.

N, D_in, H, D_out = 64, 1000, 100, 10

# Create random Tensors to hold input and outputs, and wrap them in Variables.

x = Variable(torch.randn(N, D_in).type(dtype), requires_grad=False)

y = Variable(torch.randn(N, D_out).type(dtype), requires_grad=False)


# Create random Tensors for weights, and wrap them in Variables.

w1 = Variable(torch.randn(D_in, H).type(dtype), requires_grad=True)

w2 = Variable(torch.randn(H, D_out).type(dtype), requires_grad=True)

learning_rate = 1e-6

for t in range(500):

    # Construct an instance of our MyReLU class to use in our network

    relu = MyReLU.apply

    # Forward pass: compute predicted y using operations on Variables; we compute

    # ReLU using our custom autograd operation.

    y_pred = relu(x.mm(w1)).mm(w2)

    # Compute and print loss

    loss = (y_pred - y).pow(2).sum()

    print(t, "loss.item()) = ",loss.item())

    # Use autograd to compute the backward pass.

    loss.backward()

    # Update weights using gradient descent

    w1.data -= learning_rate * w1.grad.data

    w2.data -= learning_rate * w2.grad.data

    # Manually zero the gradients after updating weights

    w1.grad.data.zero_()

    w2.grad.data.zero_()



























































Неработающий код можно посмотреть здесь

Полносвязная сеть ReLU с одним скрытым слоем и без смещений, обученная предсказывать y по x путем минимизации квадрата евклидова расстояния.

Эта реализация вычисляет прямой проход, используя операции с переменными PyTorch, и использует автоградацию PyTorch для вычисления градиентов.

Переменная PyTorch представляет собой оболочку вокруг тензора PyTorch и представляет узел в вычислительном графе. Если x — переменная, то x.data — это тензор, задающий свое значение, а x.grad — другая переменная, содержащая градиент x по отношению к некоторому скалярному значению.

PyTorch Variables имеют тот же API, что и тензоры PyTorch: (почти) любую операцию, которую вы можете выполнять с тензором, вы также можете выполнять с переменной; разница в том, что autograd позволяет автоматически вычислять градиенты.

**************

Code 1

**************

 (.env) [boris@fedora34server PYTORCH]$ cat pyTorch1.py

import torch

from torch.autograd import Variable

dtype = torch.FloatTensor

# dtype = torch.cuda.FloatTensor # Uncomment this to run on GPU

# N is batch size; D_in is input dimension;

# H is hidden dimension; D_out is output dimension.

N, D_in, H, D_out = 64, 1000, 100, 10

# Create random Tensors to hold input and outputs, and wrap them in Variables.

# Setting requires_grad=False indicates that we do not need to compute gradients

# with respect to these Variables during the backward pass.

x = Variable(torch.randn(N, D_in).type(dtype), requires_grad=False)

y = Variable(torch.randn(N, D_out).type(dtype), requires_grad=False)


# Create random Tensors for weights, and wrap them in Variables.

# Setting requires_grad=True indicates that we want to compute gradients with

# respect to these Variables during the backward pass.

w1 = Variable(torch.randn(D_in, H).type(dtype), requires_grad=True)

w2 = Variable(torch.randn(H, D_out).type(dtype), requires_grad=True)

learning_rate = 1e-6

for t in range(500):

    # Forward pass: compute predicted y using operations on Variables; these

    # are exactly the same operations we used to compute the forward pass using

    # Tensors, but we do not need to keep references to intermediate values since

    # we are not implementing the backward pass by hand.

    y_pred = x.mm(w1).clamp(min=0).mm(w2)

    # Compute and print loss using operations on Variables.

    loss = (y_pred - y).pow(2).sum()

    # Use autograd to compute the backward pass. This call will compute 

    # the gradient of loss with respect to all Variables with requires_grad=True.

    # After this call w1.grad and w2.grad will be Variables holding the gradient

    # of the loss with respect to w1 and w2 respectively.

    loss.backward()

    # Update weights using gradient descent; w1.data and w2.data are Tensors,

    # w1.grad and w2.grad are Variables and w1.grad.data and w2.grad.data are

    # Tensors.

    w1.data -= learning_rate * w1.grad.data

    w2.data -= learning_rate * w2.grad.data

    print("w1.data = ",w1.data)

    print("w1.grad.data = ",w1.grad.data) 

    # Manually zero the gradients after updating weights

    w1.grad.data.zero_()

    w2.grad.data.zero_()


























































Второй тест
************
Code 2
************
(.env) [boris@fedora34server PYTORCH]$ cat  pyTorch2.py
import torch
from torch.autograd import Variable

dtype = torch.FloatTensor
# dtype = torch.cuda.FloatTensor # Uncomment this to run on GPU

# N is batch size; D_in is input dimension;
# H is hidden dimension; D_out is output dimension.
N, D_in, H, D_out = 64, 1000, 100, 10

# Create random Tensors to hold input and outputs, and wrap them in Variables.
# Setting requires_grad=False indicates that we do not need to compute gradients
# with respect to these Variables during the backward pass.
x = Variable(torch.randn(N, D_in).type(dtype), requires_grad=False)
y = Variable(torch.randn(N, D_out).type(dtype), requires_grad=False)

# Create random Tensors for weights, and wrap them in Variables.
# Setting requires_grad=True indicates that we want to compute gradients with
# respect to these Variables during the backward pass.
w1 = Variable(torch.randn(D_in, H).type(dtype), requires_grad=True)
w2 = Variable(torch.randn(H, D_out).type(dtype), requires_grad=True)
# print("w1 = ",w1)
# print("w2 = ",w2)
learning_rate = 1e-6
for t in range(500):
    # Forward pass: compute predicted y using operations on Variables; these
    # are exactly the same operations we used to compute the forward pass using
    # Tensors, but we do not need to keep references to intermediate values since
    # we are not implementing the backward pass by hand.
    y_pred = x.mm(w1).clamp(min=0).mm(w2)

    # Compute and print loss using operations on Variables.
  
    loss = (y_pred - y).pow(2).sum()
    print(t, "loss.item() = ",loss.item())

    # Use autograd to compute the backward pass. This call will compute the
    # gradient of loss with respect to all Variables with requires_grad=True.
    # After this call w1.grad and w2.grad will be Variables holding the gradient
    # of the loss with respect to w1 and w2 respectively.

    loss.backward()

    # Update weights using gradient descent; w1.data and w2.data are Tensors,
    # w1.grad and w2.grad are Variables and w1.grad.data and w2.grad.data are
    # Tensors.
    w1.data -= learning_rate * w1.grad.data
    w2.data -= learning_rate * w2.grad.data
    # Manually zero the gradients after updating weights
    w1.grad.data.zero_()
    w2.grad.data.zero_()








References


Однако,на данный момент класс Variable устарел, и мы больше не беспокоимся между Variable и Tensor, поскольку Autograd также поддерживает Tensor .























Tuesday, April 5, 2022

Classifying Handwritten Digits via logitboost in Python

 В этом посте мы применим алгоритм LogitBoost к игрушечному набору данных для идентификации рукописных цифр.

***************

Сode 1

***************

(.env) [boris@fedora34server LOGITBOOST]$ cat logitBoost2.py

from itertools import product

import numpy as np

import matplotlib.pyplot as plt

from matplotlib import offsetbox

import seaborn as sns

sns.set(style='darkgrid', palette='colorblind', color_codes=True)


from sklearn.datasets import load_digits

from sklearn.decomposition import PCA

from sklearn.model_selection import train_test_split

from sklearn.pipeline import Pipeline

from sklearn.preprocessing import MinMaxScaler

from sklearn.tree import DecisionTreeRegressor

from sklearn.metrics import (accuracy_score, classification_report,

                             confusion_matrix)

from logitboost import LogitBoost

from tensorflow.keras.layers import Embedding



digits = load_digits()

X = digits.data

y = digits.target

images = digits.images.astype(np.int_)

n_classes = 10


# Scale the digits for numerical stability

X /= 16


# Shuffle the data and split them into training and testing sets

test_size = 1 / 3

X_train, X_test, y_train, y_test, images_train, images_test \

    = train_test_split(X, y, images, test_size=test_size, shuffle=True,

                       stratify=y, random_state=0)


print('Training shape: ', X_train.shape)

print('Test shape:     ', X_test.shape)

n_rows = 8

n_cols = 8


fig, ax = plt.subplots(nrows=n_rows, ncols=n_cols, figsize=(10, 10))

k = 0

for i, j in product(range(n_rows), range(n_cols)):

    image = images_train[n_cols * i + j]

    ax[i, j].imshow(image, cmap='binary', interpolation='none')

    ax[i, j].axis('off')


plt.show(block=False)

# plt.close()


lboost = LogitBoost(DecisionTreeRegressor(max_depth=3),

                    n_estimators=30, random_state=0)

lboost.fit(X_train, y_train)

LogitBoost(base_estimator=DecisionTreeRegressor(criterion='mse', max_depth=3,

                                                max_features=None,

                                                max_leaf_nodes=None,

                                                min_impurity_decrease=0.0,

                                                min_samples_leaf=1,

                                                min_samples_split=2,

                                                min_weight_fraction_leaf=0.0,

                                                random_state=None,

                                                splitter='best'),

           bootstrap=False, learning_rate=1.0, max_response=4.0,

           n_estimators=30, random_state=0, weight_trim_quantile=0.05)


y_pred_train = lboost.predict(X_train)

y_pred_test = lboost.predict(X_test)

accuracy_train = accuracy_score(y_train, y_pred_train)

accuracy_test = accuracy_score(y_test, y_pred_test)

print('Training accuracy: %.4f' % accuracy_train)

print('Test accuracy:     %.4f' % accuracy_test)


report_train = classification_report(y_train, y_pred_train)

report_test = classification_report(y_test, y_pred_test)

print('Training\n%s' % report_train)

print('Test\n%s' % report_test)


fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(12, 6))


sns.heatmap(confusion_matrix(y_train, y_pred_train), ax=ax[0],

            robust=True, annot=True, fmt=',d', cmap=plt.get_cmap('Blues'),

            square=True, cbar=False)

ax[0].set_xlabel('Predicted Class')

ax[0].set_ylabel('Actual Class')

ax[0].set_title('Training')


sns.heatmap(confusion_matrix(y_test, y_pred_test), ax=ax[1],

            robust=True, annot=True, fmt=',d', cmap=plt.get_cmap('Blues'),

            square=True, cbar=False)

ax[1].set_title('Testing', fontsize=14)

ax[1].set_xlabel('Predicted Class')

ax[1].set_ylabel('Actual Class')

plt.tight_layout()

plt.show(block=False)

# plt.close()

iterations = np.arange(1, lboost.n_estimators + 1)

staged_accuracy_train = list(lboost.staged_score(X_train, y_train))

staged_accuracy_test = list(lboost.staged_score(X_test, y_test))

plt.figure(figsize=(10, 8))

plt.plot(iterations, staged_accuracy_train, label='Training', marker='.')

plt.plot(iterations, staged_accuracy_test, label='Test', marker='.')

plt.xlabel('Iteration')

plt.ylabel('Accuracy')

plt.title('Ensemble accuracy during each boosting iteration', fontsize=14)

plt.legend(loc='best', shadow=True, frameon=True)

plt.tight_layout()

plt.show()

plt.close()






























*******************
Comlete Code 2
*******************
Добавим к предыдущему коду финальный фрагмент

(.env) [boris@fedora34server LOGITBOOST]$ cat logitBoost1.py
from itertools import product
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import offsetbox
import seaborn as sns
sns.set(style='darkgrid', palette='colorblind', color_codes=True)

from sklearn.datasets import load_digits
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import MinMaxScaler
from sklearn.tree import DecisionTreeRegressor
from sklearn.metrics import (accuracy_score, classification_report,
                             confusion_matrix)
from logitboost import LogitBoost
from tensorflow.keras.layers import Embedding


digits = load_digits()
X = digits.data
y = digits.target
images = digits.images.astype(np.int_)
n_classes = 10

# Scale the digits for numerical stability
X /= 16

# Shuffle the data and split them into training and testing sets
test_size = 1 / 3
X_train, X_test, y_train, y_test, images_train, images_test \
    = train_test_split(X, y, images, test_size=test_size, shuffle=True,
                       stratify=y, random_state=0)

print('Training shape: ', X_train.shape)
print('Test shape:     ', X_test.shape)
n_rows = 8
n_cols = 8

fig, ax = plt.subplots(nrows=n_rows, ncols=n_cols, figsize=(10, 10))
k = 0
for i, j in product(range(n_rows), range(n_cols)):
    image = images_train[n_cols * i + j]
    ax[i, j].imshow(image, cmap='binary', interpolation='none')
    ax[i, j].axis('off')

plt.show(block=False)
plt.close()

lboost = LogitBoost(DecisionTreeRegressor(max_depth=3),
                    n_estimators=30, random_state=0)
lboost.fit(X_train, y_train)
LogitBoost(base_estimator=DecisionTreeRegressor(criterion='mse', max_depth=3,
                                                max_features=None,
                                                max_leaf_nodes=None,
                                                min_impurity_decrease=0.0,
                                                min_samples_leaf=1,
                                                min_samples_split=2,
                                                min_weight_fraction_leaf=0.0,
                                                random_state=None,
                                                splitter='best'),
           bootstrap=False, learning_rate=1.0, max_response=4.0,
           n_estimators=30, random_state=0, weight_trim_quantile=0.05)

y_pred_train = lboost.predict(X_train)
y_pred_test = lboost.predict(X_test)

accuracy_train = accuracy_score(y_train, y_pred_train)
accuracy_test = accuracy_score(y_test, y_pred_test)

print('Training accuracy: %.4f' % accuracy_train)
print('Test accuracy:     %.4f' % accuracy_test)

report_train = classification_report(y_train, y_pred_train)
report_test = classification_report(y_test, y_pred_test)
print('Training\n%s' % report_train)
print('Test\n%s' % report_test)

fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(12, 6))

sns.heatmap(confusion_matrix(y_train, y_pred_train), ax=ax[0],
            robust=True, annot=True, fmt=',d', cmap=plt.get_cmap('Blues'),
            square=True, cbar=False)
ax[0].set_xlabel('Predicted Class')
ax[0].set_ylabel('Actual Class')
ax[0].set_title('Training')

sns.heatmap(confusion_matrix(y_test, y_pred_test), ax=ax[1],
            robust=True, annot=True, fmt=',d', cmap=plt.get_cmap('Blues'),
            square=True, cbar=False)
ax[1].set_title('Testing', fontsize=14)
ax[1].set_xlabel('Predicted Class')
ax[1].set_ylabel('Actual Class')

plt.tight_layout()
plt.show(block=False)
plt.close()

iterations = np.arange(1, lboost.n_estimators + 1)
staged_accuracy_train = list(lboost.staged_score(X_train, y_train))
staged_accuracy_test = list(lboost.staged_score(X_test, y_test))

plt.figure(figsize=(10, 8))
plt.plot(iterations, staged_accuracy_train, label='Training', marker='.')
plt.plot(iterations, staged_accuracy_test, label='Test', marker='.')

plt.xlabel('Iteration')
plt.ylabel('Accuracy')
plt.title('Ensemble accuracy during each boosting iteration', fontsize=14)
plt.legend(loc='best', shadow=True, frameon=True)

plt.tight_layout()
plt.show(block=False)
plt.close()

# Maximum number of misclassifications to show
n_misclassifications = 50
# Estimated class probabilities for the test set
prob_test_pred = lboost.predict_proba(X_test)
# Indices of the misclassified test examples
incorrect = (y_test != y_pred_test)
incorrect = np.where(incorrect)[0]

n_incorrect = len(incorrect)
print(f'Test set misclassification rate: {n_incorrect} out of {len(X_test)}')

for i in range(len(incorrect)):
    fig, ax = plt.subplots(nrows=1, ncols=2, figsize=(10, 2),
                           gridspec_kw={'width_ratios': [1, 4]})
    ax = ax.ravel()

    # Reassign i to the index of the ith incorrectly classified example
    i = incorrect[i]

    # Show the wrongly classified image
    image = images_test[i]
    ax[0].imshow(image, cmap='binary')
    ax[0].axis('off')
    ax[0].set_aspect('equal', 'box')

    palette = ['r'] * n_classes
    palette[y_test[i]] = 'g'
    sns.barplot(x=np.arange(n_classes), y=prob_test_pred[i],
                ax=ax[1], palette=palette)
    ax[1].set(ylabel='Probability', xlabel='Digit')
    ax[1].set(yscale='log', ylim=(1e-3, 1))

    true_label = y_test[i]
    pred_label = y_pred_test[i]
    pred_label_prob = prob_test_pred[i, pred_label]
    color = 'r' if true_label != pred_label else 'g'
    ax[1].get_xticklabels()[true_label].set_color('g')
    ax[1].get_xticklabels()[pred_label].set_color(color)

    ax[0].set_title('True label : %r' % true_label, fontsize=14)
    ax[1].set_title(f'Prediction: {pred_label} (prob: {pred_label_prob:.2f})',
                    color=color, fontsize=14)

    plt.tight_layout()
    plt.show()
    plt.close()

Наконец, давайте посмотрим на цифры в тестовом наборе, которые были неправильно классифицированы, и на то, что, по мнению модели LogitBoost, они представляют собой на самом деле.