【问题标题】:Pandas MultiIndex, selecting values by 1. and 2. levelPandas MultiIndex,按 1. 和 2. 级别选择值
【发布时间】:2018-03-25 15:14:42
【问题描述】:

我在选择 1. 和 2. 级别内的值时遇到了一些问题。

我通过设置 header = [0,1] 获得了 MultiIndex

In[1]:  df = pd.read_csv('Data.txt', sep='\t', header=[0,1], skipinitialspace=True)

In[2]:  print(df.columns)

Out[2]: MultiIndex(
        levels=[['20052065', '20052066', '20052082', '20052087', '20052089'], 
                ['CTF1', 'CTF2', 'CTF3', 'CTF_M', 'CTM1', 'CTM2', 'CTM3', 'CTM_M']],
        labels=[[...]],
        names=[...])

如果尝试获取2.level值和选中元素的数据 从 1. 级别我得到以下输出:

In[3]:  print(df['20052065'][['CTF1','CTF_M']])

Out[3]: TIME[s]     CTF1    CTF_M
        0.000    -14.386   14.963
        60.000   -26.937   34.729
        120.000  -29.986   58.265
            ...      ...      ...

现在我尝试为 2 个元素生成输出并执行以下操作:

In[4]:  print(df[['20052065','20052066']][['CTF1','CTF_M']])

Out[4]: KeyError: "['CTF1' 'CTF_M'] not in index"

不知何故,这不起作用。也许你知道出了什么可怕的问题?

感谢您的帮助。

编辑: In[1]: print(df) 看起来像:

Out[1]:          ELEMENT 20052065 20052066 20052082 20052087 20052089 20052090  \
       TIME[s]   TEMP[C]     CTF1     CTF1     CTF1     CTF1     CTF1     CTF1   
       0.000      24.000   -4.234   -6.728  -14.386   -4.356   -6.926  -10.205   
       60.000     36.137  -29.308  -24.795  -26.937  -30.134  -24.735  -23.474 
          ...        ...      ...      ...      ...      ...      ...      ...

*.txt 文件如下所示:

【问题讨论】:

    标签: python pandas dataframe multi-index


    【解决方案1】:

    你可以使用df.loc:

    import numpy as np
    import pandas as pd
    
    columns = pd.MultiIndex.from_product([['A','B','C'],['X','Y','Z']])
    df = pd.DataFrame(np.random.randint(10, size=(3,len(columns))), columns=columns)
    #    A        B        C      
    #    X  Y  Z  X  Y  Z  X  Y  Z
    # 0  2  7  5  1  6  0  5  0  0
    # 1  8  4  7  2  0  8  7  3  9
    # 2  0  6  8  8  1  1  8  0  2
    
    # In some cases `sort_index` may be needed to avoid UnsortedIndexError
    df = df.sort_index(axis=1)
    print(df.loc[:, (['A','B'],['X','Y'])])
    

    产量(类似):

       A     B   
       X  Y  X  Y
    0  2  7  1  6
    1  8  4  2  0
    2  0  6  8  1
    

    如果您只想选择 ('A','Y')('B','X') 列,请注意您可以将 MultiIndexed 列指定为元组:

    In [37]: df.loc[:, [('A','Y'),('B','X')]]
    Out[37]: 
       A  B
       Y  X
    0  7  1
    1  4  2
    2  6  8
    

    甚至只是df[[('A','Y'),('B','X')]](产生相同的结果)。

    一般来说,最好使用单个索引器,例如df.loc[...],而不是双索引(例如df[...][...])。它可以更快(因为它对__getitem__ 的调用更少,并且生成的临时子DataFrames 更少)和df.loc[...] = value 它是the correct way 对修改df 本身的DataFrame 的子切片进行分配。


    df[['A','B']][['X','Y']] 不起作用的原因是因为 df[['A','B']] 返回一个带有 MultiIndex 的 DataFrame:

    In [36]: df[['A','B']]
    Out[36]: 
       A        B      
       X  Y  Z  X  Y  Z
    0  2  7  5  1  6  0
    1  8  4  7  2  0  8
    2  0  6  8  8  1  1
    

    因此使用['X','Y'] 索引此DataFrame 失败,因为没有名为'X''Y' 的顶级列标签。


    有时,根据 DataFrame 的构造方式(或由于对 DataFrame 执行的操作),MultiIndex 需要先进行 lexsort 才能被切片。有一个boxed warning in the docs 提到了这个问题。要对列索引进行 lexsort 使用

    df = df.sort_index(axis=1)
    

    【讨论】:

    • 我再次得到以下输出:UnsortedIndexError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (2), lexsort depth (0)' :-/
    • 在这种情况下,使用df = df.sort_index(axis=1) 对列索引进行排序。
    • 感谢您的帮助!这行得通! :) 非常感谢您。 :)
    • unutbu,另一个问题:我想从 1. 级别属性中获取一个列表,例如:elements = df.iloc[0,1:-1].index.levels[0][0:-2] 并将它们放置为:print(df.loc[:, ([elements],['CTF1','CTF_M'])]) 但使用“对象”会导致 TypeError .如果我这样做,就可以工作:elements = df.iloc[0,1:-1].index.levels[0][0] for 1 Element。有没有办法获取 List 中的所有值?
    • 如果我正确理解了您的情况,您可以使用df.loc[:, (elements,['CTF1','CTF_M'])]——也就是说,只需删除elements 周围的括号即可。您也可以使用list(elements) 获取列表中的所有值。最后,我认为您可以使用elements = df.columns.levels[0][0:-2] 而不是df.iloc[0,1:-1].index.levels[0][0:-2],因为切片df 不会更改索引级别,只会更改标签。 (要明白我的意思,比较 df.iloc[0, 1:-1].indexdf.columns。)
    【解决方案2】:

    我认为需要slicers:

    print (df)
      20052065 20052066 20052065 20052066 20052065 20052066
          CTF1    CTF_M   CTF_M1   CTF_Mr        V        A
    0        1        2        4        5        6        7
    
    df = df.sort_index(axis=1)
    idx = pd.IndexSlice
    print (df.loc[:, idx[['20052065','20052066'], ['CTF1','CTF_M']]])
      20052065 20052066
          CTF1    CTF_M
    0        1        2
    

    【讨论】:

    • 我试过了,得到以下输出:UnsortedIndexError: 'MultiIndex Slicing requires the index to be fully lexsorted tuple len (2), lexsort depth (0)'
    • 检查修改后的解决方案 - 需要df = df.sort_index(axis=1)
    猜你喜欢
    • 2022-06-15
    • 2017-10-16
    • 2020-08-19
    • 1970-01-01
    • 2015-07-19
    • 2022-01-25
    • 1970-01-01
    • 2018-06-24
    相关资源
    最近更新 更多