"Машинное обучение"

Алгоритм KNN для классификации и регрессии: практические занятия с Scikit-Learn

Google Colab и Python

Table of Contents:
A — KNN for classification
1. Import Libraries
2. Build a dataset
3. Explore Dataset
4. Setting variables for ML
5. Split data into train and test
6. Building the model
7. Finding best k value
8. Model Complexity
9. Plotting decision boundaries
B — KNN for regression
1. Import Libraries
...
6. Building the model
7. Finding best k value
8. Model Complexity
C — Advantages and Disadvantages of KNN
Advantages
Disadvantages

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

А — КНН для классификации:

При использовании KNN для задач классификации и k = 1 наша модель просто ищет точку данных из набора данных, которая ближе к значению, которое мы хотим классифицировать. Если мы выберем k=3, k=5 или K=n, модель будет искать значения 3, 5 или n, которые ближе к нужному значению. классифицировать. Затем наше значение присваивается классу, у которого больше значений.

Пример 1.Для k=7 модель обнаруживает, что из 7 точек, которые ближе к нашему значению, 3 относятся к классу 0, а 4 относятся к классу 1. В этом случае наше значение будет присвоено классу 1.

Пример 2. Для k=6 модель обнаруживает, что из 6 точек, которые ближе к нашему значению, 3 относятся к классу 0 и 3 относятся к классу 1. В этом В этом случае модель рассчитает среднее евклидово расстояние по нашему значению и трем точкам каждого класса. Наше значение будет отнесено к классу с меньшим евклидовым расстоянием.

Практика:

1. Импорт библиотек:

Как и в любом другом проекте по машинному обучению, первым делом нужно импортировать необходимые библиотеки:

#Import Libraries:
from random import random
from random import randint
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from mlxtend.plotting import plot_decision_regions

2. Создайте набор данных:

Далее я создам поддельный набор данных для использования в этой задаче. Вы можете сделать то же самое в учебных целях или использовать свои данные, если работаете над реальной проблемой.

#Fabricating variables:
#Creating values for FeNO with 3 classes:
FeNO_0 = np.random.randint(1,20, 100)
FeNO_1 = np.random.randint(25,55, 100)
FeNO_2 = np.random.randint(45, 100, 100)
#Creating values for FEV1 with 3 classes:
FEV1_0 = [np.random.uniform(3.12,4.50) for _ in range(100)]
FEV1_1 = [np.random.uniform(2.98,4.25) for _ in range(100)]
FEV1_2 = [np.random.uniform(2.55,3.99) for _ in range(100)]
#Creating values for Bronco Dilation with 3 classes:
BD_0 = [np.random.uniform(0,0.180) for _ in range(100)]
BD_1 = [np.random.uniform(0.160,0.250) for _ in range(100)]
BD_2 = [np.random.uniform(0.200,0.700) for _ in range(100)]
#Creating labels variable with two classes (1)Disease (0)No disease:
not_asma = np.zeros((150,), dtype=int)
asma = np.ones((150,), dtype=int)

Обратите внимание, что я создал три переменные с тремя классами и переменную label только с двумя классами. Это было сделано специально, чтобы создать некоторую сложность в наборе данных, добавив некоторые записи с характеристиками обоих классов.

Теперь пришло время объединить три класса переменных в одну переменную:

#Concatenate classes into one variable:
FeNO = np.concatenate([FeNO_0, FeNO_1, FeNO_2])
FEV1 = np.concatenate([FEV1_0, FEV1_1, FEV1_2])
BD = np.concatenate([BD_0, BD_1, BD_2])
dx = np.concatenate([not_asma, asma])

А теперь создайте DataFrame и добавьте переменные в DataFrame:

#Create DataFrame:
df = pd.DataFrame()
#Add variables to DataFrame:
df['FeNO'] = FeNO.tolist()
df['FEV1'] = FEV1.tolist()
df['BD'] = BD.tolist()
df['dx'] = dx.tolist()

Чтобы проверить DataFrame, просто введите:

df

и вы увидите DataFrame с именем df с 300 строками и 4 столбцами:

3. Исследуйте набор данных:

Чтобы изучить наш набор данных и взаимосвязь между переменными:

#Exploring dataset:
# left
sns.pairplot(df, kind="scatter", hue="dx")
plt.show()
# right: you can give other arguments with plot_kws.
sns.pairplot(df, kind="scatter", hue="dx")
plt.show()

4. Установка переменных:

В проектах машинного обучения мы обычно вызываем X для набора данных, содержащего функции, и y для массива меток. Чтобы создать переменные X и y:

X = df.drop('dx', axis=1)
y = df['dx']

Мы можем проверить, все ли в порядке, набрав X:

И y:

5. Разделить данные на обучение и тестирование:

Теперь мы разделим наши данные на обучение и тестирование. Это важно, потому что мы будем обучать нашу модель с помощью обучающего подмножества и проверять точность модели с помощью тестового подмножества. В Scikit-Lear есть функция train_test_split, которую мы будем использовать. Мы будем использовать 80% наших данных для обучения и 20% для теста (обозначается test_size=0.20):

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20)

6. Построение модели:

Теперь пришло время построить модель и передать данные в модель. Начнем с k=1.

clf = KNeighborsClassifier(n_neighbors=1)
clf.fit(X_train, y_train)

Мы можем увидеть некоторые прогнозы модели:

clf.predict(X_test)

Чтобы оценить модель:

clf.score(X_test, y_test)

7. Поиск лучшего k:

