Python 类属性为iadd(+;=)和numpy.random.randn()的奇怪行为
我一直在用Python和Numpy对一个随机过程建模,并用以下代码目睹了奇怪的行为:Python 类属性为iadd(+;=)和numpy.random.randn()的奇怪行为,python,numpy,random,Python,Numpy,Random,我一直在用Python和Numpy对一个随机过程建模,并用以下代码目睹了奇怪的行为: import numpy as np class Example( object ): def __init__( self ): self.x = 0 def add_random( self ): self.x += np.random.randn(1) return self.x if __name__ == '__main__':
import numpy as np
class Example( object ):
def __init__( self ):
self.x = 0
def add_random( self ):
self.x += np.random.randn(1)
return self.x
if __name__ == '__main__':
example = Example()
state = []
for x in range(10):
state.append( example.add_random() )
print state
这将返回一个由10个相同的随机数组成的数组,而不是预期的10个不同的随机数。消除
对象。\uuuu iadd\uuuuu
运算符和/或用常量替换np.random.randn(.)
,将解决此问题。有人知道它的根是什么吗?您通过引用返回数组self.x
,因此您有10个指向同一数组的指针。每次修改数组时,所有十个指针都指向相同的修改版本
如果每次都要返回数组的单独副本,可以在add\u random
函数中return self.x.copy()
另一种修复方法是将
np.random.rand(1)
替换为np.random.rand()
soself.x
将保持标量而不是向上转换为数组。您通过引用返回数组self.x
,因此您有10个指向同一数组的指针。每次修改数组时,所有十个指针都指向相同的修改版本
如果每次都要返回数组的单独副本,可以在add\u random
函数中return self.x.copy()
另一种修复方法是将np.random.rand(1)
替换为np.random.rand()
,这样self.x
将保持标量而不是向上转换为数组。np.random.randn(1)
返回包含单个元素的数组:
In [27]: np.random.randn(1)
Out[27]: array([-1.90409169])
第一次执行此行时
self.x += np.random.randn(1)
self.x
——最初是Python整数——被numpy数组替换。该行的后续执行会就地修改x
,因为numpy数组就是这样实现就地加法的。因此return self.x
总是返回相同的数组。因此,您在主部分中创建的列表是一个包含重复10次的相同对象的列表
解决此问题的一种方法是使用np.random.randn()
而不是np.random.randn(1)
np.random.randn()
返回一个标量,因此赋值self.x+=np.random.randn(1)
每次执行时都会创建一个新的self.x
对象。np.random.randn(1)
返回一个包含单个元素的数组:
In [27]: np.random.randn(1)
Out[27]: array([-1.90409169])
第一次执行此行时
self.x += np.random.randn(1)
self.x
——最初是Python整数——被numpy数组替换。该行的后续执行会就地修改x
,因为numpy数组就是这样实现就地加法的。因此return self.x
总是返回相同的数组。因此,您在主部分中创建的列表是一个包含重复10次的相同对象的列表
解决此问题的一种方法是使用
np.random.randn()
而不是np.random.randn(1)
np.random.randn()
返回一个标量,因此赋值self.x+=np.random.randn(1)
每次执行时都会创建一个新的self.x
对象。WarrenWeckesser解释了问题的根源,但从根本上说,使用numpy
来实现这一点效率非常低。每次都要创建数组对象,这会带来很大的开销。相反,请使用random.gauss
注意,如果您想使用numpy
有效地执行此操作,那么只需使用np.random.randn(10).cumsum()
WarrenWeckesser解释了问题的根源,但从根本上说,使用numpy
执行此操作效率极低。每次都要创建数组对象,这会带来很大的开销。相反,请使用random.gauss
注意,如果您想使用numpy
有效地执行此操作,那么只需使用np.random.randn(10.cumsum()
谢谢–我将“整数”改为“标量”以使其更清晰。谢谢–我将“整数”改为“标量”以使其更清晰。