熊猫替换/字典缓慢

Posted

技术标签:

【中文标题】熊猫替换/字典缓慢【英文标题】:Pandas replace/dictionary slowness 【发布时间】:2017-06-18 12:59:54 【问题描述】:

请帮助我理解为什么这个“从字典替换”操作在 Python/Pandas 中很慢:

# Series has 200 rows and 1 column
# Dictionary has 11269 key-value pairs
series.replace(dictionary, inplace=True)

字典查找应该是 O(1)。替换列中的值应该是 O(1)。这不是矢量化操作吗?就算不向量化,迭代200行也只是200次迭代,怎么会慢呢?

这是一个 SSCCE 演示该问题:

import pandas as pd
import random

# Initialize dummy data
dictionary = 
orig = []
for x in range(11270):
    dictionary[x] = 'Some string ' + str(x)
for x in range(200):
    orig.append(random.randint(1, 11269))
series = pd.Series(orig)

# The actual operation we care about
print('Starting...')
series.replace(dictionary, inplace=True)
print('Done.')

在我的机器上运行该命令需要超过 1 秒的时间,这比执行

【问题讨论】:

请提供一个可重现的示例,并定义您所说的“慢”是什么意思。我尝试复制您的设置时没有性能问题,替换需要大约 200 毫秒。 使用 SSCCE 编辑了 OP。使用 Python 时,每次操作约 1ms 真的是预期的性能吗? 【参考方案1】:

感谢@root:我再次进行了基准测试,在 pandas v1.1.4 上发现了不同的结果

发现 series.map(dictionary) 最快,它也返回 NaN is key not present

【讨论】:

【参考方案2】:

.replace 可以进行不完整的子字符串匹配,而.map 需要在字典中提供完整的值(或者它返回 NaN)。快速但通用的解决方案(可以处理子字符串)应首先在所有可能值的字典上使用.replace(例如使用.value_counts().index 获得),然后使用此字典和.map 遍历系列的所有行。例如,此组合可以在 1/4 秒内处理 1m 行列上的特殊国家字符替换(完整子字符串),其中 .replace 单独需要 15 个。

【讨论】:

【参考方案3】:

看起来replace 有一点开销,并且通过map 明确告诉系列要做什么会产生最佳性能:

series = series.map(lambda x: dictionary.get(x,x))

如果您确定所有键都在您的字典中,则可以通过不创建 lambda 并直接提供 dictionary.get 函数来获得非常轻微的性能提升。任何不存在的键都将通过此方法返回NaN,因此请注意:

series = series.map(dictionary.get)

您也可以只提供字典本身,但这似乎会带来一些开销:

series = series.map(dictionary)

时间安排

使用您的示例数据进行一些时间比较:

%timeit series.map(dictionary.get)
10000 loops, best of 3: 124 µs per loop

%timeit series.map(lambda x: dictionary.get(x,x))
10000 loops, best of 3: 150 µs per loop

%timeit series.map(dictionary)
100 loops, best of 3: 5.45 ms per loop

%timeit series.replace(dictionary)
1 loop, best of 3: 1.23 s per loop

【讨论】:

知道是什么导致了如此多的开销吗?在我的数据框上使用.replace(dictionary) 导致我的笔记本在经过相当长的等待后崩溃,但执行.map(dictionary.get) 需要不到一秒钟的时间。对我来说很奇怪,数据帧中的内置函数可能会有几个数量级的开销;我原以为.map 会比.replace 差。 .replace 可以做不完整的子串匹配,而.map需要在字典中提供完整的值 还将为 DataFrame 添加,使用 applymap 代替:df = df.applymap(dictionary.get)

以上是关于熊猫替换/字典缓慢的主要内容,如果未能解决你的问题,请参考以下文章

熊猫时间戳与日期时间的性能缓慢

在 Soundpool 中使用许多声音时,应用程序加载时间是如此缓慢……任何替换?

Ubuntu 19.04:程序启动缓慢

Numpy 规范化代码异常缓慢

使用字典替换熊猫数据框中的单词

用字典替换熊猫系列中的值