Numpy, продукт Hadmard в вертикальном стеке 1D-массивов, значительно быстрее, чем циклический просмотр списка 1D-массивов и выполнение продукта Hadamard (поэлементно) для каждого (что имеет смысл, и я проверял его в любом случае),
У меня есть ситуация, в которой мне нужно выполнить произведение Адамара между одним набором массивов numpy и другим следующим образом:
stacked_arrays = np.vstack([1D-arrays...])
stacked_arrays *= np.power(factor, np.arange(1, num_arrays))
Однако Мне нужна эта операция, чтобы изменитькаждый компонент 1D массива в списке , и эта операция должна происходить много раз.Я знаю, что это звучит как странная особенность, но есть ли способ сделать это без цикла вроде:
factors = factor ** np.arange(1, num_arrays)
for array, f in zip([1D..arrays], factors):
array *= f
или без снятия с учета результата операции?
Также map
не может использоваться, поскольку map
создает копии массивов numpy следующим образом:
result = map(lambda x, y: x * y, zip([1D..arrays], factors))
, поскольку вы не можете сделать *=
с lambda
, возвращается список массивов numpy, оставляя оригиналы
Есть ли способ заставить np.vstack
по-прежнему ссылаться на старые массивы компонентов каким-либо образом, или альтернативный способ достижения скорости продукта Адамара между массивами, которые равны stacked
, при мутировании непакетированных массивов??Так как некоторое время может быть сэкономлено, если не нужно выполнять unstacking (np.split
).
Результаты TimeIt:
m = []
for _ in range(100):
m.append(np.array([1, 2, 4, 5], dtype=np.float64))
factors = np.expand_dims(np.power(2, np.arange(100, dtype=np.float64)), axis=1)
def split_and_unstack():
l = np.vstack(m)
l *= factors
result = np.split(l, 100)
def split_only():
l = np.vstack(m)
l *= factors
print(timeit.timeit(split_and_unstack, number=10000))
# 1.8569015570101328
print(timeit.timeit(split_only, number=10000))
# 0.9328480050317012
# makes sense that with unstacking it is about double the time
Уточнение: список [1D массивов], упомянутых выше,подсписок большего списка 1D массивов.Этот большой список collections.deque
.И это deque
должно быть перетасовано перед извлечением подсписка (то есть это буфер воспроизведения опыта для стохастического градиентного спуска).
Буфер pop
и append
скорость:
times = int(1e4)
tgt = np.array([1, 2, 3, 4])
queue = collections.deque([tgt] * times, maxlen=times)
reg_list = [tgt] * times
numpy_list = np.array([tgt] * times)
def pop():
queue.pop()
def pop_list():
reg_list.pop()
def pop_np():
global numpy_list
numpy_list = numpy_list[1:]
print(timeit.timeit(pop, number=times))
# 0.0008135469979606569
print(timeit.timeit(pop_list, number=times))
# 0.000994370027910918
print(timeit.timeit(pop_np, number=times))
# 0.0016436030273325741
def push():
queue.append(tgt)
def push_list():
reg_list.append(tgt)
numpy_list = np.array([tgt] * 1)
def push_np():
numpy_list[0] = tgt
print(timeit.timeit(push, number=times))
# 0.0008797429618425667
print(timeit.timeit(push_list, number=times))
# 0.00097957398975268
print(timeit.timeit(push_np, number=times))
# 0.003331452957354486