Прежде всего, ваше расстояние неверно.
Расстояния должны возвращать значения small для похожих векторов.Вы определили сходство , а не расстояние.
Во-вторых, использование наивного кода Python, такого как zip
, будет работать крайне плохо.Python просто плохо оптимизирует такой код, он выполнит всю работу в медленном интерпретаторе.Скорость Python хорошо, только если вы все векторизуете.И действительно, этот код можно векторизовать тривиально, и тогда, вероятно, даже не будет иметь значения, являются ли ваши входные данные двоичными или плавающими данными.То, что вы вычисляете очень сложным образом, - это не что иное, как произведение двух векторов, не так ли?
Это, ваше расстояние, вероятно, должно выглядеть так:
def distance(x, y):
return x.shape[0] - np.dot(x,y)
ИлиКакую бы дистанцию трансформацию вы намеревались использовать.
Теперь для вашей реальной проблемы: я предполагаю, что sklearn пытается ускорить ваше расстояние с помощью дерева шаров.Это не сильно поможет из-за плохой производительности обратных вызовов интерпретатора Python (на самом деле, вы, вероятно, должны предварительно вычислить всю матрицу расстояний в одной векторизованной операции - что-то вроде dist = dim - X.transpose().dot(X)
?из уравнения).Другие языки, такие как Java (например, инструмент ELKI), гораздо лучше расширить таким образом, потому что JIT-компилятор горячей точки может оптимизировать и встраивать такие вызовы везде.
Чтобы проверить гипотезу о том, что sklearn ball-дерево является причиной для нечетных значений, которые вы наблюдаете, попробуйте установить method="brute"
или около того (см. документацию), чтобы отключить дерево шаров.Но в конце вы захотите либо предварительно вычислить всю матрицу расстояний (если вы можете позволить себе затраты O (n²)), либо перейти на другой язык программирования (например, реализация расстояния в Cython помогает, но вы все равноскорее всего, данные внезапно станут массивами с плавающей точкой).