【发布时间】:2019-06-26 14:36:37
【问题描述】:
假设我有一个熊猫系列,我想将其用作多映射(每个索引键有多个值):
# intval -> data1
a = pd.Series(data=-np.arange(100000),
index=np.random.randint(0, 50000, 100000))
我想(尽快)从a 中选择所有值
其中a 的索引与另一个索引b 匹配。 (就像一个内部连接。或者一个合并,但对于系列)。
-
a的索引中可能有重复项。 -
b可能没有重复项,也不一定是a索引的子集。为了给 pandas 最好的机会,我们假设b也可以作为排序索引对象提供:
b = pd.Index(np.unique(np.random.randint(30000, 100000, 100000))).sortvalues()
所以,我们会有类似的东西:
target
a b result
3 0 3 3 0
3 1 7 8 3
4 2 8 ...
8 3 ...
9 4
...
我也只对获取结果的值感兴趣(不需要索引[3,8,...])。
如果a 没有重复项,我们只需这样做:
a.reindex(b) # Cannot reindex a duplicate axis
因为&维护了a的副本,我们不能这样做:
d = a[a.index & b.index]
d = a.loc[a.index & b.index] # same
d = a.get(a.index & b.index) # same
print d.shape
所以我认为我们需要这样做:
common = (a.index & b.index).unique()
a.loc[common]
...这很麻烦,但也很慢。它不是建立要选择的项目列表很慢:
%timeit (a.index & b).unique()
# 100 loops, best of 3: 3.39 ms per loop
%timeit (a.index & b).unique().sort_values()
# 100 loops, best of 3: 4.19 ms per loop
...所以看起来它确实检索缓慢的值:
common = ((a.index & b).unique()).sort_values()
%timeit a.loc[common]
#10 loops, best of 3: 43.3 ms per loop
%timeit a.get(common)
#10 loops, best of 3: 42.1 ms per loop
...每秒大约 20 次操作。不完全是活泼的!为什么这么慢?
肯定有一种快速的方法可以从 pandas 数据框中查找一组值吗?我不想得到一个索引对象——实际上我所要求的只是对排序索引进行合并,或者(较慢)散列 int 查找。不管怎样,这应该是一个非常快的操作——而不是在我的 3Ghz 机器上每秒 20 个操作。
还有:
分析a.loc[common]给:
ncalls tottime percall cumtime percall filename:lineno(function)
# All the time spent here.
40 1.01 0.02525 1.018 0.02546 ~:0(<method 'get_indexer_non_unique' indexing.py:1443(_has_valid_type)
...
# seems to be called a lot.
1500 0.000582 3.88e-07 0.000832 5.547e-07 ~:0(<isinstance>)
PS。我之前发布了一个类似的问题,关于为什么 Series.map 这么慢 Why is pandas.series.map so shockingly slow? 。原因是引擎盖下的惰性索引。这似乎没有发生在这里。
更新:
对于大小相似的 a 和常见的 a 是唯一的:
% timeit a.loc[common]
1000 loops, best of 3: 760 µs per loop
...正如@jpp 指出的那样。多索引可能是罪魁祸首。
【问题讨论】:
-
我给出了一半的答案,即“为什么慢”。至于“如何使其更快[使用非唯一索引]”,我认为这对于 Pandas 来说并非易事。请不要回答这个问题。
-
@coldspeed,我认为这个问题还有第二部分(即如何使用非唯一索引加速它),这就是为什么我建议 OP 不要接受我的答案。但也许这让它太宽泛了..不确定,但这是一个有效且具体的问题。
-
@jpp 我建议添加一个 cumcounted 索引以形成一个唯一的多索引。应该希望使它成为恒定的时间(因为索引是唯一的)。我会等待 OP 澄清(他们的第二部分不清楚)并将重新打开。
-
回复:重复的问题。我的问题是在不了解导致缓慢行为的原因的情况下提出的。它似乎相关,但不是引用问题的重复(这表明我们的非唯一索引在问题中很慢)。
-
+ 我也在寻找如何解决这个问题(引用的问题没有)。回复,累计指数。听起来像是正确的解决方法——虽然不明显如何在不循环 Python 的情况下使用索引。不过会考虑的。
标签: python pandas performance indexing