2015-06-19 131 views
2

假设我有以下数据框:索引数据帧后更新大熊猫多指标

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'], 
     ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']] 
tuples = list(zip(*arrays)) 
index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second']) 
s = pd.DataFrame(np.random.randn(8, 2), index=index, columns=[0, 1]) 
s 

        0   1 
first second      
bar one -0.012581 1.421286 
     two -0.048482 -0.153656 
baz one -2.616540 -1.368694 
     two -1.989319 1.627848 
foo one -0.404563 -1.099314 
     two -2.006166 0.867398 
qux one -0.843150 -1.045291 
     two  2.129620 -2.697217 

我知道通过索引选择子非数据帧:

temp = s.loc[('bar', slice(None)), slice(None)].copy() 
temp 

        0   1 
first second      
bar one -0.012581 1.421286 
     two -0.048482 -0.153656 

但是,如果我看的指数,原始索引的值仍然出现:

temp.index 
MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']], 
     labels=[[0, 0], [0, 1]], 
     names=[u'first', u'second']) 

这对正常的数据帧不会发生。如果您编制索引,剩余的副本(甚至视图)只包含选定的索引/列。这是烦人,因为我可能会经常做很多的大dataframes过滤,并在结束时,我想通过只是在做

df.index 
df 

这也发生了多指标列知道还剩下什么指标。是否有更新索引/列并删除空条目的正确方法?

要清楚,我希望过滤的数据帧具有相同的结构(多索引索引和列)。例如,我想做的事:

temp = s.loc[(('bar', 'foo'), slice(None)), :] 

但指数仍然有“巴兹”和“qux的价值观:

MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']], 
     labels=[[0, 0, 2, 2], [0, 1, 0, 1]], 
     names=[u'first', u'second']) 

要清楚,我想看看效果,我写了这snippet消除多余条目:

import pandas as pd 
def update_multiindex(df): 
    if isinstance(df.columns, pd.MultiIndex): 
     new_df = {key: df.loc[:, key] for key in df.columns if not df.loc[:,  key].empty}  
     new_df = pd.DataFrame(new_df) 
    else: 
     new_df = df.copy() 
    if isinstance(df.index, pd.MultiIndex): 
     new_df = {key: new_df.loc[key, :] for key in new_df.index if not  new_df.loc[key, :].empty} 
     new_df = pd.DataFrame(new_df).T 
    return new_df 

temp = update_multiindex(temp).index 
temp 
MultiIndex(levels=[[u'bar', u'foo'], [u'one', u'two']], 
     labels=[[0, 0, 1, 1], [0, 1, 0, 1]]) 
+0

我有这个确切的问题,我想你会发现Ezekiel Kruglick(在这个页面上)的答案可以最好地解决你的问题。我添加了一个.unique()来删除重复项:'df.index.get_level_values(some_level).unique()' –

回答

0

尝试使用droplevel

temp.index = temp.index.droplevel() 

>>> temp 
       0   1 
second      
one  0.450819 -1.071271 
two -0.371563 0.411808 

>>> temp.index 
Index([u'one', u'two'], dtype='object') 

当列打交道,这是同样的事情:

df.columns = df.columns.droplevel() 

您还可以使用xsdrop_level参数设置为True(默认值为False):

>>> s.xs('bar', drop_level=True) 
       0   1 
second      
one  0.450819 -1.071271 
two -0.371563 0.411808 
+1

这是一个未公开的方法,截至0.16.2。任何想法为什么熊猫没有'MultiIndex()'的API文档? – Andreus

+0

不知道为什么没有记录水滴。这里是MultiIndex的文档:http://pandas.pydata.org/pandas-docs/stable/advanced.html – Alexander

+0

我不想放弃关卡。我的例子是基本的,但我想过滤一个级别的多个值,并消除其他人。因此,我希望具有相同的结构,但只在过滤的数据帧索引和/或列中具有正确的值。 – user1350191

0

s索引与temp索引之间存在差异:

In [25]: s.index 
Out[25]: 
MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']], 
      labels=[[0, 0, 1, 1, 2, 2, 3, 3], [0, 1, 0, 1, 0, 1, 0, 1]], 
      names=[u'first', u'second']) 

In [26]: temp.index 
Out[26]: 
MultiIndex(levels=[[u'bar', u'baz', u'foo', u'qux'], [u'one', u'two']], 
      labels=[[0, 0], [0, 1]], 
      names=[u'first', u'second']) 

注意MultiIndex中的labels是不同的。

+0

有趣的是,我想我得到为什么这些级别仍然在那里,但如果它们被有效地消除了(即没有标签指向这些值),那么为什么要保留它们? – user1350191

+0

我的猜测是,离开MultiIndex的水平是有效的。如果您更改了关卡,则每次切片时都需要更新MultiIndex的标签。 – MangoHands

2

两点。首先,我认为你可能想要做一些对你不利的事情。我知道这很烦人,你在你的过滤索引中有很多额外的东西,但是如果你重建索引以排除缺失的分类值,那么你的新索引将与其他索引和原始索引不兼容。

这就是说,我怀疑(但不知道)MultiIndex使用这种方式是建立在CategoricalIndex之上,它有方法remove_unused_levels()。它可能包裹MultiIndex,但我不能说,因为...

其次,MultiIndex明显缺少pandas API documentation。我不使用MultiIndex,但如果您经常使用它,您可能会考虑在GitHub上寻找和/或打开关于此的票。除此之外,如果您想查找有关MultiIndex可用功能的确切信息,则可能需要通过source code

+0

好点。谢谢! – user1350191

1

如果我理解正确,你的使用模式,你可能会得到两全其美。我重点关注:

这是烦人,因为我可能会经常做很多筛选的就大 dataframes,并在结束时,我想知道的是什么 通过只是在做

DF左指数.index df

这也适用于多索引列。是否有更新索引/列并删除空条目的正确方法 ?

考虑(1)是你想知道什么是剩下的索引。考虑(2)就像上面提到的那样,如果你修改多重索引,你不能将任何数据重新合并到你的原始数据中,而且它的一些非显而易见的步骤也不会被鼓励。

底层的基本原理是,如果任何行或列已被删除,且索引不会为多索引返回更新的内容,并且这不被视为错误,因为这不是MultiIndexes的批准使用(请阅读:github.com/pydata/pandas/issues/3686)。 MultiIndex当前内容的有效API访问权限为get_level_values。

那么它会适合你的需要来调整你的实践使用它?

df.index.get_level_values(-put your level name or number here-) 

对于多指数这是批准的API访问技术,并有一些很好的理由。如果您使用get_level_values而不是.index,那么您将能够获取当前内容,同时保留所有信息以防您想要重新合并修改后的数据,或者与原始索引进行匹配以进行比较,分组等。 。

这是否符合您的需求?