Как воспроизвести kneighbors_graph(include_self=True) с помощью KNeighborsTransformer в sklearn?

Моя конечная цель — заменить некоторые методы, использующие kneighbors_graph, на преобразователи из пакета sklearn-ann. Все методы в sklearn-ann реализованы как объекты-трансформеры, совместимые со sklearn. Однако функция, которую я пытаюсь заменить, использует kneighbors_graph(mode = "connectivity", include_self=True), и мне трудно преобразовать вывод расстояния с помощью include_self=False в матрицу связности этого типа. Не все объекты-трансформеры допускают режим подключения, включая self, но все обеспечивают доступ к расчетам расстояний без self.

Я могу воспроизвести kneighbors_graph(mode = "connectivity", include_self=True) из kneighbors_graph(mode = "distance", include_self=True) (обозначаемого nn_with_self). Однако я не могу воспроизвести его из kneighbors_graph(mode = "distance", include_self=False) (имеется в виду nn_without_self), что является тем же результатом, что и KNeighborsTransformer(mode = "distance").fit_transform.

Я вижу, что nn_without_self — это супернабор nn_with_self, но я не знаю, как внутренний алгоритм выбирает, какие поля сохраняются.

Как мне воссоздать nn_with_self из матрицы nn_without_self ниже?

Далее, как я могу все время работать с разреженными матрицами, не конвертируя их в плотные?

Я попытался просмотреть внутренний код, но это похоже на начало наследования классов, и я обнаружил, что просматриваю несколько файлов одновременно, теряя след на GitHub.

from sklearn.datasets import make_classification
from sklearn.neighbors import kneighbors_graph, KNeighborsTransformer

X, _ = make_classification(n_samples=10, n_features=4, n_classes=2, n_clusters_per_class=1, random_state=0)
n_neighbors=3

# Nearest neighbors
nn_with_self = kneighbors_graph(X, n_neighbors=n_neighbors, mode = "distance", metric = "euclidean", include_self=True,n_jobs=-1).todense()
nn_without_self = kneighbors_graph(X, n_neighbors=n_neighbors, mode = "distance", metric = "euclidean", include_self=False,n_jobs=-1).todense()
nn_from_transformer = KNeighborsTransformer(mode = "distance", n_neighbors=n_neighbors, metric = "euclidean", n_jobs=-1).fit_transform(X)

np.all(nn_from_transformer == nn_without_self)
# True

np.all(nn_with_self == nn_without_self)
# False

# Is `nn_with_self` symmetric?
np.allclose(nn_with_self,nn_with_self.T)
# False

# Is `nn_without_self` symmetric?
np.allclose(nn_without_self,nn_without_self.T)
# False

Вот реальные массивы:

nn_with_self
# matrix([[0.        , 0.70550439, 0.        , 0.20463097, 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.        , 0.        , 0.        , 0.51947869, 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.44145655],
#         [0.        , 0.        , 0.        , 0.        , 0.50025504,
#          0.        , 0.        , 0.        , 0.49481662, 0.        ],
#         [0.20463097, 0.51947869, 0.        , 0.        , 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.        , 0.        , 0.50025504, 0.        , 0.        ,
#          0.        , 0.        , 0.        , 0.34132965, 0.        ],
#         [0.        , 0.88867318, 0.        , 0.        , 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.44956691],
#         [0.        , 0.        , 1.10390699, 0.        , 1.52953542,
#          0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.        , 0.        , 0.        , 0.        , 0.        ,
#          3.62670755, 0.        , 0.        , 0.        , 3.83571739],
#         [0.        , 0.        , 0.49481662, 0.        , 0.34132965,
#          0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.        , 0.44145655, 0.        , 0.        , 0.        ,
#          0.44956691, 0.        , 0.        , 0.        , 0.        ]])

nn_without_self
# matrix([[0.        , 0.70550439, 0.        , 0.20463097, 1.02852831,
#          0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.70550439, 0.        , 0.        , 0.51947869, 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.44145655],
#         [0.        , 0.        , 0.        , 0.        , 0.50025504,
#          0.        , 1.10390699, 0.        , 0.49481662, 0.        ],
#         [0.20463097, 0.51947869, 0.        , 0.        , 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.95611187],
#         [1.02852831, 0.        , 0.50025504, 0.        , 0.        ,
#          0.        , 0.        , 0.        , 0.34132965, 0.        ],
#         [0.        , 0.88867318, 0.        , 1.40547465, 0.        ,
#          0.        , 0.        , 0.        , 0.        , 0.44956691],
#         [0.        , 0.        , 1.10390699, 0.        , 1.52953542,
#          0.        , 0.        , 0.        , 1.59848513, 0.        ],
#         [0.        , 4.1280709 , 0.        , 0.        , 0.        ,
#          3.62670755, 0.        , 0.        , 0.        , 3.83571739],
#         [1.36553076, 0.        , 0.49481662, 0.        , 0.34132965,
#          0.        , 0.        , 0.        , 0.        , 0.        ],
#         [0.        , 0.44145655, 0.        , 0.95611187, 0.        ,
#          0.44956691, 0.        , 0.        , 0.        , 0.        ]])
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
119
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

В следующем коде операции выполняются с использованием разреженных матриц на протяжении всего процесса. Результирующая разреженная матрица nn_with_self_sparse включает в себя как k-соседей, так и самосоединения без необходимости преобразования в плотную матрицу в любой точке.

import numpy as np
from sklearn.datasets import make_classification
from sklearn.neighbors import KNeighborsTransformer
from scipy.sparse import coo_matrix, diags

# Create a sample dataset
X, _ = make_classification(n_samples=10, n_features=4, n_classes=2, n_clusters_per_class=1, random_state=0)
n_neighbors = 3

# Generate the kneighbors graph without self-connections
knn_transformer = KNeighborsTransformer(n_neighbors=n_neighbors, mode = "distance", metric = "euclidean", n_jobs=-1)
knn_transformer.fit(X)
nn_without_self = knn_transformer.transform(X)

# Create a sparse diagonal matrix for self-connections with zero distance
num_samples = X.shape[0]
self_connections = diags([0] * num_samples, offsets=0, shape=(num_samples, num_samples), format='coo')

# Combine the k-neighbors graph without self-connections and the self-connections matrix
nn_with_self_sparse = nn_without_self + self_connections

print("Sparse matrix with self-connections:")
print(nn_with_self_sparse)


Ответ принят как подходящий

Просто сделайте n_neighbors - 1 ради include_self=True.

from sklearn.datasets import make_classification
from sklearn.neighbors import kneighbors_graph, KNeighborsTransformer

X, _ = make_classification(n_samples=10, n_features=4, n_classes=2, n_clusters_per_class=1, random_state=0)
n_neighbors=3

# Nearest neighbors
nn_with_self = kneighbors_graph(X, n_neighbors=n_neighbors, mode = "distance", metric = "euclidean", include_self=True,n_jobs=-1).todense()
nn_from_transformer = KNeighborsTransformer(mode = "distance", n_neighbors=n_neighbors - 1, metric = "euclidean", n_jobs=-1).fit_transform(X).todense()

np.allclose(nn_from_transformer, nn_with_self)
# True

Другие вопросы по теме