Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 数组列表上Hadamard的效率_Python_Arrays_Numpy - Fatal编程技术网

Python 数组列表上Hadamard的效率

Python 数组列表上Hadamard的效率,python,arrays,numpy,Python,Arrays,Numpy,numpy是一个一维数组垂直堆栈上的Hadamard产品,它比循环遍历一维数组列表并在每个数组上执行Hadamard(元素级)产品要快得多(这很有意义,我无论如何都对它进行了测试) 我需要在一组numpy阵列和另一组numpy阵列之间执行Hadamard乘积: stacked_arrays = np.vstack([1D-arrays...]) stacked_arrays *= np.power(factor, np.arange(1, num_arrays)) 然而,我需要这个操作来改变列

numpy是一个一维数组垂直堆栈上的Hadamard产品,它比循环遍历一维数组列表并在每个数组上执行Hadamard(元素级)产品要快得多(这很有意义,我无论如何都对它进行了测试)

我需要在一组numpy阵列和另一组numpy阵列之间执行Hadamard乘积:

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
创建numpy数组的副本,因此也不能使用
map

result = map(lambda x, y: x * y, zip([1D..arrays], factors))
由于无法使用
lambda
执行
*=
,因此将返回numpy数组列表,保留原始数组未经修改

有没有办法让
np.vstack
仍然以某种方式引用旧的组件数组,或者有另一种方法可以在对未堆叠的数组进行变异时,在
堆叠的
数组之间实现哈达玛积的速度?因为如果不需要进行拆垛(
np.split
),可以节省一些时间

时间结果:

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

让我们把这个问题分解一下。您希望有一个对数组的引用列表,这些数组都是可变的,但是您希望能够作为一个块对它们执行操作

我认为你的方法是倒退的。与其尝试将阵列打包和解包到单独的缓冲区中,不如将视图维护到单个缓冲区中

替换当前循环

m = [np.array([1, 2, 4, 5], dtype=np.float64) for _ in range(100)]
使用单个缓冲区,并查看每行:

buf = np.vstack([np.array([1, 2, 4, 5], dtype=np.float64) for _ in range(100)])
m = list(buf)  # check that m[0].base is b
现在您有了一个数组列表
m
,每个数组都可以单独修改。只要您保持修改到位并且不重新分配列表元素,所有更改都将直接显示在
buf
中。同时,您可以在
buf
上执行批处理计算,只要执行到位,
m
将反映所有更改

实际上,您甚至可能不需要
m
。注意
list(buf)
如何在区块的每一行中创建视图。您也可以轻松地直接索引到缓冲区中。例如,
m[3][8]
通常以
buf
作为
buf[3,8]
来编写,但您也可以使用
buf
是一个序列的事实来编写
buf[3][8]
。这效率较低,因为它每次都会创建一个新视图(
buf[3]
),但不会太高

要提取无序的行子集,还可以使用序列索引。假设您的缓冲区保留了最后的
M
行,您希望从中洗牌并提取
N
行的子序列。您可以通过创建一个索引数组并反复洗牌这些索引来实现这一点:

 indices = np.arange(M)

 # inside the loop:

 np.random.shuffle(indices)
 chunk = buf[indices[:N]]
 # do your math on `chunk`

只要
M
没有变化,并且您相信洗牌足够随机,您就不需要重新分配或重新排序
索引。

是什么阻止您将2D堆叠数组作为列表索引?“因为您不能使用lambda*=而不是
lambda x,y:x*y
(可以是
np.multiply
),尝试
lambda x,y:np.multiply(x,y,out=x)
。记住,
*=
返回
self
进行重新分配,就像
*
一样。@mad物理学家看到我对你的第一条评论的澄清。但是基于你所说的。我想我会把它作为一个2D堆叠数组,用
np.random.shuffle
进行洗牌,并使它充当
deque
do
2DArray=2DArray[-min(2DArray.shape[0]:,DEQUE_SIZE:,:]
每次追加新行后。问题是,您不需要将数据混洗,只需将索引放入其中。我已经用一些您可能会感兴趣/相关的细节更新了我的答案。我将把循环缓冲区的实现留给您。如果您发布任何相关问题,请告诉我。因此,关于循环,我意识到了一件事ar缓冲区,将2D数组转换为循环缓冲区牺牲了。我见过一些创建Numpy循环缓冲区和的实现。我做了一些测试(如上),比较了列表、deque和np.array的pop和append(实际上是setitem,因为它是循环缓冲区)更新:所以我确实找到了另一个使用numpy的循环缓冲区实现,它声称它比笔记本条目63中的
deque
:快。@dylan。为什么要使用append或insert?你拥有的块已经是一个循环缓冲区了。你只需要跟踪哪一行就可以了你正在写信,并且有一个标志会在缓冲区满后触发。在这一点上,它比deque有效得多。@dylan。因为最初的问题并不是很清楚你的目的,我建议你问另一个问题,展示你的研究,关于如何维护缓冲区。他已经在进行大量的范围爬行重新。