Come utilizzo itertools.groupby() di Python?
Domanda
Non sono riuscito a trovare una spiegazione comprensibile su come utilizzare effettivamente Python itertools.groupby()
funzione.Quello che sto cercando di fare è questo:
- Fai un elenco: in questo caso, i figli di un oggetto oggettivato
lxml
elemento - Dividilo in gruppi in base ad alcuni criteri
- Quindi ripetere successivamente ciascuno di questi gruppi separatamente.
Ho rivisto la documentazione, E gli esempi, ma ho avuto difficoltà a provare ad applicarli oltre un semplice elenco di numeri.
Quindi, come lo utilizzo itertools.groupby()
?C'è un'altra tecnica che dovrei usare?Sarebbero apprezzati anche suggerimenti per una buona lettura "prerequisita".
Soluzione
NOTA IMPORTANTE: Si deve ordinare i tuoi dati Primo.
La parte che non ho capito è quella nella costruzione di esempio
groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
k
è la chiave di raggruppamento corrente e g
è un iteratore che puoi utilizzare per scorrere il gruppo definito da quella chiave di raggruppamento.In altre parole, il groupby
iterator stesso restituisce gli iteratori.
Eccone un esempio, utilizzando nomi di variabili più chiari:
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 " "
Questo ti darà l'output:
Un orso è un animale.
Un'anatra è un animale.Un cactus è una pianta.
Una barca veloce è un veicolo.
Uno scuolabus è un veicolo.
In questo esempio, things
è un elenco di tuple in cui il primo elemento di ciascuna tupla è il gruppo a cui appartiene il secondo elemento.
IL groupby()
la funzione accetta due argomenti:(1) i dati da raggruppare e (2) la funzione con cui raggrupparli.
Qui, lambda x: x[0]
racconta groupby()
per utilizzare il primo elemento in ogni tupla come chiave di raggruppamento.
In quanto sopra for
dichiarazione, groupby
restituisce tre coppie (chiave, iteratore di gruppo), una volta per ciascuna chiave univoca.È possibile utilizzare l'iteratore restituito per scorrere ogni singolo elemento in quel gruppo.
Ecco un esempio leggermente diverso con gli stessi dati, utilizzando una comprensione dell'elenco:
for key, group in groupby(things, lambda x: x[0]):
listOfThings = " and ".join([thing[1] for thing in group])
print key + "s: " + listOfThings + "."
Questo ti darà l'output:
animali:orso e anatra.
impianti:cactus.
veicoli:motoscafo e scuolabus.
Altri suggerimenti
Puoi mostrarci il tuo codice?
L'esempio sui documenti Python è abbastanza semplice:
groups = []
uniquekeys = []
for k, g in groupby(data, keyfunc):
groups.append(list(g)) # Store group iterator as a list
uniquekeys.append(k)
Quindi nel tuo caso, i dati sono un elenco di nodi, keyfunc è dove va la logica della funzione dei criteri e poi groupby()
raggruppa i dati.
Devi stare attento a ordinare i dati secondo i criteri prima di chiamare groupby
oppure non funzionerà. groupby
Il metodo in realtà scorre semplicemente un elenco e ogni volta che la chiave cambia crea un nuovo gruppo.
Un bel trucco con groupby è eseguire la codifica della lunghezza in una riga:
[(c,len(list(cgen))) for c,cgen in groupby(some_string)]
ti fornirà un elenco di tuple doppie in cui il primo elemento è il carattere e il secondo è il numero di ripetizioni.
Modificare:Nota che questo è ciò che separa itertools.groupby
dall'SQL GROUP BY
semantica:itertools non (e in generale non può) ordinare l'iteratore in anticipo, quindi i gruppi con la stessa "chiave" non vengono uniti.
itertools.groupby
è uno strumento per raggruppare elementi.
Da i documenti, otteniamo ulteriori informazioni su cosa potrebbe fare:
# [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
gli oggetti producono coppie di gruppi chiave in cui il gruppo è un generatore.
Caratteristiche
- UN.Raggruppa elementi consecutivi
- B.Raggruppa tutte le occorrenze di un elemento, dato un iterabile ordinato
- C.Specificare come raggruppare gli elementi con una funzione chiave
Confronti
# 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']
Usi
- Anagrammi (vedi quaderno)
- Cestinare
- Raggruppa i numeri pari e dispari
- Raggruppare un elenco per valori
- Rimuovi gli elementi duplicati
- Trova gli indici di elementi ripetuti in un array
- Dividere un array in blocchi di dimensioni n
- Trova gli elementi corrispondenti tra due elenchi
- Algoritmo di compressione (vedi quaderno)/Codifica della lunghezza di esecuzione
- Raggruppamento delle lettere per lunghezza, funzione chiave (vedi quaderno)
- Valori consecutivi sopra una soglia (vedi quaderno)
- Trova intervalli di numeri in un elenco O elementi continui (Vedere documenti)
- Trova tutte le sequenze più lunghe correlate
- Prendi sequenze consecutive che soddisfano una condizione (vedere il post correlato)
Nota:Molti di questi ultimi esempi derivano da PyCon di Víctor Terrón (parlare) (Spagnolo), "Kung Fu all'alba con Itertools".Vedi anche il groupby
codice sorgente scritto in c.
Risposta
# OP: Yes, you can use `groupby`, e.g.
[do_something(list(g)) for _, g in groupby(lxml_elements, key=criteria_func)]
Un altro esempio:
for key, igroup in itertools.groupby(xrange(12), lambda x: x // 5):
print key, list(igroup)
risultati in
0 [0, 1, 2, 3, 4]
1 [5, 6, 7, 8, 9]
2 [10, 11]
Tieni presente che igroup è un iteratore (un sottoiteratore come lo chiama la documentazione).
Questo è utile per dividere in blocchi un generatore:
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)
Un altro esempio di groupby: quando le chiavi non sono ordinate.Nell'esempio seguente, gli elementi in xx sono raggruppati in base ai valori in yy.In questo caso viene emessa prima una serie di zeri, seguita da una serie di unità e infine da una serie di zeri.
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])
Produce:
0 [0, 1, 2]
1 [3, 4, 5]
0 [6, 7, 8, 9]
AVVERTIMENTO:
La sintassi list(groupby(...)) non funzionerà nel modo previsto.Sembra distruggere gli oggetti iteratori interni, quindi utilizzando
for x in list(groupby(range(10))):
print(list(x[1]))
produrrà:
[]
[]
[]
[]
[]
[]
[]
[]
[]
[9]
Invece di list(groupby(...)), prova [(k, list(g)) for k,g in groupby(...)], o se usi spesso quella sintassi,
def groupbylist(*args, **kwargs):
return [(k, list(g)) for k, g in groupby(*args, **kwargs)]
e accedi alla funzionalità groupby evitando tutti insieme quei fastidiosi iteratori (per piccoli dati).
Vorrei fornire un altro esempio in cui il groupby senza ordinamento non funziona.Adattato dall'esempio di 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 " "
l'uscita è
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.
i gruppi con veicolo sono due, mentre ci si potrebbe aspettare un solo gruppo
@CaptSolo, ho provato il tuo esempio, ma non ha funzionato.
from itertools import groupby
[(c,len(list(cs))) for c,cs in groupby('Pedro Manoel')]
Produzione:
[('P', 1), ('e', 1), ('d', 1), ('r', 1), ('o', 1), (' ', 1), ('M', 1), ('a', 1), ('n', 1), ('o', 1), ('e', 1), ('l', 1)]
Come puoi vedere, ci sono due o e due e, ma sono divise in gruppi separati.È stato allora che ho capito che devi ordinare l'elenco passato alla funzione groupby.Quindi, l'utilizzo corretto sarebbe:
name = list('Pedro Manoel')
name.sort()
[(c,len(list(cs))) for c,cs in groupby(name)]
Produzione:
[(' ', 1), ('M', 1), ('P', 1), ('a', 1), ('d', 1), ('e', 2), ('l', 1), ('n', 1), ('o', 2), ('r', 1)]
Basta ricordare, se la lista non è ordinata, la funzione groupby non funzionerà!
Come utilizzo itertools.groupby() di Python?
Puoi utilizzare groupby per raggruppare elementi su cui eseguire l'iterazione.Dai a groupby un iterabile e un facoltativo chiave function/callable con cui controllare gli elementi non appena escono dall'iterabile e restituisce un iteratore che fornisce una doppia tupla del risultato della chiave richiamabile e degli elementi effettivi in un altro iterabile.Dall'aiuto:
groupby(iterable[, keyfunc]) -> create an iterator which returns
(key, sub-iterator) grouped by each value of key(value).
Ecco un esempio di groupby utilizzando una coroutine per raggruppare in base a un conteggio, utilizza una chiave richiamabile (in questo caso, coroutine.send
) per sputare semplicemente il conteggio per quante iterazioni e un sub-iteratore raggruppato di elementi:
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))
stampe
[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
Ordinamento e raggruppamento
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'}
Un esempio utile che ho trovato potrebbe essere utile:
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)
Esempio di input:14445221
Output di esempio:(1,1) (3,4) (1,5) (2,2) (1,1)
Puoi scrivere la tua funzione 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]}