Python numpy:sqrt到位:这是一个bug吗?

Python numpy:sqrt到位:这是一个bug吗?,python,numpy,in-place,Python,Numpy,In Place,我尝试在数组的一部分上执行sqrt,使用布尔掩码进行选择 为什么这不起作用: import numpy as np a = np.array([[4,9],[16,25]], dtype='float64') np.sqrt(a[[True, False], :], out=a[[True, False], :]) print(a[[True, False], :]) # prints [[4, 9]], sqrt in place failed print('') b = np.zer

我尝试在数组的一部分上执行sqrt,使用布尔掩码进行选择

为什么这不起作用:

import numpy as np

a = np.array([[4,9],[16,25]], dtype='float64')

np.sqrt(a[[True, False], :], out=a[[True, False], :])
print(a[[True, False], :]) # prints [[4, 9]], sqrt in place failed

print('')

b = np.zeros_like(a[[True, False], :])
np.sqrt(a[[True, False], :], out=b)
print(b) # prints [[2, 3]] sqrt in b succeeded
如果我选择一个索引,这会起作用,但对我没有帮助,因为我想进行稀疏更新:

import numpy as np

a = np.array([[4,9],[16,25]], dtype='float64')

np.sqrt(a[0, :], out=a[0, :])
print(a[0, :]) # prints [2, 3]

print('')

b = np.zeros_like(a[0, :])
np.abs(a[0, :], out=b) # prints [2, 3]
print(b)

sqrt通常不在适当的位置工作。它返回修改后的数组。因此,您必须将行np.sqrta[[True,False],:],out=a[[True,False],:]替换为a=np.sqrta[[True,False],:],out=a[[True,False],:],以获得数组a中sqrt函数的结果。

sqrt通常不起作用。它返回修改后的数组。因此,您必须将行np.sqrta[[True,False],:],out=a[[True,False],:]替换为a=np.sqrta[[True,False],:],out=a[[True,False],:],以获得数组a中sqrt函数的结果。

相关部分对此进行了解释:

高级索引始终返回数据对比的副本,而基本切片则返回视图

使用布尔数组进行索引被认为是高级的,因此您总是会得到一个副本,修改它不会触及原始数据。事实上,在你的第一个例子中,b被修改了,但a没有。使用索引只返回一个视图,这就是修改原始数据的原因。

相关部分对此进行了解释:

高级索引始终返回数据对比的副本,而基本切片则返回视图


使用布尔数组进行索引被认为是高级的,因此您总是会得到一个副本,修改它不会触及原始数据。事实上,在你的第一个例子中,b被修改了,但a没有。使用索引只会返回一个视图,这就是修改原始数据的原因。

这个问题表明,在一个简单的切片上,就地平方根是可能的。因此,给定稀疏更新,可以在稀疏布尔掩码的真实元素上循环,在这样的切片上做适当的平方根

如果布尔掩码索引返回原始数组的视图,则效率不如假设的那样高,但这可能比没有要好

import numpy as np

a = np.array([[4,9],[16,25]], dtype='float64')

mask = np.array([True, False])

for (i,) in np.argwhere(mask):
    slice = a[i]
    np.sqrt(slice, out=slice)

print(a)
给出:

[[  2.   3.]
 [ 16.  25.]]

这个问题表明,在一个简单的切片上,就地平方根是可能的。因此,给定稀疏更新,可以在稀疏布尔掩码的真实元素上循环,在这样的切片上做适当的平方根

如果布尔掩码索引返回原始数组的视图,则效率不如假设的那样高,但这可能比没有要好

import numpy as np

a = np.array([[4,9],[16,25]], dtype='float64')

mask = np.array([True, False])

for (i,) in np.argwhere(mask):
    slice = a[i]
    np.sqrt(slice, out=slice)

print(a)
给出:

[[  2.   3.]
 [ 16.  25.]]

