1. Вычислим расстояния с помощью NumPy.

import numpy as np

 

X = np.array([3, 4])

 

points = np.array([

    [3, 5],

    [6, 8],

    [4, 4]

])

 

classes = np.array([0, 1, 0])

 

distances = np.linalg.norm(points - X, axis=1)

 

nearest_index = np.argmin(distances)

 

print("Расстояния:", distances)

print("Минимальное расстояние:", distances.min())

print("Ближайший сосед:", points[nearest_index])

print("Прогнозируемый класс:", classes[nearest_index])

Результат:

Расстояния: [1. 5. 1.]

Минимальное расстояние: 1.0.

Ближайший сосед: [3, 5].

Прогнозируемый класс: 0.

Объекты [3, 5] и [4, 4] находятся на одинаковом минимальном расстоянии. Оба относятся к классу 0, поэтому прогноз не зависит от выбора одного из них.

2. Сравним результаты при разных значениях k.

import numpy as np

from sklearn.neighbors import KNeighborsClassifier

 

X_train = np.array([

    [1, 1],

    [2, 2],

    [3, 3],

    [4, 4],

    [5, 5]

])

 

y_train = np.array([1, 0, 0, 0, 1])

 

new_object = np.array([[1, 1]])

 

for k in [1, 3, 5]:

    model = KNeighborsClassifier(n_neighbors=k)

    model.fit(X_train, y_train)

 

    prediction = model.predict(new_object)

 

    print(f"k = {k}, класс = {prediction[0]}")

Результат:

k = 1, класс = 1.

k = 3, класс = 0.

k = 5, класс = 0.

При k = 1 решение определяется одним ближайшим объектом.

При k = 3 и k = 5 используется голосование нескольких соседей, поэтому результат может измениться.

Малое k повышает чувствительность к шуму, а большое k сглаживает границы классов.

В реальных задачах значение k выбирают с помощью перекрёстной проверки.

3. Сравним обычное и взвешенное среднее.

import numpy as np

from sklearn.neighbors import KNeighborsRegressor

from sklearn.pipeline import make_pipeline

from sklearn.preprocessing import StandardScaler

 

X_train = np.array([

    [1],

    [2],

    [3]

])

 

y_train = np.array([40, 50, 60])

 

new_object = np.array([[2.5]])

 

model_uniform = KNeighborsRegressor(

    n_neighbors=3,

    weights="uniform"

)

 

model_uniform.fit(X_train, y_train)

 

model_distance = KNeighborsRegressor(

    n_neighbors=3,

    weights="distance"

)

 

model_distance.fit(X_train, y_train)

 

pipeline = make_pipeline(

    StandardScaler(),

    KNeighborsRegressor(n_neighbors=3)

)

 

pipeline.fit(X_train, y_train)

 

print(

    "Обычное среднее:",

    model_uniform.predict(new_object)[0]

)

 

print(

    "Взвешенное среднее:",

    model_distance.predict(new_object)[0]

)

 

print(

    "Pipeline:",

    pipeline.predict(new_object)[0]

)

Результат:

Обычное среднее: 50.0.

Взвешенное среднее: приблизительно 51.43.

Pipeline: 50.0.

При обычном среднем все три соседа имеют одинаковое влияние на прогноз.

При взвешенном среднем более близкие объекты получают больший вес.

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