Технологии машинного обучения на простом примере

Автор: | 03.02.2022

Введение
Шпаргалка к описанию программы
Программный код
Полезные ссылки

Введение

Машинное обучение — это алгоритм обучения, реализующий постепенное улучшение исполнения поставленной задачи. Важно знать типы и технологии машинного обучения, чтобы создать правильную среду обучения.

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

Обучение без учителя (Unsupervised) — самоорганизация старых данных в новые (кластеризация данных).  Здесь исходные данные не имеют меток, данные получают их в результате обучения. Кластеризация данных, в отличие от классификации, подразумевает организацию данных без явно определяемых для этого признаков. Существенные признаки автоматически выделяются нейронной сетью из множества признаков, неявно заложенных в данных.

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

Существует множество задач, которые легко формулируются как один тип обучения, а затем преобразовываются в другую парадигму. Мы можем смешивать типы обучения, проектируя системы, которые учатся тем или иным способом, но объединяются в один более крупный алгоритм. Ниже рассмотрен простейший пример программной реализации такой задачи с использованием различных технологий машинного обучения.

Шпаргалка к описанию программы

(подробное описание программы см. в первоисточнике)

Datasets ИРИС — 3 сорта цветков с 4 признаками (длина/ширина двух типов лепестков Ириса: sepal и petal). Datasets состоит из 150 образцов (по 50 на каждый вид). Каждый сорт помечен (0, 1, 2).

Задача —  найти зависимости между размерами лепестков и сортами Ирисов

Последовательность выполнения программы:

  • Загрузка и обработка данных для анализа. Для удобства манипулирования данными делаем из них DataFrame (таблицу)
  • Строим гистограммы по каждому признаку. Распределение у некоторых переменных похоже на нормальное
  • Строим таблицу с зависимостями между признаками. Видно, что «petal width (cm)» и «petal length (cm)» имеют сильную зависимость — точки вытянуты вдоль одной линии.
  • В наглядном виде представляем корреляционную зависимость признаков. Между признаками «petal length (cm)» и «petal width (cm)» выявлена очень сильная зависимость 0.96.

В первом приближении можно просто включить все переменные в модель и посмотреть, что будет. Далее можно будет подумать, какие признаки убрать, а какие создать.

  • Разделяем данные — для обучения и тестовые (30%).
  • Линейная регрессия. Строим модель, используя переменные, которые, как мы поняли ранее, имеют сильную зависимость — это «petal length (cm)» и «petal width (cm)». Еще раз убедились в существовании  корреляции (0.962….) между этими переменными. Найденная линия регрессии хорошо повторяет направление распределения точек. Теперь, если у нас будет в наличии, например, длина листочка pental, мы сможем с большой точностью определить, какая у него ширина!
  • Классификация. Строим модель, используя все 4 переменные. Смотрим на метрики качества модели. Видим, что значения метрик на нашем примере очень хорошие (accuracy = 0.93…). Посмотрим на график. Для наглядности выборку рисуем в двух координатах и раскрашиваем по классам. Сначала отобразим тестовую выборку, как она есть. Потом, как ее предсказала наша модель. Видим, что только несколько точек на границе были классифицированы неправильно.
  • Cross-Validation. Проверим работу алгоритма на 10 случайных выборках. Смотрим на результат. Он ожидаемо ухудшился: (accuracy = 0.86…). Подбор оптимальных параметров алгоритма. Смотрим, стало немного лучше: 0.9155.
  • Уберем из модели менее значимые признаки (sepal length и sepal width), Смотрим, стало еще немного лучше: 0.9377. Сделаем новый признак (площадь листка petal), результат: 0.942.
  • Кластеризация (метод Kmeans).  Достаточно точный результат: accuracy, precision и recall больше 0.9.

Программный код

#Импортируем нужные библиотеки:
import numpy as np
import pandas as pd
from sklearn import datasets
from sklearn import linear_model
from sklearn.cluster import KMeans
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import StratifiedShuffleSplit
from sklearn.model_selection import learning_curve, GridSearchCV
from sklearn import metrics 
from pandas import DataFrame
import matplotlib.pyplot as plt
import seaborn as sns
from scipy import polyval, stats

               #Загрузка и обработка данных для анализа
# Загружаем набор данных (Ирисы):
iris = datasets.load_iris()
# Смотрим на названия переменных
print (iris.feature_names)
# Смотрим на данные, выводим 10 первых строк: 
print (iris.data[:10])
# Смотрим на целевую переменную:
print ("\niris.target_names:\n",iris.target_names)
print ("\niris.target:\n",iris.target)

# Для удобства манипулирования данными делаем из них DataFrame:
iris_frame = DataFrame(iris.data)
# Делаем имена колонок такие же, как имена переменных:
iris_frame.columns = iris.feature_names
# Добавляем столбец с целевой переменной: 
iris_frame['target'] = iris.target
# Для наглядности добавляем столбец с сортами: 
iris_frame['name'] = iris_frame.target.apply(lambda x : iris.target_names[x])
# Смотрим, что получилось:
print ("\niris_frame:\n",iris_frame)

