Вложенный цикл для массивов Python - PullRequest
1 голос
/ 29 июня 2019

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

                [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, как показано здесь: enter image description here

Это затем повторяется для остальных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]

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

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])] , ... ]

Ответы [ 3 ]

1 голос
/ 01 июля 2019

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

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 голос
/ 29 июня 2019

Не могу проверить это, но это должно привести вас к предположению нормализованных положительных данных. 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))

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

0 голосов
/ 29 июня 2019

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

То, что я сделал, было следующим c = np.array( [euc_distance(val, b) for val in a]) кто знал, что у этой проблемы может быть такое простое решение!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...