У меня есть один большой массив, называемый набором данных в Numpy размеров (700, 28, 28, 3). Предположим, что эта матрица похожа на приведенную ниже:
>>> dataset=np.random.rand(5600,28,28,3)
>>> dataset.shape
(5600, 28, 28, 3)
Теперь предположим, что у меня есть другой массив, более простой, называемый запросом, который я буду использовать для поиска в массиве набора данных.
>>> query=np.random.rand(28,28,3)
>>> query.shape
(28, 28, 3)
Один из способов поиска этого матричного запроса в более крупном — вычислить среднеквадратичную ошибку между ним и всеми элементами набора данных массива. Меньший MSE говорит мне, где находится матрица в наборе данных массива.
Проблема в том, что я не хочу создавать цикл for в Python для вычисления MSE один за другим, сохранять MSE в другом массиве, а затем получать позицию наименьшего MSE, когда цикл заканчивается. У меня уже есть два цикла for перед этим сравнением, и поэтому я хотел бы сделать его максимально эффективным и быстрым. Можно ли решить такую проблему без большого цикла for?
Вы можете создать функцию сканера, которая сканирует набор данных с помощью map
, а затем извлекает минимальное местоположение MSE из полученной карты:
MSE_scanner = lambda A : ((query-A)**2).mean() # create the MSE comparison function
MSE_array = list(map(MSE_scanner, dataset)) # array of MSEs relevant to query
MSE_minimum = min(MSE_array) # extract the minimum MSE which should the one matched
query_location = MSE_array.index(MSE_minimum) # extract the location of the minimum MSE
Возможно, вы правы в том, что цикл for
наиболее эффективен. Это может быть быстрее, чем три ответа, опубликованные до сих пор (включая мой), потому что внутри (под капотом) все эти ответы выполняют несколько проходов (обходов) через длинную последовательность (по крайней мере, один обход для вычисления SE или MSE или евклидова расстояние. Затем, по крайней мере, еще один проход, чтобы найти минимум из них.) С помощью цикла for
за один проход вы можете вычислить SE, MSE или евклидово расстояние, а также следить за «бегущим минимумом». конце этого одного прохода, вы можете иметь позицию минимума.
Вы можете сделать это:
se = (dataset-query)**2 # Squared error - shape (L,28,28,3)
sum_of_se = np.sum(se.reshape(-1,28*28*3), axis=1) # Sum of squared error - shape (L,)
print (np.argmin(sum_of_se)) # Position of minimum within sum_of_se
Для этого вы можете использовать cdist с квадратом евклидова расстояния:
import numpy as np
from scipy.spatial.distance import cdist
dataset = np.random.rand(5600, 28, 28, 3)
query = np.random.rand(28, 28, 3)
res = cdist(query.reshape((1, -1)), dataset.reshape((5600, -1)), 'seuclidean')
print(np.argmin(res))
мое личное мнение, хотя это менее эффективно, чем хорошо написанный цикл for, и цикл for я считаю наиболее эффективным алгоритмическим способом, любая большая эффективность должна исходить от распараллеливания, а не от алгоритма, но я могу ошибаться, хотелось бы услышать другие мысли