И мы видим, что точность нашей модели составляет 0,80. Неплохо, но мы можем попробовать другое число k. Чтобы найти наилучшее число k, мы пробуем разные случайные k или можем построить график, отображающий различные значения k и точность модели. В этом случае я попробую значения k от 1 до 30.

training_accuracy = []
test_accuracy = []
# try n_neighbors from 1 to 30.
neighbors_settings = range(1, 31)
for n_neighbors in neighbors_settings:
    # build the model
    clf = KNeighborsClassifier(n_neighbors=n_neighbors)
    clf.fit(X_train, y_train)
    # record training set accuracy
    training_accuracy.append(clf.score(X_train, y_train))
    # record generalization accuracy
    test_accuracy.append(clf.score(X_test, y_test))
plt.plot(neighbors_settings, training_accuracy, label="training accuracy")
plt.plot(neighbors_settings, test_accuracy, label="test accuracy")
plt.legend()

При графическом осмотре k=20 показал наилучшую точность теста. Итак, мы построили нашу модель с k=20:

clf = KNeighborsClassifier(n_neighbors=20)
clf.fit(X_train, y_train)
clf.predict(X_test)
clf.score(X_test, y_test)

Теперь у нас есть оценка 0,82, что немного выше, чем 0,8.

8. Сложность модели:

Использование k=20 вместо k=1 повысило точность нашей модели. Еще один важный аспект KNN заключается в том, что модели с более высоким k являются моделями с меньшей сложностью. Таким образом, используя более высокое значение k, мы не только повышаем точность модели, но и уменьшаем ее сложность.

9. Нанесение границ решений:

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

Первый шаг — сохранить наш набор данных в формате CSV и снова импортировать его с помощью pandas:

df.to_csv('data.csv', index = False)
data = pd.read_csv('data.csv')

Теперь мы построим функцию для создания другой модели и построения границ решений. С нашими тремя переменными мы можем построить 3 разных графика. Для этого примера я буду FEV1 и BD в качестве функций:

def knn_comparison(data,k):
    x = data[['FEV1','BD',]].values
    y = data['dx'].astype(int).values
    clf = KNeighborsClassifier(n_neighbors=k)
    clf.fit(x,y)
    print(clf.score(x,y))
    #Plot decision region:
    plot_decision_regions(x,y,clf=clf, legend=2)
    #Adding axes annotations:
    plt.xlabel('X_train')
    plt.ylabel('y_train')
    plt.title('KNN with k='+str(k))
    plt.show()

Чтобы построить модель и график, просто вызовите функцию:

knn_comparison(data,20)

B — KNN для регрессии:

Алгоритм KNN также можно использовать для регрессии. Если K=1, значением регрессии будет значение ближайшей точки в наборе данных. Если k=n и n>1, значением регрессии будет среднее евклидово расстояние между нашим значением и n точками в наборе данных.

1. Импорт библиотек:

Нам понадобится еще один:

from sklearn.neighbors import KNeighborsRegressor

Поскольку мы будем использовать тот же набор данных, мы можем сразу перейти к шагу номер 6.

6. Построение модели:

Чтобы построить модель, мы выполним шаги, очень похожие на классификацию, начиная с k = 1:

reg = KNeighborsRegressor(n_neighbors=1)
reg.fit(X_train, y_train)
reg.predict(X_test)
reg.score(X_test, y_test)

Оценка нашей модели составляет около 0,40, что довольно плохо. Мы постараемся найти наилучшее значение k и улучшить прогнозы нашей модели.

7. Поиск лучшего значения k:

training_accuracy = []
test_accuracy = []
# try n_neighbors from 1 to 30.
neighbors_settings = range(1, 31)
for n_neighbors in neighbors_settings:
    # build the model
    reg = KNeighborsRegressor(n_neighbors=n_neighbors)
    reg.fit(X_train, y_train)
    # record training set accuracy
    training_accuracy.append(reg.score(X_train, y_train))  
    # record generalization accuracy
    test_accuracy.append(reg.score(X_test, y_test))
plt.plot(neighbors_settings, training_accuracy, label="training accuracy")
plt.plot(neighbors_settings, test_accuracy, label="test accuracy")
plt.legend()

Анализируя график, k=22 кажется оптимальным значением.

reg = KNeighborsRegressor(n_neighbors=22)
reg.fit(X_train, y_train)
reg.predict(X_test)
reg.score(X_test, y_test)

Как и ожидалось, увеличение значений k увеличило оценку модели, которая теперь составляет около 0,63, что намного лучше, чем 0,39.

8. Сложность модели:

Как и в случае с классификацией, увеличение числа k в регрессионных моделях снижает сложность модели. Подумайте о большем количестве соседей, чтобы получить более точный прогноз.

C — Преимущества и недостатки KNN

Как и все другие алгоритмы, KNN имеет преимущества и недостатки. Некоторые из них:

Преимущества:
-Простая модель машинного обучения;
-Легко понять и объяснить нетехническим специалистам;
-Простота проектирования (только скорректировать на k);
-Хорошо подумать, прежде чем пробовать более сложные модели.

Недостатки:
- Медленная работа с очень большими наборами данных;
- Невозможность обработки и представления многих функций.

Заключение

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

Спасибо за чтение!

Если: вам понравилась эта статья, не забудьте подписаться на меня и, таким образом, получать все обновления о новых публикациях.

Иначе Если: вы хотите узнать больше, вы можете подписаться на членство в Medium с помощью моей реферальной ссылки. Это не будет стоить вам больше, но заплатит мне за кофе.

Еще: Спасибо, что прочитали!