В этой статье мы собираемся создать собственный алгоритм KNN с нуля и применить его к 23 различным наборам данных с использованием библиотек Numpy и Pandas.
Алгоритм K ближайших соседей
K Nearest Neighbours — один из самых простых алгоритмов прогнозирования в категории контролируемого машинного обучения.
Алгоритм работает на основе двух критериев: —
- Количество соседей для включения в кластер.
- Расстояние соседей от точки тестовых данных.
На изображении выше показано количество соседей (k = количество соседей), которые учитываются при прогнозировании значения для точки тестовых данных.
Предварительная обработка данных
Здесь мы используем набор данных бриллианты, содержащий 10 признаков, из которых 3 являются категориальными, а остальные 7 — числовыми.
Удаление выбросов
Мы можем использовать функцию boxplot() для создания диаграмм и проверки наличия каких-либо выбросов в наборе данных.
Как мы видим, в наборе данных есть выбросы. Поэтому мы удаляем эти выбросы, используя метод IQR (или выбираем любой другой метод по вашему выбору).
# IQR def remove_outlier_IQR(df, field_name): iqr = 1.5 * (np.percentile(df[field_name], 75) - np.percentile(df[field_name], 25)) df.drop(df[df[field_name] > ( iqr + np.percentile(df[field_name], 75))].index, inplace=True) df.drop(df[df[field_name] < (np.percentile( df[field_name], 25) - iqr)].index, inplace=True) return df
Печать формы фрейма данных до и после удаления выбросов с использованием IQR.
print('Shape of df before IQR:',df.shape) df2 = remove_outlier_IQR(df, 'carat') df2 = remove_outlier_IQR(df2, 'depth') df2 = remove_outlier_IQR(df2, 'price') df2 = remove_outlier_IQR(df2, 'table') df2 = remove_outlier_IQR(df2, 'height_mm') df2 = remove_outlier_IQR(df2, 'length_mm') df_final = remove_outlier_IQR(df2, 'width_mm') print('The Shape of df after IQR:',df_final.shape)
→ Форма df до IQR: (53940, 10)
→ Форма df после IQR: (46518, 10)
Кодирование категориальных признаков
В наборе данных есть 3 категориальных признака. Давайте напечатаем и посмотрим уникальные значения каждой функции.
print('Unique values of cat features:\n') print('color:', cat_df.color.unique()) print('cut_quality:', cat_df.cut_quality.unique()) print('clarity:', cat_df.clarity.unique())
Это уникальные значения категориальных признаков.
Поэтому для кодирования этих функций мы используем LabelEncoder и фиктивные переменные (или вы также можете использовать OneHotEncoder)
Мы можем использовать LabelEncoder() для преобразования cut_quality в числовые значения, такие как 0, 1, 2, ….. потому что cut_quality имеет порядковые данные.
# Label encoding using the LabelEncoder function from sklearn from sklearn.preprocessing import LabelEncoder label_encoder = LabelEncoder() df_final['cut_quality'] = label_encoder.fit_transform(df_final['cut_quality']) df_final.head(2)
Затем мы используем функцию get_dummies() из библиотеки pandas, чтобы получить фиктивные переменные для категорий цвет и четкость.
# using dummy variables for the remaing categories df_final = pd.get_dummies(df_final,columns=['color','clarity']) df_final.head()
df_final.shape --> (46518, 23)
Разделение данных для обучения и тестирования
Разделяем данные для обучения и тестирования с помощью метода train_test_split() из библиотеки sklearn. Размер test_size остается равным 25% от исходного набора данных.
data = df_final.copy() # Using sklearn for scaling and splitting from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split X = data.drop(columns=['price']) y = data['price'] # Scaling the data scaler = StandardScaler() scaled_df = scaler.fit_transform(X) X_train, X_test, y_train, y_test = train_test_split( scaled_df, y, test_size=0.25) print("X train shape: {} and y train shape: {}".format( X_train.shape, y_train.shape)) print("X test shape: {} and y test shape: {}".format(X_test.shape, y_test.shape))
Модель Sklearn KNN
Сначала мы используем модель регрессора KNN от sklearn. Для выбора оптимального значения k мы повторяем цикл for, устанавливая значение k от 1 до 10. В нашем случае полученное оптимальное значение k равно 5. Таким образом, используя это значение k = 5, мы обучаем модель, делаем прогнозы и печатаем прогнозы. ценности.
# Finding the optimal k value from sklearn import neighbors from sklearn.metrics import mean_squared_error from math import sqrt import matplotlib.pyplot as plt rmse_val = [] for K in range(10): K = K+1 model = neighbors.KNeighborsRegressor(n_neighbors=K) model.fit(X_train, y_train) pred = model.predict(X_test) error = sqrt(mean_squared_error(y_test, pred)) rmse_val.append(error) print('RMSE value for k = ', K, 'is:', error)
# Using the optimal k value. from sklearn import neighbors model = neighbors.KNeighborsRegressor(n_neighbors=5) model.fit(X_train, y_train) # fit the model pred = model.predict(X_test) pred
После sklearn мы переходим к кодированию нашей собственной модели KNN из sklearn с использованием NumPy и pandas.
Модель KNN с нуля
Мы конвертируем данные поезда и теста в массивы NumPy. Затем мы объединяем X_train и y_train в матрицу. Матрица будет содержать 22 столбца данных X_train и 1 столбец y_train в конце (т.е. последний столбец).
train = np.array(X_train) test = np.array(X_test) y_train = np.array(y_train) # reshaping the array from columns to rows y_train = y_train.reshape(-1, 1) # combining the training dataset and the y_train into a matrix train_df = np.hstack([train, y_train]) train_df[0:2]
Теперь для каждой строки (точки данных) набора тестовых данных мы находим евклидово расстояние между каждой точкой данных поезда и точкой тестовых данных. Мы используем цикл for для перебора каждой точки тестового набора данных, чтобы найти расстояния и сложить их в обучающий набор данных train_df соответственно.
Шаги:
- Мы находим расстояния между одной контрольной точкой и каждой точкой набора данных поезда.
- Мы изменяем расстояния, используя reshape(-1,1), чтобы преобразовать это в массив из 1 столбца и 11630 строк.
- Затем с помощью np.hstack() мы складываем этот массив расстояний в набор данных train_df.
- Теперь мы сортируем эту матрицу от меньшего к большему на основе столбца расстояния.
- Затем мы берем значения y_train из первых 5 строк и берем их среднее значение, чтобы получить значение прогноза.
- Мы повторяем описанные выше шаги для каждой контрольной точки и прогнозируем значения соответственно и сохраняем эти значения в массиве.
preds = [] for i in range(len(test)): distances = np.sqrt(np.sum((train - test[i])**2, axis = 1)) distances = distances.reshape(-1,1) matrix = np.hstack([train_df, distances]) sorted_matrix = matrix[matrix[:,-1].argsort()] neighbours = [sorted_matrix[i][-2] for i in range(5)] pred_value = np.mean(neighbours) preds.append(pred_value) knn_scratch_pred = np.array(preds) knn_scratch_pred
Сравнение Sklearn и нашей модели KNN
Для сравнения значений прогноза, полученных от sklearn и нашего метода knn_method, мы создаем фрейм данных pandas pred_df, как показано в коде ниже.
sklearn_pred = pred.reshape(-1,1) my_knn_pred = knn_scratch_pred.reshape(-1,1) predicted_values = np.hstack([sklearn_pred,my_knn_pred]) pred_df = pd.DataFrame(predicted_values,columns=['sklearn_preds','my_knn_preds']) pred_df
Мы видим, что предсказанные значения нашего knn_algorithm в точности аналогичны значениям, полученным с помощью библиотеки sklearn. Это показывает, что наша интуиция и метод верны и очень точны.
Полный файл кода и набор данных можно найти на Github.
Подпишитесь на Dipankar Medhi, чтобы узнать больше 🚀потрясающих материалов о машинном обучении и науке о данных.