K-Nearest Neighbor, шаг за шагом с scikit-learn
Заявление об ограничении ответственности: эта статья предназначена для самообучения, чтобы понять, как работают функции и алгоритмы машинного обучения. Проконсультируйтесь с различными ссылками, связанными в этом сообщении, для получения дополнительной информации. Код, используемый для модели, описанной ниже, можно просмотреть как файл Jupyter Notebook и получить доступ к нему из моего репозитория GitHub.
Вступление
K-Nearest Neighbor (KNN) - это управляемая модель машинного обучения ᵀᴹ для задач двоичной классификации. KNN предсказывает класс (классы) значения на основе ближайшей близости к определенному K количеству соседей.
Контролируемое обучение?
Прогнозирование выходных данных с использованием «новых данных» с использованием моделей классификации или регрессии, которые были обучены с «известными» входными данными.
KNN в основном состоит из двух параметров: нахождения подходящего количества соседей (K) и того, как расстояние между точками измеряется. Чаще всего KNN измеряется евклидовым расстоянием, расстоянием по прямой между двумя точками:
Скажем, p относится к известному атрибуту в нашем наборе данных, а q - это неизвестный атрибут, который мы пытаемся классифицировать. Если бы мы изобразили p и q на диаграмме рассеяния, KNN определил бы расстояние между двумя точками как квадратный корень из суммы квадратов разности (поскольку у нас не может быть отрицательного расстояния) всех атрибутов ( n) для каждого поля атрибута (i). Я знаю, это звучит глупо, но все, что мы делаем, это вычисляем прямолинейное расстояние от неклассифицированного атрибута до ближайшего числа соседей, известных атрибутов, как определено K:
Неизвестный атрибут адаптирует класс большинства соседей в пределах периметра K (так, что в приведенном выше примере неизвестный атрибут классифицируется как B, где K = 3). Модели KNN по умолчанию имеют одинаковый вес для полей каждого атрибута; вы можете параметризовать модель, назначив веса для конкретных атрибутов, включая расстояние (если, скажем, близость между точками в значительной степени определяет, каким может быть ее класс).
Но что, если голоса разделились? Для функции KNN scikit-learn по умолчанию атрибут будет назначен первому классу в последовательности. Таким образом, если у нас есть «Класс 0» и «Класс 1», и у нас есть равное количество голосов (скажем, K = 4, и голосование делится поровну), тогда атрибуту будет присвоен «Класс 0».
Уловка с KNN заключается в определении соответствующего количества соседей - K - так, чтобы точность модели не соответствовала ни недостаточной («сложная» модель с недостаточным количеством соседей), ни переоснащению («простая» модель со слишком большим количеством соседей) кривой обобщения.
Кривая обобщения?
Описывает точность модели, делающей точные прогнозы на основе «невидимых» новых данных. В дальнейшем модель «обобщается» от обучающей к тестовой.
KNN - хорошее введение в машинное обучение: это относительно простая модель для понимания и интерпретации, которая дает разумную производительность (точность) без излишних корректировок. Это иначе известно как алгоритм ленивого обучения. Однако он плохо справляется с редкими или объемными наборами данных.
Шаг 1. Начало работы
Scikit-learn, также известный как sklearn, представляет собой библиотеку машинного обучения с открытым исходным кодом, включающую различные модели регрессии и классификации. Я рекомендую проверить их обширную документацию и руководства для дальнейшего понимания (инструкции по установке sklearn здесь).
Откройте предпочитаемую вами среду программирования Python и импортируйте необходимые пакеты:
# Generally useful packages to have on deck: import pandas as pd import numpy as np import matplotlib.pyplot as plt # If you want to practice with sklearn's prepackaged datasets: from sklearn.datasets import load_wine # The sklearn packages we'll need: from sklearn import metrics from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split from sklearn.neighbors import KNeighborsClassifier
Для практики в sklearn.datasets есть все, что вам нужно для начала работы. Однако для этого конкретного примера я взял некоторые данные из Kaggle. Давайте посмотрим на набор данных аренды по разным городам Бразилии:
df=pd.DataFrame(pd.read_csv('data_practice/houses_to_rent_v2.csv')) display(df.head()) df.columns
Шаг 2. Убедитесь, что ваши данные подходят для модели!
Обратите внимание, что помимо непрерывных числовых значений в наборе данных у нас также есть категориальные значения (город, животное, мебель). Поэтому нам нужно внести несколько корректировок:
a) Поля для «животное» и «мебель» похожи на логические, что означает, что они просто указывают, принимает ли дом домашних животных или он меблирован (Верно / Неверно). Таким образом, мы можем преобразовать «Нет» в «0», а «Да» - в «1» (или, наоборот, ваш призыв).
б) Ну а города? Здесь мы думаем о том, чего мы хотим, чтобы наша модель KNN делала. Есть разные способы взглянуть на нашу модель классификации: например, мы могли бы просто попытаться предсказать, находится ли арендуемая квартира в Сан-Паулу (пометив город как «1», а остальные - как «0»). Сан-Паулу - это крупнейший мегаполис Бразилии и Южной Америки, поэтому мы можем сделать некоторые разумные предположения о стоимости жизни, что отражается в более высоких ценах на аренду и меньших квадратных футах. Но для целей этого руководства давайте просто поэкспериментируем с моделью, чтобы посмотреть, насколько хорошо она справляется с прогнозированием классификационных меток для каждого города в наборе данных.
# converts each unique string values to a unique integer df.city = pd.factorize(df['city'])[0] # Convert your "boolean" string values into 1s and 0s. df.animal = pd.Series(np.where(df.animal == ‘acept’, 1, 0)) df.furniture = pd.Series(np.where(df.furniture == ‘furnished’, 1, 0))
Также убедитесь, что все ваши поля числовые. Возможно, потребуется внести небольшие корректировки, особенно с наборами данных, в создании которых вы не участвовали.
Шаг 3. Масштабируйте набор данных
Масштабирование, также известное как стандартизация, - это процесс, с помощью которого данные нормализуются и заменяются Z-оценкой:
Для объяснения того, почему данные нуждаются в стандартизации, прочтите: Почему требуется масштабирование в KNN и K-Means?
from sklearn.preprocessing import StandardScaler # StandardScaler() transform the data such that its distribution # will have a mean value 0 and standard deviation of 1. scaler = StandardScaler() scaler.fit(X_train) X_train = scaler.transform(X_train) X_test = scaler.transform(X_test)
StandardScaler () - это функция, которая применяет алгоритм стандартизации, который мы связываем с методом .fit () для вычисления среднего и стандартного отклонения масштабированного набора данных. Затем мы применяем метод .transform () для центрирования и масштабирования распределения данных как для тестовой, так и для обучающей выборки.
Шаг 4. Разделите набор данных на обучающие и тестовые наборы.
Во-первых, нам нужно отделить поля атрибутов от меток. Это означает, что мы хотим отличать переменные-предикторы (X) от меток, которые мы хотим классифицировать (y), для которых в данном случае используется поле атрибута «город».
# Excluding ‘city’ and 'total(R$)', the latter because I think it's # redundant to have a field that's just the sum of 4 other fields X = df.iloc[:, 1:-1].values # Including ‘city’ only y = df.iloc[:, 0].values
Теперь мы разделим набор данных на обучающий и тестовый набор: первый - это часть набора данных, которая вводится в модель для прогнозирования класса, а вторая будет использоваться для проверки точности модели. Отсюда то, что делает KNN «контролируемой» классификационной моделью.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0,test_size=0.20) print(X_train.shape, X_test.shape) (8553, 11) (2139, 11)
Некоторые подробности о том, как работает функция train_test_split ():
random_state указывает метод случайной выборки. По умолчанию, если не указано иное, функция будет использовать экземпляр из numpy.random и создавать образец, который будет другим, если вы запустите его несколько раз. Однако в этом случае я присвоил случайному начальному значению значение «0». Данные по-прежнему случайны, но метод, с помощью которого производится выборка, можно воспроизвести. Т.е. Если бы вы повторили в точности то, что я делал до сих пор, с тем же набором данных, вы бы получили точно такую же «случайную выборку», если бы вы присвоили случайному начальному значению значение «0».
test_size - это просто желаемая доля вашего тестового набора по отношению ко всему набору данных. Таким образом, при 0,20 я указываю, что мой тестовый набор равен 20% от всего набора данных (из 10 692 строк). По умолчанию размер теста составляет 25%. Какой размер считается подходящим для наборов тестирования, зависит от статистической строгости вашей модели; обратитесь к этой теме StackExchange для более глубокого погружения.
Шаг 5: запустите и интерпретируйте модель
Используя функцию KNeighborsClassifier (), мы определяем параметр K модели (просто попробуйте начать с случайного значения). Мы обучаем модель KNN на обучающей выборке и применяем ее к тестовой выборке с помощью метода .predict ().
from sklearn.neighbors import KNeighborsClassifier # Set K = 6 (an arbitrary value) to observe the output knn = KNeighborsClassifier(n_neighbors=6) # Train the algorithm model=knn.fit(X_train, y_train) y_pred = model.predict(X_test) print(metrics.accuracy_score(y_test, y_pred)) 0.6610565684899485
Точность модели при K = 6 составляет примерно 66%. Это хорошо? Что ж, это зависит от вашего набора данных, исследовательского запроса, того, что говорится в соответствующей справочной литературе в вашей области знаний и т. Д.
Но на самом деле мы можем глубже взглянуть на показатель точности, используя функцию sklearn classification_report ().
from sklearn.metrics import classification_report print(classification_report(y_test, y_pred))
Точность и отзывчивость - это компромиссы друг друга.
Точность: сколько было правильно отнесено к этому классу (источник);
Класс «0» (обозначающий Сан-Паулу) имеет наивысшую точность, где все экземпляры классифицированных положительных результатов были правильно идентифицированы в 67% случаев.
Напомним: процент правильно классифицированных общих релевантных результатов (источник);
Для всех экземпляров, которые были классифицированы как положительные (т. Е. Экземпляров, которые правильно принадлежали к соответствующему классу «город»), класс «0» имеет лучший результат 98%, что означает, что модель была эффективной для определения соответствующих элементов для этого класса.
f1-score: среднее гармоническое значение между точностью и отзывом »( источник );
Показатель f1 полезен для сравнения с общим показателем точности.
Поддержка: количество вхождений данного класса в набор данных (источник);
У меня гораздо больше случаев появления класса «0» по сравнению со всеми другими классами вместе взятыми, что может указывать на то, что мой набор данных недостаточно сбалансирован.
Что-то еще, что мы могли бы знать, это оптимальное значение K, чтобы обеспечить наилучшую возможную точность прогноза. Мы можем попробовать запустить модель несколько раз, перебирая диапазон для K:
# Choose how many neighbors to test k_range = range(1,300) # Create a list to store scores scores=[] error = [] # Run the KNN for k in k_range: knn = KNeighborsClassifier(n_neighbors=k) knn.fit(X_train, y_train) y_pred = knn.predict(X_test) # Append the accuracy score scores.append(metrics.accuracy_score(y_test, y_pred)) # Append the error rate error.append(np.mean(y_pred != y_test)) # Print the scores print(scores)
И наоборот, мы можем попытаться определить K на основе наименьшего коэффициента ошибок:
В этом примере разница в точности в 2% не приведет к значительному повышению производительности модели, независимо от количества соседей. Во всяком случае, это пища для размышлений о том, что это за данные и что они не могут сказать нам о проблеме классификации. Например, даже если есть разница в цене и площади для мегаполиса, такого как Сан-Паулу, по сравнению с остальными, действительно ли разница заметна, чтобы провести различие между городами сопоставимого размера, такими как Белу-Оризонти и Порту-Алегри? И насколько полезна информация о разрешенных домашних животных или об аренде мебели для задач классификации по определению городов?
Иногда самое важное, что можно сделать с помощью модели, - это ограничения и уместность самого набора данных.