itertools.groupby ()를 어떻게 사용합니까?


506

실제로 파이썬 itertools.groupby()함수를 사용하는 방법에 대한 이해하기 쉬운 설명을 찾지 못했습니다 . 내가하려는 것은 이것입니다 :

  • 목록을 작성하십시오-이 경우 객관적인 lxml요소 의 자식
  • 몇 가지 기준에 따라 그룹으로 나눕니다.
  • 그런 다음 나중에 각 그룹을 개별적으로 반복하십시오.

설명서예제를 검토 했지만 간단한 숫자 목록을 넘어서 적용하는 데 문제가있었습니다.

그래서 어떻게 사용 itertools.groupby()합니까? 사용해야하는 다른 기술이 있습니까? 좋은 "전제 조건"독서에 대한 포인터도 감사하겠습니다.


답변:


655

중요 참고 : 먼저 데이터정렬해야합니다 .


내가 얻지 못한 부분은 예제 구성에서

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각 튜플의 첫 번째 항목이 두 번째 항목이 속한 그룹 인 튜플 목록입니다.

groupby()함수는 (1) 그룹화 할 데이터와 (2) 그룹화 할 함수의 두 가지 인수를 사용합니다.

여기 에서 각 튜플의 첫 번째 항목을 그룹화 키로 사용하도록 lambda x: x[0]지시 groupby()합니다.

위의 for문장에서, groupby각각의 고유 한 키에 대해 세 개의 (키, 그룹 반복자) 쌍을 한 번 반환합니다. 리턴 된 반복자를 사용하여 해당 그룹의 각 개별 항목을 반복 할 수 있습니다.

다음은 목록 이해를 사용하여 동일한 데이터를 가진 약간 다른 예입니다.

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

이것은 당신에게 출력을 줄 것입니다 :

동물 : 곰과 오리.
식물 : 선인장.
차량 : 스피드 보트 및 스쿨 버스.


1
미리 그룹을 지정하고 정렬 할 필요가없는 방법이 있습니까?
존 살바 티어

2
itertools는 보통 저를 위해 클릭하지만, 이것에 대한 '차단'도했습니다. 문서보다 훨씬 명확하게 귀하의 예를 감사했습니다. itertools는 클릭하거나하지 않는 경향이 있으며 비슷한 문제가 발생하면 파악하기가 훨씬 쉽습니다. 아직 야생에서 이것을 필요로하지 않았습니다.
Profane

3
@Julian python 문서는 대부분의 경우 훌륭해 보이지만 iterators, generators 및 cherrypy 관련 문서는 대부분 나를 미스터리합니다. Django의 문서는 이중 당황 스럽습니다.
Marc Maxmeister

6
정렬 +1-데이터를 그룹화하기 전까지는 무슨 의미인지 이해하지 못했습니다.
Cody

4
@DavidCrook은 파티에 매우 늦었지만 누군가를 도울 수 있습니다. 배열이 정렬되지 않았기 때문일 수 있으며 다음과 groupby(sorted(my_collection, key=lambda x: x[0]), lambda x: x[0]))같이 가정하고 my_collection = [("animal", "bear"), ("plant", "cactus"), ("animal", "duck")]그룹화하려고합니다.animal or plant
Robin Nemeth

71

파이썬 문서의 예는 매우 간단합니다.

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메소드는 실제로 목록을 반복하며 키가 변경 될 때마다 새 그룹을 만듭니다.


45
"당신 keyfunc은이 문서가 매우 간단하기 때문에 그것이 무엇인지 정확히 알고 있습니다." 놀랄 만한!
Jarad

5
나는 대부분의 사람들이 어떤 "데이터"와 "keyfunc"을 사용할지 말하지 않기 때문에이 "직선적"이지만 쓸모없는 예에 대해 이미 알고 있다고 생각합니다 !! 그러나 나는 당신도 모른다고 생각합니다. 그렇지 않으면 사람들은 그것을 복사하여 붙여 넣는 것이 아니라 그것을 명확히함으로써 사람들을 도울 것입니다. 아니면 당신은?
사도

69

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. iterable에 따라 항목의 모든 항목을 그룹화
  • C. 항목을 그룹화하는 방법 지정 키 기능으로 *

비교

# Define a printer for comparing outputs
>>> def print_groupby(iterable, keyfunc=None):
...    for k, g in it.groupby(iterable, keyfunc):
...        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
>>> # keyfunc = lambda s: s.islower()                      # equivalent
>>> def keyfunc(s):
...     """Return a True if a string is lowercase, else False."""   
...     return s.islower()
>>> print_groupby(sorted("bCAaCacAADBbB"), keyfunc)
key: 'False'--> group: ['A', 'A', 'A', 'B', 'B', 'C', 'C', 'D']
key: 'True'--> group: ['a', 'a', 'b', 'b', 'c']

용도

참고 : 후자의 예제 중 일부는 Víctor Terrón의 PyCon (토크) (스페인어) , "Itertools와 함께 새벽에 쿵푸" 에서 파생되었습니다 . 소스 코드 참조groupbyC로 작성된 .

* 모든 항목을 통과하고 비교하여 결과에 영향을주는 기능입니다. 주요 기능이있는 다른 객체에는 sorted(), max()및가 min()있습니다.


응답

# OP: Yes, you can use `groupby`, e.g. 
[do_something(list(g)) for _, g in groupby(lxml_elements, criteria_func)]

