熊猫替换/字典缓慢
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)
。以上是关于熊猫替换/字典缓慢的主要内容,如果未能解决你的问题,请参考以下文章