Генерация комбинаций значений из скользящего окна в Pandas - PullRequest
0 голосов
/ 12 июня 2018

Для каждой строки в моем фрейме данных мне нужно создать каждую комбинацию из двух значений столбца a из трехдневного скользящего окна, заканчивающегося в этой строке .Мой фрейм данных выглядит так:

import pandas as pd    
df = pd.DataFrame({'a': [1, 2, 3, 4, 5]},
                   index=[pd.Timestamp('20180101'),
                          pd.Timestamp('20180102'),
                          pd.Timestamp('20180103'),
                          pd.Timestamp('20180105'),
                          pd.Timestamp('20180106')])

Обратите внимание, что индекс времени неровный (несовместимые интервалы между строками).Комбинации должны выглядеть так:

row0: None
row1: [(1, 2)]
row2: [(1, 2), (1, 3), (2, 3)]
row4: [(3, 4)]
row5: [(4, 5)]

Я могу сделать это достаточно легко без окна, просто используйте itertools.combinations для генерации каждой комбинации из двухэлементы столбца a с:

import itertools as it
combos = it.combinations(df['a'], 2)
for c in combos:
    print(c)
# (1, 2)
# (1, 3)
# (1, 4)
# (1, 5)
# etc.

, но мне нужна оконная версия для моего приложения.Моя лучшая ставка на данный момент - использовать df.rolling.Я могу делать простые вещи, такие как суммирование элементов в трехдневном окне с чем-то вроде:

df.rolling('3d').sum()
# get [1, 3, 6, 7, 9] which we expect

, но я не могу выполнять более сложные операции (или возвращать из операции более сложные типы, чем действительные числа)) на скользящем окне.


Вопрос

Как использовать df.rolling для создания комбинаций поверх моего скользящего окна?Или есть какой-то другой инструмент для этого?


Попытки

До сих пор я думал, что есть какой-то способ использовать df.rolling и df.apply вместе с it.combinationsгенерировать итераторы для каждого окна в моем фрейме данных, а затем подключить этот итератор к новому столбцу моего фрейма данных.Что-то вроде:

df.rolling('3d').apply(lambda x: it.combinations(x, 2))

, который дает TypeError:

Ошибка типа: должно быть действительным числом, а не itertools.combination

, потому что df.rolling.apply требует, чтобы его аргумент возвращал единственное реальное значение, а не объект или список.

Я также пытался использовать it.combinations непосредственно в скользящем окне:

it.combinations(df.rolling('3d'), 2)

, что дает:

KeyError: 'Столбец не найден: 0'

и если я выберу столбец a явно:

it.combinations(df.rolling('3d')['a'], 2)

Я получаю:

Исключение: столбцы уже выбраны

Так что, возможно, есть способ определить функцию, которую я могу вызвать с помощью df.apply что включает итератор в моем скользящем окне в новый столбец для каждой строки моего информационного кадра?Могу ли я даже работать со строками, отличными от текущей, в функции, переданной в apply?

1 Ответ

0 голосов
/ 13 июня 2018

Хорошо, это хак, но это может быть полезно.

Все, что мы хотим сделать, - это повторно использовать средства управления окнами df.rolling.Мы могли бы попытаться заглянуть внутрь некоторых закрытых частей кода, но вместо этого давайте просто воспользуемся преимуществом того факта, что мы можем принудительно вызвать вызов функции внутри apply до того, как мы вернем float:

In [28]: dummy = df.rolling("3d")["a"].apply((lambda x: print(x) or 0), raw=False)
2018-01-01    1.0
dtype: float64
2018-01-01    1.0
2018-01-02    2.0
dtype: float64
2018-01-01    1.0
2018-01-02    2.0
2018-01-03    3.0
dtype: float64
2018-01-03    3.0
2018-01-05    4.0
dtype: float64
2018-01-05    4.0
2018-01-06    5.0
dtype: float64

И так:

In [29]: roll_slices = []

In [30]: dummy = df.rolling("3d")["a"].apply((lambda x: roll_slices.append(list(combinations(x, 2))) or 0), raw=False)

In [31]: roll_slices
Out[31]: 
[[],
 [(1.0, 2.0)],
 [(1.0, 2.0), (1.0, 3.0), (2.0, 3.0)],
 [(3.0, 4.0)],
 [(4.0, 5.0)]]

После чего вы можете делать то, что вам нравится.

...