الگوریتم KNN در کلاس بندی

الگوریتم KNN در کلاس بندی

knn
هوش مصنوعي یادگیری ماشین

الگوریتم KNN در کلاس بندی

الگوریتم K نزدیک ترین همسایگی (KNN)

یکی از ساده ترین روش های بازشناسی الگو مبتنی بر یادگیری ماشین ، به منظور دسته بندی (Classification) و رگرسیون داده ها، می توان به الگوریتم K نزدیک ترین همسایگی اشاره نمود. سادگی الگوریتم K Nearest Neighbors از نظر پیاده سازی مورد توجه می باشد. اما این سادگی به قیمت تحمیل زمان زیاد محاسبات بلاخص در داده های حجیم، خواهد بود.

توجه اصلی این الگوریتم بر روی k تعداد، از نزدیک ترین داده ها به داده ناشناخته می باشد. اگر مقدار k برابر با یک فرض شود، در واقع اشاره به الگوریتم نزدیک ترین همسایگی خواهد داشت. در این حالت تنها یکی از نزدیک ترین داده ها به داده ناشناخته مبنای مشخص کردن کلاس داده خواهد بود.

روند کلی الگوریتم

به طور کی الگوریتم شامل سه فاز زیر می باشد:

  • دریافت داده‌های اولیه: که شامل بردارهایی در یک فضای چند بعدی هستند که هر کدام شامل برچسبی به نام دسته می‌باشند.
  • فاز یادگیری: الگوریتم، شامل ذخیره‌سازی بردارهای ویژگی و برچسب دسته نمونه‌های اولیه است.
  • فاز دسته بندی: که داده های ناشناخته و بدون برچسب با توجه به فاصله اش از k نزدیک‌ترین همسایه برچسب گذاری می شوند.

به منظور درک الگوریتم کافیست مراحل مثال زیر را برای اختصاص داده ناشناخته به دو کلاس شناخته شده به صورت مساله knn تعمیم دهیم:

initial data knn
شروع الگوریتم
calculate distance knn
محاسبه فاصله

معیارهای مختلفی برای محاسبه فاصله وجود دارد که پرکاربردترین آن‌ها عبارتند از:

۱. فاصله اقلیدسی (Euclidean Distance):
۲. فاصله منهتن (Manhattan Distance):
۳. فاصله مینکوفسکی (Minkowski Distance):

💡 نکته کلیدی: اگر p=1p=1 باشد فرمول به فاصله منهتن و اگر p=2 باشد به فاصله اقلیدسی تبدیل می‌شود.

choosing knn and calsification
انتخاب k همسایگی نزدیک
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# Create a small dataset
data = pd.DataFrame({
    "Feature_1": [1.0, 1.5, 2.0, 2.3,
                  4.0, 4.5, 5.0, 5.3,
                  7.0, 7.5, 8.0, 8.3],
    "Feature_2": [1.0, 2.0, 1.5, 2.5,
                  4.0, 5.0, 4.5, 5.5,
                  7.0, 8.0, 7.5, 8.5],
    "Class":     [0, 0, 0, 0,
                  1, 1, 1, 1,
                  2, 2, 2, 2]
})
print('raw data:\n',data)#
data.info()#
data.describe()#
# Select input features and class labels
X = data[["Feature_1", "Feature_2"]].to_numpy()
y = data["Class"].to_numpy()
print('feature  2d:',X)#
print('number of samples :',X.shape[0])#

print('class 1d:',y)#
print('unique classes :', np.unique(y))#
plt.figure(figsize=(8, 6))

colors = ['red', 'blue', 'green']
labels = ['Class 0', 'Class 1', 'Class 2']

plt.scatter(X[y == 0, 0], X[y == 0, 1], color='red',label='Class 0', s=100, edgecolors='black')
plt.scatter(X[y == 1, 0], X[y == 1, 1], color='blue',label='Class 1', s=100, edgecolors='black')
plt.scatter(X[y == 2, 0], X[y == 2, 1], color='green',label='Class 0', s=100, edgecolors='black')

'''for cls in [0, 1, 2]:
    plt.scatter(X[y == cls, 0], X[y == cls, 1], 
                color=colors[cls], 
                label=labels[cls], 
                s=100, edgecolors='black')
'''
plt.xlabel("Feature 1")
plt.ylabel("Feature 2")
plt.title("Visualization of 3-Class Dataset")
plt.legend()  # خیلی ساده، بدون هیچ آرگومان اضافه!
plt.grid(True, linestyle='--', alpha=0.5)
plt.show()

import numpy as np


n_test_per_class = 1  # one sample for every class

test_indices = []
train_indices = []

# find classes
unique_classes = np.unique(y)
print('unique_classes',unique_classes)

for cls in unique_classes:
    # find indecs of the special class
    cls_indices = np.where(y == cls)[0]
    print('cls_indices',cls_indices)

    # shuffling indeces
    #np.random.shuffle(cls_indices)
    #shuffled_cls_indices = cls_indices
    shuffled_cls_indices = np.random.permutation(cls_indices)
    print('shuffled_cls_indices',shuffled_cls_indices)
    
    # splitting data for test and train 
    test_indices.extend(shuffled_cls_indices[:n_test_per_class])
    train_indices.extend(shuffled_cls_indices[n_test_per_class:])

print(test_indices)
print(train_indices)
# حالا داده‌ها رو تفکیک می‌کنیم:
X_train, X_test = X[train_indices], X[test_indices]
y_train, y_test = y[train_indices], y[test_indices]

print("تعداد هر کلاس در داده آموزش:", np.bincount(y_train))
print("تعداد هر کلاس در داده تست:", np.bincount(y_test))

