Python:インデックスセットに基づいてリストからサブセットを選択


98

すべて同じ数のエントリを持つリストがいくつかあります(それぞれがオブジェクトプロパティを指定しています)。

property_a = [545., 656., 5.4, 33.]
property_b = [ 1.2,  1.3, 2.3, 0.3]
...

同じ長さのフラグでリストする

good_objects = [True, False, False, True]

(同等のインデックスリストで簡単に置き換えることができます:

good_indices = [0, 3]

新しいリストを生成する最も簡単な方法は何ですかproperty_aselproperty_bsel、...のみ値がいずれかによって示されている含まれていたTrueエントリまたはインデックス?

property_asel = [545., 33.]
property_bsel = [ 1.2, 0.3]

回答:


126

あなたはリスト内包表記を使うことができます:

property_asel = [val for is_good, val in zip(good_objects, property_a) if is_good]

または

property_asel = [property_a[i] for i in good_indices]

後者good_indicesproperty_agood_indicesオンザフライで生成されるのではなく事前計算されると仮定すると、の長さよりも短いため、より高速です。


編集:最初のオプションはitertools.compress、Python 2.7 / 3.1以降で利用可能なオプションと同等です。@Gary Kerrの回答を参照してください。

property_asel = list(itertools.compress(property_a, good_objects))

1
@fuen:はい。Python 2では多くの原因になります(代わりにitertools.izipを使用してください。Python3ではそれほどではありません。これはzip、Python 2では新しいリストが作成されますが、Python 3では単に(遅延)ジェネレーターが返されるためです。
kennytm

OK、それで私はあなたの2番目の提案に固執するべきです、なぜならこれは私のコードの中心部分を構成するからです。
fuenfundachtzig 2010

4
@ 85:なぜパフォーマンスについて心配しているのですか?あなたがしなければならないことを書いて、遅い場合は、ボトルネックを見つけるためにテストしてください。
ゲイリーカー

1
@PreludeAndFugue:2つの同等のオプションがある場合、どちらが速いかを知って、すぐにそれを使用するのは良いことです。
fuenfundachtzig 2010

1
最初の例のfrom itertools import izip代わりにzip、それを使用して使用できます。これは、Python 3と同じイテレータ、作成
クリス・B.

28

2つのオプションが表示されます。

  1. numpyを使用する:

    property_a = numpy.array([545., 656., 5.4, 33.])
    property_b = numpy.array([ 1.2,  1.3, 2.3, 0.3])
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = property_a[good_objects]
    property_bsel = property_b[good_indices]
  2. リスト内包表記を使用して圧縮する:

    property_a = [545., 656., 5.4, 33.]
    property_b = [ 1.2,  1.3, 2.3, 0.3]
    good_objects = [True, False, False, True]
    good_indices = [0, 3]
    property_asel = [x for x, y in zip(property_a, good_objects) if y]
    property_bsel = [property_b[i] for i in good_indices]

2
OPはリストに数値を格納したいので、Numpyを使用することをお勧めします。2次元配列の方が適しています。
フィリップ

これは、Rのユーザーにとって非常に馴染みのある構文になるため、良い提案です。この種の選択は、特にネストされている場合や多次元の場合に非常に強力です。
Thomas Browne

[property_b[i] for i in good_indices]なしで使用するのに適していますnumpy
Ilya Rusin

16

組み込み関数zipを使用する

property_asel = [a for (a, truth) in zip(property_a, good_objects) if truth]

編集

2.7の新機能を見てみましょう。上記のコードに類似した関数がitertoolsモジュールに追加されました。

http://docs.python.org/library/itertools.html#itertools.compress

itertools.compress('ABCDEF', [1,0,1,0,1,1]) =>
  A, C, E, F

1
itertools.compressここの使い方に圧倒されます。リストの内包表記ははるかに読みやすくなり、圧縮機能の実行内容を詳しく調べる必要がなくなります。
PaulMcG 2010

5
うーん、compressを使用したコードははるかに読みやすくなっています:)たぶんバイアスがかかっているかもしれません。
fuenfundachtzig 2010

8

アイテムのリストとtrue / requiredインデックスのリストしかない場合は、これが最も速くなります。

property_asel = [ property_a[index] for index in good_indices ]

つまり、プロパティの選択は、真/必要なインデックスと同じ数のラウンドのみを実行します。単一のタグ(true / false)リストのルールに従う多くのプロパティリストがある場合は、同じリスト理解原則を使用してインデックスリストを作成できます。

good_indices = [ index for index, item in enumerate(good_objects) if item ]

これは、good_objects内の各項目を反復処理し(enumerateでそのインデックスを覚えている間)、項目がtrueであるインデックスのみを返します。


リストの理解が得られない人のために、コードが太字で強調表示されている英語の散文バージョンは次のとおりです。

リストのインデックスの各グループインデックス、項目が存在する中で列挙良いオブジェクトもし(どこ)の項目がTrueであります


0

MatlabとScilab言語は、あなたが尋ねている質問に対してPythonよりシンプルでエレガントな構文を提供するので、PythonでNumpyパッケージを使用してMatlab / Scilabを模倣することが最善の方法だと思います。これを行うことにより、問題の解決策は非常に簡潔でエレガントになります。

from numpy import *
property_a = array([545., 656., 5.4, 33.])
property_b = array([ 1.2,  1.3, 2.3, 0.3])
good_objects = [True, False, False, True]
good_indices = [0, 3]
property_asel = property_a[good_objects]
property_bsel = property_b[good_indices]

NumpyはMatlab / Scilabを模倣しようとしますが、それは代償を伴います。スクリプトをオーバーロードするような「配列」というキーワードですべてのリストを宣言する必要があります(この問題はMatlab / Scilabには存在しません)。このソリューションは数値の配列に制限されていることに注意してください。これは、例の場合です。


3
質問のどこにも彼はNumPyについて言及していません-NumPyとMatlabについてあなたの意見を述べる必要はありません。Pythonリストは、どちらも大まかにベクトルに対応していても、NumPy配列と同じではありません。(PythonリストはMatlabセル配列に似ています-各要素は異なるデータ型を持つことができます。NumPy配列は特定の最適化を有効にするためにより制限されています)。Pythonの組み込みfilterライブラリまたは外部ライブラリを介して、例と同様の構文を取得できますpandas。言語を交換するつもりなら、Rを試すこともできますが、それは質問が尋ねていることではありません
Livius
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.