在熊猫MultiIndex DataFrame

时间:2018-12-26 04:36:12

标签: python pandas dataframe slice multi-index

客观动机

MultiIndex API多年来一直受到欢迎,但是,就结构,工作和相关操作而言,并不是所有有关它的内容都被完全理解。

一项重要的操作是过滤。过滤是一个常见的要求,但是用例是多种多样的。因此,某些方法和功能将比其他方法和功能更适用于某些用例。

总而言之,本文旨在解决一些常见的过滤问题和用例,演示解决这些问题的各种不同方法,并讨论其适用性。这篇文章试图解决的一些高级问题是

  • 基于单个值/标签的切片
  • 基于一个或多个级别的多个标签进行切片
  • 过滤布尔条件和表达式
  • 哪种方法在什么情况下适用

这些问题已分解为6个具体问题,如下。为简单起见,下面设置中的示例DataFrame仅具有两个级别,并且没有重复的索引键。针对该问题提出的大多数解决方案可以推广到N个级别。

本文将介绍如何创建MultiIndexes,如何对它们执行赋值操作或任何与性能相关的讨论(这些是下次的单独主题)。


问题

  

将根据以下设置询问问题1-6。

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

问题1::选择单个项目
如何选择在“一个”级别中具有“ a”的行?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

另外,我如何在输出中将级别“ one”降低?

     col
two     
t      0
u      1
v      2
w      3

问题1b
如何在级别“ two”上切片所有值为“ t”的行?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

问题2::在一个级别中选择多个值
如何在级别“ one”中选择与项目“ b”和“ d”相对应的行?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

问题2b
我如何获得与“两个”级别中的“ t”和“ w”相对应的所有值?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

问题3::将单个横截面切成(x, y)
如何从df检索横截面,即具有特定索引值的一行?具体来说,如何获取{p>给出的('c', 'u')的横截面

         col
one two     
c   u      9

问题4::切片多个横截面[(a, b), (c, d), ...]
如何选择与('c', 'u')('a', 'w')对应的两行?

         col
one two     
c   u      9
a   w      3

问题5:每级切成一个项目
如何检索与“一个”级别中的“ a”或“第二”级别中的“ t”相对应的所有行?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

问题6:任意切片
如何切特定的横截面?对于“ a”和“ b”,我想选择子级别为“ u”和“ v”的所有行,对于“ d”,我想选择子级别为“ w”的行。

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15
  

问题7将使用由数字级别组成的独特设置:

np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    np.random.choice(10, size=16)
], names=['one', 'two'])

df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)

         col
one two     
a   5      0
    0      1
    3      2
    3      3
b   7      4
    9      5
    3      6
    5      7
    2      8
c   4      9
    7     10
d   6     11
    8     12
    8     13
    1     14
    6     15

问题7:在数字级别进行基于不等式的过滤
如何获得“二级”中的值大于5的所有行?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

2 个答案:

答案 0 :(得分:2)

这看起来是 dfsql

的绝佳案例
df.sql(<SQL select statement>)

https://github.com/mindsdb/dfsql

这里有一篇关于它的完整文章:

https://medium.com/riselab/why-every-data-scientist-using-pandas-needs-modin-bringing-sql-to-dataframes-3b216b29a7c0

答案 1 :(得分:0)

最近,我遇到一个用例,其中有一个3级以上的多索引数据框,在其中我无法使上面的任何解决方案产生想要的结果。上面的解决方案很可能确实可以在我的用例中使用,我尝试了几种,但是我无法在有空的时候让它们使用。

我距离专家还很远,但是我偶然发现了上面综合答案中未列出的解决方案。我不保证解决方案在任何方面都是最佳的。

这是获得与上面问题#6稍有不同的结果的不同方法。 (以及其他可能的问题)

特别是我在寻找:

  1. 从索引的一个级别中选择两个以上值,从索引的另一个级别中选择一个值的方法,
  2. 一种将索引操作保留在数据帧输出中的方式。

作为齿轮上的活动扳手(但是完全可以固定):

  1. 索引未命名。

在下面的玩具数据框中:

    index = pd.MultiIndex.from_product([['a','b'],
                               ['stock1','stock2','stock3'],
                               ['price','volume','velocity']])

    df = pd.DataFrame([1,2,3,4,5,6,7,8,9,
                      10,11,12,13,14,15,16,17,18], 
                       index)

                        0
    a stock1 price      1
             volume     2
             velocity   3
      stock2 price      4
             volume     5
             velocity   6
      stock3 price      7
             volume     8
             velocity   9
    b stock1 price     10
             volume    11
             velocity  12
      stock2 price     13
             volume    14
             velocity  15
      stock3 price     16
             volume    17
             velocity  18

当然,使用以下作品:

    df.xs(('stock1', 'velocity'), level=(1,2))

        0
    a   3
    b  12

但是我想要一个不同的结果,所以获得该结果的方法是:

   df.iloc[df.index.isin(['stock1'], level=1) & 
           df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
    b stock1 velocity  12

如果我想从一个级别获得两个以上的值,并从另一个级别获得一个(或2个以上)值:

    df.iloc[df.index.isin(['stock1','stock3'], level=1) & 
            df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
      stock3 velocity   9
    b stock1 velocity  12
      stock3 velocity  18

上面的方法可能有点笨拙,但是我发现它可以满足我的需求,而且奖金对我来说更易于理解和阅读。