我有一个大型的2D数组,我想声明一次,并根据参数改变偶然只有一些值,而不遍历整个数组。
为了构建这个数组,我使用dtype=object
将numpy ndarray类子类化,并分配给我想要更改函数的元素,例如: :
def f(parameter):
return parameter**2
for i in range(np.shape(A)[0]):
A[i,i]=f
for j in range(np.shape(A)[0]):
A[i,j]=1.
然后我重写了__getitem__
方法,以便在可调用时返回给定参数的函数求值,否则返回值本身。
def __getitem__(self, key):
value = super(numpy.ndarray, self).__getitem__(key)
if callable(value):
return value(*self.args)
else:
return value
其中self.args
之前曾被赋予myclass的实例。
但是,我需要在最后使用float数组,我不能简单地使用这种技术将此数组转换为dtype=float
数组。我还尝试使用numpy视图,这对dtype=object
无效。
你有更好的选择吗?我应该覆盖视图方法而不是getitem吗?
编辑我将来可能不得不使用Cython,所以如果你有一个解决方案,例如C指针,我很感兴趣。
答案 0 :(得分:1)
在这种情况下,将转换函数绑定到数组的每个索引都没有意义。
相反,更有效的方法是将转换定义为函数,以及它应用的数组的子集。这是一个基本的实现,
import numpy as np
class LazyEvaluation(object):
def __init__(self):
self.transforms = []
def add_transform(self, function, selection=slice(None), args={}):
self.transforms.append( (function, selection, args))
def __call__(self, x):
y = x.copy()
for function, selection, args in self.transforms:
y[selection] = function(y[selection], **args)
return y
可以按如下方式使用:
x = np.ones((6, 6))*2
le = LazyEvaluation()
le.add_transform(lambda x: 0, [[3], [0]]) # equivalent to x[3,0]
le.add_transform(lambda x: x**2, (slice(4), slice(4,6))) # equivalent to x[4,4:6]
le.add_transform(lambda x: -1, np.diag_indices(x.shape[0], x.ndim), ) # setting the diagonal
result = le(x)
print(result)
打印,
array([[-1., 2., 2., 2., 4., 4.],
[ 2., -1., 2., 2., 4., 4.],
[ 2., 2., -1., 2., 4., 4.],
[ 0., 2., 2., -1., 4., 4.],
[ 2., 2., 2., 2., -1., 2.],
[ 2., 2., 2., 2., 2., -1.]])
通过这种方式,您可以轻松支持所有高级Numpy索引(逐元素访问,切片,花式索引等),同时将数据保存在具有本机数据类型(float
的数组中, int
等)比使用dtype='object'
更有效率。