s
替换熊猫系列d
中的值已被询问并多次提出。推荐的方法(1、2、3、4)是使用
s.replace(d)
或偶尔,如果在字典键中找到了所有系列值,请使用s.map(d)
。但是,使用
s.replace
的性能通常会不合理地变慢,通常比简单的列表理解要慢5-10倍。< br替代方法
s.map(d)
具有良好的性能,但仅当在字典中找到所有键时才建议使用。为什么
s.replace
这么慢,如何提高性能?import pandas as pd, numpy as np
df = pd.DataFrame({'A': np.random.randint(0, 1000, 1000000)})
lst = df['A'].values.tolist()
##### TEST 1 #####
d = {i: i+1 for i in range(1000)}
%timeit df['A'].replace(d) # 1.98s
%timeit [d[i] for i in lst] # 134ms
##### TEST 2 #####
d = {i: i+1 for i in range(10)}
%timeit df['A'].replace(d) # 20.1ms
%timeit [d.get(i, i) for i in lst] # 243ms
注意:此问题未标记为重复,因为它正在寻找有关在给定不同数据集的情况下何时使用不同方法的具体建议。这在答案中是明确的,并且是其他问题通常未解决的一个方面。
#1 楼
一个简单的解决方案是选择一种方法,该方法取决于对字典键如何完全覆盖值的估计。一般情况
如果所有值都已映射,请使用
df['A'].map(d)
;或如果映射> 5%的值,请使用
df['A'].map(d).fillna(df['A']).astype(int)
。很少,例如<5%,d中的值
使用
df['A'].replace(d)
〜5%的“交叉点”特定于下面的基准测试。
有趣的是,在任何一种情况下,简单的列表理解通常都不如
map
。 s.replace
这么慢的原因在于,它所要做的不仅仅是映射字典。它处理一些极端情况和可能很少见的情况,这些情况通常在任何情况下都应加倍注意。这是
replace()
中pandas\generic.py
的摘录。import pandas as pd, numpy as np
df = pd.DataFrame({'A': np.random.randint(0, 1000, 1000000)})
lst = df['A'].values.tolist()
##### TEST 1 - Full Map #####
d = {i: i+1 for i in range(1000)}
%timeit df['A'].replace(d) # 1.98s
%timeit df['A'].map(d) # 84.3ms
%timeit [d[i] for i in lst] # 134ms
##### TEST 2 - Partial Map #####
d = {i: i+1 for i in range(10)}
%timeit df['A'].replace(d) # 20.1ms
%timeit df['A'].map(d).fillna(df['A']).astype(int) # 111ms
%timeit [d.get(i, i) for i in lst] # 243ms
涉及到许多步骤:
将字典转换为列表。
遍历列表并检查嵌套字典。
提供迭代器键和值转换为替换函数。
可以与
map()
中pandas\series.py
中更精简的代码进行比较:items = list(compat.iteritems(to_replace))
keys, values = zip(*items)
are_mappings = [is_dict_like(v) for v in values]
if any(are_mappings):
# handling of nested dictionaries
else:
to_replace, value = keys, values
return self.replace(to_replace, value, inplace=inplace,
limit=limit, regex=regex)
评论
带有dict的pandas列中Remap值的可能重复项@JohnE,您是对的,我大约在1周后才找到您的答案。希望我给出的解释可以帮助人们通过源代码注意到行为的何时(如果和何时)改变。随意将其标记为dup :)。
不用担心,这很好,这里有太多东西被标记为国际海事组织(IMO);-)