web-dev-qa-db-ja.com

pandas MultiIndexから列を選択する

次のようなMultiIndex列を持つDataFrameがあります。

# sample data
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'],
                                ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame(np.random.randn(4, 6), columns=col)
data

sample data

特定の列のみを選択する適切で簡単な方法は何ですか(例:['a', 'c']、範囲ではない)第2レベルから?

現在、私はそれを次のようにしています:

import itertools
tuples = [i for i in itertools.product(['one', 'two'], ['a', 'c'])]
new_index = pd.MultiIndex.from_tuples(tuples)
print(new_index)
data.reindex_axis(new_index, axis=1)

expected result

ただし、itertoolsをバストアウトし、別のMultiIndexを手動で作成してからインデックスを再作成する必要があるため、これは良い解決策のようには思えません(列のリストがそうでないため、実際のコードはさらに面倒です)フェッチが簡単です)。これを行うにはいくつかのixまたはxsの方法が必要だと確信していますが、私が試みたすべての結果はエラーになりました。

23
metakermit

それは素晴らしいことではありませんが、おそらく:

>>> data
        one                           two                    
          a         b         c         a         b         c
0 -0.927134 -1.204302  0.711426  0.854065 -0.608661  1.140052
1 -0.690745  0.517359 -0.631856  0.178464 -0.312543 -0.418541
2  1.086432  0.194193  0.808235 -0.418109  1.055057  1.886883
3 -0.373822 -0.012812  1.329105  1.774723 -2.229428 -0.617690
>>> data.loc[:,data.columns.get_level_values(1).isin({"a", "c"})]
        one                 two          
          a         c         a         c
0 -0.927134  0.711426  0.854065  1.140052
1 -0.690745 -0.631856  0.178464 -0.418541
2  1.086432  0.808235 -0.418109  1.886883
3 -0.373822  1.329105  1.774723 -0.617690

うまくいくでしょうか?

9
DSM

locまたはixを使用できます。locの例を示します。

data.loc[:, [('one', 'a'), ('one', 'c'), ('two', 'a'), ('two', 'c')]]

MultiIndexed DataFrameがあり、一部の列のみをフィルターで除外する場合は、それらの列に一致するタプルのリストを渡す必要があります。したがって、itertoolsのアプローチはほとんど問題ありませんでしたが、新しいMultiIndexを作成する必要はありません。

data.loc[:, list(itertools.product(['one', 'two'], ['a', 'c']))]
16
Viktor Kerkez

私ははるかに良い方法があると思います(今)、これが私がこの質問(グーグルのトップの結果でした)を陰から引き出すのを邪魔する理由です:

data.select(lambda x: x[1] in ['a', 'b'], axis=1)

期待どおりの出力をすばやくクリーンなワンライナーで提供します。

        one                 two          
          a         b         a         b
0 -0.341326  0.374504  0.534559  0.429019
1  0.272518  0.116542 -0.085850 -0.330562
2  1.982431 -0.420668 -0.444052  1.049747
3  0.162984 -0.898307  1.762208 -0.101360

それはほとんど自己説明的な、[1]はレベルを指します。

16
FooBar

列インデクサーの第2レベルで'a'および'c'という名前のすべての列を選択するには、スライサーを使用できます。

>>> data.loc[:, (slice(None), ('a', 'c'))]

        one                 two          
          a         c         a         c
0 -0.983172 -2.495022 -0.967064  0.124740
1  0.282661 -0.729463 -0.864767  1.716009
2  0.942445  1.276769 -0.595756 -0.973924
3  2.182908 -0.267660  0.281916 -0.587835

ここ スライサーの詳細を読むことができます。

8
Marc P.

ixselectは非推奨です!

pd.IndexSliceを使用すると、locixおよびselectよりも望ましいオプションにすることができます。


DataFrame.loc with pd.IndexSlice

# Setup
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'],
                                ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame('x', index=range(4), columns=col)
data

  one       two      
    a  b  c   a  b  c
0   x  x  x   x  x  x
1   x  x  x   x  x  x
2   x  x  x   x  x  x
3   x  x  x   x  x  x
data.loc[:, pd.IndexSlice[:, ['a', 'c']]]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

または、axisパラメータをlocに指定して、インデックスを付ける軸を明示的に指定できます。

data.loc(axis=1)[pd.IndexSlice[:, ['a', 'c']]]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

MultiIndex.get_level_values

locでフィルタリングするためにdata.columns.get_level_valuesを呼び出すことも別のオプションです。

data.loc[:, data.columns.get_level_values(1).isin(['a', 'c'])]

  one    two   
    a  c   a  c
0   x  x   x  x
1   x  x   x  x
2   x  x   x  x
3   x  x   x  x

これにより、当然のことながら、単一レベルの条件式のフィルタリングが可能になります。次に、辞書式フィルタリングを使用したランダムな例を示します。

data.loc[:, data.columns.get_level_values(1) > 'b']

  one two
    c   c
0   x   x
1   x   x
2   x   x
3   x   x

MultiIndexesのスライスとフィルタリングの詳細については、 (Select rows in pandas MultiIndex DataFrame )を参照してください。

8
cs95

最も簡単な方法は、.locを使用することです。

>>> data.loc[:, (['one', 'two'], ['a', 'b'])]


   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

[]()は、MultiIndexオブジェクトを処理するときに特別な意味を持つことに注意してください。

(...)タプルは1つのmulti-levelキーとして解釈されます

(...)リストは複数のキーを指定するために使用されます[同じレベル]

(...)リストのタプルは、レベル内のいくつかの値を参照します

(['one', 'two'], ['a', 'b'])を記述するとき、タプル内の最初のリストは、MultiIndexの第1レベルから必要なすべての値を指定します。タプル内の2番目のリストは、MultiIndexの第2レベルから取得するすべての値を指定します。

編集1:別の可能性は、slice(None)を使用して、最初のレベルから何でも欲しいことを指定することです(:によるスライスと同様に機能します)リスト)。次に、必要な第2レベルの列を指定します。

>>> data.loc[:, (slice(None), ["a", "b"])]

   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

構文slice(None)が魅力的である場合、もう1つの可能性は、pd.IndexSliceを使用することです。これにより、より複雑なインデックスでフレームをスライスできます。

>>> data.loc[:, pd.IndexSlice[:, ["a", "b"]]]

   one       two     
     a    b    a    b
0  0.4 -0.6 -0.7  0.9
1  0.1  0.4  0.5 -0.3
2  0.7 -1.6  0.7 -0.8
3 -0.9  2.6  1.9  0.6

pd.IndexSliceを使用する場合、通常どおり:を使用してフレームをスライスできます。

ソース: MultiIndex/Advanced IndexingHow to use slice(None)

6

Marc P。 のリフ スライスを使用した回答

import pandas as pd
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'], ['a', 'b', 'c', 'a', 'b', 'c']])
data = pd.DataFrame(np.random.randn(4, 6), columns=col)

data.loc[:, pd.IndexSlice[:, ['a', 'c']]]

        one                 two          
          a         c         a         c
0 -1.731008  0.718260 -1.088025 -1.489936
1 -0.681189  1.055909  1.825839  0.149438
2 -1.674623  0.769062  1.857317  0.756074
3  0.408313  1.291998  0.833145 -0.471879

pandas 0.21程度)以降、 。selectは非推奨になり、.locに置き換えられます

2
Nick P