Сокращение столбца в Pandas

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

например

 $ c 0.12 -.13 0.23 0.17 0.29 -0.11 # something like this $ c.reductions(init=1, lambda accumulator, ret: accumulator * (1 + ret)) 1.12 0.97 1.20 1.40 1.81 1.61 

NB: фактическая цена закрытия не имеет значения, поэтому использование 1 в качестве начального значения. Мне просто нужна «макет» цены закрытия.

Фактическая структура моих данных – это DataFrame именованных столбцов TimeSeries. Я предполагаю, что я ищу функцию, аналогичную applymap , но я бы предпочел не делать что-то взломанное с этой функцией и ссылаться на DF изнутри (что, я полагаю, является одним из решений этой проблемы?)

Кроме того, что бы я сделал, если бы хотел сохранить данные о returns , но с закрывающей «ценой»? Должен ли я возвращать кортеж вместо этого, и иметь TimeSeries типа (returns, closing_price) ?

Стоит отметить, что часто быстрее (а также легче понять) писать более подробно в пандах, а не писать как reduce .

В вашем конкретном примере я бы просто add а затем cumprod :

 In [2]: c.add(1).cumprod() Out[2]: 0 1.120000 1 0.974400 2 1.198512 3 1.402259 4 1.808914 5 1.609934 

или возможно init * c.add(1).cumprod() .

Примечание. Однако в некоторых случаях, например, в случае проблемы с памятью, вам может потребоваться переписать их более низкоуровневым / умным способом, но сначала стоит попробовать самый простой метод (и провести тестирование против него, например, используя% timeit или профилирующая память ).

Это не похоже, что это хорошо известная функция, но вы можете использовать expanding_apply для достижения расчета доходности:

 In [1]: s Out[1]: 0 0.12 1 -0.13 2 0.23 3 0.17 4 0.29 5 -0.11 In [2]: pd.expanding_apply(s ,lambda s: reduce(lambda x, y: x * (1+y), s, 1)) Out[2]: 0 1.120000 1 0.974400 2 1.198512 3 1.402259 4 1.808914 5 1.609934 

Я не уверен на 100%, но я полагаю, что expanding_apply работает над применяемой серией, начиная с первого индекса по текущему индексу. Я использую встроенную функцию reduce которая работает точно так же, как и ваша функция Clojure.

Docstring для expand_apply:

 Generic expanding function application Parameters ---------- arg : Series, DataFrame func : function Must produce a single value from an ndarray input min_periods : int Minimum number of observations in window required to have a value freq : None or string alias / date offset object, default=None Frequency to conform to before computing statistic center : boolean, default False Whether the label should correspond with center of window Returns ------- y : type of input argument 

Для удобства чтения я предпочитаю следующее решение:

 returns = pd.Series([0.12, -.13, 0.23, 0.17, 0.29, -0.11]) initial_value = 100 cum_growth = initial_value * (1 + returns).cumprod() >>> cum_growth 0 112.000000 1 97.440000 2 119.851200 3 140.225904 4 180.891416 5 160.993360 dtype: float64 

Если вы хотите включить начальное значение в серию:

 >>> pd.concat([pd.Series(initial_value), cum_growth]).reset_index(drop=True) 0 100.000000 1 112.000000 2 97.440000 3 119.851200 4 140.225904 5 180.891416 6 160.993360 dtype: float64