【问题标题】:How to store subset of a multiindex dataframe in a new dataframe?如何将多索引数据帧的子集存储在新数据帧中?
【发布时间】:2018-03-19 07:33:18
【问题描述】:

我有一个这样的多索引数据框:

import pandas as pd
import numpy as np


df = pd.DataFrame({'ind1': list('aaaaaaaaabbbbbbbbb'),
                   'ind2': list('cccdddeeecccdddeee'),
                   'ind3': list(range(3))*6,
                   'val1': list(range(100, 118)),
                   'val2': list(range(70, 88))})

df_mult = df.set_index(['ind1', 'ind2', 'ind3'])

                val1  val2
ind1 ind2 ind3            
a    c    0      100    70
          1      101    71
          2      102    72
     d    0      103    73
          1      104    74
          2      105    75
     e    0      106    76
          1      107    77
          2      108    78
b    c    0      109    79
          1      110    80
          2      111    81
     d    0      112    82
          1      113    83
          2      114    84
     e    0      115    85
          1      116    86
          2      117    87

我现在可以像这样使用.loc 选择它的一个子集

df_subs = df_mult.loc['a', ['c', 'd'], :]

这给出了预期

                val1  val2
ind1 ind2 ind3            
a    c    0      100    70
          1      101    71
          2      102    72
     d    0      103    73
          1      104    74
          2      105    75

如果我现在想再次选择df_subs 的子集,例如

df_subs.loc['a', 'c', :]

工作并给予

      val1  val2
ind3            
0      100    70
1      101    71
2      102    72

然而

df_subs.loc[:, 'c', :]

失败并给出错误

KeyError: '标签 [c] 不在 [列]'

为什么会失败?

编辑

最初,我在这篇文章中有两个问题。我一分为二,第二个问题可以找到here

【问题讨论】:

  • pandas.pydata.org/pandas-docs/stable/advanced.html 为什么不使用sliceIndexSlice
  • @Wen:当然,可能有更好的选择,但我仍然想了解上述尝试失败的原因。如果尝试完全错误,那么很高兴看到正确的做法,即工作替代方案。
  • @JohnE:好的,很高兴知道。我仍然需要弄清楚我什么时候必须使用IndexSlice。但似乎对于问题 1 并没有任何改变:df_mult.loc[pd.IndexSlice['a', ['c', 'd'], :], :].index 仍然在级别 0 中显示 ab;知道为什么吗?
  • @JohnE:如果我想将索引的元素用于其他用途,这可能会成为一个问题。然后df_subs.index.levels[0] 给了我Index([u'a', u'b'], dtype='object', name=u'ind1'),但是df_subs.index.get_level_values('ind1').unique() 给了我Index([u'a'], dtype='object', name=u'ind1'),这在我看来是不一致的。
  • 是的,公平点!尽管我在 99.9% 的时间里都不确定实际的重要性

标签: python pandas select dataframe multi-index


【解决方案1】:

显然,使用.loc 可能会以原始形式保留索引,直到它们被重置。使用.copy() 来避免原始数据框的任何视图仍然保留多索引值。

df_subs = df_mult.loc['a', ['c', 'd'], :].copy()

print(df_subs.index)
# MultiIndex(levels=[['a', 'b'], ['c', 'd', 'e'], [0, 1, 2]],
#            labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
#            names=['ind1', 'ind2', 'ind3'])

此外,按值过滤仍然保留多索引值:

df_subs = df_mult[df_mult['val1'] <= 105]

print(df_subs)
#                 val1  val2
# ind1 ind2 ind3            
# a    c    0      100    70
#           1      101    71
#           2      102    72
#      d    0      103    73
#           1      104    74
#           2      105    75

print(df_subs.index)
# MultiIndex(levels=[['a', 'b'], ['c', 'd', 'e'], [0, 1, 2]],
#            labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
#            names=['ind1', 'ind2', 'ind3'])

因此,请考虑按照您的原始分配手动重置索引

df_subs = df_mult.loc['a', ['c', 'd'], :].reset_index()

df_subs = df_subs.set_index(['ind1', 'ind2', 'ind3'])

print(df_subs.index)
# MultiIndex(levels=[['a'], ['c', 'd'], [0, 1, 2]],
#            labels=[[0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1], [0, 1, 2, 0, 1, 2]],
#            names=['ind1', 'ind2', 'ind3'])

最后,对于最后一个.loc 分配(#2),至少提供可能需要的第一个索引:

df_subs2 = df_subs.loc['a', 'c', :]
#       val1  val2
# ind3            
# 0      100    70
# 1      101    71
# 2      102    72

【讨论】:

    【解决方案2】:

    通过使用IndexSlice

    idx = pd.IndexSlice
    df_subs.loc[idx[:, 'c',:],:]
    Out[159]: 
                    val1  val2
    ind1 ind2 ind3            
    a    c    0      100    70
              1      101    71
              2      102    72
    

    或者您需要在行或列上进行特定切片

    df_subs.loc(axis=0)[:, 'c', :]
    Out[196]: 
                    val1  val2
    ind1 ind2 ind3            
    a    c    0      100    70
              1      101    71
              2      102    72
    

    .loc[:, 'c', :]不能工作的原因:

    您应该在 .loc 说明符中指定所有轴,即索引和列的索引器。在某些模棱两可的情况下,传递的索引器可能会被误解为索引两个轴,而不是说为行的 MuliIndex。

    Link1

    Link2

    【讨论】:

    • 好的,很高兴知道一个可行的替代方案(赞成)。但是,您知道为什么带有.loc 的版本不起作用吗?此外df_subs.loc[idx[:, 'c',:],:].index 在级别 0 中仍有 ab;知道为什么吗?
    • @Cleb 这是 git 中的讨论。你可以检查我提供的两个链接 ~ :-) 为了更安全,你可以只使用 slice 或 IndexSlice :)
    • 有趣的阅读,谢谢。我还编辑了关于问题 1 的问题;任何关于这个的cmets? (现在我不确定这是否真的相关,所以我认为应该把它分成两个问题)。
    • @Cleb 我不太确定你的 q1,你猜猜看,应该是 category 或 factor 之类的东西,即使你把它们切片,它们仍然显示原来的水平
    • 好的。我将删除这部分并为它打开一个新问题。那我已经可以在这里接受你的回答了。给我几分钟... :)
    猜你喜欢
    • 2021-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    • 2018-12-15
    • 2014-12-02
    相关资源
    最近更新 更多