代码之家  ›  专栏  ›  技术社区  ›  Roman

为什么在一种情况下,熊猫数据帧的某一列中的值更改得快而在另一种情况下更改得慢?

  •  6
  • Roman  · 技术社区  · 6 年前

    我有两段代码,它们似乎做了同样的事情,但其中一段比另一段快了近千倍。

    这是第一篇:

    t1 = time.time()
    df[new_col] = np.where(df[col] < j, val_1, val_2)
    t2 = time.time()
    ts.append(t2 - t1) 
    

    ts 我的价值观是:

    0.0007321834564208984, 0.0002918243408203125, 0.0002799034118652344
    

    相反,这部分代码:

    t1 = time.time()
    df['new_col'] = np.where((df[col] >= i1) & (df[col] < i2), val, df.new_col)
    t2 = time.time()
    ts.append(t2 - t1)
    

    创造 TS 用以下值填充:

    0.11008906364440918, 0.09556794166564941, 0.08580684661865234
    

    我不知道第一次和第二次作业的本质区别是什么。

    在两种情况下 df 应该是一样的。

    补充

    结果发现根本的区别不在我看的地方。在快速版本的代码中,我有:

    df = inp_df.copy()
    

    在类方法的开头(其中 inp_df 是该方法的输入数据帧)。在慢版本中,我直接在输入数据帧上操作。在复制输入数据帧并对其进行操作之后,它变得很快。

    2 回复  |  直到 6 年前
        1
  •  5
  •   jpp    6 年前

    分配不是瓶颈

    为pandas系列指定值很便宜,尤其是通过常规对象(如 pd.Series ,请 np.ndarray list .

    广播更便宜

    注释 broadcasting 非常便宜,即当您设置标量值时,例如 val_1 val_2 在第一个例子中。

    对于不满足条件的情况,第二个示例有一个系列分配。这个比较贵。

    计算相对昂贵

    另一方面, 计算 你的表演比较昂贵。

    在第一个示例中,您有一个计算:

    df[col] < j
    

    在第二个示例中,您至少有三个计算:

    a = df[col] >= i1
    b = df[col] < i2
    a & b
    

    因此,您可以并且应该期望第二个版本更加昂贵。

    使用 timeit

    使用 时计 用于可靠性能计时的模块。这个 可再生的 下面的示例显示了比您所声称的更小的性能差异:

    import pandas as pd, numpy as np
    
    np.random.seed(0)
    df = pd.DataFrame({'A': np.random.random(10**7)})
    
    j = 0.5
    i1, i2 = 0.25, 0.75
    
    %timeit np.where(df['A'] < j, 1, 2)                             # 85.5 ms per loop
    %timeit np.where((df['A'] >= i1) & (df['A'] < i2), 1, df['A'])  # 161 ms per loop
    

    一次计算比三次计算便宜:

    %timeit df['A'] < j                                             # 14.8 ms per loop
    %timeit (df['A'] >= i1) & (df['A'] < i2)                        # 65.6 ms per loop
    

    通过标量值广播比分配序列便宜:

    %timeit np.where(df['A'] < j, 1, df['A'])                       # 113 ms per loop
    %timeit np.where((df['A'] >= i1) & (df['A'] < i2), 1, 2)        # 146 ms per loop
    
        2
  •  5
  •   Brown Bear    6 年前

    第一次您只使用一个条件,因此它应该比检查这两个条件更快。简单示例使用ipython:

    In [3]: %timeit 1 < 2                                                                                                                                         
    20.4 ns ± 0.434 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
    
    In [4]: %timeit 1 >= 0 & 1 < 2                                                                                                                                
    37 ns ± 1.37 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)