【问题标题】:Python operating on multiple data arrays in a rolling windowPython 在滚动窗口中对多个数据数组进行操作
【发布时间】:2011-08-07 16:25:46
【问题描述】:

考虑以下代码:

class MyClass(object):

    def __init__(self):

        self.data_a = np.array(range(100))
        self.data_b = np.array(range(100,200))
        self.data_c = np.array(range(200,300))

    def _method_i_do_not_have_access_to(self, data, window, func):

        output = np.empty(np.size(data))

        for i in xrange(0, len(data)-window+1):
            output[i] = func(data[i:i+window])

        output[-window+1:] = np.nan

        return output

    def apply_a(self):

        a = self.data_a

        def _my_func(val):
            return sum(val)

        return self._method_i_do_not_have_access_to(a, 5, _my_func)

my_class = MyClass()
print my_class.apply_a()

_method_i_do_not_have_access_to 方法接受一个 numpy 数组、一个窗口参数和一个用户定义的函数句柄,并返回一个数组,该数组包含函数句柄在输入数据数组的时间点上的 window 数据点上输出的值 -一种通用的滚动方法。我无权更改此方法。

如您所见,_method_i_do_not_have_access_to 将一个输入传递给函数句柄,该函数句柄是传递给_method_i_do_not_have_access_to 的数据数组。该函数句柄仅基于通过_method_i_do_not_have_access_to 传递给它的一个数据数组上的window 数据点计算输出。

除了通过_method_i_do_not_have_access_to 传递给_my_func 的数组之外,我需要做的是允许_my_func(传递给_method_i_do_not_have_access_to 的函数句柄)对data_bdata_c 进行操作在相同的 window 索引中data_bdata_cMyClass class 中全局定义。

我想到的唯一方法是在_my_func 中包含对data_bdata_c 的引用,如下所示:

def _my_func(val):
    b = self.data_b
    c = self.data_c
    # do some calculations
    return sum(val)

但是,我需要在与val 相同的索引处对bc 进行切片(记住val 是通过_method_i_do_not_have_access_to 传递的数组的长度-window 切片)。

例如,如果_method_i_do_not_have_access_to 中的循环当前正在对输入数组的索引45 -> 50 进行操作,则_my_func 必须对bc 上的相同索引进行操作。

最终的结果是这样的:

def _my_func(val):

    b = self.data_b # somehow identify which slide we are at
    c = self.data_c # somehow identify which slide we are at

    # if _method_i_do_not_have_access_to is currently
    # operating on indexes 45->50, then the sum of 
    # val, b, and c should be the sum of the values at
    # index 45->50 at each

    return sum(val) * sum(b) + sum(c)

我有什么想法可以做到这一点吗?

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    问题是_my_func 怎么知道在哪个indizes 上运行?如果您在调用函数时事先知道 indizes,最简单的方法就是使用 lambda:lambda val: self._my_func(self.a, self.b, index, val) 和 _my_func 显然已更改以适应附加参数。

    由于您不知道 indizes,因此您必须在 self.c 周围编写一个包装器,该包装器会记住上次访问的索引(或者更好的是捕获切片运算符)并将其存储在一个变量中以供您的函数使用使用..

    编辑:敲了一个小例子,不是特别好的编码风格和所有,但应该给你的想法:

    class Foo():
        def __init__(self, data1, data2):
            self.data1 = data1
            self.data2 = data2
            self.key = 0      
    
        def getData(self):
            return Foo.Wrapper(self, self.data2)
    
        def getKey(self):
            return self.key
    
        class Wrapper():
            def __init__(self, outer, data):
                self.outer = outer
                self.data = data
    
            def __getitem__(self, key):
                self.outer.key = key
                return self.data[key]
    
    if __name__ == '__main__':
        data1 = [10, 20, 30, 40]
        data2 = [100, 200, 300, 400]
        foo = Foo(data1, data2)
        wrapped_data2 = foo.getData()
        print(wrapped_data2[2:4])
        print(data1[foo.getKey()])
    

    【讨论】:

    • 感谢您的评论,这周我会试一试。
    【解决方案2】:

    您可以将二维数组传递给 _method_i_do_not_have_access_to()。 len() 和切片操作将与它一起使用:

    In [29]: a = np.arange(100)
    In [30]: b = np.arange(100,200)
    In [31]: c = np.arange(200,300)
    In [32]: data = np.c_[a,b,c] # make your three one dimension array to one two dimension array.
    
    In [35]: data[0:10] # slice operation works.
    Out[35]:
    array([[  0, 100, 200],
           [  1, 101, 201],
           [  2, 102, 202],
           [  3, 103, 203],
           [  4, 104, 204],
           [  5, 105, 205],
           [  6, 106, 206],
           [  7, 107, 207],
           [  8, 108, 208],
           [  9, 109, 209]])
    
    In [36]: len(data) # len() works.
    Out[36]: 100
    
    In [37]: data.shape
    Out[37]: (100, 3)
    

    所以你可以定义你的 _my_func 如下:

    def _my_func(val):
        s = np.sum(val, axis=0)
        return s[0]*s[1] + s[2]
    

    【讨论】:

    • 这是一个很好的清晰解决方案,但不幸的是_method_i_do_not_have_access_to 似乎只针对输入数组的最后一个维度进行计算。这就是为什么我得出结论唯一的解决方案是将全局数组传递到my_func 并在其中切片。 +1 简洁的回应。
    【解决方案3】:

    既然_method_i_do_not.. 似乎只是将您的函数应用于您的数据,您能否让数据精确地成为一个索引数组?然后func 将使用索引对data_adata_bdata_c 进行窗口访问。可能有更快的方法,但我认为这将以最少的复杂性工作。

    换句话说,大致是这样的,如果需要,在window 上添加额外的处理:

    def apply_a(self):
    
        a = self.data_a
        b = self.data_b
        c = self.data_c
    
        def _my_func(window):
            return sum(a[window]) * sum(b[window]) + sum(c[window])
    
        return self._method_i_do_not_have_access_to(window_indices, 5, _my_func)
    

    【讨论】:

      【解决方案4】:

      这是一个技巧:

      创建一个具有__getitem__ 方法的新类DataProxy,并代理三个数据数组(您可以将其传递给它,例如在初始化时)。制作 func act onDataProxy 实例而不是标准的 numpy 数组,并将修改后的 func 和代理传递给不可访问的方法。

      这有意义吗?这个想法是 data 是一个数组没有限制,只是可以下标。所以你可以创建一个自定义的可下标类来代替数组。


      例子:

      class DataProxy:
          def __init__(self, *data):
              self.data = list(zip(*data))
      
          def __getitem__(self, item):
              return self.data[item]
      

      然后创建一个新的 DataProxy,在这样做时传入任意数量的数组,并使 func 接受索引所述实例的结果。试试看!

      【讨论】:

      • 哈不是我读的前三遍 :) 你能举个例子吗?
      • 明天我会试一试。我想我会遇到与上面评论中提到的相同的问题。
      猜你喜欢
      • 1970-01-01
      • 2013-01-04
      • 2019-03-15
      • 1970-01-01
      • 2020-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多