Python の itertools.groupby() を使用するにはどうすればよいですか?
質問
Python の実際の使用方法についてのわかりやすい説明が見つかりませんでした。 itertools.groupby()
関数。私がやろうとしていることはこれです:
- リストを取得します - この場合、オブジェクト化されたオブジェクトの子です。
lxml
要素 - いくつかの基準に基づいてグループに分ける
- その後、これらの各グループを個別に繰り返します。
レビューしました 文書, 、 そして 例, しかし、単純な数字のリストを超えてそれらを適用しようとすると苦労しました。
それで、どうやって使うのですか itertools.groupby()
?他に使用すべきテクニックはありますか?適切な「前提条件」の読み物への指摘も歓迎します。
解決
重要な注意点: あなたがしなければならない データを並べ替える 初め。
私が理解できなかった部分は、構築例では
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
iterator 自体は反復子を返します。
以下は、より明確な変数名を使用した例です。
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()
関数は 2 つの引数を取ります。(1) グループ化するデータ、および (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 + "."
これにより、次の出力が得られます。
動物:熊とアヒル。
植物:カクタス。
車両:スピードボートとスクールバス。
他のヒント
コードを見せていただけますか?
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
このメソッドは実際にはリストを反復処理するだけで、キーが変更されるたびに新しいグループを作成します。
groupby の巧妙なトリックは、長さのエンコーディングを 1 行で実行することです。
[(c,len(list(cgen))) for c,cgen in groupby(some_string)]
最初の要素が文字、2 番目の要素が繰り返し回数である 2 つのタプルのリストが表示されます。
編集:これが分離するものであることに注意してください itertools.groupby
SQLから GROUP BY
セマンティクス:itertools はイテレーターを事前にソートしない (通常はソートできない) ため、同じ「キー」を持つグループはマージされません。
itertools.groupby
項目をグループ化するためのツールです。
から ドキュメント, 、それが何をするのかをさらに収集します。
# [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
# [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
groupby
オブジェクトは、グループがジェネレーターであるキーグループのペアを生成します。
特徴
- A.連続する項目をグループ化する
- B.ソートされた反復可能オブジェクトを指定して、項目のすべての出現をグループ化します。
- C.キー機能を使用して項目をグループ化する方法を指定する
比較
# Define a printer for comparing outputs
>>> def print_groupby(iterable, key=None):
... for k, g in it.groupby(iterable, key):
... print("key: '{}'--> group: {}".format(k, list(g)))
# Feature A: group consecutive occurrences
>>> print_groupby("BCAACACAADBBB")
key: 'B'--> group: ['B']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A']
key: 'C'--> group: ['C']
key: 'A'--> group: ['A', 'A']
key: 'D'--> group: ['D']
key: 'B'--> group: ['B', 'B', 'B']
# Feature B: group all occurrences
>>> print_groupby(sorted("BCAACACAADBBB"))
key: 'A'--> group: ['A', 'A', 'A', 'A', 'A']
key: 'B'--> group: ['B', 'B', 'B', 'B']
key: 'C'--> group: ['C', 'C', 'C']
key: 'D'--> group: ['D']
# Feature C: group by a key function
>>> key = lambda x: x.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), key)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']
用途
- アナグラム (ノートを参照してください)
- ビニング
- 奇数と偶数をグループ化する
- 値ごとにリストをグループ化する
- 重複した要素を削除する
- 配列内で繰り返される要素のインデックスを見つける
- 配列を n サイズのチャンクに分割する
- 2 つのリスト間で対応する要素を検索します
- 圧縮アルゴリズム (ノートを参照してください)/ランレングスエンコーディング
- 長さによる文字のグループ化、キー機能 (ノートを参照してください)
- 連続した値がしきい値を超える (ノートを参照してください)
- リスト内の数値の範囲を検索する または 連続アイテム (見る ドキュメント)
- 関連する最長シーケンスをすべて検索する
- 条件を満たす連続したシーケンスを取得します (関連投稿を参照)
注記:後者の例のいくつかは、Víctor Terrón の PyCon から派生しています。 (話す) (スペイン語), 「Itertoolsを使った夜明けのカンフー」。も参照してください。 groupby
ソースコード Cで書かれています。
応答
# OP: Yes, you can use `groupby`, e.g.
[do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]
もう一つの例:
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]
igroup はイテレータ (ドキュメントではサブイテレータと呼ばれています) であることに注意してください。
これはジェネレーターをチャンク化する場合に便利です。
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 セットの 0 が出力され、次に 1 セットが出力され、その後に再び 0 セットが出力されます。
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]
警告:
構文 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 機能にアクセスできます。
ソートなしの 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 つだけであると考えられます。
@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)]
ご覧のとおり、o が 2 つと e が 2 つありますが、それらは別々のグループになりました。そのとき、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 関数を覚えておいてください。 動作しないでしょう!
Python の itertools.groupby() を使用するにはどうすればよいですか?
groupby を使用すると、反復処理するものをグループ化できます。groupby に反復可能でオプションの 鍵 function/callable を使用して、反復可能から出てくる項目をチェックします。キー呼び出し可能の結果と別の反復可能内の実際の項目の 2 つのタプルを与える反復子を返します。ヘルプから:
groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).
コルーチンを使用してカウントでグループ化する groupby の例を次に示します。呼び出し可能なキーを使用します (この場合、 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])]
並べ替えとグループ化
from itertools import groupby
val = [{'name': 'satyajit', 'address': 'btm', 'pin': 560076},
{'name': 'Mukul', 'address': 'Silk board', 'pin': 560078},
{'name': 'Preetam', 'address': 'btm', 'pin': 560076}]
for pin, list_data in groupby(sorted(val, key=lambda k: k['pin']),lambda x: x['pin']):
... print pin
... for rec in list_data:
... print rec
...
o/p:
560076
{'name': 'satyajit', 'pin': 560076, 'address': 'btm'}
{'name': 'Preetam', 'pin': 560076, 'address': 'btm'}
560078
{'name': 'Mukul', 'pin': 560078, 'address': 'Silk board'}
私が見つけた 1 つの便利な例が役立つかもしれません。
from itertools import groupby
#user input
myinput = input()
#creating empty list to store output
myoutput = []
for k,g in groupby(myinput):
myoutput.append((len(list(g)),int(k)))
print(*myoutput)
入力例:14445221
出力例:(1,1) (3,4) (1,5) (2,2) (1,1)
独自の groupby 関数を作成できます。
def groupby(data):
kv = {}
for k,v in data:
if k not in kv:
kv[k]=[v]
else:
kv[k].append(v)
return kv
Run on ipython:
In [10]: data = [('a', 1), ('b',2),('a',2)]
In [11]: groupby(data)
Out[11]: {'a': [1, 2], 'b': [2]}