为什么 pd.concat({}, axis=1) 比 pd.concat({}, axis=0).unstack(0) 要慢?

7
考虑以下这个Pandas系列字典。 所有系列的索引都是整数,并且可能存在一些重叠,但肯定不会完全重合。 我观察到当我有大量索引,许多不重叠和许多要连接的项时,沿着axis=1组合东西时,pd.concat似乎很慢。 这促使我离开axis=0并随后unstack()。 我最终得到了完全相同的结果。 但是unstacking更快。
有人知道为什么会出现这种情况吗?
我知道将系列堆叠在一起应该很快,但我本以为unstacking过程与pd.concat(axis=1)几乎相同。
dict_of_series = {
    's%s' % i: pd.Series(
        1, np.unique(np.random.randint(1000, 10000, size=1000))
    ) for i in range(100)
}

%%timeit
pd.concat(dict_of_series, axis=0).unstack(0)

10个循环,3次中的最佳结果:每个循环29.6毫秒

%%timeit
pd.concat(dict_of_series, axis=1)

进行了10次循环,每个循环平均需要43.1毫秒

1个回答

3
一个快速的分析显示,在调用 pd.concat(dict_of_series, axis=1) 时,大量时间都被 pd.Index.union 占用。它在内部函数 _union_indexes 中逐个对每个索引进行调用 - 就像在我的函数 union 中一样。
另一方面,pd.concat(dict_of_series, axis=0).unstack(0) 利用了一些巧妙的优化,我没有尝试分析。无论如何,在那里没有调用 _union_indexes 或者甚至是 pd.Index.union
'_union_indexes' 可能是罪魁祸首吗?很可能。我只取了索引:
idxs = [d.index for d in dict_of_series.values()]

并比较了以下两个函数:

def union(idxs):
    ans = pd.Index([])
    for idx in idxs:
        ans = ans.union(idx)
    return ans

def union_multi(idxs):
    arr0 = np.concatenate(idxs)
    arr1 = np.zeros(arr0.size)
    ans = pd.MultiIndex.from_arrays([arr0, arr1])
    return ans.levels[0]

union_union_indexes 的等价物,而 union_multi 有一些多重索引开销,但避免了对 pd.Index.union 的调用。

我的粗略计时:

>>> %timeit -n1 -r1 pd.concat(dict_of_series, axis=1)
1 loop, best of 1: 82.9 ms per loop
>>> %timeit -n1 -r1 pd.concat(dict_of_series, axis=0).unstack(0)
1 loop, best of 1: 57.9 ms per loop

>>> %timeit -n1 -r1 union(idxs)
1 loop, best of 1: 32.8 ms per loop
>>> %timeit -n1 -r1 union_multi(idxs)
1 loop, best of 1: 12.5 ms per loop

一个简单的 pd.Index(np.unique(np.concatenate(idxs))) 速度稍快,但不能用于混合类型。

(顺便提一下,pd.concat 只在所有索引都是唯一的情况下才能工作。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接