У меня есть эти данные, которые выглядят следующим образом.

                [column 1]   [column 2]   [column 3]   [column 4]   [column 5]
[row 1]        (some value)
[row 2]
[row 3]
...
[row 700 000]

И второй набор данных, который выглядит точно так же, но с меньшим количеством строк около 4. Я хотел бы рассчитать евклидово расстояние между каждыми данными в наборе данных 1 и 2 и найти минимальное значение 4, как показано здесь: введите описание изображения здесь

Затем это повторяется для остальной части 700000 rows данных. Я знаю, что не рекомендуется перебирать массивы numpy, следовательно, есть ли способ рассчитать минимальное расстояние 4 различных строк из набора данных 2, подаваемого в 1 строку набора данных 1?

Извиняюсь, если это сбивает с толку, но мои главные моменты в том, что я не хочу перебирать массив и пытаюсь найти лучший способ решения этой проблемы.

В конце я должен получить обратно 700 000 строк на 1 столбец данных с наилучшим (самым низким) значением из 4 зеленых полей набора данных 2.

import numpy as np

a = np.array([ [1,1,1,1] , [2,2,2,2] , [3,3,3,3] ])
b = np.array( [ [1,1,1,1] ] )

def euc_distance(array1, array2):
    return np.power(np.sum((array1 - array2)**2, axis = 1) , 0.5)
print(euc_distance(a,b))
# this prints out [0 2 4]

Однако, когда я попытался ввести более одного измерения,

a = np.array([ [1,1,1,1] , [2,2,2,2] , [3,3,3,3] ])
b = np.array( [ [1,1,1,1] , [2,2,2,2] ] )

def euc_distance(array1, array2):
    return np.power(np.sum((array1 - array2)**2, axis = 1) , 0.5)
print(euc_distance(a,b))
# this throws back an error as the dimensions are not the same

Я ищу способ превратить его в своего рода трехмерный массив, где я получаю массив [[euc_dist([1,1,1,1],[1,1,1,1]), euc_dist([1,1,1,1],[2,2,2,2])] , ... ]

1
Axois 29 Июн 2019 в 13:13

3 ответа

Лучший ответ

Вы можете использовать трансляцию для этого:

a = np.array([
    [1,1,1,1],
    [2,2,2,2],
    [3,3,3,3]
])
b = np.array([
    [1,1,1,1],
    [2,2,2,2]
])

def euc_distance(array1, array2):
    return np.sqrt(np.sum((array1 - array2)**2, axis = -1))

print(euc_distance(a[None, :, :], b[:, None, :]))
# [[0. 2. 4.]
#  [2. 0. 2.]]

Сравнение времени для набора данных вашего размера:

a = np.random.rand(700000, 4)
b = np.random.rand(4, 4)

c = euc_distance(a[None, :, :], b[:, None, :])
d = np.array([euc_distance(a, val) for val in b])
e = np.array([euc_distance(val, b) for val in a]).T

np.allclose(c, d)
# True
np.allclose(d, e)
# True

%timeit euc_distance(a[None, :, :], b[:, None, :])
# 113 ms ± 4.56 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit np.array([euc_distance(a, val) for val in b])
# 115 ms ± 4.32 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit np.array([euc_distance(val, b) for val in a])
# 7.03 s ± 216 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
1
Nils Werner 1 Июл 2019 в 11:17

Не могу проверить это, но это должно привести вас к предположению нормализованных положительных данных. np.argmax (np.matmul (a, b.T), ось = 1)

Небольшая проработка моего предыдущего поста. Если производительность все еще остается проблемой, вместо вашего подхода вы можете использовать это:

b = np.tile(b, (a.shape[0], 1, 1))
a = np.tile(a, (1, 1, b.shape[1])).reshape(b.shape)
absolute_dist = np.sqrt(np.sum(np.square(a - b), axis=2))

Он дает точно такой же результат, но работает примерно в 20 раз быстрее на 600 000 строк, чем генератор.

1
lmielke 1 Июл 2019 в 10:57

Спасибо всем за помощь, однако я думаю, что мне удалось решить мою собственную проблему, используя простое понимание списка. Я слишком усложнял вещи! Таким образом, вместо того, чтобы повторять все данные, я существенно сокращаю время, которое увеличивается в два раза, что увеличивается в геометрической прогрессии.

То, что я сделал, было следующим {{Х0}} кто знал, что эта проблема может иметь такое простое решение!

0
Axois 29 Июн 2019 в 16:35