পাইথন গ্রুপ দ্বারা


125

ধরে নিন যে আমার কাছে ডেটা জুটির একটি সেট রয়েছে যেখানে সূচক 0 এর মান এবং সূচক 1 টাইপ:

input = [
          ('11013331', 'KAT'), 
          ('9085267',  'NOT'), 
          ('5238761',  'ETH'), 
          ('5349618',  'ETH'), 
          ('11788544', 'NOT'), 
          ('962142',   'ETH'), 
          ('7795297',  'ETH'), 
          ('7341464',  'ETH'), 
          ('9843236',  'KAT'), 
          ('5594916',  'ETH'), 
          ('1550003',  'ETH')
        ]

আমি তাদের ধরণের (1 তম সূচকযুক্ত স্ট্রিং দ্বারা) এর মতো গ্রুপ করে রাখতে চাই:

result = [ 
           { 
             type:'KAT', 
             items: ['11013331', '9843236'] 
           },
           {
             type:'NOT', 
             items: ['9085267', '11788544'] 
           },
           {
             type:'ETH', 
             items: ['5238761', '962142', '7795297', '7341464', '5594916', '1550003'] 
           }
         ] 

আমি কীভাবে এটি দক্ষ উপায়ে অর্জন করতে পারি?

উত্তর:


153

এটি 2 পদক্ষেপে করুন। প্রথমে একটি অভিধান তৈরি করুন।

>>> input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')]
>>> from collections import defaultdict
>>> res = defaultdict(list)
>>> for v, k in input: res[k].append(v)
...

তারপরে, সেই অভিধানটি প্রত্যাশিত বিন্যাসে রূপান্তর করুন।

>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}]

এটি itertools.groupby এর মাধ্যমেও সম্ভব তবে এটির জন্য প্রথমে ইনপুটটি বাছাই করা দরকার।

