改善Pandas迭代性能

时间:2016-05-05 10:32:12

标签: python numpy pandas

我已经获得了以下代码,该代码记录单个资产的历史价格和计算的预测,并计算如果您根据预测真正投入资金,您将如何流行。用金融术语来说,它是一种反向测试。

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

我应该从哪里开始寻找?

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)

1 个答案:

答案 0 :(得分:1)

我建议在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__中的每一行生成统计信息。