pandas Series.map() 的内部实现是什么?

use*_*964 3 python performance numpy pandas

我注意到 pandas Series.map() 对于字典映射来说非常快

\n\n

准备数据如下:

\n\n
a=np.random.randint(0,1000,10**5)\ns=pd.Series(a)\nd=dict(zip(np.arange(1000),np.random.random(1000)))\n
Run Code Online (Sandbox Code Playgroud)\n\n

定时

\n\n
%timeit -n10 s.map(d)\n%timeit -n10 np.vectorize(d.get)(a)\n
Run Code Online (Sandbox Code Playgroud)\n\n

给出

\n\n
1.42 ms \xc2\xb1 168 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n20.6 ms \xc2\xb1 386 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

其中第二种方法是我在 stackoverflow 上找到的进行 numpy dict 映射的典型建议。

\n\n

numpy还有另一种典型的解决方案如下

\n\n
%%timeit -n10 \nb = np.copy(a)\nfor k, v in d.items():\n    b[a==k] = v\n
Run Code Online (Sandbox Code Playgroud)\n\n

这使

\n\n
43.9 ms \xc2\xb1 2.8 ms per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n\n

它甚至更慢,更糟糕的是,它给出了错误的结果。因为b是int类型,赋值时b[a==k] = v会返回b全为零!

\n\n

所以我想知道 pandas Series.map() 的内部实现是什么?它在numpy中实现吗?与具有相同性能的 Series.map() 等效的 numpy 是什么?我试图深入研究 Series.map() 的源代码,但无法理解它。

\n

ALo*_*llz 5

Series.map将调用_map_values()pandas/core/base.py 的一部分

您使用的是字典,因此您可以通过第一个if is_dict_like(mapper):子句来获取mapper,然后在第 1161-1162 行中您将获得此基本情况的映射函数(默认为非扩展类型na_action=None

else:
    map_f = lib.map_infer
Run Code Online (Sandbox Code Playgroud)

If you then go to that part of the code, found in pandas/_libs/lib.pyx you'll see map_infer is implemented in cython.


As they note in the comments, this is only so fast for specific inputs:

# we can fastpath dict/Series to an efficient map
# as we know that we are not going to have to yield
# python types
Run Code Online (Sandbox Code Playgroud)

  • `numpy` 没有等效的映射器。事实上,它对字典没有什么特别的作用。“向量化”代码的时间与列表理解“np.array([d[i] for i in a])”相同。Pandas 显然正在使用自定义编译代码的一个或多个函数(通过“pyx”和“cython”)。 (3认同)