为什么在一个案例中快速更改pandas数据框的列中的值而在另一个案例中更慢?

Rom*_*man 6 python performance numpy pandas

我有两段似乎做同样事情的代码但是一条代码比另一条快几千倍.

这是第一篇:

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

ts我的价值观,如:

0.0007321834564208984, 0.0002918243408203125, 0.0002799034118652344
Run Code Online (Sandbox Code Playgroud)

相比之下,这部分代码:

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)
Run Code Online (Sandbox Code Playgroud)

ts使用以下值创建填充:

0.11008906364440918, 0.09556794166564941, 0.08580684661865234
Run Code Online (Sandbox Code Playgroud)

我无法弄清楚第一次和第二次任务之间的本质区别.

两种情况df都应该是一样的.

添加

事实证明,本质区别并不在我所看到的地方.在快速版本的代码我有:

df = inp_df.copy()
Run Code Online (Sandbox Code Playgroud)

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

Bea*_*own 5

第一次只使用一个条件,因此它应该比检查这两个条件更快.简单的例子使用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)
Run Code Online (Sandbox Code Playgroud)


jpp*_*jpp 5

作业不是瓶颈

为Pandas系列分配值很便宜,特别是如果您通过常规对象(如pd.Series,np.ndarray或)进行分配list.

广播甚至更便宜

广播是非常便宜的,即当你设置标值,如val_1val_2第一例子.

您的第二个示例针对不满足您的条件的情况进行了系列分配.这是相对昂贵的.

计算相对昂贵

另一方面,您执行的计算相对昂贵.

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

df[col] < j
Run Code Online (Sandbox Code Playgroud)

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

a = df[col] >= i1
b = df[col] < i2
a & b
Run Code Online (Sandbox Code Playgroud)

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

使用 timeit

使用该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
Run Code Online (Sandbox Code Playgroud)

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

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

通过标量值进行广播比分配系列要便宜:

%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
Run Code Online (Sandbox Code Playgroud)