Python 提高迭代性能

Python 提高迭代性能,python,numpy,pandas,Python,Numpy,Pandas,我有下面的代码,它获取单个资产的历史价格和计算出的预测,并计算如果你真的根据预测进行投资,你会如何公平。用金融术语来说,这是一个回溯测试 主要问题是它的速度非常慢,我不确定改进它的正确策略是什么。我需要运行数千次,因此需要一个数量级的加速 我应该从哪里开始寻找 class accountCurve(): def __init__(self, forecasts, prices): self.curve = pd.DataFrame(columns=['Capital',

我有下面的代码,它获取单个资产的历史价格和计算出的预测,并计算如果你真的根据预测进行投资,你会如何公平。用金融术语来说,这是一个回溯测试

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

我应该从哪里开始寻找

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
如果previous.isnull()['Cash']==False:,我不太理解行
的意义。看起来好像
previous['Cash']
从来都不是空的,除了第一行之外——但是您更早地设置了第一行

也可以考虑在类之外执行<代码>预测.DROPNA(InStudioTrue)< /C> >。如果它最初是一个数据帧,您将运行它一次,而不是对每一列重复它。(我是否正确理解您在类中输入了一列

预测值

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

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

将为您的
\uuuu init\uuuuu

中的每一行生成统计数据。请您将示例输入和输出数据集(CSV/dict/JSON/Python代码格式的5-7行作为文本,以便在编码时使用)发布,并描述您希望在
for date,forecast in forecast.iteritems()
循环中实现的目标。您可以为您的输入和设置df.head(),这样人们就可以看到结构,而无需安装第三方库。顺便说一句,iTerPles更快,因为iteritems和iterrows必须为每次迭代构造一个系列对象。我认为您可能必须使用numba来实现类似的功能,尽管目前的问题很难确定。我建议将所有列重命名为单个字母a-g,并显示几行示例输入和输出。另外,如果我读对了,当
x['Cash']
nan
/
null
时,所有其他东西也会变成
nan
,也就是说它们不会从默认值修改,因此,您可以完全跳过迭代。因此,在循环之外更有效地使用
dropna
。。事实上,您应该在
曲线
本身上循环,而不是
预测
。这也非常“好”,至少看起来会更好!前面的.isnull()仅用于第一行(尽管我讨厌一直重复测试)。也许有更干净的方法。谢谢你的帮助,我会试试%lprun@cjm2671很高兴我能帮忙。至于
previous.isnull()
test,更简洁的方法是对循环前面的第一行执行所需的操作,然后从第二行开始运行循环。对于范围(1,…)
,我的代码应该正好做到这一点;但是使用
iteritems
更为复杂。