Входные размеры для функции расстояния для ближайших соседей


В контексте неконтролируемых ближайших соседей с scikit-learn я реализовал свою собственную функцию расстояния, чтобы иметь дело с моими неопределенными точками (т. е. точка представлена как нормальное распределение):

def my_mahalanobis_distance(x, y):

'''
x: array of shape (4,) x[0]: mu_x_1, x[1]: mu_x_2, 
                        x[2]: cov_x_11, x[3]: cov_x_22
y: array of shape (4,) y[0]: mu_ y_1, y[1]: mu_y_2,
                        y[2]: cov_y_11, y[3]: cov_y_22 
'''     

    cov_inv = np.linalg.inv(np.diag(x[:2])+np.diag(y[:2]))
    return sp.spatial.distance.mahalanobis(x[:2], y[:2], cov_inv)

Однако, когда я устанавливаю своих ближайших соседей:

nnbrs = NearestNeighbors(n_neighbors=1, metric='pyfunc', func=my_mahalanobis_distance)
nearest_neighbors = nnbrs.fit(X)

Где X - массив (N, 4) (n_samples, n_features), Если я напечатаю x и y в моем my_mahalanobis_distance, я получу формы (10,) вместо (4,), Как я ожидал.

Пример:

Я добавляю следующую строку к my_mahalanobis_distance:

print(x.shape)

Затем в моем основном:

n_features = 4
n_samples = 10
# generate X array:
X = np.random.rand(n_samples, n_features)
nnbrs = NearestNeighbors(n_neighbors=1, metric='pyfunc', func=my_mahalanobis_distance)
nearest_neighbors = nnbrs.fit(X)

Результат таков:

(10,)
ValueError: shapes (2,) and (8,8) not aligned: 2 (dim 0) != 8 (dim 0)
Я прекрасно понимаю ошибку, но я не понимаю, почему мой x.shape является (10,), в то время как мое число признаков составляет 4 в X.

Я использую Python 2.7.10 и scikit-learn 0.16.1.

Правка:

Замена return sp.spatial.distance.mahalanobis(x[:2], y[:2], cov_inv) на return 1 только для проверки возврата:

(10,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
Таким образом, только первый вызов my_mahalanobis_distanceневерен. Глядя на x и y значения на этой первой итерации, мои наблюдения:
  • x и y идентичны

  • Если я выполняю свой код несколько раз, x и y по-прежнему идентичны, но их значения изменились по сравнению с предыдущим запуском.

  • Эти значения, по-видимому, исходят из функции numpy.random.

Я бы сделал вывод, что такой первый вызов является отладочным фрагментом кода, который не был удален.
2 3

2 ответа:

Это не ответ, но слишком длинный для комментария. Я не могу воспроизвести ошибку.

Использование:

Python 3.5.2 и Sklearn 0.18.1

С кодом:

from sklearn.neighbors import NearestNeighbors
import numpy as np
import scipy as sp
n_features = 4
n_samples = 10
# generate X array:
X = np.random.rand(n_samples, n_features)


def my_mahalanobis_distance(x, y):    
    cov_inv = np.linalg.inv(np.diag(x[:2])+np.diag(y[:2]))
    print(x.shape)
    return sp.spatial.distance.mahalanobis(x[:2], y[:2], cov_inv)

n_features = 4
n_samples = 10
# generate X array:
X = np.random.rand(n_samples, n_features)
nnbrs = NearestNeighbors(n_neighbors=1, metric=my_mahalanobis_distance)
nearest_neighbors = nnbrs.fit(X)

Выход равен

(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)
(4,)

Я настроил свой my_mahalanobis_distance для решения этой проблемы:

def my_mahalanobis_distance(x, y):
    '''
    x: array of shape (4,) x[0]: mu_x_1, x[1]: mu_x_2, 
                            x[2]: cov_x_11, x[3]: cov_x_22
    y: array of shape (4,) y[0]: mu_ y_1, y[1]: mu_y_2,
                            y[2]: cov_y_11, y[3]: cov_y_22 
    '''     

    if (x.size, y.size) == (4, 4):        

        return sp.spatial.distance.mahalanobis(x[:2], y[:2], 
                                           np.linalg.inv(np.diag(x[2:]) 
                                           + np.diag(y[2:])))

    # to handle the buggy first call when calling NearestNeighbors.fit()
    else:
        warnings.warn('x and y are respectively of size %i and %i' % (x.size, y.size))
        return sp.spatial.distance.euclidean(x, y)