【问题标题】:Pandas Dataframe Performance apply function with shiftPandas Dataframe Performance 应用函数与 shift
【发布时间】:2017-12-29 21:32:04
【问题描述】:

我正在尝试优化我的代码。一个电话很快,但因为我经常遇到一些问题。

我的输入数据如下所示:

df = pd.DataFrame(data=np.random.randn(30),
                  index=pd.date_range(pd.datetime(2016,1,1), periods = 30))
df.iloc[:20] = np.nan

现在我只想应用一个简单的功能。这是我要优化的部分:

s = df >= df.shift(1)
s = s.applymap(lambda x: 1 if x else 0)

现在我有 1000 个循环,最好是 3:每个循环 1.36 毫秒。我想应该可以做得更快。不确定我是否应该矢量化,仅使用 numpy 或使用 cython。任何想法的最佳方法?我对移位运算符有点挣扎。

【问题讨论】:

  • 不需要循环或apply,只需:(df >= df.shift(1)).dropna().astype(int)
  • 谢谢,获得了 2 倍的改进! 1000 次循环,最好的 3 次:每个循环 776 µs
  • 其实去掉dropna。你不需要它

标签: python performance pandas numpy profiling


【解决方案1】:

您可以将比较结果直接从bool 转换为int

(df >= df.shift(1)).astype(int)

【讨论】:

    【解决方案2】:

    @Paul H 的回答很好,很高效,我通常会推荐。

    也就是说,如果您想榨取最后一点性能,这是numba 的一个不错的候选者,您可以使用它在一次数据传递中计算答案。

    from numba import njit
    
    @njit
    def do_calc(arr):
        N = arr.shape[0]
        ans = np.empty(N, dtype=np.int_)
        ans[0] = 0
        for i in range(1, N):
            ans[i] = 1 if arr[i] > arr[i-1] else 0
        return ans
    
    a = (df >= df.shift(1)).astype(int)
    b = pd.DataFrame(pd.Series(do_calc(df[0].values), df[0].index))
    
    from pandas.testing import assert_frame_equal
    assert_frame_equal(a, b)
    

    这里是时间

    In [45]: %timeit b = pd.DataFrame(pd.Series(do_calc(df[0].values), df[0].index))
    135 µs ± 1.83 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
    
    In [46]: %timeit a = (df >= df.shift(1)).astype(int)
    762 µs ± 22.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    

    【讨论】:

    • 这似乎与使用 numpy 数组的解决方案一样快。很有意思。非常感谢您的回答!!
    【解决方案3】:

    这是我目前最好的解决方案:

    values = df.values[1:] >= df.values[:-1] 
    data = np.array(values, dtype=int)
    s  = pd.DataFrame(data, df.index[1:])
    

    我得到了 10000 个循环,最好是 3 个:每个循环 125 µs。 x10 改进。但我认为它可以做得更快。

    PS:此解决方案并不完全正确,因为缺少第一个零 / nan。 PPS:可以通过 pd.DataFrame(np.append([[0]],data), df.index) 进行纠正

    【讨论】:

    • “RuntimeWarning:在更大的_equal中遇到无效值”并且输出不匹配。
    • 你是对的,这是一个错误,因为 np.nan 与浮点数进行了比较。 Numpy 将其转换为 false。这很好,但警告仍然不好。
    • 这是一个警告,但输出与这个答案和问题不匹配,所以它不起作用。
    • 你说得对。现在添加了这个解决方案。它有效并且输出匹配。但是有一个警告——不是那么好。但另一方面,这只是一个警告,它仍然有效且安全。
    猜你喜欢
    • 1970-01-01
    • 2018-02-23
    • 2019-04-10
    • 2021-10-04
    • 2017-11-14
    • 2020-07-02
    • 1970-01-01
    • 1970-01-01
    • 2012-09-26
    相关资源
    最近更新 更多