# Строим гистограммы по каждому признаку:
plt.figure(figsize=(20, 24))
plot_number = 0
for feature_name in iris['feature_names']:
  for target_name in iris['target_names']:
    plot_number += 1
    plt.subplot(4, 3, plot_number)
    plt.hist(iris_frame[iris_frame.name == target_name][feature_name])
    plt.title(target_name)
    plt.xlabel('cm')
    plt.ylabel(feature_name[:-4])
plt.show()

# Строим таблицу с зависимостями между признаками
# и раскрашиваем точки в зависимости от сортов Ирисов:
sns.pairplot(iris_frame[['sepal length (cm)','sepal width (cm)',
                         'petal length (cm)','petal width (cm)','name']],
            hue = 'name')
plt.show()

# Корреляционная зависимость между переменными
corr=iris_frame[['sepal length (cm)','sepal width (cm)',
                'petal length (cm)','petal width (cm)']].corr()
print ("\ncorr:\n",corr)

# Тепловая карта зависимости признаков
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask)] = True
with sns.axes_style("white"):
   ax = sns.heatmap(corr, mask=mask, square=True, cbar=False,
                   annot=True, linewidths=.5)
plt.show()

# Данные для обучения и тестовые данные
train_data, test_data, train_labels, test_labels = train_test_split(iris_frame[[
    'sepal length (cm)','sepal width (cm)','petal length (cm)','petal width (cm)']],
                                                                   iris_frame['target'],
                                                                  test_size = 0.3,
                                                                 random_state = 0)

# Визуально проверяем, что получившееся разбиение соответствует нашим ожиданиям:
print ("\ntrain_data:\n",train_data)
print ("\ntest_data:\n",test_data)
print ("\ntrain_labels:\n",train_labels)
print ("\ntest_labels:\n",test_labels)

                # Цикл построения моделей – оценка результата

                               # Линейная регрессия
print ("\nЛинейная регрессия:")
fit_output = stats.linregress(iris_frame[['petal length (cm)','petal width (cm)']])
slope, intercept, r_value, p_value, slope_std_error = fit_output
print("\n slope intercept, r_value, p_value, slope_std_error:\n",
 slope, intercept, r_value, p_value, slope_std_error)

# Рисуем график с точками и линией регрессии:
plt.plot(iris_frame[['petal length (cm)']], iris_frame[['petal width (cm)']],'o', label='Data')
plt.plot(iris_frame[['petal length (cm)']], intercept + slope*iris_frame[['petal length (cm)']],
        'r', linewidth=3, label='Linear regression line')
plt.ylabel('petal width (cm)')
plt.xlabel('petal length (cm)')
plt.legend()
plt.show()

                               # Классификация
print ("\nКлассификация:")
# Создаем модель Stochastic Gradient Descent:
model = linear_model.SGDClassifier(alpha=0.001, max_iter=100, random_state = 0)
model.fit(train_data, train_labels)
model_predictions = model.predict(test_data)
print ("metrics.accuracy_score:", metrics.accuracy_score(test_labels, model_predictions))
print ("metrics.classification_report:\n", metrics.classification_report(test_labels,
 model_predictions))
# Сначала отобразим тестовую выборку, как она есть,
fig = plt.figure(1, figsize=(6, 5))
plt.scatter(test_data['petal length (cm)'],
           test_data['petal width (cm)'],
          c=test_labels.astype(np.float))
plt.ylabel('petal width (cm)')
plt.xlabel('petal length (cm)')
plt.title('Test data')
plt.show()

# потом, как ее предсказала наша модель.
fig = plt.figure(1, figsize=(6, 5))
plt.ylabel('petal width (cm)')
plt.xlabel('petal length (cm)')
plt.title('Model prediction data')
plt.scatter(test_data['petal length (cm)'],
           test_data['petal width (cm)'],
          c=model_predictions.astype(np.float))
plt.show()

# Cross-Validation 
# Проверим работу алгоритма на 10 случайных выборках
scores = cross_val_score(model, train_data, train_labels, cv=10)
print ("scores.mean:\n",scores.mean())

                                   # Кластеризация K-Means
print ("\nКластеризация K-Means:")
model = KMeans(n_clusters=3, random_state = 0)
model.fit(train_data)
model_predictions = model.predict(test_data)
print ("metrics.accuracy_score:", metrics.accuracy_score(test_labels, model_predictions))
print ("metrics.classification_report:\n", metrics.classification_report(test_labels,
                                                                        model_predictions))
fig = plt.figure(1, figsize=(6, 5))
plt.scatter(test_data['petal length (cm)'], test_data['petal width (cm)'],
           c=test_labels.astype(np.float))
plt.ylabel('petal width (cm)')
plt.xlabel('petal length (cm)')
plt.title('Test data for K-means')
plt.show()
fig = plt.figure(1, figsize=(6, 5))
plt.ylabel('petal width (cm)')
plt.xlabel('petal length (cm)')
plt.title('K-means prediction data')
plt.scatter(test_data['petal length (cm)'], test_data['petal width (cm)'],
           c=model_predictions.astype(np.float))
plt.show()

 

Полезные ссылки:

 

Автор: Николай Свирневский