为啥在一种情况下更改熊猫数据框列中的值很快,而在另一种情况下更改速度很慢?

Posted

技术标签:

【中文标题】为啥在一种情况下更改熊猫数据框列中的值很快,而在另一种情况下更改速度很慢?【英文标题】:Why is changing values in a column of a pandas data frame fast in one case and slow in another one?为什么在一种情况下更改熊猫数据框列中的值很快,而在另一种情况下更改速度很慢? 【发布时间】:2019-05-07 01:25:41 【问题描述】:

我有两段代码似乎做同样的事情,但其中一段的速度几乎是另一段的一千倍。

这是第一段:

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 是方法的输入数据框)。在慢速版本中,我是直接对输入数据框进行操作。复制输入数据框并对其进行操作后,它变得很快。

【问题讨论】:

尝试预先计算 where 条件,只计算对 np.where 的调用和对 df[new_col] 的赋值。你看到了什么? 【参考方案1】:

作业不是瓶颈

为 Pandas 系列赋值很便宜,尤其是当您通过诸如pd.Seriesnp.ndarraylist 等常规对象进行赋值时。

广播更便宜

注意broadcasting 非常便宜,即当您在第一个示例中设置诸如val_1val_2 之类的标量值时。

您的第二个示例针对不满足您的条件的情况进行了系列分配。这个比较贵。

计算成本相对较高

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

在第一个例子中,你有一个计算:

df[col] < j

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

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

因此,您可以并且应该预期第二个版本会更贵。

使用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

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

%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】:

第一次只使用一个条件,所以它应该比检查这两个条件更快。简单示例使用 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)

【讨论】:

以上是关于为啥在一种情况下更改熊猫数据框列中的值很快,而在另一种情况下更改速度很慢?的主要内容,如果未能解决你的问题,请参考以下文章

比较熊猫数据框列中的值时出现类型错误

从列表列表中提取元素并将其分配为熊猫数据框列中的值

熊猫数据框列中的成员资格测试

在 Pandas 中模糊搜索列

如何迭代熊猫数据框列中的元素?

用另一个值替换熊猫数据框列中的几个值