मैं itertools.groupby () का उपयोग कैसे करूँ?


506

मैं वास्तव में पायथन के itertools.groupby()कार्य का उपयोग करने के तरीके के बारे में समझ नहीं पा रहा हूं । मैं यह करने की कोशिश कर रहा हूं:

  • एक सूची लें - इस मामले में, एक वस्तु lxmlतत्व के बच्चे
  • इसे कुछ मानदंडों के आधार पर समूहों में विभाजित करें
  • फिर बाद में इनमें से प्रत्येक समूह पर अलग से पुनरावृति।

मैंने दस्तावेज़ीकरण और उदाहरणों की समीक्षा की है , लेकिन मुझे संख्याओं की एक सरल सूची से परे उन्हें लागू करने में परेशानी हुई है।

तो, मैं कैसे उपयोग करूँ itertools.groupby()? क्या एक और तकनीक है जिसका मुझे उपयोग करना चाहिए? अच्छा "पूर्वापेक्षा" पढ़ने के लिए संकेत भी सराहना की जाएगी।


1 के लिए एक उपयोगी मामला होगा leetcode.com/problems/string-compression
ShawnLee

जवाबों:


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

यह आपको आउटपुट देगा:

एक भालू एक जानवर है।
बत्तख एक जानवर है।

कैक्टस एक पौधा है।

स्पीड बोट एक वाहन है।
एक स्कूल बस एक वाहन है।

इस उदाहरण में, thingstuples की एक सूची है जहाँ प्रत्येक tuple में पहला आइटम वह समूह है जिसका दूसरा आइटम है।

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 या तो क्लिक करते हैं या नहीं करते हैं, और अगर आप इसी तरह की समस्याओं को मारते हैं, तो समझ लेना बहुत आसान है। यह अभी तक जंगली में एक की जरूरत नहीं है।
प्रोफेन

3
@ जूलियन अजगर डॉक्स ज्यादातर सामान के लिए बहुत अच्छे लगते हैं, लेकिन जब यह पुनरावृत्तियों, जनरेटर, और चेरी की बात आती है तो डॉक्स ज्यादातर मुझे रहस्यमय करते हैं। Django के डॉक्स दोगुने चौंकाने वाले हैं।
मार्क मैक्समिस्टर

6
छँटाई के लिए +1 - मुझे तब तक समझ नहीं आया जब तक आप मेरे डेटा को समूहीकृत नहीं करते।
कोड़ी

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
रॉबिन नेमेथ

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()डेटा को समूहित करता है।

कॉल करने या काम नहीं करने से पहले आपको मापदंड द्वारा डेटा को सॉर्ट करने के लिए सावधान रहना चाहिए groupbygroupbyविधि वास्तव में सिर्फ एक सूची के माध्यम से पुनरावृत्ति करती है और जब भी कुंजी बदलती है तो एक नया समूह बनाती है।


45
तो आप पढ़ते हैं keyfuncऔर "हाँ, मुझे पता है कि वास्तव में ऐसा क्या है क्योंकि यह प्रलेखन काफी सीधा है।" अतुल्य!
जर्द

5
मेरा मानना ​​है कि ज्यादातर लोग इस "सीधे" लेकिन बेकार उदाहरण के बारे में पहले से ही जानते हैं, क्योंकि यह नहीं कहता है कि किस तरह के 'डेटा' और 'कीफंक' का उपयोग करना है !! लेकिन मुझे लगता है कि आप या तो नहीं जानते, अन्यथा आप इसे स्पष्ट करके लोगों की मदद करेंगे, न कि केवल इसे कॉपी-पेस्ट करके। या तुम करते हो?
अपोस्टोलोस

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. एक आइटम की सभी घटनाओं को समूहबद्ध करें, एक क्रमबद्ध पुनरावृत्ति को देखते हुए
  • 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']

उपयोग

नोट: बाद के उदाहरणों में से कई विक्टर टेरोन के पाइकॉन (टॉक) (स्पैनिश) , "कुंग फू एट डॉन विथ इटरटूल" से निकले हैं। स्रोत कोड भी देखेंgroupbyसी में लिखा ।

* एक ऐसा कार्य जहां परिणाम को प्रभावित करते हुए सभी वस्तुओं को पारित किया जाता है और तुलना की जाती है। प्रमुख कार्यों के साथ अन्य वस्तुओं में शामिल हैं 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
मतीन उल्हाक

1
हाँ। अधिकांश इटर्टूलस डॉकस्ट्रिंग्स इस तरह से "संक्षिप्त" हैं। चूंकि सभी पुनरावृत्तियां पुनरावृत्त हैं, इसलिए उन्हें एक बिलिन ( list(), tuple()) में डाला जाना चाहिए या सामग्री को प्रदर्शित करने के लिए लूप / समझ में लिया जाना चाहिए। ये अतिरेक हैं जो लेखक को अंतरिक्ष के संरक्षण के लिए बाहर रखा गया है।
पाइलैंग

39

ग्रुपबी के साथ एक साफ-सुथरी चाल एक पंक्ति में लंबाई एन्कोडिंग चलाने के लिए है:

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