也许值得一提的是,大多数numpy操作都不到位。sqrt通常不到位-我不是有意粗鲁,但这是一个相当模糊的说法。执行np.sqrta,out=a确实有效,试试看。对于带有out参数的某些东西,这是不正确的,即它修改out in place。值得一提的是,大多数numpy操作都不在原位。sqrt通常不在原位工作-我无意粗鲁,但这是一个相当模糊的说法。执行np.sqrta,out=a确实有效,请尝试。对于带有out参数的某些东西,这是不正确的,例如,它会修改out in place,因为您正在传递=a[[true,False],:],这将创建一个带有新基础缓冲区的新数组,该数组会被丢弃,因为您没有在任何地方保留对它的引用。因为您正在传递=a[[true,False],:]这会创建一个新的数组,其中包含一个新的底层缓冲区,该缓冲区会被丢弃,因为您没有在任何地方保留对它的引用。我希望不是这样,因为如果索引表达式位于左侧,您可以对其执行就地操作,例如像[[True,False],:]+=1。@ZuzuCorneliu,因为基于项的设置不同于基于项的获取。基本上,在将[[True,False],:]传递给np之前,已经对其进行了评估。sqrt@ZuzuCorneliu这是不同的。如另一条评论所述,您编写的内容相当于[[True,False],:]=a[[True,False],:]+1,即您使用结果创建一个新数组并将其复制回原始数组array@BlackBear哇!多大的启示啊。你确定那是真的吗?当我在做[[真,假],:]+=1NP分配一个临时值?在这里,我很高兴地在我的代码中使用类似的东西,想知道为什么它仍然像垃圾一样慢,尽管我已经用部分索引表达式替换了for。如果numpy热衷于执行不必要的alloc/copy/do op/copy reach/free ops,那么当您需要访问部分稀疏数据时,您如何优化代码?@ZuzuCorneliu您可以通过创建一个非常大的矩阵来验证这一点,该矩阵约占RAM的30%,并在这样做时观察内存使用量加倍+=1,然后在操作完成后立即返回到初始级别,即正在进行垃圾收集的副本。尽量避免使用高级索引,或者您可以设法使用SCIPY提供的实际稀疏矩阵。这太令人伤心了。我希望不是这样,因为如果索引表达式位于左侧,您可以对其执行就地操作,例如。
像[[True,False],:]+=1。@ZuzuCorneliu因为基于项的设置不同于基于项的获取。基本上,在将[[True,False],:]传递给np之前,已经对其进行了评估。sqrt@ZuzuCorneliu这是不同的。如另一条评论所述,您编写的内容相当于[[True,False],:]=a[[True,False],:]+1,即您使用结果创建一个新数组并将其复制回原始数组array@BlackBear哇!多大的启示啊。你确定那是真的吗?当我在做[[真,假],:]+=1NP分配一个临时值?在这里,我很高兴地在我的代码中使用类似的东西,想知道为什么它仍然像垃圾一样慢,尽管我已经用部分索引表达式替换了for。如果numpy热衷于执行不必要的alloc/copy/do op/copy reach/free ops,那么当您需要访问部分稀疏数据时,您如何优化代码?@ZuzuCorneliu您可以通过创建一个非常大的矩阵来验证这一点,该矩阵约占RAM的30%,并在这样做时观察内存使用量加倍+=1,然后在操作完成后立即返回到初始级别,即正在进行垃圾收集的副本。尽量避免高级索引,或者您可以设法使用SCIPY中的实际稀疏矩阵。在这个问题之前,我有一个问题:。从这里可以看到答案,for-loop版本可能效率极低,甚至比数据拷贝更糟糕。速度差异的原因可能是,即使numpy进行数据复制,内部操作也针对连续数据和仅针对连续数据进行了很好的优化,这就是为什么他们实现了这样的高级索引,总是返回一个副本。遗憾的是,他们没有把重点放在稀疏的数据上。@zucorneliu啊,好吧,那太糟糕了。当你说稀疏时,我认为你的布尔掩码有几个真值和很多假值,所以如果你在np.argwheremask上循环,你就不会在很多元素上循环。也许我误解了。在这个问题之前,我有一个问题:。从这里可以看到答案,for-loop版本可能效率极低,甚至比数据拷贝更糟糕。速度差异的原因可能是,即使numpy进行数据复制,内部操作也针对连续数据和仅针对连续数据进行了很好的优化,这就是为什么他们实现了这样的高级索引,总是返回一个副本。遗憾的是,他们没有把重点放在稀疏的数据上。@zucorneliu啊,好吧,那太糟糕了。当你说稀疏时,我认为你的布尔掩码有几个真值和很多假值,所以如果你在np.argwheremask上循环,你就不会在很多元素上循环。也许我误解了。