KneighborsClassifier, дающий другое евклидово значение, чем linalg.norm и scipy.spatial.distance.euclidean - PullRequest
0 голосов
/ 07 марта 2019

Я пытаюсь реализовать классификатор ближайших соседей в наборе mnist .
Я попытался проверить свои результаты, сравнив его со Scipy KNeighborsClassifier

Для проверки я использую первые 6 образцов в обучающем наборе и нахожу 6 ближайших соседей первого образца в обучающем наборе.
Расстояние, которое я вычисляю, не совпадает с расстоянием, заданным библиотекой KNeighborsClassifier.
Я не могу понять, почему мои значения различаются.

Я упоминал этот вопрос для получения евклидова расстояния.

Мой код:

from mlxtend.data import loadlocal_mnist
import numpy as np
from scipy.spatial import distance

train, train_label = loadlocal_mnist(
        images_path='train-images.idx3-ubyte', 
        labels_path='train-labels.idx1-ubyte')
train_label = train_label.reshape(-1, 1)

train = train[:6, :]
train_label = train_label[:6, :]
# print(train_label)

test = train.copy()
test_label = train_label.copy()

test = test[:1, :]
test_label = test_label[:1, :]

for test_idx, test_row in enumerate(test):
    for train_idx, train_row in enumerate(train):
        d1 = np.linalg.norm(train_row - test_row)
        d2 = distance.euclidean(train_row, test_row)
        d3 = (((train_row - test_row)**2).sum())**0.5
        d4 = np.dot(train_row - test_row, train_row - test_row)**0.5
        print(train_idx, d1, d2, d3, d4)

Тестовый набор - это только первый ряд набора поездов

Выходные данные для вышеупомянутого:

0 0.0 0.0 0.0 0.0
1 2618.6771469579826 2618.6771469579826 140.3923074815711 15.937377450509228
2 2372.0210791643485 2372.0210791643485 134.29817571359635 10.770329614269007
3 2139.966354875702 2139.966354875702 122.37646832622684 11.313708498984761
4 2485.1432554281455 2485.1432554281455 135.5322839769182 13.892443989449804
5 2582.292392429641 2582.292392429641 144.69968901141425 14.212670403551895

И это код KNeighborsClassifier, с которым я сравниваю:

neigh = KNeighborsClassifier(n_neighbors=6)
neigh.fit(train, train_label)
closest = neigh.kneighbors(test[0].reshape(1, -1))
print(closest)

Вывод:

(array([[   0.        , 2387.11164381, 2554.81975881, 2582.29239243,
        2672.46721215, 2773.14911247]]), array([[0, 1, 3, 5, 4, 2]], dtype=int64))

Я пытаюсь вычислить евклидово расстояние между точками данных, чтобы найти ближайших соседей.d1, d2, d3, d4 - это 4 различных подхода, которые я нашел из вопроса, связанного выше, и выходные данные являются их конкретными значениями.
Но значение расстояния, которое я получаю из KNeighborsClassifier, отличается от всех этих, в которых также используется евклидово расстояние, как указано в документации,Почему это происходит?

Ответы [ 2 ]

1 голос
/ 08 марта 2019

Хорошо, вот подсказка (в настоящее время у вас нет времени, чтобы посмотреть его дальше, и это может быть полезно):

Конечно, что-то очень неправильно в первом способе вычисления расстояний (возможно, вспособ нарезки исходных данных);чтобы увидеть это, давайте изменим ваши циклы так:

for test_idx, test_row in enumerate(test):
    for train_idx, train_row in enumerate(train):
        d1 = np.linalg.norm(train_row - test_row)
        d2 = np.linalg.norm(test_row - train_row)
        d3 = distance.euclidean(train_row, test_row)
        d4 = distance.euclidean(test_row, train_row)
        print(train_idx, d1, d2, d3, d4)

Здесь, очевидно, мы должны иметь d1 = d2 = d3 = d4;но результаты:

0 0.0 0.0 0.0 0.0
1 2618.6771469579826 2213.268623552053 2618.6771469579826 2213.268623552053
2 2372.0210791643485 2547.0901044132693 2372.0210791643485 2547.0901044132693
3 2139.966354875702 2374.7201940439213 2139.966354875702 2374.7201940439213
4 2485.1432554281455 2467.6727903026367 2485.1432554281455 2467.6727903026367
5 2582.292392429641 2449.1912951013032 2582.292392429641 2449.1912951013032

т.е. это d1 = d3 и d2 = d4, но эти две величины различны между ними;это, конечно, не должно происходить, поскольку расстояние является симметричной функцией, и порядок аргументов не должен играть никакой роли:

a = np.array((1, 2, 3))
b = np.array((4, 5, 6))
distance.euclidean(a, b)
# 5.196152422706632
distance.euclidean(b, a)
# 5.196152422706632
np.linalg.norm(a-b)
# 5.196152422706632
np.linalg.norm(b-a)
# 5.196152422706632

Пища для размышлений - надеюсь, это поможет ...

0 голосов
/ 08 марта 2019

Я не уверен, что вызвало это, но преобразование данных из np.array в список, а затем обратно в np.array, по-видимому, решило проблему.

train = np.array(train.tolist())
test = np.array(test.tolist())

Спасибо @desertnaut за идею, что проблема может заключаться в разрезании данных, но я до сих пор не могу точно сказать, в чем причина проблемы.

...