>>> sorted_input = sorted(input, key=itemgetter(1))
>>> groups = groupby(sorted_input, key=itemgetter(1))
>>> [{'type':k, 'items':[x[0] for x in v]} for k, v in groups]
[{'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}]

লক্ষ্য করুন যে এগুলি উভয়ই কীগুলির মূল ক্রমটিকে সম্মান করে না। আপনার অর্ডার রাখার দরকার হলে আপনার অর্ডারডিক্ট দরকার need

>>> from collections import OrderedDict
>>> res = OrderedDict()
>>> for v, k in input:
...   if k in res: res[k].append(v)
...   else: res[k] = [v]
... 
>>> [{'type':k, 'items':v} for k,v in res.items()]
[{'items': ['11013331', '9843236'], 'type': 'KAT'}, {'items': ['9085267', '11788544'], 'type': 'NOT'}, {'items': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}]

ইনপুট টিপলের একটি কী এবং দুই বা ততোধিক মান থাকে তবে এটি কীভাবে করা যায়: [('11013331', 'red', 'KAT'), ('9085267', 'blue' 'KAT')]যেখানে টিপলের শেষ উপাদানটি মূল এবং প্রথম দুটি মান হিসাবে হয়। ফলাফলটি এর মতো হওয়া উচিত: ফলাফল = [{প্রকার: 'কেএটি', আইটেম: [('11013331', লাল), ('9085267', নীল)]}]
ব্যবহারকারী 1144616

1
from operator import itemgetter
বাউমন

1
পদক্ষেপ 1 আমদানি ছাড়াই করা যেতে পারে:d= {}; for k,v in input: d.setdefault(k, []).append(v)
ইকো

আমি অজগরটিতে একটি ম্যাপ্রেডস প্রোগ্রামে কাজ করছি, কেবল অবাক হয়ে ভাবছি তালিকার মান বা বহিরাগত লাইব্রেরি যেমন পান্ডার সাথে কাজ না করে তালিকার মান অনুসারে গ্রুপ করার কোনও উপায় আছে কি? যদি তা না হয় তবে আমি কীভাবে আইটেমগুলি থেকে মুক্তি পাব এবং আমার ফলাফলটি টাইপ করব?
কাউরশ

54

পাইথনের অন্তর্নির্মিত itertoolsমডিউলটিতে আসলে একটি groupbyফাংশন থাকে, তবে তার জন্য উপাদানগুলিকে শ্রেণিবদ্ধ করার জন্য প্রথমে এমনভাবে বাছাই করতে হবে যেগুলি তালিকাভুক্ত করতে হবে উপাদানগুলি:

from operator import itemgetter
sortkeyfn = itemgetter(1)
input = [('11013331', 'KAT'), ('9085267', 'NOT'), ('5238761', 'ETH'), 
 ('5349618', 'ETH'), ('11788544', 'NOT'), ('962142', 'ETH'), ('7795297', 'ETH'), 
 ('7341464', 'ETH'), ('9843236', 'KAT'), ('5594916', 'ETH'), ('1550003', 'ETH')] 
input.sort(key=sortkeyfn)

এখন ইনপুটটি দেখে মনে হচ্ছে:

[('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'),
 ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH'), ('11013331', 'KAT'),
 ('9843236', 'KAT'), ('9085267', 'NOT'), ('11788544', 'NOT')]

groupbyফর্মের 2-টিউপলগুলির একটি ক্রম প্রদান করে (key, values_iterator)। আমরা যা চাই তা হ'ল ডিক্টের তালিকায় এটি পরিবর্তন করা যেখানে 'টাইপ' কী, এবং 'আইটেমস' হল মান_তালিকা দ্বারা ফিরে আসা টিউপসগুলির 0'th উপাদানগুলির একটি তালিকা। এটার মত:

from itertools import groupby
result = []
for key,valuesiter in groupby(input, key=sortkeyfn):
    result.append(dict(type=key, items=list(v[0] for v in valuesiter)))

resultআপনার প্রশ্নে বর্ণিত হিসাবে এখন আপনার কাঙ্ক্ষিত ডিকটি রয়েছে।

আপনি বিবেচনা করতে পারেন, যদিও, কেবল এ থেকে একক ডিক তৈরি করে, টাইপ অনুসারে কীড করা এবং মানগুলির তালিকা সহ প্রতিটি মান। আপনার বর্তমান ফর্মটিতে, কোনও নির্দিষ্ট ধরণের মানগুলি খুঁজে পেতে, তালিকার সাথে পুনরাবৃত্তি করতে হবে 'মিল' টাইপ কীটি মিলবে এবং তারপরে এটি থেকে 'আইটেম' উপাদানটি পাবেন। আপনি যদি 1-আইটেমের ডিক্টের তালিকার পরিবর্তে একটি একক ডিক ব্যবহার করেন, তবে আপনি একটি নির্দিষ্ট ধরণের আইটেমগুলি মাস্টার ডিকের সাথে একক কীযুক্ত অনুসন্ধানের সাথে খুঁজে পেতে পারেন। ব্যবহার করে groupby, এটি দেখতে এই রকম হবে:

result = {}
for key,valuesiter in groupby(input, key=sortkeyfn):
    result[key] = list(v[0] for v in valuesiter)

resultএখন এই resডিকটি রয়েছে (এটি @ কেনেনিটিএম এর উত্তরের মধ্যবর্তী ডিফল্টডিক্ট্টের অনুরূপ ):

{'NOT': ['9085267', '11788544'], 
 'ETH': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 
 'KAT': ['11013331', '9843236']}

(আপনি যদি এটি ওয়ান-লাইনারে হ্রাস করতে চান তবে আপনি এটি করতে পারেন:

result = dict((key,list(v[0] for v in valuesiter)
              for key,valuesiter in groupby(input, key=sortkeyfn))

বা নতুনফাঙ্গলেড ডিক-বোধগম্য ফর্মটি ব্যবহার করে:

result = {key:list(v[0] for v in valuesiter)
              for key,valuesiter in groupby(input, key=sortkeyfn)}

আমি অজগরটিতে একটি ম্যাপ্রেডস প্রোগ্রামে কাজ করছি, কেবল অবাক হয়ে ভাবছি তালিকার মান বা বহিরাগত লাইব্রেরি যেমন পান্ডার সাথে কাজ না করে তালিকার মান অনুসারে গ্রুপ করার কোনও উপায় আছে কি? যদি তা না হয় তবে আমি কীভাবে আইটেমগুলি থেকে মুক্তি পাব এবং আমার ফলাফলটি টাইপ করব?
কাউরশ

@ কৌরশ - একটি নতুন প্রশ্ন হিসাবে পোস্ট করুন, তবে "আইটেমগুলি থেকে মুক্তি পেয়ে আমার ফলাফলটি টাইপ করুন", এবং "অভিধানগুলি না নিয়েই" আপনার অর্থ কী তা বোঝাতে ভুলবেন না indicate
PaulMcG

7

আমি পান্ডসের সাধারণ গ্রুপিং পছন্দ করি । এটি শক্তিশালী, সহজ এবং বৃহত ডেটা সেটের জন্য সবচেয়ে পর্যাপ্ত

result = pandas.DataFrame(input).groupby(1).groups


3

এই উত্তরটি @ পলএমসিজি-র উত্তরের অনুরূপ তবে ইনপুটটি বাছাই করার প্রয়োজন নেই।

ফাংশনাল প্রোগ্রামিংয়ের ক্ষেত্রে তাদের groupByএক লাইনে লেখা যেতে পারে (আমদানি সহ নয়!) এবং এর বিপরীতে itertools.groupbyএটিকে ইনপুট সাজানোর প্রয়োজন হয় না:

from functools import reduce # import needed for python3; builtin in python2
from collections import defaultdict

def groupBy(key, seq):
 return reduce(lambda grp, val: grp[key(val)].append(val) or grp, seq, defaultdict(list))

(কারণ ... or grpমধ্যে lambdaযে এই জন্য reduce()কাজ, lambdaচাহিদা তার প্রথম যুক্তি ফিরে যাওয়ার কারণ list.append()সবসময় ফেরৎ সবসময় রিটার্নNoneorgrp । অর্থাত এটা পাইথন এর সীমাবদ্ধতা কাছাকাছি পেতে একটি ল্যামডা একটি একক অভিব্যক্তি শুধুমাত্র মূল্যায়ন করতে পারেন একটি হ্যাক করে।)

এটি প্রদত্ত ফাংশনটি মূল্যায়নের মাধ্যমে যার কীগুলি খুঁজে পাওয়া যায় এবং যার মানগুলি মূল ক্রমের মূল আইটেমগুলির একটি তালিকা বলে একটি ডিক দেয়। ওপির উদাহরণের জন্য, এটি হিসাবে কল করা groupBy(lambda pair: pair[1], input)এই আদেশটি ফেরত দেবে:

{'KAT': [('11013331', 'KAT'), ('9843236', 'KAT')],
 'NOT': [('9085267', 'NOT'), ('11788544', 'NOT')],
 'ETH': [('5238761', 'ETH'), ('5349618', 'ETH'), ('962142', 'ETH'), ('7795297', 'ETH'), ('7341464', 'ETH'), ('5594916', 'ETH'), ('1550003', 'ETH')]}

এবং @ পলএমসিজি-র উত্তর অনুসারে ওপি-র অনুরোধিত ফর্ম্যাটটি তালিকান বোঝার মধ্যে আবৃত করে খুঁজে পাওয়া যাবে। সুতরাং এটি এটি করবে:

result = {key: [pair[0] for pair in values],
          for key, values in groupBy(lambda pair: pair[1], input).items()}

অনেক কম কোড, তবুও বোধগম্য। এটিও ভাল কারণ এটি চাকাটি পুনরায় উদ্ভাবন করে না।
দেবদনকে

2

নিম্নলিখিত ফাংশনটি দ্রুত ( কোনও সাজানোর প্রয়োজন নেই) কোনও সূচিযুক্ত কী দ্বারা কোনও দৈর্ঘ্যের গ্রুপ টিপল করবে:

# given a sequence of tuples like [(3,'c',6),(7,'a',2),(88,'c',4),(45,'a',0)],
# returns a dict grouping tuples by idx-th element - with idx=1 we have:
# if merge is True {'c':(3,6,88,4),     'a':(7,2,45,0)}
# if merge is False {'c':((3,6),(88,4)), 'a':((7,2),(45,0))}
def group_by(seqs,idx=0,merge=True):
    d = dict()
    for seq in seqs:
        k = seq[idx]
        v = d.get(k,tuple()) + (seq[:idx]+seq[idx+1:] if merge else (seq[:idx]+seq[idx+1:],))
        d.update({k:v})
    return d

আপনার প্রশ্নের ক্ষেত্রে, আপনি যে কী অনুসারে গ্রুপ করতে চান তার সূচী 1, তাই:

group_by(input,1)

দেয়

{'ETH': ('5238761','5349618','962142','7795297','7341464','5594916','1550003'),
 'KAT': ('11013331', '9843236'),
 'NOT': ('9085267', '11788544')}

আপনি যে আউটপুটটি চেয়েছিলেন তা হুবহু নয়, তবে এটি আপনার প্রয়োজনের সাথেও উপযুক্ত হতে পারে।


আমি অজগরটিতে একটি ম্যাপ্রেডস প্রোগ্রামে কাজ করছি, কেবল অবাক হয়ে ভাবছি তালিকার মান বা বহিরাগত লাইব্রেরি যেমন পান্ডার সাথে কাজ না করে তালিকার মান অনুসারে গ্রুপ করার কোনও উপায় আছে কি? যদি তা না হয় তবে আমি কীভাবে আইটেমগুলি থেকে মুক্তি পাব এবং আমার ফলাফলটি টাইপ করব?
কাউরশ

0
result = []
# Make a set of your "types":
input_set = set([tpl[1] for tpl in input])
>>> set(['ETH', 'KAT', 'NOT'])
# Iterate over the input_set
for type_ in input_set:
    # a dict to gather things:
    D = {}
    # filter all tuples from your input with the same type as type_
    tuples = filter(lambda tpl: tpl[1] == type_, input)
    # write them in the D:
    D["type"] = type_
    D["itmes"] = [tpl[0] for tpl in tuples]
    # append D to results:
    result.append(D)

result
>>> [{'itmes': ['9085267', '11788544'], 'type': 'NOT'}, {'itmes': ['5238761', '5349618', '962142', '7795297', '7341464', '5594916', '1550003'], 'type': 'ETH'}, {'itmes': ['11013331', '9843236'], 'type': 'KAT'}]
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.