【问题标题】:Most efficient way to compute managed value计算托管价值的最有效方法
【发布时间】:2017-10-18 10:57:48
【问题描述】:

我远不是熊猫专家。我是一名普通的开发人员。

我想计算一个托管值。 我有一个 df,它是每天的市场价格(以日期为索引)和 dfTrend,它是 0 和 1,具有相同的索引。

我想将这两个数据帧发送到一个函数并获得一个托管值,这意味着当趋势为零时,我希望托管值保持平坦,当趋势为一时,我希望值增加并遵循市场价格。

例如:

我的代码运行良好,但速度很慢:

def getManagedValue(df, dfTrend):
    dfReturn = df.pct_change(1)
    dfManaged = df

    for col in df:
        for i in range(1, len(df[col])):
            dfManaged[col][0] = df[col][0]
            if dfTrend[col][i] == 1:
                dfManaged[col][i] = dfManaged[col][i-1] * (1 + dfReturn[col][i])
            else:
                dfManaged[col][i] = dfManaged[col][i-1]
    return dfManaged

有谁知道我可以如何优化它以使其运行得更快?所有列的所有单元格的迭代肯定是这里的问题。

我正在考虑用 cython 运行它,但我相信我不允许将 pandas 与 cython 一起使用,只能使用 numpy 的数组...

有人有建议吗?

干杯, 朱利安

【问题讨论】:

    标签: python python-2.7 pandas numpy scalability


    【解决方案1】:

    Pandas 的速度和能力来自于对整个阵列的操作,而不是对单个行和单元格进行迭代。如果我正确地遵循了您原始示例中的逻辑,您可以使用np.where 更快地执行此操作:

    dfManaged = np.where(dfTrend == 1, df.shift(1) * (1 + df.pct_change(1)), df.shift(1))
    
    • np.where 让你指定一些条件(在这种情况下,dfTrend == 1) 如果该条件为真,则从一个数据帧中分配值 (df.shift(1) * (1 + df.pct_change(1))) 和另一个如果 条件为假 (df.shift(1))。
    • df.shift(1)df 中的所有值向下移动一行,例如dfManaged[col][i-1] 但无需迭代。
    • 请注意,这会一次跨整个数据帧执行操作,而不是一次执行一行和一列。这应该会加快速度。

    【讨论】:

    • 非常感谢,这就是我正在寻找的。不幸的是,如果趋势 == 0,df.shift(1) 在我希望它达到平稳状态时仍在增加。我不知道为什么。 (我试图用 np.nan 替换它,并且这项工作)
    • 抱歉,您的问题/我的回答中的代码有问题,还是 dfTrend 本身有问题?
    • 在您的回答中,df.shift(1) 在 dfTrend =0 时不会将托管值保持为相同的值。
    • 我不确定我明白你的意思。您期望什么行为以及您不希望发生什么?
    【解决方案2】:

    据我所知,您使用导数 (df.pct_change(1)) 来重建您的曲线。当趋势是1时,你要使用这个导数,当它是0时,导数应该是0。

    要有效地做到这一点有点棘手。一种尝试是 (i) 使用 dfTrend 修改导数,并且 (ii) 重新计算 managed 作为导数的累积和。不过,您可能会在这里遇到一些浮点错误——我不确定。

    # step 1
    deriv = 1 + df.pct_change(1)
    deriv[dfTrend == 0] = 0 
    # step 2
    managed = np.cumsum(deriv)
    # optional -- remove potential floating point errors where possible
    managed[dfTrend == 1] = df[dfTrend == 1]
    

    【讨论】:

    • 谢谢,我找到了一个非常有效的解决方案(见下文),但无论如何我都会尝试。
    【解决方案3】:

    感谢您的回答。我自己终于找到了解决方案。

    使用 [2696 行 x 305 列] 的数据框, 使用 pandas 数据框处理它大约需要 5 分钟(使用问题中的代码)。

    我使用了 numpy 数组并下降到 2.30 分钟。

    最后,我对所有内容都进行了 cythonized 并下降到 2.5 秒,这绝对足够好。

    干杯, 朱利安

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      • 2020-03-28
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多