понеділок, 11 жовтня 2021 р.

Реалізація алгоритму $k$-найближчих сусідів.

Ілюстрація на прикладі датасет wine який вже є в sklearn.
from sklearn import datasets
#завантажуємо dataset
wine = datasets.load_wine()
 
Дані можна при потребі передати в pandas
wine_pd=pd.DataFrame(data= wine.data, columns=wine.feature_names) 
Ці дані є результатами хімічного аналізу вин, вирощених в одному регіоні в Італії, але отриманих з трьох різних сортів винограду. Аналіз визначив 13 хімічних складових, знайдених у кожному з трьох типів вин і які знаходяться в колонках набору.
 # назви ознак 
print(wine.feature_names)
['alcohol', 'malic_acid', 'ash', 'alcalinity_of_ash', 'magnesium', 'total_phenols', 'flavanoids', 'nonflavanoid_phenols', 'proanthocyanins', 'color_intensity', 'hue', 'od280/od315_of_diluted_wines', 'proline']
 
В колонці target знаходиться номер типу - 0, 1, або 2 , до якого відноситься вино з даним хімічним аналізом. Данні записані в масивах 'data', 'target'.
wine.target
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2]) 
Розіб'ємо дані на навчальні і тестові.
#в scikit-learn
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(wine.data, wine.target, test_size=0.3) # 70\% тренувальна вибірка і  30\% тестова
# В  pandas вручну
f_target=df['y']
df_data=df.iloc[:,1:]
X_train, X_test, y_train, y_test = train_test_split(df_data, df_target, test_size=0.3) 
Навчаємо модель для кількості сусідів рівній 5 і виконуємо прогнозування на тестовому наборі. Щоб отримати прогнози для тестових даних, ми викликаємо метод predict. Для кожної точки тестового набору він знаходить її найближчих 5 сусідів в навчальному наборі і знаходить серед них клас який зустрічається найчастіше.
from sklearn.neighbors import KNeighborsClassifier
#Створюємо  KNN класифікатор
knn = KNeighborsClassifier(n_neighbors=5)
#Тренуєил модель на тренувальному  наборі
knn.fit(X_train, y_train)
#Виконуємо прогнозування на тестовому наборі
y_pred = knn.predict(X_test)
y_pred
[1 2 2 2 1 2 2 2 2 0 0 0 2 0 1 2 2 2 0 0 1 0 2 0 2 1 2 2 1 0 2 1 2 1 0 1 2
 1 2 1 0 0 2 1 0 1 2 0 1 2 1 2 1 0]
Для оцінки точності використаємо метрику metrics.accuracy_score, яка обчислює частку правильно класифікованих об'єктів з тестового набору $$ \frac{1}{n}\sum_{i=1}^n [y\_pred[i]=y\_test[i]]. $$ Якщо встановити параметр normalize=False, то метрика повертає загальну кількість елементів двох списків, які співпадають, наприклад
A = [0, 2, 1, 3]
B = [0, 1, 2, 3]
accuracy_score(A, B)
0.5
accuracy_score(A, B, normalize=False)
2
Оцінюємо точність моделі порівнюючи отримані результати з тестовим набором
from sklearn import metrics
print("Accuracy:",metrics.accuracy_score(y_test, y_pred))
Accuracy: 0.6666666666666666
Точність може сильно відрізнятися оскільки залежить від конкретного розбиття даних. Знаходимо при якій кількості сусідів точність найкраща
 X_train , X_test , y_train , y_test = train_test_split(wine.data, wine.target,test_size=0.25)
training_accuracy = []
test_accuracy=[]
# задаємо діапазон n_neighbors від 1 до 30
neighbors_settings = range(1, 30)
for n_neighbors in neighbors_settings:
# будуємо модель
    knn = KNeighborsClassifier(n_neighbors=n_neighbors)
    knn.fit(X_train, y_train)
    y_pred = knn.predict(X_test)
# записуємо точність на навчальному наборі
    training_accuracy.append(metrics.accuracy_score(y_test, y_pred))
# записуємо точність на тестовому  наборі
    test_accuracy.append(metrics.accuracy_score(y_train, y_train_pr))
#Знаходимо найкращу точність
print('Найкраща точність при k=',np.argmax(training_accuracy))
Будуємо графік точності
from matplotlib.pyplot import figure
figure(figsize=(10,8))
plt.plot(neighbors_settings, training_accuracy, label="точність на тестовому наборі")
#plt.plot(neighbors_settings, test_accuracy, label="точність на тестовому наборі")
plt.ylabel("Точність")
plt.xlabel("кількість сусідів")
plt.legend()
Форма графіків, їхнє взаємне розташування та оптимальне значення $k$ залежать від конкрентного розбиття на навчальну та тестову вибірки і можуть сильно відрізнятися від наведеного тут.

Немає коментарів:

Дописати коментар