Python, работающий с несколькими массивами данных в скользящем окне - PullRequest
4 голосов
/ 07 августа 2011

рассмотрите следующий код:

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 принимает массив значений, параметр окна и дескриптор пользовательской функции и возвращает массив, содержащий значения, выведенные дескриптором функции в window точках данных во время массива входных данных - универсальный метод прокатки. У меня нет доступа к изменению этого метода.

Как вы можете видеть, _method_i_do_not_have_access_to передает один вход в дескриптор функции, который является массивом данных, переданным в _method_i_do_not_have_access_to. Этот дескриптор функции вычисляет только выходные данные на основе window точек данных для одного массива данных, переданного ему через _method_i_do_not_have_access_to.

Что мне нужно сделать, это разрешить _my_func (дескриптор функции, переданный _method_i_do_not_have_access_to) работать с data_b и data_c в дополнение к массиву, который передается с _my_func через _method_i_do_not_have_access_to при тех же window показателях . data_b и data_c определены глобально в MyClass class.

Единственный способ, которым я думал об этом, - включить ссылки на data_b и data_c в _my_func, например:

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

Однако мне нужно нарезать b и c по тем же индексам, что и val (помните, val - это отрезок длины window массива, который передается через _method_i_do_not_have_access_to).

Например, если в настоящее время цикл в _method_i_do_not_have_access_to работает с индексами 45 -> 50 во входном массиве, _my_func должен работать с теми же индексами b и c.

Окончательный результат будет примерно таким:

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)

Есть мысли о том, как мне это сделать?

Ответы [ 4 ]

1 голос
/ 08 августа 2011

вы можете передать двумерный массив в _method_i_do_not_have_access_to ().С ним будут работать len () и операция slice:

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]
1 голос
/ 07 августа 2011

Вопрос в том, как _my_func узнает, какой из них работает? Если вы знаете заранее значения при вызове вашей функции, простейшим подходом было бы просто использовать лямбду: lambda val: self._my_func(self.a, self.b, index, val) с явно измененным _my_func для размещения дополнительных параметров.

Поскольку вы не знаете индексы, вам нужно написать обертку вокруг 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()])
0 голосов
/ 07 августа 2011

Поскольку кажется, что _method_i_do_not.. просто применяет вашу функцию к вашим данным, могли бы вы иметь данные в виде массива индексов? Тогда func будет использовать индексы для оконного доступа к data_a, data_b и data_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)
0 голосов
/ 07 августа 2011

Вот хак:

Создайте новый класс DataProxy, который имеет метод __getitem__ и проксирует три массива данных (которые вы можете передать ему, например, при инициализации). Создайте func act on экземпляры DataProxy вместо стандартных массивов numpy и передайте измененный функционал и прокси недоступному методу.

Это имеет смысл? Идея состоит в том, что нет никаких ограничений на data, чтобы быть массивом, просто чтобы быть подписанным. Таким образом, вы можете создать собственный класс для использования вместо массива.


Пример:

class DataProxy:
    def __init__(self, *data):
        self.data = list(zip(*data))

    def __getitem__(self, item):
        return self.data[item]

Затем создайте новый DataProxy, передавая столько массивов, сколько вам нужно, и заставьте func принять результаты индексации указанного экземпляра. Попробуйте!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...