我有以下代码,该代码获取单个资产的历史价格并计算出预测,并根据预测来计算如果您确实投资了钱,您将如何获得公允价值。用财务术语来说,这是一种回溯测试。

主要问题是它运行缓慢,我不确定改进它的正确策略是什么。我需要运行数千次,因此需要一个数量级的加速。

我应该从哪里开始寻找?

class accountCurve():
    def __init__(self, forecasts, prices):

        self.curve = pd.DataFrame(columns=['Capital','Holding','Cash','Trade', 'Position'], dtype=float)
        forecasts.dropna(inplace=True)
        self.curve['Forecast'] = forecasts
        self.curve['Price'] = prices
        self.curve.loc[self.curve.index[0],['Capital', 'Holding', 'Cash', 'Trade', 'Position']] = [10000, 0, 10000, 0, 0]

        for date, forecast in forecasts.iteritems():
            x=self.curve.loc[date]
            previous = self.curve.shift(1).loc[date]
            if previous.isnull()['Cash']==False:
                x['Cash'] = previous['Cash'] - previous['Trade'] * x['Price']
                x['Position'] = previous['Position'] + previous['Trade']

            x['Holding'] = x['Position'] * x['Price']
            x['Capital'] = x['Cash'] + x['Holding']
            x['Trade'] = np.fix(x['Capital']/x['Price'] * x['Forecast']/20) - x['Position']


编辑:

要求的数据集:

价格:

import quandl
corn = quandl.get('CHRIS/CME_C2')
prices = corn['Open']


预测:

def ewmac(d):
    columns = pd.Series([2, 4, 8, 16, 32, 64])
    g = lambda x: d.ewm(span = x, min_periods = x*4).mean() - d.ewm(span = x*4, min_periods=x*4).mean()
    f = columns.apply(g).transpose()
    f = f*10/f.abs().mean()
    f.columns = columns
    return f.clip(-20,20)
forecasts=ewmac(prices)

最佳答案

我建议在for循环中使用numpy数组而不是数据帧。通常可以大大提高速度。

因此,代码可能类似于:

class accountCurve():
    def __init__(self, forecasts, prices):
        self.curve = pd.DataFrame(columns=['Capital','Holding','Cash','Trade', 'Position'], dtype=float)
        # forecasts.dropna(inplace=True)
        self.curve['Forecast'] = forecasts.dropna()
        self.curve['Price'] = prices
        # helper np.array:
        self.arr = np.array(self.curve)
        self.arr[0,:5] = [10000, 0, 10000, 0, 0]

        for i in range(1, self.arr.shape[0]):
            this = self.arr[i]
            prev = self.arr[i-1]
            cash = prev[2] - prev[3] * this[6]
            position = ...
            holding = ...
            capital = ...
            trade = ...
            this[:5] = [capital, holding, cash, trade, position]

        # back to data frame:
        self.curve[['Capital','Holding','Cash','Trade', 'Position']] = self.arr[:,:5]
        # or maybe this would be faster:
        # self.curve[:] = self.arr


我不太了解if previous.isnull()['Cash']==False:行的重要性。看起来previous['Cash']永远不会为空,除了第一行可能-但您可以更早设置第一行。

另外,您可以考虑在类之外执行forecasts.dropna(inplace=True)。如果它最初是一个数据帧,则将其运行一次,而不是对每列重复一次。 (我是否正确理解您将forecasts的单列输入到类中?)

我建议的下一步是使用一些行探查器来查看您的代码大部分时间都花在了哪里,并尝试优化这些瓶颈。如果使用ipython,则可以尝试运行%prun%lprun。例如

%lprun -f accountCurve.__init__  A = accountCurve(...)


会为__init__中的每一行产生统计信息。

关于python - 改善 Pandas 迭代性能,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37048265/

10-08 21:42