6

我正在尝试将(嗯,很多)返回数据列转换为收盘价列。在 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

注意:实际收盘价无关紧要,因此使用 1 作为初始值。我只需要一个“模拟”收盘价。

我的数据的实际结构是 TimeSeries 的命名列的 DataFrame。我想我正在寻找一个类似的函数applymap,但我宁愿不对该函数做一些hacky并从其中引用DF(我想这是解决这个问题的一种方法?)

此外,如果我想保留returns数据,但有收盘“价格”,我会怎么做?我应该返回一个元组,并让 TimeSeries 是类型(returns, closing_price)吗?

4

3 回答 3

6

它看起来还不是一个广为人知的功能,但您可以使用它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从第一个索引到当前索引的应用系列工作。我使用与 Clojure 函数完全一样的内置reduce函数。

文档字符串expanding_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
于 2013-01-27T00:15:40.310 回答
4

值得注意的是,在 pandas 中写得更详细,而不是写成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 或分析内存)。

于 2013-01-27T03:47:44.223 回答
0

为了可读性,我更喜欢以下解决方案:

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
于 2015-10-24T00:58:02.313 回答