Jak używać itertools.groupby Pythona ()?

głosy
364

Nie byłem w stanie znaleźć zrozumiałego wyjaśnienia jak faktycznie używać Pythona itertools.groupby()funkcji. Co staram się zrobić to w ten sposób:

  • Zrób listę - w tym przypadku dzieci z zobiektywizowany lxmlelementu
  • Podzielić na grupy w oparciu o pewne kryteria
  • Później iteracyjne nad każdą z tych grup oddzielnie.

Sprawdziliśmy dokumentację i przykłady , ale miałem problemy próbuje stosować je poza prostą listę numerów.

Tak więc, w jaki sposób mogę korzystać z itertools.groupby()? Czy istnieje inna technika I powinny być using? Wskaźniki do dobrego „warunków wstępnych” czytania będzie również mile widziane.

Utwórz 03/08/2008 o 19:27
źródło użytkownik
W innych językach...                            


13 odpowiedzi

głosy
523

Jak powiedział Sebastjan, najpierw trzeba uporządkować dane. To jest ważne.

Część I nie dostać to, że w przykładowej konstrukcji

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

kjest obecny klucz grupowanie i gjest iterator, którego można użyć do iteracyjnego grupy zdefiniowanej przez tego klucza grupowania. W Innymi słowy, groupbysama iterator zwraca iteratory.

Oto przykład tego, używając wyraźniejsze nazwy zmiennych:

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 " "

To daje wyjście:

Niedźwiedź jest zwierzęciem.
Kaczka jest zwierzęciem.

Kaktus jest rośliną.

Prędkość łodzi jest pojazd.
Szkolny autobus jest pojazdem.

W tym przykładzie thingsjest listą krotek, gdzie pierwszy element każdej krotki jest grupa druga pozycja należy.

groupby()Funkcja ma dwa parametry: (1) danych w grupie i (2) funkcji do grupy, do której za pomocą.

Tutaj lambda x: x[0]mówi groupby()się użyć pierwszy element każdej krotki jako klucz grupowania.

W powyższym foroświadczeniu groupbyzwraca trzy (klucz, grupa par iteracyjnej) - raz dla każdego unikalnego klucza. Można użyć zwrócony iterator iteracyjne nad każdą poszczególną pozycję w tej grupie.

Oto nieco inny przykład z tych samych danych na podstawie listy ze zrozumieniem:

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

To daje wyjście:

zwierzęta: niedźwiedź i kaczki.
Rośliny: kaktus.
pojazdów: prędkość łodzi i szkolny autobus.

Odpowiedział 10/08/2008 o 19:45
źródło użytkownik

głosy
65

Można pokazać nam swój kod?

Przykładem na docs Python jest całkiem prosta:

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

Więc w przypadku danych jest lista węzłów, keyfunc gdzie logika swojej funkcji, a następnie idzie kryteria groupby()grupy danych.

Musisz uważać, aby sortować dane według kryteriów zanim zadzwonisz groupbyalbo nie będzie działać. groupbyMetoda właściwie tylko iteracji listy i gdy główne zmiany to tworzy nową grupę.

Odpowiedział 03/08/2008 o 19:40
źródło użytkownik

głosy
32

Neato sztuczka z GroupBy jest uruchomienie kodowanie długości w jednym wierszu:

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

daje listę 2-krotek, gdzie pierwszym elementem jest char i 2nd jest liczba powtórzeń.

Edycja: Należy pamiętać, że to, co oddziela itertools.groupbyod SQL GROUP BYsemantyki: itertools nie (a może w ogóle nie) uporządkować iterator z góry, więc grup z „kluczem” same nie są połączone.

Odpowiedział 01/09/2008 o 00:27
źródło użytkownik

głosy
21

Inny przykład:

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

prowadzi do

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

Zauważ, że IGROUP jest iterator (sub-iterator jak nazywa go dokumentacja).

Jest to przydatne do wyrwy generator:

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)

Innym przykładem GroupBy - kiedy klawisze nie są sortowane. W poniższym przykładzie przedmiotów w xx są pogrupowane według wartości w yy. W tym przypadku jeden zbiór zer jest odtwarzany najpierw, a następnie komplet jedynek, a następnie ponownie przez zbiór zer.

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

produkuje:

0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]
Odpowiedział 21/01/2013 o 17:54
źródło użytkownik