Groupby का एक और उदाहरण - जब चाबियाँ सॉर्ट नहीं की जाती हैं। निम्नलिखित उदाहरण में, xx में आइटम yy में मूल्यों द्वारा समूहीकृत किए जाते हैं। इस मामले में, शून्य का एक सेट पहले आउटपुट होता है, उसके बाद एक सेट होता है, फिर से शून्य का एक सेट होता है।

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 एक चलने-फिरने के लिए बेहतर नहीं होगा? यह एक ऑब्जेक्ट देता है जो एक जनरेटर की तरह पुनरावृत्त करता है, लेकिन यह सी कोड का उपयोग करता है।
trojjer

@trojjer islice बेहतर होगा यदि समूह सुसंगत आकार के हैं।
woodm1979

मैं चाहता हूं: [0, 1, 2], [1, 2, 3], [2, 3, 4] ...
गिल्बर्ट्स

21

चेतावनी:

सिंटैक्स सूची (ग्रुपबाई (...) उस तरीके से काम नहीं करेगी जो आप चाहते हैं। ऐसा लगता है कि आंतरिक पुनरावृत्त वस्तुओं को नष्ट करना, इसलिए उपयोग करना

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

उत्पादन करेंगे:

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

इसके बजाय, सूची (groupby (...)) की कोशिश करें, k, groupby (...)], में जी के लिए [(k, सूची (g)), या यदि आप अक्सर उस वाक्यविन्यास का उपयोग करते हैं, तो

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

और उन सभी के साथ (छोटे डेटा के लिए) पुनरावृत्तियों से बचने के दौरान ग्रुपबी कार्यक्षमता तक पहुंच प्राप्त करें।


3
उत्तर में से कई का अर्थ है कि आप अपेक्षित परिणाम प्राप्त करने के लिए समूहबद्धता से पहले छंटनी कर सकते हैं। मुझे बस इस जवाब का सामना करना पड़ा, जो अजीब व्यवहार के बारे में बताता है जो मैंने पहले नहीं देखा है। मैंने पहले नहीं देखा क्योंकि केवल अब मैं @ ग्रुपुलर के रूप में (ग्रुपबी (रेंज) (10)) को सूचीबद्ध करने की कोशिश कर रहा था। इससे पहले मैं हमेशा "मैन्युअल रूप से" की सिफारिश करता था ताकि ग्रुपबी ऑब्जेक्ट्स के बजाय "मैन्युअल रूप से" इसका उपयोग किया जा सके। सूची () निर्माणकर्ता को "स्वचालित रूप से" करने दें।
लाल मटर

9

मैं एक और उदाहरण देना चाहूंगा जहां बिना किसी प्रकार के समूह कार्य नहीं हो रहा है। जेम्स सुलक द्वारा उदाहरण से अपनाया गया

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

मैं कुंजी द्वारा उप-पुनरावृत्तियों को संरक्षित करने के लिए एक व्यापक समझ बना रहा था, जब तक मुझे एहसास नहीं हुआ कि यह तानाशाही (समूहकारक, कुंजी) के रूप में सरल था। मिठाई।
trojjer

दूसरे विचारों पर और प्रयोग के बाद, समूह के चारों ओर लिपटा हुआ तानाशाही समूह उप-पुनरावृत्तियों को समाप्त कर देगा। अरे नहीं।
trojjer

इस उत्तर का क्या मतलब है? यह मूल उत्तर पर कैसे बन रहा है ?
codeforester

7

@ कैप्टसोलो, मैंने आपके उदाहरण की कोशिश की, लेकिन यह काम नहीं किया।

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

जैसा कि आप देख सकते हैं, दो ओ और दो ई हैं, लेकिन वे अलग-अलग समूहों में मिल गए। जब मैंने महसूस किया कि आपको समूहबाई फ़ंक्शन को दी गई सूची को क्रमबद्ध करना होगा। तो, सही उपयोग होगा:

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

बस याद रखना, अगर सूची को क्रमबद्ध नहीं किया गया है, तो ग्रुपबी फ़ंक्शन काम नहीं करेगा !


7
वास्तव में यह काम करता है। आप इस व्यवहार को टूटा हुआ मान सकते हैं, लेकिन यह कुछ मामलों में उपयोगी है। इस प्रश्न के उत्तर एक उदाहरण के लिए देखें: stackoverflow.com/questions/1553275/…
डेनिस ओटकिडैच

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[, 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
पहिए को फिर से लगाना एक महान विचार नहीं है, सवाल यह भी है कि इटर्लस ग्रुपबी को समझाना, स्वयं नहीं लिखना
user2678074

1
@ user2678074 आप सही हैं। यदि आप सीखने के दृष्टिकोण से खुद को लिखना चाहते हैं तो यह कुछ है।
स्काई

2
एक डिफाल्ट डिक्टिक्ट (सूची) का भी बेहतर उपयोग करें ताकि यह और भी छोटा हो
मिकी पेर्लस्टीन

@ मिक्कीपेर्स्टीन और तेज।
फनिडमैन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.