如何在新数据帧中存储多索引数据帧的子集?

时间:2017-10-07 18:21:15

标签: python pandas select dataframe multi-index

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

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分: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