głosy
17

OSTRZEŻENIE:

Lista składnia (GroupBy (...)) nie będzie działać w sposób, który nie zamierza. Wygląda na to, aby zniszczyć wewnętrznych obiektów iteracyjnej, więc przy użyciu

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

będzie produkować:

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

Zamiast listy (GroupBy (...)), spróbuj [(k, listy (G)) dla k, g w GroupBy (...)], lub jeśli używasz tej składni często,

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

i uzyskać dostęp do funkcjonalności GroupBy unikając te brzydkie (dla małych danych) iteratory razem.

Odpowiedział 16/11/2013 o 01:39
źródło użytkownik

głosy
11

itertools.groupby Jest to narzędzie do grupowania przedmiotów.

Od docs , możemy zbierać dalej, co może zrobić:

# [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 Przedmioty wytworzeniem pary klucza grupę, w której grupa jest generator.

cechy

  • A. Grupa kolejne elementy razem (podobny do unique_justseen przepisie)
  • B. Grupa wszystkie wystąpienia elementu, biorąc pod uwagę sortowych iterable
  • C. Określanie sposobu grupa przedmiotów z funkcją przycisku

porównania

# 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
>>> 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']

zastosowania

Kilka ostatnich przykładów wynika z PyCon Dyskusja Víctor TERRON za (angielski) (Hiszpania) , Kung Fu at Dawn z Itertools . Dla wszystkich zainteresowanych, oto kod źródłowy dlagroupby napisany w C.

Odpowiedział 25/08/2017 o 02:26
źródło użytkownik

głosy
10

Chciałbym dać inny przykład, gdzie GroupBy bez sortowania nie działa. Zaadaptowany z przykładu Jamesa 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 " "

wyjście jest

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.

istnieją dwie grupy o terenowy, podczas gdy można było oczekiwać tylko jedną grupę

Odpowiedział 07/05/2013 o 21:09
źródło użytkownik

głosy
7

@CaptSolo starałem swój przykład, ale to nie działa.

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

Wydajność:

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

Jak widać, istnieją dwa i dwa o e, ale dostali w oddzielnych grupach. To wtedy zdałem sobie sprawę, trzeba posortować przekazany do funkcji GroupBy. Tak, prawidłowe wykorzystanie byłoby:

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

Wydajność:

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

Wystarczy pamiętać, jeśli lista nie jest posortowana, funkcja GroupBy nie będzie działać !

Odpowiedział 15/10/2009 o 16:41
źródło użytkownik

głosy
5

Jak używać itertools.groupby Pythona ()?

Można użyć GroupBy rzeczy grupowych do iteracyjnego. Dajesz GroupBy iterable, a opcjonalny klucz funkcja / wpłacone przez które by sprawdzić elementy jak wyjdą z iterable i zwraca iterator, który daje dwa-krotka wyniku kluczem wymagalne i rzeczywistych elementów w inny iterable. Z pomocą:

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

Oto przykład z użyciem współprogram GroupBy do grupy przez hrabiego, używa kluczowym wymagalne (w tym przypadku coroutine.send), aby tylko wypluć liczbę iteracji dla wielu jednak i pogrupowany sub-iterator elementów:

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))

druki

[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
Odpowiedział 27/07/2015 o 18:06
źródło użytkownik

głosy
3

Sortowanie i GroupBy

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'}
Odpowiedział 01/08/2017 o 07:14
źródło użytkownik

głosy
2

Jedną z użytecznych przykładów, które natknąłem mogą być pomocne:

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)

Wejście próbki: 14445221

Próbka wyjściowa (1,1) (3,4) (1,5) (2,2) (1,1)

Odpowiedział 18/06/2017 o 17:16
źródło użytkownik

głosy
1

Możesz napisać własną funkcję 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]}
Odpowiedział 10/10/2018 o 17:53
źródło użytkownik

głosy
-1

Złóż iterator zwracającą kolejnych klawiszy i grupy z iterable. Kluczem jest funkcja obliczania kluczową wartość dla każdego elementu.

import itertools

for k,group in  itertools.groupby([['subject1','english'],['subject2','kannada']]):
for g in group:
    print(f'{k[0]} is {g[1]}')
# output : 
subject1 is english
subject2 is kannada
Odpowiedział 23/08/2018 o 06:44
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more