¿Cómo uso Python's itertools.groupby ()?

votos
364

No he podido encontrar una explicación comprensible de cómo usar realmente la itertools.groupby()función de Python . Lo que intento hacer es esto:

  • Tome una lista - en este caso, los hijos de un lxmlelemento objetivado
  • Divídalo en grupos según algunos criterios
  • Luego, itere sobre cada uno de estos grupos por separado.

Revisé la documentación y los ejemplos , pero he tenido problemas para aplicarlos más allá de una simple lista de números.

Entonces, ¿cómo uso itertools.groupby()? ¿Hay alguna otra técnica que deba usar? También se agradecerán consejos para una buena lectura de prerrequisito.

Publicado el 03/08/2008 a las 19:27
fuente por usuario
En otros idiomas...                            


13 respuestas

votos
65

¿Puedes mostrarnos tu código?

El ejemplo en los documentos de Python es bastante sencillo:

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

Entonces, en su caso, los datos son una lista de nodos, keyfunc es donde va la lógica de su función de criterios y luego groupby()agrupa los datos.

Debe tener cuidado de ordenar los datos antes de llamar groupbyo no funcionará. groupbyel método simplemente itera a través de una lista y cada vez que la tecla cambia, crea un nuevo grupo.

Respondida el 03/08/2008 a las 19:40
fuente por usuario

votos
523

Como dijo Sebastjan, primero debes ordenar tus datos. Esto es importante.

La parte que no obtuve es que en el ejemplo de construcción

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

kes la clave de agrupación actual, y ges un iterador que puede usar para iterar sobre el grupo definido por esa clave de agrupación. En otras palabras, el groupbypropio iterador devuelve iteradores.

Aquí hay un ejemplo de eso, usando nombres de variable más claros:

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

Esto te dará el resultado:

Un oso es un animal
Un pato es un animal.

Un cactus es una planta.

Una lancha rápida es un vehículo.
Un autobús escolar es un vehículo.

En este ejemplo, thingshay una lista de tuplas donde el primer elemento de cada tupla es el grupo al que pertenece el segundo elemento.

La groupby()función toma dos argumentos: (1) los datos para agrupar y (2) la función para agruparlos.

Aquí, lambda x: x[0]dice groupby()usar el primer elemento en cada tupla como la clave de agrupación.

En la fordeclaración anterior , groupbydevuelve tres pares (clave, iterador de grupo), una para cada clave única. Puede usar el iterador devuelto para iterar sobre cada elemento individual en ese grupo.

Aquí hay un ejemplo ligeramente diferente con los mismos datos, usando una lista de comprensión:

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

Esto te dará el resultado:

animales: oso y pato.
plantas: cactus.
vehículos: lancha rápida y autobús escolar.

Respondida el 10/08/2008 a las 19:45
fuente por usuario

votos
32

Un truco de neato con groupby es ejecutar la codificación de longitud en una línea:

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

le dará una lista de 2-tuplas donde el primer elemento es el carácter y el segundo es el número de repeticiones.

Editar: Tenga en cuenta que esto es lo que se separa itertools.groupbyde la GROUP BYsemántica de SQL : itertools no (y en general no puede) ordenar el iterador por adelantado, por lo que los grupos con la misma "clave" no se fusionan.

Respondida el 01/09/2008 a las 00:27
fuente por usuario

votos
7

@CaptSolo, probé tu ejemplo, pero no funcionó.

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

Salida:

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

Como puede ver, hay dos o's y dos e's, pero se dividieron en grupos separados. Fue entonces cuando me di cuenta de que necesita ordenar la lista pasada a la función groupby. Entonces, el uso correcto sería:

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

Salida:

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

Solo recuerda, si la lista no está ordenada, ¡la función groupby no funcionará !

Respondida el 15/10/2009 a las 16:41
fuente por usuario

votos
21

Otro ejemplo:

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

los resultados en

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

Tenga en cuenta que iGroup es un iterador (un sub-iterador como la documentación de la llama).

Esto es útil para fragmentar un generador:

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)

Otro ejemplo de GroupBy - cuando las teclas no están ordenados. En el siguiente ejemplo, los elementos de xx se agrupan por valores en yy. En este caso, un conjunto de ceros se emite primero, seguido por un conjunto de unos, seguido de nuevo por un conjunto de ceros.

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]
Respondida el 21/01/2013 a las 17:54
fuente por usuario

votos
10

Me gustaría dar otro ejemplo, donde GroupBy sin clase no está funcionando. Adaptado de ejemplo por 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 " "

salida es

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.

hay dos grupos con vehiculo, mientras que uno podría esperar que un solo grupo

Respondida el 07/05/2013 a las 21:09
fuente por usuario

votos
17

ADVERTENCIA:

La lista de sintaxis (GroupBy (...)) no tendrán el efecto que tiene la intención. Parece que destruir los objetos del iterador internos, por lo que usar

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

Producirá:

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

En su lugar, de la lista (GroupBy (...)), intente [(k, lista (g)) para k, g en GroupBy (...)], o si se utiliza a menudo que la sintaxis,

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

y obtener acceso a la funcionalidad GroupBy, evitando los molestos (para datos pequeña) iteradores todos juntos.

Respondida el 16/11/2013 a las 01:39
fuente por usuario

votos
5

¿Cómo uso itertools.groupby de Python ()?

Puede utilizar GroupBy a agrupar cosas para repetir. Usted da GroupBy un iterable, y una opcional clave de la función / exigible por el cual permite comprobar los artículos a medida que salen de la iterable, y devuelve un iterador que da dos tupla del resultado de la clave exigible y los elementos reales en otra iterable. A partir de la ayuda:

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

Aquí está un ejemplo de uso de un GroupBy corrutina al grupo por un conde, que utiliza una clave exigible (en este caso, coroutine.send) que acaba de escupir el recuento de embargo muchas iteraciones y una sub-agrupados iterador de elementos:

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

huellas dactilares

[(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]
Respondida el 27/07/2015 a las 18:06
fuente por usuario

votos
2

Un ejemplo útil que me encontré pueden ser útiles:

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)

de entrada de la muestra: 14445221

Resultado de muestra: (1,1) (3,4) (1,5) (2,2) (1,1)

Respondida el 18/06/2017 a las 14:16
fuente por usuario

votos
3

Clasificación y 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'}
Respondida el 01/08/2017 a las 04:14
fuente por usuario

votos
11

itertools.groupby es una herramienta para agrupar artículos.

A partir de los documentos , recogemos más de lo que podría hacer:

# [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 objetos producen pares de grupos clave en la que el grupo es un generador.

Caracteristicas

  • A. Grupo de elementos consecutivos juntos (similar a la unique_justseenreceta)
  • B. Grupo de todas las ocurrencias de un elemento, dado un iterable ordenada
  • C. especificar cómo agrupar elementos con una función clave

Las comparaciones

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

Usos

Varios de los últimos ejemplos se derivan de PyCon charla de Víctor Terrón (Inglés) (Español) , Kung Fu en la madrugada con itertools . Para todos los interesados, aquí está el código fuente para el groupbyescrito en C.

Respondida el 24/08/2017 a las 23:26
fuente por usuario

votos
-1

Hacer un iterador que devuelve las llaves y grupos consecutivos de la iterable. La clave es una función de cálculo de un valor clave para cada elemento.

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
Respondida el 23/08/2018 a las 06:44
fuente por usuario

votos
1

Puede escribir propia función 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]}
Respondida el 10/10/2018 a las 17:53
fuente por usuario

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