Python惰性求值numpy ndarray

6
我有一个大的二维数组,我希望只声明一次,并根据参数偶尔更改其中的一些值,而不必遍历整个数组。
为了构建这个数组,我使用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的实例。

然而,我需要在最后使用浮点数数组,但是用这种技巧无法将该数组简单地转换为dtype=float数组。我还尝试使用numpy视图,但对于dtype=object也不起作用。

你有更好的替代方案吗?我应该重写视图方法而不是getitem吗?

编辑未来可能需要使用Cython,因此如果您有涉及C指针的解决方案,我很感兴趣。


这是一种有趣的方法,但我不确定numpy数组是否适合它。通常情况下,当您使用numpy时,您会使用完整数组或切片进行矢量化操作,而不是逐个元素访问。以您的方式对ndarrays进行子类化,您基本上失去了所有快速numpy操作的优势。您最好从零开始创建自己的类,并将所有内容保存到纯Python结构(列表等)中。在性能方面,它将是可比较的。为什么您真正需要惰性评估?您可以使用高级索引有效地更改某些元素。 - rth
1
你只有一个单一的函数 f 吗?带有常量参数吗? - Bas Swinckels
2
你熟悉 scipy.sparse 吗?dok 格式是一个字典,(i,j) 元组作为键。这和 lil(列表的列表)是访问/更改选定项的两种最快方法。 - hpaulj
1
@hpaulj:dok非常有趣。但是,我无法像我上面展示的例子中那样使用dtype=object。请参见:https://github.com/scipy/scipy/issues/2528 - Damlatien
1
@rth:我需要惰性求值而不是通过键访问数组(即使效率很高),原因是每个赋值可能与不同类型的索引相关。对于上面的示例,我只设置了对角线为变量。例如,我还可以将一行(或更复杂的内容)分配给另一个函数g。 - Damlatien
显示剩余2条评论
1个回答

3
在这种情况下,将转换函数绑定到数组的每个索引位置是没有意义的。相反,更有效的方法是将转换定义为函数,并与它适用于的一部分数组一起使用。以下是一个基本实现:
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索引(逐元素访问、切片、花式索引等),同时将数据保留在具有本地数据类型(floatint等)的数组中,这比使用dtype ='object'更加高效。


谢谢,我已经将其基本实现为字典的子类,并且它基本上按照我想要的方式工作。然而,只是出于好奇,我想知道是否有可能用指针在C/C++中以更优雅的方式实现类似的东西?例如,可以声明一个(浮点)指针表,在声明时每个指针都会指向零或函数的结果,这样我就可以通过调用一个(或多个)函数来更新矩阵。 - Damlatien
但是要做到这一点,函数调用的指针必须绑定到一个特定的指针,我不确定是否可行。我希望我表达得足够清楚。 - Damlatien

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接