26

我有一个带有 (time,ticker) Multiindex 和bid/ask/etc 数据列的DataFrame“df”:

                          tod 最后出价 询价量
    时间记录器                  
    2013-02-01 间谍 1600 149.70 150.14 150.17 1300
                SLV 1600 30.44 30.38 30.43 3892
                GLD 1600 161.20 161.19 161.21 3860

我想使用多个键选择第二级(级别 = 1)横截面。现在,我可以用一键完成,即

    df.xs('SPY', level=1)

这给了我一个间谍的时间序列。选择多键横截面的最佳方法是什么,即 SPY 和 GLD 的组合横截面,例如:

    df.xs(['SPY', 'GLD'], level=1)

?

4

4 回答 4

21

使用更新版本的 Pandas 有更好的方法来执行此操作(请参阅版本更改日志中的使用切片器进行多索引0.14):

regression_df.loc[(slice(None), ['SPY', 'GLD']), :]

这可以通过使用变得更具可读性pd.IndexSlice

df.loc[pd.IndexSlice[:, ['SPY', 'GLD']], :]

有了约定idx = pd.IndexSlice,这就变成了

df.loc[idx[:, ['SPY', 'GLD']], :]
于 2016-03-27T03:31:31.347 回答
10

除了使用之外,我找不到更直接的方法select

>>> df

       last   tod
A SPY     1  1600
  SLV     2  1600
  GLD     3  1600

>>> df.select(lambda x: x[1] in ['SPY','GLD'])

       last   tod
A SPY     1  1600
  GLD     3  1600
于 2013-03-17T22:47:35.157 回答
4

对于它的价值,我做了以下事情:

foo = pd.DataFrame(np.random.rand(12,3), 
                   index=pd.MultiIndex.from_product([['A','B','C','D'],['Green','Red','Blue']], 
                                                    names=['Letter','Color']),
                   columns=['X','Y','Z']).sort_index()

foo.reset_index()\
   .loc[foo.reset_index().Color.isin({'Green','Red'})]\
   .set_index(foo.index.names)

此方法类似于 select,但避免使用 lambda 迭代所有行。

但是,我将其与 Panel 方法进行了比较,看起来 Panel 解决方案更快(index/loc 为 2.91 ms,to_panel/to_frame 为 1.48 ms:

foo.to_panel()[:,:,['Green','Red']].to_frame()

时间:

In [56]:
%%timeit
foo.reset_index().loc[foo.reset_index().Color.isin({'Green','Red'})].set_index(foo.index.names)
100 loops, best of 3: 2.91 ms per loop

In [57]:
%%timeit
foo2 = foo.reset_index()
foo2.loc[foo2.Color.eq('Green') | foo2.Color.eq('Red')].set_index(foo.index.names)
100 loops, best of 3: 2.85 ms per loop

In [58]:
%%timeit
foo2 = foo.reset_index()
foo2.loc[foo2.Color.ne('Blue')].set_index(foo.index.names)
100 loops, best of 3: 2.37 ms per loop

In [54]:
%%timeit
foo.to_panel()[:,:,['Green','Red']].to_frame()
1000 loops, best of 3: 1.18 ms per loop

更新

在(再次)重新审视这个话题后,我观察到以下几点:

In [100]:
%%timeit
foo2 = pd.DataFrame({k: foo.loc[k] for k in foo.index if k[1] in ['Green','Red']}).transpose()
foo2.index.names = foo.index.names
foo2.columns.names = foo2.columns.names
100 loops, best of 3: 1.97 ms per loop

In [101]:
%%timeit
foo2 = pd.DataFrame.from_dict({k: foo.loc[k] for k in foo.index if k[1] in ['Green','Red']}, orient='index')
foo2.index.names = foo.index.names
foo2.columns.names = foo2.columns.names
100 loops, best of 3: 1.82 ms per loop

如果您不关心保留级别的原始顺序和命名,您可以使用:

%%timeit
pd.concat({key: foo.xs(key, axis=0, level=1) for key in ['Green','Red']}, axis=0)
1000 loops, best of 3: 1.31 ms per loop

如果您只是在第一级选择:

%%timeit
pd.concat({key: foo.loc[key] for key in ['A','B']}, axis=0, names=foo.index.names)
1000 loops, best of 3: 1.12 ms per loop

相对:

%%timeit
foo.to_panel()[:,['A','B'],:].to_frame()
1000 loops, best of 3: 1.16 ms per loop

另一个更新

如果您对示例的索引进行排序,foo则上述许多情况都会有所改善(时间已更新以反映预排序的索引)。但是,在对索引进行排序时,可以使用 user674155 描述的解决方案:

%%timeit
foo.loc[(slice(None), ['Blue','Red']),:]
1000 loops, best of 3: 582 µs per loop

在我看来,这是最有效和最直观的(用户不需要了解面板以及它们是如何从框架创建的)。

注意:即使索引尚未排序,动态排序索引的foo性能与to_panel选项相当。

于 2016-02-25T20:05:24.967 回答
1

转换为面板,然后索引是直接的

In [20]: df = pd.DataFrame(dict(time = pd.Timestamp('20130102'), 
                                A = np.random.rand(3), 
                 ticker=['SPY','SLV','GLD'])).set_index(['time','ticker'])

In [21]: df
Out[21]: 
                          A
time       ticker          
2013-01-02 SPY     0.347209
           SLV     0.034832
           GLD     0.280951

In [22]: p = df.to_panel()

In [23]: p
Out[23]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 1 (items) x 1 (major_axis) x 3 (minor_axis)
Items axis: A to A
Major_axis axis: 2013-01-02 00:00:00 to 2013-01-02 00:00:00
Minor_axis axis: GLD to SPY

In [24]: p.ix[:,:,['SPY','GLD']]
Out[24]: 
<class 'pandas.core.panel.Panel'>
Dimensions: 1 (items) x 1 (major_axis) x 2 (minor_axis)
Items axis: A to A
Major_axis axis: 2013-01-02 00:00:00 to 2013-01-02 00:00:00
Minor_axis axis: SPY to GLD
于 2013-03-18T14:08:05.203 回答