Pandas 从数据帧中选择多关键点横截面
我有一个数据帧“df”,带有(时间、股票代码)多索引和bid/ask/etc数据列: tod last bid ask volume time ticker 2013-02-01 SPY 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 最后一次买卖量 计时器 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) df.xs('SPY',级别=1) 这给了我一系列的间谍。选择多键横截面(即SPY和GLD的组合横截面)的最佳方法是什么,例如: df.xs(['SPY', 'GLD'], level=1) df.xs(['SPY','GLD'],级别=1)Pandas 从数据帧中选择多关键点横截面,pandas,Pandas,我有一个数据帧“df”,带有(时间、股票代码)多索引和bid/ask/etc数据列: tod last bid ask volume time ticker 2013-02-01 SPY 1600 149.70 150.14 150.17 1300 SLV 1600 30.44 30.38 30.43
?除了使用
选择,我找不到更直接的方法:
>>> 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
转换为面板,则索引是直接的
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
[20]中的:df=pd.DataFrame(dict(time=pd.Timestamp('20130102'),
A=np.随机随机随机数(3),
ticker=['SPY'、'SLV'、'GLD'])。设置索引(['time'、'ticker'])
In[21]:df
出[21]:
A.
计时器
2013-01-02间谍0.347209
SLV 0.034832
GLD 0.280951
In[22]:p=df.to_面板()
In[23]:p
出[23]:
尺寸:1(项目)x 1(长轴)x 3(短轴)
项目轴:A至A
长轴:2013-01-02 00:00:00至2013-01-02 00:00:00
短轴:GLD至SPY
在[24]:p.ix[:,:,['SPY','GLD']]
出[24]:
尺寸:1(项目)x1(长轴)x2(短轴)
项目轴:A至A
长轴:2013-01-02 00:00:00至2013-01-02 00:00:00
短轴:侦察到GLD
为了它的价值,我做了以下几点:
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)
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
此方法类似于select,但避免使用lambda迭代所有行
然而,我将其与面板方法进行了比较,结果显示面板解决方案更快(索引/位置为2.91毫秒,而to_面板/to_框架为1.48毫秒:
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
更新
在(再次)重温这个话题之后,我观察到以下几点:
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)
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_面板
选项相当。对于较新版本的Pandas,有更好的方法可以做到这一点(参见版本0.14
的更改日志):
可通过使用以下工具使其更具可读性:
df.loc[pd.indexlice[:,['SPY','GLD']],:]
按照惯例,idx=pd.indexlice
,这就变成了
df.loc[idx[:,['SPY','GLD']],:]
Nice,这可能是最简单的方法。我想知道这是否是最有效的方法,因为为每一行调用lambda可能会很慢,但我也不确定当前版本中是否有更快的方法。请参见上面的面板解决方案?对于任何类型的非平凡框架,选择“如果效率非常低”。请注意,如果您有multi索引为列;)面板将分解稀疏结构。答案更一般