假设我有一个 pandas 系列,我想将其用作多重映射(每个索引键有多个值):
# intval -> data1
a = pd.Series(data=-np.arange(100000),
index=np.random.randint(0, 50000, 100000))
我想(尽快)选择来自的所有值a
where a
的索引与另一个索引匹配b
。 (就像内部联接。或者合并但用于系列)。
-
a
其索引中可能有重复项。
-
b
可能没有重复项,也不一定是a
的索引。为了给熊猫最好的机会,我们假设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,...]
不需要)。
If a
没有重复项,我们只需这样做:
a.reindex(b) # Cannot reindex a duplicate axis
Because &
维护的重复项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 次操作。
Also:
分析a.loc[common]
give:
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>)
附言。我之前发布过类似的问题,关于为什么 Series.map 这么慢为什么 pandas.series.map 如此慢? https://stackoverflow.com/questions/50633939/why-is-pandas-series-map-so-shockingly-slow。原因是引擎盖下的懒惰索引。这似乎并没有发生在这里。
Update:
对于类似大小的 a 和 common,其中 a 是唯一的:
% timeit a.loc[common]
1000 loops, best of 3: 760 µs per loop
...正如@jpp 指出的那样。多索引可能是罪魁祸首。