熊猫多索引创建性能

Bef*_*ght 7 python performance multi-index pandas

pd.MultiIndex使用不同的类方法创建相等的性能测试:

import pandas as pd

size_mult = 8
d1 = [1]*10**size_mult
d2 = [2]*10**size_mult

pd.__version__
Run Code Online (Sandbox Code Playgroud)
'0.24.2'
Run Code Online (Sandbox Code Playgroud)

.from_arraysfrom_tuplesfrom_frame

# Cell from_arrays
%%time
index_arr = pd.MultiIndex.from_arrays([d1, d2], names=['a', 'b'])
# Cell from_tuples
%%time
index_tup = pd.MultiIndex.from_tuples(zip(d1, d2), names=['a', 'b'])
# Cell from_frame
%%time
df = pd.DataFrame({'a':d1, 'b':d2})
index_frm = pd.MultiIndex.from_frame(df)
Run Code Online (Sandbox Code Playgroud)

单元的相应输出:

# from_arrays
CPU times: user 1min 15s, sys: 6.58 s, total: 1min 21s
Wall time: 1min 21s
# from_tuples
CPU times: user 26.4 s, sys: 4.99 s, total: 31.4 s
Wall time: 31.3 s
# from_frame
CPU times: user 47.9 s, sys: 5.65 s, total: 53.6 s
Wall time: 53.7 s
Run Code Online (Sandbox Code Playgroud)

让我们检查一下所有结果是否相同

index_arr.difference(index_tup)
index_arr.difference(index_frm)
Run Code Online (Sandbox Code Playgroud)

所有行产生:

MultiIndex(levels=[[1], [2]],
           codes=[[], []],
           names=['a', 'b'])
Run Code Online (Sandbox Code Playgroud)

那么为什么会有如此大的差异呢?from_arrays比慢3倍from_tuples。它甚至比创建DataFrame和在其之上构建索引要慢。

编辑:

我做了另一个更通用的测试,结果却相反:

np.random.seed(232)

size_mult = 7
d1 = np.random.randint(0, 10**size_mult, 10**size_mult)
d2 = np.random.randint(0, 10**size_mult, 10**size_mult)

start = pd.Timestamp.now()
index_arr = pd.MultiIndex.from_arrays([d1, d2], names=['a', 'b'])
print('ARR done in %f' % (pd.Timestamp.now()-start).total_seconds())

start = pd.Timestamp.now()
index_tup = pd.MultiIndex.from_tuples(zip(d1, d2), names=['a', 'b'])
print('TUP done in %f' % (pd.Timestamp.now()-start).total_seconds())
Run Code Online (Sandbox Code Playgroud)
ARR done in 9.559764
TUP done in 70.457208
Run Code Online (Sandbox Code Playgroud)

因此,from_tuples尽管源数据相同,但现在明显要慢一些。

小智 1

你的第二个例子对我来说更有意义。查看 Pandas 的源代码,from_tuples实际上调用了from_arrays,所以对我来说这from_arrays会更快。

from_tuples在这里还做了一些额外的步骤,这会花费更多的时间:

  1. 您传入了 a zip(d1, d2),它实际上是一个迭代器。from_tuples 将其转换为列表
  2. 在转换为元组列表后,它会经过一个额外的步骤将其转换为numpy 数组列表
  3. 上一步迭代元组列表两次,使得速度from_tuples明显慢于from_arrays,立刻。

所以总的来说,我并不惊讶from_tuples速度慢,因为它必须在元组列表中额外迭代两次(并做一些额外的事情),然后才能进入函数from_arrays(顺便说一句,它会再迭代几次))无论如何它都会使用。