# Find minimum and maximum values using training data only
min_values = X_train.min(axis=0)
max_values = X_train.max(axis=0)

# Scale values to the range 0 to 1
X_train_scaled = (X_train - min_values) / (max_values - min_values)
X_test_scaled = (X_test - min_values) / (max_values - min_values)

#print("X_train_scaled:", X_train_scaled)
print("X_test_scaled:\n", X_test_scaled)
# Predict the class of one sample
def knn_predict_one(sample, X_train, y_train, k):
    # Calculate the distance from the sample to every training row
    distances = np.sqrt(np.sum((X_train - sample) ** 2, axis=1))

    # Get the indexes of the k closest rows
    nearest_indexes = np.argsort(distances)[:k]

    # Get the classes of the closest rows
    nearest_classes = y_train[nearest_indexes]

    # Count the votes for each class
    votes = np.bincount(nearest_classes)

    # Return the class with the most votes
    predicted_class = np.argmax(votes)

    return predicted_class


# Choose the number of neighbors
k = 3

# Predict the class for each test sample
predictions = []

for sample in X_test_scaled:
    prediction = knn_predict_one(sample, X_train_scaled, y_train, k)
    predictions.append(prediction)

predictions = np.array(predictions)
# Calculate accuracy
accuracy = np.mean(predictions == y_test)

print("Actual classes:   ", y_test)
print("Predicted classes:", predictions)
print("Accuracy:", accuracy)

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.neighbors import KNeighborsClassifier
from sklearn.metrics import accuracy_score, classification_report

# 1. Load the Iris dataset
iris = load_iris()
X, y = iris.data, iris.target

# 2. Split data into training and test sets
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)

# 3. Scale the features
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

# 4. Create the KNN model
knn = KNeighborsClassifier(n_neighbors=5)

# 5. Train the model
knn.fit(X_train_scaled, y_train)

# 6. Make predictions
y_pred = knn.predict(X_test_scaled)

# 7. Evaluate the model
accuracy = accuracy_score(y_test, y_pred)
print(f"Test Accuracy: {accuracy:.3f}")
print("\nClassification Report:")
print(classification_report(y_test, y_pred, target_names=iris.target_names))

الگوریتم KNN در متلب

برای این مثال از داده های فیشر ایریس استفاده شده است. این 4 نوع ویژگی برای 150 داده گل را در سه دسته {‘setosa’ ‘versicolor’ ‘virginica’} دسته بندی می کند. داده ها را به دو دسته آموزشی و تست دسته بندی می کنیم.
حلقه فور نوشته شده برای محاسبه فاصله هر داده تست از مجموعه داده های آموزشی می باشد. با دستور dist فاصله اقلیدسی محاسبه شده است. نتایج در نهایت با شمارش کل داده هایی که درست تشخیص داده شده اند به پایان می رسد.

load fisheriris
X = meas;
Y = cell2mat(species);
XLrn=X(1:2:150,1:4);
CLrn=Y(1:2:150,5);
XTst=X(2:2:150,1:4);
CTst=Y(2:2:150,5);
Correct=0;
for i=1:75
    d=dist(XLrn,XTst(i,:)');
    [m, Idx]=min(d);
    Cout=CLrn(Idx);
    if(Cout==CTst(i)) 
        Correct=Correct+1;
    end
end

دراین مثال تنها نزدیکترین همسایگی در نظر گرفته شده است. با دستور min کمترین فاصله را مشخص می کنیم. ( مقدار k برابر با یک در نظر گرفته ایم.)

انتخاب پارامتر طراحی k

برای تعیین پارامتر k برای کلاس های زوج، بهتر است از اعداد فرد انتخاب شود که از برابر شدن تعداد کلاس ها در داده ها با کمترین فاصله از داده های آموزشی اجتناب شود. بهترین انتخاب k بستگی به داده‌ها دارد؛ به‌طور کلی، مقادیر بزرگ k باعث کاهش خطا در طبقه‌بندی می‌شود، اما وضوح مرز بین کلاس‌ها را کمتر می‌کند.
همانطور که اشاره شد مقدار k برابر یک نیز الگوریتم نزدیک ترین همسایه نامیده می شود.

تابع knnclassify در متلب

همانطور که در کد بالا ذکر شد شما می توانید به صورت کد نویسی برنامه ای بنویسید که دسته بندی داده ها را برای حالت k بزرگتر از یک نیز حساب کند. اما متلب کار شما را با ارائه یک فانکشن با نام fitcknn راحت می کند. به عنوان مثال برای داده های زیر می توان از تابع به این صورت استفاده نمود:

%% generate train data
n = 25; % tedad data
x1 = [ randi([1 10],[1 n]) ; randi([1 10],[1 25])];
plot (x1(1,:),x1(2,:),'r*')
x2 = [ randi([11 20],[1 n]) ; randi([1 10],[1 n])];
hold on
plot (x2(1,:),x2(2,:),'b*')

Input =  [x1,x2]';
y1 = ones(1,n);
y2 = -ones(1,n);
Target = [y1,y2];
title('train data')
%% classifier knn
k = 1
knnmodel = fitcknn(Input,Target ,'NumNeighbors',k );

در کد بالا برای یک همسایگی مورد بررسی قرار گرفته است شما می توانیدبا دادن k های بیشتر از یک نیز همسایگی های بالاتر را مورد بررسی قرار دهید. خروجی دستور اخر کلاس داده های آموزشی را برای شما مشخص خواهد کرد.

دیدگاه (1)

  1. […] باشد. با توجه به توضیحات داده شده در آشنایی با الگوریتم knn (نزدیک ترین همسایه) با مفهوم محاسبه فاصله در داده های آموزشی آشنا شده […]

فکر خود را اینجا بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *