Поиск евклидова расстояния между всеми точками одной выборки и всеми точками другой
нужна помощь.
Прохожу курс по машинному обучению с нуля, где алгоритмы пишутся вручную. Как в методе ближайших соседей посчитать евклидово расстояние всех точек тестовой выборки до точек обучающей выборки? Сделал такое с помощью циклов, но вычисляется очень долго, хотелось бы узнать как переделать на броадкастинг.
def euclid(self, data1, data2):
d = []
for i in range(len(data1)):
d.append(sum((data2 - data1.iloc[i])**2) ** 0.5)
return d
def NN(self, X_test, X):
distance = [{self.y.iloc[i]: self.euclid(X_test, X.iloc[i])} for i in range(len(X))]
return distance
Ответы (1 шт):
Чтобы получить таблицу расстояний от каждой точки одной выборки к каждой точке другой, лучше перейти в numpy:
import numpy as np
import pandas as pd
def distance(data1, data2):
x = np.asarray(data1)[..., np.newaxis]
y = np.asarray(data2).T[np.newaxis, ...]
data = np.sum((x - y)**2, axis=1)**0.5
if isinstance(data1, pd.DataFrame) and isinstance(data2, pd.DataFrame):
data = pd.DataFrame(data, index=data1.index, columns=data2.index)
return data
Здесь мы транспонируем вторую таблицу и разводим индексы на две независимые оси (первую и третью), оставляя столбцы (значения по второй оси) в качестве объединяющей размерности.
Как результат, операция x - y вернет трехмерный массив, где крайние размерности указывают на точки исходных таблиц, а вдоль размерности между ними - векторы расстояний между точками. Координаты этих векторов мы суммируем, предварительно возведя в квадрат np.sum((x - y)**2, axis=1). После этого извлекаем квадратный корень, получив расстояния.
Замечу, что есть разные варианты, как перейти к numpy.ndarray. Например, если мы уверены, что исходные данные представлены только как pandas.DataFrame, то могли бы использовать df.to_numpy() или df.values. Использование numpy.asarray дает возможность работать с двумерными массивами разного типа, например с тем же ndarray или списком списков.
Пример:
data1 = [
[0, 0, 1],
[0, 1, 0],
[1, 0, 0],
[0, 1, 1],
[1, 0, 1],
[1, 1, 0],
]
data2 = [[0, 0, 0], [1, 1, 1]]
a, b = 1, 2**0.5
expected = [
[a, b],
[a, b],
[a, b],
[b, a],
[b, a],
[b, a],
]
assert np.isclose(distance(data1, data2), expected).all()
df1 = pd.DataFrame(data1, index=range(10, 70, 10), columns=[*'xyz'])
df2 = pd.DataFrame(data2, index=[100, 500], columns=[*'xyz'])
df_expected = pd.DataFrame(expected, df1.index, df2.index)
assert distance(df1, df2).equals(df_expected)
print(distance(df1, df2))
100 500
10 1.000000 1.414214
20 1.000000 1.414214
30 1.000000 1.414214
40 1.414214 1.000000
50 1.414214 1.000000
60 1.414214 1.000000