熊猫替换/字典慢度

时间:2017-02-01 17:07:55

标签: python performance pandas dictionary

请帮助我理解为什么这个"替换字典" 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秒以上的时间,这比执行< 1000次操作的时间要长1000倍。

2 个答案:

答案 0 :(得分:12)

看起来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

答案 1 :(得分:1)

.replace可以完成不完全的子字符串匹配,而.map要求在字典中提供完整的值(否则它返回NaN)。快速但通用的解决方案(可以处理子字符串)应首先在所有可能值的字典上使用.replace(例如,通过.value_counts().index获得),然后使用该字典和{ {1}}。例如,此组合可以处理四分之一秒内在100万行列上的特殊国家字符替换(完整子字符串),其中.map仅需花费15。