Как разрешить sklearn K Nearest Neighbors взять пользовательскую метрику расстояния?

У меня есть специальная метрика расстояния, которую мне нужно использовать для KNN, K Nearest Neighbors.

Я пробовал следовать этому, но я не могу заставить его работать по какой-то причине.

Я бы предположил, что метрика расстояния должна принимать два вектора/массивы одинаковой длины, как я писал ниже:

import sklearn 
from sklearn.neighbors import NearestNeighbors
import numpy as np
import pandas as pd

def d(a,b,L):
    # Inputs: a and b are rows from a data matrix   
    return a+b+2+L

knn=NearestNeighbors(n_neighbors=1,
                 algorithm='auto',
                 metric='pyfunc',
                 func=lambda a,b: d(a,b,L)
                 )


X=pd.DataFrame({'b':[0,3,2],'c':[1.0,4.3,2.2]})
knn.fit(X)

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

ValueError: Unknown metric pyfunc. Valid metrics are ['euclidean', 'l2', 'l1', 'manhattan', 'cityblock', 'braycurtis', 'canberra', 'chebyshev', 'correlation', 'cosine', 'dice', 'hamming', 'jaccard', 'kulsinski', 'mahalanobis', 'matching', 'minkowski', 'rogerstanimoto', 'russellrao', 'seuclidean', 'sokalmichener', 'sokalsneath', 'sqeuclidean', 'yule', 'wminkowski'], or 'precomputed', or a callable

Тем не менее, я вижу то же самое в вопросе, который я привел. Любые идеи о том, как сделать эту работу на sklearn version 0.14? Я не знаю никаких различий в версиях.

Спасибо.

Ответ 1

Документация на самом деле довольно понятна в использовании аргумента метрики:

метрика: строка или вызываемый, по умолчанию 'minkowski

чтобы использовать для вычисления расстояния. Можно использовать любую метрику из scikit-learn или scipy.spatial.distance.

Если метрика является вызываемой функцией, она вызывается для каждой пары экземпляров (строк) и результирующего значения. Вызываемый должен возьмите два массива в качестве ввода и верните одно значение, указывающее расстояние между ними. Это работает для метрик Scipys, но менее эффективно чем передача имени метрики в виде строки.

Таким образом (как и в сообщении об ошибке), metric должен быть вызываемым, а не строковым. И он должен принимать два аргумента (массивы) и возвращать один. Какая ваша функция lambda.

Таким образом, ваш код можно упростить до:

import sklearn
from sklearn.neighbors import NearestNeighbors
import numpy as np
import pandas as pd

def d(a,b,L):
    return a+b+2+L

knn=NearestNeighbors(n_neighbors=1,
                 algorithm='auto',
                 metric=lambda a,b: d(a,b,L)
                 )
X=pd.DataFrame({'b':[0,3,2],'c':[1.0,4.3,2.2]})
knn.fit(X)