1
기술적으로, 문서는 아마 말해야한다 [''.join(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D.
Mateen Ulhaq

1
예. 대부분의 itertools docstring은 이러한 방식으로 "약식"됩니다. itertools의 모든 반복자이기 때문에, 그들이 내장으로 캐스팅해야 ( list(), tuple()) 또는 내용을 표시 할 수있는 루프 / 이해에 소비했다. 이들은 공간 절약을 위해 저자가 배제한 중복성입니다.
pylang

39

groupby를 사용하는 깔끔한 요령은 한 줄에 길이 인코딩을 실행하는 것입니다.

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

첫 번째 요소는 문자이고 두 번째 요소는 반복 횟수 인 2 개의 튜플 목록을 제공합니다.

편집 : 이것은 itertools.groupbySQL GROUP BY의미 와 구별 됩니다 . itertools는 미리 반복자를 정렬하지 않으며 일반적으로 동일한 "키"를 가진 그룹은 병합되지 않습니다.


27

또 다른 예:

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)

그룹 별의 또 다른 예-키가 정렬되지 않은 경우. 다음 예에서 xx의 항목은 yy의 값으로 그룹화됩니다. 이 경우, 한 세트의 0이 먼저 출력되고, 그 뒤에 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]

흥미롭지 만 itertools.islice가 iterable을 청크하는 데 더 좋지 않습니까? 생성기처럼 반복되는 객체를 반환하지만 C 코드를 사용합니다.
trojjer

그룹의 크기가 일정한 경우 @trojjer islice가 더 좋습니다.
woodm1979

[0, 1, 2], [1, 2, 3], [2, 3, 4] ...
GilbertS의

21

경고:

구문 목록 (groupby (...))이 원하는 방식으로 작동하지 않습니다. 내부 반복자 객체를 파괴하는 것 같습니다.

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

생산할 것이다 :

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

대신 list (groupby (...)) 대신 groupby (...)]에서 k, g에 대해 [(k, list (g))를 시도하거나 해당 구문을 자주 사용하는 경우,

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

작은 데이터의 경우 반복자를 피하면서 그룹 별 기능에 액세스 할 수 있습니다.


3
많은 답변은 예상 결과를 얻기 위해 groupby 전에 정렬해야하는 걸림돌을 말합니다. 방금 전에 본 적이없는 이상한 행동을 설명하는이 대답을 만났습니다. @singular가 말한 것처럼 지금은 list (groupby (range (10))을 나열하려고 시도했기 때문에 이전에는 보지 못했습니다. list () 생성자를 "자동으로"허용
Red Pea

9

정렬되지 않은 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.

하나의 그룹 만 기대할 수있는 반면, 차량에는 두 그룹이 있습니다


5
그룹화하는 기능을 키로 사용하여 데이터를 먼저 정렬해야합니다. 이것은 위의 두 게시물에 언급되어 있지만 강조 표시되어 있지 않습니다.
mbatchkarov 2016 년

나는 이것이 dict (groupby (iterator, key))만큼 간단하다는 것을 깨달을 때까지 키로 하위 반복자를 보존하기 위해 독해를하고있었습니다. 단.
trojjer December

두 번째 생각과 실험 후, 그룹별로 감싸 인 dict call은 그룹 하위 반복자를 소진시킵니다. 제길.
trojjer

이 답변의 요점은 무엇입니까? 어떻게이 구축되어 원래의 대답은 ?
codeforester

7

@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와 두 개의 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 기능 이 작동하지 않습니다 !


7
실제로 작동합니다. 이 동작이 깨 졌다고 생각할 수도 있지만 경우에 따라 유용합니다. 예를 들어이 질문에 대한 답변을 참조하십시오 stackoverflow.com/questions/1553275/...
데니스 Otkidach

6

정렬 및 그룹화

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'}

5

파이썬의 itertools.groupby ()를 어떻게 사용합니까?

groupby를 사용하여 반복 할 항목을 그룹화 할 수 있습니다. iterable과 iterable에서 나오는 항목을 확인할 수 있는 선택적 함수 / 호출 가능을 그룹별로 제공하고 키 호출 가능한 결과와 실제 항목의 두 튜플을 제공하는 반복자를 반환합니다. 또 다른 iterable. 도움에서 :

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

다음은 코 루틴을 사용하여 카운트로 그룹화하는 예입니다. 키 호출 가능 (이 경우 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])]

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)


1

이 기본 구현은이 기능을 이해하는 데 도움이되었습니다. 그것이 다른 사람들에게도 도움이되기를 바랍니다.

arr = [(1, "A"), (1, "B"), (1, "C"), (2, "D"), (2, "E"), (3, "F")]

for k,g in groupby(arr, lambda x: x[0]):
    print("--", k, "--")
    for tup in g:
        print(tup[1])  # tup[0] == k
-- 1 --
A
B
C
-- 2 --
D
E
-- 3 --
F

0

자체 그룹 별 기능을 작성할 수 있습니다.

           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]}

1
바퀴가 좋은 생각이 아니다 개혁도 문제는 itertools GROUPBY, 자신의 기록하지 설명하는 것입니다
user2678074

1
당신은 맞습니다. 학습 관점에서 직접 작성하려는 경우에 해당합니다.
Sky

2
또한 더 나은조차 짧다 있도록 defaultdict (목록)를 사용
미키 Perlstein

@MickeyPerlstein 이상.
funnydman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.