614

itertools.groupby()Pythonの関数を実際に使用する方法についての理解できる説明を見つけることができませんでした。私がやろうとしていることはこれです:

  • リストを取る-この場合、オブジェクト化されたlxml要素の子
  • いくつかの基準に基づいてグループに分割します
  • その後、これらの各グループを個別に繰り返します。

ドキュメントを確認しましたが、単純な数字のリストを超えてそれらを適用しようとすると問題が発生しました。

だから、私はどのように使用しitertools.groupby()ますか?私が使用すべき別のテクニックはありますか?良い「前提条件」の読み方へのポインタもいただければ幸いです。

4

14 に答える 14

783

重要な注意:最初にデータを並べ替える必要があります。


私が得られなかった部分は、例の構築にあります

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
   groups.append(list(g))    # Store group iterator as a list
   uniquekeys.append(k)

kは現在のグループ化キーであり、gそのグループ化キーによって定義されたグループを反復処理するために使用できる反復子です。つまり、groupby反復子自体が反復子を返します。

より明確な変数名を使用した例を次に示します。

from itertools import groupby

things = [("animal", "bear"), ("animal", "duck"), ("plant", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]

for key, group in groupby(things, lambda x: x[0]):
    for thing in group:
        print("A %s is a %s." % (thing[1], key))
    print("")
    

これにより、次の出力が得られます。

クマは動物です。
アヒルは動物です。

サボテンは植物です。

スピードボートは乗り物です。
スクールバスは乗り物です。

この例でthingsは、各タプルの最初のアイテムが 2 番目のアイテムが属するグループであるタプルのリストです。

このgroupby()関数は、(1) グループ化するデータと (2) グループ化する関数の 2 つの引数を取ります。

ここでは、各タプルの最初の項目をグループ化キーとして使用するようにlambda x: x[0]指示しています。groupby()

上記のforステートメントでgroupbyは、一意のキーごとに 1 つずつ、3 つの (キー、グループ イテレータ) ペアを返します。返された反復子を使用して、そのグループ内の個々のアイテムを反復処理できます。

リスト内包表記を使用して、同じデータを使用した少し異なる例を次に示します。

for key, group in groupby(things, lambda x: x[0]):
    listOfThings = " and ".join([thing[1] for thing in group])
    print(key + "s:  " + listOfThings + ".")

これにより、次の出力が得られます。

動物: クマとアヒル。
植物: サボテン。
乗り物:スピードボートとスクールバス。

于 2008-08-10T18:45:32.430 に答える
73

Pythonドキュメントの例は非常に単純です。

groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
    groups.append(list(g))      # Store group iterator as a list
    uniquekeys.append(k)

したがって、あなたの場合、データはノードのリストでkeyfuncあり、基準関数のロジックが行きgroupby()、データをグループ化する場所です。

電話をかける前に、基準でデータを並べ替える必要があります。そうしないと、機能しgroupbyません。groupbyメソッドは実際にはリストを反復処理するだけで、キーが変更されるたびに新しいグループが作成されます。

于 2008-08-03T18:40:09.053 に答える
50

groupbyのネイトトリックは、長さエンコーディングを1行で実行することです。

[(c,len(list(cgen))) for c,cgen in groupby(some_string)]

最初の要素がcharで、2番目の要素が繰り返し回数である2タプルのリストが表示されます。

編集:これがitertools.groupbySQLGROUP BYセマンティクスとの違いであることに注意してください。itertoolsはイテレータを事前にソートしない(そして一般的にはソートできない)ため、同じ「キー」を持つグループはマージされません。

于 2008-08-31T23:27:16.920 に答える
33

もう一つの例:

for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
    print key, list(igroup)

結果は

0 [0, 1, 2, 3, 4]
1 [5, 6, 7, 8, 9]
2 [10, 11]

igroupiteratorであることに注意してください(ドキュメントではサブ反復子と呼ばれています)。

これはジェネレーターをチャンクするのに便利です:

def chunker(items, chunk_size):
    '''Group items in chunks of chunk_size'''
    for _key, group in itertools.groupby(enumerate(items), lambda x: x[0] // chunk_size):
        yield (g[1] for g in group)

with open('file.txt') as fobj:
    for chunk in chunker(fobj):
        process(chunk)

別の例groupby- キーがソートされていない場合。次の例では、 の項目xxが の値でグループ化されていますyy。この場合、1 つのゼロのセットが最初に出力され、次に 1 のセットが続き、さらにゼロのセットが続きます。

xx = range(10)
yy = [0, 0, 0, 1, 1, 1, 0, 0, 0, 0]
for group in itertools.groupby(iter(xx), lambda x: yy[x]):
    print group[0], list(group[1])

プロデュース:

0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]
于 2013-01-21T16:54:08.263 に答える
24

警告:

構文 list(groupby(...)) は、意図したとおりには機能しません。内部イテレータオブジェクトを破壊するようですので、

for x in list(groupby(range(10))):
    print(list(x[1]))

生成されます:

[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]

list(groupby(...)) の代わりに、[(k, list(g)) for k,g in groupby(...)] を試すか、その構文を頻繁に使用する場合は、

def groupbylist(*args, **kwargs):
    return [(k, list(g)) for k, g in groupby(*args, **kwargs)]

これらの厄介な (小さなデータの場合) イテレータをまとめて回避しながら、groupby 機能にアクセスできます。

于 2013-11-16T00:39:31.500 に答える
12

ソートなしの groupby が機能しない別の例を挙げたいと思います。James Sulak による例から適応

from itertools import groupby

things = [("vehicle", "bear"), ("animal", "duck"), ("animal", "cactus"), ("vehicle", "speed boat"), ("vehicle", "school bus")]

for key, group in groupby(things, lambda x: x[0]):
    for thing in group:
        print "A %s is a %s." % (thing[1], key)
    print " "

出力は

A bear is a vehicle.

A duck is a animal.
A cactus is a animal.

A speed boat is a vehicle.
A school bus is a vehicle.

車両を持った2つのグループがありますが、1つのグループしか期待できませんでした

于 2013-05-07T20:09:46.677 に答える
9

@CaptSolo、あなたの例を試しましたが、うまくいきませんでした。

from itertools import groupby 
[(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]

出力:

[('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]

ご覧のとおり、2 つの o と 2 つの e がありますが、それらは別のグループに分類されます。そのとき、groupby 関数に渡されたリストを並べ替える必要があることに気付きました。したがって、正しい使用法は次のようになります。

name = list('Pedro Manoel')
name.sort()
[(c,len(list(cs))) for c,cs in groupby(name)]

出力:

[(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]

リストがソートされていない場合、groupby 関数は機能しません

于 2009-10-15T15:41:51.620 に答える
7

Python の itertools.groupby() を使用するにはどうすればよいですか?

groupby を使用して、繰り返し処理するものをグループ化できます。groupby にイテラブルと、イテラブルから出てくるアイテムをチェックするためのオプションのキー関数/呼び出し可能オブジェクトを指定すると、キー呼び出し可能オブジェクトの結果と実際のアイテムの 2 つのタプルを返すイテレータが返されます。別のイテラブル。ヘルプから:

groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).

コルーチンを使用してカウントでグループ化する groupby の例を次に示します。これはキー callable (この場合はcoroutine.send) を使用して、反復回数とグループ化された要素のサブ反復子のカウントを吐き出すだけです。

import itertools


def grouper(iterable, n):
    def coroutine(n):
        yield # queue up coroutine
        for i in itertools.count():
            for j in range(n):
                yield i
    groups = coroutine(n)
    next(groups) # queue up coroutine

    for c, objs in itertools.groupby(iterable, groups.send):
        yield c, list(objs)
    # or instead of materializing a list of objs, just:
    # return itertools.groupby(iterable, groups.send)

list(grouper(range(10), 3))

版画

[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
于 2015-07-27T18:06:30.897 に答える